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