getty: fix a minor problem of Ctrl-D not printing '\n'
authorDenys Vlasenko <vda.linux@googlemail.com>
Sun, 23 Oct 2011 21:58:59 +0000 (23:58 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sun, 23 Oct 2011 21:58:59 +0000 (23:58 +0200)
Also removed defines for control chars which are never changed,
and added login/getty README.

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
loginutils/README [new file with mode: 0644]
loginutils/getty.c
loginutils/login.c

diff --git a/loginutils/README b/loginutils/README
new file mode 100644 (file)
index 0000000..ce88510
--- /dev/null
@@ -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.
index 32735642b3bbb876fbb69532e121d59d3f6d591d..4d52197257ecc4d725fd9ea6969e6fb3bf0f15a5 100644 (file)
@@ -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 */
index b54beef6eab906f76b92804abc3f68b2902517a3..73db8fa63177d94fe0c0ad6ef6db9c4761c32e9a 100644 (file)
@@ -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) {