aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-08-02 16:37:39 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2017-08-02 16:37:39 +0200
commit7c40ddd9500907925041131374cb43eb87ef5494 (patch)
tree415676f7439a3c42e2137f357c8e8904a93007cc
parent95f7953f2c46c7b9c799250aa8dc6eb10cc5c726 (diff)
downloadbusybox-w32-7c40ddd9500907925041131374cb43eb87ef5494.tar.gz
busybox-w32-7c40ddd9500907925041131374cb43eb87ef5494.tar.bz2
busybox-w32-7c40ddd9500907925041131374cb43eb87ef5494.zip
NOFORK fixes
"rm -i FILE" and "yes" can now be interrupted by ^C in hush. This also now works: $ usleep 19999999 ^C $ echo $? 130 function old new delta run_pipe 1668 1711 +43 pseudo_exec_argv 312 321 +9 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 52/0) Total: 52 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--coreutils/rm.c5
-rw-r--r--coreutils/seq.c5
-rw-r--r--coreutils/usleep.c7
-rw-r--r--coreutils/yes.c3
-rw-r--r--docs/nofork_noexec.txt3
-rw-r--r--shell/hush.c31
6 files changed, 48 insertions, 6 deletions
diff --git a/coreutils/rm.c b/coreutils/rm.c
index f91c94570..5e4acab8c 100644
--- a/coreutils/rm.c
+++ b/coreutils/rm.c
@@ -16,7 +16,8 @@
16//config: help 16//config: help
17//config: rm is used to remove files or directories. 17//config: rm is used to remove files or directories.
18 18
19//applet:IF_RM(APPLET_NOFORK(rm, rm, BB_DIR_BIN, BB_SUID_DROP, rm)) 19//applet:IF_RM(APPLET_NOEXEC(rm, rm, BB_DIR_BIN, BB_SUID_DROP, rm))
20/* was NOFORK, but then "rm -i FILE" can't be ^C'ed if run by hush */
20 21
21//kbuild:lib-$(CONFIG_RM) += rm.o 22//kbuild:lib-$(CONFIG_RM) += rm.o
22 23
@@ -36,7 +37,7 @@
36 37
37#include "libbb.h" 38#include "libbb.h"
38 39
39/* This is a NOFORK applet. Be very careful! */ 40/* This is a NOEXEC applet. Be very careful! */
40 41
41int rm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 42int rm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
42int rm_main(int argc UNUSED_PARAM, char **argv) 43int rm_main(int argc UNUSED_PARAM, char **argv)
diff --git a/coreutils/seq.c b/coreutils/seq.c
index f36dbb4ec..c26ff06b9 100644
--- a/coreutils/seq.c
+++ b/coreutils/seq.c
@@ -12,7 +12,8 @@
12//config: help 12//config: help
13//config: print a sequence of numbers 13//config: print a sequence of numbers
14 14
15//applet:IF_SEQ(APPLET_NOFORK(seq, seq, BB_DIR_USR_BIN, BB_SUID_DROP, seq)) 15//applet:IF_SEQ(APPLET_NOEXEC(seq, seq, BB_DIR_USR_BIN, BB_SUID_DROP, seq))
16/* was NOFORK, but then "seq 1 999999999" can't be ^C'ed if run by hush */
16 17
17//kbuild:lib-$(CONFIG_SEQ) += seq.o 18//kbuild:lib-$(CONFIG_SEQ) += seq.o
18 19
@@ -26,7 +27,7 @@
26 27
27#include "libbb.h" 28#include "libbb.h"
28 29
29/* This is a NOFORK applet. Be very careful! */ 30/* This is a NOEXEC applet. Be very careful! */
30 31
31int seq_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 32int seq_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
32int seq_main(int argc, char **argv) 33int seq_main(int argc, char **argv)
diff --git a/coreutils/usleep.c b/coreutils/usleep.c
index 7c25aada1..684ab781b 100644
--- a/coreutils/usleep.c
+++ b/coreutils/usleep.c
@@ -38,6 +38,13 @@ int usleep_main(int argc UNUSED_PARAM, char **argv)
38 bb_show_usage(); 38 bb_show_usage();
39 } 39 }
40 40
41 /* Safe wrt NOFORK? (noforks are not allowed to run for
42 * a long time). Try "usleep 99999999" + ^C + "echo $?"
43 * in hush with FEATURE_SH_NOFORK=y.
44 * At least on uclibc, usleep() thanslates to nanosleep()
45 * which returns early on any signal (even caught one),
46 * and uclibc does not loop back on EINTR.
47 */
41 usleep(xatou(argv[1])); 48 usleep(xatou(argv[1]));
42 49
43 return EXIT_SUCCESS; 50 return EXIT_SUCCESS;
diff --git a/coreutils/yes.c b/coreutils/yes.c
index ea35d146c..c244bfe10 100644
--- a/coreutils/yes.c
+++ b/coreutils/yes.c
@@ -17,7 +17,8 @@
17//config: yes is used to repeatedly output a specific string, or 17//config: yes is used to repeatedly output a specific string, or
18//config: the default string 'y'. 18//config: the default string 'y'.
19 19
20//applet:IF_YES(APPLET_NOFORK(yes, yes, BB_DIR_USR_BIN, BB_SUID_DROP, yes)) 20//applet:IF_YES(APPLET_NOEXEC(yes, yes, BB_DIR_USR_BIN, BB_SUID_DROP, yes))
21/* was NOFORK, but then yes can't be ^C'ed if run by hush */
21 22
22//kbuild:lib-$(CONFIG_YES) += yes.o 23//kbuild:lib-$(CONFIG_YES) += yes.o
23 24
diff --git a/docs/nofork_noexec.txt b/docs/nofork_noexec.txt
index a24dd9c27..0ad4e6e60 100644
--- a/docs/nofork_noexec.txt
+++ b/docs/nofork_noexec.txt
@@ -52,6 +52,9 @@ xargs, find, shells do it (grep for "spawn_and_wait" and
52This poses much more serious limitations on what applet can do: 52This poses much more serious limitations on what applet can do:
53 53
54* all NOEXEC limitations apply. 54* all NOEXEC limitations apply.
55* do not run for a long time or wait for user input:
56 hush shell only handles signals (like ^C) after you return
57 from APPLET_main().
55* do not ever exit() or exec(). 58* do not ever exit() or exec().
56 - xfuncs are okay. They are using special trick to return 59 - xfuncs are okay. They are using special trick to return
57 to the caller applet instead of dying when they detect "x" condition. 60 to the caller applet instead of dying when they detect "x" condition.
diff --git a/shell/hush.c b/shell/hush.c
index 9f946d82f..cfefb7324 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -7363,6 +7363,8 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7363 */ 7363 */
7364 close_saved_fds_and_FILE_fds(); 7364 close_saved_fds_and_FILE_fds();
7365//FIXME: should also close saved redir fds 7365//FIXME: should also close saved redir fds
7366 /* Without this, "rm -i FILE" can't be ^C'ed: */
7367 switch_off_special_sigs(G.special_sig_mask);
7366 debug_printf_exec("running applet '%s'\n", argv[0]); 7368 debug_printf_exec("running applet '%s'\n", argv[0]);
7367 run_applet_no_and_exit(a, argv[0], argv); 7369 run_applet_no_and_exit(a, argv[0], argv);
7368 } 7370 }
@@ -8045,6 +8047,24 @@ static NOINLINE int run_pipe(struct pipe *pi)
8045 add_vars(old_vars); 8047 add_vars(old_vars);
8046/* clean_up_and_ret0: */ 8048/* clean_up_and_ret0: */
8047 restore_redirects(squirrel); 8049 restore_redirects(squirrel);
8050 /*
8051 * Try "usleep 99999999" + ^C + "echo $?"
8052 * with FEATURE_SH_NOFORK=y.
8053 */
8054 if (!funcp) {
8055 /* It was builtin or nofork.
8056 * if this would be a real fork/execed program,
8057 * it should have died if a fatal sig was received.
8058 * But OTOH, there was no separate process,
8059 * the sig was sent to _shell_, not to non-existing
8060 * child.
8061 * Let's just handle ^C only, this one is obvious:
8062 * we aren't ok with exitcode 0 when ^C was pressed
8063 * during builtin/nofork.
8064 */
8065 if (sigismember(&G.pending_set, SIGINT))
8066 rcode = 128 + SIGINT;
8067 }
8048 clean_up_and_ret1: 8068 clean_up_and_ret1:
8049 free(argv_expanded); 8069 free(argv_expanded);
8050 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) 8070 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
@@ -8060,6 +8080,14 @@ static NOINLINE int run_pipe(struct pipe *pi)
8060 if (rcode == 0) { 8080 if (rcode == 0) {
8061 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", 8081 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n",
8062 argv_expanded[0], argv_expanded[1]); 8082 argv_expanded[0], argv_expanded[1]);
8083 /*
8084 * Note: signals (^C) can't interrupt here.
8085 * We remember them and they will be acted upon
8086 * after applet returns.
8087 * This makes applets which can run for a long time
8088 * and/or wait for user input ineligible for NOFORK:
8089 * for example, "yes" or "rm" (rm -i waits for input).
8090 */
8063 rcode = run_nofork_applet(n, argv_expanded); 8091 rcode = run_nofork_applet(n, argv_expanded);
8064 } 8092 }
8065 goto clean_up_and_ret; 8093 goto clean_up_and_ret;
@@ -8491,7 +8519,7 @@ static int run_list(struct pipe *pi)
8491 G.last_bg_pid = pi->cmds[pi->num_cmds - 1].pid; 8519 G.last_bg_pid = pi->cmds[pi->num_cmds - 1].pid;
8492 G.last_bg_pid_exitcode = 0; 8520 G.last_bg_pid_exitcode = 0;
8493 debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n"); 8521 debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n");
8494/* Check pi->pi_inverted? "! sleep 1 & echo $?": bash says 1. dash and ash says 0 */ 8522/* Check pi->pi_inverted? "! sleep 1 & echo $?": bash says 1. dash and ash say 0 */
8495 rcode = EXIT_SUCCESS; 8523 rcode = EXIT_SUCCESS;
8496 goto check_traps; 8524 goto check_traps;
8497 } else { 8525 } else {
@@ -10178,6 +10206,7 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid
10178 /* So, did we get a signal? */ 10206 /* So, did we get a signal? */
10179 sig = check_and_run_traps(); 10207 sig = check_and_run_traps();
10180 if (sig /*&& sig != SIGCHLD - always true */) { 10208 if (sig /*&& sig != SIGCHLD - always true */) {
10209 /* Do this for any (non-ignored) signal, not only for ^C */
10181 ret = 128 + sig; 10210 ret = 128 + sig;
10182 break; 10211 break;
10183 } 10212 }