getty: comment out parity detection code; improve usage text
authorDenys Vlasenko <vda.linux@googlemail.com>
Sat, 22 Jan 2011 02:06:40 +0000 (03:06 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sat, 22 Jan 2011 02:06:40 +0000 (03:06 +0100)
function                                             old     new   delta
packed_usage                                       28155   28191     +36
static.erase                                          12       -     -12
getty_main                                          1847    1621    -226
------------------------------------------------------------------------------
(add/remove: 0/1 grow/shrink: 1/1 up/down: 36/-238)          Total: -202 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
loginutils/getty.c

index 0f5e333a76122030259a05a884a14d4bc41d04f5..94c9147abebc3786592f1d66efd69e74d3b01242 100644 (file)
@@ -58,9 +58,16 @@ static FILE *dbf;
  * and for line editing at the same time.
  */
 
-/* I doubt there are systems which still need this */
+/* I doubt there are systems which still... */
+/* ...have only uppercase: */
 #undef HANDLE_ALLCAPS
+/* ...use # and @ for backspace and line erase: */
 #undef ANCIENT_BS_KILL_CHARS
+/* It actually makes sense (tries to guess parity by looking at 7th bit)
+ * but it's broken, and interferes with non-ASCII login names
+ * (yes, I did receive complains from real users):
+ */
+#undef BROKEN_PARITY_DETECTION_CODE
 
 #undef  _PATH_LOGIN
 #define _PATH_LOGIN "/bin/login"
@@ -108,8 +115,11 @@ struct options {
 /* Storage for things detected while the login name was read. */
 struct chardata {
        unsigned char erase;    /* erase character */
+#ifdef ANCIENT_BS_KILL_CHARS
        unsigned char kill;     /* kill character */
+#endif
        unsigned char eol;      /* end-of-line character */
+#ifdef BROKEN_PARITY_DETECTION_CODE
        unsigned char parity;   /* what parity did we see */
        /* (parity & 1): saw odd parity char with 7th bit set */
        /* (parity & 2): saw even parity char with 7th bit set */
@@ -117,7 +127,8 @@ struct chardata {
        /* parity == 1: probably 7-bit, odd parity? */
        /* parity == 2: probably 7-bit, even parity? */
        /* parity == 3: definitely 8 bit, no parity! */
-       /* Hmm... with any value of "parity" 8 bit, no parity is possible */
+       /* Hmm... with any value of parity "8 bit, no parity" is possible */
+#endif
 #ifdef HANDLE_ALLCAPS
        unsigned char capslock; /* upper case without lower case */
 #endif
@@ -126,9 +137,13 @@ struct chardata {
 /* Initial values for the above. */
 static const struct chardata init_chardata = {
        DEF_ERASE,                              /* default erase character */
+#ifdef ANCIENT_BS_KILL_CHARS
        DEF_KILL,                               /* default kill character */
+#endif
        13,                                     /* default eol char */
+#ifdef BROKEN_PARITY_DETECTION_CODE
        0,                                      /* space parity */
+#endif
 #ifdef HANDLE_ALLCAPS
        0,                                      /* no capslock */
 #endif
@@ -137,21 +152,23 @@ static const struct chardata init_chardata = {
 #define line_buf bb_common_bufsiz1
 
 //usage:#define getty_trivial_usage
-//usage:       "[OPTIONS] BAUD_RATE TTY [TERMTYPE]"
+//usage:       "[OPTIONS] BAUD_RATE[,BAUD_RATE]... TTY [TERMTYPE]"
 //usage:#define getty_full_usage "\n\n"
 //usage:       "Open a tty, prompt for a login name, then invoke /bin/login\n"
 //usage:     "\nOptions:"
 //usage:     "\n       -h              Enable hardware (RTS/CTS) flow control"
 //usage:     "\n       -i              Don't display /etc/issue"
-//usage:     "\n       -L              Local line, don't do carrier detect"
+//usage:     "\n       -L              Local line, set CLOCAL on it"
 //usage:     "\n       -m              Get baud rate from modem's CONNECT status message"
-//usage:     "\n       -w              Wait for CR or LF before sending /etc/issue"
-//usage:     "\n       -n              Don't prompt the user for a login name"
+//usage:     "\n       -w              Wait for CR or LF before sending /etc/issue"
+//usage:     "\n       -n              Don't prompt for a login name"
 //usage:     "\n       -f ISSUE_FILE   Display ISSUE_FILE instead of /etc/issue"
 //usage:     "\n       -l LOGIN        Invoke LOGIN instead of /bin/login"
 //usage:     "\n       -t SEC          Terminate after SEC if no username is read"
 //usage:     "\n       -I INITSTR      Send INITSTR before anything else"
 //usage:     "\n       -H HOST         Log HOST into the utmp file as the hostname"
+//usage:     "\n"
+//usage:     "\nBAUD_RATE of 0 leaves it unchanged"
 
 static const char opt_string[] ALIGN1 = "I:LH:f:hil:mt:wn";
 #define F_INITSTRING    (1 << 0)   /* -I */
@@ -259,29 +276,27 @@ static void open_tty(const char *tty)
 /* termios_init - initialize termios settings */
 static void termios_init(struct termios *tp, int speed)
 {
-       speed_t ispeed, ospeed;
+       /* Flush input and output queues, important for modems! */
+       /* TODO: sleep(1)? Users report lost chars, and I hesitate
+        * to use tcdrain here instead of tcflush */
+       tcflush(0, TCIOFLUSH);
+
+       /* Set speed if it wasn't specified as "0" on command line. */
+       if (speed != B0) {
+               cfsetispeed(tp, speed);
+               cfsetospeed(tp, speed);
+       }
        /*
         * Initial termios settings: 8-bit characters, raw-mode, blocking i/o.
         * Special characters are set after we have read the login name; all
         * reads will be done in raw mode anyway. Errors will be dealt with
         * later on.
         */
-       /* flush input and output queues, important for modems! */
-       tcflush(0, TCIOFLUSH);
-       ispeed = ospeed = speed;
-       if (speed == B0) {
-               /* Speed was specified as "0" on command line.
-                * Just leave it unchanged */
-               ispeed = cfgetispeed(tp);
-               ospeed = cfgetospeed(tp);
-       }
        tp->c_cflag = CS8 | HUPCL | CREAD;
        if (option_mask32 & F_LOCAL)
                tp->c_cflag |= CLOCAL;
-       cfsetispeed(tp, ispeed);
-       cfsetospeed(tp, ospeed);
-
-       tp->c_iflag = tp->c_lflag = 0;
+       tp->c_iflag = 0;
+       tp->c_lflag = 0;
        tp->c_oflag = OPOST | ONLCR;
        tp->c_cc[VMIN] = 1;
        tp->c_cc[VTIME] = 0;
@@ -388,14 +403,14 @@ static char *get_logname(char *logname, unsigned size_logname,
        char *bp;
        char c;                         /* input character, full eight bits */
        char ascval;                    /* low 7 bits of input character */
-       int bits;                       /* # of "1" bits per character */
-       int mask;                       /* mask with 1 bit up */
+#ifdef BROKEN_PARITY_DETECTION_CODE
        static const char erase[][3] = {/* backspace-space-backspace */
                "\010\040\010",                 /* space parity */
                "\010\040\010",                 /* odd parity */
                "\210\240\210",                 /* even parity */
                "\010\040\010",                 /* 8 bit no parity */
        };
+#endif
 
        /* NB: *cp is pre-initialized with init_chardata */
 
@@ -406,14 +421,13 @@ static char *get_logname(char *logname, unsigned size_logname,
        /* Prompt for and read a login name. */
        logname[0] = '\0';
        while (!logname[0]) {
-               /* Write issue file and prompt, with "parity" bit == 0. */
+               /* Write issue file and prompt. */
                do_prompt(op);
 
                /* Read name, watch for break, parity, erase, kill, end-of-line. */
                bp = logname;
                cp->eol = '\0';
-               while (cp->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) {
@@ -427,10 +441,11 @@ static char *get_logname(char *logname, unsigned size_logname,
                        if (c == '\0' && op->numspeed > 1)
                                return NULL;
 
+#ifdef BROKEN_PARITY_DETECTION_CODE
                        /* Do parity bit handling. */
-                       if (!(option_mask32 & F_LOCAL) && (c & 0x80)) {       /* "parity" bit on? */
-                               bits = 1;
-                               mask = 1;
+                       if (!(option_mask32 & F_LOCAL) && (c & 0x80)) { /* "parity" bit on? */
+                               int bits = 1;
+                               int mask = 1;
                                while (mask & 0x7f) {
                                        if (mask & c)
                                                bits++; /* count "1" bits */
@@ -439,15 +454,18 @@ static char *get_logname(char *logname, unsigned size_logname,
                                /* ... |= 2 - even, 1 - odd */
                                cp->parity |= 2 - (bits & 1);
                        }
+                       ascval = c & 0x7f;
+#else
+                       ascval = c;
+#endif
 
                        /* Do erase, kill and end-of-line processing. */
-                       ascval = c & 0x7f;
                        switch (ascval) {
                        case CR:
                        case NL:
                                *bp = '\0';             /* terminate logname */
                                cp->eol = ascval;       /* set end-of-line char */
-                               break;
+                               goto got_logname;
                        case BS:
                        case DEL:
 #ifdef ANCIENT_BS_KILL_CHARS
@@ -455,17 +473,25 @@ static char *get_logname(char *logname, unsigned size_logname,
 #endif
                                cp->erase = ascval;     /* set erase character */
                                if (bp > logname) {
+#ifdef BROKEN_PARITY_DETECTION_CODE
                                        full_write(STDOUT_FILENO, erase[cp->parity], 3);
+#else
+                                       full_write(STDOUT_FILENO, "\010 \010", 3);
+#endif
                                        bp--;
                                }
                                break;
                        case CTL('U'):
 #ifdef ANCIENT_BS_KILL_CHARS
                        case '@':
-#endif
                                cp->kill = ascval;      /* set kill character */
+#endif
                                while (bp > logname) {
+#ifdef BROKEN_PARITY_DETECTION_CODE
                                        full_write(STDOUT_FILENO, erase[cp->parity], 3);
+#else
+                                       full_write(STDOUT_FILENO, "\010 \010", 3);
+#endif
                                        bp--;
                                }
                                break;
@@ -474,19 +500,18 @@ static char *get_logname(char *logname, unsigned size_logname,
                        default:
                                if (ascval < ' ') {
                                        /* ignore garbage characters */
-                               } else if ((int)(bp - logname) >= size_logname - 1) {
-                                       bb_error_msg_and_die("input overrun");
-                               } else {
+                               } else if ((int)(bp - logname) < size_logname - 1) {
                                        full_write(STDOUT_FILENO, &c, 1); /* echo the character */
                                        *bp++ = ascval; /* and store it */
                                }
                                break;
                        }
-               }
-       }
-       /* Handle names with upper case and no lower case. */
+               } /* end of get char loop */
+ got_logname: ;
+       } /* while logname is empty */
 
 #ifdef HANDLE_ALLCAPS
+       /* Handle names with upper case and no lower case. */
        cp->capslock = all_is_upcase(logname);
        if (cp->capslock) {
                for (bp = logname; *bp; bp++)
@@ -520,8 +545,13 @@ static void termios_final(struct termios *tp, struct chardata *cp)
                tp->c_oflag |= ONLCR;   /* map NL in output to CR-NL */
        }
        tp->c_cc[VERASE] = cp->erase;   /* set erase character */
+#ifdef ANCIENT_BS_KILL_CHARS
        tp->c_cc[VKILL] = cp->kill;     /* set kill character */
+#else
+       tp->c_cc[VKILL] = DEF_KILL;     /* set kill character */
+#endif
 
+#ifdef BROKEN_PARITY_DETECTION_CODE
        /* Account for the presence or absence of parity bits in input. */
        switch (cp->parity) {
        case 0:                                 /* space (always 0) parity */
@@ -542,17 +572,19 @@ static void termios_final(struct termios *tp, struct chardata *cp)
 // Entire parity detection madness here just begs for deletion...
                break;
        }
+#endif
 
-       /* Account for upper case without lower case. */
 #ifdef HANDLE_ALLCAPS
+       /* Account for upper case without lower case. */
        if (cp->capslock) {
                tp->c_iflag |= IUCLC;
                tp->c_lflag |= XCASE;
                tp->c_oflag |= OLCUC;
        }
 #endif
-       /* Optionally enable hardware flow control */
+
 #ifdef CRTSCTS
+       /* Optionally enable hardware flow control */
        if (option_mask32 & F_RTSCTS)
                tp->c_cflag |= CRTSCTS;
 #endif
@@ -685,7 +717,7 @@ int getty_main(int argc UNUSED_PARAM, char **argv)
 
        logname = NULL;
        if (!(option_mask32 & F_NOPROMPT)) {
-               /* NB:termios_init already set line speed
+               /* NB: termios_init already set line speed
                 * to options.speeds[0] */
                int baud_index = 0;