1 /* $NetBSD: man.c,v 1.56 2013/07/30 15:10:04 joerg Exp $ */
4 * Copyright (c) 1987, 1993, 1994, 1995
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
35 __COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994, 1995\
36 The Regents of the University of California. All rights reserved.");
41 static char sccsid
[] = "@(#)man.c 8.17 (Berkeley) 1/31/95";
43 __RCSID("$NetBSD: man.c,v 1.56 2013/07/30 15:10:04 joerg Exp $");
47 #include <sys/param.h>
48 #include <sys/queue.h>
50 #include <sys/utsname.h>
67 #include "pathnames.h"
70 #define MAN_DEBUG 0 /* debug path output */
74 * manstate: structure collecting the current global state so we can
75 * easily identify it and pass it to helper functions in one arg.
78 /* command line flags */
79 int all
; /* -a: show all matches rather than first */
80 int cat
; /* -c: do not use a pager */
81 char *conffile
; /* -C: use alternate config file */
82 int how
; /* -h: show SYNOPSIS only */
83 char *manpath
; /* -M: alternate MANPATH */
84 char *addpath
; /* -m: add these dirs to front of manpath */
85 char *pathsearch
; /* -S: path of man must contain this string */
86 char *sectionname
; /* -s: limit search to a given man section */
87 int where
; /* -w: just show paths of all matching files */
88 int getpath
; /* -p: print the path of directories containing man pages */
90 /* important tags from the config file */
91 TAG
*defaultpath
; /* _default: default MANPATH */
92 TAG
*subdirs
; /* _subdir: default subdir search list */
93 TAG
*suffixlist
; /* _suffix: for files that can be cat()'d */
94 TAG
*buildlist
; /* _build: for files that must be built */
96 /* tags for internal use */
97 TAG
*intmp
; /* _intmp: tmp files we must cleanup */
98 TAG
*missinglist
; /* _missing: pages we couldn't find */
99 TAG
*mymanpath
; /* _new_path: final version of MANPATH */
100 TAG
*section
; /* <sec>: tag for m.sectionname */
102 /* other misc stuff */
103 const char *pager
; /* pager to use */
104 size_t pagerlen
; /* length of the above */
105 const char *machine
; /* machine */
106 const char *machclass
; /* machine class */
112 static void build_page(const char *, char **, struct manstate
*);
113 static void cat(const char *);
114 static const char *check_pager(const char *);
115 static int cleanup(void);
116 static void how(const char *);
117 static void jump(char **, const char *, const char *) __dead2
;
118 static int manual(char *, struct manstate
*, glob_t
*);
119 static void onsig(int);
120 static void usage(void) __dead2
;
121 static void addpath(struct manstate
*, const char *, size_t, const char *);
122 static const char *getclass(const char *);
123 static void printmanpath(struct manstate
*);
129 main(int argc
, char **argv
)
131 static struct manstate m
;
132 int ch
, abs_section
, found
;
133 ENTRY
*esubd
, *epath
;
138 setprogname(argv
[0]);
139 setlocale(LC_ALL
, "");
141 * parse command line...
143 while ((ch
= getopt(argc
, argv
, "-aC:cfhkM:m:P:ps:S:w")) != -1)
152 case '-': /* XXX: '-' is a deprecated version of '-c' */
162 case 'P': /* -P for backward compatibility */
163 m
.manpath
= strdup(optarg
);
169 * The -f and -k options are backward compatible,
170 * undocumented ways of calling whatis(1) and apropos(1).
173 jump(argv
, "-f", "whatis");
176 jump(argv
, "-k", "apropos");
179 if (m
.sectionname
!= NULL
)
181 m
.sectionname
= optarg
;
184 m
.pathsearch
= optarg
;
196 if (!m
.getpath
&& !argc
)
200 * read the configuration file and collect any other information
201 * we will need (machine type, pager, section [if specified
202 * without '-s'], and MANPATH through the environment).
204 config(m
.conffile
); /* exits on error ... */
206 if ((m
.machine
= getenv("MACHINE")) == NULL
) {
207 struct utsname utsname
;
209 if (uname(&utsname
) == -1)
210 err(EXIT_FAILURE
, "uname");
211 m
.machine
= utsname
.machine
;
214 m
.machclass
= getclass(m
.machine
);
216 if (!m
.cat
&& !m
.how
&& !m
.where
) { /* if we need a pager ... */
217 if (!isatty(STDOUT_FILENO
)) {
220 if ((m
.pager
= getenv("PAGER")) != NULL
&&
222 m
.pager
= check_pager(m
.pager
);
224 m
.pager
= _PATH_PAGER
;
225 m
.pagerlen
= strlen(m
.pager
);
229 /* do we need to set m.section to a non-null value? */
232 m
.section
= gettag(m
.sectionname
, 0); /* -s must be a section */
233 if (m
.section
== NULL
)
234 errx(EXIT_FAILURE
, "unknown section: %s", m
.sectionname
);
236 } else if (argc
> 1) {
238 m
.section
= gettag(*argv
, 0); /* might be a section? */
246 if (m
.manpath
== NULL
)
247 m
.manpath
= getenv("MANPATH"); /* note: -M overrides getenv */
251 * get default values from config file, plus create the tags we
252 * use for keeping internal state. make sure all our mallocs
256 m
.defaultpath
= gettag("_default", 1);
257 m
.subdirs
= gettag("_subdir", 1);
258 m
.suffixlist
= gettag("_suffix", 1);
259 m
.buildlist
= gettag("_build", 1);
261 m
.mymanpath
= gettag("_new_path", 1);
262 m
.missinglist
= gettag("_missing", 1);
263 m
.intmp
= gettag("_intmp", 1);
264 if (!m
.defaultpath
|| !m
.subdirs
|| !m
.suffixlist
|| !m
.buildlist
||
265 !m
.mymanpath
|| !m
.missinglist
|| !m
.intmp
)
266 errx(EXIT_FAILURE
, "malloc failed");
269 * are we using a section whose elements are all absolute paths?
270 * (we only need to look at the first entry on the section list,
271 * as config() will ensure that any additional entries will match
274 abs_section
= (m
.section
!= NULL
&&
275 !TAILQ_EMPTY(&m
.section
->entrylist
) &&
276 *(TAILQ_FIRST(&m
.section
->entrylist
)->s
) == '/');
279 * now that we have all the data we need, we must determine the
280 * manpath we are going to use to find the requested entries using
281 * the following steps...
283 * [1] if the user specified a section and that section's elements
284 * from the config file are all absolute paths, then we override
285 * defaultpath and -M/MANPATH with the section's absolute paths.
288 m
.manpath
= NULL
; /* ignore -M/MANPATH */
289 m
.defaultpath
= m
.section
; /* overwrite _default path */
290 m
.section
= NULL
; /* promoted to defaultpath */
294 * [2] section can now only be non-null if the user asked for
295 * a section and that section's elements did not have
296 * absolute paths. in this case we use the section's
297 * elements to override _subdir from the config file.
299 * after this step, we are done processing "m.section"...
302 m
.subdirs
= m
.section
;
305 * [3] we need to setup the path we want to use (m.mymanpath).
306 * if the user gave us a path (m.manpath) use it, otherwise
307 * go with the default. in either case we need to append
308 * the subdir and machine spec to each element of the path.
310 * for absolute section paths that come from the config file,
311 * we only append the subdir spec if the path ends in
312 * a '/' --- elements that do not end in '/' are assumed to
313 * not have subdirectories. this is mainly for backward compat,
314 * but it allows non-subdir configs like:
315 * sect3 /usr/share/man/{old/,}cat3
316 * doc /usr/{pkg,share}/doc/{sendmail/op,sendmail/intro}
318 * note that we try and be careful to not put double slashes
319 * in the path (e.g. we want /usr/share/man/man1, not
320 * /usr/share/man//man1) because "more" will put the filename
321 * we generate in its prompt and the double slashes look ugly.
325 /* note: strtok is going to destroy m.manpath */
326 for (p
= strtok(m
.manpath
, ":") ; p
; p
= strtok(NULL
, ":")) {
330 TAILQ_FOREACH(esubd
, &m
.subdirs
->entrylist
, q
)
331 addpath(&m
, p
, len
, esubd
->s
);
336 TAILQ_FOREACH(epath
, &m
.defaultpath
->entrylist
, q
) {
337 /* handle trailing "/" magic here ... */
338 if (abs_section
&& epath
->s
[epath
->len
- 1] != '/') {
339 addpath(&m
, "", 1, epath
->s
);
343 TAILQ_FOREACH(esubd
, &m
.subdirs
->entrylist
, q
)
344 addpath(&m
, epath
->s
, epath
->len
, esubd
->s
);
350 * [4] finally, prepend the "-m" m.addpath to mymanpath if it
351 * was specified. subdirs and machine are always applied to
356 /* note: strtok is going to destroy m.addpath */
357 for (p
= strtok(m
.addpath
, ":") ; p
; p
= strtok(NULL
, ":")) {
361 TAILQ_FOREACH(esubd
, &m
.subdirs
->entrylist
, q
)
362 addpath(&m
, p
, len
, esubd
->s
);
371 * now m.mymanpath is complete!
374 printf("mymanpath:\n");
375 TAILQ_FOREACH(epath
, &m
.mymanpath
->entrylist
, q
) {
376 printf("\t%s\n", epath
->s
);
381 * start searching for matching files and format them if necessary.
382 * setup an interrupt handler so that we can ensure that temporary
385 (void)signal(SIGINT
, onsig
);
386 (void)signal(SIGHUP
, onsig
);
387 (void)signal(SIGPIPE
, onsig
);
389 memset(&pg
, 0, sizeof(pg
));
390 for (found
= 0; *argv
; ++argv
)
391 if (manual(*argv
, &m
, &pg
)) {
395 /* if nothing found, we're done. */
402 * handle the simple display cases first (m.cat, m.how, m.where)
405 for (ap
= pg
.gl_pathv
; *ap
!= NULL
; ++ap
) {
413 for (ap
= pg
.gl_pathv
; *ap
!= NULL
; ++ap
) {
421 for (ap
= pg
.gl_pathv
; *ap
!= NULL
; ++ap
) {
424 (void)printf("%s\n", *ap
);
430 * normal case - we display things in a single command, so
431 * build a list of things to display. first compute total
432 * length of buffer we will need so we can malloc it.
434 for (ap
= pg
.gl_pathv
, len
= m
.pagerlen
+ 1; *ap
!= NULL
; ++ap
) {
437 len
+= strlen(*ap
) + 1;
439 if ((cmd
= malloc(len
)) == NULL
) {
445 /* now build the command string... */
448 memcpy(p
, m
.pager
, len
);
451 for (ap
= pg
.gl_pathv
; *ap
!= NULL
; ++ap
) {
461 /* Use system(3) in case someone's pager is "pager arg1 arg2". */
468 manual_find_literalfile(struct manstate
*mp
, glob_t
*pg
, size_t cnt
)
472 char buf
[MAXPATHLEN
];
479 * Expand both '*' and suffix to force an actual
480 * match via fnmatch(3). Since the only match in pg
481 * is the literal file, the match is genuine.
484 TAILQ_FOREACH(suffix
, &mp
->buildlist
->entrylist
, q
) {
485 for (p
= suffix
->s
, suflen
= 0;
486 *p
!= '\0' && !isspace((unsigned char)*p
);
492 (void)snprintf(buf
, sizeof(buf
), "*%.*s", suflen
, suffix
->s
);
493 if (!fnmatch(buf
, pg
->gl_pathv
[cnt
], 0)) {
495 build_page(p
+ 1, &pg
->gl_pathv
[cnt
], mp
);
505 manual_find_buildkeyword(const char *prefix
, const char *escpage
,
506 struct manstate
*mp
, glob_t
*pg
, size_t cnt
)
510 char buf
[MAXPATHLEN
];
515 /* Try the _build keywords next. */
516 TAILQ_FOREACH(suffix
, &mp
->buildlist
->entrylist
, q
) {
517 for (p
= suffix
->s
, suflen
= 0;
518 *p
!= '\0' && !isspace((unsigned char)*p
);
524 (void)snprintf(buf
, sizeof(buf
), "%s%s%.*s",
525 prefix
, escpage
, suflen
, suffix
->s
);
526 if (!fnmatch(buf
, pg
->gl_pathv
[cnt
], 0)) {
528 build_page(p
+ 1, &pg
->gl_pathv
[cnt
], mp
);
539 * Search the manuals for the pages.
542 manual(char *page
, struct manstate
*mp
, glob_t
*pg
)
544 ENTRY
*suffix
, *mdir
;
545 int anyfound
, error
, found
;
547 char *p
, buf
[MAXPATHLEN
], *escpage
, *eptr
;
548 static const char escglob
[] = "\\~?*{}[]";
553 * Fixup page which may contain glob(3) special characters, e.g.
554 * the famous "No man page for [" FAQ.
556 if ((escpage
= malloc((2 * strlen(page
)) + 1)) == NULL
) {
566 if (strchr(escglob
, *p
) != NULL
) {
576 * If 'page' contains a slash then it's
577 * interpreted as a file specification.
579 if (strchr(page
, '/')) {
580 /* check if file actually exists */
581 (void)strlcpy(buf
, escpage
, sizeof(buf
));
582 error
= glob(buf
, GLOB_APPEND
| GLOB_BRACE
| GLOB_NOSORT
, NULL
, pg
);
584 if (error
== GLOB_NOMATCH
) {
587 errx(EXIT_FAILURE
, "glob failed");
591 if (pg
->gl_matchc
== 0)
594 /* literal file only yields one match */
595 cnt
= pg
->gl_pathc
- pg
->gl_matchc
;
597 if (manual_find_literalfile(mp
, pg
, cnt
)) {
600 /* It's not a man page, forget about it. */
601 *pg
->gl_pathv
[cnt
] = '\0';
606 if (addentry(mp
->missinglist
, page
, 0) < 0) {
616 /* For each man directory in mymanpath ... */
617 TAILQ_FOREACH(mdir
, &mp
->mymanpath
->entrylist
, q
) {
620 * use glob(3) to look in the filesystem for matching files.
621 * match any suffix here, as we will check that later.
623 (void)snprintf(buf
, sizeof(buf
), "%s/%s.*", mdir
->s
, escpage
);
624 if ((error
= glob(buf
,
625 GLOB_APPEND
| GLOB_BRACE
| GLOB_NOSORT
, NULL
, pg
)) != 0) {
626 if (error
== GLOB_NOMATCH
)
634 if (pg
->gl_matchc
== 0)
638 * start going through the matches glob(3) just found and
639 * use m.pathsearch (if present) to filter out pages we
640 * don't want. then verify the suffix is valid, and build
641 * the page if we have a _build suffix.
643 for (cnt
= pg
->gl_pathc
- pg
->gl_matchc
;
644 cnt
< pg
->gl_pathc
; ++cnt
) {
646 /* filter on directory path name */
647 if (mp
->pathsearch
) {
648 p
= strstr(pg
->gl_pathv
[cnt
], mp
->pathsearch
);
649 if (!p
|| strchr(p
, '/') == NULL
) {
650 *pg
->gl_pathv
[cnt
] = '\0'; /* zap! */
656 * Try the _suffix keywords first.
659 * Older versions of man.conf didn't have the _suffix
660 * keywords, it was assumed that everything was a .0.
661 * We just test for .0 first, it's fast and probably
664 (void)snprintf(buf
, sizeof(buf
), "*/%s.0", escpage
);
665 if (!fnmatch(buf
, pg
->gl_pathv
[cnt
], 0))
669 TAILQ_FOREACH(suffix
, &mp
->suffixlist
->entrylist
, q
) {
671 sizeof(buf
), "*/%s%s", escpage
,
673 if (!fnmatch(buf
, pg
->gl_pathv
[cnt
], 0)) {
681 /* Try the _build keywords next. */
682 found
= manual_find_buildkeyword("*/", escpage
,
687 /* Delete any other matches. */
688 while (++cnt
< pg
->gl_pathc
)
689 *pg
->gl_pathv
[cnt
] = '\0';
695 /* It's not a man page, forget about it. */
696 *pg
->gl_pathv
[cnt
] = '\0';
699 if (anyfound
&& !mp
->all
)
703 /* If not found, enter onto the missing list. */
705 if (addentry(mp
->missinglist
, page
, 0) < 0) {
718 * Build a man page for display.
721 build_page(const char *fmt
, char **pathp
, struct manstate
*mp
)
727 char buf
[MAXPATHLEN
], cmd
[MAXPATHLEN
], tpath
[MAXPATHLEN
];
730 /* Let the user know this may take awhile. */
733 warnx("Formatting manual page...");
737 * Historically man chdir'd to the root of the man tree.
738 * This was used in man pages that contained relative ".so"
739 * directives (including other man pages for command aliases etc.)
740 * It even went one step farther, by examining the first line
741 * of the man page and parsing the .so filename so it would
742 * make hard(?) links to the cat'ted man pages for space savings.
743 * (We don't do that here, but we could).
746 /* copy and find the end */
747 for (b
= buf
, p
= *pathp
; (*b
++ = *p
++) != '\0';)
751 * skip the last two path components, page name and man[n] ...
752 * (e.g. buf will be "/usr/share/man" and p will be "man1/man.1")
753 * we also save a pointer to our current directory so that we
754 * can fchdir() back to it. this allows relative MANDIR paths
755 * to work with multiple man pages... e.g. consider:
756 * cd /usr/share && man -M ./man cat ls
757 * when no "cat1" subdir files are present.
760 for (--b
, --p
, n
= 2; b
!= buf
; b
--, p
--)
764 olddir
= open(".", O_RDONLY
);
771 /* advance fmt past the suffix spec to the printf format string */
772 for (; *fmt
&& isspace((unsigned char)*fmt
); ++fmt
)
776 * Get a temporary file and build a version of the file
777 * to display. Replace the old file name with the new one.
779 if ((tmpdir
= getenv("TMPDIR")) == NULL
)
781 tmpdirlen
= strlen(tmpdir
);
782 (void)snprintf(tpath
, sizeof (tpath
), "%s%s%s", tmpdir
,
783 (tmpdirlen
> 0 && tmpdir
[tmpdirlen
-1] == '/') ? "" : "/", TMPFILE
);
784 if ((fd
= mkstemp(tpath
)) == -1) {
789 (void)snprintf(buf
, sizeof(buf
), "%s > %s", fmt
, tpath
);
790 (void)snprintf(cmd
, sizeof(cmd
), buf
, p
);
793 if ((*pathp
= strdup(tpath
)) == NULL
) {
799 /* Link the built file into the remove-when-done list. */
800 if (addentry(mp
->intmp
, *pathp
, 0) < 0) {
806 /* restore old directory so relative manpaths still work */
815 * display how information
818 how(const char *fname
)
826 if (!(fp
= fopen(fname
, "r"))) {
831 #define S1 "SYNOPSIS"
832 #define S2 "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS"
833 #define D1 "DESCRIPTION"
834 #define D2 "D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN"
835 for (lcnt
= print
= 0; fgets(buf
, sizeof(buf
), fp
);) {
836 if (!strncmp(buf
, S1
, sizeof(S1
) - 1) ||
837 !strncmp(buf
, S2
, sizeof(S2
) - 1)) {
840 } else if (!strncmp(buf
, D1
, sizeof(D1
) - 1) ||
841 !strncmp(buf
, D2
, sizeof(D2
) - 1)) {
853 for (p
= buf
; isspace((unsigned char)*p
); ++p
)
855 (void)fputs(p
, stdout
);
866 cat(const char *fname
)
872 if ((fd
= open(fname
, O_RDONLY
, 0)) < 0) {
877 while ((n
= read(fd
, buf
, sizeof(buf
))) > 0)
878 if (write(STDOUT_FILENO
, buf
, (size_t)n
) != n
) {
893 * check the user supplied page information
896 check_pager(const char *name
)
901 * if the user uses "more", we make it "more -s"; watch out for
902 * PAGER = "mypager /usr/ucb/more"
904 for (p
= name
; *p
&& !isspace((unsigned char)*p
); ++p
)
906 for (; p
> name
&& *p
!= '/'; --p
);
910 /* make sure it's "more", not "morex" */
911 if (!strncmp(p
, "more", 4) && (!p
[4] || isspace((unsigned char)p
[4]))){
913 (void)asprintf(&newname
, "%s %s", p
, "-s");
922 * strip out flag argument and jump
925 jump(char **argv
, const char *flag
, const char *name
)
929 argv
[0] = __DECONST(char *, name
);
930 for (arg
= argv
+ 1; *arg
; ++arg
)
931 if (!strcmp(*arg
, flag
))
936 err(EXIT_FAILURE
, "Cannot execute `%s'", name
);
941 * If signaled, delete the temporary files.
947 signal(signo
, SIG_DFL
);
953 * Clean up temporary files, show any error messages.
964 * note that _missing and _intmp were created by main(), so
965 * gettag() cannot return NULL here.
967 missp
= gettag("_missing", 0); /* missing man pages */
968 intmpp
= gettag("_intmp", 0); /* tmp files we need to unlink */
970 TAILQ_FOREACH(ep
, &missp
->entrylist
, q
) {
971 warnx("no entry for %s in the manual.", ep
->s
);
975 TAILQ_FOREACH(ep
, &intmpp
->entrylist
, q
)
982 getclass(const char *machine
)
986 snprintf(buf
, sizeof(buf
), "_%s", machine
);
988 return t
!= NULL
&& !TAILQ_EMPTY(&t
->entrylist
) ?
989 TAILQ_FIRST(&t
->entrylist
)->s
: NULL
;
993 addpath(struct manstate
*m
, const char *dir
, size_t len
, const char *sub
)
995 char buf
[2 * MAXPATHLEN
+ 1];
996 (void)snprintf(buf
, sizeof(buf
), "%s%s%s{/%s,%s%s%s}",
997 dir
, (dir
[len
- 1] == '/') ? "" : "/", sub
, m
->machine
,
998 m
->machclass
? "/" : "", m
->machclass
? m
->machclass
: "",
999 m
->machclass
? "," : "");
1000 if (addentry(m
->mymanpath
, buf
, 0) < 0)
1001 errx(EXIT_FAILURE
, "malloc failed");
1006 * print usage message and die
1011 (void)fprintf(stderr
, "Usage: %s [-acw|-h] [-C cfg] [-M path] "
1012 "[-m path] [-S srch] [[-s] sect] name ...\n", getprogname());
1013 (void)fprintf(stderr
,
1014 "Usage: %s -k [-C cfg] [-M path] [-m path] keyword ...\n",
1016 (void)fprintf(stderr
, "Usage: %s -p\n", getprogname());
1022 * Prints a list of directories containing man pages.
1025 printmanpath(struct manstate
*m
)
1028 char *defaultpath
= NULL
; /* _default tag value from man.conf. */
1029 char *buf
; /* for storing temporary values */
1033 TAG
*path
= m
->defaultpath
;
1034 TAG
*subdirs
= m
->subdirs
;
1036 /* the tail queue is empty if no _default tag is defined in * man.conf */
1037 if (TAILQ_EMPTY(&path
->entrylist
))
1038 errx(EXIT_FAILURE
, "Empty manpath");
1040 defaultpath
= TAILQ_LAST(&path
->entrylist
, tqh
)->s
;
1042 if (glob(defaultpath
, GLOB_BRACE
| GLOB_NOSORT
, NULL
, &pg
) != 0)
1043 err(EXIT_FAILURE
, "glob failed");
1045 if (pg
.gl_matchc
== 0) {
1046 warnx("Default path in %s doesn't exist", _PATH_MANCONF
);
1051 TAILQ_FOREACH(esubd
, &subdirs
->entrylist
, q
) {
1052 /* Drop cat page directory, only sources are relevant. */
1053 if (strncmp(esubd
->s
, "man", 3))
1056 for (ap
= pg
.gl_pathv
; *ap
!= NULL
; ++ap
) {
1057 if (asprintf(&buf
, "%s%s", *ap
, esubd
->s
) == -1)
1058 err(EXIT_FAILURE
, "memory allocation error");
1059 /* Skip non-directories. */
1060 if (stat(buf
, &sb
) == 0 && S_ISDIR(sb
.st_mode
))
1061 printf("%s\n", buf
);