Annotation of src/usr.bin/which/which.c, Revision 1.27
1.27 ! millert 1: /* $OpenBSD: which.c,v 1.26 2016/10/28 07:22:59 schwarze Exp $ */
1.1 millert 2:
3: /*
1.27 ! millert 4: * Copyright (c) 1997 Todd C. Miller <millert@openbsd.org>
1.1 millert 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/stat.h>
1.2 millert 20: #include <sys/sysctl.h>
1.1 millert 21:
22: #include <err.h>
23: #include <errno.h>
1.26 schwarze 24: #include <limits.h>
1.18 guenther 25: #include <paths.h>
1.1 millert 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.26 schwarze 37: static void __dead 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:
1.17 guenther 56: while ((ch = getopt(argc, argv, "a")) != -1)
1.2 millert 57: switch (ch) {
1.3 millert 58: case 'a':
59: allmatches = 1;
60: break;
1.2 millert 61: default:
62: usage();
63: }
1.17 guenther 64: argc -= optind;
65: argv += optind;
66:
67: if (argc == 0)
68: usage();
1.2 millert 69:
70: if (strcmp(__progname, "whereis") == 0) {
71: progmode = PROG_WHEREIS;
1.18 guenther 72: path = _PATH_STDPATH;
1.2 millert 73: } else {
1.23 millert 74: if ((path = getenv("PATH")) == NULL || *path == '\0')
75: path = _PATH_DEFPATH;
1.2 millert 76: }
1.1 millert 77:
78: /* To make access(2) do what we want */
79: if (setgid(getegid()))
1.4 deraadt 80: err(1, "Can't set gid to %u", getegid());
1.1 millert 81: if (setuid(geteuid()))
1.4 deraadt 82: err(1, "Can't set uid to %u", geteuid());
1.21 deraadt 83:
84: if (pledge("stdio rpath", NULL) == -1)
1.22 gsoares 85: err(2, "pledge");
1.1 millert 86:
1.17 guenther 87: for (n = 0; n < argc; n++)
1.3 millert 88: if (findprog(argv[n], path, progmode, allmatches) == 0)
1.1 millert 89: notfound++;
90:
1.26 schwarze 91: return ((notfound == 0) ? 0 : ((notfound == argc) ? 2 : 1));
1.1 millert 92: }
93:
94: int
1.8 millert 95: findprog(char *prog, char *path, int progmode, int allmatches)
1.1 millert 96: {
1.20 deraadt 97: char *p, filename[PATH_MAX];
1.25 millert 98: int len, rval = 0;
1.1 millert 99: struct stat sbuf;
1.13 fgsch 100: char *pathcpy;
1.1 millert 101:
102: /* Special case if prog contains '/' */
103: if (strchr(prog, '/')) {
104: if ((stat(prog, &sbuf) == 0) && S_ISREG(sbuf.st_mode) &&
105: access(prog, X_OK) == 0) {
106: (void)puts(prog);
1.12 millert 107: return (1);
1.1 millert 108: } else {
1.16 sobrado 109: warnx("%s: Command not found.", prog);
1.12 millert 110: return (0);
1.1 millert 111: }
112: }
113:
114: if ((path = strdup(path)) == NULL)
1.16 sobrado 115: err(1, "strdup");
1.13 fgsch 116: pathcpy = path;
1.1 millert 117:
1.13 fgsch 118: while ((p = strsep(&pathcpy, ":")) != NULL) {
1.1 millert 119: if (*p == '\0')
120: p = ".";
121:
1.25 millert 122: len = strlen(p);
123: while (len > 0 && p[len-1] == '/')
124: p[--len] = '\0'; /* strip trailing '/' */
1.1 millert 125:
1.25 millert 126: len = snprintf(filename, sizeof(filename), "%s/%s", p, prog);
127: if (len < 0 || len >= sizeof(filename)) {
1.19 guenther 128: warnc(ENAMETOOLONG, "%s/%s", p, prog);
1.12 millert 129: free(path);
130: return (0);
1.1 millert 131: }
132: if ((stat(filename, &sbuf) == 0) && S_ISREG(sbuf.st_mode) &&
133: access(filename, X_OK) == 0) {
134: (void)puts(filename);
1.3 millert 135: rval = 1;
1.12 millert 136: if (!allmatches) {
137: free(path);
138: return (rval);
139: }
1.1 millert 140: }
141: }
142: (void)free(path);
143:
1.2 millert 144: /* whereis(1) is silent on failure. */
1.3 millert 145: if (!rval && progmode != PROG_WHEREIS)
1.16 sobrado 146: warnx("%s: Command not found.", prog);
1.12 millert 147: return (rval);
1.1 millert 148: }
149:
1.26 schwarze 150: static void __dead
1.8 millert 151: usage(void)
1.1 millert 152: {
1.14 sobrado 153: (void)fprintf(stderr, "usage: %s [-a] name ...\n", __progname);
1.1 millert 154: exit(1);
155: }