From: Semun Lee Date: Tue, 3 Apr 2018 08:25:42 +0000 (+0900) Subject: Add preference_tool X-Git-Tag: submit/tizen_4.0/20180403.094133~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=86fc6efce50ad7406c66135aa322f8522cd366d0;p=platform%2Fcore%2Fapi%2Fpreference.git Add preference_tool This tool is migrated from tizen_3.0 branch. Change-Id: I48a7488def18819fce4253aeac61e9e069cf424b Signed-off-by: Semun Lee --- diff --git a/packaging/capi-appfw-preference.spec b/packaging/capi-appfw-preference.spec index bf4cce5..520b7db 100644 --- a/packaging/capi-appfw-preference.spec +++ b/packaging/capi-appfw-preference.spec @@ -12,6 +12,7 @@ BuildRequires: pkgconfig(sqlite3) BuildRequires: pkgconfig(glib-2.0) BuildRequires: pkgconfig(capi-appfw-app-common) BuildRequires: pkgconfig(capi-base-common) +BuildRequires: pkgconfig(libtzplatform-config) %description An Application preference library in Tizen C API @@ -43,6 +44,8 @@ rm -rf %{buildroot} %files %manifest %{name}.manifest %{_libdir}/libcapi-appfw-preference.so.* +%attr(0700,root,root) %{_bindir}/preference_tool +%attr(755,root,root) /opt/etc/dump.d/module.d/pref_dump.sh %license LICENSE %files devel diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e2b7ec9..b3a18e8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -63,4 +63,4 @@ CONFIGURE_FILE( ) INSTALL(FILES ${CMAKE_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) - +ADD_SUBDIRECTORY(tool) diff --git a/src/tool/CMakeLists.txt b/src/tool/CMakeLists.txt new file mode 100644 index 0000000..144de57 --- /dev/null +++ b/src/tool/CMakeLists.txt @@ -0,0 +1,31 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +SET(tool_name "preference_tool") + +SET(CMAKE_INSTALL_PREFIX /usr) +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + +SET(INC_DIR ${CMAKE_SOURCE_DIR}/include) +INCLUDE_DIRECTORIES(${INC_DIR}) + +SET(requires "sqlite3 glib-2.0 capi-appfw-app-common libtzplatform-config") + +INCLUDE(FindPkgConfig) +SET(EXTRA_CFLAGS "") +pkg_check_modules(${tool_name} REQUIRED ${requires}) +FOREACH(flag ${${tool_name}_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE -Wall -Werror") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") + +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=${LIB_INSTALL_DIR}") + +add_executable(${tool_name} + preference_tool.c + ) + +TARGET_LINK_LIBRARIES(${tool_name} ${fw_name} ${${tool_name}_LDFLAGS} -pie) +INSTALL(TARGETS ${tool_name} DESTINATION bin) +INSTALL(FILES pref_dump.sh DESTINATION /opt/etc/dump.d/module.d) + diff --git a/src/tool/pref_dump.sh b/src/tool/pref_dump.sh new file mode 100644 index 0000000..575ebc9 --- /dev/null +++ b/src/tool/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/src/tool/preference_tool.c b/src/tool/preference_tool.c new file mode 100644 index 0000000..9791277 --- /dev/null +++ b/src/tool/preference_tool.c @@ -0,0 +1,1056 @@ +/* + * Copyright (c) 2011 - 2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 const char *__get_package_path(const char *package_id) +{ + uid_t uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER); + const char *path; + + tzplatform_set_user(uid); + path = tzplatform_mkpath(TZ_USER_APP, package_id); + tzplatform_reset_user(); + + return path; +} + +static int is_exist_package(const char *pkgid) +{ + const char *pkg_path; + + pkg_path = __get_package_path(pkgid); + if (pkg_path == NULL) { + printf("Failed to get package path(%s)\n", pkgid); + return -1; + } + + 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]; + const char *pkg_path; + + pkg_path = __get_package_path(pkgid); + if (pkg_path == NULL) { + printf("Failed to get package path(%s)\n", pkgid); + return -1; + } + + snprintf(pkg_data_path, sizeof(pkg_data_path), "%s/data/", pkg_path); + if (access(pkg_data_path, F_OK) == -1) { + printf("Data directory is not exist in package(%s).\n", pkgid); + return -1; + } + + return 0; +} + +static gid_t __get_gid(const char *name) +{ + char buf[LINE_MAX]; + struct group entry; + struct group *ge; + int ret; + + ret = getgrnam_r(name, &entry, buf, sizeof(buf), &ge); + if (ret || ge == NULL) { + printf("Fail to get gid of %s\n", name); + return -1; + } + + return entry.gr_gid; +} + +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; + const char *pkg_path; + uid_t uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER); + gid_t gid = __get_gid("system_share"); + + pkg_path = __get_package_path(pkgid); + if (pkg_path == NULL) { + printf("Failed to get package path(%s)\n", pkgid); + return -1; + } + + snprintf(pref_dir, sizeof(pref_dir), "%s/data/.pref", pkg_path); + 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, uid, gid) < 0) { + printf("chown() failed(%d/%s)\n", + errno, strerror(errno)); + return -1; + } + } + + snprintf(cmd, sizeof(cmd), + "/usr/bin/chsmack -t -a User::Pkg::\"%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[PATH_MAX]; + uid_t uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER); + gid_t gid = __get_gid("system_share"); + + 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; + } + close(fd); + + if (chown(path, uid, gid) < 0) { + printf("chown() failed(%d/%s)\n", errno, strerror(errno)); + return -1; + } + + snprintf(cmd, sizeof(cmd), "/usr/bin/chsmack -a User::Pkg::\"%s\" %s", + pkgid, path); + if (__system(cmd)) { + printf("[pref] cmd error()\n"); + return -1; + } + + 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 \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 \n"); + printf("ex) preference_tool get org.tizen.preferencetest\n\n"); + printf("preference_tool get \n"); + printf("ex) preference_tool get "); + printf("org.tizen.preferencetest test_key\n\n"); + + printf("[Convert preference file name from plain text]\n"); + printf("preference_tool convert_file_name \n"); + printf("ex) preference_tool convert_file_name /opt/usr/apps\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]; + const char *pkg_path; + + pkg_path = __get_package_path(pkgid); + if (pkg_path == NULL) + return; + + snprintf(pref_dir, sizeof(pref_dir), "%s/data/.pref", pkg_path); + + 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); +} + +static int _add_key_info_to_file(const char *key_path, const char *key) +{ + FILE *fp = NULL; + size_t keyname_len; + char *buf = NULL; + int read_size; + int ret; + long file_size; + + fp = fopen(key_path, "r+"); + if (fp == NULL) { + printf("fopen() failed.(%d/%s).fp is null.\n", + errno, strerror(errno)); + return -1; + } + + fseek(fp, 0, SEEK_END); + file_size = ftell(fp); + rewind(fp); + + buf = (char *)calloc(1, file_size); + if (buf == NULL) { + printf("Out of memory\n"); + ret = -1; + goto out; + } + + /* write keyname and size */ + read_size = fread(buf, 1, file_size, fp); + if ((read_size <= 0)) { + printf("preference read key-val data error(%d/%s)\n", + errno, strerror(errno)); + ret = -1; + goto out; + } + + rewind(fp); + + 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)); + ret = -1; + goto out; + } + + ret = fwrite((void *)key, keyname_len, 1, fp); + if (ret <= 0) { + printf("preference write key name error(%d/%s)\n", + errno, strerror(errno)); + ret = -1; + goto out; + } + ret = fwrite((void *)buf, read_size, 1, fp); + if (ret <= 0) { + printf("preference write key-val data error(%d/%s)\n", + errno, strerror(errno)); + ret = -1; + goto out; + } + + ret = 0; + +out: + if (fp) + fclose(fp); + if (buf) + free(buf); + + return ret; +} + +static int _convert_pref_file(const char *pref_dir) +{ + DIR *dir; + struct dirent *ent; + char old_file[BUF_LEN]; + char new_file[BUF_LEN]; + gchar *convert_key; + char _key[PREFERENCE_KEY_PATH_LEN] = {0,}; + char *chrptr = NULL; + + dir = opendir(pref_dir); + if (!dir) + return -1; + + while ((ent = readdir(dir))) { + if (ent->d_type != DT_REG) + continue; + + snprintf(old_file, sizeof(old_file), "%s/%s", pref_dir, + ent->d_name); + + strncpy(_key, ent->d_name, PREFERENCE_KEY_PATH_LEN - 1); + + chrptr = strchr((const char*)_key, DELIMITER); + if (chrptr) { + chrptr = strchr((const char*)_key, DELIMITER); + while (chrptr) { + _key[chrptr-_key] = '/'; + chrptr = strchr((const char*)chrptr + 1, DELIMITER); + } + } + + convert_key = g_compute_checksum_for_string(G_CHECKSUM_SHA1, + _key, strlen(_key)); + if (convert_key == NULL) { + printf("fail to convert key\n"); + closedir(dir); + return -1; + } + + snprintf(new_file, sizeof(new_file), "%s/%s", pref_dir, + convert_key); + g_free(convert_key); + + if (rename(old_file, new_file) < 0) { + printf("rename %s to %s failed.(%d/%s)\n", + old_file, new_file, + errno, strerror(errno)); + } + + if (_add_key_info_to_file(new_file, _key) < 0) + printf("convert %s file failed\n", new_file); + } + + closedir(dir); + return 0; +} + +static int _convert_file_name(const char *app_dir) +{ + DIR *dir; + struct dirent *ent; + char buf[BUF_LEN]; + int res; + + dir = opendir(app_dir); + if (!dir) { + printf("failed to open app dir (%s)\n", app_dir); + return -1; + } + + while ((ent = readdir(dir))) { + if (ent->d_type != DT_DIR) + continue; + + if (strcmp(ent->d_name, ".") == 0 || + strcmp(ent->d_name, "..") == 0) + continue; + + snprintf(buf, sizeof(buf), "%s/%s/data/.pref", + app_dir, ent->d_name); + if (access(buf, F_OK) == -1) + continue; + + res = _convert_pref_file(buf); + if (res < 0) { + printf("_convert_pref_file error (%s)\n", buf); + closedir(dir); + return -1; + } + } + + closedir(dir); + return 0; +} + +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 if (strcmp(argv[1], "convert_file_name") == 0) { + res = _convert_file_name(argv[2]); + + if (res < 0) { + printf("converting preference file name failed (%s)\n", + argv[2]); + return -1; + } + } else { + _print_help(); + } + + return 0; +}