jobs.c revision 97688
1207753Smm/*-
2207753Smm * Copyright (c) 1991, 1993
3207753Smm *	The Regents of the University of California.  All rights reserved.
4207753Smm *
5207753Smm * This code is derived from software contributed to Berkeley by
6207753Smm * Kenneth Almquist.
7207753Smm *
8207753Smm * Redistribution and use in source and binary forms, with or without
9207753Smm * modification, are permitted provided that the following conditions
10207753Smm * are met:
11207753Smm * 1. Redistributions of source code must retain the above copyright
12207753Smm *    notice, this list of conditions and the following disclaimer.
13207753Smm * 2. Redistributions in binary form must reproduce the above copyright
14207753Smm *    notice, this list of conditions and the following disclaimer in the
15207753Smm *    documentation and/or other materials provided with the distribution.
16207753Smm * 3. All advertising materials mentioning features or use of this software
17207753Smm *    must display the following acknowledgement:
18207753Smm *	This product includes software developed by the University of
19207753Smm *	California, Berkeley and its contributors.
20207753Smm * 4. Neither the name of the University nor the names of its contributors
21207753Smm *    may be used to endorse or promote products derived from this software
22207753Smm *    without specific prior written permission.
23207753Smm *
24207753Smm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25207753Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26207753Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27207753Smm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28207753Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29207753Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30207753Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31207753Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32207753Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33207753Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34207753Smm * SUCH DAMAGE.
35207753Smm */
36207753Smm
37207753Smm#ifndef lint
38207753Smm#if 0
39207753Smmstatic char sccsid[] = "@(#)jobs.c	8.5 (Berkeley) 5/4/95";
40207753Smm#endif
41207753Smmstatic const char rcsid[] =
42207753Smm  "$FreeBSD: head/bin/sh/jobs.c 97688 2002-06-01 01:51:42Z tjr $";
43207753Smm#endif /* not lint */
44207753Smm
45207753Smm#include <fcntl.h>
46207753Smm#include <signal.h>
47207753Smm#include <errno.h>
48207753Smm#include <unistd.h>
49207753Smm#include <stdlib.h>
50207753Smm#include <sys/param.h>
51207753Smm#ifdef BSD
52207753Smm#include <sys/wait.h>
53207753Smm#include <sys/time.h>
54207753Smm#include <sys/resource.h>
55207753Smm#include <paths.h>
56207753Smm#endif
57207753Smm#include <sys/ioctl.h>
58
59#include "shell.h"
60#if JOBS
61#if OLD_TTY_DRIVER
62#include "sgtty.h"
63#else
64#include <termios.h>
65#endif
66#undef CEOF			/* syntax.h redefines this */
67#endif
68#include "redir.h"
69#include "show.h"
70#include "main.h"
71#include "parser.h"
72#include "nodes.h"
73#include "jobs.h"
74#include "options.h"
75#include "trap.h"
76#include "syntax.h"
77#include "input.h"
78#include "output.h"
79#include "memalloc.h"
80#include "error.h"
81#include "mystring.h"
82
83
84struct job *jobtab;		/* array of jobs */
85int njobs;			/* size of array */
86MKINIT pid_t backgndpid = -1;	/* pid of last background process */
87#if JOBS
88struct job *jobmru;		/* most recently used job list */
89int initialpgrp;		/* pgrp of shell on invocation */
90#endif
91int in_waitcmd = 0;		/* are we in waitcmd()? */
92int in_dowait = 0;		/* are we in dowait()? */
93volatile sig_atomic_t breakwaitcmd = 0;	/* should wait be terminated? */
94
95#if JOBS
96STATIC void restartjob(struct job *);
97#endif
98STATIC void freejob(struct job *);
99STATIC struct job *getjob(char *);
100STATIC int dowait(int, struct job *);
101#if SYSV
102STATIC int onsigchild(void);
103#endif
104STATIC int waitproc(int, int *);
105STATIC void cmdtxt(union node *);
106STATIC void cmdputs(char *);
107#if JOBS
108STATIC void setcurjob(struct job *);
109STATIC void deljob(struct job *);
110STATIC struct job *getcurjob(struct job *);
111#endif
112STATIC void showjob(struct job *, int, int);
113
114
115/*
116 * Turn job control on and off.
117 *
118 * Note:  This code assumes that the third arg to ioctl is a character
119 * pointer, which is true on Berkeley systems but not System V.  Since
120 * System V doesn't have job control yet, this isn't a problem now.
121 */
122
123MKINIT int jobctl;
124
125#if JOBS
126void
127setjobctl(int on)
128{
129#ifdef OLD_TTY_DRIVER
130	int ldisc;
131#endif
132
133	if (on == jobctl || rootshell == 0)
134		return;
135	if (on) {
136		do { /* while we are in the background */
137#ifdef OLD_TTY_DRIVER
138			if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
139#else
140			initialpgrp = tcgetpgrp(2);
141			if (initialpgrp < 0) {
142#endif
143				out2str("sh: can't access tty; job control turned off\n");
144				mflag = 0;
145				return;
146			}
147			if (initialpgrp == -1)
148				initialpgrp = getpgrp();
149			else if (initialpgrp != getpgrp()) {
150				killpg(initialpgrp, SIGTTIN);
151				continue;
152			}
153		} while (0);
154#ifdef OLD_TTY_DRIVER
155		if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
156			out2str("sh: need new tty driver to run job control; job control turned off\n");
157			mflag = 0;
158			return;
159		}
160#endif
161		setsignal(SIGTSTP);
162		setsignal(SIGTTOU);
163		setsignal(SIGTTIN);
164		setpgid(0, rootpid);
165#ifdef OLD_TTY_DRIVER
166		ioctl(2, TIOCSPGRP, (char *)&rootpid);
167#else
168		tcsetpgrp(2, rootpid);
169#endif
170	} else { /* turning job control off */
171		setpgid(0, initialpgrp);
172#ifdef OLD_TTY_DRIVER
173		ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
174#else
175		tcsetpgrp(2, initialpgrp);
176#endif
177		setsignal(SIGTSTP);
178		setsignal(SIGTTOU);
179		setsignal(SIGTTIN);
180	}
181	jobctl = on;
182}
183#endif
184
185
186#ifdef mkinit
187INCLUDE <sys/types.h>
188INCLUDE <stdlib.h>
189
190SHELLPROC {
191	backgndpid = -1;
192#if JOBS
193	jobctl = 0;
194#endif
195}
196
197#endif
198
199
200
201#if JOBS
202int
203fgcmd(int argc __unused, char **argv)
204{
205	struct job *jp;
206	int pgrp;
207	int status;
208
209	jp = getjob(argv[1]);
210	if (jp->jobctl == 0)
211		error("job not created under job control");
212	out1str(jp->ps[0].cmd);
213	out1c('\n');
214	flushout(&output);
215	pgrp = jp->ps[0].pid;
216#ifdef OLD_TTY_DRIVER
217	ioctl(2, TIOCSPGRP, (char *)&pgrp);
218#else
219	tcsetpgrp(2, pgrp);
220#endif
221	restartjob(jp);
222	INTOFF;
223	status = waitforjob(jp, (int *)NULL);
224	INTON;
225	return status;
226}
227
228
229int
230bgcmd(int argc, char **argv)
231{
232	char s[64];
233	struct job *jp;
234
235	do {
236		jp = getjob(*++argv);
237		if (jp->jobctl == 0)
238			error("job not created under job control");
239		if (jp->state == JOBDONE)
240			continue;
241		restartjob(jp);
242		fmtstr(s, 64, "[%d] ", jp - jobtab + 1);
243		out1str(s);
244		out1str(jp->ps[0].cmd);
245		out1c('\n');
246	} while (--argc > 1);
247	return 0;
248}
249
250
251STATIC void
252restartjob(struct job *jp)
253{
254	struct procstat *ps;
255	int i;
256
257	if (jp->state == JOBDONE)
258		return;
259	setcurjob(jp);
260	INTOFF;
261	killpg(jp->ps[0].pid, SIGCONT);
262	for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
263		if (WIFSTOPPED(ps->status)) {
264			ps->status = -1;
265			jp->state = 0;
266		}
267	}
268	INTON;
269}
270#endif
271
272
273int
274jobscmd(int argc, char *argv[])
275{
276	struct job *jp;
277	char *id;
278	int ch, sformat, lformat;
279
280	optind = optreset = 1;
281	sformat = lformat = 0;
282	while ((ch = getopt(argc, argv, "ls")) != -1) {
283		switch (ch) {
284		case 'l':
285			lformat = 1;
286			break;
287		case 's':
288			sformat = 1;
289			break;
290		case '?':
291		default:
292			error("unknown option: -%c", optopt);
293		}
294	}
295	argc -= optind;
296	argv += optind;
297
298	if (argc == 0)
299		showjobs(0, sformat, lformat);
300	else
301		while ((id = *argv++) != NULL)
302			showjob(getjob(id), sformat, lformat);
303
304	return (0);
305}
306
307STATIC void
308showjob(struct job *jp, int sformat, int lformat)
309{
310	char s[64];
311	struct procstat *ps;
312	struct job *j;
313	int col, curr, i, jobno, prev, procno;
314	char c;
315
316	procno = jp->nprocs;
317	jobno = jp - jobtab + 1;
318	curr = prev = 0;
319#if JOBS
320	if ((j = getcurjob(NULL)) != NULL) {
321		curr = j - jobtab + 1;
322		if ((j = getcurjob(j)) != NULL)
323			prev = j - jobtab + 1;
324	}
325#endif
326	for (ps = jp->ps ; ; ps++) {	/* for each process */
327		if (sformat) {
328			out1fmt("%d\n", ps->pid);
329			goto skip;
330		}
331		if (!lformat && ps != jp->ps)
332			goto skip;
333		if (jobno == curr)
334			c = '+';
335		else if (jobno == prev)
336			c = '-';
337		else
338			c = ' ';
339		if (ps == jp->ps)
340			fmtstr(s, 64, "[%d] %c ", jobno, c);
341		else
342			fmtstr(s, 64, "     %c ", c);
343		out1str(s);
344		col = strlen(s);
345		if (lformat) {
346			fmtstr(s, 64, "%d ", ps->pid);
347			out1str(s);
348			col += strlen(s);
349		}
350		s[0] = '\0';
351		if (ps->status == -1) {
352			strcpy(s, "Running");
353		} else if (WIFEXITED(ps->status)) {
354			fmtstr(s, 64, "Exit %d", WEXITSTATUS(ps->status));
355		} else {
356#if JOBS
357			if (WIFSTOPPED(ps->status))
358				i = WSTOPSIG(ps->status);
359			else
360#endif
361				i = WTERMSIG(ps->status);
362			if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
363				scopy(sys_siglist[i & 0x7F], s);
364			else
365				fmtstr(s, 64, "Signal %d", i & 0x7F);
366			if (WCOREDUMP(ps->status))
367				strcat(s, " (core dumped)");
368		}
369		out1str(s);
370		col += strlen(s);
371		do {
372			out1c(' ');
373			col++;
374		} while (col < 30);
375		out1str(ps->cmd);
376		out1c('\n');
377skip:		if (--procno <= 0)
378			break;
379	}
380}
381
382/*
383 * Print a list of jobs.  If "change" is nonzero, only print jobs whose
384 * statuses have changed since the last call to showjobs.
385 *
386 * If the shell is interrupted in the process of creating a job, the
387 * result may be a job structure containing zero processes.  Such structures
388 * will be freed here.
389 */
390
391void
392showjobs(int change, int sformat, int lformat)
393{
394	int jobno;
395	struct job *jp;
396
397	TRACE(("showjobs(%d) called\n", change));
398	while (dowait(0, (struct job *)NULL) > 0);
399	for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
400		if (! jp->used)
401			continue;
402		if (jp->nprocs == 0) {
403			freejob(jp);
404			continue;
405		}
406		if (change && ! jp->changed)
407			continue;
408		showjob(jp, sformat, lformat);
409		jp->changed = 0;
410		if (jp->state == JOBDONE) {
411			freejob(jp);
412		}
413	}
414}
415
416
417/*
418 * Mark a job structure as unused.
419 */
420
421STATIC void
422freejob(struct job *jp)
423{
424	struct procstat *ps;
425	int i;
426
427	INTOFF;
428	for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
429		if (ps->cmd != nullstr)
430			ckfree(ps->cmd);
431	}
432	if (jp->ps != &jp->ps0)
433		ckfree(jp->ps);
434	jp->used = 0;
435#if JOBS
436	deljob(jp);
437#endif
438	INTON;
439}
440
441
442
443int
444waitcmd(int argc, char **argv)
445{
446	struct job *job;
447	int status, retval;
448	struct job *jp;
449
450	if (argc > 1) {
451		job = getjob(argv[1]);
452	} else {
453		job = NULL;
454	}
455
456	/*
457	 * Loop until a process is terminated or stopped, or a SIGINT is
458	 * received.
459	 */
460
461	in_waitcmd++;
462	do {
463		if (job != NULL) {
464			if (job->state) {
465				status = job->ps[job->nprocs - 1].status;
466				if (WIFEXITED(status))
467					retval = WEXITSTATUS(status);
468#if JOBS
469				else if (WIFSTOPPED(status))
470					retval = WSTOPSIG(status) + 128;
471#endif
472				else
473					retval = WTERMSIG(status) + 128;
474				if (! iflag)
475					freejob(job);
476				in_waitcmd--;
477				return retval;
478			}
479		} else {
480			for (jp = jobtab ; ; jp++) {
481				if (jp >= jobtab + njobs) {	/* no running procs */
482					in_waitcmd--;
483					return 0;
484				}
485				if (jp->used && jp->state == 0)
486					break;
487			}
488		}
489	} while (dowait(1, (struct job *)NULL) != -1);
490	in_waitcmd--;
491
492	return 0;
493}
494
495
496
497int
498jobidcmd(int argc __unused, char **argv)
499{
500	struct job *jp;
501	int i;
502
503	jp = getjob(argv[1]);
504	for (i = 0 ; i < jp->nprocs ; ) {
505		out1fmt("%d", jp->ps[i].pid);
506		out1c(++i < jp->nprocs? ' ' : '\n');
507	}
508	return 0;
509}
510
511
512
513/*
514 * Convert a job name to a job structure.
515 */
516
517STATIC struct job *
518getjob(char *name)
519{
520	int jobno;
521	struct job *found, *jp;
522	int pid;
523	int i;
524
525	if (name == NULL) {
526#if JOBS
527currentjob:	if ((jp = getcurjob(NULL)) == NULL)
528			error("No current job");
529		return (jp);
530#else
531		error("No current job");
532#endif
533	} else if (name[0] == '%') {
534		if (is_digit(name[1])) {
535			jobno = number(name + 1);
536			if (jobno > 0 && jobno <= njobs
537			 && jobtab[jobno - 1].used != 0)
538				return &jobtab[jobno - 1];
539#if JOBS
540		} else if (name[1] == '%' && name[2] == '\0') {
541			goto currentjob;
542		} else if (name[1] == '+' && name[2] == '\0') {
543			goto currentjob;
544		} else if (name[1] == '-' && name[2] == '\0') {
545			if ((jp = getcurjob(NULL)) == NULL ||
546			    (jp = getcurjob(jp)) == NULL)
547				error("No previous job");
548			return (jp);
549#endif
550		} else if (name[1] == '?') {
551			found = NULL;
552			for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
553				if (jp->used && jp->nprocs > 0
554				 && strstr(jp->ps[0].cmd, name + 2) != NULL) {
555					if (found)
556						error("%s: ambiguous", name);
557					found = jp;
558				}
559			}
560			if (found != NULL)
561				return (found);
562		} else {
563			found = NULL;
564			for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
565				if (jp->used && jp->nprocs > 0
566				 && prefix(name + 1, jp->ps[0].cmd)) {
567					if (found)
568						error("%s: ambiguous", name);
569					found = jp;
570				}
571			}
572			if (found)
573				return found;
574		}
575	} else if (is_number(name)) {
576		pid = number(name);
577		for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
578			if (jp->used && jp->nprocs > 0
579			 && jp->ps[jp->nprocs - 1].pid == pid)
580				return jp;
581		}
582	}
583	error("No such job: %s", name);
584	/*NOTREACHED*/
585	return NULL;
586}
587
588
589
590/*
591 * Return a new job structure,
592 */
593
594struct job *
595makejob(union node *node __unused, int nprocs)
596{
597	int i;
598	struct job *jp;
599
600	for (i = njobs, jp = jobtab ; ; jp++) {
601		if (--i < 0) {
602			INTOFF;
603			if (njobs == 0) {
604				jobtab = ckmalloc(4 * sizeof jobtab[0]);
605#if JOBS
606				jobmru = NULL;
607#endif
608			} else {
609				jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
610				memcpy(jp, jobtab, njobs * sizeof jp[0]);
611#if JOBS
612				/* Relocate `next' pointers and list head */
613				jobmru = &jp[jobmru - jobtab];
614				for (i = 0; i < njobs; i++)
615					if (jp[i].next != NULL)
616						jp[i].next = &jp[jp[i].next -
617						    jobtab];
618#endif
619				/* Relocate `ps' pointers */
620				for (i = 0; i < njobs; i++)
621					if (jp[i].ps == &jobtab[i].ps0)
622						jp[i].ps = &jp[i].ps0;
623				ckfree(jobtab);
624				jobtab = jp;
625			}
626			jp = jobtab + njobs;
627			for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
628			INTON;
629			break;
630		}
631		if (jp->used == 0)
632			break;
633	}
634	INTOFF;
635	jp->state = 0;
636	jp->used = 1;
637	jp->changed = 0;
638	jp->nprocs = 0;
639#if JOBS
640	jp->jobctl = jobctl;
641	jp->next = NULL;
642#endif
643	if (nprocs > 1) {
644		jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
645	} else {
646		jp->ps = &jp->ps0;
647	}
648	INTON;
649	TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
650	    jp - jobtab + 1));
651	return jp;
652}
653
654#if JOBS
655STATIC void
656setcurjob(struct job *cj)
657{
658	struct job *jp, *prev;
659
660	for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
661		if (jp == cj) {
662			if (prev != NULL)
663				prev->next = jp->next;
664			else
665				jobmru = jp->next;
666			jp->next = jobmru;
667			jobmru = cj;
668			return;
669		}
670	}
671	cj->next = jobmru;
672	jobmru = cj;
673}
674
675STATIC void
676deljob(struct job *j)
677{
678	struct job *jp, *prev;
679
680	for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
681		if (jp == j) {
682			if (prev != NULL)
683				prev->next = jp->next;
684			else
685				jobmru = jp->next;
686			return;
687		}
688	}
689}
690
691/*
692 * Return the most recently used job that isn't `nj', and preferably one
693 * that is stopped.
694 */
695STATIC struct job *
696getcurjob(struct job *nj)
697{
698	struct job *jp;
699
700	/* Try to find a stopped one.. */
701	for (jp = jobmru; jp != NULL; jp = jp->next)
702		if (jp->used && jp != nj && jp->state == JOBSTOPPED)
703			return (jp);
704	/* Otherwise the most recently used job that isn't `nj' */
705	for (jp = jobmru; jp != NULL; jp = jp->next)
706		if (jp->used && jp != nj)
707			return (jp);
708
709	return (NULL);
710}
711
712#endif
713
714/*
715 * Fork of a subshell.  If we are doing job control, give the subshell its
716 * own process group.  Jp is a job structure that the job is to be added to.
717 * N is the command that will be evaluated by the child.  Both jp and n may
718 * be NULL.  The mode parameter can be one of the following:
719 *	FORK_FG - Fork off a foreground process.
720 *	FORK_BG - Fork off a background process.
721 *	FORK_NOJOB - Like FORK_FG, but don't give the process its own
722 *		     process group even if job control is on.
723 *
724 * When job control is turned off, background processes have their standard
725 * input redirected to /dev/null (except for the second and later processes
726 * in a pipeline).
727 */
728
729int
730forkshell(struct job *jp, union node *n, int mode)
731{
732	int pid;
733	int pgrp;
734
735	TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
736	    mode));
737	INTOFF;
738	pid = fork();
739	if (pid == -1) {
740		TRACE(("Fork failed, errno=%d\n", errno));
741		INTON;
742		error("Cannot fork: %s", strerror(errno));
743	}
744	if (pid == 0) {
745		struct job *p;
746		int wasroot;
747		int i;
748
749		TRACE(("Child shell %d\n", getpid()));
750		wasroot = rootshell;
751		rootshell = 0;
752		for (i = njobs, p = jobtab ; --i >= 0 ; p++)
753			if (p->used)
754				freejob(p);
755		closescript();
756		INTON;
757		clear_traps();
758#if JOBS
759		jobctl = 0;		/* do job control only in root shell */
760		if (wasroot && mode != FORK_NOJOB && mflag) {
761			if (jp == NULL || jp->nprocs == 0)
762				pgrp = getpid();
763			else
764				pgrp = jp->ps[0].pid;
765			if (setpgid(0, pgrp) == 0 && mode == FORK_FG) {
766				/*** this causes superfluous TIOCSPGRPS ***/
767#ifdef OLD_TTY_DRIVER
768				if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
769					error("TIOCSPGRP failed, errno=%d", errno);
770#else
771				if (tcsetpgrp(2, pgrp) < 0)
772					error("tcsetpgrp failed, errno=%d", errno);
773#endif
774			}
775			setsignal(SIGTSTP);
776			setsignal(SIGTTOU);
777		} else if (mode == FORK_BG) {
778			ignoresig(SIGINT);
779			ignoresig(SIGQUIT);
780			if ((jp == NULL || jp->nprocs == 0) &&
781			    ! fd0_redirected_p ()) {
782				close(0);
783				if (open(_PATH_DEVNULL, O_RDONLY) != 0)
784					error("Can't open %s: %s",
785					    _PATH_DEVNULL, strerror(errno));
786			}
787		}
788#else
789		if (mode == FORK_BG) {
790			ignoresig(SIGINT);
791			ignoresig(SIGQUIT);
792			if ((jp == NULL || jp->nprocs == 0) &&
793			    ! fd0_redirected_p ()) {
794				close(0);
795				if (open(_PATH_DEVNULL, O_RDONLY) != 0)
796					error("Can't open %s: %s",
797					    _PATH_DEVNULL, strerror(errno));
798			}
799		}
800#endif
801		if (wasroot && iflag) {
802			setsignal(SIGINT);
803			setsignal(SIGQUIT);
804			setsignal(SIGTERM);
805		}
806		return pid;
807	}
808	if (rootshell && mode != FORK_NOJOB && mflag) {
809		if (jp == NULL || jp->nprocs == 0)
810			pgrp = pid;
811		else
812			pgrp = jp->ps[0].pid;
813		setpgid(pid, pgrp);
814	}
815	if (mode == FORK_BG)
816		backgndpid = pid;		/* set $! */
817	if (jp) {
818		struct procstat *ps = &jp->ps[jp->nprocs++];
819		ps->pid = pid;
820		ps->status = -1;
821		ps->cmd = nullstr;
822		if (iflag && rootshell && n)
823			ps->cmd = commandtext(n);
824#if JOBS
825		setcurjob(jp);
826#endif
827	}
828	INTON;
829	TRACE(("In parent shell:  child = %d\n", pid));
830	return pid;
831}
832
833
834
835/*
836 * Wait for job to finish.
837 *
838 * Under job control we have the problem that while a child process is
839 * running interrupts generated by the user are sent to the child but not
840 * to the shell.  This means that an infinite loop started by an inter-
841 * active user may be hard to kill.  With job control turned off, an
842 * interactive user may place an interactive program inside a loop.  If
843 * the interactive program catches interrupts, the user doesn't want
844 * these interrupts to also abort the loop.  The approach we take here
845 * is to have the shell ignore interrupt signals while waiting for a
846 * foreground process to terminate, and then send itself an interrupt
847 * signal if the child process was terminated by an interrupt signal.
848 * Unfortunately, some programs want to do a bit of cleanup and then
849 * exit on interrupt; unless these processes terminate themselves by
850 * sending a signal to themselves (instead of calling exit) they will
851 * confuse this approach.
852 */
853
854int
855waitforjob(struct job *jp, int *origstatus)
856{
857#if JOBS
858	int mypgrp = getpgrp();
859#endif
860	int status;
861	int st;
862
863	INTOFF;
864	TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
865	while (jp->state == 0)
866		if (dowait(1, jp) == -1)
867			dotrap();
868#if JOBS
869	if (jp->jobctl) {
870#ifdef OLD_TTY_DRIVER
871		if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
872			error("TIOCSPGRP failed, errno=%d\n", errno);
873#else
874		if (tcsetpgrp(2, mypgrp) < 0)
875			error("tcsetpgrp failed, errno=%d\n", errno);
876#endif
877	}
878	if (jp->state == JOBSTOPPED)
879		setcurjob(jp);
880#endif
881	status = jp->ps[jp->nprocs - 1].status;
882	if (origstatus != NULL)
883		*origstatus = status;
884	/* convert to 8 bits */
885	if (WIFEXITED(status))
886		st = WEXITSTATUS(status);
887#if JOBS
888	else if (WIFSTOPPED(status))
889		st = WSTOPSIG(status) + 128;
890#endif
891	else
892		st = WTERMSIG(status) + 128;
893	if (! JOBS || jp->state == JOBDONE)
894		freejob(jp);
895	if (int_pending()) {
896		if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
897			kill(getpid(), SIGINT);
898		else
899			CLEAR_PENDING_INT;
900	}
901	INTON;
902	return st;
903}
904
905
906
907/*
908 * Wait for a process to terminate.
909 */
910
911STATIC int
912dowait(int block, struct job *job)
913{
914	int pid;
915	int status;
916	struct procstat *sp;
917	struct job *jp;
918	struct job *thisjob;
919	int done;
920	int stopped;
921	int core;
922	int sig;
923
924	in_dowait++;
925	TRACE(("dowait(%d) called\n", block));
926	do {
927		pid = waitproc(block, &status);
928		TRACE(("wait returns %d, status=%d\n", pid, status));
929	} while ((pid == -1 && errno == EINTR && breakwaitcmd == 0) ||
930	    (WIFSTOPPED(status) && !iflag));
931	in_dowait--;
932	if (breakwaitcmd != 0) {
933		breakwaitcmd = 0;
934		return -1;
935	}
936	if (pid <= 0)
937		return pid;
938	INTOFF;
939	thisjob = NULL;
940	for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
941		if (jp->used) {
942			done = 1;
943			stopped = 1;
944			for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
945				if (sp->pid == -1)
946					continue;
947				if (sp->pid == pid) {
948					TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
949						   pid, sp->status, status));
950					sp->status = status;
951					thisjob = jp;
952				}
953				if (sp->status == -1)
954					stopped = 0;
955				else if (WIFSTOPPED(sp->status))
956					done = 0;
957			}
958			if (stopped) {		/* stopped or done */
959				int state = done? JOBDONE : JOBSTOPPED;
960				if (jp->state != state) {
961					TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
962					jp->state = state;
963#if JOBS
964					if (done)
965						deljob(jp);
966#endif
967				}
968			}
969		}
970	}
971	INTON;
972	if (! rootshell || ! iflag || (job && thisjob == job)) {
973#if JOBS
974		if (WIFSTOPPED(status))
975			sig = WSTOPSIG(status);
976		else
977#endif
978		{
979			if (WIFEXITED(status))
980				sig = 0;
981			else
982				sig = WTERMSIG(status);
983		}
984		if (sig != 0 && sig != SIGINT && sig != SIGPIPE)
985			showjob(thisjob, 0, 0);
986	} else {
987		TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
988		if (thisjob)
989			thisjob->changed = 1;
990	}
991	return pid;
992}
993
994
995
996/*
997 * Do a wait system call.  If job control is compiled in, we accept
998 * stopped processes.  If block is zero, we return a value of zero
999 * rather than blocking.
1000 *
1001 * System V doesn't have a non-blocking wait system call.  It does
1002 * have a SIGCLD signal that is sent to a process when one of it's
1003 * children dies.  The obvious way to use SIGCLD would be to install
1004 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
1005 * was received, and have waitproc bump another counter when it got
1006 * the status of a process.  Waitproc would then know that a wait
1007 * system call would not block if the two counters were different.
1008 * This approach doesn't work because if a process has children that
1009 * have not been waited for, System V will send it a SIGCLD when it
1010 * installs a signal handler for SIGCLD.  What this means is that when
1011 * a child exits, the shell will be sent SIGCLD signals continuously
1012 * until is runs out of stack space, unless it does a wait call before
1013 * restoring the signal handler.  The code below takes advantage of
1014 * this (mis)feature by installing a signal handler for SIGCLD and
1015 * then checking to see whether it was called.  If there are any
1016 * children to be waited for, it will be.
1017 *
1018 * If neither SYSV nor BSD is defined, we don't implement nonblocking
1019 * waits at all.  In this case, the user will not be informed when
1020 * a background process until the next time she runs a real program
1021 * (as opposed to running a builtin command or just typing return),
1022 * and the jobs command may give out of date information.
1023 */
1024
1025#ifdef SYSV
1026STATIC sig_atomic_t gotsigchild;
1027
1028STATIC int onsigchild() {
1029	gotsigchild = 1;
1030}
1031#endif
1032
1033
1034STATIC int
1035waitproc(int block, int *status)
1036{
1037#ifdef BSD
1038	int flags;
1039
1040#if JOBS
1041	flags = WUNTRACED;
1042#else
1043	flags = 0;
1044#endif
1045	if (block == 0)
1046		flags |= WNOHANG;
1047	return wait3(status, flags, (struct rusage *)NULL);
1048#else
1049#ifdef SYSV
1050	int (*save)();
1051
1052	if (block == 0) {
1053		gotsigchild = 0;
1054		save = signal(SIGCLD, onsigchild);
1055		signal(SIGCLD, save);
1056		if (gotsigchild == 0)
1057			return 0;
1058	}
1059	return wait(status);
1060#else
1061	if (block == 0)
1062		return 0;
1063	return wait(status);
1064#endif
1065#endif
1066}
1067
1068/*
1069 * return 1 if there are stopped jobs, otherwise 0
1070 */
1071int job_warning = 0;
1072int
1073stoppedjobs(void)
1074{
1075	int jobno;
1076	struct job *jp;
1077
1078	if (job_warning)
1079		return (0);
1080	for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
1081		if (jp->used == 0)
1082			continue;
1083		if (jp->state == JOBSTOPPED) {
1084			out2str("You have stopped jobs.\n");
1085			job_warning = 2;
1086			return (1);
1087		}
1088	}
1089
1090	return (0);
1091}
1092
1093/*
1094 * Return a string identifying a command (to be printed by the
1095 * jobs command.
1096 */
1097
1098STATIC char *cmdnextc;
1099STATIC int cmdnleft;
1100#define MAXCMDTEXT	200
1101
1102char *
1103commandtext(union node *n)
1104{
1105	char *name;
1106
1107	cmdnextc = name = ckmalloc(MAXCMDTEXT);
1108	cmdnleft = MAXCMDTEXT - 4;
1109	cmdtxt(n);
1110	*cmdnextc = '\0';
1111	return name;
1112}
1113
1114
1115STATIC void
1116cmdtxt(union node *n)
1117{
1118	union node *np;
1119	struct nodelist *lp;
1120	char *p;
1121	int i;
1122	char s[2];
1123
1124	if (n == NULL)
1125		return;
1126	switch (n->type) {
1127	case NSEMI:
1128		cmdtxt(n->nbinary.ch1);
1129		cmdputs("; ");
1130		cmdtxt(n->nbinary.ch2);
1131		break;
1132	case NAND:
1133		cmdtxt(n->nbinary.ch1);
1134		cmdputs(" && ");
1135		cmdtxt(n->nbinary.ch2);
1136		break;
1137	case NOR:
1138		cmdtxt(n->nbinary.ch1);
1139		cmdputs(" || ");
1140		cmdtxt(n->nbinary.ch2);
1141		break;
1142	case NPIPE:
1143		for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1144			cmdtxt(lp->n);
1145			if (lp->next)
1146				cmdputs(" | ");
1147		}
1148		break;
1149	case NSUBSHELL:
1150		cmdputs("(");
1151		cmdtxt(n->nredir.n);
1152		cmdputs(")");
1153		break;
1154	case NREDIR:
1155	case NBACKGND:
1156		cmdtxt(n->nredir.n);
1157		break;
1158	case NIF:
1159		cmdputs("if ");
1160		cmdtxt(n->nif.test);
1161		cmdputs("; then ");
1162		cmdtxt(n->nif.ifpart);
1163		cmdputs("...");
1164		break;
1165	case NWHILE:
1166		cmdputs("while ");
1167		goto until;
1168	case NUNTIL:
1169		cmdputs("until ");
1170until:
1171		cmdtxt(n->nbinary.ch1);
1172		cmdputs("; do ");
1173		cmdtxt(n->nbinary.ch2);
1174		cmdputs("; done");
1175		break;
1176	case NFOR:
1177		cmdputs("for ");
1178		cmdputs(n->nfor.var);
1179		cmdputs(" in ...");
1180		break;
1181	case NCASE:
1182		cmdputs("case ");
1183		cmdputs(n->ncase.expr->narg.text);
1184		cmdputs(" in ...");
1185		break;
1186	case NDEFUN:
1187		cmdputs(n->narg.text);
1188		cmdputs("() ...");
1189		break;
1190	case NCMD:
1191		for (np = n->ncmd.args ; np ; np = np->narg.next) {
1192			cmdtxt(np);
1193			if (np->narg.next)
1194				cmdputs(" ");
1195		}
1196		for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
1197			cmdputs(" ");
1198			cmdtxt(np);
1199		}
1200		break;
1201	case NARG:
1202		cmdputs(n->narg.text);
1203		break;
1204	case NTO:
1205		p = ">";  i = 1;  goto redir;
1206	case NAPPEND:
1207		p = ">>";  i = 1;  goto redir;
1208	case NTOFD:
1209		p = ">&";  i = 1;  goto redir;
1210	case NCLOBBER:
1211		p = ">|"; i = 1; goto redir;
1212	case NFROM:
1213		p = "<";  i = 0;  goto redir;
1214	case NFROMTO:
1215		p = "<>";  i = 0;  goto redir;
1216	case NFROMFD:
1217		p = "<&";  i = 0;  goto redir;
1218redir:
1219		if (n->nfile.fd != i) {
1220			s[0] = n->nfile.fd + '0';
1221			s[1] = '\0';
1222			cmdputs(s);
1223		}
1224		cmdputs(p);
1225		if (n->type == NTOFD || n->type == NFROMFD) {
1226			s[0] = n->ndup.dupfd + '0';
1227			s[1] = '\0';
1228			cmdputs(s);
1229		} else {
1230			cmdtxt(n->nfile.fname);
1231		}
1232		break;
1233	case NHERE:
1234	case NXHERE:
1235		cmdputs("<<...");
1236		break;
1237	default:
1238		cmdputs("???");
1239		break;
1240	}
1241}
1242
1243
1244
1245STATIC void
1246cmdputs(char *s)
1247{
1248	char *p, *q;
1249	char c;
1250	int subtype = 0;
1251
1252	if (cmdnleft <= 0)
1253		return;
1254	p = s;
1255	q = cmdnextc;
1256	while ((c = *p++) != '\0') {
1257		if (c == CTLESC)
1258			*q++ = *p++;
1259		else if (c == CTLVAR) {
1260			*q++ = '$';
1261			if (--cmdnleft > 0)
1262				*q++ = '{';
1263			subtype = *p++;
1264		} else if (c == '=' && subtype != 0) {
1265			*q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
1266			subtype = 0;
1267		} else if (c == CTLENDVAR) {
1268			*q++ = '}';
1269		} else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
1270			cmdnleft++;		/* ignore it */
1271		else
1272			*q++ = c;
1273		if (--cmdnleft <= 0) {
1274			*q++ = '.';
1275			*q++ = '.';
1276			*q++ = '.';
1277			break;
1278		}
1279	}
1280	cmdnextc = q;
1281}
1282