4 * Copyright (c) 2012 - 2017 Samsung Electronics Co., Ltd.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
27 #include <sys/types.h>
28 #include <sys/statvfs.h>
33 #include <tzplatform_config.h>
35 #include <libsyscommon/libgdbus.h>
36 #include <libsyscommon/ini-parser.h>
37 #include <device/board-internal.h>
41 #include "module-intf.h"
42 #include "storaged_common.h"
46 #define MEMORY_STATUS_TMP_PATH "/tmp"
47 #define MEMORY_STATUS_OPT_PATH "/opt"
48 #define MEMNOTI_TMP_CRITICAL_VALUE (20)
50 #define MEMORY_MEGABYTE_VALUE 1048576
52 #define MEMNOTI_WARNING_VALUE (5) /* 5% under */
53 #define MEMNOTI_CRITICAL_VALUE (0.1) /* 0.1% under */
54 #define MEMNOTI_FULL_VALUE (0.0) /* 0.0% under */
56 #define SIGNAL_NEED_CLEANUP "NeedCleanup"
57 #define MEMNOTI_TIMER_INTERVAL 5000 /* milliseconds */
59 #define SIGNAL_POWEROFF_STATE "ChangeState"
61 #define STORAGE_CONF_FILE "/etc/storaged/storage.conf"
63 #define NEED_CLEANUP_DIR_PATH "/run/storaged/needcleanup"
64 #define NEED_CLEANUP_FILE_PATH "/run/storaged/needcleanup/trigger"
66 #define DM_ROOT_NODE_NAME "rootfs"
68 #define ARRAY_SIZE(name) (sizeof(name)/sizeof(name[0]))
70 #define LOW_STORAGE_WARNING "lowstorage_warning"
71 #define LOW_STORAGE_CRITICAL "lowstorage_critical"
72 #define LOW_STORAGE_FULL "lowstorage_full"
73 #define LOW_STORAGE_REMOVE "lowstorage_remove"
75 #define INTERNAL_STORAGE_NOTION "InternalStorageNotiOn"
76 #define INTERNAL_STORAGE_NOTIOFF "InternalStorageNotiOff"
78 #define RECOVERY_ACTION_IGNORE_STR "ignore"
79 #define RECOVERY_ACTION_REBOOT_RECOVERY_STR "reboot,recovery"
80 #define ROOTFS_DMVERITY_CORRUPTED_COUNT_DEFUALT (1)
81 #define ROOTFS_DMVERITY_CORRUPTED_TIMEOUT_DEFUALT (0)
83 #define PARTITION_STATUS_OK "ok"
84 #define PARTITION_STATUS_BUFFER_LEN 16
87 MEMNOTI_LEVEL_FULL = 0,
88 MEMNOTI_LEVEL_CRITICAL,
89 MEMNOTI_LEVEL_WARNING,
104 struct storage_config_info {
105 enum memory_id mem_id;
106 enum memnoti_level current_noti_level;
107 double warning_level;
108 double critical_level;
112 enum recovery_action {
113 RECOVERY_ACTION_IGNORE = 0,
114 RECOVERY_ACTION_REBOOT_RECOVERY,
117 struct storage_config_rootfs_recovery {
118 enum recovery_action action;
119 int dm_verity_corrupted_count;
120 int dm_verity_corrupted_timeout;
123 static guint memnoti_timer;
126 static guint id_storage_poweroff;
128 static struct storage_config_info storage_internal_info = {
129 .mem_id = MEMORY_INTERNAL,
130 .current_noti_level = MEMNOTI_LEVEL_NORMAL,
131 .warning_level = MEMNOTI_WARNING_VALUE,
132 .critical_level = MEMNOTI_CRITICAL_VALUE,
133 .full_level = MEMNOTI_FULL_VALUE,
136 static struct storage_config_info storage_tmp_info = {
137 .mem_id = MEMORY_TMP,
138 .current_noti_level = MEMNOTI_LEVEL_NORMAL,
139 .warning_level = MEMNOTI_TMP_CRITICAL_VALUE,
140 .critical_level = MEMNOTI_TMP_CRITICAL_VALUE,
141 .full_level = MEMNOTI_FULL_VALUE,
144 static struct storage_config_info storage_opt_info = {
145 .mem_id = MEMORY_OPT,
146 .current_noti_level = MEMNOTI_LEVEL_NORMAL,
147 .warning_level = MEMNOTI_WARNING_VALUE,
148 .critical_level = MEMNOTI_CRITICAL_VALUE,
149 .full_level = MEMNOTI_FULL_VALUE,
152 static char *recovery_action_str[] = {
153 [RECOVERY_ACTION_IGNORE] = RECOVERY_ACTION_IGNORE_STR,
154 [RECOVERY_ACTION_REBOOT_RECOVERY] = RECOVERY_ACTION_REBOOT_RECOVERY_STR,
156 static struct storage_config_rootfs_recovery storage_rootfs_recovery_info = {
157 .action = RECOVERY_ACTION_IGNORE,
158 .dm_verity_corrupted_count = ROOTFS_DMVERITY_CORRUPTED_COUNT_DEFUALT,
159 .dm_verity_corrupted_timeout = ROOTFS_DMVERITY_CORRUPTED_TIMEOUT_DEFUALT,
161 static guint poweroff_g_timeout_event_source_id = 0;
163 static void dm_verity_uevent_block_handler(struct udev_device *dev);
164 static struct uevent_handler dm_verity_uh = {
165 .subsystem = BLOCK_SUBSYSTEM,
166 .uevent_func = dm_verity_uevent_block_handler,
169 static void write_file(void)
173 fp = fopen(NEED_CLEANUP_FILE_PATH, "w+");
175 fprintf(fp, "needcleanup\n");
178 _E("Failed to open '%s'.", NEED_CLEANUP_FILE_PATH);
181 static void memcleanup_send_broadcast(struct storage_config_info *info, enum memnoti_level level, enum memnoti_level prev_level)
185 enum tzplatform_variable path;
190 if (info->mem_id == MEMORY_INTERNAL)
192 else if (info->mem_id == MEMORY_TMP)
194 else if (info->mem_id == MEMORY_OPT)
199 if (prev_level <= level)
202 if (level == MEMNOTI_LEVEL_WARNING)
204 else if (level == MEMNOTI_LEVEL_CRITICAL)
206 else if (level == MEMNOTI_LEVEL_FULL)
214 if (localtime_r(&t, &timeinfo) == NULL) {
215 _E("Failed to localtime_r.");
219 strftime(buf, sizeof(buf), "%b %d %T", &timeinfo);
220 _D("time=%s path=%d level=%s", buf, path, value);
223 ret_dbus = gdbus_signal_emit(NULL,
224 STORAGED_PATH_LOWMEM,
225 STORAGED_INTERFACE_LOWMEM,
227 g_variant_new("(is)", path, value));
229 _E("Failed to send dbus signal");
231 cleanup_storage(path, level);
234 static void _popup_cb(GVariant *var, void *user_data, GError *err)
239 _E("No message: %s", err->message);
243 if (!g_variant_get_safe(var, "(i)", &ret_val)) {
244 _E("No message: %s", g_variant_get_type_string(var));
248 _D("Reply value: %d", ret_val);
251 g_variant_unref(var);
254 static int launch_memory_popup(int num, ...)
261 ret = gdbus_call_pairs_async_with_reply(POPUP_BUS_NAME,
263 POPUP_INTERFACE_SYSTEM,
276 static void _noti_cb(GVariant *var, void *user_data, GError *err)
281 _E("No message: %s", err->message);
285 if (!g_variant_get_safe(var, "(i)", &ret_val)) {
286 _E("No message: %s", g_variant_get_type_string(var));
291 _D("Reply value: %d", ret_val);
294 g_variant_unref(var);
297 static int remove_notification(void)
301 ret = gdbus_call_sync_with_reply_int(POPUP_BUS_NAME,
303 POPUP_INTERFACE_NOTI,
304 INTERNAL_STORAGE_NOTIOFF,
305 g_variant_new("(i)", noti_id),
308 _E("Failed to remove noti(%d).", noti_id);
313 static int create_notification(void)
317 ret = gdbus_call_async_with_reply(POPUP_BUS_NAME,
319 POPUP_INTERFACE_NOTI,
320 INTERNAL_STORAGE_NOTION,
326 _E("Failed to create noti.");
331 static int launch_memory_notification(char *type)
338 if (!strncmp(type, INTERNAL_STORAGE_NOTION, sizeof(INTERNAL_STORAGE_NOTION))) {
340 ret = remove_notification();
346 ret = create_notification();
347 } else if (!strncmp(type, INTERNAL_STORAGE_NOTIOFF, sizeof(INTERNAL_STORAGE_NOTIOFF))) {
351 ret = remove_notification();
353 _E("Invalid noti type(%s).", type);
358 static int process_memory_info(enum memnoti_level level)
362 char *popup_value = NULL;
363 char *noti_value = NULL;
365 if (level < 0 || level > MEMNOTI_LEVEL_NORMAL) {
366 _E("Failed to check level(%d).", level);
370 if (level == MEMNOTI_LEVEL_WARNING) {
371 popup_value = LOW_STORAGE_WARNING;
372 noti_value = INTERNAL_STORAGE_NOTION;
373 } else if (level == MEMNOTI_LEVEL_CRITICAL) {
374 popup_value = LOW_STORAGE_CRITICAL;
375 noti_value = INTERNAL_STORAGE_NOTION;
376 } else if (level == MEMNOTI_LEVEL_FULL) {
377 popup_value = LOW_STORAGE_FULL;
378 noti_value = INTERNAL_STORAGE_NOTION;
379 } else if (level == MEMNOTI_LEVEL_NORMAL) {
380 popup_value = LOW_STORAGE_REMOVE;
381 noti_value = INTERNAL_STORAGE_NOTIOFF;
384 ret = vconf_get_int(VCONFKEY_STARTER_SEQUENCE, &val);
385 if (val == 0 || ret != 0)
388 if (!popup_value && !noti_value) {
389 _E("Invalid memnoti level(%d).", level);
393 ret = launch_memory_popup(2, "_SYSPOPUP_CONTENT_", popup_value);
395 _E("Failed to launch momory popup: %d", ret);
397 ret = launch_memory_notification(noti_value);
399 _E("Failed to launch momory notification: %d", ret);
404 static void storage_status_broadcast(struct storage_config_info *info, double total, double avail)
406 double level = (avail/total)*100;
407 enum memnoti_level prev_noti_level;
409 prev_noti_level = info->current_noti_level;
410 if (level <= info->full_level) {
411 if (info->current_noti_level == MEMNOTI_LEVEL_FULL)
413 info->current_noti_level = MEMNOTI_LEVEL_FULL;
415 memcleanup_send_broadcast(info, info->current_noti_level, prev_noti_level);
417 _I("Id=%d current level=%4.4lf warning=%4.4lf critical=%4.4lf full=%4.4lf",
418 info->mem_id, level, info->warning_level, info->critical_level, info->full_level);
422 if (level <= info->critical_level) {
423 if (info->current_noti_level == MEMNOTI_LEVEL_CRITICAL)
425 info->current_noti_level = MEMNOTI_LEVEL_CRITICAL;
427 memcleanup_send_broadcast(info, info->current_noti_level, prev_noti_level);
429 _I("Id=%d current level=%4.4lf warning=%4.4lf critical=%4.4lf full=:%4.4lf",
430 info->mem_id, level, info->warning_level, info->critical_level, info->full_level);
434 if (level <= info->warning_level) {
435 info->current_noti_level = MEMNOTI_LEVEL_WARNING;
436 _I("Id=%d current level=%4.4lf warning=%4.4lf critical=%4.4lf full=%4.4lf",
437 info->mem_id, level, info->warning_level, info->critical_level, info->full_level);
439 memcleanup_send_broadcast(info, info->current_noti_level, prev_noti_level);
441 info->current_noti_level = MEMNOTI_LEVEL_NORMAL;
444 static int storage_get_memory_size(const char *path, struct statvfs *s)
449 _E("Input param error.");
453 ret_val = statvfs(path, s);
455 _E("Failed to get storage size.");
462 static void get_storage_status(const char *path, struct statvfs *s)
464 if (strcmp(path, tzplatform_getenv(TZ_SYS_USER)) == 0)
465 storage_get_internal_memory_size(s);
467 storage_get_memory_size(path, s);
470 static void init_storage_config_info(const char *path, struct storage_config_info *info)
476 get_storage_status(path, &s);
478 dTotal = (double)s.f_frsize * s.f_blocks;
479 dAvail = (double)s.f_bsize * s.f_bavail;
481 info->full_level += (MEMORY_MEGABYTE_VALUE/dTotal)*100;
483 _I("'%s' t=%4.0lf a=%4.0lf(%4.2lf) w=%4.4lf c=%4.4lf f=%4.4lf",
484 path, dTotal, dAvail, (dAvail*100/dTotal), info->warning_level, info->critical_level, info->full_level);
487 static void check_internal_storage(struct storage_config_info *info)
489 static enum memnoti_level old = MEMNOTI_LEVEL_NORMAL;
492 if (info->current_noti_level < MEMNOTI_LEVEL_NORMAL && info->current_noti_level < old) {
493 ret_val = process_memory_info(info->current_noti_level);
495 info->current_noti_level = MEMNOTI_LEVEL_NORMAL;
498 if (info->current_noti_level == MEMNOTI_LEVEL_NORMAL && info->current_noti_level > old) {
499 ret_val = process_memory_info(info->current_noti_level);
501 info->current_noti_level = MEMNOTI_LEVEL_NORMAL;
503 old = info->current_noti_level;
506 static gboolean check_storage_status(gpointer data)
513 storage_get_internal_memory_size(&s);
514 dTotal = (double)s.f_frsize * s.f_blocks;
515 dAvail = (double)s.f_bsize * s.f_bavail;
516 storage_status_broadcast(&storage_internal_info, dTotal, dAvail);
517 check_internal_storage(&storage_internal_info);
519 storage_get_memory_size(MEMORY_STATUS_TMP_PATH, &s);
520 dTotal = (double)s.f_frsize * s.f_blocks;
521 dAvail = (double)s.f_bsize * s.f_bavail;
522 storage_status_broadcast(&storage_tmp_info, dTotal, dAvail);
524 storage_get_memory_size(MEMORY_STATUS_OPT_PATH, &s);
525 dTotal = (double)s.f_frsize * s.f_blocks;
526 dAvail = (double)s.f_bsize * s.f_bavail;
527 storage_status_broadcast(&storage_opt_info, dTotal, dAvail);
529 return G_SOURCE_CONTINUE;
532 static int init_storage_config_info_all(void)
534 init_storage_config_info(tzplatform_getenv(TZ_SYS_USER), &storage_internal_info);
535 init_storage_config_info(MEMORY_STATUS_TMP_PATH, &storage_tmp_info);
536 init_storage_config_info(MEMORY_STATUS_OPT_PATH, &storage_opt_info);
537 memnoti_timer = g_timeout_add(MEMNOTI_TIMER_INTERVAL,
538 check_storage_status, NULL);
539 if (memnoti_timer == 0)
540 _E("Failed mem available noti timer add.");
544 static GVariant *dbus_getstatus(GDBusConnection *conn,
545 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
546 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
549 unsigned long long dAvail = 0.0;
550 unsigned long long dTotal = 0.0;
552 storage_get_internal_memory_size(&s);
553 dTotal = (unsigned long long)s.f_frsize * s.f_blocks;
554 dAvail = (unsigned long long)s.f_bsize * s.f_bavail;
556 return g_variant_new("(tt)", dTotal, dAvail);
559 static GVariant *dbus_get_storage_status(GDBusConnection *conn,
560 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
561 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
568 unsigned long long dAvail = 0.0;
569 unsigned long long dTotal = 0.0;
573 g_variant_get(param, "(s)", &str_path);
575 temp = tzplatform_getenv(TZ_SYS_USER);
576 if (!strncmp(str_path, temp, strlen(temp))) {
577 ret_val = stat(str_path, &buf);
579 ret_val = storage_get_internal_memory_size(&s);
585 ret_val = storage_get_memory_size(str_path, &s);
591 dTotal = (unsigned long long)s.f_frsize * s.f_blocks;
592 dAvail = (unsigned long long)s.f_bsize * s.f_bavail;
595 pid = gdbus_connection_get_sender_pid(NULL, sender);
597 _D("PID=%d path='%s' total=%4.0llu avail=%4.0llu", pid, str_path, dTotal, dAvail);
600 return g_variant_new("(tt)", dTotal, dAvail);
603 static GVariant *dbus_getstatvfs(GDBusConnection *conn,
604 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
605 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
611 g_variant_get(param, "(s)", &str_path);
613 storage_get_memory_size(str_path, &s);
615 pid = gdbus_connection_get_sender_pid(NULL, sender);
617 _D("PID=%d path='%s'", pid, str_path);
621 return g_variant_new("(ttttttttttt)", (guint64)(s.f_bsize), (guint64)(s.f_frsize),
622 (guint64)(s.f_blocks), (guint64)(s.f_bfree), (guint64)(s.f_bavail),
623 (guint64)(s.f_files), (guint64)(s.f_ffree), (guint64)(s.f_favail),
624 (guint64)(s.f_fsid), (guint64)(s.f_flag), (guint64)(s.f_namemax));
628 static GVariant *dbus_get_storage_level(GDBusConnection *conn,
629 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
630 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
633 enum memnoti_level level;
636 g_variant_get(param, "(i)", &path_id);
638 if (path_id == TZ_SYS_USER)
639 level = storage_internal_info.current_noti_level;
640 else if (path_id == TZ_SYS_OPT)
641 level = storage_opt_info.current_noti_level;
642 else if (path_id == TZ_SYS_TMP)
643 level = storage_tmp_info.current_noti_level;
647 if (level == MEMNOTI_LEVEL_WARNING)
649 else if (level == MEMNOTI_LEVEL_CRITICAL)
651 else if (level == MEMNOTI_LEVEL_FULL)
653 else if (level == MEMNOTI_LEVEL_NORMAL)
656 value = "Not supported path";
658 return g_variant_new("(s)", value);
661 static const dbus_method_s storage_methods[] = {
662 { "getstorage", NULL, "tt", dbus_getstatus },
663 { "GetStatus", "s", "tt", dbus_get_storage_status },
664 { "GetStatvfs", "s", "ttttttttttt", dbus_getstatvfs },
665 { "GetStorageLevel", "i", "s", dbus_get_storage_level },
666 /* Add methods here */
669 static dbus_interface_u storage_interface = {
670 .name = STORAGED_INTERFACE_STORAGE,
671 .methods = storage_methods,
672 .nr_methods = ARRAY_SIZE(storage_methods),
675 static void booting_done(void)
685 /* UDEV register_udev_uevent_control */
686 ret_val = register_udev_uevent_control(&dm_verity_uh);
688 _E("Failed to register dm_verity uevent: %d", ret_val);
691 if (init_storage_config_info_all() == -1)
692 _E("Failed to remain mem noti control fd init.");
695 static void storage_poweroff(GDBusConnection *conn,
704 g_source_remove(memnoti_timer);
708 /* UDEV unregister_udev_uevent_control */
709 unregister_udev_uevent_control(&dm_verity_uh);
712 static int is_recovery_available()
717 /* check if a/b partitions are cloned */
718 ret_board_api = device_board_get_partition_ab_cloned(&cloned);
719 if (ret_board_api != 0) {
720 CRITICAL_LOG("device_board_get_partition_ab_cloned failed: %d", ret_board_api);
724 CRITICAL_LOG("Partition a/b are not cloned");
731 static gboolean reboot_recovery_handler(void *data)
735 int recovery_available;
736 gint poweroff_retval;
737 GVariant *poweroff_param = NULL;
739 recovery_available = is_recovery_available();
741 /* set current partition status as "corrupted" */
742 ret_board_api = device_board_set_partition_status('\0', "corrupted");
743 CRITICAL_LOG("device_board_set_partition_status: (%d)", ret_board_api);
744 /* clear partition ab cloned */
745 ret_board_api = device_board_clear_partition_ab_cloned();
746 CRITICAL_LOG("device_board_clear_partition_ab_cloned: (%d)", ret_board_api);
748 if (!recovery_available) {
749 CRITICAL_LOG("Recovery is not available, do not reboot/recovery");
750 return G_SOURCE_REMOVE;
753 /* toggle partition */
754 ret_board_api = device_board_switch_partition('\0');
755 CRITICAL_LOG("device_board_switch_partition: (%d)", ret_board_api);
757 /* call method for reboot recovery */
758 poweroff_param = g_variant_new("(ss)", "reboot", "recovery");
760 ret_dbus = gdbus_call_sync_with_reply_int("org.tizen.system.deviced",
761 "/Org/Tizen/System/DeviceD/PowerOff",
762 "org.tizen.system.deviced.PowerOff",
763 "PowerOffWithOption",
764 poweroff_param, &poweroff_retval);
765 g_variant_unref(poweroff_param);
768 CRITICAL_LOG("Failed to call PowerOffWithOption(reboot recovery): (%d)", ret_dbus);
769 return G_SOURCE_CONTINUE;
772 CRITICAL_LOG("org.tizen.system.deviced.PowerOff.PowerOffWithOption reboot recovery: (%d)",
775 return G_SOURCE_REMOVE;
778 static void dm_verity_uevent_block_handler(struct udev_device *dev)
780 static int dm_verity_corrupted_cnt = 0;
781 const char *dm_name = NULL;
782 const char *dm_verity_err_block_nr = NULL;
784 /* if dm_name is rootfs and DM_VERITY_ERR_BLOCK_NR exist, then reboot recovery */
785 dm_name = udev_device_get_property_value(dev, "DM_NAME");
786 dm_verity_err_block_nr = udev_device_get_property_value(dev, "DM_VERITY_ERR_BLOCK_NR");
788 if (!dm_name || !dm_verity_err_block_nr) {
792 if(strncmp(DM_ROOT_NODE_NAME, dm_name, strlen(DM_ROOT_NODE_NAME))) {
796 ++dm_verity_corrupted_cnt;
797 if (dm_verity_corrupted_cnt < storage_rootfs_recovery_info.dm_verity_corrupted_count) {
798 CRITICAL_LOG("dm_verity_corrupted_cnt: %d(<%d)",
799 dm_verity_corrupted_cnt,
800 storage_rootfs_recovery_info.dm_verity_corrupted_count);
803 /* prevent overflow */
804 dm_verity_corrupted_cnt = storage_rootfs_recovery_info.dm_verity_corrupted_count;
806 CRITICAL_LOG("Dmverity corrupted: action=(%s), count=(%d), timeout=(%d)ms",
807 recovery_action_str[storage_rootfs_recovery_info.action],
808 storage_rootfs_recovery_info.dm_verity_corrupted_count,
809 storage_rootfs_recovery_info.dm_verity_corrupted_timeout);
812 if (storage_rootfs_recovery_info.action == RECOVERY_ACTION_IGNORE) {
813 /* ignore, do nothing */
816 /* action: reboot,recovery */
817 if (storage_rootfs_recovery_info.action == RECOVERY_ACTION_REBOOT_RECOVERY &&
818 poweroff_g_timeout_event_source_id <= 0) {
819 poweroff_g_timeout_event_source_id =
820 g_timeout_add(storage_rootfs_recovery_info.dm_verity_corrupted_timeout,
821 reboot_recovery_handler, NULL);
822 _I("g_timeout_add event source id: (%u)",
823 poweroff_g_timeout_event_source_id);
827 static int config_parse_time_ms(const char *value, int *parsed_ms)
830 char *unit_ptr = strchr(value, 's');
831 if (unit_ptr == NULL) {
832 _E("Cannot find 's' in the string (%s)", value);
836 if (value > (unit_ptr - 1)) {
837 _E("Size of string should be larger than 1");
841 prefix = *(unit_ptr - 1);
843 if (isdigit(prefix)) {
844 *parsed_ms = atoi(value) * 1000;
848 *(unit_ptr - 1) = '\0';
850 *parsed_ms = atoi(value);
854 _E("Unknown unit of time");
858 static int load_config(struct parse_result *result, void *user_data)
863 if (MATCH(result->section, "StorageUsageLevelThreshold")) {
864 _D("%s,%s,%s", result->section, result->name, result->value);
867 value = result->value;
869 if (MATCH(name, "WarningLevel")) {
870 storage_internal_info.warning_level = (double)atof(value);
871 _I("WarningLevel: (%f)", storage_internal_info.warning_level);
872 } else if (MATCH(name, "CriticalLevel")) {
873 storage_internal_info.critical_level = (double)atof(value);
874 _I("CriticalLevel: (%f)", storage_internal_info.critical_level);
875 } else if (MATCH(name, "FullLevel")) {
876 storage_internal_info.full_level = (double)atof(value);
877 _I("FullLevel: (%f)", storage_internal_info.full_level);
880 } else if (MATCH(result->section, "StorageRootfsRecovery")) {
881 _D("%s,%s,%s", result->section, result->name, result->value);
884 value = result->value;
886 if (MATCH(name, "DmverityCorruptedAction")) {
887 if (!value || !(*value)) {
891 if (!strncmp(value, RECOVERY_ACTION_IGNORE_STR, strlen(RECOVERY_ACTION_IGNORE_STR))) {
892 storage_rootfs_recovery_info.action = RECOVERY_ACTION_IGNORE;
893 } else if (!strncmp(value, RECOVERY_ACTION_REBOOT_RECOVERY_STR, strlen(RECOVERY_ACTION_REBOOT_RECOVERY_STR))) {
894 storage_rootfs_recovery_info.action = RECOVERY_ACTION_REBOOT_RECOVERY;
896 _E("Unknown action: (%s)", value);
897 /* do nothing, use previous value */
900 _I("Dmverity Corrupted Action: (%s)", recovery_action_str[storage_rootfs_recovery_info.action]);
902 } else if (MATCH(name, "DmverityCorruptedCount")) {
903 storage_rootfs_recovery_info.dm_verity_corrupted_count = atoi(value);
904 _I("DmverityCorruptedCount: (%d)",
905 storage_rootfs_recovery_info.dm_verity_corrupted_count);
907 } else if (MATCH(name, "DmverityCorruptedTimeout")) {
909 if (!config_parse_time_ms(value, &ms)) {
910 storage_rootfs_recovery_info.dm_verity_corrupted_timeout = ms;
912 _I("DmverityCorruptedTimeout: (%d)ms",
913 storage_rootfs_recovery_info.dm_verity_corrupted_timeout);
923 static void storage_config_load(void)
927 ret_val = config_parse(STORAGE_CONF_FILE, load_config, NULL);
929 _E("Failed to load %s, %d Use default value.", STORAGE_CONF_FILE, ret_val);
932 static void storage_init(void *data)
939 storage_config_load();
941 ret_val = gdbus_register_object(NULL, STORAGED_PATH_STORAGE,
944 _E("Failed to register dbus interface and methods: %d", ret_val);
946 ret_val = remove_directory(NEED_CLEANUP_DIR_PATH);
948 _E("Failed to remove directory.");
949 ret_val = mkdir(NEED_CLEANUP_DIR_PATH, 0644);
951 _E("Failed to make directory: %d", errno);
953 init_cleanup_storage();
955 id_storage_poweroff = gdbus_signal_subscribe(NULL, DEVICED_PATH_POWEROFF,
956 DEVICED_INTERFACE_POWEROFF,
957 SIGNAL_POWEROFF_STATE,
958 storage_poweroff, NULL, NULL);
963 static void storage_exit(void *data)
969 free_cleanup_storage();
970 /* unregister notifier for below each event */
971 gdbus_signal_unsubscribe(NULL, id_storage_poweroff);
973 /* UDEV unregister_udev_uevent_control */
974 ret_val = unregister_udev_uevent_control(&dm_verity_uh);
976 _E("Failed to unregister block uevent: %d", ret_val);
980 static storaged_module_interface storage_module = {
982 .init = storage_init,
983 .exit = storage_exit,
986 __attribute__ ((visibility("default")))storaged_module_interface *
987 storaged_get_module_interface(void)
989 return &storage_module;