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