Move high level bwrap postprocess interface to C++

A future patch will then expose this interface via cxxrs, allowing
us to port more of the postprocess.cxx code to Rust.
This commit is contained in:
Colin Walters 2021-03-13 16:07:54 +00:00
parent da33222b95
commit 1b3bdc243e
4 changed files with 108 additions and 80 deletions

View File

@ -316,6 +316,16 @@ pub mod ffi {
fn main_print_error(msg: &str);
}
unsafe extern "C++" {
include!("rpmostree-bwrap.h");
fn bwrap_run_mutable(
rootfs_dfd: i32,
binpath: &str,
child_argv: &Vec<String>,
unified_core_mode: bool,
) -> Result<()>;
}
unsafe extern "C++" {
include!("rpmostree-clientlib.h");
fn client_require_root() -> Result<()>;

View File

@ -528,3 +528,75 @@ rpmostree_bwrap_selftest (GError **error)
return TRUE;
}
namespace rpmostreecxx {
// High level interface to bwrap, currently used by the postprocess code.
// This deals with renaming `/etc` to `/usr/etc` for example.
void
bwrap_run_mutable(int32_t rootfs_fd, rust::Str binpath,
const rust::Vec<rust::String> &child_argv,
bool unified_core_mode)
{
g_autoptr(GError) local_error = NULL;
/* For scripts, it's /etc, not /usr/etc */
if (!glnx_fstatat_allow_noent (rootfs_fd, "etc", NULL, 0, &local_error))
util::throw_gerror(local_error);
const bool renamed_usretc = (errno == ENOENT);
if (renamed_usretc)
{
if (!glnx_renameat (rootfs_fd, "usr/etc", rootfs_fd, "etc", &local_error))
util::throw_gerror(local_error);
/* But leave a compat symlink, as we used to bind mount, so scripts
* could still use that too.
*/
if (symlinkat ("../etc", rootfs_fd, "usr/etc") < 0)
{
(void)glnx_throw_errno_prefix (&local_error, "symlinkat");
util::throw_gerror(local_error);
}
}
RpmOstreeBwrapMutability mut =
unified_core_mode ? RPMOSTREE_BWRAP_MUTATE_ROFILES : RPMOSTREE_BWRAP_MUTATE_FREELY;
g_autoptr(RpmOstreeBwrap) bwrap = rpmostree_bwrap_new (rootfs_fd, mut, &local_error);
if (!bwrap)
util::throw_gerror(local_error);
if (unified_core_mode)
rpmostree_bwrap_bind_read (bwrap, "var", "/var");
else
rpmostree_bwrap_bind_readwrite (bwrap, "var", "/var");
{ auto binpath_s = std::string(binpath);
rpmostree_bwrap_append_child_argv (bwrap, binpath_s.c_str(), NULL);
}
/* https://github.com/projectatomic/bubblewrap/issues/91 */
{ bool first = true;
for (auto &elt : child_argv)
{
if (first)
first = false;
else
{
auto s = std::string(elt); // NUL terminate
rpmostree_bwrap_append_child_argv (bwrap, s.c_str(), NULL);
}
}
}
if (!rpmostree_bwrap_run (bwrap, NULL, &local_error))
util::throw_gerror(local_error);
/* Remove the symlink and swap back */
if (renamed_usretc)
{
if (!glnx_unlinkat (rootfs_fd, "usr/etc", 0, &local_error))
util::throw_gerror(local_error);
if (!glnx_renameat (rootfs_fd, "etc", rootfs_fd, "usr/etc", &local_error))
util::throw_gerror(local_error);
}
}
} /* namespace */

View File

@ -24,6 +24,16 @@
#include "libglnx.h"
#include "rust/cxx.h"
namespace rpmostreecxx {
void bwrap_run_mutable(int32_t rootfs_dfd, rust::Str binpath,
const rust::Vec<rust::String> &child_argv,
bool unified_core_mode);
}
G_BEGIN_DECLS
typedef enum {

View File

@ -55,71 +55,6 @@ typedef enum {
RPMOSTREE_POSTPROCESS_BOOT_LOCATION_MODULES,
} RpmOstreePostprocessBootLocation;
/* The "unified_core_mode" flag controls whether or not we use rofiles-fuse,
* just like pkg layering.
*/
static gboolean
run_bwrap_mutably (int rootfs_fd,
const char *binpath,
char **child_argv,
gboolean unified_core_mode,
GCancellable *cancellable,
GError **error)
{
/* For scripts, it's /etc, not /usr/etc */
if (!glnx_fstatat_allow_noent (rootfs_fd, "etc", NULL, 0, error))
return FALSE;
gboolean renamed_usretc = (errno == ENOENT);
if (renamed_usretc)
{
if (!glnx_renameat (rootfs_fd, "usr/etc", rootfs_fd, "etc", error))
return FALSE;
/* But leave a compat symlink, as we used to bind mount, so scripts
* could still use that too.
*/
if (symlinkat ("../etc", rootfs_fd, "usr/etc") < 0)
return glnx_throw_errno_prefix (error, "symlinkat");
}
RpmOstreeBwrapMutability mut =
unified_core_mode ? RPMOSTREE_BWRAP_MUTATE_ROFILES : RPMOSTREE_BWRAP_MUTATE_FREELY;
g_autoptr(RpmOstreeBwrap) bwrap = rpmostree_bwrap_new (rootfs_fd, mut, error);
if (!bwrap)
return FALSE;
if (unified_core_mode)
rpmostree_bwrap_bind_read (bwrap, "var", "/var");
else
rpmostree_bwrap_bind_readwrite (bwrap, "var", "/var");
rpmostree_bwrap_append_child_argv (bwrap, binpath, NULL);
/* https://github.com/projectatomic/bubblewrap/issues/91 */
{ gboolean first = TRUE;
for (char **iter = child_argv; iter && *iter; iter++)
{
if (first)
first = FALSE;
else
rpmostree_bwrap_append_child_argv (bwrap, *iter, NULL);
}
}
if (!rpmostree_bwrap_run (bwrap, cancellable, error))
return FALSE;
/* Remove the symlink and swap back */
if (renamed_usretc)
{
if (!glnx_unlinkat (rootfs_fd, "usr/etc", 0, error))
return FALSE;
if (!glnx_renameat (rootfs_fd, "etc", rootfs_fd, "usr/etc", error))
return FALSE;
}
return TRUE;
}
static gboolean
rename_if_exists (int src_dfd,
const char *from,
@ -278,9 +213,8 @@ rpmostree_postprocess_run_depmod (int rootfs_dfd,
GCancellable *cancellable,
GError **error)
{
const char *child_argv[] = { "depmod", "-a", kver, NULL };
if (!run_bwrap_mutably (rootfs_dfd, "depmod", (char**)child_argv, unified_core_mode, cancellable, error))
return FALSE;
rust::Vec child_argv = { rust::String("depmod"), rust::String("-a"), rust::String(kver) };
rpmostreecxx::bwrap_run_mutable (rootfs_dfd, "depmod", child_argv, (bool)unified_core_mode);
return TRUE;
}
@ -888,10 +822,8 @@ rpmostree_postprocess_final (int rootfs_dfd,
/* Now regenerate SELinux policy so that postprocess scripts from users and from us
* (e.g. the /etc/default/useradd incision) that affect it are baked in. */
const char *child_argv[] = { "semodule", "-nB", NULL };
if (!run_bwrap_mutably (rootfs_dfd, "semodule", (char**)child_argv, unified_core_mode,
cancellable, error))
return FALSE;
rust::Vec child_argv = { rust::String("semodule"), rust::String("-nB") };
rpmostreecxx::bwrap_run_mutable (rootfs_dfd, "semodule", child_argv, (bool)unified_core_mode);
}
gboolean container = FALSE;
@ -1607,9 +1539,13 @@ rpmostree_treefile_postprocessing (int rootfs_fd,
cancellable, error))
return FALSE;
g_print ("Executing `postprocess` inline script '%u'\n", i);
char *child_argv[] = { binpath, NULL };
if (!run_bwrap_mutably (rootfs_fd, binpath, child_argv, unified_core_mode, cancellable, error))
return glnx_prefix_error (error, "While executing inline postprocessing script '%i'", i);
rust::Vec child_argv = { rust::String(binpath)};
try {
rpmostreecxx::bwrap_run_mutable (rootfs_fd, binpath, child_argv, (bool)unified_core_mode);
} catch (std::exception& e) {
g_autofree char* msg = g_strdup_printf ("While executing inline postprocessing script '%i'", i);
util::rethrow_prefixed(e, msg);
}
if (!glnx_unlinkat (rootfs_fd, target_binpath, 0, error))
return FALSE;
@ -1638,12 +1574,12 @@ rpmostree_treefile_postprocessing (int rootfs_fd,
g_print ("Executing postprocessing script\n");
{
char *child_argv[] = { (char*)binpath, NULL };
if (!run_bwrap_mutably (rootfs_fd, binpath, child_argv, unified_core_mode, cancellable, error))
return glnx_prefix_error (error, "While executing postprocessing script");
rust::Vec child_argv = { rust::String(binpath) };
try {
rpmostreecxx::bwrap_run_mutable (rootfs_fd, binpath, child_argv, (bool)unified_core_mode);
} catch (std::exception& e) {
util::rethrow_prefixed(e, "Executing postprocessing script");
}
if (!glnx_unlinkat (rootfs_fd, target_binpath, 0, error))
return FALSE;