From b72baeb00328576df415f9a4b4f3d5f202e3be11 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 2 Feb 2011 18:38:57 +0100 Subject: hush: use FEATURE_SH_NOFORK to enable NOFORK trick Also expands docs Signed-off-by: Denys Vlasenko --- shell/Config.src | 9 +++++---- shell/hush.c | 11 +++++------ 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'shell') diff --git a/shell/Config.src b/shell/Config.src index c9c2439e7..e96c21620 100644 --- a/shell/Config.src +++ b/shell/Config.src @@ -123,9 +123,9 @@ config FEATURE_SH_NOFORK default n depends on (HUSH || ASH) && FEATURE_PREFER_APPLETS help - This option causes busybox shells [currently only ash] - to not execute typical fork/exec/wait sequence, but call _main - directly, if possible. (Sometimes it is not possible: for example, + This option causes busybox shells to not execute typical + fork/exec/wait sequence, but call _main directly, + if possible. (Sometimes it is not possible: for example, this is not possible in pipes). This will be done only for some applets (those which are marked @@ -133,6 +133,7 @@ config FEATURE_SH_NOFORK This may significantly speed up some shell scripts. - This feature is relatively new. Use with care. + This feature is relatively new. Use with care. Report bugs + to project mailing list. endmenu diff --git a/shell/hush.c b/shell/hush.c index 1709fd9d1..10788b8e7 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -6615,7 +6615,7 @@ static int checkjobs_and_fg_shell(struct pipe *fg_pipe) * cmd ; ... { list } ; ... * cmd && ... { list } && ... * cmd || ... { list } || ... - * If it is, then we can run cmd as a builtin, NOFORK [do we do this?], + * If it is, then we can run cmd as a builtin, NOFORK, * or (if SH_STANDALONE) an applet, and we can run the { list } * with run_list. If it isn't one of these, we fork and exec cmd. * @@ -6797,13 +6797,12 @@ static NOINLINE int run_pipe(struct pipe *pi) } /* Expand the rest into (possibly) many strings each */ - if (0) {} #if ENABLE_HUSH_BASH_COMPAT - else if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) { + if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) { argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); - } + } else #endif - else { + { argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt); } @@ -6865,7 +6864,7 @@ static NOINLINE int run_pipe(struct pipe *pi) return rcode; } - if (ENABLE_FEATURE_SH_STANDALONE) { + if (ENABLE_FEATURE_SH_NOFORK) { int n = find_applet_by_name(argv_expanded[0]); if (n >= 0 && APPLET_IS_NOFORK(n)) { rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, squirrel, argv_expanded); -- cgit v1.2.3-55-g6feb From b7c9fb27cba3d697e602f8cbf88cde135d8d6c5e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 3 Feb 2011 00:05:48 +0100 Subject: whitespace fixes Signed-off-by: Denys Vlasenko --- applets/usage_pod.c | 4 ++-- archival/lzop.c | 2 +- e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c | 4 ++-- editors/sed.c | 2 +- libbb/crc32.c | 2 +- libbb/getopt32.c | 8 ++++---- loginutils/getty.c | 2 +- modutils/modprobe.c | 2 +- networking/httpd_ssi.c | 4 ++-- networking/ntpd.c | 2 +- procps/pstree.c | 2 +- shell/shell_common.c | 6 +++--- util-linux/flock.c | 2 +- 13 files changed, 21 insertions(+), 21 deletions(-) (limited to 'shell') diff --git a/applets/usage_pod.c b/applets/usage_pod.c index da0baefc6..0b1c4aadb 100644 --- a/applets/usage_pod.c +++ b/applets/usage_pod.c @@ -31,8 +31,8 @@ #include "usage.h" #define MAKE_USAGE(aname, usage) { aname, usage }, static struct usage_data { - const char *aname; - const char *usage; + const char *aname; + const char *usage; } usage_array[] = { #include "applets.h" }; diff --git a/archival/lzop.c b/archival/lzop.c index 094e78cf9..62455c313 100644 --- a/archival/lzop.c +++ b/archival/lzop.c @@ -401,7 +401,7 @@ struct globals { #define INIT_G() do { } while (0) //#define G (*ptr_to_globals) //#define INIT_G() do { -// SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); +// SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); //} while (0) diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c b/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c index b9aab440a..7d37d232d 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c @@ -155,8 +155,8 @@ int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino) blk_t ext2fs_inode_data_blocks(ext2_filsys fs, struct ext2_inode *inode) { - return inode->i_blocks - - (inode->i_file_acl ? fs->blocksize >> 9 : 0); + return inode->i_blocks - + (inode->i_file_acl ? fs->blocksize >> 9 : 0); } diff --git a/editors/sed.c b/editors/sed.c index b91acfb7f..d3555243f 100644 --- a/editors/sed.c +++ b/editors/sed.c @@ -124,7 +124,7 @@ struct globals { } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) struct BUG_G_too_big { - char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; + char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; }; #define INIT_G() do { \ G.sed_cmd_tail = &G.sed_cmd_head; \ diff --git a/libbb/crc32.c b/libbb/crc32.c index c63bf0772..ac9836cc9 100644 --- a/libbb/crc32.c +++ b/libbb/crc32.c @@ -59,7 +59,7 @@ uint32_t FAST_FUNC crc32_block_endian0(uint32_t val, const void *buf, unsigned l const void *end = (uint8_t*)buf + len; while (buf != end) { - val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8); + val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8); buf = (uint8_t*)buf + 1; } return val; diff --git a/libbb/getopt32.c b/libbb/getopt32.c index abd412043..f3f1cfcba 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c @@ -80,9 +80,9 @@ const char *applet_long_options This struct allows you to define long options: static const char applet_longopts[] ALIGN1 = - //"name\0" has_arg val - "verbose\0" No_argument "v" - ; + //"name\0" has_arg val + "verbose\0" No_argument "v" + ; applet_long_options = applet_longopts; The last member of struct option (val) typically is set to @@ -226,7 +226,7 @@ Special characters: if specified together. In this case you must set opt_complementary = "b--cf:c--bf:f--bc". If two of the mutually exclusive options are found, getopt32 will call - bb_show_usage() and die. + bb_show_usage() and die. "x--x" Variation of the above, it means that -x option should occur at most once. diff --git a/loginutils/getty.c b/loginutils/getty.c index 34f72c465..3f20c8e81 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c @@ -334,7 +334,7 @@ static void termios_final(void) * IMAXBEL Echo BEL on input line too long * IUTF8 Appears to affect tty's idea of char widths, * observed to improve backspacing through Unicode chars - */ + */ /* line buffered input (NL or EOL or EOF chars end a line); * recognize INT/QUIT/SUSP chars; diff --git a/modutils/modprobe.c b/modutils/modprobe.c index 8d2ccc562..0d28da7ea 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c @@ -170,7 +170,7 @@ struct globals { #define G (*(struct globals*)&bb_common_bufsiz1) #define INIT_G() do { } while (0) struct BUG_G_too_big { - char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; + char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; }; diff --git a/networking/httpd_ssi.c b/networking/httpd_ssi.c index 87f43fcfa..cfe64eb46 100644 --- a/networking/httpd_ssi.c +++ b/networking/httpd_ssi.c @@ -52,9 +52,9 @@ httpd_ssi.c -o httpd_ssi static char* skip_whitespace(char *s) { - while (*s == ' ' || *s == '\t') ++s; + while (*s == ' ' || *s == '\t') ++s; - return s; + return s; } static char line[64 * 1024]; diff --git a/networking/ntpd.c b/networking/ntpd.c index 8fe529edb..3ed05ba29 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -882,7 +882,7 @@ fit(peer_t *p, double rd) // /* Do we have a loop? */ // if (p->refid == p->dstaddr || p->refid == s.refid) // return 0; - return 1; + return 1; } static peer_t* select_and_cluster(void) diff --git a/procps/pstree.c b/procps/pstree.c index ddf5dba59..4cd8cb458 100644 --- a/procps/pstree.c +++ b/procps/pstree.c @@ -76,7 +76,7 @@ struct globals { }; #define G (*ptr_to_globals) #define INIT_G() do { \ - SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ } while (0) diff --git a/shell/shell_common.c b/shell/shell_common.c index e9effd2d0..f02ed81ea 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c @@ -368,9 +368,9 @@ shell_builtin_ulimit(char **argv) #endif /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */ - argc = 1; - while (argv[argc]) - argc++; + argc = 1; + while (argv[argc]) + argc++; opts = 0; while (1) { diff --git a/util-linux/flock.c b/util-linux/flock.c index be3d552fa..77fe1f809 100644 --- a/util-linux/flock.c +++ b/util-linux/flock.c @@ -19,7 +19,7 @@ int flock_main(int argc UNUSED_PARAM, char **argv) }; #if ENABLE_LONG_OPTS - static const char getopt_longopts[] ALIGN1 = + static const char getopt_longopts[] ALIGN1 = "shared\0" No_argument "s" "exclusive\0" No_argument "x" "unlock\0" No_argument "u" -- cgit v1.2.3-55-g6feb From 8c52f803976c79812a75b9317107cc0a8fb94c7f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Feb 2011 17:36:21 +0100 Subject: ash: cosmetic cleanups Signed-off-by: Denys Vlasenko --- shell/ash.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 0bcbf9028..0e27a073c 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -105,7 +105,7 @@ //config: Enable job control in the ash shell. //config: //config:config ASH_ALIAS -//config: bool "alias support" +//config: bool "Alias support" //config: default y //config: depends on ASH //config: help @@ -116,28 +116,28 @@ //config: default y //config: depends on ASH //config: help -//config: Enable getopts builtin in the ash shell. +//config: Enable support for getopts builtin in ash. //config: //config:config ASH_BUILTIN_ECHO //config: bool "Builtin version of 'echo'" //config: default y //config: depends on ASH //config: help -//config: Enable support for echo, builtin to ash. +//config: Enable support for echo builtin in ash. //config: //config:config ASH_BUILTIN_PRINTF //config: bool "Builtin version of 'printf'" //config: default y //config: depends on ASH //config: help -//config: Enable support for printf, builtin to ash. +//config: Enable support for printf builtin in ash. //config: //config:config ASH_BUILTIN_TEST //config: bool "Builtin version of 'test'" //config: default y //config: depends on ASH //config: help -//config: Enable support for test, builtin to ash. +//config: Enable support for test builtin in ash. //config: //config:config ASH_CMDCMD //config: bool "'command' command to override shell builtins" @@ -153,7 +153,7 @@ //config: default n //config: depends on ASH //config: help -//config: Enable "check for new mail" in the ash shell. +//config: Enable "check for new mail" function in the ash shell. //config: //config:config ASH_OPTIMIZE_FOR_SIZE //config: bool "Optimize for size instead of speed" @@ -1880,7 +1880,9 @@ change_lc_ctype(const char *value) #endif #if ENABLE_ASH_MAIL static void chkmail(void); -static void changemail(const char *) FAST_FUNC; +static void changemail(const char *var_value) FAST_FUNC; +#else +# define chkmail() ((void)0) #endif static void changepath(const char *) FAST_FUNC; #if ENABLE_ASH_RANDOM_SUPPORT @@ -9563,9 +9565,9 @@ preadfd(void) if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); else { -#if ENABLE_FEATURE_TAB_COMPLETION +# if ENABLE_FEATURE_TAB_COMPLETION line_input_state->path_lookup = pathval(); -#endif +# endif nr = read_line_input(cmdedit_prompt, buf, IBUFSIZ, line_input_state); if (nr == 0) { /* Ctrl+C pressed */ @@ -9586,8 +9588,7 @@ preadfd(void) nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); #endif -#if 0 -/* nonblock_safe_read() handles this problem */ +#if 0 /* disabled: nonblock_safe_read() handles this problem */ if (nr < 0) { if (parsefile->fd == 0 && errno == EWOULDBLOCK) { int flags = fcntl(0, F_GETFL); @@ -12072,9 +12073,7 @@ cmdloop(int top) inter = 0; if (iflag && top) { inter++; -#if ENABLE_ASH_MAIL chkmail(); -#endif } n = parsecmd(inter); #if DEBUG -- cgit v1.2.3-55-g6feb From 046341e8bd91a2a2c0d44b40217fa1c5ce1dd949 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Feb 2011 17:53:59 +0100 Subject: ash: optional support for $TMOUT variable Signed-off-by: Denys Vlasenko --- include/libbb.h | 4 +++- shell/ash.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) (limited to 'shell') diff --git a/include/libbb.h b/include/libbb.h index a0e23697c..6358e654a 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1393,12 +1393,14 @@ enum { }; line_input_t *new_line_input_t(int flags) FAST_FUNC; /* So far static: void free_line_input_t(line_input_t *n) FAST_FUNC; */ -/* maxsize must be >= 2. +/* + * maxsize must be >= 2. * Returns: * -1 on read errors or EOF, or on bare Ctrl-D, * 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; #else #define MAX_HISTORY 0 diff --git a/shell/ash.c b/shell/ash.c index 0e27a073c..bdc64790c 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -97,6 +97,14 @@ //config: help //config: Enable bash-compatible extensions. //config: +//config:config ASH_IDLE_TIMEOUT +//config: bool "Idle timeout variable" +//config: default n +//config: depends on ASH +//config: help +//config: Enables bash-like auto-logout after "$TMOUT" seconds +//config: of idle time. +//config: //config:config ASH_JOB_CONTROL //config: bool "Job control" //config: default y @@ -12048,6 +12056,23 @@ 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 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; @@ -12064,6 +12089,20 @@ 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 @@ -12076,6 +12115,14 @@ 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); -- cgit v1.2.3-55-g6feb From 8ee2adab21328761b80e0cbc513eda7eaa880b24 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Feb 2011 02:03:51 +0100 Subject: echo: do not retry on write errors function old new delta echo_main 297 336 +39 stpcpy - 22 +22 run_pipe 1561 1566 +5 pseudo_exec_argv 187 192 +5 hush_exit 75 80 +5 ------------------------------------------------------------------------------ (add/remove: 3/0 grow/shrink: 4/0 up/down: 98/0) Total: 76 bytes Signed-off-by: Denys Vlasenko --- coreutils/echo.c | 87 +++++++++++++----------- shell/ash_test/ash-misc/echo_write_error.right | 2 + shell/ash_test/ash-misc/echo_write_error.tests | 7 ++ shell/ash_test/ash-redir/redir.right | 1 + shell/hush.c | 8 ++- shell/hush_test/hush-misc/echo_write_error.right | 2 + shell/hush_test/hush-misc/echo_write_error.tests | 7 ++ 7 files changed, 74 insertions(+), 40 deletions(-) create mode 100644 shell/ash_test/ash-misc/echo_write_error.right create mode 100644 shell/ash_test/ash-misc/echo_write_error.tests create mode 100644 shell/hush_test/hush-misc/echo_write_error.right create mode 100755 shell/hush_test/hush-misc/echo_write_error.tests (limited to 'shell') diff --git a/coreutils/echo.c b/coreutils/echo.c index 3821e594e..5fa3d10c5 100644 --- a/coreutils/echo.c +++ b/coreutils/echo.c @@ -29,46 +29,42 @@ /* NB: can be used by shell even if not enabled as applet */ +/* + * NB2: we don't use stdio, we need better error handing. + * Examples include writing into non-opened stdout and error on write. + * + * With stdio, output gets shoveled into stdout buffer, and even + * fflush cannot clear it out. It seems that even if libc receives + * EBADF on write attempts, it feels determined to output data no matter what. + * If echo is called by shell, it will try writing again later, and possibly + * will clobber future output. Not good. + * + * Solaris has fpurge which discards buffered input. glibc has __fpurge. + * But this function is not standard. + */ + int echo_main(int argc UNUSED_PARAM, char **argv) { + char **pp; const char *arg; + char *out; + char *buffer; + unsigned buflen; + int r; #if !ENABLE_FEATURE_FANCY_ECHO enum { eflag = '\\', nflag = 1, /* 1 -- print '\n' */ }; - /* We must check that stdout is not closed. - * The reason for this is highly non-obvious. - * echo_main is used from shell. Shell must correctly handle "echo foo" - * if stdout is closed. With stdio, output gets shoveled into - * stdout buffer, and even fflush cannot clear it out. It seems that - * even if libc receives EBADF on write attempts, it feels determined - * to output data no matter what. So it will try later, - * and possibly will clobber future output. Not good. */ -// TODO: check fcntl() & O_ACCMODE == O_WRONLY or O_RDWR? - if (fcntl(1, F_GETFL) == -1) - return 1; /* match coreutils 6.10 (sans error msg to stderr) */ - //if (dup2(1, 1) != 1) - old way - // return 1; - - arg = *++argv; - if (!arg) - goto newline_ret; + argv++; #else const char *p; char nflag = 1; char eflag = 0; - /* We must check that stdout is not closed. */ - if (fcntl(1, F_GETFL) == -1) - return 1; - - while (1) { - arg = *++argv; - if (!arg) - goto newline_ret; - if (*arg != '-') + while ((arg = *++argv) != NULL) { + if (!arg || arg[0] != '-') break; /* If it appears that we are handling options, then make sure @@ -77,7 +73,7 @@ int echo_main(int argc UNUSED_PARAM, char **argv) */ p = arg + 1; if (!*p) /* A single '-', so echo it. */ - goto just_echo; + break; do { if (!strrchr("neE", *p)) @@ -95,19 +91,27 @@ int echo_main(int argc UNUSED_PARAM, char **argv) } just_echo: #endif - while (1) { - /* arg is already == *argv and isn't NULL */ + + buflen = 1; + pp = argv; + while ((arg = *pp) != NULL) { + buflen += strlen(arg) + 1; + pp++; + } + out = buffer = xmalloc(buflen); + + while ((arg = *argv) != NULL) { int c; if (!eflag) { /* optimization for very common case */ - fputs(arg, stdout); + out = stpcpy(out, arg); } else while ((c = *arg++)) { if (c == eflag) { /* Check for escape seq. */ if (*arg == 'c') { /* '\c' means cancel newline and * ignore all subsequent chars. */ - goto ret; + goto do_write; } #if !ENABLE_FEATURE_FANCY_ECHO /* SUSv3 specifies that octal escapes must begin with '0'. */ @@ -127,21 +131,26 @@ int echo_main(int argc UNUSED_PARAM, char **argv) c = bb_process_escape_sequence(&arg); } } - bb_putchar(c); + *out++ = c; } - arg = *++argv; - if (!arg) + if (!*++argv) break; - bb_putchar(' '); + *out++ = ' '; } - newline_ret: if (nflag) { - bb_putchar('\n'); + *out++ = '\n'; } - ret: - return fflush_all(); + + do_write: + r = full_write(STDOUT_FILENO, buffer, out - buffer); + free(buffer); + if (r < 0) { + bb_perror_msg(bb_msg_write_error); + return 1; + } + return 0; } /*- diff --git a/shell/ash_test/ash-misc/echo_write_error.right b/shell/ash_test/ash-misc/echo_write_error.right new file mode 100644 index 000000000..3e91a13d3 --- /dev/null +++ b/shell/ash_test/ash-misc/echo_write_error.right @@ -0,0 +1,2 @@ +ash: write error: Broken pipe +Ok: 1 diff --git a/shell/ash_test/ash-misc/echo_write_error.tests b/shell/ash_test/ash-misc/echo_write_error.tests new file mode 100644 index 000000000..0a40c9ff7 --- /dev/null +++ b/shell/ash_test/ash-misc/echo_write_error.tests @@ -0,0 +1,7 @@ +trap "" PIPE + +{ +sleep 1 +echo Cant write this - get EPIPE +echo Ok: $? >&2 +} | { true; } diff --git a/shell/ash_test/ash-redir/redir.right b/shell/ash_test/ash-redir/redir.right index 2a02d41ce..c1a6e729a 100644 --- a/shell/ash_test/ash-redir/redir.right +++ b/shell/ash_test/ash-redir/redir.right @@ -1 +1,2 @@ +ash: write error: Bad file descriptor TEST diff --git a/shell/hush.c b/shell/hush.c index 10788b8e7..e857e7464 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -1418,6 +1418,7 @@ static void sigexit(int sig) static void hush_exit(int exitcode) NORETURN; static void hush_exit(int exitcode) { + fflush_all(); if (G.exiting <= 0 && G.traps && G.traps[0] && G.traps[0][0]) { /* Prevent recursion: * trap "echo Hi; exit" EXIT; exit @@ -6105,10 +6106,13 @@ static void exec_builtin(char ***to_free, char **argv) { #if BB_MMU - int rcode = x->b_function(argv); + int rcode; + fflush_all(); + rcode = x->b_function(argv); fflush_all(); _exit(rcode); #else + fflush_all(); /* On NOMMU, we must never block! * Example: { sleep 99 | read line; } & echo Ok */ @@ -6832,6 +6836,7 @@ static NOINLINE int run_pipe(struct pipe *pi) if (!funcp) { debug_printf_exec(": builtin '%s' '%s'...\n", x->b_cmd, argv_expanded[1]); + fflush_all(); rcode = x->b_function(argv_expanded) & 0xff; fflush_all(); } @@ -7641,6 +7646,7 @@ int hush_main(int argc, char **argv) G.global_argc -= builtin_argc; /* skip [BARGV...] "" */ G.global_argv += builtin_argc; G.global_argv[-1] = NULL; /* replace "" */ + fflush_all(); G.last_exitcode = x->b_function(argv + optind - 1); } goto final_return; diff --git a/shell/hush_test/hush-misc/echo_write_error.right b/shell/hush_test/hush-misc/echo_write_error.right new file mode 100644 index 000000000..ddcad4363 --- /dev/null +++ b/shell/hush_test/hush-misc/echo_write_error.right @@ -0,0 +1,2 @@ +hush: write error: Broken pipe +Ok: 1 diff --git a/shell/hush_test/hush-misc/echo_write_error.tests b/shell/hush_test/hush-misc/echo_write_error.tests new file mode 100755 index 000000000..0a40c9ff7 --- /dev/null +++ b/shell/hush_test/hush-misc/echo_write_error.tests @@ -0,0 +1,7 @@ +trap "" PIPE + +{ +sleep 1 +echo Cant write this - get EPIPE +echo Ok: $? >&2 +} | { true; } -- cgit v1.2.3-55-g6feb From 66c5b12dbf85142eea257ba6047191d7c0ee43f3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 8 Feb 2011 05:07:02 +0100 Subject: 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 --- editors/ed.c | 6 ++--- include/libbb.h | 5 ++-- libbb/lineedit.c | 12 ++++----- shell/ash.c | 73 ++++++++++++++++++++---------------------------------- shell/hush.c | 2 +- util-linux/fdisk.c | 2 +- 6 files changed, 39 insertions(+), 61 deletions(-) (limited to 'shell') diff --git a/editors/ed.c b/editors/ed.c index 859668406..b1b6a8d27 100644 --- a/editors/ed.c +++ b/editors/ed.c @@ -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? */ diff --git a/include/libbb.h b/include/libbb.h index dd82e9754..78b390611 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -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 diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 5dd835cca..afd28b75c 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -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) { diff --git a/shell/ash.c b/shell/ash.c index bdc64790c..aaf21cd6f 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -102,8 +102,7 @@ //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 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) { diff --git a/shell/hush.c b/shell/hush.c index e857e7464..00ef361cd 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -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 . (^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 */ diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index 02785ab85..0b93c22cc 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c @@ -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 */ -- cgit v1.2.3-55-g6feb From 7c6f2468ccc849c9f8401ee97a3d894d8f483773 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 14 Feb 2011 17:17:10 +0100 Subject: hush: do not print killer signal's name for SIGPIPE Signed-off-by: Denys Vlasenko --- shell/ash.c | 1 + shell/hush.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index aaf21cd6f..cccd6dd79 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -3892,6 +3892,7 @@ sprint_status(char *s, int status, int sigonly) #endif } st &= 0x7f; +//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata col = fmtstr(s, 32, strsignal(st)); if (WCOREDUMP(status)) { col += fmtstr(s + col, 16, " (core dumped)"); diff --git a/shell/hush.c b/shell/hush.c index 00ef361cd..4d9e5f8c7 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -6504,13 +6504,15 @@ static int checkjobs(struct pipe *fg_pipe) fg_pipe->alive_cmds--; ex = WEXITSTATUS(status); /* bash prints killer signal's name for *last* - * process in pipe (prints just newline for SIGINT). + * process in pipe (prints just newline for SIGINT/SIGPIPE). * Mimic this. Example: "sleep 5" + (^\ or kill -QUIT) */ if (WIFSIGNALED(status)) { int sig = WTERMSIG(status); if (i == fg_pipe->num_cmds-1) - printf("%s\n", sig == SIGINT ? "" : get_signame(sig)); + /* TODO: use strsignal() instead for bash compat? but that's bloat... */ + printf("%s\n", sig == SIGINT || sig == SIGPIPE ? "" : get_signame(sig)); + /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */ /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? * Maybe we need to use sig | 128? */ ex = sig + 128; -- cgit v1.2.3-55-g6feb From b12553faa8991e11c11f70a81f1d9d44078c7645 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 21 Feb 2011 03:22:20 +0100 Subject: ash: fix ash-signals/signal8 testcase failure function old new delta killcmd 109 224 +115 kill_main 882 910 +28 changepath 194 195 +1 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 144/0) Total: 144 bytes Signed-off-by: Denys Vlasenko --- procps/kill.c | 25 ++++++++++++-- shell/ash.c | 58 +++++++++++++++++++++++++------- shell/ash_test/ash-signals/sigint1.right | 1 + shell/ash_test/ash-signals/sigint1.tests | 41 ++++++++++++++++++++++ shell/hush_test/hush-misc/sigint1.right | 1 + shell/hush_test/hush-misc/sigint1.tests | 41 ++++++++++++++++++++++ 6 files changed, 152 insertions(+), 15 deletions(-) create mode 100644 shell/ash_test/ash-signals/sigint1.right create mode 100755 shell/ash_test/ash-signals/sigint1.tests create mode 100644 shell/hush_test/hush-misc/sigint1.right create mode 100755 shell/hush_test/hush-misc/sigint1.tests (limited to 'shell') diff --git a/procps/kill.c b/procps/kill.c index b51d44a70..39538016e 100644 --- a/procps/kill.c +++ b/procps/kill.c @@ -206,9 +206,27 @@ int kill_main(int argc, char **argv) /* Looks like they want to do a kill. Do that */ while (arg) { - /* Support shell 'space' trick */ - if (arg[0] == ' ') - arg++; +#if ENABLE_ASH || ENABLE_HUSH + /* + * We need to support shell's "hack formats" of + * " -PRGP_ID" (yes, with a leading space) + * and " PID1 PID2 PID3" (with degenerate case "") + */ + while (*arg != '\0') { + char *end; + if (*arg == ' ') + arg++; + pid = bb_strtoi(arg, &end, 10); + if (errno && (errno != EINVAL || *end != ' ')) { + bb_error_msg("invalid number '%s'", arg); + errors++; + } else if (kill(pid, signo) != 0) { + bb_perror_msg("can't kill pid %d", (int)pid); + errors++; + } + arg = end; /* can only point to ' ' or '\0' now */ + } +#else pid = bb_strtoi(arg, NULL, 10); if (errno) { bb_error_msg("invalid number '%s'", arg); @@ -217,6 +235,7 @@ int kill_main(int argc, char **argv) bb_perror_msg("can't kill pid %d", (int)pid); errors++; } +#endif arg = *++argv; } return errors; diff --git a/shell/ash.c b/shell/ash.c index cccd6dd79..98d2c7c29 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -3783,18 +3783,51 @@ setjobctl(int on) static int FAST_FUNC killcmd(int argc, char **argv) { - int i = 1; if (argv[1] && strcmp(argv[1], "-l") != 0) { + int i = 1; do { if (argv[i][0] == '%') { - struct job *jp = getjob(argv[i], 0); - unsigned pid = jp->ps[0].ps_pid; - /* Enough space for ' -NNN' */ - argv[i] = alloca(sizeof(int)*3 + 3); - /* kill_main has matching code to expect - * leading space. Needed to not confuse - * negative pids with "kill -SIGNAL_NO" syntax */ - sprintf(argv[i], " -%u", pid); + /* + * "kill %N" - job kill + * Converting to pgrp / pid kill + */ + struct job *jp; + char *dst; + int j, n; + + jp = getjob(argv[i], 0); + /* + * In jobs started under job control, we signal + * entire process group by kill -PGRP_ID. + * This happens, f.e., in interactive shell. + * + * Otherwise, we signal each child via + * kill PID1 PID2 PID3. + * Testcases: + * sh -c 'sleep 1|sleep 1 & kill %1' + * sh -c 'true|sleep 2 & sleep 1; kill %1' + * sh -c 'true|sleep 1 & sleep 2; kill %1' + */ + n = jp->nprocs; /* can't be 0 (I hope) */ + if (jp->jobctl) + n = 1; + dst = alloca(n * sizeof(int)*4); + argv[i] = dst; + for (j = 0; j < n; j++) { + struct procstat *ps = &jp->ps[j]; + /* Skip non-running and not-stopped members + * (i.e. dead members) of the job + */ + if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status)) + continue; + /* + * kill_main has matching code to expect + * leading space. Needed to not confuse + * negative pids with "kill -SIGNAL_NO" syntax + */ + dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid); + } + *dst = '\0'; } } while (argv[++i]); } @@ -4227,8 +4260,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv) break; job = job->prev_job; } - } else + } else { job = getjob(*argv, 0); + } /* loop until process terminated or stopped */ while (job->state == JOBRUNNING) blocking_wait_with_raise_on_sig(); @@ -4724,7 +4758,7 @@ forkchild(struct job *jp, union node *n, int mode) #if JOBS /* do job control only in root shell */ doing_jobctl = 0; - if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) { + if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) { pid_t pgrp; if (jp->nprocs == 0) @@ -4750,7 +4784,7 @@ forkchild(struct job *jp, union node *n, int mode) ash_msg_and_raise_error("can't open '%s'", bb_dev_null); } } - if (!oldlvl) { + if (oldlvl == 0) { if (iflag) { /* why if iflag only? */ setsignal(SIGINT); setsignal(SIGTERM); diff --git a/shell/ash_test/ash-signals/sigint1.right b/shell/ash_test/ash-signals/sigint1.right new file mode 100644 index 000000000..a9094b056 --- /dev/null +++ b/shell/ash_test/ash-signals/sigint1.right @@ -0,0 +1 @@ +Sending SIGINT to main shell PID diff --git a/shell/ash_test/ash-signals/sigint1.tests b/shell/ash_test/ash-signals/sigint1.tests new file mode 100755 index 000000000..20e45d940 --- /dev/null +++ b/shell/ash_test/ash-signals/sigint1.tests @@ -0,0 +1,41 @@ +# What should happen if non-interactive shell gets SIGINT? + +(sleep 1; echo Sending SIGINT to main shell PID; exec kill -INT $$) & + +# We create a child which exits with 0 even on SIGINT +# (This is truly necessary only if SIGINT is generated by ^C, +# in this testcase even bare "sleep 2" would do because +# we don't send SIGINT _to_ the_ child_...) +$THIS_SH -c 'trap "exit 0" SIGINT; sleep 2' + +# In one second, we (main shell) get SIGINT here. +# The question is whether we should, or should not, exit. + +# bash will not stop here. It will execute next command(s). + +# The rationale for this is described here: +# http://www.cons.org/cracauer/sigint.html +# +# Basically, bash will not exit on SIGINT immediately if it waits +# for a child. It will wait for the child to exit. +# If child exits NOT by dying on SIGINT, then bash will not exit. +# +# The idea is that the following script: +# | emacs file.txt +# | more cmds +# User may use ^C to interrupt editor's ops like search. But then +# emacs exits normally. User expects that script doesn't stop. +# +# This is a nice idea, but detecting "did process really exit +# with SIGINT?" is racy. Consider: +# | bash -c 'while true; do /bin/true; done' +# When ^C is pressed while bash waits for /bin/true to exit, +# it may happen that /bin/true exits with exitcode 0 before +# ^C is delivered to it as SIGINT. bash will see SIGINT, then +# it will see that child exited with 0, and bash will NOT EXIT. + +# Therefore we do not implement bash behavior. +# I'd say that emacs need to put itself into a separate pgrp +# to isolate shell from getting stray SIGINTs from ^C. + +echo Next command after SIGINT was executed diff --git a/shell/hush_test/hush-misc/sigint1.right b/shell/hush_test/hush-misc/sigint1.right new file mode 100644 index 000000000..a9094b056 --- /dev/null +++ b/shell/hush_test/hush-misc/sigint1.right @@ -0,0 +1 @@ +Sending SIGINT to main shell PID diff --git a/shell/hush_test/hush-misc/sigint1.tests b/shell/hush_test/hush-misc/sigint1.tests new file mode 100755 index 000000000..20e45d940 --- /dev/null +++ b/shell/hush_test/hush-misc/sigint1.tests @@ -0,0 +1,41 @@ +# What should happen if non-interactive shell gets SIGINT? + +(sleep 1; echo Sending SIGINT to main shell PID; exec kill -INT $$) & + +# We create a child which exits with 0 even on SIGINT +# (This is truly necessary only if SIGINT is generated by ^C, +# in this testcase even bare "sleep 2" would do because +# we don't send SIGINT _to_ the_ child_...) +$THIS_SH -c 'trap "exit 0" SIGINT; sleep 2' + +# In one second, we (main shell) get SIGINT here. +# The question is whether we should, or should not, exit. + +# bash will not stop here. It will execute next command(s). + +# The rationale for this is described here: +# http://www.cons.org/cracauer/sigint.html +# +# Basically, bash will not exit on SIGINT immediately if it waits +# for a child. It will wait for the child to exit. +# If child exits NOT by dying on SIGINT, then bash will not exit. +# +# The idea is that the following script: +# | emacs file.txt +# | more cmds +# User may use ^C to interrupt editor's ops like search. But then +# emacs exits normally. User expects that script doesn't stop. +# +# This is a nice idea, but detecting "did process really exit +# with SIGINT?" is racy. Consider: +# | bash -c 'while true; do /bin/true; done' +# When ^C is pressed while bash waits for /bin/true to exit, +# it may happen that /bin/true exits with exitcode 0 before +# ^C is delivered to it as SIGINT. bash will see SIGINT, then +# it will see that child exited with 0, and bash will NOT EXIT. + +# Therefore we do not implement bash behavior. +# I'd say that emacs need to put itself into a separate pgrp +# to isolate shell from getting stray SIGINTs from ^C. + +echo Next command after SIGINT was executed -- cgit v1.2.3-55-g6feb From bac0a25f72cdf59f34638aa3fd95bb14b103c286 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 21 Feb 2011 03:47:50 +0100 Subject: slightly better wording in comments Signed-off-by: Denys Vlasenko --- shell/ash_test/ash-signals/sigint1.tests | 4 ++-- shell/hush_test/hush-misc/sigint1.tests | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'shell') diff --git a/shell/ash_test/ash-signals/sigint1.tests b/shell/ash_test/ash-signals/sigint1.tests index 20e45d940..3d483d32a 100755 --- a/shell/ash_test/ash-signals/sigint1.tests +++ b/shell/ash_test/ash-signals/sigint1.tests @@ -3,9 +3,9 @@ (sleep 1; echo Sending SIGINT to main shell PID; exec kill -INT $$) & # We create a child which exits with 0 even on SIGINT -# (This is truly necessary only if SIGINT is generated by ^C, +# (The complex command is necessary only if SIGINT is generated by ^C, # in this testcase even bare "sleep 2" would do because -# we don't send SIGINT _to_ the_ child_...) +# in the testcase we don't send SIGINT *to the child*...) $THIS_SH -c 'trap "exit 0" SIGINT; sleep 2' # In one second, we (main shell) get SIGINT here. diff --git a/shell/hush_test/hush-misc/sigint1.tests b/shell/hush_test/hush-misc/sigint1.tests index 20e45d940..3d483d32a 100755 --- a/shell/hush_test/hush-misc/sigint1.tests +++ b/shell/hush_test/hush-misc/sigint1.tests @@ -3,9 +3,9 @@ (sleep 1; echo Sending SIGINT to main shell PID; exec kill -INT $$) & # We create a child which exits with 0 even on SIGINT -# (This is truly necessary only if SIGINT is generated by ^C, +# (The complex command is necessary only if SIGINT is generated by ^C, # in this testcase even bare "sleep 2" would do because -# we don't send SIGINT _to_ the_ child_...) +# in the testcase we don't send SIGINT *to the child*...) $THIS_SH -c 'trap "exit 0" SIGINT; sleep 2' # In one second, we (main shell) get SIGINT here. -- cgit v1.2.3-55-g6feb