diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/exec.c | 40 | ||||
-rw-r--r-- | Src/jobs.c | 9 |
2 files changed, 44 insertions, 5 deletions
diff --git a/Src/exec.c b/Src/exec.c index a462a4ee9..5aa3dba12 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1098,10 +1098,10 @@ execpline(Estate state, wordcode slcode, int how, int last1) child_block(); /* - * Get free entry in job table and initialize it. - * This is currently the only call to initjob(), so this - * is also the only place where we can expand the job table - * under us. + * Get free entry in job table and initialize it. This is currently + * the only call to initjob() (apart from a minor exception in + * clearjobtab()), so this is also the only place where we can + * expand the job table under us. */ if ((thisjob = newjob = initjob()) == -1) { child_unblock(); @@ -2816,8 +2816,38 @@ execcmd(Estate state, int input, int output, int how, int last1) } err: - if (forked) + if (forked) { + /* + * So what's going on here then? Well, I'm glad you asked. + * + * If we create multios for use in a subshell we do + * this after forking, in this function above. That + * means that the current (sub)process is responsible + * for clearing them up. However, the processes won't + * go away until we have closed the fd's talking to them. + * Since we're about to exit the shell there's nothing + * to stop us closing all fd's (including the ones 0 to 9 + * that we usually leave alone). + * + * Then we wait for any processes. When we forked, + * we cleared the jobtable and started a new job just for + * any oddments like this, so if there aren't any we won't + * need to wait. The result of not waiting is that + * the multios haven't flushed the fd's properly, leading + * to obscure missing data. + * + * It would probably be cleaner to ensure that the + * parent shell handled multios, but that requires + * some architectural changes which are likely to be + * hairy. + */ + for (i = 0; i < 10; i++) + if (fdtable[i] != FDT_UNUSED) + close(i); + closem(FDT_UNUSED); + waitjobs(); _exit(lastval); + } fixfds(save); done: diff --git a/Src/jobs.c b/Src/jobs.c index 53e654c2b..b02922a03 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -1296,6 +1296,15 @@ clearjobtab(int monitor) memset(jobtab, 0, jobtabsize * sizeof(struct job)); /* zero out table */ maxjob = 0; + + /* + * Although we don't have job control in subshells, we + * sometimes needs control structures for other purposes such + * as multios. Grab a job for this purpose; any will do + * since we've freed them all up (so there's no question + * of problems with the job table size here). + */ + thisjob = initjob(); } static int initnewjob(int i) |