postprocess: Move more code into Rust

Previously we carefully ported functionality bit by bit here.
Now take the last step and move it all in to Rust.

A reason I didn't do this in one go before is around the
incredibly twisted handling of the `/etc` vs `/usr/etc`.

I think longer term we should aim to basically have all
of our code keep it as `/etc` up until the very end.  For
now we just do a rename dance around some of the add/remove
files code.
This commit is contained in:
Colin Walters 2021-04-06 00:11:24 +00:00
parent 86f9612395
commit 46728cfd99
6 changed files with 40 additions and 94 deletions

View File

@ -128,22 +128,25 @@ pub(crate) fn compose_postprocess_final(rootfs_dfd: i32) -> CxxResult<()> {
#[context("Handling treefile 'units'")]
fn compose_postprocess_units(rootfs_dfd: &openat::Dir, treefile: &mut Treefile) -> Result<()> {
let units = if let Some(u) = treefile.parsed.units.as_ref() {
u
} else {
return Ok(());
};
let multiuser_wants = Path::new("usr/etc/systemd/system/multi-user.target.wants");
// Sanity check
if !rootfs_dfd.exists("usr/etc")? {
return Err(anyhow!("Missing usr/etc in rootfs"));
}
rootfs_dfd.ensure_dir_all(multiuser_wants, 0o755)?;
let mut created = false;
for unit in treefile.parsed.units.iter().flatten() {
if !created {
rootfs_dfd.ensure_dir_all(multiuser_wants, 0o755)?;
created = true;
}
for unit in units {
let dest = multiuser_wants.join(unit);
if rootfs_dfd.exists(&dest)? {
continue;
}
println!("Adding {} to multi-user.target.wants", unit);
let target = format!("/usr/lib/systemd/system/{}", unit);
rootfs_dfd.symlink(&dest, &target)?;
}
@ -165,21 +168,6 @@ fn compose_postprocess_default_target(rootfs_dfd: &openat::Dir, target: &str) ->
Ok(())
}
#[context("Handling targets")]
pub(crate) fn compose_postprocess_targets(
rootfs_dfd: i32,
treefile: &mut Treefile,
) -> CxxResult<()> {
let rootfs_dfd = crate::ffiutil::ffi_view_openat_dir(rootfs_dfd);
compose_postprocess_units(&rootfs_dfd, treefile)?;
if let Some(t) = treefile.parsed.default_target.as_deref() {
compose_postprocess_default_target(&rootfs_dfd, t)?;
}
Ok(())
}
/// The treefile format has two kinds of postprocessing scripts;
/// there's a single `postprocess-script` as well as inline (anonymous)
/// scripts. This function executes both kinds in bwrap containers.
@ -227,11 +215,9 @@ fn compose_postprocess_scripts(
#[context("Handling `remove-files`")]
pub(crate) fn compose_postprocess_remove_files(
rootfs_dfd: i32,
rootfs_dfd: &openat::Dir,
treefile: &mut Treefile,
) -> CxxResult<()> {
let rootfs_dfd = crate::ffiutil::ffi_view_openat_dir(rootfs_dfd);
) -> Result<()> {
for name in treefile.parsed.remove_files.iter().flatten() {
let p = Path::new(name);
if p.is_absolute() {
@ -307,13 +293,33 @@ fn compose_postprocess_rpmdb(rootfs_dfd: &openat::Dir) -> Result<()> {
pub(crate) fn compose_postprocess(
rootfs_dfd: i32,
treefile: &mut Treefile,
next_version: &str,
unified_core: bool,
) -> CxxResult<()> {
let rootfs_dfd = &crate::ffiutil::ffi_view_openat_dir(rootfs_dfd);
compose_postprocess_add_files(rootfs_dfd, treefile)?;
compose_postprocess_scripts(rootfs_dfd, treefile, unified_core)?;
// One of several dances we do around this that really needs to be completely
// reworked.
if rootfs_dfd.exists("etc")? {
rootfs_dfd.local_rename("etc", "usr/etc")?;
}
compose_postprocess_rpmdb(rootfs_dfd)?;
compose_postprocess_units(&rootfs_dfd, treefile)?;
if let Some(t) = treefile.parsed.default_target.as_deref() {
compose_postprocess_default_target(&rootfs_dfd, t)?;
}
compose_postprocess_mutate_os_release(rootfs_dfd, treefile, next_version)?;
treefile.write_compose_json(rootfs_dfd)?;
let etc_guard = crate::core::prepare_tempetc_guard(rootfs_dfd.as_raw_fd())?;
// These ones depend on the /etc path
compose_postprocess_remove_files(rootfs_dfd, treefile)?;
compose_postprocess_add_files(rootfs_dfd, treefile)?;
etc_guard.undo()?;
compose_postprocess_scripts(rootfs_dfd, treefile, unified_core)?;
Ok(())
}
@ -321,7 +327,7 @@ pub(crate) fn compose_postprocess(
/// Implementation of the treefile `mutate-os-release` field.
#[context("Updating os-release with commit version")]
pub(crate) fn compose_postprocess_mutate_os_release(
rootfs_dfd: i32,
rootfs_dfd: &openat::Dir,
treefile: &mut Treefile,
next_version: &str,
) -> Result<()> {
@ -334,7 +340,6 @@ pub(crate) fn compose_postprocess_mutate_os_release(
println!("Ignoring mutate-os-release: no commit version specified.");
return Ok(());
}
let rootfs_dfd = &crate::ffiutil::ffi_view_openat_dir(rootfs_dfd);
// find the real path to os-release using bwrap; this is an overkill but safer way
// of resolving a symlink relative to a rootfs (see discussions in
// https://github.com/projectatomic/rpm-ostree/pull/410/)

View File

@ -133,17 +133,10 @@ pub mod ffi {
// composepost.rs
extern "Rust" {
fn composepost_nsswitch_altfiles(rootfs_dfd: i32) -> Result<()>;
fn compose_postprocess_targets(rootfs_dfd: i32, treefile: &mut Treefile) -> Result<()>;
fn compose_postprocess_mutate_os_release(
rootfs_dfd: i32,
treefile: &mut Treefile,
next_version: &str,
) -> Result<()>;
fn compose_postprocess_remove_files(rootfs_dfd: i32, treefile: &mut Treefile)
-> Result<()>;
fn compose_postprocess(
rootfs_dfd: i32,
treefile: &mut Treefile,
next_version: &str,
unified_core: bool,
) -> Result<()>;
fn compose_postprocess_final(rootfs_dfd: i32) -> Result<()>;
@ -260,7 +253,6 @@ pub mod ffi {
fn get_rpmdb(&self) -> String;
fn get_files_remove_regex(&self, package: &str) -> Vec<String>;
fn print_deprecation_warnings(&self);
fn write_compose_json(&self, rootfs_dfd: i32) -> Result<()>;
fn sanitycheck_externals(&self) -> Result<()>;
fn get_checksum(&self, repo: Pin<&mut OstreeRepo>) -> Result<String>;
fn get_ostree_ref(&self) -> String;

View File

@ -746,8 +746,7 @@ for x in *; do mv ${{x}} %{{buildroot}}%{{_prefix}}/lib/ostree-jigdo/%{{name}};
}
/// Write the serialized treefile into /usr/share on the target filesystem.
pub(crate) fn write_compose_json(&self, rootfs_dfd: i32) -> CxxResult<()> {
let rootfs_dfd = crate::ffiutil::ffi_view_openat_dir(rootfs_dfd);
pub(crate) fn write_compose_json(&self, rootfs_dfd: &openat::Dir) -> Result<()> {
let target = Path::new(COMPOSE_JSON_PATH);
rootfs_dfd.ensure_dir_all(target.parent().unwrap(), 0o755)?;
rootfs_dfd.write_file_contents(target, 0o644, self.serialized.as_bytes())?;
@ -1626,7 +1625,7 @@ arch-include:
{
let workdir = tempfile::tempdir()?;
let tf = new_test_treefile(workdir.path(), VALID_PRELUDE, None).unwrap();
tf.write_compose_json(rootdir.as_raw_fd())?;
tf.write_compose_json(rootdir)?;
}
let mut src = std::io::BufReader::new(rootdir.open_file(COMPOSE_JSON_PATH)?);
let cfg = treefile_parse_stream(utils::InputFormat::JSON, &mut src, None)?;

View File

@ -954,10 +954,7 @@ impl_install_tree (RpmOstreeTreeComposeContext *self,
return FALSE;
/* Start postprocessing */
if (!rpmostree_treefile_postprocessing (self->rootfs_dfd, **self->treefile_rs, self->treefile,
next_version.length() > 0 ? next_version.c_str() : NULL, self->unified_core_and_fuse,
cancellable, error))
return glnx_prefix_error (error, "Postprocessing");
rpmostreecxx::compose_postprocess(self->rootfs_dfd, **self->treefile_rs, next_version, self->unified_core_and_fuse);
/* Until here, we targeted "rootfs.tmp" in the working directory. Most
* user-configured postprocessing has run. Now, we need to perform required

View File

@ -1132,43 +1132,6 @@ rpmostree_rootfs_postprocess_common (int rootfs_fd,
return TRUE;
}
/* Move etc -> usr/etc in the rootfs, and run through treefile
* postprocessing.
*/
gboolean
rpmostree_treefile_postprocessing (int rootfs_fd,
rpmostreecxx::Treefile &treefile_rs,
JsonObject *treefile,
const char *next_version,
gboolean unified_core_mode,
GCancellable *cancellable,
GError **error)
{
g_assert (treefile);
treefile_rs.write_compose_json(rootfs_fd);
if (!rename_if_exists (rootfs_fd, "etc", rootfs_fd, "usr/etc", error))
return FALSE;
rpmostreecxx::compose_postprocess_targets(rootfs_fd, treefile_rs);
/* Put /etc back for backwards compatibility */
if (!rename_if_exists (rootfs_fd, "usr/etc", rootfs_fd, "etc", error))
return FALSE;
rpmostreecxx::compose_postprocess_remove_files(rootfs_fd, treefile_rs);
rpmostreecxx::compose_postprocess_mutate_os_release(rootfs_fd, treefile_rs, next_version ?: "");
/* Undo etc move again */
if (!rename_if_exists (rootfs_fd, "etc", rootfs_fd, "usr/etc", error))
return FALSE;
rpmostreecxx::compose_postprocess(rootfs_fd, treefile_rs, (bool)unified_core_mode);
return TRUE;
}
/**
* rpmostree_prepare_rootfs_for_commit:
*

View File

@ -26,16 +26,6 @@
G_BEGIN_DECLS
gboolean
rpmostree_treefile_postprocessing (int rootfs_fd,
rpmostreecxx::Treefile &treefile_rs,
JsonObject *treefile,
const char *next_version,
gboolean unified_core_mode,
GCancellable *cancellable,
GError **error);
gboolean
rpmostree_rootfs_symlink_emptydir_at (int rootfs_fd,
const char *dest,