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