home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume11 / which5 / part01 next >
Encoding:
Text File  |  1990-04-04  |  10.1 KB  |  439 lines

  1. Newsgroups: comp.sources.misc
  2. organization: VU Informatika, Amsterdam, The Netherlands
  3. subject: v11i096: which5
  4. From: maart@cs.vu.nl (Maarten Litmaath)
  5. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  6.  
  7. Posting-number: Volume 11, Issue 96
  8. Submitted-by: maart@cs.vu.nl (Maarten Litmaath)
  9. Archive-name: which5/part01
  10.  
  11. There was still a small problem with which4.  :-(
  12. Thanks go to Jim Meyering <meyering@cs.utexas.edu>, who noted convert() will
  13. clobber the stack if the PATH is longer than BUF_SIZE - 1 characters.
  14. I've changed the use and implementation of convert() altogether: now it
  15. returns a path vector (cf. argv), whose components are the respective
  16. directories in the PATH.
  17. Furthermore I fixed the printing of the PATH: there are no trailing colons
  18. anymore.  Now you can do things like:
  19.  
  20.     for dir in `which`
  21.     do
  22.         set $dir/$pattern
  23.         test -f $1 || continue
  24.         for i
  25.         do
  26.             echo $i
  27.         done
  28.     done
  29.  
  30. ...to find all files in your PATH which match $pattern.
  31. However, beware of rewriting `which' in shell-script!  There were good
  32. reasons for making it a C program (check the source).
  33.  
  34. Thanks for your time,
  35.                 Maarten Litmaath @ VU Amsterdam:
  36.                 maart@cs.vu.nl, uunet!mcsun!botter!maart
  37.  
  38. : This is a shar archive.  Extract with sh, not csh.
  39. : This archive ends with exit, so do not worry about trailing junk.
  40. : --------------------------- cut here --------------------------
  41. PATH=/bin:/usr/bin:/usr/ucb
  42. echo Extracting 'which.1'
  43. sed 's/^X//' > 'which.1' << '+ END-OF-FILE ''which.1'
  44. X.TH WHICH 1 Apr\ 04\ 1990
  45. X.SH NAME
  46. Xwhich \- give alias, function or path expansion of command
  47. X.SH SYNOPSIS
  48. X.B which
  49. X[
  50. X.B \-i
  51. X] [
  52. X.B \-a
  53. X] [
  54. X.B \-\-
  55. X] [
  56. X.I command
  57. X]
  58. X.SH DESCRIPTION
  59. X.I Which
  60. Xprovides the user with the full expansion of the
  61. X.I command
  62. Xargument, be it either an \fIalias\fR, a \fIshell function\fR
  63. Xor an executable file (default). To enable search for
  64. X.I aliases
  65. Xand \fIshell functions\fR
  66. Xthe user should supply the `\fI\-i\fR'
  67. X(= interactive) flag. In that case
  68. X.I which
  69. Xexpects as standard input the expansion of the \fIalias\fR
  70. Xor \fIshell function\fR.
  71. XIf the standard input is empty or the `\fI\-i\fR' flag has not been
  72. Xgiven, \fIwhich\fR will try to locate \fIcommand\fR
  73. Xin the user's \fBPATH\fR.
  74. XThe interactive mode is easily used by setting an
  75. X.I alias
  76. Xlike the following:
  77. X.ft B
  78. X.nf
  79. X
  80. X    alias    which    alias !\\$ \\| /usr/local/bin/which \-i !\\*
  81. X
  82. X.fi
  83. X.ft R
  84. Xin \fIcsh\fR, or
  85. X.ft B
  86. X.nf
  87. X
  88. X    alias    which    eval alias '\\"\\$$#\\" |' \\
  89. X            /usr/local/bin/which \-i '${1+"$@"}'
  90. X
  91. X.fi
  92. X.ft R
  93. Xin shells which are supersets of
  94. X.I sh
  95. Xand which know \fIaliases\fR. If your shell has \fIshell functions\fR, you
  96. Xcan use the following function:
  97. X.ft B
  98. X.nf
  99. X
  100. X    which()
  101. X    {
  102. X        eval last=\\"\\$$#\\"
  103. X        set | sed \-n "/^$last(){$/,/^}$/p" |
  104. X            /usr/local/bin/which \-i ${1+"$@"}
  105. X    }
  106. X
  107. X.fi
  108. X.ft R
  109. XIf the `\fI\-a\fR' (= all) flag is given,
  110. X.I which
  111. Xwill not stop after the first `match', but search for all occurrences of
  112. X.I command
  113. Xin the user's
  114. X.B PATH.
  115. XThe `\fI\-\-\fR'
  116. Xflag can be used to end the list of options: the next argument (if present)
  117. Xwill be taken as \fIcommand\fR, even if it starts with a `\-'.
  118. X\fIWhich [\-i] [\-a] [\-\-]\fR
  119. Xwithout further arguments prints the user's
  120. X.B PATH
  121. Xbroken up into its components,
  122. Xone per line.
  123. X.PP
  124. XThis new version of the
  125. X.I which
  126. Xcommand is not a
  127. X.I csh
  128. Xscript.
  129. XBeing an executable it is much faster, and not sourcing 
  130. X.I .cshrc
  131. Xit gives a true picture of one's
  132. X.I aliases.
  133. XFurthermore it will give the correct answers even if:
  134. X.IP \-
  135. Xthe \fIeffective uid\fR
  136. X(\fIgid\fR) differs from the \fIreal\fR uid (gid)
  137. X.IP \-
  138. Xthe effective uid is 0 (\fIroot\fR).
  139. X.SH EXAMPLE
  140. X.ft B
  141. X.nf
  142. X% alias
  143. Xwhich    alias !$ | /usr/local/bin/which \-i !*
  144. X% which which
  145. Xwhich    alias !$ | /usr/local/bin/which \-i !*
  146. X% which \-a which
  147. Xwhich    alias !$ | /usr/local/bin/which \-i !*
  148. X/usr/local/bin/which
  149. X/usr/ucb/which
  150. X%
  151. X.fi
  152. X.ft R
  153. X.SH AUTHOR
  154. XMaarten Litmaath @ VU Informatika Amsterdam
  155. + END-OF-FILE which.1
  156. chmod 'u=rw,g=r,o=r' 'which.1'
  157. set `wc -c 'which.1'`
  158. count=$1
  159. case $count in
  160. 2384)    :;;
  161. *)    echo 'Bad character count in ''which.1' >&2
  162.         echo 'Count should be 2384' >&2
  163. esac
  164. echo Extracting 'Makefile'
  165. sed 's/^X//' > 'Makefile' << '+ END-OF-FILE ''Makefile'
  166. X# Makefile for /usr/local/bin/which
  167. X
  168. Xwhich:        which5.c
  169. X        cc -O which5.c -o which
  170. X
  171. Xinstall:    which
  172. X        /bin/mv -f which /usr/local/bin
  173. X
  174. Xdoc:
  175. X        nroff -man which.1 > which.man
  176. + END-OF-FILE Makefile
  177. chmod 'u=rw,g=r,o=r' 'Makefile'
  178. set `wc -c 'Makefile'`
  179. count=$1
  180. case $count in
  181. 169)    :;;
  182. *)    echo 'Bad character count in ''Makefile' >&2
  183.         echo 'Count should be 169' >&2
  184. esac
  185. echo Extracting 'which5.c'
  186. sed 's/^X//' > 'which5.c' << '+ END-OF-FILE ''which5.c'
  187. X/*
  188. X * which [-i] [-a] [--] [<command>]
  189. X * alias which alias !\$ \| /usr/local/bin/which -i !\*
  190. X * alias which 'eval alias \$$# | /usr/local/bin/which -i ${1+"$@"}'
  191. X * which()
  192. X * {
  193. X *    eval last=\"\$$#\"
  194. X *    set | sed -n "/^$last(){$/,/^}$/p" |
  195. X *        /usr/local/bin/which -i ${1+"$@"}
  196. X * }
  197. X *
  198. X * Author: Maarten Litmaath @ VU University Amsterdam (maart@cs.vu.nl)
  199. X * First change:
  200. X *    Emile LeBlanc (leblanc%math.Berkeley.EDU@ucbvax.berkeley.edu) notes
  201. X *    the access() system call considering everything executable for
  202. X *    root (!), so we give root a special treatment.  :-(
  203. X *    `which', `which -i' and `which -a' with no further arguments now
  204. X *    return the PATH environment variable, split up into its components.
  205. X *    The aliases defined above are slightly different from the previous
  206. X *    version - now it's the shell who's doing the alias checking.
  207. X * Second change:
  208. X *    Added support for shell functions and multiline aliases, added the
  209. X *    `--' option, changed the source style.
  210. X * Third change:
  211. X *    To hell with access()!
  212. X *    Now stat() is used to give the right answer even if the effective
  213. X *    uid (gid) differs from the real uid (gid).
  214. X *    We can't use setuid(geteuid()), because that's nonportable.  :-(
  215. X * Fourth change:
  216. X *    Jim Meyering <meyering@cs.utexas.edu> notes convert() will clobber
  217. X *    the stack if the PATH is longer than BUF_SIZE - 1 characters.
  218. X *    I've changed convert() altogether to return a path vector (cf. argv),
  219. X *    whose components are the respective directories in the PATH.
  220. X *    Furthermore in printing the PATH there are no trailing colons anymore.
  221. X */
  222. X
  223. X#include    <sys/types.h>
  224. X#include    <sys/stat.h>
  225. X#include    <stdio.h>
  226. X
  227. X#define        BUF_SIZE    512
  228. X#define        M_USR        0700
  229. X#define        M_GRP        0070
  230. X#define        M_OTH        0007
  231. X#define        X_ALL        0111
  232. X#define        R_ALL        0444
  233. X
  234. Xchar    Version[] =
  235. X    "@(#)which 5.0 90/03/24 Maarten Litmaath @ VU Informatika Amsterdam";
  236. Xchar    *Prog;
  237. X
  238. X
  239. Xvoid    usage()
  240. X{
  241. X    fprintf(stderr, "Usage: %s [-i] [-a] [--] [<command>]\n", Prog);
  242. X    exit(1);
  243. X}
  244. X
  245. X
  246. Xmain(argc, argv) 
  247. Xint    argc;
  248. Xregister char    **argv;
  249. X{
  250. X    register char    *path, *s, **pathv, **p;
  251. X    char    *strcpy(), *getenv(), *fgets(), buf[BUF_SIZE], **convert();
  252. X    int    all = 0, inter = 0, stop = 0, found = 0, uid, gid, mask,
  253. X        xmask, rmask;
  254. X    struct    stat    st;
  255. X    void    usage();
  256. X
  257. X
  258. X    Prog = *argv++;
  259. X    --argc;
  260. X
  261. X    while (!stop && (s = *argv) && (*s == '-')) {
  262. X        ++argv;
  263. X        --argc;
  264. X        ++s;
  265. X        while (*s)
  266. X            switch (*s++) {
  267. X            case 'a':
  268. X                all = 1;
  269. X                break;
  270. X            case 'i':
  271. X                inter = 1;
  272. X                break;
  273. X            case '-':
  274. X                stop = 1;
  275. X                break;
  276. X            default:
  277. X                usage();
  278. X            }
  279. X    }
  280. X
  281. X    if (argc > 1)
  282. X        usage();
  283. X
  284. X    if (inter && *argv) {
  285. X        while (fgets(buf, sizeof buf, stdin)) {
  286. X            if (!found) {
  287. X                printf("%s", *argv);
  288. X                found = 1;
  289. X            }
  290. X            printf("\t%s", buf);
  291. X        }
  292. X        if (found && !all)
  293. X            exit(0);
  294. X    }
  295. X
  296. X    if (!(path = getenv("PATH"))) {
  297. X        fprintf(stderr, "%s: no PATH in environment!\n", Prog);
  298. X        exit(1);
  299. X    }
  300. X
  301. X    if (!*path)
  302. X        path = ".";        /* another dubious convention */
  303. X
  304. X    pathv = convert(path);        /* convert path string to vector */
  305. X
  306. X    if (!*argv) {            /* print path if no more arguments */
  307. X        while (*pathv)
  308. X            puts(*pathv++);
  309. X        exit(0);
  310. X    }
  311. X
  312. X    uid = geteuid();
  313. X    gid = getegid();
  314. X    if (uid == 0) {
  315. X        xmask = X_ALL;
  316. X        rmask = R_ALL;
  317. X    }
  318. X
  319. X    for (p = pathv; path = *p++; ) {    /* try every component */
  320. X        s = buf;
  321. X        while (*s++ = *path++)
  322. X            ;
  323. X        (void) strcpy(s, *argv);
  324. X        *--s = '/';
  325. X
  326. X        if (stat(buf, &st) != 0 || (st.st_mode & S_IFMT) != S_IFREG)
  327. X            continue;
  328. X
  329. X        /* file exists and is regular */
  330. X
  331. X        if (uid != 0) {
  332. X            mask = st.st_uid == uid ? M_USR :
  333. X                st.st_gid == gid ? M_GRP : M_OTH;
  334. X            xmask = X_ALL & mask;
  335. X            rmask = R_ALL & mask;
  336. X        }
  337. X
  338. X        if (!(st.st_mode & xmask))
  339. X            continue;
  340. X
  341. X        /* file is executable */
  342. X
  343. X        *s = 0;
  344. X        if (stat(buf, &st) != 0) {
  345. X            perror(buf);
  346. X            continue;
  347. X        }
  348. X
  349. X        if (!(st.st_mode & rmask)) {
  350. X            fprintf(stderr,
  351. X                "%s: %s found in unreadable directory %s!\n",
  352. X                Prog, *argv, buf);
  353. X            found = 1;
  354. X            continue;
  355. X        }
  356. X
  357. X        /* directory is readable */
  358. X
  359. X        *s = '/';
  360. X        puts(buf);
  361. X        if (!all)
  362. X            exit(0);
  363. X        found = 1;
  364. X    }
  365. X
  366. X    if (found)
  367. X        exit(0);
  368. X
  369. X    fprintf(stderr, "%s not found in:\n", *argv);
  370. X    while (*pathv)
  371. X        fprintf(stderr, "%s\n", *pathv++);
  372. X    exit(1);
  373. X}
  374. X
  375. X
  376. Xchar    **convert(path)
  377. Xchar    *path;
  378. X{
  379. X    register char    *s, c;
  380. X    register int    pathc;        /* the length of the path vector */
  381. X    char    **v, **pathv, *malloc();
  382. X
  383. X    for (s = path, pathc = 2; c = *s++; )
  384. X        if (c == ':')
  385. X            ++pathc;
  386. X
  387. X    if (!(pathv = (char **) malloc(pathc * sizeof(char *)))) {
  388. X        perror("malloc");
  389. X        exit(1);
  390. X    }
  391. X
  392. X    for (s = path, v = pathv; (c = *s) != '\0'; ) {
  393. X        if (c == ':') {
  394. X            /*
  395. X             * This colon is spurious.  According to some
  396. X             * dubious convention it is made equivalent to a dot.
  397. X             */
  398. X            *v++ = ".";
  399. X            if (*++s == '\0')
  400. X                *v++ = ".";
  401. X                /*
  402. X                 * The PATH ended in a spurious colon.
  403. X                 * To be consistent we add another dot
  404. X                 * to the path vector.  One day you'll
  405. X                 * be glad we did.
  406. X                 */
  407. X        } else {
  408. X            *v++ = s;
  409. X            while ((c = *++s) != '\0')
  410. X                if (c == ':') {
  411. X                    *s++ = '\0';
  412. X                    if (*s == '\0')
  413. X                        *v++ = ".";
  414. X                        /*
  415. X                         * The PATH ended in a
  416. X                         * (spurious) colon, so
  417. X                         * add dot to the vector.
  418. X                         */
  419. X                    break;
  420. X                }
  421. X        }
  422. X    }
  423. X
  424. X    *v = 0;        /* Signal the end of the path vector. */
  425. X
  426. X    return pathv;
  427. X}
  428. + END-OF-FILE which5.c
  429. chmod 'u=rw,g=,o=' 'which5.c'
  430. set `wc -c 'which5.c'`
  431. count=$1
  432. case $count in
  433. 5142)    :;;
  434. *)    echo 'Bad character count in ''which5.c' >&2
  435.         echo 'Count should be 5142' >&2
  436. esac
  437. exit 0
  438.  
  439.