159243Sobrien/* 259243Sobrien * sh.exec.c: Search, find, and execute a command! 359243Sobrien */ 459243Sobrien/*- 559243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 659243Sobrien * All rights reserved. 759243Sobrien * 859243Sobrien * Redistribution and use in source and binary forms, with or without 959243Sobrien * modification, are permitted provided that the following conditions 1059243Sobrien * are met: 1159243Sobrien * 1. Redistributions of source code must retain the above copyright 1259243Sobrien * notice, this list of conditions and the following disclaimer. 1359243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1459243Sobrien * notice, this list of conditions and the following disclaimer in the 1559243Sobrien * documentation and/or other materials provided with the distribution. 16100616Smp * 3. Neither the name of the University nor the names of its contributors 1759243Sobrien * may be used to endorse or promote products derived from this software 1859243Sobrien * without specific prior written permission. 1959243Sobrien * 2059243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2159243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2259243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2359243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2459243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2559243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2659243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2759243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2859243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2959243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3059243Sobrien * SUCH DAMAGE. 3159243Sobrien */ 3259243Sobrien#include "sh.h" 3359243Sobrien#include "tc.h" 3459243Sobrien#include "tw.h" 3569408Sache#ifdef WINNT_NATIVE 3659243Sobrien#include <nt.const.h> 3769408Sache#endif /*WINNT_NATIVE*/ 3859243Sobrien 3959243Sobrien/* 4059243Sobrien * C shell 4159243Sobrien */ 4259243Sobrien 4359243Sobrien#ifndef OLDHASH 4459243Sobrien# define FASTHASH /* Fast hashing is the default */ 4559243Sobrien#endif /* OLDHASH */ 4659243Sobrien 4759243Sobrien/* 4859243Sobrien * System level search and execute of a command. 4959243Sobrien * We look in each directory for the specified command name. 5059243Sobrien * If the name contains a '/' then we execute only the full path name. 5159243Sobrien * If there is no search path then we execute only full path names. 5259243Sobrien */ 5359243Sobrien 5459243Sobrien/* 5559243Sobrien * As we search for the command we note the first non-trivial error 5659243Sobrien * message for presentation to the user. This allows us often 5759243Sobrien * to show that a file has the wrong mode/no access when the file 5859243Sobrien * is not in the last component of the search path, so we must 5959243Sobrien * go on after first detecting the error. 6059243Sobrien */ 6159243Sobrienstatic char *exerr; /* Execution error message */ 6259243Sobrienstatic Char *expath; /* Path for exerr */ 6359243Sobrien 6459243Sobrien/* 6559243Sobrien * The two part hash function is designed to let texec() call the 6659243Sobrien * more expensive hashname() only once and the simple hash() several 6759243Sobrien * times (once for each path component checked). 6859243Sobrien * Byte size is assumed to be 8. 6959243Sobrien */ 7059243Sobrien#define BITS_PER_BYTE 8 7159243Sobrien 7259243Sobrien#ifdef FASTHASH 7359243Sobrien/* 7459243Sobrien * xhash is an array of hash buckets which are used to hash execs. If 7559243Sobrien * it is allocated (havhash true), then to tell if ``name'' is 76231990Smp * (possibly) present in the i'th component of the variable path, look 7759243Sobrien * at the [hashname(name)] bucket of size [hashwidth] bytes, in the [i 7859243Sobrien * mod size*8]'th bit. The cache size is defaults to a length of 1024 7959243Sobrien * buckets, each 1 byte wide. This implementation guarantees that 8059243Sobrien * objects n bytes wide will be aligned on n byte boundaries. 8159243Sobrien */ 8259243Sobrien# define HSHMUL 241 8359243Sobrien 8459243Sobrienstatic unsigned long *xhash = NULL; 8559243Sobrienstatic unsigned int hashlength = 0, uhashlength = 0; 8659243Sobrienstatic unsigned int hashwidth = 0, uhashwidth = 0; 8759243Sobrienstatic int hashdebug = 0; 8859243Sobrien 8959243Sobrien# define hash(a, b) (((a) * HSHMUL + (b)) % (hashlength)) 9059243Sobrien# define widthof(t) (sizeof(t) * BITS_PER_BYTE) 9159243Sobrien# define tbit(f, i, t) (((t *) xhash)[(f)] & \ 92145479Smp (1UL << (i & (widthof(t) - 1)))) 9359243Sobrien# define tbis(f, i, t) (((t *) xhash)[(f)] |= \ 94145479Smp (1UL << (i & (widthof(t) - 1)))) 9559243Sobrien# define cbit(f, i) tbit(f, i, unsigned char) 9659243Sobrien# define cbis(f, i) tbis(f, i, unsigned char) 9759243Sobrien# define sbit(f, i) tbit(f, i, unsigned short) 9859243Sobrien# define sbis(f, i) tbis(f, i, unsigned short) 9959243Sobrien# define ibit(f, i) tbit(f, i, unsigned int) 10059243Sobrien# define ibis(f, i) tbis(f, i, unsigned int) 10159243Sobrien# define lbit(f, i) tbit(f, i, unsigned long) 10259243Sobrien# define lbis(f, i) tbis(f, i, unsigned long) 10359243Sobrien 10459243Sobrien# define bit(f, i) (hashwidth==sizeof(unsigned char) ? cbit(f,i) : \ 10559243Sobrien ((hashwidth==sizeof(unsigned short) ? sbit(f,i) : \ 10659243Sobrien ((hashwidth==sizeof(unsigned int) ? ibit(f,i) : \ 10759243Sobrien lbit(f,i)))))) 10859243Sobrien# define bis(f, i) (hashwidth==sizeof(unsigned char) ? cbis(f,i) : \ 10959243Sobrien ((hashwidth==sizeof(unsigned short) ? sbis(f,i) : \ 11059243Sobrien ((hashwidth==sizeof(unsigned int) ? ibis(f,i) : \ 11159243Sobrien lbis(f,i)))))) 11259243Sobrien#else /* OLDHASH */ 11359243Sobrien/* 11459243Sobrien * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used 11559243Sobrien * to hash execs. If it is allocated (havhash true), then to tell 11659243Sobrien * whether ``name'' is (possibly) present in the i'th component 11759243Sobrien * of the variable path, you look at the bit in xhash indexed by 11859243Sobrien * hash(hashname("name"), i). This is setup automatically 11959243Sobrien * after .login is executed, and recomputed whenever ``path'' is 12059243Sobrien * changed. 12159243Sobrien */ 12259243Sobrien# define HSHSIZ 8192 /* 1k bytes */ 12359243Sobrien# define HSHMASK (HSHSIZ - 1) 12459243Sobrien# define HSHMUL 243 12559243Sobrienstatic char xhash[HSHSIZ / BITS_PER_BYTE]; 12659243Sobrien 12759243Sobrien# define hash(a, b) (((a) * HSHMUL + (b)) & HSHMASK) 12859243Sobrien# define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */ 12959243Sobrien# define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */ 13059243Sobrien 13159243Sobrien#endif /* FASTHASH */ 13259243Sobrien 13359243Sobrien#ifdef VFORK 13459243Sobrienstatic int hits, misses; 13559243Sobrien#endif /* VFORK */ 13659243Sobrien 13759243Sobrien/* Dummy search path for just absolute search when no path */ 13859243Sobrienstatic Char *justabs[] = {STRNULL, 0}; 13959243Sobrien 140231990Smpstatic void pexerr (void) __attribute__((__noreturn__)); 141167465Smpstatic void texec (Char *, Char **); 142167465Smpint hashname (Char *); 143167465Smpstatic int iscommand (Char *); 14459243Sobrien 14559243Sobrienvoid 146167465Smpdoexec(struct command *t, int do_glob) 14759243Sobrien{ 148231990Smp Char *dp, **pv, **opv, **av, *sav; 149100616Smp struct varent *v; 150231990Smp int slash, gflag, rehashed; 151100616Smp int hashval, i; 15259243Sobrien Char *blk[2]; 15359243Sobrien 15459243Sobrien /* 15559243Sobrien * Glob the command name. We will search $path even if this does something, 15659243Sobrien * as in sh but not in csh. One special case: if there is no PATH, then we 15759243Sobrien * execute only commands which start with '/'. 15859243Sobrien */ 15959243Sobrien blk[0] = t->t_dcom[0]; 16059243Sobrien blk[1] = 0; 161100616Smp gflag = 0; 162100616Smp if (do_glob) 163167465Smp gflag = tglob(blk); 16459243Sobrien if (gflag) { 165167465Smp pv = globall(blk, gflag); 16659243Sobrien if (pv == 0) { 16759243Sobrien setname(short2str(blk[0])); 16859243Sobrien stderror(ERR_NAME | ERR_NOMATCH); 16959243Sobrien } 17059243Sobrien } 17159243Sobrien else 17259243Sobrien pv = saveblk(blk); 173167465Smp cleanup_push(pv, blk_cleanup); 17459243Sobrien 17559243Sobrien trim(pv); 17659243Sobrien 17759243Sobrien exerr = 0; 17859243Sobrien expath = Strsave(pv[0]); 17959243Sobrien#ifdef VFORK 18059243Sobrien Vexpath = expath; 18159243Sobrien#endif /* VFORK */ 18259243Sobrien 18359243Sobrien v = adrof(STRpath); 184167465Smp if (v == 0 && expath[0] != '/' && expath[0] != '.') 18559243Sobrien pexerr(); 18659243Sobrien slash = any(short2str(expath), '/'); 18759243Sobrien 18859243Sobrien /* 18959243Sobrien * Glob the argument list, if necessary. Otherwise trim off the quote bits. 19059243Sobrien */ 19159243Sobrien gflag = 0; 19259243Sobrien av = &t->t_dcom[1]; 193100616Smp if (do_glob) 194167465Smp gflag = tglob(av); 19559243Sobrien if (gflag) { 196167465Smp av = globall(av, gflag); 19759243Sobrien if (av == 0) { 19859243Sobrien setname(short2str(expath)); 19959243Sobrien stderror(ERR_NAME | ERR_NOMATCH); 20059243Sobrien } 20159243Sobrien } 20259243Sobrien else 20359243Sobrien av = saveblk(av); 20459243Sobrien 20559243Sobrien blkfree(t->t_dcom); 206167465Smp cleanup_ignore(pv); 207167465Smp cleanup_until(pv); 20859243Sobrien t->t_dcom = blkspl(pv, av); 209167465Smp xfree(pv); 210167465Smp xfree(av); 21159243Sobrien av = t->t_dcom; 21259243Sobrien trim(av); 21359243Sobrien 21459243Sobrien if (*av == NULL || **av == '\0') 21559243Sobrien pexerr(); 21659243Sobrien 21759243Sobrien xechoit(av); /* Echo command if -x */ 21859243Sobrien#ifdef CLOSE_ON_EXEC 21959243Sobrien /* 22059243Sobrien * Since all internal file descriptors are set to close on exec, we don't 22159243Sobrien * need to close them explicitly here. Just reorient ourselves for error 22259243Sobrien * messages. 22359243Sobrien */ 22459243Sobrien SHIN = 0; 22559243Sobrien SHOUT = 1; 22659243Sobrien SHDIAG = 2; 22759243Sobrien OLDSTD = 0; 22859243Sobrien isoutatty = isatty(SHOUT); 22959243Sobrien isdiagatty = isatty(SHDIAG); 23059243Sobrien#else 23159243Sobrien closech(); /* Close random fd's */ 23259243Sobrien#endif 23359243Sobrien /* 23459243Sobrien * We must do this AFTER any possible forking (like `foo` in glob) so that 23559243Sobrien * this shell can still do subprocesses. 23659243Sobrien */ 237167465Smp { 238167465Smp sigset_t set; 239167465Smp sigemptyset(&set); 240167465Smp sigaddset(&set, SIGINT); 241167465Smp sigaddset(&set, SIGCHLD); 242167465Smp sigprocmask(SIG_UNBLOCK, &set, NULL); 243167465Smp } 244167465Smp pintr_disabled = 0; 245167465Smp pchild_disabled = 0; 24659243Sobrien 24759243Sobrien /* 24859243Sobrien * If no path, no words in path, or a / in the filename then restrict the 24959243Sobrien * command search. 25059243Sobrien */ 251100616Smp if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash) 252231990Smp opv = justabs; 25359243Sobrien else 254231990Smp opv = v->vec; 25559243Sobrien sav = Strspl(STRslash, *av);/* / command name for postpending */ 256167465Smp#ifndef VFORK 257167465Smp cleanup_push(sav, xfree); 258167465Smp#else /* VFORK */ 25959243Sobrien Vsav = sav; 26059243Sobrien#endif /* VFORK */ 26159243Sobrien hashval = havhash ? hashname(*av) : 0; 26259243Sobrien 263231990Smp rehashed = 0; 264231990Smpretry: 265231990Smp pv = opv; 26659243Sobrien i = 0; 26759243Sobrien#ifdef VFORK 26859243Sobrien hits++; 26959243Sobrien#endif /* VFORK */ 27059243Sobrien do { 27159243Sobrien /* 27259243Sobrien * Try to save time by looking at the hash table for where this command 27359243Sobrien * could be. If we are doing delayed hashing, then we put the names in 27459243Sobrien * one at a time, as the user enters them. This is kinda like Korn 27559243Sobrien * Shell's "tracked aliases". 27659243Sobrien */ 27759243Sobrien if (!slash && ABSOLUTEP(pv[0]) && havhash) { 27859243Sobrien#ifdef FASTHASH 27959243Sobrien if (!bit(hashval, i)) 28059243Sobrien goto cont; 28159243Sobrien#else /* OLDHASH */ 28259243Sobrien int hashval1 = hash(hashval, i); 28359243Sobrien if (!bit(xhash, hashval1)) 28459243Sobrien goto cont; 28559243Sobrien#endif /* FASTHASH */ 28659243Sobrien } 28759243Sobrien if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */ 28859243Sobrien texec(*av, av); 28959243Sobrien else { 29059243Sobrien dp = Strspl(*pv, sav); 291167465Smp#ifndef VFORK 292167465Smp cleanup_push(dp, xfree); 293167465Smp#else /* VFORK */ 29459243Sobrien Vdp = dp; 29559243Sobrien#endif /* VFORK */ 29659243Sobrien 29759243Sobrien texec(dp, av); 298167465Smp#ifndef VFORK 299167465Smp cleanup_until(dp); 300167465Smp#else /* VFORK */ 30159243Sobrien Vdp = 0; 302167465Smp xfree(dp); 30359243Sobrien#endif /* VFORK */ 30459243Sobrien } 30559243Sobrien#ifdef VFORK 30659243Sobrien misses++; 30759243Sobrien#endif /* VFORK */ 30859243Sobriencont: 30959243Sobrien pv++; 31059243Sobrien i++; 31159243Sobrien } while (*pv); 31259243Sobrien#ifdef VFORK 31359243Sobrien hits--; 314167465Smp#endif /* VFORK */ 315231990Smp if (adrof(STRautorehash) && !rehashed && havhash && opv != justabs) { 316231990Smp dohash(NULL, NULL); 317231990Smp rehashed = 1; 318231990Smp goto retry; 319231990Smp } 320167465Smp#ifndef VFORK 321167465Smp cleanup_until(sav); 322167465Smp#else /* VFORK */ 32359243Sobrien Vsav = 0; 324167465Smp xfree(sav); 32559243Sobrien#endif /* VFORK */ 32659243Sobrien pexerr(); 32759243Sobrien} 32859243Sobrien 32959243Sobrienstatic void 330167465Smppexerr(void) 33159243Sobrien{ 33259243Sobrien /* Couldn't find the damn thing */ 33359243Sobrien if (expath) { 33459243Sobrien setname(short2str(expath)); 33559243Sobrien#ifdef VFORK 33659243Sobrien Vexpath = 0; 33759243Sobrien#endif /* VFORK */ 338167465Smp xfree(expath); 33959243Sobrien expath = 0; 34059243Sobrien } 34159243Sobrien else 34259243Sobrien setname(""); 34359243Sobrien if (exerr) 34459243Sobrien stderror(ERR_NAME | ERR_STRING, exerr); 34559243Sobrien stderror(ERR_NAME | ERR_COMMAND); 34659243Sobrien} 34759243Sobrien 34859243Sobrien/* 34959243Sobrien * Execute command f, arg list t. 35059243Sobrien * Record error message if not found. 35159243Sobrien * Also do shell scripts here. 35259243Sobrien */ 35359243Sobrienstatic void 354167465Smptexec(Char *sf, Char **st) 35559243Sobrien{ 356145479Smp char **t; 357145479Smp char *f; 358145479Smp struct varent *v; 35959243Sobrien Char **vp; 36059243Sobrien Char *lastsh[2]; 36159243Sobrien char pref[2]; 36259243Sobrien int fd; 36359243Sobrien Char *st0, **ost; 36459243Sobrien 36559243Sobrien /* The order for the conversions is significant */ 36659243Sobrien t = short2blk(st); 36759243Sobrien f = short2str(sf); 36859243Sobrien#ifdef VFORK 36959243Sobrien Vt = t; 37059243Sobrien#endif /* VFORK */ 37159243Sobrien errno = 0; /* don't use a previous error */ 37259243Sobrien#ifdef apollo 37359243Sobrien /* 37459243Sobrien * If we try to execute an nfs mounted directory on the apollo, we 37559243Sobrien * hang forever. So until apollo fixes that.. 37659243Sobrien */ 37759243Sobrien { 37859243Sobrien struct stat stb; 37959243Sobrien if (stat(f, &stb) == 0 && S_ISDIR(stb.st_mode)) 38059243Sobrien errno = EISDIR; 38159243Sobrien } 38259243Sobrien if (errno == 0) 38359243Sobrien#endif /* apollo */ 38459243Sobrien { 38559243Sobrien#ifdef ISC_POSIX_EXEC_BUG 38659243Sobrien __setostype(0); /* "0" is "__OS_SYSV" in <sys/user.h> */ 38759243Sobrien#endif /* ISC_POSIX_EXEC_BUG */ 38859243Sobrien (void) execv(f, t); 38959243Sobrien#ifdef ISC_POSIX_EXEC_BUG 39059243Sobrien __setostype(1); /* "1" is "__OS_POSIX" in <sys/user.h> */ 39159243Sobrien#endif /* ISC_POSIX_EXEC_BUG */ 39259243Sobrien } 39359243Sobrien#ifdef VFORK 39459243Sobrien Vt = 0; 39559243Sobrien#endif /* VFORK */ 39659243Sobrien blkfree((Char **) t); 39759243Sobrien switch (errno) { 39859243Sobrien 39959243Sobrien case ENOEXEC: 40069408Sache#ifdef WINNT_NATIVE 40159243Sobrien nt_feed_to_cmd(f,t); 40269408Sache#endif /* WINNT_NATIVE */ 40359243Sobrien /* 40459243Sobrien * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute 40559243Sobrien * it, don't feed it to the shell if it looks like a binary! 40659243Sobrien */ 407167465Smp if ((fd = xopen(f, O_RDONLY|O_LARGEFILE)) != -1) { 40859243Sobrien int nread; 409167465Smp if ((nread = xread(fd, pref, 2)) == 2) { 410145479Smp if (!isprint((unsigned char)pref[0]) && 411145479Smp (pref[0] != '\n' && pref[0] != '\t')) { 412167465Smp int err; 413167465Smp 414167465Smp err = errno; 415167465Smp xclose(fd); 41659243Sobrien /* 41759243Sobrien * We *know* what ENOEXEC means. 41859243Sobrien */ 419167465Smp stderror(ERR_ARCH, f, strerror(err)); 42059243Sobrien } 42159243Sobrien } 422167465Smp else if (nread < 0) { 42359243Sobrien#ifdef convex 424167465Smp int err; 425167465Smp 426167465Smp err = errno; 427167465Smp xclose(fd); 42859243Sobrien /* need to print error incase the file is migrated */ 429167465Smp stderror(ERR_SYSTEM, f, strerror(err)); 43059243Sobrien#endif 43159243Sobrien } 43259243Sobrien#ifdef _PATH_BSHELL 43359243Sobrien else { 43459243Sobrien pref[0] = '#'; 43559243Sobrien pref[1] = '\0'; 43659243Sobrien } 43759243Sobrien#endif 43859243Sobrien } 43959243Sobrien#ifdef HASHBANG 44059243Sobrien if (fd == -1 || 44159243Sobrien pref[0] != '#' || pref[1] != '!' || hashbang(fd, &vp) == -1) { 44259243Sobrien#endif /* HASHBANG */ 44359243Sobrien /* 44459243Sobrien * If there is an alias for shell, then put the words of the alias in 44559243Sobrien * front of the argument list replacing the command name. Note no 44659243Sobrien * interpretation of the words at this point. 44759243Sobrien */ 44859243Sobrien v = adrof1(STRshell, &aliases); 449100616Smp if (v == NULL || v->vec == NULL) { 45059243Sobrien vp = lastsh; 45159243Sobrien vp[0] = adrof(STRshell) ? varval(STRshell) : STR_SHELLPATH; 45259243Sobrien vp[1] = NULL; 45359243Sobrien#ifdef _PATH_BSHELL 45459243Sobrien if (fd != -1 45559243Sobrien# ifndef ISC /* Compatible with ISC's /bin/csh */ 45659243Sobrien && pref[0] != '#' 45759243Sobrien# endif /* ISC */ 45859243Sobrien ) 45959243Sobrien vp[0] = STR_BSHELL; 46059243Sobrien#endif 46159243Sobrien vp = saveblk(vp); 46259243Sobrien } 46359243Sobrien else 46459243Sobrien vp = saveblk(v->vec); 46559243Sobrien#ifdef HASHBANG 46659243Sobrien } 46759243Sobrien#endif /* HASHBANG */ 46859243Sobrien if (fd != -1) 469167465Smp xclose(fd); 47059243Sobrien 47159243Sobrien st0 = st[0]; 47259243Sobrien st[0] = sf; 47359243Sobrien ost = st; 47459243Sobrien st = blkspl(vp, st); /* Splice up the new arglst */ 47559243Sobrien ost[0] = st0; 47659243Sobrien sf = *st; 47759243Sobrien /* The order for the conversions is significant */ 47859243Sobrien t = short2blk(st); 47959243Sobrien f = short2str(sf); 480167465Smp xfree(st); 48159243Sobrien blkfree((Char **) vp); 48259243Sobrien#ifdef VFORK 48359243Sobrien Vt = t; 48459243Sobrien#endif /* VFORK */ 48559243Sobrien#ifdef ISC_POSIX_EXEC_BUG 48659243Sobrien __setostype(0); /* "0" is "__OS_SYSV" in <sys/user.h> */ 48759243Sobrien#endif /* ISC_POSIX_EXEC_BUG */ 48859243Sobrien (void) execv(f, t); 48959243Sobrien#ifdef ISC_POSIX_EXEC_BUG 49059243Sobrien __setostype(1); /* "1" is "__OS_POSIX" in <sys/user.h> */ 49159243Sobrien#endif /* ISC_POSIX_EXEC_BUG */ 49259243Sobrien#ifdef VFORK 49359243Sobrien Vt = 0; 49459243Sobrien#endif /* VFORK */ 49559243Sobrien blkfree((Char **) t); 49659243Sobrien /* The sky is falling, the sky is falling! */ 49759243Sobrien stderror(ERR_SYSTEM, f, strerror(errno)); 49859243Sobrien break; 49959243Sobrien 50059243Sobrien case ENOMEM: 50159243Sobrien stderror(ERR_SYSTEM, f, strerror(errno)); 50259243Sobrien break; 50359243Sobrien 50459243Sobrien#ifdef _IBMR2 50559243Sobrien case 0: /* execv fails and returns 0! */ 50659243Sobrien#endif /* _IBMR2 */ 50759243Sobrien case ENOENT: 50859243Sobrien break; 50959243Sobrien 51059243Sobrien default: 51159243Sobrien if (exerr == 0) { 51259243Sobrien exerr = strerror(errno); 513167465Smp xfree(expath); 51459243Sobrien expath = Strsave(sf); 51559243Sobrien#ifdef VFORK 51659243Sobrien Vexpath = expath; 51759243Sobrien#endif /* VFORK */ 51859243Sobrien } 51959243Sobrien break; 52059243Sobrien } 52159243Sobrien} 52259243Sobrien 523167465Smpstruct execash_state 52459243Sobrien{ 525167465Smp int saveIN, saveOUT, saveDIAG, saveSTD; 526167465Smp int SHIN, SHOUT, SHDIAG, OLDSTD; 527167465Smp int didfds; 52859243Sobrien#ifndef CLOSE_ON_EXEC 529167465Smp int didcch; 530167465Smp#endif 531167465Smp struct sigaction sigint, sigquit, sigterm; 532167465Smp}; 533167465Smp 534167465Smpstatic void 535167465Smpexecash_cleanup(void *xstate) 536167465Smp{ 537167465Smp struct execash_state *state; 538167465Smp 539167465Smp state = xstate; 540167465Smp sigaction(SIGINT, &state->sigint, NULL); 541167465Smp sigaction(SIGQUIT, &state->sigquit, NULL); 542167465Smp sigaction(SIGTERM, &state->sigterm, NULL); 543167465Smp 544167465Smp doneinp = 0; 545167465Smp#ifndef CLOSE_ON_EXEC 546167465Smp didcch = state->didcch; 54759243Sobrien#endif /* CLOSE_ON_EXEC */ 548167465Smp didfds = state->didfds; 549167465Smp xclose(SHIN); 550167465Smp xclose(SHOUT); 551167465Smp xclose(SHDIAG); 552167465Smp xclose(OLDSTD); 553167465Smp close_on_exec(SHIN = dmove(state->saveIN, state->SHIN), 1); 554167465Smp close_on_exec(SHOUT = dmove(state->saveOUT, state->SHOUT), 1); 555167465Smp close_on_exec(SHDIAG = dmove(state->saveDIAG, state->SHDIAG), 1); 556167465Smp close_on_exec(OLDSTD = dmove(state->saveSTD, state->OLDSTD), 1); 557167465Smp} 55859243Sobrien 559167465Smp/*ARGSUSED*/ 560167465Smpvoid 561167465Smpexecash(Char **t, struct command *kp) 562167465Smp{ 563167465Smp struct execash_state state; 564167465Smp 56559243Sobrien USE(t); 56659243Sobrien if (chkstop == 0 && setintr) 56759243Sobrien panystop(0); 56859243Sobrien /* 56959243Sobrien * Hmm, we don't really want to do that now because we might 57059243Sobrien * fail, but what is the choice 57159243Sobrien */ 57259243Sobrien rechist(NULL, adrof(STRsavehist) != NULL); 57359243Sobrien 57459243Sobrien 575167465Smp sigaction(SIGINT, &parintr, &state.sigint); 576167465Smp sigaction(SIGQUIT, &parintr, &state.sigquit); 577167465Smp sigaction(SIGTERM, &parterm, &state.sigterm); 57859243Sobrien 579167465Smp state.didfds = didfds; 58059243Sobrien#ifndef CLOSE_ON_EXEC 581167465Smp state.didcch = didcch; 58259243Sobrien#endif /* CLOSE_ON_EXEC */ 583167465Smp state.SHIN = SHIN; 584167465Smp state.SHOUT = SHOUT; 585167465Smp state.SHDIAG = SHDIAG; 586167465Smp state.OLDSTD = OLDSTD; 58759243Sobrien 588167465Smp (void)close_on_exec (state.saveIN = dcopy(SHIN, -1), 1); 589167465Smp (void)close_on_exec (state.saveOUT = dcopy(SHOUT, -1), 1); 590167465Smp (void)close_on_exec (state.saveDIAG = dcopy(SHDIAG, -1), 1); 591167465Smp (void)close_on_exec (state.saveSTD = dcopy(OLDSTD, -1), 1); 592167465Smp 59359243Sobrien lshift(kp->t_dcom, 1); 59459243Sobrien 595167465Smp (void)close_on_exec (SHIN = dcopy(0, -1), 1); 596167465Smp (void)close_on_exec (SHOUT = dcopy(1, -1), 1); 597167465Smp (void)close_on_exec (SHDIAG = dcopy(2, -1), 1); 59859243Sobrien#ifndef CLOSE_ON_EXEC 599167465Smp didcch = 0; 60059243Sobrien#endif /* CLOSE_ON_EXEC */ 601167465Smp didfds = 0; 602167465Smp cleanup_push(&state, execash_cleanup); 603167465Smp 604167465Smp /* 605316957Sdchagin * Decrement the shell level, if not in a subshell 606167465Smp */ 607316957Sdchagin if (mainpid == getpid()) 608316957Sdchagin shlvl(-1); 60969408Sache#ifdef WINNT_NATIVE 610167465Smp __nt_really_exec=1; 61169408Sache#endif /* WINNT_NATIVE */ 612167465Smp doexec(kp, 1); 61359243Sobrien 614167465Smp cleanup_until(&state); 61559243Sobrien} 61659243Sobrien 61759243Sobrienvoid 618167465Smpxechoit(Char **t) 61959243Sobrien{ 62059243Sobrien if (adrof(STRecho)) { 621100616Smp int odidfds = didfds; 62259243Sobrien flush(); 62359243Sobrien haderr = 1; 624100616Smp didfds = 0; 62559243Sobrien blkpr(t), xputchar('\n'); 626100616Smp flush(); 627100616Smp didfds = odidfds; 62859243Sobrien haderr = 0; 62959243Sobrien } 63059243Sobrien} 63159243Sobrien 63259243Sobrien/*ARGSUSED*/ 63359243Sobrienvoid 634167465Smpdohash(Char **vv, struct command *c) 63559243Sobrien{ 63659243Sobrien#ifdef COMMENT 63759243Sobrien struct stat stb; 63859243Sobrien#endif 63959243Sobrien DIR *dirp; 640145479Smp struct dirent *dp; 64159243Sobrien int i = 0; 64259243Sobrien struct varent *v = adrof(STRpath); 64359243Sobrien Char **pv; 64459243Sobrien int hashval; 64569408Sache#ifdef WINNT_NATIVE 64659243Sobrien int is_windir; /* check if it is the windows directory */ 64759243Sobrien USE(hashval); 64869408Sache#endif /* WINNT_NATIVE */ 64959243Sobrien 65059243Sobrien USE(c); 65159243Sobrien#ifdef FASTHASH 65259243Sobrien if (vv && vv[1]) { 65359243Sobrien uhashlength = atoi(short2str(vv[1])); 65459243Sobrien if (vv[2]) { 65559243Sobrien uhashwidth = atoi(short2str(vv[2])); 65659243Sobrien if ((uhashwidth != sizeof(unsigned char)) && 65759243Sobrien (uhashwidth != sizeof(unsigned short)) && 65859243Sobrien (uhashwidth != sizeof(unsigned long))) 65959243Sobrien uhashwidth = 0; 66059243Sobrien if (vv[3]) 66159243Sobrien hashdebug = atoi(short2str(vv[3])); 66259243Sobrien } 66359243Sobrien } 66459243Sobrien 66559243Sobrien if (uhashwidth) 66659243Sobrien hashwidth = uhashwidth; 66759243Sobrien else { 66859243Sobrien hashwidth = 0; 66969408Sache if (v == NULL) 67069408Sache return; 671100616Smp for (pv = v->vec; pv && *pv; pv++, hashwidth++) 67259243Sobrien continue; 67359243Sobrien if (hashwidth <= widthof(unsigned char)) 67459243Sobrien hashwidth = sizeof(unsigned char); 67559243Sobrien else if (hashwidth <= widthof(unsigned short)) 67659243Sobrien hashwidth = sizeof(unsigned short); 67759243Sobrien else if (hashwidth <= widthof(unsigned int)) 67859243Sobrien hashwidth = sizeof(unsigned int); 67959243Sobrien else 68059243Sobrien hashwidth = sizeof(unsigned long); 68159243Sobrien } 68259243Sobrien 68359243Sobrien if (uhashlength) 68459243Sobrien hashlength = uhashlength; 68559243Sobrien else 68659243Sobrien hashlength = hashwidth * (8*64);/* "average" files per dir in path */ 687167465Smp 688167465Smp xfree(xhash); 689167465Smp xhash = xcalloc(hashlength * hashwidth, 1); 69059243Sobrien#endif /* FASTHASH */ 69159243Sobrien 69259243Sobrien (void) getusername(NULL); /* flush the tilde cashe */ 69359243Sobrien tw_cmd_free(); 69459243Sobrien havhash = 1; 69559243Sobrien if (v == NULL) 69659243Sobrien return; 697100616Smp for (pv = v->vec; pv && *pv; pv++, i++) { 69859243Sobrien if (!ABSOLUTEP(pv[0])) 69959243Sobrien continue; 70059243Sobrien dirp = opendir(short2str(*pv)); 70159243Sobrien if (dirp == NULL) 70259243Sobrien continue; 703167465Smp cleanup_push(dirp, opendir_cleanup); 70459243Sobrien#ifdef COMMENT /* this isn't needed. opendir won't open 70559243Sobrien * non-dirs */ 70659243Sobrien if (fstat(dirp->dd_fd, &stb) < 0 || !S_ISDIR(stb.st_mode)) { 707167465Smp cleanup_until(dirp); 70859243Sobrien continue; 70959243Sobrien } 71059243Sobrien#endif 71169408Sache#ifdef WINNT_NATIVE 71259243Sobrien is_windir = nt_check_if_windir(short2str(*pv)); 71369408Sache#endif /* WINNT_NATIVE */ 71459243Sobrien while ((dp = readdir(dirp)) != NULL) { 71559243Sobrien if (dp->d_ino == 0) 71659243Sobrien continue; 71759243Sobrien if (dp->d_name[0] == '.' && 71859243Sobrien (dp->d_name[1] == '\0' || 71959243Sobrien (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) 72059243Sobrien continue; 72169408Sache#ifdef WINNT_NATIVE 72259243Sobrien nt_check_name_and_hash(is_windir, dp->d_name, i); 72369408Sache#else /* !WINNT_NATIVE*/ 72469408Sache#if defined(_UWIN) || defined(__CYGWIN__) 72559243Sobrien /* Turn foo.{exe,com,bat} into foo since UWIN's readdir returns 72659243Sobrien * the file with the .exe, .com, .bat extension 727231990Smp * 728231990Smp * Same for Cygwin, but only for .exe and .com extension. 72959243Sobrien */ 73059243Sobrien { 731167465Smp ssize_t ext = strlen(dp->d_name) - 4; 732131962Smp if ((ext > 0) && (strcasecmp(&dp->d_name[ext], ".exe") == 0 || 733231990Smp#ifndef __CYGWIN__ 734131962Smp strcasecmp(&dp->d_name[ext], ".bat") == 0 || 735231990Smp#endif 736167465Smp strcasecmp(&dp->d_name[ext], ".com") == 0)) { 737167465Smp#ifdef __CYGWIN__ 738167465Smp /* Also store the variation with extension. */ 739167465Smp hashval = hashname(str2short(dp->d_name)); 740167465Smp bis(hashval, i); 741131962Smp#endif /* __CYGWIN__ */ 742167465Smp dp->d_name[ext] = '\0'; 743167465Smp } 74459243Sobrien } 74569408Sache#endif /* _UWIN || __CYGWIN__ */ 74659243Sobrien# ifdef FASTHASH 74759243Sobrien hashval = hashname(str2short(dp->d_name)); 74859243Sobrien bis(hashval, i); 74959243Sobrien if (hashdebug & 1) 75059243Sobrien xprintf(CGETS(13, 1, "hash=%-4d dir=%-2d prog=%s\n"), 75159243Sobrien hashname(str2short(dp->d_name)), i, dp->d_name); 75259243Sobrien# else /* OLD HASH */ 75359243Sobrien hashval = hash(hashname(str2short(dp->d_name)), i); 75459243Sobrien bis(xhash, hashval); 75559243Sobrien# endif /* FASTHASH */ 75659243Sobrien /* tw_add_comm_name (dp->d_name); */ 75769408Sache#endif /* WINNT_NATIVE */ 75859243Sobrien } 759167465Smp cleanup_until(dirp); 76059243Sobrien } 76159243Sobrien} 76259243Sobrien 76359243Sobrien/*ARGSUSED*/ 76459243Sobrienvoid 765167465Smpdounhash(Char **v, struct command *c) 76659243Sobrien{ 76759243Sobrien USE(c); 76859243Sobrien USE(v); 76959243Sobrien havhash = 0; 77059243Sobrien#ifdef FASTHASH 771167465Smp xfree(xhash); 772167465Smp xhash = NULL; 77359243Sobrien#endif /* FASTHASH */ 77459243Sobrien} 77559243Sobrien 77659243Sobrien/*ARGSUSED*/ 77759243Sobrienvoid 778167465Smphashstat(Char **v, struct command *c) 77959243Sobrien{ 78059243Sobrien USE(c); 78159243Sobrien USE(v); 78259243Sobrien#ifdef FASTHASH 78359243Sobrien if (havhash && hashlength && hashwidth) 78459243Sobrien xprintf(CGETS(13, 2, "%d hash buckets of %d bits each\n"), 78559243Sobrien hashlength, hashwidth*8); 78659243Sobrien if (hashdebug) 78759243Sobrien xprintf(CGETS(13, 3, "debug mask = 0x%08x\n"), hashdebug); 78859243Sobrien#endif /* FASTHASH */ 78959243Sobrien#ifdef VFORK 79059243Sobrien if (hits + misses) 79159243Sobrien xprintf(CGETS(13, 4, "%d hits, %d misses, %d%%\n"), 79259243Sobrien hits, misses, 100 * hits / (hits + misses)); 79359243Sobrien#endif 79459243Sobrien} 79559243Sobrien 79659243Sobrien 79759243Sobrien/* 79859243Sobrien * Hash a command name. 79959243Sobrien */ 80069408Sacheint 801167465Smphashname(Char *cp) 80259243Sobrien{ 803145479Smp unsigned long h; 80459243Sobrien 80559243Sobrien for (h = 0; *cp; cp++) 80659243Sobrien h = hash(h, *cp); 80759243Sobrien return ((int) h); 80859243Sobrien} 80959243Sobrien 81059243Sobrienstatic int 811167465Smpiscommand(Char *name) 81259243Sobrien{ 813231990Smp Char **opv, **pv; 814145479Smp Char *sav; 815145479Smp struct varent *v; 816145479Smp int slash = any(short2str(name), '/'); 817231990Smp int hashval, rehashed, i; 81859243Sobrien 81959243Sobrien v = adrof(STRpath); 820100616Smp if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash) 821231990Smp opv = justabs; 82259243Sobrien else 823231990Smp opv = v->vec; 82459243Sobrien sav = Strspl(STRslash, name); /* / command name for postpending */ 82559243Sobrien hashval = havhash ? hashname(name) : 0; 826231990Smp 827231990Smp rehashed = 0; 828231990Smpretry: 829231990Smp pv = opv; 83059243Sobrien i = 0; 83159243Sobrien do { 83259243Sobrien if (!slash && ABSOLUTEP(pv[0]) && havhash) { 83359243Sobrien#ifdef FASTHASH 83459243Sobrien if (!bit(hashval, i)) 83559243Sobrien goto cont; 83659243Sobrien#else /* OLDHASH */ 83759243Sobrien int hashval1 = hash(hashval, i); 83859243Sobrien if (!bit(xhash, hashval1)) 83959243Sobrien goto cont; 84059243Sobrien#endif /* FASTHASH */ 84159243Sobrien } 84259243Sobrien if (pv[0][0] == 0 || eq(pv[0], STRdot)) { /* don't make ./xxx */ 84359243Sobrien if (executable(NULL, name, 0)) { 844167465Smp xfree(sav); 84559243Sobrien return i + 1; 84659243Sobrien } 84759243Sobrien } 84859243Sobrien else { 84959243Sobrien if (executable(*pv, sav, 0)) { 850167465Smp xfree(sav); 85159243Sobrien return i + 1; 85259243Sobrien } 85359243Sobrien } 85459243Sobriencont: 85559243Sobrien pv++; 85659243Sobrien i++; 85759243Sobrien } while (*pv); 858231990Smp if (adrof(STRautorehash) && !rehashed && havhash && opv != justabs) { 859231990Smp dohash(NULL, NULL); 860231990Smp rehashed = 1; 861231990Smp goto retry; 862231990Smp } 863167465Smp xfree(sav); 86459243Sobrien return 0; 86559243Sobrien} 86659243Sobrien 86759243Sobrien/* Also by: 86859243Sobrien * Andreas Luik <luik@isaak.isa.de> 86959243Sobrien * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 87059243Sobrien * Azenberstr. 35 87159243Sobrien * D-7000 Stuttgart 1 87259243Sobrien * West-Germany 87359243Sobrien * is the executable() routine below and changes to iscommand(). 87459243Sobrien * Thanks again!! 87559243Sobrien */ 87659243Sobrien 87769408Sache#ifndef WINNT_NATIVE 87859243Sobrien/* 87959243Sobrien * executable() examines the pathname obtained by concatenating dir and name 88059243Sobrien * (dir may be NULL), and returns 1 either if it is executable by us, or 88159243Sobrien * if dir_ok is set and the pathname refers to a directory. 88259243Sobrien * This is a bit kludgy, but in the name of optimization... 88359243Sobrien */ 88459243Sobrienint 885167465Smpexecutable(const Char *dir, const Char *name, int dir_ok) 88659243Sobrien{ 88759243Sobrien struct stat stbuf; 88859243Sobrien char *strname; 88959243Sobrien 89059243Sobrien if (dir && *dir) { 891167465Smp Char *path; 892167465Smp 893167465Smp path = Strspl(dir, name); 89459243Sobrien strname = short2str(path); 895167465Smp xfree(path); 89659243Sobrien } 89759243Sobrien else 89859243Sobrien strname = short2str(name); 899167465Smp 90059243Sobrien return (stat(strname, &stbuf) != -1 && 90159243Sobrien ((dir_ok && S_ISDIR(stbuf.st_mode)) || 90259243Sobrien (S_ISREG(stbuf.st_mode) && 90359243Sobrien /* save time by not calling access() in the hopeless case */ 90459243Sobrien (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) && 90559243Sobrien access(strname, X_OK) == 0 90659243Sobrien ))); 90759243Sobrien} 90869408Sache#endif /*!WINNT_NATIVE*/ 90959243Sobrien 910167465Smpstruct tellmewhat_s0_cleanup 911167465Smp{ 912167465Smp Char **dest, *val; 913167465Smp}; 914167465Smp 915167465Smpstatic void 916167465Smptellmewhat_s0_cleanup(void *xstate) 917167465Smp{ 918167465Smp struct tellmewhat_s0_cleanup *state; 919167465Smp 920167465Smp state = xstate; 921167465Smp *state->dest = state->val; 922167465Smp} 923167465Smp 92459243Sobrienint 925167465Smptellmewhat(struct wordent *lexp, Char **str) 92659243Sobrien{ 927167465Smp struct tellmewhat_s0_cleanup s0; 928145479Smp int i; 929167465Smp const struct biltins *bptr; 930145479Smp struct wordent *sp = lexp->next; 931145479Smp int aliased = 0, found; 932167465Smp Char *s1, *s2, *cmd; 93359243Sobrien Char qc; 93459243Sobrien 93559243Sobrien if (adrof1(sp->word, &aliases)) { 93659243Sobrien alias(lexp); 93759243Sobrien sp = lexp->next; 93859243Sobrien aliased = 1; 93959243Sobrien } 94059243Sobrien 941167465Smp s0.dest = &sp->word; /* to get the memory freeing right... */ 942167465Smp s0.val = sp->word; 943167465Smp cleanup_push(&s0, tellmewhat_s0_cleanup); 94459243Sobrien 94559243Sobrien /* handle quoted alias hack */ 94659243Sobrien if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE) 94759243Sobrien (sp->word)++; 94859243Sobrien 94959243Sobrien /* do quoting, if it hasn't been done */ 95059243Sobrien s1 = s2 = sp->word; 95159243Sobrien while (*s2) 95259243Sobrien switch (*s2) { 95359243Sobrien case '\'': 95459243Sobrien case '"': 95559243Sobrien qc = *s2++; 95659243Sobrien while (*s2 && *s2 != qc) 95759243Sobrien *s1++ = *s2++ | QUOTE; 95859243Sobrien if (*s2) 95959243Sobrien s2++; 96059243Sobrien break; 96159243Sobrien case '\\': 96259243Sobrien if (*++s2) 96359243Sobrien *s1++ = *s2++ | QUOTE; 96459243Sobrien break; 96559243Sobrien default: 96659243Sobrien *s1++ = *s2++; 96759243Sobrien } 96859243Sobrien *s1 = '\0'; 96959243Sobrien 97059243Sobrien for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) { 97159243Sobrien if (eq(sp->word, str2short(bptr->bname))) { 97259243Sobrien if (str == NULL) { 97359243Sobrien if (aliased) 97459243Sobrien prlex(lexp); 97559243Sobrien xprintf(CGETS(13, 5, "%S: shell built-in command.\n"), 97659243Sobrien sp->word); 97759243Sobrien flush(); 97859243Sobrien } 979167465Smp else 980167465Smp *str = Strsave(sp->word); 981167465Smp cleanup_until(&s0); 98259243Sobrien return TRUE; 98359243Sobrien } 98459243Sobrien } 98569408Sache#ifdef WINNT_NATIVE 98659243Sobrien for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) { 98759243Sobrien if (eq(sp->word, str2short(bptr->bname))) { 98859243Sobrien if (str == NULL) { 98959243Sobrien if (aliased) 99059243Sobrien prlex(lexp); 99159243Sobrien xprintf(CGETS(13, 5, "%S: shell built-in command.\n"), 99259243Sobrien sp->word); 99359243Sobrien flush(); 99459243Sobrien } 995167465Smp else 996167465Smp *str = Strsave(sp->word); 997167465Smp cleanup_until(&s0); 99859243Sobrien return TRUE; 99959243Sobrien } 100059243Sobrien } 100169408Sache#endif /* WINNT_NATIVE*/ 100259243Sobrien 100359243Sobrien sp->word = cmd = globone(sp->word, G_IGNORE); 1004167465Smp cleanup_push(cmd, xfree); 100559243Sobrien 100659243Sobrien if ((i = iscommand(sp->word)) != 0) { 1007145479Smp Char **pv; 1008145479Smp struct varent *v; 1009145479Smp int slash = any(short2str(sp->word), '/'); 101059243Sobrien 101159243Sobrien v = adrof(STRpath); 1012100616Smp if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash) 101359243Sobrien pv = justabs; 101459243Sobrien else 101559243Sobrien pv = v->vec; 101659243Sobrien 1017167465Smp pv += i - 1; 101859243Sobrien if (pv[0][0] == 0 || eq(pv[0], STRdot)) { 101959243Sobrien if (!slash) { 102059243Sobrien sp->word = Strspl(STRdotsl, sp->word); 1021167465Smp cleanup_push(sp->word, xfree); 102259243Sobrien prlex(lexp); 1023167465Smp cleanup_until(sp->word); 102459243Sobrien } 102559243Sobrien else 102659243Sobrien prlex(lexp); 102759243Sobrien } 102859243Sobrien else { 102959243Sobrien s1 = Strspl(*pv, STRslash); 103059243Sobrien sp->word = Strspl(s1, sp->word); 1031167465Smp xfree(s1); 1032167465Smp cleanup_push(sp->word, xfree); 103359243Sobrien if (str == NULL) 103459243Sobrien prlex(lexp); 103559243Sobrien else 1036167465Smp *str = Strsave(sp->word); 1037167465Smp cleanup_until(sp->word); 103859243Sobrien } 103959243Sobrien found = 1; 104059243Sobrien } 104159243Sobrien else { 104259243Sobrien if (str == NULL) { 104359243Sobrien if (aliased) 104459243Sobrien prlex(lexp); 104559243Sobrien xprintf(CGETS(13, 6, "%S: Command not found.\n"), sp->word); 104659243Sobrien flush(); 104759243Sobrien } 104859243Sobrien else 1049167465Smp *str = Strsave(sp->word); 105059243Sobrien found = 0; 105159243Sobrien } 1052167465Smp cleanup_until(&s0); 105359243Sobrien return found; 105459243Sobrien} 105559243Sobrien 105659243Sobrien/* 105759243Sobrien * Builtin to look at and list all places a command may be defined: 105859243Sobrien * aliases, shell builtins, and the path. 105959243Sobrien * 106059243Sobrien * Marc Horowitz <marc@mit.edu> 106159243Sobrien * MIT Student Information Processing Board 106259243Sobrien */ 106359243Sobrien 106459243Sobrien/*ARGSUSED*/ 106559243Sobrienvoid 1066167465Smpdowhere(Char **v, struct command *c) 106759243Sobrien{ 106859243Sobrien int found = 1; 106959243Sobrien USE(c); 1070316957Sdchagin 1071316957Sdchagin if (adrof(STRautorehash)) 1072316957Sdchagin dohash(NULL, NULL); 107359243Sobrien for (v++; *v; v++) 107459243Sobrien found &= find_cmd(*v, 1); 107559243Sobrien /* Make status nonzero if any command is not found. */ 107659243Sobrien if (!found) 1077167465Smp setcopy(STRstatus, STR1, VAR_READWRITE); 107859243Sobrien} 107959243Sobrien 108059243Sobrienint 1081167465Smpfind_cmd(Char *cmd, int prt) 108259243Sobrien{ 108359243Sobrien struct varent *var; 1084167465Smp const struct biltins *bptr; 108559243Sobrien Char **pv; 108659243Sobrien Char *sv; 1087231990Smp int hashval, rehashed, i, ex, rval = 0; 108859243Sobrien 108959243Sobrien if (prt && any(short2str(cmd), '/')) { 1090195609Smp xprintf("%s", CGETS(13, 7, "where: / in command makes no sense\n")); 109159243Sobrien return rval; 109259243Sobrien } 109359243Sobrien 109459243Sobrien /* first, look for an alias */ 109559243Sobrien 109659243Sobrien if (prt && adrof1(cmd, &aliases)) { 109759243Sobrien if ((var = adrof1(cmd, &aliases)) != NULL) { 109859243Sobrien xprintf(CGETS(13, 8, "%S is aliased to "), cmd); 1099100616Smp if (var->vec != NULL) 1100100616Smp blkpr(var->vec); 110159243Sobrien xputchar('\n'); 110259243Sobrien rval = 1; 110359243Sobrien } 110459243Sobrien } 110559243Sobrien 110659243Sobrien /* next, look for a shell builtin */ 110759243Sobrien 110859243Sobrien for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) { 110959243Sobrien if (eq(cmd, str2short(bptr->bname))) { 111059243Sobrien rval = 1; 111159243Sobrien if (prt) 111259243Sobrien xprintf(CGETS(13, 9, "%S is a shell built-in\n"), cmd); 111359243Sobrien else 111459243Sobrien return rval; 111559243Sobrien } 111659243Sobrien } 111769408Sache#ifdef WINNT_NATIVE 111859243Sobrien for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) { 111959243Sobrien if (eq(cmd, str2short(bptr->bname))) { 112059243Sobrien rval = 1; 112159243Sobrien if (prt) 112259243Sobrien xprintf(CGETS(13, 9, "%S is a shell built-in\n"), cmd); 112359243Sobrien else 112459243Sobrien return rval; 112559243Sobrien } 112659243Sobrien } 112769408Sache#endif /* WINNT_NATIVE*/ 112859243Sobrien 112959243Sobrien /* last, look through the path for the command */ 113059243Sobrien 113159243Sobrien if ((var = adrof(STRpath)) == NULL) 113259243Sobrien return rval; 113359243Sobrien 113459243Sobrien hashval = havhash ? hashname(cmd) : 0; 113559243Sobrien 113659243Sobrien sv = Strspl(STRslash, cmd); 1137167465Smp cleanup_push(sv, xfree); 113859243Sobrien 1139231990Smp rehashed = 0; 1140231990Smpretry: 1141100616Smp for (pv = var->vec, i = 0; pv && *pv; pv++, i++) { 114259243Sobrien if (havhash && !eq(*pv, STRdot)) { 114359243Sobrien#ifdef FASTHASH 114459243Sobrien if (!bit(hashval, i)) 114559243Sobrien continue; 114659243Sobrien#else /* OLDHASH */ 114759243Sobrien int hashval1 = hash(hashval, i); 114859243Sobrien if (!bit(xhash, hashval1)) 114959243Sobrien continue; 115059243Sobrien#endif /* FASTHASH */ 115159243Sobrien } 115259243Sobrien ex = executable(*pv, sv, 0); 115359243Sobrien#ifdef FASTHASH 115459243Sobrien if (!ex && (hashdebug & 2)) { 1155195609Smp xprintf("%s", CGETS(13, 10, "hash miss: ")); 115659243Sobrien ex = 1; /* Force printing */ 115759243Sobrien } 115859243Sobrien#endif /* FASTHASH */ 115959243Sobrien if (ex) { 116059243Sobrien rval = 1; 116159243Sobrien if (prt) { 116259243Sobrien xprintf("%S/", *pv); 116359243Sobrien xprintf("%S\n", cmd); 116459243Sobrien } 116559243Sobrien else 116659243Sobrien return rval; 116759243Sobrien } 116859243Sobrien } 1169316957Sdchagin /* 1170316957Sdchagin * If we are printing, we are being called from dowhere() which it 1171316957Sdchagin * has rehashed already 1172316957Sdchagin */ 1173316957Sdchagin if (!prt && adrof(STRautorehash) && !rehashed && havhash) { 1174231990Smp dohash(NULL, NULL); 1175231990Smp rehashed = 1; 1176231990Smp goto retry; 1177231990Smp } 1178167465Smp cleanup_until(sv); 117959243Sobrien return rval; 118059243Sobrien} 118169408Sache#ifdef WINNT_NATIVE 118259243Sobrienint hashval_extern(cp) 118359243Sobrien Char *cp; 118459243Sobrien{ 118559243Sobrien return havhash?hashname(cp):0; 118659243Sobrien} 118759243Sobrienint bit_extern(val,i) 118859243Sobrien int val; 118959243Sobrien int i; 119059243Sobrien{ 119159243Sobrien return bit(val,i); 119259243Sobrien} 119369408Sachevoid bis_extern(val,i) 119469408Sache int val; 119569408Sache int i; 119669408Sache{ 119769408Sache bis(val,i); 119869408Sache} 119969408Sache#endif /* WINNT_NATIVE */ 120069408Sache 1201