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