Annotation of src/usr.bin/mandoc/manpath.c, Revision 1.12
1.12 ! schwarze 1: /* $OpenBSD: manpath.c,v 1.11 2014/11/18 19:40:38 schwarze Exp $ */
1.1 schwarze 2: /*
1.12 ! schwarze 3: * Copyright (c) 2011, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
1.1 schwarze 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: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
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: */
1.11 schwarze 18: #include <sys/types.h>
19: #include <sys/stat.h>
1.3 schwarze 20:
1.1 schwarze 21: #include <assert.h>
22: #include <ctype.h>
23: #include <limits.h>
24: #include <stdio.h>
25: #include <stdlib.h>
26: #include <string.h>
27:
1.8 schwarze 28: #include "mandoc_aux.h"
1.1 schwarze 29: #include "manpath.h"
30:
31: #define MAN_CONF_FILE "/etc/man.conf"
32: #define MAN_CONF_KEY "_whatdb"
1.12 ! schwarze 33: #define MANPATH_DEFAULT "/usr/share/man:/usr/X11R6/man:/usr/local/man"
1.1 schwarze 34:
1.11 schwarze 35: static void manpath_add(struct manpaths *, const char *, int);
36: static void manpath_parseline(struct manpaths *, char *, int);
1.1 schwarze 37:
38: void
1.2 schwarze 39: manpath_parse(struct manpaths *dirs, const char *file,
40: char *defp, char *auxp)
1.1 schwarze 41: {
1.12 ! schwarze 42: char manpath_default[] = MANPATH_DEFAULT;
1.4 schwarze 43: char *insert;
1.1 schwarze 44:
1.4 schwarze 45: /* Always prepend -m. */
1.11 schwarze 46: manpath_parseline(dirs, auxp, 1);
1.1 schwarze 47:
1.4 schwarze 48: /* If -M is given, it overrides everything else. */
49: if (NULL != defp) {
1.11 schwarze 50: manpath_parseline(dirs, defp, 1);
1.4 schwarze 51: return;
52: }
53:
54: /* MANPATH and man.conf(5) cooperate. */
55: defp = getenv("MANPATH");
56: if (NULL == file)
57: file = MAN_CONF_FILE;
58:
59: /* No MANPATH; use man.conf(5) only. */
60: if (NULL == defp || '\0' == defp[0]) {
61: manpath_manconf(dirs, file);
1.12 ! schwarze 62: if (dirs->sz == 0)
! 63: manpath_parseline(dirs, manpath_default, 0);
1.4 schwarze 64: return;
65: }
66:
67: /* Prepend man.conf(5) to MANPATH. */
68: if (':' == defp[0]) {
69: manpath_manconf(dirs, file);
1.11 schwarze 70: manpath_parseline(dirs, defp, 0);
1.4 schwarze 71: return;
72: }
1.1 schwarze 73:
1.4 schwarze 74: /* Append man.conf(5) to MANPATH. */
1.6 schwarze 75: if (':' == defp[strlen(defp) - 1]) {
1.11 schwarze 76: manpath_parseline(dirs, defp, 0);
1.4 schwarze 77: manpath_manconf(dirs, file);
78: return;
79: }
80:
81: /* Insert man.conf(5) into MANPATH. */
82: insert = strstr(defp, "::");
83: if (NULL != insert) {
84: *insert++ = '\0';
1.11 schwarze 85: manpath_parseline(dirs, defp, 0);
1.4 schwarze 86: manpath_manconf(dirs, file);
1.11 schwarze 87: manpath_parseline(dirs, insert + 1, 0);
1.4 schwarze 88: return;
89: }
90:
91: /* MANPATH overrides man.conf(5) completely. */
1.11 schwarze 92: manpath_parseline(dirs, defp, 0);
1.1 schwarze 93: }
94:
95: /*
96: * Parse a FULL pathname from a colon-separated list of arrays.
97: */
1.3 schwarze 98: static void
1.11 schwarze 99: manpath_parseline(struct manpaths *dirs, char *path, int complain)
1.1 schwarze 100: {
101: char *dir;
102:
103: if (NULL == path)
104: return;
105:
106: for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
1.11 schwarze 107: manpath_add(dirs, dir, complain);
1.1 schwarze 108: }
109:
110: /*
111: * Add a directory to the array, ignoring bad directories.
112: * Grow the array one-by-one for simplicity's sake.
113: */
114: static void
1.11 schwarze 115: manpath_add(struct manpaths *dirs, const char *dir, int complain)
1.1 schwarze 116: {
117: char buf[PATH_MAX];
1.11 schwarze 118: struct stat sb;
1.1 schwarze 119: char *cp;
1.6 schwarze 120: size_t i;
1.1 schwarze 121:
1.11 schwarze 122: if (NULL == (cp = realpath(dir, buf))) {
123: if (complain) {
124: fputs("manpath: ", stderr);
125: perror(dir);
126: }
1.1 schwarze 127: return;
1.11 schwarze 128: }
1.1 schwarze 129:
130: for (i = 0; i < dirs->sz; i++)
131: if (0 == strcmp(dirs->paths[i], dir))
132: return;
133:
1.11 schwarze 134: if (stat(cp, &sb) == -1) {
135: if (complain) {
136: fputs("manpath: ", stderr);
137: perror(dir);
138: }
139: return;
140: }
141:
1.10 schwarze 142: dirs->paths = mandoc_reallocarray(dirs->paths,
143: dirs->sz + 1, sizeof(char *));
1.1 schwarze 144:
145: dirs->paths[dirs->sz++] = mandoc_strdup(cp);
146: }
147:
148: void
149: manpath_free(struct manpaths *p)
150: {
1.6 schwarze 151: size_t i;
1.1 schwarze 152:
153: for (i = 0; i < p->sz; i++)
154: free(p->paths[i]);
155:
156: free(p->paths);
157: }
158:
159: void
1.2 schwarze 160: manpath_manconf(struct manpaths *dirs, const char *file)
1.1 schwarze 161: {
162: FILE *stream;
163: char *p, *q;
164: size_t len, keysz;
165:
166: keysz = strlen(MAN_CONF_KEY);
167: assert(keysz > 0);
168:
169: if (NULL == (stream = fopen(file, "r")))
170: return;
171:
172: while (NULL != (p = fgetln(stream, &len))) {
173: if (0 == len || '\n' != p[--len])
174: break;
175: p[len] = '\0';
176: while (isspace((unsigned char)*p))
177: p++;
178: if (strncmp(MAN_CONF_KEY, p, keysz))
179: continue;
180: p += keysz;
1.7 schwarze 181: while (isspace((unsigned char)*p))
1.1 schwarze 182: p++;
183: if ('\0' == *p)
184: continue;
185: if (NULL == (q = strrchr(p, '/')))
186: continue;
187: *q = '\0';
1.11 schwarze 188: manpath_add(dirs, p, 0);
1.1 schwarze 189: }
190:
191: fclose(stream);
192: }