Imported Upstream version 1.38
[platform/upstream/connman.git] / src / storage.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2013  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <unistd.h>
28 #include <sys/stat.h>
29 #include <dirent.h>
30
31 #include <connman/storage.h>
32
33 #include "connman.h"
34
35 #define SETTINGS        "settings"
36 #define DEFAULT         "default.profile"
37
38 #define MODE            (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | \
39                         S_IXGRP | S_IROTH | S_IXOTH)
40
41 static GKeyFile *storage_load(const char *pathname)
42 {
43         GKeyFile *keyfile = NULL;
44         GError *error = NULL;
45
46         keyfile = g_key_file_new();
47
48         if (!g_key_file_load_from_file(keyfile, pathname, 0, &error)) {
49                 DBG("Unable to load %s: %s", pathname, error->message);
50                 g_clear_error(&error);
51
52                 g_key_file_free(keyfile);
53                 keyfile = NULL;
54         }
55
56         return keyfile;
57 }
58
59 static int storage_save(GKeyFile *keyfile, char *pathname)
60 {
61         gchar *data = NULL;
62         gsize length = 0;
63         GError *error = NULL;
64         int ret = 0;
65
66         data = g_key_file_to_data(keyfile, &length, NULL);
67
68         if (!g_file_set_contents(pathname, data, length, &error)) {
69                 DBG("Failed to store information: %s", error->message);
70                 g_error_free(error);
71                 ret = -EIO;
72         }
73
74         g_free(data);
75
76         return ret;
77 }
78
79 static void storage_delete(const char *pathname)
80 {
81         DBG("file path %s", pathname);
82
83         if (unlink(pathname) < 0)
84                 connman_error("Failed to remove %s", pathname);
85 }
86
87 GKeyFile *__connman_storage_load_global(void)
88 {
89         gchar *pathname;
90         GKeyFile *keyfile = NULL;
91
92         pathname = g_strdup_printf("%s/%s", STORAGEDIR, SETTINGS);
93         if (!pathname)
94                 return NULL;
95
96         keyfile = storage_load(pathname);
97
98         g_free(pathname);
99
100         return keyfile;
101 }
102
103 int __connman_storage_save_global(GKeyFile *keyfile)
104 {
105         gchar *pathname;
106         int ret;
107
108         pathname = g_strdup_printf("%s/%s", STORAGEDIR, SETTINGS);
109         if (!pathname)
110                 return -ENOMEM;
111
112         ret = storage_save(keyfile, pathname);
113
114         g_free(pathname);
115
116         return ret;
117 }
118
119 void __connman_storage_delete_global(void)
120 {
121         gchar *pathname;
122
123         pathname = g_strdup_printf("%s/%s", STORAGEDIR, SETTINGS);
124         if (!pathname)
125                 return;
126
127         storage_delete(pathname);
128
129         g_free(pathname);
130 }
131
132 GKeyFile *__connman_storage_load_config(const char *ident)
133 {
134         gchar *pathname;
135         GKeyFile *keyfile = NULL;
136
137         pathname = g_strdup_printf("%s/%s.config", STORAGEDIR, ident);
138         if (!pathname)
139                 return NULL;
140
141         keyfile = storage_load(pathname);
142
143         g_free(pathname);
144
145         return keyfile;
146 }
147
148 GKeyFile *__connman_storage_load_provider_config(const char *ident)
149 {
150         gchar *pathname;
151         GKeyFile *keyfile = NULL;
152
153         pathname = g_strdup_printf("%s/%s.config", VPN_STORAGEDIR, ident);
154         if (!pathname)
155                 return NULL;
156
157         keyfile = storage_load(pathname);
158
159         g_free(pathname);
160
161         return keyfile;
162 }
163
164 gchar **connman_storage_get_services(void)
165 {
166         struct dirent *d;
167         gchar *str;
168         DIR *dir;
169         GString *result;
170         gchar **services = NULL;
171         struct stat buf;
172         int ret;
173
174         dir = opendir(STORAGEDIR);
175         if (!dir)
176                 return NULL;
177
178         result = g_string_new(NULL);
179
180         while ((d = readdir(dir))) {
181                 if (strcmp(d->d_name, ".") == 0 ||
182                                 strcmp(d->d_name, "..") == 0 ||
183                                 strncmp(d->d_name, "provider_", 9) == 0)
184                         continue;
185
186                 switch (d->d_type) {
187                 case DT_DIR:
188                 case DT_UNKNOWN:
189                         /*
190                          * If the settings file is not found, then
191                          * assume this directory is not a services dir.
192                          */
193                         str = g_strdup_printf("%s/%s/settings", STORAGEDIR,
194                                                                 d->d_name);
195                         ret = stat(str, &buf);
196                         g_free(str);
197                         if (ret < 0)
198                                 continue;
199
200                         g_string_append_printf(result, "%s/", d->d_name);
201                         break;
202                 }
203         }
204
205         closedir(dir);
206
207         str = g_string_free(result, FALSE);
208         if (str && str[0] != '\0') {
209                 /*
210                  * Remove the trailing separator so that services doesn't end up
211                  * with an empty element.
212                  */
213                 str[strlen(str) - 1] = '\0';
214                 services = g_strsplit(str, "/", -1);
215         }
216         g_free(str);
217
218         return services;
219 }
220
221 GKeyFile *connman_storage_load_service(const char *service_id)
222 {
223         gchar *pathname;
224         GKeyFile *keyfile = NULL;
225
226         pathname = g_strdup_printf("%s/%s/%s", STORAGEDIR, service_id, SETTINGS);
227         if (!pathname)
228                 return NULL;
229
230         keyfile =  storage_load(pathname);
231         g_free(pathname);
232
233         return keyfile;
234 }
235
236 int __connman_storage_save_service(GKeyFile *keyfile, const char *service_id)
237 {
238         int ret = 0;
239         gchar *pathname, *dirname;
240
241         dirname = g_strdup_printf("%s/%s", STORAGEDIR, service_id);
242         if (!dirname)
243                 return -ENOMEM;
244
245         /* If the dir doesn't exist, create it */
246         if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) {
247                 if (mkdir(dirname, MODE) < 0) {
248                         if (errno != EEXIST) {
249                                 g_free(dirname);
250                                 return -errno;
251                         }
252                 }
253         }
254
255         pathname = g_strdup_printf("%s/%s", dirname, SETTINGS);
256
257         g_free(dirname);
258
259         ret = storage_save(keyfile, pathname);
260
261         g_free(pathname);
262
263         return ret;
264 }
265
266 static bool remove_file(const char *service_id, const char *file)
267 {
268         gchar *pathname;
269         bool ret = false;
270
271         pathname = g_strdup_printf("%s/%s/%s", STORAGEDIR, service_id, file);
272         if (!pathname)
273                 return false;
274
275         if (!g_file_test(pathname, G_FILE_TEST_EXISTS)) {
276                 ret = true;
277         } else if (g_file_test(pathname, G_FILE_TEST_IS_REGULAR)) {
278                 unlink(pathname);
279                 ret = true;
280         }
281
282         g_free(pathname);
283         return ret;
284 }
285
286 static bool remove_dir(const char *service_id)
287 {
288         gchar *pathname;
289         bool ret = false;
290
291         pathname = g_strdup_printf("%s/%s", STORAGEDIR, service_id);
292         if (!pathname)
293                 return false;
294
295         if (!g_file_test(pathname, G_FILE_TEST_EXISTS)) {
296                 ret = true;
297         } else if (g_file_test(pathname, G_FILE_TEST_IS_DIR)) {
298                 rmdir(pathname);
299                 ret = true;
300         }
301
302         g_free(pathname);
303         return ret;
304 }
305
306 bool __connman_storage_remove_service(const char *service_id)
307 {
308         bool removed;
309
310         /* Remove service configuration file */
311         removed = remove_file(service_id, SETTINGS);
312         if (!removed)
313                 return false;
314
315         /* Remove the statistics file also */
316         removed = remove_file(service_id, "data");
317         if (!removed)
318                 return false;
319
320         removed = remove_dir(service_id);
321         if (!removed)
322                 return false;
323
324         DBG("Removed service dir %s/%s", STORAGEDIR, service_id);
325
326         return true;
327 }
328
329 GKeyFile *__connman_storage_load_provider(const char *identifier)
330 {
331         gchar *pathname;
332         GKeyFile *keyfile;
333
334         pathname = g_strdup_printf("%s/%s_%s/%s", STORAGEDIR, "provider",
335                         identifier, SETTINGS);
336         if (!pathname)
337                 return NULL;
338
339         keyfile = storage_load(pathname);
340         g_free(pathname);
341
342         return keyfile;
343 }
344
345 void __connman_storage_save_provider(GKeyFile *keyfile, const char *identifier)
346 {
347         gchar *pathname, *dirname;
348
349         dirname = g_strdup_printf("%s/%s_%s", STORAGEDIR,
350                         "provider", identifier);
351         if (!dirname)
352                 return;
353
354         if (!g_file_test(dirname, G_FILE_TEST_IS_DIR) &&
355                         mkdir(dirname, MODE) < 0) {
356                 g_free(dirname);
357                 return;
358         }
359
360         pathname = g_strdup_printf("%s/%s", dirname, SETTINGS);
361         g_free(dirname);
362
363         storage_save(keyfile, pathname);
364         g_free(pathname);
365 }
366
367 static bool remove_all(const char *id)
368 {
369         bool removed;
370
371         remove_file(id, SETTINGS);
372         remove_file(id, "data");
373
374         removed = remove_dir(id);
375         if (!removed)
376                 return false;
377
378         return true;
379 }
380
381 bool __connman_storage_remove_provider(const char *identifier)
382 {
383         bool removed;
384         gchar *id;
385
386         id = g_strdup_printf("%s_%s", "provider", identifier);
387         if (!id)
388                 return false;
389
390         if (remove_all(id))
391                 DBG("Removed provider dir %s/%s", STORAGEDIR, id);
392
393         g_free(id);
394
395         id = g_strdup_printf("%s_%s", "vpn", identifier);
396         if (!id)
397                 return false;
398
399         if ((removed = remove_all(id)))
400                 DBG("Removed vpn dir %s/%s", STORAGEDIR, id);
401
402         g_free(id);
403
404         return removed;
405 }
406
407 gchar **__connman_storage_get_providers(void)
408 {
409         GSList *list = NULL;
410         int num = 0, i = 0;
411         struct dirent *d;
412         gchar *str;
413         DIR *dir;
414         struct stat buf;
415         int ret;
416         char **providers;
417         GSList *iter;
418
419         dir = opendir(STORAGEDIR);
420         if (!dir)
421                 return NULL;
422
423         while ((d = readdir(dir))) {
424                 if (strcmp(d->d_name, ".") == 0 ||
425                                 strcmp(d->d_name, "..") == 0 ||
426                                 strncmp(d->d_name, "provider_", 9) != 0)
427                         continue;
428
429                 if (d->d_type == DT_DIR) {
430                         str = g_strdup_printf("%s/%s/settings", STORAGEDIR,
431                                         d->d_name);
432                         ret = stat(str, &buf);
433                         g_free(str);
434                         if (ret < 0)
435                                 continue;
436                         list = g_slist_prepend(list, g_strdup(d->d_name));
437                         num += 1;
438                 }
439         }
440
441         closedir(dir);
442
443         providers = g_try_new0(char *, num + 1);
444         for (iter = list; iter; iter = g_slist_next(iter)) {
445                 if (providers)
446                         providers[i] = iter->data;
447                 else
448                         g_free(iter->data);
449                 i += 1;
450         }
451         g_slist_free(list);
452
453         return providers;
454 }