diff options
Diffstat (limited to 'tools/env')
| -rw-r--r-- | tools/env/fw_env.c | 269 | ||||
| -rw-r--r-- | tools/env/fw_env.h | 4 | ||||
| -rw-r--r-- | tools/env/fw_env_main.c | 67 | 
3 files changed, 288 insertions, 52 deletions
| diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c index a46205d86..04f3bf0a4 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 c04da541f..8130fa150 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 7f631c449..82116b4b2 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;  } |