* Copyright (c) 1980, 1991 The Regents of the University of California.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)sem.c 5.11 (Berkeley) %G%";
static int nosigchld
= 0, osigmask
;
static int onosigchld
= 0, oosigmask
;
execute(t
, wanttty
, pipein
, pipeout
)
register struct command
*t
;
int wanttty
, *pipein
, *pipeout
;
if ((t
->t_dflg
& F_AMPERSAND
) && wanttty
> 0)
if ((t
->t_dcom
[0][0] & (QUOTE
|TRIM
)) == QUOTE
)
(void) strcpy(t
->t_dcom
[0], t
->t_dcom
[0] + 1);
if ((t
->t_dflg
& F_REPEAT
) == 0)
if (t
->t_dflg
& F_PIPEOUT
)
* Must do << early so parent will know
* where input pointer should be.
* If noexec then this is all we do.
if (t
->t_dflg
& F_READ
) {
* This mess is the necessary kludge to handle the prefix
* builtins: nice, nohup, time. These commands can also
* be used by themselves, and this is not handled here.
* This will also work when loops are parsed.
while (t
->t_dtyp
== NODE_COMMAND
)
if (eq(t
->t_dcom
[0], "nice"))
if (index("+-", t
->t_dcom
[1][0]))
t
->t_nice
= getn(t
->t_dcom
[1]);
else if (eq(t
->t_dcom
[0], "nohup"))
else if (eq(t
->t_dcom
[0], "time"))
* Check if we have a builtin function and remember which one.
NODE_COMMAND
? isbfunc(t
) : (struct biltins
*) 0;
* We fork only if we are timed, or are not the end of
* a parenthesized list and not a simple builtin function.
* Simple meaning one that is not pipedout, niced, nohupped,
* It would be nice(?) to not fork in some of these cases.
if (((t
->t_dflg
& F_TIME
) || (t
->t_dflg
& F_NOFORK
) == 0 &&
t
->t_dflg
& (F_PIPEOUT
|F_AMPERSAND
|F_NICE
|F_NOHUP
))))
if (t
->t_dtyp
== NODE_PAREN
||
t
->t_dflg
&(F_REPEAT
|F_AMPERSAND
) || bifunc
)
if (wanttty
>= 0 && !nosigchld
) {
osigmask
= sigblock(sigmask(SIGCHLD
));
if (pid
== 0 && nosigchld
) {
int ochild
, osetintr
, ohaderr
, odidfds
;
int oSHIN
, oSHOUT
, oSHDIAG
, oOLDSTD
, otpgrp
;
* Prepare for the vfork by saving everything
* that the child corrupts before it exec's.
* Note that in some signal implementations
* which keep the signal info in user space
* (e.g. Sun's) it will also be necessary to
* save and restore the current sigvec's for
* the signals the child touches before it
if (wanttty
>= 0 && !nosigchld
&& !noexec
) {
osigmask
= sigblock(sigmask(SIGCHLD
));
omask
= sigblock(sigmask(SIGCHLD
));
ochild
= child
; osetintr
= setintr
;
ohaderr
= haderr
; odidfds
= didfds
;
oSHIN
= SHIN
; oSHOUT
= SHOUT
;
oSHDIAG
= SHDIAG
; oOLDSTD
= OLDSTD
; otpgrp
= tpgrp
;
oosigmask
= osigmask
; onosigchld
= nosigchld
;
(void) sigsetmask(omask
);
error("No more processes");
child
= ochild
; setintr
= osetintr
;
haderr
= ohaderr
; didfds
= odidfds
;
SHOUT
= oSHOUT
; SHDIAG
= oSHDIAG
;
OLDSTD
= oOLDSTD
; tpgrp
= otpgrp
;
osigmask
= oosigmask
; nosigchld
= onosigchld
;
xfree((char *)Vav
); Vav
= 0;
/* this is from pfork() */
(void) sigsetmask(omask
);
/* this is from pfork() */
(t
->t_dflg
&F_NOINTERRUPT
)) ||
gointr
&& eq(gointr
, "-");
pgrp
= pcurrjob
? pcurrjob
->p_jobid
: getpid();
(void) signal(SIGCHLD
, SIG_DFL
);
(void) signal(SIGINT
, ignint
?
(void) signal(SIGQUIT
, ignint
?
(void) signal(SIGTSTP
, SIG_DFL
);
(void) signal(SIGTTIN
, SIG_DFL
);
(void) signal(SIGTTOU
, SIG_DFL
);
(void) signal(SIGTERM
, parterm
);
} else if (tpgrp
== -1 &&
(t
->t_dflg
&F_NOINTERRUPT
)) {
(void) signal(SIGINT
, SIG_IGN
);
(void) signal(SIGQUIT
, SIG_IGN
);
if (wanttty
>= 0 && tpgrp
>= 0)
(void) ioctl(FSHTTY
, TIOCSPGRP
,
(void) signal(SIGHUP
, SIG_IGN
);
(void) setpriority(PRIO_PROCESS
,
* It would be better if we could wait for the
* whole job when we knew the last process
* had been started. Pwait, in fact, does
* wait for the whole job anyway, but this test
* doesn't really express our intentions.
if (didfds
==0 && t
->t_dflg
&F_PIPEIN
) {
if ((t
->t_dflg
& F_PIPEOUT
) == 0) {
if ((t
->t_dflg
& F_AMPERSAND
) == 0)
doio(t
, pipein
, pipeout
);
if (t
->t_dflg
& F_PIPEOUT
) {
(void) close(pipeout
[0]);
(void) close(pipeout
[1]);
* Perform a builtin function.
* If we are not forked, arrange for possible stopping
if (t
->t_dtyp
!= NODE_PAREN
) {
* For () commands must put new 0,1,2 in FSH* and recurse
OLDSTD
= dcopy(0, FOLDSTD
);
SHOUT
= dcopy(1, FSHOUT
);
SHDIAG
= dcopy(2, FSHDIAG
);
t
->t_dspr
->t_dflg
|= t
->t_dflg
& F_NOINTERRUPT
;
execute(t
->t_dspr
, wanttty
);
t
->t_dcar
->t_dflg
|= F_PIPEOUT
|
(t
->t_dflg
& (F_PIPEIN
|F_AMPERSAND
|F_STDERR
|F_NOINTERRUPT
));
execute(t
->t_dcar
, wanttty
, pipein
, pv
);
t
->t_dcdr
->t_dflg
|= F_PIPEIN
|
(F_PIPEOUT
|F_AMPERSAND
|F_NOFORK
|F_NOINTERRUPT
));
wanttty
= 0; /* got tty already */
execute(t
->t_dcdr
, wanttty
, pv
, pipeout
);
t
->t_dcar
->t_dflg
|= t
->t_dflg
& F_NOINTERRUPT
;
execute(t
->t_dcar
, wanttty
);
* In strange case of A&B make a new job after A
if (t
->t_dcar
->t_dflg
&F_AMPERSAND
&& t
->t_dcdr
&&
(t
->t_dcdr
->t_dflg
&F_AMPERSAND
) == 0)
t
->t_dflg
& (F_NOFORK
|F_NOINTERRUPT
);
execute(t
->t_dcdr
, wanttty
);
t
->t_dcar
->t_dflg
|= t
->t_dflg
& F_NOINTERRUPT
;
execute(t
->t_dcar
, wanttty
);
if ((getn(value("status")) == 0) !=
t
->t_dflg
& (F_NOFORK
|F_NOINTERRUPT
);
execute(t
->t_dcdr
, wanttty
);
* Fall through for all breaks from switch.
* If there will be no more executions of this command, flush all
* file descriptors. Places that turn on the F_REPEAT bit are
* responsible for doing donefds after the last re-execution
if (didfds
&& !(t
->t_dflg
& F_REPEAT
))
gargv
= 0, xfree((char *)v
);
pargv
= 0, xfree((char *)v
);
* Perform io redirection.
* We may or maynot be forked here.
register struct command
*t
;
register int flags
= t
->t_dflg
;
if (didfds
|| (flags
& F_REPEAT
))
if ((flags
& F_READ
) == 0) { /* F_READ already done */
} else if (flags
& F_PIPEIN
) {
} else if ((flags
& F_NOINTERRUPT
) && tpgrp
== -1) {
(void) open(_PATH_DEVNULL
, 0);
if (!(flags
& F_APPEND
) || open(cp
, O_WRONLY
|O_APPEND
, 0) < 0) {
if (!(flags
& F_OVERWRITE
) && adrof("noclobber")) {
} else if (flags
& F_PIPEOUT
)
pv
[0] = dmove(pv
[0], -1);
pv
[1] = dmove(pv
[1], -1);
if (pv
[0] >= 0 && pv
[1] >= 0)
error("Can't make pipe");
if ((stb
.st_mode
& S_IFMT
) == S_IFCHR
)
error("%s: File exists", cp
);