From 2d3b9524b1448dd6a8ef83e4e101e509d2552dcc Mon Sep 17 00:00:00 2001
From: Joachim Wiberg <troglobit@gmail.com>
Date: Fri, 16 Jun 2023 12:13:16 +0200
Subject: [PATCH 3/4] Add support for loading /etc/sysrepo/factory-default
Organization: Addiva Elektronik

Follow-up to 3d07270 which adds support for compile-time defaults, this
allows for reading /etc/sysrepo/factory-default.[xml,json] at run-time
as well.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
---
 src/common.c   | 29 +++++++++++++++++++++++++++++
 src/common.h   | 11 +++++++++++
 src/lyd_mods.c | 23 +++++++++++++++++------
 3 files changed, 57 insertions(+), 6 deletions(-)

diff --git a/src/common.c b/src/common.c
index bef98f9a..bbb0c949 100644
--- a/src/common.c
+++ b/src/common.c
@@ -1306,6 +1306,35 @@ sr_path_conn_lockfile(sr_cid_t cid, int creat, char **path)
     return err_info;
 }
 
+sr_error_info_t *
+sr_path_factory_default(char **path)
+{
+    const char *fdpath = "%s/factory-default.xml";
+    sr_error_info_t *err_info = NULL;
+    int ret, once = 0;
+
+retry:
+    ret = asprintf(path, fdpath, sr_get_repo_path());
+    if (ret == -1) {
+        SR_ERRINFO_MEM(&err_info);
+        goto cleanup;
+    }
+
+    if (sr_file_exists(*path)) {
+        return NULL;
+    }
+
+    free(*path);
+    if (!once++) {
+        fdpath = "%s/factory-default.json";
+        goto retry;
+    }
+
+cleanup:
+    *path = NULL;
+    return err_info;
+}
+
 void
 sr_remove_evpipes(void)
 {
diff --git a/src/common.h b/src/common.h
index ca5c08ca..e8d394ef 100644
--- a/src/common.h
+++ b/src/common.h
@@ -479,6 +479,17 @@ sr_error_info_t *sr_path_yang_file(const char *mod_name, const char *mod_rev, ch
  */
 sr_error_info_t *sr_path_conn_lockfile(sr_cid_t cid, int creat, char **path);
 
+/**
+ * @brief Get the path to system factory default input data used to init internal modules
+ *
+ * Looks for the file factory_default_config.xml, with fallback to
+ * factory_default_config.json in /etc/sysrepo/.
+ *
+ * @param[out] path Created path.
+ * @return err_info, NULL on success.
+ */
+sr_error_info_t *sr_path_factory_default(char **path);
+
 /**
  * @brief Remove any leftover event pipes after crashed subscriptions.
  * There should be none unless there was a subscription structure without subscriptions that crashed.
diff --git a/src/lyd_mods.c b/src/lyd_mods.c
index 94e97b97..d2d8d34a 100644
--- a/src/lyd_mods.c
+++ b/src/lyd_mods.c
@@ -955,16 +955,27 @@ sr_lydmods_create_data(const struct ly_ctx *ly_ctx)
     sr_error_info_t *err_info = NULL;
     const struct lys_module *ly_mod;
     struct lyd_node *data = NULL, *mod_data = NULL, *mod_diff = NULL;
+    LY_ERR lyrc = LY_SUCCESS;
+    char *data_path = NULL;
     uint32_t idx = 0;
     int rc;
 
-    if (!strlen(SR_INT_MOD_DATA)) {
-        /* no data to set */
-        goto cleanup;
+    /*
+     * parse and validate data:
+     *  - first look for /etc/sysrepo/factory-default.[xml,json]
+     *  - then look for any compile-time data as fallback
+     */
+    sr_path_factory_default(&data_path);
+    if (data_path) {
+        lyrc = lyd_parse_data_path(ly_ctx, data_path, 0, 0, LYD_VALIDATE_NO_STATE, &data);
+        free(data_path);
+    } else {
+        if (!strlen(SR_INT_MOD_DATA)) {
+            goto cleanup;
+        }
+        lyrc = lyd_parse_data_mem(ly_ctx, SR_INT_MOD_DATA, SR_INT_MOD_DATA_FORMAT, 0, LYD_VALIDATE_NO_STATE, &data);
     }
-
-    /* parse and validate the data */
-    if (lyd_parse_data_mem(ly_ctx, SR_INT_MOD_DATA, SR_INT_MOD_DATA_FORMAT, 0, LYD_VALIDATE_NO_STATE, &data)) {
+    if (lyrc) {
         sr_errinfo_new_ly(&err_info, ly_ctx, NULL);
         goto cleanup;
     }
-- 
2.34.1

