source: MondoRescue/branches/3.3/mindi-busybox/loginutils/getty.c@ 3622

Last change on this file since 3622 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 21.8 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Based on agetty - another getty program for Linux. By W. Z. Venema 1989
4 * Ported to Linux by Peter Orbaek <poe@daimi.aau.dk>
5 * This program is freely distributable.
6 *
7 * option added by Eric Rasmussen <ear@usfirst.org> - 12/28/95
8 *
9 * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
10 * - Added Native Language Support
11 *
12 * 1999-05-05 Thorsten Kranzkowski <dl8bcu@gmx.net>
13 * - Enabled hardware flow control before displaying /etc/issue
14 *
15 * 2011-01 Venys Vlasenko
16 * - Removed parity detection code. It can't work reliably:
17 * if all chars received have bit 7 cleared and odd (or even) parity,
18 * it is impossible to determine whether other side is 8-bit,no-parity
19 * or 7-bit,odd(even)-parity. It also interferes with non-ASCII usernames.
20 * - From now on, we assume that parity is correctly set.
21 *
22 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
23 */
24//config:config GETTY
25//config: bool "getty"
26//config: default y
27//config: select FEATURE_SYSLOG
28//config: help
29//config: getty lets you log in on a tty. It is normally invoked by init.
30//config:
31//config: Note that you can save a few bytes by disabling it and
32//config: using login applet directly.
33//config: If you need to reset tty attributes before calling login,
34//config: this script approximates getty:
35//config:
36//config: exec </dev/$1 >/dev/$1 2>&1 || exit 1
37//config: reset
38//config: stty sane; stty ispeed 38400; stty ospeed 38400
39//config: printf "%s login: " "`hostname`"
40//config: read -r login
41//config: exec /bin/login "$login"
42
43//applet:IF_GETTY(APPLET(getty, BB_DIR_SBIN, BB_SUID_DROP))
44
45//kbuild:lib-$(CONFIG_GETTY) += getty.o
46
47#include "libbb.h"
48#include <syslog.h>
49#ifndef IUCLC
50# define IUCLC 0
51#endif
52
53#ifndef LOGIN_PROCESS
54# undef ENABLE_FEATURE_UTMP
55# undef ENABLE_FEATURE_WTMP
56# define ENABLE_FEATURE_UTMP 0
57# define ENABLE_FEATURE_WTMP 0
58#endif
59
60
61/* The following is used for understandable diagnostics */
62#ifdef DEBUGGING
63static FILE *dbf;
64# define DEBUGTERM "/dev/ttyp0"
65# define debug(...) do { fprintf(dbf, __VA_ARGS__); fflush(dbf); } while (0)
66#else
67# define debug(...) ((void)0)
68#endif
69
70
71/*
72 * Things you may want to modify.
73 *
74 * You may disagree with the default line-editing etc. characters defined
75 * below. Note, however, that DEL cannot be used for interrupt generation
76 * and for line editing at the same time.
77 */
78#undef _PATH_LOGIN
79#define _PATH_LOGIN "/bin/login"
80
81/* Displayed before the login prompt.
82 * If ISSUE is not defined, getty will never display the contents of the
83 * /etc/issue file. You will not want to spit out large "issue" files at the
84 * wrong baud rate.
85 */
86#define ISSUE "/etc/issue"
87
88/* Macro to build Ctrl-LETTER. Assumes ASCII dialect */
89#define CTL(x) ((x) ^ 0100)
90
91/*
92 * When multiple baud rates are specified on the command line,
93 * the first one we will try is the first one specified.
94 */
95#define MAX_SPEED 10 /* max. nr. of baud rates */
96
97struct globals {
98 unsigned timeout;
99 const char *login; /* login program */
100 const char *fakehost;
101 const char *tty_name;
102 char *initstring; /* modem init string */
103 const char *issue; /* alternative issue file */
104 int numspeed; /* number of baud rates to try */
105 int speeds[MAX_SPEED]; /* baud rates to be tried */
106 unsigned char eol; /* end-of-line char seen (CR or NL) */
107 struct termios tty_attrs;
108 char line_buf[128];
109};
110
111#define G (*ptr_to_globals)
112#define INIT_G() do { \
113 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
114} while (0)
115
116//usage:#define getty_trivial_usage
117//usage: "[OPTIONS] BAUD_RATE[,BAUD_RATE]... TTY [TERMTYPE]"
118//usage:#define getty_full_usage "\n\n"
119//usage: "Open TTY, prompt for login name, then invoke /bin/login\n"
120//usage: "\n -h Enable hardware RTS/CTS flow control"
121//usage: "\n -L Set CLOCAL (ignore Carrier Detect state)"
122//usage: "\n -m Get baud rate from modem's CONNECT status message"
123//usage: "\n -n Don't prompt for login name"
124//usage: "\n -w Wait for CR or LF before sending /etc/issue"
125//usage: "\n -i Don't display /etc/issue"
126//usage: "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue"
127//usage: "\n -l LOGIN Invoke LOGIN instead of /bin/login"
128//usage: "\n -t SEC Terminate after SEC if no login name is read"
129//usage: "\n -I INITSTR Send INITSTR before anything else"
130//usage: "\n -H HOST Log HOST into the utmp file as the hostname"
131//usage: "\n"
132//usage: "\nBAUD_RATE of 0 leaves it unchanged"
133
134static const char opt_string[] ALIGN1 = "I:LH:f:hil:mt:wn";
135#define F_INITSTRING (1 << 0) /* -I */
136#define F_LOCAL (1 << 1) /* -L */
137#define F_FAKEHOST (1 << 2) /* -H */
138#define F_CUSTISSUE (1 << 3) /* -f */
139#define F_RTSCTS (1 << 4) /* -h */
140#define F_NOISSUE (1 << 5) /* -i */
141#define F_LOGIN (1 << 6) /* -l */
142#define F_PARSE (1 << 7) /* -m */
143#define F_TIMEOUT (1 << 8) /* -t */
144#define F_WAITCRLF (1 << 9) /* -w */
145#define F_NOPROMPT (1 << 10) /* -n */
146
147
148/* convert speed string to speed code; return <= 0 on failure */
149static int bcode(const char *s)
150{
151 int value = bb_strtou(s, NULL, 10); /* yes, int is intended! */
152 if (value < 0) /* bad terminating char, overflow, etc */
153 return value;
154 return tty_value_to_baud(value);
155}
156
157/* parse alternate baud rates */
158static void parse_speeds(char *arg)
159{
160 char *cp;
161
162 /* NB: at least one iteration is always done */
163 debug("entered parse_speeds\n");
164 while ((cp = strsep(&arg, ",")) != NULL) {
165 G.speeds[G.numspeed] = bcode(cp);
166 if (G.speeds[G.numspeed] < 0)
167 bb_error_msg_and_die("bad speed: %s", cp);
168 /* note: arg "0" turns into speed B0 */
169 G.numspeed++;
170 if (G.numspeed > MAX_SPEED)
171 bb_error_msg_and_die("too many alternate speeds");
172 }
173 debug("exiting parse_speeds\n");
174}
175
176/* parse command-line arguments */
177static void parse_args(char **argv)
178{
179 char *ts;
180 int flags;
181
182 opt_complementary = "-2:t+"; /* at least 2 args; -t N */
183 flags = getopt32(argv, opt_string,
184 &G.initstring, &G.fakehost, &G.issue,
185 &G.login, &G.timeout
186 );
187 if (flags & F_INITSTRING) {
188 G.initstring = xstrdup(G.initstring);
189 /* decode \ddd octal codes into chars */
190 strcpy_and_process_escape_sequences(G.initstring, G.initstring);
191 }
192 argv += optind;
193 debug("after getopt\n");
194
195 /* We loosen up a bit and accept both "baudrate tty" and "tty baudrate" */
196 G.tty_name = argv[0];
197 ts = argv[1]; /* baud rate(s) */
198 if (isdigit(argv[0][0])) {
199 /* A number first, assume it's a speed (BSD style) */
200 G.tty_name = ts; /* tty name is in argv[1] */
201 ts = argv[0]; /* baud rate(s) */
202 }
203 parse_speeds(ts);
204
205 if (argv[2])
206 xsetenv("TERM", argv[2]);
207
208 debug("exiting parse_args\n");
209}
210
211/* set up tty as standard input, output, error */
212static void open_tty(void)
213{
214 /* Set up new standard input, unless we are given an already opened port */
215 if (NOT_LONE_DASH(G.tty_name)) {
216 if (G.tty_name[0] != '/')
217 G.tty_name = xasprintf("/dev/%s", G.tty_name); /* will leak it */
218
219 /* Open the tty as standard input */
220 debug("open(2)\n");
221 close(0);
222 xopen(G.tty_name, O_RDWR | O_NONBLOCK); /* uses fd 0 */
223
224 /* Set proper protections and ownership */
225 fchown(0, 0, 0); /* 0:0 */
226 fchmod(0, 0620); /* crw--w---- */
227 } else {
228 char *n;
229 /*
230 * Standard input should already be connected to an open port.
231 * Make sure it is open for read/write.
232 */
233 if ((fcntl(0, F_GETFL) & (O_RDWR|O_RDONLY|O_WRONLY)) != O_RDWR)
234 bb_error_msg_and_die("stdin is not open for read/write");
235
236 /* Try to get real tty name instead of "-" */
237 n = xmalloc_ttyname(0);
238 if (n)
239 G.tty_name = n;
240 }
241 applet_name = xasprintf("getty: %s", skip_dev_pfx(G.tty_name));
242}
243
244static void set_tty_attrs(void)
245{
246 if (tcsetattr_stdin_TCSANOW(&G.tty_attrs) < 0)
247 bb_perror_msg_and_die("tcsetattr");
248}
249
250/* We manipulate tty_attrs this way:
251 * - first, we read existing tty_attrs
252 * - init_tty_attrs modifies some parts and sets it
253 * - auto_baud and/or BREAK processing can set different speed and set tty attrs
254 * - finalize_tty_attrs again modifies some parts and sets tty attrs before
255 * execing login
256 */
257static void init_tty_attrs(int speed)
258{
259 /* Try to drain output buffer, with 5 sec timeout.
260 * Added on request from users of ~600 baud serial interface
261 * with biggish buffer on a 90MHz CPU.
262 * They were losing hundreds of bytes of buffered output
263 * on tcflush.
264 */
265 signal_no_SA_RESTART_empty_mask(SIGALRM, record_signo);
266 alarm(5);
267 tcdrain(STDIN_FILENO);
268 alarm(0);
269
270 /* Flush input and output queues, important for modems! */
271 tcflush(STDIN_FILENO, TCIOFLUSH);
272
273 /* Set speed if it wasn't specified as "0" on command line */
274 if (speed != B0)
275 cfsetspeed(&G.tty_attrs, speed);
276
277 /* Initial settings: 8-bit characters, raw mode, blocking i/o.
278 * Special characters are set after we have read the login name; all
279 * reads will be done in raw mode anyway.
280 */
281 /* Clear all bits except: */
282 G.tty_attrs.c_cflag &= (0
283 /* 2 stop bits (1 otherwise)
284 * Enable parity bit (both on input and output)
285 * Odd parity (else even)
286 */
287 | CSTOPB | PARENB | PARODD
288#ifdef CMSPAR
289 | CMSPAR /* mark or space parity */
290#endif
291#ifdef CBAUD
292 | CBAUD /* (output) baud rate */
293#endif
294#ifdef CBAUDEX
295 | CBAUDEX /* (output) baud rate */
296#endif
297#ifdef CIBAUD
298 | CIBAUD /* input baud rate */
299#endif
300 );
301 /* Set: 8 bits; hang up (drop DTR) on last close; enable receive */
302 G.tty_attrs.c_cflag |= CS8 | HUPCL | CREAD;
303 if (option_mask32 & F_LOCAL) {
304 /* ignore Carrier Detect pin:
305 * opens don't block when CD is low,
306 * losing CD doesn't hang up processes whose ctty is this tty
307 */
308 G.tty_attrs.c_cflag |= CLOCAL;
309 }
310#ifdef CRTSCTS
311 if (option_mask32 & F_RTSCTS)
312 G.tty_attrs.c_cflag |= CRTSCTS; /* flow control using RTS/CTS pins */
313#endif
314 G.tty_attrs.c_iflag = 0;
315 G.tty_attrs.c_lflag = 0;
316 /* non-raw output; add CR to each NL */
317 G.tty_attrs.c_oflag = OPOST | ONLCR;
318
319 /* reads would block only if < 1 char is available */
320 G.tty_attrs.c_cc[VMIN] = 1;
321 /* no timeout (reads block forever) */
322 G.tty_attrs.c_cc[VTIME] = 0;
323#ifdef __linux__
324 G.tty_attrs.c_line = 0;
325#endif
326
327 set_tty_attrs();
328
329 debug("term_io 2\n");
330}
331
332static void finalize_tty_attrs(void)
333{
334 /* software flow control on output (stop sending if XOFF is recvd);
335 * and on input (send XOFF when buffer is full)
336 */
337 G.tty_attrs.c_iflag |= IXON | IXOFF;
338 if (G.eol == '\r') {
339 G.tty_attrs.c_iflag |= ICRNL; /* map CR on input to NL */
340 }
341 /* Other bits in c_iflag:
342 * IXANY Any recvd char enables output (any char is also a XON)
343 * INPCK Enable parity check
344 * IGNPAR Ignore parity errors (drop bad bytes)
345 * PARMRK Mark parity errors with 0xff, 0x00 prefix
346 * (else bad byte is received as 0x00)
347 * ISTRIP Strip parity bit
348 * IGNBRK Ignore break condition
349 * BRKINT Send SIGINT on break - maybe set this?
350 * INLCR Map NL to CR
351 * IGNCR Ignore CR
352 * ICRNL Map CR to NL
353 * IUCLC Map uppercase to lowercase
354 * IMAXBEL Echo BEL on input line too long
355 * IUTF8 Appears to affect tty's idea of char widths,
356 * observed to improve backspacing through Unicode chars
357 */
358
359 /* ICANON line buffered input (NL or EOL or EOF chars end a line);
360 * ISIG recognize INT/QUIT/SUSP chars;
361 * ECHO echo input chars;
362 * ECHOE echo BS-SP-BS on erase character;
363 * ECHOK echo kill char specially, not as ^c (ECHOKE controls how exactly);
364 * ECHOKE erase all input via BS-SP-BS on kill char (else go to next line)
365 * ECHOCTL Echo ctrl chars as ^c (else echo verbatim:
366 * e.g. up arrow emits "ESC-something" and thus moves cursor up!)
367 */
368 G.tty_attrs.c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE | ECHOCTL;
369 /* Other bits in c_lflag:
370 * XCASE Map uppercase to \lowercase [tried, doesn't work]
371 * ECHONL Echo NL even if ECHO is not set
372 * ECHOPRT On erase, echo erased chars
373 * [qwe<BS><BS><BS> input looks like "qwe\ewq/" on screen]
374 * NOFLSH Don't flush input buffer after interrupt or quit chars
375 * IEXTEN Enable extended functions (??)
376 * [glibc says it enables c_cc[LNEXT] "enter literal char"
377 * and c_cc[VDISCARD] "toggle discard buffered output" chars]
378 * FLUSHO Output being flushed (c_cc[VDISCARD] is in effect)
379 * PENDIN Retype pending input at next read or input char
380 * (c_cc[VREPRINT] is being processed)
381 * TOSTOP Send SIGTTOU for background output
382 * (why "stty sane" unsets this bit?)
383 */
384
385 G.tty_attrs.c_cc[VINTR] = CTL('C');
386 G.tty_attrs.c_cc[VQUIT] = CTL('\\');
387 G.tty_attrs.c_cc[VEOF] = CTL('D');
388 G.tty_attrs.c_cc[VEOL] = '\n';
389#ifdef VSWTC
390 G.tty_attrs.c_cc[VSWTC] = 0;
391#endif
392#ifdef VSWTCH
393 G.tty_attrs.c_cc[VSWTCH] = 0;
394#endif
395 G.tty_attrs.c_cc[VKILL] = CTL('U');
396 /* Other control chars:
397 * VEOL2
398 * VERASE, VWERASE - (word) erase. we may set VERASE in get_logname
399 * VREPRINT - reprint current input buffer
400 * VLNEXT, VDISCARD, VSTATUS
401 * VSUSP, VDSUSP - send (delayed) SIGTSTP
402 * VSTART, VSTOP - chars used for IXON/IXOFF
403 */
404
405 set_tty_attrs();
406
407 /* Now the newline character should be properly written */
408 full_write(STDOUT_FILENO, "\n", 1);
409}
410
411/* extract baud rate from modem status message */
412static void auto_baud(void)
413{
414 int nread;
415
416 /*
417 * This works only if the modem produces its status code AFTER raising
418 * the DCD line, and if the computer is fast enough to set the proper
419 * baud rate before the message has gone by. We expect a message of the
420 * following format:
421 *
422 * <junk><number><junk>
423 *
424 * The number is interpreted as the baud rate of the incoming call. If the
425 * modem does not tell us the baud rate within one second, we will keep
426 * using the current baud rate. It is advisable to enable BREAK
427 * processing (comma-separated list of baud rates) if the processing of
428 * modem status messages is enabled.
429 */
430
431 G.tty_attrs.c_cc[VMIN] = 0; /* don't block reads (min read is 0 chars) */
432 set_tty_attrs();
433
434 /*
435 * Wait for a while, then read everything the modem has said so far and
436 * try to extract the speed of the dial-in call.
437 */
438 sleep(1);
439 nread = safe_read(STDIN_FILENO, G.line_buf, sizeof(G.line_buf) - 1);
440 if (nread > 0) {
441 int speed;
442 char *bp;
443 G.line_buf[nread] = '\0';
444 for (bp = G.line_buf; bp < G.line_buf + nread; bp++) {
445 if (isdigit(*bp)) {
446 speed = bcode(bp);
447 if (speed > 0)
448 cfsetspeed(&G.tty_attrs, speed);
449 break;
450 }
451 }
452 }
453
454 /* Restore terminal settings */
455 G.tty_attrs.c_cc[VMIN] = 1; /* restore to value set by init_tty_attrs */
456 set_tty_attrs();
457}
458
459/* get user name, establish parity, speed, erase, kill, eol;
460 * return NULL on BREAK, logname on success
461 */
462static char *get_logname(void)
463{
464 char *bp;
465 char c;
466
467 /* Flush pending input (esp. after parsing or switching the baud rate) */
468 usleep(100*1000); /* 0.1 sec */
469 tcflush(STDIN_FILENO, TCIFLUSH);
470
471 /* Prompt for and read a login name */
472 do {
473 /* Write issue file and prompt */
474#ifdef ISSUE
475 if (!(option_mask32 & F_NOISSUE))
476 print_login_issue(G.issue, G.tty_name);
477#endif
478 print_login_prompt();
479
480 /* Read name, watch for break, erase, kill, end-of-line */
481 bp = G.line_buf;
482 while (1) {
483 /* Do not report trivial EINTR/EIO errors */
484 errno = EINTR; /* make read of 0 bytes be silent too */
485 if (read(STDIN_FILENO, &c, 1) < 1) {
486 finalize_tty_attrs();
487 if (errno == EINTR || errno == EIO)
488 exit(EXIT_SUCCESS);
489 bb_perror_msg_and_die(bb_msg_read_error);
490 }
491
492 switch (c) {
493 case '\r':
494 case '\n':
495 *bp = '\0';
496 G.eol = c;
497 goto got_logname;
498 case CTL('H'):
499 case 0x7f:
500 G.tty_attrs.c_cc[VERASE] = c;
501 if (bp > G.line_buf) {
502 full_write(STDOUT_FILENO, "\010 \010", 3);
503 bp--;
504 }
505 break;
506 case CTL('U'):
507 while (bp > G.line_buf) {
508 full_write(STDOUT_FILENO, "\010 \010", 3);
509 bp--;
510 }
511 break;
512 case CTL('C'):
513 case CTL('D'):
514 finalize_tty_attrs();
515 exit(EXIT_SUCCESS);
516 case '\0':
517 /* BREAK. If we have speeds to try,
518 * return NULL (will switch speeds and return here) */
519 if (G.numspeed > 1)
520 return NULL;
521 /* fall through and ignore it */
522 default:
523 if ((unsigned char)c < ' ') {
524 /* ignore garbage characters */
525 } else if ((int)(bp - G.line_buf) < sizeof(G.line_buf) - 1) {
526 /* echo and store the character */
527 full_write(STDOUT_FILENO, &c, 1);
528 *bp++ = c;
529 }
530 break;
531 }
532 } /* end of get char loop */
533 got_logname: ;
534 } while (G.line_buf[0] == '\0'); /* while logname is empty */
535
536 return G.line_buf;
537}
538
539static void alarm_handler(int sig UNUSED_PARAM)
540{
541 finalize_tty_attrs();
542 _exit(EXIT_SUCCESS);
543}
544
545static void sleep10(void)
546{
547 sleep(10);
548}
549
550int getty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
551int getty_main(int argc UNUSED_PARAM, char **argv)
552{
553 int n;
554 pid_t pid, tsid;
555 char *logname;
556
557 INIT_G();
558 G.login = _PATH_LOGIN; /* default login program */
559#ifdef ISSUE
560 G.issue = ISSUE; /* default issue file */
561#endif
562 G.eol = '\r';
563
564 /* Parse command-line arguments */
565 parse_args(argv);
566
567 /* Create new session and pgrp, lose controlling tty */
568 pid = setsid(); /* this also gives us our pid :) */
569 if (pid < 0) {
570 int fd;
571 /* :(
572 * docs/ctty.htm says:
573 * "This is allowed only when the current process
574 * is not a process group leader".
575 * Thus, setsid() will fail if we _already_ are
576 * a session leader - which is quite possible for getty!
577 */
578 pid = getpid();
579 if (getsid(0) != pid) {
580 //for debugging:
581 //bb_perror_msg_and_die("setsid failed:"
582 // " pid %d ppid %d"
583 // " sid %d pgid %d",
584 // pid, getppid(),
585 // getsid(0), getpgid(0));
586 bb_perror_msg_and_die("setsid");
587 /*
588 * When we can end up here?
589 * Example: setsid() fails when run alone in interactive shell:
590 * # getty 115200 /dev/tty2
591 * because shell's child (getty) is put in a new process group.
592 * But doesn't fail if shell is not interactive
593 * (and therefore doesn't create process groups for pipes),
594 * or if getty is not the first process in the process group:
595 * # true | getty 115200 /dev/tty2
596 */
597 }
598 /* Looks like we are already a session leader.
599 * In this case (setsid failed) we may still have ctty,
600 * and it may be different from tty we need to control!
601 * If we still have ctty, on Linux ioctl(TIOCSCTTY)
602 * (which we are going to use a bit later) always fails -
603 * even if we try to take ctty which is already ours!
604 * Try to drop old ctty now to prevent that.
605 * Use O_NONBLOCK: old ctty may be a serial line.
606 */
607 fd = open("/dev/tty", O_RDWR | O_NONBLOCK);
608 if (fd >= 0) {
609 /* TIOCNOTTY sends SIGHUP to the foreground
610 * process group - which may include us!
611 * Make sure to not die on it:
612 */
613 sighandler_t old = signal(SIGHUP, SIG_IGN);
614 ioctl(fd, TIOCNOTTY);
615 close(fd);
616 signal(SIGHUP, old);
617 }
618 }
619
620 /* Close stdio, and stray descriptors, just in case */
621 n = xopen(bb_dev_null, O_RDWR);
622 /* dup2(n, 0); - no, we need to handle "getty - 9600" too */
623 xdup2(n, 1);
624 xdup2(n, 2);
625 while (n > 2)
626 close(n--);
627
628 /* Logging. We want special flavor of error_msg_and_die */
629 die_func = sleep10;
630 msg_eol = "\r\n";
631 /* most likely will internally use fd #3 in CLOEXEC mode: */
632 openlog(applet_name, LOG_PID, LOG_AUTH);
633 logmode = LOGMODE_BOTH;
634
635#ifdef DEBUGGING
636 dbf = xfopen_for_write(DEBUGTERM);
637 for (n = 1; argv[n]; n++) {
638 debug(argv[n]);
639 debug("\n");
640 }
641#endif
642
643 /* Open the tty as standard input, if it is not "-" */
644 debug("calling open_tty\n");
645 open_tty();
646 ndelay_off(STDIN_FILENO);
647 debug("duping\n");
648 xdup2(STDIN_FILENO, 1);
649 xdup2(STDIN_FILENO, 2);
650
651 /* Steal ctty if we don't have it yet */
652 tsid = tcgetsid(STDIN_FILENO);
653 if (tsid < 0 || pid != tsid) {
654 if (ioctl(STDIN_FILENO, TIOCSCTTY, /*force:*/ (long)1) < 0)
655 bb_perror_msg_and_die("TIOCSCTTY");
656 }
657
658#ifdef __linux__
659 /* Make ourself a foreground process group within our session */
660 if (tcsetpgrp(STDIN_FILENO, pid) < 0)
661 bb_perror_msg_and_die("tcsetpgrp");
662#endif
663
664 /*
665 * The following ioctl will fail if stdin is not a tty, but also when
666 * there is noise on the modem control lines. In the latter case, the
667 * common course of action is (1) fix your cables (2) give the modem more
668 * time to properly reset after hanging up. SunOS users can achieve (2)
669 * by patching the SunOS kernel variable "zsadtrlow" to a larger value;
670 * 5 seconds seems to be a good value.
671 */
672 if (tcgetattr(STDIN_FILENO, &G.tty_attrs) < 0)
673 bb_perror_msg_and_die("tcgetattr");
674
675 /* Update the utmp file. This tty is ours now! */
676 update_utmp(pid, LOGIN_PROCESS, G.tty_name, "LOGIN", G.fakehost);
677
678 /* Initialize tty attrs (raw mode, eight-bit, blocking i/o) */
679 debug("calling init_tty_attrs\n");
680 init_tty_attrs(G.speeds[0]);
681
682 /* Write the modem init string and DON'T flush the buffers */
683 if (option_mask32 & F_INITSTRING) {
684 debug("writing init string\n");
685 full_write1_str(G.initstring);
686 }
687
688 /* Optionally detect the baud rate from the modem status message */
689 debug("before autobaud\n");
690 if (option_mask32 & F_PARSE)
691 auto_baud();
692
693 /* Set the optional timer */
694 signal(SIGALRM, alarm_handler);
695 alarm(G.timeout); /* if 0, alarm is not set */
696
697 /* Optionally wait for CR or LF before writing /etc/issue */
698 if (option_mask32 & F_WAITCRLF) {
699 char ch;
700 debug("waiting for cr-lf\n");
701 while (safe_read(STDIN_FILENO, &ch, 1) == 1) {
702 debug("read %x\n", (unsigned char)ch);
703 if (ch == '\n' || ch == '\r')
704 break;
705 }
706 }
707
708 logname = NULL;
709 if (!(option_mask32 & F_NOPROMPT)) {
710 /* NB: init_tty_attrs already set line speed
711 * to G.speeds[0] */
712 int baud_index = 0;
713
714 while (1) {
715 /* Read the login name */
716 debug("reading login name\n");
717 logname = get_logname();
718 if (logname)
719 break;
720 /* We are here only if G.numspeed > 1 */
721 baud_index = (baud_index + 1) % G.numspeed;
722 cfsetspeed(&G.tty_attrs, G.speeds[baud_index]);
723 set_tty_attrs();
724 }
725 }
726
727 /* Disable timer */
728 alarm(0);
729
730 finalize_tty_attrs();
731
732 /* Let the login program take care of password validation */
733 /* We use PATH because we trust that root doesn't set "bad" PATH,
734 * and getty is not suid-root applet */
735 /* With -n, logname == NULL, and login will ask for username instead */
736 BB_EXECLP(G.login, G.login, "--", logname, (char *)0);
737 bb_error_msg_and_die("can't execute '%s'", G.login);
738}
Note: See TracBrowser for help on using the repository browser.