summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefano Babic <sbabic@denx.de>2010-05-24 12:08:16 +0200
committerWolfgang Denk <wd@denx.de>2010-06-29 22:43:27 +0200
commitbd7b26f879413aa5a662718c09dab65d3a24a201 (patch)
treec8f9939fac2b3c1da7aae7604bedc1d344d5191e
parent3746a5e65ceeccf7e766df6263d2994b9abcc60e (diff)
downloadu-boot-imx-bd7b26f879413aa5a662718c09dab65d3a24a201.zip
u-boot-imx-bd7b26f879413aa5a662718c09dab65d3a24a201.tar.gz
u-boot-imx-bd7b26f879413aa5a662718c09dab65d3a24a201.tar.bz2
Tools: set multiple variable with fw_setenv utility
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@denx.de>
-rw-r--r--tools/env/fw_env.c269
-rw-r--r--tools/env/fw_env.h4
-rw-r--r--tools/env/fw_env_main.c67
3 files changed, 288 insertions, 52 deletions
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index a46205d..04f3bf0 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -45,8 +45,7 @@
#include "fw_env.h"
-#define CMD_GETENV "fw_printenv"
-#define CMD_SETENV "fw_setenv"
+#define WHITESPACE(c) ((c == '\t') || (c == ' '))
#define min(x, y) ({ \
typeof(x) _min1 = (x); \
@@ -210,7 +209,6 @@ static char default_environment[] = {
static int flash_io (int mode);
static char *envmatch (char * s1, char * s2);
-static int env_init (void);
static int parse_config (void);
#if defined(CONFIG_FILE)
@@ -225,6 +223,22 @@ static inline ulong getenvsize (void)
return rc;
}
+static char *fw_string_blank(char *s, int noblank)
+{
+ int i;
+ int len = strlen(s);
+
+ for (i = 0; i < len; i++, s++) {
+ if ((noblank && !WHITESPACE(*s)) ||
+ (!noblank && WHITESPACE(*s)))
+ break;
+ }
+ if (i == len)
+ return NULL;
+
+ return s;
+}
+
/*
* Search the environment for a variable.
* Return the value, if found, or NULL, if not found.
@@ -233,7 +247,7 @@ char *fw_getenv (char *name)
{
char *env, *nxt;
- if (env_init ())
+ if (fw_env_open())
return NULL;
for (env = environment.data; *env; env = nxt + 1) {
@@ -264,7 +278,7 @@ int fw_printenv (int argc, char *argv[])
int i, n_flag;
int rc = 0;
- if (env_init ())
+ if (fw_env_open())
return -1;
if (argc == 1) { /* Print all env variables */
@@ -327,30 +341,34 @@ int fw_printenv (int argc, char *argv[])
return rc;
}
-/*
- * 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 fw_env_close(void)
{
- int i, len;
- char *env, *nxt;
- char *oldval = NULL;
- char *name;
+ /*
+ * Update CRC
+ */
+ *environment.crc = crc32(0, (uint8_t *) environment.data, ENV_SIZE);
- if (argc < 2) {
- errno = EINVAL;
- return -1;
+ /* write environment back to flash */
+ if (flash_io(O_RDWR)) {
+ fprintf(stderr,
+ "Error: can't write fw_env to flash\n");
+ return -1;
}
- if (env_init ())
- return -1;
+ return 0;
+}
- name = argv[1];
+
+/*
+ * 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_env_write(char *name, char *value)
+{
+ int len;
+ char *env, *nxt;
+ char *oldval = NULL;
/*
* search if variable with this name already exists
@@ -358,7 +376,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 +414,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 +429,202 @@ 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 *name;
+ char *value = NULL;
+ char *tmpval = NULL;
+
+ if (argc < 2) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (fw_env_open()) {
+ fprintf(stderr, "Error: environment not initialized\n");
+ return -1;
+ }
+
+ name = argv[1];
+
+ len = strlen(name) + 2;
+ for (i = 2; i < argc; ++i)
+ len += strlen(argv[i]) + 1;
+
+ /* Allocate enough place to the data string */
for (i = 2; i < argc; ++i) {
char *val = argv[i];
-
- *env = (i == 2) ? '=' : ' ';
- while ((*++env = *val++) != '\0');
+ if (!value) {
+ value = (char *)malloc(len - strlen(name));
+ if (!value) {
+ fprintf(stderr,
+ "Cannot malloc %u bytes: %s\n",
+ len - strlen(name), strerror(errno));
+ return -1;
+ }
+ memset(value, 0, len - strlen(name));
+ tmpval = value;
+ }
+ if (i != 2)
+ *tmpval++ = ' ';
+ while (*val != '\0')
+ *tmpval++ = *val++;
}
- /* end is marked with double '\0' */
- *++env = '\0';
+ fw_env_write(name, value);
- WRITE_FLASH:
+ if (value)
+ free(value);
- /*
- * Update CRC
- */
- *environment.crc = crc32 (0, (uint8_t *) environment.data, ENV_SIZE);
+ return fw_env_close();
+}
- /* write environment back to flash */
- if (flash_io (O_RDWR)) {
- fprintf (stderr, "Error: can't write fw_env to flash\n");
+/*
+ * Parse a file and configure the u-boot variables.
+ * The script file has a very simple format, as follows:
+ *
+ * Each line has a couple with name, value:
+ * <white spaces>variable_name<white spaces>variable_value
+ *
+ * Both variable_name and variable_value are interpreted as strings.
+ * Any character after <white spaces> 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)
+{
+ FILE *fp;
+ char dump[1024]; /* Maximum line length in the file */
+ char *name;
+ char *val;
+ int lineno = 0;
+ int len;
+ int ret = 0;
+
+ if (fw_env_open()) {
+ fprintf(stderr, "Error: environment not initialized\n");
return -1;
}
- return 0;
+ if (strcmp(fname, "-") == 0)
+ fp = stdin;
+ else {
+ fp = fopen(fname, "r");
+ if (fp == NULL) {
+ fprintf(stderr, "I cannot open %s for reading\n",
+ fname);
+ return -1;
+ }
+ }
+
+ while (fgets(dump, sizeof(dump), fp)) {
+ lineno++;
+ len = strlen(dump);
+
+ /*
+ * Read a whole line from the file. If the line is too long
+ * or is not terminated, reports an error and exit.
+ */
+ if (dump[len - 1] != '\n') {
+ fprintf(stderr,
+ "Line %d not corrected terminated or too long\n",
+ lineno);
+ ret = -1;
+ break;
+ }
+
+ /* Drop ending line feed / carriage return */
+ while (len > 0 && (dump[len - 1] == '\n' ||
+ dump[len - 1] == '\r')) {
+ dump[len - 1] = '\0';
+ len--;
+ }
+
+ /* Skip comment or empty lines */
+ if ((len == 0) || dump[0] == '#')
+ continue;
+
+ /*
+ * Search for variable's name,
+ * remove leading whitespaces
+ */
+ name = fw_string_blank(dump, 1);
+ if (!name)
+ continue;
+
+ /* The first white space is the end of variable name */
+ val = fw_string_blank(name, 0);
+ len = strlen(name);
+ if (val) {
+ *val++ = '\0';
+ if ((val - name) < len)
+ val = fw_string_blank(val, 1);
+ else
+ val = NULL;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "Setting %s : %s\n",
+ name, val ? val : " removed");
+#endif
+
+ /*
+ * If there is an error setting a variable,
+ * try to save the environment and returns an error
+ */
+ if (fw_env_write(name, val)) {
+ fprintf(stderr,
+ "fw_env_write returns with error : %s\n",
+ strerror(errno));
+ ret = -1;
+ break;
+ }
+
+ }
+
+ /* Close file if not stdin */
+ if (strcmp(fname, "-") != 0)
+ fclose(fp);
+
+ ret |= fw_env_close();
+
+ return ret;
+
}
/*
@@ -880,7 +1059,7 @@ static char *envmatch (char * s1, char * s2)
/*
* Prevent confusion if running from erased flash memory
*/
-static int env_init (void)
+int fw_env_open(void)
{
int crc0, crc0_ok;
char flag0;
diff --git a/tools/env/fw_env.h b/tools/env/fw_env.h
index c04da54..8130fa1 100644
--- a/tools/env/fw_env.h
+++ b/tools/env/fw_env.h
@@ -50,5 +50,9 @@
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);
+extern int fw_env_open(void);
+extern int fw_env_write(char *name, char *value);
+extern int fw_env_close(void);
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..82116b4 100644
--- a/tools/env/fw_env_main.c
+++ b/tools/env/fw_env_main.c
@@ -42,34 +42,87 @@
#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"
+static struct option long_options[] = {
+ {"script", required_argument, NULL, 's'},
+ {"help", no_argument, NULL, 'h'},
+ {NULL, 0, NULL, 0}
+};
+
+void usage(void)
+{
+
+ fprintf(stderr, "fw_printenv/fw_setenv, "
+ "a command line interface to U-Boot environment\n\n"
+ "usage:\tfw_printenv\n"
+ "\tfw_setenv [variable name] [variable value]\n"
+ "\tfw_setenv -s [ file ]\n"
+ "\tfw_setenv -s - < [ file ]\n\n"
+ "The file passed as argument contains only pairs "
+ "name / value\n"
+ "Example:\n"
+ "# Any line starting with # is treated as comment\n"
+ "\n"
+ "\t netdev eth0\n"
+ "\t kernel_addr 400000\n"
+ "\t var1\n"
+ "\t var2 The quick brown fox jumps over the "
+ "lazy dog\n"
+ "\n"
+ "A variable without value will be dropped. It is possible\n"
+ "to put any number of spaces between the fields, but any\n"
+ "space inside the value is treated as part of the value "
+ "itself.\n\n"
+ );
+}
+
int
main(int argc, char *argv[])
{
char *p;
char *cmdname = *argv;
+ char *script_file = NULL;
+ int c;
if ((p = strrchr (cmdname, '/')) != NULL) {
cmdname = p + 1;
}
+ while ((c = getopt_long (argc, argv, "s:h",
+ long_options, NULL)) != EOF) {
+ switch (c) {
+ case 's':
+ script_file = optarg;
+ break;
+ case 'h':
+ usage();
+ return EXIT_SUCCESS;
+ }
+ }
+
+
if (strcmp(cmdname, CMD_PRINTENV) == 0) {
if (fw_printenv (argc, argv) != 0)
- return (EXIT_FAILURE);
+ return EXIT_FAILURE;
- return (EXIT_SUCCESS);
+ return EXIT_SUCCESS;
} else if (strcmp(cmdname, CMD_SETENV) == 0) {
+ if (!script_file) {
+ if (fw_setenv(argc, argv) != 0)
+ return EXIT_FAILURE;
+ } else {
+ if (fw_parse_script(script_file) != 0)
+ return EXIT_FAILURE;
+ }
- if (fw_setenv (argc, argv) != 0)
- return (EXIT_FAILURE);
-
- return (EXIT_SUCCESS);
+ return EXIT_SUCCESS;
}
@@ -77,5 +130,5 @@ main(int argc, char *argv[])
"Identity crisis - may be called as `" CMD_PRINTENV
"' or as `" CMD_SETENV "' but not as `%s'\n",
cmdname);
- return (EXIT_FAILURE);
+ return EXIT_FAILURE;
}