Annotation of mandoc/manpath.c, Revision 1.22
1.22 ! schwarze 1: /* $Id: manpath.c,v 1.21 2015/03/22 18:14:30 schwarze Exp $ */
1.1 kristaps 2: /*
1.20 schwarze 3: * Copyright (c) 2011, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
1.1 kristaps 4: * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
1.22 ! schwarze 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
1.1 kristaps 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1.22 ! schwarze 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
1.1 kristaps 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18: #include "config.h"
1.16 schwarze 19:
20: #include <sys/types.h>
1.18 schwarze 21: #include <sys/stat.h>
1.1 kristaps 22:
23: #include <ctype.h>
24: #include <limits.h>
25: #include <stdio.h>
26: #include <stdlib.h>
27: #include <string.h>
28:
1.13 schwarze 29: #include "mandoc_aux.h"
1.1 kristaps 30: #include "manpath.h"
31:
32: #define MAN_CONF_FILE "/etc/man.conf"
33:
1.18 schwarze 34: static void manpath_add(struct manpaths *, const char *, int);
35: static void manpath_parseline(struct manpaths *, char *, int);
1.1 kristaps 36:
37: void
1.5 schwarze 38: manpath_parse(struct manpaths *dirs, const char *file,
39: char *defp, char *auxp)
1.1 kristaps 40: {
1.17 schwarze 41: #if HAVE_MANPATH
1.11 schwarze 42: char cmd[(PATH_MAX * 3) + 20];
1.6 kristaps 43: FILE *stream;
44: char *buf;
45: size_t sz, bsz;
46:
47: strlcpy(cmd, "manpath", sizeof(cmd));
48: if (file) {
49: strlcat(cmd, " -C ", sizeof(cmd));
50: strlcat(cmd, file, sizeof(cmd));
51: }
52: if (auxp) {
53: strlcat(cmd, " -m ", sizeof(cmd));
54: strlcat(cmd, auxp, sizeof(cmd));
55: }
56: if (defp) {
57: strlcat(cmd, " -M ", sizeof(cmd));
58: strlcat(cmd, defp, sizeof(cmd));
59: }
60:
61: /* Open manpath(1). Ignore errors. */
62:
63: stream = popen(cmd, "r");
64: if (NULL == stream)
65: return;
66:
67: buf = NULL;
68: bsz = 0;
69:
70: /* Read in as much output as we can. */
71:
72: do {
73: buf = mandoc_realloc(buf, bsz + 1024);
1.9 kristaps 74: sz = fread(buf + bsz, 1, 1024, stream);
1.6 kristaps 75: bsz += sz;
76: } while (sz > 0);
77:
78: if ( ! ferror(stream) && feof(stream) &&
79: bsz && '\n' == buf[bsz - 1]) {
80: buf[bsz - 1] = '\0';
1.19 schwarze 81: manpath_parseline(dirs, buf, 1);
1.6 kristaps 82: }
1.1 kristaps 83:
1.6 kristaps 84: free(buf);
85: pclose(stream);
86: #else
1.20 schwarze 87: char manpath_default[] = MANPATH_DEFAULT;
1.8 kristaps 88: char *insert;
1.4 schwarze 89:
1.8 kristaps 90: /* Always prepend -m. */
1.18 schwarze 91: manpath_parseline(dirs, auxp, 1);
1.10 schwarze 92:
1.8 kristaps 93: /* If -M is given, it overrides everything else. */
94: if (NULL != defp) {
1.18 schwarze 95: manpath_parseline(dirs, defp, 1);
1.8 kristaps 96: return;
97: }
1.1 kristaps 98:
1.8 kristaps 99: /* MANPATH and man.conf(5) cooperate. */
100: defp = getenv("MANPATH");
101: if (NULL == file)
102: file = MAN_CONF_FILE;
103:
104: /* No MANPATH; use man.conf(5) only. */
105: if (NULL == defp || '\0' == defp[0]) {
106: manpath_manconf(dirs, file);
1.20 schwarze 107: if (dirs->sz == 0)
108: manpath_parseline(dirs, manpath_default, 0);
1.8 kristaps 109: return;
110: }
111:
112: /* Prepend man.conf(5) to MANPATH. */
113: if (':' == defp[0]) {
114: manpath_manconf(dirs, file);
1.18 schwarze 115: manpath_parseline(dirs, defp, 0);
1.8 kristaps 116: return;
117: }
118:
119: /* Append man.conf(5) to MANPATH. */
1.9 kristaps 120: if (':' == defp[strlen(defp) - 1]) {
1.18 schwarze 121: manpath_parseline(dirs, defp, 0);
1.8 kristaps 122: manpath_manconf(dirs, file);
123: return;
124: }
125:
126: /* Insert man.conf(5) into MANPATH. */
127: insert = strstr(defp, "::");
128: if (NULL != insert) {
129: *insert++ = '\0';
1.18 schwarze 130: manpath_parseline(dirs, defp, 0);
1.8 kristaps 131: manpath_manconf(dirs, file);
1.18 schwarze 132: manpath_parseline(dirs, insert + 1, 0);
1.8 kristaps 133: return;
134: }
135:
136: /* MANPATH overrides man.conf(5) completely. */
1.18 schwarze 137: manpath_parseline(dirs, defp, 0);
1.6 kristaps 138: #endif
1.1 kristaps 139: }
140:
141: /*
142: * Parse a FULL pathname from a colon-separated list of arrays.
143: */
1.6 kristaps 144: static void
1.18 schwarze 145: manpath_parseline(struct manpaths *dirs, char *path, int complain)
1.1 kristaps 146: {
147: char *dir;
148:
149: if (NULL == path)
150: return;
151:
152: for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
1.18 schwarze 153: manpath_add(dirs, dir, complain);
1.1 kristaps 154: }
155:
156: /*
157: * Add a directory to the array, ignoring bad directories.
158: * Grow the array one-by-one for simplicity's sake.
159: */
160: static void
1.18 schwarze 161: manpath_add(struct manpaths *dirs, const char *dir, int complain)
1.1 kristaps 162: {
163: char buf[PATH_MAX];
1.18 schwarze 164: struct stat sb;
1.1 kristaps 165: char *cp;
1.9 kristaps 166: size_t i;
1.1 kristaps 167:
1.18 schwarze 168: if (NULL == (cp = realpath(dir, buf))) {
169: if (complain) {
170: fputs("manpath: ", stderr);
171: perror(dir);
172: }
1.1 kristaps 173: return;
1.18 schwarze 174: }
1.1 kristaps 175:
176: for (i = 0; i < dirs->sz; i++)
177: if (0 == strcmp(dirs->paths[i], dir))
178: return;
179:
1.18 schwarze 180: if (stat(cp, &sb) == -1) {
181: if (complain) {
182: fputs("manpath: ", stderr);
183: perror(dir);
184: }
185: return;
186: }
187:
1.15 schwarze 188: dirs->paths = mandoc_reallocarray(dirs->paths,
189: dirs->sz + 1, sizeof(char *));
1.1 kristaps 190:
191: dirs->paths[dirs->sz++] = mandoc_strdup(cp);
1.2 kristaps 192: }
193:
194: void
195: manpath_free(struct manpaths *p)
196: {
1.9 kristaps 197: size_t i;
1.2 kristaps 198:
199: for (i = 0; i < p->sz; i++)
200: free(p->paths[i]);
201:
202: free(p->paths);
203: }
204:
205: void
1.5 schwarze 206: manpath_manconf(struct manpaths *dirs, const char *file)
1.2 kristaps 207: {
1.22 ! schwarze 208: const char *const toks[] = { "manpath", "_whatdb" };
! 209:
1.2 kristaps 210: FILE *stream;
1.22 ! schwarze 211: char *cp, *ep;
! 212: size_t len, tok;
1.1 kristaps 213:
1.22 ! schwarze 214: if ((stream = fopen(file, "r")) == NULL)
1.1 kristaps 215: return;
216:
1.22 ! schwarze 217: while ((cp = fgetln(stream, &len)) != NULL) {
! 218: ep = cp + len;
! 219: if (ep[-1] != '\n')
1.1 kristaps 220: break;
1.22 ! schwarze 221: *--ep = '\0';
! 222: while (isspace((unsigned char)*cp))
! 223: cp++;
! 224: if (*cp == '#')
1.1 kristaps 225: continue;
1.22 ! schwarze 226:
! 227: for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) {
! 228: len = strlen(toks[tok]);
! 229: if (cp + len < ep &&
! 230: isspace((unsigned char)cp[len]) &&
! 231: !strncmp(cp, toks[tok], len)) {
! 232: cp += len;
! 233: while (isspace((unsigned char)*cp))
! 234: cp++;
! 235: break;
! 236: }
! 237: }
! 238:
! 239: switch (tok) {
! 240: case 1: /* _whatdb */
! 241: while (ep > cp && ep[-1] != '/')
! 242: ep--;
! 243: if (ep == cp)
! 244: continue;
! 245: *ep = '\0';
! 246: /* FALLTHROUGH */
! 247: case 0: /* manpath */
! 248: manpath_add(dirs, cp, 0);
! 249: break;
! 250: default:
! 251: break;
! 252: }
1.1 kristaps 253: }
254:
255: fclose(stream);
256: }
CVSweb