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: }