xref: /netbsd-src/bin/sh/jobs.c (revision 7c7c171d130af9949261bc7dce2150a03c3d239c)
1 /*	$NetBSD: jobs.c,v 1.26 1998/04/07 10:16:04 fair 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. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38 
39 #include <sys/cdefs.h>
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)jobs.c	8.5 (Berkeley) 5/4/95";
43 #else
44 __RCSID("$NetBSD: jobs.c,v 1.26 1998/04/07 10:16:04 fair Exp $");
45 #endif
46 #endif /* not lint */
47 
48 #include <fcntl.h>
49 #include <signal.h>
50 #include <errno.h>
51 #include <unistd.h>
52 #include <stdlib.h>
53 #include <paths.h>
54 #include <sys/types.h>
55 #include <sys/param.h>
56 #ifdef BSD
57 #include <sys/wait.h>
58 #include <sys/time.h>
59 #include <sys/resource.h>
60 #endif
61 #include <sys/ioctl.h>
62 
63 #include "shell.h"
64 #if JOBS
65 #if OLD_TTY_DRIVER
66 #include "sgtty.h"
67 #else
68 #include <termios.h>
69 #endif
70 #undef CEOF			/* syntax.h redefines this */
71 #endif
72 #include "redir.h"
73 #include "show.h"
74 #include "main.h"
75 #include "parser.h"
76 #include "nodes.h"
77 #include "jobs.h"
78 #include "options.h"
79 #include "trap.h"
80 #include "syntax.h"
81 #include "input.h"
82 #include "output.h"
83 #include "memalloc.h"
84 #include "error.h"
85 #include "mystring.h"
86 
87 
88 struct job *jobtab;		/* array of jobs */
89 int njobs;			/* size of array */
90 MKINIT short backgndpid = -1;	/* pid of last background process */
91 #if JOBS
92 int initialpgrp;		/* pgrp of shell on invocation */
93 short curjob;			/* current job */
94 #endif
95 
96 STATIC void restartjob __P((struct job *));
97 STATIC void freejob __P((struct job *));
98 STATIC struct job *getjob __P((char *));
99 STATIC int dowait __P((int, struct job *));
100 STATIC int onsigchild __P((void));
101 STATIC int waitproc __P((int, int *));
102 STATIC void cmdtxt __P((union node *));
103 STATIC void cmdputs __P((char *));
104 
105 
106 /*
107  * Turn job control on and off.
108  *
109  * Note:  This code assumes that the third arg to ioctl is a character
110  * pointer, which is true on Berkeley systems but not System V.  Since
111  * System V doesn't have job control yet, this isn't a problem now.
112  */
113 
114 MKINIT int jobctl;
115 
116 void
117 setjobctl(on)
118 	int on;
119 {
120 #ifdef OLD_TTY_DRIVER
121 	int ldisc;
122 #endif
123 
124 	if (on == jobctl || rootshell == 0)
125 		return;
126 	if (on) {
127 		do { /* while we are in the background */
128 #ifdef OLD_TTY_DRIVER
129 			if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
130 #else
131 			initialpgrp = tcgetpgrp(2);
132 			if (initialpgrp < 0) {
133 #endif
134 				out2str("sh: can't access tty; job control turned off\n");
135 				mflag = 0;
136 				return;
137 			}
138 			if (initialpgrp == -1)
139 				initialpgrp = getpgrp();
140 			else if (initialpgrp != getpgrp()) {
141 				killpg(initialpgrp, SIGTTIN);
142 				continue;
143 			}
144 		} while (0);
145 #ifdef OLD_TTY_DRIVER
146 		if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
147 			out2str("sh: need new tty driver to run job control; job control turned off\n");
148 			mflag = 0;
149 			return;
150 		}
151 #endif
152 		setsignal(SIGTSTP);
153 		setsignal(SIGTTOU);
154 		setsignal(SIGTTIN);
155 		setpgid(0, rootpid);
156 #ifdef OLD_TTY_DRIVER
157 		ioctl(2, TIOCSPGRP, (char *)&rootpid);
158 #else
159 		tcsetpgrp(2, rootpid);
160 #endif
161 	} else { /* turning job control off */
162 		setpgid(0, initialpgrp);
163 #ifdef OLD_TTY_DRIVER
164 		ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
165 #else
166 		tcsetpgrp(2, initialpgrp);
167 #endif
168 		setsignal(SIGTSTP);
169 		setsignal(SIGTTOU);
170 		setsignal(SIGTTIN);
171 	}
172 	jobctl = on;
173 }
174 
175 
176 #ifdef mkinit
177 INCLUDE <stdlib.h>
178 
179 SHELLPROC {
180 	backgndpid = -1;
181 #if JOBS
182 	jobctl = 0;
183 #endif
184 }
185 
186 #endif
187 
188 
189 
190 #if JOBS
191 int
192 fgcmd(argc, argv)
193 	int argc;
194 	char **argv;
195 {
196 	struct job *jp;
197 	int pgrp;
198 	int status;
199 
200 	jp = getjob(argv[1]);
201 	if (jp->jobctl == 0)
202 		error("job not created under job control");
203 	pgrp = jp->ps[0].pid;
204 #ifdef OLD_TTY_DRIVER
205 	ioctl(2, TIOCSPGRP, (char *)&pgrp);
206 #else
207 	tcsetpgrp(2, pgrp);
208 #endif
209 	restartjob(jp);
210 	INTOFF;
211 	status = waitforjob(jp);
212 	INTON;
213 	return status;
214 }
215 
216 
217 int
218 bgcmd(argc, argv)
219 	int argc;
220 	char **argv;
221 {
222 	struct job *jp;
223 
224 	do {
225 		jp = getjob(*++argv);
226 		if (jp->jobctl == 0)
227 			error("job not created under job control");
228 		restartjob(jp);
229 	} while (--argc > 1);
230 	return 0;
231 }
232 
233 
234 STATIC void
235 restartjob(jp)
236 	struct job *jp;
237 {
238 	struct procstat *ps;
239 	int i;
240 
241 	if (jp->state == JOBDONE)
242 		return;
243 	INTOFF;
244 	killpg(jp->ps[0].pid, SIGCONT);
245 	for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
246 		if (WIFSTOPPED(ps->status)) {
247 			ps->status = -1;
248 			jp->state = 0;
249 		}
250 	}
251 	INTON;
252 }
253 #endif
254 
255 
256 int
257 jobscmd(argc, argv)
258 	int argc;
259 	char **argv;
260 {
261 	showjobs(0);
262 	return 0;
263 }
264 
265 
266 /*
267  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
268  * statuses have changed since the last call to showjobs.
269  *
270  * If the shell is interrupted in the process of creating a job, the
271  * result may be a job structure containing zero processes.  Such structures
272  * will be freed here.
273  */
274 
275 void
276 showjobs(change)
277 	int change;
278 {
279 	int jobno;
280 	int procno;
281 	int i;
282 	struct job *jp;
283 	struct procstat *ps;
284 	int col;
285 	char s[64];
286 
287 	TRACE(("showjobs(%d) called\n", change));
288 	while (dowait(0, (struct job *)NULL) > 0);
289 	for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
290 		if (! jp->used)
291 			continue;
292 		if (jp->nprocs == 0) {
293 			freejob(jp);
294 			continue;
295 		}
296 		if (change && ! jp->changed)
297 			continue;
298 		procno = jp->nprocs;
299 		for (ps = jp->ps ; ; ps++) {	/* for each process */
300 			if (ps == jp->ps)
301 				fmtstr(s, 64, "[%d] %d ", jobno, ps->pid);
302 			else
303 				fmtstr(s, 64, "    %d ", ps->pid);
304 			out1str(s);
305 			col = strlen(s);
306 			s[0] = '\0';
307 			if (ps->status == -1) {
308 				/* don't print anything */
309 			} else if (WIFEXITED(ps->status)) {
310 				fmtstr(s, 64, "Exit %d",
311 				       WEXITSTATUS(ps->status));
312 			} else {
313 #if JOBS
314 				if (WIFSTOPPED(ps->status))
315 					i = WSTOPSIG(ps->status);
316 				else /* WIFSIGNALED(ps->status) */
317 #endif
318 					i = WTERMSIG(ps->status);
319 				if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
320 					scopy(sys_siglist[i & 0x7F], s);
321 				else
322 					fmtstr(s, 64, "Signal %d", i & 0x7F);
323 				if (WCOREDUMP(ps->status))
324 					strcat(s, " (core dumped)");
325 			}
326 			out1str(s);
327 			col += strlen(s);
328 			do {
329 				out1c(' ');
330 				col++;
331 			} while (col < 30);
332 			out1str(ps->cmd);
333 			out1c('\n');
334 			if (--procno <= 0)
335 				break;
336 		}
337 		jp->changed = 0;
338 		if (jp->state == JOBDONE) {
339 			freejob(jp);
340 		}
341 	}
342 }
343 
344 
345 /*
346  * Mark a job structure as unused.
347  */
348 
349 STATIC void
350 freejob(jp)
351 	struct job *jp;
352 	{
353 	struct procstat *ps;
354 	int i;
355 
356 	INTOFF;
357 	for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
358 		if (ps->cmd != nullstr)
359 			ckfree(ps->cmd);
360 	}
361 	if (jp->ps != &jp->ps0)
362 		ckfree(jp->ps);
363 	jp->used = 0;
364 #if JOBS
365 	if (curjob == jp - jobtab + 1)
366 		curjob = 0;
367 #endif
368 	INTON;
369 }
370 
371 
372 
373 int
374 waitcmd(argc, argv)
375 	int argc;
376 	char **argv;
377 {
378 	struct job *job;
379 	int status, retval;
380 	struct job *jp;
381 
382 	if (argc > 1) {
383 		job = getjob(argv[1]);
384 	} else {
385 		job = NULL;
386 	}
387 	for (;;) {	/* loop until process terminated or stopped */
388 		if (job != NULL) {
389 			if (job->state) {
390 				status = job->ps[job->nprocs - 1].status;
391 				if (WIFEXITED(status))
392 					retval = WEXITSTATUS(status);
393 #if JOBS
394 				else if (WIFSTOPPED(status))
395 					retval = WSTOPSIG(status) + 128;
396 #endif
397 				else {
398 					/* XXX: limits number of signals */
399 					retval = WTERMSIG(status) + 128;
400 				}
401 				if (! iflag)
402 					freejob(job);
403 				return retval;
404 			}
405 		} else {
406 			for (jp = jobtab ; ; jp++) {
407 				if (jp >= jobtab + njobs) {	/* no running procs */
408 					return 0;
409 				}
410 				if (jp->used && jp->state == 0)
411 					break;
412 			}
413 		}
414 		dowait(1, (struct job *)NULL);
415 	}
416 }
417 
418 
419 
420 int
421 jobidcmd(argc, argv)
422 	int argc;
423 	char **argv;
424 {
425 	struct job *jp;
426 	int i;
427 
428 	jp = getjob(argv[1]);
429 	for (i = 0 ; i < jp->nprocs ; ) {
430 		out1fmt("%d", jp->ps[i].pid);
431 		out1c(++i < jp->nprocs? ' ' : '\n');
432 	}
433 	return 0;
434 }
435 
436 
437 
438 /*
439  * Convert a job name to a job structure.
440  */
441 
442 STATIC struct job *
443 getjob(name)
444 	char *name;
445 	{
446 	int jobno;
447 	struct job *jp;
448 	int pid;
449 	int i;
450 
451 	if (name == NULL) {
452 #if JOBS
453 currentjob:
454 		if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
455 			error("No current job");
456 		return &jobtab[jobno - 1];
457 #else
458 		error("No current job");
459 #endif
460 	} else if (name[0] == '%') {
461 		if (is_digit(name[1])) {
462 			jobno = number(name + 1);
463 			if (jobno > 0 && jobno <= njobs
464 			 && jobtab[jobno - 1].used != 0)
465 				return &jobtab[jobno - 1];
466 #if JOBS
467 		} else if (name[1] == '%' && name[2] == '\0') {
468 			goto currentjob;
469 #endif
470 		} else {
471 			struct job *found = NULL;
472 			for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
473 				if (jp->used && jp->nprocs > 0
474 				 && prefix(name + 1, jp->ps[0].cmd)) {
475 					if (found)
476 						error("%s: ambiguous", name);
477 					found = jp;
478 				}
479 			}
480 			if (found)
481 				return found;
482 		}
483 	} else if (is_number(name)) {
484 		pid = number(name);
485 		for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
486 			if (jp->used && jp->nprocs > 0
487 			 && jp->ps[jp->nprocs - 1].pid == pid)
488 				return jp;
489 		}
490 	}
491 	error("No such job: %s", name);
492 	/*NOTREACHED*/
493 	return NULL;
494 }
495 
496 
497 
498 /*
499  * Return a new job structure,
500  */
501 
502 struct job *
503 makejob(node, nprocs)
504 	union node *node;
505 	int nprocs;
506 {
507 	int i;
508 	struct job *jp;
509 
510 	for (i = njobs, jp = jobtab ; ; jp++) {
511 		if (--i < 0) {
512 			INTOFF;
513 			if (njobs == 0) {
514 				jobtab = ckmalloc(4 * sizeof jobtab[0]);
515 			} else {
516 				jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
517 				memcpy(jp, jobtab, njobs * sizeof jp[0]);
518 				/* Relocate `ps' pointers */
519 				for (i = 0; i < njobs; i++)
520 					if (jp[i].ps == &jobtab[i].ps0)
521 						jp[i].ps = &jp[i].ps0;
522 				ckfree(jobtab);
523 				jobtab = jp;
524 			}
525 			jp = jobtab + njobs;
526 			for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
527 			INTON;
528 			break;
529 		}
530 		if (jp->used == 0)
531 			break;
532 	}
533 	INTOFF;
534 	jp->state = 0;
535 	jp->used = 1;
536 	jp->changed = 0;
537 	jp->nprocs = 0;
538 #if JOBS
539 	jp->jobctl = jobctl;
540 #endif
541 	if (nprocs > 1) {
542 		jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
543 	} else {
544 		jp->ps = &jp->ps0;
545 	}
546 	INTON;
547 	TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
548 	    jp - jobtab + 1));
549 	return jp;
550 }
551 
552 
553 /*
554  * Fork of a subshell.  If we are doing job control, give the subshell its
555  * own process group.  Jp is a job structure that the job is to be added to.
556  * N is the command that will be evaluated by the child.  Both jp and n may
557  * be NULL.  The mode parameter can be one of the following:
558  *	FORK_FG - Fork off a foreground process.
559  *	FORK_BG - Fork off a background process.
560  *	FORK_NOJOB - Like FORK_FG, but don't give the process its own
561  *		     process group even if job control is on.
562  *
563  * When job control is turned off, background processes have their standard
564  * input redirected to /dev/null (except for the second and later processes
565  * in a pipeline).
566  */
567 
568 int
569 forkshell(jp, n, mode)
570 	union node *n;
571 	struct job *jp;
572 	int mode;
573 {
574 	int pid;
575 	int pgrp;
576 	const char *devnull = _PATH_DEVNULL;
577 	/* const */ char *nullerr = "Can't open %s";
578 
579 	TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
580 	    mode));
581 	INTOFF;
582 	pid = fork();
583 	if (pid == -1) {
584 		TRACE(("Fork failed, errno=%d\n", errno));
585 		INTON;
586 		error("Cannot fork");
587 	}
588 	if (pid == 0) {
589 		struct job *p;
590 		int wasroot;
591 		int i;
592 
593 		TRACE(("Child shell %d\n", getpid()));
594 		wasroot = rootshell;
595 		rootshell = 0;
596 		for (i = njobs, p = jobtab ; --i >= 0 ; p++)
597 			if (p->used)
598 				freejob(p);
599 		closescript();
600 		INTON;
601 		clear_traps();
602 #if JOBS
603 		jobctl = 0;		/* do job control only in root shell */
604 		if (wasroot && mode != FORK_NOJOB && mflag) {
605 			if (jp == NULL || jp->nprocs == 0)
606 				pgrp = getpid();
607 			else
608 				pgrp = jp->ps[0].pid;
609 			setpgid(0, pgrp);
610 			if (mode == FORK_FG) {
611 				/*** this causes superfluous TIOCSPGRPS ***/
612 #ifdef OLD_TTY_DRIVER
613 				if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
614 					error("TIOCSPGRP failed, errno=%d", errno);
615 #else
616 				if (tcsetpgrp(2, pgrp) < 0)
617 					error("tcsetpgrp failed, errno=%d", errno);
618 #endif
619 			}
620 			setsignal(SIGTSTP);
621 			setsignal(SIGTTOU);
622 		} else if (mode == FORK_BG) {
623 			ignoresig(SIGINT);
624 			ignoresig(SIGQUIT);
625 			if ((jp == NULL || jp->nprocs == 0) &&
626 			    ! fd0_redirected_p ()) {
627 				close(0);
628 				if (open(devnull, O_RDONLY) != 0)
629 					error(nullerr, devnull);
630 			}
631 		}
632 #else
633 		if (mode == FORK_BG) {
634 			ignoresig(SIGINT);
635 			ignoresig(SIGQUIT);
636 			if ((jp == NULL || jp->nprocs == 0) &&
637 			    ! fd0_redirected_p ()) {
638 				close(0);
639 				if (open(devnull, O_RDONLY) != 0)
640 					error(nullerr, devnull);
641 			}
642 		}
643 #endif
644 		if (wasroot && iflag) {
645 			setsignal(SIGINT);
646 			setsignal(SIGQUIT);
647 			setsignal(SIGTERM);
648 		}
649 		return pid;
650 	}
651 	if (rootshell && mode != FORK_NOJOB && mflag) {
652 		if (jp == NULL || jp->nprocs == 0)
653 			pgrp = pid;
654 		else
655 			pgrp = jp->ps[0].pid;
656 		setpgid(pid, pgrp);
657 	}
658 	if (mode == FORK_BG)
659 		backgndpid = pid;		/* set $! */
660 	if (jp) {
661 		struct procstat *ps = &jp->ps[jp->nprocs++];
662 		ps->pid = pid;
663 		ps->status = -1;
664 		ps->cmd = nullstr;
665 		if (iflag && rootshell && n)
666 			ps->cmd = commandtext(n);
667 	}
668 	INTON;
669 	TRACE(("In parent shell:  child = %d\n", pid));
670 	return pid;
671 }
672 
673 
674 
675 /*
676  * Wait for job to finish.
677  *
678  * Under job control we have the problem that while a child process is
679  * running interrupts generated by the user are sent to the child but not
680  * to the shell.  This means that an infinite loop started by an inter-
681  * active user may be hard to kill.  With job control turned off, an
682  * interactive user may place an interactive program inside a loop.  If
683  * the interactive program catches interrupts, the user doesn't want
684  * these interrupts to also abort the loop.  The approach we take here
685  * is to have the shell ignore interrupt signals while waiting for a
686  * forground process to terminate, and then send itself an interrupt
687  * signal if the child process was terminated by an interrupt signal.
688  * Unfortunately, some programs want to do a bit of cleanup and then
689  * exit on interrupt; unless these processes terminate themselves by
690  * sending a signal to themselves (instead of calling exit) they will
691  * confuse this approach.
692  */
693 
694 int
695 waitforjob(jp)
696 	struct job *jp;
697 	{
698 #if JOBS
699 	int mypgrp = getpgrp();
700 #endif
701 	int status;
702 	int st;
703 
704 	INTOFF;
705 	TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
706 	while (jp->state == 0) {
707 		dowait(1, jp);
708 	}
709 #if JOBS
710 	if (jp->jobctl) {
711 #ifdef OLD_TTY_DRIVER
712 		if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
713 			error("TIOCSPGRP failed, errno=%d\n", errno);
714 #else
715 		if (tcsetpgrp(2, mypgrp) < 0)
716 			error("tcsetpgrp failed, errno=%d\n", errno);
717 #endif
718 	}
719 	if (jp->state == JOBSTOPPED)
720 		curjob = jp - jobtab + 1;
721 #endif
722 	status = jp->ps[jp->nprocs - 1].status;
723 	/* convert to 8 bits */
724 	if (WIFEXITED(status))
725 		st = WEXITSTATUS(status);
726 #if JOBS
727 	else if (WIFSTOPPED(status))
728 		st = WSTOPSIG(status) + 128;
729 #endif
730 	else
731 		st = WTERMSIG(status) + 128;
732 	if (! JOBS || jp->state == JOBDONE)
733 		freejob(jp);
734 	CLEAR_PENDING_INT;
735 	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
736 		kill(getpid(), SIGINT);
737 	INTON;
738 	return st;
739 }
740 
741 
742 
743 /*
744  * Wait for a process to terminate.
745  */
746 
747 STATIC int
748 dowait(block, job)
749 	int block;
750 	struct job *job;
751 {
752 	int pid;
753 	int status;
754 	struct procstat *sp;
755 	struct job *jp;
756 	struct job *thisjob;
757 	int done;
758 	int stopped;
759 	int core;
760 	int sig;
761 
762 	TRACE(("dowait(%d) called\n", block));
763 	do {
764 		pid = waitproc(block, &status);
765 		TRACE(("wait returns %d, status=%d\n", pid, status));
766 	} while (pid == -1 && errno == EINTR);
767 	if (pid <= 0)
768 		return pid;
769 	INTOFF;
770 	thisjob = NULL;
771 	for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
772 		if (jp->used) {
773 			done = 1;
774 			stopped = 1;
775 			for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
776 				if (sp->pid == -1)
777 					continue;
778 				if (sp->pid == pid) {
779 					TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
780 					sp->status = status;
781 					thisjob = jp;
782 				}
783 				if (sp->status == -1)
784 					stopped = 0;
785 				else if (WIFSTOPPED(sp->status))
786 					done = 0;
787 			}
788 			if (stopped) {		/* stopped or done */
789 				int state = done? JOBDONE : JOBSTOPPED;
790 				if (jp->state != state) {
791 					TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
792 					jp->state = state;
793 #if JOBS
794 					if (done && curjob == jp - jobtab + 1)
795 						curjob = 0;		/* no current job */
796 #endif
797 				}
798 			}
799 		}
800 	}
801 	INTON;
802 	if (! rootshell || ! iflag || (job && thisjob == job)) {
803 		core = WCOREDUMP(status);
804 #if JOBS
805 		if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
806 		else
807 #endif
808 		if (WIFEXITED(status)) sig = 0;
809 		else sig = WTERMSIG(status);
810 
811 		if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
812 			if (thisjob != job)
813 				outfmt(out2, "%d: ", pid);
814 #if JOBS
815 			if (sig == SIGTSTP && rootshell && iflag)
816 				outfmt(out2, "%%%ld ",
817 				    (long)(job - jobtab + 1));
818 #endif
819 			if (sig < NSIG && sys_siglist[sig])
820 				out2str(sys_siglist[sig]);
821 			else
822 				outfmt(out2, "Signal %d", sig);
823 			if (core)
824 				out2str(" - core dumped");
825 			out2c('\n');
826 			flushout(&errout);
827 		} else {
828 			TRACE(("Not printing status: status=%d, sig=%d\n",
829 			       status, sig));
830 		}
831 	} else {
832 		TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
833 		if (thisjob)
834 			thisjob->changed = 1;
835 	}
836 	return pid;
837 }
838 
839 
840 
841 /*
842  * Do a wait system call.  If job control is compiled in, we accept
843  * stopped processes.  If block is zero, we return a value of zero
844  * rather than blocking.
845  *
846  * System V doesn't have a non-blocking wait system call.  It does
847  * have a SIGCLD signal that is sent to a process when one of it's
848  * children dies.  The obvious way to use SIGCLD would be to install
849  * a handler for SIGCLD which simply bumped a counter when a SIGCLD
850  * was received, and have waitproc bump another counter when it got
851  * the status of a process.  Waitproc would then know that a wait
852  * system call would not block if the two counters were different.
853  * This approach doesn't work because if a process has children that
854  * have not been waited for, System V will send it a SIGCLD when it
855  * installs a signal handler for SIGCLD.  What this means is that when
856  * a child exits, the shell will be sent SIGCLD signals continuously
857  * until is runs out of stack space, unless it does a wait call before
858  * restoring the signal handler.  The code below takes advantage of
859  * this (mis)feature by installing a signal handler for SIGCLD and
860  * then checking to see whether it was called.  If there are any
861  * children to be waited for, it will be.
862  *
863  * If neither SYSV nor BSD is defined, we don't implement nonblocking
864  * waits at all.  In this case, the user will not be informed when
865  * a background process until the next time she runs a real program
866  * (as opposed to running a builtin command or just typing return),
867  * and the jobs command may give out of date information.
868  */
869 
870 #ifdef SYSV
871 STATIC int gotsigchild;
872 
873 STATIC int onsigchild() {
874 	gotsigchild = 1;
875 }
876 #endif
877 
878 
879 STATIC int
880 waitproc(block, status)
881 	int block;
882 	int *status;
883 {
884 #ifdef BSD
885 	int flags;
886 
887 #if JOBS
888 	flags = WUNTRACED;
889 #else
890 	flags = 0;
891 #endif
892 	if (block == 0)
893 		flags |= WNOHANG;
894 	return wait3(status, flags, (struct rusage *)NULL);
895 #else
896 #ifdef SYSV
897 	int (*save)();
898 
899 	if (block == 0) {
900 		gotsigchild = 0;
901 		save = signal(SIGCLD, onsigchild);
902 		signal(SIGCLD, save);
903 		if (gotsigchild == 0)
904 			return 0;
905 	}
906 	return wait(status);
907 #else
908 	if (block == 0)
909 		return 0;
910 	return wait(status);
911 #endif
912 #endif
913 }
914 
915 /*
916  * return 1 if there are stopped jobs, otherwise 0
917  */
918 int job_warning = 0;
919 int
920 stoppedjobs()
921 {
922 	int jobno;
923 	struct job *jp;
924 
925 	if (job_warning)
926 		return (0);
927 	for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
928 		if (jp->used == 0)
929 			continue;
930 		if (jp->state == JOBSTOPPED) {
931 			out2str("You have stopped jobs.\n");
932 			job_warning = 2;
933 			return (1);
934 		}
935 	}
936 
937 	return (0);
938 }
939 
940 /*
941  * Return a string identifying a command (to be printed by the
942  * jobs command.
943  */
944 
945 STATIC char *cmdnextc;
946 STATIC int cmdnleft;
947 #define MAXCMDTEXT	200
948 
949 char *
950 commandtext(n)
951 	union node *n;
952 	{
953 	char *name;
954 
955 	cmdnextc = name = ckmalloc(MAXCMDTEXT);
956 	cmdnleft = MAXCMDTEXT - 4;
957 	cmdtxt(n);
958 	*cmdnextc = '\0';
959 	return name;
960 }
961 
962 
963 STATIC void
964 cmdtxt(n)
965 	union node *n;
966 	{
967 	union node *np;
968 	struct nodelist *lp;
969 	char *p;
970 	int i;
971 	char s[2];
972 
973 	if (n == NULL)
974 		return;
975 	switch (n->type) {
976 	case NSEMI:
977 		cmdtxt(n->nbinary.ch1);
978 		cmdputs("; ");
979 		cmdtxt(n->nbinary.ch2);
980 		break;
981 	case NAND:
982 		cmdtxt(n->nbinary.ch1);
983 		cmdputs(" && ");
984 		cmdtxt(n->nbinary.ch2);
985 		break;
986 	case NOR:
987 		cmdtxt(n->nbinary.ch1);
988 		cmdputs(" || ");
989 		cmdtxt(n->nbinary.ch2);
990 		break;
991 	case NPIPE:
992 		for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
993 			cmdtxt(lp->n);
994 			if (lp->next)
995 				cmdputs(" | ");
996 		}
997 		break;
998 	case NSUBSHELL:
999 		cmdputs("(");
1000 		cmdtxt(n->nredir.n);
1001 		cmdputs(")");
1002 		break;
1003 	case NREDIR:
1004 	case NBACKGND:
1005 		cmdtxt(n->nredir.n);
1006 		break;
1007 	case NIF:
1008 		cmdputs("if ");
1009 		cmdtxt(n->nif.test);
1010 		cmdputs("; then ");
1011 		cmdtxt(n->nif.ifpart);
1012 		cmdputs("...");
1013 		break;
1014 	case NWHILE:
1015 		cmdputs("while ");
1016 		goto until;
1017 	case NUNTIL:
1018 		cmdputs("until ");
1019 until:
1020 		cmdtxt(n->nbinary.ch1);
1021 		cmdputs("; do ");
1022 		cmdtxt(n->nbinary.ch2);
1023 		cmdputs("; done");
1024 		break;
1025 	case NFOR:
1026 		cmdputs("for ");
1027 		cmdputs(n->nfor.var);
1028 		cmdputs(" in ...");
1029 		break;
1030 	case NCASE:
1031 		cmdputs("case ");
1032 		cmdputs(n->ncase.expr->narg.text);
1033 		cmdputs(" in ...");
1034 		break;
1035 	case NDEFUN:
1036 		cmdputs(n->narg.text);
1037 		cmdputs("() ...");
1038 		break;
1039 	case NCMD:
1040 		for (np = n->ncmd.args ; np ; np = np->narg.next) {
1041 			cmdtxt(np);
1042 			if (np->narg.next)
1043 				cmdputs(" ");
1044 		}
1045 		for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
1046 			cmdputs(" ");
1047 			cmdtxt(np);
1048 		}
1049 		break;
1050 	case NARG:
1051 		cmdputs(n->narg.text);
1052 		break;
1053 	case NTO:
1054 		p = ">";  i = 1;  goto redir;
1055 	case NAPPEND:
1056 		p = ">>";  i = 1;  goto redir;
1057 	case NTOFD:
1058 		p = ">&";  i = 1;  goto redir;
1059 	case NFROM:
1060 		p = "<";  i = 0;  goto redir;
1061 	case NFROMFD:
1062 		p = "<&";  i = 0;  goto redir;
1063 redir:
1064 		if (n->nfile.fd != i) {
1065 			s[0] = n->nfile.fd + '0';
1066 			s[1] = '\0';
1067 			cmdputs(s);
1068 		}
1069 		cmdputs(p);
1070 		if (n->type == NTOFD || n->type == NFROMFD) {
1071 			s[0] = n->ndup.dupfd + '0';
1072 			s[1] = '\0';
1073 			cmdputs(s);
1074 		} else {
1075 			cmdtxt(n->nfile.fname);
1076 		}
1077 		break;
1078 	case NHERE:
1079 	case NXHERE:
1080 		cmdputs("<<...");
1081 		break;
1082 	default:
1083 		cmdputs("???");
1084 		break;
1085 	}
1086 }
1087 
1088 
1089 
1090 STATIC void
1091 cmdputs(s)
1092 	char *s;
1093 	{
1094 	char *p, *q;
1095 	char c;
1096 	int subtype = 0;
1097 
1098 	if (cmdnleft <= 0)
1099 		return;
1100 	p = s;
1101 	q = cmdnextc;
1102 	while ((c = *p++) != '\0') {
1103 		if (c == CTLESC)
1104 			*q++ = *p++;
1105 		else if (c == CTLVAR) {
1106 			*q++ = '$';
1107 			if (--cmdnleft > 0)
1108 				*q++ = '{';
1109 			subtype = *p++;
1110 		} else if (c == '=' && subtype != 0) {
1111 			*q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
1112 			subtype = 0;
1113 		} else if (c == CTLENDVAR) {
1114 			*q++ = '}';
1115 		} else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
1116 			cmdnleft++;		/* ignore it */
1117 		else
1118 			*q++ = c;
1119 		if (--cmdnleft <= 0) {
1120 			*q++ = '.';
1121 			*q++ = '.';
1122 			*q++ = '.';
1123 			break;
1124 		}
1125 	}
1126 	cmdnextc = q;
1127 }
1128