aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-03-31 11:22:57 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-03-31 11:22:57 +0000
commitd5762932fbcbc0a385047945276f10e2f3fea12d (patch)
tree7f48d6b4f8da360f68a4efd662e5d8de773fb001
parentd690f68554f1c1301975bc0ab0e479e6870b3589 (diff)
downloadbusybox-w32-d5762932fbcbc0a385047945276f10e2f3fea12d.tar.gz
busybox-w32-d5762932fbcbc0a385047945276f10e2f3fea12d.tar.bz2
busybox-w32-d5762932fbcbc0a385047945276f10e2f3fea12d.zip
hush: rework signal and trap handling. Some smaller bits are TODO,
expect minor breakage function old new delta set_fatal_sighandler 12 186 +174 check_and_run_traps - 122 +122 maybe_set_sighandler - 76 +76 hush_main 831 887 +56 sigtimedwait - 50 +50 __GI_sigtimedwait - 50 +50 hush_exit 49 93 +44 set_mode 749 777 +28 pseudo_exec_argv 131 151 +20 static.zero_ts - 8 +8 expand_variables 1962 1970 +8 builtin_wait 172 174 +2 set_misc_sighandler 12 - -12 set_jobctrl_sighandler 12 - -12 handler_ctrl_c 16 - -16 builtin_set_mode 28 - -28 handle_trap 97 - -97 handler_ctrl_z 107 - -107 builtin_trap 545 438 -107 run_list 2149 2006 -143 ------------------------------------------------------------------------------ (add/remove: 5/6 grow/shrink: 7/2 up/down: 638/-522) Total: 116 bytes
-rw-r--r--shell/hush.c584
1 files changed, 376 insertions, 208 deletions
diff --git a/shell/hush.c b/shell/hush.c
index cd6e12b11..bcccfb0bb 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -460,13 +460,13 @@ struct globals {
460 int last_jobid; 460 int last_jobid;
461 struct pipe *job_list; 461 struct pipe *job_list;
462 struct pipe *toplevel_list; 462 struct pipe *toplevel_list;
463 smallint ctrl_z_flag; 463//// smallint ctrl_z_flag;
464#endif 464#endif
465#if ENABLE_HUSH_LOOPS 465#if ENABLE_HUSH_LOOPS
466 smallint flag_break_continue; 466 smallint flag_break_continue;
467#endif 467#endif
468 smallint fake_mode; 468 smallint fake_mode;
469 /* these three support $?, $#, and $1 */ 469 /* These four support $?, $#, and $1 */
470 smalluint last_return_code; 470 smalluint last_return_code;
471 /* is global_argv and global_argv[1..n] malloced? (note: not [0]) */ 471 /* is global_argv and global_argv[1..n] malloced? (note: not [0]) */
472 smalluint global_args_malloced; 472 smalluint global_args_malloced;
@@ -489,10 +489,14 @@ struct globals {
489#endif 489#endif
490 unsigned char charmap[256]; 490 unsigned char charmap[256];
491 char user_input_buf[ENABLE_FEATURE_EDITING ? BUFSIZ : 2]; 491 char user_input_buf[ENABLE_FEATURE_EDITING ? BUFSIZ : 2];
492 struct { 492 /* Signal and trap handling */
493 char *cmd; 493 char **traps; /* char *traps[NSIG] */
494 struct sigaction oact; 494 /* which signals have non-DFL handler (even with no traps set)? */
495 } *traps; 495 unsigned non_DFL_mask;
496 /* which signals are known to be IGNed on entry to shell? */
497 unsigned IGN_mask;
498 sigset_t blocked_set;
499 sigset_t inherited_set;
496}; 500};
497 501
498#define G (*ptr_to_globals) 502#define G (*ptr_to_globals)
@@ -521,11 +525,9 @@ static int builtin_help(char **argv);
521static int builtin_pwd(char **argv); 525static int builtin_pwd(char **argv);
522static int builtin_read(char **argv); 526static int builtin_read(char **argv);
523static int builtin_test(char **argv); 527static int builtin_test(char **argv);
524static void handle_trap(int sig);
525static int builtin_trap(char **argv); 528static int builtin_trap(char **argv);
526static int builtin_true(char **argv); 529static int builtin_true(char **argv);
527static int builtin_set(char **argv); 530static int builtin_set(char **argv);
528static int builtin_set_mode(const char, const char);
529static int builtin_shift(char **argv); 531static int builtin_shift(char **argv);
530static int builtin_source(char **argv); 532static int builtin_source(char **argv);
531static int builtin_umask(char **argv); 533static int builtin_umask(char **argv);
@@ -750,95 +752,270 @@ static void free_strings(char **strings)
750} 752}
751 753
752 754
753/* Signals are grouped, we handle them in batches */ 755/* Basic theory of signal handling in shell
754static void set_misc_sighandler(void (*handler)(int)) 756 * ========================================
757 * This does not describe what hush does, rahter, it is current understanding
758 * what it _should_ do.
759 * http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#trap
760 *
761 * Signals are handled only after each pipe ("cmd | cmd | cmd" thing)
762 * is finished or backgrounded. It is the same in interactive and
763 * non-interactive shells, and is the same regardless of whether
764 * a user trap handler is installed or a default one is in effect.
765 * ^C or ^Z from keyboard seem to execute "at once" because it usually
766 * backgrounds (i.e. stops) or kills all members of currently running
767 * pipe.
768 *
769 * Wait builtin in interruptible by signals for which user trap is set
770 * or by SIGINT in interactive shell.
771 *
772 * Trap handlers will execute even within trap handlers. (right?)
773 *
774 * User trap handlers are forgotten when subshell is entered.
775 *
776 * If job control is off, backgrounded commands ("cmd &")
777 * have SIGINT, SIGQUIT set to SIG_IGN.
778 *
779 * Commands run in command substitution ("`cmd`")
780 * have SIGTTIN, SIGTTOU, SIGTSTP set to SIG_IGN.
781 *
782 * Ordinary commands have IGN/DFL set as inherited by the shell
783 * from its parent.
784 *
785 * Default handlers which differ from DFL action
786 * (note: subshell is not an interactive shell):
787 *
788 * SIGQUIT: ignore
789 * SIGTERM (interactive): ignore
790 * SUGHUP (interactive): send SIGCONT to stopped jobs,
791 * send SIGHUP to all jobs and exit
792 * SIGTTIN, SIGTTOU, SIGTSTP (if job control is on): ignore
793 * (note that ^Z is handled not by trapping SIGTSTP, but by seeing
794 * that all pipe members are stopped) (right?)
795 * SIGINT (interactive): wait for last pipe, ignore the rest
796 * of the command line, show prompt. (check/expand this)
797 * Example 1: this waits 5 sec, but does not execute ls:
798 * "echo $$; sleep 5; ls -l" + "kill -INT <pid>"
799 * Example 2: this does not wait and does not execute ls:
800 * "echo $$; sleep 5 & wait; ls -l" + "kill -INT <pid>"
801 *
802 * (What happens to signals which are IGN on shell start?)
803 * (What happens with signal mask on shell start?)
804 *
805 * Implementation in hush
806 * ======================
807 * We use in-kernel pending signal mask to determine which signals were sent.
808 * We block all signals which we don't want to take action immediately,
809 * i.e. we block all signals which need to have special handling as described
810 * above, and all signals which have traps set.
811 * After each pipe execution, we extract any pending signals via sigtimedwait()
812 * and act on them.
813 *
814 * unsigned non_DFL_mask: a mask of such "special" signals
815 * sigset_t blocked_set: current blocked signal set
816 *
817 * "trap - SIGxxx": clear bit in blocked_set unless it is also in non_DFL
818 * "trap 'cmd' SIGxxx": set bit in blocked_set (even if 'cmd' is '')
819 * after [v]fork, if we plan to be a shell:
820 * nothing for {} subshell (say, "true | { true; true; } | true")
821 * unset all traps if () shell. [TODO]
822 * after [v]fork, if we plan to exec:
823 * POSIX says pending signal mask is cleared in child - no need to clear it.
824 * restore blocked signal set to one inherited by shell just prior to exec.
825 *
826 * Note: as a result, we do not use signal handlers much. The only use
827 * is to restore terminal pgrp on exit.
828 *
829 * TODO: check/fix wait builtin to be interruptible.
830 */
831
832/* called once at shell init */
833static void init_signal_mask(void)
755{ 834{
756 bb_signals(0 835 unsigned sig;
757 + (1 << SIGINT) 836 unsigned mask = (1 << SIGQUIT);
758 + (1 << SIGQUIT) 837#if ENABLE_HUSH_INTERACTIVE
759 + (1 << SIGTERM) 838 if (G.interactive_fd) {
760 , handler); 839 mask = 0
840 | (1 << SIGQUIT)
841 | (1 << SIGTERM)
842 | (1 << SIGHUP)
843#if ENABLE_HUSH_JOB
844 | (1 << SIGTTIN) | (1 << SIGTTOU) | (1 << SIGTSTP)
845#endif
846 | (1 << SIGINT)
847 ;
848 }
849#endif
850 G.non_DFL_mask = mask;
851
852 /*sigemptyset(&G.blocked_set); - already is */
853 sigprocmask(SIG_SETMASK, NULL, &G.blocked_set);
854 sig = 0;
855 while (mask) {
856 if (mask & 1)
857 sigaddset(&G.blocked_set, sig);
858 mask >>= 1;
859 sig++;
860 }
861 sigprocmask(SIG_SETMASK, &G.blocked_set, &G.inherited_set);
862}
863static void check_and_run_traps(void)
864{
865 static const struct timespec zero_ts = { 0, 0 };
866 smalluint save_rcode;
867 int sig;
868
869 while (1) {
870 sig = sigtimedwait(&G.blocked_set, NULL, &zero_ts);
871 if (sig <= 0)
872 break;
873
874 if (G.traps && G.traps[sig]) {
875 if (G.traps[sig][0]) {
876 /* We have user-defined handler */
877 char *argv[] = { NULL, xstrdup(G.traps[sig]), NULL };
878 save_rcode = G.last_return_code;
879 builtin_eval(argv);
880 free(argv[1]);
881 G.last_return_code = save_rcode;
882 } /* else: "" trap, ignoring signal */
883 continue;
884 }
885 /* not a trap: special action */
886#if 0 //TODO
887 switch (sig) {
888 case SIGHUP: ...
889 break;
890 case SIGINT: ...
891 break;
892 default: /* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */
893 }
894#endif
895 }
761} 896}
762 897
898/* The stuff below needs to be migrated to "Special action" above */
899
900/////* Signals are grouped, we handle them in batches */
901////static void set_misc_sighandler(void (*handler)(int))
902////{
903//// bb_signals(0
904//// + (1 << SIGINT)
905//// + (1 << SIGQUIT)
906//// + (1 << SIGTERM)
907//// , handler);
908////}
909
763#if ENABLE_HUSH_JOB 910#if ENABLE_HUSH_JOB
764 911
912/* helper */
913static unsigned maybe_set_sighandler(int sig, void (*handler)(int))
914{
915 /* non_DFL_mask'ed signals are, well, masked,
916 * no need to set handler for them.
917 * IGN_mask'ed signals were found to be IGN on entry,
918 * do not change that -> no need to set handler for them either
919 */
920 unsigned ign = ((G.IGN_mask|G.non_DFL_mask) >> sig) & 1;
921 if (!ign) {
922 handler = signal(sig, handler);
923 ign = (handler == SIG_IGN);
924 if (ign) /* restore back to IGN! */
925 signal(sig, handler);
926 }
927 return ign << sig; /* pass back knowledge about SIG_IGN */
928}
929/* Used only to set handler to restore pgrp on exit, and to reset it to DFL */
765static void set_fatal_sighandler(void (*handler)(int)) 930static void set_fatal_sighandler(void (*handler)(int))
766{ 931{
767 bb_signals(0 932 unsigned mask = 0;
768 + (1 << SIGILL) 933
769 + (1 << SIGTRAP) 934 if (HUSH_DEBUG) {
770 + (1 << SIGABRT) 935 mask |= maybe_set_sighandler(SIGILL , handler);
771 + (1 << SIGFPE) 936 mask |= maybe_set_sighandler(SIGFPE , handler);
772 + (1 << SIGBUS) 937 mask |= maybe_set_sighandler(SIGBUS , handler);
773 + (1 << SIGSEGV) 938 mask |= maybe_set_sighandler(SIGSEGV, handler);
939 mask |= maybe_set_sighandler(SIGTRAP, handler);
940 } /* else: hush is perfect. what SEGV? */
941
942 mask |= maybe_set_sighandler(SIGABRT, handler);
943
774 /* bash 3.2 seems to handle these just like 'fatal' ones */ 944 /* bash 3.2 seems to handle these just like 'fatal' ones */
775 + (1 << SIGHUP) 945 mask |= maybe_set_sighandler(SIGPIPE, handler);
776 + (1 << SIGPIPE) 946 mask |= maybe_set_sighandler(SIGALRM, handler);
777 + (1 << SIGALRM) 947 mask |= maybe_set_sighandler(SIGHUP , handler);
778 , handler); 948
949 /* if we aren't interactive... but in this case
950 * we never want to restore pgrp on exit, and this fn is not called */
951 /*mask |= maybe_set_sighandler(SIGTERM, handler); */
952 /*mask |= maybe_set_sighandler(SIGINT , handler); */
953
954 G.IGN_mask = mask;
779} 955}
780static void set_jobctrl_sighandler(void (*handler)(int)) 956/* Used only to suppress ^Z in `cmd` */
957static void IGN_jobctrl_signals(void)
781{ 958{
782 bb_signals(0 959 bb_signals(0
783 + (1 << SIGTSTP) 960 + (1 << SIGTSTP)
784 + (1 << SIGTTIN) 961 + (1 << SIGTTIN)
785 + (1 << SIGTTOU) 962 + (1 << SIGTTOU)
786 , handler); 963 , SIG_IGN);
787} 964}
788/* SIGCHLD is special and handled separately */ 965/* SIGCHLD is special and handled separately */
789 966
790static void set_every_sighandler(void (*handler)(int)) 967////static void set_every_sighandler(void (*handler)(int))
791{ 968////{
792 set_fatal_sighandler(handler); 969//// set_fatal_sighandler(handler);
793 set_jobctrl_sighandler(handler); 970//// set_jobctrl_sighandler(handler);
794 set_misc_sighandler(handler); 971//// set_misc_sighandler(handler);
795 signal(SIGCHLD, handler); 972//// signal(SIGCHLD, handler);
796} 973////}
797 974
798static void handler_ctrl_c(int sig UNUSED_PARAM) 975////static void handler_ctrl_c(int sig UNUSED_PARAM)
799{ 976////{
800 debug_printf_jobs("got sig %d\n", sig); 977//// debug_printf_jobs("got sig %d\n", sig);
801// as usual we can have all kinds of nasty problems with leaked malloc data here 978////// as usual we can have all kinds of nasty problems with leaked malloc data here
802 siglongjmp(G.toplevel_jb, 1); 979//// siglongjmp(G.toplevel_jb, 1);
803} 980////}
804 981
805static void handler_ctrl_z(int sig UNUSED_PARAM) 982////static void handler_ctrl_z(int sig UNUSED_PARAM)
806{ 983////{
807 pid_t pid; 984//// pid_t pid;
808 985////
809 debug_printf_jobs("got tty sig %d in pid %d\n", sig, getpid()); 986//// debug_printf_jobs("got tty sig %d in pid %d\n", sig, getpid());
810 987////
811 if (!BB_MMU) { 988//// if (!BB_MMU) {
812 fputs("Sorry, backgrounding (CTRL+Z) of foreground scripts not supported on nommu\n", stderr); 989//// fputs("Sorry, backgrounding (CTRL+Z) of foreground scripts not supported on nommu\n", stderr);
813 return; 990//// return;
814 } 991//// }
815 992////
816 pid = fork(); 993//// pid = fork();
817 if (pid < 0) /* can't fork. Pretend there was no ctrl-Z */ 994//// if (pid < 0) /* can't fork. Pretend there was no ctrl-Z */
818 return; 995//// return;
819 G.ctrl_z_flag = 1; 996//// G.ctrl_z_flag = 1;
820 if (!pid) { /* child */ 997//// if (!pid) { /* child */
821 if (ENABLE_HUSH_JOB) 998//// if (ENABLE_HUSH_JOB)
822 die_sleep = 0; /* let nofork's xfuncs die */ 999//// die_sleep = 0; /* let nofork's xfuncs die */
823 bb_setpgrp(); 1000//// bb_setpgrp();
824 debug_printf_jobs("set pgrp for child %d ok\n", getpid()); 1001//// debug_printf_jobs("set pgrp for child %d ok\n", getpid());
825 set_every_sighandler(SIG_DFL); 1002//////// set_every_sighandler(SIG_DFL);
826 raise(SIGTSTP); /* resend TSTP so that child will be stopped */ 1003//// raise(SIGTSTP); /* resend TSTP so that child will be stopped */
827 debug_printf_jobs("returning in child\n"); 1004//// debug_printf_jobs("returning in child\n");
828 /* return to nofork, it will eventually exit now, 1005//// /* return to nofork, it will eventually exit now,
829 * not return back to shell */ 1006//// * not return back to shell */
830 return; 1007//// return;
831 } 1008//// }
832 /* parent */ 1009//// /* parent */
833 /* finish filling up pipe info */ 1010//// /* finish filling up pipe info */
834 G.toplevel_list->pgrp = pid; /* child is in its own pgrp */ 1011//// G.toplevel_list->pgrp = pid; /* child is in its own pgrp */
835 G.toplevel_list->cmds[0].pid = pid; 1012//// G.toplevel_list->cmds[0].pid = pid;
836 /* parent needs to longjmp out of running nofork. 1013//// /* parent needs to longjmp out of running nofork.
837 * we will "return" exitcode 0, with child put in background */ 1014//// * we will "return" exitcode 0, with child put in background */
838// as usual we can have all kinds of nasty problems with leaked malloc data here 1015////// as usual we can have all kinds of nasty problems with leaked malloc data here
839 debug_printf_jobs("siglongjmp in parent\n"); 1016//// debug_printf_jobs("siglongjmp in parent\n");
840 siglongjmp(G.toplevel_jb, 1); 1017//// siglongjmp(G.toplevel_jb, 1);
841} 1018////}
842 1019
843/* Restores tty foreground process group, and exits. 1020/* Restores tty foreground process group, and exits.
844 * May be called as signal handler for fatal signal 1021 * May be called as signal handler for fatal signal
@@ -865,8 +1042,8 @@ static void sigexit(int sig)
865 1042
866#else /* !JOB */ 1043#else /* !JOB */
867 1044
868#define set_fatal_sighandler(handler) ((void)0) 1045#define set_fatal_sighandler(handler) ((void)0)
869#define set_jobctrl_sighandler(handler) ((void)0) 1046#define IGN_jobctrl_signals(handler) ((void)0)
870 1047
871#endif /* JOB */ 1048#endif /* JOB */
872 1049
@@ -874,8 +1051,11 @@ static void sigexit(int sig)
874static void hush_exit(int exitcode) NORETURN; 1051static void hush_exit(int exitcode) NORETURN;
875static void hush_exit(int exitcode) 1052static void hush_exit(int exitcode)
876{ 1053{
877 if (G.traps && G.traps[0].cmd) 1054 if (G.traps && G.traps[0] && G.traps[0][0]) {
878 handle_trap(0); 1055 char *argv[] = { NULL, xstrdup(G.traps[0]), NULL };
1056 builtin_eval(argv);
1057 free(argv[1]);
1058 }
879 1059
880 if (ENABLE_HUSH_JOB) { 1060 if (ENABLE_HUSH_JOB) {
881 fflush(NULL); /* flush all streams */ 1061 fflush(NULL); /* flush all streams */
@@ -2052,6 +2232,8 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, char **argv, int assignme
2052 } 2232 }
2053#endif 2233#endif
2054 2234
2235 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL);
2236
2055 debug_printf_exec("execing '%s'\n", argv[0]); 2237 debug_printf_exec("execing '%s'\n", argv[0]);
2056 execvp(argv[0], argv); 2238 execvp(argv[0], argv);
2057 bb_perror_msg("can't exec '%s'", argv[0]); 2239 bb_perror_msg("can't exec '%s'", argv[0]);
@@ -2200,6 +2382,8 @@ static int checkjobs(struct pipe* fg_pipe)
2200 pid_t childpid; 2382 pid_t childpid;
2201 int rcode = 0; 2383 int rcode = 0;
2202 2384
2385 debug_printf_jobs("checkjobs %p\n", fg_pipe);
2386
2203 attributes = WUNTRACED; 2387 attributes = WUNTRACED;
2204 if (fg_pipe == NULL) 2388 if (fg_pipe == NULL)
2205 attributes |= WNOHANG; 2389 attributes |= WNOHANG;
@@ -2459,7 +2643,7 @@ static int run_pipe(struct pipe *pi)
2459 2643
2460 /* Disable job control signals for shell (parent) and 2644 /* Disable job control signals for shell (parent) and
2461 * for initial child code after fork */ 2645 * for initial child code after fork */
2462 set_jobctrl_sighandler(SIG_IGN); 2646//// set_jobctrl_sighandler(SIG_IGN);
2463 2647
2464 /* Going to fork a child per each pipe member */ 2648 /* Going to fork a child per each pipe member */
2465 pi->alive_cmds = 0; 2649 pi->alive_cmds = 0;
@@ -2486,9 +2670,9 @@ static int run_pipe(struct pipe *pi)
2486 2670
2487 command->pid = BB_MMU ? fork() : vfork(); 2671 command->pid = BB_MMU ? fork() : vfork();
2488 if (!command->pid) { /* child */ 2672 if (!command->pid) { /* child */
2489 if (ENABLE_HUSH_JOB)
2490 die_sleep = 0; /* let nofork's xfuncs die */
2491#if ENABLE_HUSH_JOB 2673#if ENABLE_HUSH_JOB
2674 die_sleep = 0; /* let nofork's xfuncs die */
2675
2492 /* Every child adds itself to new process group 2676 /* Every child adds itself to new process group
2493 * with pgid == pid_of_first_child_in_pipe */ 2677 * with pgid == pid_of_first_child_in_pipe */
2494 if (G.run_list_level == 1 && G.interactive_fd) { 2678 if (G.run_list_level == 1 && G.interactive_fd) {
@@ -2514,9 +2698,9 @@ static int run_pipe(struct pipe *pi)
2514 setup_redirects(command, NULL); 2698 setup_redirects(command, NULL);
2515 2699
2516 /* Restore default handlers just prior to exec */ 2700 /* Restore default handlers just prior to exec */
2517 set_jobctrl_sighandler(SIG_DFL); 2701//// set_jobctrl_sighandler(SIG_DFL);
2518 set_misc_sighandler(SIG_DFL); 2702//// set_misc_sighandler(SIG_DFL);
2519 signal(SIGCHLD, SIG_DFL); 2703//// signal(SIGCHLD, SIG_DFL);
2520 /* Stores to nommu_save list of env vars putenv'ed 2704 /* Stores to nommu_save list of env vars putenv'ed
2521 * (NOMMU, on MMU we don't need that) */ 2705 * (NOMMU, on MMU we don't need that) */
2522 /* cast away volatility... */ 2706 /* cast away volatility... */
@@ -2693,6 +2877,8 @@ static int run_list(struct pipe *pi)
2693 * in order to return, no direct "return" statements please. 2877 * in order to return, no direct "return" statements please.
2694 * This helps to ensure that no memory is leaked. */ 2878 * This helps to ensure that no memory is leaked. */
2695 2879
2880//TODO: needs re-thinking
2881
2696#if ENABLE_HUSH_JOB 2882#if ENABLE_HUSH_JOB
2697 /* Example of nested list: "while true; do { sleep 1 | exit 2; } done". 2883 /* Example of nested list: "while true; do { sleep 1 | exit 2; } done".
2698 * We are saving state before entering outermost list ("while...done") 2884 * We are saving state before entering outermost list ("while...done")
@@ -2713,27 +2899,27 @@ static int run_list(struct pipe *pi)
2713 restore_nofork_data(&G.nofork_save); 2899 restore_nofork_data(&G.nofork_save);
2714 } 2900 }
2715#endif 2901#endif
2716 if (G.ctrl_z_flag) { 2902//// if (G.ctrl_z_flag) {
2717 /* ctrl-Z has forked and stored pid of the child in pi->pid. 2903//// /* ctrl-Z has forked and stored pid of the child in pi->pid.
2718 * Remember this child as background job */ 2904//// * Remember this child as background job */
2719 insert_bg_job(pi); 2905//// insert_bg_job(pi);
2720 } else { 2906//// } else {
2721 /* ctrl-C. We just stop doing whatever we were doing */ 2907 /* ctrl-C. We just stop doing whatever we were doing */
2722 bb_putchar('\n'); 2908 bb_putchar('\n');
2723 } 2909//// }
2724 USE_HUSH_LOOPS(loop_top = NULL;) 2910 USE_HUSH_LOOPS(loop_top = NULL;)
2725 USE_HUSH_LOOPS(G.depth_of_loop = 0;) 2911 USE_HUSH_LOOPS(G.depth_of_loop = 0;)
2726 rcode = 0; 2912 rcode = 0;
2727 goto ret; 2913 goto ret;
2728 } 2914 }
2729 /* ctrl-Z handler will store pid etc in pi */ 2915//// /* ctrl-Z handler will store pid etc in pi */
2730 G.toplevel_list = pi; 2916//// G.toplevel_list = pi;
2731 G.ctrl_z_flag = 0; 2917//// G.ctrl_z_flag = 0;
2732#if ENABLE_FEATURE_SH_STANDALONE 2918////#if ENABLE_FEATURE_SH_STANDALONE
2733 G.nofork_save.saved = 0; /* in case we will run a nofork later */ 2919//// G.nofork_save.saved = 0; /* in case we will run a nofork later */
2734#endif 2920////#endif
2735 signal_SA_RESTART_empty_mask(SIGTSTP, handler_ctrl_z); 2921//// signal_SA_RESTART_empty_mask(SIGTSTP, handler_ctrl_z);
2736 signal(SIGINT, handler_ctrl_c); 2922//// signal(SIGINT, handler_ctrl_c);
2737 } 2923 }
2738#endif /* JOB */ 2924#endif /* JOB */
2739 2925
@@ -2854,11 +3040,17 @@ static int run_list(struct pipe *pi)
2854 continue; /* not matched yet, skip this pipe */ 3040 continue; /* not matched yet, skip this pipe */
2855 } 3041 }
2856#endif 3042#endif
2857 if (pi->num_cmds == 0) 3043 /* Just pressing <enter> in shell should check for jobs.
2858 goto check_jobs_and_continue; 3044 * OTOH, in non-interactive shell this is useless
3045 * and only leads to extra job checks */
3046 if (pi->num_cmds == 0) {
3047 if (G.interactive_fd)
3048 goto check_jobs_and_continue;
3049 continue;
3050 }
2859 3051
2860 /* After analyzing all keywords and conditions, we decided 3052 /* After analyzing all keywords and conditions, we decided
2861 * to execute this pipe. NB: has to do checkjobs(NULL) 3053 * to execute this pipe. NB: have to do checkjobs(NULL)
2862 * after run_pipe() to collect any background children, 3054 * after run_pipe() to collect any background children,
2863 * even if list execution is to be stopped. */ 3055 * even if list execution is to be stopped. */
2864 debug_printf_exec(": run_pipe with %d members\n", pi->num_cmds); 3056 debug_printf_exec(": run_pipe with %d members\n", pi->num_cmds);
@@ -2871,6 +3063,7 @@ static int run_list(struct pipe *pi)
2871 if (r != -1) { 3063 if (r != -1) {
2872 /* we only ran a builtin: rcode is already known 3064 /* we only ran a builtin: rcode is already known
2873 * and we don't need to wait for anything. */ 3065 * and we don't need to wait for anything. */
3066 check_and_run_traps();
2874#if ENABLE_HUSH_LOOPS 3067#if ENABLE_HUSH_LOOPS
2875 /* was it "break" or "continue"? */ 3068 /* was it "break" or "continue"? */
2876 if (G.flag_break_continue) { 3069 if (G.flag_break_continue) {
@@ -2895,6 +3088,7 @@ static int run_list(struct pipe *pi)
2895 /* even bash 3.2 doesn't do that well with nested bg: 3088 /* even bash 3.2 doesn't do that well with nested bg:
2896 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &". 3089 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &".
2897 * I'm NOT treating inner &'s as jobs */ 3090 * I'm NOT treating inner &'s as jobs */
3091 check_and_run_traps();
2898#if ENABLE_HUSH_JOB 3092#if ENABLE_HUSH_JOB
2899 if (G.run_list_level == 1) 3093 if (G.run_list_level == 1)
2900 insert_bg_job(pi); 3094 insert_bg_job(pi);
@@ -2905,11 +3099,13 @@ static int run_list(struct pipe *pi)
2905 if (G.run_list_level == 1 && G.interactive_fd) { 3099 if (G.run_list_level == 1 && G.interactive_fd) {
2906 /* waits for completion, then fg's main shell */ 3100 /* waits for completion, then fg's main shell */
2907 rcode = checkjobs_and_fg_shell(pi); 3101 rcode = checkjobs_and_fg_shell(pi);
3102 check_and_run_traps();
2908 debug_printf_exec(": checkjobs_and_fg_shell returned %d\n", rcode); 3103 debug_printf_exec(": checkjobs_and_fg_shell returned %d\n", rcode);
2909 } else 3104 } else
2910#endif 3105#endif
2911 { /* this one just waits for completion */ 3106 { /* this one just waits for completion */
2912 rcode = checkjobs(pi); 3107 rcode = checkjobs(pi);
3108 check_and_run_traps();
2913 debug_printf_exec(": checkjobs returned %d\n", rcode); 3109 debug_printf_exec(": checkjobs returned %d\n", rcode);
2914 } 3110 }
2915 } 3111 }
@@ -2948,17 +3144,18 @@ static int run_list(struct pipe *pi)
2948 } /* for (pi) */ 3144 } /* for (pi) */
2949 3145
2950#if ENABLE_HUSH_JOB 3146#if ENABLE_HUSH_JOB
2951 if (G.ctrl_z_flag) { 3147//// if (G.ctrl_z_flag) {
2952 /* ctrl-Z forked somewhere in the past, we are the child, 3148//// /* ctrl-Z forked somewhere in the past, we are the child,
2953 * and now we completed running the list. Exit. */ 3149//// * and now we completed running the list. Exit. */
2954//TODO: _exit? 3150//////TODO: _exit?
2955 exit(rcode); 3151//// exit(rcode);
2956 } 3152//// }
2957 ret: 3153 ret:
2958 if (!--G.run_list_level && G.interactive_fd) { 3154 G.run_list_level--;
2959 signal(SIGTSTP, SIG_IGN); 3155//// if (!G.run_list_level && G.interactive_fd) {
2960 signal(SIGINT, SIG_IGN); 3156//// signal(SIGTSTP, SIG_IGN);
2961 } 3157//// signal(SIGINT, SIG_IGN);
3158//// }
2962#endif 3159#endif
2963 debug_printf_exec("run_list lvl %d return %d\n", G.run_list_level + 1, rcode); 3160 debug_printf_exec("run_list lvl %d return %d\n", G.run_list_level + 1, rcode);
2964#if ENABLE_HUSH_LOOPS 3161#if ENABLE_HUSH_LOOPS
@@ -3478,10 +3675,10 @@ static FILE *generate_stream_from_list(struct pipe *head)
3478 /* Process substitution is not considered to be usual 3675 /* Process substitution is not considered to be usual
3479 * 'command execution'. 3676 * 'command execution'.
3480 * SUSv3 says ctrl-Z should be ignored, ctrl-C should not. */ 3677 * SUSv3 says ctrl-Z should be ignored, ctrl-C should not. */
3481 /* Not needed, we are relying on it being disabled 3678//// /* Not needed, we are relying on it being disabled
3482 * everywhere outside actual command execution. */ 3679//// * everywhere outside actual command execution. */
3483 /*set_jobctrl_sighandler(SIG_IGN);*/ 3680 IGN_jobctrl_signals();
3484 set_misc_sighandler(SIG_DFL); 3681//// set_misc_sighandler(SIG_DFL);
3485 /* Freeing 'head' here would break NOMMU. */ 3682 /* Freeing 'head' here would break NOMMU. */
3486 _exit(run_list(head)); 3683 _exit(run_list(head));
3487 } 3684 }
@@ -4287,7 +4484,6 @@ static void setup_job_control(void)
4287 pid_t shell_pgrp; 4484 pid_t shell_pgrp;
4288 4485
4289 shell_pgrp = getpgrp(); 4486 shell_pgrp = getpgrp();
4290 close_on_exec_on(G.interactive_fd);
4291 4487
4292 /* If we were ran as 'hush &', 4488 /* If we were ran as 'hush &',
4293 * sleep until we are in the foreground. */ 4489 * sleep until we are in the foreground. */
@@ -4298,8 +4494,8 @@ static void setup_job_control(void)
4298 } 4494 }
4299 4495
4300 /* Ignore job-control and misc signals. */ 4496 /* Ignore job-control and misc signals. */
4301 set_jobctrl_sighandler(SIG_IGN); 4497//// set_jobctrl_sighandler(SIG_IGN);
4302 set_misc_sighandler(SIG_IGN); 4498//// set_misc_sighandler(SIG_IGN);
4303//huh? signal(SIGCHLD, SIG_IGN); 4499//huh? signal(SIGCHLD, SIG_IGN);
4304 4500
4305 /* We _must_ restore tty pgrp on fatal signals */ 4501 /* We _must_ restore tty pgrp on fatal signals */
@@ -4312,6 +4508,16 @@ static void setup_job_control(void)
4312} 4508}
4313#endif 4509#endif
4314 4510
4511static int set_mode(const char cstate, const char mode)
4512{
4513 int state = (cstate == '-' ? 1 : 0);
4514 switch (mode) {
4515 case 'n': G.fake_mode = state; break;
4516 case 'x': /*G.debug_mode = state;*/ break;
4517 default: return EXIT_FAILURE;
4518 }
4519 return EXIT_SUCCESS;
4520}
4315 4521
4316int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 4522int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
4317int hush_main(int argc, char **argv) 4523int hush_main(int argc, char **argv)
@@ -4408,7 +4614,7 @@ int hush_main(int argc, char **argv)
4408 break; 4614 break;
4409 case 'n': 4615 case 'n':
4410 case 'x': 4616 case 'x':
4411 if (!builtin_set_mode('-', opt)) 4617 if (!set_mode('-', opt))
4412 break; 4618 break;
4413 default: 4619 default:
4414#ifndef BB_VER 4620#ifndef BB_VER
@@ -4447,6 +4653,7 @@ int hush_main(int argc, char **argv)
4447 // to (inadvertently) close/redirect it 4653 // to (inadvertently) close/redirect it
4448 } 4654 }
4449 } 4655 }
4656 init_signal_mask();
4450 debug_printf("G.interactive_fd=%d\n", G.interactive_fd); 4657 debug_printf("G.interactive_fd=%d\n", G.interactive_fd);
4451 if (G.interactive_fd) { 4658 if (G.interactive_fd) {
4452 fcntl(G.interactive_fd, F_SETFD, FD_CLOEXEC); 4659 fcntl(G.interactive_fd, F_SETFD, FD_CLOEXEC);
@@ -4475,9 +4682,10 @@ int hush_main(int argc, char **argv)
4475 } 4682 }
4476 if (G.interactive_fd) { 4683 if (G.interactive_fd) {
4477 fcntl(G.interactive_fd, F_SETFD, FD_CLOEXEC); 4684 fcntl(G.interactive_fd, F_SETFD, FD_CLOEXEC);
4478 set_misc_sighandler(SIG_IGN); 4685//// set_misc_sighandler(SIG_IGN);
4479 } 4686 }
4480 } 4687 }
4688 init_signal_mask();
4481#endif 4689#endif
4482 4690
4483#if ENABLE_HUSH_INTERACTIVE && !ENABLE_FEATURE_SH_EXTRA_QUIET 4691#if ENABLE_HUSH_INTERACTIVE && !ENABLE_FEATURE_SH_EXTRA_QUIET
@@ -4530,93 +4738,63 @@ int lash_main(int argc, char **argv)
4530/* 4738/*
4531 * Built-ins 4739 * Built-ins
4532 */ 4740 */
4533/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#trap
4534 *
4535 * Traps are also evaluated immediately instead of being delayed properly:
4536 * http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_11
4537 * Example: hush -c 'trap "echo hi" 31; sleep 10; echo moo' & sleep 1; kill -31 $!
4538 * "hi" should not be displayed until the sleep finishes
4539 * This will have to get fixed ...
4540 */
4541static void handle_trap(int sig)
4542{
4543 int save_errno, save_rcode;
4544 char *argv[] = { NULL, G.traps[sig].cmd, NULL };
4545 /* Race! We transitioned from handled to ignore/default, but
4546 * the signal came in after updating .cmd but before we could
4547 * register the new signal handler.
4548 */
4549 if (!argv[1] || argv[1][0] == '\0')
4550 return;
4551 /* need to save/restore errno/$? across traps */
4552 save_errno = errno;
4553 save_rcode = G.last_return_code;
4554 builtin_eval(argv);
4555 errno = save_errno;
4556 G.last_return_code = save_rcode;
4557}
4558static int builtin_trap(char **argv) 4741static int builtin_trap(char **argv)
4559{ 4742{
4560 size_t i; 4743 int i;
4561 int sig; 4744 int sig;
4562 bool ign = false; 4745 char *new_cmd;
4563 char *new_cmd = NULL;
4564 4746
4565 if (!G.traps) 4747 if (!G.traps)
4566 G.traps = xzalloc(sizeof(*G.traps) * NSIG); 4748 G.traps = xzalloc(sizeof(G.traps[0]) * NSIG);
4567 4749
4568 if (!argv[1]) { 4750 if (!argv[1]) {
4569 /* No args: print all trapped. This isn't 100% correct as we should 4751 /* No args: print all trapped. This isn't 100% correct as we should
4570 * be escaping the cmd so that it can be pasted back in ... 4752 * be escaping the cmd so that it can be pasted back in ...
4571 */ 4753 */
4572 for (i = 0; i < NSIG; ++i) 4754 for (i = 0; i < NSIG; ++i)
4573 if (G.traps[i].cmd) 4755 if (G.traps[i])
4574 printf("trap -- '%s' %s\n", G.traps[i].cmd, get_signame(i)); 4756 printf("trap -- '%s' %s\n", G.traps[i], get_signame(i));
4575 return EXIT_SUCCESS; 4757 return EXIT_SUCCESS;
4576 } 4758 }
4577 4759
4578 /* first arg is decimal: reset all specified */ 4760 new_cmd = NULL;
4579 sig = bb_strtou(argv[1], NULL, 10); 4761 i = 0;
4762 /* if first arg is decimal: reset all specified */
4763 sig = bb_strtou(*++argv, NULL, 10);
4580 if (errno == 0) { 4764 if (errno == 0) {
4581 int ret; 4765 int ret;
4582 i = 0;
4583 set_all: 4766 set_all:
4584 ret = EXIT_SUCCESS; 4767 ret = EXIT_SUCCESS;
4585 while (argv[++i]) { 4768 while (*argv) {
4586 char *old_cmd; 4769 sig = get_signum(*argv++);
4587
4588 sig = get_signum(argv[i]);
4589 if (sig < 0 || sig >= NSIG) { 4770 if (sig < 0 || sig >= NSIG) {
4590 ret = EXIT_FAILURE; 4771 ret = EXIT_FAILURE;
4772 /* mimic bash message exactly */
4591 bb_perror_msg("trap: %s: invalid signal specification", argv[i]); 4773 bb_perror_msg("trap: %s: invalid signal specification", argv[i]);
4592 continue; 4774 continue;
4593 } 4775 }
4594 4776
4595 /* Make sure .cmd is always a valid command list since 4777 free(G.traps[sig]);
4596 * signals can occur at any time ... 4778 G.traps[sig] = xstrdup(new_cmd);
4597 */
4598 old_cmd = G.traps[sig].cmd;
4599 G.traps[sig].cmd = xstrdup(new_cmd);
4600 free(old_cmd);
4601 4779
4602 debug_printf("trap: setting SIG%s (%i) to: %s", 4780 debug_printf("trap: setting SIG%s (%i) to '%s'",
4603 get_signame(sig), sig, G.traps[sig].cmd); 4781 get_signame(sig), sig, G.traps[sig]);
4604 4782
4605 /* There is no signal for 0 (EXIT) */ 4783 /* There is no signal for 0 (EXIT) */
4606 if (sig == 0) 4784 if (sig == 0)
4607 continue; 4785 continue;
4608 4786
4609 if (new_cmd) { 4787 if (new_cmd) {
4610 /* add/update a handler */ 4788 sigaddset(&G.blocked_set, sig);
4611 struct sigaction act = { 4789 } else {
4612 .sa_handler = ign ? SIG_IGN : handle_trap, 4790 /* there was a trap handler, we are removing it
4613 .sa_flags = SA_RESTART, 4791 * (if sig has non-DFL handling,
4614 }; 4792 * we don't need to do anything) */
4615 sigemptyset(&act.sa_mask); 4793 if (sig < 32 && (G.non_DFL_mask & (1 << sig)))
4616 sigaction(sig, &act, old_cmd ? NULL : &G.traps[sig].oact); 4794 continue;
4617 } else if (old_cmd && !new_cmd) 4795 sigdelset(&G.blocked_set, sig);
4618 /* there was a handler, and we are removing it */ 4796 }
4619 sigaction_set(sig, &G.traps[sig].oact); 4797 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
4620 } 4798 }
4621 return ret; 4799 return ret;
4622 } 4800 }
@@ -4624,17 +4802,15 @@ static int builtin_trap(char **argv)
4624 /* first arg is "-": reset all specified to default */ 4802 /* first arg is "-": reset all specified to default */
4625 /* first arg is "": ignore all specified */ 4803 /* first arg is "": ignore all specified */
4626 /* everything else: execute first arg upon signal */ 4804 /* everything else: execute first arg upon signal */
4627 if (!argv[2]) { 4805 if (!argv[1]) {
4628 bb_error_msg("trap: invalid arguments"); 4806 bb_error_msg("trap: invalid arguments");
4629 return EXIT_FAILURE; 4807 return EXIT_FAILURE;
4630 } 4808 }
4631 if (LONE_DASH(argv[1])) 4809 if (LONE_DASH(*argv))
4632 /* nothing! */; 4810 /* nothing! */;
4633 else 4811 else
4634 new_cmd = argv[1]; 4812 new_cmd = *argv;
4635 if (argv[1][0] == '\0') 4813 argv++;
4636 ign = true;
4637 i = 1;
4638 goto set_all; 4814 goto set_all;
4639} 4815}
4640 4816
@@ -4891,16 +5067,6 @@ static int builtin_read(char **argv)
4891 * 5067 *
4892 * So far, we only support "set -- [argument...]" and some of the short names. 5068 * So far, we only support "set -- [argument...]" and some of the short names.
4893 */ 5069 */
4894static int builtin_set_mode(const char cstate, const char mode)
4895{
4896 int state = (cstate == '-' ? 1 : 0);
4897 switch (mode) {
4898 case 'n': G.fake_mode = state; break;
4899 case 'x': /*G.debug_mode = state;*/ break;
4900 default: return EXIT_FAILURE;
4901 }
4902 return EXIT_SUCCESS;
4903}
4904static int builtin_set(char **argv) 5070static int builtin_set(char **argv)
4905{ 5071{
4906 int n; 5072 int n;
@@ -4922,7 +5088,7 @@ static int builtin_set(char **argv)
4922 5088
4923 if (arg[0] == '+' || arg[0] == '-') { 5089 if (arg[0] == '+' || arg[0] == '-') {
4924 for (n = 1; arg[n]; ++n) 5090 for (n = 1; arg[n]; ++n)
4925 if (builtin_set_mode(arg[0], arg[n])) 5091 if (set_mode(arg[0], arg[n]))
4926 goto error; 5092 goto error;
4927 continue; 5093 continue;
4928 } 5094 }
@@ -5068,27 +5234,29 @@ static int builtin_wait(char **argv)
5068 int ret = EXIT_SUCCESS; 5234 int ret = EXIT_SUCCESS;
5069 int status; 5235 int status;
5070 5236
5071 if (argv[1] == NULL) 5237 if (*++argv == NULL)
5072 /* don't care about exit status */ 5238 /* don't care about exit status */
5073 wait(&status); 5239 wait(NULL);
5074 5240
5075 while (argv[1]) { 5241 while (*argv) {
5076 pid_t pid = bb_strtou(argv[1], NULL, 10); 5242 pid_t pid = bb_strtou(*argv, NULL, 10);
5077 if (errno) { 5243 if (errno) {
5078 bb_perror_msg("wait %s", argv[1]); 5244 /* mimic bash message */
5245 bb_error_msg("wait: '%s': not a pid or valid job spec", *argv);
5079 return EXIT_FAILURE; 5246 return EXIT_FAILURE;
5080 } else if (waitpid(pid, &status, 0) == pid) { 5247 }
5248 if (waitpid(pid, &status, 0) == pid) {
5081 if (WIFSIGNALED(status)) 5249 if (WIFSIGNALED(status))
5082 ret = 128 + WTERMSIG(status); 5250 ret = 128 + WTERMSIG(status);
5083 else if (WIFEXITED(status)) 5251 else if (WIFEXITED(status))
5084 ret = WEXITSTATUS(status); 5252 ret = WEXITSTATUS(status);
5085 else 5253 else /* wtf? */
5086 ret = EXIT_FAILURE; 5254 ret = EXIT_FAILURE;
5087 } else { 5255 } else {
5088 bb_perror_msg("wait %s", argv[1]); 5256 bb_perror_msg("wait %s", *argv);
5089 ret = 127; 5257 ret = 127;
5090 } 5258 }
5091 ++argv; 5259 argv++;
5092 } 5260 }
5093 5261
5094 return ret; 5262 return ret;