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