aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-04-05 19:13:39 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-04-05 19:13:39 +0000
commitf9375285719035dbf2f7003d582c22447ed579f0 (patch)
treebfc4fcab7ae9f73bebe1e89d34aca33af332f57f
parent46f9b6db80e4fd0a1c50d435bc387ad28d12abb2 (diff)
downloadbusybox-w32-f9375285719035dbf2f7003d582c22447ed579f0.tar.gz
busybox-w32-f9375285719035dbf2f7003d582c22447ed579f0.tar.bz2
busybox-w32-f9375285719035dbf2f7003d582c22447ed579f0.zip
hush: audit and fix "interactive shell" setup code.
function old new delta block_signals - 139 +139 maybe_set_to_sigexit - 47 +47 run_list 2018 2030 +12 expand_variables 2155 2165 +10 maybe_set_sighandler 47 - -47 hush_main 992 918 -74 ------------------------------------------------------------------------------ (add/remove: 2/1 grow/shrink: 2/1 up/down: 208/-121) Total: 87 bytes
-rw-r--r--shell/hush.c323
1 files changed, 175 insertions, 148 deletions
diff --git a/shell/hush.c b/shell/hush.c
index eba7a86df..a3f80d512 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -850,8 +850,6 @@ static void free_strings(char **strings)
850 * Note: as a result, we do not use signal handlers much. The only uses 850 * Note: as a result, we do not use signal handlers much. The only uses
851 * are to count SIGCHLDs [disabled - bug somewhere, + bloat] 851 * are to count SIGCHLDs [disabled - bug somewhere, + bloat]
852 * and to restore tty pgrp on signal-induced exit. 852 * and to restore tty pgrp on signal-induced exit.
853 *
854 * TODO: check/fix wait builtin to be interruptible.
855 */ 853 */
856 854
857//static void SIGCHLD_handler(int sig UNUSED_PARAM) 855//static void SIGCHLD_handler(int sig UNUSED_PARAM)
@@ -859,36 +857,6 @@ static void free_strings(char **strings)
859// G.count_SIGCHLD++; 857// G.count_SIGCHLD++;
860//} 858//}
861 859
862/* called once at shell init */
863static void init_signal_mask(void)
864{
865 unsigned sig;
866 unsigned mask = (1 << SIGQUIT);
867 if (G_interactive_fd) {
868 mask = 0
869 | (1 << SIGQUIT)
870 | (1 << SIGTERM)
871 | (1 << SIGHUP)
872#if ENABLE_HUSH_JOB
873 | (1 << SIGTTIN) | (1 << SIGTTOU) | (1 << SIGTSTP)
874#endif
875 | (1 << SIGINT)
876 ;
877 }
878 G.non_DFL_mask = mask;
879
880 sigprocmask(SIG_SETMASK, NULL, &G.blocked_set);
881 sig = 0;
882 while (mask) {
883 if (mask & 1)
884 sigaddset(&G.blocked_set, sig);
885 mask >>= 1;
886 sig++;
887 }
888 sigdelset(&G.blocked_set, SIGCHLD);
889 sigprocmask(SIG_SETMASK, &G.blocked_set, &G.inherited_set);
890}
891
892static int check_and_run_traps(int sig) 860static int check_and_run_traps(int sig)
893{ 861{
894 static const struct timespec zero_timespec = { 0, 0 }; 862 static const struct timespec zero_timespec = { 0, 0 };
@@ -934,7 +902,6 @@ static int check_and_run_traps(int sig)
934} 902}
935 903
936#if ENABLE_HUSH_JOB 904#if ENABLE_HUSH_JOB
937
938/* Restores tty foreground process group, and exits. 905/* Restores tty foreground process group, and exits.
939 * May be called as signal handler for fatal signal 906 * May be called as signal handler for fatal signal
940 * (will faithfully resend signal to itself, producing correct exit state) 907 * (will faithfully resend signal to itself, producing correct exit state)
@@ -957,48 +924,6 @@ static void sigexit(int sig)
957 924
958 kill_myself_with_sig(sig); /* does not return */ 925 kill_myself_with_sig(sig); /* does not return */
959} 926}
960
961/* helper */
962static void maybe_set_sighandler(int sig)
963{
964 void (*handler)(int);
965 /* non_DFL_mask'ed signals are, well, masked,
966 * no need to set handler for them.
967 */
968 if (!((G.non_DFL_mask >> sig) & 1)) {
969 handler = signal(sig, sigexit);
970 if (handler == SIG_IGN) /* oops... restore back to IGN! */
971 signal(sig, handler);
972 }
973}
974/* Used only to set handler to restore pgrp on exit */
975static void set_fatal_signals_to_sigexit(void)
976{
977 if (HUSH_DEBUG) {
978 maybe_set_sighandler(SIGILL );
979 maybe_set_sighandler(SIGFPE );
980 maybe_set_sighandler(SIGBUS );
981 maybe_set_sighandler(SIGSEGV);
982 maybe_set_sighandler(SIGTRAP);
983 } /* else: hush is perfect. what SEGV? */
984
985 maybe_set_sighandler(SIGABRT);
986
987 /* bash 3.2 seems to handle these just like 'fatal' ones */
988 maybe_set_sighandler(SIGPIPE);
989 maybe_set_sighandler(SIGALRM);
990 maybe_set_sighandler(SIGHUP );
991
992 /* if we aren't interactive... but in this case
993 * we never want to restore pgrp on exit, and this fn is not called */
994 /*maybe_set_sighandler(SIGTERM);*/
995 /*maybe_set_sighandler(SIGINT );*/
996}
997
998#else /* !JOB */
999
1000#define set_fatal_signals_to_sigexit(handler) ((void)0)
1001
1002#endif 927#endif
1003 928
1004/* Restores tty foreground process group, and exits. */ 929/* Restores tty foreground process group, and exits. */
@@ -1007,6 +932,7 @@ static void hush_exit(int exitcode)
1007{ 932{
1008 if (G.traps && G.traps[0] && G.traps[0][0]) { 933 if (G.traps && G.traps[0] && G.traps[0][0]) {
1009 char *argv[] = { NULL, xstrdup(G.traps[0]), NULL }; 934 char *argv[] = { NULL, xstrdup(G.traps[0]), NULL };
935//TODO: do we need to prevent recursion?
1010 builtin_eval(argv); 936 builtin_eval(argv);
1011 free(argv[1]); 937 free(argv[1]);
1012 } 938 }
@@ -2896,7 +2822,7 @@ static int run_pipe(struct pipe *pi)
2896 command->pid = BB_MMU ? fork() : vfork(); 2822 command->pid = BB_MMU ? fork() : vfork();
2897 if (!command->pid) { /* child */ 2823 if (!command->pid) { /* child */
2898#if ENABLE_HUSH_JOB 2824#if ENABLE_HUSH_JOB
2899 die_sleep = 0; /* let nofork's xfuncs die */ 2825 die_sleep = 0; /* do not restore tty pgrp on xfunc death */
2900 2826
2901 /* Every child adds itself to new process group 2827 /* Every child adds itself to new process group
2902 * with pgid == pid_of_first_child_in_pipe */ 2828 * with pgid == pid_of_first_child_in_pipe */
@@ -2930,7 +2856,10 @@ static int run_pipe(struct pipe *pi)
2930 /* pseudo_exec() does not return */ 2856 /* pseudo_exec() does not return */
2931 } 2857 }
2932 2858
2933 /* parent */ 2859 /* parent or error */
2860#if ENABLE_HUSH_JOB
2861 die_sleep = -1; /* restore tty pgrp on xfunc death */
2862#endif
2934#if !BB_MMU 2863#if !BB_MMU
2935 /* Clean up after vforked child */ 2864 /* Clean up after vforked child */
2936 clean_up_after_re_execute(); 2865 clean_up_after_re_execute();
@@ -3900,6 +3829,9 @@ static FILE *generate_stream_from_string(const char *s)
3900 bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork"); 3829 bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork");
3901 3830
3902 if (pid == 0) { /* child */ 3831 if (pid == 0) { /* child */
3832#if ENABLE_HUSH_JOB
3833 die_sleep = 0; /* do not restore tty pgrp on xfunc death */
3834#endif
3903 /* Process substitution is not considered to be usual 3835 /* Process substitution is not considered to be usual
3904 * 'command execution'. 3836 * 'command execution'.
3905 * SUSv3 says ctrl-Z should be ignored, ctrl-C should not. 3837 * SUSv3 says ctrl-Z should be ignored, ctrl-C should not.
@@ -3909,8 +3841,6 @@ static FILE *generate_stream_from_string(const char *s)
3909 + (1 << SIGTTIN) 3841 + (1 << SIGTTIN)
3910 + (1 << SIGTTOU) 3842 + (1 << SIGTTOU)
3911 , SIG_IGN); 3843 , SIG_IGN);
3912 if (ENABLE_HUSH_JOB)
3913 die_sleep = 0; /* let nofork's xfuncs die */
3914 close(channel[0]); /* NB: close _first_, then move fd! */ 3844 close(channel[0]); /* NB: close _first_, then move fd! */
3915 xmove_fd(channel[1], 1); 3845 xmove_fd(channel[1], 1);
3916 /* Prevent it from trying to handle ctrl-z etc */ 3846 /* Prevent it from trying to handle ctrl-z etc */
@@ -3920,8 +3850,8 @@ static FILE *generate_stream_from_string(const char *s)
3920 _exit(G.last_return_code); 3850 _exit(G.last_return_code);
3921#else 3851#else
3922 /* We re-execute after vfork on NOMMU. This makes this script safe: 3852 /* We re-execute after vfork on NOMMU. This makes this script safe:
3923 * yes "0123456789012345678901234567890" | dd bs=32 count=64k >TESTFILE 3853 * yes "0123456789012345678901234567890" | dd bs=32 count=64k >BIG
3924 * huge=`cat TESTFILE` # was blocking here forever 3854 * huge=`cat BIG` # was blocking here forever
3925 * echo OK 3855 * echo OK
3926 */ 3856 */
3927 re_execute_shell(s); 3857 re_execute_shell(s);
@@ -3929,6 +3859,9 @@ static FILE *generate_stream_from_string(const char *s)
3929 } 3859 }
3930 3860
3931 /* parent */ 3861 /* parent */
3862#if ENABLE_HUSH_JOB
3863 die_sleep = -1; /* restore tty pgrp on xfunc death */
3864#endif
3932 clean_up_after_re_execute(); 3865 clean_up_after_re_execute();
3933 close(channel[1]); 3866 close(channel[1]);
3934 pf = fdopen(channel[0], "r"); 3867 pf = fdopen(channel[0], "r");
@@ -4945,31 +4878,81 @@ static void parse_and_run_file(FILE *f)
4945 parse_and_run_stream(&input, ';'); 4878 parse_and_run_stream(&input, ';');
4946} 4879}
4947 4880
4948#if ENABLE_HUSH_JOB 4881/* Called a few times only (or even once if "sh -c") */
4949/* Make sure we have a controlling tty. If we get started under a job 4882static void block_signals(int second_time)
4950 * aware app (like bash for example), make sure we are now in charge so
4951 * we don't fight over who gets the foreground */
4952static void setup_job_control(void)
4953{ 4883{
4954 pid_t shell_pgrp; 4884 unsigned sig;
4885 unsigned mask;
4955 4886
4956 shell_pgrp = getpgrp(); 4887 mask = (1 << SIGQUIT);
4888 if (G_interactive_fd) {
4889 mask = 0
4890 | (1 << SIGQUIT)
4891 | (1 << SIGTERM)
4892 | (1 << SIGHUP)
4893#if ENABLE_HUSH_JOB
4894 | (1 << SIGTTIN) | (1 << SIGTTOU) | (1 << SIGTSTP)
4895#endif
4896 | (1 << SIGINT)
4897 ;
4898 }
4899 G.non_DFL_mask = mask;
4957 4900
4958 /* If we were ran as 'hush &', 4901 if (!second_time)
4959 * sleep until we are in the foreground. */ 4902 sigprocmask(SIG_SETMASK, NULL, &G.blocked_set);
4960 while (tcgetpgrp(G_interactive_fd) != shell_pgrp) { 4903 sig = 0;
4961 /* Send TTIN to ourself (should stop us) */ 4904 while (mask) {
4962 kill(- shell_pgrp, SIGTTIN); 4905 if (mask & 1)
4963 shell_pgrp = getpgrp(); 4906 sigaddset(&G.blocked_set, sig);
4907 mask >>= 1;
4908 sig++;
4964 } 4909 }
4910 sigdelset(&G.blocked_set, SIGCHLD);
4965 4911
4966 /* We _must_ restore tty pgrp on fatal signals */ 4912 sigprocmask(SIG_SETMASK, &G.blocked_set,
4967 set_fatal_signals_to_sigexit(); 4913 second_time ? NULL : &G.inherited_set);
4914 /* POSIX allows shell to re-enable SIGCHLD
4915 * even if it was SIG_IGN on entry */
4916// G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */
4917 if (!second_time)
4918 signal(SIGCHLD, SIG_DFL); // SIGCHLD_handler);
4919}
4968 4920
4969 /* Put ourselves in our own process group. */ 4921#if ENABLE_HUSH_JOB
4970 bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ 4922/* helper */
4971 /* Grab control of the terminal. */ 4923static void maybe_set_to_sigexit(int sig)
4972 tcsetpgrp(G_interactive_fd, getpid()); 4924{
4925 void (*handler)(int);
4926 /* non_DFL_mask'ed signals are, well, masked,
4927 * no need to set handler for them.
4928 */
4929 if (!((G.non_DFL_mask >> sig) & 1)) {
4930 handler = signal(sig, sigexit);
4931 if (handler == SIG_IGN) /* oops... restore back to IGN! */
4932 signal(sig, handler);
4933 }
4934}
4935/* Set handlers to restore tty pgrm and exit */
4936static void set_fatal_handlers(void)
4937{
4938 /* We _must_ restore tty pgrp on fatal signals */
4939 if (HUSH_DEBUG) {
4940 maybe_set_to_sigexit(SIGILL );
4941 maybe_set_to_sigexit(SIGFPE );
4942 maybe_set_to_sigexit(SIGBUS );
4943 maybe_set_to_sigexit(SIGSEGV);
4944 maybe_set_to_sigexit(SIGTRAP);
4945 } /* else: hush is perfect. what SEGV? */
4946 maybe_set_to_sigexit(SIGABRT);
4947 /* bash 3.2 seems to handle these just like 'fatal' ones */
4948 maybe_set_to_sigexit(SIGPIPE);
4949 maybe_set_to_sigexit(SIGALRM);
4950 maybe_set_to_sigexit(SIGHUP );
4951 /* if we are interactive, SIGTERM and SIGINT are masked.
4952 * if we aren't interactive... but in this case
4953 * we never want to restore pgrp on exit, and this fn is not called */
4954 /*maybe_set_to_sigexit(SIGTERM);*/
4955 /*maybe_set_to_sigexit(SIGINT );*/
4973} 4956}
4974#endif 4957#endif
4975 4958
@@ -4994,7 +4977,7 @@ int hush_main(int argc, char **argv)
4994 .flg_export = 1, 4977 .flg_export = 1,
4995 .flg_read_only = 1, 4978 .flg_read_only = 1,
4996 }; 4979 };
4997 4980 int signal_mask_is_inited = 0;
4998 int opt; 4981 int opt;
4999 char **e; 4982 char **e;
5000 struct variable *cur_var; 4983 struct variable *cur_var;
@@ -5060,6 +5043,7 @@ int hush_main(int argc, char **argv)
5060 optind--; 5043 optind--;
5061 } /* else -c 'script' PAR0 PAR1: $0 is PAR0 */ 5044 } /* else -c 'script' PAR0 PAR1: $0 is PAR0 */
5062 G.global_argc = argc - optind; 5045 G.global_argc = argc - optind;
5046 block_signals(0); /* 0: called 1st time */
5063 parse_and_run_string(optarg); 5047 parse_and_run_string(optarg);
5064 goto final_return; 5048 goto final_return;
5065 case 'i': 5049 case 'i':
@@ -5104,10 +5088,12 @@ int hush_main(int argc, char **argv)
5104 bb_show_usage(); 5088 bb_show_usage();
5105#endif 5089#endif
5106 } 5090 }
5107 } 5091 } /* option parsing loop */
5108 5092
5109 if (!G.root_pid) 5093 if (!G.root_pid)
5110 G.root_pid = getpid(); 5094 G.root_pid = getpid();
5095
5096 /* If we are login shell... */
5111 if (argv[0] && argv[0][0] == '-') { 5097 if (argv[0] && argv[0][0] == '-') {
5112 FILE *input; 5098 FILE *input;
5113 /* XXX what should argv be while sourcing /etc/profile? */ 5099 /* XXX what should argv be while sourcing /etc/profile? */
@@ -5115,26 +5101,57 @@ int hush_main(int argc, char **argv)
5115 input = fopen_for_read("/etc/profile"); 5101 input = fopen_for_read("/etc/profile");
5116 if (input != NULL) { 5102 if (input != NULL) {
5117 close_on_exec_on(fileno(input)); 5103 close_on_exec_on(fileno(input));
5104 block_signals(0); /* 0: called 1st time */
5105 signal_mask_is_inited = 1;
5118 parse_and_run_file(input); 5106 parse_and_run_file(input);
5119 fclose(input); 5107 fclose(input);
5120 } 5108 }
5109 /* bash: after sourcing /etc/profile,
5110 * tries to source (in the given order):
5111 * ~/.bash_profile, ~/.bash_login, ~/.profile,
5112 * stopping of first found. --noprofile turns this off.
5113 * bash also sources ~/.bash_logout on exit.
5114 * If called as sh, skips .bash_XXX files.
5115 */
5121 } 5116 }
5122 5117
5123#if ENABLE_HUSH_JOB 5118 if (argv[optind]) {
5119 FILE *input;
5120 /*
5121 * Non-interactive "bash <script>" sources $BASH_ENV here
5122 * (without scanning $PATH).
5123 * If called as sh, does the same but with $ENV.
5124 */
5125 debug_printf("running script '%s'\n", argv[optind]);
5126 G.global_argv = argv + optind;
5127 G.global_argc = argc - optind;
5128 input = xfopen_for_read(argv[optind]);
5129 close_on_exec_on(fileno(input));
5130 if (!signal_mask_is_inited)
5131 block_signals(0); /* 0: called 1st time */
5132 parse_and_run_file(input);
5133#if ENABLE_FEATURE_CLEAN_UP
5134 fclose(input);
5135#endif
5136 goto final_return;
5137 }
5138
5139 /* Up to here, shell was non-interactive. Now it may become one. */
5140
5124 /* A shell is interactive if the '-i' flag was given, or if all of 5141 /* A shell is interactive if the '-i' flag was given, or if all of
5125 * the following conditions are met: 5142 * the following conditions are met:
5126 * no -c command 5143 * no -c command
5127 * no arguments remaining or the -s flag given 5144 * no arguments remaining or the -s flag given
5128 * standard input is a terminal 5145 * standard input is a terminal
5129 * standard output is a terminal 5146 * standard output is a terminal
5130 * Refer to Posix.2, the description of the 'sh' utility. */ 5147 * Refer to Posix.2, the description of the 'sh' utility.
5131 if (argv[optind] == NULL 5148 */
5132 && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) 5149#if ENABLE_HUSH_JOB
5133 ) { 5150 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
5134 G.saved_tty_pgrp = tcgetpgrp(STDIN_FILENO); 5151 G.saved_tty_pgrp = tcgetpgrp(STDIN_FILENO);
5135 debug_printf("saved_tty_pgrp=%d\n", G.saved_tty_pgrp); 5152 debug_printf("saved_tty_pgrp:%d\n", G.saved_tty_pgrp);
5136 if (G.saved_tty_pgrp >= 0) { 5153 if (G.saved_tty_pgrp >= 0) {
5137 /* try to dup to high fd#, >= 255 */ 5154 /* try to dup stdin to high fd#, >= 255 */
5138 G_interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255); 5155 G_interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255);
5139 if (G_interactive_fd < 0) { 5156 if (G_interactive_fd < 0) {
5140 /* try to dup to any fd */ 5157 /* try to dup to any fd */
@@ -5147,12 +5164,35 @@ int hush_main(int argc, char **argv)
5147// to (inadvertently) close/redirect it 5164// to (inadvertently) close/redirect it
5148 } 5165 }
5149 } 5166 }
5150 init_signal_mask(); /* note: ensures SIGCHLD is not masked */ 5167 debug_printf("interactive_fd:%d\n", G_interactive_fd);
5151 debug_printf("interactive_fd=%d\n", G_interactive_fd);
5152 if (G_interactive_fd) { 5168 if (G_interactive_fd) {
5153 fcntl(G_interactive_fd, F_SETFD, FD_CLOEXEC); 5169 pid_t shell_pgrp;
5154 /* Looks like they want an interactive shell */ 5170
5155 setup_job_control(); 5171 /* We are indeed interactive shell, and we will perform
5172 * job control. Setting up for that. */
5173
5174 close_on_exec_on(G_interactive_fd);
5175 /* If we were run as 'hush &', sleep until we are
5176 * in the foreground (tty pgrp == our pgrp).
5177 * If we get started under a job aware app (like bash),
5178 * make sure we are now in charge so we don't fight over
5179 * who gets the foreground */
5180 while (1) {
5181 shell_pgrp = getpgrp();
5182 G.saved_tty_pgrp = tcgetpgrp(G_interactive_fd);
5183 if (G.saved_tty_pgrp == shell_pgrp)
5184 break;
5185 /* send TTIN to ourself (should stop us) */
5186 kill(- shell_pgrp, SIGTTIN);
5187 }
5188 /* Block some signals */
5189 block_signals(signal_mask_is_inited);
5190 /* Set other signals to restore saved_tty_pgrp */
5191 set_fatal_handlers();
5192 /* Put ourselves in our own process group */
5193 bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */
5194 /* Grab control of the terminal */
5195 tcsetpgrp(G_interactive_fd, getpid());
5156 /* -1 is special - makes xfuncs longjmp, not exit 5196 /* -1 is special - makes xfuncs longjmp, not exit
5157 * (we reset die_sleep = 0 whereever we [v]fork) */ 5197 * (we reset die_sleep = 0 whereever we [v]fork) */
5158 die_sleep = -1; 5198 die_sleep = -1;
@@ -5160,12 +5200,12 @@ int hush_main(int argc, char **argv)
5160 /* xfunc has failed! die die die */ 5200 /* xfunc has failed! die die die */
5161 hush_exit(xfunc_error_retval); 5201 hush_exit(xfunc_error_retval);
5162 } 5202 }
5163 } 5203 } else if (!signal_mask_is_inited) {
5204 block_signals(0); /* 0: called 1st time */
5205 } /* else: block_signals(0) was done before */
5164#elif ENABLE_HUSH_INTERACTIVE 5206#elif ENABLE_HUSH_INTERACTIVE
5165/* no job control compiled, only prompt/line editing */ 5207 /* No job control compiled in, only prompt/line editing */
5166 if (argv[optind] == NULL 5208 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
5167 && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)
5168 ) {
5169 G_interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255); 5209 G_interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255);
5170 if (G_interactive_fd < 0) { 5210 if (G_interactive_fd < 0) {
5171 /* try to dup to any fd */ 5211 /* try to dup to any fd */
@@ -5174,45 +5214,32 @@ int hush_main(int argc, char **argv)
5174 /* give up */ 5214 /* give up */
5175 G_interactive_fd = 0; 5215 G_interactive_fd = 0;
5176 } 5216 }
5177 if (G_interactive_fd) {
5178 fcntl(G_interactive_fd, F_SETFD, FD_CLOEXEC);
5179 }
5180 } 5217 }
5181 init_signal_mask(); /* note: ensures SIGCHLD is not masked */ 5218 if (G_interactive_fd) {
5219 close_on_exec_on(G_interactive_fd);
5220 block_signals(signal_mask_is_inited);
5221 } else if (!signal_mask_is_inited) {
5222 block_signals(0);
5223 }
5182#else 5224#else
5183//TODO: we didn't do it for -c or /etc/profile! Shouldn't we? 5225 /* We have interactiveness code disabled */
5184 init_signal_mask(); 5226 if (!signal_mask_is_inited) {
5227 block_signals(0);
5228 }
5185#endif 5229#endif
5186 /* POSIX allows shell to re-enable SIGCHLD 5230 /* bash:
5187 * even if it was SIG_IGN on entry */ 5231 * if interactive but not a login shell, sources ~/.bashrc
5188//TODO: we didn't do it for -c or /etc/profile! Shouldn't we? 5232 * (--norc turns this off, --rcfile <file> overrides)
5189// G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ 5233 */
5190 signal(SIGCHLD, SIG_DFL); // SIGCHLD_handler);
5191 5234
5192#if ENABLE_HUSH_INTERACTIVE && !ENABLE_FEATURE_SH_EXTRA_QUIET 5235 if (!ENABLE_FEATURE_SH_EXTRA_QUIET && G_interactive_fd) {
5193 if (G_interactive_fd) {
5194 printf("\n\n%s hush - the humble shell v"HUSH_VER_STR"\n", bb_banner); 5236 printf("\n\n%s hush - the humble shell v"HUSH_VER_STR"\n", bb_banner);
5195 printf("Enter 'help' for a list of built-in commands.\n\n"); 5237 printf("Enter 'help' for a list of built-in commands.\n\n");
5196 } 5238 }
5197#endif
5198 5239
5199 if (argv[optind] == NULL) { 5240 parse_and_run_file(stdin);
5200 parse_and_run_file(stdin);
5201 } else {
5202 FILE *input;
5203 debug_printf("\nrunning script '%s'\n", argv[optind]);
5204 G.global_argv = argv + optind;
5205 G.global_argc = argc - optind;
5206 input = xfopen_for_read(argv[optind]);
5207 fcntl(fileno(input), F_SETFD, FD_CLOEXEC);
5208 parse_and_run_file(input);
5209#if ENABLE_FEATURE_CLEAN_UP
5210 fclose(input);
5211#endif
5212 }
5213 5241
5214 final_return: 5242 final_return:
5215
5216#if ENABLE_FEATURE_CLEAN_UP 5243#if ENABLE_FEATURE_CLEAN_UP
5217 if (G.cwd != bb_msg_unknown) 5244 if (G.cwd != bb_msg_unknown)
5218 free((char*)G.cwd); 5245 free((char*)G.cwd);