From 523646ee5c7d501d377a245a5dbbcd0dbf681d6f Mon Sep 17 00:00:00 2001 From: Jilles Tjoelker Date: Mon, 14 Jan 2013 16:40:50 +0000 Subject: [PATCH] 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. --- bin/sh/exec.c | 49 ++++++++++++++----------------------------------- bin/sh/sh.1 | 6 +----- 2 files changed, 15 insertions(+), 40 deletions(-) diff --git a/bin/sh/exec.c b/bin/sh/exec.c index eb3240381196..7a6dbae4172e 100644 --- a/bin/sh/exec.c +++ b/bin/sh/exec.c @@ -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; } diff --git a/bin/sh/sh.1 b/bin/sh/sh.1 index 175026746dfc..83cf7c2d0343 100644 --- a/bin/sh/sh.1 +++ b/bin/sh/sh.1 @@ -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