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