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*50033Schristos static char sccsid[] = "@(#)exec.c 5.16 (Berkeley) 06/08/91"; 1047738Sbostic #endif /* not lint */ 111292Sbill 1250028Sbostic #include <sys/types.h> 1350028Sbostic #include <dirent.h> 1450028Sbostic #include <fcntl.h> 1550028Sbostic #include <errno.h> 1650028Sbostic #include <stdlib.h> 1750028Sbostic #include <string.h> 1850028Sbostic #include <unistd.h> 19*50033Schristos #if __STDC__ 20*50033Schristos # include <stdarg.h> 21*50033Schristos #else 22*50033Schristos # include <varargs.h> 23*50033Schristos #endif 24*50033Schristos 2550023Sbostic #include "csh.h" 2650023Sbostic #include "extern.h" 271292Sbill 281292Sbill /* 2950028Sbostic * System level search and execute of a command. We look in each directory 3050028Sbostic * for the specified command name. If the name contains a '/' then we 3150028Sbostic * execute only the full path name. If there is no search path then we 3250028Sbostic * execute only full path names. 331292Sbill */ 341292Sbill 3549992Sbostic /* 361292Sbill * As we search for the command we note the first non-trivial error 371292Sbill * message for presentation to the user. This allows us often 381292Sbill * to show that a file has the wrong mode/no access when the file 391292Sbill * is not in the last component of the search path, so we must 401292Sbill * go on after first detecting the error. 411292Sbill */ 4249992Sbostic static char *exerr; /* Execution error message */ 4349992Sbostic static Char *expath; /* Path for exerr */ 441292Sbill 451292Sbill /* 4617508Sedward * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used 4717508Sedward * to hash execs. If it is allocated (havhash true), then to tell 4817508Sedward * whether ``name'' is (possibly) present in the i'th component 4917508Sedward * of the variable path, you look at the bit in xhash indexed by 5017508Sedward * hash(hashname("name"), i). This is setup automatically 511292Sbill * after .login is executed, and recomputed whenever ``path'' is 521292Sbill * changed. 5317508Sedward * The two part hash function is designed to let texec() call the 5417508Sedward * more expensive hashname() only once and the simple hash() several 5517508Sedward * times (once for each path component checked). 5617508Sedward * Byte size is assumed to be 8. 571292Sbill */ 5849992Sbostic #define HSHSIZ 8192 /* 1k bytes */ 5917508Sedward #define HSHMASK (HSHSIZ - 1) 6017508Sedward #define HSHMUL 243 6149992Sbostic static char xhash[HSHSIZ / 8]; 6249992Sbostic 6317508Sedward #define hash(a, b) ((a) * HSHMUL + (b) & HSHMASK) 6417508Sedward #define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */ 6517508Sedward #define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */ 6649992Sbostic static int hits, misses; 6749992Sbostic 681292Sbill /* Dummy search path for just absolute search when no path */ 6949992Sbostic static Char *justabs[] = {STRNULL, 0}; 701292Sbill 7150024Schristos static void pexerr __P((void)); 7250024Schristos static void texec __P((Char *, Char **)); 7350024Schristos static int hashname __P((Char *)); 7449992Sbostic 7549992Sbostic void 761292Sbill doexec(t) 7749992Sbostic register struct command *t; 781292Sbill { 7949992Sbostic register Char *dp, **pv, **av, *sav; 8049992Sbostic register struct varent *v; 8149992Sbostic register bool slash; 8249992Sbostic register int hashval = 0, hashval1, i; 8349992Sbostic Char *blk[2]; 841292Sbill 8549992Sbostic /* 8649992Sbostic * Glob the command name. We will search $path even if this does something, 8749992Sbostic * as in sh but not in csh. One special case: if there is no PATH, then we 8849992Sbostic * execute only commands which start with '/'. 8949992Sbostic */ 9049992Sbostic blk[0] = t->t_dcom[0]; 9149992Sbostic blk[1] = 0; 9249992Sbostic gflag = 0, tglob(blk); 9349992Sbostic if (gflag) { 9449992Sbostic pv = globall(blk); 9549992Sbostic if (pv == 0) { 9649992Sbostic setname(short2str(blk[0])); 9749992Sbostic stderror(ERR_NAME | ERR_NOMATCH); 9849992Sbostic } 9949992Sbostic gargv = 0; 10049992Sbostic } 10149992Sbostic else 10249992Sbostic pv = saveblk(blk); 1031292Sbill 10449992Sbostic trim(pv); 10549992Sbostic 10649992Sbostic exerr = 0; 10749992Sbostic expath = Strsave(pv[0]); 10849992Sbostic Vexpath = expath; 1091292Sbill 11049992Sbostic v = adrof(STRpath); 11149992Sbostic if (v == 0 && expath[0] != '/') { 11249992Sbostic blkfree(pv); 11349992Sbostic pexerr(); 11449992Sbostic } 11549992Sbostic slash = any(short2str(expath), '/'); 1161292Sbill 11749992Sbostic /* 11849992Sbostic * Glob the argument list, if necessary. Otherwise trim off the quote bits. 11949992Sbostic */ 12049992Sbostic gflag = 0; 12149992Sbostic av = &t->t_dcom[1]; 12249992Sbostic tglob(av); 12349992Sbostic if (gflag) { 12449992Sbostic av = globall(av); 12549992Sbostic if (av == 0) { 12649992Sbostic blkfree(pv); 12749992Sbostic setname(short2str(expath)); 12849992Sbostic stderror(ERR_NAME | ERR_NOMATCH); 12949992Sbostic } 13049992Sbostic gargv = 0; 13149992Sbostic } 13249992Sbostic else 13349992Sbostic av = saveblk(av); 1341292Sbill 13549992Sbostic blkfree(t->t_dcom); 13649992Sbostic t->t_dcom = blkspl(pv, av); 13749992Sbostic xfree((ptr_t) pv); 13849992Sbostic xfree((ptr_t) av); 13949992Sbostic av = t->t_dcom; 14049992Sbostic trim(av); 14149992Sbostic 14250024Schristos if (*av == NULL || **av == '\0') 14349992Sbostic pexerr(); 14449992Sbostic 14549992Sbostic xechoit(av); /* Echo command if -x */ 14649992Sbostic /* 14749992Sbostic * Since all internal file descriptors are set to close on exec, we don't 14849992Sbostic * need to close them explicitly here. Just reorient ourselves for error 14949992Sbostic * messages. 15049992Sbostic */ 15149992Sbostic SHIN = 0; 15249992Sbostic SHOUT = 1; 15349992Sbostic SHDIAG = 2; 15449992Sbostic OLDSTD = 0; 15549992Sbostic /* 15649992Sbostic * We must do this AFTER any possible forking (like `foo` in glob) so that 15749992Sbostic * this shell can still do subprocesses. 15849992Sbostic */ 15950028Sbostic (void) sigsetmask((sigset_t) 0); 16049992Sbostic /* 16149992Sbostic * If no path, no words in path, or a / in the filename then restrict the 16249992Sbostic * command search. 16349992Sbostic */ 16449992Sbostic if (v == 0 || v->vec[0] == 0 || slash) 16549992Sbostic pv = justabs; 16649992Sbostic else 16749992Sbostic pv = v->vec; 16849992Sbostic sav = Strspl(STRslash, *av);/* / command name for postpending */ 16949992Sbostic Vsav = sav; 17049992Sbostic if (havhash) 17149992Sbostic hashval = hashname(*av); 17249992Sbostic i = 0; 17349992Sbostic hits++; 17449992Sbostic do { 17549992Sbostic /* 17649992Sbostic * Try to save time by looking at the hash table for where this command 17749992Sbostic * could be. If we are doing delayed hashing, then we put the names in 17849992Sbostic * one at a time, as the user enters them. This is kinda like Korn 17949992Sbostic * Shell's "tracked aliases". 18049992Sbostic */ 18149992Sbostic if (!slash && pv[0][0] == '/' && havhash) { 18249992Sbostic hashval1 = hash(hashval, i); 18349992Sbostic if (!bit(xhash, hashval1)) 18449992Sbostic goto cont; 18549992Sbostic } 18649992Sbostic if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */ 18749992Sbostic texec(*av, av); 18849992Sbostic else { 18949992Sbostic dp = Strspl(*pv, sav); 19049992Sbostic Vdp = dp; 19149992Sbostic texec(dp, av); 19249992Sbostic Vdp = 0; 19349992Sbostic xfree((ptr_t) dp); 19449992Sbostic } 19549992Sbostic misses++; 1961292Sbill cont: 19749992Sbostic pv++; 19849992Sbostic i++; 19949992Sbostic } while (*pv); 20049992Sbostic hits--; 20149992Sbostic Vsav = 0; 20249992Sbostic xfree((ptr_t) sav); 20349992Sbostic pexerr(); 2041292Sbill } 2051292Sbill 20649992Sbostic static void 2071292Sbill pexerr() 2081292Sbill { 20949992Sbostic /* Couldn't find the damn thing */ 21049992Sbostic if (expath) { 21149992Sbostic setname(short2str(expath)); 21249992Sbostic Vexpath = 0; 21349992Sbostic xfree((ptr_t) expath); 21449992Sbostic expath = 0; 21549992Sbostic } 21649992Sbostic else 21749992Sbostic setname(""); 21849992Sbostic if (exerr) 21949992Sbostic stderror(ERR_NAME | ERR_STRING, exerr); 22049992Sbostic stderror(ERR_NAME | ERR_COMMAND); 2211292Sbill } 2221292Sbill 2231292Sbill /* 2241292Sbill * Execute command f, arg list t. 2251292Sbill * Record error message if not found. 2261292Sbill * Also do shell scripts here. 2271292Sbill */ 22849992Sbostic static void 22949992Sbostic texec(sf, st) 23049992Sbostic Char *sf; 23149992Sbostic register Char **st; 2321292Sbill { 23349992Sbostic register char **t; 23449992Sbostic register char *f; 23549992Sbostic register struct varent *v; 23649992Sbostic register Char **vp; 23749992Sbostic Char *lastsh[2]; 23849992Sbostic int fd; 23949992Sbostic unsigned char c; 24049992Sbostic Char *st0, **ost; 2411292Sbill 24249992Sbostic /* The order for the conversions is significant */ 24349992Sbostic t = short2blk(st); 24449992Sbostic f = short2str(sf); 24549992Sbostic Vt = t; 24649992Sbostic errno = 0; /* don't use a previous error */ 24749992Sbostic (void) execv(f, t); 24849992Sbostic Vt = 0; 24949992Sbostic blkfree((Char **) t); 25049992Sbostic switch (errno) { 2511292Sbill 25249992Sbostic case ENOEXEC: 25349992Sbostic /* 25449992Sbostic * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute 25549992Sbostic * it, don't feed it to the shell if it looks like a binary! 25649992Sbostic */ 25749992Sbostic if ((fd = open(f, O_RDONLY)) != -1) { 25849992Sbostic if (read(fd, (char *) &c, 1) == 1) { 25949992Sbostic if (!Isprint(c) && (c != '\n' && c != '\t')) { 26049992Sbostic (void) close(fd); 26149992Sbostic /* 26249992Sbostic * We *know* what ENOEXEC means. 26349992Sbostic */ 26449992Sbostic stderror(ERR_ARCH, f, strerror(errno)); 26549992Sbostic } 26649992Sbostic } 26749992Sbostic #ifdef _PATH_BSHELL 26849992Sbostic else 26949992Sbostic c = '#'; 27049992Sbostic #endif 27149992Sbostic (void) close(fd); 27249992Sbostic } 27349992Sbostic /* 27449992Sbostic * If there is an alias for shell, then put the words of the alias in 27549992Sbostic * front of the argument list replacing the command name. Note no 27649992Sbostic * interpretation of the words at this point. 27749992Sbostic */ 27849992Sbostic v = adrof1(STRshell, &aliases); 27949992Sbostic if (v == 0) { 28049992Sbostic vp = lastsh; 28149992Sbostic vp[0] = adrof(STRshell) ? value(STRshell) : STR_SHELLPATH; 28249992Sbostic vp[1] = NULL; 28349992Sbostic #ifdef _PATH_BSHELL 28449992Sbostic if (fd != -1 && c != '#') 28549992Sbostic vp[0] = STR_BSHELL; 28649992Sbostic #endif 28749992Sbostic } 28849992Sbostic else 28949992Sbostic vp = v->vec; 29049992Sbostic st0 = st[0]; 29149992Sbostic st[0] = sf; 29249992Sbostic ost = st; 29349992Sbostic st = blkspl(vp, st); /* Splice up the new arglst */ 29449992Sbostic ost[0] = st0; 29549992Sbostic sf = *st; 29649992Sbostic /* The order for the conversions is significant */ 29749992Sbostic t = short2blk(st); 29849992Sbostic f = short2str(sf); 29949992Sbostic xfree((ptr_t) st); 30049992Sbostic Vt = t; 30149992Sbostic (void) execv(f, t); 30249992Sbostic Vt = 0; 30349992Sbostic blkfree((Char **) t); 30449992Sbostic /* The sky is falling, the sky is falling! */ 3051292Sbill 30649992Sbostic case ENOMEM: 30749992Sbostic stderror(ERR_SYSTEM, f, strerror(errno)); 3081292Sbill 30949992Sbostic case ENOENT: 31049992Sbostic break; 3111292Sbill 31249992Sbostic default: 31349992Sbostic if (exerr == 0) { 31449992Sbostic exerr = strerror(errno); 31549992Sbostic if (expath) 31649992Sbostic xfree((ptr_t) expath); 31749992Sbostic expath = Strsave(sf); 31849992Sbostic Vexpath = expath; 3191292Sbill } 32049992Sbostic } 3211292Sbill } 3221292Sbill 32317508Sedward /*ARGSUSED*/ 32449992Sbostic void 3251292Sbill execash(t, kp) 32649992Sbostic char **t; 32749992Sbostic register struct command *kp; 3281292Sbill { 32949992Sbostic if (chkstop == 0 && setintr) 33049992Sbostic panystop(0); 33149992Sbostic rechist(); 33249992Sbostic (void) signal(SIGINT, parintr); 33349992Sbostic (void) signal(SIGQUIT, parintr); 33449992Sbostic (void) signal(SIGTERM, parterm); /* if doexec loses, screw */ 33549992Sbostic lshift(kp->t_dcom, 1); 33649992Sbostic exiterr = 1; 33749992Sbostic doexec(kp); 33849992Sbostic /* NOTREACHED */ 3391292Sbill } 3401292Sbill 34149992Sbostic void 3421292Sbill xechoit(t) 34349992Sbostic Char **t; 3441292Sbill { 34549992Sbostic if (adrof(STRecho)) { 34649992Sbostic flush(); 34749992Sbostic haderr = 1; 34849992Sbostic blkpr(t), xputchar('\n'); 34949992Sbostic haderr = 0; 35049992Sbostic } 3511292Sbill } 3521292Sbill 35349992Sbostic /*VARARGS0*/ 35449992Sbostic void 35531685Sbostic dohash() 3561292Sbill { 35749992Sbostic DIR *dirp; 35849992Sbostic register struct dirent *dp; 35949992Sbostic register int cnt; 36049992Sbostic int i = 0; 36149992Sbostic struct varent *v = adrof(STRpath); 36249992Sbostic Char **pv; 36349992Sbostic int hashval; 3641292Sbill 36549992Sbostic havhash = 1; 36649992Sbostic for (cnt = 0; cnt < sizeof xhash; cnt++) 36749992Sbostic xhash[cnt] = 0; 36849992Sbostic if (v == 0) 36949992Sbostic return; 37049992Sbostic for (pv = v->vec; *pv; pv++, i++) { 37149992Sbostic if (pv[0][0] != '/') 37249992Sbostic continue; 37349992Sbostic dirp = opendir(short2str(*pv)); 37449992Sbostic if (dirp == NULL) 37549992Sbostic continue; 37649992Sbostic while ((dp = readdir(dirp)) != NULL) { 37749992Sbostic if (dp->d_ino == 0) 37849992Sbostic continue; 37949992Sbostic if (dp->d_name[0] == '.' && 38049992Sbostic (dp->d_name[1] == '\0' || 38149992Sbostic dp->d_name[1] == '.' && dp->d_name[2] == '\0')) 38249992Sbostic continue; 38349992Sbostic hashval = hash(hashname(str2short(dp->d_name)), i); 38449992Sbostic bis(xhash, hashval); 38549992Sbostic /* tw_add_comm_name (dp->d_name); */ 3861292Sbill } 38749992Sbostic (void) closedir(dirp); 38849992Sbostic } 3891292Sbill } 3901292Sbill 39149992Sbostic void 3921292Sbill dounhash() 3931292Sbill { 39449992Sbostic havhash = 0; 3951292Sbill } 3961292Sbill 39749992Sbostic void 3981292Sbill hashstat() 3991292Sbill { 40049992Sbostic if (hits + misses) 40149992Sbostic xprintf("%d hits, %d misses, %d%%\n", 40249992Sbostic hits, misses, 100 * hits / (hits + misses)); 40349992Sbostic } 4041292Sbill 40517508Sedward /* 40617508Sedward * Hash a command name. 40717508Sedward */ 40849992Sbostic static int 40917508Sedward hashname(cp) 41049992Sbostic register Char *cp; 4111292Sbill { 41249992Sbostic register long h = 0; 4131292Sbill 41449992Sbostic while (*cp) 41549992Sbostic h = hash(h, *cp++); 41649992Sbostic return ((int) h); 4171292Sbill } 418