]>
git.saurik.com Git - apple/shell_cmds.git/blob - sh/jobs.c
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
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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 * 3. 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
35 static char sccsid
[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95";
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD: head/bin/sh/jobs.c 328818 2018-02-02 22:53:58Z jilles $");
41 #include <sys/ioctl.h>
42 #include <sys/param.h>
43 #include <sys/resource.h>
57 #undef CEOF /* syntax.h redefines this */
79 * A job structure contains information about a job. A job is either a
80 * single process or a set of processes contained in a pipeline. In the
81 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
86 pid_t pid
; /* process id */
87 int status
; /* status flags (defined above) */
88 char *cmd
; /* text of command being run */
93 #define JOBSTOPPED 1 /* all procs are stopped */
94 #define JOBDONE 2 /* all procs are completed */
98 struct procstat ps0
; /* status of process */
99 struct procstat
*ps
; /* status or processes when more than one */
100 short nprocs
; /* number of processes */
101 pid_t pgrp
; /* process group of this job */
102 char state
; /* true if job is finished */
103 char used
; /* true if this entry is in used */
104 char changed
; /* true if status has changed */
105 char foreground
; /* true if running in the foreground */
106 char remembered
; /* true if $! referenced */
108 char jobctl
; /* job running under job control */
109 struct job
*next
; /* job used after this one */
114 static struct job
*jobtab
; /* array of jobs */
115 static int njobs
; /* size of array */
116 static pid_t backgndpid
= -1; /* pid of last background process */
117 static struct job
*bgjob
= NULL
; /* last background process */
119 static struct job
*jobmru
; /* most recently used job list */
120 static pid_t initialpgrp
; /* pgrp of shell on invocation */
122 static int ttyfd
= -1;
124 /* mode flags for dowait */
125 #define DOWAIT_BLOCK 0x1 /* wait until a child exits */
126 #define DOWAIT_SIG 0x2 /* if DOWAIT_BLOCK, abort on signal */
127 #define DOWAIT_SIG_TRAP 0x4 /* if DOWAIT_SIG, abort on trapped signal only */
130 static void restartjob(struct job
*);
132 static void freejob(struct job
*);
133 static int waitcmdloop(struct job
*);
134 static struct job
*getjob_nonotfound(const char *);
135 static struct job
*getjob(const char *);
136 pid_t
killjob(const char *, int);
137 static pid_t
dowait(int, struct job
*);
138 static void checkzombies(void);
139 static void cmdtxt(union node
*);
140 static void cmdputs(const char *);
142 static void setcurjob(struct job
*);
143 static void deljob(struct job
*);
144 static struct job
*getcurjob(struct job
*);
146 static void printjobcmd(struct job
*);
147 static void showjob(struct job
*, int);
151 * Turn job control on and off.
171 out2fmt_flush("sh: can't access tty; job control turned off\n");
180 if (on
== jobctl
|| rootshell
== 0)
185 if ((ttyfd
= open(_PATH_TTY
, O_RDWR
| O_CLOEXEC
)) < 0) {
187 while (i
<= 2 && !isatty(i
))
190 (ttyfd
= fcntl(i
, F_DUPFD_CLOEXEC
, 10)) < 0) {
197 * Keep our TTY file descriptor out of the way of
198 * the user's redirections.
200 if ((i
= fcntl(ttyfd
, F_DUPFD_CLOEXEC
, 10)) < 0) {
207 do { /* while we are in the background */
208 initialpgrp
= tcgetpgrp(ttyfd
);
209 if (initialpgrp
< 0) {
213 if (initialpgrp
!= getpgrp()) {
227 tcsetpgrp(ttyfd
, rootpid
);
228 } else { /* turning job control off */
229 setpgid(0, initialpgrp
);
231 tcsetpgrp(ttyfd
, initialpgrp
);
246 fgcmd(int argc __unused
, char **argv __unused
)
253 jp
= getjob(*argptr
);
255 error("job not created under job control");
258 pgrp
= jp
->ps
[0].pid
;
260 tcsetpgrp(ttyfd
, pgrp
);
264 status
= waitforjob(jp
, (int *)NULL
);
271 bgcmd(int argc __unused
, char **argv __unused
)
277 jp
= getjob(*argptr
);
279 error("job not created under job control");
280 if (jp
->state
== JOBDONE
)
284 out1fmt("[%td] ", jp
- jobtab
+ 1);
286 } while (*argptr
!= NULL
&& *++argptr
!= NULL
);
292 restartjob(struct job
*jp
)
297 if (jp
->state
== JOBDONE
)
301 kill(-jp
->ps
[0].pid
, SIGCONT
);
302 for (ps
= jp
->ps
, i
= jp
->nprocs
; --i
>= 0 ; ps
++) {
303 if (WIFSTOPPED(ps
->status
)) {
314 jobscmd(int argc __unused
, char *argv
[] __unused
)
319 mode
= SHOWJOBS_DEFAULT
;
320 while ((ch
= nextopt("lps")) != '\0') {
323 mode
= SHOWJOBS_VERBOSE
;
326 mode
= SHOWJOBS_PGIDS
;
329 mode
= SHOWJOBS_PIDS
;
337 while ((id
= *argptr
++) != NULL
)
338 showjob(getjob(id
), mode
);
344 printjobcmd(struct job
*jp
)
349 for (ps
= jp
->ps
, i
= jp
->nprocs
; --i
>= 0 ; ps
++) {
358 showjob(struct job
*jp
, int mode
)
362 const char *statestr
, *coredump
;
365 int col
, curr
, i
, jobno
, prev
, procno
, status
;
368 procno
= (mode
== SHOWJOBS_PGIDS
) ? 1 : jp
->nprocs
;
369 jobno
= jp
- jobtab
+ 1;
372 if ((j
= getcurjob(NULL
)) != NULL
) {
373 curr
= j
- jobtab
+ 1;
374 if ((j
= getcurjob(j
)) != NULL
)
375 prev
= j
- jobtab
+ 1;
379 status
= jp
->ps
[jp
->nprocs
- 1].status
;
380 if (jp
->state
== 0) {
381 statestr
= "Running";
383 } else if (jp
->state
== JOBSTOPPED
) {
384 ps
= jp
->ps
+ jp
->nprocs
- 1;
385 while (!WIFSTOPPED(ps
->status
) && ps
> jp
->ps
)
387 if (WIFSTOPPED(ps
->status
))
388 i
= WSTOPSIG(ps
->status
);
391 statestr
= strsignal(i
);
392 if (statestr
== NULL
)
393 statestr
= "Suspended";
395 } else if (WIFEXITED(status
)) {
396 if (WEXITSTATUS(status
) == 0)
399 fmtstr(statebuf
, sizeof(statebuf
), "Done(%d)",
400 WEXITSTATUS(status
));
404 i
= WTERMSIG(status
);
405 statestr
= strsignal(i
);
406 if (statestr
== NULL
)
407 statestr
= "Unknown signal";
408 if (WCOREDUMP(status
))
409 coredump
= " (core dumped)";
412 for (ps
= jp
->ps
; procno
> 0 ; ps
++, procno
--) { /* for each process */
413 if (mode
== SHOWJOBS_PIDS
|| mode
== SHOWJOBS_PGIDS
) {
414 out1fmt("%d\n", (int)ps
->pid
);
417 if (mode
!= SHOWJOBS_VERBOSE
&& ps
!= jp
->ps
)
419 if (jobno
== curr
&& ps
== jp
->ps
)
421 else if (jobno
== prev
&& ps
== jp
->ps
)
426 fmtstr(s
, 64, "[%d] %c ", jobno
, c
);
428 fmtstr(s
, 64, " %c ", c
);
431 if (mode
== SHOWJOBS_VERBOSE
) {
432 fmtstr(s
, 64, "%d ", (int)ps
->pid
);
439 col
+= strlen(statestr
) + strlen(coredump
);
445 if (mode
== SHOWJOBS_VERBOSE
) {
454 * Print a list of jobs. If "change" is nonzero, only print jobs whose
455 * statuses have changed since the last call to showjobs.
457 * If the shell is interrupted in the process of creating a job, the
458 * result may be a job structure containing zero processes. Such structures
459 * will be freed here.
463 showjobs(int change
, int mode
)
468 TRACE(("showjobs(%d) called\n", change
));
470 for (jobno
= 1, jp
= jobtab
; jobno
<= njobs
; jobno
++, jp
++) {
473 if (jp
->nprocs
== 0) {
477 if (change
&& ! jp
->changed
)
480 if (mode
== SHOWJOBS_DEFAULT
|| mode
== SHOWJOBS_VERBOSE
) {
482 /* Hack: discard jobs for which $! has not been
483 * referenced in interactive mode when they terminate.
485 if (jp
->state
== JOBDONE
&& !jp
->remembered
&&
486 (iflag
|| jp
!= bgjob
)) {
495 * Mark a job structure as unused.
499 freejob(struct job
*jp
)
507 for (i
= jp
->nprocs
, ps
= jp
->ps
; --i
>= 0 ; ps
++) {
508 if (ps
->cmd
!= nullstr
)
511 if (jp
->ps
!= &jp
->ps0
)
523 waitcmd(int argc __unused
, char **argv __unused
)
530 return (waitcmdloop(NULL
));
533 job
= getjob_nonotfound(*argptr
);
537 retval
= waitcmdloop(job
);
539 } while (*argptr
!= NULL
);
545 waitcmdloop(struct job
*job
)
547 int status
, retval
, sig
;
551 * Loop until a process is terminated or stopped, or a SIGINT is
557 if (job
->state
== JOBDONE
) {
558 status
= job
->ps
[job
->nprocs
- 1].status
;
559 if (WIFEXITED(status
))
560 retval
= WEXITSTATUS(status
);
562 retval
= WTERMSIG(status
) + 128;
563 if (! iflag
|| ! job
->changed
)
573 for (jp
= jobtab
; jp
< jobtab
+ njobs
; jp
++)
574 if (jp
->used
&& jp
->state
== JOBDONE
) {
575 if (! iflag
|| ! jp
->changed
)
583 for (jp
= jobtab
; ; jp
++) {
584 if (jp
>= jobtab
+ njobs
) { /* no running procs */
587 if (jp
->used
&& jp
->state
== 0)
591 } while (dowait(DOWAIT_BLOCK
| DOWAIT_SIG
, (struct job
*)NULL
) != -1);
593 sig
= pendingsig_waitcmd
;
594 pendingsig_waitcmd
= 0;
601 jobidcmd(int argc __unused
, char **argv __unused
)
607 jp
= getjob(*argptr
);
608 for (i
= 0 ; i
< jp
->nprocs
; ) {
609 out1fmt("%d", (int)jp
->ps
[i
].pid
);
610 out1c(++i
< jp
->nprocs
? ' ' : '\n');
618 * Convert a job name to a job structure.
622 getjob_nonotfound(const char *name
)
625 struct job
*found
, *jp
;
634 error("No current job");
637 if (name
[0] == '%') {
638 if (is_digit(name
[1])) {
639 jobno
= number(name
+ 1);
640 if (jobno
> 0 && jobno
<= njobs
641 && jobtab
[jobno
- 1].used
!= 0)
642 return &jobtab
[jobno
- 1];
644 } else if ((name
[1] == '%' || name
[1] == '+') &&
646 if ((jp
= getcurjob(NULL
)) == NULL
)
647 error("No current job");
649 } else if (name
[1] == '-' && name
[2] == '\0') {
650 if ((jp
= getcurjob(NULL
)) == NULL
||
651 (jp
= getcurjob(jp
)) == NULL
)
652 error("No previous job");
655 } else if (name
[1] == '?') {
657 for (jp
= jobtab
, i
= njobs
; --i
>= 0 ; jp
++) {
658 if (jp
->used
&& jp
->nprocs
> 0
659 && strstr(jp
->ps
[0].cmd
, name
+ 2) != NULL
) {
661 error("%s: ambiguous", name
);
668 namelen
= strlen(name
);
670 for (jp
= jobtab
, i
= njobs
; --i
>= 0 ; jp
++) {
671 if (jp
->used
&& jp
->nprocs
> 0
672 && strncmp(jp
->ps
[0].cmd
, name
+ 1,
675 error("%s: ambiguous", name
);
682 } else if (is_number(name
)) {
683 pid
= (pid_t
)number(name
);
684 for (jp
= jobtab
, i
= njobs
; --i
>= 0 ; jp
++) {
685 if (jp
->used
&& jp
->nprocs
> 0
686 && jp
->ps
[jp
->nprocs
- 1].pid
== pid
)
695 getjob(const char *name
)
699 jp
= getjob_nonotfound(name
);
701 error("No such job: %s", name
);
707 killjob(const char *name
, int sig
)
713 if (jp
->state
== JOBDONE
)
716 return kill(-jp
->ps
[0].pid
, sig
);
719 for (i
= 0; i
< jp
->nprocs
; i
++)
720 if (jp
->ps
[i
].status
== -1 || WIFSTOPPED(jp
->ps
[i
].status
)) {
721 if (kill(jp
->ps
[i
].pid
, sig
) == 0)
729 * Return a new job structure,
733 makejob(union node
*node __unused
, int nprocs
)
738 for (i
= njobs
, jp
= jobtab
; ; jp
++) {
742 jobtab
= ckmalloc(4 * sizeof jobtab
[0]);
747 jp
= ckmalloc((njobs
+ 4) * sizeof jobtab
[0]);
748 memcpy(jp
, jobtab
, njobs
* sizeof jp
[0]);
750 /* Relocate `next' pointers and list head */
752 jobmru
= &jp
[jobmru
- jobtab
];
753 for (i
= 0; i
< njobs
; i
++)
754 if (jp
[i
].next
!= NULL
)
755 jp
[i
].next
= &jp
[jp
[i
].next
-
759 bgjob
= &jp
[bgjob
- jobtab
];
760 /* Relocate `ps' pointers */
761 for (i
= 0; i
< njobs
; i
++)
762 if (jp
[i
].ps
== &jobtab
[i
].ps0
)
763 jp
[i
].ps
= &jp
[i
].ps0
;
768 for (i
= 4 ; --i
>= 0 ; jobtab
[njobs
++].used
= 0)
788 jp
->ps
= ckmalloc(nprocs
* sizeof (struct procstat
));
793 TRACE(("makejob(%p, %d) returns %%%td\n", (void *)node
, nprocs
,
800 setcurjob(struct job
*cj
)
802 struct job
*jp
, *prev
;
804 for (prev
= NULL
, jp
= jobmru
; jp
!= NULL
; prev
= jp
, jp
= jp
->next
) {
807 prev
->next
= jp
->next
;
820 deljob(struct job
*j
)
822 struct job
*jp
, *prev
;
824 for (prev
= NULL
, jp
= jobmru
; jp
!= NULL
; prev
= jp
, jp
= jp
->next
) {
827 prev
->next
= jp
->next
;
836 * Return the most recently used job that isn't `nj', and preferably one
840 getcurjob(struct job
*nj
)
844 /* Try to find a stopped one.. */
845 for (jp
= jobmru
; jp
!= NULL
; jp
= jp
->next
)
846 if (jp
->used
&& jp
!= nj
&& jp
->state
== JOBSTOPPED
)
848 /* Otherwise the most recently used job that isn't `nj' */
849 for (jp
= jobmru
; jp
!= NULL
; jp
= jp
->next
)
850 if (jp
->used
&& jp
!= nj
)
859 * Fork of a subshell. If we are doing job control, give the subshell its
860 * own process group. Jp is a job structure that the job is to be added to.
861 * N is the command that will be evaluated by the child. Both jp and n may
862 * be NULL. The mode parameter can be one of the following:
863 * FORK_FG - Fork off a foreground process.
864 * FORK_BG - Fork off a background process.
865 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
866 * process group even if job control is on.
868 * When job control is turned off, background processes have their standard
869 * input redirected to /dev/null (except for the second and later processes
874 forkshell(struct job
*jp
, union node
*n
, int mode
)
879 TRACE(("forkshell(%%%td, %p, %d) called\n", jp
- jobtab
, (void *)n
,
882 if (mode
== FORK_BG
&& (jp
== NULL
|| jp
->nprocs
== 0))
887 TRACE(("Fork failed, errno=%d\n", errno
));
889 error("Cannot fork: %s", strerror(errno
));
896 TRACE(("Child shell %d\n", (int)getpid()));
899 handler
= &main_handler
;
905 jobctl
= 0; /* do job control only in root shell */
906 if (wasroot
&& mode
!= FORK_NOJOB
&& mflag
) {
907 if (jp
== NULL
|| jp
->nprocs
== 0)
910 pgrp
= jp
->ps
[0].pid
;
911 if (setpgid(0, pgrp
) == 0 && mode
== FORK_FG
&&
913 /*** this causes superfluous TIOCSPGRPS ***/
914 if (tcsetpgrp(ttyfd
, pgrp
) < 0)
915 error("tcsetpgrp failed, errno=%d", errno
);
919 } else if (mode
== FORK_BG
) {
922 if ((jp
== NULL
|| jp
->nprocs
== 0) &&
923 ! fd0_redirected_p ()) {
925 if (open(_PATH_DEVNULL
, O_RDONLY
) != 0)
926 error("cannot open %s: %s",
927 _PATH_DEVNULL
, strerror(errno
));
931 if (mode
== FORK_BG
) {
934 if ((jp
== NULL
|| jp
->nprocs
== 0) &&
935 ! fd0_redirected_p ()) {
937 if (open(_PATH_DEVNULL
, O_RDONLY
) != 0)
938 error("cannot open %s: %s",
939 _PATH_DEVNULL
, strerror(errno
));
944 for (i
= njobs
, p
= jobtab
; --i
>= 0 ; p
++)
948 if (wasroot
&& iflag
) {
955 if (rootshell
&& mode
!= FORK_NOJOB
&& mflag
) {
956 if (jp
== NULL
|| jp
->nprocs
== 0)
959 pgrp
= jp
->ps
[0].pid
;
962 if (mode
== FORK_BG
) {
963 if (bgjob
!= NULL
&& bgjob
->state
== JOBDONE
&&
964 !bgjob
->remembered
&& !iflag
)
966 backgndpid
= pid
; /* set $! */
970 struct procstat
*ps
= &jp
->ps
[jp
->nprocs
++];
974 if (iflag
&& rootshell
&& n
)
975 ps
->cmd
= commandtext(n
);
976 jp
->foreground
= mode
== FORK_FG
;
982 TRACE(("In parent shell: child = %d\n", (int)pid
));
988 vforkexecshell(struct job
*jp
, char **argv
, char **envp
, const char *path
, int idx
, int pip
[2])
991 struct jmploc jmploc
;
992 struct jmploc
*savehandler
;
994 TRACE(("vforkexecshell(%%%td, %s, %p) called\n", jp
- jobtab
, argv
[0],
998 savehandler
= handler
;
1001 TRACE(("Vfork failed, errno=%d\n", errno
));
1003 error("Cannot fork: %s", strerror(errno
));
1006 TRACE(("Child shell %d\n", (int)getpid()));
1007 if (setjmp(jmploc
.loc
))
1008 _exit(exception
== EXEXEC
? exerrno
: 2);
1017 shellexec(argv
, envp
, path
, idx
);
1019 handler
= savehandler
;
1021 struct procstat
*ps
= &jp
->ps
[jp
->nprocs
++];
1031 TRACE(("In parent shell: child = %d\n", (int)pid
));
1037 * Wait for job to finish.
1039 * Under job control we have the problem that while a child process is
1040 * running interrupts generated by the user are sent to the child but not
1041 * to the shell. This means that an infinite loop started by an inter-
1042 * active user may be hard to kill. With job control turned off, an
1043 * interactive user may place an interactive program inside a loop. If
1044 * the interactive program catches interrupts, the user doesn't want
1045 * these interrupts to also abort the loop. The approach we take here
1046 * is to have the shell ignore interrupt signals while waiting for a
1047 * foreground process to terminate, and then send itself an interrupt
1048 * signal if the child process was terminated by an interrupt signal.
1049 * Unfortunately, some programs want to do a bit of cleanup and then
1050 * exit on interrupt; unless these processes terminate themselves by
1051 * sending a signal to themselves (instead of calling exit) they will
1052 * confuse this approach.
1056 waitforjob(struct job
*jp
, int *signaled
)
1059 int propagate_int
= jp
->jobctl
&& jp
->foreground
;
1065 TRACE(("waitforjob(%%%td) called\n", jp
- jobtab
+ 1));
1066 while (jp
->state
== 0)
1067 if (dowait(DOWAIT_BLOCK
| (Tflag
? DOWAIT_SIG
|
1068 DOWAIT_SIG_TRAP
: 0), jp
) == -1)
1072 if (ttyfd
>= 0 && tcsetpgrp(ttyfd
, rootpid
) < 0)
1073 error("tcsetpgrp failed, errno=%d\n", errno
);
1075 if (jp
->state
== JOBSTOPPED
)
1078 status
= jp
->ps
[jp
->nprocs
- 1].status
;
1079 if (signaled
!= NULL
)
1080 *signaled
= WIFSIGNALED(status
);
1081 /* convert to 8 bits */
1082 if (WIFEXITED(status
))
1083 st
= WEXITSTATUS(status
);
1085 else if (WIFSTOPPED(status
))
1086 st
= WSTOPSIG(status
) + 128;
1089 st
= WTERMSIG(status
) + 128;
1090 if (! JOBS
|| jp
->state
== JOBDONE
)
1092 if (int_pending()) {
1093 if (!WIFSIGNALED(status
) || WTERMSIG(status
) != SIGINT
)
1097 else if (rootshell
&& propagate_int
&&
1098 WIFSIGNALED(status
) && WTERMSIG(status
) == SIGINT
)
1099 kill(getpid(), SIGINT
);
1107 dummy_handler(int sig __unused
)
1112 * Wait for a process to terminate.
1116 dowait(int mode
, struct job
*job
)
1118 struct sigaction sa
, osa
;
1119 sigset_t mask
, omask
;
1122 struct procstat
*sp
;
1124 struct job
*thisjob
;
1131 int restore_sigchld
;
1133 TRACE(("dowait(%d, %p) called\n", mode
, job
));
1134 restore_sigchld
= 0;
1135 if ((mode
& DOWAIT_SIG
) != 0) {
1137 sigprocmask(SIG_BLOCK
, &mask
, &omask
);
1139 if (!issigchldtrapped()) {
1140 restore_sigchld
= 1;
1141 sa
.sa_handler
= dummy_handler
;
1143 sigemptyset(&sa
.sa_mask
);
1144 sigaction(SIGCHLD
, &sa
, &osa
);
1150 wflags
= WUNTRACED
| WCONTINUED
;
1154 if ((mode
& (DOWAIT_BLOCK
| DOWAIT_SIG
)) != DOWAIT_BLOCK
)
1156 pid
= wait3(&status
, wflags
, (struct rusage
*)NULL
);
1157 TRACE(("wait returns %d, status=%d\n", (int)pid
, status
));
1158 if (pid
== 0 && (mode
& DOWAIT_SIG
) != 0) {
1160 if (((mode
& DOWAIT_SIG_TRAP
) != 0 ?
1161 pendingsig
: pendingsig_waitcmd
) != 0) {
1169 } while (pid
== -1 && errno
== EINTR
);
1170 if (pid
== -1 && errno
== ECHILD
&& job
!= NULL
)
1171 job
->state
= JOBDONE
;
1172 if ((mode
& DOWAIT_SIG
) != 0) {
1173 if (restore_sigchld
)
1174 sigaction(SIGCHLD
, &osa
, NULL
);
1175 sigprocmask(SIG_SETMASK
, &omask
, NULL
);
1182 for (jp
= jobtab
; jp
< jobtab
+ njobs
; jp
++) {
1183 if (jp
->used
&& jp
->nprocs
> 0) {
1186 for (sp
= jp
->ps
; sp
< jp
->ps
+ jp
->nprocs
; sp
++) {
1189 if (sp
->pid
== pid
&& (sp
->status
== -1 ||
1190 WIFSTOPPED(sp
->status
))) {
1191 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
1192 (int)pid
, sp
->status
,
1194 if (WIFCONTINUED(status
)) {
1198 sp
->status
= status
;
1201 if (sp
->status
== -1)
1203 else if (WIFSTOPPED(sp
->status
))
1206 if (stopped
) { /* stopped or done */
1207 int state
= done
? JOBDONE
: JOBSTOPPED
;
1208 if (jp
->state
!= state
) {
1209 TRACE(("Job %td: changing state from %d to %d\n", jp
- jobtab
+ 1, jp
->state
, state
));
1212 if (done
&& !jp
->remembered
&&
1213 !iflag
&& jp
!= bgjob
)
1225 if (!thisjob
|| thisjob
->state
== 0)
1227 else if ((!rootshell
|| !iflag
|| thisjob
== job
) &&
1228 thisjob
->foreground
&& thisjob
->state
!= JOBSTOPPED
) {
1231 for (sp
= thisjob
->ps
; sp
< thisjob
->ps
+ thisjob
->nprocs
; sp
++)
1232 if (WIFSIGNALED(sp
->status
)) {
1233 sig
= WTERMSIG(sp
->status
);
1234 coredump
= WCOREDUMP(sp
->status
);
1236 if (sig
> 0 && sig
!= SIGINT
&& sig
!= SIGPIPE
) {
1237 sigstr
= strsignal(sig
);
1241 out2str("Unknown signal");
1243 out2str(" (core dumped)");
1248 TRACE(("Not printing status, rootshell=%d, job=%p\n", rootshell
, job
));
1249 thisjob
->changed
= 1;
1257 * return 1 if there are stopped jobs, otherwise 0
1259 int job_warning
= 0;
1268 for (jobno
= 1, jp
= jobtab
; jobno
<= njobs
; jobno
++, jp
++) {
1271 if (jp
->state
== JOBSTOPPED
) {
1272 out2fmt_flush("You have stopped jobs.\n");
1285 while (njobs
> 0 && dowait(0, NULL
) > 0)
1293 return backgndpid
!= -1;
1300 if (bgjob
!= NULL
&& !forcelocal
)
1301 bgjob
->remembered
= 1;
1306 * Return a string identifying a command (to be printed by the
1310 static char *cmdnextc
;
1311 static int cmdnleft
;
1312 #define MAXCMDTEXT 200
1315 commandtext(union node
*n
)
1319 cmdnextc
= name
= ckmalloc(MAXCMDTEXT
);
1320 cmdnleft
= MAXCMDTEXT
- 4;
1328 cmdtxtdogroup(union node
*n
)
1337 cmdtxtredir(union node
*n
, const char *op
, int deffd
)
1341 if (n
->nfile
.fd
!= deffd
) {
1342 s
[0] = n
->nfile
.fd
+ '0';
1347 if (n
->type
== NTOFD
|| n
->type
== NFROMFD
) {
1348 if (n
->ndup
.dupfd
>= 0)
1349 s
[0] = n
->ndup
.dupfd
+ '0';
1355 cmdtxt(n
->nfile
.fname
);
1361 cmdtxt(union node
*n
)
1364 struct nodelist
*lp
;
1370 cmdtxt(n
->nbinary
.ch1
);
1372 cmdtxt(n
->nbinary
.ch2
);
1375 cmdtxt(n
->nbinary
.ch1
);
1377 cmdtxt(n
->nbinary
.ch2
);
1380 cmdtxt(n
->nbinary
.ch1
);
1382 cmdtxt(n
->nbinary
.ch2
);
1385 for (lp
= n
->npipe
.cmdlist
; lp
; lp
= lp
->next
) {
1393 cmdtxt(n
->nredir
.n
);
1398 cmdtxt(n
->nredir
.n
);
1402 cmdtxt(n
->nif
.test
);
1404 cmdtxt(n
->nif
.ifpart
);
1409 cmdtxt(n
->nbinary
.ch1
);
1410 cmdtxtdogroup(n
->nbinary
.ch2
);
1414 cmdtxt(n
->nbinary
.ch1
);
1415 cmdtxtdogroup(n
->nbinary
.ch2
);
1419 cmdputs(n
->nfor
.var
);
1424 cmdputs(n
->ncase
.expr
->narg
.text
);
1428 cmdputs(n
->narg
.text
);
1433 cmdtxt(n
->nnot
.com
);
1436 for (np
= n
->ncmd
.args
; np
; np
= np
->narg
.next
) {
1441 for (np
= n
->ncmd
.redirect
; np
; np
= np
->nfile
.next
) {
1447 cmdputs(n
->narg
.text
);
1450 cmdtxtredir(n
, ">", 1);
1453 cmdtxtredir(n
, ">>", 1);
1456 cmdtxtredir(n
, ">&", 1);
1459 cmdtxtredir(n
, ">|", 1);
1462 cmdtxtredir(n
, "<", 0);
1465 cmdtxtredir(n
, "<>", 0);
1468 cmdtxtredir(n
, "<&", 0);
1483 cmdputs(const char *s
)
1494 while ((c
= *p
++) != '\0') {
1497 else if (c
== CTLVAR
) {
1502 if ((subtype
& VSTYPE
) == VSLENGTH
&& --cmdnleft
> 0)
1504 } else if (c
== '=' && subtype
!= 0) {
1505 *q
= "}-+?=##%%\0X"[(subtype
& VSTYPE
) - VSNORMAL
];
1510 if (((subtype
& VSTYPE
) == VSTRIMLEFTMAX
||
1511 (subtype
& VSTYPE
) == VSTRIMRIGHTMAX
) &&
1515 } else if (c
== CTLENDVAR
) {
1517 } else if (c
== CTLBACKQ
|| c
== CTLBACKQ
+CTLQUOTE
) {
1527 } else if (c
== CTLARI
) {
1535 } else if (c
== CTLENDARI
) {
1536 if (--cmdnleft
> 0) {
1540 } else if (c
== CTLQUOTEMARK
|| c
== CTLQUOTEEND
)
1541 cmdnleft
++; /* ignore */
1544 if (--cmdnleft
<= 0) {