Add systemd state checking logic
[platform/core/system/storaged.git] / src / storage / storage.c
1 /*
2  * storaged
3  *
4  * Copyright (c) 2012 - 2017 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <stdarg.h>
23 #include <fcntl.h>
24 #include <assert.h>
25 #include <limits.h>
26 #include <vconf.h>
27 #include <sys/types.h>
28 #include <sys/statvfs.h>
29 #include <sys/stat.h>
30 #include <sys/shm.h>
31 #include <time.h>
32 #include <storage.h>
33 #include <tzplatform_config.h>
34 #include <glib.h>
35 #include <libsyscommon/dbus-system.h>
36 #include <libsyscommon/systemd-state.h>
37
38 #include "log.h"
39 #include "config-parser.h"
40 #include "module-intf.h"
41 #include "storaged_common.h"
42
43 #define MEMORY_STATUS_TMP_PATH  "/tmp"
44 #define MEMORY_STATUS_OPT_PATH  "/opt"
45 #define MEMNOTI_TMP_CRITICAL_VALUE (20)
46
47 #define MEMORY_MEGABYTE_VALUE   1048576
48
49 #define MEMNOTI_WARNING_VALUE  (5) /* 5% under */
50 #define MEMNOTI_CRITICAL_VALUE (0.1) /* 0.1% under */
51 #define MEMNOTI_FULL_VALUE     (0.0) /* 0.0% under */
52
53 #define SIGNAL_NEED_CLEANUP     "NeedCleanup"
54 #define MEMNOTI_TIMER_INTERVAL  5000 /* milliseconds */
55
56 #define SIGNAL_POWEROFF_STATE   "ChangeState"
57
58 #define STORAGE_CONF_FILE       "/etc/storaged/storage.conf"
59
60 #define NEED_CLEANUP_DIR_PATH   "/run/storaged/needcleanup"
61 #define NEED_CLEANUP_FILE_PATH  "/run/storaged/needcleanup/trigger"
62
63 #define ARRAY_SIZE(name) (sizeof(name)/sizeof(name[0]))
64
65 #define LOW_STORAGE_WARNING                     "lowstorage_warning"
66 #define LOW_STORAGE_CRITICAL                    "lowstorage_critical"
67 #define LOW_STORAGE_FULL                        "lowstorage_full"
68 #define LOW_STORAGE_REMOVE                      "lowstorage_remove"
69
70 #define INTERNAL_STORAGE_NOTION                 "InternalStorageNotiOn"
71 #define INTERNAL_STORAGE_NOTIOFF                "InternalStorageNotiOff"
72
73 enum memnoti_level {
74         MEMNOTI_LEVEL_FULL = 0,
75         MEMNOTI_LEVEL_CRITICAL,
76         MEMNOTI_LEVEL_WARNING,
77         MEMNOTI_LEVEL_NORMAL,
78 };
79
80 enum memnoti_status {
81         MEMNOTI_DISABLE,
82         MEMNOTI_ENABLE,
83 };
84
85 enum memory_id {
86         MEMORY_INTERNAL = 0,
87         MEMORY_TMP,
88         MEMORY_OPT,
89 };
90
91 struct storage_config_info {
92         enum memory_id mem_id;
93         enum memnoti_level current_noti_level;
94         double warning_level;
95         double critical_level;
96         double full_level;
97 };
98
99 static guint memnoti_timer;
100 static int noti_id;
101
102 static guint id_booting_done;
103 static guint id_storage_poweroff;
104
105 static struct storage_config_info storage_internal_info = {
106         .mem_id             = MEMORY_INTERNAL,
107         .current_noti_level = MEMNOTI_LEVEL_NORMAL,
108         .warning_level      = MEMNOTI_WARNING_VALUE,
109         .critical_level     = MEMNOTI_CRITICAL_VALUE,
110         .full_level         = MEMNOTI_FULL_VALUE,
111 };
112
113 static struct storage_config_info storage_tmp_info = {
114         .mem_id             = MEMORY_TMP,
115         .current_noti_level = MEMNOTI_LEVEL_NORMAL,
116         .warning_level      = MEMNOTI_TMP_CRITICAL_VALUE,
117         .critical_level     = MEMNOTI_TMP_CRITICAL_VALUE,
118         .full_level         = MEMNOTI_FULL_VALUE,
119 };
120
121 static struct storage_config_info storage_opt_info = {
122         .mem_id             = MEMORY_OPT,
123         .current_noti_level = MEMNOTI_LEVEL_NORMAL,
124         .warning_level      = MEMNOTI_WARNING_VALUE,
125         .critical_level     = MEMNOTI_CRITICAL_VALUE,
126         .full_level         = MEMNOTI_FULL_VALUE,
127 };
128
129 static void write_file()
130 {
131         FILE *fp;
132
133         fp = fopen(NEED_CLEANUP_FILE_PATH, "w+");
134         if (fp) {
135                 fprintf(fp, "needcleanup\n");
136                 fclose(fp);
137         } else
138                 _E("Failed to open '%s'.", NEED_CLEANUP_FILE_PATH);
139 }
140
141 static void memcleanup_send_broadcast(struct storage_config_info *info, enum memnoti_level level, enum memnoti_level prev_level)
142 {
143         time_t t;
144         struct tm timeinfo;
145         enum tzplatform_variable path;
146         char *value;
147         char buf[20];
148
149         if (info->mem_id == MEMORY_INTERNAL)
150                 path = TZ_SYS_USER;
151         else if (info->mem_id == MEMORY_TMP)
152                 path = TZ_SYS_TMP;
153         else if (info->mem_id == MEMORY_OPT)
154                 path = TZ_SYS_OPT;
155         else
156                 return;
157
158         if (prev_level <= level)
159                 return;
160
161         if (level == MEMNOTI_LEVEL_WARNING)
162                 value = "Warning";
163         else if (level == MEMNOTI_LEVEL_CRITICAL)
164                 value = "Critical";
165         else if (level == MEMNOTI_LEVEL_FULL)
166                 value = "Full";
167         else
168                 return;
169
170         write_file();
171
172         t = time(NULL);
173         if (localtime_r(&t, &timeinfo) == NULL) {
174                 _E("Failed to localtime_r.");
175                 goto out;
176         }
177
178         strftime(buf, sizeof(buf), "%b %d %T", &timeinfo);
179         _D("time=%s path=%d level=%s", buf, path, value);
180
181 out:
182         dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_LOWMEM, STORAGED_INTERFACE_LOWMEM,
183                         SIGNAL_NEED_CLEANUP, g_variant_new("(is)", path, value));
184
185 }
186
187 static void _popup_cb(GVariant *var, void *user_data, GError *err)
188 {
189          int ret;
190
191         if (!var) {
192                 _E("No message: %s", err->message);
193                 return;
194         }
195
196         if (!dh_get_param_from_var(var, "(i)", &ret)) {
197                 _E("No message: %s", g_variant_get_type_string(var));
198                 goto out;
199         }
200
201         _D("Reply value: %d", ret);
202
203 out:
204         g_variant_unref(var);
205 }
206
207 static int launch_memory_popup(int num, ...)
208 {
209         int ret;
210         va_list args;
211
212         va_start(args, num);
213
214         ret = dbus_handle_method_async_pairs_with_reply(POPUP_BUS_NAME,
215                         POPUP_PATH_SYSTEM,
216                         POPUP_INTERFACE_SYSTEM,
217                         "PopupLaunch",
218                         num,
219                         args,
220                         _popup_cb,
221                         -1,
222                         NULL);
223
224         va_end(args);
225
226         return ret;
227 }
228
229 static void _noti_cb(GVariant *var, void *user_data, GError *err)
230 {
231          int ret;
232
233         if (!var) {
234                 _E("No message: %s", err->message);
235                 return;
236         }
237
238         if (!dh_get_param_from_var(var, "(i)", &ret)) {
239                 _E("No message: %s", g_variant_get_type_string(var));
240                 goto out;
241         }
242
243         noti_id = ret;
244         _D("Reply value: %d", ret);
245
246 out:
247         g_variant_unref(var);
248 }
249
250 static int remove_notification(void)
251 {
252         const char *param[1];
253         char id_str[16];
254         int ret;
255
256         snprintf(id_str, sizeof(id_str), "%d", noti_id);
257         param[0] = id_str;
258
259         ret = dbus_handle_method_sync(POPUP_BUS_NAME,
260                 POPUP_PATH_NOTI,
261                 POPUP_INTERFACE_NOTI,
262                 INTERNAL_STORAGE_NOTIOFF,
263                 "i",
264                 param);
265         if (ret < 0)
266                 _E("Failed to remove noti(%d).", noti_id);
267
268         return ret;
269 }
270
271 static int create_notification(void)
272 {
273         int ret;
274
275         ret = dbus_handle_method_async_with_reply(POPUP_BUS_NAME,
276                 POPUP_PATH_NOTI,
277                 POPUP_INTERFACE_NOTI,
278                 INTERNAL_STORAGE_NOTION,
279                 NULL,
280                 NULL,
281                 _noti_cb,
282                 -1,
283                 NULL);
284         if (ret < 0)
285                 _E("Failed to create noti.");
286
287         return ret;
288 }
289
290 static int launch_memory_notification(char *type)
291 {
292         int ret = -1;
293
294         if (!type)
295                 return -EINVAL;
296
297         if (!strncmp(type, INTERNAL_STORAGE_NOTION, sizeof(INTERNAL_STORAGE_NOTION))) {
298                 if (noti_id) {
299                         ret = remove_notification();
300                         if (ret < 0)
301                                 return ret;
302                         noti_id = 0;
303                 }
304
305                 ret = create_notification();
306         } else if (!strncmp(type, INTERNAL_STORAGE_NOTIOFF, sizeof(INTERNAL_STORAGE_NOTIOFF))) {
307                 if (!noti_id)
308                         return -1;
309
310                 ret = remove_notification();
311         } else
312                 _E("Invalid noti type(%s).", type);
313
314         return ret;
315 }
316
317 static int process_memory_info(enum memnoti_level level)
318 {
319         int ret = -1;
320         int val = -1;
321         char *popup_value = NULL;
322         char *noti_value = NULL;
323
324         if (level < 0 || level > MEMNOTI_LEVEL_NORMAL) {
325                 _E("Failed to check level(%d).", level);
326                 return 0;
327         }
328
329         if (level == MEMNOTI_LEVEL_WARNING) {
330                 popup_value = LOW_STORAGE_WARNING;
331                 noti_value = INTERNAL_STORAGE_NOTION;
332         } else if (level == MEMNOTI_LEVEL_CRITICAL) {
333                 popup_value = LOW_STORAGE_CRITICAL;
334                 noti_value = INTERNAL_STORAGE_NOTION;
335         } else if (level == MEMNOTI_LEVEL_FULL) {
336                 popup_value = LOW_STORAGE_FULL;
337                 noti_value = INTERNAL_STORAGE_NOTION;
338         } else if (level == MEMNOTI_LEVEL_NORMAL) {
339                 popup_value = LOW_STORAGE_REMOVE;
340                 noti_value = INTERNAL_STORAGE_NOTIOFF;
341         }
342
343         ret = vconf_get_int(VCONFKEY_STARTER_SEQUENCE, &val);
344         if (val == 0 || ret != 0)
345                 return -1;
346
347         if (!popup_value && !noti_value) {
348                 _E("Invalid memnoti level(%d).", level);
349                 return 0;
350         }
351
352         ret = launch_memory_popup(2, "_SYSPOPUP_CONTENT_", popup_value);
353         if (ret < 0)
354                 _E("Failed to launch momory popup: %d", ret);
355
356         ret = launch_memory_notification(noti_value);
357         if (ret < 0)
358                 _E("Failed to launch momory notification: %d", ret);
359
360         return ret;
361 }
362
363 static void storage_status_broadcast(struct storage_config_info *info, double total, double avail)
364 {
365         double level = (avail/total)*100;
366         enum memnoti_level prev_noti_level;
367
368         prev_noti_level = info->current_noti_level;
369         if (level <= info->full_level) {
370                 if (info->current_noti_level == MEMNOTI_LEVEL_FULL)
371                         return;
372                 info->current_noti_level = MEMNOTI_LEVEL_FULL;
373
374                 memcleanup_send_broadcast(info, info->current_noti_level, prev_noti_level);
375
376                 _I("Id=%d current level=%4.4lf warning=%4.4lf critical=%4.4lf full=%4.4lf",
377                         info->mem_id, level, info->warning_level, info->critical_level, info->full_level);
378                 return;
379         }
380
381         if (level <= info->critical_level) {
382                 if (info->current_noti_level == MEMNOTI_LEVEL_CRITICAL)
383                         return;
384                 info->current_noti_level = MEMNOTI_LEVEL_CRITICAL;
385
386                 memcleanup_send_broadcast(info, info->current_noti_level, prev_noti_level);
387
388                 _I("Id=%d current level=%4.4lf warning=%4.4lf critical=%4.4lf full=:%4.4lf",
389                         info->mem_id, level, info->warning_level, info->critical_level, info->full_level);
390                 return;
391         }
392
393         if (level <= info->warning_level) {
394                 info->current_noti_level = MEMNOTI_LEVEL_WARNING;
395                 _I("Id=%d current level=%4.4lf warning=%4.4lf critical=%4.4lf full=%4.4lf",
396                         info->mem_id, level, info->warning_level, info->critical_level, info->full_level);
397
398                 memcleanup_send_broadcast(info, info->current_noti_level, prev_noti_level);
399         } else
400                 info->current_noti_level = MEMNOTI_LEVEL_NORMAL;
401 }
402
403 static int storage_get_memory_size(const char *path, struct statvfs *s)
404 {
405         int ret;
406
407         if (!path) {
408                 _E("Input param error.");
409                 return -EINVAL;
410         }
411
412         ret = statvfs(path, s);
413         if (ret) {
414                 _E("Failed to get storage size.");
415                 return -errno;
416         }
417
418         return 0;
419 }
420
421 static void get_storage_status(const char *path, struct statvfs *s)
422 {
423         if (strcmp(path, tzplatform_getenv(TZ_SYS_USER)) == 0)
424                 storage_get_internal_memory_size(s);
425         else
426                 storage_get_memory_size(path, s);
427 }
428
429 static void init_storage_config_info(const char *path, struct storage_config_info *info)
430 {
431         struct statvfs s;
432         double dAvail = 0.0;
433         double dTotal = 0.0;
434
435         get_storage_status(path, &s);
436
437         dTotal = (double)s.f_frsize * s.f_blocks;
438         dAvail = (double)s.f_bsize * s.f_bavail;
439
440         info->full_level += (MEMORY_MEGABYTE_VALUE/dTotal)*100;
441
442         _I("'%s' t=%4.0lf a=%4.0lf(%4.2lf) w=%4.4lf c=%4.4lf f=%4.4lf",
443                 path, dTotal, dAvail, (dAvail*100/dTotal), info->warning_level, info->critical_level, info->full_level);
444 }
445
446 static void check_internal_storage(struct storage_config_info *info)
447 {
448         static enum memnoti_level old = MEMNOTI_LEVEL_NORMAL;
449         int ret;
450
451         if (info->current_noti_level < MEMNOTI_LEVEL_NORMAL && info->current_noti_level < old) {
452                 ret = process_memory_info(info->current_noti_level);
453                 if (ret != 0)
454                         info->current_noti_level = MEMNOTI_LEVEL_NORMAL;
455         }
456
457         if (info->current_noti_level == MEMNOTI_LEVEL_NORMAL && info->current_noti_level > old) {
458                 ret = process_memory_info(info->current_noti_level);
459                 if (ret != 0)
460                         info->current_noti_level = MEMNOTI_LEVEL_NORMAL;
461         }
462         old = info->current_noti_level;
463 }
464
465 static gboolean check_storage_status(gpointer data)
466 {
467         struct statvfs s;
468         double dAvail = 0.0;
469         double dTotal = 0.0;
470
471         /* check internal */
472         storage_get_internal_memory_size(&s);
473         dTotal = (double)s.f_frsize * s.f_blocks;
474         dAvail = (double)s.f_bsize * s.f_bavail;
475         storage_status_broadcast(&storage_internal_info, dTotal, dAvail);
476         check_internal_storage(&storage_internal_info);
477         /* check tmp */
478         storage_get_memory_size(MEMORY_STATUS_TMP_PATH, &s);
479         dTotal = (double)s.f_frsize * s.f_blocks;
480         dAvail = (double)s.f_bsize * s.f_bavail;
481         storage_status_broadcast(&storage_tmp_info, dTotal, dAvail);
482         /* check opt */
483         storage_get_memory_size(MEMORY_STATUS_OPT_PATH, &s);
484         dTotal = (double)s.f_frsize * s.f_blocks;
485         dAvail = (double)s.f_bsize * s.f_bavail;
486         storage_status_broadcast(&storage_opt_info, dTotal, dAvail);
487
488         if (memnoti_timer) {
489                 g_source_remove(memnoti_timer);
490                 memnoti_timer = g_timeout_add(MEMNOTI_TIMER_INTERVAL,
491                                 check_storage_status, NULL);
492         }
493
494         return G_SOURCE_REMOVE;
495 }
496
497 static int init_storage_config_info_all(void)
498 {
499         init_storage_config_info(tzplatform_getenv(TZ_SYS_USER), &storage_internal_info);
500         init_storage_config_info(MEMORY_STATUS_TMP_PATH, &storage_tmp_info);
501         init_storage_config_info(MEMORY_STATUS_OPT_PATH, &storage_opt_info);
502         memnoti_timer = g_timeout_add(MEMNOTI_TIMER_INTERVAL,
503                                 check_storage_status, NULL);
504         if (memnoti_timer == 0)
505                 _E("Failed mem available noti timer add.");
506         return 0;
507 }
508
509 static GVariant *dbus_getstatus(GDBusConnection *conn,
510                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
511                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
512 {
513         struct statvfs s;
514         unsigned long long dAvail = 0.0;
515         unsigned long long dTotal = 0.0;
516
517         storage_get_internal_memory_size(&s);
518         dTotal = (unsigned long long)s.f_frsize * s.f_blocks;
519         dAvail = (unsigned long long)s.f_bsize * s.f_bavail;
520
521         return g_variant_new("(tt)", dTotal, dAvail);
522 }
523
524 static GVariant *dbus_get_storage_status(GDBusConnection *conn,
525                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
526                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
527 {
528         const char *temp;
529         char *str_path;
530         struct statvfs s;
531         struct stat buf;
532         pid_t pid;
533         unsigned long long dAvail = 0.0;
534         unsigned long long dTotal = 0.0;
535         int ret;
536         bool success = true;
537
538         g_variant_get(param, "(s)", &str_path);
539
540         temp = tzplatform_getenv(TZ_SYS_USER);
541         if (!strncmp(str_path, temp, strlen(temp))) {
542                 ret = stat(str_path, &buf);
543                 if (ret == 0) {
544                         ret = storage_get_internal_memory_size(&s);
545                         if (ret < 0)
546                                 success = false;
547                 } else
548                         success = false;
549         } else {
550                 ret = storage_get_memory_size(str_path, &s);
551                 if (ret < 0)
552                         success = false;
553         }
554
555         if (success) {
556                 dTotal = (unsigned long long)s.f_frsize * s.f_blocks;
557                 dAvail = (unsigned long long)s.f_bsize * s.f_bavail;
558         }
559
560         pid = dbus_handle_get_sender_pid(NULL, sender);
561
562         _D("PID=%d path='%s' total=%4.0llu avail=%4.0llu", pid, str_path, dTotal, dAvail);
563
564         g_free(str_path);
565         return g_variant_new("(tt)", dTotal, dAvail);
566 }
567
568 static GVariant *dbus_getstatvfs(GDBusConnection *conn,
569                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
570                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
571 {
572         char *str_path;
573         pid_t pid;
574         struct statvfs s;
575
576         g_variant_get(param, "(s)", &str_path);
577
578         storage_get_memory_size(str_path, &s);
579
580         pid = dbus_handle_get_sender_pid(NULL, sender);
581
582         _D("PID=%d path='%s'", pid, str_path);
583
584         g_free(str_path);
585
586         return g_variant_new("(ttttttttttt)", (guint64)(s.f_bsize), (guint64)(s.f_frsize),
587                         (guint64)(s.f_blocks), (guint64)(s.f_bfree), (guint64)(s.f_bavail),
588                         (guint64)(s.f_files), (guint64)(s.f_ffree), (guint64)(s.f_favail),
589                         (guint64)(s.f_fsid), (guint64)(s.f_flag), (guint64)(s.f_namemax));
590
591 }
592
593 static GVariant *dbus_get_storage_level(GDBusConnection *conn,
594                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
595                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
596 {
597         int path_id;
598         enum memnoti_level level;
599         char *value;
600
601         g_variant_get(param, "(i)", &path_id);
602
603         if (path_id == TZ_SYS_USER)
604                 level = storage_internal_info.current_noti_level;
605         else if (path_id == TZ_SYS_OPT)
606                 level = storage_opt_info.current_noti_level;
607         else if (path_id == TZ_SYS_TMP)
608                 level = storage_tmp_info.current_noti_level;
609         else
610                 level = -1;
611
612         if (level == MEMNOTI_LEVEL_WARNING)
613                 value = "Warning";
614         else if (level == MEMNOTI_LEVEL_CRITICAL)
615                 value = "Critical";
616         else if (level == MEMNOTI_LEVEL_FULL)
617                 value = "Full";
618         else if (level == MEMNOTI_LEVEL_NORMAL)
619                 value = "Normal";
620         else
621                 value = "Not supported path";
622
623         return g_variant_new("(s)", value);
624 }
625
626 static const dbus_method_s storage_methods[] = {
627         { "getstorage",     NULL,          "tt", dbus_getstatus },
628         { "GetStatus",       "s",          "tt", dbus_get_storage_status },
629         { "GetStatvfs",      "s", "ttttttttttt", dbus_getstatvfs },
630         { "GetStorageLevel", "i",           "s", dbus_get_storage_level },
631         /* Add methods here */
632 };
633
634 static dbus_interface_u storage_interface = {
635         .name = STORAGED_INTERFACE_STORAGE,
636         .methods = storage_methods,
637         .nr_methods = ARRAY_SIZE(storage_methods),
638 };
639
640 static void booting_done(void)
641 {
642         static int done;
643
644         if (done > 0)
645                 return;
646         done = 1;
647         _I("Booting done.");
648
649         if (init_storage_config_info_all() == -1)
650                 _E("Failed to remain mem noti control fd init.");
651 }
652
653 static void booting_done_received(GDBusConnection  *conn,
654                 const gchar *sender,
655                 const gchar *path,
656                 const gchar *iface,
657                 const gchar *name,
658                 GVariant *param,
659                 gpointer data)
660 {
661         _I("Signal received: %s", SYSTEMD_DBUS_SIGNAL_SYSTEM_STARTUP_FINISHED);
662         booting_done();
663 }
664
665 static void storage_poweroff(GDBusConnection  *conn,
666                 const gchar *sender,
667                 const gchar *path,
668                 const gchar *iface,
669                 const gchar *name,
670                 GVariant *param,
671                 gpointer data)
672 {
673         if (memnoti_timer) {
674                 g_source_remove(memnoti_timer);
675                 memnoti_timer = 0;
676         }
677 }
678
679 static int load_config(struct parse_result *result, void *user_data)
680 {
681         struct storage_config_info *info = (struct storage_config_info *)user_data;
682         char *name;
683         char *value;
684
685         if (!info)
686                 return -EINVAL;
687
688         if (!MATCH(result->section, "LOWSTORAGE"))
689                 return -EINVAL;
690
691         _D("%s,%s,%s", result->section, result->name, result->value);
692
693         name = result->name;
694         value = result->value;
695
696         if (MATCH(name, "WARNING_LEVEL"))
697                 info->warning_level = (double)atof(value);
698         else if (MATCH(name, "CRITICAL_LEVEL"))
699                 info->critical_level = (double)atof(value);
700         else if (MATCH(name, "FULL_LEVEL"))
701                 info->full_level = (double)atof(value);
702
703         return 0;
704 }
705
706 static void storage_config_load(struct storage_config_info *info)
707 {
708         int ret;
709
710         ret = config_parse(STORAGE_CONF_FILE, load_config, info);
711         if (ret < 0)
712                 _E("Failed to load %s, %d Use default value.", STORAGE_CONF_FILE, ret);
713 }
714
715 static void storage_init(void *data)
716 {
717         int ret;
718
719         storage_config_load(&storage_internal_info);
720
721         ret = dbus_handle_register_dbus_object(NULL, STORAGED_PATH_STORAGE,
722                         &storage_interface);
723         if (ret < 0)
724                 _E("Failed to register dbus interface and methods: %d", ret);
725
726         ret = remove_directory(NEED_CLEANUP_DIR_PATH);
727         if (ret < 0)
728                 _E("Failed to remove directory.");
729         ret = mkdir(NEED_CLEANUP_DIR_PATH, 0644);
730         if (ret < 0)
731                 _E("Failed to make directory: %d", errno);
732
733         if (check_system_boot_finished() != 0) {
734                 _I("System session is already loaded.");
735                 id_booting_done = 0;
736                 booting_done();
737         } else {
738                 /* System Session is loaded completely */
739                 id_booting_done = subscribe_dbus_signal(NULL, SYSTEMD_DBUS_PATH,
740                                 SYSTEMD_DBUS_IFACE_MANAGER,
741                                 SYSTEMD_DBUS_SIGNAL_SYSTEM_STARTUP_FINISHED,
742                                 booting_done_received, NULL, NULL);
743         }
744
745         id_storage_poweroff = subscribe_dbus_signal(NULL, DEVICED_PATH_POWEROFF,
746                         DEVICED_INTERFACE_POWEROFF,
747                         SIGNAL_POWEROFF_STATE,
748                         storage_poweroff, NULL, NULL);
749 }
750
751 static void storage_exit(void *data)
752 {
753         /* unregister notifier for below each event */
754         unsubscribe_dbus_signal(NULL, id_booting_done);
755         unsubscribe_dbus_signal(NULL, id_storage_poweroff);
756 }
757
758 static storaged_module_interface storage_module = {
759         .name = "storage",
760         .init = storage_init,
761         .exit = storage_exit,
762 };
763
764 __attribute__ ((visibility("default")))storaged_module_interface *
765 storaged_get_module_interface(void)
766 {
767         return &storage_module;
768 }