From: Youngjae Cho Date: Fri, 23 Jul 2021 06:06:46 +0000 (+0900) Subject: tool: add command line tool for managing system-info X-Git-Tag: submit/tizen/20210726.084601^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c19a8e89e66754c09f6bf90c51d5d49c249f5a25;p=platform%2Fcore%2Fapi%2Fsystem-info.git tool: add command line tool for managing system-info USAGE system-into-tool [OPTION] OPTION -l|--list-all List all system-info database entries -g|--get KEY [-v|--verbose] Get value of feature KEY If -v option is given, shows result in detail ex) system-info-tool -g tizen.org/feature/display system-info-tool -g tizen.org/system/manufacturer -v -s|--set KEY TYPE VALUE Add or update user-defined KEY Available TYPE: bool, int, double, string ex) system-info-tool -a tizen.org/feature/display bool 1 system-info-tool -a tizen.org/system/manufacturer string Tizen -c|--clear KEY Clear user-defined KEY. This cannot clear read-only system key -C|--clear-all Clear all user-defined keys -h|--help Show this help Change-Id: Id2f72ee242e12d90edc82797a21fdb8b097e2bc6 Signed-off-by: Youngjae Cho --- diff --git a/CMakeLists.txt b/CMakeLists.txt index dd5466e..5e55835 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,6 +88,7 @@ INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/system_info_intf.h DESTINATION ADD_SUBDIRECTORY(src/tizenid) ADD_SUBDIRECTORY(src/init_db) ADD_SUBDIRECTORY(test) +ADD_SUBDIRECTORY(tool) IF(UNIX) diff --git a/include/system_info_private.h b/include/system_info_private.h index 2454c76..37fd5cb 100644 --- a/include/system_info_private.h +++ b/include/system_info_private.h @@ -76,7 +76,7 @@ static const struct runtime runtime[LANG_MAX] = { }; #define NUM_HASH_FILE 10 -static inline unsigned long simple_hash(char *str) +static inline unsigned long simple_hash(const char *str) { unsigned long ret = 0; int c; diff --git a/include/system_info_type.h b/include/system_info_type.h index bbd2eab..d5a71ec 100644 --- a/include/system_info_type.h +++ b/include/system_info_type.h @@ -50,13 +50,14 @@ typedef enum { * @brief It is not decided if it should be opened to public. */ typedef enum { - SYSTEM_INFO_BOOL, + SYSTEM_INFO_TYPE_MIN = 0, + SYSTEM_INFO_BOOL = SYSTEM_INFO_TYPE_MIN, SYSTEM_INFO_INT, SYSTEM_INFO_DOUBLE, SYSTEM_INFO_STRING, + SYSTEM_INFO_TYPE_MAX, } system_info_type_e; - /** * @internal * @brief Enumeration for system information key. diff --git a/packaging/capi-system-info.spec b/packaging/capi-system-info.spec index 80f1212..afd3aa6 100644 --- a/packaging/capi-system-info.spec +++ b/packaging/capi-system-info.spec @@ -14,6 +14,7 @@ BuildRequires: pkgconfig(libxml-2.0) BuildRequires: pkgconfig(glib-2.0) BuildRequires: pkgconfig(libtzplatform-config) BuildRequires: pkgconfig(uuid) +BuildRequires: pkgconfig(libsyscommon) BuildRequires: glibc-devel-static Requires: security-config @@ -34,6 +35,14 @@ Requires: %{name} %description test A System Information test tool +%package tool +Summary: System-info command line tool package +Group: Development/System +Requires: %{name} + +%description tool +A System Information command line tool + %if 0%{?gcov:1} %package -n system-info-gcov Summary: A System Information gcov test file @@ -141,3 +150,6 @@ install -m 0644 gcov-obj/* %{buildroot}%{_datadir}/gcov/obj %files -n system-info-gcov %{_datadir}/gcov/obj/* %endif + +%files tool +%{_bindir}/system-info-tool diff --git a/tool/CMakeLists.txt b/tool/CMakeLists.txt new file mode 100755 index 0000000..5f44875 --- /dev/null +++ b/tool/CMakeLists.txt @@ -0,0 +1,14 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(TOOL_REQUIRED REQUIRED libsyscommon) + +SET(SYSTEM_INFO_TOOL "system-info-tool") +FILE(GLOB SRCS "*.c") + +ADD_EXECUTABLE(${SYSTEM_INFO_TOOL} ${SRCS}) +SET_TARGET_PROPERTIES(${SYSTEM_INFO_TOOL} PROPERTIES COMPILE_FLAGS "-fPIE") +ADD_DEPENDENCIES(${SYSTEM_INFO_TOOL} capi-system-info) +TARGET_LINK_LIBRARIES(${SYSTEM_INFO_TOOL} capi-system-info ${TOOL_REQUIRED_LDFLAGS} -pie) + +INSTALL(TARGETS ${SYSTEM_INFO_TOOL} DESTINATION bin) diff --git a/tool/system-info-tool-get.c b/tool/system-info-tool-get.c new file mode 100644 index 0000000..c6662bd --- /dev/null +++ b/tool/system-info-tool-get.c @@ -0,0 +1,271 @@ +#include +#include +#include +#include + +#include "system-info-tool.h" +#include "system-info-tool-get.h" + +void system_info_tool_get_help(void) +{ + printf(" -l|--list-all List all system-info database entries\n"); + printf(" -g|--get KEY [-v|--verbose] Get value of feature KEY\n"); + printf(" If -v option is given, shows result in detail\n"); + printf(" ex) system-info-tool -g tizen.org/feature/display\n"); + printf(" system-info-tool -g tizen.org/system/manufacturer -v\n"); +} + +static void print_dbentry(struct dbentry *dbentry, bool found) +{ + const struct db *db; + + if (!dbentry || !dbentry->db) + return; + + db = dbentry->db; + + if (found) { + printf("%s Key (%c) found: ", db->name, db->ticker); + } else { + printf("%s Key (%c) not found\n", db->name, db->ticker); + return; + } + + print_value(dbentry->value); +} + +int system_info_tool_get_raw(const char *searchkey, system_info_type_e searchtype, + enum db_e searchdb, struct dbentry *dbentry) +{ + char dbpath[BUFFER_MAX - 1]; + char dbentry_format[BUFFER_MAX]; + int retval; + + if (!dbentry) + return -EINVAL; + + if (searchdb < DB_START || searchdb >= DB_END) + return -EINVAL; + + dbentry->db = &db[searchdb]; + + /* scanf format: "%127[^:]:%127[^:]:%127s %127s" */ + snprintf(dbentry_format, sizeof(dbentry_format), "%%%d[^:]:%%%d[^:]:%%%ds %%%ds", + BUFFER_MAX - 1, BUFFER_MAX - 1, BUFFER_MAX - 1, BUFFER_MAX - 1); + + for (int i = 0; i < NUM_HASH_FILE; ++i) { + __auto_fclose__ FILE *fp = NULL; + char line[BUFFER_MAX * 8] = {0, }; + char tag[BUFFER_MAX - 1] = {0, }; + char key[BUFFER_MAX - 1] = {0, }; + char type[BUFFER_MAX - 1] = {0, }; + char value[BUFFER_MAX - 1] = {0, }; + const char *typestring; + + snprintf(dbpath, sizeof(dbpath), "%s/%d", db[searchdb].path, i); + fp = fopen(dbpath, "r"); + if (!fp) + continue; + + while ((fgets(line, sizeof(line), fp))) { + retval = sscanf(line, dbentry_format, tag, key, type, value); + if (retval != 4) + continue; + + if (strncmp(key, searchkey, strlen(key) + 1)) + continue; + + typestring = type_to_string(searchtype); + if (strncmp(type, typestring, strlen(type) + 1)) + continue; + + strncpy(dbentry->key, key, sizeof(dbentry->key) - 1); + strncpy(dbentry->tag, tag, sizeof(dbentry->tag) - 1); + dbentry->value.type = searchtype; + if (strncmp(type, "bool", sizeof("bool")) == 0) + dbentry->value.b = (value[runtime_env] == 'T'); + else if (strncmp(type, "int", sizeof("int")) == 0) + dbentry->value.i = atoi(value); + else if (strncmp(type, "double", sizeof("double")) == 0) + dbentry->value.d = atof(value); + else if (strncmp(type, "string", sizeof("string")) == 0) + dbentry->value.s = strndup(value, sizeof(value)); + + return 0; + } + } + + return -ENOENT; +} + +static int system_info_tool_get_api(const char *key, struct value *value) +{ + int retval; + int ret; + int match = 0; + int select; + int i; + + struct cache { + int match; + struct value value; + } cache[SYSTEM_INFO_TYPE_MAX] = { + { -1, { SYSTEM_INFO_BOOL, } }, + { -1, { SYSTEM_INFO_INT, } }, + { -1, { SYSTEM_INFO_DOUBLE, } }, + { -1, { SYSTEM_INFO_STRING, } }, + }; + + retval = system_info_get_platform_bool(key, &cache[SYSTEM_INFO_BOOL].value.b); + if (retval == 0) + cache[SYSTEM_INFO_BOOL].match = ++match; + + retval = system_info_get_platform_int(key, &cache[SYSTEM_INFO_INT].value.i); + if (retval == 0) + cache[SYSTEM_INFO_INT].match = ++match; + + retval = system_info_get_platform_double(key, &cache[SYSTEM_INFO_DOUBLE].value.d); + if (retval == 0) + cache[SYSTEM_INFO_DOUBLE].match = ++match; + + retval = system_info_get_platform_string(key, &cache[SYSTEM_INFO_STRING].value.s); + if (retval == 0) + cache[SYSTEM_INFO_STRING].match = ++match; + + if (match == 1) { + for (i = 0; i < SYSTEM_INFO_TYPE_MAX; ++i) + if (cache[i].match == match) + memcpy(value, &cache[i].value, sizeof(struct value)); + return 0; + } else if (match > 1) { + printf("There is multiple same keys with different type. Which type to search?\n"); + for (i = 0; i < SYSTEM_INFO_TYPE_MAX; ++i) + if (cache[i].match > 0) { + printf(" [%d] ", cache[i].match); + print_value(cache[i].value); + } + + printf("Select: "); + retval = scanf("%d", &select); + if (retval != 1) { + printf("Invalid selection\n"); + ret = -EINVAL; + goto out; + } + + for (i = 0; i < SYSTEM_INFO_TYPE_MAX; ++i) { + if (cache[i].match == select) { + memcpy(value, &cache[i].value, sizeof(struct value)); + return 0; + } + } + + if (i == SYSTEM_INFO_TYPE_MAX) { + printf("Invalid selection\n"); + ret = -EINVAL; + goto out; + } + } + + printf("key=%s is not found\n", key); + ret = -ENOENT; + +out: + free(cache[SYSTEM_INFO_STRING].value.s); + + return ret; +} + +void system_info_tool_get(const char *key, bool verbose) +{ + struct value api; + int retval; + + retval = system_info_tool_get_api(key, &api); + if (retval < 0) + return; + + /* show each database if -v option is given */ + if (verbose) { + int retplt; + int rethal; + int retusr; + + /* set db to be searched */ + __auto_free_dbentry__ struct dbentry plt = { 0, }; /* scan platform ro db */ + __auto_free_dbentry__ struct dbentry hal = { 0, }; /* scan platform hal ro db */ + __auto_free_dbentry__ struct dbentry usr = { 0, }; /* scan platform rw db */ + + retplt = system_info_tool_get_raw(key, api.type, DB_DEFAULT_RO, &plt); + print_dbentry(&plt, retplt == 0); + + rethal = system_info_tool_get_raw(key, api.type, DB_HAL_RO, &hal); + print_dbentry(&hal, rethal == 0); + + retusr = system_info_tool_get_raw(key, api.type, DB_DEFAULT_RW, &usr); + print_dbentry(&usr, retusr == 0); + + /* print description how API have derived the result */ + if (retusr == 0) { + printf("Result (=%c overrides %c,%c): ", usr.db->ticker, plt.db->ticker, hal.db->ticker); + } else if (retplt == 0 && rethal == 0) { + if (plt.value.type == SYSTEM_INFO_BOOL && hal.value.type == SYSTEM_INFO_BOOL) + printf("Result (=%c && %c): ", plt.db->ticker, hal.db->ticker); + else + printf("Result (=%c overrides %c): ", hal.db->ticker, plt.db->ticker); + } else if (retplt == 0) { + printf("Result (=%c): ", plt.db->ticker); + } else if (rethal == 0) { + printf("Result (=%c): ", hal.db->ticker); + } else { + printf("Result (error occured): "); + } + } + + print_value(api); + + return; +} + +void system_info_tool_list_all(enum db_e dbtype) +{ + char dbpath[BUFFER_MAX - 1]; + char dbentry_format[BUFFER_MAX]; + int retval; + + if (access(db[dbtype].path, F_OK) != 0) + return; + + /* scanf format: "%127[^:]:%127[^:]:%127s %127s" */ + snprintf(dbentry_format, sizeof(dbentry_format), "%%%d[^:]:%%%d[^:]:%%%ds %%%ds", + BUFFER_MAX - 1, BUFFER_MAX - 1, BUFFER_MAX - 1, BUFFER_MAX - 1); + + for (int i = 0; i < NUM_HASH_FILE; ++i) { + __auto_fclose__ FILE *fp = NULL; + char line[BUFFER_MAX * 8] = {0, }; + char tag[BUFFER_MAX - 1] = {0, }; + char key[BUFFER_MAX - 1] = {0, }; + char type[BUFFER_MAX - 1] = {0, }; + char value[BUFFER_MAX - 1] = {0, }; + + snprintf(dbpath, sizeof(dbpath), "%s/%d", db[dbtype].path, i); + fp = fopen(dbpath, "r"); + if (!fp) + continue; + + while ((fgets(line, sizeof(line), fp))) { + retval = sscanf(line, dbentry_format, tag, key, type, value); + if (retval != 4) + continue; + + printf("%s: ", db[dbtype].name); + printf("key=%s, ", key); + printf("type=%s, ", type); + if (strncmp(type, "bool", sizeof("bool")) == 0) + printf("value=%d, ", (value[runtime_env] == 'T')); + else + printf("value=%s, ", value); + printf("tag=%s\n", tag); + } + } +} diff --git a/tool/system-info-tool-get.h b/tool/system-info-tool-get.h new file mode 100644 index 0000000..f5bd039 --- /dev/null +++ b/tool/system-info-tool-get.h @@ -0,0 +1,12 @@ +#ifndef __SYSTEM_INFO_TOOL_GET_H__ +#define __SYSTEM_INFO_TOOL_GET_H__ + +#include + +void system_info_tool_get_help(void); +void system_info_tool_get(const char *key, bool verbose); +int system_info_tool_get_raw(const char *searchkey, system_info_type_e searchtype, + enum db_e searchdb, struct dbentry *dbentry); +void system_info_tool_list_all(enum db_e dbtype); + +#endif diff --git a/tool/system-info-tool-set.c b/tool/system-info-tool-set.c new file mode 100644 index 0000000..a893b45 --- /dev/null +++ b/tool/system-info-tool-set.c @@ -0,0 +1,343 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "system-info-tool.h" +#include "system-info-tool-get.h" +#include "system-info-tool-set.h" + +void system_info_tool_set_help(void) +{ + printf(" -s|--set KEY TYPE VALUE Add or update user-defined KEY\n"); + printf(" Available TYPE: bool, int, double, string\n"); + printf(" ex) system-info-tool -a tizen.org/feature/display bool 1\n"); + printf(" system-info-tool -a tizen.org/system/manufacturer string Tizen\n"); + printf(" -c|--clear KEY Clear user-defined KEY. This cannot clear read-only system key\n"); + printf(" -C|--clear-all Clear all user-defined keys\n"); +} + +static int convert_raw_optargs(const char *rawtype, const char *rawvalue, struct value *out) +{ + system_info_type_e type = string_to_type(rawtype); + + if (type == SYSTEM_INFO_TYPE_MAX) { + printf("Invalid type \"%s\"\n", rawtype); + return -EINVAL; + } + + out->type = type; + + if (type == SYSTEM_INFO_BOOL) { + int tmpbool; + if (sscanf(rawvalue, "%d", &tmpbool) == 1) { + out->b = tmpbool; + return 0; + } else if (strncasecmp(rawvalue, "true", sizeof("true")) == 0) { + out->b = true; + return 0; + } else if (strncasecmp(rawvalue, "false", sizeof("false")) == 0) { + out->b = false; + return 0; + } + printf("Invalid bool value \"%s\"\n", rawvalue); + } else if (type == SYSTEM_INFO_INT) { + if (sscanf(rawvalue, "%d", &out->i) == 1) + return 0; + printf("Invalid int value \"%s\"\n", rawvalue); + } else if (type == SYSTEM_INFO_DOUBLE) { + if (sscanf(rawvalue, "%lf", &out->d) == 1) + return 0; + printf("Invalid double value \"%s\"\n", rawvalue); + } else if (type == SYSTEM_INFO_STRING) { + out->s = strndup(rawvalue, BUFFER_MAX); + return 0; + } + + return -EINVAL; +} + +static int try_flock(FILE *fp, bool blocking) +{ + int fd = -1; + int retval; + int flags = LOCK_EX; + + if (!fp) + return -EBADF; + + fd = fileno(fp); + if (fd < 0) + return -errno; + + if (blocking == false) + flags |= LOCK_NB; + + retval = flock(fd, flags); + if (retval != 0) { + if (errno == EWOULDBLOCK) + printf("User-defined database is now being accessed by someone. Try again\n"); + else + printf("Failed to acquire exclusive flock, %m\n"); + return -errno; + } + + return 0; +} + +static int add_new_entry(const char *key, struct value value) +{ + char dbpath[BUFFER_MAX]; + char internal_key[BUFFER_MAX] = {0, }; + char internal_value[BUFFER_MAX] = {0, }; + int retval; + __auto_fclose__ FILE *fp = NULL; + + if (!key) + return -EINVAL; + + /* make internal_key */ + snprintf(internal_key, sizeof(internal_key), "platform:%s:%s", key, type_to_string(value.type)); + + /* make internal_value */ + if (value.type == SYSTEM_INFO_BOOL) { + if (value.b == true) + snprintf(internal_value, sizeof(internal_value), "TTTTTTTT"); + else + snprintf(internal_value, sizeof(internal_value), "FFFFFFFF"); + } else if (value.type == SYSTEM_INFO_INT) { + snprintf(internal_value, sizeof(internal_value), "%d", value.i); + } else if (value.type == SYSTEM_INFO_DOUBLE) { + snprintf(internal_value, sizeof(internal_value), "%lf", value.d); + } else if (value.type == SYSTEM_INFO_STRING) { + snprintf(internal_value, sizeof(internal_value), "%s", value.s); + } else { + return -EINVAL; + } + + snprintf(dbpath, sizeof(dbpath), "%s/%lu", SYSTEM_INFO_DB_RW_PATH, simple_hash(internal_key)); + fp = fopen(dbpath, "a"); + if (!fp) + return -errno; + + retval = try_flock(fp, false); + if (retval < 0) + return retval; + + retval = fprintf(fp, "%s %s\n", internal_key, internal_value); + if (retval < 0) + return -EIO; + + return 0; +} + +static int remove_entry(const char *key, system_info_type_e type) +{ + char dbpath[BUFFER_MAX]; + char backup[BUFFER_MAX]; + char internal_key[BUFFER_MAX]; + char line[BUFFER_MAX * 8]; + char readkey[BUFFER_MAX]; + char readtype[BUFFER_MAX]; + __auto_fclose__ FILE *fp1 = NULL; + __auto_fclose__ FILE *fp2 = NULL; + int retval; + + if (!key) + return -EINVAL; + + if (type < SYSTEM_INFO_TYPE_MIN || type >= SYSTEM_INFO_TYPE_MAX) + return -EINVAL; + + /* make internal_key */ + snprintf(internal_key, sizeof(internal_key), "platform:%s:%s", key, type_to_string(type)); + + snprintf(dbpath, sizeof(dbpath), "%s/%lu", SYSTEM_INFO_DB_RW_PATH, simple_hash(internal_key)); + fp1 = fopen(dbpath, "r+"); + if (!fp1) + return -errno; + + retval = try_flock(fp1, false); + if (retval < 0) + return retval; + + snprintf(backup, sizeof(backup), "%s/.backup.%lu", SYSTEM_INFO_DB_RW_PATH, simple_hash(internal_key)); + fp2 = fopen(backup, "w+"); + if (!fp2) + return -errno; + + while ((fgets(line, sizeof(line), fp1))) { + retval = sscanf(line, "platform:%127s:%127s", readkey, readtype); + if (retval != 2) + continue; + + if (strncmp(readkey, key, sizeof(readkey)) == 0 + && string_to_type(readtype) == type) + continue; + + fprintf(fp2, "%s", line); + } + + if (truncate(dbpath, 0) < 0) + printf("Failed to reset database, %m\n"); + + rewind(fp1); + rewind(fp2); + + while ((fgets(line, sizeof(line), fp2))) + fprintf(fp1, "%s", line); + + unlink(backup); + + return 0; +} + +static int modify_entry(const char *key, struct value value) +{ + int ret; + + ret = remove_entry(key, value.type); + if (ret < 0) + return ret; + + return add_new_entry(key, value); +} + +static int system_info_tool_set_entry(const char *key, struct value value) +{ + __auto_free_dbentry__ struct dbentry dbentry = {0, }; + int retval; + + if (!key) + return -EINVAL; + + retval = system_info_tool_get_raw(key, value.type, DB_DEFAULT_RW, &dbentry); + if (retval == 0) + return modify_entry(key, value); + else + return add_new_entry(key, value); +} + +static int system_info_tool_init_rw_database(void) +{ + return system("/usr/bin/mkdir -p "SYSTEM_INFO_DB_RW_PATH); +} + +int system_info_tool_set(int argc, char *argv[]) +{ + int ret; + char *key; + struct value value; + + /* argv[optind] : key + * argv[optind + 1]: type + * argv[optind + 2]: value + * check if there is at least 3 arguments */ + if (argc - optind < 3) { + printf("Need key, type, value\n"); + return -EINVAL; + } + + if (access(SYSTEM_INFO_DB_RW_PATH, F_OK) != 0) { + ret = system_info_tool_init_rw_database(); + if (ret != 0) + return -ENOTSUP; + } + + key = argv[optind]; + ret = convert_raw_optargs(argv[optind + 1], argv[optind + 2], &value); + if (ret < 0) + return ret; + + return system_info_tool_set_entry(key, value); +} + +int system_info_tool_clear_key(const char *key) +{ + int retval; + int ret; + int match = 0; + int i; + int select; + + struct cache { + int match; + struct dbentry dbentry; + } cache[SYSTEM_INFO_TYPE_MAX] = { + { -1, }, + { -1, }, + { -1, }, + { -1, }, + }; + + for (i = 0; i < SYSTEM_INFO_TYPE_MAX; ++i) { + retval = system_info_tool_get_raw(key, i, DB_DEFAULT_RW, &cache[i].dbentry); + if (retval == 0) + cache[i].match = ++match; + } + + if (match == 1) { + for (i = 0; i < SYSTEM_INFO_TYPE_MAX; ++i) { + if (cache[i].match == match) { + ret = remove_entry(cache[i].dbentry.key, cache[i].dbentry.value.type); + goto out; + } + } + } else if (match > 1) { + printf("There is multiple same keys with different type. Which type to clear?\n"); + for (i = 0; i < SYSTEM_INFO_TYPE_MAX; ++i) + if (cache[i].match > 0) { + printf(" [%d] ", cache[i].match); + print_value(cache[i].dbentry.value); + } + + printf("Select: "); + retval = scanf("%d", &select); + if (retval != 1) { + printf("Invalid selection\n"); + ret = -EINVAL; + goto out; + } + + for (i = 0; i < SYSTEM_INFO_TYPE_MAX; ++i) { + if (cache[i].match == select) { + ret = remove_entry(cache[i].dbentry.key, cache[i].dbentry.value.type); + goto out; + } + } + } + + printf("user-defined key=%s is not found\n", key); + ret = -ENOENT; + +out: + if (cache[SYSTEM_INFO_STRING].match > 0) + free(cache[SYSTEM_INFO_STRING].dbentry.value.s); + + return ret; +} + +void system_info_tool_clear_all(void) +{ + char dbpath[BUFFER_MAX]; + int retval; + + for (int i = 0; i < NUM_HASH_FILE; ++i) { + __auto_fclose__ FILE *fp = NULL; + snprintf(dbpath, sizeof(dbpath), "%s/%d", SYSTEM_INFO_DB_RW_PATH, i); + fp = fopen(dbpath, "r"); + if (!fp) + continue; + + retval = try_flock(fp, true); + if (retval < 0) + continue; + + if (truncate(dbpath, 0) < 0) + printf("Failed to reset database, %m\n"); + unlink(dbpath); + } +} diff --git a/tool/system-info-tool-set.h b/tool/system-info-tool-set.h new file mode 100644 index 0000000..16f1a62 --- /dev/null +++ b/tool/system-info-tool-set.h @@ -0,0 +1,9 @@ +#ifndef __SYSTEM_INFO_TOOL_SET_H__ +#define __SYSTEM_INFO_TOOL_SET_H__ + +void system_info_tool_set_help(void); +int system_info_tool_set(int argc, char *argv[]); +int system_info_tool_clear_key(const char *key); +void system_info_tool_clear_all(void); + +#endif diff --git a/tool/system-info-tool.c b/tool/system-info-tool.c new file mode 100644 index 0000000..538d533 --- /dev/null +++ b/tool/system-info-tool.c @@ -0,0 +1,152 @@ +#include +#include +#include +#include + +#include "system-info-tool.h" +#include "system-info-tool-get.h" +#include "system-info-tool-set.h" + +int runtime_env = C; +const struct db db[DB_END] = { +/* { dbpath, dbname, ticker } */ + [DB_DEFAULT_RO] = { SYSTEM_INFO_DB_RO_PATH, "Platform", 'A' }, + [DB_HAL_RO] = { SYSTEM_INFO_HAL_DB_RO_PATH, "HAL", 'B' }, + [DB_DEFAULT_RW] = { SYSTEM_INFO_DB_RW_PATH, "User-defined", 'C' }, +}; + +static const char *__type_to_string[SYSTEM_INFO_TYPE_MAX] = { + [SYSTEM_INFO_BOOL] = "bool", + [SYSTEM_INFO_INT] = "int", + [SYSTEM_INFO_DOUBLE] = "double", + [SYSTEM_INFO_STRING] = "string", +}; + +const char *type_to_string(system_info_type_e type) +{ + if (type < SYSTEM_INFO_TYPE_MIN || type >= SYSTEM_INFO_TYPE_MAX) + return NULL; + + return __type_to_string[type]; +} + +system_info_type_e string_to_type(const char *type) +{ + if (strncasecmp(type, "bool", sizeof("bool")) == 0) + return SYSTEM_INFO_BOOL; + else if (strncasecmp(type, "int", sizeof("int")) == 0) + return SYSTEM_INFO_INT; + else if (strncasecmp(type, "double", sizeof("double")) == 0) + return SYSTEM_INFO_DOUBLE; + else if (strncasecmp(type, "string", sizeof("string")) == 0) + return SYSTEM_INFO_STRING; + else + return SYSTEM_INFO_TYPE_MAX; +} + +void print_value(struct value value) +{ + if (value.type == SYSTEM_INFO_BOOL) + printf("type=bool, value=%d\n", value.b); + else if (value.type == SYSTEM_INFO_INT) + printf("type=int, value=%d\n", value.i); + else if (value.type == SYSTEM_INFO_DOUBLE) + printf("type=double, value=%f\n", value.d); + else if (value.type == SYSTEM_INFO_STRING) + printf("type=string, value=%s\n", value.s); + else + printf("type=inavlid, error\n"); +} + +static void system_info_tool_show_help(void) +{ + printf("USAGE\n"); + printf(" system-into-tool [OPTION]\n\n"); + printf("OPTION\n"); + system_info_tool_get_help(); + system_info_tool_set_help(); + printf(" -h|--help Show this help\n"); +} + +int main(int argc, char *argv[]) +{ + int opt; + int retval; + char *runtime_str; + char *key; + bool verbose = false; + GList *keys = NULL; + GList *elem; + + if (argc < 2) { + system_info_tool_show_help(); + return 1; + } + + runtime_str = getenv("RUNTIME_TYPE"); + if (runtime_str) { + for (int i = 0; runtime[i].lang != LANG_MAX; ++i) { + if (strncmp(runtime[i].runtime_type, runtime_str, strlen(runtime_str) + 1) == 0) { + runtime_env = runtime[i].lang; + break; + } + } + } + + const struct option long_option[] = { + { "get", required_argument, NULL, 'g' }, + { "verbose", no_argument, NULL, 'v' }, + { "list-all", no_argument, NULL, 'l' }, + { "set" , no_argument, NULL, 's' }, /* requires 3 arguments */ + { "clear", required_argument, NULL, 'c' }, + { "clear-all", no_argument, NULL, 'C' }, + { "help", no_argument, NULL, 'h' }, + { 0, 0, 0, 0 }, + }; + + for (;;) { + opt = getopt_long(argc, argv, "g:vlsc:Ch", long_option, NULL); + if (opt < 0) + break; + switch (opt) { + case 'g': + SYS_G_LIST_APPEND(keys, strdup(optarg)); + break; + case 'v': + verbose = true; + break; + case 'l': + for (int i = DB_START; i < DB_END; ++i) + system_info_tool_list_all(i); + break; + case 's': + retval = system_info_tool_set(argc, argv); + if (retval < 0) { + printf("Failed to set key\n"); + system_info_tool_set_help(); + return 1; + } + optind += 3; /* manually consume 3 arguments */ + break; + case 'c': + system_info_tool_clear_key(optarg); + break; + case 'C': + system_info_tool_clear_all(); + break; + case 'h': + system_info_tool_show_help(); + break; + default: + system_info_tool_show_help(); + break; + } + } + + SYS_G_LIST_FOREACH(keys, elem, key) { + system_info_tool_get(key, verbose); + free(key); + } + + return 0; +} diff --git a/tool/system-info-tool.h b/tool/system-info-tool.h new file mode 100644 index 0000000..7b966d2 --- /dev/null +++ b/tool/system-info-tool.h @@ -0,0 +1,80 @@ +#ifndef __SYSTEM_INFO_TOOL_H__ +#define __SYSTEM_INFO_TOOL_H__ + +#include +#include + +#include +#include +#include + +#define BUFFER_MAX 128 + +enum db_e { + DB_START = 0, + DB_DEFAULT_RO = DB_START, + DB_HAL_RO, + DB_DEFAULT_RW, + DB_END, +}; + +struct db { + const char *path; + const char *name; + const char ticker; +}; +extern const struct db db[DB_END]; + +struct value { + system_info_type_e type; + union { + bool b; + int i; + double d; + char *s; + }; +}; + +struct dbentry { + const struct db *db; + char tag[BUFFER_MAX]; + char key[BUFFER_MAX]; + struct value value; +}; + +extern int runtime_env; + +static inline void fclosep(FILE **fp) +{ + if (*fp) + fclose(*fp); +} +#define __auto_fclose__ __attribute__((cleanup(fclosep))) + +static inline void closep(int *fd) +{ + if (*fd >= 0) + close(*fd); +} +#define __auto_close__ __attribute__((cleanup(closep))) + +static inline void free_value(struct value *v) +{ + if (v->type == SYSTEM_INFO_STRING) + free(v->s); +} +#define __auto_free_value__ __attribute__((cleanup(free_value))) + +static inline void free_dbentry(struct dbentry *entry) +{ + if (entry->value.type == SYSTEM_INFO_STRING) + free(entry->value.s); +} +#define __auto_free_dbentry__ __attribute__((cleanup(free_dbentry))) + + +const char *type_to_string(system_info_type_e type); +system_info_type_e string_to_type(const char *type); +void print_value(struct value value); + +#endif