1156608Sdeischen/*- 2156608Sdeischen * SPDX-License-Identifier: BSD-3-Clause 3156608Sdeischen * 4156608Sdeischen * Copyright (c) 2000 Dan Papasian. All rights reserved. 5156608Sdeischen * 6156608Sdeischen * Redistribution and use in source and binary forms, with or without 7156608Sdeischen * modification, are permitted provided that the following conditions 8156608Sdeischen * are met: 9156608Sdeischen * 1. Redistributions of source code must retain the above copyright 10156608Sdeischen * notice, this list of conditions and the following disclaimer. 11156608Sdeischen * 2. Redistributions in binary form must reproduce the above copyright 12156608Sdeischen * notice, this list of conditions and the following disclaimer in the 13156608Sdeischen * documentation and/or other materials provided with the distribution. 14156608Sdeischen * 3. The name of the author may not be used to endorse or promote products 15156608Sdeischen * derived from this software without specific prior written permission. 16156608Sdeischen * 17156608Sdeischen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18156608Sdeischen * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19156608Sdeischen * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20156608Sdeischen * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21156608Sdeischen * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22156608Sdeischen * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23156608Sdeischen * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24156608Sdeischen * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25156608Sdeischen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26156608Sdeischen * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27156608Sdeischen */ 28156608Sdeischen 29156608Sdeischen#include <sys/cdefs.h> 30156608Sdeischen 31156608Sdeischen__FBSDID("$FreeBSD: stable/11/usr.bin/which/which.c 330449 2018-03-05 07:26:05Z eadler $"); 32156608Sdeischen 33156608Sdeischen#include <sys/param.h> 34156608Sdeischen#include <sys/stat.h> 35156608Sdeischen#include <err.h> 36156608Sdeischen#include <stdio.h> 37156608Sdeischen#include <stdlib.h> 38156608Sdeischen#include <string.h> 39156608Sdeischen#include <unistd.h> 40156608Sdeischen 41156608Sdeischenstatic void usage(void); 42156608Sdeischenstatic int print_matches(char *, char *); 43156608Sdeischen 44156608Sdeischenstatic int silent; 45156608Sdeischenstatic int allpaths; 46156608Sdeischen 47156608Sdeischenint 48156608Sdeischenmain(int argc, char **argv) 49156608Sdeischen{ 50156608Sdeischen char *p, *path; 51156608Sdeischen ssize_t pathlen; 52156608Sdeischen int opt, status; 53156608Sdeischen 54156608Sdeischen status = EXIT_SUCCESS; 55156608Sdeischen 56156608Sdeischen while ((opt = getopt(argc, argv, "as")) != -1) { 57156608Sdeischen switch (opt) { 58156608Sdeischen case 'a': 59156608Sdeischen allpaths = 1; 60156608Sdeischen break; 61156608Sdeischen case 's': 62156608Sdeischen silent = 1; 63156608Sdeischen break; 64156608Sdeischen default: 65156608Sdeischen usage(); 66156608Sdeischen break; 67156608Sdeischen } 68156608Sdeischen } 69156608Sdeischen 70156608Sdeischen argv += optind; 71156608Sdeischen argc -= optind; 72156608Sdeischen 73156608Sdeischen if (argc == 0) 74156608Sdeischen usage(); 75156608Sdeischen 76156608Sdeischen if ((p = getenv("PATH")) == NULL) 77156608Sdeischen exit(EXIT_FAILURE); 78156608Sdeischen pathlen = strlen(p) + 1; 79156608Sdeischen path = malloc(pathlen); 80156608Sdeischen if (path == NULL) 81156608Sdeischen err(EXIT_FAILURE, NULL); 82156608Sdeischen 83156608Sdeischen while (argc > 0) { 84156608Sdeischen memcpy(path, p, pathlen); 85156608Sdeischen 86156608Sdeischen if (strlen(*argv) >= FILENAME_MAX || 87156608Sdeischen print_matches(path, *argv) == -1) 88156608Sdeischen status = EXIT_FAILURE; 89156608Sdeischen 90156608Sdeischen argv++; 91156608Sdeischen argc--; 92156608Sdeischen } 93156608Sdeischen 94156608Sdeischen exit(status); 95156608Sdeischen} 96156608Sdeischen 97156608Sdeischenstatic void 98156608Sdeischenusage(void) 99156608Sdeischen{ 100156608Sdeischen 101156608Sdeischen (void)fprintf(stderr, "usage: which [-as] program ...\n"); 102156608Sdeischen exit(EXIT_FAILURE); 103156608Sdeischen} 104156608Sdeischen 105156608Sdeischenstatic int 106156608Sdeischenis_there(char *candidate) 107156608Sdeischen{ 108156608Sdeischen struct stat fin; 109156608Sdeischen 110156608Sdeischen /* XXX work around access(2) false positives for superuser */ 111156608Sdeischen if (access(candidate, X_OK) == 0 && 112156608Sdeischen stat(candidate, &fin) == 0 && 113156608Sdeischen S_ISREG(fin.st_mode) && 114156608Sdeischen (getuid() != 0 || 115156608Sdeischen (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) { 116156608Sdeischen if (!silent) 117156608Sdeischen printf("%s\n", candidate); 118156608Sdeischen return (1); 119156608Sdeischen } 120156608Sdeischen return (0); 121156608Sdeischen} 122156608Sdeischen 123156608Sdeischenstatic int 124156608Sdeischenprint_matches(char *path, char *filename) 125156608Sdeischen{ 126156608Sdeischen char candidate[PATH_MAX]; 127156608Sdeischen const char *d; 128156608Sdeischen int found; 129156608Sdeischen 130156608Sdeischen if (strchr(filename, '/') != NULL) 131156608Sdeischen return (is_there(filename) ? 0 : -1); 132156608Sdeischen found = 0; 133156608Sdeischen while ((d = strsep(&path, ":")) != NULL) { 134156608Sdeischen if (*d == '\0') 135156608Sdeischen d = "."; 136156608Sdeischen if (snprintf(candidate, sizeof(candidate), "%s/%s", d, 137156608Sdeischen filename) >= (int)sizeof(candidate)) 138156608Sdeischen continue; 139156608Sdeischen if (is_there(candidate)) { 140156608Sdeischen found = 1; 141156608Sdeischen if (!allpaths) 142156608Sdeischen break; 143156608Sdeischen } 144156608Sdeischen } 145156608Sdeischen return (found ? 0 : -1); 146156608Sdeischen} 147156608Sdeischen 148156608Sdeischen