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
37 static DHCPCD_OPTION *
38 dhcpcd_option_new(const char *opt, const char *val)
42 o = malloc(sizeof(*o));
45 o->option = strdup(opt);
46 if (o->option == NULL) {
50 o->value = strdup(val);
51 if (o->value == NULL) {
61 dhcpcd_option_free(DHCPCD_OPTION *o)
70 dhcpcd_config_free(DHCPCD_OPTION *c)
76 dhcpcd_option_free(c);
81 static DHCPCD_OPTION *
82 dhcpcd_config_get1(DHCPCD_OPTION *config, const char *opt, DHCPCD_OPTION **lst)
86 for (o = config; o; o = o->next) {
87 if (strcmp(o->option, opt) == 0)
97 dhcpcd_config_get(DHCPCD_OPTION *config, const char *opt)
102 o = dhcpcd_config_get1(config, opt, NULL);
108 static DHCPCD_OPTION *
109 dhcpcd_config_get_static1(DHCPCD_OPTION *config, const char *opt,
117 while ((o = dhcpcd_config_get1(o, "static", lst)) != NULL) {
118 if (strncmp(o->value, opt, len) == 0)
128 dhcpcd_config_get_static(DHCPCD_OPTION *config, const char *opt)
133 o = dhcpcd_config_get_static1(config, opt, NULL);
136 return o->value + strlen(opt);
140 dhcpcd_config_set1(DHCPCD_OPTION **config, const char *opt, const char *val,
143 DHCPCD_OPTION *o, *l;
149 o = dhcpcd_config_get_static1(*config, opt, &l);
151 o = dhcpcd_config_get1(*config, opt, &l);
165 len = strlen(opt) + strlen(val) + 2;
169 snprintf(t, len, "%s%s", opt, val);
177 o = dhcpcd_option_new("static", t);
179 o = dhcpcd_option_new(opt, val);
194 dhcpcd_config_set(DHCPCD_OPTION **config, const char *opt, const char *val)
199 return dhcpcd_config_set1(config, opt, val, false);
203 dhcpcd_config_set_static(DHCPCD_OPTION **config,
204 const char *opt, const char *val)
209 return dhcpcd_config_set1(config, opt, val, true);
212 #define ACT_READ (1 << 0)
213 #define ACT_WRITE (1 << 1)
214 #define ACT_LIST (1 << 2)
216 static DHCPCD_OPTION *
217 config(DHCPCD_CONNECTION *con, int action, const char *block, const char *name,
218 const DHCPCD_OPTION *no, char ***list)
221 DHCPCD_OPTION *options, *o;
222 const DHCPCD_OPTION *co;
223 char *line, *option, *p;
226 size_t len, buf_size, buf_len, i;
228 fp = fopen(con->cffile, "r");
232 skip = block && !(action & ACT_LIST) ? 1 : 0;
234 buf_len = buf_size = 0;
236 while (getline(&con->buf, &con->buflen, fp) != -1) {
238 /* Trim leading trailing newline and whitespace */
239 while (*line == ' ' || *line == '\n' || *line == '\t')
241 /* Trim trailing newline and whitespace */
243 p = line + strlen(line) - 1;
245 (*p == ' ' || *p == '\n' || *p == '\t') &&
249 option = strsep(&line, " \t");
250 /* Trim trailing whitespace */
252 p = line + strlen(line) - 1;
254 (*p == ' ' || *p == '\n' || *p == '\t') &&
258 if (action & ACT_LIST) {
259 if (strcmp(option, block) == 0)
264 /* Start of a block, skip if not ours */
265 if (strcmp(option, "interface") == 0 ||
266 strcmp(option, "ssid") == 0)
268 if (block && name && line &&
269 strcmp(option, block) == 0 &&
270 strcmp(line, name) == 0)
274 if (!(action & ACT_WRITE))
278 if ((action & ACT_WRITE && skip) ||
279 (action & ACT_LIST && !skip))
281 if (buf_len + 2 > buf_size) {
283 nbuf = realloc(buf, sizeof(char *) * buf_size);
288 if (action & ACT_WRITE && line && *line != '\0') {
289 len = strlen(option) + strlen(line) + 2;
290 buf[buf_len] = malloc(len);
291 if (buf[buf_len] == NULL)
293 snprintf(buf[buf_len], len,
294 "%s %s", option, line);
296 if (action & ACT_LIST)
297 buf[buf_len] = strdup(line);
299 buf[buf_len] = strdup(option);
300 if (buf[buf_len] == NULL)
305 if (skip || action & ACT_LIST)
307 if (*option == '\0' || *option == '#' || *option == ';')
310 options = o = malloc(sizeof(*options));
312 o->next = malloc(sizeof(*o));
318 o->option = strdup(option);
319 if (o->option == NULL) {
323 if (line == NULL || *line == '\0')
326 o->value = strdup(line);
327 if (o->value == NULL)
332 if (action & ACT_WRITE) {
333 fp = freopen(con->cffile, "w", fp);
338 for (i = 0; i < buf_len; i++) {
341 skip = buf[i][0] == '\0' ? 1 : 0;
348 fprintf(fp, "%s %s\n", block, name);
351 for (co = no; co; co = co->next) {
353 fprintf(fp, "%s %s\n", co->option, co->value);
355 fprintf(fp, "%s\n", co->option);
361 for (i = 0; i < buf_len; i++) {
372 if (action & ACT_LIST) {
377 for (i = 0; i < buf_len; i++)
382 dhcpcd_config_free(options);
389 dhcpcd_config_read(DHCPCD_CONNECTION *con, const char *block, const char *name)
393 return config(con, ACT_READ, block, name, NULL, NULL);
397 dhcpcd_config_write(DHCPCD_CONNECTION *con,
398 const char *block, const char *name,
399 const DHCPCD_OPTION *opts)
406 config(con, ACT_WRITE, block, name, opts, NULL);
414 dhcpcd_config_blocks(DHCPCD_CONNECTION *con, const char *block)
420 config(con, ACT_LIST, block, NULL, NULL, &blocks);