1*5c4a5fe1SAndy Fiddaman /*-
2*5c4a5fe1SAndy Fiddaman * SPDX-License-Identifier: BSD-2-Clause
3*5c4a5fe1SAndy Fiddaman *
4*5c4a5fe1SAndy Fiddaman * Copyright (c) 2021 John H. Baldwin <jhb@FreeBSD.org>
5*5c4a5fe1SAndy Fiddaman *
6*5c4a5fe1SAndy Fiddaman * Redistribution and use in source and binary forms, with or without
7*5c4a5fe1SAndy Fiddaman * modification, are permitted provided that the following conditions
8*5c4a5fe1SAndy Fiddaman * are met:
9*5c4a5fe1SAndy Fiddaman * 1. Redistributions of source code must retain the above copyright
10*5c4a5fe1SAndy Fiddaman * notice, this list of conditions and the following disclaimer.
11*5c4a5fe1SAndy Fiddaman * 2. Redistributions in binary form must reproduce the above copyright
12*5c4a5fe1SAndy Fiddaman * notice, this list of conditions and the following disclaimer in the
13*5c4a5fe1SAndy Fiddaman * documentation and/or other materials provided with the distribution.
14*5c4a5fe1SAndy Fiddaman *
15*5c4a5fe1SAndy Fiddaman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*5c4a5fe1SAndy Fiddaman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*5c4a5fe1SAndy Fiddaman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*5c4a5fe1SAndy Fiddaman * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*5c4a5fe1SAndy Fiddaman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*5c4a5fe1SAndy Fiddaman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*5c4a5fe1SAndy Fiddaman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*5c4a5fe1SAndy Fiddaman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*5c4a5fe1SAndy Fiddaman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*5c4a5fe1SAndy Fiddaman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*5c4a5fe1SAndy Fiddaman * SUCH DAMAGE.
26*5c4a5fe1SAndy Fiddaman */
27*5c4a5fe1SAndy Fiddaman
28*5c4a5fe1SAndy Fiddaman
29*5c4a5fe1SAndy Fiddaman #include <assert.h>
30*5c4a5fe1SAndy Fiddaman #include <err.h>
31*5c4a5fe1SAndy Fiddaman #include <stdio.h>
32*5c4a5fe1SAndy Fiddaman #include <stdlib.h>
33*5c4a5fe1SAndy Fiddaman #include <string.h>
34*5c4a5fe1SAndy Fiddaman #ifndef __FreeBSD__
35*5c4a5fe1SAndy Fiddaman #include <sys/sysmacros.h>
36*5c4a5fe1SAndy Fiddaman #endif
37*5c4a5fe1SAndy Fiddaman
38*5c4a5fe1SAndy Fiddaman #include "config.h"
39*5c4a5fe1SAndy Fiddaman
40*5c4a5fe1SAndy Fiddaman static nvlist_t *config_root;
41*5c4a5fe1SAndy Fiddaman
42*5c4a5fe1SAndy Fiddaman void
init_config(void)43*5c4a5fe1SAndy Fiddaman init_config(void)
44*5c4a5fe1SAndy Fiddaman {
45*5c4a5fe1SAndy Fiddaman config_root = nvlist_create(0);
46*5c4a5fe1SAndy Fiddaman if (config_root == NULL)
47*5c4a5fe1SAndy Fiddaman err(4, "Failed to create configuration root nvlist");
48*5c4a5fe1SAndy Fiddaman }
49*5c4a5fe1SAndy Fiddaman
50*5c4a5fe1SAndy Fiddaman static nvlist_t *
_lookup_config_node(nvlist_t * parent,const char * path,bool create)51*5c4a5fe1SAndy Fiddaman _lookup_config_node(nvlist_t *parent, const char *path, bool create)
52*5c4a5fe1SAndy Fiddaman {
53*5c4a5fe1SAndy Fiddaman char *copy, *name, *tofree;
54*5c4a5fe1SAndy Fiddaman nvlist_t *nvl, *new_nvl;
55*5c4a5fe1SAndy Fiddaman
56*5c4a5fe1SAndy Fiddaman copy = strdup(path);
57*5c4a5fe1SAndy Fiddaman if (copy == NULL)
58*5c4a5fe1SAndy Fiddaman errx(4, "Failed to allocate memory");
59*5c4a5fe1SAndy Fiddaman tofree = copy;
60*5c4a5fe1SAndy Fiddaman nvl = parent;
61*5c4a5fe1SAndy Fiddaman while ((name = strsep(©, ".")) != NULL) {
62*5c4a5fe1SAndy Fiddaman if (*name == '\0') {
63*5c4a5fe1SAndy Fiddaman warnx("Invalid configuration node: %s", path);
64*5c4a5fe1SAndy Fiddaman nvl = NULL;
65*5c4a5fe1SAndy Fiddaman break;
66*5c4a5fe1SAndy Fiddaman }
67*5c4a5fe1SAndy Fiddaman if (nvlist_exists_nvlist(nvl, name))
68*5c4a5fe1SAndy Fiddaman /*
69*5c4a5fe1SAndy Fiddaman * XXX-MJ it is incorrect to cast away the const
70*5c4a5fe1SAndy Fiddaman * qualifier like this since the contract with nvlist
71*5c4a5fe1SAndy Fiddaman * says that values are immutable, and some consumers
72*5c4a5fe1SAndy Fiddaman * will indeed add nodes to the returned nvlist. In
73*5c4a5fe1SAndy Fiddaman * practice, however, it appears to be harmless with the
74*5c4a5fe1SAndy Fiddaman * current nvlist implementation, so we just live with
75*5c4a5fe1SAndy Fiddaman * it until the implementation is reworked.
76*5c4a5fe1SAndy Fiddaman */
77*5c4a5fe1SAndy Fiddaman nvl = __DECONST(nvlist_t *,
78*5c4a5fe1SAndy Fiddaman nvlist_get_nvlist(nvl, name));
79*5c4a5fe1SAndy Fiddaman else if (nvlist_exists(nvl, name)) {
80*5c4a5fe1SAndy Fiddaman for (copy = tofree; copy < name; copy++)
81*5c4a5fe1SAndy Fiddaman if (*copy == '\0')
82*5c4a5fe1SAndy Fiddaman *copy = '.';
83*5c4a5fe1SAndy Fiddaman warnx(
84*5c4a5fe1SAndy Fiddaman "Configuration node %s is a child of existing variable %s",
85*5c4a5fe1SAndy Fiddaman path, tofree);
86*5c4a5fe1SAndy Fiddaman nvl = NULL;
87*5c4a5fe1SAndy Fiddaman break;
88*5c4a5fe1SAndy Fiddaman } else if (create) {
89*5c4a5fe1SAndy Fiddaman /*
90*5c4a5fe1SAndy Fiddaman * XXX-MJ as with the case above, "new_nvl" shouldn't be
91*5c4a5fe1SAndy Fiddaman * mutated after its ownership is given to "nvl".
92*5c4a5fe1SAndy Fiddaman */
93*5c4a5fe1SAndy Fiddaman new_nvl = nvlist_create(0);
94*5c4a5fe1SAndy Fiddaman if (new_nvl == NULL)
95*5c4a5fe1SAndy Fiddaman errx(4, "Failed to allocate memory");
96*5c4a5fe1SAndy Fiddaman #ifdef __FreeBSD__
97*5c4a5fe1SAndy Fiddaman nvlist_move_nvlist(nvl, name, new_nvl);
98*5c4a5fe1SAndy Fiddaman #else
99*5c4a5fe1SAndy Fiddaman if (nvlist_add_nvlist(nvl, name, new_nvl) != 0)
100*5c4a5fe1SAndy Fiddaman errx(4, "Failed to allocate memory");
101*5c4a5fe1SAndy Fiddaman (void) nvlist_free(new_nvl);
102*5c4a5fe1SAndy Fiddaman if (nvlist_lookup_nvlist(nvl, name, &new_nvl) != 0)
103*5c4a5fe1SAndy Fiddaman errx(4, "Failed to retrieve new nvlist");
104*5c4a5fe1SAndy Fiddaman #endif
105*5c4a5fe1SAndy Fiddaman nvl = new_nvl;
106*5c4a5fe1SAndy Fiddaman } else {
107*5c4a5fe1SAndy Fiddaman nvl = NULL;
108*5c4a5fe1SAndy Fiddaman break;
109*5c4a5fe1SAndy Fiddaman }
110*5c4a5fe1SAndy Fiddaman }
111*5c4a5fe1SAndy Fiddaman free(tofree);
112*5c4a5fe1SAndy Fiddaman return (nvl);
113*5c4a5fe1SAndy Fiddaman }
114*5c4a5fe1SAndy Fiddaman
115*5c4a5fe1SAndy Fiddaman nvlist_t *
create_config_node(const char * path)116*5c4a5fe1SAndy Fiddaman create_config_node(const char *path)
117*5c4a5fe1SAndy Fiddaman {
118*5c4a5fe1SAndy Fiddaman
119*5c4a5fe1SAndy Fiddaman return (_lookup_config_node(config_root, path, true));
120*5c4a5fe1SAndy Fiddaman }
121*5c4a5fe1SAndy Fiddaman
122*5c4a5fe1SAndy Fiddaman nvlist_t *
find_config_node(const char * path)123*5c4a5fe1SAndy Fiddaman find_config_node(const char *path)
124*5c4a5fe1SAndy Fiddaman {
125*5c4a5fe1SAndy Fiddaman
126*5c4a5fe1SAndy Fiddaman return (_lookup_config_node(config_root, path, false));
127*5c4a5fe1SAndy Fiddaman }
128*5c4a5fe1SAndy Fiddaman
129*5c4a5fe1SAndy Fiddaman nvlist_t *
create_relative_config_node(nvlist_t * parent,const char * path)130*5c4a5fe1SAndy Fiddaman create_relative_config_node(nvlist_t *parent, const char *path)
131*5c4a5fe1SAndy Fiddaman {
132*5c4a5fe1SAndy Fiddaman
133*5c4a5fe1SAndy Fiddaman return (_lookup_config_node(parent, path, true));
134*5c4a5fe1SAndy Fiddaman }
135*5c4a5fe1SAndy Fiddaman
136*5c4a5fe1SAndy Fiddaman nvlist_t *
find_relative_config_node(nvlist_t * parent,const char * path)137*5c4a5fe1SAndy Fiddaman find_relative_config_node(nvlist_t *parent, const char *path)
138*5c4a5fe1SAndy Fiddaman {
139*5c4a5fe1SAndy Fiddaman
140*5c4a5fe1SAndy Fiddaman return (_lookup_config_node(parent, path, false));
141*5c4a5fe1SAndy Fiddaman }
142*5c4a5fe1SAndy Fiddaman
143*5c4a5fe1SAndy Fiddaman void
set_config_value_node(nvlist_t * parent,const char * name,const char * value)144*5c4a5fe1SAndy Fiddaman set_config_value_node(nvlist_t *parent, const char *name, const char *value)
145*5c4a5fe1SAndy Fiddaman {
146*5c4a5fe1SAndy Fiddaman
147*5c4a5fe1SAndy Fiddaman if (strchr(name, '.') != NULL)
148*5c4a5fe1SAndy Fiddaman errx(4, "Invalid config node name %s", name);
149*5c4a5fe1SAndy Fiddaman if (parent == NULL)
150*5c4a5fe1SAndy Fiddaman parent = config_root;
151*5c4a5fe1SAndy Fiddaman if (nvlist_exists_string(parent, name))
152*5c4a5fe1SAndy Fiddaman nvlist_free_string(parent, name);
153*5c4a5fe1SAndy Fiddaman else if (nvlist_exists(parent, name))
154*5c4a5fe1SAndy Fiddaman errx(4,
155*5c4a5fe1SAndy Fiddaman "Attempting to add value %s to existing node %s of list %p",
156*5c4a5fe1SAndy Fiddaman value, name, parent);
157*5c4a5fe1SAndy Fiddaman nvlist_add_string(parent, name, value);
158*5c4a5fe1SAndy Fiddaman }
159*5c4a5fe1SAndy Fiddaman
160*5c4a5fe1SAndy Fiddaman void
set_config_value_node_if_unset(nvlist_t * const parent,const char * const name,const char * const value)161*5c4a5fe1SAndy Fiddaman set_config_value_node_if_unset(nvlist_t *const parent, const char *const name,
162*5c4a5fe1SAndy Fiddaman const char *const value)
163*5c4a5fe1SAndy Fiddaman {
164*5c4a5fe1SAndy Fiddaman if (get_config_value_node(parent, name) != NULL) {
165*5c4a5fe1SAndy Fiddaman return;
166*5c4a5fe1SAndy Fiddaman }
167*5c4a5fe1SAndy Fiddaman
168*5c4a5fe1SAndy Fiddaman set_config_value_node(parent, name, value);
169*5c4a5fe1SAndy Fiddaman }
170*5c4a5fe1SAndy Fiddaman
171*5c4a5fe1SAndy Fiddaman void
set_config_value(const char * path,const char * value)172*5c4a5fe1SAndy Fiddaman set_config_value(const char *path, const char *value)
173*5c4a5fe1SAndy Fiddaman {
174*5c4a5fe1SAndy Fiddaman const char *name;
175*5c4a5fe1SAndy Fiddaman char *node_name;
176*5c4a5fe1SAndy Fiddaman nvlist_t *nvl;
177*5c4a5fe1SAndy Fiddaman
178*5c4a5fe1SAndy Fiddaman /* Look for last separator. */
179*5c4a5fe1SAndy Fiddaman name = strrchr(path, '.');
180*5c4a5fe1SAndy Fiddaman if (name == NULL) {
181*5c4a5fe1SAndy Fiddaman nvl = config_root;
182*5c4a5fe1SAndy Fiddaman name = path;
183*5c4a5fe1SAndy Fiddaman } else {
184*5c4a5fe1SAndy Fiddaman node_name = strndup(path, name - path);
185*5c4a5fe1SAndy Fiddaman if (node_name == NULL)
186*5c4a5fe1SAndy Fiddaman errx(4, "Failed to allocate memory");
187*5c4a5fe1SAndy Fiddaman nvl = create_config_node(node_name);
188*5c4a5fe1SAndy Fiddaman if (nvl == NULL)
189*5c4a5fe1SAndy Fiddaman errx(4, "Failed to create configuration node %s",
190*5c4a5fe1SAndy Fiddaman node_name);
191*5c4a5fe1SAndy Fiddaman free(node_name);
192*5c4a5fe1SAndy Fiddaman
193*5c4a5fe1SAndy Fiddaman /* Skip over '.'. */
194*5c4a5fe1SAndy Fiddaman name++;
195*5c4a5fe1SAndy Fiddaman }
196*5c4a5fe1SAndy Fiddaman
197*5c4a5fe1SAndy Fiddaman if (nvlist_exists_nvlist(nvl, name))
198*5c4a5fe1SAndy Fiddaman errx(4, "Attempting to add value %s to existing node %s",
199*5c4a5fe1SAndy Fiddaman value, path);
200*5c4a5fe1SAndy Fiddaman set_config_value_node(nvl, name, value);
201*5c4a5fe1SAndy Fiddaman }
202*5c4a5fe1SAndy Fiddaman
203*5c4a5fe1SAndy Fiddaman void
set_config_value_if_unset(const char * const path,const char * const value)204*5c4a5fe1SAndy Fiddaman set_config_value_if_unset(const char *const path, const char *const value)
205*5c4a5fe1SAndy Fiddaman {
206*5c4a5fe1SAndy Fiddaman if (get_config_value(path) != NULL) {
207*5c4a5fe1SAndy Fiddaman return;
208*5c4a5fe1SAndy Fiddaman }
209*5c4a5fe1SAndy Fiddaman
210*5c4a5fe1SAndy Fiddaman set_config_value(path, value);
211*5c4a5fe1SAndy Fiddaman }
212*5c4a5fe1SAndy Fiddaman
213*5c4a5fe1SAndy Fiddaman static const char *
get_raw_config_value(const char * path)214*5c4a5fe1SAndy Fiddaman get_raw_config_value(const char *path)
215*5c4a5fe1SAndy Fiddaman {
216*5c4a5fe1SAndy Fiddaman const char *name;
217*5c4a5fe1SAndy Fiddaman char *node_name;
218*5c4a5fe1SAndy Fiddaman nvlist_t *nvl;
219*5c4a5fe1SAndy Fiddaman
220*5c4a5fe1SAndy Fiddaman /* Look for last separator. */
221*5c4a5fe1SAndy Fiddaman name = strrchr(path, '.');
222*5c4a5fe1SAndy Fiddaman if (name == NULL) {
223*5c4a5fe1SAndy Fiddaman nvl = config_root;
224*5c4a5fe1SAndy Fiddaman name = path;
225*5c4a5fe1SAndy Fiddaman } else {
226*5c4a5fe1SAndy Fiddaman node_name = strndup(path, name - path);
227*5c4a5fe1SAndy Fiddaman if (node_name == NULL)
228*5c4a5fe1SAndy Fiddaman errx(4, "Failed to allocate memory");
229*5c4a5fe1SAndy Fiddaman nvl = find_config_node(node_name);
230*5c4a5fe1SAndy Fiddaman free(node_name);
231*5c4a5fe1SAndy Fiddaman if (nvl == NULL)
232*5c4a5fe1SAndy Fiddaman return (NULL);
233*5c4a5fe1SAndy Fiddaman
234*5c4a5fe1SAndy Fiddaman /* Skip over '.'. */
235*5c4a5fe1SAndy Fiddaman name++;
236*5c4a5fe1SAndy Fiddaman }
237*5c4a5fe1SAndy Fiddaman
238*5c4a5fe1SAndy Fiddaman if (nvlist_exists_string(nvl, name))
239*5c4a5fe1SAndy Fiddaman return (nvlist_get_string(nvl, name));
240*5c4a5fe1SAndy Fiddaman if (nvlist_exists_nvlist(nvl, name))
241*5c4a5fe1SAndy Fiddaman warnx("Attempting to fetch value of node %s", path);
242*5c4a5fe1SAndy Fiddaman return (NULL);
243*5c4a5fe1SAndy Fiddaman }
244*5c4a5fe1SAndy Fiddaman
245*5c4a5fe1SAndy Fiddaman static char *
_expand_config_value(const char * value,int depth)246*5c4a5fe1SAndy Fiddaman _expand_config_value(const char *value, int depth)
247*5c4a5fe1SAndy Fiddaman {
248*5c4a5fe1SAndy Fiddaman FILE *valfp;
249*5c4a5fe1SAndy Fiddaman const char *cp, *vp;
250*5c4a5fe1SAndy Fiddaman char *nestedval, *path, *valbuf;
251*5c4a5fe1SAndy Fiddaman size_t valsize;
252*5c4a5fe1SAndy Fiddaman
253*5c4a5fe1SAndy Fiddaman valfp = open_memstream(&valbuf, &valsize);
254*5c4a5fe1SAndy Fiddaman if (valfp == NULL)
255*5c4a5fe1SAndy Fiddaman errx(4, "Failed to allocate memory");
256*5c4a5fe1SAndy Fiddaman
257*5c4a5fe1SAndy Fiddaman vp = value;
258*5c4a5fe1SAndy Fiddaman while (*vp != '\0') {
259*5c4a5fe1SAndy Fiddaman switch (*vp) {
260*5c4a5fe1SAndy Fiddaman case '%':
261*5c4a5fe1SAndy Fiddaman if (depth > 15) {
262*5c4a5fe1SAndy Fiddaman warnx(
263*5c4a5fe1SAndy Fiddaman "Too many recursive references in configuration value");
264*5c4a5fe1SAndy Fiddaman fputc('%', valfp);
265*5c4a5fe1SAndy Fiddaman vp++;
266*5c4a5fe1SAndy Fiddaman break;
267*5c4a5fe1SAndy Fiddaman }
268*5c4a5fe1SAndy Fiddaman if (vp[1] != '(' || vp[2] == '\0')
269*5c4a5fe1SAndy Fiddaman cp = NULL;
270*5c4a5fe1SAndy Fiddaman else
271*5c4a5fe1SAndy Fiddaman cp = strchr(vp + 2, ')');
272*5c4a5fe1SAndy Fiddaman if (cp == NULL) {
273*5c4a5fe1SAndy Fiddaman warnx(
274*5c4a5fe1SAndy Fiddaman "Invalid reference in configuration value \"%s\"",
275*5c4a5fe1SAndy Fiddaman value);
276*5c4a5fe1SAndy Fiddaman fputc('%', valfp);
277*5c4a5fe1SAndy Fiddaman vp++;
278*5c4a5fe1SAndy Fiddaman break;
279*5c4a5fe1SAndy Fiddaman }
280*5c4a5fe1SAndy Fiddaman vp += 2;
281*5c4a5fe1SAndy Fiddaman
282*5c4a5fe1SAndy Fiddaman if (cp == vp) {
283*5c4a5fe1SAndy Fiddaman warnx(
284*5c4a5fe1SAndy Fiddaman "Empty reference in configuration value \"%s\"",
285*5c4a5fe1SAndy Fiddaman value);
286*5c4a5fe1SAndy Fiddaman vp++;
287*5c4a5fe1SAndy Fiddaman break;
288*5c4a5fe1SAndy Fiddaman }
289*5c4a5fe1SAndy Fiddaman
290*5c4a5fe1SAndy Fiddaman /* Allocate a C string holding the path. */
291*5c4a5fe1SAndy Fiddaman path = strndup(vp, cp - vp);
292*5c4a5fe1SAndy Fiddaman if (path == NULL)
293*5c4a5fe1SAndy Fiddaman errx(4, "Failed to allocate memory");
294*5c4a5fe1SAndy Fiddaman
295*5c4a5fe1SAndy Fiddaman /* Advance 'vp' past the reference. */
296*5c4a5fe1SAndy Fiddaman vp = cp + 1;
297*5c4a5fe1SAndy Fiddaman
298*5c4a5fe1SAndy Fiddaman /* Fetch the referenced value. */
299*5c4a5fe1SAndy Fiddaman cp = get_raw_config_value(path);
300*5c4a5fe1SAndy Fiddaman if (cp == NULL)
301*5c4a5fe1SAndy Fiddaman warnx(
302*5c4a5fe1SAndy Fiddaman "Failed to fetch referenced configuration variable %s",
303*5c4a5fe1SAndy Fiddaman path);
304*5c4a5fe1SAndy Fiddaman else {
305*5c4a5fe1SAndy Fiddaman nestedval = _expand_config_value(cp, depth + 1);
306*5c4a5fe1SAndy Fiddaman fputs(nestedval, valfp);
307*5c4a5fe1SAndy Fiddaman free(nestedval);
308*5c4a5fe1SAndy Fiddaman }
309*5c4a5fe1SAndy Fiddaman free(path);
310*5c4a5fe1SAndy Fiddaman break;
311*5c4a5fe1SAndy Fiddaman case '\\':
312*5c4a5fe1SAndy Fiddaman vp++;
313*5c4a5fe1SAndy Fiddaman if (*vp == '\0') {
314*5c4a5fe1SAndy Fiddaman warnx(
315*5c4a5fe1SAndy Fiddaman "Trailing \\ in configuration value \"%s\"",
316*5c4a5fe1SAndy Fiddaman value);
317*5c4a5fe1SAndy Fiddaman break;
318*5c4a5fe1SAndy Fiddaman }
319*5c4a5fe1SAndy Fiddaman /* FALLTHROUGH */
320*5c4a5fe1SAndy Fiddaman default:
321*5c4a5fe1SAndy Fiddaman fputc(*vp, valfp);
322*5c4a5fe1SAndy Fiddaman vp++;
323*5c4a5fe1SAndy Fiddaman break;
324*5c4a5fe1SAndy Fiddaman }
325*5c4a5fe1SAndy Fiddaman }
326*5c4a5fe1SAndy Fiddaman fclose(valfp);
327*5c4a5fe1SAndy Fiddaman return (valbuf);
328*5c4a5fe1SAndy Fiddaman }
329*5c4a5fe1SAndy Fiddaman
330*5c4a5fe1SAndy Fiddaman static const char *
expand_config_value(const char * value)331*5c4a5fe1SAndy Fiddaman expand_config_value(const char *value)
332*5c4a5fe1SAndy Fiddaman {
333*5c4a5fe1SAndy Fiddaman static char *valbuf;
334*5c4a5fe1SAndy Fiddaman
335*5c4a5fe1SAndy Fiddaman if (strchr(value, '%') == NULL)
336*5c4a5fe1SAndy Fiddaman return (value);
337*5c4a5fe1SAndy Fiddaman
338*5c4a5fe1SAndy Fiddaman free(valbuf);
339*5c4a5fe1SAndy Fiddaman valbuf = _expand_config_value(value, 0);
340*5c4a5fe1SAndy Fiddaman return (valbuf);
341*5c4a5fe1SAndy Fiddaman }
342*5c4a5fe1SAndy Fiddaman
343*5c4a5fe1SAndy Fiddaman const char *
get_config_value(const char * path)344*5c4a5fe1SAndy Fiddaman get_config_value(const char *path)
345*5c4a5fe1SAndy Fiddaman {
346*5c4a5fe1SAndy Fiddaman const char *value;
347*5c4a5fe1SAndy Fiddaman
348*5c4a5fe1SAndy Fiddaman value = get_raw_config_value(path);
349*5c4a5fe1SAndy Fiddaman if (value == NULL)
350*5c4a5fe1SAndy Fiddaman return (NULL);
351*5c4a5fe1SAndy Fiddaman return (expand_config_value(value));
352*5c4a5fe1SAndy Fiddaman }
353*5c4a5fe1SAndy Fiddaman
354*5c4a5fe1SAndy Fiddaman const char *
get_config_value_node(const nvlist_t * parent,const char * name)355*5c4a5fe1SAndy Fiddaman get_config_value_node(const nvlist_t *parent, const char *name)
356*5c4a5fe1SAndy Fiddaman {
357*5c4a5fe1SAndy Fiddaman
358*5c4a5fe1SAndy Fiddaman if (strchr(name, '.') != NULL)
359*5c4a5fe1SAndy Fiddaman errx(4, "Invalid config node name %s", name);
360*5c4a5fe1SAndy Fiddaman if (parent == NULL)
361*5c4a5fe1SAndy Fiddaman parent = config_root;
362*5c4a5fe1SAndy Fiddaman
363*5c4a5fe1SAndy Fiddaman if (nvlist_exists_nvlist(parent, name))
364*5c4a5fe1SAndy Fiddaman warnx("Attempt to fetch value of node %s of list %p", name,
365*5c4a5fe1SAndy Fiddaman parent);
366*5c4a5fe1SAndy Fiddaman if (!nvlist_exists_string(parent, name))
367*5c4a5fe1SAndy Fiddaman return (NULL);
368*5c4a5fe1SAndy Fiddaman
369*5c4a5fe1SAndy Fiddaman return (expand_config_value(nvlist_get_string(parent, name)));
370*5c4a5fe1SAndy Fiddaman }
371*5c4a5fe1SAndy Fiddaman
372*5c4a5fe1SAndy Fiddaman static bool
_bool_value(const char * name,const char * value)373*5c4a5fe1SAndy Fiddaman _bool_value(const char *name, const char *value)
374*5c4a5fe1SAndy Fiddaman {
375*5c4a5fe1SAndy Fiddaman
376*5c4a5fe1SAndy Fiddaman if (strcasecmp(value, "true") == 0 ||
377*5c4a5fe1SAndy Fiddaman strcasecmp(value, "on") == 0 ||
378*5c4a5fe1SAndy Fiddaman strcasecmp(value, "yes") == 0 ||
379*5c4a5fe1SAndy Fiddaman strcmp(value, "1") == 0)
380*5c4a5fe1SAndy Fiddaman return (true);
381*5c4a5fe1SAndy Fiddaman if (strcasecmp(value, "false") == 0 ||
382*5c4a5fe1SAndy Fiddaman strcasecmp(value, "off") == 0 ||
383*5c4a5fe1SAndy Fiddaman strcasecmp(value, "no") == 0 ||
384*5c4a5fe1SAndy Fiddaman strcmp(value, "0") == 0)
385*5c4a5fe1SAndy Fiddaman return (false);
386*5c4a5fe1SAndy Fiddaman err(4, "Invalid value %s for boolean variable %s", value, name);
387*5c4a5fe1SAndy Fiddaman }
388*5c4a5fe1SAndy Fiddaman
389*5c4a5fe1SAndy Fiddaman bool
get_config_bool(const char * path)390*5c4a5fe1SAndy Fiddaman get_config_bool(const char *path)
391*5c4a5fe1SAndy Fiddaman {
392*5c4a5fe1SAndy Fiddaman const char *value;
393*5c4a5fe1SAndy Fiddaman
394*5c4a5fe1SAndy Fiddaman value = get_config_value(path);
395*5c4a5fe1SAndy Fiddaman if (value == NULL)
396*5c4a5fe1SAndy Fiddaman err(4, "Failed to fetch boolean variable %s", path);
397*5c4a5fe1SAndy Fiddaman return (_bool_value(path, value));
398*5c4a5fe1SAndy Fiddaman }
399*5c4a5fe1SAndy Fiddaman
400*5c4a5fe1SAndy Fiddaman bool
get_config_bool_default(const char * path,bool def)401*5c4a5fe1SAndy Fiddaman get_config_bool_default(const char *path, bool def)
402*5c4a5fe1SAndy Fiddaman {
403*5c4a5fe1SAndy Fiddaman const char *value;
404*5c4a5fe1SAndy Fiddaman
405*5c4a5fe1SAndy Fiddaman value = get_config_value(path);
406*5c4a5fe1SAndy Fiddaman if (value == NULL)
407*5c4a5fe1SAndy Fiddaman return (def);
408*5c4a5fe1SAndy Fiddaman return (_bool_value(path, value));
409*5c4a5fe1SAndy Fiddaman }
410*5c4a5fe1SAndy Fiddaman
411*5c4a5fe1SAndy Fiddaman bool
get_config_bool_node(const nvlist_t * parent,const char * name)412*5c4a5fe1SAndy Fiddaman get_config_bool_node(const nvlist_t *parent, const char *name)
413*5c4a5fe1SAndy Fiddaman {
414*5c4a5fe1SAndy Fiddaman const char *value;
415*5c4a5fe1SAndy Fiddaman
416*5c4a5fe1SAndy Fiddaman value = get_config_value_node(parent, name);
417*5c4a5fe1SAndy Fiddaman if (value == NULL)
418*5c4a5fe1SAndy Fiddaman err(4, "Failed to fetch boolean variable %s", name);
419*5c4a5fe1SAndy Fiddaman return (_bool_value(name, value));
420*5c4a5fe1SAndy Fiddaman }
421*5c4a5fe1SAndy Fiddaman
422*5c4a5fe1SAndy Fiddaman bool
get_config_bool_node_default(const nvlist_t * parent,const char * name,bool def)423*5c4a5fe1SAndy Fiddaman get_config_bool_node_default(const nvlist_t *parent, const char *name,
424*5c4a5fe1SAndy Fiddaman bool def)
425*5c4a5fe1SAndy Fiddaman {
426*5c4a5fe1SAndy Fiddaman const char *value;
427*5c4a5fe1SAndy Fiddaman
428*5c4a5fe1SAndy Fiddaman value = get_config_value_node(parent, name);
429*5c4a5fe1SAndy Fiddaman if (value == NULL)
430*5c4a5fe1SAndy Fiddaman return (def);
431*5c4a5fe1SAndy Fiddaman return (_bool_value(name, value));
432*5c4a5fe1SAndy Fiddaman }
433*5c4a5fe1SAndy Fiddaman
434*5c4a5fe1SAndy Fiddaman void
set_config_bool(const char * path,bool value)435*5c4a5fe1SAndy Fiddaman set_config_bool(const char *path, bool value)
436*5c4a5fe1SAndy Fiddaman {
437*5c4a5fe1SAndy Fiddaman
438*5c4a5fe1SAndy Fiddaman set_config_value(path, value ? "true" : "false");
439*5c4a5fe1SAndy Fiddaman }
440*5c4a5fe1SAndy Fiddaman
441*5c4a5fe1SAndy Fiddaman void
set_config_bool_node(nvlist_t * parent,const char * name,bool value)442*5c4a5fe1SAndy Fiddaman set_config_bool_node(nvlist_t *parent, const char *name, bool value)
443*5c4a5fe1SAndy Fiddaman {
444*5c4a5fe1SAndy Fiddaman
445*5c4a5fe1SAndy Fiddaman set_config_value_node(parent, name, value ? "true" : "false");
446*5c4a5fe1SAndy Fiddaman }
447*5c4a5fe1SAndy Fiddaman
448*5c4a5fe1SAndy Fiddaman static void
dump_tree(const char * prefix,const nvlist_t * nvl)449*5c4a5fe1SAndy Fiddaman dump_tree(const char *prefix, const nvlist_t *nvl)
450*5c4a5fe1SAndy Fiddaman {
451*5c4a5fe1SAndy Fiddaman const char *name;
452*5c4a5fe1SAndy Fiddaman void *cookie;
453*5c4a5fe1SAndy Fiddaman int type;
454*5c4a5fe1SAndy Fiddaman
455*5c4a5fe1SAndy Fiddaman cookie = NULL;
456*5c4a5fe1SAndy Fiddaman while ((name = nvlist_next(nvl, &type, &cookie)) != NULL) {
457*5c4a5fe1SAndy Fiddaman if (type == NV_TYPE_NVLIST) {
458*5c4a5fe1SAndy Fiddaman char *new_prefix;
459*5c4a5fe1SAndy Fiddaman
460*5c4a5fe1SAndy Fiddaman asprintf(&new_prefix, "%s%s.", prefix, name);
461*5c4a5fe1SAndy Fiddaman dump_tree(new_prefix, nvlist_get_nvlist(nvl, name));
462*5c4a5fe1SAndy Fiddaman free(new_prefix);
463*5c4a5fe1SAndy Fiddaman } else {
464*5c4a5fe1SAndy Fiddaman assert(type == NV_TYPE_STRING);
465*5c4a5fe1SAndy Fiddaman printf("%s%s=%s\n", prefix, name,
466*5c4a5fe1SAndy Fiddaman nvlist_get_string(nvl, name));
467*5c4a5fe1SAndy Fiddaman }
468*5c4a5fe1SAndy Fiddaman }
469*5c4a5fe1SAndy Fiddaman }
470*5c4a5fe1SAndy Fiddaman
471*5c4a5fe1SAndy Fiddaman void
dump_config(void)472*5c4a5fe1SAndy Fiddaman dump_config(void)
473*5c4a5fe1SAndy Fiddaman {
474*5c4a5fe1SAndy Fiddaman dump_tree("", config_root);
475*5c4a5fe1SAndy Fiddaman }
476