@@ -1073,6 +1073,7 @@ pub(crate) struct RootSetup {
10731073 pub ( crate ) physical_root_path : Utf8PathBuf ,
10741074 /// Directory file descriptor for the above physical root.
10751075 pub ( crate ) physical_root : Dir ,
1076+ pub ( crate ) target_root_path : Option < Utf8PathBuf > ,
10761077 pub ( crate ) rootfs_uuid : Option < String > ,
10771078 /// True if we should skip finalizing
10781079 skip_finalize : bool ,
@@ -1514,7 +1515,10 @@ async fn install_with_sysroot(
15141515 Bootloader :: Grub => {
15151516 crate :: bootloader:: install_via_bootupd (
15161517 & rootfs. device_info ,
1517- & rootfs. physical_root_path ,
1518+ & rootfs
1519+ . target_root_path
1520+ . clone ( )
1521+ . unwrap_or ( rootfs. physical_root_path . clone ( ) ) ,
15181522 & state. config_opts ,
15191523 Some ( & deployment_path. as_str ( ) ) ,
15201524 ) ?;
@@ -1986,6 +1990,7 @@ pub(crate) async fn install_to_filesystem(
19861990 . context ( "Mounting host / to {ALONGSIDE_ROOT_MOUNT}" ) ?;
19871991 }
19881992
1993+ let target_root_path = & fsopts. root_path . clone ( ) ;
19891994 // Check that the target is a directory
19901995 {
19911996 let root_path = & fsopts. root_path ;
@@ -2005,22 +2010,40 @@ pub(crate) async fn install_to_filesystem(
20052010 warn_on_host_root ( & rootfs_fd) ?;
20062011 }
20072012
2013+ // Get a file descriptor for the root path /target
2014+ // This is needed to find boot dev
2015+ let target_rootfs_fd = {
2016+ let rootfs_fd = Dir :: open_ambient_dir ( & target_root_path, cap_std:: ambient_authority ( ) )
2017+ . with_context ( || format ! ( "Opening target root directory {target_root_path}" ) ) ?;
2018+
2019+ tracing:: debug!( "Root filesystem: {target_root_path}" ) ;
2020+
2021+ if let Some ( false ) = rootfs_fd. is_mountpoint ( "." ) ? {
2022+ anyhow:: bail!( "Not a mountpoint: {target_root_path}" ) ;
2023+ }
2024+ rootfs_fd
2025+ } ;
2026+
20082027 // If we're installing to an ostree root, then find the physical root from
20092028 // the deployment root.
20102029 let possible_physical_root = fsopts. root_path . join ( "sysroot" ) ;
20112030 let possible_ostree_dir = possible_physical_root. join ( "ostree" ) ;
20122031 let is_already_ostree = possible_ostree_dir. exists ( ) ;
2013- if is_already_ostree {
2032+
2033+ let inspect = bootc_mount:: inspect_filesystem ( & target_root_path) ?;
2034+ tracing:: debug!( "Root {} fstype: {}" , target_root_path, inspect. fstype) ;
2035+
2036+ if is_already_ostree && inspect. fstype == "overlay" {
20142037 tracing:: debug!(
20152038 "ostree detected in {possible_ostree_dir}, assuming target is a deployment root and using {possible_physical_root}"
20162039 ) ;
20172040 fsopts. root_path = possible_physical_root;
20182041 } ;
20192042
20202043 // Get a file descriptor for the root path
2021- let rootfs_fd = {
2044+ let rootfs_fd = if fsopts . root_path . ends_with ( "sysroot" ) {
20222045 let root_path = & fsopts. root_path ;
2023- let rootfs_fd = Dir :: open_ambient_dir ( & fsopts . root_path , cap_std:: ambient_authority ( ) )
2046+ let rootfs_fd = Dir :: open_ambient_dir ( root_path, cap_std:: ambient_authority ( ) )
20242047 . with_context ( || format ! ( "Opening target root directory {root_path}" ) ) ?;
20252048
20262049 tracing:: debug!( "Root filesystem: {root_path}" ) ;
@@ -2029,17 +2052,22 @@ pub(crate) async fn install_to_filesystem(
20292052 anyhow:: bail!( "Not a mountpoint: {root_path}" ) ;
20302053 }
20312054 rootfs_fd
2055+ } else {
2056+ target_rootfs_fd. try_clone ( ) ?
20322057 } ;
20332058
2059+ // Find boot under /, instead of /sysroot
20342060 match fsopts. replace {
20352061 Some ( ReplaceMode :: Wipe ) => {
2036- let rootfs_fd = rootfs_fd . try_clone ( ) ?;
2062+ let rootfs_fd = target_rootfs_fd . try_clone ( ) ?;
20372063 println ! ( "Wiping contents of root" ) ;
20382064 tokio:: task:: spawn_blocking ( move || remove_all_in_dir_no_xdev ( & rootfs_fd, true ) )
20392065 . await ??;
20402066 }
2041- Some ( ReplaceMode :: Alongside ) => clean_boot_directories ( & rootfs_fd, is_already_ostree) ?,
2042- None => require_empty_rootdir ( & rootfs_fd) ?,
2067+ Some ( ReplaceMode :: Alongside ) => {
2068+ clean_boot_directories ( & target_rootfs_fd, is_already_ostree) ?
2069+ }
2070+ None => require_empty_rootdir ( & target_rootfs_fd) ?,
20432071 }
20442072
20452073 // Gather data about the root filesystem
@@ -2083,7 +2111,7 @@ pub(crate) async fn install_to_filesystem(
20832111
20842112 let boot_is_mount = {
20852113 let root_dev = rootfs_fd. dir_metadata ( ) ?. dev ( ) ;
2086- let boot_dev = rootfs_fd
2114+ let boot_dev = target_rootfs_fd
20872115 . symlink_metadata_optional ( BOOT ) ?
20882116 . ok_or_else ( || {
20892117 anyhow ! ( "No /{BOOT} directory found in root; this is is currently required" )
@@ -2094,9 +2122,10 @@ pub(crate) async fn install_to_filesystem(
20942122 } ;
20952123 // Find the UUID of /boot because we need it for GRUB.
20962124 let boot_uuid = if boot_is_mount {
2097- let boot_path = fsopts. root_path . join ( BOOT ) ;
2125+ let boot_path = target_root_path. join ( BOOT ) ;
2126+ tracing:: debug!( "boot_path={boot_path}" ) ;
20982127 let u = bootc_mount:: inspect_filesystem ( & boot_path)
2099- . context ( "Inspecting /{BOOT}" ) ?
2128+ . with_context ( || format ! ( "Inspecting /{BOOT}" ) ) ?
21002129 . uuid
21012130 . ok_or_else ( || anyhow ! ( "No UUID found for /{BOOT}" ) ) ?;
21022131 Some ( u)
@@ -2175,6 +2204,7 @@ pub(crate) async fn install_to_filesystem(
21752204 device_info,
21762205 physical_root_path : fsopts. root_path ,
21772206 physical_root : rootfs_fd,
2207+ target_root_path : Some ( target_root_path. clone ( ) ) ,
21782208 rootfs_uuid : inspect. uuid . clone ( ) ,
21792209 boot,
21802210 kargs,
0 commit comments