jobs.c revision 36150
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$";
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
90
91#if JOBS
92STATIC void restartjob __P((struct job *));
93#endif
94STATIC void freejob __P((struct job *));
95STATIC struct job *getjob __P((char *));
96STATIC int dowait __P((int, struct job *));
97#if SYSV
98STATIC int onsigchild __P((void));
99#endif
100STATIC int waitproc __P((int, int *));
101STATIC void cmdtxt __P((union node *));
102STATIC void cmdputs __P((char *));
103
104
105/*
106 * Turn job control on and off.
107 *
108 * Note:  This code assumes that the third arg to ioctl is a character
109 * pointer, which is true on Berkeley systems but not System V.  Since
110 * System V doesn't have job control yet, this isn't a problem now.
111 */
112
113MKINIT int jobctl;
114
115#if JOBS
116void
117setjobctl(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#endif
175
176
177#ifdef mkinit
178INCLUDE <sys/types.h>
179INCLUDE <stdlib.h>
180
181SHELLPROC {
182	backgndpid = -1;
183#if JOBS
184	jobctl = 0;
185#endif
186}
187
188#endif
189
190
191
192#if JOBS
193int
194fgcmd(argc, argv)
195	int argc __unused;
196	char **argv;
197{
198	struct job *jp;
199	int pgrp;
200	int status;
201
202	jp = getjob(argv[1]);
203	if (jp->jobctl == 0)
204		error("job not created under job control");
205	pgrp = jp->ps[0].pid;
206#ifdef OLD_TTY_DRIVER
207	ioctl(2, TIOCSPGRP, (char *)&pgrp);
208#else
209	tcsetpgrp(2, pgrp);
210#endif
211	restartjob(jp);
212	INTOFF;
213	status = waitforjob(jp);
214	INTON;
215	return status;
216}
217
218
219int
220bgcmd(argc, argv)
221	int argc;
222	char **argv;
223{
224	struct job *jp;
225
226	do {
227		jp = getjob(*++argv);
228		if (jp->jobctl == 0)
229			error("job not created under job control");
230		restartjob(jp);
231	} while (--argc > 1);
232	return 0;
233}
234
235
236STATIC void
237restartjob(jp)
238	struct job *jp;
239{
240	struct procstat *ps;
241	int i;
242
243	if (jp->state == JOBDONE)
244		return;
245	INTOFF;
246	killpg(jp->ps[0].pid, SIGCONT);
247	for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
248		if (WIFSTOPPED(ps->status)) {
249			ps->status = -1;
250			jp->state = 0;
251		}
252	}
253	INTON;
254}
255#endif
256
257
258int
259jobscmd(argc, argv)
260	int argc __unused;
261	char **argv __unused;
262{
263	showjobs(0);
264	return 0;
265}
266
267
268/*
269 * Print a list of jobs.  If "change" is nonzero, only print jobs whose
270 * statuses have changed since the last call to showjobs.
271 *
272 * If the shell is interrupted in the process of creating a job, the
273 * result may be a job structure containing zero processes.  Such structures
274 * will be freed here.
275 */
276
277void
278showjobs(change)
279	int change;
280{
281	int jobno;
282	int procno;
283	int i;
284	struct job *jp;
285	struct procstat *ps;
286	int col;
287	char s[64];
288
289	TRACE(("showjobs(%d) called\n", change));
290	while (dowait(0, (struct job *)NULL) > 0);
291	for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
292		if (! jp->used)
293			continue;
294		if (jp->nprocs == 0) {
295			freejob(jp);
296			continue;
297		}
298		if (change && ! jp->changed)
299			continue;
300		procno = jp->nprocs;
301		for (ps = jp->ps ; ; ps++) {	/* for each process */
302			if (ps == jp->ps)
303				fmtstr(s, 64, "[%d] %d ", jobno, ps->pid);
304			else
305				fmtstr(s, 64, "    %d ", ps->pid);
306			out1str(s);
307			col = strlen(s);
308			s[0] = '\0';
309			if (ps->status == -1) {
310				/* don't print anything */
311			} else if (WIFEXITED(ps->status)) {
312				fmtstr(s, 64, "Exit %d", WEXITSTATUS(ps->status));
313			} else {
314#if JOBS
315				if (WIFSTOPPED(ps->status))
316					i = WSTOPSIG(ps->status);
317				else
318#endif
319					i = WTERMSIG(ps->status);
320				if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
321					scopy(sys_siglist[i & 0x7F], s);
322				else
323					fmtstr(s, 64, "Signal %d", i & 0x7F);
324				if (WCOREDUMP(ps->status))
325					strcat(s, " (core dumped)");
326			}
327			out1str(s);
328			col += strlen(s);
329			do {
330				out1c(' ');
331				col++;
332			} while (col < 30);
333			out1str(ps->cmd);
334			out1c('\n');
335			if (--procno <= 0)
336				break;
337		}
338		jp->changed = 0;
339		if (jp->state == JOBDONE) {
340			freejob(jp);
341		}
342	}
343}
344
345
346/*
347 * Mark a job structure as unused.
348 */
349
350STATIC void
351freejob(jp)
352	struct job *jp;
353	{
354	struct procstat *ps;
355	int i;
356
357	INTOFF;
358	for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
359		if (ps->cmd != nullstr)
360			ckfree(ps->cmd);
361	}
362	if (jp->ps != &jp->ps0)
363		ckfree(jp->ps);
364	jp->used = 0;
365#if JOBS
366	if (curjob == jp - jobtab + 1)
367		curjob = 0;
368#endif
369	INTON;
370}
371
372
373
374int
375waitcmd(argc, argv)
376	int argc;
377	char **argv;
378{
379	struct job *job;
380	int status, retval;
381	struct job *jp;
382
383	if (argc > 1) {
384		job = getjob(argv[1]);
385	} else {
386		job = NULL;
387	}
388	for (;;) {	/* loop until process terminated or stopped */
389		if (job != NULL) {
390			if (job->state) {
391				status = job->ps[job->nprocs - 1].status;
392				if (WIFEXITED(status))
393					retval = WEXITSTATUS(status);
394#if JOBS
395				else if (WIFSTOPPED(status))
396					retval = WSTOPSIG(status) + 128;
397#endif
398				else
399					retval = WTERMSIG(status) + 128;
400				if (! iflag)
401					freejob(job);
402				return retval;
403			}
404		} else {
405			for (jp = jobtab ; ; jp++) {
406				if (jp >= jobtab + njobs) {	/* no running procs */
407					return 0;
408				}
409				if (jp->used && jp->state == 0)
410					break;
411			}
412		}
413		dowait(1, (struct job *)NULL);
414	}
415}
416
417
418
419int
420jobidcmd(argc, argv)
421	int argc __unused;
422	char **argv;
423{
424	struct job *jp;
425	int i;
426
427	jp = getjob(argv[1]);
428	for (i = 0 ; i < jp->nprocs ; ) {
429		out1fmt("%d", jp->ps[i].pid);
430		out1c(++i < jp->nprocs? ' ' : '\n');
431	}
432	return 0;
433}
434
435
436
437/*
438 * Convert a job name to a job structure.
439 */
440
441STATIC struct job *
442getjob(name)
443	char *name;
444	{
445	int jobno;
446	struct job *jp;
447	int pid;
448	int i;
449
450	if (name == NULL) {
451#if JOBS
452currentjob:
453		if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
454			error("No current job");
455		return &jobtab[jobno - 1];
456#else
457		error("No current job");
458#endif
459	} else if (name[0] == '%') {
460		if (is_digit(name[1])) {
461			jobno = number(name + 1);
462			if (jobno > 0 && jobno <= njobs
463			 && jobtab[jobno - 1].used != 0)
464				return &jobtab[jobno - 1];
465#if JOBS
466		} else if (name[1] == '%' && name[2] == '\0') {
467			goto currentjob;
468#endif
469		} else {
470			struct job *found = NULL;
471			for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
472				if (jp->used && jp->nprocs > 0
473				 && prefix(name + 1, jp->ps[0].cmd)) {
474					if (found)
475						error("%s: ambiguous", name);
476					found = jp;
477				}
478			}
479			if (found)
480				return found;
481		}
482	} else if (is_number(name)) {
483		pid = number(name);
484		for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
485			if (jp->used && jp->nprocs > 0
486			 && jp->ps[jp->nprocs - 1].pid == pid)
487				return jp;
488		}
489	}
490	error("No such job: %s", name);
491	/*NOTREACHED*/
492	return NULL;
493}
494
495
496
497/*
498 * Return a new job structure,
499 */
500
501struct job *
502makejob(node, nprocs)
503	union node *node __unused;
504	int nprocs;
505{
506	int i;
507	struct job *jp;
508
509	for (i = njobs, jp = jobtab ; ; jp++) {
510		if (--i < 0) {
511			INTOFF;
512			if (njobs == 0) {
513				jobtab = ckmalloc(4 * sizeof jobtab[0]);
514			} else {
515				jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
516				memcpy(jp, jobtab, njobs * sizeof jp[0]);
517				/* Relocate `ps' pointers */
518				for (i = 0; i < njobs; i++)
519					if (jp[i].ps == &jobtab[i].ps0)
520						jp[i].ps = &jp[i].ps0;
521				ckfree(jobtab);
522				jobtab = jp;
523			}
524			jp = jobtab + njobs;
525			for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
526			INTON;
527			break;
528		}
529		if (jp->used == 0)
530			break;
531	}
532	INTOFF;
533	jp->state = 0;
534	jp->used = 1;
535	jp->changed = 0;
536	jp->nprocs = 0;
537#if JOBS
538	jp->jobctl = jobctl;
539#endif
540	if (nprocs > 1) {
541		jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
542	} else {
543		jp->ps = &jp->ps0;
544	}
545	INTON;
546	TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
547	    jp - jobtab + 1));
548	return jp;
549}
550
551
552/*
553 * Fork of a subshell.  If we are doing job control, give the subshell its
554 * own process group.  Jp is a job structure that the job is to be added to.
555 * N is the command that will be evaluated by the child.  Both jp and n may
556 * be NULL.  The mode parameter can be one of the following:
557 *	FORK_FG - Fork off a foreground process.
558 *	FORK_BG - Fork off a background process.
559 *	FORK_NOJOB - Like FORK_FG, but don't give the process its own
560 *		     process group even if job control is on.
561 *
562 * When job control is turned off, background processes have their standard
563 * input redirected to /dev/null (except for the second and later processes
564 * in a pipeline).
565 */
566
567int
568forkshell(jp, n, mode)
569	union node *n;
570	struct job *jp;
571	int mode;
572{
573	int pid;
574	int pgrp;
575
576	TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
577	    mode));
578	INTOFF;
579	pid = fork();
580	if (pid == -1) {
581		TRACE(("Fork failed, errno=%d\n", errno));
582		INTON;
583		error("Cannot fork");
584	}
585	if (pid == 0) {
586		struct job *p;
587		int wasroot;
588		int i;
589
590		TRACE(("Child shell %d\n", getpid()));
591		wasroot = rootshell;
592		rootshell = 0;
593		for (i = njobs, p = jobtab ; --i >= 0 ; p++)
594			if (p->used)
595				freejob(p);
596		closescript();
597		INTON;
598		clear_traps();
599#if JOBS
600		jobctl = 0;		/* do job control only in root shell */
601		if (wasroot && mode != FORK_NOJOB && mflag) {
602			if (jp == NULL || jp->nprocs == 0)
603				pgrp = getpid();
604			else
605				pgrp = jp->ps[0].pid;
606			if (setpgid(0, pgrp) == 0 && mode == FORK_FG) {
607				/*** this causes superfluous TIOCSPGRPS ***/
608#ifdef OLD_TTY_DRIVER
609				if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
610					error("TIOCSPGRP failed, errno=%d", errno);
611#else
612				if (tcsetpgrp(2, pgrp) < 0)
613					error("tcsetpgrp failed, errno=%d", errno);
614#endif
615			}
616			setsignal(SIGTSTP);
617			setsignal(SIGTTOU);
618		} else if (mode == FORK_BG) {
619			ignoresig(SIGINT);
620			ignoresig(SIGQUIT);
621			if ((jp == NULL || jp->nprocs == 0) &&
622			    ! fd0_redirected_p ()) {
623				close(0);
624				if (open("/dev/null", O_RDONLY) != 0)
625					error("Can't open /dev/null");
626			}
627		}
628#else
629		if (mode == FORK_BG) {
630			ignoresig(SIGINT);
631			ignoresig(SIGQUIT);
632			if ((jp == NULL || jp->nprocs == 0) &&
633			    ! fd0_redirected_p ()) {
634				close(0);
635				if (open("/dev/null", O_RDONLY) != 0)
636					error("Can't open /dev/null");
637			}
638		}
639#endif
640		if (wasroot && iflag) {
641			setsignal(SIGINT);
642			setsignal(SIGQUIT);
643			setsignal(SIGTERM);
644		}
645		return pid;
646	}
647	if (rootshell && mode != FORK_NOJOB && mflag) {
648		if (jp == NULL || jp->nprocs == 0)
649			pgrp = pid;
650		else
651			pgrp = jp->ps[0].pid;
652		setpgid(pid, pgrp);
653	}
654	if (mode == FORK_BG)
655		backgndpid = pid;		/* set $! */
656	if (jp) {
657		struct procstat *ps = &jp->ps[jp->nprocs++];
658		ps->pid = pid;
659		ps->status = -1;
660		ps->cmd = nullstr;
661		if (iflag && rootshell && n)
662			ps->cmd = commandtext(n);
663	}
664	INTON;
665	TRACE(("In parent shell:  child = %d\n", pid));
666	return pid;
667}
668
669
670
671/*
672 * Wait for job to finish.
673 *
674 * Under job control we have the problem that while a child process is
675 * running interrupts generated by the user are sent to the child but not
676 * to the shell.  This means that an infinite loop started by an inter-
677 * active user may be hard to kill.  With job control turned off, an
678 * interactive user may place an interactive program inside a loop.  If
679 * the interactive program catches interrupts, the user doesn't want
680 * these interrupts to also abort the loop.  The approach we take here
681 * is to have the shell ignore interrupt signals while waiting for a
682 * forground process to terminate, and then send itself an interrupt
683 * signal if the child process was terminated by an interrupt signal.
684 * Unfortunately, some programs want to do a bit of cleanup and then
685 * exit on interrupt; unless these processes terminate themselves by
686 * sending a signal to themselves (instead of calling exit) they will
687 * confuse this approach.
688 */
689
690int
691waitforjob(jp)
692	struct job *jp;
693	{
694#if JOBS
695	int mypgrp = getpgrp();
696#endif
697	int status;
698	int st;
699
700	INTOFF;
701	TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
702	while (jp->state == 0) {
703		dowait(1, jp);
704	}
705#if JOBS
706	if (jp->jobctl) {
707#ifdef OLD_TTY_DRIVER
708		if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
709			error("TIOCSPGRP failed, errno=%d\n", errno);
710#else
711		if (tcsetpgrp(2, mypgrp) < 0)
712			error("tcsetpgrp failed, errno=%d\n", errno);
713#endif
714	}
715	if (jp->state == JOBSTOPPED)
716		curjob = jp - jobtab + 1;
717#endif
718	status = jp->ps[jp->nprocs - 1].status;
719	/* convert to 8 bits */
720	if (WIFEXITED(status))
721		st = WEXITSTATUS(status);
722#if JOBS
723	else if (WIFSTOPPED(status))
724		st = WSTOPSIG(status) + 128;
725#endif
726	else
727		st = WTERMSIG(status) + 128;
728	if (! JOBS || jp->state == JOBDONE)
729		freejob(jp);
730	CLEAR_PENDING_INT;
731	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
732		kill(getpid(), SIGINT);
733	INTON;
734	return st;
735}
736
737
738
739/*
740 * Wait for a process to terminate.
741 */
742
743STATIC int
744dowait(block, job)
745	int block;
746	struct job *job;
747{
748	int pid;
749	int status;
750	struct procstat *sp;
751	struct job *jp;
752	struct job *thisjob;
753	int done;
754	int stopped;
755	int core;
756	int sig;
757
758	TRACE(("dowait(%d) called\n", block));
759	do {
760		pid = waitproc(block, &status);
761		TRACE(("wait returns %d, status=%d\n", pid, status));
762	} while (pid == -1 && errno == EINTR);
763	if (pid <= 0)
764		return pid;
765	INTOFF;
766	thisjob = NULL;
767	for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
768		if (jp->used) {
769			done = 1;
770			stopped = 1;
771			for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
772				if (sp->pid == -1)
773					continue;
774				if (sp->pid == pid) {
775					TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
776						   pid, sp->status, status));
777					sp->status = status;
778					thisjob = jp;
779				}
780				if (sp->status == -1)
781					stopped = 0;
782				else if (WIFSTOPPED(sp->status))
783					done = 0;
784			}
785			if (stopped) {		/* stopped or done */
786				int state = done? JOBDONE : JOBSTOPPED;
787				if (jp->state != state) {
788					TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
789					jp->state = state;
790#if JOBS
791					if (done && curjob == jp - jobtab + 1)
792						curjob = 0;		/* no current job */
793#endif
794				}
795			}
796		}
797	}
798	INTON;
799	if (! rootshell || ! iflag || (job && thisjob == job)) {
800		core = WCOREDUMP(status);
801#if JOBS
802		if (WIFSTOPPED(status))
803			sig = WSTOPSIG(status);
804		else
805#endif
806			if (WIFEXITED(status))
807				sig = 0;
808			else
809				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, "%%%d ", job - jobtab + 1);
817#endif
818			if (sig < NSIG && sys_siglist[sig])
819				out2str(sys_siglist[sig]);
820			else
821				outfmt(out2, "Signal %d", sig);
822			if (core)
823				out2str(" - core dumped");
824			out2c('\n');
825			flushout(&errout);
826		} else {
827			TRACE(("Not printing status: status=%d, sig=%d\n",
828				   status, sig));
829		}
830	} else {
831		TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
832		if (thisjob)
833			thisjob->changed = 1;
834	}
835	return pid;
836}
837
838
839
840/*
841 * Do a wait system call.  If job control is compiled in, we accept
842 * stopped processes.  If block is zero, we return a value of zero
843 * rather than blocking.
844 *
845 * System V doesn't have a non-blocking wait system call.  It does
846 * have a SIGCLD signal that is sent to a process when one of it's
847 * children dies.  The obvious way to use SIGCLD would be to install
848 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
849 * was received, and have waitproc bump another counter when it got
850 * the status of a process.  Waitproc would then know that a wait
851 * system call would not block if the two counters were different.
852 * This approach doesn't work because if a process has children that
853 * have not been waited for, System V will send it a SIGCLD when it
854 * installs a signal handler for SIGCLD.  What this means is that when
855 * a child exits, the shell will be sent SIGCLD signals continuously
856 * until is runs out of stack space, unless it does a wait call before
857 * restoring the signal handler.  The code below takes advantage of
858 * this (mis)feature by installing a signal handler for SIGCLD and
859 * then checking to see whether it was called.  If there are any
860 * children to be waited for, it will be.
861 *
862 * If neither SYSV nor BSD is defined, we don't implement nonblocking
863 * waits at all.  In this case, the user will not be informed when
864 * a background process until the next time she runs a real program
865 * (as opposed to running a builtin command or just typing return),
866 * and the jobs command may give out of date information.
867 */
868
869#ifdef SYSV
870STATIC int gotsigchild;
871
872STATIC int onsigchild() {
873	gotsigchild = 1;
874}
875#endif
876
877
878STATIC int
879waitproc(block, status)
880	int block;
881	int *status;
882{
883#ifdef BSD
884	int flags;
885
886#if JOBS
887	flags = WUNTRACED;
888#else
889	flags = 0;
890#endif
891	if (block == 0)
892		flags |= WNOHANG;
893	return wait3(status, flags, (struct rusage *)NULL);
894#else
895#ifdef SYSV
896	int (*save)();
897
898	if (block == 0) {
899		gotsigchild = 0;
900		save = signal(SIGCLD, onsigchild);
901		signal(SIGCLD, save);
902		if (gotsigchild == 0)
903			return 0;
904	}
905	return wait(status);
906#else
907	if (block == 0)
908		return 0;
909	return wait(status);
910#endif
911#endif
912}
913
914/*
915 * return 1 if there are stopped jobs, otherwise 0
916 */
917int job_warning = 0;
918int
919stoppedjobs()
920{
921	int jobno;
922	struct job *jp;
923
924	if (job_warning)
925		return (0);
926	for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
927		if (jp->used == 0)
928			continue;
929		if (jp->state == JOBSTOPPED) {
930			out2str("You have stopped jobs.\n");
931			job_warning = 2;
932			return (1);
933		}
934	}
935
936	return (0);
937}
938
939/*
940 * Return a string identifying a command (to be printed by the
941 * jobs command.
942 */
943
944STATIC char *cmdnextc;
945STATIC int cmdnleft;
946STATIC void cmdtxt(), cmdputs();
947#define MAXCMDTEXT	200
948
949char *
950commandtext(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
963STATIC void
964cmdtxt(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 ");
1019until:
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;
1063redir:
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
1090STATIC void
1091cmdputs(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