xref: /netbsd-src/usr.bin/whereis/whereis.c (revision 4de49944462db29a5d62f73777065b8699bb5c01)
1*4de49944Sapb /*	$NetBSD: whereis.c,v 1.21 2008/10/17 10:53:26 apb Exp $	*/
2be667101Sjtc 
361f28255Scgd /*-
4dd831dd1Smycroft  * Copyright (c) 1993
5dd831dd1Smycroft  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * Redistribution and use in source and binary forms, with or without
861f28255Scgd  * modification, are permitted provided that the following conditions
961f28255Scgd  * are met:
1061f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1261f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1461f28255Scgd  *    documentation and/or other materials provided with the distribution.
1589aaa1bbSagc  * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd  *    may be used to endorse or promote products derived from this software
1761f28255Scgd  *    without specific prior written permission.
1861f28255Scgd  *
1961f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd  * SUCH DAMAGE.
3061f28255Scgd  */
3161f28255Scgd 
329998247bSmrg #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
3498e5374cSlukem __COPYRIGHT("@(#) Copyright (c) 1993\
3598e5374cSlukem  The Regents of the University of California.  All rights reserved.");
3661f28255Scgd #endif /* not lint */
3761f28255Scgd 
3861f28255Scgd #ifndef lint
39be667101Sjtc #if 0
40be667101Sjtc static char sccsid[] = "@(#)whereis.c	8.3 (Berkeley) 5/4/95";
41be667101Sjtc #endif
42*4de49944Sapb __RCSID("$NetBSD: whereis.c,v 1.21 2008/10/17 10:53:26 apb Exp $");
4361f28255Scgd #endif /* not lint */
4461f28255Scgd 
4561f28255Scgd #include <sys/param.h>
46dd831dd1Smycroft #include <sys/stat.h>
47dd831dd1Smycroft #include <sys/sysctl.h>
48dd831dd1Smycroft 
49dd831dd1Smycroft #include <err.h>
50dd831dd1Smycroft #include <errno.h>
5161f28255Scgd #include <stdio.h>
52dd831dd1Smycroft #include <stdlib.h>
53dd831dd1Smycroft #include <string.h>
54be667101Sjtc #include <unistd.h>
5561f28255Scgd 
568b0f9554Sperry static void usage(void) __dead;
5761f28255Scgd 
58dd831dd1Smycroft int
main(int argc,char * argv[])59745a6d0fSchristos main(int argc, char *argv[])
6061f28255Scgd {
61dd831dd1Smycroft 	struct stat sb;
62dd831dd1Smycroft 	size_t len;
63745a6d0fSchristos 	int ch, mib[2];
6460a197ffSchristos 	char *p, *std, path[MAXPATHLEN];
6560a197ffSchristos 	const char *t;
66745a6d0fSchristos 	int which = strcmp(getprogname(), "which") == 0;
67745a6d0fSchristos 	int useenvpath = which, found = 0;
6854c75404Schristos 	gid_t egid = getegid();
6954c75404Schristos 	uid_t euid = geteuid();
7054c75404Schristos 
7154c75404Schristos 	/* To make access(2) do what we want */
7254c75404Schristos 	if (setgid(egid) == -1)
7354c75404Schristos 		err(1, "Can't set gid to %lu", (unsigned long)egid);
7454c75404Schristos 	if (setuid(euid) == -1)
7554c75404Schristos 		err(1, "Can't set uid to %lu", (unsigned long)euid);
7661f28255Scgd 
77745a6d0fSchristos 	while ((ch = getopt(argc, argv, "ap")) != -1)
78dd831dd1Smycroft 		switch (ch) {
79745a6d0fSchristos 		case 'a':
80745a6d0fSchristos 			which = 0;
81745a6d0fSchristos 			break;
8264b15518Sfair 		case 'p':
8364b15518Sfair 			useenvpath = 1;	/* use environment for PATH */
8464b15518Sfair 			break;
8564b15518Sfair 
86dd831dd1Smycroft 		case '?':
8761f28255Scgd 		default:
88dd831dd1Smycroft 			usage();
8961f28255Scgd 		}
90dd831dd1Smycroft 	argc -= optind;
91dd831dd1Smycroft 	argv += optind;
92dd831dd1Smycroft 
93dd831dd1Smycroft 	if (argc == 0)
94dd831dd1Smycroft 		usage();
95dd831dd1Smycroft 
9664b15518Sfair  	if (useenvpath) {
9764b15518Sfair  		if ((std = getenv("PATH")) == NULL)
98745a6d0fSchristos  			errx(1, "PATH environment variable is not set");
9964b15518Sfair 	} else {
100dd831dd1Smycroft 		/* Retrieve the standard path. */
101dd831dd1Smycroft 		mib[0] = CTL_USER;
102dd831dd1Smycroft 		mib[1] = USER_CS_PATH;
103dd831dd1Smycroft 		if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1)
104745a6d0fSchristos 			err(1, "sysctl: user.cs_path");
105dd831dd1Smycroft 		if (len == 0)
106745a6d0fSchristos 			errx(1, "sysctl: user.cs_path (zero length)");
107dd831dd1Smycroft 		if ((std = malloc(len)) == NULL)
10885cbf55dSdrochner 			err(1, NULL);
109745a6d0fSchristos 		if (sysctl(mib, 2, std, &len, NULL, 0) == -1)
110745a6d0fSchristos 			err(1, "sysctl: user.cs_path");
11164b15518Sfair 	}
112dd831dd1Smycroft 
113dd831dd1Smycroft 	/* For each path, for each program... */
114*4de49944Sapb 	for (; *argv; ++argv) {
115ef30089dSmartin 		if (**argv == '/') {
116ef30089dSmartin 			if (stat(*argv, &sb) == -1)
117*4de49944Sapb 				continue; /* next argv */
118ef30089dSmartin 			if (!S_ISREG(sb.st_mode))
119*4de49944Sapb 				continue; /* next argv */
120ef30089dSmartin 			if (access(*argv, X_OK) == -1)
121*4de49944Sapb 				continue; /* next argv */
122ef30089dSmartin 			(void)printf("%s\n", *argv);
123ef30089dSmartin 			found++;
124ef30089dSmartin 			if (which)
125*4de49944Sapb 				continue; /* next argv */
126*4de49944Sapb 		} else for (p = std; p; ) {
127dd831dd1Smycroft 			t = p;
128dd831dd1Smycroft 			if ((p = strchr(p, ':')) != NULL) {
129dd831dd1Smycroft 				*p = '\0';
130dd831dd1Smycroft 				if (t == p)
131dd831dd1Smycroft 					t = ".";
13261f28255Scgd 			} else
133dd831dd1Smycroft 				if (strlen(t) == 0)
134dd831dd1Smycroft 					t = ".";
135dd831dd1Smycroft 			(void)snprintf(path, sizeof(path), "%s/%s", t, *argv);
136dbf34104Schristos 			len = snprintf(path, sizeof(path), "%s/%s", t, *argv);
137*4de49944Sapb 			if (p)
138*4de49944Sapb 				*p++ = ':';
139dbf34104Schristos 			if (len >= sizeof(path))
140*4de49944Sapb 				continue; /* next p */
141745a6d0fSchristos 			if (stat(path, &sb) == -1)
142*4de49944Sapb 				continue; /* next p */
143745a6d0fSchristos 			if (!S_ISREG(sb.st_mode))
144*4de49944Sapb 				continue; /* next p */
145745a6d0fSchristos 			if (access(path, X_OK) == -1)
146*4de49944Sapb 				continue; /* next p */
147dd831dd1Smycroft 			(void)printf("%s\n", path);
148df28067fSperry 			found++;
149745a6d0fSchristos 			if (which)
150*4de49944Sapb 				break; /* next argv */
151*4de49944Sapb 		}
15261f28255Scgd 	}
153f5a8ade2Smikel 
154745a6d0fSchristos 	return ((found == 0) ? 3 : ((found >= argc) ? 0 : 2));
15561f28255Scgd }
15661f28255Scgd 
157745a6d0fSchristos static void
usage(void)158745a6d0fSchristos usage(void)
15961f28255Scgd {
16061f28255Scgd 
161745a6d0fSchristos 	(void)fprintf(stderr, "Usage: %s [-ap] program [...]\n", getprogname());
162dd831dd1Smycroft 	exit(1);
16361f28255Scgd }
164