source: trunk/third/mingetty/mingetty.c.glibc @ 16272

Revision 16272, 9.5 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16271, which included commits to RCS files with non-trunk default branches.
Line 
1/*  mingetty.c
2 *
3 *  Copyright (C) 1996 Florian La Roche
4 *  florian@jurix.jura.uni-sb.de florian@suse.de
5 *
6 *  Newer versions should be on susix.jura.uni-sb.de/pub/linux/source/system
7 *  or sunsite.unc.edu/pub/Linux/system/Admin/login or /pub/Linux/system/
8 *  Daemons/init/.
9 *
10 *  utmp-handling is from agetty in util-linux 2.5 (probably from
11 *  Peter Orbaek <poe@daimi.aau.dk>)
12 *
13 *  S.u.S.E. - GmbH has paid some of the time that was needed to write
14 *  this program. Thanks a lot for their support.
15 *
16 *  This getty can only be used as console getty. It is very small, but
17 *  should be very reliable. For a modem getty, I'd also use nothing else
18 *  but mgetty.
19 *
20 *  Usage: mingetty [--noclear] tty
21 *  Example entry in /etc/inittab: 1:123:respawn:/sbin/mingetty tty1
22 *
23 *  This program is free software; you can redistribute it and/or
24 *  modify it under the terms of the GNU General Public License
25 *  as published by the Free Software Foundation; either version
26 *  2 of the License, or (at your option) any later version.
27 *
28 */
29
30#define DEBUG_THIS 0
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <unistd.h>
35#include <string.h>
36#include <sys/ioctl.h>
37#include <errno.h>
38#include <sys/stat.h>
39#include <sys/file.h>
40#include <sys/signal.h>
41#include <fcntl.h>
42#include <stdarg.h>
43#include <ctype.h>
44#include <utmp.h>
45#include <getopt.h>
46
47#ifdef linux
48#include <sys/param.h>
49#define USE_SYSLOG
50#endif
51
52 /* If USE_SYSLOG is undefined all diagnostics go directly to /dev/console. */
53#ifdef  USE_SYSLOG
54#include <syslog.h>
55#endif
56
57#define ISSUE "/etc/issue"      /* displayed before the login prompt */
58#include <sys/utsname.h>
59#include <time.h>
60
61#define LOGIN " login: "        /* login prompt */
62
63/* name of this program (argv[0]) */
64static char *progname;
65/* on which tty line are we sitting? (e.g. tty1) */
66static char *tty;
67/* some information about this host */
68static struct utsname uts;
69/* the hostname */
70static char hn[MAXHOSTNAMELEN + 1];
71/* process ID of this program */
72static pid_t pid;
73/* current time */
74static time_t cur_time;
75/* do not send a reset string to the terminal ? */
76static int noclear = 0;
77/* Print the whole string of gethostname() instead of just until the next "." */
78static int longhostname = 0;
79
80
81/*
82 * output error messages
83 */
84static void error (const char *fmt, ...)
85{
86        va_list va_alist;
87        char buf[256], *bp;
88#ifndef USE_SYSLOG
89        int fd;
90#endif
91
92#ifdef USE_SYSLOG
93        buf[0] = '\0';
94        bp = buf;
95#else
96        strcpy (buf, progname);
97        strcat (buf, ": ");
98        bp = buf + strlen (buf);
99#endif
100
101        va_start (va_alist, fmt);
102        vsprintf (bp, fmt, va_alist);
103        va_end (va_alist);
104
105#ifdef  USE_SYSLOG
106        openlog (progname, LOG_PID, LOG_AUTH);
107        syslog (LOG_ERR, buf);
108        closelog ();
109#else
110        strcat (bp, "\r\n");
111        if ((fd = open ("/dev/console", 1)) >= 0) {
112                write (fd, buf, strlen (buf));
113                close (fd);
114        }
115#endif
116        exit (1);
117}
118
119/*
120 * update_utmp - update our utmp entry
121 *
122 * The utmp file holds miscellaneous information about things started by
123 * /sbin/init and other system-related events. Our purpose is to update
124 * the utmp entry for the current process, in particular the process
125 * type and the tty line we are listening to. Return successfully only
126 * if the utmp file can be opened for update, and if we are able to find
127 * our entry in the utmp file.
128 */
129static void update_utmp (void)
130{
131        struct utmp ut;
132        int ut_fd;
133        struct utmp *utp;
134
135        utmpname (_PATH_UTMP);
136        setutent ();
137        while ((utp = getutent ()))
138                if (utp->ut_type == INIT_PROCESS && utp->ut_pid == pid)
139                        break;
140
141        if (utp) {
142                memcpy (&ut, utp, sizeof (ut));
143        } else {
144                /* some inits don't initialize utmp... */
145                /* XXX we should print out a warning message */
146                memset (&ut, 0, sizeof (ut));
147                strncpy (ut.ut_id, tty + 3, sizeof (ut.ut_id));
148        }
149        endutent ();
150
151        strncpy (ut.ut_user, "LOGIN", sizeof (ut.ut_user));
152        strncpy (ut.ut_line, tty, sizeof (ut.ut_line));
153        ut.ut_time = cur_time;
154        ut.ut_type = LOGIN_PROCESS;
155        ut.ut_pid = pid;
156
157        pututline (&ut);
158        endutent ();
159
160        if ((ut_fd = open (_PATH_WTMP, O_APPEND | O_WRONLY)) >= 0) {
161                flock (ut_fd, LOCK_EX);
162                write (ut_fd, &ut, sizeof (ut));
163                flock (ut_fd, LOCK_UN);
164                close (ut_fd);
165        }
166}
167
168/* open_tty - set up tty as standard { input, output, error } */
169static void open_tty (void)
170{
171        struct sigaction sa;
172        char buf[20];
173        int fd;
174
175        /* Set up new standard input. */
176        strcpy (buf, "/dev/");
177        strcat (buf, tty);
178        if (chown (buf, 0, 0) || chmod (buf, 0600))
179                error ("%s: %s", buf, sys_errlist[errno]);
180
181        sa.sa_handler = SIG_IGN;
182        sa.sa_flags = 0;
183        sigemptyset (&sa.sa_mask);
184        sigaction (SIGHUP, &sa, NULL);
185
186        /* vhangup() will replace all open file descriptors that point to our
187           controlling tty by a dummy that will deny further reading/writing
188           to our device. It will also reset the tty to sane defaults, so we
189           don't have to modify the tty device for sane settings.
190           We also get a SIGHUP/SIGCONT.
191         */
192        if ((fd = open (buf, O_RDWR, 0)) < 0
193                || ioctl (fd, TIOCSCTTY, (void *)1) == -1)
194                error ("%s: cannot open tty: %s", buf, sys_errlist[errno]);
195        if (!isatty (fd))
196                error ("%s: not a tty", buf);
197
198        vhangup ();
199        /* Get rid of the present stdout/stderr. */
200        close (2);
201        close (1);
202        close (0);
203        close (fd);
204        /* ioctl (0, TIOCNOTTY, (char *)1); */
205
206        if (open (buf, O_RDWR, 0) != 0)
207                error ("%s: cannot open as standard input: %s", buf,
208                                sys_errlist[errno]);
209
210        /* Set up standard output and standard error file descriptors. */
211        if (dup (0) != 1 || dup (0) != 2)
212                error ("%s: dup problem: %s", buf, sys_errlist[errno]);
213
214        /* Write a reset string to the terminal. This is very linux-specific
215           and should be checked for other systems. */
216        if (! noclear)
217                write (0, "\033c", 2);
218
219        sa.sa_handler = SIG_DFL;
220        sa.sa_flags = 0;
221        sigemptyset (&sa.sa_mask);
222        sigaction (SIGHUP, &sa, NULL);
223
224#if     DEBUG_THIS
225        printf ("session=%d, pid=%d, pgid=%d\n", getsid (0), getpid (),
226                        getpgid (0));
227#endif
228}
229
230static void output_special_char (unsigned char c)
231{
232        switch (c) {
233        case 's':
234                printf ("%s", uts.sysname);
235                break;
236        case 'n':
237                printf ("%s", uts.nodename);
238                break;
239        case 'r':
240                printf ("%s", uts.release);
241                break;
242        case 'v':
243                printf ("%s", uts.version);
244                break;
245        case 'm':
246                printf ("%s", uts.machine);
247                break;
248        case 'o':
249                printf ("%s", uts.domainname);
250                break;
251#if 0
252        case 'd':
253        case 't':
254                {
255                        char *weekday[] =
256                        {"Sun", "Mon", "Tue", "Wed", "Thu",
257                         "Fri", "Sat"};
258                        char *month[] =
259                        {"Jan", "Feb", "Mar", "Apr", "May",
260                         "Jun", "Jul", "Aug", "Sep", "Oct",
261                         "Nov", "Dec"};
262                        time_t now;
263                        struct tm *tm;
264
265                        time (&now);
266                        tm = localtime (&now);
267
268                        if (c == 'd')
269                                printf ("%s %s %d  %d",
270                                    weekday[tm->tm_wday], month[tm->tm_mon],
271                                        tm->tm_mday,
272                                     tm->tm_year < 70 ? tm->tm_year + 2000 :
273                                        tm->tm_year + 1900);
274                        else
275                                printf ("%02d:%02d:%02d",
276                                        tm->tm_hour, tm->tm_min, tm->tm_sec);
277
278                        break;
279                }
280#else
281        case 'd':
282        case 't':
283                {
284                        char buff[20];
285                        struct tm *tm = localtime (&cur_time);
286                        strftime (buff, sizeof (buff),
287                                c == 'd'? "%a %b %d %Y" : "%X", tm);
288                        fputs (buff, stdout);
289                        break;
290                }
291#endif
292
293        case 'l':
294                printf ("%s", tty);
295                break;
296        case 'u':
297        case 'U':
298                {
299                        int users = 0;
300                        struct utmp *ut;
301                        setutent ();
302                        while ((ut = getutent ()))
303                                if (ut->ut_type == USER_PROCESS)
304                                        users++;
305                        endutent ();
306                        printf ("%d", users);
307                        if (c == 'U')
308                                printf (" user%s", users == 1 ? "" : "s");
309                        break;
310                }
311        default:
312                putchar (c);
313        }
314}
315
316/* do_prompt - show login prompt, optionally preceded by /etc/issue contents */
317static void do_prompt (void)
318{
319#if     ! OLD
320        FILE *fd;
321#else
322        int fd;
323#endif
324        char c;
325
326        write (1, "\n", 1);     /* start a new line */
327#if     ! OLD
328        if ((fd = fopen (ISSUE, "r"))) {
329                while ((c = getc (fd)) != EOF) {
330                        if (c == '\\')
331                                output_special_char (getc(fd));
332                        else
333                                putchar (c);
334                }
335                fflush (stdout);
336                fclose (fd);
337        }
338#else
339        if ((fd = open (ISSUE, O_RDONLY)) >= 0) {
340                close (fd);
341        }
342#endif
343        write (1, hn, strlen (hn));
344        write (1, LOGIN, sizeof (LOGIN) - 1);
345}
346
347/* get_logname - get user name, establish speed, erase, kill, eol */
348static char *get_logname (void)
349{
350        static char logname[40];
351        char *bp;
352        unsigned char c;
353
354        ioctl (0, TCFLSH, 0);   /* flush pending input */
355
356        for (*logname = 0; *logname == 0;) {
357                do_prompt ();
358                for (bp = logname;;) {
359                        if (read (0, &c, 1) < 1) {
360                                if (errno == EINTR || errno == EIO
361                                                        || errno == ENOENT)
362                                        exit (0);
363                                error ("%s: read: %s", tty, sys_errlist[errno]);
364                        }
365                        if (c == '\n' || c == '\r') {
366                                *bp = 0;
367                                break;
368                        } else if (!isalnum (c) && c != '_')
369                                error ("%s: invalid character for login name",
370                                                                tty);
371                        else if (bp - logname >= sizeof (logname) - 1)
372                                error ("%s: too long login name", tty);
373                        else
374                                *bp++ = c;
375                }
376        }
377        return logname;
378}
379
380static void usage (void)
381{
382        error ("usage: '%s tty' with e.g. tty=tty1", progname);
383}
384
385static struct option const long_options[] = {
386        { "noclear", no_argument, &noclear, 1},
387        { "long-hostname", no_argument, &longhostname, 1},
388        { 0, 0, 0, 0 }
389};
390
391/*
392 * main program
393 */
394int main (int argc, char **argv)
395{
396        char *logname, *s;
397        int c;
398
399        progname = argv[0];
400        uname (&uts);
401        gethostname (hn, MAXHOSTNAMELEN);
402        pid = getpid ();
403        time (&cur_time);
404#if 1
405        putenv ("TERM=linux");
406#endif
407
408        while ((c = getopt_long (argc, argv, "", long_options, (int *) 0))
409                        != EOF) {
410                switch (c) {
411                        case 0:
412                                break;
413                        default:
414                                usage ();
415                }
416        }
417        if (!longhostname && (s = strchr(hn, '.')))
418                *s = '\0';
419        tty = argv[optind];
420        if (! tty)
421                usage ();
422
423        update_utmp ();
424        open_tty ();
425#if 0
426#ifdef linux
427        ioctl (0, TIOCSPGRP, &pid);
428#endif
429#endif
430        /* flush input and output queues, important for modems */
431        ioctl (0, TCFLSH, 2);
432
433        while ((logname = get_logname ()) == 0);
434
435        execl (_PATH_LOGIN, _PATH_LOGIN, "--", logname, NULL);
436        error ("%s: can't exec " _PATH_LOGIN ": %s", tty, sys_errlist[errno]);
437        exit (0);
438}
439
Note: See TracBrowser for help on using the repository browser.