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