diff options
Diffstat (limited to 'preference/preference_tool.c')
-rwxr-xr-x | preference/preference_tool.c | 800 |
1 files changed, 800 insertions, 0 deletions
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; +} |