diff --git a/bin/sh/eval.c b/bin/sh/eval.c index 4f20822d1f7..33dec0ea7be 100644 --- a/bin/sh/eval.c +++ b/bin/sh/eval.c @@ -612,12 +612,14 @@ evalcommand(cmd, flags, backcmd) volatile int e; char *lastarg; int realstatus; + int do_clearcmdentry; #if __GNUC__ /* Avoid longjmp clobbering */ (void) &argv; (void) &argc; (void) &lastarg; (void) &flags; + (void) &do_clearcmdentry; #endif /* First expand the arguments. */ @@ -626,6 +628,7 @@ evalcommand(cmd, flags, backcmd) arglist.lastp = &arglist.list; varlist.lastp = &varlist.list; varflag = 1; + do_clearcmdentry = 0; oexitstatus = exitstatus; exitstatus = 0; for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { @@ -688,8 +691,29 @@ evalcommand(cmd, flags, backcmd) * is present */ for (sp = varlist.list ; sp ; sp = sp->next) - if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) + if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) { path = sp->text + sizeof(PATH) - 1; + /* + * On `PATH=... command`, we need to make + * sure that the command isn't using the + * non-updated hash table of the outer PATH + * setting and we need to make sure that + * the hash table isn't filled with items + * from the temporary setting. + * + * It would be better to forbit using and + * updating the table while this command + * runs, by the command finding mechanism + * is heavily integrated with hash handling, + * so we just delete the hash before and after + * the command runs. Partly deleting like + * changepatch() does doesn't seem worth the + * bookinging effort, since most such runs add + * diretories in front of the new PATH. + */ + clearcmdentry(0); + do_clearcmdentry = 1; + } find_command(argv[0], &cmdentry, 1, path); if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ @@ -887,6 +911,8 @@ parent: /* parent process gets here (if we forked) */ out: if (lastarg) setvar("_", lastarg, 0); + if (do_clearcmdentry) + clearcmdentry(0); popstackmark(&smark); } diff --git a/bin/sh/exec.c b/bin/sh/exec.c index 3bfdba5eb98..67a858b184d 100644 --- a/bin/sh/exec.c +++ b/bin/sh/exec.c @@ -104,7 +104,6 @@ STATIC void tryexec __P((char *, char **, char **)); STATIC void execinterp __P((char **, char **)); #endif STATIC void printentry __P((struct tblentry *, int)); -STATIC void clearcmdentry __P((int)); STATIC struct tblentry *cmdlookup __P((char *, int)); STATIC void delete_cmd_entry __P((void)); @@ -640,7 +639,7 @@ changepath(newval) * PATH which has changed. */ -STATIC void +void clearcmdentry(firstchange) int firstchange; { diff --git a/bin/sh/exec.h b/bin/sh/exec.h index 5b8e5e4657c..bb593f01011 100644 --- a/bin/sh/exec.h +++ b/bin/sh/exec.h @@ -69,3 +69,4 @@ void addcmdentry __P((char *, struct cmdentry *)); void defun __P((char *, union node *)); int unsetfunc __P((char *)); int typecmd __P((int, char **)); +void clearcmdentry __P((int));