Change backup db logic 36/275236/1
authorIlho Kim <ilho159.kim@samsung.com>
Mon, 31 May 2021 09:56:19 +0000 (18:56 +0900)
committerIlho Kim <ilho159.kim@samsung.com>
Wed, 18 May 2022 08:37:06 +0000 (17:37 +0900)
 - Change to using sqlite3_backup api for making backup db
 - Try integrity check before restore backup db
   and if integrity check fail, the backup is cleared and continue to upgrade
 - Delete backup db when upgrade operation has failed

Change-Id: I77b8c2c197255b3aab4a44671df89d2b3652b289
Signed-off-by: Ilho Kim <ilho159.kim@samsung.com>
(cherry picked from commit 58634349e7c8372cd4f0748f61f4eb51a7cf3b9c)

src/pkg_upgrade.c

index f8cf7b7816a91762d5532b0c5d26013bfd5aa2af..b5f0e422a006fdfc9307e11a3e8a516c1cd7d4dd 100644 (file)
        tzplatform_mkpath(TZ_SYS_GLOBALUSER_DATA, \
        "pkgmgr/fota/.all_preload_rw_list")
 #define DBPATH tzplatform_mkpath(TZ_SYS_DB, "/.pkgmgr_parser.db")
-#define JOURNAL_DBPATH tzplatform_mkpath(TZ_SYS_DB, \
-       "/.pkgmgr_parser.db-journal")
 #define CERT_DBPATH tzplatform_mkpath(TZ_SYS_DB, "/.pkgmgr_cert.db")
-#define JOURNAL_CERT_DBPATH tzplatform_mkpath(TZ_SYS_DB, \
-       "/.pkgmgr_cert.db-journal")
 #define OPT_ZIP_FILE                   "/usr/system/RestoreDir/opt.zip"
 #define ALL_PRELOAD_RW_PKG_LIST "/opt/usr/share/.all_preload_rw_list"
 #define GLOBAL_USER tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)
@@ -1487,6 +1483,8 @@ do {                                                                           \
 static int __set_db_permission(const char *path)
 {
        int fd;
+       const char *files[2];
+       char journal_file[BUF_SIZE];
        struct stat sb;
        mode_t mode;
        uid_t uid;
@@ -1494,6 +1492,7 @@ static int __set_db_permission(const char *path)
        struct passwd *result;
        char buf[BUF_SIZE];
        int ret;
+       int i;
 
        ret = getpwnam_r(APPFW_USER, &pwd, buf, sizeof(buf), &result);
        if (result == NULL) {
@@ -1505,6 +1504,10 @@ static int __set_db_permission(const char *path)
        }
        uid = pwd.pw_uid;
 
+       snprintf(journal_file, sizeof(journal_file), "%s-journal", path);
+       files[0] = path;
+       files[1] = journal_file;
+
        ret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
        if (result == NULL) {
                if (ret == 0)
@@ -1513,41 +1516,44 @@ static int __set_db_permission(const char *path)
                        _LOGE("getpwuid_r failed: %d", errno);
                return -1;
        }
-       fd = open(path, O_RDONLY);
-       if (fd == -1) {
-               _LOGE("open %s failed: %d", path, errno);
-               return -1;
-       }
-       ret = fstat(fd, &sb);
-       if (ret == -1) {
-               _LOGE("stat %s failed: %d", path, errno);
-               close(fd);
-       return -1;
-       }
-       if (S_ISLNK(sb.st_mode)) {
-               _LOGE("%s is symlink!", path);
-               close(fd);
-               return -1;
-       }
-       ret = fchown(fd, uid, pwd.pw_gid);
-       if (ret == -1) {
-               _LOGE("fchown %s failed: %d", path, errno);
-               close(fd);
-               return -1;
-       }
 
-       mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
-       if (strstr(path, CERT_DBPATH))
-               mode |= S_IWOTH;
-       ret = fchmod(fd, mode);
-       if (ret == -1) {
-               _LOGE("fchmod %s failed: %d", path, errno);
+       for (i = 0; i < 2; i++) {
+               fd = open(files[i], O_RDONLY);
+               if (fd == -1) {
+                       _LOGE("open %s failed: %d", files[i], errno);
+                       return -1;
+               }
+               ret = fstat(fd, &sb);
+               if (ret == -1) {
+                       _LOGE("stat %s failed: %d", files[i], errno);
+                       close(fd);
+                       return -1;
+               }
+               if (S_ISLNK(sb.st_mode)) {
+                       _LOGE("%s is symlink!", files[i]);
+                       close(fd);
+                       return -1;
+               }
+               ret = fchown(fd, uid, pwd.pw_gid);
+               if (ret == -1) {
+                       _LOGE("fchown %s failed: %d", files[i], errno);
+                       close(fd);
+                       return -1;
+               }
+
+               mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
+               if (strstr(files[i], CERT_DBPATH))
+                       mode |= S_IWOTH;
+               ret = fchmod(fd, mode);
+               if (ret == -1) {
+                       _LOGE("fchmod %s failed: %d", files[i], errno);
+                       close(fd);
+                       return -1;
+               }
+               fsync(fd);
                close(fd);
-               return -1;
+               SET_SMACK_LABEL(files[i]);
        }
-       fsync(fd);
-       close(fd);
-       SET_SMACK_LABEL(path);
 
        return 0;
 }
@@ -1595,16 +1601,21 @@ static int __remove_backup_flag(const char *path)
 
 static int __check_and_restore_backup(const char *origin_path) {
        char backup_path[BUF_SIZE];
+       char journal_path[BUF_SIZE];
+       char journal_backup_path[BUF_SIZE];
        char buf[BUF_SIZE];
+
        snprintf(backup_path, BUF_SIZE, "%s.bck", origin_path);
+       snprintf(journal_path, BUF_SIZE, "%s-journal", origin_path);
+       snprintf(journal_backup_path, BUF_SIZE, "%s.bck-journal", origin_path);
 
-       // if backup flag exists, it means the previous backup process aborted.
-       if (access(backup_path, F_OK) && __check_backup_flag(origin_path))
+       if (access(backup_path, F_OK))
                return 0;
 
-       if (access(origin_path, F_OK) == 0) {
-               if (remove(origin_path)) {
-                       _LOG("cannot remove path(%s) : %s\n", origin_path,
+       if (access(journal_backup_path, F_OK) == 0) {
+               if (rename(journal_backup_path, journal_path)) {
+                       _LOG("fail to rename %s to %s : %s\n",
+                                       journal_backup_path, journal_path,
                                        strerror_r(errno, buf, sizeof(buf)));
                        return -1;
                }
@@ -1619,79 +1630,185 @@ static int __check_and_restore_backup(const char *origin_path) {
        return 0;
 }
 
-static int __check_and_restore_backup_dbs() {
-       if (__check_and_restore_backup(DBPATH))
+static int __db_integrity_check(char *db_path)
+{
+       const char *query = "PRAGMA integrity_check";
+       const char *val;
+       sqlite3 *db;
+       sqlite3_stmt *stmt;
+       int ret;
+
+       if (access(db_path, F_OK))
+               return 0;
+
+       ret = sqlite3_open_v2(db_path, &db, SQLITE_OPEN_READONLY, NULL);
+       if (ret != SQLITE_OK) {
+               _LOGE("Fail to open (%s) db handle\n", db_path);
                return -1;
+       }
 
-       if (__check_and_restore_backup(JOURNAL_DBPATH))
+       ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
+       if (ret != SQLITE_OK) {
+               _LOGE("prepare failed: %s\n", sqlite3_errmsg(db));
+               sqlite3_close_v2(db);
                return -1;
+       }
 
-       if (__check_and_restore_backup(CERT_DBPATH))
+       if (sqlite3_step(stmt) != SQLITE_ROW) {
+               _LOGE("sqlite3_step fail\n");
+               sqlite3_finalize(stmt);
+               sqlite3_close_v2(db);
                return -1;
+       }
 
-       if (__check_and_restore_backup(JOURNAL_CERT_DBPATH))
+       val = (const char *)sqlite3_column_text(stmt, 0);
+       if (strcmp(val, "ok")) {
+               _LOGE("Fail to integrity check, db(%s), val(%s)\n",
+                               db_path, val);
+               sqlite3_finalize(stmt);
+               sqlite3_close_v2(db);
                return -1;
+       }
+
+       sqlite3_finalize(stmt);
+       sqlite3_close_v2(db);
 
        return 0;
 }
 
-static int __backup_file(const char *src_path, const char *dest_path)
+static int __integrity_check_backup_dbs(void)
 {
-       int ret = 0;
-       int rc;
-       FILE *src = NULL;
-       FILE *dest = NULL;
-       char temp_buf[8192] = {'\0', };
-       size_t size_of_char = sizeof(char);
-       size_t size_of_temp_buf = sizeof(temp_buf);
+       char parser_db_bck[BUF_SIZE];
+       char cert_db_bck[BUF_SIZE];
+
+       snprintf(parser_db_bck, BUF_SIZE, "%s.bck", DBPATH);
+       snprintf(cert_db_bck, BUF_SIZE, "%s.bck", CERT_DBPATH);
+
+       retvm_if(__db_integrity_check(parser_db_bck) < 0,
+                       -1, "Fail to integrity check db(%s)\n",
+                       parser_db_bck);
+
+       retvm_if(__db_integrity_check(cert_db_bck) < 0,
+                       -1, "Fail to integrity check db(%s)\n",
+                       cert_db_bck);
+
+       return 0;
+}
+
+static void __remove_backup_path(const char *origin_path)
+{
+       char backup_path[BUF_SIZE];
+       char journal_backup_path[BUF_SIZE];
 
-       retvm_if(src_path == NULL || dest_path == NULL,
-                       -1, "Invalid parameters");
+       snprintf(backup_path, BUF_SIZE, "%s.bck", origin_path);
+       snprintf(journal_backup_path, BUF_SIZE, "%s.bck-journal", origin_path);
+
+       if (access(backup_path, F_OK) == 0 && remove(backup_path))
+               _LOG("cannot remove backup file(%s): %d", backup_path, errno);
+
+       if (access(journal_backup_path, F_OK) == 0
+                       && remove(journal_backup_path))
+               _LOG("cannot remove backup file(%s): %d",
+                               journal_backup_path, errno);
+}
 
-       retvm_if(access(src_path, F_OK) != 0, -1,
-                       "File(%s) is not exist", src_path);
+static void __remove_backup_dbs(void)
+{
+       __remove_backup_path(DBPATH);
+       __remove_backup_path(CERT_DBPATH);
+}
 
+static int __check_and_restore_backup_dbs(void)
+{
        // if backup flag exists, it means the previous backup process aborted.
-       if (__check_backup_flag(src_path)) {
-               if (access(dest_path, F_OK) == 0) {
-                       if (remove(dest_path))
-                               _LOG("Failed to remove uncompleted backup file "
-                                               "%s: %d", dest_path, errno);
-                       return -1;
-               }
-       } else {
-               if (__create_backup_flag(src_path)) {
-                       _LOG("failed to create backup flag");
-                       return -1;
-               }
+       if (__check_backup_flag(DBPATH) == 0
+                       || __check_backup_flag(CERT_DBPATH) == 0) {
+               __remove_backup_dbs();
+               __remove_backup_flag(DBPATH);
+               __remove_backup_flag(CERT_DBPATH);
+
+               return 0;
+       }
+
+       if (__integrity_check_backup_dbs() < 0) {
+               __remove_backup_dbs();
+               return 0;
+       }
+
+       if (__check_and_restore_backup(DBPATH))
+               return -1;
+
+       if (__check_and_restore_backup(CERT_DBPATH))
+               return -1;
+
+       return 0;
+}
+
+static int __backup_file(const char *src_path, const char *dest_path)
+{
+       int ret = 0;
+       sqlite3 *src_db;
+       sqlite3 *dest_db;
+       sqlite3_backup *p_backup;
+
+       if (src_path == NULL || dest_path == NULL) {
+               _LOGE("Invalid parameters");
+               return -1;
        }
 
-       src = fopen(src_path, "r");
-       tryvm_if(src == NULL, ret = -1, "Failed to open : %s\n", src_path);
+       if (access(src_path, F_OK) != 0) {
+               _LOGE("File(%s) is not exist", src_path);
+               return -1;
+       }
 
-       dest = fopen(dest_path, "w");
-       tryvm_if(dest == NULL, ret = -1, "Failed to open : %s\n", dest_path);
+       if (__create_backup_flag(src_path)) {
+               _LOG("failed to create backup flag");
+               return -1;
+       }
 
-       while (!feof(src)) {
-               rc = fread(temp_buf, size_of_char, size_of_temp_buf, src);
-               fwrite(temp_buf, size_of_char, rc, dest);
+       ret = sqlite3_open_v2(src_path, &src_db, SQLITE_OPEN_READONLY, NULL);
+       if (ret != SQLITE_OK) {
+               _LOGE("Fail to open (%s) db handle\n", src_path);
+               return -1;
        }
 
-       fsync(fileno(dest));
+       ret = sqlite3_open_v2(dest_path, &dest_db,
+                       SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
+       if (ret != SQLITE_OK) {
+               _LOGE("Fail to open (%s) db handle\n", dest_path);
+               sqlite3_close_v2(src_db);
+               return -1;
+       }
 
-catch:
-       if (src)
-               fclose(src);
+       p_backup = sqlite3_backup_init(dest_db, "main", src_db, "main");
+       if (p_backup) {
+               do {
+                       ret = sqlite3_backup_step(p_backup, -1);
+                       if (ret == SQLITE_BUSY || ret == SQLITE_LOCKED)
+                               sqlite3_sleep(250);
+               } while (ret == SQLITE_OK || ret == SQLITE_BUSY
+                               || ret == SQLITE_LOCKED);
 
-       if (dest)
-               fclose(dest);
+               sqlite3_backup_finish(p_backup);
+       }
 
+       ret = sqlite3_errcode(dest_db);
+       if (ret != SQLITE_OK) {
+               _LOGE("Fail to backup db err(%d)\n", ret);
+               sqlite3_close_v2(src_db);
+               sqlite3_close_v2(dest_db);
+               return -1;
+       }
+
+       sqlite3_close_v2(src_db);
+       sqlite3_close_v2(dest_db);
        __remove_backup_flag(src_path);
 
-       return ret;
+       return 0;
 }
 
-static int __backup_db(const char *src_path, const char *dest_path) {
+static int __backup_db(const char *src_path, const char *dest_path)
+{
        if (__backup_file(src_path, dest_path) != 0)
                return -1;
 
@@ -1701,59 +1818,28 @@ static int __backup_db(const char *src_path, const char *dest_path) {
        return 0;
 }
 
-static int __make_backup_dbs() {
-       int ret = 0;
+static int __make_backup_dbs()
+{
        char parser_db_bck[BUF_SIZE];
-       char parser_db_journal_bck[BUF_SIZE];
        char cert_db_bck[BUF_SIZE];
-       char cert_db_journal_bck[BUF_SIZE];
 
        snprintf(parser_db_bck, BUF_SIZE, "%s.bck", DBPATH);
-       snprintf(parser_db_journal_bck, BUF_SIZE, "%s.bck", JOURNAL_DBPATH);
        snprintf(cert_db_bck, BUF_SIZE, "%s.bck", CERT_DBPATH);
-       snprintf(cert_db_journal_bck, BUF_SIZE, "%s.bck", JOURNAL_CERT_DBPATH);
-
-       tryvm_if(__backup_db(DBPATH, parser_db_bck) == -1,
-                       ret = -1, "Fail to backup [%s] to [%s]\n",
-                       DBPATH, parser_db_bck);
 
-       tryvm_if(__backup_db(JOURNAL_DBPATH, parser_db_journal_bck) == -1,
-                       ret = -1, "Fail to backup [%s] to [%s]\n",
-                       JOURNAL_DBPATH, parser_db_journal_bck);
-
-       tryvm_if(__backup_db(CERT_DBPATH, cert_db_bck) == -1,
-                       ret = -1, "Fail to backup [%s] to [%s]\n",
-                       CERT_DBPATH, cert_db_bck);
+       if (__backup_db(DBPATH, parser_db_bck) < 0) {
+               _LOGE("Fail to backup [%s] to [%s]\n", DBPATH, parser_db_bck);
+               __remove_backup_dbs();
+               return -1;
+       }
 
-       tryvm_if(__backup_db(JOURNAL_CERT_DBPATH, cert_db_journal_bck) == -1,
-                       ret = -1, "Fail to backup [%s] to [%s]\n",
-                       JOURNAL_CERT_DBPATH, cert_db_journal_bck);
+       if (__backup_db(CERT_DBPATH, cert_db_bck) < 0) {
+               _LOGE("Fail to backup [%s] to [%s]\n",
+                               CERT_DBPATH, cert_db_bck);
+               __remove_backup_dbs();
+               return -1;
+       }
 
        return 0;
-
-catch:
-       remove(parser_db_bck);
-       remove(parser_db_journal_bck);
-       remove(cert_db_bck);
-       remove(cert_db_journal_bck);
-
-       return ret;
-}
-
-static void __remove_backup_path(const char *origin_path) {
-       char backup_path[BUF_SIZE];
-
-       snprintf(backup_path, BUF_SIZE, "%s.bck", origin_path);
-
-       if (remove(backup_path))
-               _LOG("cannot remove backup file(%s): %d", backup_path, errno);
-}
-
-static void __remove_backup_dbs() {
-       __remove_backup_path(DBPATH);
-       __remove_backup_path(JOURNAL_DBPATH);
-       __remove_backup_path(CERT_DBPATH);
-       __remove_backup_path(JOURNAL_CERT_DBPATH);
 }
 
 int main(int argc, char *argv[])
@@ -1762,14 +1848,24 @@ int main(int argc, char *argv[])
        int ret = 0;
 
        ret = __check_and_restore_backup_dbs();
-       retvm_if(ret < 0, -1, "__check_and_restore_backup_dbs is failed.\n");
+       if (ret < 0) {
+               _LOGE("__check_and_restore_backup_dbs is failed.\n");
+               return -1;
+       }
 
        ret = __make_backup_dbs();
-       retvm_if(ret < 0, -1, "__make_backup_dbs is failed.\n");
+       if (ret < 0) {
+               _LOGE("__make_backup_dbs is failed.\n");
+               return -1;
+       }
 
        /* check pkgmgr-fota dir, if it is not, then exit */
        ret = __check_pkgmgr_fota_dir();
-       retvm_if(ret < 0, -1, "__check_pkgmgr_fota_dir is failed.\n");
+       if (ret < 0) {
+               _LOGE("__check_pkgmgr_fota_dir is failed.\n");
+               __remove_backup_dbs();
+               return -1;
+       }
 
        /* clean pkgid list file */
        ret = __remove_pkgid_list();
@@ -1777,56 +1873,75 @@ int main(int argc, char *argv[])
 
        /* get pkgid from orginal pkgmgr db */
        ret = __get_pkgid_list_from_db_and_xml();
-       retvm_if(ret < 0, -1, "__get_pkgid_list_from_db_and_xml is failed.\n");
+       if (ret < 0) {
+               _LOGE("__get_pkgid_list_from_db_and_xml is failed.\n");
+               __remove_backup_dbs();
+               return -1;
+       }
 
        //__get_pkginfo_from_opt();
 
        ret = __check_tmp_all_preload_rw_pkg_list();
-       retvm_if(ret < 0, -1,
-                       "__check_tmp_all_preload_rw_pkg_list is failed.\n");
+       if (ret < 0) {
+               _LOGE("__check_tmp_all_preload_rw_pkg_list is failed.\n");
+               __remove_backup_dbs();
+               return -1;
+       }
 
        preload_rw_table = g_hash_table_new_full(
                                g_str_hash, g_str_equal, free, __free_pkginfo);
        if (__fill_preload_rw_table(preload_rw_table) < 0) {
                ret = __find_preload_rw_pkgid_from_db(preload_rw_table);
-               retvm_if(ret < 0, -1, "__find_preload_rw_pkgid_from_db is failed\n");
+               if (ret < 0) {
+                       _LOGE("__find_preload_rw_pkgid_from_db is failed\n");
+                       g_hash_table_destroy(preload_rw_table);
+                       __remove_backup_dbs();
+                       return -1;
+               }
        }
 
        if (argc == 1) {
                ret = __process_ro_fota(preload_rw_table);
                if (ret < 0) {
-                       g_hash_table_destroy(preload_rw_table);
                        _LOGE("__process_ro_fota is failed.\n");
-                       return EXIT_FAILURE;
+                       g_hash_table_destroy(preload_rw_table);
+                       __remove_backup_dbs();
+                       return -1;
                }
                ret = __process_rw_fota(preload_rw_table);
                if (ret < 0) {
-                       g_hash_table_destroy(preload_rw_table);
                        _LOGE("__process_rw_fota is failed.\n");
-                       return EXIT_FAILURE;
+                       g_hash_table_destroy(preload_rw_table);
+                       __remove_backup_dbs();
+                       return -1;
                }
        } else {
                if (strcmp(argv[1], "-rof") == 0) {
                        ret = __process_ro_fota(preload_rw_table);
                        if (ret < 0) {
-                               g_hash_table_destroy(preload_rw_table);
                                _LOGE("__process_ro_fota is failed.\n");
-                               return EXIT_FAILURE;
+                               g_hash_table_destroy(preload_rw_table);
+                               __remove_backup_dbs();
+                               return -1;
                        }
                } else if (strcmp(argv[1], "-rwf") == 0) {
                        ret = __process_rw_fota(preload_rw_table);
                        if (ret < 0) {
-                               g_hash_table_destroy(preload_rw_table);
                                _LOGE("__process_rw_fota is failed.\n");
-                               return EXIT_FAILURE;
+                               g_hash_table_destroy(preload_rw_table);
+                               __remove_backup_dbs();
+                               return -1;
                        }
                } else {
                        fprintf(stderr, "not supported operand\n");
+                       g_hash_table_destroy(preload_rw_table);
+                       __remove_backup_dbs();
+                       return -1;
                }
        }
        __make_preload_rw_list(preload_rw_table);
        g_hash_table_destroy(preload_rw_table);
        __remove_backup_dbs();
 
-       return EXIT_SUCCESS;
+       return 0;
 }