From c859939113b939b5ad4237e8f4835cd33290357f Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 3 Aug 2017 13:06:41 +0100 Subject: [PATCH] kernel: Replace how kernel version information is found. 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 =