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*60237Schristos static char sccsid[] = "@(#)exec.c 5.22 (Berkeley) 05/22/93"; 1047738Sbostic #endif /* not lint */ 111292Sbill 1250028Sbostic #include <sys/types.h> 1350639Schristos #include <sys/param.h> 1450028Sbostic #include <dirent.h> 1550028Sbostic #include <fcntl.h> 1650639Schristos #include <sys/stat.h> 1750028Sbostic #include <errno.h> 1850028Sbostic #include <stdlib.h> 1950028Sbostic #include <string.h> 2050028Sbostic #include <unistd.h> 2150033Schristos #if __STDC__ 2250033Schristos # include <stdarg.h> 2350033Schristos #else 2450033Schristos # include <varargs.h> 2550033Schristos #endif 2650033Schristos 2750023Sbostic #include "csh.h" 2850023Sbostic #include "extern.h" 291292Sbill 301292Sbill /* 3150028Sbostic * System level search and execute of a command. We look in each directory 3250028Sbostic * for the specified command name. If the name contains a '/' then we 3350028Sbostic * execute only the full path name. If there is no search path then we 3450028Sbostic * execute only full path names. 351292Sbill */ 3650076Schristos extern char **environ; 371292Sbill 3849992Sbostic /* 391292Sbill * As we search for the command we note the first non-trivial error 401292Sbill * message for presentation to the user. This allows us often 411292Sbill * to show that a file has the wrong mode/no access when the file 421292Sbill * is not in the last component of the search path, so we must 431292Sbill * go on after first detecting the error. 441292Sbill */ 4549992Sbostic static char *exerr; /* Execution error message */ 4649992Sbostic static Char *expath; /* Path for exerr */ 471292Sbill 481292Sbill /* 4917508Sedward * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used 5017508Sedward * to hash execs. If it is allocated (havhash true), then to tell 5117508Sedward * whether ``name'' is (possibly) present in the i'th component 5217508Sedward * of the variable path, you look at the bit in xhash indexed by 5317508Sedward * hash(hashname("name"), i). This is setup automatically 541292Sbill * after .login is executed, and recomputed whenever ``path'' is 551292Sbill * changed. 5617508Sedward * The two part hash function is designed to let texec() call the 5717508Sedward * more expensive hashname() only once and the simple hash() several 5817508Sedward * times (once for each path component checked). 5917508Sedward * Byte size is assumed to be 8. 601292Sbill */ 6149992Sbostic #define HSHSIZ 8192 /* 1k bytes */ 6217508Sedward #define HSHMASK (HSHSIZ - 1) 6317508Sedward #define HSHMUL 243 6449992Sbostic static char xhash[HSHSIZ / 8]; 6549992Sbostic 66*60237Schristos #define hash(a, b) (((a) * HSHMUL + (b)) & HSHMASK) 6717508Sedward #define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */ 6817508Sedward #define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */ 6949992Sbostic static int hits, misses; 7049992Sbostic 711292Sbill /* Dummy search path for just absolute search when no path */ 7249992Sbostic static Char *justabs[] = {STRNULL, 0}; 731292Sbill 7450024Schristos static void pexerr __P((void)); 7550024Schristos static void texec __P((Char *, Char **)); 7650024Schristos static int hashname __P((Char *)); 7750639Schristos static void tellmewhat __P((struct wordent *)); 7850639Schristos static int executable __P((Char *, Char *, bool)); 7950639Schristos static int iscommand __P((Char *)); 8049992Sbostic 8150639Schristos 8249992Sbostic void 8350439Schristos /*ARGSUSED*/ 8450439Schristos doexec(v, t) 8550439Schristos Char **v; 8650439Schristos struct command *t; 871292Sbill { 8849992Sbostic register Char *dp, **pv, **av, *sav; 8950439Schristos register struct varent *pathv; 9049992Sbostic register bool slash; 9149992Sbostic register int hashval = 0, hashval1, i; 9249992Sbostic Char *blk[2]; 931292Sbill 9449992Sbostic /* 9549992Sbostic * Glob the command name. We will search $path even if this does something, 9649992Sbostic * as in sh but not in csh. One special case: if there is no PATH, then we 9749992Sbostic * execute only commands which start with '/'. 9849992Sbostic */ 9949992Sbostic blk[0] = t->t_dcom[0]; 10049992Sbostic blk[1] = 0; 10149992Sbostic gflag = 0, tglob(blk); 10249992Sbostic if (gflag) { 10349992Sbostic pv = globall(blk); 10449992Sbostic if (pv == 0) { 10551589Schristos setname(vis_str(blk[0])); 10649992Sbostic stderror(ERR_NAME | ERR_NOMATCH); 10749992Sbostic } 10849992Sbostic gargv = 0; 10949992Sbostic } 11049992Sbostic else 11149992Sbostic pv = saveblk(blk); 1121292Sbill 11349992Sbostic trim(pv); 11449992Sbostic 11549992Sbostic exerr = 0; 11649992Sbostic expath = Strsave(pv[0]); 11749992Sbostic Vexpath = expath; 1181292Sbill 11950439Schristos pathv = adrof(STRpath); 12050439Schristos if (pathv == 0 && expath[0] != '/') { 12149992Sbostic blkfree(pv); 12249992Sbostic pexerr(); 12349992Sbostic } 12449992Sbostic slash = any(short2str(expath), '/'); 1251292Sbill 12649992Sbostic /* 12749992Sbostic * Glob the argument list, if necessary. Otherwise trim off the quote bits. 12849992Sbostic */ 12949992Sbostic gflag = 0; 13049992Sbostic av = &t->t_dcom[1]; 13149992Sbostic tglob(av); 13249992Sbostic if (gflag) { 13349992Sbostic av = globall(av); 13449992Sbostic if (av == 0) { 13549992Sbostic blkfree(pv); 13651589Schristos setname(vis_str(expath)); 13749992Sbostic stderror(ERR_NAME | ERR_NOMATCH); 13849992Sbostic } 13949992Sbostic gargv = 0; 14049992Sbostic } 14149992Sbostic else 14249992Sbostic av = saveblk(av); 1431292Sbill 14449992Sbostic blkfree(t->t_dcom); 14549992Sbostic t->t_dcom = blkspl(pv, av); 14649992Sbostic xfree((ptr_t) pv); 14749992Sbostic xfree((ptr_t) av); 14849992Sbostic av = t->t_dcom; 14949992Sbostic trim(av); 15049992Sbostic 15150024Schristos if (*av == NULL || **av == '\0') 15249992Sbostic pexerr(); 15349992Sbostic 15449992Sbostic xechoit(av); /* Echo command if -x */ 15549992Sbostic /* 15649992Sbostic * Since all internal file descriptors are set to close on exec, we don't 15749992Sbostic * need to close them explicitly here. Just reorient ourselves for error 15849992Sbostic * messages. 15949992Sbostic */ 16049992Sbostic SHIN = 0; 16149992Sbostic SHOUT = 1; 16250439Schristos SHERR = 2; 16349992Sbostic OLDSTD = 0; 16449992Sbostic /* 16549992Sbostic * We must do this AFTER any possible forking (like `foo` in glob) so that 16649992Sbostic * this shell can still do subprocesses. 16749992Sbostic */ 16850028Sbostic (void) sigsetmask((sigset_t) 0); 16949992Sbostic /* 17049992Sbostic * If no path, no words in path, or a / in the filename then restrict the 17149992Sbostic * command search. 17249992Sbostic */ 17350439Schristos if (pathv == 0 || pathv->vec[0] == 0 || slash) 17449992Sbostic pv = justabs; 17549992Sbostic else 17650439Schristos pv = pathv->vec; 17749992Sbostic sav = Strspl(STRslash, *av);/* / command name for postpending */ 17849992Sbostic Vsav = sav; 17949992Sbostic if (havhash) 18049992Sbostic hashval = hashname(*av); 18149992Sbostic i = 0; 18249992Sbostic hits++; 18349992Sbostic do { 18449992Sbostic /* 18549992Sbostic * Try to save time by looking at the hash table for where this command 18649992Sbostic * could be. If we are doing delayed hashing, then we put the names in 18749992Sbostic * one at a time, as the user enters them. This is kinda like Korn 18849992Sbostic * Shell's "tracked aliases". 18949992Sbostic */ 19049992Sbostic if (!slash && pv[0][0] == '/' && havhash) { 19149992Sbostic hashval1 = hash(hashval, i); 19249992Sbostic if (!bit(xhash, hashval1)) 19349992Sbostic goto cont; 19449992Sbostic } 19549992Sbostic if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */ 19649992Sbostic texec(*av, av); 19749992Sbostic else { 19849992Sbostic dp = Strspl(*pv, sav); 19949992Sbostic Vdp = dp; 20049992Sbostic texec(dp, av); 20149992Sbostic Vdp = 0; 20249992Sbostic xfree((ptr_t) dp); 20349992Sbostic } 20449992Sbostic misses++; 2051292Sbill cont: 20649992Sbostic pv++; 20749992Sbostic i++; 20849992Sbostic } while (*pv); 20949992Sbostic hits--; 21049992Sbostic Vsav = 0; 21149992Sbostic xfree((ptr_t) sav); 21249992Sbostic pexerr(); 2131292Sbill } 2141292Sbill 21549992Sbostic static void 2161292Sbill pexerr() 2171292Sbill { 21849992Sbostic /* Couldn't find the damn thing */ 21949992Sbostic if (expath) { 22051589Schristos setname(vis_str(expath)); 22149992Sbostic Vexpath = 0; 22249992Sbostic xfree((ptr_t) expath); 22349992Sbostic expath = 0; 22449992Sbostic } 22549992Sbostic else 22649992Sbostic setname(""); 22749992Sbostic if (exerr) 22849992Sbostic stderror(ERR_NAME | ERR_STRING, exerr); 22949992Sbostic stderror(ERR_NAME | ERR_COMMAND); 2301292Sbill } 2311292Sbill 2321292Sbill /* 2331292Sbill * Execute command f, arg list t. 2341292Sbill * Record error message if not found. 2351292Sbill * Also do shell scripts here. 2361292Sbill */ 23749992Sbostic static void 23849992Sbostic texec(sf, st) 23949992Sbostic Char *sf; 24049992Sbostic register Char **st; 2411292Sbill { 24249992Sbostic register char **t; 24349992Sbostic register char *f; 24449992Sbostic register struct varent *v; 24549992Sbostic register Char **vp; 24649992Sbostic Char *lastsh[2]; 24749992Sbostic int fd; 24849992Sbostic unsigned char c; 24949992Sbostic Char *st0, **ost; 2501292Sbill 25149992Sbostic /* The order for the conversions is significant */ 25249992Sbostic t = short2blk(st); 25349992Sbostic f = short2str(sf); 25449992Sbostic Vt = t; 25549992Sbostic errno = 0; /* don't use a previous error */ 25650076Schristos (void) execve(f, t, environ); 25749992Sbostic Vt = 0; 25849992Sbostic blkfree((Char **) t); 25949992Sbostic switch (errno) { 2601292Sbill 26149992Sbostic case ENOEXEC: 26249992Sbostic /* 26349992Sbostic * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute 26449992Sbostic * it, don't feed it to the shell if it looks like a binary! 26549992Sbostic */ 26649992Sbostic if ((fd = open(f, O_RDONLY)) != -1) { 26749992Sbostic if (read(fd, (char *) &c, 1) == 1) { 26849992Sbostic if (!Isprint(c) && (c != '\n' && c != '\t')) { 26949992Sbostic (void) close(fd); 27049992Sbostic /* 27149992Sbostic * We *know* what ENOEXEC means. 27249992Sbostic */ 27349992Sbostic stderror(ERR_ARCH, f, strerror(errno)); 27449992Sbostic } 27549992Sbostic } 27649992Sbostic #ifdef _PATH_BSHELL 27749992Sbostic else 27849992Sbostic c = '#'; 27949992Sbostic #endif 28049992Sbostic (void) close(fd); 28149992Sbostic } 28249992Sbostic /* 28349992Sbostic * If there is an alias for shell, then put the words of the alias in 28449992Sbostic * front of the argument list replacing the command name. Note no 28549992Sbostic * interpretation of the words at this point. 28649992Sbostic */ 28749992Sbostic v = adrof1(STRshell, &aliases); 28849992Sbostic if (v == 0) { 28949992Sbostic vp = lastsh; 29049992Sbostic vp[0] = adrof(STRshell) ? value(STRshell) : STR_SHELLPATH; 29149992Sbostic vp[1] = NULL; 29249992Sbostic #ifdef _PATH_BSHELL 29349992Sbostic if (fd != -1 && c != '#') 29449992Sbostic vp[0] = STR_BSHELL; 29549992Sbostic #endif 29649992Sbostic } 29749992Sbostic else 29849992Sbostic vp = v->vec; 29949992Sbostic st0 = st[0]; 30049992Sbostic st[0] = sf; 30149992Sbostic ost = st; 30249992Sbostic st = blkspl(vp, st); /* Splice up the new arglst */ 30349992Sbostic ost[0] = st0; 30449992Sbostic sf = *st; 30549992Sbostic /* The order for the conversions is significant */ 30649992Sbostic t = short2blk(st); 30749992Sbostic f = short2str(sf); 30849992Sbostic xfree((ptr_t) st); 30949992Sbostic Vt = t; 31050076Schristos (void) execve(f, t, environ); 31149992Sbostic Vt = 0; 31249992Sbostic blkfree((Char **) t); 31349992Sbostic /* The sky is falling, the sky is falling! */ 3141292Sbill 31549992Sbostic case ENOMEM: 31649992Sbostic stderror(ERR_SYSTEM, f, strerror(errno)); 3171292Sbill 31849992Sbostic case ENOENT: 31949992Sbostic break; 3201292Sbill 32149992Sbostic default: 32249992Sbostic if (exerr == 0) { 32349992Sbostic exerr = strerror(errno); 32449992Sbostic if (expath) 32549992Sbostic xfree((ptr_t) expath); 32649992Sbostic expath = Strsave(sf); 32749992Sbostic Vexpath = expath; 3281292Sbill } 32949992Sbostic } 3301292Sbill } 3311292Sbill 33217508Sedward /*ARGSUSED*/ 33349992Sbostic void 33451377Schristos execash(t, kp) 33551377Schristos Char **t; 33651377Schristos register struct command *kp; 3371292Sbill { 33851377Schristos int saveIN, saveOUT, saveDIAG, saveSTD; 33951377Schristos int oSHIN; 34051377Schristos int oSHOUT; 34151377Schristos int oSHERR; 34251377Schristos int oOLDSTD; 34351377Schristos jmp_buf osetexit; 34451377Schristos int my_reenter; 34551377Schristos int odidfds; 34651377Schristos sig_t osigint, osigquit, osigterm; 34751377Schristos 34849992Sbostic if (chkstop == 0 && setintr) 34949992Sbostic panystop(0); 35051377Schristos /* 35151377Schristos * Hmm, we don't really want to do that now because we might 35251377Schristos * fail, but what is the choice 35351377Schristos */ 35449992Sbostic rechist(); 35551377Schristos 35651377Schristos osigint = signal(SIGINT, parintr); 35751377Schristos osigquit = signal(SIGQUIT, parintr); 35851377Schristos osigterm = signal(SIGTERM, parterm); 35951377Schristos 36051377Schristos odidfds = didfds; 36151377Schristos oSHIN = SHIN; 36251377Schristos oSHOUT = SHOUT; 36351377Schristos oSHERR = SHERR; 36451377Schristos oOLDSTD = OLDSTD; 36551377Schristos 36651377Schristos saveIN = dcopy(SHIN, -1); 36751377Schristos saveOUT = dcopy(SHOUT, -1); 36851377Schristos saveDIAG = dcopy(SHERR, -1); 36951377Schristos saveSTD = dcopy(OLDSTD, -1); 37051377Schristos 37151377Schristos lshift(kp->t_dcom, 1); 37251377Schristos 37351377Schristos getexit(osetexit); 37451377Schristos 37551377Schristos if ((my_reenter = setexit()) == 0) { 37651377Schristos SHIN = dcopy(0, -1); 37751377Schristos SHOUT = dcopy(1, -1); 37851377Schristos SHERR = dcopy(2, -1); 37951377Schristos didfds = 0; 38051377Schristos doexec(t, kp); 38151377Schristos } 38251377Schristos 38351377Schristos (void) signal(SIGINT, osigint); 38451377Schristos (void) signal(SIGQUIT, osigquit); 38551377Schristos (void) signal(SIGTERM, osigterm); 38651377Schristos 38751377Schristos doneinp = 0; 38851377Schristos didfds = odidfds; 38951377Schristos (void) close(SHIN); 39051377Schristos (void) close(SHOUT); 39151377Schristos (void) close(SHERR); 39251377Schristos (void) close(OLDSTD); 39351377Schristos SHIN = dmove(saveIN, oSHIN); 39451377Schristos SHOUT = dmove(saveOUT, oSHOUT); 39551377Schristos SHERR = dmove(saveDIAG, oSHERR); 39651377Schristos OLDSTD = dmove(saveSTD, oOLDSTD); 39751377Schristos 39851377Schristos resexit(osetexit); 39951377Schristos if (my_reenter) 40051377Schristos stderror(ERR_SILENT); 4011292Sbill } 4021292Sbill 40349992Sbostic void 4041292Sbill xechoit(t) 40549992Sbostic Char **t; 4061292Sbill { 40749992Sbostic if (adrof(STRecho)) { 40850439Schristos (void) fflush(csherr); 40950439Schristos blkpr(csherr, t); 41050439Schristos (void) fputc('\n', csherr); 41149992Sbostic } 4121292Sbill } 4131292Sbill 41449992Sbostic void 41550439Schristos /*ARGSUSED*/ 41650439Schristos dohash(v, t) 41750439Schristos Char **v; 41850439Schristos struct command *t; 4191292Sbill { 42049992Sbostic DIR *dirp; 42149992Sbostic register struct dirent *dp; 42249992Sbostic register int cnt; 42349992Sbostic int i = 0; 42450439Schristos struct varent *pathv = adrof(STRpath); 42549992Sbostic Char **pv; 42649992Sbostic int hashval; 4271292Sbill 42849992Sbostic havhash = 1; 42949992Sbostic for (cnt = 0; cnt < sizeof xhash; cnt++) 43049992Sbostic xhash[cnt] = 0; 43150439Schristos if (pathv == 0) 43249992Sbostic return; 43350439Schristos for (pv = pathv->vec; *pv; pv++, i++) { 43449992Sbostic if (pv[0][0] != '/') 43549992Sbostic continue; 43649992Sbostic dirp = opendir(short2str(*pv)); 43749992Sbostic if (dirp == NULL) 43849992Sbostic continue; 43949992Sbostic while ((dp = readdir(dirp)) != NULL) { 44049992Sbostic if (dp->d_ino == 0) 44149992Sbostic continue; 44249992Sbostic if (dp->d_name[0] == '.' && 44349992Sbostic (dp->d_name[1] == '\0' || 444*60237Schristos (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) 44549992Sbostic continue; 44649992Sbostic hashval = hash(hashname(str2short(dp->d_name)), i); 44749992Sbostic bis(xhash, hashval); 44849992Sbostic /* tw_add_comm_name (dp->d_name); */ 4491292Sbill } 45049992Sbostic (void) closedir(dirp); 45149992Sbostic } 4521292Sbill } 4531292Sbill 45449992Sbostic void 45550439Schristos /*ARGSUSED*/ 45650439Schristos dounhash(v, t) 45750439Schristos Char **v; 45850439Schristos struct command *t; 4591292Sbill { 46049992Sbostic havhash = 0; 4611292Sbill } 4621292Sbill 46349992Sbostic void 46450439Schristos /*ARGSUSED*/ 46550439Schristos hashstat(v, t) 46650439Schristos Char **v; 46750439Schristos struct command *t; 4681292Sbill { 46949992Sbostic if (hits + misses) 47050439Schristos (void) fprintf(cshout, "%d hits, %d misses, %d%%\n", 47150439Schristos hits, misses, 100 * hits / (hits + misses)); 47249992Sbostic } 4731292Sbill 47417508Sedward /* 47517508Sedward * Hash a command name. 47617508Sedward */ 47749992Sbostic static int 47817508Sedward hashname(cp) 47949992Sbostic register Char *cp; 4801292Sbill { 48149992Sbostic register long h = 0; 4821292Sbill 48349992Sbostic while (*cp) 48449992Sbostic h = hash(h, *cp++); 48549992Sbostic return ((int) h); 4861292Sbill } 48750639Schristos 48850639Schristos static int 48950639Schristos iscommand(name) 49050639Schristos Char *name; 49150639Schristos { 49250639Schristos register Char **pv; 49350639Schristos register Char *sav; 49450639Schristos register struct varent *v; 49550639Schristos register bool slash = any(short2str(name), '/'); 49650639Schristos register int hashval = 0, hashval1, i; 49750639Schristos 49850639Schristos v = adrof(STRpath); 49950639Schristos if (v == 0 || v->vec[0] == 0 || slash) 50050639Schristos pv = justabs; 50150639Schristos else 50250639Schristos pv = v->vec; 50350639Schristos sav = Strspl(STRslash, name); /* / command name for postpending */ 50450639Schristos if (havhash) 50550639Schristos hashval = hashname(name); 50650639Schristos i = 0; 50750639Schristos do { 50850639Schristos if (!slash && pv[0][0] == '/' && havhash) { 50950639Schristos hashval1 = hash(hashval, i); 51050639Schristos if (!bit(xhash, hashval1)) 51150639Schristos goto cont; 51250639Schristos } 51350639Schristos if (pv[0][0] == 0 || eq(pv[0], STRdot)) { /* don't make ./xxx */ 51450639Schristos if (executable(NULL, name, 0)) { 51550639Schristos xfree((ptr_t) sav); 51650639Schristos return i + 1; 51750639Schristos } 51850639Schristos } 51950639Schristos else { 52050639Schristos if (executable(*pv, sav, 0)) { 52150639Schristos xfree((ptr_t) sav); 52250639Schristos return i + 1; 52350639Schristos } 52450639Schristos } 52550639Schristos cont: 52650639Schristos pv++; 52750639Schristos i++; 52850639Schristos } while (*pv); 52950639Schristos xfree((ptr_t) sav); 53050639Schristos return 0; 53150639Schristos } 53250639Schristos 53350639Schristos /* Also by: 53450639Schristos * Andreas Luik <luik@isaak.isa.de> 53550639Schristos * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 53650639Schristos * Azenberstr. 35 53750639Schristos * D-7000 Stuttgart 1 53850639Schristos * West-Germany 53950639Schristos * is the executable() routine below and changes to iscommand(). 54050639Schristos * Thanks again!! 54150639Schristos */ 54250639Schristos 54350639Schristos /* 54450639Schristos * executable() examines the pathname obtained by concatenating dir and name 54550639Schristos * (dir may be NULL), and returns 1 either if it is executable by us, or 54650639Schristos * if dir_ok is set and the pathname refers to a directory. 54750639Schristos * This is a bit kludgy, but in the name of optimization... 54850639Schristos */ 54950639Schristos static int 55050639Schristos executable(dir, name, dir_ok) 55150639Schristos Char *dir, *name; 55250639Schristos bool dir_ok; 55350639Schristos { 55450639Schristos struct stat stbuf; 55550639Schristos Char path[MAXPATHLEN + 1], *dp, *sp; 55650639Schristos char *strname; 55750639Schristos 55850639Schristos if (dir && *dir) { 55950639Schristos for (dp = path, sp = dir; *sp; *dp++ = *sp++) 56050639Schristos if (dp == &path[MAXPATHLEN + 1]) { 56150639Schristos *--dp = '\0'; 56250639Schristos break; 56350639Schristos } 56450639Schristos for (sp = name; *sp; *dp++ = *sp++) 56550639Schristos if (dp == &path[MAXPATHLEN + 1]) { 56650639Schristos *--dp = '\0'; 56750639Schristos break; 56850639Schristos } 56950639Schristos *dp = '\0'; 57050639Schristos strname = short2str(path); 57150639Schristos } 57250639Schristos else 57350639Schristos strname = short2str(name); 57450639Schristos return (stat(strname, &stbuf) != -1 && 57550639Schristos ((S_ISREG(stbuf.st_mode) && 57650639Schristos /* save time by not calling access() in the hopeless case */ 57750639Schristos (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) && 57850639Schristos access(strname, X_OK) == 0) || 57950639Schristos (dir_ok && S_ISDIR(stbuf.st_mode)))); 58050639Schristos } 58150639Schristos 58250639Schristos /* The dowhich() is by: 58350639Schristos * Andreas Luik <luik@isaak.isa.de> 58450639Schristos * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 58550639Schristos * Azenberstr. 35 58650639Schristos * D-7000 Stuttgart 1 58750639Schristos * West-Germany 58850639Schristos * Thanks!! 58950639Schristos */ 59050639Schristos /*ARGSUSED*/ 59150639Schristos void 59250639Schristos dowhich(v, c) 59350639Schristos register Char **v; 59450639Schristos struct command *c; 59550639Schristos { 59650639Schristos struct wordent lex[3]; 59750639Schristos struct varent *vp; 59850639Schristos 59950639Schristos lex[0].next = &lex[1]; 60050639Schristos lex[1].next = &lex[2]; 60150639Schristos lex[2].next = &lex[0]; 60250639Schristos 60350639Schristos lex[0].prev = &lex[2]; 60450639Schristos lex[1].prev = &lex[0]; 60550639Schristos lex[2].prev = &lex[1]; 60650639Schristos 60750639Schristos lex[0].word = STRNULL; 60850639Schristos lex[2].word = STRret; 60950639Schristos 61050639Schristos while (*++v) { 611*60237Schristos if ((vp = adrof1(*v, &aliases)) != NULL) { 61251589Schristos (void) fprintf(cshout, "%s: \t aliased to ", vis_str(*v)); 61350639Schristos blkpr(cshout, vp->vec); 61450639Schristos (void) fputc('\n', cshout); 61550639Schristos } 61650639Schristos else { 61750639Schristos lex[1].word = *v; 61850639Schristos tellmewhat(lex); 61950639Schristos } 62050639Schristos } 62150639Schristos } 62250639Schristos 62350639Schristos static void 62450639Schristos tellmewhat(lex) 62550639Schristos struct wordent *lex; 62650639Schristos { 62750639Schristos register int i; 62850639Schristos register struct biltins *bptr; 62950639Schristos register struct wordent *sp = lex->next; 63050639Schristos bool aliased = 0; 63150639Schristos Char *s0, *s1, *s2; 63250639Schristos Char qc; 63350639Schristos 63450639Schristos if (adrof1(sp->word, &aliases)) { 63550639Schristos alias(lex); 63650639Schristos sp = lex->next; 63750639Schristos aliased = 1; 63850639Schristos } 63950639Schristos 64050639Schristos s0 = sp->word; /* to get the memory freeing right... */ 64150639Schristos 64250639Schristos /* handle quoted alias hack */ 64350639Schristos if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE) 64450639Schristos (sp->word)++; 64550639Schristos 64650639Schristos /* do quoting, if it hasn't been done */ 64750639Schristos s1 = s2 = sp->word; 64850639Schristos while (*s2) 64950639Schristos switch (*s2) { 65050639Schristos case '\'': 65150639Schristos case '"': 65250639Schristos qc = *s2++; 65350639Schristos while (*s2 && *s2 != qc) 65450639Schristos *s1++ = *s2++ | QUOTE; 65550639Schristos if (*s2) 65650639Schristos s2++; 65750639Schristos break; 65850639Schristos case '\\': 65950639Schristos if (*++s2) 66050639Schristos *s1++ = *s2++ | QUOTE; 66150639Schristos break; 66250639Schristos default: 66350639Schristos *s1++ = *s2++; 66450639Schristos } 66550639Schristos *s1 = '\0'; 66650639Schristos 66750639Schristos for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) { 66850639Schristos if (eq(sp->word, str2short(bptr->bname))) { 66950639Schristos if (aliased) 67050639Schristos prlex(cshout, lex); 67150639Schristos (void) fprintf(cshout, "%s: shell built-in command.\n", 67251589Schristos vis_str(sp->word)); 67350639Schristos sp->word = s0; /* we save and then restore this */ 67450639Schristos return; 67550639Schristos } 67650639Schristos } 67750639Schristos 678*60237Schristos if ((i = iscommand(strip(sp->word))) != 0) { 67950639Schristos register Char **pv; 68050639Schristos register struct varent *v; 68150639Schristos bool slash = any(short2str(sp->word), '/'); 68250639Schristos 68350639Schristos v = adrof(STRpath); 68450639Schristos if (v == 0 || v->vec[0] == 0 || slash) 68550639Schristos pv = justabs; 68650639Schristos else 68750639Schristos pv = v->vec; 68850639Schristos 68950639Schristos while (--i) 69050639Schristos pv++; 69150639Schristos if (pv[0][0] == 0 || eq(pv[0], STRdot)) { 69250639Schristos sp->word = Strspl(STRdotsl, sp->word); 69350639Schristos prlex(cshout, lex); 69450639Schristos xfree((ptr_t) sp->word); 69550639Schristos sp->word = s0; /* we save and then restore this */ 69650639Schristos return; 69750639Schristos } 69850639Schristos s1 = Strspl(*pv, STRslash); 69950639Schristos sp->word = Strspl(s1, sp->word); 70050639Schristos xfree((ptr_t) s1); 70150639Schristos prlex(cshout, lex); 70250639Schristos xfree((ptr_t) sp->word); 70350639Schristos } 70450639Schristos else { 70550639Schristos if (aliased) 70650639Schristos prlex(cshout, lex); 70751589Schristos (void) fprintf(csherr, "%s: Command not found.\n", vis_str(sp->word)); 70850639Schristos } 70950639Schristos sp->word = s0; /* we save and then restore this */ 71050639Schristos } 711