📄 exec.c
字号:
/*- * Copyright (c) 1991 The Regents of the University of California. * 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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. */#ifndef lintstatic char sccsid[] = "@(#)exec.c 5.2 (Berkeley) 3/13/91";#endif /* not lint *//* * 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 "input.h"#include "output.h"#include "syntax.h"#include "memalloc.h"#include "error.h"#include "init.h"#include "mystring.h"#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <errno.h>#include <limits.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 */#ifdef __STDC__STATIC void tryexec(char *, char **, char **);STATIC void execinterp(char **, char **);STATIC void printentry(struct tblentry *);STATIC void clearcmdentry(int);STATIC struct tblentry *cmdlookup(char *, int);STATIC void delete_cmd_entry(void);#elseSTATIC void tryexec();STATIC void execinterp();STATIC void printentry();STATIC void clearcmdentry();STATIC struct tblentry *cmdlookup();STATIC void delete_cmd_entry();#endif/* * Exec a program. Never returns. If you change this routine, you may * have to change the find_command routine as well. */voidshellexec(argv, envp, path, index) char **argv, **envp; char *path; { char *cmdname; int e; if (strchr(argv[0], '/') != NULL) { tryexec(argv[0], argv, envp); e = errno; } else { e = ENOENT; while ((cmdname = padvance(&path, argv[0])) != NULL) { if (--index < 0 && pathopt == NULL) { tryexec(cmdname, argv, envp); if (errno != ENOENT && errno != ENOTDIR) e = errno; } stunalloc(cmdname); } } error2(argv[0], errmsg(e, E_EXEC));}STATIC voidtryexec(cmd, argv, envp) char *cmd; char **argv; char **envp; { int e; char *p;#ifdef SYSV do { execve(cmd, argv, envp); } while (errno == EINTR);#else execve(cmd, argv, envp);#endif#if !__minix_vmd e = errno; if (e == ENOEXEC) { initshellproc(); setinputfile(cmd, 0); commandname = arg0 = savestr(argv[0]);#ifndef BSD pgetc(); pungetc(); /* fill up input buffer */ p = parsenextc; if (parsenleft > 2 && p[0] == '#' && p[1] == '!') { argv[0] = cmd; execinterp(argv, envp); }#endif setparam(argv + 1); exraise(EXSHELLPROC); /*NOTREACHED*/ } errno = e;#endif}#if !defined(BSD) && !__minix_vmd/* * Execute an interpreter introduced by "#!", for systems where this * feature has not been built into the kernel. If the interpreter is * the shell, return (effectively ignoring the "#!"). If the execution * of the interpreter fails, exit. * * This code peeks inside the input buffer in order to avoid actually * reading any input. It would benefit from a rewrite. */#define NEWARGS 5STATIC voidexecinterp(argv, envp) char **argv, **envp; { int n; char *inp; char *outp; char c; char *p; char **ap; char *newargs[NEWARGS]; int i; char **ap2; char **new; n = parsenleft - 2; inp = parsenextc + 2; ap = newargs; for (;;) { while (--n >= 0 && (*inp == ' ' || *inp == '\t')) inp++; if (n < 0) goto bad; if ((c = *inp++) == '\n') break; if (ap == &newargs[NEWARGS])bad: error("Bad #! line"); STARTSTACKSTR(outp); do { STPUTC(c, outp); } while (--n >= 0 && (c = *inp++) != ' ' && c != '\t' && c != '\n'); STPUTC('\0', outp); n++, inp--; *ap++ = grabstackstr(outp); }#if !__minix if (ap == newargs + 1) { /* if no args, maybe no exec is needed */ p = newargs[0]; for (;;) { if (equal(p, "sh") || equal(p, "ash")) { return; } while (*p != '/') { if (*p == '\0') goto break2; p++; } p++; }break2:; }#endif i = (char *)ap - (char *)newargs; /* size in bytes */ if (i == 0) error("Bad #! line"); for (ap2 = argv ; *ap2++ != NULL ; ); new = ckmalloc(i + ((char *)ap2 - (char *)argv)); ap = newargs, ap2 = new; while ((i -= sizeof (char **)) >= 0) *ap2++ = *ap++; ap = argv; while (*ap2++ = *ap++); shellexec(new, envp, pathval(), 0);}#endif/* * 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. */char *pathopt;char *padvance(path, name) char **path; char *name; { register char *p, *q; char *start; int len; if (*path == NULL) return NULL; start = *path; for (p = start ; *p && *p != ':' && *p != '%' ; p++); len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ while (stackblocksize() < len) growstackblock(); q = stackblock(); if (p != start) { bcopy(start, q, p - start); q += p - start; *q++ = '/'; } strcpy(q, name); pathopt = NULL; if (*p == '%') { pathopt = ++p; while (*p && *p != ':') p++; } if (*p == ':') *path = p + 1; else *path = NULL; return stalloc(len);}/*** Command hashing code ***/hashcmd(argc, argv) char **argv; { struct tblentry **pp; struct tblentry *cmdp; int c; int verbose; struct cmdentry entry; char *name; if (argc <= 1) { for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { printentry(cmdp); } } return 0; } verbose = 0; while ((c = nextopt("rv")) != '\0') { if (c == 'r') { clearcmdentry(0); } else if (c == 'v') { verbose++; } } 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, 1); if (verbose) { if (entry.cmdtype != CMDUNKNOWN) { /* if no error msg */ cmdp = cmdlookup(name, 0); printentry(cmdp); } flushall(); } argptr++; } return 0;}STATIC voidprintentry(cmdp) struct tblentry *cmdp; { int index; char *path; char *name; if (cmdp->cmdtype == CMDNORMAL) { index = cmdp->param.index; path = pathval(); do { name = padvance(&path, cmdp->cmdname); stunalloc(name); } while (--index >= 0); out1str(name); } else if (cmdp->cmdtype == CMDBUILTIN) { out1fmt("builtin %s", cmdp->cmdname); } else if (cmdp->cmdtype == CMDFUNCTION) { out1fmt("function %s", cmdp->cmdname);#if DEBUG } else { error("internal error: cmdtype %d", cmdp->cmdtype);#endif } if (cmdp->rehash) out1c('*'); out1c('\n');}/* * Resolve a command name. If you change this routine, you may have to * change the shellexec routine as well. */voidfind_command(name, entry, printerr) char *name; struct cmdentry *entry; { struct tblentry *cmdp; int index; int prev; char *path; char *fullname; struct stat statb; int e; int i; /* If name contains a slash, don't use the hash table */ if (strchr(name, '/') != NULL) { entry->cmdtype = CMDNORMAL; entry->u.index = 0; return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -