mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-25 06:00:43 +00:00
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:
parent
3746a5e65c
commit
bd7b26f879
3 changed files with 289 additions and 53 deletions
271
tools/env/fw_env.c
vendored
271
tools/env/fw_env.c
vendored
|
@ -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
4
tools/env/fw_env.h
vendored
|
@ -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);
|
||||
|
|
67
tools/env/fw_env_main.c
vendored
67
tools/env/fw_env_main.c
vendored
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue