[PATCH BlueZ 7/9] mesh: Implement config read/write for mesh json format

Inga Stotland
2019-07-10T05:10:09Z

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