ash: add "wait -n" bashism

function                                             old     new   delta
waitcmd                                              205     288     +83
dowait                                               405     444     +39
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 122/0)             Total: 122 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2019-03-27 15:51:42 +01:00
parent da996c5d2a
commit 966f087ab4

View File

@ -3522,7 +3522,7 @@ struct procstat {
struct job { struct job {
struct procstat ps0; /* status of process */ struct procstat ps0; /* status of process */
struct procstat *ps; /* status or processes when more than one */ struct procstat *ps; /* status of processes when more than one */
#if JOBS #if JOBS
int stopstatus; /* status of a stopped job */ int stopstatus; /* status of a stopped job */
#endif #endif
@ -4235,6 +4235,9 @@ wait_block_or_sig(int *status)
#define DOWAIT_NONBLOCK 0 #define DOWAIT_NONBLOCK 0
#define DOWAIT_BLOCK 1 #define DOWAIT_BLOCK 1
#define DOWAIT_BLOCK_OR_SIG 2 #define DOWAIT_BLOCK_OR_SIG 2
#if ENABLE_ASH_BASH_COMPAT
# define DOWAIT_JOBSTATUS 0x10 /* OR this to get job's exitstatus instead of pid */
#endif
static int static int
dowait(int block, struct job *job) dowait(int block, struct job *job)
@ -4242,7 +4245,11 @@ dowait(int block, struct job *job)
int pid; int pid;
int status; int status;
struct job *jp; struct job *jp;
struct job *thisjob = NULL; struct job *thisjob;
#if ENABLE_ASH_BASH_COMPAT
bool want_jobexitstatus = (block & DOWAIT_JOBSTATUS);
block = (block & ~DOWAIT_JOBSTATUS);
#endif
TRACE(("dowait(0x%x) called\n", block)); TRACE(("dowait(0x%x) called\n", block));
@ -4279,10 +4286,10 @@ dowait(int block, struct job *job)
} }
TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
pid, status, errno, strerror(errno))); pid, status, errno, strerror(errno)));
thisjob = NULL;
if (pid <= 0) if (pid <= 0)
goto out; goto out;
thisjob = NULL;
for (jp = curjob; jp; jp = jp->prev_job) { for (jp = curjob; jp; jp = jp->prev_job) {
int jobstate; int jobstate;
struct procstat *ps; struct procstat *ps;
@ -4341,6 +4348,13 @@ dowait(int block, struct job *job)
out: out:
INT_ON; INT_ON;
#if ENABLE_ASH_BASH_COMPAT
if (want_jobexitstatus) {
pid = -1;
if (thisjob && thisjob->state == JOBDONE)
pid = thisjob->ps[thisjob->nprocs - 1].ps_status;
}
#endif
if (thisjob && thisjob == job) { if (thisjob && thisjob == job) {
char s[48 + 1]; char s[48 + 1];
int len; int len;
@ -4523,15 +4537,24 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
struct job *job; struct job *job;
int retval; int retval;
struct job *jp; struct job *jp;
#if ENABLE_ASH_BASH_COMPAT
int status;
char one = nextopt("n");
#else
nextopt(nullstr); nextopt(nullstr);
#endif
retval = 0; retval = 0;
argv = argptr; argv = argptr;
if (!*argv) { if (!argv[0]) {
/* wait for all jobs */ /* wait for all jobs / one job if -n */
for (;;) { for (;;) {
jp = curjob; jp = curjob;
#if ENABLE_ASH_BASH_COMPAT
if (one && !jp)
/* exitcode of "wait -n" with nothing to wait for is 127, not 0 */
retval = 127;
#endif
while (1) { while (1) {
if (!jp) /* no running procs */ if (!jp) /* no running procs */
goto ret; goto ret;
@ -4547,13 +4570,31 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
* with an exit status greater than 128, immediately after which * with an exit status greater than 128, immediately after which
* the trap is executed." * the trap is executed."
*/ */
#if ENABLE_ASH_BASH_COMPAT
status = dowait(DOWAIT_BLOCK_OR_SIG | DOWAIT_JOBSTATUS, NULL);
#else
dowait(DOWAIT_BLOCK_OR_SIG, NULL); dowait(DOWAIT_BLOCK_OR_SIG, NULL);
#endif
/* if child sends us a signal *and immediately exits*, /* if child sends us a signal *and immediately exits*,
* dowait() returns pid > 0. Check this case, * dowait() returns pid > 0. Check this case,
* not "if (dowait() < 0)"! * not "if (dowait() < 0)"!
*/ */
if (pending_sig) if (pending_sig)
goto sigout; goto sigout;
#if ENABLE_ASH_BASH_COMPAT
if (one) {
/* wait -n waits for one _job_, not one _process_.
* date; sleep 3 & sleep 2 | sleep 1 & wait -n; date
* should wait for 2 seconds. Not 1 or 3.
*/
if (status != -1 && !WIFSTOPPED(status)) {
retval = WEXITSTATUS(status);
if (WIFSIGNALED(status))
retval = WTERMSIG(status) + 128;
goto ret;
}
}
#endif
} }
} }