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