diff options
Diffstat (limited to 'Src/jobs.c')
-rw-r--r-- | Src/jobs.c | 92 |
1 files changed, 68 insertions, 24 deletions
diff --git a/Src/jobs.c b/Src/jobs.c index ec11c747b..2da44a4e8 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -940,10 +940,10 @@ printjob(Job jn, int lng, int synch) if ((lng & 4) || (interact && job == thisjob && jn->pwd && strcmp(jn->pwd, pwd))) { - fprintf(shout, "(pwd %s: ", (lng & 4) ? "" : "now"); - fprintdir(((lng & 4) && jn->pwd) ? jn->pwd : pwd, shout); - fprintf(shout, ")\n"); - fflush(shout); + fprintf(fout, "(pwd %s: ", (lng & 4) ? "" : "now"); + fprintdir(((lng & 4) && jn->pwd) ? jn->pwd : pwd, fout); + fprintf(fout, ")\n"); + fflush(fout); } /* delete job if done */ @@ -1111,11 +1111,16 @@ havefiles(void) } -/* wait for a particular process */ +/* + * Wait for a particular process. + * wait_cmd indicates this is from the interactive wait command, + * in which case the behaviour is a little different: the command + * itself can be interrupted by a trapped signal. + */ /**/ -void -waitforpid(pid_t pid) +int +waitforpid(pid_t pid, int wait_cmd) { int first = 1, q = queue_signal_level(); @@ -1128,18 +1133,30 @@ waitforpid(pid_t pid) else kill(pid, SIGCONT); - signal_suspend(SIGCHLD, SIGINT); + last_signal = -1; + signal_suspend(SIGCHLD, wait_cmd); + if (last_signal != SIGCHLD && wait_cmd) { + /* wait command interrupted, but no error: return */ + restore_queue_signals(q); + return 128 + last_signal; + } child_block(); } child_unblock(); restore_queue_signals(q); + + return 0; } -/* wait for a job to finish */ +/* + * Wait for a job to finish. + * wait_cmd indicates this is from the wait builtin; see + * wait_cmd in waitforpid(). + */ /**/ -static void -zwaitjob(int job, int sig) +static int +zwaitjob(int job, int wait_cmd) { int q = queue_signal_level(); Job jn = jobtab + job; @@ -1153,7 +1170,13 @@ zwaitjob(int job, int sig) while (!errflag && jn->stat && !(jn->stat & STAT_DONE) && !(interact && (jn->stat & STAT_STOPPED))) { - signal_suspend(SIGCHLD, sig); + signal_suspend(SIGCHLD, wait_cmd); + if (last_signal != SIGCHLD && wait_cmd) + { + /* builtin wait interrupted by trapped signal */ + restore_queue_signals(q); + return 128 + last_signal; + } /* Commenting this out makes ^C-ing a job started by a function stop the whole function again. But I guess it will stop something else from working properly, we have to find out @@ -1176,6 +1199,8 @@ zwaitjob(int job, int sig) } child_unblock(); restore_queue_signals(q); + + return 0; } /* wait for running job to finish */ @@ -1687,9 +1712,9 @@ bin_fg(char *name, char **argv, Options ops, int func) } else { /* Must be BIN_WAIT, so wait for all jobs */ for (job = 0; job <= maxjob; job++) if (job != thisjob && jobtab[job].stat) - zwaitjob(job, SIGINT); + retval = zwaitjob(job, 1); unqueue_signals(); - return 0; + return retval; } } @@ -1707,11 +1732,19 @@ bin_fg(char *name, char **argv, Options ops, int func) Job j; Process p; - if (findproc(pid, &j, &p, 0)) - waitforpid(pid); - else + if (findproc(pid, &j, &p, 0)) { + /* + * returns 0 for normal exit, else signal+128 + * in which case we should return that status. + */ + retval = waitforpid(pid, 1); + if (!retval) + retval = lastval2; + } else { zwarnnam(name, "pid %d is not a child of this shell", 0, pid); - retval = lastval2; + /* presumably lastval2 doesn't tell us a heck of a lot? */ + retval = 1; + } thisjob = ocj; continue; } @@ -1780,11 +1813,12 @@ bin_fg(char *name, char **argv, Options ops, int func) printjob(jobtab + job, (stopped) ? -1 : lng, 1); if (func != BIN_BG) { /* fg or wait */ if (jobtab[job].pwd && strcmp(jobtab[job].pwd, pwd)) { - fprintf(shout, "(pwd : "); - fprintdir(jobtab[job].pwd, shout); - fprintf(shout, ")\n"); + FILE *fout = (func == BIN_JOBS) ? stdout : shout; + fprintf(fout, "(pwd : "); + fprintdir(jobtab[job].pwd, fout); + fprintf(fout, ")\n"); + fflush(fout); } - fflush(shout); if (func != BIN_WAIT) { /* fg */ thisjob = job; if ((jobtab[job].stat & STAT_SUPERJOB) && @@ -1803,8 +1837,18 @@ bin_fg(char *name, char **argv, Options ops, int func) killjb(jobtab + job, SIGCONT); } if (func == BIN_WAIT) - zwaitjob(job, SIGINT); - if (func != BIN_BG) { + { + retval = zwaitjob(job, 1); + if (!retval) + retval = lastval2; + } + else if (func != BIN_BG) { + /* + * HERE: there used not to be an "else" above. How + * could it be right to wait for the foreground job + * when we've just been told to wait for another + * job (and done it)? + */ waitjobs(); retval = lastval2; } else if (ofunc == BIN_DISOWN) |