jobs.c revision 33138
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 *	$Id: jobs.c,v 1.17 1997/12/10 22:18:53 eivind Exp $
37 */
38
39#ifndef lint
40static char const sccsid[] = "@(#)jobs.c	8.5 (Berkeley) 5/4/95";
41#endif /* not lint */
42
43#include <fcntl.h>
44#include <signal.h>
45#include <errno.h>
46#include <unistd.h>
47#include <stdlib.h>
48#include <sys/param.h>
49#ifdef BSD
50#include <sys/wait.h>
51#include <sys/time.h>
52#include <sys/resource.h>
53#endif
54#include <sys/ioctl.h>
55
56#include "shell.h"
57#if JOBS
58#if OLD_TTY_DRIVER
59#include "sgtty.h"
60#else
61#include <termios.h>
62#endif
63#undef CEOF			/* syntax.h redefines this */
64#endif
65#include "redir.h"
66#include "show.h"
67#include "main.h"
68#include "parser.h"
69#include "nodes.h"
70#include "jobs.h"
71#include "options.h"
72#include "trap.h"
73#include "syntax.h"
74#include "input.h"
75#include "output.h"
76#include "memalloc.h"
77#include "error.h"
78#include "mystring.h"
79
80
81struct job *jobtab;		/* array of jobs */
82int njobs;			/* size of array */
83MKINIT pid_t backgndpid = -1;	/* pid of last background process */
84#if JOBS
85int initialpgrp;		/* pgrp of shell on invocation */
86int curjob;			/* current job */
87#endif
88sig_t oldsigint;
89sig_t oldsigquit;
90int oldsigs_valid = 0;
91
92#if JOBS
93STATIC void restartjob __P((struct job *));
94#endif
95STATIC void freejob __P((struct job *));
96STATIC struct job *getjob __P((char *));
97STATIC int dowait __P((int, struct job *));
98#if SYSV
99STATIC int onsigchild __P((void));
100#endif
101STATIC int waitproc __P((int, int *));
102STATIC void cmdtxt __P((union node *));
103STATIC 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
114MKINIT int jobctl;
115
116#if JOBS
117void
118setjobctl(on)
119	int on;
120{
121#ifdef OLD_TTY_DRIVER
122	int ldisc;
123#endif
124
125	if (on == jobctl || rootshell == 0)
126		return;
127	if (on) {
128		do { /* while we are in the background */
129#ifdef OLD_TTY_DRIVER
130			if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
131#else
132			initialpgrp = tcgetpgrp(2);
133			if (initialpgrp < 0) {
134#endif
135				out2str("sh: can't access tty; job control turned off\n");
136				mflag = 0;
137				return;
138			}
139			if (initialpgrp == -1)
140				initialpgrp = getpgrp();
141			else if (initialpgrp != getpgrp()) {
142				killpg(initialpgrp, SIGTTIN);
143				continue;
144			}
145		} while (0);
146#ifdef OLD_TTY_DRIVER
147		if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
148			out2str("sh: need new tty driver to run job control; job control turned off\n");
149			mflag = 0;
150			return;
151		}
152#endif
153		setsignal(SIGTSTP);
154		setsignal(SIGTTOU);
155		setsignal(SIGTTIN);
156		setpgid(0, rootpid);
157#ifdef OLD_TTY_DRIVER
158		ioctl(2, TIOCSPGRP, (char *)&rootpid);
159#else
160		tcsetpgrp(2, rootpid);
161#endif
162	} else { /* turning job control off */
163		setpgid(0, initialpgrp);
164#ifdef OLD_TTY_DRIVER
165		ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
166#else
167		tcsetpgrp(2, initialpgrp);
168#endif
169		setsignal(SIGTSTP);
170		setsignal(SIGTTOU);
171		setsignal(SIGTTIN);
172	}
173	jobctl = on;
174}
175#endif
176
177
178#ifdef mkinit
179INCLUDE <sys/types.h>
180INCLUDE <stdlib.h>
181
182SHELLPROC {
183	backgndpid = -1;
184#if JOBS
185	jobctl = 0;
186#endif
187}
188
189#endif
190
191
192
193#if JOBS
194int
195fgcmd(argc, argv)
196	int argc __unused;
197	char **argv;
198{
199	struct job *jp;
200	int pgrp;
201	int status;
202
203	jp = getjob(argv[1]);
204	if (jp->jobctl == 0)
205		error("job not created under job control");
206	pgrp = jp->ps[0].pid;
207#ifdef OLD_TTY_DRIVER
208	ioctl(2, TIOCSPGRP, (char *)&pgrp);
209#else
210	tcsetpgrp(2, pgrp);
211#endif
212	restartjob(jp);
213	INTOFF;
214	status = waitforjob(jp);
215	INTON;
216	return status;
217}
218
219
220int
221bgcmd(argc, argv)
222	int argc;
223	char **argv;
224{
225	struct job *jp;
226
227	do {
228		jp = getjob(*++argv);
229		if (jp->jobctl == 0)
230			error("job not created under job control");
231		restartjob(jp);
232	} while (--argc > 1);
233	return 0;
234}
235
236
237STATIC void
238restartjob(jp)
239	struct job *jp;
240{
241	struct procstat *ps;
242	int i;
243
244	if (jp->state == JOBDONE)
245		return;
246	INTOFF;
247	killpg(jp->ps[0].pid, SIGCONT);
248	for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
249		if (WIFSTOPPED(ps->status)) {
250			ps->status = -1;
251			jp->state = 0;
252		}
253	}
254	INTON;
255}
256#endif
257
258
259int
260jobscmd(argc, argv)
261	int argc __unused;
262	char **argv __unused;
263{
264	showjobs(0);
265	return 0;
266}
267
268
269/*
270 * Print a list of jobs.  If "change" is nonzero, only print jobs whose
271 * statuses have changed since the last call to showjobs.
272 *
273 * If the shell is interrupted in the process of creating a job, the
274 * result may be a job structure containing zero processes.  Such structures
275 * will be freed here.
276 */
277
278void
279showjobs(change)
280	int change;
281{
282	int jobno;
283	int procno;
284	int i;
285	struct job *jp;
286	struct procstat *ps;
287	int col;
288	char s[64];
289
290	TRACE(("showjobs(%d) called\n", change));
291	while (dowait(0, (struct job *)NULL) > 0);
292	for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
293		if (! jp->used)
294			continue;
295		if (jp->nprocs == 0) {
296			freejob(jp);
297			continue;
298		}
299		if (change && ! jp->changed)
300			continue;
301		procno = jp->nprocs;
302		for (ps = jp->ps ; ; ps++) {	/* for each process */
303			if (ps == jp->ps)
304				fmtstr(s, 64, "[%d] %d ", jobno, ps->pid);
305			else
306				fmtstr(s, 64, "    %d ", ps->pid);
307			out1str(s);
308			col = strlen(s);
309			s[0] = '\0';
310			if (ps->status == -1) {
311				/* don't print anything */
312			} else if (WIFEXITED(ps->status)) {
313				fmtstr(s, 64, "Exit %d", WEXITSTATUS(ps->status));
314			} else {
315#if JOBS
316				if (WIFSTOPPED(ps->status))
317					i = WSTOPSIG(ps->status);
318				else
319#endif
320					i = WTERMSIG(ps->status);
321				if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
322					scopy(sys_siglist[i & 0x7F], s);
323				else
324					fmtstr(s, 64, "Signal %d", i & 0x7F);
325				if (WCOREDUMP(ps->status))
326					strcat(s, " (core dumped)");
327			}
328			out1str(s);
329			col += strlen(s);
330			do {
331				out1c(' ');
332				col++;
333			} while (col < 30);
334			out1str(ps->cmd);
335			out1c('\n');
336			if (--procno <= 0)
337				break;
338		}
339		jp->changed = 0;
340		if (jp->state == JOBDONE) {
341			freejob(jp);
342		}
343	}
344}
345
346
347/*
348 * Mark a job structure as unused.
349 */
350
351STATIC void
352freejob(jp)
353	struct job *jp;
354	{
355	struct procstat *ps;
356	int i;
357
358	INTOFF;
359	for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
360		if (ps->cmd != nullstr)
361			ckfree(ps->cmd);
362	}
363	if (jp->ps != &jp->ps0)
364		ckfree(jp->ps);
365	jp->used = 0;
366#if JOBS
367	if (curjob == jp - jobtab + 1)
368		curjob = 0;
369#endif
370	INTON;
371}
372
373
374
375int
376waitcmd(argc, argv)
377	int argc;
378	char **argv;
379{
380	struct job *job;
381	int status, retval;
382	struct job *jp;
383
384	if (argc > 1) {
385		job = getjob(argv[1]);
386	} else {
387		job = NULL;
388	}
389	for (;;) {	/* loop until process terminated or stopped */
390		if (job != NULL) {
391			if (job->state) {
392				status = job->ps[job->nprocs - 1].status;
393				if (WIFEXITED(status))
394					retval = WEXITSTATUS(status);
395#if JOBS
396				else if (WIFSTOPPED(status))
397					retval = WSTOPSIG(status) + 128;
398#endif
399				else
400					retval = WTERMSIG(status) + 128;
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
420int
421jobidcmd(argc, argv)
422	int argc __unused;
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
442STATIC struct job *
443getjob(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
453currentjob:
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
502struct job *
503makejob(node, nprocs)
504	union node *node __unused;
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
568int
569forkshell(jp, n, mode)
570	union node *n;
571	struct job *jp;
572	int mode;
573{
574	int pid;
575	int pgrp;
576
577	TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
578	    mode));
579	INTOFF;
580	if (mode == FORK_FG) {
581	        oldsigquit = signal(SIGQUIT,SIG_IGN);
582                oldsigint = signal(SIGINT,SIG_IGN);
583		oldsigs_valid = 1;
584	}
585	pid = fork();
586	if (pid == -1) {
587		TRACE(("Fork failed, errno=%d\n", errno));
588		INTON;
589		error("Cannot fork");
590	}
591	if (pid == 0) {
592		struct job *p;
593		int wasroot;
594		int i;
595
596		TRACE(("Child shell %d\n", getpid()));
597		signal(SIGQUIT,SIG_DFL);
598		signal(SIGINT,SIG_DFL);
599		wasroot = rootshell;
600		rootshell = 0;
601		for (i = njobs, p = jobtab ; --i >= 0 ; p++)
602			if (p->used)
603				freejob(p);
604		closescript();
605		INTON;
606		clear_traps();
607#if JOBS
608		jobctl = 0;		/* do job control only in root shell */
609		if (wasroot && mode != FORK_NOJOB && mflag) {
610			if (jp == NULL || jp->nprocs == 0)
611				pgrp = getpid();
612			else
613				pgrp = jp->ps[0].pid;
614			if (setpgid(0, pgrp) == 0 && mode == FORK_FG) {
615				/*** this causes superfluous TIOCSPGRPS ***/
616#ifdef OLD_TTY_DRIVER
617				if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
618					error("TIOCSPGRP failed, errno=%d", errno);
619#else
620				if (tcsetpgrp(2, pgrp) < 0)
621					error("tcsetpgrp failed, errno=%d", errno);
622#endif
623			}
624			setsignal(SIGTSTP);
625			setsignal(SIGTTOU);
626		} else if (mode == FORK_BG) {
627			ignoresig(SIGINT);
628			ignoresig(SIGQUIT);
629			if ((jp == NULL || jp->nprocs == 0) &&
630			    ! fd0_redirected_p ()) {
631				close(0);
632				if (open("/dev/null", O_RDONLY) != 0)
633					error("Can't open /dev/null");
634			}
635		}
636#else
637		if (mode == FORK_BG) {
638			ignoresig(SIGINT);
639			ignoresig(SIGQUIT);
640			if ((jp == NULL || jp->nprocs == 0) &&
641			    ! fd0_redirected_p ()) {
642				close(0);
643				if (open("/dev/null", O_RDONLY) != 0)
644					error("Can't open /dev/null");
645			}
646		}
647#endif
648		if (wasroot && iflag) {
649			setsignal(SIGINT);
650			setsignal(SIGQUIT);
651			setsignal(SIGTERM);
652		}
653		return pid;
654	}
655	if (rootshell && mode != FORK_NOJOB && mflag) {
656		if (jp == NULL || jp->nprocs == 0)
657			pgrp = pid;
658		else
659			pgrp = jp->ps[0].pid;
660		setpgid(pid, pgrp);
661	}
662	if (mode == FORK_BG)
663		backgndpid = pid;		/* set $! */
664	if (jp) {
665		struct procstat *ps = &jp->ps[jp->nprocs++];
666		ps->pid = pid;
667		ps->status = -1;
668		ps->cmd = nullstr;
669		if (iflag && rootshell && n)
670			ps->cmd = commandtext(n);
671	}
672	INTON;
673	TRACE(("In parent shell:  child = %d\n", pid));
674	return pid;
675}
676
677
678
679/*
680 * Wait for job to finish.
681 *
682 * Under job control we have the problem that while a child process is
683 * running interrupts generated by the user are sent to the child but not
684 * to the shell.  This means that an infinite loop started by an inter-
685 * active user may be hard to kill.  With job control turned off, an
686 * interactive user may place an interactive program inside a loop.  If
687 * the interactive program catches interrupts, the user doesn't want
688 * these interrupts to also abort the loop.  The approach we take here
689 * is to have the shell ignore interrupt signals while waiting for a
690 * forground process to terminate, and then send itself an interrupt
691 * signal if the child process was terminated by an interrupt signal.
692 * Unfortunately, some programs want to do a bit of cleanup and then
693 * exit on interrupt; unless these processes terminate themselves by
694 * sending a signal to themselves (instead of calling exit) they will
695 * confuse this approach.
696 */
697
698int
699waitforjob(jp)
700	struct job *jp;
701	{
702#if JOBS
703	int mypgrp = getpgrp();
704#endif
705	int status;
706	int st;
707
708	INTOFF;
709	TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
710	while (jp->state == 0) {
711		dowait(1, jp);
712	}
713	if (oldsigs_valid) {
714	       signal(SIGQUIT,oldsigquit);
715	       signal(SIGINT,oldsigint);
716	       oldsigs_valid = 0;
717	}
718
719#if JOBS
720	if (jp->jobctl) {
721#ifdef OLD_TTY_DRIVER
722		if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
723			error("TIOCSPGRP failed, errno=%d\n", errno);
724#else
725		if (tcsetpgrp(2, mypgrp) < 0)
726			error("tcsetpgrp failed, errno=%d\n", errno);
727#endif
728	}
729	if (jp->state == JOBSTOPPED)
730		curjob = jp - jobtab + 1;
731#endif
732	status = jp->ps[jp->nprocs - 1].status;
733	/* convert to 8 bits */
734	if (WIFEXITED(status))
735		st = WEXITSTATUS(status);
736#if JOBS
737	else if (WIFSTOPPED(status))
738		st = WSTOPSIG(status) + 128;
739#endif
740	else
741		st = WTERMSIG(status) + 128;
742	if (! JOBS || jp->state == JOBDONE)
743		freejob(jp);
744	CLEAR_PENDING_INT;
745	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
746		kill(getpid(), SIGINT);
747	INTON;
748	return st;
749}
750
751
752
753/*
754 * Wait for a process to terminate.
755 */
756
757STATIC int
758dowait(block, job)
759	int block;
760	struct job *job;
761{
762	int pid;
763	int status;
764	struct procstat *sp;
765	struct job *jp;
766	struct job *thisjob;
767	int done;
768	int stopped;
769	int core;
770	int sig;
771
772	TRACE(("dowait(%d) called\n", block));
773	do {
774		pid = waitproc(block, &status);
775		TRACE(("wait returns %d, status=%d\n", pid, status));
776	} while (pid == -1 && errno == EINTR);
777	if (pid <= 0)
778		return pid;
779	INTOFF;
780	thisjob = NULL;
781	for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
782		if (jp->used) {
783			done = 1;
784			stopped = 1;
785			for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
786				if (sp->pid == -1)
787					continue;
788				if (sp->pid == pid) {
789					TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
790						   pid, sp->status, status));
791					sp->status = status;
792					thisjob = jp;
793				}
794				if (sp->status == -1)
795					stopped = 0;
796				else if (WIFSTOPPED(sp->status))
797					done = 0;
798			}
799			if (stopped) {		/* stopped or done */
800				int state = done? JOBDONE : JOBSTOPPED;
801				if (jp->state != state) {
802					TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
803					jp->state = state;
804#if JOBS
805					if (done && curjob == jp - jobtab + 1)
806						curjob = 0;		/* no current job */
807#endif
808				}
809			}
810		}
811	}
812	INTON;
813	if (! rootshell || ! iflag || (job && thisjob == job)) {
814		core = WCOREDUMP(status);
815#if JOBS
816		if (WIFSTOPPED(status))
817			sig = WSTOPSIG(status);
818		else
819#endif
820			if (WIFEXITED(status))
821				sig = 0;
822			else
823				sig = WTERMSIG(status);
824
825		if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
826			if (thisjob != job)
827				outfmt(out2, "%d: ", pid);
828#if JOBS
829			if (sig == SIGTSTP && rootshell && iflag)
830				outfmt(out2, "%%%d ", job - jobtab + 1);
831#endif
832			if (sig < NSIG && sys_siglist[sig])
833				out2str(sys_siglist[sig]);
834			else
835				outfmt(out2, "Signal %d", sig);
836			if (core)
837				out2str(" - core dumped");
838			out2c('\n');
839			flushout(&errout);
840		} else {
841			TRACE(("Not printing status: status=%d, sig=%d\n",
842				   status, sig));
843		}
844	} else {
845		TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
846		if (thisjob)
847			thisjob->changed = 1;
848	}
849	return pid;
850}
851
852
853
854/*
855 * Do a wait system call.  If job control is compiled in, we accept
856 * stopped processes.  If block is zero, we return a value of zero
857 * rather than blocking.
858 *
859 * System V doesn't have a non-blocking wait system call.  It does
860 * have a SIGCLD signal that is sent to a process when one of it's
861 * children dies.  The obvious way to use SIGCLD would be to install
862 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
863 * was received, and have waitproc bump another counter when it got
864 * the status of a process.  Waitproc would then know that a wait
865 * system call would not block if the two counters were different.
866 * This approach doesn't work because if a process has children that
867 * have not been waited for, System V will send it a SIGCLD when it
868 * installs a signal handler for SIGCLD.  What this means is that when
869 * a child exits, the shell will be sent SIGCLD signals continuously
870 * until is runs out of stack space, unless it does a wait call before
871 * restoring the signal handler.  The code below takes advantage of
872 * this (mis)feature by installing a signal handler for SIGCLD and
873 * then checking to see whether it was called.  If there are any
874 * children to be waited for, it will be.
875 *
876 * If neither SYSV nor BSD is defined, we don't implement nonblocking
877 * waits at all.  In this case, the user will not be informed when
878 * a background process until the next time she runs a real program
879 * (as opposed to running a builtin command or just typing return),
880 * and the jobs command may give out of date information.
881 */
882
883#ifdef SYSV
884STATIC int gotsigchild;
885
886STATIC int onsigchild() {
887	gotsigchild = 1;
888}
889#endif
890
891
892STATIC int
893waitproc(block, status)
894	int block;
895	int *status;
896{
897#ifdef BSD
898	int flags;
899
900#if JOBS
901	flags = WUNTRACED;
902#else
903	flags = 0;
904#endif
905	if (block == 0)
906		flags |= WNOHANG;
907	return wait3(status, flags, (struct rusage *)NULL);
908#else
909#ifdef SYSV
910	int (*save)();
911
912	if (block == 0) {
913		gotsigchild = 0;
914		save = signal(SIGCLD, onsigchild);
915		signal(SIGCLD, save);
916		if (gotsigchild == 0)
917			return 0;
918	}
919	return wait(status);
920#else
921	if (block == 0)
922		return 0;
923	return wait(status);
924#endif
925#endif
926}
927
928/*
929 * return 1 if there are stopped jobs, otherwise 0
930 */
931int job_warning = 0;
932int
933stoppedjobs()
934{
935	int jobno;
936	struct job *jp;
937
938	if (job_warning)
939		return (0);
940	for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
941		if (jp->used == 0)
942			continue;
943		if (jp->state == JOBSTOPPED) {
944			out2str("You have stopped jobs.\n");
945			job_warning = 2;
946			return (1);
947		}
948	}
949
950	return (0);
951}
952
953/*
954 * Return a string identifying a command (to be printed by the
955 * jobs command.
956 */
957
958STATIC char *cmdnextc;
959STATIC int cmdnleft;
960STATIC void cmdtxt(), cmdputs();
961#define MAXCMDTEXT	200
962
963char *
964commandtext(n)
965	union node *n;
966	{
967	char *name;
968
969	cmdnextc = name = ckmalloc(MAXCMDTEXT);
970	cmdnleft = MAXCMDTEXT - 4;
971	cmdtxt(n);
972	*cmdnextc = '\0';
973	return name;
974}
975
976
977STATIC void
978cmdtxt(n)
979	union node *n;
980	{
981	union node *np;
982	struct nodelist *lp;
983	char *p;
984	int i;
985	char s[2];
986
987	if (n == NULL)
988		return;
989	switch (n->type) {
990	case NSEMI:
991		cmdtxt(n->nbinary.ch1);
992		cmdputs("; ");
993		cmdtxt(n->nbinary.ch2);
994		break;
995	case NAND:
996		cmdtxt(n->nbinary.ch1);
997		cmdputs(" && ");
998		cmdtxt(n->nbinary.ch2);
999		break;
1000	case NOR:
1001		cmdtxt(n->nbinary.ch1);
1002		cmdputs(" || ");
1003		cmdtxt(n->nbinary.ch2);
1004		break;
1005	case NPIPE:
1006		for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1007			cmdtxt(lp->n);
1008			if (lp->next)
1009				cmdputs(" | ");
1010		}
1011		break;
1012	case NSUBSHELL:
1013		cmdputs("(");
1014		cmdtxt(n->nredir.n);
1015		cmdputs(")");
1016		break;
1017	case NREDIR:
1018	case NBACKGND:
1019		cmdtxt(n->nredir.n);
1020		break;
1021	case NIF:
1022		cmdputs("if ");
1023		cmdtxt(n->nif.test);
1024		cmdputs("; then ");
1025		cmdtxt(n->nif.ifpart);
1026		cmdputs("...");
1027		break;
1028	case NWHILE:
1029		cmdputs("while ");
1030		goto until;
1031	case NUNTIL:
1032		cmdputs("until ");
1033until:
1034		cmdtxt(n->nbinary.ch1);
1035		cmdputs("; do ");
1036		cmdtxt(n->nbinary.ch2);
1037		cmdputs("; done");
1038		break;
1039	case NFOR:
1040		cmdputs("for ");
1041		cmdputs(n->nfor.var);
1042		cmdputs(" in ...");
1043		break;
1044	case NCASE:
1045		cmdputs("case ");
1046		cmdputs(n->ncase.expr->narg.text);
1047		cmdputs(" in ...");
1048		break;
1049	case NDEFUN:
1050		cmdputs(n->narg.text);
1051		cmdputs("() ...");
1052		break;
1053	case NCMD:
1054		for (np = n->ncmd.args ; np ; np = np->narg.next) {
1055			cmdtxt(np);
1056			if (np->narg.next)
1057				cmdputs(" ");
1058		}
1059		for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
1060			cmdputs(" ");
1061			cmdtxt(np);
1062		}
1063		break;
1064	case NARG:
1065		cmdputs(n->narg.text);
1066		break;
1067	case NTO:
1068		p = ">";  i = 1;  goto redir;
1069	case NAPPEND:
1070		p = ">>";  i = 1;  goto redir;
1071	case NTOFD:
1072		p = ">&";  i = 1;  goto redir;
1073	case NFROM:
1074		p = "<";  i = 0;  goto redir;
1075	case NFROMFD:
1076		p = "<&";  i = 0;  goto redir;
1077redir:
1078		if (n->nfile.fd != i) {
1079			s[0] = n->nfile.fd + '0';
1080			s[1] = '\0';
1081			cmdputs(s);
1082		}
1083		cmdputs(p);
1084		if (n->type == NTOFD || n->type == NFROMFD) {
1085			s[0] = n->ndup.dupfd + '0';
1086			s[1] = '\0';
1087			cmdputs(s);
1088		} else {
1089			cmdtxt(n->nfile.fname);
1090		}
1091		break;
1092	case NHERE:
1093	case NXHERE:
1094		cmdputs("<<...");
1095		break;
1096	default:
1097		cmdputs("???");
1098		break;
1099	}
1100}
1101
1102
1103
1104STATIC void
1105cmdputs(s)
1106	char *s;
1107	{
1108	char *p, *q;
1109	char c;
1110	int subtype = 0;
1111
1112	if (cmdnleft <= 0)
1113		return;
1114	p = s;
1115	q = cmdnextc;
1116	while ((c = *p++) != '\0') {
1117		if (c == CTLESC)
1118			*q++ = *p++;
1119		else if (c == CTLVAR) {
1120			*q++ = '$';
1121			if (--cmdnleft > 0)
1122				*q++ = '{';
1123			subtype = *p++;
1124		} else if (c == '=' && subtype != 0) {
1125			*q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
1126			subtype = 0;
1127		} else if (c == CTLENDVAR) {
1128			*q++ = '}';
1129		} else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
1130			cmdnleft++;		/* ignore it */
1131		else
1132			*q++ = c;
1133		if (--cmdnleft <= 0) {
1134			*q++ = '.';
1135			*q++ = '.';
1136			*q++ = '.';
1137			break;
1138		}
1139	}
1140	cmdnextc = q;
1141}
1142