summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordarpan.ka <darpan.ka@samsung.com>2017-01-18 14:46:14 +0530
committerHwankyu Jhun <h.jhun@samsung.com>2017-03-08 13:56:39 +0900
commitfc750eec5b92ad4359fda2cda6d724628c609371 (patch)
tree2d925ca2ab4006bb8f8cd0fb02e678dd9e40dd3b
parent0104d7af8052bed95ab44ecb006ed260cb905a26 (diff)
downloadapplication-fc750eec5b92ad4359fda2cda6d724628c609371.tar.gz
application-fc750eec5b92ad4359fda2cda6d724628c609371.tar.bz2
application-fc750eec5b92ad4359fda2cda6d724628c609371.zip
Preference dump
preference dump is required for debugging purpose. It collects preference information of every installer application during system dump and also useful for OS upgrade for any issue debugging. Change-Id: Ib12c75ca1b518c1141164961290c6d2bcd6128dd Signed-off-by: darpan.ka <darpan.ka@samsung.com>
-rw-r--r--packaging/capi-appfw-application.spec4
-rw-r--r--preference/CMakeLists.txt8
-rw-r--r--preference/pref_dump.sh16
-rwxr-xr-xpreference/preference_tool.c800
4 files changed, 826 insertions, 2 deletions
diff --git a/packaging/capi-appfw-application.spec b/packaging/capi-appfw-application.spec
index d58f574..2621015 100644
--- a/packaging/capi-appfw-application.spec
+++ b/packaging/capi-appfw-application.spec
@@ -59,7 +59,9 @@ cp LICENSE %{buildroot}%{_datadir}/license/%{name}
%{_libdir}/libcapi-appfw-app-common.so.*
%{_libdir}/libcapi-appfw-preference.so.*
%{_libdir}/libcapi-appfw-event.so.*
-
+%{_bindir}/preference_tool
+%attr(0700,root,root) /usr/bin/preference_tool
+%attr(755,root,root) /opt/etc/dump.d/module.d/pref_dump.sh
%{_datadir}/license/%{name}
%files devel
diff --git a/preference/CMakeLists.txt b/preference/CMakeLists.txt
index 21da809..25e6787 100644
--- a/preference/CMakeLists.txt
+++ b/preference/CMakeLists.txt
@@ -35,6 +35,12 @@ add_library(${fw_name} SHARED
preference_inoti.c
)
+add_executable(preference_tool
+ preference_tool.c
+ )
+TARGET_LINK_LIBRARIES(preference_tool ${fw_name} -pie)
+INSTALL(TARGETS preference_tool DESTINATION bin)
+
TARGET_LINK_LIBRARIES(${fw_name} capi-appfw-app-common ${${fw_name}_LDFLAGS})
SET_TARGET_PROPERTIES(${fw_name}
@@ -62,5 +68,5 @@ CONFIGURE_FILE(
@ONLY
)
INSTALL(FILES ${CMAKE_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
-
+INSTALL(FILES pref_dump.sh DESTINATION /opt/etc/dump.d/module.d)
diff --git a/preference/pref_dump.sh b/preference/pref_dump.sh
new file mode 100644
index 0000000..575ebc9
--- /dev/null
+++ b/preference/pref_dump.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+PREF_DUMP=$1/pref
+/bin/mkdir -p $PREF_DUMP
+
+for file in `/usr/bin/find /opt/usr/apps/ -name *.pref`
+do
+ chsmack $file >> $PREF_DUMP/pref_value
+ chsmack $file/* >> $PREF_DUMP/pref_value
+ ls -alZ $file >> $PREF_DUMP/pref_value
+ PKG_ID=`echo "$file" | awk -F'/' '{print $5}'`
+ /usr/bin/preference_tool get $PKG_ID >> $PREF_DUMP/pref_value
+ mkdir -p $PREF_DUMP/$PKG_ID
+ cp -rf --preserve=all $file/* $PREF_DUMP/$PKG_ID
+ echo "===============================================" >> $PREF_DUMP/pref_value
+done
diff --git a/preference/preference_tool.c b/preference/preference_tool.c
new file mode 100755
index 0000000..093391e
--- /dev/null
+++ b/preference/preference_tool.c
@@ -0,0 +1,800 @@
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <wordexp.h>
+#include <sqlite3.h>
+#include <glib.h>
+
+#include <app_internal.h>
+#include <app_preference.h>
+#include <app_preference_internal.h>
+
+#define PREF_F_KEY_NAME "pref_key"
+#define PREF_F_TYPE_NAME "pref_type"
+#define PREF_F_DATA_NAME "pref_data"
+#define PREF_TBL_NAME "pref"
+
+#define DELIMITER 29
+#define HISTORY "/opt/var/kdb/.restore/.history/preference"
+
+typedef enum {
+ PREFERENCE_OLD_TYPE_INT = 1,
+ PREFERENCE_OLD_TYPE_BOOLEAN,
+ PREFERENCE_OLD_TYPE_DOUBLE,
+ PREFERENCE_OLD_TYPE_STRING
+} old_preference_type_e;
+
+typedef enum {
+ PREFERENCE_OP_RESTORE = 1,
+ PREFERENCE_OP_NEW_CREATE
+} preference_op_type;
+
+static sqlite3 *pref_db;
+
+static void _finish(void *data)
+{
+ if (pref_db != NULL) {
+ sqlite3_close(pref_db);
+ pref_db = NULL;
+ }
+}
+
+static int _busy_handler(void *pData, int count)
+{
+ if (count < 5) {
+ printf("Busy Handler Called!: PID(%d) / CNT(%d)\n",
+ getpid(), count + 1);
+ usleep((count + 1) * 100000);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int _initialize(const char *db_path)
+{
+ int ret;
+ char *path = strdup(db_path);
+
+ if (!path) {
+ printf("error, strdup(): Insufficient memory available\n");
+ return -1;
+ }
+
+ ret = sqlite3_open(path, &pref_db);
+ if (ret != SQLITE_OK) {
+ printf("error, fail to open db\n");
+ pref_db = NULL;
+ free(path);
+ return -1;
+ }
+
+ ret = sqlite3_busy_handler(pref_db, _busy_handler, NULL);
+ if (ret != SQLITE_OK)
+ printf("error, fail to resigter busy handler\n");
+ app_finalizer_add(_finish, NULL);
+ free(path);
+
+ return 0;
+}
+
+static int __system(const char *cmd)
+{
+ int status;
+ pid_t cpid;
+ wordexp_t p;
+ char **w;
+
+ cpid = fork();
+ if (cpid < 0) {
+ perror("fork");
+ return -1;
+ }
+
+ if (cpid == 0) {
+ /* child */
+ wordexp(cmd, &p, 0);
+ w = p.we_wordv;
+
+ execv(w[0], (char * const *)w);
+
+ wordfree(&p);
+
+ _exit(-1);
+ } else {
+ /* parent */
+ if (waitpid(cpid, &status, 0) == -1) {
+ perror("waitpid failed\n");
+ return -1;
+ }
+
+ if (WIFSIGNALED(status)) {
+ printf("signal(%d)\n", WTERMSIG(status));
+ perror("exit by signal\n");
+ return -1;
+ }
+
+ if (!WIFEXITED(status)) {
+ perror("exit abnormally\n");
+ return -1;
+ }
+
+ if (WIFEXITED(status) && WEXITSTATUS(status)) {
+ perror("child return error\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int is_exist_package(const char *pkgid)
+{
+ char pkg_path[PATH_MAX];
+
+ snprintf(pkg_path, sizeof(pkg_path), "/opt/usr/apps/%s", pkgid);
+ if (access(pkg_path, F_OK) == -1) {
+ printf("package(%s) is not exist.\n", pkgid);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int is_exist_data_dir_in_package(const char *pkgid)
+{
+ char pkg_data_path[PATH_MAX];
+
+ snprintf(pkg_data_path, sizeof(pkg_data_path),
+ "/opt/usr/apps/%s/data/", pkgid);
+ if (access(pkg_data_path, F_OK) == -1) {
+ printf("Data directory is not exist in package(%s).\n", pkgid);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int _make_key_path(const char *pkgid, const char *keyname, char *path)
+{
+ const char *key;
+ gchar *convert_key;
+ char pref_dir[PATH_MAX];
+ char cmd[PATH_MAX];
+ mode_t dir_mode = 0664 | 0111;
+
+ snprintf(pref_dir, sizeof(pref_dir), "/opt/usr/apps/%s/data/.pref",
+ pkgid);
+ if (access(pref_dir, F_OK) == -1) {
+ if (mkdir(pref_dir, dir_mode) < 0) {
+ if (is_exist_package(pkgid) < 0)
+ return -1;
+
+ if (is_exist_data_dir_in_package(pkgid) < 0)
+ return -1;
+
+ printf("pref_dir making failed.(%d/%s)\n",
+ errno, strerror(errno));
+ return -1;
+ }
+ if (chown(pref_dir, 5000, 5000) < 0) {
+ printf("chown() failed(%d/%s)\n",
+ errno, strerror(errno));
+ return -1;
+ }
+ }
+
+ snprintf(cmd, sizeof(cmd), "/usr/bin/chsmack -a \"%s\" %s",
+ pkgid, pref_dir);
+ if (__system(cmd)) {
+ printf("[pref] cmd error()\n");
+ return -1;
+ }
+
+ convert_key = g_compute_checksum_for_string(G_CHECKSUM_SHA1,
+ keyname, strlen(keyname));
+ if (convert_key == NULL) {
+ LOGE("fail to convert");
+ return PREFERENCE_ERROR_IO_ERROR;
+ }
+
+ key = (const char *)convert_key;
+ snprintf(path, PATH_MAX, "%s/%s", pref_dir, key);
+ g_free(convert_key);
+
+ return 0;
+}
+
+static int _get_key_name(const char *keyfile, char **keyname)
+{
+ int read_size = 0;
+ size_t keyname_len = 0;
+ char *convert_key = NULL;
+ FILE *fp = NULL;
+
+ fp = fopen(keyfile, "r");
+ if (fp == NULL)
+ return PREFERENCE_ERROR_FILE_OPEN;
+
+ read_size = fread((void *)&keyname_len, sizeof(int), 1, fp);
+ if (read_size <= 0 || keyname_len > PREFERENCE_KEY_PATH_LEN) {
+ fclose(fp);
+ return PREFERENCE_ERROR_FILE_FREAD;
+ }
+
+ convert_key = (char *)calloc(1, keyname_len + 1);
+ if (convert_key == NULL) {
+ LOGE("memory alloc failed");
+ fclose(fp);
+ return PREFERENCE_ERROR_OUT_OF_MEMORY;
+ }
+
+ read_size = fread((void *)convert_key, keyname_len, 1, fp);
+ if (read_size <= 0) {
+ free(convert_key);
+ fclose(fp);
+ return PREFERENCE_ERROR_FILE_FREAD;
+ }
+
+ *keyname = convert_key;
+
+ fclose(fp);
+
+ return PREFERENCE_ERROR_NONE;
+}
+
+static int _create_key(const char *path, const char *pkgid)
+{
+ int fd;
+ char cmd[1024];
+
+ fd = open(path, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
+ if (fd == -1) {
+ printf("[error] %d(%s)\n", errno, strerror(errno));
+ return -1;
+ }
+ if (fchown(fd, 5000, 5000) < 0) {
+ printf("fchown() failed(%d/%s)\n", errno, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ snprintf(cmd, sizeof(cmd), "/usr/bin/chsmack -a \"%s\" %s",
+ pkgid, path);
+ if (__system(cmd)) {
+ printf("[pref]create_key: cmd error()\n");
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+static int _create_new_preference_key(preference_op_type OP, const char *pkgid,
+ const char *key, const char *type, const char *value)
+{
+ FILE *fp;
+ int ret;
+ char key_path[PATH_MAX] = {0,};
+ size_t keyname_len;
+ int type_i;
+ int temp_i;
+ double temp_d;
+ locale_t loc;
+
+ _make_key_path(pkgid, key, key_path);
+retry:
+ fp = fopen(key_path, "r+");
+ if (fp == NULL) {
+ if (_create_key(key_path, pkgid) == -1) {
+ printf("preference key failed to create.(%d/%s)\n",
+ errno, strerror(errno));
+ return -1;
+ }
+
+ goto retry;
+ }
+
+ /* write keyname and size */
+ keyname_len = strlen(key);
+ ret = fwrite((void *)&keyname_len, sizeof(int), 1, fp);
+ if (ret <= 0) {
+ printf("preference write key name length error(%d/%s)\n",
+ errno, strerror(errno));
+ fclose(fp);
+ return -1;
+ }
+
+ ret = fwrite((void *)key, keyname_len, 1, fp);
+ if (ret <= 0) {
+ printf("preference write key name length error(%d/%s)\n",
+ errno, strerror(errno));
+ fclose(fp);
+ return -1;
+ }
+
+ loc = newlocale(LC_NUMERIC_MASK, "C", NULL);
+ uselocale(loc);
+
+ if (OP == PREFERENCE_OP_RESTORE) {
+ type_i = atoi(type);
+ switch (type_i) {
+ case PREFERENCE_OLD_TYPE_INT:
+ type_i = PREFERENCE_TYPE_INT;
+ break;
+ case PREFERENCE_OLD_TYPE_DOUBLE:
+ type_i = PREFERENCE_TYPE_DOUBLE;
+ break;
+ case PREFERENCE_OLD_TYPE_BOOLEAN:
+ type_i = PREFERENCE_TYPE_BOOLEAN;
+ break;
+ case PREFERENCE_OLD_TYPE_STRING:
+ type_i = PREFERENCE_TYPE_STRING;
+ break;
+ default:
+ break;
+ }
+ } else { /* OP is PREFERENCE_OP_NEW_CREATE.*/
+ if (strcmp(type, "int") == 0) {
+ type_i = PREFERENCE_TYPE_INT;
+ } else if (strcmp(type, "double") == 0) {
+ type_i = PREFERENCE_TYPE_DOUBLE;
+ } else if (strcmp(type, "bool") == 0) {
+ type_i = PREFERENCE_TYPE_BOOLEAN;
+ } else if (strcmp(type, "string") == 0) {
+ type_i = PREFERENCE_TYPE_STRING;
+ } else {
+ printf("key type is invalid.int|double|bool|string\n");
+ fclose(fp);
+ return -1;
+ }
+ }
+
+ ret = fwrite((void *)&type_i, sizeof(int), 1, fp);
+ if (ret <= 0) {
+ if (!errno) {
+ printf("number of written item is 0. try again\n");
+ errno = EAGAIN;
+ }
+ }
+
+ switch (type_i) {
+ case PREFERENCE_TYPE_INT:
+ temp_i = atoi(value);
+ ret = fwrite((void *)&temp_i, sizeof(int), 1, fp);
+ if (ret <= 0) {
+ printf("failed. fwrite() %d\n", ret);
+ } else {
+ printf("[SET][key]:%s [type]int[value]:%d\n",
+ key, temp_i);
+ }
+ break;
+ case PREFERENCE_TYPE_DOUBLE:
+ temp_d = atof(value);
+ ret = fwrite((void *)&temp_d, sizeof(double), 1, fp);
+ if (ret <= 0) {
+ printf("failed. fwrite() %d\n", ret);
+ } else {
+ printf("[SET][key]:%s[type]double[value]:%f\n",
+ key, temp_d);
+ }
+ break;
+ case PREFERENCE_TYPE_BOOLEAN:
+ temp_i = atoi(value);
+ ret = fwrite((void *)&temp_i, sizeof(int), 1, fp);
+ if (ret <= 0) {
+ printf("failed. fwrite() %d\n", ret);
+ } else {
+ printf("[SET][key]:%s [type]bool[value]:%d\n",
+ key, temp_i);
+ }
+ break;
+ case PREFERENCE_TYPE_STRING:
+ printf("[SET][key]:%s [type] string [value] %s\n",
+ key, value);
+ ret = fprintf(fp, "%s", value);
+ if (ftruncate(fileno(fp), ret) == -1) {
+ printf("[error] ftruncate failed %s(%s)\n",
+ key_path, value);
+ }
+ break;
+ default:
+ break;
+ }
+
+ uselocale(LC_GLOBAL_LOCALE);
+ fflush(fp);
+ if (fp) {
+ ret = fdatasync(fileno(fp));
+ fclose(fp);
+ }
+
+ return 0;
+}
+
+static int _print_pref_value_from_file_path(const char *path,
+ const char *keyname)
+{
+ FILE *fp;
+ int type = 0;
+ int read_size;
+ size_t keyname_len = 0;
+ int ret;
+ int value_int = 0;
+ double value_dbl = 0;
+ char file_buf[BUF_LEN] = {0,};
+ char *value_str = NULL;
+ int value_size = 0;
+
+ fp = fopen(path, "r");
+ if (fp == NULL) {
+ printf("fopen() failed.(%d/%s).fp is null.\n",
+ errno, strerror(errno));
+ return -1;
+ }
+
+ read_size = fread((void *)&keyname_len, sizeof(int), 1, fp);
+ if ((read_size <= 0) || (read_size > sizeof(int))) {
+ printf("key(%s) name length read error(%d)\n", keyname, errno);
+ fclose(fp);
+ return -1;
+ }
+
+ ret = fseek(fp, keyname_len, SEEK_CUR);
+ if (ret) {
+ printf("key(%s) name seek error(%d)\n", keyname, errno);
+ fclose(fp);
+ return -1;
+ }
+
+ /* read data type */
+ read_size = fread((void *)&type, sizeof(int), 1, fp);
+ if ((read_size <= 0) || (read_size > sizeof(int))) {
+ printf("key(%s) type read error(%d)\n", keyname, errno);
+ fclose(fp);
+ return -1;
+ }
+
+ /* read data value */
+ switch (type) {
+ case PREFERENCE_TYPE_INT:
+ read_size = fread((void *)&value_int, sizeof(int),
+ 1, fp);
+ if ((read_size <= 0) || (read_size > sizeof(int))) {
+ if (!ferror(fp)) {
+ printf("number of read items wrong.err: %d\n",
+ errno);
+ }
+ } else {
+ printf("[key] %s [type] int [value] %d\n",
+ keyname, value_int);
+ }
+ break;
+ case PREFERENCE_TYPE_DOUBLE:
+ read_size = fread((void *)&value_dbl, sizeof(double),
+ 1, fp);
+ if ((read_size <= 0) || (read_size > sizeof(double))) {
+ if (!ferror(fp)) {
+ printf("number of read items wrong.err:%d\n",
+ errno);
+ }
+ } else {
+ printf("[key] %s [type] double [value] %f\n",
+ keyname, value_dbl);
+ }
+ break;
+ case PREFERENCE_TYPE_BOOLEAN:
+ read_size = fread((void *)&value_int, sizeof(int),
+ 1, fp);
+ if ((read_size <= 0) || (read_size > sizeof(int))) {
+ if (!ferror(fp)) {
+ printf("number of read items wrong.err:%d\n",
+ errno);
+ }
+ } else {
+ printf("[key] %s [type] bool [value] %d\n",
+ keyname, value_int);
+ }
+ break;
+ case PREFERENCE_TYPE_STRING:
+ while (fgets(file_buf, sizeof(file_buf), fp)) {
+ if (value_str) {
+ value_size += strlen(file_buf);
+ value_str = (char *)realloc(value_str,
+ value_size);
+ if (value_str == NULL)
+ break;
+
+ strncat(value_str, file_buf, strlen(file_buf));
+ } else {
+ value_size = strlen(file_buf) + 1;
+ value_str = (char *)malloc(value_size);
+ if (value_str == NULL)
+ break;
+
+ memset(value_str, 0x00, value_size);
+ strncpy(value_str, file_buf, strlen(file_buf));
+ }
+ }
+
+ if (ferror(fp)) {
+ printf("error, fgets() failed.\n");
+ } else {
+ if (value_str) {
+ printf("[key] %s [type] string [value] %s\n",
+ keyname, value_str);
+ } else {
+ printf("[key] %s [value] NULL\n", keyname);
+ }
+ }
+ if (value_str)
+ free(value_str);
+ break;
+ default:
+ break;
+ }
+ fclose(fp);
+
+ return 0;
+}
+
+static int _restore(const char *pkgid)
+{
+ int ret;
+ char *query;
+ sqlite3_stmt *stmt = NULL;
+ const char *tmp_key;
+ const char *tmp_type;
+ const char *tmp_value;
+
+ query = sqlite3_mprintf("SELECT * FROM %s;", PREF_TBL_NAME);
+ if (query == NULL) {
+ printf("error, query is null\n");
+ return -1;
+ }
+
+ /*prepare query*/
+ ret = sqlite3_prepare_v2(pref_db, query, strlen(query), &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ printf("error, sqlite3_prepare_v2 failed(%d)\n", ret);
+ return -1;
+ }
+
+ while (1) {
+ ret = sqlite3_step(stmt);
+ if (ret == SQLITE_ROW) {
+ tmp_key = (const char *)sqlite3_column_text(stmt, 0);
+ tmp_type = (const char *)sqlite3_column_text(stmt, 1);
+ tmp_value = (const char *)sqlite3_column_text(stmt, 2);
+
+ printf("col[key]:%s\ncol[type]:%s\ncol[value]:%s\n",
+ tmp_key, tmp_type, tmp_value);
+
+ /*key create*/
+ ret = _create_new_preference_key(PREFERENCE_OP_RESTORE,
+ pkgid, tmp_key, tmp_type, tmp_value);
+ if (ret < 0) {
+ printf("create new prefer key failed (%d)\n",
+ ret);
+ return -1;
+ }
+ } else {
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+static int _remove_old_db(const char *db_path)
+{
+ int ret;
+ char journal_path[PATH_MAX];
+ char *path = strdup(db_path);
+
+ if (!path) {
+ printf("error, strdup(): Insufficient memory available\n");
+ return -1;
+ }
+
+ ret = remove(path);
+ if (ret < 0) {
+ printf("error, remove(%d/%s)\n", errno, strerror(errno));
+ free(path);
+ return -1;
+ }
+
+ snprintf(journal_path, sizeof(journal_path), "%s-journal", path);
+
+ if (access(journal_path, F_OK) == 0) {
+ ret = remove(journal_path);
+ if (ret < 0) {
+ printf("error, remove(%d/%s)\n", errno,
+ strerror(errno));
+ free(path);
+ return -1;
+ }
+ }
+ free(path);
+
+ return 0;
+}
+
+static void _print_help(void)
+{
+ printf("\n[Set preference value]\n");
+ printf("preference_tool set <pkgid> <key_name> <type> <value>\n");
+ printf("ex) preference_tool set ");
+ printf("org.tizen.preferencetest test_key string value\n\n");
+
+ printf("[Get preference value]\n");
+ printf("preference_tool get <pkgid>\n");
+ printf("ex) preference_tool get org.tizen.preferencetest\n\n");
+ printf("preference_tool get <pkgid> <key>\n");
+ printf("ex) preference_tool get ");
+ printf("org.tizen.preferencetest test_key\n\n");
+}
+
+static void _preference_set_key(const char *pkgid, const char *key,
+ const char *type, const char *value)
+{
+ _create_new_preference_key(PREFERENCE_OP_NEW_CREATE,
+ pkgid, key, type, value);
+}
+
+static void _print_preference_key(const char *pkgid, const char *key)
+{
+ char key_path[PATH_MAX] = {0,};
+
+ _make_key_path(pkgid, key, key_path);
+ _print_pref_value_from_file_path(key_path, key);
+}
+
+static void _print_preference_in_package(const char *pkgid)
+{
+ char pref_dir[PATH_MAX];
+ DIR *dir;
+ int dfd;
+ struct stat st;
+ int res;
+ struct dirent *ent = NULL;
+ const char *name;
+ char *keyname = NULL;
+ char file_full_path[PATH_MAX];
+
+ snprintf(pref_dir, sizeof(pref_dir), "/opt/usr/apps/%s/data/.pref",
+ pkgid);
+
+ dir = opendir(pref_dir);
+ if (dir == NULL) {
+ printf("Is not exist preference key in %s.\n", pkgid);
+ return;
+ }
+
+ dfd = dirfd(dir);
+ res = fstat(dfd, &st);
+ if (res < 0) {
+ printf("fstat() failed. path: %s, errno: %d(%s)\n",
+ pref_dir, errno, strerror(errno));
+ closedir(dir);
+ return;
+ }
+
+ while ((ent = readdir(dir))) {
+ name = ent->d_name;
+ if (name[0] == '.') {
+ if (name[1] == '\0')
+ continue;
+ if ((name[1] == '.') && (name[2] == '\0'))
+ continue;
+ }
+
+ snprintf(file_full_path, sizeof(file_full_path), "%s/%s",
+ pref_dir, name);
+ _get_key_name(file_full_path, &keyname);
+ _print_pref_value_from_file_path(file_full_path, keyname);
+ if (keyname) {
+ free(keyname);
+ keyname = NULL;
+ }
+ }
+ closedir(dir);
+}
+
+static void write_history(const char *str)
+{
+ FILE *fp = NULL;
+ int ret = 0;
+
+ fp = fopen(HISTORY, "a");
+ if (fp == NULL) {
+ printf("fopen() failed. FOTA history log (%d/%s)",
+ errno, strerror(errno));
+ return;
+ }
+
+ ret = fwrite((void *)str, strlen(str) + 1, 1, fp);
+ if (ret <= 0) {
+ printf("fwrite() failed. FOTA history log (%d/%s)",
+ errno, strerror(errno));
+ }
+ fclose(fp);
+}
+
+int main(int argc, char *argv[])
+{
+ int res;
+
+ if (getuid() != 0) {
+ printf("[pref] Only root user can use.\n");
+ return -1;
+ }
+
+ if (argc < 3) {
+ _print_help();
+ return -1;
+ }
+
+ if (strcmp(argv[1], "restore") == 0 && argc == 4) {
+ printf("[ start ] ----------------------------------------\n");
+ printf("Db file path:%s\n\n", argv[2]);
+
+ res = _initialize(argv[2]);
+ if (res < 0) {
+ printf("failed. _initialize(%d)\n", res);
+ return -1;
+ }
+
+ res = _restore(argv[3]);
+ if (res < 0) {
+ printf("failed. _restore(%d)\n", res);
+ write_history("\t\t- restore failed.\n");
+ printf("restore failed.\n");
+ return -1;
+ }
+
+ res = _remove_old_db(argv[2]);
+ if (res < 0) {
+ printf("failed. _remove_old_db(%d)\n", res);
+ return -1;
+ }
+
+ printf("-------------------------------------------------\n");
+ printf("done\n\n");
+ write_history("\t\t+ restore success.\n");
+ } else if (strcmp(argv[1], "get") == 0 || strcmp(argv[1], "GET") == 0) {
+ if (is_exist_package(argv[2]) < 0)
+ return -1;
+
+ if (is_exist_data_dir_in_package(argv[2]) < 0)
+ return -1;
+
+ if (argv[3])
+ _print_preference_key(argv[2], argv[3]);
+ else
+ _print_preference_in_package(argv[2]);
+ } else if (strcmp(argv[1], "set") == 0 || strcmp(argv[1], "SET") == 0) {
+ if (is_exist_package(argv[2]) < 0)
+ return -1;
+
+ if (is_exist_data_dir_in_package(argv[2]) < 0)
+ return -1;
+
+ if (argv[2] && argv[3] && argv[4] && argv[5])
+ _preference_set_key(argv[2], argv[3], argv[4], argv[5]);
+ else
+ _print_help();
+ } else {
+ _print_help();
+ }
+
+ return 0;
+}