about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--Src/Modules/clone.c25
-rw-r--r--Src/exec.c6
-rw-r--r--Src/jobs.c77
4 files changed, 86 insertions, 26 deletions
diff --git a/ChangeLog b/ChangeLog
index bd6638098..f8927c79d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2002-06-05  Peter Stephenson  <pws@csr.com>
 
+	* 17265: Src/exec.c, Src/jobs.c, Src/Modules/clone.c: Make the
+	`jobs' command work in a subshell of a shell with job control by
+	saving the valid bits of the job table.
+
 	* 17285: David Wolfe <dwolfe@gforcetech.com>:
 	Src/Builtins/rlimits.c: finally fix 16145 to eliminate duplicate
 	case statement also in ulimit.
diff --git a/Src/Modules/clone.c b/Src/Modules/clone.c
index 11387fc90..1a41b7448 100644
--- a/Src/Modules/clone.c
+++ b/Src/Modules/clone.c
@@ -53,7 +53,7 @@ bin_clone(char *nam, char **args, char *ops, int func)
     }
     pid = fork();
     if (!pid) {
-	clearjobtab();
+	clearjobtab(0);
 	ppid = getppid();
 	mypid = getpid();
 #ifdef HAVE_SETSID
@@ -61,7 +61,7 @@ bin_clone(char *nam, char **args, char *ops, int func)
 	    zwarnnam(nam, "failed to create new session: %e", NULL, errno);
 #endif
 #ifdef TIOCNOTTY
-	    if (ioctl(SHTTY, TIOCNOTTY))
+	    if (ioctl(SHTTY, TIOCNOTTY, 0))
 		zwarnnam(nam, "%e", NULL, errno);
 	    setpgrp(0L, mypid);
 #endif
@@ -98,18 +98,29 @@ static struct builtin bintab[] = {
 
 /**/
 int
-boot_clone(Module m)
+setup_(Module m)
 {
-    return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+    return 0;
 }
 
-#ifdef MODULE
+/**/
+int
+boot_(Module m)
+{
+    return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+}
 
 /**/
 int
-cleanup_clone(Module m)
+cleanup_(Module m)
 {
     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
     return 0;
 }
-#endif
+
+/**/
+int
+finish_(Module m)
+{
+    return 0;
+}
diff --git a/Src/exec.c b/Src/exec.c
index d3b33e174..4888c9fb8 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -2507,13 +2507,13 @@ forklevel;
 static void
 entersubsh(int how, int cl, int fake)
 {
-    int sig;
+    int sig, monitor;
 
     if (cl != 2)
 	for (sig = 0; sig < VSIGCOUNT; sig++)
 	    if (!(sigtrapped[sig] & ZSIG_FUNC))
 		unsettrap(sig);
-    if (unset(MONITOR)) {
+    if (!(monitor = isset(MONITOR))) {
 	if (how & Z_ASYNC) {
 	    settrap(SIGINT, NULL);
 	    settrap(SIGQUIT, NULL);
@@ -2569,7 +2569,7 @@ entersubsh(int how, int cl, int fake)
     opts[MONITOR] = opts[USEZLE] = 0;
     zleactive = 0;
     if (cl)
-	clearjobtab();
+	clearjobtab(monitor);
     times(&shtms);
     forklevel = locallevel;
 }
diff --git a/Src/jobs.c b/Src/jobs.c
index fc3737fa9..548cdb923 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -55,6 +55,12 @@ mod_export int prevjob;
 /**/
 mod_export struct job jobtab[MAXJOB];
 
+/* If we have entered a subshell, the original shell's job table. */
+static struct job *oldjobtab;
+
+/* The size of that. */
+static int oldmaxjob;
+
 /* shell timings */
  
 /**/
@@ -612,13 +618,18 @@ void
 printjob(Job jn, int lng, int synch)
 {
     Process pn;
-    int job = jn - jobtab, len = 9, sig, sflag = 0, llen;
+    int job, len = 9, sig, sflag = 0, llen;
     int conted = 0, lineleng = columns, skip = 0, doputnl = 0;
     FILE *fout = (synch == 2) ? stdout : shout;
 
     if (jn->stat & STAT_NOPRINT)
 	return;
 
+    if (jn < jobtab || jn >= jobtab + MAXJOB)
+	job = jn - oldjobtab;
+    else
+	job = jn - jobtab;
+
     if (lng < 0) {
 	conted = 1;
 	lng = 0;
@@ -655,11 +666,14 @@ printjob(Job jn, int lng, int synch)
 	}
     }
 
-/* print if necessary */
+/* print if necessary: ignore option state on explicit call to `jobs'. */
 
-    if (interact && jobbing && ((jn->stat & STAT_STOPPED) || sflag ||
-				job != thisjob)) {
+    if (synch == 2 || 
+	(interact && jobbing &&
+	 ((jn->stat & STAT_STOPPED) || sflag || job != thisjob))) {
 	int len2, fline = 1;
+	/* use special format for current job, except in `jobs' */
+	int thisfmt = job == thisjob && synch != 2;
 	Process qn;
 
 	if (!synch)
@@ -667,7 +681,7 @@ printjob(Job jn, int lng, int synch)
 	if (doputnl && !synch)
 	    putc('\n', fout);
 	for (pn = jn->procs; pn;) {
-	    len2 = ((job == thisjob) ? 5 : 10) + len;	/* 2 spaces */
+	    len2 = (thisfmt ? 5 : 10) + len;	/* 2 spaces */
 	    if (lng & 3)
 		qn = pn->next;
 	    else
@@ -678,10 +692,10 @@ printjob(Job jn, int lng, int synch)
 			break;
 		    len2 += strlen(qn->text) + 2;
 		}
-	    if (job != thisjob) {
+	    if (!thisfmt) {
 		if (fline)
 		    fprintf(fout, "[%ld]  %c ",
-			    (long)(jn - jobtab),
+			    (long)job,
 			    (job == curjob) ? '+'
 			    : (job == prevjob) ? '-' : ' ');
 		else
@@ -956,13 +970,32 @@ waitjobs(void)
 
 /**/
 mod_export void
-clearjobtab(void)
+clearjobtab(int monitor)
 {
     int i;
 
-    for (i = 1; i < MAXJOB; i++)
-	if (jobtab[i].ty)
+    for (i = 1; i < MAXJOB; i++) {
+	if (jobtab[i].ty) {
 	    zfree(jobtab[i].ty, sizeof(struct ttyinfo));
+	    jobtab[i].ty = NULL;
+	}
+	if (monitor) {
+	    /*
+	     * See if there is a jobtable worth saving.
+	     * We never free the saved version; it only happens
+	     * once for each subshell of a shell with job control,
+	     * so doesn't create a leak.
+	     */
+	    if (jobtab[i].stat)
+		oldmaxjob = i+1;
+	}
+    }
+
+    if (monitor && oldmaxjob) {
+	int sz = oldmaxjob * sizeof(struct job);
+	oldjobtab = (struct job *)zalloc(sz);
+	memcpy(oldjobtab, jobtab, sz);
+    }
 
     memset(jobtab, 0, sizeof(jobtab)); /* zero out table */
 }
@@ -1253,7 +1286,8 @@ bin_fg(char *name, char **argv, char *ops, int func)
     if (unset(NOTIFY))
 	scanjobs();
 
-    setcurjob();
+    if (func != BIN_JOBS || isset(MONITOR) || !oldmaxjob)
+	setcurjob();
 
     if (func == BIN_JOBS)
         /* If you immediately type "exit" after "jobs", this      *
@@ -1274,13 +1308,24 @@ bin_fg(char *name, char **argv, char *ops, int func)
 	    firstjob = curjob;
 	} else if (func == BIN_JOBS) {
 	    /* List jobs. */
-	    for (job = 0; job != MAXJOB; job++)
-		if (job != thisjob && jobtab[job].stat) {
+	    struct job *jobptr;
+	    int maxjob, ignorejob;
+	    if (unset(MONITOR) && oldmaxjob) {
+		jobptr = oldjobtab;
+		maxjob = oldmaxjob;
+		ignorejob = 0;
+	    } else {
+		jobptr = jobtab;
+		maxjob = MAXJOB;
+		ignorejob = thisjob;
+	    }
+	    for (job = 0; job != maxjob; job++, jobptr++)
+		if (job != ignorejob && jobptr->stat) {
 		    if ((!ops['r'] && !ops['s']) ||
 			(ops['r'] && ops['s']) ||
-			(ops['r'] && !(jobtab[job].stat & STAT_STOPPED)) ||
-			(ops['s'] && jobtab[job].stat & STAT_STOPPED))
-			printjob(job + jobtab, lng, 2);
+			(ops['r'] && !(jobptr->stat & STAT_STOPPED)) ||
+			(ops['s'] && jobptr->stat & STAT_STOPPED))
+			printjob(jobptr, lng, 2);
 		}
 	    unqueue_signals();
 	    return 0;