New API: inspect-get-windows-current-control-set
authorRichard W.M. Jones <rjones@redhat.com>
Tue, 5 Apr 2011 11:44:34 +0000 (12:44 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Tue, 5 Apr 2011 19:01:15 +0000 (20:01 +0100)
This returns the actual registry key corresponding to
CurrentControlSet (eg. it might be "ControlSet001").

Previously the inspection code was hard-coding ControlSet001.  Now we
use the correct control set, and also make it available to callers
through the API.

This commit also updates the virt-dhcp-address example so it uses this
new API.

virt-inspector displays the current control set when available.

examples/virt-dhcp-address.c
generator/generator_actions.ml
images/guest-aux/windows-system.reg
inspector/example-windows.xml
inspector/virt-inspector.c
inspector/virt-inspector.rng
src/guestfs-internal.h
src/inspect.c

index c075a47..5b68313 100644 (file)
@@ -189,7 +189,7 @@ print_dhcp_address_linux (guestfs_h *g, char *root, const char *logfile)
 
 /* Download the Windows SYSTEM hive and find DHCP configuration in there. */
 static void
-print_dhcp_address_windows (guestfs_h *g, char *root_unused)
+print_dhcp_address_windows (guestfs_h *g, char *root_fs)
 {
   char *system_path;
   char tmpfile[] = "/tmp/systemXXXXXX";
@@ -197,8 +197,7 @@ print_dhcp_address_windows (guestfs_h *g, char *root_unused)
   hive_h *h;
   hive_node_h root, node, *nodes;
   hive_value_h value;
-  int32_t dword;
-  char controlset[] = "ControlSetXXX";
+  char *controlset;
   size_t i;
   char *p;
 
@@ -222,6 +221,10 @@ print_dhcp_address_windows (guestfs_h *g, char *root_unused)
 
   free (system_path);
 
+  controlset = guestfs_inspect_get_windows_current_control_set (g, root_fs);
+  if (controlset == NULL)
+    exit (EXIT_FAILURE);
+
   /* Open the hive to parse it. */
   h = hivex_open (tmpfile, 0);
   err = errno;
@@ -234,31 +237,11 @@ print_dhcp_address_windows (guestfs_h *g, char *root_unused)
     exit (EXIT_FAILURE);
   }
 
-  /* Navigate to the Select key so we know which ControlSet is in use. */
   root = hivex_root (h);
   if (root == 0) {
     perror ("hivex_root");
     exit (EXIT_FAILURE);
   }
-  node = hivex_node_get_child (h, root, "Select");
-  if (node == 0) {
-    if (errno != 0)
-      perror ("hivex_node_get_child");
-    else
-      fprintf (stderr, "virt-dhcp-address: HKLM\\System\\Select key not found.");
-    exit (EXIT_FAILURE);
-  }
-  value = hivex_node_get_value (h, node, "Current");
-  if (value == 0) {
-    if (errno != 0)
-      perror ("hivex_node_get_value");
-    else
-      fprintf (stderr, "virt-dhcp-address: HKLM\\System\\Select Default entry not found.");
-    exit (EXIT_FAILURE);
-  }
-  /* XXX Should check the type. */
-  dword = hivex_value_dword (h, value);
-  snprintf (controlset, sizeof controlset, "ControlSet%03d", dword);
 
   /* Get ControlSetXXX\Services\Tcpip\Parameters\Interfaces. */
   const char *path[] = { controlset, "Services", "Tcpip", "Parameters",
@@ -311,6 +294,8 @@ print_dhcp_address_windows (guestfs_h *g, char *root_unused)
 
   /* Close the hive handle. */
   hivex_close (h);
+
+  free (controlset);
 }
 
 static int
index a10b7f7..c59964a 100644 (file)
@@ -1451,6 +1451,22 @@ Please read L<guestfs(3)/INSPECTION> for more details.
 See also C<guestfs_inspect_get_product_name>,
 C<guestfs_inspect_get_major_version>.");
 
+  ("inspect_get_windows_current_control_set", (RString "controlset", [Device "root"], []), -1, [],
+   [],
+   "get Windows CurrentControlSet of inspected operating system",
+   "\
+This function should only be called with a root device string
+as returned by C<guestfs_inspect_os>.
+
+This returns the Windows CurrentControlSet of the inspected guest.
+The CurrentControlSet is a registry key name such as C<ControlSet001>.
+
+This call assumes that the guest is Windows and that the
+Registry could be examined by inspection.  If this is not
+the case then an error is returned.
+
+Please read L<guestfs(3)/INSPECTION> for more details.");
+
 ]
 
 (* daemon_functions are any functions which cause some action
index 87ae779..6cb5d32 100644 (file)
@@ -1,3 +1,9 @@
+[HKEY_LOCAL_MACHINE\SYSTEM\Select]
+"Current"=dword:00000001
+"Default"=dword:00000001
+"Failed"=dword:00000000
+"LastKnownGood"=dword:00000002
+
 [HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001]
 
 [HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services]
index 7b3ae74..8e53159 100644 (file)
@@ -10,6 +10,7 @@
     <major_version>6</major_version>
     <minor_version>1</minor_version>
     <windows_systemroot>/Windows</windows_systemroot>
+    <windows_current_control_set>ControlSet001</windows_current_control_set>
     <format>installed</format>
     <mountpoints>
       <mountpoint dev="/dev/sda2">/</mountpoint>
index 4d8e3ad..d016b2d 100644 (file)
@@ -416,6 +416,14 @@ output_root (xmlTextWriterPtr xo, char *root)
                                            BAD_CAST str));
     free (str);
   );
+  DISABLE_GUESTFS_ERRORS_FOR (
+    str = guestfs_inspect_get_windows_current_control_set (g, root);
+    if (str)
+      XMLERROR (-1,
+                xmlTextWriterWriteElement (xo, BAD_CAST "windows_current_control_set",
+                                           BAD_CAST str));
+    free (str);
+  );
 
   str = guestfs_inspect_get_format (g, root);
   if (!str) exit (EXIT_FAILURE);
index 8d54fac..7a822e6 100644 (file)
@@ -37,7 +37,7 @@
             <element name="major_version"><text/></element>
             <element name="minor_version"><text/></element>
             <optional><element name="windows_systemroot"><text/></element></optional>
-
+            <optional><element name="windows_current_control_set"><text/></element></optional>
             <optional><element name="package_format"><text/></element></optional>
             <optional><element name="package_management"><text/></element></optional>
             <optional><element name="format"><text/></element></optional>
index 3a63f2e..b29fa57 100644 (file)
@@ -251,6 +251,7 @@ struct inspect_fs {
   char *arch;
   char *hostname;
   char *windows_systemroot;
+  char *windows_current_control_set;
   enum inspect_os_format format;
   int is_live_disk;
   int is_netinst_disk;
index a4f0f98..154207b 100644 (file)
@@ -25,6 +25,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <sys/stat.h>
+#include <errno.h>
 
 #ifdef HAVE_PCRE
 #include <pcre.h>
@@ -1612,7 +1613,10 @@ check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs)
 
   int ret = -1;
   hive_h *h = NULL;
-  hive_value_h *values = NULL;
+  hive_node_h root, node;
+  hive_value_h value, *values = NULL;
+  int32_t dword;
+  size_t i;
 
   if (download_to_tmp (g, system_path, system_local, MAX_REGISTRY_SIZE) == -1)
     goto out;
@@ -1623,21 +1627,49 @@ check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs)
     goto out;
   }
 
-  hive_node_h node = hivex_root (h);
-  /* XXX Don't hard-code ControlSet001.  The current control set would
-   * be another good thing to expose up through the inspection API.
-   */
+  root = hivex_root (h);
+  if (root == 0) {
+    perrorf (g, "hivex_root");
+    goto out;
+  }
+
+  /* Get the CurrentControlSet. */
+  errno = 0;
+  node = hivex_node_get_child (h, root, "Select");
+  if (node == 0) {
+    if (errno != 0)
+      perrorf (g, "hivex_node_get_child");
+    else
+      error (g, "hivex: could not locate HKLM\\SYSTEM\\Select");
+    goto out;
+  }
+
+  errno = 0;
+  value = hivex_node_get_value (h, node, "Current");
+  if (value == 0) {
+    if (errno != 0)
+      perrorf (g, "hivex_node_get_value");
+    else
+      error (g, "hivex: HKLM\\System\\Select Default entry not found.");
+    goto out;
+  }
+
+  /* XXX Should check the type. */
+  dword = hivex_value_dword (h, value);
+  fs->windows_current_control_set = safe_asprintf (g, "ControlSet%03d", dword);
+
+  /* Get the hostname. */
   const char *hivepath[] =
-    { "ControlSet001", "Services", "Tcpip", "Parameters" };
-  size_t i;
-  for (i = 0;
+    { fs->windows_current_control_set, "Services", "Tcpip", "Parameters" };
+  for (node = root, i = 0;
        node != 0 && i < sizeof hivepath / sizeof hivepath[0];
        ++i) {
     node = hivex_node_get_child (h, node, hivepath[i]);
   }
 
   if (node == 0) {
-    perrorf (g, "hivex: cannot locate HKLM\\SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters");
+    perrorf (g, "hivex: cannot locate HKLM\\SYSTEM\\%s\\Services\\Tcpip\\Parameters",
+             fs->windows_current_control_set);
     goto out;
   }
 
@@ -2011,6 +2043,22 @@ guestfs__inspect_get_windows_systemroot (guestfs_h *g, const char *root)
 }
 
 char *
+guestfs__inspect_get_windows_current_control_set (guestfs_h *g,
+                                                  const char *root)
+{
+  struct inspect_fs *fs = search_for_root (g, root);
+  if (!fs)
+    return NULL;
+
+  if (!fs->windows_current_control_set) {
+    error (g, _("not a Windows guest, or CurrentControlSet could not be determined"));
+    return NULL;
+  }
+
+  return safe_strdup (g, fs->windows_current_control_set);
+}
+
+char *
 guestfs__inspect_get_format (guestfs_h *g, const char *root)
 {
   struct inspect_fs *fs = search_for_root (g, root);
@@ -2905,6 +2953,13 @@ guestfs__inspect_get_windows_systemroot (guestfs_h *g, const char *root)
   NOT_IMPL(NULL);
 }
 
+char *
+guestfs__inspect_get_windows_current_control_set (guestfs_h *g,
+                                                  const char *root)
+{
+  NOT_IMPL(NULL);
+}
+
 char **
 guestfs__inspect_get_mountpoints (guestfs_h *g, const char *root)
 {
@@ -2978,6 +3033,7 @@ guestfs___free_inspect_info (guestfs_h *g)
     free (g->fses[i].arch);
     free (g->fses[i].hostname);
     free (g->fses[i].windows_systemroot);
+    free (g->fses[i].windows_current_control_set);
     size_t j;
     for (j = 0; j < g->fses[i].nr_fstab; ++j) {
       free (g->fses[i].fstab[j].device);