1231990Smp/* $Header: /p/tcsh/cvsroot/tcsh/sh.exec.c,v 3.79 2011/02/25 23:58:34 christos Exp $ */ 259243Sobrien/* 359243Sobrien * sh.exec.c: Search, find, and execute a command! 459243Sobrien */ 559243Sobrien/*- 659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 759243Sobrien * All rights reserved. 859243Sobrien * 959243Sobrien * Redistribution and use in source and binary forms, with or without 1059243Sobrien * modification, are permitted provided that the following conditions 1159243Sobrien * are met: 1259243Sobrien * 1. Redistributions of source code must retain the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer. 1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1559243Sobrien * notice, this list of conditions and the following disclaimer in the 1659243Sobrien * documentation and/or other materials provided with the distribution. 17100616Smp * 3. Neither the name of the University nor the names of its contributors 1859243Sobrien * may be used to endorse or promote products derived from this software 1959243Sobrien * without specific prior written permission. 2059243Sobrien * 2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2459243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3159243Sobrien * SUCH DAMAGE. 3259243Sobrien */ 3359243Sobrien#include "sh.h" 3459243Sobrien 35231990SmpRCSID("$tcsh: sh.exec.c,v 3.79 2011/02/25 23:58:34 christos Exp $") 3659243Sobrien 3759243Sobrien#include "tc.h" 3859243Sobrien#include "tw.h" 3969408Sache#ifdef WINNT_NATIVE 4059243Sobrien#include <nt.const.h> 4169408Sache#endif /*WINNT_NATIVE*/ 4259243Sobrien 4359243Sobrien/* 4459243Sobrien * C shell 4559243Sobrien */ 4659243Sobrien 4759243Sobrien#ifndef OLDHASH 4859243Sobrien# define FASTHASH /* Fast hashing is the default */ 4959243Sobrien#endif /* OLDHASH */ 5059243Sobrien 5159243Sobrien/* 5259243Sobrien * System level search and execute of a command. 5359243Sobrien * We look in each directory for the specified command name. 5459243Sobrien * If the name contains a '/' then we execute only the full path name. 5559243Sobrien * If there is no search path then we execute only full path names. 5659243Sobrien */ 5759243Sobrien 5859243Sobrien/* 5959243Sobrien * As we search for the command we note the first non-trivial error 6059243Sobrien * message for presentation to the user. This allows us often 6159243Sobrien * to show that a file has the wrong mode/no access when the file 6259243Sobrien * is not in the last component of the search path, so we must 6359243Sobrien * go on after first detecting the error. 6459243Sobrien */ 6559243Sobrienstatic char *exerr; /* Execution error message */ 6659243Sobrienstatic Char *expath; /* Path for exerr */ 6759243Sobrien 6859243Sobrien/* 6959243Sobrien * The two part hash function is designed to let texec() call the 7059243Sobrien * more expensive hashname() only once and the simple hash() several 7159243Sobrien * times (once for each path component checked). 7259243Sobrien * Byte size is assumed to be 8. 7359243Sobrien */ 7459243Sobrien#define BITS_PER_BYTE 8 7559243Sobrien 7659243Sobrien#ifdef FASTHASH 7759243Sobrien/* 7859243Sobrien * xhash is an array of hash buckets which are used to hash execs. If 7959243Sobrien * it is allocated (havhash true), then to tell if ``name'' is 80231990Smp * (possibly) present in the i'th component of the variable path, look 8159243Sobrien * at the [hashname(name)] bucket of size [hashwidth] bytes, in the [i 8259243Sobrien * mod size*8]'th bit. The cache size is defaults to a length of 1024 8359243Sobrien * buckets, each 1 byte wide. This implementation guarantees that 8459243Sobrien * objects n bytes wide will be aligned on n byte boundaries. 8559243Sobrien */ 8659243Sobrien# define HSHMUL 241 8759243Sobrien 8859243Sobrienstatic unsigned long *xhash = NULL; 8959243Sobrienstatic unsigned int hashlength = 0, uhashlength = 0; 9059243Sobrienstatic unsigned int hashwidth = 0, uhashwidth = 0; 9159243Sobrienstatic int hashdebug = 0; 9259243Sobrien 9359243Sobrien# define hash(a, b) (((a) * HSHMUL + (b)) % (hashlength)) 9459243Sobrien# define widthof(t) (sizeof(t) * BITS_PER_BYTE) 9559243Sobrien# define tbit(f, i, t) (((t *) xhash)[(f)] & \ 96145479Smp (1UL << (i & (widthof(t) - 1)))) 9759243Sobrien# define tbis(f, i, t) (((t *) xhash)[(f)] |= \ 98145479Smp (1UL << (i & (widthof(t) - 1)))) 9959243Sobrien# define cbit(f, i) tbit(f, i, unsigned char) 10059243Sobrien# define cbis(f, i) tbis(f, i, unsigned char) 10159243Sobrien# define sbit(f, i) tbit(f, i, unsigned short) 10259243Sobrien# define sbis(f, i) tbis(f, i, unsigned short) 10359243Sobrien# define ibit(f, i) tbit(f, i, unsigned int) 10459243Sobrien# define ibis(f, i) tbis(f, i, unsigned int) 10559243Sobrien# define lbit(f, i) tbit(f, i, unsigned long) 10659243Sobrien# define lbis(f, i) tbis(f, i, unsigned long) 10759243Sobrien 10859243Sobrien# define bit(f, i) (hashwidth==sizeof(unsigned char) ? cbit(f,i) : \ 10959243Sobrien ((hashwidth==sizeof(unsigned short) ? sbit(f,i) : \ 11059243Sobrien ((hashwidth==sizeof(unsigned int) ? ibit(f,i) : \ 11159243Sobrien lbit(f,i)))))) 11259243Sobrien# define bis(f, i) (hashwidth==sizeof(unsigned char) ? cbis(f,i) : \ 11359243Sobrien ((hashwidth==sizeof(unsigned short) ? sbis(f,i) : \ 11459243Sobrien ((hashwidth==sizeof(unsigned int) ? ibis(f,i) : \ 11559243Sobrien lbis(f,i)))))) 11659243Sobrien#else /* OLDHASH */ 11759243Sobrien/* 11859243Sobrien * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used 11959243Sobrien * to hash execs. If it is allocated (havhash true), then to tell 12059243Sobrien * whether ``name'' is (possibly) present in the i'th component 12159243Sobrien * of the variable path, you look at the bit in xhash indexed by 12259243Sobrien * hash(hashname("name"), i). This is setup automatically 12359243Sobrien * after .login is executed, and recomputed whenever ``path'' is 12459243Sobrien * changed. 12559243Sobrien */ 12659243Sobrien# define HSHSIZ 8192 /* 1k bytes */ 12759243Sobrien# define HSHMASK (HSHSIZ - 1) 12859243Sobrien# define HSHMUL 243 12959243Sobrienstatic char xhash[HSHSIZ / BITS_PER_BYTE]; 13059243Sobrien 13159243Sobrien# define hash(a, b) (((a) * HSHMUL + (b)) & HSHMASK) 13259243Sobrien# define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */ 13359243Sobrien# define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */ 13459243Sobrien 13559243Sobrien#endif /* FASTHASH */ 13659243Sobrien 13759243Sobrien#ifdef VFORK 13859243Sobrienstatic int hits, misses; 13959243Sobrien#endif /* VFORK */ 14059243Sobrien 14159243Sobrien/* Dummy search path for just absolute search when no path */ 14259243Sobrienstatic Char *justabs[] = {STRNULL, 0}; 14359243Sobrien 144231990Smpstatic void pexerr (void) __attribute__((__noreturn__)); 145167465Smpstatic void texec (Char *, Char **); 146167465Smpint hashname (Char *); 147167465Smpstatic int iscommand (Char *); 14859243Sobrien 14959243Sobrienvoid 150167465Smpdoexec(struct command *t, int do_glob) 15159243Sobrien{ 152231990Smp Char *dp, **pv, **opv, **av, *sav; 153100616Smp struct varent *v; 154231990Smp int slash, gflag, rehashed; 155100616Smp int hashval, i; 15659243Sobrien Char *blk[2]; 15759243Sobrien 15859243Sobrien /* 15959243Sobrien * Glob the command name. We will search $path even if this does something, 16059243Sobrien * as in sh but not in csh. One special case: if there is no PATH, then we 16159243Sobrien * execute only commands which start with '/'. 16259243Sobrien */ 16359243Sobrien blk[0] = t->t_dcom[0]; 16459243Sobrien blk[1] = 0; 165100616Smp gflag = 0; 166100616Smp if (do_glob) 167167465Smp gflag = tglob(blk); 16859243Sobrien if (gflag) { 169167465Smp pv = globall(blk, gflag); 17059243Sobrien if (pv == 0) { 17159243Sobrien setname(short2str(blk[0])); 17259243Sobrien stderror(ERR_NAME | ERR_NOMATCH); 17359243Sobrien } 17459243Sobrien } 17559243Sobrien else 17659243Sobrien pv = saveblk(blk); 177167465Smp cleanup_push(pv, blk_cleanup); 17859243Sobrien 17959243Sobrien trim(pv); 18059243Sobrien 18159243Sobrien exerr = 0; 18259243Sobrien expath = Strsave(pv[0]); 18359243Sobrien#ifdef VFORK 18459243Sobrien Vexpath = expath; 18559243Sobrien#endif /* VFORK */ 18659243Sobrien 18759243Sobrien v = adrof(STRpath); 188167465Smp if (v == 0 && expath[0] != '/' && expath[0] != '.') 18959243Sobrien pexerr(); 19059243Sobrien slash = any(short2str(expath), '/'); 19159243Sobrien 19259243Sobrien /* 19359243Sobrien * Glob the argument list, if necessary. Otherwise trim off the quote bits. 19459243Sobrien */ 19559243Sobrien gflag = 0; 19659243Sobrien av = &t->t_dcom[1]; 197100616Smp if (do_glob) 198167465Smp gflag = tglob(av); 19959243Sobrien if (gflag) { 200167465Smp av = globall(av, gflag); 20159243Sobrien if (av == 0) { 20259243Sobrien setname(short2str(expath)); 20359243Sobrien stderror(ERR_NAME | ERR_NOMATCH); 20459243Sobrien } 20559243Sobrien } 20659243Sobrien else 20759243Sobrien av = saveblk(av); 20859243Sobrien 20959243Sobrien blkfree(t->t_dcom); 210167465Smp cleanup_ignore(pv); 211167465Smp cleanup_until(pv); 21259243Sobrien t->t_dcom = blkspl(pv, av); 213167465Smp xfree(pv); 214167465Smp xfree(av); 21559243Sobrien av = t->t_dcom; 21659243Sobrien trim(av); 21759243Sobrien 21859243Sobrien if (*av == NULL || **av == '\0') 21959243Sobrien pexerr(); 22059243Sobrien 22159243Sobrien xechoit(av); /* Echo command if -x */ 22259243Sobrien#ifdef CLOSE_ON_EXEC 22359243Sobrien /* 22459243Sobrien * Since all internal file descriptors are set to close on exec, we don't 22559243Sobrien * need to close them explicitly here. Just reorient ourselves for error 22659243Sobrien * messages. 22759243Sobrien */ 22859243Sobrien SHIN = 0; 22959243Sobrien SHOUT = 1; 23059243Sobrien SHDIAG = 2; 23159243Sobrien OLDSTD = 0; 23259243Sobrien isoutatty = isatty(SHOUT); 23359243Sobrien isdiagatty = isatty(SHDIAG); 23459243Sobrien#else 23559243Sobrien closech(); /* Close random fd's */ 23659243Sobrien#endif 23759243Sobrien /* 23859243Sobrien * We must do this AFTER any possible forking (like `foo` in glob) so that 23959243Sobrien * this shell can still do subprocesses. 24059243Sobrien */ 241167465Smp { 242167465Smp sigset_t set; 243167465Smp sigemptyset(&set); 244167465Smp sigaddset(&set, SIGINT); 245167465Smp sigaddset(&set, SIGCHLD); 246167465Smp sigprocmask(SIG_UNBLOCK, &set, NULL); 247167465Smp } 248167465Smp pintr_disabled = 0; 249167465Smp pchild_disabled = 0; 25059243Sobrien 25159243Sobrien /* 25259243Sobrien * If no path, no words in path, or a / in the filename then restrict the 25359243Sobrien * command search. 25459243Sobrien */ 255100616Smp if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash) 256231990Smp opv = justabs; 25759243Sobrien else 258231990Smp opv = v->vec; 25959243Sobrien sav = Strspl(STRslash, *av);/* / command name for postpending */ 260167465Smp#ifndef VFORK 261167465Smp cleanup_push(sav, xfree); 262167465Smp#else /* VFORK */ 26359243Sobrien Vsav = sav; 26459243Sobrien#endif /* VFORK */ 26559243Sobrien hashval = havhash ? hashname(*av) : 0; 26659243Sobrien 267231990Smp rehashed = 0; 268231990Smpretry: 269231990Smp pv = opv; 27059243Sobrien i = 0; 27159243Sobrien#ifdef VFORK 27259243Sobrien hits++; 27359243Sobrien#endif /* VFORK */ 27459243Sobrien do { 27559243Sobrien /* 27659243Sobrien * Try to save time by looking at the hash table for where this command 27759243Sobrien * could be. If we are doing delayed hashing, then we put the names in 27859243Sobrien * one at a time, as the user enters them. This is kinda like Korn 27959243Sobrien * Shell's "tracked aliases". 28059243Sobrien */ 28159243Sobrien if (!slash && ABSOLUTEP(pv[0]) && havhash) { 28259243Sobrien#ifdef FASTHASH 28359243Sobrien if (!bit(hashval, i)) 28459243Sobrien goto cont; 28559243Sobrien#else /* OLDHASH */ 28659243Sobrien int hashval1 = hash(hashval, i); 28759243Sobrien if (!bit(xhash, hashval1)) 28859243Sobrien goto cont; 28959243Sobrien#endif /* FASTHASH */ 29059243Sobrien } 29159243Sobrien if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */ 29259243Sobrien texec(*av, av); 29359243Sobrien else { 29459243Sobrien dp = Strspl(*pv, sav); 295167465Smp#ifndef VFORK 296167465Smp cleanup_push(dp, xfree); 297167465Smp#else /* VFORK */ 29859243Sobrien Vdp = dp; 29959243Sobrien#endif /* VFORK */ 30059243Sobrien 30159243Sobrien texec(dp, av); 302167465Smp#ifndef VFORK 303167465Smp cleanup_until(dp); 304167465Smp#else /* VFORK */ 30559243Sobrien Vdp = 0; 306167465Smp xfree(dp); 30759243Sobrien#endif /* VFORK */ 30859243Sobrien } 30959243Sobrien#ifdef VFORK 31059243Sobrien misses++; 31159243Sobrien#endif /* VFORK */ 31259243Sobriencont: 31359243Sobrien pv++; 31459243Sobrien i++; 31559243Sobrien } while (*pv); 31659243Sobrien#ifdef VFORK 31759243Sobrien hits--; 318167465Smp#endif /* VFORK */ 319231990Smp if (adrof(STRautorehash) && !rehashed && havhash && opv != justabs) { 320231990Smp dohash(NULL, NULL); 321231990Smp rehashed = 1; 322231990Smp goto retry; 323231990Smp } 324167465Smp#ifndef VFORK 325167465Smp cleanup_until(sav); 326167465Smp#else /* VFORK */ 32759243Sobrien Vsav = 0; 328167465Smp xfree(sav); 32959243Sobrien#endif /* VFORK */ 33059243Sobrien pexerr(); 33159243Sobrien} 33259243Sobrien 33359243Sobrienstatic void 334167465Smppexerr(void) 33559243Sobrien{ 33659243Sobrien /* Couldn't find the damn thing */ 33759243Sobrien if (expath) { 33859243Sobrien setname(short2str(expath)); 33959243Sobrien#ifdef VFORK 34059243Sobrien Vexpath = 0; 34159243Sobrien#endif /* VFORK */ 342167465Smp xfree(expath); 34359243Sobrien expath = 0; 34459243Sobrien } 34559243Sobrien else 34659243Sobrien setname(""); 34759243Sobrien if (exerr) 34859243Sobrien stderror(ERR_NAME | ERR_STRING, exerr); 34959243Sobrien stderror(ERR_NAME | ERR_COMMAND); 35059243Sobrien} 35159243Sobrien 35259243Sobrien/* 35359243Sobrien * Execute command f, arg list t. 35459243Sobrien * Record error message if not found. 35559243Sobrien * Also do shell scripts here. 35659243Sobrien */ 35759243Sobrienstatic void 358167465Smptexec(Char *sf, Char **st) 35959243Sobrien{ 360145479Smp char **t; 361145479Smp char *f; 362145479Smp struct varent *v; 36359243Sobrien Char **vp; 36459243Sobrien Char *lastsh[2]; 36559243Sobrien char pref[2]; 36659243Sobrien int fd; 36759243Sobrien Char *st0, **ost; 36859243Sobrien 36959243Sobrien /* The order for the conversions is significant */ 37059243Sobrien t = short2blk(st); 37159243Sobrien f = short2str(sf); 37259243Sobrien#ifdef VFORK 37359243Sobrien Vt = t; 37459243Sobrien#endif /* VFORK */ 37559243Sobrien errno = 0; /* don't use a previous error */ 37659243Sobrien#ifdef apollo 37759243Sobrien /* 37859243Sobrien * If we try to execute an nfs mounted directory on the apollo, we 37959243Sobrien * hang forever. So until apollo fixes that.. 38059243Sobrien */ 38159243Sobrien { 38259243Sobrien struct stat stb; 38359243Sobrien if (stat(f, &stb) == 0 && S_ISDIR(stb.st_mode)) 38459243Sobrien errno = EISDIR; 38559243Sobrien } 38659243Sobrien if (errno == 0) 38759243Sobrien#endif /* apollo */ 38859243Sobrien { 38959243Sobrien#ifdef ISC_POSIX_EXEC_BUG 39059243Sobrien __setostype(0); /* "0" is "__OS_SYSV" in <sys/user.h> */ 39159243Sobrien#endif /* ISC_POSIX_EXEC_BUG */ 39259243Sobrien (void) execv(f, t); 39359243Sobrien#ifdef ISC_POSIX_EXEC_BUG 39459243Sobrien __setostype(1); /* "1" is "__OS_POSIX" in <sys/user.h> */ 39559243Sobrien#endif /* ISC_POSIX_EXEC_BUG */ 39659243Sobrien } 39759243Sobrien#ifdef VFORK 39859243Sobrien Vt = 0; 39959243Sobrien#endif /* VFORK */ 40059243Sobrien blkfree((Char **) t); 40159243Sobrien switch (errno) { 40259243Sobrien 40359243Sobrien case ENOEXEC: 40469408Sache#ifdef WINNT_NATIVE 40559243Sobrien nt_feed_to_cmd(f,t); 40669408Sache#endif /* WINNT_NATIVE */ 40759243Sobrien /* 40859243Sobrien * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute 40959243Sobrien * it, don't feed it to the shell if it looks like a binary! 41059243Sobrien */ 411167465Smp if ((fd = xopen(f, O_RDONLY|O_LARGEFILE)) != -1) { 41259243Sobrien int nread; 413167465Smp if ((nread = xread(fd, pref, 2)) == 2) { 414145479Smp if (!isprint((unsigned char)pref[0]) && 415145479Smp (pref[0] != '\n' && pref[0] != '\t')) { 416167465Smp int err; 417167465Smp 418167465Smp err = errno; 419167465Smp xclose(fd); 42059243Sobrien /* 42159243Sobrien * We *know* what ENOEXEC means. 42259243Sobrien */ 423167465Smp stderror(ERR_ARCH, f, strerror(err)); 42459243Sobrien } 42559243Sobrien } 426167465Smp else if (nread < 0) { 42759243Sobrien#ifdef convex 428167465Smp int err; 429167465Smp 430167465Smp err = errno; 431167465Smp xclose(fd); 43259243Sobrien /* need to print error incase the file is migrated */ 433167465Smp stderror(ERR_SYSTEM, f, strerror(err)); 43459243Sobrien#endif 43559243Sobrien } 43659243Sobrien#ifdef _PATH_BSHELL 43759243Sobrien else { 43859243Sobrien pref[0] = '#'; 43959243Sobrien pref[1] = '\0'; 44059243Sobrien } 44159243Sobrien#endif 44259243Sobrien } 44359243Sobrien#ifdef HASHBANG 44459243Sobrien if (fd == -1 || 44559243Sobrien pref[0] != '#' || pref[1] != '!' || hashbang(fd, &vp) == -1) { 44659243Sobrien#endif /* HASHBANG */ 44759243Sobrien /* 44859243Sobrien * If there is an alias for shell, then put the words of the alias in 44959243Sobrien * front of the argument list replacing the command name. Note no 45059243Sobrien * interpretation of the words at this point. 45159243Sobrien */ 45259243Sobrien v = adrof1(STRshell, &aliases); 453100616Smp if (v == NULL || v->vec == NULL) { 45459243Sobrien vp = lastsh; 45559243Sobrien vp[0] = adrof(STRshell) ? varval(STRshell) : STR_SHELLPATH; 45659243Sobrien vp[1] = NULL; 45759243Sobrien#ifdef _PATH_BSHELL 45859243Sobrien if (fd != -1 45959243Sobrien# ifndef ISC /* Compatible with ISC's /bin/csh */ 46059243Sobrien && pref[0] != '#' 46159243Sobrien# endif /* ISC */ 46259243Sobrien ) 46359243Sobrien vp[0] = STR_BSHELL; 46459243Sobrien#endif 46559243Sobrien vp = saveblk(vp); 46659243Sobrien } 46759243Sobrien else 46859243Sobrien vp = saveblk(v->vec); 46959243Sobrien#ifdef HASHBANG 47059243Sobrien } 47159243Sobrien#endif /* HASHBANG */ 47259243Sobrien if (fd != -1) 473167465Smp xclose(fd); 47459243Sobrien 47559243Sobrien st0 = st[0]; 47659243Sobrien st[0] = sf; 47759243Sobrien ost = st; 47859243Sobrien st = blkspl(vp, st); /* Splice up the new arglst */ 47959243Sobrien ost[0] = st0; 48059243Sobrien sf = *st; 48159243Sobrien /* The order for the conversions is significant */ 48259243Sobrien t = short2blk(st); 48359243Sobrien f = short2str(sf); 484167465Smp xfree(st); 48559243Sobrien blkfree((Char **) vp); 48659243Sobrien#ifdef VFORK 48759243Sobrien Vt = t; 48859243Sobrien#endif /* VFORK */ 48959243Sobrien#ifdef ISC_POSIX_EXEC_BUG 49059243Sobrien __setostype(0); /* "0" is "__OS_SYSV" in <sys/user.h> */ 49159243Sobrien#endif /* ISC_POSIX_EXEC_BUG */ 49259243Sobrien (void) execv(f, t); 49359243Sobrien#ifdef ISC_POSIX_EXEC_BUG 49459243Sobrien __setostype(1); /* "1" is "__OS_POSIX" in <sys/user.h> */ 49559243Sobrien#endif /* ISC_POSIX_EXEC_BUG */ 49659243Sobrien#ifdef VFORK 49759243Sobrien Vt = 0; 49859243Sobrien#endif /* VFORK */ 49959243Sobrien blkfree((Char **) t); 50059243Sobrien /* The sky is falling, the sky is falling! */ 50159243Sobrien stderror(ERR_SYSTEM, f, strerror(errno)); 50259243Sobrien break; 50359243Sobrien 50459243Sobrien case ENOMEM: 50559243Sobrien stderror(ERR_SYSTEM, f, strerror(errno)); 50659243Sobrien break; 50759243Sobrien 50859243Sobrien#ifdef _IBMR2 50959243Sobrien case 0: /* execv fails and returns 0! */ 51059243Sobrien#endif /* _IBMR2 */ 51159243Sobrien case ENOENT: 51259243Sobrien break; 51359243Sobrien 51459243Sobrien default: 51559243Sobrien if (exerr == 0) { 51659243Sobrien exerr = strerror(errno); 517167465Smp xfree(expath); 51859243Sobrien expath = Strsave(sf); 51959243Sobrien#ifdef VFORK 52059243Sobrien Vexpath = expath; 52159243Sobrien#endif /* VFORK */ 52259243Sobrien } 52359243Sobrien break; 52459243Sobrien } 52559243Sobrien} 52659243Sobrien 527167465Smpstruct execash_state 52859243Sobrien{ 529167465Smp int saveIN, saveOUT, saveDIAG, saveSTD; 530167465Smp int SHIN, SHOUT, SHDIAG, OLDSTD; 531167465Smp int didfds; 53259243Sobrien#ifndef CLOSE_ON_EXEC 533167465Smp int didcch; 534167465Smp#endif 535167465Smp struct sigaction sigint, sigquit, sigterm; 536167465Smp}; 537167465Smp 538167465Smpstatic void 539167465Smpexecash_cleanup(void *xstate) 540167465Smp{ 541167465Smp struct execash_state *state; 542167465Smp 543167465Smp state = xstate; 544167465Smp sigaction(SIGINT, &state->sigint, NULL); 545167465Smp sigaction(SIGQUIT, &state->sigquit, NULL); 546167465Smp sigaction(SIGTERM, &state->sigterm, NULL); 547167465Smp 548167465Smp doneinp = 0; 549167465Smp#ifndef CLOSE_ON_EXEC 550167465Smp didcch = state->didcch; 55159243Sobrien#endif /* CLOSE_ON_EXEC */ 552167465Smp didfds = state->didfds; 553167465Smp xclose(SHIN); 554167465Smp xclose(SHOUT); 555167465Smp xclose(SHDIAG); 556167465Smp xclose(OLDSTD); 557167465Smp close_on_exec(SHIN = dmove(state->saveIN, state->SHIN), 1); 558167465Smp close_on_exec(SHOUT = dmove(state->saveOUT, state->SHOUT), 1); 559167465Smp close_on_exec(SHDIAG = dmove(state->saveDIAG, state->SHDIAG), 1); 560167465Smp close_on_exec(OLDSTD = dmove(state->saveSTD, state->OLDSTD), 1); 561167465Smp} 56259243Sobrien 563167465Smp/*ARGSUSED*/ 564167465Smpvoid 565167465Smpexecash(Char **t, struct command *kp) 566167465Smp{ 567167465Smp struct execash_state state; 568167465Smp 56959243Sobrien USE(t); 57059243Sobrien if (chkstop == 0 && setintr) 57159243Sobrien panystop(0); 57259243Sobrien /* 57359243Sobrien * Hmm, we don't really want to do that now because we might 57459243Sobrien * fail, but what is the choice 57559243Sobrien */ 57659243Sobrien rechist(NULL, adrof(STRsavehist) != NULL); 57759243Sobrien 57859243Sobrien 579167465Smp sigaction(SIGINT, &parintr, &state.sigint); 580167465Smp sigaction(SIGQUIT, &parintr, &state.sigquit); 581167465Smp sigaction(SIGTERM, &parterm, &state.sigterm); 58259243Sobrien 583167465Smp state.didfds = didfds; 58459243Sobrien#ifndef CLOSE_ON_EXEC 585167465Smp state.didcch = didcch; 58659243Sobrien#endif /* CLOSE_ON_EXEC */ 587167465Smp state.SHIN = SHIN; 588167465Smp state.SHOUT = SHOUT; 589167465Smp state.SHDIAG = SHDIAG; 590167465Smp state.OLDSTD = OLDSTD; 59159243Sobrien 592167465Smp (void)close_on_exec (state.saveIN = dcopy(SHIN, -1), 1); 593167465Smp (void)close_on_exec (state.saveOUT = dcopy(SHOUT, -1), 1); 594167465Smp (void)close_on_exec (state.saveDIAG = dcopy(SHDIAG, -1), 1); 595167465Smp (void)close_on_exec (state.saveSTD = dcopy(OLDSTD, -1), 1); 596167465Smp 59759243Sobrien lshift(kp->t_dcom, 1); 59859243Sobrien 599167465Smp (void)close_on_exec (SHIN = dcopy(0, -1), 1); 600167465Smp (void)close_on_exec (SHOUT = dcopy(1, -1), 1); 601167465Smp (void)close_on_exec (SHDIAG = dcopy(2, -1), 1); 60259243Sobrien#ifndef CLOSE_ON_EXEC 603167465Smp didcch = 0; 60459243Sobrien#endif /* CLOSE_ON_EXEC */ 605167465Smp didfds = 0; 606167465Smp cleanup_push(&state, execash_cleanup); 607167465Smp 608167465Smp /* 609167465Smp * Decrement the shell level 610167465Smp */ 611167465Smp shlvl(-1); 61269408Sache#ifdef WINNT_NATIVE 613167465Smp __nt_really_exec=1; 61469408Sache#endif /* WINNT_NATIVE */ 615167465Smp doexec(kp, 1); 61659243Sobrien 617167465Smp cleanup_until(&state); 61859243Sobrien} 61959243Sobrien 62059243Sobrienvoid 621167465Smpxechoit(Char **t) 62259243Sobrien{ 62359243Sobrien if (adrof(STRecho)) { 624100616Smp int odidfds = didfds; 62559243Sobrien flush(); 62659243Sobrien haderr = 1; 627100616Smp didfds = 0; 62859243Sobrien blkpr(t), xputchar('\n'); 629100616Smp flush(); 630100616Smp didfds = odidfds; 63159243Sobrien haderr = 0; 63259243Sobrien } 63359243Sobrien} 63459243Sobrien 63559243Sobrien/*ARGSUSED*/ 63659243Sobrienvoid 637167465Smpdohash(Char **vv, struct command *c) 63859243Sobrien{ 63959243Sobrien#ifdef COMMENT 64059243Sobrien struct stat stb; 64159243Sobrien#endif 64259243Sobrien DIR *dirp; 643145479Smp struct dirent *dp; 64459243Sobrien int i = 0; 64559243Sobrien struct varent *v = adrof(STRpath); 64659243Sobrien Char **pv; 64759243Sobrien int hashval; 64869408Sache#ifdef WINNT_NATIVE 64959243Sobrien int is_windir; /* check if it is the windows directory */ 65059243Sobrien USE(hashval); 65169408Sache#endif /* WINNT_NATIVE */ 65259243Sobrien 65359243Sobrien USE(c); 65459243Sobrien#ifdef FASTHASH 65559243Sobrien if (vv && vv[1]) { 65659243Sobrien uhashlength = atoi(short2str(vv[1])); 65759243Sobrien if (vv[2]) { 65859243Sobrien uhashwidth = atoi(short2str(vv[2])); 65959243Sobrien if ((uhashwidth != sizeof(unsigned char)) && 66059243Sobrien (uhashwidth != sizeof(unsigned short)) && 66159243Sobrien (uhashwidth != sizeof(unsigned long))) 66259243Sobrien uhashwidth = 0; 66359243Sobrien if (vv[3]) 66459243Sobrien hashdebug = atoi(short2str(vv[3])); 66559243Sobrien } 66659243Sobrien } 66759243Sobrien 66859243Sobrien if (uhashwidth) 66959243Sobrien hashwidth = uhashwidth; 67059243Sobrien else { 67159243Sobrien hashwidth = 0; 67269408Sache if (v == NULL) 67369408Sache return; 674100616Smp for (pv = v->vec; pv && *pv; pv++, hashwidth++) 67559243Sobrien continue; 67659243Sobrien if (hashwidth <= widthof(unsigned char)) 67759243Sobrien hashwidth = sizeof(unsigned char); 67859243Sobrien else if (hashwidth <= widthof(unsigned short)) 67959243Sobrien hashwidth = sizeof(unsigned short); 68059243Sobrien else if (hashwidth <= widthof(unsigned int)) 68159243Sobrien hashwidth = sizeof(unsigned int); 68259243Sobrien else 68359243Sobrien hashwidth = sizeof(unsigned long); 68459243Sobrien } 68559243Sobrien 68659243Sobrien if (uhashlength) 68759243Sobrien hashlength = uhashlength; 68859243Sobrien else 68959243Sobrien hashlength = hashwidth * (8*64);/* "average" files per dir in path */ 690167465Smp 691167465Smp xfree(xhash); 692167465Smp xhash = xcalloc(hashlength * hashwidth, 1); 69359243Sobrien#endif /* FASTHASH */ 69459243Sobrien 69559243Sobrien (void) getusername(NULL); /* flush the tilde cashe */ 69659243Sobrien tw_cmd_free(); 69759243Sobrien havhash = 1; 69859243Sobrien if (v == NULL) 69959243Sobrien return; 700100616Smp for (pv = v->vec; pv && *pv; pv++, i++) { 70159243Sobrien if (!ABSOLUTEP(pv[0])) 70259243Sobrien continue; 70359243Sobrien dirp = opendir(short2str(*pv)); 70459243Sobrien if (dirp == NULL) 70559243Sobrien continue; 706167465Smp cleanup_push(dirp, opendir_cleanup); 70759243Sobrien#ifdef COMMENT /* this isn't needed. opendir won't open 70859243Sobrien * non-dirs */ 70959243Sobrien if (fstat(dirp->dd_fd, &stb) < 0 || !S_ISDIR(stb.st_mode)) { 710167465Smp cleanup_until(dirp); 71159243Sobrien continue; 71259243Sobrien } 71359243Sobrien#endif 71469408Sache#ifdef WINNT_NATIVE 71559243Sobrien is_windir = nt_check_if_windir(short2str(*pv)); 71669408Sache#endif /* WINNT_NATIVE */ 71759243Sobrien while ((dp = readdir(dirp)) != NULL) { 71859243Sobrien if (dp->d_ino == 0) 71959243Sobrien continue; 72059243Sobrien if (dp->d_name[0] == '.' && 72159243Sobrien (dp->d_name[1] == '\0' || 72259243Sobrien (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) 72359243Sobrien continue; 72469408Sache#ifdef WINNT_NATIVE 72559243Sobrien nt_check_name_and_hash(is_windir, dp->d_name, i); 72669408Sache#else /* !WINNT_NATIVE*/ 72769408Sache#if defined(_UWIN) || defined(__CYGWIN__) 72859243Sobrien /* Turn foo.{exe,com,bat} into foo since UWIN's readdir returns 72959243Sobrien * the file with the .exe, .com, .bat extension 730231990Smp * 731231990Smp * Same for Cygwin, but only for .exe and .com extension. 73259243Sobrien */ 73359243Sobrien { 734167465Smp ssize_t ext = strlen(dp->d_name) - 4; 735131962Smp if ((ext > 0) && (strcasecmp(&dp->d_name[ext], ".exe") == 0 || 736231990Smp#ifndef __CYGWIN__ 737131962Smp strcasecmp(&dp->d_name[ext], ".bat") == 0 || 738231990Smp#endif 739167465Smp strcasecmp(&dp->d_name[ext], ".com") == 0)) { 740167465Smp#ifdef __CYGWIN__ 741167465Smp /* Also store the variation with extension. */ 742167465Smp hashval = hashname(str2short(dp->d_name)); 743167465Smp bis(hashval, i); 744131962Smp#endif /* __CYGWIN__ */ 745167465Smp dp->d_name[ext] = '\0'; 746167465Smp } 74759243Sobrien } 74869408Sache#endif /* _UWIN || __CYGWIN__ */ 74959243Sobrien# ifdef FASTHASH 75059243Sobrien hashval = hashname(str2short(dp->d_name)); 75159243Sobrien bis(hashval, i); 75259243Sobrien if (hashdebug & 1) 75359243Sobrien xprintf(CGETS(13, 1, "hash=%-4d dir=%-2d prog=%s\n"), 75459243Sobrien hashname(str2short(dp->d_name)), i, dp->d_name); 75559243Sobrien# else /* OLD HASH */ 75659243Sobrien hashval = hash(hashname(str2short(dp->d_name)), i); 75759243Sobrien bis(xhash, hashval); 75859243Sobrien# endif /* FASTHASH */ 75959243Sobrien /* tw_add_comm_name (dp->d_name); */ 76069408Sache#endif /* WINNT_NATIVE */ 76159243Sobrien } 762167465Smp cleanup_until(dirp); 76359243Sobrien } 76459243Sobrien} 76559243Sobrien 76659243Sobrien/*ARGSUSED*/ 76759243Sobrienvoid 768167465Smpdounhash(Char **v, struct command *c) 76959243Sobrien{ 77059243Sobrien USE(c); 77159243Sobrien USE(v); 77259243Sobrien havhash = 0; 77359243Sobrien#ifdef FASTHASH 774167465Smp xfree(xhash); 775167465Smp xhash = NULL; 77659243Sobrien#endif /* FASTHASH */ 77759243Sobrien} 77859243Sobrien 77959243Sobrien/*ARGSUSED*/ 78059243Sobrienvoid 781167465Smphashstat(Char **v, struct command *c) 78259243Sobrien{ 78359243Sobrien USE(c); 78459243Sobrien USE(v); 78559243Sobrien#ifdef FASTHASH 78659243Sobrien if (havhash && hashlength && hashwidth) 78759243Sobrien xprintf(CGETS(13, 2, "%d hash buckets of %d bits each\n"), 78859243Sobrien hashlength, hashwidth*8); 78959243Sobrien if (hashdebug) 79059243Sobrien xprintf(CGETS(13, 3, "debug mask = 0x%08x\n"), hashdebug); 79159243Sobrien#endif /* FASTHASH */ 79259243Sobrien#ifdef VFORK 79359243Sobrien if (hits + misses) 79459243Sobrien xprintf(CGETS(13, 4, "%d hits, %d misses, %d%%\n"), 79559243Sobrien hits, misses, 100 * hits / (hits + misses)); 79659243Sobrien#endif 79759243Sobrien} 79859243Sobrien 79959243Sobrien 80059243Sobrien/* 80159243Sobrien * Hash a command name. 80259243Sobrien */ 80369408Sacheint 804167465Smphashname(Char *cp) 80559243Sobrien{ 806145479Smp unsigned long h; 80759243Sobrien 80859243Sobrien for (h = 0; *cp; cp++) 80959243Sobrien h = hash(h, *cp); 81059243Sobrien return ((int) h); 81159243Sobrien} 81259243Sobrien 81359243Sobrienstatic int 814167465Smpiscommand(Char *name) 81559243Sobrien{ 816231990Smp Char **opv, **pv; 817145479Smp Char *sav; 818145479Smp struct varent *v; 819145479Smp int slash = any(short2str(name), '/'); 820231990Smp int hashval, rehashed, i; 82159243Sobrien 82259243Sobrien v = adrof(STRpath); 823100616Smp if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash) 824231990Smp opv = justabs; 82559243Sobrien else 826231990Smp opv = v->vec; 82759243Sobrien sav = Strspl(STRslash, name); /* / command name for postpending */ 82859243Sobrien hashval = havhash ? hashname(name) : 0; 829231990Smp 830231990Smp rehashed = 0; 831231990Smpretry: 832231990Smp pv = opv; 83359243Sobrien i = 0; 83459243Sobrien do { 83559243Sobrien if (!slash && ABSOLUTEP(pv[0]) && havhash) { 83659243Sobrien#ifdef FASTHASH 83759243Sobrien if (!bit(hashval, i)) 83859243Sobrien goto cont; 83959243Sobrien#else /* OLDHASH */ 84059243Sobrien int hashval1 = hash(hashval, i); 84159243Sobrien if (!bit(xhash, hashval1)) 84259243Sobrien goto cont; 84359243Sobrien#endif /* FASTHASH */ 84459243Sobrien } 84559243Sobrien if (pv[0][0] == 0 || eq(pv[0], STRdot)) { /* don't make ./xxx */ 84659243Sobrien if (executable(NULL, name, 0)) { 847167465Smp xfree(sav); 84859243Sobrien return i + 1; 84959243Sobrien } 85059243Sobrien } 85159243Sobrien else { 85259243Sobrien if (executable(*pv, sav, 0)) { 853167465Smp xfree(sav); 85459243Sobrien return i + 1; 85559243Sobrien } 85659243Sobrien } 85759243Sobriencont: 85859243Sobrien pv++; 85959243Sobrien i++; 86059243Sobrien } while (*pv); 861231990Smp if (adrof(STRautorehash) && !rehashed && havhash && opv != justabs) { 862231990Smp dohash(NULL, NULL); 863231990Smp rehashed = 1; 864231990Smp goto retry; 865231990Smp } 866167465Smp xfree(sav); 86759243Sobrien return 0; 86859243Sobrien} 86959243Sobrien 87059243Sobrien/* Also by: 87159243Sobrien * Andreas Luik <luik@isaak.isa.de> 87259243Sobrien * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 87359243Sobrien * Azenberstr. 35 87459243Sobrien * D-7000 Stuttgart 1 87559243Sobrien * West-Germany 87659243Sobrien * is the executable() routine below and changes to iscommand(). 87759243Sobrien * Thanks again!! 87859243Sobrien */ 87959243Sobrien 88069408Sache#ifndef WINNT_NATIVE 88159243Sobrien/* 88259243Sobrien * executable() examines the pathname obtained by concatenating dir and name 88359243Sobrien * (dir may be NULL), and returns 1 either if it is executable by us, or 88459243Sobrien * if dir_ok is set and the pathname refers to a directory. 88559243Sobrien * This is a bit kludgy, but in the name of optimization... 88659243Sobrien */ 88759243Sobrienint 888167465Smpexecutable(const Char *dir, const Char *name, int dir_ok) 88959243Sobrien{ 89059243Sobrien struct stat stbuf; 89159243Sobrien char *strname; 89259243Sobrien 89359243Sobrien if (dir && *dir) { 894167465Smp Char *path; 895167465Smp 896167465Smp path = Strspl(dir, name); 89759243Sobrien strname = short2str(path); 898167465Smp xfree(path); 89959243Sobrien } 90059243Sobrien else 90159243Sobrien strname = short2str(name); 902167465Smp 90359243Sobrien return (stat(strname, &stbuf) != -1 && 90459243Sobrien ((dir_ok && S_ISDIR(stbuf.st_mode)) || 90559243Sobrien (S_ISREG(stbuf.st_mode) && 90659243Sobrien /* save time by not calling access() in the hopeless case */ 90759243Sobrien (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) && 90859243Sobrien access(strname, X_OK) == 0 90959243Sobrien ))); 91059243Sobrien} 91169408Sache#endif /*!WINNT_NATIVE*/ 91259243Sobrien 913167465Smpstruct tellmewhat_s0_cleanup 914167465Smp{ 915167465Smp Char **dest, *val; 916167465Smp}; 917167465Smp 918167465Smpstatic void 919167465Smptellmewhat_s0_cleanup(void *xstate) 920167465Smp{ 921167465Smp struct tellmewhat_s0_cleanup *state; 922167465Smp 923167465Smp state = xstate; 924167465Smp *state->dest = state->val; 925167465Smp} 926167465Smp 92759243Sobrienint 928167465Smptellmewhat(struct wordent *lexp, Char **str) 92959243Sobrien{ 930167465Smp struct tellmewhat_s0_cleanup s0; 931145479Smp int i; 932167465Smp const struct biltins *bptr; 933145479Smp struct wordent *sp = lexp->next; 934145479Smp int aliased = 0, found; 935167465Smp Char *s1, *s2, *cmd; 93659243Sobrien Char qc; 93759243Sobrien 93859243Sobrien if (adrof1(sp->word, &aliases)) { 93959243Sobrien alias(lexp); 94059243Sobrien sp = lexp->next; 94159243Sobrien aliased = 1; 94259243Sobrien } 94359243Sobrien 944167465Smp s0.dest = &sp->word; /* to get the memory freeing right... */ 945167465Smp s0.val = sp->word; 946167465Smp cleanup_push(&s0, tellmewhat_s0_cleanup); 94759243Sobrien 94859243Sobrien /* handle quoted alias hack */ 94959243Sobrien if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE) 95059243Sobrien (sp->word)++; 95159243Sobrien 95259243Sobrien /* do quoting, if it hasn't been done */ 95359243Sobrien s1 = s2 = sp->word; 95459243Sobrien while (*s2) 95559243Sobrien switch (*s2) { 95659243Sobrien case '\'': 95759243Sobrien case '"': 95859243Sobrien qc = *s2++; 95959243Sobrien while (*s2 && *s2 != qc) 96059243Sobrien *s1++ = *s2++ | QUOTE; 96159243Sobrien if (*s2) 96259243Sobrien s2++; 96359243Sobrien break; 96459243Sobrien case '\\': 96559243Sobrien if (*++s2) 96659243Sobrien *s1++ = *s2++ | QUOTE; 96759243Sobrien break; 96859243Sobrien default: 96959243Sobrien *s1++ = *s2++; 97059243Sobrien } 97159243Sobrien *s1 = '\0'; 97259243Sobrien 97359243Sobrien for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) { 97459243Sobrien if (eq(sp->word, str2short(bptr->bname))) { 97559243Sobrien if (str == NULL) { 97659243Sobrien if (aliased) 97759243Sobrien prlex(lexp); 97859243Sobrien xprintf(CGETS(13, 5, "%S: shell built-in command.\n"), 97959243Sobrien sp->word); 98059243Sobrien flush(); 98159243Sobrien } 982167465Smp else 983167465Smp *str = Strsave(sp->word); 984167465Smp cleanup_until(&s0); 98559243Sobrien return TRUE; 98659243Sobrien } 98759243Sobrien } 98869408Sache#ifdef WINNT_NATIVE 98959243Sobrien for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) { 99059243Sobrien if (eq(sp->word, str2short(bptr->bname))) { 99159243Sobrien if (str == NULL) { 99259243Sobrien if (aliased) 99359243Sobrien prlex(lexp); 99459243Sobrien xprintf(CGETS(13, 5, "%S: shell built-in command.\n"), 99559243Sobrien sp->word); 99659243Sobrien flush(); 99759243Sobrien } 998167465Smp else 999167465Smp *str = Strsave(sp->word); 1000167465Smp cleanup_until(&s0); 100159243Sobrien return TRUE; 100259243Sobrien } 100359243Sobrien } 100469408Sache#endif /* WINNT_NATIVE*/ 100559243Sobrien 100659243Sobrien sp->word = cmd = globone(sp->word, G_IGNORE); 1007167465Smp cleanup_push(cmd, xfree); 100859243Sobrien 100959243Sobrien if ((i = iscommand(sp->word)) != 0) { 1010145479Smp Char **pv; 1011145479Smp struct varent *v; 1012145479Smp int slash = any(short2str(sp->word), '/'); 101359243Sobrien 101459243Sobrien v = adrof(STRpath); 1015100616Smp if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash) 101659243Sobrien pv = justabs; 101759243Sobrien else 101859243Sobrien pv = v->vec; 101959243Sobrien 1020167465Smp pv += i - 1; 102159243Sobrien if (pv[0][0] == 0 || eq(pv[0], STRdot)) { 102259243Sobrien if (!slash) { 102359243Sobrien sp->word = Strspl(STRdotsl, sp->word); 1024167465Smp cleanup_push(sp->word, xfree); 102559243Sobrien prlex(lexp); 1026167465Smp cleanup_until(sp->word); 102759243Sobrien } 102859243Sobrien else 102959243Sobrien prlex(lexp); 103059243Sobrien } 103159243Sobrien else { 103259243Sobrien s1 = Strspl(*pv, STRslash); 103359243Sobrien sp->word = Strspl(s1, sp->word); 1034167465Smp xfree(s1); 1035167465Smp cleanup_push(sp->word, xfree); 103659243Sobrien if (str == NULL) 103759243Sobrien prlex(lexp); 103859243Sobrien else 1039167465Smp *str = Strsave(sp->word); 1040167465Smp cleanup_until(sp->word); 104159243Sobrien } 104259243Sobrien found = 1; 104359243Sobrien } 104459243Sobrien else { 104559243Sobrien if (str == NULL) { 104659243Sobrien if (aliased) 104759243Sobrien prlex(lexp); 104859243Sobrien xprintf(CGETS(13, 6, "%S: Command not found.\n"), sp->word); 104959243Sobrien flush(); 105059243Sobrien } 105159243Sobrien else 1052167465Smp *str = Strsave(sp->word); 105359243Sobrien found = 0; 105459243Sobrien } 1055167465Smp cleanup_until(&s0); 105659243Sobrien return found; 105759243Sobrien} 105859243Sobrien 105959243Sobrien/* 106059243Sobrien * Builtin to look at and list all places a command may be defined: 106159243Sobrien * aliases, shell builtins, and the path. 106259243Sobrien * 106359243Sobrien * Marc Horowitz <marc@mit.edu> 106459243Sobrien * MIT Student Information Processing Board 106559243Sobrien */ 106659243Sobrien 106759243Sobrien/*ARGSUSED*/ 106859243Sobrienvoid 1069167465Smpdowhere(Char **v, struct command *c) 107059243Sobrien{ 107159243Sobrien int found = 1; 107259243Sobrien USE(c); 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 } 1169231990Smp if (adrof(STRautorehash) && !rehashed && havhash) { 1170231990Smp dohash(NULL, NULL); 1171231990Smp rehashed = 1; 1172231990Smp goto retry; 1173231990Smp } 1174167465Smp cleanup_until(sv); 117559243Sobrien return rval; 117659243Sobrien} 117769408Sache#ifdef WINNT_NATIVE 117859243Sobrienint hashval_extern(cp) 117959243Sobrien Char *cp; 118059243Sobrien{ 118159243Sobrien return havhash?hashname(cp):0; 118259243Sobrien} 118359243Sobrienint bit_extern(val,i) 118459243Sobrien int val; 118559243Sobrien int i; 118659243Sobrien{ 118759243Sobrien return bit(val,i); 118859243Sobrien} 118969408Sachevoid bis_extern(val,i) 119069408Sache int val; 119169408Sache int i; 119269408Sache{ 119369408Sache bis(val,i); 119469408Sache} 119569408Sache#endif /* WINNT_NATIVE */ 119669408Sache 1197