/contrib/tcsh/sh.exec.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1196 lines · 950 code · 80 blank · 166 comment · 172 complexity · 346f5a20ecad41329829684c5bc97ae3 MD5 · raw file

  1. /* $Header: /p/tcsh/cvsroot/tcsh/sh.exec.c,v 3.79 2011/02/25 23:58:34 christos Exp $ */
  2. /*
  3. * sh.exec.c: Search, find, and execute a command!
  4. */
  5. /*-
  6. * Copyright (c) 1980, 1991 The Regents of the University of California.
  7. * All rights reserved.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. * 3. Neither the name of the University nor the names of its contributors
  18. * may be used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. */
  33. #include "sh.h"
  34. RCSID("$tcsh: sh.exec.c,v 3.79 2011/02/25 23:58:34 christos Exp $")
  35. #include "tc.h"
  36. #include "tw.h"
  37. #ifdef WINNT_NATIVE
  38. #include <nt.const.h>
  39. #endif /*WINNT_NATIVE*/
  40. /*
  41. * C shell
  42. */
  43. #ifndef OLDHASH
  44. # define FASTHASH /* Fast hashing is the default */
  45. #endif /* OLDHASH */
  46. /*
  47. * System level search and execute of a command.
  48. * We look in each directory for the specified command name.
  49. * If the name contains a '/' then we execute only the full path name.
  50. * If there is no search path then we execute only full path names.
  51. */
  52. /*
  53. * As we search for the command we note the first non-trivial error
  54. * message for presentation to the user. This allows us often
  55. * to show that a file has the wrong mode/no access when the file
  56. * is not in the last component of the search path, so we must
  57. * go on after first detecting the error.
  58. */
  59. static char *exerr; /* Execution error message */
  60. static Char *expath; /* Path for exerr */
  61. /*
  62. * The two part hash function is designed to let texec() call the
  63. * more expensive hashname() only once and the simple hash() several
  64. * times (once for each path component checked).
  65. * Byte size is assumed to be 8.
  66. */
  67. #define BITS_PER_BYTE 8
  68. #ifdef FASTHASH
  69. /*
  70. * xhash is an array of hash buckets which are used to hash execs. If
  71. * it is allocated (havhash true), then to tell if ``name'' is
  72. * (possibly) present in the i'th component of the variable path, look
  73. * at the [hashname(name)] bucket of size [hashwidth] bytes, in the [i
  74. * mod size*8]'th bit. The cache size is defaults to a length of 1024
  75. * buckets, each 1 byte wide. This implementation guarantees that
  76. * objects n bytes wide will be aligned on n byte boundaries.
  77. */
  78. # define HSHMUL 241
  79. static unsigned long *xhash = NULL;
  80. static unsigned int hashlength = 0, uhashlength = 0;
  81. static unsigned int hashwidth = 0, uhashwidth = 0;
  82. static int hashdebug = 0;
  83. # define hash(a, b) (((a) * HSHMUL + (b)) % (hashlength))
  84. # define widthof(t) (sizeof(t) * BITS_PER_BYTE)
  85. # define tbit(f, i, t) (((t *) xhash)[(f)] & \
  86. (1UL << (i & (widthof(t) - 1))))
  87. # define tbis(f, i, t) (((t *) xhash)[(f)] |= \
  88. (1UL << (i & (widthof(t) - 1))))
  89. # define cbit(f, i) tbit(f, i, unsigned char)
  90. # define cbis(f, i) tbis(f, i, unsigned char)
  91. # define sbit(f, i) tbit(f, i, unsigned short)
  92. # define sbis(f, i) tbis(f, i, unsigned short)
  93. # define ibit(f, i) tbit(f, i, unsigned int)
  94. # define ibis(f, i) tbis(f, i, unsigned int)
  95. # define lbit(f, i) tbit(f, i, unsigned long)
  96. # define lbis(f, i) tbis(f, i, unsigned long)
  97. # define bit(f, i) (hashwidth==sizeof(unsigned char) ? cbit(f,i) : \
  98. ((hashwidth==sizeof(unsigned short) ? sbit(f,i) : \
  99. ((hashwidth==sizeof(unsigned int) ? ibit(f,i) : \
  100. lbit(f,i))))))
  101. # define bis(f, i) (hashwidth==sizeof(unsigned char) ? cbis(f,i) : \
  102. ((hashwidth==sizeof(unsigned short) ? sbis(f,i) : \
  103. ((hashwidth==sizeof(unsigned int) ? ibis(f,i) : \
  104. lbis(f,i))))))
  105. #else /* OLDHASH */
  106. /*
  107. * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used
  108. * to hash execs. If it is allocated (havhash true), then to tell
  109. * whether ``name'' is (possibly) present in the i'th component
  110. * of the variable path, you look at the bit in xhash indexed by
  111. * hash(hashname("name"), i). This is setup automatically
  112. * after .login is executed, and recomputed whenever ``path'' is
  113. * changed.
  114. */
  115. # define HSHSIZ 8192 /* 1k bytes */
  116. # define HSHMASK (HSHSIZ - 1)
  117. # define HSHMUL 243
  118. static char xhash[HSHSIZ / BITS_PER_BYTE];
  119. # define hash(a, b) (((a) * HSHMUL + (b)) & HSHMASK)
  120. # define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */
  121. # define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */
  122. #endif /* FASTHASH */
  123. #ifdef VFORK
  124. static int hits, misses;
  125. #endif /* VFORK */
  126. /* Dummy search path for just absolute search when no path */
  127. static Char *justabs[] = {STRNULL, 0};
  128. static void pexerr (void) __attribute__((__noreturn__));
  129. static void texec (Char *, Char **);
  130. int hashname (Char *);
  131. static int iscommand (Char *);
  132. void
  133. doexec(struct command *t, int do_glob)
  134. {
  135. Char *dp, **pv, **opv, **av, *sav;
  136. struct varent *v;
  137. int slash, gflag, rehashed;
  138. int hashval, i;
  139. Char *blk[2];
  140. /*
  141. * Glob the command name. We will search $path even if this does something,
  142. * as in sh but not in csh. One special case: if there is no PATH, then we
  143. * execute only commands which start with '/'.
  144. */
  145. blk[0] = t->t_dcom[0];
  146. blk[1] = 0;
  147. gflag = 0;
  148. if (do_glob)
  149. gflag = tglob(blk);
  150. if (gflag) {
  151. pv = globall(blk, gflag);
  152. if (pv == 0) {
  153. setname(short2str(blk[0]));
  154. stderror(ERR_NAME | ERR_NOMATCH);
  155. }
  156. }
  157. else
  158. pv = saveblk(blk);
  159. cleanup_push(pv, blk_cleanup);
  160. trim(pv);
  161. exerr = 0;
  162. expath = Strsave(pv[0]);
  163. #ifdef VFORK
  164. Vexpath = expath;
  165. #endif /* VFORK */
  166. v = adrof(STRpath);
  167. if (v == 0 && expath[0] != '/' && expath[0] != '.')
  168. pexerr();
  169. slash = any(short2str(expath), '/');
  170. /*
  171. * Glob the argument list, if necessary. Otherwise trim off the quote bits.
  172. */
  173. gflag = 0;
  174. av = &t->t_dcom[1];
  175. if (do_glob)
  176. gflag = tglob(av);
  177. if (gflag) {
  178. av = globall(av, gflag);
  179. if (av == 0) {
  180. setname(short2str(expath));
  181. stderror(ERR_NAME | ERR_NOMATCH);
  182. }
  183. }
  184. else
  185. av = saveblk(av);
  186. blkfree(t->t_dcom);
  187. cleanup_ignore(pv);
  188. cleanup_until(pv);
  189. t->t_dcom = blkspl(pv, av);
  190. xfree(pv);
  191. xfree(av);
  192. av = t->t_dcom;
  193. trim(av);
  194. if (*av == NULL || **av == '\0')
  195. pexerr();
  196. xechoit(av); /* Echo command if -x */
  197. #ifdef CLOSE_ON_EXEC
  198. /*
  199. * Since all internal file descriptors are set to close on exec, we don't
  200. * need to close them explicitly here. Just reorient ourselves for error
  201. * messages.
  202. */
  203. SHIN = 0;
  204. SHOUT = 1;
  205. SHDIAG = 2;
  206. OLDSTD = 0;
  207. isoutatty = isatty(SHOUT);
  208. isdiagatty = isatty(SHDIAG);
  209. #else
  210. closech(); /* Close random fd's */
  211. #endif
  212. /*
  213. * We must do this AFTER any possible forking (like `foo` in glob) so that
  214. * this shell can still do subprocesses.
  215. */
  216. {
  217. sigset_t set;
  218. sigemptyset(&set);
  219. sigaddset(&set, SIGINT);
  220. sigaddset(&set, SIGCHLD);
  221. sigprocmask(SIG_UNBLOCK, &set, NULL);
  222. }
  223. pintr_disabled = 0;
  224. pchild_disabled = 0;
  225. /*
  226. * If no path, no words in path, or a / in the filename then restrict the
  227. * command search.
  228. */
  229. if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash)
  230. opv = justabs;
  231. else
  232. opv = v->vec;
  233. sav = Strspl(STRslash, *av);/* / command name for postpending */
  234. #ifndef VFORK
  235. cleanup_push(sav, xfree);
  236. #else /* VFORK */
  237. Vsav = sav;
  238. #endif /* VFORK */
  239. hashval = havhash ? hashname(*av) : 0;
  240. rehashed = 0;
  241. retry:
  242. pv = opv;
  243. i = 0;
  244. #ifdef VFORK
  245. hits++;
  246. #endif /* VFORK */
  247. do {
  248. /*
  249. * Try to save time by looking at the hash table for where this command
  250. * could be. If we are doing delayed hashing, then we put the names in
  251. * one at a time, as the user enters them. This is kinda like Korn
  252. * Shell's "tracked aliases".
  253. */
  254. if (!slash && ABSOLUTEP(pv[0]) && havhash) {
  255. #ifdef FASTHASH
  256. if (!bit(hashval, i))
  257. goto cont;
  258. #else /* OLDHASH */
  259. int hashval1 = hash(hashval, i);
  260. if (!bit(xhash, hashval1))
  261. goto cont;
  262. #endif /* FASTHASH */
  263. }
  264. if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */
  265. texec(*av, av);
  266. else {
  267. dp = Strspl(*pv, sav);
  268. #ifndef VFORK
  269. cleanup_push(dp, xfree);
  270. #else /* VFORK */
  271. Vdp = dp;
  272. #endif /* VFORK */
  273. texec(dp, av);
  274. #ifndef VFORK
  275. cleanup_until(dp);
  276. #else /* VFORK */
  277. Vdp = 0;
  278. xfree(dp);
  279. #endif /* VFORK */
  280. }
  281. #ifdef VFORK
  282. misses++;
  283. #endif /* VFORK */
  284. cont:
  285. pv++;
  286. i++;
  287. } while (*pv);
  288. #ifdef VFORK
  289. hits--;
  290. #endif /* VFORK */
  291. if (adrof(STRautorehash) && !rehashed && havhash && opv != justabs) {
  292. dohash(NULL, NULL);
  293. rehashed = 1;
  294. goto retry;
  295. }
  296. #ifndef VFORK
  297. cleanup_until(sav);
  298. #else /* VFORK */
  299. Vsav = 0;
  300. xfree(sav);
  301. #endif /* VFORK */
  302. pexerr();
  303. }
  304. static void
  305. pexerr(void)
  306. {
  307. /* Couldn't find the damn thing */
  308. if (expath) {
  309. setname(short2str(expath));
  310. #ifdef VFORK
  311. Vexpath = 0;
  312. #endif /* VFORK */
  313. xfree(expath);
  314. expath = 0;
  315. }
  316. else
  317. setname("");
  318. if (exerr)
  319. stderror(ERR_NAME | ERR_STRING, exerr);
  320. stderror(ERR_NAME | ERR_COMMAND);
  321. }
  322. /*
  323. * Execute command f, arg list t.
  324. * Record error message if not found.
  325. * Also do shell scripts here.
  326. */
  327. static void
  328. texec(Char *sf, Char **st)
  329. {
  330. char **t;
  331. char *f;
  332. struct varent *v;
  333. Char **vp;
  334. Char *lastsh[2];
  335. char pref[2];
  336. int fd;
  337. Char *st0, **ost;
  338. /* The order for the conversions is significant */
  339. t = short2blk(st);
  340. f = short2str(sf);
  341. #ifdef VFORK
  342. Vt = t;
  343. #endif /* VFORK */
  344. errno = 0; /* don't use a previous error */
  345. #ifdef apollo
  346. /*
  347. * If we try to execute an nfs mounted directory on the apollo, we
  348. * hang forever. So until apollo fixes that..
  349. */
  350. {
  351. struct stat stb;
  352. if (stat(f, &stb) == 0 && S_ISDIR(stb.st_mode))
  353. errno = EISDIR;
  354. }
  355. if (errno == 0)
  356. #endif /* apollo */
  357. {
  358. #ifdef ISC_POSIX_EXEC_BUG
  359. __setostype(0); /* "0" is "__OS_SYSV" in <sys/user.h> */
  360. #endif /* ISC_POSIX_EXEC_BUG */
  361. (void) execv(f, t);
  362. #ifdef ISC_POSIX_EXEC_BUG
  363. __setostype(1); /* "1" is "__OS_POSIX" in <sys/user.h> */
  364. #endif /* ISC_POSIX_EXEC_BUG */
  365. }
  366. #ifdef VFORK
  367. Vt = 0;
  368. #endif /* VFORK */
  369. blkfree((Char **) t);
  370. switch (errno) {
  371. case ENOEXEC:
  372. #ifdef WINNT_NATIVE
  373. nt_feed_to_cmd(f,t);
  374. #endif /* WINNT_NATIVE */
  375. /*
  376. * From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute
  377. * it, don't feed it to the shell if it looks like a binary!
  378. */
  379. if ((fd = xopen(f, O_RDONLY|O_LARGEFILE)) != -1) {
  380. int nread;
  381. if ((nread = xread(fd, pref, 2)) == 2) {
  382. if (!isprint((unsigned char)pref[0]) &&
  383. (pref[0] != '\n' && pref[0] != '\t')) {
  384. int err;
  385. err = errno;
  386. xclose(fd);
  387. /*
  388. * We *know* what ENOEXEC means.
  389. */
  390. stderror(ERR_ARCH, f, strerror(err));
  391. }
  392. }
  393. else if (nread < 0) {
  394. #ifdef convex
  395. int err;
  396. err = errno;
  397. xclose(fd);
  398. /* need to print error incase the file is migrated */
  399. stderror(ERR_SYSTEM, f, strerror(err));
  400. #endif
  401. }
  402. #ifdef _PATH_BSHELL
  403. else {
  404. pref[0] = '#';
  405. pref[1] = '\0';
  406. }
  407. #endif
  408. }
  409. #ifdef HASHBANG
  410. if (fd == -1 ||
  411. pref[0] != '#' || pref[1] != '!' || hashbang(fd, &vp) == -1) {
  412. #endif /* HASHBANG */
  413. /*
  414. * If there is an alias for shell, then put the words of the alias in
  415. * front of the argument list replacing the command name. Note no
  416. * interpretation of the words at this point.
  417. */
  418. v = adrof1(STRshell, &aliases);
  419. if (v == NULL || v->vec == NULL) {
  420. vp = lastsh;
  421. vp[0] = adrof(STRshell) ? varval(STRshell) : STR_SHELLPATH;
  422. vp[1] = NULL;
  423. #ifdef _PATH_BSHELL
  424. if (fd != -1
  425. # ifndef ISC /* Compatible with ISC's /bin/csh */
  426. && pref[0] != '#'
  427. # endif /* ISC */
  428. )
  429. vp[0] = STR_BSHELL;
  430. #endif
  431. vp = saveblk(vp);
  432. }
  433. else
  434. vp = saveblk(v->vec);
  435. #ifdef HASHBANG
  436. }
  437. #endif /* HASHBANG */
  438. if (fd != -1)
  439. xclose(fd);
  440. st0 = st[0];
  441. st[0] = sf;
  442. ost = st;
  443. st = blkspl(vp, st); /* Splice up the new arglst */
  444. ost[0] = st0;
  445. sf = *st;
  446. /* The order for the conversions is significant */
  447. t = short2blk(st);
  448. f = short2str(sf);
  449. xfree(st);
  450. blkfree((Char **) vp);
  451. #ifdef VFORK
  452. Vt = t;
  453. #endif /* VFORK */
  454. #ifdef ISC_POSIX_EXEC_BUG
  455. __setostype(0); /* "0" is "__OS_SYSV" in <sys/user.h> */
  456. #endif /* ISC_POSIX_EXEC_BUG */
  457. (void) execv(f, t);
  458. #ifdef ISC_POSIX_EXEC_BUG
  459. __setostype(1); /* "1" is "__OS_POSIX" in <sys/user.h> */
  460. #endif /* ISC_POSIX_EXEC_BUG */
  461. #ifdef VFORK
  462. Vt = 0;
  463. #endif /* VFORK */
  464. blkfree((Char **) t);
  465. /* The sky is falling, the sky is falling! */
  466. stderror(ERR_SYSTEM, f, strerror(errno));
  467. break;
  468. case ENOMEM:
  469. stderror(ERR_SYSTEM, f, strerror(errno));
  470. break;
  471. #ifdef _IBMR2
  472. case 0: /* execv fails and returns 0! */
  473. #endif /* _IBMR2 */
  474. case ENOENT:
  475. break;
  476. default:
  477. if (exerr == 0) {
  478. exerr = strerror(errno);
  479. xfree(expath);
  480. expath = Strsave(sf);
  481. #ifdef VFORK
  482. Vexpath = expath;
  483. #endif /* VFORK */
  484. }
  485. break;
  486. }
  487. }
  488. struct execash_state
  489. {
  490. int saveIN, saveOUT, saveDIAG, saveSTD;
  491. int SHIN, SHOUT, SHDIAG, OLDSTD;
  492. int didfds;
  493. #ifndef CLOSE_ON_EXEC
  494. int didcch;
  495. #endif
  496. struct sigaction sigint, sigquit, sigterm;
  497. };
  498. static void
  499. execash_cleanup(void *xstate)
  500. {
  501. struct execash_state *state;
  502. state = xstate;
  503. sigaction(SIGINT, &state->sigint, NULL);
  504. sigaction(SIGQUIT, &state->sigquit, NULL);
  505. sigaction(SIGTERM, &state->sigterm, NULL);
  506. doneinp = 0;
  507. #ifndef CLOSE_ON_EXEC
  508. didcch = state->didcch;
  509. #endif /* CLOSE_ON_EXEC */
  510. didfds = state->didfds;
  511. xclose(SHIN);
  512. xclose(SHOUT);
  513. xclose(SHDIAG);
  514. xclose(OLDSTD);
  515. close_on_exec(SHIN = dmove(state->saveIN, state->SHIN), 1);
  516. close_on_exec(SHOUT = dmove(state->saveOUT, state->SHOUT), 1);
  517. close_on_exec(SHDIAG = dmove(state->saveDIAG, state->SHDIAG), 1);
  518. close_on_exec(OLDSTD = dmove(state->saveSTD, state->OLDSTD), 1);
  519. }
  520. /*ARGSUSED*/
  521. void
  522. execash(Char **t, struct command *kp)
  523. {
  524. struct execash_state state;
  525. USE(t);
  526. if (chkstop == 0 && setintr)
  527. panystop(0);
  528. /*
  529. * Hmm, we don't really want to do that now because we might
  530. * fail, but what is the choice
  531. */
  532. rechist(NULL, adrof(STRsavehist) != NULL);
  533. sigaction(SIGINT, &parintr, &state.sigint);
  534. sigaction(SIGQUIT, &parintr, &state.sigquit);
  535. sigaction(SIGTERM, &parterm, &state.sigterm);
  536. state.didfds = didfds;
  537. #ifndef CLOSE_ON_EXEC
  538. state.didcch = didcch;
  539. #endif /* CLOSE_ON_EXEC */
  540. state.SHIN = SHIN;
  541. state.SHOUT = SHOUT;
  542. state.SHDIAG = SHDIAG;
  543. state.OLDSTD = OLDSTD;
  544. (void)close_on_exec (state.saveIN = dcopy(SHIN, -1), 1);
  545. (void)close_on_exec (state.saveOUT = dcopy(SHOUT, -1), 1);
  546. (void)close_on_exec (state.saveDIAG = dcopy(SHDIAG, -1), 1);
  547. (void)close_on_exec (state.saveSTD = dcopy(OLDSTD, -1), 1);
  548. lshift(kp->t_dcom, 1);
  549. (void)close_on_exec (SHIN = dcopy(0, -1), 1);
  550. (void)close_on_exec (SHOUT = dcopy(1, -1), 1);
  551. (void)close_on_exec (SHDIAG = dcopy(2, -1), 1);
  552. #ifndef CLOSE_ON_EXEC
  553. didcch = 0;
  554. #endif /* CLOSE_ON_EXEC */
  555. didfds = 0;
  556. cleanup_push(&state, execash_cleanup);
  557. /*
  558. * Decrement the shell level
  559. */
  560. shlvl(-1);
  561. #ifdef WINNT_NATIVE
  562. __nt_really_exec=1;
  563. #endif /* WINNT_NATIVE */
  564. doexec(kp, 1);
  565. cleanup_until(&state);
  566. }
  567. void
  568. xechoit(Char **t)
  569. {
  570. if (adrof(STRecho)) {
  571. int odidfds = didfds;
  572. flush();
  573. haderr = 1;
  574. didfds = 0;
  575. blkpr(t), xputchar('\n');
  576. flush();
  577. didfds = odidfds;
  578. haderr = 0;
  579. }
  580. }
  581. /*ARGSUSED*/
  582. void
  583. dohash(Char **vv, struct command *c)
  584. {
  585. #ifdef COMMENT
  586. struct stat stb;
  587. #endif
  588. DIR *dirp;
  589. struct dirent *dp;
  590. int i = 0;
  591. struct varent *v = adrof(STRpath);
  592. Char **pv;
  593. int hashval;
  594. #ifdef WINNT_NATIVE
  595. int is_windir; /* check if it is the windows directory */
  596. USE(hashval);
  597. #endif /* WINNT_NATIVE */
  598. USE(c);
  599. #ifdef FASTHASH
  600. if (vv && vv[1]) {
  601. uhashlength = atoi(short2str(vv[1]));
  602. if (vv[2]) {
  603. uhashwidth = atoi(short2str(vv[2]));
  604. if ((uhashwidth != sizeof(unsigned char)) &&
  605. (uhashwidth != sizeof(unsigned short)) &&
  606. (uhashwidth != sizeof(unsigned long)))
  607. uhashwidth = 0;
  608. if (vv[3])
  609. hashdebug = atoi(short2str(vv[3]));
  610. }
  611. }
  612. if (uhashwidth)
  613. hashwidth = uhashwidth;
  614. else {
  615. hashwidth = 0;
  616. if (v == NULL)
  617. return;
  618. for (pv = v->vec; pv && *pv; pv++, hashwidth++)
  619. continue;
  620. if (hashwidth <= widthof(unsigned char))
  621. hashwidth = sizeof(unsigned char);
  622. else if (hashwidth <= widthof(unsigned short))
  623. hashwidth = sizeof(unsigned short);
  624. else if (hashwidth <= widthof(unsigned int))
  625. hashwidth = sizeof(unsigned int);
  626. else
  627. hashwidth = sizeof(unsigned long);
  628. }
  629. if (uhashlength)
  630. hashlength = uhashlength;
  631. else
  632. hashlength = hashwidth * (8*64);/* "average" files per dir in path */
  633. xfree(xhash);
  634. xhash = xcalloc(hashlength * hashwidth, 1);
  635. #endif /* FASTHASH */
  636. (void) getusername(NULL); /* flush the tilde cashe */
  637. tw_cmd_free();
  638. havhash = 1;
  639. if (v == NULL)
  640. return;
  641. for (pv = v->vec; pv && *pv; pv++, i++) {
  642. if (!ABSOLUTEP(pv[0]))
  643. continue;
  644. dirp = opendir(short2str(*pv));
  645. if (dirp == NULL)
  646. continue;
  647. cleanup_push(dirp, opendir_cleanup);
  648. #ifdef COMMENT /* this isn't needed. opendir won't open
  649. * non-dirs */
  650. if (fstat(dirp->dd_fd, &stb) < 0 || !S_ISDIR(stb.st_mode)) {
  651. cleanup_until(dirp);
  652. continue;
  653. }
  654. #endif
  655. #ifdef WINNT_NATIVE
  656. is_windir = nt_check_if_windir(short2str(*pv));
  657. #endif /* WINNT_NATIVE */
  658. while ((dp = readdir(dirp)) != NULL) {
  659. if (dp->d_ino == 0)
  660. continue;
  661. if (dp->d_name[0] == '.' &&
  662. (dp->d_name[1] == '\0' ||
  663. (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
  664. continue;
  665. #ifdef WINNT_NATIVE
  666. nt_check_name_and_hash(is_windir, dp->d_name, i);
  667. #else /* !WINNT_NATIVE*/
  668. #if defined(_UWIN) || defined(__CYGWIN__)
  669. /* Turn foo.{exe,com,bat} into foo since UWIN's readdir returns
  670. * the file with the .exe, .com, .bat extension
  671. *
  672. * Same for Cygwin, but only for .exe and .com extension.
  673. */
  674. {
  675. ssize_t ext = strlen(dp->d_name) - 4;
  676. if ((ext > 0) && (strcasecmp(&dp->d_name[ext], ".exe") == 0 ||
  677. #ifndef __CYGWIN__
  678. strcasecmp(&dp->d_name[ext], ".bat") == 0 ||
  679. #endif
  680. strcasecmp(&dp->d_name[ext], ".com") == 0)) {
  681. #ifdef __CYGWIN__
  682. /* Also store the variation with extension. */
  683. hashval = hashname(str2short(dp->d_name));
  684. bis(hashval, i);
  685. #endif /* __CYGWIN__ */
  686. dp->d_name[ext] = '\0';
  687. }
  688. }
  689. #endif /* _UWIN || __CYGWIN__ */
  690. # ifdef FASTHASH
  691. hashval = hashname(str2short(dp->d_name));
  692. bis(hashval, i);
  693. if (hashdebug & 1)
  694. xprintf(CGETS(13, 1, "hash=%-4d dir=%-2d prog=%s\n"),
  695. hashname(str2short(dp->d_name)), i, dp->d_name);
  696. # else /* OLD HASH */
  697. hashval = hash(hashname(str2short(dp->d_name)), i);
  698. bis(xhash, hashval);
  699. # endif /* FASTHASH */
  700. /* tw_add_comm_name (dp->d_name); */
  701. #endif /* WINNT_NATIVE */
  702. }
  703. cleanup_until(dirp);
  704. }
  705. }
  706. /*ARGSUSED*/
  707. void
  708. dounhash(Char **v, struct command *c)
  709. {
  710. USE(c);
  711. USE(v);
  712. havhash = 0;
  713. #ifdef FASTHASH
  714. xfree(xhash);
  715. xhash = NULL;
  716. #endif /* FASTHASH */
  717. }
  718. /*ARGSUSED*/
  719. void
  720. hashstat(Char **v, struct command *c)
  721. {
  722. USE(c);
  723. USE(v);
  724. #ifdef FASTHASH
  725. if (havhash && hashlength && hashwidth)
  726. xprintf(CGETS(13, 2, "%d hash buckets of %d bits each\n"),
  727. hashlength, hashwidth*8);
  728. if (hashdebug)
  729. xprintf(CGETS(13, 3, "debug mask = 0x%08x\n"), hashdebug);
  730. #endif /* FASTHASH */
  731. #ifdef VFORK
  732. if (hits + misses)
  733. xprintf(CGETS(13, 4, "%d hits, %d misses, %d%%\n"),
  734. hits, misses, 100 * hits / (hits + misses));
  735. #endif
  736. }
  737. /*
  738. * Hash a command name.
  739. */
  740. int
  741. hashname(Char *cp)
  742. {
  743. unsigned long h;
  744. for (h = 0; *cp; cp++)
  745. h = hash(h, *cp);
  746. return ((int) h);
  747. }
  748. static int
  749. iscommand(Char *name)
  750. {
  751. Char **opv, **pv;
  752. Char *sav;
  753. struct varent *v;
  754. int slash = any(short2str(name), '/');
  755. int hashval, rehashed, i;
  756. v = adrof(STRpath);
  757. if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash)
  758. opv = justabs;
  759. else
  760. opv = v->vec;
  761. sav = Strspl(STRslash, name); /* / command name for postpending */
  762. hashval = havhash ? hashname(name) : 0;
  763. rehashed = 0;
  764. retry:
  765. pv = opv;
  766. i = 0;
  767. do {
  768. if (!slash && ABSOLUTEP(pv[0]) && havhash) {
  769. #ifdef FASTHASH
  770. if (!bit(hashval, i))
  771. goto cont;
  772. #else /* OLDHASH */
  773. int hashval1 = hash(hashval, i);
  774. if (!bit(xhash, hashval1))
  775. goto cont;
  776. #endif /* FASTHASH */
  777. }
  778. if (pv[0][0] == 0 || eq(pv[0], STRdot)) { /* don't make ./xxx */
  779. if (executable(NULL, name, 0)) {
  780. xfree(sav);
  781. return i + 1;
  782. }
  783. }
  784. else {
  785. if (executable(*pv, sav, 0)) {
  786. xfree(sav);
  787. return i + 1;
  788. }
  789. }
  790. cont:
  791. pv++;
  792. i++;
  793. } while (*pv);
  794. if (adrof(STRautorehash) && !rehashed && havhash && opv != justabs) {
  795. dohash(NULL, NULL);
  796. rehashed = 1;
  797. goto retry;
  798. }
  799. xfree(sav);
  800. return 0;
  801. }
  802. /* Also by:
  803. * Andreas Luik <luik@isaak.isa.de>
  804. * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung
  805. * Azenberstr. 35
  806. * D-7000 Stuttgart 1
  807. * West-Germany
  808. * is the executable() routine below and changes to iscommand().
  809. * Thanks again!!
  810. */
  811. #ifndef WINNT_NATIVE
  812. /*
  813. * executable() examines the pathname obtained by concatenating dir and name
  814. * (dir may be NULL), and returns 1 either if it is executable by us, or
  815. * if dir_ok is set and the pathname refers to a directory.
  816. * This is a bit kludgy, but in the name of optimization...
  817. */
  818. int
  819. executable(const Char *dir, const Char *name, int dir_ok)
  820. {
  821. struct stat stbuf;
  822. char *strname;
  823. if (dir && *dir) {
  824. Char *path;
  825. path = Strspl(dir, name);
  826. strname = short2str(path);
  827. xfree(path);
  828. }
  829. else
  830. strname = short2str(name);
  831. return (stat(strname, &stbuf) != -1 &&
  832. ((dir_ok && S_ISDIR(stbuf.st_mode)) ||
  833. (S_ISREG(stbuf.st_mode) &&
  834. /* save time by not calling access() in the hopeless case */
  835. (stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) &&
  836. access(strname, X_OK) == 0
  837. )));
  838. }
  839. #endif /*!WINNT_NATIVE*/
  840. struct tellmewhat_s0_cleanup
  841. {
  842. Char **dest, *val;
  843. };
  844. static void
  845. tellmewhat_s0_cleanup(void *xstate)
  846. {
  847. struct tellmewhat_s0_cleanup *state;
  848. state = xstate;
  849. *state->dest = state->val;
  850. }
  851. int
  852. tellmewhat(struct wordent *lexp, Char **str)
  853. {
  854. struct tellmewhat_s0_cleanup s0;
  855. int i;
  856. const struct biltins *bptr;
  857. struct wordent *sp = lexp->next;
  858. int aliased = 0, found;
  859. Char *s1, *s2, *cmd;
  860. Char qc;
  861. if (adrof1(sp->word, &aliases)) {
  862. alias(lexp);
  863. sp = lexp->next;
  864. aliased = 1;
  865. }
  866. s0.dest = &sp->word; /* to get the memory freeing right... */
  867. s0.val = sp->word;
  868. cleanup_push(&s0, tellmewhat_s0_cleanup);
  869. /* handle quoted alias hack */
  870. if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE)
  871. (sp->word)++;
  872. /* do quoting, if it hasn't been done */
  873. s1 = s2 = sp->word;
  874. while (*s2)
  875. switch (*s2) {
  876. case '\'':
  877. case '"':
  878. qc = *s2++;
  879. while (*s2 && *s2 != qc)
  880. *s1++ = *s2++ | QUOTE;
  881. if (*s2)
  882. s2++;
  883. break;
  884. case '\\':
  885. if (*++s2)
  886. *s1++ = *s2++ | QUOTE;
  887. break;
  888. default:
  889. *s1++ = *s2++;
  890. }
  891. *s1 = '\0';
  892. for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
  893. if (eq(sp->word, str2short(bptr->bname))) {
  894. if (str == NULL) {
  895. if (aliased)
  896. prlex(lexp);
  897. xprintf(CGETS(13, 5, "%S: shell built-in command.\n"),
  898. sp->word);
  899. flush();
  900. }
  901. else
  902. *str = Strsave(sp->word);
  903. cleanup_until(&s0);
  904. return TRUE;
  905. }
  906. }
  907. #ifdef WINNT_NATIVE
  908. for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) {
  909. if (eq(sp->word, str2short(bptr->bname))) {
  910. if (str == NULL) {
  911. if (aliased)
  912. prlex(lexp);
  913. xprintf(CGETS(13, 5, "%S: shell built-in command.\n"),
  914. sp->word);
  915. flush();
  916. }
  917. else
  918. *str = Strsave(sp->word);
  919. cleanup_until(&s0);
  920. return TRUE;
  921. }
  922. }
  923. #endif /* WINNT_NATIVE*/
  924. sp->word = cmd = globone(sp->word, G_IGNORE);
  925. cleanup_push(cmd, xfree);
  926. if ((i = iscommand(sp->word)) != 0) {
  927. Char **pv;
  928. struct varent *v;
  929. int slash = any(short2str(sp->word), '/');
  930. v = adrof(STRpath);
  931. if (v == NULL || v->vec == NULL || v->vec[0] == NULL || slash)
  932. pv = justabs;
  933. else
  934. pv = v->vec;
  935. pv += i - 1;
  936. if (pv[0][0] == 0 || eq(pv[0], STRdot)) {
  937. if (!slash) {
  938. sp->word = Strspl(STRdotsl, sp->word);
  939. cleanup_push(sp->word, xfree);
  940. prlex(lexp);
  941. cleanup_until(sp->word);
  942. }
  943. else
  944. prlex(lexp);
  945. }
  946. else {
  947. s1 = Strspl(*pv, STRslash);
  948. sp->word = Strspl(s1, sp->word);
  949. xfree(s1);
  950. cleanup_push(sp->word, xfree);
  951. if (str == NULL)
  952. prlex(lexp);
  953. else
  954. *str = Strsave(sp->word);
  955. cleanup_until(sp->word);
  956. }
  957. found = 1;
  958. }
  959. else {
  960. if (str == NULL) {
  961. if (aliased)
  962. prlex(lexp);
  963. xprintf(CGETS(13, 6, "%S: Command not found.\n"), sp->word);
  964. flush();
  965. }
  966. else
  967. *str = Strsave(sp->word);
  968. found = 0;
  969. }
  970. cleanup_until(&s0);
  971. return found;
  972. }
  973. /*
  974. * Builtin to look at and list all places a command may be defined:
  975. * aliases, shell builtins, and the path.
  976. *
  977. * Marc Horowitz <marc@mit.edu>
  978. * MIT Student Information Processing Board
  979. */
  980. /*ARGSUSED*/
  981. void
  982. dowhere(Char **v, struct command *c)
  983. {
  984. int found = 1;
  985. USE(c);
  986. for (v++; *v; v++)
  987. found &= find_cmd(*v, 1);
  988. /* Make status nonzero if any command is not found. */
  989. if (!found)
  990. setcopy(STRstatus, STR1, VAR_READWRITE);
  991. }
  992. int
  993. find_cmd(Char *cmd, int prt)
  994. {
  995. struct varent *var;
  996. const struct biltins *bptr;
  997. Char **pv;
  998. Char *sv;
  999. int hashval, rehashed, i, ex, rval = 0;
  1000. if (prt && any(short2str(cmd), '/')) {
  1001. xprintf("%s", CGETS(13, 7, "where: / in command makes no sense\n"));
  1002. return rval;
  1003. }
  1004. /* first, look for an alias */
  1005. if (prt && adrof1(cmd, &aliases)) {
  1006. if ((var = adrof1(cmd, &aliases)) != NULL) {
  1007. xprintf(CGETS(13, 8, "%S is aliased to "), cmd);
  1008. if (var->vec != NULL)
  1009. blkpr(var->vec);
  1010. xputchar('\n');
  1011. rval = 1;
  1012. }
  1013. }
  1014. /* next, look for a shell builtin */
  1015. for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
  1016. if (eq(cmd, str2short(bptr->bname))) {
  1017. rval = 1;
  1018. if (prt)
  1019. xprintf(CGETS(13, 9, "%S is a shell built-in\n"), cmd);
  1020. else
  1021. return rval;
  1022. }
  1023. }
  1024. #ifdef WINNT_NATIVE
  1025. for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) {
  1026. if (eq(cmd, str2short(bptr->bname))) {
  1027. rval = 1;
  1028. if (prt)
  1029. xprintf(CGETS(13, 9, "%S is a shell built-in\n"), cmd);
  1030. else
  1031. return rval;
  1032. }
  1033. }
  1034. #endif /* WINNT_NATIVE*/
  1035. /* last, look through the path for the command */
  1036. if ((var = adrof(STRpath)) == NULL)
  1037. return rval;
  1038. hashval = havhash ? hashname(cmd) : 0;
  1039. sv = Strspl(STRslash, cmd);
  1040. cleanup_push(sv, xfree);
  1041. rehashed = 0;
  1042. retry:
  1043. for (pv = var->vec, i = 0; pv && *pv; pv++, i++) {
  1044. if (havhash && !eq(*pv, STRdot)) {
  1045. #ifdef FASTHASH
  1046. if (!bit(hashval, i))
  1047. continue;
  1048. #else /* OLDHASH */
  1049. int hashval1 = hash(hashval, i);
  1050. if (!bit(xhash, hashval1))
  1051. continue;
  1052. #endif /* FASTHASH */
  1053. }
  1054. ex = executable(*pv, sv, 0);
  1055. #ifdef FASTHASH
  1056. if (!ex && (hashdebug & 2)) {
  1057. xprintf("%s", CGETS(13, 10, "hash miss: "));
  1058. ex = 1; /* Force printing */
  1059. }
  1060. #endif /* FASTHASH */
  1061. if (ex) {
  1062. rval = 1;
  1063. if (prt) {
  1064. xprintf("%S/", *pv);
  1065. xprintf("%S\n", cmd);
  1066. }
  1067. else
  1068. return rval;
  1069. }
  1070. }
  1071. if (adrof(STRautorehash) && !rehashed && havhash) {
  1072. dohash(NULL, NULL);
  1073. rehashed = 1;
  1074. goto retry;
  1075. }
  1076. cleanup_until(sv);
  1077. return rval;
  1078. }
  1079. #ifdef WINNT_NATIVE
  1080. int hashval_extern(cp)
  1081. Char *cp;
  1082. {
  1083. return havhash?hashname(cp):0;
  1084. }
  1085. int bit_extern(val,i)
  1086. int val;
  1087. int i;
  1088. {
  1089. return bit(val,i);
  1090. }
  1091. void bis_extern(val,i)
  1092. int val;
  1093. int i;
  1094. {
  1095. bis(val,i);
  1096. }
  1097. #endif /* WINNT_NATIVE */