diff mbox series

[v2,10/12] env: Add support for overwriting default environment via sysinfo

Message ID 20211103232332.2737-11-kabel@kernel.org
State Changes Requested
Delegated to: Simon Glass
Headers show
Series Board specific runtime determined default env | expand

Commit Message

Marek Behún Nov. 3, 2021, 11:23 p.m. UTC
From: Marek Behún <marek.behun@nic.cz>

The default_environment[] buffer is built at compile time, but sometimes
it makes sense for some default environment variables to be determined
at runtime, for example:
- one board code may support different boards, and needs that
    fdtfile, board, board_name
  are set appropriately when command
    env default -a
  is executed
- some boards may want to prohibit the
    env default -a
  command to remove device MAC addresses stored in
    ethaddr, ethNaddr.
  This is the case for the ESPRESSObin board code, for example, where
  currently the board_late_init() function rewrites the default
  environment array to achieve this.

Add new sysinfo IDs
  SYSINFO_ID_DEF_ENV_NAMES
  SYSINFO_ID_DEF_ENV_VALUES
corresponding to sysinfo string list of names and values of default
environment variables that are to take precedence over the
default_environment[] buffer.

Add code to default environemnt handlers in env/common.c, which iterate
these sysinfo string lists correspondingly.

Signed-off-by: Marek Behún <marek.behun@nic.cz>
---
 env/common.c      | 107 +++++++++++++++++++++++++++++++++++++++++++++-
 include/sysinfo.h |   4 ++
 2 files changed, 110 insertions(+), 1 deletion(-)

Comments

Simon Glass Nov. 5, 2021, 2:02 a.m. UTC | #1
On Wed, 3 Nov 2021 at 17:23, Marek Behún <kabel@kernel.org> wrote:
>
> From: Marek Behún <marek.behun@nic.cz>
>
> The default_environment[] buffer is built at compile time, but sometimes
> it makes sense for some default environment variables to be determined
> at runtime, for example:
> - one board code may support different boards, and needs that
>     fdtfile, board, board_name
>   are set appropriately when command
>     env default -a
>   is executed
> - some boards may want to prohibit the
>     env default -a
>   command to remove device MAC addresses stored in
>     ethaddr, ethNaddr.
>   This is the case for the ESPRESSObin board code, for example, where
>   currently the board_late_init() function rewrites the default
>   environment array to achieve this.
>
> Add new sysinfo IDs
>   SYSINFO_ID_DEF_ENV_NAMES
>   SYSINFO_ID_DEF_ENV_VALUES
> corresponding to sysinfo string list of names and values of default
> environment variables that are to take precedence over the
> default_environment[] buffer.
>
> Add code to default environemnt handlers in env/common.c, which iterate
> these sysinfo string lists correspondingly.
>
> Signed-off-by: Marek Behún <marek.behun@nic.cz>
> ---
>  env/common.c      | 107 +++++++++++++++++++++++++++++++++++++++++++++-
>  include/sysinfo.h |   4 ++
>  2 files changed, 110 insertions(+), 1 deletion(-)
>

Seems OK to me, but see my earlier request to simplify the API and
reduce flexibility.

Regards,
Simon
diff mbox series

Patch

diff --git a/env/common.c b/env/common.c
index cefe58561b..8ac287beae 100644
--- a/env/common.c
+++ b/env/common.c
@@ -22,6 +22,7 @@ 
 #include <u-boot/crc.h>
 #include <dm/ofnode.h>
 #include <net.h>
+#include <sysinfo.h>
 #include <watchdog.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -148,6 +149,31 @@  char *from_env(const char *envvar)
 	return ret;
 }
 
+static int sysinfo_default_env_get(const char *var, char *buf, unsigned len)
+{
+	struct udevice *dev;
+	unsigned idx;
+	char *name;
+	void *iter;
+
+	if (sysinfo_get(&dev) < 0 || sysinfo_detect(dev) < 0)
+		return -ENODEV;
+
+	idx = 0;
+	for_each_sysinfo_str_list(dev, SYSINFO_ID_DEF_ENV_NAMES, name, iter) {
+		if (strcmp(var, name)) {
+			++idx;
+			continue;
+		}
+
+		free(iter);
+		return sysinfo_get_str_list(dev, SYSINFO_ID_DEF_ENV_VALUES, idx,
+					    len, buf);
+	}
+
+	return -ENOENT;
+}
+
 static int env_get_from_linear(const char *env, const char *name, char *buf,
 			       unsigned len)
 {
@@ -157,6 +183,17 @@  static int env_get_from_linear(const char *env, const char *name, char *buf,
 	if (name == NULL || *name == '\0')
 		return -1;
 
+	if (env == default_environment) {
+		int res = sysinfo_default_env_get(name, buf, len);
+
+		/*
+		 * Board special default envs take precedence over the
+		 * default_environment[] array.
+		 */
+		if (res >= 0)
+			return res;
+	}
+
 	name_len = strlen(name);
 
 	for (p = env; *p != '\0'; p = end + 1) {
@@ -248,8 +285,69 @@  char *env_get_default(const char *name)
 	return NULL;
 }
 
+static int sysinfo_import_default_envs(bool all, int nvars, char * const vars[],
+				       int flags)
+{
+	struct udevice *dev;
+	char *name, *value;
+	unsigned idx;
+	void *iter;
+	int len;
+
+	if (sysinfo_get(&dev) < 0 || sysinfo_detect(dev) < 0)
+		return 0;
+
+	len = sysinfo_get_str_list_max_len(dev, SYSINFO_ID_DEF_ENV_VALUES);
+	if (len == -ENOSYS || len == -ENOENT || len == -ERANGE)
+		return 0;
+	else if (len < 0)
+		return len;
+
+	value = malloc(len + 1);
+	if (!value)
+		return -ENOMEM;
+
+	idx = 0;
+	for_each_sysinfo_str_list(dev, SYSINFO_ID_DEF_ENV_NAMES, name, iter) {
+		struct env_entry e, *ep;
+
+		if (!all) {
+			int j;
+
+			/* If name is not in vars, skip */
+			for (j = 0; j < nvars; ++j)
+				if (!strcmp(name, vars[j]))
+					break;
+			if (j == nvars) {
+				idx++;
+				continue;
+			}
+		}
+
+		len = sysinfo_get_str_list(dev, SYSINFO_ID_DEF_ENV_VALUES,
+					   idx++, ENV_SIZE, value);
+		if (len < 0)
+			continue;
+
+		e.key = name;
+		e.data = value;
+		if (!hsearch_r(e, ENV_ENTER, &ep, &env_htab, flags)) {
+			int res = -errno;
+			free(iter);
+			free(value);
+			return res;
+		}
+	}
+
+	free(value);
+
+	return 0;
+}
+
 void env_set_default(const char *s, int flags)
 {
+	int res;
+
 	if (s) {
 		if ((flags & H_INTERACTIVE) == 0) {
 			printf("*** Warning - %s, "
@@ -270,6 +368,13 @@  void env_set_default(const char *s, int flags)
 		return;
 	}
 
+	res = sysinfo_import_default_envs(true, 0, NULL, flags);
+	if (res < 0) {
+		pr_err("## Error: Board special default environment import failed: %d\n",
+		       res);
+		return;
+	}
+
 	gd->flags |= GD_FLG_ENV_READY;
 	gd->flags |= GD_FLG_ENV_DEFAULT;
 }
@@ -288,7 +393,7 @@  int env_set_default_vars(int nvars, char * const vars[], int flags)
 		       vars))
 		return -errno;
 
-	return 0;
+	return sysinfo_import_default_envs(false, nvars, vars, flags);
 }
 
 /*
diff --git a/include/sysinfo.h b/include/sysinfo.h
index d32bf3e808..587ad0dc75 100644
--- a/include/sysinfo.h
+++ b/include/sysinfo.h
@@ -47,6 +47,10 @@  enum sysinfo_id {
 	/* For show_board_info() */
 	SYSINFO_ID_BOARD_MODEL,
 
+	/* For overwriting default environment variables */
+	SYSINFO_ID_DEF_ENV_NAMES,
+	SYSINFO_ID_DEF_ENV_VALUES,
+
 	/* First value available for downstream/board used */
 	SYSINFO_ID_USER = 0x1000,
 };