1*86d7f5d3SJohn Marino /* $NetBSD: config.c,v 1.1.1.2 2009/12/02 00:26:28 haad Exp $ */
2*86d7f5d3SJohn Marino
3*86d7f5d3SJohn Marino /*
4*86d7f5d3SJohn Marino * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5*86d7f5d3SJohn Marino * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
6*86d7f5d3SJohn Marino *
7*86d7f5d3SJohn Marino * This file is part of LVM2.
8*86d7f5d3SJohn Marino *
9*86d7f5d3SJohn Marino * This copyrighted material is made available to anyone wishing to use,
10*86d7f5d3SJohn Marino * modify, copy, or redistribute it subject to the terms and conditions
11*86d7f5d3SJohn Marino * of the GNU Lesser General Public License v.2.1.
12*86d7f5d3SJohn Marino *
13*86d7f5d3SJohn Marino * You should have received a copy of the GNU Lesser General Public License
14*86d7f5d3SJohn Marino * along with this program; if not, write to the Free Software Foundation,
15*86d7f5d3SJohn Marino * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16*86d7f5d3SJohn Marino */
17*86d7f5d3SJohn Marino
18*86d7f5d3SJohn Marino #include "lib.h"
19*86d7f5d3SJohn Marino #include "config.h"
20*86d7f5d3SJohn Marino #include "crc.h"
21*86d7f5d3SJohn Marino #include "device.h"
22*86d7f5d3SJohn Marino #include "str_list.h"
23*86d7f5d3SJohn Marino #include "toolcontext.h"
24*86d7f5d3SJohn Marino #include "lvm-string.h"
25*86d7f5d3SJohn Marino #include "lvm-file.h"
26*86d7f5d3SJohn Marino
27*86d7f5d3SJohn Marino #include <sys/stat.h>
28*86d7f5d3SJohn Marino #include <sys/mman.h>
29*86d7f5d3SJohn Marino #include <unistd.h>
30*86d7f5d3SJohn Marino #include <fcntl.h>
31*86d7f5d3SJohn Marino #include <ctype.h>
32*86d7f5d3SJohn Marino
33*86d7f5d3SJohn Marino #define SECTION_B_CHAR '{'
34*86d7f5d3SJohn Marino #define SECTION_E_CHAR '}'
35*86d7f5d3SJohn Marino
36*86d7f5d3SJohn Marino enum {
37*86d7f5d3SJohn Marino TOK_INT,
38*86d7f5d3SJohn Marino TOK_FLOAT,
39*86d7f5d3SJohn Marino TOK_STRING, /* Single quotes */
40*86d7f5d3SJohn Marino TOK_STRING_ESCAPED, /* Double quotes */
41*86d7f5d3SJohn Marino TOK_EQ,
42*86d7f5d3SJohn Marino TOK_SECTION_B,
43*86d7f5d3SJohn Marino TOK_SECTION_E,
44*86d7f5d3SJohn Marino TOK_ARRAY_B,
45*86d7f5d3SJohn Marino TOK_ARRAY_E,
46*86d7f5d3SJohn Marino TOK_IDENTIFIER,
47*86d7f5d3SJohn Marino TOK_COMMA,
48*86d7f5d3SJohn Marino TOK_EOF
49*86d7f5d3SJohn Marino };
50*86d7f5d3SJohn Marino
51*86d7f5d3SJohn Marino struct parser {
52*86d7f5d3SJohn Marino const char *fb, *fe; /* file limits */
53*86d7f5d3SJohn Marino
54*86d7f5d3SJohn Marino int t; /* token limits and type */
55*86d7f5d3SJohn Marino const char *tb, *te;
56*86d7f5d3SJohn Marino
57*86d7f5d3SJohn Marino int fd; /* descriptor for file being parsed */
58*86d7f5d3SJohn Marino int line; /* line number we are on */
59*86d7f5d3SJohn Marino
60*86d7f5d3SJohn Marino struct dm_pool *mem;
61*86d7f5d3SJohn Marino };
62*86d7f5d3SJohn Marino
63*86d7f5d3SJohn Marino struct cs {
64*86d7f5d3SJohn Marino struct config_tree cft;
65*86d7f5d3SJohn Marino struct dm_pool *mem;
66*86d7f5d3SJohn Marino time_t timestamp;
67*86d7f5d3SJohn Marino char *filename;
68*86d7f5d3SJohn Marino int exists;
69*86d7f5d3SJohn Marino int keep_open;
70*86d7f5d3SJohn Marino struct device *dev;
71*86d7f5d3SJohn Marino };
72*86d7f5d3SJohn Marino
73*86d7f5d3SJohn Marino struct output_line {
74*86d7f5d3SJohn Marino FILE *fp;
75*86d7f5d3SJohn Marino struct dm_pool *mem;
76*86d7f5d3SJohn Marino putline_fn putline;
77*86d7f5d3SJohn Marino void *putline_baton;
78*86d7f5d3SJohn Marino };
79*86d7f5d3SJohn Marino
80*86d7f5d3SJohn Marino static void _get_token(struct parser *p, int tok_prev);
81*86d7f5d3SJohn Marino static void _eat_space(struct parser *p);
82*86d7f5d3SJohn Marino static struct config_node *_file(struct parser *p);
83*86d7f5d3SJohn Marino static struct config_node *_section(struct parser *p);
84*86d7f5d3SJohn Marino static struct config_value *_value(struct parser *p);
85*86d7f5d3SJohn Marino static struct config_value *_type(struct parser *p);
86*86d7f5d3SJohn Marino static int _match_aux(struct parser *p, int t);
87*86d7f5d3SJohn Marino static struct config_value *_create_value(struct dm_pool *mem);
88*86d7f5d3SJohn Marino static struct config_node *_create_node(struct dm_pool *mem);
89*86d7f5d3SJohn Marino static char *_dup_tok(struct parser *p);
90*86d7f5d3SJohn Marino
91*86d7f5d3SJohn Marino static const int sep = '/';
92*86d7f5d3SJohn Marino
93*86d7f5d3SJohn Marino #define MAX_INDENT 32
94*86d7f5d3SJohn Marino
95*86d7f5d3SJohn Marino #define match(t) do {\
96*86d7f5d3SJohn Marino if (!_match_aux(p, (t))) {\
97*86d7f5d3SJohn Marino log_error("Parse error at byte %" PRIptrdiff_t " (line %d): unexpected token", \
98*86d7f5d3SJohn Marino p->tb - p->fb + 1, p->line); \
99*86d7f5d3SJohn Marino return 0;\
100*86d7f5d3SJohn Marino } \
101*86d7f5d3SJohn Marino } while(0);
102*86d7f5d3SJohn Marino
_tok_match(const char * str,const char * b,const char * e)103*86d7f5d3SJohn Marino static int _tok_match(const char *str, const char *b, const char *e)
104*86d7f5d3SJohn Marino {
105*86d7f5d3SJohn Marino while (*str && (b != e)) {
106*86d7f5d3SJohn Marino if (*str++ != *b++)
107*86d7f5d3SJohn Marino return 0;
108*86d7f5d3SJohn Marino }
109*86d7f5d3SJohn Marino
110*86d7f5d3SJohn Marino return !(*str || (b != e));
111*86d7f5d3SJohn Marino }
112*86d7f5d3SJohn Marino
113*86d7f5d3SJohn Marino /*
114*86d7f5d3SJohn Marino * public interface
115*86d7f5d3SJohn Marino */
create_config_tree(const char * filename,int keep_open)116*86d7f5d3SJohn Marino struct config_tree *create_config_tree(const char *filename, int keep_open)
117*86d7f5d3SJohn Marino {
118*86d7f5d3SJohn Marino struct cs *c;
119*86d7f5d3SJohn Marino struct dm_pool *mem = dm_pool_create("config", 10 * 1024);
120*86d7f5d3SJohn Marino
121*86d7f5d3SJohn Marino if (!mem) {
122*86d7f5d3SJohn Marino log_error("Failed to allocate config pool.");
123*86d7f5d3SJohn Marino return 0;
124*86d7f5d3SJohn Marino }
125*86d7f5d3SJohn Marino
126*86d7f5d3SJohn Marino if (!(c = dm_pool_zalloc(mem, sizeof(*c)))) {
127*86d7f5d3SJohn Marino log_error("Failed to allocate config tree.");
128*86d7f5d3SJohn Marino dm_pool_destroy(mem);
129*86d7f5d3SJohn Marino return 0;
130*86d7f5d3SJohn Marino }
131*86d7f5d3SJohn Marino
132*86d7f5d3SJohn Marino c->mem = mem;
133*86d7f5d3SJohn Marino c->cft.root = (struct config_node *) NULL;
134*86d7f5d3SJohn Marino c->timestamp = 0;
135*86d7f5d3SJohn Marino c->exists = 0;
136*86d7f5d3SJohn Marino c->keep_open = keep_open;
137*86d7f5d3SJohn Marino c->dev = 0;
138*86d7f5d3SJohn Marino if (filename)
139*86d7f5d3SJohn Marino c->filename = dm_pool_strdup(c->mem, filename);
140*86d7f5d3SJohn Marino return &c->cft;
141*86d7f5d3SJohn Marino }
142*86d7f5d3SJohn Marino
destroy_config_tree(struct config_tree * cft)143*86d7f5d3SJohn Marino void destroy_config_tree(struct config_tree *cft)
144*86d7f5d3SJohn Marino {
145*86d7f5d3SJohn Marino struct cs *c = (struct cs *) cft;
146*86d7f5d3SJohn Marino
147*86d7f5d3SJohn Marino if (c->dev)
148*86d7f5d3SJohn Marino dev_close(c->dev);
149*86d7f5d3SJohn Marino
150*86d7f5d3SJohn Marino dm_pool_destroy(c->mem);
151*86d7f5d3SJohn Marino }
152*86d7f5d3SJohn Marino
_parse_config_file(struct parser * p,struct config_tree * cft)153*86d7f5d3SJohn Marino static int _parse_config_file(struct parser *p, struct config_tree *cft)
154*86d7f5d3SJohn Marino {
155*86d7f5d3SJohn Marino p->tb = p->te = p->fb;
156*86d7f5d3SJohn Marino p->line = 1;
157*86d7f5d3SJohn Marino _get_token(p, TOK_SECTION_E);
158*86d7f5d3SJohn Marino if (!(cft->root = _file(p)))
159*86d7f5d3SJohn Marino return_0;
160*86d7f5d3SJohn Marino
161*86d7f5d3SJohn Marino return 1;
162*86d7f5d3SJohn Marino }
163*86d7f5d3SJohn Marino
create_config_tree_from_string(struct cmd_context * cmd __attribute ((unused)),const char * config_settings)164*86d7f5d3SJohn Marino struct config_tree *create_config_tree_from_string(struct cmd_context *cmd __attribute((unused)),
165*86d7f5d3SJohn Marino const char *config_settings)
166*86d7f5d3SJohn Marino {
167*86d7f5d3SJohn Marino struct cs *c;
168*86d7f5d3SJohn Marino struct config_tree *cft;
169*86d7f5d3SJohn Marino struct parser *p;
170*86d7f5d3SJohn Marino
171*86d7f5d3SJohn Marino if (!(cft = create_config_tree(NULL, 0)))
172*86d7f5d3SJohn Marino return_NULL;
173*86d7f5d3SJohn Marino
174*86d7f5d3SJohn Marino c = (struct cs *) cft;
175*86d7f5d3SJohn Marino if (!(p = dm_pool_alloc(c->mem, sizeof(*p)))) {
176*86d7f5d3SJohn Marino log_error("Failed to allocate config tree parser.");
177*86d7f5d3SJohn Marino destroy_config_tree(cft);
178*86d7f5d3SJohn Marino return NULL;
179*86d7f5d3SJohn Marino }
180*86d7f5d3SJohn Marino
181*86d7f5d3SJohn Marino p->mem = c->mem;
182*86d7f5d3SJohn Marino p->fb = config_settings;
183*86d7f5d3SJohn Marino p->fe = config_settings + strlen(config_settings);
184*86d7f5d3SJohn Marino
185*86d7f5d3SJohn Marino if (!_parse_config_file(p, cft)) {
186*86d7f5d3SJohn Marino destroy_config_tree(cft);
187*86d7f5d3SJohn Marino return_NULL;
188*86d7f5d3SJohn Marino }
189*86d7f5d3SJohn Marino
190*86d7f5d3SJohn Marino return cft;
191*86d7f5d3SJohn Marino }
192*86d7f5d3SJohn Marino
override_config_tree_from_string(struct cmd_context * cmd,const char * config_settings)193*86d7f5d3SJohn Marino int override_config_tree_from_string(struct cmd_context *cmd,
194*86d7f5d3SJohn Marino const char *config_settings)
195*86d7f5d3SJohn Marino {
196*86d7f5d3SJohn Marino if (!(cmd->cft_override = create_config_tree_from_string(cmd,config_settings))) {
197*86d7f5d3SJohn Marino log_error("Failed to set overridden configuration entries.");
198*86d7f5d3SJohn Marino return 1;
199*86d7f5d3SJohn Marino }
200*86d7f5d3SJohn Marino
201*86d7f5d3SJohn Marino return 0;
202*86d7f5d3SJohn Marino }
203*86d7f5d3SJohn Marino
read_config_fd(struct config_tree * cft,struct device * dev,off_t offset,size_t size,off_t offset2,size_t size2,checksum_fn_t checksum_fn,uint32_t checksum)204*86d7f5d3SJohn Marino int read_config_fd(struct config_tree *cft, struct device *dev,
205*86d7f5d3SJohn Marino off_t offset, size_t size, off_t offset2, size_t size2,
206*86d7f5d3SJohn Marino checksum_fn_t checksum_fn, uint32_t checksum)
207*86d7f5d3SJohn Marino {
208*86d7f5d3SJohn Marino struct cs *c = (struct cs *) cft;
209*86d7f5d3SJohn Marino struct parser *p;
210*86d7f5d3SJohn Marino int r = 0;
211*86d7f5d3SJohn Marino int use_mmap = 1;
212*86d7f5d3SJohn Marino off_t mmap_offset = 0;
213*86d7f5d3SJohn Marino char *buf = NULL;
214*86d7f5d3SJohn Marino
215*86d7f5d3SJohn Marino if (!(p = dm_pool_alloc(c->mem, sizeof(*p))))
216*86d7f5d3SJohn Marino return_0;
217*86d7f5d3SJohn Marino p->mem = c->mem;
218*86d7f5d3SJohn Marino
219*86d7f5d3SJohn Marino /* Only use mmap with regular files */
220*86d7f5d3SJohn Marino if (!(dev->flags & DEV_REGULAR) || size2)
221*86d7f5d3SJohn Marino use_mmap = 0;
222*86d7f5d3SJohn Marino
223*86d7f5d3SJohn Marino if (use_mmap) {
224*86d7f5d3SJohn Marino mmap_offset = offset % lvm_getpagesize();
225*86d7f5d3SJohn Marino /* memory map the file */
226*86d7f5d3SJohn Marino p->fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
227*86d7f5d3SJohn Marino MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);
228*86d7f5d3SJohn Marino if (p->fb == (caddr_t) (-1)) {
229*86d7f5d3SJohn Marino log_sys_error("mmap", dev_name(dev));
230*86d7f5d3SJohn Marino goto out;
231*86d7f5d3SJohn Marino }
232*86d7f5d3SJohn Marino p->fb = p->fb + mmap_offset;
233*86d7f5d3SJohn Marino } else {
234*86d7f5d3SJohn Marino if (!(buf = dm_malloc(size + size2)))
235*86d7f5d3SJohn Marino return_0;
236*86d7f5d3SJohn Marino if (!dev_read_circular(dev, (uint64_t) offset, size,
237*86d7f5d3SJohn Marino (uint64_t) offset2, size2, buf)) {
238*86d7f5d3SJohn Marino goto out;
239*86d7f5d3SJohn Marino }
240*86d7f5d3SJohn Marino p->fb = buf;
241*86d7f5d3SJohn Marino }
242*86d7f5d3SJohn Marino
243*86d7f5d3SJohn Marino if (checksum_fn && checksum !=
244*86d7f5d3SJohn Marino (checksum_fn(checksum_fn(INITIAL_CRC, p->fb, size),
245*86d7f5d3SJohn Marino p->fb + size, size2))) {
246*86d7f5d3SJohn Marino log_error("%s: Checksum error", dev_name(dev));
247*86d7f5d3SJohn Marino goto out;
248*86d7f5d3SJohn Marino }
249*86d7f5d3SJohn Marino
250*86d7f5d3SJohn Marino p->fe = p->fb + size + size2;
251*86d7f5d3SJohn Marino
252*86d7f5d3SJohn Marino if (!_parse_config_file(p, cft))
253*86d7f5d3SJohn Marino goto_out;
254*86d7f5d3SJohn Marino
255*86d7f5d3SJohn Marino r = 1;
256*86d7f5d3SJohn Marino
257*86d7f5d3SJohn Marino out:
258*86d7f5d3SJohn Marino if (!use_mmap)
259*86d7f5d3SJohn Marino dm_free(buf);
260*86d7f5d3SJohn Marino else {
261*86d7f5d3SJohn Marino /* unmap the file */
262*86d7f5d3SJohn Marino if (munmap((char *) (p->fb - mmap_offset), size + mmap_offset)) {
263*86d7f5d3SJohn Marino log_sys_error("munmap", dev_name(dev));
264*86d7f5d3SJohn Marino r = 0;
265*86d7f5d3SJohn Marino }
266*86d7f5d3SJohn Marino }
267*86d7f5d3SJohn Marino
268*86d7f5d3SJohn Marino return r;
269*86d7f5d3SJohn Marino }
270*86d7f5d3SJohn Marino
read_config_file(struct config_tree * cft)271*86d7f5d3SJohn Marino int read_config_file(struct config_tree *cft)
272*86d7f5d3SJohn Marino {
273*86d7f5d3SJohn Marino struct cs *c = (struct cs *) cft;
274*86d7f5d3SJohn Marino struct stat info;
275*86d7f5d3SJohn Marino int r = 1;
276*86d7f5d3SJohn Marino
277*86d7f5d3SJohn Marino if (stat(c->filename, &info)) {
278*86d7f5d3SJohn Marino log_sys_error("stat", c->filename);
279*86d7f5d3SJohn Marino c->exists = 0;
280*86d7f5d3SJohn Marino return 0;
281*86d7f5d3SJohn Marino }
282*86d7f5d3SJohn Marino
283*86d7f5d3SJohn Marino if (!S_ISREG(info.st_mode)) {
284*86d7f5d3SJohn Marino log_error("%s is not a regular file", c->filename);
285*86d7f5d3SJohn Marino c->exists = 0;
286*86d7f5d3SJohn Marino return 0;
287*86d7f5d3SJohn Marino }
288*86d7f5d3SJohn Marino
289*86d7f5d3SJohn Marino c->exists = 1;
290*86d7f5d3SJohn Marino
291*86d7f5d3SJohn Marino if (info.st_size == 0) {
292*86d7f5d3SJohn Marino log_verbose("%s is empty", c->filename);
293*86d7f5d3SJohn Marino return 1;
294*86d7f5d3SJohn Marino }
295*86d7f5d3SJohn Marino
296*86d7f5d3SJohn Marino if (!c->dev) {
297*86d7f5d3SJohn Marino if (!(c->dev = dev_create_file(c->filename, NULL, NULL, 1)))
298*86d7f5d3SJohn Marino return_0;
299*86d7f5d3SJohn Marino
300*86d7f5d3SJohn Marino if (!dev_open_flags(c->dev, O_RDONLY, 0, 0))
301*86d7f5d3SJohn Marino return_0;
302*86d7f5d3SJohn Marino }
303*86d7f5d3SJohn Marino
304*86d7f5d3SJohn Marino r = read_config_fd(cft, c->dev, 0, (size_t) info.st_size, 0, 0,
305*86d7f5d3SJohn Marino (checksum_fn_t) NULL, 0);
306*86d7f5d3SJohn Marino
307*86d7f5d3SJohn Marino if (!c->keep_open) {
308*86d7f5d3SJohn Marino dev_close(c->dev);
309*86d7f5d3SJohn Marino c->dev = 0;
310*86d7f5d3SJohn Marino }
311*86d7f5d3SJohn Marino
312*86d7f5d3SJohn Marino c->timestamp = info.st_ctime;
313*86d7f5d3SJohn Marino
314*86d7f5d3SJohn Marino return r;
315*86d7f5d3SJohn Marino }
316*86d7f5d3SJohn Marino
config_file_timestamp(struct config_tree * cft)317*86d7f5d3SJohn Marino time_t config_file_timestamp(struct config_tree *cft)
318*86d7f5d3SJohn Marino {
319*86d7f5d3SJohn Marino struct cs *c = (struct cs *) cft;
320*86d7f5d3SJohn Marino
321*86d7f5d3SJohn Marino return c->timestamp;
322*86d7f5d3SJohn Marino }
323*86d7f5d3SJohn Marino
324*86d7f5d3SJohn Marino /*
325*86d7f5d3SJohn Marino * Return 1 if config files ought to be reloaded
326*86d7f5d3SJohn Marino */
config_file_changed(struct config_tree * cft)327*86d7f5d3SJohn Marino int config_file_changed(struct config_tree *cft)
328*86d7f5d3SJohn Marino {
329*86d7f5d3SJohn Marino struct cs *c = (struct cs *) cft;
330*86d7f5d3SJohn Marino struct stat info;
331*86d7f5d3SJohn Marino
332*86d7f5d3SJohn Marino if (!c->filename)
333*86d7f5d3SJohn Marino return 0;
334*86d7f5d3SJohn Marino
335*86d7f5d3SJohn Marino if (stat(c->filename, &info) == -1) {
336*86d7f5d3SJohn Marino /* Ignore a deleted config file: still use original data */
337*86d7f5d3SJohn Marino if (errno == ENOENT) {
338*86d7f5d3SJohn Marino if (!c->exists)
339*86d7f5d3SJohn Marino return 0;
340*86d7f5d3SJohn Marino log_very_verbose("Config file %s has disappeared!",
341*86d7f5d3SJohn Marino c->filename);
342*86d7f5d3SJohn Marino goto reload;
343*86d7f5d3SJohn Marino }
344*86d7f5d3SJohn Marino log_sys_error("stat", c->filename);
345*86d7f5d3SJohn Marino log_error("Failed to reload configuration files");
346*86d7f5d3SJohn Marino return 0;
347*86d7f5d3SJohn Marino }
348*86d7f5d3SJohn Marino
349*86d7f5d3SJohn Marino if (!S_ISREG(info.st_mode)) {
350*86d7f5d3SJohn Marino log_error("Configuration file %s is not a regular file",
351*86d7f5d3SJohn Marino c->filename);
352*86d7f5d3SJohn Marino goto reload;
353*86d7f5d3SJohn Marino }
354*86d7f5d3SJohn Marino
355*86d7f5d3SJohn Marino /* Unchanged? */
356*86d7f5d3SJohn Marino if (c->timestamp == info.st_ctime)
357*86d7f5d3SJohn Marino return 0;
358*86d7f5d3SJohn Marino
359*86d7f5d3SJohn Marino reload:
360*86d7f5d3SJohn Marino log_verbose("Detected config file change to %s", c->filename);
361*86d7f5d3SJohn Marino return 1;
362*86d7f5d3SJohn Marino }
363*86d7f5d3SJohn Marino
_line_start(struct output_line * outline)364*86d7f5d3SJohn Marino static int _line_start(struct output_line *outline)
365*86d7f5d3SJohn Marino {
366*86d7f5d3SJohn Marino if (!dm_pool_begin_object(outline->mem, 128)) {
367*86d7f5d3SJohn Marino log_error("dm_pool_begin_object failed for config line");
368*86d7f5d3SJohn Marino return 0;
369*86d7f5d3SJohn Marino }
370*86d7f5d3SJohn Marino
371*86d7f5d3SJohn Marino return 1;
372*86d7f5d3SJohn Marino }
373*86d7f5d3SJohn Marino
374*86d7f5d3SJohn Marino static int _line_append(struct output_line *outline, const char *fmt, ...)
375*86d7f5d3SJohn Marino __attribute__ ((format(printf, 2, 3)));
_line_append(struct output_line * outline,const char * fmt,...)376*86d7f5d3SJohn Marino static int _line_append(struct output_line *outline, const char *fmt, ...)
377*86d7f5d3SJohn Marino {
378*86d7f5d3SJohn Marino char buf[4096];
379*86d7f5d3SJohn Marino va_list ap;
380*86d7f5d3SJohn Marino int n;
381*86d7f5d3SJohn Marino
382*86d7f5d3SJohn Marino va_start(ap, fmt);
383*86d7f5d3SJohn Marino n = vsnprintf(&buf[0], sizeof buf - 1, fmt, ap);
384*86d7f5d3SJohn Marino if (n < 0 || n > (int) sizeof buf - 1) {
385*86d7f5d3SJohn Marino log_error("vsnprintf failed for config line");
386*86d7f5d3SJohn Marino return 0;
387*86d7f5d3SJohn Marino }
388*86d7f5d3SJohn Marino va_end(ap);
389*86d7f5d3SJohn Marino
390*86d7f5d3SJohn Marino if (!dm_pool_grow_object(outline->mem, &buf[0], strlen(buf))) {
391*86d7f5d3SJohn Marino log_error("dm_pool_grow_object failed for config line");
392*86d7f5d3SJohn Marino return 0;
393*86d7f5d3SJohn Marino }
394*86d7f5d3SJohn Marino
395*86d7f5d3SJohn Marino return 1;
396*86d7f5d3SJohn Marino }
397*86d7f5d3SJohn Marino
398*86d7f5d3SJohn Marino #define line_append(args...) do {if (!_line_append(outline, args)) {return_0;}} while (0)
399*86d7f5d3SJohn Marino
_line_end(struct output_line * outline)400*86d7f5d3SJohn Marino static int _line_end(struct output_line *outline)
401*86d7f5d3SJohn Marino {
402*86d7f5d3SJohn Marino const char *line;
403*86d7f5d3SJohn Marino
404*86d7f5d3SJohn Marino if (!dm_pool_grow_object(outline->mem, "\0", 1)) {
405*86d7f5d3SJohn Marino log_error("dm_pool_grow_object failed for config line");
406*86d7f5d3SJohn Marino return 0;
407*86d7f5d3SJohn Marino }
408*86d7f5d3SJohn Marino
409*86d7f5d3SJohn Marino line = dm_pool_end_object(outline->mem);
410*86d7f5d3SJohn Marino if (outline->putline)
411*86d7f5d3SJohn Marino outline->putline(line, outline->putline_baton);
412*86d7f5d3SJohn Marino else {
413*86d7f5d3SJohn Marino if (!outline->fp)
414*86d7f5d3SJohn Marino log_print("%s", line);
415*86d7f5d3SJohn Marino else
416*86d7f5d3SJohn Marino fprintf(outline->fp, "%s\n", line);
417*86d7f5d3SJohn Marino }
418*86d7f5d3SJohn Marino
419*86d7f5d3SJohn Marino return 1;
420*86d7f5d3SJohn Marino }
421*86d7f5d3SJohn Marino
_write_value(struct output_line * outline,struct config_value * v)422*86d7f5d3SJohn Marino static int _write_value(struct output_line *outline, struct config_value *v)
423*86d7f5d3SJohn Marino {
424*86d7f5d3SJohn Marino char *buf;
425*86d7f5d3SJohn Marino
426*86d7f5d3SJohn Marino switch (v->type) {
427*86d7f5d3SJohn Marino case CFG_STRING:
428*86d7f5d3SJohn Marino if (!(buf = alloca(escaped_len(v->v.str)))) {
429*86d7f5d3SJohn Marino log_error("temporary stack allocation for a config "
430*86d7f5d3SJohn Marino "string failed");
431*86d7f5d3SJohn Marino return 0;
432*86d7f5d3SJohn Marino }
433*86d7f5d3SJohn Marino line_append("\"%s\"", escape_double_quotes(buf, v->v.str));
434*86d7f5d3SJohn Marino break;
435*86d7f5d3SJohn Marino
436*86d7f5d3SJohn Marino case CFG_FLOAT:
437*86d7f5d3SJohn Marino line_append("%f", v->v.r);
438*86d7f5d3SJohn Marino break;
439*86d7f5d3SJohn Marino
440*86d7f5d3SJohn Marino case CFG_INT:
441*86d7f5d3SJohn Marino line_append("%" PRId64, v->v.i);
442*86d7f5d3SJohn Marino break;
443*86d7f5d3SJohn Marino
444*86d7f5d3SJohn Marino case CFG_EMPTY_ARRAY:
445*86d7f5d3SJohn Marino line_append("[]");
446*86d7f5d3SJohn Marino break;
447*86d7f5d3SJohn Marino
448*86d7f5d3SJohn Marino default:
449*86d7f5d3SJohn Marino log_error("_write_value: Unknown value type: %d", v->type);
450*86d7f5d3SJohn Marino
451*86d7f5d3SJohn Marino }
452*86d7f5d3SJohn Marino
453*86d7f5d3SJohn Marino return 1;
454*86d7f5d3SJohn Marino }
455*86d7f5d3SJohn Marino
_write_config(const struct config_node * n,int only_one,struct output_line * outline,int level)456*86d7f5d3SJohn Marino static int _write_config(const struct config_node *n, int only_one,
457*86d7f5d3SJohn Marino struct output_line *outline, int level)
458*86d7f5d3SJohn Marino {
459*86d7f5d3SJohn Marino char space[MAX_INDENT + 1];
460*86d7f5d3SJohn Marino int l = (level < MAX_INDENT) ? level : MAX_INDENT;
461*86d7f5d3SJohn Marino int i;
462*86d7f5d3SJohn Marino
463*86d7f5d3SJohn Marino if (!n)
464*86d7f5d3SJohn Marino return 1;
465*86d7f5d3SJohn Marino
466*86d7f5d3SJohn Marino for (i = 0; i < l; i++)
467*86d7f5d3SJohn Marino space[i] = '\t';
468*86d7f5d3SJohn Marino space[i] = '\0';
469*86d7f5d3SJohn Marino
470*86d7f5d3SJohn Marino do {
471*86d7f5d3SJohn Marino if (!_line_start(outline))
472*86d7f5d3SJohn Marino return_0;
473*86d7f5d3SJohn Marino line_append("%s%s", space, n->key);
474*86d7f5d3SJohn Marino if (!n->v) {
475*86d7f5d3SJohn Marino /* it's a sub section */
476*86d7f5d3SJohn Marino line_append(" {");
477*86d7f5d3SJohn Marino if (!_line_end(outline))
478*86d7f5d3SJohn Marino return_0;
479*86d7f5d3SJohn Marino _write_config(n->child, 0, outline, level + 1);
480*86d7f5d3SJohn Marino if (!_line_start(outline))
481*86d7f5d3SJohn Marino return_0;
482*86d7f5d3SJohn Marino line_append("%s}", space);
483*86d7f5d3SJohn Marino } else {
484*86d7f5d3SJohn Marino /* it's a value */
485*86d7f5d3SJohn Marino struct config_value *v = n->v;
486*86d7f5d3SJohn Marino line_append("=");
487*86d7f5d3SJohn Marino if (v->next) {
488*86d7f5d3SJohn Marino line_append("[");
489*86d7f5d3SJohn Marino while (v) {
490*86d7f5d3SJohn Marino if (!_write_value(outline, v))
491*86d7f5d3SJohn Marino return_0;
492*86d7f5d3SJohn Marino v = v->next;
493*86d7f5d3SJohn Marino if (v)
494*86d7f5d3SJohn Marino line_append(", ");
495*86d7f5d3SJohn Marino }
496*86d7f5d3SJohn Marino line_append("]");
497*86d7f5d3SJohn Marino } else
498*86d7f5d3SJohn Marino if (!_write_value(outline, v))
499*86d7f5d3SJohn Marino return_0;
500*86d7f5d3SJohn Marino }
501*86d7f5d3SJohn Marino if (!_line_end(outline))
502*86d7f5d3SJohn Marino return_0;
503*86d7f5d3SJohn Marino n = n->sib;
504*86d7f5d3SJohn Marino } while (n && !only_one);
505*86d7f5d3SJohn Marino /* FIXME: add error checking */
506*86d7f5d3SJohn Marino return 1;
507*86d7f5d3SJohn Marino }
508*86d7f5d3SJohn Marino
write_config_node(const struct config_node * cn,putline_fn putline,void * baton)509*86d7f5d3SJohn Marino int write_config_node(const struct config_node *cn, putline_fn putline, void *baton)
510*86d7f5d3SJohn Marino {
511*86d7f5d3SJohn Marino struct output_line outline;
512*86d7f5d3SJohn Marino outline.fp = NULL;
513*86d7f5d3SJohn Marino outline.mem = dm_pool_create("config_line", 1024);
514*86d7f5d3SJohn Marino outline.putline = putline;
515*86d7f5d3SJohn Marino outline.putline_baton = baton;
516*86d7f5d3SJohn Marino if (!_write_config(cn, 0, &outline, 0)) {
517*86d7f5d3SJohn Marino dm_pool_destroy(outline.mem);
518*86d7f5d3SJohn Marino return_0;
519*86d7f5d3SJohn Marino }
520*86d7f5d3SJohn Marino dm_pool_destroy(outline.mem);
521*86d7f5d3SJohn Marino return 1;
522*86d7f5d3SJohn Marino }
523*86d7f5d3SJohn Marino
write_config_file(struct config_tree * cft,const char * file,int argc,char ** argv)524*86d7f5d3SJohn Marino int write_config_file(struct config_tree *cft, const char *file,
525*86d7f5d3SJohn Marino int argc, char **argv)
526*86d7f5d3SJohn Marino {
527*86d7f5d3SJohn Marino struct config_node *cn;
528*86d7f5d3SJohn Marino int r = 1;
529*86d7f5d3SJohn Marino struct output_line outline;
530*86d7f5d3SJohn Marino outline.fp = NULL;
531*86d7f5d3SJohn Marino outline.putline = NULL;
532*86d7f5d3SJohn Marino
533*86d7f5d3SJohn Marino if (!file)
534*86d7f5d3SJohn Marino file = "stdout";
535*86d7f5d3SJohn Marino else if (!(outline.fp = fopen(file, "w"))) {
536*86d7f5d3SJohn Marino log_sys_error("open", file);
537*86d7f5d3SJohn Marino return 0;
538*86d7f5d3SJohn Marino }
539*86d7f5d3SJohn Marino
540*86d7f5d3SJohn Marino outline.mem = dm_pool_create("config_line", 1024);
541*86d7f5d3SJohn Marino
542*86d7f5d3SJohn Marino log_verbose("Dumping configuration to %s", file);
543*86d7f5d3SJohn Marino if (!argc) {
544*86d7f5d3SJohn Marino if (!_write_config(cft->root, 0, &outline, 0)) {
545*86d7f5d3SJohn Marino log_error("Failure while writing to %s", file);
546*86d7f5d3SJohn Marino r = 0;
547*86d7f5d3SJohn Marino }
548*86d7f5d3SJohn Marino } else while (argc--) {
549*86d7f5d3SJohn Marino if ((cn = find_config_node(cft->root, *argv))) {
550*86d7f5d3SJohn Marino if (!_write_config(cn, 1, &outline, 0)) {
551*86d7f5d3SJohn Marino log_error("Failure while writing to %s", file);
552*86d7f5d3SJohn Marino r = 0;
553*86d7f5d3SJohn Marino }
554*86d7f5d3SJohn Marino } else {
555*86d7f5d3SJohn Marino log_error("Configuration node %s not found", *argv);
556*86d7f5d3SJohn Marino r = 0;
557*86d7f5d3SJohn Marino }
558*86d7f5d3SJohn Marino argv++;
559*86d7f5d3SJohn Marino }
560*86d7f5d3SJohn Marino
561*86d7f5d3SJohn Marino if (outline.fp && lvm_fclose(outline.fp, file)) {
562*86d7f5d3SJohn Marino stack;
563*86d7f5d3SJohn Marino r = 0;
564*86d7f5d3SJohn Marino }
565*86d7f5d3SJohn Marino
566*86d7f5d3SJohn Marino dm_pool_destroy(outline.mem);
567*86d7f5d3SJohn Marino return r;
568*86d7f5d3SJohn Marino }
569*86d7f5d3SJohn Marino
570*86d7f5d3SJohn Marino /*
571*86d7f5d3SJohn Marino * parser
572*86d7f5d3SJohn Marino */
_file(struct parser * p)573*86d7f5d3SJohn Marino static struct config_node *_file(struct parser *p)
574*86d7f5d3SJohn Marino {
575*86d7f5d3SJohn Marino struct config_node *root = NULL, *n, *l = NULL;
576*86d7f5d3SJohn Marino while (p->t != TOK_EOF) {
577*86d7f5d3SJohn Marino if (!(n = _section(p)))
578*86d7f5d3SJohn Marino return_0;
579*86d7f5d3SJohn Marino
580*86d7f5d3SJohn Marino if (!root)
581*86d7f5d3SJohn Marino root = n;
582*86d7f5d3SJohn Marino else
583*86d7f5d3SJohn Marino l->sib = n;
584*86d7f5d3SJohn Marino n->parent = root;
585*86d7f5d3SJohn Marino l = n;
586*86d7f5d3SJohn Marino }
587*86d7f5d3SJohn Marino return root;
588*86d7f5d3SJohn Marino }
589*86d7f5d3SJohn Marino
_section(struct parser * p)590*86d7f5d3SJohn Marino static struct config_node *_section(struct parser *p)
591*86d7f5d3SJohn Marino {
592*86d7f5d3SJohn Marino /* IDENTIFIER SECTION_B_CHAR VALUE* SECTION_E_CHAR */
593*86d7f5d3SJohn Marino struct config_node *root, *n, *l = NULL;
594*86d7f5d3SJohn Marino if (!(root = _create_node(p->mem)))
595*86d7f5d3SJohn Marino return_0;
596*86d7f5d3SJohn Marino
597*86d7f5d3SJohn Marino if (!(root->key = _dup_tok(p)))
598*86d7f5d3SJohn Marino return_0;
599*86d7f5d3SJohn Marino
600*86d7f5d3SJohn Marino match(TOK_IDENTIFIER);
601*86d7f5d3SJohn Marino
602*86d7f5d3SJohn Marino if (p->t == TOK_SECTION_B) {
603*86d7f5d3SJohn Marino match(TOK_SECTION_B);
604*86d7f5d3SJohn Marino while (p->t != TOK_SECTION_E) {
605*86d7f5d3SJohn Marino if (!(n = _section(p)))
606*86d7f5d3SJohn Marino return_0;
607*86d7f5d3SJohn Marino
608*86d7f5d3SJohn Marino if (!root->child)
609*86d7f5d3SJohn Marino root->child = n;
610*86d7f5d3SJohn Marino else
611*86d7f5d3SJohn Marino l->sib = n;
612*86d7f5d3SJohn Marino n->parent = root;
613*86d7f5d3SJohn Marino l = n;
614*86d7f5d3SJohn Marino }
615*86d7f5d3SJohn Marino match(TOK_SECTION_E);
616*86d7f5d3SJohn Marino } else {
617*86d7f5d3SJohn Marino match(TOK_EQ);
618*86d7f5d3SJohn Marino if (!(root->v = _value(p)))
619*86d7f5d3SJohn Marino return_0;
620*86d7f5d3SJohn Marino }
621*86d7f5d3SJohn Marino
622*86d7f5d3SJohn Marino return root;
623*86d7f5d3SJohn Marino }
624*86d7f5d3SJohn Marino
_value(struct parser * p)625*86d7f5d3SJohn Marino static struct config_value *_value(struct parser *p)
626*86d7f5d3SJohn Marino {
627*86d7f5d3SJohn Marino /* '[' TYPE* ']' | TYPE */
628*86d7f5d3SJohn Marino struct config_value *h = NULL, *l, *ll = NULL;
629*86d7f5d3SJohn Marino if (p->t == TOK_ARRAY_B) {
630*86d7f5d3SJohn Marino match(TOK_ARRAY_B);
631*86d7f5d3SJohn Marino while (p->t != TOK_ARRAY_E) {
632*86d7f5d3SJohn Marino if (!(l = _type(p)))
633*86d7f5d3SJohn Marino return_0;
634*86d7f5d3SJohn Marino
635*86d7f5d3SJohn Marino if (!h)
636*86d7f5d3SJohn Marino h = l;
637*86d7f5d3SJohn Marino else
638*86d7f5d3SJohn Marino ll->next = l;
639*86d7f5d3SJohn Marino ll = l;
640*86d7f5d3SJohn Marino
641*86d7f5d3SJohn Marino if (p->t == TOK_COMMA)
642*86d7f5d3SJohn Marino match(TOK_COMMA);
643*86d7f5d3SJohn Marino }
644*86d7f5d3SJohn Marino match(TOK_ARRAY_E);
645*86d7f5d3SJohn Marino /*
646*86d7f5d3SJohn Marino * Special case for an empty array.
647*86d7f5d3SJohn Marino */
648*86d7f5d3SJohn Marino if (!h) {
649*86d7f5d3SJohn Marino if (!(h = _create_value(p->mem)))
650*86d7f5d3SJohn Marino return NULL;
651*86d7f5d3SJohn Marino
652*86d7f5d3SJohn Marino h->type = CFG_EMPTY_ARRAY;
653*86d7f5d3SJohn Marino }
654*86d7f5d3SJohn Marino
655*86d7f5d3SJohn Marino } else
656*86d7f5d3SJohn Marino h = _type(p);
657*86d7f5d3SJohn Marino
658*86d7f5d3SJohn Marino return h;
659*86d7f5d3SJohn Marino }
660*86d7f5d3SJohn Marino
_type(struct parser * p)661*86d7f5d3SJohn Marino static struct config_value *_type(struct parser *p)
662*86d7f5d3SJohn Marino {
663*86d7f5d3SJohn Marino /* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */
664*86d7f5d3SJohn Marino struct config_value *v = _create_value(p->mem);
665*86d7f5d3SJohn Marino
666*86d7f5d3SJohn Marino if (!v)
667*86d7f5d3SJohn Marino return NULL;
668*86d7f5d3SJohn Marino
669*86d7f5d3SJohn Marino switch (p->t) {
670*86d7f5d3SJohn Marino case TOK_INT:
671*86d7f5d3SJohn Marino v->type = CFG_INT;
672*86d7f5d3SJohn Marino v->v.i = strtoll(p->tb, NULL, 0); /* FIXME: check error */
673*86d7f5d3SJohn Marino match(TOK_INT);
674*86d7f5d3SJohn Marino break;
675*86d7f5d3SJohn Marino
676*86d7f5d3SJohn Marino case TOK_FLOAT:
677*86d7f5d3SJohn Marino v->type = CFG_FLOAT;
678*86d7f5d3SJohn Marino v->v.r = strtod(p->tb, NULL); /* FIXME: check error */
679*86d7f5d3SJohn Marino match(TOK_FLOAT);
680*86d7f5d3SJohn Marino break;
681*86d7f5d3SJohn Marino
682*86d7f5d3SJohn Marino case TOK_STRING:
683*86d7f5d3SJohn Marino v->type = CFG_STRING;
684*86d7f5d3SJohn Marino
685*86d7f5d3SJohn Marino p->tb++, p->te--; /* strip "'s */
686*86d7f5d3SJohn Marino if (!(v->v.str = _dup_tok(p)))
687*86d7f5d3SJohn Marino return_0;
688*86d7f5d3SJohn Marino p->te++;
689*86d7f5d3SJohn Marino match(TOK_STRING);
690*86d7f5d3SJohn Marino break;
691*86d7f5d3SJohn Marino
692*86d7f5d3SJohn Marino case TOK_STRING_ESCAPED:
693*86d7f5d3SJohn Marino v->type = CFG_STRING;
694*86d7f5d3SJohn Marino
695*86d7f5d3SJohn Marino p->tb++, p->te--; /* strip "'s */
696*86d7f5d3SJohn Marino if (!(v->v.str = _dup_tok(p)))
697*86d7f5d3SJohn Marino return_0;
698*86d7f5d3SJohn Marino unescape_double_quotes(v->v.str);
699*86d7f5d3SJohn Marino p->te++;
700*86d7f5d3SJohn Marino match(TOK_STRING_ESCAPED);
701*86d7f5d3SJohn Marino break;
702*86d7f5d3SJohn Marino
703*86d7f5d3SJohn Marino default:
704*86d7f5d3SJohn Marino log_error("Parse error at byte %" PRIptrdiff_t " (line %d): expected a value",
705*86d7f5d3SJohn Marino p->tb - p->fb + 1, p->line);
706*86d7f5d3SJohn Marino return 0;
707*86d7f5d3SJohn Marino }
708*86d7f5d3SJohn Marino return v;
709*86d7f5d3SJohn Marino }
710*86d7f5d3SJohn Marino
_match_aux(struct parser * p,int t)711*86d7f5d3SJohn Marino static int _match_aux(struct parser *p, int t)
712*86d7f5d3SJohn Marino {
713*86d7f5d3SJohn Marino if (p->t != t)
714*86d7f5d3SJohn Marino return 0;
715*86d7f5d3SJohn Marino
716*86d7f5d3SJohn Marino _get_token(p, t);
717*86d7f5d3SJohn Marino return 1;
718*86d7f5d3SJohn Marino }
719*86d7f5d3SJohn Marino
720*86d7f5d3SJohn Marino /*
721*86d7f5d3SJohn Marino * tokeniser
722*86d7f5d3SJohn Marino */
_get_token(struct parser * p,int tok_prev)723*86d7f5d3SJohn Marino static void _get_token(struct parser *p, int tok_prev)
724*86d7f5d3SJohn Marino {
725*86d7f5d3SJohn Marino int values_allowed = 0;
726*86d7f5d3SJohn Marino
727*86d7f5d3SJohn Marino p->tb = p->te;
728*86d7f5d3SJohn Marino _eat_space(p);
729*86d7f5d3SJohn Marino if (p->tb == p->fe || !*p->tb) {
730*86d7f5d3SJohn Marino p->t = TOK_EOF;
731*86d7f5d3SJohn Marino return;
732*86d7f5d3SJohn Marino }
733*86d7f5d3SJohn Marino
734*86d7f5d3SJohn Marino /* Should next token be interpreted as value instead of identifier? */
735*86d7f5d3SJohn Marino if (tok_prev == TOK_EQ || tok_prev == TOK_ARRAY_B ||
736*86d7f5d3SJohn Marino tok_prev == TOK_COMMA)
737*86d7f5d3SJohn Marino values_allowed = 1;
738*86d7f5d3SJohn Marino
739*86d7f5d3SJohn Marino p->t = TOK_INT; /* fudge so the fall through for
740*86d7f5d3SJohn Marino floats works */
741*86d7f5d3SJohn Marino switch (*p->te) {
742*86d7f5d3SJohn Marino case SECTION_B_CHAR:
743*86d7f5d3SJohn Marino p->t = TOK_SECTION_B;
744*86d7f5d3SJohn Marino p->te++;
745*86d7f5d3SJohn Marino break;
746*86d7f5d3SJohn Marino
747*86d7f5d3SJohn Marino case SECTION_E_CHAR:
748*86d7f5d3SJohn Marino p->t = TOK_SECTION_E;
749*86d7f5d3SJohn Marino p->te++;
750*86d7f5d3SJohn Marino break;
751*86d7f5d3SJohn Marino
752*86d7f5d3SJohn Marino case '[':
753*86d7f5d3SJohn Marino p->t = TOK_ARRAY_B;
754*86d7f5d3SJohn Marino p->te++;
755*86d7f5d3SJohn Marino break;
756*86d7f5d3SJohn Marino
757*86d7f5d3SJohn Marino case ']':
758*86d7f5d3SJohn Marino p->t = TOK_ARRAY_E;
759*86d7f5d3SJohn Marino p->te++;
760*86d7f5d3SJohn Marino break;
761*86d7f5d3SJohn Marino
762*86d7f5d3SJohn Marino case ',':
763*86d7f5d3SJohn Marino p->t = TOK_COMMA;
764*86d7f5d3SJohn Marino p->te++;
765*86d7f5d3SJohn Marino break;
766*86d7f5d3SJohn Marino
767*86d7f5d3SJohn Marino case '=':
768*86d7f5d3SJohn Marino p->t = TOK_EQ;
769*86d7f5d3SJohn Marino p->te++;
770*86d7f5d3SJohn Marino break;
771*86d7f5d3SJohn Marino
772*86d7f5d3SJohn Marino case '"':
773*86d7f5d3SJohn Marino p->t = TOK_STRING_ESCAPED;
774*86d7f5d3SJohn Marino p->te++;
775*86d7f5d3SJohn Marino while ((p->te != p->fe) && (*p->te) && (*p->te != '"')) {
776*86d7f5d3SJohn Marino if ((*p->te == '\\') && (p->te + 1 != p->fe) &&
777*86d7f5d3SJohn Marino *(p->te + 1))
778*86d7f5d3SJohn Marino p->te++;
779*86d7f5d3SJohn Marino p->te++;
780*86d7f5d3SJohn Marino }
781*86d7f5d3SJohn Marino
782*86d7f5d3SJohn Marino if ((p->te != p->fe) && (*p->te))
783*86d7f5d3SJohn Marino p->te++;
784*86d7f5d3SJohn Marino break;
785*86d7f5d3SJohn Marino
786*86d7f5d3SJohn Marino case '\'':
787*86d7f5d3SJohn Marino p->t = TOK_STRING;
788*86d7f5d3SJohn Marino p->te++;
789*86d7f5d3SJohn Marino while ((p->te != p->fe) && (*p->te) && (*p->te != '\''))
790*86d7f5d3SJohn Marino p->te++;
791*86d7f5d3SJohn Marino
792*86d7f5d3SJohn Marino if ((p->te != p->fe) && (*p->te))
793*86d7f5d3SJohn Marino p->te++;
794*86d7f5d3SJohn Marino break;
795*86d7f5d3SJohn Marino
796*86d7f5d3SJohn Marino case '.':
797*86d7f5d3SJohn Marino p->t = TOK_FLOAT;
798*86d7f5d3SJohn Marino case '0':
799*86d7f5d3SJohn Marino case '1':
800*86d7f5d3SJohn Marino case '2':
801*86d7f5d3SJohn Marino case '3':
802*86d7f5d3SJohn Marino case '4':
803*86d7f5d3SJohn Marino case '5':
804*86d7f5d3SJohn Marino case '6':
805*86d7f5d3SJohn Marino case '7':
806*86d7f5d3SJohn Marino case '8':
807*86d7f5d3SJohn Marino case '9':
808*86d7f5d3SJohn Marino case '+':
809*86d7f5d3SJohn Marino case '-':
810*86d7f5d3SJohn Marino if (values_allowed) {
811*86d7f5d3SJohn Marino p->te++;
812*86d7f5d3SJohn Marino while ((p->te != p->fe) && (*p->te)) {
813*86d7f5d3SJohn Marino if (*p->te == '.') {
814*86d7f5d3SJohn Marino if (p->t == TOK_FLOAT)
815*86d7f5d3SJohn Marino break;
816*86d7f5d3SJohn Marino p->t = TOK_FLOAT;
817*86d7f5d3SJohn Marino } else if (!isdigit((int) *p->te))
818*86d7f5d3SJohn Marino break;
819*86d7f5d3SJohn Marino p->te++;
820*86d7f5d3SJohn Marino }
821*86d7f5d3SJohn Marino break;
822*86d7f5d3SJohn Marino }
823*86d7f5d3SJohn Marino
824*86d7f5d3SJohn Marino default:
825*86d7f5d3SJohn Marino p->t = TOK_IDENTIFIER;
826*86d7f5d3SJohn Marino while ((p->te != p->fe) && (*p->te) && !isspace(*p->te) &&
827*86d7f5d3SJohn Marino (*p->te != '#') && (*p->te != '=') &&
828*86d7f5d3SJohn Marino (*p->te != SECTION_B_CHAR) &&
829*86d7f5d3SJohn Marino (*p->te != SECTION_E_CHAR))
830*86d7f5d3SJohn Marino p->te++;
831*86d7f5d3SJohn Marino break;
832*86d7f5d3SJohn Marino }
833*86d7f5d3SJohn Marino }
834*86d7f5d3SJohn Marino
_eat_space(struct parser * p)835*86d7f5d3SJohn Marino static void _eat_space(struct parser *p)
836*86d7f5d3SJohn Marino {
837*86d7f5d3SJohn Marino while ((p->tb != p->fe) && (*p->tb)) {
838*86d7f5d3SJohn Marino if (*p->te == '#')
839*86d7f5d3SJohn Marino while ((p->te != p->fe) && (*p->te) && (*p->te != '\n'))
840*86d7f5d3SJohn Marino p->te++;
841*86d7f5d3SJohn Marino
842*86d7f5d3SJohn Marino else if (isspace(*p->te)) {
843*86d7f5d3SJohn Marino while ((p->te != p->fe) && (*p->te) && isspace(*p->te)) {
844*86d7f5d3SJohn Marino if (*p->te == '\n')
845*86d7f5d3SJohn Marino p->line++;
846*86d7f5d3SJohn Marino p->te++;
847*86d7f5d3SJohn Marino }
848*86d7f5d3SJohn Marino }
849*86d7f5d3SJohn Marino
850*86d7f5d3SJohn Marino else
851*86d7f5d3SJohn Marino return;
852*86d7f5d3SJohn Marino
853*86d7f5d3SJohn Marino p->tb = p->te;
854*86d7f5d3SJohn Marino }
855*86d7f5d3SJohn Marino }
856*86d7f5d3SJohn Marino
857*86d7f5d3SJohn Marino /*
858*86d7f5d3SJohn Marino * memory management
859*86d7f5d3SJohn Marino */
_create_value(struct dm_pool * mem)860*86d7f5d3SJohn Marino static struct config_value *_create_value(struct dm_pool *mem)
861*86d7f5d3SJohn Marino {
862*86d7f5d3SJohn Marino struct config_value *v = dm_pool_alloc(mem, sizeof(*v));
863*86d7f5d3SJohn Marino
864*86d7f5d3SJohn Marino if (v)
865*86d7f5d3SJohn Marino memset(v, 0, sizeof(*v));
866*86d7f5d3SJohn Marino
867*86d7f5d3SJohn Marino return v;
868*86d7f5d3SJohn Marino }
869*86d7f5d3SJohn Marino
_create_node(struct dm_pool * mem)870*86d7f5d3SJohn Marino static struct config_node *_create_node(struct dm_pool *mem)
871*86d7f5d3SJohn Marino {
872*86d7f5d3SJohn Marino struct config_node *n = dm_pool_alloc(mem, sizeof(*n));
873*86d7f5d3SJohn Marino
874*86d7f5d3SJohn Marino if (n)
875*86d7f5d3SJohn Marino memset(n, 0, sizeof(*n));
876*86d7f5d3SJohn Marino
877*86d7f5d3SJohn Marino return n;
878*86d7f5d3SJohn Marino }
879*86d7f5d3SJohn Marino
_dup_tok(struct parser * p)880*86d7f5d3SJohn Marino static char *_dup_tok(struct parser *p)
881*86d7f5d3SJohn Marino {
882*86d7f5d3SJohn Marino size_t len = p->te - p->tb;
883*86d7f5d3SJohn Marino char *str = dm_pool_alloc(p->mem, len + 1);
884*86d7f5d3SJohn Marino if (!str)
885*86d7f5d3SJohn Marino return_0;
886*86d7f5d3SJohn Marino strncpy(str, p->tb, len);
887*86d7f5d3SJohn Marino str[len] = '\0';
888*86d7f5d3SJohn Marino return str;
889*86d7f5d3SJohn Marino }
890*86d7f5d3SJohn Marino
891*86d7f5d3SJohn Marino /*
892*86d7f5d3SJohn Marino * utility functions
893*86d7f5d3SJohn Marino */
_find_config_node(const struct config_node * cn,const char * path)894*86d7f5d3SJohn Marino static struct config_node *_find_config_node(const struct config_node *cn,
895*86d7f5d3SJohn Marino const char *path)
896*86d7f5d3SJohn Marino {
897*86d7f5d3SJohn Marino const char *e;
898*86d7f5d3SJohn Marino const struct config_node *cn_found = NULL;
899*86d7f5d3SJohn Marino
900*86d7f5d3SJohn Marino while (cn) {
901*86d7f5d3SJohn Marino /* trim any leading slashes */
902*86d7f5d3SJohn Marino while (*path && (*path == sep))
903*86d7f5d3SJohn Marino path++;
904*86d7f5d3SJohn Marino
905*86d7f5d3SJohn Marino /* find the end of this segment */
906*86d7f5d3SJohn Marino for (e = path; *e && (*e != sep); e++) ;
907*86d7f5d3SJohn Marino
908*86d7f5d3SJohn Marino /* hunt for the node */
909*86d7f5d3SJohn Marino cn_found = NULL;
910*86d7f5d3SJohn Marino while (cn) {
911*86d7f5d3SJohn Marino if (_tok_match(cn->key, path, e)) {
912*86d7f5d3SJohn Marino /* Inefficient */
913*86d7f5d3SJohn Marino if (!cn_found)
914*86d7f5d3SJohn Marino cn_found = cn;
915*86d7f5d3SJohn Marino else
916*86d7f5d3SJohn Marino log_error("WARNING: Ignoring duplicate"
917*86d7f5d3SJohn Marino " config node: %s ("
918*86d7f5d3SJohn Marino "seeking %s)", cn->key, path);
919*86d7f5d3SJohn Marino }
920*86d7f5d3SJohn Marino
921*86d7f5d3SJohn Marino cn = cn->sib;
922*86d7f5d3SJohn Marino }
923*86d7f5d3SJohn Marino
924*86d7f5d3SJohn Marino if (cn_found && *e)
925*86d7f5d3SJohn Marino cn = cn_found->child;
926*86d7f5d3SJohn Marino else
927*86d7f5d3SJohn Marino break; /* don't move into the last node */
928*86d7f5d3SJohn Marino
929*86d7f5d3SJohn Marino path = e;
930*86d7f5d3SJohn Marino }
931*86d7f5d3SJohn Marino
932*86d7f5d3SJohn Marino return (struct config_node *) cn_found;
933*86d7f5d3SJohn Marino }
934*86d7f5d3SJohn Marino
_find_first_config_node(const struct config_node * cn1,const struct config_node * cn2,const char * path)935*86d7f5d3SJohn Marino static struct config_node *_find_first_config_node(const struct config_node *cn1,
936*86d7f5d3SJohn Marino const struct config_node *cn2,
937*86d7f5d3SJohn Marino const char *path)
938*86d7f5d3SJohn Marino {
939*86d7f5d3SJohn Marino struct config_node *cn;
940*86d7f5d3SJohn Marino
941*86d7f5d3SJohn Marino if (cn1 && (cn = _find_config_node(cn1, path)))
942*86d7f5d3SJohn Marino return cn;
943*86d7f5d3SJohn Marino
944*86d7f5d3SJohn Marino if (cn2 && (cn = _find_config_node(cn2, path)))
945*86d7f5d3SJohn Marino return cn;
946*86d7f5d3SJohn Marino
947*86d7f5d3SJohn Marino return NULL;
948*86d7f5d3SJohn Marino }
949*86d7f5d3SJohn Marino
find_config_node(const struct config_node * cn,const char * path)950*86d7f5d3SJohn Marino struct config_node *find_config_node(const struct config_node *cn,
951*86d7f5d3SJohn Marino const char *path)
952*86d7f5d3SJohn Marino {
953*86d7f5d3SJohn Marino return _find_config_node(cn, path);
954*86d7f5d3SJohn Marino }
955*86d7f5d3SJohn Marino
_find_config_str(const struct config_node * cn1,const struct config_node * cn2,const char * path,const char * fail)956*86d7f5d3SJohn Marino static const char *_find_config_str(const struct config_node *cn1,
957*86d7f5d3SJohn Marino const struct config_node *cn2,
958*86d7f5d3SJohn Marino const char *path, const char *fail)
959*86d7f5d3SJohn Marino {
960*86d7f5d3SJohn Marino const struct config_node *n = _find_first_config_node(cn1, cn2, path);
961*86d7f5d3SJohn Marino
962*86d7f5d3SJohn Marino /* Empty strings are ignored */
963*86d7f5d3SJohn Marino if ((n && n->v && n->v->type == CFG_STRING) && (*n->v->v.str)) {
964*86d7f5d3SJohn Marino log_very_verbose("Setting %s to %s", path, n->v->v.str);
965*86d7f5d3SJohn Marino return n->v->v.str;
966*86d7f5d3SJohn Marino }
967*86d7f5d3SJohn Marino
968*86d7f5d3SJohn Marino if (fail)
969*86d7f5d3SJohn Marino log_very_verbose("%s not found in config: defaulting to %s",
970*86d7f5d3SJohn Marino path, fail);
971*86d7f5d3SJohn Marino return fail;
972*86d7f5d3SJohn Marino }
973*86d7f5d3SJohn Marino
find_config_str(const struct config_node * cn,const char * path,const char * fail)974*86d7f5d3SJohn Marino const char *find_config_str(const struct config_node *cn,
975*86d7f5d3SJohn Marino const char *path, const char *fail)
976*86d7f5d3SJohn Marino {
977*86d7f5d3SJohn Marino return _find_config_str(cn, NULL, path, fail);
978*86d7f5d3SJohn Marino }
979*86d7f5d3SJohn Marino
_find_config_int64(const struct config_node * cn1,const struct config_node * cn2,const char * path,int64_t fail)980*86d7f5d3SJohn Marino static int64_t _find_config_int64(const struct config_node *cn1,
981*86d7f5d3SJohn Marino const struct config_node *cn2,
982*86d7f5d3SJohn Marino const char *path, int64_t fail)
983*86d7f5d3SJohn Marino {
984*86d7f5d3SJohn Marino const struct config_node *n = _find_first_config_node(cn1, cn2, path);
985*86d7f5d3SJohn Marino
986*86d7f5d3SJohn Marino if (n && n->v && n->v->type == CFG_INT) {
987*86d7f5d3SJohn Marino log_very_verbose("Setting %s to %" PRId64, path, n->v->v.i);
988*86d7f5d3SJohn Marino return n->v->v.i;
989*86d7f5d3SJohn Marino }
990*86d7f5d3SJohn Marino
991*86d7f5d3SJohn Marino log_very_verbose("%s not found in config: defaulting to %" PRId64,
992*86d7f5d3SJohn Marino path, fail);
993*86d7f5d3SJohn Marino return fail;
994*86d7f5d3SJohn Marino }
995*86d7f5d3SJohn Marino
find_config_int(const struct config_node * cn,const char * path,int fail)996*86d7f5d3SJohn Marino int find_config_int(const struct config_node *cn, const char *path, int fail)
997*86d7f5d3SJohn Marino {
998*86d7f5d3SJohn Marino /* FIXME Add log_error message on overflow */
999*86d7f5d3SJohn Marino return (int) _find_config_int64(cn, NULL, path, (int64_t) fail);
1000*86d7f5d3SJohn Marino }
1001*86d7f5d3SJohn Marino
_find_config_float(const struct config_node * cn1,const struct config_node * cn2,const char * path,float fail)1002*86d7f5d3SJohn Marino static float _find_config_float(const struct config_node *cn1,
1003*86d7f5d3SJohn Marino const struct config_node *cn2,
1004*86d7f5d3SJohn Marino const char *path, float fail)
1005*86d7f5d3SJohn Marino {
1006*86d7f5d3SJohn Marino const struct config_node *n = _find_first_config_node(cn1, cn2, path);
1007*86d7f5d3SJohn Marino
1008*86d7f5d3SJohn Marino if (n && n->v && n->v->type == CFG_FLOAT) {
1009*86d7f5d3SJohn Marino log_very_verbose("Setting %s to %f", path, n->v->v.r);
1010*86d7f5d3SJohn Marino return n->v->v.r;
1011*86d7f5d3SJohn Marino }
1012*86d7f5d3SJohn Marino
1013*86d7f5d3SJohn Marino log_very_verbose("%s not found in config: defaulting to %f",
1014*86d7f5d3SJohn Marino path, fail);
1015*86d7f5d3SJohn Marino
1016*86d7f5d3SJohn Marino return fail;
1017*86d7f5d3SJohn Marino
1018*86d7f5d3SJohn Marino }
1019*86d7f5d3SJohn Marino
find_config_float(const struct config_node * cn,const char * path,float fail)1020*86d7f5d3SJohn Marino float find_config_float(const struct config_node *cn, const char *path,
1021*86d7f5d3SJohn Marino float fail)
1022*86d7f5d3SJohn Marino {
1023*86d7f5d3SJohn Marino return _find_config_float(cn, NULL, path, fail);
1024*86d7f5d3SJohn Marino }
1025*86d7f5d3SJohn Marino
find_config_tree_node(struct cmd_context * cmd,const char * path)1026*86d7f5d3SJohn Marino struct config_node *find_config_tree_node(struct cmd_context *cmd,
1027*86d7f5d3SJohn Marino const char *path)
1028*86d7f5d3SJohn Marino {
1029*86d7f5d3SJohn Marino return _find_first_config_node(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path);
1030*86d7f5d3SJohn Marino }
1031*86d7f5d3SJohn Marino
find_config_tree_str(struct cmd_context * cmd,const char * path,const char * fail)1032*86d7f5d3SJohn Marino const char *find_config_tree_str(struct cmd_context *cmd,
1033*86d7f5d3SJohn Marino const char *path, const char *fail)
1034*86d7f5d3SJohn Marino {
1035*86d7f5d3SJohn Marino return _find_config_str(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
1036*86d7f5d3SJohn Marino }
1037*86d7f5d3SJohn Marino
find_config_tree_int(struct cmd_context * cmd,const char * path,int fail)1038*86d7f5d3SJohn Marino int find_config_tree_int(struct cmd_context *cmd, const char *path,
1039*86d7f5d3SJohn Marino int fail)
1040*86d7f5d3SJohn Marino {
1041*86d7f5d3SJohn Marino /* FIXME Add log_error message on overflow */
1042*86d7f5d3SJohn Marino return (int) _find_config_int64(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, (int64_t) fail);
1043*86d7f5d3SJohn Marino }
1044*86d7f5d3SJohn Marino
find_config_tree_float(struct cmd_context * cmd,const char * path,float fail)1045*86d7f5d3SJohn Marino float find_config_tree_float(struct cmd_context *cmd, const char *path,
1046*86d7f5d3SJohn Marino float fail)
1047*86d7f5d3SJohn Marino {
1048*86d7f5d3SJohn Marino return _find_config_float(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
1049*86d7f5d3SJohn Marino }
1050*86d7f5d3SJohn Marino
_str_in_array(const char * str,const char * const values[])1051*86d7f5d3SJohn Marino static int _str_in_array(const char *str, const char * const values[])
1052*86d7f5d3SJohn Marino {
1053*86d7f5d3SJohn Marino int i;
1054*86d7f5d3SJohn Marino
1055*86d7f5d3SJohn Marino for (i = 0; values[i]; i++)
1056*86d7f5d3SJohn Marino if (!strcasecmp(str, values[i]))
1057*86d7f5d3SJohn Marino return 1;
1058*86d7f5d3SJohn Marino
1059*86d7f5d3SJohn Marino return 0;
1060*86d7f5d3SJohn Marino }
1061*86d7f5d3SJohn Marino
_str_to_bool(const char * str,int fail)1062*86d7f5d3SJohn Marino static int _str_to_bool(const char *str, int fail)
1063*86d7f5d3SJohn Marino {
1064*86d7f5d3SJohn Marino const char * const _true_values[] = { "y", "yes", "on", "true", NULL };
1065*86d7f5d3SJohn Marino const char * const _false_values[] = { "n", "no", "off", "false", NULL };
1066*86d7f5d3SJohn Marino
1067*86d7f5d3SJohn Marino if (_str_in_array(str, _true_values))
1068*86d7f5d3SJohn Marino return 1;
1069*86d7f5d3SJohn Marino
1070*86d7f5d3SJohn Marino if (_str_in_array(str, _false_values))
1071*86d7f5d3SJohn Marino return 0;
1072*86d7f5d3SJohn Marino
1073*86d7f5d3SJohn Marino return fail;
1074*86d7f5d3SJohn Marino }
1075*86d7f5d3SJohn Marino
_find_config_bool(const struct config_node * cn1,const struct config_node * cn2,const char * path,int fail)1076*86d7f5d3SJohn Marino static int _find_config_bool(const struct config_node *cn1,
1077*86d7f5d3SJohn Marino const struct config_node *cn2,
1078*86d7f5d3SJohn Marino const char *path, int fail)
1079*86d7f5d3SJohn Marino {
1080*86d7f5d3SJohn Marino const struct config_node *n = _find_first_config_node(cn1, cn2, path);
1081*86d7f5d3SJohn Marino struct config_value *v;
1082*86d7f5d3SJohn Marino
1083*86d7f5d3SJohn Marino if (!n)
1084*86d7f5d3SJohn Marino return fail;
1085*86d7f5d3SJohn Marino
1086*86d7f5d3SJohn Marino v = n->v;
1087*86d7f5d3SJohn Marino
1088*86d7f5d3SJohn Marino switch (v->type) {
1089*86d7f5d3SJohn Marino case CFG_INT:
1090*86d7f5d3SJohn Marino return v->v.i ? 1 : 0;
1091*86d7f5d3SJohn Marino
1092*86d7f5d3SJohn Marino case CFG_STRING:
1093*86d7f5d3SJohn Marino return _str_to_bool(v->v.str, fail);
1094*86d7f5d3SJohn Marino }
1095*86d7f5d3SJohn Marino
1096*86d7f5d3SJohn Marino return fail;
1097*86d7f5d3SJohn Marino }
1098*86d7f5d3SJohn Marino
find_config_bool(const struct config_node * cn,const char * path,int fail)1099*86d7f5d3SJohn Marino int find_config_bool(const struct config_node *cn, const char *path, int fail)
1100*86d7f5d3SJohn Marino {
1101*86d7f5d3SJohn Marino return _find_config_bool(cn, NULL, path, fail);
1102*86d7f5d3SJohn Marino }
1103*86d7f5d3SJohn Marino
find_config_tree_bool(struct cmd_context * cmd,const char * path,int fail)1104*86d7f5d3SJohn Marino int find_config_tree_bool(struct cmd_context *cmd, const char *path, int fail)
1105*86d7f5d3SJohn Marino {
1106*86d7f5d3SJohn Marino return _find_config_bool(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
1107*86d7f5d3SJohn Marino }
1108*86d7f5d3SJohn Marino
get_config_uint32(const struct config_node * cn,const char * path,uint32_t * result)1109*86d7f5d3SJohn Marino int get_config_uint32(const struct config_node *cn, const char *path,
1110*86d7f5d3SJohn Marino uint32_t *result)
1111*86d7f5d3SJohn Marino {
1112*86d7f5d3SJohn Marino const struct config_node *n;
1113*86d7f5d3SJohn Marino
1114*86d7f5d3SJohn Marino n = find_config_node(cn, path);
1115*86d7f5d3SJohn Marino
1116*86d7f5d3SJohn Marino if (!n || !n->v || n->v->type != CFG_INT)
1117*86d7f5d3SJohn Marino return 0;
1118*86d7f5d3SJohn Marino
1119*86d7f5d3SJohn Marino *result = n->v->v.i;
1120*86d7f5d3SJohn Marino return 1;
1121*86d7f5d3SJohn Marino }
1122*86d7f5d3SJohn Marino
get_config_uint64(const struct config_node * cn,const char * path,uint64_t * result)1123*86d7f5d3SJohn Marino int get_config_uint64(const struct config_node *cn, const char *path,
1124*86d7f5d3SJohn Marino uint64_t *result)
1125*86d7f5d3SJohn Marino {
1126*86d7f5d3SJohn Marino const struct config_node *n;
1127*86d7f5d3SJohn Marino
1128*86d7f5d3SJohn Marino n = find_config_node(cn, path);
1129*86d7f5d3SJohn Marino
1130*86d7f5d3SJohn Marino if (!n || !n->v || n->v->type != CFG_INT)
1131*86d7f5d3SJohn Marino return 0;
1132*86d7f5d3SJohn Marino
1133*86d7f5d3SJohn Marino *result = (uint64_t) n->v->v.i;
1134*86d7f5d3SJohn Marino return 1;
1135*86d7f5d3SJohn Marino }
1136*86d7f5d3SJohn Marino
get_config_str(const struct config_node * cn,const char * path,char ** result)1137*86d7f5d3SJohn Marino int get_config_str(const struct config_node *cn, const char *path,
1138*86d7f5d3SJohn Marino char **result)
1139*86d7f5d3SJohn Marino {
1140*86d7f5d3SJohn Marino const struct config_node *n;
1141*86d7f5d3SJohn Marino
1142*86d7f5d3SJohn Marino n = find_config_node(cn, path);
1143*86d7f5d3SJohn Marino
1144*86d7f5d3SJohn Marino if (!n || !n->v || n->v->type != CFG_STRING)
1145*86d7f5d3SJohn Marino return 0;
1146*86d7f5d3SJohn Marino
1147*86d7f5d3SJohn Marino *result = n->v->v.str;
1148*86d7f5d3SJohn Marino return 1;
1149*86d7f5d3SJohn Marino }
1150*86d7f5d3SJohn Marino
1151*86d7f5d3SJohn Marino /* Insert cn2 after cn1 */
_insert_config_node(struct config_node ** cn1,struct config_node * cn2)1152*86d7f5d3SJohn Marino static void _insert_config_node(struct config_node **cn1,
1153*86d7f5d3SJohn Marino struct config_node *cn2)
1154*86d7f5d3SJohn Marino {
1155*86d7f5d3SJohn Marino if (!*cn1) {
1156*86d7f5d3SJohn Marino *cn1 = cn2;
1157*86d7f5d3SJohn Marino cn2->sib = NULL;
1158*86d7f5d3SJohn Marino } else {
1159*86d7f5d3SJohn Marino cn2->sib = (*cn1)->sib;
1160*86d7f5d3SJohn Marino (*cn1)->sib = cn2;
1161*86d7f5d3SJohn Marino }
1162*86d7f5d3SJohn Marino }
1163*86d7f5d3SJohn Marino
1164*86d7f5d3SJohn Marino /*
1165*86d7f5d3SJohn Marino * Merge section cn2 into section cn1 (which has the same name)
1166*86d7f5d3SJohn Marino * overwriting any existing cn1 nodes with matching names.
1167*86d7f5d3SJohn Marino */
_merge_section(struct config_node * cn1,struct config_node * cn2)1168*86d7f5d3SJohn Marino static void _merge_section(struct config_node *cn1, struct config_node *cn2)
1169*86d7f5d3SJohn Marino {
1170*86d7f5d3SJohn Marino struct config_node *cn, *nextn, *oldn;
1171*86d7f5d3SJohn Marino struct config_value *cv;
1172*86d7f5d3SJohn Marino
1173*86d7f5d3SJohn Marino for (cn = cn2->child; cn; cn = nextn) {
1174*86d7f5d3SJohn Marino nextn = cn->sib;
1175*86d7f5d3SJohn Marino
1176*86d7f5d3SJohn Marino /* Skip "tags" */
1177*86d7f5d3SJohn Marino if (!strcmp(cn->key, "tags"))
1178*86d7f5d3SJohn Marino continue;
1179*86d7f5d3SJohn Marino
1180*86d7f5d3SJohn Marino /* Subsection? */
1181*86d7f5d3SJohn Marino if (!cn->v)
1182*86d7f5d3SJohn Marino /* Ignore - we don't have any of these yet */
1183*86d7f5d3SJohn Marino continue;
1184*86d7f5d3SJohn Marino /* Not already present? */
1185*86d7f5d3SJohn Marino if (!(oldn = find_config_node(cn1->child, cn->key))) {
1186*86d7f5d3SJohn Marino _insert_config_node(&cn1->child, cn);
1187*86d7f5d3SJohn Marino continue;
1188*86d7f5d3SJohn Marino }
1189*86d7f5d3SJohn Marino /* Merge certain value lists */
1190*86d7f5d3SJohn Marino if ((!strcmp(cn1->key, "activation") &&
1191*86d7f5d3SJohn Marino !strcmp(cn->key, "volume_list")) ||
1192*86d7f5d3SJohn Marino (!strcmp(cn1->key, "devices") &&
1193*86d7f5d3SJohn Marino (!strcmp(cn->key, "filter") || !strcmp(cn->key, "types")))) {
1194*86d7f5d3SJohn Marino cv = cn->v;
1195*86d7f5d3SJohn Marino while (cv->next)
1196*86d7f5d3SJohn Marino cv = cv->next;
1197*86d7f5d3SJohn Marino cv->next = oldn->v;
1198*86d7f5d3SJohn Marino }
1199*86d7f5d3SJohn Marino
1200*86d7f5d3SJohn Marino /* Replace values */
1201*86d7f5d3SJohn Marino oldn->v = cn->v;
1202*86d7f5d3SJohn Marino }
1203*86d7f5d3SJohn Marino }
1204*86d7f5d3SJohn Marino
_match_host_tags(struct dm_list * tags,struct config_node * tn)1205*86d7f5d3SJohn Marino static int _match_host_tags(struct dm_list *tags, struct config_node *tn)
1206*86d7f5d3SJohn Marino {
1207*86d7f5d3SJohn Marino struct config_value *tv;
1208*86d7f5d3SJohn Marino const char *str;
1209*86d7f5d3SJohn Marino
1210*86d7f5d3SJohn Marino for (tv = tn->v; tv; tv = tv->next) {
1211*86d7f5d3SJohn Marino if (tv->type != CFG_STRING)
1212*86d7f5d3SJohn Marino continue;
1213*86d7f5d3SJohn Marino str = tv->v.str;
1214*86d7f5d3SJohn Marino if (*str == '@')
1215*86d7f5d3SJohn Marino str++;
1216*86d7f5d3SJohn Marino if (!*str)
1217*86d7f5d3SJohn Marino continue;
1218*86d7f5d3SJohn Marino if (str_list_match_item(tags, str))
1219*86d7f5d3SJohn Marino return 1;
1220*86d7f5d3SJohn Marino }
1221*86d7f5d3SJohn Marino
1222*86d7f5d3SJohn Marino return 0;
1223*86d7f5d3SJohn Marino }
1224*86d7f5d3SJohn Marino
1225*86d7f5d3SJohn Marino /* Destructively merge a new config tree into an existing one */
merge_config_tree(struct cmd_context * cmd,struct config_tree * cft,struct config_tree * newdata)1226*86d7f5d3SJohn Marino int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
1227*86d7f5d3SJohn Marino struct config_tree *newdata)
1228*86d7f5d3SJohn Marino {
1229*86d7f5d3SJohn Marino struct config_node *root = cft->root;
1230*86d7f5d3SJohn Marino struct config_node *cn, *nextn, *oldn, *tn, *cn2;
1231*86d7f5d3SJohn Marino
1232*86d7f5d3SJohn Marino for (cn = newdata->root; cn; cn = nextn) {
1233*86d7f5d3SJohn Marino nextn = cn->sib;
1234*86d7f5d3SJohn Marino /* Ignore tags section */
1235*86d7f5d3SJohn Marino if (!strcmp(cn->key, "tags"))
1236*86d7f5d3SJohn Marino continue;
1237*86d7f5d3SJohn Marino /* If there's a tags node, skip if host tags don't match */
1238*86d7f5d3SJohn Marino if ((tn = find_config_node(cn->child, "tags"))) {
1239*86d7f5d3SJohn Marino if (!_match_host_tags(&cmd->tags, tn))
1240*86d7f5d3SJohn Marino continue;
1241*86d7f5d3SJohn Marino }
1242*86d7f5d3SJohn Marino if (!(oldn = find_config_node(root, cn->key))) {
1243*86d7f5d3SJohn Marino _insert_config_node(&cft->root, cn);
1244*86d7f5d3SJohn Marino /* Remove any "tags" nodes */
1245*86d7f5d3SJohn Marino for (cn2 = cn->child; cn2; cn2 = cn2->sib) {
1246*86d7f5d3SJohn Marino if (!strcmp(cn2->key, "tags")) {
1247*86d7f5d3SJohn Marino cn->child = cn2->sib;
1248*86d7f5d3SJohn Marino continue;
1249*86d7f5d3SJohn Marino }
1250*86d7f5d3SJohn Marino if (cn2->sib && !strcmp(cn2->sib->key, "tags")) {
1251*86d7f5d3SJohn Marino cn2->sib = cn2->sib->sib;
1252*86d7f5d3SJohn Marino continue;
1253*86d7f5d3SJohn Marino }
1254*86d7f5d3SJohn Marino }
1255*86d7f5d3SJohn Marino continue;
1256*86d7f5d3SJohn Marino }
1257*86d7f5d3SJohn Marino _merge_section(oldn, cn);
1258*86d7f5d3SJohn Marino }
1259*86d7f5d3SJohn Marino
1260*86d7f5d3SJohn Marino return 1;
1261*86d7f5d3SJohn Marino }
1262*86d7f5d3SJohn Marino
1263*86d7f5d3SJohn Marino /*
1264*86d7f5d3SJohn Marino * Convert a token type to the char it represents.
1265*86d7f5d3SJohn Marino */
_token_type_to_char(int type)1266*86d7f5d3SJohn Marino static char _token_type_to_char(int type)
1267*86d7f5d3SJohn Marino {
1268*86d7f5d3SJohn Marino switch (type) {
1269*86d7f5d3SJohn Marino case TOK_SECTION_B:
1270*86d7f5d3SJohn Marino return SECTION_B_CHAR;
1271*86d7f5d3SJohn Marino case TOK_SECTION_E:
1272*86d7f5d3SJohn Marino return SECTION_E_CHAR;
1273*86d7f5d3SJohn Marino default:
1274*86d7f5d3SJohn Marino return 0;
1275*86d7f5d3SJohn Marino }
1276*86d7f5d3SJohn Marino }
1277*86d7f5d3SJohn Marino
1278*86d7f5d3SJohn Marino /*
1279*86d7f5d3SJohn Marino * Returns:
1280*86d7f5d3SJohn Marino * # of 'type' tokens in 'str'.
1281*86d7f5d3SJohn Marino */
_count_tokens(const char * str,unsigned len,int type)1282*86d7f5d3SJohn Marino static unsigned _count_tokens(const char *str, unsigned len, int type)
1283*86d7f5d3SJohn Marino {
1284*86d7f5d3SJohn Marino char c;
1285*86d7f5d3SJohn Marino
1286*86d7f5d3SJohn Marino c = _token_type_to_char(type);
1287*86d7f5d3SJohn Marino
1288*86d7f5d3SJohn Marino return count_chars(str, len, c);
1289*86d7f5d3SJohn Marino }
1290*86d7f5d3SJohn Marino
config_parent_name(const struct config_node * n)1291*86d7f5d3SJohn Marino const char *config_parent_name(const struct config_node *n)
1292*86d7f5d3SJohn Marino {
1293*86d7f5d3SJohn Marino return (n->parent ? n->parent->key : "(root)");
1294*86d7f5d3SJohn Marino }
1295*86d7f5d3SJohn Marino /*
1296*86d7f5d3SJohn Marino * Heuristic function to make a quick guess as to whether a text
1297*86d7f5d3SJohn Marino * region probably contains a valid config "section". (Useful for
1298*86d7f5d3SJohn Marino * scanning areas of the disk for old metadata.)
1299*86d7f5d3SJohn Marino * Config sections contain various tokens, may contain other sections
1300*86d7f5d3SJohn Marino * and strings, and are delimited by begin (type 'TOK_SECTION_B') and
1301*86d7f5d3SJohn Marino * end (type 'TOK_SECTION_E') tokens. As a quick heuristic, we just
1302*86d7f5d3SJohn Marino * count the number of begin and end tokens, and see if they are
1303*86d7f5d3SJohn Marino * non-zero and the counts match.
1304*86d7f5d3SJohn Marino * Full validation of the section should be done with another function
1305*86d7f5d3SJohn Marino * (for example, read_config_fd).
1306*86d7f5d3SJohn Marino *
1307*86d7f5d3SJohn Marino * Returns:
1308*86d7f5d3SJohn Marino * 0 - probably is not a valid config section
1309*86d7f5d3SJohn Marino * 1 - probably _is_ a valid config section
1310*86d7f5d3SJohn Marino */
maybe_config_section(const char * str,unsigned len)1311*86d7f5d3SJohn Marino unsigned maybe_config_section(const char *str, unsigned len)
1312*86d7f5d3SJohn Marino {
1313*86d7f5d3SJohn Marino int begin_count;
1314*86d7f5d3SJohn Marino int end_count;
1315*86d7f5d3SJohn Marino
1316*86d7f5d3SJohn Marino begin_count = _count_tokens(str, len, TOK_SECTION_B);
1317*86d7f5d3SJohn Marino end_count = _count_tokens(str, len, TOK_SECTION_E);
1318*86d7f5d3SJohn Marino
1319*86d7f5d3SJohn Marino if (begin_count && end_count && (begin_count == end_count))
1320*86d7f5d3SJohn Marino return 1;
1321*86d7f5d3SJohn Marino else
1322*86d7f5d3SJohn Marino return 0;
1323*86d7f5d3SJohn Marino }
1324*86d7f5d3SJohn Marino
_clone_config_value(struct dm_pool * mem,const struct config_value * v)1325*86d7f5d3SJohn Marino static struct config_value *_clone_config_value(struct dm_pool *mem, const struct config_value *v)
1326*86d7f5d3SJohn Marino {
1327*86d7f5d3SJohn Marino if (!v)
1328*86d7f5d3SJohn Marino return NULL;
1329*86d7f5d3SJohn Marino struct config_value *new = _create_value(mem);
1330*86d7f5d3SJohn Marino new->type = v->type;
1331*86d7f5d3SJohn Marino if (v->type == CFG_STRING)
1332*86d7f5d3SJohn Marino new->v.str = dm_pool_strdup(mem, v->v.str);
1333*86d7f5d3SJohn Marino else
1334*86d7f5d3SJohn Marino new->v = v->v;
1335*86d7f5d3SJohn Marino new->next = _clone_config_value(mem, v->next);
1336*86d7f5d3SJohn Marino return new;
1337*86d7f5d3SJohn Marino }
1338*86d7f5d3SJohn Marino
clone_config_node(struct dm_pool * mem,const struct config_node * cn,int siblings)1339*86d7f5d3SJohn Marino struct config_node *clone_config_node(struct dm_pool *mem, const struct config_node *cn,
1340*86d7f5d3SJohn Marino int siblings)
1341*86d7f5d3SJohn Marino {
1342*86d7f5d3SJohn Marino if (!cn)
1343*86d7f5d3SJohn Marino return NULL;
1344*86d7f5d3SJohn Marino struct config_node *new = _create_node(mem);
1345*86d7f5d3SJohn Marino new->key = dm_pool_strdup(mem, cn->key);
1346*86d7f5d3SJohn Marino new->child = clone_config_node(mem, cn->child, 1);
1347*86d7f5d3SJohn Marino new->v = _clone_config_value(mem, cn->v);
1348*86d7f5d3SJohn Marino if (siblings)
1349*86d7f5d3SJohn Marino new->sib = clone_config_node(mem, cn->sib, siblings);
1350*86d7f5d3SJohn Marino else
1351*86d7f5d3SJohn Marino new->sib = NULL;
1352*86d7f5d3SJohn Marino return new;
1353*86d7f5d3SJohn Marino }
1354