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>
This commit is contained in:
Stefano Babic 2010-05-24 12:08:16 +02:00 committed by Wolfgang Denk
parent 3746a5e65c
commit bd7b26f879
3 changed files with 289 additions and 53 deletions

271
tools/env/fw_env.c vendored
View file

@ -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++;
for (i = 2; i < argc; ++i) {
char *val = argv[i];
*env = (i == 2) ? '=' : ' ';
while ((*++env = *val++) != '\0');
}
*env = '=';
while ((*++env = *value++) != '\0')
;
/* end is marked with double '\0' */
*++env = '\0';
WRITE_FLASH:
return 0;
}
/*
* Update CRC
*/
*environment.crc = crc32 (0, (uint8_t *) environment.data, ENV_SIZE);
/*
* 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;
/* write environment back to flash */
if (flash_io (O_RDWR)) {
fprintf (stderr, "Error: can't write fw_env to flash\n");
if (argc < 2) {
errno = EINVAL;
return -1;
}
return 0;
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];
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++;
}
fw_env_write(name, value);
if (value)
free(value);
return fw_env_close();
}
/*
* 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;
}
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;

4
tools/env/fw_env.h vendored
View file

@ -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);

View file

@ -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;
}