@@ -12,6 +12,7 @@ use crate::efi;
12
12
use crate :: model:: { ComponentStatus , ComponentUpdatable , ContentMetadata , SavedState , Status } ;
13
13
use crate :: util;
14
14
use anyhow:: { anyhow, Context , Result } ;
15
+ use camino:: { Utf8Path , Utf8PathBuf } ;
15
16
use clap:: crate_version;
16
17
use fn_error_context:: context;
17
18
use libc:: mode_t;
@@ -215,16 +216,16 @@ fn ensure_writable_boot() -> Result<()> {
215
216
}
216
217
217
218
/// 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 ( ) ;
220
221
let component = component:: new_from_name ( name) ?;
221
222
let inst = if let Some ( inst) = state. installed . get ( name) {
222
223
inst. clone ( )
223
224
} else {
224
225
anyhow:: bail!( "Component {} is not installed" , name) ;
225
226
} ;
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) ?;
228
229
let update = match update. as_ref ( ) {
229
230
Some ( p) if inst. meta . can_upgrade_to ( p) => p,
230
231
_ => return Ok ( ComponentUpdateResult :: AtLatestVersion ) ,
@@ -235,6 +236,7 @@ pub(crate) fn update(name: &str) -> Result<ComponentUpdateResult> {
235
236
let mut pending_container = state. pending . take ( ) . unwrap_or_default ( ) ;
236
237
let interrupted = pending_container. get ( component. name ( ) ) . cloned ( ) ;
237
238
pending_container. insert ( component. name ( ) . into ( ) , update. clone ( ) ) ;
239
+ let sysroot = sysroot. try_clone ( ) ?;
238
240
let mut state_guard =
239
241
SavedState :: acquire_write_lock ( sysroot) . context ( "Failed to acquire write lock" ) ?;
240
242
state_guard
@@ -256,19 +258,20 @@ pub(crate) fn update(name: &str) -> Result<ComponentUpdateResult> {
256
258
}
257
259
258
260
/// 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 ( ) ;
262
264
let component = component:: new_from_name ( name) ?;
263
265
if state. installed . contains_key ( name) {
264
266
anyhow:: bail!( "Component {} is already installed" , name) ;
265
267
} ;
266
268
267
269
ensure_writable_boot ( ) ?;
268
270
269
- let Some ( update) = component. query_update ( & sysroot) ? else {
271
+ let Some ( update) = component. query_update ( sysroot) ? else {
270
272
anyhow:: bail!( "Component {} has no available update" , name) ;
271
273
} ;
274
+ let sysroot = sysroot. try_clone ( ) ?;
272
275
let mut state_guard =
273
276
SavedState :: acquire_write_lock ( sysroot) . context ( "Failed to acquire write lock" ) ?;
274
277
@@ -408,8 +411,34 @@ pub(crate) fn print_status(status: &Status) -> Result<()> {
408
411
Ok ( ( ) )
409
412
}
410
413
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
+
411
439
pub ( crate ) fn client_run_update ( ) -> Result < ( ) > {
412
440
crate :: try_fail_point!( "update" ) ;
441
+ let rootcxt = prep_before_update ( ) ?;
413
442
let status: Status = status ( ) ?;
414
443
if status. components . is_empty ( ) && status. adoptable . is_empty ( ) {
415
444
println ! ( "No components installed." ) ;
@@ -421,7 +450,7 @@ pub(crate) fn client_run_update() -> Result<()> {
421
450
ComponentUpdatable :: Upgradable => { }
422
451
_ => continue ,
423
452
} ;
424
- match update ( name) ? {
453
+ match update ( name, & rootcxt ) ? {
425
454
ComponentUpdateResult :: AtLatestVersion => {
426
455
// Shouldn't happen unless we raced with another client
427
456
eprintln ! (
@@ -449,7 +478,7 @@ pub(crate) fn client_run_update() -> Result<()> {
449
478
}
450
479
for ( name, adoptable) in status. adoptable . iter ( ) {
451
480
if adoptable. confident {
452
- let r: ContentMetadata = adopt_and_update ( name) ?;
481
+ let r: ContentMetadata = adopt_and_update ( name, & rootcxt ) ?;
453
482
println ! ( "Adopted and updated: {}: {}" , name, r. version) ;
454
483
updated = true ;
455
484
} else {
@@ -463,12 +492,13 @@ pub(crate) fn client_run_update() -> Result<()> {
463
492
}
464
493
465
494
pub ( crate ) fn client_run_adopt_and_update ( ) -> Result < ( ) > {
495
+ let rootcxt = prep_before_update ( ) ?;
466
496
let status: Status = status ( ) ?;
467
497
if status. adoptable . is_empty ( ) {
468
498
println ! ( "No components are adoptable." ) ;
469
499
} else {
470
500
for ( name, _) in status. adoptable . iter ( ) {
471
- let r: ContentMetadata = adopt_and_update ( name) ?;
501
+ let r: ContentMetadata = adopt_and_update ( name, & rootcxt ) ?;
472
502
println ! ( "Adopted and updated: {}: {}" , name, r. version) ;
473
503
}
474
504
}
0 commit comments