Add db recovery tool 36/221736/4
authorHwankyu Jhun <h.jhun@samsung.com>
Tue, 7 Jan 2020 07:11:51 +0000 (16:11 +0900)
committerHwankyu Jhun <h.jhun@samsung.com>
Tue, 7 Jan 2020 23:39:19 +0000 (08:39 +0900)
Adds:
 - appsvc-db-recovery
 - component-db-recovery

Change-Id: I5db587cef2b177f518aa03d48455f751df759f86
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
CMakeLists.txt
packaging/aul.spec
src/aul_db.c
src/aul_db.h
tool/CMakeLists.txt
tool/recovery/CMakeLists.txt [new file with mode: 0644]
tool/recovery/appsvc_db_recovery.c [new file with mode: 0644]
tool/recovery/component_db_recovery.c [new file with mode: 0644]

index 4b66e23..5e1b8d5 100755 (executable)
@@ -12,21 +12,23 @@ ADD_DEFINITIONS("-DSHARE_PREFIX=\"${SHARE_INSTALL_PREFIX}/aul\"")
 # Set required packages
 INCLUDE(FindPkgConfig)
 SET(AUL-1_LIB_PKG_CHECK_MODULES
-       dlog
        bundle
-       xdgmime
-       libtzplatform-config
-       pkgmgr-info
        capi-system-info
-       vconf
-       sqlite3
-       iniparser
+       dlog
        gio-2.0
        glib-2.0
+       iniparser
+       libsmack
+       libtzplatform-config
        libxml-2.0
-       ttrace
+       pkgmgr-info
+       sqlite3
        storage
-       uuid)
+       ttrace
+       uuid
+       vconf
+       xdgmime
+       )
 pkg_check_modules(libpkgs REQUIRED ${AUL-1_LIB_PKG_CHECK_MODULES})
 
 FOREACH(flag ${libpkgs_CFLAGS})
index e7f0660..a3427e7 100755 (executable)
@@ -32,6 +32,7 @@ BuildRequires:  pkgconfig(ttrace)
 BuildRequires:  pkgconfig(pkgmgr-installer)
 BuildRequires:  pkgconfig(libxml-2.0)
 BuildRequires:  pkgconfig(uuid)
+BuildRequires:  pkgconfig(libsmack)
 
 Recommends: amd
 Recommends: amd-mod-component-manager
@@ -146,6 +147,8 @@ chsmack -a 'User::Home' %{TZ_SYS_DB}/.component.db-journal
 %{_bindir}/appid2pid
 %{_bindir}/launch_debug
 %{_bindir}/compmgr_tool
+%{_bindir}/appsvc-db-recovery
+%{_bindir}/component-db-recovery
 %{_datadir}/aul/miregex/*
 %{_datadir}/aul/preexec_list.txt
 %{_datadir}/appsvc/*
index 2b45fc4..2b953e1 100644 (file)
  */
 
 #define _GNU_SOURCE
-#include <stdio.h>
 #include <linux/limits.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <sys/smack.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <tzplatform_config.h>
 
 #include "aul_db.h"
@@ -77,6 +81,22 @@ sqlite3 *aul_db_open(const char *path, bool readonly)
        return db;
 }
 
+sqlite3 *aul_db_create(const char *path)
+{
+       sqlite3 *db;
+       int ret;
+
+       ret = sqlite3_open_v2(path, &db,
+                       SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
+       if (ret != SQLITE_OK) {
+               _E("sqlite3_open_v2() is failed. error(%d)", ret);
+               sqlite3_close_v2(db);
+               return NULL;
+       }
+
+       return db;
+}
+
 void aul_db_close(sqlite3 *db)
 {
        sqlite3_close_v2(db);
@@ -97,3 +117,249 @@ int aul_db_save_column_str(sqlite3_stmt *stmt, int idx, char **str)
 
        return 0;
 }
+
+static int __integrity_check(sqlite3 *db)
+{
+       const char query[] = "PRAGMA integrity_check";
+       sqlite3_stmt *stmt = NULL;
+       const char *res;
+       int ret;
+
+       ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
+       if (ret != SQLITE_OK) {
+               LOGE("sqlite3_prepare_v2() is failed. error(%s)",
+                               sqlite3_errmsg(db));
+               return -1;
+       }
+
+       ret = sqlite3_step(stmt);
+       if (ret != SQLITE_ROW) {
+               LOGE("sqlite3_step() is failed. error(%s)", sqlite3_errmsg(db));
+               sqlite3_finalize(stmt);
+               return -1;
+       }
+
+       res = (const char *)sqlite3_column_text(stmt, 0);
+       if (!res) {
+               LOGE("Failed to check integrity db. error(%s)",
+                               sqlite3_errmsg(db));
+               sqlite3_finalize(stmt);
+               return -1;
+       }
+
+       if (strcmp(res, "ok") != 0) {
+               sqlite3_finalize(stmt);
+               return -1;
+       }
+
+       sqlite3_finalize(stmt);
+
+       return 0;
+}
+
+static int __check_table(sqlite3 *db, const char **tables, int table_count)
+{
+       const char query[] = "SELECT name FROM sqlite_master "
+               "WHERE type='table' ORDER BY name ASC";
+       sqlite3_stmt *stmt = NULL;
+       const char *val;
+       int count = 0;
+
+       __PREPARE_V2(db, query, strlen(query), stmt);
+
+       while (sqlite3_step(stmt) == SQLITE_ROW && count < table_count) {
+               val = (const char *)sqlite3_column_text(stmt, 0);
+               if (val) {
+                       _W("%s %s", val, tables[count]);
+                       if (strcmp(tables[count], val) != 0)
+                               continue;
+                       count++;
+               }
+       }
+
+       sqlite3_finalize(stmt);
+
+       if (count != table_count) {
+               _E("Wrong table count(%d:%d)", count, table_count);
+               return -1;
+       }
+
+       return 0;
+}
+
+int aul_db_verify(const char *path, const char **tables, int table_count)
+{
+       sqlite3 *db;
+       int ret;
+
+       if (!path) {
+               _E("Invalid parameter");
+               return -1;
+       }
+
+       ret = access(path, F_OK);
+       if (ret != 0) {
+               _E("%s does not exists. errno(%d)", path, errno);
+               return -1;
+       }
+
+       db = aul_db_open(path, true);
+       if (!db) {
+               _E("Failed to open database(%s)", path);
+               return -1;
+       }
+
+       ret = __integrity_check(db);
+       if (ret != 0) {
+               _E("Database(%s) is corrupted", path);
+               aul_db_close(db);
+               return -1;
+       }
+
+       ret = __check_table(db, tables, table_count);
+       aul_db_close(db);
+       if (ret != 0) {
+               _E("Database(%s) is corrupted", path);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __change_permission(const char *path)
+{
+       mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
+       char path_db_journal[PATH_MAX];
+       int ret;
+
+       ret = chmod(path, mode);
+       if (ret != 0) {
+               _E("chmod() is failed. errno(%d)", errno);
+               return -1;
+       }
+
+       snprintf(path_db_journal, sizeof(path_db_journal), "%s-journal", path);
+       ret = chmod(path_db_journal, mode);
+       if (ret != 0) {
+               _E("chmod() is failed. errno(%d)", errno);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __change_ownership(const char *path, uid_t uid)
+{
+#define ROOT_UID 0
+       struct passwd pwd;
+       struct passwd *result;
+       char path_db_journal[PATH_MAX];
+       char buf[PATH_MAX];
+       uid_t new_uid;
+       int ret;
+
+       ret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
+       if (result == NULL) {
+               if (ret == 0)
+                       _E("No such user(%u)", uid);
+               else
+                       _E("getpwuid_r() is failed. errno(%d)", errno);
+               return -1;
+       }
+
+       if (pwd.pw_uid == tzplatform_getuid(TZ_SYS_GLOBALAPP_USER))
+               new_uid = ROOT_UID;
+       else
+               new_uid = pwd.pw_uid;
+
+       ret = chown(path, new_uid, pwd.pw_gid);
+       if (ret != 0) {
+               _E("chown() is failed. errno(%d)", errno);
+               return -1;
+       }
+
+       snprintf(path_db_journal, sizeof(path_db_journal), "%s-journal", path);
+       ret = chown(path_db_journal, new_uid, pwd.pw_gid);
+       if (ret != 0) {
+               _E("chown() is failed. errno(%d)", errno);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __change_smack(const char *path)
+{
+#define DB_LABEL "User::Home"
+       char path_db_journal[PATH_MAX];
+       int ret;
+
+       ret = smack_setlabel(path, DB_LABEL, SMACK_LABEL_ACCESS);
+       if (ret != 0) {
+               _E("smack_setlabel() is failed. error(%d)", ret);
+               return -1;
+       }
+
+       snprintf(path_db_journal, sizeof(path_db_journal), "%s-journal", path);
+       ret = access(path_db_journal, F_OK);
+       if (ret == 0) {
+               ret = smack_setlabel(path_db_journal, DB_LABEL,
+                               SMACK_LABEL_ACCESS);
+               if (ret != 0) {
+                       _E("smack_setlabel() is failed. error(%d)", ret);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+int aul_db_recovery(const char *path, const char *query, uid_t uid)
+{
+       char *errmsg = NULL;
+       sqlite3 *db;
+       int ret;
+
+       if (!path || !query) {
+               _E("Invalid parameter");
+               return -1;
+       }
+
+       ret = access(path, F_OK);
+       if (ret == 0)
+               unlink(path);
+
+       db = aul_db_create(path);
+       if (!db) {
+               _E("Failed to open database(%s)", path);
+               return -1;
+       }
+
+       ret = sqlite3_exec(db, query, NULL, NULL, &errmsg);
+       aul_db_close(db);
+       if (ret != SQLITE_OK) {
+               _E("sqlite3_exec() is failed. error(%d:%s)", ret, errmsg);
+               sqlite3_free(errmsg);
+               return -1;
+       }
+
+       ret = __change_smack(path);
+       if (ret != 0) {
+               _E("Failed to change smack label of %s", path);
+               return -1;
+       }
+
+       ret = __change_ownership(path, uid);
+       if (ret != 0) {
+               _E("Failed to change ownership of %s", path);
+               return -1;
+       }
+
+       ret = __change_permission(path);
+       if (ret != 0) {
+               _E("Failed to change permissions of %s", path);
+               return -1;
+       }
+
+       return 0;
+}
index 191804c..684f4dd 100644 (file)
@@ -70,6 +70,10 @@ void aul_db_close(sqlite3* db);
 
 int aul_db_save_column_str(sqlite3_stmt *stmt, int idx, char **str);
 
+int aul_db_verify(const char *path, const char **tables, int table_count);
+
+int aul_db_recovery(const char *path, const char *query, uid_t uid);
+
 #ifdef __cplusplus
 }
 #endif
index 3b38b63..b3cd133 100644 (file)
@@ -60,3 +60,5 @@ add_executable(compmgr_tool
                compmgr_tool.c)
 target_link_libraries(compmgr_tool aul ${pkgs_LDFLAGS} "-pie")
 INSTALL(TARGETS compmgr_tool DESTINATION bin)
+
+ADD_SUBDIRECTORY(recovery)
diff --git a/tool/recovery/CMakeLists.txt b/tool/recovery/CMakeLists.txt
new file mode 100644 (file)
index 0000000..020c5eb
--- /dev/null
@@ -0,0 +1,34 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+PROJECT(aul-db-recovery C)
+
+SET(PREFIX "${CMAKE_INSTALL_PREFIX}")
+SET(EXEC_PREFIX "\${prefix}")
+SET(PROJECT_NAME "${PROJECT_NAME}")
+SET(LIBDIR ${LIB_INSTALL_DIR})
+SET(INCLUDEDIR "\${prefix}/include")
+SET(VERSION ${FULLVER})
+
+INCLUDE(FindPkgConfig)
+SET(requires "dlog sqlite3 libsmack libtzplatform-config")
+pkg_check_modules(aul-db-recovery REQUIRED ${requires})
+
+FOREACH(flag ${aul-db-recovery_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -Wall -Werror -Winline")
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../../src)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../../include)
+
+ADD_EXECUTABLE(appsvc-db-recovery
+       ${CMAKE_CURRENT_SOURCE_DIR}/appsvc_db_recovery.c
+       ${CMAKE_CURRENT_SOURCE_DIR}/../../src/aul_db.c)
+TARGET_LINK_LIBRARIES(appsvc-db-recovery ${aul-db-recovery_LDFLAGS} "-pie")
+INSTALL(TARGETS appsvc-db-recovery DESTINATION bin)
+
+ADD_EXECUTABLE(component-db-recovery
+       ${CMAKE_CURRENT_SOURCE_DIR}/component_db_recovery.c
+       ${CMAKE_CURRENT_SOURCE_DIR}/../../src/aul_db.c)
+TARGET_LINK_LIBRARIES(component-db-recovery ${aul-db-recovery_LDFLAGS} "-pie")
+INSTALL(TARGETS component-db-recovery DESTINATION bin)
+
diff --git a/tool/recovery/appsvc_db_recovery.c b/tool/recovery/appsvc_db_recovery.c
new file mode 100644 (file)
index 0000000..d28a073
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2020 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <tzplatform_config.h>
+
+#include "aul_db.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#define ROOT_UID 0
+
+#define QUERY_CREATE_APPSVC                                                    \
+        "PRAGMA journal_mode = PERSIST;\n"                                     \
+        "CREATE TABLE IF NOT EXISTS appsvc (\n"                                \
+        "  operation TEXT,\n"                                                  \
+        "  mime_type TEXT DEFAULT 'NULL',\n"                                   \
+        "  uri TEXT DEFAULT 'NULL',\n"                                         \
+        "  pkg_name TEXT,\n"                                                   \
+        "  PRIMARY KEY (operation,mime_type,uri)\n"                            \
+        ");\n"                                                                 \
+        "CREATE TABLE IF NOT EXISTS alias_info (\n"                            \
+        "  alias_appid TEXT NOT NULL,\n"                                       \
+        "  appid TEXT NOT NULL,\n"                                             \
+        "  enable TEXT NOT NULL DEFAULT 'true',\n"                             \
+        "  PRIMARY KEY (alias_appid)\n"                                        \
+        ");\n"                                                                 \
+        "CREATE TABLE IF NOT EXISTS alias_info_for_uid (\n"                    \
+        "  appid TEXT NOT NULL,\n"                                             \
+        "  uid INTEGER NOT NULL,\n"                                            \
+        "  is_enabled TEXT NOT NULL DEFAULT 'false',\n"                        \
+        "  PRIMARY KEY (appid, uid)\n"                                         \
+        "  FOREIGN KEY (appid)\n"                                              \
+        "  REFERENCES alias_info(appid)\n"                                     \
+        "  ON DELETE CASCADE\n"                                                \
+        ");\n"                                                                 \
+        "CREATE TRIGGER IF NOT EXISTS update_alias_info_for_uid\n"             \
+        "  AFTER UPDATE ON alias_info_for_uid\n"                               \
+        "  BEGIN\n"                                                            \
+        "    DELETE FROM alias_info_for_uid\n"                                 \
+        "    WHERE is_enabled='true';\n"                                       \
+        "  END;\n"                                                             \
+        "CREATE TABLE IF NOT EXISTS allowed_info (\n"                          \
+        "  appid TEXT NOT NULL,\n"                                             \
+        "  allowed_appid TEXT NOT NULL,\n"                                     \
+        "  PRIMARY KEY (appid, allowed_appid)\n"                               \
+        ");"
+
+static int __check_db_integrity(uid_t uid)
+{
+       static const char *tables[] = {
+               "alias_info",
+               "alias_info_for_uid",
+               "allowed_info",
+               "appsvc",
+       };
+       char *db_path;
+       int ret;
+
+       db_path = aul_db_get_path(".appsvc.db", uid);
+       if (!db_path) {
+               _E("Failed to get db path");
+               return -1;
+       }
+
+       ret = aul_db_verify(db_path, tables, ARRAY_SIZE(tables));
+       if (ret == 0) {
+               free(db_path);
+               return 0;
+       }
+
+       ret = aul_db_recovery(db_path, QUERY_CREATE_APPSVC, uid);
+       if (ret != 0) {
+               printf("Failed to recovery %s\n", db_path);
+               free(db_path);
+               return -1;
+       }
+       free(db_path);
+
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       int ret;
+
+       if (getuid() != ROOT_UID) {
+               fprintf(stderr, "Only root user can run this tool\n");
+               return -1;
+       }
+
+       ret = __check_db_integrity(tzplatform_getuid(TZ_SYS_GLOBALAPP_USER));
+       if (ret != 0)
+               return -1;
+
+       ret = __check_db_integrity(tzplatform_getuid(TZ_SYS_DEFAULT_USER));
+       if (ret != 0)
+               return -1;
+
+       printf("appsvc DB recovery process done\n");
+
+       return 0;
+}
diff --git a/tool/recovery/component_db_recovery.c b/tool/recovery/component_db_recovery.c
new file mode 100644 (file)
index 0000000..86f49cb
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2020 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <tzplatform_config.h>
+
+#include "aul_db.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#define ROOT_UID 0
+
+#define QUERY_CREATE_COMPONENT                                                 \
+        "PRAGMA journal_mode = PERSIST;\n"                                     \
+        "CREATE TABLE IF NOT EXISTS component_info (\n"                        \
+        "  package TEXT NOT NULL,\n"                                           \
+        "  app_id TEXT NOT NULL,\n"                                            \
+        "  component_id TEXT NOT NULL,\n"                                      \
+        "  component_type TEXT NOT NULL,\n"                                    \
+        "  component_launch_mode TEXT NOT NULL,\n"                             \
+        "  component_main TEXT NOT NULL,\n"                                    \
+        "  component_icon_display NOT NULL,\n"                                 \
+        "  component_taskmanage NOT NULL,\n"                                   \
+        "  PRIMARY KEY (component_id)\n"                                       \
+        ");\n"                                                                 \
+        "CREATE TABLE IF NOT EXISTS component_localized_info (\n"              \
+        "  component_id TEXT NOT NULL,\n"                                      \
+        "  component_locale TEXT NOT NULL DEFAULT 'No Locale',\n"              \
+        "  component_label TEXT,\n"                                            \
+        "  component_icon TEXT,\n"                                             \
+        "  PRIMARY KEY (component_id, component_locale)\n"                     \
+        "  FOREIGN KEY (component_id)\n"                                       \
+        "  REFERENCES component_info(component_id) ON DELETE CASCADE\n"        \
+        ");"
+
+static int __check_db_integrity(uid_t uid)
+{
+       static const char *tables[] = {
+               "component_info",
+               "component_localized_info",
+       };
+       char *db_path;
+       int ret;
+
+       db_path = aul_db_get_path(".component.db", uid);
+       if (!db_path) {
+               _E("Failed to get db path");
+               return -1;
+       }
+
+       ret = aul_db_verify(db_path, tables, ARRAY_SIZE(tables));
+       if (ret == 0) {
+               free(db_path);
+               return 0;
+       }
+
+       ret = aul_db_recovery(db_path, QUERY_CREATE_COMPONENT, uid);
+       if (ret != 0) {
+               printf("Failed to recovery %s\n", db_path);
+               free(db_path);
+               return -1;
+       }
+
+       free(db_path);
+
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       int ret;
+
+       if (getuid() != ROOT_UID) {
+               fprintf(stderr, "Only root user can run this tool\n");
+               return -1;
+       }
+
+       ret = __check_db_integrity(tzplatform_getuid(TZ_SYS_GLOBALAPP_USER));
+       if (ret != 0)
+               return -1;
+
+       ret = __check_db_integrity(tzplatform_getuid(TZ_SYS_DEFAULT_USER));
+       if (ret != 0)
+               return -1;
+
+       printf("component DB recovery process done\n");
+
+       return 0;
+}