@@ -69,6 +69,8 @@ const BOOT: &str = "boot";
69
69
const RUN_BOOTC : & str = "/run/bootc" ;
70
70
/// The default path for the host rootfs
71
71
const 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" ;
72
74
/// This is an ext4 special directory we need to ignore.
73
75
const LOST_AND_FOUND : & str = "lost+found" ;
74
76
/// The filename of the composefs EROFS superblock; TODO move this into ostree
@@ -335,6 +337,11 @@ pub(crate) struct InstallToExistingRootOpts {
335
337
#[ clap( long) ]
336
338
pub ( crate ) acknowledge_destructive : bool ,
337
339
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
+
338
345
/// Path to the mounted root; this is now not necessary to provide.
339
346
/// Historically it was necessary to ensure the host rootfs was mounted at here
340
347
/// via e.g. `-v /:/target`.
@@ -1460,7 +1467,11 @@ impl BoundImages {
1460
1467
}
1461
1468
}
1462
1469
1463
- async fn install_to_filesystem_impl ( state : & State , rootfs : & mut RootSetup ) -> Result < ( ) > {
1470
+ async fn install_to_filesystem_impl (
1471
+ state : & State ,
1472
+ rootfs : & mut RootSetup ,
1473
+ cleanup : Cleanup ,
1474
+ ) -> Result < ( ) > {
1464
1475
if matches ! ( state. selinux_state, SELinuxFinalState :: ForceTargetDisabled ) {
1465
1476
rootfs. kargs . push ( "selinux=0" . to_string ( ) ) ;
1466
1477
}
@@ -1489,6 +1500,7 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re
1489
1500
let bound_images = BoundImages :: from_state ( state) . await ?;
1490
1501
1491
1502
// Initialize the ostree sysroot (repo, stateroot, etc.)
1503
+
1492
1504
{
1493
1505
let ( sysroot, has_ostree, imgstore) = initialize_ostree_root ( state, rootfs) . await ?;
1494
1506
@@ -1502,9 +1514,16 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re
1502
1514
& imgstore,
1503
1515
)
1504
1516
. await ?;
1517
+
1518
+ if matches ! ( cleanup, Cleanup :: TriggerOnNextBoot ) {
1519
+ let sysroot_dir = crate :: utils:: sysroot_dir ( & sysroot) ?;
1520
+ tracing:: debug!( "Writing {DESTRUCTIVE_CLEANUP}" ) ;
1521
+ sysroot_dir. atomic_write ( format ! ( "etc/{}" , DESTRUCTIVE_CLEANUP ) , b"" ) ?;
1522
+ }
1523
+
1505
1524
// We must drop the sysroot here in order to close any open file
1506
1525
// descriptors.
1507
- }
1526
+ } ;
1508
1527
1509
1528
// Run this on every install as the penultimate step
1510
1529
install_finalize ( & rootfs. physical_root_path ) . await ?;
@@ -1570,7 +1589,7 @@ pub(crate) async fn install_to_disk(mut opts: InstallToDiskOpts) -> Result<()> {
1570
1589
( rootfs, loopback_dev)
1571
1590
} ;
1572
1591
1573
- install_to_filesystem_impl ( & state, & mut rootfs) . await ?;
1592
+ install_to_filesystem_impl ( & state, & mut rootfs, Cleanup :: Skip ) . await ?;
1574
1593
1575
1594
// Drop all data about the root except the bits we need to ensure any file descriptors etc. are closed.
1576
1595
let ( root_path, luksdev) = rootfs. into_storage ( ) ;
@@ -1740,11 +1759,17 @@ fn warn_on_host_root(rootfs_fd: &Dir) -> Result<()> {
1740
1759
Ok ( ( ) )
1741
1760
}
1742
1761
1762
+ pub enum Cleanup {
1763
+ Skip ,
1764
+ TriggerOnNextBoot ,
1765
+ }
1766
+
1743
1767
/// Implementation of the `bootc install to-filsystem` CLI command.
1744
1768
#[ context( "Installing to filesystem" ) ]
1745
1769
pub ( crate ) async fn install_to_filesystem (
1746
1770
opts : InstallToFilesystemOpts ,
1747
1771
targeting_host_root : bool ,
1772
+ cleanup : Cleanup ,
1748
1773
) -> Result < ( ) > {
1749
1774
// Gather global state, destructuring the provided options.
1750
1775
// IMPORTANT: We might re-execute the current process in this function (for SELinux among other things)
@@ -1950,7 +1975,7 @@ pub(crate) async fn install_to_filesystem(
1950
1975
skip_finalize,
1951
1976
} ;
1952
1977
1953
- install_to_filesystem_impl ( & state, & mut rootfs) . await ?;
1978
+ install_to_filesystem_impl ( & state, & mut rootfs, cleanup ) . await ?;
1954
1979
1955
1980
// Drop all data about the root except the path to ensure any file descriptors etc. are closed.
1956
1981
drop ( rootfs) ;
@@ -1961,6 +1986,11 @@ pub(crate) async fn install_to_filesystem(
1961
1986
}
1962
1987
1963
1988
pub ( crate ) async fn install_to_existing_root ( opts : InstallToExistingRootOpts ) -> Result < ( ) > {
1989
+ let cleanup = match opts. cleanup {
1990
+ true => Cleanup :: TriggerOnNextBoot ,
1991
+ false => Cleanup :: Skip ,
1992
+ } ;
1993
+
1964
1994
let opts = InstallToFilesystemOpts {
1965
1995
filesystem_opts : InstallTargetFilesystemOpts {
1966
1996
root_path : opts. root_path ,
@@ -1975,7 +2005,7 @@ pub(crate) async fn install_to_existing_root(opts: InstallToExistingRootOpts) ->
1975
2005
config_opts : opts. config_opts ,
1976
2006
} ;
1977
2007
1978
- install_to_filesystem ( opts, true ) . await
2008
+ install_to_filesystem ( opts, true , cleanup ) . await
1979
2009
}
1980
2010
1981
2011
/// Implementation of `bootc install finalize`.
0 commit comments