diff -urN netbsd-sh/builtins.def ash-0.3.7.orig/builtins.def --- netbsd-sh/builtins.def Mon Apr 10 13:02:58 2000 +++ ash-0.3.7.orig/builtins.def Mon Apr 23 22:16:46 2001 @@ -49,12 +49,13 @@ # # NOTE: bltincmd must come first! -bltincmd command +bltincmd builtin #alloccmd alloc bgcmd -j bg breakcmd break continue #catfcmd catf cdcmd cd chdir +commandcmd command dotcmd . echocmd echo evalcmd eval diff -urN netbsd-sh/eval.c ash-0.3.7.orig/eval.c --- netbsd-sh/eval.c Tue May 23 12:03:18 2000 +++ ash-0.3.7.orig/eval.c Mon Apr 23 22:16:46 2001 @@ -45,7 +45,9 @@ #endif #endif /* not lint */ +#include #include +#include #include /* @@ -101,6 +103,8 @@ STATIC void evalpipe __P((union node *)); STATIC void evalcommand __P((union node *, int, struct backcmd *)); STATIC void prehash __P((union node *)); +STATIC int is_assignment_builtin __P((const char *)); +STATIC const char *get_standard_path __P((void)); /* @@ -257,6 +261,11 @@ evalcase(n, flags); break; case NDEFUN: + if (is_special_builtin(n->narg.text)) { + outfmt(out2, "%s is a special built-in\n", n->narg.text); + exitstatus = 1; + break; + } defun(n->narg.text, n->narg.next); exitstatus = 0; break; @@ -279,7 +288,7 @@ out: if (pendingsigs) dotrap(); - if ((flags & EV_EXIT) || (eflag && exitstatus && !(flags & EV_TESTED))) + if (flags & EV_EXIT) exitshell(exitstatus); } @@ -497,9 +507,14 @@ close(0); copyfd(prevfd, 0); close(prevfd); + if (pip[0] == 0) { + pip[0] = -1; + } } if (pip[1] >= 0) { - close(pip[0]); + if (pip[0] >= 0) { + close(pip[0]); + } if (pip[1] != 1) { close(1); copyfd(pip[1], 1); @@ -607,6 +622,7 @@ int argc; char **envp; int varflag; + int pseudovarflag; struct strlist *sp; int mode; int pip[2]; @@ -619,12 +635,17 @@ struct localvar *volatile savelocalvars; volatile int e; char *lastarg; + int not_special; + const char *path; + const char *standard_path; #if __GNUC__ /* Avoid longjmp clobbering */ (void) &argv; (void) &argc; (void) &lastarg; (void) &flags; + (void) ¬_special; + (void) &standard_path; #endif /* First expand the arguments. */ @@ -632,21 +653,31 @@ setstackmark(&smark); arglist.lastp = &arglist.list; varlist.lastp = &varlist.list; + arglist.list = 0; varflag = 1; + pseudovarflag = 0; oexitstatus = exitstatus; exitstatus = 0; + not_special = 0; + path = pathval(); + standard_path = NULL; for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { char *p = argp->narg.text; - if (varflag && is_name(*p)) { + if ((varflag || pseudovarflag) && is_name(*p)) { do { p++; } while (is_in_name(*p)); if (*p == '=') { - expandarg(argp, &varlist, EXP_VARTILDE); + if (varflag) + expandarg(argp, &varlist, EXP_VARTILDE); + else + expandarg(argp, &arglist, EXP_VARTILDE); continue; } } expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); + if (varflag && arglist.list && is_assignment_builtin(arglist.list->text)) + pseudovarflag = 1; varflag = 0; } *arglist.lastp = NULL; @@ -688,37 +719,75 @@ cmdentry.u.index = BLTINCMD; } else { static const char PATH[] = "PATH="; - const char *path = pathval(); + const char *oldpath = NULL; + int findflag = DO_ERR; /* * Modify the command lookup path, if a PATH= assignment * 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; - - find_command(argv[0], &cmdentry, DO_ERR, path); - if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ - exitstatus = 127; - flushout(&errout); - return; - } - /* implement the bltin builtin here */ - if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { - for (;;) { + findflag |= DO_BRUTE; + } + for(;;) { + find_command(argv[0], &cmdentry, findflag, path); + if (oldpath) { + path = oldpath; + oldpath = NULL; + } + if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ + exitstatus = 127; + flushout(&errout); + goto out; + } + /* implement the bltin builtin here */ + if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { + not_special = 1; + for(;;) { + argv++; + if (--argc == 0) + break; + if ((cmdentry.u.index = find_builtin(*argv)) < 0) { + outfmt(&errout, "%s: not found\n", *argv); + exitstatus = 127; + flushout(&errout); + goto out; + } + if (cmdentry.u.index != BLTINCMD) + break; + } + } + if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == COMMANDCMD) { + not_special = 1; argv++; - if (--argc == 0) - break; - if ((cmdentry.u.index = find_builtin(*argv)) < 0) { - outfmt(&errout, "%s: not found\n", *argv); - exitstatus = 127; - flushout(&errout); - return; + if (--argc == 0) { + exitstatus = 0; + goto out; } - if (cmdentry.u.index != BLTINCMD) - break; + if (*argv[0] == '-') { + if (!equal(argv[0], "-p")) { + argv--; + argc++; + break; + } + argv++; + if (--argc == 0) { + exitstatus = 0; + goto out; + } + if (!standard_path) { + standard_path = get_standard_path(); + } + oldpath = path; + path = standard_path; + findflag |= DO_BRUTE; + } + findflag |= DO_NOFUN; + continue; } + break; } } @@ -756,13 +825,12 @@ #ifdef DEBUG trputs("Shell function: "); trargs(argv); #endif + exitstatus = oexitstatus; redirect(cmd->ncmd.redirect, REDIR_PUSH); saveparam = shellparam; shellparam.malloc = 0; - shellparam.reset = 1; shellparam.nparam = argc - 1; shellparam.p = argv + 1; - shellparam.optnext = NULL; INTOFF; savelocalvars = localvars; localvars = NULL; @@ -772,6 +840,8 @@ freeparam((volatile struct shparam *) &saveparam); } else { + saveparam.optind = shellparam.optind; + saveparam.optoff = shellparam.optoff; freeparam(&shellparam); shellparam = saveparam; } @@ -790,6 +860,8 @@ INTOFF; poplocalvars(); localvars = savelocalvars; + saveparam.optind = shellparam.optind; + saveparam.optoff = shellparam.optoff; freeparam(&shellparam); shellparam = saveparam; handler = savehandler; @@ -832,6 +908,8 @@ out1 = &output; out2 = &errout; freestdout(); + if (!not_special && is_special_builtin(commandname)) + listsetvar(cmdenviron); cmdenviron = NULL; if (e != EXSHELLPROC) { commandname = savecmdname; @@ -867,7 +953,7 @@ for (sp = varlist.list ; sp ; sp = sp->next) setvareq(sp->text, VEXPORT|VSTACK); envp = environment(); - shellexec(argv, envp, pathval(), cmdentry.u.index); + shellexec(argv, envp, path, cmdentry.u.index); } goto out; @@ -1025,4 +1111,49 @@ shellexec(argv + 1, environment(), pathval(), 0); } return 0; +} + +STATIC int +is_assignment_builtin (command) + const char *command; +{ + static const char *assignment_builtins[] = { + "alias", "declare", "export", "local", "readonly", "typeset", + (char *)NULL + }; + int i; + + for (i = 0; assignment_builtins[i]; i++) + if (strcmp(command, assignment_builtins[i]) == 0) return 1; + return 0; +} + +int +is_special_builtin(name) + const char *name; +{ + static const char *special_builtins[] = { + "break", ":", ".", "continue", "eval", "exec", "exit", + "export", "readonly", "return", "set", "shift", "times", + "trap", "unset", (char *)NULL + }; + int i; + + if (!name) return 0; + for (i = 0; special_builtins[i]; i++) + if (equal(name, special_builtins[i])) return 1; + return 0; +} + +STATIC const char * +get_standard_path() +{ + char *p; + size_t len; + + len = confstr(_CS_PATH, NULL, 0); + p = stalloc(len + 2); + *p = '\0'; + confstr(_CS_PATH, p, len); + return p; } diff -urN netbsd-sh/eval.h ash-0.3.7.orig/eval.h --- netbsd-sh/eval.h Fri Jan 28 13:03:00 2000 +++ ash-0.3.7.orig/eval.h Mon Apr 23 22:16:46 2001 @@ -61,6 +61,7 @@ int falsecmd __P((int, char **)); int truecmd __P((int, char **)); int execcmd __P((int, char **)); +int is_special_builtin __P((const char *)); /* in_function returns nonzero if we are currently evaluating a function */ #define in_function() funcnest diff -urN netbsd-sh/exec.c ash-0.3.7.orig/exec.c --- netbsd-sh/exec.c Fri Jan 12 17:50:35 2001 +++ ash-0.3.7.orig/exec.c Mon Apr 23 22:16:46 2001 @@ -51,6 +51,7 @@ #include #include #include +#include /* * When commands are first encountered, they are entered in a hash table. @@ -108,6 +109,9 @@ STATIC void clearcmdentry __P((int)); STATIC struct tblentry *cmdlookup __P((char *, int)); STATIC void delete_cmd_entry __P((void)); +STATIC int describe_command __P((char *, int)); +STATIC int path_change __P((const char *, int *)); +STATIC int is_regular_builtin __P((const char *)); @@ -164,7 +172,7 @@ char **envp; { int e; -#ifndef BSD +#if !defined(BSD) && !defined(linux) char *p; #endif @@ -180,7 +188,7 @@ initshellproc(); setinputfile(cmd, 0); commandname = arg0 = savestr(argv[0]); -#ifndef BSD +#if !defined(BSD) && !defined(linux) pgetc(); pungetc(); /* fill up input buffer */ p = parsenextc; if (parsenleft > 2 && p[0] == '#' && p[1] == '!') { @@ -195,7 +203,7 @@ } -#ifndef BSD +#if !defined(BSD) && !defined(linux) /* * Execute an interpreter introduced by "#!", for systems where this * feature has not been built into the kernel. If the interpreter is @@ -351,27 +359,29 @@ if (*argptr == NULL) { for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { - printentry(cmdp, verbose); + if (cmdp->cmdtype != CMDBUILTIN) { + printentry(cmdp, verbose); + } } } return 0; } + c = 0; while ((name = *argptr) != NULL) { if ((cmdp = cmdlookup(name, 0)) != NULL && (cmdp->cmdtype == CMDNORMAL || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))) delete_cmd_entry(); find_command(name, &entry, DO_ERR, pathval()); - if (verbose) { - if (entry.cmdtype != CMDUNKNOWN) { /* if no error msg */ - cmdp = cmdlookup(name, 0); - printentry(cmdp, verbose); - } + if (entry.cmdtype == CMDUNKNOWN) c = 1; + else if (verbose) { + cmdp = cmdlookup(name, 0); + if (cmdp) printentry(cmdp, verbose); flushall(); } argptr++; } - return 0; + return c; } @@ -435,6 +445,10 @@ struct stat statb; int e; int i; + int bltin; + int firstchange; + int updatetbl; + int regular; /* If name contains a slash, don't use the hash table */ if (strchr(name, '/') != NULL) { @@ -459,12 +473,54 @@ return; } + updatetbl = 1; + if (act & DO_BRUTE) { + firstchange = path_change(path, &bltin); + } else { + bltin = builtinloc; + firstchange = 9999; + } + /* If name is in the table, and not invalidated by cd, we're done */ - if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) - goto success; + if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) { + if (cmdp->cmdtype == CMDFUNCTION) { + if (act & DO_NOFUN) { + updatetbl = 0; + } else { + goto success; + } + } else if (act & DO_BRUTE) { + if ((cmdp->cmdtype == CMDNORMAL && + cmdp->param.index >= firstchange) || + (cmdp->cmdtype == CMDBUILTIN && + ((builtinloc < 0 && bltin >= 0) ? + bltin : builtinloc) >= firstchange)) { + /* need to recompute the entry */ + } else { + goto success; + } + } else { + goto success; + } + } + + if ((regular = is_regular_builtin(name))) { + if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) { + goto success; + } + } else if (act & DO_BRUTE) { + if (firstchange == 0) { + updatetbl = 0; + } + } /* If %builtin not in path, check for builtin next */ - if (builtinloc < 0 && (i = find_builtin(name)) >= 0) { + if ((bltin < 0 || regular) && (i = find_builtin(name)) >= 0) { + if (!updatetbl) { + entry->cmdtype = CMDBUILTIN; + entry->u.index = i; + return; + } INTOFF; cmdp = cmdlookup(name, 1); cmdp->cmdtype = CMDBUILTIN; @@ -475,7 +531,7 @@ /* We have to search path. */ prev = -1; /* where to start */ - if (cmdp) { /* doing a rehash */ + if (cmdp && cmdp->rehash) { /* doing a rehash */ if (cmdp->cmdtype == CMDBUILTIN) prev = builtinloc; else @@ -488,26 +544,38 @@ while ((fullname = padvance(&path, name)) != NULL) { stunalloc(fullname); idx++; + if (idx >= firstchange) { + updatetbl = 0; + } if (pathopt) { if (prefix("builtin", pathopt)) { - if ((i = find_builtin(name)) < 0) - goto loop; - INTOFF; - cmdp = cmdlookup(name, 1); - cmdp->cmdtype = CMDBUILTIN; - cmdp->param.index = i; - INTON; - goto success; - } else if (prefix("func", pathopt)) { + if ((i = find_builtin(name)) >= 0) { + if (!updatetbl) { + entry->cmdtype = CMDBUILTIN; + entry->u.index = i; + return; + } + INTOFF; + cmdp = cmdlookup(name, 1); + cmdp->cmdtype = CMDBUILTIN; + cmdp->param.index = i; + INTON; + goto success; + } else { + continue; + } + } else if (!(act & DO_NOFUN) && + prefix("func", pathopt)) { /* handled below */ } else { - goto loop; /* ignore unimplemented options */ + continue; /* ignore unimplemented options */ } } /* if rehash, don't redo absolute path names */ - if (fullname[0] == '/' && idx <= prev) { + if (fullname[0] == '/' && idx <= prev && + idx < firstchange) { if (idx < prev) - goto loop; + continue; TRACE(("searchexec \"%s\": no change\n", name)); goto success; } @@ -522,7 +590,7 @@ } e = EACCES; /* if we fail, this will be the error */ if (!S_ISREG(statb.st_mode)) - goto loop; + continue; if (pathopt) { /* this is a %func directory */ stalloc(strlen(fullname) + 1); readcmdfile(fullname); @@ -544,6 +612,13 @@ } #endif TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); + /* If we aren't called with DO_BRUTE and cmdp is set, it must + be a function and we're being called with DO_NOFUN */ + if (!updatetbl) { + entry->cmdtype = CMDNORMAL; + entry->u.index = idx; + return; + } INTOFF; cmdp = cmdlookup(name, 1); cmdp->cmdtype = CMDNORMAL; @@ -553,7 +628,7 @@ } /* We failed. If there was an entry for this command, delete it */ - if (cmdp) + if (cmdp && updatetbl) delete_cmd_entry(); if (act & DO_ERR) outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC)); @@ -618,37 +693,12 @@ changepath(newval) const char *newval; { - const char *old, *new; - int idx; int firstchange; int bltin; - old = pathval(); - new = newval; - firstchange = 9999; /* assume no change */ - idx = 0; - bltin = -1; - for (;;) { - if (*old != *new) { - firstchange = idx; - if ((*old == '\0' && *new == ':') - || (*old == ':' && *new == '\0')) - firstchange++; - old = new; /* ignore subsequent differences */ - } - if (*new == '\0') - break; - if (*new == '%' && bltin < 0 && prefix("builtin", new + 1)) - bltin = idx; - if (*new == ':') { - idx++; - } - new++, old++; - } + firstchange = path_change(newval, &bltin); if (builtinloc < 0 && bltin >= 0) builtinloc = bltin; /* zap builtins */ - if (builtinloc >= 0 && bltin < 0) - firstchange = 0; clearcmdentry(firstchange); builtinloc = bltin; } @@ -838,11 +888,9 @@ { struct cmdentry entry; - INTOFF; entry.cmdtype = CMDFUNCTION; entry.u.func = copyfunc(func); addcmdentry(name, &entry); - INTON; } @@ -944,4 +992,190 @@ } } return err; +} + +STATIC int +describe_command(command, verbose) + char *command; + int verbose; +{ + struct cmdentry entry; + struct tblentry *cmdp; + char **pp; + struct alias *ap; + extern char *const parsekwd[]; + + for (pp = (char **)parsekwd; *pp; pp++) + if (**pp == *command && equal(*pp, command)) + break; + + if (*pp) { + if (verbose) { + out1fmt("%s is a reserved word\n", command); + } else { + out1fmt("%s\n", command); + } + return 0; + } + + /* Then look at the aliases */ + if ((ap = lookupalias(command, 1)) != NULL) { + if (verbose) { + out1fmt("%s is aliased to `%s'\n", command, ap->val); + } else { + out1fmt("alias %s='%s'\n", command, ap->val); + } + return 0; + } + + /* Then check if it is a tracked alias */ + if ((cmdp = cmdlookup(command, 0)) != NULL) { + entry.cmdtype = cmdp->cmdtype; + entry.u = cmdp->param; + } + else { + /* Finally use brute force */ + find_command(command, &entry, DO_ABS, pathval()); + } + + switch (entry.cmdtype) { + case CMDNORMAL: { + int j = entry.u.index; + const char *path = pathval(); + char *name; + if (j == -1) + name = command; + else { + do { + name = padvance(&path, command); + stunalloc(name); + } while (--j >= 0); + } + if (verbose) { + out1fmt("%s is %s\n", command, name); + } else { + out1fmt("%s\n", name); + } + break; + } + case CMDFUNCTION: + if (verbose) { + out1fmt("%s is a function\n", command); + } else { + out1fmt("%s\n", command); + } + break; + case CMDBUILTIN: + if (verbose) { + if (is_special_builtin(command)) { + out1fmt("%s is a special built-in utility\n", command); + } else { + out1fmt("%s is a built-in utility\n", command); + } + } else { + out1fmt("%s\n", command); + } + break; + default: + outfmt(out2, "%s not found\n", command); + return 127; + } + + return 0; +} + +int +commandcmd(argc, argv) + int argc; + char **argv; +{ + int c; + int default_path = 0; + int verify_only = 0; + int verbose_verify_only = 0; + + while ((c = nextopt("pvV")) != '\0') + switch (c) { + case 'p': + default_path = 1; + break; + case 'v': + verify_only = 1; + break; + case 'V': + verbose_verify_only = 1; + break; + default: + outfmt(out2, +"command: nextopt returned character code 0%o\n", c); + return EX_SOFTWARE; + } + + if (default_path + verify_only + verbose_verify_only > 1 || + !*argptr) { + outfmt(out2, +"command [-p] command [arg ...]\n"); + outfmt(out2, +"command {-v|-V} command\n"); + return EX_USAGE; + } + + if (verify_only || verbose_verify_only) { + return describe_command(*argptr, verbose_verify_only); + } + + return 0; +} + +STATIC int +path_change(newval, bltin) + const char *newval; + int *bltin; +{ + const char *old, *new; + int idx; + int firstchange; + + old = pathval(); + new = newval; + firstchange = 9999; /* assume no change */ + idx = 0; + *bltin = -1; + for (;;) { + if (*old != *new) { + firstchange = idx; + if ((*old == '\0' && *new == ':') + || (*old == ':' && *new == '\0')) + firstchange++; + old = new; /* ignore subsequent differences */ + } + if (*new == '\0') + break; + if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1)) + *bltin = idx; + if (*new == ':') { + idx++; + } + new++, old++; + } + if (builtinloc >= 0 && *bltin < 0) + firstchange = 0; + return firstchange; +} + +STATIC int +is_regular_builtin(name) + const char *name; +{ + static const char *regular_builtins[] = { + "alias", "bg", "cd", "command", "false", "fc", "fg", + "getopts", "jobs", "kill", "newgrp", "read", "true", + "umask", "unalias", "wait", (char *)NULL + }; + int i; + + if (!name) return 0; + for (i = 0; regular_builtins[i]; i++) + if (equal(name, regular_builtins[i])) return 1; + return 0; } diff -urN netbsd-sh/exec.h ash-0.3.7.orig/exec.h --- netbsd-sh/exec.h Tue May 23 12:03:19 2000 +++ ash-0.3.7.orig/exec.h Mon Apr 23 22:16:46 2001 @@ -56,6 +56,8 @@ #define DO_ERR 1 /* find_command prints errors */ #define DO_ABS 2 /* find_command checks absolute paths */ +#define DO_NOFUN 4 /* find_command ignores functions */ +#define DO_BRUTE 8 /* find_command ignores hash table */ extern const char *pathopt; /* set by padvance */ extern int exerrno; /* last exec error */ @@ -74,3 +76,4 @@ void defun __P((char *, union node *)); int unsetfunc __P((char *)); int typecmd __P((int, char **)); +int commandcmd __P((int, char **));