diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2011-10-24 01:58:59 +0400 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-10-24 01:58:59 +0400 |
commit | e9dc354df86e9a3026de406520f6cd03a3519495 (patch) | |
tree | be701340f824afa52536888ae116f96e02047967 | |
parent | ee320c6d9cd0781233ed599d743b4da94b4424a7 (diff) |
getty: fix a minor problem of Ctrl-D not printing '\n'
Also removed defines for control chars which are never changed,
and added login/getty README.
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | loginutils/README | 70 | ||||
-rw-r--r-- | loginutils/getty.c | 59 | ||||
-rw-r--r-- | loginutils/login.c | 1 |
3 files changed, 94 insertions, 36 deletions
diff --git a/loginutils/README b/loginutils/README new file mode 100644 index 000000000..ce8851097 --- /dev/null +++ b/loginutils/README @@ -0,0 +1,70 @@ + Getty + +??? Should getty open tty with or without O_NONBLOCK? +For serial lines, it means "should getty wait for Carrier Detect pin?" +I checked other getties: + +- agetty always uses O_NONBLOCK +- mgetty uses O_NONBLOCK unless run with -b, or as "getty" + +??? If we decided to use O_NONBLOCK (perhaps optionally with -b), +when getty should send -I INITSTR data to tty? After open succeeds? +What if we also want to initialize *modem* with some AT commands? + +??? Should we check/create /var/lock/LCK..ttyPFX lockfiles? + +??? mgetty opens tty but does NOT lock it, then waits for input via +select/poll, and when input is available, it checks lock file. +If it exists, mgetty exits (it assumes someone else uses the line). +If no, it creates the file (lock the tty). Sounds like a good algorithm +to use if we are called with -w... + +Getty should establish a new session and process group, and ensure +that tty is a ctty. + +??? Should getty ensure that other processes which might have opened +fds to this tty be dusconnected? agetty has a -R option which makes +agetty call vhangup() after tty is opened. (Then agetty opens it again, +since it probably vhangup'ed its own fd too). + +Getty should leave the tty in approximately the same state as "stty sane" +before it execs login program. Minor things we do conditionally are: + c_iflag |= ICRNL; // if '\r' was used to end username + +??? mgetty uses per-tty file to ignore connects, /etc/nologin.ttyxx - +is it useful? + +It should be possible to run "getty 0 -" from a shell prompt. +[This currently doesn't work from interactive shell since setsid() +fails in process group leader. The workaround is to run it as a child +of something. sh -c 'getty - 0; true' usually works. Should we fix this?] +It should leave tty in a sane state when it exits (Ctrl-D, -t SEC timeout): +echo should be on, speed, control chars properly set, etc. +(However, it can't restore ctty. The symptom is that "</dev/tty" +fails in the parent shell after getty exits: /dev/tty can't be opened). + +Getty should write LOGIN_PROCESS utmp record before it starts waiting +for username to be entered. + + Login + +Login should not try to set up tty parameters - apart from switching echo +off while entering password, and switching it back on after. + +Login should not leave "echo off" state when it times out reading password +or otherwise terminates (Ctrl-C, Ctrl-D etc). + +??? Should login establish a new session and/or process group, and ensure +that tty is a ctty? Without this, running login directly (not via getty) +from e.g. initscript will usually result with a login session without +ctty and without session/pgrp properly created... + +It should be possible to run "login [USER]" from a shell prompt, +and it should work (not block/die/error out). +Similarly to getty, it should leave tty in the sane state when it exits. + +??? Should login write LOGIN_PROCESS utmp record before it starts waiting +for username/password to be entered? + +Login should write USER_PROCESS utmp record just before it is about +to exec user's shell. diff --git a/loginutils/getty.c b/loginutils/getty.c index 32735642b..4d5219725 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c @@ -63,18 +63,8 @@ static FILE *dbf; */ #define ISSUE "/etc/issue" -/* Some shorthands for control characters */ -#define CTL(x) ((x) ^ 0100) /* Assumes ASCII dialect */ -#define BS CTL('H') /* back space */ -#define DEL CTL('?') /* delete */ - -/* Defaults for line-editing etc. characters; you may want to change this */ -#define DEF_INTR CTL('C') /* default interrupt character */ -#define DEF_QUIT CTL('\\') /* default quit char */ -#define DEF_KILL CTL('U') /* default kill char */ -#define DEF_EOF CTL('D') /* default EOF char */ -#define DEF_EOL '\n' -#define DEF_SWITCH 0 /* default switch char (none) */ +/* Macro to build Ctrl-LETTER. Assumes ASCII dialect */ +#define CTL(x) ((x) ^ 0100) /* * When multiple baud rates are specified on the command line, @@ -365,17 +355,17 @@ static void finalize_tty_attrs(void) * (why "stty sane" unsets this bit?) */ - G.tty_attrs.c_cc[VINTR] = DEF_INTR; - G.tty_attrs.c_cc[VQUIT] = DEF_QUIT; - G.tty_attrs.c_cc[VEOF] = DEF_EOF; - G.tty_attrs.c_cc[VEOL] = DEF_EOL; + G.tty_attrs.c_cc[VINTR] = CTL('C'); + G.tty_attrs.c_cc[VQUIT] = CTL('\\'); + G.tty_attrs.c_cc[VEOF] = CTL('D'); + G.tty_attrs.c_cc[VEOL] = '\n'; #ifdef VSWTC - G.tty_attrs.c_cc[VSWTC] = DEF_SWITCH; + G.tty_attrs.c_cc[VSWTC] = 0; #endif #ifdef VSWTCH - G.tty_attrs.c_cc[VSWTCH] = DEF_SWITCH; + G.tty_attrs.c_cc[VSWTCH] = 0; #endif - G.tty_attrs.c_cc[VKILL] = DEF_KILL; + G.tty_attrs.c_cc[VKILL] = CTL('U'); /* Other control chars: * VEOL2 * VERASE, VWERASE - (word) erase. we may set VERASE in get_logname @@ -386,6 +376,9 @@ static void finalize_tty_attrs(void) */ set_tty_attrs(); + + /* Now the newline character should be properly written */ + full_write(STDOUT_FILENO, "\n", 1); } /* extract baud rate from modem status message */ @@ -449,8 +442,7 @@ static char *get_logname(void) tcflush(STDIN_FILENO, TCIFLUSH); /* Prompt for and read a login name */ - G.line_buf[0] = '\0'; - while (!G.line_buf[0]) { + do { /* Write issue file and prompt */ #ifdef ISSUE if (!(option_mask32 & F_NOISSUE)) @@ -458,9 +450,8 @@ static char *get_logname(void) #endif print_login_prompt(); - /* Read name, watch for break, parity, erase, kill, end-of-line */ + /* Read name, watch for break, erase, kill, end-of-line */ bp = G.line_buf; - G.eol = '\0'; while (1) { /* Do not report trivial EINTR/EIO errors */ errno = EINTR; /* make read of 0 bytes be silent too */ @@ -471,20 +462,14 @@ static char *get_logname(void) bb_perror_msg_and_die(bb_msg_read_error); } - /* BREAK. If we have speeds to try, - * return NULL (will switch speeds and return here) */ - if (c == '\0' && G.numspeed > 1) - return NULL; - - /* Do erase, kill and end-of-line processing */ switch (c) { case '\r': case '\n': *bp = '\0'; G.eol = c; goto got_logname; - case BS: - case DEL: + case CTL('H'): + case 0x7f: G.tty_attrs.c_cc[VERASE] = c; if (bp > G.line_buf) { full_write(STDOUT_FILENO, "\010 \010", 3); @@ -497,9 +482,16 @@ static char *get_logname(void) bp--; } break; + case CTL('C'): case CTL('D'): finalize_tty_attrs(); exit(EXIT_SUCCESS); + case '\0': + /* BREAK. If we have speeds to try, + * return NULL (will switch speeds and return here) */ + if (G.numspeed > 1) + return NULL; + /* fall through and ignore it */ default: if ((unsigned char)c < ' ') { /* ignore garbage characters */ @@ -512,7 +504,7 @@ static char *get_logname(void) } } /* end of get char loop */ got_logname: ; - } /* while logname is empty */ + } while (G.line_buf[0] == '\0'); /* while logname is empty */ return G.line_buf; } @@ -682,9 +674,6 @@ int getty_main(int argc UNUSED_PARAM, char **argv) finalize_tty_attrs(); - /* Now the newline character should be properly written */ - full_write(STDOUT_FILENO, "\n", 1); - /* Let the login program take care of password validation */ /* We use PATH because we trust that root doesn't set "bad" PATH, * and getty is not suid-root applet */ diff --git a/loginutils/login.c b/loginutils/login.c index b54beef6e..73db8fa63 100644 --- a/loginutils/login.c +++ b/loginutils/login.c @@ -443,7 +443,6 @@ int login_main(int argc UNUSED_PARAM, char **argv) if (pw->pw_uid != 0) die_if_nologin(); - #if ENABLE_LOGIN_SESSION_AS_CHILD child_pid = vfork(); if (child_pid != 0) { |