Home | History | Annotate | Line # | Download | only in sh
      1 /*	$NetBSD: jobs.c,v 1.130 2026/07/19 19:18:13 kre Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1991, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * This code is derived from software contributed to Berkeley by
      8  * Kenneth Almquist.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. Neither the name of the University nor the names of its contributors
     19  *    may be used to endorse or promote products derived from this software
     20  *    without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  */
     34 
     35 #include <sys/cdefs.h>
     36 #ifndef lint
     37 #if 0
     38 static char sccsid[] = "@(#)jobs.c	8.5 (Berkeley) 5/4/95";
     39 #else
     40 __RCSID("$NetBSD: jobs.c,v 1.130 2026/07/19 19:18:13 kre Exp $");
     41 #endif
     42 #endif /* not lint */
     43 
     44 #include <stdio.h>
     45 #include <fcntl.h>
     46 #include <signal.h>
     47 #include <errno.h>
     48 #include <unistd.h>
     49 #include <stdlib.h>
     50 #include <paths.h>
     51 #include <sys/types.h>
     52 #include <sys/param.h>
     53 #ifdef BSD
     54 #include <sys/wait.h>
     55 #include <sys/time.h>
     56 #include <sys/resource.h>
     57 #endif
     58 #include <sys/ioctl.h>
     59 
     60 #include "shell.h"
     61 #if JOBS
     62 #if OLD_TTY_DRIVER
     63 #include "sgtty.h"
     64 #else
     65 #include <termios.h>
     66 #endif
     67 #undef CEOF			/* syntax.h redefines this */
     68 #endif
     69 #include "redir.h"
     70 #include "show.h"
     71 #include "main.h"
     72 #include "parser.h"
     73 #include "nodes.h"
     74 #include "jobs.h"
     75 #include "var.h"
     76 #include "options.h"
     77 #include "builtins.h"
     78 #include "trap.h"
     79 #include "syntax.h"
     80 #include "input.h"
     81 #include "output.h"
     82 #include "memalloc.h"
     83 #include "error.h"
     84 #include "mystring.h"
     85 
     86 
     87 #ifndef	WCONTINUED
     88 #define	WCONTINUED 0		/* So we can compile on old systems */
     89 #endif
     90 #ifndef	WIFCONTINUED
     91 #define	WIFCONTINUED(x)	(0)		/* ditto */
     92 #endif
     93 
     94 
     95 static struct job *jobtab;		/* array of jobs */
     96 static int njobs;			/* size of array */
     97 static int jobs_invalid;		/* set in child */
     98 MKINIT pid_t backgndpid = -1;	/* pid of last background process */
     99 #if JOBS
    100 int initialpgrp;		/* pgrp of shell on invocation */
    101 static int curjob = -1;		/* current job */
    102 #endif
    103 static int ttyfd = -1;
    104 
    105 STATIC void restartjob(struct job *);
    106 STATIC void freejob(struct job *);
    107 STATIC void clear_jobs(void);
    108 STATIC struct job *getjob(const char *, int);
    109 STATIC int dowait(int, struct job *, struct job **);
    110 #define WBLOCK	1
    111 #define WNOFREE 2
    112 #define WSILENT 4
    113 STATIC int jobstatus(const struct job *, int);
    114 STATIC int waitproc(int, struct job *, int *);
    115 STATIC int cmdtxt(union node *, int);
    116 STATIC void cmdlist(union node *, int);
    117 STATIC void cmdputs(const char *);
    118 inline static void cmdputi(int);
    119 
    120 #define	JNUM(j)	((int)((j) != NULL ? ((j) - jobtab) + 1 : 0))
    121 
    122 #ifdef SYSV
    123 STATIC int onsigchild(void);
    124 #endif
    125 
    126 #ifdef OLD_TTY_DRIVER
    127 static pid_t tcgetpgrp(int fd);
    128 static int tcsetpgrp(int fd, pid_t pgrp);
    129 
    130 static pid_t
    131 tcgetpgrp(int fd)
    132 {
    133 	pid_t pgrp;
    134 	if (ioctl(fd, TIOCGPGRP, (char *)&pgrp) == -1)
    135 		return -1;
    136 	else
    137 		return pgrp;
    138 }
    139 
    140 static int
    141 tcsetpgrp(int fd, pid_tpgrp)
    142 {
    143 	return ioctl(fd, TIOCSPGRP, (char *)&pgrp);
    144 }
    145 #endif
    146 
    147 static void
    148 ttyfd_change(int from, int to)
    149 {
    150 	if (ttyfd == from)
    151 		ttyfd = to;
    152 }
    153 
    154 /*
    155  * Turn job control on and off.
    156  *
    157  * Note:  This code assumes that the third arg to ioctl is a character
    158  * pointer, which is true on Berkeley systems but not System V.  Since
    159  * System V doesn't have job control yet, this isn't a problem now.
    160  */
    161 
    162 MKINIT int jobctl;
    163 
    164 void
    165 setjobctl(int on)
    166 {
    167 #ifdef OLD_TTY_DRIVER
    168 	int ldisc;
    169 #endif
    170 
    171 	if (on == jobctl || rootshell == 0)
    172 		return;
    173 	if (on) {
    174 #if defined(FIOCLEX) || defined(FD_CLOEXEC)
    175 		int i;
    176 
    177 		if (ttyfd != -1)
    178 			sh_close(ttyfd);
    179 		if ((ttyfd = open("/dev/tty", O_RDWR)) == -1) {
    180 			for (i = 0; i < 3; i++) {
    181 				if (isatty(i) && (ttyfd = dup(i)) != -1)
    182 					break;
    183 			}
    184 			if (i == 3)
    185 				goto out;
    186 		}
    187 		ttyfd = to_upper_fd(ttyfd);	/* Move to a high fd */
    188 		register_sh_fd(ttyfd, ttyfd_change);
    189 #else
    190 		out2str("sh: Need FIOCLEX or FD_CLOEXEC to support job control");
    191 		goto out;
    192 #endif
    193 		if ((initialpgrp = tcgetpgrp(ttyfd)) < 0) {
    194  out:
    195 			out2str("sh: can't access tty; job control turned off\n");
    196 			mflag = 0;
    197 			return;
    198 		}
    199 		if (initialpgrp == -1)
    200 			initialpgrp = getpgrp();
    201 		else if (initialpgrp != getpgrp())
    202 			killpg(0, SIGTTIN);
    203 
    204 #ifdef OLD_TTY_DRIVER
    205 		if (ioctl(ttyfd, TIOCGETD, (char *)&ldisc) < 0
    206 		    || ldisc != NTTYDISC) {
    207 			out2str("sh: need new tty driver to run job control; job control turned off\n");
    208 			mflag = 0;
    209 			return;
    210 		}
    211 #endif
    212 		setsignal(SIGTSTP, 0);
    213 		setsignal(SIGTTOU, 0);
    214 		setsignal(SIGTTIN, 0);
    215 		if (getpgrp() != rootpid && setpgid(0, rootpid) == -1)
    216 			error("Cannot set process group (%s) at %d",
    217 			    strerror(errno), __LINE__);
    218 		if (tcsetpgrp(ttyfd, rootpid) == -1)
    219 			error("Cannot set tty process group (%s) at %d",
    220 			    strerror(errno), __LINE__);
    221 	} else { /* turning job control off */
    222 		if (getpgrp() != initialpgrp && setpgid(0, initialpgrp) == -1)
    223 			error("Cannot set process group (%s) at %d",
    224 			    strerror(errno), __LINE__);
    225 		if (tcsetpgrp(ttyfd, initialpgrp) == -1)
    226 			error("Cannot set tty process group (%s) at %d",
    227 			    strerror(errno), __LINE__);
    228 		sh_close(ttyfd);
    229 		ttyfd = -1;
    230 		setsignal(SIGTSTP, 0);
    231 		setsignal(SIGTTOU, 0);
    232 		setsignal(SIGTTIN, 0);
    233 	}
    234 	jobctl = on;
    235 }
    236 
    237 
    238 #ifdef mkinit
    239 INCLUDE <stdlib.h>
    240 
    241 SHELLPROC {
    242 	backgndpid = -1;
    243 #if JOBS
    244 	jobctl = 0;
    245 #endif
    246 }
    247 
    248 #endif
    249 
    250 
    251 
    252 #if JOBS
    253 static int
    254 do_fgcmd(const char *arg_ptr)
    255 {
    256 	struct job *jp;
    257 	int i;
    258 	int status;
    259 
    260 	if (jobs_invalid)
    261 		error("No current jobs");
    262 	jp = getjob(arg_ptr, 0);
    263 	if (jp->jobctl == 0)
    264 		error("job not created under job control");
    265 	out1fmt("%s", jp->ps[0].cmd);
    266 	for (i = 1; i < jp->nprocs; i++)
    267 		out1fmt(" | %s", jp->ps[i].cmd );
    268 	out1c('\n');
    269 	flushall();
    270 
    271 	if (tcsetpgrp(ttyfd, jp->pgrp) == -1) {
    272 		error("Cannot set tty process group (%s) at %d",
    273 		    strerror(errno), __LINE__);
    274 	}
    275 	INTOFF;
    276 	restartjob(jp);
    277 	status = waitforjob(jp);
    278 	INTON;
    279 	return status;
    280 }
    281 
    282 int
    283 fgcmd(int argc, char **argv)
    284 {
    285 	nextopt("");
    286 	return do_fgcmd(*argptr);
    287 }
    288 
    289 int
    290 fgcmd_percent(int argc, char **argv)
    291 {
    292 	nextopt("");
    293 	return do_fgcmd(*argv);
    294 }
    295 
    296 static void
    297 set_curjob(struct job *jp, int mode)
    298 {
    299 	struct job *jp1, *jp2;
    300 	int i, ji;
    301 
    302 	ji = jp - jobtab;
    303 
    304 	/* first remove from list */
    305 	if (ji == curjob)
    306 		curjob = jp->prev_job;
    307 	else {
    308 		for (i = 0; i < njobs; i++) {
    309 			if (jobtab[i].prev_job != ji)
    310 				continue;
    311 			jobtab[i].prev_job = jp->prev_job;
    312 			break;
    313 		}
    314 	}
    315 
    316 	/* Then re-insert in correct position */
    317 	switch (mode) {
    318 	case 0:	/* job being deleted */
    319 		jp->prev_job = -1;
    320 		break;
    321 	case 1:	/* newly created job or backgrounded job,
    322 		   put after all stopped jobs. */
    323 		if (curjob != -1 && jobtab[curjob].state == JOBSTOPPED) {
    324 			for (jp1 = jobtab + curjob; ; jp1 = jp2) {
    325 				if (jp1->prev_job == -1)
    326 					break;
    327 				jp2 = jobtab + jp1->prev_job;
    328 				if (jp2->state != JOBSTOPPED)
    329 					break;
    330 			}
    331 			jp->prev_job = jp1->prev_job;
    332 			jp1->prev_job = ji;
    333 			break;
    334 		}
    335 		/* FALLTHROUGH */
    336 	case 2:	/* newly stopped job - becomes curjob */
    337 		jp->prev_job = curjob;
    338 		curjob = ji;
    339 		break;
    340 	}
    341 }
    342 
    343 int
    344 bgcmd(int argc, char **argv)
    345 {
    346 	struct job *jp;
    347 	int i;
    348 
    349 	nextopt("");
    350 	if (jobs_invalid)
    351 		error("No current jobs");
    352 	do {
    353 		jp = getjob(*argptr, 0);
    354 		if (jp->jobctl == 0)
    355 			error("job not created under job control");
    356 		set_curjob(jp, 1);
    357 		out1fmt("[%d] %s", JNUM(jp), jp->ps[0].cmd);
    358 		for (i = 1; i < jp->nprocs; i++)
    359 			out1fmt(" | %s", jp->ps[i].cmd );
    360 		out1c('\n');
    361 		flushall();
    362 		restartjob(jp);
    363 	} while (*argptr && *++argptr);
    364 	return 0;
    365 }
    366 
    367 
    368 STATIC void
    369 restartjob(struct job *jp)
    370 {
    371 	struct procstat *ps;
    372 	int i, e;
    373 
    374 	if (jp->state == JOBDONE)
    375 		return;
    376 	if (jp->pgrp == 0)
    377 		error("Job [%d] does not have a process group", JNUM(jp));
    378 
    379 	INTOFF;
    380 	for (e = i = 0; i < jp->nprocs; i++) {
    381 		/*
    382 		 * Don't touch a process we already waited for and collected
    383 		 * exit status, that pid may have been reused for something
    384 		 * else - even another of our jobs
    385 		 */
    386 		if (jp->ps[i].status != -1 && !WIFSTOPPED(jp->ps[i].status))
    387 			continue;
    388 
    389 		/*
    390 		 * Otherwise tell it to continue, if it worked, we're done
    391 		 * (we signal the whole process group)
    392 		 */
    393 		if (killpg(jp->pgrp, SIGCONT) != -1)
    394 			break;
    395 		e = errno;
    396 		break;		/* no point trying again */
    397 	}
    398 
    399 	if (e != 0)
    400 		error("Cannot continue job (%s)", strerror(e));
    401 	else if (i >= jp->nprocs)
    402 		error("Job [%d] has no stopped processes", JNUM(jp));
    403 
    404 	/*
    405 	 * Now change state of all stopped processes in the job to running
    406 	 * If there were any, the job is now running as well.
    407 	 */
    408 	for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
    409 		if (WIFSTOPPED(ps->status)) {
    410 			VTRACE(DBG_JOBS, (
    411 			   "restartjob: [%d] pid %d status change"
    412 			   " from %#x (stopped) to -1 (running)\n",
    413 			   JNUM(jp), ps->pid, ps->status));
    414 			ps->status = -1;
    415 			jp->state = JOBRUNNING;
    416 		}
    417 	}
    418 	INTON;
    419 }
    420 #endif
    421 
    422 inline static void
    423 cmdputi(int n)
    424 {
    425 	char str[20];
    426 
    427 	fmtstr(str, sizeof str, "%d", n);
    428 	cmdputs(str);
    429 }
    430 
    431 static void
    432 showjob(struct output *out, struct job *jp, int mode)
    433 {
    434 	int procno;
    435 	int st;
    436 	struct procstat *ps;
    437 	int col;
    438 	char s[64];
    439 
    440 #if JOBS
    441 	if (mode & SHOW_PGID) {
    442 		/* output only the process group ID (lead process ID) */
    443 		outfmt(out, "%ld\n",
    444 		    jp->pgrp != 0 ? (long)jp->pgrp : (long)jp->ps->pid);
    445 		return;
    446 	}
    447 #endif
    448 
    449 	procno = jp->nprocs;
    450 	if (!procno)
    451 		return;
    452 
    453 	if (mode & SHOW_PID)
    454 		mode |= SHOW_MULTILINE;
    455 
    456 	if ((procno > 1 && !(mode & SHOW_MULTILINE))
    457 	    || (mode & SHOW_SIGNALLED)) {
    458 		/* See if we have more than one status to report */
    459 		ps = jp->ps;
    460 		st = ps->status;
    461 		do {
    462 			int st1 = ps->status;
    463 			if (st1 != st)
    464 				/* yes - need multi-line output */
    465 				mode |= SHOW_MULTILINE;
    466 			if (st1 == -1 || !(mode & SHOW_SIGNALLED) || WIFEXITED(st1))
    467 				continue;
    468 			if (WIFSTOPPED(st1) || ((st1 = WTERMSIG(st1) & 0x7f)
    469 			    && st1 != SIGINT && st1 != SIGPIPE))
    470 				mode |= SHOW_ISSIG;
    471 
    472 		} while (ps++, --procno);
    473 		procno = jp->nprocs;
    474 	}
    475 
    476 	if (mode & SHOW_SIGNALLED && !(mode & SHOW_ISSIG)) {
    477 		if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE)) {
    478 			VTRACE(DBG_JOBS, ("showjob: freeing job %d\n",
    479 			    JNUM(jp)));
    480 			freejob(jp);
    481 		}
    482 		return;
    483 	}
    484 
    485 	for (ps = jp->ps; --procno >= 0; ps++) {	/* for each process */
    486 		if (ps == jp->ps)
    487 			fmtstr(s, 16, "[%d] %c ",
    488 				JNUM(jp),
    489 #if JOBS
    490 				jp - jobtab == curjob ?
    491 									  '+' :
    492 				curjob != -1 &&
    493 				    jp - jobtab == jobtab[curjob].prev_job ?
    494 									  '-' :
    495 #endif
    496 				' ');
    497 		else
    498 			fmtstr(s, 16, "      " );
    499 		col = strlen(s);
    500 		if (mode & SHOW_PID) {
    501 			fmtstr(s + col, 16, "%ld ", (long)ps->pid);
    502 			     col += strlen(s + col);
    503 		}
    504 		if (ps->status == -1) {
    505 			scopy("Running", s + col);
    506 		} else if (WIFEXITED(ps->status)) {
    507 			st = WEXITSTATUS(ps->status);
    508 			if (st)
    509 				fmtstr(s + col, 16, "Done(%d)", st);
    510 			else
    511 				fmtstr(s + col, 16, "Done");
    512 		} else {
    513 #if JOBS
    514 			if (WIFSTOPPED(ps->status))
    515 				st = WSTOPSIG(ps->status);
    516 			else /* WIFSIGNALED(ps->status) */
    517 #endif
    518 				st = WTERMSIG(ps->status);
    519 			scopyn(strsignal(st), s + col, 32);
    520 			if (WCOREDUMP(ps->status)) {
    521 				col += strlen(s + col);
    522 				scopyn(" (core dumped)", s + col,  64 - col);
    523 			}
    524 		}
    525 		col += strlen(s + col);
    526 		outstr(s, out);
    527 		do {
    528 			outc(' ', out);
    529 			col++;
    530 		} while (col < 30);
    531 		outstr(ps->cmd, out);
    532 		if (mode & SHOW_MULTILINE) {
    533 			if (procno > 0) {
    534 				outc(' ', out);
    535 				outc('|', out);
    536 			}
    537 		} else {
    538 			while (--procno >= 0)
    539 				outfmt(out, " | %s", (++ps)->cmd );
    540 		}
    541 		outc('\n', out);
    542 	}
    543 	flushout(out);
    544 	jp->flags &= ~JOBCHANGED;
    545 	if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE))
    546 		freejob(jp);
    547 }
    548 
    549 int
    550 jobscmd(int argc, char **argv)
    551 {
    552 	int mode, m;
    553 
    554 	mode = 0;
    555 	while ((m = nextopt("lpZ")))
    556 		switch (m) {
    557 		case 'l':
    558 			mode = SHOW_PID;
    559 			break;
    560 		case 'p':
    561 			mode = SHOW_PGID;
    562 			break;
    563 		case 'Z':
    564 			mode = SHOW_PROCTITLE;
    565 			break;
    566 		}
    567 
    568 	if (mode == SHOW_PROCTITLE) {
    569 		if (*argptr && **argptr)
    570 			setproctitle("%s", *argptr);
    571 		else
    572 			setproctitle(NULL);
    573 		return 0;
    574 	}
    575 
    576 	if (!iflag && !posix)
    577 		mode |= SHOW_NO_FREE;
    578 
    579 	if (*argptr) {
    580 		do
    581 			showjob(out1, getjob(*argptr,0), mode);
    582 		while (*++argptr);
    583 	} else
    584 		showjobs(out1, mode);
    585 	return 0;
    586 }
    587 
    588 
    589 /*
    590  * Print a list of jobs.  If mode includes SHOW_CHANGED, only print jobs
    591  * whose statuses have changed since the last call to showjobs.
    592  *
    593  * If the shell is interrupted in the process of creating a job, the
    594  * result may be a job structure containing zero processes.  Such structures
    595  * will be freed here.
    596  */
    597 
    598 void
    599 showjobs(struct output *out, int mode)
    600 {
    601 	int jobno;
    602 	struct job *jp;
    603 	int silent = 0, gotpid;
    604 
    605 	CTRACE(DBG_JOBS, ("showjobs(%x) called\n", mode));
    606 
    607 	/*  Collect everything pending in the kernel */
    608 	if ((gotpid = dowait(WSILENT, NULL, NULL)) > 0)
    609 		while (dowait(WSILENT, NULL, NULL) > 0)
    610 			continue;
    611 #ifdef JOBS
    612 	/*
    613 	 * Check if we are not in our foreground group, and if not
    614 	 * put us in it.
    615 	 */
    616 	if (mflag && gotpid != -1 && tcgetpgrp(ttyfd) != getpid()) {
    617 		if (tcsetpgrp(ttyfd, getpid()) == -1)
    618 			error("Cannot set tty process group (%s) at %d",
    619 			    strerror(errno), __LINE__);
    620 		VTRACE(DBG_JOBS|DBG_INPUT, ("repaired tty process group\n"));
    621 		silent = 1;
    622 	}
    623 #endif
    624 
    625 	for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
    626 		if (!jp->used)
    627 			continue;
    628 		if (jp->nprocs == 0) {
    629 			if (!jobs_invalid)
    630 				freejob(jp);
    631 			continue;
    632 		}
    633 		if ((mode & SHOW_CHANGED) && !(jp->flags & JOBCHANGED))
    634 			continue;
    635 		if (silent && (jp->flags & JOBCHANGED)) {
    636 			jp->flags &= ~JOBCHANGED;
    637 			continue;
    638 		}
    639 		showjob(out, jp, mode);
    640 	}
    641 }
    642 
    643 /*
    644  * Mark a job structure as unused.
    645  */
    646 
    647 STATIC void
    648 freejob(struct job *jp)
    649 {
    650 	INTOFF;
    651 	if (jp->ps != &jp->ps0) {
    652 		ckfree(jp->ps);
    653 		jp->ps = &jp->ps0;
    654 	}
    655 	jp->nprocs = 0;
    656 	jp->used = 0;
    657 #if JOBS
    658 	set_curjob(jp, 0);
    659 #endif
    660 	INTON;
    661 }
    662 
    663 STATIC void
    664 clear_jobs(void)
    665 {
    666 	int i;
    667 	struct job *jp;
    668 
    669 	INTOFF;
    670 	for (i = njobs, jp = jobtab ; --i >= 0 ; jp++) {
    671 		if (jp->used)
    672 			freejob(jp);
    673 	}
    674 	INTON;
    675 }
    676 
    677 
    678 /*
    679  * Extract the status of a completed job (for $?)
    680  */
    681 STATIC int
    682 jobstatus(const struct job *jp, int raw)
    683 {
    684 	int status = 0;
    685 	int retval;
    686 
    687 	if ((jp->flags & JPIPEFAIL) && jp->nprocs) {
    688 		int i;
    689 
    690 		for (i = 0; i < jp->nprocs; i++)
    691 			if (jp->ps[i].status != 0)
    692 				status = jp->ps[i].status;
    693 	} else
    694 		status = jp->ps[jp->nprocs ? jp->nprocs - 1 : 0].status;
    695 
    696 	if (raw)
    697 		return status;
    698 
    699 	if (WIFEXITED(status))
    700 		retval = WEXITSTATUS(status);
    701 #if JOBS
    702 	else if (WIFSTOPPED(status))
    703 		retval = WSTOPSIG(status) + 128;
    704 #endif
    705 	else {
    706 		/* XXX: limits number of signals */
    707 		retval = WTERMSIG(status) + 128;
    708 	}
    709 
    710 	return retval;
    711 }
    712 
    713 
    714 
    715 int
    716 waitcmd(int argc, char **argv)
    717 {
    718 	struct job *job, *last;
    719 	int retval;
    720 	struct job *jp;
    721 	int i;
    722 	int any = 0;
    723 	int found;
    724 	int oldwait = 0;
    725 	char *pid = NULL, *fpid;
    726 	char **arg;
    727 	char idstring[20];
    728 
    729 	while ((i = nextopt("np:")) != '\0') {
    730 		switch (i) {
    731 		case 'n':
    732 			any = 1;
    733 			break;
    734 		case 'p':
    735 			if (pid)
    736 				error("more than one -p unsupported");
    737 			pid = optionarg;
    738 			break;
    739 		}
    740 	}
    741 
    742 	if (!any && *argptr == 0)
    743 		oldwait = 1;
    744 
    745 	if (pid != NULL) {
    746 		if (!validname(pid, '\0', NULL))
    747 			error("invalid name: -p '%s'", pid);
    748 		if (unsetvar(pid, 0))
    749 			error("%s readonly", pid);
    750 	}
    751 
    752 	/*
    753 	 * If we have forked, and not yet created any new jobs, then
    754 	 * we have no children, whatever jobtab claims,
    755 	 * so simply return in that case.
    756 	 *
    757 	 * The return code is 127 if we had any pid args (none are found)
    758 	 * or if we had -n (nothing exited), but 0 for plain old "wait".
    759 	 */
    760 	if (jobs_invalid) {
    761 		CTRACE(DBG_WAIT, ("builtin wait%s%s in child, invalid jobtab\n",
    762 		    any ? " -n" : "", *argptr ? " pid..." : ""));
    763 		return oldwait ? 0 : 127;
    764 	}
    765 
    766 	/*
    767 	 * clear stray flags left from previous waitcmd
    768 	 * or set them instead if anything will do ("wait -n")
    769 	 */
    770 	for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
    771 		if (any && *argptr == NULL)
    772 			jp->flags |= JOBWANTED;
    773 		else
    774 			jp->flags &= ~JOBWANTED;
    775 		jp->ref = NULL;
    776 	}
    777 
    778 	CTRACE(DBG_WAIT,
    779 	    ("builtin wait%s%s\n", any ? " -n" : "", *argptr ? " pid..." : ""));
    780 
    781 	/*
    782 	 * First, validate the jobnum args, count how many refer to
    783 	 * (different) running jobs, and if we had -n, and found that one has
    784 	 * already finished, we return that one.   Otherwise remember
    785 	 * which ones we are looking for (JOBWANTED).
    786 	 */
    787 	found = 0;
    788 	last = NULL;
    789 #ifdef	DEBUG
    790 	job = NULL;
    791 #endif
    792 	for (arg = argptr; *arg; arg++) {
    793 		last = jp = getjob(*arg, 1);
    794 		if (!jp)
    795 			continue;
    796 		if (jp->ref == NULL)
    797 			jp->ref = *arg;
    798 		if (any && jp->state == JOBDONE) {
    799 			/*
    800 			 * We just want any of them, and this one is
    801 			 * ready for consumption, bon apetit ...
    802 			 */
    803 			retval = jobstatus(jp, 0);
    804 			if (pid)
    805 				setvar(pid, *arg, 0);
    806 			if (!iflag)
    807 				freejob(jp);
    808 			CTRACE(DBG_WAIT, ("wait -n found %s already done: %d\n",			    *arg, retval));
    809 			return retval;
    810 		}
    811 		if (!(jp->flags & JOBWANTED)) {
    812 			/*
    813 			 * It is possible to list the same job several
    814 			 * times - the obvious "wait 1 1 1" or
    815 			 * "wait %% %2 102" where job 2 is current and pid 102
    816 			 * However many times it is requested, it is found once.
    817 			 */
    818 			found++;
    819 			jp->flags |= JOBWANTED;
    820 		}
    821 #ifdef DEBUG
    822 		job = jp;
    823 #endif
    824 	}
    825 
    826 	VTRACE(DBG_WAIT, ("wait %s%s%sfound %d candidates (last %s)\n",
    827 	    any ? "-n " : "", *argptr ? *argptr : "",
    828 	    argptr[0] && argptr[1] ? "... " : " ", found,
    829 	    job && job->used ? (job->ref ? job->ref : "<no-arg>") : "none"));
    830 
    831 	/*
    832 	 * If we were given a list of jobnums:
    833 	 * and none of those exist, then we're done.
    834 	 */
    835 	if (*argptr && found == 0)
    836 		return 127;
    837 
    838 	/*
    839 	 * Otherwise we need to wait for something to complete
    840 	 * When it does, we check and see if it is one of the
    841 	 * jobs we're waiting on, and if so, we clean it up.
    842 	 * If we had -n, then we're done, otherwise we do it all again
    843 	 * until all we had listed are done, of if there were no
    844 	 * jobnum args, all are done.
    845 	 */
    846 
    847 	retval = any || *argptr ? 127 : 0;
    848 	fpid = NULL;
    849 	for (;;) {
    850 		VTRACE(DBG_WAIT, ("wait waiting (%d remain): ", found));
    851 		job = NULL;
    852 		for (jp = jobtab, i = njobs; --i >= 0; jp++) {
    853 			if (jp->used && jp->flags & JOBWANTED &&
    854 			    jp->state == JOBDONE) {
    855 				job = jp;
    856 				break;
    857 			}
    858 			if (jp->used && jp->state == JOBRUNNING)
    859 				job = jp;
    860 		}
    861 		if (i < 0 && job == NULL) {
    862 			CTRACE(DBG_WAIT, ("nothing running (ret: %d) fpid %s\n",
    863 			    retval, fpid ? fpid : "unset"));
    864 			if (pid && fpid)
    865 				setvar(pid, fpid, 0);
    866 			return retval;
    867 		}
    868 		jp = job;
    869 		VTRACE(DBG_WAIT, ("found @%d/%d state: %d\n", njobs-i, njobs,
    870 		    jp->state));
    871 
    872 		/*
    873 		 * There is at least 1 job running, so we can
    874 		 * safely wait() (blocking) for something to exit.
    875 		 */
    876 		if (jp->state == JOBRUNNING) {
    877 			job = NULL;
    878 			if ((i = dowait(WBLOCK|WNOFREE, NULL, &job)) == -1)
    879 			       return 128 + lastsig();
    880 
    881 			/*
    882 			 * This happens if an interloper has died
    883 			 * (eg: a child of the executable that exec'd us)
    884 			 * Simply go back and start all over again
    885 			 * (this is rare).
    886 			 */
    887 			if (job == NULL)
    888 				continue;
    889 
    890 			/*
    891 			 * one of the reported job's processes exited,
    892 			 * but there are more still running, back for more
    893 			 */
    894 			if (job->state == JOBRUNNING)
    895 				continue;
    896 		} else
    897 			job = jp;	/* we want this, and it is done */
    898 
    899 		if (job->flags & JOBWANTED) {
    900 			int rv;
    901 
    902 			job->flags &= ~JOBWANTED;	/* got it */
    903 			rv = jobstatus(job, 0);
    904 			VTRACE(DBG_WAIT, (
    905 			    "wanted %d (%s) done: st=%d", i,
    906 			    job->ref ? job->ref : "", rv));
    907 			if (any || job == last) {
    908 				retval = rv;
    909 				fpid = job->ref;
    910 
    911 				VTRACE(DBG_WAIT, (" save"));
    912 				if (pid) {
    913 				   /*
    914 				    * don't need fpid unless we are going
    915 				    * to return it.
    916 				    */
    917 				   if (fpid == NULL) {
    918 					/*
    919 					 * this only happens with "wait -n"
    920 					 * (that is, no pid args)
    921 					 */
    922 					snprintf(idstring, sizeof idstring,
    923 					    "%d", job->ps[ job->nprocs ?
    924 						    job->nprocs-1 : 0 ].pid);
    925 					fpid = idstring;
    926 				    }
    927 				    VTRACE(DBG_WAIT, (" (for %s)", fpid));
    928 				}
    929 			}
    930 
    931 			if (job->state == JOBDONE) {
    932 				VTRACE(DBG_WAIT, (" free"));
    933 				freejob(job);
    934 			}
    935 
    936 			if (any || (found > 0 && --found == 0)) {
    937 				if (pid && fpid)
    938 					setvar(pid, fpid, 0);
    939 				VTRACE(DBG_WAIT, (" return %d\n", retval));
    940 				return retval;
    941 			}
    942 			VTRACE(DBG_WAIT, ("\n"));
    943 			continue;
    944 		}
    945 
    946 		/* this is to handle "wait" (no args) */
    947 		if (oldwait && job->state == JOBDONE) {
    948 			VTRACE(DBG_JOBS|DBG_WAIT, ("Cleanup: %d\n", i));
    949 			freejob(job);
    950 		}
    951 	}
    952 }
    953 
    954 
    955 int
    956 jobidcmd(int argc, char **argv)
    957 {
    958 	struct job *jp;
    959 	int i;
    960 	int pg = 0, onep = 0, job = 0;
    961 
    962 	while ((i = nextopt("gjp"))) {
    963 		switch (i) {
    964 		case 'g':	pg = 1;		break;
    965 		case 'j':	job = 1;	break;
    966 		case 'p':	onep = 1;	break;
    967 		}
    968 	}
    969 	CTRACE(DBG_JOBS, ("jobidcmd%s%s%s%s %s\n", pg ? " -g" : "",
    970 	    onep ? " -p" : "", job ? " -j" : "", jobs_invalid ? " [inv]" : "",
    971 	    *argptr ? *argptr : "<implicit %%>"));
    972 	if (pg + onep + job > 1)
    973 		error("-g -j and -p options cannot be combined");
    974 
    975 	if (argptr[0] && argptr[1])
    976 		error("usage: jobid [-g|-p|-r] jobid");
    977 
    978 	jp = getjob(*argptr, 0);
    979 	VTRACE(DBG_JOBS, ("jobidcmd.  jp=%p [%%%d] pg=%d pid=%d\n",
    980 	    jp, JNUM(jp), jp->pgrp, jp->ps[0].pid));
    981 
    982 	if (job) {
    983 		out1fmt("%%%d\n", JNUM(jp));
    984 		return 0;
    985 	}
    986 	if (pg) {
    987 		if (jp->pgrp != 0) {
    988 			out1fmt("%ld\n", (long)jp->pgrp);
    989 			return 0;
    990 		}
    991 		return 1;
    992 	}
    993 	if (onep) {
    994 		i = jp->nprocs - 1;
    995 		if (i < 0)
    996 			return 1;
    997 		out1fmt("%ld\n", (long)jp->ps[i].pid);
    998 		return 0;
    999 	}
   1000 	for (i = 0 ; i < jp->nprocs ; ) {
   1001 		out1fmt("%ld", (long)jp->ps[i].pid);
   1002 		out1c(++i < jp->nprocs ? ' ' : '\n');
   1003 	}
   1004 	return 0;
   1005 }
   1006 
   1007 #if JOBS
   1008 #ifndef SMALL
   1009 
   1010 static int
   1011 stop_me(int sig, int force, int pgrp, pid_t pid)
   1012 {
   1013 	if (force || (!loginsh && mflag && rootshell)) {
   1014 		struct sigaction sig_dfl, sig_was;
   1015 
   1016 		sig_dfl.sa_handler = SIG_DFL;
   1017 		sig_dfl.sa_flags = 0;
   1018 		sigemptyset(&sig_dfl.sa_mask);
   1019 
   1020 		(void)sigaction(sig, &sig_dfl, &sig_was);
   1021 
   1022 		if (kill(pgrp ? 0 : pid, sig) == -1) {
   1023 			sh_warn("suspend myself");
   1024 			(void)sigaction(sig, &sig_was, NULL);
   1025 			error(NULL);
   1026 		}
   1027 
   1028 		(void)sigaction(sig, &sig_was, NULL);
   1029 
   1030 		return 0;
   1031 	}
   1032 
   1033 	if (!rootshell)
   1034 		sh_warnx("subshell environment");
   1035 	else if (!mflag)
   1036 		sh_warnx("job control disabled");
   1037 	else if (loginsh)
   1038 		sh_warnx("login shell");
   1039 	else
   1040 		sh_warnx("not possible??");
   1041 
   1042 	return 1;
   1043 }
   1044 
   1045 int
   1046 suspendcmd(int argc, char **argv)
   1047 {
   1048 	int sig = SIGTSTP;
   1049 	int force = 0;
   1050 	int pgrp = 0;
   1051 	int status = 0;
   1052 	char *target;
   1053 	int c;
   1054 
   1055 	while ((c = nextopt("fgs:")) != 0) {
   1056 		switch (c) {
   1057 		case 'f':
   1058 			force = 1;
   1059 			break;
   1060 		case 'g':
   1061 			pgrp = 1;
   1062 			break;
   1063 		case 's':
   1064 			sig = signame_to_signum(optionarg);
   1065 
   1066 			if (sig != SIGSTOP && sig != SIGTSTP &&
   1067 			    sig != SIGTTIN && sig != SIGTTOU)
   1068 				error("bad signal '%s'", optionarg);
   1069 			break;
   1070 		}
   1071 	}
   1072 
   1073 	if (!*argptr)		/* suspend myself */
   1074 		return stop_me(sig, force, pgrp, getpid());
   1075 
   1076 	while ((target = *argptr++) != NULL)
   1077 	{
   1078 		int pid;
   1079 
   1080 		if (is_number(target)) {
   1081 			if ((pid = number(target)) == 0) {
   1082 				sh_warnx("Cannot (yet) suspend kernel (%s)",
   1083 				    target);
   1084 				status = 1;
   1085 				continue;
   1086 			}
   1087 		} else if ((pid = getjobpgrp(target)) == 0) {
   1088 			sh_warnx("Unknown job: %s", target);
   1089 			status = 1;
   1090 			continue;
   1091 		}
   1092 
   1093 		if (pid == rootpid || pid == getpid()) {
   1094 			status |= stop_me(sig, force, pgrp, pid);
   1095 			continue;
   1096 		}
   1097 
   1098 		if (pid == 1 || pid == -1) {
   1099 			sh_warnx("Don't be funny");
   1100 			status = 1;
   1101 			continue;
   1102 		}
   1103 
   1104 		if (pid > 0 && pgrp)
   1105 			pid = -pid;
   1106 
   1107 		if (kill(pid, sig) == -1) {
   1108 			sh_warn("failed to suspend %s", target);
   1109 			status = 1;
   1110 		}
   1111 	}
   1112 
   1113 	return status;
   1114 }
   1115 #endif	/* SMALL */
   1116 #endif	/* JOBS */
   1117 
   1118 int
   1119 getjobpgrp(const char *name)
   1120 {
   1121 	struct job *jp;
   1122 
   1123 	if (jobs_invalid)
   1124 		return 0;
   1125 	jp = getjob(name, 1);
   1126 	if (jp == 0)
   1127 		return 0;
   1128 	return -jp->pgrp;
   1129 }
   1130 
   1131 /*
   1132  * Convert a job name to a job structure.
   1133  */
   1134 
   1135 STATIC struct job *
   1136 getjob(const char *name, int noerror)
   1137 {
   1138 	int jobno = -1;
   1139 	struct job *jp;
   1140 	int pid;
   1141 	int i;
   1142 	const char *err_msg = "No such job: %s";
   1143 
   1144 	if (name == NULL) {
   1145 #if JOBS
   1146 		jobno = curjob;
   1147 #endif
   1148 		err_msg = "No current job";
   1149 	} else if (name[0] == '%') {
   1150 		if (is_number(name + 1)) {
   1151 			jobno = number(name + 1) - 1;
   1152 		} else if (!name[1] || !name[2]) {
   1153 			switch (name[1]) {
   1154 #if JOBS
   1155 			case 0:
   1156 			case '+':
   1157 			case '%':
   1158 				jobno = curjob;
   1159 				err_msg = "No current job";
   1160 				break;
   1161 			case '-':
   1162 				jobno = curjob;
   1163 				if (jobno != -1)
   1164 					jobno = jobtab[jobno].prev_job;
   1165 				err_msg = "No previous job";
   1166 				break;
   1167 #endif
   1168 			default:
   1169 				goto check_pattern;
   1170 			}
   1171 		} else {
   1172 			struct job *found;
   1173     check_pattern:
   1174 			found = NULL;
   1175 			for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
   1176 				if (!jp->used || jp->nprocs <= 0)
   1177 					continue;
   1178 				if ((name[1] == '?'
   1179 					&& strstr(jp->ps[0].cmd, name + 2))
   1180 				    || prefix(name + 1, jp->ps[0].cmd)) {
   1181 					if (found) {
   1182 						err_msg = "%s: ambiguous";
   1183 						found = 0;
   1184 						break;
   1185 					}
   1186 					found = jp;
   1187 				}
   1188 			}
   1189 			if (found)
   1190 				return found;
   1191 		}
   1192 
   1193 	} else if (is_number(name)) {
   1194 		pid = number(name);
   1195 		for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
   1196 			if (jp->used && jp->nprocs > 0
   1197 			 && jp->ps[jp->nprocs - 1].pid == pid)
   1198 				return jp;
   1199 		}
   1200 	}
   1201 
   1202 	if (jobno >= 0 && jobno < njobs) {
   1203 		jp = jobtab + jobno;
   1204 		if (jp->used)
   1205 			return jp;
   1206 	}
   1207 	if (!noerror)
   1208 		error(err_msg, name);
   1209 	return 0;
   1210 }
   1211 
   1212 
   1213 /*
   1214  * Find out if there are any running (that is, unwaited upon)
   1215  * background children of the current shell.
   1216  *
   1217  * Return 1/0 (yes, no).
   1218  *
   1219  * Needed as we cannot optimise away sub-shell creation if
   1220  * we have such a child, or a "wait" in that sub-shell would
   1221  * observe the already existing job.
   1222  */
   1223 int
   1224 anyjobs(void)
   1225 {
   1226 	struct job *jp;
   1227 	int i;
   1228 
   1229 	if (jobs_invalid)
   1230 		return 0;
   1231 
   1232 	for (i = njobs, jp = jobtab ; --i >= 0 ; jp++) {
   1233 		if (jp->used)
   1234 			return 1;
   1235 	}
   1236 
   1237 	return 0;
   1238 }
   1239 
   1240 /*
   1241  * Output the (new) POSIX required "[%d] %d" string whenever an
   1242  * async (ie: background) job is started in an interactive shell.
   1243  * Note that a subshell environment is not regarded as interactive.
   1244  */
   1245 void
   1246 jobstarted(struct job *jp)
   1247 {
   1248 	if (!iflag || !rootshell)
   1249 		return;
   1250 
   1251 	outfmt(out2, "[%d] %ld\n", JNUM(jp),
   1252 	    jp->pgrp != 0 ? (long)jp->pgrp : (long)jp->ps->pid);
   1253 }
   1254 
   1255 /*
   1256  * Return a new job structure,
   1257  */
   1258 
   1259 struct job *
   1260 makejob(union node *node, int nprocs)
   1261 {
   1262 	int i;
   1263 	struct job *jp;
   1264 
   1265 	if (jobs_invalid && nprocs > 0) {
   1266 		VTRACE(DBG_JOBS, ("makejob(%p, %d) clearing jobtab (%d)\n",
   1267 			(void *)node, nprocs, njobs));
   1268 		clear_jobs();
   1269 		jobs_invalid = 0;
   1270 	}
   1271 
   1272 	for (i = njobs, jp = jobtab ; ; jp++) {
   1273 		if (--i < 0) {
   1274 			INTOFF;
   1275 			if (njobs == 0) {
   1276 				jobtab = ckmalloc(4 * sizeof jobtab[0]);
   1277 			} else {
   1278 				jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
   1279 				memcpy(jp, jobtab, njobs * sizeof jp[0]);
   1280 				/* Relocate `ps' pointers */
   1281 				for (i = 0; i < njobs; i++)
   1282 					if (jp[i].ps == &jobtab[i].ps0)
   1283 						jp[i].ps = &jp[i].ps0;
   1284 				ckfree(jobtab);
   1285 				jobtab = jp;
   1286 			}
   1287 			jp = jobtab + njobs;
   1288 			for (i = 4 ; --i >= 0 ; njobs++) {
   1289 				jobtab[njobs].used = 0;
   1290 				jobtab[njobs].prev_job = -1;
   1291 			}
   1292 			INTON;
   1293 			break;
   1294 		}
   1295 		if (jp->used == 0)
   1296 			break;
   1297 	}
   1298 	INTOFF;
   1299 	jp->state = JOBRUNNING;
   1300 	jp->used = 1;
   1301 	jp->flags = pipefail ? JPIPEFAIL : 0;
   1302 	jp->nprocs = 0;
   1303 	jp->pgrp = 0;
   1304 #if JOBS
   1305 	if (nprocs > 0) {
   1306 		jp->jobctl = jobctl;
   1307 		set_curjob(jp, 1);
   1308 	} else
   1309 		jp->jobctl = 0;
   1310 #endif
   1311 	if (nprocs > 1) {
   1312 		jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
   1313 	} else {
   1314 		jp->ps = &jp->ps0;
   1315 	}
   1316 	INTON;
   1317 	VTRACE(DBG_JOBS, ("makejob(%p, %d)%s returns %%%d\n", (void *)node,
   1318 	    nprocs, (jp->flags & JPIPEFAIL) ? " PF" : "", JNUM(jp)));
   1319 	return jp;
   1320 }
   1321 
   1322 
   1323 /*
   1324  * Fork off a subshell.  If we are doing job control, give the subshell its
   1325  * own process group.  Jp is a job structure that the job is to be added to.
   1326  * N is the command that will be evaluated by the child.  Both jp and n may
   1327  * be NULL.  The mode parameter can be one of the following:
   1328  *	FORK_FG - Fork off a foreground process.
   1329  *	FORK_BG - Fork off a background process.
   1330  *	FORK_NOJOB - Like FORK_FG, but don't give the process its own
   1331  *		     process group even if job control is on.
   1332  *
   1333  * When job control is turned off, background processes have their standard
   1334  * input redirected to /dev/null (except for the second and later processes
   1335  * in a pipeline).
   1336  */
   1337 
   1338 int
   1339 forkshell(struct job *jp, union node *n, int mode)
   1340 {
   1341 	pid_t pid;
   1342 	int serrno;
   1343 	sigset_t block_all, oldstate;
   1344 
   1345 	CTRACE(DBG_JOBS, ("forkshell(%%%d, %p, %d) called\n",
   1346 	    JNUM(jp), n, mode));
   1347 
   1348 	/*
   1349 	 * Immediately after the fork(), until the child process
   1350 	 * has had a chance to reset its idea of how signals should
   1351 	 * be processed, it is vulnerable to receiving signals which
   1352 	 * were trapped in the parent, but cannot be in the child,
   1353 	 * without having any good way to recognise that.
   1354 	 * So block all signals, temporarily, in the parent, just
   1355 	 * over the fork() sys call, in the child, until it is ready.
   1356 	 */
   1357 	(void)sigfillset(&block_all);
   1358 	(void)sigprocmask(SIG_BLOCK, &block_all, &oldstate);
   1359 	switch ((pid = fork())) {
   1360 	case -1:
   1361 		serrno = errno;
   1362 		(void)sigprocmask(SIG_SETMASK, &oldstate, NULL);
   1363 		VTRACE(DBG_JOBS, ("Fork failed, errno=%d\n", serrno));
   1364 		error("Cannot fork (%s)", strerror(serrno));
   1365 		/* NOTREACHED */
   1366 		break;
   1367 	case 0:
   1368 		SHELL_FORKED();
   1369 		forkchild(jp, n, mode, 0, &oldstate);
   1370 		return 0;
   1371 	default:
   1372 		(void)sigprocmask(SIG_SETMASK, &oldstate, NULL);
   1373 		return forkparent(jp, n, mode, pid);
   1374 	}
   1375 }
   1376 
   1377 int
   1378 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
   1379 {
   1380 	int pgrp = 0;
   1381 
   1382 	if (rootshell && mode != FORK_NOJOB && mflag) {
   1383 		/*
   1384 		 * The process group ID must always be that of the
   1385 		 * first process created for the job.   If this proc
   1386 		 * is the first, that's us, otherwise the pgrp has
   1387 		 * already been determined.
   1388 		 */
   1389 		if (jp == NULL || jp->nprocs == 0)
   1390 			pgrp = pid;
   1391 		else
   1392 			pgrp = jp->pgrp;
   1393 		/* This can fail because we are doing it in the child also */
   1394 		(void)setpgid(pid, pgrp);
   1395 	}
   1396 	if (mode == FORK_BG)
   1397 		backgndpid = pid;		/* set $! */
   1398 	if (jp) {
   1399 		struct procstat *ps = &jp->ps[jp->nprocs++];
   1400 		ps->pid = pid;
   1401 		ps->status = -1;
   1402 		ps->cmd[0] = 0;
   1403 		jp->pgrp = pgrp;	/* 0 if !mflag */
   1404 		if (/* iflag && rootshell && */ n)
   1405 			commandtext(ps, n);
   1406 	}
   1407 	CTRACE(DBG_JOBS, ("In parent shell: child = %d (mode %d)\n",pid,mode));
   1408 	return pid;
   1409 }
   1410 
   1411 void
   1412 forkchild(struct job *jp, union node *n, int mode, int vforked, sigset_t *sigs)
   1413 {
   1414 	int wasroot;
   1415 	int pgrp;
   1416 	const char *devnull = _PATH_DEVNULL;
   1417 	const char *nullerr = "Can't open %s";
   1418 
   1419 	wasroot = rootshell;
   1420 	CTRACE(DBG_JOBS, ("Child shell %d %sforked from %d (mode %d)\n",
   1421 	    getpid(), vforked?"v":"", getppid(), mode));
   1422 
   1423 	if (!vforked) {
   1424 		rootshell = 0;
   1425 		handler = &main_handler;
   1426 	}
   1427 
   1428 	closescript(vforked);
   1429 	clear_traps(vforked);
   1430 
   1431 	/*
   1432 	 * If the jobs table is invalid (belongs to our parent) when we are
   1433 	 * forking another child (jobs table belongs to its grandparent)
   1434 	 * Then simply zap it (it cannot have any useful information for us)
   1435 	 *
   1436 	 * We don't do this if vforked, as we're not allowed to touch any
   1437 	 * memory (almost) in that state, certainly not call malloc/free,
   1438 	 * but we don't need to, vfork() will never be used in a
   1439 	 * situation where it matters (running subshells, cmdsubs)
   1440 	 */
   1441 	if (jobs_invalid && !vforked)
   1442 		clear_jobs();
   1443 
   1444 	/*
   1445 	 * Now we have the trap state as we want it, signals can
   1446 	 * be allowed to arrive again
   1447 	 */
   1448 	(void)sigprocmask(SIG_SETMASK, sigs, NULL);
   1449 #if JOBS
   1450 	if (!vforked)
   1451 		jobctl = 0;		/* do job control only in root shell */
   1452 	if (wasroot && mode != FORK_NOJOB && mflag) {
   1453 		if (jp == NULL || jp->nprocs == 0)
   1454 			pgrp = getpid();
   1455 		else
   1456 			pgrp = jp->ps[0].pid;
   1457 		/* This can fail because we are doing it in the parent also */
   1458 		(void)setpgid(0, pgrp);
   1459 		if (mode == FORK_FG) {
   1460 			if (tcsetpgrp(ttyfd, pgrp) == -1)
   1461 				error("Cannot set tty process group (%s) at %d",
   1462 				    strerror(errno), __LINE__);
   1463 		}
   1464 		VTRACE(DBG_SIG, ("Child, resetting TSTP TTOU (mode=%d)\n",
   1465 		    mode));
   1466 		setsignal(SIGTSTP, vforked);
   1467 		setsignal(SIGTTOU, vforked);
   1468 	} else if (mode == FORK_BG) {
   1469 		VTRACE(DBG_SIG, ("BG Child, ignoring INT QUIT "
   1470 		    "(wasroot=%d mode=%d mflag=%d)\n", wasroot, mode, mflag));
   1471 		ignoresig(SIGINT, vforked);
   1472 		ignoresig(SIGQUIT, vforked);
   1473 		if ((jp == NULL || jp->nprocs == 0) &&
   1474 		    ! fd0_redirected_p ()) {
   1475 			close(0);
   1476 			if (open(devnull, O_RDONLY) != 0)
   1477 				error(nullerr, devnull);
   1478 		}
   1479 	}
   1480 #else
   1481 	if (mode == FORK_BG) {
   1482 		ignoresig(SIGINT, vforked);
   1483 		ignoresig(SIGQUIT, vforked);
   1484 		if ((jp == NULL || jp->nprocs == 0) &&
   1485 		    ! fd0_redirected_p ()) {
   1486 			close(0);
   1487 			if (open(devnull, O_RDONLY) != 0)
   1488 				error(nullerr, devnull);
   1489 		}
   1490 	}
   1491 #endif
   1492 	if (wasroot && iflag) {
   1493 		setsignal(SIGINT, vforked);
   1494 		setsignal(SIGQUIT, vforked);
   1495 		setsignal(SIGTERM, vforked);
   1496 	}
   1497 
   1498 	if (!vforked)
   1499 		jobs_invalid = 1;
   1500 }
   1501 
   1502 /*
   1503  * Wait for job to finish.
   1504  *
   1505  * Under job control we have the problem that while a child process is
   1506  * running interrupts generated by the user are sent to the child but not
   1507  * to the shell.  This means that an infinite loop started by an inter-
   1508  * active user may be hard to kill.  With job control turned off, an
   1509  * interactive user may place an interactive program inside a loop.  If
   1510  * the interactive program catches interrupts, the user doesn't want
   1511  * these interrupts to also abort the loop.  The approach we take here
   1512  * is to have the shell ignore interrupt signals while waiting for a
   1513  * foreground process to terminate, and then send itself an interrupt
   1514  * signal if the child process was terminated by an interrupt signal.
   1515  * Unfortunately, some programs want to do a bit of cleanup and then
   1516  * exit on interrupt; unless these processes terminate themselves by
   1517  * sending a signal to themselves (instead of calling exit) they will
   1518  * confuse this approach.
   1519  */
   1520 
   1521 int
   1522 waitforjob(struct job *jp)
   1523 {
   1524 #if JOBS
   1525 	int mypgrp = getpgrp();
   1526 #endif
   1527 	int status;
   1528 	int st;
   1529 
   1530 	INTOFF;
   1531 	VTRACE(DBG_JOBS, ("waitforjob(%%%d) called\n", JNUM(jp)));
   1532 	while (jp->state == JOBRUNNING) {
   1533 		dowait(WBLOCK, jp, NULL);
   1534 	}
   1535 #if JOBS
   1536 	if (jp->jobctl) {
   1537 		if (tcsetpgrp(ttyfd, mypgrp) == -1)
   1538 			error("Cannot set tty process group (%s) at %d",
   1539 			    strerror(errno), __LINE__);
   1540 	}
   1541 	if (jp->state == JOBSTOPPED && curjob != jp - jobtab)
   1542 		set_curjob(jp, 2);
   1543 #endif
   1544 	status = jobstatus(jp, 1);
   1545 
   1546 	/* convert to 8 bits */
   1547 	if (WIFEXITED(status))
   1548 		st = WEXITSTATUS(status);
   1549 #if JOBS
   1550 	else if (WIFSTOPPED(status))
   1551 		st = WSTOPSIG(status) + 128;
   1552 #endif
   1553 	else
   1554 		st = WTERMSIG(status) + 128;
   1555 
   1556 	VTRACE(DBG_JOBS, ("waitforjob: job %d, nproc %d, status %d, st %x\n",
   1557 		JNUM(jp), jp->nprocs, status, st));
   1558 #if JOBS
   1559 	if (jp->jobctl) {
   1560 		/*
   1561 		 * This is truly gross.
   1562 		 * If we're doing job control, then we did a TIOCSPGRP which
   1563 		 * caused us (the shell) to no longer be in the controlling
   1564 		 * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
   1565 		 * intuit from the subprocess exit status whether a SIGINT
   1566 		 * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
   1567 		 */
   1568 		if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
   1569 			raise(SIGINT);
   1570 	}
   1571 #endif
   1572 	if (! JOBS || jp->state == JOBDONE)
   1573 		freejob(jp);
   1574 	INTON;
   1575 	return st;
   1576 }
   1577 
   1578 
   1579 
   1580 /*
   1581  * Wait for a process (any process) to terminate.
   1582  *
   1583  * If "job" is given (not NULL), then its jobcontrol status (and mflag)
   1584  * are used to determine if we wait for stopping/continuing processes or
   1585  * only terminating ones, and the decision whether to report to stdout
   1586  * or not varies depending what happened, and whether the affected job
   1587  * is the one that was requested or not.
   1588  *
   1589  * If "changed" is not NULL, then the job which changed because a
   1590  * process terminated/stopped will be reported by setting *changed,
   1591  * if there is any such job, otherwise we set *changed = NULL.
   1592  */
   1593 
   1594 STATIC int
   1595 dowait(int flags, struct job *job, struct job **changed)
   1596 {
   1597 	int pid;
   1598 	int status;
   1599 	struct procstat *sp;
   1600 	struct job *jp;
   1601 	struct job *thisjob;
   1602 	int done;
   1603 	int stopped;
   1604 	int err;
   1605 
   1606 	VTRACE(DBG_JOBS|DBG_PROCS, ("dowait(%x) called for job %d%s\n",
   1607 	    flags, JNUM(job), changed ? " [report change]" : ""));
   1608 
   1609 	if (changed != NULL)
   1610 		*changed = NULL;
   1611 
   1612 	/*
   1613 	 * First deal with the kernel, collect info on any (one) of our
   1614 	 * children that has changed state since we last asked.
   1615 	 * (loop if we're interrupted by a signal that we aren't processing)
   1616 	 */
   1617 	do {
   1618 		err = 0;
   1619 		pid = waitproc(flags & WBLOCK, job, &status);
   1620 		if (pid == -1)
   1621 			err = errno;
   1622 		VTRACE(DBG_JOBS|DBG_PROCS,
   1623 		    ("wait returns pid %d (e:%d), status %#x (ps=%d)\n",
   1624 		    pid, err, status, pendingsigs));
   1625 	} while (pid == -1 && err == EINTR && pendingsigs == 0);
   1626 
   1627 	/*
   1628 	 * if nothing exited/stopped/..., we have nothing else to do
   1629 	 */
   1630 	if (pid <= 0)
   1631 		return pid;
   1632 
   1633 	/*
   1634 	 * Otherwise, try to find the process, somewhere in our job table
   1635 	 */
   1636 	INTOFF;
   1637 	thisjob = NULL;
   1638 	for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
   1639 		if (jp->used) {
   1640 			/*
   1641 			 * For each job that is in use (this is one)
   1642 			 */
   1643 			done = 1;	/* assume it is finished */
   1644 			stopped = 1;	/* and has stopped */
   1645 
   1646 			/*
   1647 			 * Now scan all our child processes of the job
   1648 			 */
   1649 			for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
   1650 				if (sp->pid == -1)
   1651 					continue;
   1652 				/*
   1653 				 * If the process that changed is the one
   1654 				 * we're looking at, and it was previously
   1655 				 * running (-1) or was stopped (anything else
   1656 				 * and it must have already finished earlier,
   1657 				 * so cannot be the process that just changed)
   1658 				 * then we update its status
   1659 				 */
   1660 				if (sp->pid == pid &&
   1661 				  (sp->status==-1 || WIFSTOPPED(sp->status))) {
   1662 					VTRACE(DBG_JOBS | DBG_PROCS,
   1663 			("Job %d: changing status of proc %d from %#x to ",
   1664 					    JNUM(jp), pid, sp->status));
   1665 
   1666 					/*
   1667 					 * If the process continued,
   1668 					 * then update its status to running
   1669 					 * and mark the job running as well.
   1670 					 *
   1671 					 * If it was anything but running
   1672 					 * before, flag it as a change for
   1673 					 * reporting purposes later
   1674 					 */
   1675 					if (WIFCONTINUED(status)) {
   1676 						if (sp->status != -1)
   1677 							jp->flags |= JOBCHANGED;
   1678 						sp->status = -1;
   1679 						jp->state = JOBRUNNING;
   1680 						VTRACE(DBG_JOBS|DBG_PROCS,
   1681 						    ("running\n"));
   1682 					} else {
   1683 						/* otherwise update status */
   1684 						sp->status = status;
   1685 						VTRACE(DBG_JOBS|DBG_PROCS,
   1686 						    ("%#x\n", status));
   1687 					}
   1688 
   1689 					/*
   1690 					 * We now know the affected job
   1691 					 */
   1692 					thisjob = jp;
   1693 					if (changed != NULL)
   1694 						*changed = jp;
   1695 				}
   1696 				/*
   1697 				 * After any update that might have just
   1698 				 * happened, if this process is running,
   1699 				 * the job is not stopped, or if the process
   1700 				 * simply stopped (not terminated) then the
   1701 				 * job is certainly not completed (done).
   1702 				 */
   1703 				if (sp->status == -1)
   1704 					stopped = 0;
   1705 				else if (WIFSTOPPED(sp->status))
   1706 					done = 0;
   1707 			}
   1708 
   1709 			/*
   1710 			 * Once we have examined all processes for the
   1711 			 * job, if we still show it as stopped, then...
   1712 			 */
   1713 			if (stopped) {		/* stopped or done */
   1714 				/*
   1715 				 * it might be stopped, or finished, decide:
   1716 				 */
   1717 				int state = done ? JOBDONE : JOBSTOPPED;
   1718 
   1719 				/*
   1720 				 * If that wasn't the same as it was before
   1721 				 * then update its state, and if it just
   1722 				 * completed, make it be the current job (%%)
   1723 				 */
   1724 				if (jp->state != state) {
   1725 					VTRACE(DBG_JOBS,
   1726 				("Job %d: changing state from %d to %d\n",
   1727 					    JNUM(jp), jp->state, state));
   1728 					jp->state = state;
   1729 #if JOBS
   1730 					if (done)
   1731 						set_curjob(jp, 0);
   1732 #endif
   1733 				}
   1734 			}
   1735 		}
   1736 	}
   1737 
   1738 	/*
   1739 	 * Now we have scanned all jobs.   If we found the job that
   1740 	 * the process that changed state belonged to (we occasionally
   1741 	 * fork processes without associating them with a job, when one
   1742 	 * of those finishes, we simply ignore it, the zombie has been
   1743 	 * cleaned up, which is all that matters) then we need to
   1744 	 * determine if we should say something about it to stdout
   1745 	 */
   1746 
   1747 	if (thisjob &&
   1748 	    (thisjob->state != JOBRUNNING || thisjob->flags & JOBCHANGED)) {
   1749 		int mode = 0;
   1750 
   1751 		if (!rootshell || !iflag)
   1752 			mode = SHOW_SIGNALLED;
   1753 		if ((job == thisjob && (flags & WNOFREE) == 0) ||
   1754 		    job != thisjob)
   1755 			mode = SHOW_SIGNALLED | SHOW_NO_FREE;
   1756 		if (mode && (flags & WSILENT) == 0)
   1757 			showjob(out2, thisjob, mode);
   1758 		else {
   1759 			VTRACE(DBG_JOBS,
   1760 			    ("Not printing status for %p [%d], "
   1761 			     "mode=%#x rootshell=%d, job=%p [%d]\n",
   1762 			    thisjob, JNUM(thisjob), mode, rootshell,
   1763 			    job, JNUM(job)));
   1764 			thisjob->flags |= JOBCHANGED;
   1765 		}
   1766 	}
   1767 
   1768 	INTON;
   1769 	/*
   1770 	 * Finally tell our caller that something happened (in general all
   1771 	 * anyone tests for is <= 0 (or >0) so the actual pid value here
   1772 	 * doesn't matter much, but we know pid is >0 so we may as well
   1773 	 * give back something meaningful
   1774 	 */
   1775 	return pid;
   1776 }
   1777 
   1778 
   1779 
   1780 /*
   1781  * Do a wait system call.  If job control is compiled in, we accept
   1782  * stopped processes.  If block is zero, we return a value of zero
   1783  * rather than blocking.
   1784  *
   1785  * System V doesn't have a non-blocking wait system call.  It does
   1786  * have a SIGCLD signal that is sent to a process when one of its
   1787  * children dies.  The obvious way to use SIGCLD would be to install
   1788  * a handler for SIGCLD which simply bumped a counter when a SIGCLD
   1789  * was received, and have waitproc bump another counter when it got
   1790  * the status of a process.  Waitproc would then know that a wait
   1791  * system call would not block if the two counters were different.
   1792  * This approach doesn't work because if a process has children that
   1793  * have not been waited for, System V will send it a SIGCLD when it
   1794  * installs a signal handler for SIGCLD.  What this means is that when
   1795  * a child exits, the shell will be sent SIGCLD signals continuously
   1796  * until is runs out of stack space, unless it does a wait call before
   1797  * restoring the signal handler.  The code below takes advantage of
   1798  * this (mis)feature by installing a signal handler for SIGCLD and
   1799  * then checking to see whether it was called.  If there are any
   1800  * children to be waited for, it will be.
   1801  *
   1802  * If neither SYSV nor BSD is defined, we don't implement nonblocking
   1803  * waits at all.  In this case, the user will not be informed when
   1804  * a background process ends until the next time she runs a real program
   1805  * (as opposed to running a builtin command or just typing return),
   1806  * and the jobs command may give out of date information.
   1807  */
   1808 
   1809 #ifdef SYSV
   1810 STATIC int gotsigchild;
   1811 
   1812 STATIC int onsigchild() {
   1813 	gotsigchild = 1;
   1814 }
   1815 #endif
   1816 
   1817 
   1818 STATIC int
   1819 waitproc(int block, struct job *jp, int *status)
   1820 {
   1821 #ifdef BSD
   1822 	int flags = 0;
   1823 
   1824 #if JOBS
   1825 	if (mflag || (jp != NULL && jp->jobctl))
   1826 		flags |= WUNTRACED | WCONTINUED;
   1827 #endif
   1828 	if (block == 0)
   1829 		flags |= WNOHANG;
   1830 	VTRACE(DBG_WAIT, ("waitproc: doing waitpid(flags=%#x)\n", flags));
   1831 	return waitpid(-1, status, flags);
   1832 #else
   1833 #ifdef SYSV
   1834 	int (*save)();
   1835 
   1836 	if (block == 0) {
   1837 		gotsigchild = 0;
   1838 		save = signal(SIGCLD, onsigchild);
   1839 		signal(SIGCLD, save);
   1840 		if (gotsigchild == 0)
   1841 			return 0;
   1842 	}
   1843 	return wait(status);
   1844 #else
   1845 	if (block == 0)
   1846 		return 0;
   1847 	return wait(status);
   1848 #endif
   1849 #endif
   1850 }
   1851 
   1852 /*
   1853  * return 1 if there are stopped jobs, otherwise 0
   1854  */
   1855 int job_warning = 0;
   1856 int
   1857 stoppedjobs(void)
   1858 {
   1859 	int jobno;
   1860 	struct job *jp;
   1861 
   1862 	if (job_warning || jobs_invalid)
   1863 		return (0);
   1864 	for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
   1865 		if (jp->used == 0)
   1866 			continue;
   1867 		if (jp->state == JOBSTOPPED) {
   1868 			out2str("You have stopped jobs.\n");
   1869 			job_warning = 2;
   1870 			return (1);
   1871 		}
   1872 	}
   1873 
   1874 	return (0);
   1875 }
   1876 
   1877 /*
   1878  * Return a string identifying a command (to be printed by the
   1879  * jobs command).
   1880  */
   1881 
   1882 STATIC char *cmdnextc;
   1883 STATIC int cmdnleft;
   1884 
   1885 void
   1886 commandtext(struct procstat *ps, union node *n)
   1887 {
   1888 	int len;
   1889 
   1890 	cmdnextc = ps->cmd;
   1891 	if (iflag || mflag || sizeof(ps->cmd) <= 60)
   1892 		len = sizeof(ps->cmd);
   1893 	else if (sizeof ps->cmd <= 400)
   1894 		len = 50;
   1895 	else if (sizeof ps->cmd <= 800)
   1896 		len = 80;
   1897 	else
   1898 		len = sizeof(ps->cmd) / 10;
   1899 	cmdnleft = len;
   1900 	(void)cmdtxt(n, 1);
   1901 	if (cmdnleft <= 0) {
   1902 		char *p = ps->cmd + len - 4;
   1903 		p[0] = '.';
   1904 		p[1] = '.';
   1905 		p[2] = '.';
   1906 		p[3] = 0;
   1907 	} else
   1908 		*cmdnextc = '\0';
   1909 
   1910 	VTRACE(DBG_JOBS,
   1911 	    ("commandtext: ps->cmd %p, end %p, left %d\n\t\"%s\"\n",
   1912 	    ps->cmd, cmdnextc, cmdnleft, ps->cmd));
   1913 }
   1914 
   1915 
   1916 /*
   1917  * Generate a string describing tree node n & its descendants (recursive calls)
   1918  *
   1919  * Return true (non-zero) if the output is complete (ends with an operator)
   1920  * so no ';' need be added before the following command.  Return false (zero)
   1921  * if a ';' is needed to terminate the output if it is followed by something
   1922  * which is not an operator.
   1923  */
   1924 STATIC int
   1925 cmdtxt(union node *n, int top)
   1926 {
   1927 	union node *np;
   1928 	struct nodelist *lp;
   1929 	const char *p;
   1930 	int i;
   1931 
   1932 	if (n == NULL || cmdnleft <= 0)
   1933 		return 1;
   1934 	switch (n->type) {
   1935 	case NSEMI:
   1936 		if (!cmdtxt(n->nbinary.ch1, 0))
   1937 			cmdputs(";");
   1938 		cmdputs(" ");
   1939 		return cmdtxt(n->nbinary.ch2, 0);
   1940 	case NAND:
   1941 		(void)cmdtxt(n->nbinary.ch1, 0);
   1942 		cmdputs(" && ");
   1943 		return cmdtxt(n->nbinary.ch2, 0);
   1944 	case NOR:
   1945 		(void) cmdtxt(n->nbinary.ch1, 0);
   1946 		cmdputs(" || ");
   1947 		return cmdtxt(n->nbinary.ch2, 0);
   1948 	case NDNOT:
   1949 		cmdputs("! ");
   1950 		/* FALLTHROUGH */
   1951 	case NNOT:
   1952 		cmdputs("! ");
   1953 		return cmdtxt(n->nnot.com, 0);
   1954 		break;
   1955 	case NPIPE:
   1956 		for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
   1957 			(void) cmdtxt(lp->n, 0);
   1958 			if (lp->next)
   1959 				cmdputs(" | ");
   1960 		}
   1961 		if (!top && n->npipe.backgnd) {
   1962 			cmdputs(" &");
   1963 			return 1;
   1964 		}
   1965 		return 0;
   1966 	case NSUBSHELL:
   1967 		cmdputs("(");
   1968 		(void) cmdtxt(n->nredir.n, 0);
   1969 		cmdputs(")");
   1970 		return 0;
   1971 	case NREDIR:
   1972 	case NBACKGND:
   1973 		return cmdtxt(n->nredir.n, top);
   1974 	case NIF:
   1975 		cmdputs("if ");
   1976 		if (!cmdtxt(n->nif.test, 0))
   1977 			cmdputs(";");
   1978 		cmdputs(" then ");
   1979 		i = cmdtxt(n->nif.ifpart, 0);
   1980 		if (n->nif.elsepart) {
   1981 			if (i == 0)
   1982 				cmdputs(";");
   1983 			cmdputs(" else ");
   1984 			i = cmdtxt(n->nif.elsepart, 0);
   1985 		}
   1986 		if (i == 0)
   1987 			cmdputs(";");
   1988 		cmdputs(" fi");
   1989 		return 0;
   1990 	case NWHILE:
   1991 		cmdputs("while ");
   1992 		goto until;
   1993 	case NUNTIL:
   1994 		cmdputs("until ");
   1995  until:
   1996 		if (!cmdtxt(n->nbinary.ch1, 0))
   1997 			cmdputs(";");
   1998 		cmdputs(" do ");
   1999 		if (!cmdtxt(n->nbinary.ch2, 0))
   2000 			cmdputs(";");
   2001 		cmdputs(" done");
   2002 		return 0;
   2003 	case NFOR:
   2004 		cmdputs("for ");
   2005 		cmdputs(n->nfor.var);
   2006 		cmdputs(" in ");
   2007 		cmdlist(n->nfor.args, 1);
   2008 		cmdputs("; do ");
   2009 		if (!cmdtxt(n->nfor.body, 0))
   2010 			cmdputs(";");
   2011 		cmdputs(" done");
   2012 		return 0;
   2013 	case NCASE:
   2014 		cmdputs("case ");
   2015 		cmdputs(n->ncase.expr->narg.text);
   2016 		cmdputs(" in ");
   2017 		for (np = n->ncase.cases; np; np = np->nclist.next) {
   2018 			(void) cmdtxt(np->nclist.pattern, 0);
   2019 			cmdputs(") ");
   2020 			(void) cmdtxt(np->nclist.body, 0);
   2021 			switch (n->type) {	/* switch (not if) for later */
   2022 			case NCLISTCONT:
   2023 				cmdputs(" ;& ");
   2024 				break;
   2025 			default:
   2026 				cmdputs(" ;; ");
   2027 				break;
   2028 			}
   2029 		}
   2030 		cmdputs("esac");
   2031 		return 0;
   2032 	case NDEFUN:
   2033 		cmdputs(n->narg.text);
   2034 		cmdputs("() { ... }");
   2035 		return 0;
   2036 	case NCMD:
   2037 		cmdlist(n->ncmd.args, 1);
   2038 		cmdlist(n->ncmd.redirect, 0);
   2039 		if (!top && n->ncmd.backgnd) {
   2040 			cmdputs(" &");
   2041 			return 1;
   2042 		}
   2043 		return 0;
   2044 	case NARG:
   2045 		cmdputs(n->narg.text);
   2046 		return 0;
   2047 	case NTO:
   2048 		p = ">";  i = 1;  goto redir;
   2049 	case NCLOBBER:
   2050 		p = ">|";  i = 1;  goto redir;
   2051 	case NAPPEND:
   2052 		p = ">>";  i = 1;  goto redir;
   2053 	case NTOFD:
   2054 		p = ">&";  i = 1;  goto redir;
   2055 	case NFROM:
   2056 		p = "<";  i = 0;  goto redir;
   2057 	case NFROMFD:
   2058 		p = "<&";  i = 0;  goto redir;
   2059 	case NFROMTO:
   2060 		p = "<>";  i = 0;  goto redir;
   2061  redir:
   2062 		if (n->nfile.fd != i)
   2063 			cmdputi(n->nfile.fd);
   2064 		cmdputs(p);
   2065 		if (n->type == NTOFD || n->type == NFROMFD) {
   2066 			if (n->ndup.dupfd < 0)
   2067 				cmdputs("-");
   2068 			else
   2069 				cmdputi(n->ndup.dupfd);
   2070 		} else {
   2071 			(void) cmdtxt(n->nfile.fname, 0);
   2072 		}
   2073 		return 0;
   2074 	case NHERE:
   2075 	case NXHERE:
   2076 		cmdputs("<<...");
   2077 		return 0;
   2078 	default:
   2079 		cmdputs("???");
   2080 		return 0;
   2081 	}
   2082 	return 0;
   2083 }
   2084 
   2085 STATIC void
   2086 cmdlist(union node *np, int sep)
   2087 {
   2088 	for (; np; np = np->narg.next) {
   2089 		if (!sep)
   2090 			cmdputs(" ");
   2091 		(void) cmdtxt(np, 0);
   2092 		if (sep && np->narg.next)
   2093 			cmdputs(" ");
   2094 	}
   2095 }
   2096 
   2097 
   2098 STATIC void
   2099 cmdputs(const char *s)
   2100 {
   2101 	const char *p, *str = 0;
   2102 	char c, cc[2] = " ";
   2103 	char *nextc;
   2104 	int nleft;
   2105 	int subtype = 0;
   2106 	int quoted = 0;
   2107 	static char vstype[16][4] = { "", "}", "-", "+", "?", "=",
   2108 					"#", "##", "%", "%%", "}" };
   2109 
   2110 	p = s;
   2111 	nextc = cmdnextc;
   2112 	nleft = cmdnleft;
   2113 	while (nleft > 0 && (c = *p++) != 0) {
   2114 		switch (c) {
   2115 		case CTLNONL:
   2116 			c = '\0';
   2117 			break;
   2118 		case CTLESC:
   2119 			c = *p++;
   2120 			break;
   2121 		case CTLVAR:
   2122 			subtype = *p++;
   2123 			if ((subtype & VSTYPE) == VSLENGTH)
   2124 				str = "${#"; /*}*/
   2125 			else
   2126 				str = "${"; /*}*/
   2127 			if (!(subtype & VSQUOTE) != !(quoted & 1)) {
   2128 				quoted ^= 1;
   2129 				c = '"';
   2130 			} else {
   2131 				c = *str++;
   2132 			}
   2133 			break;
   2134 		case CTLENDVAR:		/*{*/
   2135 			c = '}';
   2136 			if (quoted & 1)
   2137 				str = "\"";
   2138 			quoted >>= 1;
   2139 			subtype = 0;
   2140 			break;
   2141 		case CTLBACKQ:
   2142 			c = '$';
   2143 			str = "(...)";
   2144 			break;
   2145 		case CTLBACKQ+CTLQUOTE:
   2146 			c = '"';
   2147 			str = "$(...)\"";
   2148 			break;
   2149 		case CTLARI:
   2150 			c = '$';
   2151 			if (*p == ' ')
   2152 				p++;
   2153 			str = "((";	/*))*/
   2154 			break;
   2155 		case CTLENDARI:		/*((*/
   2156 			c = ')';
   2157 			str = ")";
   2158 			break;
   2159 		case CTLQUOTEMARK:
   2160 			quoted ^= 1;
   2161 			c = '"';
   2162 			break;
   2163 		case CTLQUOTEEND:
   2164 			quoted >>= 1;
   2165 			c = '"';
   2166 			break;
   2167 		case '=':
   2168 			if (subtype == 0)
   2169 				break;
   2170 			str = vstype[subtype & VSTYPE];
   2171 			if (subtype & VSNUL)
   2172 				c = ':';
   2173 			else
   2174 				c = *str++;		/*{*/
   2175 			if (c != '}')
   2176 				quoted <<= 1;
   2177 			else if (*p == CTLENDVAR)
   2178 				c = *str++;
   2179 			subtype = 0;
   2180 			break;
   2181 		case '\'':
   2182 		case '\\':
   2183 		case '"':
   2184 		case '$':
   2185 			/* These can only happen inside quotes */
   2186 			cc[0] = c;
   2187 			str = cc;
   2188 			c = '\\';
   2189 			break;
   2190 		default:
   2191 			break;
   2192 		}
   2193 		if (c != '\0') do {	/* c == 0 implies nothing in str */
   2194 			*nextc++ = c;
   2195 		} while (--nleft > 0 && str && (c = *str++));
   2196 		str = 0;
   2197 	}
   2198 	if ((quoted & 1) && nleft) {
   2199 		*nextc++ = '"';
   2200 		nleft--;
   2201 	}
   2202 	cmdnleft = nleft;
   2203 	cmdnextc = nextc;
   2204 }
   2205