|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1980 Regents of the University of California. ! 3: * All rights reserved. The Berkeley Software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: */ ! 6: ! 7: #ifndef lint ! 8: static char *sccsid = "@(#)sh.exec.c 5.2 (Berkeley) 6/6/85"; ! 9: #endif ! 10: ! 11: #include "sh.h" ! 12: #include <sys/dir.h> ! 13: ! 14: /* ! 15: * C shell ! 16: */ ! 17: ! 18: /* ! 19: * System level search and execute of a command. ! 20: * We look in each directory for the specified command name. ! 21: * If the name contains a '/' then we execute only the full path name. ! 22: * If there is no search path then we execute only full path names. ! 23: */ ! 24: ! 25: /* ! 26: * As we search for the command we note the first non-trivial error ! 27: * message for presentation to the user. This allows us often ! 28: * to show that a file has the wrong mode/no access when the file ! 29: * is not in the last component of the search path, so we must ! 30: * go on after first detecting the error. ! 31: */ ! 32: char *exerr; /* Execution error message */ ! 33: char *expath; /* Path for exerr */ ! 34: ! 35: /* ! 36: * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used ! 37: * to hash execs. If it is allocated (havhash true), then to tell ! 38: * whether ``name'' is (possibly) present in the i'th component ! 39: * of the variable path, you look at the bit in xhash indexed by ! 40: * hash(hashname("name"), i). This is setup automatically ! 41: * after .login is executed, and recomputed whenever ``path'' is ! 42: * changed. ! 43: * The two part hash function is designed to let texec() call the ! 44: * more expensive hashname() only once and the simple hash() several ! 45: * times (once for each path component checked). ! 46: * Byte size is assumed to be 8. ! 47: */ ! 48: #define HSHSIZ 8192 /* 1k bytes */ ! 49: #define HSHMASK (HSHSIZ - 1) ! 50: #define HSHMUL 243 ! 51: char xhash[HSHSIZ / 8]; ! 52: #define hash(a, b) ((a) * HSHMUL + (b) & HSHMASK) ! 53: #define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */ ! 54: #define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */ ! 55: #ifdef VFORK ! 56: int hits, misses; ! 57: #endif ! 58: ! 59: /* Dummy search path for just absolute search when no path */ ! 60: char *justabs[] = { "", 0 }; ! 61: ! 62: doexec(t) ! 63: register struct command *t; ! 64: { ! 65: char *sav; ! 66: register char *dp, **pv, **av; ! 67: register struct varent *v; ! 68: bool slash = any('/', t->t_dcom[0]); ! 69: int hashval, hashval1, i; ! 70: char *blk[2]; ! 71: ! 72: /* ! 73: * Glob the command name. If this does anything, then we ! 74: * will execute the command only relative to ".". One special ! 75: * case: if there is no PATH, then we execute only commands ! 76: * which start with '/'. ! 77: */ ! 78: dp = globone(t->t_dcom[0]); ! 79: sav = t->t_dcom[0]; ! 80: exerr = 0; expath = t->t_dcom[0] = dp; ! 81: xfree(sav); ! 82: v = adrof("path"); ! 83: if (v == 0 && expath[0] != '/') ! 84: pexerr(); ! 85: slash |= gflag; ! 86: ! 87: /* ! 88: * Glob the argument list, if necessary. ! 89: * Otherwise trim off the quote bits. ! 90: */ ! 91: gflag = 0; av = &t->t_dcom[1]; ! 92: tglob(av); ! 93: if (gflag) { ! 94: av = glob(av); ! 95: if (av == 0) ! 96: error("No match"); ! 97: } ! 98: blk[0] = t->t_dcom[0]; ! 99: blk[1] = 0; ! 100: av = blkspl(blk, av); ! 101: #ifdef VFORK ! 102: Vav = av; ! 103: #endif ! 104: trim(av); ! 105: ! 106: xechoit(av); /* Echo command if -x */ ! 107: /* ! 108: * Since all internal file descriptors are set to close on exec, ! 109: * we don't need to close them explicitly here. Just reorient ! 110: * ourselves for error messages. ! 111: */ ! 112: SHIN = 0; SHOUT = 1; SHDIAG = 2; OLDSTD = 0; ! 113: ! 114: /* ! 115: * We must do this AFTER any possible forking (like `foo` ! 116: * in glob) so that this shell can still do subprocesses. ! 117: */ ! 118: (void) sigsetmask(0); ! 119: ! 120: /* ! 121: * If no path, no words in path, or a / in the filename ! 122: * then restrict the command search. ! 123: */ ! 124: if (v == 0 || v->vec[0] == 0 || slash) ! 125: pv = justabs; ! 126: else ! 127: pv = v->vec; ! 128: sav = strspl("/", *av); /* / command name for postpending */ ! 129: #ifdef VFORK ! 130: Vsav = sav; ! 131: #endif ! 132: if (havhash) ! 133: hashval = hashname(*av); ! 134: i = 0; ! 135: #ifdef VFORK ! 136: hits++; ! 137: #endif ! 138: do { ! 139: if (!slash && pv[0][0] == '/' && havhash) { ! 140: hashval1 = hash(hashval, i); ! 141: if (!bit(xhash, hashval1)) ! 142: goto cont; ! 143: } ! 144: if (pv[0][0] == 0 || eq(pv[0], ".")) /* don't make ./xxx */ ! 145: texec(*av, av); ! 146: else { ! 147: dp = strspl(*pv, sav); ! 148: #ifdef VFORK ! 149: Vdp = dp; ! 150: #endif ! 151: texec(dp, av); ! 152: #ifdef VFORK ! 153: Vdp = 0; ! 154: #endif ! 155: xfree(dp); ! 156: } ! 157: #ifdef VFORK ! 158: misses++; ! 159: #endif ! 160: cont: ! 161: pv++; ! 162: i++; ! 163: } while (*pv); ! 164: #ifdef VFORK ! 165: hits--; ! 166: #endif ! 167: #ifdef VFORK ! 168: Vsav = 0; ! 169: Vav = 0; ! 170: #endif ! 171: xfree(sav); ! 172: xfree((char *)av); ! 173: pexerr(); ! 174: } ! 175: ! 176: pexerr() ! 177: { ! 178: ! 179: /* Couldn't find the damn thing */ ! 180: setname(expath); ! 181: /* xfree(expath); */ ! 182: if (exerr) ! 183: bferr(exerr); ! 184: bferr("Command not found"); ! 185: } ! 186: ! 187: /* ! 188: * Execute command f, arg list t. ! 189: * Record error message if not found. ! 190: * Also do shell scripts here. ! 191: */ ! 192: texec(f, t) ! 193: char *f; ! 194: register char **t; ! 195: { ! 196: register struct varent *v; ! 197: register char **vp; ! 198: extern char *sys_errlist[]; ! 199: char *lastsh[2]; ! 200: ! 201: execv(f, t); ! 202: switch (errno) { ! 203: ! 204: case ENOEXEC: ! 205: /* ! 206: * If there is an alias for shell, then ! 207: * put the words of the alias in front of the ! 208: * argument list replacing the command name. ! 209: * Note no interpretation of the words at this point. ! 210: */ ! 211: v = adrof1("shell", &aliases); ! 212: if (v == 0) { ! 213: #ifdef OTHERSH ! 214: register int ff = open(f, 0); ! 215: char ch; ! 216: #endif ! 217: ! 218: vp = lastsh; ! 219: vp[0] = adrof("shell") ? value("shell") : SHELLPATH; ! 220: vp[1] = (char *) NULL; ! 221: #ifdef OTHERSH ! 222: if (ff != -1 && read(ff, &ch, 1) == 1 && ch != '#') ! 223: vp[0] = OTHERSH; ! 224: (void) close(ff); ! 225: #endif ! 226: } else ! 227: vp = v->vec; ! 228: t[0] = f; ! 229: t = blkspl(vp, t); /* Splice up the new arglst */ ! 230: f = *t; ! 231: execv(f, t); ! 232: xfree((char *)t); ! 233: /* The sky is falling, the sky is falling! */ ! 234: ! 235: case ENOMEM: ! 236: Perror(f); ! 237: ! 238: case ENOENT: ! 239: break; ! 240: ! 241: default: ! 242: if (exerr == 0) { ! 243: exerr = sys_errlist[errno]; ! 244: expath = savestr(f); ! 245: } ! 246: } ! 247: } ! 248: ! 249: /*ARGSUSED*/ ! 250: execash(t, kp) ! 251: char **t; ! 252: register struct command *kp; ! 253: { ! 254: ! 255: rechist(); ! 256: (void) signal(SIGINT, parintr); ! 257: (void) signal(SIGQUIT, parintr); ! 258: (void) signal(SIGTERM, parterm); /* if doexec loses, screw */ ! 259: lshift(kp->t_dcom, 1); ! 260: exiterr++; ! 261: doexec(kp); ! 262: /*NOTREACHED*/ ! 263: } ! 264: ! 265: xechoit(t) ! 266: char **t; ! 267: { ! 268: ! 269: if (adrof("echo")) { ! 270: flush(); ! 271: haderr = 1; ! 272: blkpr(t), putchar('\n'); ! 273: haderr = 0; ! 274: } ! 275: } ! 276: ! 277: /*VARARGS0*//*ARGSUSED*/ ! 278: dohash(v) ! 279: char **v; ! 280: { ! 281: struct stat stb; ! 282: DIR *dirp; ! 283: register struct direct *dp; ! 284: register int cnt; ! 285: int i = 0; ! 286: struct varent *v = adrof("path"); ! 287: char **pv; ! 288: int hashval; ! 289: ! 290: havhash = 1; ! 291: for (cnt = 0; cnt < sizeof xhash; cnt++) ! 292: xhash[cnt] = 0; ! 293: if (v == 0) ! 294: return; ! 295: for (pv = v->vec; *pv; pv++, i++) { ! 296: if (pv[0][0] != '/') ! 297: continue; ! 298: dirp = opendir(*pv); ! 299: if (dirp == NULL) ! 300: continue; ! 301: if (fstat(dirp->dd_fd, &stb) < 0 || !isdir(stb)) { ! 302: closedir(dirp); ! 303: continue; ! 304: } ! 305: while ((dp = readdir(dirp)) != NULL) { ! 306: if (dp->d_ino == 0) ! 307: continue; ! 308: if (dp->d_name[0] == '.' && ! 309: (dp->d_name[1] == '\0' || ! 310: dp->d_name[1] == '.' && dp->d_name[2] == '\0')) ! 311: continue; ! 312: hashval = hash(hashname(dp->d_name), i); ! 313: bis(xhash, hashval); ! 314: } ! 315: closedir(dirp); ! 316: } ! 317: } ! 318: ! 319: dounhash() ! 320: { ! 321: ! 322: havhash = 0; ! 323: } ! 324: ! 325: #ifdef VFORK ! 326: hashstat() ! 327: { ! 328: ! 329: if (hits+misses) ! 330: printf("%d hits, %d misses, %d%%\n", ! 331: hits, misses, 100 * hits / (hits + misses)); ! 332: } ! 333: #endif ! 334: ! 335: /* ! 336: * Hash a command name. ! 337: */ ! 338: hashname(cp) ! 339: register char *cp; ! 340: { ! 341: register long h = 0; ! 342: ! 343: while (*cp) ! 344: h = hash(h, *cp++); ! 345: return ((int) h); ! 346: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.