165226Sgreen/** 265226Sgreen * Copyright (c) 2000 Dan Papasian. All rights reserved. 365226Sgreen * 465226Sgreen * Redistribution and use in source and binary forms, with or without 565226Sgreen * modification, are permitted provided that the following conditions 665226Sgreen * are met: 765226Sgreen * 1. Redistributions of source code must retain the above copyright 865226Sgreen * notice, this list of conditions and the following disclaimer. 965226Sgreen * 2. Redistributions in binary form must reproduce the above copyright 1065226Sgreen * notice, this list of conditions and the following disclaimer in the 1165226Sgreen * documentation and/or other materials provided with the distribution. 1265226Sgreen * 3. The name of the author may not be used to endorse or promote products 1365226Sgreen * derived from this software without specific prior written permission. 1465226Sgreen * 1565226Sgreen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1665226Sgreen * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1765226Sgreen * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1865226Sgreen * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1965226Sgreen * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2065226Sgreen * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2165226Sgreen * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2265226Sgreen * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2365226Sgreen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2465226Sgreen * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2565226Sgreen */ 2665226Sgreen 2787678Smarkm#include <sys/cdefs.h> 2887678Smarkm 2987678Smarkm__FBSDID("$FreeBSD: stable/10/usr.bin/which/which.c 320722 2017-07-06 05:59:27Z ngie $"); 3087678Smarkm 31320722Sngie#include <sys/param.h> 3265226Sgreen#include <sys/stat.h> 3365226Sgreen#include <err.h> 3465226Sgreen#include <stdio.h> 3565226Sgreen#include <stdlib.h> 3665226Sgreen#include <string.h> 3765226Sgreen#include <unistd.h> 3865226Sgreen 3965226Sgreenstatic void usage(void); 4065226Sgreenstatic int print_matches(char *, char *); 41318609Sngie 42227245Sedstatic int silent; 43227245Sedstatic int allpaths; 4465226Sgreen 4565226Sgreenint 4665226Sgreenmain(int argc, char **argv) 4765226Sgreen{ 4865226Sgreen char *p, *path; 4965226Sgreen ssize_t pathlen; 5065226Sgreen int opt, status; 5165226Sgreen 5265226Sgreen status = EXIT_SUCCESS; 5365226Sgreen 5465226Sgreen while ((opt = getopt(argc, argv, "as")) != -1) { 5565226Sgreen switch (opt) { 5665226Sgreen case 'a': 5765226Sgreen allpaths = 1; 5865226Sgreen break; 5965226Sgreen case 's': 6065226Sgreen silent = 1; 6165226Sgreen break; 6265226Sgreen default: 6365226Sgreen usage(); 6465226Sgreen break; 6565226Sgreen } 6665226Sgreen } 6765226Sgreen 6865226Sgreen argv += optind; 6965226Sgreen argc -= optind; 7065226Sgreen 71141656Sru if (argc == 0) 72141656Sru usage(); 73141656Sru 7465226Sgreen if ((p = getenv("PATH")) == NULL) 7565226Sgreen exit(EXIT_FAILURE); 7665226Sgreen pathlen = strlen(p) + 1; 7765226Sgreen path = malloc(pathlen); 7865226Sgreen if (path == NULL) 7965226Sgreen err(EXIT_FAILURE, NULL); 8065226Sgreen 8165226Sgreen while (argc > 0) { 8265226Sgreen memcpy(path, p, pathlen); 83318609Sngie 8491945Swosch if (strlen(*argv) >= FILENAME_MAX || 8565226Sgreen print_matches(path, *argv) == -1) 8665226Sgreen status = EXIT_FAILURE; 8765226Sgreen 8865226Sgreen argv++; 8965226Sgreen argc--; 9065226Sgreen } 9165226Sgreen 9265226Sgreen exit(status); 9365226Sgreen} 9465226Sgreen 9565226Sgreenstatic void 9665226Sgreenusage(void) 9765226Sgreen{ 9865226Sgreen 99141656Sru (void)fprintf(stderr, "usage: which [-as] program ...\n"); 100141656Sru exit(EXIT_FAILURE); 10165226Sgreen} 10265226Sgreen 10365226Sgreenstatic int 10465226Sgreenis_there(char *candidate) 10565226Sgreen{ 10665226Sgreen struct stat fin; 10765226Sgreen 10865226Sgreen /* XXX work around access(2) false positives for superuser */ 10965226Sgreen if (access(candidate, X_OK) == 0 && 11065226Sgreen stat(candidate, &fin) == 0 && 11165226Sgreen S_ISREG(fin.st_mode) && 11265226Sgreen (getuid() != 0 || 11365226Sgreen (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) { 11465226Sgreen if (!silent) 11565226Sgreen printf("%s\n", candidate); 11665226Sgreen return (1); 11765226Sgreen } 11865226Sgreen return (0); 11965226Sgreen} 12065226Sgreen 12165226Sgreenstatic int 12265226Sgreenprint_matches(char *path, char *filename) 12365226Sgreen{ 12465226Sgreen char candidate[PATH_MAX]; 12599118Stjr const char *d; 12665226Sgreen int found; 12765226Sgreen 12899120Stjr if (strchr(filename, '/') != NULL) 12965226Sgreen return (is_there(filename) ? 0 : -1); 13065226Sgreen found = 0; 13165226Sgreen while ((d = strsep(&path, ":")) != NULL) { 13299118Stjr if (*d == '\0') 13399118Stjr d = "."; 13465226Sgreen if (snprintf(candidate, sizeof(candidate), "%s/%s", d, 13587678Smarkm filename) >= (int)sizeof(candidate)) 13665226Sgreen continue; 13765226Sgreen if (is_there(candidate)) { 13865226Sgreen found = 1; 13965226Sgreen if (!allpaths) 14065226Sgreen break; 14165226Sgreen } 14265226Sgreen } 14365226Sgreen return (found ? 0 : -1); 14465226Sgreen} 14565226Sgreen 146