From 9e7c6a548353bde925c16434711bcc6208038d83 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 5 Apr 2011 12:44:34 +0100 Subject: [PATCH] New API: inspect-get-windows-current-control-set 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 | 31 ++++------------ generator/generator_actions.ml | 16 ++++++++ images/guest-aux/windows-system.reg | 6 +++ inspector/example-windows.xml | 1 + inspector/virt-inspector.c | 8 ++++ inspector/virt-inspector.rng | 2 +- src/guestfs-internal.h | 1 + src/inspect.c | 74 ++++++++++++++++++++++++++++++++----- 8 files changed, 106 insertions(+), 33 deletions(-) diff --git a/examples/virt-dhcp-address.c b/examples/virt-dhcp-address.c index c075a47..5b68313 100644 --- a/examples/virt-dhcp-address.c +++ b/examples/virt-dhcp-address.c @@ -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 diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml index a10b7f7..c59964a 100644 --- a/generator/generator_actions.ml +++ b/generator/generator_actions.ml @@ -1451,6 +1451,22 @@ Please read L for more details. See also C, C."); + ("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. + +This returns the Windows CurrentControlSet of the inspected guest. +The CurrentControlSet is a registry key name such as C. + +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 for more details."); + ] (* daemon_functions are any functions which cause some action diff --git a/images/guest-aux/windows-system.reg b/images/guest-aux/windows-system.reg index 87ae779..6cb5d32 100644 --- a/images/guest-aux/windows-system.reg +++ b/images/guest-aux/windows-system.reg @@ -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] diff --git a/inspector/example-windows.xml b/inspector/example-windows.xml index 7b3ae74..8e53159 100644 --- a/inspector/example-windows.xml +++ b/inspector/example-windows.xml @@ -10,6 +10,7 @@ 6 1 /Windows + ControlSet001 installed / diff --git a/inspector/virt-inspector.c b/inspector/virt-inspector.c index 4d8e3ad..d016b2d 100644 --- a/inspector/virt-inspector.c +++ b/inspector/virt-inspector.c @@ -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); diff --git a/inspector/virt-inspector.rng b/inspector/virt-inspector.rng index 8d54fac..7a822e6 100644 --- a/inspector/virt-inspector.rng +++ b/inspector/virt-inspector.rng @@ -37,7 +37,7 @@ - + diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h index 3a63f2e..b29fa57 100644 --- a/src/guestfs-internal.h +++ b/src/guestfs-internal.h @@ -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; diff --git a/src/inspect.c b/src/inspect.c index a4f0f98..154207b 100644 --- a/src/inspect.c +++ b/src/inspect.c @@ -25,6 +25,7 @@ #include #include #include +#include #ifdef HAVE_PCRE #include @@ -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); -- 1.8.3.1