Remove dbus-glib dependency and create libdhcpcd.
[dhcpcd-ui] / src / libdhcpcd / config.c
1 /*
2  * libdhcpcd
3  * Copyright 2009 Roy Marples <roy@marples.name>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  */
26
27 #include <errno.h>
28 #include <stdbool.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <dbus/dbus.h>
34
35 #define IN_LIBDHCPCD
36 #include "libdhcpcd.h"
37
38 static DHCPCD_CONFIG *
39 dhcpcd_config_new(const char *opt, const char *val)
40 {
41         DHCPCD_CONFIG *c;
42
43         c = malloc(sizeof(*c));
44         if (c == NULL)
45                 return NULL;
46         c->option = strdup(opt);
47         if (c->option == NULL) {
48                 free(c);
49                 return NULL;
50         }
51         c->value = strdup(val);
52         if (c->value == NULL) {
53                 free(c->option);
54                 free(c);
55                 return NULL;
56         }
57         c->next = NULL;
58         return c;
59 }
60
61 void
62 dhcpcd_config_free(DHCPCD_CONFIG *config)
63 {
64         DHCPCD_CONFIG *c;
65         
66         while (config) {
67                 c = config->next;
68                 free(config->option);
69                 free(config->value);
70                 free(config);
71                 config = c;
72         }
73 }       
74
75 char **
76 dhcpcd_config_blocks_get(DHCPCD_CONNECTION *con, const char *block)
77 {
78         DBusMessage *msg, *reply;
79         DBusMessageIter args;
80         DBusError error;
81         char **blocks;
82         int n_blocks;
83
84         msg = dbus_message_new_method_call(DHCPCD_SERVICE, DHCPCD_PATH,
85             DHCPCD_SERVICE, "GetConfigBlocks");
86         if (msg == NULL) {
87                 dhcpcd_error_set(con, NULL, errno);
88                 return NULL;
89         }
90         dbus_message_iter_init_append(msg, &args);
91         dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &block);
92         reply = dhcpcd_send_reply(con, msg);
93         dbus_message_unref(msg);
94         if (reply == NULL)
95                 return NULL;
96         dbus_error_init(&error);
97         blocks = NULL;
98         n_blocks = 0;
99         if (!dbus_message_get_args(reply, &error, DBUS_TYPE_ARRAY,
100                 DBUS_TYPE_STRING, &blocks, &n_blocks,
101                 DBUS_TYPE_INVALID))
102         {
103                 dhcpcd_error_set(con, error.message, 0);
104                 dbus_error_free(&error);
105         }
106         dbus_message_unref(reply);
107         return blocks;  
108 }
109
110 DHCPCD_CONFIG *
111 dhcpcd_config_load(DHCPCD_CONNECTION *con, const char *block, const char *name)
112 {
113         DHCPCD_CONFIG *config, *c, *l;
114         DBusMessage *msg, *reply;
115         DBusMessageIter args, array, item;
116         const char ns[] = "", *option, *value;
117         int errors;
118
119         msg = dbus_message_new_method_call(DHCPCD_SERVICE, DHCPCD_PATH,
120             DHCPCD_SERVICE, "GetConfig");
121         if (msg == NULL) {
122                 dhcpcd_error_set(con, NULL, errno);
123                 return NULL;
124         }
125         dbus_message_iter_init_append(msg, &args);
126         if (block == NULL)
127                 block = ns;
128         if (name == NULL)
129                 name = ns;
130         dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &block);
131         dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &name);
132         reply = dhcpcd_send_reply(con, msg);
133         dbus_message_unref(msg);
134         if (reply == NULL)
135                 return NULL;
136         if (!dbus_message_iter_init(reply, &args) ||
137             dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
138         {
139                 dbus_message_unref(reply);
140                 dhcpcd_error_set(con, NULL, EINVAL);
141                 return NULL;
142         }
143         config = l = NULL;
144         errors = con->errors;
145         dbus_message_iter_recurse(&args, &array);
146         for (;
147              dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT;
148              dbus_message_iter_next(&array))
149         {
150                 dbus_message_iter_recurse(&array, &item);
151                 if (!dhcpcd_iter_get(con, &item, DBUS_TYPE_STRING, &option) ||
152                     !dhcpcd_iter_get(con, &item, DBUS_TYPE_STRING, &value))
153                         break;
154                 c = dhcpcd_config_new(option, value);
155                 if (c == NULL) {
156                         dhcpcd_error_set(con, NULL, errno);
157                         break;
158                 }
159                 if (l == NULL)
160                         config = c;
161                 else
162                         l->next = c;
163                 l = c;
164         }
165         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
166                 if (con->errors == errors)
167                         dhcpcd_error_set(con, NULL, EINVAL);
168                 dhcpcd_config_free(config);
169                 config = NULL;
170         }
171         dbus_message_unref(reply);
172         return config;
173 }
174
175 bool
176 dhcpcd_config_save(DHCPCD_CONNECTION *con, const char *block, const char *name,
177     DHCPCD_CONFIG *config)
178 {
179         DBusMessage *msg, *reply;
180         DBusMessageIter args, array, item;
181         DHCPCD_CONFIG *c;
182         const char ns[] = "", *p;
183         bool retval;
184
185         msg = dbus_message_new_method_call(DHCPCD_SERVICE, DHCPCD_PATH,
186             DHCPCD_SERVICE, "SetConfig");
187         if (msg == NULL) {
188                 dhcpcd_error_set(con, 0, errno);
189                 return false;
190         }
191         dbus_message_iter_init_append(msg, &args);
192         dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &block);
193         dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &name);
194         dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY,
195             DBUS_STRUCT_BEGIN_CHAR_AS_STRING
196             DBUS_TYPE_STRING_AS_STRING
197             DBUS_TYPE_STRING_AS_STRING
198             DBUS_STRUCT_END_CHAR_AS_STRING,
199             &array);
200         for (c = config; c; c = c->next) {
201                 dbus_message_iter_open_container(&array,
202                     DBUS_TYPE_STRUCT, NULL, &item);
203                 dbus_message_iter_append_basic(&item,
204                     DBUS_TYPE_STRING, &c->option);
205                 if (c->value == NULL)
206                         p = ns;
207                 else
208                         p = c->value;
209                 dbus_message_iter_append_basic(&item, DBUS_TYPE_STRING, &p);
210                 dbus_message_iter_close_container(&array, &item);
211         }
212         dbus_message_iter_close_container(&args, &array);
213
214         reply = dhcpcd_send_reply(con, msg);
215         dbus_message_unref(msg);
216         if (reply == NULL)
217                 retval = false;
218         else {
219                 dbus_message_unref(reply);
220                 retval = true;
221         }
222         return retval;
223 }
224
225 static DHCPCD_CONFIG *
226 dhcpcd_config_get1(DHCPCD_CONFIG *config, const char *opt, DHCPCD_CONFIG **lst)
227 {
228         DHCPCD_CONFIG *c;
229
230         for (c = config; c; c = c->next) {
231                 if (strcmp(c->option, opt) == 0)
232                         return c;
233                 if (lst)
234                         *lst = c;
235         }
236         errno = ESRCH;
237         return NULL;
238 }
239
240 const char *
241 dhcpcd_config_get(DHCPCD_CONFIG *config, const char *opt)
242 {
243         DHCPCD_CONFIG *c;
244
245         c = dhcpcd_config_get1(config, opt, NULL);
246         if (c == NULL)
247                 return NULL;
248         return c->value;
249 }
250
251 static DHCPCD_CONFIG *
252 dhcpcd_config_get_static1(DHCPCD_CONFIG *config, const char *opt,
253     DHCPCD_CONFIG **lst)
254 {
255         DHCPCD_CONFIG *c;
256         size_t len;
257
258         c = config;
259         len = strlen(opt);
260         while ((c = dhcpcd_config_get1(c, "static", lst)) != NULL) {
261                 if (strncmp(c->value, opt, len) == 0)
262                         return c;
263                 if (lst)
264                         *lst = c;
265                 c = c->next;
266         }
267         return NULL;
268 }
269
270 const char *
271 dhcpcd_config_get_static(DHCPCD_CONFIG *config, const char *opt)
272 {
273         DHCPCD_CONFIG *c;
274
275         c = dhcpcd_config_get_static1(config, opt, NULL);
276         if (c == NULL)
277                 return NULL;
278         return c->value + strlen(opt);
279 }
280
281 static bool
282 dhcpcd_config_set1(DHCPCD_CONFIG **config, const char *opt, const char *val,
283     bool s)
284 {
285         DHCPCD_CONFIG *c, *l;
286         char *t;
287         size_t len;
288
289         l = NULL;
290         if (s)
291                 c = dhcpcd_config_get_static1(*config, opt, &l);
292         else
293                 c = dhcpcd_config_get1(*config, opt, &l);
294         if (val == NULL) {
295                 if (c == NULL)
296                         return true;
297                 if (c == *config)
298                         *config = c->next;
299                 else if (l != NULL)
300                         l->next = c->next;
301                 free(c->option);
302                 free(c->value);
303                 free(c);
304                 return true;
305         }
306         if (s) {
307                 len = strlen(opt) + strlen(val) + 2;
308                 t = malloc(len);
309                 if (t == NULL)
310                         return false;
311                 snprintf(t, len, "%s%s", opt, val);
312         } else {
313                 t = strdup(val);
314                 if (t == NULL)
315                         return false;
316         }
317         if (c == NULL) {
318                 if (s)
319                         c = dhcpcd_config_new("static", t);
320                 else
321                         c = dhcpcd_config_new(opt, val);
322                 if (c == NULL)
323                         return false;
324                 if (l == NULL)
325                         *config = c;
326                 else
327                         l->next = c;
328                 return true;
329         }
330         free(c->value);
331         c->value = t;
332         return true;
333 }
334
335 bool
336 dhcpcd_config_set(DHCPCD_CONFIG **config, const char *opt, const char *val)
337 {
338         return dhcpcd_config_set1(config, opt, val, false);
339 }
340
341 bool
342 dhcpcd_config_set_static(DHCPCD_CONFIG **config,
343     const char *opt, const char *val)
344 {
345         return dhcpcd_config_set1(config, opt, val, true);
346 }