Roman Kagan
2016-Sep-01 08:50 UTC
[Libguestfs] [PATCH v2 0/2] v2v:windows: prevent conflicts with PnP on firstboot
Wait for driver installations fired by the PnP manager to complete before running firstboot scripts. The first patch is a minor refactoring to pave the way for the second patch. The latter contains the bulk of the changes as well as the description of the idea. Roman Kagan (2): v2v:windows: factor out getting CurrentControlSet v2v:windows: prevent conflicts with PnP on firstboot --- v1 -> v2: - revert debug -> printf regression v2v/convert_windows.ml | 107 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 100 insertions(+), 7 deletions(-) -- 2.7.4
Roman Kagan
2016-Sep-01 08:50 UTC
[Libguestfs] [PATCH v2 1/2] v2v:windows: factor out getting CurrentControlSet
It will be used in new code in a followup patch. Signed-off-by: Roman Kagan <rkagan at virtuozzo.com> --- v1 -> v2: - revert debug -> printf regression v2v/convert_windows.ml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml index 55bb3ef..02c7a47 100644 --- a/v2v/convert_windows.ml +++ b/v2v/convert_windows.ml @@ -210,6 +210,13 @@ let convert ~keep_serial_console (g : G.guestfs) inspect source rcaps (*----------------------------------------------------------------------*) (* Perform the conversion of the Windows guest. *) + (* Find the 'Current' ControlSet. *) + let get_current_cs root + let select = g#hivex_node_get_child root "Select" in + let valueh = g#hivex_node_get_value select "Current" in + let value = int_of_le32 (g#hivex_value_value valueh) in + sprintf "ControlSet%03Ld" value in + let rec configure_firstboot () (match installer with | None -> () @@ -302,13 +309,7 @@ if errorlevel 3010 exit /b 0 (* Update the SYSTEM hive. When this function is called the hive has * already been opened as a hivex handle inside guestfs. *) - (* Find the 'Current' ControlSet. *) - let current_cs - let select = g#hivex_node_get_child root "Select" in - let valueh = g#hivex_node_get_value select "Current" in - let value = int_of_le32 (g#hivex_value_value valueh) in - sprintf "ControlSet%03Ld" value in - + let current_cs = get_current_cs root in debug "current ControlSet is %s" current_cs; disable_services root current_cs; -- 2.7.4
Roman Kagan
2016-Sep-01 08:50 UTC
[Libguestfs] [PATCH v2 2/2] v2v:windows: prevent conflicts with PnP on firstboot
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. -- 2.7.4
Roman Kagan
2016-Sep-01 11:37 UTC
[Libguestfs] [PATCH v2 0/2] v2v:windows: prevent conflicts with PnP on firstboot
On Thu, Sep 01, 2016 at 11:50:17AM +0300, Roman Kagan wrote:> Wait for driver installations fired by the PnP manager to complete > before running firstboot scripts. > > The first patch is a minor refactoring to pave the way for the second > patch. The latter contains the bulk of the changes as well as the > description of the idea. > > Roman Kagan (2): > v2v:windows: factor out getting CurrentControlSet > v2v:windows: prevent conflicts with PnP on firstboot > > --- > v1 -> v2: > - revert debug -> printf regression > > v2v/convert_windows.ml | 107 +++++++++++++++++++++++++++++++++++++++++++++---- > 1 file changed, 100 insertions(+), 7 deletions(-)Pushed to master. Thanks, Roman.
Seemingly Similar Threads
- [PATCH 0/8] Miscellaneous cleanups to Windows registry code.
- Re: [PATCH 2/2] v2v:windows: prevent conflicts with PnP on firstboot
- Re: [PATCH v2 2/2] v2v:windows: prevent conflicts with PnP on firstboot
- Re: [PATCH 1/2] v2v:windows: factor out getting CurrentControlSet
- [PATCH NOT TO BE APPLIED] v2v: windows: Make registry changes to all ControlSets, not