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