GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/mandoc/manpath.c Lines: 0 108 0.0 %
Date: 2016-12-06 Branches: 0 103 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: manpath.c,v 1.18 2016/05/23 18:59:00 millert Exp $	*/
2
/*
3
 * Copyright (c) 2011, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
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 AUTHORS DISCLAIM ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS 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
 */
18
#include <sys/types.h>
19
#include <sys/stat.h>
20
21
#include <ctype.h>
22
#include <err.h>
23
#include <limits.h>
24
#include <stdio.h>
25
#include <stdlib.h>
26
#include <string.h>
27
28
#include "mandoc_aux.h"
29
#include "manconf.h"
30
31
#define MAN_CONF_FILE	"/etc/man.conf"
32
#define MANPATH_DEFAULT	"/usr/share/man:/usr/X11R6/man:/usr/local/man"
33
34
static	void	 manconf_file(struct manconf *, const char *);
35
static	void	 manpath_add(struct manpaths *, const char *, int);
36
static	void	 manpath_parseline(struct manpaths *, char *, int);
37
38
39
void
40
manconf_parse(struct manconf *conf, const char *file,
41
		char *defp, char *auxp)
42
{
43
	char		*insert;
44
45
	/* Always prepend -m. */
46
	manpath_parseline(&conf->manpath, auxp, 1);
47
48
	/* If -M is given, it overrides everything else. */
49
	if (NULL != defp) {
50
		manpath_parseline(&conf->manpath, defp, 1);
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
		manconf_file(conf, file);
62
		return;
63
	}
64
65
	/* Prepend man.conf(5) to MANPATH. */
66
	if (':' == defp[0]) {
67
		manconf_file(conf, file);
68
		manpath_parseline(&conf->manpath, defp, 0);
69
		return;
70
	}
71
72
	/* Append man.conf(5) to MANPATH. */
73
	if (':' == defp[strlen(defp) - 1]) {
74
		manpath_parseline(&conf->manpath, defp, 0);
75
		manconf_file(conf, file);
76
		return;
77
	}
78
79
	/* Insert man.conf(5) into MANPATH. */
80
	insert = strstr(defp, "::");
81
	if (NULL != insert) {
82
		*insert++ = '\0';
83
		manpath_parseline(&conf->manpath, defp, 0);
84
		manconf_file(conf, file);
85
		manpath_parseline(&conf->manpath, insert + 1, 0);
86
		return;
87
	}
88
89
	/* MANPATH overrides man.conf(5) completely. */
90
	manpath_parseline(&conf->manpath, defp, 0);
91
}
92
93
/*
94
 * Parse a FULL pathname from a colon-separated list of arrays.
95
 */
96
static void
97
manpath_parseline(struct manpaths *dirs, char *path, int complain)
98
{
99
	char	*dir;
100
101
	if (NULL == path)
102
		return;
103
104
	for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
105
		manpath_add(dirs, dir, complain);
106
}
107
108
/*
109
 * Add a directory to the array, ignoring bad directories.
110
 * Grow the array one-by-one for simplicity's sake.
111
 */
112
static void
113
manpath_add(struct manpaths *dirs, const char *dir, int complain)
114
{
115
	char		 buf[PATH_MAX];
116
	struct stat	 sb;
117
	char		*cp;
118
	size_t		 i;
119
120
	if (NULL == (cp = realpath(dir, buf))) {
121
		if (complain)
122
			warn("manpath: %s", dir);
123
		return;
124
	}
125
126
	for (i = 0; i < dirs->sz; i++)
127
		if (0 == strcmp(dirs->paths[i], dir))
128
			return;
129
130
	if (stat(cp, &sb) == -1) {
131
		if (complain)
132
			warn("manpath: %s", dir);
133
		return;
134
	}
135
136
	dirs->paths = mandoc_reallocarray(dirs->paths,
137
	    dirs->sz + 1, sizeof(char *));
138
139
	dirs->paths[dirs->sz++] = mandoc_strdup(cp);
140
}
141
142
void
143
manconf_free(struct manconf *conf)
144
{
145
	size_t		 i;
146
147
	for (i = 0; i < conf->manpath.sz; i++)
148
		free(conf->manpath.paths[i]);
149
150
	free(conf->manpath.paths);
151
	free(conf->output.includes);
152
	free(conf->output.man);
153
	free(conf->output.paper);
154
	free(conf->output.style);
155
}
156
157
static void
158
manconf_file(struct manconf *conf, const char *file)
159
{
160
	const char *const toks[] = { "manpath", "output", "_whatdb" };
161
	char manpath_default[] = MANPATH_DEFAULT;
162
163
	FILE		*stream;
164
	char		*line, *cp, *ep;
165
	size_t		 linesz, tok, toklen;
166
	ssize_t		 linelen;
167
168
	if ((stream = fopen(file, "r")) == NULL)
169
		goto out;
170
171
	line = NULL;
172
	linesz = 0;
173
174
	while ((linelen = getline(&line, &linesz, stream)) != -1) {
175
		cp = line;
176
		ep = cp + linelen - 1;
177
		while (ep > cp && isspace((unsigned char)*ep))
178
			*ep-- = '\0';
179
		while (isspace((unsigned char)*cp))
180
			cp++;
181
		if (cp == ep || *cp == '#')
182
			continue;
183
184
		for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) {
185
			toklen = strlen(toks[tok]);
186
			if (cp + toklen < ep &&
187
			    isspace((unsigned char)cp[toklen]) &&
188
			    strncmp(cp, toks[tok], toklen) == 0) {
189
				cp += toklen;
190
				while (isspace((unsigned char)*cp))
191
					cp++;
192
				break;
193
			}
194
		}
195
196
		switch (tok) {
197
		case 2:  /* _whatdb */
198
			while (ep > cp && ep[-1] != '/')
199
				ep--;
200
			if (ep == cp)
201
				continue;
202
			*ep = '\0';
203
			/* FALLTHROUGH */
204
		case 0:  /* manpath */
205
			manpath_add(&conf->manpath, cp, 0);
206
			*manpath_default = '\0';
207
			break;
208
		case 1:  /* output */
209
			manconf_output(&conf->output, cp);
210
			break;
211
		default:
212
			break;
213
		}
214
	}
215
	free(line);
216
	fclose(stream);
217
218
out:
219
	if (*manpath_default != '\0')
220
		manpath_parseline(&conf->manpath, manpath_default, 0);
221
}
222
223
void
224
manconf_output(struct manoutput *conf, const char *cp)
225
{
226
	const char *const toks[] = {
227
	    "includes", "man", "paper", "style",
228
	    "indent", "width", "fragment", "mdoc"
229
	};
230
231
	size_t	 len, tok;
232
233
	for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) {
234
		len = strlen(toks[tok]);
235
		if ( ! strncmp(cp, toks[tok], len) &&
236
		    strchr(" =	", cp[len]) != NULL) {
237
			cp += len;
238
			if (*cp == '=')
239
				cp++;
240
			while (isspace((unsigned char)*cp))
241
				cp++;
242
			break;
243
		}
244
	}
245
246
	if (tok < 6 && *cp == '\0')
247
		return;
248
249
	switch (tok) {
250
	case 0:
251
		if (conf->includes == NULL)
252
			conf->includes = mandoc_strdup(cp);
253
		break;
254
	case 1:
255
		if (conf->man == NULL)
256
			conf->man = mandoc_strdup(cp);
257
		break;
258
	case 2:
259
		if (conf->paper == NULL)
260
			conf->paper = mandoc_strdup(cp);
261
		break;
262
	case 3:
263
		if (conf->style == NULL)
264
			conf->style = mandoc_strdup(cp);
265
		break;
266
	case 4:
267
		if (conf->indent == 0)
268
			conf->indent = strtonum(cp, 0, 1000, NULL);
269
		break;
270
	case 5:
271
		if (conf->width == 0)
272
			conf->width = strtonum(cp, 58, 1000, NULL);
273
		break;
274
	case 6:
275
		conf->fragment = 1;
276
		break;
277
	case 7:
278
		conf->mdoc = 1;
279
		break;
280
	default:
281
		break;
282
	}
283
}