]> git.ipfire.org Git - thirdparty/util-linux.git/blob - term-utils/agetty.c
agetty: remove atoi() from argv[] parsing [clang analyze]
[thirdparty/util-linux.git] / term-utils / agetty.c
1 /*
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.
6 *
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>
10 *
11 * This program is freely distributable.
12 */
13
14 #include <stdio.h>
15 #include <unistd.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <termios.h>
19 #include <signal.h>
20 #include <errno.h>
21 #include <sys/ioctl.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <sys/wait.h>
25 #include <fcntl.h>
26 #include <stdarg.h>
27 #include <ctype.h>
28 #include <utmp.h>
29 #include <getopt.h>
30 #include <time.h>
31 #include <sys/file.h>
32 #include <sys/socket.h>
33 #include <langinfo.h>
34 #include <grp.h>
35 #include <arpa/inet.h>
36 #include <netdb.h>
37 #include <ifaddrs.h>
38 #include <net/if.h>
39
40 #include "strutils.h"
41 #include "all-io.h"
42 #include "nls.h"
43 #include "pathnames.h"
44 #include "c.h"
45 #include "widechar.h"
46 #include "ttyutils.h"
47 #include "color-names.h"
48
49 #ifdef HAVE_SYS_PARAM_H
50 # include <sys/param.h>
51 #endif
52
53 #if defined(__FreeBSD_kernel__)
54 #include <pty.h>
55 #endif
56
57 #ifdef __linux__
58 # include <sys/kd.h>
59 # define USE_SYSLOG
60 # ifndef DEFAULT_VCTERM
61 # define DEFAULT_VCTERM "linux"
62 # endif
63 # if defined (__s390__) || defined (__s390x__)
64 # define DEFAULT_TTYS0 "dumb"
65 # define DEFAULT_TTY32 "ibm327x"
66 # define DEFAULT_TTYS1 "vt220"
67 # endif
68 # ifndef DEFAULT_STERM
69 # define DEFAULT_STERM "vt102"
70 # endif
71 #elif defined(__GNU__)
72 # define USE_SYSLOG
73 # ifndef DEFAULT_VCTERM
74 # define DEFAULT_VCTERM "hurd"
75 # endif
76 # ifndef DEFAULT_STERM
77 # define DEFAULT_STERM "vt102"
78 # endif
79 #else
80 # ifndef DEFAULT_VCTERM
81 # define DEFAULT_VCTERM "vt100"
82 # endif
83 # ifndef DEFAULT_STERM
84 # define DEFAULT_STERM "vt100"
85 # endif
86 #endif
87
88 #ifdef __FreeBSD_kernel__
89 #define USE_SYSLOG
90 #endif
91
92 /* If USE_SYSLOG is undefined all diagnostics go to /dev/console. */
93 #ifdef USE_SYSLOG
94 # include <syslog.h>
95 #endif
96
97 /*
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.
101 */
102 #ifdef LOGIN_PROCESS
103 # define SYSV_STYLE
104 #endif
105
106 /*
107 * Things you may want to modify.
108 *
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.
112 *
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.
116 */
117
118 /* Displayed before the login prompt. */
119 #ifdef SYSV_STYLE
120 # define ISSUE _PATH_ISSUE
121 # include <sys/utsname.h>
122 #endif
123
124 /* Login prompt. */
125 #define LOGIN "login: "
126 #define LOGIN_ARGV_MAX 16 /* Numbers of args for login */
127
128 /*
129 * agetty --reload
130 */
131 #ifdef AGETTY_RELOAD
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;
139 #endif
140
141 #define AGETTY_PLYMOUTH "/usr/bin/plymouth"
142 #define AGETTY_PLYMOUTH_FDFILE "/dev/null"
143
144 /*
145 * When multiple baud rates are specified on the command line, the first one
146 * we will try is the first one specified.
147 */
148 #define FIRST_SPEED 0
149
150 /* Storage for command-line options. */
151 #define MAX_SPEED 10 /* max. nr. of baud rates */
152
153 struct options {
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 */
175 };
176
177 enum {
178 CLOCAL_MODE_AUTO = 0,
179 CLOCAL_MODE_ALWAYS,
180 CLOCAL_MODE_NEVER
181 };
182
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 */
186
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 */
205
206 #define serial_tty_option(opt, flag) \
207 (((opt)->flags & (F_VCONSOLE|(flag))) == (flag))
208
209 struct Speedtab {
210 long speed;
211 speed_t code;
212 };
213
214 static const struct Speedtab speedtab[] = {
215 {50, B50},
216 {75, B75},
217 {110, B110},
218 {134, B134},
219 {150, B150},
220 {200, B200},
221 {300, B300},
222 {600, B600},
223 {1200, B1200},
224 {1800, B1800},
225 {2400, B2400},
226 {4800, B4800},
227 {9600, B9600},
228 #ifdef B19200
229 {19200, B19200},
230 #elif defined(EXTA)
231 {19200, EXTA},
232 #endif
233 #ifdef B38400
234 {38400, B38400},
235 #elif defined(EXTB)
236 {38400, EXTB},
237 #endif
238 #ifdef B57600
239 {57600, B57600},
240 #endif
241 #ifdef B115200
242 {115200, B115200},
243 #endif
244 #ifdef B230400
245 {230400, B230400},
246 #endif
247 #ifdef B460800
248 {460800, B460800},
249 #endif
250 #ifdef B500000
251 {500000, B500000},
252 #endif
253 #ifdef B576000
254 {576000, B576000},
255 #endif
256 #ifdef B921600
257 {921600, B921600},
258 #endif
259 #ifdef B1000000
260 {1000000, B1000000},
261 #endif
262 #ifdef B1152000
263 {1152000, B1152000},
264 #endif
265 #ifdef B1500000
266 {1500000, B1500000},
267 #endif
268 #ifdef B2000000
269 {2000000, B2000000},
270 #endif
271 #ifdef B2500000
272 {2500000, B2500000},
273 #endif
274 #ifdef B3000000
275 {3000000, B3000000},
276 #endif
277 #ifdef B3500000
278 {3500000, B3500000},
279 #endif
280 #ifdef B4000000
281 {4000000, B4000000},
282 #endif
283 {0, 0},
284 };
285
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);
314
315 /* Fake hostname for ut_host specified on command line. */
316 static char *fakehost;
317
318 #ifdef DEBUGGING
319 # include "closestream.h"
320 # ifndef DEBUG_OUTPUT
321 # define DEBUG_OUTPUT "/dev/tty10"
322 # endif
323 # define debug(s) do { fprintf(dbf,s); fflush(dbf); } while (0)
324 FILE *dbf;
325 #else
326 # define debug(s) do { ; } while (0)
327 #endif
328
329 int main(int argc, char **argv)
330 {
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 */
339 };
340 char *login_argv[LOGIN_ARGV_MAX + 1];
341 int login_argc = 0;
342 struct sigaction sa, sa_hup, sa_quit, sa_int;
343 sigset_t set;
344
345 setlocale(LC_ALL, "");
346 bindtextdomain(PACKAGE, LOCALEDIR);
347 textdomain(PACKAGE);
348
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);
356
357 #ifdef DEBUGGING
358 dbf = fopen(DEBUG_OUTPUT, "w");
359 for (int i = 1; i < argc; i++) {
360 if (i > 1)
361 debug(" ");
362 debug(argv[i]);
363 }
364 debug("\n");
365 #endif /* DEBUGGING */
366
367 /* Parse command-line arguments. */
368 parse_args(argc, argv, &options);
369
370 login_argv[login_argc++] = options.login; /* set login program name */
371
372 /* Update the utmp file. */
373 #ifdef SYSV_STYLE
374 update_utmp(&options);
375 #endif
376 if (options.delay)
377 sleep(options.delay);
378
379 debug("calling open_tty\n");
380
381 /* Open the tty as standard { input, output, error }. */
382 open_tty(options.tty, &termios, &options);
383
384 /* Unmask SIGHUP if inherited */
385 sigemptyset(&set);
386 sigaddset(&set, SIGHUP);
387 sigprocmask(SIG_UNBLOCK, &set, NULL);
388 sigaction(SIGHUP, &sa_hup, NULL);
389
390 tcsetpgrp(STDIN_FILENO, getpid());
391
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;
396 }
397
398 /* Initialize the termios settings (raw mode, eight-bit, blocking i/o). */
399 debug("calling termio_init\n");
400 termio_init(&options, &termios);
401
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));
408 }
409
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);
416
417 /* Optionally detect the baud rate from the modem status message. */
418 debug("before autobaud\n");
419 if (serial_tty_option(&options, F_PARSE))
420 auto_baud(&termios);
421
422 /* Set the optional timer. */
423 if (options.timeout)
424 alarm(options.timeout);
425
426 /* Optionally wait for CR or LF before writing /etc/issue */
427 if (serial_tty_option(&options, F_WAITCRLF)) {
428 char ch;
429
430 debug("waiting for cr-lf\n");
431 while (read(STDIN_FILENO, &ch, 1) == 1) {
432 /* Strip "parity bit". */
433 ch &= 0x7f;
434 #ifdef DEBUGGING
435 fprintf(dbf, "read %c\n", ch);
436 #endif
437 if (ch == '\n' || ch == '\r')
438 break;
439 }
440 }
441
442 INIT_CHARDATA(&chardata);
443
444 if (options.autolog) {
445 debug("doing auto login\n");
446 username = options.autolog;
447 }
448
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);
454 } else {
455 /* Read the login name. */
456 debug("reading login name\n");
457 while ((username =
458 get_logname(&options, &termios, &chardata)) == NULL)
459 if ((options.flags & F_VCONSOLE) == 0 && options.numspeed)
460 next_speed(&options, &termios);
461 }
462 }
463
464 /* Disable timer. */
465 if (options.timeout)
466 alarm(0);
467
468 if ((options.flags & F_VCONSOLE) == 0) {
469 /* Finalize the termios settings. */
470 termio_final(&options, &termios, &chardata);
471
472 /* Now the newline character should be properly written. */
473 write_all(STDOUT_FILENO, "\r\n", 2);
474 }
475
476 sigaction(SIGQUIT, &sa_quit, NULL);
477 sigaction(SIGINT, &sa_int, NULL);
478
479 if (username)
480 check_username(username);
481
482 if (options.logopt) {
483 /*
484 * The --login-options completely overwrites the default
485 * way how agetty composes login(1) command line.
486 */
487 login_options_to_argv(login_argv, &login_argc,
488 options.logopt, username);
489 } else {
490 if (fakehost && (options.flags & F_REMOTE)) {
491 login_argv[login_argc++] = "-h";
492 login_argv[login_argc++] = fakehost;
493 }
494 if (username) {
495 if (options.autolog)
496 login_argv[login_argc++] = "-f";
497 else
498 login_argv[login_argc++] = "--";
499 login_argv[login_argc++] = username;
500 }
501 }
502
503 login_argv[login_argc] = NULL; /* last login argv */
504
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);
509 }
510 if (options.chdir) {
511 if (chdir(options.chdir) < 0)
512 log_err(_("%s: can't change working directory %s: %m"),
513 options.tty, options.chdir);
514 }
515 if (options.nice) {
516 if (nice(options.nice) < 0)
517 log_warn(_("%s: can't change process priority: %m"),
518 options.tty);
519 }
520 free(options.osrelease);
521 #ifdef DEBUGGING
522 if (close_stream(dbf) != 0)
523 log_err("write failed: %s", DEBUG_OUTPUT);
524 #endif
525
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]);
529 }
530
531 /*
532 * Returns : @str if \u not found
533 * : @username if @str equal to "\u"
534 * : newly allocated string if \u mixed with something other
535 */
536 static char *replace_u(char *str, char *username)
537 {
538 char *entry = NULL, *p = str;
539 size_t usz = username ? strlen(username) : 0;
540
541 while (*p) {
542 size_t sz;
543 char *tp, *old = entry;
544
545 if (memcmp(p, "\\u", 2)) {
546 p++;
547 continue; /* no \u */
548 }
549 sz = strlen(str);
550
551 if (p == str && sz == 2) {
552 /* 'str' contains only '\u' */
553 free(old);
554 return username;
555 }
556
557 tp = entry = malloc(sz + usz);
558 if (!tp)
559 log_err(_("failed to allocate memory: %m"));
560
561 if (p != str) {
562 /* copy chars befor \u */
563 memcpy(tp, str, p - str);
564 tp += p - str;
565 }
566 if (usz) {
567 /* copy username */
568 memcpy(tp, username, usz);
569 tp += usz;
570 }
571 if (*(p + 2))
572 /* copy chars after \u + \0 */
573 memcpy(tp, p + 2, sz - (p - str) - 1);
574 else
575 *tp = '\0';
576
577 p = tp;
578 str = entry;
579 free(old);
580 }
581
582 return entry ? entry : str;
583 }
584
585 static void login_options_to_argv(char *argv[], int *argc,
586 char *str, char *username)
587 {
588 char *p;
589 int i = *argc;
590
591 while (str && isspace(*str))
592 str++;
593 p = str;
594
595 while (p && *p && i < LOGIN_ARGV_MAX) {
596 if (isspace(*p)) {
597 *p = '\0';
598 while (isspace(*++p))
599 ;
600 if (*p) {
601 argv[i++] = replace_u(str, username);
602 str = p;
603 }
604 } else
605 p++;
606 }
607 if (str && *str && i < LOGIN_ARGV_MAX)
608 argv[i++] = replace_u(str, username);
609 *argc = i;
610 }
611
612 #define is_speed(str) (strlen((str)) == strspn((str), "0123456789,"))
613
614 /* Parse command-line arguments. */
615 static void parse_args(int argc, char **argv, struct options *op)
616 {
617 int c;
618
619 enum {
620 VERSION_OPTION = CHAR_MAX + 1,
621 NOHINTS_OPTION,
622 NOHOSTNAME_OPTION,
623 LONGHOSTNAME_OPTION,
624 HELP_OPTION,
625 ERASE_CHARS_OPTION,
626 KILL_CHARS_OPTION,
627 RELOAD_OPTION,
628 };
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 },
664 { NULL, 0, 0, 0 }
665 };
666
667 while ((c = getopt_long(argc, argv,
668 "8a:cC:d:Ef:hH:iI:Jl:L::mnNo:pP:r:Rst:Uw", longopts,
669 NULL)) != -1) {
670 switch (c) {
671 case '8':
672 op->flags |= F_EIGHTBITS;
673 break;
674 case 'a':
675 op->autolog = optarg;
676 break;
677 case 'c':
678 op->flags |= F_KEEPCFLAGS;
679 break;
680 case 'C':
681 op->chdir = optarg;
682 break;
683 case 'd':
684 op->delay = strtou32_or_err(optarg, _("invalid delay argument"));
685 break;
686 case 'E':
687 op->flags |= F_REMOTE;
688 break;
689 case 'f':
690 op->flags |= F_CUSTISSUE;
691 op->issue = optarg;
692 break;
693 case 'h':
694 op->flags |= F_RTSCTS;
695 break;
696 case 'H':
697 fakehost = optarg;
698 break;
699 case 'i':
700 op->flags &= ~F_ISSUE;
701 break;
702 case 'I':
703 init_special_char(optarg, op);
704 op->flags |= F_INITSTRING;
705 break;
706 case 'J':
707 op->flags |= F_NOCLEAR;
708 break;
709 case 'l':
710 op->login = optarg;
711 break;
712 case 'L':
713 /* -L and -L=always have the same meaning */
714 op->clocal = CLOCAL_MODE_ALWAYS;
715 if (optarg) {
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;
722 else
723 log_err(_("invalid argument of --local-line"));
724 }
725 break;
726 case 'm':
727 op->flags |= F_PARSE;
728 break;
729 case 'n':
730 op->flags |= F_NOPROMPT;
731 break;
732 case 'N':
733 op->flags |= F_NONL;
734 break;
735 case 'o':
736 op->logopt = optarg;
737 break;
738 case 'p':
739 op->flags |= F_LOGINPAUSE;
740 break;
741 case 'P':
742 op->nice = strtos32_or_err(optarg, _("invalid nice argument"));
743 break;
744 case 'r':
745 op->chroot = optarg;
746 break;
747 case 'R':
748 op->flags |= F_HANGUP;
749 break;
750 case 's':
751 op->flags |= F_KEEPSPEED;
752 break;
753 case 't':
754 op->timeout = strtou32_or_err(optarg, _("invalid timeout argument"));
755 break;
756 case 'U':
757 op->flags |= F_LCUC;
758 break;
759 case 'w':
760 op->flags |= F_WAITCRLF;
761 break;
762 case NOHINTS_OPTION:
763 op->flags |= F_NOHINTS;
764 break;
765 case NOHOSTNAME_OPTION:
766 op->flags |= F_NOHOSTNAME;
767 break;
768 case LONGHOSTNAME_OPTION:
769 op->flags |= F_LONGHNAME;
770 break;
771 case ERASE_CHARS_OPTION:
772 op->erasechars = optarg;
773 break;
774 case KILL_CHARS_OPTION:
775 op->killchars = optarg;
776 break;
777 case RELOAD_OPTION:
778 reload_agettys();
779 exit(EXIT_SUCCESS);
780 case VERSION_OPTION:
781 printf(UTIL_LINUX_VERSION);
782 exit(EXIT_SUCCESS);
783 case HELP_OPTION:
784 usage(stdout);
785 default:
786 usage(stderr);
787 }
788 }
789
790 debug("after getopt loop\n");
791
792 if (argc < optind + 1) {
793 log_warn(_("not enough arguments"));
794 usage(stderr);
795 }
796
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"));
803 usage(stderr);
804 }
805 op->tty = argv[optind++];
806 } else {
807 op->tty = argv[optind++];
808 if (argc > optind) {
809 char *v = argv[optind];
810 if (is_speed(v)) {
811 parse_speeds(op, v);
812 optind++;
813 }
814 }
815 }
816
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;
821
822 if (argc > optind && argv[optind])
823 op->term = argv[optind];
824
825 #ifdef DO_DEVFS_FIDDLING
826 /*
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
831 */
832 if (op->tty && strlen(op->tty) < 90) {
833 char dev_name[100];
834 struct stat st;
835
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);
844 if (!op->tty)
845 log_err(_("failed to allocate memory: %m"));
846 }
847 }
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);
856 if (!op->tty)
857 log_err(_("failed to allocate memory: %m"));
858 }
859 }
860 }
861 }
862 #endif /* DO_DEVFS_FIDDLING */
863
864 debug("exiting parseargs\n");
865 }
866
867 /* Parse alternate baud rates. */
868 static void parse_speeds(struct options *op, char *arg)
869 {
870 char *cp;
871
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"));
878 }
879 debug("exiting parsespeeds\n");
880 }
881
882 #ifdef SYSV_STYLE
883
884 /* Update our utmp entry. */
885 static void update_utmp(struct options *op)
886 {
887 struct utmp ut;
888 time_t t;
889 pid_t pid = getpid();
890 pid_t sid = getsid(0);
891 char *vcline = op->vcline;
892 char *line = op->tty;
893 struct utmp *utp;
894
895 /*
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.
902 */
903 utmpname(_PATH_UTMP);
904 setutent();
905
906 /*
907 * Find my pid in utmp.
908 *
909 * FIXME: Earlier (when was that?) code here tested only utp->ut_type !=
910 * INIT_PROCESS, so maybe the >= here should be >.
911 *
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?).
914 */
915 while ((utp = getutent()))
916 if (utp->ut_pid == pid
917 && utp->ut_type >= INIT_PROCESS
918 && utp->ut_type <= DEAD_PROCESS)
919 break;
920
921 if (utp) {
922 memcpy(&ut, utp, sizeof(ut));
923 } else {
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));
929 else {
930 size_t len = strlen(line);
931 char * ptr;
932 if (len >= sizeof(ut.ut_id))
933 ptr = line + len - sizeof(ut.ut_id);
934 else
935 ptr = line;
936 strncpy(ut.ut_id, ptr, sizeof(ut.ut_id));
937 }
938 }
939
940 strncpy(ut.ut_user, "LOGIN", sizeof(ut.ut_user));
941 strncpy(ut.ut_line, line, sizeof(ut.ut_line));
942 if (fakehost)
943 strncpy(ut.ut_host, fakehost, sizeof(ut.ut_host));
944 time(&t);
945 #if defined(_HAVE_UT_TV)
946 ut.ut_tv.tv_sec = t;
947 #else
948 ut.ut_time = t;
949 #endif
950 ut.ut_type = LOGIN_PROCESS;
951 ut.ut_pid = pid;
952 ut.ut_session = sid;
953
954 pututline(&ut);
955 endutent();
956
957 {
958 #ifdef HAVE_UPDWTMP
959 updwtmp(_PATH_WTMP, &ut);
960 #else
961 int ut_fd;
962 int lf;
963
964 if ((lf = open(_PATH_WTMPLOCK, O_CREAT | O_WRONLY, 0660)) >= 0) {
965 flock(lf, LOCK_EX);
966 if ((ut_fd =
967 open(_PATH_WTMP, O_APPEND | O_WRONLY)) >= 0) {
968 write_all(ut_fd, &ut, sizeof(ut));
969 close(ut_fd);
970 }
971 flock(lf, LOCK_UN);
972 close(lf);
973 }
974 #endif /* HAVE_UPDWTMP */
975 }
976 }
977
978 #endif /* SYSV_STYLE */
979
980 /* Set up tty as stdin, stdout & stderr. */
981 static void open_tty(char *tty, struct termios *tp, struct options *op)
982 {
983 const pid_t pid = getpid();
984 int closed = 0;
985 #ifndef KDGKBMODE
986 int serial;
987 #endif
988
989 /* Set up new standard input, unless we are given an already opened port. */
990
991 if (strcmp(tty, "-") != 0) {
992 char buf[PATH_MAX+1];
993 struct group *gr = NULL;
994 struct stat st;
995 int fd, len;
996 pid_t tid;
997 gid_t gid = 0;
998
999 /* Use tty group if available */
1000 if ((gr = getgrnam("tty")))
1001 gid = gr->gr_gid;
1002
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);
1006
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);
1010
1011 /*
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.
1016 */
1017 if (fchown(fd, 0, gid) || fchmod(fd, (gid ? 0620 : 0600))) {
1018 if (errno == EROFS)
1019 log_warn("%s: %m", buf);
1020 else
1021 log_err("%s: %m", buf);
1022 }
1023
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);
1029 if (!isatty(fd))
1030 log_err(_("/dev/%s: not a tty"), tty);
1031
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);
1035 }
1036
1037 close(STDIN_FILENO);
1038 errno = 0;
1039
1040 if (op->flags & F_HANGUP) {
1041
1042 if (ioctl(fd, TIOCNOTTY))
1043 debug("TIOCNOTTY ioctl failed\n");
1044
1045 /*
1046 * Let's close all file decriptors before vhangup
1047 * https://lkml.org/lkml/2012/6/5/145
1048 */
1049 close(fd);
1050 close(STDOUT_FILENO);
1051 close(STDERR_FILENO);
1052 errno = 0;
1053 closed = 1;
1054
1055 if (vhangup())
1056 log_err(_("/dev/%s: vhangup() failed: %m"), tty);
1057 } else
1058 close(fd);
1059
1060 debug("open(2)\n");
1061 if (open(buf, O_RDWR|O_NOCTTY|O_NONBLOCK, 0) != 0)
1062 log_err(_("/dev/%s: cannot open as standard input: %m"), tty);
1063
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);
1067 }
1068
1069 } else {
1070
1071 /*
1072 * Standard input should already be connected to an open port. Make
1073 * sure it is open for read/write.
1074 */
1075
1076 if ((fcntl(STDIN_FILENO, F_GETFL, 0) & O_RDWR) != O_RDWR)
1077 log_err(_("%s: not open for read/write"), tty);
1078
1079 }
1080
1081 if (tcsetpgrp(STDIN_FILENO, pid))
1082 log_warn(_("/dev/%s: cannot set process group: %m"), tty);
1083
1084 /* Get rid of the present outputs. */
1085 if (!closed) {
1086 close(STDOUT_FILENO);
1087 close(STDERR_FILENO);
1088 errno = 0;
1089 }
1090
1091 /* Set up standard output and standard error file descriptors. */
1092 debug("duping\n");
1093
1094 /* set up stdout and stderr */
1095 if (dup(STDIN_FILENO) != 1 || dup(STDIN_FILENO) != 2)
1096 log_err(_("%s: dup problem: %m"), tty);
1097
1098 /* make stdio unbuffered for slow modem lines */
1099 setvbuf(stdout, NULL, _IONBF, 0);
1100
1101 /*
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.
1106 *
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
1110 */
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);
1114
1115 #if defined (__s390__) || defined (__s390x__)
1116 if (!op->term) {
1117 /*
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.
1122 */
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;
1129 }
1130 #endif
1131
1132 #if defined(__FreeBSD_kernel__)
1133 login_tty (0);
1134 #endif
1135
1136 /*
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.
1140 */
1141 #ifdef KDGKBMODE
1142 if (ioctl(STDIN_FILENO, KDGKBMODE, &op->kbmode) == 0)
1143 #else
1144 if (ioctl(STDIN_FILENO, TIOCMGET, &serial) < 0 && (errno == EINVAL))
1145 #endif
1146 {
1147 op->flags |= F_VCONSOLE;
1148 if (!op->term)
1149 op->term = DEFAULT_VCTERM;
1150 } else {
1151 #ifdef K_RAW
1152 op->kbmode = K_RAW;
1153 #endif
1154 if (!op->term)
1155 op->term = DEFAULT_STERM;
1156 }
1157
1158 setenv("TERM", op->term, 1);
1159 }
1160
1161 /* Initialize termios settings. */
1162 static void termio_clear(int fd)
1163 {
1164 /*
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)
1172 */
1173 write_all(fd, "\033[r\033[H\033[J", 9);
1174 }
1175
1176 /* Initialize termios settings. */
1177 static void termio_init(struct options *op, struct termios *tp)
1178 {
1179 speed_t ispeed, ospeed;
1180 struct winsize ws;
1181 struct termios lock;
1182 #ifdef TIOCGLCKTRMIOS
1183 int i = (plymouth_command("--ping") == 0) ? 30 : 0;
1184
1185 while (i-- > 0) {
1186 /*
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.
1190 */
1191 memset(&lock, 0, sizeof(struct termios));
1192 if (ioctl(STDIN_FILENO, TIOCGLCKTRMIOS, &lock) < 0)
1193 break;
1194 if (!lock.c_iflag && !lock.c_oflag && !lock.c_cflag && !lock.c_lflag)
1195 break;
1196 debug("termios locked\n");
1197 if (i == 15 && plymouth_command("quit") != 0)
1198 break;
1199 sleep(1);
1200 }
1201 memset(&lock, 0, sizeof(struct termios));
1202 ioctl(STDIN_FILENO, TIOCSLCKTRMIOS, &lock);
1203 #endif
1204
1205 if (op->flags & F_VCONSOLE) {
1206 #if defined(IUTF8) && defined(KDGKBMODE)
1207 switch(op->kbmode) {
1208 case K_UNICODE:
1209 setlocale(LC_CTYPE, "C.UTF-8");
1210 op->flags |= F_UTF8;
1211 break;
1212 case K_RAW:
1213 case K_MEDIUMRAW:
1214 case K_XLATE:
1215 default:
1216 setlocale(LC_CTYPE, "POSIX");
1217 op->flags &= ~F_UTF8;
1218 break;
1219 }
1220 #else
1221 setlocale(LC_CTYPE, "POSIX");
1222 op->flags &= ~F_UTF8;
1223 #endif
1224 reset_vc(op, tp);
1225
1226 if ((tp->c_cflag & (CS8|PARODD|PARENB)) == CS8)
1227 op->flags |= F_EIGHTBITS;
1228
1229 if ((op->flags & F_NOCLEAR) == 0)
1230 termio_clear(STDOUT_FILENO);
1231 return;
1232 }
1233
1234 /*
1235 * Serial line
1236 */
1237
1238 if (op->flags & F_KEEPSPEED || !op->numspeed) {
1239 /* Save the original setting. */
1240 ispeed = cfgetispeed(tp);
1241 ospeed = cfgetospeed(tp);
1242
1243 if (!ispeed) ispeed = TTYDEF_SPEED;
1244 if (!ospeed) ospeed = TTYDEF_SPEED;
1245
1246 } else {
1247 ospeed = ispeed = op->speeds[FIRST_SPEED];
1248 }
1249
1250 /*
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
1254 * later on.
1255 */
1256
1257 #ifdef IUTF8
1258 tp->c_iflag = tp->c_iflag & IUTF8;
1259 if (tp->c_iflag & IUTF8)
1260 op->flags |= F_UTF8;
1261 #else
1262 tp->c_iflag = 0;
1263 #endif
1264 tp->c_lflag = 0;
1265 tp->c_oflag &= OPOST | ONLCR;
1266
1267 if ((op->flags & F_KEEPCFLAGS) == 0)
1268 tp->c_cflag = CS8 | HUPCL | CREAD | (tp->c_cflag & CLOCAL);
1269
1270 /*
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.
1273 */
1274 cfsetispeed(tp, ispeed);
1275 cfsetospeed(tp, ospeed);
1276
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 */
1282 break;
1283 case CLOCAL_MODE_NEVER:
1284 tp->c_cflag &= ~CLOCAL; /* -L=never */
1285 break;
1286 case CLOCAL_MODE_AUTO: /* -L=auto */
1287 break;
1288 }
1289
1290 #ifdef HAVE_STRUCT_TERMIOS_C_LINE
1291 tp->c_line = 0;
1292 #endif
1293 tp->c_cc[VMIN] = 1;
1294 tp->c_cc[VTIME] = 0;
1295
1296 /* Check for terminal size and if not found set default */
1297 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0) {
1298 int set = 0;
1299 if (ws.ws_row == 0) {
1300 ws.ws_row = 24;
1301 set++;
1302 }
1303 if (ws.ws_col == 0) {
1304 ws.ws_col = 80;
1305 set++;
1306 }
1307 if (ioctl(STDIN_FILENO, TIOCSWINSZ, &ws))
1308 debug("TIOCSWINSZ ioctl failed\n");
1309 }
1310
1311 /* Optionally enable hardware flow control. */
1312 #ifdef CRTSCTS
1313 if (op->flags & F_RTSCTS)
1314 tp->c_cflag |= CRTSCTS;
1315 #endif
1316 /* Flush input and output queues, important for modems! */
1317 tcflush(STDIN_FILENO, TCIOFLUSH);
1318
1319 if (tcsetattr(STDIN_FILENO, TCSANOW, tp))
1320 log_warn(_("setting terminal attributes failed: %m"));
1321
1322 /* Go to blocking input even in local mode. */
1323 fcntl(STDIN_FILENO, F_SETFL,
1324 fcntl(STDIN_FILENO, F_GETFL, 0) & ~O_NONBLOCK);
1325
1326 debug("term_io 2\n");
1327 }
1328
1329 /* Reset virtual console on stdin to its defaults */
1330 static void reset_vc(const struct options *op, struct termios *tp)
1331 {
1332 int fl = 0;
1333
1334 fl |= (op->flags & F_KEEPCFLAGS) == 0 ? 0 : UL_TTY_KEEPCFLAGS;
1335 fl |= (op->flags & F_UTF8) == 0 ? 0 : UL_TTY_UTF8;
1336
1337 reset_virtual_console(tp, fl);
1338
1339 if (tcsetattr(STDIN_FILENO, TCSADRAIN, tp))
1340 log_warn(_("setting terminal attributes failed: %m"));
1341
1342 /* Go to blocking input even in local mode. */
1343 fcntl(STDIN_FILENO, F_SETFL,
1344 fcntl(STDIN_FILENO, F_GETFL, 0) & ~O_NONBLOCK);
1345 }
1346
1347 /* Extract baud rate from modem status message. */
1348 static void auto_baud(struct termios *tp)
1349 {
1350 speed_t speed;
1351 int vmin;
1352 unsigned iflag;
1353 char buf[BUFSIZ];
1354 char *bp;
1355 int nread;
1356
1357 /*
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
1361 * following format:
1362 *
1363 * <junk><number><junk>
1364 *
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.
1370 */
1371
1372 /*
1373 * Use 7-bit characters, don't block if input queue is empty. Errors will
1374 * be dealt with later on.
1375 */
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. */
1381 tp->c_cc[VMIN] = 0;
1382 tcsetattr(STDIN_FILENO, TCSANOW, tp);
1383
1384 /*
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.
1387 */
1388 sleep(1);
1389 if ((nread = read(STDIN_FILENO, buf, sizeof(buf) - 1)) > 0) {
1390 buf[nread] = '\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);
1396 }
1397 break;
1398 }
1399 }
1400
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);
1405 }
1406
1407 static char *xgethostname(void)
1408 {
1409 char *name;
1410 size_t sz = get_hostname_max() + 1;
1411
1412 name = malloc(sizeof(char) * sz);
1413 if (!name)
1414 log_err(_("failed to allocate memory: %m"));
1415
1416 if (gethostname(name, sz) != 0) {
1417 free(name);
1418 return NULL;
1419 }
1420 name[sz - 1] = '\0';
1421 return name;
1422 }
1423
1424 static char *xgetdomainname(void)
1425 {
1426 #ifdef HAVE_GETDOMAINNAME
1427 char *name;
1428 size_t sz = get_hostname_max() + 1;
1429
1430 name = malloc(sizeof(char) * sz);
1431 if (!name)
1432 log_err(_("failed to allocate memory: %m"));
1433
1434 if (getdomainname(name, sz) != 0) {
1435 free(name);
1436 return NULL;
1437 }
1438 name[sz - 1] = '\0';
1439 return name;
1440 #endif
1441 return NULL;
1442 }
1443
1444 static char *read_os_release(struct options *op, const char *varname)
1445 {
1446 int fd = -1;
1447 struct stat st;
1448 size_t varsz = strlen(varname);
1449 char *p, *buf = NULL, *ret = NULL;
1450
1451 /* read the file only once */
1452 if (!op->osrelease) {
1453 fd = open(_PATH_OS_RELEASE_ETC, O_RDONLY);
1454 if (fd == -1) {
1455 fd = open(_PATH_OS_RELEASE_USR, O_RDONLY);
1456 if (fd == -1) {
1457 log_warn(_("cannot open os-release file"));
1458 return NULL;
1459 }
1460 }
1461
1462 if (fstat(fd, &st) < 0 || st.st_size > 4 * 1024 * 1024)
1463 goto done;
1464
1465 op->osrelease = malloc(st.st_size + 1);
1466 if (!op->osrelease)
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;
1471 goto done;
1472 }
1473 op->osrelease[st.st_size] = 0;
1474 }
1475 buf = strdup(op->osrelease);
1476 if (!buf)
1477 log_err(_("failed to allocate memory: %m"));
1478 p = buf;
1479
1480 for (;;) {
1481 char *eol, *eon;
1482
1483 p += strspn(p, "\n\r");
1484 p += strspn(p, " \t\n\r");
1485 if (!*p)
1486 break;
1487 if (strspn(p, "#;\n") != 0) {
1488 p += strcspn(p, "\n\r");
1489 continue;
1490 }
1491 if (strncmp(p, varname, varsz) != 0) {
1492 p += strcspn(p, "\n\r");
1493 continue;
1494 }
1495 p += varsz;
1496 p += strspn(p, " \t\n\r=\"");
1497 eol = p + strcspn(p, "\n\r");
1498 *eol = '\0';
1499 eon = eol-1;
1500 while (eon > p) {
1501 if (*eon == '\t' || *eon == ' ') {
1502 eon--;
1503 continue;
1504 }
1505 if (*eon == '"') {
1506 *eon = '\0';
1507 break;
1508 }
1509 break;
1510 }
1511 free(ret);
1512 ret = strdup(p);
1513 if (!ret)
1514 log_err(_("failed to allocate memory: %m"));
1515 p = eol + 1;
1516 }
1517 done:
1518 free(buf);
1519 if (fd >= 0)
1520 close(fd);
1521 return ret;
1522 }
1523
1524 #ifdef AGETTY_RELOAD
1525 static void open_netlink(void)
1526 {
1527 struct sockaddr_nl addr = { 0, };
1528 int sock;
1529
1530 if (netlink_fd != AGETTY_RELOAD_FDNONE)
1531 return;
1532
1533 sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
1534 if (sock >= 0) {
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)
1539 close(sock);
1540 else
1541 netlink_fd = sock;
1542 }
1543 }
1544
1545 static int process_netlink_msg(int *changed)
1546 {
1547 char buf[4096];
1548 struct sockaddr_nl snl;
1549 struct nlmsghdr *h;
1550 int rc;
1551
1552 struct iovec iov = {
1553 .iov_base = buf,
1554 .iov_len = sizeof(buf)
1555 };
1556 struct msghdr msg = {
1557 .msg_name = &snl,
1558 .msg_namelen = sizeof(snl),
1559 .msg_iov = &iov,
1560 .msg_iovlen = 1,
1561 .msg_control = NULL,
1562 .msg_controllen = 0,
1563 .msg_flags = 0
1564 };
1565
1566 rc = recvmsg(netlink_fd, &msg, MSG_DONTWAIT);
1567 if (rc < 0) {
1568 if (errno == EWOULDBLOCK || errno == EAGAIN)
1569 return 0;
1570
1571 /* Failure, just stop listening for changes */
1572 close(netlink_fd);
1573 netlink_fd = AGETTY_RELOAD_FDNONE;
1574 return 0;
1575 }
1576
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) {
1580 close(netlink_fd);
1581 netlink_fd = AGETTY_RELOAD_FDNONE;
1582 return 0;
1583 }
1584
1585 *changed = 1;
1586 break;
1587 }
1588
1589 return 1;
1590 }
1591
1592 static int process_netlink(void)
1593 {
1594 int changed = 0;
1595 while (process_netlink_msg(&changed));
1596 return changed;
1597 }
1598
1599 static int wait_for_term_input(int fd)
1600 {
1601 char buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
1602 struct termios orig, nonc;
1603 fd_set rfds;
1604 int count, i;
1605
1606 /* Our aim here is to fall through if something fails
1607 * and not be stuck waiting. On failure assume we have input */
1608
1609 if (tcgetattr(fd, &orig) != 0)
1610 return 1;
1611
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;
1616
1617 if (tcsetattr(fd, TCSANOW, &nonc) != 0)
1618 return 1;
1619
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,
1624 S_IRUSR|S_IWUSR);
1625
1626 /* initialize reload trigger inotify stuff */
1627 if (reload_fd >= 0) {
1628 inotify_fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
1629 if (inotify_fd > 0)
1630 inotify_add_watch(inotify_fd, AGETTY_RELOAD_FILENAME,
1631 IN_ATTRIB | IN_MODIFY);
1632
1633 close(reload_fd);
1634 } else
1635 log_warn(_("failed to create reload file: %s: %m"),
1636 AGETTY_RELOAD_FILENAME);
1637 }
1638
1639 while (1) {
1640 int nfds = fd;
1641
1642 FD_ZERO(&rfds);
1643 FD_SET(fd, &rfds);
1644
1645 if (inotify_fd >= 0) {
1646 FD_SET(inotify_fd, &rfds);
1647 nfds = max(nfds, inotify_fd);
1648 }
1649 if (netlink_fd >= 0) {
1650 FD_SET(netlink_fd, &rfds);
1651 nfds = max(nfds, netlink_fd);
1652 }
1653
1654 /* If waiting fails, just fall through, presumably reading input will fail */
1655 if (select(nfds + 1, &rfds, NULL, NULL, NULL) < 0)
1656 return 1;
1657
1658 if (FD_ISSET(fd, &rfds)) {
1659 count = read(fd, buffer, sizeof (buffer));
1660
1661 tcsetattr(fd, TCSANOW, &orig);
1662
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);
1666
1667 /* Have terminal input */
1668 return 1;
1669
1670 } else if (netlink_fd >= 0 && FD_ISSET(netlink_fd, &rfds)) {
1671 if (!process_netlink())
1672 continue;
1673
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);
1677 }
1678
1679 tcsetattr(fd, TCSANOW, &orig);
1680
1681 /* Need to reprompt */
1682 return 0;
1683 }
1684 }
1685 #endif /* AGETTY_RELOAD */
1686 static void print_issue_file(struct options *op, struct termios *tp)
1687 {
1688 #ifdef ISSUE
1689 FILE *fd;
1690 #endif
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);
1694 }
1695
1696 #ifdef ISSUE
1697 if ((op->flags & F_ISSUE) && (fd = fopen(op->issue, "r"))) {
1698 int c, oflag = tp->c_oflag; /* Save current setting. */
1699
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);
1704 }
1705
1706 while ((c = getc(fd)) != EOF) {
1707 if (c == '\\')
1708 output_special_char(getc(fd), op, tp, fd);
1709 else
1710 putchar(c);
1711 }
1712 fflush(stdout);
1713
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);
1719 }
1720 fclose(fd);
1721 }
1722 #endif /* ISSUE */
1723 }
1724
1725 /* Show login prompt, optionally preceded by /etc/issue contents. */
1726 static void do_prompt(struct options *op, struct termios *tp)
1727 {
1728 again:
1729 print_issue_file(op, tp);
1730
1731 if (op->flags & F_LOGINPAUSE) {
1732 puts(_("[press ENTER to login]"));
1733 #ifdef AGETTY_RELOAD
1734 if (!wait_for_term_input(STDIN_FILENO)) {
1735 /* reload issue */
1736 if (op->flags & F_VCONSOLE)
1737 termio_clear(STDOUT_FILENO);
1738 goto again;
1739 }
1740 #endif
1741 getc(stdin);
1742 }
1743 #ifdef KDGKBLED
1744 if (!(op->flags & F_NOHINTS) && !op->autolog &&
1745 (op->flags & F_VCONSOLE)) {
1746 int kb = 0;
1747
1748 if (ioctl(STDIN_FILENO, KDGKBLED, &kb) == 0) {
1749 char hint[256] = { '\0' };
1750 int nl = 0;
1751
1752 if (access(_PATH_NUMLOCK_ON, F_OK) == 0)
1753 nl = 1;
1754
1755 if (nl && (kb & 0x02) == 0)
1756 append(hint, sizeof(hint), NULL, _("Num Lock off"));
1757
1758 else if (nl == 0 && (kb & 2) && (kb & 0x20) == 0)
1759 append(hint, sizeof(hint), NULL, _("Num Lock on"));
1760
1761 if ((kb & 0x04) && (kb & 0x40) == 0)
1762 append(hint, sizeof(hint), ", ", _("Caps Lock on"));
1763
1764 if ((kb & 0x01) && (kb & 0x10) == 0)
1765 append(hint, sizeof(hint), ", ", _("Scroll Lock on"));
1766
1767 if (*hint)
1768 printf(_("Hint: %s\n\n"), hint);
1769 }
1770 }
1771 #endif /* KDGKBLED */
1772 if ((op->flags & F_NOHOSTNAME) == 0) {
1773 char *hn = xgethostname();
1774
1775 if (hn) {
1776 char *dot = strchr(hn, '.');
1777 char *cn = hn;
1778 struct addrinfo *res = NULL;
1779
1780 if ((op->flags & F_LONGHNAME) == 0) {
1781 if (dot)
1782 *dot = '\0';
1783
1784 } else if (dot == NULL) {
1785 struct addrinfo hints;
1786
1787 memset(&hints, 0, sizeof(hints));
1788 hints.ai_flags = AI_CANONNAME;
1789
1790 if (!getaddrinfo(hn, NULL, &hints, &res)
1791 && res && res->ai_canonname)
1792 cn = res->ai_canonname;
1793 }
1794
1795 write_all(STDOUT_FILENO, cn, strlen(cn));
1796 write_all(STDOUT_FILENO, " ", 1);
1797
1798 if (res)
1799 freeaddrinfo(res);
1800 free(hn);
1801 }
1802 }
1803 if (!op->autolog) {
1804 /* Always show login prompt. */
1805 write_all(STDOUT_FILENO, LOGIN, sizeof(LOGIN) - 1);
1806 }
1807 }
1808
1809 /* Select next baud rate. */
1810 static void next_speed(struct options *op, struct termios *tp)
1811 {
1812 static int baud_index = -1;
1813
1814 if (baud_index == -1)
1815 /*
1816 * If the F_KEEPSPEED flags is set then the FIRST_SPEED is not
1817 * tested yet (see termio_init()).
1818 */
1819 baud_index =
1820 (op->flags & F_KEEPSPEED) ? FIRST_SPEED : 1 % op->numspeed;
1821 else
1822 baud_index = (baud_index + 1) % op->numspeed;
1823
1824 cfsetispeed(tp, op->speeds[baud_index]);
1825 cfsetospeed(tp, op->speeds[baud_index]);
1826 tcsetattr(STDIN_FILENO, TCSANOW, tp);
1827 }
1828
1829 /* Get user name, establish parity, speed, erase, kill & eol. */
1830 static char *get_logname(struct options *op, struct termios *tp, struct chardata *cp)
1831 {
1832 static char logname[BUFSIZ];
1833 char *bp;
1834 char c; /* input character, full eight bits */
1835 char ascval; /* low 7 bits of input character */
1836 int eightbit;
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 */
1842 };
1843
1844 /* Initialize kill, erase, parity etc. (also after switching speeds). */
1845 INIT_CHARDATA(cp);
1846
1847 /*
1848 * Flush pending input (especially important after parsing or switching
1849 * the baud rate).
1850 */
1851 if ((op->flags & F_VCONSOLE) == 0)
1852 sleep(1);
1853 tcflush(STDIN_FILENO, TCIFLUSH);
1854
1855 eightbit = (op->flags & F_EIGHTBITS);
1856 bp = logname;
1857 *bp = '\0';
1858
1859 while (*logname == '\0') {
1860
1861 /* Write issue file and prompt */
1862 do_prompt(op, tp);
1863
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);
1869 continue;
1870 }
1871 #endif
1872 cp->eol = '\0';
1873
1874 /* Read name, watch for break and end-of-line. */
1875 while (cp->eol == '\0') {
1876
1877 char key;
1878
1879 if (read(STDIN_FILENO, &c, 1) < 1) {
1880
1881 /* The terminal could be open with O_NONBLOCK when
1882 * -L (force CLOCAL) is specified... */
1883 if (errno == EINTR || errno == EAGAIN) {
1884 xusleep(250000);
1885 continue;
1886 }
1887 switch (errno) {
1888 case 0:
1889 case EIO:
1890 case ESRCH:
1891 case EINVAL:
1892 case ENOENT:
1893 break;
1894 default:
1895 log_err(_("%s: read: %m"), op->tty);
1896 }
1897 }
1898
1899 /* Do parity bit handling. */
1900 if (eightbit)
1901 ascval = c;
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) {
1906 if (mask & ascval)
1907 bits++;
1908 }
1909 cp->parity |= ((bits & 1) ? 1 : 2);
1910 }
1911
1912 if (op->killchars && strchr(op->killchars, ascval))
1913 key = CTL('U');
1914 else if (op->erasechars && strchr(op->erasechars, ascval))
1915 key = DEL;
1916 else
1917 key = ascval;
1918
1919 /* Do erase, kill and end-of-line processing. */
1920 switch (key) {
1921 case 0:
1922 *bp = 0;
1923 if (op->numspeed > 1)
1924 return NULL;
1925 break;
1926 case CR:
1927 case NL:
1928 *bp = 0; /* terminate logname */
1929 cp->eol = ascval; /* set end-of-line char */
1930 break;
1931 case BS:
1932 case DEL:
1933 cp->erase = ascval; /* set erase character */
1934 if (bp > logname) {
1935 if ((tp->c_lflag & ECHO) == 0)
1936 write_all(1, erase[cp->parity], 3);
1937 bp--;
1938 }
1939 break;
1940 case CTL('U'):
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);
1945 bp--;
1946 }
1947 break;
1948 case CTL('D'):
1949 exit(EXIT_SUCCESS);
1950 default:
1951 if (!isascii(ascval) || !isprint(ascval))
1952 break;
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 */
1958 break;
1959 }
1960 }
1961 }
1962 #ifdef HAVE_WIDECHAR
1963 if ((op->flags & (F_EIGHTBITS|F_UTF8)) == (F_EIGHTBITS|F_UTF8)) {
1964 /* Check out UTF-8 multibyte characters */
1965 ssize_t len;
1966 wchar_t *wcs, *wcp;
1967
1968 len = mbstowcs((wchar_t *)0, logname, 0);
1969 if (len < 0)
1970 log_err(_("%s: invalid character conversion for login name"), op->tty);
1971
1972 wcs = malloc((len + 1) * sizeof(wchar_t));
1973 if (!wcs)
1974 log_err(_("failed to allocate memory: %m"));
1975
1976 len = mbstowcs(wcs, logname, len + 1);
1977 if (len < 0)
1978 log_err(_("%s: invalid character conversion for login name"), op->tty);
1979
1980 wcp = wcs;
1981 while (*wcp) {
1982 const wint_t wc = *wcp++;
1983 if (!iswprint(wc))
1984 log_err(_("%s: invalid character 0x%x in login name"), op->tty, wc);
1985 }
1986 free(wcs);
1987 } else
1988 #endif
1989 if ((op->flags & F_LCUC) && (cp->capslock = caps_lock(logname))) {
1990
1991 /* Handle names with upper case and no lower case. */
1992 for (bp = logname; *bp; bp++)
1993 if (isupper(*bp))
1994 *bp = tolower(*bp); /* map name to lower case */
1995 }
1996
1997 return logname;
1998 }
1999
2000 /* Set the final tty mode bits. */
2001 static void termio_final(struct options *op, struct termios *tp, struct chardata *cp)
2002 {
2003 /* General terminal-independent stuff. */
2004
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;
2015 #ifdef __linux__
2016 tp->c_cc[VSWTC] = DEF_SWITCH;
2017 #elif defined(VSWTCH)
2018 tp->c_cc[VSWTCH] = DEF_SWITCH;
2019 #endif /* __linux__ */
2020
2021 /* Account for special characters seen in input. */
2022 if (cp->eol == CR) {
2023 tp->c_iflag |= ICRNL;
2024 tp->c_oflag |= ONLCR;
2025 }
2026 tp->c_cc[VERASE] = cp->erase;
2027 tp->c_cc[VKILL] = cp->kill;
2028
2029 /* Account for the presence or absence of parity bits in input. */
2030 switch (cp->parity) {
2031 case 0:
2032 /* space (always 0) parity */
2033 break;
2034 case 1:
2035 /* odd parity */
2036 tp->c_cflag |= PARODD;
2037 /* do not break */
2038 case 2:
2039 /* even parity */
2040 tp->c_cflag |= PARENB;
2041 tp->c_iflag |= INPCK | ISTRIP;
2042 /* do not break */
2043 case (1 | 2):
2044 /* no parity bit */
2045 tp->c_cflag &= ~CSIZE;
2046 tp->c_cflag |= CS7;
2047 break;
2048 }
2049 /* Account for upper case without lower case. */
2050 if (cp->capslock) {
2051 #ifdef IUCLC
2052 tp->c_iflag |= IUCLC;
2053 #endif
2054 #ifdef XCASE
2055 tp->c_lflag |= XCASE;
2056 #endif
2057 #ifdef OLCUC
2058 tp->c_oflag |= OLCUC;
2059 #endif
2060 }
2061 /* Optionally enable hardware flow control. */
2062 #ifdef CRTSCTS
2063 if (op->flags & F_RTSCTS)
2064 tp->c_cflag |= CRTSCTS;
2065 #endif
2066
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);
2070 }
2071
2072 /*
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
2076 */
2077 static int caps_lock(char *s)
2078 {
2079 int capslock;
2080
2081 for (capslock = 0; *s; s++) {
2082 if (islower(*s))
2083 return EXIT_SUCCESS;
2084 if (capslock == 0)
2085 capslock = isupper(*s);
2086 }
2087 return capslock;
2088 }
2089
2090 /* Convert speed string to speed code; return 0 on failure. */
2091 static speed_t bcode(char *s)
2092 {
2093 const struct Speedtab *sp;
2094 long speed = atol(s);
2095
2096 for (sp = speedtab; sp->speed; sp++)
2097 if (sp->speed == speed)
2098 return sp->code;
2099 return 0;
2100 }
2101
2102 static void __attribute__ ((__noreturn__)) usage(FILE *out)
2103 {
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);
2107
2108 fputs(USAGE_SEPARATOR, out);
2109 fputs(_("Open a terminal and set its mode.\n"), out);
2110
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)"));
2147
2148 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
2149 }
2150
2151 /*
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.
2155 */
2156 #define str2cpy(b,s1,s2) strcat(strcpy(b,s1),s2)
2157
2158 static void dolog(int priority, const char *fmt, va_list ap)
2159 {
2160 #ifndef USE_SYSLOG
2161 int fd;
2162 #endif
2163 char buf[BUFSIZ];
2164 char *bp;
2165
2166 /*
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.
2170 */
2171 #ifdef USE_SYSLOG
2172 buf[0] = '\0';
2173 bp = buf;
2174 #else
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);
2179
2180 /*
2181 * Write the diagnostic directly to /dev/console if we do not use the
2182 * syslog(3) facility.
2183 */
2184 #ifdef USE_SYSLOG
2185 openlog(program_invocation_short_name, LOG_PID, LOG_AUTHPRIV);
2186 syslog(priority, "%s", buf);
2187 closelog();
2188 #else
2189 /* Terminate with CR-LF since the console mode is unknown. */
2190 strcat(bp, "\r\n");
2191 if ((fd = open("/dev/console", 1)) >= 0) {
2192 write_all(fd, buf, strlen(buf));
2193 close(fd);
2194 }
2195 #endif /* USE_SYSLOG */
2196 }
2197
2198 static void log_err(const char *fmt, ...)
2199 {
2200 va_list ap;
2201
2202 va_start(ap, fmt);
2203 dolog(LOG_ERR, fmt, ap);
2204 va_end(ap);
2205
2206 /* Be kind to init(8). */
2207 sleep(10);
2208 exit(EXIT_FAILURE);
2209 }
2210
2211 static void log_warn(const char *fmt, ...)
2212 {
2213 va_list ap;
2214
2215 va_start(ap, fmt);
2216 dolog(LOG_WARNING, fmt, ap);
2217 va_end(ap);
2218 }
2219
2220 static void print_addr(sa_family_t family, void *addr)
2221 {
2222 char buff[INET6_ADDRSTRLEN + 1];
2223
2224 inet_ntop(family, addr, buff, sizeof(buff));
2225 printf("%s", buff);
2226 }
2227
2228 /*
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.
2232 */
2233 static void output_iface_ip(struct ifaddrs *addrs,
2234 const char *iface,
2235 sa_family_t family)
2236 {
2237 struct ifaddrs *p;
2238 struct addrinfo hints, *info = NULL;
2239 char *host = NULL;
2240 void *addr = NULL;
2241
2242 if (!addrs)
2243 return;
2244
2245 for (p = addrs; p; p = p->ifa_next) {
2246
2247 if (!p->ifa_name ||
2248 !p->ifa_addr ||
2249 p->ifa_addr->sa_family != family)
2250 continue;
2251
2252 if (iface) {
2253 /* Filter out by interface name */
2254 if (strcmp(p->ifa_name, iface) != 0)
2255 continue;
2256 } else {
2257 /* Select the "best" interface */
2258 if ((p->ifa_flags & IFF_LOOPBACK) ||
2259 !(p->ifa_flags & IFF_UP) ||
2260 !(p->ifa_flags & IFF_RUNNING))
2261 continue;
2262 }
2263
2264 addr = NULL;
2265 switch (p->ifa_addr->sa_family) {
2266 case AF_INET:
2267 addr = &((struct sockaddr_in *) p->ifa_addr)->sin_addr;
2268 break;
2269 case AF_INET6:
2270 addr = &((struct sockaddr_in6 *) p->ifa_addr)->sin6_addr;
2271 break;
2272 }
2273
2274 if (addr) {
2275 print_addr(family, addr);
2276 return;
2277 }
2278 }
2279
2280 if (iface)
2281 return;
2282
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;
2288
2289 host = xgethostname();
2290 if (host && getaddrinfo(host, NULL, &hints, &info) == 0 && info) {
2291 switch (info->ai_family) {
2292 case AF_INET:
2293 addr = &((struct sockaddr_in *) info->ai_addr)->sin_addr;
2294 break;
2295 case AF_INET6:
2296 addr = &((struct sockaddr_in6 *) info->ai_addr)->sin6_addr;
2297 break;
2298 }
2299 if (addr)
2300 print_addr(family, addr);
2301
2302 freeaddrinfo(info);
2303 }
2304 free(host);
2305 }
2306
2307 /*
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 '{').
2310 */
2311 static char *get_escape_argument(FILE *fd, char *buf, size_t bufsz)
2312 {
2313 size_t i = 0;
2314 int c = fgetc(fd);
2315
2316 if (c == EOF || (unsigned char) c != '{') {
2317 ungetc(c, fd);
2318 return NULL;
2319 }
2320
2321 do {
2322 c = fgetc(fd);
2323 if (c == EOF)
2324 return NULL;
2325 if ((unsigned char) c != '}' && i < bufsz - 1)
2326 buf[i++] = (unsigned char) c;
2327
2328 } while ((unsigned char) c != '}');
2329
2330 buf[i] = '\0';
2331 return buf;
2332 }
2333
2334 static void output_special_char(unsigned char c, struct options *op,
2335 struct termios *tp, FILE *fp)
2336 {
2337 struct utsname uts;
2338
2339 uname(&uts);
2340
2341 switch (c) {
2342 case 'e':
2343 {
2344 char escname[UL_COLORNAME_MAXSZ];
2345
2346 if (get_escape_argument(fp, escname, sizeof(escname))) {
2347 const char *esc = color_sequence_from_colorname(escname);
2348 if (esc)
2349 fputs(esc, stdout);
2350 } else
2351 fputs("\033", stdout);
2352 break;
2353 }
2354 case 's':
2355 printf("%s", uts.sysname);
2356 break;
2357 case 'n':
2358 printf("%s", uts.nodename);
2359 break;
2360 case 'r':
2361 printf("%s", uts.release);
2362 break;
2363 case 'v':
2364 printf("%s", uts.version);
2365 break;
2366 case 'm':
2367 printf("%s", uts.machine);
2368 break;
2369 case 'o':
2370 {
2371 char *dom = xgetdomainname();
2372
2373 fputs(dom ? dom : "unknown_domain", stdout);
2374 free(dom);
2375 break;
2376 }
2377 case 'O':
2378 {
2379 char *dom = NULL;
2380 char *host = xgethostname();
2381 struct addrinfo hints, *info = NULL;
2382
2383 memset(&hints, 0, sizeof(hints));
2384 hints.ai_flags = AI_CANONNAME;
2385
2386 if (host && getaddrinfo(host, NULL, &hints, &info) == 0 && info) {
2387 char *canon;
2388
2389 if (info->ai_canonname &&
2390 (canon = strchr(info->ai_canonname, '.')))
2391 dom = canon + 1;
2392 }
2393 fputs(dom ? dom : "unknown_domain", stdout);
2394 if (info)
2395 freeaddrinfo(info);
2396 free(host);
2397 break;
2398 }
2399 case 'd':
2400 case 't':
2401 {
2402 time_t now;
2403 struct tm *tm;
2404
2405 time(&now);
2406 tm = localtime(&now);
2407
2408 if (!tm)
2409 break;
2410
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),
2415 tm->tm_mday,
2416 tm->tm_year < 70 ? tm->tm_year + 2000 :
2417 tm->tm_year + 1900);
2418 else
2419 printf("%02d:%02d:%02d",
2420 tm->tm_hour, tm->tm_min, tm->tm_sec);
2421 break;
2422 }
2423 case 'l':
2424 printf ("%s", op->tty);
2425 break;
2426 case 'b':
2427 {
2428 const speed_t speed = cfgetispeed(tp);
2429 int i;
2430
2431 for (i = 0; speedtab[i].speed; i++) {
2432 if (speedtab[i].code == speed) {
2433 printf("%ld", speedtab[i].speed);
2434 break;
2435 }
2436 }
2437 break;
2438 }
2439 case 'S':
2440 {
2441 char *var = NULL, varname[64];
2442
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")))
2446 var = uts.sysname;
2447 if (var) {
2448 if (strcmp(varname, "ANSI_COLOR") == 0)
2449 printf("\033[%sm", var);
2450 else
2451 printf("%s", var);
2452 if (var != uts.sysname)
2453 free(var);
2454 }
2455 break;
2456 }
2457 case 'u':
2458 case 'U':
2459 {
2460 int users = 0;
2461 struct utmp *ut;
2462 setutent();
2463 while ((ut = getutent()))
2464 if (ut->ut_type == USER_PROCESS)
2465 users++;
2466 endutent();
2467 if (c == 'U')
2468 printf(P_("%d user", "%d users", users), users);
2469 else
2470 printf ("%d ", users);
2471 break;
2472 }
2473 case '4':
2474 case '6':
2475 {
2476 sa_family_t family = c == '4' ? AF_INET : AF_INET6;
2477 struct ifaddrs *addrs = NULL;
2478 char iface[128];
2479
2480 #ifdef AGETTY_RELOAD
2481 open_netlink();
2482 #endif
2483
2484 if (getifaddrs(&addrs))
2485 break;
2486
2487 if (get_escape_argument(fp, iface, sizeof(iface)))
2488 output_iface_ip(addrs, iface, family);
2489 else
2490 output_iface_ip(addrs, NULL, family);
2491
2492 freeifaddrs(addrs);
2493 break;
2494 }
2495 default:
2496 putchar(c);
2497 break;
2498 }
2499 }
2500
2501 static void init_special_char(char* arg, struct options *op)
2502 {
2503 char ch, *p, *q;
2504 int i;
2505
2506 op->initstring = malloc(strlen(arg) + 1);
2507 if (!op->initstring)
2508 log_err(_("failed to allocate memory: %m"));
2509
2510 /*
2511 * Copy optarg into op->initstring decoding \ddd octal
2512 * codes into chars.
2513 */
2514 q = op->initstring;
2515 p = arg;
2516 while (*p) {
2517 /* The \\ is converted to \ */
2518 if (*p == '\\') {
2519 p++;
2520 if (*p == '\\') {
2521 ch = '\\';
2522 p++;
2523 } else {
2524 /* Handle \000 - \177. */
2525 ch = 0;
2526 for (i = 1; i <= 3; i++) {
2527 if (*p >= '0' && *p <= '7') {
2528 ch <<= 3;
2529 ch += *p - '0';
2530 p++;
2531 } else {
2532 break;
2533 }
2534 }
2535 }
2536 *q++ = ch;
2537 } else
2538 *q++ = *p++;
2539 }
2540 *q = '\0';
2541 }
2542
2543 /*
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.
2546 *
2547 * Returns the final @dest length or -1 in case of error.
2548 */
2549 static ssize_t append(char *dest, size_t len, const char *sep, const char *src)
2550 {
2551 size_t dsz = 0, ssz = 0, sz;
2552 char *p;
2553
2554 if (!dest || !len || !src)
2555 return -1;
2556
2557 if (*dest)
2558 dsz = strlen(dest);
2559 if (dsz && sep)
2560 ssz = strlen(sep);
2561 sz = strlen(src);
2562
2563 if (dsz + ssz + sz + 1 > len)
2564 return -1;
2565
2566 p = dest + dsz;
2567 if (ssz) {
2568 memcpy(p, sep, ssz);
2569 p += ssz;
2570 }
2571 memcpy(p, src, sz);
2572 *(p + sz) = '\0';
2573
2574 return dsz + ssz + sz;
2575 }
2576
2577 /*
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.
2581 */
2582 static void check_username(const char* nm)
2583 {
2584 const char *p = nm;
2585 if (!nm)
2586 goto err;
2587 if (strlen(nm) > 42)
2588 goto err;
2589 while (isspace(*p))
2590 p++;
2591 if (*p == '-')
2592 goto err;
2593 return;
2594 err:
2595 errno = EPERM;
2596 log_err(_("checkname failed: %m"));
2597 }
2598
2599 /*
2600 * For the case plymouth is found on this system
2601 */
2602 static int plymouth_command(const char* arg)
2603 {
2604 static int has_plymouth = 1;
2605 pid_t pid;
2606
2607 if (!has_plymouth)
2608 return 127;
2609
2610 pid = fork();
2611 if (!pid) {
2612 int fd = open(AGETTY_PLYMOUTH_FDFILE, O_RDWR);
2613
2614 if (fd < 0)
2615 err(EXIT_FAILURE,_("cannot open %s"),
2616 AGETTY_PLYMOUTH_FDFILE);
2617 dup2(fd, 0);
2618 dup2(fd, 1);
2619 dup2(fd, 2);
2620 close(fd);
2621 execl(AGETTY_PLYMOUTH, AGETTY_PLYMOUTH, arg, (char *) NULL);
2622 exit(127);
2623 } else if (pid > 0) {
2624 int status;
2625 waitpid(pid, &status, 0);
2626 if (status == 127)
2627 has_plymouth = 0;
2628 return status;
2629 }
2630 return 1;
2631 }
2632
2633 static void reload_agettys(void)
2634 {
2635 #ifdef AGETTY_RELOAD
2636 int fd = open(AGETTY_RELOAD_FILENAME, O_CREAT|O_CLOEXEC|O_WRONLY,
2637 S_IRUSR|S_IWUSR);
2638 if (fd < 0)
2639 err(EXIT_FAILURE, _("cannot open %s"), AGETTY_RELOAD_FILENAME);
2640
2641 if (futimens(fd, NULL) < 0 || close(fd) < 0)
2642 err(EXIT_FAILURE, _("cannot touch file %s"),
2643 AGETTY_RELOAD_FILENAME);
2644 #else
2645 /* very unusual */
2646 errx(EXIT_FAILURE, _("--reload is unsupported on your system"));
2647 #endif
2648 }