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