From 1585f07ff0594b9323c05c73b4d8cc1cbdd01a32 Mon Sep 17 00:00:00 2001 From: INSUN PYO Date: Wed, 26 Jun 2019 14:49:47 +0900 Subject: [PATCH 01/16] Move storaged.service from multi-user.target to delayed.target Change-Id: Id10bce3ae57d76c3cfc335a62b0de515038b0d19 --- packaging/storaged.spec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/storaged.spec b/packaging/storaged.spec index d608baa..a4e8e0f 100644 --- a/packaging/storaged.spec +++ b/packaging/storaged.spec @@ -117,7 +117,7 @@ make %{?jobs:-j%jobs} rm -rf %{buildroot} %make_install -%install_service multi-user.target.wants storaged.service +%install_service delayed.target.wants storaged.service %find_lang extended-sd @@ -135,7 +135,7 @@ systemctl daemon-reload %license LICENSE.Apache-2.0 %config %{_sysconfdir}/dbus-1/system.d/org.tizen.system.storage.conf %{_datadir}/dbus-1/system-services/org.tizen.system.storage.service -%{_unitdir}/multi-user.target.wants/storaged.service +%{_unitdir}/delayed.target.wants/storaged.service %{_unitdir}/storaged.service %{_bindir}/storaged -- 2.7.4 From 4b382067b66b580b73b9c429c5ce58b73f876999 Mon Sep 17 00:00:00 2001 From: "sanghyeok.oh" Date: Mon, 8 Jul 2019 17:06:53 +0900 Subject: [PATCH 02/16] coverity fix Change-Id: I79e8640d6ccbd0b810451ba284d23c042ff89c67 Signed-off-by: sanghyeok.oh --- src/block/block.c | 80 +++++++++++++++++++++++++++++++++------------------ src/storage/storage.c | 6 ++-- 2 files changed, 56 insertions(+), 30 deletions(-) diff --git a/src/block/block.c b/src/block/block.c index 193edb2..874ae3d 100644 --- a/src/block/block.c +++ b/src/block/block.c @@ -394,70 +394,94 @@ static void create_file(int id, char *mount_point, bool extendedsd) _E("Failed to open '%s'.", file_name); } -static void signal_device_blocked(struct block_device *bdev) +static void broadcast_device_blocked(struct block_device *bdev) { struct block_data *data; + int ret; if (!bdev || !bdev->data) return; data = bdev->data; - dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_BLOCK_MANAGER, + ret = dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_BLOCK_MANAGER, STORAGED_INTERFACE_BLOCK_MANAGER, BLOCK_DEVICE_BLOCKED, block_data_to_gvariant(data, 0)); + if (ret < 0) + _E("Failed to send dbus signal"); } -static void signal_device_changed(struct block_device *bdev, +static void broadcast_device_changed(struct block_device *bdev, enum block_dev_operation op) { struct block_data *data; - GVariant *var = NULL; - int flags; + GVariant *param = NULL; + const char *signal_name = NULL; + int flags = 0; + int ret; - if (!bdev || !bdev->data) + if (!bdev || !bdev->data) { + _E("Failed to broadcast device changed signal. op(%d)", op); return; + } data = bdev->data; + /* set flags and signal name */ switch (op) { case BLOCK_DEV_MOUNT: BLOCK_GET_MOUNT_FLAGS(data, flags); + signal_name = BLOCK_DEVICE_CHANGED; break; case BLOCK_DEV_UNMOUNT: BLOCK_GET_UNMOUNT_FLAGS(data, flags); + signal_name = BLOCK_DEVICE_CHANGED; break; case BLOCK_DEV_FORMAT: BLOCK_GET_FORMAT_FLAGS(data, flags); + signal_name = BLOCK_DEVICE_CHANGED; break; - default: + case BLOCK_DEV_INSERT: + flags = 0; + signal_name = BLOCK_DEVICE_ADDED; + break; + case BLOCK_DEV_REMOVE: flags = 0; + signal_name = BLOCK_DEVICE_REMOVED; break; + default: + /* unknown op */ + _E("Failed to broadcast device changed signal. op(%d)", op); + return; } /* Broadcast outside with BlockManager iface */ - var = block_data_to_gvariant(data, flags); + param = block_data_to_gvariant(data, flags); - if (op == BLOCK_DEV_INSERT) - dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_BLOCK_MANAGER, + ret = dbus_handle_broadcast_dbus_signal_var( + STORAGED_PATH_BLOCK_MANAGER, STORAGED_INTERFACE_BLOCK_MANAGER, - BLOCK_DEVICE_ADDED, - var); - else if (op == BLOCK_DEV_REMOVE) - dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_BLOCK_MANAGER, - STORAGED_INTERFACE_BLOCK_MANAGER, - BLOCK_DEVICE_REMOVED, - var); - else { - dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_BLOCK_MANAGER, - STORAGED_INTERFACE_BLOCK_MANAGER, - BLOCK_DEVICE_CHANGED, - var); - dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_BLOCK_MANAGER, - STORAGED_INTERFACE_BLOCK_MANAGER, - BLOCK_DEVICE_CHANGED_2, - block_data_to_gvariant2(data, flags)); + signal_name, + param); + if (ret < 0) + _E("Failed to broadcast device changed signal. op(%d)", op); + + /* broadcast one more signal for mount, unmount, format */ + switch(op) { + case BLOCK_DEV_MOUNT: + case BLOCK_DEV_UNMOUNT: + case BLOCK_DEV_FORMAT: + ret = dbus_handle_broadcast_dbus_signal_var( + STORAGED_PATH_BLOCK_MANAGER, + STORAGED_INTERFACE_BLOCK_MANAGER, + BLOCK_DEVICE_CHANGED_2, + block_data_to_gvariant2(data, flags)); + if (ret < 0) + _E("Failed to broadcast device changed signal. op(%d)", op); + default: + /* do nothing */ + break; } } @@ -1028,7 +1052,7 @@ static bool pipe_cb(int fd, void *data) /* Broadcast outside with Block iface */ if (pdata.bdev->on_private_op == REQ_NORMAL) - signal_device_changed(pdata.bdev, pdata.op); + broadcast_device_changed(pdata.bdev, pdata.op); else if (pdata.bdev->on_private_op == REQ_PRIVATE) { if (pdata.op == BLOCK_DEV_UNMOUNT) { pdata.bdev->on_private_op = REQ_NORMAL; @@ -1351,7 +1375,7 @@ static int block_unmount(struct block_device *bdev, data = bdev->data; if (bdev->on_private_op == REQ_NORMAL) - signal_device_blocked(bdev); + broadcast_device_blocked(bdev); /* it must called before unmounting mmc */ r = mmc_check_and_unmount(data->mount_point); diff --git a/src/storage/storage.c b/src/storage/storage.c index aac728a..4979bf5 100644 --- a/src/storage/storage.c +++ b/src/storage/storage.c @@ -143,6 +143,7 @@ static void memcleanup_send_broadcast(struct storage_config_info *info, enum mem enum tzplatform_variable path; char *value; char buf[20]; + int ret; if (info->mem_id == MEMORY_INTERNAL) path = TZ_SYS_USER; @@ -177,9 +178,10 @@ static void memcleanup_send_broadcast(struct storage_config_info *info, enum mem _D("time=%s path=%d level=%s", buf, path, value); out: - dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_LOWMEM, STORAGED_INTERFACE_LOWMEM, + ret = dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_LOWMEM, STORAGED_INTERFACE_LOWMEM, SIGNAL_NEED_CLEANUP, g_variant_new("(is)", path, value)); - + if (ret < 0) + _E("Failed to send dbus signal"); } static void _popup_cb(GVariant *var, void *user_data, GError *err) -- 2.7.4 From 1dddc2a515df7dc3948c4a9db0a3ca2372c7108f Mon Sep 17 00:00:00 2001 From: INSUN PYO Date: Mon, 8 Jul 2019 20:27:50 +0900 Subject: [PATCH 03/16] Delete meaningless configuration Change-Id: Id8f15543dd3431dfb85a4c4bcb7b4b289da5391c --- systemd/org.tizen.system.storage.service | 1 - 1 file changed, 1 deletion(-) diff --git a/systemd/org.tizen.system.storage.service b/systemd/org.tizen.system.storage.service index d6127f7..4217171 100644 --- a/systemd/org.tizen.system.storage.service +++ b/systemd/org.tizen.system.storage.service @@ -1,5 +1,4 @@ [D-BUS Service] Name=org.tizen.system.storage Exec=/bin/false -User=root SystemdService=storaged.service -- 2.7.4 From 308ac96c08a481cde3af38aeb51f9dddf7ef3399 Mon Sep 17 00:00:00 2001 From: Hyotaek Shim Date: Tue, 23 Jul 2019 11:51:40 +0900 Subject: [PATCH 04/16] Fix WantedBy field in storaged.service Change-Id: I286fdc9d645bd8ef43e0406d0cc113883a043646 Signed-off-by: Hyotaek Shim --- systemd/storaged.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/systemd/storaged.service b/systemd/storaged.service index c87e5cf..4597029 100644 --- a/systemd/storaged.service +++ b/systemd/storaged.service @@ -14,4 +14,4 @@ KillSignal=SIGUSR1 NotifyAccess=main [Install] -WantedBy=multi-user.target +WantedBy=delayed.target -- 2.7.4 From 8814ee767dabfdc665226cb165ea21fe6dbc7c44 Mon Sep 17 00:00:00 2001 From: "sanghyeok.oh" Date: Wed, 14 Aug 2019 17:23:11 +0900 Subject: [PATCH 05/16] dbus: modified to use revised api Change-Id: I93d1ea9b078ce460dd869defcf5d72c82b6ae785 Signed-off-by: sanghyeok.oh --- src/block/block.c | 7 ++++--- src/storage/storage.c | 7 +++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/block/block.c b/src/block/block.c index 874ae3d..f91ea67 100644 --- a/src/block/block.c +++ b/src/block/block.c @@ -404,7 +404,8 @@ static void broadcast_device_blocked(struct block_device *bdev) data = bdev->data; - ret = dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_BLOCK_MANAGER, + ret = dbus_handle_broadcast_dbus_signal(NULL, + STORAGED_PATH_BLOCK_MANAGER, STORAGED_INTERFACE_BLOCK_MANAGER, BLOCK_DEVICE_BLOCKED, block_data_to_gvariant(data, 0)); @@ -459,7 +460,7 @@ static void broadcast_device_changed(struct block_device *bdev, /* Broadcast outside with BlockManager iface */ param = block_data_to_gvariant(data, flags); - ret = dbus_handle_broadcast_dbus_signal_var( + ret = dbus_handle_broadcast_dbus_signal(NULL, STORAGED_PATH_BLOCK_MANAGER, STORAGED_INTERFACE_BLOCK_MANAGER, signal_name, @@ -472,7 +473,7 @@ static void broadcast_device_changed(struct block_device *bdev, case BLOCK_DEV_MOUNT: case BLOCK_DEV_UNMOUNT: case BLOCK_DEV_FORMAT: - ret = dbus_handle_broadcast_dbus_signal_var( + ret = dbus_handle_broadcast_dbus_signal(NULL, STORAGED_PATH_BLOCK_MANAGER, STORAGED_INTERFACE_BLOCK_MANAGER, BLOCK_DEVICE_CHANGED_2, diff --git a/src/storage/storage.c b/src/storage/storage.c index 4979bf5..3eaf737 100644 --- a/src/storage/storage.c +++ b/src/storage/storage.c @@ -178,8 +178,11 @@ static void memcleanup_send_broadcast(struct storage_config_info *info, enum mem _D("time=%s path=%d level=%s", buf, path, value); out: - ret = dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_LOWMEM, STORAGED_INTERFACE_LOWMEM, - SIGNAL_NEED_CLEANUP, g_variant_new("(is)", path, value)); + ret = dbus_handle_broadcast_dbus_signal(NULL, + STORAGED_PATH_LOWMEM, + STORAGED_INTERFACE_LOWMEM, + SIGNAL_NEED_CLEANUP, + g_variant_new("(is)", path, value)); if (ret < 0) _E("Failed to send dbus signal"); } -- 2.7.4 From 0a79c397b9cdec364ffa622fd2f38daafe033a0c Mon Sep 17 00:00:00 2001 From: "sanghyeok.oh" Date: Fri, 16 Aug 2019 10:56:51 +0900 Subject: [PATCH 06/16] dbus: modified to use renamed api change 'dbus_handle_broadcast_dbus_signal' to 'dbus_handle_emit_dbus_signal' Change-Id: I9833be576ed9f9fe37bae72b6aaa5f7440ffc7af Signed-off-by: sanghyeok.oh --- src/block/block.c | 6 +++--- src/storage/storage.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/block/block.c b/src/block/block.c index f91ea67..a718697 100644 --- a/src/block/block.c +++ b/src/block/block.c @@ -404,7 +404,7 @@ static void broadcast_device_blocked(struct block_device *bdev) data = bdev->data; - ret = dbus_handle_broadcast_dbus_signal(NULL, + ret = dbus_handle_emit_dbus_signal(NULL, STORAGED_PATH_BLOCK_MANAGER, STORAGED_INTERFACE_BLOCK_MANAGER, BLOCK_DEVICE_BLOCKED, @@ -460,7 +460,7 @@ static void broadcast_device_changed(struct block_device *bdev, /* Broadcast outside with BlockManager iface */ param = block_data_to_gvariant(data, flags); - ret = dbus_handle_broadcast_dbus_signal(NULL, + ret = dbus_handle_emit_dbus_signal(NULL, STORAGED_PATH_BLOCK_MANAGER, STORAGED_INTERFACE_BLOCK_MANAGER, signal_name, @@ -473,7 +473,7 @@ static void broadcast_device_changed(struct block_device *bdev, case BLOCK_DEV_MOUNT: case BLOCK_DEV_UNMOUNT: case BLOCK_DEV_FORMAT: - ret = dbus_handle_broadcast_dbus_signal(NULL, + ret = dbus_handle_emit_dbus_signal(NULL, STORAGED_PATH_BLOCK_MANAGER, STORAGED_INTERFACE_BLOCK_MANAGER, BLOCK_DEVICE_CHANGED_2, diff --git a/src/storage/storage.c b/src/storage/storage.c index 3eaf737..24a613f 100644 --- a/src/storage/storage.c +++ b/src/storage/storage.c @@ -178,7 +178,7 @@ static void memcleanup_send_broadcast(struct storage_config_info *info, enum mem _D("time=%s path=%d level=%s", buf, path, value); out: - ret = dbus_handle_broadcast_dbus_signal(NULL, + ret = dbus_handle_emit_dbus_signal(NULL, STORAGED_PATH_LOWMEM, STORAGED_INTERFACE_LOWMEM, SIGNAL_NEED_CLEANUP, -- 2.7.4 From ff7ef76e47637b422304d3d65413a21a6fee5330 Mon Sep 17 00:00:00 2001 From: INSUN PYO Date: Thu, 21 Nov 2019 14:48:25 +0900 Subject: [PATCH 07/16] Remove default value at systemd services https://www.freedesktop.org/software/systemd/man/systemd.service.html - Behavior of notify is similar to exec; ... If NotifyAccess= is missing or set to none, it will be forcibly set to main. Change-Id: Idc1402ee1322d87f2102c410c5b3f9839853d853 --- systemd/storaged.service | 1 - 1 file changed, 1 deletion(-) diff --git a/systemd/storaged.service b/systemd/storaged.service index 4597029..10e95bf 100644 --- a/systemd/storaged.service +++ b/systemd/storaged.service @@ -11,7 +11,6 @@ ExecStart=/usr/bin/storaged Restart=always RestartSec=0 KillSignal=SIGUSR1 -NotifyAccess=main [Install] WantedBy=delayed.target -- 2.7.4 From 94b941f2ee66702934f3d7168faa7c5b166a0aa5 Mon Sep 17 00:00:00 2001 From: Yunmi Ha Date: Thu, 31 Oct 2019 14:28:24 +0900 Subject: [PATCH 08/16] Add CleanupStorage Function Refer to the config file, delete the data according to the storage level. config: /etc/storaged/cleanup-storage.conf Change-Id: I589c7a03fa65ac17a62d12bcd301510485ea8731 Signed-off-by: Yunmi Ha --- packaging/storaged.spec | 1 + src/storage/CMakeLists.txt | 2 + src/storage/cleanup.c | 314 ++++++++++++++++++++++++++++++++ src/storage/cleanup.h | 30 +++ src/storage/cleanup_config.c | 311 +++++++++++++++++++++++++++++++ src/storage/cleanup_config.h | 45 +++++ src/storage/sample-cleanup-storage.conf | 30 +++ src/storage/storage.c | 6 + 8 files changed, 739 insertions(+) create mode 100644 src/storage/cleanup.c create mode 100644 src/storage/cleanup.h create mode 100644 src/storage/cleanup_config.c create mode 100644 src/storage/cleanup_config.h create mode 100644 src/storage/sample-cleanup-storage.conf diff --git a/packaging/storaged.spec b/packaging/storaged.spec index a4e8e0f..78ec20d 100644 --- a/packaging/storaged.spec +++ b/packaging/storaged.spec @@ -28,6 +28,7 @@ BuildRequires: pkgconfig(app2sd) BuildRequires: pkgconfig(blkid) BuildRequires: pkgconfig(mount) BuildRequires: pkgconfig(libsyscommon) +BuildRequires: pkgconfig(json-c) BuildRequires: pkgconfig(capi-ui-efl-util) BuildRequires: pkgconfig(capi-appfw-application) diff --git a/src/storage/CMakeLists.txt b/src/storage/CMakeLists.txt index 43a614b..0b62347 100644 --- a/src/storage/CMakeLists.txt +++ b/src/storage/CMakeLists.txt @@ -6,6 +6,7 @@ pkg_check_modules(${PROJECT_NAME}_pkgs REQUIRED dlog gio-2.0 glib-2.0 + json-c storage vconf libsyscommon @@ -19,6 +20,7 @@ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wall -Werror -fvisibility=hidden -rdynamic") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC") SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/storage) INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/shared) FILE(GLOB ALL_SRCS "*.c") diff --git a/src/storage/cleanup.c b/src/storage/cleanup.c new file mode 100644 index 0000000..af6e0ec --- /dev/null +++ b/src/storage/cleanup.c @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2019, Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "cleanup.h" +#include "cleanup_config.h" + +enum cleanup_running_type { + CLEANUP_TYPE_NONE = 0, + CLEANUP_TYPE_SYSTEM, + CLEANUP_TYPE_USER +}; + +struct cleanup_request { + int cleanup_mode; + int level; +}; + +#define REMOVE(path) { \ + if(remove(path) != 0) { \ + _E("Failed to remove(%s): %d", path, errno); \ + return -errno; \ + } \ + _D("Remove (%s)", path); \ +} + +#define ASSERT(ret, format, arg...) {\ + if (!ret) { \ + _E(format, ##arg); \ + assert(ret); \ + } \ +} + +static pthread_mutex_t mutex_cancel; +static pthread_mutex_t mutex_lock; +static pthread_t cleanup_th = 0; +static GList *request_queue = NULL; +static int cleanup_canceled = 0; + +static int is_cleanup_canceled() +{ + int ret = 0; + ASSERT((pthread_mutex_lock(&mutex_cancel) == 0), "Assert: Failed to pthread_mutex_lock for cancel."); + ret = cleanup_canceled; + pthread_mutex_unlock(&mutex_cancel); + + return ret; +} + +static void cleanup_cancel() +{ + ASSERT((pthread_mutex_lock(&mutex_cancel) == 0), "Assert: Failed to pthread_mutex_lock for cancel."); + cleanup_canceled = 1; + pthread_mutex_unlock(&mutex_cancel); +} + +static int find_sub_except_item(const char *item, const char *path) +{ + if (strstr(item, path)) { + _D("Find except item: %s, path: %s", item, path); + return 0; + } + + return -1; +} + +static int remove_path(const char *path, GList *except) +{ + if (!path) + return -EINVAL; + + if (!except) + REMOVE(path) + else if (except && !g_list_find_custom(except, path, (GCompareFunc)find_sub_except_item)) + REMOVE(path); + + return 0; +} + +static int cleanup_recursive(const char *path, GList *except) +{ + DIR *dir = NULL; + struct dirent *dent; + struct stat fstat; + char sub_path[PATH_MAX] = {0,}; + int ret; + + if (except && g_list_find_custom(except, path, (GCompareFunc)strcmp)) + return 0; + + if (is_cleanup_canceled()) + return 0; + + ret = lstat(path, &fstat); + if (ret) + return -EINVAL; + + if ((fstat.st_mode & S_IFMT) == S_IFDIR) { + if (access(path, W_OK) != 0) { + _E("Failed to access file status(%s).", path); + return -EINVAL; + } + + dir = opendir(path); + if (!dir) { + _E("Failed to open dir(%s).", path); + return -EINVAL; + } + + while((dent = readdir(dir))) { + if(strcmp(dent->d_name, ".") == 0 || + strcmp(dent->d_name, "..") == 0) + continue; + + if (is_cleanup_canceled()) { + ret = -EINVAL; + break; + } + + if (PATH_MAX <= (strlen(path) + strlen(dent->d_name) + 1)) { + _E("File path sould be shorter than %d. But %d.", PATH_MAX, strlen(path) + strlen(dent->d_name) + 1); + continue; + } + + snprintf(sub_path, PATH_MAX, "%s/%s", path, dent->d_name); + ret = cleanup_recursive(sub_path, except); + if (ret != 0) + break; + } + closedir(dir); + if (!ret) + ret = remove_path(path, except); + } else + REMOVE(path); + + return ret; +} + +static int add_request_queue(int type, int level) +{ + int ret = 0; + struct cleanup_request *request = NULL, *item = NULL; + GList *list = NULL; + + ASSERT((pthread_mutex_lock(&mutex_lock) == 0), "Assert: Failed to pthread_mutex_lock."); + + for (list = g_list_first(request_queue); list != NULL; list = g_list_next(list)) { + item = list->data; + + if ((item->cleanup_mode == type) && (item->level == level)) { + _D("cleanup request is already added."); + goto cleanup; + } + } + + request = malloc(sizeof(struct cleanup_request)); + if (!request) { + ret = -ENOMEM; + goto cleanup; + } + + request->cleanup_mode = type; + request->level = level; + request_queue = g_list_append(request_queue, request); + +cleanup: + pthread_mutex_unlock(&mutex_lock); + return ret; +} + +static void remove_request_queue(struct cleanup_request *item) +{ + ASSERT((pthread_mutex_lock(&mutex_lock) == 0), "Assert: Failed to pthread_mutex_lock."); + + request_queue = g_list_remove(request_queue, item); + free(item); + pthread_mutex_unlock(&mutex_lock); +} + +static struct cleanup_request *get_request_queue() +{ + GList *list = NULL; + + ASSERT((pthread_mutex_lock(&mutex_lock) == 0), "Assert: Failed to pthread_mutex_lock."); + + list = g_list_first(request_queue); + pthread_mutex_unlock(&mutex_lock); + + return (list)? list->data :NULL; +} + +static GList *get_cleanup_config(int type) +{ + if (type == CLEANUP_TYPE_SYSTEM) + return get_cleanup_config_system(); + else if (type == CLEANUP_TYPE_USER) + return get_cleanup_config_user(); + + return NULL; +} + +// Called by thread +void *cleanup_storage_start(void *arg) +{ + GList *list_config = NULL; + GList *list = NULL; + struct cleanup_config *config = NULL; + struct cleanup_request *request = NULL; + + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + while(true) { + request = get_request_queue(); + if (!request) { + _D("There is no more cleanup request."); + break; + } + + _D("Cleanup: mode=%d, level=%d", request->cleanup_mode, request->level); + list_config = get_cleanup_config(request->cleanup_mode); + for (list= g_list_first(list_config); NULL != list; list = g_list_next(list)) { + config = list->data; + if (request->level <= config->level) + cleanup_recursive(config->path, config->exclusion_list); + } + + remove_request_queue(request); + } + cleanup_th = 0; + _D("Cleanup thread exit."); + return NULL; +} + +void cleanup_storage(enum tzplatform_variable path_id, int level) +{ + bool bth = (get_request_queue() == NULL); + int type = CLEANUP_TYPE_NONE; + int ret; + + if (path_id == TZ_SYS_OPT) + type = CLEANUP_TYPE_SYSTEM; + else if (path_id == TZ_SYS_USER) + type = CLEANUP_TYPE_USER; + else { + _D("Not supported path type: %d", path_id); + return ; + } + + if (!get_cleanup_config(type)) { + _D("There is no list for cleanup."); + return ; + } + + if (add_request_queue(type, level) != 0) { + _E("Failed to add request."); + return ; + } + //_D("Add cleanup request.(type:%d, level:%d)", type, level); + + if (bth) { + ret = pthread_create(&cleanup_th, NULL, cleanup_storage_start, NULL); + if (ret != 0) + _E("Failed to start pthread: %d", ret); + } +} + +void init_cleanup_storage() +{ + load_cleanup_config(); + + pthread_mutex_init(&mutex_lock, NULL); + pthread_mutex_init(&mutex_cancel, NULL); +} + +void free_cleanup_storage() +{ + ASSERT((pthread_mutex_lock(&mutex_lock) == 0), "Assert: Failed to pthread_mutex_lock."); + if (request_queue) + g_list_free_full(request_queue, free); + request_queue = NULL; + pthread_mutex_unlock(&mutex_lock); + + if (cleanup_th) { + _D("Cancel cleanup thread %d.", (int)cleanup_th); + cleanup_cancel(); + //pthread_cancel(cleanup_th); + pthread_join(cleanup_th, NULL); + _D("Exit cleanup thread %d.", (int)cleanup_th); + } + + free_cleanup_config(); +} diff --git a/src/storage/cleanup.h b/src/storage/cleanup.h new file mode 100644 index 0000000..46bfaa1 --- /dev/null +++ b/src/storage/cleanup.h @@ -0,0 +1,30 @@ +/* + * storaged + * + * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STORAGED_CLEANUP_H__ +#define __STORAGED_CLEANUP_H__ + +#include +#include + +void init_cleanup_storage(); +void free_cleanup_storage(); + +void cleanup_storage(enum tzplatform_variable path_id, int level); + +#endif /* #define __STORAGED_CLEANUP_H___ */ diff --git a/src/storage/cleanup_config.c b/src/storage/cleanup_config.c new file mode 100644 index 0000000..2717992 --- /dev/null +++ b/src/storage/cleanup_config.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2019, Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include "log.h" +#include "cleanup_config.h" + +char *cleanup_level_str[] = { + "full", + "critical", + "warning", + "normal" +}; + +#define DEF_CLEANUP_CONFIG_FILE "/etc/storaged/cleanup-storage.conf" +#define RESULT(ret, val) \ +{ \ + if (ret) \ + *ret = val; \ +} + +static GList *cleanup_list_system = NULL; +static GList *cleanup_list_user = NULL; + +static void free_config_item(void *data) +{ + struct cleanup_config *item = data; + + if (item->path) { + free(item->path); + item->path = NULL; + } + + if (item->exclusion_list) { + g_list_free_full(item->exclusion_list, free); + item->exclusion_list = NULL; + } + + free(item); +} + +void free_cleanup_config() +{ + if (cleanup_list_system) { + g_list_free_full(cleanup_list_system, free_config_item); + cleanup_list_system = NULL; + } + + if (cleanup_list_user) { + g_list_free_full(cleanup_list_user, free_config_item); + cleanup_list_user = NULL; + } +} + +static int get_config_string_field(struct json_object *root, const char *key, char** value) +{ + struct json_object *node = NULL; + const char *node_value; + + if (!json_object_object_get_ex(root, key, &node)) { + _D("Config doesn't contain path param."); + return 0; + } + + if (!json_object_is_type(node, json_type_string)) { + _E("'%s' type should be string. but it isn't.", key); + return -EINVAL; + } + + node_value = json_object_get_string(node); + *value = strdup(node_value); + if (*value == NULL) { + _E("Failed to duplicate string."); + return -ENOMEM; + } + + return 0; +} + +static GList *get_config_array_field(struct json_object *root, const char *key, int *ret) +{ + struct json_object *node = NULL, *obj; + int i, len; + const char *str = NULL; + char *temp; + GList *list = NULL; + + if (!json_object_object_get_ex(root, key, &node)) { + _D("Config doesn't contain '%s' param.", key); + RESULT(ret, 0); + return NULL; + } + + if (!json_object_is_type(node, json_type_array)) { + _E("'%s' type should be array. but it isn't.", key); + RESULT(ret, -EINVAL); + return NULL; + } + + len = json_object_array_length(node); + for (i = 0; i < len; i++) { + obj = json_object_array_get_idx(node, i); + str = json_object_get_string(obj); + if (!str) + { + _E("Failed to get stirng value from json object."); + RESULT(ret, -EINVAL); + goto cleanup; + } + + temp = strdup(str); + if (!temp) { + _E("Failed to duplicate array item string"); + RESULT(ret, -ENOMEM); + goto cleanup; + } + + list = g_list_append(list, temp); + } + + RESULT(ret, 0); + return list; + +cleanup: + g_list_free_full(list, free); + return NULL; +} + +static int get_cleanup_level(const char *level_str) +{ + int ret = -EINVAL; + int i; + + if (level_str == NULL) + return -EINVAL; + + for (i = 0; i< CLEANUP_LEVEL_NONE; i++) { + if (strcmp(level_str, cleanup_level_str[i]) == 0) + break; + } + + if (i < CLEANUP_LEVEL_NONE) + ret = i; + + return ret; +} + +static int add_config_item(struct json_object *obj, struct cleanup_config *item) +{ + char *temp = NULL; + int ret; + + if (!item) { + _E("Parameter is invalid."); + return -EINVAL; + } + + if (get_config_string_field(obj, "level", &temp) != 0) { + _E("There is no level node."); + return -EINVAL; + } + + item->level = get_cleanup_level(temp); + free(temp); + + if (item->level < 0) { + _E("Invalid level value."); + return -EINVAL; + } + + if (get_config_string_field(obj, "path", &item->path) != 0) + return -EINVAL; + + //todo. + //check duplicated path + + item->exclusion_list = get_config_array_field(obj, "except", &ret); + if (ret != 0) + return -EINVAL; + + //_D("Get config item: level=%d, path=%s, except count=%d", item->level, item->path, g_list_length(item->exclusion_list)); + return 0; +} + +static GList *parsing_json_array_object_to_list(struct json_object *array, int *ret) +{ + int i, len, item_size; + GList *list = NULL; + struct cleanup_config *item = NULL; + struct json_object *obj = NULL; + + if (!json_object_is_type(array, json_type_array)) { + _E("Config value is not an array."); + RESULT(ret, -EINVAL); + return NULL; + } + + len = json_object_array_length(array); + for (i = 0; i < len; ++i) { + obj = json_object_array_get_idx(array, i); + if (!json_object_is_type(obj, json_type_object)) { + _E("Array item is not an object."); + RESULT(ret, -EINVAL); + goto cleanup; + } + + item_size = sizeof(struct cleanup_config); + item = malloc(item_size); + if (!item) { + _E("Memory allocation fail. size=%d", item_size); + RESULT(ret, -ENOMEM); + goto cleanup; + } + memset(item, '\0', item_size); + + if (add_config_item(json_object_get(obj), item) != 0) { + RESULT(ret, -EINVAL); + goto cleanup; + } + list = g_list_append(list, item); + } + RESULT(ret, 0); + return list; +cleanup: + if (item) + free(item); + + g_list_free_full(list, free_config_item); + return NULL; +} + +int load_json_object_with_file(const char *file) +{ + struct json_object *root_node, *array; + const char *root = NULL; + int ret = 0; + + root_node = json_object_from_file(file); + if (root_node == NULL) { + _E("Could not create object from json file '%s'", file); + return -EINVAL; + } + + root = tzplatform_getenv(TZ_SYS_OPT); + if (json_object_object_get_ex(root_node, root, &array)) { + cleanup_list_system = parsing_json_array_object_to_list(array, &ret); + if(ret != 0) + goto cleanup; + _D("'%s' config has %d items.", root, g_list_length(cleanup_list_system)); + } + + root = tzplatform_getenv(TZ_SYS_USER); + if (json_object_object_get_ex(root_node, root, &array)) { + cleanup_list_user = parsing_json_array_object_to_list(array, &ret); + if (ret != 0) + goto cleanup; + _D("'%s' config has %d items.", root, g_list_length(cleanup_list_user)); + } + +cleanup: + json_object_put(root_node); + return ret; +} + +int load_cleanup_config() +{ + int ret = 0; + + ret = access(DEF_CLEANUP_CONFIG_FILE, F_OK|R_OK); + if (ret) { + if (errno == ENOENT) { + _D("Config file doesn't exist '%s'", DEF_CLEANUP_CONFIG_FILE); + return -ENOENT; + } + _E("Could not access config file '%s'", DEF_CLEANUP_CONFIG_FILE); + return -errno; + } + + _D("Using cleanup config file: '%s'", DEF_CLEANUP_CONFIG_FILE); + + ret = load_json_object_with_file(DEF_CLEANUP_CONFIG_FILE); + + return ret; +} + +GList *get_cleanup_config_system() +{ + return cleanup_list_system; +} + +GList *get_cleanup_config_user() +{ + return cleanup_list_user; +} diff --git a/src/storage/cleanup_config.h b/src/storage/cleanup_config.h new file mode 100644 index 0000000..c7614eb --- /dev/null +++ b/src/storage/cleanup_config.h @@ -0,0 +1,45 @@ +/* + * storaged + * + * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STORAGED_CLEANUP_CONFIG_H__ +#define __STORAGED_CLEANUP_CONFIG_H__ + +#include +#include + +enum cleanup_level { + CLEANUP_LEVEL_FULL = 0, + CLEANUP_LEVEL_CRITICAL, + CLEANUP_LEVEL_WARNING, + CLEANUP_LEVEL_NORMAL, + CLEANUP_LEVEL_NONE +}; + +struct cleanup_config { + int level; + char *path; + GList *exclusion_list; +}; + +int load_cleanup_config(); +void free_cleanup_config(); + +GList *get_cleanup_config_system(); +GList *get_cleanup_config_user(); + +#endif /* #define __STORAGED_CLEANUP_CONFIG_H___ */ diff --git a/src/storage/sample-cleanup-storage.conf b/src/storage/sample-cleanup-storage.conf new file mode 100644 index 0000000..5325515 --- /dev/null +++ b/src/storage/sample-cleanup-storage.conf @@ -0,0 +1,30 @@ +{ + "/opt":[ + { + "level":"critical", + "path":"/opt/val/test", + "except":[ + "/opt/val/test/except1", + "/opt/val/test/except2" + ] + } + ], + "/opt/usr":[ + { + "level":"full", + "path":"/opt/usr/logtest" + }, + { + "level":"full", + "path":"/opt/usr/etc/test" + }, + { + "level":"full", + "path":"/opt/usr/etc/test_crash" + }, + { + "level":"critical", + "path":"/opt/usr/data/test_GL" + } + ] +} diff --git a/src/storage/storage.c b/src/storage/storage.c index 24a613f..1badb90 100644 --- a/src/storage/storage.c +++ b/src/storage/storage.c @@ -38,6 +38,7 @@ #include "config-parser.h" #include "module-intf.h" #include "storaged_common.h" +#include "cleanup.h" #define MEMORY_STATUS_TMP_PATH "/tmp" #define MEMORY_STATUS_OPT_PATH "/opt" @@ -185,6 +186,8 @@ out: g_variant_new("(is)", path, value)); if (ret < 0) _E("Failed to send dbus signal"); + + cleanup_storage(path, level); } static void _popup_cb(GVariant *var, void *user_data, GError *err) @@ -721,6 +724,8 @@ static void storage_init(void *data) if (ret < 0) _E("Failed to make directory: %d", errno); + init_cleanup_storage(); + id_storage_poweroff = subscribe_dbus_signal(NULL, DEVICED_PATH_POWEROFF, DEVICED_INTERFACE_POWEROFF, SIGNAL_POWEROFF_STATE, @@ -731,6 +736,7 @@ static void storage_init(void *data) static void storage_exit(void *data) { + free_cleanup_storage(); /* unregister notifier for below each event */ unsubscribe_dbus_signal(NULL, id_storage_poweroff); } -- 2.7.4 From 145d266dc957a0fb5e51a4db7100060e0df6a052 Mon Sep 17 00:00:00 2001 From: Yunmi Ha Date: Tue, 26 Nov 2019 15:44:11 +0900 Subject: [PATCH 09/16] [cleanup] fix printf format for size_t Change-Id: I308f1bc1140f213fd54d7fc4f3bfabf8d3ca83a1 Signed-off-by: Yunmi Ha --- src/storage/cleanup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storage/cleanup.c b/src/storage/cleanup.c index af6e0ec..55b61bf 100644 --- a/src/storage/cleanup.c +++ b/src/storage/cleanup.c @@ -141,7 +141,7 @@ static int cleanup_recursive(const char *path, GList *except) } if (PATH_MAX <= (strlen(path) + strlen(dent->d_name) + 1)) { - _E("File path sould be shorter than %d. But %d.", PATH_MAX, strlen(path) + strlen(dent->d_name) + 1); + _E("File path sould be shorter than %d. But %zu.", PATH_MAX, strlen(path) + strlen(dent->d_name) + 1); continue; } -- 2.7.4 From 0a4f7ab47c2997a8020c2ad29e01eab5f7cea578 Mon Sep 17 00:00:00 2001 From: Yunmi Ha Date: Mon, 2 Dec 2019 10:57:01 +0900 Subject: [PATCH 10/16] block: Improve stability of unmount - Using AddPowerOffWait/RemovePowerOffWait method of deviced. - Change unmount processing order Change-Id: I8754f1d3b732f15c5aa77a2233d918578e9c2aae Signed-off-by: Yunmi Ha --- src/block/block.c | 109 ++++++++++++++++++++++++++++++++++-------------------- src/block/utils.c | 34 ++++++++++++++++- src/block/utils.h | 1 + 3 files changed, 103 insertions(+), 41 deletions(-) diff --git a/src/block/block.c b/src/block/block.c index a718697..acbd1b2 100644 --- a/src/block/block.c +++ b/src/block/block.c @@ -78,6 +78,8 @@ #define TIMEOUT_MAKE_OBJECT 500 /* milliseconds */ #define SIGNAL_POWEROFF_STATE "ChangeState" +#define METHOD_ADD_POWEROFF_WAIT "AddPowerOffWait" +#define METHOD_REMOVE_POWEROFF_WAIT "RemovePowerOffWait" #define BLOCK_DEVICE_ADDED "DeviceAdded" #define BLOCK_DEVICE_REMOVED "DeviceRemoved" @@ -212,6 +214,7 @@ static fd_handler_h phandler; static bool block_control = false; static bool block_boot = false; static pthread_mutex_t pipe_mutex = PTHREAD_MUTEX_INITIALIZER; +static bool add_poweroff_wait = false; /* Assume there is only one physical internal storage */ static int dev_internal = -1; @@ -228,6 +231,7 @@ static void remove_operation(struct block_device *bdev); static void check_removed(struct block_device *bdev, dd_list **queue, struct operation_queue **op); static bool check_unmount(struct block_device *bdev, dd_list **queue, struct operation_queue **op); static int change_mount_point(struct block_device *bdev, const char *mount_point); +static void terminate_threads(void); #define nullstr(x) (x ? x : "") static GVariant *block_data_to_gvariant(struct block_data *data, int flags); @@ -1389,52 +1393,40 @@ static int block_unmount(struct block_device *bdev, _I("Execute force unmount."); /* Force Unmount Scenario */ - while (1) { - switch (retry++) { - case 0: - /* Mobile specific: - * should unmount the below vconf key. */ - if ((data->block_type == BLOCK_MMC_DEV || - data->block_type == BLOCK_EXTENDEDSD_DEV) && - data->primary) { - /* At first, notify to other app - * who already access sdcard */ - _I("Notify to other app who already access sdcard."); - vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS, - VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED); - } - break; - case 1: - /* Second, kill app with SIGTERM */ - _I("Kill app with SIGTERM."); - terminate_process(data->mount_point, false); - break; - case 2: - /* Last time, kill app with SIGKILL */ - _I("Kill app with SIGKILL."); - terminate_process(data->mount_point, true); - break; - default: - if (umount2(data->mount_point, MNT_DETACH) != 0) { - _I("Failed to unmount with lazy option: %d", - errno); - return -errno; - } - goto out; - } - /* it takes some seconds til other app completely clean up */ - time.tv_nsec = 500 * NANO_SECOND_MULTIPLIER; + /* Mobile specific: + * should unmount the below vconf key. */ + if ((data->block_type == BLOCK_MMC_DEV || + data->block_type == BLOCK_EXTENDEDSD_DEV) && + data->primary) { + /* At first, notify to other app + * who already access sdcard */ + _I("Notify to other app who already access sdcard."); + vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS, + VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED); + } + + sync(); + if (umount2(data->mount_point, MNT_DETACH) != 0) { + _I("Failed to unmount with lazy option: %m"); + return -errno; + } + + time.tv_nsec = 500 * NANO_SECOND_MULTIPLIER; + + while (retry++ < UNMOUNT_RETRY) { + _I("Kill app with SIGTERM."); + terminate_process(data->devnode, false); nanosleep(&time, NULL); - print_open_files(data->mount_point); + _I("Kill app with SIGKILL."); + terminate_process(data->devnode, true); + nanosleep(&time, NULL); - r = mmc_check_and_unmount(data->mount_point); - if (!r) { - _D("Success to unmount '%s'.", data->mount_point); + if (!is_in_use_partition(data->devnode)) break; - } } + sync(); out: data->state = BLOCK_UNMOUNT; @@ -2701,6 +2693,16 @@ static void booting_done(void) /* if there is the attached device, try to mount */ block_init_from_udev_enumerate(); + ret = dbus_handle_method_sync(DEVICED_BUS_NAME, + DEVICED_PATH_POWEROFF, + DEVICED_INTERFACE_POWEROFF, + METHOD_ADD_POWEROFF_WAIT, + NULL, NULL); + if (ret < 0) + _E("Failed to call "METHOD_ADD_POWEROFF_WAIT" method."); + else + add_poweroff_wait = true; + block_boot = true; } @@ -2713,6 +2715,8 @@ static void block_poweroff(GDBusConnection *conn, gpointer data) { static int status = 0; + int ret; + if (status > 0) return; status = 1; @@ -2720,6 +2724,19 @@ static void block_poweroff(GDBusConnection *conn, /* unregister mmc uevent control routine */ unregister_udev_uevent_control(&uh); remove_whole_block_device(); + terminate_threads(); + + if (add_poweroff_wait) { + ret = dbus_handle_method_sync(DEVICED_BUS_NAME, + DEVICED_PATH_POWEROFF, + DEVICED_INTERFACE_POWEROFF, + METHOD_REMOVE_POWEROFF_WAIT, + NULL, NULL); + if (ret < 0) + _E("Failed to call "METHOD_REMOVE_POWEROFF_WAIT" method."); + else + add_poweroff_wait = false; + } } static void uevent_block_handler(struct udev_device *dev) @@ -3785,6 +3802,18 @@ static void block_exit(void *data) /* exit pipe */ pipe_exit(); + if (add_poweroff_wait) { + ret = dbus_handle_method_sync(DEVICED_BUS_NAME, + DEVICED_PATH_POWEROFF, + DEVICED_INTERFACE_POWEROFF, + METHOD_REMOVE_POWEROFF_WAIT, + NULL, NULL); + if (ret < 0) + _E("Failed to call "METHOD_REMOVE_POWEROFF_WAIT" method."); + else + add_poweroff_wait = false; + } + block_control = false; } diff --git a/src/block/utils.c b/src/block/utils.c index 909c8a4..1c283ba 100644 --- a/src/block/utils.c +++ b/src/block/utils.c @@ -16,7 +16,7 @@ * limitations under the License. */ - +#define _GNU_SOURCE #include #include #include @@ -127,6 +127,38 @@ int terminate_process(const char *partition, bool force) return run_child(argc, argv); } +//If no process accesses the partition, return false +//If at least one process access the partition, return true +bool is_in_use_partition(const char *partition) +{ + FILE *fp; + char *cmd = NULL; + char *line = NULL; + size_t len = 0; + bool ret = false; + + if (asprintf(&cmd, "/usr/bin/fuser -m %s", partition) < 0) { + _E("Failed to call asprintf: %m"); + return false; + } + + _D("cmd=%s\n", cmd); + fp = popen(cmd, "r"); + free(cmd); + if (fp == NULL) + return false; + + if (getline(&line, &len, fp) != -1) { + if (strtok(line, " ") != NULL) + ret = true; + } + + free(line); + pclose(fp); + + return ret; +} + int mount_check(const char *path) { int ret = false; diff --git a/src/block/utils.h b/src/block/utils.h index 23d058a..6c9f45f 100644 --- a/src/block/utils.h +++ b/src/block/utils.h @@ -25,6 +25,7 @@ int print_open_files(const char *mount_point); int terminate_process(const char *partition, bool force); +bool is_in_use_partition(const char *partition); int mount_check(const char *path); int umount_partition(const char *path, const bool force); -- 2.7.4 From 1d4ada773ed36fcbee054bc47b6c5cec0d55feed Mon Sep 17 00:00:00 2001 From: Yunmi Ha Date: Tue, 28 May 2019 17:09:53 +0900 Subject: [PATCH 11/16] block: Add exfat filesystem for mount Change-Id: I5874518a24b775a1181cb0e3d1220e0ceac15001 Signed-off-by: Yunmi Ha --- src/block/block.c | 8 ++++-- src/block/block.h | 3 +- src/block/exfat.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 src/block/exfat.c diff --git a/src/block/block.c b/src/block/block.c index acbd1b2..f48dede 100644 --- a/src/block/block.c +++ b/src/block/block.c @@ -103,9 +103,10 @@ #define EXTENDEDSD_MOUNT_PATH "/opt/extendedsd" #define VFAT_NAME "vfat" +#define EXFAT_NAME "exfat" #define EXT4_NAME "ext4" #define LUKS_NAME "crypto_LUKS" -#define EXTENDEDSD_NAME "extendedsd" +#define EXTENDEDSD_NAME "extendedsd" /* Minimum value of block id */ #define BLOCK_ID_MIN 10 @@ -1498,6 +1499,8 @@ static int block_format(struct block_data *data, } else fstype = fs_type; } + if (!strcmp(fstype, EXFAT_NAME)) + fstype = VFAT_NAME; fs = NULL; len = strlen(fstype); @@ -1506,14 +1509,13 @@ static int block_format(struct block_data *data, break; } - if (!fs) { + if (!fs || !fs->format) { BLOCK_FLAG_SET(data, FS_NOT_SUPPORTED); _E("Not supported file system(%s).", fstype); return -ENOTSUP; } _I("Format path=%s", data->devnode); - fs->check(data->devnode); r = fs->format(data->devnode); if (r < 0) { _E("Failed to format block data for %s.", data->devnode); diff --git a/src/block/block.h b/src/block/block.h index 3736819..2eb76dc 100644 --- a/src/block/block.h +++ b/src/block/block.h @@ -29,7 +29,8 @@ enum block_fs_type { FS_TYPE_VFAT = 0, - FS_TYPE_EXT4, + FS_TYPE_EXFAT, + FS_TYPE_EXT4 }; struct block_fs_ops { diff --git a/src/block/exfat.c b/src/block/exfat.c new file mode 100644 index 0000000..4a3f8e1 --- /dev/null +++ b/src/block/exfat.c @@ -0,0 +1,83 @@ +/* + * storaged + * + * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "block.h" + +/* guid 10001 - group priv_externalstorage */ +#define FS_EXFAT_MOUNT_OPT "uid=0,gid=10001,dmask=0000,fmask=0111" + +static int exfat_mount(bool smack, const char *devpath, const char *mount_point) +{ + char options[NAME_MAX]; + int r, err, retry = RETRY_COUNT; + struct timespec time = {0,}; + unsigned long mountflags = MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_DIRSYNC; + + if (smack) + snprintf(options, sizeof(options), "%s,%s", FS_EXFAT_MOUNT_OPT, SMACKFS_MOUNT_OPT); + else + snprintf(options, sizeof(options), "%s", FS_EXFAT_MOUNT_OPT); + + do { + r = mount(devpath, mount_point, "exfat", mountflags, options); + if (!r) { + _I("Storage Mounted exfat."); + return 0; + } + + err = errno; + _I("Failed to mount return=%d: %d", r, err); + time.tv_nsec = 100 * NANO_SECOND_MULTIPLIER; + nanosleep(&time, NULL); + if (r < 0 && err == EROFS) + mountflags |= MS_RDONLY; + } while (r < 0 && (err == ENOENT || err == EROFS) && retry-- > 0); + + return -err; +} + +static const struct block_fs_ops exfat_ops = { + .type = FS_TYPE_EXFAT, + .name = "exfat", + .match = NULL, + .check = NULL, + .mount = exfat_mount, + .format = NULL, +}; + +static void __CONSTRUCTOR__ module_init(void) +{ + add_fs(&exfat_ops); +} +/* +static void __DESTRUCTOR__ module_exit(void) +{ + _I("module exit"); + remove_fs(&exfat_ops); +} +*/ -- 2.7.4 From da487169022edd646ee2a6c2dd1ec2ff967ae8e0 Mon Sep 17 00:00:00 2001 From: Yunmi Ha Date: Tue, 24 Dec 2019 11:16:00 +0900 Subject: [PATCH 12/16] block: Move create file logic for block device - After mount, create "/run/external-storage/id" file. Change-Id: I7ba6f8fb94206d742742ac422adad8ce2526eec3 Signed-off-by: Yunmi Ha --- src/block/block.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/block/block.c b/src/block/block.c index f48dede..0c06b66 100644 --- a/src/block/block.c +++ b/src/block/block.c @@ -1020,6 +1020,12 @@ static bool pipe_cb(int fd, void *data) } goto out; } + + if (pdata.op == BLOCK_DEV_MOUNT && (pdata.result == 0)) { + /* Create file for block device /run/external-storage/id */ + create_file(pdata.bdev->data->id, pdata.bdev->data->mount_point, pdata.bdev->data->block_type == BLOCK_EXTENDEDSD_DEV); + } + if (pdata.op == BLOCK_DEV_MOUNT && pdata.bdev->data->state == BLOCK_MOUNT && pdata.bdev->data->block_type == BLOCK_MMC_DEV && @@ -1035,6 +1041,7 @@ static bool pipe_cb(int fd, void *data) if (ret != 0) _E("Failed to popup: %d", ret); } + if (pdata.op == BLOCK_DEV_UNMOUNT) { /* Remove file for block device /run/xxxxxx/id */ remove_file(pdata.bdev->data->id, pdata.bdev->data->block_type == BLOCK_EXTENDEDSD_DEV); @@ -2313,8 +2320,6 @@ static int add_block_device(struct udev_device *dev, const char *devnode, bool m return 0; } - /* Create file for block device /run/external-storage/id */ - create_file(bdev->data->id, bdev->data->mount_point, bdev->data->block_type == BLOCK_EXTENDEDSD_DEV); ret = add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL); if (ret < 0) { _E("Failed to add operation(mount, %s).", devnode); @@ -2879,12 +2884,6 @@ static GVariant *request_mount_block(GDBusConnection *conn, ret = -EPERM; goto out; } - - /* Create /run/external-storage/id file */ - create_file(bdev->data->id, bdev->data->mount_point, false); - } else { - /* Create file for block device /run/external-storage/id */ - create_file(bdev->data->id, bdev->data->mount_point, false); } ret = add_operation(bdev, BLOCK_DEV_MOUNT, invocation, NULL); -- 2.7.4 From c03c32c3891739fc4df0b2e97d8b7521e464d75d Mon Sep 17 00:00:00 2001 From: Yunmi Ha Date: Tue, 24 Dec 2019 16:07:50 +0900 Subject: [PATCH 13/16] Remove 'format-truncation' warning for GCC-9 Change-Id: I1ec0fe9415d76e0d6ce3539a7120fb0069e7f2b5 Signed-off-by: Yunmi Ha --- src/block/block.c | 12 ++++++++++-- src/block/utils.c | 16 +++++++++++++--- src/core/modules.c | 6 +++++- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/block/block.c b/src/block/block.c index 0c06b66..879fdf6 100644 --- a/src/block/block.c +++ b/src/block/block.c @@ -622,7 +622,11 @@ static bool check_primary_partition(const char *devnode) str[len - 1] = '\0'; for (i = 1; i <= 9; ++i) { - snprintf(str2, sizeof(str2), "%s%d", str, i); + if ((ret = snprintf(str2, sizeof(str2), "%s%d", str, i)) > sizeof(str2) - 1) { + _E("Filename is longer than buffer. Need %d size of buffer.", ret + 1); + continue; + } + if (access(str2, R_OK) != 0) continue; @@ -939,7 +943,11 @@ void mmc_make_default_path(const char *mount_path) char mmc_path[FILE_NAME_LEN_MAX + 1] = {0, }; for (i = 0; i < DIR_NUM; ++i) { - snprintf(mmc_path, sizeof(mmc_path), "%s/%s", mount_path, mmc_default_path[i]); + if ((ret = snprintf(mmc_path, sizeof(mmc_path), "%s/%s", mount_path, mmc_default_path[i])) > sizeof(mmc_path) - 1) { + _E("Path is longer than buffer. Need %d size of buffer.", ret + 1); + continue; + } + if (!g_file_test(mmc_path, G_FILE_TEST_IS_DIR)) { _D("Path(%s) did not exist.", mmc_path); ret = mkdir(mmc_path, 0777); diff --git a/src/block/utils.c b/src/block/utils.c index 1c283ba..3588914 100644 --- a/src/block/utils.c +++ b/src/block/utils.c @@ -75,7 +75,10 @@ int print_open_files(const char *mount_point) continue; pid = atoi(dir->d_name); - snprintf(buf, PATH_MAX, "/proc/%d/cmdline", pid); + if ((ret = snprintf(buf, PATH_MAX, "/proc/%d/cmdline", pid)) > PATH_MAX - 1) { + _E("File path is longer than buffer. Need %d size of buffer.", ret + 1); + continue; + } fd = open(buf, O_RDONLY); if (fd < 0) @@ -87,7 +90,11 @@ int print_open_files(const char *mount_point) continue; cmdline[ret] = '\0'; - snprintf(buf, PATH_MAX, "/proc/%d/fd", pid); + if ((ret = snprintf(buf, PATH_MAX, "/proc/%d/fd", pid)) > PATH_MAX - 1) { + _E("File path is longer than buffer. Need %d size of buffer.", ret + 1); + continue; + } + dp_child = opendir(buf); if (!dp_child) continue; @@ -98,7 +105,10 @@ int print_open_files(const char *mount_point) if (ret != 0) break; - snprintf(check_path, PATH_MAX, "%s/%s", buf, dir_child->d_name); + if ((ret = snprintf(check_path, PATH_MAX, "%s/%s", buf, dir_child->d_name)) > PATH_MAX - 1) { + _E("File path is longer than buffer. Need %d size of buffer.", ret + 1); + continue; + } if (readlink(check_path, buf2, PATH_MAX) < 0) continue; diff --git a/src/core/modules.c b/src/core/modules.c index b2ac415..3a84274 100644 --- a/src/core/modules.c +++ b/src/core/modules.c @@ -125,7 +125,11 @@ int modules_init(void *data) if (dir->d_type != DT_REG) continue; - snprintf(path, sizeof(path), "%s/%s", PLUGIN_PATH, dir->d_name); + if ((ret = snprintf(path, sizeof(path), "%s/%s", PLUGIN_PATH, dir->d_name)) > sizeof(path) - 1) { + _E("Module path is longer than buffer. Need %d size of buffer.", ret + 1); + continue; + } + ret = storaged_open_module(path, &plugin); if (ret < 0) { _E("Failed to open module(%s): %d", path, ret); -- 2.7.4 From 5f332487d4b32dbc4de540bbf871e37d28355562 Mon Sep 17 00:00:00 2001 From: Yunmi Ha Date: Mon, 6 Jan 2020 20:32:29 +0900 Subject: [PATCH 14/16] block: Remove duplicated 'DeviceChanged2' dbus signal - No one subscribes to the 'DeviceChanged2' signal. - All data of the 'DeviceChanged2' signal is contained in 'DeviceChange' signal data. Change-Id: I48e6ef3e8423ce856730d2c26087581cc4b384a8 Signed-off-by: Yunmi Ha --- src/block/block.c | 40 ---------------------------------------- 1 file changed, 40 deletions(-) diff --git a/src/block/block.c b/src/block/block.c index 879fdf6..9f0463c 100644 --- a/src/block/block.c +++ b/src/block/block.c @@ -85,7 +85,6 @@ #define BLOCK_DEVICE_REMOVED "DeviceRemoved" #define BLOCK_DEVICE_BLOCKED "DeviceBlocked" #define BLOCK_DEVICE_CHANGED "DeviceChanged" -#define BLOCK_DEVICE_CHANGED_2 "DeviceChanged2" #define BLOCK_TYPE_MMC "mmc" #define BLOCK_TYPE_SCSI "scsi" @@ -236,7 +235,6 @@ static void terminate_threads(void); #define nullstr(x) (x ? x : "") static GVariant *block_data_to_gvariant(struct block_data *data, int flags); -static GVariant *block_data_to_gvariant2(struct block_data *data, int flags); #define block_send_dbus_reply(invocation, result) if (invocation) {g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", result)); } @@ -472,23 +470,6 @@ static void broadcast_device_changed(struct block_device *bdev, param); if (ret < 0) _E("Failed to broadcast device changed signal. op(%d)", op); - - /* broadcast one more signal for mount, unmount, format */ - switch(op) { - case BLOCK_DEV_MOUNT: - case BLOCK_DEV_UNMOUNT: - case BLOCK_DEV_FORMAT: - ret = dbus_handle_emit_dbus_signal(NULL, - STORAGED_PATH_BLOCK_MANAGER, - STORAGED_INTERFACE_BLOCK_MANAGER, - BLOCK_DEVICE_CHANGED_2, - block_data_to_gvariant2(data, flags)); - if (ret < 0) - _E("Failed to broadcast device changed signal. op(%d)", op); - default: - /* do nothing */ - break; - } } static int get_mmc_mount_node(char *devnode, char *node, size_t len) @@ -3185,27 +3166,6 @@ static GVariant *block_data_to_gvariant(struct block_data *data, int flags) data->id); } -static GVariant *block_data_to_gvariant2(struct block_data *data, int flags) -{ - if (!data) - return dbus_handle_new_g_variant_tuple(); - - return g_variant_new("(issssssisibi)", - data->block_type, - nullstr(data->devnode), - nullstr(data->syspath), - nullstr(data->fs_usage), - nullstr(data->fs_type), - nullstr(data->fs_version), - nullstr(data->fs_uuid_enc), - data->readonly, - nullstr(data->mount_point), - data->state, - data->primary, - flags >= 0 ? flags : data->flags); -} - - //static int add_device_to_struct_iter(struct block_data *data, DBusMessageIter *iter) //{ // //DBusMessageIter piter; -- 2.7.4 From 136d8016a80e79e5ae1626c7061a0b5dcb7dd50f Mon Sep 17 00:00:00 2001 From: Yunmi Ha Date: Thu, 6 Feb 2020 16:55:03 +0900 Subject: [PATCH 15/16] Fix svace issue - Remove unreachable code - Replace strtok to strtok_r - Add initialize code Change-Id: Ia17c0dbfc104b839b4debcb3140aa660563ad91d Signed-off-by: Yunmi Ha --- src/block/block.c | 8 +------- src/block/utils.c | 3 ++- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/block/block.c b/src/block/block.c index 9f0463c..6fdc678 100644 --- a/src/block/block.c +++ b/src/block/block.c @@ -2858,12 +2858,6 @@ static GVariant *request_mount_block(GDBusConnection *conn, bdev->on_private_op = REQ_PRIVATE; bdev->private_pid = dbus_handle_get_sender_pid(NULL, sender); _D("Private operation state(%d). pid=%d.", bdev->on_private_op, bdev->private_pid); - } else { - if (bdev->on_private_op != REQ_NORMAL) { - _E("Failed to process mount operation."); - ret = -EPERM; - goto out; - } } /* if requester want to use a specific mount point */ @@ -3423,7 +3417,7 @@ static GVariant *request_get_mmc_primary(GDBusConnection *conn, GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data) { struct block_device *bdev; - struct block_data *data, nodata = {0,}; + struct block_data *data = NULL, nodata = {0,}; dd_list *elem; bool found = false; int i; diff --git a/src/block/utils.c b/src/block/utils.c index 3588914..572cad3 100644 --- a/src/block/utils.c +++ b/src/block/utils.c @@ -146,6 +146,7 @@ bool is_in_use_partition(const char *partition) char *line = NULL; size_t len = 0; bool ret = false; + char *saveptr; if (asprintf(&cmd, "/usr/bin/fuser -m %s", partition) < 0) { _E("Failed to call asprintf: %m"); @@ -159,7 +160,7 @@ bool is_in_use_partition(const char *partition) return false; if (getline(&line, &len, fp) != -1) { - if (strtok(line, " ") != NULL) + if (strtok_r(line, " ", &saveptr) != NULL) ret = true; } -- 2.7.4 From a59af752906449d9c2f6a8a8f4b9e3f0786a1639 Mon Sep 17 00:00:00 2001 From: Hyotaek Shim Date: Fri, 21 Feb 2020 15:23:04 +0900 Subject: [PATCH 16/16] Wait for releasing open files when BLOCK_UNMOUNT Change-Id: I1cb8d450c48e138ae8410c9b06b390da07102ec7 Signed-off-by: Hyotaek Shim --- src/block/block.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/block/block.c b/src/block/block.c index 6fdc678..a11f3f5 100644 --- a/src/block/block.c +++ b/src/block/block.c @@ -1369,7 +1369,6 @@ static int block_unmount(struct block_device *bdev, { struct block_data *data; int r, retry = 0; - struct timespec time = {0,}; if (!bdev || !bdev->data || !bdev->data->mount_point) return -EINVAL; @@ -1396,33 +1395,38 @@ static int block_unmount(struct block_device *bdev, if ((data->block_type == BLOCK_MMC_DEV || data->block_type == BLOCK_EXTENDEDSD_DEV) && data->primary) { - /* At first, notify to other app - * who already access sdcard */ + /* At first, notify to other app who already access sdcard */ _I("Notify to other app who already access sdcard."); vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS, VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED); + + /* Wait for 700 msec to release open files */ + usleep(700 * 1000); } sync(); + if (umount2(data->mount_point, MNT_DETACH) != 0) { _I("Failed to unmount with lazy option: %m"); return -errno; } - time.tv_nsec = 500 * NANO_SECOND_MULTIPLIER; - while (retry++ < UNMOUNT_RETRY) { _I("Kill app with SIGTERM."); terminate_process(data->devnode, false); - nanosleep(&time, NULL); + usleep(500 * 1000); + + if (!is_in_use_partition(data->devnode)) + break; _I("Kill app with SIGKILL."); terminate_process(data->devnode, true); - nanosleep(&time, NULL); + usleep(500 * 1000); if (!is_in_use_partition(data->devnode)) break; } + sync(); out: -- 2.7.4