sh.exec.c revision 145479
1168404Spjd/* $Header: /src/pub/tcsh/sh.exec.c,v 3.63 2004/11/23 02:10:48 christos Exp $ */ 2168404Spjd/* 3168404Spjd * sh.exec.c: Search, find, and execute a command! 4168404Spjd */ 5168404Spjd/*- 6168404Spjd * Copyright (c) 1980, 1991 The Regents of the University of California. 7168404Spjd * All rights reserved. 8168404Spjd * 9168404Spjd * Redistribution and use in source and binary forms, with or without 10168404Spjd * modification, are permitted provided that the following conditions 11168404Spjd * are met: 12168404Spjd * 1. Redistributions of source code must retain the above copyright 13168404Spjd * notice, this list of conditions and the following disclaimer. 14168404Spjd * 2. Redistributions in binary form must reproduce the above copyright 15168404Spjd * notice, this list of conditions and the following disclaimer in the 16168404Spjd * documentation and/or other materials provided with the distribution. 17168404Spjd * 3. Neither the name of the University nor the names of its contributors 18168404Spjd * may be used to endorse or promote products derived from this software 19168404Spjd * without specific prior written permission. 20168404Spjd * 21168404Spjd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22168404Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23219089Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24249195Smm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25249188Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26247265Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28168404Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29168404Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30251629Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31251629Sdelphij * SUCH DAMAGE. 32168404Spjd */ 33168404Spjd#include "sh.h" 34168404Spjd 35168404SpjdRCSID("$Id: sh.exec.c,v 3.63 2004/11/23 02:10:48 christos Exp $") 36168404Spjd 37168404Spjd#include "tc.h" 38168404Spjd#include "tw.h" 39168404Spjd#ifdef WINNT_NATIVE 40168404Spjd#include <nt.const.h> 41168404Spjd#endif /*WINNT_NATIVE*/ 42168404Spjd 43168404Spjd/* 44168404Spjd * C shell 45168404Spjd */ 46219089Spjd 47168404Spjd#ifndef OLDHASH 48168404Spjd# define FASTHASH /* Fast hashing is the default */ 49219089Spjd#endif /* OLDHASH */ 50168404Spjd 51168404Spjd/* 52168404Spjd * System level search and execute of a command. 53168404Spjd * We look in each directory for the specified command name. 54168404Spjd * If the name contains a '/' then we execute only the full path name. 55168404Spjd * If there is no search path then we execute only full path names. 56168404Spjd */ 57168404Spjd 58168404Spjd/* 59168404Spjd * As we search for the command we note the first non-trivial error 60168404Spjd * message for presentation to the user. This allows us often 61168404Spjd * to show that a file has the wrong mode/no access when the file 62185029Spjd * is not in the last component of the search path, so we must 63168404Spjd * go on after first detecting the error. 64185029Spjd */ 65219089Spjdstatic char *exerr; /* Execution error message */ 66219089Spjdstatic Char *expath; /* Path for exerr */ 67248571Smm 68248571Smm/* 69248571Smm * The two part hash function is designed to let texec() call the 70236884Smm * more expensive hashname() only once and the simple hash() several 71219089Spjd * times (once for each path component checked). 72240868Spjd * Byte size is assumed to be 8. 73168404Spjd */ 74219089Spjd#define BITS_PER_BYTE 8 75219089Spjd 76219089Spjd#ifdef FASTHASH 77219089Spjd/* 78219089Spjd * xhash is an array of hash buckets which are used to hash execs. If 79219089Spjd * it is allocated (havhash true), then to tell if ``name'' is 80185029Spjd * (possibly) presend in the i'th component of the variable path, look 81185029Spjd * at the [hashname(name)] bucket of size [hashwidth] bytes, in the [i 82168404Spjd * mod size*8]'th bit. The cache size is defaults to a length of 1024 83204073Spjd * buckets, each 1 byte wide. This implementation guarantees that 84204073Spjd * objects n bytes wide will be aligned on n byte boundaries. 85204073Spjd */ 86204073Spjd# define HSHMUL 241 87204073Spjd 88204073Spjdstatic unsigned long *xhash = NULL; 89204073Spjdstatic unsigned int hashlength = 0, uhashlength = 0; 90204073Spjdstatic unsigned int hashwidth = 0, uhashwidth = 0; 91251636Sdelphijstatic int hashdebug = 0; 92251636Sdelphij 93251636Sdelphij# define hash(a, b) (((a) * HSHMUL + (b)) % (hashlength)) 94251636Sdelphij# define widthof(t) (sizeof(t) * BITS_PER_BYTE) 95251636Sdelphij# define tbit(f, i, t) (((t *) xhash)[(f)] & \ 96251636Sdelphij (1UL << (i & (widthof(t) - 1)))) 97219089Spjd# define tbis(f, i, t) (((t *) xhash)[(f)] |= \ 98258631Savg (1UL << (i & (widthof(t) - 1)))) 99258631Savg# define cbit(f, i) tbit(f, i, unsigned char) 100258631Savg# define cbis(f, i) tbis(f, i, unsigned char) 101258631Savg# define sbit(f, i) tbit(f, i, unsigned short) 102258631Savg# define sbis(f, i) tbis(f, i, unsigned short) 103219089Spjd# define ibit(f, i) tbit(f, i, unsigned int) 104168712Spjd# define ibis(f, i) tbis(f, i, unsigned int) 105258631Savg# define lbit(f, i) tbit(f, i, unsigned long) 106258631Savg# define lbis(f, i) tbis(f, i, unsigned long) 107258631Savg 108258631Savg# define bit(f, i) (hashwidth==sizeof(unsigned char) ? cbit(f,i) : \ 109209962Smm ((hashwidth==sizeof(unsigned short) ? sbit(f,i) : \ 110258631Savg ((hashwidth==sizeof(unsigned int) ? ibit(f,i) : \ 111258631Savg lbit(f,i)))))) 112209962Smm# define bis(f, i) (hashwidth==sizeof(unsigned char) ? cbis(f,i) : \ 113209962Smm ((hashwidth==sizeof(unsigned short) ? sbis(f,i) : \ 114258631Savg ((hashwidth==sizeof(unsigned int) ? ibis(f,i) : \ 115211931Smm lbis(f,i)))))) 116258631Savg#else /* OLDHASH */ 117209962Smm/* 118209962Smm * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used 119209962Smm * to hash execs. If it is allocated (havhash true), then to tell 120219089Spjd * whether ``name'' is (possibly) present in the i'th component 121209962Smm * of the variable path, you look at the bit in xhash indexed by 122209962Smm * hash(hashname("name"), i). This is setup automatically 123211931Smm * after .login is executed, and recomputed whenever ``path'' is 124258631Savg * changed. 125258631Savg */ 126258631Savg# define HSHSIZ 8192 /* 1k bytes */ 127258631Savg# define HSHMASK (HSHSIZ - 1) 128258631Savg# define HSHMUL 243 129258631Savgstatic char xhash[HSHSIZ / BITS_PER_BYTE]; 130258631Savg 131258631Savg# define hash(a, b) (((a) * HSHMUL + (b)) & HSHMASK) 132258631Savg# define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */ 133258631Savg# define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */ 134258631Savg 135258631Savg#endif /* FASTHASH */ 136258631Savg 137258631Savg#ifdef VFORK 138258631Savgstatic int hits, misses; 139211931Smm#endif /* VFORK */ 140211931Smm 141211931Smm/* Dummy search path for just absolute search when no path */ 142258631Savgstatic Char *justabs[] = {STRNULL, 0}; 143258631Savg 144258631Savgstatic void pexerr __P((void)); 145258631Savgstatic void texec __P((Char *, Char **)); 146258631Savgint hashname __P((Char *)); 147258631Savgstatic int iscommand __P((Char *)); 148209962Smm 149209962Smmvoid 150248571Smmdoexec(t, do_glob) 151248571Smm struct command *t; 152185029Spjd int do_glob; 153219089Spjd{ 154219089Spjd Char *dp, **pv, **av, *sav; 155219089Spjd struct varent *v; 156219089Spjd int slash; 157185029Spjd int hashval, i; 158219089Spjd Char *blk[2]; 159219089Spjd 160219089Spjd /* 161219089Spjd * Glob the command name. We will search $path even if this does something, 162219089Spjd * as in sh but not in csh. One special case: if there is no PATH, then we 163219089Spjd * execute only commands which start with '/'. 164219089Spjd */ 165219089Spjd blk[0] = t->t_dcom[0]; 166219089Spjd blk[1] = 0; 167219089Spjd gflag = 0; 168243503Smm if (do_glob) 169219089Spjd tglob(blk); 170247265Smm if (gflag) { 171247265Smm pv = globall(blk); 172247265Smm if (pv == 0) { 173247265Smm setname(short2str(blk[0])); 174168404Spjd stderror(ERR_NAME | ERR_NOMATCH); 175219089Spjd } 176219089Spjd gargv = 0; 177219089Spjd } 178219089Spjd else 179219089Spjd pv = saveblk(blk); 180219089Spjd 181168404Spjd trim(pv); 182185029Spjd 183185029Spjd exerr = 0; 184185029Spjd expath = Strsave(pv[0]); 185185029Spjd#ifdef VFORK 186185029Spjd Vexpath = expath; 187185029Spjd#endif /* VFORK */ 188185029Spjd 189185029Spjd v = adrof(STRpath); 190185029Spjd if (v == 0 && expath[0] != '/' && expath[0] != '.') { 191185029Spjd blkfree(pv); 192185029Spjd pexerr(); 193185029Spjd } 194185029Spjd slash = any(short2str(expath), '/'); 195185029Spjd 196185029Spjd /* 197185029Spjd * Glob the argument list, if necessary. Otherwise trim off the quote bits. 198185029Spjd */ 199185029Spjd gflag = 0; 200185029Spjd av = &t->t_dcom[1]; 201185029Spjd if (do_glob) 202185029Spjd tglob(av); 203185029Spjd if (gflag) { 204185029Spjd av = globall(av); 205185029Spjd if (av == 0) { 206185029Spjd blkfree(pv); 207185029Spjd setname(short2str(expath)); 208185029Spjd stderror(ERR_NAME | ERR_NOMATCH); 209185029Spjd } 210185029Spjd gargv = 0; 211185029Spjd } 212185029Spjd else 213185029Spjd av = saveblk(av); 214236155Smm 215236884Smm blkfree(t->t_dcom); 216209962Smm t->t_dcom = blkspl(pv, av); 217219089Spjd xfree((ptr_t) pv); 218236155Smm xfree((ptr_t) av); 219185029Spjd av = t->t_dcom; 220185029Spjd trim(av); 221185029Spjd 222185029Spjd if (*av == NULL || **av == '\0') 223185029Spjd pexerr(); 224185029Spjd 225236155Smm xechoit(av); /* Echo command if -x */ 226219089Spjd#ifdef CLOSE_ON_EXEC 227219089Spjd /* 228209962Smm * Since all internal file descriptors are set to close on exec, we don't 229209962Smm * need to close them explicitly here. Just reorient ourselves for error 230219089Spjd * messages. 231219089Spjd */ 232219089Spjd SHIN = 0; 233236155Smm SHOUT = 1; 234236155Smm SHDIAG = 2; 235236155Smm OLDSTD = 0; 236236155Smm isoutatty = isatty(SHOUT); 237236155Smm isdiagatty = isatty(SHDIAG); 238236155Smm#else 239236155Smm closech(); /* Close random fd's */ 240236155Smm#endif 241236155Smm /* 242219089Spjd * We must do this AFTER any possible forking (like `foo` in glob) so that 243219089Spjd * this shell can still do subprocesses. 244185029Spjd */ 245219089Spjd#ifdef BSDSIGS 246209962Smm (void) sigsetmask((sigmask_t) 0); 247185029Spjd#else /* BSDSIGS */ 248219089Spjd (void) sigrelse(SIGINT); 249219089Spjd (void) sigrelse(SIGCHLD); 250219089Spjd#endif /* BSDSIGS */ 251209962Smm 252236155Smm /* 253209962Smm * If no path, no words in path, or a / in the filename then restrict the 254209962Smm * command search. 255209962Smm */ 256209962Smm if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash) 257209962Smm pv = justabs; 258209962Smm else 259209962Smm pv = v->vec; 260209962Smm sav = Strspl(STRslash, *av);/* / command name for postpending */ 261209962Smm#ifdef VFORK 262236884Smm Vsav = sav; 263236884Smm#endif /* VFORK */ 264236884Smm hashval = havhash ? hashname(*av) : 0; 265236884Smm 266236884Smm i = 0; 267236884Smm#ifdef VFORK 268236884Smm hits++; 269236884Smm#endif /* VFORK */ 270236884Smm do { 271236884Smm /* 272236884Smm * Try to save time by looking at the hash table for where this command 273236884Smm * could be. If we are doing delayed hashing, then we put the names in 274236884Smm * one at a time, as the user enters them. This is kinda like Korn 275236884Smm * Shell's "tracked aliases". 276236884Smm */ 277236884Smm if (!slash && ABSOLUTEP(pv[0]) && havhash) { 278185029Spjd#ifdef FASTHASH 279185029Spjd if (!bit(hashval, i)) 280228103Smm goto cont; 281228103Smm#else /* OLDHASH */ 282228103Smm int hashval1 = hash(hashval, i); 283228103Smm if (!bit(xhash, hashval1)) 284228103Smm goto cont; 285185029Spjd#endif /* FASTHASH */ 286185029Spjd } 287185029Spjd if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */ 288185029Spjd { 289185029Spjd 290185029Spjd#ifdef COHERENT 291185029Spjd if (t->t_dflg & F_AMPERSAND) { 292185029Spjd# ifdef JOBDEBUG 293185029Spjd xprintf("set SIGINT to SIG_IGN\n"); 294185029Spjd xprintf("set SIGQUIT to SIG_DFL\n"); 295185029Spjd# endif /* JOBDEBUG */ 296185029Spjd (void) signal(SIGINT,SIG_IGN); /* may not be necessary */ 297185029Spjd (void) signal(SIGQUIT,SIG_DFL); 298185029Spjd } 299185029Spjd 300185029Spjd if (gointr && eq(gointr, STRminus)) { 301185029Spjd# ifdef JOBDEBUG 302185029Spjd xprintf("set SIGINT to SIG_IGN\n"); 303185029Spjd xprintf("set SIGQUIT to SIG_IGN\n"); 304185029Spjd# endif /* JOBDEBUG */ 305185029Spjd (void) signal(SIGINT,SIG_IGN); /* may not be necessary */ 306219089Spjd (void) signal(SIGQUIT,SIG_IGN); 307185029Spjd } 308185029Spjd#endif /* COHERENT */ 309185029Spjd 310185029Spjd texec(*av, av); 311185029Spjd} 312185029Spjd else { 313185029Spjd dp = Strspl(*pv, sav); 314185029Spjd#ifdef VFORK 315185029Spjd Vdp = dp; 316185029Spjd#endif /* VFORK */ 317185029Spjd 318185029Spjd#ifdef COHERENT 319185029Spjd if ((t->t_dflg & F_AMPERSAND)) { 320185029Spjd# ifdef JOBDEBUG 321219089Spjd xprintf("set SIGINT to SIG_IGN\n"); 322185029Spjd# endif /* JOBDEBUG */ 323185029Spjd /* 324185029Spjd * this is necessary on Coherent or all background 325185029Spjd * jobs are killed by CTRL-C 326185029Spjd * (there must be a better fix for this) 327185029Spjd */ 328185029Spjd (void) signal(SIGINT,SIG_IGN); 329185029Spjd } 330185029Spjd if (gointr && eq(gointr,STRminus)) { 331185029Spjd# ifdef JOBDEBUG 332185029Spjd xprintf("set SIGINT to SIG_IGN\n"); 333185029Spjd xprintf("set SIGQUIT to SIG_IGN\n"); 334185029Spjd# endif /* JOBDEBUG */ 335185029Spjd (void) signal(SIGINT,SIG_IGN); /* may not be necessary */ 336185029Spjd (void) signal(SIGQUIT,SIG_IGN); 337185029Spjd } 338185029Spjd#endif /* COHERENT */ 339185029Spjd 340185029Spjd texec(dp, av); 341185029Spjd#ifdef VFORK 342185029Spjd Vdp = 0; 343185029Spjd#endif /* VFORK */ 344185029Spjd xfree((ptr_t) dp); 345185029Spjd } 346185029Spjd#ifdef VFORK 347185029Spjd misses++; 348185029Spjd#endif /* VFORK */ 349185029Spjdcont: 350185029Spjd pv++; 351185029Spjd i++; 352248571Smm } while (*pv); 353185029Spjd#ifdef VFORK 354185029Spjd hits--; 355248571Smm Vsav = 0; 356185029Spjd#endif /* VFORK */ 357185029Spjd xfree((ptr_t) sav); 358185029Spjd pexerr(); 359185029Spjd} 360185029Spjd 361185029Spjdstatic void 362185029Spjdpexerr() 363185029Spjd{ 364248571Smm /* Couldn't find the damn thing */ 365185029Spjd if (expath) { 366185029Spjd setname(short2str(expath)); 367185029Spjd#ifdef VFORK 368185029Spjd Vexpath = 0; 369185029Spjd#endif /* VFORK */ 370185029Spjd xfree((ptr_t) expath); 371185029Spjd expath = 0; 372185029Spjd } 373185029Spjd else 374185029Spjd setname(""); 375185029Spjd if (exerr) 376185029Spjd stderror(ERR_NAME | ERR_STRING, exerr); 377185029Spjd stderror(ERR_NAME | ERR_COMMAND); 378185029Spjd} 379185029Spjd 380185029Spjd/* 381185029Spjd * Execute command f, arg list t. 382185029Spjd * Record error message if not found. 383185029Spjd * Also do shell scripts here. 384185029Spjd */ 385185029Spjdstatic void 386185029Spjdtexec(sf, st) 387185029Spjd Char *sf; 388185029Spjd Char **st; 389185029Spjd{ 390185029Spjd char **t; 391185029Spjd char *f; 392185029Spjd struct varent *v; 393185029Spjd Char **vp; 394185029Spjd Char *lastsh[2]; 395185029Spjd char pref[2]; 396185029Spjd int fd; 397185029Spjd Char *st0, **ost; 398185029Spjd 399185029Spjd /* The order for the conversions is significant */ 400185029Spjd t = short2blk(st); 401185029Spjd f = short2str(sf); 402185029Spjd#ifdef VFORK 403185029Spjd Vt = t; 404185029Spjd#endif /* VFORK */ 405185029Spjd errno = 0; /* don't use a previous error */ 406185029Spjd#ifdef apollo 407185029Spjd /* 408185029Spjd * If we try to execute an nfs mounted directory on the apollo, we 409185029Spjd * hang forever. So until apollo fixes that.. 410185029Spjd */ 411185029Spjd { 412185029Spjd struct stat stb; 413185029Spjd if (stat(f, &stb) == 0 && S_ISDIR(stb.st_mode)) 414185029Spjd errno = EISDIR; 415185029Spjd } 416247187Smm if (errno == 0) 417236884Smm#endif /* apollo */ 418185029Spjd { 419185029Spjd#ifdef ISC_POSIX_EXEC_BUG 420185029Spjd __setostype(0); /* "0" is "__OS_SYSV" in <sys/user.h> */ 421185029Spjd#endif /* ISC_POSIX_EXEC_BUG */ 422236884Smm (void) execv(f, t); 423236884Smm#ifdef ISC_POSIX_EXEC_BUG 424236884Smm __setostype(1); /* "1" is "__OS_POSIX" in <sys/user.h> */ 425185029Spjd#endif /* ISC_POSIX_EXEC_BUG */ 426236884Smm } 427236884Smm#ifdef VFORK 428236884Smm Vt = 0; 429249195Smm#endif /* VFORK */ 430236884Smm blkfree((Char **) t); 431236884Smm switch (errno) { 432185029Spjd 433236884Smm case ENOEXEC: 434236884Smm#ifdef WINNT_NATIVE 435236884Smm nt_feed_to_cmd(f,t); 436236884Smm#endif /* WINNT_NATIVE */ 437249195Smm /* 438236884Smm * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute 439236884Smm * it, don't feed it to the shell if it looks like a binary! 440185029Spjd */ 441236884Smm if ((fd = open(f, O_RDONLY|O_LARGEFILE)) != -1) { 442249195Smm int nread; 443236884Smm#ifdef O_TEXT 444236884Smm setmode(fd, O_TEXT); 445236884Smm#endif 446236884Smm if ((nread = read(fd, (char *) pref, 2)) == 2) { 447249195Smm if (!isprint((unsigned char)pref[0]) && 448236884Smm (pref[0] != '\n' && pref[0] != '\t')) { 449236884Smm (void) close(fd); 450236884Smm /* 451236884Smm * We *know* what ENOEXEC means. 452236884Smm */ 453249195Smm stderror(ERR_ARCH, f, strerror(errno)); 454236884Smm } 455236884Smm } 456236884Smm else if (nread < 0 && errno != EINTR) { 457236884Smm#ifdef convex 458236884Smm /* need to print error incase the file is migrated */ 459236884Smm stderror(ERR_SYSTEM, f, strerror(errno)); 460185029Spjd#endif 461185029Spjd } 462185029Spjd#ifdef _PATH_BSHELL 463236884Smm else { 464236884Smm pref[0] = '#'; 465236884Smm pref[1] = '\0'; 466249195Smm } 467185029Spjd#endif 468185029Spjd } 469185029Spjd#ifdef HASHBANG 470185029Spjd if (fd == -1 || 471185029Spjd pref[0] != '#' || pref[1] != '!' || hashbang(fd, &vp) == -1) { 472219089Spjd#endif /* HASHBANG */ 473185029Spjd /* 474185029Spjd * If there is an alias for shell, then put the words of the alias in 475249195Smm * front of the argument list replacing the command name. Note no 476185029Spjd * interpretation of the words at this point. 477185029Spjd */ 478185029Spjd v = adrof1(STRshell, &aliases); 479209962Smm if (v == NULL || v->vec == NULL) { 480209962Smm vp = lastsh; 481209962Smm vp[0] = adrof(STRshell) ? varval(STRshell) : STR_SHELLPATH; 482209962Smm vp[1] = NULL; 483209962Smm#ifdef _PATH_BSHELL 484185029Spjd if (fd != -1 485249195Smm# ifndef ISC /* Compatible with ISC's /bin/csh */ 486185029Spjd && pref[0] != '#' 487185029Spjd# endif /* ISC */ 488185029Spjd ) 489185029Spjd vp[0] = STR_BSHELL; 490185029Spjd#endif 491185029Spjd vp = saveblk(vp); 492185029Spjd } 493249195Smm else 494185029Spjd vp = saveblk(v->vec); 495185029Spjd#ifdef HASHBANG 496185029Spjd } 497185029Spjd#endif /* HASHBANG */ 498185029Spjd if (fd != -1) 499185029Spjd (void) close(fd); 500185029Spjd 501185029Spjd st0 = st[0]; 502236884Smm st[0] = sf; 503185029Spjd ost = st; 504185029Spjd st = blkspl(vp, st); /* Splice up the new arglst */ 505185029Spjd ost[0] = st0; 506185029Spjd sf = *st; 507185029Spjd /* The order for the conversions is significant */ 508185029Spjd t = short2blk(st); 509185029Spjd f = short2str(sf); 510185029Spjd xfree((ptr_t) st); 511219089Spjd blkfree((Char **) vp); 512185029Spjd#ifdef VFORK 513185029Spjd Vt = t; 514219089Spjd#endif /* VFORK */ 515219089Spjd#ifdef ISC_POSIX_EXEC_BUG 516219089Spjd __setostype(0); /* "0" is "__OS_SYSV" in <sys/user.h> */ 517249195Smm#endif /* ISC_POSIX_EXEC_BUG */ 518248571Smm (void) execv(f, t); 519248571Smm#ifdef ISC_POSIX_EXEC_BUG 520185029Spjd __setostype(1); /* "1" is "__OS_POSIX" in <sys/user.h> */ 521248571Smm#endif /* ISC_POSIX_EXEC_BUG */ 522185029Spjd#ifdef VFORK 523249195Smm Vt = 0; 524185029Spjd#endif /* VFORK */ 525185029Spjd blkfree((Char **) t); 526185029Spjd /* The sky is falling, the sky is falling! */ 527219089Spjd stderror(ERR_SYSTEM, f, strerror(errno)); 528185029Spjd break; 529185029Spjd 530185029Spjd case ENOMEM: 531185029Spjd stderror(ERR_SYSTEM, f, strerror(errno)); 532185029Spjd break; 533185029Spjd 534185029Spjd#ifdef _IBMR2 535249195Smm case 0: /* execv fails and returns 0! */ 536185029Spjd#endif /* _IBMR2 */ 537185029Spjd case ENOENT: 538185029Spjd break; 539185029Spjd 540185029Spjd default: 541185029Spjd if (exerr == 0) { 542185029Spjd exerr = strerror(errno); 543185029Spjd if (expath) 544185029Spjd xfree((ptr_t) expath); 545185029Spjd expath = Strsave(sf); 546185029Spjd#ifdef VFORK 547185029Spjd Vexpath = expath; 548185029Spjd#endif /* VFORK */ 549249195Smm } 550185029Spjd break; 551185029Spjd } 552185029Spjd} 553185029Spjd 554185029Spjd/*ARGSUSED*/ 555185029Spjdvoid 556185029Spjdexecash(t, kp) 557185029Spjd Char **t; 558185029Spjd struct command *kp; 559185029Spjd{ 560185029Spjd int saveIN, saveOUT, saveDIAG, saveSTD; 561185029Spjd int oSHIN; 562185029Spjd int oSHOUT; 563185029Spjd int oSHDIAG; 564249195Smm int oOLDSTD; 565185029Spjd jmp_buf_t osetexit; 566185029Spjd int my_reenter; 567185029Spjd int odidfds; 568185029Spjd#ifndef CLOSE_ON_EXEC 569185029Spjd int odidcch; 570185029Spjd#endif /* CLOSE_ON_EXEC */ 571185029Spjd signalfun_t osigint, osigquit, osigterm; 572185029Spjd 573249195Smm USE(t); 574185029Spjd if (chkstop == 0 && setintr) 575219089Spjd panystop(0); 576228103Smm /* 577228103Smm * Hmm, we don't really want to do that now because we might 578228103Smm * fail, but what is the choice 579228103Smm */ 580228103Smm rechist(NULL, adrof(STRsavehist) != NULL); 581228103Smm 582228103Smm 583228103Smm osigint = signal(SIGINT, parintr); 584228103Smm osigquit = signal(SIGQUIT, parintr); 585228103Smm osigterm = signal(SIGTERM, parterm); 586228103Smm 587249195Smm odidfds = didfds; 588228103Smm#ifndef CLOSE_ON_EXEC 589228103Smm odidcch = didcch; 590228103Smm#endif /* CLOSE_ON_EXEC */ 591228103Smm oSHIN = SHIN; 592228103Smm oSHOUT = SHOUT; 593228103Smm oSHDIAG = SHDIAG; 594228103Smm oOLDSTD = OLDSTD; 595228103Smm 596219089Spjd (void)close_on_exec (saveIN = dcopy(SHIN, -1), 1); 597219089Spjd (void)close_on_exec (saveOUT = dcopy(SHOUT, -1), 1); 598249195Smm (void)close_on_exec (saveDIAG = dcopy(SHDIAG, -1), 1); 599219089Spjd (void)close_on_exec (saveSTD = dcopy(OLDSTD, -1), 1); 600219089Spjd 601219089Spjd lshift(kp->t_dcom, 1); 602219089Spjd 603249195Smm getexit(osetexit); 604219089Spjd 605185029Spjd /* PWP: setjmp/longjmp bugfix for optimizing compilers */ 606185029Spjd#ifdef cray 607185029Spjd my_reenter = 1; /* assume non-zero return val */ 608185029Spjd if (setexit() == 0) { 609185029Spjd my_reenter = 0; /* Oh well, we were wrong */ 610185029Spjd#else /* !cray */ 611185029Spjd if ((my_reenter = setexit()) == 0) { 612185029Spjd#endif /* cray */ 613185029Spjd (void)close_on_exec (SHIN = dcopy(0, -1), 1); 614185029Spjd (void)close_on_exec (SHOUT = dcopy(1, -1), 1); 615185029Spjd (void)close_on_exec (SHDIAG = dcopy(2, -1), 1); 616185029Spjd#ifndef CLOSE_ON_EXEC 617185029Spjd didcch = 0; 618185029Spjd#endif /* CLOSE_ON_EXEC */ 619185029Spjd didfds = 0; 620185029Spjd /* 621185029Spjd * Decrement the shell level 622185029Spjd */ 623185029Spjd shlvl(-1); 624209962Smm#ifdef WINNT_NATIVE 625209962Smm __nt_really_exec=1; 626209962Smm#endif /* WINNT_NATIVE */ 627209962Smm doexec(kp, 1); 628209962Smm } 629209962Smm 630209962Smm (void) sigset(SIGINT, osigint); 631209962Smm (void) sigset(SIGQUIT, osigquit); 632209962Smm (void) sigset(SIGTERM, osigterm); 633209962Smm 634209962Smm doneinp = 0; 635209962Smm#ifndef CLOSE_ON_EXEC 636209962Smm didcch = odidcch; 637209962Smm#endif /* CLOSE_ON_EXEC */ 638209962Smm didfds = odidfds; 639209962Smm (void) close(SHIN); 640209962Smm (void) close(SHOUT); 641209962Smm (void) close(SHDIAG); 642209962Smm (void) close(OLDSTD); 643209962Smm (void)close_on_exec(SHIN = dmove(saveIN, oSHIN), 1); 644209962Smm (void)close_on_exec(SHOUT = dmove(saveOUT, oSHOUT), 1); 645209962Smm (void)close_on_exec(SHDIAG = dmove(saveDIAG, oSHDIAG), 1); 646209962Smm (void)close_on_exec(OLDSTD = dmove(saveSTD, oOLDSTD), 1); 647209962Smm 648209962Smm resexit(osetexit); 649185029Spjd if (my_reenter) 650185029Spjd stderror(ERR_SILENT); 651185029Spjd} 652185029Spjd 653236884Smmvoid 654209962Smmxechoit(t) 655185029Spjd Char **t; 656185029Spjd{ 657185029Spjd if (adrof(STRecho)) { 658185029Spjd int odidfds = didfds; 659209962Smm flush(); 660236884Smm haderr = 1; 661209962Smm didfds = 0; 662219089Spjd blkpr(t), xputchar('\n'); 663219089Spjd flush(); 664219089Spjd didfds = odidfds; 665209962Smm haderr = 0; 666209962Smm } 667236884Smm} 668236884Smm 669236884Smm/*ARGSUSED*/ 670236884Smmvoid 671236884Smmdohash(vv, c) 672236884Smm Char **vv; 673236884Smm struct command *c; 674236884Smm{ 675236884Smm#ifdef COMMENT 676236884Smm struct stat stb; 677236884Smm#endif 678236884Smm DIR *dirp; 679236884Smm struct dirent *dp; 680236884Smm int i = 0; 681236884Smm struct varent *v = adrof(STRpath); 682236884Smm Char **pv; 683236884Smm int hashval; 684236884Smm#ifdef WINNT_NATIVE 685236884Smm int is_windir; /* check if it is the windows directory */ 686236884Smm USE(hashval); 687236884Smm#endif /* WINNT_NATIVE */ 688248571Smm 689248571Smm USE(c); 690236884Smm#ifdef FASTHASH 691236884Smm if (vv && vv[1]) { 692236884Smm uhashlength = atoi(short2str(vv[1])); 693236884Smm if (vv[2]) { 694236884Smm uhashwidth = atoi(short2str(vv[2])); 695209962Smm if ((uhashwidth != sizeof(unsigned char)) && 696209962Smm (uhashwidth != sizeof(unsigned short)) && 697209962Smm (uhashwidth != sizeof(unsigned long))) 698209962Smm uhashwidth = 0; 699236884Smm if (vv[3]) 700248571Smm hashdebug = atoi(short2str(vv[3])); 701248571Smm } 702236884Smm } 703236884Smm 704236884Smm if (uhashwidth) 705185029Spjd hashwidth = uhashwidth; 706185029Spjd else { 707185029Spjd hashwidth = 0; 708185029Spjd if (v == NULL) 709185029Spjd return; 710185029Spjd for (pv = v->vec; pv && *pv; pv++, hashwidth++) 711185029Spjd continue; 712185029Spjd if (hashwidth <= widthof(unsigned char)) 713185029Spjd hashwidth = sizeof(unsigned char); 714185029Spjd else if (hashwidth <= widthof(unsigned short)) 715185029Spjd hashwidth = sizeof(unsigned short); 716185029Spjd else if (hashwidth <= widthof(unsigned int)) 717185029Spjd hashwidth = sizeof(unsigned int); 718185029Spjd else 719185029Spjd hashwidth = sizeof(unsigned long); 720185029Spjd } 721239620Smm 722239620Smm if (uhashlength) 723248571Smm hashlength = uhashlength; 724239620Smm else 725248571Smm hashlength = hashwidth * (8*64);/* "average" files per dir in path */ 726248571Smm 727239620Smm if (xhash) 728239620Smm xfree((ptr_t) xhash); 729239620Smm xhash = (unsigned long *) xcalloc((size_t) (hashlength * hashwidth), 730239620Smm (size_t) 1); 731239620Smm#endif /* FASTHASH */ 732239620Smm 733239620Smm (void) getusername(NULL); /* flush the tilde cashe */ 734239620Smm tw_cmd_free(); 735249195Smm havhash = 1; 736239620Smm if (v == NULL) 737239620Smm return; 738239620Smm for (pv = v->vec; pv && *pv; pv++, i++) { 739239620Smm if (!ABSOLUTEP(pv[0])) 740239620Smm continue; 741239620Smm dirp = opendir(short2str(*pv)); 742239620Smm if (dirp == NULL) 743248571Smm continue; 744239620Smm#ifdef COMMENT /* this isn't needed. opendir won't open 745248571Smm * non-dirs */ 746248571Smm if (fstat(dirp->dd_fd, &stb) < 0 || !S_ISDIR(stb.st_mode)) { 747239620Smm (void) closedir(dirp); 748239620Smm continue; 749239620Smm } 750239620Smm#endif 751239620Smm#ifdef WINNT_NATIVE 752239620Smm is_windir = nt_check_if_windir(short2str(*pv)); 753239620Smm#endif /* WINNT_NATIVE */ 754239620Smm while ((dp = readdir(dirp)) != NULL) { 755239620Smm if (dp->d_ino == 0) 756239620Smm continue; 757239620Smm if (dp->d_name[0] == '.' && 758248571Smm (dp->d_name[1] == '\0' || 759239620Smm (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) 760239620Smm continue; 761239620Smm#ifdef WINNT_NATIVE 762185029Spjd nt_check_name_and_hash(is_windir, dp->d_name, i); 763228103Smm#else /* !WINNT_NATIVE*/ 764228103Smm#if defined(_UWIN) || defined(__CYGWIN__) 765228103Smm /* Turn foo.{exe,com,bat} into foo since UWIN's readdir returns 766228103Smm * the file with the .exe, .com, .bat extension 767228103Smm */ 768228103Smm { 769228103Smm size_t ext = strlen(dp->d_name) - 4; 770228103Smm if ((ext > 0) && (strcasecmp(&dp->d_name[ext], ".exe") == 0 || 771228103Smm strcasecmp(&dp->d_name[ext], ".bat") == 0 || 772228103Smm strcasecmp(&dp->d_name[ext], ".com") == 0)) 773228103Smm { 774239620Smm dp->d_name[ext] = '\0'; 775239620Smm#if defined(__CYGWIN__) 776228103Smm strlwr(dp->d_name); 777254074Sdelphij#endif /* __CYGWIN__ */ 778239620Smm } 779239620Smm } 780228103Smm#endif /* _UWIN || __CYGWIN__ */ 781248571Smm# ifdef FASTHASH 782248571Smm hashval = hashname(str2short(dp->d_name)); 783228103Smm bis(hashval, i); 784239620Smm if (hashdebug & 1) 785239620Smm xprintf(CGETS(13, 1, "hash=%-4d dir=%-2d prog=%s\n"), 786239620Smm hashname(str2short(dp->d_name)), i, dp->d_name); 787239620Smm# else /* OLD HASH */ 788228103Smm hashval = hash(hashname(str2short(dp->d_name)), i); 789239620Smm bis(xhash, hashval); 790254074Sdelphij# endif /* FASTHASH */ 791228103Smm /* tw_add_comm_name (dp->d_name); */ 792239620Smm#endif /* WINNT_NATIVE */ 793228103Smm } 794228103Smm (void) closedir(dirp); 795228103Smm } 796185029Spjd} 797168404Spjd 798168404Spjd/*ARGSUSED*/ 799168404Spjdvoid 800168404Spjddounhash(v, c) 801168404Spjd Char **v; 802168404Spjd struct command *c; 803168404Spjd{ 804168404Spjd USE(c); 805168404Spjd USE(v); 806168404Spjd havhash = 0; 807168404Spjd#ifdef FASTHASH 808168404Spjd if (xhash) { 809168404Spjd xfree((ptr_t) xhash); 810168404Spjd xhash = NULL; 811168404Spjd } 812168404Spjd#endif /* FASTHASH */ 813168404Spjd} 814168404Spjd 815168404Spjd/*ARGSUSED*/ 816168404Spjdvoid 817168404Spjdhashstat(v, c) 818168404Spjd Char **v; 819168404Spjd struct command *c; 820168404Spjd{ 821168404Spjd USE(c); 822168404Spjd USE(v); 823168404Spjd#ifdef FASTHASH 824168404Spjd if (havhash && hashlength && hashwidth) 825168404Spjd xprintf(CGETS(13, 2, "%d hash buckets of %d bits each\n"), 826168404Spjd hashlength, hashwidth*8); 827168404Spjd if (hashdebug) 828168404Spjd xprintf(CGETS(13, 3, "debug mask = 0x%08x\n"), hashdebug); 829168404Spjd#endif /* FASTHASH */ 830168404Spjd#ifdef VFORK 831168404Spjd if (hits + misses) 832168404Spjd xprintf(CGETS(13, 4, "%d hits, %d misses, %d%%\n"), 833168404Spjd hits, misses, 100 * hits / (hits + misses)); 834168404Spjd#endif 835168404Spjd} 836168404Spjd 837168404Spjd 838168404Spjd/* 839258631Savg * Hash a command name. 840258631Savg */ 841168404Spjdint 842258631Savghashname(cp) 843258631Savg Char *cp; 844258631Savg{ 845258631Savg unsigned long h; 846258631Savg 847258631Savg for (h = 0; *cp; cp++) 848258630Savg h = hash(h, *cp); 849219089Spjd return ((int) h); 850168404Spjd} 851258631Savg 852258631Savgstatic int 853258631Savgiscommand(name) 854258631Savg Char *name; 855258631Savg{ 856168404Spjd Char **pv; 857258631Savg Char *sav; 858168404Spjd struct varent *v; 859258631Savg int slash = any(short2str(name), '/'); 860258631Savg int hashval, i; 861219089Spjd 862258631Savg v = adrof(STRpath); 863258631Savg if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash) 864219089Spjd pv = justabs; 865258631Savg else 866258631Savg pv = v->vec; 867258631Savg sav = Strspl(STRslash, name); /* / command name for postpending */ 868258631Savg hashval = havhash ? hashname(name) : 0; 869258631Savg i = 0; 870219089Spjd do { 871258631Savg if (!slash && ABSOLUTEP(pv[0]) && havhash) { 872258631Savg#ifdef FASTHASH 873258631Savg if (!bit(hashval, i)) 874258631Savg goto cont; 875258631Savg#else /* OLDHASH */ 876258631Savg int hashval1 = hash(hashval, i); 877258631Savg if (!bit(xhash, hashval1)) 878258631Savg goto cont; 879258631Savg#endif /* FASTHASH */ 880258631Savg } 881258631Savg if (pv[0][0] == 0 || eq(pv[0], STRdot)) { /* don't make ./xxx */ 882258631Savg if (executable(NULL, name, 0)) { 883258631Savg xfree((ptr_t) sav); 884258631Savg return i + 1; 885258631Savg } 886258631Savg } 887258631Savg else { 888258631Savg if (executable(*pv, sav, 0)) { 889258631Savg xfree((ptr_t) sav); 890258631Savg return i + 1; 891258631Savg } 892258631Savg } 893258631Savgcont: 894258631Savg pv++; 895258631Savg i++; 896219089Spjd } while (*pv); 897258631Savg xfree((ptr_t) sav); 898258631Savg return 0; 899258631Savg} 900219089Spjd 901258631Savg/* Also by: 902258631Savg * Andreas Luik <luik@isaak.isa.de> 903258631Savg * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 904258631Savg * Azenberstr. 35 905258631Savg * D-7000 Stuttgart 1 906258631Savg * West-Germany 907258631Savg * is the executable() routine below and changes to iscommand(). 908258631Savg * Thanks again!! 909258631Savg */ 910258631Savg 911258631Savg#ifndef WINNT_NATIVE 912219089Spjd/* 913219089Spjd * executable() examines the pathname obtained by concatenating dir and name 914219089Spjd * (dir may be NULL), and returns 1 either if it is executable by us, or 915219089Spjd * if dir_ok is set and the pathname refers to a directory. 916258631Savg * This is a bit kludgy, but in the name of optimization... 917258631Savg */ 918258631Savgint 919258631Savgexecutable(dir, name, dir_ok) 920258631Savg Char *dir, *name; 921258631Savg int dir_ok; 922258631Savg{ 923258631Savg struct stat stbuf; 924258631Savg Char path[MAXPATHLEN + 1]; 925258631Savg char *strname; 926258631Savg (void) memset(path, 0, sizeof(path)); 927258631Savg 928258631Savg if (dir && *dir) { 929258631Savg copyn(path, dir, MAXPATHLEN); 930258631Savg catn(path, name, MAXPATHLEN); 931258631Savg strname = short2str(path); 932258631Savg } 933258631Savg else 934258631Savg strname = short2str(name); 935258631Savg 936258631Savg return (stat(strname, &stbuf) != -1 && 937258631Savg ((dir_ok && S_ISDIR(stbuf.st_mode)) || 938258631Savg (S_ISREG(stbuf.st_mode) && 939258631Savg /* save time by not calling access() in the hopeless case */ 940258631Savg (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) && 941258631Savg access(strname, X_OK) == 0 942258631Savg ))); 943258631Savg} 944258631Savg#endif /*!WINNT_NATIVE*/ 945258631Savg 946258631Savgint 947258631Savgtellmewhat(lexp, str) 948258631Savg struct wordent *lexp; 949258631Savg Char *str; 950258631Savg{ 951258631Savg int i; 952258631Savg struct biltins *bptr; 953258631Savg struct wordent *sp = lexp->next; 954258631Savg int aliased = 0, found; 955258631Savg Char *s0, *s1, *s2, *cmd; 956258631Savg Char qc; 957258631Savg 958258631Savg if (adrof1(sp->word, &aliases)) { 959258631Savg alias(lexp); 960219089Spjd sp = lexp->next; 961219089Spjd aliased = 1; 962185029Spjd } 963185029Spjd 964258631Savg s0 = sp->word; /* to get the memory freeing right... */ 965219089Spjd 966219089Spjd /* handle quoted alias hack */ 967219089Spjd if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE) 968209962Smm (sp->word)++; 969219089Spjd 970219089Spjd /* do quoting, if it hasn't been done */ 971219089Spjd s1 = s2 = sp->word; 972219089Spjd while (*s2) 973219089Spjd switch (*s2) { 974219089Spjd case '\'': 975209962Smm case '"': 976219089Spjd qc = *s2++; 977219089Spjd while (*s2 && *s2 != qc) 978209962Smm *s1++ = *s2++ | QUOTE; 979219089Spjd if (*s2) 980219089Spjd s2++; 981209962Smm break; 982219089Spjd case '\\': 983219089Spjd if (*++s2) 984219089Spjd *s1++ = *s2++ | QUOTE; 985219089Spjd break; 986211931Smm default: 987219089Spjd *s1++ = *s2++; 988219089Spjd } 989219089Spjd *s1 = '\0'; 990219089Spjd 991219089Spjd for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) { 992219089Spjd if (eq(sp->word, str2short(bptr->bname))) { 993219089Spjd if (str == NULL) { 994219089Spjd if (aliased) 995219089Spjd prlex(lexp); 996219089Spjd xprintf(CGETS(13, 5, "%S: shell built-in command.\n"), 997219089Spjd sp->word); 998219089Spjd flush(); 999219089Spjd } 1000219089Spjd else 1001219089Spjd (void) Strcpy(str, sp->word); 1002219089Spjd sp->word = s0; /* we save and then restore this */ 1003219089Spjd return TRUE; 1004219089Spjd } 1005219089Spjd } 1006219089Spjd#ifdef WINNT_NATIVE 1007219089Spjd for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) { 1008219089Spjd if (eq(sp->word, str2short(bptr->bname))) { 1009219089Spjd if (str == NULL) { 1010219089Spjd if (aliased) 1011219089Spjd prlex(lexp); 1012219089Spjd xprintf(CGETS(13, 5, "%S: shell built-in command.\n"), 1013219089Spjd sp->word); 1014219089Spjd flush(); 1015219089Spjd } 1016219089Spjd else 1017219089Spjd (void) Strcpy(str, sp->word); 1018219089Spjd sp->word = s0; /* we save and then restore this */ 1019219089Spjd return TRUE; 1020219089Spjd } 1021219089Spjd } 1022219089Spjd#endif /* WINNT_NATIVE*/ 1023219089Spjd 1024219089Spjd sp->word = cmd = globone(sp->word, G_IGNORE); 1025219089Spjd 1026219089Spjd if ((i = iscommand(sp->word)) != 0) { 1027219089Spjd Char **pv; 1028219089Spjd struct varent *v; 1029219089Spjd int slash = any(short2str(sp->word), '/'); 1030219089Spjd 1031219089Spjd v = adrof(STRpath); 1032219089Spjd if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash) 1033219089Spjd pv = justabs; 1034219089Spjd else 1035219089Spjd pv = v->vec; 1036219089Spjd 1037219089Spjd while (--i) 1038219089Spjd pv++; 1039219089Spjd if (pv[0][0] == 0 || eq(pv[0], STRdot)) { 1040219089Spjd if (!slash) { 1041219089Spjd sp->word = Strspl(STRdotsl, sp->word); 1042219089Spjd prlex(lexp); 1043219089Spjd xfree((ptr_t) sp->word); 1044219089Spjd } 1045219089Spjd else 1046219089Spjd prlex(lexp); 1047219089Spjd } 1048219089Spjd else { 1049219089Spjd s1 = Strspl(*pv, STRslash); 1050219089Spjd sp->word = Strspl(s1, sp->word); 1051219089Spjd xfree((ptr_t) s1); 1052219089Spjd if (str == NULL) 1053219089Spjd prlex(lexp); 1054219089Spjd else 1055219089Spjd (void) Strcpy(str, sp->word); 1056219089Spjd xfree((ptr_t) sp->word); 1057219089Spjd } 1058219089Spjd found = 1; 1059219089Spjd } 1060219089Spjd else { 1061219089Spjd if (str == NULL) { 1062219089Spjd if (aliased) 1063219089Spjd prlex(lexp); 1064219089Spjd xprintf(CGETS(13, 6, "%S: Command not found.\n"), sp->word); 1065219089Spjd flush(); 1066219089Spjd } 1067219089Spjd else 1068219089Spjd (void) Strcpy(str, sp->word); 1069219089Spjd found = 0; 1070219089Spjd } 1071219089Spjd sp->word = s0; /* we save and then restore this */ 1072219089Spjd xfree((ptr_t) cmd); 1073219089Spjd return found; 1074209962Smm} 1075219089Spjd 1076219089Spjd/* 1077219089Spjd * Builtin to look at and list all places a command may be defined: 1078219089Spjd * aliases, shell builtins, and the path. 1079219089Spjd * 1080219089Spjd * Marc Horowitz <marc@mit.edu> 1081219089Spjd * MIT Student Information Processing Board 1082219089Spjd */ 1083219089Spjd 1084185029Spjd/*ARGSUSED*/ 1085168404Spjdvoid 1086219089Spjddowhere(v, c) 1087219089Spjd Char **v; 1088168404Spjd struct command *c; 1089219089Spjd{ 1090219089Spjd int found = 1; 1091219089Spjd USE(c); 1092219089Spjd for (v++; *v; v++) 1093219089Spjd found &= find_cmd(*v, 1); 1094219089Spjd /* Make status nonzero if any command is not found. */ 1095240868Spjd if (!found) 1096240868Spjd set(STRstatus, Strsave(STR1), VAR_READWRITE); 1097240868Spjd} 1098240868Spjd 1099240868Spjdint 1100185029Spjdfind_cmd(cmd, prt) 1101185029Spjd Char *cmd; 1102185029Spjd int prt; 1103185029Spjd{ 1104168404Spjd struct varent *var; 1105168404Spjd struct biltins *bptr; 1106168404Spjd Char **pv; 1107168404Spjd Char *sv; 1108168404Spjd int hashval, i, ex, rval = 0; 1109168404Spjd 1110168404Spjd if (prt && any(short2str(cmd), '/')) { 1111168404Spjd xprintf(CGETS(13, 7, "where: / in command makes no sense\n")); 1112168404Spjd return rval; 1113168404Spjd } 1114168404Spjd 1115168404Spjd /* first, look for an alias */ 1116168404Spjd 1117168404Spjd if (prt && adrof1(cmd, &aliases)) { 1118168404Spjd if ((var = adrof1(cmd, &aliases)) != NULL) { 1119168404Spjd xprintf(CGETS(13, 8, "%S is aliased to "), cmd); 1120168404Spjd if (var->vec != NULL) 1121168404Spjd blkpr(var->vec); 1122168404Spjd xputchar('\n'); 1123168404Spjd rval = 1; 1124168404Spjd } 1125209962Smm } 1126168404Spjd 1127168404Spjd /* next, look for a shell builtin */ 1128240868Spjd 1129240868Spjd for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) { 1130240868Spjd if (eq(cmd, str2short(bptr->bname))) { 1131240868Spjd rval = 1; 1132240868Spjd if (prt) 1133240868Spjd xprintf(CGETS(13, 9, "%S is a shell built-in\n"), cmd); 1134168404Spjd else 1135168404Spjd return rval; 1136185029Spjd } 1137185029Spjd } 1138168404Spjd#ifdef WINNT_NATIVE 1139185029Spjd for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) { 1140185029Spjd if (eq(cmd, str2short(bptr->bname))) { 1141258631Savg rval = 1; 1142185029Spjd if (prt) 1143168404Spjd xprintf(CGETS(13, 9, "%S is a shell built-in\n"), cmd); 1144168404Spjd else 1145168404Spjd return rval; 1146168404Spjd } 1147168404Spjd } 1148185029Spjd#endif /* WINNT_NATIVE*/ 1149185029Spjd 1150185029Spjd /* last, look through the path for the command */ 1151168404Spjd 1152168404Spjd if ((var = adrof(STRpath)) == NULL) 1153168404Spjd return rval; 1154168404Spjd 1155168404Spjd hashval = havhash ? hashname(cmd) : 0; 1156168404Spjd 1157168404Spjd sv = Strspl(STRslash, cmd); 1158168404Spjd 1159168404Spjd for (pv = var->vec, i = 0; pv && *pv; pv++, i++) { 1160168404Spjd if (havhash && !eq(*pv, STRdot)) { 1161219089Spjd#ifdef FASTHASH 1162219089Spjd if (!bit(hashval, i)) 1163219089Spjd continue; 1164219089Spjd#else /* OLDHASH */ 1165219089Spjd int hashval1 = hash(hashval, i); 1166219089Spjd if (!bit(xhash, hashval1)) 1167219089Spjd continue; 1168219089Spjd#endif /* FASTHASH */ 1169219089Spjd } 1170219089Spjd ex = executable(*pv, sv, 0); 1171219089Spjd#ifdef FASTHASH 1172219089Spjd if (!ex && (hashdebug & 2)) { 1173219089Spjd xprintf(CGETS(13, 10, "hash miss: ")); 1174219089Spjd ex = 1; /* Force printing */ 1175219089Spjd } 1176219089Spjd#endif /* FASTHASH */ 1177219089Spjd if (ex) { 1178219089Spjd rval = 1; 1179219089Spjd if (prt) { 1180219089Spjd xprintf("%S/", *pv); 1181219089Spjd xprintf("%S\n", cmd); 1182219089Spjd } 1183219089Spjd else 1184219089Spjd return rval; 1185219089Spjd } 1186219089Spjd } 1187219089Spjd xfree((ptr_t) sv); 1188168404Spjd return rval; 1189168404Spjd} 1190168404Spjd#ifdef WINNT_NATIVE 1191168404Spjdint hashval_extern(cp) 1192168404Spjd Char *cp; 1193168404Spjd{ 1194168404Spjd return havhash?hashname(cp):0; 1195168404Spjd} 1196168404Spjdint bit_extern(val,i) 1197168404Spjd int val; 1198168404Spjd int i; 1199168404Spjd{ 1200168404Spjd return bit(val,i); 1201219089Spjd} 1202168404Spjdvoid bis_extern(val,i) 1203168404Spjd int val; 1204168404Spjd int i; 1205168404Spjd{ 1206168404Spjd bis(val,i); 1207168404Spjd} 1208168404Spjd#endif /* WINNT_NATIVE */ 1209168404Spjd 1210185029Spjd