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

Marek Behún
2021-11-03T23:25:31Z

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(-)

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,
};
--
2.32.0