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