@@ -12,6 +12,7 @@ use fn_error_context::context;
1212use bootc_mount as mount;
1313
1414use crate :: bootc_composefs:: boot:: { MountedImageRoot , SecurebootKeys } ;
15+ use crate :: spec:: Bootloader ;
1516use crate :: utils;
1617
1718/// The name of the mountpoint for efi (as a subdirectory of /boot, or at the toplevel)
@@ -95,13 +96,11 @@ pub(crate) fn supports_bootupd(root: &Dir) -> Result<bool> {
9596 Ok ( r)
9697}
9798
98- /// Check whether the target bootupd supports `--filesystem`.
99- ///
100- /// Runs `bootupctl backend install --help` and looks for `--filesystem` in the
101- /// output. When `deployment_path` is set the command runs inside a chroot
102- /// (via [`ChrootCmd`]) so we probe the binary from the target image.
103- fn bootupd_supports_filesystem ( rootfs : & Utf8Path , deployment_path : Option < & str > ) -> Result < bool > {
99+ fn bootupd_install_help ( rootfs : & Utf8Path , deployment_path : Option < & str > ) -> Result < String > {
100+ static STATUS : std:: sync:: OnceLock < String > = std:: sync:: OnceLock :: new ( ) ;
101+
104102 let help_args = [ "bootupctl" , "backend" , "install" , "--help" ] ;
103+
105104 let output = if let Some ( deploy) = deployment_path {
106105 let target_root = rootfs. join ( deploy) ;
107106 ChrootCmd :: new ( & target_root)
@@ -114,6 +113,17 @@ fn bootupd_supports_filesystem(rootfs: &Utf8Path, deployment_path: Option<&str>)
114113 . run_get_string ( ) ?
115114 } ;
116115
116+ Ok ( STATUS . get_or_init ( || output) . to_string ( ) )
117+ }
118+
119+ /// Check whether the target bootupd supports `--filesystem`.
120+ ///
121+ /// Runs `bootupctl backend install --help` and looks for `--filesystem` in the
122+ /// output. When `deployment_path` is set the command runs inside a chroot
123+ /// (via [`ChrootCmd`]) so we probe the binary from the target image.
124+ fn bootupd_supports_filesystem ( rootfs : & Utf8Path , deployment_path : Option < & str > ) -> Result < bool > {
125+ let output = bootupd_install_help ( rootfs, deployment_path) ?;
126+
117127 let use_filesystem = output. contains ( "--filesystem" ) ;
118128
119129 if use_filesystem {
@@ -125,6 +135,24 @@ fn bootupd_supports_filesystem(rootfs: &Utf8Path, deployment_path: Option<&str>)
125135 Ok ( use_filesystem)
126136}
127137
138+ /// Check whether the target bootupd supports `--bootloader` for installs
139+ pub ( crate ) fn bootupd_supports_bootloader_flag (
140+ rootfs : & Utf8Path ,
141+ deployment_path : Option < & str > ,
142+ ) -> Result < bool > {
143+ let output = bootupd_install_help ( rootfs, deployment_path) ?;
144+
145+ let supports_bootloader = output. contains ( "--bootloader" ) ;
146+
147+ if supports_bootloader {
148+ tracing:: debug!( "bootupd supports --bootloader" ) ;
149+ } else {
150+ tracing:: debug!( "bootupd does not support --bootloader" ) ;
151+ }
152+
153+ Ok ( supports_bootloader)
154+ }
155+
128156/// Install the bootloader via bootupd.
129157///
130158/// When the target bootupd supports `--filesystem` we pass it pointing at a
@@ -140,10 +168,12 @@ pub(crate) fn install_via_bootupd(
140168 rootfs : & Utf8Path ,
141169 configopts : & crate :: install:: InstallConfigOpts ,
142170 deployment_path : Option < & str > ,
171+ bootloader : Option < Bootloader > ,
143172) -> Result < ( ) > {
144173 let verbose = std:: env:: var_os ( "BOOTC_BOOTLOADER_DEBUG" ) . map ( |_| "-vvvv" ) ;
145174 // bootc defaults to only targeting the platform boot method.
146- let bootupd_opts = ( !configopts. generic_image ) . then_some ( [ "--update-firmware" , "--auto" ] ) ;
175+ let bootupd_opts = ( !configopts. generic_image )
176+ . then_some ( [ "--update-firmware" , "--auto" ] . map ( |x| x. to_string ( ) ) ) ;
147177
148178 // When not running inside the target container (through `--src-imgref`) we
149179 // run bootupctl from the deployment via a chroot ([`ChrootCmd`]).
@@ -159,20 +189,25 @@ pub(crate) fn install_via_bootupd(
159189 println ! ( "Installing bootloader via bootupd" ) ;
160190
161191 // Build the bootupctl arguments
162- let mut bootupd_args: Vec < & str > = vec ! [ "backend" , "install" ] ;
192+ let mut bootupd_args: Vec < String > = vec ! [ "backend" . into ( ) , "install" . into ( ) ] ;
163193 if configopts. bootupd_skip_boot_uuid {
164- bootupd_args. push ( "--with-static-configs" )
194+ bootupd_args. push ( "--with-static-configs" . into ( ) )
165195 } else {
166- bootupd_args. push ( "--write-uuid" ) ;
196+ bootupd_args. push ( "--write-uuid" . into ( ) ) ;
167197 }
168198 if let Some ( v) = verbose {
169- bootupd_args. push ( v) ;
199+ bootupd_args. push ( v. into ( ) ) ;
170200 }
171201
172- if let Some ( ref opts) = bootupd_opts {
173- bootupd_args. extend ( opts. iter ( ) . copied ( ) ) ;
202+ if let Some ( opts) = bootupd_opts {
203+ bootupd_args. extend ( opts) ;
174204 }
175205
206+ if let Some ( b) = bootloader {
207+ bootupd_args. push ( "--bootloader" . into ( ) ) ;
208+ bootupd_args. push ( b. to_string ( ) ) ;
209+ } ;
210+
176211 // When the target bootupd lacks --filesystem support, fall back to the
177212 // legacy --device flag. For --device we need the whole-disk device path
178213 // (e.g. /dev/vda), not a partition (e.g. /dev/vda3), so resolve the
@@ -188,12 +223,12 @@ pub(crate) fn install_via_bootupd(
188223 } ;
189224 if let Some ( ref dev) = root_device_path {
190225 tracing:: debug!( "bootupd does not support --filesystem, falling back to --device {dev}" ) ;
191- bootupd_args. extend ( [ "--device" , dev] ) ;
192- bootupd_args. push ( rootfs_mount) ;
226+ bootupd_args. extend ( [ "--device" . into ( ) , dev. into ( ) ] ) ;
227+ bootupd_args. push ( rootfs_mount. into ( ) ) ;
193228 } else {
194229 tracing:: debug!( "bootupd supports --filesystem" ) ;
195- bootupd_args. extend ( [ "--filesystem" , rootfs_mount] ) ;
196- bootupd_args. push ( rootfs_mount) ;
230+ bootupd_args. extend ( [ "--filesystem" . into ( ) , rootfs_mount. into ( ) ] ) ;
231+ bootupd_args. push ( rootfs_mount. into ( ) ) ;
197232 }
198233
199234 // Run inside a chroot ([`ChrootCmd`]). It sets up a fresh mount
@@ -209,7 +244,7 @@ pub(crate) fn install_via_bootupd(
209244
210245 // Prepend "bootupctl" to the args (ChrootCmd's calling
211246 // convention puts the program in args[0]).
212- let mut chroot_args = vec ! [ "bootupctl" ] ;
247+ let mut chroot_args = vec ! [ "bootupctl" . to_string ( ) ] ;
213248 chroot_args. extend ( bootupd_args) ;
214249
215250 let mut cmd = ChrootCmd :: new ( & target_root)
0 commit comments