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