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*50439Schristos static char sccsid[] = "@(#)exec.c 5.18 (Berkeley) 07/19/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> 1950033Schristos #if __STDC__ 2050033Schristos # include <stdarg.h> 2150033Schristos #else 2250033Schristos # include <varargs.h> 2350033Schristos #endif 2450033Schristos 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 */ 3450076Schristos extern char **environ; 351292Sbill 3649992Sbostic /* 371292Sbill * As we search for the command we note the first non-trivial error 381292Sbill * message for presentation to the user. This allows us often 391292Sbill * to show that a file has the wrong mode/no access when the file 401292Sbill * is not in the last component of the search path, so we must 411292Sbill * go on after first detecting the error. 421292Sbill */ 4349992Sbostic static char *exerr; /* Execution error message */ 4449992Sbostic static Char *expath; /* Path for exerr */ 451292Sbill 461292Sbill /* 4717508Sedward * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used 4817508Sedward * to hash execs. If it is allocated (havhash true), then to tell 4917508Sedward * whether ``name'' is (possibly) present in the i'th component 5017508Sedward * of the variable path, you look at the bit in xhash indexed by 5117508Sedward * hash(hashname("name"), i). This is setup automatically 521292Sbill * after .login is executed, and recomputed whenever ``path'' is 531292Sbill * changed. 5417508Sedward * The two part hash function is designed to let texec() call the 5517508Sedward * more expensive hashname() only once and the simple hash() several 5617508Sedward * times (once for each path component checked). 5717508Sedward * Byte size is assumed to be 8. 581292Sbill */ 5949992Sbostic #define HSHSIZ 8192 /* 1k bytes */ 6017508Sedward #define HSHMASK (HSHSIZ - 1) 6117508Sedward #define HSHMUL 243 6249992Sbostic static char xhash[HSHSIZ / 8]; 6349992Sbostic 6417508Sedward #define hash(a, b) ((a) * HSHMUL + (b) & HSHMASK) 6517508Sedward #define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */ 6617508Sedward #define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */ 6749992Sbostic static int hits, misses; 6849992Sbostic 691292Sbill /* Dummy search path for just absolute search when no path */ 7049992Sbostic static Char *justabs[] = {STRNULL, 0}; 711292Sbill 7250024Schristos static void pexerr __P((void)); 7350024Schristos static void texec __P((Char *, Char **)); 7450024Schristos static int hashname __P((Char *)); 7549992Sbostic 7649992Sbostic void 77*50439Schristos /*ARGSUSED*/ 78*50439Schristos doexec(v, t) 79*50439Schristos Char **v; 80*50439Schristos struct command *t; 811292Sbill { 8249992Sbostic register Char *dp, **pv, **av, *sav; 83*50439Schristos register struct varent *pathv; 8449992Sbostic register bool slash; 8549992Sbostic register int hashval = 0, hashval1, i; 8649992Sbostic Char *blk[2]; 871292Sbill 8849992Sbostic /* 8949992Sbostic * Glob the command name. We will search $path even if this does something, 9049992Sbostic * as in sh but not in csh. One special case: if there is no PATH, then we 9149992Sbostic * execute only commands which start with '/'. 9249992Sbostic */ 9349992Sbostic blk[0] = t->t_dcom[0]; 9449992Sbostic blk[1] = 0; 9549992Sbostic gflag = 0, tglob(blk); 9649992Sbostic if (gflag) { 9749992Sbostic pv = globall(blk); 9849992Sbostic if (pv == 0) { 9949992Sbostic setname(short2str(blk[0])); 10049992Sbostic stderror(ERR_NAME | ERR_NOMATCH); 10149992Sbostic } 10249992Sbostic gargv = 0; 10349992Sbostic } 10449992Sbostic else 10549992Sbostic pv = saveblk(blk); 1061292Sbill 10749992Sbostic trim(pv); 10849992Sbostic 10949992Sbostic exerr = 0; 11049992Sbostic expath = Strsave(pv[0]); 11149992Sbostic Vexpath = expath; 1121292Sbill 113*50439Schristos pathv = adrof(STRpath); 114*50439Schristos if (pathv == 0 && expath[0] != '/') { 11549992Sbostic blkfree(pv); 11649992Sbostic pexerr(); 11749992Sbostic } 11849992Sbostic slash = any(short2str(expath), '/'); 1191292Sbill 12049992Sbostic /* 12149992Sbostic * Glob the argument list, if necessary. Otherwise trim off the quote bits. 12249992Sbostic */ 12349992Sbostic gflag = 0; 12449992Sbostic av = &t->t_dcom[1]; 12549992Sbostic tglob(av); 12649992Sbostic if (gflag) { 12749992Sbostic av = globall(av); 12849992Sbostic if (av == 0) { 12949992Sbostic blkfree(pv); 13049992Sbostic setname(short2str(expath)); 13149992Sbostic stderror(ERR_NAME | ERR_NOMATCH); 13249992Sbostic } 13349992Sbostic gargv = 0; 13449992Sbostic } 13549992Sbostic else 13649992Sbostic av = saveblk(av); 1371292Sbill 13849992Sbostic blkfree(t->t_dcom); 13949992Sbostic t->t_dcom = blkspl(pv, av); 14049992Sbostic xfree((ptr_t) pv); 14149992Sbostic xfree((ptr_t) av); 14249992Sbostic av = t->t_dcom; 14349992Sbostic trim(av); 14449992Sbostic 14550024Schristos if (*av == NULL || **av == '\0') 14649992Sbostic pexerr(); 14749992Sbostic 14849992Sbostic xechoit(av); /* Echo command if -x */ 14949992Sbostic /* 15049992Sbostic * Since all internal file descriptors are set to close on exec, we don't 15149992Sbostic * need to close them explicitly here. Just reorient ourselves for error 15249992Sbostic * messages. 15349992Sbostic */ 15449992Sbostic SHIN = 0; 15549992Sbostic SHOUT = 1; 156*50439Schristos SHERR = 2; 15749992Sbostic OLDSTD = 0; 15849992Sbostic /* 15949992Sbostic * We must do this AFTER any possible forking (like `foo` in glob) so that 16049992Sbostic * this shell can still do subprocesses. 16149992Sbostic */ 16250028Sbostic (void) sigsetmask((sigset_t) 0); 16349992Sbostic /* 16449992Sbostic * If no path, no words in path, or a / in the filename then restrict the 16549992Sbostic * command search. 16649992Sbostic */ 167*50439Schristos if (pathv == 0 || pathv->vec[0] == 0 || slash) 16849992Sbostic pv = justabs; 16949992Sbostic else 170*50439Schristos pv = pathv->vec; 17149992Sbostic sav = Strspl(STRslash, *av);/* / command name for postpending */ 17249992Sbostic Vsav = sav; 17349992Sbostic if (havhash) 17449992Sbostic hashval = hashname(*av); 17549992Sbostic i = 0; 17649992Sbostic hits++; 17749992Sbostic do { 17849992Sbostic /* 17949992Sbostic * Try to save time by looking at the hash table for where this command 18049992Sbostic * could be. If we are doing delayed hashing, then we put the names in 18149992Sbostic * one at a time, as the user enters them. This is kinda like Korn 18249992Sbostic * Shell's "tracked aliases". 18349992Sbostic */ 18449992Sbostic if (!slash && pv[0][0] == '/' && havhash) { 18549992Sbostic hashval1 = hash(hashval, i); 18649992Sbostic if (!bit(xhash, hashval1)) 18749992Sbostic goto cont; 18849992Sbostic } 18949992Sbostic if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */ 19049992Sbostic texec(*av, av); 19149992Sbostic else { 19249992Sbostic dp = Strspl(*pv, sav); 19349992Sbostic Vdp = dp; 19449992Sbostic texec(dp, av); 19549992Sbostic Vdp = 0; 19649992Sbostic xfree((ptr_t) dp); 19749992Sbostic } 19849992Sbostic misses++; 1991292Sbill cont: 20049992Sbostic pv++; 20149992Sbostic i++; 20249992Sbostic } while (*pv); 20349992Sbostic hits--; 20449992Sbostic Vsav = 0; 20549992Sbostic xfree((ptr_t) sav); 20649992Sbostic pexerr(); 2071292Sbill } 2081292Sbill 20949992Sbostic static void 2101292Sbill pexerr() 2111292Sbill { 21249992Sbostic /* Couldn't find the damn thing */ 21349992Sbostic if (expath) { 21449992Sbostic setname(short2str(expath)); 21549992Sbostic Vexpath = 0; 21649992Sbostic xfree((ptr_t) expath); 21749992Sbostic expath = 0; 21849992Sbostic } 21949992Sbostic else 22049992Sbostic setname(""); 22149992Sbostic if (exerr) 22249992Sbostic stderror(ERR_NAME | ERR_STRING, exerr); 22349992Sbostic stderror(ERR_NAME | ERR_COMMAND); 2241292Sbill } 2251292Sbill 2261292Sbill /* 2271292Sbill * Execute command f, arg list t. 2281292Sbill * Record error message if not found. 2291292Sbill * Also do shell scripts here. 2301292Sbill */ 23149992Sbostic static void 23249992Sbostic texec(sf, st) 23349992Sbostic Char *sf; 23449992Sbostic register Char **st; 2351292Sbill { 23649992Sbostic register char **t; 23749992Sbostic register char *f; 23849992Sbostic register struct varent *v; 23949992Sbostic register Char **vp; 24049992Sbostic Char *lastsh[2]; 24149992Sbostic int fd; 24249992Sbostic unsigned char c; 24349992Sbostic Char *st0, **ost; 2441292Sbill 24549992Sbostic /* The order for the conversions is significant */ 24649992Sbostic t = short2blk(st); 24749992Sbostic f = short2str(sf); 24849992Sbostic Vt = t; 24949992Sbostic errno = 0; /* don't use a previous error */ 25050076Schristos (void) execve(f, t, environ); 25149992Sbostic Vt = 0; 25249992Sbostic blkfree((Char **) t); 25349992Sbostic switch (errno) { 2541292Sbill 25549992Sbostic case ENOEXEC: 25649992Sbostic /* 25749992Sbostic * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute 25849992Sbostic * it, don't feed it to the shell if it looks like a binary! 25949992Sbostic */ 26049992Sbostic if ((fd = open(f, O_RDONLY)) != -1) { 26149992Sbostic if (read(fd, (char *) &c, 1) == 1) { 26249992Sbostic if (!Isprint(c) && (c != '\n' && c != '\t')) { 26349992Sbostic (void) close(fd); 26449992Sbostic /* 26549992Sbostic * We *know* what ENOEXEC means. 26649992Sbostic */ 26749992Sbostic stderror(ERR_ARCH, f, strerror(errno)); 26849992Sbostic } 26949992Sbostic } 27049992Sbostic #ifdef _PATH_BSHELL 27149992Sbostic else 27249992Sbostic c = '#'; 27349992Sbostic #endif 27449992Sbostic (void) close(fd); 27549992Sbostic } 27649992Sbostic /* 27749992Sbostic * If there is an alias for shell, then put the words of the alias in 27849992Sbostic * front of the argument list replacing the command name. Note no 27949992Sbostic * interpretation of the words at this point. 28049992Sbostic */ 28149992Sbostic v = adrof1(STRshell, &aliases); 28249992Sbostic if (v == 0) { 28349992Sbostic vp = lastsh; 28449992Sbostic vp[0] = adrof(STRshell) ? value(STRshell) : STR_SHELLPATH; 28549992Sbostic vp[1] = NULL; 28649992Sbostic #ifdef _PATH_BSHELL 28749992Sbostic if (fd != -1 && c != '#') 28849992Sbostic vp[0] = STR_BSHELL; 28949992Sbostic #endif 29049992Sbostic } 29149992Sbostic else 29249992Sbostic vp = v->vec; 29349992Sbostic st0 = st[0]; 29449992Sbostic st[0] = sf; 29549992Sbostic ost = st; 29649992Sbostic st = blkspl(vp, st); /* Splice up the new arglst */ 29749992Sbostic ost[0] = st0; 29849992Sbostic sf = *st; 29949992Sbostic /* The order for the conversions is significant */ 30049992Sbostic t = short2blk(st); 30149992Sbostic f = short2str(sf); 30249992Sbostic xfree((ptr_t) st); 30349992Sbostic Vt = t; 30450076Schristos (void) execve(f, t, environ); 30549992Sbostic Vt = 0; 30649992Sbostic blkfree((Char **) t); 30749992Sbostic /* The sky is falling, the sky is falling! */ 3081292Sbill 30949992Sbostic case ENOMEM: 31049992Sbostic stderror(ERR_SYSTEM, f, strerror(errno)); 3111292Sbill 31249992Sbostic case ENOENT: 31349992Sbostic break; 3141292Sbill 31549992Sbostic default: 31649992Sbostic if (exerr == 0) { 31749992Sbostic exerr = strerror(errno); 31849992Sbostic if (expath) 31949992Sbostic xfree((ptr_t) expath); 32049992Sbostic expath = Strsave(sf); 32149992Sbostic Vexpath = expath; 3221292Sbill } 32349992Sbostic } 3241292Sbill } 3251292Sbill 32617508Sedward /*ARGSUSED*/ 32749992Sbostic void 328*50439Schristos execash(v, t) 329*50439Schristos Char **v; 330*50439Schristos register struct command *t; 3311292Sbill { 33249992Sbostic if (chkstop == 0 && setintr) 33349992Sbostic panystop(0); 33449992Sbostic rechist(); 33549992Sbostic (void) signal(SIGINT, parintr); 33649992Sbostic (void) signal(SIGQUIT, parintr); 33749992Sbostic (void) signal(SIGTERM, parterm); /* if doexec loses, screw */ 338*50439Schristos lshift(t->t_dcom, 1); 33949992Sbostic exiterr = 1; 340*50439Schristos doexec(NULL, t); 34149992Sbostic /* NOTREACHED */ 3421292Sbill } 3431292Sbill 34449992Sbostic void 3451292Sbill xechoit(t) 34649992Sbostic Char **t; 3471292Sbill { 34849992Sbostic if (adrof(STRecho)) { 349*50439Schristos (void) fflush(csherr); 350*50439Schristos blkpr(csherr, t); 351*50439Schristos (void) fputc('\n', csherr); 35249992Sbostic } 3531292Sbill } 3541292Sbill 35549992Sbostic void 356*50439Schristos /*ARGSUSED*/ 357*50439Schristos dohash(v, t) 358*50439Schristos Char **v; 359*50439Schristos struct command *t; 3601292Sbill { 36149992Sbostic DIR *dirp; 36249992Sbostic register struct dirent *dp; 36349992Sbostic register int cnt; 36449992Sbostic int i = 0; 365*50439Schristos struct varent *pathv = adrof(STRpath); 36649992Sbostic Char **pv; 36749992Sbostic int hashval; 3681292Sbill 36949992Sbostic havhash = 1; 37049992Sbostic for (cnt = 0; cnt < sizeof xhash; cnt++) 37149992Sbostic xhash[cnt] = 0; 372*50439Schristos if (pathv == 0) 37349992Sbostic return; 374*50439Schristos for (pv = pathv->vec; *pv; pv++, i++) { 37549992Sbostic if (pv[0][0] != '/') 37649992Sbostic continue; 37749992Sbostic dirp = opendir(short2str(*pv)); 37849992Sbostic if (dirp == NULL) 37949992Sbostic continue; 38049992Sbostic while ((dp = readdir(dirp)) != NULL) { 38149992Sbostic if (dp->d_ino == 0) 38249992Sbostic continue; 38349992Sbostic if (dp->d_name[0] == '.' && 38449992Sbostic (dp->d_name[1] == '\0' || 38549992Sbostic dp->d_name[1] == '.' && dp->d_name[2] == '\0')) 38649992Sbostic continue; 38749992Sbostic hashval = hash(hashname(str2short(dp->d_name)), i); 38849992Sbostic bis(xhash, hashval); 38949992Sbostic /* tw_add_comm_name (dp->d_name); */ 3901292Sbill } 39149992Sbostic (void) closedir(dirp); 39249992Sbostic } 3931292Sbill } 3941292Sbill 39549992Sbostic void 396*50439Schristos /*ARGSUSED*/ 397*50439Schristos dounhash(v, t) 398*50439Schristos Char **v; 399*50439Schristos struct command *t; 4001292Sbill { 40149992Sbostic havhash = 0; 4021292Sbill } 4031292Sbill 40449992Sbostic void 405*50439Schristos /*ARGSUSED*/ 406*50439Schristos hashstat(v, t) 407*50439Schristos Char **v; 408*50439Schristos struct command *t; 4091292Sbill { 41049992Sbostic if (hits + misses) 411*50439Schristos (void) fprintf(cshout, "%d hits, %d misses, %d%%\n", 412*50439Schristos hits, misses, 100 * hits / (hits + misses)); 41349992Sbostic } 4141292Sbill 41517508Sedward /* 41617508Sedward * Hash a command name. 41717508Sedward */ 41849992Sbostic static int 41917508Sedward hashname(cp) 42049992Sbostic register Char *cp; 4211292Sbill { 42249992Sbostic register long h = 0; 4231292Sbill 42449992Sbostic while (*cp) 42549992Sbostic h = hash(h, *cp++); 42649992Sbostic return ((int) h); 4271292Sbill } 428