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

Defined functions

doexec defined in line 62; used 2 times
dounhash defined in line 319; used 2 times
execash defined in line 250; used 2 times
hashname defined in line 338; used 2 times
hashstat defined in line 326; used 2 times
pexerr defined in line 176; used 2 times
texec defined in line 192; used 2 times
xechoit defined in line 265; used 2 times

Defined variables

exerr defined in line 32; used 5 times
expath defined in line 33; used 4 times
hits defined in line 56; used 6 times
justabs defined in line 60; used 1 times
misses defined in line 56; used 4 times
sccsid defined in line 8; never used
xhash defined in line 51; used 4 times

Defined macros

HSHMASK defined in line 49; used 1 times
  • in line 52
HSHMUL defined in line 50; used 1 times
  • in line 52
HSHSIZ defined in line 48; used 2 times
bis defined in line 54; used 1 times
bit defined in line 53; used 1 times
hash defined in line 52; used 3 times
Last modified: 1985-06-06
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1393
Valid CSS Valid XHTML 1.0 Strict