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