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
Richard W.M. Jones
2016-Sep-01 08:54 UTC
[Libguestfs] [PATCH v2 2/2] v2v:windows: prevent conflicts with PnP on firstboot
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
Apparently Analagous Threads
- Re: [PATCH 2/2] v2v:windows: prevent conflicts with PnP on firstboot
- [PATCH v2 0/2] v2v:windows: prevent conflicts with PnP on firstboot
- [V2V PATCH v2 1/1] convert_windows: add firstboot script to install drivers with pnputil
- [V2V PATCH 1/1] convert_windows: add firstboot script to install drivers with pnputil
- [V2V PATCH 1/1] convert_windows: add firstboot script to install drivers with pnputil