diff options
Diffstat (limited to 'Src/jobs.c')
-rw-r--r-- | Src/jobs.c | 137 |
1 files changed, 116 insertions, 21 deletions
diff --git a/Src/jobs.c b/Src/jobs.c index 0dbb10b4f..371b8eb32 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -376,6 +376,36 @@ check_cursh_sig(int sig) } } +/**/ +void +storepipestats(Job jn, int inforeground, int fixlastval) +{ + int i, pipefail = 0, jpipestats[MAX_PIPESTATS]; + Process p; + + for (p = jn->procs, i = 0; p && i < MAX_PIPESTATS; p = p->next, i++) { + jpipestats[i] = ((WIFSIGNALED(p->status)) ? + 0200 | WTERMSIG(p->status) : + WEXITSTATUS(p->status)); + if (jpipestats[i]) + pipefail = jpipestats[i]; + } + if (inforeground) { + memcpy(pipestats, jpipestats, sizeof(int)*i); + if ((jn->stat & STAT_CURSH) && i < MAX_PIPESTATS) + pipestats[i++] = lastval; + numpipestats = i; + } + + if (fixlastval) { + if (jn->stat & STAT_CURSH) { + if (!lastval && isset(PIPEFAIL)) + lastval = pipefail; + } else if (isset(PIPEFAIL)) + lastval = pipefail; + } +} + /* Update status of job, possibly printing it */ /**/ @@ -507,17 +537,13 @@ update_job(Job jn) return; jn->stat |= (somestopped) ? STAT_CHANGED | STAT_STOPPED : STAT_CHANGED | STAT_DONE; - if (job == thisjob && (jn->stat & STAT_DONE)) { - int i; - Process p; - - for (p = jn->procs, i = 0; p && i < MAX_PIPESTATS; p = p->next, i++) - pipestats[i] = ((WIFSIGNALED(p->status)) ? - 0200 | WTERMSIG(p->status) : - WEXITSTATUS(p->status)); - if ((jn->stat & STAT_CURSH) && i < MAX_PIPESTATS) - pipestats[i++] = lastval; - numpipestats = i; + if (jn->stat & STAT_DONE) { + /* This may be redundant with printjob() but note that inforeground + * is true here for STAT_CURSH jobs even when job != thisjob, most + * likely because thisjob = -1 from exec.c:execsimple() trickery. + * However, if we reset lastval here we break it for printjob(). + */ + storepipestats(jn, inforeground, 0); } if (!inforeground && (jn->stat & (STAT_SUBJOB | STAT_DONE)) == (STAT_SUBJOB | STAT_DONE)) { @@ -915,10 +941,13 @@ printjob(Job jn, int lng, int synch) int doneprint = 0, skip_print = 0; FILE *fout = (synch == 2 || !shout) ? stdout : shout; - if (oldjobtab != NULL) + if (synch > 1 && oldjobtab != NULL) job = jn - oldjobtab; else job = jn - jobtab; + DPUTS3(job < 0 || job > (oldjobtab && synch > 1 ? oldmaxjob : maxjob), + "bogus job number, jn = %L, jobtab = %L, oldjobtab = %L", + (long)jn, (long)jobtab, (long)oldjobtab); if (jn->stat & STAT_NOPRINT) { skip_print = 1; @@ -968,6 +997,9 @@ printjob(Job jn, int lng, int synch) if (skip_print) { if (jn->stat & STAT_DONE) { + /* This looks silly, but see update_job() */ + if (synch <= 1) + storepipestats(jn, job == thisjob, job == thisjob); if (should_report_time(jn)) dumptime(jn); deletejob(jn, 0); @@ -1083,9 +1115,9 @@ printjob(Job jn, int lng, int synch) fflush(fout); } -/* print "(pwd now: foo)" messages: with (lng & 4) we are printing - * the directory where the job is running, otherwise the current directory - */ + /* print "(pwd now: foo)" messages: with (lng & 4) we are printing + * the directory where the job is running, otherwise the current directory + */ if ((lng & 4) || (interact && job == thisjob && jn->pwd && strcmp(jn->pwd, pwd))) { @@ -1095,9 +1127,13 @@ printjob(Job jn, int lng, int synch) fprintf(fout, ")\n"); fflush(fout); } -/* delete job if done */ + + /* delete job if done */ if (jn->stat & STAT_DONE) { + /* This looks silly, but see update_job() */ + if (synch <= 1) + storepipestats(jn, job == thisjob, job == thisjob); if (should_report_time(jn)) dumptime(jn); deletejob(jn, 0); @@ -1113,16 +1149,48 @@ printjob(Job jn, int lng, int synch) return doneprint; } +/* Add a file to be deleted or fd to be closed to the current job */ + +/**/ +void +addfilelist(const char *name, int fd) +{ + Jobfile jf = (Jobfile)zalloc(sizeof(struct jobfile)); + LinkList ll = jobtab[thisjob].filelist; + + if (!ll) + ll = jobtab[thisjob].filelist = znewlinklist(); + if (name) + { + jf->u.name = ztrdup(name); + jf->is_fd = 0; + } + else + { + jf->u.fd = fd; + jf->is_fd = 1; + } + zaddlinknode(ll, jf); +} + +/* Finished with list of files for a job */ + /**/ void deletefilelist(LinkList file_list, int disowning) { - char *s; + Jobfile jf; if (file_list) { - while ((s = (char *)getlinknode(file_list))) { - if (!disowning) - unlink(s); - zsfree(s); + while ((jf = (Jobfile)getlinknode(file_list))) { + if (jf->is_fd) { + if (!disowning) + zclose(jf->u.fd); + } else { + if (!disowning) + unlink(jf->u.name); + zsfree(jf->u.name); + } + zfree(jf, sizeof(*jf)); } zfree(file_list, sizeof(struct linklist)); } @@ -1336,6 +1404,31 @@ zwaitjob(int job, int wait_cmd) jn->stat |= STAT_LOCKED; if (jn->stat & STAT_CHANGED) printjob(jn, !!isset(LONGLISTJOBS), 1); + if (jn->filelist) { + /* + * The main shell is finished with any file descriptors used + * for process substitution associated with this job: close + * them to indicate to listeners there's no more input. + * + * Note we can't safely delete temporary files yet as these + * are directly visible to other processes. However, + * we can't deadlock on the fact that those still exist, so + * that's not a problem. + */ + LinkNode node = firstnode(jn->filelist); + while (node) { + Jobfile jf = (Jobfile)getdata(node); + if (jf->is_fd) { + LinkNode next = nextnode(node); + (void)remnode(jn->filelist, node); + zclose(jf->u.fd); + zfree(jf, sizeof(*jf)); + node = next; + } else { + incnode(node); + } + } + } while (!errflag && jn->stat && !(jn->stat & STAT_DONE) && !(interact && (jn->stat & STAT_STOPPED))) { @@ -2522,6 +2615,8 @@ acquire_pgrp(void) while ((ttpgrp = gettygrp()) != -1 && ttpgrp != mypgrp) { mypgrp = GETPGRP(); if (mypgrp == mypid) { + if (!interact) + break; /* attachtty() will be a no-op, give up */ signal_setmask(oldset); attachtty(mypgrp); /* Might generate SIGT* */ signal_block(blockset); |