xref: /minix/usr.bin/whereis/whereis.c (revision d2532d3d)
1 /*	$NetBSD: whereis.c,v 1.21 2008/10/17 10:53:26 apb 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\
35  The Regents of the University of California.  All rights reserved.");
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.21 2008/10/17 10:53:26 apb 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) __dead;
57 
58 int
main(int argc,char * argv[])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 		if (**argv == '/') {
116 			if (stat(*argv, &sb) == -1)
117 				continue; /* next argv */
118 			if (!S_ISREG(sb.st_mode))
119 				continue; /* next argv */
120 			if (access(*argv, X_OK) == -1)
121 				continue; /* next argv */
122 			(void)printf("%s\n", *argv);
123 			found++;
124 			if (which)
125 				continue; /* next argv */
126 		} else for (p = std; p; ) {
127 			t = p;
128 			if ((p = strchr(p, ':')) != NULL) {
129 				*p = '\0';
130 				if (t == p)
131 					t = ".";
132 			} else
133 				if (strlen(t) == 0)
134 					t = ".";
135 			(void)snprintf(path, sizeof(path), "%s/%s", t, *argv);
136 			len = snprintf(path, sizeof(path), "%s/%s", t, *argv);
137 			if (p)
138 				*p++ = ':';
139 			if (len >= sizeof(path))
140 				continue; /* next p */
141 			if (stat(path, &sb) == -1)
142 				continue; /* next p */
143 			if (!S_ISREG(sb.st_mode))
144 				continue; /* next p */
145 			if (access(path, X_OK) == -1)
146 				continue; /* next p */
147 			(void)printf("%s\n", path);
148 			found++;
149 			if (which)
150 				break; /* next argv */
151 		}
152 	}
153 
154 	return ((found == 0) ? 3 : ((found >= argc) ? 0 : 2));
155 }
156 
157 static void
usage(void)158 usage(void)
159 {
160 
161 	(void)fprintf(stderr, "Usage: %s [-ap] program [...]\n", getprogname());
162 	exit(1);
163 }
164