1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2000-2010 4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 5 * 6 * (C) Copyright 2008 7 * Guennadi Liakhovetski, DENX Software Engineering, lg@denx.de. 8 */ 9 10 #define _GNU_SOURCE 11 12 #include <compiler.h> 13 #include <errno.h> 14 #include <env_flags.h> 15 #include <fcntl.h> 16 #include <libgen.h> 17 #include <linux/fs.h> 18 #include <linux/stringify.h> 19 #include <ctype.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <stddef.h> 23 #include <string.h> 24 #include <sys/types.h> 25 #include <sys/ioctl.h> 26 #include <sys/stat.h> 27 #include <unistd.h> 28 #include <dirent.h> 29 30 #ifdef MTD_OLD 31 # include <stdint.h> 32 # include <linux/mtd/mtd.h> 33 #else 34 # define __user /* nothing */ 35 # include <mtd/mtd-user.h> 36 #endif 37 38 #include <mtd/ubi-user.h> 39 40 #include "fw_env_private.h" 41 #include "fw_env.h" 42 43 struct env_opts default_opts = { 44 #ifdef CONFIG_FILE 45 .config_file = CONFIG_FILE 46 #endif 47 }; 48 49 #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) 50 51 #define min(x, y) ({ \ 52 typeof(x) _min1 = (x); \ 53 typeof(y) _min2 = (y); \ 54 (void) (&_min1 == &_min2); \ 55 _min1 < _min2 ? _min1 : _min2; }) 56 57 struct envdev_s { 58 const char *devname; /* Device name */ 59 long long devoff; /* Device offset */ 60 ulong env_size; /* environment size */ 61 ulong erase_size; /* device erase size */ 62 ulong env_sectors; /* number of environment sectors */ 63 uint8_t mtd_type; /* type of the MTD device */ 64 int is_ubi; /* set if we use UBI volume */ 65 }; 66 67 static struct envdev_s envdevices[2] = { 68 { 69 .mtd_type = MTD_ABSENT, 70 }, { 71 .mtd_type = MTD_ABSENT, 72 }, 73 }; 74 75 static int dev_current; 76 77 #define DEVNAME(i) envdevices[(i)].devname 78 #define DEVOFFSET(i) envdevices[(i)].devoff 79 #define ENVSIZE(i) envdevices[(i)].env_size 80 #define DEVESIZE(i) envdevices[(i)].erase_size 81 #define ENVSECTORS(i) envdevices[(i)].env_sectors 82 #define DEVTYPE(i) envdevices[(i)].mtd_type 83 #define IS_UBI(i) envdevices[(i)].is_ubi 84 85 #define CUR_ENVSIZE ENVSIZE(dev_current) 86 87 static unsigned long usable_envsize; 88 #define ENV_SIZE usable_envsize 89 90 struct env_image_single { 91 uint32_t crc; /* CRC32 over data bytes */ 92 char data[]; 93 }; 94 95 struct env_image_redundant { 96 uint32_t crc; /* CRC32 over data bytes */ 97 unsigned char flags; /* active or obsolete */ 98 char data[]; 99 }; 100 101 enum flag_scheme { 102 FLAG_NONE, 103 FLAG_BOOLEAN, 104 FLAG_INCREMENTAL, 105 }; 106 107 struct environment { 108 void *image; 109 uint32_t *crc; 110 unsigned char *flags; 111 char *data; 112 enum flag_scheme flag_scheme; 113 }; 114 115 static struct environment environment = { 116 .flag_scheme = FLAG_NONE, 117 }; 118 119 static int have_redund_env; 120 121 static unsigned char active_flag = 1; 122 /* obsolete_flag must be 0 to efficiently set it on NOR flash without erasing */ 123 static unsigned char obsolete_flag = 0; 124 125 #define DEFAULT_ENV_INSTANCE_STATIC 126 #include <env_default.h> 127 128 #define UBI_DEV_START "/dev/ubi" 129 #define UBI_SYSFS "/sys/class/ubi" 130 #define UBI_VOL_NAME_PATT "ubi%d_%d" 131 132 static int is_ubi_devname(const char *devname) 133 { 134 return !strncmp(devname, UBI_DEV_START, sizeof(UBI_DEV_START) - 1); 135 } 136 137 static int ubi_check_volume_sysfs_name(const char *volume_sysfs_name, 138 const char *volname) 139 { 140 char path[256]; 141 FILE *file; 142 char *name; 143 int ret; 144 145 strcpy(path, UBI_SYSFS "/"); 146 strcat(path, volume_sysfs_name); 147 strcat(path, "/name"); 148 149 file = fopen(path, "r"); 150 if (!file) 151 return -1; 152 153 ret = fscanf(file, "%ms", &name); 154 fclose(file); 155 if (ret <= 0 || !name) { 156 fprintf(stderr, 157 "Failed to read from file %s, ret = %d, name = %s\n", 158 path, ret, name); 159 return -1; 160 } 161 162 if (!strcmp(name, volname)) { 163 free(name); 164 return 0; 165 } 166 free(name); 167 168 return -1; 169 } 170 171 static int ubi_get_volnum_by_name(int devnum, const char *volname) 172 { 173 DIR *sysfs_ubi; 174 struct dirent *dirent; 175 int ret; 176 int tmp_devnum; 177 int volnum; 178 179 sysfs_ubi = opendir(UBI_SYSFS); 180 if (!sysfs_ubi) 181 return -1; 182 183 #ifdef DEBUG 184 fprintf(stderr, "Looking for volume name \"%s\"\n", volname); 185 #endif 186 187 while (1) { 188 dirent = readdir(sysfs_ubi); 189 if (!dirent) 190 return -1; 191 192 ret = sscanf(dirent->d_name, UBI_VOL_NAME_PATT, 193 &tmp_devnum, &volnum); 194 if (ret == 2 && devnum == tmp_devnum) { 195 if (ubi_check_volume_sysfs_name(dirent->d_name, 196 volname) == 0) 197 return volnum; 198 } 199 } 200 201 return -1; 202 } 203 204 static int ubi_get_devnum_by_devname(const char *devname) 205 { 206 int devnum; 207 int ret; 208 209 ret = sscanf(devname + sizeof(UBI_DEV_START) - 1, "%d", &devnum); 210 if (ret != 1) 211 return -1; 212 213 return devnum; 214 } 215 216 static const char *ubi_get_volume_devname(const char *devname, 217 const char *volname) 218 { 219 char *volume_devname; 220 int volnum; 221 int devnum; 222 int ret; 223 224 devnum = ubi_get_devnum_by_devname(devname); 225 if (devnum < 0) 226 return NULL; 227 228 volnum = ubi_get_volnum_by_name(devnum, volname); 229 if (volnum < 0) 230 return NULL; 231 232 ret = asprintf(&volume_devname, "%s_%d", devname, volnum); 233 if (ret < 0) 234 return NULL; 235 236 #ifdef DEBUG 237 fprintf(stderr, "Found ubi volume \"%s:%s\" -> %s\n", 238 devname, volname, volume_devname); 239 #endif 240 241 return volume_devname; 242 } 243 244 static void ubi_check_dev(unsigned int dev_id) 245 { 246 char *devname = (char *)DEVNAME(dev_id); 247 char *pname; 248 const char *volname = NULL; 249 const char *volume_devname; 250 251 if (!is_ubi_devname(DEVNAME(dev_id))) 252 return; 253 254 IS_UBI(dev_id) = 1; 255 256 for (pname = devname; *pname != '\0'; pname++) { 257 if (*pname == ':') { 258 *pname = '\0'; 259 volname = pname + 1; 260 break; 261 } 262 } 263 264 if (volname) { 265 /* Let's find real volume device name */ 266 volume_devname = ubi_get_volume_devname(devname, volname); 267 if (!volume_devname) { 268 fprintf(stderr, "Didn't found ubi volume \"%s\"\n", 269 volname); 270 return; 271 } 272 273 free(devname); 274 DEVNAME(dev_id) = volume_devname; 275 } 276 } 277 278 static int ubi_update_start(int fd, int64_t bytes) 279 { 280 if (ioctl(fd, UBI_IOCVOLUP, &bytes)) 281 return -1; 282 return 0; 283 } 284 285 static int ubi_read(int fd, void *buf, size_t count) 286 { 287 ssize_t ret; 288 289 while (count > 0) { 290 ret = read(fd, buf, count); 291 if (ret > 0) { 292 count -= ret; 293 buf += ret; 294 295 continue; 296 } 297 298 if (ret == 0) { 299 /* 300 * Happens in case of too short volume data size. If we 301 * return error status we will fail it will be treated 302 * as UBI device error. 303 * 304 * Leave catching this error to CRC check. 305 */ 306 fprintf(stderr, "Warning: end of data on ubi volume\n"); 307 return 0; 308 } else if (errno == EBADF) { 309 /* 310 * Happens in case of corrupted volume. The same as 311 * above, we cannot return error now, as we will still 312 * be able to successfully write environment later. 313 */ 314 fprintf(stderr, "Warning: corrupted volume?\n"); 315 return 0; 316 } else if (errno == EINTR) { 317 continue; 318 } 319 320 fprintf(stderr, "Cannot read %u bytes from ubi volume, %s\n", 321 (unsigned int)count, strerror(errno)); 322 return -1; 323 } 324 325 return 0; 326 } 327 328 static int ubi_write(int fd, const void *buf, size_t count) 329 { 330 ssize_t ret; 331 332 while (count > 0) { 333 ret = write(fd, buf, count); 334 if (ret <= 0) { 335 if (ret < 0 && errno == EINTR) 336 continue; 337 338 fprintf(stderr, "Cannot write %u bytes to ubi volume\n", 339 (unsigned int)count); 340 return -1; 341 } 342 343 count -= ret; 344 buf += ret; 345 } 346 347 return 0; 348 } 349 350 static int flash_io(int mode); 351 static int parse_config(struct env_opts *opts); 352 353 #if defined(CONFIG_FILE) 354 static int get_config(char *); 355 #endif 356 357 static char *skip_chars(char *s) 358 { 359 for (; *s != '\0'; s++) { 360 if (isblank(*s) || *s == '=') 361 return s; 362 } 363 return NULL; 364 } 365 366 static char *skip_blanks(char *s) 367 { 368 for (; *s != '\0'; s++) { 369 if (!isblank(*s)) 370 return s; 371 } 372 return NULL; 373 } 374 375 /* 376 * s1 is either a simple 'name', or a 'name=value' pair. 377 * s2 is a 'name=value' pair. 378 * If the names match, return the value of s2, else NULL. 379 */ 380 static char *envmatch(char *s1, char *s2) 381 { 382 if (s1 == NULL || s2 == NULL) 383 return NULL; 384 385 while (*s1 == *s2++) 386 if (*s1++ == '=') 387 return s2; 388 if (*s1 == '\0' && *(s2 - 1) == '=') 389 return s2; 390 return NULL; 391 } 392 393 /** 394 * Search the environment for a variable. 395 * Return the value, if found, or NULL, if not found. 396 */ 397 char *fw_getenv(char *name) 398 { 399 char *env, *nxt; 400 401 for (env = environment.data; *env; env = nxt + 1) { 402 char *val; 403 404 for (nxt = env; *nxt; ++nxt) { 405 if (nxt >= &environment.data[ENV_SIZE]) { 406 fprintf(stderr, "## Error: " 407 "environment not terminated\n"); 408 return NULL; 409 } 410 } 411 val = envmatch(name, env); 412 if (!val) 413 continue; 414 return val; 415 } 416 return NULL; 417 } 418 419 /* 420 * Search the default environment for a variable. 421 * Return the value, if found, or NULL, if not found. 422 */ 423 char *fw_getdefenv(char *name) 424 { 425 char *env, *nxt; 426 427 for (env = default_environment; *env; env = nxt + 1) { 428 char *val; 429 430 for (nxt = env; *nxt; ++nxt) { 431 if (nxt >= &default_environment[ENV_SIZE]) { 432 fprintf(stderr, "## Error: " 433 "default environment not terminated\n"); 434 return NULL; 435 } 436 } 437 val = envmatch(name, env); 438 if (!val) 439 continue; 440 return val; 441 } 442 return NULL; 443 } 444 445 /* 446 * Print the current definition of one, or more, or all 447 * environment variables 448 */ 449 int fw_printenv(int argc, char *argv[], int value_only, struct env_opts *opts) 450 { 451 int i, rc = 0; 452 453 if (value_only && argc != 1) { 454 fprintf(stderr, 455 "## Error: `-n'/`--noheader' option requires exactly one argument\n"); 456 return -1; 457 } 458 459 if (!opts) 460 opts = &default_opts; 461 462 if (fw_env_open(opts)) 463 return -1; 464 465 if (argc == 0) { /* Print all env variables */ 466 char *env, *nxt; 467 for (env = environment.data; *env; env = nxt + 1) { 468 for (nxt = env; *nxt; ++nxt) { 469 if (nxt >= &environment.data[ENV_SIZE]) { 470 fprintf(stderr, "## Error: " 471 "environment not terminated\n"); 472 return -1; 473 } 474 } 475 476 printf("%s\n", env); 477 } 478 fw_env_close(opts); 479 return 0; 480 } 481 482 for (i = 0; i < argc; ++i) { /* print a subset of env variables */ 483 char *name = argv[i]; 484 char *val = NULL; 485 486 val = fw_getenv(name); 487 if (!val) { 488 fprintf(stderr, "## Error: \"%s\" not defined\n", name); 489 rc = -1; 490 continue; 491 } 492 493 if (value_only) { 494 puts(val); 495 break; 496 } 497 498 printf("%s=%s\n", name, val); 499 } 500 501 fw_env_close(opts); 502 503 return rc; 504 } 505 506 int fw_env_flush(struct env_opts *opts) 507 { 508 if (!opts) 509 opts = &default_opts; 510 511 /* 512 * Update CRC 513 */ 514 *environment.crc = crc32(0, (uint8_t *) environment.data, ENV_SIZE); 515 516 /* write environment back to flash */ 517 if (flash_io(O_RDWR)) { 518 fprintf(stderr, "Error: can't write fw_env to flash\n"); 519 return -1; 520 } 521 522 return 0; 523 } 524 525 /* 526 * Set/Clear a single variable in the environment. 527 * This is called in sequence to update the environment 528 * in RAM without updating the copy in flash after each set 529 */ 530 int fw_env_write(char *name, char *value) 531 { 532 int len; 533 char *env, *nxt; 534 char *oldval = NULL; 535 int deleting, creating, overwriting; 536 537 /* 538 * search if variable with this name already exists 539 */ 540 for (nxt = env = environment.data; *env; env = nxt + 1) { 541 for (nxt = env; *nxt; ++nxt) { 542 if (nxt >= &environment.data[ENV_SIZE]) { 543 fprintf(stderr, "## Error: " 544 "environment not terminated\n"); 545 errno = EINVAL; 546 return -1; 547 } 548 } 549 oldval = envmatch(name, env); 550 if (oldval) 551 break; 552 } 553 554 deleting = (oldval && !(value && strlen(value))); 555 creating = (!oldval && (value && strlen(value))); 556 overwriting = (oldval && (value && strlen(value))); 557 558 /* check for permission */ 559 if (deleting) { 560 if (env_flags_validate_varaccess(name, 561 ENV_FLAGS_VARACCESS_PREVENT_DELETE)) { 562 printf("Can't delete \"%s\"\n", name); 563 errno = EROFS; 564 return -1; 565 } 566 } else if (overwriting) { 567 if (env_flags_validate_varaccess(name, 568 ENV_FLAGS_VARACCESS_PREVENT_OVERWR)) { 569 printf("Can't overwrite \"%s\"\n", name); 570 errno = EROFS; 571 return -1; 572 } else if (env_flags_validate_varaccess(name, 573 ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR)) { 574 const char *defval = fw_getdefenv(name); 575 576 if (defval == NULL) 577 defval = ""; 578 if (strcmp(oldval, defval) 579 != 0) { 580 printf("Can't overwrite \"%s\"\n", name); 581 errno = EROFS; 582 return -1; 583 } 584 } 585 } else if (creating) { 586 if (env_flags_validate_varaccess(name, 587 ENV_FLAGS_VARACCESS_PREVENT_CREATE)) { 588 printf("Can't create \"%s\"\n", name); 589 errno = EROFS; 590 return -1; 591 } 592 } else 593 /* Nothing to do */ 594 return 0; 595 596 if (deleting || overwriting) { 597 if (*++nxt == '\0') { 598 *env = '\0'; 599 } else { 600 for (;;) { 601 *env = *nxt++; 602 if ((*env == '\0') && (*nxt == '\0')) 603 break; 604 ++env; 605 } 606 } 607 *++env = '\0'; 608 } 609 610 /* Delete only ? */ 611 if (!value || !strlen(value)) 612 return 0; 613 614 /* 615 * Append new definition at the end 616 */ 617 for (env = environment.data; *env || *(env + 1); ++env) 618 ; 619 if (env > environment.data) 620 ++env; 621 /* 622 * Overflow when: 623 * "name" + "=" + "val" +"\0\0" > CUR_ENVSIZE - (env-environment) 624 */ 625 len = strlen(name) + 2; 626 /* add '=' for first arg, ' ' for all others */ 627 len += strlen(value) + 1; 628 629 if (len > (&environment.data[ENV_SIZE] - env)) { 630 fprintf(stderr, 631 "Error: environment overflow, \"%s\" deleted\n", name); 632 return -1; 633 } 634 635 while ((*env = *name++) != '\0') 636 env++; 637 *env = '='; 638 while ((*++env = *value++) != '\0') 639 ; 640 641 /* end is marked with double '\0' */ 642 *++env = '\0'; 643 644 return 0; 645 } 646 647 /* 648 * Deletes or sets environment variables. Returns -1 and sets errno error codes: 649 * 0 - OK 650 * EINVAL - need at least 1 argument 651 * EROFS - certain variables ("ethaddr", "serial#") cannot be 652 * modified or deleted 653 * 654 */ 655 int fw_env_set(int argc, char *argv[], struct env_opts *opts) 656 { 657 int i; 658 size_t len; 659 char *name, **valv; 660 char *oldval; 661 char *value = NULL; 662 int valc; 663 int ret; 664 665 if (!opts) 666 opts = &default_opts; 667 668 if (argc < 1) { 669 fprintf(stderr, "## Error: variable name missing\n"); 670 errno = EINVAL; 671 return -1; 672 } 673 674 if (fw_env_open(opts)) { 675 fprintf(stderr, "Error: environment not initialized\n"); 676 return -1; 677 } 678 679 name = argv[0]; 680 valv = argv + 1; 681 valc = argc - 1; 682 683 if (env_flags_validate_env_set_params(name, valv, valc) < 0) { 684 fw_env_close(opts); 685 return -1; 686 } 687 688 len = 0; 689 for (i = 0; i < valc; ++i) { 690 char *val = valv[i]; 691 size_t val_len = strlen(val); 692 693 if (value) 694 value[len - 1] = ' '; 695 oldval = value; 696 value = realloc(value, len + val_len + 1); 697 if (!value) { 698 fprintf(stderr, 699 "Cannot malloc %zu bytes: %s\n", 700 len, strerror(errno)); 701 free(oldval); 702 return -1; 703 } 704 705 memcpy(value + len, val, val_len); 706 len += val_len; 707 value[len++] = '\0'; 708 } 709 710 fw_env_write(name, value); 711 712 free(value); 713 714 ret = fw_env_flush(opts); 715 fw_env_close(opts); 716 717 return ret; 718 } 719 720 /* 721 * Parse a file and configure the u-boot variables. 722 * The script file has a very simple format, as follows: 723 * 724 * Each line has a couple with name, value: 725 * <white spaces>variable_name<white spaces>variable_value 726 * 727 * Both variable_name and variable_value are interpreted as strings. 728 * Any character after <white spaces> and before ending \r\n is interpreted 729 * as variable's value (no comment allowed on these lines !) 730 * 731 * Comments are allowed if the first character in the line is # 732 * 733 * Returns -1 and sets errno error codes: 734 * 0 - OK 735 * -1 - Error 736 */ 737 int fw_parse_script(char *fname, struct env_opts *opts) 738 { 739 FILE *fp; 740 char dump[1024]; /* Maximum line length in the file */ 741 char *name; 742 char *val; 743 int lineno = 0; 744 int len; 745 int ret = 0; 746 747 if (!opts) 748 opts = &default_opts; 749 750 if (fw_env_open(opts)) { 751 fprintf(stderr, "Error: environment not initialized\n"); 752 return -1; 753 } 754 755 if (strcmp(fname, "-") == 0) 756 fp = stdin; 757 else { 758 fp = fopen(fname, "r"); 759 if (fp == NULL) { 760 fprintf(stderr, "I cannot open %s for reading\n", 761 fname); 762 return -1; 763 } 764 } 765 766 while (fgets(dump, sizeof(dump), fp)) { 767 lineno++; 768 len = strlen(dump); 769 770 /* 771 * Read a whole line from the file. If the line is too long 772 * or is not terminated, reports an error and exit. 773 */ 774 if (dump[len - 1] != '\n') { 775 fprintf(stderr, 776 "Line %d not corrected terminated or too long\n", 777 lineno); 778 ret = -1; 779 break; 780 } 781 782 /* Drop ending line feed / carriage return */ 783 dump[--len] = '\0'; 784 if (len && dump[len - 1] == '\r') 785 dump[--len] = '\0'; 786 787 /* Skip comment or empty lines */ 788 if (len == 0 || dump[0] == '#') 789 continue; 790 791 /* 792 * Search for variable's name, 793 * remove leading whitespaces 794 */ 795 name = skip_blanks(dump); 796 if (!name) 797 continue; 798 799 /* The first white space is the end of variable name */ 800 val = skip_chars(name); 801 len = strlen(name); 802 if (val) { 803 *val++ = '\0'; 804 if ((val - name) < len) 805 val = skip_blanks(val); 806 else 807 val = NULL; 808 } 809 #ifdef DEBUG 810 fprintf(stderr, "Setting %s : %s\n", 811 name, val ? val : " removed"); 812 #endif 813 814 if (env_flags_validate_type(name, val) < 0) { 815 ret = -1; 816 break; 817 } 818 819 /* 820 * If there is an error setting a variable, 821 * try to save the environment and returns an error 822 */ 823 if (fw_env_write(name, val)) { 824 fprintf(stderr, 825 "fw_env_write returns with error : %s\n", 826 strerror(errno)); 827 ret = -1; 828 break; 829 } 830 831 } 832 833 /* Close file if not stdin */ 834 if (strcmp(fname, "-") != 0) 835 fclose(fp); 836 837 ret |= fw_env_flush(opts); 838 839 fw_env_close(opts); 840 841 return ret; 842 } 843 844 /** 845 * environment_end() - compute offset of first byte right after environemnt 846 * @dev - index of enviroment buffer 847 * Return: 848 * device offset of first byte right after environemnt 849 */ 850 off_t environment_end(int dev) 851 { 852 /* environment is block aligned */ 853 return DEVOFFSET(dev) + ENVSECTORS(dev) * DEVESIZE(dev); 854 } 855 856 /* 857 * Test for bad block on NAND, just returns 0 on NOR, on NAND: 858 * 0 - block is good 859 * > 0 - block is bad 860 * < 0 - failed to test 861 */ 862 static int flash_bad_block(int fd, uint8_t mtd_type, loff_t blockstart) 863 { 864 if (mtd_type == MTD_NANDFLASH) { 865 int badblock = ioctl(fd, MEMGETBADBLOCK, &blockstart); 866 867 if (badblock < 0) { 868 perror("Cannot read bad block mark"); 869 return badblock; 870 } 871 872 if (badblock) { 873 #ifdef DEBUG 874 fprintf(stderr, "Bad block at 0x%llx, skipping\n", 875 (unsigned long long)blockstart); 876 #endif 877 return badblock; 878 } 879 } 880 881 return 0; 882 } 883 884 /* 885 * Read data from flash at an offset into a provided buffer. On NAND it skips 886 * bad blocks but makes sure it stays within ENVSECTORS (dev) starting from 887 * the DEVOFFSET (dev) block. On NOR the loop is only run once. 888 */ 889 static int flash_read_buf(int dev, int fd, void *buf, size_t count, 890 off_t offset) 891 { 892 size_t blocklen; /* erase / write length - one block on NAND, 893 0 on NOR */ 894 size_t processed = 0; /* progress counter */ 895 size_t readlen = count; /* current read length */ 896 off_t block_seek; /* offset inside the current block to the start 897 of the data */ 898 loff_t blockstart; /* running start of the current block - 899 MEMGETBADBLOCK needs 64 bits */ 900 int rc; 901 902 blockstart = (offset / DEVESIZE(dev)) * DEVESIZE(dev); 903 904 /* Offset inside a block */ 905 block_seek = offset - blockstart; 906 907 if (DEVTYPE(dev) == MTD_NANDFLASH) { 908 /* 909 * NAND: calculate which blocks we are reading. We have 910 * to read one block at a time to skip bad blocks. 911 */ 912 blocklen = DEVESIZE(dev); 913 914 /* Limit to one block for the first read */ 915 if (readlen > blocklen - block_seek) 916 readlen = blocklen - block_seek; 917 } else { 918 blocklen = 0; 919 } 920 921 /* This only runs once on NOR flash */ 922 while (processed < count) { 923 rc = flash_bad_block(fd, DEVTYPE(dev), blockstart); 924 if (rc < 0) /* block test failed */ 925 return -1; 926 927 if (blockstart + block_seek + readlen > environment_end(dev)) { 928 /* End of range is reached */ 929 fprintf(stderr, "Too few good blocks within range\n"); 930 return -1; 931 } 932 933 if (rc) { /* block is bad */ 934 blockstart += blocklen; 935 continue; 936 } 937 938 /* 939 * If a block is bad, we retry in the next block at the same 940 * offset - see env/nand.c::writeenv() 941 */ 942 lseek(fd, blockstart + block_seek, SEEK_SET); 943 944 rc = read(fd, buf + processed, readlen); 945 if (rc != readlen) { 946 fprintf(stderr, "Read error on %s: %s\n", 947 DEVNAME(dev), strerror(errno)); 948 return -1; 949 } 950 #ifdef DEBUG 951 fprintf(stderr, "Read 0x%x bytes at 0x%llx on %s\n", 952 rc, (unsigned long long)blockstart + block_seek, 953 DEVNAME(dev)); 954 #endif 955 processed += readlen; 956 readlen = min(blocklen, count - processed); 957 block_seek = 0; 958 blockstart += blocklen; 959 } 960 961 return processed; 962 } 963 964 /* 965 * Write count bytes from begin of environment, but stay within 966 * ENVSECTORS(dev) sectors of 967 * DEVOFFSET (dev). Similar to the read case above, on NOR and dataflash we 968 * erase and write the whole data at once. 969 */ 970 static int flash_write_buf(int dev, int fd, void *buf, size_t count) 971 { 972 void *data; 973 struct erase_info_user erase; 974 size_t blocklen; /* length of NAND block / NOR erase sector */ 975 size_t erase_len; /* whole area that can be erased - may include 976 bad blocks */ 977 size_t erasesize; /* erase / write length - one block on NAND, 978 whole area on NOR */ 979 size_t processed = 0; /* progress counter */ 980 size_t write_total; /* total size to actually write - excluding 981 bad blocks */ 982 off_t erase_offset; /* offset to the first erase block (aligned) 983 below offset */ 984 off_t block_seek; /* offset inside the erase block to the start 985 of the data */ 986 loff_t blockstart; /* running start of the current block - 987 MEMGETBADBLOCK needs 64 bits */ 988 int rc; 989 990 /* 991 * For mtd devices only offset and size of the environment do matter 992 */ 993 if (DEVTYPE(dev) == MTD_ABSENT) { 994 blocklen = count; 995 erase_len = blocklen; 996 blockstart = DEVOFFSET(dev); 997 block_seek = 0; 998 write_total = blocklen; 999 } else { 1000 blocklen = DEVESIZE(dev); 1001 1002 erase_offset = DEVOFFSET(dev); 1003 1004 /* Maximum area we may use */ 1005 erase_len = environment_end(dev) - erase_offset; 1006 1007 blockstart = erase_offset; 1008 1009 /* Offset inside a block */ 1010 block_seek = DEVOFFSET(dev) - erase_offset; 1011 1012 /* 1013 * Data size we actually write: from the start of the block 1014 * to the start of the data, then count bytes of data, and 1015 * to the end of the block 1016 */ 1017 write_total = ((block_seek + count + blocklen - 1) / 1018 blocklen) * blocklen; 1019 } 1020 1021 /* 1022 * Support data anywhere within erase sectors: read out the complete 1023 * area to be erased, replace the environment image, write the whole 1024 * block back again. 1025 */ 1026 if (write_total > count) { 1027 data = malloc(erase_len); 1028 if (!data) { 1029 fprintf(stderr, 1030 "Cannot malloc %zu bytes: %s\n", 1031 erase_len, strerror(errno)); 1032 return -1; 1033 } 1034 1035 rc = flash_read_buf(dev, fd, data, write_total, erase_offset); 1036 if (write_total != rc) 1037 return -1; 1038 1039 #ifdef DEBUG 1040 fprintf(stderr, "Preserving data "); 1041 if (block_seek != 0) 1042 fprintf(stderr, "0x%x - 0x%lx", 0, block_seek - 1); 1043 if (block_seek + count != write_total) { 1044 if (block_seek != 0) 1045 fprintf(stderr, " and "); 1046 fprintf(stderr, "0x%lx - 0x%lx", 1047 (unsigned long)block_seek + count, 1048 (unsigned long)write_total - 1); 1049 } 1050 fprintf(stderr, "\n"); 1051 #endif 1052 /* Overwrite the old environment */ 1053 memcpy(data + block_seek, buf, count); 1054 } else { 1055 /* 1056 * We get here, iff offset is block-aligned and count is a 1057 * multiple of blocklen - see write_total calculation above 1058 */ 1059 data = buf; 1060 } 1061 1062 if (DEVTYPE(dev) == MTD_NANDFLASH) { 1063 /* 1064 * NAND: calculate which blocks we are writing. We have 1065 * to write one block at a time to skip bad blocks. 1066 */ 1067 erasesize = blocklen; 1068 } else { 1069 erasesize = erase_len; 1070 } 1071 1072 erase.length = erasesize; 1073 1074 /* This only runs once on NOR flash and SPI-dataflash */ 1075 while (processed < write_total) { 1076 rc = flash_bad_block(fd, DEVTYPE(dev), blockstart); 1077 if (rc < 0) /* block test failed */ 1078 return rc; 1079 1080 if (blockstart + erasesize > environment_end(dev)) { 1081 fprintf(stderr, "End of range reached, aborting\n"); 1082 return -1; 1083 } 1084 1085 if (rc) { /* block is bad */ 1086 blockstart += blocklen; 1087 continue; 1088 } 1089 1090 if (DEVTYPE(dev) != MTD_ABSENT) { 1091 erase.start = blockstart; 1092 ioctl(fd, MEMUNLOCK, &erase); 1093 /* These do not need an explicit erase cycle */ 1094 if (DEVTYPE(dev) != MTD_DATAFLASH) 1095 if (ioctl(fd, MEMERASE, &erase) != 0) { 1096 fprintf(stderr, 1097 "MTD erase error on %s: %s\n", 1098 DEVNAME(dev), strerror(errno)); 1099 return -1; 1100 } 1101 } 1102 1103 if (lseek(fd, blockstart, SEEK_SET) == -1) { 1104 fprintf(stderr, 1105 "Seek error on %s: %s\n", 1106 DEVNAME(dev), strerror(errno)); 1107 return -1; 1108 } 1109 #ifdef DEBUG 1110 fprintf(stderr, "Write 0x%llx bytes at 0x%llx\n", 1111 (unsigned long long)erasesize, 1112 (unsigned long long)blockstart); 1113 #endif 1114 if (write(fd, data + processed, erasesize) != erasesize) { 1115 fprintf(stderr, "Write error on %s: %s\n", 1116 DEVNAME(dev), strerror(errno)); 1117 return -1; 1118 } 1119 1120 if (DEVTYPE(dev) != MTD_ABSENT) 1121 ioctl(fd, MEMLOCK, &erase); 1122 1123 processed += erasesize; 1124 block_seek = 0; 1125 blockstart += erasesize; 1126 } 1127 1128 if (write_total > count) 1129 free(data); 1130 1131 return processed; 1132 } 1133 1134 /* 1135 * Set obsolete flag at offset - NOR flash only 1136 */ 1137 static int flash_flag_obsolete(int dev, int fd, off_t offset) 1138 { 1139 int rc; 1140 struct erase_info_user erase; 1141 1142 erase.start = DEVOFFSET(dev); 1143 erase.length = DEVESIZE(dev); 1144 /* This relies on the fact, that obsolete_flag == 0 */ 1145 rc = lseek(fd, offset, SEEK_SET); 1146 if (rc < 0) { 1147 fprintf(stderr, "Cannot seek to set the flag on %s\n", 1148 DEVNAME(dev)); 1149 return rc; 1150 } 1151 ioctl(fd, MEMUNLOCK, &erase); 1152 rc = write(fd, &obsolete_flag, sizeof(obsolete_flag)); 1153 ioctl(fd, MEMLOCK, &erase); 1154 if (rc < 0) 1155 perror("Could not set obsolete flag"); 1156 1157 return rc; 1158 } 1159 1160 static int flash_write(int fd_current, int fd_target, int dev_target) 1161 { 1162 int rc; 1163 1164 switch (environment.flag_scheme) { 1165 case FLAG_NONE: 1166 break; 1167 case FLAG_INCREMENTAL: 1168 (*environment.flags)++; 1169 break; 1170 case FLAG_BOOLEAN: 1171 *environment.flags = active_flag; 1172 break; 1173 default: 1174 fprintf(stderr, "Unimplemented flash scheme %u\n", 1175 environment.flag_scheme); 1176 return -1; 1177 } 1178 1179 #ifdef DEBUG 1180 fprintf(stderr, "Writing new environment at 0x%llx on %s\n", 1181 DEVOFFSET(dev_target), DEVNAME(dev_target)); 1182 #endif 1183 1184 if (IS_UBI(dev_target)) { 1185 if (ubi_update_start(fd_target, CUR_ENVSIZE) < 0) 1186 return 0; 1187 return ubi_write(fd_target, environment.image, CUR_ENVSIZE); 1188 } 1189 1190 rc = flash_write_buf(dev_target, fd_target, environment.image, 1191 CUR_ENVSIZE); 1192 if (rc < 0) 1193 return rc; 1194 1195 if (environment.flag_scheme == FLAG_BOOLEAN) { 1196 /* Have to set obsolete flag */ 1197 off_t offset = DEVOFFSET(dev_current) + 1198 offsetof(struct env_image_redundant, flags); 1199 #ifdef DEBUG 1200 fprintf(stderr, 1201 "Setting obsolete flag in environment at 0x%llx on %s\n", 1202 DEVOFFSET(dev_current), DEVNAME(dev_current)); 1203 #endif 1204 flash_flag_obsolete(dev_current, fd_current, offset); 1205 } 1206 1207 return 0; 1208 } 1209 1210 static int flash_read(int fd) 1211 { 1212 int rc; 1213 1214 if (IS_UBI(dev_current)) { 1215 DEVTYPE(dev_current) = MTD_ABSENT; 1216 1217 return ubi_read(fd, environment.image, CUR_ENVSIZE); 1218 } 1219 1220 rc = flash_read_buf(dev_current, fd, environment.image, CUR_ENVSIZE, 1221 DEVOFFSET(dev_current)); 1222 if (rc != CUR_ENVSIZE) 1223 return -1; 1224 1225 return 0; 1226 } 1227 1228 static int flash_open_tempfile(const char **dname, const char **target_temp) 1229 { 1230 char *dup_name = strdup(DEVNAME(dev_current)); 1231 char *temp_name = NULL; 1232 int rc = -1; 1233 1234 if (!dup_name) 1235 return -1; 1236 1237 *dname = dirname(dup_name); 1238 if (!*dname) 1239 goto err; 1240 1241 rc = asprintf(&temp_name, "%s/XXXXXX", *dname); 1242 if (rc == -1) 1243 goto err; 1244 1245 rc = mkstemp(temp_name); 1246 if (rc == -1) { 1247 /* fall back to in place write */ 1248 fprintf(stderr, 1249 "Can't create %s: %s\n", temp_name, strerror(errno)); 1250 free(temp_name); 1251 } else { 1252 *target_temp = temp_name; 1253 /* deliberately leak dup_name as dname /might/ point into 1254 * it and we need it for our caller 1255 */ 1256 dup_name = NULL; 1257 } 1258 1259 err: 1260 if (dup_name) 1261 free(dup_name); 1262 1263 return rc; 1264 } 1265 1266 static int flash_io_write(int fd_current) 1267 { 1268 int fd_target = -1, rc, dev_target; 1269 const char *dname, *target_temp = NULL; 1270 1271 if (have_redund_env) { 1272 /* switch to next partition for writing */ 1273 dev_target = !dev_current; 1274 /* dev_target: fd_target, erase_target */ 1275 fd_target = open(DEVNAME(dev_target), O_RDWR); 1276 if (fd_target < 0) { 1277 fprintf(stderr, 1278 "Can't open %s: %s\n", 1279 DEVNAME(dev_target), strerror(errno)); 1280 rc = -1; 1281 goto exit; 1282 } 1283 } else { 1284 struct stat sb; 1285 1286 if (fstat(fd_current, &sb) == 0 && S_ISREG(sb.st_mode)) { 1287 /* if any part of flash_open_tempfile() fails we fall 1288 * back to in-place writes 1289 */ 1290 fd_target = flash_open_tempfile(&dname, &target_temp); 1291 } 1292 dev_target = dev_current; 1293 if (fd_target == -1) 1294 fd_target = fd_current; 1295 } 1296 1297 rc = flash_write(fd_current, fd_target, dev_target); 1298 1299 if (fsync(fd_current) && !(errno == EINVAL || errno == EROFS)) { 1300 fprintf(stderr, 1301 "fsync failed on %s: %s\n", 1302 DEVNAME(dev_current), strerror(errno)); 1303 } 1304 1305 if (fd_current != fd_target) { 1306 if (fsync(fd_target) && 1307 !(errno == EINVAL || errno == EROFS)) { 1308 fprintf(stderr, 1309 "fsync failed on %s: %s\n", 1310 DEVNAME(dev_current), strerror(errno)); 1311 } 1312 1313 if (close(fd_target)) { 1314 fprintf(stderr, 1315 "I/O error on %s: %s\n", 1316 DEVNAME(dev_target), strerror(errno)); 1317 rc = -1; 1318 } 1319 1320 if (target_temp) { 1321 int dir_fd; 1322 1323 dir_fd = open(dname, O_DIRECTORY | O_RDONLY); 1324 if (dir_fd == -1) 1325 fprintf(stderr, 1326 "Can't open %s: %s\n", 1327 dname, strerror(errno)); 1328 1329 if (rename(target_temp, DEVNAME(dev_target))) { 1330 fprintf(stderr, 1331 "rename failed %s => %s: %s\n", 1332 target_temp, DEVNAME(dev_target), 1333 strerror(errno)); 1334 rc = -1; 1335 } 1336 1337 if (dir_fd != -1 && fsync(dir_fd)) 1338 fprintf(stderr, 1339 "fsync failed on %s: %s\n", 1340 dname, strerror(errno)); 1341 1342 if (dir_fd != -1 && close(dir_fd)) 1343 fprintf(stderr, 1344 "I/O error on %s: %s\n", 1345 dname, strerror(errno)); 1346 } 1347 } 1348 exit: 1349 return rc; 1350 } 1351 1352 static int flash_io(int mode) 1353 { 1354 int fd_current, rc; 1355 1356 /* dev_current: fd_current, erase_current */ 1357 fd_current = open(DEVNAME(dev_current), mode); 1358 if (fd_current < 0) { 1359 fprintf(stderr, 1360 "Can't open %s: %s\n", 1361 DEVNAME(dev_current), strerror(errno)); 1362 return -1; 1363 } 1364 1365 if (mode == O_RDWR) { 1366 rc = flash_io_write(fd_current); 1367 } else { 1368 rc = flash_read(fd_current); 1369 } 1370 1371 if (close(fd_current)) { 1372 fprintf(stderr, 1373 "I/O error on %s: %s\n", 1374 DEVNAME(dev_current), strerror(errno)); 1375 return -1; 1376 } 1377 1378 return rc; 1379 } 1380 1381 /* 1382 * Prevent confusion if running from erased flash memory 1383 */ 1384 int fw_env_open(struct env_opts *opts) 1385 { 1386 int crc0, crc0_ok; 1387 unsigned char flag0; 1388 void *addr0 = NULL; 1389 1390 int crc1, crc1_ok; 1391 unsigned char flag1; 1392 void *addr1 = NULL; 1393 1394 int ret; 1395 1396 struct env_image_single *single; 1397 struct env_image_redundant *redundant; 1398 1399 if (!opts) 1400 opts = &default_opts; 1401 1402 if (parse_config(opts)) /* should fill envdevices */ 1403 return -EINVAL; 1404 1405 addr0 = calloc(1, CUR_ENVSIZE); 1406 if (addr0 == NULL) { 1407 fprintf(stderr, 1408 "Not enough memory for environment (%ld bytes)\n", 1409 CUR_ENVSIZE); 1410 ret = -ENOMEM; 1411 goto open_cleanup; 1412 } 1413 1414 /* read environment from FLASH to local buffer */ 1415 environment.image = addr0; 1416 1417 if (have_redund_env) { 1418 redundant = addr0; 1419 environment.crc = &redundant->crc; 1420 environment.flags = &redundant->flags; 1421 environment.data = redundant->data; 1422 } else { 1423 single = addr0; 1424 environment.crc = &single->crc; 1425 environment.flags = NULL; 1426 environment.data = single->data; 1427 } 1428 1429 dev_current = 0; 1430 if (flash_io(O_RDONLY)) { 1431 ret = -EIO; 1432 goto open_cleanup; 1433 } 1434 1435 crc0 = crc32(0, (uint8_t *)environment.data, ENV_SIZE); 1436 1437 crc0_ok = (crc0 == *environment.crc); 1438 if (!have_redund_env) { 1439 if (!crc0_ok) { 1440 fprintf(stderr, 1441 "Warning: Bad CRC, using default environment\n"); 1442 memcpy(environment.data, default_environment, 1443 sizeof(default_environment)); 1444 } 1445 } else { 1446 flag0 = *environment.flags; 1447 1448 dev_current = 1; 1449 addr1 = calloc(1, CUR_ENVSIZE); 1450 if (addr1 == NULL) { 1451 fprintf(stderr, 1452 "Not enough memory for environment (%ld bytes)\n", 1453 CUR_ENVSIZE); 1454 ret = -ENOMEM; 1455 goto open_cleanup; 1456 } 1457 redundant = addr1; 1458 1459 /* 1460 * have to set environment.image for flash_read(), careful - 1461 * other pointers in environment still point inside addr0 1462 */ 1463 environment.image = addr1; 1464 if (flash_io(O_RDONLY)) { 1465 ret = -EIO; 1466 goto open_cleanup; 1467 } 1468 1469 /* Check flag scheme compatibility */ 1470 if (DEVTYPE(dev_current) == MTD_NORFLASH && 1471 DEVTYPE(!dev_current) == MTD_NORFLASH) { 1472 environment.flag_scheme = FLAG_BOOLEAN; 1473 } else if (DEVTYPE(dev_current) == MTD_NANDFLASH && 1474 DEVTYPE(!dev_current) == MTD_NANDFLASH) { 1475 environment.flag_scheme = FLAG_INCREMENTAL; 1476 } else if (DEVTYPE(dev_current) == MTD_DATAFLASH && 1477 DEVTYPE(!dev_current) == MTD_DATAFLASH) { 1478 environment.flag_scheme = FLAG_BOOLEAN; 1479 } else if (DEVTYPE(dev_current) == MTD_UBIVOLUME && 1480 DEVTYPE(!dev_current) == MTD_UBIVOLUME) { 1481 environment.flag_scheme = FLAG_INCREMENTAL; 1482 } else if (DEVTYPE(dev_current) == MTD_ABSENT && 1483 DEVTYPE(!dev_current) == MTD_ABSENT && 1484 IS_UBI(dev_current) == IS_UBI(!dev_current)) { 1485 environment.flag_scheme = FLAG_INCREMENTAL; 1486 } else { 1487 fprintf(stderr, "Incompatible flash types!\n"); 1488 ret = -EINVAL; 1489 goto open_cleanup; 1490 } 1491 1492 crc1 = crc32(0, (uint8_t *)redundant->data, ENV_SIZE); 1493 1494 crc1_ok = (crc1 == redundant->crc); 1495 flag1 = redundant->flags; 1496 1497 if (crc0_ok && !crc1_ok) { 1498 dev_current = 0; 1499 } else if (!crc0_ok && crc1_ok) { 1500 dev_current = 1; 1501 } else if (!crc0_ok && !crc1_ok) { 1502 fprintf(stderr, 1503 "Warning: Bad CRC, using default environment\n"); 1504 memcpy(environment.data, default_environment, 1505 sizeof(default_environment)); 1506 dev_current = 0; 1507 } else { 1508 switch (environment.flag_scheme) { 1509 case FLAG_BOOLEAN: 1510 if (flag0 == active_flag && 1511 flag1 == obsolete_flag) { 1512 dev_current = 0; 1513 } else if (flag0 == obsolete_flag && 1514 flag1 == active_flag) { 1515 dev_current = 1; 1516 } else if (flag0 == flag1) { 1517 dev_current = 0; 1518 } else if (flag0 == 0xFF) { 1519 dev_current = 0; 1520 } else if (flag1 == 0xFF) { 1521 dev_current = 1; 1522 } else { 1523 dev_current = 0; 1524 } 1525 break; 1526 case FLAG_INCREMENTAL: 1527 if (flag0 == 255 && flag1 == 0) 1528 dev_current = 1; 1529 else if ((flag1 == 255 && flag0 == 0) || 1530 flag0 >= flag1) 1531 dev_current = 0; 1532 else /* flag1 > flag0 */ 1533 dev_current = 1; 1534 break; 1535 default: 1536 fprintf(stderr, "Unknown flag scheme %u\n", 1537 environment.flag_scheme); 1538 return -1; 1539 } 1540 } 1541 1542 /* 1543 * If we are reading, we don't need the flag and the CRC any 1544 * more, if we are writing, we will re-calculate CRC and update 1545 * flags before writing out 1546 */ 1547 if (dev_current) { 1548 environment.image = addr1; 1549 environment.crc = &redundant->crc; 1550 environment.flags = &redundant->flags; 1551 environment.data = redundant->data; 1552 free(addr0); 1553 } else { 1554 environment.image = addr0; 1555 /* Other pointers are already set */ 1556 free(addr1); 1557 } 1558 #ifdef DEBUG 1559 fprintf(stderr, "Selected env in %s\n", DEVNAME(dev_current)); 1560 #endif 1561 } 1562 return 0; 1563 1564 open_cleanup: 1565 if (addr0) 1566 free(addr0); 1567 1568 if (addr1) 1569 free(addr0); 1570 1571 return ret; 1572 } 1573 1574 /* 1575 * Simply free allocated buffer with environment 1576 */ 1577 int fw_env_close(struct env_opts *opts) 1578 { 1579 if (environment.image) 1580 free(environment.image); 1581 1582 environment.image = NULL; 1583 1584 return 0; 1585 } 1586 1587 static int check_device_config(int dev) 1588 { 1589 struct stat st; 1590 int32_t lnum = 0; 1591 int fd, rc = 0; 1592 1593 /* Fills in IS_UBI(), converts DEVNAME() with ubi volume name */ 1594 ubi_check_dev(dev); 1595 1596 fd = open(DEVNAME(dev), O_RDONLY); 1597 if (fd < 0) { 1598 fprintf(stderr, 1599 "Cannot open %s: %s\n", DEVNAME(dev), strerror(errno)); 1600 return -1; 1601 } 1602 1603 rc = fstat(fd, &st); 1604 if (rc < 0) { 1605 fprintf(stderr, "Cannot stat the file %s\n", DEVNAME(dev)); 1606 goto err; 1607 } 1608 1609 if (IS_UBI(dev)) { 1610 rc = ioctl(fd, UBI_IOCEBISMAP, &lnum); 1611 if (rc < 0) { 1612 fprintf(stderr, "Cannot get UBI information for %s\n", 1613 DEVNAME(dev)); 1614 goto err; 1615 } 1616 } else if (S_ISCHR(st.st_mode)) { 1617 struct mtd_info_user mtdinfo; 1618 rc = ioctl(fd, MEMGETINFO, &mtdinfo); 1619 if (rc < 0) { 1620 fprintf(stderr, "Cannot get MTD information for %s\n", 1621 DEVNAME(dev)); 1622 goto err; 1623 } 1624 if (mtdinfo.type != MTD_NORFLASH && 1625 mtdinfo.type != MTD_NANDFLASH && 1626 mtdinfo.type != MTD_DATAFLASH && 1627 mtdinfo.type != MTD_UBIVOLUME) { 1628 fprintf(stderr, "Unsupported flash type %u on %s\n", 1629 mtdinfo.type, DEVNAME(dev)); 1630 goto err; 1631 } 1632 DEVTYPE(dev) = mtdinfo.type; 1633 if (DEVESIZE(dev) == 0) 1634 /* Assume the erase size is the same as the env-size */ 1635 DEVESIZE(dev) = ENVSIZE(dev); 1636 } else { 1637 uint64_t size; 1638 DEVTYPE(dev) = MTD_ABSENT; 1639 if (DEVESIZE(dev) == 0) 1640 /* Assume the erase size to be 512 bytes */ 1641 DEVESIZE(dev) = 0x200; 1642 1643 /* 1644 * Check for negative offsets, treat it as backwards offset 1645 * from the end of the block device 1646 */ 1647 if (DEVOFFSET(dev) < 0) { 1648 rc = ioctl(fd, BLKGETSIZE64, &size); 1649 if (rc < 0) { 1650 fprintf(stderr, 1651 "Could not get block device size on %s\n", 1652 DEVNAME(dev)); 1653 goto err; 1654 } 1655 1656 DEVOFFSET(dev) = DEVOFFSET(dev) + size; 1657 #ifdef DEBUG 1658 fprintf(stderr, 1659 "Calculated device offset 0x%llx on %s\n", 1660 DEVOFFSET(dev), DEVNAME(dev)); 1661 #endif 1662 } 1663 } 1664 1665 if (ENVSECTORS(dev) == 0) 1666 /* Assume enough sectors to cover the environment */ 1667 ENVSECTORS(dev) = DIV_ROUND_UP(ENVSIZE(dev), DEVESIZE(dev)); 1668 1669 if (DEVOFFSET(dev) % DEVESIZE(dev) != 0) { 1670 fprintf(stderr, 1671 "Environment does not start on (erase) block boundary\n"); 1672 errno = EINVAL; 1673 return -1; 1674 } 1675 1676 if (ENVSIZE(dev) > ENVSECTORS(dev) * DEVESIZE(dev)) { 1677 fprintf(stderr, 1678 "Environment does not fit into available sectors\n"); 1679 errno = EINVAL; 1680 return -1; 1681 } 1682 1683 err: 1684 close(fd); 1685 return rc; 1686 } 1687 1688 static int parse_config(struct env_opts *opts) 1689 { 1690 int rc; 1691 1692 if (!opts) 1693 opts = &default_opts; 1694 1695 #if defined(CONFIG_FILE) 1696 /* Fills in DEVNAME(), ENVSIZE(), DEVESIZE(). Or don't. */ 1697 if (get_config(opts->config_file)) { 1698 fprintf(stderr, "Cannot parse config file '%s': %m\n", 1699 opts->config_file); 1700 return -1; 1701 } 1702 #else 1703 DEVNAME(0) = DEVICE1_NAME; 1704 DEVOFFSET(0) = DEVICE1_OFFSET; 1705 ENVSIZE(0) = ENV1_SIZE; 1706 1707 /* Set defaults for DEVESIZE, ENVSECTORS later once we 1708 * know DEVTYPE 1709 */ 1710 #ifdef DEVICE1_ESIZE 1711 DEVESIZE(0) = DEVICE1_ESIZE; 1712 #endif 1713 #ifdef DEVICE1_ENVSECTORS 1714 ENVSECTORS(0) = DEVICE1_ENVSECTORS; 1715 #endif 1716 1717 #ifdef HAVE_REDUND 1718 DEVNAME(1) = DEVICE2_NAME; 1719 DEVOFFSET(1) = DEVICE2_OFFSET; 1720 ENVSIZE(1) = ENV2_SIZE; 1721 1722 /* Set defaults for DEVESIZE, ENVSECTORS later once we 1723 * know DEVTYPE 1724 */ 1725 #ifdef DEVICE2_ESIZE 1726 DEVESIZE(1) = DEVICE2_ESIZE; 1727 #endif 1728 #ifdef DEVICE2_ENVSECTORS 1729 ENVSECTORS(1) = DEVICE2_ENVSECTORS; 1730 #endif 1731 have_redund_env = 1; 1732 #endif 1733 #endif 1734 rc = check_device_config(0); 1735 if (rc < 0) 1736 return rc; 1737 1738 if (have_redund_env) { 1739 rc = check_device_config(1); 1740 if (rc < 0) 1741 return rc; 1742 1743 if (ENVSIZE(0) != ENVSIZE(1)) { 1744 fprintf(stderr, 1745 "Redundant environments have unequal size"); 1746 return -1; 1747 } 1748 } 1749 1750 usable_envsize = CUR_ENVSIZE - sizeof(uint32_t); 1751 if (have_redund_env) 1752 usable_envsize -= sizeof(char); 1753 1754 return 0; 1755 } 1756 1757 #if defined(CONFIG_FILE) 1758 static int get_config(char *fname) 1759 { 1760 FILE *fp; 1761 int i = 0; 1762 int rc; 1763 char dump[128]; 1764 char *devname; 1765 1766 fp = fopen(fname, "r"); 1767 if (fp == NULL) 1768 return -1; 1769 1770 while (i < 2 && fgets(dump, sizeof(dump), fp)) { 1771 /* Skip incomplete conversions and comment strings */ 1772 if (dump[0] == '#') 1773 continue; 1774 1775 rc = sscanf(dump, "%ms %lli %lx %lx %lx", 1776 &devname, 1777 &DEVOFFSET(i), 1778 &ENVSIZE(i), &DEVESIZE(i), &ENVSECTORS(i)); 1779 1780 if (rc < 3) 1781 continue; 1782 1783 DEVNAME(i) = devname; 1784 1785 /* Set defaults for DEVESIZE, ENVSECTORS later once we 1786 * know DEVTYPE 1787 */ 1788 1789 i++; 1790 } 1791 fclose(fp); 1792 1793 have_redund_env = i - 1; 1794 if (!i) { /* No valid entries found */ 1795 errno = EINVAL; 1796 return -1; 1797 } else 1798 return 0; 1799 } 1800 #endif 1801