source: trunk/third/tcsh/sh.proc.c @ 10519

Revision 10519, 56.2 KB checked in by lcs, 27 years ago (diff)
CVS: CVS: Fixed problem with referencing beyond the end of mesg array when NSIG was greater than its length. Use separate "sizeof" counter so the code is not vulnerable to misconfiguration due to broken ifdefs, since the ifdefs are very brittle.
Line 
1/* $Header: /afs/dev.mit.edu/source/repository/third/tcsh/sh.proc.c,v 1.2 1997-10-14 21:25:16 lcs Exp $ */
2/*
3 * sh.proc.c: Job manipulations
4 */
5/*-
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *      This product includes software developed by the University of
20 *      California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37#include "sh.h"
38
39RCSID("$Id: sh.proc.c,v 1.2 1997-10-14 21:25:16 lcs Exp $")
40
41#include "ed.h"
42#include "tc.h"
43#include "tc.wait.h"
44
45#ifdef aiws
46# undef HZ
47# define HZ 16
48#endif /* aiws */
49
50#if (defined(_BSD) && defined(_BSD_INCLUDES)) || (defined(IRIS4D) && __STDC__)
51# define BSDWAIT
52#endif
53#ifndef WTERMSIG
54# define WTERMSIG(w)    (((union wait *) &(w))->w_termsig)
55# ifndef BSDWAIT
56#  define BSDWAIT
57# endif
58#endif /* !WTERMSIG */
59#ifndef WEXITSTATUS
60# define WEXITSTATUS(w) (((union wait *) &(w))->w_retcode)
61#endif /* !WEXITSTATUS */
62#ifndef WSTOPSIG
63# define WSTOPSIG(w)    (((union wait *) &(w))->w_stopsig)
64#endif /* WSTOPSIG */
65
66#ifndef WCOREDUMP
67# ifdef BSDWAIT
68#  define WCOREDUMP(w)  (((union wait *) &(w))->w_coredump)
69# else /* !BSDWAIT */
70#  define WCOREDUMP(w)  ((w) & 0200)
71# endif /* !BSDWAIT */
72#endif /* !WCOREDUMP */
73
74/*
75 * C Shell - functions that manage processes, handling hanging, termination
76 */
77
78#define BIGINDEX        9       /* largest desirable job index */
79
80#ifdef BSDTIMES
81# if defined(SUNOS4) || defined(hp9000)
82static struct rusage zru = {{0L, 0L}, {0L, 0L}, 0L, 0L, 0L, 0L,
83                            0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L};
84
85# else /* !SUNOS4 && !hp9000 */
86#  ifdef masscomp
87/*
88 * Initialization of this structure under RTU 4.1A & RTU 5.0 is problematic
89 * because the first two elements are unions of a time_t and a struct timeval.
90 * So we'll just have to trust the loader to do the "right thing", DAS DEC-90.
91 */
92static struct rusage zru;
93#  else /* masscomp */
94static struct rusage zru = {{0L, 0L}, {0L, 0L}, 0, 0, 0, 0, 0, 0, 0,
95                            0, 0, 0, 0, 0, 0};
96#  endif /* masscomp */
97# endif /* !SUNOS4 && !hp9000 */
98#else /* ! BSDTIMES */
99# ifdef _SEQUENT_
100static struct process_stats zru = {{0L, 0L}, {0L, 0L}, 0, 0, 0, 0, 0, 0, 0,
101                                   0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
102# else /* !_SEQUENT_ */
103static struct tms zru = {0L, 0L, 0L, 0L}, lru = {0L, 0L, 0L, 0L};
104# endif /* !_SEQUENT_ */
105#endif /* !BSDTIMES */
106
107#ifndef RUSAGE_CHILDREN
108# define        RUSAGE_CHILDREN -1
109#endif
110
111static  void             pflushall      __P((void));
112static  void             pflush         __P((struct process *));
113static  void             pclrcurr       __P((struct process *));
114static  void             padd           __P((struct command *));
115static  int              pprint         __P((struct process *, int));
116static  void             ptprint        __P((struct process *));
117static  void             pads           __P((Char *));
118static  void             pkill          __P((Char **, int));
119static  struct process  *pgetcurr       __P((struct process *));
120static  void             okpcntl        __P((void));
121
122/*
123 * pchild - called at interrupt level by the SIGCHLD signal
124 *      indicating that at least one child has terminated or stopped
125 *      thus at least one wait system call will definitely return a
126 *      childs status.  Top level routines (like pwait) must be sure
127 *      to mask interrupts when playing with the proclist data structures!
128 */
129sigret_t
130/*ARGSUSED*/
131pchild(snum)
132int snum;
133{
134    register struct process *pp;
135    register struct process *fp;
136    register int pid;
137#if defined(BSDJOBS) || (!defined(BSDTIMES) && (defined(ODT) || defined(aiws) || defined(uts)))
138    extern int insource;
139#endif /* BSDJOBS */
140#ifdef BSDWAIT
141    union wait w;
142#else /* !BSDWAIT */
143    int     w;
144#endif /* !BSDWAIT */
145    int     jobflags;
146#ifdef BSDTIMES
147    struct rusage ru;
148#else /* !BSDTIMES */
149# ifdef _SEQUENT_
150    struct process_stats ru;
151    struct process_stats cpst1, cpst2;
152    timeval_t tv;
153# else /* !_SEQUENT_ */
154    struct tms proctimes;
155
156    if (!timesdone) {
157        timesdone++;
158        (void) times(&shtimes);
159    }
160# endif /* _SEQUENT_ */
161#endif /* BSDTIMES */
162
163#ifdef JOBDEBUG
164    xprintf("pchild()\n");
165#endif  /* JOBDEBUG */
166
167/* Christos on where the signal(SIGCHLD, pchild) shoud be:
168 *
169 * I think that it should go *after* the wait, unlike most signal handlers.
170 *
171 * In release two (for which I have manuals), it says that wait will remove
172 * the first child from the queue of dead children.
173 * All the rest of the children that die while in the signal handler of the
174 * SIGC(H)LD, will be placed in the queue. If signal is called to re-establish
175 * the signal handler, and there are items in the queue, the process will
176 * receive another SIGC(H)LD before signal returns. BTW this is from the
177 * manual page on comp-sim... Maybe it is not applicable to the hp's, but
178 * I read on the news in comp.unix.wizards or comp.unix.questions yesterday
179 * that another person was claiming the the signal() call should be after
180 * the wait().
181 */
182
183loop:
184    errno = 0;                  /* reset, just in case */
185#ifdef JOBDEBUG
186    xprintf("Waiting...\n");
187    flush();
188#endif
189#ifdef BSDJOBS
190# ifdef BSDTIMES
191    /* both a wait3 and rusage */
192#  if !defined(BSDWAIT) || defined(NeXT) || defined(MACH) || (defined(IRIS4D) && __STDC__ && SYSVREL <= 3)
193    pid = wait3(&w,
194       (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru);
195#  else /* BSDWAIT */
196    pid = wait3(&w.w_status,
197       (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru);
198#  endif /* BSDWAIT */
199# else /* !BSDTIMES */
200#  ifdef _SEQUENT_
201    (void) get_process_stats(&tv, PS_SELF, 0, &cpst1);
202    pid = waitpid(-1, &w,
203            (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG));
204    (void) get_process_stats(&tv, PS_SELF, 0, &cpst2);
205    pr_stat_sub(&cpst2, &cpst1, &ru);
206#  else /* !_SEQUENT_ */
207#   ifndef POSIX
208    /* we have a wait3, but no rusage stuff */
209    pid = wait3(&w.w_status,
210         (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0);
211#   else /* POSIX */
212    pid = waitpid(-1, &w,
213            (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG));
214#   endif /* POSIX */
215#  endif /* !_SEQUENT_ */
216# endif /* !BSDTIMES */
217#else /* !BSDJOBS */
218# ifdef BSDTIMES
219#  define HAVEwait3
220    /* both a wait3 and rusage */
221#  ifdef hpux
222    pid = wait3(&w.w_status, WNOHANG, 0);
223#  else /* !hpux */
224    pid = wait3(&w.w_status, WNOHANG, &ru);
225#  endif /* !hpux */
226# else /* !BSDTIMES */
227# ifdef ODT  /* For Sco Unix 3.2.0 or ODT 1.0 */
228#  define HAVEwait3
229    pid = waitpid(-1, &w,
230            (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG));
231# endif /* ODT */
232# if defined(aiws) || defined(uts)
233#  define HAVEwait3
234    pid = wait3(&w.w_status,
235        (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0);
236# endif /* aiws || uts */
237# ifndef HAVEwait3
238#  ifdef UNRELSIGS
239    /* no wait3, therefore no rusage */
240    /* on Sys V, this may hang.  I hope it's not going to be a problem */
241#   ifdef _MINIX
242    pid = wait(&w);
243#   else /* !_MINIX */
244    pid = ourwait(&w.w_status);
245#   endif /* _MINIX */
246#  else /* UNRELSIGS */
247    /*
248     * XXX: for greater than 3 we should use waitpid().
249     * but then again, SVR4 falls into the POSIX/BSDJOBS category.
250     */
251    pid = wait(&w.w_status);
252#  endif /* SYSVREL >= 3 */
253# endif /* HAVEwait3 */
254# endif /* BSDTIMES */
255# ifndef BSDSIGS
256    (void) sigset(SIGCHLD, pchild);
257# endif /* !BSDSIGS */
258#endif /* BSDJOBS */
259
260#ifdef JOBDEBUG
261    {
262        char    buffer[100];
263        xsprintf(buffer, "pid %d, retval %x termsig %x retcode %x\n",
264                 pid, w, WTERMSIG(w), WEXITSTATUS(w));
265        xprintf(buffer);
266        flush();
267    }
268#endif /* JOBDEBUG */
269
270    if (pid <= 0) {
271#ifdef JOBDEBUG
272        xprintf("errno == %d\n", errno);
273#endif
274        if (errno == EINTR) {
275            errno = 0;
276            goto loop;
277        }
278        pnoprocesses = pid == -1;
279#ifndef SIGVOID
280        return (0);
281#else /* !SIGVOID */
282        return;
283#endif /* SIGVOID */
284    }
285    for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
286        if (pid == pp->p_procid)
287            goto found;
288#ifndef BSDJOBS
289    /* this should never have happened */
290    stderror(ERR_SYNC, pid);
291    xexit(0);
292#else /* BSDJOBS */
293    goto loop;
294#endif /* BSDJOBS */
295found:
296    if (pid == atoi(short2str(value(STRchild))))
297        unsetv(STRchild);
298    pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED);
299    if (WIFSTOPPED(w)) {
300        pp->p_flags |= PSTOPPED;
301        pp->p_reason = WSTOPSIG(w);
302    }
303    else {
304        if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime))
305#ifndef BSDTIMES
306# ifdef _SEQUENT_
307            (void) get_process_stats(&pp->p_etime, PS_SELF, NULL, NULL);
308# else  /* !_SEQUENT_ */
309#  ifndef COHERENT
310            pp->p_etime = times(&proctimes);
311#  else /* !COHERENT */
312            pp->p_etime = HZ * time(NULL);
313            times(&proctimes);
314#  endif /* !COHERENT */
315# endif /* !_SEQUENT_ */
316#else /* BSDTIMES */
317            (void) gettimeofday(&pp->p_etime, NULL);
318#endif /* BSDTIMES */
319
320
321#if defined(BSDTIMES) || defined(_SEQUENT_)
322        pp->p_rusage = ru;
323#else /* !BSDTIMES && !_SEQUENT_ */
324        (void) times(&proctimes);
325        pp->p_utime = proctimes.tms_cutime - shtimes.tms_cutime;
326        pp->p_stime = proctimes.tms_cstime - shtimes.tms_cstime;
327        shtimes = proctimes;
328#endif /* !BSDTIMES && !_SEQUENT_ */
329        if (WIFSIGNALED(w)) {
330            if (WTERMSIG(w) == SIGINT)
331                pp->p_flags |= PINTERRUPTED;
332            else
333                pp->p_flags |= PSIGNALED;
334            if (WCOREDUMP(w))
335                pp->p_flags |= PDUMPED;
336            pp->p_reason = WTERMSIG(w);
337        }
338        else {
339            pp->p_reason = WEXITSTATUS(w);
340            if (pp->p_reason != 0)
341                pp->p_flags |= PAEXITED;
342            else
343                pp->p_flags |= PNEXITED;
344        }
345    }
346    jobflags = 0;
347    fp = pp;
348    do {
349        if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 &&
350            !child && adrof(STRtime) &&
351#ifdef BSDTIMES
352            fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec
353#else /* !BSDTIMES */
354# ifdef _SEQUENT_
355            fp->p_rusage.ps_utime.tv_sec + fp->p_rusage.ps_stime.tv_sec
356# else /* !_SEQUENT_ */
357#  ifndef POSIX
358            (fp->p_utime + fp->p_stime) / HZ
359#  else /* POSIX */
360            (fp->p_utime + fp->p_stime) / clk_tck
361#  endif /* POSIX */
362# endif /* !_SEQUENT_ */
363#endif /* !BSDTIMES */
364            >= atoi(short2str(value(STRtime))))
365            fp->p_flags |= PTIME;
366        jobflags |= fp->p_flags;
367    } while ((fp = fp->p_friends) != pp);
368    pp->p_flags &= ~PFOREGND;
369    if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
370        pp->p_flags &= ~PPTIME;
371        pp->p_flags |= PTIME;
372    }
373    if ((jobflags & (PRUNNING | PREPORTED)) == 0) {
374        fp = pp;
375        do {
376            if (fp->p_flags & PSTOPPED)
377                fp->p_flags |= PREPORTED;
378        } while ((fp = fp->p_friends) != pp);
379        while (fp->p_procid != fp->p_jobid)
380            fp = fp->p_friends;
381        if (jobflags & PSTOPPED) {
382            if (pcurrent && pcurrent != fp)
383                pprevious = pcurrent;
384            pcurrent = fp;
385        }
386        else
387            pclrcurr(fp);
388        if (jobflags & PFOREGND) {
389            if (!(jobflags & (PSIGNALED | PSTOPPED | PPTIME) ||
390#ifdef IIASA
391                jobflags & PAEXITED ||
392#endif /* IIASA */
393                !eq(dcwd->di_name, fp->p_cwd->di_name))) {
394            /* PWP: print a newline after ^C */
395                if (jobflags & PINTERRUPTED) {
396#ifdef SHORT_STRINGS
397                    xputchar('\r' | QUOTE), xputchar('\n');
398#else /* !SHORT_STRINGS */
399                    xprintf("\215\n");  /* \215 is a quoted ^M */
400#endif /* !SHORT_STRINGS */
401                }
402#ifdef notdef
403                else if ((jobflags & (PTIME|PSTOPPED)) == PTIME)
404                    ptprint(fp);
405#endif
406            }
407        }
408        else {
409            if (jobflags & PNOTIFY || adrof(STRnotify)) {
410#ifdef SHORT_STRINGS
411                xputchar('\r' | QUOTE), xputchar('\n');
412#else /* !SHORT_STRINGS */
413                xprintf("\215\n");      /* \215 is a quoted ^M */
414#endif /* !SHORT_STRINGS */
415                (void) pprint(pp, NUMBER | NAME | REASON);
416                if ((jobflags & PSTOPPED) == 0)
417                    pflush(pp);
418                {
419                    extern Char GettingInput;
420
421                    if (GettingInput) {
422                        errno = 0;
423                        (void) Rawmode();
424#ifdef notdef
425                        /*
426                         * don't really want to do that, because it
427                         * will erase our message in case of multi-line
428                         * input
429                         */
430                        ClearLines();
431#endif
432                        ClearDisp();
433                        Refresh();
434                    }
435                }
436            }
437            else {
438                fp->p_flags |= PNEEDNOTE;
439                neednote++;
440            }
441        }
442    }
443#if defined(BSDJOBS) || defined(HAVEwait3)
444    goto loop;
445#endif /* BSDJOBS || HAVEwait3 */
446}
447
448void
449pnote()
450{
451    register struct process *pp;
452    int     flags;
453#ifdef BSDSIGS
454    sigmask_t omask;
455#endif /* BSDSIGS */
456
457    neednote = 0;
458    for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) {
459        if (pp->p_flags & PNEEDNOTE) {
460#ifdef BSDSIGS
461            omask = sigblock(sigmask(SIGCHLD));
462#else /* !BSDSIGS */
463            (void) sighold(SIGCHLD);
464#endif /* !BSDSIGS */
465            pp->p_flags &= ~PNEEDNOTE;
466            flags = pprint(pp, NUMBER | NAME | REASON);
467            if ((flags & (PRUNNING | PSTOPPED)) == 0)
468                pflush(pp);
469#ifdef BSDSIGS
470            (void) sigsetmask(omask);
471#else /* !BSDSIGS */
472            (void) sigrelse(SIGCHLD);
473#endif /* !BSDSIGS */
474        }
475    }
476}
477
478/*
479 * pwait - wait for current job to terminate, maintaining integrity
480 *      of current and previous job indicators.
481 */
482void
483pwait()
484{
485    register struct process *fp, *pp;
486#ifdef BSDSIGS
487    sigmask_t omask;
488#endif /* BSDSIGS */
489
490    /*
491     * Here's where dead procs get flushed.
492     */
493#ifdef BSDSIGS
494    omask = sigblock(sigmask(SIGCHLD));
495#else /* !BSDSIGS */
496    (void) sighold(SIGCHLD);
497#endif /* !BSDSIGS */
498    for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next)
499        if (pp->p_procid == 0) {
500            fp->p_next = pp->p_next;
501            xfree((ptr_t) pp->p_command);
502            if (pp->p_cwd && --pp->p_cwd->di_count == 0)
503                if (pp->p_cwd->di_next == 0)
504                    dfree(pp->p_cwd);
505            xfree((ptr_t) pp);
506            pp = fp;
507        }
508#ifdef BSDSIGS
509    (void) sigsetmask(omask);
510#else /* !BSDSIGS */
511    (void) sigrelse(SIGCHLD);
512# ifdef notdef
513    if (setintr)
514        sigignore(SIGINT);
515# endif
516#endif /* !BSDSIGS */
517    pjwait(pcurrjob);
518}
519
520
521/*
522 * pjwait - wait for a job to finish or become stopped
523 *      It is assumed to be in the foreground state (PFOREGND)
524 */
525void
526pjwait(pp)
527    register struct process *pp;
528{
529    register struct process *fp;
530    int     jobflags, reason;
531#ifdef BSDSIGS
532    sigmask_t omask;
533#endif /* BSDSIGS */
534#ifdef UNRELSIGS
535    sigret_t (*inthandler)();
536#endif /* UNRELSIGS */
537    while (pp->p_procid != pp->p_jobid)
538        pp = pp->p_friends;
539    fp = pp;
540
541    do {
542        if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING)
543            xprintf("BUG: waiting for background job!\n");
544    } while ((fp = fp->p_friends) != pp);
545    /*
546     * Now keep pausing as long as we are not interrupted (SIGINT), and the
547     * target process, or any of its friends, are running
548     */
549    fp = pp;
550#ifdef BSDSIGS
551    omask = sigblock(sigmask(SIGCHLD));
552#endif /* BSDSIGS */
553#ifdef UNRELSIGS
554    if (setintr)
555        inthandler = signal(SIGINT, SIG_IGN);
556#endif /* UNRELSIGS */
557    for (;;) {
558#ifndef BSDSIGS
559        (void) sighold(SIGCHLD);
560#endif /* !BSDSIGS */
561        jobflags = 0;
562        do
563            jobflags |= fp->p_flags;
564        while ((fp = (fp->p_friends)) != pp);
565        if ((jobflags & PRUNNING) == 0)
566            break;
567#ifdef JOBDEBUG
568        xprintf("starting to sigpause for  SIGCHLD on %d\n", fp->p_procid);
569#endif /* JOBDEBUG */
570#ifdef BSDSIGS
571        /* sigpause(sigblock((sigmask_t) 0) &~ sigmask(SIGCHLD)); */
572        (void) sigpause(omask & ~sigmask(SIGCHLD));
573#else /* !BSDSIGS */
574        (void) sigpause(SIGCHLD);
575#endif /* !BSDSIGS */
576    }
577#ifdef BSDSIGS
578    (void) sigsetmask(omask);
579#else /* !BSDSIGS */
580    (void) sigrelse(SIGCHLD);
581#endif /* !BSDSIGS */
582#ifdef UNRELSIGS
583    if (setintr)
584        (void) signal(SIGINT, inthandler);
585#endif /* UNRELSIGS */
586#ifdef BSDJOBS
587    if (tpgrp > 0)              /* get tty back */
588        (void) tcsetpgrp(FSHTTY, tpgrp);
589#endif /* BSDJOBS */
590    if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) ||
591        !eq(dcwd->di_name, fp->p_cwd->di_name)) {
592        if (jobflags & PSTOPPED) {
593            xputchar('\n');
594            if (adrof(STRlistjobs)) {
595                Char   *jobcommand[3];
596
597                jobcommand[0] = STRjobs;
598                if (eq(value(STRlistjobs), STRlong))
599                    jobcommand[1] = STRml;
600                else
601                    jobcommand[1] = NULL;
602                jobcommand[2] = NULL;
603
604                dojobs(jobcommand, NULL);
605                (void) pprint(pp, SHELLDIR);
606            }
607            else
608                (void) pprint(pp, AREASON | SHELLDIR);
609        }
610        else
611            (void) pprint(pp, AREASON | SHELLDIR);
612    }
613    if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr &&
614        (!gointr || !eq(gointr, STRminus))) {
615        if ((jobflags & PSTOPPED) == 0)
616            pflush(pp);
617        pintr1(0);
618        /* NOTREACHED */
619    }
620    reason = 0;
621    fp = pp;
622    do {
623        if (fp->p_reason)
624            reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ?
625                fp->p_reason | META : fp->p_reason;
626    } while ((fp = fp->p_friends) != pp);
627    /*
628     * Don't report on backquoted jobs, cause it will mess up
629     * their output.
630     */
631    if ((reason != 0) && (adrof(STRprintexitvalue)) &&
632        (pp->p_flags & PBACKQ) == 0)
633        xprintf("Exit %d\n", reason);
634    set(STRstatus, putn(reason));
635    if (reason && exiterr)
636        exitstat();
637    pflush(pp);
638}
639
640/*
641 * dowait - wait for all processes to finish
642 */
643
644/*ARGSUSED*/
645void
646dowait(v, c)
647    Char **v;
648    struct command *c;
649{
650    register struct process *pp;
651#ifdef BSDSIGS
652    sigmask_t omask;
653#endif /* BSDSIGS */
654
655    pjobs++;
656#ifdef BSDSIGS
657    omask = sigblock(sigmask(SIGCHLD));
658loop:
659#else /* !BSDSIGS */
660    if (setintr)
661        (void) sigrelse(SIGINT);
662loop:
663    (void) sighold(SIGCHLD);
664#endif /* !BSDSIGS */
665    for (pp = proclist.p_next; pp; pp = pp->p_next)
666        if (pp->p_procid &&     /* pp->p_procid == pp->p_jobid && */
667            pp->p_flags & PRUNNING) {
668#ifdef BSDSIGS
669            (void) sigpause((sigmask_t) 0);
670#else /* !BSDSIGS */
671            (void) sigpause(SIGCHLD);
672#endif /* !BSDSIGS */
673            goto loop;
674        }
675#ifdef BSDSIGS
676    (void) sigsetmask(omask);
677#else /* !BSDSIGS */
678    (void) sigrelse(SIGCHLD);
679#endif /* !BSDSIGS */
680    pjobs = 0;
681}
682
683/*
684 * pflushall - flush all jobs from list (e.g. at fork())
685 */
686static void
687pflushall()
688{
689    register struct process *pp;
690
691    for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
692        if (pp->p_procid)
693            pflush(pp);
694}
695
696/*
697 * pflush - flag all process structures in the same job as the
698 *      the argument process for deletion.  The actual free of the
699 *      space is not done here since pflush is called at interrupt level.
700 */
701static void
702pflush(pp)
703    register struct process *pp;
704{
705    register struct process *np;
706    register int idx;
707
708    if (pp->p_procid == 0) {
709        xprintf("BUG: process flushed twice");
710        return;
711    }
712    while (pp->p_procid != pp->p_jobid)
713        pp = pp->p_friends;
714    pclrcurr(pp);
715    if (pp == pcurrjob)
716        pcurrjob = 0;
717    idx = pp->p_index;
718    np = pp;
719    do {
720        np->p_index = np->p_procid = 0;
721        np->p_flags &= ~PNEEDNOTE;
722    } while ((np = np->p_friends) != pp);
723    if (idx == pmaxindex) {
724        for (np = proclist.p_next, idx = 0; np; np = np->p_next)
725            if (np->p_index > idx)
726                idx = np->p_index;
727        pmaxindex = idx;
728    }
729}
730
731/*
732 * pclrcurr - make sure the given job is not the current or previous job;
733 *      pp MUST be the job leader
734 */
735static void
736pclrcurr(pp)
737    register struct process *pp;
738{
739    if (pp == pcurrent)
740        if (pprevious != NULL) {
741            pcurrent = pprevious;
742            pprevious = pgetcurr(pp);
743        }
744        else {
745            pcurrent = pgetcurr(pp);
746            pprevious = pgetcurr(pp);
747        }
748    else if (pp == pprevious)
749        pprevious = pgetcurr(pp);
750}
751
752/* +4 here is 1 for '\0', 1 ea for << >& >> */
753static Char command[PMAXLEN + 4];
754static int cmdlen;
755static Char *cmdp;
756
757/*
758 * palloc - allocate a process structure and fill it up.
759 *      an important assumption is made that the process is running.
760 */
761void
762palloc(pid, t)
763    int     pid;
764    register struct command *t;
765{
766    register struct process *pp;
767    int     i;
768
769    pp = (struct process *) xcalloc(1, (size_t) sizeof(struct process));
770    pp->p_procid = pid;
771    pp->p_flags = ((t->t_dflg & F_AMPERSAND) ? 0 : PFOREGND) | PRUNNING;
772    if (t->t_dflg & F_TIME)
773        pp->p_flags |= PPTIME;
774    if (t->t_dflg & F_BACKQ)
775        pp->p_flags |= PBACKQ;
776    cmdp = command;
777    cmdlen = 0;
778    padd(t);
779    *cmdp++ = 0;
780    if (t->t_dflg & F_PIPEOUT) {
781        pp->p_flags |= PPOU;
782        if (t->t_dflg & F_STDERR)
783            pp->p_flags |= PDIAG;
784    }
785    pp->p_command = Strsave(command);
786    if (pcurrjob) {
787        struct process *fp;
788
789        /* careful here with interrupt level */
790        pp->p_cwd = 0;
791        pp->p_index = pcurrjob->p_index;
792        pp->p_friends = pcurrjob;
793        pp->p_jobid = pcurrjob->p_procid;
794        for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
795            continue;
796        fp->p_friends = pp;
797    }
798    else {
799        pcurrjob = pp;
800        pp->p_jobid = pid;
801        pp->p_friends = pp;
802        pp->p_cwd = dcwd;
803        dcwd->di_count++;
804        if (pmaxindex < BIGINDEX)
805            pp->p_index = ++pmaxindex;
806        else {
807            struct process *np;
808
809            for (i = 1;; i++) {
810                for (np = proclist.p_next; np; np = np->p_next)
811                    if (np->p_index == i)
812                        goto tryagain;
813                pp->p_index = i;
814                if (i > pmaxindex)
815                    pmaxindex = i;
816                break;
817        tryagain:;
818            }
819        }
820        if (pcurrent == NULL)
821            pcurrent = pp;
822        else if (pprevious == NULL)
823            pprevious = pp;
824    }
825    pp->p_next = proclist.p_next;
826    proclist.p_next = pp;
827#ifdef BSDTIMES
828    (void) gettimeofday(&pp->p_btime, NULL);
829#else /* !BSDTIMES */
830# ifdef _SEQUENT_
831    (void) get_process_stats(&pp->p_btime, PS_SELF, NULL, NULL);
832# else /* !_SEQUENT_ */
833    {
834        struct tms tmptimes;
835
836#  ifndef COHERENT
837        pp->p_btime = times(&tmptimes);
838#  else /* !COHERENT */
839        pp->p_btime = HZ * time(NULL);
840        times(&tmptimes);
841#  endif /* !COHERENT */
842    }
843# endif /* !_SEQUENT_ */
844#endif /* !BSDTIMES */
845}
846
847static void
848padd(t)
849    register struct command *t;
850{
851    Char  **argp;
852
853    if (t == 0)
854        return;
855    switch (t->t_dtyp) {
856
857    case NODE_PAREN:
858        pads(STRLparensp);
859        padd(t->t_dspr);
860        pads(STRspRparen);
861        break;
862
863    case NODE_COMMAND:
864        for (argp = t->t_dcom; *argp; argp++) {
865            pads(*argp);
866            if (argp[1])
867                pads(STRspace);
868        }
869        break;
870
871    case NODE_OR:
872    case NODE_AND:
873    case NODE_PIPE:
874    case NODE_LIST:
875        padd(t->t_dcar);
876        switch (t->t_dtyp) {
877        case NODE_OR:
878            pads(STRspor2sp);
879            break;
880        case NODE_AND:
881            pads(STRspand2sp);
882            break;
883        case NODE_PIPE:
884            pads(STRsporsp);
885            break;
886        case NODE_LIST:
887            pads(STRsemisp);
888            break;
889        default:
890            break;
891        }
892        padd(t->t_dcdr);
893        return;
894
895    default:
896        break;
897    }
898    if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) {
899        pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp);
900        pads(t->t_dlef);
901    }
902    if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) {
903        pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow);
904        if (t->t_dflg & F_STDERR)
905            pads(STRand);
906        pads(STRspace);
907        pads(t->t_drit);
908    }
909}
910
911static void
912pads(cp)
913    Char   *cp;
914{
915    register int i;
916
917    /*
918     * Avoid the Quoted Space alias hack! Reported by:
919     * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks)
920     */
921    if (cp[0] == STRQNULL[0])
922        cp++;
923
924    i = Strlen(cp);
925
926    if (cmdlen >= PMAXLEN)
927        return;
928    if (cmdlen + i >= PMAXLEN) {
929        (void) Strcpy(cmdp, STRsp3dots);
930        cmdlen = PMAXLEN;
931        cmdp += 4;
932        return;
933    }
934    (void) Strcpy(cmdp, cp);
935    cmdp += i;
936    cmdlen += i;
937}
938
939/*
940 * psavejob - temporarily save the current job on a one level stack
941 *      so another job can be created.  Used for { } in exp6
942 *      and `` in globbing.
943 */
944void
945psavejob()
946{
947    pholdjob = pcurrjob;
948    pcurrjob = NULL;
949}
950
951/*
952 * prestjob - opposite of psavejob.  This may be missed if we are interrupted
953 *      somewhere, but pendjob cleans up anyway.
954 */
955void
956prestjob()
957{
958    pcurrjob = pholdjob;
959    pholdjob = NULL;
960}
961
962/*
963 * pendjob - indicate that a job (set of commands) has been completed
964 *      or is about to begin.
965 */
966void
967pendjob()
968{
969    register struct process *pp, *tp;
970
971    if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) {
972        pp = pcurrjob;
973        while (pp->p_procid != pp->p_jobid)
974            pp = pp->p_friends;
975        xprintf("[%d]", pp->p_index);
976        tp = pp;
977        do {
978            xprintf(" %d", pp->p_procid);
979            pp = pp->p_friends;
980        } while (pp != tp);
981        xputchar('\n');
982    }
983    pholdjob = pcurrjob = 0;
984}
985
986/*
987 * pprint - print a job
988 */
989
990/*
991 * Hacks have been added for SVR4 to deal with pipe's being spawned in
992 * reverse order
993 *
994 * David Dawes (dawes@physics.su.oz.au) Oct 1991
995 */
996
997static int
998pprint(pp, flag)
999    register struct process *pp;
1000    bool    flag;
1001{
1002    register status, reason;
1003    struct process *tp;
1004    extern char *linp, linbuf[];
1005    int     jobflags, pstatus, pcond;
1006    char   *format;
1007
1008#ifdef BACKPIPE
1009    struct process *pipehead = NULL, *pipetail = NULL, *pmarker = NULL;
1010    int inpipe = 0;
1011#endif /* BACKPIPE */
1012
1013    while (pp->p_procid != pp->p_jobid)
1014        pp = pp->p_friends;
1015    if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
1016        pp->p_flags &= ~PPTIME;
1017        pp->p_flags |= PTIME;
1018    }
1019    tp = pp;
1020    status = reason = -1;
1021    jobflags = 0;
1022    do {
1023#ifdef BACKPIPE
1024        /*
1025         * The pipeline is reversed, so locate the real head of the pipeline
1026         * if pp is at the tail of a pipe (and not already in a pipeline)
1027         */
1028        if ((pp->p_friends->p_flags & PPOU) && !inpipe && (flag & NAME)) {
1029            inpipe = 1;
1030            pipetail = pp;
1031            do
1032                pp = pp->p_friends;
1033            while (pp->p_friends->p_flags & PPOU);
1034            pipehead = pp;
1035            pmarker = pp;
1036        /*
1037         * pmarker is used to hold the place of the proc being processed, so
1038         * we can search for the next one downstream later.
1039         */
1040        }
1041        pcond = (tp != pp || (inpipe && tp == pp));
1042#else /* !BACKPIPE */
1043        pcond = (tp != pp);
1044#endif /* BACKPIPE */
1045
1046        jobflags |= pp->p_flags;
1047        pstatus = pp->p_flags & PALLSTATES;
1048        if (pcond && linp != linbuf && !(flag & FANCY) &&
1049            ((pstatus == status && pp->p_reason == reason) ||
1050             !(flag & REASON)))
1051            xputchar(' ');
1052        else {
1053            if (pcond && linp != linbuf)
1054                xputchar('\n');
1055            if (flag & NUMBER) {
1056#ifdef BACKPIPE
1057                pcond = ((pp == tp && !inpipe) ||
1058                         (inpipe && pipetail == tp && pp == pipehead));
1059#else /* BACKPIPE */
1060                pcond = (pp == tp);
1061#endif /* BACKPIPE */
1062                if (pcond)
1063                    xprintf("[%d]%s %c ", pp->p_index,
1064                            pp->p_index < 10 ? " " : "",
1065                            pp == pcurrent ? '+' :
1066                            (pp == pprevious ? '-' : ' '));
1067                else
1068                    xprintf("       ");
1069            }
1070            if (flag & FANCY) {
1071#ifdef TCF
1072                extern char *sitename();
1073
1074#endif /* TCF */
1075                xprintf("%5d ", pp->p_procid);
1076#ifdef TCF
1077                xprintf("%11s ", sitename(pp->p_procid));
1078#endif /* TCF */
1079            }
1080            if (flag & (REASON | AREASON)) {
1081                if (flag & NAME)
1082#ifdef SUSPENDED
1083                    format = "%-23s";
1084#else /* !SUSPENDED */
1085                    format = "%-21s";
1086#endif /* !SUSPENDED */
1087                else
1088                    format = "%s";
1089                if (pstatus == status)
1090                    if (pp->p_reason == reason) {
1091                        xprintf(format, "");
1092                        goto prcomd;
1093                    }
1094                    else
1095                        reason = pp->p_reason;
1096                else {
1097                    status = pstatus;
1098                    reason = pp->p_reason;
1099                }
1100                switch (status) {
1101
1102                case PRUNNING:
1103                    xprintf(format, "Running ");
1104                    break;
1105
1106                case PINTERRUPTED:
1107                case PSTOPPED:
1108                case PSIGNALED:
1109                    /*
1110                     * tell what happened to the background job
1111                     * From: Michael Schroeder
1112                     * <mlschroe@immd4.informatik.uni-erlangen.de>
1113                     */
1114                    if ((flag & REASON)
1115                        || ((flag & AREASON)
1116                            && reason != SIGINT
1117                            && (reason != SIGPIPE
1118                                || (pp->p_flags & PPOU) == 0)))
1119                        xprintf(format, mesg[pp->p_reason & ASCII].pname);
1120                    else
1121                        reason = -1;
1122                    break;
1123
1124                case PNEXITED:
1125                case PAEXITED:
1126                    if (flag & REASON)
1127                        if (pp->p_reason)
1128#ifdef SUSPENDED
1129                            xprintf("Exit %-18d", pp->p_reason);
1130#else /* SUSPENDED */
1131                            xprintf("Exit %-16d", pp->p_reason);
1132#endif /* SUSPENDED */
1133                        else
1134                            xprintf(format, "Done");
1135                    break;
1136
1137                default:
1138                    xprintf("BUG: status=%-9o", status);
1139                }
1140            }
1141        }
1142prcomd:
1143        if (flag & NAME) {
1144            xprintf("%S", pp->p_command);
1145            if (pp->p_flags & PPOU)
1146                xprintf(" |");
1147            if (pp->p_flags & PDIAG)
1148                xprintf("&");
1149        }
1150        if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED)
1151            xprintf(" (core dumped)");
1152        if (tp == pp->p_friends) {
1153            if (flag & AMPERSAND)
1154                xprintf(" &");
1155            if (flag & JOBDIR &&
1156                !eq(tp->p_cwd->di_name, dcwd->di_name)) {
1157                xprintf(" (wd: ");
1158                dtildepr(value(STRhome), tp->p_cwd->di_name);
1159                xprintf(")");
1160            }
1161        }
1162        if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) {
1163            if (linp != linbuf)
1164                xprintf("\n\t");
1165#if defined(BSDTIMES) || defined(_SEQUENT_)
1166            prusage(&zru, &pp->p_rusage, &pp->p_etime,
1167                    &pp->p_btime);
1168#else /* !BSDTIMES && !SEQUENT */
1169            lru.tms_utime = pp->p_utime;
1170            lru.tms_stime = pp->p_stime;
1171            lru.tms_cutime = 0;
1172            lru.tms_cstime = 0;
1173            prusage(&zru, &lru, pp->p_etime,
1174                    pp->p_btime);
1175#endif /* !BSDTIMES && !SEQUENT */
1176
1177        }
1178#ifdef BACKPIPE
1179        pcond = ((tp == pp->p_friends && !inpipe) ||
1180                 (inpipe && pipehead->p_friends == tp && pp == pipetail));
1181#else  /* !BACKPIPE */
1182        pcond = (tp == pp->p_friends);
1183#endif /* BACKPIPE */
1184        if (pcond) {
1185            if (linp != linbuf)
1186                xputchar('\n');
1187            if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
1188                xprintf("(wd now: ");
1189                dtildepr(value(STRhome), dcwd->di_name);
1190                xprintf(")\n");
1191            }
1192        }
1193#ifdef BACKPIPE
1194        if (inpipe) {
1195            /*
1196             * if pmaker == pipetail, we are finished that pipeline, and
1197             * can now skip to past the head
1198             */
1199            if (pmarker == pipetail) {
1200                inpipe = 0;
1201                pp = pipehead;
1202            }
1203            else {
1204            /*
1205             * set pp to one before the one we want next, so the while below
1206             * increments to the correct spot.
1207             */
1208                do
1209                    pp = pp->p_friends;
1210                while (pp->p_friends->p_friends != pmarker);
1211                pmarker = pp->p_friends;
1212            }
1213        }
1214        pcond = ((pp = pp->p_friends) != tp || inpipe);
1215#else /* !BACKPIPE */
1216        pcond = ((pp = pp->p_friends) != tp);
1217#endif /* BACKPIPE */
1218    } while (pcond);
1219
1220    if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) {
1221        if (jobflags & NUMBER)
1222            xprintf("       ");
1223        ptprint(tp);
1224    }
1225    return (jobflags);
1226}
1227
1228/*
1229 * All 4.3 BSD derived implementations are buggy and I've had enough.
1230 * The following implementation produces similar code and works in all
1231 * cases. The 4.3BSD one works only for <, >, !=
1232 */
1233# undef timercmp
1234#  define timercmp(tvp, uvp, cmp) \
1235      (((tvp)->tv_sec == (uvp)->tv_sec) ? \
1236           ((tvp)->tv_usec cmp (uvp)->tv_usec) : \
1237           ((tvp)->tv_sec  cmp (uvp)->tv_sec))
1238
1239static void
1240ptprint(tp)
1241    register struct process *tp;
1242{
1243#ifdef BSDTIMES
1244    struct timeval tetime, diff;
1245    static struct timeval ztime;
1246    struct rusage ru;
1247    static struct rusage zru;
1248    register struct process *pp = tp;
1249
1250    ru = zru;
1251    tetime = ztime;
1252    do {
1253        ruadd(&ru, &pp->p_rusage);
1254        tvsub(&diff, &pp->p_etime, &pp->p_btime);
1255        if (timercmp(&diff, &tetime, >))
1256            tetime = diff;
1257    } while ((pp = pp->p_friends) != tp);
1258    prusage(&zru, &ru, &tetime, &ztime);
1259#else /* !BSDTIMES */
1260# ifdef _SEQUENT_
1261    timeval_t tetime, diff;
1262    static timeval_t ztime;
1263    struct process_stats ru;
1264    static struct process_stats zru;
1265    register struct process *pp = tp;
1266
1267    ru = zru;
1268    tetime = ztime;
1269    do {
1270        ruadd(&ru, &pp->p_rusage);
1271        tvsub(&diff, &pp->p_etime, &pp->p_btime);
1272        if (timercmp(&diff, &tetime, >))
1273            tetime = diff;
1274    } while ((pp = pp->p_friends) != tp);
1275    prusage(&zru, &ru, &tetime, &ztime);
1276# else /* !_SEQUENT_ */
1277#  ifndef POSIX
1278    static time_t ztime = 0;
1279    static time_t zu_time = 0;
1280    static time_t zs_time = 0;
1281    time_t  tetime, diff;
1282    time_t  u_time, s_time;
1283
1284#  else /* POSIX */
1285    static clock_t ztime = 0;
1286    static clock_t zu_time = 0;
1287    static clock_t zs_time = 0;
1288    clock_t tetime, diff;
1289    clock_t u_time, s_time;
1290
1291#  endif /* POSIX */
1292    struct tms zts, rts;
1293    register struct process *pp = tp;
1294
1295    u_time = zu_time;
1296    s_time = zs_time;
1297    tetime = ztime;
1298    do {
1299        u_time += pp->p_utime;
1300        s_time += pp->p_stime;
1301        diff = pp->p_etime - pp->p_btime;
1302        if (diff > tetime)
1303            tetime = diff;
1304    } while ((pp = pp->p_friends) != tp);
1305    zts.tms_utime = zu_time;
1306    zts.tms_stime = zs_time;
1307    zts.tms_cutime = 0;
1308    zts.tms_cstime = 0;
1309    rts.tms_utime = u_time;
1310    rts.tms_stime = s_time;
1311    rts.tms_cutime = 0;
1312    rts.tms_cstime = 0;
1313    prusage(&zts, &rts, tetime, ztime);
1314# endif /* !_SEQUENT_ */
1315#endif  /* !BSDTIMES */
1316}
1317
1318/*
1319 * dojobs - print all jobs
1320 */
1321/*ARGSUSED*/
1322void
1323dojobs(v, c)
1324    Char  **v;
1325    struct command *c;
1326{
1327    register struct process *pp;
1328    register int flag = NUMBER | NAME | REASON;
1329    int     i;
1330
1331    if (chkstop)
1332        chkstop = 2;
1333    if (*++v) {
1334        if (v[1] || !eq(*v, STRml))
1335            stderror(ERR_JOBS);
1336        flag |= FANCY | JOBDIR;
1337    }
1338    for (i = 1; i <= pmaxindex; i++)
1339        for (pp = proclist.p_next; pp; pp = pp->p_next)
1340            if (pp->p_index == i && pp->p_procid == pp->p_jobid) {
1341                pp->p_flags &= ~PNEEDNOTE;
1342                if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED)))
1343                    pflush(pp);
1344                break;
1345            }
1346}
1347
1348/*
1349 * dofg - builtin - put the job into the foreground
1350 */
1351/*ARGSUSED*/
1352void
1353dofg(v, c)
1354    Char  **v;
1355    struct command *c;
1356{
1357    register struct process *pp;
1358
1359    okpcntl();
1360    ++v;
1361    do {
1362        pp = pfind(*v);
1363        pstart(pp, 1);
1364#ifndef BSDSIGS
1365# ifdef notdef
1366        if (setintr)
1367            sigignore(SIGINT);
1368# endif
1369#endif /* !BSDSIGS */
1370        pjwait(pp);
1371    } while (*v && *++v);
1372}
1373
1374/*
1375 * %... - builtin - put the job into the foreground
1376 */
1377/*ARGSUSED*/
1378void
1379dofg1(v, c)
1380    Char  **v;
1381    struct command *c;
1382{
1383    register struct process *pp;
1384
1385    okpcntl();
1386    pp = pfind(v[0]);
1387    pstart(pp, 1);
1388#ifndef BSDSIGS
1389# ifdef notdef
1390    if (setintr)
1391        sigignore(SIGINT);
1392# endif
1393#endif /* !BSDSIGS */
1394    pjwait(pp);
1395}
1396
1397/*
1398 * dobg - builtin - put the job into the background
1399 */
1400/*ARGSUSED*/
1401void
1402dobg(v, c)
1403    Char  **v;
1404    struct command *c;
1405{
1406    register struct process *pp;
1407
1408    okpcntl();
1409    ++v;
1410    do {
1411        pp = pfind(*v);
1412        pstart(pp, 0);
1413    } while (*v && *++v);
1414}
1415
1416/*
1417 * %... & - builtin - put the job into the background
1418 */
1419/*ARGSUSED*/
1420void
1421dobg1(v, c)
1422    Char  **v;
1423    struct command *c;
1424{
1425    register struct process *pp;
1426
1427    pp = pfind(v[0]);
1428    pstart(pp, 0);
1429}
1430
1431/*
1432 * dostop - builtin - stop the job
1433 */
1434/*ARGSUSED*/
1435void
1436dostop(v, c)
1437    Char  **v;
1438    struct command *c;
1439{
1440#ifdef BSDJOBS
1441    pkill(++v, SIGSTOP);
1442#endif /* BSDJOBS */
1443}
1444
1445/*
1446 * dokill - builtin - superset of kill (1)
1447 */
1448/*ARGSUSED*/
1449void
1450dokill(v, c)
1451    Char  **v;
1452    struct command *c;
1453{
1454    register int signum, len = 0;
1455    register char *name;
1456    extern int T_Cols;
1457
1458    v++;
1459    if (v[0] && v[0][0] == '-') {
1460        if (v[0][1] == 'l') {
1461            for (signum = 1; signum <= NSIG && signum < mesg_size; signum++) {
1462                if ((name = mesg[signum].iname) != NULL) {
1463                    len += strlen(name) + 1;
1464                    if (len >= T_Cols - 1) {
1465                        xputchar('\n');
1466                        len = strlen(name) + 1;
1467                    }
1468                    xprintf("%s ", name);
1469                }
1470            }
1471            xputchar('\n');
1472            return;
1473        }
1474        if (Isdigit(v[0][1])) {
1475            signum = atoi(short2str(v[0] + 1));
1476            if (signum < 0 || signum > NSIG)
1477                stderror(ERR_NAME | ERR_BADSIG);
1478        }
1479        else {
1480            for (signum = 1; signum <= NSIG && signum < mesg_size; signum++)
1481                if (mesg[signum].iname &&
1482                    eq(&v[0][1], str2short(mesg[signum].iname)))
1483                    goto gotsig;
1484            setname(short2str(&v[0][1]));
1485            stderror(ERR_NAME | ERR_UNKSIG);
1486        }
1487gotsig:
1488        v++;
1489    }
1490    else
1491        signum = SIGTERM;
1492    pkill(v, signum);
1493}
1494
1495static void
1496pkill(v, signum)
1497    Char  **v;
1498    int     signum;
1499{
1500    register struct process *pp, *np;
1501    int jobflags = 0, err1 = 0;
1502    pid_t     pid;
1503#ifdef BSDSIGS
1504    sigmask_t omask;
1505#endif /* BSDSIGS */
1506    Char   *cp;
1507
1508#ifdef BSDSIGS
1509    omask = sigmask(SIGCHLD);
1510    if (setintr)
1511        omask |= sigmask(SIGINT);
1512    omask = sigblock(omask) & ~omask;
1513#else /* !BSDSIGS */
1514    if (setintr)
1515        (void) sighold(SIGINT);
1516    (void) sighold(SIGCHLD);
1517#endif /* !BSDSIGS */
1518    gflag = 0, tglob(v);
1519    if (gflag) {
1520        v = globall(v);
1521        if (v == 0)
1522            stderror(ERR_NAME | ERR_NOMATCH);
1523    }
1524    else {
1525        v = gargv = saveblk(v);
1526        trim(v);
1527    }
1528
1529    while (v && (cp = *v)) {
1530        if (*cp == '%') {
1531            np = pp = pfind(cp);
1532            do
1533                jobflags |= np->p_flags;
1534            while ((np = np->p_friends) != pp);
1535#ifdef BSDJOBS
1536            switch (signum) {
1537
1538            case SIGSTOP:
1539            case SIGTSTP:
1540            case SIGTTIN:
1541            case SIGTTOU:
1542                if ((jobflags & PRUNNING) == 0) {
1543# ifdef SUSPENDED
1544                    xprintf("%S: Already suspended\n", cp);
1545# else /* !SUSPENDED */
1546                    xprintf("%S: Already stopped\n", cp);
1547# endif /* !SUSPENDED */
1548                    err1++;
1549                    goto cont;
1550                }
1551                break;
1552                /*
1553                 * suspend a process, kill -CONT %, then type jobs; the shell
1554                 * says it is suspended, but it is running; thanks jaap..
1555                 */
1556            case SIGCONT:
1557                pstart(pp, 0);
1558                goto cont;
1559            default:
1560                break;
1561            }
1562#endif /* BSDJOBS */
1563            if (killpg(pp->p_jobid, signum) < 0) {
1564                xprintf("%S: %s\n", cp, strerror(errno));
1565                err1++;
1566            }
1567#ifdef BSDJOBS
1568            if (signum == SIGTERM || signum == SIGHUP)
1569                (void) killpg(pp->p_jobid, SIGCONT);
1570#endif /* BSDJOBS */
1571        }
1572        else if (!(Isdigit(*cp) || *cp == '-'))
1573            stderror(ERR_NAME | ERR_JOBARGS);
1574        else {
1575            pid = atoi(short2str(cp));
1576            if (kill(pid, signum) < 0) {
1577                xprintf("%d: %s\n", pid, strerror(errno));
1578                err1++;
1579                goto cont;
1580            }
1581#ifdef BSDJOBS
1582            if (signum == SIGTERM || signum == SIGHUP)
1583                (void) kill(pid, SIGCONT);
1584#endif /* BSDJOBS */
1585        }
1586cont:
1587        v++;
1588    }
1589    if (gargv)
1590        blkfree(gargv), gargv = 0;
1591#ifdef BSDSIGS
1592    (void) sigsetmask(omask);
1593#else /* !BSDSIGS */
1594    (void) sigrelse(SIGCHLD);
1595    if (setintr)
1596        (void) sigrelse(SIGINT);
1597#endif /* !BSDSIGS */
1598    if (err1)
1599        stderror(ERR_SILENT);
1600}
1601
1602/*
1603 * pstart - start the job in foreground/background
1604 */
1605void
1606pstart(pp, foregnd)
1607    register struct process *pp;
1608    int     foregnd;
1609{
1610    register struct process *np;
1611#ifdef BSDSIGS
1612    sigmask_t omask;
1613#endif /* BSDSIGS */
1614    long    jobflags = 0;
1615
1616#ifdef BSDSIGS
1617    omask = sigblock(sigmask(SIGCHLD));
1618#else /* !BSDSIGS */
1619    (void) sighold(SIGCHLD);
1620#endif
1621    np = pp;
1622    do {
1623        jobflags |= np->p_flags;
1624        if (np->p_flags & (PRUNNING | PSTOPPED)) {
1625            np->p_flags |= PRUNNING;
1626            np->p_flags &= ~PSTOPPED;
1627            if (foregnd)
1628                np->p_flags |= PFOREGND;
1629            else
1630                np->p_flags &= ~PFOREGND;
1631        }
1632    } while ((np = np->p_friends) != pp);
1633    if (!foregnd)
1634        pclrcurr(pp);
1635    (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND);
1636#ifdef BSDJOBS
1637    if (foregnd) {
1638        (void) tcsetpgrp(FSHTTY, pp->p_jobid);
1639    }
1640    /*
1641     * 1. child process of csh (shell script) receives SIGTTIN/SIGTTOU
1642     * 2. parent process (csh) receives SIGCHLD
1643     * 3. The "csh" signal handling function pchild() is invoked
1644     *    with a SIGCHLD signal.
1645     * 4. pchild() calls wait3(WNOHANG) which returns 0.
1646     *    The child process is NOT ready to be waited for at this time.
1647     *    pchild() returns without picking-up the correct status
1648     *    for the child process which generated the SIGCHILD.
1649     * 5. CONSEQUENCE : csh is UNaware that the process is stopped
1650     * 6. THIS LINE HAS BEEN COMMENTED OUT : if (jobflags&PSTOPPED)
1651     *    (beto@aixwiz.austin.ibm.com - aug/03/91)
1652     */
1653
1654    /* if (jobflags & PSTOPPED) */
1655        (void) killpg(pp->p_jobid, SIGCONT);
1656#endif /* BSDJOBS */
1657#ifdef BSDSIGS
1658    (void) sigsetmask(omask);
1659#else /* !BSDSIGS */
1660    (void) sigrelse(SIGCHLD);
1661#endif /* !BSDSIGS */
1662}
1663
1664void
1665panystop(neednl)
1666    bool    neednl;
1667{
1668    register struct process *pp;
1669
1670    chkstop = 2;
1671    for (pp = proclist.p_next; pp; pp = pp->p_next)
1672        if (pp->p_flags & PSTOPPED)
1673            stderror(ERR_STOPPED, neednl ? "\n" : "");
1674}
1675
1676struct process *
1677pfind(cp)
1678    Char   *cp;
1679{
1680    register struct process *pp, *np;
1681
1682    if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) {
1683        if (pcurrent == NULL)
1684            stderror(ERR_NAME | ERR_JOBCUR);
1685        return (pcurrent);
1686    }
1687    if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) {
1688        if (pprevious == NULL)
1689            stderror(ERR_NAME | ERR_JOBPREV);
1690        return (pprevious);
1691    }
1692    if (Isdigit(cp[1])) {
1693        int     idx = atoi(short2str(cp + 1));
1694
1695        for (pp = proclist.p_next; pp; pp = pp->p_next)
1696            if (pp->p_index == idx && pp->p_procid == pp->p_jobid)
1697                return (pp);
1698        stderror(ERR_NAME | ERR_NOSUCHJOB);
1699    }
1700    np = NULL;
1701    for (pp = proclist.p_next; pp; pp = pp->p_next)
1702        if (pp->p_procid == pp->p_jobid) {
1703            if (cp[1] == '?') {
1704                register Char *dp;
1705
1706                for (dp = pp->p_command; *dp; dp++) {
1707                    if (*dp != cp[2])
1708                        continue;
1709                    if (prefix(cp + 2, dp))
1710                        goto match;
1711                }
1712            }
1713            else if (prefix(cp + 1, pp->p_command)) {
1714        match:
1715                if (np)
1716                    stderror(ERR_NAME | ERR_AMBIG);
1717                np = pp;
1718            }
1719        }
1720    if (np)
1721        return (np);
1722    stderror(ERR_NAME | (cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB));
1723    /* NOTREACHED */
1724    return (0);
1725}
1726
1727
1728/*
1729 * pgetcurr - find most recent job that is not pp, preferably stopped
1730 */
1731static struct process *
1732pgetcurr(pp)
1733    register struct process *pp;
1734{
1735    register struct process *np;
1736    register struct process *xp = NULL;
1737
1738    for (np = proclist.p_next; np; np = np->p_next)
1739        if (np != pcurrent && np != pp && np->p_procid &&
1740            np->p_procid == np->p_jobid) {
1741            if (np->p_flags & PSTOPPED)
1742                return (np);
1743            if (xp == NULL)
1744                xp = np;
1745        }
1746    return (xp);
1747}
1748
1749/*
1750 * donotify - flag the job so as to report termination asynchronously
1751 */
1752/*ARGSUSED*/
1753void
1754donotify(v, c)
1755    Char  **v;
1756    struct command *c;
1757{
1758    register struct process *pp;
1759
1760    pp = pfind(*++v);
1761    pp->p_flags |= PNOTIFY;
1762}
1763
1764/*
1765 * Do the fork and whatever should be done in the child side that
1766 * should not be done if we are not forking at all (like for simple builtin's)
1767 * Also do everything that needs any signals fiddled with in the parent side
1768 *
1769 * Wanttty tells whether process and/or tty pgrps are to be manipulated:
1770 *      -1:     leave tty alone; inherit pgrp from parent
1771 *       0:     already have tty; manipulate process pgrps only
1772 *       1:     want to claim tty; manipulate process and tty pgrps
1773 * It is usually just the value of tpgrp.
1774 */
1775
1776int
1777pfork(t, wanttty)
1778    struct command *t;          /* command we are forking for */
1779    int     wanttty;
1780{
1781    register int pid;
1782    bool    ignint = 0;
1783    int     pgrp;
1784#ifdef BSDSIGS
1785    sigmask_t omask;
1786#endif /* BSDSIGS */
1787#ifdef SIGSYNCH
1788    sigvec_t osv;
1789    static sigvec_t nsv = {synch_handler, ~0, 0};
1790#endif /* SIGSYNCH */
1791
1792    /*
1793     * A child will be uninterruptible only under very special conditions.
1794     * Remember that the semantics of '&' is implemented by disconnecting the
1795     * process from the tty so signals do not need to ignored just for '&'.
1796     * Thus signals are set to default action for children unless: we have had
1797     * an "onintr -" (then specifically ignored) we are not playing with
1798     * signals (inherit action)
1799     */
1800    if (setintr)
1801        ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT))
1802            || (gointr && eq(gointr, STRminus));
1803
1804#ifdef COHERENT
1805    ignint |= gointr && eq(gointr, STRminus);
1806#endif /* COHERENT */
1807
1808    /*
1809     * Check for maximum nesting of 16 processes to avoid Forking loops
1810     */
1811    if (child == 16)
1812        stderror(ERR_NESTING, 16);
1813    /*
1814     * Hold SIGCHLD until we have the process installed in our table.
1815     */
1816#ifdef SIGSYNCH
1817    if (mysigvec(SIGSYNCH, &nsv, &osv))
1818        stderror(ERR_SYSTEM, "pfork: sigvec set", strerror(errno));
1819#endif /* SIGSYNCH */
1820#ifdef BSDSIGS
1821    omask = sigblock(sigmask(SIGCHLD));
1822#else /* !BSDSIGS */
1823    (void) sighold(SIGCHLD);
1824#endif /* !BSDSIGS */
1825    while ((pid = fork()) < 0)
1826        if (setintr == 0)
1827            (void) sleep(FORKSLEEP);
1828        else {
1829#ifdef BSDSIGS
1830            (void) sigsetmask(omask);
1831#else /* !BSDSIGS */
1832            (void) sigrelse(SIGINT);
1833            (void) sigrelse(SIGCHLD);
1834#endif /* !BSDSIGS */
1835            stderror(ERR_NOPROC);
1836        }
1837    if (pid == 0) {
1838        settimes();
1839        pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
1840        pflushall();
1841        pcurrjob = NULL;
1842#if !defined(BSDTIMES) && !defined(_SEQUENT_)
1843        timesdone = 0;
1844#endif /* !defined(BSDTIMES) && !defined(_SEQUENT_) */
1845        child++;
1846        if (setintr) {
1847            setintr = 0;        /* until I think otherwise */
1848#ifndef BSDSIGS
1849            (void) sigrelse(SIGCHLD);
1850#endif /* !BSDSIGS */
1851            /*
1852             * Children just get blown away on SIGINT, SIGQUIT unless "onintr
1853             * -" seen.
1854             */
1855            (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
1856            (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
1857#ifdef BSDJOBS
1858            if (wanttty >= 0) {
1859                /* make stoppable */
1860                (void) signal(SIGTSTP, SIG_DFL);
1861                (void) signal(SIGTTIN, SIG_DFL);
1862                (void) signal(SIGTTOU, SIG_DFL);
1863            }
1864#endif /* BSDJOBS */
1865            (void) signal(SIGTERM, parterm);
1866        }
1867        else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) {
1868            (void) signal(SIGINT, SIG_IGN);
1869            (void) signal(SIGQUIT, SIG_IGN);
1870        }
1871#ifdef OREO
1872        sigignore(SIGIO);       /* ignore SIGIO in child too */
1873#endif /* OREO */
1874
1875        pgetty(wanttty, pgrp);
1876        /*
1877         * Nohup and nice apply only to NODE_COMMAND's but it would be nice
1878         * (?!?) if you could say "nohup (foo;bar)" Then the parser would have
1879         * to know about nice/nohup/time
1880         */
1881        if (t->t_dflg & F_NOHUP)
1882            (void) signal(SIGHUP, SIG_IGN);
1883        if (t->t_dflg & F_NICE)
1884#ifdef BSDNICE
1885            (void) setpriority(PRIO_PROCESS, 0, t->t_nice);
1886#else /* !BSDNICE */
1887            (void) nice(t->t_nice);
1888#endif /* !BSDNICE */
1889#ifdef F_VER
1890        if (t->t_dflg & F_VER) {
1891            tsetenv(STRSYSTYPE, t->t_systype ? STRbsd43 : STRsys53);
1892            dohash(NULL, NULL);
1893        }
1894#endif /* F_VER */
1895#ifdef SIGSYNCH
1896        /* rfw 8/89 now parent can continue */
1897        if (kill(getppid(), SIGSYNCH))
1898            stderror(ERR_SYSTEM, "pfork child: kill", strerror(errno));
1899#endif /* SIGSYNCH */
1900
1901    }
1902    else {
1903#ifdef POSIXJOBS
1904        if (wanttty >= 0) {
1905            /*
1906             * `Walking' process group fix from Beto Appleton.
1907             * (beto@aixwiz.austin.ibm.com)
1908             * If setpgid fails at this point that means that
1909             * our process leader has died. We flush the current
1910             * job and become the process leader ourselves.
1911             * The parent will figure that out later.
1912             */
1913            pgrp = pcurrjob ? pcurrjob->p_jobid : pid;
1914            if (setpgid(pid, pgrp) == -1 && errno == EPERM) {
1915                pflush(pcurrjob);
1916                pcurrjob = NULL;
1917                if (setpgid(pid, pgrp = pid) == -1) {
1918                    stderror(ERR_SYSTEM, "setpgid parent:", strerror(errno));
1919                    xexit(0);
1920                }
1921            }
1922        }
1923#endif /* POSIXJOBS */
1924        palloc(pid, t);
1925#ifdef SIGSYNCH
1926        /*
1927         * rfw 8/89 Wait for child to own terminal.  Solves half of ugly
1928         * synchronization problem.  With this change, we know that the only
1929         * reason setpgrp to a previous process in a pipeline can fail is that
1930         * the previous process has already exited. Without this hack, he may
1931         * either have exited or not yet started to run.  Two uglies become
1932         * one.
1933         */
1934        sigpause(omask & ~SYNCHMASK);
1935        if (mysigvec(SIGSYNCH, &osv, NULL))
1936            stderror(ERR_SYSTEM, "pfork parent: sigvec restore",
1937                     strerror(errno));
1938#endif /* SIGSYNCH */
1939
1940#ifdef BSDSIGS
1941        (void) sigsetmask(omask);
1942#else /* !BSDSIGS */
1943        (void) sigrelse(SIGCHLD);
1944#endif /* !BSDSIGS */
1945    }
1946    return (pid);
1947}
1948
1949static void
1950okpcntl()
1951{
1952    if (tpgrp == -1)
1953        stderror(ERR_JOBCONTROL);
1954    if (tpgrp == 0)
1955        stderror(ERR_JOBCTRLSUB);
1956}
1957
1958/*
1959 * if we don't have vfork(), things can still go in the wrong order
1960 * resulting in the famous 'Stopped (tty output)'. But some systems
1961 * don't permit the setpgid() call, (these are more recent secure
1962 * systems such as ibm's aix), when they do. Then we'd rather print
1963 * an error message than hang the shell!
1964 * I am open to suggestions how to fix that.
1965 */
1966void
1967pgetty(wanttty, pgrp)
1968    int     wanttty, pgrp;
1969{
1970#ifdef BSDJOBS
1971# if defined(BSDSIGS) && defined(POSIXJOBS)
1972    sigmask_t omask = 0;
1973# endif /* BSDSIGS && POSIXJOBS */
1974
1975# ifdef JOBDEBUG
1976    xprintf("wanttty %d\n", wanttty);
1977# endif
1978
1979# ifdef POSIXJOBS
1980    /*
1981     * christos: I am blocking the tty signals till I've set things
1982     * correctly....
1983     */
1984    if (wanttty > 0)
1985#  ifdef BSDSIGS
1986        omask = sigblock(sigmask(SIGTSTP)|sigmask(SIGTTIN));
1987#  else /* !BSDSIGS */
1988    {
1989        (void) sighold(SIGTSTP);
1990        (void) sighold(SIGTTIN);
1991    }
1992#  endif /* !BSDSIGS */
1993# endif /* POSIXJOBS */
1994
1995# ifndef POSIXJOBS
1996    if (wanttty > 0)
1997        (void) tcsetpgrp(FSHTTY, pgrp);
1998# endif /* !POSIXJOBS */
1999
2000    /*
2001     * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
2002     * Don't check for tpgrp >= 0 so even non-interactive shells give
2003     * background jobs process groups Same for the comparison in the other part
2004     * of the #ifdef
2005     */
2006    if (wanttty >= 0)
2007        if (setpgid(0, pgrp) == -1) {
2008# ifdef POSIXJOBS
2009            /* Walking process group fix; see above */
2010            if (setpgid(0, pgrp = getpid()) == -1) {
2011# endif /* POSIXJOBS */
2012                stderror(ERR_SYSTEM, "setpgid child:\n", strerror(errno));
2013                xexit(0);
2014# ifdef POSIXJOBS
2015            }
2016            wanttty = 1;  /* Now we really want the tty, since we became the
2017                           * the process group leader
2018                           */
2019# endif /* POSIXJOBS */
2020        }
2021
2022# ifdef POSIXJOBS
2023#  ifdef _SEQUENT_
2024    /* The controlling terminal is lost if all processes in the
2025     * terminal process group are zombies. In this case tcgetpgrp()
2026     * returns 0. If this happens we must set the terminal process
2027     * group again.
2028     */
2029    if (wanttty == 0 && tcgetpgrp(FSHTTY) == 0)
2030        wanttty = 1;
2031#  endif /* _SEQUENT_ */
2032    if (wanttty > 0) {
2033        /*
2034         * tcsetpgrp will set SIGTTOU to all the the processes in
2035         * the background according to POSIX... We ignore this here.
2036         */
2037        sigret_t (*old)() = sigset(SIGTTOU, SIG_IGN);
2038        (void) tcsetpgrp(FSHTTY, pgrp);
2039        (void) sigset(SIGTTOU, old);
2040
2041#  ifdef BSDSIGS
2042        (void) sigsetmask(omask);
2043#  else /* BSDSIGS */
2044        (void) sigrelse(SIGTSTP);
2045        (void) sigrelse(SIGTTIN);
2046#  endif /* !BSDSIGS */
2047    }
2048# endif /* POSIXJOBS */
2049
2050    if (tpgrp > 0)
2051        tpgrp = 0;              /* gave tty away */
2052#endif /* BSDJOBS */
2053}
Note: See TracBrowser for help on using the repository browser.