summaryrefslogtreecommitdiff
path: root/misc-utils/whereis.c
diff options
context:
space:
mode:
Diffstat (limited to 'misc-utils/whereis.c')
-rw-r--r--misc-utils/whereis.c485
1 files changed, 485 insertions, 0 deletions
diff --git a/misc-utils/whereis.c b/misc-utils/whereis.c
new file mode 100644
index 0000000..05af8e0
--- /dev/null
+++ b/misc-utils/whereis.c
@@ -0,0 +1,485 @@
+/*-
+ * Copyright (c) 1980 The Regents of the University of California.
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+/* *:aeb */
+
+/* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
+ * - added Native Language Support
+ */
+
+/* 2011-08-12 Davidlohr Bueso <dave@gnu.org>
+ * - added $PATH lookup
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "xalloc.h"
+#include "nls.h"
+#include "c.h"
+#include "closestream.h"
+
+static char *bindirs[] = {
+ "/bin",
+ "/usr/bin",
+ "/sbin",
+ "/usr/sbin",
+ "/etc",
+ "/usr/etc",
+ "/lib",
+ "/usr/lib",
+ "/lib64",
+ "/usr/lib64",
+ "/usr/games",
+ "/usr/games/bin",
+ "/usr/games/lib",
+ "/usr/emacs/etc",
+ "/usr/lib/emacs/*/etc",
+ "/usr/TeX/bin",
+ "/usr/tex/bin",
+ "/usr/interviews/bin/LINUX",
+
+ "/usr/X11R6/bin",
+ "/usr/X386/bin",
+ "/usr/bin/X11",
+ "/usr/X11/bin",
+ "/usr/X11R5/bin",
+
+ "/usr/local/bin",
+ "/usr/local/sbin",
+ "/usr/local/etc",
+ "/usr/local/lib",
+ "/usr/local/games",
+ "/usr/local/games/bin",
+ "/usr/local/emacs/etc",
+ "/usr/local/TeX/bin",
+ "/usr/local/tex/bin",
+ "/usr/local/bin/X11",
+
+ "/usr/contrib",
+ "/usr/hosts",
+ "/usr/include",
+
+ "/usr/g++-include",
+
+ "/usr/ucb",
+ "/usr/old",
+ "/usr/new",
+ "/usr/local",
+ "/usr/libexec",
+ "/usr/share",
+
+ "/opt/*/bin",
+
+ 0
+};
+
+static char *mandirs[] = {
+ "/usr/man/*",
+ "/usr/share/man/*",
+ "/usr/X386/man/*",
+ "/usr/X11/man/*",
+ "/usr/TeX/man/*",
+ "/usr/interviews/man/mann",
+ 0
+};
+
+static char *srcdirs[] = {
+ "/usr/src/*",
+ "/usr/src/lib/libc/*",
+ "/usr/src/lib/libc/net/*",
+ "/usr/src/ucb/pascal",
+ "/usr/src/ucb/pascal/utilities",
+ "/usr/src/undoc",
+ 0
+};
+
+static char sflag = 1, bflag = 1, mflag = 1, uflag;
+static char **Sflag, **Bflag, **Mflag, **pathdir, **pathdir_p;
+static int Scnt, Bcnt, Mcnt, count, print;
+
+static void __attribute__ ((__noreturn__)) usage(FILE * out)
+{
+ fputs(_("\nUsage:\n"), out);
+ fprintf(out,
+ _(" %s [options] file\n"), program_invocation_short_name);
+
+ fputs(_("\nOptions:\n"), out);
+ fputs(_(" -f <file> define search scope\n"
+ " -b search only binaries\n"
+ " -B <dirs> define binaries lookup path\n"
+ " -m search only manual paths\n"
+ " -M <dirs> define man lookup path\n"
+ " -s search only sources path\n"
+ " -S <dirs> define sources lookup path\n"
+ " -u search from unusual entities\n"
+ " -V output version information and exit\n"
+ " -h display this help and exit\n\n"), out);
+
+ fputs(_("See how to use file and dirs arguments from whereis(1) manual.\n"), out);
+ exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
+static int
+itsit(char *cp, char *dp)
+{
+ int i = strlen(dp);
+
+ if (dp[0] == 's' && dp[1] == '.' && itsit(cp, dp + 2))
+ return 1;
+ if (!strcmp(dp + i - 2, ".Z"))
+ i -= 2;
+ else if (!strcmp(dp + i - 3, ".gz"))
+ i -= 3;
+ else if (!strcmp(dp + i - 4, ".bz2"))
+ i -= 4;
+ while (*cp && *dp && *cp == *dp)
+ cp++, dp++, i--;
+ if (*cp == 0 && *dp == 0)
+ return 1;
+ while (isdigit(*dp))
+ dp++;
+ if (*cp == 0 && *dp++ == '.') {
+ --i;
+ while (i > 0 && *dp)
+ if (--i, *dp++ == '.')
+ return (*dp++ == 'C' && *dp++ == 0);
+ return 1;
+ }
+ return 0;
+}
+
+static void
+findin(char *dir, char *cp)
+{
+ DIR *dirp;
+ struct dirent *dp;
+ char *d, *dd;
+ size_t l;
+ char dirbuf[1024];
+ struct stat statbuf;
+
+ dd = strchr(dir, '*');
+ if (!dd) {
+ dirp = opendir(dir);
+ if (dirp == NULL)
+ return;
+ while ((dp = readdir(dirp)) != NULL) {
+ if (itsit(cp, dp->d_name)) {
+ count++;
+ if (print)
+ printf(" %s/%s", dir, dp->d_name);
+ }
+ }
+ closedir(dirp);
+ return;
+ }
+
+ l = strlen(dir);
+ if (l < sizeof(dirbuf)) {
+ /* refuse excessively long names */
+ strcpy(dirbuf, dir);
+ d = strchr(dirbuf, '*');
+ *d = 0;
+ dirp = opendir(dirbuf);
+ if (dirp == NULL)
+ return;
+ while ((dp = readdir(dirp)) != NULL) {
+ if (!strcmp(dp->d_name, ".") ||
+ !strcmp(dp->d_name, ".."))
+ continue;
+ if (strlen(dp->d_name) + l > sizeof(dirbuf))
+ continue;
+ sprintf(d, "%s", dp->d_name);
+ if (stat(dirbuf, &statbuf))
+ continue;
+ if (!S_ISDIR(statbuf.st_mode))
+ continue;
+ strcat(d, dd + 1);
+ findin(dirbuf, cp);
+ }
+ closedir(dirp);
+ }
+ return;
+
+}
+
+static int inpath(const char *str)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(bindirs) - 1 ; i++)
+ if (!strcmp(bindirs[i], str))
+ return 1;
+
+ for (i = 0; i < ARRAY_SIZE(mandirs) - 1; i++)
+ if (!strcmp(mandirs[i], str))
+ return 1;
+
+ for (i = 0; i < ARRAY_SIZE(srcdirs) - 1; i++)
+ if (!strcmp(srcdirs[i], str))
+ return 1;
+
+ return 0;
+}
+
+static void fillpath(void)
+{
+ char *key=NULL, *tok=NULL, *pathcp, *path = getenv("PATH");
+ int i = 0;
+
+
+ if (!path)
+ return;
+ pathcp = xstrdup(path);
+
+ for (tok = strtok_r(pathcp, ":", &key); tok;
+ tok = strtok_r(NULL, ":", &key)) {
+
+ /* make sure we don't repeat the search path */
+ if (inpath(tok))
+ continue;
+
+ pathdir = xrealloc(pathdir, (i + 1) * sizeof(char *));
+ pathdir[i++] = xstrdup(tok);
+ }
+
+ pathdir = xrealloc(pathdir, (i + 1) * sizeof(char *));
+ pathdir[i] = NULL;
+
+ pathdir_p = pathdir;
+ free(pathcp);
+}
+
+static void freepath(void)
+{
+ free(pathdir);
+}
+
+static void
+findv(char **dirv, int dirc, char *cp)
+{
+
+ while (dirc > 0)
+ findin(*dirv++, cp), dirc--;
+}
+
+static void
+looksrc(char *cp)
+{
+ if (Sflag == 0)
+ findv(srcdirs, ARRAY_SIZE(srcdirs)-1, cp);
+ else
+ findv(Sflag, Scnt, cp);
+}
+
+static void
+lookbin(char *cp)
+{
+ if (Bflag == 0) {
+ findv(bindirs, ARRAY_SIZE(bindirs)-1, cp);
+ while (*pathdir_p)
+ findin(*pathdir_p++, cp); /* look $PATH */
+ } else
+ findv(Bflag, Bcnt, cp);
+}
+
+static void
+lookman(char *cp)
+{
+ if (Mflag == 0)
+ findv(mandirs, ARRAY_SIZE(mandirs)-1, cp);
+ else
+ findv(Mflag, Mcnt, cp);
+}
+
+static void
+getlist(int *argcp, char ***argvp, char ***flagp, int *cntp)
+{
+ (*argvp)++;
+ *flagp = *argvp;
+ *cntp = 0;
+ for ((*argcp)--; *argcp > 0 && (*argvp)[0][0] != '-'; (*argcp)--)
+ (*cntp)++, (*argvp)++;
+ (*argcp)++;
+ (*argvp)--;
+}
+
+static void
+zerof(void)
+{
+ if (sflag && bflag && mflag)
+ sflag = bflag = mflag = 0;
+}
+
+static int
+print_again(char *cp)
+{
+ if (print)
+ printf("%s:", cp);
+ if (sflag) {
+ looksrc(cp);
+ if (uflag && print == 0 && count != 1) {
+ print = 1;
+ return 1;
+ }
+ }
+ count = 0;
+ if (bflag) {
+ lookbin(cp);
+ if (uflag && print == 0 && count != 1) {
+ print = 1;
+ return 1;
+ }
+ }
+ count = 0;
+ if (mflag) {
+ lookman(cp);
+ if (uflag && print == 0 && count != 1) {
+ print = 1;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void
+lookup(char *cp)
+{
+ register char *dp;
+
+ for (dp = cp; *dp; dp++)
+ continue;
+ for (; dp > cp; dp--) {
+ if (*dp == '.') {
+ *dp = 0;
+ break;
+ }
+ }
+ for (dp = cp; *dp; dp++)
+ if (*dp == '/')
+ cp = dp + 1;
+ if (uflag) {
+ print = 0;
+ count = 0;
+ } else
+ print = 1;
+
+ while (print_again(cp))
+ /* all in print_again() */ ;
+
+ if (print)
+ printf("\n");
+}
+
+/*
+ * whereis name
+ * look for source, documentation and binaries
+ */
+int
+main(int argc, char **argv)
+{
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+ atexit(close_stdout);
+
+ argc--, argv++;
+ if (argc == 0)
+ usage(stderr);
+
+ do
+ if (argv[0][0] == '-') {
+ register char *cp = argv[0] + 1;
+ while (*cp) switch (*cp++) {
+
+ case 'f':
+ break;
+
+ case 'S':
+ getlist(&argc, &argv, &Sflag, &Scnt);
+ break;
+
+ case 'B':
+ getlist(&argc, &argv, &Bflag, &Bcnt);
+ break;
+
+ case 'M':
+ getlist(&argc, &argv, &Mflag, &Mcnt);
+ break;
+
+ case 's':
+ zerof();
+ sflag++;
+ continue;
+
+ case 'u':
+ uflag++;
+ continue;
+
+ case 'b':
+ zerof();
+ bflag++;
+ continue;
+
+ case 'm':
+ zerof();
+ mflag++;
+ continue;
+ case 'V':
+ printf(_("%s from %s\n"),
+ program_invocation_short_name,
+ PACKAGE_STRING);
+ return EXIT_SUCCESS;
+ case 'h':
+ usage(stdout);
+ default:
+ usage(stderr);
+ }
+ argv++;
+ } else {
+ if (Bcnt == 0 && pathdir == NULL)
+ fillpath();
+ lookup(*argv++);
+ }
+ while (--argc > 0);
+
+ freepath();
+ return EXIT_SUCCESS;
+}