home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume10 / which4 < prev    next >
Text File  |  1990-02-13  |  9KB  |  379 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v10i064: which4 - supersedes fast which2.c
  3. From: maart@cs.vu.nl (Maarten Litmaath)
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 10, Issue 64
  7. Submitted-by: maart@cs.vu.nl (Maarten Litmaath)
  8. Archive-name: which4
  9.  
  10. Dear moderator,
  11. below is the latest version of which2.c, the fast form of the which(1)
  12. command.  Besides aliases and executables, shell functions are now
  13. recognized too.  Furthermore the output will be correct even if the
  14. effective uid (gid) of the invoker doesn't equal the real uid (gid).
  15.  
  16. An updated manual is included.
  17.  
  18. I suggest the previous 2 versions (v04i010, v05i016) to be deleted from
  19. the archives, or to be replaced with pointers to which4.
  20.  
  21. Thanks for your time,
  22.                 Maarten Litmaath @ VU Amsterdam:
  23.                 maart@cs.vu.nl, uunet!mcsun!botter!maart
  24.  
  25. : This is a shar archive.  Extract with sh, not csh.
  26. : This archive ends with exit, so do not worry about trailing junk.
  27. : --------------------------- cut here --------------------------
  28. PATH=/bin:/usr/bin:/usr/ucb
  29. echo Extracting 'which.1'
  30. sed 's/^X//' > 'which.1' << '+ END-OF-FILE ''which.1'
  31. X.TH WHICH 1 Sep\ 21\ 1989
  32. X.SH NAME
  33. Xwhich \- give alias, function or path expansion of command
  34. X.SH SYNOPSIS
  35. X.B which
  36. X[
  37. X.B \-i
  38. X] [
  39. X.B \-a
  40. X] [
  41. X.B \-\-
  42. X] [
  43. X.I command
  44. X]
  45. X.SH DESCRIPTION
  46. X.I Which
  47. Xprovides the user with the full expansion of the
  48. X.I command
  49. Xargument, be it either an \fIalias\fR, a \fIshell function\fR
  50. Xor an executable file (default). To enable search for
  51. X.I aliases
  52. Xand \fIshell functions\fR
  53. Xthe user should supply the `\fI\-i\fR'
  54. X(= interactive) flag. In that case
  55. X.I which
  56. Xexpects as standard input the expansion of the \fIalias\fR
  57. Xor \fIshell function\fR.
  58. XIf the standard input is empty or the `\fI\-i\fR' flag has not been
  59. Xgiven, \fIwhich\fR will try to locate \fIcommand\fR
  60. Xin the user's \fIPATH\fR.
  61. XThe interactive mode is easily used by setting an
  62. X.I alias
  63. Xlike the following:
  64. X.ft B
  65. X.nf
  66. X
  67. X    alias    which    alias !\\$ \\| /usr/local/bin/which \-i !\\*
  68. X
  69. X.fi
  70. X.ft R
  71. Xin \fIcsh\fR, or
  72. X.ft B
  73. X.nf
  74. X
  75. X    alias    which    eval alias '\\"\\$$#\\" |' \\
  76. X            /usr/local/bin/which \-i '${1+"$@"}'
  77. X
  78. X.fi
  79. X.ft R
  80. Xin shells which are supersets of
  81. X.I sh
  82. Xand which know \fIaliases\fR. If your shell has \fIshell functions\fR, you
  83. Xcan use the following function:
  84. X.ft B
  85. X.nf
  86. X
  87. X    which()
  88. X    {
  89. X        eval last=\\"\\$$#\\"
  90. X        set | sed \-n "/^$last(){$/,/^}$/p" |
  91. X            /usr/local/bin/which \-i ${1+"$@"}
  92. X    }
  93. X
  94. X.fi
  95. X.ft R
  96. XIf the `\fI\-a\fR' (= all) flag is given,
  97. X.I which
  98. Xwill not stop after the first `match', but search for all occurrences of
  99. X.I command
  100. Xin the user's
  101. X.I PATH.
  102. XThe `\fI\-\-\fR'
  103. Xflag can be used to end the list of options: the next argument (if present)
  104. Xwill be taken as \fIcommand\fR, even if it starts with a `\-'.
  105. X\fIWhich [\-i] [\-a] [\-\-]\fR
  106. Xwithout further arguments prints the user's
  107. X.I PATH
  108. Xbroken up into its components,
  109. Xone per line.
  110. X.PP
  111. XThis new version of the
  112. X.I which
  113. Xcommand is not a
  114. X.I csh
  115. Xscript.
  116. XBeing an executable it is much faster, and not sourcing 
  117. X.I .cshrc
  118. Xit gives a true picture of one's
  119. X.I aliases.
  120. X.SH EXAMPLE
  121. X.ft B
  122. X.nf
  123. X% alias
  124. Xwhich    alias !$ | /usr/local/bin/which \-i !*
  125. X% which which
  126. Xwhich    alias !$ | /usr/local/bin/which \-i !*
  127. X% which \-a which
  128. Xwhich    alias !$ | /usr/local/bin/which \-i !*
  129. X/usr/local/bin/which
  130. X/usr/ucb/which
  131. X%
  132. X.fi
  133. X.ft R
  134. X.SH AUTHOR
  135. XMaarten Litmaath @ VU Informatika Amsterdam
  136. + END-OF-FILE which.1
  137. chmod 'u=rw,g=r,o=r' 'which.1'
  138. set `wc -c 'which.1'`
  139. count=$1
  140. case $count in
  141. 2205)    :;;
  142. *)    echo 'Bad character count in ''which.1' >&2
  143.         echo 'Count should be 2205' >&2
  144. esac
  145. echo Extracting 'Makefile'
  146. sed 's/^X//' > 'Makefile' << '+ END-OF-FILE ''Makefile'
  147. X# Makefile for /usr/local/bin/which
  148. X
  149. Xwhich:        which4.c
  150. X        cc -O which4.c -o which
  151. X
  152. Xinstall:    which
  153. X        /bin/mv -f which /usr/local/bin
  154. X
  155. Xdoc:
  156. X        nroff -man which.1 > which.man
  157. + END-OF-FILE Makefile
  158. chmod 'u=rw,g=r,o=r' 'Makefile'
  159. set `wc -c 'Makefile'`
  160. count=$1
  161. case $count in
  162. 169)    :;;
  163. *)    echo 'Bad character count in ''Makefile' >&2
  164.         echo 'Count should be 169' >&2
  165. esac
  166. echo Extracting 'which4.c'
  167. sed 's/^X//' > 'which4.c' << '+ END-OF-FILE ''which4.c'
  168. X/*
  169. X * which [-i] [-a] [--] [<command>]
  170. X * alias which alias !\$ \| /usr/local/bin/which -i !\*
  171. X * alias which 'eval alias \$$# | /usr/local/bin/which -i ${1+"$@"}'
  172. X * which()
  173. X * {
  174. X *    eval last=\"\$$#\"
  175. X *    set | sed -n "/^$last(){$/,/^}$/p" |
  176. X *        /usr/local/bin/which -i ${1+"$@"}
  177. X * }
  178. X *
  179. X * author: Maarten Litmaath @ VU University Amsterdam (maart@cs.vu.nl)
  180. X * first change:
  181. X *    Emile LeBlanc (leblanc%math.Berkeley.EDU@ucbvax.berkeley.edu) notes
  182. X *    the access() system call considering everything executable for
  183. X *    root (!), so we give root a special treatment
  184. X *    'which', 'which -i' and 'which -a' with no further arguments now
  185. X *    return the PATH environment variable, split up into its components
  186. X *    the aliases defined above are slightly different from the previous
  187. X *    version - now it's the shell who's doing the alias checking
  188. X * second change:
  189. X *    added support for shell functions and multiline aliases, added the
  190. X *    `--' option, changed the source style
  191. X * third change:
  192. X *    to hell with access()!
  193. X *    now stat() is used to give the right answer even if the effective
  194. X *    uid (gid) differs from the real uid (gid)
  195. X *    we can't use setuid(geteuid()), because that's nonportable :-(
  196. X */
  197. X
  198. X#include    <sys/types.h>
  199. X#include    <sys/stat.h>
  200. X#include    <stdio.h>
  201. X
  202. X#define        BUF_SIZE    512
  203. X#define        M_USR        0700
  204. X#define        M_GRP        0070
  205. X#define        M_OTH        0007
  206. X#define        X_ALL        0111
  207. X#define        R_ALL        0444
  208. X
  209. Xchar    Version[] =
  210. X    "@(#)which 4.0 90/01/24 Maarten Litmaath @ VU Informatika Amsterdam";
  211. Xchar    *Prog;
  212. X
  213. X
  214. Xvoid    usage()
  215. X{
  216. X    fprintf(stderr, "Usage: %s [-i] [-a] [--] [<command>]\n", Prog);
  217. X    exit(1);
  218. X}
  219. X
  220. X
  221. Xmain(argc, argv) 
  222. Xint    argc;
  223. Xregister char    **argv;
  224. X{
  225. X    register char    *path, *s;
  226. X    char    *save, *strcpy(), *getenv(), *fgets(), buf[BUF_SIZE];
  227. X    int    all = 0, inter = 0, stop = 0, found = 0, uid, gid, mask,
  228. X        xmask, rmask;
  229. X    struct    stat    st;
  230. X    void    usage(), convert();
  231. X
  232. X
  233. X    Prog = *argv++;
  234. X    --argc;
  235. X
  236. X    while (!stop && (s = *argv) && (*s == '-')) {
  237. X        ++argv;
  238. X        --argc;
  239. X        ++s;
  240. X        while (*s)
  241. X            switch (*s++) {
  242. X            case 'a':
  243. X                all = 1;
  244. X                break;
  245. X            case 'i':
  246. X                inter = 1;
  247. X                break;
  248. X            case '-':
  249. X                stop = 1;
  250. X                break;
  251. X            default:
  252. X                usage();
  253. X            }
  254. X    }
  255. X
  256. X    if (argc > 1)
  257. X        usage();
  258. X
  259. X    if (inter && *argv) {
  260. X        while (fgets(buf, sizeof buf, stdin)) {
  261. X            if (!found) {
  262. X                printf("%s", *argv);
  263. X                found = 1;
  264. X            }
  265. X            printf("\t%s", buf);
  266. X        }
  267. X        if (found && !all)
  268. X            exit(0);
  269. X    }
  270. X
  271. X    if (!(save = path = getenv("PATH"))) {
  272. X        fprintf(stderr, "%s: no PATH in environment!\n", Prog);
  273. X        exit(1);
  274. X    }
  275. X
  276. X    if (!*path)
  277. X        save = path = ".";
  278. X
  279. X    if (!*argv) {
  280. X        convert(path, buf);
  281. X        puts(buf);
  282. X        exit(0);
  283. X    }
  284. X
  285. X    uid = geteuid();
  286. X    gid = getegid();
  287. X    if (uid == 0) {
  288. X        xmask = X_ALL;
  289. X        rmask = R_ALL;
  290. X    }
  291. X
  292. X    while (*path) {
  293. X        s = buf;
  294. X        while ((*s++ = *path) && *path++ != ':')
  295. X            ;
  296. X        if (*buf == ':') {
  297. X            /*
  298. X             * to deal with the dubious convention that a
  299. X             * spurious colon is equivalent to a dot...
  300. X             */
  301. X            *buf = '.';
  302. X            ++s;
  303. X        }
  304. X        (void) strcpy(s, *argv);
  305. X        *--s = '/';
  306. X
  307. X        if (stat(buf, &st) != 0 || (st.st_mode & S_IFMT) != S_IFREG)
  308. X            continue;
  309. X
  310. X        /* file exists and is regular */
  311. X
  312. X        if (uid != 0) {
  313. X            mask = st.st_uid == uid ? M_USR :
  314. X                st.st_gid == gid ? M_GRP : M_OTH;
  315. X            xmask = X_ALL & mask;
  316. X            rmask = R_ALL & mask;
  317. X        }
  318. X
  319. X        if (!(st.st_mode & xmask))
  320. X            continue;
  321. X
  322. X        /* file is executable */
  323. X
  324. X        *s = 0;
  325. X        if (stat(buf, &st) != 0) {
  326. X            perror(buf);
  327. X            continue;
  328. X        }
  329. X
  330. X        if (!(st.st_mode & rmask)) {
  331. X            fprintf(stderr,
  332. X                "%s: %s found in unreadable directory %s!\n",
  333. X                Prog, *argv, buf);
  334. X            found = 1;
  335. X            continue;
  336. X        }
  337. X
  338. X        /* directory is readable */
  339. X
  340. X        *s = '/';
  341. X        puts(buf);
  342. X        if (!all)
  343. X            exit(0);
  344. X        found = 1;
  345. X    }
  346. X
  347. X    if (found)
  348. X        exit(0);
  349. X
  350. X    convert(save, buf);
  351. X    fprintf(stderr, "%s not found in\n%s\n", *argv, buf);
  352. X    exit(1);
  353. X}
  354. X
  355. X
  356. Xvoid    convert(path, buf)
  357. Xregister char    *path, *buf;
  358. X{
  359. X    for (;;) {
  360. X        while ((*buf++ = *path) && *path++ != ':')
  361. X            ;
  362. X        if (!*path)
  363. X            break;
  364. X        *buf++ = '\n';
  365. X    }
  366. X    *buf = '\0';        /* to cope with a PATH ending in ':' */
  367. X}
  368. + END-OF-FILE which4.c
  369. chmod 'u=rw,g=r,o=r' 'which4.c'
  370. set `wc -c 'which4.c'`
  371. count=$1
  372. case $count in
  373. 3907)    :;;
  374. *)    echo 'Bad character count in ''which4.c' >&2
  375.         echo 'Count should be 3907' >&2
  376. esac
  377. exit 0
  378.  
  379.