From 58634349e7c8372cd4f0748f61f4eb51a7cf3b9c Mon Sep 17 00:00:00 2001 From: Ilho Kim Date: Mon, 31 May 2021 18:56:19 +0900 Subject: [PATCH] Change backup db logic - 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 --- src/pkg_upgrade/pkg_upgrade.c | 405 ++++++++++++++++++++++------------ 1 file changed, 260 insertions(+), 145 deletions(-) diff --git a/src/pkg_upgrade/pkg_upgrade.c b/src/pkg_upgrade/pkg_upgrade.c index 96d628f..6d86cbd 100644 --- a/src/pkg_upgrade/pkg_upgrade.c +++ b/src/pkg_upgrade/pkg_upgrade.c @@ -61,11 +61,7 @@ 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) @@ -1519,6 +1515,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; @@ -1526,6 +1524,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) { @@ -1537,6 +1536,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) @@ -1545,41 +1548,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; } @@ -1627,16 +1633,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; } @@ -1651,79 +1662,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]; - retvm_if(src_path == NULL || dest_path == NULL, - -1, "Invalid parameters"); + 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); - retvm_if(access(src_path, F_OK) != 0, -1, - "File(%s) is not exist", src_path); + return 0; +} +static void __remove_backup_path(const char *origin_path) +{ + char backup_path[BUF_SIZE]; + char journal_backup_path[BUF_SIZE]; + + 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); +} + +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; } - src = fopen(src_path, "r"); - tryvm_if(src == NULL, ret = -1, "Failed to open : %s\n", src_path); + if (__check_and_restore_backup(DBPATH)) + return -1; - dest = fopen(dest_path, "w"); - tryvm_if(dest == NULL, ret = -1, "Failed to open : %s\n", dest_path); + if (__check_and_restore_backup(CERT_DBPATH)) + 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); + 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; } - fsync(fileno(dest)); + if (access(src_path, F_OK) != 0) { + _LOGE("File(%s) is not exist", src_path); + return -1; + } -catch: - if (src) - fclose(src); + if (__create_backup_flag(src_path)) { + _LOG("failed to create backup flag"); + return -1; + } + + 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; + } + + 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; + } - if (dest) - fclose(dest); + 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); + 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; @@ -1733,59 +1850,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[]) @@ -1794,14 +1880,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(); @@ -1809,56 +1905,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; } -- 2.34.1