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