about summary refs log tree commit diff
path: root/Src/jobs.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/jobs.c')
-rw-r--r--Src/jobs.c57
1 files changed, 47 insertions, 10 deletions
diff --git a/Src/jobs.c b/Src/jobs.c
index 6ddef0f70..7b0eca6b6 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -175,8 +175,23 @@ update_job(Job jn)
 	    jn->ty = (struct ttyinfo *) zalloc(sizeof(struct ttyinfo));
 	    gettyinfo(jn->ty);
 	}
-	if (jn->stat & STAT_STOPPED)
+	if (jn->stat & STAT_STOPPED) {
+	    if (jn->stat & STAT_SUBJOB) {
+		/* If we have `cat foo|while read a; grep $a bar;done'
+		 * and have hit ^Z, the sub-job is stopped, but the
+		 * super-job may still be running, waiting to be stopped
+		 * or to exit. So we have to send it a SIGSTOP. */
+		int i;
+
+		for (i = 1; i < MAXJOB; i++)
+		    if ((jobtab[i].stat & STAT_SUPERJOB) &&
+			jobtab[i].other == job) {
+			killpg(jobtab[i].gleader, SIGSTOP);
+			break;
+		    }
+	    }
 	    return;
+	}
     } else {                   /* job is done, so remember return value */
 	lastval2 = val;
 	/* If last process was run in the current shell, keep old status
@@ -202,14 +217,27 @@ update_job(Job jn)
 	if (mypgrp != pgrp && inforeground &&
 	    (jn->gleader == pgrp || (pgrp > 1 && kill(-pgrp, 0) == -1))) {
 	    if (list_pipe) {
-		/*
-		 * Oh, dear, we're right in the middle of some confusion
-		 * of shell jobs on the righthand side of a pipeline, so
-		 * it's death to call attachtty() just yet.  Mark the
-		 * fact in the job, so that the attachtty() will be called
-		 * when the job is finally deleted.
-		 */
-		jn->stat |= STAT_ATTACH;
+		if (pgrp > 1 && kill(-pgrp, 0) == -1) {
+		    attachtty(mypgrp);
+		    /* check window size and adjust if necessary */
+		    adjustwinsize(0);
+		} else {
+		    /*
+		     * Oh, dear, we're right in the middle of some confusion
+		     * of shell jobs on the righthand side of a pipeline, so
+		     * it's death to call attachtty() just yet.  Mark the
+		     * fact in the job, so that the attachtty() will be called
+		     * when the job is finally deleted.
+		     */
+		    jn->stat |= STAT_ATTACH;
+		}
+		/* If we have `foo|while true; (( x++ )); done', and hit
+		 * ^C, we have to stop the loop, too. */
+		if ((val & 0200) && inforeground == 1) {
+		    breaks = loops;
+		    errflag = 1;
+		    inerrflush();
+		}
 	    } else {
 		attachtty(mypgrp);
 		/* check window size and adjust if necessary */
@@ -765,8 +793,17 @@ waitjob(int job, int sig)
 			}
 		    if (!p) {
 			jn->stat &= ~STAT_SUPERJOB;
+			if (WIFEXITED(jn->procs->status))
+			    jn->gleader = mypgrp;
+			/* This deleted the job too early if the parent
+			   shell waited for a command in a list that will
+			   be executed by the sub-shell (e.g.: if we have
+			   `ls|if true;then sleep 20;cat;fi' and ^Z the
+			   sleep, the rest will be executed by a sub-shell,
+			   but the parent shell gets notified for the
+			   sleep.
+			   deletejob(sj); */
 			kill(sj->other, SIGCONT);
-			deletejob(sj);
 		    }
 		    curjob = jn - jobtab;
 		}