"/usr/X11/man/*", "/usr/TeX/man/*", "/usr/intervIEws/man/mann", "/usr/share/info", NULL }; static const 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", NULL }; static void whereis_init_debug(void) { __UL_INIT_DEBUG(whereis, WHEREIS_DEBUG_, 0, WHEREIS_DEBUG); } static const char *whereis_type_to_name(int type) { switch (type) { case BIN_DIR: return "bin"; case MAN_DIR: return "man"; case SRC_DIR: return "src"; default: return "???"; } } static void __attribute__((__noreturn__)) usage(FILE *out) { fputs(USAGE_HEADER, out); fprintf(out, _(" %s [options] <file>\n"), program_invocation_short_name); fputs(USAGE_SEPARATOR, out); fputs(_("Locate the binary, source, and manual-page files for a command.\n"), out); fputs(USAGE_OPTIONS, out); fputs(_(" -b search only for binarIEs\n"), out); fputs(_(" -B <dirs> define binarIEs lookup path\n"), out); fputs(_(" -m search only for manuals and infos\n"), out); fputs(_(" -M <dirs> define man and info lookup path\n"), out); fputs(_(" -s search only for sources\n"), out); fputs(_(" -S <dirs> define sources lookup path\n"), out); fputs(_(" -f terminate <dirs> argument list\n"), out); fputs(_(" -u search for unusual entrIEs\n"), out); fputs(_(" -l output effective lookup paths\n"), out); fprintf(out, USAGE_MAN_TAIL("whereis(1)")); exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); } static void dirlist_add_dir(struct wh_dirlist **ls0, int type, const char *dir) { struct stat st; struct wh_dirlist *prev = NULL, *ls = *ls0; if (access(dir, R_OK) != 0) return; if (stat(dir, &st) != 0 || !S_ISDIR(st.st_mode)) return; while (ls) { if (ls->st_ino == st.st_ino && ls->st_dev == st.st_dev && ls->type == type) { DBG(LIST, ul_debugobj(*ls0, " ignore (already in list): %s", dir)); return; } prev = ls; ls = ls->next; } ls = xcalloc(1, sizeof(*ls)); ls->st_ino = st.st_ino; ls->st_dev = st.st_dev; ls->type = type; ls->path = canonicalize_path(dir); if (!*ls0) *ls0 = ls;/* first in the list */ else { assert(prev); prev->next = ls;/* add to the end of the list */ } DBG(LIST, ul_debugobj(*ls0, " add dir: %s", ls->path)); return; } /* special case for '*' in the paths */ static void dirlist_add_subdir(struct wh_dirlist **ls, int type, const char *dir) { char buf[PATH_MAX], *d; DIR *dirp; struct dirent *dp; strncpy(buf, dir, PATH_MAX); buf[PATH_MAX - 1] = '\0'; d = strchr(buf, '*'); if (!d) return; *d = 0; dirp =opendir(buf); if (!dirp) return; DBG(LIST, ul_debugobj(*ls, " scanning subdir: %s", dir)); while ((dp = readdir(dirp)) != NULL) { if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; snprintf(d, PATH_MAX - (d - buf), "%s", dp->d_name); /* a dir definition can have a star in middle of path */ strcat(buf, strchr(dir, '*') + 1); dirlist_add_dir(ls, type, buf); } closedir(dirp); return; } static void construct_dirlist_from_env(const char *env, struct wh_dirlist **ls, int type) { char *key = NULL, *tok = NULL, *pathcp, *path = getenv(env); if (!path) return; pathcp = xstrdup(path); DBG(ENV, ul_debugobj(*ls, "construct %s dirlist from: %s", whereis_type_to_name(type), path)); for (tok = strtok_r(pathcp, ":", &key); tok; tok = strtok_r(NULL, ":", &key)) dirlist_add_dir(ls, type, tok); free(pathcp); return; } static void construct_dirlist_from_argv(struct wh_dirlist **ls, int *idx, int argc, char *argv[], int type) { int i; DBG(ARGV, ul_debugobj(*ls, "construct %s dirlist from argv[%d..]", whereis_type_to_name(type), *idx)); for (i = *idx; i < argc; i++) { if (*argv[i] == '-')/* end of the list */ break; DBG(ARGV, ul_debugobj(*ls, " using argv[%d]: %s", *idx, argv[*idx])); dirlist_add_dir(ls, type, argv[i]); *idx = i; } return; } static void construct_dirlist(struct wh_dirlist **ls, |