195c635efSGarrett D'Amore /* 295c635efSGarrett D'Amore * CDDL HEADER START 395c635efSGarrett D'Amore * 495c635efSGarrett D'Amore * The contents of this file are subject to the terms of the 595c635efSGarrett D'Amore * Common Development and Distribution License (the "License"). 695c635efSGarrett D'Amore * You may not use this file except in compliance with the License. 795c635efSGarrett D'Amore * 895c635efSGarrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 995c635efSGarrett D'Amore * or http://www.opensolaris.org/os/licensing. 1095c635efSGarrett D'Amore * See the License for the specific language governing permissions 1195c635efSGarrett D'Amore * and limitations under the License. 1295c635efSGarrett D'Amore * 1395c635efSGarrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each 1495c635efSGarrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1595c635efSGarrett D'Amore * If applicable, add the following below this CDDL HEADER, with the 1695c635efSGarrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying 1795c635efSGarrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner] 1895c635efSGarrett D'Amore * 1995c635efSGarrett D'Amore * CDDL HEADER END 2095c635efSGarrett D'Amore */ 2195c635efSGarrett D'Amore 2295c635efSGarrett D'Amore /* 2395c635efSGarrett D'Amore * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. 2495c635efSGarrett D'Amore * Copyright 2012, Josef 'Jeff' Sipek <jeffpc@31bits.net>. All rights reserved. 2595c635efSGarrett D'Amore * Copyright 2014 Garrett D'Amore <garrett@damore.org> 26*d456640dSYuri Pankov * Copyright 2016 Nexenta Systems, Inc. 2795c635efSGarrett D'Amore */ 2895c635efSGarrett D'Amore 2995c635efSGarrett D'Amore /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T. */ 3095c635efSGarrett D'Amore /* All rights reserved. */ 3195c635efSGarrett D'Amore 3295c635efSGarrett D'Amore /* 3395c635efSGarrett D'Amore * University Copyright- Copyright (c) 1982, 1986, 1988 3495c635efSGarrett D'Amore * The Regents of the University of California 3595c635efSGarrett D'Amore * All Rights Reserved 3695c635efSGarrett D'Amore * 3795c635efSGarrett D'Amore * University Acknowledgment- Portions of this document are derived from 3895c635efSGarrett D'Amore * software developed by the University of California, Berkeley, and its 3995c635efSGarrett D'Amore * contributors. 4095c635efSGarrett D'Amore */ 4195c635efSGarrett D'Amore 4295c635efSGarrett D'Amore /* 4395c635efSGarrett D'Amore * Find and display reference manual pages. This version includes makewhatis 4495c635efSGarrett D'Amore * functionality as well. 4595c635efSGarrett D'Amore */ 4695c635efSGarrett D'Amore 4795c635efSGarrett D'Amore #include <sys/param.h> 4895c635efSGarrett D'Amore #include <sys/stat.h> 4995c635efSGarrett D'Amore #include <sys/termios.h> 5095c635efSGarrett D'Amore #include <sys/types.h> 5195c635efSGarrett D'Amore 5295c635efSGarrett D'Amore #include <ctype.h> 5395c635efSGarrett D'Amore #include <dirent.h> 5495c635efSGarrett D'Amore #include <err.h> 5595c635efSGarrett D'Amore #include <errno.h> 5695c635efSGarrett D'Amore #include <fcntl.h> 5795c635efSGarrett D'Amore #include <fnmatch.h> 5895c635efSGarrett D'Amore #include <limits.h> 5995c635efSGarrett D'Amore #include <locale.h> 6095c635efSGarrett D'Amore #include <malloc.h> 6195c635efSGarrett D'Amore #include <memory.h> 6295c635efSGarrett D'Amore #include <regex.h> 6395c635efSGarrett D'Amore #include <stdio.h> 6495c635efSGarrett D'Amore #include <stdlib.h> 6595c635efSGarrett D'Amore #include <string.h> 6695c635efSGarrett D'Amore #include <unistd.h> 6795c635efSGarrett D'Amore 6895c635efSGarrett D'Amore #include "man.h" 6995c635efSGarrett D'Amore 7095c635efSGarrett D'Amore 7195c635efSGarrett D'Amore /* Mapping of old directories to new directories */ 7295c635efSGarrett D'Amore static const struct map_entry { 7395c635efSGarrett D'Amore char *old_name; 7495c635efSGarrett D'Amore char *new_name; 7595c635efSGarrett D'Amore } map[] = { 7695c635efSGarrett D'Amore { "3b", "3ucb" }, 7795c635efSGarrett D'Amore { "3e", "3elf" }, 7895c635efSGarrett D'Amore { "3g", "3gen" }, 7995c635efSGarrett D'Amore { "3k", "3kstat" }, 8095c635efSGarrett D'Amore { "3n", "3socket" }, 8195c635efSGarrett D'Amore { "3r", "3rt" }, 8295c635efSGarrett D'Amore { "3s", "3c" }, 8395c635efSGarrett D'Amore { "3t", "3thr" }, 8495c635efSGarrett D'Amore { "3x", "3curses" }, 8595c635efSGarrett D'Amore { "3xc", "3xcurses" }, 8695c635efSGarrett D'Amore { "3xn", "3xnet" }, 8795c635efSGarrett D'Amore { NULL, NULL } 8895c635efSGarrett D'Amore }; 8995c635efSGarrett D'Amore 9095c635efSGarrett D'Amore struct suffix { 9195c635efSGarrett D'Amore char *ds; 9295c635efSGarrett D'Amore char *fs; 9395c635efSGarrett D'Amore }; 9495c635efSGarrett D'Amore 9595c635efSGarrett D'Amore /* 9695c635efSGarrett D'Amore * Flags that control behavior of build_manpath() 9795c635efSGarrett D'Amore * 9895c635efSGarrett D'Amore * BMP_ISPATH pathv is a vector constructed from PATH. 9995c635efSGarrett D'Amore * Perform appropriate path translations for 10095c635efSGarrett D'Amore * manpath. 10195c635efSGarrett D'Amore * BMP_APPEND_DEFMANDIR Add DEFMANDIR to the end if it hasn't 10295c635efSGarrett D'Amore * already appeared earlier. 10395c635efSGarrett D'Amore * BMP_FALLBACK_DEFMANDIR Append /usr/share/man only if no other 10495c635efSGarrett D'Amore * manpath (including derived from PATH) 10595c635efSGarrett D'Amore * elements are valid. 10695c635efSGarrett D'Amore */ 10795c635efSGarrett D'Amore #define BMP_ISPATH 1 10895c635efSGarrett D'Amore #define BMP_APPEND_DEFMANDIR 2 10995c635efSGarrett D'Amore #define BMP_FALLBACK_DEFMANDIR 4 11095c635efSGarrett D'Amore 11195c635efSGarrett D'Amore /* 11295c635efSGarrett D'Amore * When doing equality comparisons of directories, device and inode 11395c635efSGarrett D'Amore * comparisons are done. The secnode and dupnode structures are used 11495c635efSGarrett D'Amore * to form a list of lists for this processing. 11595c635efSGarrett D'Amore */ 11695c635efSGarrett D'Amore struct secnode { 11795c635efSGarrett D'Amore char *secp; 11895c635efSGarrett D'Amore struct secnode *next; 11995c635efSGarrett D'Amore }; 12095c635efSGarrett D'Amore struct dupnode { 12195c635efSGarrett D'Amore dev_t dev; /* from struct stat st_dev */ 12295c635efSGarrett D'Amore ino_t ino; /* from struct stat st_ino */ 12395c635efSGarrett D'Amore struct secnode *secl; /* sections already considered */ 12495c635efSGarrett D'Amore struct dupnode *next; 12595c635efSGarrett D'Amore }; 12695c635efSGarrett D'Amore 12795c635efSGarrett D'Amore /* 12895c635efSGarrett D'Amore * Map directories that may appear in PATH to the corresponding 12995c635efSGarrett D'Amore * man directory. 13095c635efSGarrett D'Amore */ 13195c635efSGarrett D'Amore static struct pathmap { 13295c635efSGarrett D'Amore char *bindir; 13395c635efSGarrett D'Amore char *mandir; 13495c635efSGarrett D'Amore dev_t dev; 13595c635efSGarrett D'Amore ino_t ino; 13695c635efSGarrett D'Amore } bintoman[] = { 13795c635efSGarrett D'Amore { "/sbin", "/usr/share/man,1m", 0, 0 }, 13895c635efSGarrett D'Amore { "/usr/sbin", "/usr/share/man,1m", 0, 0 }, 13995c635efSGarrett D'Amore { "/usr/ucb", "/usr/share/man,1b", 0, 0 }, 14095c635efSGarrett D'Amore { "/usr/bin", "/usr/share/man,1,1m,1s,1t,1c", 0, 0 }, 14195c635efSGarrett D'Amore { "/usr/xpg4/bin", "/usr/share/man,1", 0, 0 }, 14295c635efSGarrett D'Amore { "/usr/xpg6/bin", "/usr/share/man,1", 0, 0 }, 14395c635efSGarrett D'Amore { NULL, NULL, 0, 0 } 14495c635efSGarrett D'Amore }; 14595c635efSGarrett D'Amore 14695c635efSGarrett D'Amore struct man_node { 14795c635efSGarrett D'Amore char *path; /* mandir path */ 14895c635efSGarrett D'Amore char **secv; /* submandir suffices */ 14995c635efSGarrett D'Amore int defsrch; /* hint for man -p */ 15095c635efSGarrett D'Amore int frompath; /* hint for man -d */ 15195c635efSGarrett D'Amore struct man_node *next; 15295c635efSGarrett D'Amore }; 15395c635efSGarrett D'Amore 15495c635efSGarrett D'Amore static int all = 0; 15595c635efSGarrett D'Amore static int apropos = 0; 15695c635efSGarrett D'Amore static int debug = 0; 15795c635efSGarrett D'Amore static int found = 0; 15895c635efSGarrett D'Amore static int list = 0; 15995c635efSGarrett D'Amore static int makewhatis = 0; 16095c635efSGarrett D'Amore static int printmp = 0; 16195c635efSGarrett D'Amore static int sargs = 0; 16295c635efSGarrett D'Amore static int psoutput = 0; 16395c635efSGarrett D'Amore static int lintout = 0; 16495c635efSGarrett D'Amore static int whatis = 0; 16595c635efSGarrett D'Amore static int makewhatishere = 0; 16695c635efSGarrett D'Amore 16795c635efSGarrett D'Amore static char *mansec; 16895c635efSGarrett D'Amore static char *pager = NULL; 16995c635efSGarrett D'Amore 17095c635efSGarrett D'Amore static char *addlocale(char *); 17195c635efSGarrett D'Amore static struct man_node *build_manpath(char **, int); 17295c635efSGarrett D'Amore static void do_makewhatis(struct man_node *); 17395c635efSGarrett D'Amore static char *check_config(char *); 17495c635efSGarrett D'Amore static int cmp(const void *, const void *); 17595c635efSGarrett D'Amore static int dupcheck(struct man_node *, struct dupnode **); 17695c635efSGarrett D'Amore static int format(char *, char *, char *, char *); 17795c635efSGarrett D'Amore static void free_dupnode(struct dupnode *); 17895c635efSGarrett D'Amore static void free_manp(struct man_node *manp); 17995c635efSGarrett D'Amore static void freev(char **); 18095c635efSGarrett D'Amore static void fullpaths(struct man_node **); 18195c635efSGarrett D'Amore static void get_all_sect(struct man_node *); 18295c635efSGarrett D'Amore static int getdirs(char *, char ***, int); 18395c635efSGarrett D'Amore static void getpath(struct man_node *, char **); 18495c635efSGarrett D'Amore static void getsect(struct man_node *, char **); 18595c635efSGarrett D'Amore static void init_bintoman(void); 18695c635efSGarrett D'Amore static void lower(char *); 18795c635efSGarrett D'Amore static void mandir(char **, char *, char *, int); 18895c635efSGarrett D'Amore static int manual(struct man_node *, char *); 18995c635efSGarrett D'Amore static char *map_section(char *, char *); 19095c635efSGarrett D'Amore static char *path_to_manpath(char *); 19195c635efSGarrett D'Amore static void print_manpath(struct man_node *); 19295c635efSGarrett D'Amore static void search_whatis(char *, char *); 19395c635efSGarrett D'Amore static int searchdir(char *, char *, char *); 19495c635efSGarrett D'Amore static void sortdir(DIR *, char ***); 19595c635efSGarrett D'Amore static char **split(char *, char); 19695c635efSGarrett D'Amore static void usage_man(void); 19795c635efSGarrett D'Amore static void usage_whatapro(void); 19895c635efSGarrett D'Amore static void usage_catman(void); 19995c635efSGarrett D'Amore static void usage_makewhatis(void); 20095c635efSGarrett D'Amore static void whatapro(struct man_node *, char *); 20195c635efSGarrett D'Amore 20295c635efSGarrett D'Amore static char language[MAXPATHLEN]; /* LC_MESSAGES */ 20395c635efSGarrett D'Amore static char localedir[MAXPATHLEN]; /* locale specific path component */ 20495c635efSGarrett D'Amore 20595c635efSGarrett D'Amore static char *newsection = NULL; 20695c635efSGarrett D'Amore 20795c635efSGarrett D'Amore static int manwidth = 0; 20895c635efSGarrett D'Amore 20995c635efSGarrett D'Amore extern const char *__progname; 21095c635efSGarrett D'Amore 21195c635efSGarrett D'Amore int 21295c635efSGarrett D'Amore main(int argc, char **argv) 21395c635efSGarrett D'Amore { 21495c635efSGarrett D'Amore int c, i; 21595c635efSGarrett D'Amore char **pathv; 21695c635efSGarrett D'Amore char *manpath = NULL; 21795c635efSGarrett D'Amore static struct man_node *mandirs = NULL; 21895c635efSGarrett D'Amore int bmp_flags = 0; 21995c635efSGarrett D'Amore int ret = 0; 22095c635efSGarrett D'Amore char *opts; 22195c635efSGarrett D'Amore char *mwstr; 22295c635efSGarrett D'Amore int catman = 0; 22395c635efSGarrett D'Amore 22495c635efSGarrett D'Amore (void) setlocale(LC_ALL, ""); 22595c635efSGarrett D'Amore (void) strcpy(language, setlocale(LC_MESSAGES, (char *)NULL)); 22695c635efSGarrett D'Amore if (strcmp("C", language) != 0) 22795c635efSGarrett D'Amore (void) strlcpy(localedir, language, MAXPATHLEN); 22895c635efSGarrett D'Amore 22995c635efSGarrett D'Amore #if !defined(TEXT_DOMAIN) 23095c635efSGarrett D'Amore #define TEXT_DOMAIN "SYS_TEST" 23195c635efSGarrett D'Amore #endif 23295c635efSGarrett D'Amore (void) textdomain(TEXT_DOMAIN); 23395c635efSGarrett D'Amore 23495c635efSGarrett D'Amore if (strcmp(__progname, "apropos") == 0) { 23595c635efSGarrett D'Amore apropos++; 23695c635efSGarrett D'Amore opts = "M:ds:"; 23795c635efSGarrett D'Amore } else if (strcmp(__progname, "whatis") == 0) { 23895c635efSGarrett D'Amore apropos++; 23995c635efSGarrett D'Amore whatis++; 24095c635efSGarrett D'Amore opts = "M:ds:"; 24195c635efSGarrett D'Amore } else if (strcmp(__progname, "catman") == 0) { 24295c635efSGarrett D'Amore catman++; 24395c635efSGarrett D'Amore makewhatis++; 24495c635efSGarrett D'Amore opts = "P:M:w"; 24595c635efSGarrett D'Amore } else if (strcmp(__progname, "makewhatis") == 0) { 24695c635efSGarrett D'Amore makewhatis++; 24795c635efSGarrett D'Amore makewhatishere++; 24895c635efSGarrett D'Amore manpath = "."; 24995c635efSGarrett D'Amore opts = ""; 25095c635efSGarrett D'Amore } else { 25195c635efSGarrett D'Amore opts = "FM:P:T:adfklprs:tw"; 25295c635efSGarrett D'Amore if (argc > 1 && strcmp(argv[1], "-") == 0) { 25395c635efSGarrett D'Amore pager = "cat"; 25495c635efSGarrett D'Amore optind++; 25595c635efSGarrett D'Amore } 25695c635efSGarrett D'Amore } 25795c635efSGarrett D'Amore 25895c635efSGarrett D'Amore opterr = 0; 25995c635efSGarrett D'Amore while ((c = getopt(argc, argv, opts)) != -1) { 26095c635efSGarrett D'Amore switch (c) { 26195c635efSGarrett D'Amore case 'M': /* Respecify path for man pages */ 26295c635efSGarrett D'Amore manpath = optarg; 26395c635efSGarrett D'Amore break; 26495c635efSGarrett D'Amore case 'a': 26595c635efSGarrett D'Amore all++; 26695c635efSGarrett D'Amore break; 26795c635efSGarrett D'Amore case 'd': 26895c635efSGarrett D'Amore debug++; 26995c635efSGarrett D'Amore break; 27095c635efSGarrett D'Amore case 'f': 27195c635efSGarrett D'Amore whatis++; 27295c635efSGarrett D'Amore /*FALLTHROUGH*/ 27395c635efSGarrett D'Amore case 'k': 27495c635efSGarrett D'Amore apropos++; 27595c635efSGarrett D'Amore break; 27695c635efSGarrett D'Amore case 'l': 27795c635efSGarrett D'Amore list++; 27895c635efSGarrett D'Amore all++; 27995c635efSGarrett D'Amore break; 28095c635efSGarrett D'Amore case 'p': 28195c635efSGarrett D'Amore printmp++; 28295c635efSGarrett D'Amore break; 28395c635efSGarrett D'Amore case 's': 28495c635efSGarrett D'Amore mansec = optarg; 28595c635efSGarrett D'Amore sargs++; 28695c635efSGarrett D'Amore break; 28795c635efSGarrett D'Amore case 'r': 28895c635efSGarrett D'Amore lintout++; 28995c635efSGarrett D'Amore break; 29095c635efSGarrett D'Amore case 't': 29195c635efSGarrett D'Amore psoutput++; 29295c635efSGarrett D'Amore break; 29395c635efSGarrett D'Amore case 'T': 29495c635efSGarrett D'Amore case 'P': 29595c635efSGarrett D'Amore case 'F': 29695c635efSGarrett D'Amore /* legacy options, compatibility only and ignored */ 29795c635efSGarrett D'Amore break; 29895c635efSGarrett D'Amore case 'w': 29995c635efSGarrett D'Amore makewhatis++; 30095c635efSGarrett D'Amore break; 30195c635efSGarrett D'Amore case '?': 30295c635efSGarrett D'Amore default: 30395c635efSGarrett D'Amore if (apropos) 30495c635efSGarrett D'Amore usage_whatapro(); 30595c635efSGarrett D'Amore else if (catman) 30695c635efSGarrett D'Amore usage_catman(); 30795c635efSGarrett D'Amore else if (makewhatishere) 30895c635efSGarrett D'Amore usage_makewhatis(); 30995c635efSGarrett D'Amore else 31095c635efSGarrett D'Amore usage_man(); 31195c635efSGarrett D'Amore } 31295c635efSGarrett D'Amore } 31395c635efSGarrett D'Amore argc -= optind; 31495c635efSGarrett D'Amore argv += optind; 31595c635efSGarrett D'Amore 31695c635efSGarrett D'Amore if (argc == 0) { 31795c635efSGarrett D'Amore if (apropos) { 31895c635efSGarrett D'Amore (void) fprintf(stderr, gettext("%s what?\n"), 31995c635efSGarrett D'Amore __progname); 32095c635efSGarrett D'Amore exit(1); 32195c635efSGarrett D'Amore } else if (!printmp && !makewhatis) { 32295c635efSGarrett D'Amore (void) fprintf(stderr, 32395c635efSGarrett D'Amore gettext("What manual page do you want?\n")); 32495c635efSGarrett D'Amore exit(1); 32595c635efSGarrett D'Amore } 32695c635efSGarrett D'Amore } 32795c635efSGarrett D'Amore 32895c635efSGarrett D'Amore init_bintoman(); 32995c635efSGarrett D'Amore if (manpath == NULL && (manpath = getenv("MANPATH")) == NULL) { 33095c635efSGarrett D'Amore if ((manpath = getenv("PATH")) != NULL) 33195c635efSGarrett D'Amore bmp_flags = BMP_ISPATH | BMP_APPEND_DEFMANDIR; 33295c635efSGarrett D'Amore else 33395c635efSGarrett D'Amore manpath = DEFMANDIR; 33495c635efSGarrett D'Amore } 33595c635efSGarrett D'Amore pathv = split(manpath, ':'); 33695c635efSGarrett D'Amore mandirs = build_manpath(pathv, bmp_flags); 33795c635efSGarrett D'Amore freev(pathv); 33895c635efSGarrett D'Amore fullpaths(&mandirs); 33995c635efSGarrett D'Amore 34095c635efSGarrett D'Amore if (makewhatis) { 34195c635efSGarrett D'Amore do_makewhatis(mandirs); 34295c635efSGarrett D'Amore exit(0); 34395c635efSGarrett D'Amore } 34495c635efSGarrett D'Amore 34595c635efSGarrett D'Amore if (printmp) { 34695c635efSGarrett D'Amore print_manpath(mandirs); 34795c635efSGarrett D'Amore exit(0); 34895c635efSGarrett D'Amore } 34995c635efSGarrett D'Amore 35095c635efSGarrett D'Amore /* Collect environment information */ 35195c635efSGarrett D'Amore if (isatty(STDOUT_FILENO) && (mwstr = getenv("MANWIDTH")) != NULL && 35295c635efSGarrett D'Amore *mwstr != '\0') { 35395c635efSGarrett D'Amore if (strcasecmp(mwstr, "tty") == 0) { 35495c635efSGarrett D'Amore struct winsize ws; 35595c635efSGarrett D'Amore 35695c635efSGarrett D'Amore if (ioctl(0, TIOCGWINSZ, &ws) != 0) 35795c635efSGarrett D'Amore warn("TIOCGWINSZ"); 35895c635efSGarrett D'Amore else 35995c635efSGarrett D'Amore manwidth = ws.ws_col; 36095c635efSGarrett D'Amore } else { 36195c635efSGarrett D'Amore manwidth = (int)strtol(mwstr, (char **)NULL, 10); 36295c635efSGarrett D'Amore if (manwidth < 0) 36395c635efSGarrett D'Amore manwidth = 0; 36495c635efSGarrett D'Amore } 36595c635efSGarrett D'Amore } 36695c635efSGarrett D'Amore if (manwidth != 0) { 36795c635efSGarrett D'Amore DPRINTF("-- Using non-standard page width: %d\n", manwidth); 36895c635efSGarrett D'Amore } 36995c635efSGarrett D'Amore 37095c635efSGarrett D'Amore if (pager == NULL) { 37195c635efSGarrett D'Amore if ((pager = getenv("PAGER")) == NULL || *pager == '\0') 37295c635efSGarrett D'Amore pager = PAGER; 37395c635efSGarrett D'Amore } 37495c635efSGarrett D'Amore DPRINTF("-- Using pager: %s\n", pager); 37595c635efSGarrett D'Amore 37695c635efSGarrett D'Amore for (i = 0; i < argc; i++) { 37795c635efSGarrett D'Amore char *cmd; 37895c635efSGarrett D'Amore static struct man_node *mp; 37995c635efSGarrett D'Amore char *pv[2]; 38095c635efSGarrett D'Amore 38195c635efSGarrett D'Amore /* 38295c635efSGarrett D'Amore * If full path to command specified, customize 38395c635efSGarrett D'Amore * the manpath accordingly. 38495c635efSGarrett D'Amore */ 38595c635efSGarrett D'Amore if ((cmd = strrchr(argv[i], '/')) != NULL) { 38695c635efSGarrett D'Amore *cmd = '\0'; 38795c635efSGarrett D'Amore if ((pv[0] = strdup(argv[i])) == NULL) 38895c635efSGarrett D'Amore err(1, "strdup"); 38995c635efSGarrett D'Amore pv[1] = NULL; 39095c635efSGarrett D'Amore *cmd = '/'; 39195c635efSGarrett D'Amore mp = build_manpath(pv, 39295c635efSGarrett D'Amore BMP_ISPATH | BMP_FALLBACK_DEFMANDIR); 39395c635efSGarrett D'Amore } else { 39495c635efSGarrett D'Amore mp = mandirs; 39595c635efSGarrett D'Amore } 39695c635efSGarrett D'Amore 39795c635efSGarrett D'Amore if (apropos) 39895c635efSGarrett D'Amore whatapro(mp, argv[i]); 39995c635efSGarrett D'Amore else 40095c635efSGarrett D'Amore ret += manual(mp, argv[i]); 40195c635efSGarrett D'Amore 40295c635efSGarrett D'Amore if (mp != NULL && mp != mandirs) { 40395c635efSGarrett D'Amore free(pv[0]); 40495c635efSGarrett D'Amore free_manp(mp); 40595c635efSGarrett D'Amore } 40695c635efSGarrett D'Amore } 40795c635efSGarrett D'Amore 40895c635efSGarrett D'Amore return (ret == 0 ? 0 : 1); 40995c635efSGarrett D'Amore } 41095c635efSGarrett D'Amore 41195c635efSGarrett D'Amore /* 41295c635efSGarrett D'Amore * This routine builds the manpage structure from MANPATH or PATH, 41395c635efSGarrett D'Amore * depending on flags. See BMP_* definitions above for valid 41495c635efSGarrett D'Amore * flags. 41595c635efSGarrett D'Amore */ 41695c635efSGarrett D'Amore static struct man_node * 41795c635efSGarrett D'Amore build_manpath(char **pathv, int flags) 41895c635efSGarrett D'Amore { 41995c635efSGarrett D'Amore struct man_node *manpage = NULL; 42095c635efSGarrett D'Amore struct man_node *currp = NULL; 42195c635efSGarrett D'Amore struct man_node *lastp = NULL; 42295c635efSGarrett D'Amore char **p; 42395c635efSGarrett D'Amore char **q; 42495c635efSGarrett D'Amore char *mand = NULL; 42595c635efSGarrett D'Amore char *mandir = DEFMANDIR; 42695c635efSGarrett D'Amore int s; 42795c635efSGarrett D'Amore struct dupnode *didup = NULL; 42895c635efSGarrett D'Amore struct stat sb; 42995c635efSGarrett D'Amore 43095c635efSGarrett D'Amore s = sizeof (struct man_node); 43195c635efSGarrett D'Amore for (p = pathv; *p != NULL; ) { 43295c635efSGarrett D'Amore if (flags & BMP_ISPATH) { 43395c635efSGarrett D'Amore if ((mand = path_to_manpath(*p)) == NULL) 43495c635efSGarrett D'Amore goto next; 43595c635efSGarrett D'Amore free(*p); 43695c635efSGarrett D'Amore *p = mand; 43795c635efSGarrett D'Amore } 43895c635efSGarrett D'Amore q = split(*p, ','); 43995c635efSGarrett D'Amore if (stat(q[0], &sb) != 0 || (sb.st_mode & S_IFDIR) == 0) { 44095c635efSGarrett D'Amore freev(q); 44195c635efSGarrett D'Amore goto next; 44295c635efSGarrett D'Amore } 44395c635efSGarrett D'Amore 44495c635efSGarrett D'Amore if (access(q[0], R_OK | X_OK) == 0) { 44595c635efSGarrett D'Amore /* 44695c635efSGarrett D'Amore * Some element exists. Do not append DEFMANDIR as a 44795c635efSGarrett D'Amore * fallback. 44895c635efSGarrett D'Amore */ 44995c635efSGarrett D'Amore flags &= ~BMP_FALLBACK_DEFMANDIR; 45095c635efSGarrett D'Amore 45195c635efSGarrett D'Amore if ((currp = (struct man_node *)calloc(1, s)) == NULL) 45295c635efSGarrett D'Amore err(1, "calloc"); 45395c635efSGarrett D'Amore 45495c635efSGarrett D'Amore currp->frompath = (flags & BMP_ISPATH); 45595c635efSGarrett D'Amore 45695c635efSGarrett D'Amore if (manpage == NULL) 45795c635efSGarrett D'Amore lastp = manpage = currp; 45895c635efSGarrett D'Amore 45995c635efSGarrett D'Amore getpath(currp, p); 46095c635efSGarrett D'Amore getsect(currp, p); 46195c635efSGarrett D'Amore 46295c635efSGarrett D'Amore /* 46395c635efSGarrett D'Amore * If there are no new elements in this path, 46495c635efSGarrett D'Amore * do not add it to the manpage list. 46595c635efSGarrett D'Amore */ 46695c635efSGarrett D'Amore if (dupcheck(currp, &didup) != 0) { 46795c635efSGarrett D'Amore freev(currp->secv); 46895c635efSGarrett D'Amore free(currp); 46995c635efSGarrett D'Amore } else { 47095c635efSGarrett D'Amore currp->next = NULL; 47195c635efSGarrett D'Amore if (currp != manpage) 47295c635efSGarrett D'Amore lastp->next = currp; 47395c635efSGarrett D'Amore lastp = currp; 47495c635efSGarrett D'Amore } 47595c635efSGarrett D'Amore } 47695c635efSGarrett D'Amore freev(q); 47795c635efSGarrett D'Amore next: 47895c635efSGarrett D'Amore /* 47995c635efSGarrett D'Amore * Special handling of appending DEFMANDIR. After all pathv 48095c635efSGarrett D'Amore * elements have been processed, append DEFMANDIR if needed. 48195c635efSGarrett D'Amore */ 48295c635efSGarrett D'Amore if (p == &mandir) 48395c635efSGarrett D'Amore break; 48495c635efSGarrett D'Amore p++; 48595c635efSGarrett D'Amore if (*p != NULL) 48695c635efSGarrett D'Amore continue; 48795c635efSGarrett D'Amore if (flags & (BMP_APPEND_DEFMANDIR | BMP_FALLBACK_DEFMANDIR)) { 48895c635efSGarrett D'Amore p = &mandir; 48995c635efSGarrett D'Amore flags &= ~BMP_ISPATH; 49095c635efSGarrett D'Amore } 49195c635efSGarrett D'Amore } 49295c635efSGarrett D'Amore 49395c635efSGarrett D'Amore free_dupnode(didup); 49495c635efSGarrett D'Amore 49595c635efSGarrett D'Amore return (manpage); 49695c635efSGarrett D'Amore } 49795c635efSGarrett D'Amore 49895c635efSGarrett D'Amore /* 49995c635efSGarrett D'Amore * Store the mandir path into the manp structure. 50095c635efSGarrett D'Amore */ 50195c635efSGarrett D'Amore static void 50295c635efSGarrett D'Amore getpath(struct man_node *manp, char **pv) 50395c635efSGarrett D'Amore { 50495c635efSGarrett D'Amore char *s = *pv; 50595c635efSGarrett D'Amore int i = 0; 50695c635efSGarrett D'Amore 50795c635efSGarrett D'Amore while (*s != '\0' && *s != ',') 50895c635efSGarrett D'Amore i++, s++; 50995c635efSGarrett D'Amore 51095c635efSGarrett D'Amore if ((manp->path = (char *)malloc(i + 1)) == NULL) 51195c635efSGarrett D'Amore err(1, "malloc"); 51295c635efSGarrett D'Amore (void) strlcpy(manp->path, *pv, i + 1); 51395c635efSGarrett D'Amore } 51495c635efSGarrett D'Amore 51595c635efSGarrett D'Amore /* 51695c635efSGarrett D'Amore * Store the mandir's corresponding sections (submandir 51795c635efSGarrett D'Amore * directories) into the manp structure. 51895c635efSGarrett D'Amore */ 51995c635efSGarrett D'Amore static void 52095c635efSGarrett D'Amore getsect(struct man_node *manp, char **pv) 52195c635efSGarrett D'Amore { 52295c635efSGarrett D'Amore char *sections; 52395c635efSGarrett D'Amore char **sectp; 52495c635efSGarrett D'Amore 52595c635efSGarrett D'Amore /* Just store all sections when doing makewhatis or apropos/whatis */ 52695c635efSGarrett D'Amore if (makewhatis || apropos) { 52795c635efSGarrett D'Amore manp->defsrch = 1; 52895c635efSGarrett D'Amore DPRINTF("-- Adding %s\n", manp->path); 52995c635efSGarrett D'Amore manp->secv = NULL; 53095c635efSGarrett D'Amore get_all_sect(manp); 53195c635efSGarrett D'Amore } else if (sargs) { 532*d456640dSYuri Pankov DPRINTF("-- Adding %s: sections=%s\n", manp->path, mansec); 53395c635efSGarrett D'Amore manp->secv = split(mansec, ','); 53495c635efSGarrett D'Amore for (sectp = manp->secv; *sectp; sectp++) 53595c635efSGarrett D'Amore lower(*sectp); 53695c635efSGarrett D'Amore } else if ((sections = strchr(*pv, ',')) != NULL) { 537*d456640dSYuri Pankov sections++; 538*d456640dSYuri Pankov DPRINTF("-- Adding %s: sections=%s\n", manp->path, sections); 539*d456640dSYuri Pankov manp->secv = split(sections, ','); 54095c635efSGarrett D'Amore for (sectp = manp->secv; *sectp; sectp++) 54195c635efSGarrett D'Amore lower(*sectp); 54295c635efSGarrett D'Amore if (*manp->secv == NULL) 54395c635efSGarrett D'Amore get_all_sect(manp); 54495c635efSGarrett D'Amore } else if ((sections = check_config(*pv)) != NULL) { 54595c635efSGarrett D'Amore manp->defsrch = 1; 546*d456640dSYuri Pankov DPRINTF("-- Adding %s: sections=%s (from %s)\n", manp->path, 547*d456640dSYuri Pankov sections, CONFIG); 54895c635efSGarrett D'Amore manp->secv = split(sections, ','); 54995c635efSGarrett D'Amore for (sectp = manp->secv; *sectp; sectp++) 55095c635efSGarrett D'Amore lower(*sectp); 55195c635efSGarrett D'Amore if (*manp->secv == NULL) 55295c635efSGarrett D'Amore get_all_sect(manp); 55395c635efSGarrett D'Amore } else { 55495c635efSGarrett D'Amore manp->defsrch = 1; 555*d456640dSYuri Pankov DPRINTF("-- Adding %s: default search order\n", manp->path); 55695c635efSGarrett D'Amore manp->secv = NULL; 55795c635efSGarrett D'Amore get_all_sect(manp); 55895c635efSGarrett D'Amore } 55995c635efSGarrett D'Amore } 56095c635efSGarrett D'Amore 56195c635efSGarrett D'Amore /* 56295c635efSGarrett D'Amore * Get suffices of all sub-mandir directories in a mandir. 56395c635efSGarrett D'Amore */ 56495c635efSGarrett D'Amore static void 56595c635efSGarrett D'Amore get_all_sect(struct man_node *manp) 56695c635efSGarrett D'Amore { 56795c635efSGarrett D'Amore DIR *dp; 56895c635efSGarrett D'Amore char **dirv; 56995c635efSGarrett D'Amore char **dv; 57095c635efSGarrett D'Amore char **p; 57195c635efSGarrett D'Amore char *prev = NULL; 57295c635efSGarrett D'Amore char *tmp = NULL; 57395c635efSGarrett D'Amore int maxentries = MAXTOKENS; 57495c635efSGarrett D'Amore int entries = 0; 57595c635efSGarrett D'Amore 57695c635efSGarrett D'Amore if ((dp = opendir(manp->path)) == 0) 57795c635efSGarrett D'Amore return; 57895c635efSGarrett D'Amore 57995c635efSGarrett D'Amore sortdir(dp, &dirv); 58095c635efSGarrett D'Amore 58195c635efSGarrett D'Amore (void) closedir(dp); 58295c635efSGarrett D'Amore 58395c635efSGarrett D'Amore if (manp->secv == NULL) { 58495c635efSGarrett D'Amore if ((manp->secv = malloc(maxentries * sizeof (char *))) == NULL) 58595c635efSGarrett D'Amore err(1, "malloc"); 58695c635efSGarrett D'Amore } 58795c635efSGarrett D'Amore 58895c635efSGarrett D'Amore for (dv = dirv, p = manp->secv; *dv; dv++) { 58995c635efSGarrett D'Amore if (strcmp(*dv, CONFIG) == 0) { 59095c635efSGarrett D'Amore free(*dv); 59195c635efSGarrett D'Amore continue; 59295c635efSGarrett D'Amore } 59395c635efSGarrett D'Amore 59495c635efSGarrett D'Amore free(tmp); 59595c635efSGarrett D'Amore if ((tmp = strdup(*dv + 3)) == NULL) 59695c635efSGarrett D'Amore err(1, "strdup"); 59795c635efSGarrett D'Amore 59895c635efSGarrett D'Amore if (prev != NULL && strcmp(prev, tmp) == 0) { 59995c635efSGarrett D'Amore free(*dv); 60095c635efSGarrett D'Amore continue; 60195c635efSGarrett D'Amore } 60295c635efSGarrett D'Amore 60395c635efSGarrett D'Amore free(prev); 60495c635efSGarrett D'Amore if ((prev = strdup(*dv + 3)) == NULL) 60595c635efSGarrett D'Amore err(1, "strdup"); 60695c635efSGarrett D'Amore 60795c635efSGarrett D'Amore if ((*p = strdup(*dv + 3)) == NULL) 60895c635efSGarrett D'Amore err(1, "strdup"); 60995c635efSGarrett D'Amore 61095c635efSGarrett D'Amore p++; entries++; 61195c635efSGarrett D'Amore 61295c635efSGarrett D'Amore if (entries == maxentries) { 61395c635efSGarrett D'Amore maxentries += MAXTOKENS; 61495c635efSGarrett D'Amore if ((manp->secv = realloc(manp->secv, 61595c635efSGarrett D'Amore sizeof (char *) * maxentries)) == NULL) 61695c635efSGarrett D'Amore err(1, "realloc"); 61795c635efSGarrett D'Amore p = manp->secv + entries; 61895c635efSGarrett D'Amore } 61995c635efSGarrett D'Amore free(*dv); 62095c635efSGarrett D'Amore } 62195c635efSGarrett D'Amore free(tmp); 62295c635efSGarrett D'Amore free(prev); 62395c635efSGarrett D'Amore *p = NULL; 62495c635efSGarrett D'Amore free(dirv); 62595c635efSGarrett D'Amore } 62695c635efSGarrett D'Amore 62795c635efSGarrett D'Amore /* 62895c635efSGarrett D'Amore * Build whatis databases. 62995c635efSGarrett D'Amore */ 63095c635efSGarrett D'Amore static void 63195c635efSGarrett D'Amore do_makewhatis(struct man_node *manp) 63295c635efSGarrett D'Amore { 63395c635efSGarrett D'Amore struct man_node *p; 63495c635efSGarrett D'Amore char *ldir; 63595c635efSGarrett D'Amore 63695c635efSGarrett D'Amore for (p = manp; p != NULL; p = p->next) { 63795c635efSGarrett D'Amore ldir = addlocale(p->path); 63895c635efSGarrett D'Amore if (*localedir != '\0' && getdirs(ldir, NULL, 0) > 0) 63995c635efSGarrett D'Amore mwpath(ldir); 64095c635efSGarrett D'Amore free(ldir); 64195c635efSGarrett D'Amore mwpath(p->path); 64295c635efSGarrett D'Amore } 64395c635efSGarrett D'Amore } 64495c635efSGarrett D'Amore 64595c635efSGarrett D'Amore /* 64695c635efSGarrett D'Amore * Count mandirs under the given manpath 64795c635efSGarrett D'Amore */ 64895c635efSGarrett D'Amore static int 64995c635efSGarrett D'Amore getdirs(char *path, char ***dirv, int flag) 65095c635efSGarrett D'Amore { 65195c635efSGarrett D'Amore DIR *dp; 65295c635efSGarrett D'Amore struct dirent *d; 65395c635efSGarrett D'Amore int n = 0; 65495c635efSGarrett D'Amore int maxentries = MAXDIRS; 65595c635efSGarrett D'Amore char **dv = NULL; 65695c635efSGarrett D'Amore 65795c635efSGarrett D'Amore if ((dp = opendir(path)) == NULL) 65895c635efSGarrett D'Amore return (0); 65995c635efSGarrett D'Amore 66095c635efSGarrett D'Amore if (flag) { 66195c635efSGarrett D'Amore if ((*dirv = malloc(sizeof (char *) * 66295c635efSGarrett D'Amore maxentries)) == NULL) 66395c635efSGarrett D'Amore err(1, "malloc"); 66495c635efSGarrett D'Amore dv = *dirv; 66595c635efSGarrett D'Amore } 66695c635efSGarrett D'Amore while ((d = readdir(dp))) { 66795c635efSGarrett D'Amore if (strncmp(d->d_name, "man", 3) != 0) 66895c635efSGarrett D'Amore continue; 66995c635efSGarrett D'Amore n++; 67095c635efSGarrett D'Amore 67195c635efSGarrett D'Amore if (flag) { 67295c635efSGarrett D'Amore if ((*dv = strdup(d->d_name + 3)) == NULL) 67395c635efSGarrett D'Amore err(1, "strdup"); 67495c635efSGarrett D'Amore dv++; 67595c635efSGarrett D'Amore if ((dv - *dirv) == maxentries) { 67695c635efSGarrett D'Amore int entries = maxentries; 67795c635efSGarrett D'Amore 67895c635efSGarrett D'Amore maxentries += MAXTOKENS; 67995c635efSGarrett D'Amore if ((*dirv = realloc(*dirv, 68095c635efSGarrett D'Amore sizeof (char *) * maxentries)) == NULL) 68195c635efSGarrett D'Amore err(1, "realloc"); 68295c635efSGarrett D'Amore dv = *dirv + entries; 68395c635efSGarrett D'Amore } 68495c635efSGarrett D'Amore } 68595c635efSGarrett D'Amore } 68695c635efSGarrett D'Amore 68795c635efSGarrett D'Amore (void) closedir(dp); 68895c635efSGarrett D'Amore return (n); 68995c635efSGarrett D'Amore } 69095c635efSGarrett D'Amore 69195c635efSGarrett D'Amore 69295c635efSGarrett D'Amore /* 69395c635efSGarrett D'Amore * Find matching whatis or apropos entries. 69495c635efSGarrett D'Amore */ 69595c635efSGarrett D'Amore static void 69695c635efSGarrett D'Amore whatapro(struct man_node *manp, char *word) 69795c635efSGarrett D'Amore { 69895c635efSGarrett D'Amore char whatpath[MAXPATHLEN]; 69995c635efSGarrett D'Amore struct man_node *b; 70095c635efSGarrett D'Amore char *ldir; 70195c635efSGarrett D'Amore 70295c635efSGarrett D'Amore for (b = manp; b != NULL; b = b->next) { 70395c635efSGarrett D'Amore if (*localedir != '\0') { 70495c635efSGarrett D'Amore ldir = addlocale(b->path); 70595c635efSGarrett D'Amore if (getdirs(ldir, NULL, 0) != 0) { 70695c635efSGarrett D'Amore (void) snprintf(whatpath, sizeof (whatpath), 70795c635efSGarrett D'Amore "%s/%s", ldir, WHATIS); 70895c635efSGarrett D'Amore search_whatis(whatpath, word); 70995c635efSGarrett D'Amore } 71095c635efSGarrett D'Amore free(ldir); 71195c635efSGarrett D'Amore } 71295c635efSGarrett D'Amore (void) snprintf(whatpath, sizeof (whatpath), "%s/%s", b->path, 71395c635efSGarrett D'Amore WHATIS); 71495c635efSGarrett D'Amore search_whatis(whatpath, word); 71595c635efSGarrett D'Amore } 71695c635efSGarrett D'Amore } 71795c635efSGarrett D'Amore 71895c635efSGarrett D'Amore static void 71995c635efSGarrett D'Amore search_whatis(char *whatpath, char *word) 72095c635efSGarrett D'Amore { 72195c635efSGarrett D'Amore FILE *fp; 72295c635efSGarrett D'Amore char *line = NULL; 72395c635efSGarrett D'Amore size_t linecap = 0; 72495c635efSGarrett D'Amore char *pkwd; 72595c635efSGarrett D'Amore regex_t preg; 72695c635efSGarrett D'Amore char **ss = NULL; 72795c635efSGarrett D'Amore char s[MAXNAMELEN]; 72895c635efSGarrett D'Amore int i; 72995c635efSGarrett D'Amore 73095c635efSGarrett D'Amore if ((fp = fopen(whatpath, "r")) == NULL) { 73195c635efSGarrett D'Amore perror(whatpath); 73295c635efSGarrett D'Amore return; 73395c635efSGarrett D'Amore } 73495c635efSGarrett D'Amore 73595c635efSGarrett D'Amore DPRINTF("-- Found %s: %s\n", WHATIS, whatpath); 73695c635efSGarrett D'Amore 73795c635efSGarrett D'Amore /* Build keyword regex */ 73895c635efSGarrett D'Amore if (asprintf(&pkwd, "%s%s%s", (whatis) ? "\\<" : "", 73995c635efSGarrett D'Amore word, (whatis) ? "\\>" : "") == -1) 74095c635efSGarrett D'Amore err(1, "asprintf"); 74195c635efSGarrett D'Amore 74295c635efSGarrett D'Amore if (regcomp(&preg, pkwd, REG_BASIC | REG_ICASE | REG_NOSUB) != 0) 74395c635efSGarrett D'Amore err(1, "regcomp"); 74495c635efSGarrett D'Amore 74595c635efSGarrett D'Amore if (sargs) 74695c635efSGarrett D'Amore ss = split(mansec, ','); 74795c635efSGarrett D'Amore 74895c635efSGarrett D'Amore while (getline(&line, &linecap, fp) > 0) { 74995c635efSGarrett D'Amore if (regexec(&preg, line, 0, NULL, 0) == 0) { 75095c635efSGarrett D'Amore if (sargs) { 75195c635efSGarrett D'Amore /* Section-restricted search */ 75295c635efSGarrett D'Amore for (i = 0; ss[i] != NULL; i++) { 75395c635efSGarrett D'Amore (void) snprintf(s, sizeof (s), "(%s)", 75495c635efSGarrett D'Amore ss[i]); 75595c635efSGarrett D'Amore if (strstr(line, s) != NULL) { 75695c635efSGarrett D'Amore (void) printf("%s", line); 75795c635efSGarrett D'Amore break; 75895c635efSGarrett D'Amore } 75995c635efSGarrett D'Amore } 76095c635efSGarrett D'Amore } else { 76195c635efSGarrett D'Amore (void) printf("%s", line); 76295c635efSGarrett D'Amore } 76395c635efSGarrett D'Amore } 76495c635efSGarrett D'Amore } 76595c635efSGarrett D'Amore 76695c635efSGarrett D'Amore if (ss != NULL) 76795c635efSGarrett D'Amore freev(ss); 76895c635efSGarrett D'Amore free(pkwd); 76995c635efSGarrett D'Amore (void) fclose(fp); 77095c635efSGarrett D'Amore } 77195c635efSGarrett D'Amore 77295c635efSGarrett D'Amore 77395c635efSGarrett D'Amore /* 77495c635efSGarrett D'Amore * Split a string by specified separator. 77595c635efSGarrett D'Amore */ 77695c635efSGarrett D'Amore static char ** 77795c635efSGarrett D'Amore split(char *s1, char sep) 77895c635efSGarrett D'Amore { 77995c635efSGarrett D'Amore char **tokv, **vp; 78095c635efSGarrett D'Amore char *mp = s1, *tp; 78195c635efSGarrett D'Amore int maxentries = MAXTOKENS; 78295c635efSGarrett D'Amore int entries = 0; 78395c635efSGarrett D'Amore 78495c635efSGarrett D'Amore if ((tokv = vp = malloc(maxentries * sizeof (char *))) == NULL) 78595c635efSGarrett D'Amore err(1, "malloc"); 78695c635efSGarrett D'Amore 78795c635efSGarrett D'Amore for (; mp && *mp; mp = tp) { 78895c635efSGarrett D'Amore tp = strchr(mp, sep); 78995c635efSGarrett D'Amore if (mp == tp) { 79095c635efSGarrett D'Amore tp++; 79195c635efSGarrett D'Amore continue; 79295c635efSGarrett D'Amore } 79395c635efSGarrett D'Amore if (tp) { 79495c635efSGarrett D'Amore size_t len; 79595c635efSGarrett D'Amore 79695c635efSGarrett D'Amore len = tp - mp; 79795c635efSGarrett D'Amore if ((*vp = (char *)malloc(sizeof (char) * 79895c635efSGarrett D'Amore len + 1)) == NULL) 79995c635efSGarrett D'Amore err(1, "malloc"); 80095c635efSGarrett D'Amore (void) strncpy(*vp, mp, len); 80195c635efSGarrett D'Amore *(*vp + len) = '\0'; 80295c635efSGarrett D'Amore tp++; 80395c635efSGarrett D'Amore vp++; 80495c635efSGarrett D'Amore } else { 80595c635efSGarrett D'Amore if ((*vp = strdup(mp)) == NULL) 80695c635efSGarrett D'Amore err(1, "strdup"); 80795c635efSGarrett D'Amore vp++; 80895c635efSGarrett D'Amore } 80995c635efSGarrett D'Amore entries++; 81095c635efSGarrett D'Amore if (entries == maxentries) { 81195c635efSGarrett D'Amore maxentries += MAXTOKENS; 81295c635efSGarrett D'Amore if ((tokv = realloc(tokv, 81395c635efSGarrett D'Amore maxentries * sizeof (char *))) == NULL) 81495c635efSGarrett D'Amore err(1, "realloc"); 81595c635efSGarrett D'Amore vp = tokv + entries; 81695c635efSGarrett D'Amore } 81795c635efSGarrett D'Amore } 81895c635efSGarrett D'Amore *vp = 0; 81995c635efSGarrett D'Amore 82095c635efSGarrett D'Amore return (tokv); 82195c635efSGarrett D'Amore } 82295c635efSGarrett D'Amore 82395c635efSGarrett D'Amore /* 82495c635efSGarrett D'Amore * Free a vector allocated by split() 82595c635efSGarrett D'Amore */ 82695c635efSGarrett D'Amore static void 82795c635efSGarrett D'Amore freev(char **v) 82895c635efSGarrett D'Amore { 82995c635efSGarrett D'Amore int i; 83095c635efSGarrett D'Amore if (v != NULL) { 83195c635efSGarrett D'Amore for (i = 0; v[i] != NULL; i++) { 83295c635efSGarrett D'Amore free(v[i]); 83395c635efSGarrett D'Amore } 83495c635efSGarrett D'Amore free(v); 83595c635efSGarrett D'Amore } 83695c635efSGarrett D'Amore } 83795c635efSGarrett D'Amore 83895c635efSGarrett D'Amore /* 83995c635efSGarrett D'Amore * Convert paths to full paths if necessary 84095c635efSGarrett D'Amore */ 84195c635efSGarrett D'Amore static void 84295c635efSGarrett D'Amore fullpaths(struct man_node **manp_head) 84395c635efSGarrett D'Amore { 84495c635efSGarrett D'Amore char *cwd = NULL; 84595c635efSGarrett D'Amore char *p; 84695c635efSGarrett D'Amore int cwd_gotten = 0; 84795c635efSGarrett D'Amore struct man_node *manp = *manp_head; 84895c635efSGarrett D'Amore struct man_node *b; 84995c635efSGarrett D'Amore struct man_node *prev = NULL; 85095c635efSGarrett D'Amore 85195c635efSGarrett D'Amore for (b = manp; b != NULL; b = b->next) { 85295c635efSGarrett D'Amore if (*(b->path) == '/') { 85395c635efSGarrett D'Amore prev = b; 85495c635efSGarrett D'Amore continue; 85595c635efSGarrett D'Amore } 85695c635efSGarrett D'Amore 85795c635efSGarrett D'Amore if (!cwd_gotten) { 85895c635efSGarrett D'Amore cwd = getcwd(NULL, MAXPATHLEN); 85995c635efSGarrett D'Amore cwd_gotten = 1; 86095c635efSGarrett D'Amore } 86195c635efSGarrett D'Amore 86295c635efSGarrett D'Amore if (cwd) { 86395c635efSGarrett D'Amore /* Relative manpath with cwd: make absolute */ 86495c635efSGarrett D'Amore if (asprintf(&p, "%s/%s", cwd, b->path) == -1) 86595c635efSGarrett D'Amore err(1, "asprintf"); 86695c635efSGarrett D'Amore free(b->path); 86795c635efSGarrett D'Amore b->path = p; 86895c635efSGarrett D'Amore } else { 86995c635efSGarrett D'Amore /* Relative manpath but no cwd: omit path entry */ 87095c635efSGarrett D'Amore if (prev) 87195c635efSGarrett D'Amore prev->next = b->next; 87295c635efSGarrett D'Amore else 87395c635efSGarrett D'Amore *manp_head = b->next; 87495c635efSGarrett D'Amore 87595c635efSGarrett D'Amore free_manp(b); 87695c635efSGarrett D'Amore } 87795c635efSGarrett D'Amore } 87895c635efSGarrett D'Amore free(cwd); 87995c635efSGarrett D'Amore } 88095c635efSGarrett D'Amore 88195c635efSGarrett D'Amore /* 88295c635efSGarrett D'Amore * Free a man_node structure and its contents 88395c635efSGarrett D'Amore */ 88495c635efSGarrett D'Amore static void 88595c635efSGarrett D'Amore free_manp(struct man_node *manp) 88695c635efSGarrett D'Amore { 88795c635efSGarrett D'Amore char **p; 88895c635efSGarrett D'Amore 88995c635efSGarrett D'Amore free(manp->path); 89095c635efSGarrett D'Amore p = manp->secv; 89195c635efSGarrett D'Amore while ((p != NULL) && (*p != NULL)) { 89295c635efSGarrett D'Amore free(*p); 89395c635efSGarrett D'Amore p++; 89495c635efSGarrett D'Amore } 89595c635efSGarrett D'Amore free(manp->secv); 89695c635efSGarrett D'Amore free(manp); 89795c635efSGarrett D'Amore } 89895c635efSGarrett D'Amore 89995c635efSGarrett D'Amore 90095c635efSGarrett D'Amore /* 90195c635efSGarrett D'Amore * Map (in place) to lower case. 90295c635efSGarrett D'Amore */ 90395c635efSGarrett D'Amore static void 90495c635efSGarrett D'Amore lower(char *s) 90595c635efSGarrett D'Amore { 90695c635efSGarrett D'Amore 90795c635efSGarrett D'Amore if (s == 0) 90895c635efSGarrett D'Amore return; 90995c635efSGarrett D'Amore while (*s) { 91095c635efSGarrett D'Amore if (isupper(*s)) 91195c635efSGarrett D'Amore *s = tolower(*s); 91295c635efSGarrett D'Amore s++; 91395c635efSGarrett D'Amore } 91495c635efSGarrett D'Amore } 91595c635efSGarrett D'Amore 91695c635efSGarrett D'Amore 91795c635efSGarrett D'Amore /* 91895c635efSGarrett D'Amore * Compare function for qsort(). 91995c635efSGarrett D'Amore * Sort first by section, then by prefix. 92095c635efSGarrett D'Amore */ 92195c635efSGarrett D'Amore static int 92295c635efSGarrett D'Amore cmp(const void *arg1, const void *arg2) 92395c635efSGarrett D'Amore { 92495c635efSGarrett D'Amore int n; 92595c635efSGarrett D'Amore char **p1 = (char **)arg1; 92695c635efSGarrett D'Amore char **p2 = (char **)arg2; 92795c635efSGarrett D'Amore 92895c635efSGarrett D'Amore /* By section */ 92995c635efSGarrett D'Amore if ((n = strcmp(*p1 + 3, *p2 + 3)) != 0) 93095c635efSGarrett D'Amore return (n); 93195c635efSGarrett D'Amore 93295c635efSGarrett D'Amore /* By prefix reversed */ 93395c635efSGarrett D'Amore return (strncmp(*p2, *p1, 3)); 93495c635efSGarrett D'Amore } 93595c635efSGarrett D'Amore 93695c635efSGarrett D'Amore 93795c635efSGarrett D'Amore /* 93895c635efSGarrett D'Amore * Find a manpage. 93995c635efSGarrett D'Amore */ 94095c635efSGarrett D'Amore static int 94195c635efSGarrett D'Amore manual(struct man_node *manp, char *name) 94295c635efSGarrett D'Amore { 94395c635efSGarrett D'Amore struct man_node *p; 94495c635efSGarrett D'Amore struct man_node *local; 94595c635efSGarrett D'Amore int ndirs = 0; 94695c635efSGarrett D'Amore char *ldir; 94795c635efSGarrett D'Amore char *ldirs[2]; 94895c635efSGarrett D'Amore char *fullname = name; 94995c635efSGarrett D'Amore char *slash; 95095c635efSGarrett D'Amore 95195c635efSGarrett D'Amore if ((slash = strrchr(name, '/')) != NULL) 95295c635efSGarrett D'Amore name = slash + 1; 95395c635efSGarrett D'Amore 95495c635efSGarrett D'Amore /* For each path in MANPATH */ 95595c635efSGarrett D'Amore found = 0; 95695c635efSGarrett D'Amore 95795c635efSGarrett D'Amore for (p = manp; p != NULL; p = p->next) { 95895c635efSGarrett D'Amore DPRINTF("-- Searching mandir: %s\n", p->path); 95995c635efSGarrett D'Amore 96095c635efSGarrett D'Amore if (*localedir != '\0') { 96195c635efSGarrett D'Amore ldir = addlocale(p->path); 96295c635efSGarrett D'Amore ndirs = getdirs(ldir, NULL, 0); 96395c635efSGarrett D'Amore if (ndirs != 0) { 96495c635efSGarrett D'Amore ldirs[0] = ldir; 96595c635efSGarrett D'Amore ldirs[1] = NULL; 96695c635efSGarrett D'Amore local = build_manpath(ldirs, 0); 96795c635efSGarrett D'Amore DPRINTF("-- Locale specific subdir: %s\n", 96895c635efSGarrett D'Amore ldir); 96995c635efSGarrett D'Amore mandir(local->secv, ldir, name, 1); 97095c635efSGarrett D'Amore free_manp(local); 97195c635efSGarrett D'Amore } 97295c635efSGarrett D'Amore free(ldir); 97395c635efSGarrett D'Amore } 97495c635efSGarrett D'Amore 97595c635efSGarrett D'Amore /* 97695c635efSGarrett D'Amore * Locale mandir not valid, man page in locale 97795c635efSGarrett D'Amore * mandir not found, or -a option present 97895c635efSGarrett D'Amore */ 97995c635efSGarrett D'Amore if (ndirs == 0 || !found || all) 98095c635efSGarrett D'Amore mandir(p->secv, p->path, name, 0); 98195c635efSGarrett D'Amore 98295c635efSGarrett D'Amore if (found && !all) 98395c635efSGarrett D'Amore break; 98495c635efSGarrett D'Amore } 98595c635efSGarrett D'Amore 98695c635efSGarrett D'Amore if (!found) { 98795c635efSGarrett D'Amore if (sargs) { 98895c635efSGarrett D'Amore (void) fprintf(stderr, gettext( 98995c635efSGarrett D'Amore "No manual entry for %s in section(s) %s\n"), 99095c635efSGarrett D'Amore fullname, mansec); 99195c635efSGarrett D'Amore } else { 99295c635efSGarrett D'Amore (void) fprintf(stderr, 99395c635efSGarrett D'Amore gettext("No manual entry for %s\n"), fullname); 99495c635efSGarrett D'Amore } 99595c635efSGarrett D'Amore 99695c635efSGarrett D'Amore } 99795c635efSGarrett D'Amore 99895c635efSGarrett D'Amore return (!found); 99995c635efSGarrett D'Amore } 100095c635efSGarrett D'Amore 100195c635efSGarrett D'Amore 100295c635efSGarrett D'Amore /* 100395c635efSGarrett D'Amore * For a specified manual directory, read, store and sort section subdirs. 100495c635efSGarrett D'Amore * For each section specified, find and search matching subdirs. 100595c635efSGarrett D'Amore */ 100695c635efSGarrett D'Amore static void 100795c635efSGarrett D'Amore mandir(char **secv, char *path, char *name, int lspec) 100895c635efSGarrett D'Amore { 100995c635efSGarrett D'Amore DIR *dp; 101095c635efSGarrett D'Amore char **dirv; 101195c635efSGarrett D'Amore char **dv, **pdv; 101295c635efSGarrett D'Amore int len, dslen; 101395c635efSGarrett D'Amore 101495c635efSGarrett D'Amore if ((dp = opendir(path)) == NULL) 101595c635efSGarrett D'Amore return; 101695c635efSGarrett D'Amore 101795c635efSGarrett D'Amore if (lspec) 101895c635efSGarrett D'Amore DPRINTF("-- Searching mandir: %s\n", path); 101995c635efSGarrett D'Amore 102095c635efSGarrett D'Amore sortdir(dp, &dirv); 102195c635efSGarrett D'Amore 102295c635efSGarrett D'Amore /* Search in the order specified by MANSECTS */ 102395c635efSGarrett D'Amore for (; *secv; secv++) { 102495c635efSGarrett D'Amore len = strlen(*secv); 102595c635efSGarrett D'Amore for (dv = dirv; *dv; dv++) { 102695c635efSGarrett D'Amore dslen = strlen(*dv + 3); 102795c635efSGarrett D'Amore if (dslen > len) 102895c635efSGarrett D'Amore len = dslen; 102995c635efSGarrett D'Amore if (**secv == '\\') { 103095c635efSGarrett D'Amore if (strcmp(*secv + 1, *dv + 3) != 0) 103195c635efSGarrett D'Amore continue; 103295c635efSGarrett D'Amore } else if (strncasecmp(*secv, *dv + 3, len) != 0) { 103395c635efSGarrett D'Amore if (!all && 103495c635efSGarrett D'Amore (newsection = map_section(*secv, path)) 103595c635efSGarrett D'Amore == NULL) { 103695c635efSGarrett D'Amore continue; 103795c635efSGarrett D'Amore } 103895c635efSGarrett D'Amore if (newsection == NULL) 103995c635efSGarrett D'Amore newsection = ""; 104095c635efSGarrett D'Amore if (strncmp(newsection, *dv + 3, len) != 0) { 104195c635efSGarrett D'Amore continue; 104295c635efSGarrett D'Amore } 104395c635efSGarrett D'Amore } 104495c635efSGarrett D'Amore 104595c635efSGarrett D'Amore if (searchdir(path, *dv, name) == 0) 104695c635efSGarrett D'Amore continue; 104795c635efSGarrett D'Amore 104895c635efSGarrett D'Amore if (!all) { 104995c635efSGarrett D'Amore pdv = dirv; 105095c635efSGarrett D'Amore while (*pdv) { 105195c635efSGarrett D'Amore free(*pdv); 105295c635efSGarrett D'Amore pdv++; 105395c635efSGarrett D'Amore } 105495c635efSGarrett D'Amore (void) closedir(dp); 105595c635efSGarrett D'Amore free(dirv); 105695c635efSGarrett D'Amore return; 105795c635efSGarrett D'Amore } 105895c635efSGarrett D'Amore 105995c635efSGarrett D'Amore if (all && **dv == 'm' && *(dv + 1) && 106095c635efSGarrett D'Amore strcmp(*(dv + 1) + 3, *dv + 3) == 0) 106195c635efSGarrett D'Amore dv++; 106295c635efSGarrett D'Amore } 106395c635efSGarrett D'Amore } 106495c635efSGarrett D'Amore pdv = dirv; 106595c635efSGarrett D'Amore while (*pdv != NULL) { 106695c635efSGarrett D'Amore free(*pdv); 106795c635efSGarrett D'Amore pdv++; 106895c635efSGarrett D'Amore } 106995c635efSGarrett D'Amore free(dirv); 107095c635efSGarrett D'Amore (void) closedir(dp); 107195c635efSGarrett D'Amore } 107295c635efSGarrett D'Amore 107395c635efSGarrett D'Amore /* 107495c635efSGarrett D'Amore * Sort directories. 107595c635efSGarrett D'Amore */ 107695c635efSGarrett D'Amore static void 107795c635efSGarrett D'Amore sortdir(DIR *dp, char ***dirv) 107895c635efSGarrett D'Amore { 107995c635efSGarrett D'Amore struct dirent *d; 108095c635efSGarrett D'Amore char **dv; 108195c635efSGarrett D'Amore int maxentries = MAXDIRS; 108295c635efSGarrett D'Amore int entries = 0; 108395c635efSGarrett D'Amore 108495c635efSGarrett D'Amore if ((dv = *dirv = malloc(sizeof (char *) * 108595c635efSGarrett D'Amore maxentries)) == NULL) 108695c635efSGarrett D'Amore err(1, "malloc"); 108795c635efSGarrett D'Amore dv = *dirv; 108895c635efSGarrett D'Amore 108995c635efSGarrett D'Amore while ((d = readdir(dp))) { 109095c635efSGarrett D'Amore if (strcmp(d->d_name, ".") == 0 || 109195c635efSGarrett D'Amore strcmp(d->d_name, "..") == 0) 109295c635efSGarrett D'Amore continue; 109395c635efSGarrett D'Amore 109495c635efSGarrett D'Amore if (strncmp(d->d_name, "man", 3) == 0 || 109595c635efSGarrett D'Amore strncmp(d->d_name, "cat", 3) == 0) { 109695c635efSGarrett D'Amore if ((*dv = strdup(d->d_name)) == NULL) 109795c635efSGarrett D'Amore err(1, "strdup"); 109895c635efSGarrett D'Amore dv++; 109995c635efSGarrett D'Amore entries++; 110095c635efSGarrett D'Amore if (entries == maxentries) { 110195c635efSGarrett D'Amore maxentries += MAXDIRS; 110295c635efSGarrett D'Amore if ((*dirv = realloc(*dirv, 110395c635efSGarrett D'Amore sizeof (char *) * maxentries)) == NULL) 110495c635efSGarrett D'Amore err(1, "realloc"); 110595c635efSGarrett D'Amore dv = *dirv + entries; 110695c635efSGarrett D'Amore } 110795c635efSGarrett D'Amore } 110895c635efSGarrett D'Amore } 110995c635efSGarrett D'Amore *dv = 0; 111095c635efSGarrett D'Amore 111195c635efSGarrett D'Amore qsort((void *)*dirv, dv - *dirv, sizeof (char *), cmp); 111295c635efSGarrett D'Amore 111395c635efSGarrett D'Amore } 111495c635efSGarrett D'Amore 111595c635efSGarrett D'Amore 111695c635efSGarrett D'Amore /* 111795c635efSGarrett D'Amore * Search a section subdir for a given manpage. 111895c635efSGarrett D'Amore */ 111995c635efSGarrett D'Amore static int 112095c635efSGarrett D'Amore searchdir(char *path, char *dir, char *name) 112195c635efSGarrett D'Amore { 112295c635efSGarrett D'Amore DIR *sdp; 112395c635efSGarrett D'Amore struct dirent *sd; 112495c635efSGarrett D'Amore char sectpath[MAXPATHLEN]; 112595c635efSGarrett D'Amore char file[MAXNAMLEN]; 112695c635efSGarrett D'Amore char dname[MAXPATHLEN]; 112795c635efSGarrett D'Amore char *last; 112895c635efSGarrett D'Amore int nlen; 112995c635efSGarrett D'Amore 113095c635efSGarrett D'Amore (void) snprintf(sectpath, sizeof (sectpath), "%s/%s", path, dir); 113195c635efSGarrett D'Amore (void) snprintf(file, sizeof (file), "%s.", name); 113295c635efSGarrett D'Amore 113395c635efSGarrett D'Amore if ((sdp = opendir(sectpath)) == NULL) 113495c635efSGarrett D'Amore return (0); 113595c635efSGarrett D'Amore 113695c635efSGarrett D'Amore while ((sd = readdir(sdp))) { 113795c635efSGarrett D'Amore char *pname; 113895c635efSGarrett D'Amore 113995c635efSGarrett D'Amore if ((pname = strdup(sd->d_name)) == NULL) 114095c635efSGarrett D'Amore err(1, "strdup"); 114195c635efSGarrett D'Amore if ((last = strrchr(pname, '.')) != NULL && 114295c635efSGarrett D'Amore (strcmp(last, ".gz") == 0 || strcmp(last, ".bz2") == 0)) 114395c635efSGarrett D'Amore *last = '\0'; 114495c635efSGarrett D'Amore last = strrchr(pname, '.'); 114595c635efSGarrett D'Amore nlen = last - pname; 114695c635efSGarrett D'Amore (void) snprintf(dname, sizeof (dname), "%.*s.", nlen, pname); 114795c635efSGarrett D'Amore if (strcmp(dname, file) == 0 || 114895c635efSGarrett D'Amore strcmp(pname, name) == 0) { 114995c635efSGarrett D'Amore (void) format(path, dir, name, sd->d_name); 115095c635efSGarrett D'Amore (void) closedir(sdp); 115195c635efSGarrett D'Amore free(pname); 115295c635efSGarrett D'Amore return (1); 115395c635efSGarrett D'Amore } 115495c635efSGarrett D'Amore free(pname); 115595c635efSGarrett D'Amore } 115695c635efSGarrett D'Amore (void) closedir(sdp); 115795c635efSGarrett D'Amore 115895c635efSGarrett D'Amore return (0); 115995c635efSGarrett D'Amore } 116095c635efSGarrett D'Amore 116195c635efSGarrett D'Amore /* 116295c635efSGarrett D'Amore * Check the hash table of old directory names to see if there is a 116395c635efSGarrett D'Amore * new directory name. 116495c635efSGarrett D'Amore */ 116595c635efSGarrett D'Amore static char * 116695c635efSGarrett D'Amore map_section(char *section, char *path) 116795c635efSGarrett D'Amore { 116895c635efSGarrett D'Amore int i; 116995c635efSGarrett D'Amore char fullpath[MAXPATHLEN]; 117095c635efSGarrett D'Amore 117195c635efSGarrett D'Amore if (list) /* -l option fall through */ 117295c635efSGarrett D'Amore return (NULL); 117395c635efSGarrett D'Amore 117495c635efSGarrett D'Amore for (i = 0; map[i].new_name != NULL; i++) { 117595c635efSGarrett D'Amore if (strcmp(section, map[i].old_name) == 0) { 117695c635efSGarrett D'Amore (void) snprintf(fullpath, sizeof (fullpath), 117795c635efSGarrett D'Amore "%s/man%s", path, map[i].new_name); 117895c635efSGarrett D'Amore if (!access(fullpath, R_OK | X_OK)) { 117995c635efSGarrett D'Amore return (map[i].new_name); 118095c635efSGarrett D'Amore } else { 118195c635efSGarrett D'Amore return (NULL); 118295c635efSGarrett D'Amore } 118395c635efSGarrett D'Amore } 118495c635efSGarrett D'Amore } 118595c635efSGarrett D'Amore 118695c635efSGarrett D'Amore return (NULL); 118795c635efSGarrett D'Amore } 118895c635efSGarrett D'Amore 118995c635efSGarrett D'Amore /* 119095c635efSGarrett D'Amore * Format the manpage. 119195c635efSGarrett D'Amore */ 119295c635efSGarrett D'Amore static int 119395c635efSGarrett D'Amore format(char *path, char *dir, char *name, char *pg) 119495c635efSGarrett D'Amore { 119595c635efSGarrett D'Amore char manpname[MAXPATHLEN], catpname[MAXPATHLEN]; 119695c635efSGarrett D'Amore char cmdbuf[BUFSIZ], tmpbuf[BUFSIZ]; 119795c635efSGarrett D'Amore char *cattool; 119895c635efSGarrett D'Amore struct stat sbman, sbcat; 119995c635efSGarrett D'Amore 120095c635efSGarrett D'Amore found++; 120195c635efSGarrett D'Amore 120295c635efSGarrett D'Amore if (list) { 120395c635efSGarrett D'Amore (void) printf(gettext("%s(%s)\t-M %s\n"), name, dir + 3, path); 120495c635efSGarrett D'Amore return (-1); 120595c635efSGarrett D'Amore } 120695c635efSGarrett D'Amore 120795c635efSGarrett D'Amore (void) snprintf(manpname, sizeof (manpname), "%s/man%s/%s", path, 120895c635efSGarrett D'Amore dir + 3, pg); 120995c635efSGarrett D'Amore (void) snprintf(catpname, sizeof (catpname), "%s/cat%s/%s", path, 121095c635efSGarrett D'Amore dir + 3, pg); 121195c635efSGarrett D'Amore 121295c635efSGarrett D'Amore /* Can't do PS output if manpage doesn't exist */ 121395c635efSGarrett D'Amore if (stat(manpname, &sbman) != 0 && (psoutput|lintout)) 121495c635efSGarrett D'Amore return (-1); 121595c635efSGarrett D'Amore 121695c635efSGarrett D'Amore /* 121795c635efSGarrett D'Amore * If both manpage and catpage do not exist, manpname is 121895c635efSGarrett D'Amore * broken symlink, most likely. 121995c635efSGarrett D'Amore */ 122095c635efSGarrett D'Amore if (stat(catpname, &sbcat) != 0 && stat(manpname, &sbman) != 0) 122195c635efSGarrett D'Amore err(1, "%s", manpname); 122295c635efSGarrett D'Amore 122395c635efSGarrett D'Amore /* Setup cattool */ 122495c635efSGarrett D'Amore if (fnmatch("*.gz", manpname, 0) == 0) 122595c635efSGarrett D'Amore cattool = "gzcat"; 122695c635efSGarrett D'Amore else if (fnmatch("*.bz2", manpname, 0) == 0) 122795c635efSGarrett D'Amore cattool = "bzcat"; 122895c635efSGarrett D'Amore else 122995c635efSGarrett D'Amore cattool = "cat"; 123095c635efSGarrett D'Amore 123195c635efSGarrett D'Amore if (psoutput) { 123295c635efSGarrett D'Amore (void) snprintf(cmdbuf, BUFSIZ, 1233260e9a87SYuri Pankov "cd %s; %s %s | mandoc -Tps | lp -Tpostscript", 1234260e9a87SYuri Pankov path, cattool, manpname); 123595c635efSGarrett D'Amore DPRINTF("-- Using manpage: %s\n", manpname); 123695c635efSGarrett D'Amore goto cmd; 123795c635efSGarrett D'Amore } else if (lintout) { 123895c635efSGarrett D'Amore (void) snprintf(cmdbuf, BUFSIZ, 1239260e9a87SYuri Pankov "cd %s; %s %s | mandoc -Tlint", 1240260e9a87SYuri Pankov path, cattool, manpname); 124195c635efSGarrett D'Amore DPRINTF("-- Linting manpage: %s\n", manpname); 124295c635efSGarrett D'Amore goto cmd; 124395c635efSGarrett D'Amore } 124495c635efSGarrett D'Amore 124595c635efSGarrett D'Amore /* 124695c635efSGarrett D'Amore * Output catpage if: 124795c635efSGarrett D'Amore * - manpage doesn't exist 124895c635efSGarrett D'Amore * - output width is standard and catpage is recent enough 124995c635efSGarrett D'Amore */ 125095c635efSGarrett D'Amore if (stat(manpname, &sbman) != 0 || (manwidth == 0 && 125195c635efSGarrett D'Amore stat(catpname, &sbcat) == 0 && sbcat.st_mtime >= sbman.st_mtime)) { 125295c635efSGarrett D'Amore DPRINTF("-- Using catpage: %s\n", catpname); 125395c635efSGarrett D'Amore (void) snprintf(cmdbuf, BUFSIZ, "%s %s", pager, catpname); 125495c635efSGarrett D'Amore goto cmd; 125595c635efSGarrett D'Amore } 125695c635efSGarrett D'Amore 125795c635efSGarrett D'Amore DPRINTF("-- Using manpage: %s\n", manpname); 125895c635efSGarrett D'Amore if (manwidth > 0) 125995c635efSGarrett D'Amore (void) snprintf(tmpbuf, BUFSIZ, "-Owidth=%d ", manwidth); 1260260e9a87SYuri Pankov (void) snprintf(cmdbuf, BUFSIZ, "cd %s; %s %s | mandoc %s| %s", 1261260e9a87SYuri Pankov path, cattool, manpname, (manwidth > 0) ? tmpbuf : "", pager); 126295c635efSGarrett D'Amore 126395c635efSGarrett D'Amore cmd: 126495c635efSGarrett D'Amore DPRINTF("-- Command: %s\n", cmdbuf); 126595c635efSGarrett D'Amore 126695c635efSGarrett D'Amore if (!debug) 126795c635efSGarrett D'Amore return (system(cmdbuf) == 0); 126895c635efSGarrett D'Amore else 126995c635efSGarrett D'Amore return (0); 127095c635efSGarrett D'Amore } 127195c635efSGarrett D'Amore 127295c635efSGarrett D'Amore /* 127395c635efSGarrett D'Amore * Add <localedir> to the path. 127495c635efSGarrett D'Amore */ 127595c635efSGarrett D'Amore static char * 127695c635efSGarrett D'Amore addlocale(char *path) 127795c635efSGarrett D'Amore { 127895c635efSGarrett D'Amore char *tmp; 127995c635efSGarrett D'Amore 128095c635efSGarrett D'Amore if (asprintf(&tmp, "%s/%s", path, localedir) == -1) 128195c635efSGarrett D'Amore err(1, "asprintf"); 128295c635efSGarrett D'Amore 128395c635efSGarrett D'Amore return (tmp); 128495c635efSGarrett D'Amore } 128595c635efSGarrett D'Amore 128695c635efSGarrett D'Amore /* 128795c635efSGarrett D'Amore * Get the order of sections from man.cf. 128895c635efSGarrett D'Amore */ 128995c635efSGarrett D'Amore static char * 129095c635efSGarrett D'Amore check_config(char *path) 129195c635efSGarrett D'Amore { 129295c635efSGarrett D'Amore FILE *fp; 129395c635efSGarrett D'Amore char *rc = NULL; 1294*d456640dSYuri Pankov char *sect = NULL; 129595c635efSGarrett D'Amore char fname[MAXPATHLEN]; 129695c635efSGarrett D'Amore char *line = NULL; 1297*d456640dSYuri Pankov char *nl; 129895c635efSGarrett D'Amore size_t linecap = 0; 129995c635efSGarrett D'Amore 130095c635efSGarrett D'Amore (void) snprintf(fname, MAXPATHLEN, "%s/%s", path, CONFIG); 130195c635efSGarrett D'Amore 130295c635efSGarrett D'Amore if ((fp = fopen(fname, "r")) == NULL) 130395c635efSGarrett D'Amore return (NULL); 130495c635efSGarrett D'Amore 130595c635efSGarrett D'Amore while (getline(&line, &linecap, fp) > 0) { 1306*d456640dSYuri Pankov if ((rc = strstr(line, "MANSECTS=")) != NULL) 130795c635efSGarrett D'Amore break; 130895c635efSGarrett D'Amore } 130995c635efSGarrett D'Amore 131095c635efSGarrett D'Amore (void) fclose(fp); 131195c635efSGarrett D'Amore 1312*d456640dSYuri Pankov if (rc != NULL) { 1313*d456640dSYuri Pankov if ((nl = strchr(rc, '\n')) != NULL) 1314*d456640dSYuri Pankov *nl = '\0'; 1315*d456640dSYuri Pankov sect = strchr(rc, '=') + 1; 131695c635efSGarrett D'Amore } 131795c635efSGarrett D'Amore 1318*d456640dSYuri Pankov return (sect); 1319*d456640dSYuri Pankov } 132095c635efSGarrett D'Amore 132195c635efSGarrett D'Amore /* 132295c635efSGarrett D'Amore * Initialize the bintoman array with appropriate device and inode info. 132395c635efSGarrett D'Amore */ 132495c635efSGarrett D'Amore static void 132595c635efSGarrett D'Amore init_bintoman(void) 132695c635efSGarrett D'Amore { 132795c635efSGarrett D'Amore int i; 132895c635efSGarrett D'Amore struct stat sb; 132995c635efSGarrett D'Amore 133095c635efSGarrett D'Amore for (i = 0; bintoman[i].bindir != NULL; i++) { 133195c635efSGarrett D'Amore if (stat(bintoman[i].bindir, &sb) == 0) { 133295c635efSGarrett D'Amore bintoman[i].dev = sb.st_dev; 133395c635efSGarrett D'Amore bintoman[i].ino = sb.st_ino; 133495c635efSGarrett D'Amore } else { 133595c635efSGarrett D'Amore bintoman[i].dev = NODEV; 133695c635efSGarrett D'Amore } 133795c635efSGarrett D'Amore } 133895c635efSGarrett D'Amore } 133995c635efSGarrett D'Amore 134095c635efSGarrett D'Amore /* 134195c635efSGarrett D'Amore * If a duplicate is found, return 1. 134295c635efSGarrett D'Amore * If a duplicate is not found, add it to the dupnode list and return 0. 134395c635efSGarrett D'Amore */ 134495c635efSGarrett D'Amore static int 134595c635efSGarrett D'Amore dupcheck(struct man_node *mnp, struct dupnode **dnp) 134695c635efSGarrett D'Amore { 134795c635efSGarrett D'Amore struct dupnode *curdnp; 134895c635efSGarrett D'Amore struct secnode *cursnp; 134995c635efSGarrett D'Amore struct stat sb; 135095c635efSGarrett D'Amore int i; 135195c635efSGarrett D'Amore int rv = 1; 135295c635efSGarrett D'Amore int dupfound; 135395c635efSGarrett D'Amore 135495c635efSGarrett D'Amore /* If the path doesn't exist, treat it as a duplicate */ 135595c635efSGarrett D'Amore if (stat(mnp->path, &sb) != 0) 135695c635efSGarrett D'Amore return (1); 135795c635efSGarrett D'Amore 135895c635efSGarrett D'Amore /* If no sections were found in the man dir, treat it as duplicate */ 135995c635efSGarrett D'Amore if (mnp->secv == NULL) 136095c635efSGarrett D'Amore return (1); 136195c635efSGarrett D'Amore 136295c635efSGarrett D'Amore /* 136395c635efSGarrett D'Amore * Find the dupnode structure for the previous time this directory 136495c635efSGarrett D'Amore * was looked at. Device and inode numbers are compared so that 136595c635efSGarrett D'Amore * directories that are reached via different paths (e.g. /usr/man and 136695c635efSGarrett D'Amore * /usr/share/man) are treated as equivalent. 136795c635efSGarrett D'Amore */ 136895c635efSGarrett D'Amore for (curdnp = *dnp; curdnp != NULL; curdnp = curdnp->next) { 136995c635efSGarrett D'Amore if (curdnp->dev == sb.st_dev && curdnp->ino == sb.st_ino) 137095c635efSGarrett D'Amore break; 137195c635efSGarrett D'Amore } 137295c635efSGarrett D'Amore 137395c635efSGarrett D'Amore /* 137495c635efSGarrett D'Amore * First time this directory has been seen. Add a new node to the 137595c635efSGarrett D'Amore * head of the list. Since all entries are guaranteed to be unique 137695c635efSGarrett D'Amore * copy all sections to new node. 137795c635efSGarrett D'Amore */ 137895c635efSGarrett D'Amore if (curdnp == NULL) { 137995c635efSGarrett D'Amore if ((curdnp = calloc(1, sizeof (struct dupnode))) == NULL) 138095c635efSGarrett D'Amore err(1, "calloc"); 138195c635efSGarrett D'Amore for (i = 0; mnp->secv[i] != NULL; i++) { 138295c635efSGarrett D'Amore if ((cursnp = calloc(1, sizeof (struct secnode))) 138395c635efSGarrett D'Amore == NULL) 138495c635efSGarrett D'Amore err(1, "calloc"); 138595c635efSGarrett D'Amore cursnp->next = curdnp->secl; 138695c635efSGarrett D'Amore curdnp->secl = cursnp; 138795c635efSGarrett D'Amore if ((cursnp->secp = strdup(mnp->secv[i])) == NULL) 138895c635efSGarrett D'Amore err(1, "strdup"); 138995c635efSGarrett D'Amore } 139095c635efSGarrett D'Amore curdnp->dev = sb.st_dev; 139195c635efSGarrett D'Amore curdnp->ino = sb.st_ino; 139295c635efSGarrett D'Amore curdnp->next = *dnp; 139395c635efSGarrett D'Amore *dnp = curdnp; 139495c635efSGarrett D'Amore return (0); 139595c635efSGarrett D'Amore } 139695c635efSGarrett D'Amore 139795c635efSGarrett D'Amore /* 139895c635efSGarrett D'Amore * Traverse the section vector in the man_node and the section list 139995c635efSGarrett D'Amore * in dupnode cache to eliminate all duplicates from man_node. 140095c635efSGarrett D'Amore */ 140195c635efSGarrett D'Amore for (i = 0; mnp->secv[i] != NULL; i++) { 140295c635efSGarrett D'Amore dupfound = 0; 140395c635efSGarrett D'Amore for (cursnp = curdnp->secl; cursnp != NULL; 140495c635efSGarrett D'Amore cursnp = cursnp->next) { 140595c635efSGarrett D'Amore if (strcmp(mnp->secv[i], cursnp->secp) == 0) { 140695c635efSGarrett D'Amore dupfound = 1; 140795c635efSGarrett D'Amore break; 140895c635efSGarrett D'Amore } 140995c635efSGarrett D'Amore } 141095c635efSGarrett D'Amore if (dupfound) { 141195c635efSGarrett D'Amore mnp->secv[i][0] = '\0'; 141295c635efSGarrett D'Amore continue; 141395c635efSGarrett D'Amore } 141495c635efSGarrett D'Amore 141595c635efSGarrett D'Amore 141695c635efSGarrett D'Amore /* 141795c635efSGarrett D'Amore * Update curdnp and set return value to indicate that this 141895c635efSGarrett D'Amore * was not all duplicates. 141995c635efSGarrett D'Amore */ 142095c635efSGarrett D'Amore if ((cursnp = calloc(1, sizeof (struct secnode))) == NULL) 142195c635efSGarrett D'Amore err(1, "calloc"); 142295c635efSGarrett D'Amore cursnp->next = curdnp->secl; 142395c635efSGarrett D'Amore curdnp->secl = cursnp; 142495c635efSGarrett D'Amore if ((cursnp->secp = strdup(mnp->secv[i])) == NULL) 142595c635efSGarrett D'Amore err(1, "strdup"); 142695c635efSGarrett D'Amore rv = 0; 142795c635efSGarrett D'Amore } 142895c635efSGarrett D'Amore 142995c635efSGarrett D'Amore return (rv); 143095c635efSGarrett D'Amore } 143195c635efSGarrett D'Amore 143295c635efSGarrett D'Amore /* 143395c635efSGarrett D'Amore * Given a bindir, return corresponding mandir. 143495c635efSGarrett D'Amore */ 143595c635efSGarrett D'Amore static char * 143695c635efSGarrett D'Amore path_to_manpath(char *bindir) 143795c635efSGarrett D'Amore { 143895c635efSGarrett D'Amore char *mand, *p; 143995c635efSGarrett D'Amore int i; 144095c635efSGarrett D'Amore struct stat sb; 144195c635efSGarrett D'Amore 144295c635efSGarrett D'Amore /* First look for known translations for specific bin paths */ 144395c635efSGarrett D'Amore if (stat(bindir, &sb) != 0) { 144495c635efSGarrett D'Amore return (NULL); 144595c635efSGarrett D'Amore } 144695c635efSGarrett D'Amore for (i = 0; bintoman[i].bindir != NULL; i++) { 144795c635efSGarrett D'Amore if (sb.st_dev == bintoman[i].dev && 144895c635efSGarrett D'Amore sb.st_ino == bintoman[i].ino) { 144995c635efSGarrett D'Amore if ((mand = strdup(bintoman[i].mandir)) == NULL) 145095c635efSGarrett D'Amore err(1, "strdup"); 145195c635efSGarrett D'Amore if ((p = strchr(mand, ',')) != NULL) 145295c635efSGarrett D'Amore *p = '\0'; 145395c635efSGarrett D'Amore if (stat(mand, &sb) != 0) { 145495c635efSGarrett D'Amore free(mand); 145595c635efSGarrett D'Amore return (NULL); 145695c635efSGarrett D'Amore } 145795c635efSGarrett D'Amore if (p != NULL) 145895c635efSGarrett D'Amore *p = ','; 145995c635efSGarrett D'Amore return (mand); 146095c635efSGarrett D'Amore } 146195c635efSGarrett D'Amore } 146295c635efSGarrett D'Amore 146395c635efSGarrett D'Amore /* 146495c635efSGarrett D'Amore * No specific translation found. Try `dirname $bindir`/share/man 146595c635efSGarrett D'Amore * and `dirname $bindir`/man 146695c635efSGarrett D'Amore */ 146795c635efSGarrett D'Amore if ((mand = malloc(MAXPATHLEN)) == NULL) 146895c635efSGarrett D'Amore err(1, "malloc"); 146995c635efSGarrett D'Amore if (strlcpy(mand, bindir, MAXPATHLEN) >= MAXPATHLEN) { 147095c635efSGarrett D'Amore free(mand); 147195c635efSGarrett D'Amore return (NULL); 147295c635efSGarrett D'Amore } 147395c635efSGarrett D'Amore 147495c635efSGarrett D'Amore /* 147595c635efSGarrett D'Amore * Advance to end of buffer, strip trailing /'s then remove last 147695c635efSGarrett D'Amore * directory component. 147795c635efSGarrett D'Amore */ 147895c635efSGarrett D'Amore for (p = mand; *p != '\0'; p++) 147995c635efSGarrett D'Amore ; 148095c635efSGarrett D'Amore for (; p > mand && *p == '/'; p--) 148195c635efSGarrett D'Amore ; 148295c635efSGarrett D'Amore for (; p > mand && *p != '/'; p--) 148395c635efSGarrett D'Amore ; 148495c635efSGarrett D'Amore if (p == mand && *p == '.') { 148595c635efSGarrett D'Amore if (realpath("..", mand) == NULL) { 148695c635efSGarrett D'Amore free(mand); 148795c635efSGarrett D'Amore return (NULL); 148895c635efSGarrett D'Amore } 148995c635efSGarrett D'Amore for (; *p != '\0'; p++) 149095c635efSGarrett D'Amore ; 149195c635efSGarrett D'Amore } else { 149295c635efSGarrett D'Amore *p = '\0'; 149395c635efSGarrett D'Amore } 149495c635efSGarrett D'Amore 149595c635efSGarrett D'Amore if (strlcat(mand, "/share/man", MAXPATHLEN) >= MAXPATHLEN) { 149695c635efSGarrett D'Amore free(mand); 149795c635efSGarrett D'Amore return (NULL); 149895c635efSGarrett D'Amore } 149995c635efSGarrett D'Amore 150095c635efSGarrett D'Amore if ((stat(mand, &sb) == 0) && S_ISDIR(sb.st_mode)) { 150195c635efSGarrett D'Amore return (mand); 150295c635efSGarrett D'Amore } 150395c635efSGarrett D'Amore 150495c635efSGarrett D'Amore /* 150595c635efSGarrett D'Amore * Strip the /share/man off and try /man 150695c635efSGarrett D'Amore */ 150795c635efSGarrett D'Amore *p = '\0'; 150895c635efSGarrett D'Amore if (strlcat(mand, "/man", MAXPATHLEN) >= MAXPATHLEN) { 150995c635efSGarrett D'Amore free(mand); 151095c635efSGarrett D'Amore return (NULL); 151195c635efSGarrett D'Amore } 151295c635efSGarrett D'Amore if ((stat(mand, &sb) == 0) && S_ISDIR(sb.st_mode)) { 151395c635efSGarrett D'Amore return (mand); 151495c635efSGarrett D'Amore } 151595c635efSGarrett D'Amore 151695c635efSGarrett D'Amore /* 151795c635efSGarrett D'Amore * No man or share/man directory found 151895c635efSGarrett D'Amore */ 151995c635efSGarrett D'Amore free(mand); 152095c635efSGarrett D'Amore return (NULL); 152195c635efSGarrett D'Amore } 152295c635efSGarrett D'Amore 152395c635efSGarrett D'Amore /* 152495c635efSGarrett D'Amore * Free a linked list of dupnode structs. 152595c635efSGarrett D'Amore */ 152695c635efSGarrett D'Amore void 1527*d456640dSYuri Pankov free_dupnode(struct dupnode *dnp) 1528*d456640dSYuri Pankov { 152995c635efSGarrett D'Amore struct dupnode *dnp2; 153095c635efSGarrett D'Amore struct secnode *snp; 153195c635efSGarrett D'Amore 153295c635efSGarrett D'Amore while (dnp != NULL) { 153395c635efSGarrett D'Amore dnp2 = dnp; 153495c635efSGarrett D'Amore dnp = dnp->next; 153595c635efSGarrett D'Amore while (dnp2->secl != NULL) { 153695c635efSGarrett D'Amore snp = dnp2->secl; 153795c635efSGarrett D'Amore dnp2->secl = dnp2->secl->next; 153895c635efSGarrett D'Amore free(snp->secp); 153995c635efSGarrett D'Amore free(snp); 154095c635efSGarrett D'Amore } 154195c635efSGarrett D'Amore free(dnp2); 154295c635efSGarrett D'Amore } 154395c635efSGarrett D'Amore } 154495c635efSGarrett D'Amore 154595c635efSGarrett D'Amore /* 154695c635efSGarrett D'Amore * Print manp linked list to stdout. 154795c635efSGarrett D'Amore */ 154895c635efSGarrett D'Amore void 154995c635efSGarrett D'Amore print_manpath(struct man_node *manp) 155095c635efSGarrett D'Amore { 155195c635efSGarrett D'Amore char colon[2] = "\0\0"; 155295c635efSGarrett D'Amore char **secp; 155395c635efSGarrett D'Amore 155495c635efSGarrett D'Amore for (; manp != NULL; manp = manp->next) { 155595c635efSGarrett D'Amore (void) printf("%s%s", colon, manp->path); 155695c635efSGarrett D'Amore colon[0] = ':'; 155795c635efSGarrett D'Amore 155895c635efSGarrett D'Amore /* 155995c635efSGarrett D'Amore * If man.cf or a directory scan was used to create section 156095c635efSGarrett D'Amore * list, do not print section list again. If the output of 156195c635efSGarrett D'Amore * man -p is used to set MANPATH, subsequent runs of man 156295c635efSGarrett D'Amore * will re-read man.cf and/or scan man directories as 156395c635efSGarrett D'Amore * required. 156495c635efSGarrett D'Amore */ 156595c635efSGarrett D'Amore if (manp->defsrch != 0) 156695c635efSGarrett D'Amore continue; 156795c635efSGarrett D'Amore 156895c635efSGarrett D'Amore for (secp = manp->secv; *secp != NULL; secp++) { 156995c635efSGarrett D'Amore /* 157095c635efSGarrett D'Amore * Section deduplication may have eliminated some 157195c635efSGarrett D'Amore * sections from the vector. Avoid displaying this 157295c635efSGarrett D'Amore * detail which would appear as ",," in output 157395c635efSGarrett D'Amore */ 157495c635efSGarrett D'Amore if ((*secp)[0] != '\0') 157595c635efSGarrett D'Amore (void) printf(",%s", *secp); 157695c635efSGarrett D'Amore } 157795c635efSGarrett D'Amore } 157895c635efSGarrett D'Amore (void) printf("\n"); 157995c635efSGarrett D'Amore } 158095c635efSGarrett D'Amore 158195c635efSGarrett D'Amore static void 158295c635efSGarrett D'Amore usage_man(void) 158395c635efSGarrett D'Amore { 158495c635efSGarrett D'Amore 158595c635efSGarrett D'Amore (void) fprintf(stderr, gettext( 158695c635efSGarrett D'Amore "usage: man [-alptw] [-M path] [-s section] name ...\n" 158795c635efSGarrett D'Amore " man [-M path] [-s section] -k keyword ...\n" 158895c635efSGarrett D'Amore " man [-M path] [-s section] -f keyword ...\n")); 158995c635efSGarrett D'Amore 159095c635efSGarrett D'Amore exit(1); 159195c635efSGarrett D'Amore } 159295c635efSGarrett D'Amore 159395c635efSGarrett D'Amore static void 159495c635efSGarrett D'Amore usage_whatapro(void) 159595c635efSGarrett D'Amore { 159695c635efSGarrett D'Amore 159795c635efSGarrett D'Amore (void) fprintf(stderr, gettext( 159895c635efSGarrett D'Amore "usage: %s [-M path] [-s section] keyword ...\n"), 159995c635efSGarrett D'Amore whatis ? "whatis" : "apropos"); 160095c635efSGarrett D'Amore 160195c635efSGarrett D'Amore exit(1); 160295c635efSGarrett D'Amore } 160395c635efSGarrett D'Amore 160495c635efSGarrett D'Amore static void 160595c635efSGarrett D'Amore usage_catman(void) 160695c635efSGarrett D'Amore { 160795c635efSGarrett D'Amore (void) fprintf(stderr, gettext( 160895c635efSGarrett D'Amore "usage: catman [-M path] [-w]\n")); 160995c635efSGarrett D'Amore 161095c635efSGarrett D'Amore exit(1); 161195c635efSGarrett D'Amore } 161295c635efSGarrett D'Amore 161395c635efSGarrett D'Amore static void 161495c635efSGarrett D'Amore usage_makewhatis(void) 161595c635efSGarrett D'Amore { 161695c635efSGarrett D'Amore (void) fprintf(stderr, gettext("usage: makewhatis\n")); 161795c635efSGarrett D'Amore 161895c635efSGarrett D'Amore exit(1); 161995c635efSGarrett D'Amore } 1620