home *** CD-ROM | disk | FTP | other *** search
- /*
- * which [-i] [-a] [--] [<command>]
- * alias which alias !\$ \| /usr/local/bin/which -i !\*
- * alias which 'eval alias \$$# | /usr/local/bin/which -i ${1+"$@"}'
- * which()
- * {
- * eval last=\"\$$#\"
- * set | sed -n "/^$last(){$/,/^}$/p" |
- * /usr/local/bin/which -i ${1+"$@"}
- * }
- *
- * Author: Maarten Litmaath @ VU University Amsterdam (maart@cs.vu.nl)
- * First change:
- * Emile LeBlanc (leblanc%math.Berkeley.EDU@ucbvax.berkeley.edu) notes
- * the access() system call considering everything executable for
- * root (!), so we give root a special treatment. :-(
- * `which', `which -i' and `which -a' with no further arguments now
- * return the PATH environment variable, split up into its components.
- * The aliases defined above are slightly different from the previous
- * version - now it's the shell who's doing the alias checking.
- * Second change:
- * Added support for shell functions and multiline aliases, added the
- * `--' option, changed the source style.
- * Third change:
- * To hell with access()!
- * Now stat() is used to give the right answer even if the effective
- * uid (gid) differs from the real uid (gid).
- * We can't use setuid(geteuid()), because that's nonportable. :-(
- * Fourth change:
- * Jim Meyering <meyering@cs.utexas.edu> notes convert() will clobber
- * the stack if the PATH is longer than BUF_SIZE - 1 characters.
- * I've changed convert() altogether to return a path vector (cf. argv),
- * whose components are the respective directories in the PATH.
- * Furthermore in printing the PATH there are no trailing colons anymore.
- */
-
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <stdio.h>
- #ifdef __GNUC__
- /* for all the extern progs... */
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #endif
-
- #if defined(__GNUC__) && defined(atarist)
- /* note: tcsh keeps PATH like .:/dev/c/bin:... but when it sets up an env
- for a prog, it converts it to .,c:\bin,... */
- #define DIRSEP ','
- #define SLASH '\\'
- #else
- #define DIRSEP ':'
- #define SLASH '/'
- #endif
-
- #define BUF_SIZE 512
- #define M_USR 0700
- #define M_GRP 0070
- #define M_OTH 0007
- #define X_ALL 0111
- #define R_ALL 0444
-
- char Version[] =
- "@(#)which 5.0 90/03/24 Maarten Litmaath @ VU Informatika Amsterdam";
- char *Prog;
-
- #ifdef atarist
- /* we need to look for files with extensions, too... */
- char *extn[] = {"", ".ttp", ".prg", ".tos", ".acc",
- ".csh", ".sh", ".g", (char *)0};
- #endif
-
-
- void usage()
- {
- fprintf(stderr, "%s\n\n", Version);
- fprintf(stderr, "Usage: %s [-i] [-a] [--] [<command>]\n", Prog);
- exit(1);
- }
-
- #ifdef __GNUC__
- char **convert();
- #endif
-
- void main(argc, argv)
- int argc;
- register char **argv;
- {
- register char *path, *s, **pathv, **p;
- #ifdef __GNUC__
- char buf[BUF_SIZE];
- #else
- char *strcpy(), *getenv(), *fgets(), buf[BUF_SIZE], **convert();
- #endif
- int all = 0, inter = 0, stop = 0, found = 0, uid, gid, mask,
- xmask, rmask;
- struct stat st;
- void usage();
- #ifdef atarist
- /* to deal with extensions... */
- int stret;
- char *pend;
- char **pextn;
- #endif
-
-
- Prog = *argv++;
- --argc;
-
- while (!stop && (s = *argv) && (*s == '-')) {
- ++argv;
- --argc;
- ++s;
- while (*s)
- switch (*s++) {
- case 'a':
- all = 1;
- break;
- case 'i':
- inter = 1;
- break;
- case '-':
- stop = 1;
- break;
- default:
- usage();
- }
- }
-
- if (argc > 1)
- usage();
-
- if (inter && *argv) {
- while (fgets(buf, sizeof buf, stdin)) {
- if (!found) {
- /*!!! printf("%s", *argv);*/
- printf("%s:", *argv);
- found = 1;
- }
- /*!!! printf("\t%s", buf);*/
- printf("\taliased to %s", buf);
- }
- if (found && !all)
- exit(0);
- }
-
- if (!(path = getenv("PATH"))) {
- fprintf(stderr, "%s: no PATH in environment!\n", Prog);
- exit(1);
- }
-
- if (!*path)
- path = "."; /* another dubious convention */
-
- pathv = convert(path); /* convert path string to vector */
-
- if (!*argv) { /* print path if no more arguments */
- while (*pathv)
- puts(*pathv++);
- exit(0);
- }
-
- uid = geteuid();
- gid = getegid();
- if (uid == 0) {
- xmask = X_ALL;
- rmask = R_ALL;
- }
-
- for (p = pathv; path = *p++; ) { /* try every component */
- s = buf;
- while (*s++ = *path++)
- ;
- (void) strcpy(s, *argv);
- *--s = SLASH;
-
- #ifdef atarist
- /*
- * here we deal with extensions. keep a ptr to null at
- * end of basic string. this assumes user did NOT give
- * a suffix! then we move along the list until we find
- * a regular file. if we get thru the loop, and if list
- * was exhausted, next. otherwise test again if reg file.
- */
- pend = &buf[strlen(buf)]; /* -> null at end */
- for (pextn = extn; *pextn; pextn++)
- {
- strcpy (pend, *pextn);
- /*fprintf(stderr,"test %s\n",buf);*/
- if (stret = stat(buf, &st) == 0
- && (st.st_mode & S_IFMT) == S_IFREG)
- break;
- }
- if (*pextn == NULL)
- continue;
- if (stret == 0 && (st.st_mode & S_IFMT) != S_IFREG)
- continue;
- #else
- if (stat(buf, &st) != 0 || (st.st_mode & S_IFMT) != S_IFREG)
- continue;
- #endif
-
- /* file exists and is regular */
-
- if (uid != 0) {
- mask = st.st_uid == uid ? M_USR :
- st.st_gid == gid ? M_GRP : M_OTH;
- xmask = X_ALL & mask;
- rmask = R_ALL & mask;
- }
-
- if (!(st.st_mode & xmask))
- continue;
-
- /* file is executable */
-
- *s = 0;
- if (stat(buf, &st) != 0) {
- perror(buf);
- continue;
- }
-
- if (!(st.st_mode & rmask)) {
- fprintf(stderr,
- "%s: %s found in unreadable directory %s!\n",
- Prog, *argv, buf);
- found = 1;
- continue;
- }
-
- /* directory is readable */
-
- *s = SLASH;
- puts(buf);
- if (!all)
- exit(0);
- found = 1;
- }
-
- if (found)
- exit(0);
-
- fprintf(stderr, "%s not found in:\n", *argv);
- while (*pathv)
- fprintf(stderr, "%s\n", *pathv++);
- exit(1);
- }
-
-
-
- char **convert(path)
- char *path;
- {
- register char *s, c;
- register int pathc; /* the length of the path vector */
- #ifdef __GNUC__
- char **v, **pathv;
- #else
- char **v, **pathv, *malloc();
- #endif
-
- for (s = path, pathc = 2; c = *s++; )
- if (c == DIRSEP)
- ++pathc;
-
- if (!(pathv = (char **) malloc(pathc * sizeof(char *)))) {
- perror("malloc");
- exit(1);
- }
-
- for (s = path, v = pathv; (c = *s) != '\0'; ) {
- if (c == DIRSEP) {
- /*
- * This colon is spurious. According to some
- * dubious convention it is made equivalent to a dot.
- */
- *v++ = ".";
- if (*++s == '\0')
- *v++ = ".";
- /*
- * The PATH ended in a spurious colon.
- * To be consistent we add another dot
- * to the path vector. One day you'll
- * be glad we did.
- */
- } else {
- *v++ = s;
- while ((c = *++s) != '\0')
- if (c == DIRSEP) {
- *s++ = '\0';
- if (*s == '\0')
- *v++ = ".";
- /*
- * The PATH ended in a
- * (spurious) colon, so
- * add dot to the vector.
- */
- break;
- }
- }
- }
-
- *v = 0; /* Signal the end of the path vector. */
-
- return pathv;
- }
-