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