3 * Copyright 2009-2014 Roy Marples <roy@marples.name>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 static DHCPCD_OPTION *
39 dhcpcd_option_new(const char *opt, const char *val)
43 o = malloc(sizeof(*o));
46 o->option = strdup(opt);
47 if (o->option == NULL) {
51 o->value = strdup(val);
52 if (o->value == NULL) {
62 dhcpcd_option_free(DHCPCD_OPTION *o)
71 dhcpcd_config_free(DHCPCD_OPTION *c)
77 dhcpcd_option_free(c);
82 static DHCPCD_OPTION *
83 dhcpcd_config_get1(DHCPCD_OPTION *config, const char *opt, DHCPCD_OPTION **lst)
87 for (o = config; o; o = o->next) {
88 if (strcmp(o->option, opt) == 0)
98 dhcpcd_config_get(DHCPCD_OPTION *config, const char *opt)
103 o = dhcpcd_config_get1(config, opt, NULL);
109 static DHCPCD_OPTION *
110 dhcpcd_config_get_static1(DHCPCD_OPTION *config, const char *opt,
118 while ((o = dhcpcd_config_get1(o, "static", lst)) != NULL) {
119 if (strncmp(o->value, opt, len) == 0)
129 dhcpcd_config_get_static(DHCPCD_OPTION *config, const char *opt)
134 o = dhcpcd_config_get_static1(config, opt, NULL);
137 return o->value + strlen(opt);
141 dhcpcd_config_set1(DHCPCD_OPTION **config, const char *opt, const char *val,
144 DHCPCD_OPTION *o, *l;
150 o = dhcpcd_config_get_static1(*config, opt, &l);
152 o = dhcpcd_config_get1(*config, opt, &l);
166 len = strlen(opt) + strlen(val) + 2;
170 snprintf(t, len, "%s%s", opt, val);
178 o = dhcpcd_option_new("static", t);
180 o = dhcpcd_option_new(opt, val);
196 dhcpcd_config_set(DHCPCD_OPTION **config, const char *opt, const char *val)
201 return dhcpcd_config_set1(config, opt, val, false);
205 dhcpcd_config_set_static(DHCPCD_OPTION **config,
206 const char *opt, const char *val)
211 return dhcpcd_config_set1(config, opt, val, true);
214 #define ACT_READ (1 << 0)
215 #define ACT_WRITE (1 << 1)
216 #define ACT_LIST (1 << 2)
218 static DHCPCD_OPTION *
219 config(DHCPCD_CONNECTION *con, int action, const char *block, const char *name,
220 const DHCPCD_OPTION *no, char ***list)
223 DHCPCD_OPTION *options, *o;
224 const DHCPCD_OPTION *co;
225 char *line, *option, *p;
228 size_t len, buf_size, buf_len, i;
230 fp = fopen(con->cffile, "r");
234 skip = block && !(action & ACT_LIST) ? 1 : 0;
236 buf_len = buf_size = 0;
238 while (getline(&con->buf, &con->buflen, fp) != -1) {
240 /* Trim leading trailing newline and whitespace */
241 while (*line == ' ' || *line == '\n' || *line == '\t')
243 /* Trim trailing newline and whitespace */
245 p = line + strlen(line) - 1;
247 (*p == ' ' || *p == '\n' || *p == '\t') &&
251 option = strsep(&line, " \t");
252 /* Trim trailing whitespace */
254 p = line + strlen(line) - 1;
256 (*p == ' ' || *p == '\n' || *p == '\t') &&
260 if (action & ACT_LIST) {
261 if (strcmp(option, block) == 0)
266 /* Start of a block, skip if not ours */
267 if (strcmp(option, "interface") == 0 ||
268 strcmp(option, "ssid") == 0)
270 if (block && name && line &&
271 strcmp(option, block) == 0 &&
272 strcmp(line, name) == 0)
276 if (!(action & ACT_WRITE))
280 if ((action & ACT_WRITE && skip) ||
281 (action & ACT_LIST && !skip))
283 if (buf_len + 2 > buf_size) {
285 nbuf = realloc(buf, sizeof(char *) * buf_size);
290 if (action & ACT_WRITE && line && *line != '\0') {
291 len = strlen(option) + strlen(line) + 2;
292 buf[buf_len] = malloc(len);
293 if (buf[buf_len] == NULL)
295 snprintf(buf[buf_len], len,
296 "%s %s", option, line);
298 if (action & ACT_LIST)
299 buf[buf_len] = strdup(line);
301 buf[buf_len] = strdup(option);
302 if (buf[buf_len] == NULL)
307 if (skip || action & ACT_LIST)
309 if (*option == '\0' || *option == '#' || *option == ';')
312 options = o = malloc(sizeof(*options));
314 o->next = malloc(sizeof(*o));
320 o->option = strdup(option);
321 if (o->option == NULL) {
325 if (line == NULL || *line == '\0')
328 o->value = strdup(line);
329 if (o->value == NULL)
334 if (action & ACT_WRITE) {
335 fp = freopen(con->cffile, "w", fp);
340 for (i = 0; i < buf_len; i++) {
343 skip = buf[i][0] == '\0' ? 1 : 0;
350 fprintf(fp, "%s %s\n", block, name);
353 for (co = no; co; co = co->next) {
355 fprintf(fp, "%s %s\n", co->option, co->value);
357 fprintf(fp, "%s\n", co->option);
363 for (i = 0; i < buf_len; i++) {
374 if (action & ACT_LIST) {
379 for (i = 0; i < buf_len; i++)
384 dhcpcd_config_free(options);
391 dhcpcd_config_read(DHCPCD_CONNECTION *con, const char *block, const char *name)
395 return config(con, ACT_READ, block, name, NULL, NULL);
399 dhcpcd_config_writeable(DHCPCD_CONNECTION *con)
402 return (access(con->cffile, W_OK) == 0);
406 dhcpcd_config_write(DHCPCD_CONNECTION *con,
407 const char *block, const char *name,
408 const DHCPCD_OPTION *opts)
415 config(con, ACT_WRITE, block, name, opts, NULL);
423 dhcpcd_config_blocks(DHCPCD_CONNECTION *con, const char *block)
429 config(con, ACT_LIST, block, NULL, NULL, &blocks);