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