77use std:: path:: Path ;
88
99use anyhow:: Result ;
10+ use camino:: Utf8PathBuf ;
1011use cap_std_ext:: cap_std:: fs:: Dir ;
1112use cap_std_ext:: dirext:: CapStdExtDirExt ;
1213use serde:: Serialize ;
@@ -25,35 +26,67 @@ pub(crate) struct Kernel {
2526 pub ( crate ) unified : bool ,
2627}
2728
29+ /// Internal-only kernel wrapper with extra information (paths to
30+ /// vmlinuz, initramfs) that are useful but we don't want to leak out
31+ /// via serialization to inspection.
32+ ///
33+ /// `Kernel` implements `From<KernelInternal>` so we can just `.into()`
34+ /// to get the "public" form where needed.
35+ pub ( crate ) struct KernelInternal {
36+ pub ( crate ) kernel : Kernel ,
37+ /// Path to vmlinuz for traditional kernels.
38+ /// This is `None` for UKI images.
39+ pub ( crate ) vmlinuz : Option < Utf8PathBuf > ,
40+ /// Path to initramfs.img for traditional kernels.
41+ /// This is `None` for UKI images.
42+ pub ( crate ) initramfs : Option < Utf8PathBuf > ,
43+ }
44+
45+ impl From < KernelInternal > for Kernel {
46+ fn from ( kernel_internal : KernelInternal ) -> Self {
47+ kernel_internal. kernel
48+ }
49+ }
50+
2851/// Find the kernel in a container image root directory.
2952///
3053/// This function first attempts to find a UKI in `/boot/EFI/Linux/*.efi`.
3154/// If that doesn't exist, it falls back to looking for a traditional kernel
3255/// layout with `/usr/lib/modules/<version>/vmlinuz`.
3356///
3457/// Returns `None` if no kernel is found.
35- pub ( crate ) fn find_kernel ( root : & Dir ) -> Result < Option < Kernel > > {
58+ pub ( crate ) fn find_kernel ( root : & Dir ) -> Result < Option < KernelInternal > > {
3659 // First, try to find a UKI
3760 if let Some ( uki_filename) = find_uki_filename ( root) ? {
3861 let version = uki_filename
3962 . strip_suffix ( ".efi" )
4063 . unwrap_or ( & uki_filename)
4164 . to_owned ( ) ;
42- return Ok ( Some ( Kernel {
43- version,
44- unified : true ,
65+ return Ok ( Some ( KernelInternal {
66+ kernel : Kernel {
67+ version,
68+ unified : true ,
69+ } ,
70+ vmlinuz : None ,
71+ initramfs : None ,
4572 } ) ) ;
4673 }
4774
4875 // Fall back to checking for a traditional kernel via ostree_ext
49- if let Some ( kernel_dir ) = ostree_ext:: bootabletree:: find_kernel_dir_fs ( root) ? {
50- let version = kernel_dir
76+ if let Some ( modules_dir ) = ostree_ext:: bootabletree:: find_kernel_dir_fs ( root) ? {
77+ let version = modules_dir
5178 . file_name ( )
52- . ok_or_else ( || anyhow:: anyhow!( "kernel dir should have a file name: {kernel_dir }" ) ) ?
79+ . ok_or_else ( || anyhow:: anyhow!( "kernel dir should have a file name: {modules_dir }" ) ) ?
5380 . to_owned ( ) ;
54- return Ok ( Some ( Kernel {
55- version,
56- unified : false ,
81+ let vmlinuz = modules_dir. join ( "vmlinuz" ) ;
82+ let initramfs = modules_dir. join ( "initramfs.img" ) ;
83+ return Ok ( Some ( KernelInternal {
84+ kernel : Kernel {
85+ version,
86+ unified : false ,
87+ } ,
88+ vmlinuz : Some ( vmlinuz) ,
89+ initramfs : Some ( initramfs) ,
5790 } ) ) ;
5891 }
5992
@@ -93,6 +126,7 @@ fn find_uki_filename(root: &Dir) -> Result<Option<String>> {
93126#[ cfg( test) ]
94127mod tests {
95128 use super :: * ;
129+ use camino:: Utf8Path ;
96130 use cap_std_ext:: { cap_std, cap_tempfile, dirext:: CapStdExtDirExt } ;
97131
98132 #[ test]
@@ -111,9 +145,21 @@ mod tests {
111145 b"fake kernel" ,
112146 ) ?;
113147
114- let kernel = find_kernel ( & tempdir) ?. expect ( "should find kernel" ) ;
115- assert_eq ! ( kernel. version, "6.12.0-100.fc41.x86_64" ) ;
116- assert ! ( !kernel. unified) ;
148+ let kernel_internal = find_kernel ( & tempdir) ?. expect ( "should find kernel" ) ;
149+ assert_eq ! ( kernel_internal. kernel. version, "6.12.0-100.fc41.x86_64" ) ;
150+ assert ! ( !kernel_internal. kernel. unified) ;
151+ assert_eq ! (
152+ kernel_internal. vmlinuz. as_deref( ) ,
153+ Some ( Utf8Path :: new(
154+ "usr/lib/modules/6.12.0-100.fc41.x86_64/vmlinuz"
155+ ) )
156+ ) ;
157+ assert_eq ! (
158+ kernel_internal. initramfs. as_deref( ) ,
159+ Some ( Utf8Path :: new(
160+ "usr/lib/modules/6.12.0-100.fc41.x86_64/initramfs.img"
161+ ) )
162+ ) ;
117163 Ok ( ( ) )
118164 }
119165
@@ -123,9 +169,11 @@ mod tests {
123169 tempdir. create_dir_all ( "boot/EFI/Linux" ) ?;
124170 tempdir. atomic_write ( "boot/EFI/Linux/fedora-6.12.0.efi" , b"fake uki" ) ?;
125171
126- let kernel = find_kernel ( & tempdir) ?. expect ( "should find kernel" ) ;
127- assert_eq ! ( kernel. version, "fedora-6.12.0" ) ;
128- assert ! ( kernel. unified) ;
172+ let kernel_internal = find_kernel ( & tempdir) ?. expect ( "should find kernel" ) ;
173+ assert_eq ! ( kernel_internal. kernel. version, "fedora-6.12.0" ) ;
174+ assert ! ( kernel_internal. kernel. unified) ;
175+ assert ! ( kernel_internal. vmlinuz. is_none( ) ) ;
176+ assert ! ( kernel_internal. initramfs. is_none( ) ) ;
129177 Ok ( ( ) )
130178 }
131179
@@ -141,10 +189,10 @@ mod tests {
141189 tempdir. create_dir_all ( "boot/EFI/Linux" ) ?;
142190 tempdir. atomic_write ( "boot/EFI/Linux/fedora-6.12.0.efi" , b"fake uki" ) ?;
143191
144- let kernel = find_kernel ( & tempdir) ?. expect ( "should find kernel" ) ;
192+ let kernel_internal = find_kernel ( & tempdir) ?. expect ( "should find kernel" ) ;
145193 // UKI should take precedence
146- assert_eq ! ( kernel. version, "fedora-6.12.0" ) ;
147- assert ! ( kernel. unified) ;
194+ assert_eq ! ( kernel_internal . kernel. version, "fedora-6.12.0" ) ;
195+ assert ! ( kernel_internal . kernel. unified) ;
148196 Ok ( ( ) )
149197 }
150198
0 commit comments