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