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