]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/conf.c
Merge pull request #3235 from xinhua9569/master
[mirror_lxc.git] / src / lxc / conf.c
index cb5730af6588ed8d1f5e154d978ddcc7deb86627..457e1e16585b71db1069e7baf4fa86ec5b1acfd8 100644 (file)
@@ -1,25 +1,4 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+/* SPDX-License-Identifier: LGPL-2.1+ */
 
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE 1
@@ -57,6 +36,7 @@
 #include "af_unix.h"
 #include "caps.h"
 #include "cgroup.h"
+#include "cgroup2_devices.h"
 #include "conf.h"
 #include "config.h"
 #include "confile.h"
@@ -79,6 +59,7 @@
 #include "syscall_wrappers.h"
 #include "terminal.h"
 #include "utils.h"
+#include "uuid.h"
 
 #ifdef MAJOR_IN_MKDEV
 #include <sys/mkdev.h>
@@ -306,8 +287,8 @@ static struct limit_opt limit_opt[] = {
 
 static int run_buffer(char *buffer)
 {
-       int ret;
-       char *output;
+       __do_free char *output = NULL;
+       int fd, ret;
        struct lxc_popen_FILE *f;
 
        f = lxc_popen(buffer);
@@ -323,10 +304,25 @@ static int run_buffer(char *buffer)
                return -1;
        }
 
-       while (fgets(output, LXC_LOG_BUFFER_SIZE, f->f))
-               DEBUG("Script %s with output: %s", buffer, output);
+       fd = fileno(f->f);
+       if (fd < 0) {
+               SYSERROR("Failed to retrieve underlying file descriptor");
+               lxc_pclose(f);
+               return -1;
+       }
 
-       free(output);
+       for (int i = 0; i < 10; i++) {
+               ssize_t bytes_read;
+
+               bytes_read = lxc_read_nointr(fd, output, LXC_LOG_BUFFER_SIZE - 1);
+               if (bytes_read > 0) {
+                       output[bytes_read] = '\0';
+                       DEBUG("Script %s produced output: %s", buffer, output);
+                       continue;
+               }
+
+               break;
+       }
 
        ret = lxc_pclose(f);
        if (ret == -1) {
@@ -347,9 +343,8 @@ int run_script_argv(const char *name, unsigned int hook_version,
                    const char *section, const char *script,
                    const char *hookname, char **argv)
 {
+       __do_free char *buffer = NULL;
        int buf_pos, i, ret;
-       char *buffer;
-       int fret = -1;
        size_t size = 0;
 
        if (hook_version == 0)
@@ -393,7 +388,7 @@ int run_script_argv(const char *name, unsigned int hook_version,
                buf_pos = snprintf(buffer, size, "exec %s", script);
        if (buf_pos < 0 || (size_t)buf_pos >= size) {
                ERROR("Failed to create command line for script \"%s\"", script);
-               goto on_error;
+               return -1;
        }
 
        if (hook_version == 1) {
@@ -401,7 +396,7 @@ int run_script_argv(const char *name, unsigned int hook_version,
                if (ret < 0) {
                        SYSERROR("Failed to set environment variable: "
                                 "LXC_HOOK_TYPE=%s", hookname);
-                       goto on_error;
+                       return -1;
                }
                TRACE("Set environment variable: LXC_HOOK_TYPE=%s", hookname);
 
@@ -409,7 +404,7 @@ int run_script_argv(const char *name, unsigned int hook_version,
                if (ret < 0) {
                        SYSERROR("Failed to set environment variable: "
                                 "LXC_HOOK_SECTION=%s", section);
-                       goto on_error;
+                       return -1;
                }
                TRACE("Set environment variable: LXC_HOOK_SECTION=%s", section);
 
@@ -417,13 +412,13 @@ int run_script_argv(const char *name, unsigned int hook_version,
                        char *parent;
 
                        if (!argv || !argv[0])
-                               goto on_error;
+                               return -1;
 
                        ret = setenv("LXC_NET_TYPE", argv[0], 1);
                        if (ret < 0) {
                                SYSERROR("Failed to set environment variable: "
                                         "LXC_NET_TYPE=%s", argv[0]);
-                               goto on_error;
+                               return -1;
                        }
                        TRACE("Set environment variable: LXC_NET_TYPE=%s", argv[0]);
 
@@ -434,7 +429,7 @@ int run_script_argv(const char *name, unsigned int hook_version,
                                if (ret < 0) {
                                        SYSERROR("Failed to set environment "
                                                 "variable: LXC_NET_PARENT=%s", parent);
-                                       goto on_error;
+                                       return -1;
                                }
                                TRACE("Set environment variable: LXC_NET_PARENT=%s", parent);
                        } else if (strcmp(argv[0], "phys") == 0) {
@@ -442,7 +437,7 @@ int run_script_argv(const char *name, unsigned int hook_version,
                                if (ret < 0) {
                                        SYSERROR("Failed to set environment "
                                                 "variable: LXC_NET_PARENT=%s", parent);
-                                       goto on_error;
+                                       return -1;
                                }
                                TRACE("Set environment variable: LXC_NET_PARENT=%s", parent);
                        } else if (strcmp(argv[0], "veth") == 0) {
@@ -452,7 +447,7 @@ int run_script_argv(const char *name, unsigned int hook_version,
                                if (ret < 0) {
                                        SYSERROR("Failed to set environment "
                                                 "variable: LXC_NET_PEER=%s", peer);
-                                       goto on_error;
+                                       return -1;
                                }
                                TRACE("Set environment variable: LXC_NET_PEER=%s", peer);
 
@@ -460,7 +455,7 @@ int run_script_argv(const char *name, unsigned int hook_version,
                                if (ret < 0) {
                                        SYSERROR("Failed to set environment "
                                                 "variable: LXC_NET_PARENT=%s", parent);
-                                       goto on_error;
+                                       return -1;
                                }
                                TRACE("Set environment variable: LXC_NET_PARENT=%s", parent);
                        }
@@ -473,16 +468,12 @@ int run_script_argv(const char *name, unsigned int hook_version,
                ret = snprintf(buffer + buf_pos, len, " %s", argv[i]);
                if (ret < 0 || (size_t)ret >= len) {
                        ERROR("Failed to create command line for script \"%s\"", script);
-                       goto on_error;
+                       return -1;
                }
                buf_pos += ret;
        }
 
-       fret = run_buffer(buffer);
-
-on_error:
-       free(buffer);
-       return fret;
+       return run_buffer(buffer);
 }
 
 int run_script(const char *name, const char *section, const char *script, ...)
@@ -543,9 +534,9 @@ int run_script(const char *name, const char *section, const char *script, ...)
  */
 int pin_rootfs(const char *rootfs)
 {
+       __do_free char *absrootfs = NULL;
        int fd, ret;
        char absrootfspin[PATH_MAX];
-       char *absrootfs;
        struct stat s;
        struct statfs sfs;
 
@@ -557,18 +548,13 @@ int pin_rootfs(const char *rootfs)
                return -2;
 
        ret = stat(absrootfs, &s);
-       if (ret < 0) {
-               free(absrootfs);
+       if (ret < 0)
                return -1;
-       }
 
-       if (!S_ISDIR(s.st_mode)) {
-               free(absrootfs);
+       if (!S_ISDIR(s.st_mode))
                return -2;
-       }
 
        ret = snprintf(absrootfspin, PATH_MAX, "%s/.lxc-keep", absrootfs);
-       free(absrootfs);
        if (ret < 0 || ret >= PATH_MAX)
                return -1;
 
@@ -701,10 +687,9 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
        };
 
        for (i = 0; default_mounts[i].match_mask; i++) {
+               __do_free char *destination = NULL, *source = NULL;
                int saved_errno;
                unsigned long mflags;
-               char *destination = NULL;
-               char *source = NULL;
                if ((flags & default_mounts[i].match_mask) != default_mounts[i].match_flag)
                        continue;
 
@@ -717,16 +702,12 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
 
                if (!default_mounts[i].destination) {
                        ERROR("BUG: auto mounts destination %d was NULL", i);
-                       free(source);
                        return -1;
                }
 
                /* will act like strdup if %r is not present */
                destination = lxc_string_replace("%r", conf->rootfs.path ? conf->rootfs.mount : "", default_mounts[i].destination);
                if (!destination) {
-                       saved_errno = errno;
-                       free(source);
-                       errno = saved_errno;
                        return -1;
                }
 
@@ -744,8 +725,6 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
                        SYSERROR("Failed to mount \"%s\" on \"%s\" with flags %lu", source, destination, mflags);
                }
 
-               free(source);
-               free(destination);
                if (r < 0) {
                        errno = saved_errno;
                        return -1;
@@ -1027,7 +1006,7 @@ int lxc_allocate_ttys(struct lxc_conf *conf)
                        SYSWARN("Failed to set FD_CLOEXEC flag on slave fd %d of "
                                "tty device \"%s\"", tty->slave, tty->name);
 
-               tty->busy = 0;
+               tty->busy = -1;
        }
 
        INFO("Finished creating %zu tty devices", ttys->max);
@@ -1136,18 +1115,21 @@ on_error:
  * error, log it but don't fail yet.
  */
 static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs,
-                        const char *lxcpath)
+                        int autodevtmpfssize, const char *lxcpath)
 {
        __do_free char *path = NULL;
        int ret;
        size_t clen;
        mode_t cur_mask;
+        char mount_options[128];
 
        INFO("Preparing \"/dev\"");
 
        /* $(rootfs->mount) + "/dev/pts" + '\0' */
        clen = (rootfs->path ? strlen(rootfs->mount) : 0) + 9;
        path = must_realloc(NULL, clen);
+       sprintf(mount_options, "size=%d,mode=755", (autodevtmpfssize != 0) ? autodevtmpfssize : 500000);
+       DEBUG("Using mount options: %s", mount_options);
 
        ret = snprintf(path, clen, "%s/dev", rootfs->path ? rootfs->mount : "");
        if (ret < 0 || (size_t)ret >= clen)
@@ -1161,8 +1143,8 @@ static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs,
                goto reset_umask;
        }
 
-       ret = safe_mount("none", path, "tmpfs", 0, "size=500000,mode=755",
-                        rootfs->path ? rootfs->mount : NULL);
+       ret = safe_mount("none", path, "tmpfs", 0, mount_options,
+                        rootfs->path ? rootfs->mount : NULL );
        if (ret < 0) {
                SYSERROR("Failed to mount tmpfs on \"%s\"", path);
                goto reset_umask;
@@ -1270,7 +1252,7 @@ static int lxc_fill_autodev(const struct lxc_rootfs *rootfs)
                                 */
                                ret = open(path, O_RDONLY | O_CLOEXEC);
                                if (ret >= 0) {
-                                       close(ret);
+                                       close_prot_errno_disarm(ret);
                                        /* Device nodes are fully useable. */
                                        use_mknod = LXC_DEVNODE_OPEN;
                                        continue;
@@ -1364,11 +1346,8 @@ static int lxc_mount_rootfs(struct lxc_conf *conf)
 
 int lxc_chroot(const struct lxc_rootfs *rootfs)
 {
+       __do_free char *nroot = NULL;
        int i, ret;
-       char *p, *p2;
-       char buf[LXC_LINELEN];
-       char *nroot;
-       FILE *f;
        char *root = rootfs->mount;
 
        nroot = realpath(root, NULL);
@@ -1378,10 +1357,8 @@ int lxc_chroot(const struct lxc_rootfs *rootfs)
        }
 
        ret = chdir("/");
-       if (ret < 0) {
-               free(nroot);
+       if (ret < 0)
                return -1;
-       }
 
        /* We could use here MS_MOVE, but in userns this mount is locked and
         * can't be moved.
@@ -1389,10 +1366,8 @@ int lxc_chroot(const struct lxc_rootfs *rootfs)
        ret = mount(nroot, "/", NULL, MS_REC | MS_BIND, NULL);
        if (ret < 0) {
                SYSERROR("Failed to mount \"%s\" onto \"/\" as MS_REC | MS_BIND", nroot);
-               free(nroot);
                return -1;
        }
-       free(nroot);
 
        ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL);
        if (ret < 0) {
@@ -1411,7 +1386,11 @@ int lxc_chroot(const struct lxc_rootfs *rootfs)
         * inherited mounts are locked and we should live with all this trash.
         */
        for (;;) {
+               __do_fclose FILE *f = NULL;
+               __do_free char *line = NULL;
+               char *slider1, *slider2;
                int progress = 0;
+               size_t len = 0;
 
                f = fopen("./proc/self/mountinfo", "r");
                if (!f) {
@@ -1419,33 +1398,31 @@ int lxc_chroot(const struct lxc_rootfs *rootfs)
                        return -1;
                }
 
-               while (fgets(buf, LXC_LINELEN, f)) {
-                       for (p = buf, i=0; p && i < 4; i++)
-                               p = strchr(p+1, ' ');
+               while (getline(&line, &len, f) > 0) {
+                       for (slider1 = line, i = 0; slider1 && i < 4; i++)
+                               slider1 = strchr(slider1 + 1, ' ');
 
-                       if (!p)
+                       if (!slider1)
                                continue;
 
-                       p2 = strchr(p+1, ' ');
-                       if (!p2)
+                       slider2 = strchr(slider1 + 1, ' ');
+                       if (!slider2)
                                continue;
 
-                       *p2 = '\0';
-                       *p = '.';
+                       *slider2 = '\0';
+                       *slider1 = '.';
 
-                       if (strcmp(p + 1, "/") == 0)
+                       if (strcmp(slider1 + 1, "/") == 0)
                                continue;
 
-                       if (strcmp(p + 1, "/proc") == 0)
+                       if (strcmp(slider1 + 1, "/proc") == 0)
                                continue;
 
-                       ret = umount2(p, MNT_DETACH);
+                       ret = umount2(slider1, MNT_DETACH);
                        if (ret == 0)
                                progress++;
                }
 
-               fclose(f);
-
                if (!progress)
                        break;
        }
@@ -1497,8 +1474,8 @@ int lxc_chroot(const struct lxc_rootfs *rootfs)
  */
 static int lxc_pivot_root(const char *rootfs)
 {
-       int oldroot;
-       int newroot = -1, ret = -1;
+       __do_close_prot_errno int oldroot = -EBADF, newroot = -EBADF;
+       int ret;
 
        oldroot = open("/", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
        if (oldroot < 0) {
@@ -1509,23 +1486,21 @@ static int lxc_pivot_root(const char *rootfs)
        newroot = open(rootfs, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
        if (newroot < 0) {
                SYSERROR("Failed to open new root directory");
-               goto on_error;
+               return -1;
        }
 
        /* change into new root fs */
        ret = fchdir(newroot);
        if (ret < 0) {
-               ret = -1;
                SYSERROR("Failed to change to new rootfs \"%s\"", rootfs);
-               goto on_error;
+               return -1;
        }
 
        /* pivot_root into our new root fs */
        ret = pivot_root(".", ".");
        if (ret < 0) {
-               ret = -1;
                SYSERROR("Failed to pivot_root()");
-               goto on_error;
+               return -1;
        }
 
        /* At this point the old-root is mounted on top of our new-root. To
@@ -1534,9 +1509,8 @@ static int lxc_pivot_root(const char *rootfs)
         */
        ret = fchdir(oldroot);
        if (ret < 0) {
-               ret = -1;
                SYSERROR("Failed to enter old root directory");
-               goto on_error;
+               return -1;
        }
 
        /* Make oldroot rslave to make sure our umounts don't propagate to the
@@ -1544,36 +1518,25 @@ static int lxc_pivot_root(const char *rootfs)
         */
        ret = mount("", ".", "", MS_SLAVE | MS_REC, NULL);
        if (ret < 0) {
-               ret = -1;
                SYSERROR("Failed to make oldroot rslave");
-               goto on_error;
+               return -1;
        }
 
        ret = umount2(".", MNT_DETACH);
        if (ret < 0) {
-               ret = -1;
                SYSERROR("Failed to detach old root directory");
-               goto on_error;
+               return -1;
        }
 
        ret = fchdir(newroot);
        if (ret < 0) {
-               ret = -1;
                SYSERROR("Failed to re-enter new root directory");
-               goto on_error;
+               return -1;
        }
 
-       ret = 0;
-
        TRACE("pivot_root(\"%s\") successful", rootfs);
 
-on_error:
-       close(oldroot);
-
-       if (newroot >= 0)
-               close(newroot);
-
-       return ret;
+       return 0;
 }
 
 static int lxc_setup_rootfs_switch_root(const struct lxc_rootfs *rootfs)
@@ -1890,16 +1853,21 @@ static void parse_mntopt(char *opt, unsigned long *flags, char **data, size_t si
 {
        struct mount_opt *mo;
 
-       /* If opt is found in mount_opt, set or clear flags.
-        * Otherwise append it to data. */
-
-       for (mo = &mount_opt[0]; mo->name != NULL; mo++) {
-               if (strncmp(opt, mo->name, strlen(mo->name)) == 0) {
-                       if (mo->clear)
-                               *flags &= ~mo->flag;
-                       else
-                               *flags |= mo->flag;
-                       return;
+       /* If '=' is contained in opt, the option must go into data. */
+       if (!strchr(opt, '=')) {
+
+               /* If opt is found in mount_opt, set or clear flags.
+                * Otherwise append it to data. */
+               size_t opt_len = strlen(opt);
+               for (mo = &mount_opt[0]; mo->name != NULL; mo++) {
+                       size_t mo_name_len = strlen(mo->name);
+                       if (opt_len == mo_name_len && strncmp(opt, mo->name, mo_name_len) == 0) {
+                               if (mo->clear)
+                                       *flags &= ~mo->flag;
+                               else
+                                       *flags |= mo->flag;
+                               return;
+                       }
                }
        }
 
@@ -1911,7 +1879,8 @@ static void parse_mntopt(char *opt, unsigned long *flags, char **data, size_t si
 
 int parse_mntopts(const char *mntopts, unsigned long *mntflags, char **mntdata)
 {
-       char *data, *p, *s;
+       __do_free char *data = NULL, *s = NULL;
+       char *p;
        size_t size;
 
        *mntdata = NULL;
@@ -1926,20 +1895,15 @@ int parse_mntopts(const char *mntopts, unsigned long *mntflags, char **mntdata)
 
        size = strlen(s) + 1;
        data = malloc(size);
-       if (!data) {
-               free(s);
+       if (!data)
                return -1;
-       }
        *data = 0;
 
        lxc_iterate_parts(p, s, ",")
                parse_mntopt(p, mntflags, &data, size);
 
        if (*data)
-               *mntdata = data;
-       else
-               free(data);
-       free(s);
+               *mntdata = move_ptr(data);
 
        return 0;
 }
@@ -1964,7 +1928,8 @@ static void parse_propagationopt(char *opt, unsigned long *flags)
 
 int parse_propagationopts(const char *mntopts, unsigned long *pflags)
 {
-       char *p, *s;
+       __do_free char *s = NULL;
+       char *p;
 
        if (!mntopts)
                return 0;
@@ -1978,7 +1943,6 @@ int parse_propagationopts(const char *mntopts, unsigned long *pflags)
        *pflags = 0L;
        lxc_iterate_parts(p, s, ",")
                parse_propagationopt(p, pflags);
-       free(s);
 
        return 0;
 }
@@ -2162,8 +2126,9 @@ static int mount_entry_create_dir_file(const struct mntent *mntent,
                                       const struct lxc_rootfs *rootfs,
                                       const char *lxc_name, const char *lxc_path)
 {
+       __do_free char *p1 = NULL;
        int ret;
-       char *p1, *p2;
+       char *p2;
 
        if (strncmp(mntent->mnt_type, "overlay", 7) == 0) {
                ret = ovl_mkdir(mntent, rootfs, lxc_name, lxc_path);
@@ -2193,7 +2158,6 @@ static int mount_entry_create_dir_file(const struct mntent *mntent,
        p2 = dirname(p1);
 
        ret = mkdir_p(p2, 0755);
-       free(p1);
        if (ret < 0 && errno != EEXIST) {
                SYSERROR("Failed to create directory \"%s\"", path);
                return -1;
@@ -2214,9 +2178,9 @@ static inline int mount_entry_on_generic(struct mntent *mntent,
                                         const char *lxc_name,
                                         const char *lxc_path)
 {
+       __do_free char *mntdata = NULL;
        int ret;
        unsigned long mntflags;
-       char *mntdata;
        bool dev, optional, relative;
        unsigned long pflags = 0;
        char *rootfs_path = NULL;
@@ -2249,7 +2213,6 @@ static inline int mount_entry_on_generic(struct mntent *mntent,
        ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type, mntflags,
                          pflags, mntdata, optional, dev, relative, rootfs_path);
 
-       free(mntdata);
        return ret;
 }
 
@@ -2402,10 +2365,10 @@ static const char nesting_helpers[] =
 FILE *make_anonymous_mount_file(struct lxc_list *mount,
                                bool include_nesting_helpers)
 {
+       __do_close_prot_errno int fd = -EBADF;
        int ret;
        char *mount_entry;
        struct lxc_list *iterator;
-       int fd = -1;
 
        fd = memfd_create(".lxc_mount_file", MFD_CLOEXEC);
        if (fd < 0) {
@@ -2431,30 +2394,25 @@ FILE *make_anonymous_mount_file(struct lxc_list *mount,
 
                ret = lxc_write_nointr(fd, mount_entry, len);
                if (ret != len)
-                       goto on_error;
+                       return NULL;
 
                ret = lxc_write_nointr(fd, "\n", 1);
                if (ret != 1)
-                       goto on_error;
+                       return NULL;
        }
 
        if (include_nesting_helpers) {
                ret = lxc_write_nointr(fd, nesting_helpers,
                                       STRARRAYLEN(nesting_helpers));
                if (ret != STRARRAYLEN(nesting_helpers))
-                       goto on_error;
+                       return NULL;
        }
 
        ret = lseek(fd, 0, SEEK_SET);
        if (ret < 0)
-               goto on_error;
-
-       return fdopen(fd, "r+");
+               return NULL;
 
-on_error:
-       SYSERROR("Failed to write mount entry to temporary mount file");
-       close(fd);
-       return NULL;
+       return fdopen(move_fd(fd), "r+");
 }
 
 static int setup_mount_entries(const struct lxc_conf *conf,
@@ -2462,17 +2420,13 @@ static int setup_mount_entries(const struct lxc_conf *conf,
                               struct lxc_list *mount, const char *lxc_name,
                               const char *lxc_path)
 {
-       int ret;
-       FILE *f;
+       __do_fclose FILE *f = NULL;
 
        f = make_anonymous_mount_file(mount, conf->lsm_aa_allow_nesting);
        if (!f)
                return -1;
 
-       ret = mount_file_entries(conf, rootfs, f, lxc_name, lxc_path);
-       fclose(f);
-
-       return ret;
+       return mount_file_entries(conf, rootfs, f, lxc_name, lxc_path);
 }
 
 static int parse_cap(const char *cap)
@@ -2660,10 +2614,10 @@ int setup_resource_limits(struct lxc_list *limits, pid_t pid)
 
 int setup_sysctl_parameters(struct lxc_list *sysctls)
 {
+       __do_free char *tmp = NULL;
        struct lxc_list *it;
        struct lxc_sysctl *elem;
        int ret = 0;
-       char *tmp = NULL;
        char filename[PATH_MAX] = {0};
 
        lxc_list_for_each (it, sysctls) {
@@ -2675,7 +2629,6 @@ int setup_sysctl_parameters(struct lxc_list *sysctls)
                }
 
                ret = snprintf(filename, sizeof(filename), "/proc/sys/%s", tmp);
-               free(tmp);
                if (ret < 0 || (size_t)ret >= sizeof(filename)) {
                        ERROR("Error setting up sysctl parameters path");
                        return -1;
@@ -2695,10 +2648,10 @@ int setup_sysctl_parameters(struct lxc_list *sysctls)
 
 int setup_proc_filesystem(struct lxc_list *procs, pid_t pid)
 {
+       __do_free char *tmp = NULL;
        struct lxc_list *it;
        struct lxc_proc *elem;
        int ret = 0;
-       char *tmp = NULL;
        char filename[PATH_MAX] = {0};
 
        lxc_list_for_each (it, procs) {
@@ -2710,7 +2663,6 @@ int setup_proc_filesystem(struct lxc_list *procs, pid_t pid)
                }
 
                ret = snprintf(filename, sizeof(filename), "/proc/%d/%s", pid, tmp);
-               free(tmp);
                if (ret < 0 || (size_t)ret >= sizeof(filename)) {
                        ERROR("Error setting up proc filesystem path");
                        return -1;
@@ -2768,6 +2720,7 @@ struct lxc_conf *lxc_conf_init(void)
        new->logfd = -1;
        lxc_list_init(&new->cgroup);
        lxc_list_init(&new->cgroup2);
+       lxc_list_init(&new->devices);
        lxc_list_init(&new->network);
        lxc_list_init(&new->mount_list);
        lxc_list_init(&new->caps);
@@ -2800,6 +2753,7 @@ struct lxc_conf *lxc_conf_init(void)
        new->init_gid = 0;
        memset(&new->cgroup_meta, 0, sizeof(struct lxc_cgroup));
        memset(&new->ns_share, 0, sizeof(char *) * LXC_NS_MAX);
+       seccomp_conf_init(new);
 
        return new;
 }
@@ -2807,30 +2761,28 @@ struct lxc_conf *lxc_conf_init(void)
 int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
                     size_t buf_size)
 {
-       int fd, ret;
+       __do_close_prot_errno int fd = -EBADF;
+       int ret;
        char path[PATH_MAX];
 
        if (geteuid() != 0 && idtype == ID_TYPE_GID) {
-               size_t buflen;
+               __do_close_prot_errno int setgroups_fd = -EBADF;
 
                ret = snprintf(path, PATH_MAX, "/proc/%d/setgroups", pid);
                if (ret < 0 || ret >= PATH_MAX)
                        return -E2BIG;
 
-               fd = open(path, O_WRONLY);
-               if (fd < 0 && errno != ENOENT) {
+               setgroups_fd = open(path, O_WRONLY);
+               if (setgroups_fd < 0 && errno != ENOENT) {
                        SYSERROR("Failed to open \"%s\"", path);
                        return -1;
                }
 
-               if (fd >= 0) {
-                       buflen = STRLITERALLEN("deny\n");
-                       errno = 0;
-                       ret = lxc_write_nointr(fd, "deny\n", buflen);
-                       close(fd);
-                       if (ret != buflen) {
-                               SYSERROR("Failed to write \"deny\" to "
-                                        "\"/proc/%d/setgroups\"", pid);
+               if (setgroups_fd >= 0) {
+                       ret = lxc_write_nointr(setgroups_fd, "deny\n",
+                                              STRLITERALLEN("deny\n"));
+                       if (ret != STRLITERALLEN("deny\n")) {
+                               SYSERROR("Failed to write \"deny\" to \"/proc/%d/setgroups\"", pid);
                                return -1;
                        }
                        TRACE("Wrote \"deny\" to \"/proc/%d/setgroups\"", pid);
@@ -2848,9 +2800,7 @@ int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
                return -1;
        }
 
-       errno = 0;
        ret = lxc_write_nointr(fd, buf, buf_size);
-       close(fd);
        if (ret != buf_size) {
                SYSERROR("Failed to write %cid mapping to \"%s\"",
                         idtype == ID_TYPE_UID ? 'u' : 'g', path);
@@ -2869,29 +2819,27 @@ int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
  */
 static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap)
 {
-       char *path;
+       __do_free char *path = NULL;
        int ret;
        struct stat st;
-       int fret = 0;
 
+       errno = EINVAL;
        if (cap != CAP_SETUID && cap != CAP_SETGID)
-               return -EINVAL;
+               return -1;
 
+       errno = ENOENT;
        path = on_path(binary, NULL);
        if (!path)
-               return -ENOENT;
+               return -1;
 
        ret = stat(path, &st);
-       if (ret < 0) {
-               fret = -errno;
-               goto cleanup;
-       }
+       if (ret < 0)
+               return -1;
 
        /* Check if the binary is setuid. */
        if (st.st_mode & S_ISUID) {
                DEBUG("The binary \"%s\" does have the setuid bit set", path);
-               fret = 1;
-               goto cleanup;
+               return 1;
        }
 
 #if HAVE_LIBCAP && LIBCAP_SUPPORTS_FILE_CAPABILITIES
@@ -2901,8 +2849,7 @@ static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap)
            lxc_file_cap_is_set(path, CAP_SETUID, CAP_PERMITTED)) {
                DEBUG("The binary \"%s\" has CAP_SETUID in its CAP_EFFECTIVE "
                      "and CAP_PERMITTED sets", path);
-               fret = 1;
-               goto cleanup;
+               return 1;
        }
 
        /* Check if it has the CAP_SETGID capability. */
@@ -2911,8 +2858,7 @@ static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap)
            lxc_file_cap_is_set(path, CAP_SETGID, CAP_PERMITTED)) {
                DEBUG("The binary \"%s\" has CAP_SETGID in its CAP_EFFECTIVE "
                      "and CAP_PERMITTED sets", path);
-               fret = 1;
-               goto cleanup;
+               return 1;
        }
 #else
        /* If we cannot check for file capabilities we need to give the benefit
@@ -2921,12 +2867,9 @@ static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap)
         */
        DEBUG("Cannot check for file capabilities as full capability support is "
              "missing. Manual intervention needed");
-       fret = 1;
 #endif
 
-cleanup:
-       free(path);
-       return fret;
+       return 1;
 }
 
 int lxc_map_ids_exec_wrapper(void *args)
@@ -3314,11 +3257,12 @@ void tmp_proc_unmount(struct lxc_conf *lxc_conf)
 /* Walk /proc/mounts and change any shared entries to slave. */
 void remount_all_slave(void)
 {
-       int memfd, mntinfo_fd, ret;
+       __do_free char *line = NULL;
+       __do_fclose FILE *f = NULL;
+       __do_close_prot_errno int memfd = -EBADF, mntinfo_fd = -EBADF;
+       int ret;
        ssize_t copied;
-       FILE *f;
        size_t len = 0;
-       char *line = NULL;
 
        mntinfo_fd = open("/proc/self/mountinfo", O_RDONLY | O_CLOEXEC);
        if (mntinfo_fd < 0) {
@@ -3332,13 +3276,11 @@ void remount_all_slave(void)
 
                if (errno != ENOSYS) {
                        SYSERROR("Failed to create temporary in-memory file");
-                       close(mntinfo_fd);
                        return;
                }
 
                memfd = lxc_make_tmpfile(template, true);
                if (memfd < 0) {
-                       close(mntinfo_fd);
                        WARN("Failed to create temporary file");
                        return;
                }
@@ -3351,30 +3293,27 @@ again:
                        goto again;
 
                SYSERROR("Failed to copy \"/proc/self/mountinfo\"");
-               close(mntinfo_fd);
-               close(memfd);
                return;
        }
-       close(mntinfo_fd);
 
-       /* After a successful fdopen() memfd will be closed when calling
-        * fclose(f). Calling close(memfd) afterwards is undefined.
-        */
        ret = lseek(memfd, 0, SEEK_SET);
        if (ret < 0) {
                SYSERROR("Failed to reset file descriptor offset");
-               close(memfd);
                return;
        }
 
        f = fdopen(memfd, "r");
        if (!f) {
-               SYSERROR("Failed to open copy of \"/proc/self/mountinfo\" to mark "
-                               "all shared. Continuing");
-               close(memfd);
+               SYSERROR("Failed to open copy of \"/proc/self/mountinfo\" to mark all shared. Continuing");
                return;
        }
 
+       /*
+        * After a successful fdopen() memfd will be closed when calling
+        * fclose(f). Calling close(memfd) afterwards is undefined.
+        */
+       move_fd(memfd);
+
        while (getline(&line, &len, f) != -1) {
                char *opts, *target;
 
@@ -3399,8 +3338,6 @@ again:
                }
                TRACE("Remounted \"%s\" as MS_SLAVE", target);
        }
-       fclose(f);
-       free(line);
        TRACE("Remounted all mount table entries as MS_SLAVE");
 }
 
@@ -3414,10 +3351,9 @@ static int lxc_execute_bind_init(struct lxc_handler *handler)
        /* If init exists in the container, don't bind mount a static one */
        p = choose_init(conf->rootfs.mount);
        if (p) {
-               char *old = p;
+               __do_free char *old = p;
 
                p = strdup(old + strlen(conf->rootfs.mount));
-               free(old);
                if (!p)
                        return -ENOMEM;
 
@@ -3542,6 +3478,56 @@ static bool execveat_supported(void)
        return true;
 }
 
+static int lxc_setup_boot_id(void)
+{
+       int ret;
+       const char *boot_id_path = "/proc/sys/kernel/random/boot_id";
+       const char *mock_boot_id_path = "/dev/.lxc-boot-id";
+       lxc_id128_t n;
+
+       if (access(boot_id_path, F_OK))
+               return 0;
+
+       memset(&n, 0, sizeof(n));
+       if (lxc_id128_randomize(&n)) {
+               SYSERROR("Failed to generate random data for uuid");
+               return -1;
+       }
+
+       ret = lxc_id128_write(mock_boot_id_path, n);
+       if (ret < 0) {
+               SYSERROR("Failed to write uuid to %s", mock_boot_id_path);
+               return -1;
+       }
+
+       ret = chmod(mock_boot_id_path, 0444);
+       if (ret < 0) {
+               SYSERROR("Failed to chown %s", mock_boot_id_path);
+               (void)unlink(mock_boot_id_path);
+               return -1;
+       }
+
+       ret = mount(mock_boot_id_path, boot_id_path, NULL, MS_BIND, NULL);
+       if (ret < 0) {
+               SYSERROR("Failed to mount %s to %s", mock_boot_id_path,
+                        boot_id_path);
+               (void)unlink(mock_boot_id_path);
+               return -1;
+       }
+
+       ret = mount(NULL, boot_id_path, NULL,
+                   (MS_BIND | MS_REMOUNT | MS_RDONLY | MS_NOSUID | MS_NOEXEC |
+                    MS_NODEV),
+                   NULL);
+       if (ret < 0) {
+               SYSERROR("Failed to remount %s read-only", boot_id_path);
+               (void)unlink(mock_boot_id_path);
+               return -1;
+       }
+
+       return 0;
+}
+
 int lxc_setup(struct lxc_handler *handler)
 {
        int ret;
@@ -3566,20 +3552,23 @@ int lxc_setup(struct lxc_handler *handler)
        if (ret < 0)
                return -1;
 
-       ret = lxc_setup_network_in_child_namespaces(lxc_conf, &lxc_conf->network);
-       if (ret < 0) {
-               ERROR("Failed to setup network");
-               return -1;
-       }
+       if (handler->ns_clone_flags & CLONE_NEWNET) {
+               ret = lxc_setup_network_in_child_namespaces(lxc_conf,
+                                                           &lxc_conf->network);
+               if (ret < 0) {
+                       ERROR("Failed to setup network");
+                       return -1;
+               }
 
-       ret = lxc_network_send_name_and_ifindex_to_parent(handler);
-       if (ret < 0) {
-               ERROR("Failed to send network device names and ifindices to parent");
-               return -1;
+               ret = lxc_network_send_name_and_ifindex_to_parent(handler);
+               if (ret < 0) {
+                       ERROR("Failed to send network device names and ifindices to parent");
+                       return -1;
+               }
        }
 
        if (lxc_conf->autodev > 0) {
-               ret = mount_autodev(name, &lxc_conf->rootfs, lxcpath);
+               ret = mount_autodev(name, &lxc_conf->rootfs, lxc_conf->autodevtmpfssize, lxcpath);
                if (ret < 0) {
                        ERROR("Failed to mount \"/dev\"");
                        return -1;
@@ -3601,6 +3590,15 @@ int lxc_setup(struct lxc_handler *handler)
                return -1;
        }
 
+       if (!lxc_list_empty(&lxc_conf->mount_list)) {
+               ret = setup_mount_entries(lxc_conf, &lxc_conf->rootfs,
+                                         &lxc_conf->mount_list, name, lxcpath);
+               if (ret < 0) {
+                       ERROR("Failed to setup mount entries");
+                       return -1;
+               }
+       }
+
        if (lxc_conf->is_execute) {
                if (execveat_supported()) {
                        int fd;
@@ -3659,15 +3657,6 @@ int lxc_setup(struct lxc_handler *handler)
                }
        }
 
-       if (!lxc_list_empty(&lxc_conf->mount_list)) {
-               ret = setup_mount_entries(lxc_conf, &lxc_conf->rootfs,
-                                         &lxc_conf->mount_list, name, lxcpath);
-               if (ret < 0) {
-                       ERROR("Failed to setup mount entries");
-                       return -1;
-               }
-       }
-
        /* Make sure any start hooks are in the container */
        if (!verify_start_hooks(lxc_conf)) {
                ERROR("Failed to verify start hooks");
@@ -3699,6 +3688,10 @@ int lxc_setup(struct lxc_handler *handler)
                return -1;
        }
 
+       /* Setting the boot-id is best-effort for now. */
+       if (lxc_conf->autodev > 0)
+               (void)lxc_setup_boot_id();
+
        ret = lxc_setup_devpts(lxc_conf);
        if (ret < 0) {
                ERROR("Failed to setup new devpts instance");
@@ -3753,29 +3746,14 @@ int run_lxc_hooks(const char *name, char *hookname, struct lxc_conf *conf,
                  char *argv[])
 {
        struct lxc_list *it;
-       int which = -1;
-
-       if (strcmp(hookname, "pre-start") == 0)
-               which = LXCHOOK_PRESTART;
-       else if (strcmp(hookname, "start-host") == 0)
-               which = LXCHOOK_START_HOST;
-       else if (strcmp(hookname, "pre-mount") == 0)
-               which = LXCHOOK_PREMOUNT;
-       else if (strcmp(hookname, "mount") == 0)
-               which = LXCHOOK_MOUNT;
-       else if (strcmp(hookname, "autodev") == 0)
-               which = LXCHOOK_AUTODEV;
-       else if (strcmp(hookname, "start") == 0)
-               which = LXCHOOK_START;
-       else if (strcmp(hookname, "stop") == 0)
-               which = LXCHOOK_STOP;
-       else if (strcmp(hookname, "post-stop") == 0)
-               which = LXCHOOK_POSTSTOP;
-       else if (strcmp(hookname, "clone") == 0)
-               which = LXCHOOK_CLONE;
-       else if (strcmp(hookname, "destroy") == 0)
-               which = LXCHOOK_DESTROY;
-       else
+       int which;
+
+       for (which = 0; which < NUM_LXC_HOOKS; which ++) {
+               if (strcmp(hookname, lxchook_names[which]) == 0)
+                       break;
+       }
+
+       if (which >= NUM_LXC_HOOKS)
                return -1;
 
        lxc_list_for_each (it, &conf->hooks[which]) {
@@ -3890,6 +3868,17 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version)
        return 0;
 }
 
+static void lxc_clear_devices(struct lxc_conf *conf)
+{
+       struct lxc_list *list = &conf->devices;
+       struct lxc_list *it, *next;
+
+       lxc_list_for_each_safe(it, list, next) {
+               lxc_list_del(it);
+               free(it);
+       }
+}
+
 int lxc_clear_limits(struct lxc_conf *c, const char *key)
 {
        struct lxc_list *it, *next;
@@ -4104,6 +4093,7 @@ void lxc_conf_free(struct lxc_conf *conf)
        free(conf->rootfs.bdev_type);
        free(conf->rootfs.options);
        free(conf->rootfs.path);
+       free(conf->rootfs.data);
        free(conf->logfile);
        if (conf->logfd != -1)
                close(conf->logfd);
@@ -4121,11 +4111,13 @@ void lxc_conf_free(struct lxc_conf *conf)
        free(conf->lsm_aa_profile);
        free(conf->lsm_aa_profile_computed);
        free(conf->lsm_se_context);
-       lxc_seccomp_free(conf);
+       lxc_seccomp_free(&conf->seccomp);
        lxc_clear_config_caps(conf);
        lxc_clear_config_keepcaps(conf);
        lxc_clear_cgroups(conf, "lxc.cgroup", CGROUP_SUPER_MAGIC);
        lxc_clear_cgroups(conf, "lxc.cgroup2", CGROUP2_SUPER_MAGIC);
+       lxc_clear_devices(conf);
+       lxc_clear_cgroup2_devices(conf);
        lxc_clear_hooks(conf, "lxc.hook");
        lxc_clear_mount_entries(conf);
        lxc_clear_idmaps(conf);
@@ -4252,18 +4244,20 @@ static struct id_map *mapped_hostid_add(struct lxc_conf *conf, uid_t id,
 
 struct lxc_list *get_minimal_idmap(struct lxc_conf *conf)
 {
+       __do_free struct id_map *container_root_uid = NULL,
+                               *container_root_gid = NULL,
+                               *host_uid_map = NULL, *host_gid_map = NULL;
+       __do_free struct lxc_list *idmap = NULL;
        uid_t euid, egid;
        uid_t nsuid = (conf->root_nsuid_map != NULL) ? 0 : conf->init_uid;
        gid_t nsgid = (conf->root_nsgid_map != NULL) ? 0 : conf->init_gid;
-       struct lxc_list *idmap = NULL, *tmplist = NULL;
-       struct id_map *container_root_uid = NULL, *container_root_gid = NULL,
-                     *host_uid_map = NULL, *host_gid_map = NULL;
+       struct lxc_list *tmplist = NULL;
 
        /* Find container root mappings. */
        container_root_uid = mapped_nsid_add(conf, nsuid, ID_TYPE_UID);
        if (!container_root_uid) {
                DEBUG("Failed to find mapping for namespace uid %d", 0);
-               goto on_error;
+               return NULL;
        }
        euid = geteuid();
        if (euid >= container_root_uid->hostid &&
@@ -4273,7 +4267,7 @@ struct lxc_list *get_minimal_idmap(struct lxc_conf *conf)
        container_root_gid = mapped_nsid_add(conf, nsgid, ID_TYPE_GID);
        if (!container_root_gid) {
                DEBUG("Failed to find mapping for namespace gid %d", 0);
-               goto on_error;
+               return NULL;
        }
        egid = getegid();
        if (egid >= container_root_gid->hostid &&
@@ -4285,84 +4279,68 @@ struct lxc_list *get_minimal_idmap(struct lxc_conf *conf)
                host_uid_map = mapped_hostid_add(conf, euid, ID_TYPE_UID);
        if (!host_uid_map) {
                DEBUG("Failed to find mapping for uid %d", euid);
-               goto on_error;
+               return NULL;
        }
 
        if (!host_gid_map)
                host_gid_map = mapped_hostid_add(conf, egid, ID_TYPE_GID);
        if (!host_gid_map) {
                DEBUG("Failed to find mapping for gid %d", egid);
-               goto on_error;
+               return NULL;
        }
 
        /* Allocate new {g,u}id map list. */
        idmap = malloc(sizeof(*idmap));
        if (!idmap)
-               goto on_error;
+               return NULL;
        lxc_list_init(idmap);
 
        /* Add container root to the map. */
        tmplist = malloc(sizeof(*tmplist));
        if (!tmplist)
-               goto on_error;
+               return NULL;
        lxc_list_add_elem(tmplist, container_root_uid);
        lxc_list_add_tail(idmap, tmplist);
 
        if (host_uid_map && (host_uid_map != container_root_uid)) {
                /* idmap will now keep track of that memory. */
-               container_root_uid = NULL;
+               move_ptr(container_root_uid);
 
                /* Add container root to the map. */
                tmplist = malloc(sizeof(*tmplist));
                if (!tmplist)
-                       goto on_error;
+                       return NULL;
                lxc_list_add_elem(tmplist, host_uid_map);
                lxc_list_add_tail(idmap, tmplist);
        }
        /* idmap will now keep track of that memory. */
-       container_root_uid = NULL;
+       move_ptr(container_root_uid);
        /* idmap will now keep track of that memory. */
-       host_uid_map = NULL;
+       move_ptr(host_uid_map);
 
        tmplist = malloc(sizeof(*tmplist));
        if (!tmplist)
-               goto on_error;
+               return NULL;
        lxc_list_add_elem(tmplist, container_root_gid);
        lxc_list_add_tail(idmap, tmplist);
 
        if (host_gid_map && (host_gid_map != container_root_gid)) {
                /* idmap will now keep track of that memory. */
-               container_root_gid = NULL;
+               move_ptr(container_root_gid);
 
                tmplist = malloc(sizeof(*tmplist));
                if (!tmplist)
-                       goto on_error;
+                       return NULL;
                lxc_list_add_elem(tmplist, host_gid_map);
                lxc_list_add_tail(idmap, tmplist);
        }
        /* idmap will now keep track of that memory. */
-       container_root_gid = NULL;
+       move_ptr(container_root_gid);
        /* idmap will now keep track of that memory. */
-       host_gid_map = NULL;
+       move_ptr(host_gid_map);
 
        TRACE("Allocated minimal idmapping");
-       return idmap;
-
-on_error:
-       if (idmap) {
-               lxc_free_idmap(idmap);
-               free(idmap);
-       }
-       if (container_root_uid)
-               free(container_root_uid);
-       if (container_root_gid)
-               free(container_root_gid);
-       if (host_uid_map && (host_uid_map != container_root_uid))
-               free(host_uid_map);
-       if (host_gid_map && (host_gid_map != container_root_gid))
-               free(host_gid_map);
-
-       return NULL;
+       return move_ptr(idmap);
 }
 
 /* Run a function in a new user namespace.
@@ -4405,7 +4383,7 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
        d.p[1] = p[1];
 
        /* Clone child in new user namespace. */
-       pid = lxc_raw_clone_cb(run_userns_fn, &d, CLONE_NEWUSER);
+       pid = lxc_raw_clone_cb(run_userns_fn, &d, CLONE_NEWUSER, NULL);
        if (pid < 0) {
                ERROR("Failed to clone process in new user namespace");
                goto on_error;
@@ -4487,7 +4465,7 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
        d.p[1] = p[1];
 
        /* Clone child in new user namespace. */
-       pid = lxc_clone(run_userns_fn, &d, CLONE_NEWUSER);
+       pid = lxc_clone(run_userns_fn, &d, CLONE_NEWUSER, NULL);
        if (pid < 0) {
                ERROR("Failed to clone process in new user namespace");
                goto on_error;
@@ -4644,10 +4622,9 @@ on_error:
 /* not thread-safe, do not use from api without first forking */
 static char *getuname(void)
 {
+       __do_free char *buf = NULL;
        struct passwd pwent;
        struct passwd *pwentp = NULL;
-       char *buf;
-       char *username;
        size_t bufsize;
        int ret;
 
@@ -4665,23 +4642,18 @@ static char *getuname(void)
                        WARN("Could not find matched password record.");
 
                ERROR("Failed to get password record - %u", geteuid());
-               free(buf);
                return NULL;
        }
 
-       username = strdup(pwent.pw_name);
-       free(buf);
-
-       return username;
+       return strdup(pwent.pw_name);
 }
 
 /* not thread-safe, do not use from api without first forking */
 static char *getgname(void)
 {
+       __do_free char *buf = NULL;
        struct group grent;
        struct group *grentp = NULL;
-       char *buf;
-       char *grname;
        size_t bufsize;
        int ret;
 
@@ -4699,44 +4671,35 @@ static char *getgname(void)
                        WARN("Could not find matched group record");
 
                ERROR("Failed to get group record - %u", getegid());
-               free(buf);
                return NULL;
        }
 
-       grname = strdup(grent.gr_name);
-       free(buf);
-
-       return grname;
+       return strdup(grent.gr_name);
 }
 
 /* not thread-safe, do not use from api without first forking */
 void suggest_default_idmap(void)
 {
-       char *uname, *gname;
-       FILE *f;
+       __do_free char *gname = NULL, *line = NULL, *uname = NULL;
+       __do_fclose FILE *subuid_f = NULL, *subgid_f = NULL;
        unsigned int uid = 0, urange = 0, gid = 0, grange = 0;
        size_t len = 0;
-       char *line = NULL;
 
        uname = getuname();
        if (!uname)
                return;
 
        gname = getgname();
-       if (!gname) {
-               free(uname);
+       if (!gname)
                return;
-       }
 
-       f = fopen(subuidfile, "r");
-       if (!f) {
+       subuid_f = fopen(subuidfile, "r");
+       if (!subuid_f) {
                ERROR("Your system is not configured with subuids");
-               free(gname);
-               free(uname);
                return;
        }
 
-       while (getline(&line, &len, f) != -1) {
+       while (getline(&line, &len, subuid_f) != -1) {
                char *p, *p2;
                size_t no_newline = 0;
 
@@ -4766,17 +4729,14 @@ void suggest_default_idmap(void)
                if (lxc_safe_uint(p2, &urange) < 0)
                        WARN("Could not parse UID range");
        }
-       fclose(f);
 
-       f = fopen(subgidfile, "r");
-       if (!f) {
+       subgid_f = fopen(subgidfile, "r");
+       if (!subgid_f) {
                ERROR("Your system is not configured with subgids");
-               free(gname);
-               free(uname);
                return;
        }
 
-       while (getline(&line, &len, f) != -1) {
+       while (getline(&line, &len, subgid_f) != -1) {
                char *p, *p2;
                size_t no_newline = 0;
 
@@ -4806,15 +4766,10 @@ void suggest_default_idmap(void)
                if (lxc_safe_uint(p2, &grange) < 0)
                        WARN("Could not parse GID range");
        }
-       fclose(f);
-
-       free(line);
 
        if (!urange || !grange) {
                ERROR("You do not have subuids or subgids allocated");
                ERROR("Unprivileged containers require subuids and subgids");
-               free(uname);
-               free(gname);
                return;
        }
 
@@ -4824,9 +4779,6 @@ void suggest_default_idmap(void)
        ERROR("lxc.include = %s", LXC_DEFAULT_CONFIG);
        ERROR("lxc.idmap = u 0 %u %u", uid, urange);
        ERROR("lxc.idmap = g 0 %u %u", gid, grange);
-
-       free(gname);
-       free(uname);
 }
 
 static void free_cgroup_settings(struct lxc_list *result)