ld.elf_so, grep, make: use mmap()
[minix3.git] / commands / ash / jobs.c
blob8333f8b90a64ed69bac86f4356859e2718ca08ad
1 /*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95";
36 #endif
37 #endif /* not lint */
38 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD: src/bin/sh/jobs.c,v 1.67 2004/04/06 20:06:51 markm Exp $");
43 #include "shell.h"
45 #include <sys/types.h>
46 #include <fcntl.h>
47 #include <signal.h>
48 #include <errno.h>
49 #ifndef NO_PATHS_H
50 #include <paths.h>
51 #endif
52 #include <unistd.h>
53 #include <stdlib.h>
54 #ifdef POSIX
55 #include <signal.h>
56 #include <sys/wait.h>
57 #elif defined(BSD)
58 #include <sys/param.h>
59 #include <sys/wait.h>
60 #include <sys/time.h>
61 #include <sys/resource.h>
62 #endif
63 #include <sys/ioctl.h>
65 #if JOBS
66 #include <termios.h>
67 #undef CEOF /* syntax.h redefines this */
68 #endif
69 #include "redir.h"
70 #include "show.h"
71 #include "main.h"
72 #include "parser.h"
73 #include "nodes.h"
74 #include "jobs.h"
75 #include "options.h"
76 #include "trap.h"
77 #include "syntax.h"
78 #include "input.h"
79 #include "output.h"
80 #include "memalloc.h"
81 #include "error.h"
82 #include "mystring.h"
83 #include "builtins.h"
85 #ifdef __minix
86 /* #define NO_KILLPG */
87 #endif
89 #ifndef _PATH_TTY
90 #define _PATH_TTY "/dev/tty"
91 #endif
92 #ifndef _PATH_DEVNULL
93 #define _PATH_DEVNULL "/dev/null"
94 #endif
96 STATIC struct job *jobtab; /* array of jobs */
97 STATIC int njobs; /* size of array */
98 MKINIT pid_t backgndpid = -1; /* pid of last background process */
99 #if JOBS
100 STATIC struct job *jobmru; /* most recently used job list */
101 STATIC pid_t initialpgrp; /* pgrp of shell on invocation */
102 #endif
103 int in_waitcmd = 0; /* are we in waitcmd()? */
104 int in_dowait = 0; /* are we in dowait()? */
105 volatile sig_atomic_t breakwaitcmd = 0; /* should wait be terminated? */
106 #if JOBS
107 static int ttyfd = -1;
108 #endif
110 #ifndef WCOREDUMP
111 #define WCOREDUMP(s) ((s) & 0x80)
112 #endif
114 #if JOBS
115 STATIC void restartjob(struct job *);
116 #endif
117 STATIC void freejob(struct job *);
118 STATIC struct job *getjob(char *);
119 STATIC pid_t dowait(int, struct job *);
120 STATIC pid_t waitproc(int, int *);
121 STATIC void cmdtxt(union node *);
122 STATIC void cmdputs(char *);
123 #if JOBS
124 STATIC void setcurjob(struct job *);
125 STATIC void deljob(struct job *);
126 STATIC struct job *getcurjob(struct job *);
127 #endif
128 STATIC void showjob(struct job *, pid_t, int, int);
130 #ifdef NO_KILLPG
131 static int killpg(pid_t,int);
132 #endif
135 * Turn job control on and off.
138 MKINIT int jobctl;
140 #if JOBS
141 void
142 setjobctl(int on)
144 int i;
146 if (on == jobctl || rootshell == 0)
147 return;
148 if (on) {
149 if (ttyfd != -1)
150 close(ttyfd);
151 if ((ttyfd = open(_PATH_TTY, O_RDWR)) < 0) {
152 i = 0;
153 while (i <= 2 && !isatty(i))
154 i++;
155 if (i > 2 || (ttyfd = fcntl(i, F_DUPFD, 10)) < 0)
156 goto out;
158 if (ttyfd < 10) {
160 * Keep our TTY file descriptor out of the way of
161 * the user's redirections.
163 if ((i = fcntl(ttyfd, F_DUPFD, 10)) < 0) {
164 close(ttyfd);
165 ttyfd = -1;
166 goto out;
168 close(ttyfd);
169 ttyfd = i;
171 if (fcntl(ttyfd, F_SETFD, FD_CLOEXEC) < 0) {
172 close(ttyfd);
173 ttyfd = -1;
174 goto out;
176 do { /* while we are in the background */
177 initialpgrp = tcgetpgrp(ttyfd);
178 if (initialpgrp < 0) {
179 out: out2str("sh: can't access tty; job control turned off\n");
180 mflag = 0;
181 return;
183 if (initialpgrp == -1)
184 initialpgrp = getpgrp();
185 else if (initialpgrp != getpgrp()) {
186 killpg(0, SIGTTIN);
187 continue;
189 } while (0);
190 setsignal(SIGTSTP);
191 setsignal(SIGTTOU);
192 setsignal(SIGTTIN);
193 setpgid(0, rootpid);
194 tcsetpgrp(ttyfd, rootpid);
195 } else { /* turning job control off */
196 setpgid(0, initialpgrp);
197 tcsetpgrp(ttyfd, initialpgrp);
198 close(ttyfd);
199 ttyfd = -1;
200 setsignal(SIGTSTP);
201 setsignal(SIGTTOU);
202 setsignal(SIGTTIN);
204 jobctl = on;
206 #endif
209 #ifdef mkinit
210 INCLUDE <sys/types.h>
211 INCLUDE <stdlib.h>
213 SHELLPROC {
214 backgndpid = -1;
215 #if JOBS
216 jobctl = 0;
217 #endif
220 #endif
224 #if JOBS
226 fgcmd(int argc __unused, char **argv)
228 struct job *jp;
229 pid_t pgrp;
230 int status;
232 jp = getjob(argv[1]);
233 if (jp->jobctl == 0)
234 error("job not created under job control");
235 out1str(jp->ps[0].cmd);
236 out1c('\n');
237 flushout(&output);
238 pgrp = jp->ps[0].pid;
239 tcsetpgrp(ttyfd, pgrp);
240 restartjob(jp);
241 jp->foreground = 1;
242 INTOFF;
243 status = waitforjob(jp, (int *)NULL);
244 INTON;
245 return status;
250 bgcmd(int argc, char **argv)
252 char s[64];
253 struct job *jp;
255 do {
256 jp = getjob(*++argv);
257 if (jp->jobctl == 0)
258 error("job not created under job control");
259 if (jp->state == JOBDONE)
260 continue;
261 restartjob(jp);
262 jp->foreground = 0;
263 fmtstr(s, 64, "[%td] ", jp - jobtab + 1);
264 out1str(s);
265 out1str(jp->ps[0].cmd);
266 out1c('\n');
267 } while (--argc > 1);
268 return 0;
272 STATIC void
273 restartjob(struct job *jp)
275 struct procstat *ps;
276 int i;
278 if (jp->state == JOBDONE)
279 return;
280 setcurjob(jp);
281 INTOFF;
282 killpg(jp->ps[0].pid, SIGCONT);
283 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
284 if (WIFSTOPPED(ps->status)) {
285 ps->status = -1;
286 jp->state = 0;
289 INTON;
291 #endif
295 jobscmd(int argc, char *argv[])
297 char *id;
298 int ch, sformat, lformat;
300 optind = optreset = 1;
301 opterr = 0;
302 sformat = lformat = 0;
303 while ((ch = getopt(argc, argv, "ls")) != -1) {
304 switch (ch) {
305 case 'l':
306 lformat = 1;
307 break;
308 case 's':
309 sformat = 1;
310 break;
311 case '?':
312 default:
313 error("unknown option: -%c", optopt);
316 argc -= optind;
317 argv += optind;
319 if (argc == 0)
320 showjobs(0, sformat, lformat);
321 else
322 while ((id = *argv++) != NULL)
323 showjob(getjob(id), 0, sformat, lformat);
325 return (0);
328 STATIC void
329 showjob(struct job *jp, pid_t pid, int sformat, int lformat)
331 char s[64];
332 struct procstat *ps;
333 #if JOBS
334 struct job *j;
335 #endif
336 int col, curr, i, jobno, prev, procno;
337 char c;
339 procno = jp->nprocs;
340 jobno = jp - jobtab + 1;
341 curr = prev = 0;
342 #if JOBS
343 if ((j = getcurjob(NULL)) != NULL) {
344 curr = j - jobtab + 1;
345 if ((j = getcurjob(j)) != NULL)
346 prev = j - jobtab + 1;
348 #endif
349 for (ps = jp->ps ; ; ps++) { /* for each process */
350 if (sformat) {
351 out1fmt("%d\n", (int)ps->pid);
352 goto skip;
354 if (!lformat && ps != jp->ps && pid == 0)
355 goto skip;
356 if (pid != 0 && pid != ps->pid)
357 goto skip;
358 if (jobno == curr && ps == jp->ps)
359 c = '+';
360 else if (jobno == prev && ps == jp->ps)
361 c = '-';
362 else
363 c = ' ';
364 if (ps == jp->ps)
365 fmtstr(s, 64, "[%d] %c ", jobno, c);
366 else
367 fmtstr(s, 64, " %c ", c);
368 out1str(s);
369 col = strlen(s);
370 if (lformat) {
371 fmtstr(s, 64, "%d ", (int)ps->pid);
372 out1str(s);
373 col += strlen(s);
375 s[0] = '\0';
376 if (ps != jp->ps) {
377 *s = '\0';
378 } else if (ps->status == -1) {
379 strcpy(s, "Running");
380 } else if (WIFEXITED(ps->status)) {
381 if (WEXITSTATUS(ps->status) == 0)
382 strcpy(s, "Done");
383 else
384 fmtstr(s, 64, "Done (%d)",
385 WEXITSTATUS(ps->status));
386 } else {
387 #if JOBS
388 if (WIFSTOPPED(ps->status))
389 i = WSTOPSIG(ps->status);
390 else
391 #endif
392 i = WTERMSIG(ps->status);
393 if ((i & 0x7F) < _NSIG && strsiglist(i & 0x7F))
394 scopy(strsiglist(i & 0x7F), s);
395 else
396 fmtstr(s, 64, "Signal %d", i & 0x7F);
397 if (WCOREDUMP(ps->status))
398 strcat(s, " (core dumped)");
400 out1str(s);
401 col += strlen(s);
402 do {
403 out1c(' ');
404 col++;
405 } while (col < 30);
406 out1str(ps->cmd);
407 out1c('\n');
408 skip: if (--procno <= 0)
409 break;
414 * Print a list of jobs. If "change" is nonzero, only print jobs whose
415 * statuses have changed since the last call to showjobs.
417 * If the shell is interrupted in the process of creating a job, the
418 * result may be a job structure containing zero processes. Such structures
419 * will be freed here.
422 void
423 showjobs(int change, int sformat, int lformat)
425 int jobno;
426 struct job *jp;
428 TRACE(("showjobs(%d) called\n", change));
429 while (dowait(0, (struct job *)NULL) > 0);
430 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
431 if (! jp->used)
432 continue;
433 if (jp->nprocs == 0) {
434 freejob(jp);
435 continue;
437 if (change && ! jp->changed)
438 continue;
439 showjob(jp, 0, sformat, lformat);
440 jp->changed = 0;
441 if (jp->state == JOBDONE) {
442 freejob(jp);
449 * Mark a job structure as unused.
452 STATIC void
453 freejob(struct job *jp)
455 struct procstat *ps;
456 int i;
458 INTOFF;
459 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
460 if (ps->cmd != nullstr)
461 ckfree(ps->cmd);
463 if (jp->ps != &jp->ps0)
464 ckfree(jp->ps);
465 jp->used = 0;
466 #if JOBS
467 deljob(jp);
468 #endif
469 INTON;
475 waitcmd(int argc, char **argv)
477 struct job *job;
478 int status, retval;
479 struct job *jp;
481 if (argc > 1) {
482 job = getjob(argv[1]);
483 } else {
484 job = NULL;
488 * Loop until a process is terminated or stopped, or a SIGINT is
489 * received.
492 in_waitcmd++;
493 do {
494 if (job != NULL) {
495 if (job->state) {
496 status = job->ps[job->nprocs - 1].status;
497 if (WIFEXITED(status))
498 retval = WEXITSTATUS(status);
499 #if JOBS
500 else if (WIFSTOPPED(status))
501 retval = WSTOPSIG(status) + 128;
502 #endif
503 else
504 retval = WTERMSIG(status) + 128;
505 if (! iflag)
506 freejob(job);
507 in_waitcmd--;
508 return retval;
510 } else {
511 for (jp = jobtab ; ; jp++) {
512 if (jp >= jobtab + njobs) { /* no running procs */
513 in_waitcmd--;
514 return 0;
516 if (jp->used && jp->state == 0)
517 break;
520 } while (dowait(1, (struct job *)NULL) != -1);
521 in_waitcmd--;
523 return 0;
529 jobidcmd(int argc __unused, char **argv)
531 struct job *jp;
532 int i;
534 jp = getjob(argv[1]);
535 for (i = 0 ; i < jp->nprocs ; ) {
536 out1fmt("%d", (int)jp->ps[i].pid);
537 out1c(++i < jp->nprocs? ' ' : '\n');
539 return 0;
545 * Convert a job name to a job structure.
548 STATIC struct job *
549 getjob(char *name)
551 int jobno;
552 struct job *found, *jp;
553 pid_t pid;
554 int i;
556 if (name == NULL) {
557 #if JOBS
558 currentjob: if ((jp = getcurjob(NULL)) == NULL)
559 error("No current job");
560 return (jp);
561 #else
562 error("No current job");
563 #endif
564 } else if (name[0] == '%') {
565 if (is_digit(name[1])) {
566 jobno = number(name + 1);
567 if (jobno > 0 && jobno <= njobs
568 && jobtab[jobno - 1].used != 0)
569 return &jobtab[jobno - 1];
570 #if JOBS
571 } else if (name[1] == '%' && name[2] == '\0') {
572 goto currentjob;
573 } else if (name[1] == '+' && name[2] == '\0') {
574 goto currentjob;
575 } else if (name[1] == '-' && name[2] == '\0') {
576 if ((jp = getcurjob(NULL)) == NULL ||
577 (jp = getcurjob(jp)) == NULL)
578 error("No previous job");
579 return (jp);
580 #endif
581 } else if (name[1] == '?') {
582 found = NULL;
583 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
584 if (jp->used && jp->nprocs > 0
585 && strstr(jp->ps[0].cmd, name + 2) != NULL) {
586 if (found)
587 error("%s: ambiguous", name);
588 found = jp;
591 if (found != NULL)
592 return (found);
593 } else {
594 found = NULL;
595 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
596 if (jp->used && jp->nprocs > 0
597 && prefix(name + 1, jp->ps[0].cmd)) {
598 if (found)
599 error("%s: ambiguous", name);
600 found = jp;
603 if (found)
604 return found;
606 } else if (is_number(name)) {
607 pid = (pid_t)number(name);
608 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
609 if (jp->used && jp->nprocs > 0
610 && jp->ps[jp->nprocs - 1].pid == pid)
611 return jp;
614 error("No such job: %s", name);
615 /*NOTREACHED*/
616 return NULL;
622 * Return a new job structure,
625 struct job *
626 makejob(union node *node __unused, int nprocs)
628 int i;
629 struct job *jp;
631 for (i = njobs, jp = jobtab ; ; jp++) {
632 if (--i < 0) {
633 INTOFF;
634 if (njobs == 0) {
635 jobtab = ckmalloc(4 * sizeof jobtab[0]);
636 #if JOBS
637 jobmru = NULL;
638 #endif
639 } else {
640 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
641 memcpy(jp, jobtab, njobs * sizeof jp[0]);
642 #if JOBS
643 /* Relocate `next' pointers and list head */
644 if (jobmru != NULL)
645 jobmru = &jp[jobmru - jobtab];
646 for (i = 0; i < njobs; i++)
647 if (jp[i].next != NULL)
648 jp[i].next = &jp[jp[i].next -
649 jobtab];
650 #endif
651 /* Relocate `ps' pointers */
652 for (i = 0; i < njobs; i++)
653 if (jp[i].ps == &jobtab[i].ps0)
654 jp[i].ps = &jp[i].ps0;
655 ckfree(jobtab);
656 jobtab = jp;
658 jp = jobtab + njobs;
659 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
660 INTON;
661 break;
663 if (jp->used == 0)
664 break;
666 INTOFF;
667 jp->state = 0;
668 jp->used = 1;
669 jp->changed = 0;
670 jp->nprocs = 0;
671 jp->foreground = 0;
672 #if JOBS
673 jp->jobctl = jobctl;
674 jp->next = NULL;
675 #endif
676 if (nprocs > 1) {
677 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
678 } else {
679 jp->ps = &jp->ps0;
681 INTON;
682 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
683 jp - jobtab + 1));
684 return jp;
687 #if JOBS
688 STATIC void
689 setcurjob(struct job *cj)
691 struct job *jp, *prev;
693 for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
694 if (jp == cj) {
695 if (prev != NULL)
696 prev->next = jp->next;
697 else
698 jobmru = jp->next;
699 jp->next = jobmru;
700 jobmru = cj;
701 return;
704 cj->next = jobmru;
705 jobmru = cj;
708 STATIC void
709 deljob(struct job *j)
711 struct job *jp, *prev;
713 for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
714 if (jp == j) {
715 if (prev != NULL)
716 prev->next = jp->next;
717 else
718 jobmru = jp->next;
719 return;
725 * Return the most recently used job that isn't `nj', and preferably one
726 * that is stopped.
728 STATIC struct job *
729 getcurjob(struct job *nj)
731 struct job *jp;
733 /* Try to find a stopped one.. */
734 for (jp = jobmru; jp != NULL; jp = jp->next)
735 if (jp->used && jp != nj && jp->state == JOBSTOPPED)
736 return (jp);
737 /* Otherwise the most recently used job that isn't `nj' */
738 for (jp = jobmru; jp != NULL; jp = jp->next)
739 if (jp->used && jp != nj)
740 return (jp);
742 return (NULL);
745 #endif
748 * Fork of a subshell. If we are doing job control, give the subshell its
749 * own process group. Jp is a job structure that the job is to be added to.
750 * N is the command that will be evaluated by the child. Both jp and n may
751 * be NULL. The mode parameter can be one of the following:
752 * FORK_FG - Fork off a foreground process.
753 * FORK_BG - Fork off a background process.
754 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
755 * process group even if job control is on.
757 * When job control is turned off, background processes have their standard
758 * input redirected to /dev/null (except for the second and later processes
759 * in a pipeline).
762 pid_t
763 forkshell(struct job *jp, union node *n, int mode)
765 pid_t pid;
766 pid_t pgrp;
768 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
769 mode));
770 INTOFF;
771 flushall();
772 pid = fork();
773 if (pid == -1) {
774 TRACE(("Fork failed, errno=%d\n", errno));
775 INTON;
776 error("Cannot fork: %s", strerror(errno));
778 if (pid == 0) {
779 struct job *p;
780 int wasroot;
781 int i;
783 TRACE(("Child shell %d\n", (int)getpid()));
784 wasroot = rootshell;
785 rootshell = 0;
786 closescript();
787 INTON;
788 clear_traps();
789 #if JOBS
790 jobctl = 0; /* do job control only in root shell */
791 if (wasroot && mode != FORK_NOJOB && mflag) {
792 if (jp == NULL || jp->nprocs == 0)
793 pgrp = getpid();
794 else
795 pgrp = jp->ps[0].pid;
796 if (setpgid(0, pgrp) == 0 && mode == FORK_FG) {
797 /*** this causes superfluous TIOCSPGRPS ***/
798 if (tcsetpgrp(ttyfd, pgrp) < 0)
799 error("tcsetpgrp failed, errno=%d", errno);
801 setsignal(SIGTSTP);
802 setsignal(SIGTTOU);
803 } else if (mode == FORK_BG) {
804 ignoresig(SIGINT);
805 ignoresig(SIGQUIT);
806 if ((jp == NULL || jp->nprocs == 0) &&
807 ! fd0_redirected_p ()) {
808 close(0);
809 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
810 error("Can't open %s: %s",
811 _PATH_DEVNULL, strerror(errno));
814 #else
815 if (mode == FORK_BG) {
816 ignoresig(SIGINT);
817 ignoresig(SIGQUIT);
818 if ((jp == NULL || jp->nprocs == 0) &&
819 ! fd0_redirected_p ()) {
820 close(0);
821 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
822 error("Can't open %s: %s",
823 _PATH_DEVNULL, strerror(errno));
826 #endif
827 INTOFF;
828 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
829 if (p->used)
830 freejob(p);
831 INTON;
832 if (wasroot && iflag) {
833 setsignal(SIGINT);
834 setsignal(SIGQUIT);
835 setsignal(SIGTERM);
837 return pid;
839 if (rootshell && mode != FORK_NOJOB && mflag) {
840 if (jp == NULL || jp->nprocs == 0)
841 pgrp = pid;
842 else
843 pgrp = jp->ps[0].pid;
844 #if JOBS
845 setpgid(pid, pgrp);
846 #endif
848 if (mode == FORK_BG)
849 backgndpid = pid; /* set $! */
850 if (jp) {
851 struct procstat *ps = &jp->ps[jp->nprocs++];
852 ps->pid = pid;
853 ps->status = -1;
854 ps->cmd = nullstr;
855 if (iflag && rootshell && n)
856 ps->cmd = commandtext(n);
857 jp->foreground = mode == FORK_FG;
858 #if JOBS
859 setcurjob(jp);
860 #endif
862 INTON;
863 TRACE(("In parent shell: child = %d\n", (int)pid));
864 return pid;
870 * Wait for job to finish.
872 * Under job control we have the problem that while a child process is
873 * running interrupts generated by the user are sent to the child but not
874 * to the shell. This means that an infinite loop started by an inter-
875 * active user may be hard to kill. With job control turned off, an
876 * interactive user may place an interactive program inside a loop. If
877 * the interactive program catches interrupts, the user doesn't want
878 * these interrupts to also abort the loop. The approach we take here
879 * is to have the shell ignore interrupt signals while waiting for a
880 * foreground process to terminate, and then send itself an interrupt
881 * signal if the child process was terminated by an interrupt signal.
882 * Unfortunately, some programs want to do a bit of cleanup and then
883 * exit on interrupt; unless these processes terminate themselves by
884 * sending a signal to themselves (instead of calling exit) they will
885 * confuse this approach.
889 waitforjob(struct job *jp, int *origstatus)
891 #if JOBS
892 pid_t mypgrp = getpgrp();
893 #endif
894 int status;
895 int st;
897 INTOFF;
898 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
899 while (jp->state == 0)
900 if (dowait(1, jp) == -1)
901 dotrap();
902 #if JOBS
903 if (jp->jobctl) {
904 if (tcsetpgrp(ttyfd, mypgrp) < 0)
905 error("tcsetpgrp failed, errno=%d\n", errno);
907 if (jp->state == JOBSTOPPED)
908 setcurjob(jp);
909 #endif
910 status = jp->ps[jp->nprocs - 1].status;
911 if (origstatus != NULL)
912 *origstatus = status;
913 /* convert to 8 bits */
914 if (WIFEXITED(status))
915 st = WEXITSTATUS(status);
916 #if JOBS
917 else if (WIFSTOPPED(status))
918 st = WSTOPSIG(status) + 128;
919 #endif
920 else
921 st = WTERMSIG(status) + 128;
922 if (! JOBS || jp->state == JOBDONE)
923 freejob(jp);
924 if (int_pending()) {
925 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
926 kill(getpid(), SIGINT);
927 else
928 CLEAR_PENDING_INT;
930 INTON;
931 return st;
937 * Wait for a process to terminate.
940 STATIC pid_t
941 dowait(int block, struct job *job)
943 pid_t pid;
944 int status, core;
945 struct procstat *sp;
946 struct job *jp;
947 struct job *thisjob;
948 int done;
949 int stopped;
950 int sig;
951 int i;
953 in_dowait++;
954 TRACE(("dowait(%d) called\n", block));
955 do {
956 pid = waitproc(block, &status);
957 TRACE(("wait returns %d, status=%d\n", (int)pid, status));
958 } while ((pid == -1 && errno == EINTR && breakwaitcmd == 0) ||
959 (pid > 0 && WIFSTOPPED(status) && !iflag));
960 in_dowait--;
961 if (breakwaitcmd != 0) {
962 breakwaitcmd = 0;
963 return -1;
965 if (pid <= 0)
966 return pid;
967 INTOFF;
968 thisjob = NULL;
969 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
970 if (jp->used) {
971 done = 1;
972 stopped = 1;
973 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
974 if (sp->pid == -1)
975 continue;
976 if (sp->pid == pid) {
977 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
978 (int)pid, sp->status,
979 status));
980 sp->status = status;
981 thisjob = jp;
983 if (sp->status == -1)
984 stopped = 0;
985 else if (WIFSTOPPED(sp->status))
986 done = 0;
988 if (stopped) { /* stopped or done */
989 int state = done? JOBDONE : JOBSTOPPED;
990 if (jp->state != state) {
991 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
992 jp->state = state;
993 #if JOBS
994 if (done)
995 deljob(jp);
996 #endif
1001 INTON;
1002 if (! rootshell || ! iflag || (job && thisjob == job)) {
1003 core = WCOREDUMP(status);
1004 #if JOBS
1005 if (WIFSTOPPED(status))
1006 sig = WSTOPSIG(status);
1007 else
1008 #endif
1010 if (WIFEXITED(status))
1011 sig = 0;
1012 else
1013 sig = WTERMSIG(status);
1015 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
1016 if (!mflag ||
1017 (thisjob->foreground && !WIFSTOPPED(status))) {
1018 i = WTERMSIG(status);
1019 if ((i & 0x7F) < _NSIG && strsiglist(i & 0x7F))
1020 out1str(strsiglist(i & 0x7F));
1021 else
1022 out1fmt("Signal %d", i & 0x7F);
1023 if (core)
1024 out1str(" (core dumped)");
1025 out1c('\n');
1026 } else
1027 showjob(thisjob, pid, 0, 0);
1029 } else {
1030 TRACE(("Not printing status, rootshell=%d, job=%p\n", rootshell, job));
1031 if (thisjob)
1032 thisjob->changed = 1;
1034 return pid;
1040 * Do a wait system call. If job control is compiled in, we accept
1041 * stopped processes. If block is zero, we return a value of zero
1042 * rather than blocking.
1044 STATIC pid_t
1045 waitproc(int block, int *status)
1047 #if POSIX
1048 int flags;
1050 #if JOBS
1051 flags = ((rootshell && is_interactive) ? WUNTRACED : 0);
1052 #else
1053 flags = 0;
1054 #endif /* JOBS */
1055 return waitpid(-1, status, (block == 0 ? WNOHANG : 0) | flags);
1056 #else /* !POSIX */
1057 /* Assume BSD */
1058 int flags;
1060 #if JOBS
1061 flags = WUNTRACED;
1062 #else
1063 flags = 0;
1064 #endif /* JOBS */
1065 if (block == 0)
1066 flags |= WNOHANG;
1067 return wait3(status, flags, (struct rusage *)NULL);
1068 #endif /* POSIX */
1072 * return 1 if there are stopped jobs, otherwise 0
1074 int job_warning = 0;
1076 stoppedjobs(void)
1078 int jobno;
1079 struct job *jp;
1081 if (job_warning)
1082 return (0);
1083 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
1084 if (jp->used == 0)
1085 continue;
1086 if (jp->state == JOBSTOPPED) {
1087 out2str("You have stopped jobs.\n");
1088 job_warning = 2;
1089 return (1);
1093 return (0);
1097 * Return a string identifying a command (to be printed by the
1098 * jobs command.
1101 STATIC char *cmdnextc;
1102 STATIC int cmdnleft;
1103 #define MAXCMDTEXT 200
1105 char *
1106 commandtext(union node *n)
1108 char *name;
1110 cmdnextc = name = ckmalloc(MAXCMDTEXT);
1111 cmdnleft = MAXCMDTEXT - 4;
1112 cmdtxt(n);
1113 *cmdnextc = '\0';
1114 return name;
1118 STATIC void
1119 cmdtxt(union node *n)
1121 union node *np;
1122 struct nodelist *lp;
1123 char *p;
1124 int i;
1125 char s[2];
1127 if (n == NULL)
1128 return;
1129 switch (n->type) {
1130 case NSEMI:
1131 cmdtxt(n->nbinary.ch1);
1132 cmdputs("; ");
1133 cmdtxt(n->nbinary.ch2);
1134 break;
1135 case NAND:
1136 cmdtxt(n->nbinary.ch1);
1137 cmdputs(" && ");
1138 cmdtxt(n->nbinary.ch2);
1139 break;
1140 case NOR:
1141 cmdtxt(n->nbinary.ch1);
1142 cmdputs(" || ");
1143 cmdtxt(n->nbinary.ch2);
1144 break;
1145 case NPIPE:
1146 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1147 cmdtxt(lp->n);
1148 if (lp->next)
1149 cmdputs(" | ");
1151 break;
1152 case NSUBSHELL:
1153 cmdputs("(");
1154 cmdtxt(n->nredir.n);
1155 cmdputs(")");
1156 break;
1157 case NREDIR:
1158 case NBACKGND:
1159 cmdtxt(n->nredir.n);
1160 break;
1161 case NIF:
1162 cmdputs("if ");
1163 cmdtxt(n->nif.test);
1164 cmdputs("; then ");
1165 cmdtxt(n->nif.ifpart);
1166 cmdputs("...");
1167 break;
1168 case NWHILE:
1169 cmdputs("while ");
1170 goto until;
1171 case NUNTIL:
1172 cmdputs("until ");
1173 until:
1174 cmdtxt(n->nbinary.ch1);
1175 cmdputs("; do ");
1176 cmdtxt(n->nbinary.ch2);
1177 cmdputs("; done");
1178 break;
1179 case NFOR:
1180 cmdputs("for ");
1181 cmdputs(n->nfor.var);
1182 cmdputs(" in ...");
1183 break;
1184 case NCASE:
1185 cmdputs("case ");
1186 cmdputs(n->ncase.expr->narg.text);
1187 cmdputs(" in ...");
1188 break;
1189 case NDEFUN:
1190 cmdputs(n->narg.text);
1191 cmdputs("() ...");
1192 break;
1193 case NCMD:
1194 for (np = n->ncmd.args ; np ; np = np->narg.next) {
1195 cmdtxt(np);
1196 if (np->narg.next)
1197 cmdputs(" ");
1199 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
1200 cmdputs(" ");
1201 cmdtxt(np);
1203 break;
1204 case NARG:
1205 cmdputs(n->narg.text);
1206 break;
1207 case NTO:
1208 p = ">"; i = 1; goto redir;
1209 case NAPPEND:
1210 p = ">>"; i = 1; goto redir;
1211 case NTOFD:
1212 p = ">&"; i = 1; goto redir;
1213 case NCLOBBER:
1214 p = ">|"; i = 1; goto redir;
1215 case NFROM:
1216 p = "<"; i = 0; goto redir;
1217 case NFROMTO:
1218 p = "<>"; i = 0; goto redir;
1219 case NFROMFD:
1220 p = "<&"; i = 0; goto redir;
1221 redir:
1222 if (n->nfile.fd != i) {
1223 s[0] = n->nfile.fd + '0';
1224 s[1] = '\0';
1225 cmdputs(s);
1227 cmdputs(p);
1228 if (n->type == NTOFD || n->type == NFROMFD) {
1229 if (n->ndup.dupfd >= 0)
1230 s[0] = n->ndup.dupfd + '0';
1231 else
1232 s[0] = '-';
1233 s[1] = '\0';
1234 cmdputs(s);
1235 } else {
1236 cmdtxt(n->nfile.fname);
1238 break;
1239 case NHERE:
1240 case NXHERE:
1241 cmdputs("<<...");
1242 break;
1243 default:
1244 cmdputs("???");
1245 break;
1251 STATIC void
1252 cmdputs(char *s)
1254 char *p, *q;
1255 char c;
1256 int subtype = 0;
1258 if (cmdnleft <= 0)
1259 return;
1260 p = s;
1261 q = cmdnextc;
1262 while ((c = *p++) != '\0') {
1263 if (c == CTLESC)
1264 *q++ = *p++;
1265 else if (c == CTLVAR) {
1266 *q++ = '$';
1267 if (--cmdnleft > 0)
1268 *q++ = '{';
1269 subtype = *p++;
1270 } else if (c == '=' && subtype != 0) {
1271 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
1272 subtype = 0;
1273 } else if (c == CTLENDVAR) {
1274 *q++ = '}';
1275 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
1276 cmdnleft++; /* ignore it */
1277 else
1278 *q++ = c;
1279 if (--cmdnleft <= 0) {
1280 *q++ = '.';
1281 *q++ = '.';
1282 *q++ = '.';
1283 break;
1286 cmdnextc = q;
1289 #ifdef NO_KILLPG
1290 static int killpg(grp, sig)
1291 pid_t grp;
1292 int sig;
1294 return kill(-grp, sig);
1296 #endif
1299 * $PchId: jobs.c,v 1.7 2006/05/22 12:02:13 philip Exp $