xref: /openbsd-src/bin/csh/proc.c (revision 44d35ad997e2d5789997c091f582f48f10c58ee4)
1 /*	$OpenBSD: proc.c,v 1.12 2000/06/28 19:41:10 millert Exp $	*/
2 /*	$NetBSD: proc.c,v 1.9 1995/04/29 23:21:33 mycroft Exp $	*/
3 
4 /*-
5  * Copyright (c) 1980, 1991, 1993
6  *	The Regents of the University of California.  All rights reserved.
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
39 static char sccsid[] = "@(#)proc.c	8.1 (Berkeley) 5/31/93";
40 #else
41 static char rcsid[] = "$OpenBSD: proc.c,v 1.12 2000/06/28 19:41:10 millert Exp $";
42 #endif
43 #endif /* not lint */
44 
45 #include <sys/types.h>
46 #include <sys/wait.h>
47 #include <errno.h>
48 #include <unistd.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #ifdef __STDC__
52 # include <stdarg.h>
53 #else
54 # include <varargs.h>
55 #endif
56 
57 #include "csh.h"
58 #include "dir.h"
59 #include "proc.h"
60 #include "extern.h"
61 
62 #define BIGINDEX	9	/* largest desirable job index */
63 
64 static struct rusage zru;
65 
66 static void	 pflushall __P((void));
67 static void	 pflush __P((struct process *));
68 static void	 pclrcurr __P((struct process *));
69 static void	 padd __P((struct command *));
70 static int	 pprint __P((struct process *, int));
71 static void	 ptprint __P((struct process *));
72 static void	 pads __P((Char *));
73 static void	 pkill __P((Char **v, int));
74 static struct	process
75 		*pgetcurr __P((struct process *));
76 static void	 okpcntl __P((void));
77 
78 /*
79  * pchild - called at interrupt level by the SIGCHLD signal
80  *	indicating that at least one child has terminated or stopped
81  *	thus at least one wait system call will definitely return a
82  *	childs status.  Top level routines (like pwait) must be sure
83  *	to mask interrupts when playing with the proclist data structures!
84  */
85 /* ARGUSED */
86 void
87 pchild(notused)
88 	int notused;
89 {
90     register struct process *pp;
91     register struct process *fp;
92     register int pid;
93     extern int insource;
94     int save_errno = errno;
95     union wait w;
96     int     jobflags;
97     struct rusage ru;
98 
99 loop:
100     errno = 0;			/* reset, just in case */
101     pid = wait3(&w.w_status,
102        (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru);
103 
104     if (pid <= 0) {
105 	if (errno == EINTR) {
106 	    errno = 0;
107 	    goto loop;
108 	}
109 	pnoprocesses = pid == -1;
110 	errno = save_errno;
111 	return;
112     }
113     for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
114 	if (pid == pp->p_pid)
115 	    goto found;
116     goto loop;
117 found:
118     if (pid == atoi(short2str(value(STRchild))))
119 	unsetv(STRchild);
120     pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED);
121     if (WIFSTOPPED(w)) {
122 	pp->p_flags |= PSTOPPED;
123 	pp->p_reason = w.w_stopsig;
124     }
125     else {
126 	if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime))
127 	    (void) gettimeofday(&pp->p_etime, NULL);
128 
129 	pp->p_rusage = ru;
130 	if (WIFSIGNALED(w)) {
131 	    if (w.w_termsig == SIGINT)
132 		pp->p_flags |= PINTERRUPTED;
133 	    else
134 		pp->p_flags |= PSIGNALED;
135 	    if (w.w_coredump)
136 		pp->p_flags |= PDUMPED;
137 	    pp->p_reason = w.w_termsig;
138 	}
139 	else {
140 	    pp->p_reason = w.w_retcode;
141 	    if (pp->p_reason != 0)
142 		pp->p_flags |= PAEXITED;
143 	    else
144 		pp->p_flags |= PNEXITED;
145 	}
146     }
147     jobflags = 0;
148     fp = pp;
149     do {
150 	if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 &&
151 	    !child && adrof(STRtime) &&
152 	    fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec
153 	    >= atoi(short2str(value(STRtime))))
154 	    fp->p_flags |= PTIME;
155 	jobflags |= fp->p_flags;
156     } while ((fp = fp->p_friends) != pp);
157     pp->p_flags &= ~PFOREGND;
158     if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
159 	pp->p_flags &= ~PPTIME;
160 	pp->p_flags |= PTIME;
161     }
162     if ((jobflags & (PRUNNING | PREPORTED)) == 0) {
163 	fp = pp;
164 	do {
165 	    if (fp->p_flags & PSTOPPED)
166 		fp->p_flags |= PREPORTED;
167 	} while ((fp = fp->p_friends) != pp);
168 	while (fp->p_pid != fp->p_jobid)
169 	    fp = fp->p_friends;
170 	if (jobflags & PSTOPPED) {
171 	    if (pcurrent && pcurrent != fp)
172 		pprevious = pcurrent;
173 	    pcurrent = fp;
174 	}
175 	else
176 	    pclrcurr(fp);
177 	if (jobflags & PFOREGND) {
178 	    if (jobflags & (PSIGNALED | PSTOPPED | PPTIME) ||
179 #ifdef IIASA
180 		jobflags & PAEXITED ||
181 #endif
182 		!eq(dcwd->di_name, fp->p_cwd->di_name)) {
183 		;		/* print in pjwait */
184 	    }
185 	    /* PWP: print a newline after ^C */
186 	    else if (jobflags & PINTERRUPTED) {
187 		(void) vis_fputc('\r' | QUOTE, cshout);
188 		(void) fputc('\n', cshout);
189 	    }
190 	}
191 	else {
192 	    if (jobflags & PNOTIFY || adrof(STRnotify)) {
193 		(void) vis_fputc('\r' | QUOTE, cshout);
194 		(void) fputc('\n', cshout);
195 		(void) pprint(pp, NUMBER | NAME | REASON);
196 		if ((jobflags & PSTOPPED) == 0)
197 		    pflush(pp);
198 	    }
199 	    else {
200 		fp->p_flags |= PNEEDNOTE;
201 		neednote++;
202 	    }
203 	}
204     }
205     goto loop;
206 }
207 
208 void
209 pnote()
210 {
211     register struct process *pp;
212     int     flags;
213     sigset_t sigset, osigset;
214 
215     neednote = 0;
216     sigemptyset(&sigset);
217     sigaddset(&sigset, SIGCHLD);
218     for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) {
219 	if (pp->p_flags & PNEEDNOTE) {
220 	    sigprocmask(SIG_BLOCK, &sigset, &osigset);
221 	    pp->p_flags &= ~PNEEDNOTE;
222 	    flags = pprint(pp, NUMBER | NAME | REASON);
223 	    if ((flags & (PRUNNING | PSTOPPED)) == 0)
224 		pflush(pp);
225 	    sigprocmask(SIG_SETMASK, &osigset, NULL);
226 	}
227     }
228 }
229 
230 /*
231  * pwait - wait for current job to terminate, maintaining integrity
232  *	of current and previous job indicators.
233  */
234 void
235 pwait()
236 {
237     register struct process *fp, *pp;
238     sigset_t sigset, osigset;
239 
240     /*
241      * Here's where dead procs get flushed.
242      */
243     sigemptyset(&sigset);
244     sigaddset(&sigset, SIGCHLD);
245     sigprocmask(SIG_BLOCK, &sigset, &osigset);
246     for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next)
247 	if (pp->p_pid == 0) {
248 	    fp->p_next = pp->p_next;
249 	    xfree((ptr_t) pp->p_command);
250 	    if (pp->p_cwd && --pp->p_cwd->di_count == 0)
251 		if (pp->p_cwd->di_next == 0)
252 		    dfree(pp->p_cwd);
253 	    xfree((ptr_t) pp);
254 	    pp = fp;
255 	}
256     sigprocmask(SIG_SETMASK, &osigset, NULL);
257     pjwait(pcurrjob);
258 }
259 
260 
261 /*
262  * pjwait - wait for a job to finish or become stopped
263  *	It is assumed to be in the foreground state (PFOREGND)
264  */
265 void
266 pjwait(pp)
267     register struct process *pp;
268 {
269     register struct process *fp;
270     int     jobflags, reason;
271     sigset_t sigset, osigset;
272 
273     while (pp->p_pid != pp->p_jobid)
274 	pp = pp->p_friends;
275     fp = pp;
276 
277     do {
278 	if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING)
279 	    (void) fprintf(csherr, "BUG: waiting for background job!\n");
280     } while ((fp = fp->p_friends) != pp);
281     /*
282      * Now keep pausing as long as we are not interrupted (SIGINT), and the
283      * target process, or any of its friends, are running
284      */
285     fp = pp;
286     sigemptyset(&sigset);
287     sigaddset(&sigset, SIGCHLD);
288     sigprocmask(SIG_BLOCK, &sigset, &osigset);
289     for (;;) {
290 	sigemptyset(&sigset);
291 	sigaddset(&sigset, SIGCHLD);
292 	sigprocmask(SIG_BLOCK, &sigset, NULL);
293 	jobflags = 0;
294 	do
295 	    jobflags |= fp->p_flags;
296 	while ((fp = (fp->p_friends)) != pp);
297 	if ((jobflags & PRUNNING) == 0)
298 	    break;
299 #ifdef JOBDEBUG
300 	(void) fprintf(csherr, "starting to sigsuspend for  SIGCHLD on %d\n",
301 		       fp->p_pid);
302 #endif				/* JOBDEBUG */
303 	sigset = osigset;
304 	sigdelset(&sigset, SIGCHLD);
305 	sigsuspend(&sigset);
306     }
307     sigprocmask(SIG_SETMASK, &osigset, NULL);
308     if (tpgrp > 0)		/* get tty back */
309 	(void) tcsetpgrp(FSHTTY, tpgrp);
310     if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) ||
311 	!eq(dcwd->di_name, fp->p_cwd->di_name)) {
312 	if (jobflags & PSTOPPED) {
313 	    (void) fputc('\n', cshout);
314 	    if (adrof(STRlistjobs)) {
315 		Char   *jobcommand[3];
316 
317 		jobcommand[0] = STRjobs;
318 		if (eq(value(STRlistjobs), STRlong))
319 		    jobcommand[1] = STRml;
320 		else
321 		    jobcommand[1] = NULL;
322 		jobcommand[2] = NULL;
323 
324 		dojobs(jobcommand, NULL);
325 		(void) pprint(pp, SHELLDIR);
326 	    }
327 	    else
328 		(void) pprint(pp, AREASON | SHELLDIR);
329 	}
330 	else
331 	    (void) pprint(pp, AREASON | SHELLDIR);
332     }
333     if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr &&
334 	(!gointr || !eq(gointr, STRminus))) {
335 	if ((jobflags & PSTOPPED) == 0)
336 	    pflush(pp);
337 	pintr1(0);
338 	/* NOTREACHED */
339     }
340     reason = 0;
341     fp = pp;
342     do {
343 	if (fp->p_reason)
344 	    reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ?
345 		fp->p_reason | META : fp->p_reason;
346     } while ((fp = fp->p_friends) != pp);
347     if ((reason != 0) && (adrof(STRprintexitvalue))) {
348 	(void) fprintf(cshout, "Exit %d\n", reason);
349     }
350     set(STRstatus, putn(reason));
351     if (reason && exiterr)
352 	exitstat();
353     pflush(pp);
354 }
355 
356 /*
357  * dowait - wait for all processes to finish
358  */
359 void
360 /*ARGSUSED*/
361 dowait(v, t)
362     Char **v;
363     struct command *t;
364 {
365     register struct process *pp;
366     sigset_t sigset, osigset;
367 
368     pjobs++;
369     sigemptyset(&sigset);
370     sigaddset(&sigset, SIGCHLD);
371     sigprocmask(SIG_BLOCK, &sigset, &osigset);
372 loop:
373     for (pp = proclist.p_next; pp; pp = pp->p_next)
374 	if (pp->p_pid &&	/* pp->p_pid == pp->p_jobid && */
375 	    pp->p_flags & PRUNNING) {
376 	    sigemptyset(&sigset);
377 	    sigsuspend(&sigset);
378 	    goto loop;
379 	}
380     sigprocmask(SIG_SETMASK, &osigset, NULL);
381     pjobs = 0;
382 }
383 
384 /*
385  * pflushall - flush all jobs from list (e.g. at fork())
386  */
387 static void
388 pflushall()
389 {
390     register struct process *pp;
391 
392     for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
393 	if (pp->p_pid)
394 	    pflush(pp);
395 }
396 
397 /*
398  * pflush - flag all process structures in the same job as the
399  *	the argument process for deletion.  The actual free of the
400  *	space is not done here since pflush is called at interrupt level.
401  */
402 static void
403 pflush(pp)
404     register struct process *pp;
405 {
406     register struct process *np;
407     register int idx;
408 
409     if (pp->p_pid == 0) {
410 	(void) fprintf(csherr, "BUG: process flushed twice");
411 	return;
412     }
413     while (pp->p_pid != pp->p_jobid)
414 	pp = pp->p_friends;
415     pclrcurr(pp);
416     if (pp == pcurrjob)
417 	pcurrjob = 0;
418     idx = pp->p_index;
419     np = pp;
420     do {
421 	np->p_index = np->p_pid = 0;
422 	np->p_flags &= ~PNEEDNOTE;
423     } while ((np = np->p_friends) != pp);
424     if (idx == pmaxindex) {
425 	for (np = proclist.p_next, idx = 0; np; np = np->p_next)
426 	    if (np->p_index > idx)
427 		idx = np->p_index;
428 	pmaxindex = idx;
429     }
430 }
431 
432 /*
433  * pclrcurr - make sure the given job is not the current or previous job;
434  *	pp MUST be the job leader
435  */
436 static void
437 pclrcurr(pp)
438     register struct process *pp;
439 {
440 
441     if (pp == pcurrent)
442 	if (pprevious != NULL) {
443 	    pcurrent = pprevious;
444 	    pprevious = pgetcurr(pp);
445 	}
446 	else {
447 	    pcurrent = pgetcurr(pp);
448 	    pprevious = pgetcurr(pp);
449 	}
450     else if (pp == pprevious)
451 	pprevious = pgetcurr(pp);
452 }
453 
454 /* +4 here is 1 for '\0', 1 ea for << >& >> */
455 static Char command[PMAXLEN + 4];
456 static int cmdlen;
457 static Char *cmdp;
458 
459 /*
460  * palloc - allocate a process structure and fill it up.
461  *	an important assumption is made that the process is running.
462  */
463 void
464 palloc(pid, t)
465     int     pid;
466     register struct command *t;
467 {
468     register struct process *pp;
469     int     i;
470 
471     pp = (struct process *) xcalloc(1, (size_t) sizeof(struct process));
472     pp->p_pid = pid;
473     pp->p_flags = t->t_dflg & F_AMPERSAND ? PRUNNING : PRUNNING | PFOREGND;
474     if (t->t_dflg & F_TIME)
475 	pp->p_flags |= PPTIME;
476     cmdp = command;
477     cmdlen = 0;
478     padd(t);
479     *cmdp++ = 0;
480     if (t->t_dflg & F_PIPEOUT) {
481 	pp->p_flags |= PPOU;
482 	if (t->t_dflg & F_STDERR)
483 	    pp->p_flags |= PERR;
484     }
485     pp->p_command = Strsave(command);
486     if (pcurrjob) {
487 	struct process *fp;
488 
489 	/* careful here with interrupt level */
490 	pp->p_cwd = 0;
491 	pp->p_index = pcurrjob->p_index;
492 	pp->p_friends = pcurrjob;
493 	pp->p_jobid = pcurrjob->p_pid;
494 	for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
495 	    continue;
496 	fp->p_friends = pp;
497     }
498     else {
499 	pcurrjob = pp;
500 	pp->p_jobid = pid;
501 	pp->p_friends = pp;
502 	pp->p_cwd = dcwd;
503 	dcwd->di_count++;
504 	if (pmaxindex < BIGINDEX)
505 	    pp->p_index = ++pmaxindex;
506 	else {
507 	    struct process *np;
508 
509 	    for (i = 1;; i++) {
510 		for (np = proclist.p_next; np; np = np->p_next)
511 		    if (np->p_index == i)
512 			goto tryagain;
513 		pp->p_index = i;
514 		if (i > pmaxindex)
515 		    pmaxindex = i;
516 		break;
517 	tryagain:;
518 	    }
519 	}
520 	if (pcurrent == NULL)
521 	    pcurrent = pp;
522 	else if (pprevious == NULL)
523 	    pprevious = pp;
524     }
525     pp->p_next = proclist.p_next;
526     proclist.p_next = pp;
527     (void) gettimeofday(&pp->p_btime, NULL);
528 }
529 
530 static void
531 padd(t)
532     register struct command *t;
533 {
534     Char  **argp;
535 
536     if (t == 0)
537 	return;
538     switch (t->t_dtyp) {
539 
540     case NODE_PAREN:
541 	pads(STRLparensp);
542 	padd(t->t_dspr);
543 	pads(STRspRparen);
544 	break;
545 
546     case NODE_COMMAND:
547 	for (argp = t->t_dcom; *argp; argp++) {
548 	    pads(*argp);
549 	    if (argp[1])
550 		pads(STRspace);
551 	}
552 	break;
553 
554     case NODE_OR:
555     case NODE_AND:
556     case NODE_PIPE:
557     case NODE_LIST:
558 	padd(t->t_dcar);
559 	switch (t->t_dtyp) {
560 	case NODE_OR:
561 	    pads(STRspor2sp);
562 	    break;
563 	case NODE_AND:
564 	    pads(STRspand2sp);
565 	    break;
566 	case NODE_PIPE:
567 	    pads(STRsporsp);
568 	    break;
569 	case NODE_LIST:
570 	    pads(STRsemisp);
571 	    break;
572 	}
573 	padd(t->t_dcdr);
574 	return;
575     }
576     if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) {
577 	pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp);
578 	pads(t->t_dlef);
579     }
580     if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) {
581 	pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow);
582 	if (t->t_dflg & F_STDERR)
583 	    pads(STRand);
584 	pads(STRspace);
585 	pads(t->t_drit);
586     }
587 }
588 
589 static void
590 pads(cp)
591     Char   *cp;
592 {
593     register int i;
594 
595     /*
596      * Avoid the Quoted Space alias hack! Reported by:
597      * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks)
598      */
599     if (cp[0] == STRQNULL[0])
600 	cp++;
601 
602     i = Strlen(cp);
603 
604     if (cmdlen >= PMAXLEN)
605 	return;
606     if (cmdlen + i >= PMAXLEN) {
607 	(void) Strcpy(cmdp, STRsp3dots);
608 	cmdlen = PMAXLEN;
609 	cmdp += 4;
610 	return;
611     }
612     (void) Strcpy(cmdp, cp);
613     cmdp += i;
614     cmdlen += i;
615 }
616 
617 /*
618  * psavejob - temporarily save the current job on a one level stack
619  *	so another job can be created.  Used for { } in exp6
620  *	and `` in globbing.
621  */
622 void
623 psavejob()
624 {
625 
626     pholdjob = pcurrjob;
627     pcurrjob = NULL;
628 }
629 
630 /*
631  * prestjob - opposite of psavejob.  This may be missed if we are interrupted
632  *	somewhere, but pendjob cleans up anyway.
633  */
634 void
635 prestjob()
636 {
637 
638     pcurrjob = pholdjob;
639     pholdjob = NULL;
640 }
641 
642 /*
643  * pendjob - indicate that a job (set of commands) has been completed
644  *	or is about to begin.
645  */
646 void
647 pendjob()
648 {
649     register struct process *pp, *tp;
650 
651     if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) {
652 	pp = pcurrjob;
653 	while (pp->p_pid != pp->p_jobid)
654 	    pp = pp->p_friends;
655 	(void) fprintf(cshout, "[%d]", pp->p_index);
656 	tp = pp;
657 	do {
658 	    (void) fprintf(cshout, " %d", pp->p_pid);
659 	    pp = pp->p_friends;
660 	} while (pp != tp);
661 	(void) fputc('\n', cshout);
662     }
663     pholdjob = pcurrjob = 0;
664 }
665 
666 /*
667  * pprint - print a job
668  */
669 static int
670 pprint(pp, flag)
671     register struct process *pp;
672     bool    flag;
673 {
674     register status, reason;
675     struct process *tp;
676     int     jobflags, pstatus;
677     bool hadnl = 1;	/* did we just have a newline */
678     char   *format;
679 
680     (void) fpurge(cshout);
681 
682     while (pp->p_pid != pp->p_jobid)
683 	pp = pp->p_friends;
684     if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
685 	pp->p_flags &= ~PPTIME;
686 	pp->p_flags |= PTIME;
687     }
688     tp = pp;
689     status = reason = -1;
690     jobflags = 0;
691     do {
692 	jobflags |= pp->p_flags;
693 	pstatus = pp->p_flags & PALLSTATES;
694 	if (tp != pp && !hadnl && !(flag & FANCY) &&
695 	    ((pstatus == status && pp->p_reason == reason) ||
696 	     !(flag & REASON))) {
697 	    (void) fputc(' ', cshout);
698 	    hadnl = 0;
699 	}
700 	else {
701 	    if (tp != pp && !hadnl) {
702 		(void) fputc('\n', cshout);
703 		hadnl = 1;
704 	    }
705 	    if (flag & NUMBER) {
706 		if (pp == tp)
707 		    (void) fprintf(cshout, "[%d]%s %c ", pp->p_index,
708 			    pp->p_index < 10 ? " " : "",
709 			    pp == pcurrent ? '+' :
710 			    (pp == pprevious ? '-' : ' '));
711 		else
712 		    (void) fprintf(cshout, "       ");
713 		hadnl = 0;
714 	    }
715 	    if (flag & FANCY) {
716 		(void) fprintf(cshout, "%5d ", pp->p_pid);
717 		hadnl = 0;
718 	    }
719 	    if (flag & (REASON | AREASON)) {
720 		if (flag & NAME)
721 		    format = "%-23s";
722 		else
723 		    format = "%s";
724 		if (pstatus == status)
725 		    if (pp->p_reason == reason) {
726 			(void) fprintf(cshout, format, "");
727 			hadnl = 0;
728 			goto prcomd;
729 		    }
730 		    else
731 			reason = pp->p_reason;
732 		else {
733 		    status = pstatus;
734 		    reason = pp->p_reason;
735 		}
736 		switch (status) {
737 
738 		case PRUNNING:
739 		    (void) fprintf(cshout, format, "Running ");
740 		    hadnl = 0;
741 		    break;
742 
743 		case PINTERRUPTED:
744 		case PSTOPPED:
745 		case PSIGNALED:
746 		    /*
747 		     * tell what happened to the background job
748 		     * From: Michael Schroeder
749 		     * <mlschroe@immd4.informatik.uni-erlangen.de>
750 		     */
751 		    if ((flag & REASON)
752 			|| ((flag & AREASON)
753 			    && reason != SIGINT
754 			    && (reason != SIGPIPE
755 				|| (pp->p_flags & PPOU) == 0))) {
756 			(void) fprintf(cshout, format,
757 				       sys_siglist[(unsigned char)
758 						   pp->p_reason]);
759 			hadnl = 0;
760 		    }
761 		    break;
762 
763 		case PNEXITED:
764 		case PAEXITED:
765 		    if (flag & REASON) {
766 			if (pp->p_reason)
767 			    (void) fprintf(cshout, "Exit %-18d", pp->p_reason);
768 			else
769 			    (void) fprintf(cshout, format, "Done");
770 			hadnl = 0;
771 		    }
772 		    break;
773 
774 		default:
775 		    (void) fprintf(csherr, "BUG: status=%-9o", status);
776 		}
777 	    }
778 	}
779 prcomd:
780 	if (flag & NAME) {
781 	    (void) fprintf(cshout, "%s", vis_str(pp->p_command));
782 	    if (pp->p_flags & PPOU)
783 		(void) fprintf(cshout, " |");
784 	    if (pp->p_flags & PERR)
785 		(void) fputc('&', cshout);
786 	    hadnl = 0;
787 	}
788 	if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) {
789 	    (void) fprintf(cshout, " (core dumped)");
790 	    hadnl = 0;
791 	}
792 	if (tp == pp->p_friends) {
793 	    if (flag & AMPERSAND) {
794 		(void) fprintf(cshout, " &");
795 		hadnl = 0;
796 	    }
797 	    if (flag & JOBDIR &&
798 		!eq(tp->p_cwd->di_name, dcwd->di_name)) {
799 		(void) fprintf(cshout, " (wd: ");
800 		dtildepr(value(STRhome), tp->p_cwd->di_name);
801 		(void) fputc(')', cshout);
802 		hadnl = 0;
803 	    }
804 	}
805 	if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) {
806 	    if (!hadnl)
807 		(void) fprintf(cshout, "\n\t");
808 	    prusage(&zru, &pp->p_rusage, &pp->p_etime,
809 		    &pp->p_btime);
810 	    hadnl = 1;
811 	}
812 	if (tp == pp->p_friends) {
813 	    if (!hadnl) {
814 		(void) fputc('\n', cshout);
815 		hadnl = 1;
816 	    }
817 	    if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
818 		(void) fprintf(cshout, "(wd now: ");
819 		dtildepr(value(STRhome), dcwd->di_name);
820 		(void) fprintf(cshout, ")\n");
821 		hadnl = 1;
822 	    }
823 	}
824     } while ((pp = pp->p_friends) != tp);
825     if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) {
826 	if (jobflags & NUMBER)
827 	    (void) fprintf(cshout, "       ");
828 	ptprint(tp);
829 	hadnl = 1;
830     }
831     (void) fflush(cshout);
832     return (jobflags);
833 }
834 
835 static void
836 ptprint(tp)
837     register struct process *tp;
838 {
839     struct timeval tetime, diff;
840     static struct timeval ztime;
841     struct rusage ru;
842     static struct rusage zru;
843     register struct process *pp = tp;
844 
845     ru = zru;
846     tetime = ztime;
847     do {
848 	ruadd(&ru, &pp->p_rusage);
849 	timersub(&pp->p_etime, &pp->p_btime, &diff);
850 	if (timercmp(&diff, &tetime, >))
851 	    tetime = diff;
852     } while ((pp = pp->p_friends) != tp);
853     prusage(&zru, &ru, &tetime, &ztime);
854 }
855 
856 /*
857  * dojobs - print all jobs
858  */
859 void
860 /*ARGSUSED*/
861 dojobs(v, t)
862     Char **v;
863     struct command *t;
864 {
865     register struct process *pp;
866     register int flag = NUMBER | NAME | REASON;
867     int     i;
868 
869     if (chkstop)
870 	chkstop = 2;
871     if (*++v) {
872 	if (v[1] || !eq(*v, STRml))
873 	    stderror(ERR_JOBS);
874 	flag |= FANCY | JOBDIR;
875     }
876     for (i = 1; i <= pmaxindex; i++)
877 	for (pp = proclist.p_next; pp; pp = pp->p_next)
878 	    if (pp->p_index == i && pp->p_pid == pp->p_jobid) {
879 		pp->p_flags &= ~PNEEDNOTE;
880 		if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED)))
881 		    pflush(pp);
882 		break;
883 	    }
884 }
885 
886 /*
887  * dofg - builtin - put the job into the foreground
888  */
889 void
890 /*ARGSUSED*/
891 dofg(v, t)
892     Char **v;
893     struct command *t;
894 {
895     register struct process *pp;
896 
897     okpcntl();
898     ++v;
899     do {
900 	pp = pfind(*v);
901 	pstart(pp, 1);
902 	pjwait(pp);
903     } while (*v && *++v);
904 }
905 
906 /*
907  * %... - builtin - put the job into the foreground
908  */
909 void
910 /*ARGSUSED*/
911 dofg1(v, t)
912     Char **v;
913     struct command *t;
914 {
915     register struct process *pp;
916 
917     okpcntl();
918     pp = pfind(v[0]);
919     pstart(pp, 1);
920     pjwait(pp);
921 }
922 
923 /*
924  * dobg - builtin - put the job into the background
925  */
926 void
927 /*ARGSUSED*/
928 dobg(v, t)
929     Char **v;
930     struct command *t;
931 {
932     register struct process *pp;
933 
934     okpcntl();
935     ++v;
936     do {
937 	pp = pfind(*v);
938 	pstart(pp, 0);
939     } while (*v && *++v);
940 }
941 
942 /*
943  * %... & - builtin - put the job into the background
944  */
945 void
946 /*ARGSUSED*/
947 dobg1(v, t)
948     Char **v;
949     struct command *t;
950 {
951     register struct process *pp;
952 
953     pp = pfind(v[0]);
954     pstart(pp, 0);
955 }
956 
957 /*
958  * dostop - builtin - stop the job
959  */
960 void
961 /*ARGSUSED*/
962 dostop(v, t)
963     Char **v;
964     struct command *t;
965 {
966     pkill(++v, SIGSTOP);
967 }
968 
969 /*
970  * dokill - builtin - superset of kill (1)
971  */
972 void
973 /*ARGSUSED*/
974 dokill(v, t)
975     Char **v;
976     struct command *t;
977 {
978     register int signum = SIGTERM;
979     register char *name;
980 
981     v++;
982     if (v[0] && v[0][0] == '-') {
983 	if (v[0][1] == 'l') {
984 	    if (v[1]) {
985 		if (!Isdigit(v[1][0]))
986 		    stderror(ERR_NAME | ERR_BADSIG);
987 
988 		signum = atoi(short2str(v[1]));
989 		if (signum < 0 || signum >= NSIG)
990 		    stderror(ERR_NAME | ERR_BADSIG);
991 		else if (signum == 0)
992 		    (void) fputc('0', cshout); /* 0's symbolic name is '0' */
993 		else
994 		    (void) fprintf(cshout, "%s ", sys_signame[signum]);
995 	    } else {
996 		for (signum = 1; signum < NSIG; signum++) {
997 		    (void) fprintf(cshout, "%s ", sys_signame[signum]);
998 		    if (signum == NSIG / 2)
999 			(void) fputc('\n', cshout);
1000 	    	}
1001 	    }
1002 	    (void) fputc('\n', cshout);
1003 	    return;
1004 	}
1005 	if (Isdigit(v[0][1])) {
1006 	    signum = atoi(short2str(v[0] + 1));
1007 	    if (signum < 0 || signum > NSIG)
1008 		stderror(ERR_NAME | ERR_BADSIG);
1009 	}
1010 	else {
1011 	    if (v[0][1] == 's' && (Isspace(v[0][2]) || v[0][2] == '\0')) {
1012 		v++;
1013 		name = short2str(&v[0][0]);
1014 	    } else {
1015 		name = short2str(&v[0][1]);
1016 	    }
1017 
1018 	    if (v[0] == NULL || v[1] == NULL) {
1019 		stderror(ERR_NAME | ERR_TOOFEW);
1020 		return;
1021 	    }
1022 
1023 	    for (signum = 1; signum < NSIG; signum++)
1024 		if (!strcasecmp(sys_signame[signum], name) ||
1025 		    (strlen(name) > 3 && !strncasecmp("SIG", name, 3) &&
1026 		     !strcasecmp(sys_signame[signum], name + 3)))
1027 			break;
1028 
1029 	    if (signum == NSIG) {
1030 		if (name[0] == '0')
1031 		    signum = 0;
1032 		else {
1033 		    setname(vis_str(&v[0][0]));
1034 		    stderror(ERR_NAME | ERR_UNKSIG);
1035 		}
1036 	    }
1037 	}
1038 	v++;
1039     }
1040     pkill(v, signum);
1041 }
1042 
1043 static void
1044 pkill(v, signum)
1045     Char  **v;
1046     int     signum;
1047 {
1048     register struct process *pp, *np;
1049     register int jobflags = 0;
1050     int     pid, err1 = 0;
1051     sigset_t sigset;
1052     Char   *cp;
1053 
1054     sigemptyset(&sigset);
1055     sigaddset(&sigset, SIGCHLD);
1056     if (setintr)
1057 	sigaddset(&sigset, SIGINT);
1058     sigprocmask(SIG_BLOCK, &sigset, NULL);
1059     gflag = 0, tglob(v);
1060     if (gflag) {
1061 	v = globall(v);
1062 	if (v == 0)
1063 	    stderror(ERR_NAME | ERR_NOMATCH);
1064     }
1065     else {
1066 	v = gargv = saveblk(v);
1067 	trim(v);
1068     }
1069 
1070     while (v && (cp = *v)) {
1071 	if (*cp == '%') {
1072 	    np = pp = pfind(cp);
1073 	    do
1074 		jobflags |= np->p_flags;
1075 	    while ((np = np->p_friends) != pp);
1076 	    switch (signum) {
1077 
1078 	    case SIGSTOP:
1079 	    case SIGTSTP:
1080 	    case SIGTTIN:
1081 	    case SIGTTOU:
1082 		if ((jobflags & PRUNNING) == 0) {
1083 		    (void) fprintf(csherr, "%s: Already suspended\n",
1084 				   vis_str(cp));
1085 		    err1++;
1086 		    goto cont;
1087 		}
1088 		break;
1089 		/*
1090 		 * suspend a process, kill -CONT %, then type jobs; the shell
1091 		 * says it is suspended, but it is running; thanks jaap..
1092 		 */
1093 	    case SIGCONT:
1094 		pstart(pp, 0);
1095 		goto cont;
1096 	    }
1097 	    if (kill(-pp->p_jobid, signum) < 0) {
1098 		(void) fprintf(csherr, "%s: %s\n", vis_str(cp),
1099 			       strerror(errno));
1100 		err1++;
1101 	    }
1102 	    if (signum == SIGTERM || signum == SIGHUP)
1103 		(void) kill(-pp->p_jobid, SIGCONT);
1104 	}
1105 	else if (!(Isdigit(*cp) || *cp == '-'))
1106 	    stderror(ERR_NAME | ERR_JOBARGS);
1107 	else {
1108 	    char *ep;
1109 	    char *pidnam = short2str(cp);
1110 
1111 	    pid = strtol(pidnam, &ep, 10);
1112 	    if (!*pidnam || *ep) {
1113 		(void) fprintf(csherr, "%s: illegal process id\n", pidnam);
1114 		err1++;
1115 		goto cont;
1116 	    }
1117 	    if (kill((pid_t) pid, signum) < 0) {
1118 		(void) fprintf(csherr, "%d: %s\n", pid, strerror(errno));
1119 		err1++;
1120 		goto cont;
1121 	    }
1122 	    if (signum == SIGTERM || signum == SIGHUP)
1123 		(void) kill((pid_t) pid, SIGCONT);
1124 	}
1125 cont:
1126 	v++;
1127     }
1128     if (gargv)
1129 	blkfree(gargv), gargv = 0;
1130     sigprocmask(SIG_UNBLOCK, &sigset, NULL);
1131     if (err1)
1132 	stderror(ERR_SILENT);
1133 }
1134 
1135 /*
1136  * pstart - start the job in foreground/background
1137  */
1138 void
1139 pstart(pp, foregnd)
1140     register struct process *pp;
1141     int     foregnd;
1142 {
1143     register struct process *np;
1144     sigset_t sigset, osigset;
1145     long    jobflags = 0;
1146 
1147     sigemptyset(&sigset);
1148     sigaddset(&sigset, SIGCHLD);
1149     sigprocmask(SIG_BLOCK, &sigset, &osigset);
1150     np = pp;
1151     do {
1152 	jobflags |= np->p_flags;
1153 	if (np->p_flags & (PRUNNING | PSTOPPED)) {
1154 	    np->p_flags |= PRUNNING;
1155 	    np->p_flags &= ~PSTOPPED;
1156 	    if (foregnd)
1157 		np->p_flags |= PFOREGND;
1158 	    else
1159 		np->p_flags &= ~PFOREGND;
1160 	}
1161     } while ((np = np->p_friends) != pp);
1162     if (!foregnd)
1163 	pclrcurr(pp);
1164     (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND);
1165     if (foregnd)
1166 	(void) tcsetpgrp(FSHTTY, pp->p_jobid);
1167     if (jobflags & PSTOPPED)
1168 	(void) kill(-pp->p_jobid, SIGCONT);
1169     sigprocmask(SIG_SETMASK, &osigset, NULL);
1170 }
1171 
1172 void
1173 panystop(neednl)
1174     bool    neednl;
1175 {
1176     register struct process *pp;
1177 
1178     chkstop = 2;
1179     for (pp = proclist.p_next; pp; pp = pp->p_next)
1180 	if (pp->p_flags & PSTOPPED)
1181 	    stderror(ERR_STOPPED, neednl ? "\n" : "");
1182 }
1183 
1184 struct process *
1185 pfind(cp)
1186     Char   *cp;
1187 {
1188     register struct process *pp, *np;
1189 
1190     if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) {
1191 	if (pcurrent == NULL)
1192 	    stderror(ERR_NAME | ERR_JOBCUR);
1193 	return (pcurrent);
1194     }
1195     if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) {
1196 	if (pprevious == NULL)
1197 	    stderror(ERR_NAME | ERR_JOBPREV);
1198 	return (pprevious);
1199     }
1200     if (Isdigit(cp[1])) {
1201 	int     idx = atoi(short2str(cp + 1));
1202 
1203 	for (pp = proclist.p_next; pp; pp = pp->p_next)
1204 	    if (pp->p_index == idx && pp->p_pid == pp->p_jobid)
1205 		return (pp);
1206 	stderror(ERR_NAME | ERR_NOSUCHJOB);
1207     }
1208     np = NULL;
1209     for (pp = proclist.p_next; pp; pp = pp->p_next)
1210 	if (pp->p_pid == pp->p_jobid) {
1211 	    if (cp[1] == '?') {
1212 		register Char *dp;
1213 
1214 		for (dp = pp->p_command; *dp; dp++) {
1215 		    if (*dp != cp[2])
1216 			continue;
1217 		    if (prefix(cp + 2, dp))
1218 			goto match;
1219 		}
1220 	    }
1221 	    else if (prefix(cp + 1, pp->p_command)) {
1222 	match:
1223 		if (np)
1224 		    stderror(ERR_NAME | ERR_AMBIG);
1225 		np = pp;
1226 	    }
1227 	}
1228     if (np)
1229 	return (np);
1230     stderror(ERR_NAME | (cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB));
1231     /* NOTREACHED */
1232     return (0);
1233 }
1234 
1235 
1236 /*
1237  * pgetcurr - find most recent job that is not pp, preferably stopped
1238  */
1239 static struct process *
1240 pgetcurr(pp)
1241     register struct process *pp;
1242 {
1243     register struct process *np;
1244     register struct process *xp = NULL;
1245 
1246     for (np = proclist.p_next; np; np = np->p_next)
1247 	if (np != pcurrent && np != pp && np->p_pid &&
1248 	    np->p_pid == np->p_jobid) {
1249 	    if (np->p_flags & PSTOPPED)
1250 		return (np);
1251 	    if (xp == NULL)
1252 		xp = np;
1253 	}
1254     return (xp);
1255 }
1256 
1257 /*
1258  * donotify - flag the job so as to report termination asynchronously
1259  */
1260 void
1261 /*ARGSUSED*/
1262 donotify(v, t)
1263     Char **v;
1264     struct command *t;
1265 {
1266     register struct process *pp;
1267 
1268     pp = pfind(*++v);
1269     pp->p_flags |= PNOTIFY;
1270 }
1271 
1272 /*
1273  * Do the fork and whatever should be done in the child side that
1274  * should not be done if we are not forking at all (like for simple builtin's)
1275  * Also do everything that needs any signals fiddled with in the parent side
1276  *
1277  * Wanttty tells whether process and/or tty pgrps are to be manipulated:
1278  *	-1:	leave tty alone; inherit pgrp from parent
1279  *	 0:	already have tty; manipulate process pgrps only
1280  *	 1:	want to claim tty; manipulate process and tty pgrps
1281  * It is usually just the value of tpgrp.
1282  */
1283 
1284 int
1285 pfork(t, wanttty)
1286     struct command *t;		/* command we are forking for */
1287     int     wanttty;
1288 {
1289     register int pid;
1290     bool    ignint = 0;
1291     int     pgrp;
1292     sigset_t sigset, osigset;
1293 
1294     /*
1295      * A child will be uninterruptible only under very special conditions.
1296      * Remember that the semantics of '&' is implemented by disconnecting the
1297      * process from the tty so signals do not need to ignored just for '&'.
1298      * Thus signals are set to default action for children unless: we have had
1299      * an "onintr -" (then specifically ignored) we are not playing with
1300      * signals (inherit action)
1301      */
1302     if (setintr)
1303 	ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT))
1304 	    || (gointr && eq(gointr, STRminus));
1305     /*
1306      * Check for maximum nesting of 16 processes to avoid Forking loops
1307      */
1308     if (child == 16)
1309 	stderror(ERR_NESTING, 16);
1310     /*
1311      * Hold SIGCHLD until we have the process installed in our table.
1312      */
1313     sigemptyset(&sigset);
1314     sigaddset(&sigset, SIGCHLD);
1315     sigprocmask(SIG_BLOCK, &sigset, &osigset);
1316     while ((pid = fork()) < 0)
1317 	if (setintr == 0)
1318 	    (void) sleep(FORKSLEEP);
1319 	else {
1320 	    sigprocmask(SIG_SETMASK, &osigset, NULL);
1321 	    stderror(ERR_NOPROC);
1322 	}
1323     if (pid == 0) {
1324 	settimes();
1325 	pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
1326 	pflushall();
1327 	pcurrjob = NULL;
1328 	child++;
1329 	if (setintr) {
1330 	    setintr = 0;	/* until I think otherwise */
1331 	    /*
1332 	     * Children just get blown away on SIGINT, SIGQUIT unless "onintr
1333 	     * -" seen.
1334 	     */
1335 	    (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
1336 	    (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
1337 	    if (wanttty >= 0) {
1338 		/* make stoppable */
1339 		(void) signal(SIGTSTP, SIG_DFL);
1340 		(void) signal(SIGTTIN, SIG_DFL);
1341 		(void) signal(SIGTTOU, SIG_DFL);
1342 	    }
1343 	    (void) signal(SIGTERM, parterm);
1344 	}
1345 	else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) {
1346 	    (void) signal(SIGINT, SIG_IGN);
1347 	    (void) signal(SIGQUIT, SIG_IGN);
1348 	}
1349 	pgetty(wanttty, pgrp);
1350 	/*
1351 	 * Nohup and nice apply only to NODE_COMMAND's but it would be nice
1352 	 * (?!?) if you could say "nohup (foo;bar)" Then the parser would have
1353 	 * to know about nice/nohup/time
1354 	 */
1355 	if (t->t_dflg & F_NOHUP)
1356 	    (void) signal(SIGHUP, SIG_IGN);
1357 	if (t->t_dflg & F_NICE)
1358 	    (void) setpriority(PRIO_PROCESS, 0, t->t_nice);
1359     }
1360     else {
1361 	if (wanttty >= 0)
1362 	    (void) setpgid(pid, pcurrjob ? pcurrjob->p_jobid : pid);
1363 	palloc(pid, t);
1364 	sigprocmask(SIG_SETMASK, &osigset, NULL);
1365     }
1366 
1367     return (pid);
1368 }
1369 
1370 static void
1371 okpcntl()
1372 {
1373     if (tpgrp == -1)
1374 	stderror(ERR_JOBCONTROL);
1375     if (tpgrp == 0)
1376 	stderror(ERR_JOBCTRLSUB);
1377 }
1378 
1379 /*
1380  * if we don't have vfork(), things can still go in the wrong order
1381  * resulting in the famous 'Stopped (tty output)'. But some systems
1382  * don't permit the setpgid() call, (these are more recent secure
1383  * systems such as ibm's aix). Then we'd rather print an error message
1384  * than hang the shell!
1385  * I am open to suggestions how to fix that.
1386  */
1387 void
1388 pgetty(wanttty, pgrp)
1389     int     wanttty, pgrp;
1390 {
1391     sigset_t sigset, osigset;
1392 
1393     /*
1394      * christos: I am blocking the tty signals till I've set things
1395      * correctly....
1396      */
1397     if (wanttty > 0) {
1398 	sigemptyset(&sigset);
1399 	sigaddset(&sigset, SIGTSTP);
1400 	sigaddset(&sigset, SIGTTIN);
1401 	sigaddset(&sigset, SIGTTOU);
1402 	sigprocmask(SIG_BLOCK, &sigset, &osigset);
1403     }
1404     /*
1405      * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
1406      * Don't check for tpgrp >= 0 so even non-interactive shells give
1407      * background jobs process groups Same for the comparison in the other part
1408      * of the #ifdef
1409      */
1410     if (wanttty >= 0)
1411 	if (setpgid(0, pgrp) == -1) {
1412 	    (void) fprintf(csherr, "csh: setpgid error.\n");
1413 	    xexit(0);
1414 	}
1415 
1416     if (wanttty > 0) {
1417 	(void) tcsetpgrp(FSHTTY, pgrp);
1418 	sigprocmask(SIG_SETMASK, &osigset, NULL);
1419     }
1420 
1421     if (tpgrp > 0)
1422 	tpgrp = 0;		/* gave tty away */
1423 }
1424