]> git.ipfire.org Git - thirdparty/util-linux.git/blob - term-utils/agetty.c
Merge branch 'libuuid/coverity' of https://github.com/t-8ch/util-linux
[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 <utmpx.h>
29 #include <getopt.h>
30 #include <time.h>
31 #include <sys/socket.h>
32 #include <langinfo.h>
33 #include <grp.h>
34 #include <pwd.h>
35 #include <arpa/inet.h>
36 #include <netdb.h>
37 #include <ifaddrs.h>
38 #include <net/if.h>
39 #include <sys/utsname.h>
40
41 #include "strutils.h"
42 #include "all-io.h"
43 #include "nls.h"
44 #include "pathnames.h"
45 #include "c.h"
46 #include "cctype.h"
47 #include "widechar.h"
48 #include "ttyutils.h"
49 #include "color-names.h"
50 #include "env.h"
51 #include "path.h"
52 #include "fileutils.h"
53
54 #include "logindefs.h"
55
56 #ifdef USE_PLYMOUTH_SUPPORT
57 # include "plymouth-ctrl.h"
58 #endif
59
60 #ifdef HAVE_SYS_PARAM_H
61 # include <sys/param.h>
62 #endif
63
64 #ifdef HAVE_GETTTYNAM
65 # include <ttyent.h>
66 #endif
67
68 #if defined(__FreeBSD_kernel__)
69 # include <pty.h>
70 # ifdef HAVE_UTMP_H
71 # include <utmp.h>
72 # endif
73 # ifdef HAVE_LIBUTIL_H
74 # include <libutil.h>
75 # endif
76 #endif
77
78 #ifdef USE_SYSTEMD
79 # include <systemd/sd-daemon.h>
80 # include <systemd/sd-login.h>
81 #endif
82
83 #ifdef __linux__
84 # include <sys/kd.h>
85 # define USE_SYSLOG
86 #elif defined(__GNU__)
87 # define USE_SYSLOG
88 #endif
89
90 #ifdef __FreeBSD_kernel__
91 #define USE_SYSLOG
92 #endif
93
94 /* If USE_SYSLOG is undefined all diagnostics go to /dev/console. */
95 #ifdef USE_SYSLOG
96 # include <syslog.h>
97 #endif
98
99 /*
100 * Some heuristics to find out what environment we are in: if it is not
101 * System V, assume it is SunOS 4. The LOGIN_PROCESS is defined in System V
102 * utmp.h, which will select System V style getty.
103 */
104 #ifdef LOGIN_PROCESS
105 # define SYSV_STYLE
106 #endif
107
108 /*
109 * Things you may want to modify.
110 *
111 * If ISSUE_SUPPORT is not defined, agetty will never display the contents of
112 * the /etc/issue file. You will not want to spit out large "issue" files at
113 * the wrong baud rate. Relevant for System V only.
114 *
115 * You may disagree with the default line-editing etc. characters defined
116 * below. Note, however, that DEL cannot be used for interrupt generation
117 * and for line editing at the same time.
118 */
119
120 /* Displayed before the login prompt. */
121 #ifdef SYSV_STYLE
122 # define ISSUE_SUPPORT
123 # if defined(HAVE_SCANDIRAT) && defined(HAVE_OPENAT)
124 # include <dirent.h>
125 # define ISSUEDIR_SUPPORT
126 # define ISSUEDIR_EXT ".issue"
127 # define ISSUEDIR_EXTSIZ (sizeof(ISSUEDIR_EXT) - 1)
128 # endif
129 #endif
130
131 /* Login prompt. */
132 #define LOGIN_PROMPT "login: "
133
134 /* Numbers of args for login(1) */
135 #define LOGIN_ARGV_MAX 16
136
137 /*
138 * agetty --reload
139 */
140 #ifdef AGETTY_RELOAD
141 # include <sys/inotify.h>
142 # include <linux/netlink.h>
143 # include <linux/rtnetlink.h>
144 # define AGETTY_RELOAD_FILENAME "/run/agetty.reload" /* trigger file */
145 # define AGETTY_RELOAD_FDNONE -2 /* uninitialized fd */
146 static int inotify_fd = AGETTY_RELOAD_FDNONE;
147 static int netlink_fd = AGETTY_RELOAD_FDNONE;
148 static uint32_t netlink_groups;
149 #endif
150
151 struct issue {
152 FILE *output;
153 char *mem;
154 size_t mem_sz;
155
156 #ifdef AGETTY_RELOAD
157 char *mem_old;
158 #endif
159 unsigned int do_tcsetattr : 1,
160 do_tcrestore : 1;
161 };
162
163 /*
164 * When multiple baud rates are specified on the command line, the first one
165 * we will try is the first one specified.
166 */
167 #define FIRST_SPEED 0
168
169 /* Storage for command-line options. */
170 #define MAX_SPEED 10 /* max. nr. of baud rates */
171
172 struct options {
173 int flags; /* toggle switches, see below */
174 unsigned int timeout; /* time-out period */
175 char *autolog; /* login the user automatically */
176 char *chdir; /* Chdir before the login */
177 char *chroot; /* Chroot before the login */
178 char *login; /* login program */
179 char *logopt; /* options for login program */
180 const char *tty; /* name of tty */
181 const char *vcline; /* line of virtual console */
182 char *term; /* terminal type */
183 char *initstring; /* modem init string */
184 char *issue; /* alternative issue file or directory */
185 char *erasechars; /* string with erase chars */
186 char *killchars; /* string with kill chars */
187 char *osrelease; /* /etc/os-release data */
188 unsigned int delay; /* Sleep seconds before prompt */
189 int nice; /* Run login with this priority */
190 int numspeed; /* number of baud rates to try */
191 int clocal; /* CLOCAL_MODE_* */
192 int kbmode; /* Keyboard mode if virtual console */
193 int tty_is_stdin; /* is the tty the standard input stream */
194 speed_t speeds[MAX_SPEED]; /* baud rates to be tried */
195 };
196
197 enum {
198 CLOCAL_MODE_AUTO = 0,
199 CLOCAL_MODE_ALWAYS,
200 CLOCAL_MODE_NEVER
201 };
202
203 #define F_PARSE (1<<0) /* process modem status messages */
204 #define F_ISSUE (1<<1) /* display /etc/issue or /etc/issue.d */
205 #define F_RTSCTS (1<<2) /* enable RTS/CTS flow control */
206
207 #define F_INITSTRING (1<<4) /* initstring is set */
208 #define F_WAITCRLF (1<<5) /* wait for CR or LF */
209
210 #define F_NOPROMPT (1<<7) /* do not ask for login name! */
211 #define F_LCUC (1<<8) /* support for *LCUC stty modes */
212 #define F_KEEPSPEED (1<<9) /* follow baud rate from kernel */
213 #define F_KEEPCFLAGS (1<<10) /* reuse c_cflags setup from kernel */
214 #define F_EIGHTBITS (1<<11) /* Assume 8bit-clean tty */
215 #define F_VCONSOLE (1<<12) /* This is a virtual console */
216 #define F_HANGUP (1<<13) /* Do call vhangup(2) */
217 #define F_UTF8 (1<<14) /* We can do UTF8 */
218 #define F_LOGINPAUSE (1<<15) /* Wait for any key before dropping login prompt */
219 #define F_NOCLEAR (1<<16) /* Do not clear the screen before prompting */
220 #define F_NONL (1<<17) /* No newline before issue */
221 #define F_NOHOSTNAME (1<<18) /* Do not show the hostname */
222 #define F_LONGHNAME (1<<19) /* Show Full qualified hostname */
223 #define F_NOHINTS (1<<20) /* Don't print hints */
224 #define F_REMOTE (1<<21) /* Add '-h fakehost' to login(1) command line */
225
226 #define serial_tty_option(opt, flag) \
227 (((opt)->flags & (F_VCONSOLE|(flag))) == (flag))
228
229 struct Speedtab {
230 long speed;
231 speed_t code;
232 };
233
234 static const struct Speedtab speedtab[] = {
235 {50, B50},
236 {75, B75},
237 {110, B110},
238 {134, B134},
239 {150, B150},
240 {200, B200},
241 {300, B300},
242 {600, B600},
243 {1200, B1200},
244 {1800, B1800},
245 {2400, B2400},
246 {4800, B4800},
247 {9600, B9600},
248 #ifdef B19200
249 {19200, B19200},
250 #elif defined(EXTA)
251 {19200, EXTA},
252 #endif
253 #ifdef B38400
254 {38400, B38400},
255 #elif defined(EXTB)
256 {38400, EXTB},
257 #endif
258 #ifdef B57600
259 {57600, B57600},
260 #endif
261 #ifdef B115200
262 {115200, B115200},
263 #endif
264 #ifdef B230400
265 {230400, B230400},
266 #endif
267 #ifdef B460800
268 {460800, B460800},
269 #endif
270 #ifdef B500000
271 {500000, B500000},
272 #endif
273 #ifdef B576000
274 {576000, B576000},
275 #endif
276 #ifdef B921600
277 {921600, B921600},
278 #endif
279 #ifdef B1000000
280 {1000000, B1000000},
281 #endif
282 #ifdef B1152000
283 {1152000, B1152000},
284 #endif
285 #ifdef B1500000
286 {1500000, B1500000},
287 #endif
288 #ifdef B2000000
289 {2000000, B2000000},
290 #endif
291 #ifdef B2500000
292 {2500000, B2500000},
293 #endif
294 #ifdef B3000000
295 {3000000, B3000000},
296 #endif
297 #ifdef B3500000
298 {3500000, B3500000},
299 #endif
300 #ifdef B4000000
301 {4000000, B4000000},
302 #endif
303 {0, 0},
304 };
305
306 static void init_special_char(char* arg, struct options *op);
307 static void parse_args(int argc, char **argv, struct options *op);
308 static void parse_speeds(struct options *op, char *arg);
309 static void update_utmp(struct options *op);
310 static void open_tty(const char *tty, struct termios *tp, struct options *op);
311 static void termio_init(struct options *op, struct termios *tp);
312 static void reset_vc(const struct options *op, struct termios *tp, int canon);
313 static void auto_baud(struct termios *tp);
314 static void list_speeds(void);
315 static void output_special_char (struct issue *ie, unsigned char c, struct options *op,
316 struct termios *tp, FILE *fp);
317 static void do_prompt(struct issue *ie, struct options *op, struct termios *tp);
318 static void next_speed(struct options *op, struct termios *tp);
319 static char *get_logname(struct issue *ie, struct options *op,
320 struct termios *tp, struct chardata *cp);
321 static void termio_final(struct options *op,
322 struct termios *tp, struct chardata *cp);
323 static int caps_lock(char *s);
324 static speed_t bcode(char *s);
325 static void usage(void) __attribute__((__noreturn__));
326 static void exit_slowly(int code) __attribute__((__noreturn__));
327 static void log_err(const char *, ...) __attribute__((__noreturn__))
328 __attribute__((__format__(printf, 1, 2)));
329 static void log_warn (const char *, ...)
330 __attribute__((__format__(printf, 1, 2)));
331 static ssize_t append(char *dest, size_t len, const char *sep, const char *src);
332 static void check_username (const char* nm);
333 static void login_options_to_argv(char *argv[], int *argc, char *str, char *username);
334 static void reload_agettys(void);
335 static void print_issue_file(struct issue *ie, struct options *op, struct termios *tp);
336 static void eval_issue_file(struct issue *ie, struct options *op, struct termios *tp);
337 static void show_issue(struct options *op);
338 static void load_credentials(struct options *op);
339
340
341 /* Fake hostname for ut_host specified on command line. */
342 static char *fakehost;
343
344 #ifdef DEBUGGING
345 # include "closestream.h"
346 # ifndef DEBUG_OUTPUT
347 # define DEBUG_OUTPUT "/dev/tty10"
348 # endif
349 # define debug(s) do { fprintf(dbf,s); fflush(dbf); } while (0)
350 FILE *dbf;
351 #else
352 # define debug(s) do { ; } while (0)
353 #endif
354
355 int main(int argc, char **argv)
356 {
357 char *username = NULL; /* login name, given to /bin/login */
358 struct chardata chardata; /* will be set by get_logname() */
359 struct termios termios; /* terminal mode bits */
360 struct options options = {
361 .flags = F_ISSUE, /* show /etc/issue (SYSV_STYLE) */
362 .login = _PATH_LOGIN, /* default login program */
363 .tty = "tty1" /* default tty line */
364 };
365 struct issue issue = {
366 .mem = NULL,
367 };
368 char *login_argv[LOGIN_ARGV_MAX + 1];
369 int login_argc = 0;
370 struct sigaction sa, sa_hup, sa_quit, sa_int;
371 sigset_t set;
372
373 setlocale(LC_ALL, "");
374 bindtextdomain(PACKAGE, LOCALEDIR);
375 textdomain(PACKAGE);
376
377 /* In case vhangup(2) has to called */
378 sa.sa_handler = SIG_IGN;
379 sa.sa_flags = SA_RESTART;
380 sigemptyset (&sa.sa_mask);
381 sigaction(SIGHUP, &sa, &sa_hup);
382 sigaction(SIGQUIT, &sa, &sa_quit);
383 sigaction(SIGINT, &sa, &sa_int);
384
385 #ifdef DEBUGGING
386 {
387 int i;
388
389 dbf = fopen(DEBUG_OUTPUT, "w");
390 for (i = 1; i < argc; i++) {
391 if (i > 1)
392 debug(" ");
393 debug(argv[i]);
394 }
395 debug("\n");
396 }
397 #endif /* DEBUGGING */
398
399 /* Load systemd credentials. */
400 load_credentials(&options);
401
402 /* Parse command-line arguments. */
403 parse_args(argc, argv, &options);
404
405 login_argv[login_argc++] = options.login; /* set login program name */
406
407 /* Update the utmp file. */
408 #ifdef SYSV_STYLE
409 update_utmp(&options);
410 #endif
411 if (options.delay)
412 sleep(options.delay);
413
414 debug("calling open_tty\n");
415
416 /* Open the tty as standard { input, output, error }. */
417 open_tty(options.tty, &termios, &options);
418
419 /* Unmask SIGHUP if inherited */
420 sigemptyset(&set);
421 sigaddset(&set, SIGHUP);
422 sigprocmask(SIG_UNBLOCK, &set, NULL);
423 sigaction(SIGHUP, &sa_hup, NULL);
424
425 tcsetpgrp(STDIN_FILENO, getpid());
426
427 /* Default is to follow the current line speed and then default to 9600 */
428 if ((options.flags & F_VCONSOLE) == 0 && options.numspeed == 0) {
429 options.speeds[options.numspeed++] = bcode("9600");
430 options.flags |= F_KEEPSPEED;
431 }
432
433 /* Initialize the termios settings (raw mode, eight-bit, blocking i/o). */
434 debug("calling termio_init\n");
435 termio_init(&options, &termios);
436
437 /* Write the modem init string and DO NOT flush the buffers. */
438 if (options.flags & F_INITSTRING &&
439 options.initstring && *options.initstring != '\0') {
440 debug("writing init string\n");
441 write_all(STDOUT_FILENO, options.initstring,
442 strlen(options.initstring));
443 }
444
445 if (options.flags & F_VCONSOLE || options.clocal != CLOCAL_MODE_ALWAYS)
446 /* Go to blocking mode unless -L is specified, this change
447 * affects stdout, stdin and stderr as all the file descriptors
448 * are created by dup(). */
449 fcntl(STDOUT_FILENO, F_SETFL,
450 fcntl(STDOUT_FILENO, F_GETFL, 0) & ~O_NONBLOCK);
451
452 /* Optionally detect the baud rate from the modem status message. */
453 debug("before autobaud\n");
454 if (serial_tty_option(&options, F_PARSE))
455 auto_baud(&termios);
456
457 /* Set the optional timer. */
458 if (options.timeout)
459 alarm(options.timeout);
460
461 /* Optionally wait for CR or LF before writing /etc/issue */
462 if (serial_tty_option(&options, F_WAITCRLF)) {
463 char ch;
464
465 debug("waiting for cr-lf\n");
466 while (read(STDIN_FILENO, &ch, 1) == 1) {
467 /* Strip "parity bit". */
468 ch &= 0x7f;
469 #ifdef DEBUGGING
470 fprintf(dbf, "read %c\n", ch);
471 #endif
472 if (ch == '\n' || ch == '\r')
473 break;
474 }
475 }
476
477 INIT_CHARDATA(&chardata);
478
479 if (options.autolog) {
480 debug("doing auto login\n");
481 username = options.autolog;
482 }
483
484 if (options.flags & F_NOPROMPT) { /* --skip-login */
485 eval_issue_file(&issue, &options, &termios);
486 print_issue_file(&issue, &options, &termios);
487
488 } else { /* regular (auto)login */
489 if ((options.flags & F_NOHOSTNAME) == 0 &&
490 getlogindefs_bool("LOGIN_PLAIN_PROMPT", 0) == 1)
491 /* /etc/login.defs enbles --nohostname too */
492 options.flags |= F_NOHOSTNAME;
493
494 if (options.autolog) {
495 /* Autologin prompt */
496 eval_issue_file(&issue, &options, &termios);
497 do_prompt(&issue, &options, &termios);
498 printf(_("%s%s (automatic login)\n"), LOGIN_PROMPT,
499 options.autolog);
500 } else {
501 /* Read the login name. */
502 debug("reading login name\n");
503 while ((username =
504 get_logname(&issue, &options, &termios, &chardata)) == NULL)
505 if ((options.flags & F_VCONSOLE) == 0 && options.numspeed)
506 next_speed(&options, &termios);
507 }
508 }
509
510 /* Disable timer. */
511 if (options.timeout)
512 alarm(0);
513
514 /* Finalize the termios settings. */
515 if ((options.flags & F_VCONSOLE) == 0)
516 termio_final(&options, &termios, &chardata);
517 else
518 reset_vc(&options, &termios, 1);
519
520 /* Now the newline character should be properly written. */
521 write_all(STDOUT_FILENO, "\r\n", 2);
522
523 sigaction(SIGQUIT, &sa_quit, NULL);
524 sigaction(SIGINT, &sa_int, NULL);
525
526 if (username)
527 check_username(username);
528
529 if (options.logopt) {
530 /*
531 * The --login-options completely overwrites the default
532 * way how agetty composes login(1) command line.
533 */
534 login_options_to_argv(login_argv, &login_argc,
535 options.logopt, username);
536 } else {
537 if (options.flags & F_REMOTE) {
538 if (fakehost) {
539 login_argv[login_argc++] = "-h";
540 login_argv[login_argc++] = fakehost;
541 } else if (options.flags & F_NOHOSTNAME)
542 login_argv[login_argc++] = "-H";
543 }
544 if (username) {
545 if (options.autolog)
546 login_argv[login_argc++] = "-f";
547 login_argv[login_argc++] = "--";
548 login_argv[login_argc++] = username;
549 }
550 }
551
552 login_argv[login_argc] = NULL; /* last login argv */
553
554 if (options.chroot && chroot(options.chroot) < 0)
555 log_err(_("%s: can't change root directory %s: %m"),
556 options.tty, options.chroot);
557 if (options.chdir && chdir(options.chdir) < 0)
558 log_err(_("%s: can't change working directory %s: %m"),
559 options.tty, options.chdir);
560 if (options.nice && nice(options.nice) < 0)
561 log_warn(_("%s: can't change process priority: %m"),
562 options.tty);
563
564 #ifdef DEBUGGING
565 if (close_stream(dbf) != 0)
566 log_err("write failed: %s", DEBUG_OUTPUT);
567 #endif
568
569 /* Let the login program take care of password validation. */
570 execv(options.login, login_argv);
571
572 free(options.osrelease);
573 free(options.autolog);
574
575 log_err(_("%s: can't exec %s: %m"), options.tty, login_argv[0]);
576 }
577
578 /*
579 * Returns : @str if \u not found
580 * : @username if @str equal to "\u"
581 * : newly allocated string if \u mixed with something other
582 */
583 static char *replace_u(char *str, char *username)
584 {
585 char *entry = NULL, *p = str;
586 size_t usz = username ? strlen(username) : 0;
587
588 while (*p) {
589 size_t sz;
590 char *tp, *old = entry;
591
592 if (memcmp(p, "\\u", 2) != 0) {
593 p++;
594 continue; /* no \u */
595 }
596 sz = strlen(str);
597
598 if (p == str && sz == 2) {
599 /* 'str' contains only '\u' */
600 free(old);
601 return username;
602 }
603
604 tp = entry = malloc(sz + usz);
605 if (!tp)
606 log_err(_("failed to allocate memory: %m"));
607
608 if (p != str)
609 /* copy chars before \u */
610 tp = mempcpy(tp, str, p - str);
611 if (usz)
612 /* copy username */
613 tp = mempcpy(tp, username, usz);
614
615 if (*(p + 2))
616 /* copy chars after \u + \0 */
617 memcpy(tp, p + 2, sz - (p - str) - 1);
618 else
619 *tp = '\0';
620
621 p = tp;
622 str = entry;
623 free(old);
624 }
625
626 return entry ? entry : str;
627 }
628
629 static void login_options_to_argv(char *argv[], int *argc,
630 char *str, char *username)
631 {
632 char *p;
633 int i = *argc;
634
635 while (str && isspace(*str))
636 str++;
637 p = str;
638
639 while (p && *p && i < LOGIN_ARGV_MAX) {
640 if (isspace(*p)) {
641 *p = '\0';
642 while (isspace(*++p))
643 ;
644 if (*p) {
645 argv[i++] = replace_u(str, username);
646 str = p;
647 }
648 } else
649 p++;
650 }
651 if (str && *str && i < LOGIN_ARGV_MAX)
652 argv[i++] = replace_u(str, username);
653 *argc = i;
654 }
655
656 static void output_version(void)
657 {
658 static const char *features[] = {
659 #ifdef DEBUGGING
660 "debug",
661 #endif
662 #ifdef CRTSCTS
663 "flow control",
664 #endif
665 #ifdef KDGKBLED
666 "hints",
667 #endif
668 #ifdef ISSUE_SUPPORT
669 "issue",
670 #endif
671 #ifdef ISSUEDIR_SUPPORT
672 "issue.d",
673 #endif
674 #ifdef KDGKBMODE
675 "keyboard mode",
676 #endif
677 #ifdef USE_PLYMOUTH_SUPPORT
678 "plymouth",
679 #endif
680 #ifdef AGETTY_RELOAD
681 "reload",
682 #endif
683 #ifdef USE_SYSLOG
684 "syslog",
685 #endif
686 #ifdef HAVE_WIDECHAR
687 "widechar",
688 #endif
689 NULL
690 };
691 unsigned int i;
692
693 printf( _("%s from %s"), program_invocation_short_name, PACKAGE_STRING);
694 fputs(" (", stdout);
695 for (i = 0; features[i]; i++) {
696 if (0 < i)
697 fputs(", ", stdout);
698 printf("%s", features[i]);
699 }
700 fputs(")\n", stdout);
701 }
702
703 #define is_speed(str) (strlen((str)) == strspn((str), "0123456789,"))
704
705 /* Parse command-line arguments. */
706 static void parse_args(int argc, char **argv, struct options *op)
707 {
708 int c;
709 int opt_show_issue = 0;
710
711 enum {
712 VERSION_OPTION = CHAR_MAX + 1,
713 NOHINTS_OPTION,
714 NOHOSTNAME_OPTION,
715 LONGHOSTNAME_OPTION,
716 HELP_OPTION,
717 ERASE_CHARS_OPTION,
718 KILL_CHARS_OPTION,
719 RELOAD_OPTION,
720 LIST_SPEEDS_OPTION,
721 ISSUE_SHOW_OPTION,
722 };
723 const struct option longopts[] = {
724 { "8bits", no_argument, NULL, '8' },
725 { "autologin", required_argument, NULL, 'a' },
726 { "noreset", no_argument, NULL, 'c' },
727 { "chdir", required_argument, NULL, 'C' },
728 { "delay", required_argument, NULL, 'd' },
729 { "remote", no_argument, NULL, 'E' },
730 { "issue-file", required_argument, NULL, 'f' },
731 { "show-issue", no_argument, NULL, ISSUE_SHOW_OPTION },
732 { "flow-control", no_argument, NULL, 'h' },
733 { "host", required_argument, NULL, 'H' },
734 { "noissue", no_argument, NULL, 'i' },
735 { "init-string", required_argument, NULL, 'I' },
736 { "noclear", no_argument, NULL, 'J' },
737 { "login-program", required_argument, NULL, 'l' },
738 { "local-line", optional_argument, NULL, 'L' },
739 { "extract-baud", no_argument, NULL, 'm' },
740 { "list-speeds", no_argument, NULL, LIST_SPEEDS_OPTION },
741 { "skip-login", no_argument, NULL, 'n' },
742 { "nonewline", no_argument, NULL, 'N' },
743 { "login-options", required_argument, NULL, 'o' },
744 { "login-pause", no_argument, NULL, 'p' },
745 { "nice", required_argument, NULL, 'P' },
746 { "chroot", required_argument, NULL, 'r' },
747 { "hangup", no_argument, NULL, 'R' },
748 { "keep-baud", no_argument, NULL, 's' },
749 { "timeout", required_argument, NULL, 't' },
750 { "detect-case", no_argument, NULL, 'U' },
751 { "wait-cr", no_argument, NULL, 'w' },
752 { "nohints", no_argument, NULL, NOHINTS_OPTION },
753 { "nohostname", no_argument, NULL, NOHOSTNAME_OPTION },
754 { "long-hostname", no_argument, NULL, LONGHOSTNAME_OPTION },
755 { "reload", no_argument, NULL, RELOAD_OPTION },
756 { "version", no_argument, NULL, VERSION_OPTION },
757 { "help", no_argument, NULL, HELP_OPTION },
758 { "erase-chars", required_argument, NULL, ERASE_CHARS_OPTION },
759 { "kill-chars", required_argument, NULL, KILL_CHARS_OPTION },
760 { NULL, 0, NULL, 0 }
761 };
762
763 while ((c = getopt_long(argc, argv,
764 "8a:cC:d:Ef:hH:iI:Jl:L::mnNo:pP:r:Rst:Uw", longopts,
765 NULL)) != -1) {
766 switch (c) {
767 case '8':
768 op->flags |= F_EIGHTBITS;
769 break;
770 case 'a':
771 free(op->autolog);
772 op->autolog = strdup(optarg);
773 if (!op->autolog)
774 log_err(_("failed to allocate memory: %m"));
775 break;
776 case 'c':
777 op->flags |= F_KEEPCFLAGS;
778 break;
779 case 'C':
780 op->chdir = optarg;
781 break;
782 case 'd':
783 op->delay = strtou32_or_err(optarg, _("invalid delay argument"));
784 break;
785 case 'E':
786 op->flags |= F_REMOTE;
787 break;
788 case 'f':
789 op->issue = optarg;
790 break;
791 case 'h':
792 op->flags |= F_RTSCTS;
793 break;
794 case 'H':
795 fakehost = optarg;
796 break;
797 case 'i':
798 op->flags &= ~F_ISSUE;
799 break;
800 case 'I':
801 init_special_char(optarg, op);
802 op->flags |= F_INITSTRING;
803 break;
804 case 'J':
805 op->flags |= F_NOCLEAR;
806 break;
807 case 'l':
808 op->login = optarg;
809 break;
810 case 'L':
811 /* -L and -L=always have the same meaning */
812 op->clocal = CLOCAL_MODE_ALWAYS;
813 if (optarg) {
814 if (strcmp(optarg, "=always") == 0)
815 op->clocal = CLOCAL_MODE_ALWAYS;
816 else if (strcmp(optarg, "=never") == 0)
817 op->clocal = CLOCAL_MODE_NEVER;
818 else if (strcmp(optarg, "=auto") == 0)
819 op->clocal = CLOCAL_MODE_AUTO;
820 else
821 log_err(_("invalid argument of --local-line"));
822 }
823 break;
824 case 'm':
825 op->flags |= F_PARSE;
826 break;
827 case 'n':
828 op->flags |= F_NOPROMPT;
829 break;
830 case 'N':
831 op->flags |= F_NONL;
832 break;
833 case 'o':
834 op->logopt = optarg;
835 break;
836 case 'p':
837 op->flags |= F_LOGINPAUSE;
838 break;
839 case 'P':
840 op->nice = strtos32_or_err(optarg, _("invalid nice argument"));
841 break;
842 case 'r':
843 op->chroot = optarg;
844 break;
845 case 'R':
846 op->flags |= F_HANGUP;
847 break;
848 case 's':
849 op->flags |= F_KEEPSPEED;
850 break;
851 case 't':
852 op->timeout = strtou32_or_err(optarg, _("invalid timeout argument"));
853 break;
854 case 'U':
855 op->flags |= F_LCUC;
856 break;
857 case 'w':
858 op->flags |= F_WAITCRLF;
859 break;
860 case NOHINTS_OPTION:
861 op->flags |= F_NOHINTS;
862 break;
863 case NOHOSTNAME_OPTION:
864 op->flags |= F_NOHOSTNAME;
865 break;
866 case LONGHOSTNAME_OPTION:
867 op->flags |= F_LONGHNAME;
868 break;
869 case ERASE_CHARS_OPTION:
870 op->erasechars = optarg;
871 break;
872 case KILL_CHARS_OPTION:
873 op->killchars = optarg;
874 break;
875 case RELOAD_OPTION:
876 reload_agettys();
877 exit(EXIT_SUCCESS);
878 case LIST_SPEEDS_OPTION:
879 list_speeds();
880 exit(EXIT_SUCCESS);
881 case ISSUE_SHOW_OPTION:
882 opt_show_issue = 1;
883 break;
884 case VERSION_OPTION:
885 output_version();
886 exit(EXIT_SUCCESS);
887 case HELP_OPTION:
888 usage();
889 default:
890 errtryhelp(EXIT_FAILURE);
891 }
892 }
893
894 if (opt_show_issue) {
895 show_issue(op);
896 exit(EXIT_SUCCESS);
897 }
898
899 debug("after getopt loop\n");
900
901 if (argc < optind + 1) {
902 log_warn(_("not enough arguments"));
903 errx(EXIT_FAILURE, _("not enough arguments"));
904 }
905
906 /* Accept "tty", "baudrate tty", and "tty baudrate". */
907 if (is_speed(argv[optind])) {
908 /* Assume BSD style speed. */
909 parse_speeds(op, argv[optind++]);
910 if (argc < optind + 1) {
911 log_warn(_("not enough arguments"));
912 errx(EXIT_FAILURE, _("not enough arguments"));
913 }
914 op->tty = argv[optind++];
915 } else {
916 op->tty = argv[optind++];
917 if (argc > optind) {
918 char *v = argv[optind];
919 if (is_speed(v)) {
920 parse_speeds(op, v);
921 optind++;
922 }
923 }
924 }
925
926 /* resolve the tty path in case it was provided as stdin */
927 if (strcmp(op->tty, "-") == 0) {
928 op->tty_is_stdin = 1;
929 int fd = get_terminal_name(NULL, &op->tty, NULL);
930 if (fd < 0) {
931 log_warn(_("could not get terminal name: %d"), fd);
932 }
933 }
934
935 /* On virtual console remember the line which is used for */
936 if (strncmp(op->tty, "tty", 3) == 0 &&
937 strspn(op->tty + 3, "0123456789") == strlen(op->tty+3))
938 op->vcline = op->tty+3;
939
940 if (argc > optind && argv[optind])
941 op->term = argv[optind];
942
943 debug("exiting parseargs\n");
944 }
945
946 /* Parse alternate baud rates. */
947 static void parse_speeds(struct options *op, char *arg)
948 {
949 char *cp;
950 char *str = strdup(arg);
951
952 if (!str)
953 log_err(_("failed to allocate memory: %m"));
954
955 debug("entered parse_speeds:\n");
956 for (cp = strtok(str, ","); cp != NULL; cp = strtok((char *)0, ",")) {
957 if ((op->speeds[op->numspeed++] = bcode(cp)) <= 0)
958 log_err(_("bad speed: %s"), cp);
959 if (op->numspeed >= MAX_SPEED)
960 log_err(_("too many alternate speeds"));
961 }
962 debug("exiting parsespeeds\n");
963 free(str);
964 }
965
966 #ifdef SYSV_STYLE
967
968 /* Update our utmp entry. */
969 static void update_utmp(struct options *op)
970 {
971 struct utmpx ut;
972 time_t t;
973 pid_t pid = getpid();
974 pid_t sid = getsid(0);
975 const char *vcline = op->vcline;
976 const char *line = op->tty;
977 struct utmpx *utp;
978
979 /*
980 * The utmp file holds miscellaneous information about things started by
981 * /sbin/init and other system-related events. Our purpose is to update
982 * the utmp entry for the current process, in particular the process type
983 * and the tty line we are listening to. Return successfully only if the
984 * utmp file can be opened for update, and if we are able to find our
985 * entry in the utmp file.
986 */
987 utmpxname(_PATH_UTMP);
988 setutxent();
989
990 /*
991 * Find my pid in utmp.
992 *
993 * FIXME: Earlier (when was that?) code here tested only utp->ut_type !=
994 * INIT_PROCESS, so maybe the >= here should be >.
995 *
996 * FIXME: The present code is taken from login.c, so if this is changed,
997 * maybe login has to be changed as well (is this true?).
998 */
999 while ((utp = getutxent()))
1000 if (utp->ut_pid == pid
1001 && utp->ut_type >= INIT_PROCESS
1002 && utp->ut_type <= DEAD_PROCESS)
1003 break;
1004
1005 if (utp) {
1006 memcpy(&ut, utp, sizeof(ut));
1007 } else {
1008 /* Some inits do not initialize utmp. */
1009 memset(&ut, 0, sizeof(ut));
1010 if (vcline && *vcline)
1011 /* Standard virtual console devices */
1012 str2memcpy(ut.ut_id, vcline, sizeof(ut.ut_id));
1013 else {
1014 size_t len = strlen(line);
1015 const char * ptr;
1016 if (len >= sizeof(ut.ut_id))
1017 ptr = line + len - sizeof(ut.ut_id);
1018 else
1019 ptr = line;
1020 str2memcpy(ut.ut_id, ptr, sizeof(ut.ut_id));
1021 }
1022 }
1023
1024 str2memcpy(ut.ut_user, "LOGIN", sizeof(ut.ut_user));
1025 str2memcpy(ut.ut_line, line, sizeof(ut.ut_line));
1026 if (fakehost)
1027 str2memcpy(ut.ut_host, fakehost, sizeof(ut.ut_host));
1028 time(&t);
1029 ut.ut_tv.tv_sec = t;
1030 ut.ut_type = LOGIN_PROCESS;
1031 ut.ut_pid = pid;
1032 ut.ut_session = sid;
1033
1034 pututxline(&ut);
1035 endutxent();
1036
1037 updwtmpx(_PATH_WTMP, &ut);
1038 }
1039
1040 #endif /* SYSV_STYLE */
1041
1042 /* Set up tty as stdin, stdout & stderr. */
1043 static void open_tty(const char *tty, struct termios *tp, struct options *op)
1044 {
1045 const pid_t pid = getpid();
1046 int closed = 0;
1047 #ifndef KDGKBMODE
1048 int serial;
1049 #endif
1050
1051 /* Set up new standard input, unless we are given an already opened port. */
1052
1053 if (!op->tty_is_stdin) {
1054 char buf[PATH_MAX+1];
1055 struct group *gr = NULL;
1056 struct stat st;
1057 int fd, len;
1058 pid_t tid;
1059 gid_t gid = 0;
1060
1061 /* Use tty group if available */
1062 if ((gr = getgrnam("tty")))
1063 gid = gr->gr_gid;
1064
1065 len = snprintf(buf, sizeof(buf), "/dev/%s", tty);
1066 if (len < 0 || (size_t)len >= sizeof(buf))
1067 log_err(_("/dev/%s: cannot open as standard input: %m"), tty);
1068
1069 /* Open the tty as standard input. */
1070 if ((fd = open(buf, O_RDWR|O_NOCTTY|O_NONBLOCK, 0)) < 0)
1071 log_err(_("/dev/%s: cannot open as standard input: %m"), tty);
1072
1073 /*
1074 * There is always a race between this reset and the call to
1075 * vhangup() that s.o. can use to get access to your tty.
1076 * Linux login(1) will change tty permissions. Use root owner and group
1077 * with permission -rw------- for the period between getty and login.
1078 */
1079 if (fchown(fd, 0, gid) || fchmod(fd, (gid ? 0620 : 0600))) {
1080 if (errno == EROFS)
1081 log_warn("%s: %m", buf);
1082 else
1083 log_err("%s: %m", buf);
1084 }
1085
1086 /* Sanity checks... */
1087 if (fstat(fd, &st) < 0)
1088 log_err("%s: %m", buf);
1089 if ((st.st_mode & S_IFMT) != S_IFCHR)
1090 log_err(_("/dev/%s: not a character device"), tty);
1091 if (!isatty(fd))
1092 log_err(_("/dev/%s: not a tty"), tty);
1093
1094 if (((tid = tcgetsid(fd)) < 0) || (pid != tid)) {
1095 if (ioctl(fd, TIOCSCTTY, 1) == -1)
1096 log_warn(_("/dev/%s: cannot get controlling tty: %m"), tty);
1097 }
1098
1099 close(STDIN_FILENO);
1100 errno = 0;
1101
1102 if (op->flags & F_HANGUP) {
1103
1104 if (ioctl(fd, TIOCNOTTY))
1105 debug("TIOCNOTTY ioctl failed\n");
1106
1107 /*
1108 * Let's close all file descriptors before vhangup
1109 * https://lkml.org/lkml/2012/6/5/145
1110 */
1111 close(fd);
1112 close(STDOUT_FILENO);
1113 close(STDERR_FILENO);
1114 errno = 0;
1115 closed = 1;
1116
1117 if (vhangup())
1118 log_err(_("/dev/%s: vhangup() failed: %m"), tty);
1119 } else
1120 close(fd);
1121
1122 debug("open(2)\n");
1123 if (open(buf, O_RDWR|O_NOCTTY|O_NONBLOCK, 0) != 0)
1124 log_err(_("/dev/%s: cannot open as standard input: %m"), tty);
1125
1126 if (((tid = tcgetsid(STDIN_FILENO)) < 0) || (pid != tid)) {
1127 if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) == -1)
1128 log_warn(_("/dev/%s: cannot get controlling tty: %m"), tty);
1129 }
1130
1131 } else {
1132
1133 /*
1134 * Standard input should already be connected to an open port. Make
1135 * sure it is open for read/write.
1136 */
1137
1138 if ((fcntl(STDIN_FILENO, F_GETFL, 0) & O_RDWR) != O_RDWR)
1139 log_err(_("%s: not open for read/write"), tty);
1140
1141 }
1142
1143 if (tcsetpgrp(STDIN_FILENO, pid))
1144 log_warn(_("/dev/%s: cannot set process group: %m"), tty);
1145
1146 /* Get rid of the present outputs. */
1147 if (!closed) {
1148 close(STDOUT_FILENO);
1149 close(STDERR_FILENO);
1150 errno = 0;
1151 }
1152
1153 /* Set up standard output and standard error file descriptors. */
1154 debug("duping\n");
1155
1156 /* set up stdout and stderr */
1157 if (dup(STDIN_FILENO) != 1 || dup(STDIN_FILENO) != 2)
1158 log_err(_("%s: dup problem: %m"), tty);
1159
1160 /* make stdio unbuffered for slow modem lines */
1161 setvbuf(stdout, NULL, _IONBF, 0);
1162
1163 /*
1164 * The following ioctl will fail if stdin is not a tty, but also when
1165 * there is noise on the modem control lines. In the latter case, the
1166 * common course of action is (1) fix your cables (2) give the modem
1167 * more time to properly reset after hanging up.
1168 *
1169 * SunOS users can achieve (2) by patching the SunOS kernel variable
1170 * "zsadtrlow" to a larger value; 5 seconds seems to be a good value.
1171 * http://www.sunmanagers.org/archives/1993/0574.html
1172 */
1173 memset(tp, 0, sizeof(struct termios));
1174 if (tcgetattr(STDIN_FILENO, tp) < 0)
1175 log_err(_("%s: failed to get terminal attributes: %m"), tty);
1176
1177 #if defined(__FreeBSD_kernel__)
1178 login_tty (0);
1179 #endif
1180
1181 /*
1182 * Detect if this is a virtual console or serial/modem line.
1183 * In case of a virtual console the ioctl KDGKBMODE succeeds
1184 * whereas on other lines it will fails.
1185 */
1186 #ifdef KDGKBMODE
1187 if (ioctl(STDIN_FILENO, KDGKBMODE, &op->kbmode) == 0)
1188 #else
1189 if (ioctl(STDIN_FILENO, TIOCMGET, &serial) < 0 && (errno == EINVAL))
1190 #endif
1191 {
1192 op->flags |= F_VCONSOLE;
1193 } else {
1194 #ifdef K_RAW
1195 op->kbmode = K_RAW;
1196 #endif
1197 }
1198
1199 if (!op->term)
1200 op->term = get_terminal_default_type(op->tty, !(op->flags & F_VCONSOLE));
1201 if (!op->term)
1202 log_err(_("failed to allocate memory: %m"));
1203
1204 if (setenv("TERM", op->term, 1) != 0)
1205 log_err(_("failed to set the %s environment variable"), "TERM");
1206 }
1207
1208 /* Initialize termios settings. */
1209 static void termio_clear(int fd)
1210 {
1211 /*
1212 * Do not write a full reset (ESC c) because this destroys
1213 * the unicode mode again if the terminal was in unicode
1214 * mode. Also it clears the CONSOLE_MAGIC features which
1215 * are required for some languages/console-fonts.
1216 * Just put the cursor to the home position (ESC [ H),
1217 * erase everything below the cursor (ESC [ J), and set the
1218 * scrolling region to the full window (ESC [ r)
1219 */
1220 write_all(fd, "\033[r\033[H\033[J", 9);
1221 }
1222
1223 /* Initialize termios settings. */
1224 static void termio_init(struct options *op, struct termios *tp)
1225 {
1226 speed_t ispeed, ospeed;
1227 struct winsize ws;
1228 #ifdef USE_PLYMOUTH_SUPPORT
1229 struct termios lock;
1230 int i = (plymouth_command(MAGIC_PING) == 0) ? PLYMOUTH_TERMIOS_FLAGS_DELAY : 0;
1231 if (i)
1232 plymouth_command(MAGIC_QUIT);
1233 while (i-- > 0) {
1234 /*
1235 * Even with TTYReset=no it seems with systemd or plymouth
1236 * the termios flags become changed from under the first
1237 * agetty on a serial system console as the flags are locked.
1238 */
1239 memset(&lock, 0, sizeof(struct termios));
1240 if (ioctl(STDIN_FILENO, TIOCGLCKTRMIOS, &lock) < 0)
1241 break;
1242 if (!lock.c_iflag && !lock.c_oflag && !lock.c_cflag && !lock.c_lflag)
1243 break;
1244 debug("termios locked\n");
1245 sleep(1);
1246 }
1247 memset(&lock, 0, sizeof(struct termios));
1248 ioctl(STDIN_FILENO, TIOCSLCKTRMIOS, &lock);
1249 #endif
1250
1251 if (op->flags & F_VCONSOLE) {
1252 #if defined(IUTF8) && defined(KDGKBMODE)
1253 switch(op->kbmode) {
1254 case K_UNICODE:
1255 setlocale(LC_CTYPE, "C.UTF-8");
1256 op->flags |= F_UTF8;
1257 break;
1258 case K_RAW:
1259 case K_MEDIUMRAW:
1260 case K_XLATE:
1261 default:
1262 setlocale(LC_CTYPE, "POSIX");
1263 op->flags &= ~F_UTF8;
1264 break;
1265 }
1266 #else
1267 setlocale(LC_CTYPE, "POSIX");
1268 op->flags &= ~F_UTF8;
1269 #endif
1270 reset_vc(op, tp, 0);
1271
1272 if ((tp->c_cflag & (CS8|PARODD|PARENB)) == CS8)
1273 op->flags |= F_EIGHTBITS;
1274
1275 if ((op->flags & F_NOCLEAR) == 0)
1276 termio_clear(STDOUT_FILENO);
1277 return;
1278 }
1279
1280 /*
1281 * Serial line
1282 */
1283
1284 if (op->flags & F_KEEPSPEED || !op->numspeed) {
1285 /* Save the original setting. */
1286 ispeed = cfgetispeed(tp);
1287 ospeed = cfgetospeed(tp);
1288
1289 /* Save also the original speed to array of the speeds to make
1290 * it possible to return the original after unexpected BREAKs.
1291 */
1292 if (op->numspeed)
1293 op->speeds[op->numspeed++] = ispeed ? ispeed :
1294 ospeed ? ospeed :
1295 TTYDEF_SPEED;
1296 if (!ispeed)
1297 ispeed = TTYDEF_SPEED;
1298 if (!ospeed)
1299 ospeed = TTYDEF_SPEED;
1300 } else {
1301 ospeed = ispeed = op->speeds[FIRST_SPEED];
1302 }
1303
1304 /*
1305 * Initial termios settings: 8-bit characters, raw-mode, blocking i/o.
1306 * Special characters are set after we have read the login name; all
1307 * reads will be done in raw mode anyway. Errors will be dealt with
1308 * later on.
1309 */
1310
1311 /* The default is set c_iflag in termio_final() according to chardata.
1312 * Unfortunately, the chardata are not set according to the serial line
1313 * if --autolog is enabled. In this case we do not read from the line
1314 * at all. The best what we can do in this case is to keep c_iflag
1315 * unmodified for --autolog.
1316 */
1317 if (!op->autolog) {
1318 #ifdef IUTF8
1319 tp->c_iflag = tp->c_iflag & IUTF8;
1320 if (tp->c_iflag & IUTF8)
1321 op->flags |= F_UTF8;
1322 #else
1323 tp->c_iflag = 0;
1324 #endif
1325 }
1326
1327 tp->c_lflag = 0;
1328 tp->c_oflag &= OPOST | ONLCR;
1329
1330 if ((op->flags & F_KEEPCFLAGS) == 0)
1331 tp->c_cflag = CS8 | HUPCL | CREAD | (tp->c_cflag & CLOCAL);
1332
1333 /*
1334 * Note that the speed is stored in the c_cflag termios field, so we have
1335 * set the speed always when the cflag is reset.
1336 */
1337 cfsetispeed(tp, ispeed);
1338 cfsetospeed(tp, ospeed);
1339
1340 /* The default is to follow setting from kernel, but it's possible
1341 * to explicitly remove/add CLOCAL flag by -L[=<mode>]*/
1342 switch (op->clocal) {
1343 case CLOCAL_MODE_ALWAYS:
1344 tp->c_cflag |= CLOCAL; /* -L or -L=always */
1345 break;
1346 case CLOCAL_MODE_NEVER:
1347 tp->c_cflag &= ~CLOCAL; /* -L=never */
1348 break;
1349 case CLOCAL_MODE_AUTO: /* -L=auto */
1350 break;
1351 }
1352
1353 #ifdef HAVE_STRUCT_TERMIOS_C_LINE
1354 tp->c_line = 0;
1355 #endif
1356 tp->c_cc[VMIN] = 1;
1357 tp->c_cc[VTIME] = 0;
1358
1359 /* Check for terminal size and if not found set default */
1360 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0) {
1361 if (ws.ws_row == 0)
1362 ws.ws_row = 24;
1363 if (ws.ws_col == 0)
1364 ws.ws_col = 80;
1365 if (ioctl(STDIN_FILENO, TIOCSWINSZ, &ws))
1366 debug("TIOCSWINSZ ioctl failed\n");
1367 }
1368
1369 /* Optionally enable hardware flow control. */
1370 #ifdef CRTSCTS
1371 if (op->flags & F_RTSCTS)
1372 tp->c_cflag |= CRTSCTS;
1373 #endif
1374 /* Flush input and output queues, important for modems! */
1375 tcflush(STDIN_FILENO, TCIOFLUSH);
1376
1377 if (tcsetattr(STDIN_FILENO, TCSANOW, tp))
1378 log_warn(_("setting terminal attributes failed: %m"));
1379
1380 /* Go to blocking input even in local mode. */
1381 fcntl(STDIN_FILENO, F_SETFL,
1382 fcntl(STDIN_FILENO, F_GETFL, 0) & ~O_NONBLOCK);
1383
1384 debug("term_io 2\n");
1385 }
1386
1387 /* Reset virtual console on stdin to its defaults */
1388 static void reset_vc(const struct options *op, struct termios *tp, int canon)
1389 {
1390 int fl = 0;
1391
1392 fl |= (op->flags & F_KEEPCFLAGS) == 0 ? 0 : UL_TTY_KEEPCFLAGS;
1393 fl |= (op->flags & F_UTF8) == 0 ? 0 : UL_TTY_UTF8;
1394
1395 reset_virtual_console(tp, fl);
1396
1397 #ifdef AGETTY_RELOAD
1398 /*
1399 * Discard all the flags that makes the line go canonical with echoing.
1400 * We need to know when the user starts typing.
1401 */
1402 if (canon == 0)
1403 tp->c_lflag = 0;
1404 #endif
1405
1406 if (tcsetattr(STDIN_FILENO, TCSADRAIN, tp))
1407 log_warn(_("setting terminal attributes failed: %m"));
1408
1409 /* Go to blocking input even in local mode. */
1410 fcntl(STDIN_FILENO, F_SETFL,
1411 fcntl(STDIN_FILENO, F_GETFL, 0) & ~O_NONBLOCK);
1412 }
1413
1414 /* Extract baud rate from modem status message. */
1415 static void auto_baud(struct termios *tp)
1416 {
1417 speed_t speed;
1418 int vmin;
1419 unsigned iflag;
1420 char buf[BUFSIZ];
1421 char *bp;
1422 int nread;
1423
1424 /*
1425 * This works only if the modem produces its status code AFTER raising
1426 * the DCD line, and if the computer is fast enough to set the proper
1427 * baud rate before the message has gone by. We expect a message of the
1428 * following format:
1429 *
1430 * <junk><number><junk>
1431 *
1432 * The number is interpreted as the baud rate of the incoming call. If the
1433 * modem does not tell us the baud rate within one second, we will keep
1434 * using the current baud rate. It is advisable to enable BREAK
1435 * processing (comma-separated list of baud rates) if the processing of
1436 * modem status messages is enabled.
1437 */
1438
1439 /*
1440 * Use 7-bit characters, don't block if input queue is empty. Errors will
1441 * be dealt with later on.
1442 */
1443 iflag = tp->c_iflag;
1444 /* Enable 8th-bit stripping. */
1445 tp->c_iflag |= ISTRIP;
1446 vmin = tp->c_cc[VMIN];
1447 /* Do not block when queue is empty. */
1448 tp->c_cc[VMIN] = 0;
1449 tcsetattr(STDIN_FILENO, TCSANOW, tp);
1450
1451 /*
1452 * Wait for a while, then read everything the modem has said so far and
1453 * try to extract the speed of the dial-in call.
1454 */
1455 sleep(1);
1456 if ((nread = read(STDIN_FILENO, buf, sizeof(buf) - 1)) > 0) {
1457 buf[nread] = '\0';
1458 for (bp = buf; bp < buf + nread; bp++)
1459 if (c_isascii(*bp) && isdigit(*bp)) {
1460 if ((speed = bcode(bp))) {
1461 cfsetispeed(tp, speed);
1462 cfsetospeed(tp, speed);
1463 }
1464 break;
1465 }
1466 }
1467
1468 /* Restore terminal settings. Errors will be dealt with later on. */
1469 tp->c_iflag = iflag;
1470 tp->c_cc[VMIN] = vmin;
1471 tcsetattr(STDIN_FILENO, TCSANOW, tp);
1472 }
1473
1474 static char *xgethostname(void)
1475 {
1476 char *name;
1477 size_t sz = get_hostname_max() + 1;
1478
1479 name = malloc(sizeof(char) * sz);
1480 if (!name)
1481 log_err(_("failed to allocate memory: %m"));
1482
1483 if (gethostname(name, sz) != 0) {
1484 free(name);
1485 return NULL;
1486 }
1487 name[sz - 1] = '\0';
1488 return name;
1489 }
1490
1491 static char *xgetdomainname(void)
1492 {
1493 #ifdef HAVE_GETDOMAINNAME
1494 char *name;
1495 const size_t sz = get_hostname_max() + 1;
1496
1497 name = malloc(sizeof(char) * sz);
1498 if (!name)
1499 log_err(_("failed to allocate memory: %m"));
1500
1501 if (getdomainname(name, sz) != 0) {
1502 free(name);
1503 return NULL;
1504 }
1505 name[sz - 1] = '\0';
1506 return name;
1507 #else
1508 return NULL;
1509 #endif
1510 }
1511
1512
1513 static char *read_os_release(struct options *op, const char *varname)
1514 {
1515 int fd = -1;
1516 struct stat st;
1517 size_t varsz = strlen(varname);
1518 char *p, *buf = NULL, *ret = NULL;
1519
1520 /* read the file only once */
1521 if (!op->osrelease) {
1522 fd = open(_PATH_OS_RELEASE_ETC, O_RDONLY);
1523 if (fd == -1) {
1524 fd = open(_PATH_OS_RELEASE_USR, O_RDONLY);
1525 if (fd == -1) {
1526 log_warn(_("cannot open os-release file"));
1527 return NULL;
1528 }
1529 }
1530
1531 if (fstat(fd, &st) < 0 || st.st_size > 4 * 1024 * 1024)
1532 goto done;
1533
1534 op->osrelease = malloc(st.st_size + 1);
1535 if (!op->osrelease)
1536 log_err(_("failed to allocate memory: %m"));
1537 if (read_all(fd, op->osrelease, st.st_size) != (ssize_t) st.st_size) {
1538 free(op->osrelease);
1539 op->osrelease = NULL;
1540 goto done;
1541 }
1542 op->osrelease[st.st_size] = 0;
1543 }
1544 buf = strdup(op->osrelease);
1545 if (!buf)
1546 log_err(_("failed to allocate memory: %m"));
1547 p = buf;
1548
1549 for (;;) {
1550 char *eol, *eon;
1551
1552 p += strspn(p, "\n\r");
1553 p += strspn(p, " \t\n\r");
1554 if (!*p)
1555 break;
1556 if (strspn(p, "#;\n") != 0) {
1557 p += strcspn(p, "\n\r");
1558 continue;
1559 }
1560 if (strncmp(p, varname, varsz) != 0) {
1561 p += strcspn(p, "\n\r");
1562 continue;
1563 }
1564 p += varsz;
1565 p += strspn(p, " \t\n\r");
1566
1567 if (*p != '=')
1568 continue;
1569
1570 p += strspn(p, " \t\n\r=\"");
1571 eol = p + strcspn(p, "\n\r");
1572 *eol = '\0';
1573 eon = eol-1;
1574 while (eon > p) {
1575 if (*eon == '\t' || *eon == ' ') {
1576 eon--;
1577 continue;
1578 }
1579 if (*eon == '"') {
1580 *eon = '\0';
1581 break;
1582 }
1583 break;
1584 }
1585 free(ret);
1586 ret = strdup(p);
1587 if (!ret)
1588 log_err(_("failed to allocate memory: %m"));
1589 p = eol + 1;
1590 }
1591 done:
1592 free(buf);
1593 if (fd >= 0)
1594 close(fd);
1595 return ret;
1596 }
1597
1598 #ifdef AGETTY_RELOAD
1599 static void open_netlink(void)
1600 {
1601 struct sockaddr_nl addr = { 0, };
1602 int sock;
1603
1604 if (netlink_fd != AGETTY_RELOAD_FDNONE)
1605 return;
1606
1607 sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
1608 if (sock >= 0) {
1609 addr.nl_family = AF_NETLINK;
1610 addr.nl_pid = getpid();
1611 addr.nl_groups = netlink_groups;
1612 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
1613 close(sock);
1614 else
1615 netlink_fd = sock;
1616 }
1617 }
1618
1619 static int process_netlink_msg(int *triggered)
1620 {
1621 char buf[4096];
1622 struct sockaddr_nl snl;
1623 struct nlmsghdr *h;
1624 int rc;
1625
1626 struct iovec iov = {
1627 .iov_base = buf,
1628 .iov_len = sizeof(buf)
1629 };
1630 struct msghdr msg = {
1631 .msg_name = &snl,
1632 .msg_namelen = sizeof(snl),
1633 .msg_iov = &iov,
1634 .msg_iovlen = 1,
1635 .msg_control = NULL,
1636 .msg_controllen = 0,
1637 .msg_flags = 0
1638 };
1639
1640 rc = recvmsg(netlink_fd, &msg, MSG_DONTWAIT);
1641 if (rc < 0) {
1642 if (errno == EWOULDBLOCK || errno == EAGAIN)
1643 return 0;
1644
1645 /* Failure, just stop listening for changes */
1646 close(netlink_fd);
1647 netlink_fd = AGETTY_RELOAD_FDNONE;
1648 return 0;
1649 }
1650
1651 for (h = (struct nlmsghdr *)buf; NLMSG_OK(h, (unsigned int)rc); h = NLMSG_NEXT(h, rc)) {
1652 if (h->nlmsg_type == NLMSG_DONE ||
1653 h->nlmsg_type == NLMSG_ERROR) {
1654 close(netlink_fd);
1655 netlink_fd = AGETTY_RELOAD_FDNONE;
1656 return 0;
1657 }
1658
1659 *triggered = 1;
1660 break;
1661 }
1662
1663 return 1;
1664 }
1665
1666 static int process_netlink(void)
1667 {
1668 int triggered = 0;
1669 while (process_netlink_msg(&triggered));
1670 return triggered;
1671 }
1672
1673 static int wait_for_term_input(int fd)
1674 {
1675 char buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
1676 fd_set rfds;
1677
1678 if (inotify_fd == AGETTY_RELOAD_FDNONE) {
1679 /* make sure the reload trigger file exists */
1680 int reload_fd = open(AGETTY_RELOAD_FILENAME,
1681 O_CREAT|O_CLOEXEC|O_RDONLY,
1682 S_IRUSR|S_IWUSR);
1683
1684 /* initialize reload trigger inotify stuff */
1685 if (reload_fd >= 0) {
1686 inotify_fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
1687 if (inotify_fd > 0)
1688 inotify_add_watch(inotify_fd, AGETTY_RELOAD_FILENAME,
1689 IN_ATTRIB | IN_MODIFY);
1690
1691 close(reload_fd);
1692 } else
1693 log_warn(_("failed to create reload file: %s: %m"),
1694 AGETTY_RELOAD_FILENAME);
1695 }
1696
1697 while (1) {
1698 int nfds = fd;
1699
1700 FD_ZERO(&rfds);
1701 FD_SET(fd, &rfds);
1702
1703 if (inotify_fd >= 0) {
1704 FD_SET(inotify_fd, &rfds);
1705 nfds = max(nfds, inotify_fd);
1706 }
1707 if (netlink_fd >= 0) {
1708 FD_SET(netlink_fd, &rfds);
1709 nfds = max(nfds, netlink_fd);
1710 }
1711
1712 /* If waiting fails, just fall through, presumably reading input will fail */
1713 if (select(nfds + 1, &rfds, NULL, NULL, NULL) < 0)
1714 return 1;
1715
1716 if (FD_ISSET(fd, &rfds)) {
1717 return 1;
1718
1719 }
1720
1721 if (netlink_fd >= 0 && FD_ISSET(netlink_fd, &rfds)) {
1722 if (!process_netlink())
1723 continue;
1724
1725 /* Just drain the inotify buffer */
1726 } else if (inotify_fd >= 0 && FD_ISSET(inotify_fd, &rfds)) {
1727 while (read(inotify_fd, buffer, sizeof (buffer)) > 0);
1728 }
1729
1730 return 0;
1731 }
1732 }
1733 #endif /* AGETTY_RELOAD */
1734
1735 #ifdef ISSUEDIR_SUPPORT
1736 static int issuedir_filter(const struct dirent *d)
1737 {
1738 size_t namesz;
1739
1740 #ifdef _DIRENT_HAVE_D_TYPE
1741 if (d->d_type != DT_UNKNOWN && d->d_type != DT_REG &&
1742 d->d_type != DT_LNK)
1743 return 0;
1744 #endif
1745 if (*d->d_name == '.')
1746 return 0;
1747
1748 namesz = strlen(d->d_name);
1749 if (!namesz || namesz < ISSUEDIR_EXTSIZ + 1 ||
1750 strcmp(d->d_name + (namesz - ISSUEDIR_EXTSIZ), ISSUEDIR_EXT) != 0)
1751 return 0;
1752
1753 /* Accept this */
1754 return 1;
1755 }
1756
1757
1758 static int issuefile_read_stream(struct issue *ie, FILE *f, struct options *op, struct termios *tp);
1759
1760 /* returns: 0 on success, 1 cannot open, <0 on error
1761 */
1762 static int issuedir_read(struct issue *ie, const char *dirname,
1763 struct options *op, struct termios *tp)
1764 {
1765 int dd, nfiles, i;
1766 struct dirent **namelist = NULL;
1767
1768 dd = open(dirname, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
1769 if (dd < 0)
1770 return 1;
1771
1772 nfiles = scandirat(dd, ".", &namelist, issuedir_filter, versionsort);
1773 if (nfiles <= 0)
1774 goto done;
1775
1776 ie->do_tcsetattr = 1;
1777
1778 for (i = 0; i < nfiles; i++) {
1779 struct dirent *d = namelist[i];
1780 FILE *f;
1781
1782 f = fopen_at(dd, d->d_name, O_RDONLY|O_CLOEXEC, "r" UL_CLOEXECSTR);
1783 if (f) {
1784 issuefile_read_stream(ie, f, op, tp);
1785 fclose(f);
1786 }
1787 }
1788
1789 for (i = 0; i < nfiles; i++)
1790 free(namelist[i]);
1791 free(namelist);
1792 done:
1793 close(dd);
1794 return 0;
1795 }
1796
1797 #else /* !ISSUEDIR_SUPPORT */
1798 static int issuedir_read(struct issue *ie __attribute__((__unused__)),
1799 const char *dirname __attribute__((__unused__)),
1800 struct options *op __attribute__((__unused__)),
1801 struct termios *tp __attribute__((__unused__)))
1802 {
1803 return 1;
1804 }
1805 #endif /* ISSUEDIR_SUPPORT */
1806
1807 #ifndef ISSUE_SUPPORT
1808 static void print_issue_file(struct issue *ie __attribute__((__unused__)),
1809 struct options *op,
1810 struct termios *tp __attribute__((__unused__)))
1811 {
1812 if ((op->flags & F_NONL) == 0) {
1813 /* Issue not in use, start with a new line. */
1814 write_all(STDOUT_FILENO, "\r\n", 2);
1815 }
1816 }
1817
1818 static void eval_issue_file(struct issue *ie __attribute__((__unused__)),
1819 struct options *op __attribute__((__unused__)),
1820 struct termios *tp __attribute__((__unused__)))
1821 {
1822 }
1823
1824 static void show_issue(struct options *op __attribute__((__unused__)))
1825 {
1826 }
1827
1828 #else /* ISSUE_SUPPORT */
1829
1830 static int issuefile_read_stream(
1831 struct issue *ie, FILE *f,
1832 struct options *op, struct termios *tp)
1833 {
1834 struct stat st;
1835 int c;
1836
1837 if (fstat(fileno(f), &st) || !S_ISREG(st.st_mode))
1838 return 1;
1839
1840 if (!ie->output) {
1841 free(ie->mem);
1842 ie->mem_sz = 0;
1843 ie->mem = NULL;
1844 ie->output = open_memstream(&ie->mem, &ie->mem_sz);
1845 }
1846
1847 while ((c = fgetc(f)) != EOF) {
1848 if (c == '\\')
1849 output_special_char(ie, fgetc(f), op, tp, f);
1850 else
1851 putc(c, ie->output);
1852 }
1853
1854 return 0;
1855 }
1856
1857 static int issuefile_read(
1858 struct issue *ie, const char *filename,
1859 struct options *op, struct termios *tp)
1860 {
1861 FILE *f = fopen(filename, "r" UL_CLOEXECSTR);
1862 int rc = 1;
1863
1864 if (f) {
1865 rc = issuefile_read_stream(ie, f, op, tp);
1866 fclose(f);
1867 }
1868 return rc;
1869 }
1870
1871
1872 #ifdef AGETTY_RELOAD
1873 static int issue_is_changed(struct issue *ie)
1874 {
1875 if (ie->mem_old && ie->mem
1876 && strcmp(ie->mem_old, ie->mem) == 0) {
1877 free(ie->mem_old);
1878 ie->mem_old = ie->mem;
1879 ie->mem = NULL;
1880 ie->mem_sz = 0;
1881 return 0;
1882 }
1883
1884 return 1;
1885 }
1886 #endif
1887
1888 static void print_issue_file(struct issue *ie,
1889 struct options *op,
1890 struct termios *tp)
1891 {
1892 int oflag = tp->c_oflag; /* Save current setting. */
1893
1894 if ((op->flags & F_NONL) == 0) {
1895 /* Issue not in use, start with a new line. */
1896 write_all(STDOUT_FILENO, "\r\n", 2);
1897 }
1898
1899 if (ie->do_tcsetattr) {
1900 if ((op->flags & F_VCONSOLE) == 0) {
1901 /* Map new line in output to carriage return & new line. */
1902 tp->c_oflag |= (ONLCR | OPOST);
1903 tcsetattr(STDIN_FILENO, TCSADRAIN, tp);
1904 }
1905 }
1906
1907 if (ie->mem_sz && ie->mem)
1908 write_all(STDOUT_FILENO, ie->mem, ie->mem_sz);
1909
1910 if (ie->do_tcrestore) {
1911 /* Restore settings. */
1912 tp->c_oflag = oflag;
1913 /* Wait till output is gone. */
1914 tcsetattr(STDIN_FILENO, TCSADRAIN, tp);
1915 }
1916
1917 #ifdef AGETTY_RELOAD
1918 free(ie->mem_old);
1919 ie->mem_old = ie->mem;
1920 ie->mem = NULL;
1921 ie->mem_sz = 0;
1922 #else
1923 free(ie->mem);
1924 ie->mem = NULL;
1925 ie->mem_sz = 0;
1926 #endif
1927 }
1928
1929 static void eval_issue_file(struct issue *ie,
1930 struct options *op,
1931 struct termios *tp)
1932 {
1933 int has_file = 0;
1934
1935 #ifdef AGETTY_RELOAD
1936 netlink_groups = 0;
1937 #endif
1938 if (!(op->flags & F_ISSUE))
1939 goto done;
1940 /*
1941 * The custom issue file or directory list specified by:
1942 * agetty --isue-file <path[:path]...>
1943 * Note that nothing is printed if the file/dir does not exist.
1944 */
1945 if (op->issue) {
1946 char *list = strdup(op->issue);
1947 char *file;
1948
1949 if (!list)
1950 log_err(_("failed to allocate memory: %m"));
1951
1952 for (file = strtok(list, ":"); file; file = strtok(NULL, ":")) {
1953 struct stat st;
1954
1955 if (stat(file, &st) < 0)
1956 continue;
1957 if (S_ISDIR(st.st_mode))
1958 issuedir_read(ie, file, op, tp);
1959 else
1960 issuefile_read(ie, file, op, tp);
1961 }
1962 free(list);
1963 goto done;
1964 }
1965
1966 /* The default /etc/issue and optional /etc/issue.d directory as
1967 * extension to the file. The /etc/issue.d directory is ignored if
1968 * there is no /etc/issue file. The file may be empty or symlink.
1969 */
1970 if (access(_PATH_ISSUE, F_OK|R_OK) == 0) {
1971 issuefile_read(ie, _PATH_ISSUE, op, tp);
1972 issuedir_read(ie, _PATH_ISSUEDIR, op, tp);
1973 goto done;
1974 }
1975
1976 /* Fallback @runstatedir (usually /run) -- the file is not required to
1977 * read the dir.
1978 */
1979 if (issuefile_read(ie, _PATH_RUNSTATEDIR "/" _PATH_ISSUE_FILENAME, op, tp) == 0)
1980 has_file++;
1981 if (issuedir_read(ie, _PATH_RUNSTATEDIR "/" _PATH_ISSUE_DIRNAME, op, tp) == 0)
1982 has_file++;
1983 if (has_file)
1984 goto done;
1985
1986 /* Fallback @sysconfstaticdir (usually /usr/lib) -- the file is not
1987 * required to read the dir
1988 */
1989 issuefile_read(ie, _PATH_SYSCONFSTATICDIR "/" _PATH_ISSUE_FILENAME, op, tp);
1990 issuedir_read(ie, _PATH_SYSCONFSTATICDIR "/" _PATH_ISSUE_DIRNAME, op, tp);
1991
1992 done:
1993
1994 #ifdef AGETTY_RELOAD
1995 if (netlink_groups != 0)
1996 open_netlink();
1997 #endif
1998 if (ie->output) {
1999 fclose(ie->output);
2000 ie->output = NULL;
2001 }
2002 }
2003
2004 /* This is --show-issue backend, executed by normal user on the current
2005 * terminal.
2006 */
2007 static void show_issue(struct options *op)
2008 {
2009 struct issue ie = { .output = NULL };
2010 struct termios tp;
2011
2012 memset(&tp, 0, sizeof(struct termios));
2013 if (tcgetattr(STDIN_FILENO, &tp) < 0)
2014 err(EXIT_FAILURE, _("failed to get terminal attributes: %m"));
2015
2016 eval_issue_file(&ie, op, &tp);
2017
2018 if (ie.mem_sz)
2019 write_all(STDOUT_FILENO, ie.mem, ie.mem_sz);
2020 if (ie.output)
2021 fclose(ie.output);
2022 free(ie.mem);
2023 }
2024
2025 #endif /* ISSUE_SUPPORT */
2026
2027 /* Show login prompt, optionally preceded by /etc/issue contents. */
2028 static void do_prompt(struct issue *ie, struct options *op, struct termios *tp)
2029 {
2030 #ifdef AGETTY_RELOAD
2031 again:
2032 #endif
2033 print_issue_file(ie, op, tp);
2034
2035 if (op->flags & F_LOGINPAUSE) {
2036 puts(_("[press ENTER to login]"));
2037 #ifdef AGETTY_RELOAD
2038 /* reload issue */
2039 if (!wait_for_term_input(STDIN_FILENO)) {
2040 eval_issue_file(ie, op, tp);
2041 if (issue_is_changed(ie)) {
2042 if ((op->flags & F_VCONSOLE)
2043 && (op->flags & F_NOCLEAR) == 0)
2044 termio_clear(STDOUT_FILENO);
2045 goto again;
2046 }
2047 }
2048 #endif
2049 getc(stdin);
2050 }
2051 #ifdef KDGKBLED
2052 if (!(op->flags & F_NOHINTS) && !op->autolog &&
2053 (op->flags & F_VCONSOLE)) {
2054 int kb = 0;
2055
2056 if (ioctl(STDIN_FILENO, KDGKBLED, &kb) == 0) {
2057 char hint[256] = { '\0' };
2058 int nl = 0;
2059
2060 if (access(_PATH_NUMLOCK_ON, F_OK) == 0)
2061 nl = 1;
2062
2063 if (nl && (kb & 0x02) == 0)
2064 append(hint, sizeof(hint), NULL, _("Num Lock off"));
2065
2066 else if (nl == 0 && (kb & 2) && (kb & 0x20) == 0)
2067 append(hint, sizeof(hint), NULL, _("Num Lock on"));
2068
2069 if ((kb & 0x04) && (kb & 0x40) == 0)
2070 append(hint, sizeof(hint), ", ", _("Caps Lock on"));
2071
2072 if ((kb & 0x01) && (kb & 0x10) == 0)
2073 append(hint, sizeof(hint), ", ", _("Scroll Lock on"));
2074
2075 if (*hint)
2076 printf(_("Hint: %s\n\n"), hint);
2077 }
2078 }
2079 #endif /* KDGKBLED */
2080 if ((op->flags & F_NOHOSTNAME) == 0) {
2081 char *hn = xgethostname();
2082
2083 if (hn) {
2084 char *dot = strchr(hn, '.');
2085 char *cn = hn;
2086 struct addrinfo *res = NULL;
2087
2088 if ((op->flags & F_LONGHNAME) == 0) {
2089 if (dot)
2090 *dot = '\0';
2091
2092 } else if (dot == NULL) {
2093 struct addrinfo hints;
2094
2095 memset(&hints, 0, sizeof(hints));
2096 hints.ai_flags = AI_CANONNAME;
2097
2098 if (!getaddrinfo(hn, NULL, &hints, &res)
2099 && res && res->ai_canonname)
2100 cn = res->ai_canonname;
2101 }
2102
2103 write_all(STDOUT_FILENO, cn, strlen(cn));
2104 write_all(STDOUT_FILENO, " ", 1);
2105
2106 if (res)
2107 freeaddrinfo(res);
2108 free(hn);
2109 }
2110 }
2111 if (!op->autolog) {
2112 /* Always show login prompt. */
2113 write_all(STDOUT_FILENO, LOGIN_PROMPT,
2114 sizeof(LOGIN_PROMPT) - 1);
2115 }
2116 }
2117
2118 /* Select next baud rate. */
2119 static void next_speed(struct options *op, struct termios *tp)
2120 {
2121 static int baud_index = -1;
2122
2123 if (baud_index == -1)
2124 /*
2125 * If the F_KEEPSPEED flags is set then the FIRST_SPEED is not
2126 * tested yet (see termio_init()).
2127 */
2128 baud_index =
2129 (op->flags & F_KEEPSPEED) ? FIRST_SPEED : 1 % op->numspeed;
2130 else
2131 baud_index = (baud_index + 1) % op->numspeed;
2132
2133 cfsetispeed(tp, op->speeds[baud_index]);
2134 cfsetospeed(tp, op->speeds[baud_index]);
2135 tcsetattr(STDIN_FILENO, TCSANOW, tp);
2136 }
2137
2138 /* Get user name, establish parity, speed, erase, kill & eol. */
2139 static char *get_logname(struct issue *ie, struct options *op, struct termios *tp, struct chardata *cp)
2140 {
2141 static char logname[BUFSIZ];
2142 char *bp;
2143 char c; /* input character, full eight bits */
2144 char ascval; /* low 7 bits of input character */
2145 int eightbit;
2146 static char *erase[] = { /* backspace-space-backspace */
2147 "\010\040\010", /* space parity */
2148 "\010\040\010", /* odd parity */
2149 "\210\240\210", /* even parity */
2150 "\210\240\210", /* no parity */
2151 };
2152
2153 /* Initialize kill, erase, parity etc. (also after switching speeds). */
2154 INIT_CHARDATA(cp);
2155
2156 /*
2157 * Flush pending input (especially important after parsing or switching
2158 * the baud rate).
2159 */
2160 if ((op->flags & F_VCONSOLE) == 0)
2161 sleep(1);
2162 tcflush(STDIN_FILENO, TCIFLUSH);
2163
2164 eightbit = (op->flags & (F_EIGHTBITS|F_UTF8));
2165 bp = logname;
2166 *bp = '\0';
2167
2168 eval_issue_file(ie, op, tp);
2169 while (*logname == '\0') {
2170 /* Write issue file and prompt */
2171 do_prompt(ie, op, tp);
2172
2173 no_reload:
2174 #ifdef AGETTY_RELOAD
2175 if (!wait_for_term_input(STDIN_FILENO)) {
2176 /* refresh prompt -- discard input data, clear terminal
2177 * and call do_prompt() again
2178 */
2179 if ((op->flags & F_VCONSOLE) == 0)
2180 sleep(1);
2181 eval_issue_file(ie, op, tp);
2182 if (!issue_is_changed(ie))
2183 goto no_reload;
2184 tcflush(STDIN_FILENO, TCIFLUSH);
2185 if ((op->flags & F_VCONSOLE)
2186 && (op->flags & F_NOCLEAR) == 0)
2187 termio_clear(STDOUT_FILENO);
2188 bp = logname;
2189 *bp = '\0';
2190 continue;
2191 }
2192 #endif
2193 cp->eol = '\0';
2194
2195 /* Read name, watch for break and end-of-line. */
2196 while (cp->eol == '\0') {
2197
2198 char key;
2199 ssize_t readres;
2200
2201 debug("read from FD\n");
2202 readres = read(STDIN_FILENO, &c, 1);
2203 if (readres < 0) {
2204 debug("read failed\n");
2205
2206 /* The terminal could be open with O_NONBLOCK when
2207 * -L (force CLOCAL) is specified... */
2208 if (errno == EINTR || errno == EAGAIN) {
2209 xusleep(250000);
2210 continue;
2211 }
2212 switch (errno) {
2213 case 0:
2214 case EIO:
2215 case ESRCH:
2216 case EINVAL:
2217 case ENOENT:
2218 exit_slowly(EXIT_SUCCESS);
2219 default:
2220 log_err(_("%s: read: %m"), op->tty);
2221 }
2222 }
2223
2224 if (readres == 0)
2225 c = 0;
2226
2227 /* Do parity bit handling. */
2228 if (eightbit)
2229 ascval = c;
2230 else if (c != (ascval = (c & 0177))) {
2231 uint32_t bits; /* # of "1" bits per character */
2232 uint32_t mask; /* mask with 1 bit up */
2233 for (bits = 1, mask = 1; mask & 0177; mask <<= 1) {
2234 if (mask & ascval)
2235 bits++;
2236 }
2237 cp->parity |= ((bits & 1) ? 1 : 2);
2238 }
2239
2240 if (op->killchars && strchr(op->killchars, ascval))
2241 key = CTL('U');
2242 else if (op->erasechars && strchr(op->erasechars, ascval))
2243 key = DEL;
2244 else
2245 key = ascval;
2246
2247 /* Do erase, kill and end-of-line processing. */
2248 switch (key) {
2249 case 0:
2250 *bp = 0;
2251 if (op->numspeed > 1 && !(op->flags & F_VCONSOLE))
2252 return NULL;
2253 if (readres == 0)
2254 exit_slowly(EXIT_SUCCESS);
2255 break;
2256 case CR:
2257 case NL:
2258 *bp = 0; /* terminate logname */
2259 cp->eol = ascval; /* set end-of-line char */
2260 break;
2261 case BS:
2262 case DEL:
2263 cp->erase = ascval; /* set erase character */
2264 if (bp > logname) {
2265 if ((tp->c_lflag & ECHO) == 0)
2266 write_all(1, erase[cp->parity], 3);
2267 bp--;
2268 }
2269 break;
2270 case CTL('U'):
2271 cp->kill = ascval; /* set kill character */
2272 /* fallthrough */
2273 case CTL('C'):
2274 if (key == CTL('C') && !(op->flags & F_VCONSOLE))
2275 /* Ignore CTRL+C on serial line */
2276 break;
2277 while (bp > logname) {
2278 if ((tp->c_lflag & ECHO) == 0)
2279 write_all(1, erase[cp->parity], 3);
2280 bp--;
2281 }
2282 break;
2283 case CTL('D'):
2284 exit(EXIT_SUCCESS);
2285 default:
2286 if ((size_t)(bp - logname) >= sizeof(logname) - 1)
2287 log_err(_("%s: input overrun"), op->tty);
2288 if ((tp->c_lflag & ECHO) == 0)
2289 write_all(1, &c, 1); /* echo the character */
2290 *bp++ = ascval; /* and store it */
2291 break;
2292 }
2293 /* Everything was erased. */
2294 if (bp == logname && cp->eol == '\0')
2295 goto no_reload;
2296 }
2297 }
2298
2299 #ifdef HAVE_WIDECHAR
2300 if ((op->flags & (F_EIGHTBITS|F_UTF8)) == (F_EIGHTBITS|F_UTF8)) {
2301 /* Check out UTF-8 multibyte characters */
2302 ssize_t len;
2303 wchar_t *wcs, *wcp;
2304
2305 len = mbstowcs((wchar_t *)0, logname, 0);
2306 if (len < 0)
2307 log_err(_("%s: invalid character conversion for login name"), op->tty);
2308
2309 wcs = malloc((len + 1) * sizeof(wchar_t));
2310 if (!wcs)
2311 log_err(_("failed to allocate memory: %m"));
2312
2313 len = mbstowcs(wcs, logname, len + 1);
2314 if (len < 0)
2315 log_err(_("%s: invalid character conversion for login name"), op->tty);
2316
2317 wcp = wcs;
2318 while (*wcp) {
2319 const wint_t wc = *wcp++;
2320 if (!iswprint(wc))
2321 log_err(_("%s: invalid character 0x%x in login name"), op->tty, wc);
2322 }
2323 free(wcs);
2324 } else
2325 #endif
2326 if ((op->flags & F_LCUC) && (cp->capslock = caps_lock(logname))) {
2327
2328 /* Handle names with upper case and no lower case. */
2329 for (bp = logname; *bp; bp++)
2330 if (isupper(*bp))
2331 *bp = tolower(*bp); /* map name to lower case */
2332 }
2333
2334 return logname;
2335 }
2336
2337 /* Set the final tty mode bits. */
2338 static void termio_final(struct options *op, struct termios *tp, struct chardata *cp)
2339 {
2340 /* General terminal-independent stuff. */
2341
2342 /* 2-way flow control */
2343 tp->c_iflag |= IXON | IXOFF;
2344 tp->c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE;
2345 /* no longer| ECHOCTL | ECHOPRT */
2346 tp->c_oflag |= OPOST;
2347 /* tp->c_cflag = 0; */
2348 tp->c_cc[VINTR] = DEF_INTR;
2349 tp->c_cc[VQUIT] = DEF_QUIT;
2350 tp->c_cc[VEOF] = DEF_EOF;
2351 tp->c_cc[VEOL] = DEF_EOL;
2352 #ifdef __linux__
2353 tp->c_cc[VSWTC] = DEF_SWITCH;
2354 #elif defined(VSWTCH)
2355 tp->c_cc[VSWTCH] = DEF_SWITCH;
2356 #endif /* __linux__ */
2357
2358 /* Account for special characters seen in input. */
2359 if (cp->eol == CR) {
2360 tp->c_iflag |= ICRNL;
2361 tp->c_oflag |= ONLCR;
2362 }
2363 tp->c_cc[VERASE] = cp->erase;
2364 tp->c_cc[VKILL] = cp->kill;
2365
2366 /* Account for the presence or absence of parity bits in input. */
2367 switch (cp->parity) {
2368 case 0:
2369 /* space (always 0) parity */
2370 break;
2371 case 1:
2372 /* odd parity */
2373 tp->c_cflag |= PARODD;
2374 /* fallthrough */
2375 case 2:
2376 /* even parity */
2377 tp->c_cflag |= PARENB;
2378 tp->c_iflag |= INPCK | ISTRIP;
2379 /* fallthrough */
2380 case (1 | 2):
2381 /* no parity bit */
2382 tp->c_cflag &= ~CSIZE;
2383 tp->c_cflag |= CS7;
2384 break;
2385 }
2386 /* Account for upper case without lower case. */
2387 if (cp->capslock) {
2388 #ifdef IUCLC
2389 tp->c_iflag |= IUCLC;
2390 #endif
2391 #ifdef XCASE
2392 tp->c_lflag |= XCASE;
2393 #endif
2394 #ifdef OLCUC
2395 tp->c_oflag |= OLCUC;
2396 #endif
2397 }
2398 /* Optionally enable hardware flow control. */
2399 #ifdef CRTSCTS
2400 if (op->flags & F_RTSCTS)
2401 tp->c_cflag |= CRTSCTS;
2402 #endif
2403
2404 /* Finally, make the new settings effective. */
2405 if (tcsetattr(STDIN_FILENO, TCSANOW, tp) < 0)
2406 log_err(_("%s: failed to set terminal attributes: %m"), op->tty);
2407 }
2408
2409 /*
2410 * String contains upper case without lower case.
2411 * http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=52940
2412 * http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=156242
2413 */
2414 static int caps_lock(char *s)
2415 {
2416 int capslock;
2417
2418 for (capslock = 0; *s; s++) {
2419 if (islower(*s))
2420 return EXIT_SUCCESS;
2421 if (capslock == 0)
2422 capslock = isupper(*s);
2423 }
2424 return capslock;
2425 }
2426
2427 /* Convert speed string to speed code; return 0 on failure. */
2428 static speed_t bcode(char *s)
2429 {
2430 const struct Speedtab *sp;
2431 char *end = NULL;
2432 long speed;
2433
2434 errno = 0;
2435 speed = strtol(s, &end, 10);
2436
2437 if (errno || !end || end == s)
2438 return 0;
2439
2440 for (sp = speedtab; sp->speed; sp++)
2441 if (sp->speed == speed)
2442 return sp->code;
2443 return 0;
2444 }
2445
2446 static void __attribute__((__noreturn__)) usage(void)
2447 {
2448 FILE *out = stdout;
2449
2450 fputs(USAGE_HEADER, out);
2451 fprintf(out, _(" %1$s [options] <line> [<baud_rate>,...] [<termtype>]\n"
2452 " %1$s [options] <baud_rate>,... <line> [<termtype>]\n"), program_invocation_short_name);
2453
2454 fputs(USAGE_SEPARATOR, out);
2455 fputs(_("Open a terminal and set its mode.\n"), out);
2456
2457 fputs(USAGE_OPTIONS, out);
2458 fputs(_(" -8, --8bits assume 8-bit tty\n"), out);
2459 fputs(_(" -a, --autologin <user> login the specified user automatically\n"), out);
2460 fputs(_(" -c, --noreset do not reset control mode\n"), out);
2461 fputs(_(" -E, --remote use -r <hostname> for login(1)\n"), out);
2462 fputs(_(" -f, --issue-file <list> display issue files or directories\n"), out);
2463 fputs(_(" --show-issue display issue file and exit\n"), out);
2464 fputs(_(" -h, --flow-control enable hardware flow control\n"), out);
2465 fputs(_(" -H, --host <hostname> specify login host\n"), out);
2466 fputs(_(" -i, --noissue do not display issue file\n"), out);
2467 fputs(_(" -I, --init-string <string> set init string\n"), out);
2468 fputs(_(" -J, --noclear do not clear the screen before prompt\n"), out);
2469 fputs(_(" -l, --login-program <file> specify login program\n"), out);
2470 fputs(_(" -L, --local-line[=<mode>] control the local line flag\n"), out);
2471 fputs(_(" -m, --extract-baud extract baud rate during connect\n"), out);
2472 fputs(_(" -n, --skip-login do not prompt for login\n"), out);
2473 fputs(_(" -N, --nonewline do not print a newline before issue\n"), out);
2474 fputs(_(" -o, --login-options <opts> options that are passed to login\n"), out);
2475 fputs(_(" -p, --login-pause wait for any key before the login\n"), out);
2476 fputs(_(" -r, --chroot <dir> change root to the directory\n"), out);
2477 fputs(_(" -R, --hangup do virtually hangup on the tty\n"), out);
2478 fputs(_(" -s, --keep-baud try to keep baud rate after break\n"), out);
2479 fputs(_(" -t, --timeout <number> login process timeout\n"), out);
2480 fputs(_(" -U, --detect-case detect uppercase terminal\n"), out);
2481 fputs(_(" -w, --wait-cr wait carriage-return\n"), out);
2482 fputs(_(" --nohints do not print hints\n"), out);
2483 fputs(_(" --nohostname no hostname at all will be shown\n"), out);
2484 fputs(_(" --long-hostname show full qualified hostname\n"), out);
2485 fputs(_(" --erase-chars <string> additional backspace chars\n"), out);
2486 fputs(_(" --kill-chars <string> additional kill chars\n"), out);
2487 fputs(_(" --chdir <directory> chdir before the login\n"), out);
2488 fputs(_(" --delay <number> sleep seconds before prompt\n"), out);
2489 fputs(_(" --nice <number> run login with this priority\n"), out);
2490 fputs(_(" --reload reload prompts on running agetty instances\n"), out);
2491 fputs(_(" --list-speeds display supported baud rates\n"), out);
2492 fprintf(out, " --help %s\n", USAGE_OPTSTR_HELP);
2493 fprintf(out, " --version %s\n", USAGE_OPTSTR_VERSION);
2494 fprintf(out, USAGE_MAN_TAIL("agetty(8)"));
2495
2496 exit(EXIT_SUCCESS);
2497 }
2498
2499 static void list_speeds(void)
2500 {
2501 const struct Speedtab *sp;
2502
2503 for (sp = speedtab; sp->speed; sp++)
2504 printf("%10ld\n", sp->speed);
2505 }
2506
2507 /*
2508 * Helper function reports errors to console or syslog.
2509 * Will be used by log_err() and log_warn() therefore
2510 * it takes a format as well as va_list.
2511 */
2512 static void dolog(int priority
2513 #ifndef USE_SYSLOG
2514 __attribute__((__unused__))
2515 #endif
2516 , const char *fmt, va_list ap)
2517 {
2518 #ifdef USE_SYSLOG
2519 /*
2520 * If the diagnostic is reported via syslog(3), the process name is
2521 * automatically prepended to the message. If we write directly to
2522 * /dev/console, we must prepend the process name ourselves.
2523 */
2524 openlog("agetty", LOG_PID, LOG_AUTHPRIV);
2525 vsyslog(priority, fmt, ap);
2526 closelog();
2527 #else
2528 /*
2529 * Write the diagnostic directly to /dev/console if we do not use
2530 * the syslog(3) facility.
2531 */
2532 char buf[BUFSIZ];
2533 char new_fmt[BUFSIZ];
2534 int fd;
2535
2536 snprintf(new_fmt, sizeof(new_fmt), "%s: %s\r\n",
2537 program_invocation_short_name, fmt);
2538 /* Terminate with CR-LF since the console mode is unknown. */
2539 vsnprintf(buf, sizeof(buf), new_fmt, ap);
2540
2541 if ((fd = open("/dev/console", 1)) >= 0) {
2542 write_all(fd, buf, strlen(buf));
2543 close(fd);
2544 }
2545 #endif /* USE_SYSLOG */
2546 }
2547
2548 static void exit_slowly(int code)
2549 {
2550 /* Be kind to init(8). */
2551 sleep(10);
2552 exit(code);
2553 }
2554
2555 static void log_err(const char *fmt, ...)
2556 {
2557 va_list ap;
2558
2559 va_start(ap, fmt);
2560 dolog(LOG_ERR, fmt, ap);
2561 va_end(ap);
2562
2563 exit_slowly(EXIT_FAILURE);
2564 }
2565
2566 static void log_warn(const char *fmt, ...)
2567 {
2568 va_list ap;
2569
2570 va_start(ap, fmt);
2571 dolog(LOG_WARNING, fmt, ap);
2572 va_end(ap);
2573 }
2574
2575 static void print_addr(struct issue *ie, sa_family_t family, void *addr)
2576 {
2577 char buff[INET6_ADDRSTRLEN + 1];
2578
2579 inet_ntop(family, addr, buff, sizeof(buff));
2580 fprintf(ie->output, "%s", buff);
2581 }
2582
2583 /*
2584 * Prints IP for the specified interface (@iface), if the interface is not
2585 * specified then prints the "best" one (UP, RUNNING, non-LOOPBACK). If not
2586 * found the "best" interface then prints at least host IP.
2587 */
2588 static void output_iface_ip(struct issue *ie,
2589 struct ifaddrs *addrs,
2590 const char *iface,
2591 sa_family_t family)
2592 {
2593 struct ifaddrs *p;
2594 struct addrinfo hints, *info = NULL;
2595 char *host = NULL;
2596 void *addr = NULL;
2597
2598 if (!addrs)
2599 return;
2600
2601 for (p = addrs; p; p = p->ifa_next) {
2602
2603 if (!p->ifa_name ||
2604 !p->ifa_addr ||
2605 p->ifa_addr->sa_family != family)
2606 continue;
2607
2608 if (iface) {
2609 /* Filter out by interface name */
2610 if (strcmp(p->ifa_name, iface) != 0)
2611 continue;
2612 } else {
2613 /* Select the "best" interface */
2614 if ((p->ifa_flags & IFF_LOOPBACK) ||
2615 !(p->ifa_flags & IFF_UP) ||
2616 !(p->ifa_flags & IFF_RUNNING))
2617 continue;
2618 }
2619
2620 addr = NULL;
2621 switch (p->ifa_addr->sa_family) {
2622 case AF_INET:
2623 addr = &((struct sockaddr_in *) p->ifa_addr)->sin_addr;
2624 break;
2625 case AF_INET6:
2626 addr = &((struct sockaddr_in6 *) p->ifa_addr)->sin6_addr;
2627 break;
2628 }
2629
2630 if (addr) {
2631 print_addr(ie, family, addr);
2632 return;
2633 }
2634 }
2635
2636 if (iface)
2637 return;
2638
2639 /* Hmm.. not found the best interface, print host IP at least */
2640 memset(&hints, 0, sizeof(hints));
2641 hints.ai_family = family;
2642 if (family == AF_INET6)
2643 hints.ai_flags = AI_V4MAPPED;
2644
2645 host = xgethostname();
2646 if (host && getaddrinfo(host, NULL, &hints, &info) == 0 && info) {
2647 switch (info->ai_family) {
2648 case AF_INET:
2649 addr = &((struct sockaddr_in *) info->ai_addr)->sin_addr;
2650 break;
2651 case AF_INET6:
2652 addr = &((struct sockaddr_in6 *) info->ai_addr)->sin6_addr;
2653 break;
2654 }
2655 if (addr)
2656 print_addr(ie, family, addr);
2657
2658 freeaddrinfo(info);
2659 }
2660 free(host);
2661 }
2662
2663 /*
2664 * parses \x{argument}, if not argument specified then returns NULL, the @fd
2665 * has to point to one char after the sequence (it means '{').
2666 */
2667 static char *get_escape_argument(FILE *fd, char *buf, size_t bufsz)
2668 {
2669 size_t i = 0;
2670 int c = fgetc(fd);
2671
2672 if (c == EOF || (unsigned char) c != '{') {
2673 ungetc(c, fd);
2674 return NULL;
2675 }
2676
2677 do {
2678 c = fgetc(fd);
2679 if (c == EOF)
2680 return NULL;
2681 if ((unsigned char) c != '}' && i < bufsz - 1)
2682 buf[i++] = (unsigned char) c;
2683
2684 } while ((unsigned char) c != '}');
2685
2686 buf[i] = '\0';
2687 return buf;
2688 }
2689
2690 static void output_special_char(struct issue *ie,
2691 unsigned char c,
2692 struct options *op,
2693 struct termios *tp,
2694 FILE *fp)
2695 {
2696 struct utsname uts;
2697
2698 switch (c) {
2699 case 'e':
2700 {
2701 char escname[UL_COLORNAME_MAXSZ];
2702
2703 if (get_escape_argument(fp, escname, sizeof(escname))) {
2704 char *esc = color_get_sequence(escname);
2705
2706 if (esc) {
2707 fputs(esc, ie->output);
2708 free(esc);
2709 }
2710 } else
2711 fputs("\033", ie->output);
2712 break;
2713 }
2714 case 's':
2715 uname(&uts);
2716 fprintf(ie->output, "%s", uts.sysname);
2717 break;
2718 case 'n':
2719 uname(&uts);
2720 fprintf(ie->output, "%s", uts.nodename);
2721 break;
2722 case 'r':
2723 uname(&uts);
2724 fprintf(ie->output, "%s", uts.release);
2725 break;
2726 case 'v':
2727 uname(&uts);
2728 fprintf(ie->output, "%s", uts.version);
2729 break;
2730 case 'm':
2731 uname(&uts);
2732 fprintf(ie->output, "%s", uts.machine);
2733 break;
2734 case 'o':
2735 {
2736 char *dom = xgetdomainname();
2737
2738 fputs(dom ? dom : "unknown_domain", ie->output);
2739 free(dom);
2740 break;
2741 }
2742 case 'O':
2743 {
2744 char *dom = NULL;
2745 char *host = xgethostname();
2746 struct addrinfo hints, *info = NULL;
2747
2748 memset(&hints, 0, sizeof(hints));
2749 hints.ai_flags = AI_CANONNAME;
2750
2751 if (host && getaddrinfo(host, NULL, &hints, &info) == 0 && info) {
2752 char *canon;
2753
2754 if (info->ai_canonname &&
2755 (canon = strchr(info->ai_canonname, '.')))
2756 dom = canon + 1;
2757 }
2758 fputs(dom ? dom : "unknown_domain", ie->output);
2759 if (info)
2760 freeaddrinfo(info);
2761 free(host);
2762 break;
2763 }
2764 case 'd':
2765 case 't':
2766 {
2767 time_t now;
2768 struct tm tm;
2769
2770 time(&now);
2771 localtime_r(&now, &tm);
2772
2773 if (c == 'd') /* ISO 8601 */
2774 fprintf(ie->output, "%s %s %2d %d",
2775 nl_langinfo(ABDAY_1 + tm.tm_wday),
2776 nl_langinfo(ABMON_1 + tm.tm_mon),
2777 tm.tm_mday,
2778 tm.tm_year < 70 ? tm.tm_year + 2000 :
2779 tm.tm_year + 1900);
2780 else
2781 fprintf(ie->output, "%02d:%02d:%02d",
2782 tm.tm_hour, tm.tm_min, tm.tm_sec);
2783 break;
2784 }
2785 case 'l':
2786 fprintf (ie->output, "%s", op->tty);
2787 break;
2788 case 'b':
2789 {
2790 const speed_t speed = cfgetispeed(tp);
2791 int i;
2792
2793 for (i = 0; speedtab[i].speed; i++) {
2794 if (speedtab[i].code == speed) {
2795 fprintf(ie->output, "%ld", speedtab[i].speed);
2796 break;
2797 }
2798 }
2799 break;
2800 }
2801 case 'S':
2802 {
2803 char *var = NULL, varname[64];
2804
2805 /* \S{varname} */
2806 if (get_escape_argument(fp, varname, sizeof(varname))) {
2807 var = read_os_release(op, varname);
2808 if (var) {
2809 if (strcmp(varname, "ANSI_COLOR") == 0)
2810 fprintf(ie->output, "\033[%sm", var);
2811 else
2812 fputs(var, ie->output);
2813 }
2814 /* \S */
2815 } else if ((var = read_os_release(op, "PRETTY_NAME"))) {
2816 fputs(var, ie->output);
2817
2818 /* \S and PRETTY_NAME not found */
2819 } else {
2820 uname(&uts);
2821 fputs(uts.sysname, ie->output);
2822 }
2823
2824 free(var);
2825
2826 break;
2827 }
2828 case 'u':
2829 case 'U':
2830 {
2831 int users = 0;
2832 #ifdef USE_SYSTEMD
2833 if (sd_booted() > 0) {
2834 users = sd_get_sessions(NULL);
2835 if (users < 0)
2836 users = 0;
2837 } else {
2838 #endif
2839 users = 0;
2840 struct utmpx *ut;
2841 setutxent();
2842 while ((ut = getutxent()))
2843 if (ut->ut_type == USER_PROCESS)
2844 users++;
2845 endutxent();
2846 #ifdef USE_SYSTEMD
2847 }
2848 #endif
2849 if (c == 'U')
2850 fprintf(ie->output, P_("%d user", "%d users", users), users);
2851 else
2852 fprintf (ie->output, "%d ", users);
2853 break;
2854 }
2855 #if defined(RTMGRP_IPV4_IFADDR) && defined(RTMGRP_IPV6_IFADDR)
2856 case '4':
2857 case '6':
2858 {
2859 sa_family_t family = c == '4' ? AF_INET : AF_INET6;
2860 struct ifaddrs *addrs = NULL;
2861 char iface[128];
2862
2863 if (getifaddrs(&addrs))
2864 break;
2865
2866 if (get_escape_argument(fp, iface, sizeof(iface)))
2867 output_iface_ip(ie, addrs, iface, family);
2868 else
2869 output_iface_ip(ie, addrs, NULL, family);
2870
2871 freeifaddrs(addrs);
2872
2873 if (c == '4')
2874 netlink_groups |= RTMGRP_IPV4_IFADDR;
2875 else
2876 netlink_groups |= RTMGRP_IPV6_IFADDR;
2877 break;
2878 }
2879 #endif
2880 default:
2881 putc(c, ie->output);
2882 break;
2883 }
2884 }
2885
2886 static void init_special_char(char* arg, struct options *op)
2887 {
2888 char ch, *p, *q;
2889 int i;
2890
2891 op->initstring = malloc(strlen(arg) + 1);
2892 if (!op->initstring)
2893 log_err(_("failed to allocate memory: %m"));
2894
2895 /*
2896 * Copy optarg into op->initstring decoding \ddd octal
2897 * codes into chars.
2898 */
2899 q = op->initstring;
2900 p = arg;
2901 while (*p) {
2902 /* The \\ is converted to \ */
2903 if (*p == '\\') {
2904 p++;
2905 if (*p == '\\') {
2906 ch = '\\';
2907 p++;
2908 } else {
2909 /* Handle \000 - \177. */
2910 ch = 0;
2911 for (i = 1; i <= 3; i++) {
2912 if (*p >= '0' && *p <= '7') {
2913 ch <<= 3;
2914 ch += *p - '0';
2915 p++;
2916 } else {
2917 break;
2918 }
2919 }
2920 }
2921 *q++ = ch;
2922 } else
2923 *q++ = *p++;
2924 }
2925 *q = '\0';
2926 }
2927
2928 /*
2929 * Appends @str to @dest and if @dest is not empty then use @sep as a
2930 * separator. The maximal final length of the @dest is @len.
2931 *
2932 * Returns the final @dest length or -1 in case of error.
2933 */
2934 static ssize_t append(char *dest, size_t len, const char *sep, const char *src)
2935 {
2936 size_t dsz = 0, ssz = 0, sz;
2937 char *p;
2938
2939 if (!dest || !len || !src)
2940 return -1;
2941
2942 if (*dest)
2943 dsz = strlen(dest);
2944 if (dsz && sep)
2945 ssz = strlen(sep);
2946 sz = strlen(src);
2947
2948 if (dsz + ssz + sz + 1 > len)
2949 return -1;
2950
2951 p = dest + dsz;
2952 if (ssz) {
2953 p = mempcpy(p, sep, ssz);
2954 }
2955 memcpy(p, src, sz);
2956 *(p + sz) = '\0';
2957
2958 return dsz + ssz + sz;
2959 }
2960
2961 /*
2962 * Do not allow the user to pass an option as a user name
2963 * To be more safe: Use `--' to make sure the rest is
2964 * interpreted as non-options by the program, if it supports it.
2965 */
2966 static void check_username(const char* nm)
2967 {
2968 const char *p = nm;
2969 if (!nm)
2970 goto err;
2971 if (strlen(nm) > 42)
2972 goto err;
2973 while (isspace(*p))
2974 p++;
2975 if (*p == '-')
2976 goto err;
2977 return;
2978 err:
2979 errno = EPERM;
2980 log_err(_("checkname failed: %m"));
2981 }
2982
2983 static void reload_agettys(void)
2984 {
2985 #ifdef AGETTY_RELOAD
2986 int fd = open(AGETTY_RELOAD_FILENAME, O_CREAT|O_CLOEXEC|O_WRONLY,
2987 S_IRUSR|S_IWUSR);
2988 if (fd < 0)
2989 err(EXIT_FAILURE, _("cannot open %s"), AGETTY_RELOAD_FILENAME);
2990
2991 if (futimens(fd, NULL) < 0 || close(fd) < 0)
2992 err(EXIT_FAILURE, _("cannot touch file %s"),
2993 AGETTY_RELOAD_FILENAME);
2994 #else
2995 /* very unusual */
2996 errx(EXIT_FAILURE, _("--reload is unsupported on your system"));
2997 #endif
2998 }
2999
3000 static void load_credentials(struct options *op) {
3001 char *env;
3002 DIR *dir;
3003 struct dirent *d;
3004 struct path_cxt *pc;
3005
3006 env = safe_getenv("CREDENTIALS_DIRECTORY");
3007 if (!env)
3008 return;
3009
3010 pc = ul_new_path("%s", env);
3011 if (!pc) {
3012 log_warn(_("failed to initialize path context"));
3013 return;
3014 }
3015
3016 dir = ul_path_opendir(pc, NULL);
3017 if (!dir) {
3018 log_warn(_("failed to open credentials directory"));
3019 return;
3020 }
3021
3022 while ((d = xreaddir(dir))) {
3023 char *str;
3024
3025 if (strcmp(d->d_name, "agetty.autologin") == 0) {
3026 ul_path_read_string(pc, &str, d->d_name);
3027 free(op->autolog);
3028 op->autolog = str;
3029 }
3030 }
3031 closedir(dir);
3032 }