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