147738Sbostic /*- 247823Sbostic * Copyright (c) 1980, 1991 The Regents of the University of California. 347738Sbostic * All rights reserved. 447738Sbostic * 547738Sbostic * %sccs.include.redist.c% 621930Sdist */ 721930Sdist 817508Sedward #ifndef lint 9*50028Sbostic static char sccsid[] = "@(#)exec.c 5.15 (Berkeley) 06/08/91"; 1047738Sbostic #endif /* not lint */ 111292Sbill 12*50028Sbostic #include <sys/types.h> 13*50028Sbostic #include <dirent.h> 14*50028Sbostic #include <fcntl.h> 15*50028Sbostic #include <errno.h> 16*50028Sbostic #include <stdlib.h> 17*50028Sbostic #include <string.h> 18*50028Sbostic #include <unistd.h> 1950023Sbostic #include "csh.h" 2050023Sbostic #include "extern.h" 211292Sbill 221292Sbill /* 23*50028Sbostic * System level search and execute of a command. We look in each directory 24*50028Sbostic * for the specified command name. If the name contains a '/' then we 25*50028Sbostic * execute only the full path name. If there is no search path then we 26*50028Sbostic * execute only full path names. 271292Sbill */ 281292Sbill 2949992Sbostic /* 301292Sbill * As we search for the command we note the first non-trivial error 311292Sbill * message for presentation to the user. This allows us often 321292Sbill * to show that a file has the wrong mode/no access when the file 331292Sbill * is not in the last component of the search path, so we must 341292Sbill * go on after first detecting the error. 351292Sbill */ 3649992Sbostic static char *exerr; /* Execution error message */ 3749992Sbostic static Char *expath; /* Path for exerr */ 381292Sbill 391292Sbill /* 4017508Sedward * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used 4117508Sedward * to hash execs. If it is allocated (havhash true), then to tell 4217508Sedward * whether ``name'' is (possibly) present in the i'th component 4317508Sedward * of the variable path, you look at the bit in xhash indexed by 4417508Sedward * hash(hashname("name"), i). This is setup automatically 451292Sbill * after .login is executed, and recomputed whenever ``path'' is 461292Sbill * changed. 4717508Sedward * The two part hash function is designed to let texec() call the 4817508Sedward * more expensive hashname() only once and the simple hash() several 4917508Sedward * times (once for each path component checked). 5017508Sedward * Byte size is assumed to be 8. 511292Sbill */ 5249992Sbostic #define HSHSIZ 8192 /* 1k bytes */ 5317508Sedward #define HSHMASK (HSHSIZ - 1) 5417508Sedward #define HSHMUL 243 5549992Sbostic static char xhash[HSHSIZ / 8]; 5649992Sbostic 5717508Sedward #define hash(a, b) ((a) * HSHMUL + (b) & HSHMASK) 5817508Sedward #define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */ 5917508Sedward #define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */ 6049992Sbostic static int hits, misses; 6149992Sbostic 621292Sbill /* Dummy search path for just absolute search when no path */ 6349992Sbostic static Char *justabs[] = {STRNULL, 0}; 641292Sbill 6550024Schristos static void pexerr __P((void)); 6650024Schristos static void texec __P((Char *, Char **)); 6750024Schristos static int hashname __P((Char *)); 6849992Sbostic 6949992Sbostic void 701292Sbill doexec(t) 7149992Sbostic register struct command *t; 721292Sbill { 7349992Sbostic register Char *dp, **pv, **av, *sav; 7449992Sbostic register struct varent *v; 7549992Sbostic register bool slash; 7649992Sbostic register int hashval = 0, hashval1, i; 7749992Sbostic Char *blk[2]; 781292Sbill 7949992Sbostic /* 8049992Sbostic * Glob the command name. We will search $path even if this does something, 8149992Sbostic * as in sh but not in csh. One special case: if there is no PATH, then we 8249992Sbostic * execute only commands which start with '/'. 8349992Sbostic */ 8449992Sbostic blk[0] = t->t_dcom[0]; 8549992Sbostic blk[1] = 0; 8649992Sbostic gflag = 0, tglob(blk); 8749992Sbostic if (gflag) { 8849992Sbostic pv = globall(blk); 8949992Sbostic if (pv == 0) { 9049992Sbostic setname(short2str(blk[0])); 9149992Sbostic stderror(ERR_NAME | ERR_NOMATCH); 9249992Sbostic } 9349992Sbostic gargv = 0; 9449992Sbostic } 9549992Sbostic else 9649992Sbostic pv = saveblk(blk); 971292Sbill 9849992Sbostic trim(pv); 9949992Sbostic 10049992Sbostic exerr = 0; 10149992Sbostic expath = Strsave(pv[0]); 10249992Sbostic Vexpath = expath; 1031292Sbill 10449992Sbostic v = adrof(STRpath); 10549992Sbostic if (v == 0 && expath[0] != '/') { 10649992Sbostic blkfree(pv); 10749992Sbostic pexerr(); 10849992Sbostic } 10949992Sbostic slash = any(short2str(expath), '/'); 1101292Sbill 11149992Sbostic /* 11249992Sbostic * Glob the argument list, if necessary. Otherwise trim off the quote bits. 11349992Sbostic */ 11449992Sbostic gflag = 0; 11549992Sbostic av = &t->t_dcom[1]; 11649992Sbostic tglob(av); 11749992Sbostic if (gflag) { 11849992Sbostic av = globall(av); 11949992Sbostic if (av == 0) { 12049992Sbostic blkfree(pv); 12149992Sbostic setname(short2str(expath)); 12249992Sbostic stderror(ERR_NAME | ERR_NOMATCH); 12349992Sbostic } 12449992Sbostic gargv = 0; 12549992Sbostic } 12649992Sbostic else 12749992Sbostic av = saveblk(av); 1281292Sbill 12949992Sbostic blkfree(t->t_dcom); 13049992Sbostic t->t_dcom = blkspl(pv, av); 13149992Sbostic xfree((ptr_t) pv); 13249992Sbostic xfree((ptr_t) av); 13349992Sbostic av = t->t_dcom; 13449992Sbostic trim(av); 13549992Sbostic 13650024Schristos if (*av == NULL || **av == '\0') 13749992Sbostic pexerr(); 13849992Sbostic 13949992Sbostic xechoit(av); /* Echo command if -x */ 14049992Sbostic /* 14149992Sbostic * Since all internal file descriptors are set to close on exec, we don't 14249992Sbostic * need to close them explicitly here. Just reorient ourselves for error 14349992Sbostic * messages. 14449992Sbostic */ 14549992Sbostic SHIN = 0; 14649992Sbostic SHOUT = 1; 14749992Sbostic SHDIAG = 2; 14849992Sbostic OLDSTD = 0; 14949992Sbostic /* 15049992Sbostic * We must do this AFTER any possible forking (like `foo` in glob) so that 15149992Sbostic * this shell can still do subprocesses. 15249992Sbostic */ 153*50028Sbostic (void) sigsetmask((sigset_t) 0); 15449992Sbostic /* 15549992Sbostic * If no path, no words in path, or a / in the filename then restrict the 15649992Sbostic * command search. 15749992Sbostic */ 15849992Sbostic if (v == 0 || v->vec[0] == 0 || slash) 15949992Sbostic pv = justabs; 16049992Sbostic else 16149992Sbostic pv = v->vec; 16249992Sbostic sav = Strspl(STRslash, *av);/* / command name for postpending */ 16349992Sbostic Vsav = sav; 16449992Sbostic if (havhash) 16549992Sbostic hashval = hashname(*av); 16649992Sbostic i = 0; 16749992Sbostic hits++; 16849992Sbostic do { 16949992Sbostic /* 17049992Sbostic * Try to save time by looking at the hash table for where this command 17149992Sbostic * could be. If we are doing delayed hashing, then we put the names in 17249992Sbostic * one at a time, as the user enters them. This is kinda like Korn 17349992Sbostic * Shell's "tracked aliases". 17449992Sbostic */ 17549992Sbostic if (!slash && pv[0][0] == '/' && havhash) { 17649992Sbostic hashval1 = hash(hashval, i); 17749992Sbostic if (!bit(xhash, hashval1)) 17849992Sbostic goto cont; 17949992Sbostic } 18049992Sbostic if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */ 18149992Sbostic texec(*av, av); 18249992Sbostic else { 18349992Sbostic dp = Strspl(*pv, sav); 18449992Sbostic Vdp = dp; 18549992Sbostic texec(dp, av); 18649992Sbostic Vdp = 0; 18749992Sbostic xfree((ptr_t) dp); 18849992Sbostic } 18949992Sbostic misses++; 1901292Sbill cont: 19149992Sbostic pv++; 19249992Sbostic i++; 19349992Sbostic } while (*pv); 19449992Sbostic hits--; 19549992Sbostic Vsav = 0; 19649992Sbostic xfree((ptr_t) sav); 19749992Sbostic pexerr(); 1981292Sbill } 1991292Sbill 20049992Sbostic static void 2011292Sbill pexerr() 2021292Sbill { 20349992Sbostic /* Couldn't find the damn thing */ 20449992Sbostic if (expath) { 20549992Sbostic setname(short2str(expath)); 20649992Sbostic Vexpath = 0; 20749992Sbostic xfree((ptr_t) expath); 20849992Sbostic expath = 0; 20949992Sbostic } 21049992Sbostic else 21149992Sbostic setname(""); 21249992Sbostic if (exerr) 21349992Sbostic stderror(ERR_NAME | ERR_STRING, exerr); 21449992Sbostic stderror(ERR_NAME | ERR_COMMAND); 2151292Sbill } 2161292Sbill 2171292Sbill /* 2181292Sbill * Execute command f, arg list t. 2191292Sbill * Record error message if not found. 2201292Sbill * Also do shell scripts here. 2211292Sbill */ 22249992Sbostic static void 22349992Sbostic texec(sf, st) 22449992Sbostic Char *sf; 22549992Sbostic register Char **st; 2261292Sbill { 22749992Sbostic register char **t; 22849992Sbostic register char *f; 22949992Sbostic register struct varent *v; 23049992Sbostic register Char **vp; 23149992Sbostic Char *lastsh[2]; 23249992Sbostic int fd; 23349992Sbostic unsigned char c; 23449992Sbostic Char *st0, **ost; 2351292Sbill 23649992Sbostic /* The order for the conversions is significant */ 23749992Sbostic t = short2blk(st); 23849992Sbostic f = short2str(sf); 23949992Sbostic Vt = t; 24049992Sbostic errno = 0; /* don't use a previous error */ 24149992Sbostic (void) execv(f, t); 24249992Sbostic Vt = 0; 24349992Sbostic blkfree((Char **) t); 24449992Sbostic switch (errno) { 2451292Sbill 24649992Sbostic case ENOEXEC: 24749992Sbostic /* 24849992Sbostic * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute 24949992Sbostic * it, don't feed it to the shell if it looks like a binary! 25049992Sbostic */ 25149992Sbostic if ((fd = open(f, O_RDONLY)) != -1) { 25249992Sbostic if (read(fd, (char *) &c, 1) == 1) { 25349992Sbostic if (!Isprint(c) && (c != '\n' && c != '\t')) { 25449992Sbostic (void) close(fd); 25549992Sbostic /* 25649992Sbostic * We *know* what ENOEXEC means. 25749992Sbostic */ 25849992Sbostic stderror(ERR_ARCH, f, strerror(errno)); 25949992Sbostic } 26049992Sbostic } 26149992Sbostic #ifdef _PATH_BSHELL 26249992Sbostic else 26349992Sbostic c = '#'; 26449992Sbostic #endif 26549992Sbostic (void) close(fd); 26649992Sbostic } 26749992Sbostic /* 26849992Sbostic * If there is an alias for shell, then put the words of the alias in 26949992Sbostic * front of the argument list replacing the command name. Note no 27049992Sbostic * interpretation of the words at this point. 27149992Sbostic */ 27249992Sbostic v = adrof1(STRshell, &aliases); 27349992Sbostic if (v == 0) { 27449992Sbostic vp = lastsh; 27549992Sbostic vp[0] = adrof(STRshell) ? value(STRshell) : STR_SHELLPATH; 27649992Sbostic vp[1] = NULL; 27749992Sbostic #ifdef _PATH_BSHELL 27849992Sbostic if (fd != -1 && c != '#') 27949992Sbostic vp[0] = STR_BSHELL; 28049992Sbostic #endif 28149992Sbostic } 28249992Sbostic else 28349992Sbostic vp = v->vec; 28449992Sbostic st0 = st[0]; 28549992Sbostic st[0] = sf; 28649992Sbostic ost = st; 28749992Sbostic st = blkspl(vp, st); /* Splice up the new arglst */ 28849992Sbostic ost[0] = st0; 28949992Sbostic sf = *st; 29049992Sbostic /* The order for the conversions is significant */ 29149992Sbostic t = short2blk(st); 29249992Sbostic f = short2str(sf); 29349992Sbostic xfree((ptr_t) st); 29449992Sbostic Vt = t; 29549992Sbostic (void) execv(f, t); 29649992Sbostic Vt = 0; 29749992Sbostic blkfree((Char **) t); 29849992Sbostic /* The sky is falling, the sky is falling! */ 2991292Sbill 30049992Sbostic case ENOMEM: 30149992Sbostic stderror(ERR_SYSTEM, f, strerror(errno)); 3021292Sbill 30349992Sbostic case ENOENT: 30449992Sbostic break; 3051292Sbill 30649992Sbostic default: 30749992Sbostic if (exerr == 0) { 30849992Sbostic exerr = strerror(errno); 30949992Sbostic if (expath) 31049992Sbostic xfree((ptr_t) expath); 31149992Sbostic expath = Strsave(sf); 31249992Sbostic Vexpath = expath; 3131292Sbill } 31449992Sbostic } 3151292Sbill } 3161292Sbill 31717508Sedward /*ARGSUSED*/ 31849992Sbostic void 3191292Sbill execash(t, kp) 32049992Sbostic char **t; 32149992Sbostic register struct command *kp; 3221292Sbill { 32349992Sbostic if (chkstop == 0 && setintr) 32449992Sbostic panystop(0); 32549992Sbostic rechist(); 32649992Sbostic (void) signal(SIGINT, parintr); 32749992Sbostic (void) signal(SIGQUIT, parintr); 32849992Sbostic (void) signal(SIGTERM, parterm); /* if doexec loses, screw */ 32949992Sbostic lshift(kp->t_dcom, 1); 33049992Sbostic exiterr = 1; 33149992Sbostic doexec(kp); 33249992Sbostic /* NOTREACHED */ 3331292Sbill } 3341292Sbill 33549992Sbostic void 3361292Sbill xechoit(t) 33749992Sbostic Char **t; 3381292Sbill { 33949992Sbostic if (adrof(STRecho)) { 34049992Sbostic flush(); 34149992Sbostic haderr = 1; 34249992Sbostic blkpr(t), xputchar('\n'); 34349992Sbostic haderr = 0; 34449992Sbostic } 3451292Sbill } 3461292Sbill 34749992Sbostic /*VARARGS0*/ 34849992Sbostic void 34931685Sbostic dohash() 3501292Sbill { 35149992Sbostic DIR *dirp; 35249992Sbostic register struct dirent *dp; 35349992Sbostic register int cnt; 35449992Sbostic int i = 0; 35549992Sbostic struct varent *v = adrof(STRpath); 35649992Sbostic Char **pv; 35749992Sbostic int hashval; 3581292Sbill 35949992Sbostic havhash = 1; 36049992Sbostic for (cnt = 0; cnt < sizeof xhash; cnt++) 36149992Sbostic xhash[cnt] = 0; 36249992Sbostic if (v == 0) 36349992Sbostic return; 36449992Sbostic for (pv = v->vec; *pv; pv++, i++) { 36549992Sbostic if (pv[0][0] != '/') 36649992Sbostic continue; 36749992Sbostic dirp = opendir(short2str(*pv)); 36849992Sbostic if (dirp == NULL) 36949992Sbostic continue; 37049992Sbostic while ((dp = readdir(dirp)) != NULL) { 37149992Sbostic if (dp->d_ino == 0) 37249992Sbostic continue; 37349992Sbostic if (dp->d_name[0] == '.' && 37449992Sbostic (dp->d_name[1] == '\0' || 37549992Sbostic dp->d_name[1] == '.' && dp->d_name[2] == '\0')) 37649992Sbostic continue; 37749992Sbostic hashval = hash(hashname(str2short(dp->d_name)), i); 37849992Sbostic bis(xhash, hashval); 37949992Sbostic /* tw_add_comm_name (dp->d_name); */ 3801292Sbill } 38149992Sbostic (void) closedir(dirp); 38249992Sbostic } 3831292Sbill } 3841292Sbill 38549992Sbostic void 3861292Sbill dounhash() 3871292Sbill { 38849992Sbostic havhash = 0; 3891292Sbill } 3901292Sbill 39149992Sbostic void 3921292Sbill hashstat() 3931292Sbill { 39449992Sbostic if (hits + misses) 39549992Sbostic xprintf("%d hits, %d misses, %d%%\n", 39649992Sbostic hits, misses, 100 * hits / (hits + misses)); 39749992Sbostic } 3981292Sbill 39917508Sedward /* 40017508Sedward * Hash a command name. 40117508Sedward */ 40249992Sbostic static int 40317508Sedward hashname(cp) 40449992Sbostic register Char *cp; 4051292Sbill { 40649992Sbostic register long h = 0; 4071292Sbill 40849992Sbostic while (*cp) 40949992Sbostic h = hash(h, *cp++); 41049992Sbostic return ((int) h); 4111292Sbill } 412