static char *sccsid
= "@(#)sh.exec.c 4.1 10/9/80";
* System level search and execute of a command.
* We look in each directory for the specified command name.
* If the name contains a '/' then we execute only the full path name.
* If there is no search path then we execute only full path names.
* As we search for the command we note the first non-trivial error
* message for presentation to the user. This allows us often
* to show that a file has the wrong mode/no access when the file
* is not in the last component of the search path, so we must
* go on after first detecting the error.
char *exerr
; /* Execution error message */
char *expath
; /* Path for exerr */
* Xhash is an array of HSHSIZ chars, which are used to hash execs.
* If it is allocated, then to tell whether ``name'' is (possibly)
* present in the i'th component of the variable path, you look at
* the i'th bit of xhash[hash("name")]. This is setup automatically
* after .login is executed, and recomputed whenever ``path'' is
/* Dummy search path for just absolute search when no path */
char *justabs
[] = { "", 0 };
register struct command
*t
;
register char *dp
, **pv
, **av
;
register struct varent
*v
;
bool slash
= any('/', t
->t_dcom
[0]);
* Glob the command name. If this does anything, then we
* will execute the command only relative to ".". One special
* case: if there is no PATH, then we execute only commands
dp
= globone(t
->t_dcom
[0]);
exerr
= 0; expath
= t
->t_dcom
[0] = dp
;
if (v
== 0 && expath
[0] != '/')
* Glob the argument list, if necessary.
* Otherwise trim off the quote bits.
gflag
= 0; av
= &t
->t_dcom
[1];
xechoit(av
); /* Echo command if -x */
closech(); /* Close random fd's */
* We must do this after any possible forking (like `foo`
* in glob) so that this shell can still do subprocesses.
sigsys(SIGCHLD
, SIG_IGN
); /* sigsys for vforks sake */
* If no path, no words in path, or a / in the filename
* then restrict the command search.
if (v
== 0 || v
->vec
[0] == 0 || slash
)
sav
= strspl("/", *av
); /* / command name for postpending */
hashval
= xhash
[hash(*av
)];
if (!slash
&& pv
[0][0] == '/' && havhash
&& (hashval
& (1 << (i
% 8))) == 0)
if (pv
[0][0] == 0 || eq(pv
[0], ".")) /* don't make ./xxx */
/* Couldn't find the damn thing */
bferr("Command not found");
char *lastsh
[] = { SHELLPATH
, 0 };
* Execute command f, arg list t.
* Record error message if not found.
* Also do shell scripts here.
register struct varent
*v
;
extern char *sys_errlist
[];
* If there is an alias for shell, then
* put the words of the alias in front of the
* argument list replacing the command name.
* Note no interpretation of the words at this point.
v
= adrof1("shell", &aliases
);
register int ff
= open(f
, 0);
vp
[0] = adrof("shell") ? value("shell") : SHELLPATH
;
if (ff
!= -1 && read(ff
, &ch
, 1) == 1 && ch
!= '#')
t
= blkspl(vp
, t
); /* Splice up the new arglst */
/* The sky is falling, the sky is falling! */
exerr
= sys_errlist
[errno
];
register struct command
*kp
;
signal(SIGQUIT
, parintr
);
signal(SIGTERM
, parterm
); /* if doexec loses, screw */
struct direct dirbuf
[BUFSIZ
/ sizeof (struct direct
)];
struct varent
*v
= adrof("path");
for (cnt
= 0; cnt
< HSHSIZ
; cnt
++)
for (pv
= v
->vec
; *pv
; pv
++, i
= (i
+ 1) % 8) {
if (fstat(dirf
, &stb
) < 0 || !isdir(stb
)) {
while ((cnt
= read(dirf
, (char *) dirbuf
, sizeof dirbuf
)) >= sizeof dirbuf
[0]) {
register struct direct
*ep
= dirbuf
;
for (cnt
/= sizeof(struct direct
); cnt
> 0; cnt
--, ep
++) {
copdent(d_name
, ep
->d_name
);
xhash
[hash(d_name
)] |= (1 << i
);
printf("%d hits, %d misses, %2d%%\n", hits
, misses
, 100 * hits
/ (hits
+ misses
));