The current detection code for Linux kernels assumes that a kernel
package contains everything in it, i.e. the kernel itself, its modules,
and its configuration. However, since recent Ubuntu versions (e.g.
starting from 18.04) modules & config (with few more files) are split in
an own package, thus not detecting the modpath from installed vmlinuz
files.
To overcome this situation, rework this detection a bit:
1) find the vmlinuz file as before, but then immediately make sure it
exists by stat'ing it
2) find the modules path from the package as before:
2a) if found, extract the version in the same step
2b) if not found, get the kernel version from the vmlinuz filename,
and use it to detect the modules path
3) check that the modules path exists
The detection done in (2b) is based on the current packaging scheme
found in the most important Linux distributions (Fedora, RHEL, CentOS,
Debian, Ubuntu, openSUSE, AltLinux, and possibly more). The notable
exception is Arch Linux.
As additional change, do not assume the config file is in the same
package as vmlinuz, but directly look into the filesystem using the
version we already have.
---
v2v/linux_kernels.ml | 47 +++++++++++++++++++++++++++++---------------
1 file changed, 31 insertions(+), 16 deletions(-)
diff --git a/v2v/linux_kernels.ml b/v2v/linux_kernels.ml
index c047d6deb..24f61429d 100644
--- a/v2v/linux_kernels.ml
+++ b/v2v/linux_kernels.ml
@@ -103,27 +103,42 @@ let detect_kernels (g : G.guestfs) inspect family bootloader =
None
)
else (
- (* Which of these is the kernel itself? *)
+ (* Which of these is the kernel itself? Also, make sure to check
+ * it exists by stat'ing it.
+ *)
let vmlinuz = List.find (
fun filename -> String.is_prefix filename "/boot/vmlinuz-"
) files in
- (* Which of these is the modpath? *)
- let modpath = List.find (
- fun filename ->
- String.length filename >= 14 &&
- String.is_prefix filename "/lib/modules/"
- ) files in
-
- (* Check vmlinuz & modpath exist. *)
- if not (g#is_dir ~followsymlinks:true modpath) then
- raise Not_found;
let vmlinuz_stat =
try g#statns vmlinuz with G.Error _ -> raise Not_found in
- (* Get/construct the version. XXX Read this from kernel file. *)
- let version =
- let prefix_len = String.length "/lib/modules/" in
- String.sub modpath prefix_len (String.length modpath - prefix_len) in
+ (* Determine the modpath from the package, falling back to the
+ * version in the vmlinuz file name.
+ *)
+ let modpath, version =
+ let prefix = "/lib/modules/" in
+ try
+ let prefix_len = String.length prefix in
+ List.find_map (
+ fun filename ->
+ let filename_len = String.length filename in
+ if filename_len > prefix_len &&
+ String.is_prefix filename prefix then (
+ let version = String.sub filename prefix_len
+ (filename_len - prefix_len) in
+ Some (filename, version)
+ ) else
+ None
+ ) files
+ with Not_found ->
+ let version =
+ String.sub vmlinuz 14 (String.length vmlinuz - 14) in
+ let modpath = prefix ^ version in
+ modpath, version in
+
+ (* Check that the modpath exists. *)
+ if not (g#is_dir ~followsymlinks:true modpath) then
+ raise Not_found;
(* Find the initramfs which corresponds to the kernel.
* Since the initramfs is built at runtime, and doesn't have
@@ -188,7 +203,7 @@ let detect_kernels (g : G.guestfs) inspect family bootloader =
let config_file =
let cfg = "/boot/config-" ^ version in
- if List.mem cfg files then Some cfg
+ if g#is_file ~followsymlinks:true cfg then Some cfg
else None in
let kernel_supports what kconf =
--
2.17.0