From 4c5bb4f2163f8b18d1c001dd0dd5d462657ca477 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 16 Mar 2021 23:44:55 +0000 Subject: [PATCH] Move `units` and `default-target` processing to Rust More oxidation. --- rust/src/composepost.rs | 54 +++++++++++++++++++++ rust/src/lib.rs | 1 + rust/src/treefile.rs | 4 +- src/libpriv/rpmostree-postprocess.cxx | 67 +-------------------------- 4 files changed, 58 insertions(+), 68 deletions(-) diff --git a/rust/src/composepost.rs b/rust/src/composepost.rs index aa157703..5b4d17a9 100644 --- a/rust/src/composepost.rs +++ b/rust/src/composepost.rs @@ -125,6 +125,60 @@ pub(crate) fn compose_postprocess_final(rootfs_dfd: i32) -> CxxResult<()> { Ok(tasks.par_iter().try_for_each(|f| f(&rootfs_dfd))?) } +#[context("Handling treefile 'units'")] +fn compose_postprocess_units(rootfs_dfd: &openat::Dir, treefile: &mut Treefile) -> Result<()> { + let multiuser_wants = Path::new("usr/etc/systemd/system/multi-user.target.wants"); + + let mut created = false; + for unit in treefile.parsed.units.iter().flatten() { + if !created { + rootfs_dfd.ensure_dir_all(multiuser_wants, 0o755)?; + created = true; + } + + 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)?; + } + Ok(()) +} + +#[context("Handling treefile 'default-target'")] +fn compose_postprocess_default_target(rootfs_dfd: &openat::Dir, target: &str) -> Result<()> { + /* This used to be in /etc, but doing it in /usr makes more sense, as it's + * part of the OS defaults. This was changed in particular to work with + * ConditionFirstBoot= which runs `systemctl preset-all`: + * https://github.com/projectatomic/rpm-ostree/pull/1425 + */ + let default_target_path = "usr/lib/systemd/system/default.target"; + rootfs_dfd.remove_file_optional(default_target_path)?; + let dest = format!("/usr/lib/systemd/system/{}", target); + rootfs_dfd.symlink(default_target_path, dest)?; + + 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. diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 70d0a7f7..fa9621ad 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -88,6 +88,7 @@ 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( rootfs_dfd: i32, treefile: &mut Treefile, diff --git a/rust/src/treefile.rs b/rust/src/treefile.rs index 3e4e23b6..cc4273d0 100644 --- a/rust/src/treefile.rs +++ b/rust/src/treefile.rs @@ -1012,10 +1012,10 @@ pub(crate) struct TreeComposeConfig { // systemd #[serde(skip_serializing_if = "Option::is_none")] - units: Option>, + pub(crate) units: Option>, #[serde(skip_serializing_if = "Option::is_none")] #[serde(rename = "default-target")] - default_target: Option, + pub(crate) default_target: Option, #[serde(skip_serializing_if = "Option::is_none")] #[serde(rename = "machineid-compat")] // Defaults to `true` diff --git a/src/libpriv/rpmostree-postprocess.cxx b/src/libpriv/rpmostree-postprocess.cxx index 87ebc3db..b1f4ab9a 100644 --- a/src/libpriv/rpmostree-postprocess.cxx +++ b/src/libpriv/rpmostree-postprocess.cxx @@ -1213,74 +1213,9 @@ rpmostree_treefile_postprocessing (int rootfs_fd, if (!rename_if_exists (rootfs_fd, "etc", rootfs_fd, "usr/etc", error)) return FALSE; - JsonArray *units = NULL; - if (json_object_has_member (treefile, "units")) - units = json_object_get_array_member (treefile, "units"); + rpmostreecxx::compose_postprocess_targets(rootfs_fd, treefile_rs); guint len; - if (units) - len = json_array_get_length (units); - else - len = 0; - - { - glnx_autofd int multiuser_wants_dfd = -1; - - if (!glnx_shutil_mkdir_p_at (rootfs_fd, "usr/etc/systemd/system/multi-user.target.wants", 0755, - cancellable, error)) - return FALSE; - if (!glnx_opendirat (rootfs_fd, "usr/etc/systemd/system/multi-user.target.wants", TRUE, - &multiuser_wants_dfd, error)) - return FALSE; - - for (guint i = 0; i < len; i++) - { - const char *unitname = _rpmostree_jsonutil_array_require_string_element (units, i, error); - g_autofree char *symlink_target = NULL; - struct stat stbuf; - - if (!unitname) - return FALSE; - - symlink_target = g_strconcat ("/usr/lib/systemd/system/", unitname, NULL); - - if (fstatat (multiuser_wants_dfd, unitname, &stbuf, AT_SYMLINK_NOFOLLOW) < 0) - { - if (errno != ENOENT) - return glnx_throw_errno_prefix (error, "fstatat(%s)", unitname); - } - else - continue; - - g_print ("Adding %s to multi-user.target.wants\n", unitname); - - if (symlinkat (symlink_target, multiuser_wants_dfd, unitname) < 0) - return glnx_throw_errno_prefix (error, "symlinkat(%s)", unitname); - } - } - - const char *default_target = NULL; - if (!_rpmostree_jsonutil_object_get_optional_string_member (treefile, "default-target", - &default_target, error)) - return FALSE; - - if (default_target != NULL) - { - g_autofree char *dest_default_target_path = - g_strconcat ("/usr/lib/systemd/system/", default_target, NULL); - - /* This used to be in /etc, but doing it in /usr makes more sense, as it's - * part of the OS defaults. This was changed in particular to work with - * ConditionFirstBoot= which runs `systemctl preset-all`: - * https://github.com/projectatomic/rpm-ostree/pull/1425 - */ - static const char default_target_path[] = "usr/lib/systemd/system/default.target"; - (void) unlinkat (rootfs_fd, default_target_path, 0); - - if (symlinkat (dest_default_target_path, rootfs_fd, default_target_path) < 0) - return glnx_throw_errno_prefix (error, "symlinkat(%s)", default_target_path); - } - JsonArray *remove = NULL; if (json_object_has_member (treefile, "remove-files")) {