From 229ddada9ce1da029037bedf1a8f7b8b42b4ac09 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 12 Mar 2020 21:10:29 +0000 Subject: [PATCH] WIP: main: Also automatically remount rw /sysroot for `ostree pull` etc. See https://github.com/coreos/fedora-coreos-tracker/issues/343 When we added the read-only sysroot support it broke using "raw" `ostree pull` and `ostree refs --create` and all of the core repo CLIs that just operate on a repo and not a sysroot. Fixing this is a bit ugly as it "layer crosses" things even more. Extract a helper function that works in both cases. --- src/ostree/ot-main.c | 75 +++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 21 deletions(-) diff --git a/src/ostree/ot-main.c b/src/ostree/ot-main.c index a044cef23f..53278695e5 100644 --- a/src/ostree/ot-main.c +++ b/src/ostree/ot-main.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include "ot-main.h" #include "ostree.h" @@ -292,6 +294,46 @@ ostree_parse_sysroot_or_repo_option (GOptionContext *context, return TRUE; } + +static gboolean +ostree_maybe_setup_mount_namespace (gboolean *out_ns, + GError **error) +{ + *out_ns = FALSE; + + /* If we're not root, then we almost certainly can't be remounting anything */ + if (getuid () != 0) + return TRUE; + + /* If the system isn't booted via libostree, also nothing to do */ + if (!glnx_fstatat_allow_noent (AT_FDCWD, "/run/ostree-booted", NULL, 0, error)) + return FALSE; + if (errno == ENOENT) + return TRUE; + + glnx_autofd int sysroot_subdir_fd = glnx_opendirat_with_errno (AT_FDCWD, "/sysroot", TRUE); + if (sysroot_subdir_fd < 0) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "opendirat"); + /* No /sysroot - nothing to do */ + return TRUE; + } + + struct statvfs stvfs; + if (fstatvfs (sysroot_subdir_fd, &stvfs) < 0) + return glnx_throw_errno_prefix (error, "fstatvfs"); + if (stvfs.f_flag & ST_RDONLY) + { + if (unshare (CLONE_NEWNS) < 0) + return glnx_throw_errno_prefix (error, "preparing writable sysroot: unshare (CLONE_NEWNS)"); + + *out_ns = TRUE; + } + + return TRUE; +} + gboolean ostree_option_context_parse (GOptionContext *context, const GOptionEntry *main_entries, @@ -387,6 +429,14 @@ ostree_option_context_parse (GOptionContext *context, cancellable, error); if (!repo) return FALSE; + gboolean setup_ns = FALSE; + if (!ostree_maybe_setup_mount_namespace (&setup_ns, error)) + return FALSE; + if (setup_ns) + { + if (mount ("/sysroot", "/sysroot", NULL, MS_REMOUNT | MS_SILENT, NULL) < 0) + return glnx_throw_errno_prefix (error, "Remounting /sysroot rw"); + } } if (out_repo) @@ -452,27 +502,10 @@ ostree_admin_option_context_parse (GOptionContext *context, */ if (ostree_sysroot_is_booted (sysroot)) { - int sysroot_fd = ostree_sysroot_get_fd (sysroot); - g_assert_cmpint (sysroot_fd, !=, -1); - - glnx_autofd int sysroot_subdir_fd = glnx_opendirat_with_errno (sysroot_fd, "sysroot", TRUE); - if (sysroot_subdir_fd < 0) - { - if (errno != ENOENT) - return glnx_throw_errno_prefix (error, "opendirat"); - } - else if (getuid () == 0) - { - struct statvfs stvfs; - if (fstatvfs (sysroot_subdir_fd, &stvfs) < 0) - return glnx_throw_errno_prefix (error, "fstatvfs"); - if (stvfs.f_flag & ST_RDONLY) - { - if (unshare (CLONE_NEWNS) < 0) - return glnx_throw_errno_prefix (error, "preparing writable sysroot: unshare (CLONE_NEWNS)"); - ostree_sysroot_set_mount_namespace_in_use (sysroot); - } - } + gboolean setup_ns = FALSE; + if (!ostree_maybe_setup_mount_namespace (&setup_ns, error)) + return FALSE; + ostree_sysroot_set_mount_namespace_in_use (sysroot); } /* Released when sysroot is finalized, or on process exit */