@@ -788,6 +788,8 @@ pub(crate) async fn run_impl(opts: RunEphemeralOpts) -> Result<()> {
788788
789789 // Process host mounts and prepare virtiofsd instances for each using async manager
790790 let mut additional_mounts = Vec :: new ( ) ;
791+ // Collect mount unit credentials to inject via SMBIOS instead of writing to filesystem
792+ let mut mount_unit_smbios_creds = Vec :: new ( ) ;
791793
792794 debug ! (
793795 "Checking for host mounts directory: /run/host-mounts exists = {}" ,
@@ -798,8 +800,7 @@ pub(crate) async fn run_impl(opts: RunEphemeralOpts) -> Result<()> {
798800 Utf8Path :: new( "/run/systemd-units" ) . exists( )
799801 ) ;
800802
801- let target_unitdir = "/run/source-image/etc/systemd/system" ;
802-
803+ let mut mount_unit_names = Vec :: new ( ) ;
803804 if Utf8Path :: new ( "/run/host-mounts" ) . exists ( ) {
804805 for entry in fs:: read_dir ( "/run/host-mounts" ) ? {
805806 let entry = entry?;
@@ -832,73 +833,48 @@ pub(crate) async fn run_impl(opts: RunEphemeralOpts) -> Result<()> {
832833 } ;
833834 additional_mounts. push ( ( virtiofsd_config, tag. clone ( ) ) ) ;
834835
835- // Create individual . mount unit for this virtiofs mount
836+ // Generate mount unit via SMBIOS credentials instead of writing to filesystem
836837 let mount_point = format ! ( "/run/virtiofs-mnt-{}" , mount_name_str) ;
837-
838- // Use systemd-escape to properly escape the mount path
839- let escaped_path = Command :: new ( "systemd-escape" )
840- . args ( [ "-p" , & mount_point] )
841- . output ( )
842- . map ( |output| String :: from_utf8_lossy ( & output. stdout ) . trim ( ) . to_string ( ) )
843- . unwrap_or_else ( |_| {
844- // Fallback if systemd-escape is not available
845- mount_point
846- . replace ( "/" , "-" )
847- . trim_start_matches ( '-' )
848- . to_string ( )
849- } ) ;
850-
851- let mount_unit_name = format ! ( "{}.mount" , escaped_path) ;
852- let mount_options = if is_readonly { "ro" } else { "defaults" } ;
853-
854- let mount_unit_content = format ! (
855- r#"[Unit]
856- Description=Mount virtiofs {}
857- DefaultDependencies=no
858- After=systemd-remount-fs.service
859- Before=local-fs.target shutdown.target
860-
861- [Mount]
862- What={}
863- Where={}
864- Type=virtiofs
865- Options={}
866-
867- [Install]
868- WantedBy=local-fs.target
869- "# ,
870- mount_name_str, tag, mount_point, mount_options
838+ let unit_name = crate :: credentials:: guest_path_to_unit_name ( & mount_point) ;
839+ let mount_unit_content =
840+ crate :: credentials:: generate_mount_unit ( & tag, & mount_point, is_readonly) ;
841+ let encoded_mount = data_encoding:: BASE64 . encode ( mount_unit_content. as_bytes ( ) ) ;
842+
843+ // Create SMBIOS credential for the mount unit
844+ let mount_cred = format ! (
845+ "io.systemd.credential.binary:systemd.extra-unit.{unit_name}={encoded_mount}"
871846 ) ;
847+ mount_unit_smbios_creds. push ( mount_cred) ;
872848
873- let mount_unit_path = format ! ( "{target_unitdir}/{mount_unit_name}" ) ;
874- fs:: write ( & mount_unit_path, mount_unit_content)
875- . with_context ( || format ! ( "Failed to write mount unit to {}" , mount_unit_path) ) ?;
876-
877- // Enable the mount unit by creating symlink in local-fs.target.wants/
878- let wants_dir = format ! ( "{target_unitdir}/local-fs.target.wants" ) ;
879- fs:: create_dir_all ( & wants_dir) ?;
880- let wants_link = format ! ( "{}/{}" , wants_dir, mount_unit_name) ;
881- let relative_target = format ! ( "../{}" , mount_unit_name) ;
882- std:: os:: unix:: fs:: symlink ( & relative_target, & wants_link) ?;
883-
884- // Create mount point directory in the image
885- let image_mount_point = format ! ( "/run/source-image{}" , mount_point) ;
886- fs:: create_dir_all ( & image_mount_point) . ok ( ) ;
849+ // Collect unit name for the local-fs.target dropin
850+ mount_unit_names. push ( unit_name. clone ( ) ) ;
887851
888852 debug ! (
889- "Generated mount unit: {} (enabled in local-fs.target )" ,
890- mount_unit_name
853+ "Generated SMBIOS credential for mount unit: {} ({} )" ,
854+ unit_name , mode
891855 ) ;
892856 }
893857 }
894858
859+ // If we have mount units, create a single dropin for local-fs.target
860+ if !mount_unit_names. is_empty ( ) {
861+ let wants_list = mount_unit_names. join ( " " ) ;
862+ let dropin_content = format ! ( "[Unit]\n Wants={}\n " , wants_list) ;
863+ let encoded_dropin = data_encoding:: BASE64 . encode ( dropin_content. as_bytes ( ) ) ;
864+ let dropin_cred = format ! (
865+ "io.systemd.credential.binary:systemd.unit-dropin.local-fs.target~bcvk-mounts={encoded_dropin}"
866+ ) ;
867+ mount_unit_smbios_creds. push ( dropin_cred) ;
868+ debug ! (
869+ "Created local-fs.target dropin for {} mount units" ,
870+ mount_unit_names. len( )
871+ ) ;
872+ }
873+
895874 // Handle --execute: pipes will be created when adding to qemu_config later
896875 // No need to create files anymore as we're using pipes
897876
898- let default_wantsdir = format ! ( "{target_unitdir}/default.target.wants" ) ;
899- fs:: create_dir_all ( & default_wantsdir) ?;
900-
901- // Create systemd unit to stream journal to virtio-serial device
877+ // Create systemd unit to stream journal to virtio-serial device via SMBIOS credential
902878 let journal_stream_unit = r#"[Unit]
903879Description=Stream systemd journal to host via virtio-serial
904880DefaultDependencies=no
@@ -916,17 +892,23 @@ RestartSec=1s
916892[Install]
917893WantedBy=sysinit.target
918894"# ;
919- let journal_unit_path = format ! ( "{target_unitdir}/bcvk-journal-stream.service" ) ;
920- tokio:: fs:: write ( & journal_unit_path, journal_stream_unit) . await ?;
921- debug ! ( "Created journal streaming unit at {journal_unit_path}" ) ;
922-
923- // Enable the journal streaming unit
924- let sysinit_wantsdir = format ! ( "{target_unitdir}/sysinit.target.wants" ) ;
925- tokio:: fs:: create_dir_all ( & sysinit_wantsdir) . await ?;
926- let journal_wants_link = format ! ( "{sysinit_wantsdir}/bcvk-journal-stream.service" ) ;
927- tokio:: fs:: symlink ( "../bcvk-journal-stream.service" , & journal_wants_link) . await ?;
928- debug ! ( "Enabled journal streaming unit in sysinit.target.wants" ) ;
895+ let encoded_journal = data_encoding:: BASE64 . encode ( journal_stream_unit. as_bytes ( ) ) ;
896+ let journal_cred = format ! (
897+ "io.systemd.credential.binary:systemd.extra-unit.bcvk-journal-stream.service={encoded_journal}"
898+ ) ;
899+ mount_unit_smbios_creds. push ( journal_cred) ;
900+ debug ! ( "Generated SMBIOS credential for journal streaming unit" ) ;
901+
902+ // Create dropin for sysinit.target to enable journal streaming
903+ let journal_dropin = "[Unit]\n Wants=bcvk-journal-stream.service\n " ;
904+ let encoded_dropin = data_encoding:: BASE64 . encode ( journal_dropin. as_bytes ( ) ) ;
905+ let dropin_cred = format ! (
906+ "io.systemd.credential.binary:systemd.unit-dropin.sysinit.target~bcvk-journal={encoded_dropin}"
907+ ) ;
908+ mount_unit_smbios_creds. push ( dropin_cred) ;
909+ debug ! ( "Created sysinit.target dropin to enable journal streaming unit" ) ;
929910
911+ // Create execute units via SMBIOS credentials if needed
930912 match opts. common . execute . as_slice ( ) {
931913 [ ] => { }
932914 elts => {
@@ -946,8 +928,7 @@ StandardError=inherit
946928 service_content. push_str ( & format ! ( "ExecStart={elt}\n " ) ) ;
947929 }
948930
949- let service_finish = format ! (
950- r#"[Unit]
931+ let service_finish = r#"[Unit]
951932Description=Execute Script Service Completion
952933After=bootc-execute.service
953934Requires=dev-virtio\\x2dports-executestatus.device
@@ -957,24 +938,34 @@ Type=oneshot
957938ExecStart=systemctl show bootc-execute
958939ExecStart=systemctl poweroff
959940StandardOutput=file:/dev/virtio-ports/executestatus
960- "#
961- ) ;
941+ "# ;
962942
963- let service_path = format ! ( "{target_unitdir}/bootc-execute.service" ) ;
964- fs:: write ( service_path, service_content) ?;
965- let service_path = format ! ( "{target_unitdir}/bootc-execute-finish.service" ) ;
966- fs:: write ( service_path, service_finish) ?;
943+ // Inject execute units via SMBIOS credentials
944+ let encoded_execute = data_encoding:: BASE64 . encode ( service_content. as_bytes ( ) ) ;
945+ let execute_cred = format ! (
946+ "io.systemd.credential.binary:systemd.extra-unit.bootc-execute.service={encoded_execute}"
947+ ) ;
948+ mount_unit_smbios_creds. push ( execute_cred) ;
967949
968- for svc in [ "bootc-execute.service" , "bootc-execute-finish.service" ] {
969- let wants_link = format ! ( "{default_wantsdir}/{svc}" ) ;
970- debug ! ( "Creating execute service symlink: {}" , & wants_link) ;
971- std:: os:: unix:: fs:: symlink ( format ! ( "../{svc}" ) , wants_link) ?;
972- }
950+ let encoded_finish = data_encoding:: BASE64 . encode ( service_finish. as_bytes ( ) ) ;
951+ let finish_cred = format ! (
952+ "io.systemd.credential.binary:systemd.extra-unit.bootc-execute-finish.service={encoded_finish}"
953+ ) ;
954+ mount_unit_smbios_creds. push ( finish_cred) ;
955+
956+ // Create dropin for default.target to enable execute services
957+ let execute_dropin =
958+ "[Unit]\n Wants=bootc-execute.service bootc-execute-finish.service\n " ;
959+ let encoded_dropin = data_encoding:: BASE64 . encode ( execute_dropin. as_bytes ( ) ) ;
960+ let dropin_cred = format ! (
961+ "io.systemd.credential.binary:systemd.unit-dropin.default.target~bcvk-execute={encoded_dropin}"
962+ ) ;
963+ mount_unit_smbios_creds. push ( dropin_cred) ;
964+ debug ! ( "Generated SMBIOS credentials for execute units" ) ;
973965 }
974966 }
975967
976- // Copy systemd units if provided (after mount units have been generated)
977- // Also inject if we created mount units that need to be copied
968+ // Copy systemd units if provided (for --systemd-units-dir option)
978969 inject_systemd_units ( ) ?;
979970
980971 // Prepare main virtiofsd config for the source image (will be spawned by QEMU)
@@ -1059,22 +1050,30 @@ StandardOutput=file:/dev/virtio-ports/executestatus
10591050 "swap" . into ( ) ,
10601051 crate :: to_disk:: Format :: Raw ,
10611052 ) ;
1062- let svc = format ! (
1063- r#"[Unit]
1053+
1054+ // Create swap unit via SMBIOS credential
1055+ let svc = r#"[Unit]
10641056Description=bcvk ephemeral swap
10651057
10661058[Swap]
10671059What=/dev/disk/by-id/virtio-swap
10681060Options=
1069- "#
1070- ) ;
1071-
1061+ "# ;
10721062 let service_name = r#"dev-disk-by\x2did-virtio\x2dswap.swap"# ;
1073- let service_path = format ! ( "{target_unitdir}/{service_name}" ) ;
1074- fs:: write ( & service_path, svc) ?;
1063+ let encoded_swap = data_encoding:: BASE64 . encode ( svc. as_bytes ( ) ) ;
1064+ let swap_cred = format ! (
1065+ "io.systemd.credential.binary:systemd.extra-unit.{service_name}={encoded_swap}"
1066+ ) ;
1067+ mount_unit_smbios_creds. push ( swap_cred) ;
10751068
1076- let wants_link = format ! ( "{default_wantsdir}/{service_name}" ) ;
1077- std:: os:: unix:: fs:: symlink ( format ! ( "../{service_name}" ) , wants_link) ?;
1069+ // Create dropin for default.target to enable swap
1070+ let swap_dropin = format ! ( "[Unit]\n Wants={service_name}\n " ) ;
1071+ let encoded_dropin = data_encoding:: BASE64 . encode ( swap_dropin. as_bytes ( ) ) ;
1072+ let dropin_cred = format ! (
1073+ "io.systemd.credential.binary:systemd.unit-dropin.default.target~bcvk-swap={encoded_dropin}"
1074+ ) ;
1075+ mount_unit_smbios_creds. push ( dropin_cred) ;
1076+ debug ! ( "Generated SMBIOS credential for swap unit" ) ;
10781077
10791078 tmp_swapfile = Some ( tmpf) ;
10801079 }
@@ -1204,6 +1203,13 @@ Options=
12041203 } ) ?;
12051204 } ;
12061205
1206+ // Add all SMBIOS credentials for mount units, journal, and execute services
1207+ let cred_count = mount_unit_smbios_creds. len ( ) ;
1208+ for cred in mount_unit_smbios_creds {
1209+ qemu_config. add_smbios_credential ( cred) ;
1210+ }
1211+ debug ! ( "Added {} SMBIOS credentials to QEMU config" , cred_count) ;
1212+
12071213 debug ! ( "Starting QEMU with systemd debugging enabled" ) ;
12081214
12091215 // Spawn QEMU with all virtiofsd processes handled internally
0 commit comments