From c4e0057fa78ebb524b9241ad7245fcd1074ba414 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:19 -0600 Subject: env: Refactor do_apply to a flag Use a flag in hsearch_r for insert mode passed from import to allow the behavior be different based on use. Now that "do_check" is called for all imports, ensure console init is complete before updating the console on relocation import Signed-off-by: Joe Hershberger --- common/cmd_nvedit.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'common/cmd_nvedit.c') diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 006131f45..a8dc9a694 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -116,7 +116,7 @@ static int env_print(char *name) e.key = name; e.data = NULL; - hsearch_r(e, FIND, &ep, &env_htab); + hsearch_r(e, FIND, &ep, &env_htab, 0); if (ep == NULL) return 0; len = printf("%s=%s\n", ep->key, ep->data); @@ -224,7 +224,7 @@ int env_check_apply(const char *name, const char *oldval, else if (strcmp(name, "stderr") == 0) console = stderr; - if (console != -1) { + if (console != -1 && (gd->flags & GD_FLG_DEVINIT) != 0) { if ((newval == NULL) || (*newval == '\0')) { /* We cannot delete stdin/stdout/stderr */ if ((flag & H_FORCE) == 0) @@ -344,20 +344,19 @@ static int _do_env_set(int flag, int argc, char * const argv[]) */ e.key = name; e.data = NULL; - hsearch_r(e, FIND, &ep, &env_htab); + hsearch_r(e, FIND, &ep, &env_htab, 0); /* - * Perform requested checks. Notice how since we are overwriting - * a single variable, we need to set H_NOCLEAR + * Perform requested checks. */ - if (env_check_apply(name, ep ? ep->data : NULL, value, H_NOCLEAR)) { + if (env_check_apply(name, ep ? ep->data : NULL, value, 0)) { debug("check function did not approve, refusing\n"); return 1; } /* Delete only ? */ if (argc < 3 || argv[2] == NULL) { - int rc = hdelete_r(name, &env_htab, 0); + int rc = hdelete_r(name, &env_htab, H_INTERACTIVE); return !rc; } @@ -384,7 +383,7 @@ static int _do_env_set(int flag, int argc, char * const argv[]) e.key = name; e.data = value; - hsearch_r(e, ENTER, &ep, &env_htab); + hsearch_r(e, ENTER, &ep, &env_htab, H_INTERACTIVE); free(value); if (!ep) { printf("## Error inserting \"%s\" variable, errno=%d\n", @@ -552,7 +551,7 @@ char *getenv(const char *name) e.key = name; e.data = NULL; - hsearch_r(e, FIND, &ep, &env_htab); + hsearch_r(e, FIND, &ep, &env_htab, 0); return ep ? ep->data : NULL; } @@ -951,7 +950,7 @@ static int do_env_import(cmd_tbl_t *cmdtp, int flag, } if (himport_r(&env_htab, addr, size, sep, del ? 0 : H_NOCLEAR, - 0, NULL, 0 /* do_apply */) == 0) { + 0, NULL) == 0) { error("Environment import failed: errno = %d\n", errno); return 1; } -- cgit v1.2.3-70-g09d2 From 7afcf3a55b5f484b3d3442053fae8186a3fb92d7 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:21 -0600 Subject: env: Refactor apply into change_ok Move the read of the old value to inside the check function. In some cases it can be avoided all together and at the least the code is only called from one place. Also name the function and the callback to more clearly describe what it does. Pass the ENTRY instead of just the name for direct access to the whole data structure. Pass an enum to the callback that specifies the operation being approved. Signed-off-by: Joe Hershberger --- common/cmd_nvedit.c | 34 +++++++++++-------------- common/env_common.c | 3 ++- include/environment.h | 7 +++--- include/search.h | 13 +++++++--- lib/hashtable.c | 70 +++++++++++++++++++++++++++++++-------------------- 5 files changed, 72 insertions(+), 55 deletions(-) (limited to 'common/cmd_nvedit.c') diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index a8dc9a694..da5689ca6 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -208,10 +208,20 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag, * overwriting of write-once variables. */ -int env_check_apply(const char *name, const char *oldval, - const char *newval, int flag) +int env_change_ok(const ENTRY *item, const char *newval, enum env_op op, + int flag) { int console = -1; + const char *name; +#if !defined(CONFIG_ENV_OVERWRITE) && defined(CONFIG_OVERWRITE_ETHADDR_ONCE) \ +&& defined(CONFIG_ETHADDR) + const char *oldval = NULL; + + if (op != env_op_create) + oldval = item->data; +#endif + + name = item->key; /* Default value for NULL to protect string-manipulating functions */ newval = newval ? : ""; @@ -242,12 +252,12 @@ int env_check_apply(const char *name, const char *oldval, #endif /* CONFIG_CONSOLE_MUX */ } +#ifndef CONFIG_ENV_OVERWRITE /* * Some variables like "ethaddr" and "serial#" can be set only once and * cannot be deleted, unless CONFIG_ENV_OVERWRITE is defined. */ -#ifndef CONFIG_ENV_OVERWRITE - if (oldval != NULL && /* variable exists */ + if (op != env_op_create && /* variable exists */ (flag & H_FORCE) == 0) { /* and we are not forced */ if (strcmp(name, "serial#") == 0 || (strcmp(name, "ethaddr") == 0 @@ -265,7 +275,7 @@ int env_check_apply(const char *name, const char *oldval, * (which will erase all variables prior to calling this), * we want the baudrate to actually change - for real. */ - if (oldval != NULL || /* variable exists */ + if (op != env_op_create || /* variable exists */ (flag & H_NOCLEAR) == 0) { /* or env is clear */ /* * Switch to new baudrate if new baudrate is supported @@ -339,20 +349,6 @@ static int _do_env_set(int flag, int argc, char * const argv[]) } env_id++; - /* - * search if variable with this name already exists - */ - e.key = name; - e.data = NULL; - hsearch_r(e, FIND, &ep, &env_htab, 0); - - /* - * Perform requested checks. - */ - if (env_check_apply(name, ep ? ep->data : NULL, value, 0)) { - debug("check function did not approve, refusing\n"); - return 1; - } /* Delete only ? */ if (argc < 3 || argv[2] == NULL) { diff --git a/common/env_common.c b/common/env_common.c index f22f5b968..a960aa803 100644 --- a/common/env_common.c +++ b/common/env_common.c @@ -40,7 +40,7 @@ DECLARE_GLOBAL_DATA_PTR; #include struct hsearch_data env_htab = { - .apply = env_check_apply, + .change_ok = env_change_ok, }; static uchar __env_get_char_spec(int index) @@ -162,6 +162,7 @@ void env_relocate(void) { #if defined(CONFIG_NEEDS_MANUAL_RELOC) env_reloc(); + env_htab.change_ok += gd->reloc_off; #endif if (gd->env_valid == 0) { #if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD) diff --git a/include/environment.h b/include/environment.h index e8ab7033b..4b19f32be 100644 --- a/include/environment.h +++ b/include/environment.h @@ -188,13 +188,12 @@ int set_default_vars(int nvars, char * const vars[]); int env_import(const char *buf, int check); /* - * Check if variable "name" can be changed from oldval to newval, - * and if so, apply the changes (e.g. baudrate). + * Check if variable "item" can be changed to newval * When (flag & H_FORCE) is set, it does not print out any error * message and forces overwriting of write-once variables. */ -int env_check_apply(const char *name, const char *oldval, - const char *newval, int flag); +int env_change_ok(const ENTRY *item, const char *newval, enum env_op op, + int flag); #endif /* DO_DEPS_ONLY */ diff --git a/include/search.h b/include/search.h index f5165b0a9..fa00ea1b3 100644 --- a/include/search.h +++ b/include/search.h @@ -32,6 +32,12 @@ #define __set_errno(val) do { errno = val; } while (0) +enum env_op { + env_op_create, + env_op_delete, + env_op_overwrite, +}; + /* Action which shall be performed in the call the hsearch. */ typedef enum { FIND, @@ -59,14 +65,13 @@ struct hsearch_data { unsigned int filled; /* * Callback function which will check whether the given change for variable - * "name" from "oldval" to "newval" may be applied or not, and possibly apply - * such change. + * "item" to "newval" may be applied or not, and possibly apply such change. * When (flag & H_FORCE) is set, it shall not print out any error message and * shall force overwriting of write-once variables. .* Must return 0 for approval, 1 for denial. */ - int (*apply)(const char *name, const char *oldval, - const char *newval, int flag); + int (*change_ok)(const ENTRY *__item, const char *newval, enum env_op, + int flag); }; /* Create a new hashing table which will at most contain NEL elements. */ diff --git a/lib/hashtable.c b/lib/hashtable.c index f4d579505..6861a4202 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -66,12 +66,16 @@ * Instead the interface of all functions is extended to take an argument * which describes the current status. */ + typedef struct _ENTRY { int used; ENTRY entry; } _ENTRY; +static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep, + int idx); + /* * hcreate() */ @@ -259,6 +263,17 @@ static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action, && strcmp(item.key, htab->table[idx].entry.key) == 0) { /* Overwrite existing value? */ if ((action == ENTER) && (item.data != NULL)) { + /* check for permission */ + if (htab->change_ok != NULL && htab->change_ok( + &htab->table[idx].entry, item.data, + env_op_overwrite, flag)) { + debug("change_ok() rejected setting variable " + "%s, skipping it!\n", item.key); + __set_errno(EPERM); + *retval = NULL; + return 0; + } + free(htab->table[idx].entry.data); htab->table[idx].entry.data = strdup(item.data); if (!htab->table[idx].entry.data) { @@ -383,6 +398,17 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, ++htab->filled; + /* check for permission */ + if (htab->change_ok != NULL && htab->change_ok( + &htab->table[idx].entry, item.data, env_op_create, flag)) { + debug("change_ok() rejected setting variable " + "%s, skipping it!\n", item.key); + _hdelete(item.key, htab, &htab->table[idx].entry, idx); + __set_errno(EPERM); + *retval = NULL; + return 0; + } + /* return new entry */ *retval = &htab->table[idx].entry; return 1; @@ -404,6 +430,18 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, * do that. */ +static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep, + int idx) +{ + /* free used ENTRY */ + debug("hdelete: DELETING key \"%s\"\n", key); + free((void *)ep->key); + free(ep->data); + htab->table[idx].used = -1; + + --htab->filled; +} + int hdelete_r(const char *key, struct hsearch_data *htab, int flag) { ENTRY e, *ep; @@ -420,19 +458,15 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag) } /* Check for permission */ - if (htab->apply != NULL && - htab->apply(ep->key, ep->data, NULL, flag)) { + if (htab->change_ok != NULL && + htab->change_ok(ep, NULL, env_op_delete, flag)) { + debug("change_ok() rejected deleting variable " + "%s, skipping it!\n", key); __set_errno(EPERM); return 0; } - /* free used ENTRY */ - debug("hdelete: DELETING key \"%s\"\n", key); - free((void *)ep->key); - free(ep->data); - htab->table[idx].used = -1; - - --htab->filled; + _hdelete(key, htab, ep, idx); return 1; } @@ -800,24 +834,6 @@ int himport_r(struct hsearch_data *htab, e.key = name; e.data = value; - /* if there is an apply function, check what it has to say */ - if (htab->apply != NULL) { - debug("searching before calling cb function" - " for %s\n", name); - /* - * Search for variable in existing env, so to pass - * its previous value to the apply callback - */ - hsearch_r(e, FIND, &rv, htab, 0); - debug("previous value was %s\n", rv ? rv->data : ""); - if (htab->apply(name, rv ? rv->data : NULL, - value, flag)) { - debug("callback function refused to set" - " variable %s, skipping it!\n", name); - continue; - } - } - hsearch_r(e, ENTER, &rv, htab, flag); if (rv == NULL) { printf("himport_r: can't insert \"%s=%s\" into hash table\n", -- cgit v1.2.3-70-g09d2 From be11235ab802844e12d84921a38fd8ae4ddda080 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:23 -0600 Subject: env: Hide '.' variables in env print by default When printing all variables with env print, don't print variables that begin with '.'. If env print is called with a '-a' switch, then include variables that begin with '.' (just like the ls command). Variables printed explicitly will be printed even without the -a. Signed-off-by: Joe Hershberger --- board/esd/pmc440/cmd_pmc440.c | 2 +- common/cmd_nvedit.c | 26 +++++++++++++++++--------- common/env_dataflash.c | 2 +- common/env_eeprom.c | 2 +- common/env_fat.c | 2 +- common/env_flash.c | 4 ++-- common/env_mmc.c | 2 +- common/env_nand.c | 4 ++-- common/env_nvram.c | 2 +- common/env_onenand.c | 2 +- common/env_sf.c | 4 ++-- include/search.h | 5 +++-- lib/hashtable.c | 5 ++++- 13 files changed, 37 insertions(+), 25 deletions(-) (limited to 'common/cmd_nvedit.c') diff --git a/board/esd/pmc440/cmd_pmc440.c b/board/esd/pmc440/cmd_pmc440.c index f1ffb7b54..e9a78a303 100644 --- a/board/esd/pmc440/cmd_pmc440.c +++ b/board/esd/pmc440/cmd_pmc440.c @@ -391,7 +391,7 @@ int do_painit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) nextbase -= ((CONFIG_ENV_SIZE + 4096 - 1) & ~(4096 - 1)); envp = (env_t *)nextbase; res = (char *)envp->data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index da5689ca6..022ad3942 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -106,7 +106,7 @@ int get_env_id(void) * * Returns 0 in case of error, or length of printed string */ -static int env_print(char *name) +static int env_print(char *name, int flag) { char *res = NULL; size_t len; @@ -116,7 +116,7 @@ static int env_print(char *name) e.key = name; e.data = NULL; - hsearch_r(e, FIND, &ep, &env_htab, 0); + hsearch_r(e, FIND, &ep, &env_htab, flag); if (ep == NULL) return 0; len = printf("%s=%s\n", ep->key, ep->data); @@ -124,7 +124,7 @@ static int env_print(char *name) } /* print whole list */ - len = hexport_r(&env_htab, '\n', &res, 0, 0, NULL); + len = hexport_r(&env_htab, '\n', flag, &res, 0, 0, NULL); if (len > 0) { puts(res); @@ -141,10 +141,17 @@ static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc, { int i; int rcode = 0; + int env_flag = H_HIDE_DOT; + + if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'a') { + argc--; + argv++; + env_flag &= ~H_HIDE_DOT; + } if (argc == 1) { /* print all env vars */ - rcode = env_print(NULL); + rcode = env_print(NULL, env_flag); if (!rcode) return 1; printf("\nEnvironment size: %d/%ld bytes\n", @@ -153,8 +160,9 @@ static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc, } /* print selected env vars */ + env_flag &= ~H_HIDE_DOT; for (i = 1; i < argc; ++i) { - int rc = env_print(argv[i]); + int rc = env_print(argv[i], env_flag); if (!rc) { printf("## Error: \"%s\" not defined\n", argv[i]); ++rcode; @@ -807,7 +815,7 @@ NXTARG: ; argv++; if (sep) { /* export as text file */ - len = hexport_r(&env_htab, sep, &addr, size, argc, argv); + len = hexport_r(&env_htab, sep, 0, &addr, size, argc, argv); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; @@ -825,7 +833,7 @@ NXTARG: ; else /* export as raw binary data */ res = addr; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, argc, argv); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, argc, argv); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; @@ -1037,7 +1045,7 @@ static char env_help_text[] = #if defined(CONFIG_CMD_IMPORTENV) "env import [-d] [-t | -b | -c] addr [size] - import environment\n" #endif - "env print [name ...] - print environment\n" + "env print [-a | name ...] - print environment\n" #if defined(CONFIG_CMD_RUN) "env run var [...] - run commands in an environment variable\n" #endif @@ -1069,7 +1077,7 @@ U_BOOT_CMD_COMPLETE( U_BOOT_CMD_COMPLETE( printenv, CONFIG_SYS_MAXARGS, 1, do_env_print, "print environment variables", - "\n - print values of all environment variables\n" + "[-a]\n - print [all] values of all environment variables\n" "printenv name ...\n" " - print value of environment variable 'name'", var_complete diff --git a/common/env_dataflash.c b/common/env_dataflash.c index 3c5af37bf..38c96157b 100644 --- a/common/env_dataflash.c +++ b/common/env_dataflash.c @@ -60,7 +60,7 @@ int saveenv(void) char *res; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/env_eeprom.c b/common/env_eeprom.c index b66bba29f..45c935b6d 100644 --- a/common/env_eeprom.c +++ b/common/env_eeprom.c @@ -139,7 +139,7 @@ int saveenv(void) BUG_ON(env_ptr != NULL); res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/env_fat.c b/common/env_fat.c index 6ef531821..c0f18ab97 100644 --- a/common/env_fat.c +++ b/common/env_fat.c @@ -61,7 +61,7 @@ int saveenv(void) int err; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/env_flash.c b/common/env_flash.c index aa970d440..e07d336a4 100644 --- a/common/env_flash.c +++ b/common/env_flash.c @@ -142,7 +142,7 @@ int saveenv(void) goto done; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); goto done; @@ -275,7 +275,7 @@ int saveenv(void) goto done; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); goto done; diff --git a/common/env_mmc.c b/common/env_mmc.c index a2ff90bf4..ce2167121 100644 --- a/common/env_mmc.c +++ b/common/env_mmc.c @@ -130,7 +130,7 @@ int saveenv(void) } res = (char *)&env_new->data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); ret = 1; diff --git a/common/env_nand.c b/common/env_nand.c index 79e803370..22e72a20b 100644 --- a/common/env_nand.c +++ b/common/env_nand.c @@ -186,7 +186,7 @@ int saveenv(void) return 1; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; @@ -239,7 +239,7 @@ int saveenv(void) return 1; res = (char *)&env_new->data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/env_nvram.c b/common/env_nvram.c index 6483db39d..eab0e7be0 100644 --- a/common/env_nvram.c +++ b/common/env_nvram.c @@ -90,7 +90,7 @@ int saveenv(void) int rcode = 0; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/env_onenand.c b/common/env_onenand.c index da3507125..faa903d2f 100644 --- a/common/env_onenand.c +++ b/common/env_onenand.c @@ -95,7 +95,7 @@ int saveenv(void) }; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/env_sf.c b/common/env_sf.c index bbd472fcf..d9e908546 100644 --- a/common/env_sf.c +++ b/common/env_sf.c @@ -79,7 +79,7 @@ int saveenv(void) } res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; @@ -277,7 +277,7 @@ int saveenv(void) } res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); goto done; diff --git a/include/search.h b/include/search.h index fa00ea1b3..1e48deb1c 100644 --- a/include/search.h +++ b/include/search.h @@ -107,7 +107,7 @@ extern int hdelete_r(const char *__key, struct hsearch_data *__htab, int __flag); extern ssize_t hexport_r(struct hsearch_data *__htab, - const char __sep, char **__resp, size_t __size, + const char __sep, int __flag, char **__resp, size_t __size, int argc, char * const argv[]); /* @@ -120,9 +120,10 @@ extern int himport_r(struct hsearch_data *__htab, const char *__env, size_t __size, const char __sep, int __flag, int nvars, char * const vars[]); -/* Flags for himport_r(), hdelete_r(), and hsearch_r() */ +/* Flags for himport_r(), hexport_r(), hdelete_r(), and hsearch_r() */ #define H_NOCLEAR (1 << 0) /* do not clear hash table before importing */ #define H_FORCE (1 << 1) /* overwrite read-only/write-once variables */ #define H_INTERACTIVE (1 << 2) /* indicate that an import is user directed */ +#define H_HIDE_DOT (1 << 3) /* don't print env vars that begin with '.' */ #endif /* search.h */ diff --git a/lib/hashtable.c b/lib/hashtable.c index 6861a4202..7c6b96cac 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -522,7 +522,7 @@ static int cmpkey(const void *p1, const void *p2) return (strcmp(e1->key, e2->key)); } -ssize_t hexport_r(struct hsearch_data *htab, const char sep, +ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag, char **resp, size_t size, int argc, char * const argv[]) { @@ -559,6 +559,9 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep, if ((argc > 0) && (found == 0)) continue; + if ((flag & H_HIDE_DOT) && ep->key[0] == '.') + continue; + list[n++] = ep; totlen += strlen(ep->key) + 2; -- cgit v1.2.3-70-g09d2 From 5e2b3e0c59df3313254941b453ffeadba9e673ae Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:25 -0600 Subject: env: Add a command to view callbacks The callbacks can be bound, but are otherwise invisible. Add a command to show what callbacks are available. Signed-off-by: Joe Hershberger !!! fix callback command --- README | 1 + common/cmd_nvedit.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) (limited to 'common/cmd_nvedit.c') diff --git a/README b/README index e00a7c2a8..ac61a32ad 100644 --- a/README +++ b/README @@ -815,6 +815,7 @@ The following options need to be configured: CONFIG_CMD_EDITENV edit env variable CONFIG_CMD_EEPROM * EEPROM read/write support CONFIG_CMD_ELF * bootelf, bootvx + CONFIG_CMD_ENV_CALLBACK * display details about env callbacks CONFIG_CMD_EXPORTENV * export the environment CONFIG_CMD_EXT2 * ext2 command support CONFIG_CMD_EXT4 * ext4 command support diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 022ad3942..1e51b9d06 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -514,6 +514,81 @@ int do_env_ask(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } #endif +#if defined(CONFIG_CMD_ENV_CALLBACK) +static int print_static_binding(const char *var_name, const char *callback_name) +{ + printf("\t%-20s %-20s\n", var_name, callback_name); + + return 0; +} + +static int print_active_callback(ENTRY *entry) +{ + struct env_clbk_tbl *clbkp; + int i; + int num_callbacks; + + if (entry->callback == NULL) + return 0; + + /* look up the callback in the linker-list */ + num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk); + for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk); + i < num_callbacks; + i++, clbkp++) { +#if defined(CONFIG_NEEDS_MANUAL_RELOC) + if (entry->callback == clbkp->callback + gd->reloc_off) +#else + if (entry->callback == clbkp->callback) +#endif + break; + } + + if (i == num_callbacks) + /* this should probably never happen, but just in case... */ + printf("\t%-20s %p\n", entry->key, entry->callback); + else + printf("\t%-20s %-20s\n", entry->key, clbkp->name); + + return 0; +} + +/* + * Print the callbacks available and what they are bound to + */ +int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct env_clbk_tbl *clbkp; + int i; + int num_callbacks; + + /* Print the available callbacks */ + puts("Available callbacks:\n"); + puts("\tCallback Name\n"); + puts("\t-------------\n"); + num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk); + for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk); + i < num_callbacks; + i++, clbkp++) + printf("\t%s\n", clbkp->name); + puts("\n"); + + /* Print the static bindings that may exist */ + puts("Static callback bindings:\n"); + printf("\t%-20s %-20s\n", "Variable Name", "Callback Name"); + printf("\t%-20s %-20s\n", "-------------", "-------------"); + env_attr_walk(ENV_CALLBACK_LIST_STATIC, print_static_binding); + puts("\n"); + + /* walk through each variable and print the callback if it has one */ + puts("Active callback bindings:\n"); + printf("\t%-20s %-20s\n", "Variable Name", "Callback Name"); + printf("\t%-20s %-20s\n", "-------------", "-------------"); + hwalk_r(&env_htab, print_active_callback); + return 0; +} +#endif + /* * Interactively edit an environment variable */ @@ -981,6 +1056,9 @@ static cmd_tbl_t cmd_env_sub[] = { #if defined(CONFIG_CMD_EDITENV) U_BOOT_CMD_MKENT(edit, 2, 0, do_env_edit, "", ""), #endif +#if defined(CONFIG_CMD_ENV_CALLBACK) + U_BOOT_CMD_MKENT(callbacks, 1, 0, do_env_callback, "", ""), +#endif #if defined(CONFIG_CMD_EXPORTENV) U_BOOT_CMD_MKENT(export, 4, 0, do_env_export, "", ""), #endif @@ -1030,6 +1108,9 @@ static int do_env(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) static char env_help_text[] = #if defined(CONFIG_CMD_ASKENV) "ask name [message] [size] - ask for environment variable\nenv " +#endif +#if defined(CONFIG_CMD_ENV_CALLBACK) + "callbacks - print callbacks and their associated variables\nenv " #endif "default [-f] -a - [forcibly] reset default environment\n" "env default [-f] var [...] - [forcibly] reset variable(s) to their default values\n" -- cgit v1.2.3-70-g09d2 From a9f51c9b4315f699e7185c85d1d09d2d7819a4eb Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:26 -0600 Subject: env: Add a bootfile env handler Remove the hard-coded bootfile handler and use a callback instead Signed-off-by: Joe Hershberger --- common/cmd_nvedit.c | 9 --------- include/env_callback.h | 1 + net/net.c | 17 +++++++++++++++++ 3 files changed, 18 insertions(+), 9 deletions(-) (limited to 'common/cmd_nvedit.c') diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 1e51b9d06..874baef86 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -50,9 +50,6 @@ #include #include #include -#if defined(CONFIG_CMD_NET) -#include -#endif DECLARE_GLOBAL_DATA_PTR; @@ -328,12 +325,6 @@ int env_change_ok(const ENTRY *item, const char *newval, enum env_op op, load_addr = simple_strtoul(newval, NULL, 16); return 0; } -#if defined(CONFIG_CMD_NET) - else if (strcmp(name, "bootfile") == 0) { - copy_filename(BootFile, newval, sizeof(BootFile)); - return 0; - } -#endif return 0; } diff --git a/include/env_callback.h b/include/env_callback.h index 5a460f353..bce01362c 100644 --- a/include/env_callback.h +++ b/include/env_callback.h @@ -39,6 +39,7 @@ * a new association in the ".callbacks" environment variable. */ #define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \ + "bootfile:bootfile," \ CONFIG_ENV_CALLBACK_LIST_STATIC struct env_clbk_tbl { diff --git a/net/net.c b/net/net.c index da68a61d6..a40cde1e9 100644 --- a/net/net.c +++ b/net/net.c @@ -82,6 +82,7 @@ #include #include +#include #include #if defined(CONFIG_STATUS_LED) #include @@ -208,6 +209,22 @@ static int NetTryCount; /**********************************************************************/ +static int on_bootfile(const char *name, const char *value, enum env_op op, + int flags) +{ + switch (op) { + case env_op_create: + case env_op_overwrite: + copy_filename(BootFile, value, sizeof(BootFile)); + break; + default: + break; + } + + return 0; +} +U_BOOT_ENV_CALLBACK(bootfile, on_bootfile); + /* * Check if autoload is enabled. If so, use either NFS or TFTP to download * the boot file. -- cgit v1.2.3-70-g09d2 From 32057717e06a4e703fdf3774671cea14554de76b Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:27 -0600 Subject: env: Add a baudrate env handler Remove the hard-coded baudrate handler and use a callback instead Signed-off-by: Joe Hershberger --- common/cmd_nvedit.c | 47 --------------------------------- drivers/serial/serial.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ include/env_callback.h | 1 + 3 files changed, 71 insertions(+), 47 deletions(-) (limited to 'common/cmd_nvedit.c') diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 874baef86..df136cfa3 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -77,12 +77,6 @@ ulong load_addr = CONFIG_SYS_LOAD_ADDR; /* Default Load Address */ ulong save_addr; /* Default Save Address */ ulong save_size; /* Default Save Size (in bytes) */ -/* - * Table with supported baudrates (defined in config_xyz.h) - */ -static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE; -#define N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0])) - /* * This variable is incremented on each do_env_set(), so it can * be used via get_env_id() as an indication, if the environment @@ -275,47 +269,6 @@ int env_change_ok(const ENTRY *item, const char *newval, enum env_op op, } } #endif - /* - * When we change baudrate, or we are doing an env default -a - * (which will erase all variables prior to calling this), - * we want the baudrate to actually change - for real. - */ - if (op != env_op_create || /* variable exists */ - (flag & H_NOCLEAR) == 0) { /* or env is clear */ - /* - * Switch to new baudrate if new baudrate is supported - */ - if (strcmp(name, "baudrate") == 0) { - int baudrate = simple_strtoul(newval, NULL, 10); - int i; - for (i = 0; i < N_BAUDRATES; ++i) { - if (baudrate == baudrate_table[i]) - break; - } - if (i == N_BAUDRATES) { - if ((flag & H_FORCE) == 0) - printf("## Baudrate %d bps not " - "supported\n", baudrate); - return 1; - } - if (gd->baudrate == baudrate) { - /* If unchanged, we just say it's OK */ - return 0; - } - printf("## Switch baudrate to %d bps and" - "press ENTER ...\n", baudrate); - udelay(50000); - gd->baudrate = baudrate; -#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2) - gd->bd->bi_baudrate = baudrate; -#endif - - serial_setbrg(); - udelay(50000); - while (getc() != '\r') - ; - } - } /* * Some variables should be updated when the corresponding diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index f5f43a6dd..1f8955a0f 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -22,6 +22,7 @@ */ #include +#include #include #include #include @@ -32,6 +33,11 @@ DECLARE_GLOBAL_DATA_PTR; static struct serial_device *serial_devices; static struct serial_device *serial_current; +/* + * Table with supported baudrates (defined in config_xyz.h) + */ +static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE; +#define N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0])) /** * serial_null() - Void registration routine of a serial driver @@ -45,6 +51,70 @@ static void serial_null(void) { } +/** + * on_baudrate() - Update the actual baudrate when the env var changes + * + * This will check for a valid baudrate and only apply it if valid. + */ +static int on_baudrate(const char *name, const char *value, enum env_op op, + int flags) +{ + int i; + int baudrate; + + switch (op) { + case env_op_create: + case env_op_overwrite: + /* + * Switch to new baudrate if new baudrate is supported + */ + baudrate = simple_strtoul(value, NULL, 10); + + /* Not actually changing */ + if (gd->baudrate == baudrate) + return 0; + + for (i = 0; i < N_BAUDRATES; ++i) { + if (baudrate == baudrate_table[i]) + break; + } + if (i == N_BAUDRATES) { + if ((flags & H_FORCE) == 0) + printf("## Baudrate %d bps not supported\n", + baudrate); + return 1; + } + if ((flags & H_INTERACTIVE) != 0) { + printf("## Switch baudrate to %d" + " bps and press ENTER ...\n", baudrate); + udelay(50000); + } + + gd->baudrate = baudrate; +#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2) + gd->bd->bi_baudrate = baudrate; +#endif + + serial_setbrg(); + + udelay(50000); + + if ((flags & H_INTERACTIVE) != 0) + while (1) { + if (getc() == '\r') + break; + } + + return 0; + case env_op_delete: + printf("## Baudrate may not be deleted\n"); + return 1; + default: + return 0; + } +} +U_BOOT_ENV_CALLBACK(baudrate, on_baudrate); + /** * serial_initfunc() - Forward declare of driver registration routine * @name: Name of the real driver registration routine. diff --git a/include/env_callback.h b/include/env_callback.h index bce01362c..2f5048fa4 100644 --- a/include/env_callback.h +++ b/include/env_callback.h @@ -39,6 +39,7 @@ * a new association in the ".callbacks" environment variable. */ #define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \ + "baudrate:baudrate," \ "bootfile:bootfile," \ CONFIG_ENV_CALLBACK_LIST_STATIC -- cgit v1.2.3-70-g09d2 From 1cf0a8b2fbe38ed07b1babaaacfc22bd427f66f0 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:28 -0600 Subject: env: Add a loadaddr env handler Remove the hard-coded loadaddr handler and use a callback instead Signed-off-by: Joe Hershberger --- common/cmd_nvedit.c | 12 ------------ common/image.c | 21 +++++++++++++++++++++ include/env_callback.h | 1 + 3 files changed, 22 insertions(+), 12 deletions(-) (limited to 'common/cmd_nvedit.c') diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index df136cfa3..9ff8b36d3 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -73,10 +73,6 @@ SPI_FLASH|NVRAM|MMC|FAT|REMOTE} or CONFIG_ENV_IS_NOWHERE */ #define MAX_ENV_SIZE (1 << 20) /* 1 MiB */ -ulong load_addr = CONFIG_SYS_LOAD_ADDR; /* Default Load Address */ -ulong save_addr; /* Default Save Address */ -ulong save_size; /* Default Save Size (in bytes) */ - /* * This variable is incremented on each do_env_set(), so it can * be used via get_env_id() as an indication, if the environment @@ -270,14 +266,6 @@ int env_change_ok(const ENTRY *item, const char *newval, enum env_op op, } #endif - /* - * Some variables should be updated when the corresponding - * entry in the environment is changed - */ - if (strcmp(name, "loadaddr") == 0) { - load_addr = simple_strtoul(newval, NULL, 16); - return 0; - } return 0; } diff --git a/common/image.c b/common/image.c index 69e888c5d..95498e618 100644 --- a/common/image.c +++ b/common/image.c @@ -43,6 +43,7 @@ #include #endif +#include #include #if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT) @@ -416,6 +417,26 @@ static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch, /* Shared dual-format routines */ /*****************************************************************************/ #ifndef USE_HOSTCC +ulong load_addr = CONFIG_SYS_LOAD_ADDR; /* Default Load Address */ +ulong save_addr; /* Default Save Address */ +ulong save_size; /* Default Save Size (in bytes) */ + +static int on_loadaddr(const char *name, const char *value, enum env_op op, + int flags) +{ + switch (op) { + case env_op_create: + case env_op_overwrite: + load_addr = simple_strtoul(value, NULL, 16); + break; + default: + break; + } + + return 0; +} +U_BOOT_ENV_CALLBACK(loadaddr, on_loadaddr); + ulong getenv_bootm_low(void) { char *s = getenv("bootm_low"); diff --git a/include/env_callback.h b/include/env_callback.h index 2f5048fa4..bb398ec57 100644 --- a/include/env_callback.h +++ b/include/env_callback.h @@ -41,6 +41,7 @@ #define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \ "baudrate:baudrate," \ "bootfile:bootfile," \ + "loadaddr:loadaddr," \ CONFIG_ENV_CALLBACK_LIST_STATIC struct env_clbk_tbl { -- cgit v1.2.3-70-g09d2 From 849d5d9cda0e7c94797874d842e9b132ec45a565 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:29 -0600 Subject: env: Add a console env handler Remove the hard-coded console handler and use a callback instead Signed-off-by: Joe Hershberger --- common/cmd_nvedit.c | 36 +++--------------------------------- common/console.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ include/env_callback.h | 1 + 3 files changed, 48 insertions(+), 33 deletions(-) (limited to 'common/cmd_nvedit.c') diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 9ff8b36d3..cb191cd06 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include @@ -206,10 +205,9 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag, int env_change_ok(const ENTRY *item, const char *newval, enum env_op op, int flag) { - int console = -1; +#ifndef CONFIG_ENV_OVERWRITE const char *name; -#if !defined(CONFIG_ENV_OVERWRITE) && defined(CONFIG_OVERWRITE_ETHADDR_ONCE) \ -&& defined(CONFIG_ETHADDR) +#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR) const char *oldval = NULL; if (op != env_op_create) @@ -217,35 +215,7 @@ int env_change_ok(const ENTRY *item, const char *newval, enum env_op op, #endif name = item->key; - - /* Default value for NULL to protect string-manipulating functions */ - newval = newval ? : ""; - - /* Check for console redirection */ - if (strcmp(name, "stdin") == 0) - console = stdin; - else if (strcmp(name, "stdout") == 0) - console = stdout; - else if (strcmp(name, "stderr") == 0) - console = stderr; - - if (console != -1 && (gd->flags & GD_FLG_DEVINIT) != 0) { - if ((newval == NULL) || (*newval == '\0')) { - /* We cannot delete stdin/stdout/stderr */ - if ((flag & H_FORCE) == 0) - printf("Can't delete \"%s\"\n", name); - return 1; - } - -#ifdef CONFIG_CONSOLE_MUX - if (iomux_doenv(console, newval)) - return 1; -#else - /* Try assigning specified device */ - if (console_assign(console, newval) < 0) - return 1; -#endif /* CONFIG_CONSOLE_MUX */ - } +#endif #ifndef CONFIG_ENV_OVERWRITE /* diff --git a/common/console.c b/common/console.c index c21934d1b..270170b3d 100644 --- a/common/console.c +++ b/common/console.c @@ -24,11 +24,55 @@ #include #include #include +#include #include #include +#include DECLARE_GLOBAL_DATA_PTR; +static int on_console(const char *name, const char *value, enum env_op op, + int flags) +{ + int console = -1; + + /* Check for console redirection */ + if (strcmp(name, "stdin") == 0) + console = stdin; + else if (strcmp(name, "stdout") == 0) + console = stdout; + else if (strcmp(name, "stderr") == 0) + console = stderr; + + /* if not actually setting a console variable, we don't care */ + if (console == -1 || (gd->flags & GD_FLG_DEVINIT) == 0) + return 0; + + switch (op) { + case env_op_create: + case env_op_overwrite: + +#ifdef CONFIG_CONSOLE_MUX + if (iomux_doenv(console, value)) + return 1; +#else + /* Try assigning specified device */ + if (console_assign(console, value) < 0) + return 1; +#endif /* CONFIG_CONSOLE_MUX */ + return 0; + + case env_op_delete: + if ((flags & H_FORCE) == 0) + printf("Can't delete \"%s\"\n", name); + return 1; + + default: + return 0; + } +} +U_BOOT_ENV_CALLBACK(console, on_console); + #ifdef CONFIG_SYS_CONSOLE_IS_IN_ENV /* * if overwrite_console returns 1, the stdin, stderr and stdout diff --git a/include/env_callback.h b/include/env_callback.h index bb398ec57..9d2d2c9bf 100644 --- a/include/env_callback.h +++ b/include/env_callback.h @@ -42,6 +42,7 @@ "baudrate:baudrate," \ "bootfile:bootfile," \ "loadaddr:loadaddr," \ + "stdin:console,stdout:console,stderr:console," \ CONFIG_ENV_CALLBACK_LIST_STATIC struct env_clbk_tbl { -- cgit v1.2.3-70-g09d2 From 2598090b7e17f8bdca95b22e7f27217054730e02 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:31 -0600 Subject: env: Add environment variable flags Currently just validates variable types as decimal, hexidecimal, boolean, ip address, and mac address. If the entry is not found in the env ".flags", then look in the static one. This allows the env to override the static definitions, but prevents the need to have every definition in the environment distracting you. Signed-off-by: Joe Hershberger --- README | 37 ++++++ common/Makefile | 2 + common/cmd_nvedit.c | 50 +------- common/env_common.c | 2 +- common/env_flags.c | 319 +++++++++++++++++++++++++++++++++++++++++++++++++ include/env_callback.h | 2 + include/env_default.h | 3 + include/env_flags.h | 76 ++++++++++++ include/environment.h | 9 +- include/search.h | 1 + lib/hashtable.c | 4 + 11 files changed, 447 insertions(+), 58 deletions(-) create mode 100644 common/env_flags.c create mode 100644 include/env_flags.h (limited to 'common/cmd_nvedit.c') diff --git a/README b/README index ac61a32ad..acb711a38 100644 --- a/README +++ b/README @@ -2188,6 +2188,11 @@ CBFS (Coreboot Filesystem) support serial# is unaffected by this, i. e. it remains read-only.] + The same can be accomplished in a more flexible way + for any variable by configuring the type of access + to allow for those variables in the ".flags" variable + or define CONFIG_ENV_FLAGS_LIST_STATIC. + - Protected RAM: CONFIG_PRAM @@ -3113,6 +3118,38 @@ Configuration Settings: cases. This setting can be used to tune behaviour; see lib/hashtable.c for details. +- CONFIG_ENV_FLAGS_LIST_DEFAULT +- CONFIG_ENV_FLAGS_LIST_STATIC + Enable validation of the values given to enviroment variables when + calling env set. Variables can be restricted to only decimal, + hexadecimal, or boolean. If CONFIG_CMD_NET is also defined, + the variables can also be restricted to IP address or MAC address. + + The format of the list is: + type_attribute = [s|d|x|b|i|m] + attributes = type_attribute + entry = variable_name[:attributes] + list = entry[,list] + + The type attributes are: + s - String (default) + d - Decimal + x - Hexadecimal + b - Boolean ([1yYtT|0nNfF]) + i - IP address + m - MAC address + + - CONFIG_ENV_FLAGS_LIST_DEFAULT + Define this to a list (string) to define the ".flags" + envirnoment variable in the default or embedded environment. + + - CONFIG_ENV_FLAGS_LIST_STATIC + Define this to a list (string) to define validation that + should be done if an entry is not found in the ".flags" + environment variable. To override a setting in the static + list, simply add an entry for the same variable name to the + ".flags" variable. + The following definitions that deal with the placement and management of environment data (variable area); in general, we support the following configurations: diff --git a/common/Makefile b/common/Makefile index 04812e9b2..c77439556 100644 --- a/common/Makefile +++ b/common/Makefile @@ -47,6 +47,7 @@ COBJS-y += cmd_version.o COBJS-y += env_attr.o COBJS-y += env_callback.o COBJS-y += env_common.o +COBJS-y += env_flags.o COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o XCOBJS-$(CONFIG_ENV_IS_EMBEDDED) += env_embedded.o @@ -212,6 +213,7 @@ COBJS-$(CONFIG_SPL_NET_SUPPORT) += cmd_nvedit.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_attr.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_callback.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_common.o +COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_flags.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_nowhere.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o endif diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index cb191cd06..f645194bf 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -191,58 +191,10 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag, #endif #endif /* CONFIG_SPL_BUILD */ -/* - * Perform consistency checking before setting, replacing, or deleting an - * environment variable, then (if successful) apply the changes to internals so - * to make them effective. Code for this function was taken out of - * _do_env_set(), which now calls it instead. - * Also called as a callback function by himport_r(). - * Returns 0 in case of success, 1 in case of failure. - * When (flag & H_FORCE) is set, do not print out any error message and force - * overwriting of write-once variables. - */ - -int env_change_ok(const ENTRY *item, const char *newval, enum env_op op, - int flag) -{ -#ifndef CONFIG_ENV_OVERWRITE - const char *name; -#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR) - const char *oldval = NULL; - - if (op != env_op_create) - oldval = item->data; -#endif - - name = item->key; -#endif - -#ifndef CONFIG_ENV_OVERWRITE - /* - * Some variables like "ethaddr" and "serial#" can be set only once and - * cannot be deleted, unless CONFIG_ENV_OVERWRITE is defined. - */ - if (op != env_op_create && /* variable exists */ - (flag & H_FORCE) == 0) { /* and we are not forced */ - if (strcmp(name, "serial#") == 0 || - (strcmp(name, "ethaddr") == 0 -#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR) - && strcmp(oldval, __stringify(CONFIG_ETHADDR)) != 0 -#endif /* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */ - )) { - printf("Can't overwrite \"%s\"\n", name); - return 1; - } - } -#endif - - return 0; -} - /* * Set a new environment variable, * or replace or delete an existing one. -*/ + */ static int _do_env_set(int flag, int argc, char * const argv[]) { int i, len; diff --git a/common/env_common.c b/common/env_common.c index 067fe3f4c..bb18070c5 100644 --- a/common/env_common.c +++ b/common/env_common.c @@ -40,7 +40,7 @@ DECLARE_GLOBAL_DATA_PTR; #include struct hsearch_data env_htab = { - .change_ok = env_change_ok, + .change_ok = env_flags_validate, }; static uchar __env_get_char_spec(int index) diff --git a/common/env_flags.c b/common/env_flags.c new file mode 100644 index 000000000..a58d614bb --- /dev/null +++ b/common/env_flags.c @@ -0,0 +1,319 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +#include +#include + +#ifdef CONFIG_CMD_NET +#define ENV_FLAGS_NET_VARTYPE_REPS "im" +#else +#define ENV_FLAGS_NET_VARTYPE_REPS "" +#endif + +static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS; + +/* + * Parse the flags string from a .flags attribute list into the vartype enum. + */ +enum env_flags_vartype env_flags_parse_vartype(const char *flags) +{ + char *type; + + if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC) + return env_flags_vartype_string; + + type = strchr(env_flags_vartype_rep, + flags[ENV_FLAGS_VARTYPE_LOC]); + + if (type != NULL) + return (enum env_flags_vartype) + (type - &env_flags_vartype_rep[0]); + + printf("## Warning: Unknown environment variable type '%c'\n", + flags[ENV_FLAGS_VARTYPE_LOC]); + return env_flags_vartype_string; +} + +static inline int is_hex_prefix(const char *value) +{ + return value[0] == '0' && (value[1] == 'x' || value[1] == 'X'); +} + +static void skip_num(int hex, const char *value, const char **end, + int max_digits) +{ + int i; + + if (hex && is_hex_prefix(value)) + value += 2; + + for (i = max_digits; i != 0; i--) { + if (hex && !isxdigit(*value)) + break; + if (!hex && !isdigit(*value)) + break; + value++; + } + if (end != NULL) + *end = value; +} + +/* + * Based on the declared type enum, validate that the value string complies + * with that format + */ +static int _env_flags_validate_type(const char *value, + enum env_flags_vartype type) +{ + const char *end; +#ifdef CONFIG_CMD_NET + const char *cur; + int i; +#endif + + switch (type) { + case env_flags_vartype_string: + break; + case env_flags_vartype_decimal: + skip_num(0, value, &end, -1); + if (*end != '\0') + return -1; + break; + case env_flags_vartype_hex: + skip_num(1, value, &end, -1); + if (*end != '\0') + return -1; + if (value + 2 == end && is_hex_prefix(value)) + return -1; + break; + case env_flags_vartype_bool: + if (value[0] != '1' && value[0] != 'y' && value[0] != 't' && + value[0] != 'Y' && value[0] != 'T' && + value[0] != '0' && value[0] != 'n' && value[0] != 'f' && + value[0] != 'N' && value[0] != 'F') + return -1; + if (value[1] != '\0') + return -1; + break; +#ifdef CONFIG_CMD_NET + case env_flags_vartype_ipaddr: + cur = value; + for (i = 0; i < 4; i++) { + skip_num(0, cur, &end, 3); + if (cur == end) + return -1; + if (i != 3 && *end != '.') + return -1; + if (i == 3 && *end != '\0') + return -1; + cur = end + 1; + } + break; + case env_flags_vartype_macaddr: + cur = value; + for (i = 0; i < 6; i++) { + skip_num(1, cur, &end, 2); + if (cur == end) + return -1; + if (cur + 2 == end && is_hex_prefix(cur)) + return -1; + if (i != 5 && *end != ':') + return -1; + if (i == 5 && *end != '\0') + return -1; + cur = end + 1; + } + break; +#endif + case env_flags_vartype_end: + return -1; + } + + /* OK */ + return 0; +} + +/* + * Look for flags in a provided list and failing that the static list + */ +static inline int env_flags_lookup(const char *flags_list, const char *name, + char *flags) +{ + int ret = 1; + + if (!flags) + /* bad parameter */ + return -1; + + /* try the env first */ + if (flags_list) + ret = env_attr_lookup(flags_list, name, flags); + + if (ret != 0) + /* if not found in the env, look in the static list */ + ret = env_attr_lookup(ENV_FLAGS_LIST_STATIC, name, flags); + + return ret; +} + +/* + * Parse the flag charachters from the .flags attribute list into the binary + * form to be stored in the environment entry->flags field. + */ +static int env_parse_flags_to_bin(const char *flags) +{ + return env_flags_parse_vartype(flags) & ENV_FLAGS_VARTYPE_BIN_MASK; +} + +/* + * Look for possible flags for a newly added variable + * This is called specifically when the variable did not exist in the hash + * previously, so the blanket update did not find this variable. + */ +void env_flags_init(ENTRY *var_entry) +{ + const char *var_name = var_entry->key; + const char *flags_list = getenv(ENV_FLAGS_VAR); + char flags[ENV_FLAGS_ATTR_MAX_LEN + 1] = ""; + int ret = 1; + + /* look in the ".flags" and static for a reference to this variable */ + ret = env_flags_lookup(flags_list, var_name, flags); + + /* if any flags were found, set the binary form to the entry */ + if (!ret && strlen(flags)) + var_entry->flags = env_parse_flags_to_bin(flags); +} + +/* + * Called on each existing env var prior to the blanket update since removing + * a flag in the flag list should remove its flags. + */ +static int clear_flags(ENTRY *entry) +{ + entry->flags = 0; + + return 0; +} + +/* + * Call for each element in the list that defines flags for a variable + */ +static int set_flags(const char *name, const char *value) +{ + ENTRY e, *ep; + + e.key = name; + e.data = NULL; + hsearch_r(e, FIND, &ep, &env_htab, 0); + + /* does the env variable actually exist? */ + if (ep != NULL) { + /* the flag list is empty, so clear the flags */ + if (value == NULL || strlen(value) == 0) + ep->flags = 0; + else + /* assign the requested flags */ + ep->flags = env_parse_flags_to_bin(value); + } + + return 0; +} + +static int on_flags(const char *name, const char *value, enum env_op op, + int flags) +{ + /* remove all flags */ + hwalk_r(&env_htab, clear_flags); + + /* configure any static flags */ + env_attr_walk(ENV_FLAGS_LIST_STATIC, set_flags); + /* configure any dynamic flags */ + env_attr_walk(value, set_flags); + + return 0; +} +U_BOOT_ENV_CALLBACK(flags, on_flags); + +/* + * Perform consistency checking before creating, overwriting, or deleting an + * environment variable. Called as a callback function by hsearch_r() and + * hdelete_r(). Returns 0 in case of success, 1 in case of failure. + * When (flag & H_FORCE) is set, do not print out any error message and force + * overwriting of write-once variables. + */ + +int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op, + int flag) +{ + const char *name; +#if !defined(CONFIG_ENV_OVERWRITE) && defined(CONFIG_OVERWRITE_ETHADDR_ONCE) \ +&& defined(CONFIG_ETHADDR) + const char *oldval = NULL; + + if (op != env_op_create) + oldval = item->data; +#endif + + name = item->key; + + /* Default value for NULL to protect string-manipulating functions */ + newval = newval ? : ""; + +#ifndef CONFIG_ENV_OVERWRITE + /* + * Some variables like "ethaddr" and "serial#" can be set only once and + * cannot be deleted, unless CONFIG_ENV_OVERWRITE is defined. + */ + if (op != env_op_create && /* variable exists */ + (flag & H_FORCE) == 0) { /* and we are not forced */ + if (strcmp(name, "serial#") == 0 || + (strcmp(name, "ethaddr") == 0 +#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR) + && strcmp(oldval, __stringify(CONFIG_ETHADDR)) != 0 +#endif /* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */ + )) { + printf("Can't overwrite \"%s\"\n", name); + return 1; + } + } +#endif + + /* validate the value to match the variable type */ + if (op != env_op_delete) { + enum env_flags_vartype type = (enum env_flags_vartype) + (ENV_FLAGS_VARTYPE_BIN_MASK & item->flags); + + if (_env_flags_validate_type(newval, type) < 0) { + printf("## Error: flags type check failure for " + "\"%s\" <= \"%s\" (type: %c)\n", + name, newval, env_flags_vartype_rep[type]); + return -1; + } + } + + return 0; +} diff --git a/include/env_callback.h b/include/env_callback.h index f52e133f1..47fdc6fa9 100644 --- a/include/env_callback.h +++ b/include/env_callback.h @@ -24,6 +24,7 @@ #ifndef __ENV_CALLBACK_H__ #define __ENV_CALLBACK_H__ +#include #include #include @@ -45,6 +46,7 @@ * a new association in the ".callbacks" environment variable. */ #define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \ + ENV_FLAGS_VAR ":flags," \ "baudrate:baudrate," \ "bootfile:bootfile," \ "loadaddr:loadaddr," \ diff --git a/include/env_default.h b/include/env_default.h index d05eba161..39c5b7c6a 100644 --- a/include/env_default.h +++ b/include/env_default.h @@ -41,6 +41,9 @@ const uchar default_environment[] = { #ifdef CONFIG_ENV_CALLBACK_LIST_DEFAULT ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0" #endif +#ifdef CONFIG_ENV_FLAGS_LIST_DEFAULT + ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0" +#endif #ifdef CONFIG_BOOTARGS "bootargs=" CONFIG_BOOTARGS "\0" #endif diff --git a/include/env_flags.h b/include/env_flags.h new file mode 100644 index 000000000..bf25f2746 --- /dev/null +++ b/include/env_flags.h @@ -0,0 +1,76 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ENV_FLAGS_H__ +#define __ENV_FLAGS_H__ + +enum env_flags_vartype { + env_flags_vartype_string, + env_flags_vartype_decimal, + env_flags_vartype_hex, + env_flags_vartype_bool, +#ifdef CONFIG_CMD_NET + env_flags_vartype_ipaddr, + env_flags_vartype_macaddr, +#endif + env_flags_vartype_end +}; + +#define ENV_FLAGS_VAR ".flags" +#define ENV_FLAGS_ATTR_MAX_LEN 2 +#define ENV_FLAGS_VARTYPE_LOC 0 + +#ifndef CONFIG_ENV_FLAGS_LIST_STATIC +#define CONFIG_ENV_FLAGS_LIST_STATIC "" +#endif + +#define ENV_FLAGS_LIST_STATIC \ + CONFIG_ENV_FLAGS_LIST_STATIC + +/* + * Parse the flags string from a .flags attribute list into the vartype enum. + */ +enum env_flags_vartype env_flags_parse_vartype(const char *flags); + +#include + +/* + * When adding a variable to the environment, initialize the flags for that + * variable. + */ +void env_flags_init(ENTRY *var_entry); + +/* + * Validate the newval for to conform with the requirements defined by its flags + */ +int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op, + int flag); + +/* + * These are the binary flags used in the environment entry->flags variable to + * decribe properties of veriables in the table + */ +#define ENV_FLAGS_VARTYPE_BIN_MASK 0x00000007 +/* The actual variable type values use the enum value (within the mask) */ + +#endif /* __ENV_FLAGS_H__ */ diff --git a/include/environment.h b/include/environment.h index 6c3021552..00e59ba78 100644 --- a/include/environment.h +++ b/include/environment.h @@ -166,6 +166,7 @@ extern void env_reloc(void); #include #include +#include #include extern struct hsearch_data env_htab; @@ -189,14 +190,6 @@ int set_default_vars(int nvars, char * const vars[]); /* Import from binary representation into hash table */ int env_import(const char *buf, int check); -/* - * Check if variable "item" can be changed to newval - * When (flag & H_FORCE) is set, it does not print out any error - * message and forces overwriting of write-once variables. - */ -int env_change_ok(const ENTRY *item, const char *newval, enum env_op op, - int flag); - #endif /* DO_DEPS_ONLY */ #endif /* _ENVIRONMENT_H_ */ diff --git a/include/search.h b/include/search.h index d68e24a03..13d3be629 100644 --- a/include/search.h +++ b/include/search.h @@ -49,6 +49,7 @@ typedef struct entry { char *data; int (*callback)(const char *name, const char *value, enum env_op op, int flags); + int flags; } ENTRY; /* Opaque type for internal use. */ diff --git a/lib/hashtable.c b/lib/hashtable.c index e9226665f..07ebfb218 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -55,6 +55,7 @@ #endif #include +#include #include /* @@ -412,6 +413,8 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, /* This is a new entry, so look up a possible callback */ env_callback_init(&htab->table[idx].entry); + /* Also look for flags */ + env_flags_init(&htab->table[idx].entry); /* check for permission */ if (htab->change_ok != NULL && htab->change_ok( @@ -465,6 +468,7 @@ static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep, free((void *)ep->key); free(ep->data); ep->callback = NULL; + ep->flags = 0; htab->table[idx].used = -1; --htab->filled; -- cgit v1.2.3-70-g09d2 From fffad71bc489cf224eda6d826a1645423852ee45 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:33 -0600 Subject: env: Add a command to display details about env flags Similar to the env callback command, this will show details about the options available, the static list, and the currently active variables. Signed-off-by: Joe Hershberger --- README | 1 + common/cmd_nvedit.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++ common/env_flags.c | 34 ++++++++++++++++++++++++++++++ include/env_flags.h | 11 ++++++++++ 4 files changed, 105 insertions(+) (limited to 'common/cmd_nvedit.c') diff --git a/README b/README index acb711a38..08c0fccb5 100644 --- a/README +++ b/README @@ -816,6 +816,7 @@ The following options need to be configured: CONFIG_CMD_EEPROM * EEPROM read/write support CONFIG_CMD_ELF * bootelf, bootvx CONFIG_CMD_ENV_CALLBACK * display details about env callbacks + CONFIG_CMD_ENV_FLAGS * display details about env flags CONFIG_CMD_EXPORTENV * export the environment CONFIG_CMD_EXT2 * ext2 command support CONFIG_CMD_EXT4 * ext4 command support diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index f645194bf..468b89cc9 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -443,6 +443,59 @@ int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } #endif +#if defined(CONFIG_CMD_ENV_FLAGS) +static int print_static_flags(const char *var_name, const char *flags) +{ + enum env_flags_vartype type = env_flags_parse_vartype(flags); + + printf("\t%-20s %-20s\n", var_name, env_flags_get_vartype_name(type)); + + return 0; +} + +static int print_active_flags(ENTRY *entry) +{ + enum env_flags_vartype type; + + if (entry->flags == 0) + return 0; + + type = (enum env_flags_vartype) + (entry->flags & ENV_FLAGS_VARTYPE_BIN_MASK); + printf("\t%-20s %-20s\n", entry->key, env_flags_get_vartype_name(type)); + + return 0; +} + +/* + * Print the flags available and what variables have flags + */ +int do_env_flags(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + /* Print the available variable types */ + printf("Available variable type flags (position %d):\n", + ENV_FLAGS_VARTYPE_LOC); + puts("\tFlag\tVariable Type Name\n"); + puts("\t----\t------------------\n"); + env_flags_print_vartypes(); + puts("\n"); + + /* Print the static flags that may exist */ + puts("Static flags:\n"); + printf("\t%-20s %-20s\n", "Variable Name", "Variable Type"); + printf("\t%-20s %-20s\n", "-------------", "-------------"); + env_attr_walk(ENV_FLAGS_LIST_STATIC, print_static_flags); + puts("\n"); + + /* walk through each variable and print the flags if non-default */ + puts("Active flags:\n"); + printf("\t%-20s %-20s\n", "Variable Name", "Variable Type"); + printf("\t%-20s %-20s\n", "-------------", "-------------"); + hwalk_r(&env_htab, print_active_flags); + return 0; +} +#endif + /* * Interactively edit an environment variable */ @@ -913,6 +966,9 @@ static cmd_tbl_t cmd_env_sub[] = { #if defined(CONFIG_CMD_ENV_CALLBACK) U_BOOT_CMD_MKENT(callbacks, 1, 0, do_env_callback, "", ""), #endif +#if defined(CONFIG_CMD_ENV_FLAGS) + U_BOOT_CMD_MKENT(flags, 1, 0, do_env_flags, "", ""), +#endif #if defined(CONFIG_CMD_EXPORTENV) U_BOOT_CMD_MKENT(export, 4, 0, do_env_export, "", ""), #endif @@ -974,6 +1030,9 @@ static char env_help_text[] = #if defined(CONFIG_CMD_EXPORTENV) "env export [-t | -b | -c] [-s size] addr [var ...] - export environment\n" #endif +#if defined(CONFIG_CMD_ENV_FLAGS) + "env flags - print variables that have non-default flags\n" +#endif #if defined(CONFIG_CMD_GREPENV) "env grep string [...] - search environment\n" #endif diff --git a/common/env_flags.c b/common/env_flags.c index ed0857cf9..09f93d59d 100644 --- a/common/env_flags.c +++ b/common/env_flags.c @@ -43,6 +43,40 @@ #endif static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS; +#ifdef CONFIG_CMD_ENV_FLAGS +static const char * const env_flags_vartype_names[] = { + "string", + "decimal", + "hexadecimal", + "boolean", +#ifdef CONFIG_CMD_NET + "IP address", + "MAC address", +#endif +}; + +/* + * Print the whole list of available type flags. + */ +void env_flags_print_vartypes(void) +{ + enum env_flags_vartype curtype = (enum env_flags_vartype)0; + + while (curtype != env_flags_vartype_end) { + printf("\t%c -\t%s\n", env_flags_vartype_rep[curtype], + env_flags_vartype_names[curtype]); + curtype++; + } +} + +/* + * Return the name of the type. + */ +const char *env_flags_get_vartype_name(enum env_flags_vartype type) +{ + return env_flags_vartype_names[type]; +} +#endif /* CONFIG_CMD_ENV_FLAGS */ /* * Parse the flags string from a .flags attribute list into the vartype enum. diff --git a/include/env_flags.h b/include/env_flags.h index 33334464d..7e72523f0 100644 --- a/include/env_flags.h +++ b/include/env_flags.h @@ -47,6 +47,17 @@ enum env_flags_vartype { #define ENV_FLAGS_LIST_STATIC \ CONFIG_ENV_FLAGS_LIST_STATIC +#ifdef CONFIG_CMD_ENV_FLAGS +/* + * Print the whole list of available type flags. + */ +void env_flags_print_vartypes(void); +/* + * Return the name of the type. + */ +const char *env_flags_get_vartype_name(enum env_flags_vartype type); +#endif + /* * Parse the flags string from a .flags attribute list into the vartype enum. */ -- cgit v1.2.3-70-g09d2 From 267541f776f1e2bec21681c6e39a4c93af9621cf Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:34 -0600 Subject: env: Add support for access control to .flags Add support for read-only, write-once, and change-default. Signed-off-by: Joe Hershberger --- README | 13 ++++- common/cmd_nvedit.c | 31 ++++++++-- common/env_common.c | 18 ++++++ common/env_flags.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++-- include/env_flags.h | 50 +++++++++++++++- include/environment.h | 3 + tools/env/fw_env.c | 74 +++++++++++++++++++++-- 7 files changed, 330 insertions(+), 18 deletions(-) (limited to 'common/cmd_nvedit.c') diff --git a/README b/README index 08c0fccb5..b5c1c0377 100644 --- a/README +++ b/README @@ -3128,7 +3128,8 @@ Configuration Settings: The format of the list is: type_attribute = [s|d|x|b|i|m] - attributes = type_attribute + access_atribute = [a|r|o|c] + attributes = type_attribute[access_atribute] entry = variable_name[:attributes] list = entry[,list] @@ -3140,6 +3141,12 @@ Configuration Settings: i - IP address m - MAC address + The access attributes are: + a - Any (default) + r - Read-only + o - Write-once + c - Change-default + - CONFIG_ENV_FLAGS_LIST_DEFAULT Define this to a list (string) to define the ".flags" envirnoment variable in the default or embedded environment. @@ -3151,6 +3158,10 @@ Configuration Settings: list, simply add an entry for the same variable name to the ".flags" variable. +- CONFIG_ENV_ACCESS_IGNORE_FORCE + If defined, don't allow the -f switch to env set override variable + access flags. + The following definitions that deal with the placement and management of environment data (variable area); in general, we support the following configurations: diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 468b89cc9..e8dfbf5d8 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -447,8 +447,11 @@ int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) static int print_static_flags(const char *var_name, const char *flags) { enum env_flags_vartype type = env_flags_parse_vartype(flags); + enum env_flags_varaccess access = env_flags_parse_varaccess(flags); - printf("\t%-20s %-20s\n", var_name, env_flags_get_vartype_name(type)); + printf("\t%-20s %-20s %-20s\n", var_name, + env_flags_get_vartype_name(type), + env_flags_get_varaccess_name(access)); return 0; } @@ -456,13 +459,17 @@ static int print_static_flags(const char *var_name, const char *flags) static int print_active_flags(ENTRY *entry) { enum env_flags_vartype type; + enum env_flags_varaccess access; if (entry->flags == 0) return 0; type = (enum env_flags_vartype) (entry->flags & ENV_FLAGS_VARTYPE_BIN_MASK); - printf("\t%-20s %-20s\n", entry->key, env_flags_get_vartype_name(type)); + access = env_flags_parse_varaccess_from_binflags(entry->flags); + printf("\t%-20s %-20s %-20s\n", entry->key, + env_flags_get_vartype_name(type), + env_flags_get_varaccess_name(access)); return 0; } @@ -480,17 +487,29 @@ int do_env_flags(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) env_flags_print_vartypes(); puts("\n"); + /* Print the available variable access types */ + printf("Available variable access flags (position %d):\n", + ENV_FLAGS_VARACCESS_LOC); + puts("\tFlag\tVariable Access Name\n"); + puts("\t----\t--------------------\n"); + env_flags_print_varaccess(); + puts("\n"); + /* Print the static flags that may exist */ puts("Static flags:\n"); - printf("\t%-20s %-20s\n", "Variable Name", "Variable Type"); - printf("\t%-20s %-20s\n", "-------------", "-------------"); + printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type", + "Variable Access"); + printf("\t%-20s %-20s %-20s\n", "-------------", "-------------", + "---------------"); env_attr_walk(ENV_FLAGS_LIST_STATIC, print_static_flags); puts("\n"); /* walk through each variable and print the flags if non-default */ puts("Active flags:\n"); - printf("\t%-20s %-20s\n", "Variable Name", "Variable Type"); - printf("\t%-20s %-20s\n", "-------------", "-------------"); + printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type", + "Variable Access"); + printf("\t%-20s %-20s %-20s\n", "-------------", "-------------", + "---------------"); hwalk_r(&env_htab, print_active_flags); return 0; } diff --git a/common/env_common.c b/common/env_common.c index bb18070c5..906b41fcc 100644 --- a/common/env_common.c +++ b/common/env_common.c @@ -95,6 +95,24 @@ int getenv_yesno(const char *var) 1 : 0; } +/* + * Look up the variable from the default environment + */ +char *getenv_default(const char *name) +{ + char *ret_val; + unsigned long really_valid = gd->env_valid; + unsigned long real_gd_flags = gd->flags; + + /* Pretend that the image is bad. */ + gd->flags &= ~GD_FLG_ENV_READY; + gd->env_valid = 0; + ret_val = getenv(name); + gd->env_valid = really_valid; + gd->flags = real_gd_flags; + return ret_val; +} + void set_default_env(const char *s) { int flags = 0; diff --git a/common/env_flags.c b/common/env_flags.c index 09f93d59d..4caf12e69 100644 --- a/common/env_flags.c +++ b/common/env_flags.c @@ -43,6 +43,17 @@ #endif static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS; +static const char env_flags_varaccess_rep[] = "aroc"; +static const int env_flags_varaccess_mask[] = { + 0, + ENV_FLAGS_VARACCESS_PREVENT_DELETE | + ENV_FLAGS_VARACCESS_PREVENT_CREATE | + ENV_FLAGS_VARACCESS_PREVENT_OVERWR, + ENV_FLAGS_VARACCESS_PREVENT_DELETE | + ENV_FLAGS_VARACCESS_PREVENT_OVERWR, + ENV_FLAGS_VARACCESS_PREVENT_DELETE | + ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR}; + #ifdef CONFIG_CMD_ENV_FLAGS static const char * const env_flags_vartype_names[] = { "string", @@ -54,6 +65,12 @@ static const char * const env_flags_vartype_names[] = { "MAC address", #endif }; +static const char * const env_flags_varaccess_names[] = { + "any", + "read-only", + "write-once", + "change-default", +}; /* * Print the whole list of available type flags. @@ -69,6 +86,20 @@ void env_flags_print_vartypes(void) } } +/* + * Print the whole list of available access flags. + */ +void env_flags_print_varaccess(void) +{ + enum env_flags_varaccess curaccess = (enum env_flags_varaccess)0; + + while (curaccess != env_flags_varaccess_end) { + printf("\t%c -\t%s\n", env_flags_varaccess_rep[curaccess], + env_flags_varaccess_names[curaccess]); + curaccess++; + } +} + /* * Return the name of the type. */ @@ -76,6 +107,14 @@ const char *env_flags_get_vartype_name(enum env_flags_vartype type) { return env_flags_vartype_names[type]; } + +/* + * Return the name of the access. + */ +const char *env_flags_get_varaccess_name(enum env_flags_varaccess access) +{ + return env_flags_varaccess_names[access]; +} #endif /* CONFIG_CMD_ENV_FLAGS */ /* @@ -100,6 +139,46 @@ enum env_flags_vartype env_flags_parse_vartype(const char *flags) return env_flags_vartype_string; } +/* + * Parse the flags string from a .flags attribute list into the varaccess enum. + */ +enum env_flags_varaccess env_flags_parse_varaccess(const char *flags) +{ + char *access; + + if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC) + return env_flags_varaccess_any; + + access = strchr(env_flags_varaccess_rep, + flags[ENV_FLAGS_VARACCESS_LOC]); + + if (access != NULL) + return (enum env_flags_varaccess) + (access - &env_flags_varaccess_rep[0]); + + printf("## Warning: Unknown environment variable access method '%c'\n", + flags[ENV_FLAGS_VARACCESS_LOC]); + return env_flags_varaccess_any; +} + +/* + * Parse the binary flags from a hash table entry into the varaccess enum. + */ +enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags) +{ + int i; + + for (i = 0; i < sizeof(env_flags_varaccess_mask); i++) + if (env_flags_varaccess_mask[i] == + (binflags & ENV_FLAGS_VARACCESS_BIN_MASK)) + return (enum env_flags_varaccess)i; + + printf("Warning: Non-standard access flags. (0x%x)\n", + binflags & ENV_FLAGS_VARACCESS_BIN_MASK); + + return env_flags_varaccess_any; +} + static inline int is_hex_prefix(const char *value) { return value[0] == '0' && (value[1] == 'x' || value[1] == 'X'); @@ -241,6 +320,23 @@ enum env_flags_vartype env_flags_get_type(const char *name) return env_flags_parse_vartype(flags); } +/* + * Look up the access of a variable directly from the .flags var. + */ +enum env_flags_varaccess env_flags_get_varaccess(const char *name) +{ + const char *flags_list = getenv(ENV_FLAGS_VAR); + char flags[ENV_FLAGS_ATTR_MAX_LEN + 1]; + + if (env_flags_lookup(flags_list, name, flags)) + return env_flags_varaccess_any; + + if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC) + return env_flags_varaccess_any; + + return env_flags_parse_varaccess(flags); +} + /* * Validate that the proposed new value for "name" is valid according to the * defined flags for that variable, if any. @@ -261,6 +357,21 @@ int env_flags_validate_type(const char *name, const char *value) return 0; } +/* + * Validate that the proposed access to variable "name" is valid according to + * the defined flags for that variable, if any. + */ +int env_flags_validate_varaccess(const char *name, int check_mask) +{ + enum env_flags_varaccess access; + int access_mask; + + access = env_flags_get_varaccess(name); + access_mask = env_flags_varaccess_mask[access]; + + return (check_mask & access_mask) != 0; +} + /* * Validate the parameters to "env set" directly */ @@ -292,7 +403,12 @@ int env_flags_validate_env_set_params(int argc, char * const argv[]) */ static int env_parse_flags_to_bin(const char *flags) { - return env_flags_parse_vartype(flags) & ENV_FLAGS_VARTYPE_BIN_MASK; + int binflags; + + binflags = env_flags_parse_vartype(flags) & ENV_FLAGS_VARTYPE_BIN_MASK; + binflags |= env_flags_varaccess_mask[env_flags_parse_varaccess(flags)]; + + return binflags; } /* @@ -377,13 +493,10 @@ int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op, int flag) { const char *name; -#if !defined(CONFIG_ENV_OVERWRITE) && defined(CONFIG_OVERWRITE_ETHADDR_ONCE) \ -&& defined(CONFIG_ETHADDR) const char *oldval = NULL; if (op != env_op_create) oldval = item->data; -#endif name = item->key; @@ -422,6 +535,44 @@ int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op, } } + /* check for access permission */ +#ifndef CONFIG_ENV_ACCESS_IGNORE_FORCE + if (flag & H_FORCE) + return 0; +#endif + switch (op) { + case env_op_delete: + if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_DELETE) { + printf("## Error: Can't delete \"%s\"\n", name); + return 1; + } + break; + case env_op_overwrite: + if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_OVERWR) { + printf("## Error: Can't overwrite \"%s\"\n", name); + return 1; + } else if (item->flags & + ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR) { + const char *defval = getenv_default(name); + + if (defval == NULL) + defval = ""; + printf("oldval: %s defval: %s\n", oldval, defval); + if (strcmp(oldval, defval) != 0) { + printf("## Error: Can't overwrite \"%s\"\n", + name); + return 1; + } + } + break; + case env_op_create: + if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_CREATE) { + printf("## Error: Can't create \"%s\"\n", name); + return 1; + } + break; + } + return 0; } diff --git a/include/env_flags.h b/include/env_flags.h index 7e72523f0..0bdae0783 100644 --- a/include/env_flags.h +++ b/include/env_flags.h @@ -36,9 +36,18 @@ enum env_flags_vartype { env_flags_vartype_end }; +enum env_flags_varaccess { + env_flags_varaccess_any, + env_flags_varaccess_readonly, + env_flags_varaccess_writeonce, + env_flags_varaccess_changedefault, + env_flags_varaccess_end +}; + #define ENV_FLAGS_VAR ".flags" #define ENV_FLAGS_ATTR_MAX_LEN 2 #define ENV_FLAGS_VARTYPE_LOC 0 +#define ENV_FLAGS_VARACCESS_LOC 1 #ifndef CONFIG_ENV_FLAGS_LIST_STATIC #define CONFIG_ENV_FLAGS_LIST_STATIC "" @@ -52,27 +61,57 @@ enum env_flags_vartype { * Print the whole list of available type flags. */ void env_flags_print_vartypes(void); +/* + * Print the whole list of available access flags. + */ +void env_flags_print_varaccess(void); /* * Return the name of the type. */ const char *env_flags_get_vartype_name(enum env_flags_vartype type); +/* + * Return the name of the access. + */ +const char *env_flags_get_varaccess_name(enum env_flags_varaccess access); #endif /* * Parse the flags string from a .flags attribute list into the vartype enum. */ enum env_flags_vartype env_flags_parse_vartype(const char *flags); +/* + * Parse the flags string from a .flags attribute list into the varaccess enum. + */ +enum env_flags_varaccess env_flags_parse_varaccess(const char *flags); +/* + * Parse the binary flags from a hash table entry into the varaccess enum. + */ +enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags); #ifdef USE_HOSTCC /* * Look up the type of a variable directly from the .flags var. */ enum env_flags_vartype env_flags_get_type(const char *name); +/* + * Look up the access of a variable directly from the .flags var. + */ +enum env_flags_varaccess env_flags_get_access(const char *name); /* * Validate the newval for its type to conform with the requirements defined by * its flags (directly looked at the .flags var). */ int env_flags_validate_type(const char *name, const char *newval); +/* + * Validate the newval for its access to conform with the requirements defined + * by its flags (directly looked at the .flags var). + */ +int env_flags_validate_access(const char *name, int check_mask); +/* + * Validate that the proposed access to variable "name" is valid according to + * the defined flags for that variable, if any. + */ +int env_flags_validate_varaccess(const char *name, int check_mask); /* * Validate the parameters passed to "env set" for type compliance */ @@ -94,13 +133,18 @@ void env_flags_init(ENTRY *var_entry); int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op, int flag); +#endif /* USE_HOSTCC */ + /* * These are the binary flags used in the environment entry->flags variable to * decribe properties of veriables in the table */ -#define ENV_FLAGS_VARTYPE_BIN_MASK 0x00000007 +#define ENV_FLAGS_VARTYPE_BIN_MASK 0x00000007 /* The actual variable type values use the enum value (within the mask) */ - -#endif /* USE_HOSTCC */ +#define ENV_FLAGS_VARACCESS_PREVENT_DELETE 0x00000008 +#define ENV_FLAGS_VARACCESS_PREVENT_CREATE 0x00000010 +#define ENV_FLAGS_VARACCESS_PREVENT_OVERWR 0x00000020 +#define ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR 0x00000040 +#define ENV_FLAGS_VARACCESS_BIN_MASK 0x00000078 #endif /* __ENV_FLAGS_H__ */ diff --git a/include/environment.h b/include/environment.h index 00e59ba78..e64b43d2d 100644 --- a/include/environment.h +++ b/include/environment.h @@ -181,6 +181,9 @@ unsigned char env_get_char_memory(int index); /* Function that updates CRC of the enironment */ void env_crc_update(void); +/* Look up the variable from the default environment */ +char *getenv_default(const char *name); + /* [re]set to the default environment */ void set_default_env(const char *s); diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c index 5be36fc35..a596a1b0d 100644 --- a/tools/env/fw_env.c +++ b/tools/env/fw_env.c @@ -181,6 +181,32 @@ char *fw_getenv (char *name) return NULL; } +/* + * Search the default environment for a variable. + * Return the value, if found, or NULL, if not found. + */ +char *fw_getdefenv(char *name) +{ + char *env, *nxt; + + for (env = default_environment; *env; env = nxt + 1) { + char *val; + + for (nxt = env; *nxt; ++nxt) { + if (nxt >= &default_environment[ENV_SIZE]) { + fprintf(stderr, "## Error: " + "default environment not terminated\n"); + return NULL; + } + } + val = envmatch(name, env); + if (!val) + continue; + return val; + } + return NULL; +} + /* * Print the current definition of one, or more, or all * environment variables @@ -282,6 +308,7 @@ int fw_env_write(char *name, char *value) int len; char *env, *nxt; char *oldval = NULL; + int deleting, creating, overwriting; /* * search if variable with this name already exists @@ -299,10 +326,49 @@ int fw_env_write(char *name, char *value) break; } - /* - * Delete any existing definition - */ - if (oldval) { + deleting = (oldval && !(value && strlen(value))); + creating = (!oldval && (value && strlen(value))); + overwriting = (oldval && (value && strlen(value))); + + /* check for permission */ + if (deleting) { + if (env_flags_validate_varaccess(name, + ENV_FLAGS_VARACCESS_PREVENT_DELETE)) { + printf("Can't delete \"%s\"\n", name); + errno = EROFS; + return -1; + } + } else if (overwriting) { + if (env_flags_validate_varaccess(name, + ENV_FLAGS_VARACCESS_PREVENT_OVERWR)) { + printf("Can't overwrite \"%s\"\n", name); + errno = EROFS; + return -1; + } else if (env_flags_validate_varaccess(name, + ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR)) { + const char *defval = fw_getdefenv(name); + + if (defval == NULL) + defval = ""; + if (strcmp(oldval, defval) + != 0) { + printf("Can't overwrite \"%s\"\n", name); + errno = EROFS; + return -1; + } + } + } else if (creating) { + if (env_flags_validate_varaccess(name, + ENV_FLAGS_VARACCESS_PREVENT_CREATE)) { + printf("Can't create \"%s\"\n", name); + errno = EROFS; + return -1; + } + } else + /* Nothing to do */ + return 0; + + if (deleting || overwriting) { #ifndef CONFIG_ENV_OVERWRITE /* * Ethernet Address and serial# can be set only once -- cgit v1.2.3-70-g09d2 From 24ab5a1914283b891fa50bc285128bc5fd4ac50a Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:35 -0600 Subject: env: Add setenv force support Now that we have support for permissions, add a way to override them. Signed-off-by: Joe Hershberger --- common/cmd_nvedit.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) (limited to 'common/cmd_nvedit.c') diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index e8dfbf5d8..988d6b3c7 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -200,7 +200,24 @@ static int _do_env_set(int flag, int argc, char * const argv[]) int i, len; char *name, *value, *s; ENTRY e, *ep; + int env_flag = H_INTERACTIVE; + debug("Initial value for argc=%d\n", argc); + while (argc > 1 && **(argv + 1) == '-') { + char *arg = *++argv; + + --argc; + while (*++arg) { + switch (*arg) { + case 'f': /* force */ + env_flag |= H_FORCE; + break; + default: + return CMD_RET_USAGE; + } + } + } + debug("Final value for argc=%d\n", argc); name = argv[1]; value = argv[2]; @@ -214,7 +231,7 @@ static int _do_env_set(int flag, int argc, char * const argv[]) /* Delete only ? */ if (argc < 3 || argv[2] == NULL) { - int rc = hdelete_r(name, &env_htab, H_INTERACTIVE); + int rc = hdelete_r(name, &env_htab, env_flag); return !rc; } @@ -241,7 +258,7 @@ static int _do_env_set(int flag, int argc, char * const argv[]) e.key = name; e.data = value; - hsearch_r(e, ENTER, &ep, &env_htab, H_INTERACTIVE); + hsearch_r(e, ENTER, &ep, &env_htab, env_flag); free(value); if (!ep) { printf("## Error inserting \"%s\" variable, errno=%d\n", @@ -1109,10 +1126,10 @@ U_BOOT_CMD_COMPLETE( U_BOOT_CMD_COMPLETE( setenv, CONFIG_SYS_MAXARGS, 0, do_env_set, "set environment variables", - "name value ...\n" - " - set environment variable 'name' to 'value ...'\n" - "setenv name\n" - " - delete environment variable 'name'", + "[-f] name value ...\n" + " - [forcibly] set environment variable 'name' to 'value ...'\n" + "setenv [-f] name\n" + " - [forcibly] delete environment variable 'name'", var_complete ); -- cgit v1.2.3-70-g09d2 From 9d8d661d7fda6ccda1d5fc31565f207b7648bc6d Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:36 -0600 Subject: env: Implement the env delete command Implement a way to delete more than one variable at a time. Signed-off-by: Joe Hershberger --- common/cmd_nvedit.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) (limited to 'common/cmd_nvedit.c') diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 988d6b3c7..7633f0c44 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -725,8 +725,36 @@ static int do_env_default(cmd_tbl_t *cmdtp, int __flag, static int do_env_delete(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - printf("Not implemented yet\n"); - return 0; + int env_flag = H_INTERACTIVE; + int ret = 0; + + debug("Initial value for argc=%d\n", argc); + while (argc > 1 && **(argv + 1) == '-') { + char *arg = *++argv; + + --argc; + while (*++arg) { + switch (*arg) { + case 'f': /* force */ + env_flag |= H_FORCE; + break; + default: + return CMD_RET_USAGE; + } + } + } + debug("Final value for argc=%d\n", argc); + + env_id++; + + while (--argc > 0) { + char *name = *++argv; + + if (!hdelete_r(name, &env_htab, env_flag)) + ret = 1; + } + + return ret; } #ifdef CONFIG_CMD_EXPORTENV @@ -995,7 +1023,7 @@ static cmd_tbl_t cmd_env_sub[] = { U_BOOT_CMD_MKENT(ask, CONFIG_SYS_MAXARGS, 1, do_env_ask, "", ""), #endif U_BOOT_CMD_MKENT(default, 1, 0, do_env_default, "", ""), - U_BOOT_CMD_MKENT(delete, 2, 0, do_env_delete, "", ""), + U_BOOT_CMD_MKENT(delete, CONFIG_SYS_MAXARGS, 0, do_env_delete, "", ""), #if defined(CONFIG_CMD_EDITENV) U_BOOT_CMD_MKENT(edit, 2, 0, do_env_edit, "", ""), #endif @@ -1060,6 +1088,7 @@ static char env_help_text[] = #endif "default [-f] -a - [forcibly] reset default environment\n" "env default [-f] var [...] - [forcibly] reset variable(s) to their default values\n" + "env delete [-f] var [...] - [forcibly] delete variable(s)\n" #if defined(CONFIG_CMD_EDITENV) "env edit name - edit environment variable\n" #endif -- cgit v1.2.3-70-g09d2