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