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