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