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