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*50023Sbostic static char sccsid[] = "@(#)exec.c 5.13 (Berkeley) 06/07/91"; 1047738Sbostic #endif /* not lint */ 111292Sbill 12*50023Sbostic #include "csh.h" 13*50023Sbostic #include "extern.h" 141292Sbill 151292Sbill /* 161292Sbill * System level search and execute of a command. 171292Sbill * We look in each directory for the specified command name. 181292Sbill * If the name contains a '/' then we execute only the full path name. 191292Sbill * If there is no search path then we execute only full path names. 201292Sbill */ 211292Sbill 2249992Sbostic /* 231292Sbill * As we search for the command we note the first non-trivial error 241292Sbill * message for presentation to the user. This allows us often 251292Sbill * to show that a file has the wrong mode/no access when the file 261292Sbill * is not in the last component of the search path, so we must 271292Sbill * go on after first detecting the error. 281292Sbill */ 2949992Sbostic static char *exerr; /* Execution error message */ 3049992Sbostic static Char *expath; /* Path for exerr */ 311292Sbill 321292Sbill /* 3317508Sedward * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used 3417508Sedward * to hash execs. If it is allocated (havhash true), then to tell 3517508Sedward * whether ``name'' is (possibly) present in the i'th component 3617508Sedward * of the variable path, you look at the bit in xhash indexed by 3717508Sedward * hash(hashname("name"), i). This is setup automatically 381292Sbill * after .login is executed, and recomputed whenever ``path'' is 391292Sbill * changed. 4017508Sedward * The two part hash function is designed to let texec() call the 4117508Sedward * more expensive hashname() only once and the simple hash() several 4217508Sedward * times (once for each path component checked). 4317508Sedward * Byte size is assumed to be 8. 441292Sbill */ 4549992Sbostic #define HSHSIZ 8192 /* 1k bytes */ 4617508Sedward #define HSHMASK (HSHSIZ - 1) 4717508Sedward #define HSHMUL 243 4849992Sbostic static char xhash[HSHSIZ / 8]; 4949992Sbostic 5017508Sedward #define hash(a, b) ((a) * HSHMUL + (b) & HSHMASK) 5117508Sedward #define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */ 5217508Sedward #define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */ 5349992Sbostic static int hits, misses; 5449992Sbostic 551292Sbill /* Dummy search path for just absolute search when no path */ 5649992Sbostic static Char *justabs[] = {STRNULL, 0}; 571292Sbill 5849992Sbostic static void pexerr(); 5949992Sbostic static void texec(); 6049992Sbostic static int hashname(); 6149992Sbostic 6249992Sbostic void 631292Sbill doexec(t) 6449992Sbostic register struct command *t; 651292Sbill { 6649992Sbostic register Char *dp, **pv, **av, *sav; 6749992Sbostic register struct varent *v; 6849992Sbostic register bool slash; 6949992Sbostic register int hashval = 0, hashval1, i; 7049992Sbostic Char *blk[2]; 711292Sbill 7249992Sbostic /* 7349992Sbostic * Glob the command name. We will search $path even if this does something, 7449992Sbostic * as in sh but not in csh. One special case: if there is no PATH, then we 7549992Sbostic * execute only commands which start with '/'. 7649992Sbostic */ 7749992Sbostic blk[0] = t->t_dcom[0]; 7849992Sbostic blk[1] = 0; 7949992Sbostic gflag = 0, tglob(blk); 8049992Sbostic if (gflag) { 8149992Sbostic pv = globall(blk); 8249992Sbostic if (pv == 0) { 8349992Sbostic setname(short2str(blk[0])); 8449992Sbostic stderror(ERR_NAME | ERR_NOMATCH); 8549992Sbostic } 8649992Sbostic gargv = 0; 8749992Sbostic } 8849992Sbostic else 8949992Sbostic pv = saveblk(blk); 901292Sbill 9149992Sbostic trim(pv); 9249992Sbostic 9349992Sbostic exerr = 0; 9449992Sbostic expath = Strsave(pv[0]); 9549992Sbostic Vexpath = expath; 961292Sbill 9749992Sbostic v = adrof(STRpath); 9849992Sbostic if (v == 0 && expath[0] != '/') { 9949992Sbostic blkfree(pv); 10049992Sbostic pexerr(); 10149992Sbostic } 10249992Sbostic slash = any(short2str(expath), '/'); 1031292Sbill 10449992Sbostic /* 10549992Sbostic * Glob the argument list, if necessary. Otherwise trim off the quote bits. 10649992Sbostic */ 10749992Sbostic gflag = 0; 10849992Sbostic av = &t->t_dcom[1]; 10949992Sbostic tglob(av); 11049992Sbostic if (gflag) { 11149992Sbostic av = globall(av); 11249992Sbostic if (av == 0) { 11349992Sbostic blkfree(pv); 11449992Sbostic setname(short2str(expath)); 11549992Sbostic stderror(ERR_NAME | ERR_NOMATCH); 11649992Sbostic } 11749992Sbostic gargv = 0; 11849992Sbostic } 11949992Sbostic else 12049992Sbostic av = saveblk(av); 1211292Sbill 12249992Sbostic blkfree(t->t_dcom); 12349992Sbostic t->t_dcom = blkspl(pv, av); 12449992Sbostic xfree((ptr_t) pv); 12549992Sbostic xfree((ptr_t) av); 12649992Sbostic av = t->t_dcom; 12749992Sbostic trim(av); 12849992Sbostic 12949992Sbostic if (*av == (Char *) 0 || **av == '\0') 13049992Sbostic pexerr(); 13149992Sbostic 13249992Sbostic xechoit(av); /* Echo command if -x */ 13349992Sbostic /* 13449992Sbostic * Since all internal file descriptors are set to close on exec, we don't 13549992Sbostic * need to close them explicitly here. Just reorient ourselves for error 13649992Sbostic * messages. 13749992Sbostic */ 13849992Sbostic SHIN = 0; 13949992Sbostic SHOUT = 1; 14049992Sbostic SHDIAG = 2; 14149992Sbostic OLDSTD = 0; 14249992Sbostic /* 14349992Sbostic * We must do this AFTER any possible forking (like `foo` in glob) so that 14449992Sbostic * this shell can still do subprocesses. 14549992Sbostic */ 14649992Sbostic (void) sigsetmask((sigmask_t) 0); 14749992Sbostic /* 14849992Sbostic * If no path, no words in path, or a / in the filename then restrict the 14949992Sbostic * command search. 15049992Sbostic */ 15149992Sbostic if (v == 0 || v->vec[0] == 0 || slash) 15249992Sbostic pv = justabs; 15349992Sbostic else 15449992Sbostic pv = v->vec; 15549992Sbostic sav = Strspl(STRslash, *av);/* / command name for postpending */ 15649992Sbostic Vsav = sav; 15749992Sbostic if (havhash) 15849992Sbostic hashval = hashname(*av); 15949992Sbostic i = 0; 16049992Sbostic hits++; 16149992Sbostic do { 16249992Sbostic /* 16349992Sbostic * Try to save time by looking at the hash table for where this command 16449992Sbostic * could be. If we are doing delayed hashing, then we put the names in 16549992Sbostic * one at a time, as the user enters them. This is kinda like Korn 16649992Sbostic * Shell's "tracked aliases". 16749992Sbostic */ 16849992Sbostic if (!slash && pv[0][0] == '/' && havhash) { 16949992Sbostic hashval1 = hash(hashval, i); 17049992Sbostic if (!bit(xhash, hashval1)) 17149992Sbostic goto cont; 17249992Sbostic } 17349992Sbostic if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */ 17449992Sbostic texec(*av, av); 17549992Sbostic else { 17649992Sbostic dp = Strspl(*pv, sav); 17749992Sbostic Vdp = dp; 17849992Sbostic texec(dp, av); 17949992Sbostic Vdp = 0; 18049992Sbostic xfree((ptr_t) dp); 18149992Sbostic } 18249992Sbostic misses++; 1831292Sbill cont: 18449992Sbostic pv++; 18549992Sbostic i++; 18649992Sbostic } while (*pv); 18749992Sbostic hits--; 18849992Sbostic Vsav = 0; 18949992Sbostic xfree((ptr_t) sav); 19049992Sbostic pexerr(); 1911292Sbill } 1921292Sbill 19349992Sbostic static void 1941292Sbill pexerr() 1951292Sbill { 19649992Sbostic /* Couldn't find the damn thing */ 19749992Sbostic if (expath) { 19849992Sbostic setname(short2str(expath)); 19949992Sbostic Vexpath = 0; 20049992Sbostic xfree((ptr_t) expath); 20149992Sbostic expath = 0; 20249992Sbostic } 20349992Sbostic else 20449992Sbostic setname(""); 20549992Sbostic if (exerr) 20649992Sbostic stderror(ERR_NAME | ERR_STRING, exerr); 20749992Sbostic stderror(ERR_NAME | ERR_COMMAND); 2081292Sbill } 2091292Sbill 2101292Sbill /* 2111292Sbill * Execute command f, arg list t. 2121292Sbill * Record error message if not found. 2131292Sbill * Also do shell scripts here. 2141292Sbill */ 21549992Sbostic static void 21649992Sbostic texec(sf, st) 21749992Sbostic Char *sf; 21849992Sbostic register Char **st; 2191292Sbill { 22049992Sbostic register char **t; 22149992Sbostic register char *f; 22249992Sbostic register struct varent *v; 22349992Sbostic register Char **vp; 22449992Sbostic Char *lastsh[2]; 22549992Sbostic int fd; 22649992Sbostic unsigned char c; 22749992Sbostic Char *st0, **ost; 2281292Sbill 22949992Sbostic /* The order for the conversions is significant */ 23049992Sbostic t = short2blk(st); 23149992Sbostic f = short2str(sf); 23249992Sbostic Vt = t; 23349992Sbostic errno = 0; /* don't use a previous error */ 23449992Sbostic (void) execv(f, t); 23549992Sbostic Vt = 0; 23649992Sbostic blkfree((Char **) t); 23749992Sbostic switch (errno) { 2381292Sbill 23949992Sbostic case ENOEXEC: 24049992Sbostic /* 24149992Sbostic * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute 24249992Sbostic * it, don't feed it to the shell if it looks like a binary! 24349992Sbostic */ 24449992Sbostic if ((fd = open(f, O_RDONLY)) != -1) { 24549992Sbostic if (read(fd, (char *) &c, 1) == 1) { 24649992Sbostic if (!Isprint(c) && (c != '\n' && c != '\t')) { 24749992Sbostic (void) close(fd); 24849992Sbostic /* 24949992Sbostic * We *know* what ENOEXEC means. 25049992Sbostic */ 25149992Sbostic stderror(ERR_ARCH, f, strerror(errno)); 25249992Sbostic } 25349992Sbostic } 25449992Sbostic #ifdef _PATH_BSHELL 25549992Sbostic else 25649992Sbostic c = '#'; 25749992Sbostic #endif 25849992Sbostic (void) close(fd); 25949992Sbostic } 26049992Sbostic /* 26149992Sbostic * If there is an alias for shell, then put the words of the alias in 26249992Sbostic * front of the argument list replacing the command name. Note no 26349992Sbostic * interpretation of the words at this point. 26449992Sbostic */ 26549992Sbostic v = adrof1(STRshell, &aliases); 26649992Sbostic if (v == 0) { 26749992Sbostic vp = lastsh; 26849992Sbostic vp[0] = adrof(STRshell) ? value(STRshell) : STR_SHELLPATH; 26949992Sbostic vp[1] = NULL; 27049992Sbostic #ifdef _PATH_BSHELL 27149992Sbostic if (fd != -1 && c != '#') 27249992Sbostic vp[0] = STR_BSHELL; 27349992Sbostic #endif 27449992Sbostic } 27549992Sbostic else 27649992Sbostic vp = v->vec; 27749992Sbostic st0 = st[0]; 27849992Sbostic st[0] = sf; 27949992Sbostic ost = st; 28049992Sbostic st = blkspl(vp, st); /* Splice up the new arglst */ 28149992Sbostic ost[0] = st0; 28249992Sbostic sf = *st; 28349992Sbostic /* The order for the conversions is significant */ 28449992Sbostic t = short2blk(st); 28549992Sbostic f = short2str(sf); 28649992Sbostic xfree((ptr_t) st); 28749992Sbostic Vt = t; 28849992Sbostic (void) execv(f, t); 28949992Sbostic Vt = 0; 29049992Sbostic blkfree((Char **) t); 29149992Sbostic /* The sky is falling, the sky is falling! */ 2921292Sbill 29349992Sbostic case ENOMEM: 29449992Sbostic stderror(ERR_SYSTEM, f, strerror(errno)); 2951292Sbill 29649992Sbostic case ENOENT: 29749992Sbostic break; 2981292Sbill 29949992Sbostic default: 30049992Sbostic if (exerr == 0) { 30149992Sbostic exerr = strerror(errno); 30249992Sbostic if (expath) 30349992Sbostic xfree((ptr_t) expath); 30449992Sbostic expath = Strsave(sf); 30549992Sbostic Vexpath = expath; 3061292Sbill } 30749992Sbostic } 3081292Sbill } 3091292Sbill 31017508Sedward /*ARGSUSED*/ 31149992Sbostic void 3121292Sbill execash(t, kp) 31349992Sbostic char **t; 31449992Sbostic register struct command *kp; 3151292Sbill { 31649992Sbostic if (chkstop == 0 && setintr) 31749992Sbostic panystop(0); 31849992Sbostic rechist(); 31949992Sbostic (void) signal(SIGINT, parintr); 32049992Sbostic (void) signal(SIGQUIT, parintr); 32149992Sbostic (void) signal(SIGTERM, parterm); /* if doexec loses, screw */ 32249992Sbostic lshift(kp->t_dcom, 1); 32349992Sbostic exiterr = 1; 32449992Sbostic doexec(kp); 32549992Sbostic /* NOTREACHED */ 3261292Sbill } 3271292Sbill 32849992Sbostic void 3291292Sbill xechoit(t) 33049992Sbostic Char **t; 3311292Sbill { 33249992Sbostic if (adrof(STRecho)) { 33349992Sbostic flush(); 33449992Sbostic haderr = 1; 33549992Sbostic blkpr(t), xputchar('\n'); 33649992Sbostic haderr = 0; 33749992Sbostic } 3381292Sbill } 3391292Sbill 34049992Sbostic /*VARARGS0*/ 34149992Sbostic void 34231685Sbostic dohash() 3431292Sbill { 34449992Sbostic DIR *dirp; 34549992Sbostic register struct dirent *dp; 34649992Sbostic register int cnt; 34749992Sbostic int i = 0; 34849992Sbostic struct varent *v = adrof(STRpath); 34949992Sbostic Char **pv; 35049992Sbostic int hashval; 3511292Sbill 35249992Sbostic havhash = 1; 35349992Sbostic for (cnt = 0; cnt < sizeof xhash; cnt++) 35449992Sbostic xhash[cnt] = 0; 35549992Sbostic if (v == 0) 35649992Sbostic return; 35749992Sbostic for (pv = v->vec; *pv; pv++, i++) { 35849992Sbostic if (pv[0][0] != '/') 35949992Sbostic continue; 36049992Sbostic dirp = opendir(short2str(*pv)); 36149992Sbostic if (dirp == NULL) 36249992Sbostic continue; 36349992Sbostic while ((dp = readdir(dirp)) != NULL) { 36449992Sbostic if (dp->d_ino == 0) 36549992Sbostic continue; 36649992Sbostic if (dp->d_name[0] == '.' && 36749992Sbostic (dp->d_name[1] == '\0' || 36849992Sbostic dp->d_name[1] == '.' && dp->d_name[2] == '\0')) 36949992Sbostic continue; 37049992Sbostic hashval = hash(hashname(str2short(dp->d_name)), i); 37149992Sbostic bis(xhash, hashval); 37249992Sbostic /* tw_add_comm_name (dp->d_name); */ 3731292Sbill } 37449992Sbostic (void) closedir(dirp); 37549992Sbostic } 3761292Sbill } 3771292Sbill 37849992Sbostic void 3791292Sbill dounhash() 3801292Sbill { 38149992Sbostic havhash = 0; 3821292Sbill } 3831292Sbill 38449992Sbostic void 3851292Sbill hashstat() 3861292Sbill { 38749992Sbostic if (hits + misses) 38849992Sbostic xprintf("%d hits, %d misses, %d%%\n", 38949992Sbostic hits, misses, 100 * hits / (hits + misses)); 39049992Sbostic } 3911292Sbill 39217508Sedward /* 39317508Sedward * Hash a command name. 39417508Sedward */ 39549992Sbostic static int 39617508Sedward hashname(cp) 39749992Sbostic register Char *cp; 3981292Sbill { 39949992Sbostic register long h = 0; 4001292Sbill 40149992Sbostic while (*cp) 40249992Sbostic h = hash(h, *cp++); 40349992Sbostic return ((int) h); 4041292Sbill } 405