Skip to content

Commit

Permalink
utils.rs: remove duplicate tmpfiles entries
Browse files Browse the repository at this point in the history
With Jonathan's suggestion:
from rpmostree_context_assemble(), we call a function like
`rpmostreecxx::deduplicate_tmpfiles_entries(tmprootfs_dfd)`, which scans
the dropins, sorts them into two `HashMaps` and then unlink all the
`pkg-*` files and create a single `pkg-rpm-ostree-autovar.conf`
(re-using the same prefix ensures that this same logic works client-side).
See #26 (comment)

Fixes #26
  • Loading branch information
HuijingHei committed Nov 28, 2023
1 parent 066fa29 commit 12b1ecb
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 0 deletions.
14 changes: 14 additions & 0 deletions rpmostree-cxxrs.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -2921,6 +2921,9 @@ extern "C"
void rpmostreecxx$cxxbridge1$cache_branch_to_nevra (::rust::Str nevra,
::rust::String *return$) noexcept;

::rust::repr::PtrLen
rpmostreecxx$cxxbridge1$deduplicate_tmpfiles_entries (::std::int32_t rootfs) noexcept;

::std::uint32_t
rpmostreecxx$cxxbridge1$CxxGObjectArray$length (::rpmostreecxx::CxxGObjectArray &self) noexcept
{
Expand Down Expand Up @@ -6055,6 +6058,16 @@ cache_branch_to_nevra (::rust::Str nevra) noexcept
rpmostreecxx$cxxbridge1$cache_branch_to_nevra (nevra, &return$.value);
return ::std::move (return$.value);
}

void
deduplicate_tmpfiles_entries (::std::int32_t rootfs)
{
::rust::repr::PtrLen error$ = rpmostreecxx$cxxbridge1$deduplicate_tmpfiles_entries (rootfs);
if (error$.ptr)
{
throw ::rust::impl< ::rust::Error>::error (error$);
}
}
} // namespace rpmostreecxx

extern "C"
Expand Down Expand Up @@ -6769,5 +6782,6 @@ Vec< ::rpmostreecxx::LockedPackage>::truncate (::std::size_t len)
{
return cxxbridge1$rust_vec$rpmostreecxx$LockedPackage$truncate (this, len);
}

} // namespace cxxbridge1
} // namespace rust
2 changes: 2 additions & 0 deletions rpmostree-cxxrs.h
Original file line number Diff line number Diff line change
Expand Up @@ -2043,4 +2043,6 @@ ::rpmostreecxx::GKeyFile *treefile_to_origin (::rpmostreecxx::Treefile const &tf
void origin_validate_roundtrip (::rpmostreecxx::GKeyFile const &kf) noexcept;

::rust::String cache_branch_to_nevra (::rust::Str nevra) noexcept;

void deduplicate_tmpfiles_entries (::std::int32_t rootfs);
} // namespace rpmostreecxx
1 change: 1 addition & 0 deletions rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,7 @@ pub mod ffi {
extern "Rust" {
fn prepare_rpm_layering(rootfs: i32, merge_passwd_dir: &str) -> Result<bool>;
fn complete_rpm_layering(rootfs: i32) -> Result<()>;
fn deduplicate_tmpfiles_entries(rootfs: i32) -> Result<()>;
fn passwd_cleanup(rootfs: i32) -> Result<()>;
fn migrate_group_except_root(rootfs: i32, preserved_groups: &Vec<String>) -> Result<()>;
fn migrate_passwd_except_root(rootfs: i32) -> Result<()>;
Expand Down
103 changes: 103 additions & 0 deletions rust/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,23 @@
*/

use crate::cxxrsutil::*;
use crate::ffiutil;
use crate::variant_utils;
use anyhow::{bail, Context, Result};
use camino::Utf8Path;
use cap_std::fs::{Dir, OpenOptions};
use cap_std::io_lifetimes::AsFilelike;
use fn_error_context::context;
use glib::Variant;
use once_cell::sync::Lazy;
use ostree_ext::prelude::*;
use ostree_ext::{glib, ostree};
use regex::Regex;
use rustix::fs::OpenOptionsExt;
use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::io::prelude::*;
use std::io::BufReader;
use std::os::fd::OwnedFd;
use std::os::unix::io::IntoRawFd;
use std::path::Path;
Expand Down Expand Up @@ -304,6 +309,104 @@ pub(crate) fn translate_path_for_ostree_impl(path: &str) -> Option<String> {
None
}

#[context("Deduplicate tmpfiles entries")]
pub fn deduplicate_tmpfiles_entries(tmprootfs_dfd: i32) -> CxxResult<()> {
let tmprootfs_dfd = unsafe { ffiutil::ffi_dirfd(tmprootfs_dfd)? };
static TMPFILESD: &str = "usr/lib/tmpfiles.d";
let tmpfiles_dir = tmprootfs_dfd
.open_dir(TMPFILESD)
.context("readdir {TMPFILESD}")?;

let mut auto_tmpfiles_list = Vec::new();
let mut system_tmpfiles_list = Vec::new();

for entry in tmpfiles_dir.entries()? {
let entry = entry?;
let name = entry.file_name();
let name = name.to_str().unwrap();
// skip README
if name == "README" {
continue;
}
if name.starts_with("pkg-") {
auto_tmpfiles_list.push(format!("{name}"));
} else {
system_tmpfiles_list.push(format!("{name}"));
}
}

if auto_tmpfiles_list.is_empty() || system_tmpfiles_list.is_empty() {
println!("Not found any auto-generated or system tmpfiles.d config");
return Ok(());
}

// save all entries to hashmaps
let mut auto_tmpfiles_entries =
save_tmpfile_entries(&tmpfiles_dir, &auto_tmpfiles_list).unwrap();
let system_tmpfiles_entries =
save_tmpfile_entries(&tmpfiles_dir, &system_tmpfiles_list).unwrap();

// remove duplicated entries in auto-generated tmpfiles.d,
// which are already in system
for key in system_tmpfiles_entries.keys() {
if auto_tmpfiles_entries.contains_key(key) {
auto_tmpfiles_entries.remove(key);
}
}

{
// save the noduplicated entries
let auto_tmpfiles_entries_nodup: Vec<String> =
auto_tmpfiles_entries.into_values().collect();

let mut openopts = OpenOptions::new();
openopts.create(true).write(true).mode(0o644);
static AUTOVAR_PATH: &str = "pkg-rpm-ostree-autovar.conf";
let mut path = tmpfiles_dir
.open_with(AUTOVAR_PATH, &openopts)
.with_context(|| format!("Creating {AUTOVAR_PATH}"))?;

for entry in auto_tmpfiles_entries_nodup {
path.write_all(entry.as_bytes())?;
path.write_all(b"\n")?;
}
}

// unlink all the auto-generated files
for path in &auto_tmpfiles_list {
tmpfiles_dir
.remove_file(path)
.with_context(|| format!("unlinkat({})", path))?;
}
Ok(())
}

#[context("Save tmpfiles entries to hashmap")]
pub(crate) fn save_tmpfile_entries(
tmpfiles_dir: &Dir,
var_list: &Vec<String>,
) -> Result<HashMap<String, String>> {
let mut tmpflies_entries: HashMap<String, String> = HashMap::new();
for tmpflies in var_list.iter() {
let contents = tmpfiles_dir.open(tmpflies).map(BufReader::new)?;

for (line_num, line) in contents.lines().enumerate() {
let input = line
.with_context(|| format!("failed to read tmpfiles entry at line {}", line_num))?;

// Skip empty and comment lines
if input.is_empty() || input.starts_with('#') {
continue;
}

let parts: Vec<&str> = input.split_whitespace().collect();
let entry = parts.get(1).unwrap();
tmpflies_entries.insert(entry.to_string(), input.to_string());
}
}
Ok(tmpflies_entries)
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
5 changes: 5 additions & 0 deletions src/libpriv/rpmostree-core.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -4442,6 +4442,11 @@ rpmostree_context_assemble (RpmOstreeContext *self, GCancellable *cancellable, G
task->end (msg);
}

/* Remove duplicated tmpfiles entries;
* see https://github.com/coreos/rpm-ostree/issues/26
*/
ROSCXX_TRY (deduplicate_tmpfiles_entries (tmprootfs_dfd), error);

/* We want this to be the first error message if something went wrong
* with a script; see https://github.com/projectatomic/rpm-ostree/pull/888
* (otherwise, on a script that did `rm -rf`, we'd fail first on the renameat below)
Expand Down

0 comments on commit 12b1ecb

Please sign in to comment.