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*50639Schristos static char sccsid[] = "@(#)exec.c 5.19 (Berkeley) 07/28/91"; 1047738Sbostic #endif /* not lint */ 111292Sbill 1250028Sbostic #include <sys/types.h> 13*50639Schristos #include <sys/param.h> 1450028Sbostic #include <dirent.h> 1550028Sbostic #include <fcntl.h> 16*50639Schristos #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 6617508Sedward #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 *)); 77*50639Schristos static void tellmewhat __P((struct wordent *)); 78*50639Schristos static int executable __P((Char *, Char *, bool)); 79*50639Schristos static int iscommand __P((Char *)); 8049992Sbostic 81*50639Schristos 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) { 10549992Sbostic setname(short2str(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); 13649992Sbostic setname(short2str(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) { 22049992Sbostic setname(short2str(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 33450439Schristos execash(v, t) 33550439Schristos Char **v; 33650439Schristos register struct command *t; 3371292Sbill { 33849992Sbostic if (chkstop == 0 && setintr) 33949992Sbostic panystop(0); 34049992Sbostic rechist(); 34149992Sbostic (void) signal(SIGINT, parintr); 34249992Sbostic (void) signal(SIGQUIT, parintr); 34349992Sbostic (void) signal(SIGTERM, parterm); /* if doexec loses, screw */ 34450439Schristos lshift(t->t_dcom, 1); 34549992Sbostic exiterr = 1; 34650439Schristos doexec(NULL, t); 34749992Sbostic /* NOTREACHED */ 3481292Sbill } 3491292Sbill 35049992Sbostic void 3511292Sbill xechoit(t) 35249992Sbostic Char **t; 3531292Sbill { 35449992Sbostic if (adrof(STRecho)) { 35550439Schristos (void) fflush(csherr); 35650439Schristos blkpr(csherr, t); 35750439Schristos (void) fputc('\n', csherr); 35849992Sbostic } 3591292Sbill } 3601292Sbill 36149992Sbostic void 36250439Schristos /*ARGSUSED*/ 36350439Schristos dohash(v, t) 36450439Schristos Char **v; 36550439Schristos struct command *t; 3661292Sbill { 36749992Sbostic DIR *dirp; 36849992Sbostic register struct dirent *dp; 36949992Sbostic register int cnt; 37049992Sbostic int i = 0; 37150439Schristos struct varent *pathv = adrof(STRpath); 37249992Sbostic Char **pv; 37349992Sbostic int hashval; 3741292Sbill 37549992Sbostic havhash = 1; 37649992Sbostic for (cnt = 0; cnt < sizeof xhash; cnt++) 37749992Sbostic xhash[cnt] = 0; 37850439Schristos if (pathv == 0) 37949992Sbostic return; 38050439Schristos for (pv = pathv->vec; *pv; pv++, i++) { 38149992Sbostic if (pv[0][0] != '/') 38249992Sbostic continue; 38349992Sbostic dirp = opendir(short2str(*pv)); 38449992Sbostic if (dirp == NULL) 38549992Sbostic continue; 38649992Sbostic while ((dp = readdir(dirp)) != NULL) { 38749992Sbostic if (dp->d_ino == 0) 38849992Sbostic continue; 38949992Sbostic if (dp->d_name[0] == '.' && 39049992Sbostic (dp->d_name[1] == '\0' || 39149992Sbostic dp->d_name[1] == '.' && dp->d_name[2] == '\0')) 39249992Sbostic continue; 39349992Sbostic hashval = hash(hashname(str2short(dp->d_name)), i); 39449992Sbostic bis(xhash, hashval); 39549992Sbostic /* tw_add_comm_name (dp->d_name); */ 3961292Sbill } 39749992Sbostic (void) closedir(dirp); 39849992Sbostic } 3991292Sbill } 4001292Sbill 40149992Sbostic void 40250439Schristos /*ARGSUSED*/ 40350439Schristos dounhash(v, t) 40450439Schristos Char **v; 40550439Schristos struct command *t; 4061292Sbill { 40749992Sbostic havhash = 0; 4081292Sbill } 4091292Sbill 41049992Sbostic void 41150439Schristos /*ARGSUSED*/ 41250439Schristos hashstat(v, t) 41350439Schristos Char **v; 41450439Schristos struct command *t; 4151292Sbill { 41649992Sbostic if (hits + misses) 41750439Schristos (void) fprintf(cshout, "%d hits, %d misses, %d%%\n", 41850439Schristos hits, misses, 100 * hits / (hits + misses)); 41949992Sbostic } 4201292Sbill 42117508Sedward /* 42217508Sedward * Hash a command name. 42317508Sedward */ 42449992Sbostic static int 42517508Sedward hashname(cp) 42649992Sbostic register Char *cp; 4271292Sbill { 42849992Sbostic register long h = 0; 4291292Sbill 43049992Sbostic while (*cp) 43149992Sbostic h = hash(h, *cp++); 43249992Sbostic return ((int) h); 4331292Sbill } 434*50639Schristos 435*50639Schristos static int 436*50639Schristos iscommand(name) 437*50639Schristos Char *name; 438*50639Schristos { 439*50639Schristos register Char **pv; 440*50639Schristos register Char *sav; 441*50639Schristos register struct varent *v; 442*50639Schristos register bool slash = any(short2str(name), '/'); 443*50639Schristos register int hashval = 0, hashval1, i; 444*50639Schristos 445*50639Schristos v = adrof(STRpath); 446*50639Schristos if (v == 0 || v->vec[0] == 0 || slash) 447*50639Schristos pv = justabs; 448*50639Schristos else 449*50639Schristos pv = v->vec; 450*50639Schristos sav = Strspl(STRslash, name); /* / command name for postpending */ 451*50639Schristos if (havhash) 452*50639Schristos hashval = hashname(name); 453*50639Schristos i = 0; 454*50639Schristos do { 455*50639Schristos if (!slash && pv[0][0] == '/' && havhash) { 456*50639Schristos hashval1 = hash(hashval, i); 457*50639Schristos if (!bit(xhash, hashval1)) 458*50639Schristos goto cont; 459*50639Schristos } 460*50639Schristos if (pv[0][0] == 0 || eq(pv[0], STRdot)) { /* don't make ./xxx */ 461*50639Schristos if (executable(NULL, name, 0)) { 462*50639Schristos xfree((ptr_t) sav); 463*50639Schristos return i + 1; 464*50639Schristos } 465*50639Schristos } 466*50639Schristos else { 467*50639Schristos if (executable(*pv, sav, 0)) { 468*50639Schristos xfree((ptr_t) sav); 469*50639Schristos return i + 1; 470*50639Schristos } 471*50639Schristos } 472*50639Schristos cont: 473*50639Schristos pv++; 474*50639Schristos i++; 475*50639Schristos } while (*pv); 476*50639Schristos xfree((ptr_t) sav); 477*50639Schristos return 0; 478*50639Schristos } 479*50639Schristos 480*50639Schristos /* Also by: 481*50639Schristos * Andreas Luik <luik@isaak.isa.de> 482*50639Schristos * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 483*50639Schristos * Azenberstr. 35 484*50639Schristos * D-7000 Stuttgart 1 485*50639Schristos * West-Germany 486*50639Schristos * is the executable() routine below and changes to iscommand(). 487*50639Schristos * Thanks again!! 488*50639Schristos */ 489*50639Schristos 490*50639Schristos /* 491*50639Schristos * executable() examines the pathname obtained by concatenating dir and name 492*50639Schristos * (dir may be NULL), and returns 1 either if it is executable by us, or 493*50639Schristos * if dir_ok is set and the pathname refers to a directory. 494*50639Schristos * This is a bit kludgy, but in the name of optimization... 495*50639Schristos */ 496*50639Schristos static int 497*50639Schristos executable(dir, name, dir_ok) 498*50639Schristos Char *dir, *name; 499*50639Schristos bool dir_ok; 500*50639Schristos { 501*50639Schristos struct stat stbuf; 502*50639Schristos Char path[MAXPATHLEN + 1], *dp, *sp; 503*50639Schristos char *strname; 504*50639Schristos 505*50639Schristos if (dir && *dir) { 506*50639Schristos for (dp = path, sp = dir; *sp; *dp++ = *sp++) 507*50639Schristos if (dp == &path[MAXPATHLEN + 1]) { 508*50639Schristos *--dp = '\0'; 509*50639Schristos break; 510*50639Schristos } 511*50639Schristos for (sp = name; *sp; *dp++ = *sp++) 512*50639Schristos if (dp == &path[MAXPATHLEN + 1]) { 513*50639Schristos *--dp = '\0'; 514*50639Schristos break; 515*50639Schristos } 516*50639Schristos *dp = '\0'; 517*50639Schristos strname = short2str(path); 518*50639Schristos } 519*50639Schristos else 520*50639Schristos strname = short2str(name); 521*50639Schristos return (stat(strname, &stbuf) != -1 && 522*50639Schristos ((S_ISREG(stbuf.st_mode) && 523*50639Schristos /* save time by not calling access() in the hopeless case */ 524*50639Schristos (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) && 525*50639Schristos access(strname, X_OK) == 0) || 526*50639Schristos (dir_ok && S_ISDIR(stbuf.st_mode)))); 527*50639Schristos } 528*50639Schristos 529*50639Schristos /* The dowhich() is by: 530*50639Schristos * Andreas Luik <luik@isaak.isa.de> 531*50639Schristos * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 532*50639Schristos * Azenberstr. 35 533*50639Schristos * D-7000 Stuttgart 1 534*50639Schristos * West-Germany 535*50639Schristos * Thanks!! 536*50639Schristos */ 537*50639Schristos /*ARGSUSED*/ 538*50639Schristos void 539*50639Schristos dowhich(v, c) 540*50639Schristos register Char **v; 541*50639Schristos struct command *c; 542*50639Schristos { 543*50639Schristos struct wordent lex[3]; 544*50639Schristos struct varent *vp; 545*50639Schristos 546*50639Schristos lex[0].next = &lex[1]; 547*50639Schristos lex[1].next = &lex[2]; 548*50639Schristos lex[2].next = &lex[0]; 549*50639Schristos 550*50639Schristos lex[0].prev = &lex[2]; 551*50639Schristos lex[1].prev = &lex[0]; 552*50639Schristos lex[2].prev = &lex[1]; 553*50639Schristos 554*50639Schristos lex[0].word = STRNULL; 555*50639Schristos lex[2].word = STRret; 556*50639Schristos 557*50639Schristos while (*++v) { 558*50639Schristos if (vp = adrof1(*v, &aliases)) { 559*50639Schristos (void) fprintf(cshout, "%s: \t aliased to ", short2str(*v)); 560*50639Schristos blkpr(cshout, vp->vec); 561*50639Schristos (void) fputc('\n', cshout); 562*50639Schristos } 563*50639Schristos else { 564*50639Schristos lex[1].word = *v; 565*50639Schristos tellmewhat(lex); 566*50639Schristos } 567*50639Schristos } 568*50639Schristos } 569*50639Schristos 570*50639Schristos static void 571*50639Schristos tellmewhat(lex) 572*50639Schristos struct wordent *lex; 573*50639Schristos { 574*50639Schristos register int i; 575*50639Schristos register struct biltins *bptr; 576*50639Schristos register struct wordent *sp = lex->next; 577*50639Schristos bool aliased = 0; 578*50639Schristos Char *s0, *s1, *s2; 579*50639Schristos Char qc; 580*50639Schristos 581*50639Schristos if (adrof1(sp->word, &aliases)) { 582*50639Schristos alias(lex); 583*50639Schristos sp = lex->next; 584*50639Schristos aliased = 1; 585*50639Schristos } 586*50639Schristos 587*50639Schristos s0 = sp->word; /* to get the memory freeing right... */ 588*50639Schristos 589*50639Schristos /* handle quoted alias hack */ 590*50639Schristos if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE) 591*50639Schristos (sp->word)++; 592*50639Schristos 593*50639Schristos /* do quoting, if it hasn't been done */ 594*50639Schristos s1 = s2 = sp->word; 595*50639Schristos while (*s2) 596*50639Schristos switch (*s2) { 597*50639Schristos case '\'': 598*50639Schristos case '"': 599*50639Schristos qc = *s2++; 600*50639Schristos while (*s2 && *s2 != qc) 601*50639Schristos *s1++ = *s2++ | QUOTE; 602*50639Schristos if (*s2) 603*50639Schristos s2++; 604*50639Schristos break; 605*50639Schristos case '\\': 606*50639Schristos if (*++s2) 607*50639Schristos *s1++ = *s2++ | QUOTE; 608*50639Schristos break; 609*50639Schristos default: 610*50639Schristos *s1++ = *s2++; 611*50639Schristos } 612*50639Schristos *s1 = '\0'; 613*50639Schristos 614*50639Schristos for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) { 615*50639Schristos if (eq(sp->word, str2short(bptr->bname))) { 616*50639Schristos if (aliased) 617*50639Schristos prlex(cshout, lex); 618*50639Schristos (void) fprintf(cshout, "%s: shell built-in command.\n", 619*50639Schristos short2str(sp->word)); 620*50639Schristos sp->word = s0; /* we save and then restore this */ 621*50639Schristos return; 622*50639Schristos } 623*50639Schristos } 624*50639Schristos 625*50639Schristos if (i = iscommand(strip(sp->word))) { 626*50639Schristos register Char **pv; 627*50639Schristos register struct varent *v; 628*50639Schristos bool slash = any(short2str(sp->word), '/'); 629*50639Schristos 630*50639Schristos v = adrof(STRpath); 631*50639Schristos if (v == 0 || v->vec[0] == 0 || slash) 632*50639Schristos pv = justabs; 633*50639Schristos else 634*50639Schristos pv = v->vec; 635*50639Schristos 636*50639Schristos while (--i) 637*50639Schristos pv++; 638*50639Schristos if (pv[0][0] == 0 || eq(pv[0], STRdot)) { 639*50639Schristos sp->word = Strspl(STRdotsl, sp->word); 640*50639Schristos prlex(cshout, lex); 641*50639Schristos xfree((ptr_t) sp->word); 642*50639Schristos sp->word = s0; /* we save and then restore this */ 643*50639Schristos return; 644*50639Schristos } 645*50639Schristos s1 = Strspl(*pv, STRslash); 646*50639Schristos sp->word = Strspl(s1, sp->word); 647*50639Schristos xfree((ptr_t) s1); 648*50639Schristos prlex(cshout, lex); 649*50639Schristos xfree((ptr_t) sp->word); 650*50639Schristos } 651*50639Schristos else { 652*50639Schristos if (aliased) 653*50639Schristos prlex(cshout, lex); 654*50639Schristos (void) fprintf(csherr, "%s: Command not found.\n", short2str(sp->word)); 655*50639Schristos } 656*50639Schristos sp->word = s0; /* we save and then restore this */ 657*50639Schristos } 658