From 4ff38caa83d5f8f5bc36ff0baa4fa4b3895b1f4f Mon Sep 17 00:00:00 2001 From: June McEnroe Date: Tue, 15 Mar 2022 22:26:11 -0400 Subject: Remove dash Moved to https://git.causal.agency/dash/ and jorts. --- bin/dash/src/exec.c | 908 ---------------------------------------------------- 1 file changed, 908 deletions(-) delete mode 100644 bin/dash/src/exec.c (limited to 'bin/dash/src/exec.c') diff --git a/bin/dash/src/exec.c b/bin/dash/src/exec.c deleted file mode 100644 index 87354d49..00000000 --- a/bin/dash/src/exec.c +++ /dev/null @@ -1,908 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1997-2005 - * Herbert Xu . All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#ifdef HAVE_PATHS_H -#include -#endif - -/* - * When commands are first encountered, they are entered in a hash table. - * This ensures that a full path search will not have to be done for them - * on each invocation. - * - * We should investigate converting to a linear search, even though that - * would make the command name "hash" a misnomer. - */ - -#include "shell.h" -#include "main.h" -#include "nodes.h" -#include "parser.h" -#include "redir.h" -#include "eval.h" -#include "exec.h" -#include "builtins.h" -#include "var.h" -#include "options.h" -#include "output.h" -#include "syntax.h" -#include "memalloc.h" -#include "error.h" -#include "init.h" -#include "mystring.h" -#include "show.h" -#include "jobs.h" -#include "alias.h" -#include "system.h" - - -#define CMDTABLESIZE 31 /* should be prime */ -#define ARB 1 /* actual size determined at run time */ - - - -struct tblentry { - struct tblentry *next; /* next entry in hash chain */ - union param param; /* definition of builtin function */ - short cmdtype; /* index identifying command */ - char rehash; /* if set, cd done since entry created */ - char cmdname[ARB]; /* name of command */ -}; - - -STATIC struct tblentry *cmdtable[CMDTABLESIZE]; -STATIC int builtinloc = -1; /* index in path of %builtin, or -1 */ - - -STATIC void tryexec(char *, char **, char **); -STATIC void printentry(struct tblentry *); -STATIC void clearcmdentry(void); -STATIC struct tblentry *cmdlookup(const char *, int); -STATIC void delete_cmd_entry(void); -STATIC void addcmdentry(char *, struct cmdentry *); -STATIC int describe_command(struct output *, char *, const char *, int); - - -/* - * Exec a program. Never returns. If you change this routine, you may - * have to change the find_command routine as well. - */ - -void -shellexec(char **argv, const char *path, int idx) -{ - char *cmdname; - int e; - char **envp; - int exerrno; - - envp = environment(); - if (strchr(argv[0], '/') != NULL) { - tryexec(argv[0], argv, envp); - e = errno; - } else { - e = ENOENT; - while (padvance(&path, argv[0]) >= 0) { - cmdname = stackblock(); - if (--idx < 0 && pathopt == NULL) { - tryexec(cmdname, argv, envp); - if (errno != ENOENT && errno != ENOTDIR) - e = errno; - } - } - } - - /* Map to POSIX errors */ - switch (e) { - default: - exerrno = 126; - break; - case ELOOP: - case ENAMETOOLONG: - case ENOENT: - case ENOTDIR: - exerrno = 127; - break; - } - exitstatus = exerrno; - TRACE(("shellexec failed for %s, errno %d, suppressint %d\n", - argv[0], e, suppressint )); - exerror(EXEND, "%s: %s", argv[0], errmsg(e, E_EXEC)); - /* NOTREACHED */ -} - - -STATIC void -tryexec(char *cmd, char **argv, char **envp) -{ - char *const path_bshell = _PATH_BSHELL; - -repeat: -#ifdef SYSV - do { - execve(cmd, argv, envp); - } while (errno == EINTR); -#else - execve(cmd, argv, envp); -#endif - if (cmd != path_bshell && errno == ENOEXEC) { - *argv-- = cmd; - *argv = cmd = path_bshell; - goto repeat; - } -} - -static const char *legal_pathopt(const char *opt, const char *term, int magic) -{ - switch (magic) { - case 0: - opt = NULL; - break; - - case 1: - opt = prefix(opt, "builtin") ?: prefix(opt, "func"); - break; - - default: - opt += strcspn(opt, term); - break; - } - - if (opt && *opt == '%') - opt++; - - return opt; -} - -/* - * Do a path search. The variable path (passed by reference) should be - * set to the start of the path before the first call; padvance will update - * this value as it proceeds. Successive calls to padvance will return - * the possible path expansions in sequence. If an option (indicated by - * a percent sign) appears in the path entry then the global variable - * pathopt will be set to point to it; otherwise pathopt will be set to - * NULL. - * - * If magic is 0 then pathopt recognition will be disabled. If magic is - * 1 we shall recognise %builtin/%func. Otherwise we shall accept any - * pathopt. - */ - -const char *pathopt; - -int padvance_magic(const char **path, const char *name, int magic) -{ - const char *term = "%:"; - const char *lpathopt; - const char *p; - char *q; - const char *start; - size_t qlen; - size_t len; - - if (*path == NULL) - return -1; - - lpathopt = NULL; - start = *path; - - if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) { - lpathopt = start + 1; - start = p; - term = ":"; - } - - len = strcspn(start, term); - p = start + len; - - if (*p == '%') { - size_t extra = strchrnul(p, ':') - p; - - if (legal_pathopt(p + 1, term, magic)) - lpathopt = p + 1; - else - len += extra; - - p += extra; - } - - pathopt = lpathopt; - *path = *p == ':' ? p + 1 : NULL; - - /* "2" is for '/' and '\0' */ - qlen = len + strlen(name) + 2; - q = growstackto(qlen); - - if (likely(len)) { - q = mempcpy(q, start, len); - *q++ = '/'; - } - strcpy(q, name); - - return qlen; -} - - - -/*** Command hashing code ***/ - - -int -hashcmd(int argc, char **argv) -{ - struct tblentry **pp; - struct tblentry *cmdp; - int c; - struct cmdentry entry; - char *name; - - while ((c = nextopt("r")) != '\0') { - clearcmdentry(); - return 0; - } - if (*argptr == NULL) { - for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { - for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { - if (cmdp->cmdtype == CMDNORMAL) - printentry(cmdp); - } - } - return 0; - } - c = 0; - while ((name = *argptr) != NULL) { - if ((cmdp = cmdlookup(name, 0)) && - (cmdp->cmdtype == CMDNORMAL || - (cmdp->cmdtype == CMDBUILTIN && - !(cmdp->param.cmd->flags & BUILTIN_REGULAR) && - builtinloc > 0))) - delete_cmd_entry(); - find_command(name, &entry, DO_ERR, pathval()); - if (entry.cmdtype == CMDUNKNOWN) - c = 1; - argptr++; - } - return c; -} - - -STATIC void -printentry(struct tblentry *cmdp) -{ - int idx; - const char *path; - char *name; - - idx = cmdp->param.index; - path = pathval(); - do { - padvance(&path, cmdp->cmdname); - } while (--idx >= 0); - name = stackblock(); - out1str(name); - out1fmt(snlfmt, cmdp->rehash ? "*" : nullstr); -} - - - -/* - * Resolve a command name. If you change this routine, you may have to - * change the shellexec routine as well. - */ - -void -find_command(char *name, struct cmdentry *entry, int act, const char *path) -{ - struct tblentry *cmdp; - int idx; - int prev; - char *fullname; - struct stat64 statb; - int e; - int updatetbl; - struct builtincmd *bcmd; - int len; - - /* If name contains a slash, don't use PATH or hash table */ - if (strchr(name, '/') != NULL) { - entry->u.index = -1; - if (act & DO_ABS) { - while (stat64(name, &statb) < 0) { -#ifdef SYSV - if (errno == EINTR) - continue; -#endif - entry->cmdtype = CMDUNKNOWN; - return; - } - } - entry->cmdtype = CMDNORMAL; - return; - } - - updatetbl = (path == pathval()); - if (!updatetbl) - act |= DO_ALTPATH; - - /* If name is in the table, check answer will be ok */ - if ((cmdp = cmdlookup(name, 0)) != NULL) { - int bit; - - switch (cmdp->cmdtype) { - default: -#if DEBUG - abort(); -#endif - case CMDNORMAL: - bit = DO_ALTPATH | DO_REGBLTIN; - break; - case CMDFUNCTION: - bit = DO_NOFUNC; - break; - case CMDBUILTIN: - bit = cmdp->param.cmd->flags & BUILTIN_REGULAR ? - 0 : DO_REGBLTIN; - break; - } - if (act & bit) { - if (act & bit & DO_REGBLTIN) - goto fail; - - updatetbl = 0; - cmdp = NULL; - } else if (cmdp->rehash == 0) - /* if not invalidated by cd, we're done */ - goto success; - } - - /* If %builtin not in path, check for builtin next */ - bcmd = find_builtin(name); - if (bcmd && ((bcmd->flags & BUILTIN_REGULAR) | (act & DO_ALTPATH) | - (builtinloc <= 0))) - goto builtin_success; - - if (act & DO_REGBLTIN) - goto fail; - - /* We have to search path. */ - prev = -1; /* where to start */ - if (cmdp && cmdp->rehash) { /* doing a rehash */ - if (cmdp->cmdtype == CMDBUILTIN) - prev = builtinloc; - else - prev = cmdp->param.index; - } - - e = ENOENT; - idx = -1; -loop: - while ((len = padvance(&path, name)) >= 0) { - const char *lpathopt = pathopt; - - fullname = stackblock(); - idx++; - if (lpathopt) { - if (*lpathopt == 'b') { - if (bcmd) - goto builtin_success; - continue; - } else if (!(act & DO_NOFUNC)) { - /* handled below */ - } else { - /* ignore unimplemented options */ - continue; - } - } - /* if rehash, don't redo absolute path names */ - if (fullname[0] == '/' && idx <= prev) { - if (idx < prev) - continue; - TRACE(("searchexec \"%s\": no change\n", name)); - goto success; - } - while (stat64(fullname, &statb) < 0) { -#ifdef SYSV - if (errno == EINTR) - continue; -#endif - if (errno != ENOENT && errno != ENOTDIR) - e = errno; - goto loop; - } - e = EACCES; /* if we fail, this will be the error */ - if (!S_ISREG(statb.st_mode)) - continue; - if (lpathopt) { /* this is a %func directory */ - stalloc(len); - readcmdfile(fullname); - if ((cmdp = cmdlookup(name, 0)) == NULL || - cmdp->cmdtype != CMDFUNCTION) - sh_error("%s not defined in %s", name, - fullname); - stunalloc(fullname); - goto success; - } -#ifdef notdef - /* XXX this code stops root executing stuff, and is buggy - if you need a group from the group list. */ - if (statb.st_uid == geteuid()) { - if ((statb.st_mode & 0100) == 0) - goto loop; - } else if (statb.st_gid == getegid()) { - if ((statb.st_mode & 010) == 0) - goto loop; - } else { - if ((statb.st_mode & 01) == 0) - goto loop; - } -#endif - TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); - if (!updatetbl) { - entry->cmdtype = CMDNORMAL; - entry->u.index = idx; - return; - } - INTOFF; - cmdp = cmdlookup(name, 1); - cmdp->cmdtype = CMDNORMAL; - cmdp->param.index = idx; - INTON; - goto success; - } - - /* We failed. If there was an entry for this command, delete it */ - if (cmdp && updatetbl) - delete_cmd_entry(); - if (act & DO_ERR) - sh_warnx("%s: %s", name, errmsg(e, E_EXEC)); -fail: - entry->cmdtype = CMDUNKNOWN; - return; - -builtin_success: - if (!updatetbl) { - entry->cmdtype = CMDBUILTIN; - entry->u.cmd = bcmd; - return; - } - INTOFF; - cmdp = cmdlookup(name, 1); - cmdp->cmdtype = CMDBUILTIN; - cmdp->param.cmd = bcmd; - INTON; -success: - cmdp->rehash = 0; - entry->cmdtype = cmdp->cmdtype; - entry->u = cmdp->param; -} - - - -/* - * Search the table of builtin commands. - */ - -struct builtincmd * -find_builtin(const char *name) -{ - struct builtincmd *bp; - - bp = bsearch( - &name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd), - pstrcmp - ); - return bp; -} - - - -/* - * Called when a cd is done. Marks all commands so the next time they - * are executed they will be rehashed. - */ - -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->cmdtype == CMDBUILTIN && - !(cmdp->param.cmd->flags & BUILTIN_REGULAR) && - builtinloc > 0 - )) - cmdp->rehash = 1; - } - } -} - - - -/* - * Fix command hash table when PATH changed. - * Called before PATH is changed. The argument is the new value of PATH; - * pathval() still returns the old value at this point. - * Called with interrupts off. - */ - -void -changepath(const char *newval) -{ - const char *new; - int idx; - int bltin; - - new = newval; - idx = 0; - bltin = -1; - for (;;) { - if (*new == '%' && prefix(new + 1, "builtin")) { - bltin = idx; - break; - } - new = strchr(new, ':'); - if (!new) - break; - idx++; - new++; - } - builtinloc = bltin; - clearcmdentry(); -} - - -/* - * Clear out command entries. The argument specifies the first entry in - * PATH which has changed. - */ - -STATIC void -clearcmdentry(void) -{ - struct tblentry **tblp; - struct tblentry **pp; - struct tblentry *cmdp; - - INTOFF; - for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) { - pp = tblp; - while ((cmdp = *pp) != NULL) { - if (cmdp->cmdtype == CMDNORMAL || - (cmdp->cmdtype == CMDBUILTIN && - !(cmdp->param.cmd->flags & BUILTIN_REGULAR) && - builtinloc > 0)) { - *pp = cmdp->next; - ckfree(cmdp); - } else { - pp = &cmdp->next; - } - } - } - INTON; -} - - - -/* - * Locate a command in the command hash table. If "add" is nonzero, - * add the command to the table if it is not already present. The - * variable "lastcmdentry" is set to point to the address of the link - * pointing to the entry, so that delete_cmd_entry can delete the - * entry. - * - * Interrupts must be off if called with add != 0. - */ - -struct tblentry **lastcmdentry; - - -STATIC struct tblentry * -cmdlookup(const char *name, int add) -{ - unsigned int hashval; - const char *p; - struct tblentry *cmdp; - struct tblentry **pp; - - p = name; - hashval = (unsigned char)*p << 4; - while (*p) - hashval += (unsigned char)*p++; - hashval &= 0x7FFF; - pp = &cmdtable[hashval % CMDTABLESIZE]; - for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { - if (equal(cmdp->cmdname, name)) - break; - pp = &cmdp->next; - } - if (add && cmdp == NULL) { - cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB - + strlen(name) + 1); - cmdp->next = NULL; - cmdp->cmdtype = CMDUNKNOWN; - strcpy(cmdp->cmdname, name); - } - lastcmdentry = pp; - return cmdp; -} - -/* - * Delete the command entry returned on the last lookup. - */ - -STATIC void -delete_cmd_entry(void) -{ - struct tblentry *cmdp; - - INTOFF; - cmdp = *lastcmdentry; - *lastcmdentry = cmdp->next; - if (cmdp->cmdtype == CMDFUNCTION) - freefunc(cmdp->param.func); - ckfree(cmdp); - INTON; -} - - - -#ifdef notdef -void -getcmdentry(char *name, struct cmdentry *entry) -{ - struct tblentry *cmdp = cmdlookup(name, 0); - - if (cmdp) { - entry->u = cmdp->param; - entry->cmdtype = cmdp->cmdtype; - } else { - entry->cmdtype = CMDUNKNOWN; - entry->u.index = 0; - } -} -#endif - - -/* - * Add a new command entry, replacing any existing command entry for - * the same name - except special builtins. - */ - -STATIC void -addcmdentry(char *name, struct cmdentry *entry) -{ - struct tblentry *cmdp; - - cmdp = cmdlookup(name, 1); - if (cmdp->cmdtype == CMDFUNCTION) { - freefunc(cmdp->param.func); - } - cmdp->cmdtype = entry->cmdtype; - cmdp->param = entry->u; - cmdp->rehash = 0; -} - - -/* - * Define a shell function. - */ - -void -defun(union node *func) -{ - struct cmdentry entry; - - INTOFF; - entry.cmdtype = CMDFUNCTION; - entry.u.func = copyfunc(func); - addcmdentry(func->ndefun.text, &entry); - INTON; -} - - -/* - * Delete a function if it exists. - */ - -void -unsetfunc(const char *name) -{ - struct tblentry *cmdp; - - if ((cmdp = cmdlookup(name, 0)) != NULL && - cmdp->cmdtype == CMDFUNCTION) - delete_cmd_entry(); -} - -/* - * Locate and print what a word is... - */ - -int -typecmd(int argc, char **argv) -{ - int i; - int err = 0; - - for (i = 1; i < argc; i++) { - err |= describe_command(out1, argv[i], NULL, 1); - } - return err; -} - -STATIC int -describe_command(out, command, path, verbose) - struct output *out; - char *command; - const char *path; - int verbose; -{ - struct cmdentry entry; - struct tblentry *cmdp; - const struct alias *ap; - - if (verbose) { - outstr(command, out); - } - - /* First look at the keywords */ - if (findkwd(command)) { - outstr(verbose ? " is a shell keyword" : command, out); - goto out; - } - - /* Then look at the aliases */ - if ((ap = lookupalias(command, 0)) != NULL) { - if (verbose) { - outfmt(out, " is an alias for %s", ap->val); - } else { - outstr("alias ", out); - printalias(ap); - return 0; - } - goto out; - } - - /* Then if the standard search path is used, check if it is - * a tracked alias. - */ - if (path == NULL) { - path = pathval(); - cmdp = cmdlookup(command, 0); - } else { - cmdp = NULL; - } - - if (cmdp != NULL) { - entry.cmdtype = cmdp->cmdtype; - entry.u = cmdp->param; - } else { - /* Finally use brute force */ - find_command(command, &entry, DO_ABS, path); - } - - switch (entry.cmdtype) { - case CMDNORMAL: { - int j = entry.u.index; - char *p; - if (j == -1) { - p = command; - } else { - do { - padvance(&path, command); - } while (--j >= 0); - p = stackblock(); - } - if (verbose) { - outfmt( - out, " is%s %s", - cmdp ? " a tracked alias for" : nullstr, p - ); - } else { - outstr(p, out); - } - break; - } - - case CMDFUNCTION: - if (verbose) { - outstr(" is a shell function", out); - } else { - outstr(command, out); - } - break; - - case CMDBUILTIN: - if (verbose) { - outfmt( - out, " is a %sshell builtin", - entry.u.cmd->flags & BUILTIN_SPECIAL ? - "special " : nullstr - ); - } else { - outstr(command, out); - } - break; - - default: - if (verbose) { - outstr(": not found\n", out); - } - return 127; - } - -out: - outc('\n', out); - return 0; -} - -int -commandcmd(argc, argv) - int argc; - char **argv; -{ - char *cmd; - int c; - enum { - VERIFY_BRIEF = 1, - VERIFY_VERBOSE = 2, - } verify = 0; - const char *path = NULL; - - while ((c = nextopt("pvV")) != '\0') - if (c == 'V') - verify |= VERIFY_VERBOSE; - else if (c == 'v') - verify |= VERIFY_BRIEF; -#ifdef DEBUG - else if (c != 'p') - abort(); -#endif - else - path = defpath; - - cmd = *argptr; - if (verify && cmd) - return describe_command(out1, cmd, path, verify - VERIFY_BRIEF); - - return 0; -} -- cgit 1.4.1