mandoc: update to 1.14.5
[unleashed.git] / bin / which / which.c
blobbacbe419e4de20172667096d390c25ea81a37309
1 /* $OpenBSD: which.c,v 1.26 2016/10/28 07:22:59 schwarze Exp $ */
3 /*
4 * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
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.
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.
19 #include <sys/stat.h>
21 #include <err.h>
22 #include <errno.h>
23 #include <limits.h>
24 #include <paths.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
30 #define PROG_WHICH 1
31 #define PROG_WHEREIS 2
33 extern char *__progname;
35 int findprog(char *, char *, int, int);
36 static void __dead usage(void);
39 * which(1) -- find an executable(s) in the user's path
40 * whereis(1) -- find an executable(s) in the default user path
42 * Return values:
43 * 0 - all executables found
44 * 1 - some found, some not
45 * 2 - none found
48 int
49 main(int argc, char *argv[])
51 char *path;
52 size_t n;
53 int ch, allmatches = 0, notfound = 0, progmode = PROG_WHICH;
55 while ((ch = getopt(argc, argv, "a")) != -1)
56 switch (ch) {
57 case 'a':
58 allmatches = 1;
59 break;
60 default:
61 usage();
63 argc -= optind;
64 argv += optind;
66 if (argc == 0)
67 usage();
69 if (strcmp(__progname, "whereis") == 0) {
70 progmode = PROG_WHEREIS;
71 path = _PATH_STDPATH;
72 } else {
73 if ((path = getenv("PATH")) == NULL || *path == '\0')
74 path = _PATH_DEFPATH;
77 /* To make access(2) do what we want */
78 if (setgid(getegid()))
79 err(1, "Can't set gid to %u", getegid());
80 if (setuid(geteuid()))
81 err(1, "Can't set uid to %u", geteuid());
83 if (pledge("stdio rpath", NULL) == -1)
84 err(2, "pledge");
86 for (n = 0; n < argc; n++)
87 if (findprog(argv[n], path, progmode, allmatches) == 0)
88 notfound++;
90 return ((notfound == 0) ? 0 : ((notfound == argc) ? 2 : 1));
93 int
94 findprog(char *prog, char *path, int progmode, int allmatches)
96 char *p, filename[PATH_MAX];
97 int len, rval = 0;
98 struct stat sbuf;
99 char *pathcpy;
101 /* Special case if prog contains '/' */
102 if (strchr(prog, '/')) {
103 if ((stat(prog, &sbuf) == 0) && S_ISREG(sbuf.st_mode) &&
104 access(prog, X_OK) == 0) {
105 (void)puts(prog);
106 return (1);
107 } else {
108 warnx("%s: Command not found.", prog);
109 return (0);
113 if ((path = strdup(path)) == NULL)
114 err(1, "strdup");
115 pathcpy = path;
117 while ((p = strsep(&pathcpy, ":")) != NULL) {
118 if (*p == '\0')
119 p = ".";
121 len = strlen(p);
122 while (len > 0 && p[len-1] == '/')
123 p[--len] = '\0'; /* strip trailing '/' */
125 len = snprintf(filename, sizeof(filename), "%s/%s", p, prog);
126 if (len < 0 || len >= sizeof(filename)) {
127 warnc(ENAMETOOLONG, "%s/%s", p, prog);
128 free(path);
129 return (0);
131 if ((stat(filename, &sbuf) == 0) && S_ISREG(sbuf.st_mode) &&
132 access(filename, X_OK) == 0) {
133 (void)puts(filename);
134 rval = 1;
135 if (!allmatches) {
136 free(path);
137 return (rval);
141 (void)free(path);
143 /* whereis(1) is silent on failure. */
144 if (!rval && progmode != PROG_WHEREIS)
145 warnx("%s: Command not found.", prog);
146 return (rval);
149 static void __dead
150 usage(void)
152 (void)fprintf(stderr, "usage: %s [-a] name ...\n", __progname);
153 exit(1);