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/stat.h> 32cc70d84cSBrian Feldman #include <sys/param.h> 33cc70d84cSBrian Feldman 34cc70d84cSBrian Feldman #include <err.h> 35cc70d84cSBrian Feldman #include <stdio.h> 36cc70d84cSBrian Feldman #include <stdlib.h> 37cc70d84cSBrian Feldman #include <string.h> 38cc70d84cSBrian Feldman #include <unistd.h> 39cc70d84cSBrian Feldman 40cc70d84cSBrian Feldman static void usage(void); 41cc70d84cSBrian Feldman static int print_matches(char *, char *); 42cc70d84cSBrian Feldman 43cc70d84cSBrian Feldman int silent; 44cc70d84cSBrian Feldman int allpaths; 45cc70d84cSBrian Feldman 46cc70d84cSBrian Feldman int 47cc70d84cSBrian Feldman main(int argc, char **argv) 48cc70d84cSBrian Feldman { 49cc70d84cSBrian Feldman char *p, *path; 50cc70d84cSBrian Feldman ssize_t pathlen; 51cc70d84cSBrian Feldman int opt, status; 52cc70d84cSBrian Feldman 53cc70d84cSBrian Feldman status = EXIT_SUCCESS; 54cc70d84cSBrian Feldman 55cc70d84cSBrian Feldman /* If called without args, die silently to conform */ 56cc70d84cSBrian Feldman if (argc < 2) 57cc70d84cSBrian Feldman exit(EXIT_FAILURE); 58cc70d84cSBrian Feldman 59cc70d84cSBrian Feldman while ((opt = getopt(argc, argv, "as")) != -1) { 60cc70d84cSBrian Feldman switch (opt) { 61cc70d84cSBrian Feldman case 'a': 62cc70d84cSBrian Feldman allpaths = 1; 63cc70d84cSBrian Feldman break; 64cc70d84cSBrian Feldman case 's': 65cc70d84cSBrian Feldman silent = 1; 66cc70d84cSBrian Feldman break; 67cc70d84cSBrian Feldman default: 68cc70d84cSBrian Feldman usage(); 69cc70d84cSBrian Feldman break; 70cc70d84cSBrian Feldman } 71cc70d84cSBrian Feldman } 72cc70d84cSBrian Feldman 73cc70d84cSBrian Feldman argv += optind; 74cc70d84cSBrian Feldman argc -= optind; 75cc70d84cSBrian Feldman 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 if (argc == 0) 84cc70d84cSBrian Feldman status = EXIT_FAILURE; 85cc70d84cSBrian Feldman 86cc70d84cSBrian Feldman while (argc > 0) { 87cc70d84cSBrian Feldman memcpy(path, p, pathlen); 88cc70d84cSBrian Feldman 89f2c819bfSWolfram Schneider if (strlen(*argv) >= FILENAME_MAX || 90cc70d84cSBrian Feldman print_matches(path, *argv) == -1) 91cc70d84cSBrian Feldman status = EXIT_FAILURE; 92cc70d84cSBrian Feldman 93cc70d84cSBrian Feldman argv++; 94cc70d84cSBrian Feldman argc--; 95cc70d84cSBrian Feldman } 96cc70d84cSBrian Feldman 97cc70d84cSBrian Feldman exit(status); 98cc70d84cSBrian Feldman } 99cc70d84cSBrian Feldman 100cc70d84cSBrian Feldman static void 101cc70d84cSBrian Feldman usage(void) 102cc70d84cSBrian Feldman { 103cc70d84cSBrian Feldman 104cc70d84cSBrian Feldman errx(EXIT_FAILURE, "usage: which [-as] program ..."); 105cc70d84cSBrian Feldman } 106cc70d84cSBrian Feldman 107cc70d84cSBrian Feldman static int 108cc70d84cSBrian Feldman is_there(char *candidate) 109cc70d84cSBrian Feldman { 110cc70d84cSBrian Feldman struct stat fin; 111cc70d84cSBrian Feldman 112cc70d84cSBrian Feldman /* XXX work around access(2) false positives for superuser */ 113cc70d84cSBrian Feldman if (access(candidate, X_OK) == 0 && 114cc70d84cSBrian Feldman stat(candidate, &fin) == 0 && 115cc70d84cSBrian Feldman S_ISREG(fin.st_mode) && 116cc70d84cSBrian Feldman (getuid() != 0 || 117cc70d84cSBrian Feldman (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) { 118cc70d84cSBrian Feldman if (!silent) 119cc70d84cSBrian Feldman printf("%s\n", candidate); 120cc70d84cSBrian Feldman return (1); 121cc70d84cSBrian Feldman } 122cc70d84cSBrian Feldman return (0); 123cc70d84cSBrian Feldman } 124cc70d84cSBrian Feldman 125cc70d84cSBrian Feldman static int 126cc70d84cSBrian Feldman print_matches(char *path, char *filename) 127cc70d84cSBrian Feldman { 128cc70d84cSBrian Feldman char candidate[PATH_MAX]; 1298c821782STim J. Robbins const char *d; 130cc70d84cSBrian Feldman int found; 131cc70d84cSBrian Feldman 132cc70d84cSBrian Feldman if (*filename == '/') 133cc70d84cSBrian Feldman return (is_there(filename) ? 0 : -1); 134cc70d84cSBrian Feldman found = 0; 135cc70d84cSBrian Feldman while ((d = strsep(&path, ":")) != NULL) { 1368c821782STim J. Robbins if (*d == '\0') 1378c821782STim J. Robbins d = "."; 138cc70d84cSBrian Feldman if (snprintf(candidate, sizeof(candidate), "%s/%s", d, 1391c6cde4bSMark Murray filename) >= (int)sizeof(candidate)) 140cc70d84cSBrian Feldman continue; 141cc70d84cSBrian Feldman if (is_there(candidate)) { 142cc70d84cSBrian Feldman found = 1; 143cc70d84cSBrian Feldman if (!allpaths) 144cc70d84cSBrian Feldman break; 145cc70d84cSBrian Feldman } 146cc70d84cSBrian Feldman } 147cc70d84cSBrian Feldman return (found ? 0 : -1); 148cc70d84cSBrian Feldman } 149cc70d84cSBrian Feldman 150