|
|
1.1 root 1: /*
2: * locate a program file along the user's PATH.
3: * try to mimic output of the BSD version.
4: */
5: #include <stdio.h>
6: #include <sys/stat.h>
7: #include <access.h>
8:
9: char *getenv();
10: char *index();
11: char **parsepath(); /* parse PATH into argv-like structure */
12: void fatal(); /* display error message and die */
13: void usage(); /* display usage message and die */
14: char *calloc();
15: char *index();
16:
17: #define TRUE (0 == 0)
18: #define FALSE (0 != 0)
19: #define EXEC_BITS (S_IEXEC | (S_IEXEC >> 3) | (S_IEXEC >> 6))
20:
21: main(argc, argv)
22: int argc;
23: char *argv[];
24: {
25: char *pathp; /* pointer to PATH string */
26: char **pathpp; /* pointer to path entries */
27: char **pathlist; /* pointer to path list */
28: static char pathbuf[BUFSIZ]; /* expanded file names */
29: static char path[BUFSIZ]; /* saved copy for error msgs */
30:
31: if ((pathp = getenv("PATH")) == NULL)
32: fatal("PATH not found in environment");
33: strcpy(path, pathp);
34: if (--argc < 1)
35: usage();
36: pathlist = parsepath(pathp);
37:
38: for (++argv; argc-- > 0; ++argv) {
39: pathpp = pathlist;
40: for ( ; *pathpp != NULL; ++pathpp) {
41: if (**pathpp != '\0') {
42: strcpy(pathbuf, *pathpp);
43: strcat(pathbuf, "/");
44: strcat(pathbuf, *argv);
45: } else
46: strcpy(pathbuf, *argv);
47: if (is_exec(pathbuf)) {
48: puts(pathbuf);
49: break;
50: }
51: }
52: if (*pathpp == NULL)
53: if (index(*argv, '/') != NULL)
54: printf("%s not found\n", *argv);
55: else
56: printf("no %s in %s\n", *argv, path);
57: }
58: exit(0);
59: }
60:
61: /*
62: * check to see if the given name is executable.
63: * this isn't as trivial as it may seem since access() says
64: * that root (UID 0) can execute anything, even if the
65: * execute mode bits are not set.
66: */
67: is_exec(name)
68: char *name;
69: {
70: static struct stat statbuf;
71:
72: if (access(name, AEXEC) != 0)
73: return FALSE;
74: if (stat(name, &statbuf) == -1) {
75: fprintf(stderr, "%s: Unable to stat\n", name);
76: return FALSE;
77: }
78: if ((statbuf.st_mode & S_IFMT) != S_IFREG)
79: return FALSE;
80: return (getuid() != 0 || (statbuf.st_mode & EXEC_BITS));
81: }
82:
83: /*
84: * parse a path of the form dir1:dir2:dir3 into an array of pointers to
85: * the individual directory entries. Note that this null terminates each
86: * directory entry by replacing all ':' characters in "path" with NUL's.
87: * take special care of leading and trailing ':' which imply the current
88: * directory.
89: */
90: char **
91: parsepath(path)
92: char *path;
93: {
94: register char *cp;
95: register int i = 1;
96: char **patharray, **pp;
97:
98: for (cp = path; *cp != '\0'; ) /* calculate number of entries */
99: if (*cp++ == ':')
100: ++i;
101: if ((patharray = (char **)calloc(i + 1, sizeof (char *))) == NULL)
102: fatal("Out of memory for PATH list");
103: for (cp = path, pp = patharray; *cp != '\0' || pp == patharray; ) {
104: *pp++ = cp;
105: while (*cp != '\0') {
106: if (*cp == ':') {
107: *cp++ = '\0';
108: break;
109: }
110: ++cp;
111: }
112: if ((pp - patharray) < i)
113: *pp = cp;
114: }
115: return (patharray);
116: }
117:
118: void
119: usage()
120: {
121: fatal("usage: which name ....");
122: }
123:
124: void
125: fatal(info)
126: char *info;
127: {
128: fprintf(stderr, "which: %r\n", &info);
129: exit(1);
130: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.