This adds implementation of mesh_config_create_config(), mesh_config_release_config(), mesh_config_get_config(), mesh_config_get_config_backup(), mesh_config_restore_backup() and mesh_config_save_config() for the JSON based node configuration storage. --- mesh/mesh-config-json.c | 171 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) diff --git a/mesh/mesh-config-json.c b/mesh/mesh-config-json.c index 5ca086ad0..3c65b3846 100644 --- a/mesh/mesh-config-json.c +++ b/mesh/mesh-config-json.c @@ -22,9 +22,14 @@ #endif #define _GNU_SOURCE + +#include <dirent.h> #include <errno.h> +#include <fcntl.h> +#include <ftw.h> #include <stdio.h> #include <string.h> +#include <unistd.h> #include <ell/ell.h> #include <json-c/json.h> @@ -35,6 +40,10 @@ #define CHECK_KEY_IDX_RANGE(x) (((x) >= 0) && ((x) <= 4095)) +static const char *cfg_name = "/node.json"; +static const char *bak_name = "/node.json.bak"; +static const char *tmp_name = "/node.json.tmp"; + static bool get_int(json_object *jobj, const char *keyword, int *value) { json_object *jvalue; @@ -1827,3 +1836,165 @@ bool mesh_config_model_sub_del_all(void *cfg, uint16_t addr, uint32_t mod_id, return delete_model_property(jnode, addr, mod_id, vendor, "subscribe"); } + +static char *create_filename(const char *dir, const char *fname) +{ + size_t path_len = strlen(dir) + strlen(fname); + + if (path_len + 1 >= PATH_MAX) + return NULL; + + return l_strdup_printf("%s%s", dir, fname); +} + +static void *get_node_config(const char *dir, const char *fname) +{ + int fd; + char *str = NULL, *fname_full; + struct stat st; + ssize_t sz; + json_object *jconfig = NULL; + + fname_full = create_filename(dir, fname); + if (!fname) + return NULL; + + l_info("Loading configuration from %s", fname_full); + + fd = open(fname_full, O_RDONLY); + if (fd < 0) + goto done; + + if (fstat(fd, &st) == -1) + goto done; + + str = (char *) l_new(char, st.st_size + 1); + if (!str) + goto done; + + sz = read(fd, str, st.st_size); + if (sz != st.st_size) { + l_error("Failed to read configuration file %s", fname_full); + goto done; + } + + jconfig = json_tokener_parse(str); + +done: + if (fd >= 0) + close(fd); + + l_free(str); + l_free(fname_full); + + return jconfig; +} + +void *mesh_config_get_config(const char *dir) +{ + if (!dir) + return NULL; + + return get_node_config(dir, cfg_name); +} + +void *mesh_config_get_config_backup(const char *dir) +{ + if (!dir) + return NULL; + + return get_node_config(cfg_name, bak_name); +} + +bool mesh_config_restore_backup(const char *dir) +{ + char *fname_cfg = NULL, *fname_bak = NULL; + bool res = false; + + fname_cfg = create_filename(dir, cfg_name); + fname_bak = create_filename(dir, bak_name); + + if (fname_cfg && fname_bak) { + remove(fname_cfg); + rename(fname_bak, fname_cfg); + res = true; + } + + l_free(fname_bak); + l_free(fname_cfg); + + return res; +} + +static bool save_config(void *cfg, const char *fname) +{ + FILE *outfile; + const char *str; + bool result = false; + json_object *jnode = cfg; + + outfile = fopen(fname, "w"); + + if (!outfile) + return false; + + str = json_object_to_json_string_ext(jnode, JSON_C_TO_STRING_PRETTY); + + if (fwrite(str, sizeof(char), strlen(str), outfile) < strlen(str)) + l_warn("Incomplete write of mesh configuration"); + else + result = true; + + fclose(outfile); + + return result; +} + +void *mesh_config_create_config(void) +{ + return json_object_new_object(); +} + +void mesh_config_release_config(void *cfg) +{ + json_object *jnode = cfg; + + if (!cfg) + return; + + json_object_put(jnode); +} + +bool mesh_config_save_config(const char *dir, void *cfg) +{ + char *fname_cfg; + char *fname_bak; + char *fname_tmp; + bool result = false; + + fname_cfg = create_filename(dir, cfg_name); + fname_bak = create_filename(dir, bak_name); + fname_tmp = create_filename(dir, tmp_name); + + if (!fname_cfg || !fname_bak || !fname_tmp) + goto done; + + result = save_config(cfg, fname_tmp); + + if (result) { + remove(fname_bak); + rename(fname_cfg, fname_bak); + rename(fname_tmp, fname_cfg); + } else { + l_error("Failed to save configuration to %s", fname_tmp); + } + + remove(fname_tmp); + +done: + l_free(fname_cfg); + l_free(fname_bak); + l_free(fname_tmp); + + return result; +} -- 2.21.0