diff options
-rw-r--r-- | common/env.c | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/common/env.c b/common/env.c new file mode 100644 index 0000000000..241110f588 --- /dev/null +++ b/common/env.c @@ -0,0 +1,296 @@ +#include <common.h> +#include <command.h> +#include <driver.h> +#include <malloc.h> +#include <asm-generic/errno.h> + +static ulong env_size; +static char *env_name_spec; + +struct variable_d { + struct variable_d *next; + char data[0]; +}; + +#define VARIABLE_D_SIZE(name, value) (sizeof(struct variable_d) + strlen(name) + strlen(value) + 2) + +static struct variable_d *env_list; + +static char *var_val(struct variable_d *var) +{ + return &var->data[strlen(var->data) + 2]; +} + +static char *var_name(struct variable_d *var) +{ + return var->data; +} + +char *getenv (const char *name) +{ + struct variable_d *var; + + if (!env_list) { + printf("getenv(%s): not initialized\n",name); + return NULL; + } + + var = env_list->next; + + while (var) { + if (!strcmp(var_name(var), name)) + return var_val(var); + var = var->next; + } + return 0; +} + +void setenv (const char *name, const char *value) +{ + struct variable_d *var = env_list; + struct variable_d *newvar = NULL; + + if (!env_list) { + printf("setenv(%s): not initialized\n",name); + return; + } + + if (value) { + newvar = malloc(VARIABLE_D_SIZE(name, value)); + if (!newvar) { + printf("cannot setenv: out of mem\n"); + return; + } + + strcpy(&newvar->data[0], name); + strcpy(&newvar->data[strlen(name) + 2], value); + newvar->next = NULL; + } + + while (var->next) { + if (!strcmp(var->next->data, name)) { + if (value) { + newvar->next = var->next->next; + free(var->next); + var->next = newvar; + return; + } else { + struct variable_d *tmp; + tmp = var->next; + var->next = var->next->next; + free(var->next); + return; + } + } + var = var->next; + } + var->next = newvar; +} + +int add_env_spec(char *spec) +{ + char *env; + char *data; + int err; + unsigned long crc; + struct memarea_info info; + + printf("%s\n",__FUNCTION__); + + if (spec_str_to_info(spec, &info)) { + printf("-ENOPARSE\n"); + return -1; + } + + /* Do it the simple way for now: Assume that the whole + * environment sector plus the environment list fits in + * memory. + */ + + env_size = info.size; + env_name_spec = spec; + + env = malloc(env_size); + if (!env) { + err = -ENOMEM; + goto err_out; + } + + env_list = malloc(sizeof(struct variable_d)); + if (!env_list) { + err = -ENOMEM; + goto err_out; + } + + env_list->next = NULL; + + err = read(info.device, env, env_size, info.start, 0); + if (err != env_size) + goto err_out; + + /* Make sure we don't go crazy with a corrupted environment */ + *(env + env_size - 1) = 0; + *(env + env_size - 2) = 0; + + crc = *(ulong *)env; + if (crc != crc32(0, env + sizeof(ulong), env_size - sizeof(ulong))) { + printf("environment is corrupt\n"); + err = -ENODEV; + goto err_out; + } + + data = env + sizeof(env); + + while(*data) { + char *delim = strchr(data, '='); + int len = strlen(data); + printf("data: %s\n", data); + + if (!delim) + goto err_out; + + *delim = 0; + setenv(data, delim + 1); + data += len + 1; + } + + free(env); + + return 0; +err_out: + printf("error\n"); + return -1; +} + +int saveenv(void) +{ + struct variable_d *var = env_list->next; + struct memarea_info info; + unsigned char *env; + int left, ret = 0, ofs; + + if (spec_str_to_info(env_name_spec, &info)) { + printf("-ENOPARSE\n"); + return -1; + } + + env = malloc(env_size); + if (!env) { + printf("out of memory\n"); + ret = -ENOMEM; + goto err_out; + } + + memset(env, 0, env_size); + + left = env_size - 2; + ofs = 4; + + while (var) { + int nlen = strlen(var_name(var)); + int vlen = strlen(var_val(var)); + + if (ofs + nlen + 1 + vlen + 2 >= env_size) { + printf("no space left in environment\n"); + ret = -ENOSPC; + goto err_out; + } + strcpy(env + ofs, var_name(var)); + ofs += nlen; + *(env + ofs) = '='; + ofs++; + strcpy(env + ofs, var_val(var)); + ofs += vlen + 1; + + var = var->next; + } + + *(ulong *)env = crc32(0, env + sizeof(ulong), env_size - sizeof(ulong)); + + ret = erase(info.device, info.size, info.start); + if (ret) { + printf("unable to erase\n"); + goto err_out; + } + + ret = write(info.device, env, info.size, info.start, 0); + if (ret < 0) { + printf("unable to write\n"); + goto err_out; + } + + free(env); + + return 0; + +err_out: + if (env) + free(env); + + return ret; +} + +int do_printenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + struct variable_d *var = env_list->next; + + if (argc == 2) { + char *val = getenv(argv[1]); + if (val) { + printf("%s=%s\n", argv[1], val); + return 0; + } + printf("## Error: \"%s\" not defined\n", argv[1]); + return -EINVAL; + } + + while (var) { + printf("%s=%s\n", var_name(var), var_val(var)); + var = var->next; + } + + return 0; +} + +U_BOOT_CMD( + printenv, CFG_MAXARGS, 1, do_printenv, + "printenv- print environment variables\n", + "\n - print values of all environment variables\n" + "printenv name ...\n" + " - print value of environment variable 'name'\n" +); + +int do_setenv ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + if (argc < 2) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + setenv(argv[1], argv[2]); + + return 0; +} + +U_BOOT_CMD( + setenv, CFG_MAXARGS, 0, do_setenv, + "setenv - set environment variables\n", + "name value ...\n" + " - set environment variable 'name' to 'value ...'\n" + "setenv name\n" + " - delete environment variable 'name'\n" +); + +int do_saveenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + printf ("Saving Environment to %s...\n", env_name_spec); + + return saveenv(); +} + +U_BOOT_CMD( + saveenv, 1, 0, do_saveenv, + "saveenv - save environment variables to persistent storage\n", + NULL +); + |