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