3 * Copyright (C) 1996 Florian La Roche <laroche@redhat.com>
4 * Copyright (C) 2002, 2003 Red Hat, Inc
6 * This getty can only be used as a small console getty. Look at mgetty
7 * for a real modem getty.
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
16 * - autologin only at first login
17 * - /etc/mingetty.conf that can be used instead of /etc/inittab for
18 * command line options
19 * - Can UTF-8 setup be done within mingetty?
20 * - Also add /bin/login-type functionality in here?
28 #include <sys/ioctl.h>
38 #include <sys/param.h>
40 #include <sys/utsname.h>
43 /* name of this program (argv[0]) */
44 static char *progname;
45 /* on which tty line are we sitting? (e.g. tty1) */
47 /* some information about this host */
48 static struct utsname uts;
50 static char hn[MAXHOSTNAMELEN + 1];
51 /* process and session ID of this program */
52 static pid_t pid, sid;
53 /* login program invoked */
54 static char *loginprog = "/bin/login";
55 /* Do not send a reset string to the terminal. */
56 static int noclear = 0;
57 /* Do not print a newline. */
58 static int nonewline = 0;
59 /* Do not print /etc/issue. */
60 static int noissue = 0;
61 /* Do not call vhangup() on the tty. */
62 static int nohangup = 0;
63 /* Do not print any hostname. */
64 static int nohostname = 0;
65 /* Print the whole string of gethostname() instead of just until the next "." */
66 static int longhostname = 0;
67 /* time to wait, seconds */
69 /* chroot directory */
70 static char *ch_root = NULL;
71 /* working directory to change into */
72 static char *ch_dir = NULL;
73 /* 'nice' level of the program */
74 static int priority = 0;
75 /* automatic login with this user */
76 static char *autologin = NULL;
77 /* try to read a char before dropping to login prompt */
78 static int loginpause = 0;
80 /* error() - output error messages */
81 static void error (const char *fmt, ...)
85 va_start (va_alist, fmt);
86 openlog (progname, LOG_PID, LOG_AUTH);
87 vsyslog (LOG_ERR, fmt, va_alist);
88 /* no need, we exit anyway: closelog (); */
94 /* update_utmp() - update our utmp entry */
95 static void update_utmp (void)
102 while ((utp = getutent ()))
103 if (utp->ut_type == INIT_PROCESS && utp->ut_pid == pid)
107 memcpy (&ut, utp, sizeof (ut));
109 /* some inits don't initialize utmp... */
111 memset (&ut, 0, sizeof (ut));
112 if (strncmp (x, "tty", 3) == 0)
114 if (strlen (x) > sizeof (ut.ut_id))
115 x += strlen (x) - sizeof (ut.ut_id);
116 strncpy (ut.ut_id, x, sizeof (ut.ut_id));
119 strncpy (ut.ut_user, "LOGIN", sizeof (ut.ut_user));
120 strncpy (ut.ut_line, tty, sizeof (ut.ut_line));
122 ut.ut_time = cur_time;
123 ut.ut_type = LOGIN_PROCESS;
130 updwtmp (_PATH_WTMP, &ut);
133 /* open_tty - set up tty as standard { input, output, error } */
134 static void open_tty (void)
136 struct sigaction sa, sa_old;
140 /* Set up new standard input. */
144 strcpy (buf, "/dev/");
147 /* There is always a race between this reset and the call to
148 vhangup() that s.o. can use to get access to your tty. */
149 if (chown (buf, 0, 0) || chmod (buf, 0600))
151 error ("%s: %s", tty, strerror (errno));
153 sa.sa_handler = SIG_IGN;
155 sigemptyset (&sa.sa_mask);
156 sigaction (SIGHUP, &sa, &sa_old);
158 /* vhangup() will replace all open file descriptors in the kernel
159 that point to our controlling tty by a dummy that will deny
160 further reading/writing to our device. It will also reset the
161 tty to sane defaults, so we don't have to modify the tty device
162 for sane settings. We also get a SIGHUP/SIGCONT.
164 if ((fd = open (buf, O_RDWR, 0)) < 0)
165 error ("%s: cannot open tty: %s", tty, strerror (errno));
166 if (ioctl (fd, TIOCSCTTY, (void *) 1) == -1)
167 error ("%s: no controlling tty: %s", tty, strerror (errno));
169 error ("%s: not a tty", tty);
173 error ("%s: vhangup() failed", tty);
174 /* Get rid of the present stdout/stderr. */
179 if ((fd = open (buf, O_RDWR, 0)) != 0)
180 error ("%s: cannot open tty: %s", tty,
182 if (ioctl (fd, TIOCSCTTY, (void *) 1) == -1)
183 error ("%s: no controlling tty: %s", tty,
186 /* Set up stdin/stdout/stderr. */
187 if (dup2 (fd, 0) != 0 || dup2 (fd, 1) != 1 || dup2 (fd, 2) != 2)
188 error ("%s: dup2(): %s", tty, strerror (errno));
192 /* Write a reset string to the terminal. This is very linux-specific
193 and should be checked for other systems. */
195 write (0, "\033c", 2);
197 sigaction (SIGHUP, &sa_old, NULL);
200 static void output_special_char (unsigned char c)
204 printf ("%s", uts.sysname);
207 printf ("%s", uts.nodename);
210 printf ("%s", uts.release);
213 printf ("%s", uts.version);
216 printf ("%s", uts.machine);
219 printf ("%s", uts.domainname);
230 tm = localtime (&cur_time);
231 strftime (buff, sizeof (buff),
232 c == 'd'? "%a %b %d %Y" : "%X", tm);
233 fputs (buff, stdout);
237 tm = localtime (&cur_time);
238 if (c == 'd') /* ISO 8601 */
239 printf ("%d-%02d-%02d", 1900 + tm->tm_year,
240 tm->tm_mon + 1, tm->tm_mday);
242 printf ("%02d:%02d:%02d", tm->tm_hour,
243 tm->tm_min, tm->tm_sec);
257 while ((ut = getutent ()))
258 if (ut->ut_type == USER_PROCESS)
261 printf ("%d", users);
263 printf (" user%s", users == 1 ? "" : "s");
271 /* do_prompt - show login prompt, optionally preceded by /etc/issue contents */
272 static void do_prompt (int showlogin)
279 if (noissue == 0 && (fd = fopen ("/etc/issue", "r"))) {
280 while ((c = getc (fd)) != EOF) {
282 output_special_char (getc (fd));
289 puts ("[press ENTER to login]");
299 static char *get_logname (void)
301 static char logname[40];
305 tcflush (0, TCIFLUSH); /* flush pending input */
306 for (*logname = 0; *logname == 0;) {
308 for (bp = logname;;) {
309 if (read (0, &c, 1) < 1) {
310 if (errno == EINTR || errno == EIO
313 error ("%s: read: %s", tty, strerror (errno));
315 if (c == '\n' || c == '\r') {
318 } else if (!isprint (c))
319 error ("%s: invalid character 0x%x in login"
321 else if ((size_t)(bp - logname) >= sizeof (logname) - 1)
322 error ("%s: too long login name", tty);
330 static void usage (void)
332 error ("usage: '%s [--noclear] [--nonewline] [--noissue] "
333 "[--nohangup] [--nohostname] [--long-hostname] "
334 "[--loginprog=/bin/login] [--nice=10] [--delay=10] "
335 "[--chdir=/home] [--chroot=/chroot] [--autologin=user] "
337 "tty' with e.g. tty=tty1", progname);
340 static struct option const long_options[] = {
341 { "autologin", required_argument, NULL, 'a' },
342 { "loginpause", no_argument, &loginpause, 'p' },
343 { "chdir", required_argument, NULL, 'w' },
344 { "chroot", required_argument, NULL, 'r' },
345 { "delay", required_argument, NULL, 'd' },
346 { "noclear", no_argument, &noclear, 1 },
347 { "nonewline", no_argument, &nonewline, 1 },
348 { "noissue", no_argument, &noissue, 1 },
349 { "nohangup", no_argument, &nohangup, 1 },
350 { "no-hostname", no_argument, &nohostname, 1 }, /* compat option */
351 { "nohostname", no_argument, &nohostname, 1 },
352 { "loginprog", required_argument, NULL, 'l' },
353 { "long-hostname", no_argument, &longhostname, 1 },
354 { "nice", required_argument, NULL, 'n' },
358 int main (int argc, char **argv)
365 progname = "mingetty";
367 gethostname (hn, MAXHOSTNAMELEN);
368 hn[MAXHOSTNAMELEN] = '\0';
371 #if defined(s390) || defined(__s390__)
372 putenv ("TERM=dumb");
374 putenv ("TERM=linux");
377 while ((c = getopt_long (argc, argv, "a:p:d:l:n:w:r:", long_options,
378 (int *) 0)) != EOF) {
386 delay = atoi (optarg);
392 priority = atoi (optarg);
404 if (longhostname == 0 && (s = strchr (hn, '.')))
410 if (strncmp (tty, "/dev/", 5) == 0) /* ignore leading "/dev/" */
419 printf ("login: %s (automatic login)\n", autologin);
422 while ((logname = get_logname ()) == 0)
432 execl (loginprog, loginprog, autologin? "-f" : "--", logname, NULL);
433 error ("%s: can't exec %s: %s", tty, loginprog, strerror (errno));