The old code was fairly bogus. In the new code there is one "public"
function:
val get_kernel_version : bool -> string -> string option
which takes a full vmlinuz path and returns the kernel version from it
if possible (or None if not). This function first looks at the file
content to see if the version can be extracted, and if that fails
looks at the filename.
As a side effect of making this change, we also filter out kernels
from /boot where we cannot read the kernel version.
---
src/format_ext2_kernel.ml | 78 +++++++++++++++++++++++++++++++----------------
1 file changed, 51 insertions(+), 27 deletions(-)
diff --git a/src/format_ext2_kernel.ml b/src/format_ext2_kernel.ml
index 0bb67fe..55c5af9 100644
--- a/src/format_ext2_kernel.ml
+++ b/src/format_ext2_kernel.ml
@@ -79,7 +79,10 @@ and find_kernel_from_env_vars debug =
if debug >= 1 then
printf "supermin: kernel: SUPERMIN_KERNEL_VERSION=%s\n%!" v;
v
- with Not_found -> get_kernel_version_from_file kernel_env in
+ with Not_found ->
+ match get_kernel_version debug kernel_env with
+ | Some v -> v
+ | None -> raise Not_found in
let kernel_name = Filename.basename kernel_env in
let modpath = find_modpath debug kernel_version in
Some (kernel_env, kernel_name, kernel_version, modpath)
@@ -123,17 +126,17 @@ and find_kernel_from_boot debug host_cpu =
let files = List.sort (fun a b -> compare_version b a) files in
let kernels =
- List.map (
+ filter_map (
fun kernel_name ->
- let kernel_version = get_kernel_version kernel_name in
let kernel_file = "/boot" // kernel_name in
- let modpath = find_modpath debug kernel_version in
- (kernel_file, kernel_name, kernel_version, modpath)
+ match get_kernel_version debug kernel_file with
+ | None -> None
+ | Some kernel_version ->
+ let modpath = find_modpath debug kernel_version in
+ if not (has_modpath modpath) then None
+ else Some (kernel_file, kernel_name, kernel_version, modpath)
) files in
- let kernels =
- List.filter (fun (_, _, _, modpath) -> has_modpath modpath) kernels in
-
match kernels with
| kernel :: _ -> Some kernel
| [] -> None
@@ -187,24 +190,43 @@ and has_modpath modpath =
try (stat (modpath // "modules.dep")).st_kind = S_REG
with Unix_error _ -> false
-and get_kernel_version kernel_name =
- if (string_prefix "vmlinuz-" kernel_name) ||
- (string_prefix "vmlinux-" kernel_name) then (
- let kv = String.sub kernel_name 8 (String.length kernel_name - 8) in
- if modules_dep_exists kv then kv
- else get_kernel_version_from_name kernel_name
- ) else get_kernel_version_from_name kernel_name
-
-and modules_dep_exists kv =
- try (lstat ("/lib/modules/" ^ kv ^ "/modules.dep")).st_kind =
S_REG
- with Unix_error _ -> false
-
-and get_kernel_version_from_name kernel_name =
- get_kernel_version_from_file ("/boot" // kernel_name)
+(* Extract the kernel version from a Linux kernel file.
+ *
+ * This first sees if we can get the information from the file
+ * content (see below) and if that fails tries to parse the
+ * filename.
+ *)
+and get_kernel_version debug kernel_file =
+ if debug >= 1 then
+ printf "supermin: kernel: kernel version of %s%!" kernel_file;
+ match get_kernel_version_from_file_content kernel_file with
+ | Some version ->
+ if debug >= 1 then printf " = %s (from content)\n%!" version;
+ Some version
+ | None ->
+ (* Try to work it out from the filename instead. *)
+ let basename = Filename.basename kernel_file in
+ if string_prefix "vmlinuz-" basename || string_prefix "vmlinux-"
basename
+ then (
+ let version = String.sub basename 8 (String.length basename - 8) in
+ (* Does the version look reasonable? *)
+ let modpath = "/lib/modules" // version in
+ if has_modpath modpath then (
+ if debug >= 1 then printf " = %s (from filename)\n%!" version;
+ Some version
+ ) else (
+ if debug >= 1 then printf " = error, no modpath\n%!";
+ None
+ )
+ )
+ else (
+ if debug >= 1 then printf " = error, cannot parse filename\n%!";
+ None
+ )
(* Extract the kernel version from a Linux kernel file.
*
- * Returns a string containing the version or [Not_found] if the
+ * Returns a string containing the version or [None] if the
* file can't be read, is not a Linux kernel, or the version can't
* be found.
*
@@ -217,7 +239,7 @@ and get_kernel_version_from_name kernel_name =
*
* Bugs: probably limited to x86 kernels.
*)
-and get_kernel_version_from_file file =
+and get_kernel_version_from_file_content file =
try
let chan = open_in file in
let buf = read_string chan 514 4 in
@@ -247,10 +269,12 @@ and get_kernel_version_from_file file =
)
else raise Not_found
in
- loop 0
+ let version = loop 0 in
+ Some version
with
- | Sys_error _ -> raise Not_found
- | Invalid_argument _ -> raise Not_found
+ | Not_found
+ | Sys_error _
+ | Invalid_argument _ -> None
(* Read an unsigned little endian short at a specified offset in a file. *)
and read_leshort chan offset =
--
2.13.1