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