xref: /illumos-gate/usr/src/cmd/csh/sh.proc.c (revision 6c02b4a4)
17c478bd9Sstevel@tonic-gate /*
28e3c57a3Sraf  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
77c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
87c478bd9Sstevel@tonic-gate 
97c478bd9Sstevel@tonic-gate /*
107c478bd9Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
117c478bd9Sstevel@tonic-gate  * All rights reserved. The Berkeley Software License Agreement
127c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
137c478bd9Sstevel@tonic-gate  */
147c478bd9Sstevel@tonic-gate 
157c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
167c478bd9Sstevel@tonic-gate 
177c478bd9Sstevel@tonic-gate #include "sh.h"
187c478bd9Sstevel@tonic-gate #include "sh.dir.h"
197c478bd9Sstevel@tonic-gate #include "sh.proc.h"
207c478bd9Sstevel@tonic-gate #include "wait.h"
217c478bd9Sstevel@tonic-gate #include "sh.tconst.h"
227c478bd9Sstevel@tonic-gate 
237c478bd9Sstevel@tonic-gate /*
247c478bd9Sstevel@tonic-gate  * C Shell - functions that manage processes, handling hanging, termination
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #define BIGINDEX	9	/* largest desirable job index */
287c478bd9Sstevel@tonic-gate 
29*6c02b4a4Smuffin void	pjwait(struct process *);
30*6c02b4a4Smuffin void	pflush(struct process *);
31*6c02b4a4Smuffin void	pclrcurr(struct process *);
32*6c02b4a4Smuffin void	padd(struct command *);
33*6c02b4a4Smuffin void	pads(tchar *);
34*6c02b4a4Smuffin void	ptprint(struct process *);
35*6c02b4a4Smuffin void	pkill(tchar **, int);
36*6c02b4a4Smuffin void	pstart(struct process *, int);
37*6c02b4a4Smuffin void	okpcntl(void);
38*6c02b4a4Smuffin struct process	*pgetcurr(struct process *);
39*6c02b4a4Smuffin struct process	*pfind(tchar *);
40*6c02b4a4Smuffin 
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate  * pchild - called at interrupt level by the SIGCHLD signal
437c478bd9Sstevel@tonic-gate  *	indicating that at least one child has terminated or stopped
447c478bd9Sstevel@tonic-gate  *	thus at least one wait system call will definitely return a
457c478bd9Sstevel@tonic-gate  *	childs status.  Top level routines (like pwait) must be sure
467c478bd9Sstevel@tonic-gate  *	to mask interrupts when playing with the proclist data structures!
477c478bd9Sstevel@tonic-gate  */
487c478bd9Sstevel@tonic-gate void
49*6c02b4a4Smuffin pchild(void)
507c478bd9Sstevel@tonic-gate {
51*6c02b4a4Smuffin 	struct process *pp;
52*6c02b4a4Smuffin 	struct process	*fp;
53*6c02b4a4Smuffin 	int pid;
547c478bd9Sstevel@tonic-gate 	union wait w;
557c478bd9Sstevel@tonic-gate 	int jobflags;
567c478bd9Sstevel@tonic-gate 	struct rusage ru;
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #ifdef TRACE
597c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pchile()\n");
607c478bd9Sstevel@tonic-gate #endif
617c478bd9Sstevel@tonic-gate loop:
627c478bd9Sstevel@tonic-gate 	pid = csh_wait3(&w, (setintr ? WNOHANG|WUNTRACED:WNOHANG), &ru);
637c478bd9Sstevel@tonic-gate         /*
647c478bd9Sstevel@tonic-gate          * SysV sends a SIGCHLD when the child process
657c478bd9Sstevel@tonic-gate          * receives a SIGCONT, and result of that action is ignored here
667c478bd9Sstevel@tonic-gate          */
677c478bd9Sstevel@tonic-gate         if ( w.w_status == WCONTFLG )
687c478bd9Sstevel@tonic-gate                 return;
697c478bd9Sstevel@tonic-gate 	if (pid <= 0) {
707c478bd9Sstevel@tonic-gate 		if (errno == EINTR) {
717c478bd9Sstevel@tonic-gate 			errno = 0;
727c478bd9Sstevel@tonic-gate 			goto loop;
737c478bd9Sstevel@tonic-gate 		}
747c478bd9Sstevel@tonic-gate 		pnoprocesses = pid == -1;
757c478bd9Sstevel@tonic-gate 		return;
767c478bd9Sstevel@tonic-gate 	}
777c478bd9Sstevel@tonic-gate 	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
787c478bd9Sstevel@tonic-gate 		if (pid == pp->p_pid)
797c478bd9Sstevel@tonic-gate 			goto found;
807c478bd9Sstevel@tonic-gate 	goto loop;
817c478bd9Sstevel@tonic-gate found:
827c478bd9Sstevel@tonic-gate 	if (pid == atoi_(value(S_child /*"child"*/)))
837c478bd9Sstevel@tonic-gate 		unsetv(S_child /*"child"*/);
847c478bd9Sstevel@tonic-gate 	pp->p_flags &= ~(PRUNNING|PSTOPPED|PREPORTED);
857c478bd9Sstevel@tonic-gate 	if (WIFSTOPPED(w)) {
867c478bd9Sstevel@tonic-gate 		pp->p_flags |= PSTOPPED;
877c478bd9Sstevel@tonic-gate 		pp->p_reason = w.w_stopsig;
887c478bd9Sstevel@tonic-gate 	} else {
897c478bd9Sstevel@tonic-gate 		if (pp->p_flags & (PTIME|PPTIME) || adrof(S_time /*"time"*/))
907c478bd9Sstevel@tonic-gate 			(void) gettimeofday(&pp->p_etime, (struct timezone *)0);
917c478bd9Sstevel@tonic-gate 		pp->p_rusage = ru;
927c478bd9Sstevel@tonic-gate 		if (WIFSIGNALED(w)) {
937c478bd9Sstevel@tonic-gate 			if (w.w_termsig == SIGINT)
947c478bd9Sstevel@tonic-gate 				pp->p_flags |= PINTERRUPTED;
957c478bd9Sstevel@tonic-gate 			else
967c478bd9Sstevel@tonic-gate 				pp->p_flags |= PSIGNALED;
977c478bd9Sstevel@tonic-gate 			if (w.w_coredump)
987c478bd9Sstevel@tonic-gate 				pp->p_flags |= PDUMPED;
997c478bd9Sstevel@tonic-gate 			pp->p_reason = w.w_termsig;
1007c478bd9Sstevel@tonic-gate 		} else {
1017c478bd9Sstevel@tonic-gate 			pp->p_reason = w.w_retcode;
1027c478bd9Sstevel@tonic-gate 			if (pp->p_reason != 0)
1037c478bd9Sstevel@tonic-gate 				pp->p_flags |= PAEXITED;
1047c478bd9Sstevel@tonic-gate 			else
1057c478bd9Sstevel@tonic-gate 				pp->p_flags |= PNEXITED;
1067c478bd9Sstevel@tonic-gate 		}
1077c478bd9Sstevel@tonic-gate 	}
1087c478bd9Sstevel@tonic-gate 	jobflags = 0;
1097c478bd9Sstevel@tonic-gate 	fp = pp;
1107c478bd9Sstevel@tonic-gate 	do {
1117c478bd9Sstevel@tonic-gate 		if ((fp->p_flags & (PPTIME|PRUNNING|PSTOPPED)) == 0 &&
1127c478bd9Sstevel@tonic-gate 		    !child && adrof(S_time /*"time"*/) &&
1137c478bd9Sstevel@tonic-gate 		    fp->p_rusage.ru_utime.tv_sec+fp->p_rusage.ru_stime.tv_sec >=
1147c478bd9Sstevel@tonic-gate 		     atoi_(value(S_time /*"time"*/)))
1157c478bd9Sstevel@tonic-gate 			fp->p_flags |= PTIME;
1167c478bd9Sstevel@tonic-gate 		jobflags |= fp->p_flags;
1177c478bd9Sstevel@tonic-gate 	} while ((fp = fp->p_friends) != pp);
1187c478bd9Sstevel@tonic-gate 	pp->p_flags &= ~PFOREGND;
1197c478bd9Sstevel@tonic-gate 	if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
1207c478bd9Sstevel@tonic-gate 		pp->p_flags &= ~PPTIME;
1217c478bd9Sstevel@tonic-gate 		pp->p_flags |= PTIME;
1227c478bd9Sstevel@tonic-gate 	}
1237c478bd9Sstevel@tonic-gate 	if ((jobflags & (PRUNNING|PREPORTED)) == 0) {
1247c478bd9Sstevel@tonic-gate 		fp = pp;
1257c478bd9Sstevel@tonic-gate 		do {
1267c478bd9Sstevel@tonic-gate 			if (fp->p_flags&PSTOPPED)
1277c478bd9Sstevel@tonic-gate 				fp->p_flags |= PREPORTED;
1287c478bd9Sstevel@tonic-gate 		} while((fp = fp->p_friends) != pp);
1297c478bd9Sstevel@tonic-gate 		while(fp->p_pid != fp->p_jobid)
1307c478bd9Sstevel@tonic-gate 			fp = fp->p_friends;
1317c478bd9Sstevel@tonic-gate 		if (jobflags&PSTOPPED) {
1327c478bd9Sstevel@tonic-gate 			if (pcurrent && pcurrent != fp)
1337c478bd9Sstevel@tonic-gate 				pprevious = pcurrent;
1347c478bd9Sstevel@tonic-gate 			pcurrent = fp;
1357c478bd9Sstevel@tonic-gate 		} else
1367c478bd9Sstevel@tonic-gate 			pclrcurr(fp);
1377c478bd9Sstevel@tonic-gate 		if (jobflags&PFOREGND) {
1387c478bd9Sstevel@tonic-gate 			if (jobflags & (PSIGNALED|PSTOPPED|PPTIME) ||
1397c478bd9Sstevel@tonic-gate #ifdef IIASA
1407c478bd9Sstevel@tonic-gate 			    jobflags & PAEXITED ||
1417c478bd9Sstevel@tonic-gate #endif
1427c478bd9Sstevel@tonic-gate 			    !eq(dcwd->di_name, fp->p_cwd->di_name)) {
1437c478bd9Sstevel@tonic-gate 				;	/* print in pjwait */
1447c478bd9Sstevel@tonic-gate 			}
1457c478bd9Sstevel@tonic-gate 		} else {
1467c478bd9Sstevel@tonic-gate 			if (jobflags&PNOTIFY || adrof(S_notify /*"notify"*/)) {
1477c478bd9Sstevel@tonic-gate 				write_string("\015\n");
1487c478bd9Sstevel@tonic-gate 				flush();
1497c478bd9Sstevel@tonic-gate 				(void) pprint(pp, NUMBER|NAME|REASON);
1507c478bd9Sstevel@tonic-gate 				if ((jobflags&PSTOPPED) == 0)
1517c478bd9Sstevel@tonic-gate 					pflush(pp);
1527c478bd9Sstevel@tonic-gate 			} else {
1537c478bd9Sstevel@tonic-gate 				fp->p_flags |= PNEEDNOTE;
1547c478bd9Sstevel@tonic-gate 				neednote++;
1557c478bd9Sstevel@tonic-gate 			}
1567c478bd9Sstevel@tonic-gate 		}
1577c478bd9Sstevel@tonic-gate 	}
1587c478bd9Sstevel@tonic-gate 	goto loop;
1597c478bd9Sstevel@tonic-gate }
1607c478bd9Sstevel@tonic-gate 
161*6c02b4a4Smuffin void
162*6c02b4a4Smuffin pnote(void)
1637c478bd9Sstevel@tonic-gate {
164*6c02b4a4Smuffin 	struct process *pp;
1657c478bd9Sstevel@tonic-gate 	int flags, omask;
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate #ifdef TRACE
1687c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pnote()\n");
1697c478bd9Sstevel@tonic-gate #endif
1707c478bd9Sstevel@tonic-gate 	neednote = 0;
1717c478bd9Sstevel@tonic-gate 	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) {
1727c478bd9Sstevel@tonic-gate 		if (pp->p_flags & PNEEDNOTE) {
1737c478bd9Sstevel@tonic-gate 			omask = sigblock(sigmask(SIGCHLD));
1747c478bd9Sstevel@tonic-gate 			pp->p_flags &= ~PNEEDNOTE;
1757c478bd9Sstevel@tonic-gate 			flags = pprint(pp, NUMBER|NAME|REASON);
1767c478bd9Sstevel@tonic-gate 			if ((flags&(PRUNNING|PSTOPPED)) == 0)
1777c478bd9Sstevel@tonic-gate 				pflush(pp);
1787c478bd9Sstevel@tonic-gate 			(void) sigsetmask(omask);
1797c478bd9Sstevel@tonic-gate 		}
1807c478bd9Sstevel@tonic-gate 	}
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate /*
1847c478bd9Sstevel@tonic-gate  * pwait - wait for current job to terminate, maintaining integrity
1857c478bd9Sstevel@tonic-gate  *	of current and previous job indicators.
1867c478bd9Sstevel@tonic-gate  */
187*6c02b4a4Smuffin void
188*6c02b4a4Smuffin pwait(void)
1897c478bd9Sstevel@tonic-gate {
190*6c02b4a4Smuffin 	struct process *fp, *pp;
1917c478bd9Sstevel@tonic-gate 	int omask;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate #ifdef TRACE
1947c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pwait()\n");
1957c478bd9Sstevel@tonic-gate #endif
1967c478bd9Sstevel@tonic-gate 	/*
1977c478bd9Sstevel@tonic-gate 	 * Here's where dead procs get flushed.
1987c478bd9Sstevel@tonic-gate 	 */
1997c478bd9Sstevel@tonic-gate 	omask = sigblock(sigmask(SIGCHLD));
2007c478bd9Sstevel@tonic-gate 	for (pp = (fp = &proclist)->p_next; pp != PNULL; pp = (fp = pp)->p_next)
2017c478bd9Sstevel@tonic-gate 		if (pp->p_pid == 0) {
2027c478bd9Sstevel@tonic-gate 			fp->p_next = pp->p_next;
2037c478bd9Sstevel@tonic-gate 			xfree(pp->p_command);
2047c478bd9Sstevel@tonic-gate 			if (pp->p_cwd && --pp->p_cwd->di_count == 0)
2057c478bd9Sstevel@tonic-gate 				if (pp->p_cwd->di_next == 0)
2067c478bd9Sstevel@tonic-gate 					dfree(pp->p_cwd);
2077c478bd9Sstevel@tonic-gate 			xfree( (tchar *)pp);
2087c478bd9Sstevel@tonic-gate 			pp = fp;
2097c478bd9Sstevel@tonic-gate 		}
2107c478bd9Sstevel@tonic-gate 	(void) sigsetmask(omask);
2117c478bd9Sstevel@tonic-gate 	pjwait(pcurrjob);
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate /*
2157c478bd9Sstevel@tonic-gate  * pjwait - wait for a job to finish or become stopped
2167c478bd9Sstevel@tonic-gate  *	It is assumed to be in the foreground state (PFOREGND)
2177c478bd9Sstevel@tonic-gate  */
218*6c02b4a4Smuffin void
219*6c02b4a4Smuffin pjwait(struct process *pp)
2207c478bd9Sstevel@tonic-gate {
221*6c02b4a4Smuffin 	struct process *fp;
2227c478bd9Sstevel@tonic-gate 	int jobflags, reason, omask;
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate #ifdef TRACE
2257c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pjwait()\n");
2267c478bd9Sstevel@tonic-gate #endif
2277c478bd9Sstevel@tonic-gate 	while (pp->p_pid != pp->p_jobid)
2287c478bd9Sstevel@tonic-gate 		pp = pp->p_friends;
2297c478bd9Sstevel@tonic-gate 	fp = pp;
2307c478bd9Sstevel@tonic-gate 	do {
2317c478bd9Sstevel@tonic-gate 		if ((fp->p_flags&(PFOREGND|PRUNNING)) == PRUNNING)
2327c478bd9Sstevel@tonic-gate 			printf("BUG: waiting for background job!\n");
2337c478bd9Sstevel@tonic-gate 	} while ((fp = fp->p_friends) != pp);
2347c478bd9Sstevel@tonic-gate 	/*
2357c478bd9Sstevel@tonic-gate 	 * Now keep pausing as long as we are not interrupted (SIGINT),
2367c478bd9Sstevel@tonic-gate 	 * and the target process, or any of its friends, are running
2377c478bd9Sstevel@tonic-gate 	 */
2387c478bd9Sstevel@tonic-gate 	fp = pp;
2397c478bd9Sstevel@tonic-gate 	omask = sigblock(sigmask(SIGCHLD));
2407c478bd9Sstevel@tonic-gate 	for (;;) {
2417c478bd9Sstevel@tonic-gate 		jobflags = 0;
2427c478bd9Sstevel@tonic-gate 		do
2437c478bd9Sstevel@tonic-gate 			jobflags |= fp->p_flags;
2447c478bd9Sstevel@tonic-gate 		while ((fp = (fp->p_friends)) != pp);
2457c478bd9Sstevel@tonic-gate 		if ((jobflags & PRUNNING) == 0)
2467c478bd9Sstevel@tonic-gate 			break;
2478e3c57a3Sraf 		/*
2488e3c57a3Sraf 		 * At this point, csh used to call:
2498e3c57a3Sraf 		 *	sigpause(sigblock(0) &~ sigmask(SIGCHLD));
2508e3c57a3Sraf 		 * expecting to receive a SIGCHLD signal from the
2518e3c57a3Sraf 		 * termination of the child and to invoke the
2528e3c57a3Sraf 		 * signal handler, pchild(), as a result.
2538e3c57a3Sraf 		 *
2548e3c57a3Sraf 		 * However, vfork() now causes a vfork()'d child to
2558e3c57a3Sraf 		 * have all of its active signal handlers reset to
2568e3c57a3Sraf 		 * SIG_DFL, to forstall parent memory corruption due
2578e3c57a3Sraf 		 * to race conditions with signal handling.
2588e3c57a3Sraf 		 *
2598e3c57a3Sraf 		 * If this instance of csh is itself a child of vfork(),
2608e3c57a3Sraf 		 * which can happen when the top-level csh performs a
2618e3c57a3Sraf 		 * command substitution inside an i/o redirection, like:
2628e3c57a3Sraf 		 *	/bin/echo foo >`/bin/echo trash`
2638e3c57a3Sraf 		 * then we will never receive SIGCHLD.  To accommodate
2648e3c57a3Sraf 		 * this, we wait until one of our children terminates
2658e3c57a3Sraf 		 * (without actually reaping the child) and call the
2668e3c57a3Sraf 		 * SIGCHLD signal handler (pchild()) directly.
2678e3c57a3Sraf 		 */
2688e3c57a3Sraf 		if (csh_wait_noreap() > 0)
2698e3c57a3Sraf 			pchild();	/* simulate receipt of SIGCHLD */
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate 	(void) sigsetmask(omask);
2727c478bd9Sstevel@tonic-gate 	if (tpgrp > 0)			/* get tty back */
2737c478bd9Sstevel@tonic-gate 		(void) ioctl(FSHTTY, TIOCSPGRP,  (char *)&tpgrp);
2747c478bd9Sstevel@tonic-gate 	if ((jobflags&(PSIGNALED|PSTOPPED|PTIME)) ||
2757c478bd9Sstevel@tonic-gate 	     !eq(dcwd->di_name, fp->p_cwd->di_name)) {
2767c478bd9Sstevel@tonic-gate 		if (jobflags&PSTOPPED)
2777c478bd9Sstevel@tonic-gate 			printf("\n");
2787c478bd9Sstevel@tonic-gate 		(void) pprint(pp, AREASON|SHELLDIR);
2797c478bd9Sstevel@tonic-gate 	}
2807c478bd9Sstevel@tonic-gate 	if ((jobflags&(PINTERRUPTED|PSTOPPED)) && setintr &&
2817c478bd9Sstevel@tonic-gate 	    (!gointr || !eq(gointr, S_MINUS /*"-"*/))) {
2827c478bd9Sstevel@tonic-gate 		if ((jobflags & PSTOPPED) == 0)
2837c478bd9Sstevel@tonic-gate 			pflush(pp);
2847c478bd9Sstevel@tonic-gate 		pintr1(0);
2857c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
2867c478bd9Sstevel@tonic-gate 	}
2877c478bd9Sstevel@tonic-gate 	reason = 0;
2887c478bd9Sstevel@tonic-gate 	fp = pp;
2897c478bd9Sstevel@tonic-gate 	do {
2907c478bd9Sstevel@tonic-gate 		if (fp->p_reason)
2917c478bd9Sstevel@tonic-gate 			reason = fp->p_flags & (PSIGNALED|PINTERRUPTED) ?
2927c478bd9Sstevel@tonic-gate 				fp->p_reason | ABN_TERM : fp->p_reason;
2937c478bd9Sstevel@tonic-gate 	} while ((fp = fp->p_friends) != pp);
2947c478bd9Sstevel@tonic-gate 	set(S_status/*"status"*/, putn(reason));
2957c478bd9Sstevel@tonic-gate 	if (reason && exiterr)
2967c478bd9Sstevel@tonic-gate 		exitstat();
2977c478bd9Sstevel@tonic-gate 	pflush(pp);
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate /*
3017c478bd9Sstevel@tonic-gate  * dowait - wait for all processes to finish
3027c478bd9Sstevel@tonic-gate  */
303*6c02b4a4Smuffin void
304*6c02b4a4Smuffin dowait(void)
3057c478bd9Sstevel@tonic-gate {
306*6c02b4a4Smuffin 	struct process *pp;
3077c478bd9Sstevel@tonic-gate 	int omask;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate #ifdef TRACE
3107c478bd9Sstevel@tonic-gate 	tprintf("TRACE- dowait()\n");
3117c478bd9Sstevel@tonic-gate #endif
3127c478bd9Sstevel@tonic-gate 	pjobs++;
3137c478bd9Sstevel@tonic-gate 	omask = sigblock(sigmask(SIGCHLD));
3147c478bd9Sstevel@tonic-gate loop:
3157c478bd9Sstevel@tonic-gate 	for (pp = proclist.p_next; pp; pp = pp->p_next)
3167c478bd9Sstevel@tonic-gate 		if (pp->p_pid && /* pp->p_pid == pp->p_jobid && */
3177c478bd9Sstevel@tonic-gate 		    pp->p_flags&PRUNNING) {
3187c478bd9Sstevel@tonic-gate 			sigpause(0);
3197c478bd9Sstevel@tonic-gate 			goto loop;
3207c478bd9Sstevel@tonic-gate 		}
3217c478bd9Sstevel@tonic-gate 	(void) sigsetmask(omask);
3227c478bd9Sstevel@tonic-gate 	pjobs = 0;
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate /*
3267c478bd9Sstevel@tonic-gate  * pflushall - flush all jobs from list (e.g. at fork())
3277c478bd9Sstevel@tonic-gate  */
328*6c02b4a4Smuffin void
329*6c02b4a4Smuffin pflushall(void)
3307c478bd9Sstevel@tonic-gate {
331*6c02b4a4Smuffin 	struct process	*pp;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate #ifdef TRACE
3347c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pflush()\n");
3357c478bd9Sstevel@tonic-gate #endif
3367c478bd9Sstevel@tonic-gate 	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
3377c478bd9Sstevel@tonic-gate 		if (pp->p_pid)
3387c478bd9Sstevel@tonic-gate 			pflush(pp);
3397c478bd9Sstevel@tonic-gate }
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate /*
3427c478bd9Sstevel@tonic-gate  * pflush - flag all process structures in the same job as the
3437c478bd9Sstevel@tonic-gate  *	the argument process for deletion.  The actual free of the
3447c478bd9Sstevel@tonic-gate  *	space is not done here since pflush is called at interrupt level.
3457c478bd9Sstevel@tonic-gate  */
346*6c02b4a4Smuffin void
347*6c02b4a4Smuffin pflush(struct process *pp)
3487c478bd9Sstevel@tonic-gate {
349*6c02b4a4Smuffin 	struct process *np;
350*6c02b4a4Smuffin 	int index;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate #ifdef TRACE
3537c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pflush()\n");
3547c478bd9Sstevel@tonic-gate #endif
3557c478bd9Sstevel@tonic-gate 	if (pp->p_pid == 0) {
3567c478bd9Sstevel@tonic-gate 		printf("BUG: process flushed twice");
3577c478bd9Sstevel@tonic-gate 		return;
3587c478bd9Sstevel@tonic-gate 	}
3597c478bd9Sstevel@tonic-gate 	while (pp->p_pid != pp->p_jobid)
3607c478bd9Sstevel@tonic-gate 		pp = pp->p_friends;
3617c478bd9Sstevel@tonic-gate 	pclrcurr(pp);
3627c478bd9Sstevel@tonic-gate 	if (pp == pcurrjob)
3637c478bd9Sstevel@tonic-gate 		pcurrjob = 0;
3647c478bd9Sstevel@tonic-gate 	index = pp->p_index;
3657c478bd9Sstevel@tonic-gate 	np = pp;
3667c478bd9Sstevel@tonic-gate 	do {
3677c478bd9Sstevel@tonic-gate 		np->p_index = np->p_pid = 0;
3687c478bd9Sstevel@tonic-gate 		np->p_flags &= ~PNEEDNOTE;
3697c478bd9Sstevel@tonic-gate 	} while ((np = np->p_friends) != pp);
3707c478bd9Sstevel@tonic-gate 	if (index == pmaxindex) {
3717c478bd9Sstevel@tonic-gate 		for (np = proclist.p_next, index = 0; np; np = np->p_next)
3727c478bd9Sstevel@tonic-gate 			if (np->p_index > (tchar)index)
3737c478bd9Sstevel@tonic-gate 				index = np->p_index;
3747c478bd9Sstevel@tonic-gate 		pmaxindex = index;
3757c478bd9Sstevel@tonic-gate 	}
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate /*
3797c478bd9Sstevel@tonic-gate  * pclrcurr - make sure the given job is not the current or previous job;
3807c478bd9Sstevel@tonic-gate  *	pp MUST be the job leader
3817c478bd9Sstevel@tonic-gate  */
382*6c02b4a4Smuffin void
383*6c02b4a4Smuffin pclrcurr(struct process *pp)
3847c478bd9Sstevel@tonic-gate {
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate #ifdef TRACE
3877c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pclrcurr()\n");
3887c478bd9Sstevel@tonic-gate #endif
3897c478bd9Sstevel@tonic-gate 	if (pp == pcurrent)
3907c478bd9Sstevel@tonic-gate 		if (pprevious != PNULL) {
3917c478bd9Sstevel@tonic-gate 			pcurrent = pprevious;
3927c478bd9Sstevel@tonic-gate 			pprevious = pgetcurr(pp);
3937c478bd9Sstevel@tonic-gate 		} else {
3947c478bd9Sstevel@tonic-gate 			pcurrent = pgetcurr(pp);
3957c478bd9Sstevel@tonic-gate 			pprevious = pgetcurr(pp);
3967c478bd9Sstevel@tonic-gate 		}
3977c478bd9Sstevel@tonic-gate 	else if (pp == pprevious)
3987c478bd9Sstevel@tonic-gate 		pprevious = pgetcurr(pp);
3997c478bd9Sstevel@tonic-gate }
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate /* +4 here is 1 for '\0', 1 ea for << >& >> */
4027c478bd9Sstevel@tonic-gate tchar	command[PMAXLEN+4];
4037c478bd9Sstevel@tonic-gate int	cmdlen;
4047c478bd9Sstevel@tonic-gate tchar	*cmdp;
4057c478bd9Sstevel@tonic-gate /*
4067c478bd9Sstevel@tonic-gate  * palloc - allocate a process structure and fill it up.
4077c478bd9Sstevel@tonic-gate  *	an important assumption is made that the process is running.
4087c478bd9Sstevel@tonic-gate  */
409*6c02b4a4Smuffin void
410*6c02b4a4Smuffin palloc(int pid, struct command *t)
4117c478bd9Sstevel@tonic-gate {
412*6c02b4a4Smuffin 	struct process	*pp;
4137c478bd9Sstevel@tonic-gate 	int i;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate #ifdef TRACE
4167c478bd9Sstevel@tonic-gate 	tprintf("TRACE- palloc()\n");
4177c478bd9Sstevel@tonic-gate #endif
4187c478bd9Sstevel@tonic-gate 	pp = (struct process *)calloc(1, sizeof(struct process));
4197c478bd9Sstevel@tonic-gate 	pp->p_pid = pid;
4207c478bd9Sstevel@tonic-gate 	pp->p_flags = t->t_dflg & FAND ? PRUNNING : PRUNNING|PFOREGND;
4217c478bd9Sstevel@tonic-gate 	if (t->t_dflg & FTIME)
4227c478bd9Sstevel@tonic-gate 		pp->p_flags |= PPTIME;
4237c478bd9Sstevel@tonic-gate 	cmdp = command;
4247c478bd9Sstevel@tonic-gate 	cmdlen = 0;
4257c478bd9Sstevel@tonic-gate 	padd(t);
4267c478bd9Sstevel@tonic-gate 	*cmdp++ = 0;
4277c478bd9Sstevel@tonic-gate 	if (t->t_dflg & FPOU) {
4287c478bd9Sstevel@tonic-gate 		pp->p_flags |= PPOU;
4297c478bd9Sstevel@tonic-gate 		if (t->t_dflg & FDIAG)
4307c478bd9Sstevel@tonic-gate 			pp->p_flags |= PDIAG;
4317c478bd9Sstevel@tonic-gate 	}
4327c478bd9Sstevel@tonic-gate 	pp->p_command = savestr(command);
4337c478bd9Sstevel@tonic-gate 	if (pcurrjob) {
4347c478bd9Sstevel@tonic-gate 		struct process *fp;
4357c478bd9Sstevel@tonic-gate 		/* careful here with interrupt level */
4367c478bd9Sstevel@tonic-gate 		pp->p_cwd = 0;
4377c478bd9Sstevel@tonic-gate 		pp->p_index = pcurrjob->p_index;
4387c478bd9Sstevel@tonic-gate 		pp->p_friends = pcurrjob;
4397c478bd9Sstevel@tonic-gate 		pp->p_jobid = pcurrjob->p_pid;
4407c478bd9Sstevel@tonic-gate 		for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
4417c478bd9Sstevel@tonic-gate 			;
4427c478bd9Sstevel@tonic-gate 		fp->p_friends = pp;
4437c478bd9Sstevel@tonic-gate 	} else {
4447c478bd9Sstevel@tonic-gate 		pcurrjob = pp;
4457c478bd9Sstevel@tonic-gate 		pp->p_jobid = pid;
4467c478bd9Sstevel@tonic-gate 		pp->p_friends = pp;
4477c478bd9Sstevel@tonic-gate 		pp->p_cwd = dcwd;
4487c478bd9Sstevel@tonic-gate 		dcwd->di_count++;
4497c478bd9Sstevel@tonic-gate 		if (pmaxindex < BIGINDEX)
4507c478bd9Sstevel@tonic-gate 			pp->p_index = ++pmaxindex;
4517c478bd9Sstevel@tonic-gate 		else {
4527c478bd9Sstevel@tonic-gate 			struct process *np;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 			for (i = 1; ; i++) {
4557c478bd9Sstevel@tonic-gate 				for (np = proclist.p_next; np; np = np->p_next)
4567c478bd9Sstevel@tonic-gate 					if (np->p_index == i)
4577c478bd9Sstevel@tonic-gate 						goto tryagain;
4587c478bd9Sstevel@tonic-gate 				pp->p_index = i;
4597c478bd9Sstevel@tonic-gate 				if (i > pmaxindex)
4607c478bd9Sstevel@tonic-gate 					pmaxindex = i;
4617c478bd9Sstevel@tonic-gate 				break;
4627c478bd9Sstevel@tonic-gate 			tryagain:;
4637c478bd9Sstevel@tonic-gate 			}
4647c478bd9Sstevel@tonic-gate 		}
4657c478bd9Sstevel@tonic-gate 		pprevious = pcurrent;
4667c478bd9Sstevel@tonic-gate 		pcurrent = pp;
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 	pp->p_next = proclist.p_next;
4697c478bd9Sstevel@tonic-gate 	proclist.p_next = pp;
4707c478bd9Sstevel@tonic-gate 	(void) gettimeofday(&pp->p_btime, (struct timezone *)0);
4717c478bd9Sstevel@tonic-gate }
4727c478bd9Sstevel@tonic-gate 
473*6c02b4a4Smuffin void
474*6c02b4a4Smuffin padd(struct command *t)
4757c478bd9Sstevel@tonic-gate {
4767c478bd9Sstevel@tonic-gate 	tchar **argp;
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate #ifdef TRACE
4797c478bd9Sstevel@tonic-gate 	tprintf("TRACE- padd()\n");
4807c478bd9Sstevel@tonic-gate #endif
4817c478bd9Sstevel@tonic-gate 	if (t == 0)
4827c478bd9Sstevel@tonic-gate 		return;
4837c478bd9Sstevel@tonic-gate 	switch (t->t_dtyp) {
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	case TPAR:
4867c478bd9Sstevel@tonic-gate 		pads(S_LBRASP /*"( "*/);
4877c478bd9Sstevel@tonic-gate 		padd(t->t_dspr);
4887c478bd9Sstevel@tonic-gate 		pads(S_SPRBRA /*" )"*/);
4897c478bd9Sstevel@tonic-gate 		break;
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	case TCOM:
4927c478bd9Sstevel@tonic-gate 		for (argp = t->t_dcom; *argp; argp++) {
4937c478bd9Sstevel@tonic-gate 			pads(*argp);
4947c478bd9Sstevel@tonic-gate 			if (argp[1])
4957c478bd9Sstevel@tonic-gate 				pads(S_SP /*" "*/);
4967c478bd9Sstevel@tonic-gate 		}
4977c478bd9Sstevel@tonic-gate 		break;
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	case TOR:
5007c478bd9Sstevel@tonic-gate 	case TAND:
5017c478bd9Sstevel@tonic-gate 	case TFIL:
5027c478bd9Sstevel@tonic-gate 	case TLST:
5037c478bd9Sstevel@tonic-gate 		padd(t->t_dcar);
5047c478bd9Sstevel@tonic-gate 		switch (t->t_dtyp) {
5057c478bd9Sstevel@tonic-gate 		case TOR:
5067c478bd9Sstevel@tonic-gate 			pads(S_SPBARBARSP /*" || " */);
5077c478bd9Sstevel@tonic-gate 			break;
5087c478bd9Sstevel@tonic-gate 		case TAND:
5097c478bd9Sstevel@tonic-gate 			pads(S_SPANDANDSP /*" && "*/);
5107c478bd9Sstevel@tonic-gate 			break;
5117c478bd9Sstevel@tonic-gate 		case TFIL:
5127c478bd9Sstevel@tonic-gate 			pads(S_SPBARSP /*" | "*/);
5137c478bd9Sstevel@tonic-gate 			break;
5147c478bd9Sstevel@tonic-gate 		case TLST:
5157c478bd9Sstevel@tonic-gate 			pads(S_SEMICOLONSP /*"; "*/);
5167c478bd9Sstevel@tonic-gate 			break;
5177c478bd9Sstevel@tonic-gate 		}
5187c478bd9Sstevel@tonic-gate 		padd(t->t_dcdr);
5197c478bd9Sstevel@tonic-gate 		return;
5207c478bd9Sstevel@tonic-gate 	}
5217c478bd9Sstevel@tonic-gate 	if ((t->t_dflg & FPIN) == 0 && t->t_dlef) {
5227c478bd9Sstevel@tonic-gate 		pads((t->t_dflg & FHERE) ? S_SPLESLESSP /*" << " */ : S_SPLESSP /*" < "*/);
5237c478bd9Sstevel@tonic-gate 		pads(t->t_dlef);
5247c478bd9Sstevel@tonic-gate 	}
5257c478bd9Sstevel@tonic-gate 	if ((t->t_dflg & FPOU) == 0 && t->t_drit) {
5267c478bd9Sstevel@tonic-gate 		pads((t->t_dflg & FCAT) ? S_SPGTRGTRSP /*" >>" */ : S_SPGTR /*" >"*/);
5277c478bd9Sstevel@tonic-gate 		if (t->t_dflg & FDIAG)
5287c478bd9Sstevel@tonic-gate 			pads(S_AND /*"&"*/);
5297c478bd9Sstevel@tonic-gate 		pads(S_SP /*" "*/);
5307c478bd9Sstevel@tonic-gate 		pads(t->t_drit);
5317c478bd9Sstevel@tonic-gate 	}
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate 
534*6c02b4a4Smuffin void
535*6c02b4a4Smuffin pads(tchar *cp)
5367c478bd9Sstevel@tonic-gate {
537*6c02b4a4Smuffin 	int i = strlen_(cp);
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate #ifdef TRACE
5407c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pads()\n");
5417c478bd9Sstevel@tonic-gate #endif
5427c478bd9Sstevel@tonic-gate 	if (cmdlen >= PMAXLEN)
5437c478bd9Sstevel@tonic-gate 		return;
5447c478bd9Sstevel@tonic-gate 	if (cmdlen + i >= PMAXLEN) {
5457c478bd9Sstevel@tonic-gate 		(void) strcpy_(cmdp, S_SPPPP /*" ..."*/);
5467c478bd9Sstevel@tonic-gate 		cmdlen = PMAXLEN;
5477c478bd9Sstevel@tonic-gate 		cmdp += 4;
5487c478bd9Sstevel@tonic-gate 		return;
5497c478bd9Sstevel@tonic-gate 	}
5507c478bd9Sstevel@tonic-gate 	(void) strcpy_(cmdp, cp);
5517c478bd9Sstevel@tonic-gate 	cmdp += i;
5527c478bd9Sstevel@tonic-gate 	cmdlen += i;
5537c478bd9Sstevel@tonic-gate }
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate /*
5567c478bd9Sstevel@tonic-gate  * psavejob - temporarily save the current job on a one level stack
5577c478bd9Sstevel@tonic-gate  *	so another job can be created.  Used for { } in exp6
5587c478bd9Sstevel@tonic-gate  *	and `` in globbing.
5597c478bd9Sstevel@tonic-gate  */
560*6c02b4a4Smuffin void
561*6c02b4a4Smuffin psavejob(void)
5627c478bd9Sstevel@tonic-gate {
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate #ifdef TRACE
5657c478bd9Sstevel@tonic-gate 	tprintf("TRACE- psavejob()\n");
5667c478bd9Sstevel@tonic-gate #endif
5677c478bd9Sstevel@tonic-gate 	pholdjob = pcurrjob;
5687c478bd9Sstevel@tonic-gate 	pcurrjob = PNULL;
5697c478bd9Sstevel@tonic-gate }
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate /*
5727c478bd9Sstevel@tonic-gate  * prestjob - opposite of psavejob.  This may be missed if we are interrupted
5737c478bd9Sstevel@tonic-gate  *	somewhere, but pendjob cleans up anyway.
5747c478bd9Sstevel@tonic-gate  */
575*6c02b4a4Smuffin void
576*6c02b4a4Smuffin prestjob(void)
5777c478bd9Sstevel@tonic-gate {
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate #ifdef TRACE
5807c478bd9Sstevel@tonic-gate 	tprintf("TRACE- prestjob()\n");
5817c478bd9Sstevel@tonic-gate #endif
5827c478bd9Sstevel@tonic-gate 	pcurrjob = pholdjob;
5837c478bd9Sstevel@tonic-gate 	pholdjob = PNULL;
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate /*
5877c478bd9Sstevel@tonic-gate  * pendjob - indicate that a job (set of commands) has been completed
5887c478bd9Sstevel@tonic-gate  *	or is about to begin.
5897c478bd9Sstevel@tonic-gate  */
590*6c02b4a4Smuffin void
591*6c02b4a4Smuffin pendjob(void)
5927c478bd9Sstevel@tonic-gate {
593*6c02b4a4Smuffin 	struct process *pp, *tp;
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate #ifdef TRACE
5967c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pendjob()\n");
5977c478bd9Sstevel@tonic-gate #endif
5987c478bd9Sstevel@tonic-gate 	if (pcurrjob && (pcurrjob->p_flags&(PFOREGND|PSTOPPED)) == 0) {
5997c478bd9Sstevel@tonic-gate 		pp = pcurrjob;
6007c478bd9Sstevel@tonic-gate 		while (pp->p_pid != pp->p_jobid)
6017c478bd9Sstevel@tonic-gate 			pp = pp->p_friends;
6027c478bd9Sstevel@tonic-gate 		printf("[%d]", pp->p_index);
6037c478bd9Sstevel@tonic-gate 		tp = pp;
6047c478bd9Sstevel@tonic-gate 		do {
6057c478bd9Sstevel@tonic-gate 			printf(" %d", pp->p_pid);
6067c478bd9Sstevel@tonic-gate 			pp = pp->p_friends;
6077c478bd9Sstevel@tonic-gate 		} while (pp != tp);
6087c478bd9Sstevel@tonic-gate 		printf("\n");
6097c478bd9Sstevel@tonic-gate 	}
6107c478bd9Sstevel@tonic-gate 	pholdjob = pcurrjob = 0;
6117c478bd9Sstevel@tonic-gate }
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate /*
6147c478bd9Sstevel@tonic-gate  * pprint - print a job
6157c478bd9Sstevel@tonic-gate  */
616*6c02b4a4Smuffin int
617*6c02b4a4Smuffin pprint(struct process *pp, int flag)
6187c478bd9Sstevel@tonic-gate {
619*6c02b4a4Smuffin 	int status, reason;
6207c478bd9Sstevel@tonic-gate 	struct process *tp;
6217c478bd9Sstevel@tonic-gate 	extern char *linp, linbuf[];
6227c478bd9Sstevel@tonic-gate 	int jobflags, pstatus;
6237c478bd9Sstevel@tonic-gate 	char *format;
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate #ifdef TRACE
6267c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pprint()\n");
6277c478bd9Sstevel@tonic-gate #endif
6287c478bd9Sstevel@tonic-gate 	while (pp->p_pid != pp->p_jobid)
6297c478bd9Sstevel@tonic-gate 		pp = pp->p_friends;
6307c478bd9Sstevel@tonic-gate 	if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
6317c478bd9Sstevel@tonic-gate 		pp->p_flags &= ~PPTIME;
6327c478bd9Sstevel@tonic-gate 		pp->p_flags |= PTIME;
6337c478bd9Sstevel@tonic-gate 	}
6347c478bd9Sstevel@tonic-gate 	tp = pp;
6357c478bd9Sstevel@tonic-gate 	status = reason = -1;
6367c478bd9Sstevel@tonic-gate 	jobflags = 0;
6377c478bd9Sstevel@tonic-gate 	do {
6387c478bd9Sstevel@tonic-gate 		jobflags |= pp->p_flags;
6397c478bd9Sstevel@tonic-gate 		pstatus = pp->p_flags & PALLSTATES;
6407c478bd9Sstevel@tonic-gate 		if (tp != pp && linp != linbuf && !(flag&FANCY) &&
6417c478bd9Sstevel@tonic-gate 		    (pstatus == status && pp->p_reason == reason ||
6427c478bd9Sstevel@tonic-gate 		     !(flag&REASON)))
6437c478bd9Sstevel@tonic-gate 			printf(" ");
6447c478bd9Sstevel@tonic-gate 		else {
6457c478bd9Sstevel@tonic-gate 			if (tp != pp && linp != linbuf)
6467c478bd9Sstevel@tonic-gate 				printf("\n");
6477c478bd9Sstevel@tonic-gate 			if(flag&NUMBER)
6487c478bd9Sstevel@tonic-gate 				if (pp == tp)
6497c478bd9Sstevel@tonic-gate 					printf("[%d]%s %c ", pp->p_index,
6507c478bd9Sstevel@tonic-gate 					    pp->p_index < 10 ? " " : "",
6517c478bd9Sstevel@tonic-gate 					    pp==pcurrent ? '+' :
6527c478bd9Sstevel@tonic-gate 						(pp == pprevious ? (tchar) '-'
6537c478bd9Sstevel@tonic-gate 							: (tchar) ' '));
6547c478bd9Sstevel@tonic-gate 				else
6557c478bd9Sstevel@tonic-gate 					printf("       ");
6567c478bd9Sstevel@tonic-gate 			if (flag&FANCY)
6577c478bd9Sstevel@tonic-gate 				printf("%5d ", pp->p_pid);
6587c478bd9Sstevel@tonic-gate 			if (flag&(REASON|AREASON)) {
6597c478bd9Sstevel@tonic-gate 				if (flag&NAME)
6607c478bd9Sstevel@tonic-gate 					format = "%-21s";
6617c478bd9Sstevel@tonic-gate 				else
6627c478bd9Sstevel@tonic-gate 					format = "%s";
6637c478bd9Sstevel@tonic-gate 				if (pstatus == status)
6647c478bd9Sstevel@tonic-gate 					if (pp->p_reason == reason) {
6657c478bd9Sstevel@tonic-gate 						printf(format, "");
6667c478bd9Sstevel@tonic-gate 						goto prcomd;
6677c478bd9Sstevel@tonic-gate 					} else
6687c478bd9Sstevel@tonic-gate 						reason = pp->p_reason;
6697c478bd9Sstevel@tonic-gate 				else {
6707c478bd9Sstevel@tonic-gate 					status = pstatus;
6717c478bd9Sstevel@tonic-gate 					reason = pp->p_reason;
6727c478bd9Sstevel@tonic-gate 				}
6737c478bd9Sstevel@tonic-gate 				switch (status) {
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 				case PRUNNING:
6767c478bd9Sstevel@tonic-gate 					printf(format, "Running ");
6777c478bd9Sstevel@tonic-gate 					break;
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 				case PINTERRUPTED:
6807c478bd9Sstevel@tonic-gate 				case PSTOPPED:
6817c478bd9Sstevel@tonic-gate 				case PSIGNALED:
6827c478bd9Sstevel@tonic-gate 					if ((flag&(REASON|AREASON))
6837c478bd9Sstevel@tonic-gate 					    && reason != SIGINT
6847c478bd9Sstevel@tonic-gate 					    && reason != SIGPIPE)
6857c478bd9Sstevel@tonic-gate 						printf(format,
6867c478bd9Sstevel@tonic-gate 						    strsignal(pp->p_reason));
6877c478bd9Sstevel@tonic-gate 					break;
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 				case PNEXITED:
6907c478bd9Sstevel@tonic-gate 				case PAEXITED:
6917c478bd9Sstevel@tonic-gate 					if (flag & REASON)
6927c478bd9Sstevel@tonic-gate 						if (pp->p_reason)
6937c478bd9Sstevel@tonic-gate 							printf("Exit %-16d", pp->p_reason);
6947c478bd9Sstevel@tonic-gate 						else
6957c478bd9Sstevel@tonic-gate 							printf(format, "Done");
6967c478bd9Sstevel@tonic-gate 					break;
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 				default:
6997c478bd9Sstevel@tonic-gate 					printf("BUG: status=%-9o", status);
7007c478bd9Sstevel@tonic-gate 				}
7017c478bd9Sstevel@tonic-gate 			}
7027c478bd9Sstevel@tonic-gate 		}
7037c478bd9Sstevel@tonic-gate prcomd:
7047c478bd9Sstevel@tonic-gate 		if (flag&NAME) {
7057c478bd9Sstevel@tonic-gate 			printf("%t", pp->p_command);
7067c478bd9Sstevel@tonic-gate 			if (pp->p_flags & PPOU)
7077c478bd9Sstevel@tonic-gate 				printf(" |");
7087c478bd9Sstevel@tonic-gate 			if (pp->p_flags & PDIAG)
7097c478bd9Sstevel@tonic-gate 				printf("&");
7107c478bd9Sstevel@tonic-gate 		}
7117c478bd9Sstevel@tonic-gate 		if (flag&(REASON|AREASON) && pp->p_flags&PDUMPED)
7127c478bd9Sstevel@tonic-gate 			printf(" (core dumped)");
7137c478bd9Sstevel@tonic-gate 		if (tp == pp->p_friends) {
7147c478bd9Sstevel@tonic-gate 			if (flag&AMPERSAND)
7157c478bd9Sstevel@tonic-gate 				printf(" &");
7167c478bd9Sstevel@tonic-gate 			if (flag&JOBDIR &&
7177c478bd9Sstevel@tonic-gate 			    !eq(tp->p_cwd->di_name, dcwd->di_name)) {
7187c478bd9Sstevel@tonic-gate 				printf(" (wd: ");
7197c478bd9Sstevel@tonic-gate 				dtildepr(value(S_home /*"home"*/), tp->p_cwd->di_name);
7207c478bd9Sstevel@tonic-gate 				printf(")");
7217c478bd9Sstevel@tonic-gate 			}
7227c478bd9Sstevel@tonic-gate 		}
7237c478bd9Sstevel@tonic-gate 		if (pp->p_flags&PPTIME && !(status&(PSTOPPED|PRUNNING))) {
7247c478bd9Sstevel@tonic-gate 			if (linp != linbuf)
7257c478bd9Sstevel@tonic-gate 				printf("\n\t");
7267c478bd9Sstevel@tonic-gate 			{ static struct rusage zru;
7277c478bd9Sstevel@tonic-gate 			  prusage(&zru, &pp->p_rusage, &pp->p_etime,
7287c478bd9Sstevel@tonic-gate 			    &pp->p_btime);
7297c478bd9Sstevel@tonic-gate 			}
7307c478bd9Sstevel@tonic-gate 		}
7317c478bd9Sstevel@tonic-gate 		if (tp == pp->p_friends) {
7327c478bd9Sstevel@tonic-gate 			if (linp != linbuf)
7337c478bd9Sstevel@tonic-gate 				printf("\n");
7347c478bd9Sstevel@tonic-gate 			if (flag&SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
7357c478bd9Sstevel@tonic-gate 				printf("(wd now: ");
7367c478bd9Sstevel@tonic-gate 				dtildepr(value(S_home /* "home" */), dcwd->di_name);
7377c478bd9Sstevel@tonic-gate 				printf(")\n");
7387c478bd9Sstevel@tonic-gate 			}
7397c478bd9Sstevel@tonic-gate 		}
7407c478bd9Sstevel@tonic-gate 	} while ((pp = pp->p_friends) != tp);
7417c478bd9Sstevel@tonic-gate 	if (jobflags&PTIME && (jobflags&(PSTOPPED|PRUNNING)) == 0) {
7427c478bd9Sstevel@tonic-gate 		if (jobflags & NUMBER)
7437c478bd9Sstevel@tonic-gate 			printf("       ");
7447c478bd9Sstevel@tonic-gate 		ptprint(tp);
7457c478bd9Sstevel@tonic-gate 	}
7467c478bd9Sstevel@tonic-gate 	return (jobflags);
7477c478bd9Sstevel@tonic-gate }
7487c478bd9Sstevel@tonic-gate 
749*6c02b4a4Smuffin void
750*6c02b4a4Smuffin ptprint(struct process *tp)
7517c478bd9Sstevel@tonic-gate {
7527c478bd9Sstevel@tonic-gate 	struct timeval tetime, diff;
7537c478bd9Sstevel@tonic-gate 	static struct timeval ztime;
7547c478bd9Sstevel@tonic-gate 	struct rusage ru;
7557c478bd9Sstevel@tonic-gate 	static struct rusage zru;
756*6c02b4a4Smuffin 	struct process *pp = tp;
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate #ifdef TRACE
7597c478bd9Sstevel@tonic-gate 	tprintf("TRACE- ptprint()\n");
7607c478bd9Sstevel@tonic-gate #endif
7617c478bd9Sstevel@tonic-gate 	ru = zru;
7627c478bd9Sstevel@tonic-gate 	tetime = ztime;
7637c478bd9Sstevel@tonic-gate 	do {
7647c478bd9Sstevel@tonic-gate 		ruadd(&ru, &pp->p_rusage);
7657c478bd9Sstevel@tonic-gate 		tvsub(&diff, &pp->p_etime, &pp->p_btime);
7667c478bd9Sstevel@tonic-gate 		if (timercmp(&diff, &tetime, >))
7677c478bd9Sstevel@tonic-gate 			tetime = diff;
7687c478bd9Sstevel@tonic-gate 	} while ((pp = pp->p_friends) != tp);
7697c478bd9Sstevel@tonic-gate 	prusage(&zru, &ru, &tetime, &ztime);
7707c478bd9Sstevel@tonic-gate }
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate /*
7737c478bd9Sstevel@tonic-gate  * dojobs - print all jobs
7747c478bd9Sstevel@tonic-gate  */
775*6c02b4a4Smuffin void
776*6c02b4a4Smuffin dojobs(tchar **v)
7777c478bd9Sstevel@tonic-gate {
778*6c02b4a4Smuffin 	struct process *pp;
779*6c02b4a4Smuffin 	int flag = NUMBER|NAME|REASON;
7807c478bd9Sstevel@tonic-gate 	int i;
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate #ifdef TRACE
7837c478bd9Sstevel@tonic-gate 	tprintf("TRACE- dojobs()\n");
7847c478bd9Sstevel@tonic-gate #endif
7857c478bd9Sstevel@tonic-gate 	if (chkstop)
7867c478bd9Sstevel@tonic-gate 		chkstop = 2;
7877c478bd9Sstevel@tonic-gate 	if (*++v) {
7887c478bd9Sstevel@tonic-gate 		if (v[1] || !eq(*v, S_DASHl /*"-l"*/))
7897c478bd9Sstevel@tonic-gate 			error("Usage: jobs [ -l ]");
7907c478bd9Sstevel@tonic-gate 		flag |= FANCY|JOBDIR;
7917c478bd9Sstevel@tonic-gate 	}
7927c478bd9Sstevel@tonic-gate 	for (i = 1; i <= pmaxindex; i++)
7937c478bd9Sstevel@tonic-gate 		for (pp = proclist.p_next; pp; pp = pp->p_next)
7947c478bd9Sstevel@tonic-gate 			if (pp->p_index == i && pp->p_pid == pp->p_jobid) {
7957c478bd9Sstevel@tonic-gate 				pp->p_flags &= ~PNEEDNOTE;
7967c478bd9Sstevel@tonic-gate 				if (!(pprint(pp, flag) & (PRUNNING|PSTOPPED)))
7977c478bd9Sstevel@tonic-gate 					pflush(pp);
7987c478bd9Sstevel@tonic-gate 				break;
7997c478bd9Sstevel@tonic-gate 			}
8007c478bd9Sstevel@tonic-gate }
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate /*
8037c478bd9Sstevel@tonic-gate  * dofg - builtin - put the job into the foreground
8047c478bd9Sstevel@tonic-gate  */
805*6c02b4a4Smuffin void
806*6c02b4a4Smuffin dofg(tchar **v)
8077c478bd9Sstevel@tonic-gate {
808*6c02b4a4Smuffin 	struct process *pp;
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate #ifdef TRACE
8117c478bd9Sstevel@tonic-gate 	tprintf("TRACE- dofg()\n");
8127c478bd9Sstevel@tonic-gate #endif
8137c478bd9Sstevel@tonic-gate 	okpcntl();
8147c478bd9Sstevel@tonic-gate 	++v;
8157c478bd9Sstevel@tonic-gate 	do {
8167c478bd9Sstevel@tonic-gate 		pp = pfind(*v);
8177c478bd9Sstevel@tonic-gate 		pstart(pp, 1);
8187c478bd9Sstevel@tonic-gate 		pjwait(pp);
8197c478bd9Sstevel@tonic-gate 	} while (*v && *++v);
8207c478bd9Sstevel@tonic-gate }
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate /*
8237c478bd9Sstevel@tonic-gate  * %... - builtin - put the job into the foreground
8247c478bd9Sstevel@tonic-gate  */
825*6c02b4a4Smuffin void
826*6c02b4a4Smuffin dofg1(tchar **v)
8277c478bd9Sstevel@tonic-gate {
828*6c02b4a4Smuffin 	struct process *pp;
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate #ifdef TRACE
8317c478bd9Sstevel@tonic-gate 	tprintf("TRACE- untty()\n");
8327c478bd9Sstevel@tonic-gate #endif
8337c478bd9Sstevel@tonic-gate 	okpcntl();
8347c478bd9Sstevel@tonic-gate 	pp = pfind(v[0]);
8357c478bd9Sstevel@tonic-gate 	pstart(pp, 1);
8367c478bd9Sstevel@tonic-gate 	pjwait(pp);
8377c478bd9Sstevel@tonic-gate }
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate /*
8407c478bd9Sstevel@tonic-gate  * dobg - builtin - put the job into the background
8417c478bd9Sstevel@tonic-gate  */
842*6c02b4a4Smuffin void
843*6c02b4a4Smuffin dobg(tchar **v)
8447c478bd9Sstevel@tonic-gate {
845*6c02b4a4Smuffin 	struct process *pp;
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate #ifdef TRACE
8487c478bd9Sstevel@tonic-gate 	tprintf("TRACE- dobg()\n");
8497c478bd9Sstevel@tonic-gate #endif
8507c478bd9Sstevel@tonic-gate 	okpcntl();
8517c478bd9Sstevel@tonic-gate 	++v;
8527c478bd9Sstevel@tonic-gate 	do {
8537c478bd9Sstevel@tonic-gate 		pp = pfind(*v);
8547c478bd9Sstevel@tonic-gate 		pstart(pp, 0);
8557c478bd9Sstevel@tonic-gate 	} while (*v && *++v);
8567c478bd9Sstevel@tonic-gate }
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate /*
8597c478bd9Sstevel@tonic-gate  * %... & - builtin - put the job into the background
8607c478bd9Sstevel@tonic-gate  */
861*6c02b4a4Smuffin void
862*6c02b4a4Smuffin dobg1(tchar **v)
8637c478bd9Sstevel@tonic-gate {
864*6c02b4a4Smuffin 	struct process *pp;
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate #ifdef TRACE
8677c478bd9Sstevel@tonic-gate 	tprintf("TRACE- dobg1()\n");
8687c478bd9Sstevel@tonic-gate #endif
8697c478bd9Sstevel@tonic-gate 	pp = pfind(v[0]);
8707c478bd9Sstevel@tonic-gate 	pstart(pp, 0);
8717c478bd9Sstevel@tonic-gate }
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate /*
8747c478bd9Sstevel@tonic-gate  * dostop - builtin - stop the job
8757c478bd9Sstevel@tonic-gate  */
876*6c02b4a4Smuffin void
877*6c02b4a4Smuffin dostop(tchar **v)
8787c478bd9Sstevel@tonic-gate {
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate #ifdef TRACE
8817c478bd9Sstevel@tonic-gate 	tprintf("TRACE- dostop()\n");
8827c478bd9Sstevel@tonic-gate #endif
8837c478bd9Sstevel@tonic-gate 	pkill(++v, SIGSTOP);
8847c478bd9Sstevel@tonic-gate }
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate /*
8877c478bd9Sstevel@tonic-gate  * dokill - builtin - superset of kill (1)
8887c478bd9Sstevel@tonic-gate  */
889*6c02b4a4Smuffin void
890*6c02b4a4Smuffin dokill(tchar **v)
8917c478bd9Sstevel@tonic-gate {
892*6c02b4a4Smuffin 	int signum;
893*6c02b4a4Smuffin 	tchar *name;
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate #ifdef TRACE
8967c478bd9Sstevel@tonic-gate 	tprintf("TRACE- dokill()\n");
8977c478bd9Sstevel@tonic-gate #endif
8987c478bd9Sstevel@tonic-gate 	v++;
8997c478bd9Sstevel@tonic-gate 	if (v[0] && v[0][0] == '-') {
9007c478bd9Sstevel@tonic-gate 		if (v[0][1] == 'l') {
9017c478bd9Sstevel@tonic-gate 			for (signum = 1; signum <= NSIG-1; signum++) {
9027c478bd9Sstevel@tonic-gate 				char	sbuf[BUFSIZ];
9037c478bd9Sstevel@tonic-gate 				if (sig2str(signum, sbuf) == 0)
9047c478bd9Sstevel@tonic-gate 					printf("%s ", sbuf);
9057c478bd9Sstevel@tonic-gate 				if (signum % 8 == 0)
9067c478bd9Sstevel@tonic-gate 					Putchar('\n');
9077c478bd9Sstevel@tonic-gate 			}
9087c478bd9Sstevel@tonic-gate 			Putchar('\n');
9097c478bd9Sstevel@tonic-gate 			return;
9107c478bd9Sstevel@tonic-gate 		}
9117c478bd9Sstevel@tonic-gate 		if (digit(v[0][1])) {
9127c478bd9Sstevel@tonic-gate 			signum = atoi_(v[0]+1);
9137c478bd9Sstevel@tonic-gate 			if (signum < 0 || signum > NSIG)
9147c478bd9Sstevel@tonic-gate 				bferr("Bad signal number");
9157c478bd9Sstevel@tonic-gate 		} else {
9167c478bd9Sstevel@tonic-gate 			int	signo;
9177c478bd9Sstevel@tonic-gate 			char	sbuf[BUFSIZ];
9187c478bd9Sstevel@tonic-gate 			name = &v[0][1];
9197c478bd9Sstevel@tonic-gate 			tstostr(sbuf, name);
9207c478bd9Sstevel@tonic-gate 			if (str2sig(sbuf, &signo) == 0) {
9217c478bd9Sstevel@tonic-gate 				signum = signo;
9227c478bd9Sstevel@tonic-gate 				goto gotsig;
9237c478bd9Sstevel@tonic-gate 			}
9247c478bd9Sstevel@tonic-gate 			if (eq(name, S_IOT /*"IOT"*/)) {
9257c478bd9Sstevel@tonic-gate 				signum = SIGABRT;
9267c478bd9Sstevel@tonic-gate 				goto gotsig;
9277c478bd9Sstevel@tonic-gate 			}
9287c478bd9Sstevel@tonic-gate 			setname(name);
9297c478bd9Sstevel@tonic-gate 			bferr("Unknown signal; kill -l lists signals");
9307c478bd9Sstevel@tonic-gate 		}
9317c478bd9Sstevel@tonic-gate gotsig:
9327c478bd9Sstevel@tonic-gate 		v++;
9337c478bd9Sstevel@tonic-gate 	} else
9347c478bd9Sstevel@tonic-gate 		signum = SIGTERM;
9357c478bd9Sstevel@tonic-gate 	pkill(v, signum);
9367c478bd9Sstevel@tonic-gate }
9377c478bd9Sstevel@tonic-gate 
938*6c02b4a4Smuffin void
939*6c02b4a4Smuffin pkill(tchar **v, int signum)
9407c478bd9Sstevel@tonic-gate {
941*6c02b4a4Smuffin 	struct process *pp, *np;
942*6c02b4a4Smuffin 	int jobflags = 0;
9437c478bd9Sstevel@tonic-gate 	int omask, pid, err = 0;
9447c478bd9Sstevel@tonic-gate 	tchar *cp;
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate #ifdef TRACE
9477c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pkill()\n");
9487c478bd9Sstevel@tonic-gate #endif
9497c478bd9Sstevel@tonic-gate 	omask = sigmask(SIGCHLD);
9507c478bd9Sstevel@tonic-gate 	if (setintr)
9517c478bd9Sstevel@tonic-gate 		omask |= sigmask(SIGINT);
9527c478bd9Sstevel@tonic-gate 	omask = sigblock(omask) & ~omask;
9537c478bd9Sstevel@tonic-gate 	while (*v) {
9547c478bd9Sstevel@tonic-gate 		cp = globone(*v);
9557c478bd9Sstevel@tonic-gate 		if (*cp == '%') {
9567c478bd9Sstevel@tonic-gate 			np = pp = pfind(cp);
9577c478bd9Sstevel@tonic-gate 			do
9587c478bd9Sstevel@tonic-gate 				jobflags |= np->p_flags;
9597c478bd9Sstevel@tonic-gate 			while ((np = np->p_friends) != pp);
9607c478bd9Sstevel@tonic-gate 			switch (signum) {
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 			case SIGSTOP:
9637c478bd9Sstevel@tonic-gate 			case SIGTSTP:
9647c478bd9Sstevel@tonic-gate 			case SIGTTIN:
9657c478bd9Sstevel@tonic-gate 			case SIGTTOU:
9667c478bd9Sstevel@tonic-gate 				if ((jobflags & PRUNNING) == 0) {
9677c478bd9Sstevel@tonic-gate 					/* %s -> %t */
9687c478bd9Sstevel@tonic-gate 					printf("%t: Already stopped\n", cp);
9697c478bd9Sstevel@tonic-gate 					err++;
9707c478bd9Sstevel@tonic-gate 					goto cont;
9717c478bd9Sstevel@tonic-gate 				}
9727c478bd9Sstevel@tonic-gate 			}
9737c478bd9Sstevel@tonic-gate 			if (killpg(pp->p_jobid, signum) < 0) {
9747c478bd9Sstevel@tonic-gate 				/* %s -> %t */
9757c478bd9Sstevel@tonic-gate 				printf("%t: ", cp);
9767c478bd9Sstevel@tonic-gate 				printf("%s\n", strerror(errno));
9777c478bd9Sstevel@tonic-gate 				err++;
9787c478bd9Sstevel@tonic-gate 			}
9797c478bd9Sstevel@tonic-gate 			if (signum == SIGTERM || signum == SIGHUP)
9807c478bd9Sstevel@tonic-gate 				(void) killpg(pp->p_jobid, SIGCONT);
9817c478bd9Sstevel@tonic-gate 		} else if (!(digit(*cp) || *cp == '-'))
9827c478bd9Sstevel@tonic-gate 			bferr("Arguments should be jobs or process id's");
9837c478bd9Sstevel@tonic-gate 		else {
9847c478bd9Sstevel@tonic-gate 			pid = atoi_(cp);
9857c478bd9Sstevel@tonic-gate 			if (kill(pid, signum) < 0) {
9867c478bd9Sstevel@tonic-gate 				printf("%d: ", pid);
9877c478bd9Sstevel@tonic-gate 				printf("%s\n", strerror(errno));
9887c478bd9Sstevel@tonic-gate 				err++;
9897c478bd9Sstevel@tonic-gate 				goto cont;
9907c478bd9Sstevel@tonic-gate 			}
9917c478bd9Sstevel@tonic-gate 			if (signum == SIGTERM || signum == SIGHUP)
9927c478bd9Sstevel@tonic-gate 				(void) kill(pid, SIGCONT);
9937c478bd9Sstevel@tonic-gate 		}
9947c478bd9Sstevel@tonic-gate cont:
9957c478bd9Sstevel@tonic-gate 		xfree(cp);
9967c478bd9Sstevel@tonic-gate 		v++;
9977c478bd9Sstevel@tonic-gate 	}
9987c478bd9Sstevel@tonic-gate 	(void) sigsetmask(omask);
9997c478bd9Sstevel@tonic-gate 	if (err)
10007c478bd9Sstevel@tonic-gate 		error(NULL);
10017c478bd9Sstevel@tonic-gate }
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate /*
10047c478bd9Sstevel@tonic-gate  * pstart - start the job in foreground/background
10057c478bd9Sstevel@tonic-gate  */
1006*6c02b4a4Smuffin void
1007*6c02b4a4Smuffin pstart(struct process *pp, int foregnd)
10087c478bd9Sstevel@tonic-gate {
1009*6c02b4a4Smuffin 	struct process *np;
10107c478bd9Sstevel@tonic-gate 	int omask, jobflags = 0;
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate #ifdef TRACE
10137c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pstart()\n");
10147c478bd9Sstevel@tonic-gate #endif
10157c478bd9Sstevel@tonic-gate 	omask = sigblock(sigmask(SIGCHLD));
10167c478bd9Sstevel@tonic-gate 	np = pp;
10177c478bd9Sstevel@tonic-gate 	do {
10187c478bd9Sstevel@tonic-gate 		jobflags |= np->p_flags;
10197c478bd9Sstevel@tonic-gate 		if (np->p_flags&(PRUNNING|PSTOPPED)) {
10207c478bd9Sstevel@tonic-gate 			np->p_flags |= PRUNNING;
10217c478bd9Sstevel@tonic-gate 			np->p_flags &= ~PSTOPPED;
10227c478bd9Sstevel@tonic-gate 			if (foregnd)
10237c478bd9Sstevel@tonic-gate 				np->p_flags |= PFOREGND;
10247c478bd9Sstevel@tonic-gate 			else
10257c478bd9Sstevel@tonic-gate 				np->p_flags &= ~PFOREGND;
10267c478bd9Sstevel@tonic-gate 		}
10277c478bd9Sstevel@tonic-gate 	} while((np = np->p_friends) != pp);
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	if (foregnd)
10307c478bd9Sstevel@tonic-gate 		pclrcurr(pp);
10317c478bd9Sstevel@tonic-gate 	else
10327c478bd9Sstevel@tonic-gate 	{
10337c478bd9Sstevel@tonic-gate 		if ( pprevious && (pprevious->p_flags & PSTOPPED) )
10347c478bd9Sstevel@tonic-gate 		{
10357c478bd9Sstevel@tonic-gate 			pcurrent = pprevious;
10367c478bd9Sstevel@tonic-gate 			pprevious = pgetcurr(PNULL);
10377c478bd9Sstevel@tonic-gate 		}
10387c478bd9Sstevel@tonic-gate 		else
10397c478bd9Sstevel@tonic-gate 		{
10407c478bd9Sstevel@tonic-gate 			pcurrent = pgetcurr(pp);
10417c478bd9Sstevel@tonic-gate 			if ( !pcurrent || (pcurrent->p_flags & PRUNNING) )
10427c478bd9Sstevel@tonic-gate 				pcurrent = pp;
10437c478bd9Sstevel@tonic-gate 			else
10447c478bd9Sstevel@tonic-gate 				pprevious = pp;
10457c478bd9Sstevel@tonic-gate 		}
10467c478bd9Sstevel@tonic-gate 	}
10477c478bd9Sstevel@tonic-gate 	(void) pprint(pp, foregnd ? NAME|JOBDIR : NUMBER|NAME|AMPERSAND);
10487c478bd9Sstevel@tonic-gate 	if (foregnd)
10497c478bd9Sstevel@tonic-gate 		(void) ioctl(FSHTTY, TIOCSPGRP,  (char *)&pp->p_jobid);
10507c478bd9Sstevel@tonic-gate 	if (jobflags&PSTOPPED)
10517c478bd9Sstevel@tonic-gate 		(void) killpg(pp->p_jobid, SIGCONT);
10527c478bd9Sstevel@tonic-gate 	(void) sigsetmask(omask);
10537c478bd9Sstevel@tonic-gate }
10547c478bd9Sstevel@tonic-gate 
1055*6c02b4a4Smuffin void
1056*6c02b4a4Smuffin panystop(int neednl)
10577c478bd9Sstevel@tonic-gate {
1058*6c02b4a4Smuffin 	struct process *pp;
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate #ifdef TRACE
10617c478bd9Sstevel@tonic-gate 	tprintf("TRACE- panystop()\n");
10627c478bd9Sstevel@tonic-gate #endif
10637c478bd9Sstevel@tonic-gate 	chkstop = 2;
10647c478bd9Sstevel@tonic-gate 	for (pp = proclist.p_next; pp; pp = pp->p_next)
10657c478bd9Sstevel@tonic-gate 		if (pp->p_flags & PSTOPPED)
10667c478bd9Sstevel@tonic-gate 			error("\nThere are stopped jobs" + 1 - neednl);
10677c478bd9Sstevel@tonic-gate }
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate struct process *
1070*6c02b4a4Smuffin pfind(tchar *cp)
10717c478bd9Sstevel@tonic-gate {
1072*6c02b4a4Smuffin 	struct process *pp, *np;
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate #ifdef TRACE
10757c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pfind()\n");
10767c478bd9Sstevel@tonic-gate #endif
10777c478bd9Sstevel@tonic-gate 	if (cp == 0 || cp[1] == 0 || eq(cp, S_PARCENTPARCENT /*"%%"*/) ||
10787c478bd9Sstevel@tonic-gate 				     eq(cp, S_PARCENTPLUS /*"%+"*/)) {
10797c478bd9Sstevel@tonic-gate 		if (pcurrent == PNULL)
10807c478bd9Sstevel@tonic-gate 			if ( (pcurrent = pgetcurr(PNULL)) == PNULL )
10817c478bd9Sstevel@tonic-gate 				bferr("No current job");
10827c478bd9Sstevel@tonic-gate 		return (pcurrent);
10837c478bd9Sstevel@tonic-gate 	}
10847c478bd9Sstevel@tonic-gate 	if (eq(cp, S_PARCENTMINUS /*"%-"*/) ||
10857c478bd9Sstevel@tonic-gate 	    eq(cp, S_PARCENTSHARP /*"%#"*/)) {
10867c478bd9Sstevel@tonic-gate 		if (pprevious == PNULL)
10877c478bd9Sstevel@tonic-gate 			bferr("No previous job");
10887c478bd9Sstevel@tonic-gate 		return (pprevious);
10897c478bd9Sstevel@tonic-gate 	}
10907c478bd9Sstevel@tonic-gate 	if (digit(cp[1])) {
10917c478bd9Sstevel@tonic-gate 		int index = atoi_(cp+1);
10927c478bd9Sstevel@tonic-gate 		for (pp = proclist.p_next; pp; pp = pp->p_next)
10937c478bd9Sstevel@tonic-gate 			if (pp->p_index == index && pp->p_pid == pp->p_jobid)
10947c478bd9Sstevel@tonic-gate 				return (pp);
10957c478bd9Sstevel@tonic-gate 		bferr("No such job");
10967c478bd9Sstevel@tonic-gate 	}
10977c478bd9Sstevel@tonic-gate 	np = PNULL;
10987c478bd9Sstevel@tonic-gate 	for (pp = proclist.p_next; pp; pp = pp->p_next)
10997c478bd9Sstevel@tonic-gate 		if (pp->p_pid == pp->p_jobid) {
11007c478bd9Sstevel@tonic-gate 			if (cp[1] == '?') {
1101*6c02b4a4Smuffin 				tchar *dp;
11027c478bd9Sstevel@tonic-gate 				for (dp = pp->p_command; *dp; dp++) {
11037c478bd9Sstevel@tonic-gate 					if (*dp != cp[2])
11047c478bd9Sstevel@tonic-gate 						continue;
11057c478bd9Sstevel@tonic-gate 					if (prefix(cp+2, dp))
11067c478bd9Sstevel@tonic-gate 						goto match;
11077c478bd9Sstevel@tonic-gate 				}
11087c478bd9Sstevel@tonic-gate 			} else if (prefix(cp+1, pp->p_command)) {
11097c478bd9Sstevel@tonic-gate match:
11107c478bd9Sstevel@tonic-gate 				if (np)
11117c478bd9Sstevel@tonic-gate 					bferr("Ambiguous");
11127c478bd9Sstevel@tonic-gate 				np = pp;
11137c478bd9Sstevel@tonic-gate 			}
11147c478bd9Sstevel@tonic-gate 		}
11157c478bd9Sstevel@tonic-gate 	if (np)
11167c478bd9Sstevel@tonic-gate 		return (np);
11177c478bd9Sstevel@tonic-gate 	if (cp[1] == '?')
11187c478bd9Sstevel@tonic-gate 		bferr("No job matches pattern");
11197c478bd9Sstevel@tonic-gate 	else
11207c478bd9Sstevel@tonic-gate 		bferr("No such job");
11217c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
11227c478bd9Sstevel@tonic-gate }
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate /*
11257c478bd9Sstevel@tonic-gate  * pgetcurr - find most recent job that is not pp, preferably stopped
11267c478bd9Sstevel@tonic-gate  */
11277c478bd9Sstevel@tonic-gate struct process *
1128*6c02b4a4Smuffin pgetcurr(struct process *pp)
11297c478bd9Sstevel@tonic-gate {
1130*6c02b4a4Smuffin 	struct process *np;
1131*6c02b4a4Smuffin 	struct process *xp = PNULL;
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate #ifdef TRACE
11347c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pgetcurr()\n");
11357c478bd9Sstevel@tonic-gate #endif
11367c478bd9Sstevel@tonic-gate 	for (np = proclist.p_next; np; np = np->p_next)
11377c478bd9Sstevel@tonic-gate 		if (np != pcurrent && np != pp && np->p_pid &&
11387c478bd9Sstevel@tonic-gate 		    np->p_pid == np->p_jobid) {
11397c478bd9Sstevel@tonic-gate 			if (np->p_flags & PSTOPPED)
11407c478bd9Sstevel@tonic-gate 				return (np);
11417c478bd9Sstevel@tonic-gate 			if (xp == PNULL)
11427c478bd9Sstevel@tonic-gate 				xp = np;
11437c478bd9Sstevel@tonic-gate 		}
11447c478bd9Sstevel@tonic-gate 	return (xp);
11457c478bd9Sstevel@tonic-gate }
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate /*
11487c478bd9Sstevel@tonic-gate  * donotify - flag the job so as to report termination asynchronously
11497c478bd9Sstevel@tonic-gate  */
1150*6c02b4a4Smuffin void
1151*6c02b4a4Smuffin donotify(tchar **v)
11527c478bd9Sstevel@tonic-gate {
1153*6c02b4a4Smuffin 	struct process *pp;
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate #ifdef TRACE
11567c478bd9Sstevel@tonic-gate 	tprintf("TRACE- donotify()\n");
11577c478bd9Sstevel@tonic-gate #endif
11587c478bd9Sstevel@tonic-gate 	pp = pfind(*++v);
11597c478bd9Sstevel@tonic-gate 	pp->p_flags |= PNOTIFY;
11607c478bd9Sstevel@tonic-gate }
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate /*
11637c478bd9Sstevel@tonic-gate  * Do the fork and whatever should be done in the child side that
11647c478bd9Sstevel@tonic-gate  * should not be done if we are not forking at all (like for simple builtin's)
11657c478bd9Sstevel@tonic-gate  * Also do everything that needs any signals fiddled with in the parent side
11667c478bd9Sstevel@tonic-gate  *
11677c478bd9Sstevel@tonic-gate  * Wanttty tells whether process and/or tty pgrps are to be manipulated:
11687c478bd9Sstevel@tonic-gate  *	-1:	leave tty alone; inherit pgrp from parent
11697c478bd9Sstevel@tonic-gate  *	 0:	already have tty; manipulate process pgrps only
11707c478bd9Sstevel@tonic-gate  *	 1:	want to claim tty; manipulate process and tty pgrps
11717c478bd9Sstevel@tonic-gate  * It is usually just the value of tpgrp.
1172*6c02b4a4Smuffin  *
1173*6c02b4a4Smuffin  * argument:
1174*6c02b4a4Smuffin  *	 t:	command we are forking for
11757c478bd9Sstevel@tonic-gate  */
1176*6c02b4a4Smuffin int
1177*6c02b4a4Smuffin pfork(struct command *t, int wanttty)
11787c478bd9Sstevel@tonic-gate {
1179*6c02b4a4Smuffin 	int pid;
11807c478bd9Sstevel@tonic-gate 	bool ignint = 0;
11817c478bd9Sstevel@tonic-gate 	int pgrp, omask;
11827c478bd9Sstevel@tonic-gate 	int child_pid;
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate #ifdef TRACE
11857c478bd9Sstevel@tonic-gate 	tprintf("TRACE- pfork()\n");
11867c478bd9Sstevel@tonic-gate #endif
11877c478bd9Sstevel@tonic-gate 	/*
11887c478bd9Sstevel@tonic-gate 	 * A child will be uninterruptible only under very special
11897c478bd9Sstevel@tonic-gate 	 * conditions. Remember that the semantics of '&' is
11907c478bd9Sstevel@tonic-gate 	 * implemented by disconnecting the process from the tty so
11917c478bd9Sstevel@tonic-gate 	 * signals do not need to ignored just for '&'.
11927c478bd9Sstevel@tonic-gate 	 * Thus signals are set to default action for children unless:
11937c478bd9Sstevel@tonic-gate 	 *	we have had an "onintr -" (then specifically ignored)
11947c478bd9Sstevel@tonic-gate 	 *	we are not playing with signals (inherit action)
11957c478bd9Sstevel@tonic-gate 	 */
11967c478bd9Sstevel@tonic-gate 	if (setintr)
11977c478bd9Sstevel@tonic-gate 		ignint = (tpgrp == -1 && (t->t_dflg&FINT))
11987c478bd9Sstevel@tonic-gate 		    || (gointr && eq(gointr, S_MINUS /*"-"*/));
11997c478bd9Sstevel@tonic-gate 	/*
12007c478bd9Sstevel@tonic-gate 	 * Hold SIGCHLD until we have the process installed in our table.
12017c478bd9Sstevel@tonic-gate 	 */
12027c478bd9Sstevel@tonic-gate 	omask = sigblock(sigmask(SIGCHLD));
12037c478bd9Sstevel@tonic-gate 	while ((pid = fork()) < 0)
12047c478bd9Sstevel@tonic-gate 		if (setintr == 0)
12057c478bd9Sstevel@tonic-gate 			sleep(FORKSLEEP);
12067c478bd9Sstevel@tonic-gate 		else {
12077c478bd9Sstevel@tonic-gate 			(void) sigsetmask(omask);
12087c478bd9Sstevel@tonic-gate 			error("Fork failed");
12097c478bd9Sstevel@tonic-gate 		}
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 	/*
12127c478bd9Sstevel@tonic-gate 	 * setup the process group
12137c478bd9Sstevel@tonic-gate 	 */
12147c478bd9Sstevel@tonic-gate 	if (pid == 0)
12157c478bd9Sstevel@tonic-gate 		child_pid = getpid();
12167c478bd9Sstevel@tonic-gate 	else
12177c478bd9Sstevel@tonic-gate 		child_pid = pid;
12187c478bd9Sstevel@tonic-gate 	pgrp = pcurrjob ? pcurrjob->p_jobid : child_pid;
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate 	if (pid == 0) {
12217c478bd9Sstevel@tonic-gate 		int sigttou;
12227c478bd9Sstevel@tonic-gate 		settimes();
12237c478bd9Sstevel@tonic-gate 		pflushall();
12247c478bd9Sstevel@tonic-gate 		pcurrjob = PNULL;
12257c478bd9Sstevel@tonic-gate 		child++;
12267c478bd9Sstevel@tonic-gate 		if (setintr) {
12277c478bd9Sstevel@tonic-gate 			setintr = 0;		/* until I think otherwise */
12287c478bd9Sstevel@tonic-gate 			/*
12297c478bd9Sstevel@tonic-gate 			 * Children just get blown away on SIGINT, SIGQUIT
12307c478bd9Sstevel@tonic-gate 			 * unless "onintr -" seen.
12317c478bd9Sstevel@tonic-gate 			 */
12327c478bd9Sstevel@tonic-gate 			(void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
12337c478bd9Sstevel@tonic-gate 			(void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
12347c478bd9Sstevel@tonic-gate 			if (wanttty >= 0) {
12357c478bd9Sstevel@tonic-gate 				/* make stoppable */
12367c478bd9Sstevel@tonic-gate 				(void) signal(SIGTSTP, SIG_DFL);
12377c478bd9Sstevel@tonic-gate 				(void) signal(SIGTTIN, SIG_DFL);
12387c478bd9Sstevel@tonic-gate 				(void) signal(SIGTTOU, SIG_DFL);
12397c478bd9Sstevel@tonic-gate 			}
12407c478bd9Sstevel@tonic-gate 			(void) signal(SIGTERM, parterm);
12417c478bd9Sstevel@tonic-gate 		} else if (tpgrp == -1 && (t->t_dflg&FINT)) {
12427c478bd9Sstevel@tonic-gate 			(void) signal(SIGINT, SIG_IGN);
12437c478bd9Sstevel@tonic-gate 			(void) signal(SIGQUIT, SIG_IGN);
12447c478bd9Sstevel@tonic-gate 		}
12457c478bd9Sstevel@tonic-gate 		if (wanttty >= 0 && tpgrp >= 0)
12467c478bd9Sstevel@tonic-gate 			(void) setpgid(0, pgrp);
12477c478bd9Sstevel@tonic-gate 		if (wanttty > 0) {
12487c478bd9Sstevel@tonic-gate 			sigttou = sigblock (sigmask(SIGTTOU)|
12497c478bd9Sstevel@tonic-gate 					    sigmask(SIGTTIN)|
12507c478bd9Sstevel@tonic-gate 					    sigmask(SIGTSTP));
12517c478bd9Sstevel@tonic-gate 			(void) ioctl(FSHTTY, TIOCSPGRP,  (char *)&pgrp);
12527c478bd9Sstevel@tonic-gate 			sigsetmask (sigttou);
12537c478bd9Sstevel@tonic-gate 		}
12547c478bd9Sstevel@tonic-gate 		if (tpgrp > 0)
12557c478bd9Sstevel@tonic-gate 			tpgrp = 0;		/* gave tty away */
12567c478bd9Sstevel@tonic-gate 		/*
12577c478bd9Sstevel@tonic-gate 		 * Nohup and nice apply only to TCOM's but it would be
12587c478bd9Sstevel@tonic-gate 		 * nice (?!?) if you could say "nohup (foo;bar)"
12597c478bd9Sstevel@tonic-gate 		 * Then the parser would have to know about nice/nohup/time
12607c478bd9Sstevel@tonic-gate 		 */
12617c478bd9Sstevel@tonic-gate 		if (t->t_dflg & FNOHUP)
12627c478bd9Sstevel@tonic-gate 			(void) signal(SIGHUP, SIG_IGN);
12637c478bd9Sstevel@tonic-gate 		if (t->t_dflg & FNICE)
12647c478bd9Sstevel@tonic-gate 			(void) setpriority(PRIO_PROCESS, 0, t->t_nice);
12657c478bd9Sstevel@tonic-gate 	} else {
12667c478bd9Sstevel@tonic-gate 		if (wanttty >= 0 && tpgrp >= 0)
12677c478bd9Sstevel@tonic-gate 			setpgid(pid, pgrp);
12687c478bd9Sstevel@tonic-gate 		palloc(pid, t);
12697c478bd9Sstevel@tonic-gate 		(void) sigsetmask(omask);
12707c478bd9Sstevel@tonic-gate 	}
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 	return (pid);
12737c478bd9Sstevel@tonic-gate }
12747c478bd9Sstevel@tonic-gate 
1275*6c02b4a4Smuffin void
1276*6c02b4a4Smuffin okpcntl(void)
12777c478bd9Sstevel@tonic-gate {
12787c478bd9Sstevel@tonic-gate #ifdef TRACE
12797c478bd9Sstevel@tonic-gate 	tprintf("TRACE- okpcntl()\n");
12807c478bd9Sstevel@tonic-gate #endif
12817c478bd9Sstevel@tonic-gate 
12827c478bd9Sstevel@tonic-gate 	if (tpgrp == -1)
12837c478bd9Sstevel@tonic-gate 		error("No job control in this shell");
12847c478bd9Sstevel@tonic-gate 	if (tpgrp == 0)
12857c478bd9Sstevel@tonic-gate 		error("No job control in subshells");
12867c478bd9Sstevel@tonic-gate }
12877c478bd9Sstevel@tonic-gate 
1288