Imported Upstream version 1.35
[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 GKeyFile *__connman_storage_open_service(const char *service_id)
165 {
166         gchar *pathname;
167         GKeyFile *keyfile = NULL;
168
169         pathname = g_strdup_printf("%s/%s/%s", STORAGEDIR, service_id, SETTINGS);
170         if (!pathname)
171                 return NULL;
172
173         keyfile =  storage_load(pathname);
174         if (keyfile) {
175                 g_free(pathname);
176                 return keyfile;
177         }
178
179         g_free(pathname);
180
181         keyfile = g_key_file_new();
182
183         return keyfile;
184 }
185
186 gchar **connman_storage_get_services(void)
187 {
188         struct dirent *d;
189         gchar *str;
190         DIR *dir;
191         GString *result;
192         gchar **services = NULL;
193         struct stat buf;
194         int ret;
195
196         dir = opendir(STORAGEDIR);
197         if (!dir)
198                 return NULL;
199
200         result = g_string_new(NULL);
201
202         while ((d = readdir(dir))) {
203                 if (strcmp(d->d_name, ".") == 0 ||
204                                 strcmp(d->d_name, "..") == 0 ||
205                                 strncmp(d->d_name, "provider_", 9) == 0)
206                         continue;
207
208                 switch (d->d_type) {
209                 case DT_DIR:
210                 case DT_UNKNOWN:
211                         /*
212                          * If the settings file is not found, then
213                          * assume this directory is not a services dir.
214                          */
215                         str = g_strdup_printf("%s/%s/settings", STORAGEDIR,
216                                                                 d->d_name);
217                         ret = stat(str, &buf);
218                         g_free(str);
219                         if (ret < 0)
220                                 continue;
221
222                         g_string_append_printf(result, "%s/", d->d_name);
223                         break;
224                 }
225         }
226
227         closedir(dir);
228
229         str = g_string_free(result, FALSE);
230         if (str && str[0] != '\0') {
231                 /*
232                  * Remove the trailing separator so that services doesn't end up
233                  * with an empty element.
234                  */
235                 str[strlen(str) - 1] = '\0';
236                 services = g_strsplit(str, "/", -1);
237         }
238         g_free(str);
239
240         return services;
241 }
242
243 GKeyFile *connman_storage_load_service(const char *service_id)
244 {
245         gchar *pathname;
246         GKeyFile *keyfile = NULL;
247
248         pathname = g_strdup_printf("%s/%s/%s", STORAGEDIR, service_id, SETTINGS);
249         if (!pathname)
250                 return NULL;
251
252         keyfile =  storage_load(pathname);
253         g_free(pathname);
254
255         return keyfile;
256 }
257
258 int __connman_storage_save_service(GKeyFile *keyfile, const char *service_id)
259 {
260         int ret = 0;
261         gchar *pathname, *dirname;
262
263         dirname = g_strdup_printf("%s/%s", STORAGEDIR, service_id);
264         if (!dirname)
265                 return -ENOMEM;
266
267         /* If the dir doesn't exist, create it */
268         if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) {
269                 if (mkdir(dirname, MODE) < 0) {
270                         if (errno != EEXIST) {
271                                 g_free(dirname);
272                                 return -errno;
273                         }
274                 }
275         }
276
277         pathname = g_strdup_printf("%s/%s", dirname, SETTINGS);
278
279         g_free(dirname);
280
281         ret = storage_save(keyfile, pathname);
282
283         g_free(pathname);
284
285         return ret;
286 }
287
288 static bool remove_file(const char *service_id, const char *file)
289 {
290         gchar *pathname;
291         bool ret = false;
292
293         pathname = g_strdup_printf("%s/%s/%s", STORAGEDIR, service_id, file);
294         if (!pathname)
295                 return false;
296
297         if (!g_file_test(pathname, G_FILE_TEST_EXISTS)) {
298                 ret = true;
299         } else if (g_file_test(pathname, G_FILE_TEST_IS_REGULAR)) {
300                 unlink(pathname);
301                 ret = true;
302         }
303
304         g_free(pathname);
305         return ret;
306 }
307
308 static bool remove_dir(const char *service_id)
309 {
310         gchar *pathname;
311         bool ret = false;
312
313         pathname = g_strdup_printf("%s/%s", STORAGEDIR, service_id);
314         if (!pathname)
315                 return false;
316
317         if (!g_file_test(pathname, G_FILE_TEST_EXISTS)) {
318                 ret = true;
319         } else if (g_file_test(pathname, G_FILE_TEST_IS_DIR)) {
320                 rmdir(pathname);
321                 ret = true;
322         }
323
324         g_free(pathname);
325         return ret;
326 }
327
328 bool __connman_storage_remove_service(const char *service_id)
329 {
330         bool removed;
331
332         /* Remove service configuration file */
333         removed = remove_file(service_id, SETTINGS);
334         if (!removed)
335                 return false;
336
337         /* Remove the statistics file also */
338         removed = remove_file(service_id, "data");
339         if (!removed)
340                 return false;
341
342         removed = remove_dir(service_id);
343         if (!removed)
344                 return false;
345
346         DBG("Removed service dir %s/%s", STORAGEDIR, service_id);
347
348         return true;
349 }
350
351 GKeyFile *__connman_storage_load_provider(const char *identifier)
352 {
353         gchar *pathname;
354         GKeyFile *keyfile;
355
356         pathname = g_strdup_printf("%s/%s_%s/%s", STORAGEDIR, "provider",
357                         identifier, SETTINGS);
358         if (!pathname)
359                 return NULL;
360
361         keyfile = storage_load(pathname);
362         g_free(pathname);
363
364         return keyfile;
365 }
366
367 void __connman_storage_save_provider(GKeyFile *keyfile, const char *identifier)
368 {
369         gchar *pathname, *dirname;
370
371         dirname = g_strdup_printf("%s/%s_%s", STORAGEDIR,
372                         "provider", identifier);
373         if (!dirname)
374                 return;
375
376         if (!g_file_test(dirname, G_FILE_TEST_IS_DIR) &&
377                         mkdir(dirname, MODE) < 0) {
378                 g_free(dirname);
379                 return;
380         }
381
382         pathname = g_strdup_printf("%s/%s", dirname, SETTINGS);
383         g_free(dirname);
384
385         storage_save(keyfile, pathname);
386         g_free(pathname);
387 }
388
389 static bool remove_all(const char *id)
390 {
391         bool removed;
392
393         remove_file(id, SETTINGS);
394         remove_file(id, "data");
395
396         removed = remove_dir(id);
397         if (!removed)
398                 return false;
399
400         return true;
401 }
402
403 bool __connman_storage_remove_provider(const char *identifier)
404 {
405         bool removed;
406         gchar *id;
407
408         id = g_strdup_printf("%s_%s", "provider", identifier);
409         if (!id)
410                 return false;
411
412         if (remove_all(id))
413                 DBG("Removed provider dir %s/%s", STORAGEDIR, id);
414
415         g_free(id);
416
417         id = g_strdup_printf("%s_%s", "vpn", identifier);
418         if (!id)
419                 return false;
420
421         if ((removed = remove_all(id)))
422                 DBG("Removed vpn dir %s/%s", STORAGEDIR, id);
423
424         g_free(id);
425
426         return removed;
427 }
428
429 gchar **__connman_storage_get_providers(void)
430 {
431         GSList *list = NULL;
432         int num = 0, i = 0;
433         struct dirent *d;
434         gchar *str;
435         DIR *dir;
436         struct stat buf;
437         int ret;
438         char **providers;
439         GSList *iter;
440
441         dir = opendir(STORAGEDIR);
442         if (!dir)
443                 return NULL;
444
445         while ((d = readdir(dir))) {
446                 if (strcmp(d->d_name, ".") == 0 ||
447                                 strcmp(d->d_name, "..") == 0 ||
448                                 strncmp(d->d_name, "provider_", 9) != 0)
449                         continue;
450
451                 if (d->d_type == DT_DIR) {
452                         str = g_strdup_printf("%s/%s/settings", STORAGEDIR,
453                                         d->d_name);
454                         ret = stat(str, &buf);
455                         g_free(str);
456                         if (ret < 0)
457                                 continue;
458                         list = g_slist_prepend(list, g_strdup(d->d_name));
459                         num += 1;
460                 }
461         }
462
463         closedir(dir);
464
465         providers = g_try_new0(char *, num + 1);
466         for (iter = list; iter; iter = g_slist_next(iter)) {
467                 if (providers)
468                         providers[i] = iter->data;
469                 else
470                         g_free(iter->data);
471                 i += 1;
472         }
473         g_slist_free(list);
474
475         return providers;
476 }