device: renew dhcp leases on awake for software devices
[NetworkManager.git] / libnm-core / nm-keyfile-utils.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* NetworkManager system settings service
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  * (C) Copyright 2010 Red Hat, Inc.
19  */
20
21 #include "nm-default.h"
22
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "nm-keyfile-utils.h"
27 #include "nm-keyfile-internal.h"
28 #include "nm-setting-wired.h"
29 #include "nm-setting-wireless.h"
30 #include "nm-setting-wireless-security.h"
31
32 typedef struct {
33         const char *setting;
34         const char *alias;
35 } SettingAlias;
36
37 static const SettingAlias alias_list[] = {
38         { NM_SETTING_WIRED_SETTING_NAME, "ethernet" },
39         { NM_SETTING_WIRELESS_SETTING_NAME, "wifi" },
40         { NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, "wifi-security" },
41 };
42
43 const char *
44 nm_keyfile_plugin_get_alias_for_setting_name (const char *setting_name)
45 {
46         guint i;
47
48         g_return_val_if_fail (setting_name != NULL, NULL);
49
50         for (i = 0; i < G_N_ELEMENTS (alias_list); i++) {
51                 if (strcmp (setting_name, alias_list[i].setting) == 0)
52                         return alias_list[i].alias;
53         }
54         return NULL;
55 }
56
57 const char *
58 nm_keyfile_plugin_get_setting_name_for_alias (const char *alias)
59 {
60         guint i;
61
62         g_return_val_if_fail (alias != NULL, NULL);
63
64         for (i = 0; i < G_N_ELEMENTS (alias_list); i++) {
65                 if (strcmp (alias, alias_list[i].alias) == 0)
66                         return alias_list[i].setting;
67         }
68         return NULL;
69 }
70
71 /**********************************************************************/
72
73 /* List helpers */
74 #define DEFINE_KF_LIST_WRAPPER(stype, get_ctype, set_ctype) \
75 get_ctype \
76 nm_keyfile_plugin_kf_get_##stype##_list (GKeyFile *kf, \
77                                          const char *group, \
78                                          const char *key, \
79                                          gsize *out_length, \
80                                          GError **error) \
81 { \
82         get_ctype list; \
83         const char *alias; \
84         GError *local = NULL; \
85  \
86         list = g_key_file_get_##stype##_list (kf, group, key, out_length, &local); \
87         if (g_error_matches (local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) { \
88                 alias = nm_keyfile_plugin_get_alias_for_setting_name (group); \
89                 if (alias) { \
90                         g_clear_error (&local); \
91                         list = g_key_file_get_##stype##_list (kf, alias, key, out_length, &local); \
92                 } \
93         } \
94         if (local) \
95                 g_propagate_error (error, local); \
96         return list; \
97 } \
98  \
99 void \
100 nm_keyfile_plugin_kf_set_##stype##_list (GKeyFile *kf, \
101                                          const char *group, \
102                                          const char *key, \
103                                          set_ctype list[], \
104                                          gsize length) \
105 { \
106         const char *alias; \
107  \
108         alias = nm_keyfile_plugin_get_alias_for_setting_name (group); \
109         g_key_file_set_##stype##_list (kf, alias ? alias : group, key, list, length); \
110 }
111
112 DEFINE_KF_LIST_WRAPPER(integer, gint*, gint);
113 DEFINE_KF_LIST_WRAPPER(string, gchar **, const gchar* const);
114
115 /* Single value helpers */
116 #define DEFINE_KF_WRAPPER(stype, get_ctype, set_ctype) \
117 get_ctype \
118 nm_keyfile_plugin_kf_get_##stype (GKeyFile *kf, \
119                                   const char *group, \
120                                   const char *key, \
121                                   GError **error) \
122 { \
123         get_ctype val; \
124         const char *alias; \
125         GError *local = NULL; \
126  \
127         val = g_key_file_get_##stype (kf, group, key, &local); \
128         if (g_error_matches (local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) { \
129                 alias = nm_keyfile_plugin_get_alias_for_setting_name (group); \
130                 if (alias) { \
131                         g_clear_error (&local); \
132                         val = g_key_file_get_##stype (kf, alias, key, &local); \
133                 } \
134         } \
135         if (local) \
136                 g_propagate_error (error, local); \
137         return val; \
138 } \
139  \
140 void \
141 nm_keyfile_plugin_kf_set_##stype (GKeyFile *kf, \
142                                   const char *group, \
143                                   const char *key, \
144                                   set_ctype value) \
145 { \
146         const char *alias; \
147  \
148         alias = nm_keyfile_plugin_get_alias_for_setting_name (group); \
149         g_key_file_set_##stype (kf, alias ? alias : group, key, value); \
150 }
151
152 DEFINE_KF_WRAPPER(string, gchar*, const gchar*);
153 DEFINE_KF_WRAPPER(integer, gint, gint);
154 DEFINE_KF_WRAPPER(uint64, guint64, guint64);
155 DEFINE_KF_WRAPPER(boolean, gboolean, gboolean);
156 DEFINE_KF_WRAPPER(value, gchar*, const gchar*);
157
158
159 gchar **
160 nm_keyfile_plugin_kf_get_keys (GKeyFile *kf,
161                                const char *group,
162                                gsize *out_length,
163                                GError **error)
164 {
165         gchar **keys;
166         const char *alias;
167         GError *local = NULL;
168
169         keys = g_key_file_get_keys (kf, group, out_length, &local);
170         if (g_error_matches (local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) {
171                 alias = nm_keyfile_plugin_get_alias_for_setting_name (group);
172                 if (alias) {
173                         g_clear_error (&local);
174                         keys = g_key_file_get_keys (kf, alias, out_length, &local);
175                 }
176         }
177         if (local)
178                 g_propagate_error (error, local);
179         return keys;
180 }
181
182 gboolean
183 nm_keyfile_plugin_kf_has_key (GKeyFile *kf,
184                               const char *group,
185                               const char *key,
186                               GError **error)
187 {
188         gboolean has;
189         const char *alias;
190         GError *local = NULL;
191
192         has = g_key_file_has_key (kf, group, key, &local);
193         if (g_error_matches (local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) {
194                 alias = nm_keyfile_plugin_get_alias_for_setting_name (group);
195                 if (alias) {
196                         g_clear_error (&local);
197                         has = g_key_file_has_key (kf, alias, key, &local);
198                 }
199         }
200         if (local)
201                 g_propagate_error (error, local);
202         return has;
203 }
204
205 /************************************************************************/
206
207 void
208 _nm_keyfile_copy (GKeyFile *dst, GKeyFile *src)
209 {
210         gs_strfreev char **groups = NULL;
211         guint g, k;
212
213         groups = g_key_file_get_groups (src, NULL);
214         for (g = 0; groups && groups[g]; g++) {
215                 const char *group = groups[g];
216                 gs_strfreev char **keys = NULL;
217
218                 keys = g_key_file_get_keys (src, group, NULL, NULL);
219                 if (!keys)
220                         continue;
221
222                 for (k = 0; keys[k]; k++) {
223                         const char *key = keys[k];
224                         gs_free char *value = NULL;
225
226                         value = g_key_file_get_value (src, group, key, NULL);
227                         if (value)
228                                 g_key_file_set_value (dst, group, key, value);
229                         else
230                                 g_key_file_remove_key (dst, group, key, NULL);
231                 }
232         }
233 }
234
235 /************************************************************************/
236
237 gboolean
238 _nm_keyfile_a_contains_all_in_b (GKeyFile *kf_a, GKeyFile *kf_b)
239 {
240         gs_strfreev char **groups = NULL;
241         guint i, j;
242
243         if (kf_a == kf_b)
244                 return TRUE;
245         if (!kf_a || !kf_b)
246                 return FALSE;
247
248         groups = g_key_file_get_groups (kf_a, NULL);
249         for (i = 0; groups && groups[i]; i++) {
250                 gs_strfreev char **keys = NULL;
251
252                 keys = g_key_file_get_keys (kf_a, groups[i], NULL, NULL);
253                 if (!keys)
254                         continue;
255
256                 for (j = 0; keys[j]; j++) {
257                         gs_free char *key_a = g_key_file_get_value (kf_a, groups[i], keys[j], NULL);
258                         gs_free char *key_b = g_key_file_get_value (kf_b, groups[i], keys[j], NULL);
259
260                         if (g_strcmp0 (key_a, key_b) != 0)
261                                 return FALSE;
262                 }
263         }
264         return TRUE;
265 }
266
267
268 static gboolean
269 _nm_keyfile_equals_ordered (GKeyFile *kf_a, GKeyFile *kf_b)
270 {
271         gs_strfreev char **groups = NULL;
272         gs_strfreev char **groups_b = NULL;
273         guint i, j;
274
275         if (kf_a == kf_b)
276                 return TRUE;
277         if (!kf_a || !kf_b)
278                 return FALSE;
279
280         groups = g_key_file_get_groups (kf_a, NULL);
281         groups_b = g_key_file_get_groups (kf_b, NULL);
282         if (!groups && !groups_b)
283                 return TRUE;
284         if (!groups || !groups_b)
285                 return FALSE;
286         for (i = 0; groups[i] && groups_b[i] && !strcmp (groups[i], groups_b[i]); i++)
287                 ;
288         if (groups[i] || groups_b[i])
289                 return FALSE;
290
291         for (i = 0; groups[i]; i++) {
292                 gs_strfreev char **keys = NULL;
293                 gs_strfreev char **keys_b = NULL;
294
295                 keys = g_key_file_get_keys (kf_a, groups[i], NULL, NULL);
296                 keys_b = g_key_file_get_keys (kf_b, groups[i], NULL, NULL);
297
298                 if ((!keys) != (!keys_b))
299                         return FALSE;
300                 if (!keys)
301                         continue;
302
303                 for (j = 0; keys[j] && keys_b[j] && !strcmp (keys[j], keys_b[j]); j++)
304                         ;
305                 if (keys[j] || keys_b[j])
306                         return FALSE;
307
308                 for (j = 0; keys[j]; j++) {
309                         gs_free char *key_a = g_key_file_get_value (kf_a, groups[i], keys[j], NULL);
310                         gs_free char *key_b = g_key_file_get_value (kf_b, groups[i], keys[j], NULL);
311
312                         if (g_strcmp0 (key_a, key_b) != 0)
313                                 return FALSE;
314                 }
315         }
316         return TRUE;
317 }
318
319 gboolean
320 _nm_keyfile_equals (GKeyFile *kf_a, GKeyFile *kf_b, gboolean consider_order)
321 {
322         if (!consider_order) {
323                 return    _nm_keyfile_a_contains_all_in_b (kf_a, kf_b)
324                        && _nm_keyfile_a_contains_all_in_b (kf_b, kf_a);
325         } else {
326                 return _nm_keyfile_equals_ordered (kf_a, kf_b);
327         }
328 }
329
330 gboolean
331 _nm_keyfile_has_values (GKeyFile *keyfile)
332 {
333         gs_strfreev char **groups = NULL;
334
335         g_return_val_if_fail (keyfile, FALSE);
336
337         groups = g_key_file_get_groups (keyfile, NULL);
338         return groups && groups[0];
339 }