@@ -12,6 +12,7 @@ use crate::efi;
1212use crate :: model:: { ComponentStatus , ComponentUpdatable , ContentMetadata , SavedState , Status } ;
1313use crate :: util;
1414use anyhow:: { anyhow, Context , Result } ;
15+ use camino:: { Utf8Path , Utf8PathBuf } ;
1516use clap:: crate_version;
1617use fn_error_context:: context;
1718use libc:: mode_t;
@@ -215,16 +216,16 @@ fn ensure_writable_boot() -> Result<()> {
215216}
216217
217218/// daemon implementation of component update
218- pub ( crate ) fn update ( name : & str ) -> Result < ComponentUpdateResult > {
219- let mut state = SavedState :: load_from_disk ( "/" ) ?. unwrap_or_default ( ) ;
219+ pub ( crate ) fn update ( name : & str , rootcxt : & RootContext ) -> Result < ComponentUpdateResult > {
220+ let mut state = SavedState :: load_from_disk ( & rootcxt . path ) ?. unwrap_or_default ( ) ;
220221 let component = component:: new_from_name ( name) ?;
221222 let inst = if let Some ( inst) = state. installed . get ( name) {
222223 inst. clone ( )
223224 } else {
224225 anyhow:: bail!( "Component {} is not installed" , name) ;
225226 } ;
226- let sysroot = openat :: Dir :: open ( "/" ) ? ;
227- let update = component. query_update ( & sysroot) ?;
227+ let sysroot = & rootcxt . sysroot ;
228+ let update = component. query_update ( sysroot) ?;
228229 let update = match update. as_ref ( ) {
229230 Some ( p) if inst. meta . can_upgrade_to ( p) => p,
230231 _ => return Ok ( ComponentUpdateResult :: AtLatestVersion ) ,
@@ -235,6 +236,7 @@ pub(crate) fn update(name: &str) -> Result<ComponentUpdateResult> {
235236 let mut pending_container = state. pending . take ( ) . unwrap_or_default ( ) ;
236237 let interrupted = pending_container. get ( component. name ( ) ) . cloned ( ) ;
237238 pending_container. insert ( component. name ( ) . into ( ) , update. clone ( ) ) ;
239+ let sysroot = sysroot. try_clone ( ) ?;
238240 let mut state_guard =
239241 SavedState :: acquire_write_lock ( sysroot) . context ( "Failed to acquire write lock" ) ?;
240242 state_guard
@@ -256,19 +258,20 @@ pub(crate) fn update(name: &str) -> Result<ComponentUpdateResult> {
256258}
257259
258260/// daemon implementation of component adoption
259- pub ( crate ) fn adopt_and_update ( name : & str ) -> Result < ContentMetadata > {
260- let sysroot = openat :: Dir :: open ( "/" ) ? ;
261- let mut state = SavedState :: load_from_disk ( "/" ) ?. unwrap_or_default ( ) ;
261+ pub ( crate ) fn adopt_and_update ( name : & str , rootcxt : & RootContext ) -> Result < ContentMetadata > {
262+ let sysroot = & rootcxt . sysroot ;
263+ let mut state = SavedState :: load_from_disk ( & rootcxt . path ) ?. unwrap_or_default ( ) ;
262264 let component = component:: new_from_name ( name) ?;
263265 if state. installed . contains_key ( name) {
264266 anyhow:: bail!( "Component {} is already installed" , name) ;
265267 } ;
266268
267269 ensure_writable_boot ( ) ?;
268270
269- let Some ( update) = component. query_update ( & sysroot) ? else {
271+ let Some ( update) = component. query_update ( sysroot) ? else {
270272 anyhow:: bail!( "Component {} has no available update" , name) ;
271273 } ;
274+ let sysroot = sysroot. try_clone ( ) ?;
272275 let mut state_guard =
273276 SavedState :: acquire_write_lock ( sysroot) . context ( "Failed to acquire write lock" ) ?;
274277
@@ -408,8 +411,34 @@ pub(crate) fn print_status(status: &Status) -> Result<()> {
408411 Ok ( ( ) )
409412}
410413
414+ pub struct RootContext {
415+ pub sysroot : openat:: Dir ,
416+ pub path : Utf8PathBuf ,
417+ #[ allow( dead_code) ]
418+ pub devices : Vec < String > ,
419+ }
420+
421+ impl RootContext {
422+ fn new ( sysroot : openat:: Dir , path : & str , devices : Vec < String > ) -> Self {
423+ Self {
424+ sysroot,
425+ path : Utf8Path :: new ( path) . into ( ) ,
426+ devices,
427+ }
428+ }
429+ }
430+
431+ /// Initialize parent devices to prepare the update
432+ fn prep_before_update ( ) -> Result < RootContext > {
433+ let path = "/" ;
434+ let sysroot = openat:: Dir :: open ( path) . context ( "Opening root dir" ) ?;
435+ let devices = crate :: blockdev:: get_devices ( path) . context ( "get parent devices" ) ?;
436+ Ok ( RootContext :: new ( sysroot, path, devices) )
437+ }
438+
411439pub ( crate ) fn client_run_update ( ) -> Result < ( ) > {
412440 crate :: try_fail_point!( "update" ) ;
441+ let rootcxt = prep_before_update ( ) ?;
413442 let status: Status = status ( ) ?;
414443 if status. components . is_empty ( ) && status. adoptable . is_empty ( ) {
415444 println ! ( "No components installed." ) ;
@@ -421,7 +450,7 @@ pub(crate) fn client_run_update() -> Result<()> {
421450 ComponentUpdatable :: Upgradable => { }
422451 _ => continue ,
423452 } ;
424- match update ( name) ? {
453+ match update ( name, & rootcxt ) ? {
425454 ComponentUpdateResult :: AtLatestVersion => {
426455 // Shouldn't happen unless we raced with another client
427456 eprintln ! (
@@ -449,7 +478,7 @@ pub(crate) fn client_run_update() -> Result<()> {
449478 }
450479 for ( name, adoptable) in status. adoptable . iter ( ) {
451480 if adoptable. confident {
452- let r: ContentMetadata = adopt_and_update ( name) ?;
481+ let r: ContentMetadata = adopt_and_update ( name, & rootcxt ) ?;
453482 println ! ( "Adopted and updated: {}: {}" , name, r. version) ;
454483 updated = true ;
455484 } else {
@@ -463,12 +492,13 @@ pub(crate) fn client_run_update() -> Result<()> {
463492}
464493
465494pub ( crate ) fn client_run_adopt_and_update ( ) -> Result < ( ) > {
495+ let rootcxt = prep_before_update ( ) ?;
466496 let status: Status = status ( ) ?;
467497 if status. adoptable . is_empty ( ) {
468498 println ! ( "No components are adoptable." ) ;
469499 } else {
470500 for ( name, _) in status. adoptable . iter ( ) {
471- let r: ContentMetadata = adopt_and_update ( name) ?;
501+ let r: ContentMetadata = adopt_and_update ( name, & rootcxt ) ?;
472502 println ! ( "Adopted and updated: {}: {}" , name, r. version) ;
473503 }
474504 }
0 commit comments