From: Gabriel Valcazar <gabriel.valcazar@digi.com>
Date: Wed, 7 Apr 2021 11:35:15 +0200
Subject: [PATCH] Implement U-Boot environment access functions

Keep the same function signatures as u-boot-fw-utils, so that all code making
use of this functionality remains compatible. Use the libubootenv
implementation of the fw_printenv and fw_setenv apps as reference.

https://jira.digi.com/browse/DEL-7410

Signed-off-by: Javier Viguera <javier.viguera@digi.com>
Signed-off-by: Jose Diaz de Grenu <Jose.DiazdeGrenu@digi.com>
Signed-off-by: Gonzalo Ruiz <Gonzalo.Ruiz@digi.com>
Signed-off-by: Gabriel Valcazar <gabriel.valcazar@digi.com>
---
 src/libuboot.h  | 23 ++++++++++++
 src/uboot_env.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 119 insertions(+)

diff --git a/src/libuboot.h b/src/libuboot.h
index bfcaeb1d609f..b15969f89174 100644
--- a/src/libuboot.h
+++ b/src/libuboot.h
@@ -159,6 +159,29 @@ const char *libuboot_getname(void *entry);
  */
 const char *libuboot_getvalue(void *entry);
 
+/*
+ * Get U-Boot's environment variable.
+ *
+ * Params:
+ *   'name'  (input)   Name of the environment variable
+ *   'value' (output)  Pointer to the variable's value
+ *                     (NULL if not found)
+ *
+ * Return: 0 on sucess, -1 on failure
+ */
+int uboot_getenv(char *name, const char **value);
+
+/*
+ * Set U-Boot's environment variable.
+ *
+ * Params:
+ *   'name'  (input)  Name of the environment variable
+ *   'value' (input)  Value of the environment variable
+ *
+ * Return: 0 on sucess, -1 on failure
+ */
+int uboot_setenv(char *name, char *value);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/uboot_env.c b/src/uboot_env.c
index 2fd08f5a07db..87f831b0cdc7 100644
--- a/src/uboot_env.c
+++ b/src/uboot_env.c
@@ -1632,3 +1632,99 @@ void libuboot_close(struct uboot_ctx *ctx) {
 void libuboot_exit(struct uboot_ctx *ctx) {
 	free(ctx);
 }
+
+static int uboot_common_init(struct uboot_ctx *ctx)
+{
+	const char *cfgfname = "/etc/fw_env.config";
+	const char *defenvfile = "/etc/u-boot-initial-env";
+
+	if (libuboot_read_config(ctx, cfgfname) < 0) {
+		fprintf(stderr, "Configuration file wrong or corrupted\n");
+		return -1;
+	}
+
+	if (libuboot_open(ctx) < 0) {
+		fprintf(stderr, "Cannot read environment, using default\n");
+		if (libuboot_load_file(ctx, defenvfile) < 0) {
+			fprintf(stderr, "Cannot read default environment from file\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Function:    uboot_getenv
+ * Description: get U-Boot's environment variable
+ */
+int uboot_getenv(char *name, const char **value)
+{
+	struct uboot_ctx *ctx;
+	int ret = 0;
+
+	ret = libuboot_initialize(&ctx, NULL);
+	if (ret < 0) {
+		fprintf(stderr, "Cannot initialize environment\n");
+		goto err;
+	}
+
+	ret = uboot_common_init(ctx);
+	if (ret < 0)
+		goto err;
+
+	*value = libuboot_get_env(ctx, name);
+
+err:
+	libuboot_close(ctx);
+	libuboot_exit(ctx);
+
+	return ret ? -1 : 0;
+}
+
+/*
+ * Function:    uboot_setenv
+ * Description: set U-Boot's environment variable
+ */
+int uboot_setenv(char *name, char *value)
+{
+	struct uboot_ctx *ctx;
+	bool need_store = false;
+	const char *curr;
+	int ret = 0;
+
+	ret = libuboot_initialize(&ctx, NULL);
+	if (ret < 0) {
+		fprintf(stderr, "Cannot initialize environment\n");
+		goto err;
+	}
+
+	ret = uboot_common_init(ctx);
+	if (ret < 0)
+		goto err;
+
+	curr = libuboot_get_env(ctx, name);
+	if (value == NULL) {
+		if (curr != NULL) {
+			libuboot_set_env(ctx, name, NULL);
+			need_store = true;
+		}
+	} else {
+		if (curr == NULL || strcmp(curr, value) != 0) {
+			libuboot_set_env(ctx, name, value);
+			need_store = true;
+		}
+	}
+
+	if (need_store) {
+		ret = libuboot_env_store(ctx);
+		if (ret)
+			fprintf(stderr, "Error storing the env\n");
+	}
+
+err:
+	libuboot_close(ctx);
+	libuboot_exit(ctx);
+
+	return ret ? -1 : 0;
+}
