xref: /freebsd/usr.bin/which/which.c (revision d481fdf2247be18c57e1d45a1b1f18d8a8afc77a)
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/param.h>
32*d481fdf2SEnji Cooper #include <sys/stat.h>
33cc70d84cSBrian Feldman #include <err.h>
34cc70d84cSBrian Feldman #include <stdio.h>
35cc70d84cSBrian Feldman #include <stdlib.h>
36cc70d84cSBrian Feldman #include <string.h>
37cc70d84cSBrian Feldman #include <unistd.h>
38cc70d84cSBrian Feldman 
39cc70d84cSBrian Feldman static void	 usage(void);
40cc70d84cSBrian Feldman static int	 print_matches(char *, char *);
41cc70d84cSBrian Feldman 
4294cd9385SEd Schouten static int 	 silent;
4394cd9385SEd Schouten static int 	 allpaths;
44cc70d84cSBrian Feldman 
45cc70d84cSBrian Feldman int
46cc70d84cSBrian Feldman main(int argc, char **argv)
47cc70d84cSBrian Feldman {
48cc70d84cSBrian Feldman 	char *p, *path;
49cc70d84cSBrian Feldman 	ssize_t pathlen;
50cc70d84cSBrian Feldman 	int opt, status;
51cc70d84cSBrian Feldman 
52cc70d84cSBrian Feldman 	status = EXIT_SUCCESS;
53cc70d84cSBrian Feldman 
54cc70d84cSBrian Feldman 	while ((opt = getopt(argc, argv, "as")) != -1) {
55cc70d84cSBrian Feldman 		switch (opt) {
56cc70d84cSBrian Feldman 		case 'a':
57cc70d84cSBrian Feldman 			allpaths = 1;
58cc70d84cSBrian Feldman 			break;
59cc70d84cSBrian Feldman 		case 's':
60cc70d84cSBrian Feldman 			silent = 1;
61cc70d84cSBrian Feldman 			break;
62cc70d84cSBrian Feldman 		default:
63cc70d84cSBrian Feldman 			usage();
64cc70d84cSBrian Feldman 			break;
65cc70d84cSBrian Feldman 		}
66cc70d84cSBrian Feldman 	}
67cc70d84cSBrian Feldman 
68cc70d84cSBrian Feldman 	argv += optind;
69cc70d84cSBrian Feldman 	argc -= optind;
70cc70d84cSBrian Feldman 
71b7a311f2SRuslan Ermilov 	if (argc == 0)
72b7a311f2SRuslan Ermilov 		usage();
73b7a311f2SRuslan Ermilov 
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 	while (argc > 0) {
82cc70d84cSBrian Feldman 		memcpy(path, p, pathlen);
83cc70d84cSBrian Feldman 
84f2c819bfSWolfram Schneider 		if (strlen(*argv) >= FILENAME_MAX ||
85cc70d84cSBrian Feldman 		    print_matches(path, *argv) == -1)
86cc70d84cSBrian Feldman 			status = EXIT_FAILURE;
87cc70d84cSBrian Feldman 
88cc70d84cSBrian Feldman 		argv++;
89cc70d84cSBrian Feldman 		argc--;
90cc70d84cSBrian Feldman 	}
91cc70d84cSBrian Feldman 
92cc70d84cSBrian Feldman 	exit(status);
93cc70d84cSBrian Feldman }
94cc70d84cSBrian Feldman 
95cc70d84cSBrian Feldman static void
96cc70d84cSBrian Feldman usage(void)
97cc70d84cSBrian Feldman {
98cc70d84cSBrian Feldman 
99b7a311f2SRuslan Ermilov 	(void)fprintf(stderr, "usage: which [-as] program ...\n");
100b7a311f2SRuslan Ermilov 	exit(EXIT_FAILURE);
101cc70d84cSBrian Feldman }
102cc70d84cSBrian Feldman 
103cc70d84cSBrian Feldman static int
104cc70d84cSBrian Feldman is_there(char *candidate)
105cc70d84cSBrian Feldman {
106cc70d84cSBrian Feldman 	struct stat fin;
107cc70d84cSBrian Feldman 
108cc70d84cSBrian Feldman 	/* XXX work around access(2) false positives for superuser */
109cc70d84cSBrian Feldman 	if (access(candidate, X_OK) == 0 &&
110cc70d84cSBrian Feldman 	    stat(candidate, &fin) == 0 &&
111cc70d84cSBrian Feldman 	    S_ISREG(fin.st_mode) &&
112cc70d84cSBrian Feldman 	    (getuid() != 0 ||
113cc70d84cSBrian Feldman 	    (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) {
114cc70d84cSBrian Feldman 		if (!silent)
115cc70d84cSBrian Feldman 			printf("%s\n", candidate);
116cc70d84cSBrian Feldman 		return (1);
117cc70d84cSBrian Feldman 	}
118cc70d84cSBrian Feldman 	return (0);
119cc70d84cSBrian Feldman }
120cc70d84cSBrian Feldman 
121cc70d84cSBrian Feldman static int
122cc70d84cSBrian Feldman print_matches(char *path, char *filename)
123cc70d84cSBrian Feldman {
124cc70d84cSBrian Feldman 	char candidate[PATH_MAX];
1258c821782STim J. Robbins 	const char *d;
126cc70d84cSBrian Feldman 	int found;
127cc70d84cSBrian Feldman 
128721da592STim J. Robbins 	if (strchr(filename, '/') != NULL)
129cc70d84cSBrian Feldman 		return (is_there(filename) ? 0 : -1);
130cc70d84cSBrian Feldman 	found = 0;
131cc70d84cSBrian Feldman 	while ((d = strsep(&path, ":")) != NULL) {
1328c821782STim J. Robbins 		if (*d == '\0')
1338c821782STim J. Robbins 			d = ".";
134cc70d84cSBrian Feldman 		if (snprintf(candidate, sizeof(candidate), "%s/%s", d,
1351c6cde4bSMark Murray 		    filename) >= (int)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