jobs.c revision 20425
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.8 1996/10/16 02:30:39 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#ifdef 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;
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;
259	char **argv;
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;
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	register 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			register 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;
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			setpgid(0, pgrp);
604			if (mode == FORK_FG) {
605				/*** this causes superfluous TIOCSPGRPS ***/
606#ifdef OLD_TTY_DRIVER
607				if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
608					error("TIOCSPGRP failed, errno=%d", errno);
609#else
610				if (tcsetpgrp(2, pgrp) < 0)
611					error("tcsetpgrp failed, errno=%d", errno);
612#endif
613			}
614			setsignal(SIGTSTP);
615			setsignal(SIGTTOU);
616		} else if (mode == FORK_BG) {
617			ignoresig(SIGINT);
618			ignoresig(SIGQUIT);
619			if ((jp == NULL || jp->nprocs == 0) &&
620			    ! fd0_redirected_p ()) {
621				close(0);
622				if (open("/dev/null", O_RDONLY) != 0)
623					error("Can't open /dev/null");
624			}
625		}
626#else
627		if (mode == FORK_BG) {
628			ignoresig(SIGINT);
629			ignoresig(SIGQUIT);
630			if ((jp == NULL || jp->nprocs == 0) &&
631			    ! fd0_redirected_p ()) {
632				close(0);
633				if (open("/dev/null", O_RDONLY) != 0)
634					error("Can't open /dev/null");
635			}
636		}
637#endif
638		if (wasroot && iflag) {
639			setsignal(SIGINT);
640			setsignal(SIGQUIT);
641			setsignal(SIGTERM);
642		}
643		return pid;
644	}
645	if (rootshell && mode != FORK_NOJOB && mflag) {
646		if (jp == NULL || jp->nprocs == 0)
647			pgrp = pid;
648		else
649			pgrp = jp->ps[0].pid;
650		setpgid(pid, pgrp);
651	}
652	if (mode == FORK_BG)
653		backgndpid = pid;		/* set $! */
654	if (jp) {
655		struct procstat *ps = &jp->ps[jp->nprocs++];
656		ps->pid = pid;
657		ps->status = -1;
658		ps->cmd = nullstr;
659		if (iflag && rootshell && n)
660			ps->cmd = commandtext(n);
661	}
662	INTON;
663	TRACE(("In parent shell:  child = %d\n", pid));
664	return pid;
665}
666
667
668
669/*
670 * Wait for job to finish.
671 *
672 * Under job control we have the problem that while a child process is
673 * running interrupts generated by the user are sent to the child but not
674 * to the shell.  This means that an infinite loop started by an inter-
675 * active user may be hard to kill.  With job control turned off, an
676 * interactive user may place an interactive program inside a loop.  If
677 * the interactive program catches interrupts, the user doesn't want
678 * these interrupts to also abort the loop.  The approach we take here
679 * is to have the shell ignore interrupt signals while waiting for a
680 * forground process to terminate, and then send itself an interrupt
681 * signal if the child process was terminated by an interrupt signal.
682 * Unfortunately, some programs want to do a bit of cleanup and then
683 * exit on interrupt; unless these processes terminate themselves by
684 * sending a signal to themselves (instead of calling exit) they will
685 * confuse this approach.
686 */
687
688int
689waitforjob(jp)
690	register struct job *jp;
691	{
692#if JOBS
693	int mypgrp = getpgrp();
694#endif
695	int status;
696	int st;
697
698	INTOFF;
699	TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
700	while (jp->state == 0) {
701		dowait(1, jp);
702	}
703#if JOBS
704	if (jp->jobctl) {
705#ifdef OLD_TTY_DRIVER
706		if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
707			error("TIOCSPGRP failed, errno=%d\n", errno);
708#else
709		if (tcsetpgrp(2, mypgrp) < 0)
710			error("tcsetpgrp failed, errno=%d\n", errno);
711#endif
712	}
713	if (jp->state == JOBSTOPPED)
714		curjob = jp - jobtab + 1;
715#endif
716	status = jp->ps[jp->nprocs - 1].status;
717	/* convert to 8 bits */
718	if ((status & 0xFF) == 0)
719		st = status >> 8 & 0xFF;
720#if JOBS
721	else if ((status & 0xFF) == 0177)
722		st = (status >> 8 & 0x7F) + 128;
723#endif
724	else
725		st = (status & 0x7F) + 128;
726	if (! JOBS || jp->state == JOBDONE)
727		freejob(jp);
728	CLEAR_PENDING_INT;
729	if ((status & 0x7F) == SIGINT)
730		kill(getpid(), SIGINT);
731	INTON;
732	return st;
733}
734
735
736
737/*
738 * Wait for a process to terminate.
739 */
740
741STATIC int
742dowait(block, job)
743	int block;
744	struct job *job;
745{
746	int pid;
747	int status;
748	struct procstat *sp;
749	struct job *jp;
750	struct job *thisjob;
751	int done;
752	int stopped;
753	int core;
754
755	TRACE(("dowait(%d) called\n", block));
756	do {
757		pid = waitproc(block, &status);
758		TRACE(("wait returns %d, status=%d\n", pid, status));
759	} while (pid == -1 && errno == EINTR);
760	if (pid <= 0)
761		return pid;
762	INTOFF;
763	thisjob = NULL;
764	for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
765		if (jp->used) {
766			done = 1;
767			stopped = 1;
768			for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
769				if (sp->pid == -1)
770					continue;
771				if (sp->pid == pid) {
772					TRACE(("Changin status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
773					sp->status = status;
774					thisjob = jp;
775				}
776				if (sp->status == -1)
777					stopped = 0;
778				else if ((sp->status & 0377) == 0177)
779					done = 0;
780			}
781			if (stopped) {		/* stopped or done */
782				int state = done? JOBDONE : JOBSTOPPED;
783				if (jp->state != state) {
784					TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
785					jp->state = state;
786#if JOBS
787					if (done && curjob == jp - jobtab + 1)
788						curjob = 0;		/* no current job */
789#endif
790				}
791			}
792		}
793	}
794	INTON;
795	if (! rootshell || ! iflag || (job && thisjob == job)) {
796#if JOBS
797		if ((status & 0xFF) == 0177)
798			status >>= 8;
799#endif
800		core = status & 0x80;
801		status &= 0x7F;
802		if (status != 0 && status != SIGINT && status != SIGPIPE) {
803			if (thisjob != job)
804				outfmt(out2, "%d: ", pid);
805#if JOBS
806			if (status == SIGTSTP && rootshell && iflag)
807				outfmt(out2, "%%%d ", job - jobtab + 1);
808#endif
809			if (status < NSIG && sys_siglist[status])
810				out2str(sys_siglist[status]);
811			else
812				outfmt(out2, "Signal %d", status);
813			if (core)
814				out2str(" - core dumped");
815			out2c('\n');
816			flushout(&errout);
817		} else {
818			TRACE(("Not printing status: status=%d\n", status));
819		}
820	} else {
821		TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
822		if (thisjob)
823			thisjob->changed = 1;
824	}
825	return pid;
826}
827
828
829
830/*
831 * Do a wait system call.  If job control is compiled in, we accept
832 * stopped processes.  If block is zero, we return a value of zero
833 * rather than blocking.
834 *
835 * System V doesn't have a non-blocking wait system call.  It does
836 * have a SIGCLD signal that is sent to a process when one of it's
837 * children dies.  The obvious way to use SIGCLD would be to install
838 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
839 * was received, and have waitproc bump another counter when it got
840 * the status of a process.  Waitproc would then know that a wait
841 * system call would not block if the two counters were different.
842 * This approach doesn't work because if a process has children that
843 * have not been waited for, System V will send it a SIGCLD when it
844 * installs a signal handler for SIGCLD.  What this means is that when
845 * a child exits, the shell will be sent SIGCLD signals continuously
846 * until is runs out of stack space, unless it does a wait call before
847 * restoring the signal handler.  The code below takes advantage of
848 * this (mis)feature by installing a signal handler for SIGCLD and
849 * then checking to see whether it was called.  If there are any
850 * children to be waited for, it will be.
851 *
852 * If neither SYSV nor BSD is defined, we don't implement nonblocking
853 * waits at all.  In this case, the user will not be informed when
854 * a background process until the next time she runs a real program
855 * (as opposed to running a builtin command or just typing return),
856 * and the jobs command may give out of date information.
857 */
858
859#ifdef SYSV
860STATIC int gotsigchild;
861
862STATIC int onsigchild() {
863	gotsigchild = 1;
864}
865#endif
866
867
868STATIC int
869waitproc(block, status)
870	int block;
871	int *status;
872{
873#ifdef BSD
874	int flags;
875
876#if JOBS
877	flags = WUNTRACED;
878#else
879	flags = 0;
880#endif
881	if (block == 0)
882		flags |= WNOHANG;
883	return wait3(status, flags, (struct rusage *)NULL);
884#else
885#ifdef SYSV
886	int (*save)();
887
888	if (block == 0) {
889		gotsigchild = 0;
890		save = signal(SIGCLD, onsigchild);
891		signal(SIGCLD, save);
892		if (gotsigchild == 0)
893			return 0;
894	}
895	return wait(status);
896#else
897	if (block == 0)
898		return 0;
899	return wait(status);
900#endif
901#endif
902}
903
904/*
905 * return 1 if there are stopped jobs, otherwise 0
906 */
907int job_warning = 0;
908int
909stoppedjobs()
910{
911	register int jobno;
912	register struct job *jp;
913
914	if (job_warning)
915		return (0);
916	for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
917		if (jp->used == 0)
918			continue;
919		if (jp->state == JOBSTOPPED) {
920			out2str("You have stopped jobs.\n");
921			job_warning = 2;
922			return (1);
923		}
924	}
925
926	return (0);
927}
928
929/*
930 * Return a string identifying a command (to be printed by the
931 * jobs command.
932 */
933
934STATIC char *cmdnextc;
935STATIC int cmdnleft;
936STATIC void cmdtxt(), cmdputs();
937#define MAXCMDTEXT	200
938
939char *
940commandtext(n)
941	union node *n;
942	{
943	char *name;
944
945	cmdnextc = name = ckmalloc(MAXCMDTEXT);
946	cmdnleft = MAXCMDTEXT - 4;
947	cmdtxt(n);
948	*cmdnextc = '\0';
949	return name;
950}
951
952
953STATIC void
954cmdtxt(n)
955	union node *n;
956	{
957	union node *np;
958	struct nodelist *lp;
959	char *p;
960	int i;
961	char s[2];
962
963	if (n == NULL)
964		return;
965	switch (n->type) {
966	case NSEMI:
967		cmdtxt(n->nbinary.ch1);
968		cmdputs("; ");
969		cmdtxt(n->nbinary.ch2);
970		break;
971	case NAND:
972		cmdtxt(n->nbinary.ch1);
973		cmdputs(" && ");
974		cmdtxt(n->nbinary.ch2);
975		break;
976	case NOR:
977		cmdtxt(n->nbinary.ch1);
978		cmdputs(" || ");
979		cmdtxt(n->nbinary.ch2);
980		break;
981	case NPIPE:
982		for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
983			cmdtxt(lp->n);
984			if (lp->next)
985				cmdputs(" | ");
986		}
987		break;
988	case NSUBSHELL:
989		cmdputs("(");
990		cmdtxt(n->nredir.n);
991		cmdputs(")");
992		break;
993	case NREDIR:
994	case NBACKGND:
995		cmdtxt(n->nredir.n);
996		break;
997	case NIF:
998		cmdputs("if ");
999		cmdtxt(n->nif.test);
1000		cmdputs("; then ");
1001		cmdtxt(n->nif.ifpart);
1002		cmdputs("...");
1003		break;
1004	case NWHILE:
1005		cmdputs("while ");
1006		goto until;
1007	case NUNTIL:
1008		cmdputs("until ");
1009until:
1010		cmdtxt(n->nbinary.ch1);
1011		cmdputs("; do ");
1012		cmdtxt(n->nbinary.ch2);
1013		cmdputs("; done");
1014		break;
1015	case NFOR:
1016		cmdputs("for ");
1017		cmdputs(n->nfor.var);
1018		cmdputs(" in ...");
1019		break;
1020	case NCASE:
1021		cmdputs("case ");
1022		cmdputs(n->ncase.expr->narg.text);
1023		cmdputs(" in ...");
1024		break;
1025	case NDEFUN:
1026		cmdputs(n->narg.text);
1027		cmdputs("() ...");
1028		break;
1029	case NCMD:
1030		for (np = n->ncmd.args ; np ; np = np->narg.next) {
1031			cmdtxt(np);
1032			if (np->narg.next)
1033				cmdputs(" ");
1034		}
1035		for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
1036			cmdputs(" ");
1037			cmdtxt(np);
1038		}
1039		break;
1040	case NARG:
1041		cmdputs(n->narg.text);
1042		break;
1043	case NTO:
1044		p = ">";  i = 1;  goto redir;
1045	case NAPPEND:
1046		p = ">>";  i = 1;  goto redir;
1047	case NTOFD:
1048		p = ">&";  i = 1;  goto redir;
1049	case NFROM:
1050		p = "<";  i = 0;  goto redir;
1051	case NFROMFD:
1052		p = "<&";  i = 0;  goto redir;
1053redir:
1054		if (n->nfile.fd != i) {
1055			s[0] = n->nfile.fd + '0';
1056			s[1] = '\0';
1057			cmdputs(s);
1058		}
1059		cmdputs(p);
1060		if (n->type == NTOFD || n->type == NFROMFD) {
1061			s[0] = n->ndup.dupfd + '0';
1062			s[1] = '\0';
1063			cmdputs(s);
1064		} else {
1065			cmdtxt(n->nfile.fname);
1066		}
1067		break;
1068	case NHERE:
1069	case NXHERE:
1070		cmdputs("<<...");
1071		break;
1072	default:
1073		cmdputs("???");
1074		break;
1075	}
1076}
1077
1078
1079
1080STATIC void
1081cmdputs(s)
1082	char *s;
1083	{
1084	register char *p, *q;
1085	register char c;
1086	int subtype = 0;
1087
1088	if (cmdnleft <= 0)
1089		return;
1090	p = s;
1091	q = cmdnextc;
1092	while ((c = *p++) != '\0') {
1093		if (c == CTLESC)
1094			*q++ = *p++;
1095		else if (c == CTLVAR) {
1096			*q++ = '$';
1097			if (--cmdnleft > 0)
1098				*q++ = '{';
1099			subtype = *p++;
1100		} else if (c == '=' && subtype != 0) {
1101			*q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
1102			subtype = 0;
1103		} else if (c == CTLENDVAR) {
1104			*q++ = '}';
1105		} else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
1106			cmdnleft++;		/* ignore it */
1107		else
1108			*q++ = c;
1109		if (--cmdnleft <= 0) {
1110			*q++ = '.';
1111			*q++ = '.';
1112			*q++ = '.';
1113			break;
1114		}
1115	}
1116	cmdnextc = q;
1117}
1118