[U-Boot] [PATCH] Tools: set multiple variable with fw_setenv utility
Stefano Babic
sbabic at denx.de
Fri May 21 12:52:11 CEST 2010
Add a sort of batch mode to fw_setenv, allowing to set
multiple variables in one shot, without updating the flash after
each set as now. It is added the possibility to pass
a config file with a list of pairs <variable, value> to be set,
separated by a TAB character.
Signed-off-by: Stefano Babic <sbabic at denx.de>
---
tools/env/fw_env.c | 216 +++++++++++++++++++++++++++++++++++++++--------
tools/env/fw_env.h | 7 ++
tools/env/fw_env_main.c | 32 +++++++-
3 files changed, 218 insertions(+), 37 deletions(-)
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index a46205d..506a806 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -45,9 +45,6 @@
#include "fw_env.h"
-#define CMD_GETENV "fw_printenv"
-#define CMD_SETENV "fw_setenv"
-
#define min(x, y) ({ \
typeof(x) _min1 = (x); \
typeof(y) _min2 = (y); \
@@ -328,29 +325,15 @@ int fw_printenv (int argc, char *argv[])
}
/*
- * Deletes or sets environment variables. Returns -1 and sets errno error codes:
- * 0 - OK
- * EINVAL - need at least 1 argument
- * EROFS - certain variables ("ethaddr", "serial#") cannot be
- * modified or deleted
- *
+ * Set/Clear a single variable in the environment.
+ * This is called in sequence to update the environment
+ * in RAM without updating the copy in flash after each set
*/
-int fw_setenv (int argc, char *argv[])
+int fw_set_single_var(char *name, char *value)
{
- int i, len;
+ int len;
char *env, *nxt;
char *oldval = NULL;
- char *name;
-
- if (argc < 2) {
- errno = EINVAL;
- return -1;
- }
-
- if (env_init ())
- return -1;
-
- name = argv[1];
/*
* search if variable with this name already exists
@@ -358,7 +341,7 @@ int fw_setenv (int argc, char *argv[])
for (nxt = env = environment.data; *env; env = nxt + 1) {
for (nxt = env; *nxt; ++nxt) {
if (nxt >= &environment.data[ENV_SIZE]) {
- fprintf (stderr, "## Error: "
+ fprintf(stderr, "## Error: "
"environment not terminated\n");
errno = EINVAL;
return -1;
@@ -396,8 +379,8 @@ int fw_setenv (int argc, char *argv[])
}
/* Delete only ? */
- if (argc < 3)
- goto WRITE_FLASH;
+ if (!value || !strlen(value))
+ return 0;
/*
* Append new definition at the end
@@ -411,41 +394,204 @@ int fw_setenv (int argc, char *argv[])
*/
len = strlen (name) + 2;
/* add '=' for first arg, ' ' for all others */
- for (i = 2; i < argc; ++i) {
- len += strlen (argv[i]) + 1;
- }
+ len += strlen(value) + 1;
+
if (len > (&environment.data[ENV_SIZE] - env)) {
fprintf (stderr,
"Error: environment overflow, \"%s\" deleted\n",
name);
return -1;
}
+
while ((*env = *name++) != '\0')
env++;
+ *env = '=';
+ while ((*++env = *value++) != '\0')
+ ;
+
+ /* end is marked with double '\0' */
+ *++env = '\0';
+
+ return 0;
+}
+
+/*
+ * Deletes or sets environment variables. Returns -1 and sets errno error codes:
+ * 0 - OK
+ * EINVAL - need at least 1 argument
+ * EROFS - certain variables ("ethaddr", "serial#") cannot be
+ * modified or deleted
+ *
+ */
+int fw_setenv(int argc, char *argv[])
+{
+ int i, len;
+ char *env;
+ char *name;
+ char *value = NULL;
+ char *tmpval = NULL;
+
+ if (argc < 2) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (env_init())
+ return -1;
+
+ name = argv[1];
+
+ /*
+ * Overflow when:
+ * "name" + "=" + "val" +"\0\0" > CONFIG_ENV_SIZE - (env-environment)
+ */
+ len = strlen(name) + 2;
+ /* add '=' for first arg, ' ' for all others */
+ for (i = 2; i < argc; ++i)
+ len += strlen(argv[i]) + 1;
+
+ if (len > (&environment.data[ENV_SIZE] - env)) {
+ fprintf(stderr,
+ "Error: environment overflow, \"%s\" deleted\n",
+ name);
+ return -1;
+ }
+
+ /* Allocate enough place to the data string */
for (i = 2; i < argc; ++i) {
char *val = argv[i];
+ if (!value) {
+ value = (char *)malloc(len - strlen(name));
+ memset(value, 0, len - strlen(name));
+ tmpval = value;
+ }
+ if (i != 2)
+ *tmpval++ = ' ';
+ while (*val != '\0')
+ *tmpval++ = *val++;
+ }
+
+ fw_set_single_var(name, value);
- *env = (i == 2) ? '=' : ' ';
- while ((*++env = *val++) != '\0');
+ /*
+ * Update CRC
+ */
+ *environment.crc = crc32(0, (uint8_t *) environment.data, ENV_SIZE);
+
+ /* write environment back to flash */
+ if (flash_io(O_RDWR)) {
+ fprintf(stderr, "Error: can't write fw_env to flash\n");
+ return -1;
}
- /* end is marked with double '\0' */
- *++env = '\0';
+ if (value)
+ free(value);
+
+ return 0;
- WRITE_FLASH:
+}
+
+/*
+ * Deletes or sets multiple environment variables.
+ * Returns -1 and sets errno error codes:
+ * 0 - OK
+ * EINVAL - need at least 1 argument
+ * EROFS - certain variables ("ethaddr", "serial#") cannot be
+ * modified or deleted
+ *
+ */
+int fw_setenv_multiple(fw_env_list *list, int count)
+{
+
+ int i, ret;
+
+ if (env_init())
+ return -1;
+
+ for (i = 0; i < count; i++) {
+ ret = fw_set_single_var(list[i].name, list[i].value);
+ if (ret) {
+ fprintf(stderr, "Error: can't set %s to %s\n",
+ list[i].name, list[i].value);
+ return -1;
+ }
+ }
/*
* Update CRC
*/
- *environment.crc = crc32 (0, (uint8_t *) environment.data, ENV_SIZE);
+ *environment.crc = crc32(0, (uint8_t *) environment.data, ENV_SIZE);
/* write environment back to flash */
- if (flash_io (O_RDWR)) {
+ if (flash_io(O_RDWR)) {
fprintf (stderr, "Error: can't write fw_env to flash\n");
return -1;
}
return 0;
+
+}
+
+/*
+ * Parse script to generate list of variables to set
+ * The script file has a very simple format, as follows:
+ *
+ * Each line has a couple with name, value:
+ * variable_name<TAB>variable_value
+ *
+ * Both variable_name and variable_value are interpreted as strings.
+ * Any character after <TAB> and before ending \r\n is interpreted
+ * as variable's value (no comment allowed on these lines !)
+ *
+ * Comments are allowed if the first character in the line is #
+ *
+ * Returns -1 and sets errno error codes:
+ * 0 - OK
+ * -1 - Error
+ */
+int fw_parse_script(char *fname, fw_env_list *list, int count)
+{
+ FILE *fp;
+ int i = 0;
+ char dump[128];
+ char *name;
+ char *val;
+
+
+ fp = fopen(fname, "r");
+ if (fp == NULL)
+ return -1;
+
+ while (fgets(dump, sizeof(dump), fp)) {
+ /* Skip incomplete conversions and comment strings */
+ if (dump[0] == '#')
+ continue;
+
+ list[i].name[0] = '\0';
+ list[i].value[0] = '\0';
+
+ val = strtok(dump, "\r\n");
+ if (!val)
+ continue;
+
+ name = strtok(dump, "\t");
+ if (!name)
+ continue;
+
+ strncpy(list[i].name, name, sizeof(list[i].name) - 1);
+
+ val = strtok(NULL, "\t");
+ if (val)
+ strncpy(list[i].value, val, sizeof(list[i].value) - 1);
+
+ printf("name = %s value = %s\n", list[i].name, list[i].value);
+ i++;
+
+ if (i >= count)
+ return count;
+ }
+
+ return i;
}
/*
diff --git a/tools/env/fw_env.h b/tools/env/fw_env.h
index c04da54..bd494c0 100644
--- a/tools/env/fw_env.h
+++ b/tools/env/fw_env.h
@@ -47,8 +47,15 @@
"ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}::off; " \
"bootm"
+typedef struct {
+ char name[255];
+ char value[255];
+} fw_env_list;
+
extern int fw_printenv(int argc, char *argv[]);
extern char *fw_getenv (char *name);
extern int fw_setenv (int argc, char *argv[]);
+extern int fw_parse_script(char *fname, fw_env_list *list, int count);
+extern int fw_setenv_multiple(fw_env_list *list, int count);
extern unsigned long crc32 (unsigned long, const unsigned char *, unsigned);
diff --git a/tools/env/fw_env_main.c b/tools/env/fw_env_main.c
index 7f631c4..42a7168 100644
--- a/tools/env/fw_env_main.c
+++ b/tools/env/fw_env_main.c
@@ -42,16 +42,26 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <getopt.h>
#include "fw_env.h"
#define CMD_PRINTENV "fw_printenv"
#define CMD_SETENV "fw_setenv"
+#define MAX_SET_VARS 1024
+
+static struct option long_options[] = {
+ {"script", required_argument, NULL, 's'},
+ {NULL, 0, NULL, 0}
+};
int
main(int argc, char *argv[])
{
char *p;
char *cmdname = *argv;
+ char *script_file = NULL;
+ fw_env_list *list;
+ int c, count;
if ((p = strrchr (cmdname, '/')) != NULL) {
cmdname = p + 1;
@@ -65,9 +75,27 @@ main(int argc, char *argv[])
return (EXIT_SUCCESS);
} else if (strcmp(cmdname, CMD_SETENV) == 0) {
+ while ((c = getopt_long (argc, argv, "s:",
+ long_options, NULL)) != EOF) {
+ switch (c) {
+ case 's':
+ script_file = optarg;
+ break;
+ }
+ }
- if (fw_setenv (argc, argv) != 0)
- return (EXIT_FAILURE);
+ if (!script_file) {
+ if (fw_setenv(argc, argv) != 0)
+ return EXIT_FAILURE;
+ } else {
+ list = (fw_env_list *)malloc(MAX_SET_VARS *
+ sizeof(fw_env_list));
+ count = fw_parse_script(script_file,
+ list, MAX_SET_VARS);
+
+ if (fw_setenv_multiple(list, count) != 0)
+ return EXIT_FAILURE;
+ }
return (EXIT_SUCCESS);
--
1.6.3.3
More information about the U-Boot
mailing list