Bring kernel version checking (utsname) into the central process.
[virt-mem.git] / lib / virt_mem_utsname.ml
diff --git a/lib/virt_mem_utsname.ml b/lib/virt_mem_utsname.ml
new file mode 100644 (file)
index 0000000..61a2b37
--- /dev/null
@@ -0,0 +1,93 @@
+(* Memory info command for virtual domains.
+   (C) Copyright 2008 Richard W.M. Jones, Red Hat Inc.
+   http://libvirt.org/
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *)
+
+open Printf
+
+open Virt_mem_gettext.Gettext
+open Virt_mem_utils
+open Virt_mem_types
+open Virt_mem_mmap
+
+(* Truncate an OCaml string at the first ASCII NUL character, ie. as
+ * if it were a C string.
+ *)
+let truncate str =
+  try
+    let i = String.index str '\000' in
+    String.sub str 0 i
+  with
+    Not_found -> str
+
+let parse_utsname bits =
+  (* Expect the first (sysname) field to always be "Linux", which is
+   * also a good way to tell if we're synchronized to the right bit of
+   * memory.
+   *)
+  bitmatch bits with
+  | { "Linux\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" : 65*8 : string;
+      nodename : 65*8 : string;
+      release : 65*8 : string;
+      version : 65*8 : string;
+      machine : 65*8 : string;
+      domainname : 65*8 : string } ->
+      Some {
+       kernel_name = "Linux";
+       nodename = truncate nodename;
+       kernel_release = truncate release;
+       kernel_version = truncate version;
+       machine = truncate machine;
+       domainname = truncate domainname
+      }
+  | { _ } ->
+      None
+
+let find_utsname debug (domid, name, arch, mem, lookup_ksym) =
+  let utsname =
+    (* In Linux 2.6.25, the symbol is init_uts_ns.
+     * http://lxr.linux.no/linux/init/version.c
+     *)
+    try
+      let addr = lookup_ksym "init_uts_ns" in
+
+      let bs = Bitstring.bitstring_of_string (get_bytes mem addr (65*6+4)) in
+      (bitmatch bs with
+       | { _ : 32 : int;             (* the kref, atomic_t, always 32 bits *)
+          new_utsname : -1 : bitstring } ->
+          parse_utsname new_utsname
+       | { _ } ->
+          if debug then
+            eprintf (f_"%s: unexpected init_uts_ns in kernel image\n") name;
+          None
+      )
+    with
+      Not_found ->
+       (* In Linux 2.6.9, the symbol is system_utsname.
+        * http://lxr.linux.no/linux-bk+v2.6.9/include/linux/utsname.h#L24
+        *)
+       try
+         let addr = lookup_ksym "system_utsname" in
+
+         let bits =
+           Bitstring.bitstring_of_string (get_bytes mem addr (65*6)) in
+         parse_utsname bits
+           with
+             Not_found ->
+               eprintf (f_"%s: could not find utsname in kernel image\n") name
+  in
+  (domid, name, arch, mem, lookup_ksym, utsname)