diff options
author | Ron Yorston <rmy@pobox.com> | 2019-03-31 08:55:48 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2019-03-31 09:51:00 +0100 |
commit | 61e0e3160a8be3ed8488b09200a5dca1bd1b21b4 (patch) | |
tree | d55341d875d1dd0d77445960723a47418efd14e5 /shell | |
parent | be2949717934c19890879cf2a8fc74c5da55d1c7 (diff) | |
parent | 35082fc2c17369223669e099f422acc0982ee4ff (diff) | |
download | busybox-w32-61e0e3160a8be3ed8488b09200a5dca1bd1b21b4.tar.gz busybox-w32-61e0e3160a8be3ed8488b09200a5dca1bd1b21b4.tar.bz2 busybox-w32-61e0e3160a8be3ed8488b09200a5dca1bd1b21b4.zip |
Merge branch 'busybox' into merge
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 53 | ||||
-rw-r--r-- | shell/hush.c | 35 |
2 files changed, 79 insertions, 9 deletions
diff --git a/shell/ash.c b/shell/ash.c index 5f64bebe3..8a3c3ae35 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -3866,7 +3866,7 @@ struct procstat { | |||
3866 | 3866 | ||
3867 | struct job { | 3867 | struct job { |
3868 | struct procstat ps0; /* status of process */ | 3868 | struct procstat ps0; /* status of process */ |
3869 | struct procstat *ps; /* status or processes when more than one */ | 3869 | struct procstat *ps; /* status of processes when more than one */ |
3870 | #if JOBS | 3870 | #if JOBS |
3871 | int stopstatus; /* status of a stopped job */ | 3871 | int stopstatus; /* status of a stopped job */ |
3872 | #endif | 3872 | #endif |
@@ -4703,6 +4703,9 @@ wait_block_or_sig(int *status) | |||
4703 | #define DOWAIT_NONBLOCK 0 | 4703 | #define DOWAIT_NONBLOCK 0 |
4704 | #define DOWAIT_BLOCK 1 | 4704 | #define DOWAIT_BLOCK 1 |
4705 | #define DOWAIT_BLOCK_OR_SIG 2 | 4705 | #define DOWAIT_BLOCK_OR_SIG 2 |
4706 | #if ENABLE_ASH_BASH_COMPAT | ||
4707 | # define DOWAIT_JOBSTATUS 0x10 /* OR this to get job's exitstatus instead of pid */ | ||
4708 | #endif | ||
4706 | 4709 | ||
4707 | static int | 4710 | static int |
4708 | dowait(int block, struct job *job) | 4711 | dowait(int block, struct job *job) |
@@ -4710,7 +4713,11 @@ dowait(int block, struct job *job) | |||
4710 | int pid; | 4713 | int pid; |
4711 | int status; | 4714 | int status; |
4712 | struct job *jp; | 4715 | struct job *jp; |
4713 | struct job *thisjob = NULL; | 4716 | struct job *thisjob; |
4717 | #if ENABLE_ASH_BASH_COMPAT | ||
4718 | bool want_jobexitstatus = (block & DOWAIT_JOBSTATUS); | ||
4719 | block = (block & ~DOWAIT_JOBSTATUS); | ||
4720 | #endif | ||
4714 | 4721 | ||
4715 | TRACE(("dowait(0x%x) called\n", block)); | 4722 | TRACE(("dowait(0x%x) called\n", block)); |
4716 | 4723 | ||
@@ -4747,10 +4754,10 @@ dowait(int block, struct job *job) | |||
4747 | } | 4754 | } |
4748 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", | 4755 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", |
4749 | pid, status, errno, strerror(errno))); | 4756 | pid, status, errno, strerror(errno))); |
4757 | thisjob = NULL; | ||
4750 | if (pid <= 0) | 4758 | if (pid <= 0) |
4751 | goto out; | 4759 | goto out; |
4752 | 4760 | ||
4753 | thisjob = NULL; | ||
4754 | for (jp = curjob; jp; jp = jp->prev_job) { | 4761 | for (jp = curjob; jp; jp = jp->prev_job) { |
4755 | int jobstate; | 4762 | int jobstate; |
4756 | struct procstat *ps; | 4763 | struct procstat *ps; |
@@ -4814,6 +4821,13 @@ dowait(int block, struct job *job) | |||
4814 | out: | 4821 | out: |
4815 | INT_ON; | 4822 | INT_ON; |
4816 | 4823 | ||
4824 | #if ENABLE_ASH_BASH_COMPAT | ||
4825 | if (want_jobexitstatus) { | ||
4826 | pid = -1; | ||
4827 | if (thisjob && thisjob->state == JOBDONE) | ||
4828 | pid = thisjob->ps[thisjob->nprocs - 1].ps_status; | ||
4829 | } | ||
4830 | #endif | ||
4817 | if (thisjob && thisjob == job) { | 4831 | if (thisjob && thisjob == job) { |
4818 | char s[48 + 1]; | 4832 | char s[48 + 1]; |
4819 | int len; | 4833 | int len; |
@@ -4996,15 +5010,24 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
4996 | struct job *job; | 5010 | struct job *job; |
4997 | int retval; | 5011 | int retval; |
4998 | struct job *jp; | 5012 | struct job *jp; |
4999 | 5013 | #if ENABLE_ASH_BASH_COMPAT | |
5014 | int status; | ||
5015 | char one = nextopt("n"); | ||
5016 | #else | ||
5000 | nextopt(nullstr); | 5017 | nextopt(nullstr); |
5018 | #endif | ||
5001 | retval = 0; | 5019 | retval = 0; |
5002 | 5020 | ||
5003 | argv = argptr; | 5021 | argv = argptr; |
5004 | if (!*argv) { | 5022 | if (!argv[0]) { |
5005 | /* wait for all jobs */ | 5023 | /* wait for all jobs / one job if -n */ |
5006 | for (;;) { | 5024 | for (;;) { |
5007 | jp = curjob; | 5025 | jp = curjob; |
5026 | #if ENABLE_ASH_BASH_COMPAT | ||
5027 | if (one && !jp) | ||
5028 | /* exitcode of "wait -n" with nothing to wait for is 127, not 0 */ | ||
5029 | retval = 127; | ||
5030 | #endif | ||
5008 | while (1) { | 5031 | while (1) { |
5009 | if (!jp) /* no running procs */ | 5032 | if (!jp) /* no running procs */ |
5010 | goto ret; | 5033 | goto ret; |
@@ -5020,13 +5043,31 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
5020 | * with an exit status greater than 128, immediately after which | 5043 | * with an exit status greater than 128, immediately after which |
5021 | * the trap is executed." | 5044 | * the trap is executed." |
5022 | */ | 5045 | */ |
5046 | #if ENABLE_ASH_BASH_COMPAT | ||
5047 | status = dowait(DOWAIT_BLOCK_OR_SIG | DOWAIT_JOBSTATUS, NULL); | ||
5048 | #else | ||
5023 | dowait(DOWAIT_BLOCK_OR_SIG, NULL); | 5049 | dowait(DOWAIT_BLOCK_OR_SIG, NULL); |
5050 | #endif | ||
5024 | /* if child sends us a signal *and immediately exits*, | 5051 | /* if child sends us a signal *and immediately exits*, |
5025 | * dowait() returns pid > 0. Check this case, | 5052 | * dowait() returns pid > 0. Check this case, |
5026 | * not "if (dowait() < 0)"! | 5053 | * not "if (dowait() < 0)"! |
5027 | */ | 5054 | */ |
5028 | if (pending_sig) | 5055 | if (pending_sig) |
5029 | goto sigout; | 5056 | goto sigout; |
5057 | #if ENABLE_ASH_BASH_COMPAT | ||
5058 | if (one) { | ||
5059 | /* wait -n waits for one _job_, not one _process_. | ||
5060 | * date; sleep 3 & sleep 2 | sleep 1 & wait -n; date | ||
5061 | * should wait for 2 seconds. Not 1 or 3. | ||
5062 | */ | ||
5063 | if (status != -1 && !WIFSTOPPED(status)) { | ||
5064 | retval = WEXITSTATUS(status); | ||
5065 | if (WIFSIGNALED(status)) | ||
5066 | retval = WTERMSIG(status) + 128; | ||
5067 | goto ret; | ||
5068 | } | ||
5069 | } | ||
5070 | #endif | ||
5030 | } | 5071 | } |
5031 | } | 5072 | } |
5032 | 5073 | ||
diff --git a/shell/hush.c b/shell/hush.c index 920a85299..fa9afa38e 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -923,7 +923,7 @@ struct globals { | |||
923 | # define G_flag_return_in_progress 0 | 923 | # define G_flag_return_in_progress 0 |
924 | #endif | 924 | #endif |
925 | smallint exiting; /* used to prevent EXIT trap recursion */ | 925 | smallint exiting; /* used to prevent EXIT trap recursion */ |
926 | /* These support $?, $#, and $1 */ | 926 | /* These support $? */ |
927 | smalluint last_exitcode; | 927 | smalluint last_exitcode; |
928 | smalluint expand_exitcode; | 928 | smalluint expand_exitcode; |
929 | smalluint last_bg_pid_exitcode; | 929 | smalluint last_bg_pid_exitcode; |
@@ -934,6 +934,9 @@ struct globals { | |||
934 | #else | 934 | #else |
935 | # define G_global_args_malloced 0 | 935 | # define G_global_args_malloced 0 |
936 | #endif | 936 | #endif |
937 | #if ENABLE_HUSH_BASH_COMPAT | ||
938 | int dead_job_exitcode; /* for "wait -n" */ | ||
939 | #endif | ||
937 | /* how many non-NULL argv's we have. NB: $# + 1 */ | 940 | /* how many non-NULL argv's we have. NB: $# + 1 */ |
938 | int global_argc; | 941 | int global_argc; |
939 | char **global_argv; | 942 | char **global_argv; |
@@ -8657,6 +8660,9 @@ static int process_wait_result(struct pipe *fg_pipe, pid_t childpid, int status) | |||
8657 | pi->cmds[i].pid = 0; | 8660 | pi->cmds[i].pid = 0; |
8658 | pi->alive_cmds--; | 8661 | pi->alive_cmds--; |
8659 | if (!pi->alive_cmds) { | 8662 | if (!pi->alive_cmds) { |
8663 | #if ENABLE_HUSH_BASH_COMPAT | ||
8664 | G.dead_job_exitcode = job_exited_or_stopped(pi); | ||
8665 | #endif | ||
8660 | if (G_interactive_fd) { | 8666 | if (G_interactive_fd) { |
8661 | printf(JOB_STATUS_FORMAT, pi->jobid, | 8667 | printf(JOB_STATUS_FORMAT, pi->jobid, |
8662 | "Done", pi->cmdtext); | 8668 | "Done", pi->cmdtext); |
@@ -8763,7 +8769,7 @@ static int checkjobs(struct pipe *fg_pipe, pid_t waitfor_pid) | |||
8763 | /* fg_pipe exited or stopped */ | 8769 | /* fg_pipe exited or stopped */ |
8764 | break; | 8770 | break; |
8765 | } | 8771 | } |
8766 | if (childpid == waitfor_pid) { | 8772 | if (childpid == waitfor_pid) { /* "wait PID" */ |
8767 | debug_printf_exec("childpid==waitfor_pid:%d status:0x%08x\n", childpid, status); | 8773 | debug_printf_exec("childpid==waitfor_pid:%d status:0x%08x\n", childpid, status); |
8768 | rcode = WEXITSTATUS(status); | 8774 | rcode = WEXITSTATUS(status); |
8769 | if (WIFSIGNALED(status)) | 8775 | if (WIFSIGNALED(status)) |
@@ -8774,6 +8780,15 @@ static int checkjobs(struct pipe *fg_pipe, pid_t waitfor_pid) | |||
8774 | rcode++; | 8780 | rcode++; |
8775 | break; /* "wait PID" called us, give it exitcode+1 */ | 8781 | break; /* "wait PID" called us, give it exitcode+1 */ |
8776 | } | 8782 | } |
8783 | #if ENABLE_HUSH_BASH_COMPAT | ||
8784 | if (-1 == waitfor_pid /* "wait -n" (wait for any one job) */ | ||
8785 | && G.dead_job_exitcode >= 0 /* some job did finish */ | ||
8786 | ) { | ||
8787 | debug_printf_exec("waitfor_pid:-1\n"); | ||
8788 | rcode = G.dead_job_exitcode + 1; | ||
8789 | break; | ||
8790 | } | ||
8791 | #endif | ||
8777 | /* This wasn't one of our processes, or */ | 8792 | /* This wasn't one of our processes, or */ |
8778 | /* fg_pipe still has running processes, do waitpid again */ | 8793 | /* fg_pipe still has running processes, do waitpid again */ |
8779 | } /* while (waitpid succeeds)... */ | 8794 | } /* while (waitpid succeeds)... */ |
@@ -11471,6 +11486,12 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid | |||
11471 | ret--; | 11486 | ret--; |
11472 | if (ret < 0) /* if ECHILD, may need to fix "ret" */ | 11487 | if (ret < 0) /* if ECHILD, may need to fix "ret" */ |
11473 | ret = 0; | 11488 | ret = 0; |
11489 | #if ENABLE_HUSH_BASH_COMPAT | ||
11490 | if (waitfor_pid == -1 && errno == ECHILD) { | ||
11491 | /* exitcode of "wait -n" with no children is 127, not 0 */ | ||
11492 | ret = 127; | ||
11493 | } | ||
11494 | #endif | ||
11474 | sigprocmask(SIG_SETMASK, &oldset, NULL); | 11495 | sigprocmask(SIG_SETMASK, &oldset, NULL); |
11475 | break; | 11496 | break; |
11476 | } | 11497 | } |
@@ -11499,6 +11520,14 @@ static int FAST_FUNC builtin_wait(char **argv) | |||
11499 | int status; | 11520 | int status; |
11500 | 11521 | ||
11501 | argv = skip_dash_dash(argv); | 11522 | argv = skip_dash_dash(argv); |
11523 | #if ENABLE_HUSH_BASH_COMPAT | ||
11524 | if (argv[0] && strcmp(argv[0], "-n") == 0) { | ||
11525 | /* wait -n */ | ||
11526 | /* (bash accepts "wait -n PID" too and ignores PID) */ | ||
11527 | G.dead_job_exitcode = -1; | ||
11528 | return wait_for_child_or_signal(NULL, -1 /*no job, wait for one job*/); | ||
11529 | } | ||
11530 | #endif | ||
11502 | if (argv[0] == NULL) { | 11531 | if (argv[0] == NULL) { |
11503 | /* Don't care about wait results */ | 11532 | /* Don't care about wait results */ |
11504 | /* Note 1: must wait until there are no more children */ | 11533 | /* Note 1: must wait until there are no more children */ |
@@ -11516,7 +11545,7 @@ static int FAST_FUNC builtin_wait(char **argv) | |||
11516 | * ^C <-- after ~4 sec from keyboard | 11545 | * ^C <-- after ~4 sec from keyboard |
11517 | * $ | 11546 | * $ |
11518 | */ | 11547 | */ |
11519 | return wait_for_child_or_signal(NULL, 0 /*(no job and no pid to wait for)*/); | 11548 | return wait_for_child_or_signal(NULL, 0 /*no job and no pid to wait for*/); |
11520 | } | 11549 | } |
11521 | 11550 | ||
11522 | do { | 11551 | do { |