From f0ec738376dfc54620d5e66ef34fee529cd61bf2 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 5 Jan 2017 21:57:41 -0500 Subject: [PATCH] libpriv: Enhance internal bwrap API Make it a real struct with methods. This noticeably increases the ergonomics and design of the API. The main goal here is to introduce the enum which defines whether or not the rootfs is mutable or not. We move the "rofiles" mode from the RPM script code down into the bwrap layer, which will make it easier to reuse for treecompose. Closes: #560 Approved by: jlebon --- src/libpriv/rpmostree-bwrap.c | 316 ++++++++++++++++++++-------- src/libpriv/rpmostree-bwrap.h | 31 ++- src/libpriv/rpmostree-postprocess.c | 34 ++- src/libpriv/rpmostree-scripts.c | 114 +++------- 4 files changed, 297 insertions(+), 198 deletions(-) diff --git a/src/libpriv/rpmostree-bwrap.c b/src/libpriv/rpmostree-bwrap.c index 13e7c698..02131846 100644 --- a/src/libpriv/rpmostree-bwrap.c +++ b/src/libpriv/rpmostree-bwrap.c @@ -22,6 +22,8 @@ #include "rpmostree-bwrap.h" #include +#include +#include void rpmostree_ptrarray_append_strdup (GPtrArray *argv_array, ...) @@ -35,30 +37,180 @@ rpmostree_ptrarray_append_strdup (GPtrArray *argv_array, ...) va_end (args); } -GPtrArray * -rpmostree_bwrap_base_argv_new_for_rootfs (int rootfs_fd, GError **error) +struct RpmOstreeBwrap { + guint refcount; + + gboolean executed; + + int rootfs_fd; + + GPtrArray *argv; + const char *child_argv0; + char *rofiles_mnt; + + GSpawnChildSetupFunc child_setup_func; + gpointer child_setup_data; +}; + +RpmOstreeBwrap * +rpmostree_bwrap_ref (RpmOstreeBwrap *bwrap) { - g_autoptr(GPtrArray) bwrap_argv = g_ptr_array_new_with_free_func (g_free); + bwrap->refcount++; + return bwrap; +} + +void +rpmostree_bwrap_unref (RpmOstreeBwrap *bwrap) +{ + bwrap->refcount--; + if (bwrap->refcount > 0) + return; + + if (bwrap->rofiles_mnt) + { + g_autoptr(GError) tmp_error = NULL; + const char *fusermount_argv[] = { "fusermount", "-u", bwrap->rofiles_mnt, NULL}; + int estatus; + + if (!g_spawn_sync (NULL, (char**)fusermount_argv, NULL, G_SPAWN_SEARCH_PATH, + NULL, NULL, NULL, NULL, &estatus, &tmp_error)) + { + g_prefix_error (&tmp_error, "Executing fusermount: "); + goto out; + } + if (!g_spawn_check_exit_status (estatus, &tmp_error)) + { + g_prefix_error (&tmp_error, "Executing fusermount: "); + goto out; + } + + (void) unlinkat (AT_FDCWD, bwrap->rofiles_mnt, AT_REMOVEDIR); + out: + /* We don't want a failure to unmount to be fatal, so all we do here + * is log. Though in practice what we *really* want is for the + * fusermount to be in the bwrap namespace, and hence tied by the + * kernel to the lifecycle of the container. This would require + * special casing for somehow doing FUSE mounts in bwrap. Which + * would be hard because NO_NEW_PRIVS turns off the setuid bits for + * fuse. + */ + if (tmp_error) + sd_journal_print (LOG_WARNING, "%s", tmp_error->message); + } + + g_ptr_array_unref (bwrap->argv); + g_free (bwrap->rofiles_mnt); + g_free (bwrap); +} + +void +rpmostree_bwrap_append_bwrap_argv (RpmOstreeBwrap *bwrap, ...) +{ + va_list args; + char *arg; + + g_assert (!bwrap->executed); + + va_start (args, bwrap); + while ((arg = va_arg (args, char *))) + g_ptr_array_add (bwrap->argv, g_strdup (arg)); + va_end (args); +} + +void +rpmostree_bwrap_append_child_argv (RpmOstreeBwrap *bwrap, ...) +{ + va_list args; + char *arg; + + g_assert (!bwrap->executed); + + va_start (args, bwrap); + while ((arg = va_arg (args, char *))) + { + char *v = g_strdup (arg); + g_ptr_array_add (bwrap->argv, v); + /* Stash argv0 for error messages */ + if (!bwrap->child_argv0) + bwrap->child_argv0 = v; + } + va_end (args); +} + +static void +child_setup_fchdir (gpointer user_data) +{ + int fd = GPOINTER_TO_INT (user_data); + if (fchdir (fd) < 0) + err (1, "fchdir"); +} + +static gboolean +setup_rofiles_usr (RpmOstreeBwrap *bwrap, + GError **error) +{ + gboolean ret = FALSE; + int estatus; + const char *rofiles_argv[] = { "rofiles-fuse", "./usr", NULL, NULL}; + gboolean mntpoint_created = FALSE; + + bwrap->rofiles_mnt = g_strdup ("/tmp/rofiles-fuse.XXXXXX"); + rofiles_argv[2] = bwrap->rofiles_mnt; + + if (!glnx_mkdtempat (AT_FDCWD, bwrap->rofiles_mnt, 0700, error)) + goto out; + mntpoint_created = TRUE; + + if (!g_spawn_sync (NULL, (char**)rofiles_argv, NULL, G_SPAWN_SEARCH_PATH, + child_setup_fchdir, GINT_TO_POINTER (bwrap->rootfs_fd), + NULL, NULL, &estatus, error)) + goto out; + if (!g_spawn_check_exit_status (estatus, error)) + goto out; + + rpmostree_bwrap_append_bwrap_argv (bwrap, "--bind", bwrap->rofiles_mnt, "/usr", NULL); + + ret = TRUE; + out: + if (!ret && mntpoint_created) + (void) unlinkat (AT_FDCWD, bwrap->rofiles_mnt, AT_REMOVEDIR); + return ret; +} + +RpmOstreeBwrap * +rpmostree_bwrap_new (int rootfs_fd, + RpmOstreeBwrapMutability mutable, + GError **error, + ...) +{ + va_list args; + RpmOstreeBwrap *retval = NULL; + g_autoptr(RpmOstreeBwrap) ret = g_new0 (RpmOstreeBwrap, 1); static const char *usr_links[] = {"lib", "lib32", "lib64", "bin", "sbin"}; - rpmostree_ptrarray_append_strdup (bwrap_argv, - WITH_BUBBLEWRAP_PATH, - "--dev", "/dev", - "--proc", "/proc", - "--dir", "/tmp", - "--chdir", "/", - "--ro-bind", "/sys/block", "/sys/block", - "--ro-bind", "/sys/bus", "/sys/bus", - "--ro-bind", "/sys/class", "/sys/class", - "--ro-bind", "/sys/dev", "/sys/dev", - "--ro-bind", "/sys/devices", "/sys/devices", - NULL); + ret->refcount = 1; + ret->rootfs_fd = rootfs_fd; + ret->argv = g_ptr_array_new_with_free_func (g_free); + + rpmostree_bwrap_append_bwrap_argv (ret, + WITH_BUBBLEWRAP_PATH, + "--dev", "/dev", + "--proc", "/proc", + "--dir", "/tmp", + "--chdir", "/", + "--ro-bind", "/sys/block", "/sys/block", + "--ro-bind", "/sys/bus", "/sys/bus", + "--ro-bind", "/sys/class", "/sys/class", + "--ro-bind", "/sys/dev", "/sys/dev", + "--ro-bind", "/sys/devices", "/sys/devices", + NULL); for (guint i = 0; i < G_N_ELEMENTS (usr_links); i++) { const char *subdir = usr_links[i]; struct stat stbuf; - char *path; + g_autofree char *srcpath = NULL; + g_autofree char *destpath = NULL; if (fstatat (rootfs_fd, subdir, &stbuf, AT_SYMLINK_NOFOLLOW) < 0) { @@ -72,70 +224,68 @@ rpmostree_bwrap_base_argv_new_for_rootfs (int rootfs_fd, GError **error) else if (!S_ISLNK (stbuf.st_mode)) continue; - g_ptr_array_add (bwrap_argv, g_strdup ("--symlink")); - - path = g_strconcat ("usr/", subdir, NULL); - g_ptr_array_add (bwrap_argv, path); - - path = g_strconcat ("/", subdir, NULL); - g_ptr_array_add (bwrap_argv, path); + srcpath = g_strconcat ("usr/", subdir, NULL); + destpath = g_strconcat ("/", subdir, NULL); + rpmostree_bwrap_append_bwrap_argv (ret, "--symlink", srcpath, destpath, NULL); } - return g_steal_pointer (&bwrap_argv); + switch (mutable) + { + case RPMOSTREE_BWRAP_IMMUTABLE: + rpmostree_bwrap_append_bwrap_argv (ret, "--ro-bind", "usr", "/usr", NULL); + break; + case RPMOSTREE_BWRAP_MUTATE_ROFILES: + if (!setup_rofiles_usr (ret, error)) + goto out; + break; + case RPMOSTREE_BWRAP_MUTATE_FREELY: + rpmostree_bwrap_append_bwrap_argv (ret, "--bind", "usr", "/usr", NULL); + break; + } + + { const char *arg; + va_start (args, error); + while ((arg = va_arg (args, char *))) + g_ptr_array_add (ret->argv, g_strdup (arg)); + va_end (args); + } + + retval = g_steal_pointer (&ret); + out: + return retval; } -static void -child_setup_fchdir (gpointer user_data) -{ - int fd = GPOINTER_TO_INT (user_data); - if (fchdir (fd) < 0) - err (1, "fchdir"); -} - -gboolean -rpmostree_run_sync_fchdir_setup (char **argv_array, GSpawnFlags flags, - int rootfs_fd, GError **error) -{ - int estatus; - - if (!g_spawn_sync (NULL, argv_array, NULL, flags, - child_setup_fchdir, GINT_TO_POINTER (rootfs_fd), - NULL, NULL, &estatus, error)) - return FALSE; - if (!g_spawn_check_exit_status (estatus, error)) - return FALSE; - - return TRUE; -} - -typedef struct { - int rootfs_fd; - GSpawnChildSetupFunc func; - gpointer data; -} ChildSetupData; - static void bwrap_child_setup (gpointer data) { - ChildSetupData *cdata = data; + RpmOstreeBwrap *bwrap = data; - if (fchdir (cdata->rootfs_fd) < 0) + if (fchdir (bwrap->rootfs_fd) < 0) err (1, "fchdir"); - if (cdata->func) - cdata->func (cdata->data); + if (bwrap->child_setup_func) + bwrap->child_setup_func (bwrap->child_setup_data); +} + +void +rpmostree_bwrap_set_child_setup (RpmOstreeBwrap *bwrap, + GSpawnChildSetupFunc func, + gpointer data) +{ + g_assert (!bwrap->executed); + bwrap->child_setup_func = func; + bwrap->child_setup_data = data; } gboolean -rpmostree_run_bwrap_sync_setup (char **argv_array, - int rootfs_fd, - GSpawnChildSetupFunc func, - gpointer data, - GError **error) +rpmostree_bwrap_run (RpmOstreeBwrap *bwrap, + GError **error) { int estatus; const char *current_lang = getenv ("LANG"); - ChildSetupData csetupdata = { rootfs_fd, func, data }; + + g_assert (!bwrap->executed); + bwrap->executed = TRUE; if (!current_lang) current_lang = "C"; @@ -151,43 +301,43 @@ rpmostree_run_bwrap_sync_setup (char **argv_array, lang_var, NULL}; - if (!g_spawn_sync (NULL, argv_array, (char**) bwrap_env, G_SPAWN_SEARCH_PATH, - bwrap_child_setup, &csetupdata, + /* Add the final NULL */ + g_ptr_array_add (bwrap->argv, NULL); + + if (!g_spawn_sync (NULL, (char**)bwrap->argv->pdata, (char**) bwrap_env, G_SPAWN_SEARCH_PATH, + bwrap_child_setup, bwrap, NULL, NULL, &estatus, error)) - return FALSE; + { + g_prefix_error (error, "Executing bwrap(%s): ", bwrap->child_argv0); + return FALSE; + } if (!g_spawn_check_exit_status (estatus, error)) - return FALSE; + { + g_prefix_error (error, "Executing bwrap(%s): ", bwrap->child_argv0); + return FALSE; + } } return TRUE; } -gboolean -rpmostree_run_bwrap_sync (char **argv_array, int rootfs_fd, GError **error) -{ - return rpmostree_run_bwrap_sync_setup (argv_array, rootfs_fd, NULL, NULL, error); -} - /* Execute /bin/true inside a bwrap container on the host */ gboolean rpmostree_bwrap_selftest (GError **error) { glnx_fd_close int host_root_dfd = -1; - g_autoptr(GPtrArray) bwrap_argv = NULL; + g_autoptr(RpmOstreeBwrap) bwrap = NULL; if (!glnx_opendirat (AT_FDCWD, "/", TRUE, &host_root_dfd, error)) return FALSE; - bwrap_argv = rpmostree_bwrap_base_argv_new_for_rootfs (host_root_dfd, error); - if (!bwrap_argv) + bwrap = rpmostree_bwrap_new (host_root_dfd, RPMOSTREE_BWRAP_IMMUTABLE, error, NULL); + if (!bwrap) return FALSE; - rpmostree_ptrarray_append_strdup (bwrap_argv, - "--ro-bind", "usr", "/usr", - NULL); - g_ptr_array_add (bwrap_argv, g_strdup ("true")); - g_ptr_array_add (bwrap_argv, NULL); - if (!rpmostree_run_bwrap_sync ((char**)bwrap_argv->pdata, host_root_dfd, error)) + rpmostree_bwrap_append_child_argv (bwrap, "true", NULL); + + if (!rpmostree_bwrap_run (bwrap, error)) { g_prefix_error (error, "bwrap test failed, see : "); return FALSE; diff --git a/src/libpriv/rpmostree-bwrap.h b/src/libpriv/rpmostree-bwrap.h index fc2ffe5e..a5d6ab75 100644 --- a/src/libpriv/rpmostree-bwrap.h +++ b/src/libpriv/rpmostree-bwrap.h @@ -24,17 +24,32 @@ #include "libglnx.h" -GPtrArray *rpmostree_bwrap_base_argv_new_for_rootfs (int rootfs, GError **error); +typedef enum { + RPMOSTREE_BWRAP_IMMUTABLE = 0, + RPMOSTREE_BWRAP_MUTATE_ROFILES, + RPMOSTREE_BWRAP_MUTATE_FREELY +} RpmOstreeBwrapMutability; +typedef struct RpmOstreeBwrap RpmOstreeBwrap; +RpmOstreeBwrap *rpmostree_bwrap_ref (RpmOstreeBwrap *bwrap); +void rpmostree_bwrap_unref (RpmOstreeBwrap *bwrap); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(RpmOstreeBwrap, rpmostree_bwrap_unref) + +/* TODO - move this utility elsewhere */ void rpmostree_ptrarray_append_strdup (GPtrArray *argv_array, ...) G_GNUC_NULL_TERMINATED; -gboolean rpmostree_run_sync_fchdir_setup (char **argv_array, GSpawnFlags flags, - int rootfs_fd, GError **error); +RpmOstreeBwrap *rpmostree_bwrap_new (int rootfs, + RpmOstreeBwrapMutability mutable, + GError **error, + ...) G_GNUC_NULL_TERMINATED; -gboolean rpmostree_run_bwrap_sync (char **argv_array, int rootfs_fd, GError **error); -gboolean rpmostree_run_bwrap_sync_setup (char **argv_array, int rootfs_fd, - GSpawnChildSetupFunc func, - gpointer data, - GError **error); +void rpmostree_bwrap_append_bwrap_argv (RpmOstreeBwrap *bwrap, ...) G_GNUC_NULL_TERMINATED; +void rpmostree_bwrap_append_child_argv (RpmOstreeBwrap *bwrap, ...) G_GNUC_NULL_TERMINATED; + +void rpmostree_bwrap_set_child_setup (RpmOstreeBwrap *bwrap, + GSpawnChildSetupFunc func, + gpointer data); + +gboolean rpmostree_bwrap_run (RpmOstreeBwrap *bwrap, GError **error); gboolean rpmostree_bwrap_selftest (GError **error); diff --git a/src/libpriv/rpmostree-postprocess.c b/src/libpriv/rpmostree-postprocess.c index e853dd18..16adb5f7 100644 --- a/src/libpriv/rpmostree-postprocess.c +++ b/src/libpriv/rpmostree-postprocess.c @@ -58,22 +58,20 @@ run_sync_in_root_at (int rootfs_fd, gpointer data, GError **error) { - g_autoptr(GPtrArray) bwrap_argv = NULL; - - bwrap_argv = rpmostree_bwrap_base_argv_new_for_rootfs (rootfs_fd, error); - if (!bwrap_argv) - return FALSE; + g_autoptr(RpmOstreeBwrap) bwrap = NULL; /* Bind all of the primary toplevel dirs; unlike the script case, treecompose * isn't yet operating on hardlinks, so we can just bind mount things mutably. */ - rpmostree_ptrarray_append_strdup (bwrap_argv, - "--bind", "usr", "/usr", - "--bind", "var", "/var", - "--bind", "etc", "/etc", - NULL); + bwrap = rpmostree_bwrap_new (rootfs_fd, RPMOSTREE_BWRAP_MUTATE_FREELY, error, + "--bind", "var", "/var", + "--bind", "etc", "/etc", + NULL); + if (!bwrap) + return FALSE; + + rpmostree_bwrap_append_child_argv (bwrap, binpath, NULL); - g_ptr_array_add (bwrap_argv, g_strdup (binpath)); /* https://github.com/projectatomic/bubblewrap/issues/91 */ { gboolean first = TRUE; for (char **iter = child_argv; iter && *iter; iter++) @@ -81,17 +79,15 @@ run_sync_in_root_at (int rootfs_fd, if (first) first = FALSE; else - g_ptr_array_add (bwrap_argv, g_strdup (*iter)); + rpmostree_bwrap_append_child_argv (bwrap, *iter, NULL); } } - g_ptr_array_add (bwrap_argv, NULL); - if (!rpmostree_run_bwrap_sync_setup ((char**)bwrap_argv->pdata, rootfs_fd, - setup_func, data, error)) - { - g_prefix_error (error, "Executing bwrap(%s): ", child_argv[0]); - return FALSE; - } + if (setup_func) + rpmostree_bwrap_set_child_setup (bwrap, setup_func, data); + + if (!rpmostree_bwrap_run (bwrap, error)) + return FALSE; return TRUE; } diff --git a/src/libpriv/rpmostree-scripts.c b/src/libpriv/rpmostree-scripts.c index b80219bf..6c033099 100644 --- a/src/libpriv/rpmostree-scripts.c +++ b/src/libpriv/rpmostree-scripts.c @@ -21,7 +21,6 @@ #include "config.h" #include -#include #include "rpmostree-output.h" #include "rpmostree-bwrap.h" #include @@ -77,38 +76,6 @@ static const KnownRpmScriptKind unsupported_scripts[] = { RPMTAG_VERIFYSCRIPT, RPMTAG_VERIFYSCRIPTPROG, RPMTAG_VERIFYSCRIPTFLAGS}, }; -static void -fusermount_cleanup (const char *mountpoint) -{ - g_autoptr(GError) tmp_error = NULL; - const char *fusermount_argv[] = { "fusermount", "-u", mountpoint, NULL}; - int estatus; - - if (!g_spawn_sync (NULL, (char**)fusermount_argv, NULL, G_SPAWN_SEARCH_PATH, - NULL, NULL, NULL, NULL, &estatus, &tmp_error)) - { - g_prefix_error (&tmp_error, "Executing fusermount: "); - goto out; - } - if (!g_spawn_check_exit_status (estatus, &tmp_error)) - { - g_prefix_error (&tmp_error, "Executing fusermount: "); - goto out; - } - - out: - /* We don't want a failure to unmount to be fatal, so all we do here - * is log. Though in practice what we *really* want is for the - * fusermount to be in the bwrap namespace, and hence tied by the - * kernel to the lifecycle of the container. This would require - * special casing for somehow doing FUSE mounts in bwrap. Which - * would be hard because NO_NEW_PRIVS turns off the setuid bits for - * fuse. - */ - if (tmp_error) - sd_journal_print (LOG_WARNING, "%s", tmp_error->message); -} - static RpmOstreeScriptAction lookup_script_action (DnfPackage *package, GHashTable *ignored_scripts, @@ -172,44 +139,27 @@ run_script_in_bwrap_container (int rootfs_fd, GError **error) { gboolean ret = FALSE; - char *rofiles_mnt = strdupa ("/tmp/rofiles-fuse.XXXXXX"); - const char *rofiles_argv[] = { "rofiles-fuse", "./usr", rofiles_mnt, NULL}; const char *pkg_script = glnx_strjoina (name, ".", scriptdesc+1); const char *postscript_name = glnx_strjoina ("/", pkg_script); - const char *postscript_path_container = glnx_strjoina ("/usr/", postscript_name); - const char *postscript_path_host; - gboolean mntpoint_created = FALSE; - gboolean fuse_mounted = FALSE; - g_autoptr(GPtrArray) bwrap_argv = g_ptr_array_new (); + const char *postscript_path_container = glnx_strjoina ("/usr", postscript_name); + const char *postscript_path_host = postscript_path_container + 1; + g_autoptr(RpmOstreeBwrap) bwrap = NULL; gboolean created_var_tmp = FALSE; - if (!glnx_mkdtempat (AT_FDCWD, rofiles_mnt, 0700, error)) - goto out; - - mntpoint_created = TRUE; - - if (!rpmostree_run_sync_fchdir_setup ((char**)rofiles_argv, G_SPAWN_SEARCH_PATH, - rootfs_fd, error)) - { - g_prefix_error (error, "Executing rofiles-fuse: "); - goto out; - } - - fuse_mounted = TRUE; - - postscript_path_host = glnx_strjoina (rofiles_mnt, "/", postscript_name); - /* TODO - Create a pipe and send this to bwrap so it's inside the - * tmpfs + * tmpfs. Note the +1 on the path to skip the leading /. */ - if (!g_file_set_contents (postscript_path_host, script, -1, error)) + if (!glnx_file_replace_contents_at (rootfs_fd, postscript_path_host, + (guint8*)script, -1, + GLNX_FILE_REPLACE_NODATASYNC, + NULL, error)) { g_prefix_error (error, "Writing script to %s: ", postscript_path_host); goto out; } - if (chmod (postscript_path_host, 0755) != 0) + if (fchmodat (rootfs_fd, postscript_path_host, 0755, 0) != 0) { - g_prefix_error (error, "chmod %s: ", postscript_path_host); + glnx_set_error_from_errno (error); goto out; } @@ -236,40 +186,28 @@ run_script_in_bwrap_container (int rootfs_fd, else created_var_tmp = TRUE; - bwrap_argv = rpmostree_bwrap_base_argv_new_for_rootfs (rootfs_fd, error); - if (!bwrap_argv) + bwrap = rpmostree_bwrap_new (rootfs_fd, RPMOSTREE_BWRAP_MUTATE_ROFILES, error, + /* Scripts can see a /var with compat links like alternatives */ + "--ro-bind", "./var", "/var", + /* But no need to access persistent /tmp, so make it /tmp */ + "--bind", "/tmp", "/var/tmp", + /* Allow RPM scripts to change the /etc defaults */ + "--symlink", "usr/etc", "/etc", + NULL); + if (!bwrap) goto out; - rpmostree_ptrarray_append_strdup (bwrap_argv, - "--bind", rofiles_mnt, "/usr", - /* Scripts can see a /var with compat links like alternatives */ - "--ro-bind", "./var", "/var", - /* But no need to access persistent /tmp, so make it /tmp */ - "--bind", "/tmp", "/var/tmp", - /* Allow RPM scripts to change the /etc defaults */ - "--symlink", "usr/etc", "/etc", - NULL); + rpmostree_bwrap_append_child_argv (bwrap, + postscript_path_container, + /* http://www.rpm.org/max-rpm/s1-rpm-inside-scripts.html#S3-RPM-INSIDE-PRE-SCRIPT */ + "1", + NULL); - g_ptr_array_add (bwrap_argv, g_strdup (postscript_path_container)); - /* http://www.rpm.org/max-rpm/s1-rpm-inside-scripts.html#S3-RPM-INSIDE-PRE-SCRIPT */ - g_ptr_array_add (bwrap_argv, g_strdup ("1")); - g_ptr_array_add (bwrap_argv, NULL); - - if (!rpmostree_run_bwrap_sync ((char**)bwrap_argv->pdata, rootfs_fd, error)) - { - g_prefix_error (error, "Executing bwrap: "); - goto out; - } + if (!rpmostree_bwrap_run (bwrap, error)) + goto out; ret = TRUE; out: - if (fuse_mounted) - { - (void) unlink (postscript_path_host); - fusermount_cleanup (rofiles_mnt); - } - if (mntpoint_created) - (void) unlinkat (AT_FDCWD, rofiles_mnt, AT_REMOVEDIR); if (created_var_tmp) (void) unlinkat (rootfs_fd, "var/tmp", AT_REMOVEDIR); return ret;