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

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