@@ -56,6 +56,8 @@ use crate::utils::sigpolicy_from_opts;
5656const BOOT : & str = "boot" ;
5757/// Directory for transient runtime state
5858const RUN_BOOTC : & str = "/run/bootc" ;
59+ /// The default path for the host rootfs
60+ const ALONGSIDE_ROOT_MOUNT : & str = "/target" ;
5961/// This is an ext4 special directory we need to ignore.
6062const LOST_AND_FOUND : & str = "lost+found" ;
6163/// The filename of the composefs EROFS superblock; TODO move this into ostree
@@ -316,9 +318,10 @@ pub(crate) struct InstallToExistingRootOpts {
316318 #[ clap( long) ]
317319 pub ( crate ) acknowledge_destructive : bool ,
318320
319- /// Path to the mounted root; it's expected to invoke podman with
320- /// `-v /:/target`, then supplying this argument is unnecessary.
321- #[ clap( default_value = "/target" ) ]
321+ /// Path to the mounted root; this is now not necessary to provide.
322+ /// Historically it was necessary to ensure the host rootfs was mounted at here
323+ /// via e.g. `-v /:/target`.
324+ #[ clap( default_value = ALONGSIDE_ROOT_MOUNT ) ]
322325 pub ( crate ) root_path : Utf8PathBuf ,
323326}
324327
@@ -333,8 +336,6 @@ pub(crate) struct SourceInfo {
333336 pub ( crate ) selinux : bool ,
334337 /// Whether the source is available in the host mount namespace
335338 pub ( crate ) in_host_mountns : bool ,
336- /// Whether we were invoked with -v /var/lib/containers:/var/lib/containers
337- pub ( crate ) have_host_container_storage : bool ,
338339}
339340
340341// Shared read-only global state
@@ -516,38 +517,13 @@ impl SourceInfo {
516517 tracing:: debug!( "Finding digest for image ID {}" , container_info. imageid) ;
517518 let digest = crate :: podman:: imageid_to_digest ( & container_info. imageid ) ?;
518519
519- let have_host_container_storage = Utf8Path :: new ( crate :: podman:: CONTAINER_STORAGE )
520- . try_exists ( ) ?
521- && ostree_ext:: mountutil:: is_mountpoint (
522- & root,
523- crate :: podman:: CONTAINER_STORAGE . trim_start_matches ( '/' ) ,
524- ) ?
525- . unwrap_or_default ( ) ;
526-
527- // Verify up front we can do the fetch
528- if have_host_container_storage {
529- tracing:: debug!( "Host container storage found" ) ;
530- } else {
531- tracing:: debug!(
532- "No {} mount available, checking skopeo" ,
533- crate :: podman:: CONTAINER_STORAGE
534- ) ;
535- require_skopeo_with_containers_storage ( ) ?;
536- }
537-
538- Self :: new (
539- imageref,
540- Some ( digest) ,
541- root,
542- true ,
543- have_host_container_storage,
544- )
520+ Self :: new ( imageref, Some ( digest) , root, true )
545521 }
546522
547523 #[ context( "Creating source info from a given imageref" ) ]
548524 pub ( crate ) fn from_imageref ( imageref : & str , root : & Dir ) -> Result < Self > {
549525 let imageref = ostree_container:: ImageReference :: try_from ( imageref) ?;
550- Self :: new ( imageref, None , root, false , false )
526+ Self :: new ( imageref, None , root, false )
551527 }
552528
553529 fn have_selinux_from_repo ( root : & Dir ) -> Result < bool > {
@@ -573,7 +549,6 @@ impl SourceInfo {
573549 digest : Option < String > ,
574550 root : & Dir ,
575551 in_host_mountns : bool ,
576- have_host_container_storage : bool ,
577552 ) -> Result < Self > {
578553 let selinux = if Path :: new ( "/ostree/repo" ) . try_exists ( ) ? {
579554 Self :: have_selinux_from_repo ( root) ?
@@ -585,7 +560,6 @@ impl SourceInfo {
585560 digest,
586561 selinux,
587562 in_host_mountns,
588- have_host_container_storage,
589563 } )
590564 }
591565}
@@ -716,19 +690,7 @@ async fn install_container(
716690 }
717691 } ;
718692
719- // We need to fetch the container image from the root mount namespace. If
720- // we don't have /var/lib/containers mounted in this image, fork off skopeo
721- // in the host mountnfs.
722- let skopeo_cmd = if !state. source . have_host_container_storage {
723- Some ( run_in_host_mountns ( "skopeo" ) )
724- } else {
725- None
726- } ;
727- let proxy_cfg = ostree_container:: store:: ImageProxyConfig {
728- skopeo_cmd,
729- ..Default :: default ( )
730- } ;
731-
693+ let proxy_cfg = ostree_container:: store:: ImageProxyConfig :: default ( ) ;
732694 ( src_imageref, Some ( proxy_cfg) )
733695 } ;
734696 let src_imageref = ostree_container:: OstreeImageReference {
@@ -895,32 +857,6 @@ pub(crate) fn exec_in_host_mountns(args: &[std::ffi::OsString]) -> Result<()> {
895857 Err ( Command :: new ( cmd) . args ( args) . exec ( ) ) . context ( "exec" ) ?
896858}
897859
898- #[ context( "Querying skopeo version" ) ]
899- fn require_skopeo_with_containers_storage ( ) -> Result < ( ) > {
900- let out = Task :: new_cmd ( "skopeo --version" , run_in_host_mountns ( "skopeo" ) )
901- . args ( [ "--version" ] )
902- . quiet ( )
903- . read ( )
904- . context ( "Failed to run skopeo (it currently must be installed in the host root)" ) ?;
905- let mut v = out
906- . strip_prefix ( "skopeo version " )
907- . map ( |v| v. split ( '.' ) )
908- . ok_or_else ( || anyhow:: anyhow!( "Unexpected output from skopeo version" ) ) ?;
909- let major = v
910- . next ( )
911- . ok_or_else ( || anyhow:: anyhow!( "Missing major version" ) ) ?;
912- let minor = v
913- . next ( )
914- . ok_or_else ( || anyhow:: anyhow!( "Missing minor version" ) ) ?;
915- let ( major, minor) = ( major. parse :: < u64 > ( ) ?, minor. parse :: < u64 > ( ) ?) ;
916- let supported = major > 1 || minor > 10 ;
917- if supported {
918- Ok ( ( ) )
919- } else {
920- anyhow:: bail!( "skopeo >= 1.11 is required on host" )
921- }
922- }
923-
924860pub ( crate ) struct RootSetup {
925861 luks_device : Option < String > ,
926862 device_info : crate :: blockdev:: PartitionTable ,
@@ -1269,6 +1205,8 @@ async fn prepare_install(
12691205 tracing:: debug!( "Target image reference: {target_imgref}" ) ;
12701206
12711207 // A bit of basic global state setup
1208+ crate :: mount:: ensure_mirrored_host_mount ( "/dev" ) ?;
1209+ crate :: mount:: ensure_mirrored_host_mount ( "/var/lib/containers" ) ?;
12721210 ensure_var ( ) ?;
12731211 setup_tmp_mounts ( ) ?;
12741212 // Allocate a temporary directory we can use in various places to avoid
@@ -1454,12 +1392,6 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re
14541392 . ok_or_else ( || anyhow ! ( "No uuid for boot/root" ) ) ?;
14551393 tracing:: debug!( "boot uuid={boot_uuid}" ) ;
14561394
1457- // If we're doing an alongside install, then the /dev bootupd sees needs to be the host's.
1458- ensure ! (
1459- crate :: mount:: is_same_as_host( Utf8Path :: new( "/dev" ) ) ?,
1460- "Missing /dev mount to host /dev"
1461- ) ;
1462-
14631395 let bound_images = BoundImages :: from_state ( state) . await ?;
14641396
14651397 // Initialize the ostree sysroot (repo, stateroot, etc.)
@@ -1514,9 +1446,6 @@ pub(crate) async fn install_to_disk(mut opts: InstallToDiskOpts) -> Result<()> {
15141446 block_opts. device
15151447 ) ;
15161448 }
1517- if !crate :: mount:: is_same_as_host ( Utf8Path :: new ( "/dev" ) ) ? {
1518- anyhow:: bail!( "Loopback mounts (--via-loopback) require host devices (-v /dev:/dev)" ) ;
1519- }
15201449 } else if !target_blockdev_meta. file_type ( ) . is_block_device ( ) {
15211450 anyhow:: bail!( "Not a block device: {}" , block_opts. device) ;
15221451 }
@@ -1705,6 +1634,23 @@ pub(crate) async fn install_to_filesystem(
17051634 // And the last bit of state here is the fsopts, which we also destructure now.
17061635 let mut fsopts = opts. filesystem_opts ;
17071636
1637+ // If we're doing an alongside install, automatically set up the host rootfs
1638+ // mount if it wasn't done already.
1639+ if targeting_host_root
1640+ && fsopts. root_path . as_str ( ) == ALONGSIDE_ROOT_MOUNT
1641+ && !fsopts. root_path . try_exists ( ) ?
1642+ {
1643+ tracing:: debug!( "Mounting host / to {ALONGSIDE_ROOT_MOUNT}" ) ;
1644+ std:: fs:: create_dir ( ALONGSIDE_ROOT_MOUNT ) ?;
1645+ crate :: mount:: bind_mount_from_pidns (
1646+ crate :: mount:: PID1 ,
1647+ "/" . into ( ) ,
1648+ ALONGSIDE_ROOT_MOUNT . into ( ) ,
1649+ true ,
1650+ )
1651+ . context ( "Mounting host / to {ALONGSIDE_ROOT_MOUNT}" ) ?;
1652+ }
1653+
17081654 // Check that the target is a directory
17091655 {
17101656 let root_path = & fsopts. root_path ;
0 commit comments