proc.c revision 1.13 1 /* $NetBSD: proc.c,v 1.13 1998/07/28 02:23:39 mycroft Exp $ */
2
3 /*-
4 * Copyright (c) 1980, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)proc.c 8.1 (Berkeley) 5/31/93";
40 #else
41 __RCSID("$NetBSD: proc.c,v 1.13 1998/07/28 02:23:39 mycroft Exp $");
42 #endif
43 #endif /* not lint */
44
45 #include <sys/types.h>
46 #include <sys/wait.h>
47 #include <errno.h>
48 #include <unistd.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #if __STDC__
52 # include <stdarg.h>
53 #else
54 # include <varargs.h>
55 #endif
56
57 #include "csh.h"
58 #include "dir.h"
59 #include "proc.h"
60 #include "extern.h"
61
62 #define BIGINDEX 9 /* largest desirable job index */
63
64 static struct rusage zru;
65
66 static void pflushall __P((void));
67 static void pflush __P((struct process *));
68 static void pclrcurr __P((struct process *));
69 static void padd __P((struct command *));
70 static int pprint __P((struct process *, int));
71 static void ptprint __P((struct process *));
72 static void pads __P((Char *));
73 static void pkill __P((Char **v, int));
74 static struct process
75 *pgetcurr __P((struct process *));
76 static void okpcntl __P((void));
77
78 /*
79 * pchild - called at interrupt level by the SIGCHLD signal
80 * indicating that at least one child has terminated or stopped
81 * thus at least one wait system call will definitely return a
82 * childs status. Top level routines (like pwait) must be sure
83 * to mask interrupts when playing with the proclist data structures!
84 */
85 /* ARGSUSED */
86 void
87 pchild(notused)
88 int notused;
89 {
90 struct process *pp;
91 struct process *fp;
92 int pid;
93 extern int insource;
94 union wait w;
95 int jobflags;
96 struct rusage ru;
97
98 loop:
99 errno = 0; /* reset, just in case */
100 pid = wait3(&w.w_status,
101 (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru);
102
103 if (pid <= 0) {
104 if (errno == EINTR) {
105 errno = 0;
106 goto loop;
107 }
108 pnoprocesses = pid == -1;
109 return;
110 }
111 for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
112 if (pid == pp->p_pid)
113 goto found;
114 goto loop;
115 found:
116 if (pid == atoi(short2str(value(STRchild))))
117 unsetv(STRchild);
118 pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED);
119 if (WIFSTOPPED(w)) {
120 pp->p_flags |= PSTOPPED;
121 pp->p_reason = w.w_stopsig;
122 }
123 else {
124 if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime))
125 (void) gettimeofday(&pp->p_etime, NULL);
126
127 pp->p_rusage = ru;
128 if (WIFSIGNALED(w)) {
129 if (w.w_termsig == SIGINT)
130 pp->p_flags |= PINTERRUPTED;
131 else
132 pp->p_flags |= PSIGNALED;
133 if (w.w_coredump)
134 pp->p_flags |= PDUMPED;
135 pp->p_reason = w.w_termsig;
136 }
137 else {
138 pp->p_reason = w.w_retcode;
139 if (pp->p_reason != 0)
140 pp->p_flags |= PAEXITED;
141 else
142 pp->p_flags |= PNEXITED;
143 }
144 }
145 jobflags = 0;
146 fp = pp;
147 do {
148 if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 &&
149 !child && adrof(STRtime) &&
150 fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec
151 >= atoi(short2str(value(STRtime))))
152 fp->p_flags |= PTIME;
153 jobflags |= fp->p_flags;
154 } while ((fp = fp->p_friends) != pp);
155 pp->p_flags &= ~PFOREGND;
156 if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
157 pp->p_flags &= ~PPTIME;
158 pp->p_flags |= PTIME;
159 }
160 if ((jobflags & (PRUNNING | PREPORTED)) == 0) {
161 fp = pp;
162 do {
163 if (fp->p_flags & PSTOPPED)
164 fp->p_flags |= PREPORTED;
165 } while ((fp = fp->p_friends) != pp);
166 while (fp->p_pid != fp->p_jobid)
167 fp = fp->p_friends;
168 if (jobflags & PSTOPPED) {
169 if (pcurrent && pcurrent != fp)
170 pprevious = pcurrent;
171 pcurrent = fp;
172 }
173 else
174 pclrcurr(fp);
175 if (jobflags & PFOREGND) {
176 if (jobflags & (PSIGNALED | PSTOPPED | PPTIME) ||
177 #ifdef IIASA
178 jobflags & PAEXITED ||
179 #endif
180 !eq(dcwd->di_name, fp->p_cwd->di_name)) {
181 ; /* print in pjwait */
182 }
183 /* PWP: print a newline after ^C */
184 else if (jobflags & PINTERRUPTED) {
185 (void) vis_fputc('\r' | QUOTE, cshout);
186 (void) fputc('\n', cshout);
187 }
188 }
189 else {
190 if (jobflags & PNOTIFY || adrof(STRnotify)) {
191 (void) vis_fputc('\r' | QUOTE, cshout);
192 (void) fputc('\n', cshout);
193 (void) pprint(pp, NUMBER | NAME | REASON);
194 if ((jobflags & PSTOPPED) == 0)
195 pflush(pp);
196 }
197 else {
198 fp->p_flags |= PNEEDNOTE;
199 neednote++;
200 }
201 }
202 }
203 goto loop;
204 }
205
206 void
207 pnote()
208 {
209 struct process *pp;
210 int flags;
211 sigset_t sigset, osigset;
212
213 neednote = 0;
214 sigemptyset(&sigset);
215 sigaddset(&sigset, SIGCHLD);
216 for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) {
217 if (pp->p_flags & PNEEDNOTE) {
218 sigprocmask(SIG_BLOCK, &sigset, &osigset);
219 pp->p_flags &= ~PNEEDNOTE;
220 flags = pprint(pp, NUMBER | NAME | REASON);
221 if ((flags & (PRUNNING | PSTOPPED)) == 0)
222 pflush(pp);
223 sigprocmask(SIG_SETMASK, &osigset, NULL);
224 }
225 }
226 }
227
228 /*
229 * pwait - wait for current job to terminate, maintaining integrity
230 * of current and previous job indicators.
231 */
232 void
233 pwait()
234 {
235 struct process *fp, *pp;
236 sigset_t sigset, osigset;
237
238 /*
239 * Here's where dead procs get flushed.
240 */
241 sigemptyset(&sigset);
242 sigaddset(&sigset, SIGCHLD);
243 sigprocmask(SIG_BLOCK, &sigset, &osigset);
244 for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next)
245 if (pp->p_pid == 0) {
246 fp->p_next = pp->p_next;
247 xfree((ptr_t) pp->p_command);
248 if (pp->p_cwd && --pp->p_cwd->di_count == 0)
249 if (pp->p_cwd->di_next == 0)
250 dfree(pp->p_cwd);
251 xfree((ptr_t) pp);
252 pp = fp;
253 }
254 sigprocmask(SIG_SETMASK, &osigset, NULL);
255 pjwait(pcurrjob);
256 }
257
258
259 /*
260 * pjwait - wait for a job to finish or become stopped
261 * It is assumed to be in the foreground state (PFOREGND)
262 */
263 void
264 pjwait(pp)
265 struct process *pp;
266 {
267 struct process *fp;
268 int jobflags, reason;
269 sigset_t sigset, osigset;
270
271 while (pp->p_pid != pp->p_jobid)
272 pp = pp->p_friends;
273 fp = pp;
274
275 do {
276 if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING)
277 (void) fprintf(csherr, "BUG: waiting for background job!\n");
278 } while ((fp = fp->p_friends) != pp);
279 /*
280 * Now keep pausing as long as we are not interrupted (SIGINT), and the
281 * target process, or any of its friends, are running
282 */
283 fp = pp;
284 sigemptyset(&sigset);
285 sigaddset(&sigset, SIGCHLD);
286 sigprocmask(SIG_BLOCK, &sigset, &osigset);
287 for (;;) {
288 sigemptyset(&sigset);
289 sigaddset(&sigset, SIGCHLD);
290 sigprocmask(SIG_BLOCK, &sigset, NULL);
291 jobflags = 0;
292 do
293 jobflags |= fp->p_flags;
294 while ((fp = (fp->p_friends)) != pp);
295 if ((jobflags & PRUNNING) == 0)
296 break;
297 #ifdef JOBDEBUG
298 (void) fprintf(csherr, "starting to sigsuspend for SIGCHLD on %d\n",
299 fp->p_pid);
300 #endif /* JOBDEBUG */
301 sigset = osigset;
302 sigdelset(&sigset, SIGCHLD);
303 sigsuspend(&sigset);
304 }
305 sigprocmask(SIG_SETMASK, &osigset, NULL);
306 if (tpgrp > 0) /* get tty back */
307 (void) tcsetpgrp(FSHTTY, tpgrp);
308 if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) ||
309 !eq(dcwd->di_name, fp->p_cwd->di_name)) {
310 if (jobflags & PSTOPPED) {
311 (void) fputc('\n', cshout);
312 if (adrof(STRlistjobs)) {
313 Char *jobcommand[3];
314
315 jobcommand[0] = STRjobs;
316 if (eq(value(STRlistjobs), STRlong))
317 jobcommand[1] = STRml;
318 else
319 jobcommand[1] = NULL;
320 jobcommand[2] = NULL;
321
322 dojobs(jobcommand, NULL);
323 (void) pprint(pp, SHELLDIR);
324 }
325 else
326 (void) pprint(pp, AREASON | SHELLDIR);
327 }
328 else
329 (void) pprint(pp, AREASON | SHELLDIR);
330 }
331 if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr &&
332 (!gointr || !eq(gointr, STRminus))) {
333 if ((jobflags & PSTOPPED) == 0)
334 pflush(pp);
335 pintr1(0);
336 /* NOTREACHED */
337 }
338 reason = 0;
339 fp = pp;
340 do {
341 if (fp->p_reason)
342 reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ?
343 fp->p_reason | META : fp->p_reason;
344 } while ((fp = fp->p_friends) != pp);
345 if ((reason != 0) && (adrof(STRprintexitvalue))) {
346 (void) fprintf(cshout, "Exit %d\n", reason);
347 }
348 set(STRstatus, putn(reason));
349 if (reason && exiterr) {
350 exitstat();
351 /* NOTREACHED */
352 }
353 pflush(pp);
354 }
355
356 /*
357 * dowait - wait for all processes to finish
358 */
359 void
360 /*ARGSUSED*/
361 dowait(v, t)
362 Char **v;
363 struct command *t;
364 {
365 struct process *pp;
366 sigset_t sigset, osigset;
367
368 pjobs++;
369 sigemptyset(&sigset);
370 sigaddset(&sigset, SIGCHLD);
371 sigprocmask(SIG_BLOCK, &sigset, &osigset);
372 loop:
373 for (pp = proclist.p_next; pp; pp = pp->p_next)
374 if (pp->p_pid && /* pp->p_pid == pp->p_jobid && */
375 pp->p_flags & PRUNNING) {
376 sigemptyset(&sigset);
377 sigsuspend(&sigset);
378 goto loop;
379 }
380 sigprocmask(SIG_SETMASK, &osigset, NULL);
381 pjobs = 0;
382 }
383
384 /*
385 * pflushall - flush all jobs from list (e.g. at fork())
386 */
387 static void
388 pflushall()
389 {
390 struct process *pp;
391
392 for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
393 if (pp->p_pid)
394 pflush(pp);
395 }
396
397 /*
398 * pflush - flag all process structures in the same job as the
399 * the argument process for deletion. The actual free of the
400 * space is not done here since pflush is called at interrupt level.
401 */
402 static void
403 pflush(pp)
404 struct process *pp;
405 {
406 struct process *np;
407 int idx;
408
409 if (pp->p_pid == 0) {
410 (void) fprintf(csherr, "BUG: process flushed twice");
411 return;
412 }
413 while (pp->p_pid != pp->p_jobid)
414 pp = pp->p_friends;
415 pclrcurr(pp);
416 if (pp == pcurrjob)
417 pcurrjob = 0;
418 idx = pp->p_index;
419 np = pp;
420 do {
421 np->p_index = np->p_pid = 0;
422 np->p_flags &= ~PNEEDNOTE;
423 } while ((np = np->p_friends) != pp);
424 if (idx == pmaxindex) {
425 for (np = proclist.p_next, idx = 0; np; np = np->p_next)
426 if (np->p_index > idx)
427 idx = np->p_index;
428 pmaxindex = idx;
429 }
430 }
431
432 /*
433 * pclrcurr - make sure the given job is not the current or previous job;
434 * pp MUST be the job leader
435 */
436 static void
437 pclrcurr(pp)
438 struct process *pp;
439 {
440
441 if (pp == pcurrent)
442 if (pprevious != NULL) {
443 pcurrent = pprevious;
444 pprevious = pgetcurr(pp);
445 }
446 else {
447 pcurrent = pgetcurr(pp);
448 pprevious = pgetcurr(pp);
449 }
450 else if (pp == pprevious)
451 pprevious = pgetcurr(pp);
452 }
453
454 /* +4 here is 1 for '\0', 1 ea for << >& >> */
455 static Char command[PMAXLEN + 4];
456 static int cmdlen;
457 static Char *cmdp;
458
459 /*
460 * palloc - allocate a process structure and fill it up.
461 * an important assumption is made that the process is running.
462 */
463 void
464 palloc(pid, t)
465 int pid;
466 struct command *t;
467 {
468 struct process *pp;
469 int i;
470
471 pp = (struct process *) xcalloc(1, (size_t) sizeof(struct process));
472 pp->p_pid = pid;
473 pp->p_flags = t->t_dflg & F_AMPERSAND ? PRUNNING : PRUNNING | PFOREGND;
474 if (t->t_dflg & F_TIME)
475 pp->p_flags |= PPTIME;
476 cmdp = command;
477 cmdlen = 0;
478 padd(t);
479 *cmdp++ = 0;
480 if (t->t_dflg & F_PIPEOUT) {
481 pp->p_flags |= PPOU;
482 if (t->t_dflg & F_STDERR)
483 pp->p_flags |= PERR;
484 }
485 pp->p_command = Strsave(command);
486 if (pcurrjob) {
487 struct process *fp;
488
489 /* careful here with interrupt level */
490 pp->p_cwd = 0;
491 pp->p_index = pcurrjob->p_index;
492 pp->p_friends = pcurrjob;
493 pp->p_jobid = pcurrjob->p_pid;
494 for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
495 continue;
496 fp->p_friends = pp;
497 }
498 else {
499 pcurrjob = pp;
500 pp->p_jobid = pid;
501 pp->p_friends = pp;
502 pp->p_cwd = dcwd;
503 dcwd->di_count++;
504 if (pmaxindex < BIGINDEX)
505 pp->p_index = ++pmaxindex;
506 else {
507 struct process *np;
508
509 for (i = 1;; i++) {
510 for (np = proclist.p_next; np; np = np->p_next)
511 if (np->p_index == i)
512 goto tryagain;
513 pp->p_index = i;
514 if (i > pmaxindex)
515 pmaxindex = i;
516 break;
517 tryagain:;
518 }
519 }
520 if (pcurrent == NULL)
521 pcurrent = pp;
522 else if (pprevious == NULL)
523 pprevious = pp;
524 }
525 pp->p_next = proclist.p_next;
526 proclist.p_next = pp;
527 (void) gettimeofday(&pp->p_btime, NULL);
528 }
529
530 static void
531 padd(t)
532 struct command *t;
533 {
534 Char **argp;
535
536 if (t == 0)
537 return;
538 switch (t->t_dtyp) {
539
540 case NODE_PAREN:
541 pads(STRLparensp);
542 padd(t->t_dspr);
543 pads(STRspRparen);
544 break;
545
546 case NODE_COMMAND:
547 for (argp = t->t_dcom; *argp; argp++) {
548 pads(*argp);
549 if (argp[1])
550 pads(STRspace);
551 }
552 break;
553
554 case NODE_OR:
555 case NODE_AND:
556 case NODE_PIPE:
557 case NODE_LIST:
558 padd(t->t_dcar);
559 switch (t->t_dtyp) {
560 case NODE_OR:
561 pads(STRspor2sp);
562 break;
563 case NODE_AND:
564 pads(STRspand2sp);
565 break;
566 case NODE_PIPE:
567 pads(STRsporsp);
568 break;
569 case NODE_LIST:
570 pads(STRsemisp);
571 break;
572 }
573 padd(t->t_dcdr);
574 return;
575 }
576 if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) {
577 pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp);
578 pads(t->t_dlef);
579 }
580 if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) {
581 pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow);
582 if (t->t_dflg & F_STDERR)
583 pads(STRand);
584 pads(STRspace);
585 pads(t->t_drit);
586 }
587 }
588
589 static void
590 pads(cp)
591 Char *cp;
592 {
593 int i;
594
595 /*
596 * Avoid the Quoted Space alias hack! Reported by:
597 * sam (at) john-bigboote.ICS.UCI.EDU (Sam Horrocks)
598 */
599 if (cp[0] == STRQNULL[0])
600 cp++;
601
602 i = Strlen(cp);
603
604 if (cmdlen >= PMAXLEN)
605 return;
606 if (cmdlen + i >= PMAXLEN) {
607 (void) Strcpy(cmdp, STRsp3dots);
608 cmdlen = PMAXLEN;
609 cmdp += 4;
610 return;
611 }
612 (void) Strcpy(cmdp, cp);
613 cmdp += i;
614 cmdlen += i;
615 }
616
617 /*
618 * psavejob - temporarily save the current job on a one level stack
619 * so another job can be created. Used for { } in exp6
620 * and `` in globbing.
621 */
622 void
623 psavejob()
624 {
625
626 pholdjob = pcurrjob;
627 pcurrjob = NULL;
628 }
629
630 /*
631 * prestjob - opposite of psavejob. This may be missed if we are interrupted
632 * somewhere, but pendjob cleans up anyway.
633 */
634 void
635 prestjob()
636 {
637
638 pcurrjob = pholdjob;
639 pholdjob = NULL;
640 }
641
642 /*
643 * pendjob - indicate that a job (set of commands) has been completed
644 * or is about to begin.
645 */
646 void
647 pendjob()
648 {
649 struct process *pp, *tp;
650
651 if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) {
652 pp = pcurrjob;
653 while (pp->p_pid != pp->p_jobid)
654 pp = pp->p_friends;
655 (void) fprintf(cshout, "[%d]", pp->p_index);
656 tp = pp;
657 do {
658 (void) fprintf(cshout, " %d", pp->p_pid);
659 pp = pp->p_friends;
660 } while (pp != tp);
661 (void) fputc('\n', cshout);
662 }
663 pholdjob = pcurrjob = 0;
664 }
665
666 /*
667 * pprint - print a job
668 */
669 static int
670 pprint(pp, flag)
671 struct process *pp;
672 bool flag;
673 {
674 int status, reason;
675 struct process *tp;
676 int jobflags, pstatus;
677 bool hadnl = 1; /* did we just have a newline */
678 char *format;
679
680 (void) fpurge(cshout);
681
682 while (pp->p_pid != pp->p_jobid)
683 pp = pp->p_friends;
684 if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
685 pp->p_flags &= ~PPTIME;
686 pp->p_flags |= PTIME;
687 }
688 tp = pp;
689 status = reason = -1;
690 jobflags = 0;
691 do {
692 jobflags |= pp->p_flags;
693 pstatus = pp->p_flags & PALLSTATES;
694 if (tp != pp && !hadnl && !(flag & FANCY) &&
695 ((pstatus == status && pp->p_reason == reason) ||
696 !(flag & REASON))) {
697 (void) fputc(' ', cshout);
698 hadnl = 0;
699 }
700 else {
701 if (tp != pp && !hadnl) {
702 (void) fputc('\n', cshout);
703 hadnl = 1;
704 }
705 if (flag & NUMBER) {
706 if (pp == tp)
707 (void) fprintf(cshout, "[%d]%s %c ", pp->p_index,
708 pp->p_index < 10 ? " " : "",
709 pp == pcurrent ? '+' :
710 (pp == pprevious ? '-' : ' '));
711 else
712 (void) fprintf(cshout, " ");
713 hadnl = 0;
714 }
715 if (flag & FANCY) {
716 (void) fprintf(cshout, "%5d ", pp->p_pid);
717 hadnl = 0;
718 }
719 if (flag & (REASON | AREASON)) {
720 if (flag & NAME)
721 format = "%-23s";
722 else
723 format = "%s";
724 if (pstatus == status)
725 if (pp->p_reason == reason) {
726 (void) fprintf(cshout, format, "");
727 hadnl = 0;
728 goto prcomd;
729 }
730 else
731 reason = pp->p_reason;
732 else {
733 status = pstatus;
734 reason = pp->p_reason;
735 }
736 switch (status) {
737
738 case PRUNNING:
739 (void) fprintf(cshout, format, "Running ");
740 hadnl = 0;
741 break;
742
743 case PINTERRUPTED:
744 case PSTOPPED:
745 case PSIGNALED:
746 /*
747 * tell what happened to the background job
748 * From: Michael Schroeder
749 * <mlschroe (at) immd4.informatik.uni-erlangen.de>
750 */
751 if ((flag & REASON)
752 || ((flag & AREASON)
753 && reason != SIGINT
754 && (reason != SIGPIPE
755 || (pp->p_flags & PPOU) == 0))) {
756 (void) fprintf(cshout, format,
757 sys_siglist[(unsigned char)
758 pp->p_reason]);
759 hadnl = 0;
760 }
761 break;
762
763 case PNEXITED:
764 case PAEXITED:
765 if (flag & REASON) {
766 if (pp->p_reason)
767 (void) fprintf(cshout, "Exit %-18d", pp->p_reason);
768 else
769 (void) fprintf(cshout, format, "Done");
770 hadnl = 0;
771 }
772 break;
773
774 default:
775 (void) fprintf(csherr, "BUG: status=%-9o", status);
776 }
777 }
778 }
779 prcomd:
780 if (flag & NAME) {
781 (void) fprintf(cshout, "%s", vis_str(pp->p_command));
782 if (pp->p_flags & PPOU)
783 (void) fprintf(cshout, " |");
784 if (pp->p_flags & PERR)
785 (void) fputc('&', cshout);
786 hadnl = 0;
787 }
788 if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) {
789 (void) fprintf(cshout, " (core dumped)");
790 hadnl = 0;
791 }
792 if (tp == pp->p_friends) {
793 if (flag & AMPERSAND) {
794 (void) fprintf(cshout, " &");
795 hadnl = 0;
796 }
797 if (flag & JOBDIR &&
798 !eq(tp->p_cwd->di_name, dcwd->di_name)) {
799 (void) fprintf(cshout, " (wd: ");
800 dtildepr(value(STRhome), tp->p_cwd->di_name);
801 (void) fputc(')', cshout);
802 hadnl = 0;
803 }
804 }
805 if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) {
806 if (!hadnl)
807 (void) fprintf(cshout, "\n\t");
808 prusage(&zru, &pp->p_rusage, &pp->p_etime,
809 &pp->p_btime);
810 hadnl = 1;
811 }
812 if (tp == pp->p_friends) {
813 if (!hadnl) {
814 (void) fputc('\n', cshout);
815 hadnl = 1;
816 }
817 if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
818 (void) fprintf(cshout, "(wd now: ");
819 dtildepr(value(STRhome), dcwd->di_name);
820 (void) fprintf(cshout, ")\n");
821 hadnl = 1;
822 }
823 }
824 } while ((pp = pp->p_friends) != tp);
825 if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) {
826 if (jobflags & NUMBER)
827 (void) fprintf(cshout, " ");
828 ptprint(tp);
829 hadnl = 1;
830 }
831 (void) fflush(cshout);
832 return (jobflags);
833 }
834
835 static void
836 ptprint(tp)
837 struct process *tp;
838 {
839 struct timeval tetime, diff;
840 static struct timeval ztime;
841 struct rusage ru;
842 static struct rusage zru;
843 struct process *pp = tp;
844
845 ru = zru;
846 tetime = ztime;
847 do {
848 ruadd(&ru, &pp->p_rusage);
849 timersub(&pp->p_etime, &pp->p_btime, &diff);
850 if (timercmp(&diff, &tetime, >))
851 tetime = diff;
852 } while ((pp = pp->p_friends) != tp);
853 prusage(&zru, &ru, &tetime, &ztime);
854 }
855
856 /*
857 * dojobs - print all jobs
858 */
859 void
860 /*ARGSUSED*/
861 dojobs(v, t)
862 Char **v;
863 struct command *t;
864 {
865 struct process *pp;
866 int flag = NUMBER | NAME | REASON;
867 int i;
868
869 if (chkstop)
870 chkstop = 2;
871 if (*++v) {
872 if (v[1] || !eq(*v, STRml)) {
873 stderror(ERR_JOBS);
874 /* NOTREACHED */
875 }
876 flag |= FANCY | JOBDIR;
877 }
878 for (i = 1; i <= pmaxindex; i++)
879 for (pp = proclist.p_next; pp; pp = pp->p_next)
880 if (pp->p_index == i && pp->p_pid == pp->p_jobid) {
881 pp->p_flags &= ~PNEEDNOTE;
882 if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED)))
883 pflush(pp);
884 break;
885 }
886 }
887
888 /*
889 * dofg - builtin - put the job into the foreground
890 */
891 void
892 /*ARGSUSED*/
893 dofg(v, t)
894 Char **v;
895 struct command *t;
896 {
897 struct process *pp;
898
899 okpcntl();
900 ++v;
901 do {
902 pp = pfind(*v);
903 pstart(pp, 1);
904 pjwait(pp);
905 } while (*v && *++v);
906 }
907
908 /*
909 * %... - builtin - put the job into the foreground
910 */
911 void
912 /*ARGSUSED*/
913 dofg1(v, t)
914 Char **v;
915 struct command *t;
916 {
917 struct process *pp;
918
919 okpcntl();
920 pp = pfind(v[0]);
921 pstart(pp, 1);
922 pjwait(pp);
923 }
924
925 /*
926 * dobg - builtin - put the job into the background
927 */
928 void
929 /*ARGSUSED*/
930 dobg(v, t)
931 Char **v;
932 struct command *t;
933 {
934 struct process *pp;
935
936 okpcntl();
937 ++v;
938 do {
939 pp = pfind(*v);
940 pstart(pp, 0);
941 } while (*v && *++v);
942 }
943
944 /*
945 * %... & - builtin - put the job into the background
946 */
947 void
948 /*ARGSUSED*/
949 dobg1(v, t)
950 Char **v;
951 struct command *t;
952 {
953 struct process *pp;
954
955 pp = pfind(v[0]);
956 pstart(pp, 0);
957 }
958
959 /*
960 * dostop - builtin - stop the job
961 */
962 void
963 /*ARGSUSED*/
964 dostop(v, t)
965 Char **v;
966 struct command *t;
967 {
968 pkill(++v, SIGSTOP);
969 }
970
971 /*
972 * dokill - builtin - superset of kill (1)
973 */
974 void
975 /*ARGSUSED*/
976 dokill(v, t)
977 Char **v;
978 struct command *t;
979 {
980 int signum = SIGTERM;
981 char *name;
982
983 v++;
984 if (v[0] && v[0][0] == '-') {
985 if (v[0][1] == 'l') {
986 if (v[1]) {
987 if (!Isdigit(v[1][0])) {
988 stderror(ERR_NAME | ERR_BADSIG);
989 /* NOTREACHED */
990 }
991
992 signum = atoi(short2str(v[1]));
993 if (signum < 0 || signum >= NSIG) {
994 stderror(ERR_NAME | ERR_BADSIG);
995 /* NOTREACHED */
996 }
997 else if (signum == 0)
998 (void) fputc('0', cshout); /* 0's symbolic name is '0' */
999 else
1000 (void) fprintf(cshout, "%s ", sys_signame[signum]);
1001 } else {
1002 for (signum = 1; signum < NSIG; signum++) {
1003 (void) fprintf(cshout, "%s ", sys_signame[signum]);
1004 if (signum == NSIG / 2)
1005 (void) fputc('\n', cshout);
1006 }
1007 }
1008 (void) fputc('\n', cshout);
1009 return;
1010 }
1011 if (Isdigit(v[0][1])) {
1012 signum = atoi(short2str(v[0] + 1));
1013 if (signum < 0 || signum > NSIG) {
1014 stderror(ERR_NAME | ERR_BADSIG);
1015 /* NOTREACHED */
1016 }
1017 }
1018 else {
1019 if (v[0][1] == 's' && (Isspace(v[0][2]) || v[0][2] == '\0'))
1020 v++;
1021 else
1022 (*v)++;
1023
1024 if (v[0] == NULL || v[1] == NULL) {
1025 stderror(ERR_NAME | ERR_TOOFEW);
1026 /* NOTREACHED */
1027 }
1028
1029 name = short2str(&v[0][0]);
1030 for (signum = 1; signum < NSIG; signum++)
1031 if (!strcasecmp(sys_signame[signum], name))
1032 break;
1033
1034 if (signum == NSIG) {
1035 if (v[0][0] == '0')
1036 signum = 0;
1037 else {
1038 setname(vis_str(&v[0][0]));
1039 stderror(ERR_NAME | ERR_UNKSIG);
1040 /* NOTREACHED */
1041 }
1042 }
1043 }
1044 v++;
1045 }
1046 pkill(v, signum);
1047 }
1048
1049 static void
1050 pkill(v, signum)
1051 Char **v;
1052 int signum;
1053 {
1054 struct process *pp, *np;
1055 int jobflags = 0;
1056 int pid, err1 = 0;
1057 sigset_t sigset;
1058 Char *cp;
1059
1060 sigemptyset(&sigset);
1061 sigaddset(&sigset, SIGCHLD);
1062 if (setintr)
1063 sigaddset(&sigset, SIGINT);
1064 sigprocmask(SIG_BLOCK, &sigset, NULL);
1065 gflag = 0, tglob(v);
1066 if (gflag) {
1067 v = globall(v);
1068 if (v == 0) {
1069 stderror(ERR_NAME | ERR_NOMATCH);
1070 /* NOTREACHED */
1071 }
1072 }
1073 else {
1074 v = gargv = saveblk(v);
1075 trim(v);
1076 }
1077
1078 while (v && (cp = *v)) {
1079 if (*cp == '%') {
1080 np = pp = pfind(cp);
1081 do
1082 jobflags |= np->p_flags;
1083 while ((np = np->p_friends) != pp);
1084 switch (signum) {
1085
1086 case SIGSTOP:
1087 case SIGTSTP:
1088 case SIGTTIN:
1089 case SIGTTOU:
1090 if ((jobflags & PRUNNING) == 0) {
1091 (void) fprintf(csherr, "%s: Already suspended\n",
1092 vis_str(cp));
1093 err1++;
1094 goto cont;
1095 }
1096 break;
1097 /*
1098 * suspend a process, kill -CONT %, then type jobs; the shell
1099 * says it is suspended, but it is running; thanks jaap..
1100 */
1101 case SIGCONT:
1102 pstart(pp, 0);
1103 goto cont;
1104 }
1105 if (kill(-pp->p_jobid, signum) < 0) {
1106 (void) fprintf(csherr, "%s: %s\n", vis_str(cp),
1107 strerror(errno));
1108 err1++;
1109 }
1110 if (signum == SIGTERM || signum == SIGHUP)
1111 (void) kill(-pp->p_jobid, SIGCONT);
1112 }
1113 else if (!(Isdigit(*cp) || *cp == '-')) {
1114 stderror(ERR_NAME | ERR_JOBARGS);
1115 /* NOTREACHED */
1116 }
1117 else {
1118 pid = atoi(short2str(cp));
1119 if (kill((pid_t) pid, signum) < 0) {
1120 (void) fprintf(csherr, "%d: %s\n", pid, strerror(errno));
1121 err1++;
1122 goto cont;
1123 }
1124 if (signum == SIGTERM || signum == SIGHUP)
1125 (void) kill((pid_t) pid, SIGCONT);
1126 }
1127 cont:
1128 v++;
1129 }
1130 if (gargv)
1131 blkfree(gargv), gargv = 0;
1132 sigprocmask(SIG_UNBLOCK, &sigset, NULL);
1133 if (err1) {
1134 stderror(ERR_SILENT);
1135 /* NOTREACHED */
1136 }
1137 }
1138
1139 /*
1140 * pstart - start the job in foreground/background
1141 */
1142 void
1143 pstart(pp, foregnd)
1144 struct process *pp;
1145 int foregnd;
1146 {
1147 struct process *np;
1148 sigset_t sigset, osigset;
1149 long jobflags = 0;
1150
1151 sigemptyset(&sigset);
1152 sigaddset(&sigset, SIGCHLD);
1153 sigprocmask(SIG_BLOCK, &sigset, &osigset);
1154 np = pp;
1155 do {
1156 jobflags |= np->p_flags;
1157 if (np->p_flags & (PRUNNING | PSTOPPED)) {
1158 np->p_flags |= PRUNNING;
1159 np->p_flags &= ~PSTOPPED;
1160 if (foregnd)
1161 np->p_flags |= PFOREGND;
1162 else
1163 np->p_flags &= ~PFOREGND;
1164 }
1165 } while ((np = np->p_friends) != pp);
1166 if (!foregnd)
1167 pclrcurr(pp);
1168 (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND);
1169 if (foregnd)
1170 (void) tcsetpgrp(FSHTTY, pp->p_jobid);
1171 if (jobflags & PSTOPPED)
1172 (void) kill(-pp->p_jobid, SIGCONT);
1173 sigprocmask(SIG_SETMASK, &osigset, NULL);
1174 }
1175
1176 void
1177 panystop(neednl)
1178 bool neednl;
1179 {
1180 struct process *pp;
1181
1182 chkstop = 2;
1183 for (pp = proclist.p_next; pp; pp = pp->p_next)
1184 if (pp->p_flags & PSTOPPED) {
1185 stderror(ERR_STOPPED, neednl ? "\n" : "");
1186 /* NOTREACHED */
1187 }
1188 }
1189
1190 struct process *
1191 pfind(cp)
1192 Char *cp;
1193 {
1194 struct process *pp, *np;
1195
1196 if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) {
1197 if (pcurrent == NULL) {
1198 stderror(ERR_NAME | ERR_JOBCUR);
1199 /* NOTREACHED */
1200 }
1201 return (pcurrent);
1202 }
1203 if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) {
1204 if (pprevious == NULL) {
1205 stderror(ERR_NAME | ERR_JOBPREV);
1206 /* NOTREACHED */
1207 }
1208 return (pprevious);
1209 }
1210 if (Isdigit(cp[1])) {
1211 int idx = atoi(short2str(cp + 1));
1212
1213 for (pp = proclist.p_next; pp; pp = pp->p_next)
1214 if (pp->p_index == idx && pp->p_pid == pp->p_jobid)
1215 return (pp);
1216 stderror(ERR_NAME | ERR_NOSUCHJOB);
1217 /* NOTREACHED */
1218 }
1219 np = NULL;
1220 for (pp = proclist.p_next; pp; pp = pp->p_next)
1221 if (pp->p_pid == pp->p_jobid) {
1222 if (cp[1] == '?') {
1223 Char *dp;
1224
1225 for (dp = pp->p_command; *dp; dp++) {
1226 if (*dp != cp[2])
1227 continue;
1228 if (prefix(cp + 2, dp))
1229 goto match;
1230 }
1231 }
1232 else if (prefix(cp + 1, pp->p_command)) {
1233 match:
1234 if (np) {
1235 stderror(ERR_NAME | ERR_AMBIG);
1236 /* NOTREACHED */
1237 }
1238 np = pp;
1239 }
1240 }
1241 if (np)
1242 return (np);
1243 stderror(ERR_NAME | (cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB));
1244 /* NOTREACHED */
1245 return (0);
1246 }
1247
1248
1249 /*
1250 * pgetcurr - find most recent job that is not pp, preferably stopped
1251 */
1252 static struct process *
1253 pgetcurr(pp)
1254 struct process *pp;
1255 {
1256 struct process *np;
1257 struct process *xp = NULL;
1258
1259 for (np = proclist.p_next; np; np = np->p_next)
1260 if (np != pcurrent && np != pp && np->p_pid &&
1261 np->p_pid == np->p_jobid) {
1262 if (np->p_flags & PSTOPPED)
1263 return (np);
1264 if (xp == NULL)
1265 xp = np;
1266 }
1267 return (xp);
1268 }
1269
1270 /*
1271 * donotify - flag the job so as to report termination asynchronously
1272 */
1273 void
1274 /*ARGSUSED*/
1275 donotify(v, t)
1276 Char **v;
1277 struct command *t;
1278 {
1279 struct process *pp;
1280
1281 pp = pfind(*++v);
1282 pp->p_flags |= PNOTIFY;
1283 }
1284
1285 /*
1286 * Do the fork and whatever should be done in the child side that
1287 * should not be done if we are not forking at all (like for simple builtin's)
1288 * Also do everything that needs any signals fiddled with in the parent side
1289 *
1290 * Wanttty tells whether process and/or tty pgrps are to be manipulated:
1291 * -1: leave tty alone; inherit pgrp from parent
1292 * 0: already have tty; manipulate process pgrps only
1293 * 1: want to claim tty; manipulate process and tty pgrps
1294 * It is usually just the value of tpgrp.
1295 */
1296
1297 int
1298 pfork(t, wanttty)
1299 struct command *t; /* command we are forking for */
1300 int wanttty;
1301 {
1302 int pid;
1303 bool ignint = 0;
1304 int pgrp;
1305 sigset_t sigset, osigset;
1306
1307 /*
1308 * A child will be uninterruptible only under very special conditions.
1309 * Remember that the semantics of '&' is implemented by disconnecting the
1310 * process from the tty so signals do not need to ignored just for '&'.
1311 * Thus signals are set to default action for children unless: we have had
1312 * an "onintr -" (then specifically ignored) we are not playing with
1313 * signals (inherit action)
1314 */
1315 if (setintr)
1316 ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT))
1317 || (gointr && eq(gointr, STRminus));
1318 /*
1319 * Check for maximum nesting of 16 processes to avoid Forking loops
1320 */
1321 if (child == 16) {
1322 stderror(ERR_NESTING, 16);
1323 /* NOTREACHED */
1324 }
1325 /*
1326 * Hold SIGCHLD until we have the process installed in our table.
1327 */
1328 sigemptyset(&sigset);
1329 sigaddset(&sigset, SIGCHLD);
1330 sigprocmask(SIG_BLOCK, &sigset, &osigset);
1331 while ((pid = fork()) < 0)
1332 if (setintr == 0)
1333 (void) sleep(FORKSLEEP);
1334 else {
1335 sigprocmask(SIG_SETMASK, &osigset, NULL);
1336 stderror(ERR_NOPROC);
1337 /* NOTREACHED */
1338 }
1339 if (pid == 0) {
1340 settimes();
1341 pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
1342 pflushall();
1343 pcurrjob = NULL;
1344 child++;
1345 if (setintr) {
1346 setintr = 0; /* until I think otherwise */
1347 /*
1348 * Children just get blown away on SIGINT, SIGQUIT unless "onintr
1349 * -" seen.
1350 */
1351 (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
1352 (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
1353 if (wanttty >= 0) {
1354 /* make stoppable */
1355 (void) signal(SIGTSTP, SIG_DFL);
1356 (void) signal(SIGTTIN, SIG_DFL);
1357 (void) signal(SIGTTOU, SIG_DFL);
1358 }
1359 (void) signal(SIGTERM, parterm);
1360 }
1361 else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) {
1362 (void) signal(SIGINT, SIG_IGN);
1363 (void) signal(SIGQUIT, SIG_IGN);
1364 }
1365 pgetty(wanttty, pgrp);
1366 /*
1367 * Nohup and nice apply only to NODE_COMMAND's but it would be nice
1368 * (?!?) if you could say "nohup (foo;bar)" Then the parser would have
1369 * to know about nice/nohup/time
1370 */
1371 if (t->t_dflg & F_NOHUP)
1372 (void) signal(SIGHUP, SIG_IGN);
1373 if (t->t_dflg & F_NICE)
1374 (void) setpriority(PRIO_PROCESS, 0, t->t_nice);
1375 }
1376 else {
1377 if (wanttty >= 0)
1378 (void) setpgid(pid, pcurrjob ? pcurrjob->p_jobid : pid);
1379 palloc(pid, t);
1380 sigprocmask(SIG_SETMASK, &osigset, NULL);
1381 }
1382
1383 return (pid);
1384 }
1385
1386 static void
1387 okpcntl()
1388 {
1389 if (tpgrp == -1)
1390 stderror(ERR_JOBCONTROL);
1391 if (tpgrp == 0)
1392 stderror(ERR_JOBCTRLSUB);
1393 /* NOTREACHED */
1394 }
1395
1396 /*
1397 * if we don't have vfork(), things can still go in the wrong order
1398 * resulting in the famous 'Stopped (tty output)'. But some systems
1399 * don't permit the setpgid() call, (these are more recent secure
1400 * systems such as ibm's aix). Then we'd rather print an error message
1401 * than hang the shell!
1402 * I am open to suggestions how to fix that.
1403 */
1404 void
1405 pgetty(wanttty, pgrp)
1406 int wanttty, pgrp;
1407 {
1408 sigset_t sigset, osigset;
1409
1410 /*
1411 * christos: I am blocking the tty signals till I've set things
1412 * correctly....
1413 */
1414 if (wanttty > 0) {
1415 sigemptyset(&sigset);
1416 sigaddset(&sigset, SIGTSTP);
1417 sigaddset(&sigset, SIGTTIN);
1418 sigaddset(&sigset, SIGTTOU);
1419 sigprocmask(SIG_BLOCK, &sigset, &osigset);
1420 }
1421 /*
1422 * From: Michael Schroeder <mlschroe (at) immd4.informatik.uni-erlangen.de>
1423 * Don't check for tpgrp >= 0 so even non-interactive shells give
1424 * background jobs process groups Same for the comparison in the other part
1425 * of the #ifdef
1426 */
1427 if (wanttty >= 0)
1428 if (setpgid(0, pgrp) == -1) {
1429 (void) fprintf(csherr, "csh: setpgid error.\n");
1430 xexit(0);
1431 /* NOTREACHED */
1432 }
1433
1434 if (wanttty > 0) {
1435 (void) tcsetpgrp(FSHTTY, pgrp);
1436 sigprocmask(SIG_SETMASK, &osigset, NULL);
1437 }
1438
1439 if (tpgrp > 0)
1440 tpgrp = 0; /* gave tty away */
1441 }
1442