sh.exec.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 432 行
C
432 行
#ifndef lintstatic char *sccsid = "@(#)sh.exec.c 4.4 (ULTRIX) 9/11/90";#endif/************************************************************************ * * * Copyright (c) 1988 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//* ------------------------------------------------------------------ *//* | Copyright Unpublished, MIPS Computer Systems, Inc. All Rights | *//* | Reserved. This software contains proprietary and confidential | *//* | information of MIPS and its suppliers. Use, disclosure or | *//* | reproduction is prohibited without the prior express written | *//* | consent of MIPS. | *//* ------------------------------------------------------------------ *//* $Header: sh.exec.c,v 1.9 87/02/27 11:38:43 dce Exp $ *//* * Modification History * * 001 - Gary A. Gaudet - Mon Nov 13 15:58:10 EST 1989 * changed char xhash[] to unsigned char. * changed to allow 8-bit characters in shell script. * * 002 - Bob Fontaine - Fri Aug 10 09:23:30 EDT 1990 * Changed call to internal printf routine to csh_printf to avoid * conflicts with stdio library routine of the same name. * * 003 - Bob Fontaine - Thu Aug 23 14:27:15 EDT 1990 * Before we check to see if the file is a cross compiled binary, * stat the file and if 0 length don't bother opening and reading. * This only slows down execution time; commands like /bin/true take * a long time to execute. Fixes QAR # 637. */#include "sh.h"#include <sys/dir.h>/* * C shell *//* * System level search and execute of a command. * We look in each directory for the specified command name. * If the name contains a '/' then we execute only the full path name. * If there is no search path then we execute only full path names. *//* * As we search for the command we note the first non-trivial error * message for presentation to the user. This allows us often * to show that a file has the wrong mode/no access when the file * is not in the last component of the search path, so we must * go on after first detecting the error. */char *exerr; /* Execution error message */char *expath; /* Path for exerr *//* * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used * to hash execs. If it is allocated (havhash true), then to tell * whether ``name'' is (possibly) present in the i'th component * of the variable path, you look at the bit in xhash indexed by * hash(hashname("name"), i). This is setup automatically * after .login is executed, and recomputed whenever ``path'' is * changed. * The two part hash function is designed to let texec() call the * more expensive hashname() only once and the simple hash() several * times (once for each path component checked). * Byte size is assumed to be 8. */#define HSHSIZ 8192 /* 1k bytes */#define HSHMASK (HSHSIZ - 1)#define HSHMUL 243unsigned char xhash[HSHSIZ / 8]; /* 001 - GAG */#define hash(a, b) ((a) * HSHMUL + (b) & HSHMASK)#define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */#define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */#ifdef VFORKint hits, misses;#endif/* Dummy search path for just absolute search when no path */char *justabs[] = { "", 0 };doexec(t) register struct command *t;{ char *sav; register char *dp, **pv, **av; register struct varent *v; bool slash = any('/', t->t_dcom[0]); int hashval, hashval1, i; char *blk[2]; /* * Glob the command name. If this does anything, then we * will execute the command only relative to ".". One special * case: if there is no PATH, then we execute only commands * which start with '/'. */ dp = globone(t->t_dcom[0]); sav = t->t_dcom[0]; exerr = 0; expath = t->t_dcom[0] = dp; xfree(sav); v = adrof("path"); if (v == 0 && expath[0] != '/') pexerr(); slash |= gflag; /* * Glob the argument list, if necessary. * Otherwise trim off the quote bits. */ gflag = 0; av = &t->t_dcom[1]; tglob(av); if (gflag) { av = glob(av); if (av == 0) error("No match"); } blk[0] = t->t_dcom[0]; blk[1] = 0; av = blkspl(blk, av);#ifdef VFORK Vav = av;#endif trim(av); xechoit(av); /* Echo command if -x */ /* * Since all internal file descriptors are set to close on exec, * we don't need to close them explicitly here. Just reorient * ourselves for error messages. */ SHIN = 0; SHOUT = 1; SHDIAG = 2; OLDSTD = 0;#ifndef BSD4_3 /* * In non-4.3 systems, we don't close on exec yet. */ { int i; for (i = 3; i < NOFILE; i++) { (void) close(i); } }#endif /* * We must do this AFTER any possible forking (like `foo` * in glob) so that this shell can still do subprocesses. */ (void) sigsetmask(0); /* * If no path, no words in path, or a / in the filename * then restrict the command search. */ if (v == 0 || v->vec[0] == 0 || slash) pv = justabs; else pv = v->vec; sav = strspl("/", *av); /* / command name for postpending */#ifdef VFORK Vsav = sav;#endif if (havhash) hashval = hashname(*av); i = 0;#ifdef VFORK hits++;#endif do { if (!slash && pv[0][0] == '/' && havhash) { hashval1 = hash(hashval, i); if (!bit(xhash, hashval1)) goto cont; } if (pv[0][0] == 0 || eq(pv[0], ".")) /* don't make ./xxx */ texec(*av, av); else { dp = strspl(*pv, sav);#ifdef VFORK Vdp = dp;#endif texec(dp, av);#ifdef VFORK Vdp = 0;#endif xfree(dp); }#ifdef VFORK misses++;#endifcont: pv++; i++; } while (*pv);#ifdef VFORK hits--;#endif#ifdef VFORK Vsav = 0; Vav = 0;#endif xfree(sav); xfree((char *)av); pexerr();}pexerr(){ /* Couldn't find the damn thing */ setname(expath); /* xfree(expath); */ if (exerr) bferr(exerr); bferr("Command not found");}/* * Execute command f, arg list t. * Record error message if not found. * Also do shell scripts here. */texec(f, t) char *f; register char **t;{ register struct varent *v; register char **vp; extern char *sys_errlist[]; char *lastsh[2]; int fd; /* File descriptor */ char buf[32]; /* Buffer for file data */ int i; /* For looking thru buf */ int skip; /* Flag for skipping file */ struct stat stb; /* 003 */ execv(f, t); switch (errno) { case ENOEXEC: /* * First, read the first 32 characters of the file to * look for null characters. If any are found, this is * probably a cross-compiled binary or a mistake, and * we don't want to execute it. */ if ((fd = open(f, 0)) >= 0) { skip = 0; fstat(fd,&stb); i = 0; if(stb.st_size > 0) /* 003 */ i = read(fd, buf, sizeof(buf)) - 1; (void) close(fd); while (i >= 0) { if (buf[i] == '\0') { /* 001 - GAG */ skip = 1; break; } i--; } if (skip) { exerr = "Non-ASCII shell script (may be cross-compiler object)"; expath = savestr(f); break; } } /* * If there is an alias for shell, then * put the words of the alias in front of the * argument list replacing the command name. * Note no interpretation of the words at this point. */ v = adrof1("shell", &aliases); if (v == 0) {#ifdef OTHERSH register int ff = open(f, 0); char ch;#endif vp = lastsh; vp[0] = adrof("shell") ? value("shell") : SHELLPATH; vp[1] = (char *) NULL;#ifdef OTHERSH if (ff != -1 && read(ff, &ch, 1) == 1 && ch != '#') vp[0] = OTHERSH; (void) close(ff);#endif } else vp = v->vec; t[0] = f; t = blkspl(vp, t); /* Splice up the new arglst */ f = *t; execv(f, t); xfree((char *)t); /* The sky is falling, the sky is falling! */ case ENOMEM: Perror(f); case ENOENT: break; default: if (exerr == 0) { exerr = sys_errlist[errno]; expath = savestr(f); } }}/*ARGSUSED*/execash(t, kp) char **t; register struct command *kp;{ rechist(); (void) signal(SIGINT, parintr); (void) signal(SIGQUIT, parintr); (void) signal(SIGTERM, parterm); /* if doexec loses, screw */ lshift(kp->t_dcom, 1); exiterr++; doexec(kp); /*NOTREACHED*/}xechoit(t) char **t;{ if (adrof("echo")) { flush(); haderr = 1; blkpr(t), putchar('\n'); haderr = 0; }}/*VARARGS0*//*ARGSUSED*/dohash(vv) char **vv;{ struct stat stb; DIR *dirp; register struct direct *dp; register int cnt; int i = 0; struct varent *v = adrof("path"); char **pv; int hashval; havhash = 1; for (cnt = 0; cnt < sizeof xhash; cnt++) xhash[cnt] = 0; if (v == 0) return; for (pv = v->vec; *pv; pv++, i++) { if (pv[0][0] != '/') continue; dirp = opendir(*pv); if (dirp == NULL) continue; if (fstat(dirp->dd_fd, &stb) < 0 || !isdir(stb)) { closedir(dirp); continue; } while ((dp = readdir(dirp)) != NULL) { if (dp->d_ino == 0) continue; if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || dp->d_name[1] == '.' && dp->d_name[2] == '\0')) continue; hashval = hash(hashname(dp->d_name), i); bis(xhash, hashval); } closedir(dirp); }}dounhash(){ havhash = 0;}#ifdef VFORKhashstat(){ if (hits+misses) csh_printf("%d hits, %d misses, %d%%\n", hits, misses, 100 * hits / (hits + misses));}#endif/* * Hash a command name. */hashname(cp) register char *cp;{ register long h = 0; while (*cp) h = hash(h, *cp++); return ((int) h);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?