jobs.c revision 33142
1219820Sjeff/*-
2219820Sjeff * Copyright (c) 1991, 1993
3219820Sjeff *	The Regents of the University of California.  All rights reserved.
4219820Sjeff *
5290003Shselasky * This code is derived from software contributed to Berkeley by
6219820Sjeff * Kenneth Almquist.
7219820Sjeff *
8219820Sjeff * Redistribution and use in source and binary forms, with or without
9219820Sjeff * modification, are permitted provided that the following conditions
10219820Sjeff * are met:
11219820Sjeff * 1. Redistributions of source code must retain the above copyright
12219820Sjeff *    notice, this list of conditions and the following disclaimer.
13219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright
14219820Sjeff *    notice, this list of conditions and the following disclaimer in the
15219820Sjeff *    documentation and/or other materials provided with the distribution.
16219820Sjeff * 3. All advertising materials mentioning features or use of this software
17219820Sjeff *    must display the following acknowledgement:
18219820Sjeff *	This product includes software developed by the University of
19219820Sjeff *	California, Berkeley and its contributors.
20219820Sjeff * 4. Neither the name of the University nor the names of its contributors
21219820Sjeff *    may be used to endorse or promote products derived from this software
22219820Sjeff *    without specific prior written permission.
23219820Sjeff *
24219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25219820Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26219820Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27219820Sjeff * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28289644Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29289644Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30219820Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31219820Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32219820Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33219820Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34219820Sjeff * SUCH DAMAGE.
35219820Sjeff *
36219820Sjeff *	$Id: jobs.c,v 1.17 1997/12/10 22:18:53 eivind Exp $
37219820Sjeff */
38219820Sjeff
39219820Sjeff#ifndef lint
40219820Sjeffstatic char const sccsid[] = "@(#)jobs.c	8.5 (Berkeley) 5/4/95";
41219820Sjeff#endif /* not lint */
42219820Sjeff
43219820Sjeff#include <fcntl.h>
44219820Sjeff#include <signal.h>
45219820Sjeff#include <errno.h>
46219820Sjeff#include <unistd.h>
47219820Sjeff#include <stdlib.h>
48219820Sjeff#include <sys/param.h>
49219820Sjeff#ifdef BSD
50219820Sjeff#include <sys/wait.h>
51219820Sjeff#include <sys/time.h>
52219820Sjeff#include <sys/resource.h>
53310250Shselasky#endif
54219820Sjeff#include <sys/ioctl.h>
55219820Sjeff
56219820Sjeff#include "shell.h"
57310250Shselasky#if JOBS
58219820Sjeff#if OLD_TTY_DRIVER
59219820Sjeff#include "sgtty.h"
60219820Sjeff#else
61219820Sjeff#include <termios.h>
62219820Sjeff#endif
63219820Sjeff#undef CEOF			/* syntax.h redefines this */
64293419Shselasky#endif
65219820Sjeff#include "redir.h"
66219820Sjeff#include "show.h"
67310250Shselasky#include "main.h"
68219820Sjeff#include "parser.h"
69219820Sjeff#include "nodes.h"
70219820Sjeff#include "jobs.h"
71219820Sjeff#include "options.h"
72219820Sjeff#include "trap.h"
73219820Sjeff#include "syntax.h"
74219820Sjeff#include "input.h"
75219820Sjeff#include "output.h"
76219820Sjeff#include "memalloc.h"
77219820Sjeff#include "error.h"
78219820Sjeff#include "mystring.h"
79219820Sjeff
80219820Sjeff
81219820Sjeffstruct job *jobtab;		/* array of jobs */
82219820Sjeffint njobs;			/* size of array */
83219820SjeffMKINIT pid_t backgndpid = -1;	/* pid of last background process */
84219820Sjeff#if JOBS
85219820Sjeffint initialpgrp;		/* pgrp of shell on invocation */
86219820Sjeffint curjob;			/* current job */
87219820Sjeff#endif
88310250Shselasky
89219820Sjeff#if JOBS
90219820SjeffSTATIC void restartjob __P((struct job *));
91293419Shselasky#endif
92219820SjeffSTATIC void freejob __P((struct job *));
93219820SjeffSTATIC struct job *getjob __P((char *));
94219820SjeffSTATIC int dowait __P((int, struct job *));
95219820Sjeff#if SYSV
96219820SjeffSTATIC int onsigchild __P((void));
97219820Sjeff#endif
98219820SjeffSTATIC int waitproc __P((int, int *));
99219820SjeffSTATIC void cmdtxt __P((union node *));
100219820SjeffSTATIC void cmdputs __P((char *));
101219820Sjeff
102219820Sjeff
103293419Shselasky/*
104219820Sjeff * Turn job control on and off.
105219820Sjeff *
106219820Sjeff * Note:  This code assumes that the third arg to ioctl is a character
107219820Sjeff * pointer, which is true on Berkeley systems but not System V.  Since
108219820Sjeff * System V doesn't have job control yet, this isn't a problem now.
109219820Sjeff */
110219820Sjeff
111219820SjeffMKINIT int jobctl;
112219820Sjeff
113219820Sjeff#if JOBS
114290003Shselaskyvoid
115290003Shselaskysetjobctl(on)
116290003Shselasky	int on;
117290003Shselasky{
118290003Shselasky#ifdef OLD_TTY_DRIVER
119290003Shselasky	int ldisc;
120310250Shselasky#endif
121290003Shselasky
122290003Shselasky	if (on == jobctl || rootshell == 0)
123290003Shselasky		return;
124293419Shselasky	if (on) {
125290003Shselasky		do { /* while we are in the background */
126290003Shselasky#ifdef OLD_TTY_DRIVER
127290003Shselasky			if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
128290003Shselasky#else
129290003Shselasky			initialpgrp = tcgetpgrp(2);
130290003Shselasky			if (initialpgrp < 0) {
131219820Sjeff#endif
132219820Sjeff				out2str("sh: can't access tty; job control turned off\n");
133219820Sjeff				mflag = 0;
134219820Sjeff				return;
135219820Sjeff			}
136219820Sjeff			if (initialpgrp == -1)
137219820Sjeff				initialpgrp = getpgrp();
138310250Shselasky			else if (initialpgrp != getpgrp()) {
139219820Sjeff				killpg(initialpgrp, SIGTTIN);
140219820Sjeff				continue;
141293419Shselasky			}
142293419Shselasky		} while (0);
143219820Sjeff#ifdef OLD_TTY_DRIVER
144219820Sjeff		if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
145219820Sjeff			out2str("sh: need new tty driver to run job control; job control turned off\n");
146219820Sjeff			mflag = 0;
147219820Sjeff			return;
148219820Sjeff		}
149219820Sjeff#endif
150219820Sjeff		setsignal(SIGTSTP);
151328653Shselasky		setsignal(SIGTTOU);
152328653Shselasky		setsignal(SIGTTIN);
153328653Shselasky		setpgid(0, rootpid);
154328653Shselasky#ifdef OLD_TTY_DRIVER
155328653Shselasky		ioctl(2, TIOCSPGRP, (char *)&rootpid);
156328653Shselasky#else
157328653Shselasky		tcsetpgrp(2, rootpid);
158328653Shselasky#endif
159328653Shselasky	} else { /* turning job control off */
160328653Shselasky		setpgid(0, initialpgrp);
161328653Shselasky#ifdef OLD_TTY_DRIVER
162328653Shselasky		ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
163328653Shselasky#else
164328653Shselasky		tcsetpgrp(2, initialpgrp);
165328653Shselasky#endif
166328653Shselasky		setsignal(SIGTSTP);
167328653Shselasky		setsignal(SIGTTOU);
168328653Shselasky		setsignal(SIGTTIN);
169328653Shselasky	}
170328653Shselasky	jobctl = on;
171328653Shselasky}
172219820Sjeff#endif
173
174
175#ifdef mkinit
176INCLUDE <sys/types.h>
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 (WIFSTOPPED(ps->status)) {
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 (WIFEXITED(ps->status)) {
310				fmtstr(s, 64, "Exit %d", WEXITSTATUS(ps->status));
311			} else {
312#if JOBS
313				if (WIFSTOPPED(ps->status))
314					i = WSTOPSIG(ps->status);
315				else
316#endif
317					i = WTERMSIG(ps->status);
318				if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
319					scopy(sys_siglist[i & 0x7F], s);
320				else
321					fmtstr(s, 64, "Signal %d", i & 0x7F);
322				if (WCOREDUMP(ps->status))
323					strcat(s, " (core dumped)");
324			}
325			out1str(s);
326			col += strlen(s);
327			do {
328				out1c(' ');
329				col++;
330			} while (col < 30);
331			out1str(ps->cmd);
332			out1c('\n');
333			if (--procno <= 0)
334				break;
335		}
336		jp->changed = 0;
337		if (jp->state == JOBDONE) {
338			freejob(jp);
339		}
340	}
341}
342
343
344/*
345 * Mark a job structure as unused.
346 */
347
348STATIC void
349freejob(jp)
350	struct job *jp;
351	{
352	struct procstat *ps;
353	int i;
354
355	INTOFF;
356	for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
357		if (ps->cmd != nullstr)
358			ckfree(ps->cmd);
359	}
360	if (jp->ps != &jp->ps0)
361		ckfree(jp->ps);
362	jp->used = 0;
363#if JOBS
364	if (curjob == jp - jobtab + 1)
365		curjob = 0;
366#endif
367	INTON;
368}
369
370
371
372int
373waitcmd(argc, argv)
374	int argc;
375	char **argv;
376{
377	struct job *job;
378	int status, retval;
379	struct job *jp;
380
381	if (argc > 1) {
382		job = getjob(argv[1]);
383	} else {
384		job = NULL;
385	}
386	for (;;) {	/* loop until process terminated or stopped */
387		if (job != NULL) {
388			if (job->state) {
389				status = job->ps[job->nprocs - 1].status;
390				if (WIFEXITED(status))
391					retval = WEXITSTATUS(status);
392#if JOBS
393				else if (WIFSTOPPED(status))
394					retval = WSTOPSIG(status) + 128;
395#endif
396				else
397					retval = WTERMSIG(status) + 128;
398				if (! iflag)
399					freejob(job);
400				return retval;
401			}
402		} else {
403			for (jp = jobtab ; ; jp++) {
404				if (jp >= jobtab + njobs) {	/* no running procs */
405					return 0;
406				}
407				if (jp->used && jp->state == 0)
408					break;
409			}
410		}
411		dowait(1, (struct job *)NULL);
412	}
413}
414
415
416
417int
418jobidcmd(argc, argv)
419	int argc __unused;
420	char **argv;
421{
422	struct job *jp;
423	int i;
424
425	jp = getjob(argv[1]);
426	for (i = 0 ; i < jp->nprocs ; ) {
427		out1fmt("%d", jp->ps[i].pid);
428		out1c(++i < jp->nprocs? ' ' : '\n');
429	}
430	return 0;
431}
432
433
434
435/*
436 * Convert a job name to a job structure.
437 */
438
439STATIC struct job *
440getjob(name)
441	char *name;
442	{
443	int jobno;
444	struct job *jp;
445	int pid;
446	int i;
447
448	if (name == NULL) {
449#if JOBS
450currentjob:
451		if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
452			error("No current job");
453		return &jobtab[jobno - 1];
454#else
455		error("No current job");
456#endif
457	} else if (name[0] == '%') {
458		if (is_digit(name[1])) {
459			jobno = number(name + 1);
460			if (jobno > 0 && jobno <= njobs
461			 && jobtab[jobno - 1].used != 0)
462				return &jobtab[jobno - 1];
463#if JOBS
464		} else if (name[1] == '%' && name[2] == '\0') {
465			goto currentjob;
466#endif
467		} else {
468			struct job *found = NULL;
469			for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
470				if (jp->used && jp->nprocs > 0
471				 && prefix(name + 1, jp->ps[0].cmd)) {
472					if (found)
473						error("%s: ambiguous", name);
474					found = jp;
475				}
476			}
477			if (found)
478				return found;
479		}
480	} else if (is_number(name)) {
481		pid = number(name);
482		for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
483			if (jp->used && jp->nprocs > 0
484			 && jp->ps[jp->nprocs - 1].pid == pid)
485				return jp;
486		}
487	}
488	error("No such job: %s", name);
489	/*NOTREACHED*/
490	return NULL;
491}
492
493
494
495/*
496 * Return a new job structure,
497 */
498
499struct job *
500makejob(node, nprocs)
501	union node *node __unused;
502	int nprocs;
503{
504	int i;
505	struct job *jp;
506
507	for (i = njobs, jp = jobtab ; ; jp++) {
508		if (--i < 0) {
509			INTOFF;
510			if (njobs == 0) {
511				jobtab = ckmalloc(4 * sizeof jobtab[0]);
512			} else {
513				jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
514				memcpy(jp, jobtab, njobs * sizeof jp[0]);
515				/* Relocate `ps' pointers */
516				for (i = 0; i < njobs; i++)
517					if (jp[i].ps == &jobtab[i].ps0)
518						jp[i].ps = &jp[i].ps0;
519				ckfree(jobtab);
520				jobtab = jp;
521			}
522			jp = jobtab + njobs;
523			for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
524			INTON;
525			break;
526		}
527		if (jp->used == 0)
528			break;
529	}
530	INTOFF;
531	jp->state = 0;
532	jp->used = 1;
533	jp->changed = 0;
534	jp->nprocs = 0;
535#if JOBS
536	jp->jobctl = jobctl;
537#endif
538	if (nprocs > 1) {
539		jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
540	} else {
541		jp->ps = &jp->ps0;
542	}
543	INTON;
544	TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
545	    jp - jobtab + 1));
546	return jp;
547}
548
549
550/*
551 * Fork of a subshell.  If we are doing job control, give the subshell its
552 * own process group.  Jp is a job structure that the job is to be added to.
553 * N is the command that will be evaluated by the child.  Both jp and n may
554 * be NULL.  The mode parameter can be one of the following:
555 *	FORK_FG - Fork off a foreground process.
556 *	FORK_BG - Fork off a background process.
557 *	FORK_NOJOB - Like FORK_FG, but don't give the process its own
558 *		     process group even if job control is on.
559 *
560 * When job control is turned off, background processes have their standard
561 * input redirected to /dev/null (except for the second and later processes
562 * in a pipeline).
563 */
564
565int
566forkshell(jp, n, mode)
567	union node *n;
568	struct job *jp;
569	int mode;
570{
571	int pid;
572	int pgrp;
573
574	TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
575	    mode));
576	INTOFF;
577	pid = fork();
578	if (pid == -1) {
579		TRACE(("Fork failed, errno=%d\n", errno));
580		INTON;
581		error("Cannot fork");
582	}
583	if (pid == 0) {
584		struct job *p;
585		int wasroot;
586		int i;
587
588		TRACE(("Child shell %d\n", getpid()));
589		wasroot = rootshell;
590		rootshell = 0;
591		for (i = njobs, p = jobtab ; --i >= 0 ; p++)
592			if (p->used)
593				freejob(p);
594		closescript();
595		INTON;
596		clear_traps();
597#if JOBS
598		jobctl = 0;		/* do job control only in root shell */
599		if (wasroot && mode != FORK_NOJOB && mflag) {
600			if (jp == NULL || jp->nprocs == 0)
601				pgrp = getpid();
602			else
603				pgrp = jp->ps[0].pid;
604			if (setpgid(0, pgrp) == 0 && 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	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 (WIFEXITED(status))
719		st = WEXITSTATUS(status);
720#if JOBS
721	else if (WIFSTOPPED(status))
722		st = WSTOPSIG(status) + 128;
723#endif
724	else
725		st = WTERMSIG(status) + 128;
726	if (! JOBS || jp->state == JOBDONE)
727		freejob(jp);
728	CLEAR_PENDING_INT;
729	if (WIFSIGNALED(status) && WTERMSIG(status) == 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	int sig;
755
756	TRACE(("dowait(%d) called\n", block));
757	do {
758		pid = waitproc(block, &status);
759		TRACE(("wait returns %d, status=%d\n", pid, status));
760	} while (pid == -1 && errno == EINTR);
761	if (pid <= 0)
762		return pid;
763	INTOFF;
764	thisjob = NULL;
765	for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
766		if (jp->used) {
767			done = 1;
768			stopped = 1;
769			for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
770				if (sp->pid == -1)
771					continue;
772				if (sp->pid == pid) {
773					TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
774						   pid, sp->status, status));
775					sp->status = status;
776					thisjob = jp;
777				}
778				if (sp->status == -1)
779					stopped = 0;
780				else if (WIFSTOPPED(sp->status))
781					done = 0;
782			}
783			if (stopped) {		/* stopped or done */
784				int state = done? JOBDONE : JOBSTOPPED;
785				if (jp->state != state) {
786					TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
787					jp->state = state;
788#if JOBS
789					if (done && curjob == jp - jobtab + 1)
790						curjob = 0;		/* no current job */
791#endif
792				}
793			}
794		}
795	}
796	INTON;
797	if (! rootshell || ! iflag || (job && thisjob == job)) {
798		core = WCOREDUMP(status);
799#if JOBS
800		if (WIFSTOPPED(status))
801			sig = WSTOPSIG(status);
802		else
803#endif
804			if (WIFEXITED(status))
805				sig = 0;
806			else
807				sig = WTERMSIG(status);
808
809		if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
810			if (thisjob != job)
811				outfmt(out2, "%d: ", pid);
812#if JOBS
813			if (sig == SIGTSTP && rootshell && iflag)
814				outfmt(out2, "%%%d ", job - jobtab + 1);
815#endif
816			if (sig < NSIG && sys_siglist[sig])
817				out2str(sys_siglist[sig]);
818			else
819				outfmt(out2, "Signal %d", sig);
820			if (core)
821				out2str(" - core dumped");
822			out2c('\n');
823			flushout(&errout);
824		} else {
825			TRACE(("Not printing status: status=%d, sig=%d\n",
826				   status, sig));
827		}
828	} else {
829		TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
830		if (thisjob)
831			thisjob->changed = 1;
832	}
833	return pid;
834}
835
836
837
838/*
839 * Do a wait system call.  If job control is compiled in, we accept
840 * stopped processes.  If block is zero, we return a value of zero
841 * rather than blocking.
842 *
843 * System V doesn't have a non-blocking wait system call.  It does
844 * have a SIGCLD signal that is sent to a process when one of it's
845 * children dies.  The obvious way to use SIGCLD would be to install
846 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
847 * was received, and have waitproc bump another counter when it got
848 * the status of a process.  Waitproc would then know that a wait
849 * system call would not block if the two counters were different.
850 * This approach doesn't work because if a process has children that
851 * have not been waited for, System V will send it a SIGCLD when it
852 * installs a signal handler for SIGCLD.  What this means is that when
853 * a child exits, the shell will be sent SIGCLD signals continuously
854 * until is runs out of stack space, unless it does a wait call before
855 * restoring the signal handler.  The code below takes advantage of
856 * this (mis)feature by installing a signal handler for SIGCLD and
857 * then checking to see whether it was called.  If there are any
858 * children to be waited for, it will be.
859 *
860 * If neither SYSV nor BSD is defined, we don't implement nonblocking
861 * waits at all.  In this case, the user will not be informed when
862 * a background process until the next time she runs a real program
863 * (as opposed to running a builtin command or just typing return),
864 * and the jobs command may give out of date information.
865 */
866
867#ifdef SYSV
868STATIC int gotsigchild;
869
870STATIC int onsigchild() {
871	gotsigchild = 1;
872}
873#endif
874
875
876STATIC int
877waitproc(block, status)
878	int block;
879	int *status;
880{
881#ifdef BSD
882	int flags;
883
884#if JOBS
885	flags = WUNTRACED;
886#else
887	flags = 0;
888#endif
889	if (block == 0)
890		flags |= WNOHANG;
891	return wait3(status, flags, (struct rusage *)NULL);
892#else
893#ifdef SYSV
894	int (*save)();
895
896	if (block == 0) {
897		gotsigchild = 0;
898		save = signal(SIGCLD, onsigchild);
899		signal(SIGCLD, save);
900		if (gotsigchild == 0)
901			return 0;
902	}
903	return wait(status);
904#else
905	if (block == 0)
906		return 0;
907	return wait(status);
908#endif
909#endif
910}
911
912/*
913 * return 1 if there are stopped jobs, otherwise 0
914 */
915int job_warning = 0;
916int
917stoppedjobs()
918{
919	int jobno;
920	struct job *jp;
921
922	if (job_warning)
923		return (0);
924	for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
925		if (jp->used == 0)
926			continue;
927		if (jp->state == JOBSTOPPED) {
928			out2str("You have stopped jobs.\n");
929			job_warning = 2;
930			return (1);
931		}
932	}
933
934	return (0);
935}
936
937/*
938 * Return a string identifying a command (to be printed by the
939 * jobs command.
940 */
941
942STATIC char *cmdnextc;
943STATIC int cmdnleft;
944STATIC void cmdtxt(), cmdputs();
945#define MAXCMDTEXT	200
946
947char *
948commandtext(n)
949	union node *n;
950	{
951	char *name;
952
953	cmdnextc = name = ckmalloc(MAXCMDTEXT);
954	cmdnleft = MAXCMDTEXT - 4;
955	cmdtxt(n);
956	*cmdnextc = '\0';
957	return name;
958}
959
960
961STATIC void
962cmdtxt(n)
963	union node *n;
964	{
965	union node *np;
966	struct nodelist *lp;
967	char *p;
968	int i;
969	char s[2];
970
971	if (n == NULL)
972		return;
973	switch (n->type) {
974	case NSEMI:
975		cmdtxt(n->nbinary.ch1);
976		cmdputs("; ");
977		cmdtxt(n->nbinary.ch2);
978		break;
979	case NAND:
980		cmdtxt(n->nbinary.ch1);
981		cmdputs(" && ");
982		cmdtxt(n->nbinary.ch2);
983		break;
984	case NOR:
985		cmdtxt(n->nbinary.ch1);
986		cmdputs(" || ");
987		cmdtxt(n->nbinary.ch2);
988		break;
989	case NPIPE:
990		for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
991			cmdtxt(lp->n);
992			if (lp->next)
993				cmdputs(" | ");
994		}
995		break;
996	case NSUBSHELL:
997		cmdputs("(");
998		cmdtxt(n->nredir.n);
999		cmdputs(")");
1000		break;
1001	case NREDIR:
1002	case NBACKGND:
1003		cmdtxt(n->nredir.n);
1004		break;
1005	case NIF:
1006		cmdputs("if ");
1007		cmdtxt(n->nif.test);
1008		cmdputs("; then ");
1009		cmdtxt(n->nif.ifpart);
1010		cmdputs("...");
1011		break;
1012	case NWHILE:
1013		cmdputs("while ");
1014		goto until;
1015	case NUNTIL:
1016		cmdputs("until ");
1017until:
1018		cmdtxt(n->nbinary.ch1);
1019		cmdputs("; do ");
1020		cmdtxt(n->nbinary.ch2);
1021		cmdputs("; done");
1022		break;
1023	case NFOR:
1024		cmdputs("for ");
1025		cmdputs(n->nfor.var);
1026		cmdputs(" in ...");
1027		break;
1028	case NCASE:
1029		cmdputs("case ");
1030		cmdputs(n->ncase.expr->narg.text);
1031		cmdputs(" in ...");
1032		break;
1033	case NDEFUN:
1034		cmdputs(n->narg.text);
1035		cmdputs("() ...");
1036		break;
1037	case NCMD:
1038		for (np = n->ncmd.args ; np ; np = np->narg.next) {
1039			cmdtxt(np);
1040			if (np->narg.next)
1041				cmdputs(" ");
1042		}
1043		for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
1044			cmdputs(" ");
1045			cmdtxt(np);
1046		}
1047		break;
1048	case NARG:
1049		cmdputs(n->narg.text);
1050		break;
1051	case NTO:
1052		p = ">";  i = 1;  goto redir;
1053	case NAPPEND:
1054		p = ">>";  i = 1;  goto redir;
1055	case NTOFD:
1056		p = ">&";  i = 1;  goto redir;
1057	case NFROM:
1058		p = "<";  i = 0;  goto redir;
1059	case NFROMFD:
1060		p = "<&";  i = 0;  goto redir;
1061redir:
1062		if (n->nfile.fd != i) {
1063			s[0] = n->nfile.fd + '0';
1064			s[1] = '\0';
1065			cmdputs(s);
1066		}
1067		cmdputs(p);
1068		if (n->type == NTOFD || n->type == NFROMFD) {
1069			s[0] = n->ndup.dupfd + '0';
1070			s[1] = '\0';
1071			cmdputs(s);
1072		} else {
1073			cmdtxt(n->nfile.fname);
1074		}
1075		break;
1076	case NHERE:
1077	case NXHERE:
1078		cmdputs("<<...");
1079		break;
1080	default:
1081		cmdputs("???");
1082		break;
1083	}
1084}
1085
1086
1087
1088STATIC void
1089cmdputs(s)
1090	char *s;
1091	{
1092	char *p, *q;
1093	char c;
1094	int subtype = 0;
1095
1096	if (cmdnleft <= 0)
1097		return;
1098	p = s;
1099	q = cmdnextc;
1100	while ((c = *p++) != '\0') {
1101		if (c == CTLESC)
1102			*q++ = *p++;
1103		else if (c == CTLVAR) {
1104			*q++ = '$';
1105			if (--cmdnleft > 0)
1106				*q++ = '{';
1107			subtype = *p++;
1108		} else if (c == '=' && subtype != 0) {
1109			*q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
1110			subtype = 0;
1111		} else if (c == CTLENDVAR) {
1112			*q++ = '}';
1113		} else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
1114			cmdnleft++;		/* ignore it */
1115		else
1116			*q++ = c;
1117		if (--cmdnleft <= 0) {
1118			*q++ = '.';
1119			*q++ = '.';
1120			*q++ = '.';
1121			break;
1122		}
1123	}
1124	cmdnextc = q;
1125}
1126