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);
195 dhcpcd_config_set(DHCPCD_OPTION **config, const char *opt, const char *val)
200 return dhcpcd_config_set1(config, opt, val, false);
204 dhcpcd_config_set_static(DHCPCD_OPTION **config,
205 const char *opt, const char *val)
210 return dhcpcd_config_set1(config, opt, val, true);
213 #define ACT_READ (1 << 0)
214 #define ACT_WRITE (1 << 1)
215 #define ACT_LIST (1 << 2)
217 static DHCPCD_OPTION *
218 config(DHCPCD_CONNECTION *con, int action, const char *block, const char *name,
219 const DHCPCD_OPTION *no, char ***list)
222 DHCPCD_OPTION *options, *o;
223 const DHCPCD_OPTION *co;
224 char *line, *option, *p;
227 size_t len, buf_size, buf_len, i;
229 fp = fopen(con->cffile, "r");
233 skip = block && !(action & ACT_LIST) ? 1 : 0;
235 buf_len = buf_size = 0;
237 while (getline(&con->buf, &con->buflen, fp) != -1) {
239 /* Trim leading trailing newline and whitespace */
240 while (*line == ' ' || *line == '\n' || *line == '\t')
242 /* Trim trailing newline and whitespace */
244 p = line + strlen(line) - 1;
246 (*p == ' ' || *p == '\n' || *p == '\t') &&
250 option = strsep(&line, " \t");
251 /* Trim trailing whitespace */
253 p = line + strlen(line) - 1;
255 (*p == ' ' || *p == '\n' || *p == '\t') &&
259 if (action & ACT_LIST) {
260 if (strcmp(option, block) == 0)
265 /* Start of a block, skip if not ours */
266 if (strcmp(option, "interface") == 0 ||
267 strcmp(option, "ssid") == 0)
269 if (block && name && line &&
270 strcmp(option, block) == 0 &&
271 strcmp(line, name) == 0)
275 if (!(action & ACT_WRITE))
279 if ((action & ACT_WRITE && skip) ||
280 (action & ACT_LIST && !skip))
282 if (buf_len + 2 > buf_size) {
284 nbuf = realloc(buf, sizeof(char *) * buf_size);
289 if (action & ACT_WRITE && line && *line != '\0') {
290 len = strlen(option) + strlen(line) + 2;
291 buf[buf_len] = malloc(len);
292 if (buf[buf_len] == NULL)
294 snprintf(buf[buf_len], len,
295 "%s %s", option, line);
297 if (action & ACT_LIST)
298 buf[buf_len] = strdup(line);
300 buf[buf_len] = strdup(option);
301 if (buf[buf_len] == NULL)
306 if (skip || action & ACT_LIST)
308 if (*option == '\0' || *option == '#' || *option == ';')
311 options = o = malloc(sizeof(*options));
313 o->next = malloc(sizeof(*o));
319 o->option = strdup(option);
320 if (o->option == NULL) {
324 if (line == NULL || *line == '\0')
327 o->value = strdup(line);
328 if (o->value == NULL)
333 if (action & ACT_WRITE) {
334 fp = freopen(con->cffile, "w", fp);
339 for (i = 0; i < buf_len; i++) {
342 skip = buf[i][0] == '\0' ? 1 : 0;
349 fprintf(fp, "%s %s\n", block, name);
352 for (co = no; co; co = co->next) {
354 fprintf(fp, "%s %s\n", co->option, co->value);
356 fprintf(fp, "%s\n", co->option);
362 for (i = 0; i < buf_len; i++) {
373 if (action & ACT_LIST) {
378 for (i = 0; i < buf_len; i++)
383 dhcpcd_config_free(options);
390 dhcpcd_config_read(DHCPCD_CONNECTION *con, const char *block, const char *name)
394 return config(con, ACT_READ, block, name, NULL, NULL);
398 dhcpcd_config_write(DHCPCD_CONNECTION *con,
399 const char *block, const char *name,
400 const DHCPCD_OPTION *opts)
407 config(con, ACT_WRITE, block, name, opts, NULL);
415 dhcpcd_config_blocks(DHCPCD_CONNECTION *con, const char *block)
421 config(con, ACT_LIST, block, NULL, NULL, &blocks);