@@ -1815,6 +1815,42 @@ fn require_empty_rootdir(rootfs_fd: &Dir) -> Result<()> {
18151815 Ok ( ( ) )
18161816}
18171817
1818+ #[ context( "Removing boot directory content except loader and ostree dirs" ) ]
1819+ fn remove_all_except_loader_dirs ( bootdir : & Dir ) -> Result < ( ) > {
1820+ let entries = bootdir. entries ( ) . context ( "Reading boot directory entries" ) ?;
1821+ let protected_dirs = [ "loader" , "ostree" ] ;
1822+
1823+ for entry in entries {
1824+ let entry = entry. context ( "Reading directory entry" ) ?;
1825+ let file_name = entry. file_name ( ) ;
1826+ let file_name = if let Some ( n) = file_name. to_str ( ) {
1827+ n
1828+ } else {
1829+ anyhow:: bail!( "Invalid non-UTF8 filename: {file_name:?} in /boot" ) ;
1830+ } ;
1831+
1832+ // Skip any entry that starts with a protected prefix,
1833+ // as we also need to protect loader.0 or loader.1
1834+ if protected_dirs. iter ( ) . any ( |p| file_name. starts_with ( p) ) {
1835+ continue ;
1836+ }
1837+
1838+ let etype = entry. file_type ( ) ?;
1839+ if etype == FileType :: dir ( ) {
1840+ // Open the directory and remove its contents
1841+ if let Some ( subdir) = bootdir. open_dir_noxdev ( & file_name) ? {
1842+ remove_all_in_dir_no_xdev ( & subdir, false )
1843+ . with_context ( || format ! ( "Removing directory contents: {}" , file_name) ) ?;
1844+ }
1845+ } else {
1846+ bootdir
1847+ . remove_file_optional ( & file_name)
1848+ . with_context ( || format ! ( "Removing file: {}" , file_name) ) ?;
1849+ }
1850+ }
1851+ Ok ( ( ) )
1852+ }
1853+
18181854/// Remove all entries in a directory, but do not traverse across distinct devices.
18191855/// If mount_err is true, then an error is returned if a mount point is found;
18201856/// otherwise it is silently ignored.
@@ -1838,29 +1874,22 @@ fn remove_all_in_dir_no_xdev(d: &Dir, mount_err: bool) -> Result<()> {
18381874}
18391875
18401876#[ context( "Removing boot directory content" ) ]
1841- fn clean_boot_directories ( rootfs : & Dir , is_ostree : bool ) -> Result < ( ) > {
1877+ fn clean_boot_directories ( rootfs : & Dir ) -> Result < ( ) > {
18421878 let bootdir =
18431879 crate :: utils:: open_dir_remount_rw ( rootfs, BOOT . into ( ) ) . context ( "Opening /boot" ) ?;
18441880
1845- if is_ostree {
1846- // On ostree systems, the boot directory already has our desired format, we should only
1847- // remove the bootupd-state.json file to avoid bootupctl complaining it already exists.
1848- bootdir
1849- . remove_file_optional ( "bootupd-state.json" )
1850- . context ( "removing bootupd-state.json" ) ?;
1851- } else {
1852- // This should not remove /boot/efi note.
1853- remove_all_in_dir_no_xdev ( & bootdir, false ) . context ( "Emptying /boot" ) ?;
1854- // TODO: Discover the ESP the same way bootupd does it; we should also
1855- // support not wiping the ESP.
1856- if ARCH_USES_EFI {
1857- if let Some ( efidir) = bootdir
1858- . open_dir_optional ( crate :: bootloader:: EFI_DIR )
1859- . context ( "Opening /boot/efi" ) ?
1860- {
1861- remove_all_in_dir_no_xdev ( & efidir, false )
1862- . context ( "Emptying EFI system partition" ) ?;
1863- }
1881+ // This should not remove /boot/efi note.
1882+ remove_all_except_loader_dirs ( & bootdir) . context ( "Emptying /boot except protected dirs" ) ?;
1883+
1884+ // TODO: Discover the ESP the same way bootupd does it; we should also
1885+ // support not wiping the ESP.
1886+ if ARCH_USES_EFI {
1887+ if let Some ( efidir) = bootdir
1888+ . open_dir_optional ( crate :: bootloader:: EFI_DIR )
1889+ . context ( "Opening /boot/efi" ) ?
1890+ {
1891+ remove_all_in_dir_no_xdev ( & efidir, false )
1892+ . context ( "Emptying EFI system partition" ) ?;
18641893 }
18651894 }
18661895
@@ -2068,7 +2097,7 @@ pub(crate) async fn install_to_filesystem(
20682097 }
20692098 // Find boot under /
20702099 Some ( ReplaceMode :: Alongside ) => {
2071- clean_boot_directories ( & target_rootfs_fd, is_already_ostree ) ?
2100+ clean_boot_directories ( & target_rootfs_fd) ?
20722101 }
20732102 None => require_empty_rootdir ( & target_rootfs_fd) ?,
20742103 }
0 commit comments