[U-Boot] [RFC] env: Group environment variables

John Schmoller
2009-11-04T16:34:12Z

This patch groups environment variables using a non-invasive protocol.
Grouping is achieved by setting a "grouping" variable to a string of
variables, and setting the master grouping variable, "env_groups" to
the list of these grouping variables.

For instance,
setenv net ipaddr netmask gatewayip serverip
setenv boot bootcmd bootdelay bootargs
setenv env_groups net boot

would print 4 variables grouped under net, 3 variables grouped under
boot, and the rest of the variables grouped under "other". If env_groups
is not defined, print behaves normally.

Signed-off-by: John Schmoller <jschmoller@xes-inc.com>
---
I'm interesetd in seeing peoples opinions of this implementation of grouping
environment variables. My major concerns about this implementation are

1) Using parse_line() requires placing several potentially large char array
(CONFIG_SYS_CBSIZE in size) on the stack. Parse_line() does seem to be the
right tool for the job, though.

2) Trying to figure out which enviroment variables have already been printed
in groups is less than elegant. Currently, it's a brute-force approach of
looking through every entry until a variable is found in a group or not.
Suggestions for cleaner algorithms here would be appreciated.

Implementation notes:
If env_groups is defined, none of the grouping variables will be printed.
This seemed to clutter up the printenv output.

Grouping environment variables will almost certainly lead to a reqirement for
bumping up CONFIG_SYS_MAXARGS.

Example output:
=> printenv
=== pci variables ===
pci1inboundmembus=0x00000000
pci1inboundmemphys=0x00000000
pci1inboundmemsize=0x08000000
pci1outboundmembus=0x80000000
pci1outboundmemphys=0x80000000
pci1outboundmemsize=0x40000000
pci1outboundiobus=0x00000000
pci1outboundiophys=0xe8000000
pci1outboundiosize=0x00800000
pci2outboundmembus=0xc0000000
pci2outboundmemphys=0xc0000000
pci2outboundmemsize=0x10000000

=== boot variables ===
bootcmd_flash1=run set_bootargs; bootm 0xfef00000 - 0xfff00000
bootcmd_flash2=run set_bootargs; bootm 0xf6f00000 - 0xf7f00000
bootcmd=tftp 10000000 home/jschmoller/vxWorks.st;bootvx
bootdelay=3
bootfile=/home/shared/pxe/pxelinux.0
bootcmd_net=run set_bootargs; $download_cmd $osaddr $osfile; if test $? -eq 0; then if test -n $fdtaddr; then $download_cmd $fdtaddr $fdtfile; if test $? -eq 0; then bootm $osaddr - $fdtaddr; else; echo FDT DOWNLOAD FAILED; fi; else; bootm $osaddr; fi; else; echo OS DOWNLOAD FAILED; fi;

=== prog variables ===
prog_uboot1=$download_cmd $loadaddr $ubootfile; if test $? -eq 0; then protect off 0xfff80000 +80000; erase 0xfff80000 +80000; cp.w $loadaddr 0xfff80000 40000; protect on 0xfff80000 +80000; cmp.b $loadaddr 0xfff80000 80000; if test $? -ne 0; then echo PROGRAM FAILED; else; echo PROGRAM SUCCEEDED; fi; else; echo DOWNLOAD FAILED; fi;
prog_uboot2=$download_cmd $loadaddr $ubootfile; if test $? -eq 0; then protect off 0xf7f80000 +80000; erase 0xf7f80000 +80000; cp.w $loadaddr 0xf7f80000 40000; protect on 0xf7f80000 +80000; cmp.b $loadaddr 0xf7f80000 80000; if test $? -ne 0; then echo PROGRAM FAILED; else; echo PROGRAM SUCCEEDED; fi; else; echo DOWNLOAD FAILED; fi;
ubootfile=home/jschmoller/u-boot.bin
prog_os1=$download_cmd $osaddr $osfile; if test $? -eq 0; then erase 0xfef00000 +$filesize; cp.b $osaddr 0xfef00000 $filesize; cmp.b $osaddr 0xfef00000 $filesize; if test $? -ne 0; then echo OS PROGRAM FAILED; else; echo OS PROGRAM SUCCEEDED; fi; else; echo OS DOWNLOAD FAILED; fi;
prog_os2=$download_cmd $osaddr $osfile; if test $? -eq 0; then erase 0xf6f00000 +$filesize; cp.b $osaddr 0xf6f00000 $filesize; cmp.b $osaddr 0xf6f00000 $filesize; if test $? -ne 0; then echo OS PROGRAM FAILED; else; echo OS PROGRAM SUCCEEDED; fi; else; echo OS DOWNLOAD FAILED; fi;
osfile=/home/user/board.uImage
osaddr=0x1000000
prog_fdt1=$download_cmd $fdtaddr $fdtfile; if test $? -eq 0; then erase 0xfff00000 +$filesize;cp.b $fdtaddr 0xfff00000 $filesize; cmp.b $fdtaddr 0xfff00000 $filesize; if test $? -ne 0; then echo FDT PROGRAM FAILED; else; echo FDT PROGRAM SUCCEEDED; fi; else; echo FDT DOWNLOAD FAILED; fi;
prog_fdt2=$download_cmd $fdtaddr $fdtfile; if test $? -eq 0; then erase 0xf7f00000 +$filesize;cp.b $fdtaddr 0xf7f00000 $filesize; cmp.b $fdtaddr 0xf7f00000 $filesize; if test $? -ne 0; then echo FDT PROGRAM FAILED; else; echo FDT PROGRAM SUCCEEDED; fi; else; echo FDT DOWNLOAD FAILED; fi;
fdtfile=/home/user/board.dtb
fdtaddr=c00000

=== net variables ===
## Error: "ipaddr" not defined
netmask=255.255.0.0
serverip=10.52.0.33
gatewayip=10.52.0.1
ethaddr=00:17:3c:00:5f:30
ethact=eTSEC1

=== board variables ===
serial#=02091009
board_cfg=90030065B-1
board_rev=SB

=== junk variables ===
## Error: group "junk" not defined

=== other variables ===
baudrate=115200
loads_echo=1
preboot=
autoload=yes
download_cmd=tftp
console_args=console=ttyS0,115200
root_args=root=/dev/nfs rw
misc_args=ip=on
set_bootargs=setenv bootargs ${console_args} ${root_args} ${misc_args}
loadaddr=0x1000000
pci2outboundiobus=0x00000000
pci2outboundiophys=0xe8800000
pci2outboundiosize=0x00800000
eth1addr=00:17:3c:00:5f:31
dnsip=10.52.0.1
skip_nand_bbt=yes
pcidelay=1000
loadaddr=100000
bootargs=motetsec(0,0)host:/home/mstarzewski/xes8572-vxWorks.st h=10.52.0.33 e=10.52.143.154:ffff0000 u=drives pw=drives f=0x0
filesize=869D2
fileaddr=10000000
stdin=serial
stdout=serial
stderr=serial

Environment size: 4148/32764 bytes
=>

common/cmd_nvedit.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 110 insertions(+), 10 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index eb89e9e..6420e17 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -71,6 +71,54 @@ SPI_FLASH|MG_DISK|NVRAM|NOWHERE}
#define XMK_STR(x) #x
#define MK_STR(x) XMK_STR(x)

+enum {
+ PRINTENV_STATE_MATCHED = 0,
+ PRINTENV_STATE_ALL,
+ PRINTENV_STATE_SEARCH,
+ PRINTENV_STATE_GROUP
+};
+
+static int env_in_group(char *env)
+{
+ char *s;
+ char group_buf[CONFIG_SYS_CBSIZE];
+ char *group_argv[CONFIG_SYS_MAXARGS + 1];
+ int group_argc;
+ char env_buf[CONFIG_SYS_CBSIZE];
+ char *env_argv[CONFIG_SYS_MAXARGS + 1];
+ int env_argc;
+ int i, j;
+
+ if (strcmp("env_groups", env) == 0)
+ return 1;
+
+ if ((s = getenv("env_groups")) == NULL)
+ return 0;
+
+ strcpy(group_buf, s);
+ group_argc = parse_line(group_buf, group_argv);
+
+ /* Spin through all group variables specified in "env_groups" */
+ for (i = 0; i < group_argc; i++) {
+ if ((s = getenv(group_argv[i])) == NULL)
+ continue;
+
+ if (strcmp(group_argv[i], env) == 0)
+ return 1;
+
+ strcpy(env_buf, s);
+ env_argc = parse_line(env_buf, env_argv);
+
+ /* Spin through all vars contained in each group variable */
+ for (j = 0; j < env_argc; j++) {
+ if (strcmp(env_argv[j], env) == 0)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
/************************************************************************
************************************************************************/

@@ -101,30 +149,48 @@ int get_env_id (void)
* state 0: finish printing this string and return (matched!)
* state 1: no matching to be done; print everything
* state 2: continue searching for matched name
+ * state 3: print all only if not found in a group
*/
static int printenv(char *name, int state)
{
- int i, j;
- char c, buf[17];
+ int i, j, prev_state, size;
+ char c, buf[17], *str, *addr;

i = 0;
buf[16] = '\0';
+ prev_state = state;

while (state && env_get_char(i) != '\0') {
- if (state == 2 && envmatch((uchar *)name, i) >= 0)
- state = 0;
+ if (state == PRINTENV_STATE_SEARCH &&
+ envmatch((uchar *)name, i) >= 0)
+ state = PRINTENV_STATE_MATCHED;
+
+ if (prev_state == PRINTENV_STATE_GROUP) {
+ addr = (char *)env_get_addr(i);
+ size = strchr(addr, '=') - addr;
+ str = malloc((size + 1) * sizeof(char));
+ strncpy(str, addr, size);
+ str[size] = '\0';
+
+ if (env_in_group(str))
+ state = PRINTENV_STATE_SEARCH;
+ else
+ state = PRINTENV_STATE_ALL;
+
+ free(str);
+ }

j = 0;
do {
buf[j++] = c = env_get_char(i++);
if (j == sizeof(buf) - 1) {
- if (state <= 1)
+ if (state != PRINTENV_STATE_SEARCH)
puts(buf);
j = 0;
}
} while (c != '\0');

- if (state <= 1) {
+ if (state != PRINTENV_STATE_SEARCH) {
if (j)
puts(buf);
putc('\n');
@@ -134,7 +200,7 @@ static int printenv(char *name, int state)
return -1;
}

- if (state == 0)
+ if (state == PRINTENV_STATE_MATCHED)
i = 0;
return i;
}
@@ -143,10 +209,44 @@ int do_printenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
int i;
int rcode = 0;
+ char *s;
+ char group_buf[CONFIG_SYS_CBSIZE];
+ char *group_argv[CONFIG_SYS_MAXARGS + 1];
+ int group_argc;
+ char env_buf[CONFIG_SYS_CBSIZE];
+ char *env_argv[CONFIG_SYS_MAXARGS + 1];
+ int env_argc;

if (argc == 1) {
- /* print all env vars */
- rcode = printenv(NULL, 1);
+ if ((s = getenv("env_groups")) == NULL) {
+ /* print all env vars */
+ rcode = printenv(NULL, PRINTENV_STATE_ALL);
+ } else {
+ /* print all env vars, but group them */
+ strcpy(group_buf, s);
+ group_argc = parse_line(group_buf, group_argv);
+
+ /* Cycle through all the groups in env_groups */
+ for (i = 0; i < group_argc; i++) {
+ printf("=== %s variables ===\n", group_argv[i]);
+ if ((s = getenv(group_argv[i])) == NULL) {
+ printf("## Error: group \"%s",
+ group_argv[i]);
+ printf("\" not defined\n\n");
+ continue;
+ }
+
+ /* Recursively call printenv for each group */
+ sprintf(env_buf, "printenv %s", s);
+ env_argc = parse_line(env_buf, env_argv);
+ do_printenv(cmdtp, flag, env_argc, env_argv);
+ putc('\n');
+ }
+
+ puts("=== other variables ===\n");
+ rcode = printenv(NULL, PRINTENV_STATE_GROUP);
+ }
+
if (rcode < 0)
return 1;
printf("\nEnvironment size: %d/%ld bytes\n",
@@ -157,7 +257,7 @@ int do_printenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
/* print selected env vars */
for (i = 1; i < argc; ++i) {
char *name = argv[i];
- if (printenv(name, 2)) {
+ if (printenv(name, PRINTENV_STATE_SEARCH)) {
printf("## Error: \"%s\" not defined\n", name);
++rcode;
}
--
1.6.0.4