Annotation of src/usr.bin/which/which.c, Revision 1.17
1.17 ! guenther 1: /* $OpenBSD: which.c,v 1.16 2010/05/31 14:01:49 sobrado Exp $ */
1.1 millert 2:
3: /*
4: * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
5: *
1.9 millert 6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
1.1 millert 9: *
1.11 millert 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 millert 17: */
18:
19: #include <sys/param.h>
20: #include <sys/stat.h>
1.2 millert 21: #include <sys/sysctl.h>
1.1 millert 22:
23: #include <err.h>
24: #include <errno.h>
25: #include <locale.h>
26: #include <stdio.h>
27: #include <stdlib.h>
28: #include <string.h>
29: #include <unistd.h>
30:
1.2 millert 31: #define PROG_WHICH 1
32: #define PROG_WHEREIS 2
33:
1.1 millert 34: extern char *__progname;
35:
1.6 millert 36: int findprog(char *, char *, int, int);
1.12 millert 37: __dead void usage(void);
1.1 millert 38:
39: /*
40: * which(1) -- find an executable(s) in the user's path
1.2 millert 41: * whereis(1) -- find an executable(s) in the default user path
1.1 millert 42: *
43: * Return values:
44: * 0 - all executables found
45: * 1 - some found, some not
46: * 2 - none found
47: */
48:
49: int
1.10 deraadt 50: main(int argc, char *argv[])
1.1 millert 51: {
52: char *path;
1.2 millert 53: size_t n;
1.3 millert 54: int ch, allmatches = 0, notfound = 0, progmode = PROG_WHICH;
1.1 millert 55:
56: (void)setlocale(LC_ALL, "");
57:
1.17 ! guenther 58: while ((ch = getopt(argc, argv, "a")) != -1)
1.2 millert 59: switch (ch) {
1.3 millert 60: case 'a':
61: allmatches = 1;
62: break;
1.2 millert 63: default:
64: usage();
65: }
1.17 ! guenther 66: argc -= optind;
! 67: argv += optind;
! 68:
! 69: if (argc == 0)
! 70: usage();
1.2 millert 71:
72: /*
73: * which(1) uses user's $PATH.
74: * whereis(1) uses user.cs_path from sysctl(3).
75: */
76: if (strcmp(__progname, "whereis") == 0) {
77: int mib[2];
78:
79: progmode = PROG_WHEREIS;
80: mib[0] = CTL_USER;
81: mib[1] = USER_CS_PATH;
82: if (sysctl(mib, 2, NULL, &n, NULL, 0) == -1)
1.4 deraadt 83: err(1, "unable to get length of user.cs_path");
1.2 millert 84: if (n == 0)
1.4 deraadt 85: errx(1, "user.cs_path was zero length!");
1.2 millert 86: if ((path = (char *)malloc(n)) == NULL)
1.4 deraadt 87: errx(1, "can't allocate memory.");
1.2 millert 88: if (sysctl(mib, 2, path, &n, NULL, 0) == -1)
1.4 deraadt 89: err(1, "unable to get user.cs_path");
1.2 millert 90: } else {
91: if ((path = getenv("PATH")) == NULL)
1.4 deraadt 92: err(1, "can't get $PATH from environment");
1.2 millert 93: }
1.1 millert 94:
95: /* To make access(2) do what we want */
96: if (setgid(getegid()))
1.4 deraadt 97: err(1, "Can't set gid to %u", getegid());
1.1 millert 98: if (setuid(geteuid()))
1.4 deraadt 99: err(1, "Can't set uid to %u", geteuid());
1.1 millert 100:
1.17 ! guenther 101: for (n = 0; n < argc; n++)
1.3 millert 102: if (findprog(argv[n], path, progmode, allmatches) == 0)
1.1 millert 103: notfound++;
104:
1.17 ! guenther 105: exit((notfound == 0) ? 0 : ((notfound == argc) ? 2 : 1));
1.1 millert 106: }
107:
108: int
1.8 millert 109: findprog(char *prog, char *path, int progmode, int allmatches)
1.1 millert 110: {
111: char *p, filename[MAXPATHLEN];
1.3 millert 112: int proglen, plen, rval = 0;
1.1 millert 113: struct stat sbuf;
1.13 fgsch 114: char *pathcpy;
1.1 millert 115:
116: /* Special case if prog contains '/' */
117: if (strchr(prog, '/')) {
118: if ((stat(prog, &sbuf) == 0) && S_ISREG(sbuf.st_mode) &&
119: access(prog, X_OK) == 0) {
120: (void)puts(prog);
1.12 millert 121: return (1);
1.1 millert 122: } else {
1.16 sobrado 123: warnx("%s: Command not found.", prog);
1.12 millert 124: return (0);
1.1 millert 125: }
126: }
127:
128: if ((path = strdup(path)) == NULL)
1.16 sobrado 129: err(1, "strdup");
1.13 fgsch 130: pathcpy = path;
1.1 millert 131:
132: proglen = strlen(prog);
1.13 fgsch 133: while ((p = strsep(&pathcpy, ":")) != NULL) {
1.1 millert 134: if (*p == '\0')
135: p = ".";
136:
137: plen = strlen(p);
138: while (p[plen-1] == '/')
139: p[--plen] = '\0'; /* strip trailing '/' */
140:
141: if (plen + 1 + proglen >= sizeof(filename)) {
142: warnx("%s/%s: %s", p, prog, strerror(ENAMETOOLONG));
1.12 millert 143: free(path);
144: return (0);
1.1 millert 145: }
146:
1.8 millert 147: snprintf(filename, sizeof(filename), "%s/%s", p, prog);
1.1 millert 148: if ((stat(filename, &sbuf) == 0) && S_ISREG(sbuf.st_mode) &&
149: access(filename, X_OK) == 0) {
150: (void)puts(filename);
1.3 millert 151: rval = 1;
1.12 millert 152: if (!allmatches) {
153: free(path);
154: return (rval);
155: }
1.1 millert 156: }
157: }
158: (void)free(path);
159:
1.2 millert 160: /* whereis(1) is silent on failure. */
1.3 millert 161: if (!rval && progmode != PROG_WHEREIS)
1.16 sobrado 162: warnx("%s: Command not found.", prog);
1.12 millert 163: return (rval);
1.1 millert 164: }
165:
1.12 millert 166: __dead void
1.8 millert 167: usage(void)
1.1 millert 168: {
1.14 sobrado 169: (void)fprintf(stderr, "usage: %s [-a] name ...\n", __progname);
1.1 millert 170: exit(1);
171: }