* Copyright (c) 1980, 1991 The Regents of the University of California.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)sem.c 5.12 (Berkeley) %G%";
execute(t
, wanttty
, pipein
, pipeout
)
register struct command
*t
;
int wanttty
, *pipein
, *pipeout
;
static sigmask_t csigmask
;
static sigmask_t ocsigmask
;
static int onosigchld
= 0;
static int nosigchld
= 0;
if (t
->t_dflg
& F_AMPERSAND
)
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
) {
set(STRstatus
, Strsave(STR0
));
* 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
while (t
->t_dtyp
== NODE_COMMAND
)
if (eq(t
->t_dcom
[0], STRnice
))
if (strchr("+-", t
->t_dcom
[1][0]))
else if (eq(t
->t_dcom
[0], STRnohup
))
else if (eq(t
->t_dcom
[0], STRtime
))
if (t
->t_dtyp
== NODE_COMMAND
) {
* Check if we have a builtin function and remember which one.
else { /* not a command */
bifunc
= (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, or &'d. It would be nice(?) to not
* fork in some of these cases.
* Prevent forking cd, pushd, popd, chdir cause this will cause the
* shell not to change dir!
if (bifunc
&& (bifunc
->bfunct
== dochngd
||
bifunc
->bfunct
== dopushd
||
bifunc
->bfunct
== dopopd
))
if (((t
->t_dflg
& F_TIME
) || (t
->t_dflg
& F_NOFORK
) == 0 &&
(F_PIPEOUT
| F_AMPERSAND
| F_NICE
| F_NOHUP
))) ||
* We have to fork for eval too.
(bifunc
&& (t
->t_dflg
& F_PIPEIN
) != 0 &&
bifunc
->bfunct
== doeval
))
if (t
->t_dtyp
== NODE_PAREN
||
t
->t_dflg
& (F_REPEAT
| F_AMPERSAND
) || bifunc
)
* We need to block SIGCHLD here, so that if the process does
* not die before we can set the process group
if (wanttty
>= 0 && !nosigchld
) {
csigmask
= sigblock(sigmask(SIGCHLD
));
if (pid
== 0 && nosigchld
) {
(void) sigsetmask(csigmask
);
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
if (wanttty
>= 0 && !nosigchld
&& !noexec
) {
csigmask
= sigblock(sigmask(SIGCHLD
));
omask
= sigblock(sigmask(SIGCHLD
) | sigmask(SIGINT
));
(void) sigsetmask(omask
);
/* this is from pfork() */
(void) sigsetmask(omask
);
/* this is from pfork() */
(void) sigsetmask(csigmask
);
(t
->t_dflg
& F_NOINTERRUPT
))
|| gointr
&& eq(gointr
, STRminus
);
pgrp
= pcurrjob
? pcurrjob
->p_jobid
: getpid();
(void) signal(SIGINT
, SIG_IGN
);
(void) signal(SIGQUIT
, SIG_IGN
);
(void) signal(SIGINT
, vffree
);
(void) signal(SIGQUIT
, SIG_DFL
);
(void) signal(SIGTSTP
, SIG_DFL
);
(void) signal(SIGTTIN
, SIG_DFL
);
(void) signal(SIGTTOU
, SIG_DFL
);
(void) signal(SIGTERM
, parterm
);
(t
->t_dflg
& F_NOINTERRUPT
)) {
(void) signal(SIGINT
, SIG_IGN
);
(void) signal(SIGQUIT
, SIG_IGN
);
(void) signal(SIGHUP
, SIG_IGN
);
(void) setpriority(PRIO_PROCESS
, 0, t
->t_nice
);
* 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) {
(void) sigsetmask(csigmask
);
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
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
, NULL
, NULL
);
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
| (t
->t_dflg
&
(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
, NULL
, NULL
);
* 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_dcdr
->t_dflg
|= t
->t_dflg
&
(F_NOFORK
| F_NOINTERRUPT
);
execute(t
->t_dcdr
, wanttty
, NULL
, NULL
);
t
->t_dcar
->t_dflg
|= t
->t_dflg
& F_NOINTERRUPT
;
execute(t
->t_dcar
, wanttty
, NULL
, NULL
);
if ((getn(value(STRstatus
)) == 0) !=
t
->t_dcdr
->t_dflg
|= t
->t_dflg
&
(F_NOFORK
| F_NOINTERRUPT
);
execute(t
->t_dcdr
, wanttty
, NULL
, NULL
);
* 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
))
* 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 */
* so < /dev/std{in,out,err} work
cp
= globone(Dfix1(cp
), G_IGNORE
);
(void) strncpy(tmp
, short2str(cp
), MAXPATHLEN
);
tmp
[MAXPATHLEN
- 1] = '\0';
if ((fd
= open(tmp
, O_RDONLY
)) < 0)
stderror(ERR_SYSTEM
, tmp
, strerror(errno
));
else if (flags
& F_PIPEIN
) {
else if ((flags
& F_NOINTERRUPT
) && tpgrp
== -1) {
(void) open(_PATH_DEVNULL
, O_RDONLY
);
(void) ioctl(0, FIONCLEX
, (char *) 0);
cp
= globone(Dfix1(cp
), G_IGNORE
);
(void) Strncpy(tmp
, cp
, MAXPATHLEN
);
tmp
[MAXPATHLEN
- 1] = '\0';
* so > /dev/std{out,err} work
if ((flags
& F_APPEND
) &&
(fd
= open(short2str(tmp
), O_WRONLY
| O_APPEND
)) >= 0);
(fd
= open(short2str(tmp
), O_WRONLY
)) >= 0)
(void) lseek(1, (off_t
) 0, L_XTND
);
if (!(flags
& F_OVERWRITE
) && adrof(STRnoclobber
)) {
stderror(ERR_SYSTEM
, short2str(tmp
), strerror(errno
));
if ((fd
= creat(short2str(tmp
), 0666)) < 0)
stderror(ERR_SYSTEM
, short2str(tmp
), strerror(errno
));
else if (flags
& F_PIPEOUT
) {
(void) ioctl(1, FIONCLEX
, (char *) 0);
(void) ioctl(2, FIONCLEX
, (char *) 0);
pv
[0] = dmove(pv
[0], -1);
pv
[1] = dmove(pv
[1], -1);
if (pv
[0] >= 0 && pv
[1] >= 0)
if (stat(ptr
= short2str(cp
), &stb
) < 0)
if ((stb
.st_mode
& S_IFMT
) == S_IFCHR
)
stderror(ERR_EXISTS
, ptr
);