home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2651 < prev    next >
Internet Message Format  |  1991-02-02  |  11KB

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