147823Sbostic /*-
260765Sbostic * Copyright (c) 1980, 1991, 1993
360765Sbostic * The Regents of the University of California. All rights reserved.
447823Sbostic *
547823Sbostic * %sccs.include.redist.c%
621940Sdist */
721940Sdist
817509Sedward #ifndef lint
9*68576Schristos static char sccsid[] = "@(#)proc.c 8.2 (Berkeley) 03/22/95";
1047823Sbostic #endif /* not lint */
111302Sbill
1250028Sbostic #include <sys/types.h>
1350028Sbostic #include <sys/wait.h>
1450028Sbostic #include <errno.h>
1550028Sbostic #include <unistd.h>
1650028Sbostic #include <stdlib.h>
1750028Sbostic #include <string.h>
1850033Schristos #if __STDC__
1950033Schristos # include <stdarg.h>
2050033Schristos #else
2150033Schristos # include <varargs.h>
2250033Schristos #endif
2350033Schristos
2450023Sbostic #include "csh.h"
2550023Sbostic #include "dir.h"
2650023Sbostic #include "proc.h"
2750023Sbostic #include "extern.h"
281302Sbill
291302Sbill #define BIGINDEX 9 /* largest desirable job index */
301302Sbill
3149992Sbostic static struct rusage zru;
3249992Sbostic
3350024Schristos static void pflushall __P((void));
3450024Schristos static void pflush __P((struct process *));
3550024Schristos static void pclrcurr __P((struct process *));
3650024Schristos static void padd __P((struct command *));
3750024Schristos static int pprint __P((struct process *, int));
3850024Schristos static void ptprint __P((struct process *));
3950024Schristos static void pads __P((Char *));
4050024Schristos static void pkill __P((Char **v, int));
4151437Sleres static struct process
4250024Schristos *pgetcurr __P((struct process *));
4350024Schristos static void okpcntl __P((void));
4449992Sbostic
451302Sbill /*
461302Sbill * pchild - called at interrupt level by the SIGCHLD signal
471302Sbill * indicating that at least one child has terminated or stopped
481302Sbill * thus at least one wait system call will definitely return a
491302Sbill * childs status. Top level routines (like pwait) must be sure
501302Sbill * to mask interrupts when playing with the proclist data structures!
511302Sbill */
5250023Sbostic /* ARGUSED */
5346657Sbostic void
pchild(notused)5450023Sbostic pchild(notused)
5550023Sbostic int notused;
561302Sbill {
5749992Sbostic register struct process *pp;
5849992Sbostic register struct process *fp;
5949992Sbostic register int pid;
6049992Sbostic extern int insource;
6149992Sbostic union wait w;
6249992Sbostic int jobflags;
6349992Sbostic struct rusage ru;
641302Sbill
651302Sbill loop:
6649992Sbostic errno = 0; /* reset, just in case */
6749992Sbostic pid = wait3(&w.w_status,
6849992Sbostic (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru);
6949992Sbostic
7049992Sbostic if (pid <= 0) {
7149992Sbostic if (errno == EINTR) {
7249992Sbostic errno = 0;
7349992Sbostic goto loop;
741302Sbill }
7549992Sbostic pnoprocesses = pid == -1;
7649992Sbostic return;
7749992Sbostic }
7850040Schristos for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
7949992Sbostic if (pid == pp->p_pid)
8049992Sbostic goto found;
8149992Sbostic goto loop;
821302Sbill found:
8349992Sbostic if (pid == atoi(short2str(value(STRchild))))
8449992Sbostic unsetv(STRchild);
8549992Sbostic pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED);
8649992Sbostic if (WIFSTOPPED(w)) {
8749992Sbostic pp->p_flags |= PSTOPPED;
8849992Sbostic pp->p_reason = w.w_stopsig;
8949992Sbostic }
9049992Sbostic else {
9149992Sbostic if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime))
9250028Sbostic (void) gettimeofday(&pp->p_etime, NULL);
9349992Sbostic
9449992Sbostic pp->p_rusage = ru;
9549992Sbostic if (WIFSIGNALED(w)) {
9649992Sbostic if (w.w_termsig == SIGINT)
9749992Sbostic pp->p_flags |= PINTERRUPTED;
9849992Sbostic else
9949992Sbostic pp->p_flags |= PSIGNALED;
10049992Sbostic if (w.w_coredump)
10149992Sbostic pp->p_flags |= PDUMPED;
10249992Sbostic pp->p_reason = w.w_termsig;
1031302Sbill }
10449992Sbostic else {
10549992Sbostic pp->p_reason = w.w_retcode;
10649992Sbostic if (pp->p_reason != 0)
10749992Sbostic pp->p_flags |= PAEXITED;
10849992Sbostic else
10949992Sbostic pp->p_flags |= PNEXITED;
11049992Sbostic }
11149992Sbostic }
11249992Sbostic jobflags = 0;
11349992Sbostic fp = pp;
11449992Sbostic do {
11549992Sbostic if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 &&
11649992Sbostic !child && adrof(STRtime) &&
11749992Sbostic fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec
11849992Sbostic >= atoi(short2str(value(STRtime))))
11949992Sbostic fp->p_flags |= PTIME;
12049992Sbostic jobflags |= fp->p_flags;
12149992Sbostic } while ((fp = fp->p_friends) != pp);
12249992Sbostic pp->p_flags &= ~PFOREGND;
12349992Sbostic if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
12449992Sbostic pp->p_flags &= ~PPTIME;
12549992Sbostic pp->p_flags |= PTIME;
12649992Sbostic }
12749992Sbostic if ((jobflags & (PRUNNING | PREPORTED)) == 0) {
1281302Sbill fp = pp;
1291302Sbill do {
13049992Sbostic if (fp->p_flags & PSTOPPED)
13149992Sbostic fp->p_flags |= PREPORTED;
1321302Sbill } while ((fp = fp->p_friends) != pp);
13349992Sbostic while (fp->p_pid != fp->p_jobid)
13449992Sbostic fp = fp->p_friends;
13549992Sbostic if (jobflags & PSTOPPED) {
13649992Sbostic if (pcurrent && pcurrent != fp)
13749992Sbostic pprevious = pcurrent;
13849992Sbostic pcurrent = fp;
1391302Sbill }
14049992Sbostic else
14149992Sbostic pclrcurr(fp);
14249992Sbostic if (jobflags & PFOREGND) {
14349992Sbostic if (jobflags & (PSIGNALED | PSTOPPED | PPTIME) ||
14449992Sbostic #ifdef IIASA
14549992Sbostic jobflags & PAEXITED ||
14649992Sbostic #endif
14749992Sbostic !eq(dcwd->di_name, fp->p_cwd->di_name)) {
14849992Sbostic ; /* print in pjwait */
14949992Sbostic }
15049992Sbostic /* PWP: print a newline after ^C */
15150445Schristos else if (jobflags & PINTERRUPTED) {
15251589Schristos (void) vis_fputc('\r' | QUOTE, cshout);
15350445Schristos (void) fputc('\n', cshout);
15450445Schristos }
1551302Sbill }
15649992Sbostic else {
15749992Sbostic if (jobflags & PNOTIFY || adrof(STRnotify)) {
15851589Schristos (void) vis_fputc('\r' | QUOTE, cshout);
15950445Schristos (void) fputc('\n', cshout);
16049992Sbostic (void) pprint(pp, NUMBER | NAME | REASON);
16149992Sbostic if ((jobflags & PSTOPPED) == 0)
16249992Sbostic pflush(pp);
16349992Sbostic }
16449992Sbostic else {
16549992Sbostic fp->p_flags |= PNEEDNOTE;
16649992Sbostic neednote++;
16749992Sbostic }
16849992Sbostic }
16949992Sbostic }
17049992Sbostic goto loop;
1711302Sbill }
1721302Sbill
17349992Sbostic void
pnote()1741302Sbill pnote()
1751302Sbill {
17649992Sbostic register struct process *pp;
17749992Sbostic int flags;
178*68576Schristos sigset_t sigset, osigset;
1791302Sbill
18049992Sbostic neednote = 0;
181*68576Schristos sigemptyset(&sigset);
182*68576Schristos sigaddset(&sigset, SIGCHLD);
18350040Schristos for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) {
18449992Sbostic if (pp->p_flags & PNEEDNOTE) {
185*68576Schristos sigprocmask(SIG_BLOCK, &sigset, &osigset);
18649992Sbostic pp->p_flags &= ~PNEEDNOTE;
18749992Sbostic flags = pprint(pp, NUMBER | NAME | REASON);
18849992Sbostic if ((flags & (PRUNNING | PSTOPPED)) == 0)
18949992Sbostic pflush(pp);
190*68576Schristos sigprocmask(SIG_SETMASK, &osigset, NULL);
1911302Sbill }
19249992Sbostic }
1931302Sbill }
1941302Sbill
1951302Sbill /*
1961302Sbill * pwait - wait for current job to terminate, maintaining integrity
1971302Sbill * of current and previous job indicators.
1981302Sbill */
19949992Sbostic void
pwait()2001302Sbill pwait()
2011302Sbill {
20249992Sbostic register struct process *fp, *pp;
203*68576Schristos sigset_t sigset, osigset;
2041302Sbill
20549992Sbostic /*
20649992Sbostic * Here's where dead procs get flushed.
20749992Sbostic */
208*68576Schristos sigemptyset(&sigset);
209*68576Schristos sigaddset(&sigset, SIGCHLD);
210*68576Schristos sigprocmask(SIG_BLOCK, &sigset, &osigset);
21150040Schristos for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next)
21249992Sbostic if (pp->p_pid == 0) {
21349992Sbostic fp->p_next = pp->p_next;
21449992Sbostic xfree((ptr_t) pp->p_command);
21549992Sbostic if (pp->p_cwd && --pp->p_cwd->di_count == 0)
21649992Sbostic if (pp->p_cwd->di_next == 0)
21749992Sbostic dfree(pp->p_cwd);
21849992Sbostic xfree((ptr_t) pp);
21949992Sbostic pp = fp;
22049992Sbostic }
221*68576Schristos sigprocmask(SIG_SETMASK, &osigset, NULL);
22249992Sbostic pjwait(pcurrjob);
2231302Sbill }
2241302Sbill
22549992Sbostic
2261302Sbill /*
2271302Sbill * pjwait - wait for a job to finish or become stopped
2281302Sbill * It is assumed to be in the foreground state (PFOREGND)
2291302Sbill */
23049992Sbostic void
pjwait(pp)2311302Sbill pjwait(pp)
23249992Sbostic register struct process *pp;
2331302Sbill {
23449992Sbostic register struct process *fp;
23549992Sbostic int jobflags, reason;
236*68576Schristos sigset_t sigset, osigset;
2371302Sbill
23849992Sbostic while (pp->p_pid != pp->p_jobid)
23949992Sbostic pp = pp->p_friends;
24049992Sbostic fp = pp;
24149992Sbostic
24249992Sbostic do {
24349992Sbostic if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING)
24450439Schristos (void) fprintf(csherr, "BUG: waiting for background job!\n");
24549992Sbostic } while ((fp = fp->p_friends) != pp);
24649992Sbostic /*
24749992Sbostic * Now keep pausing as long as we are not interrupted (SIGINT), and the
24849992Sbostic * target process, or any of its friends, are running
24949992Sbostic */
25049992Sbostic fp = pp;
251*68576Schristos sigemptyset(&sigset);
252*68576Schristos sigaddset(&sigset, SIGCHLD);
253*68576Schristos sigprocmask(SIG_BLOCK, &sigset, &osigset);
25449992Sbostic for (;;) {
255*68576Schristos sigemptyset(&sigset);
256*68576Schristos sigaddset(&sigset, SIGCHLD);
257*68576Schristos sigprocmask(SIG_BLOCK, &sigset, NULL);
25849992Sbostic jobflags = 0;
25949992Sbostic do
26049992Sbostic jobflags |= fp->p_flags;
26149992Sbostic while ((fp = (fp->p_friends)) != pp);
26249992Sbostic if ((jobflags & PRUNNING) == 0)
26349992Sbostic break;
26449992Sbostic #ifdef JOBDEBUG
265*68576Schristos (void) fprintf(csherr, "starting to sigsuspend for SIGCHLD on %d\n",
26650439Schristos fp->p_pid);
26749992Sbostic #endif /* JOBDEBUG */
268*68576Schristos sigset = osigset;
269*68576Schristos sigdelset(&sigset, SIGCHLD);
270*68576Schristos sigsuspend(&sigset);
27149992Sbostic }
272*68576Schristos sigprocmask(SIG_SETMASK, &osigset, NULL);
27349992Sbostic if (tpgrp > 0) /* get tty back */
27449992Sbostic (void) tcsetpgrp(FSHTTY, tpgrp);
27549992Sbostic if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) ||
27649992Sbostic !eq(dcwd->di_name, fp->p_cwd->di_name)) {
27749992Sbostic if (jobflags & PSTOPPED) {
27850445Schristos (void) fputc('\n', cshout);
27949992Sbostic if (adrof(STRlistjobs)) {
28049992Sbostic Char *jobcommand[3];
28149992Sbostic
28249992Sbostic jobcommand[0] = STRjobs;
28349992Sbostic if (eq(value(STRlistjobs), STRlong))
28449992Sbostic jobcommand[1] = STRml;
28549992Sbostic else
28649992Sbostic jobcommand[1] = NULL;
28749992Sbostic jobcommand[2] = NULL;
28849992Sbostic
28950439Schristos dojobs(jobcommand, NULL);
29049992Sbostic (void) pprint(pp, SHELLDIR);
29149992Sbostic }
29249992Sbostic else
29349992Sbostic (void) pprint(pp, AREASON | SHELLDIR);
2941302Sbill }
29549992Sbostic else
29649992Sbostic (void) pprint(pp, AREASON | SHELLDIR);
29749992Sbostic }
29849992Sbostic if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr &&
29949992Sbostic (!gointr || !eq(gointr, STRminus))) {
30049992Sbostic if ((jobflags & PSTOPPED) == 0)
30149992Sbostic pflush(pp);
30249992Sbostic pintr1(0);
30349992Sbostic /* NOTREACHED */
30449992Sbostic }
30549992Sbostic reason = 0;
30649992Sbostic fp = pp;
30749992Sbostic do {
30849992Sbostic if (fp->p_reason)
30949992Sbostic reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ?
31049992Sbostic fp->p_reason | META : fp->p_reason;
31149992Sbostic } while ((fp = fp->p_friends) != pp);
31250445Schristos if ((reason != 0) && (adrof(STRprintexitvalue))) {
31350439Schristos (void) fprintf(cshout, "Exit %d\n", reason);
31450445Schristos }
31549992Sbostic set(STRstatus, putn(reason));
31649992Sbostic if (reason && exiterr)
31749992Sbostic exitstat();
31849992Sbostic pflush(pp);
3191302Sbill }
3201302Sbill
3211302Sbill /*
3221302Sbill * dowait - wait for all processes to finish
3231302Sbill */
32449992Sbostic void
32550439Schristos /*ARGSUSED*/
dowait(v,t)32650439Schristos dowait(v, t)
32750439Schristos Char **v;
32850439Schristos struct command *t;
3291302Sbill {
33049992Sbostic register struct process *pp;
331*68576Schristos sigset_t sigset, osigset;
3321302Sbill
33349992Sbostic pjobs++;
334*68576Schristos sigemptyset(&sigset);
335*68576Schristos sigaddset(&sigset, SIGCHLD);
336*68576Schristos sigprocmask(SIG_BLOCK, &sigset, &osigset);
3371302Sbill loop:
33849992Sbostic for (pp = proclist.p_next; pp; pp = pp->p_next)
33949992Sbostic if (pp->p_pid && /* pp->p_pid == pp->p_jobid && */
34049992Sbostic pp->p_flags & PRUNNING) {
341*68576Schristos sigemptyset(&sigset);
342*68576Schristos sigsuspend(&sigset);
34349992Sbostic goto loop;
34449992Sbostic }
345*68576Schristos sigprocmask(SIG_SETMASK, &osigset, NULL);
34649992Sbostic pjobs = 0;
3471302Sbill }
3481302Sbill
3491302Sbill /*
3501302Sbill * pflushall - flush all jobs from list (e.g. at fork())
3511302Sbill */
35249992Sbostic static void
pflushall()3531302Sbill pflushall()
3541302Sbill {
35549992Sbostic register struct process *pp;
3561302Sbill
35750040Schristos for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
35849992Sbostic if (pp->p_pid)
35949992Sbostic pflush(pp);
3601302Sbill }
3611302Sbill
3621302Sbill /*
3631302Sbill * pflush - flag all process structures in the same job as the
3641302Sbill * the argument process for deletion. The actual free of the
3651302Sbill * space is not done here since pflush is called at interrupt level.
3661302Sbill */
36749992Sbostic static void
pflush(pp)3681302Sbill pflush(pp)
36949992Sbostic register struct process *pp;
3701302Sbill {
37149992Sbostic register struct process *np;
37249992Sbostic register int idx;
3731302Sbill
37449992Sbostic if (pp->p_pid == 0) {
37550439Schristos (void) fprintf(csherr, "BUG: process flushed twice");
37649992Sbostic return;
37749992Sbostic }
37849992Sbostic while (pp->p_pid != pp->p_jobid)
37949992Sbostic pp = pp->p_friends;
38049992Sbostic pclrcurr(pp);
38149992Sbostic if (pp == pcurrjob)
38249992Sbostic pcurrjob = 0;
38349992Sbostic idx = pp->p_index;
38449992Sbostic np = pp;
38549992Sbostic do {
38649992Sbostic np->p_index = np->p_pid = 0;
38749992Sbostic np->p_flags &= ~PNEEDNOTE;
38849992Sbostic } while ((np = np->p_friends) != pp);
38949992Sbostic if (idx == pmaxindex) {
39049992Sbostic for (np = proclist.p_next, idx = 0; np; np = np->p_next)
39149992Sbostic if (np->p_index > idx)
39249992Sbostic idx = np->p_index;
39349992Sbostic pmaxindex = idx;
39449992Sbostic }
3951302Sbill }
3961302Sbill
3971302Sbill /*
3981302Sbill * pclrcurr - make sure the given job is not the current or previous job;
3991302Sbill * pp MUST be the job leader
4001302Sbill */
40149992Sbostic static void
pclrcurr(pp)4021302Sbill pclrcurr(pp)
40349992Sbostic register struct process *pp;
4041302Sbill {
4051302Sbill
40649992Sbostic if (pp == pcurrent)
40750040Schristos if (pprevious != NULL) {
40849992Sbostic pcurrent = pprevious;
40949992Sbostic pprevious = pgetcurr(pp);
41049992Sbostic }
41149992Sbostic else {
41249992Sbostic pcurrent = pgetcurr(pp);
41349992Sbostic pprevious = pgetcurr(pp);
41449992Sbostic }
41549992Sbostic else if (pp == pprevious)
41649992Sbostic pprevious = pgetcurr(pp);
4171302Sbill }
4181302Sbill
4191302Sbill /* +4 here is 1 for '\0', 1 ea for << >& >> */
42049992Sbostic static Char command[PMAXLEN + 4];
42149992Sbostic static int cmdlen;
42249992Sbostic static Char *cmdp;
42349992Sbostic
4241302Sbill /*
4251302Sbill * palloc - allocate a process structure and fill it up.
4261302Sbill * an important assumption is made that the process is running.
4271302Sbill */
42849992Sbostic void
palloc(pid,t)4291302Sbill palloc(pid, t)
43049992Sbostic int pid;
43149992Sbostic register struct command *t;
4321302Sbill {
43349992Sbostic register struct process *pp;
43449992Sbostic int i;
4351302Sbill
43649992Sbostic pp = (struct process *) xcalloc(1, (size_t) sizeof(struct process));
43749992Sbostic pp->p_pid = pid;
43849992Sbostic pp->p_flags = t->t_dflg & F_AMPERSAND ? PRUNNING : PRUNNING | PFOREGND;
43949992Sbostic if (t->t_dflg & F_TIME)
44049992Sbostic pp->p_flags |= PPTIME;
44149992Sbostic cmdp = command;
44249992Sbostic cmdlen = 0;
44349992Sbostic padd(t);
44449992Sbostic *cmdp++ = 0;
44549992Sbostic if (t->t_dflg & F_PIPEOUT) {
44649992Sbostic pp->p_flags |= PPOU;
44749992Sbostic if (t->t_dflg & F_STDERR)
44850439Schristos pp->p_flags |= PERR;
44949992Sbostic }
45049992Sbostic pp->p_command = Strsave(command);
45149992Sbostic if (pcurrjob) {
45249992Sbostic struct process *fp;
4531302Sbill
45449992Sbostic /* careful here with interrupt level */
45549992Sbostic pp->p_cwd = 0;
45649992Sbostic pp->p_index = pcurrjob->p_index;
45749992Sbostic pp->p_friends = pcurrjob;
45849992Sbostic pp->p_jobid = pcurrjob->p_pid;
45951437Sleres for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
46051437Sleres continue;
46149992Sbostic fp->p_friends = pp;
46249992Sbostic }
46349992Sbostic else {
46449992Sbostic pcurrjob = pp;
46549992Sbostic pp->p_jobid = pid;
46649992Sbostic pp->p_friends = pp;
46749992Sbostic pp->p_cwd = dcwd;
46849992Sbostic dcwd->di_count++;
46949992Sbostic if (pmaxindex < BIGINDEX)
47049992Sbostic pp->p_index = ++pmaxindex;
47149992Sbostic else {
47249992Sbostic struct process *np;
47349992Sbostic
47449992Sbostic for (i = 1;; i++) {
47549992Sbostic for (np = proclist.p_next; np; np = np->p_next)
47649992Sbostic if (np->p_index == i)
47749992Sbostic goto tryagain;
47849992Sbostic pp->p_index = i;
47949992Sbostic if (i > pmaxindex)
48049992Sbostic pmaxindex = i;
48149992Sbostic break;
48249992Sbostic tryagain:;
48349992Sbostic }
4841302Sbill }
48550040Schristos if (pcurrent == NULL)
48649992Sbostic pcurrent = pp;
48750040Schristos else if (pprevious == NULL)
48849992Sbostic pprevious = pp;
48949992Sbostic }
49049992Sbostic pp->p_next = proclist.p_next;
49149992Sbostic proclist.p_next = pp;
49250028Sbostic (void) gettimeofday(&pp->p_btime, NULL);
4931302Sbill }
4941302Sbill
49549992Sbostic static void
padd(t)4961302Sbill padd(t)
49749992Sbostic register struct command *t;
4981302Sbill {
49949992Sbostic Char **argp;
5001302Sbill
50149992Sbostic if (t == 0)
50249992Sbostic return;
50349992Sbostic switch (t->t_dtyp) {
5041302Sbill
50549992Sbostic case NODE_PAREN:
50649992Sbostic pads(STRLparensp);
50749992Sbostic padd(t->t_dspr);
50849992Sbostic pads(STRspRparen);
50949992Sbostic break;
5101302Sbill
51149992Sbostic case NODE_COMMAND:
51249992Sbostic for (argp = t->t_dcom; *argp; argp++) {
51349992Sbostic pads(*argp);
51449992Sbostic if (argp[1])
51549992Sbostic pads(STRspace);
51649992Sbostic }
51749992Sbostic break;
5181302Sbill
51949992Sbostic case NODE_OR:
52049992Sbostic case NODE_AND:
52149992Sbostic case NODE_PIPE:
52249992Sbostic case NODE_LIST:
52349992Sbostic padd(t->t_dcar);
52449992Sbostic switch (t->t_dtyp) {
52547724Sbostic case NODE_OR:
52649992Sbostic pads(STRspor2sp);
52749992Sbostic break;
52847724Sbostic case NODE_AND:
52949992Sbostic pads(STRspand2sp);
53049992Sbostic break;
53147724Sbostic case NODE_PIPE:
53249992Sbostic pads(STRsporsp);
53349992Sbostic break;
53447724Sbostic case NODE_LIST:
53549992Sbostic pads(STRsemisp);
53649992Sbostic break;
5371302Sbill }
53849992Sbostic padd(t->t_dcdr);
53949992Sbostic return;
54049992Sbostic }
54149992Sbostic if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) {
54249992Sbostic pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp);
54349992Sbostic pads(t->t_dlef);
54449992Sbostic }
54549992Sbostic if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) {
54649992Sbostic pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow);
54749992Sbostic if (t->t_dflg & F_STDERR)
54849992Sbostic pads(STRand);
54949992Sbostic pads(STRspace);
55049992Sbostic pads(t->t_drit);
55149992Sbostic }
5521302Sbill }
5531302Sbill
55449992Sbostic static void
pads(cp)5551302Sbill pads(cp)
55649992Sbostic Char *cp;
5571302Sbill {
55849992Sbostic register int i;
5591302Sbill
56049992Sbostic /*
56149992Sbostic * Avoid the Quoted Space alias hack! Reported by:
56249992Sbostic * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks)
56349992Sbostic */
56449992Sbostic if (cp[0] == STRQNULL[0])
56549992Sbostic cp++;
56649992Sbostic
56749992Sbostic i = Strlen(cp);
56849992Sbostic
56949992Sbostic if (cmdlen >= PMAXLEN)
57049992Sbostic return;
57149992Sbostic if (cmdlen + i >= PMAXLEN) {
57249992Sbostic (void) Strcpy(cmdp, STRsp3dots);
57349992Sbostic cmdlen = PMAXLEN;
57449992Sbostic cmdp += 4;
57549992Sbostic return;
57649992Sbostic }
57749992Sbostic (void) Strcpy(cmdp, cp);
57849992Sbostic cmdp += i;
57949992Sbostic cmdlen += i;
5801302Sbill }
5811302Sbill
5821302Sbill /*
5831302Sbill * psavejob - temporarily save the current job on a one level stack
5841302Sbill * so another job can be created. Used for { } in exp6
5851302Sbill * and `` in globbing.
5861302Sbill */
58749992Sbostic void
psavejob()5881302Sbill psavejob()
5891302Sbill {
5901302Sbill
59149992Sbostic pholdjob = pcurrjob;
59250040Schristos pcurrjob = NULL;
5931302Sbill }
5941302Sbill
5951302Sbill /*
5961302Sbill * prestjob - opposite of psavejob. This may be missed if we are interrupted
5971302Sbill * somewhere, but pendjob cleans up anyway.
5981302Sbill */
59949992Sbostic void
prestjob()6001302Sbill prestjob()
6011302Sbill {
6021302Sbill
60349992Sbostic pcurrjob = pholdjob;
60450040Schristos pholdjob = NULL;
6051302Sbill }
6061302Sbill
6071302Sbill /*
6081302Sbill * pendjob - indicate that a job (set of commands) has been completed
6091302Sbill * or is about to begin.
6101302Sbill */
61149992Sbostic void
pendjob()6121302Sbill pendjob()
6131302Sbill {
61449992Sbostic register struct process *pp, *tp;
6151302Sbill
61649992Sbostic if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) {
61749992Sbostic pp = pcurrjob;
61849992Sbostic while (pp->p_pid != pp->p_jobid)
61949992Sbostic pp = pp->p_friends;
62050439Schristos (void) fprintf(cshout, "[%d]", pp->p_index);
62149992Sbostic tp = pp;
62249992Sbostic do {
62350439Schristos (void) fprintf(cshout, " %d", pp->p_pid);
62449992Sbostic pp = pp->p_friends;
62549992Sbostic } while (pp != tp);
62650439Schristos (void) fputc('\n', cshout);
62749992Sbostic }
62849992Sbostic pholdjob = pcurrjob = 0;
6291302Sbill }
6301302Sbill
6311302Sbill /*
6321302Sbill * pprint - print a job
6331302Sbill */
63449992Sbostic static int
pprint(pp,flag)6351302Sbill pprint(pp, flag)
63649992Sbostic register struct process *pp;
63749992Sbostic bool flag;
6381302Sbill {
63949992Sbostic register status, reason;
64049992Sbostic struct process *tp;
64149992Sbostic int jobflags, pstatus;
64250445Schristos bool hadnl = 1; /* did we just have a newline */
64349992Sbostic char *format;
6441302Sbill
64550439Schristos (void) fpurge(cshout);
64650439Schristos
64749992Sbostic while (pp->p_pid != pp->p_jobid)
64849992Sbostic pp = pp->p_friends;
64949992Sbostic if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
65049992Sbostic pp->p_flags &= ~PPTIME;
65149992Sbostic pp->p_flags |= PTIME;
65249992Sbostic }
65349992Sbostic tp = pp;
65449992Sbostic status = reason = -1;
65549992Sbostic jobflags = 0;
65649992Sbostic do {
65749992Sbostic jobflags |= pp->p_flags;
65849992Sbostic pstatus = pp->p_flags & PALLSTATES;
65951437Sleres if (tp != pp && !hadnl && !(flag & FANCY) &&
66050445Schristos ((pstatus == status && pp->p_reason == reason) ||
66150445Schristos !(flag & REASON))) {
66250439Schristos (void) fputc(' ', cshout);
66350445Schristos hadnl = 0;
66450445Schristos }
66549992Sbostic else {
66650445Schristos if (tp != pp && !hadnl) {
66750439Schristos (void) fputc('\n', cshout);
66850445Schristos hadnl = 1;
66950445Schristos }
67050445Schristos if (flag & NUMBER) {
67149992Sbostic if (pp == tp)
67250439Schristos (void) fprintf(cshout, "[%d]%s %c ", pp->p_index,
67349992Sbostic pp->p_index < 10 ? " " : "",
67449992Sbostic pp == pcurrent ? '+' :
67549992Sbostic (pp == pprevious ? '-' : ' '));
67649992Sbostic else
67750439Schristos (void) fprintf(cshout, " ");
67850445Schristos hadnl = 0;
67950445Schristos }
68049992Sbostic if (flag & FANCY) {
68150439Schristos (void) fprintf(cshout, "%5d ", pp->p_pid);
68250445Schristos hadnl = 0;
68349992Sbostic }
68449992Sbostic if (flag & (REASON | AREASON)) {
68549992Sbostic if (flag & NAME)
68649992Sbostic format = "%-23s";
68749992Sbostic else
68849992Sbostic format = "%s";
68949992Sbostic if (pstatus == status)
69049992Sbostic if (pp->p_reason == reason) {
69150439Schristos (void) fprintf(cshout, format, "");
69250445Schristos hadnl = 0;
69349992Sbostic goto prcomd;
69449992Sbostic }
69549992Sbostic else
69649992Sbostic reason = pp->p_reason;
6971302Sbill else {
69849992Sbostic status = pstatus;
69949992Sbostic reason = pp->p_reason;
70049992Sbostic }
70149992Sbostic switch (status) {
7021302Sbill
70349992Sbostic case PRUNNING:
70450439Schristos (void) fprintf(cshout, format, "Running ");
70550445Schristos hadnl = 0;
70649992Sbostic break;
7071302Sbill
70849992Sbostic case PINTERRUPTED:
70949992Sbostic case PSTOPPED:
71049992Sbostic case PSIGNALED:
71150445Schristos /*
71250445Schristos * tell what happened to the background job
71350445Schristos * From: Michael Schroeder
71450445Schristos * <mlschroe@immd4.informatik.uni-erlangen.de>
71550445Schristos */
71650445Schristos if ((flag & REASON)
71750445Schristos || ((flag & AREASON)
71850445Schristos && reason != SIGINT
71950445Schristos && (reason != SIGPIPE
72050445Schristos || (pp->p_flags & PPOU) == 0))) {
72151437Sleres (void) fprintf(cshout, format,
72260237Schristos sys_siglist[(unsigned char)
72360237Schristos pp->p_reason]);
72450445Schristos hadnl = 0;
72550445Schristos }
72649992Sbostic break;
7271302Sbill
72849992Sbostic case PNEXITED:
72949992Sbostic case PAEXITED:
73050445Schristos if (flag & REASON) {
73149992Sbostic if (pp->p_reason)
73250439Schristos (void) fprintf(cshout, "Exit %-18d", pp->p_reason);
73349992Sbostic else
73450439Schristos (void) fprintf(cshout, format, "Done");
73550445Schristos hadnl = 0;
73650445Schristos }
73749992Sbostic break;
7381302Sbill
73949992Sbostic default:
74050439Schristos (void) fprintf(csherr, "BUG: status=%-9o", status);
7411302Sbill }
74249992Sbostic }
74349992Sbostic }
7441302Sbill prcomd:
74549992Sbostic if (flag & NAME) {
74651589Schristos (void) fprintf(cshout, "%s", vis_str(pp->p_command));
74749992Sbostic if (pp->p_flags & PPOU)
74850439Schristos (void) fprintf(cshout, " |");
74950439Schristos if (pp->p_flags & PERR)
75050439Schristos (void) fputc('&', cshout);
75150445Schristos hadnl = 0;
7521302Sbill }
75350445Schristos if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) {
75450439Schristos (void) fprintf(cshout, " (core dumped)");
75550445Schristos hadnl = 0;
75650445Schristos }
75749992Sbostic if (tp == pp->p_friends) {
75850445Schristos if (flag & AMPERSAND) {
75950439Schristos (void) fprintf(cshout, " &");
76050445Schristos hadnl = 0;
76150445Schristos }
76249992Sbostic if (flag & JOBDIR &&
76349992Sbostic !eq(tp->p_cwd->di_name, dcwd->di_name)) {
76450439Schristos (void) fprintf(cshout, " (wd: ");
76549992Sbostic dtildepr(value(STRhome), tp->p_cwd->di_name);
76650439Schristos (void) fputc(')', cshout);
76750445Schristos hadnl = 0;
76849992Sbostic }
76949992Sbostic }
77049992Sbostic if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) {
77150445Schristos if (!hadnl)
77250445Schristos (void) fprintf(cshout, "\n\t");
77349992Sbostic prusage(&zru, &pp->p_rusage, &pp->p_etime,
77449992Sbostic &pp->p_btime);
77550445Schristos hadnl = 1;
77649992Sbostic }
77749992Sbostic if (tp == pp->p_friends) {
77850445Schristos if (!hadnl) {
77950439Schristos (void) fputc('\n', cshout);
78050445Schristos hadnl = 1;
78150445Schristos }
78249992Sbostic if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
78350439Schristos (void) fprintf(cshout, "(wd now: ");
78449992Sbostic dtildepr(value(STRhome), dcwd->di_name);
78550439Schristos (void) fprintf(cshout, ")\n");
78650445Schristos hadnl = 1;
78749992Sbostic }
78849992Sbostic }
78949992Sbostic } while ((pp = pp->p_friends) != tp);
79049992Sbostic if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) {
79149992Sbostic if (jobflags & NUMBER)
79250439Schristos (void) fprintf(cshout, " ");
79349992Sbostic ptprint(tp);
79450445Schristos hadnl = 1;
79549992Sbostic }
79650439Schristos (void) fflush(cshout);
79749992Sbostic return (jobflags);
7981302Sbill }
7991302Sbill
80049992Sbostic static void
ptprint(tp)8011302Sbill ptprint(tp)
80249992Sbostic register struct process *tp;
8031302Sbill {
80449992Sbostic struct timeval tetime, diff;
80549992Sbostic static struct timeval ztime;
80649992Sbostic struct rusage ru;
80749992Sbostic static struct rusage zru;
80849992Sbostic register struct process *pp = tp;
8091302Sbill
81049992Sbostic ru = zru;
81149992Sbostic tetime = ztime;
81249992Sbostic do {
81349992Sbostic ruadd(&ru, &pp->p_rusage);
81449992Sbostic tvsub(&diff, &pp->p_etime, &pp->p_btime);
81549992Sbostic if (timercmp(&diff, &tetime, >))
81649992Sbostic tetime = diff;
81749992Sbostic } while ((pp = pp->p_friends) != tp);
81849992Sbostic prusage(&zru, &ru, &tetime, &ztime);
8191302Sbill }
8201302Sbill
8211302Sbill /*
8221302Sbill * dojobs - print all jobs
8231302Sbill */
82449992Sbostic void
82550439Schristos /*ARGSUSED*/
dojobs(v,t)82650439Schristos dojobs(v, t)
82750439Schristos Char **v;
82850439Schristos struct command *t;
8291302Sbill {
83049992Sbostic register struct process *pp;
83149992Sbostic register int flag = NUMBER | NAME | REASON;
83249992Sbostic int i;
8331302Sbill
83449992Sbostic if (chkstop)
83549992Sbostic chkstop = 2;
83649992Sbostic if (*++v) {
83749992Sbostic if (v[1] || !eq(*v, STRml))
83849992Sbostic stderror(ERR_JOBS);
83949992Sbostic flag |= FANCY | JOBDIR;
84049992Sbostic }
84149992Sbostic for (i = 1; i <= pmaxindex; i++)
84249992Sbostic for (pp = proclist.p_next; pp; pp = pp->p_next)
84349992Sbostic if (pp->p_index == i && pp->p_pid == pp->p_jobid) {
84449992Sbostic pp->p_flags &= ~PNEEDNOTE;
84549992Sbostic if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED)))
84649992Sbostic pflush(pp);
84749992Sbostic break;
84849992Sbostic }
8491302Sbill }
8501302Sbill
8511302Sbill /*
8521302Sbill * dofg - builtin - put the job into the foreground
8531302Sbill */
85449992Sbostic void
85550439Schristos /*ARGSUSED*/
dofg(v,t)85650439Schristos dofg(v, t)
85750439Schristos Char **v;
85850439Schristos struct command *t;
8591302Sbill {
86049992Sbostic register struct process *pp;
8611302Sbill
86249992Sbostic okpcntl();
86349992Sbostic ++v;
86449992Sbostic do {
86549992Sbostic pp = pfind(*v);
86649992Sbostic pstart(pp, 1);
86749992Sbostic pjwait(pp);
86849992Sbostic } while (*v && *++v);
8691302Sbill }
8701302Sbill
8711302Sbill /*
8721302Sbill * %... - builtin - put the job into the foreground
8731302Sbill */
87449992Sbostic void
87550439Schristos /*ARGSUSED*/
dofg1(v,t)87650439Schristos dofg1(v, t)
87750439Schristos Char **v;
87850439Schristos struct command *t;
8791302Sbill {
88049992Sbostic register struct process *pp;
8811302Sbill
88249992Sbostic okpcntl();
88349992Sbostic pp = pfind(v[0]);
88449992Sbostic pstart(pp, 1);
88549992Sbostic pjwait(pp);
8861302Sbill }
8871302Sbill
8881302Sbill /*
8891302Sbill * dobg - builtin - put the job into the background
8901302Sbill */
89149992Sbostic void
89250439Schristos /*ARGSUSED*/
dobg(v,t)89350439Schristos dobg(v, t)
89450439Schristos Char **v;
89550439Schristos struct command *t;
8961302Sbill {
89749992Sbostic register struct process *pp;
8981302Sbill
89949992Sbostic okpcntl();
90049992Sbostic ++v;
90149992Sbostic do {
90249992Sbostic pp = pfind(*v);
90349992Sbostic pstart(pp, 0);
90449992Sbostic } while (*v && *++v);
9051302Sbill }
9061302Sbill
9071302Sbill /*
9081302Sbill * %... & - builtin - put the job into the background
9091302Sbill */
91049992Sbostic void
91150439Schristos /*ARGSUSED*/
dobg1(v,t)91250439Schristos dobg1(v, t)
91350439Schristos Char **v;
91450439Schristos struct command *t;
9151302Sbill {
91649992Sbostic register struct process *pp;
9171302Sbill
91849992Sbostic pp = pfind(v[0]);
91949992Sbostic pstart(pp, 0);
9201302Sbill }
9211302Sbill
9221302Sbill /*
9231302Sbill * dostop - builtin - stop the job
9241302Sbill */
92549992Sbostic void
92650439Schristos /*ARGSUSED*/
dostop(v,t)92750439Schristos dostop(v, t)
92850439Schristos Char **v;
92950439Schristos struct command *t;
9301302Sbill {
93149992Sbostic pkill(++v, SIGSTOP);
9321302Sbill }
9331302Sbill
9341302Sbill /*
9351302Sbill * dokill - builtin - superset of kill (1)
9361302Sbill */
93749992Sbostic void
93850439Schristos /*ARGSUSED*/
dokill(v,t)93950439Schristos dokill(v, t)
94050439Schristos Char **v;
94150439Schristos struct command *t;
9421302Sbill {
94350761Schristos register int signum = SIGTERM;
94449992Sbostic register char *name;
9451302Sbill
94649992Sbostic v++;
94749992Sbostic if (v[0] && v[0][0] == '-') {
94849992Sbostic if (v[0][1] == 'l') {
94950761Schristos for (signum = 1; signum < NSIG; signum++) {
95050761Schristos (void) fprintf(cshout, "%s ", sys_signame[signum]);
95150761Schristos if (signum == NSIG / 2)
95250761Schristos (void) fputc('\n', cshout);
95349992Sbostic }
95450439Schristos (void) fputc('\n', cshout);
95549992Sbostic return;
95649992Sbostic }
95749992Sbostic if (Isdigit(v[0][1])) {
95849992Sbostic signum = atoi(short2str(v[0] + 1));
95949992Sbostic if (signum < 0 || signum > NSIG)
96049992Sbostic stderror(ERR_NAME | ERR_BADSIG);
96149992Sbostic }
96249992Sbostic else {
96350761Schristos name = short2str(&v[0][1]);
96450761Schristos if (!strncasecmp(name, "sig", 3))
96550761Schristos name += 3;
96650761Schristos
96751437Sleres for (signum = 1; signum < NSIG; signum++)
96850761Schristos if (!strcasecmp(sys_signame[signum], name))
96950761Schristos break;
97050761Schristos
97150761Schristos if (signum == NSIG) {
97251589Schristos setname(vis_str(&v[0][1]));
97350761Schristos stderror(ERR_NAME | ERR_UNKSIG);
97450761Schristos }
97549992Sbostic }
97649992Sbostic v++;
97749992Sbostic }
97849992Sbostic pkill(v, signum);
9791302Sbill }
9801302Sbill
98149992Sbostic static void
pkill(v,signum)9821302Sbill pkill(v, signum)
98349992Sbostic Char **v;
98449992Sbostic int signum;
9851302Sbill {
98649992Sbostic register struct process *pp, *np;
98749992Sbostic register int jobflags = 0;
98849992Sbostic int pid, err1 = 0;
989*68576Schristos sigset_t sigset;
99049992Sbostic Char *cp;
9911302Sbill
992*68576Schristos sigemptyset(&sigset);
993*68576Schristos sigaddset(&sigset, SIGCHLD);
99449992Sbostic if (setintr)
995*68576Schristos sigaddset(&sigset, SIGINT);
996*68576Schristos sigprocmask(SIG_BLOCK, &sigset, NULL);
99749992Sbostic gflag = 0, tglob(v);
99849992Sbostic if (gflag) {
99949992Sbostic v = globall(v);
100049992Sbostic if (v == 0)
100149992Sbostic stderror(ERR_NAME | ERR_NOMATCH);
100249992Sbostic }
100349992Sbostic else {
100449992Sbostic v = gargv = saveblk(v);
100549992Sbostic trim(v);
100649992Sbostic }
10071302Sbill
100849992Sbostic while (v && (cp = *v)) {
100949992Sbostic if (*cp == '%') {
101049992Sbostic np = pp = pfind(cp);
101149992Sbostic do
101249992Sbostic jobflags |= np->p_flags;
101349992Sbostic while ((np = np->p_friends) != pp);
101449992Sbostic switch (signum) {
101549992Sbostic
101649992Sbostic case SIGSTOP:
101749992Sbostic case SIGTSTP:
101849992Sbostic case SIGTTIN:
101949992Sbostic case SIGTTOU:
102049992Sbostic if ((jobflags & PRUNNING) == 0) {
102151437Sleres (void) fprintf(csherr, "%s: Already suspended\n",
102251589Schristos vis_str(cp));
102349992Sbostic err1++;
102449992Sbostic goto cont;
10251302Sbill }
102649992Sbostic break;
102749992Sbostic /*
102849992Sbostic * suspend a process, kill -CONT %, then type jobs; the shell
102949992Sbostic * says it is suspended, but it is running; thanks jaap..
103049992Sbostic */
103149992Sbostic case SIGCONT:
103249992Sbostic pstart(pp, 0);
103349992Sbostic goto cont;
103449992Sbostic }
103549992Sbostic if (killpg((pid_t) pp->p_jobid, signum) < 0) {
103651589Schristos (void) fprintf(csherr, "%s: %s\n", vis_str(cp),
103750439Schristos strerror(errno));
103849992Sbostic err1++;
103949992Sbostic }
104049992Sbostic if (signum == SIGTERM || signum == SIGHUP)
104149992Sbostic (void) killpg((pid_t) pp->p_jobid, SIGCONT);
104249992Sbostic }
104349992Sbostic else if (!(Isdigit(*cp) || *cp == '-'))
104449992Sbostic stderror(ERR_NAME | ERR_JOBARGS);
104549992Sbostic else {
104649992Sbostic pid = atoi(short2str(cp));
104749992Sbostic if (kill((pid_t) pid, signum) < 0) {
104850439Schristos (void) fprintf(csherr, "%d: %s\n", pid, strerror(errno));
104949992Sbostic err1++;
105049992Sbostic goto cont;
105149992Sbostic }
105249992Sbostic if (signum == SIGTERM || signum == SIGHUP)
105349992Sbostic (void) kill((pid_t) pid, SIGCONT);
105449992Sbostic }
10551302Sbill cont:
105649992Sbostic v++;
105749992Sbostic }
105849992Sbostic if (gargv)
105949992Sbostic blkfree(gargv), gargv = 0;
1060*68576Schristos sigprocmask(SIG_UNBLOCK, &sigset, NULL);
106149992Sbostic if (err1)
106249992Sbostic stderror(ERR_SILENT);
10631302Sbill }
10641302Sbill
10651302Sbill /*
10661302Sbill * pstart - start the job in foreground/background
10671302Sbill */
106849992Sbostic void
pstart(pp,foregnd)10691302Sbill pstart(pp, foregnd)
107049992Sbostic register struct process *pp;
107149992Sbostic int foregnd;
10721302Sbill {
107349992Sbostic register struct process *np;
1074*68576Schristos sigset_t sigset, osigset;
107549992Sbostic long jobflags = 0;
10761302Sbill
1077*68576Schristos sigemptyset(&sigset);
1078*68576Schristos sigaddset(&sigset, SIGCHLD);
1079*68576Schristos sigprocmask(SIG_BLOCK, &sigset, &osigset);
108049992Sbostic np = pp;
108149992Sbostic do {
108249992Sbostic jobflags |= np->p_flags;
108349992Sbostic if (np->p_flags & (PRUNNING | PSTOPPED)) {
108449992Sbostic np->p_flags |= PRUNNING;
108549992Sbostic np->p_flags &= ~PSTOPPED;
108649992Sbostic if (foregnd)
108749992Sbostic np->p_flags |= PFOREGND;
108849992Sbostic else
108949992Sbostic np->p_flags &= ~PFOREGND;
109049992Sbostic }
109149992Sbostic } while ((np = np->p_friends) != pp);
109249992Sbostic if (!foregnd)
109349992Sbostic pclrcurr(pp);
109449992Sbostic (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND);
109549992Sbostic if (foregnd)
109649992Sbostic (void) tcsetpgrp(FSHTTY, pp->p_jobid);
109749992Sbostic if (jobflags & PSTOPPED)
109849992Sbostic (void) killpg((pid_t) pp->p_jobid, SIGCONT);
1099*68576Schristos sigprocmask(SIG_SETMASK, &osigset, NULL);
11001302Sbill }
11011302Sbill
110249992Sbostic void
panystop(neednl)11031302Sbill panystop(neednl)
110449992Sbostic bool neednl;
11051302Sbill {
110649992Sbostic register struct process *pp;
11071302Sbill
110849992Sbostic chkstop = 2;
110949992Sbostic for (pp = proclist.p_next; pp; pp = pp->p_next)
111049992Sbostic if (pp->p_flags & PSTOPPED)
111149992Sbostic stderror(ERR_STOPPED, neednl ? "\n" : "");
11121302Sbill }
11131302Sbill
11141302Sbill struct process *
pfind(cp)11151302Sbill pfind(cp)
111649992Sbostic Char *cp;
11171302Sbill {
111849992Sbostic register struct process *pp, *np;
11191302Sbill
112049992Sbostic if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) {
112150040Schristos if (pcurrent == NULL)
112249992Sbostic stderror(ERR_NAME | ERR_JOBCUR);
112349992Sbostic return (pcurrent);
112449992Sbostic }
112549992Sbostic if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) {
112650040Schristos if (pprevious == NULL)
112749992Sbostic stderror(ERR_NAME | ERR_JOBPREV);
112849992Sbostic return (pprevious);
112949992Sbostic }
113049992Sbostic if (Isdigit(cp[1])) {
113149992Sbostic int idx = atoi(short2str(cp + 1));
113249992Sbostic
11331302Sbill for (pp = proclist.p_next; pp; pp = pp->p_next)
113449992Sbostic if (pp->p_index == idx && pp->p_pid == pp->p_jobid)
113549992Sbostic return (pp);
113649992Sbostic stderror(ERR_NAME | ERR_NOSUCHJOB);
113749992Sbostic }
113850040Schristos np = NULL;
113949992Sbostic for (pp = proclist.p_next; pp; pp = pp->p_next)
114049992Sbostic if (pp->p_pid == pp->p_jobid) {
114149992Sbostic if (cp[1] == '?') {
114249992Sbostic register Char *dp;
114349992Sbostic
114449992Sbostic for (dp = pp->p_command; *dp; dp++) {
114549992Sbostic if (*dp != cp[2])
114649992Sbostic continue;
114749992Sbostic if (prefix(cp + 2, dp))
114849992Sbostic goto match;
11491302Sbill }
115049992Sbostic }
115149992Sbostic else if (prefix(cp + 1, pp->p_command)) {
115249992Sbostic match:
115349992Sbostic if (np)
115449992Sbostic stderror(ERR_NAME | ERR_AMBIG);
115549992Sbostic np = pp;
115649992Sbostic }
115749992Sbostic }
115849992Sbostic if (np)
115949992Sbostic return (np);
116049992Sbostic stderror(ERR_NAME | cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB);
116149992Sbostic /* NOTREACHED */
116249992Sbostic return (0);
11631302Sbill }
11641302Sbill
116549992Sbostic
11661302Sbill /*
11672357Swnj * pgetcurr - find most recent job that is not pp, preferably stopped
11681302Sbill */
116949992Sbostic static struct process *
pgetcurr(pp)11701302Sbill pgetcurr(pp)
117149992Sbostic register struct process *pp;
11721302Sbill {
117349992Sbostic register struct process *np;
117450040Schristos register struct process *xp = NULL;
11751302Sbill
117649992Sbostic for (np = proclist.p_next; np; np = np->p_next)
117749992Sbostic if (np != pcurrent && np != pp && np->p_pid &&
117849992Sbostic np->p_pid == np->p_jobid) {
117949992Sbostic if (np->p_flags & PSTOPPED)
118049992Sbostic return (np);
118150040Schristos if (xp == NULL)
118249992Sbostic xp = np;
118349992Sbostic }
118449992Sbostic return (xp);
11851302Sbill }
11861302Sbill
11871302Sbill /*
11881302Sbill * donotify - flag the job so as to report termination asynchronously
11891302Sbill */
119049992Sbostic void
119150439Schristos /*ARGSUSED*/
donotify(v,t)119250439Schristos donotify(v, t)
119350439Schristos Char **v;
119450439Schristos struct command *t;
11951302Sbill {
119649992Sbostic register struct process *pp;
11971302Sbill
119849992Sbostic pp = pfind(*++v);
119949992Sbostic pp->p_flags |= PNOTIFY;
12001302Sbill }
12011302Sbill
12021302Sbill /*
12031302Sbill * Do the fork and whatever should be done in the child side that
12041302Sbill * should not be done if we are not forking at all (like for simple builtin's)
12051302Sbill * Also do everything that needs any signals fiddled with in the parent side
12061302Sbill *
12071302Sbill * Wanttty tells whether process and/or tty pgrps are to be manipulated:
12081302Sbill * -1: leave tty alone; inherit pgrp from parent
12091302Sbill * 0: already have tty; manipulate process pgrps only
12101302Sbill * 1: want to claim tty; manipulate process and tty pgrps
12111302Sbill * It is usually just the value of tpgrp.
12121302Sbill */
121349992Sbostic
121449992Sbostic int
pfork(t,wanttty)12151302Sbill pfork(t, wanttty)
121649992Sbostic struct command *t; /* command we are forking for */
121749992Sbostic int wanttty;
12181302Sbill {
121949992Sbostic register int pid;
122049992Sbostic bool ignint = 0;
122149992Sbostic int pgrp;
1222*68576Schristos sigset_t sigset, osigset;
12231302Sbill
122449992Sbostic /*
122549992Sbostic * A child will be uninterruptible only under very special conditions.
122649992Sbostic * Remember that the semantics of '&' is implemented by disconnecting the
122749992Sbostic * process from the tty so signals do not need to ignored just for '&'.
122849992Sbostic * Thus signals are set to default action for children unless: we have had
122949992Sbostic * an "onintr -" (then specifically ignored) we are not playing with
123049992Sbostic * signals (inherit action)
123149992Sbostic */
123249992Sbostic if (setintr)
123349992Sbostic ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT))
123449992Sbostic || (gointr && eq(gointr, STRminus));
123549992Sbostic /*
123649992Sbostic * Check for maximum nesting of 16 processes to avoid Forking loops
123749992Sbostic */
123849992Sbostic if (child == 16)
123949992Sbostic stderror(ERR_NESTING, 16);
124049992Sbostic /*
124149992Sbostic * Hold SIGCHLD until we have the process installed in our table.
124249992Sbostic */
1243*68576Schristos sigemptyset(&sigset);
1244*68576Schristos sigaddset(&sigset, SIGCHLD);
1245*68576Schristos sigprocmask(SIG_BLOCK, &sigset, &osigset);
124649992Sbostic while ((pid = fork()) < 0)
124749992Sbostic if (setintr == 0)
124849992Sbostic (void) sleep(FORKSLEEP);
124949992Sbostic else {
1250*68576Schristos sigprocmask(SIG_SETMASK, &osigset, NULL);
125149992Sbostic stderror(ERR_NOPROC);
125249992Sbostic }
125349992Sbostic if (pid == 0) {
125449992Sbostic settimes();
125549992Sbostic pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
125649992Sbostic pflushall();
125750040Schristos pcurrjob = NULL;
125849992Sbostic child++;
125949992Sbostic if (setintr) {
126049992Sbostic setintr = 0; /* until I think otherwise */
126149992Sbostic /*
126249992Sbostic * Children just get blown away on SIGINT, SIGQUIT unless "onintr
126349992Sbostic * -" seen.
126449992Sbostic */
126549992Sbostic (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
126649992Sbostic (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
126749992Sbostic if (wanttty >= 0) {
126849992Sbostic /* make stoppable */
126949992Sbostic (void) signal(SIGTSTP, SIG_DFL);
127049992Sbostic (void) signal(SIGTTIN, SIG_DFL);
127149992Sbostic (void) signal(SIGTTOU, SIG_DFL);
127249992Sbostic }
127349992Sbostic (void) signal(SIGTERM, parterm);
127449992Sbostic }
127549992Sbostic else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) {
127649992Sbostic (void) signal(SIGINT, SIG_IGN);
127749992Sbostic (void) signal(SIGQUIT, SIG_IGN);
127849992Sbostic }
127949992Sbostic pgetty(wanttty, pgrp);
12801302Sbill /*
128149992Sbostic * Nohup and nice apply only to NODE_COMMAND's but it would be nice
128249992Sbostic * (?!?) if you could say "nohup (foo;bar)" Then the parser would have
128349992Sbostic * to know about nice/nohup/time
12841302Sbill */
128549992Sbostic if (t->t_dflg & F_NOHUP)
128649992Sbostic (void) signal(SIGHUP, SIG_IGN);
128749992Sbostic if (t->t_dflg & F_NICE)
128849992Sbostic (void) setpriority(PRIO_PROCESS, 0, t->t_nice);
128949992Sbostic }
129049992Sbostic else {
129149992Sbostic if (wanttty >= 0)
129249992Sbostic (void) setpgid(pid, pcurrjob ? pcurrjob->p_jobid : pid);
129349992Sbostic palloc(pid, t);
1294*68576Schristos sigprocmask(SIG_SETMASK, &osigset, NULL);
129549992Sbostic }
12961302Sbill
129749992Sbostic return (pid);
12981302Sbill }
12991302Sbill
130049992Sbostic static void
okpcntl()13011302Sbill okpcntl()
13021302Sbill {
130349992Sbostic if (tpgrp == -1)
130449992Sbostic stderror(ERR_JOBCONTROL);
130549992Sbostic if (tpgrp == 0)
130649992Sbostic stderror(ERR_JOBCTRLSUB);
130749992Sbostic }
13081302Sbill
130949992Sbostic /*
131049992Sbostic * if we don't have vfork(), things can still go in the wrong order
131149992Sbostic * resulting in the famous 'Stopped (tty output)'. But some systems
131249992Sbostic * don't permit the setpgid() call, (these are more recent secure
131349992Sbostic * systems such as ibm's aix). Then we'd rather print an error message
131449992Sbostic * than hang the shell!
131549992Sbostic * I am open to suggestions how to fix that.
131649992Sbostic */
131749992Sbostic void
pgetty(wanttty,pgrp)131849992Sbostic pgetty(wanttty, pgrp)
131949992Sbostic int wanttty, pgrp;
132049992Sbostic {
1321*68576Schristos sigset_t sigset, osigset;
132249992Sbostic
132349992Sbostic /*
132449992Sbostic * christos: I am blocking the tty signals till I've set things
132549992Sbostic * correctly....
132649992Sbostic */
1327*68576Schristos if (wanttty > 0) {
1328*68576Schristos sigemptyset(&sigset);
1329*68576Schristos sigaddset(&sigset, SIGTSTP);
1330*68576Schristos sigaddset(&sigset, SIGTTIN);
1331*68576Schristos sigaddset(&sigset, SIGTTOU);
1332*68576Schristos sigprocmask(SIG_BLOCK, &sigset, &osigset);
1333*68576Schristos }
133449992Sbostic /*
133549992Sbostic * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
133649992Sbostic * Don't check for tpgrp >= 0 so even non-interactive shells give
133749992Sbostic * background jobs process groups Same for the comparison in the other part
133849992Sbostic * of the #ifdef
133949992Sbostic */
134049992Sbostic if (wanttty >= 0)
134149992Sbostic if (setpgid(0, pgrp) == -1) {
134250439Schristos (void) fprintf(csherr, "csh: setpgid error.\n");
134349992Sbostic xexit(0);
134449992Sbostic }
134549992Sbostic
134649992Sbostic if (wanttty > 0) {
134749992Sbostic (void) tcsetpgrp(FSHTTY, pgrp);
1348*68576Schristos sigprocmask(SIG_SETMASK, &osigset, NULL);
134949992Sbostic }
135049992Sbostic
135149992Sbostic if (tpgrp > 0)
135249992Sbostic tpgrp = 0; /* gave tty away */
13531302Sbill }
1354