Richard W.M. Jones
2016-Aug-23 16:33 UTC
Re: [Libguestfs] [PATCH 2/2] v2v:windows: prevent conflicts with PnP on firstboot
On Wed, Aug 17, 2016 at 08:59:44PM +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@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 751a6ab..10a6d31 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 "\ > +@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.This one looks OK, ACK. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-builder quickly builds VMs from scratch http://libguestfs.org/virt-builder.1.html
Possibly Parallel Threads
- Re: [PATCH v2 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