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