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

Revision 16272, 9.6 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 <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
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                flock (ut_fd, LOCK_EX);
166                write (ut_fd, &ut, sizeof (ut));
167                flock (ut_fd, LOCK_UN);
168                close (ut_fd);
169        }
170}
171
172/* open_tty - set up tty as standard { input, output, error } */
173static void open_tty (void)
174{
175        struct sigaction sa;
176        char buf[20];
177        int fd;
178
179        /* Set up new standard input. */
180        strcpy (buf, "/dev/");
181        strcat (buf, tty);
182        if (chown (buf, 0, 0) || chmod (buf, 0600))
183                error ("%s: %s", buf, sys_errlist[errno]);
184
185        sa.sa_handler = SIG_IGN;
186        sa.sa_flags = 0;
187        sigemptyset (&sa.sa_mask);
188        sigaction (SIGHUP, &sa, NULL);
189
190        /* vhangup() will replace all open file descriptors that point to our
191           controlling tty by a dummy that will deny further reading/writing
192           to our device. It will also reset the tty to sane defaults, so we
193           don't have to modify the tty device for sane settings.
194           We also get a SIGHUP/SIGCONT.
195         */
196        if ((fd = open (buf, O_RDWR, 0)) < 0
197                || ioctl (fd, TIOCSCTTY, (void *)1) == -1)
198                error ("%s: cannot open tty: %s", buf, sys_errlist[errno]);
199        if (!isatty (fd))
200                error ("%s: not a tty", buf);
201
202        vhangup ();
203        /* Get rid of the present stdout/stderr. */
204        close (2);
205        close (1);
206        close (0);
207        close (fd);
208        /* ioctl (0, TIOCNOTTY, (char *)1); */
209
210        if (open (buf, O_RDWR, 0) != 0)
211                error ("%s: cannot open as standard input: %s", buf,
212                                sys_errlist[errno]);
213
214        /* Set up standard output and standard error file descriptors. */
215        if (dup (0) != 1 || dup (0) != 2)
216                error ("%s: dup problem: %s", buf, sys_errlist[errno]);
217
218        /* Write a reset string to the terminal. This is very linux-specific
219           and should be checked for other systems. */
220        if (! noclear)
221                write (0, "\033c", 2);
222
223        sa.sa_handler = SIG_DFL;
224        sa.sa_flags = 0;
225        sigemptyset (&sa.sa_mask);
226        sigaction (SIGHUP, &sa, NULL);
227
228#if     DEBUG_THIS
229        printf ("session=%d, pid=%d, pgid=%d\n", getsid (0), getpid (),
230                        getpgid (0));
231#endif
232}
233
234static void output_special_char (unsigned char c)
235{
236        switch (c) {
237        case 's':
238                printf ("%s", uts.sysname);
239                break;
240        case 'n':
241                printf ("%s", uts.nodename);
242                break;
243        case 'r':
244                printf ("%s", uts.release);
245                break;
246        case 'v':
247                printf ("%s", uts.version);
248                break;
249        case 'm':
250                printf ("%s", uts.machine);
251                break;
252        case 'o':
253                printf ("%s", uts.domainname);
254                break;
255#if 0
256        case 'd':
257        case 't':
258                {
259                        char *weekday[] =
260                        {"Sun", "Mon", "Tue", "Wed", "Thu",
261                         "Fri", "Sat"};
262                        char *month[] =
263                        {"Jan", "Feb", "Mar", "Apr", "May",
264                         "Jun", "Jul", "Aug", "Sep", "Oct",
265                         "Nov", "Dec"};
266                        time_t now;
267                        struct tm *tm;
268
269                        time (&now);
270                        tm = localtime (&now);
271
272                        if (c == 'd')
273                                printf ("%s %s %d  %d",
274                                    weekday[tm->tm_wday], month[tm->tm_mon],
275                                        tm->tm_mday,
276                                     tm->tm_year < 70 ? tm->tm_year + 2000 :
277                                        tm->tm_year + 1900);
278                        else
279                                printf ("%02d:%02d:%02d",
280                                        tm->tm_hour, tm->tm_min, tm->tm_sec);
281
282                        break;
283                }
284#else
285        case 'd':
286        case 't':
287                {
288                        char buff[20];
289                        struct tm *tm = localtime (&cur_time);
290                        strftime (buff, sizeof (buff),
291                                c == 'd'? "%a %b %d %Y" : "%X", tm);
292                        fputs (buff, stdout);
293                        break;
294                }
295#endif
296
297        case 'l':
298                printf ("%s", tty);
299                break;
300        case 'u':
301        case 'U':
302                {
303                        int users = 0;
304                        struct utmp *ut;
305                        setutent ();
306                        while ((ut = getutent ()))
307                                if (ut->ut_type == USER_PROCESS)
308                                        users++;
309                        endutent ();
310                        printf ("%d", users);
311                        if (c == 'U')
312                                printf (" user%s", users == 1 ? "" : "s");
313                        break;
314                }
315        default:
316                putchar (c);
317        }
318}
319
320/* do_prompt - show login prompt, optionally preceded by /etc/issue contents */
321static void do_prompt (void)
322{
323#if     ! OLD
324        FILE *fd;
325#else
326        int fd;
327#endif
328        char c;
329
330        write (1, "\n", 1);     /* start a new line */
331#if     ! OLD
332        if ((fd = fopen (ISSUE, "r"))) {
333                while ((c = getc (fd)) != EOF) {
334                        if (c == '\\')
335                                output_special_char (getc(fd));
336                        else
337                                putchar (c);
338                }
339                fflush (stdout);
340                fclose (fd);
341        }
342#else
343        if ((fd = open (ISSUE, O_RDONLY)) >= 0) {
344                close (fd);
345        }
346#endif
347        write (1, hn, strlen (hn));
348        write (1, LOGIN, sizeof (LOGIN) - 1);
349}
350
351/* get_logname - get user name, establish speed, erase, kill, eol */
352static char *get_logname (void)
353{
354        static char logname[40];
355        char *bp;
356        unsigned char c;
357
358        ioctl (0, TCFLSH, 0);   /* flush pending input */
359
360        for (*logname = 0; *logname == 0;) {
361                do_prompt ();
362                for (bp = logname;;) {
363                        if (read (0, &c, 1) < 1) {
364                                if (errno == EINTR || errno == EIO
365                                                        || errno == ENOENT)
366                                        exit (0);
367                                error ("%s: read: %s", tty, sys_errlist[errno]);
368                        }
369                        if (c == '\n' || c == '\r') {
370                                *bp = 0;
371                                break;
372                        } else if (!isalnum (c) && c != '_')
373                                error ("%s: invalid character for login name",
374                                                                tty);
375                        else if (bp - logname >= sizeof (logname) - 1)
376                                error ("%s: too long login name", tty);
377                        else
378                                *bp++ = c;
379                }
380        }
381        return logname;
382}
383
384static void usage (void)
385{
386        error ("usage: '%s tty' with e.g. tty=tty1", progname);
387}
388
389static struct option const long_options[] = {
390        { "noclear", no_argument, &noclear, 1},
391        { "long-hostname", no_argument, &longhostname, 1},
392        { 0, 0, 0, 0 }
393};
394
395/*
396 * main program
397 */
398int main (int argc, char **argv)
399{
400        char *logname, *s;
401        int c;
402
403        progname = argv[0];
404        uname (&uts);
405        gethostname (hn, MAXHOSTNAMELEN);
406        pid = getpid ();
407        time (&cur_time);
408#if 1
409        putenv ("TERM=linux");
410#endif
411
412        while ((c = getopt_long (argc, argv, "", long_options, (int *) 0))
413                        != EOF) {
414                switch (c) {
415                        case 0:
416                                break;
417                        default:
418                                usage ();
419                }
420        }
421        if (!longhostname && (s = strchr(hn, '.')))
422                *s = '\0';
423        tty = argv[optind];
424        if (! tty)
425                usage ();
426
427        update_utmp ();
428        open_tty ();
429#if 0
430#ifdef linux
431        ioctl (0, TIOCSPGRP, &pid);
432#endif
433#endif
434        /* flush input and output queues, important for modems */
435        ioctl (0, TCFLSH, 2);
436
437        while ((logname = get_logname ()) == 0);
438
439        execl (_PATH_LOGIN, _PATH_LOGIN, "--", logname, NULL);
440        error ("%s: can't exec " _PATH_LOGIN ": %s", tty, sys_errlist[errno]);
441        exit (0);
442}
443
Note: See TracBrowser for help on using the repository browser.