1*95c635efSGarrett D'Amore /* 2*95c635efSGarrett D'Amore * CDDL HEADER START 3*95c635efSGarrett D'Amore * 4*95c635efSGarrett D'Amore * The contents of this file are subject to the terms of the 5*95c635efSGarrett D'Amore * Common Development and Distribution License (the "License"). 6*95c635efSGarrett D'Amore * You may not use this file except in compliance with the License. 7*95c635efSGarrett D'Amore * 8*95c635efSGarrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*95c635efSGarrett D'Amore * or http://www.opensolaris.org/os/licensing. 10*95c635efSGarrett D'Amore * See the License for the specific language governing permissions 11*95c635efSGarrett D'Amore * and limitations under the License. 12*95c635efSGarrett D'Amore * 13*95c635efSGarrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each 14*95c635efSGarrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*95c635efSGarrett D'Amore * If applicable, add the following below this CDDL HEADER, with the 16*95c635efSGarrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying 17*95c635efSGarrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner] 18*95c635efSGarrett D'Amore * 19*95c635efSGarrett D'Amore * CDDL HEADER END 20*95c635efSGarrett D'Amore */ 21*95c635efSGarrett D'Amore 22*95c635efSGarrett D'Amore /* 23*95c635efSGarrett D'Amore * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. 24*95c635efSGarrett D'Amore * Copyright 2012, Josef 'Jeff' Sipek <jeffpc@31bits.net>. All rights reserved. 25*95c635efSGarrett D'Amore * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 26*95c635efSGarrett D'Amore * Copyright 2014 Garrett D'Amore <garrett@damore.org> 27*95c635efSGarrett D'Amore */ 28*95c635efSGarrett D'Amore 29*95c635efSGarrett D'Amore /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T. */ 30*95c635efSGarrett D'Amore /* All rights reserved. */ 31*95c635efSGarrett D'Amore 32*95c635efSGarrett D'Amore /* 33*95c635efSGarrett D'Amore * University Copyright- Copyright (c) 1982, 1986, 1988 34*95c635efSGarrett D'Amore * The Regents of the University of California 35*95c635efSGarrett D'Amore * All Rights Reserved 36*95c635efSGarrett D'Amore * 37*95c635efSGarrett D'Amore * University Acknowledgment- Portions of this document are derived from 38*95c635efSGarrett D'Amore * software developed by the University of California, Berkeley, and its 39*95c635efSGarrett D'Amore * contributors. 40*95c635efSGarrett D'Amore */ 41*95c635efSGarrett D'Amore 42*95c635efSGarrett D'Amore /* 43*95c635efSGarrett D'Amore * Find and display reference manual pages. This version includes makewhatis 44*95c635efSGarrett D'Amore * functionality as well. 45*95c635efSGarrett D'Amore */ 46*95c635efSGarrett D'Amore 47*95c635efSGarrett D'Amore #include <sys/param.h> 48*95c635efSGarrett D'Amore #include <sys/stat.h> 49*95c635efSGarrett D'Amore #include <sys/termios.h> 50*95c635efSGarrett D'Amore #include <sys/types.h> 51*95c635efSGarrett D'Amore 52*95c635efSGarrett D'Amore #include <ctype.h> 53*95c635efSGarrett D'Amore #include <dirent.h> 54*95c635efSGarrett D'Amore #include <err.h> 55*95c635efSGarrett D'Amore #include <errno.h> 56*95c635efSGarrett D'Amore #include <fcntl.h> 57*95c635efSGarrett D'Amore #include <fnmatch.h> 58*95c635efSGarrett D'Amore #include <limits.h> 59*95c635efSGarrett D'Amore #include <locale.h> 60*95c635efSGarrett D'Amore #include <malloc.h> 61*95c635efSGarrett D'Amore #include <memory.h> 62*95c635efSGarrett D'Amore #include <regex.h> 63*95c635efSGarrett D'Amore #include <stdio.h> 64*95c635efSGarrett D'Amore #include <stdlib.h> 65*95c635efSGarrett D'Amore #include <string.h> 66*95c635efSGarrett D'Amore #include <unistd.h> 67*95c635efSGarrett D'Amore 68*95c635efSGarrett D'Amore #include "man.h" 69*95c635efSGarrett D'Amore 70*95c635efSGarrett D'Amore 71*95c635efSGarrett D'Amore /* Mapping of old directories to new directories */ 72*95c635efSGarrett D'Amore static const struct map_entry { 73*95c635efSGarrett D'Amore char *old_name; 74*95c635efSGarrett D'Amore char *new_name; 75*95c635efSGarrett D'Amore } map[] = { 76*95c635efSGarrett D'Amore { "3b", "3ucb" }, 77*95c635efSGarrett D'Amore { "3e", "3elf" }, 78*95c635efSGarrett D'Amore { "3g", "3gen" }, 79*95c635efSGarrett D'Amore { "3k", "3kstat" }, 80*95c635efSGarrett D'Amore { "3n", "3socket" }, 81*95c635efSGarrett D'Amore { "3r", "3rt" }, 82*95c635efSGarrett D'Amore { "3s", "3c" }, 83*95c635efSGarrett D'Amore { "3t", "3thr" }, 84*95c635efSGarrett D'Amore { "3x", "3curses" }, 85*95c635efSGarrett D'Amore { "3xc", "3xcurses" }, 86*95c635efSGarrett D'Amore { "3xn", "3xnet" }, 87*95c635efSGarrett D'Amore { NULL, NULL } 88*95c635efSGarrett D'Amore }; 89*95c635efSGarrett D'Amore 90*95c635efSGarrett D'Amore struct suffix { 91*95c635efSGarrett D'Amore char *ds; 92*95c635efSGarrett D'Amore char *fs; 93*95c635efSGarrett D'Amore }; 94*95c635efSGarrett D'Amore 95*95c635efSGarrett D'Amore /* 96*95c635efSGarrett D'Amore * Flags that control behavior of build_manpath() 97*95c635efSGarrett D'Amore * 98*95c635efSGarrett D'Amore * BMP_ISPATH pathv is a vector constructed from PATH. 99*95c635efSGarrett D'Amore * Perform appropriate path translations for 100*95c635efSGarrett D'Amore * manpath. 101*95c635efSGarrett D'Amore * BMP_APPEND_DEFMANDIR Add DEFMANDIR to the end if it hasn't 102*95c635efSGarrett D'Amore * already appeared earlier. 103*95c635efSGarrett D'Amore * BMP_FALLBACK_DEFMANDIR Append /usr/share/man only if no other 104*95c635efSGarrett D'Amore * manpath (including derived from PATH) 105*95c635efSGarrett D'Amore * elements are valid. 106*95c635efSGarrett D'Amore */ 107*95c635efSGarrett D'Amore #define BMP_ISPATH 1 108*95c635efSGarrett D'Amore #define BMP_APPEND_DEFMANDIR 2 109*95c635efSGarrett D'Amore #define BMP_FALLBACK_DEFMANDIR 4 110*95c635efSGarrett D'Amore 111*95c635efSGarrett D'Amore /* 112*95c635efSGarrett D'Amore * When doing equality comparisons of directories, device and inode 113*95c635efSGarrett D'Amore * comparisons are done. The secnode and dupnode structures are used 114*95c635efSGarrett D'Amore * to form a list of lists for this processing. 115*95c635efSGarrett D'Amore */ 116*95c635efSGarrett D'Amore struct secnode { 117*95c635efSGarrett D'Amore char *secp; 118*95c635efSGarrett D'Amore struct secnode *next; 119*95c635efSGarrett D'Amore }; 120*95c635efSGarrett D'Amore struct dupnode { 121*95c635efSGarrett D'Amore dev_t dev; /* from struct stat st_dev */ 122*95c635efSGarrett D'Amore ino_t ino; /* from struct stat st_ino */ 123*95c635efSGarrett D'Amore struct secnode *secl; /* sections already considered */ 124*95c635efSGarrett D'Amore struct dupnode *next; 125*95c635efSGarrett D'Amore }; 126*95c635efSGarrett D'Amore 127*95c635efSGarrett D'Amore /* 128*95c635efSGarrett D'Amore * Map directories that may appear in PATH to the corresponding 129*95c635efSGarrett D'Amore * man directory. 130*95c635efSGarrett D'Amore */ 131*95c635efSGarrett D'Amore static struct pathmap { 132*95c635efSGarrett D'Amore char *bindir; 133*95c635efSGarrett D'Amore char *mandir; 134*95c635efSGarrett D'Amore dev_t dev; 135*95c635efSGarrett D'Amore ino_t ino; 136*95c635efSGarrett D'Amore } bintoman[] = { 137*95c635efSGarrett D'Amore { "/sbin", "/usr/share/man,1m", 0, 0 }, 138*95c635efSGarrett D'Amore { "/usr/sbin", "/usr/share/man,1m", 0, 0 }, 139*95c635efSGarrett D'Amore { "/usr/ucb", "/usr/share/man,1b", 0, 0 }, 140*95c635efSGarrett D'Amore { "/usr/bin", "/usr/share/man,1,1m,1s,1t,1c", 0, 0 }, 141*95c635efSGarrett D'Amore { "/usr/xpg4/bin", "/usr/share/man,1", 0, 0 }, 142*95c635efSGarrett D'Amore { "/usr/xpg6/bin", "/usr/share/man,1", 0, 0 }, 143*95c635efSGarrett D'Amore { NULL, NULL, 0, 0 } 144*95c635efSGarrett D'Amore }; 145*95c635efSGarrett D'Amore 146*95c635efSGarrett D'Amore struct man_node { 147*95c635efSGarrett D'Amore char *path; /* mandir path */ 148*95c635efSGarrett D'Amore char **secv; /* submandir suffices */ 149*95c635efSGarrett D'Amore int defsrch; /* hint for man -p */ 150*95c635efSGarrett D'Amore int frompath; /* hint for man -d */ 151*95c635efSGarrett D'Amore struct man_node *next; 152*95c635efSGarrett D'Amore }; 153*95c635efSGarrett D'Amore 154*95c635efSGarrett D'Amore static int all = 0; 155*95c635efSGarrett D'Amore static int apropos = 0; 156*95c635efSGarrett D'Amore static int debug = 0; 157*95c635efSGarrett D'Amore static int found = 0; 158*95c635efSGarrett D'Amore static int list = 0; 159*95c635efSGarrett D'Amore static int makewhatis = 0; 160*95c635efSGarrett D'Amore static int printmp = 0; 161*95c635efSGarrett D'Amore static int sargs = 0; 162*95c635efSGarrett D'Amore static int psoutput = 0; 163*95c635efSGarrett D'Amore static int lintout = 0; 164*95c635efSGarrett D'Amore static int whatis = 0; 165*95c635efSGarrett D'Amore static int makewhatishere = 0; 166*95c635efSGarrett D'Amore 167*95c635efSGarrett D'Amore static char *mansec; 168*95c635efSGarrett D'Amore static char *pager = NULL; 169*95c635efSGarrett D'Amore 170*95c635efSGarrett D'Amore static char *addlocale(char *); 171*95c635efSGarrett D'Amore static struct man_node *build_manpath(char **, int); 172*95c635efSGarrett D'Amore static void do_makewhatis(struct man_node *); 173*95c635efSGarrett D'Amore static char *check_config(char *); 174*95c635efSGarrett D'Amore static int cmp(const void *, const void *); 175*95c635efSGarrett D'Amore static int dupcheck(struct man_node *, struct dupnode **); 176*95c635efSGarrett D'Amore static int format(char *, char *, char *, char *); 177*95c635efSGarrett D'Amore static void free_dupnode(struct dupnode *); 178*95c635efSGarrett D'Amore static void free_manp(struct man_node *manp); 179*95c635efSGarrett D'Amore static void freev(char **); 180*95c635efSGarrett D'Amore static void fullpaths(struct man_node **); 181*95c635efSGarrett D'Amore static void get_all_sect(struct man_node *); 182*95c635efSGarrett D'Amore static int getdirs(char *, char ***, int); 183*95c635efSGarrett D'Amore static void getpath(struct man_node *, char **); 184*95c635efSGarrett D'Amore static void getsect(struct man_node *, char **); 185*95c635efSGarrett D'Amore static void init_bintoman(void); 186*95c635efSGarrett D'Amore static void lower(char *); 187*95c635efSGarrett D'Amore static void mandir(char **, char *, char *, int); 188*95c635efSGarrett D'Amore static int manual(struct man_node *, char *); 189*95c635efSGarrett D'Amore static char *map_section(char *, char *); 190*95c635efSGarrett D'Amore static char *path_to_manpath(char *); 191*95c635efSGarrett D'Amore static void print_manpath(struct man_node *); 192*95c635efSGarrett D'Amore static void search_whatis(char *, char *); 193*95c635efSGarrett D'Amore static int searchdir(char *, char *, char *); 194*95c635efSGarrett D'Amore static void sortdir(DIR *, char ***); 195*95c635efSGarrett D'Amore static char **split(char *, char); 196*95c635efSGarrett D'Amore static void usage_man(void); 197*95c635efSGarrett D'Amore static void usage_whatapro(void); 198*95c635efSGarrett D'Amore static void usage_catman(void); 199*95c635efSGarrett D'Amore static void usage_makewhatis(void); 200*95c635efSGarrett D'Amore static void whatapro(struct man_node *, char *); 201*95c635efSGarrett D'Amore 202*95c635efSGarrett D'Amore static char language[MAXPATHLEN]; /* LC_MESSAGES */ 203*95c635efSGarrett D'Amore static char localedir[MAXPATHLEN]; /* locale specific path component */ 204*95c635efSGarrett D'Amore 205*95c635efSGarrett D'Amore static char *newsection = NULL; 206*95c635efSGarrett D'Amore 207*95c635efSGarrett D'Amore static int manwidth = 0; 208*95c635efSGarrett D'Amore 209*95c635efSGarrett D'Amore extern const char *__progname; 210*95c635efSGarrett D'Amore 211*95c635efSGarrett D'Amore int 212*95c635efSGarrett D'Amore main(int argc, char **argv) 213*95c635efSGarrett D'Amore { 214*95c635efSGarrett D'Amore int c, i; 215*95c635efSGarrett D'Amore char **pathv; 216*95c635efSGarrett D'Amore char *manpath = NULL; 217*95c635efSGarrett D'Amore static struct man_node *mandirs = NULL; 218*95c635efSGarrett D'Amore int bmp_flags = 0; 219*95c635efSGarrett D'Amore int ret = 0; 220*95c635efSGarrett D'Amore char *opts; 221*95c635efSGarrett D'Amore char *mwstr; 222*95c635efSGarrett D'Amore int catman = 0; 223*95c635efSGarrett D'Amore 224*95c635efSGarrett D'Amore (void) setlocale(LC_ALL, ""); 225*95c635efSGarrett D'Amore (void) strcpy(language, setlocale(LC_MESSAGES, (char *)NULL)); 226*95c635efSGarrett D'Amore if (strcmp("C", language) != 0) 227*95c635efSGarrett D'Amore (void) strlcpy(localedir, language, MAXPATHLEN); 228*95c635efSGarrett D'Amore 229*95c635efSGarrett D'Amore #if !defined(TEXT_DOMAIN) 230*95c635efSGarrett D'Amore #define TEXT_DOMAIN "SYS_TEST" 231*95c635efSGarrett D'Amore #endif 232*95c635efSGarrett D'Amore (void) textdomain(TEXT_DOMAIN); 233*95c635efSGarrett D'Amore 234*95c635efSGarrett D'Amore if (strcmp(__progname, "apropos") == 0) { 235*95c635efSGarrett D'Amore apropos++; 236*95c635efSGarrett D'Amore opts = "M:ds:"; 237*95c635efSGarrett D'Amore } else if (strcmp(__progname, "whatis") == 0) { 238*95c635efSGarrett D'Amore apropos++; 239*95c635efSGarrett D'Amore whatis++; 240*95c635efSGarrett D'Amore opts = "M:ds:"; 241*95c635efSGarrett D'Amore } else if (strcmp(__progname, "catman") == 0) { 242*95c635efSGarrett D'Amore catman++; 243*95c635efSGarrett D'Amore makewhatis++; 244*95c635efSGarrett D'Amore opts = "P:M:w"; 245*95c635efSGarrett D'Amore } else if (strcmp(__progname, "makewhatis") == 0) { 246*95c635efSGarrett D'Amore makewhatis++; 247*95c635efSGarrett D'Amore makewhatishere++; 248*95c635efSGarrett D'Amore manpath = "."; 249*95c635efSGarrett D'Amore opts = ""; 250*95c635efSGarrett D'Amore } else { 251*95c635efSGarrett D'Amore opts = "FM:P:T:adfklprs:tw"; 252*95c635efSGarrett D'Amore if (argc > 1 && strcmp(argv[1], "-") == 0) { 253*95c635efSGarrett D'Amore pager = "cat"; 254*95c635efSGarrett D'Amore optind++; 255*95c635efSGarrett D'Amore } 256*95c635efSGarrett D'Amore } 257*95c635efSGarrett D'Amore 258*95c635efSGarrett D'Amore opterr = 0; 259*95c635efSGarrett D'Amore while ((c = getopt(argc, argv, opts)) != -1) { 260*95c635efSGarrett D'Amore switch (c) { 261*95c635efSGarrett D'Amore case 'M': /* Respecify path for man pages */ 262*95c635efSGarrett D'Amore manpath = optarg; 263*95c635efSGarrett D'Amore break; 264*95c635efSGarrett D'Amore case 'a': 265*95c635efSGarrett D'Amore all++; 266*95c635efSGarrett D'Amore break; 267*95c635efSGarrett D'Amore case 'd': 268*95c635efSGarrett D'Amore debug++; 269*95c635efSGarrett D'Amore break; 270*95c635efSGarrett D'Amore case 'f': 271*95c635efSGarrett D'Amore whatis++; 272*95c635efSGarrett D'Amore /*FALLTHROUGH*/ 273*95c635efSGarrett D'Amore case 'k': 274*95c635efSGarrett D'Amore apropos++; 275*95c635efSGarrett D'Amore break; 276*95c635efSGarrett D'Amore case 'l': 277*95c635efSGarrett D'Amore list++; 278*95c635efSGarrett D'Amore all++; 279*95c635efSGarrett D'Amore break; 280*95c635efSGarrett D'Amore case 'p': 281*95c635efSGarrett D'Amore printmp++; 282*95c635efSGarrett D'Amore break; 283*95c635efSGarrett D'Amore case 's': 284*95c635efSGarrett D'Amore mansec = optarg; 285*95c635efSGarrett D'Amore sargs++; 286*95c635efSGarrett D'Amore break; 287*95c635efSGarrett D'Amore case 'r': 288*95c635efSGarrett D'Amore lintout++; 289*95c635efSGarrett D'Amore break; 290*95c635efSGarrett D'Amore case 't': 291*95c635efSGarrett D'Amore psoutput++; 292*95c635efSGarrett D'Amore break; 293*95c635efSGarrett D'Amore case 'T': 294*95c635efSGarrett D'Amore case 'P': 295*95c635efSGarrett D'Amore case 'F': 296*95c635efSGarrett D'Amore /* legacy options, compatibility only and ignored */ 297*95c635efSGarrett D'Amore break; 298*95c635efSGarrett D'Amore case 'w': 299*95c635efSGarrett D'Amore makewhatis++; 300*95c635efSGarrett D'Amore break; 301*95c635efSGarrett D'Amore case '?': 302*95c635efSGarrett D'Amore default: 303*95c635efSGarrett D'Amore if (apropos) 304*95c635efSGarrett D'Amore usage_whatapro(); 305*95c635efSGarrett D'Amore else if (catman) 306*95c635efSGarrett D'Amore usage_catman(); 307*95c635efSGarrett D'Amore else if (makewhatishere) 308*95c635efSGarrett D'Amore usage_makewhatis(); 309*95c635efSGarrett D'Amore else 310*95c635efSGarrett D'Amore usage_man(); 311*95c635efSGarrett D'Amore } 312*95c635efSGarrett D'Amore } 313*95c635efSGarrett D'Amore argc -= optind; 314*95c635efSGarrett D'Amore argv += optind; 315*95c635efSGarrett D'Amore 316*95c635efSGarrett D'Amore if (argc == 0) { 317*95c635efSGarrett D'Amore if (apropos) { 318*95c635efSGarrett D'Amore (void) fprintf(stderr, gettext("%s what?\n"), 319*95c635efSGarrett D'Amore __progname); 320*95c635efSGarrett D'Amore exit(1); 321*95c635efSGarrett D'Amore } else if (!printmp && !makewhatis) { 322*95c635efSGarrett D'Amore (void) fprintf(stderr, 323*95c635efSGarrett D'Amore gettext("What manual page do you want?\n")); 324*95c635efSGarrett D'Amore exit(1); 325*95c635efSGarrett D'Amore } 326*95c635efSGarrett D'Amore } 327*95c635efSGarrett D'Amore 328*95c635efSGarrett D'Amore init_bintoman(); 329*95c635efSGarrett D'Amore if (manpath == NULL && (manpath = getenv("MANPATH")) == NULL) { 330*95c635efSGarrett D'Amore if ((manpath = getenv("PATH")) != NULL) 331*95c635efSGarrett D'Amore bmp_flags = BMP_ISPATH | BMP_APPEND_DEFMANDIR; 332*95c635efSGarrett D'Amore else 333*95c635efSGarrett D'Amore manpath = DEFMANDIR; 334*95c635efSGarrett D'Amore } 335*95c635efSGarrett D'Amore pathv = split(manpath, ':'); 336*95c635efSGarrett D'Amore mandirs = build_manpath(pathv, bmp_flags); 337*95c635efSGarrett D'Amore freev(pathv); 338*95c635efSGarrett D'Amore fullpaths(&mandirs); 339*95c635efSGarrett D'Amore 340*95c635efSGarrett D'Amore if (makewhatis) { 341*95c635efSGarrett D'Amore do_makewhatis(mandirs); 342*95c635efSGarrett D'Amore exit(0); 343*95c635efSGarrett D'Amore } 344*95c635efSGarrett D'Amore 345*95c635efSGarrett D'Amore if (printmp) { 346*95c635efSGarrett D'Amore print_manpath(mandirs); 347*95c635efSGarrett D'Amore exit(0); 348*95c635efSGarrett D'Amore } 349*95c635efSGarrett D'Amore 350*95c635efSGarrett D'Amore /* Collect environment information */ 351*95c635efSGarrett D'Amore if (isatty(STDOUT_FILENO) && (mwstr = getenv("MANWIDTH")) != NULL && 352*95c635efSGarrett D'Amore *mwstr != '\0') { 353*95c635efSGarrett D'Amore if (strcasecmp(mwstr, "tty") == 0) { 354*95c635efSGarrett D'Amore struct winsize ws; 355*95c635efSGarrett D'Amore 356*95c635efSGarrett D'Amore if (ioctl(0, TIOCGWINSZ, &ws) != 0) 357*95c635efSGarrett D'Amore warn("TIOCGWINSZ"); 358*95c635efSGarrett D'Amore else 359*95c635efSGarrett D'Amore manwidth = ws.ws_col; 360*95c635efSGarrett D'Amore } else { 361*95c635efSGarrett D'Amore manwidth = (int)strtol(mwstr, (char **)NULL, 10); 362*95c635efSGarrett D'Amore if (manwidth < 0) 363*95c635efSGarrett D'Amore manwidth = 0; 364*95c635efSGarrett D'Amore } 365*95c635efSGarrett D'Amore } 366*95c635efSGarrett D'Amore if (manwidth != 0) { 367*95c635efSGarrett D'Amore DPRINTF("-- Using non-standard page width: %d\n", manwidth); 368*95c635efSGarrett D'Amore } 369*95c635efSGarrett D'Amore 370*95c635efSGarrett D'Amore if (pager == NULL) { 371*95c635efSGarrett D'Amore if ((pager = getenv("PAGER")) == NULL || *pager == '\0') 372*95c635efSGarrett D'Amore pager = PAGER; 373*95c635efSGarrett D'Amore } 374*95c635efSGarrett D'Amore DPRINTF("-- Using pager: %s\n", pager); 375*95c635efSGarrett D'Amore 376*95c635efSGarrett D'Amore for (i = 0; i < argc; i++) { 377*95c635efSGarrett D'Amore char *cmd; 378*95c635efSGarrett D'Amore static struct man_node *mp; 379*95c635efSGarrett D'Amore char *pv[2]; 380*95c635efSGarrett D'Amore 381*95c635efSGarrett D'Amore /* 382*95c635efSGarrett D'Amore * If full path to command specified, customize 383*95c635efSGarrett D'Amore * the manpath accordingly. 384*95c635efSGarrett D'Amore */ 385*95c635efSGarrett D'Amore if ((cmd = strrchr(argv[i], '/')) != NULL) { 386*95c635efSGarrett D'Amore *cmd = '\0'; 387*95c635efSGarrett D'Amore if ((pv[0] = strdup(argv[i])) == NULL) 388*95c635efSGarrett D'Amore err(1, "strdup"); 389*95c635efSGarrett D'Amore pv[1] = NULL; 390*95c635efSGarrett D'Amore *cmd = '/'; 391*95c635efSGarrett D'Amore mp = build_manpath(pv, 392*95c635efSGarrett D'Amore BMP_ISPATH | BMP_FALLBACK_DEFMANDIR); 393*95c635efSGarrett D'Amore } else { 394*95c635efSGarrett D'Amore mp = mandirs; 395*95c635efSGarrett D'Amore } 396*95c635efSGarrett D'Amore 397*95c635efSGarrett D'Amore if (apropos) 398*95c635efSGarrett D'Amore whatapro(mp, argv[i]); 399*95c635efSGarrett D'Amore else 400*95c635efSGarrett D'Amore ret += manual(mp, argv[i]); 401*95c635efSGarrett D'Amore 402*95c635efSGarrett D'Amore if (mp != NULL && mp != mandirs) { 403*95c635efSGarrett D'Amore free(pv[0]); 404*95c635efSGarrett D'Amore free_manp(mp); 405*95c635efSGarrett D'Amore } 406*95c635efSGarrett D'Amore } 407*95c635efSGarrett D'Amore 408*95c635efSGarrett D'Amore return (ret == 0 ? 0 : 1); 409*95c635efSGarrett D'Amore } 410*95c635efSGarrett D'Amore 411*95c635efSGarrett D'Amore /* 412*95c635efSGarrett D'Amore * This routine builds the manpage structure from MANPATH or PATH, 413*95c635efSGarrett D'Amore * depending on flags. See BMP_* definitions above for valid 414*95c635efSGarrett D'Amore * flags. 415*95c635efSGarrett D'Amore */ 416*95c635efSGarrett D'Amore static struct man_node * 417*95c635efSGarrett D'Amore build_manpath(char **pathv, int flags) 418*95c635efSGarrett D'Amore { 419*95c635efSGarrett D'Amore struct man_node *manpage = NULL; 420*95c635efSGarrett D'Amore struct man_node *currp = NULL; 421*95c635efSGarrett D'Amore struct man_node *lastp = NULL; 422*95c635efSGarrett D'Amore char **p; 423*95c635efSGarrett D'Amore char **q; 424*95c635efSGarrett D'Amore char *mand = NULL; 425*95c635efSGarrett D'Amore char *mandir = DEFMANDIR; 426*95c635efSGarrett D'Amore int s; 427*95c635efSGarrett D'Amore struct dupnode *didup = NULL; 428*95c635efSGarrett D'Amore struct stat sb; 429*95c635efSGarrett D'Amore 430*95c635efSGarrett D'Amore s = sizeof (struct man_node); 431*95c635efSGarrett D'Amore for (p = pathv; *p != NULL; ) { 432*95c635efSGarrett D'Amore if (flags & BMP_ISPATH) { 433*95c635efSGarrett D'Amore if ((mand = path_to_manpath(*p)) == NULL) 434*95c635efSGarrett D'Amore goto next; 435*95c635efSGarrett D'Amore free(*p); 436*95c635efSGarrett D'Amore *p = mand; 437*95c635efSGarrett D'Amore } 438*95c635efSGarrett D'Amore q = split(*p, ','); 439*95c635efSGarrett D'Amore if (stat(q[0], &sb) != 0 || (sb.st_mode & S_IFDIR) == 0) { 440*95c635efSGarrett D'Amore freev(q); 441*95c635efSGarrett D'Amore goto next; 442*95c635efSGarrett D'Amore } 443*95c635efSGarrett D'Amore 444*95c635efSGarrett D'Amore if (access(q[0], R_OK | X_OK) == 0) { 445*95c635efSGarrett D'Amore /* 446*95c635efSGarrett D'Amore * Some element exists. Do not append DEFMANDIR as a 447*95c635efSGarrett D'Amore * fallback. 448*95c635efSGarrett D'Amore */ 449*95c635efSGarrett D'Amore flags &= ~BMP_FALLBACK_DEFMANDIR; 450*95c635efSGarrett D'Amore 451*95c635efSGarrett D'Amore if ((currp = (struct man_node *)calloc(1, s)) == NULL) 452*95c635efSGarrett D'Amore err(1, "calloc"); 453*95c635efSGarrett D'Amore 454*95c635efSGarrett D'Amore currp->frompath = (flags & BMP_ISPATH); 455*95c635efSGarrett D'Amore 456*95c635efSGarrett D'Amore if (manpage == NULL) 457*95c635efSGarrett D'Amore lastp = manpage = currp; 458*95c635efSGarrett D'Amore 459*95c635efSGarrett D'Amore getpath(currp, p); 460*95c635efSGarrett D'Amore getsect(currp, p); 461*95c635efSGarrett D'Amore 462*95c635efSGarrett D'Amore /* 463*95c635efSGarrett D'Amore * If there are no new elements in this path, 464*95c635efSGarrett D'Amore * do not add it to the manpage list. 465*95c635efSGarrett D'Amore */ 466*95c635efSGarrett D'Amore if (dupcheck(currp, &didup) != 0) { 467*95c635efSGarrett D'Amore freev(currp->secv); 468*95c635efSGarrett D'Amore free(currp); 469*95c635efSGarrett D'Amore } else { 470*95c635efSGarrett D'Amore currp->next = NULL; 471*95c635efSGarrett D'Amore if (currp != manpage) 472*95c635efSGarrett D'Amore lastp->next = currp; 473*95c635efSGarrett D'Amore lastp = currp; 474*95c635efSGarrett D'Amore } 475*95c635efSGarrett D'Amore } 476*95c635efSGarrett D'Amore freev(q); 477*95c635efSGarrett D'Amore next: 478*95c635efSGarrett D'Amore /* 479*95c635efSGarrett D'Amore * Special handling of appending DEFMANDIR. After all pathv 480*95c635efSGarrett D'Amore * elements have been processed, append DEFMANDIR if needed. 481*95c635efSGarrett D'Amore */ 482*95c635efSGarrett D'Amore if (p == &mandir) 483*95c635efSGarrett D'Amore break; 484*95c635efSGarrett D'Amore p++; 485*95c635efSGarrett D'Amore if (*p != NULL) 486*95c635efSGarrett D'Amore continue; 487*95c635efSGarrett D'Amore if (flags & (BMP_APPEND_DEFMANDIR | BMP_FALLBACK_DEFMANDIR)) { 488*95c635efSGarrett D'Amore p = &mandir; 489*95c635efSGarrett D'Amore flags &= ~BMP_ISPATH; 490*95c635efSGarrett D'Amore } 491*95c635efSGarrett D'Amore } 492*95c635efSGarrett D'Amore 493*95c635efSGarrett D'Amore free_dupnode(didup); 494*95c635efSGarrett D'Amore 495*95c635efSGarrett D'Amore return (manpage); 496*95c635efSGarrett D'Amore } 497*95c635efSGarrett D'Amore 498*95c635efSGarrett D'Amore /* 499*95c635efSGarrett D'Amore * Store the mandir path into the manp structure. 500*95c635efSGarrett D'Amore */ 501*95c635efSGarrett D'Amore static void 502*95c635efSGarrett D'Amore getpath(struct man_node *manp, char **pv) 503*95c635efSGarrett D'Amore { 504*95c635efSGarrett D'Amore char *s = *pv; 505*95c635efSGarrett D'Amore int i = 0; 506*95c635efSGarrett D'Amore 507*95c635efSGarrett D'Amore while (*s != '\0' && *s != ',') 508*95c635efSGarrett D'Amore i++, s++; 509*95c635efSGarrett D'Amore 510*95c635efSGarrett D'Amore if ((manp->path = (char *)malloc(i + 1)) == NULL) 511*95c635efSGarrett D'Amore err(1, "malloc"); 512*95c635efSGarrett D'Amore (void) strlcpy(manp->path, *pv, i + 1); 513*95c635efSGarrett D'Amore } 514*95c635efSGarrett D'Amore 515*95c635efSGarrett D'Amore /* 516*95c635efSGarrett D'Amore * Store the mandir's corresponding sections (submandir 517*95c635efSGarrett D'Amore * directories) into the manp structure. 518*95c635efSGarrett D'Amore */ 519*95c635efSGarrett D'Amore static void 520*95c635efSGarrett D'Amore getsect(struct man_node *manp, char **pv) 521*95c635efSGarrett D'Amore { 522*95c635efSGarrett D'Amore char *sections; 523*95c635efSGarrett D'Amore char **sectp; 524*95c635efSGarrett D'Amore 525*95c635efSGarrett D'Amore /* Just store all sections when doing makewhatis or apropos/whatis */ 526*95c635efSGarrett D'Amore if (makewhatis || apropos) { 527*95c635efSGarrett D'Amore manp->defsrch = 1; 528*95c635efSGarrett D'Amore DPRINTF("-- Adding %s\n", manp->path); 529*95c635efSGarrett D'Amore manp->secv = NULL; 530*95c635efSGarrett D'Amore get_all_sect(manp); 531*95c635efSGarrett D'Amore } else if (sargs) { 532*95c635efSGarrett D'Amore manp->secv = split(mansec, ','); 533*95c635efSGarrett D'Amore for (sectp = manp->secv; *sectp; sectp++) 534*95c635efSGarrett D'Amore lower(*sectp); 535*95c635efSGarrett D'Amore } else if ((sections = strchr(*pv, ',')) != NULL) { 536*95c635efSGarrett D'Amore DPRINTF("-- Adding %s: MANSECTS=%s\n", manp->path, sections); 537*95c635efSGarrett D'Amore manp->secv = split(++sections, ','); 538*95c635efSGarrett D'Amore for (sectp = manp->secv; *sectp; sectp++) 539*95c635efSGarrett D'Amore lower(*sectp); 540*95c635efSGarrett D'Amore if (*manp->secv == NULL) 541*95c635efSGarrett D'Amore get_all_sect(manp); 542*95c635efSGarrett D'Amore } else if ((sections = check_config(*pv)) != NULL) { 543*95c635efSGarrett D'Amore manp->defsrch = 1; 544*95c635efSGarrett D'Amore DPRINTF("-- Adding %s: from %s, MANSECTS=%s\n", manp->path, 545*95c635efSGarrett D'Amore CONFIG, sections); 546*95c635efSGarrett D'Amore manp->secv = split(sections, ','); 547*95c635efSGarrett D'Amore for (sectp = manp->secv; *sectp; sectp++) 548*95c635efSGarrett D'Amore lower(*sectp); 549*95c635efSGarrett D'Amore if (*manp->secv == NULL) 550*95c635efSGarrett D'Amore get_all_sect(manp); 551*95c635efSGarrett D'Amore } else { 552*95c635efSGarrett D'Amore manp->defsrch = 1; 553*95c635efSGarrett D'Amore DPRINTF("-- Adding %s: default sort order\n", manp->path); 554*95c635efSGarrett D'Amore manp->secv = NULL; 555*95c635efSGarrett D'Amore get_all_sect(manp); 556*95c635efSGarrett D'Amore } 557*95c635efSGarrett D'Amore } 558*95c635efSGarrett D'Amore 559*95c635efSGarrett D'Amore /* 560*95c635efSGarrett D'Amore * Get suffices of all sub-mandir directories in a mandir. 561*95c635efSGarrett D'Amore */ 562*95c635efSGarrett D'Amore static void 563*95c635efSGarrett D'Amore get_all_sect(struct man_node *manp) 564*95c635efSGarrett D'Amore { 565*95c635efSGarrett D'Amore DIR *dp; 566*95c635efSGarrett D'Amore char **dirv; 567*95c635efSGarrett D'Amore char **dv; 568*95c635efSGarrett D'Amore char **p; 569*95c635efSGarrett D'Amore char *prev = NULL; 570*95c635efSGarrett D'Amore char *tmp = NULL; 571*95c635efSGarrett D'Amore int maxentries = MAXTOKENS; 572*95c635efSGarrett D'Amore int entries = 0; 573*95c635efSGarrett D'Amore 574*95c635efSGarrett D'Amore if ((dp = opendir(manp->path)) == 0) 575*95c635efSGarrett D'Amore return; 576*95c635efSGarrett D'Amore 577*95c635efSGarrett D'Amore sortdir(dp, &dirv); 578*95c635efSGarrett D'Amore 579*95c635efSGarrett D'Amore (void) closedir(dp); 580*95c635efSGarrett D'Amore 581*95c635efSGarrett D'Amore if (manp->secv == NULL) { 582*95c635efSGarrett D'Amore if ((manp->secv = malloc(maxentries * sizeof (char *))) == NULL) 583*95c635efSGarrett D'Amore err(1, "malloc"); 584*95c635efSGarrett D'Amore } 585*95c635efSGarrett D'Amore 586*95c635efSGarrett D'Amore for (dv = dirv, p = manp->secv; *dv; dv++) { 587*95c635efSGarrett D'Amore if (strcmp(*dv, CONFIG) == 0) { 588*95c635efSGarrett D'Amore free(*dv); 589*95c635efSGarrett D'Amore continue; 590*95c635efSGarrett D'Amore } 591*95c635efSGarrett D'Amore 592*95c635efSGarrett D'Amore free(tmp); 593*95c635efSGarrett D'Amore if ((tmp = strdup(*dv + 3)) == NULL) 594*95c635efSGarrett D'Amore err(1, "strdup"); 595*95c635efSGarrett D'Amore 596*95c635efSGarrett D'Amore if (prev != NULL && strcmp(prev, tmp) == 0) { 597*95c635efSGarrett D'Amore free(*dv); 598*95c635efSGarrett D'Amore continue; 599*95c635efSGarrett D'Amore } 600*95c635efSGarrett D'Amore 601*95c635efSGarrett D'Amore free(prev); 602*95c635efSGarrett D'Amore if ((prev = strdup(*dv + 3)) == NULL) 603*95c635efSGarrett D'Amore err(1, "strdup"); 604*95c635efSGarrett D'Amore 605*95c635efSGarrett D'Amore if ((*p = strdup(*dv + 3)) == NULL) 606*95c635efSGarrett D'Amore err(1, "strdup"); 607*95c635efSGarrett D'Amore 608*95c635efSGarrett D'Amore p++; entries++; 609*95c635efSGarrett D'Amore 610*95c635efSGarrett D'Amore if (entries == maxentries) { 611*95c635efSGarrett D'Amore maxentries += MAXTOKENS; 612*95c635efSGarrett D'Amore if ((manp->secv = realloc(manp->secv, 613*95c635efSGarrett D'Amore sizeof (char *) * maxentries)) == NULL) 614*95c635efSGarrett D'Amore err(1, "realloc"); 615*95c635efSGarrett D'Amore p = manp->secv + entries; 616*95c635efSGarrett D'Amore } 617*95c635efSGarrett D'Amore free(*dv); 618*95c635efSGarrett D'Amore } 619*95c635efSGarrett D'Amore free(tmp); 620*95c635efSGarrett D'Amore free(prev); 621*95c635efSGarrett D'Amore *p = NULL; 622*95c635efSGarrett D'Amore free(dirv); 623*95c635efSGarrett D'Amore } 624*95c635efSGarrett D'Amore 625*95c635efSGarrett D'Amore /* 626*95c635efSGarrett D'Amore * Build whatis databases. 627*95c635efSGarrett D'Amore */ 628*95c635efSGarrett D'Amore static void 629*95c635efSGarrett D'Amore do_makewhatis(struct man_node *manp) 630*95c635efSGarrett D'Amore { 631*95c635efSGarrett D'Amore struct man_node *p; 632*95c635efSGarrett D'Amore char *ldir; 633*95c635efSGarrett D'Amore 634*95c635efSGarrett D'Amore for (p = manp; p != NULL; p = p->next) { 635*95c635efSGarrett D'Amore ldir = addlocale(p->path); 636*95c635efSGarrett D'Amore if (*localedir != '\0' && getdirs(ldir, NULL, 0) > 0) 637*95c635efSGarrett D'Amore mwpath(ldir); 638*95c635efSGarrett D'Amore free(ldir); 639*95c635efSGarrett D'Amore mwpath(p->path); 640*95c635efSGarrett D'Amore } 641*95c635efSGarrett D'Amore } 642*95c635efSGarrett D'Amore 643*95c635efSGarrett D'Amore /* 644*95c635efSGarrett D'Amore * Count mandirs under the given manpath 645*95c635efSGarrett D'Amore */ 646*95c635efSGarrett D'Amore static int 647*95c635efSGarrett D'Amore getdirs(char *path, char ***dirv, int flag) 648*95c635efSGarrett D'Amore { 649*95c635efSGarrett D'Amore DIR *dp; 650*95c635efSGarrett D'Amore struct dirent *d; 651*95c635efSGarrett D'Amore int n = 0; 652*95c635efSGarrett D'Amore int maxentries = MAXDIRS; 653*95c635efSGarrett D'Amore char **dv = NULL; 654*95c635efSGarrett D'Amore 655*95c635efSGarrett D'Amore if ((dp = opendir(path)) == NULL) 656*95c635efSGarrett D'Amore return (0); 657*95c635efSGarrett D'Amore 658*95c635efSGarrett D'Amore if (flag) { 659*95c635efSGarrett D'Amore if ((*dirv = malloc(sizeof (char *) * 660*95c635efSGarrett D'Amore maxentries)) == NULL) 661*95c635efSGarrett D'Amore err(1, "malloc"); 662*95c635efSGarrett D'Amore dv = *dirv; 663*95c635efSGarrett D'Amore } 664*95c635efSGarrett D'Amore while ((d = readdir(dp))) { 665*95c635efSGarrett D'Amore if (strncmp(d->d_name, "man", 3) != 0) 666*95c635efSGarrett D'Amore continue; 667*95c635efSGarrett D'Amore n++; 668*95c635efSGarrett D'Amore 669*95c635efSGarrett D'Amore if (flag) { 670*95c635efSGarrett D'Amore if ((*dv = strdup(d->d_name + 3)) == NULL) 671*95c635efSGarrett D'Amore err(1, "strdup"); 672*95c635efSGarrett D'Amore dv++; 673*95c635efSGarrett D'Amore if ((dv - *dirv) == maxentries) { 674*95c635efSGarrett D'Amore int entries = maxentries; 675*95c635efSGarrett D'Amore 676*95c635efSGarrett D'Amore maxentries += MAXTOKENS; 677*95c635efSGarrett D'Amore if ((*dirv = realloc(*dirv, 678*95c635efSGarrett D'Amore sizeof (char *) * maxentries)) == NULL) 679*95c635efSGarrett D'Amore err(1, "realloc"); 680*95c635efSGarrett D'Amore dv = *dirv + entries; 681*95c635efSGarrett D'Amore } 682*95c635efSGarrett D'Amore } 683*95c635efSGarrett D'Amore } 684*95c635efSGarrett D'Amore 685*95c635efSGarrett D'Amore (void) closedir(dp); 686*95c635efSGarrett D'Amore return (n); 687*95c635efSGarrett D'Amore } 688*95c635efSGarrett D'Amore 689*95c635efSGarrett D'Amore 690*95c635efSGarrett D'Amore /* 691*95c635efSGarrett D'Amore * Find matching whatis or apropos entries. 692*95c635efSGarrett D'Amore */ 693*95c635efSGarrett D'Amore static void 694*95c635efSGarrett D'Amore whatapro(struct man_node *manp, char *word) 695*95c635efSGarrett D'Amore { 696*95c635efSGarrett D'Amore char whatpath[MAXPATHLEN]; 697*95c635efSGarrett D'Amore struct man_node *b; 698*95c635efSGarrett D'Amore char *ldir; 699*95c635efSGarrett D'Amore 700*95c635efSGarrett D'Amore for (b = manp; b != NULL; b = b->next) { 701*95c635efSGarrett D'Amore if (*localedir != '\0') { 702*95c635efSGarrett D'Amore ldir = addlocale(b->path); 703*95c635efSGarrett D'Amore if (getdirs(ldir, NULL, 0) != 0) { 704*95c635efSGarrett D'Amore (void) snprintf(whatpath, sizeof (whatpath), 705*95c635efSGarrett D'Amore "%s/%s", ldir, WHATIS); 706*95c635efSGarrett D'Amore search_whatis(whatpath, word); 707*95c635efSGarrett D'Amore } 708*95c635efSGarrett D'Amore free(ldir); 709*95c635efSGarrett D'Amore } 710*95c635efSGarrett D'Amore (void) snprintf(whatpath, sizeof (whatpath), "%s/%s", b->path, 711*95c635efSGarrett D'Amore WHATIS); 712*95c635efSGarrett D'Amore search_whatis(whatpath, word); 713*95c635efSGarrett D'Amore } 714*95c635efSGarrett D'Amore } 715*95c635efSGarrett D'Amore 716*95c635efSGarrett D'Amore static void 717*95c635efSGarrett D'Amore search_whatis(char *whatpath, char *word) 718*95c635efSGarrett D'Amore { 719*95c635efSGarrett D'Amore FILE *fp; 720*95c635efSGarrett D'Amore char *line = NULL; 721*95c635efSGarrett D'Amore size_t linecap = 0; 722*95c635efSGarrett D'Amore char *pkwd; 723*95c635efSGarrett D'Amore regex_t preg; 724*95c635efSGarrett D'Amore char **ss = NULL; 725*95c635efSGarrett D'Amore char s[MAXNAMELEN]; 726*95c635efSGarrett D'Amore int i; 727*95c635efSGarrett D'Amore 728*95c635efSGarrett D'Amore if ((fp = fopen(whatpath, "r")) == NULL) { 729*95c635efSGarrett D'Amore perror(whatpath); 730*95c635efSGarrett D'Amore return; 731*95c635efSGarrett D'Amore } 732*95c635efSGarrett D'Amore 733*95c635efSGarrett D'Amore DPRINTF("-- Found %s: %s\n", WHATIS, whatpath); 734*95c635efSGarrett D'Amore 735*95c635efSGarrett D'Amore /* Build keyword regex */ 736*95c635efSGarrett D'Amore if (asprintf(&pkwd, "%s%s%s", (whatis) ? "\\<" : "", 737*95c635efSGarrett D'Amore word, (whatis) ? "\\>" : "") == -1) 738*95c635efSGarrett D'Amore err(1, "asprintf"); 739*95c635efSGarrett D'Amore 740*95c635efSGarrett D'Amore if (regcomp(&preg, pkwd, REG_BASIC | REG_ICASE | REG_NOSUB) != 0) 741*95c635efSGarrett D'Amore err(1, "regcomp"); 742*95c635efSGarrett D'Amore 743*95c635efSGarrett D'Amore if (sargs) 744*95c635efSGarrett D'Amore ss = split(mansec, ','); 745*95c635efSGarrett D'Amore 746*95c635efSGarrett D'Amore while (getline(&line, &linecap, fp) > 0) { 747*95c635efSGarrett D'Amore if (regexec(&preg, line, 0, NULL, 0) == 0) { 748*95c635efSGarrett D'Amore if (sargs) { 749*95c635efSGarrett D'Amore /* Section-restricted search */ 750*95c635efSGarrett D'Amore for (i = 0; ss[i] != NULL; i++) { 751*95c635efSGarrett D'Amore (void) snprintf(s, sizeof (s), "(%s)", 752*95c635efSGarrett D'Amore ss[i]); 753*95c635efSGarrett D'Amore if (strstr(line, s) != NULL) { 754*95c635efSGarrett D'Amore (void) printf("%s", line); 755*95c635efSGarrett D'Amore break; 756*95c635efSGarrett D'Amore } 757*95c635efSGarrett D'Amore } 758*95c635efSGarrett D'Amore } else { 759*95c635efSGarrett D'Amore (void) printf("%s", line); 760*95c635efSGarrett D'Amore } 761*95c635efSGarrett D'Amore } 762*95c635efSGarrett D'Amore } 763*95c635efSGarrett D'Amore 764*95c635efSGarrett D'Amore if (ss != NULL) 765*95c635efSGarrett D'Amore freev(ss); 766*95c635efSGarrett D'Amore free(pkwd); 767*95c635efSGarrett D'Amore (void) fclose(fp); 768*95c635efSGarrett D'Amore } 769*95c635efSGarrett D'Amore 770*95c635efSGarrett D'Amore 771*95c635efSGarrett D'Amore /* 772*95c635efSGarrett D'Amore * Split a string by specified separator. 773*95c635efSGarrett D'Amore */ 774*95c635efSGarrett D'Amore static char ** 775*95c635efSGarrett D'Amore split(char *s1, char sep) 776*95c635efSGarrett D'Amore { 777*95c635efSGarrett D'Amore char **tokv, **vp; 778*95c635efSGarrett D'Amore char *mp = s1, *tp; 779*95c635efSGarrett D'Amore int maxentries = MAXTOKENS; 780*95c635efSGarrett D'Amore int entries = 0; 781*95c635efSGarrett D'Amore 782*95c635efSGarrett D'Amore if ((tokv = vp = malloc(maxentries * sizeof (char *))) == NULL) 783*95c635efSGarrett D'Amore err(1, "malloc"); 784*95c635efSGarrett D'Amore 785*95c635efSGarrett D'Amore for (; mp && *mp; mp = tp) { 786*95c635efSGarrett D'Amore tp = strchr(mp, sep); 787*95c635efSGarrett D'Amore if (mp == tp) { 788*95c635efSGarrett D'Amore tp++; 789*95c635efSGarrett D'Amore continue; 790*95c635efSGarrett D'Amore } 791*95c635efSGarrett D'Amore if (tp) { 792*95c635efSGarrett D'Amore size_t len; 793*95c635efSGarrett D'Amore 794*95c635efSGarrett D'Amore len = tp - mp; 795*95c635efSGarrett D'Amore if ((*vp = (char *)malloc(sizeof (char) * 796*95c635efSGarrett D'Amore len + 1)) == NULL) 797*95c635efSGarrett D'Amore err(1, "malloc"); 798*95c635efSGarrett D'Amore (void) strncpy(*vp, mp, len); 799*95c635efSGarrett D'Amore *(*vp + len) = '\0'; 800*95c635efSGarrett D'Amore tp++; 801*95c635efSGarrett D'Amore vp++; 802*95c635efSGarrett D'Amore } else { 803*95c635efSGarrett D'Amore if ((*vp = strdup(mp)) == NULL) 804*95c635efSGarrett D'Amore err(1, "strdup"); 805*95c635efSGarrett D'Amore vp++; 806*95c635efSGarrett D'Amore } 807*95c635efSGarrett D'Amore entries++; 808*95c635efSGarrett D'Amore if (entries == maxentries) { 809*95c635efSGarrett D'Amore maxentries += MAXTOKENS; 810*95c635efSGarrett D'Amore if ((tokv = realloc(tokv, 811*95c635efSGarrett D'Amore maxentries * sizeof (char *))) == NULL) 812*95c635efSGarrett D'Amore err(1, "realloc"); 813*95c635efSGarrett D'Amore vp = tokv + entries; 814*95c635efSGarrett D'Amore } 815*95c635efSGarrett D'Amore } 816*95c635efSGarrett D'Amore *vp = 0; 817*95c635efSGarrett D'Amore 818*95c635efSGarrett D'Amore return (tokv); 819*95c635efSGarrett D'Amore } 820*95c635efSGarrett D'Amore 821*95c635efSGarrett D'Amore /* 822*95c635efSGarrett D'Amore * Free a vector allocated by split() 823*95c635efSGarrett D'Amore */ 824*95c635efSGarrett D'Amore static void 825*95c635efSGarrett D'Amore freev(char **v) 826*95c635efSGarrett D'Amore { 827*95c635efSGarrett D'Amore int i; 828*95c635efSGarrett D'Amore if (v != NULL) { 829*95c635efSGarrett D'Amore for (i = 0; v[i] != NULL; i++) { 830*95c635efSGarrett D'Amore free(v[i]); 831*95c635efSGarrett D'Amore } 832*95c635efSGarrett D'Amore free(v); 833*95c635efSGarrett D'Amore } 834*95c635efSGarrett D'Amore } 835*95c635efSGarrett D'Amore 836*95c635efSGarrett D'Amore /* 837*95c635efSGarrett D'Amore * Convert paths to full paths if necessary 838*95c635efSGarrett D'Amore */ 839*95c635efSGarrett D'Amore static void 840*95c635efSGarrett D'Amore fullpaths(struct man_node **manp_head) 841*95c635efSGarrett D'Amore { 842*95c635efSGarrett D'Amore char *cwd = NULL; 843*95c635efSGarrett D'Amore char *p; 844*95c635efSGarrett D'Amore int cwd_gotten = 0; 845*95c635efSGarrett D'Amore struct man_node *manp = *manp_head; 846*95c635efSGarrett D'Amore struct man_node *b; 847*95c635efSGarrett D'Amore struct man_node *prev = NULL; 848*95c635efSGarrett D'Amore 849*95c635efSGarrett D'Amore for (b = manp; b != NULL; b = b->next) { 850*95c635efSGarrett D'Amore if (*(b->path) == '/') { 851*95c635efSGarrett D'Amore prev = b; 852*95c635efSGarrett D'Amore continue; 853*95c635efSGarrett D'Amore } 854*95c635efSGarrett D'Amore 855*95c635efSGarrett D'Amore if (!cwd_gotten) { 856*95c635efSGarrett D'Amore cwd = getcwd(NULL, MAXPATHLEN); 857*95c635efSGarrett D'Amore cwd_gotten = 1; 858*95c635efSGarrett D'Amore } 859*95c635efSGarrett D'Amore 860*95c635efSGarrett D'Amore if (cwd) { 861*95c635efSGarrett D'Amore /* Relative manpath with cwd: make absolute */ 862*95c635efSGarrett D'Amore if (asprintf(&p, "%s/%s", cwd, b->path) == -1) 863*95c635efSGarrett D'Amore err(1, "asprintf"); 864*95c635efSGarrett D'Amore free(b->path); 865*95c635efSGarrett D'Amore b->path = p; 866*95c635efSGarrett D'Amore } else { 867*95c635efSGarrett D'Amore /* Relative manpath but no cwd: omit path entry */ 868*95c635efSGarrett D'Amore if (prev) 869*95c635efSGarrett D'Amore prev->next = b->next; 870*95c635efSGarrett D'Amore else 871*95c635efSGarrett D'Amore *manp_head = b->next; 872*95c635efSGarrett D'Amore 873*95c635efSGarrett D'Amore free_manp(b); 874*95c635efSGarrett D'Amore } 875*95c635efSGarrett D'Amore } 876*95c635efSGarrett D'Amore free(cwd); 877*95c635efSGarrett D'Amore } 878*95c635efSGarrett D'Amore 879*95c635efSGarrett D'Amore /* 880*95c635efSGarrett D'Amore * Free a man_node structure and its contents 881*95c635efSGarrett D'Amore */ 882*95c635efSGarrett D'Amore static void 883*95c635efSGarrett D'Amore free_manp(struct man_node *manp) 884*95c635efSGarrett D'Amore { 885*95c635efSGarrett D'Amore char **p; 886*95c635efSGarrett D'Amore 887*95c635efSGarrett D'Amore free(manp->path); 888*95c635efSGarrett D'Amore p = manp->secv; 889*95c635efSGarrett D'Amore while ((p != NULL) && (*p != NULL)) { 890*95c635efSGarrett D'Amore free(*p); 891*95c635efSGarrett D'Amore p++; 892*95c635efSGarrett D'Amore } 893*95c635efSGarrett D'Amore free(manp->secv); 894*95c635efSGarrett D'Amore free(manp); 895*95c635efSGarrett D'Amore } 896*95c635efSGarrett D'Amore 897*95c635efSGarrett D'Amore 898*95c635efSGarrett D'Amore /* 899*95c635efSGarrett D'Amore * Map (in place) to lower case. 900*95c635efSGarrett D'Amore */ 901*95c635efSGarrett D'Amore static void 902*95c635efSGarrett D'Amore lower(char *s) 903*95c635efSGarrett D'Amore { 904*95c635efSGarrett D'Amore 905*95c635efSGarrett D'Amore if (s == 0) 906*95c635efSGarrett D'Amore return; 907*95c635efSGarrett D'Amore while (*s) { 908*95c635efSGarrett D'Amore if (isupper(*s)) 909*95c635efSGarrett D'Amore *s = tolower(*s); 910*95c635efSGarrett D'Amore s++; 911*95c635efSGarrett D'Amore } 912*95c635efSGarrett D'Amore } 913*95c635efSGarrett D'Amore 914*95c635efSGarrett D'Amore 915*95c635efSGarrett D'Amore /* 916*95c635efSGarrett D'Amore * Compare function for qsort(). 917*95c635efSGarrett D'Amore * Sort first by section, then by prefix. 918*95c635efSGarrett D'Amore */ 919*95c635efSGarrett D'Amore static int 920*95c635efSGarrett D'Amore cmp(const void *arg1, const void *arg2) 921*95c635efSGarrett D'Amore { 922*95c635efSGarrett D'Amore int n; 923*95c635efSGarrett D'Amore char **p1 = (char **)arg1; 924*95c635efSGarrett D'Amore char **p2 = (char **)arg2; 925*95c635efSGarrett D'Amore 926*95c635efSGarrett D'Amore /* By section */ 927*95c635efSGarrett D'Amore if ((n = strcmp(*p1 + 3, *p2 + 3)) != 0) 928*95c635efSGarrett D'Amore return (n); 929*95c635efSGarrett D'Amore 930*95c635efSGarrett D'Amore /* By prefix reversed */ 931*95c635efSGarrett D'Amore return (strncmp(*p2, *p1, 3)); 932*95c635efSGarrett D'Amore } 933*95c635efSGarrett D'Amore 934*95c635efSGarrett D'Amore 935*95c635efSGarrett D'Amore /* 936*95c635efSGarrett D'Amore * Find a manpage. 937*95c635efSGarrett D'Amore */ 938*95c635efSGarrett D'Amore static int 939*95c635efSGarrett D'Amore manual(struct man_node *manp, char *name) 940*95c635efSGarrett D'Amore { 941*95c635efSGarrett D'Amore struct man_node *p; 942*95c635efSGarrett D'Amore struct man_node *local; 943*95c635efSGarrett D'Amore int ndirs = 0; 944*95c635efSGarrett D'Amore char *ldir; 945*95c635efSGarrett D'Amore char *ldirs[2]; 946*95c635efSGarrett D'Amore char *fullname = name; 947*95c635efSGarrett D'Amore char *slash; 948*95c635efSGarrett D'Amore 949*95c635efSGarrett D'Amore if ((slash = strrchr(name, '/')) != NULL) 950*95c635efSGarrett D'Amore name = slash + 1; 951*95c635efSGarrett D'Amore 952*95c635efSGarrett D'Amore /* For each path in MANPATH */ 953*95c635efSGarrett D'Amore found = 0; 954*95c635efSGarrett D'Amore 955*95c635efSGarrett D'Amore for (p = manp; p != NULL; p = p->next) { 956*95c635efSGarrett D'Amore DPRINTF("-- Searching mandir: %s\n", p->path); 957*95c635efSGarrett D'Amore 958*95c635efSGarrett D'Amore if (*localedir != '\0') { 959*95c635efSGarrett D'Amore ldir = addlocale(p->path); 960*95c635efSGarrett D'Amore ndirs = getdirs(ldir, NULL, 0); 961*95c635efSGarrett D'Amore if (ndirs != 0) { 962*95c635efSGarrett D'Amore ldirs[0] = ldir; 963*95c635efSGarrett D'Amore ldirs[1] = NULL; 964*95c635efSGarrett D'Amore local = build_manpath(ldirs, 0); 965*95c635efSGarrett D'Amore DPRINTF("-- Locale specific subdir: %s\n", 966*95c635efSGarrett D'Amore ldir); 967*95c635efSGarrett D'Amore mandir(local->secv, ldir, name, 1); 968*95c635efSGarrett D'Amore free_manp(local); 969*95c635efSGarrett D'Amore } 970*95c635efSGarrett D'Amore free(ldir); 971*95c635efSGarrett D'Amore } 972*95c635efSGarrett D'Amore 973*95c635efSGarrett D'Amore /* 974*95c635efSGarrett D'Amore * Locale mandir not valid, man page in locale 975*95c635efSGarrett D'Amore * mandir not found, or -a option present 976*95c635efSGarrett D'Amore */ 977*95c635efSGarrett D'Amore if (ndirs == 0 || !found || all) 978*95c635efSGarrett D'Amore mandir(p->secv, p->path, name, 0); 979*95c635efSGarrett D'Amore 980*95c635efSGarrett D'Amore if (found && !all) 981*95c635efSGarrett D'Amore break; 982*95c635efSGarrett D'Amore } 983*95c635efSGarrett D'Amore 984*95c635efSGarrett D'Amore if (!found) { 985*95c635efSGarrett D'Amore if (sargs) { 986*95c635efSGarrett D'Amore (void) fprintf(stderr, gettext( 987*95c635efSGarrett D'Amore "No manual entry for %s in section(s) %s\n"), 988*95c635efSGarrett D'Amore fullname, mansec); 989*95c635efSGarrett D'Amore } else { 990*95c635efSGarrett D'Amore (void) fprintf(stderr, 991*95c635efSGarrett D'Amore gettext("No manual entry for %s\n"), fullname); 992*95c635efSGarrett D'Amore } 993*95c635efSGarrett D'Amore 994*95c635efSGarrett D'Amore } 995*95c635efSGarrett D'Amore 996*95c635efSGarrett D'Amore return (!found); 997*95c635efSGarrett D'Amore } 998*95c635efSGarrett D'Amore 999*95c635efSGarrett D'Amore 1000*95c635efSGarrett D'Amore /* 1001*95c635efSGarrett D'Amore * For a specified manual directory, read, store and sort section subdirs. 1002*95c635efSGarrett D'Amore * For each section specified, find and search matching subdirs. 1003*95c635efSGarrett D'Amore */ 1004*95c635efSGarrett D'Amore static void 1005*95c635efSGarrett D'Amore mandir(char **secv, char *path, char *name, int lspec) 1006*95c635efSGarrett D'Amore { 1007*95c635efSGarrett D'Amore DIR *dp; 1008*95c635efSGarrett D'Amore char **dirv; 1009*95c635efSGarrett D'Amore char **dv, **pdv; 1010*95c635efSGarrett D'Amore int len, dslen; 1011*95c635efSGarrett D'Amore 1012*95c635efSGarrett D'Amore if ((dp = opendir(path)) == NULL) 1013*95c635efSGarrett D'Amore return; 1014*95c635efSGarrett D'Amore 1015*95c635efSGarrett D'Amore if (lspec) 1016*95c635efSGarrett D'Amore DPRINTF("-- Searching mandir: %s\n", path); 1017*95c635efSGarrett D'Amore 1018*95c635efSGarrett D'Amore sortdir(dp, &dirv); 1019*95c635efSGarrett D'Amore 1020*95c635efSGarrett D'Amore /* Search in the order specified by MANSECTS */ 1021*95c635efSGarrett D'Amore for (; *secv; secv++) { 1022*95c635efSGarrett D'Amore len = strlen(*secv); 1023*95c635efSGarrett D'Amore for (dv = dirv; *dv; dv++) { 1024*95c635efSGarrett D'Amore dslen = strlen(*dv + 3); 1025*95c635efSGarrett D'Amore if (dslen > len) 1026*95c635efSGarrett D'Amore len = dslen; 1027*95c635efSGarrett D'Amore if (**secv == '\\') { 1028*95c635efSGarrett D'Amore if (strcmp(*secv + 1, *dv + 3) != 0) 1029*95c635efSGarrett D'Amore continue; 1030*95c635efSGarrett D'Amore } else if (strncasecmp(*secv, *dv + 3, len) != 0) { 1031*95c635efSGarrett D'Amore if (!all && 1032*95c635efSGarrett D'Amore (newsection = map_section(*secv, path)) 1033*95c635efSGarrett D'Amore == NULL) { 1034*95c635efSGarrett D'Amore continue; 1035*95c635efSGarrett D'Amore } 1036*95c635efSGarrett D'Amore if (newsection == NULL) 1037*95c635efSGarrett D'Amore newsection = ""; 1038*95c635efSGarrett D'Amore if (strncmp(newsection, *dv + 3, len) != 0) { 1039*95c635efSGarrett D'Amore continue; 1040*95c635efSGarrett D'Amore } 1041*95c635efSGarrett D'Amore } 1042*95c635efSGarrett D'Amore 1043*95c635efSGarrett D'Amore if (searchdir(path, *dv, name) == 0) 1044*95c635efSGarrett D'Amore continue; 1045*95c635efSGarrett D'Amore 1046*95c635efSGarrett D'Amore if (!all) { 1047*95c635efSGarrett D'Amore pdv = dirv; 1048*95c635efSGarrett D'Amore while (*pdv) { 1049*95c635efSGarrett D'Amore free(*pdv); 1050*95c635efSGarrett D'Amore pdv++; 1051*95c635efSGarrett D'Amore } 1052*95c635efSGarrett D'Amore (void) closedir(dp); 1053*95c635efSGarrett D'Amore free(dirv); 1054*95c635efSGarrett D'Amore return; 1055*95c635efSGarrett D'Amore } 1056*95c635efSGarrett D'Amore 1057*95c635efSGarrett D'Amore if (all && **dv == 'm' && *(dv + 1) && 1058*95c635efSGarrett D'Amore strcmp(*(dv + 1) + 3, *dv + 3) == 0) 1059*95c635efSGarrett D'Amore dv++; 1060*95c635efSGarrett D'Amore } 1061*95c635efSGarrett D'Amore } 1062*95c635efSGarrett D'Amore pdv = dirv; 1063*95c635efSGarrett D'Amore while (*pdv != NULL) { 1064*95c635efSGarrett D'Amore free(*pdv); 1065*95c635efSGarrett D'Amore pdv++; 1066*95c635efSGarrett D'Amore } 1067*95c635efSGarrett D'Amore free(dirv); 1068*95c635efSGarrett D'Amore (void) closedir(dp); 1069*95c635efSGarrett D'Amore } 1070*95c635efSGarrett D'Amore 1071*95c635efSGarrett D'Amore /* 1072*95c635efSGarrett D'Amore * Sort directories. 1073*95c635efSGarrett D'Amore */ 1074*95c635efSGarrett D'Amore static void 1075*95c635efSGarrett D'Amore sortdir(DIR *dp, char ***dirv) 1076*95c635efSGarrett D'Amore { 1077*95c635efSGarrett D'Amore struct dirent *d; 1078*95c635efSGarrett D'Amore char **dv; 1079*95c635efSGarrett D'Amore int maxentries = MAXDIRS; 1080*95c635efSGarrett D'Amore int entries = 0; 1081*95c635efSGarrett D'Amore 1082*95c635efSGarrett D'Amore if ((dv = *dirv = malloc(sizeof (char *) * 1083*95c635efSGarrett D'Amore maxentries)) == NULL) 1084*95c635efSGarrett D'Amore err(1, "malloc"); 1085*95c635efSGarrett D'Amore dv = *dirv; 1086*95c635efSGarrett D'Amore 1087*95c635efSGarrett D'Amore while ((d = readdir(dp))) { 1088*95c635efSGarrett D'Amore if (strcmp(d->d_name, ".") == 0 || 1089*95c635efSGarrett D'Amore strcmp(d->d_name, "..") == 0) 1090*95c635efSGarrett D'Amore continue; 1091*95c635efSGarrett D'Amore 1092*95c635efSGarrett D'Amore if (strncmp(d->d_name, "man", 3) == 0 || 1093*95c635efSGarrett D'Amore strncmp(d->d_name, "cat", 3) == 0) { 1094*95c635efSGarrett D'Amore if ((*dv = strdup(d->d_name)) == NULL) 1095*95c635efSGarrett D'Amore err(1, "strdup"); 1096*95c635efSGarrett D'Amore dv++; 1097*95c635efSGarrett D'Amore entries++; 1098*95c635efSGarrett D'Amore if (entries == maxentries) { 1099*95c635efSGarrett D'Amore maxentries += MAXDIRS; 1100*95c635efSGarrett D'Amore if ((*dirv = realloc(*dirv, 1101*95c635efSGarrett D'Amore sizeof (char *) * maxentries)) == NULL) 1102*95c635efSGarrett D'Amore err(1, "realloc"); 1103*95c635efSGarrett D'Amore dv = *dirv + entries; 1104*95c635efSGarrett D'Amore } 1105*95c635efSGarrett D'Amore } 1106*95c635efSGarrett D'Amore } 1107*95c635efSGarrett D'Amore *dv = 0; 1108*95c635efSGarrett D'Amore 1109*95c635efSGarrett D'Amore qsort((void *)*dirv, dv - *dirv, sizeof (char *), cmp); 1110*95c635efSGarrett D'Amore 1111*95c635efSGarrett D'Amore } 1112*95c635efSGarrett D'Amore 1113*95c635efSGarrett D'Amore 1114*95c635efSGarrett D'Amore /* 1115*95c635efSGarrett D'Amore * Search a section subdir for a given manpage. 1116*95c635efSGarrett D'Amore */ 1117*95c635efSGarrett D'Amore static int 1118*95c635efSGarrett D'Amore searchdir(char *path, char *dir, char *name) 1119*95c635efSGarrett D'Amore { 1120*95c635efSGarrett D'Amore DIR *sdp; 1121*95c635efSGarrett D'Amore struct dirent *sd; 1122*95c635efSGarrett D'Amore char sectpath[MAXPATHLEN]; 1123*95c635efSGarrett D'Amore char file[MAXNAMLEN]; 1124*95c635efSGarrett D'Amore char dname[MAXPATHLEN]; 1125*95c635efSGarrett D'Amore char *last; 1126*95c635efSGarrett D'Amore int nlen; 1127*95c635efSGarrett D'Amore 1128*95c635efSGarrett D'Amore (void) snprintf(sectpath, sizeof (sectpath), "%s/%s", path, dir); 1129*95c635efSGarrett D'Amore (void) snprintf(file, sizeof (file), "%s.", name); 1130*95c635efSGarrett D'Amore 1131*95c635efSGarrett D'Amore if ((sdp = opendir(sectpath)) == NULL) 1132*95c635efSGarrett D'Amore return (0); 1133*95c635efSGarrett D'Amore 1134*95c635efSGarrett D'Amore while ((sd = readdir(sdp))) { 1135*95c635efSGarrett D'Amore char *pname; 1136*95c635efSGarrett D'Amore 1137*95c635efSGarrett D'Amore if ((pname = strdup(sd->d_name)) == NULL) 1138*95c635efSGarrett D'Amore err(1, "strdup"); 1139*95c635efSGarrett D'Amore if ((last = strrchr(pname, '.')) != NULL && 1140*95c635efSGarrett D'Amore (strcmp(last, ".gz") == 0 || strcmp(last, ".bz2") == 0)) 1141*95c635efSGarrett D'Amore *last = '\0'; 1142*95c635efSGarrett D'Amore last = strrchr(pname, '.'); 1143*95c635efSGarrett D'Amore nlen = last - pname; 1144*95c635efSGarrett D'Amore (void) snprintf(dname, sizeof (dname), "%.*s.", nlen, pname); 1145*95c635efSGarrett D'Amore if (strcmp(dname, file) == 0 || 1146*95c635efSGarrett D'Amore strcmp(pname, name) == 0) { 1147*95c635efSGarrett D'Amore (void) format(path, dir, name, sd->d_name); 1148*95c635efSGarrett D'Amore (void) closedir(sdp); 1149*95c635efSGarrett D'Amore free(pname); 1150*95c635efSGarrett D'Amore return (1); 1151*95c635efSGarrett D'Amore } 1152*95c635efSGarrett D'Amore free(pname); 1153*95c635efSGarrett D'Amore } 1154*95c635efSGarrett D'Amore (void) closedir(sdp); 1155*95c635efSGarrett D'Amore 1156*95c635efSGarrett D'Amore return (0); 1157*95c635efSGarrett D'Amore } 1158*95c635efSGarrett D'Amore 1159*95c635efSGarrett D'Amore /* 1160*95c635efSGarrett D'Amore * Check the hash table of old directory names to see if there is a 1161*95c635efSGarrett D'Amore * new directory name. 1162*95c635efSGarrett D'Amore */ 1163*95c635efSGarrett D'Amore static char * 1164*95c635efSGarrett D'Amore map_section(char *section, char *path) 1165*95c635efSGarrett D'Amore { 1166*95c635efSGarrett D'Amore int i; 1167*95c635efSGarrett D'Amore char fullpath[MAXPATHLEN]; 1168*95c635efSGarrett D'Amore 1169*95c635efSGarrett D'Amore if (list) /* -l option fall through */ 1170*95c635efSGarrett D'Amore return (NULL); 1171*95c635efSGarrett D'Amore 1172*95c635efSGarrett D'Amore for (i = 0; map[i].new_name != NULL; i++) { 1173*95c635efSGarrett D'Amore if (strcmp(section, map[i].old_name) == 0) { 1174*95c635efSGarrett D'Amore (void) snprintf(fullpath, sizeof (fullpath), 1175*95c635efSGarrett D'Amore "%s/man%s", path, map[i].new_name); 1176*95c635efSGarrett D'Amore if (!access(fullpath, R_OK | X_OK)) { 1177*95c635efSGarrett D'Amore return (map[i].new_name); 1178*95c635efSGarrett D'Amore } else { 1179*95c635efSGarrett D'Amore return (NULL); 1180*95c635efSGarrett D'Amore } 1181*95c635efSGarrett D'Amore } 1182*95c635efSGarrett D'Amore } 1183*95c635efSGarrett D'Amore 1184*95c635efSGarrett D'Amore return (NULL); 1185*95c635efSGarrett D'Amore } 1186*95c635efSGarrett D'Amore 1187*95c635efSGarrett D'Amore /* 1188*95c635efSGarrett D'Amore * Format the manpage. 1189*95c635efSGarrett D'Amore */ 1190*95c635efSGarrett D'Amore static int 1191*95c635efSGarrett D'Amore format(char *path, char *dir, char *name, char *pg) 1192*95c635efSGarrett D'Amore { 1193*95c635efSGarrett D'Amore char manpname[MAXPATHLEN], catpname[MAXPATHLEN]; 1194*95c635efSGarrett D'Amore char cmdbuf[BUFSIZ], tmpbuf[BUFSIZ]; 1195*95c635efSGarrett D'Amore char *cattool; 1196*95c635efSGarrett D'Amore int utf8 = 0; 1197*95c635efSGarrett D'Amore struct stat sbman, sbcat; 1198*95c635efSGarrett D'Amore 1199*95c635efSGarrett D'Amore found++; 1200*95c635efSGarrett D'Amore 1201*95c635efSGarrett D'Amore if (list) { 1202*95c635efSGarrett D'Amore (void) printf(gettext("%s(%s)\t-M %s\n"), name, dir + 3, path); 1203*95c635efSGarrett D'Amore return (-1); 1204*95c635efSGarrett D'Amore } 1205*95c635efSGarrett D'Amore 1206*95c635efSGarrett D'Amore (void) snprintf(manpname, sizeof (manpname), "%s/man%s/%s", path, 1207*95c635efSGarrett D'Amore dir + 3, pg); 1208*95c635efSGarrett D'Amore (void) snprintf(catpname, sizeof (catpname), "%s/cat%s/%s", path, 1209*95c635efSGarrett D'Amore dir + 3, pg); 1210*95c635efSGarrett D'Amore 1211*95c635efSGarrett D'Amore /* Can't do PS output if manpage doesn't exist */ 1212*95c635efSGarrett D'Amore if (stat(manpname, &sbman) != 0 && (psoutput|lintout)) 1213*95c635efSGarrett D'Amore return (-1); 1214*95c635efSGarrett D'Amore 1215*95c635efSGarrett D'Amore /* 1216*95c635efSGarrett D'Amore * If both manpage and catpage do not exist, manpname is 1217*95c635efSGarrett D'Amore * broken symlink, most likely. 1218*95c635efSGarrett D'Amore */ 1219*95c635efSGarrett D'Amore if (stat(catpname, &sbcat) != 0 && stat(manpname, &sbman) != 0) 1220*95c635efSGarrett D'Amore err(1, "%s", manpname); 1221*95c635efSGarrett D'Amore 1222*95c635efSGarrett D'Amore /* Setup cattool */ 1223*95c635efSGarrett D'Amore if (fnmatch("*.gz", manpname, 0) == 0) 1224*95c635efSGarrett D'Amore cattool = "gzcat"; 1225*95c635efSGarrett D'Amore else if (fnmatch("*.bz2", manpname, 0) == 0) 1226*95c635efSGarrett D'Amore cattool = "bzcat"; 1227*95c635efSGarrett D'Amore else 1228*95c635efSGarrett D'Amore cattool = "cat"; 1229*95c635efSGarrett D'Amore 1230*95c635efSGarrett D'Amore /* Preprocess UTF-8 input with preconv (could be smarter) */ 1231*95c635efSGarrett D'Amore if (strstr(path, "UTF-8") != NULL) 1232*95c635efSGarrett D'Amore utf8 = 1; 1233*95c635efSGarrett D'Amore 1234*95c635efSGarrett D'Amore if (psoutput) { 1235*95c635efSGarrett D'Amore (void) snprintf(cmdbuf, BUFSIZ, 1236*95c635efSGarrett D'Amore "cd %s; %s %s%s | mandoc -Tps | lp -Tpostscript", 1237*95c635efSGarrett D'Amore path, cattool, manpname, 1238*95c635efSGarrett D'Amore utf8 ? " | " PRECONV " -e UTF-8" : ""); 1239*95c635efSGarrett D'Amore DPRINTF("-- Using manpage: %s\n", manpname); 1240*95c635efSGarrett D'Amore goto cmd; 1241*95c635efSGarrett D'Amore } else if (lintout) { 1242*95c635efSGarrett D'Amore (void) snprintf(cmdbuf, BUFSIZ, 1243*95c635efSGarrett D'Amore "cd %s; %s %s%s | mandoc -Tlint", 1244*95c635efSGarrett D'Amore path, cattool, manpname, 1245*95c635efSGarrett D'Amore utf8 ? " | " PRECONV " -e UTF-8" : ""); 1246*95c635efSGarrett D'Amore DPRINTF("-- Linting manpage: %s\n", manpname); 1247*95c635efSGarrett D'Amore goto cmd; 1248*95c635efSGarrett D'Amore } 1249*95c635efSGarrett D'Amore 1250*95c635efSGarrett D'Amore /* 1251*95c635efSGarrett D'Amore * Output catpage if: 1252*95c635efSGarrett D'Amore * - manpage doesn't exist 1253*95c635efSGarrett D'Amore * - output width is standard and catpage is recent enough 1254*95c635efSGarrett D'Amore */ 1255*95c635efSGarrett D'Amore if (stat(manpname, &sbman) != 0 || (manwidth == 0 && 1256*95c635efSGarrett D'Amore stat(catpname, &sbcat) == 0 && sbcat.st_mtime >= sbman.st_mtime)) { 1257*95c635efSGarrett D'Amore DPRINTF("-- Using catpage: %s\n", catpname); 1258*95c635efSGarrett D'Amore (void) snprintf(cmdbuf, BUFSIZ, "%s %s", pager, catpname); 1259*95c635efSGarrett D'Amore goto cmd; 1260*95c635efSGarrett D'Amore } 1261*95c635efSGarrett D'Amore 1262*95c635efSGarrett D'Amore DPRINTF("-- Using manpage: %s\n", manpname); 1263*95c635efSGarrett D'Amore if (manwidth > 0) 1264*95c635efSGarrett D'Amore (void) snprintf(tmpbuf, BUFSIZ, "-Owidth=%d ", manwidth); 1265*95c635efSGarrett D'Amore (void) snprintf(cmdbuf, BUFSIZ, "cd %s; %s %s%s | mandoc -T%s %s| %s", 1266*95c635efSGarrett D'Amore path, cattool, manpname, 1267*95c635efSGarrett D'Amore utf8 ? " | " PRECONV " -e UTF-8 " : "", 1268*95c635efSGarrett D'Amore utf8 ? "utf8" : "ascii", (manwidth > 0) ? tmpbuf : "", pager); 1269*95c635efSGarrett D'Amore 1270*95c635efSGarrett D'Amore cmd: 1271*95c635efSGarrett D'Amore DPRINTF("-- Command: %s\n", cmdbuf); 1272*95c635efSGarrett D'Amore 1273*95c635efSGarrett D'Amore if (!debug) 1274*95c635efSGarrett D'Amore return (system(cmdbuf) == 0); 1275*95c635efSGarrett D'Amore else 1276*95c635efSGarrett D'Amore return (0); 1277*95c635efSGarrett D'Amore } 1278*95c635efSGarrett D'Amore 1279*95c635efSGarrett D'Amore /* 1280*95c635efSGarrett D'Amore * Add <localedir> to the path. 1281*95c635efSGarrett D'Amore */ 1282*95c635efSGarrett D'Amore static char * 1283*95c635efSGarrett D'Amore addlocale(char *path) 1284*95c635efSGarrett D'Amore { 1285*95c635efSGarrett D'Amore char *tmp; 1286*95c635efSGarrett D'Amore 1287*95c635efSGarrett D'Amore if (asprintf(&tmp, "%s/%s", path, localedir) == -1) 1288*95c635efSGarrett D'Amore err(1, "asprintf"); 1289*95c635efSGarrett D'Amore 1290*95c635efSGarrett D'Amore return (tmp); 1291*95c635efSGarrett D'Amore } 1292*95c635efSGarrett D'Amore 1293*95c635efSGarrett D'Amore /* 1294*95c635efSGarrett D'Amore * Get the order of sections from man.cf. 1295*95c635efSGarrett D'Amore */ 1296*95c635efSGarrett D'Amore static char * 1297*95c635efSGarrett D'Amore check_config(char *path) 1298*95c635efSGarrett D'Amore { 1299*95c635efSGarrett D'Amore FILE *fp; 1300*95c635efSGarrett D'Amore char *rc = NULL; 1301*95c635efSGarrett D'Amore char *sect; 1302*95c635efSGarrett D'Amore char fname[MAXPATHLEN]; 1303*95c635efSGarrett D'Amore char *line = NULL; 1304*95c635efSGarrett D'Amore size_t linecap = 0; 1305*95c635efSGarrett D'Amore 1306*95c635efSGarrett D'Amore (void) snprintf(fname, MAXPATHLEN, "%s/%s", path, CONFIG); 1307*95c635efSGarrett D'Amore 1308*95c635efSGarrett D'Amore if ((fp = fopen(fname, "r")) == NULL) 1309*95c635efSGarrett D'Amore return (NULL); 1310*95c635efSGarrett D'Amore 1311*95c635efSGarrett D'Amore while (getline(&line, &linecap, fp) > 0) { 1312*95c635efSGarrett D'Amore if ((rc = strstr(line, "MANSECTS")) != NULL) 1313*95c635efSGarrett D'Amore break; 1314*95c635efSGarrett D'Amore } 1315*95c635efSGarrett D'Amore 1316*95c635efSGarrett D'Amore (void) fclose(fp); 1317*95c635efSGarrett D'Amore 1318*95c635efSGarrett D'Amore if (rc == NULL || (sect = strchr(line, '=')) == NULL) 1319*95c635efSGarrett D'Amore return (NULL); 1320*95c635efSGarrett D'Amore else 1321*95c635efSGarrett D'Amore return (++sect); 1322*95c635efSGarrett D'Amore } 1323*95c635efSGarrett D'Amore 1324*95c635efSGarrett D'Amore 1325*95c635efSGarrett D'Amore /* 1326*95c635efSGarrett D'Amore * Initialize the bintoman array with appropriate device and inode info. 1327*95c635efSGarrett D'Amore */ 1328*95c635efSGarrett D'Amore static void 1329*95c635efSGarrett D'Amore init_bintoman(void) 1330*95c635efSGarrett D'Amore { 1331*95c635efSGarrett D'Amore int i; 1332*95c635efSGarrett D'Amore struct stat sb; 1333*95c635efSGarrett D'Amore 1334*95c635efSGarrett D'Amore for (i = 0; bintoman[i].bindir != NULL; i++) { 1335*95c635efSGarrett D'Amore if (stat(bintoman[i].bindir, &sb) == 0) { 1336*95c635efSGarrett D'Amore bintoman[i].dev = sb.st_dev; 1337*95c635efSGarrett D'Amore bintoman[i].ino = sb.st_ino; 1338*95c635efSGarrett D'Amore } else { 1339*95c635efSGarrett D'Amore bintoman[i].dev = NODEV; 1340*95c635efSGarrett D'Amore } 1341*95c635efSGarrett D'Amore } 1342*95c635efSGarrett D'Amore } 1343*95c635efSGarrett D'Amore 1344*95c635efSGarrett D'Amore /* 1345*95c635efSGarrett D'Amore * If a duplicate is found, return 1. 1346*95c635efSGarrett D'Amore * If a duplicate is not found, add it to the dupnode list and return 0. 1347*95c635efSGarrett D'Amore */ 1348*95c635efSGarrett D'Amore static int 1349*95c635efSGarrett D'Amore dupcheck(struct man_node *mnp, struct dupnode **dnp) 1350*95c635efSGarrett D'Amore { 1351*95c635efSGarrett D'Amore struct dupnode *curdnp; 1352*95c635efSGarrett D'Amore struct secnode *cursnp; 1353*95c635efSGarrett D'Amore struct stat sb; 1354*95c635efSGarrett D'Amore int i; 1355*95c635efSGarrett D'Amore int rv = 1; 1356*95c635efSGarrett D'Amore int dupfound; 1357*95c635efSGarrett D'Amore 1358*95c635efSGarrett D'Amore /* If the path doesn't exist, treat it as a duplicate */ 1359*95c635efSGarrett D'Amore if (stat(mnp->path, &sb) != 0) 1360*95c635efSGarrett D'Amore return (1); 1361*95c635efSGarrett D'Amore 1362*95c635efSGarrett D'Amore /* If no sections were found in the man dir, treat it as duplicate */ 1363*95c635efSGarrett D'Amore if (mnp->secv == NULL) 1364*95c635efSGarrett D'Amore return (1); 1365*95c635efSGarrett D'Amore 1366*95c635efSGarrett D'Amore /* 1367*95c635efSGarrett D'Amore * Find the dupnode structure for the previous time this directory 1368*95c635efSGarrett D'Amore * was looked at. Device and inode numbers are compared so that 1369*95c635efSGarrett D'Amore * directories that are reached via different paths (e.g. /usr/man and 1370*95c635efSGarrett D'Amore * /usr/share/man) are treated as equivalent. 1371*95c635efSGarrett D'Amore */ 1372*95c635efSGarrett D'Amore for (curdnp = *dnp; curdnp != NULL; curdnp = curdnp->next) { 1373*95c635efSGarrett D'Amore if (curdnp->dev == sb.st_dev && curdnp->ino == sb.st_ino) 1374*95c635efSGarrett D'Amore break; 1375*95c635efSGarrett D'Amore } 1376*95c635efSGarrett D'Amore 1377*95c635efSGarrett D'Amore /* 1378*95c635efSGarrett D'Amore * First time this directory has been seen. Add a new node to the 1379*95c635efSGarrett D'Amore * head of the list. Since all entries are guaranteed to be unique 1380*95c635efSGarrett D'Amore * copy all sections to new node. 1381*95c635efSGarrett D'Amore */ 1382*95c635efSGarrett D'Amore if (curdnp == NULL) { 1383*95c635efSGarrett D'Amore if ((curdnp = calloc(1, sizeof (struct dupnode))) == NULL) 1384*95c635efSGarrett D'Amore err(1, "calloc"); 1385*95c635efSGarrett D'Amore for (i = 0; mnp->secv[i] != NULL; i++) { 1386*95c635efSGarrett D'Amore if ((cursnp = calloc(1, sizeof (struct secnode))) 1387*95c635efSGarrett D'Amore == NULL) 1388*95c635efSGarrett D'Amore err(1, "calloc"); 1389*95c635efSGarrett D'Amore cursnp->next = curdnp->secl; 1390*95c635efSGarrett D'Amore curdnp->secl = cursnp; 1391*95c635efSGarrett D'Amore if ((cursnp->secp = strdup(mnp->secv[i])) == NULL) 1392*95c635efSGarrett D'Amore err(1, "strdup"); 1393*95c635efSGarrett D'Amore } 1394*95c635efSGarrett D'Amore curdnp->dev = sb.st_dev; 1395*95c635efSGarrett D'Amore curdnp->ino = sb.st_ino; 1396*95c635efSGarrett D'Amore curdnp->next = *dnp; 1397*95c635efSGarrett D'Amore *dnp = curdnp; 1398*95c635efSGarrett D'Amore return (0); 1399*95c635efSGarrett D'Amore } 1400*95c635efSGarrett D'Amore 1401*95c635efSGarrett D'Amore /* 1402*95c635efSGarrett D'Amore * Traverse the section vector in the man_node and the section list 1403*95c635efSGarrett D'Amore * in dupnode cache to eliminate all duplicates from man_node. 1404*95c635efSGarrett D'Amore */ 1405*95c635efSGarrett D'Amore for (i = 0; mnp->secv[i] != NULL; i++) { 1406*95c635efSGarrett D'Amore dupfound = 0; 1407*95c635efSGarrett D'Amore for (cursnp = curdnp->secl; cursnp != NULL; 1408*95c635efSGarrett D'Amore cursnp = cursnp->next) { 1409*95c635efSGarrett D'Amore if (strcmp(mnp->secv[i], cursnp->secp) == 0) { 1410*95c635efSGarrett D'Amore dupfound = 1; 1411*95c635efSGarrett D'Amore break; 1412*95c635efSGarrett D'Amore } 1413*95c635efSGarrett D'Amore } 1414*95c635efSGarrett D'Amore if (dupfound) { 1415*95c635efSGarrett D'Amore mnp->secv[i][0] = '\0'; 1416*95c635efSGarrett D'Amore continue; 1417*95c635efSGarrett D'Amore } 1418*95c635efSGarrett D'Amore 1419*95c635efSGarrett D'Amore 1420*95c635efSGarrett D'Amore /* 1421*95c635efSGarrett D'Amore * Update curdnp and set return value to indicate that this 1422*95c635efSGarrett D'Amore * was not all duplicates. 1423*95c635efSGarrett D'Amore */ 1424*95c635efSGarrett D'Amore if ((cursnp = calloc(1, sizeof (struct secnode))) == NULL) 1425*95c635efSGarrett D'Amore err(1, "calloc"); 1426*95c635efSGarrett D'Amore cursnp->next = curdnp->secl; 1427*95c635efSGarrett D'Amore curdnp->secl = cursnp; 1428*95c635efSGarrett D'Amore if ((cursnp->secp = strdup(mnp->secv[i])) == NULL) 1429*95c635efSGarrett D'Amore err(1, "strdup"); 1430*95c635efSGarrett D'Amore rv = 0; 1431*95c635efSGarrett D'Amore } 1432*95c635efSGarrett D'Amore 1433*95c635efSGarrett D'Amore return (rv); 1434*95c635efSGarrett D'Amore } 1435*95c635efSGarrett D'Amore 1436*95c635efSGarrett D'Amore /* 1437*95c635efSGarrett D'Amore * Given a bindir, return corresponding mandir. 1438*95c635efSGarrett D'Amore */ 1439*95c635efSGarrett D'Amore static char * 1440*95c635efSGarrett D'Amore path_to_manpath(char *bindir) 1441*95c635efSGarrett D'Amore { 1442*95c635efSGarrett D'Amore char *mand, *p; 1443*95c635efSGarrett D'Amore int i; 1444*95c635efSGarrett D'Amore struct stat sb; 1445*95c635efSGarrett D'Amore 1446*95c635efSGarrett D'Amore /* First look for known translations for specific bin paths */ 1447*95c635efSGarrett D'Amore if (stat(bindir, &sb) != 0) { 1448*95c635efSGarrett D'Amore return (NULL); 1449*95c635efSGarrett D'Amore } 1450*95c635efSGarrett D'Amore for (i = 0; bintoman[i].bindir != NULL; i++) { 1451*95c635efSGarrett D'Amore if (sb.st_dev == bintoman[i].dev && 1452*95c635efSGarrett D'Amore sb.st_ino == bintoman[i].ino) { 1453*95c635efSGarrett D'Amore if ((mand = strdup(bintoman[i].mandir)) == NULL) 1454*95c635efSGarrett D'Amore err(1, "strdup"); 1455*95c635efSGarrett D'Amore if ((p = strchr(mand, ',')) != NULL) 1456*95c635efSGarrett D'Amore *p = '\0'; 1457*95c635efSGarrett D'Amore if (stat(mand, &sb) != 0) { 1458*95c635efSGarrett D'Amore free(mand); 1459*95c635efSGarrett D'Amore return (NULL); 1460*95c635efSGarrett D'Amore } 1461*95c635efSGarrett D'Amore if (p != NULL) 1462*95c635efSGarrett D'Amore *p = ','; 1463*95c635efSGarrett D'Amore return (mand); 1464*95c635efSGarrett D'Amore } 1465*95c635efSGarrett D'Amore } 1466*95c635efSGarrett D'Amore 1467*95c635efSGarrett D'Amore /* 1468*95c635efSGarrett D'Amore * No specific translation found. Try `dirname $bindir`/share/man 1469*95c635efSGarrett D'Amore * and `dirname $bindir`/man 1470*95c635efSGarrett D'Amore */ 1471*95c635efSGarrett D'Amore if ((mand = malloc(MAXPATHLEN)) == NULL) 1472*95c635efSGarrett D'Amore err(1, "malloc"); 1473*95c635efSGarrett D'Amore if (strlcpy(mand, bindir, MAXPATHLEN) >= MAXPATHLEN) { 1474*95c635efSGarrett D'Amore free(mand); 1475*95c635efSGarrett D'Amore return (NULL); 1476*95c635efSGarrett D'Amore } 1477*95c635efSGarrett D'Amore 1478*95c635efSGarrett D'Amore /* 1479*95c635efSGarrett D'Amore * Advance to end of buffer, strip trailing /'s then remove last 1480*95c635efSGarrett D'Amore * directory component. 1481*95c635efSGarrett D'Amore */ 1482*95c635efSGarrett D'Amore for (p = mand; *p != '\0'; p++) 1483*95c635efSGarrett D'Amore ; 1484*95c635efSGarrett D'Amore for (; p > mand && *p == '/'; p--) 1485*95c635efSGarrett D'Amore ; 1486*95c635efSGarrett D'Amore for (; p > mand && *p != '/'; p--) 1487*95c635efSGarrett D'Amore ; 1488*95c635efSGarrett D'Amore if (p == mand && *p == '.') { 1489*95c635efSGarrett D'Amore if (realpath("..", mand) == NULL) { 1490*95c635efSGarrett D'Amore free(mand); 1491*95c635efSGarrett D'Amore return (NULL); 1492*95c635efSGarrett D'Amore } 1493*95c635efSGarrett D'Amore for (; *p != '\0'; p++) 1494*95c635efSGarrett D'Amore ; 1495*95c635efSGarrett D'Amore } else { 1496*95c635efSGarrett D'Amore *p = '\0'; 1497*95c635efSGarrett D'Amore } 1498*95c635efSGarrett D'Amore 1499*95c635efSGarrett D'Amore if (strlcat(mand, "/share/man", MAXPATHLEN) >= MAXPATHLEN) { 1500*95c635efSGarrett D'Amore free(mand); 1501*95c635efSGarrett D'Amore return (NULL); 1502*95c635efSGarrett D'Amore } 1503*95c635efSGarrett D'Amore 1504*95c635efSGarrett D'Amore if ((stat(mand, &sb) == 0) && S_ISDIR(sb.st_mode)) { 1505*95c635efSGarrett D'Amore return (mand); 1506*95c635efSGarrett D'Amore } 1507*95c635efSGarrett D'Amore 1508*95c635efSGarrett D'Amore /* 1509*95c635efSGarrett D'Amore * Strip the /share/man off and try /man 1510*95c635efSGarrett D'Amore */ 1511*95c635efSGarrett D'Amore *p = '\0'; 1512*95c635efSGarrett D'Amore if (strlcat(mand, "/man", MAXPATHLEN) >= MAXPATHLEN) { 1513*95c635efSGarrett D'Amore free(mand); 1514*95c635efSGarrett D'Amore return (NULL); 1515*95c635efSGarrett D'Amore } 1516*95c635efSGarrett D'Amore if ((stat(mand, &sb) == 0) && S_ISDIR(sb.st_mode)) { 1517*95c635efSGarrett D'Amore return (mand); 1518*95c635efSGarrett D'Amore } 1519*95c635efSGarrett D'Amore 1520*95c635efSGarrett D'Amore /* 1521*95c635efSGarrett D'Amore * No man or share/man directory found 1522*95c635efSGarrett D'Amore */ 1523*95c635efSGarrett D'Amore free(mand); 1524*95c635efSGarrett D'Amore return (NULL); 1525*95c635efSGarrett D'Amore } 1526*95c635efSGarrett D'Amore 1527*95c635efSGarrett D'Amore /* 1528*95c635efSGarrett D'Amore * Free a linked list of dupnode structs. 1529*95c635efSGarrett D'Amore */ 1530*95c635efSGarrett D'Amore void 1531*95c635efSGarrett D'Amore free_dupnode(struct dupnode *dnp) { 1532*95c635efSGarrett D'Amore struct dupnode *dnp2; 1533*95c635efSGarrett D'Amore struct secnode *snp; 1534*95c635efSGarrett D'Amore 1535*95c635efSGarrett D'Amore while (dnp != NULL) { 1536*95c635efSGarrett D'Amore dnp2 = dnp; 1537*95c635efSGarrett D'Amore dnp = dnp->next; 1538*95c635efSGarrett D'Amore while (dnp2->secl != NULL) { 1539*95c635efSGarrett D'Amore snp = dnp2->secl; 1540*95c635efSGarrett D'Amore dnp2->secl = dnp2->secl->next; 1541*95c635efSGarrett D'Amore free(snp->secp); 1542*95c635efSGarrett D'Amore free(snp); 1543*95c635efSGarrett D'Amore } 1544*95c635efSGarrett D'Amore free(dnp2); 1545*95c635efSGarrett D'Amore } 1546*95c635efSGarrett D'Amore } 1547*95c635efSGarrett D'Amore 1548*95c635efSGarrett D'Amore /* 1549*95c635efSGarrett D'Amore * Print manp linked list to stdout. 1550*95c635efSGarrett D'Amore */ 1551*95c635efSGarrett D'Amore void 1552*95c635efSGarrett D'Amore print_manpath(struct man_node *manp) 1553*95c635efSGarrett D'Amore { 1554*95c635efSGarrett D'Amore char colon[2] = "\0\0"; 1555*95c635efSGarrett D'Amore char **secp; 1556*95c635efSGarrett D'Amore 1557*95c635efSGarrett D'Amore for (; manp != NULL; manp = manp->next) { 1558*95c635efSGarrett D'Amore (void) printf("%s%s", colon, manp->path); 1559*95c635efSGarrett D'Amore colon[0] = ':'; 1560*95c635efSGarrett D'Amore 1561*95c635efSGarrett D'Amore /* 1562*95c635efSGarrett D'Amore * If man.cf or a directory scan was used to create section 1563*95c635efSGarrett D'Amore * list, do not print section list again. If the output of 1564*95c635efSGarrett D'Amore * man -p is used to set MANPATH, subsequent runs of man 1565*95c635efSGarrett D'Amore * will re-read man.cf and/or scan man directories as 1566*95c635efSGarrett D'Amore * required. 1567*95c635efSGarrett D'Amore */ 1568*95c635efSGarrett D'Amore if (manp->defsrch != 0) 1569*95c635efSGarrett D'Amore continue; 1570*95c635efSGarrett D'Amore 1571*95c635efSGarrett D'Amore for (secp = manp->secv; *secp != NULL; secp++) { 1572*95c635efSGarrett D'Amore /* 1573*95c635efSGarrett D'Amore * Section deduplication may have eliminated some 1574*95c635efSGarrett D'Amore * sections from the vector. Avoid displaying this 1575*95c635efSGarrett D'Amore * detail which would appear as ",," in output 1576*95c635efSGarrett D'Amore */ 1577*95c635efSGarrett D'Amore if ((*secp)[0] != '\0') 1578*95c635efSGarrett D'Amore (void) printf(",%s", *secp); 1579*95c635efSGarrett D'Amore } 1580*95c635efSGarrett D'Amore } 1581*95c635efSGarrett D'Amore (void) printf("\n"); 1582*95c635efSGarrett D'Amore } 1583*95c635efSGarrett D'Amore 1584*95c635efSGarrett D'Amore static void 1585*95c635efSGarrett D'Amore usage_man(void) 1586*95c635efSGarrett D'Amore { 1587*95c635efSGarrett D'Amore 1588*95c635efSGarrett D'Amore (void) fprintf(stderr, gettext( 1589*95c635efSGarrett D'Amore "usage: man [-alptw] [-M path] [-s section] name ...\n" 1590*95c635efSGarrett D'Amore " man [-M path] [-s section] -k keyword ...\n" 1591*95c635efSGarrett D'Amore " man [-M path] [-s section] -f keyword ...\n")); 1592*95c635efSGarrett D'Amore 1593*95c635efSGarrett D'Amore exit(1); 1594*95c635efSGarrett D'Amore } 1595*95c635efSGarrett D'Amore 1596*95c635efSGarrett D'Amore static void 1597*95c635efSGarrett D'Amore usage_whatapro(void) 1598*95c635efSGarrett D'Amore { 1599*95c635efSGarrett D'Amore 1600*95c635efSGarrett D'Amore (void) fprintf(stderr, gettext( 1601*95c635efSGarrett D'Amore "usage: %s [-M path] [-s section] keyword ...\n"), 1602*95c635efSGarrett D'Amore whatis ? "whatis" : "apropos"); 1603*95c635efSGarrett D'Amore 1604*95c635efSGarrett D'Amore exit(1); 1605*95c635efSGarrett D'Amore } 1606*95c635efSGarrett D'Amore 1607*95c635efSGarrett D'Amore static void 1608*95c635efSGarrett D'Amore usage_catman(void) 1609*95c635efSGarrett D'Amore { 1610*95c635efSGarrett D'Amore (void) fprintf(stderr, gettext( 1611*95c635efSGarrett D'Amore "usage: catman [-M path] [-w]\n")); 1612*95c635efSGarrett D'Amore 1613*95c635efSGarrett D'Amore exit(1); 1614*95c635efSGarrett D'Amore } 1615*95c635efSGarrett D'Amore 1616*95c635efSGarrett D'Amore static void 1617*95c635efSGarrett D'Amore usage_makewhatis(void) 1618*95c635efSGarrett D'Amore { 1619*95c635efSGarrett D'Amore (void) fprintf(stderr, gettext("usage: makewhatis\n")); 1620*95c635efSGarrett D'Amore 1621*95c635efSGarrett D'Amore exit(1); 1622*95c635efSGarrett D'Amore } 1623