source: trunk/third/mingetty/mingetty.c @ 16281

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