Home | History | Annotate | Download | only in csh
      1     0    stevel /*
      2  2182      chin  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
      3     0    stevel  * Use is subject to license terms.
      4     0    stevel  */
      5     0    stevel 
      6     0    stevel /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
      7     0    stevel /*	  All Rights Reserved  	*/
      8     0    stevel 
      9     0    stevel /*
     10     0    stevel  * Copyright (c) 1980 Regents of the University of California.
     11     0    stevel  * All rights reserved. The Berkeley Software License Agreement
     12     0    stevel  * specifies the terms and conditions for redistribution.
     13     0    stevel  */
     14     0    stevel 
     15     0    stevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
     16     0    stevel 
     17     0    stevel #include "sh.h"
     18     0    stevel #include "sh.dir.h"
     19     0    stevel #include "sh.proc.h"
     20     0    stevel #include "wait.h"
     21     0    stevel #include "sh.tconst.h"
     22     0    stevel 
     23     0    stevel /*
     24     0    stevel  * C Shell - functions that manage processes, handling hanging, termination
     25     0    stevel  */
     26     0    stevel 
     27   559   nakanon #define	BIGINDEX	9	/* largest desirable job index */
     28     0    stevel 
     29   356    muffin void	pjwait(struct process *);
     30   356    muffin void	pflush(struct process *);
     31   356    muffin void	pclrcurr(struct process *);
     32   356    muffin void	padd(struct command *);
     33   356    muffin void	pads(tchar *);
     34   356    muffin void	ptprint(struct process *);
     35   356    muffin void	pkill(tchar **, int);
     36   356    muffin void	pstart(struct process *, int);
     37   356    muffin void	okpcntl(void);
     38   356    muffin struct process	*pgetcurr(struct process *);
     39   356    muffin struct process	*pfind(tchar *);
     40   356    muffin 
     41     0    stevel /*
     42     0    stevel  * pchild - called at interrupt level by the SIGCHLD signal
     43     0    stevel  *	indicating that at least one child has terminated or stopped
     44     0    stevel  *	thus at least one wait system call will definitely return a
     45     0    stevel  *	childs status.  Top level routines (like pwait) must be sure
     46     0    stevel  *	to mask interrupts when playing with the proclist data structures!
     47     0    stevel  */
     48     0    stevel void
     49   356    muffin pchild(void)
     50     0    stevel {
     51   356    muffin 	struct process *pp;
     52   356    muffin 	struct process	*fp;
     53   356    muffin 	int pid;
     54     0    stevel 	union wait w;
     55     0    stevel 	int jobflags;
     56     0    stevel 	struct rusage ru;
     57     0    stevel 
     58     0    stevel #ifdef TRACE
     59     0    stevel 	tprintf("TRACE- pchile()\n");
     60     0    stevel #endif
     61     0    stevel loop:
     62     0    stevel 	pid = csh_wait3(&w, (setintr ? WNOHANG|WUNTRACED:WNOHANG), &ru);
     63   559   nakanon 	/*
     64   559   nakanon 	 * SysV sends a SIGCHLD when the child process
     65   559   nakanon 	 * receives a SIGCONT, and result of that action is ignored here
     66   559   nakanon 	 */
     67   559   nakanon 	if (w.w_status == WCONTFLG)
     68   559   nakanon 		return;
     69     0    stevel 	if (pid <= 0) {
     70     0    stevel 		if (errno == EINTR) {
     71     0    stevel 			errno = 0;
     72     0    stevel 			goto loop;
     73     0    stevel 		}
     74     0    stevel 		pnoprocesses = pid == -1;
     75     0    stevel 		return;
     76     0    stevel 	}
     77     0    stevel 	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
     78     0    stevel 		if (pid == pp->p_pid)
     79     0    stevel 			goto found;
     80     0    stevel 	goto loop;
     81     0    stevel found:
     82   559   nakanon 	if (pid == atoi_(value(S_child /* "child" */)))
     83   559   nakanon 		unsetv(S_child /* "child" */);
     84     0    stevel 	pp->p_flags &= ~(PRUNNING|PSTOPPED|PREPORTED);
     85     0    stevel 	if (WIFSTOPPED(w)) {
     86     0    stevel 		pp->p_flags |= PSTOPPED;
     87     0    stevel 		pp->p_reason = w.w_stopsig;
     88     0    stevel 	} else {
     89   559   nakanon 		if (pp->p_flags & (PTIME|PPTIME) || adrof(S_time /* "time" */))
     90     0    stevel 			(void) gettimeofday(&pp->p_etime, (struct timezone *)0);
     91     0    stevel 		pp->p_rusage = ru;
     92     0    stevel 		if (WIFSIGNALED(w)) {
     93     0    stevel 			if (w.w_termsig == SIGINT)
     94     0    stevel 				pp->p_flags |= PINTERRUPTED;
     95     0    stevel 			else
     96     0    stevel 				pp->p_flags |= PSIGNALED;
     97     0    stevel 			if (w.w_coredump)
     98     0    stevel 				pp->p_flags |= PDUMPED;
     99     0    stevel 			pp->p_reason = w.w_termsig;
    100     0    stevel 		} else {
    101     0    stevel 			pp->p_reason = w.w_retcode;
    102     0    stevel 			if (pp->p_reason != 0)
    103     0    stevel 				pp->p_flags |= PAEXITED;
    104     0    stevel 			else
    105     0    stevel 				pp->p_flags |= PNEXITED;
    106     0    stevel 		}
    107     0    stevel 	}
    108     0    stevel 	jobflags = 0;
    109     0    stevel 	fp = pp;
    110     0    stevel 	do {
    111     0    stevel 		if ((fp->p_flags & (PPTIME|PRUNNING|PSTOPPED)) == 0 &&
    112   559   nakanon 		    !child && adrof(S_time /* "time" */) &&
    113     0    stevel 		    fp->p_rusage.ru_utime.tv_sec+fp->p_rusage.ru_stime.tv_sec >=
    114   559   nakanon 		    atoi_(value(S_time /* "time" */)))
    115     0    stevel 			fp->p_flags |= PTIME;
    116     0    stevel 		jobflags |= fp->p_flags;
    117     0    stevel 	} while ((fp = fp->p_friends) != pp);
    118     0    stevel 	pp->p_flags &= ~PFOREGND;
    119     0    stevel 	if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
    120     0    stevel 		pp->p_flags &= ~PPTIME;
    121     0    stevel 		pp->p_flags |= PTIME;
    122     0    stevel 	}
    123     0    stevel 	if ((jobflags & (PRUNNING|PREPORTED)) == 0) {
    124     0    stevel 		fp = pp;
    125     0    stevel 		do {
    126     0    stevel 			if (fp->p_flags&PSTOPPED)
    127     0    stevel 				fp->p_flags |= PREPORTED;
    128   559   nakanon 		} while ((fp = fp->p_friends) != pp);
    129   559   nakanon 		while (fp->p_pid != fp->p_jobid)
    130     0    stevel 			fp = fp->p_friends;
    131     0    stevel 		if (jobflags&PSTOPPED) {
    132     0    stevel 			if (pcurrent && pcurrent != fp)
    133     0    stevel 				pprevious = pcurrent;
    134     0    stevel 			pcurrent = fp;
    135     0    stevel 		} else
    136     0    stevel 			pclrcurr(fp);
    137     0    stevel 		if (jobflags&PFOREGND) {
    138     0    stevel 			if (jobflags & (PSIGNALED|PSTOPPED|PPTIME) ||
    139     0    stevel #ifdef IIASA
    140     0    stevel 			    jobflags & PAEXITED ||
    141     0    stevel #endif
    142     0    stevel 			    !eq(dcwd->di_name, fp->p_cwd->di_name)) {
    143     0    stevel 				;	/* print in pjwait */
    144     0    stevel 			}
    145     0    stevel 		} else {
    146   559   nakanon 			if (jobflags&PNOTIFY || adrof(S_notify /* "notify" */)) {
    147     0    stevel 				write_string("\015\n");
    148     0    stevel 				flush();
    149     0    stevel 				(void) pprint(pp, NUMBER|NAME|REASON);
    150     0    stevel 				if ((jobflags&PSTOPPED) == 0)
    151     0    stevel 					pflush(pp);
    152     0    stevel 			} else {
    153     0    stevel 				fp->p_flags |= PNEEDNOTE;
    154     0    stevel 				neednote++;
    155     0    stevel 			}
    156     0    stevel 		}
    157     0    stevel 	}
    158     0    stevel 	goto loop;
    159     0    stevel }
    160     0    stevel 
    161   356    muffin void
    162   356    muffin pnote(void)
    163     0    stevel {
    164   356    muffin 	struct process *pp;
    165     0    stevel 	int flags, omask;
    166     0    stevel 
    167     0    stevel #ifdef TRACE
    168     0    stevel 	tprintf("TRACE- pnote()\n");
    169     0    stevel #endif
    170     0    stevel 	neednote = 0;
    171     0    stevel 	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) {
    172     0    stevel 		if (pp->p_flags & PNEEDNOTE) {
    173     0    stevel 			omask = sigblock(sigmask(SIGCHLD));
    174     0    stevel 			pp->p_flags &= ~PNEEDNOTE;
    175     0    stevel 			flags = pprint(pp, NUMBER|NAME|REASON);
    176     0    stevel 			if ((flags&(PRUNNING|PSTOPPED)) == 0)
    177     0    stevel 				pflush(pp);
    178     0    stevel 			(void) sigsetmask(omask);
    179     0    stevel 		}
    180     0    stevel 	}
    181     0    stevel }
    182     0    stevel 
    183     0    stevel /*
    184     0    stevel  * pwait - wait for current job to terminate, maintaining integrity
    185     0    stevel  *	of current and previous job indicators.
    186     0    stevel  */
    187   356    muffin void
    188   356    muffin pwait(void)
    189     0    stevel {
    190   356    muffin 	struct process *fp, *pp;
    191     0    stevel 	int omask;
    192     0    stevel 
    193     0    stevel #ifdef TRACE
    194     0    stevel 	tprintf("TRACE- pwait()\n");
    195     0    stevel #endif
    196     0    stevel 	/*
    197     0    stevel 	 * Here's where dead procs get flushed.
    198     0    stevel 	 */
    199     0    stevel 	omask = sigblock(sigmask(SIGCHLD));
    200     0    stevel 	for (pp = (fp = &proclist)->p_next; pp != PNULL; pp = (fp = pp)->p_next)
    201     0    stevel 		if (pp->p_pid == 0) {
    202     0    stevel 			fp->p_next = pp->p_next;
    203     0    stevel 			xfree(pp->p_command);
    204     0    stevel 			if (pp->p_cwd && --pp->p_cwd->di_count == 0)
    205     0    stevel 				if (pp->p_cwd->di_next == 0)
    206     0    stevel 					dfree(pp->p_cwd);
    207   559   nakanon 			xfree((tchar *)pp);
    208     0    stevel 			pp = fp;
    209     0    stevel 		}
    210     0    stevel 	(void) sigsetmask(omask);
    211     0    stevel 	pjwait(pcurrjob);
    212     0    stevel }
    213     0    stevel 
    214     0    stevel /*
    215     0    stevel  * pjwait - wait for a job to finish or become stopped
    216     0    stevel  *	It is assumed to be in the foreground state (PFOREGND)
    217     0    stevel  */
    218   356    muffin void
    219   356    muffin pjwait(struct process *pp)
    220     0    stevel {
    221   356    muffin 	struct process *fp;
    222     0    stevel 	int jobflags, reason, omask;
    223     0    stevel 
    224     0    stevel #ifdef TRACE
    225     0    stevel 	tprintf("TRACE- pjwait()\n");
    226     0    stevel #endif
    227     0    stevel 	while (pp->p_pid != pp->p_jobid)
    228     0    stevel 		pp = pp->p_friends;
    229     0    stevel 	fp = pp;
    230     0    stevel 	do {
    231     0    stevel 		if ((fp->p_flags&(PFOREGND|PRUNNING)) == PRUNNING)
    232     0    stevel 			printf("BUG: waiting for background job!\n");
    233     0    stevel 	} while ((fp = fp->p_friends) != pp);
    234     0    stevel 	/*
    235     0    stevel 	 * Now keep pausing as long as we are not interrupted (SIGINT),
    236     0    stevel 	 * and the target process, or any of its friends, are running
    237     0    stevel 	 */
    238     0    stevel 	fp = pp;
    239     0    stevel 	omask = sigblock(sigmask(SIGCHLD));
    240     0    stevel 	for (;;) {
    241     0    stevel 		jobflags = 0;
    242     0    stevel 		do
    243     0    stevel 			jobflags |= fp->p_flags;
    244     0    stevel 		while ((fp = (fp->p_friends)) != pp);
    245     0    stevel 		if ((jobflags & PRUNNING) == 0)
    246     0    stevel 			break;
    247   200       raf 		/*
    248   200       raf 		 * At this point, csh used to call:
    249   200       raf 		 *	sigpause(sigblock(0) &~ sigmask(SIGCHLD));
    250   200       raf 		 * expecting to receive a SIGCHLD signal from the
    251   200       raf 		 * termination of the child and to invoke the
    252   200       raf 		 * signal handler, pchild(), as a result.
    253   200       raf 		 *
    254   200       raf 		 * However, vfork() now causes a vfork()'d child to
    255   200       raf 		 * have all of its active signal handlers reset to
    256   200       raf 		 * SIG_DFL, to forstall parent memory corruption due
    257   200       raf 		 * to race conditions with signal handling.
    258   200       raf 		 *
    259   200       raf 		 * If this instance of csh is itself a child of vfork(),
    260   200       raf 		 * which can happen when the top-level csh performs a
    261   200       raf 		 * command substitution inside an i/o redirection, like:
    262   200       raf 		 *	/bin/echo foo >`/bin/echo trash`
    263   200       raf 		 * then we will never receive SIGCHLD.  To accommodate
    264   200       raf 		 * this, we wait until one of our children terminates
    265   200       raf 		 * (without actually reaping the child) and call the
    266   200       raf 		 * SIGCHLD signal handler (pchild()) directly.
    267   200       raf 		 */
    268   200       raf 		if (csh_wait_noreap() > 0)
    269   200       raf 			pchild();	/* simulate receipt of SIGCHLD */
    270     0    stevel 	}
    271     0    stevel 	(void) sigsetmask(omask);
    272     0    stevel 	if (tpgrp > 0)			/* get tty back */
    273     0    stevel 		(void) ioctl(FSHTTY, TIOCSPGRP,  (char *)&tpgrp);
    274     0    stevel 	if ((jobflags&(PSIGNALED|PSTOPPED|PTIME)) ||
    275   559   nakanon 	    !eq(dcwd->di_name, fp->p_cwd->di_name)) {
    276     0    stevel 		if (jobflags&PSTOPPED)
    277     0    stevel 			printf("\n");
    278     0    stevel 		(void) pprint(pp, AREASON|SHELLDIR);
    279     0    stevel 	}
    280     0    stevel 	if ((jobflags&(PINTERRUPTED|PSTOPPED)) && setintr &&
    281   559   nakanon 	    (!gointr || !eq(gointr, S_MINUS /* "-" */))) {
    282     0    stevel 		if ((jobflags & PSTOPPED) == 0)
    283     0    stevel 			pflush(pp);
    284     0    stevel 		pintr1(0);
    285     0    stevel 		/*NOTREACHED*/
    286     0    stevel 	}
    287     0    stevel 	reason = 0;
    288     0    stevel 	fp = pp;
    289     0    stevel 	do {
    290     0    stevel 		if (fp->p_reason)
    291     0    stevel 			reason = fp->p_flags & (PSIGNALED|PINTERRUPTED) ?
    292     0    stevel 				fp->p_reason | ABN_TERM : fp->p_reason;
    293     0    stevel 	} while ((fp = fp->p_friends) != pp);
    294   559   nakanon 	set(S_status /* "status" */, putn(reason));
    295     0    stevel 	if (reason && exiterr)
    296     0    stevel 		exitstat();
    297     0    stevel 	pflush(pp);
    298     0    stevel }
    299     0    stevel 
    300     0    stevel /*
    301     0    stevel  * dowait - wait for all processes to finish
    302     0    stevel  */
    303   356    muffin void
    304   356    muffin dowait(void)
    305     0    stevel {
    306   356    muffin 	struct process *pp;
    307     0    stevel 	int omask;
    308     0    stevel 
    309     0    stevel #ifdef TRACE
    310     0    stevel 	tprintf("TRACE- dowait()\n");
    311     0    stevel #endif
    312     0    stevel 	pjobs++;
    313     0    stevel 	omask = sigblock(sigmask(SIGCHLD));
    314     0    stevel loop:
    315     0    stevel 	for (pp = proclist.p_next; pp; pp = pp->p_next)
    316     0    stevel 		if (pp->p_pid && /* pp->p_pid == pp->p_jobid && */
    317     0    stevel 		    pp->p_flags&PRUNNING) {
    318     0    stevel 			sigpause(0);
    319     0    stevel 			goto loop;
    320     0    stevel 		}
    321     0    stevel 	(void) sigsetmask(omask);
    322     0    stevel 	pjobs = 0;
    323     0    stevel }
    324     0    stevel 
    325     0    stevel /*
    326     0    stevel  * pflushall - flush all jobs from list (e.g. at fork())
    327     0    stevel  */
    328   356    muffin void
    329   356    muffin pflushall(void)
    330     0    stevel {
    331   356    muffin 	struct process	*pp;
    332     0    stevel 
    333     0    stevel #ifdef TRACE
    334     0    stevel 	tprintf("TRACE- pflush()\n");
    335     0    stevel #endif
    336     0    stevel 	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
    337     0    stevel 		if (pp->p_pid)
    338     0    stevel 			pflush(pp);
    339     0    stevel }
    340     0    stevel 
    341     0    stevel /*
    342     0    stevel  * pflush - flag all process structures in the same job as the
    343     0    stevel  *	the argument process for deletion.  The actual free of the
    344     0    stevel  *	space is not done here since pflush is called at interrupt level.
    345     0    stevel  */
    346   356    muffin void
    347   356    muffin pflush(struct process *pp)
    348     0    stevel {
    349   356    muffin 	struct process *np;
    350   356    muffin 	int index;
    351     0    stevel 
    352     0    stevel #ifdef TRACE
    353     0    stevel 	tprintf("TRACE- pflush()\n");
    354     0    stevel #endif
    355     0    stevel 	if (pp->p_pid == 0) {
    356     0    stevel 		printf("BUG: process flushed twice");
    357     0    stevel 		return;
    358     0    stevel 	}
    359     0    stevel 	while (pp->p_pid != pp->p_jobid)
    360     0    stevel 		pp = pp->p_friends;
    361     0    stevel 	pclrcurr(pp);
    362     0    stevel 	if (pp == pcurrjob)
    363     0    stevel 		pcurrjob = 0;
    364     0    stevel 	index = pp->p_index;
    365     0    stevel 	np = pp;
    366     0    stevel 	do {
    367     0    stevel 		np->p_index = np->p_pid = 0;
    368     0    stevel 		np->p_flags &= ~PNEEDNOTE;
    369     0    stevel 	} while ((np = np->p_friends) != pp);
    370     0    stevel 	if (index == pmaxindex) {
    371     0    stevel 		for (np = proclist.p_next, index = 0; np; np = np->p_next)
    372     0    stevel 			if (np->p_index > (tchar)index)
    373     0    stevel 				index = np->p_index;
    374     0    stevel 		pmaxindex = index;
    375     0    stevel 	}
    376     0    stevel }
    377     0    stevel 
    378     0    stevel /*
    379     0    stevel  * pclrcurr - make sure the given job is not the current or previous job;
    380     0    stevel  *	pp MUST be the job leader
    381     0    stevel  */
    382   356    muffin void
    383   356    muffin pclrcurr(struct process *pp)
    384     0    stevel {
    385     0    stevel 
    386     0    stevel #ifdef TRACE
    387     0    stevel 	tprintf("TRACE- pclrcurr()\n");
    388     0    stevel #endif
    389     0    stevel 	if (pp == pcurrent)
    390     0    stevel 		if (pprevious != PNULL) {
    391     0    stevel 			pcurrent = pprevious;
    392     0    stevel 			pprevious = pgetcurr(pp);
    393     0    stevel 		} else {
    394     0    stevel 			pcurrent = pgetcurr(pp);
    395     0    stevel 			pprevious = pgetcurr(pp);
    396     0    stevel 		}
    397     0    stevel 	else if (pp == pprevious)
    398     0    stevel 		pprevious = pgetcurr(pp);
    399     0    stevel }
    400     0    stevel 
    401     0    stevel /* +4 here is 1 for '\0', 1 ea for << >& >> */
    402     0    stevel tchar	command[PMAXLEN+4];
    403     0    stevel int	cmdlen;
    404     0    stevel tchar	*cmdp;
    405     0    stevel /*
    406     0    stevel  * palloc - allocate a process structure and fill it up.
    407     0    stevel  *	an important assumption is made that the process is running.
    408     0    stevel  */
    409   356    muffin void
    410   356    muffin palloc(int pid, struct command *t)
    411     0    stevel {
    412   356    muffin 	struct process	*pp;
    413     0    stevel 	int i;
    414     0    stevel 
    415     0    stevel #ifdef TRACE
    416     0    stevel 	tprintf("TRACE- palloc()\n");
    417     0    stevel #endif
    418   559   nakanon 	pp = (struct process *)xcalloc(1, sizeof (struct process));
    419     0    stevel 	pp->p_pid = pid;
    420     0    stevel 	pp->p_flags = t->t_dflg & FAND ? PRUNNING : PRUNNING|PFOREGND;
    421     0    stevel 	if (t->t_dflg & FTIME)
    422     0    stevel 		pp->p_flags |= PPTIME;
    423     0    stevel 	cmdp = command;
    424     0    stevel 	cmdlen = 0;
    425     0    stevel 	padd(t);
    426     0    stevel 	*cmdp++ = 0;
    427     0    stevel 	if (t->t_dflg & FPOU) {
    428     0    stevel 		pp->p_flags |= PPOU;
    429     0    stevel 		if (t->t_dflg & FDIAG)
    430     0    stevel 			pp->p_flags |= PDIAG;
    431     0    stevel 	}
    432     0    stevel 	pp->p_command = savestr(command);
    433     0    stevel 	if (pcurrjob) {
    434     0    stevel 		struct process *fp;
    435     0    stevel 		/* careful here with interrupt level */
    436     0    stevel 		pp->p_cwd = 0;
    437     0    stevel 		pp->p_index = pcurrjob->p_index;
    438     0    stevel 		pp->p_friends = pcurrjob;
    439     0    stevel 		pp->p_jobid = pcurrjob->p_pid;
    440     0    stevel 		for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
    441     0    stevel 			;
    442     0    stevel 		fp->p_friends = pp;
    443     0    stevel 	} else {
    444     0    stevel 		pcurrjob = pp;
    445     0    stevel 		pp->p_jobid = pid;
    446     0    stevel 		pp->p_friends = pp;
    447     0    stevel 		pp->p_cwd = dcwd;
    448     0    stevel 		dcwd->di_count++;
    449     0    stevel 		if (pmaxindex < BIGINDEX)
    450     0    stevel 			pp->p_index = ++pmaxindex;
    451     0    stevel 		else {
    452     0    stevel 			struct process *np;
    453     0    stevel 
    454     0    stevel 			for (i = 1; ; i++) {
    455     0    stevel 				for (np = proclist.p_next; np; np = np->p_next)
    456     0    stevel 					if (np->p_index == i)
    457     0    stevel 						goto tryagain;
    458     0    stevel 				pp->p_index = i;
    459     0    stevel 				if (i > pmaxindex)
    460     0    stevel 					pmaxindex = i;
    461   559   nakanon 				break;
    462     0    stevel 			tryagain:;
    463     0    stevel 			}
    464     0    stevel 		}
    465     0    stevel 		pprevious = pcurrent;
    466     0    stevel 		pcurrent = pp;
    467     0    stevel 	}
    468     0    stevel 	pp->p_next = proclist.p_next;
    469     0    stevel 	proclist.p_next = pp;
    470     0    stevel 	(void) gettimeofday(&pp->p_btime, (struct timezone *)0);
    471     0    stevel }
    472     0    stevel 
    473   356    muffin void
    474   356    muffin padd(struct command *t)
    475     0    stevel {
    476     0    stevel 	tchar **argp;
    477     0    stevel 
    478     0    stevel #ifdef TRACE
    479     0    stevel 	tprintf("TRACE- padd()\n");
    480     0    stevel #endif
    481     0    stevel 	if (t == 0)
    482     0    stevel 		return;
    483     0    stevel 	switch (t->t_dtyp) {
    484     0    stevel 
    485     0    stevel 	case TPAR:
    486   559   nakanon 		pads(S_LBRASP /* "( " */);
    487     0    stevel 		padd(t->t_dspr);
    488   559   nakanon 		pads(S_SPRBRA /* " )" */);
    489     0    stevel 		break;
    490     0    stevel 
    491     0    stevel 	case TCOM:
    492     0    stevel 		for (argp = t->t_dcom; *argp; argp++) {
    493     0    stevel 			pads(*argp);
    494     0    stevel 			if (argp[1])
    495   559   nakanon 				pads(S_SP /* " " */);
    496     0    stevel 		}
    497     0    stevel 		break;
    498     0    stevel 
    499     0    stevel 	case TOR:
    500     0    stevel 	case TAND:
    501     0    stevel 	case TFIL:
    502     0    stevel 	case TLST:
    503     0    stevel 		padd(t->t_dcar);
    504     0    stevel 		switch (t->t_dtyp) {
    505     0    stevel 		case TOR:
    506   559   nakanon 			pads(S_SPBARBARSP /* " || " */);
    507     0    stevel 			break;
    508     0    stevel 		case TAND:
    509   559   nakanon 			pads(S_SPANDANDSP /* " && " */);
    510     0    stevel 			break;
    511     0    stevel 		case TFIL:
    512   559   nakanon 			pads(S_SPBARSP /* " | " */);
    513     0    stevel 			break;
    514     0    stevel 		case TLST:
    515   559   nakanon 			pads(S_SEMICOLONSP /* "; " */);
    516     0    stevel 			break;
    517     0    stevel 		}
    518     0    stevel 		padd(t->t_dcdr);
    519     0    stevel 		return;
    520     0    stevel 	}
    521     0    stevel 	if ((t->t_dflg & FPIN) == 0 && t->t_dlef) {
    522   559   nakanon 		pads((t->t_dflg & FHERE) ? S_SPLESLESSP /* " << " */ : S_SPLESSP /* " < " */);
    523     0    stevel 		pads(t->t_dlef);
    524     0    stevel 	}
    525     0    stevel 	if ((t->t_dflg & FPOU) == 0 && t->t_drit) {
    526   559   nakanon 		pads((t->t_dflg & FCAT) ? S_SPGTRGTRSP /* " >>" */ : S_SPGTR /* " >" */);
    527     0    stevel 		if (t->t_dflg & FDIAG)
    528   559   nakanon 			pads(S_AND /* "&" */);
    529   559   nakanon 		pads(S_SP /* " " */);
    530     0    stevel 		pads(t->t_drit);
    531     0    stevel 	}
    532     0    stevel }
    533     0    stevel 
    534   356    muffin void
    535   356    muffin pads(tchar *cp)
    536     0    stevel {
    537   356    muffin 	int i = strlen_(cp);
    538     0    stevel 
    539     0    stevel #ifdef TRACE
    540     0    stevel 	tprintf("TRACE- pads()\n");
    541     0    stevel #endif
    542     0    stevel 	if (cmdlen >= PMAXLEN)
    543     0    stevel 		return;
    544     0    stevel 	if (cmdlen + i >= PMAXLEN) {
    545   559   nakanon 		(void) strcpy_(cmdp, S_SPPPP /* " ..." */);
    546     0    stevel 		cmdlen = PMAXLEN;
    547     0    stevel 		cmdp += 4;
    548     0    stevel 		return;
    549     0    stevel 	}
    550     0    stevel 	(void) strcpy_(cmdp, cp);
    551     0    stevel 	cmdp += i;
    552     0    stevel 	cmdlen += i;
    553     0    stevel }
    554     0    stevel 
    555     0    stevel /*
    556     0    stevel  * psavejob - temporarily save the current job on a one level stack
    557     0    stevel  *	so another job can be created.  Used for { } in exp6
    558     0    stevel  *	and `` in globbing.
    559     0    stevel  */
    560   356    muffin void
    561   356    muffin psavejob(void)
    562     0    stevel {
    563     0    stevel 
    564     0    stevel #ifdef TRACE
    565     0    stevel 	tprintf("TRACE- psavejob()\n");
    566     0    stevel #endif
    567     0    stevel 	pholdjob = pcurrjob;
    568     0    stevel 	pcurrjob = PNULL;
    569     0    stevel }
    570     0    stevel 
    571     0    stevel /*
    572     0    stevel  * prestjob - opposite of psavejob.  This may be missed if we are interrupted
    573     0    stevel  *	somewhere, but pendjob cleans up anyway.
    574     0    stevel  */
    575   356    muffin void
    576   356    muffin prestjob(void)
    577     0    stevel {
    578     0    stevel 
    579     0    stevel #ifdef TRACE
    580     0    stevel 	tprintf("TRACE- prestjob()\n");
    581     0    stevel #endif
    582     0    stevel 	pcurrjob = pholdjob;
    583     0    stevel 	pholdjob = PNULL;
    584     0    stevel }
    585     0    stevel 
    586     0    stevel /*
    587     0    stevel  * pendjob - indicate that a job (set of commands) has been completed
    588     0    stevel  *	or is about to begin.
    589     0    stevel  */
    590   356    muffin void
    591   356    muffin pendjob(void)
    592     0    stevel {
    593   356    muffin 	struct process *pp, *tp;
    594     0    stevel 
    595     0    stevel #ifdef TRACE
    596     0    stevel 	tprintf("TRACE- pendjob()\n");
    597     0    stevel #endif
    598     0    stevel 	if (pcurrjob && (pcurrjob->p_flags&(PFOREGND|PSTOPPED)) == 0) {
    599     0    stevel 		pp = pcurrjob;
    600     0    stevel 		while (pp->p_pid != pp->p_jobid)
    601     0    stevel 			pp = pp->p_friends;
    602     0    stevel 		printf("[%d]", pp->p_index);
    603     0    stevel 		tp = pp;
    604     0    stevel 		do {
    605     0    stevel 			printf(" %d", pp->p_pid);
    606     0    stevel 			pp = pp->p_friends;
    607     0    stevel 		} while (pp != tp);
    608     0    stevel 		printf("\n");
    609     0    stevel 	}
    610     0    stevel 	pholdjob = pcurrjob = 0;
    611     0    stevel }
    612     0    stevel 
    613     0    stevel /*
    614     0    stevel  * pprint - print a job
    615     0    stevel  */
    616   356    muffin int
    617   356    muffin pprint(struct process *pp, int flag)
    618     0    stevel {
    619   356    muffin 	int status, reason;
    620     0    stevel 	struct process *tp;
    621     0    stevel 	extern char *linp, linbuf[];
    622     0    stevel 	int jobflags, pstatus;
    623     0    stevel 	char *format;
    624     0    stevel 
    625     0    stevel #ifdef TRACE
    626     0    stevel 	tprintf("TRACE- pprint()\n");
    627     0    stevel #endif
    628     0    stevel 	while (pp->p_pid != pp->p_jobid)
    629     0    stevel 		pp = pp->p_friends;
    630     0    stevel 	if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
    631     0    stevel 		pp->p_flags &= ~PPTIME;
    632     0    stevel 		pp->p_flags |= PTIME;
    633     0    stevel 	}
    634     0    stevel 	tp = pp;
    635   559   nakanon 	status = reason = -1;
    636     0    stevel 	jobflags = 0;
    637     0    stevel 	do {
    638     0    stevel 		jobflags |= pp->p_flags;
    639     0    stevel 		pstatus = pp->p_flags & PALLSTATES;
    640     0    stevel 		if (tp != pp && linp != linbuf && !(flag&FANCY) &&
    641     0    stevel 		    (pstatus == status && pp->p_reason == reason ||
    642   559   nakanon 		    !(flag&REASON)))
    643     0    stevel 			printf(" ");
    644     0    stevel 		else {
    645     0    stevel 			if (tp != pp && linp != linbuf)
    646     0    stevel 				printf("\n");
    647   559   nakanon 			if (flag&NUMBER)
    648     0    stevel 				if (pp == tp)
    649     0    stevel 					printf("[%d]%s %c ", pp->p_index,
    650     0    stevel 					    pp->p_index < 10 ? " " : "",
    651   559   nakanon 					    pp == pcurrent ? '+' :
    652     0    stevel 						(pp == pprevious ? (tchar) '-'
    653     0    stevel 							: (tchar) ' '));
    654     0    stevel 				else
    655     0    stevel 					printf("       ");
    656     0    stevel 			if (flag&FANCY)
    657     0    stevel 				printf("%5d ", pp->p_pid);
    658     0    stevel 			if (flag&(REASON|AREASON)) {
    659     0    stevel 				if (flag&NAME)
    660     0    stevel 					format = "%-21s";
    661     0    stevel 				else
    662     0    stevel 					format = "%s";
    663     0    stevel 				if (pstatus == status)
    664     0    stevel 					if (pp->p_reason == reason) {
    665     0    stevel 						printf(format, "");
    666     0    stevel 						goto prcomd;
    667     0    stevel 					} else
    668     0    stevel 						reason = pp->p_reason;
    669     0    stevel 				else {
    670     0    stevel 					status = pstatus;
    671     0    stevel 					reason = pp->p_reason;
    672     0    stevel 				}
    673     0    stevel 				switch (status) {
    674     0    stevel 
    675     0    stevel 				case PRUNNING:
    676     0    stevel 					printf(format, "Running ");
    677     0    stevel 					break;
    678     0    stevel 
    679     0    stevel 				case PINTERRUPTED:
    680     0    stevel 				case PSTOPPED:
    681     0    stevel 				case PSIGNALED:
    682     0    stevel 					if ((flag&(REASON|AREASON))
    683     0    stevel 					    && reason != SIGINT
    684     0    stevel 					    && reason != SIGPIPE)
    685     0    stevel 						printf(format,
    686     0    stevel 						    strsignal(pp->p_reason));
    687     0    stevel 					break;
    688     0    stevel 
    689     0    stevel 				case PNEXITED:
    690     0    stevel 				case PAEXITED:
    691     0    stevel 					if (flag & REASON)
    692     0    stevel 						if (pp->p_reason)
    693     0    stevel 							printf("Exit %-16d", pp->p_reason);
    694     0    stevel 						else
    695     0    stevel 							printf(format, "Done");
    696     0    stevel 					break;
    697     0    stevel 
    698     0    stevel 				default:
    699     0    stevel 					printf("BUG: status=%-9o", status);
    700     0    stevel 				}
    701     0    stevel 			}
    702     0    stevel 		}
    703     0    stevel prcomd:
    704     0    stevel 		if (flag&NAME) {
    705     0    stevel 			printf("%t", pp->p_command);
    706     0    stevel 			if (pp->p_flags & PPOU)
    707     0    stevel 				printf(" |");
    708     0    stevel 			if (pp->p_flags & PDIAG)
    709     0    stevel 				printf("&");
    710     0    stevel 		}
    711     0    stevel 		if (flag&(REASON|AREASON) && pp->p_flags&PDUMPED)
    712     0    stevel 			printf(" (core dumped)");
    713     0    stevel 		if (tp == pp->p_friends) {
    714     0    stevel 			if (flag&AMPERSAND)
    715     0    stevel 				printf(" &");
    716     0    stevel 			if (flag&JOBDIR &&
    717     0    stevel 			    !eq(tp->p_cwd->di_name, dcwd->di_name)) {
    718     0    stevel 				printf(" (wd: ");
    719   559   nakanon 				dtildepr(value(S_home /* "home" */), tp->p_cwd->di_name);
    720     0    stevel 				printf(")");
    721     0    stevel 			}
    722     0    stevel 		}
    723     0    stevel 		if (pp->p_flags&PPTIME && !(status&(PSTOPPED|PRUNNING))) {
    724     0    stevel 			if (linp != linbuf)
    725     0    stevel 				printf("\n\t");
    726     0    stevel 			{ static struct rusage zru;
    727   559   nakanon 			    prusage(&zru, &pp->p_rusage, &pp->p_etime,
    728     0    stevel 			    &pp->p_btime);
    729     0    stevel 			}
    730     0    stevel 		}
    731     0    stevel 		if (tp == pp->p_friends) {
    732     0    stevel 			if (linp != linbuf)
    733     0    stevel 				printf("\n");
    734     0    stevel 			if (flag&SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
    735     0    stevel 				printf("(wd now: ");
    736     0    stevel 				dtildepr(value(S_home /* "home" */), dcwd->di_name);
    737     0    stevel 				printf(")\n");
    738     0    stevel 			}
    739     0    stevel 		}
    740     0    stevel 	} while ((pp = pp->p_friends) != tp);
    741     0    stevel 	if (jobflags&PTIME && (jobflags&(PSTOPPED|PRUNNING)) == 0) {
    742     0    stevel 		if (jobflags & NUMBER)
    743     0    stevel 			printf("       ");
    744     0    stevel 		ptprint(tp);
    745     0    stevel 	}
    746     0    stevel 	return (jobflags);
    747     0    stevel }
    748     0    stevel 
    749   356    muffin void
    750   356    muffin ptprint(struct process *tp)
    751     0    stevel {
    752     0    stevel 	struct timeval tetime, diff;
    753     0    stevel 	static struct timeval ztime;
    754     0    stevel 	struct rusage ru;
    755     0    stevel 	static struct rusage zru;
    756   356    muffin 	struct process *pp = tp;
    757     0    stevel 
    758     0    stevel #ifdef TRACE
    759     0    stevel 	tprintf("TRACE- ptprint()\n");
    760     0    stevel #endif
    761     0    stevel 	ru = zru;
    762     0    stevel 	tetime = ztime;
    763     0    stevel 	do {
    764     0    stevel 		ruadd(&ru, &pp->p_rusage);
    765     0    stevel 		tvsub(&diff, &pp->p_etime, &pp->p_btime);
    766     0    stevel 		if (timercmp(&diff, &tetime, >))
    767     0    stevel 			tetime = diff;
    768     0    stevel 	} while ((pp = pp->p_friends) != tp);
    769     0    stevel 	prusage(&zru, &ru, &tetime, &ztime);
    770     0    stevel }
    771     0    stevel 
    772     0    stevel /*
    773     0    stevel  * dojobs - print all jobs
    774     0    stevel  */
    775   356    muffin void
    776   356    muffin dojobs(tchar **v)
    777     0    stevel {
    778   356    muffin 	struct process *pp;
    779   356    muffin 	int flag = NUMBER|NAME|REASON;
    780     0    stevel 	int i;
    781     0    stevel 
    782     0    stevel #ifdef TRACE
    783     0    stevel 	tprintf("TRACE- dojobs()\n");
    784     0    stevel #endif
    785     0    stevel 	if (chkstop)
    786     0    stevel 		chkstop = 2;
    787     0    stevel 	if (*++v) {
    788   559   nakanon 		if (v[1] || !eq(*v, S_DASHl /* "-l" */))
    789     0    stevel 			error("Usage: jobs [ -l ]");
    790     0    stevel 		flag |= FANCY|JOBDIR;
    791     0    stevel 	}
    792     0    stevel 	for (i = 1; i <= pmaxindex; i++)
    793     0    stevel 		for (pp = proclist.p_next; pp; pp = pp->p_next)
    794     0    stevel 			if (pp->p_index == i && pp->p_pid == pp->p_jobid) {
    795     0    stevel 				pp->p_flags &= ~PNEEDNOTE;
    796     0    stevel 				if (!(pprint(pp, flag) & (PRUNNING|PSTOPPED)))
    797     0    stevel 					pflush(pp);
    798     0    stevel 				break;
    799     0    stevel 			}
    800     0    stevel }
    801     0    stevel 
    802     0    stevel /*
    803     0    stevel  * dofg - builtin - put the job into the foreground
    804     0    stevel  */
    805   356    muffin void
    806   356    muffin dofg(tchar **v)
    807     0    stevel {
    808   356    muffin 	struct process *pp;
    809     0    stevel 
    810     0    stevel #ifdef TRACE
    811     0    stevel 	tprintf("TRACE- dofg()\n");
    812     0    stevel #endif
    813     0    stevel 	okpcntl();
    814     0    stevel 	++v;
    815     0    stevel 	do {
    816     0    stevel 		pp = pfind(*v);
    817     0    stevel 		pstart(pp, 1);
    818     0    stevel 		pjwait(pp);
    819     0    stevel 	} while (*v && *++v);
    820     0    stevel }
    821     0    stevel 
    822     0    stevel /*
    823     0    stevel  * %... - builtin - put the job into the foreground
    824     0    stevel  */
    825   356    muffin void
    826   356    muffin dofg1(tchar **v)
    827     0    stevel {
    828   356    muffin 	struct process *pp;
    829     0    stevel 
    830     0    stevel #ifdef TRACE
    831     0    stevel 	tprintf("TRACE- untty()\n");
    832     0    stevel #endif
    833     0    stevel 	okpcntl();
    834     0    stevel 	pp = pfind(v[0]);
    835     0    stevel 	pstart(pp, 1);
    836     0    stevel 	pjwait(pp);
    837     0    stevel }
    838     0    stevel 
    839     0    stevel /*
    840     0    stevel  * dobg - builtin - put the job into the background
    841     0    stevel  */
    842   356    muffin void
    843   356    muffin dobg(tchar **v)
    844     0    stevel {
    845   356    muffin 	struct process *pp;
    846     0    stevel 
    847     0    stevel #ifdef TRACE
    848     0    stevel 	tprintf("TRACE- dobg()\n");
    849     0    stevel #endif
    850     0    stevel 	okpcntl();
    851     0    stevel 	++v;
    852     0    stevel 	do {
    853     0    stevel 		pp = pfind(*v);
    854     0    stevel 		pstart(pp, 0);
    855     0    stevel 	} while (*v && *++v);
    856     0    stevel }
    857     0    stevel 
    858     0    stevel /*
    859     0    stevel  * %... & - builtin - put the job into the background
    860     0    stevel  */
    861   356    muffin void
    862   356    muffin dobg1(tchar **v)
    863     0    stevel {
    864   356    muffin 	struct process *pp;
    865     0    stevel 
    866     0    stevel #ifdef TRACE
    867     0    stevel 	tprintf("TRACE- dobg1()\n");
    868     0    stevel #endif
    869     0    stevel 	pp = pfind(v[0]);
    870     0    stevel 	pstart(pp, 0);
    871     0    stevel }
    872     0    stevel 
    873     0    stevel /*
    874     0    stevel  * dostop - builtin - stop the job
    875     0    stevel  */
    876   356    muffin void
    877   356    muffin dostop(tchar **v)
    878     0    stevel {
    879     0    stevel 
    880     0    stevel #ifdef TRACE
    881     0    stevel 	tprintf("TRACE- dostop()\n");
    882     0    stevel #endif
    883     0    stevel 	pkill(++v, SIGSTOP);
    884     0    stevel }
    885     0    stevel 
    886     0    stevel /*
    887     0    stevel  * dokill - builtin - superset of kill (1)
    888     0    stevel  */
    889   356    muffin void
    890   356    muffin dokill(tchar **v)
    891     0    stevel {
    892   356    muffin 	int signum;
    893   356    muffin 	tchar *name;
    894     0    stevel 
    895     0    stevel #ifdef TRACE
    896     0    stevel 	tprintf("TRACE- dokill()\n");
    897     0    stevel #endif
    898     0    stevel 	v++;
    899     0    stevel 	if (v[0] && v[0][0] == '-') {
    900     0    stevel 		if (v[0][1] == 'l') {
    901     0    stevel 			for (signum = 1; signum <= NSIG-1; signum++) {
    902     0    stevel 				char	sbuf[BUFSIZ];
    903     0    stevel 				if (sig2str(signum, sbuf) == 0)
    904     0    stevel 					printf("%s ", sbuf);
    905     0    stevel 				if (signum % 8 == 0)
    906     0    stevel 					Putchar('\n');
    907     0    stevel 			}
    908     0    stevel 			Putchar('\n');
    909     0    stevel 			return;
    910     0    stevel 		}
    911     0    stevel 		if (digit(v[0][1])) {
    912  2182      chin 			if (chkalldigit_(v[0]+1) != 0) {
    913  2182      chin 				setname(v[0]+1);
    914  2182      chin 				bferr("Unknown signal; kill -l lists signals");
    915  2182      chin 			}
    916     0    stevel 			signum = atoi_(v[0]+1);
    917     0    stevel 			if (signum < 0 || signum > NSIG)
    918     0    stevel 				bferr("Bad signal number");
    919     0    stevel 		} else {
    920     0    stevel 			int	signo;
    921     0    stevel 			char	sbuf[BUFSIZ];
    922     0    stevel 			name = &v[0][1];
    923     0    stevel 			tstostr(sbuf, name);
    924     0    stevel 			if (str2sig(sbuf, &signo) == 0) {
    925     0    stevel 				signum = signo;
    926     0    stevel 				goto gotsig;
    927     0    stevel 			}
    928   559   nakanon 			if (eq(name, S_IOT /* "IOT" */)) {
    929     0    stevel 				signum = SIGABRT;
    930     0    stevel 				goto gotsig;
    931     0    stevel 			}
    932     0    stevel 			setname(name);
    933     0    stevel 			bferr("Unknown signal; kill -l lists signals");
    934     0    stevel 		}
    935     0    stevel gotsig:
    936     0    stevel 		v++;
    937     0    stevel 	} else
    938     0    stevel 		signum = SIGTERM;
    939     0    stevel 	pkill(v, signum);
    940     0    stevel }
    941     0    stevel 
    942   356    muffin void
    943   356    muffin pkill(tchar **v, int signum)
    944     0    stevel {
    945   356    muffin 	struct process *pp, *np;
    946   356    muffin 	int jobflags = 0;
    947     0    stevel 	int omask, pid, err = 0;
    948     0    stevel 	tchar *cp;
    949     0    stevel 
    950     0    stevel #ifdef TRACE
    951     0    stevel 	tprintf("TRACE- pkill()\n");
    952     0    stevel #endif
    953     0    stevel 	omask = sigmask(SIGCHLD);
    954     0    stevel 	if (setintr)
    955     0    stevel 		omask |= sigmask(SIGINT);
    956     0    stevel 	omask = sigblock(omask) & ~omask;
    957     0    stevel 	while (*v) {
    958     0    stevel 		cp = globone(*v);
    959     0    stevel 		if (*cp == '%') {
    960     0    stevel 			np = pp = pfind(cp);
    961     0    stevel 			do
    962     0    stevel 				jobflags |= np->p_flags;
    963     0    stevel 			while ((np = np->p_friends) != pp);
    964     0    stevel 			switch (signum) {
    965     0    stevel 
    966     0    stevel 			case SIGSTOP:
    967     0    stevel 			case SIGTSTP:
    968     0    stevel 			case SIGTTIN:
    969     0    stevel 			case SIGTTOU:
    970     0    stevel 				if ((jobflags & PRUNNING) == 0) {
    971     0    stevel 					/* %s -> %t */
    972     0    stevel 					printf("%t: Already stopped\n", cp);
    973     0    stevel 					err++;
    974     0    stevel 					goto cont;
    975     0    stevel 				}
    976     0    stevel 			}
    977     0    stevel 			if (killpg(pp->p_jobid, signum) < 0) {
    978     0    stevel 				/* %s -> %t */
    979     0    stevel 				printf("%t: ", cp);
    980     0    stevel 				printf("%s\n", strerror(errno));
    981     0    stevel 				err++;
    982     0    stevel 			}
    983     0    stevel 			if (signum == SIGTERM || signum == SIGHUP)
    984     0    stevel 				(void) killpg(pp->p_jobid, SIGCONT);
    985     0    stevel 		} else if (!(digit(*cp) || *cp == '-'))
    986     0    stevel 			bferr("Arguments should be jobs or process id's");
    987     0    stevel 		else {
    988     0    stevel 			pid = atoi_(cp);
    989     0    stevel 			if (kill(pid, signum) < 0) {
    990     0    stevel 				printf("%d: ", pid);
    991     0    stevel 				printf("%s\n", strerror(errno));
    992     0    stevel 				err++;
    993     0    stevel 				goto cont;
    994     0    stevel 			}
    995     0    stevel 			if (signum == SIGTERM || signum == SIGHUP)
    996     0    stevel 				(void) kill(pid, SIGCONT);
    997     0    stevel 		}
    998     0    stevel cont:
    999     0    stevel 		xfree(cp);
   1000     0    stevel 		v++;
   1001     0    stevel 	}
   1002     0    stevel 	(void) sigsetmask(omask);
   1003     0    stevel 	if (err)
   1004     0    stevel 		error(NULL);
   1005     0    stevel }
   1006     0    stevel 
   1007     0    stevel /*
   1008     0    stevel  * pstart - start the job in foreground/background
   1009     0    stevel  */
   1010   356    muffin void
   1011   356    muffin pstart(struct process *pp, int foregnd)
   1012     0    stevel {
   1013   356    muffin 	struct process *np;
   1014     0    stevel 	int omask, jobflags = 0;
   1015     0    stevel 
   1016     0    stevel #ifdef TRACE
   1017     0    stevel 	tprintf("TRACE- pstart()\n");
   1018     0    stevel #endif
   1019     0    stevel 	omask = sigblock(sigmask(SIGCHLD));
   1020     0    stevel 	np = pp;
   1021     0    stevel 	do {
   1022     0    stevel 		jobflags |= np->p_flags;
   1023     0    stevel 		if (np->p_flags&(PRUNNING|PSTOPPED)) {
   1024     0    stevel 			np->p_flags |= PRUNNING;
   1025     0    stevel 			np->p_flags &= ~PSTOPPED;
   1026     0    stevel 			if (foregnd)
   1027     0    stevel 				np->p_flags |= PFOREGND;
   1028     0    stevel 			else
   1029     0    stevel 				np->p_flags &= ~PFOREGND;
   1030     0    stevel 		}
   1031   559   nakanon 	} while ((np = np->p_friends) != pp);
   1032     0    stevel 
   1033     0    stevel 	if (foregnd)
   1034     0    stevel 		pclrcurr(pp);
   1035     0    stevel 	else
   1036     0    stevel 	{
   1037   559   nakanon 		if (pprevious && (pprevious->p_flags & PSTOPPED))
   1038     0    stevel 		{
   1039     0    stevel 			pcurrent = pprevious;
   1040     0    stevel 			pprevious = pgetcurr(PNULL);
   1041     0    stevel 		}
   1042     0    stevel 		else
   1043   559   nakanon 		{
   1044     0    stevel 			pcurrent = pgetcurr(pp);
   1045   559   nakanon 			if (!pcurrent || (pcurrent->p_flags & PRUNNING))
   1046     0    stevel 				pcurrent = pp;
   1047     0    stevel 			else
   1048     0    stevel 				pprevious = pp;
   1049     0    stevel 		}
   1050     0    stevel 	}
   1051     0    stevel 	(void) pprint(pp, foregnd ? NAME|JOBDIR : NUMBER|NAME|AMPERSAND);
   1052     0    stevel 	if (foregnd)
   1053     0    stevel 		(void) ioctl(FSHTTY, TIOCSPGRP,  (char *)&pp->p_jobid);
   1054     0    stevel 	if (jobflags&PSTOPPED)
   1055     0    stevel 		(void) killpg(pp->p_jobid, SIGCONT);
   1056     0    stevel 	(void) sigsetmask(omask);
   1057     0    stevel }
   1058     0    stevel 
   1059   356    muffin void
   1060   356    muffin panystop(int neednl)
   1061     0    stevel {
   1062   356    muffin 	struct process *pp;
   1063     0    stevel 
   1064     0    stevel #ifdef TRACE
   1065     0    stevel 	tprintf("TRACE- panystop()\n");
   1066     0    stevel #endif
   1067     0    stevel 	chkstop = 2;
   1068     0    stevel 	for (pp = proclist.p_next; pp; pp = pp->p_next)
   1069     0    stevel 		if (pp->p_flags & PSTOPPED)
   1070     0    stevel 			error("\nThere are stopped jobs" + 1 - neednl);
   1071     0    stevel }
   1072     0    stevel 
   1073     0    stevel struct process *
   1074   356    muffin pfind(tchar *cp)
   1075     0    stevel {
   1076   356    muffin 	struct process *pp, *np;
   1077     0    stevel 
   1078     0    stevel #ifdef TRACE
   1079     0    stevel 	tprintf("TRACE- pfind()\n");
   1080     0    stevel #endif
   1081   559   nakanon 	if (cp == 0 || cp[1] == 0 || eq(cp, S_PARCENTPARCENT /* "%%" */) ||
   1082   559   nakanon 					eq(cp, S_PARCENTPLUS /* "%+" */)) {
   1083     0    stevel 		if (pcurrent == PNULL)
   1084   559   nakanon 			if ((pcurrent = pgetcurr(PNULL)) == PNULL)
   1085     0    stevel 				bferr("No current job");
   1086     0    stevel 		return (pcurrent);
   1087     0    stevel 	}
   1088   559   nakanon 	if (eq(cp, S_PARCENTMINUS /* "%-" */) ||
   1089   559   nakanon 	    eq(cp, S_PARCENTSHARP /* "%#" */)) {
   1090     0    stevel 		if (pprevious == PNULL)
   1091     0    stevel 			bferr("No previous job");
   1092     0    stevel 		return (pprevious);
   1093     0    stevel 	}
   1094     0    stevel 	if (digit(cp[1])) {
   1095     0    stevel 		int index = atoi_(cp+1);
   1096     0    stevel 		for (pp = proclist.p_next; pp; pp = pp->p_next)
   1097     0    stevel 			if (pp->p_index == index && pp->p_pid == pp->p_jobid)
   1098     0    stevel 				return (pp);
   1099     0    stevel 		bferr("No such job");
   1100     0    stevel 	}
   1101     0    stevel 	np = PNULL;
   1102     0    stevel 	for (pp = proclist.p_next; pp; pp = pp->p_next)
   1103     0    stevel 		if (pp->p_pid == pp->p_jobid) {
   1104     0    stevel 			if (cp[1] == '?') {
   1105   356    muffin 				tchar *dp;
   1106     0    stevel 				for (dp = pp->p_command; *dp; dp++) {
   1107     0    stevel 					if (*dp != cp[2])
   1108     0    stevel 						continue;
   1109     0    stevel 					if (prefix(cp+2, dp))
   1110     0    stevel 						goto match;
   1111     0    stevel 				}
   1112     0    stevel 			} else if (prefix(cp+1, pp->p_command)) {
   1113     0    stevel match:
   1114     0    stevel 				if (np)
   1115     0    stevel 					bferr("Ambiguous");
   1116     0    stevel 				np = pp;
   1117     0    stevel 			}
   1118     0    stevel 		}
   1119     0    stevel 	if (np)
   1120     0    stevel 		return (np);
   1121     0    stevel 	if (cp[1] == '?')
   1122     0    stevel 		bferr("No job matches pattern");
   1123     0    stevel 	else
   1124     0    stevel 		bferr("No such job");
   1125     0    stevel 	/*NOTREACHED*/
   1126     0    stevel }
   1127     0    stevel 
   1128     0    stevel /*
   1129     0    stevel  * pgetcurr - find most recent job that is not pp, preferably stopped
   1130     0    stevel  */
   1131     0    stevel struct process *
   1132   356    muffin pgetcurr(struct process *pp)
   1133     0    stevel {
   1134   356    muffin 	struct process *np;
   1135   356    muffin 	struct process *xp = PNULL;
   1136     0    stevel 
   1137     0    stevel #ifdef TRACE
   1138     0    stevel 	tprintf("TRACE- pgetcurr()\n");
   1139     0    stevel #endif
   1140     0    stevel 	for (np = proclist.p_next; np; np = np->p_next)
   1141     0    stevel 		if (np != pcurrent && np != pp && np->p_pid &&
   1142     0    stevel 		    np->p_pid == np->p_jobid) {
   1143     0    stevel 			if (np->p_flags & PSTOPPED)
   1144     0    stevel 				return (np);
   1145     0    stevel 			if (xp == PNULL)
   1146     0    stevel 				xp = np;
   1147     0    stevel 		}
   1148     0    stevel 	return (xp);
   1149     0    stevel }
   1150     0    stevel 
   1151     0    stevel /*
   1152     0    stevel  * donotify - flag the job so as to report termination asynchronously
   1153     0    stevel  */
   1154   356    muffin void
   1155   356    muffin donotify(tchar **v)
   1156     0    stevel {
   1157   356    muffin 	struct process *pp;
   1158     0    stevel 
   1159     0    stevel #ifdef TRACE
   1160     0    stevel 	tprintf("TRACE- donotify()\n");
   1161     0    stevel #endif
   1162     0    stevel 	pp = pfind(*++v);
   1163     0    stevel 	pp->p_flags |= PNOTIFY;
   1164     0    stevel }
   1165     0    stevel 
   1166     0    stevel /*
   1167     0    stevel  * Do the fork and whatever should be done in the child side that
   1168     0    stevel  * should not be done if we are not forking at all (like for simple builtin's)
   1169     0    stevel  * Also do everything that needs any signals fiddled with in the parent side
   1170     0    stevel  *
   1171     0    stevel  * Wanttty tells whether process and/or tty pgrps are to be manipulated:
   1172     0    stevel  *	-1:	leave tty alone; inherit pgrp from parent
   1173     0    stevel  *	 0:	already have tty; manipulate process pgrps only
   1174     0    stevel  *	 1:	want to claim tty; manipulate process and tty pgrps
   1175     0    stevel  * It is usually just the value of tpgrp.
   1176   356    muffin  *
   1177   356    muffin  * argument:
   1178   356    muffin  *	 t:	command we are forking for
   1179     0    stevel  */
   1180   356    muffin int
   1181   356    muffin pfork(struct command *t, int wanttty)
   1182     0    stevel {
   1183   356    muffin 	int pid;
   1184     0    stevel 	bool ignint = 0;
   1185     0    stevel 	int pgrp, omask;
   1186     0    stevel 	int child_pid;
   1187     0    stevel 
   1188     0    stevel #ifdef TRACE
   1189     0    stevel 	tprintf("TRACE- pfork()\n");
   1190     0    stevel #endif
   1191     0    stevel 	/*
   1192     0    stevel 	 * A child will be uninterruptible only under very special
   1193     0    stevel 	 * conditions. Remember that the semantics of '&' is
   1194     0    stevel 	 * implemented by disconnecting the process from the tty so
   1195     0    stevel 	 * signals do not need to ignored just for '&'.
   1196     0    stevel 	 * Thus signals are set to default action for children unless:
   1197     0    stevel 	 *	we have had an "onintr -" (then specifically ignored)
   1198     0    stevel 	 *	we are not playing with signals (inherit action)
   1199     0    stevel 	 */
   1200     0    stevel 	if (setintr)
   1201     0    stevel 		ignint = (tpgrp == -1 && (t->t_dflg&FINT))
   1202   559   nakanon 		    || (gointr && eq(gointr, S_MINUS /* "-" */));
   1203     0    stevel 	/*
   1204     0    stevel 	 * Hold SIGCHLD until we have the process installed in our table.
   1205     0    stevel 	 */
   1206     0    stevel 	omask = sigblock(sigmask(SIGCHLD));
   1207     0    stevel 	while ((pid = fork()) < 0)
   1208     0    stevel 		if (setintr == 0)
   1209     0    stevel 			sleep(FORKSLEEP);
   1210     0    stevel 		else {
   1211     0    stevel 			(void) sigsetmask(omask);
   1212     0    stevel 			error("Fork failed");
   1213     0    stevel 		}
   1214     0    stevel 
   1215     0    stevel 	/*
   1216     0    stevel 	 * setup the process group
   1217     0    stevel 	 */
   1218     0    stevel 	if (pid == 0)
   1219     0    stevel 		child_pid = getpid();
   1220     0    stevel 	else
   1221     0    stevel 		child_pid = pid;
   1222     0    stevel 	pgrp = pcurrjob ? pcurrjob->p_jobid : child_pid;
   1223     0    stevel 
   1224     0    stevel 	if (pid == 0) {
   1225     0    stevel 		int sigttou;
   1226     0    stevel 		settimes();
   1227     0    stevel 		pflushall();
   1228     0    stevel 		pcurrjob = PNULL;
   1229     0    stevel 		child++;
   1230     0    stevel 		if (setintr) {
   1231     0    stevel 			setintr = 0;		/* until I think otherwise */
   1232     0    stevel 			/*
   1233     0    stevel 			 * Children just get blown away on SIGINT, SIGQUIT
   1234     0    stevel 			 * unless "onintr -" seen.
   1235     0    stevel 			 */
   1236     0    stevel 			(void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
   1237     0    stevel 			(void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
   1238     0    stevel 			if (wanttty >= 0) {
   1239     0    stevel 				/* make stoppable */
   1240     0    stevel 				(void) signal(SIGTSTP, SIG_DFL);
   1241     0    stevel 				(void) signal(SIGTTIN, SIG_DFL);
   1242     0    stevel 				(void) signal(SIGTTOU, SIG_DFL);
   1243     0    stevel 			}
   1244     0    stevel 			(void) signal(SIGTERM, parterm);
   1245     0    stevel 		} else if (tpgrp == -1 && (t->t_dflg&FINT)) {
   1246     0    stevel 			(void) signal(SIGINT, SIG_IGN);
   1247     0    stevel 			(void) signal(SIGQUIT, SIG_IGN);
   1248     0    stevel 		}
   1249     0    stevel 		if (wanttty >= 0 && tpgrp >= 0)
   1250     0    stevel 			(void) setpgid(0, pgrp);
   1251     0    stevel 		if (wanttty > 0) {
   1252   559   nakanon 			sigttou = sigblock(sigmask(SIGTTOU) |
   1253   559   nakanon 					    sigmask(SIGTTIN) |
   1254     0    stevel 					    sigmask(SIGTSTP));
   1255     0    stevel 			(void) ioctl(FSHTTY, TIOCSPGRP,  (char *)&pgrp);
   1256   559   nakanon 			sigsetmask(sigttou);
   1257     0    stevel 		}
   1258     0    stevel 		if (tpgrp > 0)
   1259     0    stevel 			tpgrp = 0;		/* gave tty away */
   1260     0    stevel 		/*
   1261     0    stevel 		 * Nohup and nice apply only to TCOM's but it would be
   1262     0    stevel 		 * nice (?!?) if you could say "nohup (foo;bar)"
   1263     0    stevel 		 * Then the parser would have to know about nice/nohup/time
   1264     0    stevel 		 */
   1265     0    stevel 		if (t->t_dflg & FNOHUP)
   1266     0    stevel 			(void) signal(SIGHUP, SIG_IGN);
   1267     0    stevel 		if (t->t_dflg & FNICE)
   1268     0    stevel 			(void) setpriority(PRIO_PROCESS, 0, t->t_nice);
   1269     0    stevel 	} else {
   1270     0    stevel 		if (wanttty >= 0 && tpgrp >= 0)
   1271     0    stevel 			setpgid(pid, pgrp);
   1272     0    stevel 		palloc(pid, t);
   1273     0    stevel 		(void) sigsetmask(omask);
   1274     0    stevel 	}
   1275     0    stevel 
   1276     0    stevel 	return (pid);
   1277     0    stevel }
   1278     0    stevel 
   1279   356    muffin void
   1280   356    muffin okpcntl(void)
   1281     0    stevel {
   1282     0    stevel #ifdef TRACE
   1283     0    stevel 	tprintf("TRACE- okpcntl()\n");
   1284     0    stevel #endif
   1285     0    stevel 
   1286     0    stevel 	if (tpgrp == -1)
   1287     0    stevel 		error("No job control in this shell");
   1288     0    stevel 	if (tpgrp == 0)
   1289     0    stevel 		error("No job control in subshells");
   1290     0    stevel }
   1291  2200  mg147109 
   1292  2200  mg147109 void
   1293  2200  mg147109 hupforegnd(void)
   1294  2200  mg147109 {
   1295  2200  mg147109 	struct process *pp;
   1296  2200  mg147109 	int omask;
   1297  2200  mg147109 
   1298  2200  mg147109 	omask = sigblock(sigmask(SIGCHLD));
   1299  2200  mg147109 	for (pp = (&proclist)->p_next; pp != PNULL; pp = pp->p_next)
   1300  2200  mg147109 		if (pp->p_pid > 0) {
   1301  2200  mg147109 			if (pp->p_flags & PFOREGND)
   1302  2200  mg147109 				(void) kill(pp->p_pid, SIGHUP);
   1303  2200  mg147109 		}
   1304  2200  mg147109 	(void) sigsetmask(omask);
   1305  2200  mg147109 }
   1306