From ade8db3575b98584c842fae7911db10a4010f300 Mon Sep 17 00:00:00 2001 From: jusung son Date: Tue, 29 May 2018 09:55:50 +0900 Subject: [PATCH] Add dump command in vconftool Change-Id: I285ace5ad1f01c311e47bc47fc19e2f2464e335e Signed-off-by: jusung son --- backend/sqlite.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++ client/c_direct.c | 83 +++++++++++++++++++++++++++++++ client/c_direct.h | 3 ++ client/c_main.c | 8 +++ common/backend.h | 3 ++ common/direct.c | 109 +++++++++++++++++++++++++++++++++++++++++ common/direct.h | 3 ++ vconf-compat/vconftool | 10 ++++ 8 files changed, 349 insertions(+) mode change 100755 => 100644 vconf-compat/vconftool diff --git a/backend/sqlite.c b/backend/sqlite.c index 78a1c5c..7368f98 100644 --- a/backend/sqlite.c +++ b/backend/sqlite.c @@ -487,6 +487,135 @@ end: return ret; } + +static int get_dump(const char *dbpath, char ***keys, void ***values, int **value_len, unsigned int *klen) +{ + sqlite3 *db; + int sql_ret; + int ret = 0; + int index; + const char list_query[] = "select * from buxton ORDER BY key"; + const char count_query[] = "select count(key) from buxton"; + sqlite3_stmt *stmt; + int key_count = 0; + char **key_list = NULL; + void **value_list = NULL; + int *value_len_list = NULL; + + if (!dbpath || !*dbpath || !keys || !values || !value_len) { + errno = EINVAL; + return -1; + } + + db = open_sqlite3(dbpath, true); + if (!db) + return -1; + + sql_ret = sqlite3_prepare_v2(db, count_query, strlen(count_query), + &stmt, NULL); + if (sql_ret != SQLITE_OK) { + bxt_err("prepare error, ret = %d, extended = %d\n", + sql_ret, sqlite3_extended_errcode(db)); + return -1; + } + + sql_ret = sqlite3_step(stmt); + if (sql_ret == SQLITE_ROW) { + key_count = (int)sqlite3_column_int(stmt, 0); + } else { + bxt_err("sqlite3_step error, ret = %d, extended = %d\n", + sql_ret, sqlite3_extended_errcode(db)); + ret = -1; + goto end; + } + + sqlite3_finalize(stmt); + stmt = NULL; + + sql_ret = sqlite3_prepare_v2(db, list_query, strlen(list_query), + &stmt, NULL); + if (sql_ret != SQLITE_OK) { + bxt_err("prepare error, ret = %d, extended = %d\n", + sql_ret, sqlite3_extended_errcode(db)); + ret = -1; + goto end; + } + + key_list = calloc(key_count + 1, sizeof(char *)); + value_list = calloc(key_count + 1, sizeof(void *)); + value_len_list = calloc(key_count + 1, sizeof(int)); + + if (!key_list || !value_list || !value_len_list) { + bxt_err("calloc error OOM"); + ret = -1; + goto end; + } + + for (index = 0; index < key_count; index++) { + sql_ret = sqlite3_step(stmt); + if (sql_ret != SQLITE_ROW) { + bxt_err("sqlite3_step error, ret = %d, extended = %d index = %d , count = %d", + sql_ret, sqlite3_extended_errcode(db), index, key_count); + ret = -1; + goto end; + } + + key_list[index] = strdup((char *)sqlite3_column_text(stmt, 0)); + value_len_list[index] = sqlite3_column_bytes(stmt, 1); + if (value_len_list[index] > 0) { + value_list[index] = malloc(sizeof(void *) * (value_len_list[index] + 1)); + if (value_list[index] == NULL) { + bxt_err("malloc error"); + ret = -1; + goto end; + } + memcpy(value_list[index], (void *)sqlite3_column_blob(stmt, 1), value_len_list[index]); + } else { + value_list[index] = NULL; + } + } + + *keys = key_list; + *values = value_list; + *value_len = value_len_list; + *klen = key_count; + +end: + if (stmt != NULL) { + sql_ret = sqlite3_finalize(stmt); + if (sql_ret != SQLITE_OK) { + bxt_err("Sqlite3 error [%d] : <%s> finalizing statement\n", sql_ret, + sqlite3_errmsg(db)); + ret = -1; + } + } + + if (ret != 0) { + if (key_list) { + for (index = 0; index < key_count; index++) { + if (key_list[index]) + free(key_list[index]); + } + free(key_list); + } + + if (value_list) { + for (index = 0; index < key_count; index++) { + if (value_list[index]) + free(value_list[index]); + } + free(value_list); + } + + if (value_len_list) + free(value_len_list); + } + + bxt_dbg("dump '%s'", dbpath); + + return ret; +} + static void module_exit(void) { g_hash_table_destroy(dbs); @@ -518,5 +647,6 @@ DEFINE_BUXTON_BACKEND = { .get_value = get_value, .unset_value = unset_value, .list_keys = list_keys, + .get_dump = get_dump, }; diff --git a/client/c_direct.c b/client/c_direct.c index 469b595..451d051 100644 --- a/client/c_direct.c +++ b/client/c_direct.c @@ -29,10 +29,21 @@ #include "c_log.h" #include "c_common.h" #include "c_direct.h" +#include #define BUFFER_SIZE 1024 static const char *confpath; +static const char const *type_names[BUXTON_TYPE_MAX] = { + [BUXTON_TYPE_UNKNOWN] = "Unknown", + [BUXTON_TYPE_STRING] = "String", + [BUXTON_TYPE_INT32] = "Int32", + [BUXTON_TYPE_UINT32] = "UInt32", + [BUXTON_TYPE_INT64] = "Int64", + [BUXTON_TYPE_UINT64] = "UInt64", + [BUXTON_TYPE_DOUBLE] = "Double", + [BUXTON_TYPE_BOOLEAN] = "Boolean", +}; void c_direct_set_conf(const char *conf) { @@ -529,3 +540,75 @@ int c_direct_remove_garbage(const struct buxton_layer *layer, return 0; } + +int c_direct_dump(const struct buxton_layer *layer, + UNUSED const char *key, UNUSED const char *value, + UNUSED const char *rpriv, UNUSED const char *wpriv) +{ + int r, key_len, i; + struct buxton_value *value_list; + char **key_list; + char err_buf[BUFFER_SIZE]; + + if (!layer) { + errno = EINVAL; + strerror_r(errno, err_buf, sizeof(err_buf)); + bxt_err("List: Layer '%s': %s", + layer ? buxton_layer_get_name(layer) : "", + err_buf); + return -1; + } + + r = c_init(); + if (r == -1) + return -1; + + r = direct_dump(layer, &key_list, &value_list, &key_len); + + c_exit(); + + if (r == -1) { + strerror_r(errno, err_buf, sizeof(err_buf)); + bxt_err("List: Layer '%s': %s", buxton_layer_get_name(layer), + err_buf); + return -1; + } + + for (i = 0 ; i < key_len; i++) { + printf("%s, value = ", key_list[i]); + + switch (value_list[i].type) { + case BUXTON_TYPE_STRING: + printf("%s (%s)\n", value_list[i].value.s, type_names[value_list[i].type]); + free(value_list[i].value.s); + break; + case BUXTON_TYPE_INT32: + printf("%d (%s)\n", value_list[i].value.i, type_names[value_list[i].type]); + break; + case BUXTON_TYPE_UINT32: + printf("%u (%s)\n", value_list[i].value.u, type_names[value_list[i].type]); + break; + case BUXTON_TYPE_INT64: + printf("%" PRId64 " (%s)\n", value_list[i].value.i64, type_names[value_list[i].type]); + break; + case BUXTON_TYPE_UINT64: + printf("%" PRIu64 " (%s)\n", value_list[i].value.u64, type_names[value_list[i].type]); + break; + case BUXTON_TYPE_DOUBLE: + printf("%lf (%s)\n", value_list[i].value.d, type_names[value_list[i].type]); + break; + case BUXTON_TYPE_BOOLEAN: + printf("%s (%s)\n", value_list[i].value.b ? "True" : "False", type_names[value_list[i].type]); + break; + default: + printf("Unknown type\n"); + break; + } + } + + buxton_free_keys(key_list); + free(value_list); + + return 0; +} + diff --git a/client/c_direct.h b/client/c_direct.h index 1a9a178..9c0a0ed 100644 --- a/client/c_direct.h +++ b/client/c_direct.h @@ -93,4 +93,7 @@ int c_direct_create_bool(const struct buxton_layer *layer, int c_direct_remove_garbage(UNUSED const struct buxton_layer *layer, UNUSED const char *key, UNUSED const char *value, UNUSED const char *rpriv, UNUSED const char *wpriv); +int c_direct_dump(const struct buxton_layer *layer, + UNUSED const char *key, UNUSED const char *value, + UNUSED const char *rpriv, UNUSED const char *wpriv); diff --git a/client/c_main.c b/client/c_main.c index dcd63a8..344a816 100644 --- a/client/c_main.c +++ b/client/c_main.c @@ -254,6 +254,14 @@ static const struct command const commands[] = { .func = c_direct_remove_garbage, .dfunc = c_direct_remove_garbage, }, + { + .name = "dump", + .summary = "Dump for a layer", + .nargs = 1, + .usage = "LAYER", + .func = c_direct_dump, + .dfunc = c_direct_dump, + }, }; static const struct command *find_comm(const char *name) diff --git a/common/backend.h b/common/backend.h index f3c29c3..7db0627 100644 --- a/common/backend.h +++ b/common/backend.h @@ -38,6 +38,8 @@ typedef int (*backend_get_value)(const char *dbpath, typedef int (*backend_unset_value)(const char *dbpath, const char *key); typedef int (*backend_list_keys)(const char *dbpath, char ***keys, unsigned int *klen, bool readonly); +typedef int (*backend_get_dump)(const char *dbpath, + char ***keys, void ***values, int **value_len, unsigned int *klen); struct backend { const char *name; @@ -52,6 +54,7 @@ struct backend { backend_get_value get_value; backend_unset_value unset_value; backend_list_keys list_keys; + backend_get_dump get_dump; void *reserved[7]; }; diff --git a/common/direct.c b/common/direct.c index fc38989..e953459 100644 --- a/common/direct.c +++ b/common/direct.c @@ -488,6 +488,115 @@ int direct_list(const struct buxton_layer *layer, return 0; } +int direct_dump(const struct buxton_layer *layer, + char ***key_list, struct buxton_value **value_list, int *len) +{ + int ret; + const struct layer *ly; + const struct backend *backend; + char path[FILENAME_MAX]; + unsigned int base_len, nomal_len; + int i, j; + struct buxton_value *_value_list = NULL; + char **base_keys = NULL, **normal_keys = NULL; + void **base_values = NULL, **normal_values = NULL; + int *base_value_len = NULL, *normal_value_len = NULL; + void *tmp; + int len_tmp; + + if (!layer || !key_list || !value_list || !len) { + errno = EINVAL; + return -1; + } + + ly = conf_get_layer(layer->name); + if (!ly) + return -1; + + backend = backend_get(ly->backend); + assert(backend); + + if (!backend->get_dump) { + bxt_err("dump: backend '%s' has no list func", + backend->name); + return -1; + } + + ret = get_path(layer->uid, BUXTON_LAYER_BASE, + ly, path, sizeof(path)); + if (ret == -1) + return -1; + + /*base_keys is sorted data */ + ret = backend->get_dump(path, &base_keys, &base_values, &base_value_len, &base_len); + if (ret == -1) { + bxt_err("dump: get_dump failed"); + return -1; + } + + ret = get_path(layer->uid, BUXTON_LAYER_NORMAL, + ly, path, sizeof(path)); + if (ret == -1) { + buxton_free_keys(base_keys); + buxton_free_keys((char **)base_values); + goto out; + } + + /* normal_keys is sorted data */ + ret = backend->get_dump(path, &normal_keys, &normal_values, &normal_value_len, &nomal_len); + if (ret == -1) { + bxt_err("dump: get_dump failed"); + goto out; + } + + _value_list = calloc(base_len, sizeof(struct buxton_value)); + if (_value_list == NULL) { + bxt_err("dump: calloc failed"); + ret = -1; + goto out; + } + + for (i = 0, j = 0; i < base_len; i++) { + if (j < nomal_len) { + if (strcmp(base_keys[i], normal_keys[j]) == 0) { + tmp = normal_values[j]; + len_tmp = normal_value_len[j]; + j++; + } else { + tmp = base_values[i]; + len_tmp = base_value_len[i]; + } + } else { + tmp = base_values[i]; + len_tmp = base_value_len[i]; + } + ret = deserialz_data((uint8_t *)tmp, len_tmp, NULL, NULL, &_value_list[i]); + if (ret == -1) { + bxt_err("dump: deserialz_data failed %s ", base_keys[i]); + goto out; + } + } + + *key_list = base_keys; + *value_list = _value_list; + *len = base_len; + +out: + buxton_free_keys((char **)base_values); + buxton_free_keys(normal_keys); + buxton_free_keys((char **)normal_values); + free(base_value_len); + free(normal_value_len); + + if (ret != 0) { + buxton_free_keys(base_keys); + + if (_value_list) + free(_value_list); + } + return ret; +} + int direct_get_priv(const struct buxton_layer *layer, const char *key, enum buxton_priv_type type, char **priv) { diff --git a/common/direct.h b/common/direct.h index ac0ef0a..380877c 100644 --- a/common/direct.h +++ b/common/direct.h @@ -43,3 +43,6 @@ int direct_set_priv(const struct buxton_layer *layer, const char *key, enum buxton_priv_type type, const char *priv); int direct_remove_db(const struct buxton_layer *layer); + +int direct_dump(const struct buxton_layer *layer, + char ***key_list, struct buxton_value **value_list, int *len); diff --git a/vconf-compat/vconftool b/vconf-compat/vconftool old mode 100755 new mode 100644 index 833b46c..acf6ad6 --- a/vconf-compat/vconftool +++ b/vconf-compat/vconftool @@ -97,6 +97,15 @@ do_get() { fi } +do_dump() { + [ -z "${OPT_KEY}" ] && echo "Invalid key name" && usage + + LAYER=`get_layer ${OPT_KEY}` + + dbg ${BUXTONTOOL} ${OPT_DIRECT} dump ${LAYER} + ${BUXTONTOOL} ${OPT_DIRECT} dump ${LAYER} +} + do_unset() { [ -z "${OPT_KEY}" ] && echo "Invalid key name" && usage @@ -323,6 +332,7 @@ set) do_set ;; unset) do_unset ;; backup) do_backup ;; restore) do_restore ;; +dump) do_dump ;; *) usage ;; esac -- 2.7.4