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