Base Code merged to SPIN 2.4
[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         DBG("Loading %s", pathname);
47
48         keyfile = g_key_file_new();
49
50         if (!g_key_file_load_from_file(keyfile, pathname, 0, &error)) {
51                 DBG("Unable to load %s: %s", pathname, error->message);
52                 g_clear_error(&error);
53
54                 g_key_file_free(keyfile);
55                 keyfile = NULL;
56         }
57
58         return keyfile;
59 }
60
61 static int storage_save(GKeyFile *keyfile, char *pathname)
62 {
63         gchar *data = NULL;
64         gsize length = 0;
65         GError *error = NULL;
66         int ret = 0;
67
68         data = g_key_file_to_data(keyfile, &length, NULL);
69
70         if (!g_file_set_contents(pathname, data, length, &error)) {
71                 DBG("Failed to store information: %s", error->message);
72                 g_error_free(error);
73                 ret = -EIO;
74         }
75
76         g_free(data);
77
78         return ret;
79 }
80
81 static void storage_delete(const char *pathname)
82 {
83         DBG("file path %s", pathname);
84
85         if (unlink(pathname) < 0)
86                 connman_error("Failed to remove %s", pathname);
87 }
88
89 GKeyFile *__connman_storage_load_global(void)
90 {
91         gchar *pathname;
92         GKeyFile *keyfile = NULL;
93
94         pathname = g_strdup_printf("%s/%s", STORAGEDIR, SETTINGS);
95         if (!pathname)
96                 return NULL;
97
98         keyfile = storage_load(pathname);
99
100         g_free(pathname);
101
102         return keyfile;
103 }
104
105 int __connman_storage_save_global(GKeyFile *keyfile)
106 {
107         gchar *pathname;
108         int ret;
109
110         pathname = g_strdup_printf("%s/%s", STORAGEDIR, SETTINGS);
111         if (!pathname)
112                 return -ENOMEM;
113
114         ret = storage_save(keyfile, pathname);
115
116         g_free(pathname);
117
118         return ret;
119 }
120
121 void __connman_storage_delete_global(void)
122 {
123         gchar *pathname;
124
125         pathname = g_strdup_printf("%s/%s", STORAGEDIR, SETTINGS);
126         if (!pathname)
127                 return;
128
129         storage_delete(pathname);
130
131         g_free(pathname);
132 }
133
134 GKeyFile *__connman_storage_load_config(const char *ident)
135 {
136         gchar *pathname;
137         GKeyFile *keyfile = NULL;
138
139         pathname = g_strdup_printf("%s/%s.config", STORAGEDIR, ident);
140         if (!pathname)
141                 return NULL;
142
143         keyfile = storage_load(pathname);
144
145         g_free(pathname);
146
147         return keyfile;
148 }
149
150 GKeyFile *__connman_storage_load_provider_config(const char *ident)
151 {
152         gchar *pathname;
153         GKeyFile *keyfile = NULL;
154
155         pathname = g_strdup_printf("%s/%s.config", VPN_STORAGEDIR, ident);
156         if (!pathname)
157                 return NULL;
158
159         keyfile = storage_load(pathname);
160
161         g_free(pathname);
162
163         return keyfile;
164 }
165
166 GKeyFile *__connman_storage_open_service(const char *service_id)
167 {
168         gchar *pathname;
169         GKeyFile *keyfile = NULL;
170
171         pathname = g_strdup_printf("%s/%s/%s", STORAGEDIR, service_id, SETTINGS);
172         if (!pathname)
173                 return NULL;
174
175         keyfile =  storage_load(pathname);
176         if (keyfile) {
177                 g_free(pathname);
178                 return keyfile;
179         }
180
181         g_free(pathname);
182
183         keyfile = g_key_file_new();
184
185         return keyfile;
186 }
187
188 gchar **connman_storage_get_services(void)
189 {
190         struct dirent *d;
191         gchar *str;
192         DIR *dir;
193         GString *result;
194         gchar **services = NULL;
195         struct stat buf;
196         int ret;
197
198         dir = opendir(STORAGEDIR);
199         if (!dir)
200                 return NULL;
201
202         result = g_string_new(NULL);
203
204         while ((d = readdir(dir))) {
205                 if (strcmp(d->d_name, ".") == 0 ||
206                                 strcmp(d->d_name, "..") == 0 ||
207                                 strncmp(d->d_name, "provider_", 9) == 0)
208                         continue;
209
210                 switch (d->d_type) {
211                 case DT_DIR:
212                 case DT_UNKNOWN:
213                         /*
214                          * If the settings file is not found, then
215                          * assume this directory is not a services dir.
216                          */
217                         str = g_strdup_printf("%s/%s/settings", STORAGEDIR,
218                                                                 d->d_name);
219                         ret = stat(str, &buf);
220                         g_free(str);
221                         if (ret < 0)
222                                 continue;
223
224                         g_string_append_printf(result, "%s/", d->d_name);
225                         break;
226                 }
227         }
228
229         closedir(dir);
230
231         str = g_string_free(result, FALSE);
232         if (str && str[0] != '\0') {
233                 /*
234                  * Remove the trailing separator so that services doesn't end up
235                  * with an empty element.
236                  */
237                 str[strlen(str) - 1] = '\0';
238                 services = g_strsplit(str, "/", -1);
239         }
240         g_free(str);
241
242         return services;
243 }
244
245 GKeyFile *connman_storage_load_service(const char *service_id)
246 {
247         gchar *pathname;
248         GKeyFile *keyfile = NULL;
249
250         pathname = g_strdup_printf("%s/%s/%s", STORAGEDIR, service_id, SETTINGS);
251         if (!pathname)
252                 return NULL;
253
254         keyfile =  storage_load(pathname);
255         g_free(pathname);
256
257         return keyfile;
258 }
259
260 int __connman_storage_save_service(GKeyFile *keyfile, const char *service_id)
261 {
262         int ret = 0;
263         gchar *pathname, *dirname;
264
265         dirname = g_strdup_printf("%s/%s", STORAGEDIR, service_id);
266         if (!dirname)
267                 return -ENOMEM;
268
269         /* If the dir doesn't exist, create it */
270         if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) {
271                 if (mkdir(dirname, MODE) < 0) {
272                         if (errno != EEXIST) {
273                                 g_free(dirname);
274                                 return -errno;
275                         }
276                 }
277         }
278
279         pathname = g_strdup_printf("%s/%s", dirname, SETTINGS);
280
281         g_free(dirname);
282
283         ret = storage_save(keyfile, pathname);
284
285         g_free(pathname);
286
287         return ret;
288 }
289
290 static bool remove_file(const char *service_id, const char *file)
291 {
292         gchar *pathname;
293         bool ret = false;
294
295         pathname = g_strdup_printf("%s/%s/%s", STORAGEDIR, service_id, file);
296         if (!pathname)
297                 return false;
298
299         if (!g_file_test(pathname, G_FILE_TEST_EXISTS)) {
300                 ret = true;
301         } else if (g_file_test(pathname, G_FILE_TEST_IS_REGULAR)) {
302                 unlink(pathname);
303                 ret = true;
304         }
305
306         g_free(pathname);
307         return ret;
308 }
309
310 static bool remove_dir(const char *service_id)
311 {
312         gchar *pathname;
313         bool ret = false;
314
315         pathname = g_strdup_printf("%s/%s", STORAGEDIR, service_id);
316         if (!pathname)
317                 return false;
318
319         if (!g_file_test(pathname, G_FILE_TEST_EXISTS)) {
320                 ret = true;
321         } else if (g_file_test(pathname, G_FILE_TEST_IS_DIR)) {
322                 rmdir(pathname);
323                 ret = true;
324         }
325
326         g_free(pathname);
327         return ret;
328 }
329
330 bool __connman_storage_remove_service(const char *service_id)
331 {
332         bool removed;
333
334         /* Remove service configuration file */
335         removed = remove_file(service_id, SETTINGS);
336         if (!removed)
337                 return false;
338
339         /* Remove the statistics file also */
340         removed = remove_file(service_id, "data");
341         if (!removed)
342                 return false;
343
344         removed = remove_dir(service_id);
345         if (!removed)
346                 return false;
347
348         DBG("Removed service dir %s/%s", STORAGEDIR, service_id);
349
350         return true;
351 }
352
353 GKeyFile *__connman_storage_load_provider(const char *identifier)
354 {
355         gchar *pathname;
356         GKeyFile *keyfile;
357
358         pathname = g_strdup_printf("%s/%s_%s/%s", STORAGEDIR, "provider",
359                         identifier, SETTINGS);
360         if (!pathname)
361                 return NULL;
362
363         keyfile = storage_load(pathname);
364         g_free(pathname);
365
366         return keyfile;
367 }
368
369 void __connman_storage_save_provider(GKeyFile *keyfile, const char *identifier)
370 {
371         gchar *pathname, *dirname;
372
373         dirname = g_strdup_printf("%s/%s_%s", STORAGEDIR,
374                         "provider", identifier);
375         if (!dirname)
376                 return;
377
378         if (!g_file_test(dirname, G_FILE_TEST_IS_DIR) &&
379                         mkdir(dirname, MODE) < 0) {
380                 g_free(dirname);
381                 return;
382         }
383
384         pathname = g_strdup_printf("%s/%s", dirname, SETTINGS);
385         g_free(dirname);
386
387         storage_save(keyfile, pathname);
388         g_free(pathname);
389 }
390
391 static bool remove_all(const char *id)
392 {
393         bool removed;
394
395         remove_file(id, SETTINGS);
396         remove_file(id, "data");
397
398         removed = remove_dir(id);
399         if (!removed)
400                 return false;
401
402         return true;
403 }
404
405 bool __connman_storage_remove_provider(const char *identifier)
406 {
407         bool removed;
408         gchar *id;
409
410         id = g_strdup_printf("%s_%s", "provider", identifier);
411         if (!id)
412                 return false;
413
414         if (remove_all(id))
415                 DBG("Removed provider dir %s/%s", STORAGEDIR, id);
416
417         g_free(id);
418
419         id = g_strdup_printf("%s_%s", "vpn", identifier);
420         if (!id)
421                 return false;
422
423         if ((removed = remove_all(id)))
424                 DBG("Removed vpn dir %s/%s", STORAGEDIR, id);
425
426         g_free(id);
427
428         return removed;
429 }
430
431 gchar **__connman_storage_get_providers(void)
432 {
433         GSList *list = NULL;
434         int num = 0, i = 0;
435         struct dirent *d;
436         gchar *str;
437         DIR *dir;
438         struct stat buf;
439         int ret;
440         char **providers;
441         GSList *iter;
442
443         dir = opendir(STORAGEDIR);
444         if (!dir)
445                 return NULL;
446
447         while ((d = readdir(dir))) {
448                 if (strcmp(d->d_name, ".") == 0 ||
449                                 strcmp(d->d_name, "..") == 0 ||
450                                 strncmp(d->d_name, "provider_", 9) != 0)
451                         continue;
452
453                 if (d->d_type == DT_DIR) {
454                         str = g_strdup_printf("%s/%s/settings", STORAGEDIR,
455                                         d->d_name);
456                         ret = stat(str, &buf);
457                         g_free(str);
458                         if (ret < 0)
459                                 continue;
460                         list = g_slist_prepend(list, g_strdup(d->d_name));
461                         num += 1;
462                 }
463         }
464
465         closedir(dir);
466
467         providers = g_try_new0(char *, num + 1);
468         for (iter = list; iter; iter = g_slist_next(iter)) {
469                 if (providers)
470                         providers[i] = iter->data;
471                 else
472                         g_free(iter->data);
473                 i += 1;
474         }
475         g_slist_free(list);
476
477         return providers;
478 }