xref: /freebsd/usr.bin/which/which.c (revision cc70d84c4a6b6e1c0224bbdfd5bd306252d9fb4f)
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  * $FreeBSD$
27cc70d84cSBrian Feldman  */
28cc70d84cSBrian Feldman 
29cc70d84cSBrian Feldman #include <sys/stat.h>
30cc70d84cSBrian Feldman #include <sys/param.h>
31cc70d84cSBrian Feldman 
32cc70d84cSBrian Feldman #include <err.h>
33cc70d84cSBrian Feldman #include <stdio.h>
34cc70d84cSBrian Feldman #include <stdlib.h>
35cc70d84cSBrian Feldman #include <string.h>
36cc70d84cSBrian Feldman #include <unistd.h>
37cc70d84cSBrian Feldman 
38cc70d84cSBrian Feldman static void	 usage(void);
39cc70d84cSBrian Feldman static int	 print_matches(char *, char *);
40cc70d84cSBrian Feldman 
41cc70d84cSBrian Feldman int 	silent;
42cc70d84cSBrian Feldman int 	allpaths;
43cc70d84cSBrian Feldman 
44cc70d84cSBrian Feldman int
45cc70d84cSBrian Feldman main(int argc, char **argv)
46cc70d84cSBrian Feldman {
47cc70d84cSBrian Feldman 	char *p, *path;
48cc70d84cSBrian Feldman 	ssize_t pathlen;
49cc70d84cSBrian Feldman 	int opt, status;
50cc70d84cSBrian Feldman 
51cc70d84cSBrian Feldman 	status = EXIT_SUCCESS;
52cc70d84cSBrian Feldman 
53cc70d84cSBrian Feldman 	/* If called without args, die silently to conform */
54cc70d84cSBrian Feldman 	if (argc < 2)
55cc70d84cSBrian Feldman 		exit(EXIT_FAILURE);
56cc70d84cSBrian Feldman 
57cc70d84cSBrian Feldman 	while ((opt = getopt(argc, argv, "as")) != -1) {
58cc70d84cSBrian Feldman 		switch (opt) {
59cc70d84cSBrian Feldman 		case 'a':
60cc70d84cSBrian Feldman 			allpaths = 1;
61cc70d84cSBrian Feldman 			break;
62cc70d84cSBrian Feldman 		case 's':
63cc70d84cSBrian Feldman 			silent = 1;
64cc70d84cSBrian Feldman 			break;
65cc70d84cSBrian Feldman 		default:
66cc70d84cSBrian Feldman 			usage();
67cc70d84cSBrian Feldman 			break;
68cc70d84cSBrian Feldman 		}
69cc70d84cSBrian Feldman 	}
70cc70d84cSBrian Feldman 
71cc70d84cSBrian Feldman 	argv += optind;
72cc70d84cSBrian Feldman 	argc -= optind;
73cc70d84cSBrian Feldman 
74cc70d84cSBrian Feldman 	if ((p = getenv("PATH")) == NULL)
75cc70d84cSBrian Feldman 		exit(EXIT_FAILURE);
76cc70d84cSBrian Feldman 	pathlen = strlen(p) + 1;
77cc70d84cSBrian Feldman 	path = malloc(pathlen);
78cc70d84cSBrian Feldman 	if (path == NULL)
79cc70d84cSBrian Feldman 		err(EXIT_FAILURE, NULL);
80cc70d84cSBrian Feldman 
81cc70d84cSBrian Feldman 	if (argc == 0)
82cc70d84cSBrian Feldman 		status = EXIT_FAILURE;
83cc70d84cSBrian Feldman 
84cc70d84cSBrian Feldman 	while (argc > 0) {
85cc70d84cSBrian Feldman 		memcpy(path, p, pathlen);
86cc70d84cSBrian Feldman 
87cc70d84cSBrian Feldman 		if (strlen(*argv) > FILENAME_MAX ||
88cc70d84cSBrian Feldman 		    print_matches(path, *argv) == -1)
89cc70d84cSBrian Feldman 			status = EXIT_FAILURE;
90cc70d84cSBrian Feldman 
91cc70d84cSBrian Feldman 		argv++;
92cc70d84cSBrian Feldman 		argc--;
93cc70d84cSBrian Feldman 	}
94cc70d84cSBrian Feldman 
95cc70d84cSBrian Feldman 	exit(status);
96cc70d84cSBrian Feldman }
97cc70d84cSBrian Feldman 
98cc70d84cSBrian Feldman static void
99cc70d84cSBrian Feldman usage(void)
100cc70d84cSBrian Feldman {
101cc70d84cSBrian Feldman 
102cc70d84cSBrian Feldman 	errx(EXIT_FAILURE, "usage: which [-as] program ...");
103cc70d84cSBrian Feldman }
104cc70d84cSBrian Feldman 
105cc70d84cSBrian Feldman static int
106cc70d84cSBrian Feldman is_there(char *candidate)
107cc70d84cSBrian Feldman {
108cc70d84cSBrian Feldman 	struct stat fin;
109cc70d84cSBrian Feldman 
110cc70d84cSBrian Feldman 	/* XXX work around access(2) false positives for superuser */
111cc70d84cSBrian Feldman 	if (access(candidate, X_OK) == 0 &&
112cc70d84cSBrian Feldman 	    stat(candidate, &fin) == 0 &&
113cc70d84cSBrian Feldman 	    S_ISREG(fin.st_mode) &&
114cc70d84cSBrian Feldman 	    (getuid() != 0 ||
115cc70d84cSBrian Feldman 	    (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) {
116cc70d84cSBrian Feldman 		if (!silent)
117cc70d84cSBrian Feldman 			printf("%s\n", candidate);
118cc70d84cSBrian Feldman 		return (1);
119cc70d84cSBrian Feldman 	}
120cc70d84cSBrian Feldman 	return (0);
121cc70d84cSBrian Feldman }
122cc70d84cSBrian Feldman 
123cc70d84cSBrian Feldman static int
124cc70d84cSBrian Feldman print_matches(char *path, char *filename)
125cc70d84cSBrian Feldman {
126cc70d84cSBrian Feldman 	char candidate[PATH_MAX];
127cc70d84cSBrian Feldman 	char *d;
128cc70d84cSBrian Feldman 	int found;
129cc70d84cSBrian Feldman 
130cc70d84cSBrian Feldman 	if (*filename == '/')
131cc70d84cSBrian Feldman 		return (is_there(filename) ? 0 : -1);
132cc70d84cSBrian Feldman 	found = 0;
133cc70d84cSBrian Feldman 	while ((d = strsep(&path, ":")) != NULL) {
134cc70d84cSBrian Feldman 		if (snprintf(candidate, sizeof(candidate), "%s/%s", d,
135cc70d84cSBrian Feldman 		    filename) >= sizeof(candidate))
136cc70d84cSBrian Feldman 			continue;
137cc70d84cSBrian Feldman 		if (is_there(candidate)) {
138cc70d84cSBrian Feldman 			found = 1;
139cc70d84cSBrian Feldman 			if (!allpaths)
140cc70d84cSBrian Feldman 				break;
141cc70d84cSBrian Feldman 		}
142cc70d84cSBrian Feldman 	}
143cc70d84cSBrian Feldman 	return (found ? 0 : -1);
144cc70d84cSBrian Feldman }
145cc70d84cSBrian Feldman 
146