1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 4466 dk208809 * Common Development and Distribution License (the "License"). 6 4466 dk208809 * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 6639 samf * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T. */ 27 0 stevel /* All rights reserved. */ 28 0 stevel 29 0 stevel /* 30 0 stevel * University Copyright- Copyright (c) 1982, 1986, 1988 31 0 stevel * The Regents of the University of California 32 0 stevel * All Rights Reserved 33 0 stevel * 34 0 stevel * University Acknowledgment- Portions of this document are derived from 35 0 stevel * software developed by the University of California, Berkeley, and its 36 0 stevel * contributors. 37 0 stevel */ 38 0 stevel 39 0 stevel 40 0 stevel /* 41 0 stevel * man 42 0 stevel * links to apropos, whatis, and catman 43 0 stevel * This version uses more for underlining and paging. 44 0 stevel */ 45 0 stevel 46 0 stevel #include <stdio.h> 47 0 stevel #include <ctype.h> 48 0 stevel #include <sgtty.h> 49 0 stevel #include <sys/param.h> 50 0 stevel #include <sys/types.h> 51 0 stevel #include <sys/stat.h> 52 0 stevel #include <signal.h> 53 0 stevel #include <string.h> 54 0 stevel #include <malloc.h> 55 0 stevel #include <dirent.h> 56 0 stevel #include <errno.h> 57 0 stevel #include <fcntl.h> 58 0 stevel #include <locale.h> 59 0 stevel #include <stdlib.h> 60 0 stevel #include <unistd.h> 61 0 stevel #include <memory.h> 62 0 stevel #include <limits.h> 63 0 stevel #include <wchar.h> 64 0 stevel 65 0 stevel #define MACROF "tmac.an" /* name of <locale> macro file */ 66 0 stevel #define TMAC_AN "-man" /* default macro file */ 67 0 stevel 68 0 stevel /* 69 0 stevel * The default search path for man subtrees. 70 0 stevel */ 71 0 stevel 72 0 stevel #define MANDIR "/usr/share/man" /* default mandir */ 73 0 stevel #define MAKEWHATIS "/usr/lib/makewhatis" 74 0 stevel #define WHATIS "windex" 75 0 stevel #define TEMPLATE "/tmp/mpXXXXXX" 76 0 stevel #define CONFIG "man.cf" 77 0 stevel 78 0 stevel /* 79 0 stevel * Names for formatting and display programs. The values given 80 0 stevel * below are reasonable defaults, but sites with source may 81 0 stevel * wish to modify them to match the local environment. The 82 0 stevel * value for TCAT is particularly problematic as there's no 83 0 stevel * accepted standard value available for it. (The definition 84 0 stevel * below assumes C.A.T. troff output and prints it). 85 0 stevel */ 86 0 stevel 87 0 stevel #define MORE "more -s" /* default paging filter */ 88 0 stevel #define CAT_S "/usr/bin/cat -s" /* for '-' opt (no more) */ 89 0 stevel #define CAT_ "/usr/bin/cat" /* for when output is not a tty */ 90 0 stevel #define TROFF "troff" /* local name for troff */ 91 0 stevel #define TCAT "lp -c -T troff" /* command to "display" troff output */ 92 0 stevel 93 0 stevel #define SOLIMIT 10 /* maximum allowed .so chain length */ 94 0 stevel #define MAXDIRS 128 /* max # of subdirs per manpath */ 95 0 stevel #define MAXPAGES 32 /* max # for multiple pages */ 96 0 stevel #define PLEN 3 /* prefix length {man, cat, fmt} */ 97 0 stevel #define TMPLEN 7 /* length of tmpfile prefix */ 98 0 stevel #define MAXTOKENS 64 99 0 stevel #define MAXSUFFIX 20 /* length of section suffix */ 100 0 stevel 101 0 stevel #define DOT_SO ".so " 102 0 stevel #define PREPROC_SPEC "'\\\" " 103 0 stevel 104 0 stevel #define DPRINTF if (debug && !catmando) \ 105 0 stevel (void) printf 106 0 stevel 107 0 stevel #define sys(s) (debug ? ((void)puts(s), 0) : system(s)) 108 0 stevel #define eq(a, b) (strcmp(a, b) == 0) 109 0 stevel #define match(a, b, c) (strncmp(a, b, c) == 0) 110 0 stevel 111 0 stevel #define ISDIR(A) ((A.st_mode & S_IFMT) == S_IFDIR) 112 0 stevel 113 0 stevel #define SROFF_CMD "/usr/lib/sgml/sgml2roff" /* sgml converter */ 114 0 stevel #define MANDIRNAME "man" /* man directory */ 115 0 stevel #define SGMLDIR "sman" /* sman directory */ 116 0 stevel #define SGML_SYMBOL "<!DOCTYPE" /* a sgml file should contain this */ 117 0 stevel #define SGML_SYMBOL_LEN 9 /* length of SGML_SYMBOL */ 118 0 stevel 119 0 stevel /* 120 0 stevel * Directory mapping of old directories to new directories 121 0 stevel */ 122 0 stevel 123 0 stevel typedef struct { 124 0 stevel char *old_name; 125 0 stevel char *new_name; 126 0 stevel } map_entry; 127 0 stevel 128 0 stevel static const map_entry map[] = { 129 0 stevel { "3b", "3ucb" }, 130 0 stevel { "3e", "3elf" }, 131 0 stevel { "3g", "3gen" }, 132 0 stevel { "3k", "3kstat" }, 133 0 stevel { "3n", "3socket" }, 134 0 stevel { "3r", "3rt" }, 135 0 stevel { "3s", "3c" }, 136 0 stevel { "3t", "3thr" }, 137 0 stevel { "3x", "3curses" }, 138 0 stevel { "3xc", "3xcurses" }, 139 0 stevel { "3xn", "3xnet" } 140 0 stevel }; 141 0 stevel 142 0 stevel /* 143 0 stevel * A list of known preprocessors to precede the formatter itself 144 0 stevel * in the formatting pipeline. Preprocessors are specified by 145 0 stevel * starting a manual page with a line of the form: 146 0 stevel * '\" X 147 0 stevel * where X is a string consisting of letters from the p_tag fields 148 0 stevel * below. 149 0 stevel */ 150 0 stevel static const struct preprocessor { 151 0 stevel char p_tag; 152 0 stevel char *p_nroff, 153 0 stevel *p_troff; 154 0 stevel } preprocessors [] = { 155 0 stevel {'c', "cw", "cw"}, 156 0 stevel {'e', "neqn /usr/share/lib/pub/eqnchar", 157 0 stevel "eqn /usr/share/lib/pub/eqnchar"}, 158 0 stevel {'p', "pic", "pic"}, 159 0 stevel {'r', "refer", "refer"}, 160 0 stevel {'t', "tbl", "tbl"}, 161 0 stevel {'v', "vgrind -f", "vgrind -f"}, 162 0 stevel {0, 0, 0} 163 0 stevel }; 164 0 stevel 165 0 stevel struct suffix { 166 0 stevel char *ds; 167 0 stevel char *fs; 168 0 stevel }; 169 0 stevel 170 0 stevel /* 171 6639 samf * Flags that control behavior of build_manpath() 172 6639 samf * 173 6639 samf * BMP_ISPATH pathv is a vector constructed from PATH. 174 6639 samf * Perform appropriate path translations for 175 6639 samf * manpath. 176 6639 samf * BMP_APPEND_MANDIR Add /usr/share/man to the end if it 177 6639 samf * hasn't already appeared earlier. 178 6639 samf * BMP_FALLBACK_MANDIR Append /usr/share/man only if no other 179 6639 samf * manpath (including derived from PATH) 180 6639 samf * elements are valid. 181 6639 samf */ 182 6639 samf #define BMP_ISPATH 1 183 6639 samf #define BMP_APPEND_MANDIR 2 184 6639 samf #define BMP_FALLBACK_MANDIR 4 185 6639 samf 186 6639 samf /* 187 6639 samf * When doing equality comparisons of directories, device and inode 188 6639 samf * comparisons are done. The dupsec and dupnode structures are used 189 6639 samf * to form a list of lists for this processing. 190 6639 samf */ 191 6639 samf struct secnode { 192 6639 samf char *secp; 193 6639 samf struct secnode *next; 194 6639 samf }; 195 6639 samf struct dupnode { 196 6639 samf dev_t dev; /* from struct stat st_dev */ 197 6639 samf ino_t ino; /* from struct stat st_ino */ 198 6639 samf struct secnode *secl; /* sections already considered */ 199 6639 samf struct dupnode *next; 200 6639 samf }; 201 6639 samf 202 6639 samf /* 203 6639 samf * Map directories that may appear in PATH to the corresponding 204 6639 samf * man directory 205 6639 samf */ 206 6639 samf static struct pathmap { 207 6639 samf char *bindir; 208 6639 samf char *mandir; 209 6639 samf dev_t dev; 210 6639 samf ino_t ino; 211 6639 samf } bintoman[] = { 212 6639 samf {"/sbin", "/usr/share/man,1m", 0, 0}, 213 6639 samf {"/usr/sbin", "/usr/share/man,1m", 0, 0}, 214 6639 samf {"/usr/ucb", "/usr/share/man,1b", 0, 0}, 215 7172 samf {"/usr/bin/X11", "/usr/X11/share/man", 0, 0}, 216 6639 samf /* 217 6639 samf * Restrict to section 1 so that whatis /usr/{,xpg4,xpg6}/bin/ls 218 6639 samf * does not confuse users with section 1 and 1b 219 6639 samf */ 220 6639 samf {"/usr/bin", "/usr/share/man,1,1m,1s,1t,1c,1f", 0, 0}, 221 6639 samf {"/usr/xpg4/bin", "/usr/share/man,1", 0, 0}, 222 6639 samf {"/usr/xpg6/bin", "/usr/share/man,1", 0, 0}, 223 6639 samf {NULL, NULL, 0, 0} 224 6639 samf }; 225 6639 samf 226 6639 samf /* 227 0 stevel * Subdirectories to search for unformatted/formatted man page 228 0 stevel * versions, in nroff and troff variations. The searching 229 0 stevel * code in manual() is structured to expect there to be two 230 0 stevel * subdirectories apiece, the first for unformatted files 231 0 stevel * and the second for formatted ones. 232 0 stevel */ 233 0 stevel static char *nroffdirs[] = { "man", "cat", 0 }; 234 0 stevel static char *troffdirs[] = { "man", "fmt", 0 }; 235 0 stevel 236 0 stevel #define MAN_USAGE "\ 237 6639 samf usage:\tman [-] [-adFlprt] [-M path] [-T macro-package ] [ -s section ] \ 238 0 stevel name ...\n\ 239 0 stevel \tman [-M path] -k keyword ...\n\tman [-M path] -f file ..." 240 0 stevel #define CATMAN_USAGE "\ 241 0 stevel usage:\tcatman [-p] [-c|-ntw] [-M path] [-T macro-package ] [sections]" 242 0 stevel 243 0 stevel static char *opts[] = { 244 6639 samf "FfkrpP:M:T:ts:lad", /* man */ 245 0 stevel "wpnP:M:T:tc" /* catman */ 246 0 stevel }; 247 0 stevel 248 0 stevel struct man_node { 249 0 stevel char *path; /* mandir path */ 250 0 stevel char **secv; /* submandir suffices */ 251 6639 samf int defsrch; /* hint for man -p to avoid section list */ 252 6639 samf int frompath; /* hint for man -d and catman -p */ 253 0 stevel struct man_node *next; 254 0 stevel }; 255 0 stevel 256 0 stevel static char *pages[MAXPAGES]; 257 0 stevel static char **endp = pages; 258 0 stevel 259 0 stevel /* 260 0 stevel * flags (options) 261 0 stevel */ 262 0 stevel static int nomore; 263 0 stevel static int troffit; 264 0 stevel static int debug; 265 0 stevel static int Tflag; 266 0 stevel static int sargs; 267 0 stevel static int margs; 268 0 stevel static int force; 269 0 stevel static int found; 270 0 stevel static int list; 271 0 stevel static int all; 272 0 stevel static int whatis; 273 0 stevel static int apropos; 274 0 stevel static int catmando; 275 0 stevel static int nowhatis; 276 0 stevel static int whatonly; 277 0 stevel static int compargs; /* -c option for catman */ 278 6639 samf static int printmp; 279 0 stevel 280 0 stevel static char *CAT = CAT_; 281 0 stevel static char macros[MAXPATHLEN]; 282 0 stevel static char *mansec; 283 0 stevel static char *pager; 284 0 stevel static char *troffcmd; 285 0 stevel static char *troffcat; 286 0 stevel static char **subdirs; 287 0 stevel 288 0 stevel static char *check_config(char *); 289 6639 samf static struct man_node *build_manpath(char **, int); 290 0 stevel static void getpath(struct man_node *, char **); 291 0 stevel static void getsect(struct man_node *, char **); 292 0 stevel static void get_all_sect(struct man_node *); 293 0 stevel static void catman(struct man_node *, char **, int); 294 0 stevel static int makecat(char *, char **, int); 295 0 stevel static int getdirs(char *, char ***, short); 296 0 stevel static void whatapro(struct man_node *, char *, int); 297 6639 samf static void lookup_windex(char *, char *, char **); 298 0 stevel static int icmp(wchar_t *, wchar_t *); 299 0 stevel static void more(char **, int); 300 0 stevel static void cleanup(char **); 301 0 stevel static void bye(int); 302 0 stevel static char **split(char *, char); 303 6639 samf static void freev(char **); 304 4466 dk208809 static void fullpaths(struct man_node **); 305 0 stevel static void lower(char *); 306 0 stevel static int cmp(const void *, const void *); 307 0 stevel static void manual(struct man_node *, char *); 308 0 stevel static void mandir(char **, char *, char *); 309 0 stevel static void sortdir(DIR *, char ***); 310 0 stevel static int searchdir(char *, char *, char *); 311 0 stevel static int windex(char **, char *, char *); 312 0 stevel static void section(struct suffix *, char *); 313 6639 samf static int bfsearch(FILE *, char **, char *, char **); 314 6639 samf static int compare(char *, char *, char **); 315 0 stevel static int format(char *, char *, char *, char *); 316 0 stevel static char *addlocale(char *); 317 0 stevel static int get_manconfig(FILE *, char *); 318 0 stevel static void malloc_error(void); 319 0 stevel static int sgmlcheck(const char *); 320 0 stevel static char *map_section(char *, char *); 321 4466 dk208809 static void free_manp(struct man_node *manp); 322 6639 samf static void init_bintoman(void); 323 6639 samf static char *path_to_manpath(char *); 324 6639 samf static int dupcheck(struct man_node *, struct dupnode **); 325 6639 samf static void free_dupnode(struct dupnode *); 326 6639 samf static void print_manpath(struct man_node *, char *); 327 0 stevel 328 0 stevel /* 329 0 stevel * This flag is used when the SGML-to-troff converter 330 0 stevel * is absent - all the SGML searches are bypassed. 331 0 stevel */ 332 0 stevel static int no_sroff = 0; 333 0 stevel 334 0 stevel /* 335 0 stevel * This flag is used to describe the case where we've found 336 0 stevel * an SGML formatted manpage in the sman directory, we haven't 337 0 stevel * found a troff formatted manpage, and we don't have the SGML to troff 338 0 stevel * conversion utility on the system. 339 0 stevel */ 340 0 stevel static int sman_no_man_no_sroff; 341 0 stevel 342 0 stevel static char language[PATH_MAX + 1]; /* LC_MESSAGES */ 343 0 stevel static char localedir[PATH_MAX + 1]; /* locale specific path component */ 344 0 stevel 345 0 stevel static int defaultmandir = 1; /* if processing default mandir, 1 */ 346 0 stevel 347 0 stevel static char *newsection = NULL; 348 0 stevel 349 0 stevel int 350 0 stevel main(int argc, char *argv[]) 351 0 stevel { 352 0 stevel int badopts = 0; 353 0 stevel int c; 354 6639 samf char **pathv; 355 0 stevel char *cmdname; 356 6639 samf char *manpath = NULL; 357 0 stevel static struct man_node *manpage = NULL; 358 6639 samf int bmp_flags = 0; 359 0 stevel 360 0 stevel if (access(SROFF_CMD, F_OK | X_OK) != 0) 361 0 stevel no_sroff = 1; 362 0 stevel 363 0 stevel (void) setlocale(LC_ALL, ""); 364 0 stevel (void) strcpy(language, setlocale(LC_MESSAGES, (char *)0)); 365 0 stevel if (strcmp("C", language) != 0) 366 0 stevel (void) sprintf(localedir, "%s", language); 367 0 stevel 368 0 stevel #if !defined(TEXT_DOMAIN) 369 0 stevel #define TEXT_DOMAIN "SYS_TEST" 370 0 stevel #endif 371 0 stevel (void) textdomain(TEXT_DOMAIN); 372 0 stevel 373 0 stevel (void) strcpy(macros, TMAC_AN); 374 0 stevel 375 0 stevel /* 376 0 stevel * get base part of command name 377 0 stevel */ 378 0 stevel if ((cmdname = strrchr(argv[0], '/')) != NULL) 379 0 stevel cmdname++; 380 0 stevel else 381 0 stevel cmdname = argv[0]; 382 0 stevel 383 0 stevel if (eq(cmdname, "apropos") || eq(cmdname, "whatis")) { 384 0 stevel whatis++; 385 0 stevel apropos = (*cmdname == 'a'); 386 0 stevel if ((optind = 1) == argc) { 387 0 stevel (void) fprintf(stderr, gettext("%s what?\n"), cmdname); 388 0 stevel exit(2); 389 0 stevel } 390 0 stevel goto doargs; 391 0 stevel } else if (eq(cmdname, "catman")) 392 0 stevel catmando++; 393 0 stevel 394 0 stevel opterr = 0; 395 0 stevel while ((c = getopt(argc, argv, opts[catmando])) != -1) 396 0 stevel switch (c) { 397 0 stevel 398 0 stevel /* 399 0 stevel * man specific options 400 0 stevel */ 401 0 stevel case 'k': 402 0 stevel apropos++; 403 0 stevel /*FALLTHROUGH*/ 404 0 stevel case 'f': 405 0 stevel whatis++; 406 0 stevel break; 407 0 stevel case 'F': 408 0 stevel force++; /* do lookups the hard way */ 409 0 stevel break; 410 0 stevel case 's': 411 0 stevel mansec = optarg; 412 0 stevel sargs++; 413 0 stevel break; 414 0 stevel case 'r': 415 0 stevel nomore++, troffit++; 416 0 stevel break; 417 0 stevel case 'l': 418 0 stevel list++; /* implies all */ 419 0 stevel /*FALLTHROUGH*/ 420 0 stevel case 'a': 421 0 stevel all++; 422 0 stevel break; 423 0 stevel case 'd': 424 6639 samf debug++; 425 6639 samf break; 426 0 stevel /* 427 6639 samf * man and catman use -p differently. In catman it 428 6639 samf * enables debug mode and in man it prints the (possibly 429 6639 samf * derived from PATH or name operand) MANPATH. 430 0 stevel */ 431 0 stevel case 'p': 432 6639 samf if (catmando == 0) { 433 6639 samf printmp++; 434 6639 samf } else { 435 6639 samf debug++; 436 6639 samf } 437 0 stevel break; 438 0 stevel case 'n': 439 0 stevel nowhatis++; 440 0 stevel break; 441 0 stevel case 'w': 442 0 stevel whatonly++; 443 0 stevel break; 444 0 stevel case 'c': /* n|troff compatibility */ 445 0 stevel if (no_sroff) 446 0 stevel (void) fprintf(stderr, gettext( 447 8107 Pu "catman: SGML conversion not " 448 0 stevel "available -- -c flag ignored\n")); 449 0 stevel else 450 0 stevel compargs++; 451 0 stevel continue; 452 0 stevel 453 0 stevel /* 454 0 stevel * shared options 455 0 stevel */ 456 0 stevel case 'P': /* Backwards compatibility */ 457 0 stevel case 'M': /* Respecify path for man pages. */ 458 0 stevel manpath = optarg; 459 0 stevel margs++; 460 0 stevel break; 461 0 stevel case 'T': /* Respecify man macros */ 462 0 stevel (void) strcpy(macros, optarg); 463 0 stevel Tflag++; 464 0 stevel break; 465 0 stevel case 't': 466 0 stevel troffit++; 467 0 stevel break; 468 0 stevel case '?': 469 0 stevel badopts++; 470 0 stevel } 471 0 stevel 472 0 stevel /* 473 0 stevel * Bad options or no args? 474 6639 samf * (man -p and catman don't need args) 475 0 stevel */ 476 6639 samf if (badopts || (!catmando && !printmp && optind == argc)) { 477 0 stevel (void) fprintf(stderr, "%s\n", catmando ? 478 0 stevel gettext(CATMAN_USAGE) : gettext(MAN_USAGE)); 479 0 stevel exit(2); 480 0 stevel } 481 0 stevel 482 0 stevel if (compargs && (nowhatis || whatonly || troffit)) { 483 0 stevel (void) fprintf(stderr, "%s\n", gettext(CATMAN_USAGE)); 484 0 stevel (void) fprintf(stderr, gettext( 485 8107 Pu "-c option cannot be used with [-w][-n][-t]\n")); 486 0 stevel exit(2); 487 0 stevel } 488 0 stevel 489 0 stevel if (sargs && margs && catmando) { 490 0 stevel (void) fprintf(stderr, "%s\n", gettext(CATMAN_USAGE)); 491 0 stevel exit(2); 492 0 stevel } 493 0 stevel 494 0 stevel if (troffit == 0 && nomore == 0 && !isatty(fileno(stdout))) 495 0 stevel nomore++; 496 0 stevel 497 0 stevel /* 498 0 stevel * Collect environment information. 499 0 stevel */ 500 0 stevel if (troffit) { 501 0 stevel if ((troffcmd = getenv("TROFF")) == NULL) 502 0 stevel troffcmd = TROFF; 503 0 stevel if ((troffcat = getenv("TCAT")) == NULL) 504 0 stevel troffcat = TCAT; 505 0 stevel } else { 506 0 stevel if (((pager = getenv("PAGER")) == NULL) || 507 0 stevel (*pager == NULL)) 508 0 stevel pager = MORE; 509 0 stevel } 510 0 stevel 511 0 stevel doargs: 512 0 stevel subdirs = troffit ? troffdirs : nroffdirs; 513 0 stevel 514 6639 samf init_bintoman(); 515 6639 samf 516 6639 samf if (manpath == NULL && (manpath = getenv("MANPATH")) == NULL) { 517 6639 samf if ((manpath = getenv("PATH")) != NULL) { 518 6639 samf bmp_flags = BMP_ISPATH | BMP_APPEND_MANDIR; 519 6639 samf } else { 520 6639 samf manpath = MANDIR; 521 6639 samf } 522 6639 samf } 523 6639 samf 524 0 stevel pathv = split(manpath, ':'); 525 0 stevel 526 6639 samf manpage = build_manpath(pathv, bmp_flags); 527 0 stevel 528 0 stevel /* release pathv allocated by split() */ 529 6639 samf freev(pathv); 530 0 stevel 531 4466 dk208809 fullpaths(&manpage); 532 0 stevel 533 0 stevel if (catmando) { 534 0 stevel catman(manpage, argv+optind, argc-optind); 535 0 stevel exit(0); 536 0 stevel } 537 0 stevel 538 0 stevel /* 539 0 stevel * The manual routine contains windows during which 540 0 stevel * termination would leave a temp file behind. Thus 541 0 stevel * we blanket the whole thing with a clean-up routine. 542 0 stevel */ 543 0 stevel if (signal(SIGINT, SIG_IGN) == SIG_DFL) { 544 0 stevel (void) signal(SIGINT, bye); 545 0 stevel (void) signal(SIGQUIT, bye); 546 0 stevel (void) signal(SIGTERM, bye); 547 0 stevel } 548 0 stevel 549 6639 samf /* 550 6639 samf * "man -p" without operands 551 6639 samf */ 552 6639 samf if ((printmp != 0) && (optind == argc)) { 553 6639 samf print_manpath(manpage, NULL); 554 6639 samf exit(0); 555 6639 samf } 556 6639 samf 557 0 stevel for (; optind < argc; optind++) { 558 0 stevel if (strcmp(argv[optind], "-") == 0) { 559 0 stevel nomore++; 560 0 stevel CAT = CAT_S; 561 6639 samf } else { 562 6639 samf char *cmd; 563 6639 samf static struct man_node *mp; 564 6639 samf char *pv[2]; 565 6639 samf 566 6639 samf /* 567 6639 samf * If full path to command specified, customize 568 6639 samf * manpath accordingly 569 6639 samf */ 570 6639 samf if ((cmd = strrchr(argv[optind], '/')) != NULL) { 571 6639 samf *cmd = '\0'; 572 6639 samf if ((pv[0] = strdup(argv[optind])) == NULL) { 573 6639 samf malloc_error(); 574 6639 samf } 575 6639 samf pv[1] = NULL; 576 6639 samf *cmd = '/'; 577 6639 samf mp = build_manpath(pv, 578 6639 samf BMP_ISPATH|BMP_FALLBACK_MANDIR); 579 6639 samf } else { 580 6639 samf mp = manpage; 581 6639 samf } 582 6639 samf 583 6639 samf if (whatis) { 584 6639 samf whatapro(mp, argv[optind], apropos); 585 6639 samf } else if (printmp != 0) { 586 6639 samf print_manpath(mp, argv[optind]); 587 6639 samf } else { 588 6639 samf manual(mp, argv[optind]); 589 6639 samf } 590 6639 samf 591 6639 samf if (mp != NULL && mp != manpage) { 592 6639 samf free(pv[0]); 593 6639 samf free_manp(mp); 594 6639 samf } 595 6639 samf } 596 0 stevel } 597 0 stevel return (0); 598 0 stevel /*NOTREACHED*/ 599 0 stevel } 600 0 stevel 601 0 stevel /* 602 6639 samf * This routine builds the manpage structure from MANPATH or PATH, 603 6639 samf * depending on flags. See BMP_* definitions above for valid 604 6639 samf * flags. 605 6639 samf * 606 6639 samf * Assumes pathv elements were malloc'd, as done by split(). 607 6639 samf * Elements may be freed and reallocated to have different contents. 608 0 stevel */ 609 0 stevel 610 0 stevel static struct man_node * 611 6639 samf build_manpath(char **pathv, int flags) 612 0 stevel { 613 0 stevel struct man_node *manpage = NULL; 614 0 stevel struct man_node *currp = NULL; 615 0 stevel struct man_node *lastp = NULL; 616 0 stevel char **p; 617 0 stevel char **q; 618 6639 samf char *mand = NULL; 619 6639 samf char *mandir = MANDIR; 620 0 stevel int s; 621 6639 samf struct dupnode *didup = NULL; 622 0 stevel 623 0 stevel s = sizeof (struct man_node); 624 6639 samf for (p = pathv; *p; ) { 625 0 stevel 626 6639 samf if (flags & BMP_ISPATH) { 627 6639 samf if ((mand = path_to_manpath(*p)) == NULL) { 628 6639 samf goto next; 629 6639 samf } 630 6639 samf free(*p); 631 6639 samf *p = mand; 632 6639 samf } 633 0 stevel q = split(*p, ','); 634 0 stevel 635 0 stevel if (access(q[0], R_OK|X_OK) != 0) { 636 0 stevel if (catmando) { 637 0 stevel (void) fprintf(stderr, 638 8107 Pu gettext("%s is not accessible.\n"), 639 8107 Pu q[0]); 640 0 stevel (void) fflush(stderr); 641 0 stevel } 642 0 stevel } else { 643 0 stevel 644 6639 samf /* 645 6639 samf * Some element exists. Do not append MANDIR as a 646 6639 samf * fallback. 647 6639 samf */ 648 6639 samf flags &= ~BMP_FALLBACK_MANDIR; 649 0 stevel 650 6639 samf if ((currp = (struct man_node *)calloc(1, s)) == NULL) { 651 0 stevel malloc_error(); 652 6639 samf } 653 6639 samf 654 6639 samf currp->frompath = (flags & BMP_ISPATH); 655 6639 samf 656 6639 samf if (manpage == NULL) { 657 6639 samf lastp = manpage = currp; 658 6639 samf } 659 0 stevel 660 0 stevel getpath(currp, p); 661 0 stevel getsect(currp, p); 662 0 stevel 663 6639 samf /* 664 6639 samf * If there are no new elements in this path, 665 6639 samf * do not add it to the manpage list 666 6639 samf */ 667 6639 samf if (dupcheck(currp, &didup) != 0) { 668 6639 samf freev(currp->secv); 669 6639 samf free(currp); 670 6639 samf } else { 671 6639 samf currp->next = NULL; 672 6639 samf if (currp != manpage) { 673 6639 samf lastp->next = currp; 674 6639 samf } 675 6639 samf lastp = currp; 676 6639 samf } 677 0 stevel } 678 6639 samf freev(q); 679 6639 samf next: 680 6639 samf /* 681 6639 samf * Special handling of appending MANDIR. 682 6639 samf * After all pathv elements have been processed, append MANDIR 683 6639 samf * if needed. 684 6639 samf */ 685 6639 samf if (p == &mandir) { 686 6639 samf break; 687 6639 samf } 688 6639 samf p++; 689 6639 samf if (*p != NULL) { 690 6639 samf continue; 691 6639 samf } 692 6639 samf if (flags & (BMP_APPEND_MANDIR|BMP_FALLBACK_MANDIR)) { 693 6639 samf p = &mandir; 694 6639 samf flags &= ~BMP_ISPATH; 695 6639 samf } 696 6639 samf } 697 6639 samf 698 6639 samf free_dupnode(didup); 699 0 stevel 700 0 stevel return (manpage); 701 0 stevel } 702 0 stevel 703 0 stevel /* 704 0 stevel * Stores the mandir path into the manp structure. 705 0 stevel */ 706 0 stevel 707 0 stevel static void 708 0 stevel getpath(struct man_node *manp, char **pv) 709 0 stevel { 710 0 stevel char *s; 711 0 stevel int i = 0; 712 0 stevel 713 0 stevel s = *pv; 714 0 stevel 715 0 stevel while (*s != NULL && *s != ',') 716 0 stevel i++, s++; 717 0 stevel 718 0 stevel manp->path = (char *)malloc(i+1); 719 0 stevel if (manp->path == NULL) 720 0 stevel malloc_error(); 721 0 stevel (void) strncpy(manp->path, *pv, i); 722 0 stevel *(manp->path + i) = '\0'; 723 0 stevel } 724 0 stevel 725 0 stevel /* 726 0 stevel * Stores the mandir's corresponding sections (submandir 727 0 stevel * directories) into the manp structure. 728 0 stevel */ 729 0 stevel 730 0 stevel static void 731 0 stevel getsect(struct man_node *manp, char **pv) 732 0 stevel { 733 0 stevel char *sections; 734 0 stevel char **sectp; 735 0 stevel 736 0 stevel if (sargs) { 737 0 stevel manp->secv = split(mansec, ','); 738 0 stevel 739 0 stevel for (sectp = manp->secv; *sectp; sectp++) 740 0 stevel lower(*sectp); 741 0 stevel } else if ((sections = strchr(*pv, ',')) != NULL) { 742 6639 samf if (debug) { 743 6639 samf if (manp->frompath != 0) { 744 6639 samf /* 745 6639 samf * TRANSLATION_NOTE - message for man -d or catman -p 746 6639 samf * ex. /usr/share/man: derived from PATH, MANSECTS=,1b 747 6639 samf */ 748 6639 samf (void) printf(gettext( 749 8107 Pu "%s: derived from PATH, MANSECTS=%s\n"), 750 8107 Pu manp->path, sections); 751 6639 samf } else { 752 0 stevel /* 753 0 stevel * TRANSLATION_NOTE - message for man -d or catman -p 754 0 stevel * ex. /usr/share/man: from -M option, MANSECTS=,1,2,3c 755 0 stevel */ 756 6639 samf (void) fprintf(stdout, gettext( 757 8107 Pu "%s: from -M option, MANSECTS=%s\n"), 758 8107 Pu manp->path, sections); 759 6639 samf } 760 6639 samf } 761 0 stevel manp->secv = split(++sections, ','); 762 0 stevel for (sectp = manp->secv; *sectp; sectp++) 763 0 stevel lower(*sectp); 764 0 stevel 765 0 stevel if (*manp->secv == NULL) 766 0 stevel get_all_sect(manp); 767 0 stevel } else if ((sections = check_config(*pv)) != NULL) { 768 6639 samf manp->defsrch = 1; 769 0 stevel /* 770 0 stevel * TRANSLATION_NOTE - message for man -d or catman -p 771 0 stevel * ex. /usr/share/man: from man.cf, MANSECTS=1,1m,1c,1f 772 0 stevel */ 773 0 stevel if (debug) 774 0 stevel (void) fprintf(stdout, gettext( 775 8107 Pu "%s: from %s, MANSECTS=%s\n"), 776 0 stevel manp->path, CONFIG, sections); 777 0 stevel manp->secv = split(sections, ','); 778 0 stevel 779 0 stevel for (sectp = manp->secv; *sectp; sectp++) 780 0 stevel lower(*sectp); 781 0 stevel 782 0 stevel if (*manp->secv == NULL) 783 0 stevel get_all_sect(manp); 784 0 stevel } else { 785 6639 samf manp->defsrch = 1; 786 0 stevel /* 787 0 stevel * TRANSLATION_NOTE - message for man -d or catman -p 788 0 stevel * if man.cf has not been found or sections has not been specified 789 0 stevel * man/catman searches the sections lexicographically. 790 0 stevel */ 791 0 stevel if (debug) 792 0 stevel (void) fprintf(stdout, gettext( 793 0 stevel "%s: search the sections lexicographically\n"), 794 0 stevel manp->path); 795 0 stevel manp->secv = NULL; 796 0 stevel get_all_sect(manp); 797 0 stevel } 798 0 stevel } 799 0 stevel 800 0 stevel /* 801 0 stevel * Get suffices of all sub-mandir directories in a mandir. 802 0 stevel */ 803 0 stevel 804 0 stevel static void 805 0 stevel get_all_sect(struct man_node *manp) 806 0 stevel { 807 0 stevel DIR *dp; 808 0 stevel char **dirv; 809 0 stevel char **dv; 810 0 stevel char **p; 811 0 stevel char prev[MAXSUFFIX]; 812 0 stevel char tmp[MAXSUFFIX]; 813 0 stevel int plen; 814 0 stevel int maxentries = MAXTOKENS; 815 0 stevel int entries = 0; 816 0 stevel 817 0 stevel if ((dp = opendir(manp->path)) == 0) 818 0 stevel return; 819 0 stevel 820 0 stevel /* 821 0 stevel * sortdir() allocates memory for dirv and dirv[]. 822 0 stevel */ 823 0 stevel sortdir(dp, &dirv); 824 0 stevel 825 0 stevel (void) closedir(dp); 826 0 stevel 827 0 stevel if (manp->secv == NULL) { 828 0 stevel /* 829 0 stevel * allocates memory for manp->secv only if it's NULL 830 0 stevel */ 831 0 stevel manp->secv = (char **)malloc(maxentries * sizeof (char *)); 832 0 stevel if (manp->secv == NULL) 833 0 stevel malloc_error(); 834 0 stevel } 835 0 stevel 836 0 stevel (void) memset(tmp, 0, MAXSUFFIX); 837 0 stevel (void) memset(prev, 0, MAXSUFFIX); 838 0 stevel for (dv = dirv, p = manp->secv; *dv; dv++) { 839 0 stevel plen = PLEN; 840 0 stevel if (match(*dv, SGMLDIR, PLEN+1)) 841 0 stevel ++plen; 842 0 stevel 843 0 stevel if (strcmp(*dv, CONFIG) == 0) { 844 0 stevel /* release memory allocated by sortdir */ 845 0 stevel free(*dv); 846 0 stevel continue; 847 0 stevel } 848 0 stevel 849 0 stevel (void) sprintf(tmp, "%s", *dv + plen); 850 0 stevel 851 0 stevel if (strcmp(prev, tmp) == 0) { 852 0 stevel /* release memory allocated by sortdir */ 853 0 stevel free(*dv); 854 0 stevel continue; 855 0 stevel } 856 0 stevel 857 0 stevel (void) sprintf(prev, "%s", *dv + plen); 858 0 stevel /* 859 0 stevel * copy the string in (*dv + plen) to *p 860 0 stevel */ 861 0 stevel *p = strdup(*dv + plen); 862 0 stevel if (*p == NULL) 863 0 stevel malloc_error(); 864 0 stevel p++; 865 0 stevel entries++; 866 0 stevel if (entries == maxentries) { 867 0 stevel maxentries += MAXTOKENS; 868 0 stevel manp->secv = (char **)realloc(manp->secv, 869 8107 Pu sizeof (char *) * maxentries); 870 0 stevel if (manp->secv == NULL) 871 0 stevel malloc_error(); 872 0 stevel p = manp->secv + entries; 873 0 stevel } 874 0 stevel /* release memory allocated by sortdir */ 875 0 stevel free(*dv); 876 0 stevel } 877 0 stevel *p = 0; 878 0 stevel /* release memory allocated by sortdir */ 879 0 stevel free(dirv); 880 0 stevel } 881 0 stevel 882 0 stevel /* 883 0 stevel * Format man pages (build cat pages); if no 884 0 stevel * sections are specified, build all of them. 885 0 stevel * When building cat pages: 886 0 stevel * catman() tries to build cat pages for locale specific 887 0 stevel * man dirs first. Then, catman() tries to build cat pages 888 0 stevel * for the default man dir (for C locale like /usr/share/man) 889 0 stevel * regardless of the locale. 890 0 stevel * When building windex file: 891 0 stevel * catman() tries to build windex file for locale specific 892 0 stevel * man dirs first. Then, catman() tries to build windex file 893 0 stevel * for the default man dir (for C locale like /usr/share/man) 894 0 stevel * regardless of the locale. 895 0 stevel */ 896 0 stevel 897 0 stevel static void 898 0 stevel catman(struct man_node *manp, char **argv, int argc) 899 0 stevel { 900 0 stevel char cmdbuf[BUFSIZ]; 901 0 stevel char **dv; 902 0 stevel int changed; 903 0 stevel struct man_node *p; 904 0 stevel int ndirs = 0; 905 0 stevel char *ldir; 906 0 stevel int i; 907 6639 samf struct dupnode *dnp = NULL; 908 6639 samf char **realsecv; 909 6639 samf char *fakesecv[2] = { " catman ", NULL }; 910 0 stevel 911 0 stevel for (p = manp; p != NULL; p = p->next) { 912 6639 samf /* 913 6639 samf * prevent catman from doing very heavy lifting multiple 914 6639 samf * times on some directory 915 6639 samf */ 916 6639 samf realsecv = p->secv; 917 6639 samf p->secv = fakesecv; 918 6639 samf if (dupcheck(p, &dnp) != 0) { 919 6639 samf p->secv = realsecv; 920 6639 samf continue; 921 6639 samf } 922 6639 samf 923 0 stevel /* 924 0 stevel * TRANSLATION_NOTE - message for catman -p 925 0 stevel * ex. mandir path = /usr/share/man 926 0 stevel */ 927 0 stevel if (debug) 928 0 stevel (void) fprintf(stdout, gettext( 929 8107 Pu "\nmandir path = %s\n"), p->path); 930 0 stevel ndirs = 0; 931 6639 samf 932 0 stevel /* 933 0 stevel * Build cat pages 934 0 stevel * addlocale() allocates memory and returns it 935 0 stevel */ 936 0 stevel ldir = addlocale(p->path); 937 0 stevel if (!whatonly) { 938 0 stevel if (*localedir != '\0') { 939 0 stevel if (defaultmandir) 940 0 stevel defaultmandir = 0; 941 0 stevel /* getdirs allocate memory for dv */ 942 0 stevel ndirs = getdirs(ldir, &dv, 1); 943 0 stevel if (ndirs != 0) { 944 0 stevel changed = argc ? 945 8107 Pu makecat(ldir, argv, argc) : 946 8107 Pu makecat(ldir, dv, ndirs); 947 0 stevel /* release memory by getdirs */ 948 0 stevel for (i = 0; i < ndirs; i++) { 949 0 stevel free(dv[i]); 950 0 stevel } 951 0 stevel free(dv); 952 0 stevel } 953 0 stevel } 954 0 stevel 955 0 stevel /* default man dir is always processed */ 956 0 stevel defaultmandir = 1; 957 0 stevel ndirs = getdirs(p->path, &dv, 1); 958 0 stevel changed = argc ? 959 8107 Pu makecat(p->path, argv, argc) : 960 8107 Pu makecat(p->path, dv, ndirs); 961 0 stevel /* release memory allocated by getdirs */ 962 0 stevel for (i = 0; i < ndirs; i++) { 963 0 stevel free(dv[i]); 964 0 stevel } 965 0 stevel free(dv); 966 0 stevel } 967 0 stevel /* 968 0 stevel * Build whatis database 969 0 stevel * print error message if locale is set and man dir not found 970 0 stevel * won't build it at all if -c option is on 971 0 stevel */ 972 0 stevel if (!compargs && (whatonly || (!nowhatis && changed))) { 973 0 stevel if (*localedir != '\0') { 974 0 stevel /* just count the number of ndirs */ 975 0 stevel if ((ndirs = getdirs(ldir, NULL, 0)) != 0) { 976 0 stevel (void) sprintf(cmdbuf, 977 8107 Pu "/usr/bin/sh %s %s", 978 8107 Pu MAKEWHATIS, ldir); 979 0 stevel (void) sys(cmdbuf); 980 0 stevel } 981 0 stevel } 982 0 stevel /* whatis database of the default man dir */ 983 0 stevel /* will be always built in C locale. */ 984 0 stevel (void) sprintf(cmdbuf, 985 8107 Pu "/usr/bin/sh %s %s", 986 8107 Pu MAKEWHATIS, p->path); 987 0 stevel (void) sys(cmdbuf); 988 0 stevel } 989 0 stevel /* release memory allocated by addlocale() */ 990 0 stevel free(ldir); 991 0 stevel } 992 6639 samf free_dupnode(dnp); 993 0 stevel } 994 0 stevel 995 0 stevel /* 996 0 stevel * Build cat pages for given sections 997 0 stevel */ 998 0 stevel 999 0 stevel static int 1000 0 stevel makecat(char *path, char **dv, int ndirs) 1001 0 stevel { 1002 0 stevel DIR *dp, *sdp; 1003 0 stevel struct dirent *d; 1004 0 stevel struct stat sbuf; 1005 0 stevel char mandir[MAXPATHLEN+1]; 1006 0 stevel char smandir[MAXPATHLEN+1]; 1007 0 stevel char catdir[MAXPATHLEN+1]; 1008 0 stevel char *dirp, *sdirp; 1009 0 stevel int i, fmt; 1010 0 stevel int manflag, smanflag; 1011 0 stevel 1012 0 stevel for (i = fmt = 0; i < ndirs; i++) { 1013 0 stevel (void) snprintf(mandir, MAXPATHLEN, "%s/%s%s", 1014 8107 Pu path, MANDIRNAME, dv[i]); 1015 0 stevel (void) snprintf(smandir, MAXPATHLEN, "%s/%s%s", 1016 8107 Pu path, SGMLDIR, dv[i]); 1017 0 stevel (void) snprintf(catdir, MAXPATHLEN, "%s/%s%s", 1018 8107 Pu path, subdirs[1], dv[i]); 1019 0 stevel dirp = strrchr(mandir, '/') + 1; 1020 0 stevel sdirp = strrchr(smandir, '/') + 1; 1021 0 stevel 1022 0 stevel manflag = smanflag = 0; 1023 0 stevel 1024 0 stevel if ((dp = opendir(mandir)) != NULL) 1025 0 stevel manflag = 1; 1026 0 stevel 1027 0 stevel if (!no_sroff && (sdp = opendir(smandir)) != NULL) 1028 0 stevel smanflag = 1; 1029 0 stevel 1030 0 stevel if (dp == 0 && sdp == 0) { 1031 0 stevel if (strcmp(mandir, CONFIG) == 0) 1032 0 stevel perror(mandir); 1033 0 stevel continue; 1034 0 stevel } 1035 0 stevel /* 1036 0 stevel * TRANSLATION_NOTE - message for catman -p 1037 0 stevel * ex. Building cat pages for mandir = /usr/share/man/ja 1038 0 stevel */ 1039 0 stevel if (debug) 1040 0 stevel (void) fprintf(stdout, gettext( 1041 0 stevel "Building cat pages for mandir = %s\n"), path); 1042 0 stevel 1043 0 stevel if (!compargs && stat(catdir, &sbuf) < 0) { 1044 0 stevel (void) umask(02); 1045 0 stevel /* 1046 0 stevel * TRANSLATION_NOTE - message for catman -p 1047 0 stevel * ex. mkdir /usr/share/man/ja/cat3c 1048 0 stevel */ 1049 0 stevel if (debug) 1050 0 stevel (void) fprintf(stdout, gettext("mkdir %s\n"), 1051 8107 Pu catdir); 1052 0 stevel else { 1053 0 stevel if (mkdir(catdir, 0755) < 0) { 1054 0 stevel perror(catdir); 1055 0 stevel continue; 1056 0 stevel } 1057 0 stevel (void) chmod(catdir, 0755); 1058 0 stevel } 1059 0 stevel } 1060 0 stevel 1061 0 stevel /* 1062 0 stevel * if it is -c option of catman, if there is no 1063 0 stevel * coresponding man dir for sman files to go to, 1064 0 stevel * make the man dir 1065 0 stevel */ 1066 0 stevel 1067 0 stevel if (compargs && !manflag) { 1068 0 stevel if (mkdir(mandir, 0755) < 0) { 1069 0 stevel perror(mandir); 1070 0 stevel continue; 1071 0 stevel } 1072 0 stevel (void) chmod(mandir, 0755); 1073 0 stevel } 1074 0 stevel 1075 0 stevel if (smanflag) { 1076 0 stevel while ((d = readdir(sdp))) { 1077 0 stevel if (eq(".", d->d_name) || eq("..", d->d_name)) 1078 0 stevel continue; 1079 0 stevel 1080 0 stevel if (format(path, sdirp, (char *)0, d->d_name) 1081 8107 Pu > 0) 1082 0 stevel fmt++; 1083 0 stevel } 1084 0 stevel } 1085 0 stevel 1086 0 stevel if (manflag && !compargs) { 1087 0 stevel while ((d = readdir(dp))) { 1088 0 stevel if (eq(".", d->d_name) || eq("..", d->d_name)) 1089 0 stevel continue; 1090 0 stevel 1091 0 stevel if (format(path, dirp, (char *)0, d->d_name) 1092 8107 Pu > 0) 1093 0 stevel fmt++; 1094 0 stevel } 1095 0 stevel } 1096 0 stevel 1097 0 stevel if (manflag) 1098 0 stevel (void) closedir(dp); 1099 0 stevel 1100 0 stevel if (smanflag) 1101 0 stevel (void) closedir(sdp); 1102 0 stevel 1103 0 stevel } 1104 0 stevel return (fmt); 1105 0 stevel } 1106 0 stevel 1107 0 stevel 1108 0 stevel /* 1109 0 stevel * Get all "man" and "sman" dirs under a given manpath 1110 0 stevel * and return the number found 1111 0 stevel * If -c option is on, only count sman dirs 1112 0 stevel */ 1113 0 stevel 1114 0 stevel static int 1115 0 stevel getdirs(char *path, char ***dirv, short flag) 1116 0 stevel { 1117 0 stevel DIR *dp; 1118 0 stevel struct dirent *d; 1119 0 stevel int n = 0; 1120 0 stevel int plen, sgml_flag, man_flag; 1121 0 stevel int i = 0; 1122 0 stevel int maxentries = MAXDIRS; 1123 0 stevel char **dv; 1124 0 stevel 1125 0 stevel if ((dp = opendir(path)) == 0) { 1126 0 stevel if (debug) { 1127 0 stevel if (*localedir != '\0') 1128 0 stevel (void) printf(gettext("\ 1129 0 stevel locale is %s, search in %s\n"), localedir, path); 1130 0 stevel perror(path); 1131 0 stevel } 1132 0 stevel return (0); 1133 0 stevel } 1134 0 stevel 1135 0 stevel if (flag) { 1136 0 stevel /* allocate memory for dirv */ 1137 0 stevel *dirv = (char **)malloc(sizeof (char *) * 1138 8107 Pu maxentries); 1139 0 stevel if (*dirv == NULL) 1140 0 stevel malloc_error(); 1141 0 stevel dv = *dirv; 1142 0 stevel } 1143 0 stevel while ((d = readdir(dp))) { 1144 0 stevel plen = PLEN; 1145 0 stevel man_flag = sgml_flag = 0; 1146 0 stevel if (match(d->d_name, SGMLDIR, PLEN+1)) { 1147 0 stevel plen = PLEN + 1; 1148 0 stevel sgml_flag = 1; 1149 0 stevel i++; 1150 0 stevel } 1151 0 stevel 1152 0 stevel if (match(subdirs[0], d->d_name, PLEN)) 1153 0 stevel man_flag = 1; 1154 0 stevel 1155 0 stevel if (compargs && sgml_flag) { 1156 0 stevel if (flag) { 1157 0 stevel *dv = strdup(d->d_name+plen); 1158 0 stevel if (*dv == NULL) 1159 0 stevel malloc_error(); 1160 0 stevel dv++; 1161 0 stevel n = i; 1162 0 stevel } 1163 0 stevel } else if (!compargs && (sgml_flag || man_flag)) { 1164 0 stevel if (flag) { 1165 0 stevel *dv = strdup(d->d_name+plen); 1166 0 stevel if (*dv == NULL) 1167 0 stevel malloc_error(); 1168 0 stevel dv++; 1169 0 stevel } 1170 0 stevel n++; 1171 0 stevel } 1172 0 stevel if (flag) { 1173 0 stevel if ((dv - *dirv) == maxentries) { 1174 0 stevel int entries = maxentries; 1175 0 stevel maxentries += MAXTOKENS; 1176 0 stevel *dirv = (char **)realloc(*dirv, 1177 8107 Pu sizeof (char *) * maxentries); 1178 0 stevel if (*dirv == NULL) 1179 0 stevel malloc_error(); 1180 0 stevel dv = *dirv + entries; 1181 0 stevel } 1182 0 stevel } 1183 0 stevel } 1184 0 stevel 1185 0 stevel (void) closedir(dp); 1186 0 stevel return (n); 1187 0 stevel } 1188 0 stevel 1189 0 stevel 1190 0 stevel /* 1191 0 stevel * Find matching whatis or apropos entries 1192 0 stevel * whatapro() tries to handle the windex file of the locale specific 1193 0 stevel * man dirs first, then tries to handle the windex file of the default 1194 0 stevel * man dir (of C locale like /usr/share/man). 1195 0 stevel */ 1196 0 stevel 1197 0 stevel static void 1198 0 stevel whatapro(struct man_node *manp, char *word, int apropos) 1199 0 stevel { 1200 0 stevel char whatpath[MAXPATHLEN+1]; 1201 0 stevel char *p; 1202 0 stevel struct man_node *b; 1203 0 stevel int ndirs = 0; 1204 0 stevel char *ldir; 1205 0 stevel 1206 0 stevel 1207 0 stevel /* 1208 0 stevel * TRANSLATION_NOTE - message for man -d 1209 0 stevel * %s takes a parameter to -k option. 1210 0 stevel */ 1211 0 stevel DPRINTF(gettext("word = %s \n"), word); 1212 0 stevel 1213 0 stevel /* 1214 0 stevel * get base part of name 1215 0 stevel */ 1216 0 stevel if (!apropos) { 1217 0 stevel if ((p = strrchr(word, '/')) == NULL) 1218 0 stevel p = word; 1219 0 stevel else 1220 0 stevel p++; 1221 0 stevel } else { 1222 0 stevel p = word; 1223 0 stevel } 1224 0 stevel 1225 0 stevel for (b = manp; b != NULL; b = b->next) { 1226 0 stevel 1227 0 stevel if (*localedir != '\0') { 1228 0 stevel /* addlocale() allocates memory and returns it */ 1229 0 stevel ldir = addlocale(b->path); 1230 0 stevel if (defaultmandir) 1231 0 stevel defaultmandir = 0; 1232 0 stevel ndirs = getdirs(ldir, NULL, 0); 1233 0 stevel if (ndirs != 0) { 1234 0 stevel (void) sprintf(whatpath, "%s/%s", ldir, WHATIS); 1235 0 stevel /* 1236 0 stevel * TRANSLATION_NOTE - message for man -d 1237 0 stevel * ex. mandir path = /usr/share/man/ja 1238 0 stevel */ 1239 0 stevel DPRINTF(gettext("\nmandir path = %s\n"), ldir); 1240 6639 samf lookup_windex(whatpath, p, b->secv); 1241 0 stevel } 1242 0 stevel /* release memory allocated by addlocale() */ 1243 0 stevel free(ldir); 1244 0 stevel } 1245 0 stevel 1246 0 stevel defaultmandir = 1; 1247 0 stevel (void) sprintf(whatpath, "%s/%s", b->path, WHATIS); 1248 0 stevel /* 1249 0 stevel * TRANSLATION_NOTE - message for man -d 1250 0 stevel * ex. mandir path = /usr/share/man 1251 0 stevel */ 1252 0 stevel DPRINTF(gettext("\nmandir path = %s\n"), b->path); 1253 0 stevel 1254 6639 samf lookup_windex(whatpath, p, b->secv); 1255 0 stevel } 1256 0 stevel } 1257 0 stevel 1258 0 stevel 1259 0 stevel static void 1260 6639 samf lookup_windex(char *whatpath, char *word, char **secv) 1261 0 stevel { 1262 0 stevel FILE *fp; 1263 0 stevel char *matches[MAXPAGES]; 1264 0 stevel char **pp; 1265 0 stevel wchar_t wbuf[BUFSIZ]; 1266 0 stevel wchar_t *word_wchar = NULL; 1267 0 stevel wchar_t *ws; 1268 0 stevel size_t word_len, ret; 1269 0 stevel 1270 0 stevel if ((fp = fopen(whatpath, "r")) == NULL) { 1271 0 stevel perror(whatpath); 1272 0 stevel return; 1273 0 stevel } 1274 0 stevel 1275 0 stevel if (apropos) { 1276 0 stevel word_len = strlen(word) + 1; 1277 0 stevel if ((word_wchar = (wchar_t *)malloc(sizeof (wchar_t) * 1278 8107 Pu word_len)) == NULL) { 1279 0 stevel malloc_error(); 1280 0 stevel } 1281 0 stevel ret = mbstowcs(word_wchar, (const char *)word, word_len); 1282 0 stevel if (ret == (size_t)-1) { 1283 0 stevel (void) fprintf(stderr, gettext( 1284 8107 Pu "Invalid character in keyword\n")); 1285 0 stevel exit(1); 1286 0 stevel } 1287 0 stevel while (fgetws(wbuf, BUFSIZ, fp) != NULL) 1288 0 stevel for (ws = wbuf; *ws; ws++) 1289 0 stevel if (icmp(word_wchar, ws) == 0) { 1290 0 stevel (void) printf("%ws", wbuf); 1291 0 stevel break; 1292 0 stevel } 1293 0 stevel } else { 1294 6639 samf if (bfsearch(fp, matches, word, secv)) 1295 0 stevel for (pp = matches; *pp; pp++) { 1296 0 stevel (void) printf("%s", *pp); 1297 0 stevel /* 1298 0 stevel * release memory allocated by 1299 0 stevel * strdup() in bfsearch() 1300 0 stevel */ 1301 0 stevel free(*pp); 1302 0 stevel } 1303 0 stevel } 1304 0 stevel (void) fclose(fp); 1305 0 stevel if (word_wchar) 1306 0 stevel free(word_wchar); 1307 0 stevel 1308 0 stevel } 1309 0 stevel 1310 0 stevel 1311 0 stevel /* 1312 0 stevel * case-insensitive compare unless upper case is used 1313 0 stevel * ie) "mount" matches mount, Mount, MOUNT 1314 0 stevel * "Mount" matches Mount, MOUNT 1315 0 stevel * "MOUNT" matches MOUNT only 1316 0 stevel * If matched return 0. Otherwise, return 1. 1317 0 stevel */ 1318 0 stevel 1319 0 stevel static int 1320 0 stevel icmp(wchar_t *ws, wchar_t *wt) 1321 0 stevel { 1322 0 stevel for (; (*ws == 0) || 1323 8107 Pu (*ws == (iswupper(*ws) ? *wt: towlower(*wt))); 1324 8107 Pu ws++, wt++) 1325 0 stevel if (*ws == 0) 1326 0 stevel return (0); 1327 0 stevel 1328 0 stevel return (1); 1329 0 stevel } 1330 0 stevel 1331 0 stevel 1332 0 stevel /* 1333 0 stevel * Invoke PAGER with all matching man pages 1334 0 stevel */ 1335 0 stevel 1336 0 stevel static void 1337 0 stevel more(char **pages, int plain) 1338 0 stevel { 1339 0 stevel char cmdbuf[BUFSIZ]; 1340 0 stevel char **vp; 1341 0 stevel 1342 0 stevel /* 1343 0 stevel * Dont bother. 1344 0 stevel */ 1345 0 stevel if (list || (*pages == 0)) 1346 0 stevel return; 1347 0 stevel 1348 0 stevel if (plain && troffit) { 1349 0 stevel cleanup(pages); 1350 0 stevel return; 1351 0 stevel } 1352 0 stevel (void) sprintf(cmdbuf, "%s", troffit ? troffcat : 1353 0 stevel plain ? CAT : pager); 1354 0 stevel 1355 0 stevel /* 1356 0 stevel * Build arg list 1357 0 stevel */ 1358 0 stevel for (vp = pages; vp < endp; vp++) { 1359 0 stevel (void) strcat(cmdbuf, " "); 1360 0 stevel (void) strcat(cmdbuf, *vp); 1361 0 stevel } 1362 0 stevel (void) sys(cmdbuf); 1363 0 stevel cleanup(pages); 1364 0 stevel } 1365 0 stevel 1366 0 stevel 1367 0 stevel /* 1368 0 stevel * Get rid of dregs. 1369 0 stevel */ 1370 0 stevel 1371 0 stevel static void 1372 0 stevel cleanup(char **pages) 1373 0 stevel { 1374 0 stevel char **vp; 1375 0 stevel 1376 0 stevel for (vp = pages; vp < endp; vp++) { 1377 0 stevel if (match(TEMPLATE, *vp, TMPLEN)) 1378 0 stevel (void) unlink(*vp); 1379 0 stevel free(*vp); 1380 0 stevel } 1381 0 stevel 1382 0 stevel endp = pages; /* reset */ 1383 0 stevel } 1384 0 stevel 1385 0 stevel 1386 0 stevel /* 1387 0 stevel * Clean things up after receiving a signal. 1388 0 stevel */ 1389 0 stevel 1390 0 stevel /*ARGSUSED*/ 1391 0 stevel static void 1392 0 stevel bye(int sig) 1393 0 stevel { 1394 0 stevel cleanup(pages); 1395 0 stevel exit(1); 1396 0 stevel /*NOTREACHED*/ 1397 0 stevel } 1398 0 stevel 1399 0 stevel 1400 0 stevel /* 1401 0 stevel * Split a string by specified separator. 1402 0 stevel * ignore empty components/adjacent separators. 1403 0 stevel * returns vector to all tokens 1404 0 stevel */ 1405 0 stevel 1406 0 stevel static char ** 1407 0 stevel split(char *s1, char sep) 1408 0 stevel { 1409 0 stevel char **tokv, **vp; 1410 0 stevel char *mp, *tp; 1411 0 stevel int maxentries = MAXTOKENS; 1412 0 stevel int entries = 0; 1413 0 stevel 1414 0 stevel tokv = vp = (char **)malloc(maxentries * sizeof (char *)); 1415 0 stevel if (tokv == NULL) 1416 0 stevel malloc_error(); 1417 0 stevel mp = s1; 1418 0 stevel for (; mp && *mp; mp = tp) { 1419 0 stevel tp = strchr(mp, sep); 1420 0 stevel if (mp == tp) { /* empty component */ 1421 0 stevel tp++; /* ignore */ 1422 0 stevel continue; 1423 0 stevel } 1424 0 stevel if (tp) { 1425 0 stevel /* a component found */ 1426 0 stevel size_t len; 1427 0 stevel 1428 0 stevel len = tp - mp; 1429 0 stevel *vp = (char *)malloc(sizeof (char) * len + 1); 1430 0 stevel if (*vp == NULL) 1431 0 stevel malloc_error(); 1432 0 stevel (void) strncpy(*vp, mp, len); 1433 0 stevel *(*vp + len) = '\0'; 1434 0 stevel tp++; 1435 0 stevel vp++; 1436 0 stevel } else { 1437 0 stevel /* the last component */ 1438 0 stevel *vp = strdup(mp); 1439 0 stevel if (*vp == NULL) 1440 0 stevel malloc_error(); 1441 0 stevel vp++; 1442 0 stevel } 1443 0 stevel entries++; 1444 0 stevel if (entries == maxentries) { 1445 0 stevel maxentries += MAXTOKENS; 1446 0 stevel tokv = (char **)realloc(tokv, 1447 8107 Pu maxentries * sizeof (char *)); 1448 0 stevel if (tokv == NULL) 1449 0 stevel malloc_error(); 1450 0 stevel vp = tokv + entries; 1451 0 stevel } 1452 0 stevel } 1453 0 stevel *vp = 0; 1454 0 stevel return (tokv); 1455 0 stevel } 1456 0 stevel 1457 6639 samf /* 1458 6639 samf * Free a vector allocated by split(); 1459 6639 samf */ 1460 6639 samf static void 1461 7172 samf freev(char **v) 1462 7172 samf { 1463 6639 samf int i; 1464 6639 samf for (i = 0; v[i] != NULL; i++) { 1465 6639 samf free(v[i]); 1466 6639 samf } 1467 6639 samf free(v); 1468 6639 samf } 1469 0 stevel 1470 0 stevel /* 1471 0 stevel * Convert paths to full paths if necessary 1472 0 stevel * 1473 0 stevel */ 1474 0 stevel 1475 0 stevel static void 1476 4466 dk208809 fullpaths(struct man_node **manp_head) 1477 0 stevel { 1478 4466 dk208809 char *cwd = NULL; 1479 0 stevel char *p; 1480 4466 dk208809 char cwd_gotten = 0; 1481 4466 dk208809 struct man_node *manp = *manp_head; 1482 0 stevel struct man_node *b; 1483 4466 dk208809 struct man_node *prev = NULL; 1484 0 stevel 1485 0 stevel for (b = manp; b != NULL; b = b->next) { 1486 4466 dk208809 if (*(b->path) == '/') { 1487 4466 dk208809 prev = b; 1488 0 stevel continue; 1489 0 stevel } 1490 4466 dk208809 1491 4466 dk208809 /* try to get cwd if haven't already */ 1492 4466 dk208809 if (!cwd_gotten) { 1493 4466 dk208809 cwd = getcwd(NULL, MAXPATHLEN+1); 1494 4466 dk208809 cwd_gotten = 1; 1495 4466 dk208809 } 1496 4466 dk208809 1497 4466 dk208809 if (cwd) { 1498 4466 dk208809 /* case: relative manpath with cwd: make absolute */ 1499 4466 dk208809 if ((p = malloc(strlen(b->path)+strlen(cwd)+2)) == 1500 4466 dk208809 NULL) { 1501 4466 dk208809 malloc_error(); 1502 4466 dk208809 } 1503 4466 dk208809 (void) sprintf(p, "%s/%s", cwd, b->path); 1504 4466 dk208809 /* 1505 4466 dk208809 * resetting b->path 1506 4466 dk208809 */ 1507 4466 dk208809 free(b->path); 1508 4466 dk208809 b->path = p; 1509 4466 dk208809 } else { 1510 4466 dk208809 /* case: relative manpath but no cwd: omit path entry */ 1511 4466 dk208809 if (prev) 1512 4466 dk208809 prev->next = b->next; 1513 4466 dk208809 else 1514 4466 dk208809 *manp_head = b->next; 1515 4466 dk208809 1516 4466 dk208809 free_manp(b); 1517 4466 dk208809 } 1518 0 stevel } 1519 0 stevel /* 1520 0 stevel * release memory allocated by getcwd() 1521 0 stevel */ 1522 0 stevel free(cwd); 1523 4466 dk208809 } 1524 4466 dk208809 1525 4466 dk208809 /* 1526 4466 dk208809 * Free a man_node structure and its contents 1527 4466 dk208809 */ 1528 4466 dk208809 1529 4466 dk208809 static void 1530 4466 dk208809 free_manp(struct man_node *manp) 1531 4466 dk208809 { 1532 4466 dk208809 char **p; 1533 4466 dk208809 1534 4466 dk208809 free(manp->path); 1535 4466 dk208809 p = manp->secv; 1536 4466 dk208809 while ((p != NULL) && (*p != NULL)) { 1537 4466 dk208809 free(*p); 1538 4466 dk208809 p++; 1539 4466 dk208809 } 1540 4466 dk208809 free(manp->secv); 1541 4466 dk208809 free(manp); 1542 0 stevel } 1543 0 stevel 1544 0 stevel 1545 0 stevel /* 1546 0 stevel * Map (in place) to lower case 1547 0 stevel */ 1548 0 stevel 1549 0 stevel static void 1550 0 stevel lower(char *s) 1551 0 stevel { 1552 0 stevel if (s == 0) 1553 0 stevel return; 1554 0 stevel while (*s) { 1555 0 stevel if (isupper(*s)) 1556 0 stevel *s = tolower(*s); 1557 0 stevel s++; 1558 0 stevel } 1559 0 stevel } 1560 0 stevel 1561 0 stevel 1562 0 stevel /* 1563 0 stevel * compare for sort() 1564 0 stevel * sort first by section-spec, then by prefix {sman, man, cat, fmt} 1565 0 stevel * note: prefix is reverse sorted so that "sman" and "man" always 1566 0 stevel * comes before {cat, fmt} 1567 0 stevel */ 1568 0 stevel 1569 0 stevel static int 1570 0 stevel cmp(const void *arg1, const void *arg2) 1571 0 stevel { 1572 0 stevel int n; 1573 0 stevel char **p1 = (char **)arg1; 1574 0 stevel char **p2 = (char **)arg2; 1575 0 stevel 1576 0 stevel 1577 0 stevel /* by section; sman always before man dirs */ 1578 0 stevel if ((n = strcmp(*p1 + PLEN + (**p1 == 's' ? 1 : 0), 1579 8107 Pu *p2 + PLEN + (**p2 == 's' ? 1 : 0)))) 1580 0 stevel return (n); 1581 0 stevel 1582 0 stevel /* by prefix reversed */ 1583 0 stevel return (strncmp(*p2, *p1, PLEN)); 1584 0 stevel } 1585 0 stevel 1586 0 stevel 1587 0 stevel /* 1588 0 stevel * Find a man page ... 1589 0 stevel * Loop through each path specified, 1590 0 stevel * first try the lookup method (whatis database), 1591 0 stevel * and if it doesn't exist, do the hard way. 1592 0 stevel */ 1593 0 stevel 1594 0 stevel static void 1595 0 stevel manual(struct man_node *manp, char *name) 1596 0 stevel { 1597 0 stevel struct man_node *p; 1598 6639 samf struct man_node *local; 1599 0 stevel int ndirs = 0; 1600 0 stevel char *ldir; 1601 0 stevel char *ldirs[2]; 1602 6639 samf char *fullname = name; 1603 6639 samf char *slash; 1604 6639 samf 1605 6639 samf if ((slash = strrchr(name, '/')) != NULL) { 1606 6639 samf name = slash + 1; 1607 6639 samf } 1608 0 stevel 1609 0 stevel /* 1610 0 stevel * for each path in MANPATH 1611 0 stevel */ 1612 0 stevel found = 0; 1613 0 stevel 1614 0 stevel for (p = manp; p != NULL; p = p->next) { 1615 0 stevel /* 1616 0 stevel * TRANSLATION_NOTE - message for man -d 1617 0 stevel * ex. mandir path = /usr/share/man 1618 0 stevel */ 1619 0 stevel DPRINTF(gettext("\nmandir path = %s\n"), p->path); 1620 0 stevel 1621 0 stevel if (*localedir != '\0') { 1622 0 stevel /* addlocale() allocates memory and returns it */ 1623 0 stevel ldir = addlocale(p->path); 1624 0 stevel if (defaultmandir) 1625 0 stevel defaultmandir = 0; 1626 0 stevel /* 1627 0 stevel * TRANSLATION_NOTE - message for man -d 1628 0 stevel * ex. localedir = ja, ldir = /usr/share/man/ja 1629 0 stevel */ 1630 0 stevel if (debug) 1631 7172 samf (void) printf(gettext( 1632 8107 Pu "localedir = %s, ldir = %s\n"), 1633 8107 Pu localedir, ldir); 1634 0 stevel ndirs = getdirs(ldir, NULL, 0); 1635 0 stevel if (ndirs != 0) { 1636 0 stevel ldirs[0] = ldir; 1637 0 stevel ldirs[1] = NULL; 1638 6639 samf local = build_manpath(ldirs, 0); 1639 0 stevel if (force || 1640 0 stevel windex(local->secv, ldir, name) < 0) 1641 0 stevel mandir(local->secv, ldir, name); 1642 6639 samf free_manp(local); 1643 0 stevel } 1644 0 stevel /* release memory allocated by addlocale() */ 1645 0 stevel free(ldir); 1646 0 stevel } 1647 0 stevel 1648 0 stevel defaultmandir = 1; 1649 0 stevel /* 1650 0 stevel * locale mandir not valid, man page in locale 1651 0 stevel * mandir not found, or -a option present 1652 0 stevel */ 1653 0 stevel if (ndirs == 0 || !found || all) { 1654 0 stevel if (force || windex(p->secv, p->path, name) < 0) 1655 0 stevel mandir(p->secv, p->path, name); 1656 0 stevel } 1657 0 stevel 1658 0 stevel if (found && !all) 1659 0 stevel break; 1660 0 stevel } 1661 0 stevel 1662 0 stevel if (found) { 1663 0 stevel more(pages, nomore); 1664 0 stevel } else { 1665 0 stevel if (sargs) { 1666 0 stevel (void) printf(gettext("No entry for %s in section(s) " 1667 6639 samf "%s of the manual.\n"), fullname, mansec); 1668 0 stevel } else { 1669 0 stevel (void) printf(gettext( 1670 6639 samf "No manual entry for %s.\n"), fullname, mansec); 1671 0 stevel } 1672 0 stevel 1673 0 stevel if (sman_no_man_no_sroff) 1674 0 stevel (void) printf(gettext("(An SGML manpage was found " 1675 0 stevel "for '%s' but it cannot be displayed.)\n"), 1676 6639 samf fullname, mansec); 1677 0 stevel } 1678 0 stevel sman_no_man_no_sroff = 0; 1679 0 stevel } 1680 0 stevel 1681 0 stevel 1682 0 stevel /* 1683 0 stevel * For a specified manual directory, 1684 0 stevel * read, store, & sort section subdirs, 1685 0 stevel * for each section specified 1686 0 stevel * find and search matching subdirs 1687 0 stevel */ 1688 0 stevel 1689 0 stevel static void 1690 0 stevel mandir(char **secv, char *path, char *name) 1691 0 stevel { 1692 0 stevel DIR *dp; 1693 0 stevel char **dirv; 1694 0 stevel char **dv, **pdv; 1695 0 stevel int len, dslen, plen = PLEN; 1696 0 stevel 1697 0 stevel if ((dp = opendir(path)) == 0) { 1698 0 stevel /* 1699 0 stevel * TRANSLATION_NOTE - message for man -d or catman -p 1700 0 stevel * opendir(%s) returned 0 1701 0 stevel */ 1702 0 stevel if (debug) 1703 0 stevel (void) fprintf(stdout, gettext( 1704 8107 Pu " opendir on %s failed\n"), path); 1705 0 stevel return; 1706 0 stevel } 1707 0 stevel 1708 0 stevel /* 1709 0 stevel * TRANSLATION_NOTE - message for man -d or catman -p 1710 0 stevel * ex. mandir path = /usr/share/man/ja 1711 0 stevel */ 1712 0 stevel if (debug) 1713 0 stevel (void) printf(gettext("mandir path = %s\n"), path); 1714 0 stevel 1715 0 stevel /* 1716 0 stevel * sordir() allocates memory for dirv and dirv[]. 1717 0 stevel */ 1718 0 stevel sortdir(dp, &dirv); 1719 0 stevel /* 1720 0 stevel * Search in the order specified by MANSECTS 1721 0 stevel */ 1722 0 stevel for (; *secv; secv++) { 1723 0 stevel /* 1724 0 stevel * TRANSLATION_NOTE - message for man -d or catman -p 1725 0 stevel * ex. section = 3c 1726 0 stevel */ 1727 0 stevel DPRINTF(gettext(" section = %s\n"), *secv); 1728 0 stevel len = strlen(*secv); 1729 0 stevel for (dv = dirv; *dv; dv++) { 1730 0 stevel plen = PLEN; 1731 0 stevel if (*dv[0] == 's') 1732 0 stevel plen++; 1733 0 stevel dslen = strlen(*dv+plen); 1734 0 stevel if (dslen > len) 1735 0 stevel len = dslen; 1736 0 stevel if (**secv == '\\') { 1737 0 stevel if (!eq(*secv + 1, *dv+plen)) 1738 0 stevel continue; 1739 0 stevel } else if (!match(*secv, *dv+plen, len)) { 1740 0 stevel /* check to see if directory name changed */ 1741 0 stevel if (!all && 1742 0 stevel (newsection = map_section(*secv, path)) 1743 0 stevel == NULL) { 1744 0 stevel continue; 1745 0 stevel } 1746 0 stevel if (newsection == NULL) 1747 0 stevel newsection = ""; 1748 0 stevel if (!match(newsection, *dv+plen, len)) { 1749 0 stevel continue; 1750 0 stevel } 1751 0 stevel } 1752 0 stevel 1753 0 stevel if (searchdir(path, *dv, name) == 0) 1754 0 stevel continue; 1755 0 stevel 1756 0 stevel if (!all) { 1757 0 stevel /* release memory allocated by sortdir() */ 1758 0 stevel pdv = dirv; 1759 0 stevel while (*pdv) { 1760 0 stevel free(*pdv); 1761 0 stevel pdv++; 1762 0 stevel } 1763 0 stevel (void) closedir(dp); 1764 0 stevel /* release memory allocated by sortdir() */ 1765 0 stevel free(dirv); 1766 0 stevel return; 1767 0 stevel } 1768 0 stevel /* 1769 0 stevel * if we found a match in the man dir skip 1770 0 stevel * the corresponding cat dir if it exists 1771 0 stevel */ 1772 0 stevel if (all && **dv == 'm' && *(dv+1) && 1773 8107 Pu eq(*(dv+1)+plen, *dv+plen)) 1774 0 stevel dv++; 1775 0 stevel } 1776 0 stevel } 1777 0 stevel /* release memory allocated by sortdir() */ 1778 0 stevel pdv = dirv; 1779 0 stevel while (*pdv) { 1780 0 stevel free(*pdv); 1781 0 stevel pdv++; 1782 0 stevel } 1783 0 stevel free(dirv); 1784 0 stevel (void) closedir(dp); 1785 0 stevel } 1786 0 stevel 1787 0 stevel /* 1788 0 stevel * Sort directories. 1789 0 stevel */ 1790 0 stevel 1791 0 stevel static void 1792 0 stevel sortdir(DIR *dp, char ***dirv) 1793 0 stevel { 1794 0 stevel struct dirent *d; 1795 0 stevel char **dv; 1796 0 stevel int maxentries = MAXDIRS; 1797 0 stevel int entries = 0; 1798 0 stevel 1799 0 stevel *dirv = (char **)malloc(sizeof (char *) * maxentries); 1800 0 stevel dv = *dirv; 1801 0 stevel while ((d = readdir(dp))) { /* store dirs */ 1802 0 stevel if (eq(d->d_name, ".") || eq(d->d_name, "..")) /* ignore */ 1803 0 stevel continue; 1804 0 stevel 1805 0 stevel /* check if it matches sman, man, cat format */ 1806 0 stevel if (match(d->d_name, SGMLDIR, PLEN+1) || 1807 0 stevel match(d->d_name, subdirs[0], PLEN) || 1808 0 stevel match(d->d_name, subdirs[1], PLEN)) { 1809 0 stevel *dv = malloc(strlen(d->d_name) + 1); 1810 0 stevel if (*dv == NULL) 1811 0 stevel malloc_error(); 1812 0 stevel (void) strcpy(*dv, d->d_name); 1813 0 stevel dv++; 1814 0 stevel entries++; 1815 0 stevel if (entries == maxentries) { 1816 0 stevel maxentries += MAXDIRS; 1817 0 stevel *dirv = (char **)realloc(*dirv, 1818 8107 Pu sizeof (char *) * maxentries); 1819 0 stevel if (*dirv == NULL) 1820 0 stevel malloc_error(); 1821 0 stevel dv = *dirv + entries; 1822 0 stevel } 1823 0 stevel } 1824 0 stevel } 1825 0 stevel *dv = 0; 1826 0 stevel 1827 0 stevel qsort((void *)*dirv, dv - *dirv, sizeof (char *), cmp); 1828 0 stevel 1829 0 stevel } 1830 0 stevel 1831 0 stevel 1832 0 stevel /* 1833 0 stevel * Search a section subdirectory for a 1834 0 stevel * given man page, return 1 for success 1835 0 stevel */ 1836 0 stevel 1837 0 stevel static int 1838 0 stevel searchdir(char *path, char *dir, char *name) 1839 0 stevel { 1840 0 stevel DIR *sdp; 1841 0 stevel struct dirent *sd; 1842 0 stevel char sectpath[MAXPATHLEN+1]; 1843 0 stevel char file[MAXNAMLEN+1]; 1844 0 stevel char dname[MAXPATHLEN+1]; 1845 0 stevel char *last; 1846 0 stevel int nlen; 1847 0 stevel 1848 0 stevel /* 1849 0 stevel * TRANSLATION_NOTE - message for man -d or catman -p 1850 0 stevel * ex. scanning = man3c 1851 0 stevel */ 1852 0 stevel DPRINTF(gettext(" scanning = %s\n"), dir); 1853 0 stevel (void) sprintf(sectpath, "%s/%s", path, dir); 1854 0 stevel (void) snprintf(file, MAXPATHLEN, "%s.", name); 1855 0 stevel 1856 0 stevel if ((sdp = opendir(sectpath)) == 0) { 1857 0 stevel if (errno != ENOTDIR) /* ignore matching cruft */ 1858 0 stevel perror(sectpath); 1859 0 stevel return (0); 1860 0 stevel } 1861 0 stevel while ((sd = readdir(sdp))) { 1862 0 stevel last = strrchr(sd->d_name, '.'); 1863 0 stevel nlen = last - sd->d_name; 1864 0 stevel (void) sprintf(dname, "%.*s.", nlen, sd->d_name); 1865 0 stevel if (eq(dname, file) || eq(sd->d_name, name)) { 1866 0 stevel if (no_sroff && *dir == 's') { 1867 0 stevel sman_no_man_no_sroff = 1; 1868 0 stevel return (0); 1869 0 stevel } 1870 0 stevel (void) format(path, dir, name, sd->d_name); 1871 0 stevel (void) closedir(sdp); 1872 0 stevel return (1); 1873 0 stevel } 1874 0 stevel } 1875 0 stevel (void) closedir(sdp); 1876 0 stevel return (0); 1877 0 stevel } 1878 0 stevel 1879 0 stevel /* 1880 0 stevel * Check the hash table of old directory names to see if there is a 1881 0 stevel * new directory name. 1882 0 stevel * Returns new directory name if a match; after checking to be sure 1883 0 stevel * directory exists. 1884 0 stevel * Otherwise returns NULL 1885 0 stevel */ 1886 0 stevel 1887 0 stevel static char * 1888 0 stevel map_section(char *section, char *path) 1889 0 stevel { 1890 0 stevel int i; 1891 0 stevel int len; 1892 0 stevel char fullpath[MAXPATHLEN]; 1893 0 stevel 1894 0 stevel if (list) /* -l option fall through */ 1895 0 stevel return (NULL); 1896 0 stevel 1897 0 stevel for (i = 0; i <= ((sizeof (map)/sizeof (map[0]) - 1)); i++) { 1898 0 stevel if (strlen(section) > strlen(map[i].new_name)) { 1899 0 stevel len = strlen(section); 1900 0 stevel } else { 1901 0 stevel len = strlen(map[i].new_name); 1902 0 stevel } 1903 0 stevel if (match(section, map[i].old_name, len)) { 1904 0 stevel (void) sprintf(fullpath, 1905 0 stevel "%s/sman%s", path, map[i].new_name); 1906 0 stevel if (!access(fullpath, R_OK | X_OK)) { 1907 0 stevel return (map[i].new_name); 1908 0 stevel } else { 1909 0 stevel return (NULL); 1910 0 stevel } 1911 0 stevel } 1912 0 stevel } 1913 0 stevel 1914 0 stevel return (NULL); 1915 0 stevel } 1916 0 stevel 1917 0 stevel 1918 0 stevel /* 1919 0 stevel * Use windex database for quick lookup of man pages 1920 0 stevel * instead of mandir() (brute force search) 1921 0 stevel */ 1922 0 stevel 1923 0 stevel static int 1924 0 stevel windex(char **secv, char *path, char *name) 1925 0 stevel { 1926 0 stevel FILE *fp; 1927 0 stevel struct stat sbuf; 1928 0 stevel struct suffix *sp; 1929 0 stevel struct suffix psecs[MAXPAGES]; 1930 0 stevel char whatfile[MAXPATHLEN+1]; 1931 0 stevel char page[MAXPATHLEN+1]; 1932 0 stevel char *matches[MAXPAGES]; 1933 0 stevel char *file, *dir; 1934 0 stevel char **sv, **vp; 1935 0 stevel int len, dslen, exist, i; 1936 0 stevel int found_in_windex = 0; 1937 0 stevel char *tmp[] = {0, 0, 0, 0}; 1938 0 stevel 1939 0 stevel 1940 0 stevel (void) sprintf(whatfile, "%s/%s", path, WHATIS); 1941 0 stevel if ((fp = fopen(whatfile, "r")) == NULL) { 1942 0 stevel if (errno == ENOENT) 1943 0 stevel return (-1); 1944 0 stevel return (0); 1945 0 stevel } 1946 0 stevel 1947 0 stevel /* 1948 0 stevel * TRANSLATION_NOTE - message for man -d or catman -p 1949 0 stevel * ex. search in = /usr/share/man/ja/windex file 1950 0 stevel */ 1951 0 stevel if (debug) 1952 0 stevel (void) fprintf(stdout, gettext( 1953 8107 Pu " search in = %s file\n"), whatfile); 1954 0 stevel 1955 6639 samf if (bfsearch(fp, matches, name, NULL) == 0) { 1956 0 stevel (void) fclose(fp); 1957 0 stevel return (-1); /* force search in mandir */ 1958 0 stevel } 1959 0 stevel 1960 0 stevel (void) fclose(fp); 1961 0 stevel 1962 0 stevel /* 1963 0 stevel * Save and split sections 1964 0 stevel * section() allocates memory for sp->ds 1965 0 stevel */ 1966 0 stevel for (sp = psecs, vp = matches; *vp; vp++, sp++) 1967 0 stevel section(sp, *vp); 1968 0 stevel 1969 0 stevel sp->ds = 0; 1970 0 stevel 1971 0 stevel /* 1972 0 stevel * Search in the order specified 1973 0 stevel * by MANSECTS 1974 0 stevel */ 1975 0 stevel for (; *secv; secv++) { 1976 0 stevel len = strlen(*secv); 1977 0 stevel 1978 0 stevel /* 1979 0 stevel * TRANSLATION_NOTE - message for man -d or catman -p 1980 0 stevel * ex. search an entry to match printf.3c 1981 0 stevel */ 1982 0 stevel if (debug) 1983 0 stevel (void) fprintf(stdout, gettext( 1984 0 stevel " search an entry to match %s.%s\n"), name, *secv); 1985 0 stevel /* 1986 0 stevel * For every whatis entry that 1987 0 stevel * was matched 1988 0 stevel */ 1989 0 stevel for (sp = psecs; sp->ds; sp++) { 1990 0 stevel dslen = strlen(sp->ds); 1991 0 stevel if (dslen > len) 1992 0 stevel len = dslen; 1993 0 stevel if (**secv == '\\') { 1994 0 stevel if (!eq(*secv + 1, sp->ds)) 1995 0 stevel continue; 1996 0 stevel } else if (!match(*secv, sp->ds, len)) { 1997 0 stevel /* check to see if directory name changed */ 1998 0 stevel if (!all && 1999 0 stevel (newsection = map_section(*secv, path)) 2000 0 stevel == NULL) { 2001 0 stevel continue; 2002 0 stevel } 2003 0 stevel if (newsection == NULL) 2004 0 stevel newsection = ""; 2005 0 stevel if (!match(newsection, sp->ds, len)) { 2006 0 stevel continue; 2007 0 stevel } 2008 0 stevel } 2009 0 stevel /* 2010 0 stevel * here to form "sman", "man", "cat"|"fmt" in 2011 0 stevel * order 2012 0 stevel */ 2013 0 stevel if (!no_sroff) { 2014 0 stevel tmp[0] = SGMLDIR; 2015 0 stevel for (i = 1; i < 4; i++) 2016 0 stevel tmp[i] = subdirs[i-1]; 2017 0 stevel } else { 2018 0 stevel for (i = 0; i < 3; i++) 2019 0 stevel tmp[i] = subdirs[i]; 2020 0 stevel } 2021 0 stevel 2022 0 stevel for (sv = tmp; *sv; sv++) { 2023 0 stevel (void) sprintf(page, 2024 0 stevel "%s/%s%s/%s%s%s", path, *sv, 2025 0 stevel sp->ds, name, *sp->fs ? "." : "", 2026 0 stevel sp->fs); 2027 0 stevel exist = (stat(page, &sbuf) == 0); 2028 0 stevel if (exist) 2029 0 stevel break; 2030 0 stevel } 2031 0 stevel if (!exist) { 2032 0 stevel (void) fprintf(stderr, gettext( 2033 0 stevel "%s entry incorrect: %s(%s) not found.\n"), 2034 0 stevel WHATIS, name, sp->ds); 2035 0 stevel continue; 2036 0 stevel } 2037 0 stevel 2038 0 stevel file = strrchr(page, '/'), *file = 0; 2039 0 stevel dir = strrchr(page, '/'); 2040 0 stevel 2041 0 stevel /* 2042 0 stevel * By now we have a match 2043 0 stevel */ 2044 0 stevel found_in_windex = 1; 2045 0 stevel (void) format(path, ++dir, name, ++file); 2046 0 stevel 2047 0 stevel if (!all) 2048 0 stevel goto finish; 2049 0 stevel } 2050 0 stevel } 2051 0 stevel finish: 2052 0 stevel /* 2053 0 stevel * release memory allocated by section() 2054 0 stevel */ 2055 0 stevel sp = psecs; 2056 0 stevel while (sp->ds) { 2057 0 stevel free(sp->ds); 2058 0 stevel sp->ds = NULL; 2059 0 stevel sp++; 2060 0 stevel } 2061 0 stevel 2062 0 stevel /* 2063 0 stevel * If we didn't find a match, return failure as if we didn't find 2064 0 stevel * the windex at all. Why? Well, if you create a windex, then upgrade 2065 0 stevel * to a later release that contains new man pages, and forget to 2066 0 stevel * recreate the windex (since we don't do that automatically), you 2067 0 stevel * won't see any new man pages since they aren't in the windex. 2068 0 stevel * Pretending we didn't see a windex at all if there are no matches 2069 0 stevel * forces a search of the underlying directory. After all, the 2070 0 stevel * goal of the windex is to enable searches (man -k) and speed things 2071 0 stevel * up, not to _prevent_ you from seeing new man pages, so this seems 2072 0 stevel * ok. The only problem is when there are multiple entries (different 2073 0 stevel * sections), and some are in and some are out. Say you do 'man ls', 2074 0 stevel * and ls(1) isn't in the windex, but ls(1B) is. In that case, we 2075 0 stevel * will find a match in ls(1B), and you'll see that man page. 2076 0 stevel * That doesn't seem bad since if you specify the section the search 2077 0 stevel * will be restricted too. So in the example above, if you do 2078 0 stevel * 'man -s 1 ls' you'll get ls(1). 2079 0 stevel */ 2080 0 stevel if (found_in_windex) 2081 0 stevel return (0); 2082 0 stevel else 2083 0 stevel return (-1); 2084 0 stevel } 2085 0 stevel 2086 0 stevel 2087 0 stevel /* 2088 0 stevel * Return pointers to the section-spec 2089 0 stevel * and file-suffix of a whatis entry 2090 0 stevel */ 2091 0 stevel 2092 0 stevel static void 2093 0 stevel section(struct suffix *sp, char *s) 2094 0 stevel { 2095 0 stevel char *lp, *p; 2096 0 stevel 2097 0 stevel lp = strchr(s, '('); 2098 0 stevel p = strchr(s, ')'); 2099 0 stevel 2100 0 stevel if (++lp == 0 || p == 0 || lp == p) { 2101 0 stevel (void) fprintf(stderr, 2102 0 stevel gettext("mangled windex entry:\n\t%s\n"), s); 2103 0 stevel return; 2104 0 stevel } 2105 0 stevel *p = 0; 2106 0 stevel 2107 0 stevel /* 2108 0 stevel * copy the string pointed to by lp 2109 0 stevel */ 2110 0 stevel lp = strdup(lp); 2111 0 stevel if (lp == NULL) 2112 0 stevel malloc_error(); 2113 0 stevel /* 2114 0 stevel * release memory in s 2115 0 stevel * s has been allocated memory in bfsearch() 2116 0 stevel */ 2117 0 stevel free(s); 2118 0 stevel 2119 0 stevel lower(lp); 2120 0 stevel 2121 0 stevel /* 2122 0 stevel * split section-specifier if file-name 2123 0 stevel * suffix differs from section-suffix 2124 0 stevel */ 2125 0 stevel sp->ds = lp; 2126 0 stevel if ((p = strchr(lp, '/'))) { 2127 0 stevel *p++ = 0; 2128 0 stevel sp->fs = p; 2129 0 stevel } else 2130 0 stevel sp->fs = lp; 2131 0 stevel } 2132 0 stevel 2133 0 stevel 2134 0 stevel /* 2135 0 stevel * Binary file search to find matching man 2136 0 stevel * pages in whatis database. 2137 0 stevel */ 2138 0 stevel 2139 0 stevel static int 2140 6639 samf bfsearch(FILE *fp, char **matchv, char *key, char **secv) 2141 0 stevel { 2142 0 stevel char entry[BUFSIZ]; 2143 0 stevel char **vp; 2144 0 stevel long top, bot, mid; 2145 0 stevel int c; 2146 0 stevel 2147 0 stevel vp = matchv; 2148 0 stevel bot = 0; 2149 0 stevel (void) fseek(fp, 0L, 2); 2150 0 stevel top = ftell(fp); 2151 0 stevel for (;;) { 2152 0 stevel mid = (top+bot)/2; 2153 0 stevel (void) fseek(fp, mid, 0); 2154 0 stevel do { 2155 0 stevel c = getc(fp); 2156 0 stevel mid++; 2157 0 stevel } while (c != EOF && c != '\n'); 2158 0 stevel if (fgets(entry, sizeof (entry), fp) == NULL) 2159 0 stevel break; 2160 6639 samf switch (compare(key, entry, secv)) { 2161 0 stevel case -2: 2162 0 stevel case -1: 2163 0 stevel case 0: 2164 0 stevel if (top <= mid) 2165 0 stevel break; 2166 0 stevel top = mid; 2167 0 stevel continue; 2168 0 stevel case 1: 2169 0 stevel case 2: 2170 0 stevel bot = mid; 2171 0 stevel continue; 2172 0 stevel } 2173 0 stevel break; 2174 0 stevel } 2175 0 stevel (void) fseek(fp, bot, 0); 2176 0 stevel while (ftell(fp) < top) { 2177 0 stevel if (fgets(entry, sizeof (entry), fp) == NULL) { 2178 0 stevel *matchv = 0; 2179 0 stevel return (matchv - vp); 2180 0 stevel } 2181 6639 samf switch (compare(key, entry, secv)) { 2182 0 stevel case -2: 2183 0 stevel *matchv = 0; 2184 0 stevel return (matchv - vp); 2185 0 stevel case -1: 2186 0 stevel case 0: 2187 0 stevel *matchv = strdup(entry); 2188 0 stevel if (*matchv == NULL) 2189 0 stevel malloc_error(); 2190 0 stevel else 2191 0 stevel matchv++; 2192 0 stevel break; 2193 0 stevel case 1: 2194 0 stevel case 2: 2195 0 stevel continue; 2196 0 stevel } 2197 0 stevel break; 2198 0 stevel } 2199 0 stevel while (fgets(entry, sizeof (entry), fp)) { 2200 6639 samf switch (compare(key, entry, secv)) { 2201 0 stevel case -1: 2202 0 stevel case 0: 2203 0 stevel *matchv = strdup(entry); 2204 0 stevel if (*matchv == NULL) 2205 0 stevel malloc_error(); 2206 0 stevel else 2207 0 stevel matchv++; 2208 0 stevel continue; 2209 0 stevel } 2210 0 stevel break; 2211 0 stevel } 2212 0 stevel *matchv = 0; 2213 0 stevel return (matchv - vp); 2214 0 stevel } 2215 0 stevel 2216 0 stevel static int 2217 6639 samf compare(char *key, char *entry, char **secv) 2218 0 stevel { 2219 0 stevel char *entbuf; 2220 0 stevel char *s; 2221 0 stevel int comp, mlen; 2222 0 stevel int mbcurmax = MB_CUR_MAX; 2223 6639 samf char *secp = NULL; 2224 6639 samf int rv; 2225 6639 samf int eblen; 2226 0 stevel 2227 0 stevel entbuf = strdup(entry); 2228 0 stevel if (entbuf == NULL) { 2229 0 stevel malloc_error(); 2230 0 stevel } 2231 6639 samf eblen = strlen(entbuf); 2232 0 stevel 2233 0 stevel s = entbuf; 2234 0 stevel while (*s) { 2235 0 stevel if (*s == '\t' || *s == ' ') { 2236 0 stevel *s = '\0'; 2237 0 stevel break; 2238 0 stevel } 2239 0 stevel mlen = mblen(s, mbcurmax); 2240 0 stevel if (mlen == -1) { 2241 0 stevel (void) fprintf(stderr, gettext( 2242 8107 Pu "Invalid character in windex file.\n")); 2243 0 stevel exit(1); 2244 0 stevel } 2245 0 stevel s += mlen; 2246 0 stevel } 2247 6639 samf /* 2248 6639 samf * Find the section within parantheses 2249 6639 samf */ 2250 6639 samf if (secv != NULL && (s - entbuf) < eblen) { 2251 6639 samf if ((secp = strchr(s + 1, ')')) != NULL) { 2252 6639 samf *secp = '\0'; 2253 6639 samf if ((secp = strchr(s + 1, '(')) != NULL) { 2254 6639 samf secp++; 2255 6639 samf } 2256 6639 samf } 2257 6639 samf } 2258 0 stevel 2259 0 stevel comp = strcmp(key, entbuf); 2260 6639 samf if (comp == 0) { 2261 6639 samf if (secp == NULL) { 2262 6639 samf rv = 0; 2263 6639 samf } else { 2264 6639 samf while (*secv != NULL) { 2265 6639 samf if ((strcmp(*secv, secp)) == 0) { 2266 6639 samf rv = 0; 2267 6639 samf break; 2268 6639 samf } 2269 6639 samf secv++; 2270 6639 samf } 2271 6639 samf } 2272 6639 samf } else if (comp < 0) { 2273 6639 samf rv = -2; 2274 6639 samf } else { 2275 6639 samf rv = 2; 2276 6639 samf } 2277 0 stevel free(entbuf); 2278 6639 samf return (rv); 2279 0 stevel } 2280 0 stevel 2281 0 stevel 2282 0 stevel /* 2283 0 stevel * Format a man page and follow .so references 2284 0 stevel * if necessary. 2285 0 stevel */ 2286 0 stevel 2287 0 stevel static int 2288 0 stevel format(char *path, char *dir, char *name, char *pg) 2289 0 stevel { 2290 0 stevel char manpname[MAXPATHLEN+1], catpname[MAXPATHLEN+1]; 2291 0 stevel char manpname_sgml[MAXPATHLEN+1], smantmpname[MAXPATHLEN+1]; 2292 0 stevel char soed[MAXPATHLEN+1], soref[MAXPATHLEN+1]; 2293 0 stevel char manbuf[BUFSIZ], cmdbuf[BUFSIZ], tmpbuf[BUFSIZ]; 2294 0 stevel char tmpdir[MAXPATHLEN+1]; 2295 0 stevel int socount, updatedcat, regencat; 2296 0 stevel struct stat mansb, catsb, smansb; 2297 0 stevel char *tmpname; 2298 0 stevel int catonly = 0; 2299 0 stevel struct stat statb; 2300 0 stevel int plen = PLEN; 2301 0 stevel FILE *md; 2302 0 stevel int tempfd; 2303 0 stevel ssize_t count; 2304 0 stevel int temp, sgml_flag = 0, check_flag = 0; 2305 0 stevel char prntbuf[BUFSIZ + 1]; 2306 0 stevel char *ptr; 2307 0 stevel char *new_m; 2308 0 stevel char *tmpsubdir; 2309 0 stevel 2310 0 stevel found++; 2311 0 stevel 2312 0 stevel if (*dir != 'm' && *dir != 's') 2313 0 stevel catonly++; 2314 0 stevel 2315 0 stevel 2316 0 stevel if (*dir == 's') { 2317 0 stevel tmpsubdir = SGMLDIR; 2318 0 stevel ++plen; 2319 0 stevel (void) sprintf(manpname_sgml, "%s/man%s/%s", 2320 8107 Pu path, dir+plen, pg); 2321 0 stevel } else 2322 0 stevel tmpsubdir = MANDIRNAME; 2323 0 stevel 2324 0 stevel if (list) { 2325 0 stevel (void) printf(gettext("%s (%s)\t-M %s\n"), 2326 0 stevel name, dir+plen, path); 2327 0 stevel return (-1); 2328 0 stevel } 2329 0 stevel 2330 0 stevel (void) sprintf(manpname, "%s/%s%s/%s", path, tmpsubdir, dir+plen, pg); 2331 0 stevel (void) sprintf(catpname, "%s/%s%s/%s", path, subdirs[1], dir+plen, pg); 2332 0 stevel 2333 0 stevel (void) sprintf(smantmpname, "%s/%s%s/%s", path, SGMLDIR, dir+plen, pg); 2334 0 stevel 2335 0 stevel /* 2336 0 stevel * TRANSLATION_NOTE - message for man -d or catman -p 2337 0 stevel * ex. unformatted = /usr/share/man/ja/man3s/printf.3s 2338 0 stevel */ 2339 0 stevel DPRINTF(gettext( 2340 8107 Pu " unformatted = %s\n"), catonly ? "" : manpname); 2341 0 stevel /* 2342 0 stevel * TRANSLATION_NOTE - message for man -d or catman -p 2343 0 stevel * ex. formatted = /usr/share/man/ja/cat3s/printf.3s 2344 0 stevel */ 2345 0 stevel DPRINTF(gettext( 2346 8107 Pu " formatted = %s\n"), catpname); 2347 0 stevel 2348 0 stevel /* 2349 0 stevel * Take care of indirect references to other man pages; 2350 0 stevel * i.e., resolve files containing only ".so manx/file.x". 2351 0 stevel * We follow .so chains, replacing title with the .so'ed 2352 0 stevel * file at each stage, and keeping track of how many times 2353 0 stevel * we've done so, so that we can avoid looping. 2354 0 stevel */ 2355 0 stevel *soed = 0; 2356 0 stevel socount = 0; 2357 0 stevel for (;;) { 2358 0 stevel FILE *md; 2359 0 stevel char *cp; 2360 0 stevel char *s; 2361 0 stevel char *new_s; 2362 0 stevel 2363 0 stevel if (catonly) 2364 0 stevel break; 2365 0 stevel /* 2366 0 stevel * Grab manpname's first line, stashing it in manbuf. 2367 0 stevel */ 2368 0 stevel 2369 0 stevel 2370 0 stevel if ((md = fopen(manpname, "r")) == NULL) { 2371 0 stevel if (*soed && errno == ENOENT) { 2372 0 stevel (void) fprintf(stderr, 2373 0 stevel gettext("Can't find referent of " 2374 8107 Pu ".so in %s\n"), soed); 2375 0 stevel (void) fflush(stderr); 2376 0 stevel return (-1); 2377 0 stevel } 2378 0 stevel perror(manpname); 2379 0 stevel return (-1); 2380 0 stevel } 2381 0 stevel if (fgets(manbuf, BUFSIZ-1, md) == NULL) { 2382 0 stevel (void) fclose(md); 2383 0 stevel (void) fprintf(stderr, gettext("%s: null file\n"), 2384 0 stevel manpname); 2385 0 stevel (void) fflush(stderr); 2386 0 stevel return (-1); 2387 0 stevel } 2388 0 stevel (void) fclose(md); 2389 0 stevel 2390 0 stevel if (strncmp(manbuf, DOT_SO, sizeof (DOT_SO) - 1)) 2391 0 stevel break; 2392 0 stevel so_again: if (++socount > SOLIMIT) { 2393 0 stevel (void) fprintf(stderr, gettext(".so chain too long\n")); 2394 0 stevel (void) fflush(stderr); 2395 0 stevel return (-1); 2396 0 stevel } 2397 0 stevel s = manbuf + sizeof (DOT_SO) - 1; 2398 0 stevel if ((check_flag == 1) && ((new_s = strrchr(s, '/')) != NULL)) { 2399 0 stevel new_s++; 2400 0 stevel (void) sprintf(s, "%s%s/%s", 2401 8107 Pu tmpsubdir, dir+plen, new_s); 2402 0 stevel } 2403 0 stevel 2404 0 stevel cp = strrchr(s, '\n'); 2405 0 stevel if (cp) 2406 0 stevel *cp = '\0'; 2407 0 stevel /* 2408 0 stevel * Compensate for sloppy typists by stripping 2409 0 stevel * trailing white space. 2410 0 stevel */ 2411 0 stevel cp = s + strlen(s); 2412 0 stevel while (--cp >= s && (*cp == ' ' || *cp == '\t')) 2413 0 stevel *cp = '\0'; 2414 0 stevel 2415 0 stevel /* 2416 0 stevel * Go off and find the next link in the chain. 2417 0 stevel */ 2418 0 stevel (void) strcpy(soed, manpname); 2419 0 stevel (void) strcpy(soref, s); 2420 0 stevel (void) sprintf(manpname, "%s/%s", path, s); 2421 0 stevel /* 2422 0 stevel * TRANSLATION_NOTE - message for man -d or catman -p 2423 0 stevel * ex. .so ref = man3c/string.3c 2424 0 stevel */ 2425 0 stevel DPRINTF(gettext(".so ref = %s\n"), s); 2426 0 stevel } 2427 0 stevel 2428 0 stevel /* 2429 0 stevel * Make symlinks if so'ed and cattin' 2430 0 stevel */ 2431 0 stevel if (socount && catmando) { 2432 0 stevel (void) sprintf(cmdbuf, "cd %s; rm -f %s; ln -s ../%s%s %s", 2433 0 stevel path, catpname, subdirs[1], soref+plen, catpname); 2434 0 stevel (void) sys(cmdbuf); 2435 0 stevel return (1); 2436 0 stevel } 2437 0 stevel 2438 0 stevel /* 2439 0 stevel * Obtain the cat page that corresponds to the man page. 2440 0 stevel * If it already exists, is up to date, and if we haven't 2441 0 stevel * been told not to use it, use it as it stands. 2442 0 stevel */ 2443 0 stevel regencat = updatedcat = 0; 2444 0 stevel if (compargs || (!catonly && stat(manpname, &mansb) >= 0 && 2445 0 stevel (stat(catpname, &catsb) < 0 || catsb.st_mtime < mansb.st_mtime)) || 2446 0 stevel (access(catpname, R_OK) != 0)) { 2447 0 stevel /* 2448 0 stevel * Construct a shell command line for formatting manpname. 2449 0 stevel * The resulting file goes initially into /tmp. If possible, 2450 0 stevel * it will later be moved to catpname. 2451 0 stevel */ 2452 0 stevel 2453 0 stevel int pipestage = 0; 2454 0 stevel int needcol = 0; 2455 0 stevel char *cbp = cmdbuf; 2456 0 stevel 2457 0 stevel regencat = updatedcat = 1; 2458 0 stevel 2459 0 stevel if (!catmando && !debug && !check_flag) { 2460 0 stevel (void) fprintf(stderr, gettext( 2461 8107 Pu "Reformatting page. Please Wait...")); 2462 0 stevel if (sargs && (newsection != NULL) && 2463 0 stevel (*newsection != '\0')) { 2464 0 stevel (void) fprintf(stderr, gettext( 2465 0 stevel "\nThe directory name has been changed " 2466 0 stevel "to %s\n"), newsection); 2467 0 stevel } 2468 0 stevel (void) fflush(stderr); 2469 0 stevel } 2470 0 stevel 2471 0 stevel /* 2472 0 stevel * in catman command, if the file exists in sman dir already, 2473 0 stevel * don't need to convert the file in man dir to cat dir 2474 0 stevel */ 2475 0 stevel 2476 0 stevel if (!no_sroff && catmando && 2477 8107 Pu match(tmpsubdir, MANDIRNAME, PLEN) && 2478 8107 Pu stat(smantmpname, &smansb) >= 0) 2479 0 stevel return (1); 2480 0 stevel 2481 0 stevel /* 2482 0 stevel * cd to path so that relative .so commands will work 2483 0 stevel * correctly 2484 0 stevel */ 2485 0 stevel (void) sprintf(cbp, "cd %s; ", path); 2486 0 stevel cbp += strlen(cbp); 2487 0 stevel 2488 0 stevel 2489 0 stevel /* 2490 0 stevel * check to see whether it is a sgml file 2491 0 stevel * assume sgml symbol(>!DOCTYPE) can be found in the first 2492 0 stevel * BUFSIZ bytes 2493 0 stevel */ 2494 0 stevel 2495 0 stevel if ((temp = open(manpname, 0)) == -1) { 2496 0 stevel perror(manpname); 2497 0 stevel return (-1); 2498 0 stevel } 2499 0 stevel 2500 0 stevel if ((count = read(temp, prntbuf, BUFSIZ)) <= 0) { 2501 0 stevel perror(manpname); 2502 0 stevel return (-1); 2503 0 stevel } 2504 0 stevel 2505 0 stevel prntbuf[count] = '\0'; /* null terminate */ 2506 0 stevel ptr = prntbuf; 2507 0 stevel if (sgmlcheck((const char *)ptr) == 1) { 2508 0 stevel sgml_flag = 1; 2509 0 stevel if (defaultmandir && *localedir) { 2510 0 stevel (void) sprintf(cbp, "LC_MESSAGES=C %s %s ", 2511 8107 Pu SROFF_CMD, manpname); 2512 0 stevel } else { 2513 0 stevel (void) sprintf(cbp, "%s %s ", 2514 8107 Pu SROFF_CMD, manpname); 2515 0 stevel } 2516 0 stevel cbp += strlen(cbp); 2517 0 stevel } else if (*dir == 's') { 2518 0 stevel (void) close(temp); 2519 0 stevel return (-1); 2520 0 stevel } 2521 0 stevel (void) close(temp); 2522 0 stevel 2523 0 stevel /* 2524 0 stevel * Check for special formatting requirements by examining 2525 0 stevel * manpname's first line preprocessor specifications. 2526 0 stevel */ 2527 0 stevel 2528 0 stevel if (strncmp(manbuf, PREPROC_SPEC, 2529 0 stevel sizeof (PREPROC_SPEC) - 1) == 0) { 2530 0 stevel char *ptp; 2531 0 stevel 2532 0 stevel ptp = manbuf + sizeof (PREPROC_SPEC) - 1; 2533 0 stevel while (*ptp && *ptp != '\n') { 2534 0 stevel const struct preprocessor *pp; 2535 0 stevel 2536 0 stevel /* 2537 0 stevel * Check for a preprocessor we know about. 2538 0 stevel */ 2539 0 stevel for (pp = preprocessors; pp->p_tag; pp++) { 2540 0 stevel if (pp->p_tag == *ptp) 2541 0 stevel break; 2542 0 stevel } 2543 0 stevel if (pp->p_tag == 0) { 2544 0 stevel (void) fprintf(stderr, 2545 0 stevel gettext("unknown preprocessor " 2546 8107 Pu "specifier %c\n"), *ptp); 2547 0 stevel (void) fflush(stderr); 2548 0 stevel return (-1); 2549 0 stevel } 2550 0 stevel 2551 0 stevel /* 2552 0 stevel * Add it to the pipeline. 2553 0 stevel */ 2554 0 stevel (void) sprintf(cbp, "%s %s |", 2555 8107 Pu troffit ? pp->p_troff : pp->p_nroff, 2556 8107 Pu pipestage++ == 0 ? manpname : "-"); 2557 0 stevel cbp += strlen(cbp); 2558 0 stevel 2559 0 stevel /* 2560 0 stevel * Special treatment: if tbl is among the 2561 0 stevel * preprocessors and we'll process with 2562 0 stevel * nroff, we have to pass things through 2563 0 stevel * col at the end of the pipeline. 2564 0 stevel */ 2565 0 stevel if (pp->p_tag == 't' && !troffit) 2566 0 stevel needcol++; 2567 0 stevel 2568 0 stevel ptp++; 2569 0 stevel } 2570 0 stevel } 2571 0 stevel 2572 0 stevel /* 2573 0 stevel * if catman, use the cat page name 2574 0 stevel * otherwise, dup template and create another 2575 0 stevel * (needed for multiple pages) 2576 0 stevel */ 2577 0 stevel if (catmando) 2578 0 stevel tmpname = catpname; 2579 0 stevel else { 2580 0 stevel tmpname = strdup(TEMPLATE); 2581 0 stevel if (tmpname == NULL) 2582 0 stevel malloc_error(); 2583 0 stevel (void) close(mkstemp(tmpname)); 2584 0 stevel } 2585 0 stevel 2586 0 stevel if (! Tflag) { 2587 0 stevel if (*localedir != '\0') { 2588 0 stevel (void) sprintf(macros, "%s/%s", path, MACROF); 2589 0 stevel /* 2590 0 stevel * TRANSLATION_NOTE - message for man -d or catman -p 2591 0 stevel * ex. locale macros = /usr/share/man/ja/tmac.an 2592 0 stevel */ 2593 0 stevel if (debug) 2594 0 stevel (void) printf(gettext( 2595 8107 Pu "\nlocale macros = %s "), 2596 8107 Pu macros); 2597 0 stevel if (stat(macros, &statb) < 0) 2598 0 stevel (void) strcpy(macros, TMAC_AN); 2599 0 stevel /* 2600 0 stevel * TRANSLATION_NOTE - message for man -d or catman -p 2601 0 stevel * ex. macros = /usr/share/man/ja/tman.an 2602 0 stevel */ 2603 0 stevel if (debug) 2604 0 stevel (void) printf(gettext( 2605 8107 Pu "\nmacros = %s\n"), 2606 8107 Pu macros); 2607 0 stevel } 2608 0 stevel } 2609 0 stevel 2610 8107 Pu tmpdir[0] = '\0'; 2611 0 stevel if (sgml_flag == 1) { 2612 0 stevel if (check_flag == 0) { 2613 0 stevel strcpy(tmpdir, "/tmp/sman_XXXXXX"); 2614 0 stevel if ((tempfd = mkstemp(tmpdir)) == -1) { 2615 0 stevel (void) fprintf(stderr, gettext( 2616 0 stevel "%s: null file\n"), tmpdir); 2617 0 stevel (void) fflush(stderr); 2618 0 stevel return (-1); 2619 0 stevel } 2620 0 stevel 2621 0 stevel if (debug) 2622 0 stevel close(tempfd); 2623 0 stevel 2624 0 stevel (void) sprintf(tmpbuf, "%s > %s", 2625 8107 Pu cmdbuf, tmpdir); 2626 0 stevel if (sys(tmpbuf)) { 2627 0 stevel /* 2628 0 stevel * TRANSLATION_NOTE - message for man -d or catman -p 2629 0 stevel * Error message if sys(%s) failed 2630 0 stevel */ 2631 0 stevel (void) fprintf(stderr, gettext( 2632 8107 Pu "sys(%s) fail!\n"), tmpbuf); 2633 0 stevel (void) fprintf(stderr, 2634 8107 Pu gettext(" aborted (sorry)\n")); 2635 0 stevel (void) fflush(stderr); 2636 0 stevel /* release memory for tmpname */ 2637 0 stevel if (!catmando) { 2638 0 stevel (void) unlink(tmpdir); 2639 0 stevel (void) unlink(tmpname); 2640 0 stevel free(tmpname); 2641 0 stevel } 2642 0 stevel return (-1); 2643 0 stevel } else if (debug == 0) { 2644 0 stevel if ((md = fdopen(tempfd, "r")) 2645 0 stevel == NULL) { 2646 0 stevel (void) fprintf(stderr, gettext( 2647 0 stevel "%s: null file\n"), tmpdir); 2648 0 stevel (void) fflush(stderr); 2649 0 stevel close(tempfd); 2650 0 stevel /* release memory for tmpname */ 2651 0 stevel if (!catmando) 2652 0 stevel free(tmpname); 2653 0 stevel return (-1); 2654 0 stevel } 2655 0 stevel 2656 0 stevel /* if the file is empty, */ 2657 0 stevel /* it's a fragment, do nothing */ 2658 0 stevel if (fgets(manbuf, BUFSIZ-1, md) 2659 8107 Pu == NULL) { 2660 0 stevel (void) fclose(md); 2661 0 stevel /* release memory for tmpname */ 2662 0 stevel if (!catmando) 2663 0 stevel free(tmpname); 2664 0 stevel return (1); 2665 0 stevel } 2666 0 stevel (void) fclose(md); 2667 0 stevel 2668 0 stevel if (strncmp(manbuf, DOT_SO, 2669 8107 Pu sizeof (DOT_SO) - 1) == 0) { 2670 0 stevel if (!compargs) { 2671 0 stevel check_flag = 1; 2672 0 stevel (void) unlink(tmpdir); 2673 0 stevel (void) unlink(tmpname); 2674 0 stevel /* release memory for tmpname */ 2675 0 stevel if (!catmando) 2676 0 stevel free(tmpname); 2677 0 stevel goto so_again; 2678 0 stevel } else { 2679 0 stevel (void) unlink(tmpdir); 2680 0 stevel strcpy(tmpdir, 2681 0 stevel "/tmp/sman_XXXXXX"); 2682 0 stevel tempfd = mkstemp(tmpdir); 2683 0 stevel if ((tempfd == -1) || 2684 0 stevel (md = fdopen(tempfd, "w")) 2685 0 stevel == NULL) { 2686 0 stevel (void) fprintf(stderr, 2687 8107 Pu gettext( 2688 0 stevel "%s: null file\n"), 2689 0 stevel tmpdir); 2690 0 stevel (void) fflush(stderr); 2691 0 stevel if (tempfd != -1) 2692 0 stevel close(tempfd); 2693 0 stevel /* release memory for tmpname */ 2694 0 stevel if (!catmando) 2695 0 stevel free(tmpname); 2696 0 stevel return (-1); 2697 0 stevel } 2698 0 stevel if ((new_m = strrchr(manbuf, '/')) != NULL) { 2699 0 stevel (void) fprintf(md, ".so man%s%s\n", dir+plen, new_m); 2700 0 stevel } else { 2701 0 stevel /* 2702 0 stevel * TRANSLATION_NOTE - message for catman -c 2703 0 stevel * Error message if unable to get file name 2704 0 stevel */ 2705 0 stevel (void) fprintf(stderr, 2706 8107 Pu gettext("file not found\n")); 2707 0 stevel (void) fflush(stderr); 2708 0 stevel return (-1); 2709 0 stevel } 2710 0 stevel (void) fclose(md); 2711 0 stevel } 2712 0 stevel } 2713 0 stevel } 2714 0 stevel if (catmando && compargs) 2715 0 stevel (void) sprintf(cmdbuf, "cat %s > %s", 2716 8107 Pu tmpdir, manpname_sgml); 2717 0 stevel else 2718 8107 Pu (void) sprintf(cmdbuf, " cat %s | tbl | eqn | %s %s - %s > %s", 2719 8107 Pu tmpdir, troffit ? troffcmd : "nroff -u0 -Tlp", 2720 8107 Pu macros, troffit ? "" : " | col -x", tmpname); 2721 0 stevel } else 2722 0 stevel if (catmando && compargs) 2723 0 stevel (void) sprintf(cbp, " > %s", 2724 8107 Pu manpname_sgml); 2725 0 stevel else 2726 8107 Pu (void) sprintf(cbp, " | tbl | eqn | %s %s - %s > %s", 2727 8107 Pu troffit ? troffcmd : "nroff -u0 -Tlp", 2728 8107 Pu macros, troffit ? "" : " | col -x", tmpname); 2729 0 stevel 2730 0 stevel } else 2731 8107 Pu (void) sprintf(cbp, "%s %s %s%s > %s", 2732 8107 Pu troffit ? troffcmd : "nroff -u0 -Tlp", 2733 8107 Pu macros, pipestage == 0 ? manpname : "-", 2734 8107 Pu troffit ? "" : " | col -x", tmpname); 2735 0 stevel 2736 0 stevel /* Reformat the page. */ 2737 0 stevel if (sys(cmdbuf)) { 2738 0 stevel /* 2739 0 stevel * TRANSLATION_NOTE - message for man -d or catman -p 2740 0 stevel * Error message if sys(%s) failed 2741 0 stevel */ 2742 0 stevel (void) fprintf(stderr, gettext( 2743 8107 Pu "sys(%s) fail!\n"), cmdbuf); 2744 0 stevel (void) fprintf(stderr, gettext(" aborted (sorry)\n")); 2745 0 stevel (void) fflush(stderr); 2746 0 stevel (void) unlink(tmpname); 2747 0 stevel /* release memory for tmpname */ 2748 0 stevel if (!catmando) 2749 0 stevel free(tmpname); 2750 0 stevel return (-1); 2751 0 stevel } 2752 0 stevel 2753 8107 Pu if (tmpdir[0] != '\0') 2754 8107 Pu (void) unlink(tmpdir); 2755 0 stevel 2756 0 stevel if (catmando) 2757 0 stevel return (1); 2758 0 stevel 2759 0 stevel /* 2760 0 stevel * Attempt to move the cat page to its proper home. 2761 0 stevel */ 2762 0 stevel (void) sprintf(cmdbuf, 2763 8107 Pu "trap '' 1 15; /usr/bin/mv -f %s %s 2> /dev/null", 2764 8107 Pu tmpname, 2765 8107 Pu catpname); 2766 0 stevel if (sys(cmdbuf)) 2767 0 stevel updatedcat = 0; 2768 0 stevel else if (debug == 0) 2769 0 stevel (void) chmod(catpname, 0644); 2770 0 stevel 2771 0 stevel if (debug) { 2772 0 stevel /* release memory for tmpname */ 2773 0 stevel if (!catmando) 2774 0 stevel free(tmpname); 2775 0 stevel (void) unlink(tmpname); 2776 0 stevel return (1); 2777 0 stevel } 2778 0 stevel 2779 0 stevel (void) fprintf(stderr, gettext(" done\n")); 2780 0 stevel (void) fflush(stderr); 2781 0 stevel } 2782 0 stevel 2783 0 stevel /* 2784 0 stevel * Save file name (dup if necessary) 2785 0 stevel * to view later 2786 0 stevel * fix for 1123802 - don't save names if we are invoked as catman 2787 0 stevel */ 2788 0 stevel if (!catmando) { 2789 0 stevel char **tmpp; 2790 0 stevel int dup; 2791 0 stevel char *newpage; 2792 0 stevel 2793 0 stevel if (regencat && !updatedcat) 2794 0 stevel newpage = tmpname; 2795 0 stevel else { 2796 0 stevel newpage = strdup(catpname); 2797 0 stevel if (newpage == NULL) 2798 0 stevel malloc_error(); 2799 0 stevel } 2800 0 stevel /* make sure we don't add a dup */ 2801 0 stevel dup = 0; 2802 0 stevel for (tmpp = pages; tmpp < endp; tmpp++) { 2803 0 stevel if (strcmp(*tmpp, newpage) == 0) { 2804 0 stevel dup = 1; 2805 0 stevel break; 2806 0 stevel } 2807 0 stevel } 2808 0 stevel if (!dup) 2809 0 stevel *endp++ = newpage; 2810 0 stevel if (endp >= &pages[MAXPAGES]) { 2811 0 stevel fprintf(stderr, 2812 0 stevel gettext("Internal pages array overflow!\n")); 2813 0 stevel exit(1); 2814 0 stevel } 2815 0 stevel } 2816 0 stevel 2817 0 stevel return (regencat); 2818 0 stevel } 2819 0 stevel 2820 0 stevel /* 2821 0 stevel * Add <localedir> to the path. 2822 0 stevel */ 2823 0 stevel 2824 0 stevel static char * 2825 0 stevel addlocale(char *path) 2826 0 stevel { 2827 0 stevel 2828 0 stevel char *tmp; 2829 0 stevel 2830 0 stevel tmp = malloc(strlen(path) + strlen(localedir) + 2); 2831 0 stevel if (tmp == NULL) 2832 0 stevel malloc_error(); 2833 0 stevel (void) sprintf(tmp, "%s/%s", path, localedir); 2834 0 stevel return (tmp); 2835 0 stevel 2836 0 stevel } 2837 0 stevel 2838 0 stevel /* 2839 0 stevel * From the configuration file "man.cf", get the order of suffices of 2840 0 stevel * sub-mandirs to be used in the search path for a given mandir. 2841 0 stevel */ 2842 0 stevel 2843 0 stevel static char * 2844 0 stevel check_config(char *path) 2845 0 stevel { 2846 0 stevel FILE *fp; 2847 0 stevel static char submandir[BUFSIZ]; 2848 0 stevel char *sect; 2849 0 stevel char fname[MAXPATHLEN]; 2850 0 stevel 2851 0 stevel (void) sprintf(fname, "%s/%s", path, CONFIG); 2852 0 stevel 2853 0 stevel if ((fp = fopen(fname, "r")) == NULL) 2854 0 stevel return (NULL); 2855 0 stevel else { 2856 0 stevel if (get_manconfig(fp, submandir) == -1) { 2857 0 stevel (void) fclose(fp); 2858 0 stevel return (NULL); 2859 0 stevel } 2860 0 stevel 2861 0 stevel (void) fclose(fp); 2862 0 stevel 2863 0 stevel sect = strchr(submandir, '='); 2864 0 stevel if (sect != NULL) 2865 0 stevel return (++sect); 2866 0 stevel else 2867 0 stevel return (NULL); 2868 0 stevel } 2869 0 stevel } 2870 0 stevel 2871 0 stevel /* 2872 0 stevel * This routine is for getting the MANSECTS entry from man.cf. 2873 0 stevel * It sets submandir to the line in man.cf that contains 2874 0 stevel * MANSECTS=sections[,sections]... 2875 0 stevel */ 2876 0 stevel 2877 0 stevel static int 2878 0 stevel get_manconfig(FILE *fp, char *submandir) 2879 0 stevel { 2880 0 stevel char *s, *t, *rc; 2881 0 stevel char buf[BUFSIZ]; 2882 0 stevel 2883 0 stevel while ((rc = fgets(buf, sizeof (buf), fp)) != NULL) { 2884 0 stevel 2885 0 stevel /* 2886 0 stevel * skip leading blanks 2887 0 stevel */ 2888 0 stevel for (t = buf; *t != '\0'; t++) { 2889 0 stevel if (!isspace(*t)) 2890 0 stevel break; 2891 0 stevel } 2892 0 stevel /* 2893 0 stevel * skip line that starts with '#' or empty line 2894 0 stevel */ 2895 0 stevel if (*t == '#' || *t == '\0') 2896 0 stevel continue; 2897 0 stevel 2898 0 stevel if (strstr(buf, "MANSECTS") != NULL) 2899 0 stevel break; 2900 0 stevel } 2901 0 stevel 2902 0 stevel /* 2903 0 stevel * the man.cf file doesn't have a MANSECTS entry 2904 0 stevel */ 2905 0 stevel if (rc == NULL) 2906 0 stevel return (-1); 2907 0 stevel 2908 0 stevel s = strchr(buf, '\n'); 2909 0 stevel *s = '\0'; /* replace '\n' with '\0' */ 2910 0 stevel 2911 0 stevel (void) strcpy(submandir, buf); 2912 0 stevel return (0); 2913 0 stevel } 2914 0 stevel 2915 0 stevel static void 2916 0 stevel malloc_error(void) 2917 0 stevel { 2918 0 stevel (void) fprintf(stderr, gettext( 2919 8107 Pu "Memory allocation failed.\n")); 2920 0 stevel exit(1); 2921 0 stevel } 2922 0 stevel 2923 0 stevel static int 2924 0 stevel sgmlcheck(const char *s1) 2925 0 stevel { 2926 0 stevel const char *s2 = SGML_SYMBOL; 2927 0 stevel int len; 2928 0 stevel 2929 0 stevel while (*s1) { 2930 0 stevel /* 2931 0 stevel * Assume the first character of SGML_SYMBOL(*s2) is '<'. 2932 0 stevel * Therefore, not necessary to do toupper(*s1) here. 2933 0 stevel */ 2934 0 stevel if (*s1 == *s2) { 2935 0 stevel /* 2936 0 stevel * *s1 is '<'. Check the following substring matches 2937 0 stevel * with "!DOCTYPE". 2938 0 stevel */ 2939 0 stevel s1++; 2940 0 stevel if (strncasecmp(s1, s2 + 1, SGML_SYMBOL_LEN - 1) 2941 8107 Pu == 0) { 2942 0 stevel /* 2943 0 stevel * SGML_SYMBOL found 2944 0 stevel */ 2945 0 stevel return (1); 2946 0 stevel } 2947 0 stevel continue; 2948 0 stevel } else if (isascii(*s1)) { 2949 0 stevel /* 2950 0 stevel * *s1 is an ASCII char 2951 0 stevel * Skip one character 2952 0 stevel */ 2953 0 stevel s1++; 2954 0 stevel continue; 2955 0 stevel } else { 2956 0 stevel /* 2957 0 stevel * *s1 is a non-ASCII char or 2958 0 stevel * the first byte of the multibyte char. 2959 0 stevel * Skip one character 2960 0 stevel */ 2961 0 stevel len = mblen(s1, MB_CUR_MAX); 2962 0 stevel if (len == -1) 2963 0 stevel len = 1; 2964 0 stevel s1 += len; 2965 0 stevel continue; 2966 0 stevel } 2967 0 stevel } 2968 0 stevel /* 2969 0 stevel * SGML_SYMBOL not found 2970 0 stevel */ 2971 0 stevel return (0); 2972 0 stevel } 2973 0 stevel 2974 0 stevel /* 2975 6639 samf * Initializes the bintoman array with appropriate device and inode info 2976 0 stevel */ 2977 0 stevel 2978 6639 samf static void 2979 6639 samf init_bintoman(void) 2980 0 stevel { 2981 6639 samf int i; 2982 6639 samf struct stat sb; 2983 0 stevel 2984 6639 samf for (i = 0; bintoman[i].bindir != NULL; i++) { 2985 6639 samf if (stat(bintoman[i].bindir, &sb) == 0) { 2986 6639 samf bintoman[i].dev = sb.st_dev; 2987 6639 samf bintoman[i].ino = sb.st_ino; 2988 6639 samf } else { 2989 6639 samf bintoman[i].dev = NODEV; 2990 6639 samf } 2991 0 stevel } 2992 0 stevel } 2993 0 stevel 2994 0 stevel /* 2995 6639 samf * If a duplicate is found, return 1 2996 6639 samf * If a duplicate is not found, add it to the dupnode list and return 0 2997 6639 samf */ 2998 6639 samf static int 2999 7172 samf dupcheck(struct man_node *mnp, struct dupnode **dnp) 3000 7172 samf { 3001 6639 samf struct dupnode *curdnp; 3002 6639 samf struct secnode *cursnp; 3003 6639 samf struct stat sb; 3004 6639 samf int i; 3005 6639 samf int rv = 1; 3006 6639 samf int dupfound; 3007 6639 samf 3008 6639 samf /* 3009 6639 samf * If the path doesn't exist, treat it as a duplicate 3010 6639 samf */ 3011 6639 samf if (stat(mnp->path, &sb) != 0) { 3012 7172 samf return (1); 3013 7172 samf } 3014 7172 samf 3015 7172 samf /* 3016 7172 samf * If no sections were found in the man dir, treat it as duplicate 3017 7172 samf */ 3018 7172 samf if (mnp->secv == NULL) { 3019 6639 samf return (1); 3020 6639 samf } 3021 6639 samf 3022 6639 samf /* 3023 6639 samf * Find the dupnode structure for the previous time this directory 3024 6639 samf * was looked at. Device and inode numbers are compared so that 3025 6639 samf * directories that are reached via different paths (e.g. /usr/man vs. 3026 6639 samf * /usr/share/man) are treated as equivalent. 3027 6639 samf */ 3028 6639 samf for (curdnp = *dnp; curdnp != NULL; curdnp = curdnp->next) { 3029 6639 samf if (curdnp->dev == sb.st_dev && curdnp->ino == sb.st_ino) { 3030 6639 samf break; 3031 6639 samf } 3032 6639 samf } 3033 6639 samf 3034 6639 samf /* 3035 6639 samf * First time this directory has been seen. Add a new node to the 3036 6639 samf * head of the list. Since all entries are guaranteed to be unique 3037 6639 samf * copy all sections to new node. 3038 6639 samf */ 3039 6639 samf if (curdnp == NULL) { 3040 6639 samf if ((curdnp = calloc(1, sizeof (struct dupnode))) == NULL) { 3041 6639 samf malloc_error(); 3042 6639 samf } 3043 6639 samf for (i = 0; mnp->secv[i] != NULL; i++) { 3044 6639 samf if ((cursnp = calloc(1, sizeof (struct secnode))) 3045 6639 samf == NULL) { 3046 6639 samf malloc_error(); 3047 6639 samf } 3048 6639 samf cursnp->next = curdnp->secl; 3049 6639 samf curdnp->secl = cursnp; 3050 6639 samf if ((cursnp->secp = strdup(mnp->secv[i])) == NULL) { 3051 6639 samf malloc_error(); 3052 6639 samf } 3053 6639 samf } 3054 6639 samf curdnp->dev = sb.st_dev; 3055 6639 samf curdnp->ino = sb.st_ino; 3056 6639 samf curdnp->next = *dnp; 3057 6639 samf *dnp = curdnp; 3058 6639 samf return (0); 3059 6639 samf } 3060 6639 samf 3061 6639 samf /* 3062 6639 samf * Traverse the section vector in the man_node and the section list 3063 6639 samf * in dupnode cache to eliminate all duplicates from man_node 3064 6639 samf */ 3065 6639 samf for (i = 0; mnp->secv[i] != NULL; i++) { 3066 6639 samf dupfound = 0; 3067 6639 samf for (cursnp = curdnp->secl; cursnp != NULL; 3068 6639 samf cursnp = cursnp->next) { 3069 6639 samf if (strcmp(mnp->secv[i], cursnp->secp) == 0) { 3070 6639 samf dupfound = 1; 3071 6639 samf break; 3072 6639 samf } 3073 6639 samf } 3074 6639 samf if (dupfound) { 3075 6639 samf mnp->secv[i][0] = '\0'; 3076 6639 samf continue; 3077 6639 samf } 3078 6639 samf 3079 6639 samf 3080 6639 samf /* 3081 6639 samf * Update curdnp and set return value to indicate that this 3082 6639 samf * was not all duplicates. 3083 6639 samf */ 3084 6639 samf if ((cursnp = calloc(1, sizeof (struct secnode))) == NULL) { 3085 6639 samf malloc_error(); 3086 6639 samf } 3087 6639 samf cursnp->next = curdnp->secl; 3088 6639 samf curdnp->secl = cursnp; 3089 6639 samf if ((cursnp->secp = strdup(mnp->secv[i])) == NULL) { 3090 6639 samf malloc_error(); 3091 6639 samf } 3092 6639 samf rv = 0; 3093 6639 samf } 3094 6639 samf 3095 6639 samf return (rv); 3096 6639 samf } 3097 6639 samf 3098 6639 samf /* 3099 6639 samf * Given a bin directory, return the corresponding man directory. 3100 6639 samf * Return string must be free()d by the caller. 3101 6639 samf * 3102 6639 samf * NULL will be returned if no matching man directory can be found. 3103 0 stevel */ 3104 0 stevel 3105 6639 samf static char * 3106 6639 samf path_to_manpath(char *bindir) 3107 6639 samf { 3108 6639 samf char *mand, *p; 3109 6639 samf int i; 3110 6639 samf struct stat sb; 3111 6639 samf 3112 6639 samf /* 3113 6639 samf * First look for known translations for specific bin paths 3114 6639 samf */ 3115 6639 samf if (stat(bindir, &sb) != 0) { 3116 6639 samf return (NULL); 3117 6639 samf } 3118 6639 samf for (i = 0; bintoman[i].bindir != NULL; i++) { 3119 6639 samf if (sb.st_dev == bintoman[i].dev && 3120 6639 samf sb.st_ino == bintoman[i].ino) { 3121 6639 samf if ((mand = strdup(bintoman[i].mandir)) == NULL) { 3122 6639 samf malloc_error(); 3123 6639 samf } 3124 6639 samf if ((p = strchr(mand, ',')) != NULL) { 3125 6639 samf *p = '\0'; 3126 6639 samf } 3127 6639 samf if (stat(mand, &sb) != 0) { 3128 6639 samf free(mand); 3129 6639 samf return (NULL); 3130 6639 samf } 3131 6639 samf if (p != NULL) { 3132 6639 samf *p = ','; 3133 6639 samf } 3134 6639 samf return (mand); 3135 6639 samf } 3136 6639 samf } 3137 6639 samf 3138 6639 samf /* 3139 6639 samf * No specific translation found. Try `dirname $bindir`/man 3140 6639 samf * and `dirname $bindir`/share/man 3141 6639 samf */ 3142 6639 samf if ((mand = malloc(PATH_MAX)) == NULL) { 3143 6639 samf malloc_error(); 3144 6639 samf } 3145 6639 samf 3146 6639 samf if (strlcpy(mand, bindir, PATH_MAX) >= PATH_MAX) { 3147 6639 samf free(mand); 3148 6639 samf return (NULL); 3149 6639 samf } 3150 6639 samf 3151 6639 samf /* 3152 6639 samf * Advance to end of buffer, strip trailing /'s then remove last 3153 6639 samf * directory component. 3154 6639 samf */ 3155 6639 samf for (p = mand; *p != '\0'; p++) 3156 6639 samf ; 3157 6639 samf for (; p > mand && *p == '/'; p--) 3158 6639 samf ; 3159 6639 samf for (; p > mand && *p != '/'; p--) 3160 6639 samf ; 3161 6639 samf if (p == mand && *p == '.') { 3162 6639 samf if (realpath("..", mand) == NULL) { 3163 6639 samf free(mand); 3164 6639 samf return (NULL); 3165 6639 samf } 3166 7172 samf for (; *p != '\0'; p++) 3167 7172 samf ; 3168 6639 samf } else { 3169 6639 samf *p = '\0'; 3170 6639 samf } 3171 6639 samf 3172 6639 samf if (strlcat(mand, "/man", PATH_MAX) >= PATH_MAX) { 3173 6639 samf free(mand); 3174 6639 samf return (NULL); 3175 6639 samf } 3176 6639 samf 3177 7172 samf if ((stat(mand, &sb) == 0) && S_ISDIR(sb.st_mode)) { 3178 6639 samf return (mand); 3179 6639 samf } 3180 6639 samf 3181 6639 samf /* 3182 6639 samf * Strip the /man off and try /share/man 3183 6639 samf */ 3184 6639 samf *p = '\0'; 3185 6639 samf if (strlcat(mand, "/share/man", PATH_MAX) >= PATH_MAX) { 3186 6639 samf free(mand); 3187 6639 samf return (NULL); 3188 6639 samf } 3189 7172 samf if ((stat(mand, &sb) == 0) && S_ISDIR(sb.st_mode)) { 3190 7172 samf return (mand); 3191 6639 samf } 3192 6639 samf 3193 7172 samf /* 3194 7172 samf * No man or share/man directory found 3195 7172 samf */ 3196 7172 samf free(mand); 3197 7172 samf return (NULL); 3198 6639 samf } 3199 6639 samf 3200 6639 samf /* 3201 6639 samf * Free a linked list of dupnode structs 3202 6639 samf */ 3203 0 stevel void 3204 6639 samf free_dupnode(struct dupnode *dnp) { 3205 6639 samf struct dupnode *dnp2; 3206 6639 samf struct secnode *snp; 3207 6639 samf 3208 6639 samf while (dnp != NULL) { 3209 6639 samf dnp2 = dnp; 3210 6639 samf dnp = dnp->next; 3211 6639 samf while (dnp2->secl != NULL) { 3212 6639 samf snp = dnp2->secl; 3213 6639 samf dnp2->secl = dnp2->secl->next; 3214 6639 samf free(snp->secp); 3215 6639 samf free(snp); 3216 6639 samf } 3217 6639 samf free(dnp2); 3218 6639 samf } 3219 6639 samf } 3220 6639 samf 3221 6639 samf /* 3222 6639 samf * prints manp linked list to stdout. 3223 6639 samf * 3224 6639 samf * If namep is NULL, output can be used for setting MANPATH. 3225 6639 samf * 3226 6639 samf * If namep is not NULL output is two columns. First column is the string 3227 6639 samf * pointed to by namep. Second column is a MANPATH-compatible representation 3228 6639 samf * of manp linked list. 3229 6639 samf */ 3230 6639 samf void 3231 6639 samf print_manpath(struct man_node *manp, char *namep) 3232 0 stevel { 3233 6639 samf char colon[2]; 3234 6639 samf char **secp; 3235 0 stevel 3236 6639 samf if (namep != NULL) { 3237 6639 samf (void) printf("%s ", namep); 3238 6639 samf } 3239 6639 samf 3240 6639 samf colon[0] = '\0'; 3241 6639 samf colon[1] = '\0'; 3242 6639 samf 3243 6639 samf for (; manp != NULL; manp = manp->next) { 3244 6639 samf (void) printf("%s%s", colon, manp->path); 3245 6639 samf colon[0] = ':'; 3246 6639 samf 3247 6639 samf /* 3248 6639 samf * If man.cf or a directory scan was used to create section 3249 6639 samf * list, do not print section list again. If the output of 3250 6639 samf * man -p is used to set MANPATH, subsequent runs of man 3251 6639 samf * will re-read man.cf and/or scan man directories as 3252 6639 samf * required. 3253 6639 samf */ 3254 6639 samf if (manp->defsrch != 0) { 3255 6639 samf continue; 3256 6639 samf } 3257 6639 samf 3258 6639 samf for (secp = manp->secv; *secp != NULL; secp++) { 3259 6639 samf /* 3260 6639 samf * Section deduplication may have eliminated some 3261 6639 samf * sections from the vector. Avoid displaying this 3262 6639 samf * detail which would appear as ",," in output 3263 6639 samf */ 3264 6639 samf if ((*secp)[0] != '\0') { 3265 6639 samf (void) printf(",%s", *secp); 3266 6639 samf } 3267 6639 samf } 3268 6639 samf } 3269 6639 samf (void) printf("\n"); 3270 0 stevel } 3271