jobs.c revision 1.22 1 /* $NetBSD: jobs.c,v 1.22 1997/07/04 21:02:04 christos Exp $ */
2
3 /*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95";
43 #else
44 __RCSID("$NetBSD: jobs.c,v 1.22 1997/07/04 21:02:04 christos Exp $");
45 #endif
46 #endif /* not lint */
47
48 #include <fcntl.h>
49 #include <signal.h>
50 #include <errno.h>
51 #include <unistd.h>
52 #include <stdlib.h>
53 #include <sys/types.h>
54 #include <sys/param.h>
55 #ifdef BSD
56 #include <sys/wait.h>
57 #include <sys/time.h>
58 #include <sys/resource.h>
59 #endif
60 #include <sys/ioctl.h>
61
62 #include "shell.h"
63 #if JOBS
64 #if OLD_TTY_DRIVER
65 #include "sgtty.h"
66 #else
67 #include <termios.h>
68 #endif
69 #undef CEOF /* syntax.h redefines this */
70 #endif
71 #include "redir.h"
72 #include "show.h"
73 #include "main.h"
74 #include "parser.h"
75 #include "nodes.h"
76 #include "jobs.h"
77 #include "options.h"
78 #include "trap.h"
79 #include "syntax.h"
80 #include "input.h"
81 #include "output.h"
82 #include "memalloc.h"
83 #include "error.h"
84 #include "mystring.h"
85
86
87 struct job *jobtab; /* array of jobs */
88 int njobs; /* size of array */
89 MKINIT short backgndpid = -1; /* pid of last background process */
90 #if JOBS
91 int initialpgrp; /* pgrp of shell on invocation */
92 short curjob; /* current job */
93 #endif
94
95 STATIC void restartjob __P((struct job *));
96 STATIC void freejob __P((struct job *));
97 STATIC struct job *getjob __P((char *));
98 STATIC int dowait __P((int, struct job *));
99 STATIC int onsigchild __P((void));
100 STATIC int waitproc __P((int, int *));
101 STATIC void cmdtxt __P((union node *));
102 STATIC void cmdputs __P((char *));
103
104
105 /*
106 * Turn job control on and off.
107 *
108 * Note: This code assumes that the third arg to ioctl is a character
109 * pointer, which is true on Berkeley systems but not System V. Since
110 * System V doesn't have job control yet, this isn't a problem now.
111 */
112
113 MKINIT int jobctl;
114
115 void
116 setjobctl(on)
117 int on;
118 {
119 #ifdef OLD_TTY_DRIVER
120 int ldisc;
121 #endif
122
123 if (on == jobctl || rootshell == 0)
124 return;
125 if (on) {
126 do { /* while we are in the background */
127 #ifdef OLD_TTY_DRIVER
128 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
129 #else
130 initialpgrp = tcgetpgrp(2);
131 if (initialpgrp < 0) {
132 #endif
133 out2str("sh: can't access tty; job control turned off\n");
134 mflag = 0;
135 return;
136 }
137 if (initialpgrp == -1)
138 initialpgrp = getpgrp();
139 else if (initialpgrp != getpgrp()) {
140 killpg(initialpgrp, SIGTTIN);
141 continue;
142 }
143 } while (0);
144 #ifdef OLD_TTY_DRIVER
145 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
146 out2str("sh: need new tty driver to run job control; job control turned off\n");
147 mflag = 0;
148 return;
149 }
150 #endif
151 setsignal(SIGTSTP);
152 setsignal(SIGTTOU);
153 setsignal(SIGTTIN);
154 setpgid(0, rootpid);
155 #ifdef OLD_TTY_DRIVER
156 ioctl(2, TIOCSPGRP, (char *)&rootpid);
157 #else
158 tcsetpgrp(2, rootpid);
159 #endif
160 } else { /* turning job control off */
161 setpgid(0, initialpgrp);
162 #ifdef OLD_TTY_DRIVER
163 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
164 #else
165 tcsetpgrp(2, initialpgrp);
166 #endif
167 setsignal(SIGTSTP);
168 setsignal(SIGTTOU);
169 setsignal(SIGTTIN);
170 }
171 jobctl = on;
172 }
173
174
175 #ifdef mkinit
176 INCLUDE <stdlib.h>
177
178 SHELLPROC {
179 backgndpid = -1;
180 #if JOBS
181 jobctl = 0;
182 #endif
183 }
184
185 #endif
186
187
188
189 #if JOBS
190 int
191 fgcmd(argc, argv)
192 int argc;
193 char **argv;
194 {
195 struct job *jp;
196 int pgrp;
197 int status;
198
199 jp = getjob(argv[1]);
200 if (jp->jobctl == 0)
201 error("job not created under job control");
202 pgrp = jp->ps[0].pid;
203 #ifdef OLD_TTY_DRIVER
204 ioctl(2, TIOCSPGRP, (char *)&pgrp);
205 #else
206 tcsetpgrp(2, pgrp);
207 #endif
208 restartjob(jp);
209 INTOFF;
210 status = waitforjob(jp);
211 INTON;
212 return status;
213 }
214
215
216 int
217 bgcmd(argc, argv)
218 int argc;
219 char **argv;
220 {
221 struct job *jp;
222
223 do {
224 jp = getjob(*++argv);
225 if (jp->jobctl == 0)
226 error("job not created under job control");
227 restartjob(jp);
228 } while (--argc > 1);
229 return 0;
230 }
231
232
233 STATIC void
234 restartjob(jp)
235 struct job *jp;
236 {
237 struct procstat *ps;
238 int i;
239
240 if (jp->state == JOBDONE)
241 return;
242 INTOFF;
243 killpg(jp->ps[0].pid, SIGCONT);
244 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
245 if ((ps->status & 0377) == 0177) {
246 ps->status = -1;
247 jp->state = 0;
248 }
249 }
250 INTON;
251 }
252 #endif
253
254
255 int
256 jobscmd(argc, argv)
257 int argc;
258 char **argv;
259 {
260 showjobs(0);
261 return 0;
262 }
263
264
265 /*
266 * Print a list of jobs. If "change" is nonzero, only print jobs whose
267 * statuses have changed since the last call to showjobs.
268 *
269 * If the shell is interrupted in the process of creating a job, the
270 * result may be a job structure containing zero processes. Such structures
271 * will be freed here.
272 */
273
274 void
275 showjobs(change)
276 int change;
277 {
278 int jobno;
279 int procno;
280 int i;
281 struct job *jp;
282 struct procstat *ps;
283 int col;
284 char s[64];
285
286 TRACE(("showjobs(%d) called\n", change));
287 while (dowait(0, (struct job *)NULL) > 0);
288 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
289 if (! jp->used)
290 continue;
291 if (jp->nprocs == 0) {
292 freejob(jp);
293 continue;
294 }
295 if (change && ! jp->changed)
296 continue;
297 procno = jp->nprocs;
298 for (ps = jp->ps ; ; ps++) { /* for each process */
299 if (ps == jp->ps)
300 fmtstr(s, 64, "[%d] %d ", jobno, ps->pid);
301 else
302 fmtstr(s, 64, " %d ", ps->pid);
303 out1str(s);
304 col = strlen(s);
305 s[0] = '\0';
306 if (ps->status == -1) {
307 /* don't print anything */
308 } else if ((ps->status & 0xFF) == 0) {
309 fmtstr(s, 64, "Exit %d", ps->status >> 8);
310 } else {
311 i = ps->status;
312 #if JOBS
313 if ((i & 0xFF) == 0177)
314 i >>= 8;
315 #endif
316 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
317 scopy(sys_siglist[i & 0x7F], s);
318 else
319 fmtstr(s, 64, "Signal %d", i & 0x7F);
320 if (i & 0x80)
321 strcat(s, " (core dumped)");
322 }
323 out1str(s);
324 col += strlen(s);
325 do {
326 out1c(' ');
327 col++;
328 } while (col < 30);
329 out1str(ps->cmd);
330 out1c('\n');
331 if (--procno <= 0)
332 break;
333 }
334 jp->changed = 0;
335 if (jp->state == JOBDONE) {
336 freejob(jp);
337 }
338 }
339 }
340
341
342 /*
343 * Mark a job structure as unused.
344 */
345
346 STATIC void
347 freejob(jp)
348 struct job *jp;
349 {
350 struct procstat *ps;
351 int i;
352
353 INTOFF;
354 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
355 if (ps->cmd != nullstr)
356 ckfree(ps->cmd);
357 }
358 if (jp->ps != &jp->ps0)
359 ckfree(jp->ps);
360 jp->used = 0;
361 #if JOBS
362 if (curjob == jp - jobtab + 1)
363 curjob = 0;
364 #endif
365 INTON;
366 }
367
368
369
370 int
371 waitcmd(argc, argv)
372 int argc;
373 char **argv;
374 {
375 struct job *job;
376 int status;
377 struct job *jp;
378
379 if (argc > 1) {
380 job = getjob(argv[1]);
381 } else {
382 job = NULL;
383 }
384 for (;;) { /* loop until process terminated or stopped */
385 if (job != NULL) {
386 if (job->state) {
387 status = job->ps[job->nprocs - 1].status;
388 if ((status & 0xFF) == 0)
389 status = status >> 8 & 0xFF;
390 #if JOBS
391 else if ((status & 0xFF) == 0177)
392 status = (status >> 8 & 0x7F) + 128;
393 #endif
394 else
395 status = (status & 0x7F) + 128;
396 if (! iflag)
397 freejob(job);
398 return status;
399 }
400 } else {
401 for (jp = jobtab ; ; jp++) {
402 if (jp >= jobtab + njobs) { /* no running procs */
403 return 0;
404 }
405 if (jp->used && jp->state == 0)
406 break;
407 }
408 }
409 dowait(1, (struct job *)NULL);
410 }
411 }
412
413
414
415 int
416 jobidcmd(argc, argv)
417 int argc;
418 char **argv;
419 {
420 struct job *jp;
421 int i;
422
423 jp = getjob(argv[1]);
424 for (i = 0 ; i < jp->nprocs ; ) {
425 out1fmt("%d", jp->ps[i].pid);
426 out1c(++i < jp->nprocs? ' ' : '\n');
427 }
428 return 0;
429 }
430
431
432
433 /*
434 * Convert a job name to a job structure.
435 */
436
437 STATIC struct job *
438 getjob(name)
439 char *name;
440 {
441 int jobno;
442 struct job *jp;
443 int pid;
444 int i;
445
446 if (name == NULL) {
447 #if JOBS
448 currentjob:
449 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
450 error("No current job");
451 return &jobtab[jobno - 1];
452 #else
453 error("No current job");
454 #endif
455 } else if (name[0] == '%') {
456 if (is_digit(name[1])) {
457 jobno = number(name + 1);
458 if (jobno > 0 && jobno <= njobs
459 && jobtab[jobno - 1].used != 0)
460 return &jobtab[jobno - 1];
461 #if JOBS
462 } else if (name[1] == '%' && name[2] == '\0') {
463 goto currentjob;
464 #endif
465 } else {
466 struct job *found = NULL;
467 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
468 if (jp->used && jp->nprocs > 0
469 && prefix(name + 1, jp->ps[0].cmd)) {
470 if (found)
471 error("%s: ambiguous", name);
472 found = jp;
473 }
474 }
475 if (found)
476 return found;
477 }
478 } else if (is_number(name)) {
479 pid = number(name);
480 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
481 if (jp->used && jp->nprocs > 0
482 && jp->ps[jp->nprocs - 1].pid == pid)
483 return jp;
484 }
485 }
486 error("No such job: %s", name);
487 /*NOTREACHED*/
488 return NULL;
489 }
490
491
492
493 /*
494 * Return a new job structure,
495 */
496
497 struct job *
498 makejob(node, nprocs)
499 union node *node;
500 int nprocs;
501 {
502 int i;
503 struct job *jp;
504
505 for (i = njobs, jp = jobtab ; ; jp++) {
506 if (--i < 0) {
507 INTOFF;
508 if (njobs == 0) {
509 jobtab = ckmalloc(4 * sizeof jobtab[0]);
510 } else {
511 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
512 memcpy(jp, jobtab, njobs * sizeof jp[0]);
513 /* Relocate `ps' pointers */
514 for (i = 0; i < njobs; i++)
515 if (jp[i].ps == &jobtab[i].ps0)
516 jp[i].ps = &jp[i].ps0;
517 ckfree(jobtab);
518 jobtab = jp;
519 }
520 jp = jobtab + njobs;
521 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
522 INTON;
523 break;
524 }
525 if (jp->used == 0)
526 break;
527 }
528 INTOFF;
529 jp->state = 0;
530 jp->used = 1;
531 jp->changed = 0;
532 jp->nprocs = 0;
533 #if JOBS
534 jp->jobctl = jobctl;
535 #endif
536 if (nprocs > 1) {
537 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
538 } else {
539 jp->ps = &jp->ps0;
540 }
541 INTON;
542 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
543 jp - jobtab + 1));
544 return jp;
545 }
546
547
548 /*
549 * Fork of a subshell. If we are doing job control, give the subshell its
550 * own process group. Jp is a job structure that the job is to be added to.
551 * N is the command that will be evaluated by the child. Both jp and n may
552 * be NULL. The mode parameter can be one of the following:
553 * FORK_FG - Fork off a foreground process.
554 * FORK_BG - Fork off a background process.
555 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
556 * process group even if job control is on.
557 *
558 * When job control is turned off, background processes have their standard
559 * input redirected to /dev/null (except for the second and later processes
560 * in a pipeline).
561 */
562
563 int
564 forkshell(jp, n, mode)
565 union node *n;
566 struct job *jp;
567 int mode;
568 {
569 int pid;
570 int pgrp;
571
572 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
573 mode));
574 INTOFF;
575 pid = fork();
576 if (pid == -1) {
577 TRACE(("Fork failed, errno=%d\n", errno));
578 INTON;
579 error("Cannot fork");
580 }
581 if (pid == 0) {
582 struct job *p;
583 int wasroot;
584 int i;
585
586 TRACE(("Child shell %d\n", getpid()));
587 wasroot = rootshell;
588 rootshell = 0;
589 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
590 if (p->used)
591 freejob(p);
592 closescript();
593 INTON;
594 clear_traps();
595 #if JOBS
596 jobctl = 0; /* do job control only in root shell */
597 if (wasroot && mode != FORK_NOJOB && mflag) {
598 if (jp == NULL || jp->nprocs == 0)
599 pgrp = getpid();
600 else
601 pgrp = jp->ps[0].pid;
602 setpgid(0, pgrp);
603 if (mode == FORK_FG) {
604 /*** this causes superfluous TIOCSPGRPS ***/
605 #ifdef OLD_TTY_DRIVER
606 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
607 error("TIOCSPGRP failed, errno=%d", errno);
608 #else
609 if (tcsetpgrp(2, pgrp) < 0)
610 error("tcsetpgrp failed, errno=%d", errno);
611 #endif
612 }
613 setsignal(SIGTSTP);
614 setsignal(SIGTTOU);
615 } else if (mode == FORK_BG) {
616 ignoresig(SIGINT);
617 ignoresig(SIGQUIT);
618 if ((jp == NULL || jp->nprocs == 0) &&
619 ! fd0_redirected_p ()) {
620 close(0);
621 if (open("/dev/null", O_RDONLY) != 0)
622 error("Can't open /dev/null");
623 }
624 }
625 #else
626 if (mode == FORK_BG) {
627 ignoresig(SIGINT);
628 ignoresig(SIGQUIT);
629 if ((jp == NULL || jp->nprocs == 0) &&
630 ! fd0_redirected_p ()) {
631 close(0);
632 if (open("/dev/null", O_RDONLY) != 0)
633 error("Can't open /dev/null");
634 }
635 }
636 #endif
637 if (wasroot && iflag) {
638 setsignal(SIGINT);
639 setsignal(SIGQUIT);
640 setsignal(SIGTERM);
641 }
642 return pid;
643 }
644 if (rootshell && mode != FORK_NOJOB && mflag) {
645 if (jp == NULL || jp->nprocs == 0)
646 pgrp = pid;
647 else
648 pgrp = jp->ps[0].pid;
649 setpgid(pid, pgrp);
650 }
651 if (mode == FORK_BG)
652 backgndpid = pid; /* set $! */
653 if (jp) {
654 struct procstat *ps = &jp->ps[jp->nprocs++];
655 ps->pid = pid;
656 ps->status = -1;
657 ps->cmd = nullstr;
658 if (iflag && rootshell && n)
659 ps->cmd = commandtext(n);
660 }
661 INTON;
662 TRACE(("In parent shell: child = %d\n", pid));
663 return pid;
664 }
665
666
667
668 /*
669 * Wait for job to finish.
670 *
671 * Under job control we have the problem that while a child process is
672 * running interrupts generated by the user are sent to the child but not
673 * to the shell. This means that an infinite loop started by an inter-
674 * active user may be hard to kill. With job control turned off, an
675 * interactive user may place an interactive program inside a loop. If
676 * the interactive program catches interrupts, the user doesn't want
677 * these interrupts to also abort the loop. The approach we take here
678 * is to have the shell ignore interrupt signals while waiting for a
679 * forground process to terminate, and then send itself an interrupt
680 * signal if the child process was terminated by an interrupt signal.
681 * Unfortunately, some programs want to do a bit of cleanup and then
682 * exit on interrupt; unless these processes terminate themselves by
683 * sending a signal to themselves (instead of calling exit) they will
684 * confuse this approach.
685 */
686
687 int
688 waitforjob(jp)
689 struct job *jp;
690 {
691 #if JOBS
692 int mypgrp = getpgrp();
693 #endif
694 int status;
695 int st;
696
697 INTOFF;
698 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
699 while (jp->state == 0) {
700 dowait(1, jp);
701 }
702 #if JOBS
703 if (jp->jobctl) {
704 #ifdef OLD_TTY_DRIVER
705 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
706 error("TIOCSPGRP failed, errno=%d\n", errno);
707 #else
708 if (tcsetpgrp(2, mypgrp) < 0)
709 error("tcsetpgrp failed, errno=%d\n", errno);
710 #endif
711 }
712 if (jp->state == JOBSTOPPED)
713 curjob = jp - jobtab + 1;
714 #endif
715 status = jp->ps[jp->nprocs - 1].status;
716 /* convert to 8 bits */
717 if ((status & 0xFF) == 0)
718 st = status >> 8 & 0xFF;
719 #if JOBS
720 else if ((status & 0xFF) == 0177)
721 st = (status >> 8 & 0x7F) + 128;
722 #endif
723 else
724 st = (status & 0x7F) + 128;
725 if (! JOBS || jp->state == JOBDONE)
726 freejob(jp);
727 CLEAR_PENDING_INT;
728 if ((status & 0x7F) == SIGINT)
729 kill(getpid(), SIGINT);
730 INTON;
731 return st;
732 }
733
734
735
736 /*
737 * Wait for a process to terminate.
738 */
739
740 STATIC int
741 dowait(block, job)
742 int block;
743 struct job *job;
744 {
745 int pid;
746 int status;
747 struct procstat *sp;
748 struct job *jp;
749 struct job *thisjob;
750 int done;
751 int stopped;
752 int core;
753
754 TRACE(("dowait(%d) called\n", block));
755 do {
756 pid = waitproc(block, &status);
757 TRACE(("wait returns %d, status=%d\n", pid, status));
758 } while (pid == -1 && errno == EINTR);
759 if (pid <= 0)
760 return pid;
761 INTOFF;
762 thisjob = NULL;
763 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
764 if (jp->used) {
765 done = 1;
766 stopped = 1;
767 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
768 if (sp->pid == -1)
769 continue;
770 if (sp->pid == pid) {
771 TRACE(("Changin status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
772 sp->status = status;
773 thisjob = jp;
774 }
775 if (sp->status == -1)
776 stopped = 0;
777 else if ((sp->status & 0377) == 0177)
778 done = 0;
779 }
780 if (stopped) { /* stopped or done */
781 int state = done? JOBDONE : JOBSTOPPED;
782 if (jp->state != state) {
783 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
784 jp->state = state;
785 #if JOBS
786 if (done && curjob == jp - jobtab + 1)
787 curjob = 0; /* no current job */
788 #endif
789 }
790 }
791 }
792 }
793 INTON;
794 if (! rootshell || ! iflag || (job && thisjob == job)) {
795 #if JOBS
796 if ((status & 0xFF) == 0177)
797 status >>= 8;
798 #endif
799 core = status & 0x80;
800 status &= 0x7F;
801 if (status != 0 && status != SIGINT && status != SIGPIPE) {
802 if (thisjob != job)
803 outfmt(out2, "%d: ", pid);
804 #if JOBS
805 if (status == SIGTSTP && rootshell && iflag)
806 outfmt(out2, "%%%d ", job - jobtab + 1);
807 #endif
808 if (status < NSIG && sys_siglist[status])
809 out2str(sys_siglist[status]);
810 else
811 outfmt(out2, "Signal %d", status);
812 if (core)
813 out2str(" - core dumped");
814 out2c('\n');
815 flushout(&errout);
816 } else {
817 TRACE(("Not printing status: status=%d\n", status));
818 }
819 } else {
820 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
821 if (thisjob)
822 thisjob->changed = 1;
823 }
824 return pid;
825 }
826
827
828
829 /*
830 * Do a wait system call. If job control is compiled in, we accept
831 * stopped processes. If block is zero, we return a value of zero
832 * rather than blocking.
833 *
834 * System V doesn't have a non-blocking wait system call. It does
835 * have a SIGCLD signal that is sent to a process when one of it's
836 * children dies. The obvious way to use SIGCLD would be to install
837 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
838 * was received, and have waitproc bump another counter when it got
839 * the status of a process. Waitproc would then know that a wait
840 * system call would not block if the two counters were different.
841 * This approach doesn't work because if a process has children that
842 * have not been waited for, System V will send it a SIGCLD when it
843 * installs a signal handler for SIGCLD. What this means is that when
844 * a child exits, the shell will be sent SIGCLD signals continuously
845 * until is runs out of stack space, unless it does a wait call before
846 * restoring the signal handler. The code below takes advantage of
847 * this (mis)feature by installing a signal handler for SIGCLD and
848 * then checking to see whether it was called. If there are any
849 * children to be waited for, it will be.
850 *
851 * If neither SYSV nor BSD is defined, we don't implement nonblocking
852 * waits at all. In this case, the user will not be informed when
853 * a background process until the next time she runs a real program
854 * (as opposed to running a builtin command or just typing return),
855 * and the jobs command may give out of date information.
856 */
857
858 #ifdef SYSV
859 STATIC int gotsigchild;
860
861 STATIC int onsigchild() {
862 gotsigchild = 1;
863 }
864 #endif
865
866
867 STATIC int
868 waitproc(block, status)
869 int block;
870 int *status;
871 {
872 #ifdef BSD
873 int flags;
874
875 #if JOBS
876 flags = WUNTRACED;
877 #else
878 flags = 0;
879 #endif
880 if (block == 0)
881 flags |= WNOHANG;
882 return wait3(status, flags, (struct rusage *)NULL);
883 #else
884 #ifdef SYSV
885 int (*save)();
886
887 if (block == 0) {
888 gotsigchild = 0;
889 save = signal(SIGCLD, onsigchild);
890 signal(SIGCLD, save);
891 if (gotsigchild == 0)
892 return 0;
893 }
894 return wait(status);
895 #else
896 if (block == 0)
897 return 0;
898 return wait(status);
899 #endif
900 #endif
901 }
902
903 /*
904 * return 1 if there are stopped jobs, otherwise 0
905 */
906 int job_warning = 0;
907 int
908 stoppedjobs()
909 {
910 int jobno;
911 struct job *jp;
912
913 if (job_warning)
914 return (0);
915 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
916 if (jp->used == 0)
917 continue;
918 if (jp->state == JOBSTOPPED) {
919 out2str("You have stopped jobs.\n");
920 job_warning = 2;
921 return (1);
922 }
923 }
924
925 return (0);
926 }
927
928 /*
929 * Return a string identifying a command (to be printed by the
930 * jobs command.
931 */
932
933 STATIC char *cmdnextc;
934 STATIC int cmdnleft;
935 #define MAXCMDTEXT 200
936
937 char *
938 commandtext(n)
939 union node *n;
940 {
941 char *name;
942
943 cmdnextc = name = ckmalloc(MAXCMDTEXT);
944 cmdnleft = MAXCMDTEXT - 4;
945 cmdtxt(n);
946 *cmdnextc = '\0';
947 return name;
948 }
949
950
951 STATIC void
952 cmdtxt(n)
953 union node *n;
954 {
955 union node *np;
956 struct nodelist *lp;
957 char *p;
958 int i;
959 char s[2];
960
961 if (n == NULL)
962 return;
963 switch (n->type) {
964 case NSEMI:
965 cmdtxt(n->nbinary.ch1);
966 cmdputs("; ");
967 cmdtxt(n->nbinary.ch2);
968 break;
969 case NAND:
970 cmdtxt(n->nbinary.ch1);
971 cmdputs(" && ");
972 cmdtxt(n->nbinary.ch2);
973 break;
974 case NOR:
975 cmdtxt(n->nbinary.ch1);
976 cmdputs(" || ");
977 cmdtxt(n->nbinary.ch2);
978 break;
979 case NPIPE:
980 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
981 cmdtxt(lp->n);
982 if (lp->next)
983 cmdputs(" | ");
984 }
985 break;
986 case NSUBSHELL:
987 cmdputs("(");
988 cmdtxt(n->nredir.n);
989 cmdputs(")");
990 break;
991 case NREDIR:
992 case NBACKGND:
993 cmdtxt(n->nredir.n);
994 break;
995 case NIF:
996 cmdputs("if ");
997 cmdtxt(n->nif.test);
998 cmdputs("; then ");
999 cmdtxt(n->nif.ifpart);
1000 cmdputs("...");
1001 break;
1002 case NWHILE:
1003 cmdputs("while ");
1004 goto until;
1005 case NUNTIL:
1006 cmdputs("until ");
1007 until:
1008 cmdtxt(n->nbinary.ch1);
1009 cmdputs("; do ");
1010 cmdtxt(n->nbinary.ch2);
1011 cmdputs("; done");
1012 break;
1013 case NFOR:
1014 cmdputs("for ");
1015 cmdputs(n->nfor.var);
1016 cmdputs(" in ...");
1017 break;
1018 case NCASE:
1019 cmdputs("case ");
1020 cmdputs(n->ncase.expr->narg.text);
1021 cmdputs(" in ...");
1022 break;
1023 case NDEFUN:
1024 cmdputs(n->narg.text);
1025 cmdputs("() ...");
1026 break;
1027 case NCMD:
1028 for (np = n->ncmd.args ; np ; np = np->narg.next) {
1029 cmdtxt(np);
1030 if (np->narg.next)
1031 cmdputs(" ");
1032 }
1033 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
1034 cmdputs(" ");
1035 cmdtxt(np);
1036 }
1037 break;
1038 case NARG:
1039 cmdputs(n->narg.text);
1040 break;
1041 case NTO:
1042 p = ">"; i = 1; goto redir;
1043 case NAPPEND:
1044 p = ">>"; i = 1; goto redir;
1045 case NTOFD:
1046 p = ">&"; i = 1; goto redir;
1047 case NFROM:
1048 p = "<"; i = 0; goto redir;
1049 case NFROMFD:
1050 p = "<&"; i = 0; goto redir;
1051 redir:
1052 if (n->nfile.fd != i) {
1053 s[0] = n->nfile.fd + '0';
1054 s[1] = '\0';
1055 cmdputs(s);
1056 }
1057 cmdputs(p);
1058 if (n->type == NTOFD || n->type == NFROMFD) {
1059 s[0] = n->ndup.dupfd + '0';
1060 s[1] = '\0';
1061 cmdputs(s);
1062 } else {
1063 cmdtxt(n->nfile.fname);
1064 }
1065 break;
1066 case NHERE:
1067 case NXHERE:
1068 cmdputs("<<...");
1069 break;
1070 default:
1071 cmdputs("???");
1072 break;
1073 }
1074 }
1075
1076
1077
1078 STATIC void
1079 cmdputs(s)
1080 char *s;
1081 {
1082 char *p, *q;
1083 char c;
1084 int subtype = 0;
1085
1086 if (cmdnleft <= 0)
1087 return;
1088 p = s;
1089 q = cmdnextc;
1090 while ((c = *p++) != '\0') {
1091 if (c == CTLESC)
1092 *q++ = *p++;
1093 else if (c == CTLVAR) {
1094 *q++ = '$';
1095 if (--cmdnleft > 0)
1096 *q++ = '{';
1097 subtype = *p++;
1098 } else if (c == '=' && subtype != 0) {
1099 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
1100 subtype = 0;
1101 } else if (c == CTLENDVAR) {
1102 *q++ = '}';
1103 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
1104 cmdnleft++; /* ignore it */
1105 else
1106 *q++ = c;
1107 if (--cmdnleft <= 0) {
1108 *q++ = '.';
1109 *q++ = '.';
1110 *q++ = '.';
1111 break;
1112 }
1113 }
1114 cmdnextc = q;
1115 }
1116