[Libguestfs] [PATCH v2 2/2] v2v:windows: prevent conflicts with PnP on firstboot
Richard W.M. Jones
rjones at redhat.com
Thu Sep 1 08:54:29 UTC 2016
On Thu, Sep 01, 2016 at 11:50:19AM +0300, Roman Kagan wrote:
> When put on new virtual hardware Windows will start driver installation
> for newly discovered devices.
>
> The problem is that it happens asynchronously and concurrently with
> other activities, in particular, the firstboot scripts. This may result
> in conflicts (because a firstboot script may want to install or
> uninstall a driver, etc.) and eventually in the system left in
> inconsistent state.
>
> In order to prevent it, add another firstboot script which calls a
> special utility, pnp_wait, whose sole purpose is to wait until all
> PnP-related activities are finished. (It does so via a WinAPI call
> which isn't available from a script so it has to be a compiled .exe.
> The source code for it can be found in the corresponding directory in
> https://github.com/rwmjones/rhsrvany). This firstboot script is put
> first, so that other firstboot scripts do not have to worry about
> interactions with PnP manager any more.
>
> One caveat is that on Windows XP and Windows 2003 the PnP manager always
> fires the "Found New Hardware" wizard, which doesn't allow PnP to make
> any progress until the user closes it. As a result, this firstboot
> script would never finish.
>
> To work it around, follow the Microsoft KB
> (https://support.microsoft.com/en-us/kb/938596) and set up a registry
> key to make the the PnP manager not fire the wizard; the key is restored
> to its initial state upon PnP completion. Unfortunately this only works
> on systems having the mentioned update installed; otherwise the user
> will have to interact with the UI.
>
> Signed-off-by: Roman Kagan <rkagan at virtuozzo.com>
> ---
> v2v/convert_windows.ml | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 92 insertions(+)
>
> diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml
> index 02c7a47..bd1bc53 100644
> --- a/v2v/convert_windows.ml
> +++ b/v2v/convert_windows.ml
> @@ -43,6 +43,18 @@ let convert ~keep_serial_console (g : G.guestfs) inspect source rcaps =
> try Sys.getenv "VIRT_TOOLS_DATA_DIR"
> with Not_found -> Guestfs_config.datadir // "virt-tools" in
>
> + let pnp_wait_exe = virt_tools_data_dir // "pnp_wait.exe" in
> + let pnp_wait_exe =
> + try
> + let chan = open_in pnp_wait_exe in
> + close_in chan;
> + Some pnp_wait_exe
> + with
> + Sys_error msg ->
> + warning (f_"'%s' is missing. Firstboot scripts may conflict with PnP. Original error: %s")
> + pnp_wait_exe msg;
> + None in
> +
> (* Check if either RHEV-APT or VMDP exists. This is optional. *)
> let tools = [`RhevApt, "rhev-apt.exe"; `VmdpExe, "vmdp.exe"] in
> let installer =
> @@ -218,6 +230,7 @@ let convert ~keep_serial_console (g : G.guestfs) inspect source rcaps =
> sprintf "ControlSet%03Ld" value in
>
> let rec configure_firstboot () =
> + wait_pnp ();
> (match installer with
> | None -> ()
> | Some (`RhevApt, tool_path) -> configure_rhev_apt tool_path
> @@ -226,6 +239,85 @@ let convert ~keep_serial_console (g : G.guestfs) inspect source rcaps =
> unconfigure_xenpv ();
> unconfigure_prltools ()
>
> + and set_reg_val_dword_1 root key_path name =
> + (* set reg value to REG_DWORD 1, creating intermediate keys if needed *)
> + let node =
> + let rec loop parent = function
> + | [] -> parent
> + | x :: xs ->
> + let node =
> + match g#hivex_node_get_child parent x with
> + | 0L -> g#hivex_node_add_child parent x (* not found, create *)
> + | node -> node in
> + loop node xs
> + in
> + loop root key_path in
> + let valueh = g#hivex_node_get_value node name in
> + let value =
> + match valueh with
> + | 0L -> None
> + | _ -> Some (int_of_le32 (g#hivex_value_value valueh)) in
> + g#hivex_node_set_value node name 4_L (le32_of_int 1_L);
> + value
> +
> + and reg_restore key name value =
> + let strkey = String.concat "\\" key in
> + match value with
> + | Some value -> sprintf "\
> +reg add \"%s\" /v %s /t REG_DWORD /d %Ld /f" strkey name value
> + | None -> sprintf "\
> +reg delete \"%s\" /v %s /f" strkey name
> +
> + and wait_pnp () =
> + (* prevent destructive interactions of firstboot with PnP *)
> + match pnp_wait_exe with
> + | None -> ()
> + | Some pnp_wait_exe ->
> + let pnp_wait_path = [""; "Program Files"; "Guestfs"; "Firstboot";
> + "pnp_wait.exe"] in
> + (* suppress "New Hardware Wizard" until PnP settles (see
> + * https://support.microsoft.com/en-us/kb/938596) and restore it
> + * afterwards *)
> + let reg_restore_str =
> + match inspect.i_major_version, inspect.i_minor_version with
> + (* WinXP 32bit *)
> + | 5, 1 ->
> + let key_path = ["Policies"; "Microsoft"; "Windows"; "DeviceInstall";
> + "Settings"] in
> + let name = "SuppressNewHWUI" in
> + let value = Windows.with_hive_write g software_hive_filename (
> + fun root ->
> + set_reg_val_dword_1 root key_path name
> + ) in
> + reg_restore ("HKLM\\Software" :: key_path) name value
> +
> + (* WinXP 64bit / Win2k3 *)
> + | 5, 2 ->
> + let key_path = ["Services"; "PlugPlay"; "Parameters"] in
> + let name = "SuppressUI" in
> + let value = Windows.with_hive_write g system_hive_filename (
> + fun root ->
> + let current_cs = get_current_cs root in
> + set_reg_val_dword_1 root (current_cs :: key_path) name
> + ) in
> + reg_restore ("HKLM\\SYSTEM\\CurrentControlSet" :: key_path) name
> + value
> +
> + (* any later Windows *)
> + | _ -> "" in
> +
> + let fb_script = sprintf "\
> + at echo off
> +
> +echo Wait for PnP to complete
> +\"%s\" >\"%%~dpn0.log\" 2>&1
> +%s" (String.concat "\\" pnp_wait_path) reg_restore_str in
> +
> + Firstboot.add_firstboot_script g inspect.i_root "wait pnp" fb_script;
> + (* add_firstboot_script has created the path already *)
> + g#upload pnp_wait_exe (g#case_sensitive_path
> + (String.concat "/" pnp_wait_path))
> +
> and configure_rhev_apt tool_path =
> (* Configure RHEV-APT (the RHEV guest agent). However if it doesn't
> * exist just warn about it and continue.
ACK.
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
libguestfs lets you edit virtual machines. Supports shell scripting,
bindings from many languages. http://libguestfs.org
More information about the Libguestfs
mailing list