xref: /freebsd/usr.bin/which/which.c (revision 8c821782f8ae62a05cccbb092a3fa8730d4a0bdb)
1cc70d84cSBrian Feldman /**
2cc70d84cSBrian Feldman  * Copyright (c) 2000 Dan Papasian.  All rights reserved.
3cc70d84cSBrian Feldman  *
4cc70d84cSBrian Feldman  * Redistribution and use in source and binary forms, with or without
5cc70d84cSBrian Feldman  * modification, are permitted provided that the following conditions
6cc70d84cSBrian Feldman  * are met:
7cc70d84cSBrian Feldman  * 1. Redistributions of source code must retain the above copyright
8cc70d84cSBrian Feldman  *    notice, this list of conditions and the following disclaimer.
9cc70d84cSBrian Feldman  * 2. Redistributions in binary form must reproduce the above copyright
10cc70d84cSBrian Feldman  *    notice, this list of conditions and the following disclaimer in the
11cc70d84cSBrian Feldman  *    documentation and/or other materials provided with the distribution.
12cc70d84cSBrian Feldman  * 3. The name of the author may not be used to endorse or promote products
13cc70d84cSBrian Feldman  *    derived from this software without specific prior written permission.
14cc70d84cSBrian Feldman  *
15cc70d84cSBrian Feldman  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16cc70d84cSBrian Feldman  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17cc70d84cSBrian Feldman  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18cc70d84cSBrian Feldman  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19cc70d84cSBrian Feldman  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20cc70d84cSBrian Feldman  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21cc70d84cSBrian Feldman  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22cc70d84cSBrian Feldman  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23cc70d84cSBrian Feldman  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24cc70d84cSBrian Feldman  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25cc70d84cSBrian Feldman  */
26cc70d84cSBrian Feldman 
271c6cde4bSMark Murray #include <sys/cdefs.h>
281c6cde4bSMark Murray 
291c6cde4bSMark Murray __FBSDID("$FreeBSD$");
301c6cde4bSMark Murray 
31cc70d84cSBrian Feldman #include <sys/stat.h>
32cc70d84cSBrian Feldman #include <sys/param.h>
33cc70d84cSBrian Feldman 
34cc70d84cSBrian Feldman #include <err.h>
35cc70d84cSBrian Feldman #include <stdio.h>
36cc70d84cSBrian Feldman #include <stdlib.h>
37cc70d84cSBrian Feldman #include <string.h>
38cc70d84cSBrian Feldman #include <unistd.h>
39cc70d84cSBrian Feldman 
40cc70d84cSBrian Feldman static void	 usage(void);
41cc70d84cSBrian Feldman static int	 print_matches(char *, char *);
42cc70d84cSBrian Feldman 
43cc70d84cSBrian Feldman int 	silent;
44cc70d84cSBrian Feldman int 	allpaths;
45cc70d84cSBrian Feldman 
46cc70d84cSBrian Feldman int
47cc70d84cSBrian Feldman main(int argc, char **argv)
48cc70d84cSBrian Feldman {
49cc70d84cSBrian Feldman 	char *p, *path;
50cc70d84cSBrian Feldman 	ssize_t pathlen;
51cc70d84cSBrian Feldman 	int opt, status;
52cc70d84cSBrian Feldman 
53cc70d84cSBrian Feldman 	status = EXIT_SUCCESS;
54cc70d84cSBrian Feldman 
55cc70d84cSBrian Feldman 	/* If called without args, die silently to conform */
56cc70d84cSBrian Feldman 	if (argc < 2)
57cc70d84cSBrian Feldman 		exit(EXIT_FAILURE);
58cc70d84cSBrian Feldman 
59cc70d84cSBrian Feldman 	while ((opt = getopt(argc, argv, "as")) != -1) {
60cc70d84cSBrian Feldman 		switch (opt) {
61cc70d84cSBrian Feldman 		case 'a':
62cc70d84cSBrian Feldman 			allpaths = 1;
63cc70d84cSBrian Feldman 			break;
64cc70d84cSBrian Feldman 		case 's':
65cc70d84cSBrian Feldman 			silent = 1;
66cc70d84cSBrian Feldman 			break;
67cc70d84cSBrian Feldman 		default:
68cc70d84cSBrian Feldman 			usage();
69cc70d84cSBrian Feldman 			break;
70cc70d84cSBrian Feldman 		}
71cc70d84cSBrian Feldman 	}
72cc70d84cSBrian Feldman 
73cc70d84cSBrian Feldman 	argv += optind;
74cc70d84cSBrian Feldman 	argc -= optind;
75cc70d84cSBrian Feldman 
76cc70d84cSBrian Feldman 	if ((p = getenv("PATH")) == NULL)
77cc70d84cSBrian Feldman 		exit(EXIT_FAILURE);
78cc70d84cSBrian Feldman 	pathlen = strlen(p) + 1;
79cc70d84cSBrian Feldman 	path = malloc(pathlen);
80cc70d84cSBrian Feldman 	if (path == NULL)
81cc70d84cSBrian Feldman 		err(EXIT_FAILURE, NULL);
82cc70d84cSBrian Feldman 
83cc70d84cSBrian Feldman 	if (argc == 0)
84cc70d84cSBrian Feldman 		status = EXIT_FAILURE;
85cc70d84cSBrian Feldman 
86cc70d84cSBrian Feldman 	while (argc > 0) {
87cc70d84cSBrian Feldman 		memcpy(path, p, pathlen);
88cc70d84cSBrian Feldman 
89f2c819bfSWolfram Schneider 		if (strlen(*argv) >= FILENAME_MAX ||
90cc70d84cSBrian Feldman 		    print_matches(path, *argv) == -1)
91cc70d84cSBrian Feldman 			status = EXIT_FAILURE;
92cc70d84cSBrian Feldman 
93cc70d84cSBrian Feldman 		argv++;
94cc70d84cSBrian Feldman 		argc--;
95cc70d84cSBrian Feldman 	}
96cc70d84cSBrian Feldman 
97cc70d84cSBrian Feldman 	exit(status);
98cc70d84cSBrian Feldman }
99cc70d84cSBrian Feldman 
100cc70d84cSBrian Feldman static void
101cc70d84cSBrian Feldman usage(void)
102cc70d84cSBrian Feldman {
103cc70d84cSBrian Feldman 
104cc70d84cSBrian Feldman 	errx(EXIT_FAILURE, "usage: which [-as] program ...");
105cc70d84cSBrian Feldman }
106cc70d84cSBrian Feldman 
107cc70d84cSBrian Feldman static int
108cc70d84cSBrian Feldman is_there(char *candidate)
109cc70d84cSBrian Feldman {
110cc70d84cSBrian Feldman 	struct stat fin;
111cc70d84cSBrian Feldman 
112cc70d84cSBrian Feldman 	/* XXX work around access(2) false positives for superuser */
113cc70d84cSBrian Feldman 	if (access(candidate, X_OK) == 0 &&
114cc70d84cSBrian Feldman 	    stat(candidate, &fin) == 0 &&
115cc70d84cSBrian Feldman 	    S_ISREG(fin.st_mode) &&
116cc70d84cSBrian Feldman 	    (getuid() != 0 ||
117cc70d84cSBrian Feldman 	    (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) {
118cc70d84cSBrian Feldman 		if (!silent)
119cc70d84cSBrian Feldman 			printf("%s\n", candidate);
120cc70d84cSBrian Feldman 		return (1);
121cc70d84cSBrian Feldman 	}
122cc70d84cSBrian Feldman 	return (0);
123cc70d84cSBrian Feldman }
124cc70d84cSBrian Feldman 
125cc70d84cSBrian Feldman static int
126cc70d84cSBrian Feldman print_matches(char *path, char *filename)
127cc70d84cSBrian Feldman {
128cc70d84cSBrian Feldman 	char candidate[PATH_MAX];
1298c821782STim J. Robbins 	const char *d;
130cc70d84cSBrian Feldman 	int found;
131cc70d84cSBrian Feldman 
132cc70d84cSBrian Feldman 	if (*filename == '/')
133cc70d84cSBrian Feldman 		return (is_there(filename) ? 0 : -1);
134cc70d84cSBrian Feldman 	found = 0;
135cc70d84cSBrian Feldman 	while ((d = strsep(&path, ":")) != NULL) {
1368c821782STim J. Robbins 		if (*d == '\0')
1378c821782STim J. Robbins 			d = ".";
138cc70d84cSBrian Feldman 		if (snprintf(candidate, sizeof(candidate), "%s/%s", d,
1391c6cde4bSMark Murray 		    filename) >= (int)sizeof(candidate))
140cc70d84cSBrian Feldman 			continue;
141cc70d84cSBrian Feldman 		if (is_there(candidate)) {
142cc70d84cSBrian Feldman 			found = 1;
143cc70d84cSBrian Feldman 			if (!allpaths)
144cc70d84cSBrian Feldman 				break;
145cc70d84cSBrian Feldman 		}
146cc70d84cSBrian Feldman 	}
147cc70d84cSBrian Feldman 	return (found ? 0 : -1);
148cc70d84cSBrian Feldman }
149cc70d84cSBrian Feldman 
150