sh.exec.c revision 167465
1167465Smp/* $Header: /p/tcsh/cvsroot/tcsh/sh.exec.c,v 3.73 2006/08/24 20:56:31 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 35167465SmpRCSID("$tcsh: sh.exec.c,v 3.73 2006/08/24 20:56:31 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 8059243Sobrien * (possibly) presend 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 144167465Smpstatic void pexerr (void); 145167465Smpstatic void texec (Char *, Char **); 146167465Smpint hashname (Char *); 147167465Smpstatic int iscommand (Char *); 14859243Sobrien 14959243Sobrienvoid 150167465Smpdoexec(struct command *t, int do_glob) 15159243Sobrien{ 152100616Smp Char *dp, **pv, **av, *sav; 153100616Smp struct varent *v; 154167465Smp int slash, gflag; 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) 25659243Sobrien pv = justabs; 25759243Sobrien else 25859243Sobrien pv = 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 26759243Sobrien i = 0; 26859243Sobrien#ifdef VFORK 26959243Sobrien hits++; 27059243Sobrien#endif /* VFORK */ 27159243Sobrien do { 27259243Sobrien /* 27359243Sobrien * Try to save time by looking at the hash table for where this command 27459243Sobrien * could be. If we are doing delayed hashing, then we put the names in 27559243Sobrien * one at a time, as the user enters them. This is kinda like Korn 27659243Sobrien * Shell's "tracked aliases". 27759243Sobrien */ 27859243Sobrien if (!slash && ABSOLUTEP(pv[0]) && havhash) { 27959243Sobrien#ifdef FASTHASH 28059243Sobrien if (!bit(hashval, i)) 28159243Sobrien goto cont; 28259243Sobrien#else /* OLDHASH */ 28359243Sobrien int hashval1 = hash(hashval, i); 28459243Sobrien if (!bit(xhash, hashval1)) 28559243Sobrien goto cont; 28659243Sobrien#endif /* FASTHASH */ 28759243Sobrien } 28859243Sobrien if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */ 28959243Sobrien texec(*av, av); 29059243Sobrien else { 29159243Sobrien dp = Strspl(*pv, sav); 292167465Smp#ifndef VFORK 293167465Smp cleanup_push(dp, xfree); 294167465Smp#else /* VFORK */ 29559243Sobrien Vdp = dp; 29659243Sobrien#endif /* VFORK */ 29759243Sobrien 29859243Sobrien texec(dp, av); 299167465Smp#ifndef VFORK 300167465Smp cleanup_until(dp); 301167465Smp#else /* VFORK */ 30259243Sobrien Vdp = 0; 303167465Smp xfree(dp); 30459243Sobrien#endif /* VFORK */ 30559243Sobrien } 30659243Sobrien#ifdef VFORK 30759243Sobrien misses++; 30859243Sobrien#endif /* VFORK */ 30959243Sobriencont: 31059243Sobrien pv++; 31159243Sobrien i++; 31259243Sobrien } while (*pv); 31359243Sobrien#ifdef VFORK 31459243Sobrien hits--; 315167465Smp#endif /* VFORK */ 316167465Smp#ifndef VFORK 317167465Smp cleanup_until(sav); 318167465Smp#else /* VFORK */ 31959243Sobrien Vsav = 0; 320167465Smp xfree(sav); 32159243Sobrien#endif /* VFORK */ 32259243Sobrien pexerr(); 32359243Sobrien} 32459243Sobrien 32559243Sobrienstatic void 326167465Smppexerr(void) 32759243Sobrien{ 32859243Sobrien /* Couldn't find the damn thing */ 32959243Sobrien if (expath) { 33059243Sobrien setname(short2str(expath)); 33159243Sobrien#ifdef VFORK 33259243Sobrien Vexpath = 0; 33359243Sobrien#endif /* VFORK */ 334167465Smp xfree(expath); 33559243Sobrien expath = 0; 33659243Sobrien } 33759243Sobrien else 33859243Sobrien setname(""); 33959243Sobrien if (exerr) 34059243Sobrien stderror(ERR_NAME | ERR_STRING, exerr); 34159243Sobrien stderror(ERR_NAME | ERR_COMMAND); 34259243Sobrien} 34359243Sobrien 34459243Sobrien/* 34559243Sobrien * Execute command f, arg list t. 34659243Sobrien * Record error message if not found. 34759243Sobrien * Also do shell scripts here. 34859243Sobrien */ 34959243Sobrienstatic void 350167465Smptexec(Char *sf, Char **st) 35159243Sobrien{ 352145479Smp char **t; 353145479Smp char *f; 354145479Smp struct varent *v; 35559243Sobrien Char **vp; 35659243Sobrien Char *lastsh[2]; 35759243Sobrien char pref[2]; 35859243Sobrien int fd; 35959243Sobrien Char *st0, **ost; 36059243Sobrien 36159243Sobrien /* The order for the conversions is significant */ 36259243Sobrien t = short2blk(st); 36359243Sobrien f = short2str(sf); 36459243Sobrien#ifdef VFORK 36559243Sobrien Vt = t; 36659243Sobrien#endif /* VFORK */ 36759243Sobrien errno = 0; /* don't use a previous error */ 36859243Sobrien#ifdef apollo 36959243Sobrien /* 37059243Sobrien * If we try to execute an nfs mounted directory on the apollo, we 37159243Sobrien * hang forever. So until apollo fixes that.. 37259243Sobrien */ 37359243Sobrien { 37459243Sobrien struct stat stb; 37559243Sobrien if (stat(f, &stb) == 0 && S_ISDIR(stb.st_mode)) 37659243Sobrien errno = EISDIR; 37759243Sobrien } 37859243Sobrien if (errno == 0) 37959243Sobrien#endif /* apollo */ 38059243Sobrien { 38159243Sobrien#ifdef ISC_POSIX_EXEC_BUG 38259243Sobrien __setostype(0); /* "0" is "__OS_SYSV" in <sys/user.h> */ 38359243Sobrien#endif /* ISC_POSIX_EXEC_BUG */ 38459243Sobrien (void) execv(f, t); 38559243Sobrien#ifdef ISC_POSIX_EXEC_BUG 38659243Sobrien __setostype(1); /* "1" is "__OS_POSIX" in <sys/user.h> */ 38759243Sobrien#endif /* ISC_POSIX_EXEC_BUG */ 38859243Sobrien } 38959243Sobrien#ifdef VFORK 39059243Sobrien Vt = 0; 39159243Sobrien#endif /* VFORK */ 39259243Sobrien blkfree((Char **) t); 39359243Sobrien switch (errno) { 39459243Sobrien 39559243Sobrien case ENOEXEC: 39669408Sache#ifdef WINNT_NATIVE 39759243Sobrien nt_feed_to_cmd(f,t); 39869408Sache#endif /* WINNT_NATIVE */ 39959243Sobrien /* 40059243Sobrien * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute 40159243Sobrien * it, don't feed it to the shell if it looks like a binary! 40259243Sobrien */ 403167465Smp if ((fd = xopen(f, O_RDONLY|O_LARGEFILE)) != -1) { 40459243Sobrien int nread; 405131962Smp#ifdef O_TEXT 406131962Smp setmode(fd, O_TEXT); 407131962Smp#endif 408167465Smp if ((nread = xread(fd, pref, 2)) == 2) { 409145479Smp if (!isprint((unsigned char)pref[0]) && 410145479Smp (pref[0] != '\n' && pref[0] != '\t')) { 411167465Smp int err; 412167465Smp 413167465Smp err = errno; 414167465Smp xclose(fd); 41559243Sobrien /* 41659243Sobrien * We *know* what ENOEXEC means. 41759243Sobrien */ 418167465Smp stderror(ERR_ARCH, f, strerror(err)); 41959243Sobrien } 42059243Sobrien } 421167465Smp else if (nread < 0) { 42259243Sobrien#ifdef convex 423167465Smp int err; 424167465Smp 425167465Smp err = errno; 426167465Smp xclose(fd); 42759243Sobrien /* need to print error incase the file is migrated */ 428167465Smp stderror(ERR_SYSTEM, f, strerror(err)); 42959243Sobrien#endif 43059243Sobrien } 43159243Sobrien#ifdef _PATH_BSHELL 43259243Sobrien else { 43359243Sobrien pref[0] = '#'; 43459243Sobrien pref[1] = '\0'; 43559243Sobrien } 43659243Sobrien#endif 43759243Sobrien } 43859243Sobrien#ifdef HASHBANG 43959243Sobrien if (fd == -1 || 44059243Sobrien pref[0] != '#' || pref[1] != '!' || hashbang(fd, &vp) == -1) { 44159243Sobrien#endif /* HASHBANG */ 44259243Sobrien /* 44359243Sobrien * If there is an alias for shell, then put the words of the alias in 44459243Sobrien * front of the argument list replacing the command name. Note no 44559243Sobrien * interpretation of the words at this point. 44659243Sobrien */ 44759243Sobrien v = adrof1(STRshell, &aliases); 448100616Smp if (v == NULL || v->vec == NULL) { 44959243Sobrien vp = lastsh; 45059243Sobrien vp[0] = adrof(STRshell) ? varval(STRshell) : STR_SHELLPATH; 45159243Sobrien vp[1] = NULL; 45259243Sobrien#ifdef _PATH_BSHELL 45359243Sobrien if (fd != -1 45459243Sobrien# ifndef ISC /* Compatible with ISC's /bin/csh */ 45559243Sobrien && pref[0] != '#' 45659243Sobrien# endif /* ISC */ 45759243Sobrien ) 45859243Sobrien vp[0] = STR_BSHELL; 45959243Sobrien#endif 46059243Sobrien vp = saveblk(vp); 46159243Sobrien } 46259243Sobrien else 46359243Sobrien vp = saveblk(v->vec); 46459243Sobrien#ifdef HASHBANG 46559243Sobrien } 46659243Sobrien#endif /* HASHBANG */ 46759243Sobrien if (fd != -1) 468167465Smp xclose(fd); 46959243Sobrien 47059243Sobrien st0 = st[0]; 47159243Sobrien st[0] = sf; 47259243Sobrien ost = st; 47359243Sobrien st = blkspl(vp, st); /* Splice up the new arglst */ 47459243Sobrien ost[0] = st0; 47559243Sobrien sf = *st; 47659243Sobrien /* The order for the conversions is significant */ 47759243Sobrien t = short2blk(st); 47859243Sobrien f = short2str(sf); 479167465Smp xfree(st); 48059243Sobrien blkfree((Char **) vp); 48159243Sobrien#ifdef VFORK 48259243Sobrien Vt = t; 48359243Sobrien#endif /* VFORK */ 48459243Sobrien#ifdef ISC_POSIX_EXEC_BUG 48559243Sobrien __setostype(0); /* "0" is "__OS_SYSV" in <sys/user.h> */ 48659243Sobrien#endif /* ISC_POSIX_EXEC_BUG */ 48759243Sobrien (void) execv(f, t); 48859243Sobrien#ifdef ISC_POSIX_EXEC_BUG 48959243Sobrien __setostype(1); /* "1" is "__OS_POSIX" in <sys/user.h> */ 49059243Sobrien#endif /* ISC_POSIX_EXEC_BUG */ 49159243Sobrien#ifdef VFORK 49259243Sobrien Vt = 0; 49359243Sobrien#endif /* VFORK */ 49459243Sobrien blkfree((Char **) t); 49559243Sobrien /* The sky is falling, the sky is falling! */ 49659243Sobrien stderror(ERR_SYSTEM, f, strerror(errno)); 49759243Sobrien break; 49859243Sobrien 49959243Sobrien case ENOMEM: 50059243Sobrien stderror(ERR_SYSTEM, f, strerror(errno)); 50159243Sobrien break; 50259243Sobrien 50359243Sobrien#ifdef _IBMR2 50459243Sobrien case 0: /* execv fails and returns 0! */ 50559243Sobrien#endif /* _IBMR2 */ 50659243Sobrien case ENOENT: 50759243Sobrien break; 50859243Sobrien 50959243Sobrien default: 51059243Sobrien if (exerr == 0) { 51159243Sobrien exerr = strerror(errno); 512167465Smp xfree(expath); 51359243Sobrien expath = Strsave(sf); 51459243Sobrien#ifdef VFORK 51559243Sobrien Vexpath = expath; 51659243Sobrien#endif /* VFORK */ 51759243Sobrien } 51859243Sobrien break; 51959243Sobrien } 52059243Sobrien} 52159243Sobrien 522167465Smpstruct execash_state 52359243Sobrien{ 524167465Smp int saveIN, saveOUT, saveDIAG, saveSTD; 525167465Smp int SHIN, SHOUT, SHDIAG, OLDSTD; 526167465Smp int didfds; 52759243Sobrien#ifndef CLOSE_ON_EXEC 528167465Smp int didcch; 529167465Smp#endif 530167465Smp struct sigaction sigint, sigquit, sigterm; 531167465Smp}; 532167465Smp 533167465Smpstatic void 534167465Smpexecash_cleanup(void *xstate) 535167465Smp{ 536167465Smp struct execash_state *state; 537167465Smp 538167465Smp state = xstate; 539167465Smp sigaction(SIGINT, &state->sigint, NULL); 540167465Smp sigaction(SIGQUIT, &state->sigquit, NULL); 541167465Smp sigaction(SIGTERM, &state->sigterm, NULL); 542167465Smp 543167465Smp doneinp = 0; 544167465Smp#ifndef CLOSE_ON_EXEC 545167465Smp didcch = state->didcch; 54659243Sobrien#endif /* CLOSE_ON_EXEC */ 547167465Smp didfds = state->didfds; 548167465Smp xclose(SHIN); 549167465Smp xclose(SHOUT); 550167465Smp xclose(SHDIAG); 551167465Smp xclose(OLDSTD); 552167465Smp close_on_exec(SHIN = dmove(state->saveIN, state->SHIN), 1); 553167465Smp close_on_exec(SHOUT = dmove(state->saveOUT, state->SHOUT), 1); 554167465Smp close_on_exec(SHDIAG = dmove(state->saveDIAG, state->SHDIAG), 1); 555167465Smp close_on_exec(OLDSTD = dmove(state->saveSTD, state->OLDSTD), 1); 556167465Smp} 55759243Sobrien 558167465Smp/*ARGSUSED*/ 559167465Smpvoid 560167465Smpexecash(Char **t, struct command *kp) 561167465Smp{ 562167465Smp struct execash_state state; 563167465Smp 56459243Sobrien USE(t); 56559243Sobrien if (chkstop == 0 && setintr) 56659243Sobrien panystop(0); 56759243Sobrien /* 56859243Sobrien * Hmm, we don't really want to do that now because we might 56959243Sobrien * fail, but what is the choice 57059243Sobrien */ 57159243Sobrien rechist(NULL, adrof(STRsavehist) != NULL); 57259243Sobrien 57359243Sobrien 574167465Smp sigaction(SIGINT, &parintr, &state.sigint); 575167465Smp sigaction(SIGQUIT, &parintr, &state.sigquit); 576167465Smp sigaction(SIGTERM, &parterm, &state.sigterm); 57759243Sobrien 578167465Smp state.didfds = didfds; 57959243Sobrien#ifndef CLOSE_ON_EXEC 580167465Smp state.didcch = didcch; 58159243Sobrien#endif /* CLOSE_ON_EXEC */ 582167465Smp state.SHIN = SHIN; 583167465Smp state.SHOUT = SHOUT; 584167465Smp state.SHDIAG = SHDIAG; 585167465Smp state.OLDSTD = OLDSTD; 58659243Sobrien 587167465Smp (void)close_on_exec (state.saveIN = dcopy(SHIN, -1), 1); 588167465Smp (void)close_on_exec (state.saveOUT = dcopy(SHOUT, -1), 1); 589167465Smp (void)close_on_exec (state.saveDIAG = dcopy(SHDIAG, -1), 1); 590167465Smp (void)close_on_exec (state.saveSTD = dcopy(OLDSTD, -1), 1); 591167465Smp 59259243Sobrien lshift(kp->t_dcom, 1); 59359243Sobrien 594167465Smp (void)close_on_exec (SHIN = dcopy(0, -1), 1); 595167465Smp (void)close_on_exec (SHOUT = dcopy(1, -1), 1); 596167465Smp (void)close_on_exec (SHDIAG = dcopy(2, -1), 1); 59759243Sobrien#ifndef CLOSE_ON_EXEC 598167465Smp didcch = 0; 59959243Sobrien#endif /* CLOSE_ON_EXEC */ 600167465Smp didfds = 0; 601167465Smp cleanup_push(&state, execash_cleanup); 602167465Smp 603167465Smp /* 604167465Smp * Decrement the shell level 605167465Smp */ 606167465Smp shlvl(-1); 60769408Sache#ifdef WINNT_NATIVE 608167465Smp __nt_really_exec=1; 60969408Sache#endif /* WINNT_NATIVE */ 610167465Smp doexec(kp, 1); 61159243Sobrien 612167465Smp cleanup_until(&state); 61359243Sobrien} 61459243Sobrien 61559243Sobrienvoid 616167465Smpxechoit(Char **t) 61759243Sobrien{ 61859243Sobrien if (adrof(STRecho)) { 619100616Smp int odidfds = didfds; 62059243Sobrien flush(); 62159243Sobrien haderr = 1; 622100616Smp didfds = 0; 62359243Sobrien blkpr(t), xputchar('\n'); 624100616Smp flush(); 625100616Smp didfds = odidfds; 62659243Sobrien haderr = 0; 62759243Sobrien } 62859243Sobrien} 62959243Sobrien 63059243Sobrien/*ARGSUSED*/ 63159243Sobrienvoid 632167465Smpdohash(Char **vv, struct command *c) 63359243Sobrien{ 63459243Sobrien#ifdef COMMENT 63559243Sobrien struct stat stb; 63659243Sobrien#endif 63759243Sobrien DIR *dirp; 638145479Smp struct dirent *dp; 63959243Sobrien int i = 0; 64059243Sobrien struct varent *v = adrof(STRpath); 64159243Sobrien Char **pv; 64259243Sobrien int hashval; 64369408Sache#ifdef WINNT_NATIVE 64459243Sobrien int is_windir; /* check if it is the windows directory */ 64559243Sobrien USE(hashval); 64669408Sache#endif /* WINNT_NATIVE */ 64759243Sobrien 64859243Sobrien USE(c); 64959243Sobrien#ifdef FASTHASH 65059243Sobrien if (vv && vv[1]) { 65159243Sobrien uhashlength = atoi(short2str(vv[1])); 65259243Sobrien if (vv[2]) { 65359243Sobrien uhashwidth = atoi(short2str(vv[2])); 65459243Sobrien if ((uhashwidth != sizeof(unsigned char)) && 65559243Sobrien (uhashwidth != sizeof(unsigned short)) && 65659243Sobrien (uhashwidth != sizeof(unsigned long))) 65759243Sobrien uhashwidth = 0; 65859243Sobrien if (vv[3]) 65959243Sobrien hashdebug = atoi(short2str(vv[3])); 66059243Sobrien } 66159243Sobrien } 66259243Sobrien 66359243Sobrien if (uhashwidth) 66459243Sobrien hashwidth = uhashwidth; 66559243Sobrien else { 66659243Sobrien hashwidth = 0; 66769408Sache if (v == NULL) 66869408Sache return; 669100616Smp for (pv = v->vec; pv && *pv; pv++, hashwidth++) 67059243Sobrien continue; 67159243Sobrien if (hashwidth <= widthof(unsigned char)) 67259243Sobrien hashwidth = sizeof(unsigned char); 67359243Sobrien else if (hashwidth <= widthof(unsigned short)) 67459243Sobrien hashwidth = sizeof(unsigned short); 67559243Sobrien else if (hashwidth <= widthof(unsigned int)) 67659243Sobrien hashwidth = sizeof(unsigned int); 67759243Sobrien else 67859243Sobrien hashwidth = sizeof(unsigned long); 67959243Sobrien } 68059243Sobrien 68159243Sobrien if (uhashlength) 68259243Sobrien hashlength = uhashlength; 68359243Sobrien else 68459243Sobrien hashlength = hashwidth * (8*64);/* "average" files per dir in path */ 685167465Smp 686167465Smp xfree(xhash); 687167465Smp xhash = xcalloc(hashlength * hashwidth, 1); 68859243Sobrien#endif /* FASTHASH */ 68959243Sobrien 69059243Sobrien (void) getusername(NULL); /* flush the tilde cashe */ 69159243Sobrien tw_cmd_free(); 69259243Sobrien havhash = 1; 69359243Sobrien if (v == NULL) 69459243Sobrien return; 695100616Smp for (pv = v->vec; pv && *pv; pv++, i++) { 69659243Sobrien if (!ABSOLUTEP(pv[0])) 69759243Sobrien continue; 69859243Sobrien dirp = opendir(short2str(*pv)); 69959243Sobrien if (dirp == NULL) 70059243Sobrien continue; 701167465Smp cleanup_push(dirp, opendir_cleanup); 70259243Sobrien#ifdef COMMENT /* this isn't needed. opendir won't open 70359243Sobrien * non-dirs */ 70459243Sobrien if (fstat(dirp->dd_fd, &stb) < 0 || !S_ISDIR(stb.st_mode)) { 705167465Smp cleanup_until(dirp); 70659243Sobrien continue; 70759243Sobrien } 70859243Sobrien#endif 70969408Sache#ifdef WINNT_NATIVE 71059243Sobrien is_windir = nt_check_if_windir(short2str(*pv)); 71169408Sache#endif /* WINNT_NATIVE */ 71259243Sobrien while ((dp = readdir(dirp)) != NULL) { 71359243Sobrien if (dp->d_ino == 0) 71459243Sobrien continue; 71559243Sobrien if (dp->d_name[0] == '.' && 71659243Sobrien (dp->d_name[1] == '\0' || 71759243Sobrien (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) 71859243Sobrien continue; 71969408Sache#ifdef WINNT_NATIVE 72059243Sobrien nt_check_name_and_hash(is_windir, dp->d_name, i); 72169408Sache#else /* !WINNT_NATIVE*/ 72269408Sache#if defined(_UWIN) || defined(__CYGWIN__) 72359243Sobrien /* Turn foo.{exe,com,bat} into foo since UWIN's readdir returns 72459243Sobrien * the file with the .exe, .com, .bat extension 72559243Sobrien */ 72659243Sobrien { 727167465Smp ssize_t ext = strlen(dp->d_name) - 4; 728131962Smp if ((ext > 0) && (strcasecmp(&dp->d_name[ext], ".exe") == 0 || 729131962Smp strcasecmp(&dp->d_name[ext], ".bat") == 0 || 730167465Smp strcasecmp(&dp->d_name[ext], ".com") == 0)) { 731167465Smp#ifdef __CYGWIN__ 732167465Smp /* Also store the variation with extension. */ 733167465Smp hashval = hashname(str2short(dp->d_name)); 734167465Smp bis(hashval, i); 735131962Smp#endif /* __CYGWIN__ */ 736167465Smp dp->d_name[ext] = '\0'; 737167465Smp } 73859243Sobrien } 73969408Sache#endif /* _UWIN || __CYGWIN__ */ 74059243Sobrien# ifdef FASTHASH 74159243Sobrien hashval = hashname(str2short(dp->d_name)); 74259243Sobrien bis(hashval, i); 74359243Sobrien if (hashdebug & 1) 74459243Sobrien xprintf(CGETS(13, 1, "hash=%-4d dir=%-2d prog=%s\n"), 74559243Sobrien hashname(str2short(dp->d_name)), i, dp->d_name); 74659243Sobrien# else /* OLD HASH */ 74759243Sobrien hashval = hash(hashname(str2short(dp->d_name)), i); 74859243Sobrien bis(xhash, hashval); 74959243Sobrien# endif /* FASTHASH */ 75059243Sobrien /* tw_add_comm_name (dp->d_name); */ 75169408Sache#endif /* WINNT_NATIVE */ 75259243Sobrien } 753167465Smp cleanup_until(dirp); 75459243Sobrien } 75559243Sobrien} 75659243Sobrien 75759243Sobrien/*ARGSUSED*/ 75859243Sobrienvoid 759167465Smpdounhash(Char **v, struct command *c) 76059243Sobrien{ 76159243Sobrien USE(c); 76259243Sobrien USE(v); 76359243Sobrien havhash = 0; 76459243Sobrien#ifdef FASTHASH 765167465Smp xfree(xhash); 766167465Smp xhash = NULL; 76759243Sobrien#endif /* FASTHASH */ 76859243Sobrien} 76959243Sobrien 77059243Sobrien/*ARGSUSED*/ 77159243Sobrienvoid 772167465Smphashstat(Char **v, struct command *c) 77359243Sobrien{ 77459243Sobrien USE(c); 77559243Sobrien USE(v); 77659243Sobrien#ifdef FASTHASH 77759243Sobrien if (havhash && hashlength && hashwidth) 77859243Sobrien xprintf(CGETS(13, 2, "%d hash buckets of %d bits each\n"), 77959243Sobrien hashlength, hashwidth*8); 78059243Sobrien if (hashdebug) 78159243Sobrien xprintf(CGETS(13, 3, "debug mask = 0x%08x\n"), hashdebug); 78259243Sobrien#endif /* FASTHASH */ 78359243Sobrien#ifdef VFORK 78459243Sobrien if (hits + misses) 78559243Sobrien xprintf(CGETS(13, 4, "%d hits, %d misses, %d%%\n"), 78659243Sobrien hits, misses, 100 * hits / (hits + misses)); 78759243Sobrien#endif 78859243Sobrien} 78959243Sobrien 79059243Sobrien 79159243Sobrien/* 79259243Sobrien * Hash a command name. 79359243Sobrien */ 79469408Sacheint 795167465Smphashname(Char *cp) 79659243Sobrien{ 797145479Smp unsigned long h; 79859243Sobrien 79959243Sobrien for (h = 0; *cp; cp++) 80059243Sobrien h = hash(h, *cp); 80159243Sobrien return ((int) h); 80259243Sobrien} 80359243Sobrien 80459243Sobrienstatic int 805167465Smpiscommand(Char *name) 80659243Sobrien{ 807145479Smp Char **pv; 808145479Smp Char *sav; 809145479Smp struct varent *v; 810145479Smp int slash = any(short2str(name), '/'); 811145479Smp int hashval, i; 81259243Sobrien 81359243Sobrien v = adrof(STRpath); 814100616Smp if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash) 81559243Sobrien pv = justabs; 81659243Sobrien else 81759243Sobrien pv = v->vec; 81859243Sobrien sav = Strspl(STRslash, name); /* / command name for postpending */ 81959243Sobrien hashval = havhash ? hashname(name) : 0; 82059243Sobrien i = 0; 82159243Sobrien do { 82259243Sobrien if (!slash && ABSOLUTEP(pv[0]) && havhash) { 82359243Sobrien#ifdef FASTHASH 82459243Sobrien if (!bit(hashval, i)) 82559243Sobrien goto cont; 82659243Sobrien#else /* OLDHASH */ 82759243Sobrien int hashval1 = hash(hashval, i); 82859243Sobrien if (!bit(xhash, hashval1)) 82959243Sobrien goto cont; 83059243Sobrien#endif /* FASTHASH */ 83159243Sobrien } 83259243Sobrien if (pv[0][0] == 0 || eq(pv[0], STRdot)) { /* don't make ./xxx */ 83359243Sobrien if (executable(NULL, name, 0)) { 834167465Smp xfree(sav); 83559243Sobrien return i + 1; 83659243Sobrien } 83759243Sobrien } 83859243Sobrien else { 83959243Sobrien if (executable(*pv, sav, 0)) { 840167465Smp xfree(sav); 84159243Sobrien return i + 1; 84259243Sobrien } 84359243Sobrien } 84459243Sobriencont: 84559243Sobrien pv++; 84659243Sobrien i++; 84759243Sobrien } while (*pv); 848167465Smp xfree(sav); 84959243Sobrien return 0; 85059243Sobrien} 85159243Sobrien 85259243Sobrien/* Also by: 85359243Sobrien * Andreas Luik <luik@isaak.isa.de> 85459243Sobrien * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 85559243Sobrien * Azenberstr. 35 85659243Sobrien * D-7000 Stuttgart 1 85759243Sobrien * West-Germany 85859243Sobrien * is the executable() routine below and changes to iscommand(). 85959243Sobrien * Thanks again!! 86059243Sobrien */ 86159243Sobrien 86269408Sache#ifndef WINNT_NATIVE 86359243Sobrien/* 86459243Sobrien * executable() examines the pathname obtained by concatenating dir and name 86559243Sobrien * (dir may be NULL), and returns 1 either if it is executable by us, or 86659243Sobrien * if dir_ok is set and the pathname refers to a directory. 86759243Sobrien * This is a bit kludgy, but in the name of optimization... 86859243Sobrien */ 86959243Sobrienint 870167465Smpexecutable(const Char *dir, const Char *name, int dir_ok) 87159243Sobrien{ 87259243Sobrien struct stat stbuf; 87359243Sobrien char *strname; 87459243Sobrien 87559243Sobrien if (dir && *dir) { 876167465Smp Char *path; 877167465Smp 878167465Smp path = Strspl(dir, name); 87959243Sobrien strname = short2str(path); 880167465Smp xfree(path); 88159243Sobrien } 88259243Sobrien else 88359243Sobrien strname = short2str(name); 884167465Smp 88559243Sobrien return (stat(strname, &stbuf) != -1 && 88659243Sobrien ((dir_ok && S_ISDIR(stbuf.st_mode)) || 88759243Sobrien (S_ISREG(stbuf.st_mode) && 88859243Sobrien /* save time by not calling access() in the hopeless case */ 88959243Sobrien (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) && 89059243Sobrien access(strname, X_OK) == 0 89159243Sobrien ))); 89259243Sobrien} 89369408Sache#endif /*!WINNT_NATIVE*/ 89459243Sobrien 895167465Smpstruct tellmewhat_s0_cleanup 896167465Smp{ 897167465Smp Char **dest, *val; 898167465Smp}; 899167465Smp 900167465Smpstatic void 901167465Smptellmewhat_s0_cleanup(void *xstate) 902167465Smp{ 903167465Smp struct tellmewhat_s0_cleanup *state; 904167465Smp 905167465Smp state = xstate; 906167465Smp *state->dest = state->val; 907167465Smp} 908167465Smp 90959243Sobrienint 910167465Smptellmewhat(struct wordent *lexp, Char **str) 91159243Sobrien{ 912167465Smp struct tellmewhat_s0_cleanup s0; 913145479Smp int i; 914167465Smp const struct biltins *bptr; 915145479Smp struct wordent *sp = lexp->next; 916145479Smp int aliased = 0, found; 917167465Smp Char *s1, *s2, *cmd; 91859243Sobrien Char qc; 91959243Sobrien 92059243Sobrien if (adrof1(sp->word, &aliases)) { 92159243Sobrien alias(lexp); 92259243Sobrien sp = lexp->next; 92359243Sobrien aliased = 1; 92459243Sobrien } 92559243Sobrien 926167465Smp s0.dest = &sp->word; /* to get the memory freeing right... */ 927167465Smp s0.val = sp->word; 928167465Smp cleanup_push(&s0, tellmewhat_s0_cleanup); 92959243Sobrien 93059243Sobrien /* handle quoted alias hack */ 93159243Sobrien if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE) 93259243Sobrien (sp->word)++; 93359243Sobrien 93459243Sobrien /* do quoting, if it hasn't been done */ 93559243Sobrien s1 = s2 = sp->word; 93659243Sobrien while (*s2) 93759243Sobrien switch (*s2) { 93859243Sobrien case '\'': 93959243Sobrien case '"': 94059243Sobrien qc = *s2++; 94159243Sobrien while (*s2 && *s2 != qc) 94259243Sobrien *s1++ = *s2++ | QUOTE; 94359243Sobrien if (*s2) 94459243Sobrien s2++; 94559243Sobrien break; 94659243Sobrien case '\\': 94759243Sobrien if (*++s2) 94859243Sobrien *s1++ = *s2++ | QUOTE; 94959243Sobrien break; 95059243Sobrien default: 95159243Sobrien *s1++ = *s2++; 95259243Sobrien } 95359243Sobrien *s1 = '\0'; 95459243Sobrien 95559243Sobrien for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) { 95659243Sobrien if (eq(sp->word, str2short(bptr->bname))) { 95759243Sobrien if (str == NULL) { 95859243Sobrien if (aliased) 95959243Sobrien prlex(lexp); 96059243Sobrien xprintf(CGETS(13, 5, "%S: shell built-in command.\n"), 96159243Sobrien sp->word); 96259243Sobrien flush(); 96359243Sobrien } 964167465Smp else 965167465Smp *str = Strsave(sp->word); 966167465Smp cleanup_until(&s0); 96759243Sobrien return TRUE; 96859243Sobrien } 96959243Sobrien } 97069408Sache#ifdef WINNT_NATIVE 97159243Sobrien for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) { 97259243Sobrien if (eq(sp->word, str2short(bptr->bname))) { 97359243Sobrien if (str == NULL) { 97459243Sobrien if (aliased) 97559243Sobrien prlex(lexp); 97659243Sobrien xprintf(CGETS(13, 5, "%S: shell built-in command.\n"), 97759243Sobrien sp->word); 97859243Sobrien flush(); 97959243Sobrien } 980167465Smp else 981167465Smp *str = Strsave(sp->word); 982167465Smp cleanup_until(&s0); 98359243Sobrien return TRUE; 98459243Sobrien } 98559243Sobrien } 98669408Sache#endif /* WINNT_NATIVE*/ 98759243Sobrien 98859243Sobrien sp->word = cmd = globone(sp->word, G_IGNORE); 989167465Smp cleanup_push(cmd, xfree); 99059243Sobrien 99159243Sobrien if ((i = iscommand(sp->word)) != 0) { 992145479Smp Char **pv; 993145479Smp struct varent *v; 994145479Smp int slash = any(short2str(sp->word), '/'); 99559243Sobrien 99659243Sobrien v = adrof(STRpath); 997100616Smp if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash) 99859243Sobrien pv = justabs; 99959243Sobrien else 100059243Sobrien pv = v->vec; 100159243Sobrien 1002167465Smp pv += i - 1; 100359243Sobrien if (pv[0][0] == 0 || eq(pv[0], STRdot)) { 100459243Sobrien if (!slash) { 100559243Sobrien sp->word = Strspl(STRdotsl, sp->word); 1006167465Smp cleanup_push(sp->word, xfree); 100759243Sobrien prlex(lexp); 1008167465Smp cleanup_until(sp->word); 100959243Sobrien } 101059243Sobrien else 101159243Sobrien prlex(lexp); 101259243Sobrien } 101359243Sobrien else { 101459243Sobrien s1 = Strspl(*pv, STRslash); 101559243Sobrien sp->word = Strspl(s1, sp->word); 1016167465Smp xfree(s1); 1017167465Smp cleanup_push(sp->word, xfree); 101859243Sobrien if (str == NULL) 101959243Sobrien prlex(lexp); 102059243Sobrien else 1021167465Smp *str = Strsave(sp->word); 1022167465Smp cleanup_until(sp->word); 102359243Sobrien } 102459243Sobrien found = 1; 102559243Sobrien } 102659243Sobrien else { 102759243Sobrien if (str == NULL) { 102859243Sobrien if (aliased) 102959243Sobrien prlex(lexp); 103059243Sobrien xprintf(CGETS(13, 6, "%S: Command not found.\n"), sp->word); 103159243Sobrien flush(); 103259243Sobrien } 103359243Sobrien else 1034167465Smp *str = Strsave(sp->word); 103559243Sobrien found = 0; 103659243Sobrien } 1037167465Smp cleanup_until(&s0); 103859243Sobrien return found; 103959243Sobrien} 104059243Sobrien 104159243Sobrien/* 104259243Sobrien * Builtin to look at and list all places a command may be defined: 104359243Sobrien * aliases, shell builtins, and the path. 104459243Sobrien * 104559243Sobrien * Marc Horowitz <marc@mit.edu> 104659243Sobrien * MIT Student Information Processing Board 104759243Sobrien */ 104859243Sobrien 104959243Sobrien/*ARGSUSED*/ 105059243Sobrienvoid 1051167465Smpdowhere(Char **v, struct command *c) 105259243Sobrien{ 105359243Sobrien int found = 1; 105459243Sobrien USE(c); 105559243Sobrien for (v++; *v; v++) 105659243Sobrien found &= find_cmd(*v, 1); 105759243Sobrien /* Make status nonzero if any command is not found. */ 105859243Sobrien if (!found) 1059167465Smp setcopy(STRstatus, STR1, VAR_READWRITE); 106059243Sobrien} 106159243Sobrien 106259243Sobrienint 1063167465Smpfind_cmd(Char *cmd, int prt) 106459243Sobrien{ 106559243Sobrien struct varent *var; 1066167465Smp const struct biltins *bptr; 106759243Sobrien Char **pv; 106859243Sobrien Char *sv; 106959243Sobrien int hashval, i, ex, rval = 0; 107059243Sobrien 107159243Sobrien if (prt && any(short2str(cmd), '/')) { 107259243Sobrien xprintf(CGETS(13, 7, "where: / in command makes no sense\n")); 107359243Sobrien return rval; 107459243Sobrien } 107559243Sobrien 107659243Sobrien /* first, look for an alias */ 107759243Sobrien 107859243Sobrien if (prt && adrof1(cmd, &aliases)) { 107959243Sobrien if ((var = adrof1(cmd, &aliases)) != NULL) { 108059243Sobrien xprintf(CGETS(13, 8, "%S is aliased to "), cmd); 1081100616Smp if (var->vec != NULL) 1082100616Smp blkpr(var->vec); 108359243Sobrien xputchar('\n'); 108459243Sobrien rval = 1; 108559243Sobrien } 108659243Sobrien } 108759243Sobrien 108859243Sobrien /* next, look for a shell builtin */ 108959243Sobrien 109059243Sobrien for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) { 109159243Sobrien if (eq(cmd, str2short(bptr->bname))) { 109259243Sobrien rval = 1; 109359243Sobrien if (prt) 109459243Sobrien xprintf(CGETS(13, 9, "%S is a shell built-in\n"), cmd); 109559243Sobrien else 109659243Sobrien return rval; 109759243Sobrien } 109859243Sobrien } 109969408Sache#ifdef WINNT_NATIVE 110059243Sobrien for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) { 110159243Sobrien if (eq(cmd, str2short(bptr->bname))) { 110259243Sobrien rval = 1; 110359243Sobrien if (prt) 110459243Sobrien xprintf(CGETS(13, 9, "%S is a shell built-in\n"), cmd); 110559243Sobrien else 110659243Sobrien return rval; 110759243Sobrien } 110859243Sobrien } 110969408Sache#endif /* WINNT_NATIVE*/ 111059243Sobrien 111159243Sobrien /* last, look through the path for the command */ 111259243Sobrien 111359243Sobrien if ((var = adrof(STRpath)) == NULL) 111459243Sobrien return rval; 111559243Sobrien 111659243Sobrien hashval = havhash ? hashname(cmd) : 0; 111759243Sobrien 111859243Sobrien sv = Strspl(STRslash, cmd); 1119167465Smp cleanup_push(sv, xfree); 112059243Sobrien 1121100616Smp for (pv = var->vec, i = 0; pv && *pv; pv++, i++) { 112259243Sobrien if (havhash && !eq(*pv, STRdot)) { 112359243Sobrien#ifdef FASTHASH 112459243Sobrien if (!bit(hashval, i)) 112559243Sobrien continue; 112659243Sobrien#else /* OLDHASH */ 112759243Sobrien int hashval1 = hash(hashval, i); 112859243Sobrien if (!bit(xhash, hashval1)) 112959243Sobrien continue; 113059243Sobrien#endif /* FASTHASH */ 113159243Sobrien } 113259243Sobrien ex = executable(*pv, sv, 0); 113359243Sobrien#ifdef FASTHASH 113459243Sobrien if (!ex && (hashdebug & 2)) { 113559243Sobrien xprintf(CGETS(13, 10, "hash miss: ")); 113659243Sobrien ex = 1; /* Force printing */ 113759243Sobrien } 113859243Sobrien#endif /* FASTHASH */ 113959243Sobrien if (ex) { 114059243Sobrien rval = 1; 114159243Sobrien if (prt) { 114259243Sobrien xprintf("%S/", *pv); 114359243Sobrien xprintf("%S\n", cmd); 114459243Sobrien } 114559243Sobrien else 114659243Sobrien return rval; 114759243Sobrien } 114859243Sobrien } 1149167465Smp cleanup_until(sv); 115059243Sobrien return rval; 115159243Sobrien} 115269408Sache#ifdef WINNT_NATIVE 115359243Sobrienint hashval_extern(cp) 115459243Sobrien Char *cp; 115559243Sobrien{ 115659243Sobrien return havhash?hashname(cp):0; 115759243Sobrien} 115859243Sobrienint bit_extern(val,i) 115959243Sobrien int val; 116059243Sobrien int i; 116159243Sobrien{ 116259243Sobrien return bit(val,i); 116359243Sobrien} 116469408Sachevoid bis_extern(val,i) 116569408Sache int val; 116669408Sache int i; 116769408Sache{ 116869408Sache bis(val,i); 116969408Sache} 117069408Sache#endif /* WINNT_NATIVE */ 117169408Sache 1172