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