nvedit.c 30.1 KB
Newer Older
W
wdenk 已提交
1
/*
2
 * (C) Copyright 2000-2013
W
wdenk 已提交
3 4 5 6
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 *
 * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
 * Andreas Heppel <aheppel@sysgo.de>
K
Kim Phillips 已提交
7 8 9
 *
 * Copyright 2011 Freescale Semiconductor, Inc.
 *
10
 * SPDX-License-Identifier:	GPL-2.0+
W
wdenk 已提交
11 12
 */

13
/*
W
wdenk 已提交
14 15
 * Support for persistent environment data
 *
16 17
 * The "environment" is stored on external storage as a list of '\0'
 * terminated "name=value" strings. The end of the list is marked by
18
 * a double '\0'. The environment is preceded by a 32 bit CRC over
19 20
 * the data part and, in case of redundant environment, a byte of
 * flags.
W
wdenk 已提交
21
 *
22 23 24
 * This linearized representation will also be used before
 * relocation, i. e. as long as we don't have a full C runtime
 * environment. After that, we use a hash table.
W
wdenk 已提交
25 26 27
 */

#include <common.h>
28
#include <cli.h>
W
wdenk 已提交
29
#include <command.h>
30
#include <console.h>
W
wdenk 已提交
31
#include <environment.h>
32 33
#include <search.h>
#include <errno.h>
P
Peter Tyser 已提交
34
#include <malloc.h>
35
#include <mapmem.h>
36
#include <watchdog.h>
W
wdenk 已提交
37 38
#include <linux/stddef.h>
#include <asm/byteorder.h>
39
#include <asm/io.h>
W
wdenk 已提交
40

41 42
DECLARE_GLOBAL_DATA_PTR;

43 44 45 46
#if	!defined(CONFIG_ENV_IS_IN_EEPROM)	&& \
	!defined(CONFIG_ENV_IS_IN_FLASH)	&& \
	!defined(CONFIG_ENV_IS_IN_DATAFLASH)	&& \
	!defined(CONFIG_ENV_IS_IN_MMC)		&& \
47
	!defined(CONFIG_ENV_IS_IN_FAT)		&& \
48
	!defined(CONFIG_ENV_IS_IN_EXT4)		&& \
49 50 51
	!defined(CONFIG_ENV_IS_IN_NAND)		&& \
	!defined(CONFIG_ENV_IS_IN_NVRAM)	&& \
	!defined(CONFIG_ENV_IS_IN_ONENAND)	&& \
P
Peng Fan 已提交
52
	!defined(CONFIG_ENV_IS_IN_SATA)		&& \
53
	!defined(CONFIG_ENV_IS_IN_SPI_FLASH)	&& \
54
	!defined(CONFIG_ENV_IS_IN_REMOTE)	&& \
55
	!defined(CONFIG_ENV_IS_IN_UBI)		&& \
56
	!defined(CONFIG_ENV_IS_NOWHERE)
U
unsik Kim 已提交
57
# error Define one of CONFIG_ENV_IS_IN_{EEPROM|FLASH|DATAFLASH|ONENAND|\
P
Peng Fan 已提交
58
SATA|SPI_FLASH|NVRAM|MMC|FAT|EXT4|REMOTE|UBI} or CONFIG_ENV_IS_NOWHERE
W
wdenk 已提交
59 60
#endif

61 62 63 64
/*
 * Maximum expected input data size for import command
 */
#define	MAX_ENV_SIZE	(1 << 20)	/* 1 MiB */
W
wdenk 已提交
65

H
Heiko Schocher 已提交
66
/*
67
 * This variable is incremented on each do_env_set(), so it can
H
Heiko Schocher 已提交
68 69 70 71 72
 * be used via get_env_id() as an indication, if the environment
 * has changed or not. So it is possible to reread an environment
 * variable only if the environment was changed ... done so for
 * example in NetInitLoop()
 */
H
Heiko Schocher 已提交
73
static int env_id = 1;
W
wdenk 已提交
74

75
int get_env_id(void)
H
Heiko Schocher 已提交
76 77 78
{
	return env_id;
}
W
wdenk 已提交
79

I
Ilya Yanok 已提交
80
#ifndef CONFIG_SPL_BUILD
81
/*
82 83 84
 * Command interface: print one or all environment variables
 *
 * Returns 0 in case of error, or length of printed string
85
 */
86
static int env_print(char *name, int flag)
W
wdenk 已提交
87
{
88
	char *res = NULL;
89
	ssize_t len;
90 91 92 93 94 95

	if (name) {		/* print a single name */
		ENTRY e, *ep;

		e.key = name;
		e.data = NULL;
96
		hsearch_r(e, FIND, &ep, &env_htab, flag);
97 98
		if (ep == NULL)
			return 0;
99
		len = printf("%s=%s\n", ep->key, ep->data);
100 101
		return len;
	}
W
wdenk 已提交
102

103
	/* print whole list */
104
	len = hexport_r(&env_htab, '\n', flag, &res, 0, 0, NULL);
W
wdenk 已提交
105

106 107 108 109
	if (len > 0) {
		puts(res);
		free(res);
		return len;
W
wdenk 已提交
110 111
	}

112
	/* should never happen */
113
	printf("## Error: cannot export environment\n");
114
	return 0;
115
}
W
wdenk 已提交
116

K
Kim Phillips 已提交
117 118
static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc,
			char * const argv[])
119 120 121
{
	int i;
	int rcode = 0;
122 123 124 125 126 127 128
	int env_flag = H_HIDE_DOT;

	if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'a') {
		argc--;
		argv++;
		env_flag &= ~H_HIDE_DOT;
	}
W
wdenk 已提交
129

130 131
	if (argc == 1) {
		/* print all env vars */
132
		rcode = env_print(NULL, env_flag);
133
		if (!rcode)
134 135 136 137 138
			return 1;
		printf("\nEnvironment size: %d/%ld bytes\n",
			rcode, (ulong)ENV_SIZE);
		return 0;
	}
W
wdenk 已提交
139

140
	/* print selected env vars */
141
	env_flag &= ~H_HIDE_DOT;
142
	for (i = 1; i < argc; ++i) {
143
		int rc = env_print(argv[i], env_flag);
144 145
		if (!rc) {
			printf("## Error: \"%s\" not defined\n", argv[i]);
146
			++rcode;
W
wdenk 已提交
147 148
		}
	}
149

W
wdenk 已提交
150 151 152
	return rcode;
}

K
Kim Phillips 已提交
153
#ifdef CONFIG_CMD_GREPENV
154 155
static int do_env_grep(cmd_tbl_t *cmdtp, int flag,
		       int argc, char * const argv[])
K
Kim Phillips 已提交
156
{
157
	char *res = NULL;
158
	int len, grep_how, grep_what;
K
Kim Phillips 已提交
159 160

	if (argc < 2)
161
		return CMD_RET_USAGE;
K
Kim Phillips 已提交
162

163 164
	grep_how  = H_MATCH_SUBSTR;	/* default: substring search	*/
	grep_what = H_MATCH_BOTH;	/* default: grep names and values */
165

P
Pierre Aubert 已提交
166 167
	while (--argc > 0 && **++argv == '-') {
		char *arg = *argv;
168 169
		while (*++arg) {
			switch (*arg) {
170 171 172 173 174
#ifdef CONFIG_REGEX
			case 'e':		/* use regex matching */
				grep_how  = H_MATCH_REGEX;
				break;
#endif
175
			case 'n':		/* grep for name */
176
				grep_what = H_MATCH_KEY;
177 178
				break;
			case 'v':		/* grep for value */
179
				grep_what = H_MATCH_DATA;
180 181
				break;
			case 'b':		/* grep for both */
182
				grep_what = H_MATCH_BOTH;
183 184 185 186 187 188 189 190 191 192
				break;
			case '-':
				goto DONE;
			default:
				return CMD_RET_USAGE;
			}
		}
	}

DONE:
193
	len = hexport_r(&env_htab, '\n',
194
			flag | grep_what | grep_how,
195
			&res, 0, argc, argv);
K
Kim Phillips 已提交
196

197 198 199
	if (len > 0) {
		puts(res);
		free(res);
K
Kim Phillips 已提交
200 201
	}

202 203 204 205
	if (len < 2)
		return 1;

	return 0;
K
Kim Phillips 已提交
206 207
}
#endif
I
Ilya Yanok 已提交
208
#endif /* CONFIG_SPL_BUILD */
K
Kim Phillips 已提交
209

210 211 212
/*
 * Set a new environment variable,
 * or replace or delete an existing one.
213
 */
214
static int _do_env_set(int flag, int argc, char * const argv[], int env_flag)
215 216 217 218 219
{
	int   i, len;
	char  *name, *value, *s;
	ENTRY e, *ep;

J
Joe Hershberger 已提交
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
	debug("Initial value for argc=%d\n", argc);
	while (argc > 1 && **(argv + 1) == '-') {
		char *arg = *++argv;

		--argc;
		while (*++arg) {
			switch (*arg) {
			case 'f':		/* force */
				env_flag |= H_FORCE;
				break;
			default:
				return CMD_RET_USAGE;
			}
		}
	}
	debug("Final value for argc=%d\n", argc);
236 237 238 239 240 241 242 243 244 245
	name = argv[1];

	if (strchr(name, '=')) {
		printf("## Error: illegal character '='"
		       "in variable name \"%s\"\n", name);
		return 1;
	}

	env_id++;

W
wdenk 已提交
246
	/* Delete only ? */
247
	if (argc < 3 || argv[2] == NULL) {
J
Joe Hershberger 已提交
248
		int rc = hdelete_r(name, &env_htab, env_flag);
249
		return !rc;
W
wdenk 已提交
250 251 252
	}

	/*
253
	 * Insert / replace new value
W
wdenk 已提交
254
	 */
255
	for (i = 2, len = 0; i < argc; ++i)
W
wdenk 已提交
256
		len += strlen(argv[i]) + 1;
257 258 259

	value = malloc(len);
	if (value == NULL) {
260
		printf("## Can't malloc %d bytes\n", len);
W
wdenk 已提交
261 262
		return 1;
	}
263
	for (i = 2, s = value; i < argc; ++i) {
264
		char *v = argv[i];
W
wdenk 已提交
265

266
		while ((*s++ = *v++) != '\0')
W
wdenk 已提交
267
			;
268
		*(s - 1) = ' ';
269 270 271 272
	}
	if (s != value)
		*--s = '\0';

273 274
	e.key	= name;
	e.data	= value;
J
Joe Hershberger 已提交
275
	hsearch_r(e, ENTER, &ep, &env_htab, env_flag);
276 277 278 279 280
	free(value);
	if (!ep) {
		printf("## Error inserting \"%s\" variable, errno=%d\n",
			name, errno);
		return 1;
W
wdenk 已提交
281 282 283 284 285
	}

	return 0;
}

286
int setenv(const char *varname, const char *varvalue)
W
wdenk 已提交
287
{
288 289
	const char * const argv[4] = { "setenv", varname, varvalue, NULL };

290 291 292 293
	/* before import into hashtable */
	if (!(gd->flags & GD_FLG_ENV_READY))
		return 1;

294
	if (varvalue == NULL || varvalue[0] == '\0')
295
		return _do_env_set(0, 2, (char * const *)argv, H_PROGRAMMATIC);
296
	else
297
		return _do_env_set(0, 3, (char * const *)argv, H_PROGRAMMATIC);
W
wdenk 已提交
298 299
}

S
Simon Glass 已提交
300 301 302
/**
 * Set an environment variable to an integer value
 *
303
 * @param varname	Environment variable to set
S
Simon Glass 已提交
304 305 306 307 308 309 310 311 312 313 314 315
 * @param value		Value to set it to
 * @return 0 if ok, 1 on error
 */
int setenv_ulong(const char *varname, ulong value)
{
	/* TODO: this should be unsigned */
	char *str = simple_itoa(value);

	return setenv(varname, str);
}

/**
316
 * Set an environment variable to an value in hex
S
Simon Glass 已提交
317
 *
318
 * @param varname	Environment variable to set
319
 * @param value		Value to set it to
S
Simon Glass 已提交
320 321
 * @return 0 if ok, 1 on error
 */
322
int setenv_hex(const char *varname, ulong value)
S
Simon Glass 已提交
323 324 325
{
	char str[17];

326
	sprintf(str, "%lx", value);
S
Simon Glass 已提交
327 328 329
	return setenv(varname, str);
}

330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
ulong getenv_hex(const char *varname, ulong default_val)
{
	const char *s;
	ulong value;
	char *endp;

	s = getenv(varname);
	if (s)
		value = simple_strtoul(s, &endp, 16);
	if (!s || endp == s)
		return default_val;

	return value;
}

I
Ilya Yanok 已提交
345
#ifndef CONFIG_SPL_BUILD
K
Kim Phillips 已提交
346
static int do_env_set(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
W
wdenk 已提交
347
{
348
	if (argc < 2)
349
		return CMD_RET_USAGE;
W
wdenk 已提交
350

351
	return _do_env_set(flag, argc, argv, H_INTERACTIVE);
W
wdenk 已提交
352 353
}

354
/*
W
wdenk 已提交
355 356
 * Prompt for environment variable
 */
357
#if defined(CONFIG_CMD_ASKENV)
358
int do_env_ask(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
W
wdenk 已提交
359
{
360
	char message[CONFIG_SYS_CBSIZE];
W
Wolfgang Denk 已提交
361
	int i, len, pos, size;
W
wdenk 已提交
362
	char *local_args[4];
W
Wolfgang Denk 已提交
363
	char *endptr;
W
wdenk 已提交
364 365 366 367 368 369

	local_args[0] = argv[0];
	local_args[1] = argv[1];
	local_args[2] = NULL;
	local_args[3] = NULL;

W
Wolfgang Denk 已提交
370 371 372 373 374 375
	/*
	 * Check the syntax:
	 *
	 * env_ask envname [message1 ...] [size]
	 */
	if (argc == 1)
376
		return CMD_RET_USAGE;
W
wdenk 已提交
377

W
Wolfgang Denk 已提交
378 379 380 381 382 383 384 385 386 387 388 389 390
	/*
	 * We test the last argument if it can be converted
	 * into a decimal number.  If yes, we assume it's
	 * the size.  Otherwise we echo it as part of the
	 * message.
	 */
	i = simple_strtoul(argv[argc - 1], &endptr, 10);
	if (*endptr != '\0') {			/* no size */
		size = CONFIG_SYS_CBSIZE - 1;
	} else {				/* size given */
		size = i;
		--argc;
	}
W
wdenk 已提交
391

W
Wolfgang Denk 已提交
392 393 394 395 396
	if (argc <= 2) {
		sprintf(message, "Please enter '%s': ", argv[1]);
	} else {
		/* env_ask envname message1 ... messagen [size] */
		for (i = 2, pos = 0; i < argc; i++) {
397
			if (pos)
W
wdenk 已提交
398
				message[pos++] = ' ';
399

400
			strcpy(message + pos, argv[i]);
W
wdenk 已提交
401 402
			pos += strlen(argv[i]);
		}
W
Wolfgang Denk 已提交
403
		message[pos++] = ' ';
W
wdenk 已提交
404 405 406
		message[pos] = '\0';
	}

407 408
	if (size >= CONFIG_SYS_CBSIZE)
		size = CONFIG_SYS_CBSIZE - 1;
W
wdenk 已提交
409 410 411 412 413

	if (size <= 0)
		return 1;

	/* prompt for input */
414
	len = cli_readline(message);
W
wdenk 已提交
415 416 417 418 419 420 421 422 423 424 425

	if (size < len)
		console_buffer[size] = '\0';

	len = 2;
	if (console_buffer[0] != '\0') {
		local_args[2] = console_buffer;
		len = 3;
	}

	/* Continue calling setenv code */
426
	return _do_env_set(flag, len, local_args, H_INTERACTIVE);
W
wdenk 已提交
427
}
428
#endif
W
wdenk 已提交
429

430
#if defined(CONFIG_CMD_ENV_CALLBACK)
431 432
static int print_static_binding(const char *var_name, const char *callback_name,
				void *priv)
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
{
	printf("\t%-20s %-20s\n", var_name, callback_name);

	return 0;
}

static int print_active_callback(ENTRY *entry)
{
	struct env_clbk_tbl *clbkp;
	int i;
	int num_callbacks;

	if (entry->callback == NULL)
		return 0;

	/* look up the callback in the linker-list */
	num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
	     i < num_callbacks;
	     i++, clbkp++) {
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
		if (entry->callback == clbkp->callback + gd->reloc_off)
#else
		if (entry->callback == clbkp->callback)
#endif
			break;
	}

	if (i == num_callbacks)
		/* this should probably never happen, but just in case... */
		printf("\t%-20s %p\n", entry->key, entry->callback);
	else
		printf("\t%-20s %-20s\n", entry->key, clbkp->name);

	return 0;
}

/*
 * Print the callbacks available and what they are bound to
 */
int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct env_clbk_tbl *clbkp;
	int i;
	int num_callbacks;

	/* Print the available callbacks */
	puts("Available callbacks:\n");
	puts("\tCallback Name\n");
	puts("\t-------------\n");
	num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
	     i < num_callbacks;
	     i++, clbkp++)
		printf("\t%s\n", clbkp->name);
	puts("\n");

	/* Print the static bindings that may exist */
	puts("Static callback bindings:\n");
	printf("\t%-20s %-20s\n", "Variable Name", "Callback Name");
	printf("\t%-20s %-20s\n", "-------------", "-------------");
494
	env_attr_walk(ENV_CALLBACK_LIST_STATIC, print_static_binding, NULL);
495 496 497 498 499 500 501 502 503 504 505
	puts("\n");

	/* walk through each variable and print the callback if it has one */
	puts("Active callback bindings:\n");
	printf("\t%-20s %-20s\n", "Variable Name", "Callback Name");
	printf("\t%-20s %-20s\n", "-------------", "-------------");
	hwalk_r(&env_htab, print_active_callback);
	return 0;
}
#endif

506
#if defined(CONFIG_CMD_ENV_FLAGS)
507 508
static int print_static_flags(const char *var_name, const char *flags,
			      void *priv)
509 510
{
	enum env_flags_vartype type = env_flags_parse_vartype(flags);
511
	enum env_flags_varaccess access = env_flags_parse_varaccess(flags);
512

513 514 515
	printf("\t%-20s %-20s %-20s\n", var_name,
		env_flags_get_vartype_name(type),
		env_flags_get_varaccess_name(access));
516 517 518 519 520 521 522

	return 0;
}

static int print_active_flags(ENTRY *entry)
{
	enum env_flags_vartype type;
523
	enum env_flags_varaccess access;
524 525 526 527 528 529

	if (entry->flags == 0)
		return 0;

	type = (enum env_flags_vartype)
		(entry->flags & ENV_FLAGS_VARTYPE_BIN_MASK);
530 531 532 533
	access = env_flags_parse_varaccess_from_binflags(entry->flags);
	printf("\t%-20s %-20s %-20s\n", entry->key,
		env_flags_get_vartype_name(type),
		env_flags_get_varaccess_name(access));
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550

	return 0;
}

/*
 * Print the flags available and what variables have flags
 */
int do_env_flags(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	/* Print the available variable types */
	printf("Available variable type flags (position %d):\n",
		ENV_FLAGS_VARTYPE_LOC);
	puts("\tFlag\tVariable Type Name\n");
	puts("\t----\t------------------\n");
	env_flags_print_vartypes();
	puts("\n");

551 552 553 554 555 556 557 558
	/* Print the available variable access types */
	printf("Available variable access flags (position %d):\n",
		ENV_FLAGS_VARACCESS_LOC);
	puts("\tFlag\tVariable Access Name\n");
	puts("\t----\t--------------------\n");
	env_flags_print_varaccess();
	puts("\n");

559 560
	/* Print the static flags that may exist */
	puts("Static flags:\n");
561 562 563 564
	printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type",
		"Variable Access");
	printf("\t%-20s %-20s %-20s\n", "-------------", "-------------",
		"---------------");
565
	env_attr_walk(ENV_FLAGS_LIST_STATIC, print_static_flags, NULL);
566 567 568 569
	puts("\n");

	/* walk through each variable and print the flags if non-default */
	puts("Active flags:\n");
570 571 572 573
	printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type",
		"Variable Access");
	printf("\t%-20s %-20s %-20s\n", "-------------", "-------------",
		"---------------");
574 575 576 577 578
	hwalk_r(&env_htab, print_active_flags);
	return 0;
}
#endif

579
/*
P
Peter Tyser 已提交
580 581 582
 * Interactively edit an environment variable
 */
#if defined(CONFIG_CMD_EDITENV)
K
Kim Phillips 已提交
583 584
static int do_env_edit(cmd_tbl_t *cmdtp, int flag, int argc,
		       char * const argv[])
P
Peter Tyser 已提交
585 586 587 588
{
	char buffer[CONFIG_SYS_CBSIZE];
	char *init_val;

589
	if (argc < 2)
590
		return CMD_RET_USAGE;
P
Peter Tyser 已提交
591

592 593 594 595
	/* before import into hashtable */
	if (!(gd->flags & GD_FLG_ENV_READY))
		return 1;

P
Peter Tyser 已提交
596 597 598
	/* Set read buffer to initial value or empty sting */
	init_val = getenv(argv[1]);
	if (init_val)
599
		snprintf(buffer, CONFIG_SYS_CBSIZE, "%s", init_val);
P
Peter Tyser 已提交
600 601 602
	else
		buffer[0] = '\0';

603
	if (cli_readline_into_buffer("edit: ", buffer, 0) < 0)
604
		return 1;
P
Peter Tyser 已提交
605

606 607 608 609 610 611 612 613 614 615
	if (buffer[0] == '\0') {
		const char * const _argv[3] = { "setenv", argv[1], NULL };

		return _do_env_set(0, 2, (char * const *)_argv, H_INTERACTIVE);
	} else {
		const char * const _argv[4] = { "setenv", argv[1], buffer,
			NULL };

		return _do_env_set(0, 3, (char * const *)_argv, H_INTERACTIVE);
	}
P
Peter Tyser 已提交
616 617
}
#endif /* CONFIG_CMD_EDITENV */
I
Ilya Yanok 已提交
618
#endif /* CONFIG_SPL_BUILD */
P
Peter Tyser 已提交
619

620
/*
W
wdenk 已提交
621 622 623 624
 * Look up variable from environment,
 * return address of storage for that variable,
 * or NULL if not found
 */
625
char *getenv(const char *name)
W
wdenk 已提交
626
{
627
	if (gd->flags & GD_FLG_ENV_READY) { /* after import into hashtable */
628
		ENTRY e, *ep;
W
wdenk 已提交
629

630
		WATCHDOG_RESET();
631

632 633
		e.key	= name;
		e.data	= NULL;
J
Joe Hershberger 已提交
634
		hsearch_r(e, FIND, &ep, &env_htab, 0);
635

636
		return ep ? ep->data : NULL;
W
wdenk 已提交
637 638
	}

639 640 641
	/* restricted capabilities before import */
	if (getenv_f(name, (char *)(gd->env_buf), sizeof(gd->env_buf)) > 0)
		return (char *)(gd->env_buf);
642

643
	return NULL;
W
wdenk 已提交
644 645
}

646 647 648
/*
 * Look up variable from environment for restricted C runtime env.
 */
649
int getenv_f(const char *name, char *buf, unsigned len)
W
wdenk 已提交
650 651 652
{
	int i, nxt;

653
	for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) {
W
wdenk 已提交
654 655
		int val, n;

656 657 658
		for (nxt = i; env_get_char(nxt) != '\0'; ++nxt) {
			if (nxt >= CONFIG_ENV_SIZE)
				return -1;
W
wdenk 已提交
659
		}
660 661 662

		val = envmatch((uchar *)name, i);
		if (val < 0)
W
wdenk 已提交
663
			continue;
664

W
wdenk 已提交
665
		/* found; copy out */
666
		for (n = 0; n < len; ++n, ++buf) {
667 668
			*buf = env_get_char(val++);
			if (*buf == '\0')
669 670 671 672 673 674
				return n;
		}

		if (n)
			*--buf = '\0';

675 676
		printf("env_buf [%d bytes] too small for value of \"%s\"\n",
			len, name);
677 678

		return n;
W
wdenk 已提交
679
	}
680

681
	return -1;
W
wdenk 已提交
682 683
}

684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
/**
 * Decode the integer value of an environment variable and return it.
 *
 * @param name		Name of environemnt variable
 * @param base		Number base to use (normally 10, or 16 for hex)
 * @param default_val	Default value to return if the variable is not
 *			found
 * @return the decoded value, or default_val if not found
 */
ulong getenv_ulong(const char *name, int base, ulong default_val)
{
	/*
	 * We can use getenv() here, even before relocation, since the
	 * environment variable value is an integer and thus short.
	 */
	const char *str = getenv(name);

	return str ? simple_strtoul(str, NULL, base) : default_val;
}

I
Ilya Yanok 已提交
704
#ifndef CONFIG_SPL_BUILD
705
#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE)
K
Kim Phillips 已提交
706 707
static int do_env_save(cmd_tbl_t *cmdtp, int flag, int argc,
		       char * const argv[])
W
wdenk 已提交
708
{
709
	printf("Saving Environment to %s...\n", env_name_spec);
W
wdenk 已提交
710

711
	return saveenv() ? 1 : 0;
W
wdenk 已提交
712
}
W
wdenk 已提交
713

M
Mike Frysinger 已提交
714
U_BOOT_CMD(
715
	saveenv, 1, 0,	do_env_save,
P
Peter Tyser 已提交
716
	"save environment variables to persistent storage",
W
Wolfgang Denk 已提交
717
	""
M
Mike Frysinger 已提交
718
);
W
wdenk 已提交
719
#endif
I
Ilya Yanok 已提交
720
#endif /* CONFIG_SPL_BUILD */
W
wdenk 已提交
721 722


723
/*
W
wdenk 已提交
724 725 726 727
 * Match a name / name=value pair
 *
 * s1 is either a simple 'name', or a 'name=value' pair.
 * i2 is the environment index for a 'name2=value2' pair.
728
 * If the names match, return the index for the value2, else -1.
W
wdenk 已提交
729
 */
730
int envmatch(uchar *s1, int i2)
W
wdenk 已提交
731
{
732 733 734
	if (s1 == NULL)
		return -1;

W
wdenk 已提交
735 736
	while (*s1 == env_get_char(i2++))
		if (*s1++ == '=')
737
			return i2;
738

W
wdenk 已提交
739
	if (*s1 == '\0' && env_get_char(i2-1) == '=')
740
		return i2;
741

742
	return -1;
W
wdenk 已提交
743
}
W
wdenk 已提交
744

I
Ilya Yanok 已提交
745
#ifndef CONFIG_SPL_BUILD
746
static int do_env_default(cmd_tbl_t *cmdtp, int __flag,
747
			  int argc, char * const argv[])
748
{
749
	int all = 0, flag = 0;
750

751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
	debug("Initial value for argc=%d\n", argc);
	while (--argc > 0 && **++argv == '-') {
		char *arg = *argv;

		while (*++arg) {
			switch (*arg) {
			case 'a':		/* default all */
				all = 1;
				break;
			case 'f':		/* force */
				flag |= H_FORCE;
				break;
			default:
				return cmd_usage(cmdtp);
			}
		}
	}
	debug("Final value for argc=%d\n", argc);
	if (all && (argc == 0)) {
		/* Reset the whole environment */
		set_default_env("## Resetting to default environment\n");
		return 0;
	}
	if (!all && (argc > 0)) {
		/* Reset individual variables */
		set_default_vars(argc, argv);
		return 0;
	}

	return cmd_usage(cmdtp);
781 782
}

783 784
static int do_env_delete(cmd_tbl_t *cmdtp, int flag,
			 int argc, char * const argv[])
785
{
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
	int env_flag = H_INTERACTIVE;
	int ret = 0;

	debug("Initial value for argc=%d\n", argc);
	while (argc > 1 && **(argv + 1) == '-') {
		char *arg = *++argv;

		--argc;
		while (*++arg) {
			switch (*arg) {
			case 'f':		/* force */
				env_flag |= H_FORCE;
				break;
			default:
				return CMD_RET_USAGE;
			}
		}
	}
	debug("Final value for argc=%d\n", argc);

	env_id++;

	while (--argc > 0) {
		char *name = *++argv;

		if (!hdelete_r(name, &env_htab, env_flag))
			ret = 1;
	}

	return ret;
816 817
}

818
#ifdef CONFIG_CMD_EXPORTENV
819
/*
820
 * env export [-t | -b | -c] [-s size] addr [var ...]
821 822 823 824 825 826 827 828 829
 *	-t:	export as text format; if size is given, data will be
 *		padded with '\0' bytes; if not, one terminating '\0'
 *		will be added (which is included in the "filesize"
 *		setting so you can for exmple copy this to flash and
 *		keep the termination).
 *	-b:	export as binary format (name=value pairs separated by
 *		'\0', list end marked by double "\0\0")
 *	-c:	export as checksum protected environment format as
 *		used for example by "saveenv" command
830 831
 *	-s size:
 *		size of output buffer
832
 *	addr:	memory address where environment gets stored
833 834 835
 *	var...	List of variable names that get included into the
 *		export. Without arguments, the whole environment gets
 *		exported.
836 837 838 839
 *
 * With "-c" and size is NOT given, then the export command will
 * format the data as currently used for the persistent storage,
 * i. e. it will use CONFIG_ENV_SECT_SIZE as output block size and
840
 * prepend a valid CRC32 checksum and, in case of redundant
841 842 843 844 845 846 847 848
 * environment, a "current" redundancy flag. If size is given, this
 * value will be used instead of CONFIG_ENV_SECT_SIZE; again, CRC32
 * checksum and redundancy flag will be inserted.
 *
 * With "-b" and "-t", always only the real data (including a
 * terminating '\0' byte) will be written; here the optional size
 * argument will be used to make sure not to overflow the user
 * provided buffer; the command will abort if the size is not
849
 * sufficient. Any remaining space will be '\0' padded.
850 851 852 853
 *
 * On successful return, the variable "filesize" will be set.
 * Note that filesize includes the trailing/terminating '\0' byte(s).
 *
854
 * Usage scenario:  create a text snapshot/backup of the current settings:
855 856 857 858 859 860 861 862 863
 *
 *	=> env export -t 100000
 *	=> era ${backup_addr} +${filesize}
 *	=> cp.b 100000 ${backup_addr} ${filesize}
 *
 * Re-import this snapshot, deleting all other settings:
 *
 *	=> env import -d -t ${backup_addr}
 */
864 865
static int do_env_export(cmd_tbl_t *cmdtp, int flag,
			 int argc, char * const argv[])
866 867
{
	char	buf[32];
868 869
	ulong	addr;
	char	*ptr, *cmd, *res;
870
	size_t	size = 0;
871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893
	ssize_t	len;
	env_t	*envp;
	char	sep = '\n';
	int	chk = 0;
	int	fmt = 0;

	cmd = *argv;

	while (--argc > 0 && **++argv == '-') {
		char *arg = *argv;
		while (*++arg) {
			switch (*arg) {
			case 'b':		/* raw binary format */
				if (fmt++)
					goto sep_err;
				sep = '\0';
				break;
			case 'c':		/* external checksum format */
				if (fmt++)
					goto sep_err;
				sep = '\0';
				chk = 1;
				break;
894 895 896 897 898
			case 's':		/* size given */
				if (--argc <= 0)
					return cmd_usage(cmdtp);
				size = simple_strtoul(*++argv, NULL, 16);
				goto NXTARG;
899 900 901 902 903 904
			case 't':		/* text format */
				if (fmt++)
					goto sep_err;
				sep = '\n';
				break;
			default:
905
				return CMD_RET_USAGE;
906 907
			}
		}
908
NXTARG:		;
909 910
	}

911
	if (argc < 1)
912
		return CMD_RET_USAGE;
W
wdenk 已提交
913

914 915
	addr = simple_strtoul(argv[0], NULL, 16);
	ptr = map_sysmem(addr, size);
916

917
	if (size)
918
		memset(ptr, '\0', size);
919 920 921

	argc--;
	argv++;
922 923

	if (sep) {		/* export as text file */
924 925
		len = hexport_r(&env_htab, sep,
				H_MATCH_KEY | H_MATCH_IDENT,
926
				&ptr, size, argc, argv);
927
		if (len < 0) {
928
			error("Cannot export environment: errno = %d\n", errno);
929 930
			return 1;
		}
931
		sprintf(buf, "%zX", (size_t)len);
932 933 934 935 936
		setenv("filesize", buf);

		return 0;
	}

937
	envp = (env_t *)ptr;
938 939 940 941

	if (chk)		/* export as checksum protected block */
		res = (char *)envp->data;
	else			/* export as raw binary data */
942
		res = ptr;
943

944 945 946
	len = hexport_r(&env_htab, '\0',
			H_MATCH_KEY | H_MATCH_IDENT,
			&res, ENV_SIZE, argc, argv);
947
	if (len < 0) {
948
		error("Cannot export environment: errno = %d\n", errno);
949 950 951 952
		return 1;
	}

	if (chk) {
953
		envp->crc = crc32(0, envp->data, ENV_SIZE);
954 955 956 957
#ifdef CONFIG_ENV_ADDR_REDUND
		envp->flags = ACTIVE_FLAG;
#endif
	}
958
	setenv_hex("filesize", len + offsetof(env_t, data));
959 960 961 962

	return 0;

sep_err:
963
	printf("## %s: only one of \"-b\", \"-c\" or \"-t\" allowed\n",	cmd);
964 965
	return 1;
}
966
#endif
967

968
#ifdef CONFIG_CMD_IMPORTENV
969
/*
970
 * env import [-d] [-t [-r] | -b | -c] addr [size]
971
 *	-d:	delete existing environment before importing;
972
 *		otherwise overwrite / append to existing definitions
973 974
 *	-t:	assume text format; either "size" must be given or the
 *		text data must be '\0' terminated
975 976 977 978
 *	-r:	handle CRLF like LF, that means exported variables with
 *		a content which ends with \r won't get imported. Used
 *		to import text files created with editors which are using CRLF
 *		for line endings. Only effective in addition to -t.
979 980 981 982 983 984
 *	-b:	assume binary format ('\0' separated, "\0\0" terminated)
 *	-c:	assume checksum protected environment format
 *	addr:	memory address to read from
 *	size:	length of input data; if missing, proper '\0'
 *		termination is mandatory
 */
985 986
static int do_env_import(cmd_tbl_t *cmdtp, int flag,
			 int argc, char * const argv[])
987
{
988 989
	ulong	addr;
	char	*cmd, *ptr;
990 991 992 993
	char	sep = '\n';
	int	chk = 0;
	int	fmt = 0;
	int	del = 0;
994
	int	crlf_is_lf = 0;
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
	size_t	size;

	cmd = *argv;

	while (--argc > 0 && **++argv == '-') {
		char *arg = *argv;
		while (*++arg) {
			switch (*arg) {
			case 'b':		/* raw binary format */
				if (fmt++)
					goto sep_err;
				sep = '\0';
				break;
			case 'c':		/* external checksum format */
				if (fmt++)
					goto sep_err;
				sep = '\0';
				chk = 1;
				break;
			case 't':		/* text format */
				if (fmt++)
					goto sep_err;
				sep = '\n';
				break;
1019 1020 1021
			case 'r':		/* handle CRLF like LF */
				crlf_is_lf = 1;
				break;
1022 1023 1024 1025
			case 'd':
				del = 1;
				break;
			default:
1026
				return CMD_RET_USAGE;
1027 1028 1029 1030
			}
		}
	}

1031
	if (argc < 1)
1032
		return CMD_RET_USAGE;
1033 1034 1035 1036

	if (!fmt)
		printf("## Warning: defaulting to text format\n");

1037 1038 1039
	if (sep != '\n' && crlf_is_lf )
		crlf_is_lf = 0;

1040 1041
	addr = simple_strtoul(argv[0], NULL, 16);
	ptr = map_sysmem(addr, 0);
1042 1043 1044

	if (argc == 2) {
		size = simple_strtoul(argv[1], NULL, 16);
1045 1046 1047
	} else if (argc == 1 && chk) {
		puts("## Error: external checksum format must pass size\n");
		return CMD_RET_FAILURE;
1048
	} else {
1049
		char *s = ptr;
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062

		size = 0;

		while (size < MAX_ENV_SIZE) {
			if ((*s == sep) && (*(s+1) == '\0'))
				break;
			++s;
			++size;
		}
		if (size == MAX_ENV_SIZE) {
			printf("## Warning: Input data exceeds %d bytes"
				" - truncated\n", MAX_ENV_SIZE);
		}
1063
		size += 2;
S
Simon Glass 已提交
1064
		printf("## Info: input data size = %zu = 0x%zX\n", size, size);
1065 1066 1067 1068
	}

	if (chk) {
		uint32_t crc;
1069
		env_t *ep = (env_t *)ptr;
1070 1071 1072 1073 1074 1075 1076 1077

		size -= offsetof(env_t, data);
		memcpy(&crc, &ep->crc, sizeof(crc));

		if (crc32(0, ep->data, size) != crc) {
			puts("## Error: bad CRC, import failed\n");
			return 1;
		}
1078
		ptr = (char *)ep->data;
1079 1080
	}

1081 1082
	if (himport_r(&env_htab, ptr, size, sep, del ? 0 : H_NOCLEAR,
			crlf_is_lf, 0, NULL) == 0) {
1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
		error("Environment import failed: errno = %d\n", errno);
		return 1;
	}
	gd->flags |= GD_FLG_ENV_READY;

	return 0;

sep_err:
	printf("## %s: only one of \"-b\", \"-c\" or \"-t\" allowed\n",
		cmd);
	return 1;
}
1095
#endif
1096

1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113
#if defined(CONFIG_CMD_ENV_EXISTS)
static int do_env_exists(cmd_tbl_t *cmdtp, int flag, int argc,
		       char * const argv[])
{
	ENTRY e, *ep;

	if (argc < 2)
		return CMD_RET_USAGE;

	e.key = argv[1];
	e.data = NULL;
	hsearch_r(e, FIND, &ep, &env_htab, 0);

	return (ep == NULL) ? 1 : 0;
}
#endif

1114 1115 1116 1117 1118 1119 1120 1121
/*
 * New command line interface: "env" command with subcommands
 */
static cmd_tbl_t cmd_env_sub[] = {
#if defined(CONFIG_CMD_ASKENV)
	U_BOOT_CMD_MKENT(ask, CONFIG_SYS_MAXARGS, 1, do_env_ask, "", ""),
#endif
	U_BOOT_CMD_MKENT(default, 1, 0, do_env_default, "", ""),
1122
	U_BOOT_CMD_MKENT(delete, CONFIG_SYS_MAXARGS, 0, do_env_delete, "", ""),
1123 1124 1125
#if defined(CONFIG_CMD_EDITENV)
	U_BOOT_CMD_MKENT(edit, 2, 0, do_env_edit, "", ""),
#endif
1126 1127 1128
#if defined(CONFIG_CMD_ENV_CALLBACK)
	U_BOOT_CMD_MKENT(callbacks, 1, 0, do_env_callback, "", ""),
#endif
1129 1130 1131
#if defined(CONFIG_CMD_ENV_FLAGS)
	U_BOOT_CMD_MKENT(flags, 1, 0, do_env_flags, "", ""),
#endif
1132
#if defined(CONFIG_CMD_EXPORTENV)
1133
	U_BOOT_CMD_MKENT(export, 4, 0, do_env_export, "", ""),
1134
#endif
K
Kim Phillips 已提交
1135 1136 1137
#if defined(CONFIG_CMD_GREPENV)
	U_BOOT_CMD_MKENT(grep, CONFIG_SYS_MAXARGS, 1, do_env_grep, "", ""),
#endif
1138
#if defined(CONFIG_CMD_IMPORTENV)
1139
	U_BOOT_CMD_MKENT(import, 5, 0, do_env_import, "", ""),
1140
#endif
1141 1142 1143 1144 1145 1146 1147 1148
	U_BOOT_CMD_MKENT(print, CONFIG_SYS_MAXARGS, 1, do_env_print, "", ""),
#if defined(CONFIG_CMD_RUN)
	U_BOOT_CMD_MKENT(run, CONFIG_SYS_MAXARGS, 1, do_run, "", ""),
#endif
#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE)
	U_BOOT_CMD_MKENT(save, 1, 0, do_env_save, "", ""),
#endif
	U_BOOT_CMD_MKENT(set, CONFIG_SYS_MAXARGS, 0, do_env_set, "", ""),
1149 1150 1151
#if defined(CONFIG_CMD_ENV_EXISTS)
	U_BOOT_CMD_MKENT(exists, 2, 0, do_env_exists, "", ""),
#endif
1152 1153
};

1154
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
1155 1156 1157 1158 1159 1160
void env_reloc(void)
{
	fixup_cmdtable(cmd_env_sub, ARRAY_SIZE(cmd_env_sub));
}
#endif

1161
static int do_env(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1162 1163 1164
{
	cmd_tbl_t *cp;

1165
	if (argc < 2)
1166
		return CMD_RET_USAGE;
1167

1168 1169 1170 1171 1172 1173 1174 1175 1176
	/* drop initial "env" arg */
	argc--;
	argv++;

	cp = find_cmd_tbl(argv[0], cmd_env_sub, ARRAY_SIZE(cmd_env_sub));

	if (cp)
		return cp->cmd(cmdtp, flag, argc, argv);

1177
	return CMD_RET_USAGE;
1178 1179
}

K
Kim Phillips 已提交
1180 1181
#ifdef CONFIG_SYS_LONGHELP
static char env_help_text[] =
1182 1183
#if defined(CONFIG_CMD_ASKENV)
	"ask name [message] [size] - ask for environment variable\nenv "
1184 1185 1186
#endif
#if defined(CONFIG_CMD_ENV_CALLBACK)
	"callbacks - print callbacks and their associated variables\nenv "
1187
#endif
1188 1189
	"default [-f] -a - [forcibly] reset default environment\n"
	"env default [-f] var [...] - [forcibly] reset variable(s) to their default values\n"
1190
	"env delete [-f] var [...] - [forcibly] delete variable(s)\n"
1191 1192 1193
#if defined(CONFIG_CMD_EDITENV)
	"env edit name - edit environment variable\n"
#endif
1194 1195 1196
#if defined(CONFIG_CMD_ENV_EXISTS)
	"env exists name - tests for existence of variable\n"
#endif
1197
#if defined(CONFIG_CMD_EXPORTENV)
1198
	"env export [-t | -b | -c] [-s size] addr [var ...] - export environment\n"
1199
#endif
1200 1201 1202
#if defined(CONFIG_CMD_ENV_FLAGS)
	"env flags - print variables that have non-default flags\n"
#endif
K
Kim Phillips 已提交
1203
#if defined(CONFIG_CMD_GREPENV)
1204 1205 1206
#ifdef CONFIG_REGEX
	"env grep [-e] [-n | -v | -b] string [...] - search environment\n"
#else
1207
	"env grep [-n | -v | -b] string [...] - search environment\n"
K
Kim Phillips 已提交
1208
#endif
1209
#endif
1210
#if defined(CONFIG_CMD_IMPORTENV)
1211
	"env import [-d] [-t [-r] | -b | -c] addr [size] - import environment\n"
1212
#endif
1213
	"env print [-a | name ...] - print environment\n"
1214 1215 1216
#if defined(CONFIG_CMD_RUN)
	"env run var [...] - run commands in an environment variable\n"
#endif
1217
#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE)
1218
	"env save - save environment\n"
1219
#endif
K
Kim Phillips 已提交
1220 1221 1222 1223 1224 1225
	"env set [-f] name [arg ...]\n";
#endif

U_BOOT_CMD(
	env, CONFIG_SYS_MAXARGS, 1, do_env,
	"environment handling commands", env_help_text
1226 1227 1228 1229 1230
);

/*
 * Old command line interface, kept for compatibility
 */
W
wdenk 已提交
1231

P
Peter Tyser 已提交
1232
#if defined(CONFIG_CMD_EDITENV)
1233
U_BOOT_CMD_COMPLETE(
1234
	editenv, 2, 0,	do_env_edit,
P
Peter Tyser 已提交
1235 1236
	"edit environment variable",
	"name\n"
1237 1238
	"    - edit environment variable 'name'",
	var_complete
P
Peter Tyser 已提交
1239 1240 1241
);
#endif

1242
U_BOOT_CMD_COMPLETE(
1243
	printenv, CONFIG_SYS_MAXARGS, 1,	do_env_print,
P
Peter Tyser 已提交
1244
	"print environment variables",
1245
	"[-a]\n    - print [all] values of all environment variables\n"
W
wdenk 已提交
1246
	"printenv name ...\n"
1247 1248
	"    - print value of environment variable 'name'",
	var_complete
W
wdenk 已提交
1249 1250
);

K
Kim Phillips 已提交
1251 1252 1253 1254
#ifdef CONFIG_CMD_GREPENV
U_BOOT_CMD_COMPLETE(
	grepenv, CONFIG_SYS_MAXARGS, 0,  do_env_grep,
	"search environment variables",
1255 1256 1257
#ifdef CONFIG_REGEX
	"[-e] [-n | -v | -b] string ...\n"
#else
1258
	"[-n | -v | -b] string ...\n"
1259
#endif
1260
	"    - list environment name=value pairs matching 'string'\n"
1261 1262 1263
#ifdef CONFIG_REGEX
	"      \"-e\": enable regular expressions;\n"
#endif
1264 1265
	"      \"-n\": search variable names; \"-v\": search values;\n"
	"      \"-b\": search both names and values (default)",
K
Kim Phillips 已提交
1266 1267 1268 1269
	var_complete
);
#endif

1270
U_BOOT_CMD_COMPLETE(
1271
	setenv, CONFIG_SYS_MAXARGS, 0,	do_env_set,
P
Peter Tyser 已提交
1272
	"set environment variables",
J
Joe Hershberger 已提交
1273 1274 1275 1276
	"[-f] name value ...\n"
	"    - [forcibly] set environment variable 'name' to 'value ...'\n"
	"setenv [-f] name\n"
	"    - [forcibly] delete environment variable 'name'",
1277
	var_complete
W
wdenk 已提交
1278 1279
);

1280
#if defined(CONFIG_CMD_ASKENV)
W
wdenk 已提交
1281

W
wdenk 已提交
1282
U_BOOT_CMD(
1283
	askenv,	CONFIG_SYS_MAXARGS,	1,	do_env_ask,
P
Peter Tyser 已提交
1284
	"get environment variables from stdin",
W
wdenk 已提交
1285
	"name [message] [size]\n"
W
Wolfgang Denk 已提交
1286
	"    - get environment variable 'name' from stdin (max 'size' chars)"
W
wdenk 已提交
1287
);
1288
#endif
W
wdenk 已提交
1289

1290
#if defined(CONFIG_CMD_RUN)
1291
U_BOOT_CMD_COMPLETE(
1292
	run,	CONFIG_SYS_MAXARGS,	1,	do_run,
P
Peter Tyser 已提交
1293
	"run commands in an environment variable",
W
wdenk 已提交
1294
	"var [...]\n"
1295 1296
	"    - run the commands in the environment variable(s) 'var'",
	var_complete
W
wdenk 已提交
1297
);
1298
#endif
I
Ilya Yanok 已提交
1299
#endif /* CONFIG_SPL_BUILD */