* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley Software License Agreement
* specifies the terms and conditions for redistribution.
static char *sccsid
= "@(#)exec.c 5.2 (Berkeley) %G%";
* 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 bits (HSHSIZ / 8 chars), which are used
* to hash execs. If it is allocated (havhash true), then to tell
* whether ``name'' is (possibly) present in the i'th component
* of the variable path, you look at the bit in xhash indexed by
* hash(hashname("name"), i). This is setup automatically
* after .login is executed, and recomputed whenever ``path'' is
* The two part hash function is designed to let texec() call the
* more expensive hashname() only once and the simple hash() several
* times (once for each path component checked).
* Byte size is assumed to be 8.
#define HSHSIZ 8192 /* 1k bytes */
#define HSHMASK (HSHSIZ - 1)
#define hash(a, b) ((a) * HSHMUL + (b) & HSHMASK)
#define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */
#define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */
/* 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]);
int hashval
, hashval1
, i
;
* 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 */
* Since all internal file descriptors are set to close on exec,
* we don't need to close them explicitly here. Just reorient
* ourselves for error messages.
SHIN
= 0; SHOUT
= 1; SHDIAG
= 2; OLDSTD
= 0;
* We must do this AFTER any possible forking (like `foo`
* in glob) so that this shell can still do subprocesses.
* 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 */
if (!slash
&& pv
[0][0] == '/' && havhash
) {
hashval1
= hash(hashval
, i
);
if (!bit(xhash
, hashval1
))
if (pv
[0][0] == 0 || eq(pv
[0], ".")) /* don't make ./xxx */
/* Couldn't find the damn thing */
bferr("Command not found");
* 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
;
(void) signal(SIGINT
, parintr
);
(void) signal(SIGQUIT
, parintr
);
(void) signal(SIGTERM
, parterm
); /* if doexec loses, screw */
register struct direct
*dp
;
struct varent
*v
= adrof("path");
for (cnt
= 0; cnt
< sizeof xhash
; cnt
++)
for (pv
= v
->vec
; *pv
; pv
++, i
++) {
if (fstat(dirp
->dd_fd
, &stb
) < 0 || !isdir(stb
)) {
while ((dp
= readdir(dirp
)) != NULL
) {
if (dp
->d_name
[0] == '.' &&
(dp
->d_name
[1] == '\0' ||
dp
->d_name
[1] == '.' && dp
->d_name
[2] == '\0'))
hashval
= hash(hashname(dp
->d_name
), i
);
printf("%d hits, %d misses, %d%%\n",
hits
, misses
, 100 * hits
/ (hits
+ misses
));