aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2020-02-20 12:28:31 +0000
committerRon Yorston <rmy@pobox.com>2020-02-20 12:28:31 +0000
commiteee533be9b75c2f5f92f37d7516e12cf9e4992be (patch)
tree90dbb287476e63907711acc6060df5f9d6cf6053 /shell
parent412c2cab62dcae5509404b48d83aa10717d3b68e (diff)
parent23bc562a0556d1c0ddad4252fa8d46c863b5fa88 (diff)
downloadbusybox-w32-eee533be9b75c2f5f92f37d7516e12cf9e4992be.tar.gz
busybox-w32-eee533be9b75c2f5f92f37d7516e12cf9e4992be.tar.bz2
busybox-w32-eee533be9b75c2f5f92f37d7516e12cf9e4992be.zip
Merge branch 'busybox' into merge
Diffstat (limited to 'shell')
-rw-r--r--shell/ash.c177
-rw-r--r--shell/hush.c20
2 files changed, 106 insertions, 91 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 4c143b8e9..39b14d5a6 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -4181,8 +4181,6 @@ static struct job *jobtab; //5
4181static unsigned njobs; //4 4181static unsigned njobs; //4
4182/* current job */ 4182/* current job */
4183static struct job *curjob; //lots 4183static struct job *curjob; //lots
4184/* number of presumed living untracked jobs */
4185static int jobless; //4
4186 4184
4187#if 0 4185#if 0
4188/* Bash has a feature: it restores termios after a successful wait for 4186/* Bash has a feature: it restores termios after a successful wait for
@@ -4796,8 +4794,19 @@ wait_block_or_sig(int *status)
4796#if 1 4794#if 1
4797 sigfillset(&mask); 4795 sigfillset(&mask);
4798 sigprocmask2(SIG_SETMASK, &mask); /* mask is updated */ 4796 sigprocmask2(SIG_SETMASK, &mask); /* mask is updated */
4799 while (!got_sigchld && !pending_sig) 4797 while (!got_sigchld && !pending_sig) {
4800 sigsuspend(&mask); 4798 sigsuspend(&mask);
4799 /* ^^^ add "sigdelset(&mask, SIGCHLD);" before sigsuspend
4800 * to make sure SIGCHLD is not masked off?
4801 * It was reported that this:
4802 * fn() { : | return; }
4803 * shopt -s lastpipe
4804 * fn
4805 * exec ash SCRIPT
4806 * under bash 4.4.23 runs SCRIPT with SIGCHLD masked,
4807 * making "wait" commands in SCRIPT block forever.
4808 */
4809 }
4801 sigprocmask(SIG_SETMASK, &mask, NULL); 4810 sigprocmask(SIG_SETMASK, &mask, NULL);
4802#else /* unsafe: a signal can set pending_sig after check, but before pause() */ 4811#else /* unsafe: a signal can set pending_sig after check, but before pause() */
4803 while (!got_sigchld && !pending_sig) 4812 while (!got_sigchld && !pending_sig)
@@ -4819,7 +4828,7 @@ wait_block_or_sig(int *status)
4819#endif 4828#endif
4820 4829
4821static int 4830static int
4822dowait(int block, struct job *job) 4831waitone(int block, struct job *job)
4823{ 4832{
4824 int pid; 4833 int pid;
4825 int status; 4834 int status;
@@ -4925,10 +4934,6 @@ dowait(int block, struct job *job)
4925 goto out; 4934 goto out;
4926 } 4935 }
4927 /* The process wasn't found in job list */ 4936 /* The process wasn't found in job list */
4928#if JOBS
4929 if (!WIFSTOPPED(status))
4930 jobless--;
4931#endif
4932 out: 4937 out:
4933 INT_ON; 4938 INT_ON;
4934 4939
@@ -4953,6 +4958,20 @@ dowait(int block, struct job *job)
4953 return pid; 4958 return pid;
4954} 4959}
4955 4960
4961static int
4962dowait(int block, struct job *jp)
4963{
4964 int pid = block == DOWAIT_NONBLOCK ? got_sigchld : 1;
4965
4966 while (jp ? jp->state == JOBRUNNING : pid > 0) {
4967 if (!jp)
4968 got_sigchld = 0;
4969 pid = waitone(block, jp);
4970 }
4971
4972 return pid;
4973}
4974
4956#if JOBS 4975#if JOBS
4957static void 4976static void
4958showjob(struct job *jp, int mode) 4977showjob(struct job *jp, int mode)
@@ -5041,8 +5060,7 @@ showjobs(int mode)
5041 TRACE(("showjobs(0x%x) called\n", mode)); 5060 TRACE(("showjobs(0x%x) called\n", mode));
5042 5061
5043 /* Handle all finished jobs */ 5062 /* Handle all finished jobs */
5044 while (dowait(DOWAIT_NONBLOCK, NULL) > 0) 5063 dowait(DOWAIT_NONBLOCK, NULL);
5045 continue;
5046 5064
5047 for (jp = curjob; jp; jp = jp->prev_job) { 5065 for (jp = curjob; jp; jp = jp->prev_job) {
5048 if (!(mode & SHOW_CHANGED) || jp->changed) { 5066 if (!(mode & SHOW_CHANGED) || jp->changed) {
@@ -5159,10 +5177,10 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
5159#else 5177#else
5160 dowait(DOWAIT_BLOCK_OR_SIG, NULL); 5178 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
5161#endif 5179#endif
5162 /* if child sends us a signal *and immediately exits*, 5180 /* if child sends us a signal *and immediately exits*,
5163 * dowait() returns pid > 0. Check this case, 5181 * dowait() returns pid > 0. Check this case,
5164 * not "if (dowait() < 0)"! 5182 * not "if (dowait() < 0)"!
5165 */ 5183 */
5166 if (pending_sig) 5184 if (pending_sig)
5167 goto sigout; 5185 goto sigout;
5168#if BASH_WAIT_N 5186#if BASH_WAIT_N
@@ -5198,11 +5216,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
5198 job = getjob(*argv, 0); 5216 job = getjob(*argv, 0);
5199 } 5217 }
5200 /* loop until process terminated or stopped */ 5218 /* loop until process terminated or stopped */
5201 while (job->state == JOBRUNNING) { 5219 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
5202 dowait(DOWAIT_BLOCK_OR_SIG, NULL); 5220 if (pending_sig)
5203 if (pending_sig) 5221 goto sigout;
5204 goto sigout;
5205 }
5206 job->waited = 1; 5222 job->waited = 1;
5207 retval = getstatus(job); 5223 retval = getstatus(job);
5208 repeat: ; 5224 repeat: ;
@@ -5755,7 +5771,6 @@ forkchild(struct job *jp, union node *n, int mode)
5755#endif 5771#endif
5756 for (jp = curjob; jp; jp = jp->prev_job) 5772 for (jp = curjob; jp; jp = jp->prev_job)
5757 freejob(jp); 5773 freejob(jp);
5758 jobless = 0;
5759} 5774}
5760#endif 5775#endif
5761 5776
@@ -5774,13 +5789,8 @@ forkparent(struct job *jp, union node *n, int mode, HANDLE proc)
5774 pid_t pid = GetProcessId(proc); 5789 pid_t pid = GetProcessId(proc);
5775#endif 5790#endif
5776 TRACE(("In parent shell: child = %d\n", pid)); 5791 TRACE(("In parent shell: child = %d\n", pid));
5777 if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */ 5792 if (!jp) /* jp is NULL when called by openhere() for heredoc support */
5778 /* jp is NULL when called by openhere() for heredoc support */
5779 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
5780 continue;
5781 jobless++;
5782 return; 5793 return;
5783 }
5784#if JOBS 5794#if JOBS
5785 if (mode != FORK_NOJOB && jp->jobctl) { 5795 if (mode != FORK_NOJOB && jp->jobctl) {
5786 int pgrp; 5796 int pgrp;
@@ -5862,43 +5872,41 @@ waitforjob(struct job *jp)
5862{ 5872{
5863 int st; 5873 int st;
5864 5874
5865 TRACE(("waitforjob(%%%d) called\n", jobno(jp))); 5875 TRACE(("waitforjob(%%%d) called\n", jp ? jobno(jp) : 0));
5866 5876
5867 INT_OFF; 5877 /* In non-interactive shells, we _can_ get
5868 while (jp->state == JOBRUNNING) { 5878 * a keyboard signal here and be EINTRed, but we just loop
5869 /* In non-interactive shells, we _can_ get 5879 * inside dowait(), waiting for command to complete.
5870 * a keyboard signal here and be EINTRed, 5880 *
5871 * but we just loop back, waiting for command to complete. 5881 * man bash:
5872 * 5882 * "If bash is waiting for a command to complete and receives
5873 * man bash: 5883 * a signal for which a trap has been set, the trap
5874 * "If bash is waiting for a command to complete and receives 5884 * will not be executed until the command completes."
5875 * a signal for which a trap has been set, the trap 5885 *
5876 * will not be executed until the command completes." 5886 * Reality is that even if trap is not set, bash
5877 * 5887 * will not act on the signal until command completes.
5878 * Reality is that even if trap is not set, bash 5888 * Try this. sleep5intoff.c:
5879 * will not act on the signal until command completes. 5889 * #include <signal.h>
5880 * Try this. sleep5intoff.c: 5890 * #include <unistd.h>
5881 * #include <signal.h> 5891 * int main() {
5882 * #include <unistd.h> 5892 * sigset_t set;
5883 * int main() { 5893 * sigemptyset(&set);
5884 * sigset_t set; 5894 * sigaddset(&set, SIGINT);
5885 * sigemptyset(&set); 5895 * sigaddset(&set, SIGQUIT);
5886 * sigaddset(&set, SIGINT); 5896 * sigprocmask(SIG_BLOCK, &set, NULL);
5887 * sigaddset(&set, SIGQUIT); 5897 * sleep(5);
5888 * sigprocmask(SIG_BLOCK, &set, NULL); 5898 * return 0;
5889 * sleep(5); 5899 * }
5890 * return 0; 5900 * $ bash -c './sleep5intoff; echo hi'
5891 * } 5901 * ^C^C^C^C <--- pressing ^C once a second
5892 * $ bash -c './sleep5intoff; echo hi' 5902 * $ _
5893 * ^C^C^C^C <--- pressing ^C once a second 5903 * $ bash -c './sleep5intoff; echo hi'
5894 * $ _ 5904 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5895 * $ bash -c './sleep5intoff; echo hi' 5905 * $ _
5896 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT) 5906 */
5897 * $ _ 5907 dowait(jp ? DOWAIT_BLOCK : DOWAIT_NONBLOCK, jp);
5898 */ 5908 if (!jp)
5899 dowait(DOWAIT_BLOCK, jp); 5909 return exitstatus;
5900 }
5901 INT_ON;
5902 5910
5903 st = getstatus(jp); 5911 st = getstatus(jp);
5904#if JOBS 5912#if JOBS
@@ -10991,6 +10999,8 @@ evalcommand(union node *cmd, int flags)
10991 goto out; 10999 goto out;
10992 } 11000 }
10993 11001
11002 jp = NULL;
11003
10994 /* Execute the command. */ 11004 /* Execute the command. */
10995 switch (cmdentry.cmdtype) { 11005 switch (cmdentry.cmdtype) {
10996 default: { 11006 default: {
@@ -11052,8 +11062,6 @@ evalcommand(union node *cmd, int flags)
11052 fs.varlist = varlist.list; 11062 fs.varlist = varlist.list;
11053 jp = makejob(/*cmd,*/ 1); 11063 jp = makejob(/*cmd,*/ 1);
11054 spawn_forkshell(&fs, jp, cmd, FORK_FG); 11064 spawn_forkshell(&fs, jp, cmd, FORK_FG);
11055 status = waitforjob(jp);
11056 INT_ON;
11057 TRACE(("forked child exited with %d\n", status)); 11065 TRACE(("forked child exited with %d\n", status));
11058 break; 11066 break;
11059 } 11067 }
@@ -11072,8 +11080,6 @@ evalcommand(union node *cmd, int flags)
11072 jp = makejob(/*cmd,*/ 1); 11080 jp = makejob(/*cmd,*/ 1);
11073 if (forkshell(jp, cmd, FORK_FG) != 0) { 11081 if (forkshell(jp, cmd, FORK_FG) != 0) {
11074 /* parent */ 11082 /* parent */
11075 status = waitforjob(jp);
11076 INT_ON;
11077 TRACE(("forked child exited with %d\n", status)); 11083 TRACE(("forked child exited with %d\n", status));
11078 break; 11084 break;
11079 } 11085 }
@@ -11092,33 +11098,23 @@ evalcommand(union node *cmd, int flags)
11092 if (cmd_is_exec && argc > 1) 11098 if (cmd_is_exec && argc > 1)
11093 listsetvar(varlist.list, VEXPORT); 11099 listsetvar(varlist.list, VEXPORT);
11094 } 11100 }
11095 11101 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)
11096 /* Tight loop with builtins only: 11102 && !(exception_type == EXERROR && spclbltin <= 0)
11097 * "while kill -0 $child; do true; done" 11103 ) {
11098 * will never exit even if $child died, unless we do this
11099 * to reap the zombie and make kill detect that it's gone: */
11100 dowait(DOWAIT_NONBLOCK, NULL);
11101
11102 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
11103 if (exception_type == EXERROR && spclbltin <= 0) {
11104 FORCE_INT_ON;
11105 goto readstatus;
11106 }
11107 raise: 11104 raise:
11108 longjmp(exception_handler->loc, 1); 11105 longjmp(exception_handler->loc, 1);
11109 } 11106 }
11110 goto readstatus; 11107 break;
11111 11108
11112 case CMDFUNCTION: 11109 case CMDFUNCTION:
11113 /* See above for the rationale */
11114 dowait(DOWAIT_NONBLOCK, NULL);
11115 if (evalfun(cmdentry.u.func, argc, argv, flags)) 11110 if (evalfun(cmdentry.u.func, argc, argv, flags))
11116 goto raise; 11111 goto raise;
11117 readstatus:
11118 status = exitstatus;
11119 break; 11112 break;
11120 } /* switch */ 11113 } /* switch */
11121 11114
11115 status = waitforjob(jp);
11116 FORCE_INT_ON;
11117
11122 out: 11118 out:
11123 if (cmd->ncmd.redirect) 11119 if (cmd->ncmd.redirect)
11124 popredir(/*drop:*/ cmd_is_exec); 11120 popredir(/*drop:*/ cmd_is_exec);
@@ -14956,11 +14952,6 @@ init(void)
14956#if !ENABLE_PLATFORM_MINGW32 14952#if !ENABLE_PLATFORM_MINGW32
14957 sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ 14953 sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
14958 setsignal(SIGCHLD); 14954 setsignal(SIGCHLD);
14959
14960 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
14961 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
14962 */
14963 signal(SIGHUP, SIG_DFL);
14964#endif 14955#endif
14965 14956
14966 { 14957 {
@@ -15448,6 +15439,16 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
15448 } 15439 }
15449#endif 15440#endif
15450 state4: /* XXX ??? - why isn't this before the "if" statement */ 15441 state4: /* XXX ??? - why isn't this before the "if" statement */
15442
15443 /* Interactive bash re-enables SIGHUP which is SIG_IGNed on entry.
15444 * Try:
15445 * trap '' hup; bash; echo RET # type "kill -hup $$", see SIGHUP having effect
15446 * trap '' hup; bash -c 'kill -hup $$; echo ALIVE' # here SIGHUP is SIG_IGNed
15447 */
15448#if !ENABLE_PLATFORM_MINGW32
15449 signal(SIGHUP, SIG_DFL);
15450#endif
15451
15451 cmdloop(1); 15452 cmdloop(1);
15452 } 15453 }
15453#if PROFILE 15454#if PROFILE
diff --git a/shell/hush.c b/shell/hush.c
index 6e44d4e11..bced388bf 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -9775,10 +9775,14 @@ static void install_sighandlers(unsigned mask)
9775 */ 9775 */
9776 if (sig == SIGCHLD) 9776 if (sig == SIGCHLD)
9777 continue; 9777 continue;
9778 /* bash re-enables SIGHUP which is SIG_IGNed on entry. 9778 /* Interactive bash re-enables SIGHUP which is SIG_IGNed on entry.
9779 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$" 9779 * Try:
9780 * trap '' hup; bash; echo RET # type "kill -hup $$", see SIGHUP having effect
9781 * trap '' hup; bash -c 'kill -hup $$; echo ALIVE' # here SIGHUP is SIG_IGNed
9780 */ 9782 */
9781 //if (sig == SIGHUP) continue; - TODO? 9783 if (sig == SIGHUP && G_interactive_fd)
9784 continue;
9785 /* Unless one of the above signals, is it SIG_IGN? */
9782 if (old_handler == SIG_IGN) { 9786 if (old_handler == SIG_IGN) {
9783 /* oops... restore back to IGN, and record this fact */ 9787 /* oops... restore back to IGN, and record this fact */
9784 install_sighandler(sig, old_handler); 9788 install_sighandler(sig, old_handler);
@@ -11554,6 +11558,16 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid
11554 /* It is vitally important for sigsuspend that SIGCHLD has non-DFL handler! */ 11558 /* It is vitally important for sigsuspend that SIGCHLD has non-DFL handler! */
11555 /* Note: sigsuspend invokes signal handler */ 11559 /* Note: sigsuspend invokes signal handler */
11556 sigsuspend(&oldset); 11560 sigsuspend(&oldset);
11561 /* ^^^ add "sigdelset(&oldset, SIGCHLD)" before sigsuspend
11562 * to make sure SIGCHLD is not masked off?
11563 * It was reported that this:
11564 * fn() { : | return; }
11565 * shopt -s lastpipe
11566 * fn
11567 * exec hush SCRIPT
11568 * under bash 4.4.23 runs SCRIPT with SIGCHLD masked,
11569 * making "wait" commands in SCRIPT block forever.
11570 */
11557 restore: 11571 restore:
11558 sigprocmask(SIG_SETMASK, &oldset, NULL); 11572 sigprocmask(SIG_SETMASK, &oldset, NULL);
11559 check_sig: 11573 check_sig: