From 9f6d9ee94e61aaa479f8b629a58648b049b45b97 Mon Sep 17 00:00:00 2001 From: Ilho Kim Date: Thu, 24 Sep 2020 13:51:52 +0900 Subject: [PATCH] Backup databases before running pkg_upgrade If pkg_upgrade forced terminated before it finished and then rerun pkgmgr database will contain the result of previous work it can cause errors when upgrading so pkg_upgrade needs to backup the pkgmgr database before running and remove the backup files after all is done Change-Id: Ifbcc46071609df01829089beb93f942ce9283831 Signed-off-by: Ilho Kim --- CMakeLists.txt | 1 + packaging/pkgmgr-tool.spec | 1 + src/pkg_upgrade/CMakeLists.txt | 1 + src/pkg_upgrade/pkg_upgrade.c | 242 +++++++++++++++++++++++++++++++++ 4 files changed, 245 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 35b9ef7..6b4891e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ PKG_CHECK_MODULES(TZPLATFORM_DEPS REQUIRED libtzplatform-config) PKG_CHECK_MODULES(AUL_DEPS REQUIRED aul) PKG_CHECK_MODULES(STORAGE_DEPS REQUIRED storage) PKG_CHECK_MODULES(SQLITE_DEPS REQUIRED sqlite3) +PKG_CHECK_MODULES(SMACK_DEPS REQUIRED libsmack) INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,-zdefs -pie" ) diff --git a/packaging/pkgmgr-tool.spec b/packaging/pkgmgr-tool.spec index c3ae576..ad79f58 100644 --- a/packaging/pkgmgr-tool.spec +++ b/packaging/pkgmgr-tool.spec @@ -18,6 +18,7 @@ BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(bundle) BuildRequires: pkgconfig(pkgmgr-info) BuildRequires: pkgconfig(iniparser) +BuildRequires: pkgconfig(libsmack) BuildRequires: pkgconfig(libtzplatform-config) BuildRequires: pkgconfig(xdgmime) BuildRequires: pkgconfig(pkgmgr) diff --git a/src/pkg_upgrade/CMakeLists.txt b/src/pkg_upgrade/CMakeLists.txt index acad83c..6688c88 100644 --- a/src/pkg_upgrade/CMakeLists.txt +++ b/src/pkg_upgrade/CMakeLists.txt @@ -15,6 +15,7 @@ APPLY_PKG_CONFIG(${TARGET_PKG_UPGRADE} PUBLIC PKGMGR_PARSER_DEPS STORAGE_DEPS TZPLATFORM_DEPS + SMACK_DEPS ) # Install diff --git a/src/pkg_upgrade/pkg_upgrade.c b/src/pkg_upgrade/pkg_upgrade.c index 0b0277d..f2274d8 100644 --- a/src/pkg_upgrade/pkg_upgrade.c +++ b/src/pkg_upgrade/pkg_upgrade.c @@ -19,11 +19,13 @@ #define _GNU_SOURCE +#include #include #include #include #include #include +#include #include #include #include @@ -33,6 +35,7 @@ #include #include #include +#include #include #include @@ -58,8 +61,15 @@ 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) +#define APPFW_USER "app_fw" struct pkginfo { char *pkgid; @@ -1497,11 +1507,242 @@ static int __fill_preload_rw_table(GHashTable *preload_rw_table) return 0; } +#define DB_LABEL "User::Home" +#define SET_SMACK_LABEL(x) \ +do { \ + if (smack_setlabel((x), DB_LABEL, SMACK_LABEL_ACCESS)) \ + _LOGE("failed chsmack -a %s %s", DB_LABEL, x); \ + else \ + _LOG("chsmack -a %s %s", DB_LABEL, x); \ +} while (0) + +static int __set_db_permission(const char *path) +{ + int fd; + struct stat sb; + mode_t mode; + uid_t uid; + struct passwd pwd; + struct passwd *result; + char buf[BUF_SIZE]; + int ret; + + ret = getpwnam_r(APPFW_USER, &pwd, buf, sizeof(buf), &result); + if (result == NULL) { + if (ret == 0) + _LOGE("no such user: %s", APPFW_USER); + else + _LOGE("getpwnam_r failed: %d", errno); + return -1; + } + uid = pwd.pw_uid; + + ret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &result); + if (result == NULL) { + if (ret == 0) + _LOGE("no such user: %d", uid); + else + _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); + close(fd); + return -1; + } + fsync(fd); + close(fd); + SET_SMACK_LABEL(path); + + return 0; +} + +static int __check_and_restore_backup(const char *origin_path) { + char backup_path[BUF_SIZE]; + char buf[BUF_SIZE]; + snprintf(backup_path, BUF_SIZE, "%s.bck", 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, + strerror_r(errno, buf, sizeof(buf))); + return -1; + } + } + + if (rename(backup_path, origin_path)) { + _LOG("fail to rename %s to %s : %s\n", backup_path, origin_path, + strerror_r(errno, buf, sizeof(buf))); + return -1; + } + + return 0; +} + +static int __check_and_restore_backup_dbs() { + if (__check_and_restore_backup(DBPATH)) + return -1; + + if (__check_and_restore_backup(JOURNAL_DBPATH)) + return -1; + + if (__check_and_restore_backup(CERT_DBPATH)) + return -1; + + if (__check_and_restore_backup(JOURNAL_CERT_DBPATH)) + return -1; + + return 0; +} + +static int __backup_file(const char *src_path, const char *dest_path) +{ + 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); + + retvm_if(src_path == NULL || dest_path == NULL, + -1, "Invalid parameters"); + + retvm_if(access(src_path, F_OK) != 0, -1, + "File(%s) is not exist", src_path); + + retvm_if(access(dest_path, F_OK) == 0, -1, + "File(%s) is already exist", dest_path); + + retvm_if(rename(src_path, dest_path) != 0, -1, + "Fail to move file %s to %s", src_path, dest_path); + + src = fopen(dest_path, "r"); + tryvm_if(src == NULL, ret = -1, "Failed to open : %s\n", dest_path); + + dest = fopen(src_path, "w"); + tryvm_if(dest == NULL, ret = -1, "Failed to open : %s\n", src_path); + + while (!feof(src)) { + rc = fread(temp_buf, size_of_char, size_of_temp_buf, src); + fwrite(temp_buf, size_of_char, rc, dest); + } + + fsync(fileno(dest)); + +catch: + if (src) + fclose(src); + + if (dest) + fclose(dest); + + return ret; +} + +static int __make_backup_dbs() { + int ret = 0; + 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_file(DBPATH, parser_db_bck) == -1, + ret = -1, "Fail to backup [%s] to [%s]\n", + DBPATH, parser_db_bck); + tryvm_if(__set_db_permission(DBPATH) == -1, + ret = -1, "Fail to set db permission\n"); + + tryvm_if(__backup_file(JOURNAL_DBPATH, parser_db_journal_bck) == -1, + ret = -1, "Fail to backup [%s] to [%s]\n", + JOURNAL_DBPATH, parser_db_journal_bck); + tryvm_if(__set_db_permission(JOURNAL_DBPATH) == -1, + ret = -1, "Fail to set db permission\n"); + + tryvm_if(__backup_file(CERT_DBPATH, cert_db_bck) == -1, + ret = -1, "Fail to backup [%s] to [%s]\n", + CERT_DBPATH, cert_db_bck); + tryvm_if(__set_db_permission(CERT_DBPATH) == -1, + ret = -1, "Fail to set db permission\n"); + + tryvm_if(__backup_file(JOURNAL_CERT_DBPATH, cert_db_journal_bck) == -1, + ret = -1, "Fail to backup [%s] to [%s]\n", + JOURNAL_CERT_DBPATH, cert_db_journal_bck); + tryvm_if(__set_db_permission(JOURNAL_CERT_DBPATH) == -1, + ret = -1, "Fail to set db permission\n"); + + 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[]) { GHashTable *preload_rw_table; int ret = 0; + ret = __check_and_restore_backup_dbs(); + retvm_if(ret < 0, -1, "__check_and_restore_backup_dbs is failed.\n"); + + ret = __make_backup_dbs(); + retvm_if(ret < 0, -1, "__make_backup_dbs is failed.\n"); + /* 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"); @@ -1561,5 +1802,6 @@ int main(int argc, char *argv[]) } __make_preload_rw_list(preload_rw_table); g_hash_table_destroy(preload_rw_table); + __remove_backup_dbs(); return EXIT_SUCCESS; } -- 2.34.1