2 * Alternate Getty (agetty) 'agetty' is a versatile, portable, easy to use
3 * replacement for getty on SunOS 4.1.x or the SAC ttymon/ttyadm/sacadm/pmadm
4 * suite on Solaris and other SVR4 systems. 'agetty' was written by Wietse
5 * Venema, enhanced by John DiMarco, and further enhanced by Dennis Cronin.
7 * Ported to Linux by Peter Orbaek <poe@daimi.aau.dk>
8 * Adopt the mingetty features for a better support
9 * of virtual consoles by Werner Fink <werner@suse.de>
11 * This program is freely distributable.
21 #include <sys/ioctl.h>
22 #include <sys/types.h>
32 #include <sys/socket.h>
35 #include <arpa/inet.h>
43 #include "pathnames.h"
47 #include "color-names.h"
49 #ifdef HAVE_SYS_PARAM_H
50 # include <sys/param.h>
53 #if defined(__FreeBSD_kernel__)
60 # ifndef DEFAULT_VCTERM
61 # define DEFAULT_VCTERM "linux"
63 # if defined (__s390__) || defined (__s390x__)
64 # define DEFAULT_TTYS0 "dumb"
65 # define DEFAULT_TTY32 "ibm327x"
66 # define DEFAULT_TTYS1 "vt220"
68 # ifndef DEFAULT_STERM
69 # define DEFAULT_STERM "vt102"
71 #elif defined(__GNU__)
73 # ifndef DEFAULT_VCTERM
74 # define DEFAULT_VCTERM "hurd"
76 # ifndef DEFAULT_STERM
77 # define DEFAULT_STERM "vt102"
80 # ifndef DEFAULT_VCTERM
81 # define DEFAULT_VCTERM "vt100"
83 # ifndef DEFAULT_STERM
84 # define DEFAULT_STERM "vt100"
88 #ifdef __FreeBSD_kernel__
92 /* If USE_SYSLOG is undefined all diagnostics go to /dev/console. */
98 * Some heuristics to find out what environment we are in: if it is not
99 * System V, assume it is SunOS 4. The LOGIN_PROCESS is defined in System V
100 * utmp.h, which will select System V style getty.
107 * Things you may want to modify.
109 * If ISSUE is not defined, agetty will never display the contents of the
110 * /etc/issue file. You will not want to spit out large "issue" files at the
111 * wrong baud rate. Relevant for System V only.
113 * You may disagree with the default line-editing etc. characters defined
114 * below. Note, however, that DEL cannot be used for interrupt generation
115 * and for line editing at the same time.
118 /* Displayed before the login prompt. */
120 # define ISSUE _PATH_ISSUE
121 # include <sys/utsname.h>
125 #define LOGIN "login: "
126 #define LOGIN_ARGV_MAX 16 /* Numbers of args for login */
132 # include <sys/inotify.h>
133 # include <linux/netlink.h>
134 # include <linux/rtnetlink.h>
135 # define AGETTY_RELOAD_FILENAME "/run/agetty.reload" /* trigger file */
136 # define AGETTY_RELOAD_FDNONE -2 /* uninitialized fd */
137 static int inotify_fd
= AGETTY_RELOAD_FDNONE
;
138 static int netlink_fd
= AGETTY_RELOAD_FDNONE
;
141 #define AGETTY_PLYMOUTH "/usr/bin/plymouth"
142 #define AGETTY_PLYMOUTH_FDFILE "/dev/null"
145 * When multiple baud rates are specified on the command line, the first one
146 * we will try is the first one specified.
148 #define FIRST_SPEED 0
150 /* Storage for command-line options. */
151 #define MAX_SPEED 10 /* max. nr. of baud rates */
154 int flags
; /* toggle switches, see below */
155 unsigned int timeout
; /* time-out period */
156 char *autolog
; /* login the user automatically */
157 char *chdir
; /* Chdir before the login */
158 char *chroot
; /* Chroot before the login */
159 char *login
; /* login program */
160 char *logopt
; /* options for login program */
161 char *tty
; /* name of tty */
162 char *vcline
; /* line of virtual console */
163 char *term
; /* terminal type */
164 char *initstring
; /* modem init string */
165 char *issue
; /* alternative issue file */
166 char *erasechars
; /* string with erase chars */
167 char *killchars
; /* string with kill chars */
168 char *osrelease
; /* /etc/os-release data */
169 unsigned int delay
; /* Sleep seconds before prompt */
170 int nice
; /* Run login with this priority */
171 int numspeed
; /* number of baud rates to try */
172 int clocal
; /* CLOCAL_MODE_* */
173 int kbmode
; /* Keyboard mode if virtual console */
174 speed_t speeds
[MAX_SPEED
]; /* baud rates to be tried */
178 CLOCAL_MODE_AUTO
= 0,
183 #define F_PARSE (1<<0) /* process modem status messages */
184 #define F_ISSUE (1<<1) /* display /etc/issue */
185 #define F_RTSCTS (1<<2) /* enable RTS/CTS flow control */
187 #define F_INITSTRING (1<<4) /* initstring is set */
188 #define F_WAITCRLF (1<<5) /* wait for CR or LF */
189 #define F_CUSTISSUE (1<<6) /* give alternative issue file */
190 #define F_NOPROMPT (1<<7) /* do not ask for login name! */
191 #define F_LCUC (1<<8) /* support for *LCUC stty modes */
192 #define F_KEEPSPEED (1<<9) /* follow baud rate from kernel */
193 #define F_KEEPCFLAGS (1<<10) /* reuse c_cflags setup from kernel */
194 #define F_EIGHTBITS (1<<11) /* Assume 8bit-clean tty */
195 #define F_VCONSOLE (1<<12) /* This is a virtual console */
196 #define F_HANGUP (1<<13) /* Do call vhangup(2) */
197 #define F_UTF8 (1<<14) /* We can do UTF8 */
198 #define F_LOGINPAUSE (1<<15) /* Wait for any key before dropping login prompt */
199 #define F_NOCLEAR (1<<16) /* Do not clear the screen before prompting */
200 #define F_NONL (1<<17) /* No newline before issue */
201 #define F_NOHOSTNAME (1<<18) /* Do not show the hostname */
202 #define F_LONGHNAME (1<<19) /* Show Full qualified hostname */
203 #define F_NOHINTS (1<<20) /* Don't print hints */
204 #define F_REMOTE (1<<21) /* Add '-h fakehost' to login(1) command line */
206 #define serial_tty_option(opt, flag) \
207 (((opt)->flags & (F_VCONSOLE|(flag))) == (flag))
214 static const struct Speedtab speedtab
[] = {
286 static void init_special_char(char* arg
, struct options
*op
);
287 static void parse_args(int argc
, char **argv
, struct options
*op
);
288 static void parse_speeds(struct options
*op
, char *arg
);
289 static void update_utmp(struct options
*op
);
290 static void open_tty(char *tty
, struct termios
*tp
, struct options
*op
);
291 static void termio_init(struct options
*op
, struct termios
*tp
);
292 static void reset_vc (const struct options
*op
, struct termios
*tp
);
293 static void auto_baud(struct termios
*tp
);
294 static void output_special_char (unsigned char c
, struct options
*op
,
295 struct termios
*tp
, FILE *fp
);
296 static void do_prompt(struct options
*op
, struct termios
*tp
);
297 static void next_speed(struct options
*op
, struct termios
*tp
);
298 static char *get_logname(struct options
*op
,
299 struct termios
*tp
, struct chardata
*cp
);
300 static void termio_final(struct options
*op
,
301 struct termios
*tp
, struct chardata
*cp
);
302 static int caps_lock(char *s
);
303 static speed_t
bcode(char *s
);
304 static void usage(FILE * out
) __attribute__((__noreturn__
));
305 static void log_err(const char *, ...) __attribute__((__noreturn__
))
306 __attribute__((__format__(printf
, 1, 2)));
307 static void log_warn (const char *, ...)
308 __attribute__((__format__(printf
, 1, 2)));
309 static ssize_t
append(char *dest
, size_t len
, const char *sep
, const char *src
);
310 static void check_username (const char* nm
);
311 static void login_options_to_argv(char *argv
[], int *argc
, char *str
, char *username
);
312 static int plymouth_command(const char* arg
);
313 static void reload_agettys(void);
315 /* Fake hostname for ut_host specified on command line. */
316 static char *fakehost
;
319 # include "closestream.h"
320 # ifndef DEBUG_OUTPUT
321 # define DEBUG_OUTPUT "/dev/tty10"
323 # define debug(s) do { fprintf(dbf,s); fflush(dbf); } while (0)
326 # define debug(s) do { ; } while (0)
329 int main(int argc
, char **argv
)
331 char *username
= NULL
; /* login name, given to /bin/login */
332 struct chardata chardata
; /* will be set by get_logname() */
333 struct termios termios
; /* terminal mode bits */
334 struct options options
= {
335 .flags
= F_ISSUE
, /* show /etc/issue (SYSV_STYLE) */
336 .login
= _PATH_LOGIN
, /* default login program */
337 .tty
= "tty1", /* default tty line */
338 .issue
= ISSUE
/* default issue file */
340 char *login_argv
[LOGIN_ARGV_MAX
+ 1];
342 struct sigaction sa
, sa_hup
, sa_quit
, sa_int
;
345 setlocale(LC_ALL
, "");
346 bindtextdomain(PACKAGE
, LOCALEDIR
);
349 /* In case vhangup(2) has to called */
350 sa
.sa_handler
= SIG_IGN
;
351 sa
.sa_flags
= SA_RESTART
;
352 sigemptyset (&sa
.sa_mask
);
353 sigaction(SIGHUP
, &sa
, &sa_hup
);
354 sigaction(SIGQUIT
, &sa
, &sa_quit
);
355 sigaction(SIGINT
, &sa
, &sa_int
);
358 dbf
= fopen(DEBUG_OUTPUT
, "w");
359 for (int i
= 1; i
< argc
; i
++) {
365 #endif /* DEBUGGING */
367 /* Parse command-line arguments. */
368 parse_args(argc
, argv
, &options
);
370 login_argv
[login_argc
++] = options
.login
; /* set login program name */
372 /* Update the utmp file. */
374 update_utmp(&options
);
377 sleep(options
.delay
);
379 debug("calling open_tty\n");
381 /* Open the tty as standard { input, output, error }. */
382 open_tty(options
.tty
, &termios
, &options
);
384 /* Unmask SIGHUP if inherited */
386 sigaddset(&set
, SIGHUP
);
387 sigprocmask(SIG_UNBLOCK
, &set
, NULL
);
388 sigaction(SIGHUP
, &sa_hup
, NULL
);
390 tcsetpgrp(STDIN_FILENO
, getpid());
392 /* Default is to follow the current line speend and then default to 9600 */
393 if ((options
.flags
& F_VCONSOLE
) == 0 && options
.numspeed
== 0) {
394 options
.speeds
[options
.numspeed
++] = bcode("9600");
395 options
.flags
|= F_KEEPSPEED
;
398 /* Initialize the termios settings (raw mode, eight-bit, blocking i/o). */
399 debug("calling termio_init\n");
400 termio_init(&options
, &termios
);
402 /* Write the modem init string and DO NOT flush the buffers. */
403 if (serial_tty_option(&options
, F_INITSTRING
) &&
404 options
.initstring
&& *options
.initstring
!= '\0') {
405 debug("writing init string\n");
406 write_all(STDOUT_FILENO
, options
.initstring
,
407 strlen(options
.initstring
));
410 if (options
.flags
& F_VCONSOLE
|| options
.clocal
!= CLOCAL_MODE_ALWAYS
)
411 /* Go to blocking mode unless -L is specified, this change
412 * affects stdout, stdin and stderr as all the file descriptors
413 * are created by dup(). */
414 fcntl(STDOUT_FILENO
, F_SETFL
,
415 fcntl(STDOUT_FILENO
, F_GETFL
, 0) & ~O_NONBLOCK
);
417 /* Optionally detect the baud rate from the modem status message. */
418 debug("before autobaud\n");
419 if (serial_tty_option(&options
, F_PARSE
))
422 /* Set the optional timer. */
424 alarm(options
.timeout
);
426 /* Optionally wait for CR or LF before writing /etc/issue */
427 if (serial_tty_option(&options
, F_WAITCRLF
)) {
430 debug("waiting for cr-lf\n");
431 while (read(STDIN_FILENO
, &ch
, 1) == 1) {
432 /* Strip "parity bit". */
435 fprintf(dbf
, "read %c\n", ch
);
437 if (ch
== '\n' || ch
== '\r')
442 INIT_CHARDATA(&chardata
);
444 if (options
.autolog
) {
445 debug("doing auto login\n");
446 username
= options
.autolog
;
449 if ((options
.flags
& F_NOPROMPT
) == 0) {
450 if (options
.autolog
) {
451 /* Autologin prompt */
452 do_prompt(&options
, &termios
);
453 printf(_("%s%s (automatic login)\n"), LOGIN
, options
.autolog
);
455 /* Read the login name. */
456 debug("reading login name\n");
458 get_logname(&options
, &termios
, &chardata
)) == NULL
)
459 if ((options
.flags
& F_VCONSOLE
) == 0 && options
.numspeed
)
460 next_speed(&options
, &termios
);
468 if ((options
.flags
& F_VCONSOLE
) == 0) {
469 /* Finalize the termios settings. */
470 termio_final(&options
, &termios
, &chardata
);
472 /* Now the newline character should be properly written. */
473 write_all(STDOUT_FILENO
, "\r\n", 2);
476 sigaction(SIGQUIT
, &sa_quit
, NULL
);
477 sigaction(SIGINT
, &sa_int
, NULL
);
480 check_username(username
);
482 if (options
.logopt
) {
484 * The --login-options completely overwrites the default
485 * way how agetty composes login(1) command line.
487 login_options_to_argv(login_argv
, &login_argc
,
488 options
.logopt
, username
);
490 if (fakehost
&& (options
.flags
& F_REMOTE
)) {
491 login_argv
[login_argc
++] = "-h";
492 login_argv
[login_argc
++] = fakehost
;
496 login_argv
[login_argc
++] = "-f";
498 login_argv
[login_argc
++] = "--";
499 login_argv
[login_argc
++] = username
;
503 login_argv
[login_argc
] = NULL
; /* last login argv */
505 if (options
.chroot
) {
506 if (chroot(options
.chroot
) < 0)
507 log_err(_("%s: can't change root directory %s: %m"),
508 options
.tty
, options
.chroot
);
511 if (chdir(options
.chdir
) < 0)
512 log_err(_("%s: can't change working directory %s: %m"),
513 options
.tty
, options
.chdir
);
516 if (nice(options
.nice
) < 0)
517 log_warn(_("%s: can't change process priority: %m"),
520 free(options
.osrelease
);
522 if (close_stream(dbf
) != 0)
523 log_err("write failed: %s", DEBUG_OUTPUT
);
526 /* Let the login program take care of password validation. */
527 execv(options
.login
, login_argv
);
528 log_err(_("%s: can't exec %s: %m"), options
.tty
, login_argv
[0]);
532 * Returns : @str if \u not found
533 * : @username if @str equal to "\u"
534 * : newly allocated string if \u mixed with something other
536 static char *replace_u(char *str
, char *username
)
538 char *entry
= NULL
, *p
= str
;
539 size_t usz
= username
? strlen(username
) : 0;
543 char *tp
, *old
= entry
;
545 if (memcmp(p
, "\\u", 2)) {
547 continue; /* no \u */
551 if (p
== str
&& sz
== 2) {
552 /* 'str' contains only '\u' */
557 tp
= entry
= malloc(sz
+ usz
);
559 log_err(_("failed to allocate memory: %m"));
562 /* copy chars befor \u */
563 memcpy(tp
, str
, p
- str
);
568 memcpy(tp
, username
, usz
);
572 /* copy chars after \u + \0 */
573 memcpy(tp
, p
+ 2, sz
- (p
- str
) - 1);
582 return entry
? entry
: str
;
585 static void login_options_to_argv(char *argv
[], int *argc
,
586 char *str
, char *username
)
591 while (str
&& isspace(*str
))
595 while (p
&& *p
&& i
< LOGIN_ARGV_MAX
) {
598 while (isspace(*++p
))
601 argv
[i
++] = replace_u(str
, username
);
607 if (str
&& *str
&& i
< LOGIN_ARGV_MAX
)
608 argv
[i
++] = replace_u(str
, username
);
612 #define is_speed(str) (strlen((str)) == strspn((str), "0123456789,"))
614 /* Parse command-line arguments. */
615 static void parse_args(int argc
, char **argv
, struct options
*op
)
620 VERSION_OPTION
= CHAR_MAX
+ 1,
629 const struct option longopts
[] = {
630 { "8bits", no_argument
, 0, '8' },
631 { "autologin", required_argument
, 0, 'a' },
632 { "noreset", no_argument
, 0, 'c' },
633 { "chdir", required_argument
, 0, 'C' },
634 { "delay", required_argument
, 0, 'd' },
635 { "remote", no_argument
, 0, 'E' },
636 { "issue-file", required_argument
, 0, 'f' },
637 { "flow-control", no_argument
, 0, 'h' },
638 { "host", required_argument
, 0, 'H' },
639 { "noissue", no_argument
, 0, 'i' },
640 { "init-string", required_argument
, 0, 'I' },
641 { "noclear", no_argument
, 0, 'J' },
642 { "login-program", required_argument
, 0, 'l' },
643 { "local-line", optional_argument
, 0, 'L' },
644 { "extract-baud", no_argument
, 0, 'm' },
645 { "skip-login", no_argument
, 0, 'n' },
646 { "nonewline", no_argument
, 0, 'N' },
647 { "login-options", required_argument
, 0, 'o' },
648 { "login-pause", no_argument
, 0, 'p' },
649 { "nice", required_argument
, 0, 'P' },
650 { "chroot", required_argument
, 0, 'r' },
651 { "hangup", no_argument
, 0, 'R' },
652 { "keep-baud", no_argument
, 0, 's' },
653 { "timeout", required_argument
, 0, 't' },
654 { "detect-case", no_argument
, 0, 'U' },
655 { "wait-cr", no_argument
, 0, 'w' },
656 { "nohints", no_argument
, 0, NOHINTS_OPTION
},
657 { "nohostname", no_argument
, 0, NOHOSTNAME_OPTION
},
658 { "long-hostname", no_argument
, 0, LONGHOSTNAME_OPTION
},
659 { "reload", no_argument
, 0, RELOAD_OPTION
},
660 { "version", no_argument
, 0, VERSION_OPTION
},
661 { "help", no_argument
, 0, HELP_OPTION
},
662 { "erase-chars", required_argument
, 0, ERASE_CHARS_OPTION
},
663 { "kill-chars", required_argument
, 0, KILL_CHARS_OPTION
},
667 while ((c
= getopt_long(argc
, argv
,
668 "8a:cC:d:Ef:hH:iI:Jl:L::mnNo:pP:r:Rst:Uw", longopts
,
672 op
->flags
|= F_EIGHTBITS
;
675 op
->autolog
= optarg
;
678 op
->flags
|= F_KEEPCFLAGS
;
684 op
->delay
= strtou32_or_err(optarg
, _("invalid delay argument"));
687 op
->flags
|= F_REMOTE
;
690 op
->flags
|= F_CUSTISSUE
;
694 op
->flags
|= F_RTSCTS
;
700 op
->flags
&= ~F_ISSUE
;
703 init_special_char(optarg
, op
);
704 op
->flags
|= F_INITSTRING
;
707 op
->flags
|= F_NOCLEAR
;
713 /* -L and -L=always have the same meaning */
714 op
->clocal
= CLOCAL_MODE_ALWAYS
;
716 if (strcmp(optarg
, "=always") == 0)
717 op
->clocal
= CLOCAL_MODE_ALWAYS
;
718 else if (strcmp(optarg
, "=never") == 0)
719 op
->clocal
= CLOCAL_MODE_NEVER
;
720 else if (strcmp(optarg
, "=auto") == 0)
721 op
->clocal
= CLOCAL_MODE_AUTO
;
723 log_err(_("invalid argument of --local-line"));
727 op
->flags
|= F_PARSE
;
730 op
->flags
|= F_NOPROMPT
;
739 op
->flags
|= F_LOGINPAUSE
;
742 op
->nice
= strtos32_or_err(optarg
, _("invalid nice argument"));
748 op
->flags
|= F_HANGUP
;
751 op
->flags
|= F_KEEPSPEED
;
754 op
->timeout
= strtou32_or_err(optarg
, _("invalid timeout argument"));
760 op
->flags
|= F_WAITCRLF
;
763 op
->flags
|= F_NOHINTS
;
765 case NOHOSTNAME_OPTION
:
766 op
->flags
|= F_NOHOSTNAME
;
768 case LONGHOSTNAME_OPTION
:
769 op
->flags
|= F_LONGHNAME
;
771 case ERASE_CHARS_OPTION
:
772 op
->erasechars
= optarg
;
774 case KILL_CHARS_OPTION
:
775 op
->killchars
= optarg
;
781 printf(UTIL_LINUX_VERSION
);
790 debug("after getopt loop\n");
792 if (argc
< optind
+ 1) {
793 log_warn(_("not enough arguments"));
797 /* Accept "tty", "baudrate tty", and "tty baudrate". */
798 if (is_speed(argv
[optind
])) {
799 /* Assume BSD style speed. */
800 parse_speeds(op
, argv
[optind
++]);
801 if (argc
< optind
+ 1) {
802 warn(_("not enough arguments"));
805 op
->tty
= argv
[optind
++];
807 op
->tty
= argv
[optind
++];
809 char *v
= argv
[optind
];
817 /* On virtual console remember the line which is used for */
818 if (strncmp(op
->tty
, "tty", 3) == 0 &&
819 strspn(op
->tty
+ 3, "0123456789") == strlen(op
->tty
+3))
820 op
->vcline
= op
->tty
+3;
822 if (argc
> optind
&& argv
[optind
])
823 op
->term
= argv
[optind
];
825 #ifdef DO_DEVFS_FIDDLING
827 * Some devfs junk, following Goswin Brederlow:
828 * turn ttyS<n> into tts/<n>
829 * turn tty<n> into vc/<n>
830 * http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=72241
832 if (op
->tty
&& strlen(op
->tty
) < 90) {
836 if (strncmp(op
->tty
, "ttyS", 4) == 0) {
837 strcpy(dev_name
, "/dev/");
838 strcat(dev_name
, op
->tty
);
839 if (stat(dev_name
, &st
) < 0) {
840 strcpy(dev_name
, "/dev/tts/");
841 strcat(dev_name
, op
->tty
+ 4);
842 if (stat(dev_name
, &st
) == 0) {
843 op
->tty
= strdup(dev_name
+ 5);
845 log_err(_("failed to allocate memory: %m"));
848 } else if (strncmp(op
->tty
, "tty", 3) == 0) {
849 strcpy(dev_name
, "/dev/");
850 strncat(dev_name
, op
->tty
, 90);
851 if (stat(dev_name
, &st
) < 0) {
852 strcpy(dev_name
, "/dev/vc/");
853 strcat(dev_name
, op
->tty
+ 3);
854 if (stat(dev_name
, &st
) == 0) {
855 op
->tty
= strdup(dev_name
+ 5);
857 log_err(_("failed to allocate memory: %m"));
862 #endif /* DO_DEVFS_FIDDLING */
864 debug("exiting parseargs\n");
867 /* Parse alternate baud rates. */
868 static void parse_speeds(struct options
*op
, char *arg
)
872 debug("entered parse_speeds\n");
873 for (cp
= strtok(arg
, ","); cp
!= NULL
; cp
= strtok((char *)0, ",")) {
874 if ((op
->speeds
[op
->numspeed
++] = bcode(cp
)) <= 0)
875 log_err(_("bad speed: %s"), cp
);
876 if (op
->numspeed
>= MAX_SPEED
)
877 log_err(_("too many alternate speeds"));
879 debug("exiting parsespeeds\n");
884 /* Update our utmp entry. */
885 static void update_utmp(struct options
*op
)
889 pid_t pid
= getpid();
890 pid_t sid
= getsid(0);
891 char *vcline
= op
->vcline
;
892 char *line
= op
->tty
;
896 * The utmp file holds miscellaneous information about things started by
897 * /sbin/init and other system-related events. Our purpose is to update
898 * the utmp entry for the current process, in particular the process type
899 * and the tty line we are listening to. Return successfully only if the
900 * utmp file can be opened for update, and if we are able to find our
901 * entry in the utmp file.
903 utmpname(_PATH_UTMP
);
907 * Find my pid in utmp.
909 * FIXME: Earlier (when was that?) code here tested only utp->ut_type !=
910 * INIT_PROCESS, so maybe the >= here should be >.
912 * FIXME: The present code is taken from login.c, so if this is changed,
913 * maybe login has to be changed as well (is this true?).
915 while ((utp
= getutent()))
916 if (utp
->ut_pid
== pid
917 && utp
->ut_type
>= INIT_PROCESS
918 && utp
->ut_type
<= DEAD_PROCESS
)
922 memcpy(&ut
, utp
, sizeof(ut
));
924 /* Some inits do not initialize utmp. */
925 memset(&ut
, 0, sizeof(ut
));
926 if (vcline
&& *vcline
)
927 /* Standard virtual console devices */
928 strncpy(ut
.ut_id
, vcline
, sizeof(ut
.ut_id
));
930 size_t len
= strlen(line
);
932 if (len
>= sizeof(ut
.ut_id
))
933 ptr
= line
+ len
- sizeof(ut
.ut_id
);
936 strncpy(ut
.ut_id
, ptr
, sizeof(ut
.ut_id
));
940 strncpy(ut
.ut_user
, "LOGIN", sizeof(ut
.ut_user
));
941 strncpy(ut
.ut_line
, line
, sizeof(ut
.ut_line
));
943 strncpy(ut
.ut_host
, fakehost
, sizeof(ut
.ut_host
));
945 #if defined(_HAVE_UT_TV)
950 ut
.ut_type
= LOGIN_PROCESS
;
959 updwtmp(_PATH_WTMP
, &ut
);
964 if ((lf
= open(_PATH_WTMPLOCK
, O_CREAT
| O_WRONLY
, 0660)) >= 0) {
967 open(_PATH_WTMP
, O_APPEND
| O_WRONLY
)) >= 0) {
968 write_all(ut_fd
, &ut
, sizeof(ut
));
974 #endif /* HAVE_UPDWTMP */
978 #endif /* SYSV_STYLE */
980 /* Set up tty as stdin, stdout & stderr. */
981 static void open_tty(char *tty
, struct termios
*tp
, struct options
*op
)
983 const pid_t pid
= getpid();
989 /* Set up new standard input, unless we are given an already opened port. */
991 if (strcmp(tty
, "-") != 0) {
992 char buf
[PATH_MAX
+1];
993 struct group
*gr
= NULL
;
999 /* Use tty group if available */
1000 if ((gr
= getgrnam("tty")))
1003 len
= snprintf(buf
, sizeof(buf
), "/dev/%s", tty
);
1004 if (len
< 0 || (size_t)len
>= sizeof(buf
))
1005 log_err(_("/dev/%s: cannot open as standard input: %m"), tty
);
1007 /* Open the tty as standard input. */
1008 if ((fd
= open(buf
, O_RDWR
|O_NOCTTY
|O_NONBLOCK
, 0)) < 0)
1009 log_err(_("/dev/%s: cannot open as standard input: %m"), tty
);
1012 * There is always a race between this reset and the call to
1013 * vhangup() that s.o. can use to get access to your tty.
1014 * Linux login(1) will change tty permissions. Use root owner and group
1015 * with permission -rw------- for the period between getty and login.
1017 if (fchown(fd
, 0, gid
) || fchmod(fd
, (gid
? 0620 : 0600))) {
1019 log_warn("%s: %m", buf
);
1021 log_err("%s: %m", buf
);
1024 /* Sanity checks... */
1025 if (fstat(fd
, &st
) < 0)
1026 log_err("%s: %m", buf
);
1027 if ((st
.st_mode
& S_IFMT
) != S_IFCHR
)
1028 log_err(_("/dev/%s: not a character device"), tty
);
1030 log_err(_("/dev/%s: not a tty"), tty
);
1032 if (((tid
= tcgetsid(fd
)) < 0) || (pid
!= tid
)) {
1033 if (ioctl(fd
, TIOCSCTTY
, 1) == -1)
1034 log_warn(_("/dev/%s: cannot get controlling tty: %m"), tty
);
1037 close(STDIN_FILENO
);
1040 if (op
->flags
& F_HANGUP
) {
1042 if (ioctl(fd
, TIOCNOTTY
))
1043 debug("TIOCNOTTY ioctl failed\n");
1046 * Let's close all file decriptors before vhangup
1047 * https://lkml.org/lkml/2012/6/5/145
1050 close(STDOUT_FILENO
);
1051 close(STDERR_FILENO
);
1056 log_err(_("/dev/%s: vhangup() failed: %m"), tty
);
1061 if (open(buf
, O_RDWR
|O_NOCTTY
|O_NONBLOCK
, 0) != 0)
1062 log_err(_("/dev/%s: cannot open as standard input: %m"), tty
);
1064 if (((tid
= tcgetsid(STDIN_FILENO
)) < 0) || (pid
!= tid
)) {
1065 if (ioctl(STDIN_FILENO
, TIOCSCTTY
, 1) == -1)
1066 log_warn(_("/dev/%s: cannot get controlling tty: %m"), tty
);
1072 * Standard input should already be connected to an open port. Make
1073 * sure it is open for read/write.
1076 if ((fcntl(STDIN_FILENO
, F_GETFL
, 0) & O_RDWR
) != O_RDWR
)
1077 log_err(_("%s: not open for read/write"), tty
);
1081 if (tcsetpgrp(STDIN_FILENO
, pid
))
1082 log_warn(_("/dev/%s: cannot set process group: %m"), tty
);
1084 /* Get rid of the present outputs. */
1086 close(STDOUT_FILENO
);
1087 close(STDERR_FILENO
);
1091 /* Set up standard output and standard error file descriptors. */
1094 /* set up stdout and stderr */
1095 if (dup(STDIN_FILENO
) != 1 || dup(STDIN_FILENO
) != 2)
1096 log_err(_("%s: dup problem: %m"), tty
);
1098 /* make stdio unbuffered for slow modem lines */
1099 setvbuf(stdout
, NULL
, _IONBF
, 0);
1102 * The following ioctl will fail if stdin is not a tty, but also when
1103 * there is noise on the modem control lines. In the latter case, the
1104 * common course of action is (1) fix your cables (2) give the modem
1105 * more time to properly reset after hanging up.
1107 * SunOS users can achieve (2) by patching the SunOS kernel variable
1108 * "zsadtrlow" to a larger value; 5 seconds seems to be a good value.
1109 * http://www.sunmanagers.org/archives/1993/0574.html
1111 memset(tp
, 0, sizeof(struct termios
));
1112 if (tcgetattr(STDIN_FILENO
, tp
) < 0)
1113 log_err(_("%s: failed to get terminal attributes: %m"), tty
);
1115 #if defined (__s390__) || defined (__s390x__)
1118 * Special terminal on first serial line on a S/390(x) which
1119 * is due legacy reasons a block terminal of type 3270 or
1120 * higher. Whereas the second serial line on a S/390(x) is
1121 * a real character terminal which is compatible with VT220.
1123 if (strcmp(op
->tty
, "ttyS0") == 0) /* linux/drivers/s390/char/con3215.c */
1124 op
->term
= DEFAULT_TTYS0
;
1125 else if (strncmp(op
->tty
, "3270/tty", 8) == 0) /* linux/drivers/s390/char/con3270.c */
1126 op
->term
= DEFAULT_TTY32
;
1127 else if (strcmp(op
->tty
, "ttyS1") == 0) /* linux/drivers/s390/char/sclp_vt220.c */
1128 op
->term
= DEFAULT_TTYS1
;
1132 #if defined(__FreeBSD_kernel__)
1137 * Detect if this is a virtual console or serial/modem line.
1138 * In case of a virtual console the ioctl KDGKBMODE succeeds
1139 * whereas on other lines it will fails.
1142 if (ioctl(STDIN_FILENO
, KDGKBMODE
, &op
->kbmode
) == 0)
1144 if (ioctl(STDIN_FILENO
, TIOCMGET
, &serial
) < 0 && (errno
== EINVAL
))
1147 op
->flags
|= F_VCONSOLE
;
1149 op
->term
= DEFAULT_VCTERM
;
1155 op
->term
= DEFAULT_STERM
;
1158 setenv("TERM", op
->term
, 1);
1161 /* Initialize termios settings. */
1162 static void termio_clear(int fd
)
1165 * Do not write a full reset (ESC c) because this destroys
1166 * the unicode mode again if the terminal was in unicode
1167 * mode. Also it clears the CONSOLE_MAGIC features which
1168 * are required for some languages/console-fonts.
1169 * Just put the cursor to the home position (ESC [ H),
1170 * erase everything below the cursor (ESC [ J), and set the
1171 * scrolling region to the full window (ESC [ r)
1173 write_all(fd
, "\033[r\033[H\033[J", 9);
1176 /* Initialize termios settings. */
1177 static void termio_init(struct options
*op
, struct termios
*tp
)
1179 speed_t ispeed
, ospeed
;
1181 struct termios lock
;
1182 #ifdef TIOCGLCKTRMIOS
1183 int i
= (plymouth_command("--ping") == 0) ? 30 : 0;
1187 * Even with TTYReset=no it seems with systemd or plymouth
1188 * the termios flags become changed from under the first
1189 * agetty on a serial system console as the flags are locked.
1191 memset(&lock
, 0, sizeof(struct termios
));
1192 if (ioctl(STDIN_FILENO
, TIOCGLCKTRMIOS
, &lock
) < 0)
1194 if (!lock
.c_iflag
&& !lock
.c_oflag
&& !lock
.c_cflag
&& !lock
.c_lflag
)
1196 debug("termios locked\n");
1197 if (i
== 15 && plymouth_command("quit") != 0)
1201 memset(&lock
, 0, sizeof(struct termios
));
1202 ioctl(STDIN_FILENO
, TIOCSLCKTRMIOS
, &lock
);
1205 if (op
->flags
& F_VCONSOLE
) {
1206 #if defined(IUTF8) && defined(KDGKBMODE)
1207 switch(op
->kbmode
) {
1209 setlocale(LC_CTYPE
, "C.UTF-8");
1210 op
->flags
|= F_UTF8
;
1216 setlocale(LC_CTYPE
, "POSIX");
1217 op
->flags
&= ~F_UTF8
;
1221 setlocale(LC_CTYPE
, "POSIX");
1222 op
->flags
&= ~F_UTF8
;
1226 if ((tp
->c_cflag
& (CS8
|PARODD
|PARENB
)) == CS8
)
1227 op
->flags
|= F_EIGHTBITS
;
1229 if ((op
->flags
& F_NOCLEAR
) == 0)
1230 termio_clear(STDOUT_FILENO
);
1238 if (op
->flags
& F_KEEPSPEED
|| !op
->numspeed
) {
1239 /* Save the original setting. */
1240 ispeed
= cfgetispeed(tp
);
1241 ospeed
= cfgetospeed(tp
);
1243 if (!ispeed
) ispeed
= TTYDEF_SPEED
;
1244 if (!ospeed
) ospeed
= TTYDEF_SPEED
;
1247 ospeed
= ispeed
= op
->speeds
[FIRST_SPEED
];
1251 * Initial termios settings: 8-bit characters, raw-mode, blocking i/o.
1252 * Special characters are set after we have read the login name; all
1253 * reads will be done in raw mode anyway. Errors will be dealt with
1258 tp
->c_iflag
= tp
->c_iflag
& IUTF8
;
1259 if (tp
->c_iflag
& IUTF8
)
1260 op
->flags
|= F_UTF8
;
1265 tp
->c_oflag
&= OPOST
| ONLCR
;
1267 if ((op
->flags
& F_KEEPCFLAGS
) == 0)
1268 tp
->c_cflag
= CS8
| HUPCL
| CREAD
| (tp
->c_cflag
& CLOCAL
);
1271 * Note that the speed is stored in the c_cflag termios field, so we have
1272 * set the speed always when the cflag se reseted.
1274 cfsetispeed(tp
, ispeed
);
1275 cfsetospeed(tp
, ospeed
);
1277 /* The default is to follow setting from kernel, but it's possible
1278 * to explicitly remove/add CLOCAL flag by -L[=<mode>]*/
1279 switch (op
->clocal
) {
1280 case CLOCAL_MODE_ALWAYS
:
1281 tp
->c_cflag
|= CLOCAL
; /* -L or -L=always */
1283 case CLOCAL_MODE_NEVER
:
1284 tp
->c_cflag
&= ~CLOCAL
; /* -L=never */
1286 case CLOCAL_MODE_AUTO
: /* -L=auto */
1290 #ifdef HAVE_STRUCT_TERMIOS_C_LINE
1294 tp
->c_cc
[VTIME
] = 0;
1296 /* Check for terminal size and if not found set default */
1297 if (ioctl(STDIN_FILENO
, TIOCGWINSZ
, &ws
) == 0) {
1299 if (ws
.ws_row
== 0) {
1303 if (ws
.ws_col
== 0) {
1307 if (ioctl(STDIN_FILENO
, TIOCSWINSZ
, &ws
))
1308 debug("TIOCSWINSZ ioctl failed\n");
1311 /* Optionally enable hardware flow control. */
1313 if (op
->flags
& F_RTSCTS
)
1314 tp
->c_cflag
|= CRTSCTS
;
1316 /* Flush input and output queues, important for modems! */
1317 tcflush(STDIN_FILENO
, TCIOFLUSH
);
1319 if (tcsetattr(STDIN_FILENO
, TCSANOW
, tp
))
1320 log_warn(_("setting terminal attributes failed: %m"));
1322 /* Go to blocking input even in local mode. */
1323 fcntl(STDIN_FILENO
, F_SETFL
,
1324 fcntl(STDIN_FILENO
, F_GETFL
, 0) & ~O_NONBLOCK
);
1326 debug("term_io 2\n");
1329 /* Reset virtual console on stdin to its defaults */
1330 static void reset_vc(const struct options
*op
, struct termios
*tp
)
1334 fl
|= (op
->flags
& F_KEEPCFLAGS
) == 0 ? 0 : UL_TTY_KEEPCFLAGS
;
1335 fl
|= (op
->flags
& F_UTF8
) == 0 ? 0 : UL_TTY_UTF8
;
1337 reset_virtual_console(tp
, fl
);
1339 if (tcsetattr(STDIN_FILENO
, TCSADRAIN
, tp
))
1340 log_warn(_("setting terminal attributes failed: %m"));
1342 /* Go to blocking input even in local mode. */
1343 fcntl(STDIN_FILENO
, F_SETFL
,
1344 fcntl(STDIN_FILENO
, F_GETFL
, 0) & ~O_NONBLOCK
);
1347 /* Extract baud rate from modem status message. */
1348 static void auto_baud(struct termios
*tp
)
1358 * This works only if the modem produces its status code AFTER raising
1359 * the DCD line, and if the computer is fast enough to set the proper
1360 * baud rate before the message has gone by. We expect a message of the
1363 * <junk><number><junk>
1365 * The number is interpreted as the baud rate of the incoming call. If the
1366 * modem does not tell us the baud rate within one second, we will keep
1367 * using the current baud rate. It is advisable to enable BREAK
1368 * processing (comma-separated list of baud rates) if the processing of
1369 * modem status messages is enabled.
1373 * Use 7-bit characters, don't block if input queue is empty. Errors will
1374 * be dealt with later on.
1376 iflag
= tp
->c_iflag
;
1377 /* Enable 8th-bit stripping. */
1378 tp
->c_iflag
|= ISTRIP
;
1379 vmin
= tp
->c_cc
[VMIN
];
1380 /* Do not block when queue is empty. */
1382 tcsetattr(STDIN_FILENO
, TCSANOW
, tp
);
1385 * Wait for a while, then read everything the modem has said so far and
1386 * try to extract the speed of the dial-in call.
1389 if ((nread
= read(STDIN_FILENO
, buf
, sizeof(buf
) - 1)) > 0) {
1391 for (bp
= buf
; bp
< buf
+ nread
; bp
++)
1392 if (isascii(*bp
) && isdigit(*bp
)) {
1393 if ((speed
= bcode(bp
))) {
1394 cfsetispeed(tp
, speed
);
1395 cfsetospeed(tp
, speed
);
1401 /* Restore terminal settings. Errors will be dealt with later on. */
1402 tp
->c_iflag
= iflag
;
1403 tp
->c_cc
[VMIN
] = vmin
;
1404 tcsetattr(STDIN_FILENO
, TCSANOW
, tp
);
1407 static char *xgethostname(void)
1410 size_t sz
= get_hostname_max() + 1;
1412 name
= malloc(sizeof(char) * sz
);
1414 log_err(_("failed to allocate memory: %m"));
1416 if (gethostname(name
, sz
) != 0) {
1420 name
[sz
- 1] = '\0';
1424 static char *xgetdomainname(void)
1426 #ifdef HAVE_GETDOMAINNAME
1428 size_t sz
= get_hostname_max() + 1;
1430 name
= malloc(sizeof(char) * sz
);
1432 log_err(_("failed to allocate memory: %m"));
1434 if (getdomainname(name
, sz
) != 0) {
1438 name
[sz
- 1] = '\0';
1444 static char *read_os_release(struct options
*op
, const char *varname
)
1448 size_t varsz
= strlen(varname
);
1449 char *p
, *buf
= NULL
, *ret
= NULL
;
1451 /* read the file only once */
1452 if (!op
->osrelease
) {
1453 fd
= open(_PATH_OS_RELEASE_ETC
, O_RDONLY
);
1455 fd
= open(_PATH_OS_RELEASE_USR
, O_RDONLY
);
1457 log_warn(_("cannot open os-release file"));
1462 if (fstat(fd
, &st
) < 0 || st
.st_size
> 4 * 1024 * 1024)
1465 op
->osrelease
= malloc(st
.st_size
+ 1);
1467 log_err(_("failed to allocate memory: %m"));
1468 if (read_all(fd
, op
->osrelease
, st
.st_size
) != (ssize_t
) st
.st_size
) {
1469 free(op
->osrelease
);
1470 op
->osrelease
= NULL
;
1473 op
->osrelease
[st
.st_size
] = 0;
1475 buf
= strdup(op
->osrelease
);
1477 log_err(_("failed to allocate memory: %m"));
1483 p
+= strspn(p
, "\n\r");
1484 p
+= strspn(p
, " \t\n\r");
1487 if (strspn(p
, "#;\n") != 0) {
1488 p
+= strcspn(p
, "\n\r");
1491 if (strncmp(p
, varname
, varsz
) != 0) {
1492 p
+= strcspn(p
, "\n\r");
1496 p
+= strspn(p
, " \t\n\r=\"");
1497 eol
= p
+ strcspn(p
, "\n\r");
1501 if (*eon
== '\t' || *eon
== ' ') {
1514 log_err(_("failed to allocate memory: %m"));
1524 #ifdef AGETTY_RELOAD
1525 static void open_netlink(void)
1527 struct sockaddr_nl addr
= { 0, };
1530 if (netlink_fd
!= AGETTY_RELOAD_FDNONE
)
1533 sock
= socket(AF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
1535 addr
.nl_family
= AF_NETLINK
;
1536 addr
.nl_pid
= getpid();
1537 addr
.nl_groups
= RTMGRP_IPV4_IFADDR
| RTMGRP_IPV6_IFADDR
;
1538 if (bind(sock
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
1545 static int process_netlink_msg(int *changed
)
1548 struct sockaddr_nl snl
;
1552 struct iovec iov
= {
1554 .iov_len
= sizeof(buf
)
1556 struct msghdr msg
= {
1558 .msg_namelen
= sizeof(snl
),
1561 .msg_control
= NULL
,
1562 .msg_controllen
= 0,
1566 rc
= recvmsg(netlink_fd
, &msg
, MSG_DONTWAIT
);
1568 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
1571 /* Failure, just stop listening for changes */
1573 netlink_fd
= AGETTY_RELOAD_FDNONE
;
1577 for (h
= (struct nlmsghdr
*)buf
; NLMSG_OK(h
, (unsigned int)rc
); h
= NLMSG_NEXT(h
, rc
)) {
1578 if (h
->nlmsg_type
== NLMSG_DONE
||
1579 h
->nlmsg_type
== NLMSG_ERROR
) {
1581 netlink_fd
= AGETTY_RELOAD_FDNONE
;
1592 static int process_netlink(void)
1595 while (process_netlink_msg(&changed
));
1599 static int wait_for_term_input(int fd
)
1601 char buffer
[sizeof(struct inotify_event
) + NAME_MAX
+ 1];
1602 struct termios orig
, nonc
;
1606 /* Our aim here is to fall through if something fails
1607 * and not be stuck waiting. On failure assume we have input */
1609 if (tcgetattr(fd
, &orig
) != 0)
1612 memcpy(&nonc
, &orig
, sizeof (nonc
));
1613 nonc
.c_lflag
&= ~(ICANON
| ECHO
| ECHOE
| ECHOK
| ECHOKE
);
1614 nonc
.c_cc
[VMIN
] = 1;
1615 nonc
.c_cc
[VTIME
] = 0;
1617 if (tcsetattr(fd
, TCSANOW
, &nonc
) != 0)
1620 if (inotify_fd
== AGETTY_RELOAD_FDNONE
) {
1621 /* make sure the reload trigger file exists */
1622 int reload_fd
= open(AGETTY_RELOAD_FILENAME
,
1623 O_CREAT
|O_CLOEXEC
|O_RDONLY
,
1626 /* initialize reload trigger inotify stuff */
1627 if (reload_fd
>= 0) {
1628 inotify_fd
= inotify_init1(IN_NONBLOCK
| IN_CLOEXEC
);
1630 inotify_add_watch(inotify_fd
, AGETTY_RELOAD_FILENAME
,
1631 IN_ATTRIB
| IN_MODIFY
);
1635 log_warn(_("failed to create reload file: %s: %m"),
1636 AGETTY_RELOAD_FILENAME
);
1645 if (inotify_fd
>= 0) {
1646 FD_SET(inotify_fd
, &rfds
);
1647 nfds
= max(nfds
, inotify_fd
);
1649 if (netlink_fd
>= 0) {
1650 FD_SET(netlink_fd
, &rfds
);
1651 nfds
= max(nfds
, netlink_fd
);
1654 /* If waiting fails, just fall through, presumably reading input will fail */
1655 if (select(nfds
+ 1, &rfds
, NULL
, NULL
, NULL
) < 0)
1658 if (FD_ISSET(fd
, &rfds
)) {
1659 count
= read(fd
, buffer
, sizeof (buffer
));
1661 tcsetattr(fd
, TCSANOW
, &orig
);
1663 /* Reinject the bytes we read back into the buffer, usually just one byte */
1664 for (i
= 0; i
< count
; i
++)
1665 ioctl(fd
, TIOCSTI
, buffer
+ i
);
1667 /* Have terminal input */
1670 } else if (netlink_fd
>= 0 && FD_ISSET(netlink_fd
, &rfds
)) {
1671 if (!process_netlink())
1674 /* Just drain the inotify buffer */
1675 } else if (inotify_fd
>= 0 && FD_ISSET(inotify_fd
, &rfds
)) {
1676 while (read(inotify_fd
, buffer
, sizeof (buffer
)) > 0);
1679 tcsetattr(fd
, TCSANOW
, &orig
);
1681 /* Need to reprompt */
1685 #endif /* AGETTY_RELOAD */
1686 static void print_issue_file(struct options
*op
, struct termios
*tp
)
1691 if ((op
->flags
& F_NONL
) == 0) {
1692 /* Issue not in use, start with a new line. */
1693 write_all(STDOUT_FILENO
, "\r\n", 2);
1697 if ((op
->flags
& F_ISSUE
) && (fd
= fopen(op
->issue
, "r"))) {
1698 int c
, oflag
= tp
->c_oflag
; /* Save current setting. */
1700 if ((op
->flags
& F_VCONSOLE
) == 0) {
1701 /* Map new line in output to carriage return & new line. */
1702 tp
->c_oflag
|= (ONLCR
| OPOST
);
1703 tcsetattr(STDIN_FILENO
, TCSADRAIN
, tp
);
1706 while ((c
= getc(fd
)) != EOF
) {
1708 output_special_char(getc(fd
), op
, tp
, fd
);
1714 if ((op
->flags
& F_VCONSOLE
) == 0) {
1715 /* Restore settings. */
1716 tp
->c_oflag
= oflag
;
1717 /* Wait till output is gone. */
1718 tcsetattr(STDIN_FILENO
, TCSADRAIN
, tp
);
1725 /* Show login prompt, optionally preceded by /etc/issue contents. */
1726 static void do_prompt(struct options
*op
, struct termios
*tp
)
1729 print_issue_file(op
, tp
);
1731 if (op
->flags
& F_LOGINPAUSE
) {
1732 puts(_("[press ENTER to login]"));
1733 #ifdef AGETTY_RELOAD
1734 if (!wait_for_term_input(STDIN_FILENO
)) {
1736 if (op
->flags
& F_VCONSOLE
)
1737 termio_clear(STDOUT_FILENO
);
1744 if (!(op
->flags
& F_NOHINTS
) && !op
->autolog
&&
1745 (op
->flags
& F_VCONSOLE
)) {
1748 if (ioctl(STDIN_FILENO
, KDGKBLED
, &kb
) == 0) {
1749 char hint
[256] = { '\0' };
1752 if (access(_PATH_NUMLOCK_ON
, F_OK
) == 0)
1755 if (nl
&& (kb
& 0x02) == 0)
1756 append(hint
, sizeof(hint
), NULL
, _("Num Lock off"));
1758 else if (nl
== 0 && (kb
& 2) && (kb
& 0x20) == 0)
1759 append(hint
, sizeof(hint
), NULL
, _("Num Lock on"));
1761 if ((kb
& 0x04) && (kb
& 0x40) == 0)
1762 append(hint
, sizeof(hint
), ", ", _("Caps Lock on"));
1764 if ((kb
& 0x01) && (kb
& 0x10) == 0)
1765 append(hint
, sizeof(hint
), ", ", _("Scroll Lock on"));
1768 printf(_("Hint: %s\n\n"), hint
);
1771 #endif /* KDGKBLED */
1772 if ((op
->flags
& F_NOHOSTNAME
) == 0) {
1773 char *hn
= xgethostname();
1776 char *dot
= strchr(hn
, '.');
1778 struct addrinfo
*res
= NULL
;
1780 if ((op
->flags
& F_LONGHNAME
) == 0) {
1784 } else if (dot
== NULL
) {
1785 struct addrinfo hints
;
1787 memset(&hints
, 0, sizeof(hints
));
1788 hints
.ai_flags
= AI_CANONNAME
;
1790 if (!getaddrinfo(hn
, NULL
, &hints
, &res
)
1791 && res
&& res
->ai_canonname
)
1792 cn
= res
->ai_canonname
;
1795 write_all(STDOUT_FILENO
, cn
, strlen(cn
));
1796 write_all(STDOUT_FILENO
, " ", 1);
1804 /* Always show login prompt. */
1805 write_all(STDOUT_FILENO
, LOGIN
, sizeof(LOGIN
) - 1);
1809 /* Select next baud rate. */
1810 static void next_speed(struct options
*op
, struct termios
*tp
)
1812 static int baud_index
= -1;
1814 if (baud_index
== -1)
1816 * If the F_KEEPSPEED flags is set then the FIRST_SPEED is not
1817 * tested yet (see termio_init()).
1820 (op
->flags
& F_KEEPSPEED
) ? FIRST_SPEED
: 1 % op
->numspeed
;
1822 baud_index
= (baud_index
+ 1) % op
->numspeed
;
1824 cfsetispeed(tp
, op
->speeds
[baud_index
]);
1825 cfsetospeed(tp
, op
->speeds
[baud_index
]);
1826 tcsetattr(STDIN_FILENO
, TCSANOW
, tp
);
1829 /* Get user name, establish parity, speed, erase, kill & eol. */
1830 static char *get_logname(struct options
*op
, struct termios
*tp
, struct chardata
*cp
)
1832 static char logname
[BUFSIZ
];
1834 char c
; /* input character, full eight bits */
1835 char ascval
; /* low 7 bits of input character */
1837 static char *erase
[] = { /* backspace-space-backspace */
1838 "\010\040\010", /* space parity */
1839 "\010\040\010", /* odd parity */
1840 "\210\240\210", /* even parity */
1841 "\210\240\210", /* no parity */
1844 /* Initialize kill, erase, parity etc. (also after switching speeds). */
1848 * Flush pending input (especially important after parsing or switching
1851 if ((op
->flags
& F_VCONSOLE
) == 0)
1853 tcflush(STDIN_FILENO
, TCIFLUSH
);
1855 eightbit
= (op
->flags
& F_EIGHTBITS
);
1859 while (*logname
== '\0') {
1861 /* Write issue file and prompt */
1864 #ifdef AGETTY_RELOAD
1865 /* If asked to reprompt *before* terminal input arrives, then do so */
1866 if (!wait_for_term_input(STDIN_FILENO
)) {
1867 if (op
->flags
& F_VCONSOLE
)
1868 termio_clear(STDOUT_FILENO
);
1874 /* Read name, watch for break and end-of-line. */
1875 while (cp
->eol
== '\0') {
1879 if (read(STDIN_FILENO
, &c
, 1) < 1) {
1881 /* The terminal could be open with O_NONBLOCK when
1882 * -L (force CLOCAL) is specified... */
1883 if (errno
== EINTR
|| errno
== EAGAIN
) {
1895 log_err(_("%s: read: %m"), op
->tty
);
1899 /* Do parity bit handling. */
1902 else if (c
!= (ascval
= (c
& 0177))) {
1903 uint32_t bits
; /* # of "1" bits per character */
1904 uint32_t mask
; /* mask with 1 bit up */
1905 for (bits
= 1, mask
= 1; mask
& 0177; mask
<<= 1) {
1909 cp
->parity
|= ((bits
& 1) ? 1 : 2);
1912 if (op
->killchars
&& strchr(op
->killchars
, ascval
))
1914 else if (op
->erasechars
&& strchr(op
->erasechars
, ascval
))
1919 /* Do erase, kill and end-of-line processing. */
1923 if (op
->numspeed
> 1)
1928 *bp
= 0; /* terminate logname */
1929 cp
->eol
= ascval
; /* set end-of-line char */
1933 cp
->erase
= ascval
; /* set erase character */
1935 if ((tp
->c_lflag
& ECHO
) == 0)
1936 write_all(1, erase
[cp
->parity
], 3);
1941 cp
->kill
= ascval
; /* set kill character */
1942 while (bp
> logname
) {
1943 if ((tp
->c_lflag
& ECHO
) == 0)
1944 write_all(1, erase
[cp
->parity
], 3);
1951 if (!isascii(ascval
) || !isprint(ascval
))
1953 if ((size_t)(bp
- logname
) >= sizeof(logname
) - 1)
1954 log_err(_("%s: input overrun"), op
->tty
);
1955 if ((tp
->c_lflag
& ECHO
) == 0)
1956 write_all(1, &c
, 1); /* echo the character */
1957 *bp
++ = ascval
; /* and store it */
1962 #ifdef HAVE_WIDECHAR
1963 if ((op
->flags
& (F_EIGHTBITS
|F_UTF8
)) == (F_EIGHTBITS
|F_UTF8
)) {
1964 /* Check out UTF-8 multibyte characters */
1968 len
= mbstowcs((wchar_t *)0, logname
, 0);
1970 log_err(_("%s: invalid character conversion for login name"), op
->tty
);
1972 wcs
= malloc((len
+ 1) * sizeof(wchar_t));
1974 log_err(_("failed to allocate memory: %m"));
1976 len
= mbstowcs(wcs
, logname
, len
+ 1);
1978 log_err(_("%s: invalid character conversion for login name"), op
->tty
);
1982 const wint_t wc
= *wcp
++;
1984 log_err(_("%s: invalid character 0x%x in login name"), op
->tty
, wc
);
1989 if ((op
->flags
& F_LCUC
) && (cp
->capslock
= caps_lock(logname
))) {
1991 /* Handle names with upper case and no lower case. */
1992 for (bp
= logname
; *bp
; bp
++)
1994 *bp
= tolower(*bp
); /* map name to lower case */
2000 /* Set the final tty mode bits. */
2001 static void termio_final(struct options
*op
, struct termios
*tp
, struct chardata
*cp
)
2003 /* General terminal-independent stuff. */
2005 /* 2-way flow control */
2006 tp
->c_iflag
|= IXON
| IXOFF
;
2007 tp
->c_lflag
|= ICANON
| ISIG
| ECHO
| ECHOE
| ECHOK
| ECHOKE
;
2008 /* no longer| ECHOCTL | ECHOPRT */
2009 tp
->c_oflag
|= OPOST
;
2010 /* tp->c_cflag = 0; */
2011 tp
->c_cc
[VINTR
] = DEF_INTR
;
2012 tp
->c_cc
[VQUIT
] = DEF_QUIT
;
2013 tp
->c_cc
[VEOF
] = DEF_EOF
;
2014 tp
->c_cc
[VEOL
] = DEF_EOL
;
2016 tp
->c_cc
[VSWTC
] = DEF_SWITCH
;
2017 #elif defined(VSWTCH)
2018 tp
->c_cc
[VSWTCH
] = DEF_SWITCH
;
2019 #endif /* __linux__ */
2021 /* Account for special characters seen in input. */
2022 if (cp
->eol
== CR
) {
2023 tp
->c_iflag
|= ICRNL
;
2024 tp
->c_oflag
|= ONLCR
;
2026 tp
->c_cc
[VERASE
] = cp
->erase
;
2027 tp
->c_cc
[VKILL
] = cp
->kill
;
2029 /* Account for the presence or absence of parity bits in input. */
2030 switch (cp
->parity
) {
2032 /* space (always 0) parity */
2036 tp
->c_cflag
|= PARODD
;
2040 tp
->c_cflag
|= PARENB
;
2041 tp
->c_iflag
|= INPCK
| ISTRIP
;
2045 tp
->c_cflag
&= ~CSIZE
;
2049 /* Account for upper case without lower case. */
2052 tp
->c_iflag
|= IUCLC
;
2055 tp
->c_lflag
|= XCASE
;
2058 tp
->c_oflag
|= OLCUC
;
2061 /* Optionally enable hardware flow control. */
2063 if (op
->flags
& F_RTSCTS
)
2064 tp
->c_cflag
|= CRTSCTS
;
2067 /* Finally, make the new settings effective. */
2068 if (tcsetattr(STDIN_FILENO
, TCSANOW
, tp
) < 0)
2069 log_err(_("%s: failed to set terminal attributes: %m"), op
->tty
);
2073 * String contains upper case without lower case.
2074 * http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=52940
2075 * http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=156242
2077 static int caps_lock(char *s
)
2081 for (capslock
= 0; *s
; s
++) {
2083 return EXIT_SUCCESS
;
2085 capslock
= isupper(*s
);
2090 /* Convert speed string to speed code; return 0 on failure. */
2091 static speed_t
bcode(char *s
)
2093 const struct Speedtab
*sp
;
2094 long speed
= atol(s
);
2096 for (sp
= speedtab
; sp
->speed
; sp
++)
2097 if (sp
->speed
== speed
)
2102 static void __attribute__ ((__noreturn__
)) usage(FILE *out
)
2104 fputs(USAGE_HEADER
, out
);
2105 fprintf(out
, _(" %1$s [options] <line> [<baud_rate>,...] [<termtype>]\n"
2106 " %1$s [options] <baud_rate>,... <line> [<termtype>]\n"), program_invocation_short_name
);
2108 fputs(USAGE_SEPARATOR
, out
);
2109 fputs(_("Open a terminal and set its mode.\n"), out
);
2111 fputs(USAGE_OPTIONS
, out
);
2112 fputs(_(" -8, --8bits assume 8-bit tty\n"), out
);
2113 fputs(_(" -a, --autologin <user> login the specified user automatically\n"), out
);
2114 fputs(_(" -c, --noreset do not reset control mode\n"), out
);
2115 fputs(_(" -E, --remote use -r <hostname> for login(1)\n"), out
);
2116 fputs(_(" -f, --issue-file <file> display issue file\n"), out
);
2117 fputs(_(" -h, --flow-control enable hardware flow control\n"), out
);
2118 fputs(_(" -H, --host <hostname> specify login host\n"), out
);
2119 fputs(_(" -i, --noissue do not display issue file\n"), out
);
2120 fputs(_(" -I, --init-string <string> set init string\n"), out
);
2121 fputs(_(" -J --noclear do not clear the screen before prompt\n"), out
);
2122 fputs(_(" -l, --login-program <file> specify login program\n"), out
);
2123 fputs(_(" -L, --local-line[=<mode>] control the local line flag\n"), out
);
2124 fputs(_(" -m, --extract-baud extract baud rate during connect\n"), out
);
2125 fputs(_(" -n, --skip-login do not prompt for login\n"), out
);
2126 fputs(_(" -N --nonewline do not print a newline before issue\n"), out
);
2127 fputs(_(" -o, --login-options <opts> options that are passed to login\n"), out
);
2128 fputs(_(" -p, --login-pause wait for any key before the login\n"), out
);
2129 fputs(_(" -r, --chroot <dir> change root to the directory\n"), out
);
2130 fputs(_(" -R, --hangup do virtually hangup on the tty\n"), out
);
2131 fputs(_(" -s, --keep-baud try to keep baud rate after break\n"), out
);
2132 fputs(_(" -t, --timeout <number> login process timeout\n"), out
);
2133 fputs(_(" -U, --detect-case detect uppercase terminal\n"), out
);
2134 fputs(_(" -w, --wait-cr wait carriage-return\n"), out
);
2135 fputs(_(" --nohints do not print hints\n"), out
);
2136 fputs(_(" --nohostname no hostname at all will be shown\n"), out
);
2137 fputs(_(" --long-hostname show full qualified hostname\n"), out
);
2138 fputs(_(" --erase-chars <string> additional backspace chars\n"), out
);
2139 fputs(_(" --kill-chars <string> additional kill chars\n"), out
);
2140 fputs(_(" --chdir <directory> chdir before the login\n"), out
);
2141 fputs(_(" --delay <number> sleep seconds before prompt\n"), out
);
2142 fputs(_(" --nice <number> run login with this priority\n"), out
);
2143 fputs(_(" --reload reload prompts on running agetty instances\n"), out
);
2144 fputs(_(" --help display this help and exit\n"), out
);
2145 fputs(_(" --version output version information and exit\n"), out
);
2146 fprintf(out
, USAGE_MAN_TAIL("agetty(8)"));
2148 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
2152 * Helper function reports errors to console or syslog.
2153 * Will be used by log_err() and log_warn() therefore
2154 * it takes a format as well as va_list.
2156 #define str2cpy(b,s1,s2) strcat(strcpy(b,s1),s2)
2158 static void dolog(int priority
, const char *fmt
, va_list ap
)
2167 * If the diagnostic is reported via syslog(3), the process name is
2168 * automatically prepended to the message. If we write directly to
2169 * /dev/console, we must prepend the process name ourselves.
2175 str2cpy(buf
, program_invocation_short_name
, ": ");
2176 bp
= buf
+ strlen(buf
);
2177 #endif /* USE_SYSLOG */
2178 vsnprintf(bp
, sizeof(buf
)-strlen(buf
), fmt
, ap
);
2181 * Write the diagnostic directly to /dev/console if we do not use the
2182 * syslog(3) facility.
2185 openlog(program_invocation_short_name
, LOG_PID
, LOG_AUTHPRIV
);
2186 syslog(priority
, "%s", buf
);
2189 /* Terminate with CR-LF since the console mode is unknown. */
2191 if ((fd
= open("/dev/console", 1)) >= 0) {
2192 write_all(fd
, buf
, strlen(buf
));
2195 #endif /* USE_SYSLOG */
2198 static void log_err(const char *fmt
, ...)
2203 dolog(LOG_ERR
, fmt
, ap
);
2206 /* Be kind to init(8). */
2211 static void log_warn(const char *fmt
, ...)
2216 dolog(LOG_WARNING
, fmt
, ap
);
2220 static void print_addr(sa_family_t family
, void *addr
)
2222 char buff
[INET6_ADDRSTRLEN
+ 1];
2224 inet_ntop(family
, addr
, buff
, sizeof(buff
));
2229 * Prints IP for the specified interface (@iface), if the interface is not
2230 * specified then prints the "best" one (UP, RUNNING, non-LOOPBACK). If not
2231 * found the "best" interface then prints at least host IP.
2233 static void output_iface_ip(struct ifaddrs
*addrs
,
2238 struct addrinfo hints
, *info
= NULL
;
2245 for (p
= addrs
; p
; p
= p
->ifa_next
) {
2249 p
->ifa_addr
->sa_family
!= family
)
2253 /* Filter out by interface name */
2254 if (strcmp(p
->ifa_name
, iface
) != 0)
2257 /* Select the "best" interface */
2258 if ((p
->ifa_flags
& IFF_LOOPBACK
) ||
2259 !(p
->ifa_flags
& IFF_UP
) ||
2260 !(p
->ifa_flags
& IFF_RUNNING
))
2265 switch (p
->ifa_addr
->sa_family
) {
2267 addr
= &((struct sockaddr_in
*) p
->ifa_addr
)->sin_addr
;
2270 addr
= &((struct sockaddr_in6
*) p
->ifa_addr
)->sin6_addr
;
2275 print_addr(family
, addr
);
2283 /* Hmm.. not found the best interface, print host IP at least */
2284 memset(&hints
, 0, sizeof(hints
));
2285 hints
.ai_family
= family
;
2286 if (family
== AF_INET6
)
2287 hints
.ai_flags
= AI_V4MAPPED
;
2289 host
= xgethostname();
2290 if (host
&& getaddrinfo(host
, NULL
, &hints
, &info
) == 0 && info
) {
2291 switch (info
->ai_family
) {
2293 addr
= &((struct sockaddr_in
*) info
->ai_addr
)->sin_addr
;
2296 addr
= &((struct sockaddr_in6
*) info
->ai_addr
)->sin6_addr
;
2300 print_addr(family
, addr
);
2308 * parses \x{argument}, if not argument specified then returns NULL, the @fd
2309 * has to point to one char after the sequence (it means '{').
2311 static char *get_escape_argument(FILE *fd
, char *buf
, size_t bufsz
)
2316 if (c
== EOF
|| (unsigned char) c
!= '{') {
2325 if ((unsigned char) c
!= '}' && i
< bufsz
- 1)
2326 buf
[i
++] = (unsigned char) c
;
2328 } while ((unsigned char) c
!= '}');
2334 static void output_special_char(unsigned char c
, struct options
*op
,
2335 struct termios
*tp
, FILE *fp
)
2344 char escname
[UL_COLORNAME_MAXSZ
];
2346 if (get_escape_argument(fp
, escname
, sizeof(escname
))) {
2347 const char *esc
= color_sequence_from_colorname(escname
);
2351 fputs("\033", stdout
);
2355 printf("%s", uts
.sysname
);
2358 printf("%s", uts
.nodename
);
2361 printf("%s", uts
.release
);
2364 printf("%s", uts
.version
);
2367 printf("%s", uts
.machine
);
2371 char *dom
= xgetdomainname();
2373 fputs(dom
? dom
: "unknown_domain", stdout
);
2380 char *host
= xgethostname();
2381 struct addrinfo hints
, *info
= NULL
;
2383 memset(&hints
, 0, sizeof(hints
));
2384 hints
.ai_flags
= AI_CANONNAME
;
2386 if (host
&& getaddrinfo(host
, NULL
, &hints
, &info
) == 0 && info
) {
2389 if (info
->ai_canonname
&&
2390 (canon
= strchr(info
->ai_canonname
, '.')))
2393 fputs(dom
? dom
: "unknown_domain", stdout
);
2406 tm
= localtime(&now
);
2411 if (c
== 'd') /* ISO 8601 */
2412 printf("%s %s %d %d",
2413 nl_langinfo(ABDAY_1
+ tm
->tm_wday
),
2414 nl_langinfo(ABMON_1
+ tm
->tm_mon
),
2416 tm
->tm_year
< 70 ? tm
->tm_year
+ 2000 :
2417 tm
->tm_year
+ 1900);
2419 printf("%02d:%02d:%02d",
2420 tm
->tm_hour
, tm
->tm_min
, tm
->tm_sec
);
2424 printf ("%s", op
->tty
);
2428 const speed_t speed
= cfgetispeed(tp
);
2431 for (i
= 0; speedtab
[i
].speed
; i
++) {
2432 if (speedtab
[i
].code
== speed
) {
2433 printf("%ld", speedtab
[i
].speed
);
2441 char *var
= NULL
, varname
[64];
2443 if (get_escape_argument(fp
, varname
, sizeof(varname
)))
2444 var
= read_os_release(op
, varname
);
2445 else if (!(var
= read_os_release(op
, "PRETTY_NAME")))
2448 if (strcmp(varname
, "ANSI_COLOR") == 0)
2449 printf("\033[%sm", var
);
2452 if (var
!= uts
.sysname
)
2463 while ((ut
= getutent()))
2464 if (ut
->ut_type
== USER_PROCESS
)
2468 printf(P_("%d user", "%d users", users
), users
);
2470 printf ("%d ", users
);
2476 sa_family_t family
= c
== '4' ? AF_INET
: AF_INET6
;
2477 struct ifaddrs
*addrs
= NULL
;
2480 #ifdef AGETTY_RELOAD
2484 if (getifaddrs(&addrs
))
2487 if (get_escape_argument(fp
, iface
, sizeof(iface
)))
2488 output_iface_ip(addrs
, iface
, family
);
2490 output_iface_ip(addrs
, NULL
, family
);
2501 static void init_special_char(char* arg
, struct options
*op
)
2506 op
->initstring
= malloc(strlen(arg
) + 1);
2507 if (!op
->initstring
)
2508 log_err(_("failed to allocate memory: %m"));
2511 * Copy optarg into op->initstring decoding \ddd octal
2517 /* The \\ is converted to \ */
2524 /* Handle \000 - \177. */
2526 for (i
= 1; i
<= 3; i
++) {
2527 if (*p
>= '0' && *p
<= '7') {
2544 * Appends @str to @dest and if @dest is not empty then use use @sep as a
2545 * separator. The maximal final length of the @dest is @len.
2547 * Returns the final @dest length or -1 in case of error.
2549 static ssize_t
append(char *dest
, size_t len
, const char *sep
, const char *src
)
2551 size_t dsz
= 0, ssz
= 0, sz
;
2554 if (!dest
|| !len
|| !src
)
2563 if (dsz
+ ssz
+ sz
+ 1 > len
)
2568 memcpy(p
, sep
, ssz
);
2574 return dsz
+ ssz
+ sz
;
2578 * Do not allow the user to pass an option as a user name
2579 * To be more safe: Use `--' to make sure the rest is
2580 * interpreted as non-options by the program, if it supports it.
2582 static void check_username(const char* nm
)
2587 if (strlen(nm
) > 42)
2596 log_err(_("checkname failed: %m"));
2600 * For the case plymouth is found on this system
2602 static int plymouth_command(const char* arg
)
2604 static int has_plymouth
= 1;
2612 int fd
= open(AGETTY_PLYMOUTH_FDFILE
, O_RDWR
);
2615 err(EXIT_FAILURE
,_("cannot open %s"),
2616 AGETTY_PLYMOUTH_FDFILE
);
2621 execl(AGETTY_PLYMOUTH
, AGETTY_PLYMOUTH
, arg
, (char *) NULL
);
2623 } else if (pid
> 0) {
2625 waitpid(pid
, &status
, 0);
2633 static void reload_agettys(void)
2635 #ifdef AGETTY_RELOAD
2636 int fd
= open(AGETTY_RELOAD_FILENAME
, O_CREAT
|O_CLOEXEC
|O_WRONLY
,
2639 err(EXIT_FAILURE
, _("cannot open %s"), AGETTY_RELOAD_FILENAME
);
2641 if (futimens(fd
, NULL
) < 0 || close(fd
) < 0)
2642 err(EXIT_FAILURE
, _("cannot touch file %s"),
2643 AGETTY_RELOAD_FILENAME
);
2646 errx(EXIT_FAILURE
, _("--reload is unsupported on your system"));