env: Move env_set() to env.h
[oweals/u-boot.git] / tools / env / fw_env.c
index 299e0c9608bb2bc3b9e0298929726c14a337f96c..f06252d9168af09a6e31e48f59570e3380c36f22 100644 (file)
@@ -1,19 +1,20 @@
+// 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>
+#include <libgen.h>
 #include <linux/fs.h>
 #include <linux/stringify.h>
 #include <ctype.h>
@@ -25,6 +26,7 @@
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <dirent.h>
 
 #ifdef MTD_OLD
 # include <stdint.h>
@@ -34,6 +36,8 @@
 # include <mtd/mtd-user.h>
 #endif
 
+#include <mtd/ubi-user.h>
+
 #include "fw_env_private.h"
 #include "fw_env.h"
 
@@ -58,16 +62,17 @@ struct envdev_s {
        ulong erase_size;               /* device erase size */
        ulong env_sectors;              /* number of environment sectors */
        uint8_t mtd_type;               /* type of the MTD device */
+       int is_ubi;                     /* set if we use UBI volume */
 };
 
-static struct envdev_s envdevices[2] =
-{
+static struct envdev_s envdevices[2] = {
        {
                .mtd_type = MTD_ABSENT,
        }, {
                .mtd_type = MTD_ABSENT,
        },
 };
+
 static int dev_current;
 
 #define DEVNAME(i)    envdevices[(i)].devname
@@ -76,6 +81,7 @@ static int dev_current;
 #define DEVESIZE(i)   envdevices[(i)].erase_size
 #define ENVSECTORS(i) envdevices[(i)].env_sectors
 #define DEVTYPE(i)    envdevices[(i)].mtd_type
+#define IS_UBI(i)     envdevices[(i)].is_ubi
 
 #define CUR_ENVSIZE ENVSIZE(dev_current)
 
@@ -83,14 +89,14 @@ static unsigned long usable_envsize;
 #define ENV_SIZE      usable_envsize
 
 struct env_image_single {
-       uint32_t        crc;    /* CRC32 over data bytes    */
-       char            data[];
+       uint32_t crc;           /* CRC32 over data bytes    */
+       char data[];
 };
 
 struct env_image_redundant {
-       uint32_t        crc;    /* CRC32 over data bytes    */
-       unsigned char   flags;  /* active or obsolete */
-       char            data[];
+       uint32_t crc;           /* CRC32 over data bytes    */
+       unsigned char flags;    /* active or obsolete */
+       char data[];
 };
 
 enum flag_scheme {
@@ -100,20 +106,18 @@ enum flag_scheme {
 };
 
 struct environment {
-       void                    *image;
-       uint32_t                *crc;
-       unsigned char           *flags;
-       char                    *data;
-       enum flag_scheme        flag_scheme;
+       void *image;
+       uint32_t *crc;
+       unsigned char *flags;
+       char *data;
+       enum flag_scheme flag_scheme;
 };
 
 static struct environment environment = {
        .flag_scheme = FLAG_NONE,
 };
 
-static int env_aes_cbc_crypt(char *data, const int enc, uint8_t *key);
-
-static int HaveRedundEnv = 0;
+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 */
@@ -122,17 +126,239 @@ static unsigned char obsolete_flag = 0;
 #define DEFAULT_ENV_INSTANCE_STATIC
 #include <env_default.h>
 
-static int flash_io (int mode);
+#define UBI_DEV_START "/dev/ubi"
+#define UBI_SYSFS "/sys/class/ubi"
+#define UBI_VOL_NAME_PATT "ubi%d_%d"
+
+static int is_ubi_devname(const char *devname)
+{
+       return !strncmp(devname, UBI_DEV_START, sizeof(UBI_DEV_START) - 1);
+}
+
+static int ubi_check_volume_sysfs_name(const char *volume_sysfs_name,
+                                      const char *volname)
+{
+       char path[256];
+       FILE *file;
+       char *name;
+       int ret;
+
+       strcpy(path, UBI_SYSFS "/");
+       strcat(path, volume_sysfs_name);
+       strcat(path, "/name");
+
+       file = fopen(path, "r");
+       if (!file)
+               return -1;
+
+       ret = fscanf(file, "%ms", &name);
+       fclose(file);
+       if (ret <= 0 || !name) {
+               fprintf(stderr,
+                       "Failed to read from file %s, ret = %d, name = %s\n",
+                       path, ret, name);
+               return -1;
+       }
+
+       if (!strcmp(name, volname)) {
+               free(name);
+               return 0;
+       }
+       free(name);
+
+       return -1;
+}
+
+static int ubi_get_volnum_by_name(int devnum, const char *volname)
+{
+       DIR *sysfs_ubi;
+       struct dirent *dirent;
+       int ret;
+       int tmp_devnum;
+       int volnum;
+
+       sysfs_ubi = opendir(UBI_SYSFS);
+       if (!sysfs_ubi)
+               return -1;
+
+#ifdef DEBUG
+       fprintf(stderr, "Looking for volume name \"%s\"\n", volname);
+#endif
+
+       while (1) {
+               dirent = readdir(sysfs_ubi);
+               if (!dirent)
+                       return -1;
+
+               ret = sscanf(dirent->d_name, UBI_VOL_NAME_PATT,
+                            &tmp_devnum, &volnum);
+               if (ret == 2 && devnum == tmp_devnum) {
+                       if (ubi_check_volume_sysfs_name(dirent->d_name,
+                                                       volname) == 0)
+                               return volnum;
+               }
+       }
+
+       return -1;
+}
+
+static int ubi_get_devnum_by_devname(const char *devname)
+{
+       int devnum;
+       int ret;
+
+       ret = sscanf(devname + sizeof(UBI_DEV_START) - 1, "%d", &devnum);
+       if (ret != 1)
+               return -1;
+
+       return devnum;
+}
+
+static const char *ubi_get_volume_devname(const char *devname,
+                                         const char *volname)
+{
+       char *volume_devname;
+       int volnum;
+       int devnum;
+       int ret;
+
+       devnum = ubi_get_devnum_by_devname(devname);
+       if (devnum < 0)
+               return NULL;
+
+       volnum = ubi_get_volnum_by_name(devnum, volname);
+       if (volnum < 0)
+               return NULL;
+
+       ret = asprintf(&volume_devname, "%s_%d", devname, volnum);
+       if (ret < 0)
+               return NULL;
+
+#ifdef DEBUG
+       fprintf(stderr, "Found ubi volume \"%s:%s\" -> %s\n",
+               devname, volname, volume_devname);
+#endif
+
+       return volume_devname;
+}
+
+static void ubi_check_dev(unsigned int dev_id)
+{
+       char *devname = (char *)DEVNAME(dev_id);
+       char *pname;
+       const char *volname = NULL;
+       const char *volume_devname;
+
+       if (!is_ubi_devname(DEVNAME(dev_id)))
+               return;
+
+       IS_UBI(dev_id) = 1;
+
+       for (pname = devname; *pname != '\0'; pname++) {
+               if (*pname == ':') {
+                       *pname = '\0';
+                       volname = pname + 1;
+                       break;
+               }
+       }
+
+       if (volname) {
+               /* Let's find real volume device name */
+               volume_devname = ubi_get_volume_devname(devname, volname);
+               if (!volume_devname) {
+                       fprintf(stderr, "Didn't found ubi volume \"%s\"\n",
+                               volname);
+                       return;
+               }
+
+               free(devname);
+               DEVNAME(dev_id) = volume_devname;
+       }
+}
+
+static int ubi_update_start(int fd, int64_t bytes)
+{
+       if (ioctl(fd, UBI_IOCVOLUP, &bytes))
+               return -1;
+       return 0;
+}
+
+static int ubi_read(int fd, void *buf, size_t count)
+{
+       ssize_t ret;
+
+       while (count > 0) {
+               ret = read(fd, buf, count);
+               if (ret > 0) {
+                       count -= ret;
+                       buf += ret;
+
+                       continue;
+               }
+
+               if (ret == 0) {
+                       /*
+                        * Happens in case of too short volume data size. If we
+                        * return error status we will fail it will be treated
+                        * as UBI device error.
+                        *
+                        * Leave catching this error to CRC check.
+                        */
+                       fprintf(stderr, "Warning: end of data on ubi volume\n");
+                       return 0;
+               } else if (errno == EBADF) {
+                       /*
+                        * Happens in case of corrupted volume. The same as
+                        * above, we cannot return error now, as we will still
+                        * be able to successfully write environment later.
+                        */
+                       fprintf(stderr, "Warning: corrupted volume?\n");
+                       return 0;
+               } else if (errno == EINTR) {
+                       continue;
+               }
+
+               fprintf(stderr, "Cannot read %u bytes from ubi volume, %s\n",
+                       (unsigned int)count, strerror(errno));
+               return -1;
+       }
+
+       return 0;
+}
+
+static int ubi_write(int fd, const void *buf, size_t count)
+{
+       ssize_t ret;
+
+       while (count > 0) {
+               ret = write(fd, buf, count);
+               if (ret <= 0) {
+                       if (ret < 0 && errno == EINTR)
+                               continue;
+
+                       fprintf(stderr, "Cannot write %u bytes to ubi volume\n",
+                               (unsigned int)count);
+                       return -1;
+               }
+
+               count -= ret;
+               buf += ret;
+       }
+
+       return 0;
+}
+
+static int flash_io(int mode);
 static int parse_config(struct env_opts *opts);
 
 #if defined(CONFIG_FILE)
-static int get_config (char *);
+static int get_config(char *);
 #endif
 
 static char *skip_chars(char *s)
 {
        for (; *s != '\0'; s++) {
-               if (isblank(*s))
+               if (isblank(*s) || *s == '=')
                        return s;
        }
        return NULL;
@@ -169,7 +395,7 @@ static char *envmatch(char *s1, char *s2)
  * Search the environment for a variable.
  * Return the value, if found, or NULL, if not found.
  */
-char *fw_getenv (char *name)
+char *fw_getenv(char *name)
 {
        char *env, *nxt;
 
@@ -178,12 +404,12 @@ char *fw_getenv (char *name)
 
                for (nxt = env; *nxt; ++nxt) {
                        if (nxt >= &environment.data[ENV_SIZE]) {
-                               fprintf (stderr, "## Error: "
+                               fprintf(stderr, "## Error: "
                                        "environment not terminated\n");
                                return NULL;
                        }
                }
-               val = envmatch (name, env);
+               val = envmatch(name, env);
                if (!val)
                        continue;
                return val;
@@ -217,34 +443,6 @@ char *fw_getdefenv(char *name)
        return NULL;
 }
 
-int parse_aes_key(char *key, uint8_t *bin_key)
-{
-       char tmp[5] = { '0', 'x', 0, 0, 0 };
-       unsigned long ul;
-       int i;
-
-       if (strnlen(key, 64) != 32) {
-               fprintf(stderr,
-                       "## Error: '-a' option requires 16-byte AES key\n");
-               return -1;
-       }
-
-       for (i = 0; i < 16; i++) {
-               tmp[2] = key[0];
-               tmp[3] = key[1];
-               errno = 0;
-               ul = strtoul(tmp, NULL, 16);
-               if (errno) {
-                       fprintf(stderr,
-                               "## Error: '-a' option requires valid AES key\n");
-                       return -1;
-               }
-               bin_key[i] = ul & 0xff;
-               key += 2;
-       }
-       return 0;
-}
-
 /*
  * Print the current definition of one, or more, or all
  * environment variables
@@ -255,7 +453,7 @@ int fw_printenv(int argc, char *argv[], int value_only, struct env_opts *opts)
 
        if (value_only && argc != 1) {
                fprintf(stderr,
-                       "## Error: `-n' option requires exactly one argument\n");
+                       "## Error: `-n'/`--noheader' option requires exactly one argument\n");
                return -1;
        }
 
@@ -265,18 +463,18 @@ int fw_printenv(int argc, char *argv[], int value_only, struct env_opts *opts)
        if (fw_env_open(opts))
                return -1;
 
-       if (argc == 0) {                /* Print all env variables  */
+       if (argc == 0) {        /* Print all env variables  */
                char *env, *nxt;
                for (env = environment.data; *env; env = nxt + 1) {
                        for (nxt = env; *nxt; ++nxt) {
                                if (nxt >= &environment.data[ENV_SIZE]) {
-                                       fprintf (stderr, "## Error: "
+                                       fprintf(stderr, "## Error: "
                                                "environment not terminated\n");
                                        return -1;
                                }
                        }
 
-                       printf ("%s\n", env);
+                       printf("%s\n", env);
                }
                fw_env_close(opts);
                return 0;
@@ -288,7 +486,7 @@ int fw_printenv(int argc, char *argv[], int value_only, struct env_opts *opts)
 
                val = fw_getenv(name);
                if (!val) {
-                       fprintf (stderr, "## Error: \"%s\" not defined\n", name);
+                       fprintf(stderr, "## Error: \"%s\" not defined\n", name);
                        rc = -1;
                        continue;
                }
@@ -308,21 +506,9 @@ int fw_printenv(int argc, char *argv[], int value_only, struct env_opts *opts)
 
 int fw_env_flush(struct env_opts *opts)
 {
-       int ret;
-
        if (!opts)
                opts = &default_opts;
 
-       if (opts->aes_flag) {
-               ret = env_aes_cbc_crypt(environment.data, 1,
-                                       opts->aes_key);
-               if (ret) {
-                       fprintf(stderr,
-                               "Error: can't encrypt env for flash\n");
-                       return ret;
-               }
-       }
-
        /*
         * Update CRC
         */
@@ -330,15 +516,13 @@ int fw_env_flush(struct env_opts *opts)
 
        /* write environment back to flash */
        if (flash_io(O_RDWR)) {
-               fprintf(stderr,
-                       "Error: can't write fw_env to flash\n");
-                       return -1;
+               fprintf(stderr, "Error: can't write fw_env to flash\n");
+               return -1;
        }
 
        return 0;
 }
 
-
 /*
  * Set/Clear a single variable in the environment.
  * This is called in sequence to update the environment
@@ -363,7 +547,8 @@ int fw_env_write(char *name, char *value)
                                return -1;
                        }
                }
-               if ((oldval = envmatch (name, env)) != NULL)
+               oldval = envmatch(name, env);
+               if (oldval)
                        break;
        }
 
@@ -386,7 +571,7 @@ int fw_env_write(char *name, char *value)
                        errno = EROFS;
                        return -1;
                } else if (env_flags_validate_varaccess(name,
-                   ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR)) {
+                          ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR)) {
                        const char *defval = fw_getdefenv(name);
 
                        if (defval == NULL)
@@ -430,21 +615,21 @@ int fw_env_write(char *name, char *value)
        /*
         * Append new definition at the end
         */
-       for (env = environment.data; *env || *(env + 1); ++env);
+       for (env = environment.data; *env || *(env + 1); ++env)
+               ;
        if (env > environment.data)
                ++env;
        /*
         * Overflow when:
         * "name" + "=" + "val" +"\0\0"  > CUR_ENVSIZE - (env-environment)
         */
-       len = strlen (name) + 2;
+       len = strlen(name) + 2;
        /* add '=' for first arg, ' ' for all others */
        len += strlen(value) + 1;
 
        if (len > (&environment.data[ENV_SIZE] - env)) {
-               fprintf (stderr,
-                       "Error: environment overflow, \"%s\" deleted\n",
-                       name);
+               fprintf(stderr,
+                       "Error: environment overflow, \"%s\" deleted\n", name);
                return -1;
        }
 
@@ -468,11 +653,12 @@ int fw_env_write(char *name, char *value)
  *         modified or deleted
  *
  */
-int fw_setenv(int argc, char *argv[], struct env_opts *opts)
+int fw_env_set(int argc, char *argv[], struct env_opts *opts)
 {
        int i;
        size_t len;
        char *name, **valv;
+       char *oldval;
        char *value = NULL;
        int valc;
        int ret;
@@ -507,11 +693,13 @@ int fw_setenv(int argc, char *argv[], struct env_opts *opts)
 
                if (value)
                        value[len - 1] = ' ';
+               oldval = value;
                value = realloc(value, len + val_len + 1);
                if (!value) {
                        fprintf(stderr,
                                "Cannot malloc %zu bytes: %s\n",
                                len, strerror(errno));
+                       free(oldval);
                        return -1;
                }
 
@@ -550,7 +738,8 @@ int fw_setenv(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;
@@ -571,41 +760,39 @@ int fw_parse_script(char *fname, struct env_opts *opts)
                fp = fopen(fname, "r");
                if (fp == NULL) {
                        fprintf(stderr, "I cannot open %s for reading\n",
-                                fname);
+                               fname);
                        return -1;
                }
        }
 
-       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;
 
@@ -619,7 +806,6 @@ int fw_parse_script(char *fname, struct env_opts *opts)
                        else
                                val = NULL;
                }
-
 #ifdef DEBUG
                fprintf(stderr, "Setting %s : %s\n",
                        name, val ? val : " removed");
@@ -636,13 +822,14 @@ int fw_parse_script(char *fname, struct env_opts *opts)
                 */
                if (fw_env_write(name, val)) {
                        fprintf(stderr,
-                       "fw_env_write returns with error : %s\n",
+                               "fw_env_write returns with error : %s\n",
                                strerror(errno));
                        ret = -1;
                        break;
                }
 
        }
+       free(line);
 
        /* Close file if not stdin */
        if (strcmp(fname, "-") != 0)
@@ -656,10 +843,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)
 {
@@ -679,13 +866,13 @@ static int flash_bad_block(int fd, uint8_t mtd_type, loff_t blockstart)
                int badblock = ioctl(fd, MEMGETBADBLOCK, &blockstart);
 
                if (badblock < 0) {
-                       perror ("Cannot read bad block mark");
+                       perror("Cannot read bad block mark");
                        return badblock;
                }
 
                if (badblock) {
 #ifdef DEBUG
-                       fprintf (stderr, "Bad block at 0x%llx, skipping\n",
+                       fprintf(stderr, "Bad block at 0x%llx, skipping\n",
                                (unsigned long long)blockstart);
 #endif
                        return badblock;
@@ -700,8 +887,8 @@ static int flash_bad_block(int fd, uint8_t mtd_type, loff_t blockstart)
  * bad blocks but makes sure it stays within ENVSECTORS (dev) starting from
  * the DEVOFFSET (dev) block. On NOR the loop is only run once.
  */
-static int flash_read_buf (int dev, int fd, void *buf, size_t count,
-                          off_t offset)
+static int flash_read_buf(int dev, int fd, void *buf, size_t count,
+                         off_t offset)
 {
        size_t blocklen;        /* erase / write length - one block on NAND,
                                   0 on NOR */
@@ -713,7 +900,7 @@ static int flash_read_buf (int dev, int fd, void *buf, size_t count,
                                   MEMGETBADBLOCK needs 64 bits */
        int rc;
 
-       blockstart = (offset / DEVESIZE (dev)) * DEVESIZE (dev);
+       blockstart = (offset / DEVESIZE(dev)) * DEVESIZE(dev);
 
        /* Offset inside a block */
        block_seek = offset - blockstart;
@@ -723,7 +910,7 @@ static int flash_read_buf (int dev, int fd, void *buf, size_t count,
                 * NAND: calculate which blocks we are reading. We have
                 * to read one block at a time to skip bad blocks.
                 */
-               blocklen = DEVESIZE (dev);
+               blocklen = DEVESIZE(dev);
 
                /* Limit to one block for the first read */
                if (readlen > blocklen - block_seek)
@@ -735,40 +922,39 @@ static int flash_read_buf (int dev, int fd, void *buf, size_t count,
        /* This only runs once on NOR flash */
        while (processed < count) {
                rc = flash_bad_block(fd, DEVTYPE(dev), blockstart);
-               if (rc < 0)             /* block test failed */
+               if (rc < 0)     /* block test failed */
                        return -1;
 
                if (blockstart + block_seek + readlen > environment_end(dev)) {
                        /* End of range is reached */
-                       fprintf (stderr,
-                                "Too few good blocks within range\n");
+                       fprintf(stderr, "Too few good blocks within range\n");
                        return -1;
                }
 
-               if (rc) {               /* block is bad */
+               if (rc) {       /* block is bad */
                        blockstart += blocklen;
                        continue;
                }
 
                /*
                 * If a block is bad, we retry in the next block at the same
-                * offset - see common/env_nand.c::writeenv()
+                * offset - see env/nand.c::writeenv()
                 */
-               lseek (fd, blockstart + block_seek, SEEK_SET);
+               lseek(fd, blockstart + block_seek, SEEK_SET);
 
-               rc = read (fd, buf + processed, readlen);
+               rc = read(fd, buf + processed, readlen);
                if (rc != readlen) {
-                       fprintf (stderr, "Read error on %s: %s\n",
-                                DEVNAME (dev), strerror (errno));
+                       fprintf(stderr, "Read error on %s: %s\n",
+                               DEVNAME(dev), strerror(errno));
                        return -1;
                }
 #ifdef DEBUG
                fprintf(stderr, "Read 0x%x bytes at 0x%llx on %s\n",
-                       rc, (unsigned long long) blockstart + block_seek,
+                       rc, (unsigned long long)blockstart + block_seek,
                        DEVNAME(dev));
 #endif
                processed += readlen;
-               readlen = min (blocklen, count - processed);
+               readlen = min(blocklen, count - processed);
                block_seek = 0;
                blockstart += blocklen;
        }
@@ -830,7 +1016,7 @@ static int flash_write_buf(int dev, int fd, void *buf, size_t count)
                 * to the end of the block
                 */
                write_total = ((block_seek + count + blocklen - 1) /
-                                                       blocklen) * blocklen;
+                              blocklen) * blocklen;
        }
 
        /*
@@ -839,11 +1025,11 @@ static int flash_write_buf(int dev, int fd, void *buf, size_t count)
         * block back again.
         */
        if (write_total > count) {
-               data = malloc (erase_len);
+               data = malloc(erase_len);
                if (!data) {
-                       fprintf (stderr,
-                                "Cannot malloc %zu bytes: %s\n",
-                                erase_len, strerror (errno));
+                       fprintf(stderr,
+                               "Cannot malloc %zu bytes: %s\n",
+                               erase_len, strerror(errno));
                        return -1;
                }
 
@@ -859,13 +1045,13 @@ static int flash_write_buf(int dev, int fd, void *buf, size_t count)
                        if (block_seek != 0)
                                fprintf(stderr, " and ");
                        fprintf(stderr, "0x%lx - 0x%lx",
-                               (unsigned long) block_seek + count,
-                               (unsigned long) write_total - 1);
+                               (unsigned long)block_seek + count,
+                               (unsigned long)write_total - 1);
                }
                fprintf(stderr, "\n");
 #endif
                /* Overwrite the old environment */
-               memcpy (data + block_seek, buf, count);
+               memcpy(data + block_seek, buf, count);
        } else {
                /*
                 * We get here, iff offset is block-aligned and count is a
@@ -889,15 +1075,15 @@ static int flash_write_buf(int dev, int fd, void *buf, size_t count)
        /* This only runs once on NOR flash and SPI-dataflash */
        while (processed < write_total) {
                rc = flash_bad_block(fd, DEVTYPE(dev), blockstart);
-               if (rc < 0)             /* block test failed */
+               if (rc < 0)     /* block test failed */
                        return rc;
 
                if (blockstart + erasesize > environment_end(dev)) {
-                       fprintf (stderr, "End of range reached, aborting\n");
+                       fprintf(stderr, "End of range reached, aborting\n");
                        return -1;
                }
 
-               if (rc) {               /* block is bad */
+               if (rc) {       /* block is bad */
                        blockstart += blocklen;
                        continue;
                }
@@ -915,34 +1101,33 @@ static int flash_write_buf(int dev, int fd, void *buf, size_t count)
                                }
                }
 
-               if (lseek (fd, blockstart, SEEK_SET) == -1) {
-                       fprintf (stderr,
-                                "Seek error on %s: %s\n",
-                                DEVNAME (dev), strerror (errno));
+               if (lseek(fd, blockstart, SEEK_SET) == -1) {
+                       fprintf(stderr,
+                               "Seek error on %s: %s\n",
+                               DEVNAME(dev), strerror(errno));
                        return -1;
                }
-
 #ifdef DEBUG
                fprintf(stderr, "Write 0x%llx bytes at 0x%llx\n",
-                       (unsigned long long) erasesize,
-                       (unsigned long long) blockstart);
+                       (unsigned long long)erasesize,
+                       (unsigned long long)blockstart);
 #endif
-               if (write (fd, data + processed, erasesize) != erasesize) {
-                       fprintf (stderr, "Write error on %s: %s\n",
-                                DEVNAME (dev), strerror (errno));
+               if (write(fd, data + processed, erasesize) != erasesize) {
+                       fprintf(stderr, "Write error on %s: %s\n",
+                               DEVNAME(dev), strerror(errno));
                        return -1;
                }
 
                if (DEVTYPE(dev) != MTD_ABSENT)
                        ioctl(fd, MEMLOCK, &erase);
 
-               processed  += erasesize;
+               processed += erasesize;
                block_seek = 0;
                blockstart += erasesize;
        }
 
        if (write_total > count)
-               free (data);
+               free(data);
 
        return processed;
 }
@@ -950,52 +1135,30 @@ static int flash_write_buf(int dev, int fd, void *buf, size_t count)
 /*
  * Set obsolete flag at offset - NOR flash only
  */
-static int flash_flag_obsolete (int dev, int fd, off_t offset)
+static int flash_flag_obsolete(int dev, int fd, off_t offset)
 {
        int rc;
        struct erase_info_user erase;
 
-       erase.start  = DEVOFFSET (dev);
-       erase.length = DEVESIZE (dev);
+       erase.start = DEVOFFSET(dev);
+       erase.length = DEVESIZE(dev);
        /* This relies on the fact, that obsolete_flag == 0 */
-       rc = lseek (fd, offset, SEEK_SET);
+       rc = lseek(fd, offset, SEEK_SET);
        if (rc < 0) {
-               fprintf (stderr, "Cannot seek to set the flag on %s \n",
-                        DEVNAME (dev));
+               fprintf(stderr, "Cannot seek to set the flag on %s\n",
+                       DEVNAME(dev));
                return rc;
        }
-       ioctl (fd, MEMUNLOCK, &erase);
-       rc = write (fd, &obsolete_flag, sizeof (obsolete_flag));
-       ioctl (fd, MEMLOCK, &erase);
+       ioctl(fd, MEMUNLOCK, &erase);
+       rc = write(fd, &obsolete_flag, sizeof(obsolete_flag));
+       ioctl(fd, MEMLOCK, &erase);
        if (rc < 0)
-               perror ("Could not set obsolete flag");
+               perror("Could not set obsolete flag");
 
        return rc;
 }
 
-/* Encrypt or decrypt the environment before writing or reading it. */
-static int env_aes_cbc_crypt(char *payload, const int enc, uint8_t *key)
-{
-       uint8_t *data = (uint8_t *)payload;
-       const int len = usable_envsize;
-       uint8_t key_exp[AES_EXPAND_KEY_LENGTH];
-       uint32_t aes_blocks;
-
-       /* First we expand the key. */
-       aes_expand_key(key, key_exp);
-
-       /* Calculate the number of AES blocks to encrypt. */
-       aes_blocks = DIV_ROUND_UP(len, AES_KEY_LENGTH);
-
-       if (enc)
-               aes_cbc_encrypt_blocks(key_exp, data, data, aes_blocks);
-       else
-               aes_cbc_decrypt_blocks(key_exp, data, data, aes_blocks);
-
-       return 0;
-}
-
-static int flash_write (int fd_current, int fd_target, int dev_target)
+static int flash_write(int fd_current, int fd_target, int dev_target)
 {
        int rc;
 
@@ -1009,16 +1172,22 @@ static int flash_write (int fd_current, int fd_target, int dev_target)
                *environment.flags = active_flag;
                break;
        default:
-               fprintf (stderr, "Unimplemented flash scheme %u \n",
-                        environment.flag_scheme);
+               fprintf(stderr, "Unimplemented flash scheme %u\n",
+                       environment.flag_scheme);
                return -1;
        }
 
 #ifdef DEBUG
        fprintf(stderr, "Writing new environment at 0x%llx on %s\n",
-               DEVOFFSET (dev_target), DEVNAME (dev_target));
+               DEVOFFSET(dev_target), DEVNAME(dev_target));
 #endif
 
+       if (IS_UBI(dev_target)) {
+               if (ubi_update_start(fd_target, CUR_ENVSIZE) < 0)
+                       return 0;
+               return ubi_write(fd_target, environment.image, CUR_ENVSIZE);
+       }
+
        rc = flash_write_buf(dev_target, fd_target, environment.image,
                             CUR_ENVSIZE);
        if (rc < 0)
@@ -1026,23 +1195,29 @@ static int flash_write (int fd_current, int fd_target, int dev_target)
 
        if (environment.flag_scheme == FLAG_BOOLEAN) {
                /* Have to set obsolete flag */
-               off_t offset = DEVOFFSET (dev_current) +
-                       offsetof (struct env_image_redundant, flags);
+               off_t offset = DEVOFFSET(dev_current) +
+                   offsetof(struct env_image_redundant, flags);
 #ifdef DEBUG
                fprintf(stderr,
                        "Setting obsolete flag in environment at 0x%llx on %s\n",
-                       DEVOFFSET (dev_current), DEVNAME (dev_current));
+                       DEVOFFSET(dev_current), DEVNAME(dev_current));
 #endif
-               flash_flag_obsolete (dev_current, fd_current, offset);
+               flash_flag_obsolete(dev_current, fd_current, offset);
        }
 
        return 0;
 }
 
-static int flash_read (int fd)
+static int flash_read(int fd)
 {
        int rc;
 
+       if (IS_UBI(dev_current)) {
+               DEVTYPE(dev_current) = MTD_ABSENT;
+
+               return ubi_read(fd, environment.image, CUR_ENVSIZE);
+       }
+
        rc = flash_read_buf(dev_current, fd, environment.image, CUR_ENVSIZE,
                            DEVOFFSET(dev_current));
        if (rc != CUR_ENVSIZE)
@@ -1051,58 +1226,153 @@ static int flash_read (int fd)
        return 0;
 }
 
-static int flash_io (int mode)
+static int flash_open_tempfile(const char **dname, const char **target_temp)
 {
-       int fd_current, fd_target, rc, dev_target;
+       char *dup_name = strdup(DEVNAME(dev_current));
+       char *temp_name = NULL;
+       int rc = -1;
 
-       /* dev_current: fd_current, erase_current */
-       fd_current = open (DEVNAME (dev_current), mode);
-       if (fd_current < 0) {
-               fprintf (stderr,
-                        "Can't open %s: %s\n",
-                        DEVNAME (dev_current), strerror (errno));
+       if (!dup_name)
                return -1;
+
+       *dname = dirname(dup_name);
+       if (!*dname)
+               goto err;
+
+       rc = asprintf(&temp_name, "%s/XXXXXX", *dname);
+       if (rc == -1)
+               goto err;
+
+       rc = mkstemp(temp_name);
+       if (rc == -1) {
+               /* fall back to in place write */
+               fprintf(stderr,
+                       "Can't create %s: %s\n", temp_name, strerror(errno));
+               free(temp_name);
+       } else {
+               *target_temp = temp_name;
+               /* deliberately leak dup_name as dname /might/ point into
+                * it and we need it for our caller
+                */
+               dup_name = NULL;
        }
 
-       if (mode == O_RDWR) {
-               if (HaveRedundEnv) {
-                       /* switch to next partition for writing */
-                       dev_target = !dev_current;
-                       /* dev_target: fd_target, erase_target */
-                       fd_target = open (DEVNAME (dev_target), mode);
-                       if (fd_target < 0) {
-                               fprintf (stderr,
-                                        "Can't open %s: %s\n",
-                                        DEVNAME (dev_target),
-                                        strerror (errno));
-                               rc = -1;
-                               goto exit;
-                       }
-               } else {
-                       dev_target = dev_current;
+err:
+       if (dup_name)
+               free(dup_name);
+
+       return rc;
+}
+
+static int flash_io_write(int fd_current)
+{
+       int fd_target = -1, rc, dev_target;
+       const char *dname, *target_temp = NULL;
+
+       if (have_redund_env) {
+               /* switch to next partition for writing */
+               dev_target = !dev_current;
+               /* dev_target: fd_target, erase_target */
+               fd_target = open(DEVNAME(dev_target), O_RDWR);
+               if (fd_target < 0) {
+                       fprintf(stderr,
+                               "Can't open %s: %s\n",
+                               DEVNAME(dev_target), strerror(errno));
+                       rc = -1;
+                       goto exit;
+               }
+       } else {
+               struct stat sb;
+
+               if (fstat(fd_current, &sb) == 0 && S_ISREG(sb.st_mode)) {
+                       /* if any part of flash_open_tempfile() fails we fall
+                        * back to in-place writes
+                        */
+                       fd_target = flash_open_tempfile(&dname, &target_temp);
+               }
+               dev_target = dev_current;
+               if (fd_target == -1)
                        fd_target = fd_current;
+       }
+
+       rc = flash_write(fd_current, fd_target, dev_target);
+
+       if (fsync(fd_current) && !(errno == EINVAL || errno == EROFS)) {
+               fprintf(stderr,
+                       "fsync failed on %s: %s\n",
+                       DEVNAME(dev_current), strerror(errno));
+       }
+
+       if (fd_current != fd_target) {
+               if (fsync(fd_target) &&
+                   !(errno == EINVAL || errno == EROFS)) {
+                       fprintf(stderr,
+                               "fsync failed on %s: %s\n",
+                               DEVNAME(dev_current), strerror(errno));
                }
 
-               rc = flash_write (fd_current, fd_target, dev_target);
+               if (close(fd_target)) {
+                       fprintf(stderr,
+                               "I/O error on %s: %s\n",
+                               DEVNAME(dev_target), strerror(errno));
+                       rc = -1;
+               }
 
-               if (HaveRedundEnv) {
-                       if (close (fd_target)) {
-                               fprintf (stderr,
-                                       "I/O error on %s: %s\n",
-                                       DEVNAME (dev_target),
-                                       strerror (errno));
+               if (rc >= 0 && target_temp) {
+                       int dir_fd;
+
+                       dir_fd = open(dname, O_DIRECTORY | O_RDONLY);
+                       if (dir_fd == -1)
+                               fprintf(stderr,
+                                       "Can't open %s: %s\n",
+                                       dname, strerror(errno));
+
+                       if (rename(target_temp, DEVNAME(dev_target))) {
+                               fprintf(stderr,
+                                       "rename failed %s => %s: %s\n",
+                                       target_temp, DEVNAME(dev_target),
+                                       strerror(errno));
                                rc = -1;
                        }
+
+                       if (dir_fd != -1 && fsync(dir_fd))
+                               fprintf(stderr,
+                                       "fsync failed on %s: %s\n",
+                                       dname, strerror(errno));
+
+                       if (dir_fd != -1 && close(dir_fd))
+                               fprintf(stderr,
+                                       "I/O error on %s: %s\n",
+                                       dname, strerror(errno));
                }
+       }
+ exit:
+       return rc;
+}
+
+static int flash_io(int mode)
+{
+       int fd_current, rc;
+
+       /* dev_current: fd_current, erase_current */
+       fd_current = open(DEVNAME(dev_current), mode);
+       if (fd_current < 0) {
+               fprintf(stderr,
+                       "Can't open %s: %s\n",
+                       DEVNAME(dev_current), strerror(errno));
+               return -1;
+       }
+
+       if (mode == O_RDWR) {
+               rc = flash_io_write(fd_current);
        } else {
-               rc = flash_read (fd_current);
+               rc = flash_read(fd_current);
        }
 
-exit:
-       if (close (fd_current)) {
-               fprintf (stderr,
-                        "I/O error on %s: %s\n",
-                        DEVNAME (dev_current), strerror (errno));
+       if (close(fd_current)) {
+               fprintf(stderr,
+                       "I/O error on %s: %s\n",
+                       DEVNAME(dev_current), strerror(errno));
                return -1;
        }
 
@@ -1130,7 +1400,7 @@ int fw_env_open(struct env_opts *opts)
        if (!opts)
                opts = &default_opts;
 
-       if (parse_config(opts))         /* should fill envdevices */
+       if (parse_config(opts)) /* should fill envdevices */
                return -EINVAL;
 
        addr0 = calloc(1, CUR_ENVSIZE);
@@ -1145,16 +1415,16 @@ int fw_env_open(struct env_opts *opts)
        /* read environment from FLASH to local buffer */
        environment.image = addr0;
 
-       if (HaveRedundEnv) {
+       if (have_redund_env) {
                redundant = addr0;
-               environment.crc         = &redundant->crc;
-               environment.flags       = &redundant->flags;
-               environment.data        = redundant->data;
+               environment.crc = &redundant->crc;
+               environment.flags = &redundant->flags;
+               environment.data = redundant->data;
        } else {
                single = addr0;
-               environment.crc         = &single->crc;
-               environment.flags       = NULL;
-               environment.data        = single->data;
+               environment.crc = &single->crc;
+               environment.flags = NULL;
+               environment.data = single->data;
        }
 
        dev_current = 0;
@@ -1163,21 +1433,15 @@ int fw_env_open(struct env_opts *opts)
                goto open_cleanup;
        }
 
-       crc0 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE);
-
-       if (opts->aes_flag) {
-               ret = env_aes_cbc_crypt(environment.data, 0,
-                                       opts->aes_key);
-               if (ret)
-                       goto open_cleanup;
-       }
+       crc0 = crc32(0, (uint8_t *)environment.data, ENV_SIZE);
 
        crc0_ok = (crc0 == *environment.crc);
-       if (!HaveRedundEnv) {
+       if (!have_redund_env) {
                if (!crc0_ok) {
-                       fprintf (stderr,
+                       fprintf(stderr,
                                "Warning: Bad CRC, using default environment\n");
-                       memcpy(environment.data, default_environment, sizeof default_environment);
+                       memcpy(environment.data, default_environment,
+                              sizeof(default_environment));
                }
        } else {
                flag0 = *environment.flags;
@@ -1217,22 +1481,16 @@ int fw_env_open(struct env_opts *opts)
                           DEVTYPE(!dev_current) == MTD_UBIVOLUME) {
                        environment.flag_scheme = FLAG_INCREMENTAL;
                } else if (DEVTYPE(dev_current) == MTD_ABSENT &&
-                          DEVTYPE(!dev_current) == MTD_ABSENT) {
+                          DEVTYPE(!dev_current) == MTD_ABSENT &&
+                          IS_UBI(dev_current) == IS_UBI(!dev_current)) {
                        environment.flag_scheme = FLAG_INCREMENTAL;
                } else {
-                       fprintf (stderr, "Incompatible flash types!\n");
+                       fprintf(stderr, "Incompatible flash types!\n");
                        ret = -EINVAL;
                        goto open_cleanup;
                }
 
-               crc1 = crc32 (0, (uint8_t *) redundant->data, ENV_SIZE);
-
-               if (opts->aes_flag) {
-                       ret = env_aes_cbc_crypt(redundant->data, 0,
-                                               opts->aes_key);
-                       if (ret)
-                               goto open_cleanup;
-               }
+               crc1 = crc32(0, (uint8_t *)redundant->data, ENV_SIZE);
 
                crc1_ok = (crc1 == redundant->crc);
                flag1 = redundant->flags;
@@ -1242,10 +1500,10 @@ int fw_env_open(struct env_opts *opts)
                } else if (!crc0_ok && crc1_ok) {
                        dev_current = 1;
                } else if (!crc0_ok && !crc1_ok) {
-                       fprintf (stderr,
+                       fprintf(stderr,
                                "Warning: Bad CRC, using default environment\n");
-                       memcpy (environment.data, default_environment,
-                               sizeof default_environment);
+                       memcpy(environment.data, default_environment,
+                              sizeof(default_environment));
                        dev_current = 0;
                } else {
                        switch (environment.flag_scheme) {
@@ -1272,12 +1530,12 @@ int fw_env_open(struct env_opts *opts)
                                else if ((flag1 == 255 && flag0 == 0) ||
                                         flag0 >= flag1)
                                        dev_current = 0;
-                               else /* flag1 > flag0 */
+                               else    /* flag1 > flag0 */
                                        dev_current = 1;
                                break;
                        default:
-                               fprintf (stderr, "Unknown flag scheme %u \n",
-                                        environment.flag_scheme);
+                               fprintf(stderr, "Unknown flag scheme %u\n",
+                                       environment.flag_scheme);
                                return -1;
                        }
                }
@@ -1288,15 +1546,15 @@ int fw_env_open(struct env_opts *opts)
                 * flags before writing out
                 */
                if (dev_current) {
-                       environment.image       = addr1;
-                       environment.crc         = &redundant->crc;
-                       environment.flags       = &redundant->flags;
-                       environment.data        = redundant->data;
-                       free (addr0);
+                       environment.image = addr1;
+                       environment.crc = &redundant->crc;
+                       environment.flags = &redundant->flags;
+                       environment.data = redundant->data;
+                       free(addr0);
                } else {
-                       environment.image       = addr0;
+                       environment.image = addr0;
                        /* Other pointers are already set */
-                       free (addr1);
+                       free(addr1);
                }
 #ifdef DEBUG
                fprintf(stderr, "Selected env in %s\n", DEVNAME(dev_current));
@@ -1304,12 +1562,12 @@ int fw_env_open(struct env_opts *opts)
        }
        return 0;
 
-open_cleanup:
+ open_cleanup:
        if (addr0)
                free(addr0);
 
        if (addr1)
-               free(addr0);
+               free(addr1);
 
        return ret;
 }
@@ -1330,24 +1588,33 @@ int fw_env_close(struct env_opts *opts)
 static int check_device_config(int dev)
 {
        struct stat st;
+       int32_t lnum = 0;
        int fd, rc = 0;
 
+       /* Fills in IS_UBI(), converts DEVNAME() with ubi volume name */
+       ubi_check_dev(dev);
+
        fd = open(DEVNAME(dev), O_RDONLY);
        if (fd < 0) {
                fprintf(stderr,
-                       "Cannot open %s: %s\n",
-                       DEVNAME(dev), strerror(errno));
+                       "Cannot open %s: %s\n", DEVNAME(dev), strerror(errno));
                return -1;
        }
 
        rc = fstat(fd, &st);
        if (rc < 0) {
-               fprintf(stderr, "Cannot stat the file %s\n",
-                       DEVNAME(dev));
+               fprintf(stderr, "Cannot stat the file %s\n", DEVNAME(dev));
                goto err;
        }
 
-       if (S_ISCHR(st.st_mode)) {
+       if (IS_UBI(dev)) {
+               rc = ioctl(fd, UBI_IOCEBISMAP, &lnum);
+               if (rc < 0) {
+                       fprintf(stderr, "Cannot get UBI information for %s\n",
+                               DEVNAME(dev));
+                       goto err;
+               }
+       } else if (S_ISCHR(st.st_mode)) {
                struct mtd_info_user mtdinfo;
                rc = ioctl(fd, MEMGETINFO, &mtdinfo);
                if (rc < 0) {
@@ -1381,14 +1648,16 @@ static int check_device_config(int dev)
                if (DEVOFFSET(dev) < 0) {
                        rc = ioctl(fd, BLKGETSIZE64, &size);
                        if (rc < 0) {
-                               fprintf(stderr, "Could not get block device size on %s\n",
+                               fprintf(stderr,
+                                       "Could not get block device size on %s\n",
                                        DEVNAME(dev));
                                goto err;
                        }
 
                        DEVOFFSET(dev) = DEVOFFSET(dev) + size;
 #ifdef DEBUG
-                       fprintf(stderr, "Calculated device offset 0x%llx on %s\n",
+                       fprintf(stderr,
+                               "Calculated device offset 0x%llx on %s\n",
                                DEVOFFSET(dev), DEVNAME(dev));
 #endif
                }
@@ -1399,18 +1668,20 @@ static int check_device_config(int dev)
                ENVSECTORS(dev) = DIV_ROUND_UP(ENVSIZE(dev), DEVESIZE(dev));
 
        if (DEVOFFSET(dev) % DEVESIZE(dev) != 0) {
-               fprintf(stderr, "Environment does not start on (erase) block boundary\n");
+               fprintf(stderr,
+                       "Environment does not start on (erase) block boundary\n");
                errno = EINVAL;
                return -1;
        }
 
        if (ENVSIZE(dev) > ENVSECTORS(dev) * DEVESIZE(dev)) {
-               fprintf(stderr, "Environment does not fit into available sectors\n");
+               fprintf(stderr,
+                       "Environment does not fit into available sectors\n");
                errno = EINVAL;
                return -1;
        }
 
-err:
+ err:
        close(fd);
        return rc;
 }
@@ -1430,87 +1701,83 @@ static int parse_config(struct env_opts *opts)
                return -1;
        }
 #else
-       DEVNAME (0) = DEVICE1_NAME;
-       DEVOFFSET (0) = DEVICE1_OFFSET;
-       ENVSIZE (0) = ENV1_SIZE;
+       DEVNAME(0) = DEVICE1_NAME;
+       DEVOFFSET(0) = DEVICE1_OFFSET;
+       ENVSIZE(0) = ENV1_SIZE;
 
        /* Set defaults for DEVESIZE, ENVSECTORS later once we
         * know DEVTYPE
         */
 #ifdef DEVICE1_ESIZE
-       DEVESIZE (0) = DEVICE1_ESIZE;
+       DEVESIZE(0) = DEVICE1_ESIZE;
 #endif
 #ifdef DEVICE1_ENVSECTORS
-       ENVSECTORS (0) = DEVICE1_ENVSECTORS;
+       ENVSECTORS(0) = DEVICE1_ENVSECTORS;
 #endif
 
 #ifdef HAVE_REDUND
-       DEVNAME (1) = DEVICE2_NAME;
-       DEVOFFSET (1) = DEVICE2_OFFSET;
-       ENVSIZE (1) = ENV2_SIZE;
+       DEVNAME(1) = DEVICE2_NAME;
+       DEVOFFSET(1) = DEVICE2_OFFSET;
+       ENVSIZE(1) = ENV2_SIZE;
 
        /* Set defaults for DEVESIZE, ENVSECTORS later once we
         * know DEVTYPE
         */
 #ifdef DEVICE2_ESIZE
-       DEVESIZE (1) = DEVICE2_ESIZE;
+       DEVESIZE(1) = DEVICE2_ESIZE;
 #endif
 #ifdef DEVICE2_ENVSECTORS
-       ENVSECTORS (1) = DEVICE2_ENVSECTORS;
+       ENVSECTORS(1) = DEVICE2_ENVSECTORS;
 #endif
-       HaveRedundEnv = 1;
+       have_redund_env = 1;
 #endif
 #endif
        rc = check_device_config(0);
        if (rc < 0)
                return rc;
 
-       if (HaveRedundEnv) {
+       if (have_redund_env) {
                rc = check_device_config(1);
                if (rc < 0)
                        return rc;
 
                if (ENVSIZE(0) != ENVSIZE(1)) {
                        fprintf(stderr,
-                               "Redundant environments have unequal size");
+                               "Redundant environments have unequal size\n");
                        return -1;
                }
        }
 
        usable_envsize = CUR_ENVSIZE - sizeof(uint32_t);
-       if (HaveRedundEnv)
+       if (have_redund_env)
                usable_envsize -= sizeof(char);
 
-       if (opts->aes_flag)
-               usable_envsize &= ~(AES_KEY_LENGTH - 1);
-
        return 0;
 }
 
 #if defined(CONFIG_FILE)
-static int get_config (char *fname)
+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");
+       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));
+                           &ENVSIZE(i), &DEVESIZE(i), &ENVSECTORS(i));
 
                if (rc < 3)
                        continue;
@@ -1523,10 +1790,11 @@ static int get_config (char *fname)
 
                i++;
        }
-       fclose (fp);
+       free(line);
+       fclose(fp);
 
-       HaveRedundEnv = i - 1;
-       if (!i) {                       /* No valid entries found */
+       have_redund_env = i - 1;
+       if (!i) {               /* No valid entries found */
                errno = EINVAL;
                return -1;
        } else