proc.c revision 1.17 1 /* $NetBSD: proc.c,v 1.17 1999/03/19 12:58:00 christos 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.17 1999/03/19 12:58:00 christos 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 int w;
95 int jobflags;
96 struct rusage ru;
97
98 loop:
99 errno = 0; /* reset, just in case */
100 pid = wait3(&w,
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 = WSTOPSIG(w);
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 (WTERMSIG(w) == SIGINT)
130 pp->p_flags |= PINTERRUPTED;
131 else
132 pp->p_flags |= PSIGNALED;
133 if (WCOREDUMP(w))
134 pp->p_flags |= PDUMPED;
135 pp->p_reason = WTERMSIG(w);
136 }
137 else {
138 pp->p_reason = WEXITSTATUS(w);
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 (void) sigaddset(&sigset, SIGCHLD);
216 for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) {
217 if (pp->p_flags & PNEEDNOTE) {
218 (void) 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 (void) 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 (void) sigaddset(&sigset, SIGCHLD);
243 (void) 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 (void) 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 (void) sigaddset(&sigset, SIGCHLD);
286 (void) sigprocmask(SIG_BLOCK, &sigset, &osigset);
287 for (;;) {
288 sigemptyset(&sigset);
289 (void) sigaddset(&sigset, SIGCHLD);
290 (void) 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 (void) sigdelset(&sigset, SIGCHLD);
303 (void) sigsuspend(&sigset);
304 }
305 (void) 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 }
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 struct process *pp;
363 sigset_t sigset, osigset;
364
365 pjobs++;
366 sigemptyset(&sigset);
367 (void) sigaddset(&sigset, SIGCHLD);
368 (void) 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 (void) sigsuspend(&sigset);
375 goto loop;
376 }
377 (void) 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 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 struct process *pp;
402 {
403 struct process *np;
404 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 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 struct command *t;
464 {
465 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 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 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 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, " %ld", (long)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 struct process *pp;
669 bool flag;
670 {
671 int 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, "%5ld ", (long)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 struct process *tp;
835 {
836 struct timeval tetime, diff;
837 static struct timeval ztime;
838 struct rusage ru;
839 static struct rusage zru;
840 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 struct process *pp;
863 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 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 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 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 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 int signum = SIGTERM;
976 char *name;
977
978 v++;
979 if (v[0] && v[0][0] == '-') {
980 if (v[0][1] == 'l') {
981 if (v[1]) {
982 if (!Isdigit(v[1][0]))
983 stderror(ERR_NAME | ERR_BADSIG);
984
985 signum = atoi(short2str(v[1]));
986 if (signum < 0 || signum >= NSIG)
987 stderror(ERR_NAME | ERR_BADSIG);
988 else if (signum == 0)
989 (void) fputc('0', cshout); /* 0's symbolic name is '0' */
990 else
991 (void) fprintf(cshout, "%s ", sys_signame[signum]);
992 } else {
993 for (signum = 1; signum < NSIG; signum++) {
994 (void) fprintf(cshout, "%s ", sys_signame[signum]);
995 if (signum == NSIG / 2)
996 (void) fputc('\n', cshout);
997 }
998 }
999 (void) fputc('\n', cshout);
1000 return;
1001 }
1002 if (Isdigit(v[0][1])) {
1003 signum = atoi(short2str(v[0] + 1));
1004 if (signum < 0 || signum > NSIG)
1005 stderror(ERR_NAME | ERR_BADSIG);
1006 }
1007 else {
1008 if (v[0][1] == 's' && (Isspace(v[0][2]) || v[0][2] == '\0'))
1009 v++;
1010 else
1011 (*v)++;
1012
1013 if (v[0] == NULL || v[1] == NULL)
1014 stderror(ERR_NAME | ERR_TOOFEW);
1015
1016 name = short2str(&v[0][0]);
1017 for (signum = 1; signum < NSIG; signum++)
1018 if (!strcasecmp(sys_signame[signum], name) ||
1019 (!strncasecmp("SIG", name, 3) && /* skip "SIG" prefix */
1020 !strcasecmp(sys_signame[signum], name + 3)))
1021 break;
1022
1023 if (signum == NSIG) {
1024 if (v[0][0] == '0')
1025 signum = 0;
1026 else {
1027 setname(vis_str(&v[0][0]));
1028 stderror(ERR_NAME | ERR_UNKSIG);
1029 }
1030 }
1031 }
1032 v++;
1033 }
1034 pkill(v, signum);
1035 }
1036
1037 static void
1038 pkill(v, signum)
1039 Char **v;
1040 int signum;
1041 {
1042 struct process *pp, *np;
1043 int jobflags = 0;
1044 int pid, err1 = 0;
1045 sigset_t sigset;
1046 Char *cp;
1047
1048 sigemptyset(&sigset);
1049 (void) sigaddset(&sigset, SIGCHLD);
1050 if (setintr)
1051 (void) sigaddset(&sigset, SIGINT);
1052 (void) sigprocmask(SIG_BLOCK, &sigset, NULL);
1053 gflag = 0, tglob(v);
1054 if (gflag) {
1055 v = globall(v);
1056 if (v == 0)
1057 stderror(ERR_NAME | ERR_NOMATCH);
1058 }
1059 else {
1060 v = gargv = saveblk(v);
1061 trim(v);
1062 }
1063
1064 while (v && (cp = *v)) {
1065 if (*cp == '%') {
1066 np = pp = pfind(cp);
1067 do
1068 jobflags |= np->p_flags;
1069 while ((np = np->p_friends) != pp);
1070 switch (signum) {
1071
1072 case SIGSTOP:
1073 case SIGTSTP:
1074 case SIGTTIN:
1075 case SIGTTOU:
1076 if ((jobflags & PRUNNING) == 0) {
1077 (void) fprintf(csherr, "%s: Already suspended\n",
1078 vis_str(cp));
1079 err1++;
1080 goto cont;
1081 }
1082 break;
1083 /*
1084 * suspend a process, kill -CONT %, then type jobs; the shell
1085 * says it is suspended, but it is running; thanks jaap..
1086 */
1087 case SIGCONT:
1088 pstart(pp, 0);
1089 goto cont;
1090 }
1091 if (kill(-pp->p_jobid, signum) < 0) {
1092 (void) fprintf(csherr, "%s: %s\n", vis_str(cp),
1093 strerror(errno));
1094 err1++;
1095 }
1096 if (signum == SIGTERM || signum == SIGHUP)
1097 (void) kill(-pp->p_jobid, SIGCONT);
1098 }
1099 else if (!(Isdigit(*cp) || *cp == '-'))
1100 stderror(ERR_NAME | ERR_JOBARGS);
1101 else {
1102 pid = atoi(short2str(cp));
1103 if (kill((pid_t) pid, signum) < 0) {
1104 (void) fprintf(csherr, "%d: %s\n", pid, strerror(errno));
1105 err1++;
1106 goto cont;
1107 }
1108 if (signum == SIGTERM || signum == SIGHUP)
1109 (void) kill((pid_t) pid, SIGCONT);
1110 }
1111 cont:
1112 v++;
1113 }
1114 if (gargv)
1115 blkfree(gargv), gargv = 0;
1116 (void) sigprocmask(SIG_UNBLOCK, &sigset, NULL);
1117 if (err1)
1118 stderror(ERR_SILENT);
1119 }
1120
1121 /*
1122 * pstart - start the job in foreground/background
1123 */
1124 void
1125 pstart(pp, foregnd)
1126 struct process *pp;
1127 int foregnd;
1128 {
1129 struct process *np;
1130 sigset_t sigset, osigset;
1131 long jobflags = 0;
1132
1133 sigemptyset(&sigset);
1134 (void) sigaddset(&sigset, SIGCHLD);
1135 (void) sigprocmask(SIG_BLOCK, &sigset, &osigset);
1136 np = pp;
1137 do {
1138 jobflags |= np->p_flags;
1139 if (np->p_flags & (PRUNNING | PSTOPPED)) {
1140 np->p_flags |= PRUNNING;
1141 np->p_flags &= ~PSTOPPED;
1142 if (foregnd)
1143 np->p_flags |= PFOREGND;
1144 else
1145 np->p_flags &= ~PFOREGND;
1146 }
1147 } while ((np = np->p_friends) != pp);
1148 if (!foregnd)
1149 pclrcurr(pp);
1150 (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND);
1151 if (foregnd)
1152 (void) tcsetpgrp(FSHTTY, pp->p_jobid);
1153 if (jobflags & PSTOPPED)
1154 (void) kill(-pp->p_jobid, SIGCONT);
1155 (void) sigprocmask(SIG_SETMASK, &osigset, NULL);
1156 }
1157
1158 void
1159 panystop(neednl)
1160 bool neednl;
1161 {
1162 struct process *pp;
1163
1164 chkstop = 2;
1165 for (pp = proclist.p_next; pp; pp = pp->p_next)
1166 if (pp->p_flags & PSTOPPED)
1167 stderror(ERR_STOPPED, neednl ? "\n" : "");
1168 }
1169
1170 struct process *
1171 pfind(cp)
1172 Char *cp;
1173 {
1174 struct process *pp, *np;
1175
1176 if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) {
1177 if (pcurrent == NULL)
1178 stderror(ERR_NAME | ERR_JOBCUR);
1179 return (pcurrent);
1180 }
1181 if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) {
1182 if (pprevious == NULL)
1183 stderror(ERR_NAME | ERR_JOBPREV);
1184 return (pprevious);
1185 }
1186 if (Isdigit(cp[1])) {
1187 int idx = atoi(short2str(cp + 1));
1188
1189 for (pp = proclist.p_next; pp; pp = pp->p_next)
1190 if (pp->p_index == idx && pp->p_pid == pp->p_jobid)
1191 return (pp);
1192 stderror(ERR_NAME | ERR_NOSUCHJOB);
1193 }
1194 np = NULL;
1195 for (pp = proclist.p_next; pp; pp = pp->p_next)
1196 if (pp->p_pid == pp->p_jobid) {
1197 if (cp[1] == '?') {
1198 Char *dp;
1199
1200 for (dp = pp->p_command; *dp; dp++) {
1201 if (*dp != cp[2])
1202 continue;
1203 if (prefix(cp + 2, dp))
1204 goto match;
1205 }
1206 }
1207 else if (prefix(cp + 1, pp->p_command)) {
1208 match:
1209 if (np)
1210 stderror(ERR_NAME | ERR_AMBIG);
1211 np = pp;
1212 }
1213 }
1214 if (np)
1215 return (np);
1216 stderror(ERR_NAME | (cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB));
1217 /* NOTREACHED */
1218 }
1219
1220
1221 /*
1222 * pgetcurr - find most recent job that is not pp, preferably stopped
1223 */
1224 static struct process *
1225 pgetcurr(pp)
1226 struct process *pp;
1227 {
1228 struct process *np;
1229 struct process *xp = NULL;
1230
1231 for (np = proclist.p_next; np; np = np->p_next)
1232 if (np != pcurrent && np != pp && np->p_pid &&
1233 np->p_pid == np->p_jobid) {
1234 if (np->p_flags & PSTOPPED)
1235 return (np);
1236 if (xp == NULL)
1237 xp = np;
1238 }
1239 return (xp);
1240 }
1241
1242 /*
1243 * donotify - flag the job so as to report termination asynchronously
1244 */
1245 void
1246 /*ARGSUSED*/
1247 donotify(v, t)
1248 Char **v;
1249 struct command *t;
1250 {
1251 struct process *pp;
1252
1253 pp = pfind(*++v);
1254 pp->p_flags |= PNOTIFY;
1255 }
1256
1257 /*
1258 * Do the fork and whatever should be done in the child side that
1259 * should not be done if we are not forking at all (like for simple builtin's)
1260 * Also do everything that needs any signals fiddled with in the parent side
1261 *
1262 * Wanttty tells whether process and/or tty pgrps are to be manipulated:
1263 * -1: leave tty alone; inherit pgrp from parent
1264 * 0: already have tty; manipulate process pgrps only
1265 * 1: want to claim tty; manipulate process and tty pgrps
1266 * It is usually just the value of tpgrp.
1267 */
1268
1269 int
1270 pfork(t, wanttty)
1271 struct command *t; /* command we are forking for */
1272 int wanttty;
1273 {
1274 int pid;
1275 bool ignint = 0;
1276 int pgrp;
1277 sigset_t sigset, osigset;
1278
1279 /*
1280 * A child will be uninterruptible only under very special conditions.
1281 * Remember that the semantics of '&' is implemented by disconnecting the
1282 * process from the tty so signals do not need to ignored just for '&'.
1283 * Thus signals are set to default action for children unless: we have had
1284 * an "onintr -" (then specifically ignored) we are not playing with
1285 * signals (inherit action)
1286 */
1287 if (setintr)
1288 ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT))
1289 || (gointr && eq(gointr, STRminus));
1290 /*
1291 * Check for maximum nesting of 16 processes to avoid Forking loops
1292 */
1293 if (child == 16)
1294 stderror(ERR_NESTING, 16);
1295 /*
1296 * Hold SIGCHLD until we have the process installed in our table.
1297 */
1298 sigemptyset(&sigset);
1299 (void) sigaddset(&sigset, SIGCHLD);
1300 (void) sigprocmask(SIG_BLOCK, &sigset, &osigset);
1301 while ((pid = fork()) < 0)
1302 if (setintr == 0)
1303 (void) sleep(FORKSLEEP);
1304 else {
1305 (void) sigprocmask(SIG_SETMASK, &osigset, NULL);
1306 stderror(ERR_NOPROC);
1307 }
1308 if (pid == 0) {
1309 settimes();
1310 pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
1311 pflushall();
1312 pcurrjob = NULL;
1313 child++;
1314 if (setintr) {
1315 setintr = 0; /* until I think otherwise */
1316 /*
1317 * Children just get blown away on SIGINT, SIGQUIT unless "onintr
1318 * -" seen.
1319 */
1320 (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
1321 (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
1322 if (wanttty >= 0) {
1323 /* make stoppable */
1324 (void) signal(SIGTSTP, SIG_DFL);
1325 (void) signal(SIGTTIN, SIG_DFL);
1326 (void) signal(SIGTTOU, SIG_DFL);
1327 }
1328 (void) signal(SIGTERM, parterm);
1329 }
1330 else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) {
1331 (void) signal(SIGINT, SIG_IGN);
1332 (void) signal(SIGQUIT, SIG_IGN);
1333 }
1334 pgetty(wanttty, pgrp);
1335 /*
1336 * Nohup and nice apply only to NODE_COMMAND's but it would be nice
1337 * (?!?) if you could say "nohup (foo;bar)" Then the parser would have
1338 * to know about nice/nohup/time
1339 */
1340 if (t->t_dflg & F_NOHUP)
1341 (void) signal(SIGHUP, SIG_IGN);
1342 if (t->t_dflg & F_NICE)
1343 (void) setpriority(PRIO_PROCESS, 0, t->t_nice);
1344 }
1345 else {
1346 if (wanttty >= 0)
1347 (void) setpgid(pid, pcurrjob ? pcurrjob->p_jobid : pid);
1348 palloc(pid, t);
1349 (void) sigprocmask(SIG_SETMASK, &osigset, NULL);
1350 }
1351
1352 return (pid);
1353 }
1354
1355 static void
1356 okpcntl()
1357 {
1358 if (tpgrp == -1)
1359 stderror(ERR_JOBCONTROL);
1360 if (tpgrp == 0)
1361 stderror(ERR_JOBCTRLSUB);
1362 /* NOTREACHED */
1363 }
1364
1365 /*
1366 * if we don't have vfork(), things can still go in the wrong order
1367 * resulting in the famous 'Stopped (tty output)'. But some systems
1368 * don't permit the setpgid() call, (these are more recent secure
1369 * systems such as ibm's aix). Then we'd rather print an error message
1370 * than hang the shell!
1371 * I am open to suggestions how to fix that.
1372 */
1373 void
1374 pgetty(wanttty, pgrp)
1375 int wanttty, pgrp;
1376 {
1377 sigset_t sigset, osigset;
1378
1379 /*
1380 * christos: I am blocking the tty signals till I've set things
1381 * correctly....
1382 */
1383 if (wanttty > 0) {
1384 sigemptyset(&sigset);
1385 (void) sigaddset(&sigset, SIGTSTP);
1386 (void) sigaddset(&sigset, SIGTTIN);
1387 (void) sigaddset(&sigset, SIGTTOU);
1388 (void) sigprocmask(SIG_BLOCK, &sigset, &osigset);
1389 }
1390 /*
1391 * From: Michael Schroeder <mlschroe (at) immd4.informatik.uni-erlangen.de>
1392 * Don't check for tpgrp >= 0 so even non-interactive shells give
1393 * background jobs process groups Same for the comparison in the other part
1394 * of the #ifdef
1395 */
1396 if (wanttty >= 0)
1397 if (setpgid(0, pgrp) == -1) {
1398 (void) fprintf(csherr, "csh: setpgid error.\n");
1399 xexit(0);
1400 }
1401
1402 if (wanttty > 0) {
1403 (void) tcsetpgrp(FSHTTY, pgrp);
1404 (void) sigprocmask(SIG_SETMASK, &osigset, NULL);
1405 }
1406
1407 if (tpgrp > 0)
1408 tpgrp = 0; /* gave tty away */
1409 }
1410