1 /* $NetBSD: jobs.c,v 1.63 2005/06/01 15:41:19 lukem Exp $ */
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 static char sccsid
[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95";
39 __RCSID("$NetBSD: jobs.c,v 1.63 2005/06/01 15:41:19 lukem Exp $");
46 #include <sys/types.h>
49 #if JOBS && !defined(_MSC_VER)
66 #include "shinstance.h"
68 //static struct job *jobtab; /* array of jobs */
69 //static int njobs; /* size of array */
70 //static int jobs_invalid; /* set in child */
71 //MKINIT pid_t backgndpid = -1; /* pid of last background process */
73 //int initialpgrp; /* pgrp of shell on invocation */
74 //static int curjob = -1; /* current job */
76 //static int ttyfd = -1;
78 STATIC
void restartjob(shinstance
*, struct job
*);
79 STATIC
void freejob(shinstance
*, struct job
*);
80 STATIC
struct job
*getjob(shinstance
*, const char *, int);
81 STATIC
int dowait(shinstance
*, int, struct job
*);
82 STATIC
int waitproc(shinstance
*, int, struct job
*, int *);
83 STATIC
void cmdtxt(shinstance
*, union node
*);
84 STATIC
void cmdlist(shinstance
*, union node
*, int);
85 STATIC
void cmdputs(shinstance
*, const char *);
89 * Turn job control on and off.
91 * Note: This code assumes that the third arg to ioctl is a character
92 * pointer, which is true on Berkeley systems but not System V. Since
93 * System V doesn't have job control yet, this isn't a problem now.
99 setjobctl(shinstance
*psh
, int on
)
101 if (on
== psh
->jobctl
|| psh
->rootshell
== 0)
106 if (psh
->ttyfd
!= -1)
107 shfile_close(&psh
->fdtab
, psh
->ttyfd
);
108 if ((psh
->ttyfd
= shfile_open(&psh
->fdtab
, "/dev/tty", O_RDWR
, 0)) == -1) {
109 for (i
= 0; i
< 3; i
++) {
110 if (shfile_isatty(&psh
->fdtab
, i
)
111 && (psh
->ttyfd
= shfile_dup(&psh
->fdtab
, i
)) != -1)
117 /* Move to a high fd */
118 for (i
= 10; i
> 2; i
--) {
119 if ((err
= shfile_fcntl(&psh
->fdtab
, psh
->ttyfd
, F_DUPFD
, (1 << i
) - 1)) != -1)
123 shfile_close(&psh
->fdtab
, psh
->ttyfd
);
126 err
= shfile_cloexec(&psh
->fdtab
, psh
->ttyfd
, 1);
128 shfile_close(&psh
->fdtab
, psh
->ttyfd
);
132 do { /* while we are in the background */
133 if ((psh
->initialpgrp
= sh_tcgetpgrp(psh
, psh
->ttyfd
)) < 0) {
135 out2str(psh
, "sh: can't access tty; job control turned off\n");
139 if (psh
->initialpgrp
== -1)
140 psh
->initialpgrp
= sh_getpgrp(psh
);
141 else if (psh
->initialpgrp
!= sh_getpgrp(psh
)) {
142 sh_killpg(psh
, 0, SIGTTIN
);
147 setsignal(psh
, SIGTSTP
, 0);
148 setsignal(psh
, SIGTTOU
, 0);
149 setsignal(psh
, SIGTTIN
, 0);
150 if (sh_getpgid(psh
, 0) != psh
->rootpid
&& sh_setpgid(psh
, 0, psh
->rootpid
) == -1)
151 error(psh
, "Cannot set process group (%s) at %d",
152 strerror(errno
), __LINE__
);
153 if (sh_tcsetpgrp(psh
, psh
->ttyfd
, psh
->rootpid
) == -1)
154 error(psh
, "Cannot set tty process group (%s) at %d",
155 strerror(errno
), __LINE__
);
156 } else { /* turning job control off */
157 if (sh_getpgid(psh
, 0) != psh
->initialpgrp
&& sh_setpgid(psh
, 0, psh
->initialpgrp
) == -1)
158 error(psh
, "Cannot set process group (%s) at %d",
159 strerror(errno
), __LINE__
);
160 if (sh_tcsetpgrp(psh
, psh
->ttyfd
, psh
->initialpgrp
) == -1)
161 error(psh
, "Cannot set tty process group (%s) at %d",
162 strerror(errno
), __LINE__
);
163 shfile_close(&psh
->fdtab
, psh
->ttyfd
);
165 setsignal(psh
, SIGTSTP
, 0);
166 setsignal(psh
, SIGTTOU
, 0);
167 setsignal(psh
, SIGTTIN
, 0);
177 psh
->backgndpid
= -1;
189 fgcmd(shinstance
*psh
, int argc
, char **argv
)
196 jp
= getjob(psh
, *psh
->argptr
, 0);
198 error(psh
, "job not created under job control");
199 out1fmt(psh
, "%s", jp
->ps
[0].cmd
);
200 for (i
= 1; i
< jp
->nprocs
; i
++)
201 out1fmt(psh
, " | %s", jp
->ps
[i
].cmd
);
203 output_flushall(psh
);
205 for (i
= 0; i
< jp
->nprocs
; i
++)
206 if (sh_tcsetpgrp(psh
, psh
->ttyfd
, jp
->ps
[i
].pid
) != -1)
209 if (i
>= jp
->nprocs
) {
210 error(psh
, "Cannot set tty process group (%s) at %d",
211 strerror(errno
), __LINE__
);
215 status
= waitforjob(psh
, jp
);
221 set_curjob(shinstance
*psh
, struct job
*jp
, int mode
)
223 struct job
*jp1
, *jp2
;
226 ji
= (int)(jp
- psh
->jobtab
);
228 /* first remove from list */
229 if (ji
== psh
->curjob
)
230 psh
->curjob
= jp
->prev_job
;
232 for (i
= 0; i
< psh
->njobs
; i
++) {
233 if (psh
->jobtab
[i
].prev_job
!= ji
)
235 psh
->jobtab
[i
].prev_job
= jp
->prev_job
;
240 /* Then re-insert in correct position */
242 case 0: /* job being deleted */
245 case 1: /* newly created job or backgrounded job,
246 put after all stopped jobs. */
247 if (psh
->curjob
!= -1 && psh
->jobtab
[psh
->curjob
].state
== JOBSTOPPED
) {
248 for (jp1
= psh
->jobtab
+ psh
->curjob
; ; jp1
= jp2
) {
249 if (jp1
->prev_job
== -1)
251 jp2
= psh
->jobtab
+ jp1
->prev_job
;
252 if (jp2
->state
!= JOBSTOPPED
)
255 jp
->prev_job
= jp1
->prev_job
;
260 case 2: /* newly stopped job - becomes psh->curjob */
261 jp
->prev_job
= psh
->curjob
;
268 bgcmd(shinstance
*psh
, int argc
, char **argv
)
275 jp
= getjob(psh
, *psh
->argptr
, 0);
277 error(psh
, "job not created under job control");
278 set_curjob(psh
, jp
, 1);
279 out1fmt(psh
, "[%ld] %s", (long)(jp
- psh
->jobtab
+ 1), jp
->ps
[0].cmd
);
280 for (i
= 1; i
< jp
->nprocs
; i
++)
281 out1fmt(psh
, " | %s", jp
->ps
[i
].cmd
);
283 output_flushall(psh
);
285 } while (*psh
->argptr
&& *++psh
->argptr
);
291 restartjob(shinstance
*psh
, struct job
*jp
)
296 if (jp
->state
== JOBDONE
)
299 for (i
= 0; i
< jp
->nprocs
; i
++)
300 if (sh_killpg(psh
, jp
->ps
[i
].pid
, SIGCONT
) != -1)
303 error(psh
, "Cannot continue job (%s)", strerror(errno
));
304 for (ps
= jp
->ps
, i
= jp
->nprocs
; --i
>= 0 ; ps
++) {
305 if (WIFSTOPPED(ps
->status
)) {
307 jp
->state
= JOBRUNNING
;
315 showjob(shinstance
*psh
, struct output
*out
, struct job
*jp
, int mode
)
324 if (mode
& SHOW_PGID
) {
325 /* just output process (group) id of pipeline */
326 outfmt(out
, "%ld\n", (long)jp
->ps
->pid
);
336 mode
|= SHOW_MULTILINE
;
338 if ((procno
> 1 && !(mode
& SHOW_MULTILINE
))
339 || (mode
& SHOW_SIGNALLED
)) {
340 /* See if we have more than one status to report */
344 int st1
= ps
->status
;
346 /* yes - need multi-line output */
347 mode
|= SHOW_MULTILINE
;
348 if (st1
== -1 || !(mode
& SHOW_SIGNALLED
) || WIFEXITED(st1
))
350 if (WIFSTOPPED(st1
) || ((st1
= WTERMSIG(st1
) & 0x7f)
351 && st1
!= SIGINT
&& st1
!= SIGPIPE
))
354 } while (ps
++, --procno
);
358 if (mode
& SHOW_SIGNALLED
&& !(mode
& SHOW_ISSIG
)) {
359 if (jp
->state
== JOBDONE
&& !(mode
& SHOW_NO_FREE
)) {
360 TRACE((psh
, "showjob: freeing job %d\n", jp
- psh
->jobtab
+ 1));
366 for (ps
= jp
->ps
; --procno
>= 0; ps
++) { /* for each process */
368 fmtstr(s
, 16, "[%ld] %c ",
369 (long)(jp
- psh
->jobtab
+ 1),
371 jp
== psh
->jobtab
+ psh
->curjob
? '+' :
372 psh
->curjob
!= -1 && jp
== psh
->jobtab
+
373 psh
->jobtab
[psh
->curjob
].prev_job
? '-' :
379 if (mode
& SHOW_PID
) {
380 fmtstr(s
+ col
, 16, "%ld ", (long)ps
->pid
);
381 col
+= strlen(s
+ col
);
383 if (ps
->status
== -1) {
384 scopy("Running", s
+ col
);
385 } else if (WIFEXITED(ps
->status
)) {
386 st
= WEXITSTATUS(ps
->status
);
388 fmtstr(s
+ col
, 16, "Done(%d)", st
);
390 fmtstr(s
+ col
, 16, "Done");
393 if (WIFSTOPPED(ps
->status
))
394 st
= WSTOPSIG(ps
->status
);
395 else /* WIFSIGNALED(ps->status) */
397 st
= WTERMSIG(ps
->status
);
399 if (st
< NSIG
&& sys_siglist
[st
])
400 scopyn(sys_siglist
[st
], s
+ col
, 32);
402 fmtstr(s
+ col
, 16, "Signal %d", st
);
403 if (WCOREDUMP(ps
->status
)) {
404 col
+= strlen(s
+ col
);
405 scopyn(" (core dumped)", s
+ col
, 64 - col
);
408 col
+= strlen(s
+ col
);
414 outstr(ps
->cmd
, out
);
415 if (mode
& SHOW_MULTILINE
) {
421 while (--procno
>= 0)
422 outfmt(out
, " | %s", (++ps
)->cmd
);
428 if (jp
->state
== JOBDONE
&& !(mode
& SHOW_NO_FREE
))
434 jobscmd(shinstance
*psh
, int argc
, char **argv
)
437 int sv
= psh
->jobs_invalid
;
439 psh
->jobs_invalid
= 0;
441 while ((m
= nextopt(psh
, "lp")))
448 showjob(psh
, psh
->out1
, getjob(psh
, *psh
->argptr
,0), mode
);
449 while (*++psh
->argptr
);
451 showjobs(psh
, psh
->out1
, mode
);
452 psh
->jobs_invalid
= sv
;
458 * Print a list of jobs. If "change" is nonzero, only print jobs whose
459 * statuses have changed since the last call to showjobs.
461 * If the shell is interrupted in the process of creating a job, the
462 * result may be a job structure containing zero processes. Such structures
463 * will be freed here.
467 showjobs(shinstance
*psh
, struct output
*out
, int mode
)
471 int silent
= 0, gotpid
;
473 TRACE((psh
, "showjobs(%x) called\n", mode
));
475 /* If not even one one job changed, there is nothing to do */
476 gotpid
= dowait(psh
, 0, NULL
);
477 while (dowait(psh
, 0, NULL
) > 0)
481 * Check if we are not in our foreground group, and if not
484 if (mflag(psh
) && gotpid
!= -1 && sh_tcgetpgrp(psh
, psh
->ttyfd
) != sh_getpid(psh
)) {
485 if (sh_tcsetpgrp(psh
, psh
->ttyfd
, sh_getpid(psh
)) == -1)
486 error(psh
, "Cannot set tty process group (%s) at %d",
487 strerror(errno
), __LINE__
);
488 TRACE((psh
, "repaired tty process group\n"));
492 if (psh
->jobs_invalid
)
495 for (jobno
= 1, jp
= psh
->jobtab
; jobno
<= psh
->njobs
; jobno
++, jp
++) {
498 if (jp
->nprocs
== 0) {
502 if ((mode
& SHOW_CHANGED
) && !jp
->changed
)
504 if (silent
&& jp
->changed
) {
508 showjob(psh
, out
, jp
, mode
);
513 * Mark a job structure as unused.
517 freejob(shinstance
*psh
, struct job
*jp
)
520 if (jp
->ps
!= &jp
->ps0
) {
527 set_curjob(psh
, jp
, 0);
535 waitcmd(shinstance
*psh
, int argc
, char **argv
)
544 /* wait for all jobs */
546 if (psh
->jobs_invalid
)
549 if (jp
>= psh
->jobtab
+ psh
->njobs
) {
550 /* no running procs */
553 if (!jp
->used
|| jp
->state
!= JOBRUNNING
) {
557 if (dowait(psh
, 1, (struct job
*)NULL
) == -1)
563 retval
= 127; /* XXXGCC: -Wuninitialized */
564 for (; *psh
->argptr
; psh
->argptr
++) {
565 job
= getjob(psh
, *psh
->argptr
, 1);
570 /* loop until process terminated or stopped */
571 while (job
->state
== JOBRUNNING
) {
572 if (dowait(psh
, 1, (struct job
*)NULL
) == -1)
575 status
= job
->ps
[job
->nprocs
].status
;
576 if (WIFEXITED(status
))
577 retval
= WEXITSTATUS(status
);
579 else if (WIFSTOPPED(status
))
580 retval
= WSTOPSIG(status
) + 128;
583 /* XXX: limits number of signals */
584 retval
= WTERMSIG(status
) + 128;
595 jobidcmd(shinstance
*psh
, int argc
, char **argv
)
601 jp
= getjob(psh
, *psh
->argptr
, 0);
602 for (i
= 0 ; i
< jp
->nprocs
; ) {
603 out1fmt(psh
, "%ld", (long)jp
->ps
[i
].pid
);
604 out1c(psh
, ++i
< jp
->nprocs
? ' ' : '\n');
610 getjobpgrp(shinstance
*psh
, const char *name
)
614 jp
= getjob(psh
, name
, 1);
617 return -jp
->ps
[0].pid
;
621 * Convert a job name to a job structure.
625 getjob(shinstance
*psh
, const char *name
, int noerror
)
631 const char *err_msg
= "No such job: %s";
637 err_msg
= "No current job";
638 } else if (name
[0] == '%') {
639 if (is_number(name
+ 1)) {
640 jobno
= number(psh
, name
+ 1) - 1;
641 } else if (!name
[2]) {
648 err_msg
= "No current job";
653 jobno
= psh
->jobtab
[jobno
].prev_job
;
654 err_msg
= "No previous job";
664 for (jp
= psh
->jobtab
, i
= psh
->njobs
; --i
>= 0 ; jp
++) {
665 if (!jp
->used
|| jp
->nprocs
<= 0)
668 && strstr(jp
->ps
[0].cmd
, name
+ 2))
669 || prefix(name
+ 1, jp
->ps
[0].cmd
)) {
671 err_msg
= "%s: ambiguous";
682 } else if (is_number(name
)) {
683 pid
= number(psh
, name
);
684 for (jp
= psh
->jobtab
, i
= psh
->njobs
; --i
>= 0 ; jp
++) {
685 if (jp
->used
&& jp
->nprocs
> 0
686 && jp
->ps
[jp
->nprocs
- 1].pid
== pid
)
691 if (!psh
->jobs_invalid
&& jobno
>= 0 && jobno
< psh
->njobs
) {
692 jp
= psh
->jobtab
+ jobno
;
697 error(psh
, err_msg
, name
);
704 * Return a new job structure,
708 makejob(shinstance
*psh
, union node
*node
, int nprocs
)
713 if (psh
->jobs_invalid
) {
714 for (i
= psh
->njobs
, jp
= psh
->jobtab
; --i
>= 0 ; jp
++) {
718 psh
->jobs_invalid
= 0;
721 for (i
= psh
->njobs
, jp
= psh
->jobtab
; ; jp
++) {
724 if (psh
->njobs
== 0) {
725 psh
->jobtab
= ckmalloc(4 * sizeof psh
->jobtab
[0]);
727 jp
= ckmalloc((psh
->njobs
+ 4) * sizeof psh
->jobtab
[0]);
728 memcpy(jp
, psh
->jobtab
, psh
->njobs
* sizeof jp
[0]);
729 /* Relocate `ps' pointers */
730 for (i
= 0; i
< psh
->njobs
; i
++)
731 if (jp
[i
].ps
== &psh
->jobtab
[i
].ps0
)
732 jp
[i
].ps
= &jp
[i
].ps0
;
736 jp
= psh
->jobtab
+ psh
->njobs
;
737 for (i
= 4 ; --i
>= 0 ; psh
->jobtab
[psh
->njobs
++].used
= 0);
745 jp
->state
= JOBRUNNING
;
750 jp
->jobctl
= psh
->jobctl
;
751 set_curjob(psh
, jp
, 1);
754 jp
->ps
= ckmalloc(nprocs
* sizeof (struct procstat
));
759 TRACE((psh
, "makejob(0x%lx, %d) returns %%%d\n", (long)node
, nprocs
,
760 jp
- psh
->jobtab
+ 1));
766 * Fork off a subshell. If we are doing job control, give the subshell its
767 * own process group. Jp is a job structure that the job is to be added to.
768 * N is the command that will be evaluated by the child. Both jp and n may
769 * be NULL. The mode parameter can be one of the following:
770 * FORK_FG - Fork off a foreground process.
771 * FORK_BG - Fork off a background process.
772 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
773 * process group even if job control is on.
775 * When job control is turned off, background processes have their standard
776 * input redirected to /dev/null (except for the second and later processes
781 forkshell(shinstance
*psh
, struct job
*jp
, union node
*n
, int mode
)
785 TRACE((psh
, "forkshell(%%%d, %p, %d) called\n", jp
- psh
->jobtab
, n
, mode
));
786 switch ((pid
= sh_fork(psh
))) {
788 TRACE((psh
, "Fork failed, errno=%d\n", errno
));
790 error(psh
, "Cannot fork");
791 return -1; /* won't get here */
793 forkchild(psh
, jp
, n
, mode
, 0);
796 return forkparent(psh
, jp
, n
, mode
, pid
);
801 forkparent(shinstance
*psh
, struct job
*jp
, union node
*n
, int mode
, pid_t pid
)
805 if (psh
->rootshell
&& mode
!= FORK_NOJOB
&& mflag(psh
)) {
806 if (jp
== NULL
|| jp
->nprocs
== 0)
809 pgrp
= jp
->ps
[0].pid
;
810 /* This can fail because we are doing it in the child also */
811 (void)sh_setpgid(psh
, pid
, pgrp
);
814 psh
->backgndpid
= pid
; /* set $! */
816 struct procstat
*ps
= &jp
->ps
[jp
->nprocs
++];
820 if (/* iflag && rootshell && */ n
)
821 commandtext(psh
, ps
, n
);
823 TRACE((psh
, "In parent shell: child = %d\n", pid
));
828 forkchild(shinstance
*psh
, struct job
*jp
, union node
*n
, int mode
, int vforked
)
832 const char *devnull
= _PATH_DEVNULL
;
833 const char *nullerr
= "Can't open %s";
835 wasroot
= psh
->rootshell
;
836 TRACE((psh
, "Child shell %d\n", sh_getpid(psh
)));
840 closescript(psh
, vforked
);
841 clear_traps(psh
, vforked
);
844 psh
->jobctl
= 0; /* do job control only in root shell */
845 if (wasroot
&& mode
!= FORK_NOJOB
&& mflag(psh
)) {
846 if (jp
== NULL
|| jp
->nprocs
== 0)
847 pgrp
= sh_getpid(psh
);
849 pgrp
= jp
->ps
[0].pid
;
850 /* This can fail because we are doing it in the parent also */
851 (void)sh_setpgid(psh
, 0, pgrp
);
852 if (mode
== FORK_FG
) {
853 if (sh_tcsetpgrp(psh
, psh
->ttyfd
, pgrp
) == -1)
854 error(psh
, "Cannot set tty process group (%s) at %d",
855 strerror(errno
), __LINE__
);
857 setsignal(psh
, SIGTSTP
, vforked
);
858 setsignal(psh
, SIGTTOU
, vforked
);
859 } else if (mode
== FORK_BG
) {
860 ignoresig(psh
, SIGINT
, vforked
);
861 ignoresig(psh
, SIGQUIT
, vforked
);
862 if ((jp
== NULL
|| jp
->nprocs
== 0) &&
863 ! fd0_redirected_p(psh
)) {
864 shfile_close(&psh
->fdtab
, 0);
865 if (shfile_open(&psh
->fdtab
, devnull
, O_RDONLY
, 0) != 0)
866 error(psh
, nullerr
, devnull
);
870 if (mode
== FORK_BG
) {
871 ignoresig(psh
, SIGINT
, vforked
);
872 ignoresig(psh
, SIGQUIT
, vforked
);
873 if ((jp
== NULL
|| jp
->nprocs
== 0) &&
874 ! fd0_redirected_p(psh
)) {
875 shfile_close(&psh
->fdtab
, 0);
876 if (shfile_open(&psh
->fdtab
, devnull
, O_RDONLY
, 0) != 0)
877 error(psh
, nullerr
, devnull
);
881 if (wasroot
&& iflag(psh
)) {
882 setsignal(psh
, SIGINT
, vforked
);
883 setsignal(psh
, SIGQUIT
, vforked
);
884 setsignal(psh
, SIGTERM
, vforked
);
888 psh
->jobs_invalid
= 1;
892 * Wait for job to finish.
894 * Under job control we have the problem that while a child process is
895 * running interrupts generated by the user are sent to the child but not
896 * to the shell. This means that an infinite loop started by an inter-
897 * active user may be hard to kill. With job control turned off, an
898 * interactive user may place an interactive program inside a loop. If
899 * the interactive program catches interrupts, the user doesn't want
900 * these interrupts to also abort the loop. The approach we take here
901 * is to have the shell ignore interrupt signals while waiting for a
902 * forground process to terminate, and then send itself an interrupt
903 * signal if the child process was terminated by an interrupt signal.
904 * Unfortunately, some programs want to do a bit of cleanup and then
905 * exit on interrupt; unless these processes terminate themselves by
906 * sending a signal to themselves (instead of calling exit) they will
907 * confuse this approach.
911 waitforjob(shinstance
*psh
, struct job
*jp
)
914 int mypgrp
= sh_getpgrp(psh
);
920 TRACE((psh
, "waitforjob(%%%d) called\n", jp
- psh
->jobtab
+ 1));
921 while (jp
->state
== JOBRUNNING
) {
926 if (sh_tcsetpgrp(psh
, psh
->ttyfd
, mypgrp
) == -1)
927 error(psh
, "Cannot set tty process group (%s) at %d",
928 strerror(errno
), __LINE__
);
930 if (jp
->state
== JOBSTOPPED
&& psh
->curjob
!= jp
- psh
->jobtab
)
931 set_curjob(psh
, jp
, 2);
933 status
= jp
->ps
[jp
->nprocs
- 1].status
;
934 /* convert to 8 bits */
935 if (WIFEXITED(status
))
936 st
= WEXITSTATUS(status
);
938 else if (WIFSTOPPED(status
))
939 st
= WSTOPSIG(status
) + 128;
942 st
= WTERMSIG(status
) + 128;
943 TRACE((psh
, "waitforjob: job %d, nproc %d, status %x, st %x\n",
944 jp
- psh
->jobtab
+ 1, jp
->nprocs
, status
, st
));
948 * This is truly gross.
949 * If we're doing job control, then we did a TIOCSPGRP which
950 * caused us (the shell) to no longer be in the controlling
951 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
952 * intuit from the subprocess exit status whether a SIGINT
953 * occurred, and if so interrupt ourselves. Yuck. - mycroft
955 if (WIFSIGNALED(status
) && WTERMSIG(status
) == SIGINT
)
956 sh_raise_sigint(psh
);/*raise(SIGINT);*/
959 if (! JOBS
|| jp
->state
== JOBDONE
)
968 * Wait for a process to terminate.
972 dowait(shinstance
*psh
, int block
, struct job
*job
)
982 TRACE((psh
, "dowait(%d) called\n", block
));
984 pid
= waitproc(psh
, block
, job
, &status
);
985 TRACE((psh
, "wait returns pid %d, status %d\n", pid
, status
));
986 } while (pid
== -1 && errno
== EINTR
&& psh
->gotsig
[SIGINT
- 1] == 0);
991 for (jp
= psh
->jobtab
; jp
< psh
->jobtab
+ psh
->njobs
; jp
++) {
995 for (sp
= jp
->ps
; sp
< jp
->ps
+ jp
->nprocs
; sp
++) {
998 if (sp
->pid
== pid
) {
999 TRACE((psh
, "Job %d: changing status of proc %d from 0x%x to 0x%x\n", jp
- psh
->jobtab
+ 1, pid
, sp
->status
, status
));
1000 sp
->status
= status
;
1003 if (sp
->status
== -1)
1005 else if (WIFSTOPPED(sp
->status
))
1008 if (stopped
) { /* stopped or done */
1009 int state
= done
? JOBDONE
: JOBSTOPPED
;
1010 if (jp
->state
!= state
) {
1011 TRACE((psh
, "Job %d: changing state from %d to %d\n", jp
- psh
->jobtab
+ 1, jp
->state
, state
));
1015 set_curjob(psh
, jp
, 0);
1022 if (thisjob
&& thisjob
->state
!= JOBRUNNING
) {
1024 if (!psh
->rootshell
|| !iflag(psh
))
1025 mode
= SHOW_SIGNALLED
;
1027 mode
= SHOW_SIGNALLED
| SHOW_NO_FREE
;
1029 showjob(psh
, psh
->out2
, thisjob
, mode
);
1031 TRACE((psh
, "Not printing status, rootshell=%d, job=%p\n",
1032 psh
->rootshell
, job
));
1033 thisjob
->changed
= 1;
1044 * Do a wait system call. If job control is compiled in, we accept
1045 * stopped processes. If block is zero, we return a value of zero
1046 * rather than blocking.
1049 waitproc(shinstance
*psh
, int block
, struct job
*jp
, int *status
)
1054 if (jp
!= NULL
&& jp
->jobctl
)
1059 return sh_waitpid(psh
, -1, status
, flags
);
1063 * return 1 if there are stopped jobs, otherwise 0
1065 //int job_warning = 0;
1067 stoppedjobs(shinstance
*psh
)
1072 if (psh
->job_warning
|| psh
->jobs_invalid
)
1074 for (jobno
= 1, jp
= psh
->jobtab
; jobno
<= psh
->njobs
; jobno
++, jp
++) {
1077 if (jp
->state
== JOBSTOPPED
) {
1078 out2str(psh
, "You have stopped jobs.\n");
1079 psh
->job_warning
= 2;
1088 * Return a string identifying a command (to be printed by the
1092 //STATIC char *cmdnextc;
1093 //STATIC int cmdnleft;
1096 commandtext(shinstance
*psh
, struct procstat
*ps
, union node
*n
)
1100 psh
->cmdnextc
= ps
->cmd
;
1101 if (iflag(psh
) || mflag(psh
) || sizeof(ps
->cmd
) < 100)
1102 len
= sizeof(ps
->cmd
);
1104 len
= sizeof(ps
->cmd
) / 10;
1105 psh
->cmdnleft
= len
;
1107 if (psh
->cmdnleft
<= 0) {
1108 char *p
= ps
->cmd
+ len
- 4;
1114 *psh
->cmdnextc
= '\0';
1115 TRACE((psh
, "commandtext: ps->cmd %x, end %x, left %d\n\t\"%s\"\n",
1116 ps
->cmd
, psh
->cmdnextc
, psh
->cmdnleft
, ps
->cmd
));
1121 cmdtxt(shinstance
*psh
, union node
*n
)
1124 struct nodelist
*lp
;
1129 if (n
== NULL
|| psh
->cmdnleft
<= 0)
1133 cmdtxt(psh
, n
->nbinary
.ch1
);
1135 cmdtxt(psh
, n
->nbinary
.ch2
);
1138 cmdtxt(psh
, n
->nbinary
.ch1
);
1139 cmdputs(psh
, " && ");
1140 cmdtxt(psh
, n
->nbinary
.ch2
);
1143 cmdtxt(psh
, n
->nbinary
.ch1
);
1144 cmdputs(psh
, " || ");
1145 cmdtxt(psh
, n
->nbinary
.ch2
);
1148 for (lp
= n
->npipe
.cmdlist
; lp
; lp
= lp
->next
) {
1151 cmdputs(psh
, " | ");
1156 cmdtxt(psh
, n
->nredir
.n
);
1161 cmdtxt(psh
, n
->nredir
.n
);
1164 cmdputs(psh
, "if ");
1165 cmdtxt(psh
, n
->nif
.test
);
1166 cmdputs(psh
, "; then ");
1167 cmdtxt(psh
, n
->nif
.ifpart
);
1168 if (n
->nif
.elsepart
) {
1169 cmdputs(psh
, "; else ");
1170 cmdtxt(psh
, n
->nif
.elsepart
);
1172 cmdputs(psh
, "; fi");
1175 cmdputs(psh
, "while ");
1178 cmdputs(psh
, "until ");
1180 cmdtxt(psh
, n
->nbinary
.ch1
);
1181 cmdputs(psh
, "; do ");
1182 cmdtxt(psh
, n
->nbinary
.ch2
);
1183 cmdputs(psh
, "; done");
1186 cmdputs(psh
, "for ");
1187 cmdputs(psh
, n
->nfor
.var
);
1188 cmdputs(psh
, " in ");
1189 cmdlist(psh
, n
->nfor
.args
, 1);
1190 cmdputs(psh
, "; do ");
1191 cmdtxt(psh
, n
->nfor
.body
);
1192 cmdputs(psh
, "; done");
1195 cmdputs(psh
, "case ");
1196 cmdputs(psh
, n
->ncase
.expr
->narg
.text
);
1197 cmdputs(psh
, " in ");
1198 for (np
= n
->ncase
.cases
; np
; np
= np
->nclist
.next
) {
1199 cmdtxt(psh
, np
->nclist
.pattern
);
1201 cmdtxt(psh
, np
->nclist
.body
);
1202 cmdputs(psh
, ";; ");
1204 cmdputs(psh
, "esac");
1207 cmdputs(psh
, n
->narg
.text
);
1208 cmdputs(psh
, "() { ... }");
1211 cmdlist(psh
, n
->ncmd
.args
, 1);
1212 cmdlist(psh
, n
->ncmd
.redirect
, 0);
1215 cmdputs(psh
, n
->narg
.text
);
1218 p
= ">"; i
= 1; goto redir
;
1220 p
= ">|"; i
= 1; goto redir
;
1222 p
= ">>"; i
= 1; goto redir
;
1224 p
= ">&"; i
= 1; goto redir
;
1226 p
= "<"; i
= 0; goto redir
;
1228 p
= "<&"; i
= 0; goto redir
;
1230 p
= "<>"; i
= 0; goto redir
;
1232 if (n
->nfile
.fd
!= i
) {
1233 s
[0] = n
->nfile
.fd
+ '0';
1238 if (n
->type
== NTOFD
|| n
->type
== NFROMFD
) {
1239 s
[0] = n
->ndup
.dupfd
+ '0';
1243 cmdtxt(psh
, n
->nfile
.fname
);
1248 cmdputs(psh
, "<<...");
1251 cmdputs(psh
, "???");
1257 cmdlist(shinstance
*psh
, union node
*np
, int sep
)
1259 for (; np
; np
= np
->narg
.next
) {
1263 if (sep
&& np
->narg
.next
)
1270 cmdputs(shinstance
*psh
, const char *s
)
1272 const char *p
, *str
= 0;
1273 char c
, cc
[2] = " ";
1278 static char vstype
[16][4] = { "", "}", "-", "+", "?", "=",
1279 "#", "##", "%", "%%" };
1282 nextc
= psh
->cmdnextc
;
1283 nleft
= psh
->cmdnleft
;
1284 while (nleft
> 0 && (c
= *p
++) != 0) {
1291 if ((subtype
& VSTYPE
) == VSLENGTH
)
1295 if (!(subtype
& VSQUOTE
) != !(quoted
& 1)) {
1314 case CTLBACKQ
+CTLQUOTE
:
1333 str
= vstype
[subtype
& VSTYPE
];
1334 if (subtype
& VSNUL
)
1345 /* These can only happen inside quotes */
1355 } while (--nleft
> 0 && str
&& (c
= *str
++));
1358 if ((quoted
& 1) && nleft
) {
1362 psh
->cmdnleft
= nleft
;
1363 psh
->cmdnextc
= nextc
;