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