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