1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2000-2013 4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 5 * 6 * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com> 7 * Andreas Heppel <aheppel@sysgo.de> 8 * 9 * Copyright 2011 Freescale Semiconductor, Inc. 10 */ 11 12 /* 13 * Support for persistent environment data 14 * 15 * The "environment" is stored on external storage as a list of '\0' 16 * terminated "name=value" strings. The end of the list is marked by 17 * a double '\0'. The environment is preceded by a 32 bit CRC over 18 * the data part and, in case of redundant environment, a byte of 19 * flags. 20 * 21 * This linearized representation will also be used before 22 * relocation, i. e. as long as we don't have a full C runtime 23 * environment. After that, we use a hash table. 24 */ 25 26 #include <common.h> 27 #include <cli.h> 28 #include <command.h> 29 #include <console.h> 30 #include <environment.h> 31 #include <search.h> 32 #include <errno.h> 33 #include <malloc.h> 34 #include <mapmem.h> 35 #include <watchdog.h> 36 #include <linux/stddef.h> 37 #include <asm/byteorder.h> 38 #include <asm/io.h> 39 40 DECLARE_GLOBAL_DATA_PTR; 41 42 #if !defined(CONFIG_ENV_IS_IN_EEPROM) && \ 43 !defined(CONFIG_ENV_IS_IN_FLASH) && \ 44 !defined(CONFIG_ENV_IS_IN_MMC) && \ 45 !defined(CONFIG_ENV_IS_IN_FAT) && \ 46 !defined(CONFIG_ENV_IS_IN_EXT4) && \ 47 !defined(CONFIG_ENV_IS_IN_NAND) && \ 48 !defined(CONFIG_ENV_IS_IN_NVRAM) && \ 49 !defined(CONFIG_ENV_IS_IN_ONENAND) && \ 50 !defined(CONFIG_ENV_IS_IN_SATA) && \ 51 !defined(CONFIG_ENV_IS_IN_SPI_FLASH) && \ 52 !defined(CONFIG_ENV_IS_IN_REMOTE) && \ 53 !defined(CONFIG_ENV_IS_IN_UBI) && \ 54 !defined(CONFIG_ENV_IS_NOWHERE) 55 # error Define one of CONFIG_ENV_IS_IN_{EEPROM|FLASH|MMC|FAT|EXT4|\ 56 NAND|NVRAM|ONENAND|SATA|SPI_FLASH|REMOTE|UBI} or CONFIG_ENV_IS_NOWHERE 57 #endif 58 59 /* 60 * Maximum expected input data size for import command 61 */ 62 #define MAX_ENV_SIZE (1 << 20) /* 1 MiB */ 63 64 /* 65 * This variable is incremented on each do_env_set(), so it can 66 * be used via get_env_id() as an indication, if the environment 67 * has changed or not. So it is possible to reread an environment 68 * variable only if the environment was changed ... done so for 69 * example in NetInitLoop() 70 */ 71 static int env_id = 1; 72 73 int get_env_id(void) 74 { 75 return env_id; 76 } 77 78 #ifndef CONFIG_SPL_BUILD 79 /* 80 * Command interface: print one or all environment variables 81 * 82 * Returns 0 in case of error, or length of printed string 83 */ 84 static int env_print(char *name, int flag) 85 { 86 char *res = NULL; 87 ssize_t len; 88 89 if (name) { /* print a single name */ 90 ENTRY e, *ep; 91 92 e.key = name; 93 e.data = NULL; 94 hsearch_r(e, FIND, &ep, &env_htab, flag); 95 if (ep == NULL) 96 return 0; 97 len = printf("%s=%s\n", ep->key, ep->data); 98 return len; 99 } 100 101 /* print whole list */ 102 len = hexport_r(&env_htab, '\n', flag, &res, 0, 0, NULL); 103 104 if (len > 0) { 105 puts(res); 106 free(res); 107 return len; 108 } 109 110 /* should never happen */ 111 printf("## Error: cannot export environment\n"); 112 return 0; 113 } 114 115 static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc, 116 char * const argv[]) 117 { 118 int i; 119 int rcode = 0; 120 int env_flag = H_HIDE_DOT; 121 122 if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'a') { 123 argc--; 124 argv++; 125 env_flag &= ~H_HIDE_DOT; 126 } 127 128 if (argc == 1) { 129 /* print all env vars */ 130 rcode = env_print(NULL, env_flag); 131 if (!rcode) 132 return 1; 133 printf("\nEnvironment size: %d/%ld bytes\n", 134 rcode, (ulong)ENV_SIZE); 135 return 0; 136 } 137 138 /* print selected env vars */ 139 env_flag &= ~H_HIDE_DOT; 140 for (i = 1; i < argc; ++i) { 141 int rc = env_print(argv[i], env_flag); 142 if (!rc) { 143 printf("## Error: \"%s\" not defined\n", argv[i]); 144 ++rcode; 145 } 146 } 147 148 return rcode; 149 } 150 151 #ifdef CONFIG_CMD_GREPENV 152 static int do_env_grep(cmd_tbl_t *cmdtp, int flag, 153 int argc, char * const argv[]) 154 { 155 char *res = NULL; 156 int len, grep_how, grep_what; 157 158 if (argc < 2) 159 return CMD_RET_USAGE; 160 161 grep_how = H_MATCH_SUBSTR; /* default: substring search */ 162 grep_what = H_MATCH_BOTH; /* default: grep names and values */ 163 164 while (--argc > 0 && **++argv == '-') { 165 char *arg = *argv; 166 while (*++arg) { 167 switch (*arg) { 168 #ifdef CONFIG_REGEX 169 case 'e': /* use regex matching */ 170 grep_how = H_MATCH_REGEX; 171 break; 172 #endif 173 case 'n': /* grep for name */ 174 grep_what = H_MATCH_KEY; 175 break; 176 case 'v': /* grep for value */ 177 grep_what = H_MATCH_DATA; 178 break; 179 case 'b': /* grep for both */ 180 grep_what = H_MATCH_BOTH; 181 break; 182 case '-': 183 goto DONE; 184 default: 185 return CMD_RET_USAGE; 186 } 187 } 188 } 189 190 DONE: 191 len = hexport_r(&env_htab, '\n', 192 flag | grep_what | grep_how, 193 &res, 0, argc, argv); 194 195 if (len > 0) { 196 puts(res); 197 free(res); 198 } 199 200 if (len < 2) 201 return 1; 202 203 return 0; 204 } 205 #endif 206 #endif /* CONFIG_SPL_BUILD */ 207 208 /* 209 * Set a new environment variable, 210 * or replace or delete an existing one. 211 */ 212 static int _do_env_set(int flag, int argc, char * const argv[], int env_flag) 213 { 214 int i, len; 215 char *name, *value, *s; 216 ENTRY e, *ep; 217 218 debug("Initial value for argc=%d\n", argc); 219 while (argc > 1 && **(argv + 1) == '-') { 220 char *arg = *++argv; 221 222 --argc; 223 while (*++arg) { 224 switch (*arg) { 225 case 'f': /* force */ 226 env_flag |= H_FORCE; 227 break; 228 default: 229 return CMD_RET_USAGE; 230 } 231 } 232 } 233 debug("Final value for argc=%d\n", argc); 234 name = argv[1]; 235 236 if (strchr(name, '=')) { 237 printf("## Error: illegal character '='" 238 "in variable name \"%s\"\n", name); 239 return 1; 240 } 241 242 env_id++; 243 244 /* Delete only ? */ 245 if (argc < 3 || argv[2] == NULL) { 246 int rc = hdelete_r(name, &env_htab, env_flag); 247 return !rc; 248 } 249 250 /* 251 * Insert / replace new value 252 */ 253 for (i = 2, len = 0; i < argc; ++i) 254 len += strlen(argv[i]) + 1; 255 256 value = malloc(len); 257 if (value == NULL) { 258 printf("## Can't malloc %d bytes\n", len); 259 return 1; 260 } 261 for (i = 2, s = value; i < argc; ++i) { 262 char *v = argv[i]; 263 264 while ((*s++ = *v++) != '\0') 265 ; 266 *(s - 1) = ' '; 267 } 268 if (s != value) 269 *--s = '\0'; 270 271 e.key = name; 272 e.data = value; 273 hsearch_r(e, ENTER, &ep, &env_htab, env_flag); 274 free(value); 275 if (!ep) { 276 printf("## Error inserting \"%s\" variable, errno=%d\n", 277 name, errno); 278 return 1; 279 } 280 281 return 0; 282 } 283 284 int env_set(const char *varname, const char *varvalue) 285 { 286 const char * const argv[4] = { "setenv", varname, varvalue, NULL }; 287 288 /* before import into hashtable */ 289 if (!(gd->flags & GD_FLG_ENV_READY)) 290 return 1; 291 292 if (varvalue == NULL || varvalue[0] == '\0') 293 return _do_env_set(0, 2, (char * const *)argv, H_PROGRAMMATIC); 294 else 295 return _do_env_set(0, 3, (char * const *)argv, H_PROGRAMMATIC); 296 } 297 298 /** 299 * Set an environment variable to an integer value 300 * 301 * @param varname Environment variable to set 302 * @param value Value to set it to 303 * @return 0 if ok, 1 on error 304 */ 305 int env_set_ulong(const char *varname, ulong value) 306 { 307 /* TODO: this should be unsigned */ 308 char *str = simple_itoa(value); 309 310 return env_set(varname, str); 311 } 312 313 /** 314 * Set an environment variable to an value in hex 315 * 316 * @param varname Environment variable to set 317 * @param value Value to set it to 318 * @return 0 if ok, 1 on error 319 */ 320 int env_set_hex(const char *varname, ulong value) 321 { 322 char str[17]; 323 324 sprintf(str, "%lx", value); 325 return env_set(varname, str); 326 } 327 328 ulong env_get_hex(const char *varname, ulong default_val) 329 { 330 const char *s; 331 ulong value; 332 char *endp; 333 334 s = env_get(varname); 335 if (s) 336 value = simple_strtoul(s, &endp, 16); 337 if (!s || endp == s) 338 return default_val; 339 340 return value; 341 } 342 343 void eth_parse_enetaddr(const char *addr, uint8_t *enetaddr) 344 { 345 char *end; 346 int i; 347 348 for (i = 0; i < 6; ++i) { 349 enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0; 350 if (addr) 351 addr = (*end) ? end + 1 : end; 352 } 353 } 354 355 int eth_env_get_enetaddr(const char *name, uint8_t *enetaddr) 356 { 357 eth_parse_enetaddr(env_get(name), enetaddr); 358 return is_valid_ethaddr(enetaddr); 359 } 360 361 int eth_env_set_enetaddr(const char *name, const uint8_t *enetaddr) 362 { 363 char buf[ARP_HLEN_ASCII + 1]; 364 365 if (eth_env_get_enetaddr(name, (uint8_t *)buf)) 366 return -EEXIST; 367 368 sprintf(buf, "%pM", enetaddr); 369 370 return env_set(name, buf); 371 } 372 373 #ifndef CONFIG_SPL_BUILD 374 static int do_env_set(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 375 { 376 if (argc < 2) 377 return CMD_RET_USAGE; 378 379 return _do_env_set(flag, argc, argv, H_INTERACTIVE); 380 } 381 382 /* 383 * Prompt for environment variable 384 */ 385 #if defined(CONFIG_CMD_ASKENV) 386 int do_env_ask(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 387 { 388 char message[CONFIG_SYS_CBSIZE]; 389 int i, len, pos, size; 390 char *local_args[4]; 391 char *endptr; 392 393 local_args[0] = argv[0]; 394 local_args[1] = argv[1]; 395 local_args[2] = NULL; 396 local_args[3] = NULL; 397 398 /* 399 * Check the syntax: 400 * 401 * env_ask envname [message1 ...] [size] 402 */ 403 if (argc == 1) 404 return CMD_RET_USAGE; 405 406 /* 407 * We test the last argument if it can be converted 408 * into a decimal number. If yes, we assume it's 409 * the size. Otherwise we echo it as part of the 410 * message. 411 */ 412 i = simple_strtoul(argv[argc - 1], &endptr, 10); 413 if (*endptr != '\0') { /* no size */ 414 size = CONFIG_SYS_CBSIZE - 1; 415 } else { /* size given */ 416 size = i; 417 --argc; 418 } 419 420 if (argc <= 2) { 421 sprintf(message, "Please enter '%s': ", argv[1]); 422 } else { 423 /* env_ask envname message1 ... messagen [size] */ 424 for (i = 2, pos = 0; i < argc && pos+1 < sizeof(message); i++) { 425 if (pos) 426 message[pos++] = ' '; 427 428 strncpy(message + pos, argv[i], sizeof(message) - pos); 429 pos += strlen(argv[i]); 430 } 431 if (pos < sizeof(message) - 1) { 432 message[pos++] = ' '; 433 message[pos] = '\0'; 434 } else 435 message[CONFIG_SYS_CBSIZE - 1] = '\0'; 436 } 437 438 if (size >= CONFIG_SYS_CBSIZE) 439 size = CONFIG_SYS_CBSIZE - 1; 440 441 if (size <= 0) 442 return 1; 443 444 /* prompt for input */ 445 len = cli_readline(message); 446 447 if (size < len) 448 console_buffer[size] = '\0'; 449 450 len = 2; 451 if (console_buffer[0] != '\0') { 452 local_args[2] = console_buffer; 453 len = 3; 454 } 455 456 /* Continue calling setenv code */ 457 return _do_env_set(flag, len, local_args, H_INTERACTIVE); 458 } 459 #endif 460 461 #if defined(CONFIG_CMD_ENV_CALLBACK) 462 static int print_static_binding(const char *var_name, const char *callback_name, 463 void *priv) 464 { 465 printf("\t%-20s %-20s\n", var_name, callback_name); 466 467 return 0; 468 } 469 470 static int print_active_callback(ENTRY *entry) 471 { 472 struct env_clbk_tbl *clbkp; 473 int i; 474 int num_callbacks; 475 476 if (entry->callback == NULL) 477 return 0; 478 479 /* look up the callback in the linker-list */ 480 num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk); 481 for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk); 482 i < num_callbacks; 483 i++, clbkp++) { 484 #if defined(CONFIG_NEEDS_MANUAL_RELOC) 485 if (entry->callback == clbkp->callback + gd->reloc_off) 486 #else 487 if (entry->callback == clbkp->callback) 488 #endif 489 break; 490 } 491 492 if (i == num_callbacks) 493 /* this should probably never happen, but just in case... */ 494 printf("\t%-20s %p\n", entry->key, entry->callback); 495 else 496 printf("\t%-20s %-20s\n", entry->key, clbkp->name); 497 498 return 0; 499 } 500 501 /* 502 * Print the callbacks available and what they are bound to 503 */ 504 int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 505 { 506 struct env_clbk_tbl *clbkp; 507 int i; 508 int num_callbacks; 509 510 /* Print the available callbacks */ 511 puts("Available callbacks:\n"); 512 puts("\tCallback Name\n"); 513 puts("\t-------------\n"); 514 num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk); 515 for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk); 516 i < num_callbacks; 517 i++, clbkp++) 518 printf("\t%s\n", clbkp->name); 519 puts("\n"); 520 521 /* Print the static bindings that may exist */ 522 puts("Static callback bindings:\n"); 523 printf("\t%-20s %-20s\n", "Variable Name", "Callback Name"); 524 printf("\t%-20s %-20s\n", "-------------", "-------------"); 525 env_attr_walk(ENV_CALLBACK_LIST_STATIC, print_static_binding, NULL); 526 puts("\n"); 527 528 /* walk through each variable and print the callback if it has one */ 529 puts("Active callback bindings:\n"); 530 printf("\t%-20s %-20s\n", "Variable Name", "Callback Name"); 531 printf("\t%-20s %-20s\n", "-------------", "-------------"); 532 hwalk_r(&env_htab, print_active_callback); 533 return 0; 534 } 535 #endif 536 537 #if defined(CONFIG_CMD_ENV_FLAGS) 538 static int print_static_flags(const char *var_name, const char *flags, 539 void *priv) 540 { 541 enum env_flags_vartype type = env_flags_parse_vartype(flags); 542 enum env_flags_varaccess access = env_flags_parse_varaccess(flags); 543 544 printf("\t%-20s %-20s %-20s\n", var_name, 545 env_flags_get_vartype_name(type), 546 env_flags_get_varaccess_name(access)); 547 548 return 0; 549 } 550 551 static int print_active_flags(ENTRY *entry) 552 { 553 enum env_flags_vartype type; 554 enum env_flags_varaccess access; 555 556 if (entry->flags == 0) 557 return 0; 558 559 type = (enum env_flags_vartype) 560 (entry->flags & ENV_FLAGS_VARTYPE_BIN_MASK); 561 access = env_flags_parse_varaccess_from_binflags(entry->flags); 562 printf("\t%-20s %-20s %-20s\n", entry->key, 563 env_flags_get_vartype_name(type), 564 env_flags_get_varaccess_name(access)); 565 566 return 0; 567 } 568 569 /* 570 * Print the flags available and what variables have flags 571 */ 572 int do_env_flags(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 573 { 574 /* Print the available variable types */ 575 printf("Available variable type flags (position %d):\n", 576 ENV_FLAGS_VARTYPE_LOC); 577 puts("\tFlag\tVariable Type Name\n"); 578 puts("\t----\t------------------\n"); 579 env_flags_print_vartypes(); 580 puts("\n"); 581 582 /* Print the available variable access types */ 583 printf("Available variable access flags (position %d):\n", 584 ENV_FLAGS_VARACCESS_LOC); 585 puts("\tFlag\tVariable Access Name\n"); 586 puts("\t----\t--------------------\n"); 587 env_flags_print_varaccess(); 588 puts("\n"); 589 590 /* Print the static flags that may exist */ 591 puts("Static flags:\n"); 592 printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type", 593 "Variable Access"); 594 printf("\t%-20s %-20s %-20s\n", "-------------", "-------------", 595 "---------------"); 596 env_attr_walk(ENV_FLAGS_LIST_STATIC, print_static_flags, NULL); 597 puts("\n"); 598 599 /* walk through each variable and print the flags if non-default */ 600 puts("Active flags:\n"); 601 printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type", 602 "Variable Access"); 603 printf("\t%-20s %-20s %-20s\n", "-------------", "-------------", 604 "---------------"); 605 hwalk_r(&env_htab, print_active_flags); 606 return 0; 607 } 608 #endif 609 610 /* 611 * Interactively edit an environment variable 612 */ 613 #if defined(CONFIG_CMD_EDITENV) 614 static int do_env_edit(cmd_tbl_t *cmdtp, int flag, int argc, 615 char * const argv[]) 616 { 617 char buffer[CONFIG_SYS_CBSIZE]; 618 char *init_val; 619 620 if (argc < 2) 621 return CMD_RET_USAGE; 622 623 /* before import into hashtable */ 624 if (!(gd->flags & GD_FLG_ENV_READY)) 625 return 1; 626 627 /* Set read buffer to initial value or empty sting */ 628 init_val = env_get(argv[1]); 629 if (init_val) 630 snprintf(buffer, CONFIG_SYS_CBSIZE, "%s", init_val); 631 else 632 buffer[0] = '\0'; 633 634 if (cli_readline_into_buffer("edit: ", buffer, 0) < 0) 635 return 1; 636 637 if (buffer[0] == '\0') { 638 const char * const _argv[3] = { "setenv", argv[1], NULL }; 639 640 return _do_env_set(0, 2, (char * const *)_argv, H_INTERACTIVE); 641 } else { 642 const char * const _argv[4] = { "setenv", argv[1], buffer, 643 NULL }; 644 645 return _do_env_set(0, 3, (char * const *)_argv, H_INTERACTIVE); 646 } 647 } 648 #endif /* CONFIG_CMD_EDITENV */ 649 #endif /* CONFIG_SPL_BUILD */ 650 651 /* 652 * Look up variable from environment, 653 * return address of storage for that variable, 654 * or NULL if not found 655 */ 656 char *env_get(const char *name) 657 { 658 if (gd->flags & GD_FLG_ENV_READY) { /* after import into hashtable */ 659 ENTRY e, *ep; 660 661 WATCHDOG_RESET(); 662 663 e.key = name; 664 e.data = NULL; 665 hsearch_r(e, FIND, &ep, &env_htab, 0); 666 667 return ep ? ep->data : NULL; 668 } 669 670 /* restricted capabilities before import */ 671 if (env_get_f(name, (char *)(gd->env_buf), sizeof(gd->env_buf)) > 0) 672 return (char *)(gd->env_buf); 673 674 return NULL; 675 } 676 677 /* 678 * Look up variable from environment for restricted C runtime env. 679 */ 680 int env_get_f(const char *name, char *buf, unsigned len) 681 { 682 int i, nxt, c; 683 684 for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) { 685 int val, n; 686 687 for (nxt = i; (c = env_get_char(nxt)) != '\0'; ++nxt) { 688 if (c < 0) 689 return c; 690 if (nxt >= CONFIG_ENV_SIZE) 691 return -1; 692 } 693 694 val = envmatch((uchar *)name, i); 695 if (val < 0) 696 continue; 697 698 /* found; copy out */ 699 for (n = 0; n < len; ++n, ++buf) { 700 c = env_get_char(val++); 701 if (c < 0) 702 return c; 703 *buf = c; 704 if (*buf == '\0') 705 return n; 706 } 707 708 if (n) 709 *--buf = '\0'; 710 711 printf("env_buf [%d bytes] too small for value of \"%s\"\n", 712 len, name); 713 714 return n; 715 } 716 717 return -1; 718 } 719 720 /** 721 * Decode the integer value of an environment variable and return it. 722 * 723 * @param name Name of environment variable 724 * @param base Number base to use (normally 10, or 16 for hex) 725 * @param default_val Default value to return if the variable is not 726 * found 727 * @return the decoded value, or default_val if not found 728 */ 729 ulong env_get_ulong(const char *name, int base, ulong default_val) 730 { 731 /* 732 * We can use env_get() here, even before relocation, since the 733 * environment variable value is an integer and thus short. 734 */ 735 const char *str = env_get(name); 736 737 return str ? simple_strtoul(str, NULL, base) : default_val; 738 } 739 740 #ifndef CONFIG_SPL_BUILD 741 #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) 742 static int do_env_save(cmd_tbl_t *cmdtp, int flag, int argc, 743 char * const argv[]) 744 { 745 return env_save() ? 1 : 0; 746 } 747 748 U_BOOT_CMD( 749 saveenv, 1, 0, do_env_save, 750 "save environment variables to persistent storage", 751 "" 752 ); 753 #endif 754 #endif /* CONFIG_SPL_BUILD */ 755 756 757 /* 758 * Match a name / name=value pair 759 * 760 * s1 is either a simple 'name', or a 'name=value' pair. 761 * i2 is the environment index for a 'name2=value2' pair. 762 * If the names match, return the index for the value2, else -1. 763 */ 764 int envmatch(uchar *s1, int i2) 765 { 766 if (s1 == NULL) 767 return -1; 768 769 while (*s1 == env_get_char(i2++)) 770 if (*s1++ == '=') 771 return i2; 772 773 if (*s1 == '\0' && env_get_char(i2-1) == '=') 774 return i2; 775 776 return -1; 777 } 778 779 #ifndef CONFIG_SPL_BUILD 780 static int do_env_default(cmd_tbl_t *cmdtp, int flag, 781 int argc, char * const argv[]) 782 { 783 int all = 0, env_flag = H_INTERACTIVE; 784 785 debug("Initial value for argc=%d\n", argc); 786 while (--argc > 0 && **++argv == '-') { 787 char *arg = *argv; 788 789 while (*++arg) { 790 switch (*arg) { 791 case 'a': /* default all */ 792 all = 1; 793 break; 794 case 'f': /* force */ 795 env_flag |= H_FORCE; 796 break; 797 default: 798 return cmd_usage(cmdtp); 799 } 800 } 801 } 802 debug("Final value for argc=%d\n", argc); 803 if (all && (argc == 0)) { 804 /* Reset the whole environment */ 805 set_default_env("## Resetting to default environment\n", 806 env_flag); 807 return 0; 808 } 809 if (!all && (argc > 0)) { 810 /* Reset individual variables */ 811 set_default_vars(argc, argv, env_flag); 812 return 0; 813 } 814 815 return cmd_usage(cmdtp); 816 } 817 818 static int do_env_delete(cmd_tbl_t *cmdtp, int flag, 819 int argc, char * const argv[]) 820 { 821 int env_flag = H_INTERACTIVE; 822 int ret = 0; 823 824 debug("Initial value for argc=%d\n", argc); 825 while (argc > 1 && **(argv + 1) == '-') { 826 char *arg = *++argv; 827 828 --argc; 829 while (*++arg) { 830 switch (*arg) { 831 case 'f': /* force */ 832 env_flag |= H_FORCE; 833 break; 834 default: 835 return CMD_RET_USAGE; 836 } 837 } 838 } 839 debug("Final value for argc=%d\n", argc); 840 841 env_id++; 842 843 while (--argc > 0) { 844 char *name = *++argv; 845 846 if (!hdelete_r(name, &env_htab, env_flag)) 847 ret = 1; 848 } 849 850 return ret; 851 } 852 853 #ifdef CONFIG_CMD_EXPORTENV 854 /* 855 * env export [-t | -b | -c] [-s size] addr [var ...] 856 * -t: export as text format; if size is given, data will be 857 * padded with '\0' bytes; if not, one terminating '\0' 858 * will be added (which is included in the "filesize" 859 * setting so you can for exmple copy this to flash and 860 * keep the termination). 861 * -b: export as binary format (name=value pairs separated by 862 * '\0', list end marked by double "\0\0") 863 * -c: export as checksum protected environment format as 864 * used for example by "saveenv" command 865 * -s size: 866 * size of output buffer 867 * addr: memory address where environment gets stored 868 * var... List of variable names that get included into the 869 * export. Without arguments, the whole environment gets 870 * exported. 871 * 872 * With "-c" and size is NOT given, then the export command will 873 * format the data as currently used for the persistent storage, 874 * i. e. it will use CONFIG_ENV_SECT_SIZE as output block size and 875 * prepend a valid CRC32 checksum and, in case of redundant 876 * environment, a "current" redundancy flag. If size is given, this 877 * value will be used instead of CONFIG_ENV_SECT_SIZE; again, CRC32 878 * checksum and redundancy flag will be inserted. 879 * 880 * With "-b" and "-t", always only the real data (including a 881 * terminating '\0' byte) will be written; here the optional size 882 * argument will be used to make sure not to overflow the user 883 * provided buffer; the command will abort if the size is not 884 * sufficient. Any remaining space will be '\0' padded. 885 * 886 * On successful return, the variable "filesize" will be set. 887 * Note that filesize includes the trailing/terminating '\0' byte(s). 888 * 889 * Usage scenario: create a text snapshot/backup of the current settings: 890 * 891 * => env export -t 100000 892 * => era ${backup_addr} +${filesize} 893 * => cp.b 100000 ${backup_addr} ${filesize} 894 * 895 * Re-import this snapshot, deleting all other settings: 896 * 897 * => env import -d -t ${backup_addr} 898 */ 899 static int do_env_export(cmd_tbl_t *cmdtp, int flag, 900 int argc, char * const argv[]) 901 { 902 char buf[32]; 903 ulong addr; 904 char *ptr, *cmd, *res; 905 size_t size = 0; 906 ssize_t len; 907 env_t *envp; 908 char sep = '\n'; 909 int chk = 0; 910 int fmt = 0; 911 912 cmd = *argv; 913 914 while (--argc > 0 && **++argv == '-') { 915 char *arg = *argv; 916 while (*++arg) { 917 switch (*arg) { 918 case 'b': /* raw binary format */ 919 if (fmt++) 920 goto sep_err; 921 sep = '\0'; 922 break; 923 case 'c': /* external checksum format */ 924 if (fmt++) 925 goto sep_err; 926 sep = '\0'; 927 chk = 1; 928 break; 929 case 's': /* size given */ 930 if (--argc <= 0) 931 return cmd_usage(cmdtp); 932 size = simple_strtoul(*++argv, NULL, 16); 933 goto NXTARG; 934 case 't': /* text format */ 935 if (fmt++) 936 goto sep_err; 937 sep = '\n'; 938 break; 939 default: 940 return CMD_RET_USAGE; 941 } 942 } 943 NXTARG: ; 944 } 945 946 if (argc < 1) 947 return CMD_RET_USAGE; 948 949 addr = simple_strtoul(argv[0], NULL, 16); 950 ptr = map_sysmem(addr, size); 951 952 if (size) 953 memset(ptr, '\0', size); 954 955 argc--; 956 argv++; 957 958 if (sep) { /* export as text file */ 959 len = hexport_r(&env_htab, sep, 960 H_MATCH_KEY | H_MATCH_IDENT, 961 &ptr, size, argc, argv); 962 if (len < 0) { 963 pr_err("## Error: Cannot export environment: errno = %d\n", 964 errno); 965 return 1; 966 } 967 sprintf(buf, "%zX", (size_t)len); 968 env_set("filesize", buf); 969 970 return 0; 971 } 972 973 envp = (env_t *)ptr; 974 975 if (chk) /* export as checksum protected block */ 976 res = (char *)envp->data; 977 else /* export as raw binary data */ 978 res = ptr; 979 980 len = hexport_r(&env_htab, '\0', 981 H_MATCH_KEY | H_MATCH_IDENT, 982 &res, ENV_SIZE, argc, argv); 983 if (len < 0) { 984 pr_err("## Error: Cannot export environment: errno = %d\n", 985 errno); 986 return 1; 987 } 988 989 if (chk) { 990 envp->crc = crc32(0, envp->data, 991 size ? size - offsetof(env_t, data) : ENV_SIZE); 992 #ifdef CONFIG_ENV_ADDR_REDUND 993 envp->flags = ACTIVE_FLAG; 994 #endif 995 } 996 env_set_hex("filesize", len + offsetof(env_t, data)); 997 998 return 0; 999 1000 sep_err: 1001 printf("## Error: %s: only one of \"-b\", \"-c\" or \"-t\" allowed\n", 1002 cmd); 1003 return 1; 1004 } 1005 #endif 1006 1007 #ifdef CONFIG_CMD_IMPORTENV 1008 /* 1009 * env import [-d] [-t [-r] | -b | -c] addr [size] [var ...] 1010 * -d: delete existing environment before importing if no var is 1011 * passed; if vars are passed, if one var is in the current 1012 * environment but not in the environment at addr, delete var from 1013 * current environment; 1014 * otherwise overwrite / append to existing definitions 1015 * -t: assume text format; either "size" must be given or the 1016 * text data must be '\0' terminated 1017 * -r: handle CRLF like LF, that means exported variables with 1018 * a content which ends with \r won't get imported. Used 1019 * to import text files created with editors which are using CRLF 1020 * for line endings. Only effective in addition to -t. 1021 * -b: assume binary format ('\0' separated, "\0\0" terminated) 1022 * -c: assume checksum protected environment format 1023 * addr: memory address to read from 1024 * size: length of input data; if missing, proper '\0' 1025 * termination is mandatory 1026 * if var is set and size should be missing (i.e. '\0' 1027 * termination), set size to '-' 1028 * var... List of the names of the only variables that get imported from 1029 * the environment at address 'addr'. Without arguments, the whole 1030 * environment gets imported. 1031 */ 1032 static int do_env_import(cmd_tbl_t *cmdtp, int flag, 1033 int argc, char * const argv[]) 1034 { 1035 ulong addr; 1036 char *cmd, *ptr; 1037 char sep = '\n'; 1038 int chk = 0; 1039 int fmt = 0; 1040 int del = 0; 1041 int crlf_is_lf = 0; 1042 int wl = 0; 1043 size_t size; 1044 1045 cmd = *argv; 1046 1047 while (--argc > 0 && **++argv == '-') { 1048 char *arg = *argv; 1049 while (*++arg) { 1050 switch (*arg) { 1051 case 'b': /* raw binary format */ 1052 if (fmt++) 1053 goto sep_err; 1054 sep = '\0'; 1055 break; 1056 case 'c': /* external checksum format */ 1057 if (fmt++) 1058 goto sep_err; 1059 sep = '\0'; 1060 chk = 1; 1061 break; 1062 case 't': /* text format */ 1063 if (fmt++) 1064 goto sep_err; 1065 sep = '\n'; 1066 break; 1067 case 'r': /* handle CRLF like LF */ 1068 crlf_is_lf = 1; 1069 break; 1070 case 'd': 1071 del = 1; 1072 break; 1073 default: 1074 return CMD_RET_USAGE; 1075 } 1076 } 1077 } 1078 1079 if (argc < 1) 1080 return CMD_RET_USAGE; 1081 1082 if (!fmt) 1083 printf("## Warning: defaulting to text format\n"); 1084 1085 if (sep != '\n' && crlf_is_lf ) 1086 crlf_is_lf = 0; 1087 1088 addr = simple_strtoul(argv[0], NULL, 16); 1089 ptr = map_sysmem(addr, 0); 1090 1091 if (argc >= 2 && strcmp(argv[1], "-")) { 1092 size = simple_strtoul(argv[1], NULL, 16); 1093 } else if (chk) { 1094 puts("## Error: external checksum format must pass size\n"); 1095 return CMD_RET_FAILURE; 1096 } else { 1097 char *s = ptr; 1098 1099 size = 0; 1100 1101 while (size < MAX_ENV_SIZE) { 1102 if ((*s == sep) && (*(s+1) == '\0')) 1103 break; 1104 ++s; 1105 ++size; 1106 } 1107 if (size == MAX_ENV_SIZE) { 1108 printf("## Warning: Input data exceeds %d bytes" 1109 " - truncated\n", MAX_ENV_SIZE); 1110 } 1111 size += 2; 1112 printf("## Info: input data size = %zu = 0x%zX\n", size, size); 1113 } 1114 1115 if (argc > 2) 1116 wl = 1; 1117 1118 if (chk) { 1119 uint32_t crc; 1120 env_t *ep = (env_t *)ptr; 1121 1122 size -= offsetof(env_t, data); 1123 memcpy(&crc, &ep->crc, sizeof(crc)); 1124 1125 if (crc32(0, ep->data, size) != crc) { 1126 puts("## Error: bad CRC, import failed\n"); 1127 return 1; 1128 } 1129 ptr = (char *)ep->data; 1130 } 1131 1132 if (!himport_r(&env_htab, ptr, size, sep, del ? 0 : H_NOCLEAR, 1133 crlf_is_lf, wl ? argc - 2 : 0, wl ? &argv[2] : NULL)) { 1134 pr_err("## Error: Environment import failed: errno = %d\n", 1135 errno); 1136 return 1; 1137 } 1138 gd->flags |= GD_FLG_ENV_READY; 1139 1140 return 0; 1141 1142 sep_err: 1143 printf("## %s: only one of \"-b\", \"-c\" or \"-t\" allowed\n", 1144 cmd); 1145 return 1; 1146 } 1147 #endif 1148 1149 #if defined(CONFIG_CMD_ENV_EXISTS) 1150 static int do_env_exists(cmd_tbl_t *cmdtp, int flag, int argc, 1151 char * const argv[]) 1152 { 1153 ENTRY e, *ep; 1154 1155 if (argc < 2) 1156 return CMD_RET_USAGE; 1157 1158 e.key = argv[1]; 1159 e.data = NULL; 1160 hsearch_r(e, FIND, &ep, &env_htab, 0); 1161 1162 return (ep == NULL) ? 1 : 0; 1163 } 1164 #endif 1165 1166 /* 1167 * New command line interface: "env" command with subcommands 1168 */ 1169 static cmd_tbl_t cmd_env_sub[] = { 1170 #if defined(CONFIG_CMD_ASKENV) 1171 U_BOOT_CMD_MKENT(ask, CONFIG_SYS_MAXARGS, 1, do_env_ask, "", ""), 1172 #endif 1173 U_BOOT_CMD_MKENT(default, 1, 0, do_env_default, "", ""), 1174 U_BOOT_CMD_MKENT(delete, CONFIG_SYS_MAXARGS, 0, do_env_delete, "", ""), 1175 #if defined(CONFIG_CMD_EDITENV) 1176 U_BOOT_CMD_MKENT(edit, 2, 0, do_env_edit, "", ""), 1177 #endif 1178 #if defined(CONFIG_CMD_ENV_CALLBACK) 1179 U_BOOT_CMD_MKENT(callbacks, 1, 0, do_env_callback, "", ""), 1180 #endif 1181 #if defined(CONFIG_CMD_ENV_FLAGS) 1182 U_BOOT_CMD_MKENT(flags, 1, 0, do_env_flags, "", ""), 1183 #endif 1184 #if defined(CONFIG_CMD_EXPORTENV) 1185 U_BOOT_CMD_MKENT(export, 4, 0, do_env_export, "", ""), 1186 #endif 1187 #if defined(CONFIG_CMD_GREPENV) 1188 U_BOOT_CMD_MKENT(grep, CONFIG_SYS_MAXARGS, 1, do_env_grep, "", ""), 1189 #endif 1190 #if defined(CONFIG_CMD_IMPORTENV) 1191 U_BOOT_CMD_MKENT(import, 5, 0, do_env_import, "", ""), 1192 #endif 1193 U_BOOT_CMD_MKENT(print, CONFIG_SYS_MAXARGS, 1, do_env_print, "", ""), 1194 #if defined(CONFIG_CMD_RUN) 1195 U_BOOT_CMD_MKENT(run, CONFIG_SYS_MAXARGS, 1, do_run, "", ""), 1196 #endif 1197 #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) 1198 U_BOOT_CMD_MKENT(save, 1, 0, do_env_save, "", ""), 1199 #endif 1200 U_BOOT_CMD_MKENT(set, CONFIG_SYS_MAXARGS, 0, do_env_set, "", ""), 1201 #if defined(CONFIG_CMD_ENV_EXISTS) 1202 U_BOOT_CMD_MKENT(exists, 2, 0, do_env_exists, "", ""), 1203 #endif 1204 }; 1205 1206 #if defined(CONFIG_NEEDS_MANUAL_RELOC) 1207 void env_reloc(void) 1208 { 1209 fixup_cmdtable(cmd_env_sub, ARRAY_SIZE(cmd_env_sub)); 1210 } 1211 #endif 1212 1213 static int do_env(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 1214 { 1215 cmd_tbl_t *cp; 1216 1217 if (argc < 2) 1218 return CMD_RET_USAGE; 1219 1220 /* drop initial "env" arg */ 1221 argc--; 1222 argv++; 1223 1224 cp = find_cmd_tbl(argv[0], cmd_env_sub, ARRAY_SIZE(cmd_env_sub)); 1225 1226 if (cp) 1227 return cp->cmd(cmdtp, flag, argc, argv); 1228 1229 return CMD_RET_USAGE; 1230 } 1231 1232 #ifdef CONFIG_SYS_LONGHELP 1233 static char env_help_text[] = 1234 #if defined(CONFIG_CMD_ASKENV) 1235 "ask name [message] [size] - ask for environment variable\nenv " 1236 #endif 1237 #if defined(CONFIG_CMD_ENV_CALLBACK) 1238 "callbacks - print callbacks and their associated variables\nenv " 1239 #endif 1240 "default [-f] -a - [forcibly] reset default environment\n" 1241 "env default [-f] var [...] - [forcibly] reset variable(s) to their default values\n" 1242 "env delete [-f] var [...] - [forcibly] delete variable(s)\n" 1243 #if defined(CONFIG_CMD_EDITENV) 1244 "env edit name - edit environment variable\n" 1245 #endif 1246 #if defined(CONFIG_CMD_ENV_EXISTS) 1247 "env exists name - tests for existence of variable\n" 1248 #endif 1249 #if defined(CONFIG_CMD_EXPORTENV) 1250 "env export [-t | -b | -c] [-s size] addr [var ...] - export environment\n" 1251 #endif 1252 #if defined(CONFIG_CMD_ENV_FLAGS) 1253 "env flags - print variables that have non-default flags\n" 1254 #endif 1255 #if defined(CONFIG_CMD_GREPENV) 1256 #ifdef CONFIG_REGEX 1257 "env grep [-e] [-n | -v | -b] string [...] - search environment\n" 1258 #else 1259 "env grep [-n | -v | -b] string [...] - search environment\n" 1260 #endif 1261 #endif 1262 #if defined(CONFIG_CMD_IMPORTENV) 1263 "env import [-d] [-t [-r] | -b | -c] addr [size] [var ...] - import environment\n" 1264 #endif 1265 "env print [-a | name ...] - print environment\n" 1266 #if defined(CONFIG_CMD_RUN) 1267 "env run var [...] - run commands in an environment variable\n" 1268 #endif 1269 #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) 1270 "env save - save environment\n" 1271 #endif 1272 "env set [-f] name [arg ...]\n"; 1273 #endif 1274 1275 U_BOOT_CMD( 1276 env, CONFIG_SYS_MAXARGS, 1, do_env, 1277 "environment handling commands", env_help_text 1278 ); 1279 1280 /* 1281 * Old command line interface, kept for compatibility 1282 */ 1283 1284 #if defined(CONFIG_CMD_EDITENV) 1285 U_BOOT_CMD_COMPLETE( 1286 editenv, 2, 0, do_env_edit, 1287 "edit environment variable", 1288 "name\n" 1289 " - edit environment variable 'name'", 1290 var_complete 1291 ); 1292 #endif 1293 1294 U_BOOT_CMD_COMPLETE( 1295 printenv, CONFIG_SYS_MAXARGS, 1, do_env_print, 1296 "print environment variables", 1297 "[-a]\n - print [all] values of all environment variables\n" 1298 "printenv name ...\n" 1299 " - print value of environment variable 'name'", 1300 var_complete 1301 ); 1302 1303 #ifdef CONFIG_CMD_GREPENV 1304 U_BOOT_CMD_COMPLETE( 1305 grepenv, CONFIG_SYS_MAXARGS, 0, do_env_grep, 1306 "search environment variables", 1307 #ifdef CONFIG_REGEX 1308 "[-e] [-n | -v | -b] string ...\n" 1309 #else 1310 "[-n | -v | -b] string ...\n" 1311 #endif 1312 " - list environment name=value pairs matching 'string'\n" 1313 #ifdef CONFIG_REGEX 1314 " \"-e\": enable regular expressions;\n" 1315 #endif 1316 " \"-n\": search variable names; \"-v\": search values;\n" 1317 " \"-b\": search both names and values (default)", 1318 var_complete 1319 ); 1320 #endif 1321 1322 U_BOOT_CMD_COMPLETE( 1323 setenv, CONFIG_SYS_MAXARGS, 0, do_env_set, 1324 "set environment variables", 1325 "[-f] name value ...\n" 1326 " - [forcibly] set environment variable 'name' to 'value ...'\n" 1327 "setenv [-f] name\n" 1328 " - [forcibly] delete environment variable 'name'", 1329 var_complete 1330 ); 1331 1332 #if defined(CONFIG_CMD_ASKENV) 1333 1334 U_BOOT_CMD( 1335 askenv, CONFIG_SYS_MAXARGS, 1, do_env_ask, 1336 "get environment variables from stdin", 1337 "name [message] [size]\n" 1338 " - get environment variable 'name' from stdin (max 'size' chars)" 1339 ); 1340 #endif 1341 1342 #if defined(CONFIG_CMD_RUN) 1343 U_BOOT_CMD_COMPLETE( 1344 run, CONFIG_SYS_MAXARGS, 1, do_run, 1345 "run commands in an environment variable", 1346 "var [...]\n" 1347 " - run the commands in the environment variable(s) 'var'", 1348 var_complete 1349 ); 1350 #endif 1351 #endif /* CONFIG_SPL_BUILD */ 1352