Hi alex,

On 08/03/2018 12:52, Alex Kiernan wrote:
> If the U-Boot environment is stored in a regular file and redundant
> operation isn't set, then write to a temporary file and perform an
> atomic rename.
> 

Even if it is not explicitely set (IMHO it should), this code can
be used as library and linked to own application. That means that
concurrency can happens. I mean:

> Signed-off-by: Alex Kiernan <[email protected]>
> ---
> 
>  tools/env/fw_env.c | 81 
> ++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 78 insertions(+), 3 deletions(-)
> 
> diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
> index 2df3504..b814c4e 100644
> --- a/tools/env/fw_env.c
> +++ b/tools/env/fw_env.c
> @@ -14,6 +14,7 @@
>  #include <errno.h>
>  #include <env_flags.h>
>  #include <fcntl.h>
> +#include <libgen.h>
>  #include <linux/fs.h>
>  #include <linux/stringify.h>
>  #include <ctype.h>
> @@ -1229,9 +1230,46 @@ static int flash_read (int fd)
>       return 0;
>  }
>  
> +static int flash_open_tempfile(const char **dname, const char **target_temp)
> +{
> +     char *dup_name = strdup(DEVNAME (dev_current));
> +     char *temp_name = NULL;
> +     int rc = -1;
> +
> +     if (!dup_name)
> +             return -1;
> +
> +     *dname = dirname(dup_name);
> +     if (!*dname)
> +             goto err;
> +
> +     rc = asprintf(&temp_name, "%s/uboot.tmp", *dname);

Filename is fixed - should we not use mkstemp ?

> +     if (rc == -1)
> +             goto err;
> +
> +     rc = open(temp_name, O_RDWR | O_CREAT | O_TRUNC, 0700);
> +     if (rc == -1) {
> +             /* fall back to in place write */
> +             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;
> +     }
> +
> +err:
> +     if (dup_name)
> +             free(dup_name);
> +
> +     return rc;
> +}
> +
>  static int flash_io_write (int fd_current)
>  {
> -     int fd_target, rc, dev_target;
> +     int fd_target = -1, rc, dev_target;
> +     const char *dname, *target_temp = NULL;
>  
>       if (HaveRedundEnv) {
>               /* switch to next partition for writing */
> @@ -1247,8 +1285,17 @@ static int flash_io_write (int fd_current)
>                       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;
> -             fd_target = fd_current;
> +             if (fd_target == -1)
> +                     fd_target = fd_current;
>       }
>  
>       rc = flash_write (fd_current, fd_target, dev_target);
> @@ -1260,7 +1307,7 @@ static int flash_io_write (int fd_current)
>                        DEVNAME (dev_current), strerror (errno));
>       }
>  
> -     if (HaveRedundEnv) {
> +     if (fd_current != fd_target) {
>               if (fsync(fd_target) &&
>                   !(errno == EINVAL || errno == EROFS)) {
>                       fprintf (stderr,
> @@ -1275,6 +1322,34 @@ static int flash_io_write (int fd_current)
>                                strerror (errno));
>                       rc = -1;
>               }
> +
> +             if (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;
> 

Best regards,
Stefano

-- 
=====================================================================
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: [email protected]
=====================================================================
_______________________________________________
U-Boot mailing list
[email protected]
https://lists.denx.de/listinfo/u-boot

Reply via email to