ash: fix TMOUT not restoring tty attributes
authorDenys Vlasenko <vda.linux@googlemail.com>
Tue, 8 Feb 2011 04:07:02 +0000 (05:07 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 8 Feb 2011 04:07:02 +0000 (05:07 +0100)
function                                             old     new   delta
pgetc                                                420     500     +80
readtoken1                                          3202    3239     +37
read_line_input                                     3316    3337     +21
udhcpc_main                                         2610    2630     +20
file_get                                             266     272      +6
expandarg                                            958     963      +5
localcmd                                             257     259      +2
addLines                                              85      87      +2
read_line                                             94      95      +1
ed_main                                             2540    2541      +1
timed_out                                              1       -      -1
lineedit_read_key                                    256     255      -1
alrm_sighandler                                       44       -     -44
cmdloop                                              539     434    -105
------------------------------------------------------------------------------
(add/remove: 0/2 grow/shrink: 10/2 up/down: 175/-151)          Total: 24 bytes
   text    data     bss     dec     hex filename
 887379     936   17200  905515   dd12b busybox_old
 887411     936   17192  905539   dd143 busybox_unstripped

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
editors/ed.c
include/libbb.h
libbb/lineedit.c
shell/ash.c
shell/hush.c
util-linux/fdisk.c

index 8596684..b1b6a8d 100644 (file)
@@ -129,7 +129,7 @@ static void doCommands(void)
                 * 0  on ctrl-C,
                 * >0 length of input string, including terminating '\n'
                 */
-               len = read_line_input(": ", buf, sizeof(buf), NULL);
+               len = read_line_input(NULL, ": ", buf, sizeof(buf), /*timeout*/ -1);
                if (len <= 0)
                        return;
                endbuf = &buf[len - 1];
@@ -227,7 +227,7 @@ static void doCommands(void)
                        }
                        if (!dirty)
                                return;
-                       len = read_line_input("Really quit? ", buf, 16, NULL);
+                       len = read_line_input(NULL, "Really quit? ", buf, 16, /*timeout*/ -1);
                        /* read error/EOF - no way to continue */
                        if (len < 0)
                                return;
@@ -541,7 +541,7 @@ static void addLines(int num)
                 * 0  on ctrl-C,
                 * >0 length of input string, including terminating '\n'
                 */
-               len = read_line_input("", buf, sizeof(buf), NULL);
+               len = read_line_input(NULL, "", buf, sizeof(buf), /*timeout*/ -1);
                if (len <= 0) {
                        /* Previously, ctrl-C was exiting to shell.
                         * Now we exit to ed prompt. Is in important? */
index dd82e97..78b3906 100644 (file)
@@ -1403,12 +1403,11 @@ line_input_t *new_line_input_t(int flags) FAST_FUNC;
  * 0  on ctrl-C (the line entered is still returned in 'command'),
  * >0 length of input string, including terminating '\n'
  */
-/* NB: ash has timeout code which can be moved into read_line_input, if needed */
-int read_line_input(const char* prompt, char* command, int maxsize, line_input_t *state) FAST_FUNC;
+int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) FAST_FUNC;
 #else
 #define MAX_HISTORY 0
 int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC;
-#define read_line_input(prompt, command, maxsize, state) \
+#define read_line_input(state, prompt, command, maxsize, timeout) \
        read_line_input(prompt, command, maxsize)
 #endif
 
index 5dd835c..afd28b7 100644 (file)
@@ -1809,10 +1809,9 @@ static void win_changed(int nsig)
        errno = sv_errno;
 }
 
-static int lineedit_read_key(char *read_key_buffer)
+static int lineedit_read_key(char *read_key_buffer, int timeout)
 {
        int64_t ic;
-       int timeout = -1;
 #if ENABLE_UNICODE_SUPPORT
        char unicode_buf[MB_CUR_MAX + 1];
        int unicode_idx = 0;
@@ -1917,7 +1916,7 @@ static int isrtl_str(void)
  * 0  on ctrl-C (the line entered is still returned in 'command'),
  * >0 length of input string, including terminating '\n'
  */
-int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, line_input_t *st)
+int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout)
 {
        int len;
 #if ENABLE_FEATURE_TAB_COMPLETION
@@ -1991,7 +1990,6 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
        new_settings.c_cc[VINTR] = _POSIX_VDISABLE;
        tcsetattr_stdin_TCSANOW(&new_settings);
 
-       /* Now initialize things */
        previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
        win_changed(0); /* do initial resizing */
 #if ENABLE_USERNAME_OR_HOMEDIR
@@ -2033,7 +2031,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
                int32_t ic, ic_raw;
 
                fflush_all();
-               ic = ic_raw = lineedit_read_key(read_key_buffer);
+               ic = ic_raw = lineedit_read_key(read_key_buffer, timeout);
 
 #if ENABLE_FEATURE_EDITING_VI
                newdelflag = 1;
@@ -2194,7 +2192,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
                case 'd'|VI_CMDMODE_BIT: {
                        int nc, sc;
 
-                       ic = lineedit_read_key(read_key_buffer);
+                       ic = lineedit_read_key(read_key_buffer, timeout);
                        if (errno) /* error */
                                goto return_error_indicator;
                        if (ic == ic_raw) { /* "cc", "dd" */
@@ -2258,7 +2256,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
                        break;
                case 'r'|VI_CMDMODE_BIT:
 //FIXME: unicode case?
-                       ic = lineedit_read_key(read_key_buffer);
+                       ic = lineedit_read_key(read_key_buffer, timeout);
                        if (errno) /* error */
                                goto return_error_indicator;
                        if (ic < ' ' || ic > 255) {
index bdc6479..aaf21cd 100644 (file)
 //config:      default n
 //config:      depends on ASH
 //config:      help
-//config:        Enables bash-like auto-logout after "$TMOUT" seconds
-//config:        of idle time.
+//config:        Enables bash-like auto-logout after $TMOUT seconds of idle time.
 //config:
 //config:config ASH_JOB_CONTROL
 //config:      bool "Job control"
@@ -408,6 +407,9 @@ static const char *var_end(const char *var)
 
 
 /* ============ Interrupts / exceptions */
+
+static void exitshell(void) NORETURN;
+
 /*
  * These macros allow the user to suspend the handling of interrupt signals
  * over a period of time.  This is similar to SIGHOLD or to sigblock, but
@@ -9573,10 +9575,21 @@ preadfd(void)
        if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
                nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
        else {
+               int timeout = -1;
+# if ENABLE_ASH_IDLE_TIMEOUT
+               if (iflag) {
+                       const char *tmout_var = lookupvar("TMOUT");
+                       if (tmout_var) {
+                               timeout = atoi(tmout_var) * 1000;
+                               if (timeout <= 0)
+                                       timeout = -1;
+                       }
+               }
+# endif
 # if ENABLE_FEATURE_TAB_COMPLETION
                line_input_state->path_lookup = pathval();
 # endif
-               nr = read_line_input(cmdedit_prompt, buf, IBUFSIZ, line_input_state);
+               nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
                if (nr == 0) {
                        /* Ctrl+C pressed */
                        if (trap[SIGINT]) {
@@ -9587,9 +9600,17 @@ preadfd(void)
                        }
                        goto retry;
                }
-               if (nr < 0 && errno == 0) {
-                       /* Ctrl+D pressed */
-                       nr = 0;
+               if (nr < 0) {
+                       if (errno == 0) {
+                               /* Ctrl+D pressed */
+                               nr = 0;
+                       }
+# if ENABLE_ASH_IDLE_TIMEOUT
+                       else if (errno == EAGAIN && timeout > 0) {
+                               printf("\007timed out waiting for input: auto-logout\n");
+                               exitshell();
+                       }
+# endif
                }
        }
 #else
@@ -12056,23 +12077,6 @@ evalcmd(int argc UNUSED_PARAM, char **argv)
        return exitstatus;
 }
 
-#if ENABLE_ASH_IDLE_TIMEOUT
-static smallint timed_out;
-
-static void alrm_sighandler(int sig UNUSED_PARAM)
-{
-       /* Close stdin, making interactive command reading stop.
-        * Otherwise, timeout doesn't trigger until <Enter> is pressed.
-        */
-       int sv = errno;
-       close(0);
-       open("/dev/null", O_RDONLY);
-       errno = sv;
-
-       timed_out = 1;
-}
-#endif
-
 /*
  * Read and execute commands.
  * "Top" is nonzero for the top level command loop;
@@ -12089,20 +12093,6 @@ cmdloop(int top)
        TRACE(("cmdloop(%d) called\n", top));
        for (;;) {
                int skip;
-#if ENABLE_ASH_IDLE_TIMEOUT
-               int tmout_seconds = 0;
-
-               if (top && iflag) {
-                       const char *tmout_var = lookupvar("TMOUT");
-                       if (tmout_var) {
-                               tmout_seconds = atoi(tmout_var);
-                               if (tmout_seconds > 0) {
-                                       signal(SIGALRM, alrm_sighandler);
-                                       alarm(tmout_seconds);
-                               }
-                       }
-               }
-#endif
 
                setstackmark(&smark);
 #if JOBS
@@ -12115,14 +12105,6 @@ cmdloop(int top)
                        chkmail();
                }
                n = parsecmd(inter);
-#if ENABLE_ASH_IDLE_TIMEOUT
-               if (timed_out) {
-                       printf("\007timed out waiting for input: auto-logout\n");
-                       break;
-               }
-               if (tmout_seconds > 0)
-                       alarm(0);
-#endif
 #if DEBUG
                if (DEBUG > 2 && debug && (n != NODE_EOF))
                        showtree(n);
@@ -12850,7 +12832,6 @@ ulimitcmd(int argc UNUSED_PARAM, char **argv)
 /*
  * Called to exit the shell.
  */
-static void exitshell(void) NORETURN;
 static void
 exitshell(void)
 {
index e857e74..00ef361 100644 (file)
@@ -1902,7 +1902,7 @@ static void get_user_input(struct in_str *i)
                G.flag_SIGINT = 0;
                /* buglet: SIGINT will not make new prompt to appear _at once_,
                 * only after <Enter>. (^C will work) */
-               r = read_line_input(prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, G.line_input_state);
+               r = read_line_input(G.line_input_state, prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, /*timeout*/ -1);
                /* catch *SIGINT* etc (^C is handled by read_line_input) */
                check_and_run_traps(0);
        } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */
index 02785ab..0b93c22 100644 (file)
@@ -548,7 +548,7 @@ read_line(const char *prompt)
 {
        int sz;
 
-       sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL);
+       sz = read_line_input(NULL, prompt, line_buffer, sizeof(line_buffer), /*timeout*/ -1);
        if (sz <= 0)
                exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */