summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjusung <jusung07.son@samsung.com>2021-05-28 11:10:40 +0900
committerjusung <jusung07.son@samsung.com>2021-05-28 13:49:57 +0900
commit10942c3eafe37e3848621bdae2baf996c2ab25d3 (patch)
treed42329cc2ce7335cbeae9e158195ff56367424b3
parenta51e64889212b4f934f23cf1e87781d6b1197b4f (diff)
downloadbuxton2-10942c3eafe37e3848621bdae2baf996c2ab25d3.tar.gz
buxton2-10942c3eafe37e3848621bdae2baf996c2ab25d3.tar.bz2
buxton2-10942c3eafe37e3848621bdae2baf996c2ab25d3.zip
Add db intergrity check
Change-Id: I5455149b0424a490ad21e31cb6ddfbe3928ae4a4 Signed-off-by: jusung <jusung07.son@samsung.com>
-rw-r--r--backend/sqlite.c183
-rw-r--r--common/backend.h2
-rw-r--r--common/direct.c30
-rw-r--r--common/direct.h3
-rw-r--r--daemon/daemon.c11
5 files changed, 227 insertions, 2 deletions
diff --git a/backend/sqlite.c b/backend/sqlite.c
index 5ec0b7d..c7bf8b6 100644
--- a/backend/sqlite.c
+++ b/backend/sqlite.c
@@ -23,6 +23,8 @@
#include <string.h>
#include <fcntl.h>
#include <stdbool.h>
+#include <sys/stat.h>
+#include <stdio.h>
#include <glib.h>
#include <sqlite3.h>
@@ -34,6 +36,7 @@
#define BUXTON_DEFAULT_WAL_AUTOCHECKPOINT 100
#define BASE_DB_PATH tzplatform_getenv(TZ_SYS_RO_ETC)
+#define MAX_PATH_LEN 512
#define QUERY_MAX_LEN 8192
#define QUERY_CREATE_TABLE_BUXTON "create table if not exists buxton " \
@@ -42,6 +45,7 @@
"PRIMARY KEY(key)) "
static GHashTable *dbs;
+static bool is_db_corrupted;
static void free_db(sqlite3 *db)
{
@@ -310,8 +314,9 @@ static int get_value(const char *dbpath, const char *key, void **data,
r = sqlite3_prepare_v2(db, select_query, strlen(select_query),
&stmt, NULL);
if (r != SQLITE_OK) {
- bxt_err("prepare error, ret = %d, extended = %d\n",
- r, sqlite3_extended_errcode(db));
+ bxt_err("prepare error, ret = %d, extended = %d %s",
+ r, sqlite3_extended_errcode(db),
+ sqlite3_errmsg(db));
return BUXTON_ERROR_IO_ERROR;
}
@@ -612,6 +617,179 @@ end:
return ret;
}
+static int check_integrity_cb(void *pid, int argc, char **argv, char **notUsed)
+{
+ if (strcmp(argv[0], "ok")) {
+ bxt_err("db integrity result : %s", argv[0]);
+ is_db_corrupted = true;
+ return -1;
+ }
+
+ bxt_dbg("db integrity result : %s", argv[0]);
+ return 0;
+}
+
+static void delete_db_file(const char *dbpath)
+{
+ char target_path[MAX_PATH_LEN];
+ int ret;
+
+ bxt_info("delet db file %s", dbpath);
+
+ ret = unlink(dbpath);
+ if (ret != 0)
+ bxt_err("unlink(%s) is failed. errno(%d)", dbpath, ret);
+
+ snprintf(target_path, sizeof(target_path), "%s-shm", dbpath);
+ ret = unlink(target_path);
+ if (ret != 0)
+ bxt_err("unlink(%s) is failed. errno(%d)", target_path, ret);
+
+ snprintf(target_path, sizeof(target_path), "%s-wal", dbpath);
+ ret = unlink(target_path);
+ if (ret != 0)
+ bxt_err("unlink(%s) is failed. errno(%d)", target_path, ret);
+}
+
+/* LCOV_EXCL_START */
+static int recover_corrupted_db(const char *dbpath)
+{
+ int sql_ret;
+ sqlite3 *db;
+
+ bxt_info("DB is corrupted, start to recover corrupted db %s", dbpath);
+
+ delete_db_file(dbpath);
+
+ sql_ret = sqlite3_open_v2(dbpath, &db,
+ SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE,
+ NULL);
+ if (sql_ret != SQLITE_OK) {
+ bxt_err("Failed to open db[%s : %d] %s",
+ dbpath, sql_ret, sqlite3_errmsg(db));
+ return BUXTON_ERROR_IO_ERROR;
+ }
+
+ sql_ret = sqlite3_exec(db, "PRAGMA journal_mode = WAL", NULL, NULL, NULL);
+ if (sql_ret) {
+ bxt_err("change journal mode '%s' failed: %s",
+ dbpath, sqlite3_errmsg(db));
+ sqlite3_close(db);
+ return BUXTON_ERROR_IO_ERROR;
+ }
+
+ sql_ret = sqlite3_exec(db, QUERY_CREATE_TABLE_BUXTON, NULL, NULL, NULL);
+ if (sql_ret != SQLITE_OK) {
+ bxt_err("Create tables '%s' failed: %s",
+ dbpath, sqlite3_errmsg(db));
+
+ sqlite3_close(db);
+ return BUXTON_ERROR_IO_ERROR;
+ }
+
+ sql_ret = sqlite3_wal_autocheckpoint(
+ db, BUXTON_DEFAULT_WAL_AUTOCHECKPOINT);
+ if (sql_ret != SQLITE_OK)
+ bxt_err("SET DEFAULT_WAL_AUTOCHECKPOINT failed : %d", sql_ret);
+
+ sqlite3_close(db);
+
+ return BUXTON_ERROR_NONE;
+}
+/* LCOV_EXCL_STOP */
+
+static int check_integrity(sqlite3 *db)
+{
+ int ret;
+
+ ret = sqlite3_exec(db, "PRAGMA integrity_check",
+ check_integrity_cb, NULL, NULL);
+ if (ret != SQLITE_OK || is_db_corrupted) {
+ bxt_err("Failed to exec query[%d][%s]", ret, sqlite3_errmsg(db));
+ return BUXTON_ERROR_IO_ERROR;
+ }
+ return BUXTON_ERROR_NONE;
+}
+
+static int check_table(sqlite3 *db)
+{
+ int ret;
+ int count = 0;
+ const char query[] =
+ "SELECT count(name) FROM sqlite_master WHERE type='table'";
+ sqlite3_stmt *stmt;
+
+ ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ bxt_err("prepare error: %s", sqlite3_errmsg(db));
+ return BUXTON_ERROR_IO_ERROR;
+ }
+
+ ret = sqlite3_step(stmt);
+ if(ret == SQLITE_ROW)
+ count = sqlite3_column_int(stmt, 0);
+
+ if (count == 0) {
+ bxt_err("table error: %d", ret);
+ ret = BUXTON_ERROR_IO_ERROR;
+ } else {
+ ret = BUXTON_ERROR_NONE;
+ }
+
+ sqlite3_finalize(stmt);
+
+ return ret;
+}
+
+static int check_owner(const char *dbpath)
+{
+ struct stat info;
+
+ stat(dbpath, &info);
+ if (info.st_uid != getuid()) {
+ bxt_err("invalid owner [%d : %d]", getuid(), info.st_uid);
+ return BUXTON_ERROR_IO_ERROR;
+ }
+
+ return BUXTON_ERROR_NONE;
+}
+
+static int check_db(const char *dbpath)
+{
+ int ret;
+ sqlite3 *db;
+
+ ret = sqlite3_open_v2(dbpath, &db,
+ SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
+ if (ret != SQLITE_OK) {
+ bxt_err("Failed to open db[%s : %d] %s",
+ dbpath, ret, sqlite3_errmsg(db));
+ ret = BUXTON_ERROR_IO_ERROR;
+ goto out;
+ }
+
+ ret = check_owner(dbpath);
+ if (ret != BUXTON_ERROR_NONE)
+ goto out;
+
+ ret = check_integrity(db);
+ if (ret != BUXTON_ERROR_NONE)
+ goto out;
+
+ ret = check_table(db);
+ if (ret != BUXTON_ERROR_NONE)
+ goto out;
+
+out:
+ if (db)
+ sqlite3_close(db);
+
+ if (ret != BUXTON_ERROR_NONE)
+ ret = recover_corrupted_db(dbpath);
+
+ return ret;
+}
+
static void module_exit(void)
{
g_hash_table_destroy(dbs);
@@ -644,5 +822,6 @@ DEFINE_BUXTON_BACKEND = {
.unset_value = unset_value,
.list_keys = list_keys,
.get_dump = get_dump,
+ .check_db = check_db,
};
diff --git a/common/backend.h b/common/backend.h
index 7db0627..db51677 100644
--- a/common/backend.h
+++ b/common/backend.h
@@ -40,6 +40,7 @@ typedef int (*backend_list_keys)(const char *dbpath,
char ***keys, unsigned int *klen, bool readonly);
typedef int (*backend_get_dump)(const char *dbpath,
char ***keys, void ***values, int **value_len, unsigned int *klen);
+typedef int (*backend_check_db)(const char *dbpath);
struct backend {
const char *name;
@@ -55,6 +56,7 @@ struct backend {
backend_unset_value unset_value;
backend_list_keys list_keys;
backend_get_dump get_dump;
+ backend_check_db check_db;
void *reserved[7];
};
diff --git a/common/direct.c b/common/direct.c
index cabc3a9..bebb250 100644
--- a/common/direct.c
+++ b/common/direct.c
@@ -757,6 +757,36 @@ void direct_exit(void)
backend_exit();
}
+int direct_db_check(const char *layer_name)
+{
+ int r;
+ const struct layer *ly;
+ const struct backend *backend;
+ char path[FILENAME_MAX];
+
+ r = conf_get_layer(layer_name, &ly);
+ if (r != BUXTON_ERROR_NONE)
+ return r;
+
+ r = backend_get(ly->backend, &backend);
+ if (r != BUXTON_ERROR_NONE)
+ return r;
+
+ if (!backend->check_db) {
+ bxt_err("backend '%s' has no db_check func",
+ backend->name);
+ return BUXTON_ERROR_INVALID_OPERATION;
+ }
+
+ r = get_path(0, LAYER_ATTRIBUTE_RW, ly, path, sizeof(path));
+ if (r != BUXTON_ERROR_NONE)
+ return r;
+
+ r = backend->check_db(path);
+
+ return r;
+}
+
int direct_init(const char *moddir, const char *confpath, bool *log_on, int *max_line)
{
int r;
diff --git a/common/direct.h b/common/direct.h
index b8f3385..1dc7af2 100644
--- a/common/direct.h
+++ b/common/direct.h
@@ -44,3 +44,6 @@ int direct_remove_db(const struct buxton_layer *layer);
int direct_dump(const struct buxton_layer *layer,
char ***key_list, struct buxton_value **value_list, int *len);
+
+int direct_db_check(const char *layer_name);
+
diff --git a/daemon/daemon.c b/daemon/daemon.c
index 903bfd6..bd01d67 100644
--- a/daemon/daemon.c
+++ b/daemon/daemon.c
@@ -46,6 +46,9 @@
#define BXT_LOG_FOLDER "/run/buxton2/log"
#define BXT_NULL_STRING "(VCONF_NULL)"
+#define BXT_SYSTEM_DB_LAYER "system"
+#define BXT_SYSTEM_MEMORY_LAYER "memory"
+
static int _log_max_line = 2000;
static bool _log_on = true;
@@ -1129,6 +1132,14 @@ static int bxt_init(struct bxt_daemon *bxtd, const char *confpath)
if (r != BUXTON_ERROR_NONE)
return r;
+ r = direct_db_check(BXT_SYSTEM_DB_LAYER);
+ if (r != BUXTON_ERROR_NONE)
+ return r;
+
+ r = direct_db_check(BXT_SYSTEM_MEMORY_LAYER);
+ if (r != BUXTON_ERROR_NONE)
+ return r;
+
bxtd->sk = sock_get_server(SOCKPATH);
if (bxtd->sk < 0)
return bxtd->sk;