binman: Rename the main module
[oweals/u-boot.git] / tools / env / fw_env.c
index 77eac3d6c1736eabc97fe5eadb138fb2e08d90a4..381739d28df20edf7422861bdc946cd2982d2e3f 100644 (file)
@@ -1,16 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * (C) Copyright 2000-2010
  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  *
  * (C) Copyright 2008
  * Guennadi Liakhovetski, DENX Software Engineering, lg@denx.de.
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #define _GNU_SOURCE
 
 #include <compiler.h>
+#include <env.h>
 #include <errno.h>
 #include <env_flags.h>
 #include <fcntl.h>
@@ -25,6 +25,7 @@
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
+#include <u-boot/crc.h>
 #include <unistd.h>
 #include <dirent.h>
 
@@ -111,6 +112,7 @@ struct environment {
        unsigned char *flags;
        char *data;
        enum flag_scheme flag_scheme;
+       int dirty;
 };
 
 static struct environment environment = {
@@ -119,10 +121,6 @@ static struct environment environment = {
 
 static int have_redund_env;
 
-static unsigned char active_flag = 1;
-/* obsolete_flag must be 0 to efficiently set it on NOR flash without erasing */
-static unsigned char obsolete_flag = 0;
-
 #define DEFAULT_ENV_INSTANCE_STATIC
 #include <env_default.h>
 
@@ -509,6 +507,9 @@ int fw_env_flush(struct env_opts *opts)
        if (!opts)
                opts = &default_opts;
 
+       if (!environment.dirty)
+               return 0;
+
        /*
         * Update CRC
         */
@@ -554,7 +555,8 @@ int fw_env_write(char *name, char *value)
 
        deleting = (oldval && !(value && strlen(value)));
        creating = (!oldval && (value && strlen(value)));
-       overwriting = (oldval && (value && strlen(value)));
+       overwriting = (oldval && (value && strlen(value) &&
+                                 strcmp(oldval, value)));
 
        /* check for permission */
        if (deleting) {
@@ -594,6 +596,7 @@ int fw_env_write(char *name, char *value)
                /* Nothing to do */
                return 0;
 
+       environment.dirty = 1;
        if (deleting || overwriting) {
                if (*++nxt == '\0') {
                        *env = '\0';
@@ -738,7 +741,8 @@ int fw_env_set(int argc, char *argv[], struct env_opts *opts)
 int fw_parse_script(char *fname, struct env_opts *opts)
 {
        FILE *fp;
-       char dump[1024];        /* Maximum line length in the file */
+       char *line = NULL;
+       size_t linesize = 0;
        char *name;
        char *val;
        int lineno = 0;
@@ -764,36 +768,34 @@ int fw_parse_script(char *fname, struct env_opts *opts)
                }
        }
 
-       while (fgets(dump, sizeof(dump), fp)) {
+       while ((len = getline(&line, &linesize, fp)) != -1) {
                lineno++;
-               len = strlen(dump);
 
                /*
-                * Read a whole line from the file. If the line is too long
-                * or is not terminated, reports an error and exit.
+                * Read a whole line from the file. If the line is not
+                * terminated, reports an error and exit.
                 */
-               if (dump[len - 1] != '\n') {
+               if (line[len - 1] != '\n') {
                        fprintf(stderr,
-                               "Line %d not corrected terminated or too long\n",
+                               "Line %d not correctly terminated\n",
                                lineno);
                        ret = -1;
                        break;
                }
 
                /* Drop ending line feed / carriage return */
-               dump[--len] = '\0';
-               if (len && dump[len - 1] == '\r')
-                       dump[--len] = '\0';
+               line[--len] = '\0';
+               if (len && line[len - 1] == '\r')
+                       line[--len] = '\0';
 
                /* Skip comment or empty lines */
-               if (len == 0 || dump[0] == '#')
+               if (len == 0 || line[0] == '#')
                        continue;
 
                /*
-                * Search for variable's name,
-                * remove leading whitespaces
+                * Search for variable's name remove leading whitespaces
                 */
-               name = skip_blanks(dump);
+               name = skip_blanks(line);
                if (!name)
                        continue;
 
@@ -830,6 +832,7 @@ int fw_parse_script(char *fname, struct env_opts *opts)
                }
 
        }
+       free(line);
 
        /* Close file if not stdin */
        if (strcmp(fname, "-") != 0)
@@ -843,10 +846,10 @@ int fw_parse_script(char *fname, struct env_opts *opts)
 }
 
 /**
- * environment_end() - compute offset of first byte right after environemnt
+ * environment_end() - compute offset of first byte right after environment
  * @dev - index of enviroment buffer
  * Return:
- *  device offset of first byte right after environemnt
+ *  device offset of first byte right after environment
  */
 off_t environment_end(int dev)
 {
@@ -1139,10 +1142,11 @@ static int flash_flag_obsolete(int dev, int fd, off_t offset)
 {
        int rc;
        struct erase_info_user erase;
+       char tmp = ENV_REDUND_OBSOLETE;
 
        erase.start = DEVOFFSET(dev);
        erase.length = DEVESIZE(dev);
-       /* This relies on the fact, that obsolete_flag == 0 */
+       /* This relies on the fact, that ENV_REDUND_OBSOLETE == 0 */
        rc = lseek(fd, offset, SEEK_SET);
        if (rc < 0) {
                fprintf(stderr, "Cannot seek to set the flag on %s\n",
@@ -1150,7 +1154,7 @@ static int flash_flag_obsolete(int dev, int fd, off_t offset)
                return rc;
        }
        ioctl(fd, MEMUNLOCK, &erase);
-       rc = write(fd, &obsolete_flag, sizeof(obsolete_flag));
+       rc = write(fd, &tmp, sizeof(tmp));
        ioctl(fd, MEMLOCK, &erase);
        if (rc < 0)
                perror("Could not set obsolete flag");
@@ -1169,7 +1173,7 @@ static int flash_write(int fd_current, int fd_target, int dev_target)
                (*environment.flags)++;
                break;
        case FLAG_BOOLEAN:
-               *environment.flags = active_flag;
+               *environment.flags = ENV_REDUND_ACTIVE;
                break;
        default:
                fprintf(stderr, "Unimplemented flash scheme %u\n",
@@ -1318,7 +1322,7 @@ static int flash_io_write(int fd_current)
                        rc = -1;
                }
 
-               if (target_temp) {
+               if (rc >= 0 && target_temp) {
                        int dir_fd;
 
                        dir_fd = open(dname, O_DIRECTORY | O_RDONLY);
@@ -1442,6 +1446,7 @@ int fw_env_open(struct env_opts *opts)
                                "Warning: Bad CRC, using default environment\n");
                        memcpy(environment.data, default_environment,
                               sizeof(default_environment));
+                       environment.dirty = 1;
                }
        } else {
                flag0 = *environment.flags;
@@ -1495,6 +1500,16 @@ int fw_env_open(struct env_opts *opts)
                crc1_ok = (crc1 == redundant->crc);
                flag1 = redundant->flags;
 
+               /*
+                * environment.data still points to ((struct
+                * env_image_redundant *)addr0)->data. If the two
+                * environments differ, or one has bad crc, force a
+                * write-out by marking the environment dirty.
+                */
+               if (memcmp(environment.data, redundant->data, ENV_SIZE) ||
+                   !crc0_ok || !crc1_ok)
+                       environment.dirty = 1;
+
                if (crc0_ok && !crc1_ok) {
                        dev_current = 0;
                } else if (!crc0_ok && crc1_ok) {
@@ -1504,15 +1519,16 @@ int fw_env_open(struct env_opts *opts)
                                "Warning: Bad CRC, using default environment\n");
                        memcpy(environment.data, default_environment,
                               sizeof(default_environment));
+                       environment.dirty = 1;
                        dev_current = 0;
                } else {
                        switch (environment.flag_scheme) {
                        case FLAG_BOOLEAN:
-                               if (flag0 == active_flag &&
-                                   flag1 == obsolete_flag) {
+                               if (flag0 == ENV_REDUND_ACTIVE &&
+                                   flag1 == ENV_REDUND_OBSOLETE) {
                                        dev_current = 0;
-                               } else if (flag0 == obsolete_flag &&
-                                          flag1 == active_flag) {
+                               } else if (flag0 == ENV_REDUND_OBSOLETE &&
+                                          flag1 == ENV_REDUND_ACTIVE) {
                                        dev_current = 1;
                                } else if (flag0 == flag1) {
                                        dev_current = 0;
@@ -1567,7 +1583,7 @@ int fw_env_open(struct env_opts *opts)
                free(addr0);
 
        if (addr1)
-               free(addr0);
+               free(addr1);
 
        return ret;
 }
@@ -1743,7 +1759,7 @@ static int parse_config(struct env_opts *opts)
 
                if (ENVSIZE(0) != ENVSIZE(1)) {
                        fprintf(stderr,
-                               "Redundant environments have unequal size");
+                               "Redundant environments have unequal size\n");
                        return -1;
                }
        }
@@ -1761,19 +1777,20 @@ static int get_config(char *fname)
        FILE *fp;
        int i = 0;
        int rc;
-       char dump[128];
+       char *line = NULL;
+       size_t linesize = 0;
        char *devname;
 
        fp = fopen(fname, "r");
        if (fp == NULL)
                return -1;
 
-       while (i < 2 && fgets(dump, sizeof(dump), fp)) {
-               /* Skip incomplete conversions and comment strings */
-               if (dump[0] == '#')
+       while (i < 2 && getline(&line, &linesize, fp) != -1) {
+               /* Skip comment strings */
+               if (line[0] == '#')
                        continue;
 
-               rc = sscanf(dump, "%ms %lli %lx %lx %lx",
+               rc = sscanf(line, "%ms %lli %lx %lx %lx",
                            &devname,
                            &DEVOFFSET(i),
                            &ENVSIZE(i), &DEVESIZE(i), &ENVSECTORS(i));
@@ -1789,6 +1806,7 @@ static int get_config(char *fname)
 
                i++;
        }
+       free(line);
        fclose(fp);
 
        have_redund_env = i - 1;