udhcpc: fix a problem with binary-encoded options #2
[oweals/busybox.git] / loginutils / getty.c
index 168ae4de1f822e64dc3a53e0186f894980915b49..e5d13bed6b8161d8822edd3e260fb99cff2b9ee8 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,
@@ -254,7 +244,6 @@ static void init_tty_attrs(int speed)
        alarm(5);
        tcdrain(STDIN_FILENO);
        alarm(0);
-       signal(SIGALRM, SIG_DFL); /* do not break -t TIMEOUT! */
 
        /* Flush input and output queues, important for modems! */
        tcflush(STDIN_FILENO, TCIOFLUSH);
@@ -277,7 +266,9 @@ static void init_tty_attrs(int speed)
 #ifdef CMSPAR
                | CMSPAR  /* mark or space parity */
 #endif
+#ifdef CBAUD
                | CBAUD   /* (output) baud rate */
+#endif
 #ifdef CBAUDEX
                | CBAUDEX /* (output) baud rate */
 #endif
@@ -303,8 +294,10 @@ static void init_tty_attrs(int speed)
        /* non-raw output; add CR to each NL */
        G.tty_attrs.c_oflag = OPOST | ONLCR;
 
-       G.tty_attrs.c_cc[VMIN] = 1; /* block reads if < 1 char is available */
-       G.tty_attrs.c_cc[VTIME] = 0; /* no timeout (reads block forever) */
+       /* reads would block only if < 1 char is available */
+       G.tty_attrs.c_cc[VMIN] = 1;
+       /* no timeout (reads block forever) */
+       G.tty_attrs.c_cc[VTIME] = 0;
 #ifdef __linux__
        G.tty_attrs.c_line = 0;
 #endif
@@ -366,17 +359,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
@@ -387,6 +380,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 */
@@ -450,8 +446,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))
@@ -459,32 +454,26 @@ 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 */
                        if (read(STDIN_FILENO, &c, 1) < 1) {
+                               finalize_tty_attrs();
                                if (errno == EINTR || errno == EIO)
                                        exit(EXIT_SUCCESS);
                                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,8 +486,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 */
@@ -511,7 +508,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;
 }
@@ -551,19 +548,34 @@ int getty_main(int argc UNUSED_PARAM, char **argv)
                 * a session leader - which is quite possible for getty!
                 */
                pid = getpid();
-               if (getsid(0) != pid)
+               if (getsid(0) != pid) {
+                       //for debugging:
+                       //bb_perror_msg_and_die("setsid failed:"
+                       //      " pid %d ppid %d"
+                       //      " sid %d pgid %d",
+                       //      pid, getppid(),
+                       //      getsid(0), getpgid(0));
                        bb_perror_msg_and_die("setsid");
+               }
                /* Looks like we are already a session leader.
                 * In this case (setsid failed) we may still have ctty,
                 * and it may be different from tty we need to control!
                 * If we still have ctty, on Linux ioctl(TIOCSCTTY)
-                * (which we are going to call a bit later) always fails.
-                * Try to drop ctty now to prevent that.
+                * (which we are going to use a bit later) always fails -
+                * even if we try to take ctty which is already ours!
+                * Try to drop old ctty now to prevent that.
+                * Use O_NONBLOCK: old ctty may be a serial line.
                 */
-               fd = open("/dev/tty", O_RDWR);
+               fd = open("/dev/tty", O_RDWR | O_NONBLOCK);
                if (fd >= 0) {
+                       /* TIOCNOTTY sends SIGHUP to the foreground
+                        * process group - which may include us!
+                        * Make sure to not die on it:
+                        */
+                       sighandler_t old = signal(SIGHUP, SIG_IGN);
                        ioctl(fd, TIOCNOTTY);
                        close(fd);
+                       signal(SIGHUP, old);
                }
        }
 
@@ -679,9 +691,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 */