@@ -5,7 +5,7 @@ use cap_std_ext::{
55 cap_std:: { ambient_authority, fs:: Dir } ,
66 dirext:: CapStdExtDirExt ,
77} ;
8- use composefs:: fsverity:: { FsVerityHashValue , Sha512HashValue } ;
8+ use composefs:: fsverity:: Sha512HashValue ;
99use composefs_boot:: bootloader:: { EFI_ADDON_DIR_EXT , EFI_EXT } ;
1010
1111use crate :: {
@@ -14,6 +14,7 @@ use crate::{
1414 find_vmlinuz_initrd_duplicates, get_efi_uuid_source, get_esp_partition,
1515 get_sysroot_parent_dev, mount_esp, BootType , SYSTEMD_UKI_DIR ,
1616 } ,
17+ gc:: composefs_gc,
1718 repo:: open_composefs_repo,
1819 rollback:: { composefs_rollback, rename_exchange_user_cfg} ,
1920 status:: { composefs_deployment_status, get_sorted_grub_uki_boot_entries} ,
@@ -23,21 +24,17 @@ use crate::{
2324 TYPE1_ENT_PATH , TYPE1_ENT_PATH_STAGED , USER_CFG_STAGED ,
2425 } ,
2526 parsers:: bls_config:: { parse_bls_config, BLSConfigType } ,
26- spec:: { Bootloader , DeploymentEntry } ,
27+ spec:: { BootEntry , Bootloader , DeploymentEntry } ,
2728 status:: Slot ,
2829} ;
2930
30- struct ObjectRefs {
31- other_depl : HashSet < Sha512HashValue > ,
32- depl_to_del : HashSet < Sha512HashValue > ,
31+ pub ( crate ) struct ObjectRefs {
32+ pub ( crate ) other_depl : HashSet < Sha512HashValue > ,
33+ pub ( crate ) depl_to_del : HashSet < Sha512HashValue > ,
3334}
3435
3536#[ fn_error_context:: context( "Deleting Type1 Entry {}" , depl. deployment. verity) ]
36- fn delete_type1_entries (
37- depl : & DeploymentEntry ,
38- boot_dir : & Dir ,
39- deleting_staged : bool ,
40- ) -> Result < ( ) > {
37+ fn delete_type1_entry ( depl : & DeploymentEntry , boot_dir : & Dir , deleting_staged : bool ) -> Result < ( ) > {
4138 let entries_dir_path = if deleting_staged {
4239 TYPE1_ENT_PATH_STAGED
4340 } else {
@@ -81,8 +78,8 @@ fn delete_type1_entries(
8178 }
8279
8380 // Boot dir in case of EFI will be the ESP
84- delete_uki ( & depl. deployment . verity , boot_dir) ?;
8581 entry. remove_file ( ) . context ( "Removing .conf file" ) ?;
82+ delete_uki ( & depl. deployment . verity , boot_dir) ?;
8683
8784 break ;
8885 }
@@ -96,12 +93,12 @@ fn delete_type1_entries(
9693 continue ;
9794 }
9895
96+ entry. remove_file ( ) . context ( "Removing .conf file" ) ?;
97+
9998 if should_del_kernel {
10099 delete_kernel_initrd ( & bls_config. cfg_type , boot_dir) ?;
101100 }
102101
103- entry. remove_file ( ) . context ( "Removing .conf file" ) ?;
104-
105102 break ;
106103 }
107104
@@ -156,6 +153,7 @@ fn delete_kernel_initrd(bls_config: &BLSConfigType, boot_dir: &Dir) -> Result<()
156153/// Deletes the UKI `uki_id` and any addons specific to it
157154#[ fn_error_context:: context( "Deleting UKI and UKI addons {uki_id}" ) ]
158155fn delete_uki ( uki_id : & str , esp_mnt : & Dir ) -> Result < ( ) > {
156+ // TODO: We don't delete global addons here
159157 let ukis = esp_mnt. open_dir ( SYSTEMD_UKI_DIR ) ?;
160158
161159 for entry in ukis. entries_utf8 ( ) ? {
@@ -209,27 +207,28 @@ fn remove_grub_menucfg_entry(id: &str, boot_dir: &Dir, deleting_staged: bool) ->
209207 rename_exchange_user_cfg ( & grub_dir)
210208}
211209
210+ #[ fn_error_context:: context( "Deleting boot entries for deployment {}" , deployment. deployment. verity) ]
212211fn delete_depl_boot_entries ( deployment : & DeploymentEntry , deleting_staged : bool ) -> Result < ( ) > {
213212 match deployment. deployment . bootloader {
214213 Bootloader :: Grub => {
215214 let boot_dir = Dir :: open_ambient_dir ( "/sysroot/boot" , ambient_authority ( ) )
216215 . context ( "Opening boot dir" ) ?;
217216
218217 match deployment. deployment . boot_type {
219- BootType :: Bls => delete_type1_entries ( deployment, & boot_dir, deleting_staged) ,
218+ BootType :: Bls => delete_type1_entry ( deployment, & boot_dir, deleting_staged) ,
220219
221220 BootType :: Uki => {
222221 let device = get_sysroot_parent_dev ( ) ?;
223222 let ( esp_part, ..) = get_esp_partition ( & device) ?;
224223 let esp_mount = mount_esp ( & esp_part) ?;
225224
226- delete_uki ( & deployment. deployment . verity , & esp_mount. fd ) ?;
227-
228225 remove_grub_menucfg_entry (
229226 & deployment. deployment . verity ,
230227 & boot_dir,
231228 deleting_staged,
232- )
229+ ) ?;
230+
231+ delete_uki ( & deployment. deployment . verity , & esp_mount. fd )
233232 }
234233 }
235234 }
@@ -241,44 +240,12 @@ fn delete_depl_boot_entries(deployment: &DeploymentEntry, deleting_staged: bool)
241240 let esp_mount = mount_esp ( & esp_part) ?;
242241
243242 // For Systemd UKI as well, we use .conf files
244- delete_type1_entries ( deployment, & esp_mount. fd , deleting_staged)
243+ delete_type1_entry ( deployment, & esp_mount. fd , deleting_staged)
245244 }
246245 }
247246}
248247
249- pub ( crate ) async fn delete_composefs_deployment ( deployment_id : & str , delete : bool ) -> Result < ( ) > {
250- let host = composefs_deployment_status ( ) . await ?;
251-
252- let booted = host. require_composefs_booted ( ) ?;
253-
254- let all_depls = host. all_composefs_deployments ( ) ?;
255-
256- let depl_to_del = all_depls
257- . iter ( )
258- . find ( |d| d. deployment . verity == deployment_id) ;
259-
260- let Some ( depl_to_del) = depl_to_del else {
261- anyhow:: bail!( "Deployment {deployment_id} not found" ) ;
262- } ;
263-
264- let deleting_staged = host
265- . status
266- . staged
267- . as_ref ( )
268- . and_then ( |s| s. composefs . as_ref ( ) )
269- . map_or ( false , |cfs| cfs. verity == deployment_id) ;
270-
271- // Get all objects referenced by all images
272- // Delete objects that are only referenced by the deployment to be deleted
273-
274- // Unqueue rollback. This makes it easier to delete boot entries later on
275- if matches ! ( depl_to_del. ty, Some ( Slot :: Rollback ) ) && host. status . rollback_queued {
276- composefs_rollback ( ) . await ?;
277- }
278-
279- let sysroot =
280- Dir :: open_ambient_dir ( "/sysroot" , ambient_authority ( ) ) . context ( "Opening sysroot" ) ?;
281-
248+ pub ( crate ) fn get_image_objects ( sysroot : & Dir , deployment_id : Option < & str > ) -> Result < ObjectRefs > {
282249 let repo = open_composefs_repo ( & sysroot) ?;
283250
284251 let images_dir = sysroot
@@ -303,19 +270,73 @@ pub(crate) async fn delete_composefs_deployment(deployment_id: &str, delete: boo
303270 . objects_for_image ( & img_name)
304271 . with_context ( || format ! ( "Getting objects for image {img_name}" ) ) ?;
305272
306- if img_name == deployment_id {
307- object_refs. depl_to_del . extend ( objects) ;
273+ if let Some ( deployment_id) = deployment_id {
274+ if deployment_id == img_name {
275+ object_refs. depl_to_del . extend ( objects) ;
276+ }
308277 } else {
309278 object_refs. other_depl . extend ( objects) ;
310279 }
311280 }
312281
313- let diff: Vec < & Sha512HashValue > = object_refs
314- . depl_to_del
315- . difference ( & object_refs. other_depl )
316- . collect ( ) ;
282+ Ok ( object_refs)
283+ }
284+
285+ pub ( crate ) fn delete_image ( sysroot : & Dir , deployment_id : & str ) -> Result < ( ) > {
286+ let img_path = Path :: new ( "composefs" ) . join ( "images" ) . join ( deployment_id) ;
287+
288+ sysroot
289+ . remove_file ( & img_path)
290+ . context ( "Deleting EROFS image" )
291+ }
317292
318- tracing:: debug!( "diff: {:#?}" , diff) ;
293+ pub ( crate ) fn delete_state_dir ( sysroot : & Dir , deployment_id : & str ) -> Result < ( ) > {
294+ let state_dir = Path :: new ( STATE_DIR_RELATIVE ) . join ( deployment_id) ;
295+
296+ sysroot
297+ . remove_dir_all ( & state_dir)
298+ . with_context ( || format ! ( "Removing dir {state_dir:?}" ) )
299+ }
300+
301+ pub ( crate ) fn delete_staged ( staged : & Option < BootEntry > ) -> Result < ( ) > {
302+ if staged. is_none ( ) {
303+ tracing:: debug!( "No staged deployment" ) ;
304+ return Ok ( ( ) ) ;
305+ } ;
306+
307+ let file = Path :: new ( COMPOSEFS_TRANSIENT_STATE_DIR ) . join ( COMPOSEFS_STAGED_DEPLOYMENT_FNAME ) ;
308+ tracing:: debug!( "Deleting staged file {file:?}" ) ;
309+ std:: fs:: remove_file ( file) . context ( "Removing staged file" ) ?;
310+
311+ Ok ( ( ) )
312+ }
313+
314+ pub ( crate ) async fn delete_composefs_deployment ( deployment_id : & str , delete : bool ) -> Result < ( ) > {
315+ let host = composefs_deployment_status ( ) . await ?;
316+
317+ let booted = host. require_composefs_booted ( ) ?;
318+
319+ let all_depls = host. all_composefs_deployments ( ) ?;
320+
321+ let depl_to_del = all_depls
322+ . iter ( )
323+ . find ( |d| d. deployment . verity == deployment_id) ;
324+
325+ let Some ( depl_to_del) = depl_to_del else {
326+ anyhow:: bail!( "Deployment {deployment_id} not found" ) ;
327+ } ;
328+
329+ let deleting_staged = host
330+ . status
331+ . staged
332+ . as_ref ( )
333+ . and_then ( |s| s. composefs . as_ref ( ) )
334+ . map_or ( false , |cfs| cfs. verity == deployment_id) ;
335+
336+ // Unqueue rollback. This makes it easier to delete boot entries later on
337+ if matches ! ( depl_to_del. ty, Some ( Slot :: Rollback ) ) && host. status . rollback_queued {
338+ composefs_rollback ( ) . await ?;
339+ }
319340
320341 // For debugging, but maybe useful elsewhere?
321342 if !delete {
@@ -338,32 +359,7 @@ pub(crate) async fn delete_composefs_deployment(deployment_id: &str, delete: boo
338359
339360 delete_depl_boot_entries ( & depl_to_del, deleting_staged) ?;
340361
341- // Delete the image
342- let img_path = Path :: new ( "composefs" ) . join ( "images" ) . join ( deployment_id) ;
343- sysroot
344- . remove_file ( & img_path)
345- . context ( "Deleting EROFS image" ) ?;
346-
347- if deleting_staged {
348- let file = Path :: new ( COMPOSEFS_TRANSIENT_STATE_DIR ) . join ( COMPOSEFS_STAGED_DEPLOYMENT_FNAME ) ;
349- tracing:: debug!( "Deleting staged file {file:?}" ) ;
350- std:: fs:: remove_file ( file) . context ( "Removing staged file" ) ?;
351- }
352-
353- let state_dir = Path :: new ( STATE_DIR_RELATIVE ) . join ( deployment_id) ;
354- sysroot
355- . remove_dir_all ( & state_dir)
356- . with_context ( || format ! ( "Removing dir {state_dir:?}" ) ) ?;
357-
358- for sha in diff {
359- let object_path = Path :: new ( "composefs" )
360- . join ( "objects" )
361- . join ( sha. to_object_pathname ( ) ) ;
362-
363- sysroot
364- . remove_file ( & object_path)
365- . with_context ( || format ! ( "Removing {object_path:?}" ) ) ?;
366- }
362+ composefs_gc ( ) . await ?;
367363
368364 Ok ( ( ) )
369365}
0 commit comments