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*260e9a87SYuri Pankov * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 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) { 53295c635efSGarrett D'Amore manp->secv = split(mansec, ','); 53395c635efSGarrett D'Amore for (sectp = manp->secv; *sectp; sectp++) 53495c635efSGarrett D'Amore lower(*sectp); 53595c635efSGarrett D'Amore } else if ((sections = strchr(*pv, ',')) != NULL) { 53695c635efSGarrett D'Amore DPRINTF("-- Adding %s: MANSECTS=%s\n", manp->path, sections); 53795c635efSGarrett D'Amore manp->secv = split(++sections, ','); 53895c635efSGarrett D'Amore for (sectp = manp->secv; *sectp; sectp++) 53995c635efSGarrett D'Amore lower(*sectp); 54095c635efSGarrett D'Amore if (*manp->secv == NULL) 54195c635efSGarrett D'Amore get_all_sect(manp); 54295c635efSGarrett D'Amore } else if ((sections = check_config(*pv)) != NULL) { 54395c635efSGarrett D'Amore manp->defsrch = 1; 54495c635efSGarrett D'Amore DPRINTF("-- Adding %s: from %s, MANSECTS=%s\n", manp->path, 54595c635efSGarrett D'Amore CONFIG, sections); 54695c635efSGarrett D'Amore manp->secv = split(sections, ','); 54795c635efSGarrett D'Amore for (sectp = manp->secv; *sectp; sectp++) 54895c635efSGarrett D'Amore lower(*sectp); 54995c635efSGarrett D'Amore if (*manp->secv == NULL) 55095c635efSGarrett D'Amore get_all_sect(manp); 55195c635efSGarrett D'Amore } else { 55295c635efSGarrett D'Amore manp->defsrch = 1; 55395c635efSGarrett D'Amore DPRINTF("-- Adding %s: default sort order\n", manp->path); 55495c635efSGarrett D'Amore manp->secv = NULL; 55595c635efSGarrett D'Amore get_all_sect(manp); 55695c635efSGarrett D'Amore } 55795c635efSGarrett D'Amore } 55895c635efSGarrett D'Amore 55995c635efSGarrett D'Amore /* 56095c635efSGarrett D'Amore * Get suffices of all sub-mandir directories in a mandir. 56195c635efSGarrett D'Amore */ 56295c635efSGarrett D'Amore static void 56395c635efSGarrett D'Amore get_all_sect(struct man_node *manp) 56495c635efSGarrett D'Amore { 56595c635efSGarrett D'Amore DIR *dp; 56695c635efSGarrett D'Amore char **dirv; 56795c635efSGarrett D'Amore char **dv; 56895c635efSGarrett D'Amore char **p; 56995c635efSGarrett D'Amore char *prev = NULL; 57095c635efSGarrett D'Amore char *tmp = NULL; 57195c635efSGarrett D'Amore int maxentries = MAXTOKENS; 57295c635efSGarrett D'Amore int entries = 0; 57395c635efSGarrett D'Amore 57495c635efSGarrett D'Amore if ((dp = opendir(manp->path)) == 0) 57595c635efSGarrett D'Amore return; 57695c635efSGarrett D'Amore 57795c635efSGarrett D'Amore sortdir(dp, &dirv); 57895c635efSGarrett D'Amore 57995c635efSGarrett D'Amore (void) closedir(dp); 58095c635efSGarrett D'Amore 58195c635efSGarrett D'Amore if (manp->secv == NULL) { 58295c635efSGarrett D'Amore if ((manp->secv = malloc(maxentries * sizeof (char *))) == NULL) 58395c635efSGarrett D'Amore err(1, "malloc"); 58495c635efSGarrett D'Amore } 58595c635efSGarrett D'Amore 58695c635efSGarrett D'Amore for (dv = dirv, p = manp->secv; *dv; dv++) { 58795c635efSGarrett D'Amore if (strcmp(*dv, CONFIG) == 0) { 58895c635efSGarrett D'Amore free(*dv); 58995c635efSGarrett D'Amore continue; 59095c635efSGarrett D'Amore } 59195c635efSGarrett D'Amore 59295c635efSGarrett D'Amore free(tmp); 59395c635efSGarrett D'Amore if ((tmp = strdup(*dv + 3)) == NULL) 59495c635efSGarrett D'Amore err(1, "strdup"); 59595c635efSGarrett D'Amore 59695c635efSGarrett D'Amore if (prev != NULL && strcmp(prev, tmp) == 0) { 59795c635efSGarrett D'Amore free(*dv); 59895c635efSGarrett D'Amore continue; 59995c635efSGarrett D'Amore } 60095c635efSGarrett D'Amore 60195c635efSGarrett D'Amore free(prev); 60295c635efSGarrett D'Amore if ((prev = strdup(*dv + 3)) == NULL) 60395c635efSGarrett D'Amore err(1, "strdup"); 60495c635efSGarrett D'Amore 60595c635efSGarrett D'Amore if ((*p = strdup(*dv + 3)) == NULL) 60695c635efSGarrett D'Amore err(1, "strdup"); 60795c635efSGarrett D'Amore 60895c635efSGarrett D'Amore p++; entries++; 60995c635efSGarrett D'Amore 61095c635efSGarrett D'Amore if (entries == maxentries) { 61195c635efSGarrett D'Amore maxentries += MAXTOKENS; 61295c635efSGarrett D'Amore if ((manp->secv = realloc(manp->secv, 61395c635efSGarrett D'Amore sizeof (char *) * maxentries)) == NULL) 61495c635efSGarrett D'Amore err(1, "realloc"); 61595c635efSGarrett D'Amore p = manp->secv + entries; 61695c635efSGarrett D'Amore } 61795c635efSGarrett D'Amore free(*dv); 61895c635efSGarrett D'Amore } 61995c635efSGarrett D'Amore free(tmp); 62095c635efSGarrett D'Amore free(prev); 62195c635efSGarrett D'Amore *p = NULL; 62295c635efSGarrett D'Amore free(dirv); 62395c635efSGarrett D'Amore } 62495c635efSGarrett D'Amore 62595c635efSGarrett D'Amore /* 62695c635efSGarrett D'Amore * Build whatis databases. 62795c635efSGarrett D'Amore */ 62895c635efSGarrett D'Amore static void 62995c635efSGarrett D'Amore do_makewhatis(struct man_node *manp) 63095c635efSGarrett D'Amore { 63195c635efSGarrett D'Amore struct man_node *p; 63295c635efSGarrett D'Amore char *ldir; 63395c635efSGarrett D'Amore 63495c635efSGarrett D'Amore for (p = manp; p != NULL; p = p->next) { 63595c635efSGarrett D'Amore ldir = addlocale(p->path); 63695c635efSGarrett D'Amore if (*localedir != '\0' && getdirs(ldir, NULL, 0) > 0) 63795c635efSGarrett D'Amore mwpath(ldir); 63895c635efSGarrett D'Amore free(ldir); 63995c635efSGarrett D'Amore mwpath(p->path); 64095c635efSGarrett D'Amore } 64195c635efSGarrett D'Amore } 64295c635efSGarrett D'Amore 64395c635efSGarrett D'Amore /* 64495c635efSGarrett D'Amore * Count mandirs under the given manpath 64595c635efSGarrett D'Amore */ 64695c635efSGarrett D'Amore static int 64795c635efSGarrett D'Amore getdirs(char *path, char ***dirv, int flag) 64895c635efSGarrett D'Amore { 64995c635efSGarrett D'Amore DIR *dp; 65095c635efSGarrett D'Amore struct dirent *d; 65195c635efSGarrett D'Amore int n = 0; 65295c635efSGarrett D'Amore int maxentries = MAXDIRS; 65395c635efSGarrett D'Amore char **dv = NULL; 65495c635efSGarrett D'Amore 65595c635efSGarrett D'Amore if ((dp = opendir(path)) == NULL) 65695c635efSGarrett D'Amore return (0); 65795c635efSGarrett D'Amore 65895c635efSGarrett D'Amore if (flag) { 65995c635efSGarrett D'Amore if ((*dirv = malloc(sizeof (char *) * 66095c635efSGarrett D'Amore maxentries)) == NULL) 66195c635efSGarrett D'Amore err(1, "malloc"); 66295c635efSGarrett D'Amore dv = *dirv; 66395c635efSGarrett D'Amore } 66495c635efSGarrett D'Amore while ((d = readdir(dp))) { 66595c635efSGarrett D'Amore if (strncmp(d->d_name, "man", 3) != 0) 66695c635efSGarrett D'Amore continue; 66795c635efSGarrett D'Amore n++; 66895c635efSGarrett D'Amore 66995c635efSGarrett D'Amore if (flag) { 67095c635efSGarrett D'Amore if ((*dv = strdup(d->d_name + 3)) == NULL) 67195c635efSGarrett D'Amore err(1, "strdup"); 67295c635efSGarrett D'Amore dv++; 67395c635efSGarrett D'Amore if ((dv - *dirv) == maxentries) { 67495c635efSGarrett D'Amore int entries = maxentries; 67595c635efSGarrett D'Amore 67695c635efSGarrett D'Amore maxentries += MAXTOKENS; 67795c635efSGarrett D'Amore if ((*dirv = realloc(*dirv, 67895c635efSGarrett D'Amore sizeof (char *) * maxentries)) == NULL) 67995c635efSGarrett D'Amore err(1, "realloc"); 68095c635efSGarrett D'Amore dv = *dirv + entries; 68195c635efSGarrett D'Amore } 68295c635efSGarrett D'Amore } 68395c635efSGarrett D'Amore } 68495c635efSGarrett D'Amore 68595c635efSGarrett D'Amore (void) closedir(dp); 68695c635efSGarrett D'Amore return (n); 68795c635efSGarrett D'Amore } 68895c635efSGarrett D'Amore 68995c635efSGarrett D'Amore 69095c635efSGarrett D'Amore /* 69195c635efSGarrett D'Amore * Find matching whatis or apropos entries. 69295c635efSGarrett D'Amore */ 69395c635efSGarrett D'Amore static void 69495c635efSGarrett D'Amore whatapro(struct man_node *manp, char *word) 69595c635efSGarrett D'Amore { 69695c635efSGarrett D'Amore char whatpath[MAXPATHLEN]; 69795c635efSGarrett D'Amore struct man_node *b; 69895c635efSGarrett D'Amore char *ldir; 69995c635efSGarrett D'Amore 70095c635efSGarrett D'Amore for (b = manp; b != NULL; b = b->next) { 70195c635efSGarrett D'Amore if (*localedir != '\0') { 70295c635efSGarrett D'Amore ldir = addlocale(b->path); 70395c635efSGarrett D'Amore if (getdirs(ldir, NULL, 0) != 0) { 70495c635efSGarrett D'Amore (void) snprintf(whatpath, sizeof (whatpath), 70595c635efSGarrett D'Amore "%s/%s", ldir, WHATIS); 70695c635efSGarrett D'Amore search_whatis(whatpath, word); 70795c635efSGarrett D'Amore } 70895c635efSGarrett D'Amore free(ldir); 70995c635efSGarrett D'Amore } 71095c635efSGarrett D'Amore (void) snprintf(whatpath, sizeof (whatpath), "%s/%s", b->path, 71195c635efSGarrett D'Amore WHATIS); 71295c635efSGarrett D'Amore search_whatis(whatpath, word); 71395c635efSGarrett D'Amore } 71495c635efSGarrett D'Amore } 71595c635efSGarrett D'Amore 71695c635efSGarrett D'Amore static void 71795c635efSGarrett D'Amore search_whatis(char *whatpath, char *word) 71895c635efSGarrett D'Amore { 71995c635efSGarrett D'Amore FILE *fp; 72095c635efSGarrett D'Amore char *line = NULL; 72195c635efSGarrett D'Amore size_t linecap = 0; 72295c635efSGarrett D'Amore char *pkwd; 72395c635efSGarrett D'Amore regex_t preg; 72495c635efSGarrett D'Amore char **ss = NULL; 72595c635efSGarrett D'Amore char s[MAXNAMELEN]; 72695c635efSGarrett D'Amore int i; 72795c635efSGarrett D'Amore 72895c635efSGarrett D'Amore if ((fp = fopen(whatpath, "r")) == NULL) { 72995c635efSGarrett D'Amore perror(whatpath); 73095c635efSGarrett D'Amore return; 73195c635efSGarrett D'Amore } 73295c635efSGarrett D'Amore 73395c635efSGarrett D'Amore DPRINTF("-- Found %s: %s\n", WHATIS, whatpath); 73495c635efSGarrett D'Amore 73595c635efSGarrett D'Amore /* Build keyword regex */ 73695c635efSGarrett D'Amore if (asprintf(&pkwd, "%s%s%s", (whatis) ? "\\<" : "", 73795c635efSGarrett D'Amore word, (whatis) ? "\\>" : "") == -1) 73895c635efSGarrett D'Amore err(1, "asprintf"); 73995c635efSGarrett D'Amore 74095c635efSGarrett D'Amore if (regcomp(&preg, pkwd, REG_BASIC | REG_ICASE | REG_NOSUB) != 0) 74195c635efSGarrett D'Amore err(1, "regcomp"); 74295c635efSGarrett D'Amore 74395c635efSGarrett D'Amore if (sargs) 74495c635efSGarrett D'Amore ss = split(mansec, ','); 74595c635efSGarrett D'Amore 74695c635efSGarrett D'Amore while (getline(&line, &linecap, fp) > 0) { 74795c635efSGarrett D'Amore if (regexec(&preg, line, 0, NULL, 0) == 0) { 74895c635efSGarrett D'Amore if (sargs) { 74995c635efSGarrett D'Amore /* Section-restricted search */ 75095c635efSGarrett D'Amore for (i = 0; ss[i] != NULL; i++) { 75195c635efSGarrett D'Amore (void) snprintf(s, sizeof (s), "(%s)", 75295c635efSGarrett D'Amore ss[i]); 75395c635efSGarrett D'Amore if (strstr(line, s) != NULL) { 75495c635efSGarrett D'Amore (void) printf("%s", line); 75595c635efSGarrett D'Amore break; 75695c635efSGarrett D'Amore } 75795c635efSGarrett D'Amore } 75895c635efSGarrett D'Amore } else { 75995c635efSGarrett D'Amore (void) printf("%s", line); 76095c635efSGarrett D'Amore } 76195c635efSGarrett D'Amore } 76295c635efSGarrett D'Amore } 76395c635efSGarrett D'Amore 76495c635efSGarrett D'Amore if (ss != NULL) 76595c635efSGarrett D'Amore freev(ss); 76695c635efSGarrett D'Amore free(pkwd); 76795c635efSGarrett D'Amore (void) fclose(fp); 76895c635efSGarrett D'Amore } 76995c635efSGarrett D'Amore 77095c635efSGarrett D'Amore 77195c635efSGarrett D'Amore /* 77295c635efSGarrett D'Amore * Split a string by specified separator. 77395c635efSGarrett D'Amore */ 77495c635efSGarrett D'Amore static char ** 77595c635efSGarrett D'Amore split(char *s1, char sep) 77695c635efSGarrett D'Amore { 77795c635efSGarrett D'Amore char **tokv, **vp; 77895c635efSGarrett D'Amore char *mp = s1, *tp; 77995c635efSGarrett D'Amore int maxentries = MAXTOKENS; 78095c635efSGarrett D'Amore int entries = 0; 78195c635efSGarrett D'Amore 78295c635efSGarrett D'Amore if ((tokv = vp = malloc(maxentries * sizeof (char *))) == NULL) 78395c635efSGarrett D'Amore err(1, "malloc"); 78495c635efSGarrett D'Amore 78595c635efSGarrett D'Amore for (; mp && *mp; mp = tp) { 78695c635efSGarrett D'Amore tp = strchr(mp, sep); 78795c635efSGarrett D'Amore if (mp == tp) { 78895c635efSGarrett D'Amore tp++; 78995c635efSGarrett D'Amore continue; 79095c635efSGarrett D'Amore } 79195c635efSGarrett D'Amore if (tp) { 79295c635efSGarrett D'Amore size_t len; 79395c635efSGarrett D'Amore 79495c635efSGarrett D'Amore len = tp - mp; 79595c635efSGarrett D'Amore if ((*vp = (char *)malloc(sizeof (char) * 79695c635efSGarrett D'Amore len + 1)) == NULL) 79795c635efSGarrett D'Amore err(1, "malloc"); 79895c635efSGarrett D'Amore (void) strncpy(*vp, mp, len); 79995c635efSGarrett D'Amore *(*vp + len) = '\0'; 80095c635efSGarrett D'Amore tp++; 80195c635efSGarrett D'Amore vp++; 80295c635efSGarrett D'Amore } else { 80395c635efSGarrett D'Amore if ((*vp = strdup(mp)) == NULL) 80495c635efSGarrett D'Amore err(1, "strdup"); 80595c635efSGarrett D'Amore vp++; 80695c635efSGarrett D'Amore } 80795c635efSGarrett D'Amore entries++; 80895c635efSGarrett D'Amore if (entries == maxentries) { 80995c635efSGarrett D'Amore maxentries += MAXTOKENS; 81095c635efSGarrett D'Amore if ((tokv = realloc(tokv, 81195c635efSGarrett D'Amore maxentries * sizeof (char *))) == NULL) 81295c635efSGarrett D'Amore err(1, "realloc"); 81395c635efSGarrett D'Amore vp = tokv + entries; 81495c635efSGarrett D'Amore } 81595c635efSGarrett D'Amore } 81695c635efSGarrett D'Amore *vp = 0; 81795c635efSGarrett D'Amore 81895c635efSGarrett D'Amore return (tokv); 81995c635efSGarrett D'Amore } 82095c635efSGarrett D'Amore 82195c635efSGarrett D'Amore /* 82295c635efSGarrett D'Amore * Free a vector allocated by split() 82395c635efSGarrett D'Amore */ 82495c635efSGarrett D'Amore static void 82595c635efSGarrett D'Amore freev(char **v) 82695c635efSGarrett D'Amore { 82795c635efSGarrett D'Amore int i; 82895c635efSGarrett D'Amore if (v != NULL) { 82995c635efSGarrett D'Amore for (i = 0; v[i] != NULL; i++) { 83095c635efSGarrett D'Amore free(v[i]); 83195c635efSGarrett D'Amore } 83295c635efSGarrett D'Amore free(v); 83395c635efSGarrett D'Amore } 83495c635efSGarrett D'Amore } 83595c635efSGarrett D'Amore 83695c635efSGarrett D'Amore /* 83795c635efSGarrett D'Amore * Convert paths to full paths if necessary 83895c635efSGarrett D'Amore */ 83995c635efSGarrett D'Amore static void 84095c635efSGarrett D'Amore fullpaths(struct man_node **manp_head) 84195c635efSGarrett D'Amore { 84295c635efSGarrett D'Amore char *cwd = NULL; 84395c635efSGarrett D'Amore char *p; 84495c635efSGarrett D'Amore int cwd_gotten = 0; 84595c635efSGarrett D'Amore struct man_node *manp = *manp_head; 84695c635efSGarrett D'Amore struct man_node *b; 84795c635efSGarrett D'Amore struct man_node *prev = NULL; 84895c635efSGarrett D'Amore 84995c635efSGarrett D'Amore for (b = manp; b != NULL; b = b->next) { 85095c635efSGarrett D'Amore if (*(b->path) == '/') { 85195c635efSGarrett D'Amore prev = b; 85295c635efSGarrett D'Amore continue; 85395c635efSGarrett D'Amore } 85495c635efSGarrett D'Amore 85595c635efSGarrett D'Amore if (!cwd_gotten) { 85695c635efSGarrett D'Amore cwd = getcwd(NULL, MAXPATHLEN); 85795c635efSGarrett D'Amore cwd_gotten = 1; 85895c635efSGarrett D'Amore } 85995c635efSGarrett D'Amore 86095c635efSGarrett D'Amore if (cwd) { 86195c635efSGarrett D'Amore /* Relative manpath with cwd: make absolute */ 86295c635efSGarrett D'Amore if (asprintf(&p, "%s/%s", cwd, b->path) == -1) 86395c635efSGarrett D'Amore err(1, "asprintf"); 86495c635efSGarrett D'Amore free(b->path); 86595c635efSGarrett D'Amore b->path = p; 86695c635efSGarrett D'Amore } else { 86795c635efSGarrett D'Amore /* Relative manpath but no cwd: omit path entry */ 86895c635efSGarrett D'Amore if (prev) 86995c635efSGarrett D'Amore prev->next = b->next; 87095c635efSGarrett D'Amore else 87195c635efSGarrett D'Amore *manp_head = b->next; 87295c635efSGarrett D'Amore 87395c635efSGarrett D'Amore free_manp(b); 87495c635efSGarrett D'Amore } 87595c635efSGarrett D'Amore } 87695c635efSGarrett D'Amore free(cwd); 87795c635efSGarrett D'Amore } 87895c635efSGarrett D'Amore 87995c635efSGarrett D'Amore /* 88095c635efSGarrett D'Amore * Free a man_node structure and its contents 88195c635efSGarrett D'Amore */ 88295c635efSGarrett D'Amore static void 88395c635efSGarrett D'Amore free_manp(struct man_node *manp) 88495c635efSGarrett D'Amore { 88595c635efSGarrett D'Amore char **p; 88695c635efSGarrett D'Amore 88795c635efSGarrett D'Amore free(manp->path); 88895c635efSGarrett D'Amore p = manp->secv; 88995c635efSGarrett D'Amore while ((p != NULL) && (*p != NULL)) { 89095c635efSGarrett D'Amore free(*p); 89195c635efSGarrett D'Amore p++; 89295c635efSGarrett D'Amore } 89395c635efSGarrett D'Amore free(manp->secv); 89495c635efSGarrett D'Amore free(manp); 89595c635efSGarrett D'Amore } 89695c635efSGarrett D'Amore 89795c635efSGarrett D'Amore 89895c635efSGarrett D'Amore /* 89995c635efSGarrett D'Amore * Map (in place) to lower case. 90095c635efSGarrett D'Amore */ 90195c635efSGarrett D'Amore static void 90295c635efSGarrett D'Amore lower(char *s) 90395c635efSGarrett D'Amore { 90495c635efSGarrett D'Amore 90595c635efSGarrett D'Amore if (s == 0) 90695c635efSGarrett D'Amore return; 90795c635efSGarrett D'Amore while (*s) { 90895c635efSGarrett D'Amore if (isupper(*s)) 90995c635efSGarrett D'Amore *s = tolower(*s); 91095c635efSGarrett D'Amore s++; 91195c635efSGarrett D'Amore } 91295c635efSGarrett D'Amore } 91395c635efSGarrett D'Amore 91495c635efSGarrett D'Amore 91595c635efSGarrett D'Amore /* 91695c635efSGarrett D'Amore * Compare function for qsort(). 91795c635efSGarrett D'Amore * Sort first by section, then by prefix. 91895c635efSGarrett D'Amore */ 91995c635efSGarrett D'Amore static int 92095c635efSGarrett D'Amore cmp(const void *arg1, const void *arg2) 92195c635efSGarrett D'Amore { 92295c635efSGarrett D'Amore int n; 92395c635efSGarrett D'Amore char **p1 = (char **)arg1; 92495c635efSGarrett D'Amore char **p2 = (char **)arg2; 92595c635efSGarrett D'Amore 92695c635efSGarrett D'Amore /* By section */ 92795c635efSGarrett D'Amore if ((n = strcmp(*p1 + 3, *p2 + 3)) != 0) 92895c635efSGarrett D'Amore return (n); 92995c635efSGarrett D'Amore 93095c635efSGarrett D'Amore /* By prefix reversed */ 93195c635efSGarrett D'Amore return (strncmp(*p2, *p1, 3)); 93295c635efSGarrett D'Amore } 93395c635efSGarrett D'Amore 93495c635efSGarrett D'Amore 93595c635efSGarrett D'Amore /* 93695c635efSGarrett D'Amore * Find a manpage. 93795c635efSGarrett D'Amore */ 93895c635efSGarrett D'Amore static int 93995c635efSGarrett D'Amore manual(struct man_node *manp, char *name) 94095c635efSGarrett D'Amore { 94195c635efSGarrett D'Amore struct man_node *p; 94295c635efSGarrett D'Amore struct man_node *local; 94395c635efSGarrett D'Amore int ndirs = 0; 94495c635efSGarrett D'Amore char *ldir; 94595c635efSGarrett D'Amore char *ldirs[2]; 94695c635efSGarrett D'Amore char *fullname = name; 94795c635efSGarrett D'Amore char *slash; 94895c635efSGarrett D'Amore 94995c635efSGarrett D'Amore if ((slash = strrchr(name, '/')) != NULL) 95095c635efSGarrett D'Amore name = slash + 1; 95195c635efSGarrett D'Amore 95295c635efSGarrett D'Amore /* For each path in MANPATH */ 95395c635efSGarrett D'Amore found = 0; 95495c635efSGarrett D'Amore 95595c635efSGarrett D'Amore for (p = manp; p != NULL; p = p->next) { 95695c635efSGarrett D'Amore DPRINTF("-- Searching mandir: %s\n", p->path); 95795c635efSGarrett D'Amore 95895c635efSGarrett D'Amore if (*localedir != '\0') { 95995c635efSGarrett D'Amore ldir = addlocale(p->path); 96095c635efSGarrett D'Amore ndirs = getdirs(ldir, NULL, 0); 96195c635efSGarrett D'Amore if (ndirs != 0) { 96295c635efSGarrett D'Amore ldirs[0] = ldir; 96395c635efSGarrett D'Amore ldirs[1] = NULL; 96495c635efSGarrett D'Amore local = build_manpath(ldirs, 0); 96595c635efSGarrett D'Amore DPRINTF("-- Locale specific subdir: %s\n", 96695c635efSGarrett D'Amore ldir); 96795c635efSGarrett D'Amore mandir(local->secv, ldir, name, 1); 96895c635efSGarrett D'Amore free_manp(local); 96995c635efSGarrett D'Amore } 97095c635efSGarrett D'Amore free(ldir); 97195c635efSGarrett D'Amore } 97295c635efSGarrett D'Amore 97395c635efSGarrett D'Amore /* 97495c635efSGarrett D'Amore * Locale mandir not valid, man page in locale 97595c635efSGarrett D'Amore * mandir not found, or -a option present 97695c635efSGarrett D'Amore */ 97795c635efSGarrett D'Amore if (ndirs == 0 || !found || all) 97895c635efSGarrett D'Amore mandir(p->secv, p->path, name, 0); 97995c635efSGarrett D'Amore 98095c635efSGarrett D'Amore if (found && !all) 98195c635efSGarrett D'Amore break; 98295c635efSGarrett D'Amore } 98395c635efSGarrett D'Amore 98495c635efSGarrett D'Amore if (!found) { 98595c635efSGarrett D'Amore if (sargs) { 98695c635efSGarrett D'Amore (void) fprintf(stderr, gettext( 98795c635efSGarrett D'Amore "No manual entry for %s in section(s) %s\n"), 98895c635efSGarrett D'Amore fullname, mansec); 98995c635efSGarrett D'Amore } else { 99095c635efSGarrett D'Amore (void) fprintf(stderr, 99195c635efSGarrett D'Amore gettext("No manual entry for %s\n"), fullname); 99295c635efSGarrett D'Amore } 99395c635efSGarrett D'Amore 99495c635efSGarrett D'Amore } 99595c635efSGarrett D'Amore 99695c635efSGarrett D'Amore return (!found); 99795c635efSGarrett D'Amore } 99895c635efSGarrett D'Amore 99995c635efSGarrett D'Amore 100095c635efSGarrett D'Amore /* 100195c635efSGarrett D'Amore * For a specified manual directory, read, store and sort section subdirs. 100295c635efSGarrett D'Amore * For each section specified, find and search matching subdirs. 100395c635efSGarrett D'Amore */ 100495c635efSGarrett D'Amore static void 100595c635efSGarrett D'Amore mandir(char **secv, char *path, char *name, int lspec) 100695c635efSGarrett D'Amore { 100795c635efSGarrett D'Amore DIR *dp; 100895c635efSGarrett D'Amore char **dirv; 100995c635efSGarrett D'Amore char **dv, **pdv; 101095c635efSGarrett D'Amore int len, dslen; 101195c635efSGarrett D'Amore 101295c635efSGarrett D'Amore if ((dp = opendir(path)) == NULL) 101395c635efSGarrett D'Amore return; 101495c635efSGarrett D'Amore 101595c635efSGarrett D'Amore if (lspec) 101695c635efSGarrett D'Amore DPRINTF("-- Searching mandir: %s\n", path); 101795c635efSGarrett D'Amore 101895c635efSGarrett D'Amore sortdir(dp, &dirv); 101995c635efSGarrett D'Amore 102095c635efSGarrett D'Amore /* Search in the order specified by MANSECTS */ 102195c635efSGarrett D'Amore for (; *secv; secv++) { 102295c635efSGarrett D'Amore len = strlen(*secv); 102395c635efSGarrett D'Amore for (dv = dirv; *dv; dv++) { 102495c635efSGarrett D'Amore dslen = strlen(*dv + 3); 102595c635efSGarrett D'Amore if (dslen > len) 102695c635efSGarrett D'Amore len = dslen; 102795c635efSGarrett D'Amore if (**secv == '\\') { 102895c635efSGarrett D'Amore if (strcmp(*secv + 1, *dv + 3) != 0) 102995c635efSGarrett D'Amore continue; 103095c635efSGarrett D'Amore } else if (strncasecmp(*secv, *dv + 3, len) != 0) { 103195c635efSGarrett D'Amore if (!all && 103295c635efSGarrett D'Amore (newsection = map_section(*secv, path)) 103395c635efSGarrett D'Amore == NULL) { 103495c635efSGarrett D'Amore continue; 103595c635efSGarrett D'Amore } 103695c635efSGarrett D'Amore if (newsection == NULL) 103795c635efSGarrett D'Amore newsection = ""; 103895c635efSGarrett D'Amore if (strncmp(newsection, *dv + 3, len) != 0) { 103995c635efSGarrett D'Amore continue; 104095c635efSGarrett D'Amore } 104195c635efSGarrett D'Amore } 104295c635efSGarrett D'Amore 104395c635efSGarrett D'Amore if (searchdir(path, *dv, name) == 0) 104495c635efSGarrett D'Amore continue; 104595c635efSGarrett D'Amore 104695c635efSGarrett D'Amore if (!all) { 104795c635efSGarrett D'Amore pdv = dirv; 104895c635efSGarrett D'Amore while (*pdv) { 104995c635efSGarrett D'Amore free(*pdv); 105095c635efSGarrett D'Amore pdv++; 105195c635efSGarrett D'Amore } 105295c635efSGarrett D'Amore (void) closedir(dp); 105395c635efSGarrett D'Amore free(dirv); 105495c635efSGarrett D'Amore return; 105595c635efSGarrett D'Amore } 105695c635efSGarrett D'Amore 105795c635efSGarrett D'Amore if (all && **dv == 'm' && *(dv + 1) && 105895c635efSGarrett D'Amore strcmp(*(dv + 1) + 3, *dv + 3) == 0) 105995c635efSGarrett D'Amore dv++; 106095c635efSGarrett D'Amore } 106195c635efSGarrett D'Amore } 106295c635efSGarrett D'Amore pdv = dirv; 106395c635efSGarrett D'Amore while (*pdv != NULL) { 106495c635efSGarrett D'Amore free(*pdv); 106595c635efSGarrett D'Amore pdv++; 106695c635efSGarrett D'Amore } 106795c635efSGarrett D'Amore free(dirv); 106895c635efSGarrett D'Amore (void) closedir(dp); 106995c635efSGarrett D'Amore } 107095c635efSGarrett D'Amore 107195c635efSGarrett D'Amore /* 107295c635efSGarrett D'Amore * Sort directories. 107395c635efSGarrett D'Amore */ 107495c635efSGarrett D'Amore static void 107595c635efSGarrett D'Amore sortdir(DIR *dp, char ***dirv) 107695c635efSGarrett D'Amore { 107795c635efSGarrett D'Amore struct dirent *d; 107895c635efSGarrett D'Amore char **dv; 107995c635efSGarrett D'Amore int maxentries = MAXDIRS; 108095c635efSGarrett D'Amore int entries = 0; 108195c635efSGarrett D'Amore 108295c635efSGarrett D'Amore if ((dv = *dirv = malloc(sizeof (char *) * 108395c635efSGarrett D'Amore maxentries)) == NULL) 108495c635efSGarrett D'Amore err(1, "malloc"); 108595c635efSGarrett D'Amore dv = *dirv; 108695c635efSGarrett D'Amore 108795c635efSGarrett D'Amore while ((d = readdir(dp))) { 108895c635efSGarrett D'Amore if (strcmp(d->d_name, ".") == 0 || 108995c635efSGarrett D'Amore strcmp(d->d_name, "..") == 0) 109095c635efSGarrett D'Amore continue; 109195c635efSGarrett D'Amore 109295c635efSGarrett D'Amore if (strncmp(d->d_name, "man", 3) == 0 || 109395c635efSGarrett D'Amore strncmp(d->d_name, "cat", 3) == 0) { 109495c635efSGarrett D'Amore if ((*dv = strdup(d->d_name)) == NULL) 109595c635efSGarrett D'Amore err(1, "strdup"); 109695c635efSGarrett D'Amore dv++; 109795c635efSGarrett D'Amore entries++; 109895c635efSGarrett D'Amore if (entries == maxentries) { 109995c635efSGarrett D'Amore maxentries += MAXDIRS; 110095c635efSGarrett D'Amore if ((*dirv = realloc(*dirv, 110195c635efSGarrett D'Amore sizeof (char *) * maxentries)) == NULL) 110295c635efSGarrett D'Amore err(1, "realloc"); 110395c635efSGarrett D'Amore dv = *dirv + entries; 110495c635efSGarrett D'Amore } 110595c635efSGarrett D'Amore } 110695c635efSGarrett D'Amore } 110795c635efSGarrett D'Amore *dv = 0; 110895c635efSGarrett D'Amore 110995c635efSGarrett D'Amore qsort((void *)*dirv, dv - *dirv, sizeof (char *), cmp); 111095c635efSGarrett D'Amore 111195c635efSGarrett D'Amore } 111295c635efSGarrett D'Amore 111395c635efSGarrett D'Amore 111495c635efSGarrett D'Amore /* 111595c635efSGarrett D'Amore * Search a section subdir for a given manpage. 111695c635efSGarrett D'Amore */ 111795c635efSGarrett D'Amore static int 111895c635efSGarrett D'Amore searchdir(char *path, char *dir, char *name) 111995c635efSGarrett D'Amore { 112095c635efSGarrett D'Amore DIR *sdp; 112195c635efSGarrett D'Amore struct dirent *sd; 112295c635efSGarrett D'Amore char sectpath[MAXPATHLEN]; 112395c635efSGarrett D'Amore char file[MAXNAMLEN]; 112495c635efSGarrett D'Amore char dname[MAXPATHLEN]; 112595c635efSGarrett D'Amore char *last; 112695c635efSGarrett D'Amore int nlen; 112795c635efSGarrett D'Amore 112895c635efSGarrett D'Amore (void) snprintf(sectpath, sizeof (sectpath), "%s/%s", path, dir); 112995c635efSGarrett D'Amore (void) snprintf(file, sizeof (file), "%s.", name); 113095c635efSGarrett D'Amore 113195c635efSGarrett D'Amore if ((sdp = opendir(sectpath)) == NULL) 113295c635efSGarrett D'Amore return (0); 113395c635efSGarrett D'Amore 113495c635efSGarrett D'Amore while ((sd = readdir(sdp))) { 113595c635efSGarrett D'Amore char *pname; 113695c635efSGarrett D'Amore 113795c635efSGarrett D'Amore if ((pname = strdup(sd->d_name)) == NULL) 113895c635efSGarrett D'Amore err(1, "strdup"); 113995c635efSGarrett D'Amore if ((last = strrchr(pname, '.')) != NULL && 114095c635efSGarrett D'Amore (strcmp(last, ".gz") == 0 || strcmp(last, ".bz2") == 0)) 114195c635efSGarrett D'Amore *last = '\0'; 114295c635efSGarrett D'Amore last = strrchr(pname, '.'); 114395c635efSGarrett D'Amore nlen = last - pname; 114495c635efSGarrett D'Amore (void) snprintf(dname, sizeof (dname), "%.*s.", nlen, pname); 114595c635efSGarrett D'Amore if (strcmp(dname, file) == 0 || 114695c635efSGarrett D'Amore strcmp(pname, name) == 0) { 114795c635efSGarrett D'Amore (void) format(path, dir, name, sd->d_name); 114895c635efSGarrett D'Amore (void) closedir(sdp); 114995c635efSGarrett D'Amore free(pname); 115095c635efSGarrett D'Amore return (1); 115195c635efSGarrett D'Amore } 115295c635efSGarrett D'Amore free(pname); 115395c635efSGarrett D'Amore } 115495c635efSGarrett D'Amore (void) closedir(sdp); 115595c635efSGarrett D'Amore 115695c635efSGarrett D'Amore return (0); 115795c635efSGarrett D'Amore } 115895c635efSGarrett D'Amore 115995c635efSGarrett D'Amore /* 116095c635efSGarrett D'Amore * Check the hash table of old directory names to see if there is a 116195c635efSGarrett D'Amore * new directory name. 116295c635efSGarrett D'Amore */ 116395c635efSGarrett D'Amore static char * 116495c635efSGarrett D'Amore map_section(char *section, char *path) 116595c635efSGarrett D'Amore { 116695c635efSGarrett D'Amore int i; 116795c635efSGarrett D'Amore char fullpath[MAXPATHLEN]; 116895c635efSGarrett D'Amore 116995c635efSGarrett D'Amore if (list) /* -l option fall through */ 117095c635efSGarrett D'Amore return (NULL); 117195c635efSGarrett D'Amore 117295c635efSGarrett D'Amore for (i = 0; map[i].new_name != NULL; i++) { 117395c635efSGarrett D'Amore if (strcmp(section, map[i].old_name) == 0) { 117495c635efSGarrett D'Amore (void) snprintf(fullpath, sizeof (fullpath), 117595c635efSGarrett D'Amore "%s/man%s", path, map[i].new_name); 117695c635efSGarrett D'Amore if (!access(fullpath, R_OK | X_OK)) { 117795c635efSGarrett D'Amore return (map[i].new_name); 117895c635efSGarrett D'Amore } else { 117995c635efSGarrett D'Amore return (NULL); 118095c635efSGarrett D'Amore } 118195c635efSGarrett D'Amore } 118295c635efSGarrett D'Amore } 118395c635efSGarrett D'Amore 118495c635efSGarrett D'Amore return (NULL); 118595c635efSGarrett D'Amore } 118695c635efSGarrett D'Amore 118795c635efSGarrett D'Amore /* 118895c635efSGarrett D'Amore * Format the manpage. 118995c635efSGarrett D'Amore */ 119095c635efSGarrett D'Amore static int 119195c635efSGarrett D'Amore format(char *path, char *dir, char *name, char *pg) 119295c635efSGarrett D'Amore { 119395c635efSGarrett D'Amore char manpname[MAXPATHLEN], catpname[MAXPATHLEN]; 119495c635efSGarrett D'Amore char cmdbuf[BUFSIZ], tmpbuf[BUFSIZ]; 119595c635efSGarrett D'Amore char *cattool; 119695c635efSGarrett D'Amore struct stat sbman, sbcat; 119795c635efSGarrett D'Amore 119895c635efSGarrett D'Amore found++; 119995c635efSGarrett D'Amore 120095c635efSGarrett D'Amore if (list) { 120195c635efSGarrett D'Amore (void) printf(gettext("%s(%s)\t-M %s\n"), name, dir + 3, path); 120295c635efSGarrett D'Amore return (-1); 120395c635efSGarrett D'Amore } 120495c635efSGarrett D'Amore 120595c635efSGarrett D'Amore (void) snprintf(manpname, sizeof (manpname), "%s/man%s/%s", path, 120695c635efSGarrett D'Amore dir + 3, pg); 120795c635efSGarrett D'Amore (void) snprintf(catpname, sizeof (catpname), "%s/cat%s/%s", path, 120895c635efSGarrett D'Amore dir + 3, pg); 120995c635efSGarrett D'Amore 121095c635efSGarrett D'Amore /* Can't do PS output if manpage doesn't exist */ 121195c635efSGarrett D'Amore if (stat(manpname, &sbman) != 0 && (psoutput|lintout)) 121295c635efSGarrett D'Amore return (-1); 121395c635efSGarrett D'Amore 121495c635efSGarrett D'Amore /* 121595c635efSGarrett D'Amore * If both manpage and catpage do not exist, manpname is 121695c635efSGarrett D'Amore * broken symlink, most likely. 121795c635efSGarrett D'Amore */ 121895c635efSGarrett D'Amore if (stat(catpname, &sbcat) != 0 && stat(manpname, &sbman) != 0) 121995c635efSGarrett D'Amore err(1, "%s", manpname); 122095c635efSGarrett D'Amore 122195c635efSGarrett D'Amore /* Setup cattool */ 122295c635efSGarrett D'Amore if (fnmatch("*.gz", manpname, 0) == 0) 122395c635efSGarrett D'Amore cattool = "gzcat"; 122495c635efSGarrett D'Amore else if (fnmatch("*.bz2", manpname, 0) == 0) 122595c635efSGarrett D'Amore cattool = "bzcat"; 122695c635efSGarrett D'Amore else 122795c635efSGarrett D'Amore cattool = "cat"; 122895c635efSGarrett D'Amore 122995c635efSGarrett D'Amore if (psoutput) { 123095c635efSGarrett D'Amore (void) snprintf(cmdbuf, BUFSIZ, 1231*260e9a87SYuri Pankov "cd %s; %s %s | mandoc -Tps | lp -Tpostscript", 1232*260e9a87SYuri Pankov path, cattool, manpname); 123395c635efSGarrett D'Amore DPRINTF("-- Using manpage: %s\n", manpname); 123495c635efSGarrett D'Amore goto cmd; 123595c635efSGarrett D'Amore } else if (lintout) { 123695c635efSGarrett D'Amore (void) snprintf(cmdbuf, BUFSIZ, 1237*260e9a87SYuri Pankov "cd %s; %s %s | mandoc -Tlint", 1238*260e9a87SYuri Pankov path, cattool, manpname); 123995c635efSGarrett D'Amore DPRINTF("-- Linting manpage: %s\n", manpname); 124095c635efSGarrett D'Amore goto cmd; 124195c635efSGarrett D'Amore } 124295c635efSGarrett D'Amore 124395c635efSGarrett D'Amore /* 124495c635efSGarrett D'Amore * Output catpage if: 124595c635efSGarrett D'Amore * - manpage doesn't exist 124695c635efSGarrett D'Amore * - output width is standard and catpage is recent enough 124795c635efSGarrett D'Amore */ 124895c635efSGarrett D'Amore if (stat(manpname, &sbman) != 0 || (manwidth == 0 && 124995c635efSGarrett D'Amore stat(catpname, &sbcat) == 0 && sbcat.st_mtime >= sbman.st_mtime)) { 125095c635efSGarrett D'Amore DPRINTF("-- Using catpage: %s\n", catpname); 125195c635efSGarrett D'Amore (void) snprintf(cmdbuf, BUFSIZ, "%s %s", pager, catpname); 125295c635efSGarrett D'Amore goto cmd; 125395c635efSGarrett D'Amore } 125495c635efSGarrett D'Amore 125595c635efSGarrett D'Amore DPRINTF("-- Using manpage: %s\n", manpname); 125695c635efSGarrett D'Amore if (manwidth > 0) 125795c635efSGarrett D'Amore (void) snprintf(tmpbuf, BUFSIZ, "-Owidth=%d ", manwidth); 1258*260e9a87SYuri Pankov (void) snprintf(cmdbuf, BUFSIZ, "cd %s; %s %s | mandoc %s| %s", 1259*260e9a87SYuri Pankov path, cattool, manpname, (manwidth > 0) ? tmpbuf : "", pager); 126095c635efSGarrett D'Amore 126195c635efSGarrett D'Amore cmd: 126295c635efSGarrett D'Amore DPRINTF("-- Command: %s\n", cmdbuf); 126395c635efSGarrett D'Amore 126495c635efSGarrett D'Amore if (!debug) 126595c635efSGarrett D'Amore return (system(cmdbuf) == 0); 126695c635efSGarrett D'Amore else 126795c635efSGarrett D'Amore return (0); 126895c635efSGarrett D'Amore } 126995c635efSGarrett D'Amore 127095c635efSGarrett D'Amore /* 127195c635efSGarrett D'Amore * Add <localedir> to the path. 127295c635efSGarrett D'Amore */ 127395c635efSGarrett D'Amore static char * 127495c635efSGarrett D'Amore addlocale(char *path) 127595c635efSGarrett D'Amore { 127695c635efSGarrett D'Amore char *tmp; 127795c635efSGarrett D'Amore 127895c635efSGarrett D'Amore if (asprintf(&tmp, "%s/%s", path, localedir) == -1) 127995c635efSGarrett D'Amore err(1, "asprintf"); 128095c635efSGarrett D'Amore 128195c635efSGarrett D'Amore return (tmp); 128295c635efSGarrett D'Amore } 128395c635efSGarrett D'Amore 128495c635efSGarrett D'Amore /* 128595c635efSGarrett D'Amore * Get the order of sections from man.cf. 128695c635efSGarrett D'Amore */ 128795c635efSGarrett D'Amore static char * 128895c635efSGarrett D'Amore check_config(char *path) 128995c635efSGarrett D'Amore { 129095c635efSGarrett D'Amore FILE *fp; 129195c635efSGarrett D'Amore char *rc = NULL; 129295c635efSGarrett D'Amore char *sect; 129395c635efSGarrett D'Amore char fname[MAXPATHLEN]; 129495c635efSGarrett D'Amore char *line = NULL; 129595c635efSGarrett D'Amore size_t linecap = 0; 129695c635efSGarrett D'Amore 129795c635efSGarrett D'Amore (void) snprintf(fname, MAXPATHLEN, "%s/%s", path, CONFIG); 129895c635efSGarrett D'Amore 129995c635efSGarrett D'Amore if ((fp = fopen(fname, "r")) == NULL) 130095c635efSGarrett D'Amore return (NULL); 130195c635efSGarrett D'Amore 130295c635efSGarrett D'Amore while (getline(&line, &linecap, fp) > 0) { 130395c635efSGarrett D'Amore if ((rc = strstr(line, "MANSECTS")) != NULL) 130495c635efSGarrett D'Amore break; 130595c635efSGarrett D'Amore } 130695c635efSGarrett D'Amore 130795c635efSGarrett D'Amore (void) fclose(fp); 130895c635efSGarrett D'Amore 130995c635efSGarrett D'Amore if (rc == NULL || (sect = strchr(line, '=')) == NULL) 131095c635efSGarrett D'Amore return (NULL); 131195c635efSGarrett D'Amore else 131295c635efSGarrett D'Amore return (++sect); 131395c635efSGarrett D'Amore } 131495c635efSGarrett D'Amore 131595c635efSGarrett D'Amore 131695c635efSGarrett D'Amore /* 131795c635efSGarrett D'Amore * Initialize the bintoman array with appropriate device and inode info. 131895c635efSGarrett D'Amore */ 131995c635efSGarrett D'Amore static void 132095c635efSGarrett D'Amore init_bintoman(void) 132195c635efSGarrett D'Amore { 132295c635efSGarrett D'Amore int i; 132395c635efSGarrett D'Amore struct stat sb; 132495c635efSGarrett D'Amore 132595c635efSGarrett D'Amore for (i = 0; bintoman[i].bindir != NULL; i++) { 132695c635efSGarrett D'Amore if (stat(bintoman[i].bindir, &sb) == 0) { 132795c635efSGarrett D'Amore bintoman[i].dev = sb.st_dev; 132895c635efSGarrett D'Amore bintoman[i].ino = sb.st_ino; 132995c635efSGarrett D'Amore } else { 133095c635efSGarrett D'Amore bintoman[i].dev = NODEV; 133195c635efSGarrett D'Amore } 133295c635efSGarrett D'Amore } 133395c635efSGarrett D'Amore } 133495c635efSGarrett D'Amore 133595c635efSGarrett D'Amore /* 133695c635efSGarrett D'Amore * If a duplicate is found, return 1. 133795c635efSGarrett D'Amore * If a duplicate is not found, add it to the dupnode list and return 0. 133895c635efSGarrett D'Amore */ 133995c635efSGarrett D'Amore static int 134095c635efSGarrett D'Amore dupcheck(struct man_node *mnp, struct dupnode **dnp) 134195c635efSGarrett D'Amore { 134295c635efSGarrett D'Amore struct dupnode *curdnp; 134395c635efSGarrett D'Amore struct secnode *cursnp; 134495c635efSGarrett D'Amore struct stat sb; 134595c635efSGarrett D'Amore int i; 134695c635efSGarrett D'Amore int rv = 1; 134795c635efSGarrett D'Amore int dupfound; 134895c635efSGarrett D'Amore 134995c635efSGarrett D'Amore /* If the path doesn't exist, treat it as a duplicate */ 135095c635efSGarrett D'Amore if (stat(mnp->path, &sb) != 0) 135195c635efSGarrett D'Amore return (1); 135295c635efSGarrett D'Amore 135395c635efSGarrett D'Amore /* If no sections were found in the man dir, treat it as duplicate */ 135495c635efSGarrett D'Amore if (mnp->secv == NULL) 135595c635efSGarrett D'Amore return (1); 135695c635efSGarrett D'Amore 135795c635efSGarrett D'Amore /* 135895c635efSGarrett D'Amore * Find the dupnode structure for the previous time this directory 135995c635efSGarrett D'Amore * was looked at. Device and inode numbers are compared so that 136095c635efSGarrett D'Amore * directories that are reached via different paths (e.g. /usr/man and 136195c635efSGarrett D'Amore * /usr/share/man) are treated as equivalent. 136295c635efSGarrett D'Amore */ 136395c635efSGarrett D'Amore for (curdnp = *dnp; curdnp != NULL; curdnp = curdnp->next) { 136495c635efSGarrett D'Amore if (curdnp->dev == sb.st_dev && curdnp->ino == sb.st_ino) 136595c635efSGarrett D'Amore break; 136695c635efSGarrett D'Amore } 136795c635efSGarrett D'Amore 136895c635efSGarrett D'Amore /* 136995c635efSGarrett D'Amore * First time this directory has been seen. Add a new node to the 137095c635efSGarrett D'Amore * head of the list. Since all entries are guaranteed to be unique 137195c635efSGarrett D'Amore * copy all sections to new node. 137295c635efSGarrett D'Amore */ 137395c635efSGarrett D'Amore if (curdnp == NULL) { 137495c635efSGarrett D'Amore if ((curdnp = calloc(1, sizeof (struct dupnode))) == NULL) 137595c635efSGarrett D'Amore err(1, "calloc"); 137695c635efSGarrett D'Amore for (i = 0; mnp->secv[i] != NULL; i++) { 137795c635efSGarrett D'Amore if ((cursnp = calloc(1, sizeof (struct secnode))) 137895c635efSGarrett D'Amore == NULL) 137995c635efSGarrett D'Amore err(1, "calloc"); 138095c635efSGarrett D'Amore cursnp->next = curdnp->secl; 138195c635efSGarrett D'Amore curdnp->secl = cursnp; 138295c635efSGarrett D'Amore if ((cursnp->secp = strdup(mnp->secv[i])) == NULL) 138395c635efSGarrett D'Amore err(1, "strdup"); 138495c635efSGarrett D'Amore } 138595c635efSGarrett D'Amore curdnp->dev = sb.st_dev; 138695c635efSGarrett D'Amore curdnp->ino = sb.st_ino; 138795c635efSGarrett D'Amore curdnp->next = *dnp; 138895c635efSGarrett D'Amore *dnp = curdnp; 138995c635efSGarrett D'Amore return (0); 139095c635efSGarrett D'Amore } 139195c635efSGarrett D'Amore 139295c635efSGarrett D'Amore /* 139395c635efSGarrett D'Amore * Traverse the section vector in the man_node and the section list 139495c635efSGarrett D'Amore * in dupnode cache to eliminate all duplicates from man_node. 139595c635efSGarrett D'Amore */ 139695c635efSGarrett D'Amore for (i = 0; mnp->secv[i] != NULL; i++) { 139795c635efSGarrett D'Amore dupfound = 0; 139895c635efSGarrett D'Amore for (cursnp = curdnp->secl; cursnp != NULL; 139995c635efSGarrett D'Amore cursnp = cursnp->next) { 140095c635efSGarrett D'Amore if (strcmp(mnp->secv[i], cursnp->secp) == 0) { 140195c635efSGarrett D'Amore dupfound = 1; 140295c635efSGarrett D'Amore break; 140395c635efSGarrett D'Amore } 140495c635efSGarrett D'Amore } 140595c635efSGarrett D'Amore if (dupfound) { 140695c635efSGarrett D'Amore mnp->secv[i][0] = '\0'; 140795c635efSGarrett D'Amore continue; 140895c635efSGarrett D'Amore } 140995c635efSGarrett D'Amore 141095c635efSGarrett D'Amore 141195c635efSGarrett D'Amore /* 141295c635efSGarrett D'Amore * Update curdnp and set return value to indicate that this 141395c635efSGarrett D'Amore * was not all duplicates. 141495c635efSGarrett D'Amore */ 141595c635efSGarrett D'Amore if ((cursnp = calloc(1, sizeof (struct secnode))) == NULL) 141695c635efSGarrett D'Amore err(1, "calloc"); 141795c635efSGarrett D'Amore cursnp->next = curdnp->secl; 141895c635efSGarrett D'Amore curdnp->secl = cursnp; 141995c635efSGarrett D'Amore if ((cursnp->secp = strdup(mnp->secv[i])) == NULL) 142095c635efSGarrett D'Amore err(1, "strdup"); 142195c635efSGarrett D'Amore rv = 0; 142295c635efSGarrett D'Amore } 142395c635efSGarrett D'Amore 142495c635efSGarrett D'Amore return (rv); 142595c635efSGarrett D'Amore } 142695c635efSGarrett D'Amore 142795c635efSGarrett D'Amore /* 142895c635efSGarrett D'Amore * Given a bindir, return corresponding mandir. 142995c635efSGarrett D'Amore */ 143095c635efSGarrett D'Amore static char * 143195c635efSGarrett D'Amore path_to_manpath(char *bindir) 143295c635efSGarrett D'Amore { 143395c635efSGarrett D'Amore char *mand, *p; 143495c635efSGarrett D'Amore int i; 143595c635efSGarrett D'Amore struct stat sb; 143695c635efSGarrett D'Amore 143795c635efSGarrett D'Amore /* First look for known translations for specific bin paths */ 143895c635efSGarrett D'Amore if (stat(bindir, &sb) != 0) { 143995c635efSGarrett D'Amore return (NULL); 144095c635efSGarrett D'Amore } 144195c635efSGarrett D'Amore for (i = 0; bintoman[i].bindir != NULL; i++) { 144295c635efSGarrett D'Amore if (sb.st_dev == bintoman[i].dev && 144395c635efSGarrett D'Amore sb.st_ino == bintoman[i].ino) { 144495c635efSGarrett D'Amore if ((mand = strdup(bintoman[i].mandir)) == NULL) 144595c635efSGarrett D'Amore err(1, "strdup"); 144695c635efSGarrett D'Amore if ((p = strchr(mand, ',')) != NULL) 144795c635efSGarrett D'Amore *p = '\0'; 144895c635efSGarrett D'Amore if (stat(mand, &sb) != 0) { 144995c635efSGarrett D'Amore free(mand); 145095c635efSGarrett D'Amore return (NULL); 145195c635efSGarrett D'Amore } 145295c635efSGarrett D'Amore if (p != NULL) 145395c635efSGarrett D'Amore *p = ','; 145495c635efSGarrett D'Amore return (mand); 145595c635efSGarrett D'Amore } 145695c635efSGarrett D'Amore } 145795c635efSGarrett D'Amore 145895c635efSGarrett D'Amore /* 145995c635efSGarrett D'Amore * No specific translation found. Try `dirname $bindir`/share/man 146095c635efSGarrett D'Amore * and `dirname $bindir`/man 146195c635efSGarrett D'Amore */ 146295c635efSGarrett D'Amore if ((mand = malloc(MAXPATHLEN)) == NULL) 146395c635efSGarrett D'Amore err(1, "malloc"); 146495c635efSGarrett D'Amore if (strlcpy(mand, bindir, MAXPATHLEN) >= MAXPATHLEN) { 146595c635efSGarrett D'Amore free(mand); 146695c635efSGarrett D'Amore return (NULL); 146795c635efSGarrett D'Amore } 146895c635efSGarrett D'Amore 146995c635efSGarrett D'Amore /* 147095c635efSGarrett D'Amore * Advance to end of buffer, strip trailing /'s then remove last 147195c635efSGarrett D'Amore * directory component. 147295c635efSGarrett D'Amore */ 147395c635efSGarrett D'Amore for (p = mand; *p != '\0'; p++) 147495c635efSGarrett D'Amore ; 147595c635efSGarrett D'Amore for (; p > mand && *p == '/'; p--) 147695c635efSGarrett D'Amore ; 147795c635efSGarrett D'Amore for (; p > mand && *p != '/'; p--) 147895c635efSGarrett D'Amore ; 147995c635efSGarrett D'Amore if (p == mand && *p == '.') { 148095c635efSGarrett D'Amore if (realpath("..", mand) == NULL) { 148195c635efSGarrett D'Amore free(mand); 148295c635efSGarrett D'Amore return (NULL); 148395c635efSGarrett D'Amore } 148495c635efSGarrett D'Amore for (; *p != '\0'; p++) 148595c635efSGarrett D'Amore ; 148695c635efSGarrett D'Amore } else { 148795c635efSGarrett D'Amore *p = '\0'; 148895c635efSGarrett D'Amore } 148995c635efSGarrett D'Amore 149095c635efSGarrett D'Amore if (strlcat(mand, "/share/man", MAXPATHLEN) >= MAXPATHLEN) { 149195c635efSGarrett D'Amore free(mand); 149295c635efSGarrett D'Amore return (NULL); 149395c635efSGarrett D'Amore } 149495c635efSGarrett D'Amore 149595c635efSGarrett D'Amore if ((stat(mand, &sb) == 0) && S_ISDIR(sb.st_mode)) { 149695c635efSGarrett D'Amore return (mand); 149795c635efSGarrett D'Amore } 149895c635efSGarrett D'Amore 149995c635efSGarrett D'Amore /* 150095c635efSGarrett D'Amore * Strip the /share/man off and try /man 150195c635efSGarrett D'Amore */ 150295c635efSGarrett D'Amore *p = '\0'; 150395c635efSGarrett D'Amore if (strlcat(mand, "/man", MAXPATHLEN) >= MAXPATHLEN) { 150495c635efSGarrett D'Amore free(mand); 150595c635efSGarrett D'Amore return (NULL); 150695c635efSGarrett D'Amore } 150795c635efSGarrett D'Amore if ((stat(mand, &sb) == 0) && S_ISDIR(sb.st_mode)) { 150895c635efSGarrett D'Amore return (mand); 150995c635efSGarrett D'Amore } 151095c635efSGarrett D'Amore 151195c635efSGarrett D'Amore /* 151295c635efSGarrett D'Amore * No man or share/man directory found 151395c635efSGarrett D'Amore */ 151495c635efSGarrett D'Amore free(mand); 151595c635efSGarrett D'Amore return (NULL); 151695c635efSGarrett D'Amore } 151795c635efSGarrett D'Amore 151895c635efSGarrett D'Amore /* 151995c635efSGarrett D'Amore * Free a linked list of dupnode structs. 152095c635efSGarrett D'Amore */ 152195c635efSGarrett D'Amore void 152295c635efSGarrett D'Amore free_dupnode(struct dupnode *dnp) { 152395c635efSGarrett D'Amore struct dupnode *dnp2; 152495c635efSGarrett D'Amore struct secnode *snp; 152595c635efSGarrett D'Amore 152695c635efSGarrett D'Amore while (dnp != NULL) { 152795c635efSGarrett D'Amore dnp2 = dnp; 152895c635efSGarrett D'Amore dnp = dnp->next; 152995c635efSGarrett D'Amore while (dnp2->secl != NULL) { 153095c635efSGarrett D'Amore snp = dnp2->secl; 153195c635efSGarrett D'Amore dnp2->secl = dnp2->secl->next; 153295c635efSGarrett D'Amore free(snp->secp); 153395c635efSGarrett D'Amore free(snp); 153495c635efSGarrett D'Amore } 153595c635efSGarrett D'Amore free(dnp2); 153695c635efSGarrett D'Amore } 153795c635efSGarrett D'Amore } 153895c635efSGarrett D'Amore 153995c635efSGarrett D'Amore /* 154095c635efSGarrett D'Amore * Print manp linked list to stdout. 154195c635efSGarrett D'Amore */ 154295c635efSGarrett D'Amore void 154395c635efSGarrett D'Amore print_manpath(struct man_node *manp) 154495c635efSGarrett D'Amore { 154595c635efSGarrett D'Amore char colon[2] = "\0\0"; 154695c635efSGarrett D'Amore char **secp; 154795c635efSGarrett D'Amore 154895c635efSGarrett D'Amore for (; manp != NULL; manp = manp->next) { 154995c635efSGarrett D'Amore (void) printf("%s%s", colon, manp->path); 155095c635efSGarrett D'Amore colon[0] = ':'; 155195c635efSGarrett D'Amore 155295c635efSGarrett D'Amore /* 155395c635efSGarrett D'Amore * If man.cf or a directory scan was used to create section 155495c635efSGarrett D'Amore * list, do not print section list again. If the output of 155595c635efSGarrett D'Amore * man -p is used to set MANPATH, subsequent runs of man 155695c635efSGarrett D'Amore * will re-read man.cf and/or scan man directories as 155795c635efSGarrett D'Amore * required. 155895c635efSGarrett D'Amore */ 155995c635efSGarrett D'Amore if (manp->defsrch != 0) 156095c635efSGarrett D'Amore continue; 156195c635efSGarrett D'Amore 156295c635efSGarrett D'Amore for (secp = manp->secv; *secp != NULL; secp++) { 156395c635efSGarrett D'Amore /* 156495c635efSGarrett D'Amore * Section deduplication may have eliminated some 156595c635efSGarrett D'Amore * sections from the vector. Avoid displaying this 156695c635efSGarrett D'Amore * detail which would appear as ",," in output 156795c635efSGarrett D'Amore */ 156895c635efSGarrett D'Amore if ((*secp)[0] != '\0') 156995c635efSGarrett D'Amore (void) printf(",%s", *secp); 157095c635efSGarrett D'Amore } 157195c635efSGarrett D'Amore } 157295c635efSGarrett D'Amore (void) printf("\n"); 157395c635efSGarrett D'Amore } 157495c635efSGarrett D'Amore 157595c635efSGarrett D'Amore static void 157695c635efSGarrett D'Amore usage_man(void) 157795c635efSGarrett D'Amore { 157895c635efSGarrett D'Amore 157995c635efSGarrett D'Amore (void) fprintf(stderr, gettext( 158095c635efSGarrett D'Amore "usage: man [-alptw] [-M path] [-s section] name ...\n" 158195c635efSGarrett D'Amore " man [-M path] [-s section] -k keyword ...\n" 158295c635efSGarrett D'Amore " man [-M path] [-s section] -f keyword ...\n")); 158395c635efSGarrett D'Amore 158495c635efSGarrett D'Amore exit(1); 158595c635efSGarrett D'Amore } 158695c635efSGarrett D'Amore 158795c635efSGarrett D'Amore static void 158895c635efSGarrett D'Amore usage_whatapro(void) 158995c635efSGarrett D'Amore { 159095c635efSGarrett D'Amore 159195c635efSGarrett D'Amore (void) fprintf(stderr, gettext( 159295c635efSGarrett D'Amore "usage: %s [-M path] [-s section] keyword ...\n"), 159395c635efSGarrett D'Amore whatis ? "whatis" : "apropos"); 159495c635efSGarrett D'Amore 159595c635efSGarrett D'Amore exit(1); 159695c635efSGarrett D'Amore } 159795c635efSGarrett D'Amore 159895c635efSGarrett D'Amore static void 159995c635efSGarrett D'Amore usage_catman(void) 160095c635efSGarrett D'Amore { 160195c635efSGarrett D'Amore (void) fprintf(stderr, gettext( 160295c635efSGarrett D'Amore "usage: catman [-M path] [-w]\n")); 160395c635efSGarrett D'Amore 160495c635efSGarrett D'Amore exit(1); 160595c635efSGarrett D'Amore } 160695c635efSGarrett D'Amore 160795c635efSGarrett D'Amore static void 160895c635efSGarrett D'Amore usage_makewhatis(void) 160995c635efSGarrett D'Amore { 161095c635efSGarrett D'Amore (void) fprintf(stderr, gettext("usage: makewhatis\n")); 161195c635efSGarrett D'Amore 161295c635efSGarrett D'Amore exit(1); 161395c635efSGarrett D'Amore } 1614