xref: /netbsd-src/usr.bin/whereis/whereis.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: whereis.c,v 1.17 2004/05/23 02:24:06 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1993\n\
35 	The Regents of the University of California.  All rights reserved.\n");
36 #endif /* not lint */
37 
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)whereis.c	8.3 (Berkeley) 5/4/95";
41 #endif
42 __RCSID("$NetBSD: whereis.c,v 1.17 2004/05/23 02:24:06 christos Exp $");
43 #endif /* not lint */
44 
45 #include <sys/param.h>
46 #include <sys/stat.h>
47 #include <sys/sysctl.h>
48 
49 #include <err.h>
50 #include <errno.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <unistd.h>
55 
56 static void usage(void) __attribute__((__noreturn__));
57 
58 int
59 main(int argc, char *argv[])
60 {
61 	struct stat sb;
62 	size_t len;
63 	int ch, mib[2];
64 	char *p, *std, path[MAXPATHLEN];
65 	const char *t;
66 	int which = strcmp(getprogname(), "which") == 0;
67 	int useenvpath = which, found = 0;
68 	gid_t egid = getegid();
69 	uid_t euid = geteuid();
70 
71 	/* To make access(2) do what we want */
72 	if (setgid(egid) == -1)
73 		err(1, "Can't set gid to %lu", (unsigned long)egid);
74 	if (setuid(euid) == -1)
75 		err(1, "Can't set uid to %lu", (unsigned long)euid);
76 
77 	while ((ch = getopt(argc, argv, "ap")) != -1)
78 		switch (ch) {
79 		case 'a':
80 			which = 0;
81 			break;
82 		case 'p':
83 			useenvpath = 1;	/* use environment for PATH */
84 			break;
85 
86 		case '?':
87 		default:
88 			usage();
89 		}
90 	argc -= optind;
91 	argv += optind;
92 
93 	if (argc == 0)
94 		usage();
95 
96  	if (useenvpath) {
97  		if ((std = getenv("PATH")) == NULL)
98  			errx(1, "PATH environment variable is not set");
99 	} else {
100 		/* Retrieve the standard path. */
101 		mib[0] = CTL_USER;
102 		mib[1] = USER_CS_PATH;
103 		if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1)
104 			err(1, "sysctl: user.cs_path");
105 		if (len == 0)
106 			errx(1, "sysctl: user.cs_path (zero length)");
107 		if ((std = malloc(len)) == NULL)
108 			err(1, NULL);
109 		if (sysctl(mib, 2, std, &len, NULL, 0) == -1)
110 			err(1, "sysctl: user.cs_path");
111 	}
112 
113 	/* For each path, for each program... */
114 	for (; *argv; ++argv)
115 		for (p = std; p; p && (*p++ = ':')) {
116 			t = p;
117 			if ((p = strchr(p, ':')) != NULL) {
118 				*p = '\0';
119 				if (t == p)
120 					t = ".";
121 			} else
122 				if (strlen(t) == 0)
123 					t = ".";
124 			(void)snprintf(path, sizeof(path), "%s/%s", t, *argv);
125 			len = snprintf(path, sizeof(path), "%s/%s", t, *argv);
126 			if (len >= sizeof(path))
127 				continue;
128 			if (stat(path, &sb) == -1)
129 				continue;
130 			if (!S_ISREG(sb.st_mode))
131 				continue;
132 			if (access(path, X_OK) == -1)
133 				continue;
134 			(void)printf("%s\n", path);
135 			found++;
136 			if (which)
137 				break;
138 		}
139 
140 	return ((found == 0) ? 3 : ((found >= argc) ? 0 : 2));
141 }
142 
143 static void
144 usage(void)
145 {
146 
147 	(void)fprintf(stderr, "Usage: %s [-ap] program [...]\n", getprogname());
148 	exit(1);
149 }
150