Backup databases before running pkg_upgrade 85/244785/6
authorIlho Kim <ilho159.kim@samsung.com>
Thu, 24 Sep 2020 04:51:52 +0000 (13:51 +0900)
committerIlho Kim <ilho159.kim@samsung.com>
Fri, 25 Sep 2020 01:32:19 +0000 (10:32 +0900)
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 <ilho159.kim@samsung.com>
CMakeLists.txt
packaging/pkgmgr-tool.spec
src/pkg_upgrade/CMakeLists.txt
src/pkg_upgrade/pkg_upgrade.c

index 35b9ef7..6b4891e 100644 (file)
@@ -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" )
index c3ae576..ad79f58 100644 (file)
@@ -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)
index acad83c..6688c88 100644 (file)
@@ -15,6 +15,7 @@ APPLY_PKG_CONFIG(${TARGET_PKG_UPGRADE} PUBLIC
   PKGMGR_PARSER_DEPS
   STORAGE_DEPS
   TZPLATFORM_DEPS
+  SMACK_DEPS
 )
 
 # Install
index 0b0277d..f2274d8 100644 (file)
 
 #define _GNU_SOURCE
 
+#include <fcntl.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <dirent.h>
 #include <unistd.h>
+#include <sys/smack.h>
 #include <sys/stat.h>
 #include <errno.h>
 #include <iniparser.h>
@@ -33,6 +35,7 @@
 #include <sys/time.h>
 #include <libxml/xmlreader.h>
 #include <sqlite3.h>
+#include <pwd.h>
 
 #include <package-manager-types.h>
 #include <package-manager.h>
        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;
 }