aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2010-01-12 15:19:31 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2010-01-12 15:19:31 +0100
commite89a241b9ed76aed22bde93f58311db9c159cde2 (patch)
tree703fcdf66e1ceb244fcb4b31b9cf5bb66a0c313f /shell
parentf3ec0fb1b4ae594c152dd626996f3abdc28b13be (diff)
downloadbusybox-w32-e89a241b9ed76aed22bde93f58311db9c159cde2.tar.gz
busybox-w32-e89a241b9ed76aed22bde93f58311db9c159cde2.tar.bz2
busybox-w32-e89a241b9ed76aed22bde93f58311db9c159cde2.zip
hush: fix subshell.tests failure on NOMMU
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r--shell/hush.c104
-rw-r--r--shell/hush_test/hush-trap/subshell.right15
-rwxr-xr-xshell/hush_test/hush-trap/subshell.tests10
3 files changed, 88 insertions, 41 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 7d851ed97..8de8d3c2a 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -520,6 +520,7 @@ struct globals {
520 smalluint last_exitcode; 520 smalluint last_exitcode;
521 /* are global_argv and global_argv[1..n] malloced? (note: not [0]) */ 521 /* are global_argv and global_argv[1..n] malloced? (note: not [0]) */
522 smalluint global_args_malloced; 522 smalluint global_args_malloced;
523 smalluint inherited_set_is_saved;
523 /* how many non-NULL argv's we have. NB: $# + 1 */ 524 /* how many non-NULL argv's we have. NB: $# + 1 */
524 int global_argc; 525 int global_argc;
525 char **global_argv; 526 char **global_argv;
@@ -1050,7 +1051,8 @@ static void restore_G_args(save_arg_t *sv, char **argv)
1050 * 1051 *
1051 * Trap handlers will execute even within trap handlers. (right?) 1052 * Trap handlers will execute even within trap handlers. (right?)
1052 * 1053 *
1053 * User trap handlers are forgotten when subshell ("(cmd)") is entered. 1054 * User trap handlers are forgotten when subshell ("(cmd)") is entered,
1055 * except for handlers set to '' (empty string).
1054 * 1056 *
1055 * If job control is off, backgrounded commands ("cmd &") 1057 * If job control is off, backgrounded commands ("cmd &")
1056 * have SIGINT, SIGQUIT set to SIG_IGN. 1058 * have SIGINT, SIGQUIT set to SIG_IGN.
@@ -1106,7 +1108,7 @@ static void restore_G_args(save_arg_t *sv, char **argv)
1106 * after [v]fork, if we plan to be a shell: 1108 * after [v]fork, if we plan to be a shell:
1107 * unblock signals with special interactive handling 1109 * unblock signals with special interactive handling
1108 * (child shell is not interactive), 1110 * (child shell is not interactive),
1109 * unset all traps (note: regardless of child shell's type - {}, (), etc) 1111 * unset all traps except '' (note: regardless of child shell's type - {}, (), etc)
1110 * after [v]fork, if we plan to exec: 1112 * after [v]fork, if we plan to exec:
1111 * POSIX says fork clears pending signal mask in child - no need to clear it. 1113 * POSIX says fork clears pending signal mask in child - no need to clear it.
1112 * Restore blocked signal set to one inherited by shell just prior to exec. 1114 * Restore blocked signal set to one inherited by shell just prior to exec.
@@ -1118,7 +1120,7 @@ static void restore_G_args(save_arg_t *sv, char **argv)
1118 * Note 2 (compat): 1120 * Note 2 (compat):
1119 * Standard says "When a subshell is entered, traps that are not being ignored 1121 * Standard says "When a subshell is entered, traps that are not being ignored
1120 * are set to the default actions". bash interprets it so that traps which 1122 * are set to the default actions". bash interprets it so that traps which
1121 * are set to "" (ignore) are NOT reset to defaults. We do the same. 1123 * are set to '' (ignore) are NOT reset to defaults. We do the same.
1122 */ 1124 */
1123enum { 1125enum {
1124 SPECIAL_INTERACTIVE_SIGS = 0 1126 SPECIAL_INTERACTIVE_SIGS = 0
@@ -2925,6 +2927,7 @@ static void re_execute_shell(char ***to_free, const char *s,
2925# endif 2927# endif
2926 char **argv, **pp; 2928 char **argv, **pp;
2927 unsigned cnt; 2929 unsigned cnt;
2930 unsigned long long empty_trap_mask;
2928 2931
2929 if (!g_argv0) { /* heredoc */ 2932 if (!g_argv0) { /* heredoc */
2930 argv = heredoc_argv; 2933 argv = heredoc_argv;
@@ -2941,12 +2944,22 @@ static void re_execute_shell(char ***to_free, const char *s,
2941 if (pp) while (*pp++) 2944 if (pp) while (*pp++)
2942 cnt++; 2945 cnt++;
2943 2946
2944 sprintf(param_buf, "-$%x:%x:%x:%x:%x" IF_HUSH_LOOPS(":%x") 2947 empty_trap_mask = 0;
2948 if (G.traps) {
2949 int sig;
2950 for (sig = 1; sig < NSIG; sig++) {
2951 if (G.traps[sig] && !G.traps[sig][0])
2952 empty_trap_mask |= 1LL << sig;
2953 }
2954 }
2955
2956 sprintf(param_buf, "-$%x:%x:%x:%x:%x:%llx" IF_HUSH_LOOPS(":%x")
2945 , (unsigned) G.root_pid 2957 , (unsigned) G.root_pid
2946 , (unsigned) G.root_ppid 2958 , (unsigned) G.root_ppid
2947 , (unsigned) G.last_bg_pid 2959 , (unsigned) G.last_bg_pid
2948 , (unsigned) G.last_exitcode 2960 , (unsigned) G.last_exitcode
2949 , cnt 2961 , cnt
2962 , empty_trap_mask
2950 IF_HUSH_LOOPS(, G.depth_of_loop) 2963 IF_HUSH_LOOPS(, G.depth_of_loop)
2951 ); 2964 );
2952 /* 1:hush 2:-$<pid>:<pid>:<exitcode>:<depth> <vars...> <funcs...> 2965 /* 1:hush 2:-$<pid>:<pid>:<exitcode>:<depth> <vars...> <funcs...>
@@ -3002,7 +3015,9 @@ static void re_execute_shell(char ***to_free, const char *s,
3002 * _inside_ group (just before echo 1), it works. 3015 * _inside_ group (just before echo 1), it works.
3003 * 3016 *
3004 * I conclude it means we don't need to pass active traps here. 3017 * I conclude it means we don't need to pass active traps here.
3005 * exec syscall below resets them to SIG_DFL for us. 3018 * Even if we would use signal handlers instead of signal masking
3019 * in order to implement trap handling,
3020 * exec syscall below resets signals to SIG_DFL for us.
3006 */ 3021 */
3007 *pp++ = (char *) "-c"; 3022 *pp++ = (char *) "-c";
3008 *pp++ = (char *) s; 3023 *pp++ = (char *) s;
@@ -5447,7 +5462,7 @@ static FILE *generate_stream_from_string(const char *s, pid_t *pid_p)
5447 pid_t pid; 5462 pid_t pid;
5448 int channel[2]; 5463 int channel[2];
5449# if !BB_MMU 5464# if !BB_MMU
5450 char **to_free; 5465 char **to_free = NULL;
5451# endif 5466# endif
5452 5467
5453 xpipe(channel); 5468 xpipe(channel);
@@ -6677,10 +6692,17 @@ static void parse_and_run_file(FILE *f)
6677} 6692}
6678 6693
6679/* Called a few times only (or even once if "sh -c") */ 6694/* Called a few times only (or even once if "sh -c") */
6680static void block_signals(int second_time) 6695static void init_sigmasks(void)
6681{ 6696{
6682 unsigned sig; 6697 unsigned sig;
6683 unsigned mask; 6698 unsigned mask;
6699 sigset_t old_blocked_set;
6700
6701 if (!G.inherited_set_is_saved) {
6702 sigprocmask(SIG_SETMASK, NULL, &G.blocked_set);
6703 G.inherited_set = G.blocked_set;
6704 }
6705 old_blocked_set = G.blocked_set;
6684 6706
6685 mask = (1 << SIGQUIT); 6707 mask = (1 << SIGQUIT);
6686 if (G_interactive_fd) { 6708 if (G_interactive_fd) {
@@ -6690,8 +6712,6 @@ static void block_signals(int second_time)
6690 } 6712 }
6691 G.non_DFL_mask = mask; 6713 G.non_DFL_mask = mask;
6692 6714
6693 if (!second_time)
6694 sigprocmask(SIG_SETMASK, NULL, &G.blocked_set);
6695 sig = 0; 6715 sig = 0;
6696 while (mask) { 6716 while (mask) {
6697 if (mask & 1) 6717 if (mask & 1)
@@ -6701,18 +6721,21 @@ static void block_signals(int second_time)
6701 } 6721 }
6702 sigdelset(&G.blocked_set, SIGCHLD); 6722 sigdelset(&G.blocked_set, SIGCHLD);
6703 6723
6704 sigprocmask(SIG_SETMASK, &G.blocked_set, 6724 if (memcmp(&old_blocked_set, &G.blocked_set, sizeof(old_blocked_set)) != 0)
6705 second_time ? NULL : &G.inherited_set); 6725 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
6726
6706 /* POSIX allows shell to re-enable SIGCHLD 6727 /* POSIX allows shell to re-enable SIGCHLD
6707 * even if it was SIG_IGN on entry */ 6728 * even if it was SIG_IGN on entry */
6708#if ENABLE_HUSH_FAST 6729#if ENABLE_HUSH_FAST
6709 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ 6730 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */
6710 if (!second_time) 6731 if (!G.inherited_set_is_saved)
6711 signal(SIGCHLD, SIGCHLD_handler); 6732 signal(SIGCHLD, SIGCHLD_handler);
6712#else 6733#else
6713 if (!second_time) 6734 if (!G.inherited_set_is_saved)
6714 signal(SIGCHLD, SIG_DFL); 6735 signal(SIGCHLD, SIG_DFL);
6715#endif 6736#endif
6737
6738 G.inherited_set_is_saved = 1;
6716} 6739}
6717 6740
6718#if ENABLE_HUSH_JOB 6741#if ENABLE_HUSH_JOB
@@ -6774,7 +6797,6 @@ int hush_main(int argc, char **argv)
6774 .flg_export = 1, 6797 .flg_export = 1,
6775 .flg_read_only = 1, 6798 .flg_read_only = 1,
6776 }; 6799 };
6777 int signal_mask_is_inited = 0;
6778 int opt; 6800 int opt;
6779 unsigned builtin_argc; 6801 unsigned builtin_argc;
6780 char **e; 6802 char **e;
@@ -6865,10 +6887,9 @@ int hush_main(int argc, char **argv)
6865 } 6887 }
6866 6888
6867 /* Shell is non-interactive at first. We need to call 6889 /* Shell is non-interactive at first. We need to call
6868 * block_signals(0) if we are going to execute "sh <script>", 6890 * init_sigmasks() if we are going to execute "sh <script>",
6869 * "sh -c <cmds>" or login shell's /etc/profile and friends. 6891 * "sh -c <cmds>" or login shell's /etc/profile and friends.
6870 * If we later decide that we are interactive, we run block_signals(0) 6892 * If we later decide that we are interactive, we run init_sigmasks()
6871 * (or re-run block_signals(1) if we ran block_signals(0) before)
6872 * in order to intercept (more) signals. 6893 * in order to intercept (more) signals.
6873 */ 6894 */
6874 6895
@@ -6908,7 +6929,7 @@ int hush_main(int argc, char **argv)
6908 /* -c 'builtin' [BARGV...] "" ARG0 [ARG1...] */ 6929 /* -c 'builtin' [BARGV...] "" ARG0 [ARG1...] */
6909 const struct built_in_command *x; 6930 const struct built_in_command *x;
6910 6931
6911 block_signals(0); /* 0: called 1st time */ 6932 init_sigmasks();
6912 x = find_builtin(optarg); 6933 x = find_builtin(optarg);
6913 if (x) { /* paranoia */ 6934 if (x) { /* paranoia */
6914 G.global_argc -= builtin_argc; /* skip [BARGV...] "" */ 6935 G.global_argc -= builtin_argc; /* skip [BARGV...] "" */
@@ -6924,7 +6945,7 @@ int hush_main(int argc, char **argv)
6924 G.global_argv[0] = argv[0]; 6945 G.global_argv[0] = argv[0];
6925 G.global_argc--; 6946 G.global_argc--;
6926 } /* else -c 'script' ARG0 [ARG1...]: $0 is ARG0 */ 6947 } /* else -c 'script' ARG0 [ARG1...]: $0 is ARG0 */
6927 block_signals(0); /* 0: called 1st time */ 6948 init_sigmasks();
6928 parse_and_run_string(optarg); 6949 parse_and_run_string(optarg);
6929 goto final_return; 6950 goto final_return;
6930 case 'i': 6951 case 'i':
@@ -6940,7 +6961,9 @@ int hush_main(int argc, char **argv)
6940 case '<': /* "big heredoc" support */ 6961 case '<': /* "big heredoc" support */
6941 full_write(STDOUT_FILENO, optarg, strlen(optarg)); 6962 full_write(STDOUT_FILENO, optarg, strlen(optarg));
6942 _exit(0); 6963 _exit(0);
6943 case '$': 6964 case '$': {
6965 unsigned long long empty_trap_mask;
6966
6944 G.root_pid = bb_strtou(optarg, &optarg, 16); 6967 G.root_pid = bb_strtou(optarg, &optarg, 16);
6945 optarg++; 6968 optarg++;
6946 G.root_ppid = bb_strtou(optarg, &optarg, 16); 6969 G.root_ppid = bb_strtou(optarg, &optarg, 16);
@@ -6950,11 +6973,26 @@ int hush_main(int argc, char **argv)
6950 G.last_exitcode = bb_strtou(optarg, &optarg, 16); 6973 G.last_exitcode = bb_strtou(optarg, &optarg, 16);
6951 optarg++; 6974 optarg++;
6952 builtin_argc = bb_strtou(optarg, &optarg, 16); 6975 builtin_argc = bb_strtou(optarg, &optarg, 16);
6976 optarg++;
6977 empty_trap_mask = bb_strtoull(optarg, &optarg, 16);
6978 if (empty_trap_mask != 0) {
6979 int sig;
6980 init_sigmasks();
6981 G.traps = xzalloc(sizeof(G.traps[0]) * NSIG);
6982 for (sig = 1; sig < NSIG; sig++) {
6983 if (empty_trap_mask & (1LL << sig)) {
6984 G.traps[sig] = xzalloc(1); /* == xstrdup(""); */
6985 sigaddset(&G.blocked_set, sig);
6986 }
6987 }
6988 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
6989 }
6953# if ENABLE_HUSH_LOOPS 6990# if ENABLE_HUSH_LOOPS
6954 optarg++; 6991 optarg++;
6955 G.depth_of_loop = bb_strtou(optarg, &optarg, 16); 6992 G.depth_of_loop = bb_strtou(optarg, &optarg, 16);
6956# endif 6993# endif
6957 break; 6994 break;
6995 }
6958 case 'R': 6996 case 'R':
6959 case 'V': 6997 case 'V':
6960 set_local_var(xstrdup(optarg), /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ opt == 'R'); 6998 set_local_var(xstrdup(optarg), /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ opt == 'R');
@@ -6997,8 +7035,7 @@ int hush_main(int argc, char **argv)
6997 input = fopen_for_read("/etc/profile"); 7035 input = fopen_for_read("/etc/profile");
6998 if (input != NULL) { 7036 if (input != NULL) {
6999 close_on_exec_on(fileno(input)); 7037 close_on_exec_on(fileno(input));
7000 block_signals(0); /* 0: called 1st time */ 7038 init_sigmasks();
7001 signal_mask_is_inited = 1;
7002 parse_and_run_file(input); 7039 parse_and_run_file(input);
7003 fclose(input); 7040 fclose(input);
7004 } 7041 }
@@ -7023,8 +7060,7 @@ int hush_main(int argc, char **argv)
7023 G.global_argc = argc - optind; 7060 G.global_argc = argc - optind;
7024 input = xfopen_for_read(argv[optind]); 7061 input = xfopen_for_read(argv[optind]);
7025 close_on_exec_on(fileno(input)); 7062 close_on_exec_on(fileno(input));
7026 if (!signal_mask_is_inited) 7063 init_sigmasks();
7027 block_signals(0); /* 0: called 1st time */
7028 parse_and_run_file(input); 7064 parse_and_run_file(input);
7029#if ENABLE_FEATURE_CLEAN_UP 7065#if ENABLE_FEATURE_CLEAN_UP
7030 fclose(input); 7066 fclose(input);
@@ -7033,7 +7069,7 @@ int hush_main(int argc, char **argv)
7033 } 7069 }
7034 7070
7035 /* Up to here, shell was non-interactive. Now it may become one. 7071 /* Up to here, shell was non-interactive. Now it may become one.
7036 * NB: don't forget to (re)run block_signals(0/1) as needed. 7072 * NB: don't forget to (re)run init_sigmasks() as needed.
7037 */ 7073 */
7038 7074
7039 /* A shell is interactive if the '-i' flag was given, 7075 /* A shell is interactive if the '-i' flag was given,
@@ -7086,7 +7122,7 @@ int hush_main(int argc, char **argv)
7086 } 7122 }
7087 7123
7088 /* Block some signals */ 7124 /* Block some signals */
7089 block_signals(signal_mask_is_inited); 7125 init_sigmasks();
7090 7126
7091 if (G_saved_tty_pgrp) { 7127 if (G_saved_tty_pgrp) {
7092 /* Set other signals to restore saved_tty_pgrp */ 7128 /* Set other signals to restore saved_tty_pgrp */
@@ -7100,9 +7136,9 @@ int hush_main(int argc, char **argv)
7100 /* -1 is special - makes xfuncs longjmp, not exit 7136 /* -1 is special - makes xfuncs longjmp, not exit
7101 * (we reset die_sleep = 0 whereever we [v]fork) */ 7137 * (we reset die_sleep = 0 whereever we [v]fork) */
7102 enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */ 7138 enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */
7103 } else if (!signal_mask_is_inited) { 7139 } else {
7104 block_signals(0); /* 0: called 1st time */ 7140 init_sigmasks();
7105 } /* else: block_signals(0) was done before */ 7141 }
7106#elif ENABLE_HUSH_INTERACTIVE 7142#elif ENABLE_HUSH_INTERACTIVE
7107 /* No job control compiled in, only prompt/line editing */ 7143 /* No job control compiled in, only prompt/line editing */
7108 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { 7144 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
@@ -7117,15 +7153,11 @@ int hush_main(int argc, char **argv)
7117 } 7153 }
7118 if (G_interactive_fd) { 7154 if (G_interactive_fd) {
7119 close_on_exec_on(G_interactive_fd); 7155 close_on_exec_on(G_interactive_fd);
7120 block_signals(signal_mask_is_inited);
7121 } else if (!signal_mask_is_inited) {
7122 block_signals(0);
7123 } 7156 }
7157 init_sigmasks();
7124#else 7158#else
7125 /* We have interactiveness code disabled */ 7159 /* We have interactiveness code disabled */
7126 if (!signal_mask_is_inited) { 7160 init_sigmasks();
7127 block_signals(0);
7128 }
7129#endif 7161#endif
7130 /* bash: 7162 /* bash:
7131 * if interactive but not a login shell, sources ~/.bashrc 7163 * if interactive but not a login shell, sources ~/.bashrc
@@ -7471,7 +7503,7 @@ static int FAST_FUNC builtin_trap(char **argv)
7471 free(G.traps[sig]); 7503 free(G.traps[sig]);
7472 G.traps[sig] = xstrdup(new_cmd); 7504 G.traps[sig] = xstrdup(new_cmd);
7473 7505
7474 debug_printf("trap: setting SIG%s (%i) to '%s'", 7506 debug_printf("trap: setting SIG%s (%i) to '%s'\n",
7475 get_signame(sig), sig, G.traps[sig]); 7507 get_signame(sig), sig, G.traps[sig]);
7476 7508
7477 /* There is no signal for 0 (EXIT) */ 7509 /* There is no signal for 0 (EXIT) */
diff --git a/shell/hush_test/hush-trap/subshell.right b/shell/hush_test/hush-trap/subshell.right
index 0d20ed4e9..f865b932b 100644
--- a/shell/hush_test/hush-trap/subshell.right
+++ b/shell/hush_test/hush-trap/subshell.right
@@ -1,6 +1,21 @@
1trap -- '' HUP
2trap -- '' QUIT
3trap -- '' SYS
1Ok 4Ok
5trap -- '' HUP
6trap -- '' QUIT
7trap -- '' SYS
2Ok 8Ok
9trap -- '' HUP
10trap -- '' QUIT
11trap -- '' SYS
3Ok 12Ok
13trap -- '' HUP
14trap -- '' QUIT
15trap -- '' SYS
4Ok 16Ok
17trap -- '' HUP
18trap -- '' QUIT
19trap -- '' SYS
5TERM 20TERM
6Done 21Done
diff --git a/shell/hush_test/hush-trap/subshell.tests b/shell/hush_test/hush-trap/subshell.tests
index 4564c2ee2..045294bf4 100755
--- a/shell/hush_test/hush-trap/subshell.tests
+++ b/shell/hush_test/hush-trap/subshell.tests
@@ -12,9 +12,9 @@ trap 'bad: caught WINCH' WINCH
12trap 'bad: caught TERM' TERM 12trap 'bad: caught TERM' TERM
13 13
14# using bash, because we don't have $PPID (yet) 14# using bash, because we don't have $PPID (yet)
15(bash -c 'kill -HUP $PPID'; echo Ok) 15(trap; bash -c 'kill -HUP $PPID'; echo Ok)
16(bash -c 'kill -QUIT $PPID'; echo Ok) 16(trap; bash -c 'kill -QUIT $PPID'; echo Ok)
17(bash -c 'kill -SYS $PPID'; echo Ok) 17(trap; bash -c 'kill -SYS $PPID'; echo Ok)
18(bash -c 'kill -WINCH $PPID'; echo Ok) 18(trap; bash -c 'kill -WINCH $PPID'; echo Ok)
19(bash -c 'kill -TERM $PPID'; echo Bad: TERM is not reset) 19(trap; bash -c 'kill -TERM $PPID'; echo Bad: TERM is not reset)
20echo Done 20echo Done