xref: /illumos-gate/usr/src/cmd/sh/jobs.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
24*7c478bd9Sstevel@tonic-gate 
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate /*
27*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1996, by Sun Microsystems, Inc.
28*7c478bd9Sstevel@tonic-gate  * All rights reserved.
29*7c478bd9Sstevel@tonic-gate  */
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*7c478bd9Sstevel@tonic-gate /*
33*7c478bd9Sstevel@tonic-gate  * Job control for UNIX Shell
34*7c478bd9Sstevel@tonic-gate  */
35*7c478bd9Sstevel@tonic-gate 
36*7c478bd9Sstevel@tonic-gate #include	<sys/termio.h>
37*7c478bd9Sstevel@tonic-gate #include	<sys/types.h>
38*7c478bd9Sstevel@tonic-gate #include	<sys/wait.h>
39*7c478bd9Sstevel@tonic-gate #include	<sys/param.h>
40*7c478bd9Sstevel@tonic-gate #include	<fcntl.h>
41*7c478bd9Sstevel@tonic-gate #include	<errno.h>
42*7c478bd9Sstevel@tonic-gate #include	"defs.h"
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate /*
45*7c478bd9Sstevel@tonic-gate  * one of these for each active job
46*7c478bd9Sstevel@tonic-gate  */
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate struct job
49*7c478bd9Sstevel@tonic-gate {
50*7c478bd9Sstevel@tonic-gate 	struct job *j_nxtp;	/* next job in job ID order */
51*7c478bd9Sstevel@tonic-gate 	struct job *j_curp;	/* next job in job currency order */
52*7c478bd9Sstevel@tonic-gate 	struct termios j_stty;	/* termio save area when job stops */
53*7c478bd9Sstevel@tonic-gate 	pid_t  j_pid;		/* job leader's process ID */
54*7c478bd9Sstevel@tonic-gate 	pid_t  j_pgid;		/* job's process group ID */
55*7c478bd9Sstevel@tonic-gate 	pid_t  j_tgid;		/* job's foreground process group ID */
56*7c478bd9Sstevel@tonic-gate 	uint   j_jid;		/* job ID */
57*7c478bd9Sstevel@tonic-gate 	ushort j_xval;		/* exit code, or exit or stop signal */
58*7c478bd9Sstevel@tonic-gate 	ushort j_flag;		/* various status flags defined below */
59*7c478bd9Sstevel@tonic-gate 	char  *j_pwd;		/* job's working directory */
60*7c478bd9Sstevel@tonic-gate 	char  *j_cmd;		/* cmd used to invoke this job */
61*7c478bd9Sstevel@tonic-gate };
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate /* defines for j_flag */
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate #define	J_DUMPED	0001	/* job has core dumped */
66*7c478bd9Sstevel@tonic-gate #define	J_NOTIFY	0002	/* job has changed status */
67*7c478bd9Sstevel@tonic-gate #define	J_SAVETTY	0004	/* job was stopped in foreground, and its */
68*7c478bd9Sstevel@tonic-gate 				/*   termio settings were saved */
69*7c478bd9Sstevel@tonic-gate #define	J_STOPPED	0010	/* job has been stopped */
70*7c478bd9Sstevel@tonic-gate #define	J_SIGNALED	0020	/* job has received signal; j_xval has it */
71*7c478bd9Sstevel@tonic-gate #define	J_DONE		0040	/* job has finished */
72*7c478bd9Sstevel@tonic-gate #define	J_RUNNING	0100	/* job is currently running */
73*7c478bd9Sstevel@tonic-gate #define	J_FOREGND	0200	/* job was put in foreground by shell */
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate /* options to the printjob() function defined below */
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate #define	PR_CUR		00001	/* print job currency ('+', '-', or ' ') */
78*7c478bd9Sstevel@tonic-gate #define	PR_JID		00002	/* print job ID				 */
79*7c478bd9Sstevel@tonic-gate #define	PR_PGID		00004	/* print job's process group ID		 */
80*7c478bd9Sstevel@tonic-gate #define	PR_STAT		00010	/* print status obtained from wait	 */
81*7c478bd9Sstevel@tonic-gate #define	PR_CMD		00020	/* print cmd that invoked job		 */
82*7c478bd9Sstevel@tonic-gate #define	PR_AMP		00040	/* print a '&' if in the background	 */
83*7c478bd9Sstevel@tonic-gate #define	PR_PWD		00100	/* print jobs present working directory	 */
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate #define	PR_DFL		(PR_CUR|PR_JID|PR_STAT|PR_CMD) /* default options */
86*7c478bd9Sstevel@tonic-gate #define	PR_LONG		(PR_DFL|PR_PGID|PR_PWD)	/* long options */
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate static struct termios 	mystty;	 /* default termio settings		 */
89*7c478bd9Sstevel@tonic-gate static int 		eofflg,
90*7c478bd9Sstevel@tonic-gate 			jobcnt,	 /* number of active jobs		 */
91*7c478bd9Sstevel@tonic-gate 			jobdone, /* number of active but finished jobs	 */
92*7c478bd9Sstevel@tonic-gate 			jobnote; /* jobs requiring notification		 */
93*7c478bd9Sstevel@tonic-gate static pid_t		svpgid,	 /* saved process group ID		 */
94*7c478bd9Sstevel@tonic-gate 			svtgid;	 /* saved foreground process group ID	 */
95*7c478bd9Sstevel@tonic-gate static struct job 	*jobcur, /* active jobs listed in currency order */
96*7c478bd9Sstevel@tonic-gate 			**nextjob,
97*7c478bd9Sstevel@tonic-gate 			*thisjob,
98*7c478bd9Sstevel@tonic-gate 			*joblst; /* active jobs listed in job ID order	 */
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate pid_t
101*7c478bd9Sstevel@tonic-gate tcgetpgrp(fd)
102*7c478bd9Sstevel@tonic-gate {
103*7c478bd9Sstevel@tonic-gate 	pid_t pgid;
104*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, TIOCGPGRP, &pgid) == 0)
105*7c478bd9Sstevel@tonic-gate 		return (pgid);
106*7c478bd9Sstevel@tonic-gate 	return ((pid_t)-1);
107*7c478bd9Sstevel@tonic-gate }
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate int
110*7c478bd9Sstevel@tonic-gate tcsetpgrp(fd, pgid)
111*7c478bd9Sstevel@tonic-gate int fd;
112*7c478bd9Sstevel@tonic-gate pid_t pgid;
113*7c478bd9Sstevel@tonic-gate {
114*7c478bd9Sstevel@tonic-gate 	return (ioctl(fd, TIOCSPGRP, &pgid));
115*7c478bd9Sstevel@tonic-gate }
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate static struct job *
118*7c478bd9Sstevel@tonic-gate pgid2job(pgid)
119*7c478bd9Sstevel@tonic-gate register pid_t pgid;
120*7c478bd9Sstevel@tonic-gate {
121*7c478bd9Sstevel@tonic-gate 	register struct job *jp;
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 	for (jp = joblst; jp != 0 && jp->j_pid != pgid; jp = jp->j_nxtp)
124*7c478bd9Sstevel@tonic-gate 		continue;
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate 	return (jp);
127*7c478bd9Sstevel@tonic-gate }
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate static struct job *
130*7c478bd9Sstevel@tonic-gate str2job(cmd, job, mustbejob)
131*7c478bd9Sstevel@tonic-gate register char *cmd;
132*7c478bd9Sstevel@tonic-gate register char *job;
133*7c478bd9Sstevel@tonic-gate int mustbejob;
134*7c478bd9Sstevel@tonic-gate {
135*7c478bd9Sstevel@tonic-gate 	register struct job *jp, *njp;
136*7c478bd9Sstevel@tonic-gate 	register i;
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 	if (*job != '%')
139*7c478bd9Sstevel@tonic-gate 		jp = pgid2job(stoi(job));
140*7c478bd9Sstevel@tonic-gate 	else if (*++job == 0 || *job == '+' || *job == '%' || *job == '-') {
141*7c478bd9Sstevel@tonic-gate 		jp = jobcur;
142*7c478bd9Sstevel@tonic-gate 		if (*job == '-' && jp)
143*7c478bd9Sstevel@tonic-gate 			jp = jp->j_curp;
144*7c478bd9Sstevel@tonic-gate 	} else if (*job >= '0' && *job <= '9') {
145*7c478bd9Sstevel@tonic-gate 		i = stoi(job);
146*7c478bd9Sstevel@tonic-gate 		for (jp = joblst; jp && jp->j_jid != i; jp = jp->j_nxtp)
147*7c478bd9Sstevel@tonic-gate 			continue;
148*7c478bd9Sstevel@tonic-gate 	} else if (*job == '?') {
149*7c478bd9Sstevel@tonic-gate 		register j;
150*7c478bd9Sstevel@tonic-gate 		register char *p;
151*7c478bd9Sstevel@tonic-gate 		i = strlen(++job);
152*7c478bd9Sstevel@tonic-gate 		jp = 0;
153*7c478bd9Sstevel@tonic-gate 		for (njp = jobcur; njp; njp = njp->j_curp) {
154*7c478bd9Sstevel@tonic-gate 			if (njp->j_jid == 0)
155*7c478bd9Sstevel@tonic-gate 				continue;
156*7c478bd9Sstevel@tonic-gate 			for (p = njp->j_cmd, j = strlen(p); j >= i; p++, j--) {
157*7c478bd9Sstevel@tonic-gate 				if (strncmp(job, p, i) == 0) {
158*7c478bd9Sstevel@tonic-gate 					if (jp != 0)
159*7c478bd9Sstevel@tonic-gate 						failed(cmd, ambiguous);
160*7c478bd9Sstevel@tonic-gate 					jp = njp;
161*7c478bd9Sstevel@tonic-gate 					break;
162*7c478bd9Sstevel@tonic-gate 				}
163*7c478bd9Sstevel@tonic-gate 			}
164*7c478bd9Sstevel@tonic-gate 		}
165*7c478bd9Sstevel@tonic-gate 	} else {
166*7c478bd9Sstevel@tonic-gate 		i = strlen(job);
167*7c478bd9Sstevel@tonic-gate 		jp = 0;
168*7c478bd9Sstevel@tonic-gate 		for (njp = jobcur; njp; njp = njp->j_curp) {
169*7c478bd9Sstevel@tonic-gate 			if (njp->j_jid == 0)
170*7c478bd9Sstevel@tonic-gate 				continue;
171*7c478bd9Sstevel@tonic-gate 			if (strncmp(job, njp->j_cmd, i) == 0) {
172*7c478bd9Sstevel@tonic-gate 				if (jp != 0)
173*7c478bd9Sstevel@tonic-gate 					failed(cmd, ambiguous);
174*7c478bd9Sstevel@tonic-gate 				jp = njp;
175*7c478bd9Sstevel@tonic-gate 			}
176*7c478bd9Sstevel@tonic-gate 		}
177*7c478bd9Sstevel@tonic-gate 	}
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 	if (mustbejob && (jp == 0 || jp->j_jid == 0))
180*7c478bd9Sstevel@tonic-gate 		failed(cmd, nosuchjob);
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 	return (jp);
183*7c478bd9Sstevel@tonic-gate }
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate static void
186*7c478bd9Sstevel@tonic-gate freejob(jp)
187*7c478bd9Sstevel@tonic-gate register struct job *jp;
188*7c478bd9Sstevel@tonic-gate {
189*7c478bd9Sstevel@tonic-gate 	register struct job **njp;
190*7c478bd9Sstevel@tonic-gate 	register struct job **cjp;
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate 	for (njp = &joblst; *njp != jp; njp = &(*njp)->j_nxtp)
193*7c478bd9Sstevel@tonic-gate 		continue;
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	for (cjp = &jobcur; *cjp != jp; cjp = &(*cjp)->j_curp)
196*7c478bd9Sstevel@tonic-gate 		continue;
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 	*njp = jp->j_nxtp;
199*7c478bd9Sstevel@tonic-gate 	*cjp = jp->j_curp;
200*7c478bd9Sstevel@tonic-gate 	free(jp);
201*7c478bd9Sstevel@tonic-gate 	jobcnt--;
202*7c478bd9Sstevel@tonic-gate 	jobdone--;
203*7c478bd9Sstevel@tonic-gate }
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate /*
206*7c478bd9Sstevel@tonic-gate  * Collect the foreground job.
207*7c478bd9Sstevel@tonic-gate  * Used in the case where the subshell wants
208*7c478bd9Sstevel@tonic-gate  * to exit, but needs to wait until the fg job
209*7c478bd9Sstevel@tonic-gate  * is done.
210*7c478bd9Sstevel@tonic-gate  */
211*7c478bd9Sstevel@tonic-gate collect_fg_job()
212*7c478bd9Sstevel@tonic-gate {
213*7c478bd9Sstevel@tonic-gate 	register struct job *jp;
214*7c478bd9Sstevel@tonic-gate 	register pid_t pid;
215*7c478bd9Sstevel@tonic-gate 	int stat;
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 	for (jp = joblst; jp; jp = jp->j_nxtp)
218*7c478bd9Sstevel@tonic-gate 		if (jp->j_flag & J_FOREGND)
219*7c478bd9Sstevel@tonic-gate 			break;
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 	if (!jp)
222*7c478bd9Sstevel@tonic-gate 		/* no foreground job */
223*7c478bd9Sstevel@tonic-gate 		return;
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	/*
226*7c478bd9Sstevel@tonic-gate 	 * Wait on fg job until wait succeeds
227*7c478bd9Sstevel@tonic-gate 	 * or it fails due to no waitable children.
228*7c478bd9Sstevel@tonic-gate 	 */
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 	while (1) {
231*7c478bd9Sstevel@tonic-gate 		errno = 0;
232*7c478bd9Sstevel@tonic-gate 		pid = waitpid(jp->j_pid, &stat, 0);
233*7c478bd9Sstevel@tonic-gate 		if (pid == jp->j_pid || (pid == -1 && errno == ECHILD))
234*7c478bd9Sstevel@tonic-gate 			break;
235*7c478bd9Sstevel@tonic-gate 	}
236*7c478bd9Sstevel@tonic-gate }
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate /*
239*7c478bd9Sstevel@tonic-gate  * analyze the status of a job
240*7c478bd9Sstevel@tonic-gate  */
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate static int
243*7c478bd9Sstevel@tonic-gate statjob(jp, stat, fg, rc)
244*7c478bd9Sstevel@tonic-gate register struct job *jp;
245*7c478bd9Sstevel@tonic-gate register stat;
246*7c478bd9Sstevel@tonic-gate int fg;
247*7c478bd9Sstevel@tonic-gate int rc;
248*7c478bd9Sstevel@tonic-gate {
249*7c478bd9Sstevel@tonic-gate 	pid_t tgid;
250*7c478bd9Sstevel@tonic-gate 	int done = 0;
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 	if (WIFCONTINUED(stat)) {
253*7c478bd9Sstevel@tonic-gate 		if (jp->j_flag & J_STOPPED) {
254*7c478bd9Sstevel@tonic-gate 			jp->j_flag &= ~(J_STOPPED|J_SIGNALED|J_SAVETTY);
255*7c478bd9Sstevel@tonic-gate 			jp->j_flag |= J_RUNNING;
256*7c478bd9Sstevel@tonic-gate 			if (!fg && jp->j_jid) {
257*7c478bd9Sstevel@tonic-gate 				jp->j_flag |= J_NOTIFY;
258*7c478bd9Sstevel@tonic-gate 				jobnote++;
259*7c478bd9Sstevel@tonic-gate 			}
260*7c478bd9Sstevel@tonic-gate 		}
261*7c478bd9Sstevel@tonic-gate 	} else if (WIFSTOPPED(stat)) {
262*7c478bd9Sstevel@tonic-gate 		jp->j_xval = WSTOPSIG(stat);
263*7c478bd9Sstevel@tonic-gate 		jp->j_flag &= ~J_RUNNING;
264*7c478bd9Sstevel@tonic-gate 		jp->j_flag |= (J_SIGNALED|J_STOPPED);
265*7c478bd9Sstevel@tonic-gate 		jp->j_pgid = getpgid(jp->j_pid);
266*7c478bd9Sstevel@tonic-gate 		jp->j_tgid = jp->j_pgid;
267*7c478bd9Sstevel@tonic-gate 		if (fg) {
268*7c478bd9Sstevel@tonic-gate 			if (tgid = settgid(mypgid, jp->j_pgid))
269*7c478bd9Sstevel@tonic-gate 				jp->j_tgid = tgid;
270*7c478bd9Sstevel@tonic-gate 			else {
271*7c478bd9Sstevel@tonic-gate 				jp->j_flag |= J_SAVETTY;
272*7c478bd9Sstevel@tonic-gate 				tcgetattr(0, &jp->j_stty);
273*7c478bd9Sstevel@tonic-gate 				(void) tcsetattr(0, TCSANOW, &mystty);
274*7c478bd9Sstevel@tonic-gate 			}
275*7c478bd9Sstevel@tonic-gate 		}
276*7c478bd9Sstevel@tonic-gate 		if (jp->j_jid) {
277*7c478bd9Sstevel@tonic-gate 			jp->j_flag |= J_NOTIFY;
278*7c478bd9Sstevel@tonic-gate 			jobnote++;
279*7c478bd9Sstevel@tonic-gate 		}
280*7c478bd9Sstevel@tonic-gate 	} else {
281*7c478bd9Sstevel@tonic-gate 		jp->j_flag &= ~J_RUNNING;
282*7c478bd9Sstevel@tonic-gate 		jp->j_flag |= J_DONE;
283*7c478bd9Sstevel@tonic-gate 		done++;
284*7c478bd9Sstevel@tonic-gate 		jobdone++;
285*7c478bd9Sstevel@tonic-gate 		if (WIFSIGNALED(stat)) {
286*7c478bd9Sstevel@tonic-gate 			jp->j_xval = WTERMSIG(stat);
287*7c478bd9Sstevel@tonic-gate 			jp->j_flag |= J_SIGNALED;
288*7c478bd9Sstevel@tonic-gate 			if (WCOREDUMP(stat))
289*7c478bd9Sstevel@tonic-gate 				jp->j_flag |= J_DUMPED;
290*7c478bd9Sstevel@tonic-gate 			if (!fg || jp->j_xval != SIGINT) {
291*7c478bd9Sstevel@tonic-gate 				jp->j_flag |= J_NOTIFY;
292*7c478bd9Sstevel@tonic-gate 				jobnote++;
293*7c478bd9Sstevel@tonic-gate 			}
294*7c478bd9Sstevel@tonic-gate 		} else { /* WIFEXITED */
295*7c478bd9Sstevel@tonic-gate 			jp->j_xval = WEXITSTATUS(stat);
296*7c478bd9Sstevel@tonic-gate 			jp->j_flag &= ~J_SIGNALED;
297*7c478bd9Sstevel@tonic-gate 			if (!fg && jp->j_jid) {
298*7c478bd9Sstevel@tonic-gate 				jp->j_flag |= J_NOTIFY;
299*7c478bd9Sstevel@tonic-gate 				jobnote++;
300*7c478bd9Sstevel@tonic-gate 			}
301*7c478bd9Sstevel@tonic-gate 		}
302*7c478bd9Sstevel@tonic-gate 		if (fg) {
303*7c478bd9Sstevel@tonic-gate 			if (!settgid(mypgid, jp->j_pgid) ||
304*7c478bd9Sstevel@tonic-gate 			    !settgid(mypgid, getpgid(jp->j_pid)))
305*7c478bd9Sstevel@tonic-gate 				tcgetattr(0, &mystty);
306*7c478bd9Sstevel@tonic-gate 		}
307*7c478bd9Sstevel@tonic-gate 	}
308*7c478bd9Sstevel@tonic-gate 	if (rc) {
309*7c478bd9Sstevel@tonic-gate 		exitval = jp->j_xval;
310*7c478bd9Sstevel@tonic-gate 		if (jp->j_flag & J_SIGNALED)
311*7c478bd9Sstevel@tonic-gate 			exitval |= SIGFLG;
312*7c478bd9Sstevel@tonic-gate 		exitset();
313*7c478bd9Sstevel@tonic-gate 	}
314*7c478bd9Sstevel@tonic-gate 	if (done && !(jp->j_flag & J_NOTIFY))
315*7c478bd9Sstevel@tonic-gate 		freejob(jp);
316*7c478bd9Sstevel@tonic-gate 	return (done);
317*7c478bd9Sstevel@tonic-gate }
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate /*
320*7c478bd9Sstevel@tonic-gate  * collect the status of jobs that have recently exited or stopped -
321*7c478bd9Sstevel@tonic-gate  * if wnohang == WNOHANG, wait until error, or all jobs are accounted for;
322*7c478bd9Sstevel@tonic-gate  *
323*7c478bd9Sstevel@tonic-gate  * called after each command is executed, with wnohang == 0, and as part
324*7c478bd9Sstevel@tonic-gate  * of "wait" builtin with wnohang == WNOHANG
325*7c478bd9Sstevel@tonic-gate  *
326*7c478bd9Sstevel@tonic-gate  * We do not need to call chktrap here if waitpid(2) is called with
327*7c478bd9Sstevel@tonic-gate  * wnohang == 0, because that only happens from syswait() which is called
328*7c478bd9Sstevel@tonic-gate  * from builtin() where chktrap() is already called.
329*7c478bd9Sstevel@tonic-gate  */
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate static void
332*7c478bd9Sstevel@tonic-gate collectjobs(wnohang)
333*7c478bd9Sstevel@tonic-gate {
334*7c478bd9Sstevel@tonic-gate 	pid_t pid;
335*7c478bd9Sstevel@tonic-gate 	register struct job *jp;
336*7c478bd9Sstevel@tonic-gate 	int stat, n;
337*7c478bd9Sstevel@tonic-gate 	int wflags;
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg))
340*7c478bd9Sstevel@tonic-gate 		wflags = WUNTRACED|WCONTINUED;
341*7c478bd9Sstevel@tonic-gate 	else
342*7c478bd9Sstevel@tonic-gate 		wflags = 0;
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 	for (n = jobcnt - jobdone; n > 0; n--) {
345*7c478bd9Sstevel@tonic-gate 		if ((pid = waitpid(-1, &stat, wnohang|wflags)) <= 0)
346*7c478bd9Sstevel@tonic-gate 			break;
347*7c478bd9Sstevel@tonic-gate 		if (jp = pgid2job(pid))
348*7c478bd9Sstevel@tonic-gate 			(void) statjob(jp, stat, 0, 0);
349*7c478bd9Sstevel@tonic-gate 	}
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate }
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate void
354*7c478bd9Sstevel@tonic-gate freejobs()
355*7c478bd9Sstevel@tonic-gate {
356*7c478bd9Sstevel@tonic-gate 	register struct job *jp;
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 	collectjobs(WNOHANG);
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	if (jobnote) {
361*7c478bd9Sstevel@tonic-gate 		register int savefd = setb(2);
362*7c478bd9Sstevel@tonic-gate 		for (jp = joblst; jp; jp = jp->j_nxtp) {
363*7c478bd9Sstevel@tonic-gate 			if (jp->j_flag & J_NOTIFY) {
364*7c478bd9Sstevel@tonic-gate 				if (jp->j_jid)
365*7c478bd9Sstevel@tonic-gate 					printjob(jp, PR_DFL);
366*7c478bd9Sstevel@tonic-gate 				else if (jp->j_flag & J_FOREGND)
367*7c478bd9Sstevel@tonic-gate 					printjob(jp, PR_STAT);
368*7c478bd9Sstevel@tonic-gate 				else
369*7c478bd9Sstevel@tonic-gate 					printjob(jp, PR_STAT|PR_PGID);
370*7c478bd9Sstevel@tonic-gate 			}
371*7c478bd9Sstevel@tonic-gate 		}
372*7c478bd9Sstevel@tonic-gate 		(void) setb(savefd);
373*7c478bd9Sstevel@tonic-gate 	}
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 	if (jobdone) {
376*7c478bd9Sstevel@tonic-gate 		for (jp = joblst; jp; jp = jp->j_nxtp) {
377*7c478bd9Sstevel@tonic-gate 			if (jp->j_flag & J_DONE)
378*7c478bd9Sstevel@tonic-gate 				freejob(jp);
379*7c478bd9Sstevel@tonic-gate 		}
380*7c478bd9Sstevel@tonic-gate 	}
381*7c478bd9Sstevel@tonic-gate }
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate static void
384*7c478bd9Sstevel@tonic-gate waitjob(jp)
385*7c478bd9Sstevel@tonic-gate register struct job *jp;
386*7c478bd9Sstevel@tonic-gate {
387*7c478bd9Sstevel@tonic-gate 	int stat;
388*7c478bd9Sstevel@tonic-gate 	int done;
389*7c478bd9Sstevel@tonic-gate 	pid_t pid = jp->j_pid;
390*7c478bd9Sstevel@tonic-gate 	int wflags;
391*7c478bd9Sstevel@tonic-gate 	int ret = 0;
392*7c478bd9Sstevel@tonic-gate 	int	err = 0;
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg))
395*7c478bd9Sstevel@tonic-gate 		wflags = WUNTRACED;
396*7c478bd9Sstevel@tonic-gate 	else
397*7c478bd9Sstevel@tonic-gate 		wflags = 0;
398*7c478bd9Sstevel@tonic-gate 	do {
399*7c478bd9Sstevel@tonic-gate 		errno = 0;
400*7c478bd9Sstevel@tonic-gate 		ret = waitpid(pid, &stat, wflags|WNOWAIT);
401*7c478bd9Sstevel@tonic-gate 		err = errno;
402*7c478bd9Sstevel@tonic-gate 		if (ret == -1 && err == ECHILD) {
403*7c478bd9Sstevel@tonic-gate 			stat = 0;
404*7c478bd9Sstevel@tonic-gate 			break;
405*7c478bd9Sstevel@tonic-gate 		}
406*7c478bd9Sstevel@tonic-gate 	} while (ret != pid);
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	done = statjob(jp, stat, 1, 1);
409*7c478bd9Sstevel@tonic-gate 	waitpid(pid, 0, wflags);
410*7c478bd9Sstevel@tonic-gate 	if (done && exitval && (flags & errflg))
411*7c478bd9Sstevel@tonic-gate 		exitsh(exitval);
412*7c478bd9Sstevel@tonic-gate 	flags |= eflag;
413*7c478bd9Sstevel@tonic-gate }
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate /*
416*7c478bd9Sstevel@tonic-gate  * modify the foreground process group to *new* only if the
417*7c478bd9Sstevel@tonic-gate  * current foreground process group is equal to *expected*
418*7c478bd9Sstevel@tonic-gate  */
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate int
421*7c478bd9Sstevel@tonic-gate settgid(new, expected)
422*7c478bd9Sstevel@tonic-gate pid_t new, expected;
423*7c478bd9Sstevel@tonic-gate {
424*7c478bd9Sstevel@tonic-gate 	register pid_t current = tcgetpgrp(0);
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	if (current != expected)
427*7c478bd9Sstevel@tonic-gate 		return (current);
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	if (new != current)
430*7c478bd9Sstevel@tonic-gate 		tcsetpgrp(0, new);
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate 	return (0);
433*7c478bd9Sstevel@tonic-gate }
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate static void
436*7c478bd9Sstevel@tonic-gate restartjob(jp, fg)
437*7c478bd9Sstevel@tonic-gate register struct job *jp;
438*7c478bd9Sstevel@tonic-gate {
439*7c478bd9Sstevel@tonic-gate 	if (jp != jobcur) {
440*7c478bd9Sstevel@tonic-gate 		register struct job *t;
441*7c478bd9Sstevel@tonic-gate 		for (t = jobcur; t->j_curp != jp; t = t->j_curp);
442*7c478bd9Sstevel@tonic-gate 		t->j_curp = jp->j_curp;
443*7c478bd9Sstevel@tonic-gate 		jp->j_curp = jobcur;
444*7c478bd9Sstevel@tonic-gate 		jobcur = jp;
445*7c478bd9Sstevel@tonic-gate 	}
446*7c478bd9Sstevel@tonic-gate 	if (fg) {
447*7c478bd9Sstevel@tonic-gate 		if (jp->j_flag & J_SAVETTY) {
448*7c478bd9Sstevel@tonic-gate 			jp->j_stty.c_lflag &= ~TOSTOP;
449*7c478bd9Sstevel@tonic-gate 			jp->j_stty.c_lflag |= (mystty.c_lflag&TOSTOP);
450*7c478bd9Sstevel@tonic-gate 			jp->j_stty.c_cc[VSUSP] = mystty.c_cc[VSUSP];
451*7c478bd9Sstevel@tonic-gate 			jp->j_stty.c_cc[VDSUSP] = mystty.c_cc[VDSUSP];
452*7c478bd9Sstevel@tonic-gate 			(void) tcsetattr(0, TCSADRAIN, &jp->j_stty);
453*7c478bd9Sstevel@tonic-gate 		}
454*7c478bd9Sstevel@tonic-gate 		(void) settgid(jp->j_tgid, mypgid);
455*7c478bd9Sstevel@tonic-gate 	}
456*7c478bd9Sstevel@tonic-gate 	(void) kill(-(jp->j_pgid), SIGCONT);
457*7c478bd9Sstevel@tonic-gate 	if (jp->j_tgid != jp->j_pgid)
458*7c478bd9Sstevel@tonic-gate 		(void) kill(-(jp->j_tgid), SIGCONT);
459*7c478bd9Sstevel@tonic-gate 	jp->j_flag &= ~(J_STOPPED|J_SIGNALED|J_SAVETTY);
460*7c478bd9Sstevel@tonic-gate 	jp->j_flag |= J_RUNNING;
461*7c478bd9Sstevel@tonic-gate 	if (fg)  {
462*7c478bd9Sstevel@tonic-gate 		jp->j_flag |= J_FOREGND;
463*7c478bd9Sstevel@tonic-gate 		printjob(jp, PR_JID|PR_CMD);
464*7c478bd9Sstevel@tonic-gate 		waitjob(jp);
465*7c478bd9Sstevel@tonic-gate 	} else {
466*7c478bd9Sstevel@tonic-gate 		jp->j_flag &= ~J_FOREGND;
467*7c478bd9Sstevel@tonic-gate 		printjob(jp, PR_JID|PR_CMD|PR_AMP);
468*7c478bd9Sstevel@tonic-gate 	}
469*7c478bd9Sstevel@tonic-gate }
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate static
472*7c478bd9Sstevel@tonic-gate printjob(jp, propts)
473*7c478bd9Sstevel@tonic-gate register struct job *jp;
474*7c478bd9Sstevel@tonic-gate {
475*7c478bd9Sstevel@tonic-gate 	int sp = 0;
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	if (jp->j_flag & J_NOTIFY) {
478*7c478bd9Sstevel@tonic-gate 		jobnote--;
479*7c478bd9Sstevel@tonic-gate 		jp->j_flag &= ~J_NOTIFY;
480*7c478bd9Sstevel@tonic-gate 	}
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 	if (propts & PR_JID) {
483*7c478bd9Sstevel@tonic-gate 		prc_buff('[');
484*7c478bd9Sstevel@tonic-gate 		prn_buff(jp->j_jid);
485*7c478bd9Sstevel@tonic-gate 		prc_buff(']');
486*7c478bd9Sstevel@tonic-gate 		sp = 1;
487*7c478bd9Sstevel@tonic-gate 	}
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate 	if (propts & PR_CUR) {
490*7c478bd9Sstevel@tonic-gate 		while (sp-- > 0)
491*7c478bd9Sstevel@tonic-gate 			prc_buff(SPACE);
492*7c478bd9Sstevel@tonic-gate 		sp = 1;
493*7c478bd9Sstevel@tonic-gate 		if (jobcur == jp)
494*7c478bd9Sstevel@tonic-gate 			prc_buff('+');
495*7c478bd9Sstevel@tonic-gate 		else if (jobcur != 0 && jobcur->j_curp == jp)
496*7c478bd9Sstevel@tonic-gate 			prc_buff('-');
497*7c478bd9Sstevel@tonic-gate 		else
498*7c478bd9Sstevel@tonic-gate 			sp++;
499*7c478bd9Sstevel@tonic-gate 	}
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 	if (propts & PR_PGID) {
502*7c478bd9Sstevel@tonic-gate 		while (sp-- > 0)
503*7c478bd9Sstevel@tonic-gate 			prc_buff(SPACE);
504*7c478bd9Sstevel@tonic-gate 		prn_buff(jp->j_pid);
505*7c478bd9Sstevel@tonic-gate 		sp = 1;
506*7c478bd9Sstevel@tonic-gate 	}
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 	if (propts & PR_STAT) {
509*7c478bd9Sstevel@tonic-gate 		while (sp-- > 0)
510*7c478bd9Sstevel@tonic-gate 			prc_buff(SPACE);
511*7c478bd9Sstevel@tonic-gate 		sp = 28;
512*7c478bd9Sstevel@tonic-gate 		if (jp->j_flag & J_SIGNALED) {
513*7c478bd9Sstevel@tonic-gate 			char *sigstr, *strsignal();
514*7c478bd9Sstevel@tonic-gate 			if ((sigstr = strsignal(jp->j_xval)) != NULL) {
515*7c478bd9Sstevel@tonic-gate 				sp -= strlen(sigstr);
516*7c478bd9Sstevel@tonic-gate 				prs_buff(sigstr);
517*7c478bd9Sstevel@tonic-gate 			} else {
518*7c478bd9Sstevel@tonic-gate 				itos(jp->j_xval);
519*7c478bd9Sstevel@tonic-gate 				sp -= strlen(numbuf) + 7;
520*7c478bd9Sstevel@tonic-gate 				prs_buff("Signal ");
521*7c478bd9Sstevel@tonic-gate 				prs_buff(numbuf);
522*7c478bd9Sstevel@tonic-gate 			}
523*7c478bd9Sstevel@tonic-gate 			if (jp->j_flag & J_DUMPED) {
524*7c478bd9Sstevel@tonic-gate 				sp -= strlen(coredump);
525*7c478bd9Sstevel@tonic-gate 				prs_buff(coredump);
526*7c478bd9Sstevel@tonic-gate 			}
527*7c478bd9Sstevel@tonic-gate 		} else if (jp->j_flag & J_DONE) {
528*7c478bd9Sstevel@tonic-gate 			itos(jp->j_xval);
529*7c478bd9Sstevel@tonic-gate 			sp -= strlen(exited) + strlen(numbuf) + 2;
530*7c478bd9Sstevel@tonic-gate 			prs_buff(exited);
531*7c478bd9Sstevel@tonic-gate 			prc_buff('(');
532*7c478bd9Sstevel@tonic-gate 			itos(jp->j_xval);
533*7c478bd9Sstevel@tonic-gate 			prs_buff(numbuf);
534*7c478bd9Sstevel@tonic-gate 			prc_buff(')');
535*7c478bd9Sstevel@tonic-gate 		} else {
536*7c478bd9Sstevel@tonic-gate 			sp -= strlen(running);
537*7c478bd9Sstevel@tonic-gate 			prs_buff(running);
538*7c478bd9Sstevel@tonic-gate 		}
539*7c478bd9Sstevel@tonic-gate 		if (sp < 1)
540*7c478bd9Sstevel@tonic-gate 			sp = 1;
541*7c478bd9Sstevel@tonic-gate 	}
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate 	if (propts & PR_CMD) {
544*7c478bd9Sstevel@tonic-gate 		while (sp-- > 0)
545*7c478bd9Sstevel@tonic-gate 			prc_buff(SPACE);
546*7c478bd9Sstevel@tonic-gate 		prs_buff(jp->j_cmd);
547*7c478bd9Sstevel@tonic-gate 		sp = 1;
548*7c478bd9Sstevel@tonic-gate 	}
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	if (propts & PR_AMP) {
551*7c478bd9Sstevel@tonic-gate 		while (sp-- > 0)
552*7c478bd9Sstevel@tonic-gate 			prc_buff(SPACE);
553*7c478bd9Sstevel@tonic-gate 		prc_buff('&');
554*7c478bd9Sstevel@tonic-gate 		sp = 1;
555*7c478bd9Sstevel@tonic-gate 	}
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 	if (propts & PR_PWD) {
558*7c478bd9Sstevel@tonic-gate 		while (sp-- > 0)
559*7c478bd9Sstevel@tonic-gate 			prc_buff(SPACE);
560*7c478bd9Sstevel@tonic-gate 		prs_buff("(wd: ");
561*7c478bd9Sstevel@tonic-gate 		prs_buff(jp->j_pwd);
562*7c478bd9Sstevel@tonic-gate 		prc_buff(')');
563*7c478bd9Sstevel@tonic-gate 	}
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 	prc_buff(NL);
566*7c478bd9Sstevel@tonic-gate 	flushb();
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate }
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate /*
572*7c478bd9Sstevel@tonic-gate  * called to initialize job control for each new input file to the shell,
573*7c478bd9Sstevel@tonic-gate  * and after the "exec" builtin
574*7c478bd9Sstevel@tonic-gate  */
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate void
577*7c478bd9Sstevel@tonic-gate startjobs()
578*7c478bd9Sstevel@tonic-gate {
579*7c478bd9Sstevel@tonic-gate 	svpgid = mypgid;
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 	if (tcgetattr(0, &mystty) == -1 || (svtgid = tcgetpgrp(0)) == -1) {
582*7c478bd9Sstevel@tonic-gate 		flags &= ~jcflg;
583*7c478bd9Sstevel@tonic-gate 		return;
584*7c478bd9Sstevel@tonic-gate 	}
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate 	flags |= jcflg;
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate 	handle(SIGTTOU, SIG_IGN);
589*7c478bd9Sstevel@tonic-gate 	handle(SIGTSTP, SIG_DFL);
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 	if (mysid != mypgid) {
592*7c478bd9Sstevel@tonic-gate 		setpgid(0, 0);
593*7c478bd9Sstevel@tonic-gate 		mypgid = mypid;
594*7c478bd9Sstevel@tonic-gate 		(void) settgid(mypgid, svpgid);
595*7c478bd9Sstevel@tonic-gate 	}
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate }
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate int
600*7c478bd9Sstevel@tonic-gate endjobs(check_if)
601*7c478bd9Sstevel@tonic-gate int check_if;
602*7c478bd9Sstevel@tonic-gate {
603*7c478bd9Sstevel@tonic-gate 	if ((flags & (jcoff|jcflg)) != jcflg)
604*7c478bd9Sstevel@tonic-gate 		return (1);
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate 	if (check_if && jobcnt && eofflg++ == 0) {
607*7c478bd9Sstevel@tonic-gate 		register struct job *jp;
608*7c478bd9Sstevel@tonic-gate 		if (check_if & JOB_STOPPED) {
609*7c478bd9Sstevel@tonic-gate 			for (jp = joblst; jp; jp = jp->j_nxtp) {
610*7c478bd9Sstevel@tonic-gate 				if (jp->j_jid && (jp->j_flag & J_STOPPED)) {
611*7c478bd9Sstevel@tonic-gate 					prs(jobsstopped);
612*7c478bd9Sstevel@tonic-gate 					prc(NL);
613*7c478bd9Sstevel@tonic-gate 					return (0);
614*7c478bd9Sstevel@tonic-gate 				}
615*7c478bd9Sstevel@tonic-gate 			}
616*7c478bd9Sstevel@tonic-gate 		}
617*7c478bd9Sstevel@tonic-gate 		if (check_if & JOB_RUNNING) {
618*7c478bd9Sstevel@tonic-gate 			for (jp = joblst; jp; jp = jp->j_nxtp) {
619*7c478bd9Sstevel@tonic-gate 				if (jp->j_jid && (jp->j_flag & J_RUNNING)) {
620*7c478bd9Sstevel@tonic-gate 					prs(jobsrunning);
621*7c478bd9Sstevel@tonic-gate 					prc(NL);
622*7c478bd9Sstevel@tonic-gate 					return (0);
623*7c478bd9Sstevel@tonic-gate 				}
624*7c478bd9Sstevel@tonic-gate 			}
625*7c478bd9Sstevel@tonic-gate 		}
626*7c478bd9Sstevel@tonic-gate 	}
627*7c478bd9Sstevel@tonic-gate 
628*7c478bd9Sstevel@tonic-gate 	if (svpgid != mypgid) {
629*7c478bd9Sstevel@tonic-gate 		(void) settgid(svtgid, mypgid);
630*7c478bd9Sstevel@tonic-gate 		setpgid(0, svpgid);
631*7c478bd9Sstevel@tonic-gate 	}
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 	return (1);
634*7c478bd9Sstevel@tonic-gate }
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate 
637*7c478bd9Sstevel@tonic-gate /*
638*7c478bd9Sstevel@tonic-gate  * called by the shell to reserve a job slot for a job about to be spawned
639*7c478bd9Sstevel@tonic-gate  */
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate void
642*7c478bd9Sstevel@tonic-gate deallocjob()
643*7c478bd9Sstevel@tonic-gate {
644*7c478bd9Sstevel@tonic-gate 	free(thisjob);
645*7c478bd9Sstevel@tonic-gate 	jobcnt--;
646*7c478bd9Sstevel@tonic-gate }
647*7c478bd9Sstevel@tonic-gate 
648*7c478bd9Sstevel@tonic-gate allocjob(cmd, cwd, monitor)
649*7c478bd9Sstevel@tonic-gate register char *cmd;
650*7c478bd9Sstevel@tonic-gate register unchar *cwd;
651*7c478bd9Sstevel@tonic-gate int monitor;
652*7c478bd9Sstevel@tonic-gate {
653*7c478bd9Sstevel@tonic-gate 	register struct job *jp, **jpp;
654*7c478bd9Sstevel@tonic-gate 	register int jid, cmdlen, cwdlen;
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate 	cmdlen = strlen(cmd) + 1;
657*7c478bd9Sstevel@tonic-gate 	if (cmd[cmdlen-2] == '&') {
658*7c478bd9Sstevel@tonic-gate 		cmd[cmdlen-3] = 0;
659*7c478bd9Sstevel@tonic-gate 		cmdlen -= 2;
660*7c478bd9Sstevel@tonic-gate 	}
661*7c478bd9Sstevel@tonic-gate 	cwdlen = strlen(cwd) + 1;
662*7c478bd9Sstevel@tonic-gate 	jp = (struct job *) alloc(sizeof (struct job) + cmdlen + cwdlen);
663*7c478bd9Sstevel@tonic-gate 	if (jp == 0)
664*7c478bd9Sstevel@tonic-gate 		error(nostack);
665*7c478bd9Sstevel@tonic-gate 	jobcnt++;
666*7c478bd9Sstevel@tonic-gate 	jp->j_cmd = ((char *)jp) + sizeof (struct job);
667*7c478bd9Sstevel@tonic-gate 	strcpy(jp->j_cmd, cmd);
668*7c478bd9Sstevel@tonic-gate 	jp->j_pwd = jp->j_cmd + cmdlen;
669*7c478bd9Sstevel@tonic-gate 	strcpy(jp->j_pwd, cwd);
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 	jpp = &joblst;
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate 	if (monitor) {
674*7c478bd9Sstevel@tonic-gate 		for (; *jpp; jpp = &(*jpp)->j_nxtp)
675*7c478bd9Sstevel@tonic-gate 			if ((*jpp)->j_jid != 0)
676*7c478bd9Sstevel@tonic-gate 				break;
677*7c478bd9Sstevel@tonic-gate 		for (jid = 1; *jpp; jpp = &(*jpp)->j_nxtp, jid++)
678*7c478bd9Sstevel@tonic-gate 			if ((*jpp)->j_jid != jid)
679*7c478bd9Sstevel@tonic-gate 				break;
680*7c478bd9Sstevel@tonic-gate 	} else
681*7c478bd9Sstevel@tonic-gate 		jid = 0;
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 	jp->j_jid = jid;
684*7c478bd9Sstevel@tonic-gate 	nextjob = jpp;
685*7c478bd9Sstevel@tonic-gate 	thisjob = jp;
686*7c478bd9Sstevel@tonic-gate }
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate clearjobs()
689*7c478bd9Sstevel@tonic-gate {
690*7c478bd9Sstevel@tonic-gate 	register struct job *jp, *sjp;
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate 	for (jp = joblst; jp; jp = sjp) {
693*7c478bd9Sstevel@tonic-gate 		sjp = jp->j_nxtp;
694*7c478bd9Sstevel@tonic-gate 		free(jp);
695*7c478bd9Sstevel@tonic-gate 	}
696*7c478bd9Sstevel@tonic-gate 	joblst = NULL;
697*7c478bd9Sstevel@tonic-gate 	jobcnt = 0;
698*7c478bd9Sstevel@tonic-gate 	jobnote = 0;
699*7c478bd9Sstevel@tonic-gate 	jobdone = 0;
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate }
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate makejob(monitor, fg)
704*7c478bd9Sstevel@tonic-gate int monitor, fg;
705*7c478bd9Sstevel@tonic-gate {
706*7c478bd9Sstevel@tonic-gate 	if (monitor) {
707*7c478bd9Sstevel@tonic-gate 		mypgid = mypid;
708*7c478bd9Sstevel@tonic-gate 		setpgid(0, 0);
709*7c478bd9Sstevel@tonic-gate 		if (fg)
710*7c478bd9Sstevel@tonic-gate 			tcsetpgrp(0, mypid);
711*7c478bd9Sstevel@tonic-gate 		handle(SIGTTOU, SIG_DFL);
712*7c478bd9Sstevel@tonic-gate 		handle(SIGTSTP, SIG_DFL);
713*7c478bd9Sstevel@tonic-gate 	} else if (!fg) {
714*7c478bd9Sstevel@tonic-gate #ifdef NICE
715*7c478bd9Sstevel@tonic-gate 		nice(NICE);
716*7c478bd9Sstevel@tonic-gate #endif
717*7c478bd9Sstevel@tonic-gate 		handle(SIGTTIN, SIG_IGN);
718*7c478bd9Sstevel@tonic-gate 		handle(SIGINT,  SIG_IGN);
719*7c478bd9Sstevel@tonic-gate 		handle(SIGQUIT, SIG_IGN);
720*7c478bd9Sstevel@tonic-gate 		if (!ioset)
721*7c478bd9Sstevel@tonic-gate 			renamef(chkopen(devnull, 0), 0);
722*7c478bd9Sstevel@tonic-gate 	}
723*7c478bd9Sstevel@tonic-gate }
724*7c478bd9Sstevel@tonic-gate 
725*7c478bd9Sstevel@tonic-gate /*
726*7c478bd9Sstevel@tonic-gate  * called by the shell after job has been spawned, to fill in the
727*7c478bd9Sstevel@tonic-gate  * job slot, and wait for the job if in the foreground
728*7c478bd9Sstevel@tonic-gate  */
729*7c478bd9Sstevel@tonic-gate 
730*7c478bd9Sstevel@tonic-gate void
731*7c478bd9Sstevel@tonic-gate postjob(pid, fg)
732*7c478bd9Sstevel@tonic-gate pid_t pid;
733*7c478bd9Sstevel@tonic-gate int fg;
734*7c478bd9Sstevel@tonic-gate {
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate 	register propts;
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate 	thisjob->j_nxtp = *nextjob;
739*7c478bd9Sstevel@tonic-gate 	*nextjob = thisjob;
740*7c478bd9Sstevel@tonic-gate 	thisjob->j_curp = jobcur;
741*7c478bd9Sstevel@tonic-gate 	jobcur = thisjob;
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 	if (thisjob->j_jid) {
744*7c478bd9Sstevel@tonic-gate 		thisjob->j_pgid = pid;
745*7c478bd9Sstevel@tonic-gate 		propts = PR_JID|PR_PGID;
746*7c478bd9Sstevel@tonic-gate 	} else {
747*7c478bd9Sstevel@tonic-gate 		thisjob->j_pgid = mypgid;
748*7c478bd9Sstevel@tonic-gate 		propts = PR_PGID;
749*7c478bd9Sstevel@tonic-gate 	}
750*7c478bd9Sstevel@tonic-gate 
751*7c478bd9Sstevel@tonic-gate 	thisjob->j_flag = J_RUNNING;
752*7c478bd9Sstevel@tonic-gate 	thisjob->j_tgid = thisjob->j_pgid;
753*7c478bd9Sstevel@tonic-gate 	thisjob->j_pid = pid;
754*7c478bd9Sstevel@tonic-gate 	eofflg = 0;
755*7c478bd9Sstevel@tonic-gate 
756*7c478bd9Sstevel@tonic-gate 	if (fg) {
757*7c478bd9Sstevel@tonic-gate 		thisjob->j_flag |= J_FOREGND;
758*7c478bd9Sstevel@tonic-gate 		waitjob(thisjob);
759*7c478bd9Sstevel@tonic-gate 	} else  {
760*7c478bd9Sstevel@tonic-gate 		if (flags & ttyflg)
761*7c478bd9Sstevel@tonic-gate 			printjob(thisjob, propts);
762*7c478bd9Sstevel@tonic-gate 		assnum(&pcsadr, (long)pid);
763*7c478bd9Sstevel@tonic-gate 	}
764*7c478bd9Sstevel@tonic-gate }
765*7c478bd9Sstevel@tonic-gate 
766*7c478bd9Sstevel@tonic-gate /*
767*7c478bd9Sstevel@tonic-gate  * the builtin "jobs" command
768*7c478bd9Sstevel@tonic-gate  */
769*7c478bd9Sstevel@tonic-gate 
770*7c478bd9Sstevel@tonic-gate void
771*7c478bd9Sstevel@tonic-gate sysjobs(argc, argv)
772*7c478bd9Sstevel@tonic-gate int argc;
773*7c478bd9Sstevel@tonic-gate char *argv[];
774*7c478bd9Sstevel@tonic-gate {
775*7c478bd9Sstevel@tonic-gate 	register char *cmd = *argv;
776*7c478bd9Sstevel@tonic-gate 	register struct job *jp;
777*7c478bd9Sstevel@tonic-gate 	register propts, c;
778*7c478bd9Sstevel@tonic-gate 	extern int opterr, i;
779*7c478bd9Sstevel@tonic-gate 	int savoptind = optind;
780*7c478bd9Sstevel@tonic-gate 	int loptind = -1;
781*7c478bd9Sstevel@tonic-gate 	int savopterr = opterr;
782*7c478bd9Sstevel@tonic-gate 	int savsp = _sp;
783*7c478bd9Sstevel@tonic-gate 	char *savoptarg = optarg;
784*7c478bd9Sstevel@tonic-gate 	optind = 1;
785*7c478bd9Sstevel@tonic-gate 	opterr = 0;
786*7c478bd9Sstevel@tonic-gate 	_sp = 1;
787*7c478bd9Sstevel@tonic-gate 	propts = 0;
788*7c478bd9Sstevel@tonic-gate 
789*7c478bd9Sstevel@tonic-gate 	if ((flags & jcflg) == 0)
790*7c478bd9Sstevel@tonic-gate 		failed(cmd, nojc);
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "lpx")) != -1) {
793*7c478bd9Sstevel@tonic-gate 		if (propts) {
794*7c478bd9Sstevel@tonic-gate 			failure(usage, jobsuse);
795*7c478bd9Sstevel@tonic-gate 			goto err;
796*7c478bd9Sstevel@tonic-gate 		}
797*7c478bd9Sstevel@tonic-gate 		switch (c) {
798*7c478bd9Sstevel@tonic-gate 			case 'x':
799*7c478bd9Sstevel@tonic-gate 				propts = -1;
800*7c478bd9Sstevel@tonic-gate 				break;
801*7c478bd9Sstevel@tonic-gate 			case 'p':
802*7c478bd9Sstevel@tonic-gate 				propts = PR_PGID;
803*7c478bd9Sstevel@tonic-gate 				break;
804*7c478bd9Sstevel@tonic-gate 			case 'l':
805*7c478bd9Sstevel@tonic-gate 				propts = PR_LONG;
806*7c478bd9Sstevel@tonic-gate 				break;
807*7c478bd9Sstevel@tonic-gate 			case '?':
808*7c478bd9Sstevel@tonic-gate 				failure(usage, jobsuse);
809*7c478bd9Sstevel@tonic-gate 				goto err;
810*7c478bd9Sstevel@tonic-gate 		}
811*7c478bd9Sstevel@tonic-gate 	}
812*7c478bd9Sstevel@tonic-gate 
813*7c478bd9Sstevel@tonic-gate 	loptind = optind;
814*7c478bd9Sstevel@tonic-gate err:
815*7c478bd9Sstevel@tonic-gate 	optind = savoptind;
816*7c478bd9Sstevel@tonic-gate 	optarg = savoptarg;
817*7c478bd9Sstevel@tonic-gate 	opterr = savopterr;
818*7c478bd9Sstevel@tonic-gate 	_sp = savsp;
819*7c478bd9Sstevel@tonic-gate 	if (loptind == -1)
820*7c478bd9Sstevel@tonic-gate 		return;
821*7c478bd9Sstevel@tonic-gate 
822*7c478bd9Sstevel@tonic-gate 	if (propts == -1) {
823*7c478bd9Sstevel@tonic-gate 		register unsigned char *bp;
824*7c478bd9Sstevel@tonic-gate 		register char *cp;
825*7c478bd9Sstevel@tonic-gate 		unsigned char *savebp;
826*7c478bd9Sstevel@tonic-gate 		for (savebp = bp = locstak(); loptind < argc; loptind++) {
827*7c478bd9Sstevel@tonic-gate 			cp = argv[loptind];
828*7c478bd9Sstevel@tonic-gate 			if (*cp == '%') {
829*7c478bd9Sstevel@tonic-gate 				jp = str2job(cmd, cp, 1);
830*7c478bd9Sstevel@tonic-gate 				itos(jp->j_pid);
831*7c478bd9Sstevel@tonic-gate 				cp = (char *)numbuf;
832*7c478bd9Sstevel@tonic-gate 			}
833*7c478bd9Sstevel@tonic-gate 			while (*cp) {
834*7c478bd9Sstevel@tonic-gate 				if (bp >= brkend)
835*7c478bd9Sstevel@tonic-gate 					growstak(bp);
836*7c478bd9Sstevel@tonic-gate 				*bp++ = *cp++;
837*7c478bd9Sstevel@tonic-gate 			}
838*7c478bd9Sstevel@tonic-gate 			if (bp >= brkend)
839*7c478bd9Sstevel@tonic-gate 				growstak(bp);
840*7c478bd9Sstevel@tonic-gate 			*bp++ = SPACE;
841*7c478bd9Sstevel@tonic-gate 		}
842*7c478bd9Sstevel@tonic-gate 		endstak(bp);
843*7c478bd9Sstevel@tonic-gate 		execexp(savebp, 0);
844*7c478bd9Sstevel@tonic-gate 		return;
845*7c478bd9Sstevel@tonic-gate 	}
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate 	collectjobs(WNOHANG);
848*7c478bd9Sstevel@tonic-gate 
849*7c478bd9Sstevel@tonic-gate 	if (propts == 0)
850*7c478bd9Sstevel@tonic-gate 		propts = PR_DFL;
851*7c478bd9Sstevel@tonic-gate 
852*7c478bd9Sstevel@tonic-gate 	if (loptind == argc) {
853*7c478bd9Sstevel@tonic-gate 		for (jp = joblst; jp; jp = jp->j_nxtp) {
854*7c478bd9Sstevel@tonic-gate 			if (jp->j_jid)
855*7c478bd9Sstevel@tonic-gate 				printjob(jp, propts);
856*7c478bd9Sstevel@tonic-gate 		}
857*7c478bd9Sstevel@tonic-gate 	} else do
858*7c478bd9Sstevel@tonic-gate 		printjob(str2job(cmd, argv[loptind++], 1), propts);
859*7c478bd9Sstevel@tonic-gate 	while (loptind < argc);
860*7c478bd9Sstevel@tonic-gate 
861*7c478bd9Sstevel@tonic-gate }
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate /*
864*7c478bd9Sstevel@tonic-gate  * the builtin "fg" and "bg" commands
865*7c478bd9Sstevel@tonic-gate  */
866*7c478bd9Sstevel@tonic-gate 
867*7c478bd9Sstevel@tonic-gate sysfgbg(argc, argv)
868*7c478bd9Sstevel@tonic-gate int argc;
869*7c478bd9Sstevel@tonic-gate char *argv[];
870*7c478bd9Sstevel@tonic-gate {
871*7c478bd9Sstevel@tonic-gate 	register char *cmd = *argv;
872*7c478bd9Sstevel@tonic-gate 	register fg;
873*7c478bd9Sstevel@tonic-gate 
874*7c478bd9Sstevel@tonic-gate 	if ((flags & jcflg) == 0)
875*7c478bd9Sstevel@tonic-gate 		failed(cmd, nojc);
876*7c478bd9Sstevel@tonic-gate 
877*7c478bd9Sstevel@tonic-gate 	fg = eq("fg", cmd);
878*7c478bd9Sstevel@tonic-gate 
879*7c478bd9Sstevel@tonic-gate 	if (*++argv == 0) {
880*7c478bd9Sstevel@tonic-gate 		struct job *jp;
881*7c478bd9Sstevel@tonic-gate 		for (jp = jobcur; ; jp = jp->j_curp) {
882*7c478bd9Sstevel@tonic-gate 			if (jp == 0)
883*7c478bd9Sstevel@tonic-gate 				failed(cmd, nocurjob);
884*7c478bd9Sstevel@tonic-gate 			if (jp->j_jid)
885*7c478bd9Sstevel@tonic-gate 				break;
886*7c478bd9Sstevel@tonic-gate 		}
887*7c478bd9Sstevel@tonic-gate 		restartjob(jp, fg);
888*7c478bd9Sstevel@tonic-gate 	}
889*7c478bd9Sstevel@tonic-gate 
890*7c478bd9Sstevel@tonic-gate 	else do
891*7c478bd9Sstevel@tonic-gate 		restartjob(str2job(cmd, *argv, 1), fg);
892*7c478bd9Sstevel@tonic-gate 	while (*++argv);
893*7c478bd9Sstevel@tonic-gate 
894*7c478bd9Sstevel@tonic-gate }
895*7c478bd9Sstevel@tonic-gate 
896*7c478bd9Sstevel@tonic-gate /*
897*7c478bd9Sstevel@tonic-gate  * the builtin "wait" commands
898*7c478bd9Sstevel@tonic-gate  */
899*7c478bd9Sstevel@tonic-gate 
900*7c478bd9Sstevel@tonic-gate void
901*7c478bd9Sstevel@tonic-gate syswait(argc, argv)
902*7c478bd9Sstevel@tonic-gate int argc;
903*7c478bd9Sstevel@tonic-gate char *argv[];
904*7c478bd9Sstevel@tonic-gate {
905*7c478bd9Sstevel@tonic-gate 	register char *cmd = *argv;
906*7c478bd9Sstevel@tonic-gate 	register struct job *jp;
907*7c478bd9Sstevel@tonic-gate 	int stat;
908*7c478bd9Sstevel@tonic-gate 	int wflags;
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate 	if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg))
911*7c478bd9Sstevel@tonic-gate 		wflags = WUNTRACED;
912*7c478bd9Sstevel@tonic-gate 	else
913*7c478bd9Sstevel@tonic-gate 		wflags = 0;
914*7c478bd9Sstevel@tonic-gate 
915*7c478bd9Sstevel@tonic-gate 	if (argc == 1)
916*7c478bd9Sstevel@tonic-gate 		collectjobs(0);
917*7c478bd9Sstevel@tonic-gate 	else while (--argc) {
918*7c478bd9Sstevel@tonic-gate 		if ((jp = str2job(cmd, *++argv, 0)) == 0)
919*7c478bd9Sstevel@tonic-gate 			continue;
920*7c478bd9Sstevel@tonic-gate 		if (!(jp->j_flag & J_RUNNING))
921*7c478bd9Sstevel@tonic-gate 			continue;
922*7c478bd9Sstevel@tonic-gate 		if (waitpid(jp->j_pid, &stat, wflags) <= 0)
923*7c478bd9Sstevel@tonic-gate 			break;
924*7c478bd9Sstevel@tonic-gate 		(void) statjob(jp, stat, 0, 1);
925*7c478bd9Sstevel@tonic-gate 	}
926*7c478bd9Sstevel@tonic-gate }
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate static
929*7c478bd9Sstevel@tonic-gate sigv(cmd, sig, args)
930*7c478bd9Sstevel@tonic-gate 	char *cmd;
931*7c478bd9Sstevel@tonic-gate 	int sig;
932*7c478bd9Sstevel@tonic-gate 	char *args;
933*7c478bd9Sstevel@tonic-gate {
934*7c478bd9Sstevel@tonic-gate 	int pgrp = 0;
935*7c478bd9Sstevel@tonic-gate 	int stopme = 0;
936*7c478bd9Sstevel@tonic-gate 	pid_t id;
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate 	if (*args == '%') {
939*7c478bd9Sstevel@tonic-gate 		register struct job *jp;
940*7c478bd9Sstevel@tonic-gate 		jp = str2job(cmd, args, 1);
941*7c478bd9Sstevel@tonic-gate 		id = jp->j_pgid;
942*7c478bd9Sstevel@tonic-gate 		pgrp++;
943*7c478bd9Sstevel@tonic-gate 	} else {
944*7c478bd9Sstevel@tonic-gate 		if (*args == '-') {
945*7c478bd9Sstevel@tonic-gate 			pgrp++;
946*7c478bd9Sstevel@tonic-gate 			args++;
947*7c478bd9Sstevel@tonic-gate 		}
948*7c478bd9Sstevel@tonic-gate 		id = 0;
949*7c478bd9Sstevel@tonic-gate 		do {
950*7c478bd9Sstevel@tonic-gate 			if (*args < '0' || *args > '9') {
951*7c478bd9Sstevel@tonic-gate 				failure(cmd, badid);
952*7c478bd9Sstevel@tonic-gate 				return;
953*7c478bd9Sstevel@tonic-gate 			}
954*7c478bd9Sstevel@tonic-gate 			id = (id * 10) + (*args - '0');
955*7c478bd9Sstevel@tonic-gate 		} while (*++args);
956*7c478bd9Sstevel@tonic-gate 		if (id == 0) {
957*7c478bd9Sstevel@tonic-gate 			id = mypgid;
958*7c478bd9Sstevel@tonic-gate 			pgrp++;
959*7c478bd9Sstevel@tonic-gate 		}
960*7c478bd9Sstevel@tonic-gate 	}
961*7c478bd9Sstevel@tonic-gate 
962*7c478bd9Sstevel@tonic-gate 	if (sig == SIGSTOP) {
963*7c478bd9Sstevel@tonic-gate 		if (id == mysid || id == mypid && mypgid == mysid) {
964*7c478bd9Sstevel@tonic-gate 			failure(cmd, loginsh);
965*7c478bd9Sstevel@tonic-gate 			return;
966*7c478bd9Sstevel@tonic-gate 		}
967*7c478bd9Sstevel@tonic-gate 		if (id == mypgid && mypgid != svpgid) {
968*7c478bd9Sstevel@tonic-gate 			(void) settgid(svtgid, mypgid);
969*7c478bd9Sstevel@tonic-gate 			setpgid(0, svpgid);
970*7c478bd9Sstevel@tonic-gate 			stopme++;
971*7c478bd9Sstevel@tonic-gate 		}
972*7c478bd9Sstevel@tonic-gate 	}
973*7c478bd9Sstevel@tonic-gate 
974*7c478bd9Sstevel@tonic-gate 	if (pgrp)
975*7c478bd9Sstevel@tonic-gate 		id = -id;
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate 	if (kill(id, sig) < 0) {
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate 		switch (errno) {
980*7c478bd9Sstevel@tonic-gate 			case EPERM:
981*7c478bd9Sstevel@tonic-gate 				failure(cmd, eacces);
982*7c478bd9Sstevel@tonic-gate 				break;
983*7c478bd9Sstevel@tonic-gate 
984*7c478bd9Sstevel@tonic-gate 			case EINVAL:
985*7c478bd9Sstevel@tonic-gate 				failure(cmd, badsig);
986*7c478bd9Sstevel@tonic-gate 				break;
987*7c478bd9Sstevel@tonic-gate 
988*7c478bd9Sstevel@tonic-gate 			default:
989*7c478bd9Sstevel@tonic-gate 				if (pgrp)
990*7c478bd9Sstevel@tonic-gate 					failure(cmd, nosuchpgid);
991*7c478bd9Sstevel@tonic-gate 				else
992*7c478bd9Sstevel@tonic-gate 					failure(cmd, nosuchpid);
993*7c478bd9Sstevel@tonic-gate 				break;
994*7c478bd9Sstevel@tonic-gate 		}
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate 	} else if (sig == SIGTERM && pgrp)
997*7c478bd9Sstevel@tonic-gate 		(void) kill(id, SIGCONT);
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate 	if (stopme) {
1000*7c478bd9Sstevel@tonic-gate 		setpgid(0, mypgid);
1001*7c478bd9Sstevel@tonic-gate 		(void) settgid(mypgid, svpgid);
1002*7c478bd9Sstevel@tonic-gate 	}
1003*7c478bd9Sstevel@tonic-gate 
1004*7c478bd9Sstevel@tonic-gate }
1005*7c478bd9Sstevel@tonic-gate 
1006*7c478bd9Sstevel@tonic-gate sysstop(argc, argv)
1007*7c478bd9Sstevel@tonic-gate int argc;
1008*7c478bd9Sstevel@tonic-gate char *argv[];
1009*7c478bd9Sstevel@tonic-gate {
1010*7c478bd9Sstevel@tonic-gate 	char *cmd = *argv;
1011*7c478bd9Sstevel@tonic-gate 	if (argc <= 1)
1012*7c478bd9Sstevel@tonic-gate 		failed(usage, stopuse);
1013*7c478bd9Sstevel@tonic-gate 	while (*++argv)
1014*7c478bd9Sstevel@tonic-gate 		sigv(cmd, SIGSTOP, *argv);
1015*7c478bd9Sstevel@tonic-gate }
1016*7c478bd9Sstevel@tonic-gate 
1017*7c478bd9Sstevel@tonic-gate syskill(argc, argv)
1018*7c478bd9Sstevel@tonic-gate int argc;
1019*7c478bd9Sstevel@tonic-gate char *argv[];
1020*7c478bd9Sstevel@tonic-gate {
1021*7c478bd9Sstevel@tonic-gate 	char *cmd = *argv;
1022*7c478bd9Sstevel@tonic-gate 	int sig = SIGTERM;
1023*7c478bd9Sstevel@tonic-gate 
1024*7c478bd9Sstevel@tonic-gate 	if (argc == 1) {
1025*7c478bd9Sstevel@tonic-gate 		failure(usage, killuse);
1026*7c478bd9Sstevel@tonic-gate 		return;
1027*7c478bd9Sstevel@tonic-gate 	}
1028*7c478bd9Sstevel@tonic-gate 
1029*7c478bd9Sstevel@tonic-gate 	if (argv[1][0] == '-') {
1030*7c478bd9Sstevel@tonic-gate 
1031*7c478bd9Sstevel@tonic-gate 		if (argc == 2) {
1032*7c478bd9Sstevel@tonic-gate 
1033*7c478bd9Sstevel@tonic-gate 			register i;
1034*7c478bd9Sstevel@tonic-gate 			register cnt = 0;
1035*7c478bd9Sstevel@tonic-gate 			register char sep = 0;
1036*7c478bd9Sstevel@tonic-gate 			char buf[12];
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate 			if (!eq(argv[1], "-l")) {
1039*7c478bd9Sstevel@tonic-gate 				failure(usage, killuse);
1040*7c478bd9Sstevel@tonic-gate 				return;
1041*7c478bd9Sstevel@tonic-gate 			}
1042*7c478bd9Sstevel@tonic-gate 
1043*7c478bd9Sstevel@tonic-gate 			for (i = 1; i < MAXTRAP; i++) {
1044*7c478bd9Sstevel@tonic-gate 				if (sig2str(i, buf) < 0)
1045*7c478bd9Sstevel@tonic-gate 					continue;
1046*7c478bd9Sstevel@tonic-gate 				if (sep)
1047*7c478bd9Sstevel@tonic-gate 					prc_buff(sep);
1048*7c478bd9Sstevel@tonic-gate 				prs_buff(buf);
1049*7c478bd9Sstevel@tonic-gate 				if ((flags & ttyflg) && (++cnt % 10))
1050*7c478bd9Sstevel@tonic-gate 					sep = TAB;
1051*7c478bd9Sstevel@tonic-gate 				else
1052*7c478bd9Sstevel@tonic-gate 					sep = NL;
1053*7c478bd9Sstevel@tonic-gate 			}
1054*7c478bd9Sstevel@tonic-gate 			prc_buff(NL);
1055*7c478bd9Sstevel@tonic-gate 			return;
1056*7c478bd9Sstevel@tonic-gate 		}
1057*7c478bd9Sstevel@tonic-gate 
1058*7c478bd9Sstevel@tonic-gate 		if (str2sig(&argv[1][1], &sig)) {
1059*7c478bd9Sstevel@tonic-gate 			failure(cmd, badsig);
1060*7c478bd9Sstevel@tonic-gate 			return;
1061*7c478bd9Sstevel@tonic-gate 		}
1062*7c478bd9Sstevel@tonic-gate 		argv++;
1063*7c478bd9Sstevel@tonic-gate 	}
1064*7c478bd9Sstevel@tonic-gate 
1065*7c478bd9Sstevel@tonic-gate 	while (*++argv)
1066*7c478bd9Sstevel@tonic-gate 		sigv(cmd, sig, *argv);
1067*7c478bd9Sstevel@tonic-gate 
1068*7c478bd9Sstevel@tonic-gate }
1069*7c478bd9Sstevel@tonic-gate 
1070*7c478bd9Sstevel@tonic-gate syssusp(argc, argv)
1071*7c478bd9Sstevel@tonic-gate int argc;
1072*7c478bd9Sstevel@tonic-gate char *argv[];
1073*7c478bd9Sstevel@tonic-gate {
1074*7c478bd9Sstevel@tonic-gate 	if (argc != 1)
1075*7c478bd9Sstevel@tonic-gate 		failed(argv[0], badopt);
1076*7c478bd9Sstevel@tonic-gate 	sigv(argv[0], SIGSTOP, "0");
1077*7c478bd9Sstevel@tonic-gate }
1078