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