diff --git a/customize/firstboot.ml b/customize/firstboot.ml index 5396ded3e..3a5c10a46 100644 --- a/customize/firstboot.ml +++ b/customize/firstboot.ml @@ -318,12 +318,7 @@ echo uninstalling firstboot service let filename = g#case_sensitive_path filename in Registry.with_hive_write g filename (fun root_node -> - (* Find the 'Current' ControlSet. *) - let current_cs = - let select = g#hivex_node_get_child root_node "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 = g#inspect_get_windows_current_control_set root in (* Add a new rhsrvany service to the system registry to execute * firstboot. NB: All these edits are in the HKLM\SYSTEM hive. diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml index a23121935..eabbd5644 100644 --- a/v2v/convert_windows.ml +++ b/v2v/convert_windows.ml @@ -68,17 +68,16 @@ let convert ~keep_serial_console (g : G.guestfs) inspect source rcaps = None ) in - (* Get the Windows %systemroot%. *) - let systemroot = g#inspect_get_windows_systemroot inspect.i_root in - (* Get the software and system hive files. *) let software_hive_filename = - let filename = sprintf "%s/system32/config/software" systemroot in + let filename = sprintf "%s/system32/config/software" + inspect.i_windows_systemroot in let filename = g#case_sensitive_path filename in filename in let system_hive_filename = - let filename = sprintf "%s/system32/config/system" systemroot in + let filename = sprintf "%s/system32/config/system" + inspect.i_windows_systemroot in let filename = g#case_sensitive_path filename in filename in @@ -223,13 +222,6 @@ 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 () = wait_pnp (); (match installer with @@ -298,8 +290,8 @@ reg delete \"%s\" /v %s /f" strkey name let name = "SuppressUI" in let value = Registry.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 + set_reg_val_dword_1 root (inspect.i_windows_current_control_set + :: key_path) name ) in reg_restore ("HKLM\\SYSTEM\\CurrentControlSet" :: key_path) name value @@ -402,18 +394,16 @@ 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. *) - let current_cs = get_current_cs root in - debug "current ControlSet is %s" current_cs; + disable_xenpv_win_drivers root; + disable_prl_drivers root; + disable_autoreboot root; + Windows_virtio.install_drivers g inspect root rcaps - disable_xenpv_win_drivers root current_cs; - disable_prl_drivers root current_cs; - disable_autoreboot root current_cs; - Windows_virtio.install_drivers g inspect systemroot - root current_cs rcaps - - and disable_xenpv_win_drivers root current_cs = + and disable_xenpv_win_drivers root = (* Disable xenpv-win service (RHBZ#809273). *) - let services = Registry.get_node g root [current_cs; "Services"] in + let services = + Registry.get_node g root + [inspect.i_windows_current_control_set; "Services"] in match services with | None -> () @@ -422,9 +412,11 @@ if errorlevel 3010 exit /b 0 if node <> 0L then g#hivex_node_set_value node "Start" 4_L (le32_of_int 4_L) - and disable_prl_drivers root current_cs = + and disable_prl_drivers root = (* Prevent Parallels drivers from loading at boot. *) - let services = Registry.get_node g root [current_cs; "Services"] in + let services = + Registry.get_node g root + [inspect.i_windows_current_control_set; "Services"] in let prl_svcs = [ "prl_boot"; "prl_dd"; "prl_eth5"; "prl_fs"; "prl_memdev"; "prl_mouf"; "prl_pv32"; "prl_pv64"; "prl_scsi"; "prl_sound"; "prl_strg"; "prl_tg"; "prl_time"; @@ -447,7 +439,8 @@ if errorlevel 3010 exit /b 0 * HKLM, System\CurrentControlSet\Control\Class\{4d36e967-e325-11ce-bfc1-08002be10318}, LowerFilters, 0x00018002, prl_strg *) let strg_cls = Registry.get_node g root - [current_cs; "Control"; "Class"; + [inspect.i_windows_current_control_set; + "Control"; "Class"; "{4d36e967-e325-11ce-bfc1-08002be10318}"] in match strg_cls with | None -> () @@ -467,12 +460,13 @@ if errorlevel 3010 exit /b 0 g#hivex_node_set_value strg_cls lfkey 7_L data ) - and disable_autoreboot root current_cs = + and disable_autoreboot root = (* If the guest reboots after a crash, it's hard to see the original * error (eg. the infamous 0x0000007B). Turn off autoreboot. *) let crash_control = - Registry.get_node g root [current_cs; "Control"; "CrashControl"] in + Registry.get_node g root [inspect.i_windows_current_control_set; + "Control"; "CrashControl"] in match crash_control with | None -> () | Some crash_control -> diff --git a/v2v/inspect_source.ml b/v2v/inspect_source.ml index 3936e7201..3b16c4266 100644 --- a/v2v/inspect_source.ml +++ b/v2v/inspect_source.ml @@ -32,6 +32,8 @@ let rec inspect_source root_choice g = reject_if_not_installed_image g root; + let typ = g#inspect_get_type root in + (* Mount up the filesystems. *) let mps = g#inspect_get_mountpoints root in let cmp (a,_) (b,_) = compare (String.length a) (String.length b) in @@ -65,9 +67,20 @@ let rec inspect_source root_choice g = StringMap.add name (app :: vs) map ) StringMap.empty apps in + (* If the guest is Windows, get some Windows-specific inspection + * data, else (for simplicity when accessing) use empty strings. + *) + let systemroot, current_cs = + match typ with + | "windows" -> + g#inspect_get_windows_systemroot root, + g#inspect_get_windows_current_control_set root + | _ -> + "", "" in + let inspect = { i_root = root; - i_type = g#inspect_get_type root; + i_type = typ; i_distro = g#inspect_get_distro root; i_arch = g#inspect_get_arch root; i_major_version = g#inspect_get_major_version root; @@ -80,6 +93,8 @@ let rec inspect_source root_choice g = i_apps = apps; i_apps_map = apps_map; i_firmware = get_firmware_bootable_device g; + i_windows_systemroot = systemroot; + i_windows_current_control_set = current_cs; } in debug "%s" (string_of_inspect inspect); diff --git a/v2v/types.ml b/v2v/types.ml index afeb178f7..7fd63279b 100644 --- a/v2v/types.ml +++ b/v2v/types.ml @@ -324,6 +324,8 @@ type inspect = { i_apps : Guestfs.application2 list; i_apps_map : Guestfs.application2 list StringMap.t; i_firmware : i_firmware; + i_windows_systemroot : string; + i_windows_current_control_set : string; } let string_of_inspect inspect = @@ -339,6 +341,8 @@ i_package_management = %s i_product_name = %s i_product_variant = %s i_firmware = %s +i_windows_systemroot = %s +i_windows_current_control_set = %s " inspect.i_root inspect.i_type inspect.i_distro @@ -352,6 +356,8 @@ i_firmware = %s (match inspect.i_firmware with | I_BIOS -> "BIOS" | I_UEFI devices -> sprintf "UEFI [%s]" (String.concat ", " devices)) + inspect.i_windows_systemroot + inspect.i_windows_current_control_set type mpstat = { mp_dev : string; diff --git a/v2v/types.mli b/v2v/types.mli index 96ab36a24..df50b1bf9 100644 --- a/v2v/types.mli +++ b/v2v/types.mli @@ -230,6 +230,8 @@ type inspect = { i_firmware : i_firmware; (** The list of EFI system partitions for the guest with UEFI, otherwise the BIOS identifier. *) + i_windows_systemroot : string; + i_windows_current_control_set : string; } (** Inspection information. *) diff --git a/v2v/v2v_unit_tests.ml b/v2v/v2v_unit_tests.ml index 1133d9297..af86afa6c 100644 --- a/v2v/v2v_unit_tests.ml +++ b/v2v/v2v_unit_tests.ml @@ -30,7 +30,8 @@ let inspect_defaults = { i_major_version = 0; i_minor_version = 0; i_root = ""; i_package_format = ""; i_package_management = ""; i_product_name = ""; i_product_variant = ""; i_mountpoints = []; - i_apps = []; i_apps_map = StringMap.empty; i_firmware = I_BIOS + i_apps = []; i_apps_map = StringMap.empty; i_firmware = I_BIOS; + i_windows_systemroot = ""; i_windows_current_control_set = ""; } let test_get_ostype ctx = diff --git a/v2v/windows_virtio.ml b/v2v/windows_virtio.ml index a63ab44ef..2c28524c0 100644 --- a/v2v/windows_virtio.ml +++ b/v2v/windows_virtio.ml @@ -37,9 +37,9 @@ let scsi_class_guid = "{4D36E97B-E325-11CE-BFC1-08002BE10318}" let viostor_pciid = "VEN_1AF4&DEV_1001&SUBSYS_00021AF4&REV_00" let vioscsi_pciid = "VEN_1AF4&DEV_1004&SUBSYS_00081AF4&REV_00" -let rec install_drivers g inspect systemroot root current_cs rcaps = +let rec install_drivers g inspect root rcaps = (* Copy the virtio drivers to the guest. *) - let driverdir = sprintf "%s/Drivers/VirtIO" systemroot in + let driverdir = sprintf "%s/Drivers/VirtIO" inspect.i_windows_systemroot in g#mkdir_p driverdir; if not (copy_drivers g inspect driverdir) then ( @@ -98,22 +98,22 @@ let rec install_drivers g inspect systemroot root current_cs rcaps = (* Block driver needs tweaks to allow booting; the rest is set up by PnP * manager *) let source = driverdir // (driver_name ^ ".sys") in - let target = sprintf "%s/system32/drivers/%s.sys" systemroot driver_name in + let target = sprintf "%s/system32/drivers/%s.sys" + inspect.i_windows_systemroot driver_name in let target = g#case_sensitive_path target in g#cp source target; - add_guestor_to_registry g root current_cs driver_name - viostor_pciid; + add_guestor_to_registry g inspect root driver_name viostor_pciid; Virtio_blk | Some Virtio_SCSI, _, true -> (* Block driver needs tweaks to allow booting; the rest is set up by PnP * manager *) let source = driverdir // "vioscsi.sys" in - let target = sprintf "%s/system32/drivers/vioscsi.sys" systemroot in + let target = sprintf "%s/system32/drivers/vioscsi.sys" + inspect.i_windows_systemroot in let target = g#case_sensitive_path target in g#cp source target; - add_guestor_to_registry g root current_cs "vioscsi" - vioscsi_pciid; + add_guestor_to_registry g inspect root "vioscsi" vioscsi_pciid; Virtio_SCSI | Some IDE, _, _ -> @@ -168,18 +168,18 @@ let rec install_drivers g inspect systemroot root current_cs rcaps = (block, net, video) ) -and add_guestor_to_registry g root current_cs drv_name drv_pciid = +and add_guestor_to_registry g inspect root drv_name drv_pciid = let ddb_node = g#hivex_node_get_child root "DriverDatabase" in let regedits = if ddb_node = 0L then - cdb_regedits current_cs drv_name drv_pciid + cdb_regedits inspect drv_name drv_pciid else - ddb_regedits current_cs drv_name drv_pciid in + ddb_regedits inspect drv_name drv_pciid in let drv_sys_path = sprintf "system32\\drivers\\%s.sys" drv_name in let common_regedits = [ - [ current_cs; "Services"; drv_name ], + [ inspect.i_windows_current_control_set; "Services"; drv_name ], [ "Type", REG_DWORD 0x1_l; "Start", REG_DWORD 0x0_l; "Group", REG_SZ "SCSI miniport"; @@ -189,19 +189,20 @@ and add_guestor_to_registry g root current_cs drv_name drv_pciid = reg_import g root (regedits @ common_regedits) -and cdb_regedits current_cs drv_name drv_pciid = +and cdb_regedits inspect drv_name drv_pciid = (* See http://rwmj.wordpress.com/2010/04/30/tip-install-a-device-driver-in-a-windows-vm/ * NB: All these edits are in the HKLM\SYSTEM hive. No other * hive may be modified here. *) [ - [ current_cs; "Control"; "CriticalDeviceDatabase"; + [ inspect.i_windows_current_control_set; + "Control"; "CriticalDeviceDatabase"; "PCI#" ^ drv_pciid ], [ "Service", REG_SZ drv_name; "ClassGUID", REG_SZ scsi_class_guid ]; ] -and ddb_regedits current_cs drv_name drv_pciid = +and ddb_regedits inspect drv_name drv_pciid = (* Windows >= 8 doesn't use the CriticalDeviceDatabase. Instead * one must add keys into the DriverDatabase. *) diff --git a/v2v/windows_virtio.mli b/v2v/windows_virtio.mli index 1d2526066..4ceeebe43 100644 --- a/v2v/windows_virtio.mli +++ b/v2v/windows_virtio.mli @@ -19,17 +19,16 @@ (** Functions for installing Windows virtio drivers. *) val install_drivers - : Guestfs.guestfs -> Types.inspect -> string -> Registry.node -> string -> + : Guestfs.guestfs -> Types.inspect -> Registry.node -> Types.requested_guestcaps -> Types.guestcaps_block_type * Types.guestcaps_net_type * Types.guestcaps_video_type -(** [install_drivers g inspect systemroot root current_cs rcaps] +(** [install_drivers g inspect root rcaps] installs virtio drivers from the driver directory or driver ISO into the guest driver directory and updates the registry so that the [viostor.sys] driver gets loaded by Windows at boot. [root] is the root node of the system hive (which is open for writes - when this function is called). [current_cs] is the name of the - [CurrentControlSet] (eg. ["ControlSet001"]). + when this function is called). [rcaps] is the set of guest "capabilities" requested by the caller. This may include the type of the block driver, network driver, and video driver.