1316958Sdchagin/* $Header: /p/tcsh/cvsroot/tcsh/sh.exec.c,v 3.81 2016/09/12 16:33:54 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 35316958SdchaginRCSID("$tcsh: sh.exec.c,v 3.81 2016/09/12 16:33:54 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 /* 609316958Sdchagin * Decrement the shell level, if not in a subshell 610167465Smp */ 611316958Sdchagin if (mainpid == getpid()) 612316958Sdchagin shlvl(-1); 61369408Sache#ifdef WINNT_NATIVE 614167465Smp __nt_really_exec=1; 61569408Sache#endif /* WINNT_NATIVE */ 616167465Smp doexec(kp, 1); 61759243Sobrien 618167465Smp cleanup_until(&state); 61959243Sobrien} 62059243Sobrien 62159243Sobrienvoid 622167465Smpxechoit(Char **t) 62359243Sobrien{ 62459243Sobrien if (adrof(STRecho)) { 625100616Smp int odidfds = didfds; 62659243Sobrien flush(); 62759243Sobrien haderr = 1; 628100616Smp didfds = 0; 62959243Sobrien blkpr(t), xputchar('\n'); 630100616Smp flush(); 631100616Smp didfds = odidfds; 63259243Sobrien haderr = 0; 63359243Sobrien } 63459243Sobrien} 63559243Sobrien 63659243Sobrien/*ARGSUSED*/ 63759243Sobrienvoid 638167465Smpdohash(Char **vv, struct command *c) 63959243Sobrien{ 64059243Sobrien#ifdef COMMENT 64159243Sobrien struct stat stb; 64259243Sobrien#endif 64359243Sobrien DIR *dirp; 644145479Smp struct dirent *dp; 64559243Sobrien int i = 0; 64659243Sobrien struct varent *v = adrof(STRpath); 64759243Sobrien Char **pv; 64859243Sobrien int hashval; 64969408Sache#ifdef WINNT_NATIVE 65059243Sobrien int is_windir; /* check if it is the windows directory */ 65159243Sobrien USE(hashval); 65269408Sache#endif /* WINNT_NATIVE */ 65359243Sobrien 65459243Sobrien USE(c); 65559243Sobrien#ifdef FASTHASH 65659243Sobrien if (vv && vv[1]) { 65759243Sobrien uhashlength = atoi(short2str(vv[1])); 65859243Sobrien if (vv[2]) { 65959243Sobrien uhashwidth = atoi(short2str(vv[2])); 66059243Sobrien if ((uhashwidth != sizeof(unsigned char)) && 66159243Sobrien (uhashwidth != sizeof(unsigned short)) && 66259243Sobrien (uhashwidth != sizeof(unsigned long))) 66359243Sobrien uhashwidth = 0; 66459243Sobrien if (vv[3]) 66559243Sobrien hashdebug = atoi(short2str(vv[3])); 66659243Sobrien } 66759243Sobrien } 66859243Sobrien 66959243Sobrien if (uhashwidth) 67059243Sobrien hashwidth = uhashwidth; 67159243Sobrien else { 67259243Sobrien hashwidth = 0; 67369408Sache if (v == NULL) 67469408Sache return; 675100616Smp for (pv = v->vec; pv && *pv; pv++, hashwidth++) 67659243Sobrien continue; 67759243Sobrien if (hashwidth <= widthof(unsigned char)) 67859243Sobrien hashwidth = sizeof(unsigned char); 67959243Sobrien else if (hashwidth <= widthof(unsigned short)) 68059243Sobrien hashwidth = sizeof(unsigned short); 68159243Sobrien else if (hashwidth <= widthof(unsigned int)) 68259243Sobrien hashwidth = sizeof(unsigned int); 68359243Sobrien else 68459243Sobrien hashwidth = sizeof(unsigned long); 68559243Sobrien } 68659243Sobrien 68759243Sobrien if (uhashlength) 68859243Sobrien hashlength = uhashlength; 68959243Sobrien else 69059243Sobrien hashlength = hashwidth * (8*64);/* "average" files per dir in path */ 691167465Smp 692167465Smp xfree(xhash); 693167465Smp xhash = xcalloc(hashlength * hashwidth, 1); 69459243Sobrien#endif /* FASTHASH */ 69559243Sobrien 69659243Sobrien (void) getusername(NULL); /* flush the tilde cashe */ 69759243Sobrien tw_cmd_free(); 69859243Sobrien havhash = 1; 69959243Sobrien if (v == NULL) 70059243Sobrien return; 701100616Smp for (pv = v->vec; pv && *pv; pv++, i++) { 70259243Sobrien if (!ABSOLUTEP(pv[0])) 70359243Sobrien continue; 70459243Sobrien dirp = opendir(short2str(*pv)); 70559243Sobrien if (dirp == NULL) 70659243Sobrien continue; 707167465Smp cleanup_push(dirp, opendir_cleanup); 70859243Sobrien#ifdef COMMENT /* this isn't needed. opendir won't open 70959243Sobrien * non-dirs */ 71059243Sobrien if (fstat(dirp->dd_fd, &stb) < 0 || !S_ISDIR(stb.st_mode)) { 711167465Smp cleanup_until(dirp); 71259243Sobrien continue; 71359243Sobrien } 71459243Sobrien#endif 71569408Sache#ifdef WINNT_NATIVE 71659243Sobrien is_windir = nt_check_if_windir(short2str(*pv)); 71769408Sache#endif /* WINNT_NATIVE */ 71859243Sobrien while ((dp = readdir(dirp)) != NULL) { 71959243Sobrien if (dp->d_ino == 0) 72059243Sobrien continue; 72159243Sobrien if (dp->d_name[0] == '.' && 72259243Sobrien (dp->d_name[1] == '\0' || 72359243Sobrien (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) 72459243Sobrien continue; 72569408Sache#ifdef WINNT_NATIVE 72659243Sobrien nt_check_name_and_hash(is_windir, dp->d_name, i); 72769408Sache#else /* !WINNT_NATIVE*/ 72869408Sache#if defined(_UWIN) || defined(__CYGWIN__) 72959243Sobrien /* Turn foo.{exe,com,bat} into foo since UWIN's readdir returns 73059243Sobrien * the file with the .exe, .com, .bat extension 731231990Smp * 732231990Smp * Same for Cygwin, but only for .exe and .com extension. 73359243Sobrien */ 73459243Sobrien { 735167465Smp ssize_t ext = strlen(dp->d_name) - 4; 736131962Smp if ((ext > 0) && (strcasecmp(&dp->d_name[ext], ".exe") == 0 || 737231990Smp#ifndef __CYGWIN__ 738131962Smp strcasecmp(&dp->d_name[ext], ".bat") == 0 || 739231990Smp#endif 740167465Smp strcasecmp(&dp->d_name[ext], ".com") == 0)) { 741167465Smp#ifdef __CYGWIN__ 742167465Smp /* Also store the variation with extension. */ 743167465Smp hashval = hashname(str2short(dp->d_name)); 744167465Smp bis(hashval, i); 745131962Smp#endif /* __CYGWIN__ */ 746167465Smp dp->d_name[ext] = '\0'; 747167465Smp } 74859243Sobrien } 74969408Sache#endif /* _UWIN || __CYGWIN__ */ 75059243Sobrien# ifdef FASTHASH 75159243Sobrien hashval = hashname(str2short(dp->d_name)); 75259243Sobrien bis(hashval, i); 75359243Sobrien if (hashdebug & 1) 75459243Sobrien xprintf(CGETS(13, 1, "hash=%-4d dir=%-2d prog=%s\n"), 75559243Sobrien hashname(str2short(dp->d_name)), i, dp->d_name); 75659243Sobrien# else /* OLD HASH */ 75759243Sobrien hashval = hash(hashname(str2short(dp->d_name)), i); 75859243Sobrien bis(xhash, hashval); 75959243Sobrien# endif /* FASTHASH */ 76059243Sobrien /* tw_add_comm_name (dp->d_name); */ 76169408Sache#endif /* WINNT_NATIVE */ 76259243Sobrien } 763167465Smp cleanup_until(dirp); 76459243Sobrien } 76559243Sobrien} 76659243Sobrien 76759243Sobrien/*ARGSUSED*/ 76859243Sobrienvoid 769167465Smpdounhash(Char **v, struct command *c) 77059243Sobrien{ 77159243Sobrien USE(c); 77259243Sobrien USE(v); 77359243Sobrien havhash = 0; 77459243Sobrien#ifdef FASTHASH 775167465Smp xfree(xhash); 776167465Smp xhash = NULL; 77759243Sobrien#endif /* FASTHASH */ 77859243Sobrien} 77959243Sobrien 78059243Sobrien/*ARGSUSED*/ 78159243Sobrienvoid 782167465Smphashstat(Char **v, struct command *c) 78359243Sobrien{ 78459243Sobrien USE(c); 78559243Sobrien USE(v); 78659243Sobrien#ifdef FASTHASH 78759243Sobrien if (havhash && hashlength && hashwidth) 78859243Sobrien xprintf(CGETS(13, 2, "%d hash buckets of %d bits each\n"), 78959243Sobrien hashlength, hashwidth*8); 79059243Sobrien if (hashdebug) 79159243Sobrien xprintf(CGETS(13, 3, "debug mask = 0x%08x\n"), hashdebug); 79259243Sobrien#endif /* FASTHASH */ 79359243Sobrien#ifdef VFORK 79459243Sobrien if (hits + misses) 79559243Sobrien xprintf(CGETS(13, 4, "%d hits, %d misses, %d%%\n"), 79659243Sobrien hits, misses, 100 * hits / (hits + misses)); 79759243Sobrien#endif 79859243Sobrien} 79959243Sobrien 80059243Sobrien 80159243Sobrien/* 80259243Sobrien * Hash a command name. 80359243Sobrien */ 80469408Sacheint 805167465Smphashname(Char *cp) 80659243Sobrien{ 807145479Smp unsigned long h; 80859243Sobrien 80959243Sobrien for (h = 0; *cp; cp++) 81059243Sobrien h = hash(h, *cp); 81159243Sobrien return ((int) h); 81259243Sobrien} 81359243Sobrien 81459243Sobrienstatic int 815167465Smpiscommand(Char *name) 81659243Sobrien{ 817231990Smp Char **opv, **pv; 818145479Smp Char *sav; 819145479Smp struct varent *v; 820145479Smp int slash = any(short2str(name), '/'); 821231990Smp int hashval, rehashed, i; 82259243Sobrien 82359243Sobrien v = adrof(STRpath); 824100616Smp if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash) 825231990Smp opv = justabs; 82659243Sobrien else 827231990Smp opv = v->vec; 82859243Sobrien sav = Strspl(STRslash, name); /* / command name for postpending */ 82959243Sobrien hashval = havhash ? hashname(name) : 0; 830231990Smp 831231990Smp rehashed = 0; 832231990Smpretry: 833231990Smp pv = opv; 83459243Sobrien i = 0; 83559243Sobrien do { 83659243Sobrien if (!slash && ABSOLUTEP(pv[0]) && havhash) { 83759243Sobrien#ifdef FASTHASH 83859243Sobrien if (!bit(hashval, i)) 83959243Sobrien goto cont; 84059243Sobrien#else /* OLDHASH */ 84159243Sobrien int hashval1 = hash(hashval, i); 84259243Sobrien if (!bit(xhash, hashval1)) 84359243Sobrien goto cont; 84459243Sobrien#endif /* FASTHASH */ 84559243Sobrien } 84659243Sobrien if (pv[0][0] == 0 || eq(pv[0], STRdot)) { /* don't make ./xxx */ 84759243Sobrien if (executable(NULL, name, 0)) { 848167465Smp xfree(sav); 84959243Sobrien return i + 1; 85059243Sobrien } 85159243Sobrien } 85259243Sobrien else { 85359243Sobrien if (executable(*pv, sav, 0)) { 854167465Smp xfree(sav); 85559243Sobrien return i + 1; 85659243Sobrien } 85759243Sobrien } 85859243Sobriencont: 85959243Sobrien pv++; 86059243Sobrien i++; 86159243Sobrien } while (*pv); 862231990Smp if (adrof(STRautorehash) && !rehashed && havhash && opv != justabs) { 863231990Smp dohash(NULL, NULL); 864231990Smp rehashed = 1; 865231990Smp goto retry; 866231990Smp } 867167465Smp xfree(sav); 86859243Sobrien return 0; 86959243Sobrien} 87059243Sobrien 87159243Sobrien/* Also by: 87259243Sobrien * Andreas Luik <luik@isaak.isa.de> 87359243Sobrien * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 87459243Sobrien * Azenberstr. 35 87559243Sobrien * D-7000 Stuttgart 1 87659243Sobrien * West-Germany 87759243Sobrien * is the executable() routine below and changes to iscommand(). 87859243Sobrien * Thanks again!! 87959243Sobrien */ 88059243Sobrien 88169408Sache#ifndef WINNT_NATIVE 88259243Sobrien/* 88359243Sobrien * executable() examines the pathname obtained by concatenating dir and name 88459243Sobrien * (dir may be NULL), and returns 1 either if it is executable by us, or 88559243Sobrien * if dir_ok is set and the pathname refers to a directory. 88659243Sobrien * This is a bit kludgy, but in the name of optimization... 88759243Sobrien */ 88859243Sobrienint 889167465Smpexecutable(const Char *dir, const Char *name, int dir_ok) 89059243Sobrien{ 89159243Sobrien struct stat stbuf; 89259243Sobrien char *strname; 89359243Sobrien 89459243Sobrien if (dir && *dir) { 895167465Smp Char *path; 896167465Smp 897167465Smp path = Strspl(dir, name); 89859243Sobrien strname = short2str(path); 899167465Smp xfree(path); 90059243Sobrien } 90159243Sobrien else 90259243Sobrien strname = short2str(name); 903167465Smp 90459243Sobrien return (stat(strname, &stbuf) != -1 && 90559243Sobrien ((dir_ok && S_ISDIR(stbuf.st_mode)) || 90659243Sobrien (S_ISREG(stbuf.st_mode) && 90759243Sobrien /* save time by not calling access() in the hopeless case */ 90859243Sobrien (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) && 90959243Sobrien access(strname, X_OK) == 0 91059243Sobrien ))); 91159243Sobrien} 91269408Sache#endif /*!WINNT_NATIVE*/ 91359243Sobrien 914167465Smpstruct tellmewhat_s0_cleanup 915167465Smp{ 916167465Smp Char **dest, *val; 917167465Smp}; 918167465Smp 919167465Smpstatic void 920167465Smptellmewhat_s0_cleanup(void *xstate) 921167465Smp{ 922167465Smp struct tellmewhat_s0_cleanup *state; 923167465Smp 924167465Smp state = xstate; 925167465Smp *state->dest = state->val; 926167465Smp} 927167465Smp 92859243Sobrienint 929167465Smptellmewhat(struct wordent *lexp, Char **str) 93059243Sobrien{ 931167465Smp struct tellmewhat_s0_cleanup s0; 932145479Smp int i; 933167465Smp const struct biltins *bptr; 934145479Smp struct wordent *sp = lexp->next; 935145479Smp int aliased = 0, found; 936167465Smp Char *s1, *s2, *cmd; 93759243Sobrien Char qc; 93859243Sobrien 93959243Sobrien if (adrof1(sp->word, &aliases)) { 94059243Sobrien alias(lexp); 94159243Sobrien sp = lexp->next; 94259243Sobrien aliased = 1; 94359243Sobrien } 94459243Sobrien 945167465Smp s0.dest = &sp->word; /* to get the memory freeing right... */ 946167465Smp s0.val = sp->word; 947167465Smp cleanup_push(&s0, tellmewhat_s0_cleanup); 94859243Sobrien 94959243Sobrien /* handle quoted alias hack */ 95059243Sobrien if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE) 95159243Sobrien (sp->word)++; 95259243Sobrien 95359243Sobrien /* do quoting, if it hasn't been done */ 95459243Sobrien s1 = s2 = sp->word; 95559243Sobrien while (*s2) 95659243Sobrien switch (*s2) { 95759243Sobrien case '\'': 95859243Sobrien case '"': 95959243Sobrien qc = *s2++; 96059243Sobrien while (*s2 && *s2 != qc) 96159243Sobrien *s1++ = *s2++ | QUOTE; 96259243Sobrien if (*s2) 96359243Sobrien s2++; 96459243Sobrien break; 96559243Sobrien case '\\': 96659243Sobrien if (*++s2) 96759243Sobrien *s1++ = *s2++ | QUOTE; 96859243Sobrien break; 96959243Sobrien default: 97059243Sobrien *s1++ = *s2++; 97159243Sobrien } 97259243Sobrien *s1 = '\0'; 97359243Sobrien 97459243Sobrien for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) { 97559243Sobrien if (eq(sp->word, str2short(bptr->bname))) { 97659243Sobrien if (str == NULL) { 97759243Sobrien if (aliased) 97859243Sobrien prlex(lexp); 97959243Sobrien xprintf(CGETS(13, 5, "%S: shell built-in command.\n"), 98059243Sobrien sp->word); 98159243Sobrien flush(); 98259243Sobrien } 983167465Smp else 984167465Smp *str = Strsave(sp->word); 985167465Smp cleanup_until(&s0); 98659243Sobrien return TRUE; 98759243Sobrien } 98859243Sobrien } 98969408Sache#ifdef WINNT_NATIVE 99059243Sobrien for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) { 99159243Sobrien if (eq(sp->word, str2short(bptr->bname))) { 99259243Sobrien if (str == NULL) { 99359243Sobrien if (aliased) 99459243Sobrien prlex(lexp); 99559243Sobrien xprintf(CGETS(13, 5, "%S: shell built-in command.\n"), 99659243Sobrien sp->word); 99759243Sobrien flush(); 99859243Sobrien } 999167465Smp else 1000167465Smp *str = Strsave(sp->word); 1001167465Smp cleanup_until(&s0); 100259243Sobrien return TRUE; 100359243Sobrien } 100459243Sobrien } 100569408Sache#endif /* WINNT_NATIVE*/ 100659243Sobrien 100759243Sobrien sp->word = cmd = globone(sp->word, G_IGNORE); 1008167465Smp cleanup_push(cmd, xfree); 100959243Sobrien 101059243Sobrien if ((i = iscommand(sp->word)) != 0) { 1011145479Smp Char **pv; 1012145479Smp struct varent *v; 1013145479Smp int slash = any(short2str(sp->word), '/'); 101459243Sobrien 101559243Sobrien v = adrof(STRpath); 1016100616Smp if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash) 101759243Sobrien pv = justabs; 101859243Sobrien else 101959243Sobrien pv = v->vec; 102059243Sobrien 1021167465Smp pv += i - 1; 102259243Sobrien if (pv[0][0] == 0 || eq(pv[0], STRdot)) { 102359243Sobrien if (!slash) { 102459243Sobrien sp->word = Strspl(STRdotsl, sp->word); 1025167465Smp cleanup_push(sp->word, xfree); 102659243Sobrien prlex(lexp); 1027167465Smp cleanup_until(sp->word); 102859243Sobrien } 102959243Sobrien else 103059243Sobrien prlex(lexp); 103159243Sobrien } 103259243Sobrien else { 103359243Sobrien s1 = Strspl(*pv, STRslash); 103459243Sobrien sp->word = Strspl(s1, sp->word); 1035167465Smp xfree(s1); 1036167465Smp cleanup_push(sp->word, xfree); 103759243Sobrien if (str == NULL) 103859243Sobrien prlex(lexp); 103959243Sobrien else 1040167465Smp *str = Strsave(sp->word); 1041167465Smp cleanup_until(sp->word); 104259243Sobrien } 104359243Sobrien found = 1; 104459243Sobrien } 104559243Sobrien else { 104659243Sobrien if (str == NULL) { 104759243Sobrien if (aliased) 104859243Sobrien prlex(lexp); 104959243Sobrien xprintf(CGETS(13, 6, "%S: Command not found.\n"), sp->word); 105059243Sobrien flush(); 105159243Sobrien } 105259243Sobrien else 1053167465Smp *str = Strsave(sp->word); 105459243Sobrien found = 0; 105559243Sobrien } 1056167465Smp cleanup_until(&s0); 105759243Sobrien return found; 105859243Sobrien} 105959243Sobrien 106059243Sobrien/* 106159243Sobrien * Builtin to look at and list all places a command may be defined: 106259243Sobrien * aliases, shell builtins, and the path. 106359243Sobrien * 106459243Sobrien * Marc Horowitz <marc@mit.edu> 106559243Sobrien * MIT Student Information Processing Board 106659243Sobrien */ 106759243Sobrien 106859243Sobrien/*ARGSUSED*/ 106959243Sobrienvoid 1070167465Smpdowhere(Char **v, struct command *c) 107159243Sobrien{ 107259243Sobrien int found = 1; 107359243Sobrien USE(c); 1074316958Sdchagin 1075316958Sdchagin if (adrof(STRautorehash)) 1076316958Sdchagin dohash(NULL, NULL); 107759243Sobrien for (v++; *v; v++) 107859243Sobrien found &= find_cmd(*v, 1); 107959243Sobrien /* Make status nonzero if any command is not found. */ 108059243Sobrien if (!found) 1081167465Smp setcopy(STRstatus, STR1, VAR_READWRITE); 108259243Sobrien} 108359243Sobrien 108459243Sobrienint 1085167465Smpfind_cmd(Char *cmd, int prt) 108659243Sobrien{ 108759243Sobrien struct varent *var; 1088167465Smp const struct biltins *bptr; 108959243Sobrien Char **pv; 109059243Sobrien Char *sv; 1091231990Smp int hashval, rehashed, i, ex, rval = 0; 109259243Sobrien 109359243Sobrien if (prt && any(short2str(cmd), '/')) { 1094195609Smp xprintf("%s", CGETS(13, 7, "where: / in command makes no sense\n")); 109559243Sobrien return rval; 109659243Sobrien } 109759243Sobrien 109859243Sobrien /* first, look for an alias */ 109959243Sobrien 110059243Sobrien if (prt && adrof1(cmd, &aliases)) { 110159243Sobrien if ((var = adrof1(cmd, &aliases)) != NULL) { 110259243Sobrien xprintf(CGETS(13, 8, "%S is aliased to "), cmd); 1103100616Smp if (var->vec != NULL) 1104100616Smp blkpr(var->vec); 110559243Sobrien xputchar('\n'); 110659243Sobrien rval = 1; 110759243Sobrien } 110859243Sobrien } 110959243Sobrien 111059243Sobrien /* next, look for a shell builtin */ 111159243Sobrien 111259243Sobrien for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) { 111359243Sobrien if (eq(cmd, str2short(bptr->bname))) { 111459243Sobrien rval = 1; 111559243Sobrien if (prt) 111659243Sobrien xprintf(CGETS(13, 9, "%S is a shell built-in\n"), cmd); 111759243Sobrien else 111859243Sobrien return rval; 111959243Sobrien } 112059243Sobrien } 112169408Sache#ifdef WINNT_NATIVE 112259243Sobrien for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) { 112359243Sobrien if (eq(cmd, str2short(bptr->bname))) { 112459243Sobrien rval = 1; 112559243Sobrien if (prt) 112659243Sobrien xprintf(CGETS(13, 9, "%S is a shell built-in\n"), cmd); 112759243Sobrien else 112859243Sobrien return rval; 112959243Sobrien } 113059243Sobrien } 113169408Sache#endif /* WINNT_NATIVE*/ 113259243Sobrien 113359243Sobrien /* last, look through the path for the command */ 113459243Sobrien 113559243Sobrien if ((var = adrof(STRpath)) == NULL) 113659243Sobrien return rval; 113759243Sobrien 113859243Sobrien hashval = havhash ? hashname(cmd) : 0; 113959243Sobrien 114059243Sobrien sv = Strspl(STRslash, cmd); 1141167465Smp cleanup_push(sv, xfree); 114259243Sobrien 1143231990Smp rehashed = 0; 1144231990Smpretry: 1145100616Smp for (pv = var->vec, i = 0; pv && *pv; pv++, i++) { 114659243Sobrien if (havhash && !eq(*pv, STRdot)) { 114759243Sobrien#ifdef FASTHASH 114859243Sobrien if (!bit(hashval, i)) 114959243Sobrien continue; 115059243Sobrien#else /* OLDHASH */ 115159243Sobrien int hashval1 = hash(hashval, i); 115259243Sobrien if (!bit(xhash, hashval1)) 115359243Sobrien continue; 115459243Sobrien#endif /* FASTHASH */ 115559243Sobrien } 115659243Sobrien ex = executable(*pv, sv, 0); 115759243Sobrien#ifdef FASTHASH 115859243Sobrien if (!ex && (hashdebug & 2)) { 1159195609Smp xprintf("%s", CGETS(13, 10, "hash miss: ")); 116059243Sobrien ex = 1; /* Force printing */ 116159243Sobrien } 116259243Sobrien#endif /* FASTHASH */ 116359243Sobrien if (ex) { 116459243Sobrien rval = 1; 116559243Sobrien if (prt) { 116659243Sobrien xprintf("%S/", *pv); 116759243Sobrien xprintf("%S\n", cmd); 116859243Sobrien } 116959243Sobrien else 117059243Sobrien return rval; 117159243Sobrien } 117259243Sobrien } 1173316958Sdchagin /* 1174316958Sdchagin * If we are printing, we are being called from dowhere() which it 1175316958Sdchagin * has rehashed already 1176316958Sdchagin */ 1177316958Sdchagin if (!prt && adrof(STRautorehash) && !rehashed && havhash) { 1178231990Smp dohash(NULL, NULL); 1179231990Smp rehashed = 1; 1180231990Smp goto retry; 1181231990Smp } 1182167465Smp cleanup_until(sv); 118359243Sobrien return rval; 118459243Sobrien} 118569408Sache#ifdef WINNT_NATIVE 118659243Sobrienint hashval_extern(cp) 118759243Sobrien Char *cp; 118859243Sobrien{ 118959243Sobrien return havhash?hashname(cp):0; 119059243Sobrien} 119159243Sobrienint bit_extern(val,i) 119259243Sobrien int val; 119359243Sobrien int i; 119459243Sobrien{ 119559243Sobrien return bit(val,i); 119659243Sobrien} 119769408Sachevoid bis_extern(val,i) 119869408Sache int val; 119969408Sache int i; 120069408Sache{ 120169408Sache bis(val,i); 120269408Sache} 120369408Sache#endif /* WINNT_NATIVE */ 120469408Sache 1205