diff --git a/lib/src/cli.rs b/lib/src/cli.rs index 42a9925ed..2de0e10a2 100644 --- a/lib/src/cli.rs +++ b/lib/src/cli.rs @@ -357,7 +357,7 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> { } } else { let fetched = crate::deploy::pull(sysroot, imgref, opts.quiet).await?; - let mut kargs = crate::deploy::get_kargs(repo, fetched.as_ref())?; + let kargs = crate::kargs::get_kargs(repo, &booted_deployment, fetched.as_ref())?; let staged_digest = staged_image.as_ref().map(|s| s.image_digest.as_str()); let fetched_digest = fetched.manifest_digest.as_str(); tracing::debug!("staged: {staged_digest:?}"); @@ -380,7 +380,7 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> { } else { let osname = booted_deployment.osname(); let mut opts = ostree::SysrootDeployTreeOpts::default(); - let kargs: Vec<&str> = kargs.iter_mut().map(|s| s.as_str() ).collect(); + let kargs: Vec<&str> = kargs.iter().map(|s| s.as_str() ).collect(); opts.override_kernel_argv = Some(kargs.as_slice()); crate::deploy::stage(sysroot, &osname, &fetched, &spec, Some(opts)).await?; changed = true; @@ -455,7 +455,7 @@ async fn switch(opts: SwitchOpts) -> Result<()> { let new_spec = RequiredHostSpec::from_spec(&new_spec)?; let fetched = crate::deploy::pull(sysroot, &target, opts.quiet).await?; - let mut kargs = crate::deploy::get_kargs(repo, fetched.as_ref())?; + let kargs = crate::kargs::get_kargs(repo, &booted_deployment, fetched.as_ref())?; if !opts.retain { // By default, we prune the previous ostree ref so it will go away after later upgrades @@ -470,7 +470,7 @@ async fn switch(opts: SwitchOpts) -> Result<()> { let stateroot = booted_deployment.osname(); let mut opts = ostree::SysrootDeployTreeOpts::default(); - let kargs: Vec<&str> = kargs.iter_mut().map(|s| s.as_str() ).collect(); + let kargs: Vec<&str> = kargs.iter().map(|s| s.as_str() ).collect(); opts.override_kernel_argv = Some(kargs.as_slice()); crate::deploy::stage(sysroot, &stateroot, &fetched, &new_spec, Some(opts)).await?; @@ -497,18 +497,18 @@ async fn edit(opts: EditOpts) -> Result<()> { if new_host.spec == host.spec { println!("Edit cancelled, no changes made."); - return Ok(()); + return Ok(()); } let new_spec = RequiredHostSpec::from_spec(&new_host.spec)?; let fetched = crate::deploy::pull(sysroot, new_spec.image, opts.quiet).await?; let repo = &sysroot.repo(); - let mut kargs = crate::deploy::get_kargs(repo, fetched.as_ref())?; + let kargs = crate::kargs::get_kargs(repo, &booted_deployment, fetched.as_ref())?; // TODO gc old layers here let stateroot = booted_deployment.osname(); let mut opts = ostree::SysrootDeployTreeOpts::default(); - let kargs: Vec<&str> = kargs.iter_mut().map(|s| s.as_str() ).collect(); + let kargs: Vec<&str> = kargs.iter().map(|s| s.as_str() ).collect(); opts.override_kernel_argv = Some(kargs.as_slice()); crate::deploy::stage(sysroot, &stateroot, &fetched, &new_spec, Some(opts)).await?; diff --git a/lib/src/deploy.rs b/lib/src/deploy.rs index 3f98d556a..7c5772920 100644 --- a/lib/src/deploy.rs +++ b/lib/src/deploy.rs @@ -13,12 +13,9 @@ use ostree::{gio, glib}; use ostree_container::OstreeImageReference; use ostree_ext::container as ostree_container; use ostree_ext::container::store::PrepareResult; -use ostree_ext::ostree; +use ostree_ext::ostree::{self}; use ostree_ext::ostree::Deployment; use ostree_ext::sysroot::SysrootLock; -use ostree_ext::prelude::FileExt; -use ostree_ext::prelude::Cast; -use ostree_ext::prelude::FileEnumeratorExt; use crate::spec::HostSpec; use crate::spec::ImageReference; @@ -347,64 +344,6 @@ pub(crate) fn switch_origin_inplace(root: &Dir, imgref: &ImageReference) -> Resu Ok(newest_deployment) } -pub fn get_kargs(repo: &ostree::Repo, fetched: &ImageState) -> Result> { - let cancellable = gio::Cancellable::NONE; - - // Get the running kernel commandline arguments - let kargs = ostree::KernelArgs::new(); - ostree::KernelArgs::append_proc_cmdline( - &kargs, - cancellable, - )?; - let mut kargs: Vec = kargs.to_strv().iter().map(|s| { s.as_str().to_string() }).collect(); - - // Get the kargs in kargs.d of the booted system - let mut existing_kargs = vec![]; - let fragments = liboverdrop::scan(&["/usr/lib"], "bootc/kargs.d", &["toml"], true); - for (_name, path) in fragments { - let buffer = std::fs::read_to_string(&path)?; - existing_kargs.push(buffer.trim().to_string()); - } - - // Get the kargs in kargs.d of the remote image - let mut remote_kargs = vec![]; - let (fetched_tree, _) = repo.read_commit(fetched.ostree_commit.as_str(), cancellable)?; - let fetched_tree = fetched_tree.resolve_relative_path("/usr/lib/bootc/kargs.d"); - let fetched_tree = fetched_tree.downcast::().expect("downcast"); - match fetched_tree.query_exists(cancellable) { - true => {} - false => { - return Ok(vec![]); - } - } - let queryattrs = "standard::name,standard::type"; - let queryflags = gio::FileQueryInfoFlags::NOFOLLOW_SYMLINKS; - let fetched_iter = fetched_tree.enumerate_children(queryattrs, queryflags, cancellable)?; - while let Some(fetched_info) = fetched_iter.next_file(cancellable)? { - let fetched_child = fetched_iter.child(&fetched_info); - let fetched_child = fetched_child.downcast::().expect("downcast"); - fetched_child.ensure_resolved()?; - let fetched_contents_checksum = fetched_child.checksum(); - let f = ostree::Repo::load_file(repo, fetched_contents_checksum.as_str(), cancellable)?; - let file_content = f.0; - let mut buffer = vec![]; - let mut reader = ostree_ext::prelude::InputStreamExtManual::into_read(file_content.unwrap()); - let _ = std::io::Read::read_to_end(&mut reader, &mut buffer); - let s = std::string::String::from_utf8(buffer)?; - remote_kargs.push(s.trim().to_string()); - } - - // get the diff between the existing and remote kargs - let mut added_kargs: Vec = remote_kargs.clone().into_iter().filter(|item| !existing_kargs.contains(item)).collect(); - let removed_kargs: Vec = existing_kargs.clone().into_iter().filter(|item| !remote_kargs.contains(item)).collect(); - - // apply the diff to the system kargs - kargs.retain(|x| !removed_kargs.contains(x)); - kargs.append(&mut added_kargs); - - Ok(kargs) -} - #[test] fn test_switch_inplace() -> Result<()> { use cap_std::fs::DirBuilderExt; diff --git a/lib/src/kargs.rs b/lib/src/kargs.rs new file mode 100644 index 000000000..7b88cb9bf --- /dev/null +++ b/lib/src/kargs.rs @@ -0,0 +1,99 @@ +use anyhow::Ok; +use anyhow::Result; + +use ostree::gio; +use ostree_ext::ostree; +use ostree_ext::ostree::Deployment; +use crate::deploy::ImageState; +use ostree_ext::prelude::FileExt; +use ostree_ext::prelude::Cast; +use ostree_ext::prelude::FileEnumeratorExt; + +use serde::Deserialize; + +#[derive(Deserialize)] +struct Config { + kargs: Vec, + supported: Supported, +} + +#[derive(Deserialize)] +struct Supported { + architecture: String, +} + +pub(crate) fn get_kargs(repo: &ostree::Repo, booted_deployment: &Deployment, fetched: &ImageState) -> Result> { + let cancellable = gio::Cancellable::NONE; + let mut kargs: Vec = vec![]; + + // Get the running kargs of the booted system + match ostree::Deployment::bootconfig(booted_deployment) { + Some(bootconfig) => { + match ostree::BootconfigParser::get(&bootconfig, "options") { + Some(options) => { + let options: Vec<&str> = options.split_whitespace().collect(); + let mut options: Vec = options.into_iter().map(|s| s.to_string()).collect(); + kargs.append(&mut options); + }, + None => () + } + }, + None => () + }; + + // Get the kargs in kargs.d of the booted system + let mut existing_kargs: Vec = vec![]; + let fragments = liboverdrop::scan(&["/usr/lib"], "bootc/kargs.d", &["toml"], true); + for (_name, path) in fragments { + let s = std::fs::read_to_string(&path)?; + let mut parsed_kargs = parse_file(s.clone())?; + existing_kargs.append(&mut parsed_kargs); + } + + // Get the kargs in kargs.d of the remote image + let mut remote_kargs: Vec = vec![]; + let (fetched_tree, _) = repo.read_commit(fetched.ostree_commit.as_str(), cancellable)?; + let fetched_tree = fetched_tree.resolve_relative_path("/usr/lib/bootc/kargs.d"); + let fetched_tree = fetched_tree.downcast::().expect("downcast"); + match fetched_tree.query_exists(cancellable) { + true => {} + false => { + return Ok(vec![]); + } + } + let queryattrs = "standard::name,standard::type"; + let queryflags = gio::FileQueryInfoFlags::NOFOLLOW_SYMLINKS; + let fetched_iter = fetched_tree.enumerate_children(queryattrs, queryflags, cancellable)?; + while let Some(fetched_info) = fetched_iter.next_file(cancellable)? { + let fetched_child = fetched_iter.child(&fetched_info); + let fetched_child = fetched_child.downcast::().expect("downcast"); + fetched_child.ensure_resolved()?; + let fetched_contents_checksum = fetched_child.checksum(); + let f = ostree::Repo::load_file(repo, fetched_contents_checksum.as_str(), cancellable)?; + let file_content = f.0; + let mut reader = ostree_ext::prelude::InputStreamExtManual::into_read(file_content.unwrap()); + let s = std::io::read_to_string(&mut reader)?; + let mut parsed_kargs = parse_file(s.clone())?; + remote_kargs.append(&mut parsed_kargs); + } + + // get the diff between the existing and remote kargs + let mut added_kargs: Vec = remote_kargs.clone().into_iter().filter(|item| !existing_kargs.contains(item)).collect(); + let removed_kargs: Vec = existing_kargs.clone().into_iter().filter(|item| !remote_kargs.contains(item)).collect(); + + // apply the diff to the system kargs + kargs.retain(|x| !removed_kargs.contains(x)); + kargs.append(&mut added_kargs); + + Ok(kargs) +} + +pub fn parse_file(file_content: String) -> Result> { + let arch = std::env::consts::ARCH; + let de: Config = toml::from_str(&file_content).unwrap(); + let mut parsed_kargs: Vec = vec![]; + if de.supported.architecture == arch { + parsed_kargs = de.kargs; + } + return Ok(parsed_kargs); +} diff --git a/lib/src/lib.rs b/lib/src/lib.rs index aad5d95b2..2253b58f7 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -19,6 +19,7 @@ pub mod cli; pub(crate) mod deploy; +pub(crate) mod kargs; pub(crate) mod journal; mod lsm; pub(crate) mod metadata;