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