1*47738Sbostic /*- 2*47738Sbostic * Copyright (c) 1980 The Regents of the University of California. 3*47738Sbostic * All rights reserved. 4*47738Sbostic * 5*47738Sbostic * %sccs.include.redist.c% 621930Sdist */ 721930Sdist 817508Sedward #ifndef lint 9*47738Sbostic static char sccsid[] = "@(#)exec.c 5.10 (Berkeley) 04/02/91"; 10*47738Sbostic #endif /* not lint */ 111292Sbill 121292Sbill #include "sh.h" 1313560Ssam #include <sys/dir.h> 1442406Sbostic #include <string.h> 1537251Sbostic #include "pathnames.h" 161292Sbill 171292Sbill /* 181292Sbill * C shell 191292Sbill */ 201292Sbill 211292Sbill /* 221292Sbill * System level search and execute of a command. 231292Sbill * We look in each directory for the specified command name. 241292Sbill * If the name contains a '/' then we execute only the full path name. 251292Sbill * If there is no search path then we execute only full path names. 261292Sbill */ 271292Sbill 281292Sbill /* 291292Sbill * As we search for the command we note the first non-trivial error 301292Sbill * message for presentation to the user. This allows us often 311292Sbill * to show that a file has the wrong mode/no access when the file 321292Sbill * is not in the last component of the search path, so we must 331292Sbill * go on after first detecting the error. 341292Sbill */ 351292Sbill char *exerr; /* Execution error message */ 361292Sbill char *expath; /* Path for exerr */ 371292Sbill 381292Sbill /* 3917508Sedward * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used 4017508Sedward * to hash execs. If it is allocated (havhash true), then to tell 4117508Sedward * whether ``name'' is (possibly) present in the i'th component 4217508Sedward * of the variable path, you look at the bit in xhash indexed by 4317508Sedward * hash(hashname("name"), i). This is setup automatically 441292Sbill * after .login is executed, and recomputed whenever ``path'' is 451292Sbill * changed. 4617508Sedward * The two part hash function is designed to let texec() call the 4717508Sedward * more expensive hashname() only once and the simple hash() several 4817508Sedward * times (once for each path component checked). 4917508Sedward * Byte size is assumed to be 8. 501292Sbill */ 5117508Sedward #define HSHSIZ 8192 /* 1k bytes */ 5217508Sedward #define HSHMASK (HSHSIZ - 1) 5317508Sedward #define HSHMUL 243 5417508Sedward char xhash[HSHSIZ / 8]; 5517508Sedward #define hash(a, b) ((a) * HSHMUL + (b) & HSHMASK) 5617508Sedward #define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */ 5717508Sedward #define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */ 581292Sbill #ifdef VFORK 591292Sbill int hits, misses; 601292Sbill #endif 611292Sbill 621292Sbill /* Dummy search path for just absolute search when no path */ 631292Sbill char *justabs[] = { "", 0 }; 641292Sbill 651292Sbill doexec(t) 661292Sbill register struct command *t; 671292Sbill { 681292Sbill char *sav; 691292Sbill register char *dp, **pv, **av; 701292Sbill register struct varent *v; 7147408Sbostic bool slash = (bool)index(t->t_dcom[0], '/'); 7217508Sedward int hashval, hashval1, i; 731292Sbill char *blk[2]; 741292Sbill 751292Sbill /* 761292Sbill * Glob the command name. If this does anything, then we 771292Sbill * will execute the command only relative to ".". One special 781292Sbill * case: if there is no PATH, then we execute only commands 791292Sbill * which start with '/'. 801292Sbill */ 811292Sbill dp = globone(t->t_dcom[0]); 821292Sbill sav = t->t_dcom[0]; 831292Sbill exerr = 0; expath = t->t_dcom[0] = dp; 841292Sbill xfree(sav); 851292Sbill v = adrof("path"); 861292Sbill if (v == 0 && expath[0] != '/') 871292Sbill pexerr(); 881292Sbill slash |= gflag; 891292Sbill 901292Sbill /* 911292Sbill * Glob the argument list, if necessary. 921292Sbill * Otherwise trim off the quote bits. 931292Sbill */ 941292Sbill gflag = 0; av = &t->t_dcom[1]; 9517508Sedward tglob(av); 961292Sbill if (gflag) { 9747408Sbostic av = globall(av); 981292Sbill if (av == 0) 991292Sbill error("No match"); 1001292Sbill } 1011292Sbill blk[0] = t->t_dcom[0]; 1021292Sbill blk[1] = 0; 1031292Sbill av = blkspl(blk, av); 1041292Sbill #ifdef VFORK 1051292Sbill Vav = av; 1061292Sbill #endif 10717508Sedward trim(av); 1081292Sbill 1091292Sbill xechoit(av); /* Echo command if -x */ 11017508Sedward /* 11117508Sedward * Since all internal file descriptors are set to close on exec, 11217508Sedward * we don't need to close them explicitly here. Just reorient 11317508Sedward * ourselves for error messages. 11417508Sedward */ 11517508Sedward SHIN = 0; SHOUT = 1; SHDIAG = 2; OLDSTD = 0; 1161292Sbill 1171292Sbill /* 11812996Ssam * We must do this AFTER any possible forking (like `foo` 1191292Sbill * in glob) so that this shell can still do subprocesses. 1201292Sbill */ 12131685Sbostic (void) sigsetmask(0L); 1221292Sbill 1231292Sbill /* 1241292Sbill * If no path, no words in path, or a / in the filename 1251292Sbill * then restrict the command search. 1261292Sbill */ 1271292Sbill if (v == 0 || v->vec[0] == 0 || slash) 1281292Sbill pv = justabs; 1291292Sbill else 1301292Sbill pv = v->vec; 1311292Sbill sav = strspl("/", *av); /* / command name for postpending */ 1321292Sbill #ifdef VFORK 1331292Sbill Vsav = sav; 1341292Sbill #endif 1351292Sbill if (havhash) 13617508Sedward hashval = hashname(*av); 1371292Sbill i = 0; 1381292Sbill #ifdef VFORK 1391292Sbill hits++; 1401292Sbill #endif 1411292Sbill do { 14217508Sedward if (!slash && pv[0][0] == '/' && havhash) { 14317508Sedward hashval1 = hash(hashval, i); 14417508Sedward if (!bit(xhash, hashval1)) 14517508Sedward goto cont; 14617508Sedward } 1471292Sbill if (pv[0][0] == 0 || eq(pv[0], ".")) /* don't make ./xxx */ 1481292Sbill texec(*av, av); 1491292Sbill else { 1501292Sbill dp = strspl(*pv, sav); 1511292Sbill #ifdef VFORK 1521292Sbill Vdp = dp; 1531292Sbill #endif 1541292Sbill texec(dp, av); 1551292Sbill #ifdef VFORK 1561292Sbill Vdp = 0; 1571292Sbill #endif 1581292Sbill xfree(dp); 1591292Sbill } 1601292Sbill #ifdef VFORK 1611292Sbill misses++; 1621292Sbill #endif 1631292Sbill cont: 1641292Sbill pv++; 1651292Sbill i++; 1661292Sbill } while (*pv); 1671292Sbill #ifdef VFORK 1681292Sbill hits--; 1691292Sbill #endif 1701292Sbill #ifdef VFORK 1711292Sbill Vsav = 0; 1721292Sbill Vav = 0; 1731292Sbill #endif 1741292Sbill xfree(sav); 17517508Sedward xfree((char *)av); 1761292Sbill pexerr(); 1771292Sbill } 1781292Sbill 1791292Sbill pexerr() 1801292Sbill { 1811292Sbill 1821292Sbill /* Couldn't find the damn thing */ 1831292Sbill setname(expath); 1841292Sbill /* xfree(expath); */ 1851292Sbill if (exerr) 1861292Sbill bferr(exerr); 1871292Sbill bferr("Command not found"); 1881292Sbill } 1891292Sbill 1901292Sbill /* 1911292Sbill * Execute command f, arg list t. 1921292Sbill * Record error message if not found. 1931292Sbill * Also do shell scripts here. 1941292Sbill */ 1951292Sbill texec(f, t) 1961292Sbill char *f; 1971292Sbill register char **t; 1981292Sbill { 1991292Sbill register struct varent *v; 2001292Sbill register char **vp; 20117508Sedward char *lastsh[2]; 2021292Sbill 2031292Sbill execv(f, t); 2041292Sbill switch (errno) { 2051292Sbill 2061292Sbill case ENOEXEC: 2071292Sbill /* 2081292Sbill * If there is an alias for shell, then 2091292Sbill * put the words of the alias in front of the 2101292Sbill * argument list replacing the command name. 2111292Sbill * Note no interpretation of the words at this point. 2121292Sbill */ 2131292Sbill v = adrof1("shell", &aliases); 2141292Sbill if (v == 0) { 2151292Sbill register int ff = open(f, 0); 2161292Sbill char ch; 2171292Sbill 2181292Sbill vp = lastsh; 21936786Sbostic vp[0] = adrof("shell") ? value("shell") : _PATH_CSHELL; 22018131Skarels vp[1] = (char *) NULL; 2211292Sbill if (ff != -1 && read(ff, &ch, 1) == 1 && ch != '#') 22236786Sbostic vp[0] = _PATH_BSHELL; 22317508Sedward (void) close(ff); 2241292Sbill } else 2251292Sbill vp = v->vec; 2261292Sbill t[0] = f; 2271292Sbill t = blkspl(vp, t); /* Splice up the new arglst */ 2281292Sbill f = *t; 2291292Sbill execv(f, t); 2301292Sbill xfree((char *)t); 2311292Sbill /* The sky is falling, the sky is falling! */ 2321292Sbill 2331292Sbill case ENOMEM: 2341292Sbill Perror(f); 2351292Sbill 2361292Sbill case ENOENT: 2371292Sbill break; 2381292Sbill 2391292Sbill default: 2401292Sbill if (exerr == 0) { 24142406Sbostic exerr = strerror(errno); 2421292Sbill expath = savestr(f); 2431292Sbill } 2441292Sbill } 2451292Sbill } 2461292Sbill 24717508Sedward /*ARGSUSED*/ 2481292Sbill execash(t, kp) 24917508Sedward char **t; 2501292Sbill register struct command *kp; 2511292Sbill { 2521292Sbill 2534188Smckusic rechist(); 25417508Sedward (void) signal(SIGINT, parintr); 25517508Sedward (void) signal(SIGQUIT, parintr); 25617508Sedward (void) signal(SIGTERM, parterm); /* if doexec loses, screw */ 2571292Sbill lshift(kp->t_dcom, 1); 2581292Sbill exiterr++; 2591292Sbill doexec(kp); 2601292Sbill /*NOTREACHED*/ 2611292Sbill } 2621292Sbill 2631292Sbill xechoit(t) 2641292Sbill char **t; 2651292Sbill { 2661292Sbill 2671292Sbill if (adrof("echo")) { 2681292Sbill flush(); 2691292Sbill haderr = 1; 27034340Sbostic blkpr(t), cshputchar('\n'); 2711292Sbill haderr = 0; 2721292Sbill } 2731292Sbill } 2741292Sbill 27517508Sedward /*VARARGS0*//*ARGSUSED*/ 27631685Sbostic dohash() 2771292Sbill { 2781292Sbill struct stat stb; 2795774Smckusic DIR *dirp; 2805774Smckusic register struct direct *dp; 2815774Smckusic register int cnt; 2821292Sbill int i = 0; 2831292Sbill struct varent *v = adrof("path"); 2841292Sbill char **pv; 28517508Sedward int hashval; 2861292Sbill 2871292Sbill havhash = 1; 28817508Sedward for (cnt = 0; cnt < sizeof xhash; cnt++) 2891292Sbill xhash[cnt] = 0; 2901292Sbill if (v == 0) 2911292Sbill return; 29217508Sedward for (pv = v->vec; *pv; pv++, i++) { 2931292Sbill if (pv[0][0] != '/') 2941292Sbill continue; 2955774Smckusic dirp = opendir(*pv); 2965774Smckusic if (dirp == NULL) 2971292Sbill continue; 29847724Sbostic if (fstat(dirp->dd_fd, &stb) < 0 || !S_ISDIR(stb.st_mode)) { 2995774Smckusic closedir(dirp); 3001292Sbill continue; 3011292Sbill } 3025774Smckusic while ((dp = readdir(dirp)) != NULL) { 3035774Smckusic if (dp->d_ino == 0) 3045774Smckusic continue; 30517508Sedward if (dp->d_name[0] == '.' && 30617508Sedward (dp->d_name[1] == '\0' || 30717508Sedward dp->d_name[1] == '.' && dp->d_name[2] == '\0')) 30817508Sedward continue; 30917508Sedward hashval = hash(hashname(dp->d_name), i); 31017508Sedward bis(xhash, hashval); 3111292Sbill } 3125774Smckusic closedir(dirp); 3131292Sbill } 3141292Sbill } 3151292Sbill 3161292Sbill dounhash() 3171292Sbill { 3181292Sbill 3191292Sbill havhash = 0; 3201292Sbill } 3211292Sbill 3221292Sbill #ifdef VFORK 3231292Sbill hashstat() 3241292Sbill { 3251292Sbill 3261292Sbill if (hits+misses) 32717508Sedward printf("%d hits, %d misses, %d%%\n", 32817508Sedward hits, misses, 100 * hits / (hits + misses)); 3291292Sbill } 3301292Sbill #endif 3311292Sbill 33217508Sedward /* 33317508Sedward * Hash a command name. 33417508Sedward */ 33517508Sedward hashname(cp) 3361292Sbill register char *cp; 3371292Sbill { 33817508Sedward register long h = 0; 3391292Sbill 3401292Sbill while (*cp) 34117508Sedward h = hash(h, *cp++); 34217508Sedward return ((int) h); 3431292Sbill } 344