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