ash: fix TMOUT not restoring tty attributes

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>
This commit is contained in:
Denys Vlasenko 2011-02-08 05:07:02 +01:00
parent dd807c16f9
commit 66c5b12dbf
6 changed files with 39 additions and 61 deletions

View File

@ -129,7 +129,7 @@ static void doCommands(void)
* 0 on ctrl-C, * 0 on ctrl-C,
* >0 length of input string, including terminating '\n' * >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) if (len <= 0)
return; return;
endbuf = &buf[len - 1]; endbuf = &buf[len - 1];
@ -227,7 +227,7 @@ static void doCommands(void)
} }
if (!dirty) if (!dirty)
return; 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 */ /* read error/EOF - no way to continue */
if (len < 0) if (len < 0)
return; return;
@ -541,7 +541,7 @@ static void addLines(int num)
* 0 on ctrl-C, * 0 on ctrl-C,
* >0 length of input string, including terminating '\n' * >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) { if (len <= 0) {
/* Previously, ctrl-C was exiting to shell. /* Previously, ctrl-C was exiting to shell.
* Now we exit to ed prompt. Is in important? */ * Now we exit to ed prompt. Is in important? */

View 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 on ctrl-C (the line entered is still returned in 'command'),
* >0 length of input string, including terminating '\n' * >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(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) FAST_FUNC;
int read_line_input(const char* prompt, char* command, int maxsize, line_input_t *state) FAST_FUNC;
#else #else
#define MAX_HISTORY 0 #define MAX_HISTORY 0
int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC; 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) read_line_input(prompt, command, maxsize)
#endif #endif

View File

@ -1809,10 +1809,9 @@ static void win_changed(int nsig)
errno = sv_errno; 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; int64_t ic;
int timeout = -1;
#if ENABLE_UNICODE_SUPPORT #if ENABLE_UNICODE_SUPPORT
char unicode_buf[MB_CUR_MAX + 1]; char unicode_buf[MB_CUR_MAX + 1];
int unicode_idx = 0; 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 on ctrl-C (the line entered is still returned in 'command'),
* >0 length of input string, including terminating '\n' * >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; int len;
#if ENABLE_FEATURE_TAB_COMPLETION #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; new_settings.c_cc[VINTR] = _POSIX_VDISABLE;
tcsetattr_stdin_TCSANOW(&new_settings); tcsetattr_stdin_TCSANOW(&new_settings);
/* Now initialize things */
previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
win_changed(0); /* do initial resizing */ win_changed(0); /* do initial resizing */
#if ENABLE_USERNAME_OR_HOMEDIR #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; int32_t ic, ic_raw;
fflush_all(); 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 #if ENABLE_FEATURE_EDITING_VI
newdelflag = 1; 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: { case 'd'|VI_CMDMODE_BIT: {
int nc, sc; int nc, sc;
ic = lineedit_read_key(read_key_buffer); ic = lineedit_read_key(read_key_buffer, timeout);
if (errno) /* error */ if (errno) /* error */
goto return_error_indicator; goto return_error_indicator;
if (ic == ic_raw) { /* "cc", "dd" */ 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; break;
case 'r'|VI_CMDMODE_BIT: case 'r'|VI_CMDMODE_BIT:
//FIXME: unicode case? //FIXME: unicode case?
ic = lineedit_read_key(read_key_buffer); ic = lineedit_read_key(read_key_buffer, timeout);
if (errno) /* error */ if (errno) /* error */
goto return_error_indicator; goto return_error_indicator;
if (ic < ' ' || ic > 255) { if (ic < ' ' || ic > 255) {

View File

@ -102,8 +102,7 @@
//config: default n //config: default n
//config: depends on ASH //config: depends on ASH
//config: help //config: help
//config: Enables bash-like auto-logout after "$TMOUT" seconds //config: Enables bash-like auto-logout after $TMOUT seconds of idle time.
//config: of idle time.
//config: //config:
//config:config ASH_JOB_CONTROL //config:config ASH_JOB_CONTROL
//config: bool "Job control" //config: bool "Job control"
@ -408,6 +407,9 @@ static const char *var_end(const char *var)
/* ============ Interrupts / exceptions */ /* ============ Interrupts / exceptions */
static void exitshell(void) NORETURN;
/* /*
* These macros allow the user to suspend the handling of interrupt signals * 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 * 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) if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
else { 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 # if ENABLE_FEATURE_TAB_COMPLETION
line_input_state->path_lookup = pathval(); line_input_state->path_lookup = pathval();
# endif # 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) { if (nr == 0) {
/* Ctrl+C pressed */ /* Ctrl+C pressed */
if (trap[SIGINT]) { if (trap[SIGINT]) {
@ -9587,9 +9600,17 @@ preadfd(void)
} }
goto retry; goto retry;
} }
if (nr < 0 && errno == 0) { if (nr < 0) {
/* Ctrl+D pressed */ if (errno == 0) {
nr = 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 #else
@ -12056,23 +12077,6 @@ evalcmd(int argc UNUSED_PARAM, char **argv)
return exitstatus; 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. * Read and execute commands.
* "Top" is nonzero for the top level command loop; * "Top" is nonzero for the top level command loop;
@ -12089,20 +12093,6 @@ cmdloop(int top)
TRACE(("cmdloop(%d) called\n", top)); TRACE(("cmdloop(%d) called\n", top));
for (;;) { for (;;) {
int skip; 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); setstackmark(&smark);
#if JOBS #if JOBS
@ -12115,14 +12105,6 @@ cmdloop(int top)
chkmail(); chkmail();
} }
n = parsecmd(inter); 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
if (DEBUG > 2 && debug && (n != NODE_EOF)) if (DEBUG > 2 && debug && (n != NODE_EOF))
showtree(n); showtree(n);
@ -12850,7 +12832,6 @@ ulimitcmd(int argc UNUSED_PARAM, char **argv)
/* /*
* Called to exit the shell. * Called to exit the shell.
*/ */
static void exitshell(void) NORETURN;
static void static void
exitshell(void) exitshell(void)
{ {

View File

@ -1902,7 +1902,7 @@ static void get_user_input(struct in_str *i)
G.flag_SIGINT = 0; G.flag_SIGINT = 0;
/* buglet: SIGINT will not make new prompt to appear _at once_, /* buglet: SIGINT will not make new prompt to appear _at once_,
* only after <Enter>. (^C will work) */ * 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) */ /* catch *SIGINT* etc (^C is handled by read_line_input) */
check_and_run_traps(0); check_and_run_traps(0);
} while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */ } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */

View File

@ -548,7 +548,7 @@ read_line(const char *prompt)
{ {
int sz; 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) if (sz <= 0)
exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */ exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */