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