Annotation of src/usr.bin/which/which.c, Revision 1.11
1.11 ! millert 1: /* $OpenBSD: which.c,v 1.10 2003/06/10 22:20:54 deraadt 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: #ifndef lint
1.11 ! millert 20: static const char rcsid[] = "$OpenBSD: which.c,v 1.10 2003/06/10 22:20:54 deraadt Exp $";
1.1 millert 21: #endif /* not lint */
22:
23: #include <sys/param.h>
24: #include <sys/stat.h>
1.2 millert 25: #include <sys/sysctl.h>
1.1 millert 26:
27: #include <err.h>
28: #include <errno.h>
29: #include <locale.h>
30: #include <stdio.h>
31: #include <stdlib.h>
32: #include <string.h>
33: #include <unistd.h>
34:
1.2 millert 35: #define PROG_WHICH 1
36: #define PROG_WHEREIS 2
37:
1.1 millert 38: extern char *__progname;
39:
1.6 millert 40: int findprog(char *, char *, int, int);
41: void usage(void);
1.1 millert 42:
43: /*
44: * which(1) -- find an executable(s) in the user's path
1.2 millert 45: * whereis(1) -- find an executable(s) in the default user path
1.1 millert 46: *
47: * Return values:
48: * 0 - all executables found
49: * 1 - some found, some not
50: * 2 - none found
51: */
52:
53: int
1.10 deraadt 54: main(int argc, char *argv[])
1.1 millert 55: {
56: char *path;
1.2 millert 57: size_t n;
1.3 millert 58: int ch, allmatches = 0, notfound = 0, progmode = PROG_WHICH;
1.1 millert 59:
60: (void)setlocale(LC_ALL, "");
61:
62: if (argc == 1)
63: usage();
64:
1.2 millert 65: /* Don't accept command args but check since old whereis(1) used to */
1.3 millert 66: while ((ch = getopt(argc, argv, "a")) != -1) {
1.2 millert 67: switch (ch) {
1.3 millert 68: case 'a':
69: allmatches = 1;
70: break;
1.2 millert 71: default:
72: usage();
73: }
74: }
75:
76: /*
77: * which(1) uses user's $PATH.
78: * whereis(1) uses user.cs_path from sysctl(3).
79: */
80: if (strcmp(__progname, "whereis") == 0) {
81: int mib[2];
82:
83: progmode = PROG_WHEREIS;
84: mib[0] = CTL_USER;
85: mib[1] = USER_CS_PATH;
86: if (sysctl(mib, 2, NULL, &n, NULL, 0) == -1)
1.4 deraadt 87: err(1, "unable to get length of user.cs_path");
1.2 millert 88: if (n == 0)
1.4 deraadt 89: errx(1, "user.cs_path was zero length!");
1.2 millert 90: if ((path = (char *)malloc(n)) == NULL)
1.4 deraadt 91: errx(1, "can't allocate memory.");
1.2 millert 92: if (sysctl(mib, 2, path, &n, NULL, 0) == -1)
1.4 deraadt 93: err(1, "unable to get user.cs_path");
1.2 millert 94: } else {
95: if ((path = getenv("PATH")) == NULL)
1.4 deraadt 96: err(1, "can't get $PATH from environment");
1.2 millert 97: }
1.1 millert 98:
99: /* To make access(2) do what we want */
100: if (setgid(getegid()))
1.4 deraadt 101: err(1, "Can't set gid to %u", getegid());
1.1 millert 102: if (setuid(geteuid()))
1.4 deraadt 103: err(1, "Can't set uid to %u", geteuid());
1.1 millert 104:
1.3 millert 105: for (n = optind; n < argc; n++)
106: if (findprog(argv[n], path, progmode, allmatches) == 0)
1.1 millert 107: notfound++;
108:
109: exit((notfound == 0) ? 0 : ((notfound == argc - 1) ? 2 : 1));
110: }
111:
112: int
1.8 millert 113: findprog(char *prog, char *path, int progmode, int allmatches)
1.1 millert 114: {
115: char *p, filename[MAXPATHLEN];
1.3 millert 116: int proglen, plen, rval = 0;
1.1 millert 117: struct stat sbuf;
118:
119: /* Special case if prog contains '/' */
120: if (strchr(prog, '/')) {
121: if ((stat(prog, &sbuf) == 0) && S_ISREG(sbuf.st_mode) &&
122: access(prog, X_OK) == 0) {
123: (void)puts(prog);
124: return(1);
125: } else {
126: (void)printf("%s: Command not found.\n", prog);
127: return(0);
128: }
129: }
130:
131: if ((path = strdup(path)) == NULL)
1.4 deraadt 132: errx(1, "Can't allocate memory.");
1.1 millert 133:
134: proglen = strlen(prog);
135: while ((p = strsep(&path, ":")) != NULL) {
136: if (*p == '\0')
137: p = ".";
138:
139: plen = strlen(p);
140: while (p[plen-1] == '/')
141: p[--plen] = '\0'; /* strip trailing '/' */
142:
143: if (plen + 1 + proglen >= sizeof(filename)) {
144: warnx("%s/%s: %s", p, prog, strerror(ENAMETOOLONG));
145: return(0);
146: }
147:
1.8 millert 148: snprintf(filename, sizeof(filename), "%s/%s", p, prog);
1.1 millert 149: if ((stat(filename, &sbuf) == 0) && S_ISREG(sbuf.st_mode) &&
150: access(filename, X_OK) == 0) {
151: (void)puts(filename);
1.3 millert 152: rval = 1;
153: if (!allmatches)
154: return(rval);
1.1 millert 155: }
156: }
157: (void)free(path);
158:
1.2 millert 159: /* whereis(1) is silent on failure. */
1.3 millert 160: if (!rval && progmode != PROG_WHEREIS)
1.2 millert 161: (void)printf("%s: Command not found.\n", prog);
1.3 millert 162: return(rval);
1.1 millert 163: }
164:
165: void
1.8 millert 166: usage(void)
1.1 millert 167: {
1.3 millert 168: (void) fprintf(stderr, "Usage: %s [-a] name [...]\n", __progname);
1.1 millert 169: exit(1);
170: }