* exec.c - command execution
* This file is part of zsh, the Z shell.
* This software is Copyright 1992 by Paul Falstad
* Permission is hereby granted to copy, reproduce, redistribute or otherwise
* use this software as long as: there is no monetary profit gained
* specifically from the use or reproduction of this software, it is not
* sold, rented, traded or otherwise marketed, and this copyright notice is
* included prominently in any copy made.
* The author make no claims as to the fitness or correctness of this software
* for any use whatsoever, and it is provided as is. Any use of this software
* is at the user's own risk.
#define execerr() { if (forked) exit(1); \
closemnodes(mfds); errflag = 1; return; }
/* parse list in a string */
List
parselstring(s
) /**/
if (!(l
= parse_list())) {
if (l
= parselstring(s
)) {
/* fork and set limits */
if (thisjob
>= MAXJOB
-1) {
zerr("job table full",NULL
,0);
zerr("fork failed: %e",NULL
,errno
);
for (t0
= 0; t0
!= RLIM_NLIMITS
; t0
++)
/* execute a current shell command */
/* execve after handling $_ and #! */
#define POUNDBANGLIMIT 64
int zexecve(pth
,argv
) /**/
static char buf
[MAXPATHLEN
*2];
for (eep
= environ
; *eep
; eep
++)
if (**eep
== '_' && (*eep
)[1] == '=') break;
if (*pth
== '/') strcpy(buf
+2,pth
);
else sprintf(buf
+2,"%s/%s",pwd
,pth
);
if (!*eep
) eep
[1] = NULL
;
execve(pth
,argv
,environ
);
if ((eno
= errno
) == ENOEXEC
) {
char buf
[POUNDBANGLIMIT
+1],*ptr
,*ptr2
,*argv0
;
if ((fd
= open(pth
,O_RDONLY
)) >= 0) {
ct
= read(fd
,buf
,POUNDBANGLIMIT
);
for (t0
= 0; t0
!= ct
; t0
++)
buf
[POUNDBANGLIMIT
] = '\0';
for (ptr
= buf
+2; *ptr
&& *ptr
== ' '; ptr
++);
for (ptr2
= ptr
; *ptr
&& *ptr
!= ' '; ptr
++);
execve(ptr2
,argv
-2,environ
);
execve(ptr2
,argv
-1,environ
);
execve("/bin/sh",argv
-1,environ
);
for (t0
= 0; t0
!= ct
; t0
++)
execve("/bin/sh",argv
-1,environ
);
#define MAXCMDLEN (MAXPATHLEN*4)
/* execute an external command */
char *z
,*s
,buf
[MAXCMDLEN
],buf2
[MAXCMDLEN
];
zerr("no command",NULL
,0);
cn
= (Cmdnam
) gethnode(peekfirst(args
),cmdnamtab
);
if (cn
&& cn
->type
== DISABLED
)
if (z
= zgetenv("ARGV0")) {
setdata(firstnode(args
),ztrdup(z
));
sprintf(buf2
,"-%s",arg0
);
setdata(firstnode(args
),ztrdup(buf2
));
if (strlen(arg0
) > MAXPATHLEN
) {
zerr("command too long: %s",arg0
,0);
errno
= zexecve(arg0
,argv
);
if (arg0
== s
|| unset(PATHDIRS
)) {
zerr("%e: %s",arg0
,errno
);
if (cn
&& ISEXCMD(cn
->type
)) {
for (pp
= path
; pp
< cn
->pcomp
; pp
++)
if (**pp
== '.' && (*pp
)[1] == '\0') {
if (ee
!= ENOENT
) eno
= ee
;
} else if (**pp
!= '/') {
if (ee
!= ENOENT
) eno
= ee
;
ee
= zexecve(cn
->u
.nam
,argv
);
if (ee
!= ENOENT
) eno
= ee
;
for (pp
= path
; *pp
; pp
++)
if ((*pp
)[0] == '.' && !(*pp
)[1]) {
if (ee
!= ENOENT
) eno
= ee
;
if (ee
!= ENOENT
) eno
= ee
;
if (eno
) zerr("%e: %s",arg0
,eno
);
else zerr("command not found: %s",arg0
,0);
#define try(X) { if (iscom(X)) return ztrdup(X); }
/* get the full pathname of an external command */
char *z
,*s
,buf
[MAXCMDLEN
];
cn
= (Cmdnam
) gethnode(arg0
,cmdnamtab
);
if (!cn
&& isset(HASHCMDS
)) hashcmd(arg0
,path
);
if (cn
&& cn
->type
== DISABLED
) cn
= NULL
;
if (strlen(arg0
) > MAXPATHLEN
) return NULL
;
if (arg0
== s
|| unset(PATHDIRS
)) {
if (cn
&& ISEXCMD(cn
->type
)) {
for (pp
= path
; pp
< cn
->pcomp
; pp
++)
for (pp
= path
; *pp
; pp
++) {
return (access(s
,X_OK
) == 0 && stat(s
,&statbuf
) >= 0 &&
S_ISREG(statbuf
.st_mode
));
if (*s
== '.' && s
[-1] == '/' &&
(s
[1] == '/' || s
[1] == '\0' ||
(s
[1] == '.' && (s
[2] == '/' || s
[2] == '\0')))) return 1;
int hashcmd(arg0
,pp
) /**/
if (!*pp
|| isrelative(*pp
)) return 0;
cn
= (Cmdnam
) zcalloc(sizeof *cn
);
addhnode(ztrdup(arg0
),cn
,cmdnamtab
,freecmdnam
);
if (unset(HASHDIRS
)) return 1;
for (pq
= pathchecked
; pq
<= pp
; pq
++) {
if (isrelative(*pq
) || !(dir
= opendir(*pq
))) continue;
readdir(dir
); readdir(dir
);
while (de
= readdir(dir
)) addhcmdnode(de
->d_name
,pq
);
for (pq
= pathchecked
; *pq
; pq
++) {
if (isrelative(*pq
) || !(dir
= opendir(*pq
))) continue;
readdir(dir
); readdir(dir
);
while (de
= readdir(dir
)) addhcmdnode(de
->d_name
,pq
);
execlist2(list
->left
,list
->type
,!list
->right
);
if (sigtrapped
[SIGDEBUG
])
if (sigtrapped
[SIGERR
] && lastval
)
if (list
->right
&& !retflag
)
void execlist2(list
,type
,last1
) /**/
Sublist list
;int type
;int last1
;
execpline(list
,type
,last1
);
if (!execpline(list
,SYNC
,0)) execlist2(list
->right
,type
,last1
);
else while (list
= list
->right
)
if (list
->type
== ANDNEXT
) {
execlist2(list
->right
,type
,last1
);
if (execpline(list
,SYNC
,0)) execlist2(list
->right
,type
,last1
);
else while (list
= list
->right
)
if (list
->type
== ORNEXT
) {
execlist2(list
->right
,type
,last1
);
int execpline(l
,how
,last1
) /**/
Sublist l
;int how
;int last1
;
ipipe
[0] = ipipe
[1] = opipe
[0] = opipe
[1] = 0;
if ((thisjob
= getfreejob()) == -1)
jobtab
[thisjob
].stat
|= STAT_TIMED
;
if (l
->flags
& PFLAG_COPROC
) {
execpline2(l
->left
,how
,opipe
[0],ipipe
[1],last1
);
if (l
->flags
& PFLAG_COPROC
) close(ipipe
[1]);
if (l
->flags
& PFLAG_NOT
) lastval
= !lastval
;
void execpline2(pline
,how
,input
,output
,last1
) /**/
Pline pline
;int how
;int input
;int output
;int last1
;
if (pline
->type
== END
) {
execcmd(pline
->left
,input
,output
,how
==ASYNC
,last1
);
if (pline
->left
->type
>= CURSH
&& how
== SYNC
) {
/* if we are doing "foo | bar" where foo is a current
shell command, do foo in a subshell and do
the rest of the pipeline in the current shell. */
execcmd(pline
->left
,input
,pipes
[1],how
==ASYNC
,0);
zerr("fork failed: %e",NULL
,errno
);
char *text
= getjobtext((vptr
) pline
->left
);
/* otherwise just do the pipeline normally. */
execcmd(pline
->left
,input
,pipes
[1],how
==ASYNC
,0);
execpline2(pline
->right
,how
,pipes
[0],output
,last1
);
/* make the argv array */
char **makecline(list
) /**/
fprintf(stderr
,"%s",(prompt4
) ? prompt4
: "");
for (node
= firstnode(list
); node
; incnode(node
),ct
++);
ptr
= argv
= 2+(char **) ncalloc((ct
+4)*sizeof(char *));
for (node
= firstnode(list
); node
; incnode(node
))
if (*(char *) getdata(node
)) {
untokenize(getdata(node
));
fputs(getdata(node
),stderr
);
for (node
= firstnode(list
); node
; incnode(node
),ct
++);
ptr
= argv
= 2+(char **) ncalloc((ct
+4)*sizeof(char *));
for (node
= firstnode(list
); node
; incnode(node
))
if (*(char *) getdata(node
)) {
untokenize(getdata(node
));
/* untokenize the command line and remove null arguments */
for (node
= firstnode(l
); node
; node
= next
) {
if (!*(char *) getdata(node
)) uremnode(l
,node
);
else untokenize(getdata(node
));
if (*s
== Nularg
) chuck(s
--);
else *s
= ztokens
[*s
-Pound
];
/* nonzero if we shouldn't clobber a file */
if (unset(NOCLOBBER
) || f
->type
& 1) return 0;
if (stat(f
->name
,&buf
) == -1) return 1;
return S_ISREG(buf
.st_mode
);
/* close an multio (success) */
void closemn(mfds
,fd
) /**/
struct multio
**mfds
;int fd
;
if (mfds
[fd
]->rflag
== 0)
/* close all the mnodes (failure) */
void closemnodes(mfds
) /**/
for (t0
= 0; t0
!= 10; t0
++)
for (t1
= 0; t1
!= mfds
[t0
]->ct
; t1
++)
close(mfds
[t0
]->fds
[t1
]);
/* add a fd to an multio */
/* an multio is a list of fds associated with a certain fd.
thus if you do "foo >bar >ble", the multio for fd 1 will have
two fds, the result of open("bar",...), and the result of
void addfd(forked
,save
,mfds
,fd1
,fd2
,rflag
) /**/
int forked
;int *save
;struct multio
**mfds
;int fd1
;int fd2
;int rflag
;
if (!mfds
[fd1
]) { /* starting a new multio */
mfds
[fd1
] = (struct multio
*) alloc(sizeof(struct multio
));
if (!forked
&& fd1
!= fd2
&& fd1
< 10)
mfds
[fd1
]->rflag
= rflag
;
if (mfds
[fd1
]->rflag
!= rflag
) {
zerr("file mode mismatch on fd %d",NULL
,fd1
);
if (mfds
[fd1
]->ct
== 1) { /* split the stream */
mfds
[fd1
]->fds
[0] = movefd(fd1
);
mfds
[fd1
]->fds
[1] = movefd(fd2
);
mfds
[fd1
]->pipe
= pipes
[1-rflag
];
} else /* add another fd to an already split stream */
mfds
[fd1
]->fds
[mfds
[fd1
]->ct
++] = movefd(fd2
);
void addvars(l
,export
) /**/
v
= (struct varasg
*) ugetnode(l
);
if (v
->type
== PMFLAG_s
) {
if (v
->type
== PMFLAG_s
&& (!full(vl
) || !nextnode(firstnode(vl
)))) {
pm
= setsparam(v
->name
,val
= ztrdup(""));
untokenize(peekfirst(vl
));
pm
= setsparam(v
->name
,val
= ztrdup(ugetnode(vl
)));
if (export
&& !(pm
->flags
& PMFLAG_x
))
ptr
= arr
= (char **) zalloc(sizeof(char **)*(countnodes(vl
)+1));
void execcmd(cmd
,input
,output
,bkg
,last1
) /**/
Cmd cmd
;int input
;int output
;int bkg
;int last1
;
int fil
,forked
= 0,iscursh
= 0,nullexec
= 0;
for (t0
= 0; t0
!= 10; t0
++) {
if ((type
= cmd
->type
) == SIMPLE
&& !full(args
))
if (cmd
->flags
& CFLAG_EXEC
) {
zerr("redirection with no command",NULL
,0);
} else if (*readnullcmd
&&
((Redir
)peekfirst(cmd
->redir
))->type
== READ
&&
!nextnode(firstnode(cmd
->redir
))) {
addnode(args
,strdup(readnullcmd
));
addnode(args
,strdup(nullcmd
));
if (full(args
) && *(char *) peekfirst(args
) == '%') {
insnode(args
,(Lknode
) args
,strdup((bkg
) ? "bg" : "fg"));
if (isset(AUTORESUME
) && !bkg
&& !full(cmd
->redir
) && full(args
) &&
!input
&& type
== SIMPLE
&& !nextnode(firstnode(args
))) {
if (unset(NOTIFY
)) scanjobs();
if (findjobnam(peekfirst(args
)) != -1)
pushnode(args
,strdup("fg"));
if (unset(RMSTARSILENT
) && interact
&& isset(SHINSTDIN
) &&
type
== SIMPLE
&& full(args
) && nextnode(firstnode(args
)) &&
!strcmp(peekfirst(args
),"rm")) {
char *s
= getdata(nextnode(firstnode(args
)));
if (s
[0] == Star
&& !s
[1])
else if (l
> 2 && s
[l
-2] == '/' && s
[l
-1] == Star
) {
if (jobbing
) { /* get the text associated with this command */
s
= text
= getjobtext((vptr
) cmd
);
prefork(args
); /* do prefork substitutions */
if (full(args
) && ((char*)peekfirst(args
))[0] == Inbrack
&&
((char*)peekfirst(args
))[1] == '\0')
((char*)peekfirst(args
))[0] = '[';
if (type
== SIMPLE
&& full(args
) && !(cmd
->flags
& CFLAG_COMMAND
)) {
cn
= (Cmdnam
) gethnode(t
= s
= peekfirst(args
),cmdnamtab
);
if (!cn
&& isset(HASHCMDS
) && strcmp(t
,"..")) {
while (*t
&& *t
!= '/') t
++;
if (!*t
) hashcmd(s
,pathchecked
);
if (type
== SIMPLE
&& !cn
&& isset(AUTOCD
) && isset(SHINSTDIN
) &&
full(args
) && !full(cmd
->redir
) &&
!nextnode(firstnode(args
)) && cancd(peekfirst(args
))) {
pushnode(args
,strdup("cd"));
cn
= (Cmdnam
) gethnode("cd",cmdnamtab
);
/* this is nonzero if cmd is a current shell procedure */
iscursh
= (type
>= CURSH
) || (type
== SIMPLE
&& cn
&&
(cn
->type
== BUILTIN
|| cn
->type
== SHFUNC
));
/* if this command is backgrounded or (this is an external
command and we are not exec'ing it) or this is a builtin
with output piped somewhere, then fork. If this is the
last stage in a subshell pipeline, don't fork, but make
the rest of the function think we forked. */
if (bkg
|| !(iscursh
|| (cmd
->flags
& CFLAG_EXEC
)) ||
(cn
&& (cn
->type
== BUILTIN
|| cn
->type
== SHFUNC
) && output
)) {
pid
= (last1
&& execok()) ? 0 : phork();
( void ) addproc(pid
,text
);
if (bkg
&& isset(BGNICE
))
/* perform postfork substitutions */
postfork(args
,!(cmd
->flags
& CFLAG_NOGLOB
));
while (full(args
) && (s
= peekfirst(args
)) && !*s
) ugetnode(args
);
if (input
) /* add pipeline input/output to mnodes */
addfd(forked
,save
,mfds
,0,input
,0);
addfd(forked
,save
,mfds
,1,output
,1);
spawnpipes(cmd
->redir
); /* do process substitutions */
if ((fn
= (struct redir
*) ugetnode(cmd
->redir
))->type
== INPIPE
) {
addfd(forked
,save
,mfds
,fn
->fd1
,fn
->fd2
,0);
} else if (fn
->type
== OUTPIPE
) {
addfd(forked
,save
,mfds
,fn
->fd1
,fn
->fd2
,1);
if (!(fn
->type
== HERESTR
|| fn
->type
== CLOSE
|| fn
->type
==
MERGE
|| fn
->type
== MERGEOUT
))
if (xpandredir(fn
,cmd
->redir
))
if (fn
->type
== HERESTR
) {
addfd(forked
,save
,mfds
,fn
->fd1
,fil
,0);
} else if (fn
->type
== READ
) {
fil
= open(fn
->name
,O_RDONLY
);
zerr("%e: %s",fn
->name
,errno
);
addfd(forked
,save
,mfds
,fn
->fd1
,fil
,0);
} else if (fn
->type
== CLOSE
) {
if (!forked
&& fn
->fd1
< 10)
save
[fn
->fd1
] = movefd(fn
->fd1
);
} else if (fn
->type
== MERGE
|| fn
->type
== MERGEOUT
) {
if (fn
->fd2
== FD_COPROC
)
fn
->fd2
= (fn
->type
== MERGEOUT
) ? coprocout
: coprocin
;
if (!forked
&& fn
->fd1
< 10)
save
[fn
->fd1
] = movefd(fn
->fd1
);
addfd(forked
,save
,mfds
,fn
->fd1
,fil
,fn
->type
== MERGEOUT
);
(isset(NOCLOBBER
) && !(fn
->type
& 1)) ?
O_WRONLY
|O_APPEND
: O_WRONLY
|O_APPEND
|O_CREAT
,0666);
fil
= open(fn
->name
,dontclob(fn
) ?
O_WRONLY
|O_CREAT
|O_EXCL
: O_WRONLY
|O_CREAT
|O_TRUNC
,0666);
zerr("%e: %s",fn
->name
,errno
);
addfd(forked
,save
,mfds
,fn
->fd1
,fil
,1);
/* we are done with redirection. close the mnodes, spawning
tee/cat processes as necessary. */
for (t0
= 0; t0
!= 10; t0
++)
static int (*func
[]) DCLPROTO((Cmd
)) = {
execcursh
,exectime
,execfuncdef
,execfor
,execwhile
,
execrepeat
,execif
,execcase
,execselect
,execcond
};
lastval
= (func
[type
-CURSH
])(cmd
);
else if (iscursh
) /* builtin or shell function */
if (cn
&& cn
->type
== SHFUNC
)
lastval
= execbin(args
,cn
);
if (isset(PRINTEXITVALUE
) && isset(SHINSTDIN
) &&
fprintf(stderr
,"zsh: exit %d\n",lastval
);
zerr("write error: %e",NULL
,errno
);
execute(cmd
->flags
& CFLAG_DASH
);
/* restore fds after redirecting a builtin */
for (t0
= 0; t0
!= 10; t0
++)
void entersubsh(bkg
) /**/
if (open("/dev/null",O_RDWR
))
zerr("can't open /dev/null: %e",NULL
,errno
);
else if (!jobtab
[thisjob
].gleader
)
jobtab
[thisjob
].gleader
= getpid();
setpgrp(0L,jobtab
[thisjob
].gleader
);
attachtty(jobtab
[thisjob
].gleader
);
setpgrp(0L,jobtab
[thisjob
].gleader
);
if (!sigtrapped
[SIGQUIT
])
opts
[MONITOR
] = OPT_UNSET
;
/* close all internal shell fds */
for (t0
= 10; t0
!= NOFILE
; t0
++)
/* convert here document into a here string */
char *gethere(str
,typ
) /**/
int qt
= 0,siz
= 0,l
,strip
= 0;
for (u
= bptr
, v
= str
; *u
!= '\n' && *v
; u
++,v
++)
if (!(*u
== '\n' && !*v
))
if (!qt
&& l
> 1 && bptr
[l
-1] == '\n' && bptr
[l
-2] == '\\')
if (siz
&& t
[siz
-1] == '\n')
(s
[1] == '$' || s
[1] == '`')) chuck(s
);
/* open here string fd */
if ((fd
= open(s
,O_CREAT
|O_WRONLY
,0600)) == -1)
while (t
= ugetnode(fake
))
for (t0
= 0; t0
!= mn
->ct
; t0
++)
for (t0
= 0; t0
!= mn
->ct
; t0
++)
while (len
= read(mn
->fds
[t0
],buf
,4096))
for (t0
= 0; t0
!= mn
->ct
; t0
++)
while ((len
= read(mn
->pipe
,buf
,4096)) > 0)
for (t0
= 0; t0
!= mn
->ct
; t0
++)
write(mn
->fds
[t0
],buf
,len
);
void closeallelse(mn
) /**/
for (t0
= 0; t0
!= NOFILE
; t0
++)
for (t1
= 0; t1
!= mn
->ct
; t1
++)
long int zstrtol(s
,t
,base
) /**/
char *s
;char **t
;int base
;
for (; *s
>= '0' && *s
< ('0'+base
); s
++)
for (; idigit(*s
) || (*s
>= 'a' && *s
< ('a'+base
-10))
|| (*s
>= 'A' && *s
< ('A'+base
-10)); s
++)
ret
= ret
*base
+(idigit(*s
) ? (*s
-'0') : (*s
& 0x1f)+9);
Lklist
getoutput(cmd
,qt
) /**/
for (cmd
++; *cmd
== ' '; cmd
++);
for (s
= cmd
; *s
&& *s
!= ' '; s
++)
else if (*s
== '$') *s
= String
;
stream
= open(fi
,O_RDONLY
);
return readoutput(stream
,qt
);
if (!(list
= parselstring(cmd
)))
return readoutput(pipes
[0],qt
);
/* read output of command substitution */
Lklist
readoutput(in
,qt
) /**/
ptr
= buf
= ncalloc(bsiz
= 64);
while ((c
= fgetc(fin
)) != EOF
)
ptr
= buf
= ncalloc(bsiz
= 64);
char *pp
= ncalloc(bsiz
*= 2);
if (ptr
!= buf
&& ptr
[-1] == '\n')
if (cnt
) addnode(ret
,buf
);
char *getoutputfile(cmd
) /**/
char *nam
= gettemp(),*str
;
for (str
= cmd
; *str
&& *str
!= Outpar
; str
++);
if (!(list
= parselstring(cmd
)))
if (!jobtab
[thisjob
].filelist
)
jobtab
[thisjob
].filelist
= newlist();
addnode(jobtab
[thisjob
].filelist
,ztrdup(nam
));
waitpid(pid
,NULL
,WUNTRACED
);
/* get a temporary named pipe */
if (mknod(tnam
,0010666,0) < 0) return NULL
;
char *getoutproc(cmd
) /**/
zerr("doesn't look like your system supports FIFOs.",NULL
,0);
for (str
= cmd
; *str
&& *str
!= Outpar
; str
++);
if (!jobtab
[thisjob
].filelist
)
jobtab
[thisjob
].filelist
= newlist();
addnode(jobtab
[thisjob
].filelist
,ztrdup(pnam
));
if (!(list
= parselstring(cmd
)))
fd
= open(pnam
,O_WRONLY
);
zerr("can't open %s: %e",pnam
,errno
);
fd
= open("/dev/null",O_RDONLY
);
char *getinproc(cmd
) /**/
zerr("doesn't look like your system supports FIFOs.",NULL
,0);
for (str
= cmd
; *str
&& *str
!= Outpar
; str
++);
if (!jobtab
[thisjob
].filelist
)
jobtab
[thisjob
].filelist
= newlist();
addnode(jobtab
[thisjob
].filelist
,ztrdup(pnam
));
if (!(list
= parselstring(cmd
)))
fd
= open(pnam
,O_RDONLY
);
/* > >(...) (does not use named pipes) */
for (str
= cmd
; *str
&& *str
!= Outpar
; str
++);
if (!(list
= parselstring(cmd
+2)))
for (str
= cmd
; *str
&& *str
!= Outpar
; str
++);
if (!(list
= parselstring(cmd
+2)))
/* run a list, saving the current job num */
return mktemp(dyncat(tmpprefix
,"XXXXXX"));
/* my getwd; all the other ones I tried confused the SIGCHLD handler */
static char buf0
[MAXPATHLEN
];
char buf3
[MAXPATHLEN
],*buf2
= buf0
+1;
if (stat("..",&sbuf
) < 0)
if (sbuf
.st_ino
== ino
&& sbuf
.st_dev
== dev
)
readdir(dir
); readdir(dir
);
while (de
= readdir(dir
))
readdir(dir
); readdir(dir
);
while (de
= readdir(dir
))
/* open pipes with fds >= 10 */
/* do process substitution with redirection */
f
->fd2
= getoutpipe(str
);
/* perform time ... command */
if (!cmd
->u
.pline
) { shelltime(); return 0; }
execpline(cmd
->u
.pline
,TIMED
,0);
int execfuncdef(cmd
) /**/
while (s
= ugetnode(cmd
->args
))
cc
= (Cmdnam
) zalloc(sizeof *cc
);
cc
->u
.list
= (List
) dupstruct(cmd
->u
.list
);
addhnode(ztrdup(s
),cc
,cmdnamtab
,freecmdnam
);
if (!strncmp(s
,"TRAP",4))
/* evaluate a [[ ... ]] */
return !evalcond(cmd
->u
.cond
);
void execshfunc(cmd
,cn
) /**/
if (!(cn
->flags
& PMFLAG_u
)) return;
if (!(l
= getfpfunc(nam
= peekfirst(cmd
->args
)))) {
zerr("function not found: %s",nam
,0);
cn
->u
.list
= (List
) dupstruct(l
);
doshfunc(l
,cmd
->args
,cn
->flags
);
void doshfuncnoval(list
,args
,flags
) /**/
List list
; Lklist args
; int flags
;
doshfunc(list
,args
,flags
);
void doshfunc(list
,args
,flags
) /**/
List list
; Lklist args
; int flags
;
int oxtr
= opts
[XTRACE
],opev
= opts
[PRINTEXITVALUE
],xexittr
;
xexittr
= sigtrapped
[SIGEXIT
];
xexitfn
= sigfuncs
[SIGEXIT
];
if (flags
& PMFLAG_t
) opts
[XTRACE
] = OPT_SET
;
opts
[PRINTEXITVALUE
] = OPT_UNSET
;
pparams
= x
= (char **) zcalloc(((sizeof *x
)*(1+countnodes(args
))));
argzero
= ztrdup(ugetnode(args
));
while (*x
= ugetnode(args
))
pparams
= zcalloc(sizeof *pparams
);
argzero
= ztrdup(argzero
);
runlist(dupstruct(list
));
while (s
= getnode(locallist
)) unsetparam(s
);
if (sigfuncs
[SIGEXIT
] && sigfuncs
[SIGEXIT
] != xexitfn
) {
freestruct(sigfuncs
[SIGEXIT
]);
sigtrapped
[SIGEXIT
] = xexittr
;
sigfuncs
[SIGEXIT
] = xexitfn
;
opts
[PRINTEXITVALUE
] = opev
;
/* search fpath for an undefined function */
char **pp
= fpath
,buf
[MAXPATHLEN
];
sprintf(buf
,"%s/%s",*pp
,s
);
if (!access(buf
,R_OK
) && (fd
= open(buf
,O_RDONLY
)) != -1)
if (read(fd
,d
,len
) != len
)
/* check to see if AUTOCD applies here */
if ((t
= getsparam(s
)) && *t
== '/') return 1;
char sbuf
[MAXPATHLEN
],**cp
;
for (cp
= cdpath
; *cp
; cp
++)
sprintf(sbuf
,"%s/%s",*cp
,s
);
return !(access(s
,X_OK
) || stat(s
,&buf
) || !S_ISDIR(buf
.st_mode
));