/** * Copyright (c) 2000 Dan Papasian. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD: src/usr.bin/which/which.c,v 1.6 2005/02/10 16:04:22 ru Exp $"); #include #include #include #include #include #include #include static void usage(void); static int print_matches(char *, char *); int silent; int allpaths; int main(int argc, char **argv) { char *p, *path; ssize_t pathlen; int opt, status; status = EXIT_SUCCESS; while ((opt = getopt(argc, argv, "as")) != -1) { switch (opt) { case 'a': allpaths = 1; break; case 's': silent = 1; break; default: usage(); break; } } argv += optind; argc -= optind; if (argc == 0) usage(); if ((p = getenv("PATH")) == NULL) exit(EXIT_FAILURE); pathlen = strlen(p) + 1; path = malloc(pathlen); if (path == NULL) err(EXIT_FAILURE, NULL); while (argc > 0) { memcpy(path, p, pathlen); if (strlen(*argv) >= FILENAME_MAX || print_matches(path, *argv) == -1) status = EXIT_FAILURE; argv++; argc--; } exit(status); } static void usage(void) { (void)fprintf(stderr, "usage: which [-as] program ...\n"); exit(EXIT_FAILURE); } static int is_there(char *candidate) { struct stat fin; /* XXX work around access(2) false positives for superuser */ if (access(candidate, X_OK) == 0 && stat(candidate, &fin) == 0 && S_ISREG(fin.st_mode) && (getuid() != 0 || (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) { if (!silent) printf("%s\n", candidate); return (1); } return (0); } static int print_matches(char *path, char *filename) { char candidate[PATH_MAX]; const char *d; int found; if (strchr(filename, '/') != NULL) return (is_there(filename) ? 0 : -1); found = 0; while ((d = strsep(&path, ":")) != NULL) { if (*d == '\0') d = "."; if (snprintf(candidate, sizeof(candidate), "%s/%s", d, filename) >= (int)sizeof(candidate)) continue; if (is_there(candidate)) { found = 1; if (!allpaths) break; } } return (found ? 0 : -1); }