diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-03-31 11:22:57 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-03-31 11:22:57 +0000 |
commit | d5762932fbcbc0a385047945276f10e2f3fea12d (patch) | |
tree | 7f48d6b4f8da360f68a4efd662e5d8de773fb001 | |
parent | d690f68554f1c1301975bc0ab0e479e6870b3589 (diff) | |
download | busybox-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.c | 584 |
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); | |||
521 | static int builtin_pwd(char **argv); | 525 | static int builtin_pwd(char **argv); |
522 | static int builtin_read(char **argv); | 526 | static int builtin_read(char **argv); |
523 | static int builtin_test(char **argv); | 527 | static int builtin_test(char **argv); |
524 | static void handle_trap(int sig); | ||
525 | static int builtin_trap(char **argv); | 528 | static int builtin_trap(char **argv); |
526 | static int builtin_true(char **argv); | 529 | static int builtin_true(char **argv); |
527 | static int builtin_set(char **argv); | 530 | static int builtin_set(char **argv); |
528 | static int builtin_set_mode(const char, const char); | ||
529 | static int builtin_shift(char **argv); | 531 | static int builtin_shift(char **argv); |
530 | static int builtin_source(char **argv); | 532 | static int builtin_source(char **argv); |
531 | static int builtin_umask(char **argv); | 533 | static 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 |
754 | static 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 */ | ||
833 | static 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 | } | ||
863 | static 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 */ | ||
913 | static 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 */ | ||
765 | static void set_fatal_sighandler(void (*handler)(int)) | 930 | static 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 | } |
780 | static void set_jobctrl_sighandler(void (*handler)(int)) | 956 | /* Used only to suppress ^Z in `cmd` */ |
957 | static 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 | ||
790 | static 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 | ||
798 | static 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 | ||
805 | static 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) | |||
874 | static void hush_exit(int exitcode) NORETURN; | 1051 | static void hush_exit(int exitcode) NORETURN; |
875 | static void hush_exit(int exitcode) | 1052 | static 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 | ||
4511 | static 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 | ||
4316 | int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 4522 | int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
4317 | int hush_main(int argc, char **argv) | 4523 | int 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 | */ | ||
4541 | static 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 | } | ||
4558 | static int builtin_trap(char **argv) | 4741 | static 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 | */ |
4894 | static 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 | } | ||
4904 | static int builtin_set(char **argv) | 5070 | static 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; |