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