Move units and default-target processing to Rust

More oxidation.
This commit is contained in:
Colin Walters 2021-03-16 23:44:55 +00:00
parent ef931e20b0
commit 4c5bb4f216
4 changed files with 58 additions and 68 deletions

View File

@ -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))?) 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; /// The treefile format has two kinds of postprocessing scripts;
/// there's a single `postprocess-script` as well as inline (anonymous) /// there's a single `postprocess-script` as well as inline (anonymous)
/// scripts. This function executes both kinds in bwrap containers. /// scripts. This function executes both kinds in bwrap containers.

View File

@ -88,6 +88,7 @@ pub mod ffi {
// composepost.rs // composepost.rs
extern "Rust" { extern "Rust" {
fn composepost_nsswitch_altfiles(rootfs_dfd: i32) -> Result<()>; fn composepost_nsswitch_altfiles(rootfs_dfd: i32) -> Result<()>;
fn compose_postprocess_targets(rootfs_dfd: i32, treefile: &mut Treefile) -> Result<()>;
fn compose_postprocess( fn compose_postprocess(
rootfs_dfd: i32, rootfs_dfd: i32,
treefile: &mut Treefile, treefile: &mut Treefile,

View File

@ -1012,10 +1012,10 @@ pub(crate) struct TreeComposeConfig {
// systemd // systemd
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
units: Option<Vec<String>>, pub(crate) units: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "default-target")] #[serde(rename = "default-target")]
default_target: Option<String>, pub(crate) default_target: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "machineid-compat")] #[serde(rename = "machineid-compat")]
// Defaults to `true` // Defaults to `true`

View File

@ -1213,74 +1213,9 @@ rpmostree_treefile_postprocessing (int rootfs_fd,
if (!rename_if_exists (rootfs_fd, "etc", rootfs_fd, "usr/etc", error)) if (!rename_if_exists (rootfs_fd, "etc", rootfs_fd, "usr/etc", error))
return FALSE; return FALSE;
JsonArray *units = NULL; rpmostreecxx::compose_postprocess_targets(rootfs_fd, treefile_rs);
if (json_object_has_member (treefile, "units"))
units = json_object_get_array_member (treefile, "units");
guint len; 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; JsonArray *remove = NULL;
if (json_object_has_member (treefile, "remove-files")) if (json_object_has_member (treefile, "remove-files"))
{ {