do not lock vnode while doing VFS_STATFS
[unix-history] / usr / src / bin / csh / proc.c
CommitLineData
b79f4fa9
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
094e80ed 3 * All rights reserved. The Berkeley Software License Agreement
b79f4fa9
DF
4 * specifies the terms and conditions for redistribution.
5 */
6
35371dec 7#ifndef lint
fad613b5 8static char *sccsid = "@(#)proc.c 5.10 (Berkeley) %G%";
094e80ed 9#endif
2d4bbda8
BJ
10
11#include "sh.h"
12#include "sh.dir.h"
13#include "sh.proc.h"
3ffa6b49 14#include <sys/wait.h>
2d4bbda8
BJ
15#include <sys/ioctl.h>
16
17/*
18 * C Shell - functions that manage processes, handling hanging, termination
19 */
20
21#define BIGINDEX 9 /* largest desirable job index */
22
23/*
24 * pchild - called at interrupt level by the SIGCHLD signal
25 * indicating that at least one child has terminated or stopped
26 * thus at least one wait system call will definitely return a
27 * childs status. Top level routines (like pwait) must be sure
28 * to mask interrupts when playing with the proclist data structures!
29 */
30pchild()
31{
32 register struct process *pp;
33 register struct process *fp;
34 register int pid;
35 union wait w;
36 int jobflags;
ea775389 37 struct rusage ru;
470cb5e7 38 extern int insource;
2d4bbda8 39
2d4bbda8 40loop:
470cb5e7 41 pid = wait3(&w, (setintr && (intty || insource) ? WNOHANG|WUNTRACED:WNOHANG), &ru);
2d4bbda8
BJ
42 if (pid <= 0) {
43 if (errno == EINTR) {
44 errno = 0;
45 goto loop;
46 }
47 pnoprocesses = pid == -1;
48 return;
49 }
50 for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
51 if (pid == pp->p_pid)
52 goto found;
53 goto loop;
54found:
55 if (pid == atoi(value("child")))
56 unsetv("child");
57 pp->p_flags &= ~(PRUNNING|PSTOPPED|PREPORTED);
58 if (WIFSTOPPED(w)) {
59 pp->p_flags |= PSTOPPED;
60 pp->p_reason = w.w_stopsig;
61 } else {
35371dec
EW
62 if (pp->p_flags & (PTIME|PPTIME) || adrof("time"))
63 (void) gettimeofday(&pp->p_etime, (struct timezone *)0);
ea775389 64 pp->p_rusage = ru;
2d4bbda8
BJ
65 if (WIFSIGNALED(w)) {
66 if (w.w_termsig == SIGINT)
67 pp->p_flags |= PINTERRUPTED;
68 else
69 pp->p_flags |= PSIGNALED;
70 if (w.w_coredump)
71 pp->p_flags |= PDUMPED;
72 pp->p_reason = w.w_termsig;
73 } else {
74 pp->p_reason = w.w_retcode;
2d4bbda8 75 if (pp->p_reason != 0)
2d4bbda8
BJ
76 pp->p_flags |= PAEXITED;
77 else
78 pp->p_flags |= PNEXITED;
79 }
80 }
81 jobflags = 0;
82 fp = pp;
83 do {
84 if ((fp->p_flags & (PPTIME|PRUNNING|PSTOPPED)) == 0 &&
85 !child && adrof("time") &&
35371dec 86 fp->p_rusage.ru_utime.tv_sec+fp->p_rusage.ru_stime.tv_sec >=
2d4bbda8
BJ
87 atoi(value("time")))
88 fp->p_flags |= PTIME;
89 jobflags |= fp->p_flags;
90 } while ((fp = fp->p_friends) != pp);
91 pp->p_flags &= ~PFOREGND;
92 if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
93 pp->p_flags &= ~PPTIME;
94 pp->p_flags |= PTIME;
95 }
96 if ((jobflags & (PRUNNING|PREPORTED)) == 0) {
97 fp = pp;
98 do {
99 if (fp->p_flags&PSTOPPED)
100 fp->p_flags |= PREPORTED;
101 } while((fp = fp->p_friends) != pp);
102 while(fp->p_pid != fp->p_jobid)
103 fp = fp->p_friends;
a132d4ed
BJ
104 if (jobflags&PSTOPPED) {
105 if (pcurrent && pcurrent != fp)
106 pprevious = pcurrent;
107 pcurrent = fp;
108 } else
109 pclrcurr(fp);
2d4bbda8 110 if (jobflags&PFOREGND) {
2d4bbda8
BJ
111 if (jobflags & (PSIGNALED|PSTOPPED|PPTIME) ||
112#ifdef IIASA
113 jobflags & PAEXITED ||
114#endif
115 !eq(dcwd->di_name, fp->p_cwd->di_name)) {
401149be 116 ; /* print in pjwait */
b3409321
BJ
117 }
118/*
119 else if ((jobflags & (PTIME|PSTOPPED)) == PTIME)
2d4bbda8 120 ptprint(fp);
b3409321 121*/
2d4bbda8
BJ
122 } else {
123 if (jobflags&PNOTIFY || adrof("notify")) {
124 printf("\215\n");
35371dec 125 (void) pprint(pp, NUMBER|NAME|REASON);
2d4bbda8
BJ
126 if ((jobflags&PSTOPPED) == 0)
127 pflush(pp);
128 } else {
2d4bbda8
BJ
129 fp->p_flags |= PNEEDNOTE;
130 neednote++;
131 }
132 }
133 }
134 goto loop;
135}
136
137pnote()
138{
139 register struct process *pp;
1f7b623f
KB
140 int flags;
141 long omask;
2d4bbda8
BJ
142
143 neednote = 0;
144 for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) {
145 if (pp->p_flags & PNEEDNOTE) {
d33af40e 146 omask = sigblock(sigmask(SIGCHLD));
2d4bbda8
BJ
147 pp->p_flags &= ~PNEEDNOTE;
148 flags = pprint(pp, NUMBER|NAME|REASON);
149 if ((flags&(PRUNNING|PSTOPPED)) == 0)
150 pflush(pp);
35371dec 151 (void) sigsetmask(omask);
2d4bbda8
BJ
152 }
153 }
154}
155
156/*
157 * pwait - wait for current job to terminate, maintaining integrity
158 * of current and previous job indicators.
159 */
160pwait()
161{
162 register struct process *fp, *pp;
1f7b623f 163 long omask;
2d4bbda8
BJ
164
165 /*
166 * Here's where dead procs get flushed.
167 */
d33af40e 168 omask = sigblock(sigmask(SIGCHLD));
2d4bbda8
BJ
169 for (pp = (fp = &proclist)->p_next; pp != PNULL; pp = (fp = pp)->p_next)
170 if (pp->p_pid == 0) {
171 fp->p_next = pp->p_next;
172 xfree(pp->p_command);
173 if (pp->p_cwd && --pp->p_cwd->di_count == 0)
174 if (pp->p_cwd->di_next == 0)
175 dfree(pp->p_cwd);
176 xfree((char *)pp);
177 pp = fp;
178 }
35371dec 179 (void) sigsetmask(omask);
2d4bbda8
BJ
180 pjwait(pcurrjob);
181}
182
183/*
184 * pjwait - wait for a job to finish or become stopped
185 * It is assumed to be in the foreground state (PFOREGND)
186 */
187pjwait(pp)
188 register struct process *pp;
189{
190 register struct process *fp;
1f7b623f
KB
191 int jobflags, reason;
192 long omask;
d33af40e 193
525f24a3
SL
194 while (pp->p_pid != pp->p_jobid)
195 pp = pp->p_friends;
2d4bbda8
BJ
196 fp = pp;
197 do {
198 if ((fp->p_flags&(PFOREGND|PRUNNING)) == PRUNNING)
199 printf("BUG: waiting for background job!\n");
200 } while ((fp = fp->p_friends) != pp);
201 /*
202 * Now keep pausing as long as we are not interrupted (SIGINT),
203 * and the target process, or any of its friends, are running
204 */
205 fp = pp;
d33af40e 206 omask = sigblock(sigmask(SIGCHLD));
2d4bbda8 207 for (;;) {
2d4bbda8
BJ
208 jobflags = 0;
209 do
210 jobflags |= fp->p_flags;
d33af40e 211 while ((fp = (fp->p_friends)) != pp);
2d4bbda8
BJ
212 if ((jobflags & PRUNNING) == 0)
213 break;
1f7b623f 214 sigpause(sigblock(0L) &~ sigmask(SIGCHLD));
2d4bbda8 215 }
35371dec
EW
216 (void) sigsetmask(omask);
217 if (tpgrp > 0) /* get tty back */
218 (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&tpgrp);
cd4a3dcb
BJ
219 if ((jobflags&(PSIGNALED|PSTOPPED|PTIME)) ||
220 !eq(dcwd->di_name, fp->p_cwd->di_name)) {
221 if (jobflags&PSTOPPED)
222 printf("\n");
35371dec 223 (void) pprint(pp, AREASON|SHELLDIR);
cd4a3dcb 224 }
401149be 225 if ((jobflags&(PINTERRUPTED|PSTOPPED)) && setintr &&
2d4bbda8 226 (!gointr || !eq(gointr, "-"))) {
401149be
BJ
227 if ((jobflags & PSTOPPED) == 0)
228 pflush(pp);
401149be 229 pintr1(0);
2d4bbda8
BJ
230 /*NOTREACHED*/
231 }
232 reason = 0;
233 fp = pp;
234 do {
235 if (fp->p_reason)
236 reason = fp->p_flags & (PSIGNALED|PINTERRUPTED) ?
237 fp->p_reason | QUOTE : fp->p_reason;
238 } while ((fp = fp->p_friends) != pp);
239 set("status", putn(reason));
240 if (reason && exiterr)
241 exitstat();
242 pflush(pp);
243}
244
245/*
246 * dowait - wait for all processes to finish
247 */
248dowait()
249{
250 register struct process *pp;
1f7b623f 251 long omask;
2d4bbda8
BJ
252
253 pjobs++;
d33af40e 254 omask = sigblock(sigmask(SIGCHLD));
2d4bbda8 255loop:
2d4bbda8 256 for (pp = proclist.p_next; pp; pp = pp->p_next)
525f24a3 257 if (pp->p_pid && /* pp->p_pid == pp->p_jobid && */
2d4bbda8 258 pp->p_flags&PRUNNING) {
1f7b623f 259 sigpause(0L);
2d4bbda8
BJ
260 goto loop;
261 }
35371dec 262 (void) sigsetmask(omask);
2d4bbda8
BJ
263 pjobs = 0;
264}
265
266/*
267 * pflushall - flush all jobs from list (e.g. at fork())
268 */
269pflushall()
270{
271 register struct process *pp;
272
273 for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
274 if (pp->p_pid)
275 pflush(pp);
276}
277
278/*
279 * pflush - flag all process structures in the same job as the
280 * the argument process for deletion. The actual free of the
281 * space is not done here since pflush is called at interrupt level.
282 */
283pflush(pp)
284 register struct process *pp;
285{
286 register struct process *np;
287 register int index;
288
289 if (pp->p_pid == 0) {
290 printf("BUG: process flushed twice");
291 return;
292 }
293 while (pp->p_pid != pp->p_jobid)
294 pp = pp->p_friends;
295 pclrcurr(pp);
296 if (pp == pcurrjob)
297 pcurrjob = 0;
298 index = pp->p_index;
299 np = pp;
300 do {
301 np->p_index = np->p_pid = 0;
302 np->p_flags &= ~PNEEDNOTE;
303 } while ((np = np->p_friends) != pp);
304 if (index == pmaxindex) {
305 for (np = proclist.p_next, index = 0; np; np = np->p_next)
306 if (np->p_index > index)
307 index = np->p_index;
308 pmaxindex = index;
309 }
310}
311
312/*
313 * pclrcurr - make sure the given job is not the current or previous job;
314 * pp MUST be the job leader
315 */
316pclrcurr(pp)
317 register struct process *pp;
318{
319
320 if (pp == pcurrent)
321 if (pprevious != PNULL) {
322 pcurrent = pprevious;
323 pprevious = pgetcurr(pp);
324 } else {
325 pcurrent = pgetcurr(pp);
326 pprevious = pgetcurr(pp);
327 }
328 else if (pp == pprevious)
329 pprevious = pgetcurr(pp);
330}
331
332/* +4 here is 1 for '\0', 1 ea for << >& >> */
333char command[PMAXLEN+4];
334int cmdlen;
335char *cmdp;
336/*
337 * palloc - allocate a process structure and fill it up.
338 * an important assumption is made that the process is running.
339 */
340palloc(pid, t)
341 int pid;
342 register struct command *t;
343{
344 register struct process *pp;
345 int i;
346
347 pp = (struct process *)calloc(1, sizeof(struct process));
348 pp->p_pid = pid;
349 pp->p_flags = t->t_dflg & FAND ? PRUNNING : PRUNNING|PFOREGND;
350 if (t->t_dflg & FTIME)
351 pp->p_flags |= PPTIME;
352 cmdp = command;
353 cmdlen = 0;
354 padd(t);
355 *cmdp++ = 0;
356 if (t->t_dflg & FPOU) {
357 pp->p_flags |= PPOU;
358 if (t->t_dflg & FDIAG)
359 pp->p_flags |= PDIAG;
360 }
361 pp->p_command = savestr(command);
362 if (pcurrjob) {
363 struct process *fp;
364 /* careful here with interrupt level */
365 pp->p_cwd = 0;
366 pp->p_index = pcurrjob->p_index;
367 pp->p_friends = pcurrjob;
368 pp->p_jobid = pcurrjob->p_pid;
369 for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
370 ;
371 fp->p_friends = pp;
372 } else {
373 pcurrjob = pp;
374 pp->p_jobid = pid;
375 pp->p_friends = pp;
376 pp->p_cwd = dcwd;
377 dcwd->di_count++;
378 if (pmaxindex < BIGINDEX)
379 pp->p_index = ++pmaxindex;
380 else {
381 struct process *np;
382
383 for (i = 1; ; i++) {
384 for (np = proclist.p_next; np; np = np->p_next)
385 if (np->p_index == i)
386 goto tryagain;
a132d4ed
BJ
387 pp->p_index = i;
388 if (i > pmaxindex)
389 pmaxindex = i;
2d4bbda8
BJ
390 break;
391 tryagain:;
392 }
393 }
394 if (pcurrent == PNULL)
395 pcurrent = pp;
396 else if (pprevious == PNULL)
397 pprevious = pp;
398 }
399 pp->p_next = proclist.p_next;
400 proclist.p_next = pp;
35371dec 401 (void) gettimeofday(&pp->p_btime, (struct timezone *)0);
2d4bbda8
BJ
402}
403
404padd(t)
405 register struct command *t;
406{
407 char **argp;
408
409 if (t == 0)
410 return;
411 switch (t->t_dtyp) {
412
413 case TPAR:
414 pads("( ");
415 padd(t->t_dspr);
416 pads(" )");
417 break;
418
419 case TCOM:
420 for (argp = t->t_dcom; *argp; argp++) {
421 pads(*argp);
422 if (argp[1])
423 pads(" ");
424 }
425 break;
426
1544707d
EW
427 case TOR:
428 case TAND:
2d4bbda8 429 case TFIL:
2d4bbda8
BJ
430 case TLST:
431 padd(t->t_dcar);
1544707d
EW
432 switch (t->t_dtyp) {
433 case TOR:
434 pads(" || ");
435 break;
436 case TAND:
437 pads(" && ");
438 break;
439 case TFIL:
440 pads(" | ");
441 break;
442 case TLST:
443 pads("; ");
444 break;
445 }
2d4bbda8
BJ
446 padd(t->t_dcdr);
447 return;
448 }
449 if ((t->t_dflg & FPIN) == 0 && t->t_dlef) {
450 pads((t->t_dflg & FHERE) ? " << " : " < ");
451 pads(t->t_dlef);
452 }
453 if ((t->t_dflg & FPOU) == 0 && t->t_drit) {
454 pads((t->t_dflg & FCAT) ? " >>" : " >");
455 if (t->t_dflg & FDIAG)
456 pads("&");
457 pads(" ");
458 pads(t->t_drit);
459 }
460}
461
462pads(cp)
463 char *cp;
464{
465 register int i = strlen(cp);
466
467 if (cmdlen >= PMAXLEN)
468 return;
469 if (cmdlen + i >= PMAXLEN) {
35371dec 470 (void) strcpy(cmdp, " ...");
2d4bbda8
BJ
471 cmdlen = PMAXLEN;
472 cmdp += 4;
473 return;
474 }
35371dec 475 (void) strcpy(cmdp, cp);
2d4bbda8
BJ
476 cmdp += i;
477 cmdlen += i;
478}
479
480/*
481 * psavejob - temporarily save the current job on a one level stack
482 * so another job can be created. Used for { } in exp6
483 * and `` in globbing.
484 */
485psavejob()
486{
487
488 pholdjob = pcurrjob;
489 pcurrjob = PNULL;
490}
491
492/*
493 * prestjob - opposite of psavejob. This may be missed if we are interrupted
494 * somewhere, but pendjob cleans up anyway.
495 */
496prestjob()
497{
498
499 pcurrjob = pholdjob;
500 pholdjob = PNULL;
501}
502
503/*
504 * pendjob - indicate that a job (set of commands) has been completed
505 * or is about to begin.
506 */
507pendjob()
508{
509 register struct process *pp, *tp;
510
511 if (pcurrjob && (pcurrjob->p_flags&(PFOREGND|PSTOPPED)) == 0) {
512 pp = pcurrjob;
513 while (pp->p_pid != pp->p_jobid)
514 pp = pp->p_friends;
515 printf("[%d]", pp->p_index);
516 tp = pp;
517 do {
518 printf(" %d", pp->p_pid);
519 pp = pp->p_friends;
520 } while (pp != tp);
521 printf("\n");
522 }
523 pholdjob = pcurrjob = 0;
524}
525
526/*
527 * pprint - print a job
528 */
529pprint(pp, flag)
530 register struct process *pp;
531{
532 register status, reason;
533 struct process *tp;
534 extern char *linp, linbuf[];
535 int jobflags, pstatus;
536 char *format;
537
538 while (pp->p_pid != pp->p_jobid)
539 pp = pp->p_friends;
540 if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
541 pp->p_flags &= ~PPTIME;
542 pp->p_flags |= PTIME;
543 }
544 tp = pp;
545 status = reason = -1;
546 jobflags = 0;
547 do {
548 jobflags |= pp->p_flags;
549 pstatus = pp->p_flags & PALLSTATES;
550 if (tp != pp && linp != linbuf && !(flag&FANCY) &&
551 (pstatus == status && pp->p_reason == reason ||
552 !(flag&REASON)))
553 printf(" ");
554 else {
555 if (tp != pp && linp != linbuf)
556 printf("\n");
557 if(flag&NUMBER)
558 if (pp == tp)
559 printf("[%d]%s %c ", pp->p_index,
560 pp->p_index < 10 ? " " : "",
561 pp==pcurrent ? '+' :
562 (pp == pprevious ? '-' : ' '));
563 else
564 printf(" ");
565 if (flag&FANCY)
566 printf("%5d ", pp->p_pid);
567 if (flag&(REASON|AREASON)) {
568 if (flag&NAME)
9c279653 569 format = "%-23s";
2d4bbda8
BJ
570 else
571 format = "%s";
572 if (pstatus == status)
573 if (pp->p_reason == reason) {
574 printf(format, "");
575 goto prcomd;
576 } else
577 reason = pp->p_reason;
578 else {
579 status = pstatus;
580 reason = pp->p_reason;
581 }
582 switch (status) {
583
584 case PRUNNING:
585 printf(format, "Running ");
586 break;
587
588 case PINTERRUPTED:
589 case PSTOPPED:
590 case PSIGNALED:
793f6534
JL
591 if ((flag&(REASON|AREASON))
592 && reason != SIGINT
593 && reason != SIGPIPE)
2d4bbda8
BJ
594 printf(format, mesg[pp->p_reason].pname);
595 break;
596
597 case PNEXITED:
598 case PAEXITED:
599 if (flag & REASON)
600 if (pp->p_reason)
601 printf("Exit %-16d", pp->p_reason);
602 else
603 printf(format, "Done");
604 break;
605
606 default:
607 printf("BUG: status=%-9o", status);
608 }
609 }
610 }
611prcomd:
612 if (flag&NAME) {
613 printf("%s", pp->p_command);
614 if (pp->p_flags & PPOU)
615 printf(" |");
616 if (pp->p_flags & PDIAG)
617 printf("&");
618 }
619 if (flag&(REASON|AREASON) && pp->p_flags&PDUMPED)
620 printf(" (core dumped)");
621 if (tp == pp->p_friends) {
622 if (flag&AMPERSAND)
623 printf(" &");
624 if (flag&JOBDIR &&
625 !eq(tp->p_cwd->di_name, dcwd->di_name)) {
626 printf(" (wd: ");
627 dtildepr(value("home"), tp->p_cwd->di_name);
628 printf(")");
629 }
630 }
631 if (pp->p_flags&PPTIME && !(status&(PSTOPPED|PRUNNING))) {
632 if (linp != linbuf)
633 printf("\n\t");
ea775389 634 { static struct rusage zru;
ae3d9709
SL
635 prusage(&zru, &pp->p_rusage, &pp->p_etime,
636 &pp->p_btime);
ea775389 637 }
2d4bbda8
BJ
638 }
639 if (tp == pp->p_friends) {
640 if (linp != linbuf)
641 printf("\n");
642 if (flag&SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
643 printf("(wd now: ");
644 dtildepr(value("home"), dcwd->di_name);
645 printf(")\n");
646 }
647 }
648 } while ((pp = pp->p_friends) != tp);
649 if (jobflags&PTIME && (jobflags&(PSTOPPED|PRUNNING)) == 0) {
650 if (jobflags & NUMBER)
651 printf(" ");
652 ptprint(tp);
653 }
654 return (jobflags);
655}
656
657ptprint(tp)
658 register struct process *tp;
659{
ae3d9709
SL
660 struct timeval tetime, diff;
661 static struct timeval ztime;
ea775389
SL
662 struct rusage ru;
663 static struct rusage zru;
2d4bbda8
BJ
664 register struct process *pp = tp;
665
ea775389 666 ru = zru;
ae3d9709 667 tetime = ztime;
2d4bbda8 668 do {
ea775389 669 ruadd(&ru, &pp->p_rusage);
ae3d9709
SL
670 tvsub(&diff, &pp->p_etime, &pp->p_btime);
671 if (timercmp(&diff, &tetime, >))
672 tetime = diff;
2d4bbda8 673 } while ((pp = pp->p_friends) != tp);
ae3d9709 674 prusage(&zru, &ru, &tetime, &ztime);
2d4bbda8
BJ
675}
676
677/*
678 * dojobs - print all jobs
679 */
680dojobs(v)
681 char **v;
682{
683 register struct process *pp;
684 register int flag = NUMBER|NAME|REASON;
685 int i;
686
687 if (chkstop)
688 chkstop = 2;
689 if (*++v) {
690 if (v[1] || !eq(*v, "-l"))
691 error("Usage: jobs [ -l ]");
692 flag |= FANCY|JOBDIR;
693 }
694 for (i = 1; i <= pmaxindex; i++)
695 for (pp = proclist.p_next; pp; pp = pp->p_next)
696 if (pp->p_index == i && pp->p_pid == pp->p_jobid) {
697 pp->p_flags &= ~PNEEDNOTE;
698 if (!(pprint(pp, flag) & (PRUNNING|PSTOPPED)))
699 pflush(pp);
700 break;
701 }
702}
703
704/*
705 * dofg - builtin - put the job into the foreground
706 */
707dofg(v)
708 char **v;
709{
710 register struct process *pp;
711
712 okpcntl();
713 ++v;
714 do {
715 pp = pfind(*v);
716 pstart(pp, 1);
2d4bbda8
BJ
717 pjwait(pp);
718 } while (*v && *++v);
719}
720
721/*
722 * %... - builtin - put the job into the foreground
723 */
724dofg1(v)
725 char **v;
726{
727 register struct process *pp;
728
729 okpcntl();
730 pp = pfind(v[0]);
731 pstart(pp, 1);
2d4bbda8
BJ
732 pjwait(pp);
733}
734
735/*
736 * dobg - builtin - put the job into the background
737 */
738dobg(v)
739 char **v;
740{
741 register struct process *pp;
742
743 okpcntl();
744 ++v;
745 do {
746 pp = pfind(*v);
747 pstart(pp, 0);
748 } while (*v && *++v);
749}
750
751/*
752 * %... & - builtin - put the job into the background
753 */
754dobg1(v)
755 char **v;
756{
757 register struct process *pp;
758
759 pp = pfind(v[0]);
760 pstart(pp, 0);
761}
762
763/*
764 * dostop - builtin - stop the job
765 */
766dostop(v)
767 char **v;
768{
769
770 pkill(++v, SIGSTOP);
771}
772
773/*
774 * dokill - builtin - superset of kill (1)
775 */
776dokill(v)
777 char **v;
778{
779 register int signum;
780 register char *name;
781
782 v++;
783 if (v[0] && v[0][0] == '-') {
784 if (v[0][1] == 'l') {
785 for (signum = 1; signum <= NSIG; signum++) {
786 if (name = mesg[signum].iname)
787 printf("%s ", name);
788 if (signum == 16)
fad613b5 789 cshputchar('\n');
2d4bbda8 790 }
fad613b5 791 cshputchar('\n');
2d4bbda8
BJ
792 return;
793 }
794 if (digit(v[0][1])) {
795 signum = atoi(v[0]+1);
793f6534 796 if (signum < 0 || signum > NSIG)
2d4bbda8
BJ
797 bferr("Bad signal number");
798 } else {
799 name = &v[0][1];
800 for (signum = 1; signum <= NSIG; signum++)
801 if (mesg[signum].iname &&
802 eq(name, mesg[signum].iname))
803 goto gotsig;
804 setname(name);
805 bferr("Unknown signal; kill -l lists signals");
806 }
807gotsig:
808 v++;
809 } else
810 signum = SIGTERM;
811 pkill(v, signum);
812}
813
814pkill(v, signum)
815 char **v;
816 int signum;
817{
818 register struct process *pp, *np;
819 register int jobflags = 0;
1f7b623f
KB
820 int pid, err = 0;
821 long omask;
525f24a3 822 char *cp;
2d4bbda8 823 extern char *sys_errlist[];
2d4bbda8 824
d33af40e 825 omask = sigmask(SIGCHLD);
2d4bbda8 826 if (setintr)
d33af40e
RC
827 omask |= sigmask(SIGINT);
828 omask = sigblock(omask) & ~omask;
2d4bbda8 829 while (*v) {
525f24a3
SL
830 cp = globone(*v);
831 if (*cp == '%') {
832 np = pp = pfind(cp);
2d4bbda8
BJ
833 do
834 jobflags |= np->p_flags;
835 while ((np = np->p_friends) != pp);
836 switch (signum) {
837
838 case SIGSTOP:
839 case SIGTSTP:
840 case SIGTTIN:
841 case SIGTTOU:
842 if ((jobflags & PRUNNING) == 0) {
9c279653 843 printf("%s: Already suspended\n", cp);
2d4bbda8
BJ
844 err++;
845 goto cont;
846 }
847 }
9f4aa2a3
KM
848 if (killpg(pp->p_jobid, signum) < 0) {
849 printf("%s: ", cp);
850 printf("%s\n", sys_errlist[errno]);
851 err++;
852 }
2d4bbda8 853 if (signum == SIGTERM || signum == SIGHUP)
35371dec 854 (void) killpg(pp->p_jobid, SIGCONT);
793f6534 855 } else if (!(digit(*cp) || *cp == '-'))
2d4bbda8
BJ
856 bferr("Arguments should be jobs or process id's");
857 else {
525f24a3 858 pid = atoi(cp);
2d4bbda8
BJ
859 if (kill(pid, signum) < 0) {
860 printf("%d: ", pid);
861 printf("%s\n", sys_errlist[errno]);
862 err++;
863 goto cont;
864 }
865 if (signum == SIGTERM || signum == SIGHUP)
35371dec 866 (void) kill(pid, SIGCONT);
2d4bbda8
BJ
867 }
868cont:
525f24a3 869 xfree(cp);
2d4bbda8
BJ
870 v++;
871 }
35371dec 872 (void) sigsetmask(omask);
2d4bbda8
BJ
873 if (err)
874 error(NOSTR);
875}
876
877/*
878 * pstart - start the job in foreground/background
879 */
880pstart(pp, foregnd)
881 register struct process *pp;
882 int foregnd;
883{
884 register struct process *np;
1f7b623f
KB
885 int jobflags = 0;
886 long omask;
2d4bbda8 887
d33af40e 888 omask = sigblock(sigmask(SIGCHLD));
2d4bbda8
BJ
889 np = pp;
890 do {
891 jobflags |= np->p_flags;
892 if (np->p_flags&(PRUNNING|PSTOPPED)) {
893 np->p_flags |= PRUNNING;
894 np->p_flags &= ~PSTOPPED;
895 if (foregnd)
896 np->p_flags |= PFOREGND;
897 else
898 np->p_flags &= ~PFOREGND;
899 }
900 } while((np = np->p_friends) != pp);
a132d4ed
BJ
901 if (!foregnd)
902 pclrcurr(pp);
35371dec 903 (void) pprint(pp, foregnd ? NAME|JOBDIR : NUMBER|NAME|AMPERSAND);
2d4bbda8 904 if (foregnd)
35371dec 905 (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&pp->p_jobid);
2d4bbda8 906 if (jobflags&PSTOPPED)
35371dec
EW
907 (void) killpg(pp->p_jobid, SIGCONT);
908 (void) sigsetmask(omask);
2d4bbda8
BJ
909}
910
911panystop(neednl)
912{
913 register struct process *pp;
914
915 chkstop = 2;
916 for (pp = proclist.p_next; pp; pp = pp->p_next)
917 if (pp->p_flags & PSTOPPED)
9c279653 918 error("\nThere are suspended jobs" + 1 - neednl);
2d4bbda8
BJ
919}
920
921struct process *
922pfind(cp)
923 char *cp;
924{
925 register struct process *pp, *np;
926
927 if (cp == 0 || cp[1] == 0 || eq(cp, "%%") || eq(cp, "%+")) {
928 if (pcurrent == PNULL)
929 bferr("No current job");
930 return (pcurrent);
931 }
932 if (eq(cp, "%-") || eq(cp, "%#")) {
933 if (pprevious == PNULL)
934 bferr("No previous job");
935 return (pprevious);
936 }
937 if (digit(cp[1])) {
938 int index = atoi(cp+1);
939 for (pp = proclist.p_next; pp; pp = pp->p_next)
940 if (pp->p_index == index && pp->p_pid == pp->p_jobid)
941 return (pp);
942 bferr("No such job");
943 }
944 np = PNULL;
945 for (pp = proclist.p_next; pp; pp = pp->p_next)
946 if (pp->p_pid == pp->p_jobid) {
947 if (cp[1] == '?') {
948 register char *dp;
949 for (dp = pp->p_command; *dp; dp++) {
950 if (*dp != cp[2])
951 continue;
952 if (prefix(cp+2, dp))
953 goto match;
954 }
955 } else if (prefix(cp+1, pp->p_command)) {
956match:
957 if (np)
958 bferr("Ambiguous");
959 np = pp;
960 }
961 }
962 if (np)
963 return (np);
964 if (cp[1] == '?')
965 bferr("No job matches pattern");
966 else
967 bferr("No such job");
35371dec 968 /*NOTREACHED*/
2d4bbda8
BJ
969}
970
971/*
a132d4ed 972 * pgetcurr - find most recent job that is not pp, preferably stopped
2d4bbda8
BJ
973 */
974struct process *
975pgetcurr(pp)
976 register struct process *pp;
977{
978 register struct process *np;
a132d4ed 979 register struct process *xp = PNULL;
2d4bbda8
BJ
980
981 for (np = proclist.p_next; np; np = np->p_next)
982 if (np != pcurrent && np != pp && np->p_pid &&
983 np->p_pid == np->p_jobid) {
a132d4ed
BJ
984 if (np->p_flags & PSTOPPED)
985 return (np);
986 if (xp == PNULL)
987 xp = np;
2d4bbda8 988 }
a132d4ed 989 return (xp);
2d4bbda8
BJ
990}
991
992/*
993 * donotify - flag the job so as to report termination asynchronously
994 */
995donotify(v)
996 char **v;
997{
998 register struct process *pp;
999
1000 pp = pfind(*++v);
1001 pp->p_flags |= PNOTIFY;
1002}
1003
1004/*
1005 * Do the fork and whatever should be done in the child side that
1006 * should not be done if we are not forking at all (like for simple builtin's)
1007 * Also do everything that needs any signals fiddled with in the parent side
1008 *
1009 * Wanttty tells whether process and/or tty pgrps are to be manipulated:
1010 * -1: leave tty alone; inherit pgrp from parent
1011 * 0: already have tty; manipulate process pgrps only
1012 * 1: want to claim tty; manipulate process and tty pgrps
1013 * It is usually just the value of tpgrp.
1014 */
1015pfork(t, wanttty)
1016 struct command *t; /* command we are forking for */
1017 int wanttty;
1018{
1019 register int pid;
1020 bool ignint = 0;
1f7b623f
KB
1021 int pgrp;
1022 long omask;
2d4bbda8
BJ
1023
1024 /*
1025 * A child will be uninterruptible only under very special
1026 * conditions. Remember that the semantics of '&' is
1027 * implemented by disconnecting the process from the tty so
1028 * signals do not need to ignored just for '&'.
1029 * Thus signals are set to default action for children unless:
1030 * we have had an "onintr -" (then specifically ignored)
1031 * we are not playing with signals (inherit action)
1032 */
1033 if (setintr)
1034 ignint = (tpgrp == -1 && (t->t_dflg&FINT))
1035 || (gointr && eq(gointr, "-"));
1036 /*
1037 * Hold SIGCHLD until we have the process installed in our table.
1038 */
d33af40e 1039 omask = sigblock(sigmask(SIGCHLD));
2d4bbda8
BJ
1040 while ((pid = fork()) < 0)
1041 if (setintr == 0)
1042 sleep(FORKSLEEP);
1043 else {
35371dec 1044 (void) sigsetmask(omask);
2d4bbda8
BJ
1045 error("No more processes");
1046 }
1047 if (pid == 0) {
1048 settimes();
1049 pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
1050 pflushall();
1051 pcurrjob = PNULL;
2d4bbda8
BJ
1052 child++;
1053 if (setintr) {
1054 setintr = 0; /* until I think otherwise */
2d4bbda8
BJ
1055 /*
1056 * Children just get blown away on SIGINT, SIGQUIT
1057 * unless "onintr -" seen.
1058 */
35371dec
EW
1059 (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
1060 (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
2d4bbda8
BJ
1061 if (wanttty >= 0) {
1062 /* make stoppable */
35371dec
EW
1063 (void) signal(SIGTSTP, SIG_DFL);
1064 (void) signal(SIGTTIN, SIG_DFL);
1065 (void) signal(SIGTTOU, SIG_DFL);
2d4bbda8 1066 }
35371dec 1067 (void) signal(SIGTERM, parterm);
2d4bbda8 1068 } else if (tpgrp == -1 && (t->t_dflg&FINT)) {
35371dec
EW
1069 (void) signal(SIGINT, SIG_IGN);
1070 (void) signal(SIGQUIT, SIG_IGN);
2d4bbda8
BJ
1071 }
1072 if (wanttty > 0)
35371dec 1073 (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&pgrp);
2d4bbda8 1074 if (wanttty >= 0 && tpgrp >= 0)
35371dec 1075 (void) setpgrp(0, pgrp);
2d4bbda8
BJ
1076 if (tpgrp > 0)
1077 tpgrp = 0; /* gave tty away */
1078 /*
1079 * Nohup and nice apply only to TCOM's but it would be
1080 * nice (?!?) if you could say "nohup (foo;bar)"
1081 * Then the parser would have to know about nice/nohup/time
1082 */
1083 if (t->t_dflg & FNOHUP)
35371dec 1084 (void) signal(SIGHUP, SIG_IGN);
d33af40e 1085 if (t->t_dflg & FNICE)
793f6534 1086 (void) setpriority(PRIO_PROCESS, 0, t->t_nice);
2d4bbda8
BJ
1087 } else {
1088 palloc(pid, t);
35371dec 1089 (void) sigsetmask(omask);
2d4bbda8
BJ
1090 }
1091
1092 return (pid);
1093}
1094
1095okpcntl()
1096{
1097
1098 if (tpgrp == -1)
1099 error("No job control in this shell");
1100 if (tpgrp == 0)
1101 error("No job control in subshells");
1102}