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