Release version 0.25.2
[platform/core/appfw/pkgmgr-info.git] / tool / pkg-db-recovery.c
index 650f3c0..f48d2b4 100644 (file)
@@ -20,6 +20,7 @@
 
 #define _GNU_SOURCE
 
+#include <ctype.h>
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -39,6 +40,7 @@
 #include <tzplatform_config.h>
 
 #include <pkgmgr_parser_db.h>
+#include <pkgmgr_parser_db_queries.h>
 
 #ifdef LOG_TAG
 #undef LOG_TAG
@@ -69,6 +71,27 @@ typedef struct user_info {
 
 static GList *user_info_list;
 
+char *string_trim_inplace(char *s) {
+       char *original = s;
+       size_t len = 0;
+
+       while (isspace((unsigned char) *s))
+               s++;
+
+       if (*s) {
+               char *p = s;
+               while (*p)
+                       p++;
+               while (isspace((unsigned char) *(--p)));
+               p[1] = '\0';
+               len = (size_t) (p - s + 1);
+       }
+
+       if (len > MAX_QUERY_LEN)
+               return NULL;
+       return (s == original) ? s : memmove(original, s, len + 1);
+}
+
 static char *__get_dbpath(uid_t uid)
 {
        const char *db_path;
@@ -350,12 +373,134 @@ static void _get_user_list()
 
                info->uid = uid;
                info->db_path = __get_dbpath(uid);
-               user_info_list = g_list_append(user_info_list, info);
+               user_info_list = g_list_prepend(user_info_list, info);
        }
 
        closedir(dir);
 }
 
+static bool __check_db_schema(const char *db_path,
+               const char **db_tables, const char **init_queries) {
+       int ret = -1;
+       int i;
+       sqlite3_stmt *stmt = NULL;
+       const char *check_result;
+       char *schema_in_library, *schema_in_db;
+       static const char table_schema_query[] =
+                       "SELECT sql from sqlite_master WHERE name=?";
+       sqlite3 *db;
+       char *schema_lib_tmp;
+       char *schema_lib_ptr;
+       char *schema_db_tmp;
+       char *schema_db_ptr;
+       char *line_db;
+       char *line_library;
+
+       ret = sqlite3_open_v2(db_path, &db,
+                       SQLITE_OPEN_READONLY, NULL);
+       if (ret != SQLITE_OK) {
+               LOGE("Failed to open db");
+               sqlite3_close_v2(db);
+               return false;
+       }
+
+       ret = sqlite3_busy_handler(db, __db_busy_handler, NULL);
+       if (ret != SQLITE_OK) {
+               LOGE("failed to register busy handler: %s",
+                               sqlite3_errmsg(db));
+               sqlite3_close_v2(db);
+               return ret;
+       }
+       for (i = 0; db_tables[i] != NULL; i++) {
+               ret = sqlite3_prepare_v2(db, table_schema_query,
+                               strlen(table_schema_query), &stmt, NULL);
+               if (ret != SQLITE_OK) {
+                       LOGE("Failed to check db schema : %s",
+                                       sqlite3_errmsg(db));
+                       goto err;
+               }
+
+               ret = sqlite3_bind_text(stmt, 1,
+                               db_tables[i],-1, SQLITE_STATIC);
+
+               ret = sqlite3_step(stmt);
+               if (ret != SQLITE_ROW) {
+                       LOGE("Failed to check db schema :%s",
+                                       sqlite3_errmsg(db));
+                       goto err;
+               }
+
+               check_result = (const char *)sqlite3_column_text(stmt, 0);
+               if (!check_result) {
+                       LOGE("Failed to check db schema :%s",
+                                       sqlite3_errmsg(db));
+                       goto err;
+               }
+
+               schema_in_library = strstr(init_queries[i], db_tables[i]);
+               if (schema_in_library == NULL) {
+                       LOGE("Failed to get initialization query from library");
+                       goto err;
+               }
+               schema_lib_tmp = strdup(schema_in_library);
+               schema_lib_ptr = schema_lib_tmp;
+               if (schema_lib_tmp == NULL) {
+                       LOGE("Out of memory");
+                       goto err;
+               }
+
+               schema_in_db = strstr(check_result, db_tables[i]);
+               if (schema_in_db == NULL) {
+                       LOGE("Failed to get initialization query from db");
+                       free(schema_lib_ptr);
+                       goto err;
+               }
+               schema_db_tmp = strdup(schema_in_db);
+               schema_db_ptr = schema_db_tmp;
+               if (schema_db_tmp == NULL) {
+                       LOGE("Out of memory");
+                       free(schema_lib_ptr);
+                       goto err;
+               }
+
+               while (true) {
+                       line_db = strsep(&schema_db_tmp, ",");
+                       line_library = strsep(&schema_lib_tmp, ",");
+                       if (line_db == NULL || line_library == NULL)
+                               break;
+
+                       if (string_trim_inplace(line_db) == NULL ||
+                                       string_trim_inplace(line_library) == NULL)
+                               break;
+
+                       ret = strcmp(string_trim_inplace(line_db),
+                                       string_trim_inplace(line_library));
+                       if (ret != 0)
+                               break;
+               }
+
+               free(schema_lib_ptr);
+               free(schema_db_ptr);
+
+               if (ret != 0) {
+                       LOGE("Broken schema detected in table[%s], query[%s]",
+                                       db_tables[i], schema_in_db);
+                       goto err;
+               }
+
+               sqlite3_finalize(stmt);
+               stmt = NULL;
+       }
+
+       sqlite3_close(db);
+       return true;
+
+err:
+       sqlite3_finalize(stmt);
+       sqlite3_close(db);
+       return false;
+}
+
 static void _check_db()
 {
        int need_recovery = false;
@@ -369,6 +514,14 @@ static void _check_db()
        } else if (__check_aborted(GLOBAL_USER)) {
                LOGE("Previous recovery was aborted. restore entire pkgmgr db");
                need_recovery = true;
+       } else if (!__check_db_schema(PKGMGR_PARSER_DB_FILE,
+                       PARSER_TABLES, PARSER_INIT_QUERIES)) {
+               LOGE("Global parser db schema was broken. restore entire pkgmgr db");
+               need_recovery = true;
+       } else if (!__check_db_schema(PKGMGR_CERT_DB_FILE,
+                       CERT_TABLES, CERT_INIT_QUERIES)) {
+               LOGE("Cert db schema was broken. restore entire pkgmgr db");
+               need_recovery = true;
        }
 
        if (need_recovery) {