xref: /freebsd/usr.bin/which/which.c (revision 1de7b4b805ddbf2429da511c053686ac4591ed89)
1*1de7b4b8SPedro F. Giffuni /*-
2*1de7b4b8SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
3*1de7b4b8SPedro 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 #include <sys/cdefs.h>
301c6cde4bSMark Murray 
311c6cde4bSMark Murray __FBSDID("$FreeBSD$");
321c6cde4bSMark Murray 
33cc70d84cSBrian Feldman #include <sys/param.h>
34d481fdf2SEnji Cooper #include <sys/stat.h>
35cc70d84cSBrian Feldman #include <err.h>
36cc70d84cSBrian Feldman #include <stdio.h>
37cc70d84cSBrian Feldman #include <stdlib.h>
38cc70d84cSBrian Feldman #include <string.h>
39cc70d84cSBrian Feldman #include <unistd.h>
40cc70d84cSBrian Feldman 
41cc70d84cSBrian Feldman static void	 usage(void);
42cc70d84cSBrian Feldman static int	 print_matches(char *, char *);
43cc70d84cSBrian Feldman 
4494cd9385SEd Schouten static int 	 silent;
4594cd9385SEd Schouten static int 	 allpaths;
46cc70d84cSBrian Feldman 
47cc70d84cSBrian Feldman int
48cc70d84cSBrian Feldman main(int argc, char **argv)
49cc70d84cSBrian Feldman {
50cc70d84cSBrian Feldman 	char *p, *path;
51cc70d84cSBrian Feldman 	ssize_t pathlen;
52cc70d84cSBrian Feldman 	int opt, status;
53cc70d84cSBrian Feldman 
54cc70d84cSBrian Feldman 	status = EXIT_SUCCESS;
55cc70d84cSBrian Feldman 
56cc70d84cSBrian Feldman 	while ((opt = getopt(argc, argv, "as")) != -1) {
57cc70d84cSBrian Feldman 		switch (opt) {
58cc70d84cSBrian Feldman 		case 'a':
59cc70d84cSBrian Feldman 			allpaths = 1;
60cc70d84cSBrian Feldman 			break;
61cc70d84cSBrian Feldman 		case 's':
62cc70d84cSBrian Feldman 			silent = 1;
63cc70d84cSBrian Feldman 			break;
64cc70d84cSBrian Feldman 		default:
65cc70d84cSBrian Feldman 			usage();
66cc70d84cSBrian Feldman 			break;
67cc70d84cSBrian Feldman 		}
68cc70d84cSBrian Feldman 	}
69cc70d84cSBrian Feldman 
70cc70d84cSBrian Feldman 	argv += optind;
71cc70d84cSBrian Feldman 	argc -= optind;
72cc70d84cSBrian Feldman 
73b7a311f2SRuslan Ermilov 	if (argc == 0)
74b7a311f2SRuslan Ermilov 		usage();
75b7a311f2SRuslan Ermilov 
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 	while (argc > 0) {
84cc70d84cSBrian Feldman 		memcpy(path, p, pathlen);
85cc70d84cSBrian Feldman 
86f2c819bfSWolfram Schneider 		if (strlen(*argv) >= FILENAME_MAX ||
87cc70d84cSBrian Feldman 		    print_matches(path, *argv) == -1)
88cc70d84cSBrian Feldman 			status = EXIT_FAILURE;
89cc70d84cSBrian Feldman 
90cc70d84cSBrian Feldman 		argv++;
91cc70d84cSBrian Feldman 		argc--;
92cc70d84cSBrian Feldman 	}
93cc70d84cSBrian Feldman 
94cc70d84cSBrian Feldman 	exit(status);
95cc70d84cSBrian Feldman }
96cc70d84cSBrian Feldman 
97cc70d84cSBrian Feldman static void
98cc70d84cSBrian Feldman usage(void)
99cc70d84cSBrian Feldman {
100cc70d84cSBrian Feldman 
101b7a311f2SRuslan Ermilov 	(void)fprintf(stderr, "usage: which [-as] program ...\n");
102b7a311f2SRuslan Ermilov 	exit(EXIT_FAILURE);
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];
1278c821782STim J. Robbins 	const char *d;
128cc70d84cSBrian Feldman 	int found;
129cc70d84cSBrian Feldman 
130721da592STim J. Robbins 	if (strchr(filename, '/') != NULL)
131cc70d84cSBrian Feldman 		return (is_there(filename) ? 0 : -1);
132cc70d84cSBrian Feldman 	found = 0;
133cc70d84cSBrian Feldman 	while ((d = strsep(&path, ":")) != NULL) {
1348c821782STim J. Robbins 		if (*d == '\0')
1358c821782STim J. Robbins 			d = ".";
136cc70d84cSBrian Feldman 		if (snprintf(candidate, sizeof(candidate), "%s/%s", d,
1371c6cde4bSMark Murray 		    filename) >= (int)sizeof(candidate))
138cc70d84cSBrian Feldman 			continue;
139cc70d84cSBrian Feldman 		if (is_there(candidate)) {
140cc70d84cSBrian Feldman 			found = 1;
141cc70d84cSBrian Feldman 			if (!allpaths)
142cc70d84cSBrian Feldman 				break;
143cc70d84cSBrian Feldman 		}
144cc70d84cSBrian Feldman 	}
145cc70d84cSBrian Feldman 	return (found ? 0 : -1);
146cc70d84cSBrian Feldman }
147cc70d84cSBrian Feldman 
148