sh: Simplify cd-hash interaction.
Instead of rechecking relative paths for all hashed utilities after a cd, track if any utility in cmdtable depends on a relative path in PATH. If there is such a utility, cd clears the entire table. As a result, the '*' in hash no longer happens.
This commit is contained in:
parent
eb84fc957c
commit
523646ee5c
@ -86,12 +86,12 @@ struct tblentry {
|
||||
union param param; /* definition of builtin function */
|
||||
int special; /* flag for special builtin commands */
|
||||
signed char cmdtype; /* index identifying command */
|
||||
char rehash; /* if set, cd done since entry created */
|
||||
char cmdname[]; /* name of command */
|
||||
};
|
||||
|
||||
|
||||
static struct tblentry *cmdtable[CMDTABLESIZE];
|
||||
static int cmdtable_cd = 0; /* cmdtable contains cd-dependent entries */
|
||||
int exerrno = 0; /* Last exec error */
|
||||
|
||||
|
||||
@ -305,8 +305,6 @@ printentry(struct tblentry *cmdp, int verbose)
|
||||
error("internal error: cmdtype %d", cmdp->cmdtype);
|
||||
#endif
|
||||
}
|
||||
if (cmdp->rehash)
|
||||
out1c('*');
|
||||
out1c('\n');
|
||||
}
|
||||
|
||||
@ -323,12 +321,12 @@ find_command(const char *name, struct cmdentry *entry, int act,
|
||||
{
|
||||
struct tblentry *cmdp, loc_cmd;
|
||||
int idx;
|
||||
int prev;
|
||||
char *fullname;
|
||||
struct stat statb;
|
||||
int e;
|
||||
int i;
|
||||
int spec;
|
||||
int cd;
|
||||
|
||||
/* If name contains a slash, don't use the hash table */
|
||||
if (strchr(name, '/') != NULL) {
|
||||
@ -337,8 +335,10 @@ find_command(const char *name, struct cmdentry *entry, int act,
|
||||
return;
|
||||
}
|
||||
|
||||
cd = 0;
|
||||
|
||||
/* If name is in the table, and not invalidated by cd, we're done */
|
||||
if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
|
||||
if ((cmdp = cmdlookup(name, 0)) != NULL) {
|
||||
if (cmdp->cmdtype == CMDFUNCTION && act & DO_NOFUNC)
|
||||
cmdp = NULL;
|
||||
else
|
||||
@ -359,13 +359,6 @@ find_command(const char *name, struct cmdentry *entry, int act,
|
||||
}
|
||||
|
||||
/* We have to search path. */
|
||||
prev = -1; /* where to start */
|
||||
if (cmdp) { /* doing a rehash */
|
||||
if (cmdp->cmdtype == CMDBUILTIN)
|
||||
prev = -1;
|
||||
else
|
||||
prev = cmdp->param.index;
|
||||
}
|
||||
|
||||
e = ENOENT;
|
||||
idx = -1;
|
||||
@ -380,13 +373,8 @@ find_command(const char *name, struct cmdentry *entry, int act,
|
||||
goto loop; /* ignore unimplemented options */
|
||||
}
|
||||
}
|
||||
/* if rehash, don't redo absolute path names */
|
||||
if (fullname[0] == '/' && idx <= prev) {
|
||||
if (idx < prev)
|
||||
goto loop;
|
||||
TRACE(("searchexec \"%s\": no change\n", name));
|
||||
goto success;
|
||||
}
|
||||
if (fullname[0] != '/')
|
||||
cd = 1;
|
||||
if (stat(fullname, &statb) < 0) {
|
||||
if (errno != ENOENT && errno != ENOTDIR)
|
||||
e = errno;
|
||||
@ -426,9 +414,6 @@ find_command(const char *name, struct cmdentry *entry, int act,
|
||||
goto success;
|
||||
}
|
||||
|
||||
/* We failed. If there was an entry for this command, delete it */
|
||||
if (cmdp && cmdp->cmdtype != CMDFUNCTION)
|
||||
delete_cmd_entry();
|
||||
if (act & DO_ERR) {
|
||||
if (e == ENOENT || e == ENOTDIR)
|
||||
outfmt(out2, "%s: not found\n", name);
|
||||
@ -440,7 +425,8 @@ find_command(const char *name, struct cmdentry *entry, int act,
|
||||
return;
|
||||
|
||||
success:
|
||||
cmdp->rehash = 0;
|
||||
if (cd)
|
||||
cmdtable_cd = 1;
|
||||
entry->cmdtype = cmdp->cmdtype;
|
||||
entry->u = cmdp->param;
|
||||
entry->special = cmdp->special;
|
||||
@ -469,22 +455,15 @@ find_builtin(const char *name, int *special)
|
||||
|
||||
|
||||
/*
|
||||
* Called when a cd is done. Marks all commands so the next time they
|
||||
* are executed they will be rehashed.
|
||||
* Called when a cd is done. If any entry in cmdtable depends on the current
|
||||
* directory, simply clear cmdtable completely.
|
||||
*/
|
||||
|
||||
void
|
||||
hashcd(void)
|
||||
{
|
||||
struct tblentry **pp;
|
||||
struct tblentry *cmdp;
|
||||
|
||||
for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
|
||||
for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
|
||||
if (cmdp->cmdtype == CMDNORMAL)
|
||||
cmdp->rehash = 1;
|
||||
}
|
||||
}
|
||||
if (cmdtable_cd)
|
||||
clearcmdentry();
|
||||
}
|
||||
|
||||
|
||||
@ -526,6 +505,7 @@ clearcmdentry(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
cmdtable_cd = 0;
|
||||
INTON;
|
||||
}
|
||||
|
||||
@ -566,7 +546,6 @@ cmdlookup(const char *name, int add)
|
||||
+ strlen(name) + 1);
|
||||
cmdp->next = NULL;
|
||||
cmdp->cmdtype = CMDUNKNOWN;
|
||||
cmdp->rehash = 0;
|
||||
strcpy(cmdp->cmdname, name);
|
||||
INTON;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@
|
||||
.\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 15, 2012
|
||||
.Dd January 14, 2013
|
||||
.Dt SH 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -2219,10 +2219,6 @@ The shell maintains a hash table which remembers the locations of commands.
|
||||
With no arguments whatsoever, the
|
||||
.Ic hash
|
||||
command prints out the contents of this table.
|
||||
Entries which have not been looked at since the last
|
||||
.Ic cd
|
||||
command are marked with an asterisk;
|
||||
it is possible for these entries to be invalid.
|
||||
.Pp
|
||||
With arguments, the
|
||||
.Ic hash
|
||||
|
Loading…
Reference in New Issue
Block a user