147738Sbostic /*- 260765Sbostic * Copyright (c) 1980, 1991, 1993 360765Sbostic * The Regents of the University of California. All rights reserved. 447738Sbostic * 547738Sbostic * %sccs.include.redist.c% 621930Sdist */ 721930Sdist 817508Sedward #ifndef lint 9*68576Schristos static char sccsid[] = "@(#)exec.c 8.2 (Berkeley) 03/22/95"; 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 6660237Schristos #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]; 93*68576Schristos sigset_t sigset; 941292Sbill 9549992Sbostic /* 9649992Sbostic * Glob the command name. We will search $path even if this does something, 9749992Sbostic * as in sh but not in csh. One special case: if there is no PATH, then we 9849992Sbostic * execute only commands which start with '/'. 9949992Sbostic */ 10049992Sbostic blk[0] = t->t_dcom[0]; 10149992Sbostic blk[1] = 0; 10249992Sbostic gflag = 0, tglob(blk); 10349992Sbostic if (gflag) { 10449992Sbostic pv = globall(blk); 10549992Sbostic if (pv == 0) { 10651589Schristos setname(vis_str(blk[0])); 10749992Sbostic stderror(ERR_NAME | ERR_NOMATCH); 10849992Sbostic } 10949992Sbostic gargv = 0; 11049992Sbostic } 11149992Sbostic else 11249992Sbostic pv = saveblk(blk); 1131292Sbill 11449992Sbostic trim(pv); 11549992Sbostic 11649992Sbostic exerr = 0; 11749992Sbostic expath = Strsave(pv[0]); 11849992Sbostic Vexpath = expath; 1191292Sbill 12050439Schristos pathv = adrof(STRpath); 12150439Schristos if (pathv == 0 && expath[0] != '/') { 12249992Sbostic blkfree(pv); 12349992Sbostic pexerr(); 12449992Sbostic } 12549992Sbostic slash = any(short2str(expath), '/'); 1261292Sbill 12749992Sbostic /* 12849992Sbostic * Glob the argument list, if necessary. Otherwise trim off the quote bits. 12949992Sbostic */ 13049992Sbostic gflag = 0; 13149992Sbostic av = &t->t_dcom[1]; 13249992Sbostic tglob(av); 13349992Sbostic if (gflag) { 13449992Sbostic av = globall(av); 13549992Sbostic if (av == 0) { 13649992Sbostic blkfree(pv); 13751589Schristos setname(vis_str(expath)); 13849992Sbostic stderror(ERR_NAME | ERR_NOMATCH); 13949992Sbostic } 14049992Sbostic gargv = 0; 14149992Sbostic } 14249992Sbostic else 14349992Sbostic av = saveblk(av); 1441292Sbill 14549992Sbostic blkfree(t->t_dcom); 14649992Sbostic t->t_dcom = blkspl(pv, av); 14749992Sbostic xfree((ptr_t) pv); 14849992Sbostic xfree((ptr_t) av); 14949992Sbostic av = t->t_dcom; 15049992Sbostic trim(av); 15149992Sbostic 15250024Schristos if (*av == NULL || **av == '\0') 15349992Sbostic pexerr(); 15449992Sbostic 15549992Sbostic xechoit(av); /* Echo command if -x */ 15649992Sbostic /* 15749992Sbostic * Since all internal file descriptors are set to close on exec, we don't 15849992Sbostic * need to close them explicitly here. Just reorient ourselves for error 15949992Sbostic * messages. 16049992Sbostic */ 16149992Sbostic SHIN = 0; 16249992Sbostic SHOUT = 1; 16350439Schristos SHERR = 2; 16449992Sbostic OLDSTD = 0; 16549992Sbostic /* 16649992Sbostic * We must do this AFTER any possible forking (like `foo` in glob) so that 16749992Sbostic * this shell can still do subprocesses. 16849992Sbostic */ 169*68576Schristos sigemptyset(&sigset); 170*68576Schristos sigprocmask(SIG_SETMASK, &sigset, NULL); 17149992Sbostic /* 17249992Sbostic * If no path, no words in path, or a / in the filename then restrict the 17349992Sbostic * command search. 17449992Sbostic */ 17550439Schristos if (pathv == 0 || pathv->vec[0] == 0 || slash) 17649992Sbostic pv = justabs; 17749992Sbostic else 17850439Schristos pv = pathv->vec; 17949992Sbostic sav = Strspl(STRslash, *av);/* / command name for postpending */ 18049992Sbostic Vsav = sav; 18149992Sbostic if (havhash) 18249992Sbostic hashval = hashname(*av); 18349992Sbostic i = 0; 18449992Sbostic hits++; 18549992Sbostic do { 18649992Sbostic /* 18749992Sbostic * Try to save time by looking at the hash table for where this command 18849992Sbostic * could be. If we are doing delayed hashing, then we put the names in 18949992Sbostic * one at a time, as the user enters them. This is kinda like Korn 19049992Sbostic * Shell's "tracked aliases". 19149992Sbostic */ 19249992Sbostic if (!slash && pv[0][0] == '/' && havhash) { 19349992Sbostic hashval1 = hash(hashval, i); 19449992Sbostic if (!bit(xhash, hashval1)) 19549992Sbostic goto cont; 19649992Sbostic } 19749992Sbostic if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */ 19849992Sbostic texec(*av, av); 19949992Sbostic else { 20049992Sbostic dp = Strspl(*pv, sav); 20149992Sbostic Vdp = dp; 20249992Sbostic texec(dp, av); 20349992Sbostic Vdp = 0; 20449992Sbostic xfree((ptr_t) dp); 20549992Sbostic } 20649992Sbostic misses++; 2071292Sbill cont: 20849992Sbostic pv++; 20949992Sbostic i++; 21049992Sbostic } while (*pv); 21149992Sbostic hits--; 21249992Sbostic Vsav = 0; 21349992Sbostic xfree((ptr_t) sav); 21449992Sbostic pexerr(); 2151292Sbill } 2161292Sbill 21749992Sbostic static void 2181292Sbill pexerr() 2191292Sbill { 22049992Sbostic /* Couldn't find the damn thing */ 22149992Sbostic if (expath) { 22251589Schristos setname(vis_str(expath)); 22349992Sbostic Vexpath = 0; 22449992Sbostic xfree((ptr_t) expath); 22549992Sbostic expath = 0; 22649992Sbostic } 22749992Sbostic else 22849992Sbostic setname(""); 22949992Sbostic if (exerr) 23049992Sbostic stderror(ERR_NAME | ERR_STRING, exerr); 23149992Sbostic stderror(ERR_NAME | ERR_COMMAND); 2321292Sbill } 2331292Sbill 2341292Sbill /* 2351292Sbill * Execute command f, arg list t. 2361292Sbill * Record error message if not found. 2371292Sbill * Also do shell scripts here. 2381292Sbill */ 23949992Sbostic static void 24049992Sbostic texec(sf, st) 24149992Sbostic Char *sf; 24249992Sbostic register Char **st; 2431292Sbill { 24449992Sbostic register char **t; 24549992Sbostic register char *f; 24649992Sbostic register struct varent *v; 24749992Sbostic register Char **vp; 24849992Sbostic Char *lastsh[2]; 24949992Sbostic int fd; 25049992Sbostic unsigned char c; 25149992Sbostic Char *st0, **ost; 2521292Sbill 25349992Sbostic /* The order for the conversions is significant */ 25449992Sbostic t = short2blk(st); 25549992Sbostic f = short2str(sf); 25649992Sbostic Vt = t; 25749992Sbostic errno = 0; /* don't use a previous error */ 25850076Schristos (void) execve(f, t, environ); 25949992Sbostic Vt = 0; 26049992Sbostic blkfree((Char **) t); 26149992Sbostic switch (errno) { 2621292Sbill 26349992Sbostic case ENOEXEC: 26449992Sbostic /* 26549992Sbostic * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute 26649992Sbostic * it, don't feed it to the shell if it looks like a binary! 26749992Sbostic */ 26849992Sbostic if ((fd = open(f, O_RDONLY)) != -1) { 26949992Sbostic if (read(fd, (char *) &c, 1) == 1) { 27049992Sbostic if (!Isprint(c) && (c != '\n' && c != '\t')) { 27149992Sbostic (void) close(fd); 27249992Sbostic /* 27349992Sbostic * We *know* what ENOEXEC means. 27449992Sbostic */ 27549992Sbostic stderror(ERR_ARCH, f, strerror(errno)); 27649992Sbostic } 27749992Sbostic } 27849992Sbostic #ifdef _PATH_BSHELL 27949992Sbostic else 28049992Sbostic c = '#'; 28149992Sbostic #endif 28249992Sbostic (void) close(fd); 28349992Sbostic } 28449992Sbostic /* 28549992Sbostic * If there is an alias for shell, then put the words of the alias in 28649992Sbostic * front of the argument list replacing the command name. Note no 28749992Sbostic * interpretation of the words at this point. 28849992Sbostic */ 28949992Sbostic v = adrof1(STRshell, &aliases); 29049992Sbostic if (v == 0) { 29149992Sbostic vp = lastsh; 29249992Sbostic vp[0] = adrof(STRshell) ? value(STRshell) : STR_SHELLPATH; 29349992Sbostic vp[1] = NULL; 29449992Sbostic #ifdef _PATH_BSHELL 29549992Sbostic if (fd != -1 && c != '#') 29649992Sbostic vp[0] = STR_BSHELL; 29749992Sbostic #endif 29849992Sbostic } 29949992Sbostic else 30049992Sbostic vp = v->vec; 30149992Sbostic st0 = st[0]; 30249992Sbostic st[0] = sf; 30349992Sbostic ost = st; 30449992Sbostic st = blkspl(vp, st); /* Splice up the new arglst */ 30549992Sbostic ost[0] = st0; 30649992Sbostic sf = *st; 30749992Sbostic /* The order for the conversions is significant */ 30849992Sbostic t = short2blk(st); 30949992Sbostic f = short2str(sf); 31049992Sbostic xfree((ptr_t) st); 31149992Sbostic Vt = t; 31250076Schristos (void) execve(f, t, environ); 31349992Sbostic Vt = 0; 31449992Sbostic blkfree((Char **) t); 31549992Sbostic /* The sky is falling, the sky is falling! */ 3161292Sbill 31749992Sbostic case ENOMEM: 31849992Sbostic stderror(ERR_SYSTEM, f, strerror(errno)); 3191292Sbill 32049992Sbostic case ENOENT: 32149992Sbostic break; 3221292Sbill 32349992Sbostic default: 32449992Sbostic if (exerr == 0) { 32549992Sbostic exerr = strerror(errno); 32649992Sbostic if (expath) 32749992Sbostic xfree((ptr_t) expath); 32849992Sbostic expath = Strsave(sf); 32949992Sbostic Vexpath = expath; 3301292Sbill } 33149992Sbostic } 3321292Sbill } 3331292Sbill 33417508Sedward /*ARGSUSED*/ 33549992Sbostic void 33651377Schristos execash(t, kp) 33751377Schristos Char **t; 33851377Schristos register struct command *kp; 3391292Sbill { 34051377Schristos int saveIN, saveOUT, saveDIAG, saveSTD; 34151377Schristos int oSHIN; 34251377Schristos int oSHOUT; 34351377Schristos int oSHERR; 34451377Schristos int oOLDSTD; 34551377Schristos jmp_buf osetexit; 34651377Schristos int my_reenter; 34751377Schristos int odidfds; 34851377Schristos sig_t osigint, osigquit, osigterm; 34951377Schristos 35049992Sbostic if (chkstop == 0 && setintr) 35149992Sbostic panystop(0); 35251377Schristos /* 35351377Schristos * Hmm, we don't really want to do that now because we might 35451377Schristos * fail, but what is the choice 35551377Schristos */ 35649992Sbostic rechist(); 35751377Schristos 35851377Schristos osigint = signal(SIGINT, parintr); 35951377Schristos osigquit = signal(SIGQUIT, parintr); 36051377Schristos osigterm = signal(SIGTERM, parterm); 36151377Schristos 36251377Schristos odidfds = didfds; 36351377Schristos oSHIN = SHIN; 36451377Schristos oSHOUT = SHOUT; 36551377Schristos oSHERR = SHERR; 36651377Schristos oOLDSTD = OLDSTD; 36751377Schristos 36851377Schristos saveIN = dcopy(SHIN, -1); 36951377Schristos saveOUT = dcopy(SHOUT, -1); 37051377Schristos saveDIAG = dcopy(SHERR, -1); 37151377Schristos saveSTD = dcopy(OLDSTD, -1); 37251377Schristos 37351377Schristos lshift(kp->t_dcom, 1); 37451377Schristos 37551377Schristos getexit(osetexit); 37651377Schristos 37751377Schristos if ((my_reenter = setexit()) == 0) { 37851377Schristos SHIN = dcopy(0, -1); 37951377Schristos SHOUT = dcopy(1, -1); 38051377Schristos SHERR = dcopy(2, -1); 38151377Schristos didfds = 0; 38251377Schristos doexec(t, kp); 38351377Schristos } 38451377Schristos 38551377Schristos (void) signal(SIGINT, osigint); 38651377Schristos (void) signal(SIGQUIT, osigquit); 38751377Schristos (void) signal(SIGTERM, osigterm); 38851377Schristos 38951377Schristos doneinp = 0; 39051377Schristos didfds = odidfds; 39151377Schristos (void) close(SHIN); 39251377Schristos (void) close(SHOUT); 39351377Schristos (void) close(SHERR); 39451377Schristos (void) close(OLDSTD); 39551377Schristos SHIN = dmove(saveIN, oSHIN); 39651377Schristos SHOUT = dmove(saveOUT, oSHOUT); 39751377Schristos SHERR = dmove(saveDIAG, oSHERR); 39851377Schristos OLDSTD = dmove(saveSTD, oOLDSTD); 39951377Schristos 40051377Schristos resexit(osetexit); 40151377Schristos if (my_reenter) 40251377Schristos stderror(ERR_SILENT); 4031292Sbill } 4041292Sbill 40549992Sbostic void 4061292Sbill xechoit(t) 40749992Sbostic Char **t; 4081292Sbill { 40949992Sbostic if (adrof(STRecho)) { 41050439Schristos (void) fflush(csherr); 41150439Schristos blkpr(csherr, t); 41250439Schristos (void) fputc('\n', csherr); 41349992Sbostic } 4141292Sbill } 4151292Sbill 41649992Sbostic void 41750439Schristos /*ARGSUSED*/ 41850439Schristos dohash(v, t) 41950439Schristos Char **v; 42050439Schristos struct command *t; 4211292Sbill { 42249992Sbostic DIR *dirp; 42349992Sbostic register struct dirent *dp; 42449992Sbostic register int cnt; 42549992Sbostic int i = 0; 42650439Schristos struct varent *pathv = adrof(STRpath); 42749992Sbostic Char **pv; 42849992Sbostic int hashval; 4291292Sbill 43049992Sbostic havhash = 1; 43149992Sbostic for (cnt = 0; cnt < sizeof xhash; cnt++) 43249992Sbostic xhash[cnt] = 0; 43350439Schristos if (pathv == 0) 43449992Sbostic return; 43550439Schristos for (pv = pathv->vec; *pv; pv++, i++) { 43649992Sbostic if (pv[0][0] != '/') 43749992Sbostic continue; 43849992Sbostic dirp = opendir(short2str(*pv)); 43949992Sbostic if (dirp == NULL) 44049992Sbostic continue; 44149992Sbostic while ((dp = readdir(dirp)) != NULL) { 44249992Sbostic if (dp->d_ino == 0) 44349992Sbostic continue; 44449992Sbostic if (dp->d_name[0] == '.' && 44549992Sbostic (dp->d_name[1] == '\0' || 44660237Schristos (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) 44749992Sbostic continue; 44849992Sbostic hashval = hash(hashname(str2short(dp->d_name)), i); 44949992Sbostic bis(xhash, hashval); 45049992Sbostic /* tw_add_comm_name (dp->d_name); */ 4511292Sbill } 45249992Sbostic (void) closedir(dirp); 45349992Sbostic } 4541292Sbill } 4551292Sbill 45649992Sbostic void 45750439Schristos /*ARGSUSED*/ 45850439Schristos dounhash(v, t) 45950439Schristos Char **v; 46050439Schristos struct command *t; 4611292Sbill { 46249992Sbostic havhash = 0; 4631292Sbill } 4641292Sbill 46549992Sbostic void 46650439Schristos /*ARGSUSED*/ 46750439Schristos hashstat(v, t) 46850439Schristos Char **v; 46950439Schristos struct command *t; 4701292Sbill { 47149992Sbostic if (hits + misses) 47250439Schristos (void) fprintf(cshout, "%d hits, %d misses, %d%%\n", 47350439Schristos hits, misses, 100 * hits / (hits + misses)); 47449992Sbostic } 4751292Sbill 47617508Sedward /* 47717508Sedward * Hash a command name. 47817508Sedward */ 47949992Sbostic static int 48017508Sedward hashname(cp) 48149992Sbostic register Char *cp; 4821292Sbill { 48349992Sbostic register long h = 0; 4841292Sbill 48549992Sbostic while (*cp) 48649992Sbostic h = hash(h, *cp++); 48749992Sbostic return ((int) h); 4881292Sbill } 48950639Schristos 49050639Schristos static int 49150639Schristos iscommand(name) 49250639Schristos Char *name; 49350639Schristos { 49450639Schristos register Char **pv; 49550639Schristos register Char *sav; 49650639Schristos register struct varent *v; 49750639Schristos register bool slash = any(short2str(name), '/'); 49850639Schristos register int hashval = 0, hashval1, i; 49950639Schristos 50050639Schristos v = adrof(STRpath); 50150639Schristos if (v == 0 || v->vec[0] == 0 || slash) 50250639Schristos pv = justabs; 50350639Schristos else 50450639Schristos pv = v->vec; 50550639Schristos sav = Strspl(STRslash, name); /* / command name for postpending */ 50650639Schristos if (havhash) 50750639Schristos hashval = hashname(name); 50850639Schristos i = 0; 50950639Schristos do { 51050639Schristos if (!slash && pv[0][0] == '/' && havhash) { 51150639Schristos hashval1 = hash(hashval, i); 51250639Schristos if (!bit(xhash, hashval1)) 51350639Schristos goto cont; 51450639Schristos } 51550639Schristos if (pv[0][0] == 0 || eq(pv[0], STRdot)) { /* don't make ./xxx */ 51650639Schristos if (executable(NULL, name, 0)) { 51750639Schristos xfree((ptr_t) sav); 51850639Schristos return i + 1; 51950639Schristos } 52050639Schristos } 52150639Schristos else { 52250639Schristos if (executable(*pv, sav, 0)) { 52350639Schristos xfree((ptr_t) sav); 52450639Schristos return i + 1; 52550639Schristos } 52650639Schristos } 52750639Schristos cont: 52850639Schristos pv++; 52950639Schristos i++; 53050639Schristos } while (*pv); 53150639Schristos xfree((ptr_t) sav); 53250639Schristos return 0; 53350639Schristos } 53450639Schristos 53550639Schristos /* Also by: 53650639Schristos * Andreas Luik <luik@isaak.isa.de> 53750639Schristos * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 53850639Schristos * Azenberstr. 35 53950639Schristos * D-7000 Stuttgart 1 54050639Schristos * West-Germany 54150639Schristos * is the executable() routine below and changes to iscommand(). 54250639Schristos * Thanks again!! 54350639Schristos */ 54450639Schristos 54550639Schristos /* 54650639Schristos * executable() examines the pathname obtained by concatenating dir and name 54750639Schristos * (dir may be NULL), and returns 1 either if it is executable by us, or 54850639Schristos * if dir_ok is set and the pathname refers to a directory. 54950639Schristos * This is a bit kludgy, but in the name of optimization... 55050639Schristos */ 55150639Schristos static int 55250639Schristos executable(dir, name, dir_ok) 55350639Schristos Char *dir, *name; 55450639Schristos bool dir_ok; 55550639Schristos { 55650639Schristos struct stat stbuf; 55750639Schristos Char path[MAXPATHLEN + 1], *dp, *sp; 55850639Schristos char *strname; 55950639Schristos 56050639Schristos if (dir && *dir) { 56150639Schristos for (dp = path, sp = dir; *sp; *dp++ = *sp++) 56250639Schristos if (dp == &path[MAXPATHLEN + 1]) { 56350639Schristos *--dp = '\0'; 56450639Schristos break; 56550639Schristos } 56650639Schristos for (sp = name; *sp; *dp++ = *sp++) 56750639Schristos if (dp == &path[MAXPATHLEN + 1]) { 56850639Schristos *--dp = '\0'; 56950639Schristos break; 57050639Schristos } 57150639Schristos *dp = '\0'; 57250639Schristos strname = short2str(path); 57350639Schristos } 57450639Schristos else 57550639Schristos strname = short2str(name); 57650639Schristos return (stat(strname, &stbuf) != -1 && 57750639Schristos ((S_ISREG(stbuf.st_mode) && 57850639Schristos /* save time by not calling access() in the hopeless case */ 57950639Schristos (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) && 58050639Schristos access(strname, X_OK) == 0) || 58150639Schristos (dir_ok && S_ISDIR(stbuf.st_mode)))); 58250639Schristos } 58350639Schristos 58450639Schristos /* The dowhich() is by: 58550639Schristos * Andreas Luik <luik@isaak.isa.de> 58650639Schristos * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 58750639Schristos * Azenberstr. 35 58850639Schristos * D-7000 Stuttgart 1 58950639Schristos * West-Germany 59050639Schristos * Thanks!! 59150639Schristos */ 59250639Schristos /*ARGSUSED*/ 59350639Schristos void 59450639Schristos dowhich(v, c) 59550639Schristos register Char **v; 59650639Schristos struct command *c; 59750639Schristos { 59850639Schristos struct wordent lex[3]; 59950639Schristos struct varent *vp; 60050639Schristos 60150639Schristos lex[0].next = &lex[1]; 60250639Schristos lex[1].next = &lex[2]; 60350639Schristos lex[2].next = &lex[0]; 60450639Schristos 60550639Schristos lex[0].prev = &lex[2]; 60650639Schristos lex[1].prev = &lex[0]; 60750639Schristos lex[2].prev = &lex[1]; 60850639Schristos 60950639Schristos lex[0].word = STRNULL; 61050639Schristos lex[2].word = STRret; 61150639Schristos 61250639Schristos while (*++v) { 61360237Schristos if ((vp = adrof1(*v, &aliases)) != NULL) { 61451589Schristos (void) fprintf(cshout, "%s: \t aliased to ", vis_str(*v)); 61550639Schristos blkpr(cshout, vp->vec); 61650639Schristos (void) fputc('\n', cshout); 61750639Schristos } 61850639Schristos else { 61950639Schristos lex[1].word = *v; 62050639Schristos tellmewhat(lex); 62150639Schristos } 62250639Schristos } 62350639Schristos } 62450639Schristos 62550639Schristos static void 62650639Schristos tellmewhat(lex) 62750639Schristos struct wordent *lex; 62850639Schristos { 62950639Schristos register int i; 63050639Schristos register struct biltins *bptr; 63150639Schristos register struct wordent *sp = lex->next; 63250639Schristos bool aliased = 0; 63350639Schristos Char *s0, *s1, *s2; 63450639Schristos Char qc; 63550639Schristos 63650639Schristos if (adrof1(sp->word, &aliases)) { 63750639Schristos alias(lex); 63850639Schristos sp = lex->next; 63950639Schristos aliased = 1; 64050639Schristos } 64150639Schristos 64250639Schristos s0 = sp->word; /* to get the memory freeing right... */ 64350639Schristos 64450639Schristos /* handle quoted alias hack */ 64550639Schristos if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE) 64650639Schristos (sp->word)++; 64750639Schristos 64850639Schristos /* do quoting, if it hasn't been done */ 64950639Schristos s1 = s2 = sp->word; 65050639Schristos while (*s2) 65150639Schristos switch (*s2) { 65250639Schristos case '\'': 65350639Schristos case '"': 65450639Schristos qc = *s2++; 65550639Schristos while (*s2 && *s2 != qc) 65650639Schristos *s1++ = *s2++ | QUOTE; 65750639Schristos if (*s2) 65850639Schristos s2++; 65950639Schristos break; 66050639Schristos case '\\': 66150639Schristos if (*++s2) 66250639Schristos *s1++ = *s2++ | QUOTE; 66350639Schristos break; 66450639Schristos default: 66550639Schristos *s1++ = *s2++; 66650639Schristos } 66750639Schristos *s1 = '\0'; 66850639Schristos 66950639Schristos for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) { 67050639Schristos if (eq(sp->word, str2short(bptr->bname))) { 67150639Schristos if (aliased) 67250639Schristos prlex(cshout, lex); 67350639Schristos (void) fprintf(cshout, "%s: shell built-in command.\n", 67451589Schristos vis_str(sp->word)); 67550639Schristos sp->word = s0; /* we save and then restore this */ 67650639Schristos return; 67750639Schristos } 67850639Schristos } 67950639Schristos 68060237Schristos if ((i = iscommand(strip(sp->word))) != 0) { 68150639Schristos register Char **pv; 68250639Schristos register struct varent *v; 68350639Schristos bool slash = any(short2str(sp->word), '/'); 68450639Schristos 68550639Schristos v = adrof(STRpath); 68650639Schristos if (v == 0 || v->vec[0] == 0 || slash) 68750639Schristos pv = justabs; 68850639Schristos else 68950639Schristos pv = v->vec; 69050639Schristos 69150639Schristos while (--i) 69250639Schristos pv++; 69350639Schristos if (pv[0][0] == 0 || eq(pv[0], STRdot)) { 69450639Schristos sp->word = Strspl(STRdotsl, sp->word); 69550639Schristos prlex(cshout, lex); 69650639Schristos xfree((ptr_t) sp->word); 69750639Schristos sp->word = s0; /* we save and then restore this */ 69850639Schristos return; 69950639Schristos } 70050639Schristos s1 = Strspl(*pv, STRslash); 70150639Schristos sp->word = Strspl(s1, sp->word); 70250639Schristos xfree((ptr_t) s1); 70350639Schristos prlex(cshout, lex); 70450639Schristos xfree((ptr_t) sp->word); 70550639Schristos } 70650639Schristos else { 70750639Schristos if (aliased) 70850639Schristos prlex(cshout, lex); 70951589Schristos (void) fprintf(csherr, "%s: Command not found.\n", vis_str(sp->word)); 71050639Schristos } 71150639Schristos sp->word = s0; /* we save and then restore this */ 71250639Schristos } 713