@@ -69,6 +69,8 @@ const BOOT: &str = "boot";
6969const RUN_BOOTC : & str = "/run/bootc" ;
7070/// The default path for the host rootfs
7171const ALONGSIDE_ROOT_MOUNT : & str = "/target" ;
72+ /// Global flag to signal the booted system was provisioned via an alongside bootc install
73+ const DESTRUCTIVE_CLEANUP : & str = "bootc-destructive-cleanup" ;
7274/// This is an ext4 special directory we need to ignore.
7375const LOST_AND_FOUND : & str = "lost+found" ;
7476/// The filename of the composefs EROFS superblock; TODO move this into ostree
@@ -335,6 +337,11 @@ pub(crate) struct InstallToExistingRootOpts {
335337 #[ clap( long) ]
336338 pub ( crate ) acknowledge_destructive : bool ,
337339
340+ /// Add the bootc-destructive-cleanup systemd service to delete files from
341+ /// the previous install on first boot
342+ #[ clap( long) ]
343+ pub ( crate ) cleanup : bool ,
344+
338345 /// Path to the mounted root; this is now not necessary to provide.
339346 /// Historically it was necessary to ensure the host rootfs was mounted at here
340347 /// via e.g. `-v /:/target`.
@@ -1460,7 +1467,7 @@ impl BoundImages {
14601467 }
14611468}
14621469
1463- async fn install_to_filesystem_impl ( state : & State , rootfs : & mut RootSetup ) -> Result < ( ) > {
1470+ async fn install_to_filesystem_impl ( state : & State , rootfs : & mut RootSetup ) -> Result < Storage > {
14641471 if matches ! ( state. selinux_state, SELinuxFinalState :: ForceTargetDisabled ) {
14651472 rootfs. kargs . push ( "selinux=0" . to_string ( ) ) ;
14661473 }
@@ -1489,7 +1496,8 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re
14891496 let bound_images = BoundImages :: from_state ( state) . await ?;
14901497
14911498 // Initialize the ostree sysroot (repo, stateroot, etc.)
1492- {
1499+
1500+ let sysroot = {
14931501 let ( sysroot, has_ostree, imgstore) = initialize_ostree_root ( state, rootfs) . await ?;
14941502
14951503 install_with_sysroot (
@@ -1504,7 +1512,9 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re
15041512 . await ?;
15051513 // We must drop the sysroot here in order to close any open file
15061514 // descriptors.
1507- }
1515+ //
1516+ sysroot
1517+ } ;
15081518
15091519 // Run this on every install as the penultimate step
15101520 install_finalize ( & rootfs. physical_root_path ) . await ?;
@@ -1517,7 +1527,7 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re
15171527 }
15181528 }
15191529
1520- Ok ( ( ) )
1530+ Ok ( sysroot )
15211531}
15221532
15231533fn installation_complete ( ) {
@@ -1740,11 +1750,17 @@ fn warn_on_host_root(rootfs_fd: &Dir) -> Result<()> {
17401750 Ok ( ( ) )
17411751}
17421752
1753+ pub enum Cleanup {
1754+ Skip ,
1755+ TriggerOnNextBoot ,
1756+ }
1757+
17431758/// Implementation of the `bootc install to-filsystem` CLI command.
17441759#[ context( "Installing to filesystem" ) ]
17451760pub ( crate ) async fn install_to_filesystem (
17461761 opts : InstallToFilesystemOpts ,
17471762 targeting_host_root : bool ,
1763+ cleanup : Cleanup ,
17481764) -> Result < ( ) > {
17491765 // Gather global state, destructuring the provided options.
17501766 // IMPORTANT: We might re-execute the current process in this function (for SELinux among other things)
@@ -1950,7 +1966,13 @@ pub(crate) async fn install_to_filesystem(
19501966 skip_finalize,
19511967 } ;
19521968
1953- install_to_filesystem_impl ( & state, & mut rootfs) . await ?;
1969+ let sysroot = install_to_filesystem_impl ( & state, & mut rootfs) . await ?;
1970+
1971+ if matches ! ( cleanup, Cleanup :: TriggerOnNextBoot ) {
1972+ let sysroot_dir = crate :: utils:: sysroot_dir ( & sysroot. sysroot ) ?;
1973+ tracing:: debug!( "Writing {DESTRUCTIVE_CLEANUP}" ) ;
1974+ sysroot_dir. atomic_write ( format ! ( "etc/{}" , DESTRUCTIVE_CLEANUP ) , b"" ) ?;
1975+ }
19541976
19551977 // Drop all data about the root except the path to ensure any file descriptors etc. are closed.
19561978 drop ( rootfs) ;
@@ -1961,6 +1983,11 @@ pub(crate) async fn install_to_filesystem(
19611983}
19621984
19631985pub ( crate ) async fn install_to_existing_root ( opts : InstallToExistingRootOpts ) -> Result < ( ) > {
1986+ let cleanup = match opts. cleanup {
1987+ true => Cleanup :: TriggerOnNextBoot ,
1988+ false => Cleanup :: Skip ,
1989+ } ;
1990+
19641991 let opts = InstallToFilesystemOpts {
19651992 filesystem_opts : InstallTargetFilesystemOpts {
19661993 root_path : opts. root_path ,
@@ -1975,7 +2002,7 @@ pub(crate) async fn install_to_existing_root(opts: InstallToExistingRootOpts) ->
19752002 config_opts : opts. config_opts ,
19762003 } ;
19772004
1978- install_to_filesystem ( opts, true ) . await
2005+ install_to_filesystem ( opts, true , cleanup ) . await
19792006}
19802007
19812008/// Implementation of `bootc install finalize`.
0 commit comments