|
|
1.1 ! root 1: static char *sccsid = "@(#)sh.exec.c 4.1 10/9/80"; ! 2: ! 3: #include "sh.h" ! 4: #include <ndir.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: sigsys(SIGCHLD, SIG_IGN); /* sigsys for vforks sake */ ! 97: ! 98: /* ! 99: * If no path, no words in path, or a / in the filename ! 100: * then restrict the command search. ! 101: */ ! 102: if (v == 0 || v->vec[0] == 0 || slash) ! 103: pv = justabs; ! 104: else ! 105: pv = v->vec; ! 106: sav = strspl("/", *av); /* / command name for postpending */ ! 107: #ifdef VFORK ! 108: Vsav = sav; ! 109: #endif ! 110: if (havhash) ! 111: hashval = xhash[hash(*av)]; ! 112: i = 0; ! 113: #ifdef VFORK ! 114: hits++; ! 115: #endif ! 116: do { ! 117: if (!slash && pv[0][0] == '/' && havhash && (hashval & (1 << (i % 8))) == 0) ! 118: goto cont; ! 119: if (pv[0][0] == 0 || eq(pv[0], ".")) /* don't make ./xxx */ ! 120: texec(*av, av); ! 121: else { ! 122: dp = strspl(*pv, sav); ! 123: #ifdef VFORK ! 124: Vdp = dp; ! 125: #endif ! 126: texec(dp, av); ! 127: #ifdef VFORK ! 128: Vdp = 0; ! 129: #endif ! 130: xfree(dp); ! 131: } ! 132: #ifdef VFORK ! 133: misses++; ! 134: #endif ! 135: cont: ! 136: pv++; ! 137: i++; ! 138: } while (*pv); ! 139: #ifdef VFORK ! 140: hits--; ! 141: #endif ! 142: #ifdef VFORK ! 143: Vsav = 0; ! 144: Vav = 0; ! 145: #endif ! 146: xfree(sav); ! 147: xfree(av); ! 148: pexerr(); ! 149: } ! 150: ! 151: pexerr() ! 152: { ! 153: ! 154: /* Couldn't find the damn thing */ ! 155: setname(expath); ! 156: /* xfree(expath); */ ! 157: if (exerr) ! 158: bferr(exerr); ! 159: bferr("Command not found"); ! 160: } ! 161: ! 162: /* Last resort shell */ ! 163: char *lastsh[] = { SHELLPATH, 0 }; ! 164: ! 165: /* ! 166: * Execute command f, arg list t. ! 167: * Record error message if not found. ! 168: * Also do shell scripts here. ! 169: */ ! 170: texec(f, t) ! 171: char *f; ! 172: register char **t; ! 173: { ! 174: register struct varent *v; ! 175: register char **vp; ! 176: extern char *sys_errlist[]; ! 177: ! 178: execv(f, t); ! 179: switch (errno) { ! 180: ! 181: case ENOEXEC: ! 182: /* ! 183: * If there is an alias for shell, then ! 184: * put the words of the alias in front of the ! 185: * argument list replacing the command name. ! 186: * Note no interpretation of the words at this point. ! 187: */ ! 188: v = adrof1("shell", &aliases); ! 189: if (v == 0) { ! 190: #ifdef OTHERSH ! 191: register int ff = open(f, 0); ! 192: char ch; ! 193: #endif ! 194: ! 195: vp = lastsh; ! 196: vp[0] = adrof("shell") ? value("shell") : SHELLPATH; ! 197: #ifdef OTHERSH ! 198: if (ff != -1 && read(ff, &ch, 1) == 1 && ch != '#') ! 199: vp[0] = OTHERSH; ! 200: close(ff); ! 201: #endif ! 202: } else ! 203: vp = v->vec; ! 204: t[0] = f; ! 205: t = blkspl(vp, t); /* Splice up the new arglst */ ! 206: f = *t; ! 207: execv(f, t); ! 208: xfree((char *)t); ! 209: /* The sky is falling, the sky is falling! */ ! 210: ! 211: case ENOMEM: ! 212: Perror(f); ! 213: ! 214: case ENOENT: ! 215: break; ! 216: ! 217: default: ! 218: if (exerr == 0) { ! 219: exerr = sys_errlist[errno]; ! 220: expath = savestr(f); ! 221: } ! 222: } ! 223: } ! 224: ! 225: execash(t, kp) ! 226: register struct command *kp; ! 227: { ! 228: ! 229: didcch++; ! 230: signal(SIGINT, parintr); ! 231: signal(SIGQUIT, parintr); ! 232: signal(SIGTERM, parterm); /* if doexec loses, screw */ ! 233: lshift(kp->t_dcom, 1); ! 234: exiterr++; ! 235: doexec(kp); ! 236: /*NOTREACHED*/ ! 237: } ! 238: ! 239: xechoit(t) ! 240: char **t; ! 241: { ! 242: ! 243: if (adrof("echo")) { ! 244: flush(); ! 245: haderr = 1; ! 246: blkpr(t), printf("\n"); ! 247: haderr = 0; ! 248: } ! 249: } ! 250: ! 251: dohash() ! 252: { ! 253: struct stat stb; ! 254: register struct direct *dp; ! 255: DIR *df; ! 256: int i = 0; ! 257: register int cnt; ! 258: struct varent *v = adrof("path"); ! 259: register char **pv; ! 260: ! 261: havhash = 1; ! 262: for (cnt = 0; cnt < HSHSIZ; cnt++) ! 263: xhash[cnt] = 0; ! 264: if (v == 0) ! 265: return; ! 266: for (pv = v->vec; *pv; pv++, i = (i + 1) % 8) { ! 267: if (pv[0][0] != '/') ! 268: continue; ! 269: df = opendir(*pv); ! 270: if (df == 0) ! 271: continue; ! 272: if (stat(*pv, &stb) < 0 || !isdir(stb)) { ! 273: closedir(df); ! 274: continue; ! 275: } ! 276: while ((dp = readdir(df)) != 0) { ! 277: if (dp->d_ino == 0) ! 278: continue; ! 279: xhash[hash(dp->d_name)] |= (1 << i); ! 280: } ! 281: closedir(df); ! 282: } ! 283: } ! 284: ! 285: dounhash() ! 286: { ! 287: ! 288: havhash = 0; ! 289: } ! 290: ! 291: #ifdef VFORK ! 292: hashstat() ! 293: { ! 294: ! 295: if (hits+misses) ! 296: printf("%d hits, %d misses, %2d%%\n", hits, misses, 100 * hits / (hits + misses)); ! 297: } ! 298: #endif ! 299: ! 300: hash(cp) ! 301: register char *cp; ! 302: { ! 303: register long hash = 0; ! 304: int retval; ! 305: ! 306: while (*cp) ! 307: hash += hash + *cp++; ! 308: if (hash < 0) ! 309: hash = -hash; ! 310: retval = hash % HSHSIZ; ! 311: return (retval); ! 312: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.