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