aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2011-01-24 14:35:09 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2011-01-24 14:35:09 +0100
commitfaaf8cb3faf413485f2ea1bb3656ac40cb48b785 (patch)
tree165225d4a3f3f0273ec8c0259973f357c9df0754
parent6596380f52cd48b8b44443bb5677ec8caf538761 (diff)
downloadbusybox-w32-faaf8cb3faf413485f2ea1bb3656ac40cb48b785.tar.gz
busybox-w32-faaf8cb3faf413485f2ea1bb3656ac40cb48b785.tar.bz2
busybox-w32-faaf8cb3faf413485f2ea1bb3656ac40cb48b785.zip
getty: more simplifications; explain how we treat parity now
function old new delta getty_main 1471 1434 -37 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--loginutils/getty.c188
1 files changed, 93 insertions, 95 deletions
diff --git a/loginutils/getty.c b/loginutils/getty.c
index bf66f2287..402e1c097 100644
--- a/loginutils/getty.c
+++ b/loginutils/getty.c
@@ -1,15 +1,23 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* Based on agetty - another getty program for Linux. By W. Z. Venema 1989 2/*
3 * Based on agetty - another getty program for Linux. By W. Z. Venema 1989
3 * Ported to Linux by Peter Orbaek <poe@daimi.aau.dk> 4 * Ported to Linux by Peter Orbaek <poe@daimi.aau.dk>
4 * This program is freely distributable. 5 * This program is freely distributable.
5 * 6 *
6 * option added by Eric Rasmussen <ear@usfirst.org> - 12/28/95 7 * option added by Eric Rasmussen <ear@usfirst.org> - 12/28/95
7 * 8 *
8 * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org> 9 * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
9 * - added Native Language Support 10 * - Added Native Language Support
10 * 11 *
11 * 1999-05-05 Thorsten Kranzkowski <dl8bcu@gmx.net> 12 * 1999-05-05 Thorsten Kranzkowski <dl8bcu@gmx.net>
12 * - enable hardware flow control before displaying /etc/issue 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.
13 * 21 *
14 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 22 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
15 */ 23 */
@@ -23,13 +31,7 @@
23# define IUCLC 0 31# define IUCLC 0
24#endif 32#endif
25 33
26/* 34#ifndef LOGIN_PROCESS
27 * Some heuristics to find out what environment we are in: if it is not
28 * System V, assume it is SunOS 4.
29 */
30#ifdef LOGIN_PROCESS /* defined in System V utmp.h */
31# include <sys/utsname.h>
32#else /* if !sysV style, wtmp/utmp code is off */
33# undef ENABLE_FEATURE_UTMP 35# undef ENABLE_FEATURE_UTMP
34# undef ENABLE_FEATURE_WTMP 36# undef ENABLE_FEATURE_WTMP
35# define ENABLE_FEATURE_UTMP 0 37# define ENABLE_FEATURE_UTMP 0
@@ -37,7 +39,7 @@
37#endif 39#endif
38 40
39 41
40/* The following is used for understandable diagnostics. */ 42/* The following is used for understandable diagnostics */
41#ifdef DEBUGGING 43#ifdef DEBUGGING
42static FILE *dbf; 44static FILE *dbf;
43# define DEBUGTERM "/dev/ttyp0" 45# define DEBUGTERM "/dev/ttyp0"
@@ -64,14 +66,14 @@ static FILE *dbf;
64 */ 66 */
65#define ISSUE "/etc/issue" 67#define ISSUE "/etc/issue"
66 68
67/* Some shorthands for control characters. */ 69/* Some shorthands for control characters */
68#define CTL(x) ((x) ^ 0100) /* Assumes ASCII dialect */ 70#define CTL(x) ((x) ^ 0100) /* Assumes ASCII dialect */
69#define CR CTL('M') /* carriage return */ 71#define CR CTL('M') /* carriage return */
70#define NL CTL('J') /* line feed */ 72#define NL CTL('J') /* line feed */
71#define BS CTL('H') /* back space */ 73#define BS CTL('H') /* back space */
72#define DEL CTL('?') /* delete */ 74#define DEL CTL('?') /* delete */
73 75
74/* Defaults for line-editing etc. characters; you may want to change this. */ 76/* Defaults for line-editing etc. characters; you may want to change this */
75#define DEF_ERASE DEL /* default erase character */ 77#define DEF_ERASE DEL /* default erase character */
76#define DEF_INTR CTL('C') /* default interrupt character */ 78#define DEF_INTR CTL('C') /* default interrupt character */
77#define DEF_QUIT CTL('\\') /* default quit char */ 79#define DEF_QUIT CTL('\\') /* default quit char */
@@ -81,23 +83,22 @@ static FILE *dbf;
81#define DEF_SWITCH 0 /* default switch char */ 83#define DEF_SWITCH 0 /* default switch char */
82 84
83/* 85/*
84 * When multiple baud rates are specified on the command line, the first one 86 * When multiple baud rates are specified on the command line,
85 * we will try is the first one specified. 87 * the first one we will try is the first one specified.
86 */ 88 */
87#define MAX_SPEED 10 /* max. nr. of baud rates */ 89#define MAX_SPEED 10 /* max. nr. of baud rates */
88 90
89struct globals { 91struct globals {
90 unsigned timeout; /* time-out period */ 92 unsigned timeout; /* time-out period */
91 const char *login; /* login program */ 93 const char *login; /* login program */
94 const char *fakehost;
92 const char *tty; /* name of tty */ 95 const char *tty; /* name of tty */
93 const char *initstring; /* modem init string */ 96 const char *initstring; /* modem init string */
94 const char *issue; /* alternative issue file */ 97 const char *issue; /* alternative issue file */
95 int numspeed; /* number of baud rates to try */ 98 int numspeed; /* number of baud rates to try */
96 int speeds[MAX_SPEED]; /* baud rates to be tried */ 99 int speeds[MAX_SPEED]; /* baud rates to be tried */
100 unsigned char eol; /* end-of-line char seen (CR or NL) */
97 struct termios termios; /* terminal mode bits */ 101 struct termios termios; /* terminal mode bits */
98 /* Storage for things detected while the login name was read. */
99 unsigned char erase; /* erase character */
100 unsigned char eol; /* end-of-line character */
101 char line_buf[128]; 102 char line_buf[128];
102}; 103};
103 104
@@ -168,14 +169,14 @@ static void parse_speeds(char *arg)
168} 169}
169 170
170/* parse command-line arguments */ 171/* parse command-line arguments */
171static void parse_args(char **argv, char **fakehost_p) 172static void parse_args(char **argv)
172{ 173{
173 char *ts; 174 char *ts;
174 int flags; 175 int flags;
175 176
176 opt_complementary = "-2:t+"; /* at least 2 args; -t N */ 177 opt_complementary = "-2:t+"; /* at least 2 args; -t N */
177 flags = getopt32(argv, opt_string, 178 flags = getopt32(argv, opt_string,
178 &G.initstring, fakehost_p, &G.issue, 179 &G.initstring, &G.fakehost, &G.issue,
179 &G.login, &G.timeout 180 &G.login, &G.timeout
180 ); 181 );
181 if (flags & F_INITSTRING) { 182 if (flags & F_INITSTRING) {
@@ -206,17 +207,17 @@ static void parse_args(char **argv, char **fakehost_p)
206/* set up tty as standard input, output, error */ 207/* set up tty as standard input, output, error */
207static void open_tty(void) 208static void open_tty(void)
208{ 209{
209 /* Set up new standard input, unless we are given an already opened port. */ 210 /* Set up new standard input, unless we are given an already opened port */
210 if (NOT_LONE_DASH(G.tty)) { 211 if (NOT_LONE_DASH(G.tty)) {
211 if (G.tty[0] != '/') 212 if (G.tty[0] != '/')
212 G.tty = xasprintf("/dev/%s", G.tty); /* will leak it */ 213 G.tty = xasprintf("/dev/%s", G.tty); /* will leak it */
213 214
214 /* Open the tty as standard input. */ 215 /* Open the tty as standard input */
215 debug("open(2)\n"); 216 debug("open(2)\n");
216 close(0); 217 close(0);
217 xopen(G.tty, O_RDWR | O_NONBLOCK); /* uses fd 0 */ 218 xopen(G.tty, O_RDWR | O_NONBLOCK); /* uses fd 0 */
218 219
219 /* Set proper protections and ownership. */ 220 /* Set proper protections and ownership */
220 fchown(0, 0, 0); /* 0:0 */ 221 fchown(0, 0, 0); /* 0:0 */
221 fchmod(0, 0620); /* crw--w---- */ 222 fchmod(0, 0620); /* crw--w---- */
222 } else { 223 } else {
@@ -229,7 +230,13 @@ static void open_tty(void)
229 } 230 }
230} 231}
231 232
232/* initialize termios settings */ 233/* We manipulate termios this way:
234 * - first, we read existing termios settings
235 * - termios_init modifies some parts and sets it
236 * - auto_baud and/or BREAK processing can set different speed and set termios
237 * - termios_final again modifies some parts and sets termios before
238 * execing login
239 */
233static void termios_init(int speed) 240static void termios_init(int speed)
234{ 241{
235 /* Flush input and output queues, important for modems! 242 /* Flush input and output queues, important for modems!
@@ -240,7 +247,7 @@ static void termios_init(int speed)
240 usleep(100*1000); /* 0.1 sec */ 247 usleep(100*1000); /* 0.1 sec */
241 tcflush(STDIN_FILENO, TCIOFLUSH); 248 tcflush(STDIN_FILENO, TCIOFLUSH);
242 249
243 /* Set speed if it wasn't specified as "0" on command line. */ 250 /* Set speed if it wasn't specified as "0" on command line */
244 if (speed != B0) 251 if (speed != B0)
245 cfsetspeed(&G.termios, speed); 252 cfsetspeed(&G.termios, speed);
246 253
@@ -271,13 +278,44 @@ static void termios_init(int speed)
271 debug("term_io 2\n"); 278 debug("term_io 2\n");
272} 279}
273 280
281static void termios_final(void)
282{
283 /* General terminal-independent stuff */
284 G.termios.c_iflag |= IXON | IXOFF; /* 2-way flow control */
285 G.termios.c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE;
286 /* no longer in lflag: | ECHOCTL | ECHOPRT */
287 G.termios.c_oflag |= OPOST;
288 /* G.termios.c_cflag = 0; */
289 G.termios.c_cc[VINTR] = DEF_INTR;
290 G.termios.c_cc[VQUIT] = DEF_QUIT;
291 G.termios.c_cc[VEOF] = DEF_EOF;
292 G.termios.c_cc[VEOL] = DEF_EOL;
293#ifdef VSWTC
294 G.termios.c_cc[VSWTC] = DEF_SWITCH;
295#endif
296
297 /* Account for special characters seen in input */
298 if (G.eol == CR) {
299 G.termios.c_iflag |= ICRNL; /* map CR in input to NL */
300 /* already done by termios_init */
301 /* G.termios.c_oflag |= ONLCR; map NL in output to CR-NL */
302 }
303 G.termios.c_cc[VKILL] = DEF_KILL;
304
305#ifdef CRTSCTS
306 /* Optionally enable hardware flow control */
307 if (option_mask32 & F_RTSCTS)
308 G.termios.c_cflag |= CRTSCTS;
309#endif
310
311 /* Finally, make the new settings effective */
312 if (tcsetattr_stdin_TCSANOW(&G.termios) < 0)
313 bb_perror_msg_and_die("tcsetattr");
314}
315
274/* extract baud rate from modem status message */ 316/* extract baud rate from modem status message */
275static void auto_baud(void) 317static void auto_baud(void)
276{ 318{
277 int speed;
278 int vmin;
279 unsigned iflag;
280 char *bp;
281 int nread; 319 int nread;
282 320
283 /* 321 /*
@@ -296,12 +334,9 @@ static void auto_baud(void)
296 */ 334 */
297 335
298 /* 336 /*
299 * Use 7-bit characters, don't block if input queue is empty. Errors will 337 * Don't block if input queue is empty.
300 * be dealt with later on. 338 * Errors will be dealt with later on.
301 */ 339 */
302 iflag = G.termios.c_iflag;
303 G.termios.c_iflag |= ISTRIP; /* enable 8th-bit stripping */
304 vmin = G.termios.c_cc[VMIN];
305 G.termios.c_cc[VMIN] = 0; /* don't block if queue empty */ 340 G.termios.c_cc[VMIN] = 0; /* don't block if queue empty */
306 tcsetattr_stdin_TCSANOW(&G.termios); 341 tcsetattr_stdin_TCSANOW(&G.termios);
307 342
@@ -312,6 +347,8 @@ static void auto_baud(void)
312 sleep(1); 347 sleep(1);
313 nread = safe_read(STDIN_FILENO, G.line_buf, sizeof(G.line_buf) - 1); 348 nread = safe_read(STDIN_FILENO, G.line_buf, sizeof(G.line_buf) - 1);
314 if (nread > 0) { 349 if (nread > 0) {
350 int speed;
351 char *bp;
315 G.line_buf[nread] = '\0'; 352 G.line_buf[nread] = '\0';
316 for (bp = G.line_buf; bp < G.line_buf + nread; bp++) { 353 for (bp = G.line_buf; bp < G.line_buf + nread; bp++) {
317 if (isdigit(*bp)) { 354 if (isdigit(*bp)) {
@@ -323,38 +360,38 @@ static void auto_baud(void)
323 } 360 }
324 } 361 }
325 362
326 /* Restore terminal settings. Errors will be dealt with later on. */ 363 /* Restore terminal settings. Errors will be dealt with later on */
327 G.termios.c_iflag = iflag; 364 G.termios.c_cc[VMIN] = 1; /* restore to value set by termios_init */
328 G.termios.c_cc[VMIN] = vmin;
329 tcsetattr_stdin_TCSANOW(&G.termios); 365 tcsetattr_stdin_TCSANOW(&G.termios);
330} 366}
331 367
332/* get user name, establish parity, speed, erase, kill, eol; 368/* get user name, establish parity, speed, erase, kill, eol;
333 * return NULL on BREAK, logname on success */ 369 * return NULL on BREAK, logname on success
370 */
334static char *get_logname(void) 371static char *get_logname(void)
335{ 372{
336 char *bp; 373 char *bp;
337 char c; 374 char c;
338 375
339 /* Flush pending input (esp. after parsing or switching the baud rate). */ 376 /* Flush pending input (esp. after parsing or switching the baud rate) */
340 usleep(100*1000); /* 0.1 sec */ 377 usleep(100*1000); /* 0.1 sec */
341 tcflush(STDIN_FILENO, TCIOFLUSH); 378 tcflush(STDIN_FILENO, TCIOFLUSH);
342 379
343 /* Prompt for and read a login name. */ 380 /* Prompt for and read a login name */
344 G.line_buf[0] = '\0'; 381 G.line_buf[0] = '\0';
345 while (!G.line_buf[0]) { 382 while (!G.line_buf[0]) {
346 /* Write issue file and prompt. */ 383 /* Write issue file and prompt */
347#ifdef ISSUE 384#ifdef ISSUE
348 if (!(option_mask32 & F_NOISSUE)) 385 if (!(option_mask32 & F_NOISSUE))
349 print_login_issue(G.issue, G.tty); 386 print_login_issue(G.issue, G.tty);
350#endif 387#endif
351 print_login_prompt(); 388 print_login_prompt();
352 389
353 /* Read name, watch for break, parity, erase, kill, end-of-line. */ 390 /* Read name, watch for break, parity, erase, kill, end-of-line */
354 bp = G.line_buf; 391 bp = G.line_buf;
355 G.eol = '\0'; 392 G.eol = '\0';
356 while (1) { 393 while (1) {
357 /* Do not report trivial EINTR/EIO errors. */ 394 /* Do not report trivial EINTR/EIO errors */
358 errno = EINTR; /* make read of 0 bytes be silent too */ 395 errno = EINTR; /* make read of 0 bytes be silent too */
359 if (read(STDIN_FILENO, &c, 1) < 1) { 396 if (read(STDIN_FILENO, &c, 1) < 1) {
360 if (errno == EINTR || errno == EIO) 397 if (errno == EINTR || errno == EIO)
@@ -367,7 +404,7 @@ static char *get_logname(void)
367 if (c == '\0' && G.numspeed > 1) 404 if (c == '\0' && G.numspeed > 1)
368 return NULL; 405 return NULL;
369 406
370 /* Do erase, kill and end-of-line processing. */ 407 /* Do erase, kill and end-of-line processing */
371 switch (c) { 408 switch (c) {
372 case CR: 409 case CR:
373 case NL: 410 case NL:
@@ -376,7 +413,7 @@ static char *get_logname(void)
376 goto got_logname; 413 goto got_logname;
377 case BS: 414 case BS:
378 case DEL: 415 case DEL:
379 G.erase = c; 416 G.termios.c_cc[VERASE] = c;
380 if (bp > G.line_buf) { 417 if (bp > G.line_buf) {
381 full_write(STDOUT_FILENO, "\010 \010", 3); 418 full_write(STDOUT_FILENO, "\010 \010", 3);
382 bp--; 419 bp--;
@@ -407,61 +444,22 @@ static char *get_logname(void)
407 return G.line_buf; 444 return G.line_buf;
408} 445}
409 446
410/* set the final tty mode bits */
411static void termios_final(void)
412{
413 /* General terminal-independent stuff. */
414 G.termios.c_iflag |= IXON | IXOFF; /* 2-way flow control */
415 G.termios.c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE;
416 /* no longer in lflag: | ECHOCTL | ECHOPRT */
417 G.termios.c_oflag |= OPOST;
418 /* G.termios.c_cflag = 0; */
419 G.termios.c_cc[VINTR] = DEF_INTR; /* default interrupt */
420 G.termios.c_cc[VQUIT] = DEF_QUIT; /* default quit */
421 G.termios.c_cc[VEOF] = DEF_EOF; /* default EOF character */
422 G.termios.c_cc[VEOL] = DEF_EOL;
423#ifdef VSWTC
424 G.termios.c_cc[VSWTC] = DEF_SWITCH; /* default switch character */
425#endif
426
427 /* Account for special characters seen in input. */
428 if (G.eol == CR) {
429 G.termios.c_iflag |= ICRNL; /* map CR in input to NL */
430 G.termios.c_oflag |= ONLCR; /* map NL in output to CR-NL */
431 }
432 G.termios.c_cc[VERASE] = G.erase; /* set erase character */
433 G.termios.c_cc[VKILL] = DEF_KILL; /* set kill character */
434
435#ifdef CRTSCTS
436 /* Optionally enable hardware flow control */
437 if (option_mask32 & F_RTSCTS)
438 G.termios.c_cflag |= CRTSCTS;
439#endif
440
441 /* Finally, make the new settings effective */
442 if (tcsetattr_stdin_TCSANOW(&G.termios) < 0)
443 bb_perror_msg_and_die("tcsetattr");
444}
445
446int getty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 447int getty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
447int getty_main(int argc UNUSED_PARAM, char **argv) 448int getty_main(int argc UNUSED_PARAM, char **argv)
448{ 449{
449 int n; 450 int n;
450 pid_t pid; 451 pid_t pid;
451 char *fakehost = NULL; /* Fake hostname for ut_host */
452 char *logname; 452 char *logname;
453 453
454 INIT_G(); 454 INIT_G();
455 G.login = _PATH_LOGIN; /* default login program */ 455 G.login = _PATH_LOGIN; /* default login program */
456 G.initstring = ""; /* modem init string */
457#ifdef ISSUE 456#ifdef ISSUE
458 G.issue = ISSUE; /* default issue file */ 457 G.issue = ISSUE; /* default issue file */
459#endif 458#endif
460 G.erase = DEF_ERASE;
461 G.eol = CR; 459 G.eol = CR;
462 460
463 /* Parse command-line arguments. */ 461 /* Parse command-line arguments */
464 parse_args(argv, &fakehost); 462 parse_args(argv);
465 463
466 logmode = LOGMODE_NONE; 464 logmode = LOGMODE_NONE;
467 465
@@ -524,9 +522,9 @@ int getty_main(int argc UNUSED_PARAM, char **argv)
524#endif 522#endif
525 523
526 /* Update the utmp file. This tty is ours now! */ 524 /* Update the utmp file. This tty is ours now! */
527 update_utmp(pid, LOGIN_PROCESS, G.tty, "LOGIN", fakehost); 525 update_utmp(pid, LOGIN_PROCESS, G.tty, "LOGIN", G.fakehost);
528 526
529 /* Initialize the termios settings (raw mode, eight-bit, blocking i/o). */ 527 /* Initialize the termios settings (raw mode, eight-bit, blocking i/o) */
530 debug("calling termios_init\n"); 528 debug("calling termios_init\n");
531 termios_init(G.speeds[0]); 529 termios_init(G.speeds[0]);
532 530
@@ -563,30 +561,30 @@ int getty_main(int argc UNUSED_PARAM, char **argv)
563 int baud_index = 0; 561 int baud_index = 0;
564 562
565 while (1) { 563 while (1) {
566 /* Read the login name. */ 564 /* Read the login name */
567 debug("reading login name\n"); 565 debug("reading login name\n");
568 logname = get_logname(); 566 logname = get_logname();
569 if (logname) 567 if (logname)
570 break; 568 break;
571 /* We are here only if G.numspeed > 1. */ 569 /* We are here only if G.numspeed > 1 */
572 baud_index = (baud_index + 1) % G.numspeed; 570 baud_index = (baud_index + 1) % G.numspeed;
573 cfsetspeed(&G.termios, G.speeds[baud_index]); 571 cfsetspeed(&G.termios, G.speeds[baud_index]);
574 tcsetattr_stdin_TCSANOW(&G.termios); 572 tcsetattr_stdin_TCSANOW(&G.termios);
575 } 573 }
576 } 574 }
577 575
578 /* Disable timer. */ 576 /* Disable timer */
579 alarm(0); 577 alarm(0);
580 578
581 /* Finalize the termios settings. */ 579 /* Finalize the termios settings */
582 termios_final(); 580 termios_final();
583 581
584 /* Now the newline character should be properly written. */ 582 /* Now the newline character should be properly written */
585 full_write(STDOUT_FILENO, "\n", 1); 583 full_write(STDOUT_FILENO, "\n", 1);
586 584
587 /* Let the login program take care of password validation. */ 585 /* Let the login program take care of password validation */
588 /* We use PATH because we trust that root doesn't set "bad" PATH, 586 /* We use PATH because we trust that root doesn't set "bad" PATH,
589 * and getty is not suid-root applet. */ 587 * and getty is not suid-root applet */
590 /* With -n, logname == NULL, and login will ask for username instead */ 588 /* With -n, logname == NULL, and login will ask for username instead */
591 BB_EXECLP(G.login, G.login, "--", logname, NULL); 589 BB_EXECLP(G.login, G.login, "--", logname, NULL);
592 bb_error_msg_and_die("can't execute '%s'", G.login); 590 bb_error_msg_and_die("can't execute '%s'", G.login);