Compare commits
No commits in common. "a9-ppc64le" and "c9-beta" have entirely different histories.
a9-ppc64le
...
c9-beta
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,2 @@
|
|||||||
SOURCES/guestfs-tools-1.51.6.tar.gz
|
SOURCES/guestfs-tools-1.52.2.tar.gz
|
||||||
SOURCES/libguestfs.keyring
|
SOURCES/libguestfs.keyring
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
7a64ba52bca3a3591d2e639a6bc9002d61e7d374 SOURCES/guestfs-tools-1.51.6.tar.gz
|
6eb02f4f70cb224548567ce7e4b67712c8ebb643 SOURCES/guestfs-tools-1.52.2.tar.gz
|
||||||
1bbc40f501a7fef9eef2a39b701a71aee2fea7c4 SOURCES/libguestfs.keyring
|
1bbc40f501a7fef9eef2a39b701a71aee2fea7c4 SOURCES/libguestfs.keyring
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
From b5fdf9eac368a1c5df4ddd93ce40884924e6092a Mon Sep 17 00:00:00 2001
|
From 1107ededf2cad9982befb4d4b90353117b29d474 Mon Sep 17 00:00:00 2001
|
||||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||||
Date: Tue, 7 Jul 2015 09:28:03 -0400
|
Date: Tue, 7 Jul 2015 09:28:03 -0400
|
||||||
Subject: [PATCH] RHEL: Reject use of libguestfs-winsupport features except for
|
Subject: [PATCH] RHEL: Reject use of libguestfs-winsupport features except for
|
@ -1,26 +0,0 @@
|
|||||||
From 28ecb8693bbded3e1c70c1baa57f3498a6b8127e Mon Sep 17 00:00:00 2001
|
|
||||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
|
||||||
Date: Sat, 9 Dec 2023 12:59:13 +0000
|
|
||||||
Subject: [PATCH] Update common submodule
|
|
||||||
|
|
||||||
Pick up this bug fix:
|
|
||||||
|
|
||||||
mltools/libosinfo-c.c: Fix off-by-one error
|
|
||||||
---
|
|
||||||
common | 2 +-
|
|
||||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
||||||
|
|
||||||
Submodule common cd29aee91..0dba002c2:
|
|
||||||
diff --git a/common/mltools/libosinfo-c.c b/common/mltools/libosinfo-c.c
|
|
||||||
index 93357fd91..a48c8989f 100644
|
|
||||||
--- a/common/mltools/libosinfo-c.c
|
|
||||||
+++ b/common/mltools/libosinfo-c.c
|
|
||||||
@@ -296,7 +296,7 @@ v2v_osinfo_os_get_device_drivers (value osv)
|
|
||||||
|
|
||||||
driver = OSINFO_DEVICE_DRIVER(osinfo_list_get_nth (OSINFO_LIST(list), i));
|
|
||||||
|
|
||||||
- vi = caml_alloc (6, 0);
|
|
||||||
+ vi = caml_alloc (7, 0);
|
|
||||||
str = osinfo_device_driver_get_architecture (driver);
|
|
||||||
copyv = caml_copy_string (str);
|
|
||||||
Store_field (vi, 0, copyv);
|
|
@ -1,4 +1,4 @@
|
|||||||
From 511de43cdca80381d52360e050bf57f7079f46d6 Mon Sep 17 00:00:00 2001
|
From 517a2ad502fa3773db50e883c0bece69b03b31ca Mon Sep 17 00:00:00 2001
|
||||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||||
Date: Mon, 21 Nov 2022 13:03:22 +0000
|
Date: Mon, 21 Nov 2022 13:03:22 +0000
|
||||||
Subject: [PATCH] RHEL: builder: Disable opensuse repository
|
Subject: [PATCH] RHEL: builder: Disable opensuse repository
|
@ -1,63 +0,0 @@
|
|||||||
From 5f9beb89443f84640efc52ee6cd68f7f880fb66b Mon Sep 17 00:00:00 2001
|
|
||||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
|
||||||
Date: Fri, 19 Jan 2024 13:22:51 +0000
|
|
||||||
Subject: [PATCH] builder: Add a test of the --chown parameter
|
|
||||||
|
|
||||||
Also update the libguestfs common submodule, pulling in this change
|
|
||||||
from libguestfs:
|
|
||||||
|
|
||||||
generator/customize.ml: Split --chown parameter on ':' character
|
|
||||||
|
|
||||||
and this patch to common/mltools:
|
|
||||||
|
|
||||||
mltools/libosinfo-c.c: Fix off-by-one error
|
|
||||||
|
|
||||||
(cherry picked from commit 299dc5ec2a0bdd9adecef75adc6a5eca0dc685b1)
|
|
||||||
---
|
|
||||||
builder/test-virt-builder.sh | 4 ++++
|
|
||||||
common | 2 +-
|
|
||||||
2 files changed, 5 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/builder/test-virt-builder.sh b/builder/test-virt-builder.sh
|
|
||||||
index 705788a3c..f839fd7af 100755
|
|
||||||
--- a/builder/test-virt-builder.sh
|
|
||||||
+++ b/builder/test-virt-builder.sh
|
|
||||||
@@ -69,6 +69,7 @@ virt-builder phony-fedora \
|
|
||||||
--write '/etc/append6:
|
|
||||||
' \
|
|
||||||
--append-line '/etc/append6:line2' \
|
|
||||||
+ --chown 1:1:/etc/append6 \
|
|
||||||
--firstboot Makefile --firstboot-command 'echo "hello"' \
|
|
||||||
--firstboot-install "minicom,inkscape"
|
|
||||||
|
|
||||||
@@ -112,6 +113,7 @@ echo append5:
|
|
||||||
cat /etc/append5
|
|
||||||
echo append6:
|
|
||||||
cat /etc/append6
|
|
||||||
+stat /etc/append6 | grep '^[ug]id:'
|
|
||||||
|
|
||||||
echo -----
|
|
||||||
EOF
|
|
||||||
@@ -154,6 +156,8 @@ append6:
|
|
||||||
|
|
||||||
line2
|
|
||||||
|
|
||||||
+uid: 1
|
|
||||||
+gid: 1
|
|
||||||
-----" ]; then
|
|
||||||
echo "$0: unexpected output:"
|
|
||||||
cat test-virt-builder.out
|
|
||||||
Submodule common 0dba002c2..54869c987:
|
|
||||||
diff --git a/common/mlcustomize/customize_cmdline.ml b/common/mlcustomize/customize_cmdline.ml
|
|
||||||
index 245d9960a..48ee33445 100644
|
|
||||||
--- a/common/mlcustomize/customize_cmdline.ml
|
|
||||||
+++ b/common/mlcustomize/customize_cmdline.ml
|
|
||||||
@@ -157,7 +157,7 @@ let rec argspec () =
|
|
||||||
let len = String.length arg in
|
|
||||||
String.sub arg 0 i, String.sub arg (i+1) (len-(i+1))
|
|
||||||
and split_string_triplet option_name arg =
|
|
||||||
- match String.nsplit ~max:3 "," arg with
|
|
||||||
+ match String.nsplit ~max:3 ":" arg with
|
|
||||||
| [a; b; c] -> a, b, c
|
|
||||||
| _ ->
|
|
||||||
error (f_"invalid format for '--%s' parameter, see the man page")
|
|
254
SOURCES/0003-customize-Implement-inject-blnsvr-operation.patch
Normal file
254
SOURCES/0003-customize-Implement-inject-blnsvr-operation.patch
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
From 1cb20d561c6b2e93980ba9c7c7269b32f6d768eb Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||||
|
Date: Thu, 16 May 2024 12:49:24 +0100
|
||||||
|
Subject: [PATCH] customize: Implement --inject-blnsvr operation
|
||||||
|
|
||||||
|
Also updates the common submodule with the generated changes from
|
||||||
|
libguestfs, and the implementation of Inject_virtio_win.inject_blnsvr.
|
||||||
|
|
||||||
|
(cherry picked from commit 80d258baa49214c8e59b91d6085595c9b989fc0d)
|
||||||
|
---
|
||||||
|
common | 2 +-
|
||||||
|
customize/customize_run.ml | 13 +++++++++++--
|
||||||
|
2 files changed, 12 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
Submodule common 7cbb3ba35...a78839676:
|
||||||
|
diff --git a/common/mlcustomize/customize-options.pod b/common/mlcustomize/customize-options.pod
|
||||||
|
index ff93630d8..b2ac57526 100644
|
||||||
|
--- a/common/mlcustomize/customize-options.pod
|
||||||
|
+++ b/common/mlcustomize/customize-options.pod
|
||||||
|
@@ -193,6 +193,18 @@ L<virt-builder(1)/INSTALLING PACKAGES>.
|
||||||
|
Set the hostname of the guest to C<HOSTNAME>. You can use a
|
||||||
|
dotted hostname.domainname (FQDN) if you want.
|
||||||
|
|
||||||
|
+=item B<--inject-blnsvr> METHOD
|
||||||
|
+
|
||||||
|
+Inject the Balloon Server (F<blnsvr.exe>) into a Windows guest.
|
||||||
|
+This operation also injects a firstboot script so that the Balloon
|
||||||
|
+Server is installed when the guest boots.
|
||||||
|
+
|
||||||
|
+The parameter is the same as used by the I<--inject-virtio-win> operation.
|
||||||
|
+
|
||||||
|
+Note that to do a full conversion of a Windows guest from a
|
||||||
|
+foreign hypervisor like VMware (which involves many other operations)
|
||||||
|
+you should use the L<virt-v2v(1)> tool instead of this.
|
||||||
|
+
|
||||||
|
=item B<--inject-qemu-ga> METHOD
|
||||||
|
|
||||||
|
Inject the QEMU Guest Agent into a Windows guest. The guest
|
||||||
|
diff --git a/common/mlcustomize/customize-synopsis.pod b/common/mlcustomize/customize-synopsis.pod
|
||||||
|
index bb0ce1255..957de8cf2 100644
|
||||||
|
--- a/common/mlcustomize/customize-synopsis.pod
|
||||||
|
+++ b/common/mlcustomize/customize-synopsis.pod
|
||||||
|
@@ -3,16 +3,16 @@
|
||||||
|
[--copy SOURCE:DEST] [--copy-in LOCALPATH:REMOTEDIR]
|
||||||
|
[--delete PATH] [--edit FILE:EXPR] [--firstboot SCRIPT]
|
||||||
|
[--firstboot-command 'CMD+ARGS'] [--firstboot-install PKG,PKG..]
|
||||||
|
- [--hostname HOSTNAME] [--inject-qemu-ga METHOD]
|
||||||
|
- [--inject-virtio-win METHOD] [--install PKG,PKG..]
|
||||||
|
- [--link TARGET:LINK[:LINK..]] [--mkdir DIR] [--move SOURCE:DEST]
|
||||||
|
- [--password USER:SELECTOR] [--root-password SELECTOR]
|
||||||
|
- [--run SCRIPT] [--run-command 'CMD+ARGS'] [--scrub FILE]
|
||||||
|
- [--sm-attach SELECTOR] [--sm-register] [--sm-remove]
|
||||||
|
- [--sm-unregister] [--ssh-inject USER[:SELECTOR]]
|
||||||
|
- [--tar-in TARFILE:REMOTEDIR] [--timezone TIMEZONE] [--touch FILE]
|
||||||
|
- [--truncate FILE] [--truncate-recursive PATH]
|
||||||
|
- [--uninstall PKG,PKG..] [--update] [--upload FILE:DEST]
|
||||||
|
- [--write FILE:CONTENT] [--no-logfile]
|
||||||
|
+ [--hostname HOSTNAME] [--inject-blnsvr METHOD]
|
||||||
|
+ [--inject-qemu-ga METHOD] [--inject-virtio-win METHOD]
|
||||||
|
+ [--install PKG,PKG..] [--link TARGET:LINK[:LINK..]] [--mkdir DIR]
|
||||||
|
+ [--move SOURCE:DEST] [--password USER:SELECTOR]
|
||||||
|
+ [--root-password SELECTOR] [--run SCRIPT]
|
||||||
|
+ [--run-command 'CMD+ARGS'] [--scrub FILE] [--sm-attach SELECTOR]
|
||||||
|
+ [--sm-register] [--sm-remove] [--sm-unregister]
|
||||||
|
+ [--ssh-inject USER[:SELECTOR]] [--tar-in TARFILE:REMOTEDIR]
|
||||||
|
+ [--timezone TIMEZONE] [--touch FILE] [--truncate FILE]
|
||||||
|
+ [--truncate-recursive PATH] [--uninstall PKG,PKG..] [--update]
|
||||||
|
+ [--upload FILE:DEST] [--write FILE:CONTENT] [--no-logfile]
|
||||||
|
[--password-crypto md5|sha256|sha512] [--no-selinux-relabel]
|
||||||
|
[--selinux-relabel] [--sm-credentials SELECTOR]
|
||||||
|
diff --git a/common/mlcustomize/customize_cmdline.ml b/common/mlcustomize/customize_cmdline.ml
|
||||||
|
index 48ee33445..c4d6a77d5 100644
|
||||||
|
--- a/common/mlcustomize/customize_cmdline.ml
|
||||||
|
+++ b/common/mlcustomize/customize_cmdline.ml
|
||||||
|
@@ -61,6 +61,8 @@ and op = [
|
||||||
|
(* --firstboot-install PKG,PKG.. *)
|
||||||
|
| `Hostname of string
|
||||||
|
(* --hostname HOSTNAME *)
|
||||||
|
+ | `InjectBalloonServer of string
|
||||||
|
+ (* --inject-blnsvr METHOD *)
|
||||||
|
| `InjectQemuGA of string
|
||||||
|
(* --inject-qemu-ga METHOD *)
|
||||||
|
| `InjectVirtioWin of string
|
||||||
|
@@ -286,6 +288,12 @@ let rec argspec () =
|
||||||
|
s_"Set the hostname"
|
||||||
|
),
|
||||||
|
Some "HOSTNAME", "Set the hostname of the guest to C<HOSTNAME>. You can use a\ndotted hostname.domainname (FQDN) if you want.";
|
||||||
|
+ (
|
||||||
|
+ [ L"inject-blnsvr" ],
|
||||||
|
+ Getopt.String (s_"METHOD", fun s -> List.push_front (`InjectBalloonServer s) ops),
|
||||||
|
+ s_"Inject the Balloon Server into a Windows guest"
|
||||||
|
+ ),
|
||||||
|
+ Some "METHOD", "Inject the Balloon Server (F<blnsvr.exe>) into a Windows guest.\nThis operation also injects a firstboot script so that the Balloon\nServer is installed when the guest boots.\n\nThe parameter is the same as used by the I<--inject-virtio-win> operation.\n\nNote that to do a full conversion of a Windows guest from a\nforeign hypervisor like VMware (which involves many other operations)\nyou should use the L<virt-v2v(1)> tool instead of this.";
|
||||||
|
(
|
||||||
|
[ L"inject-qemu-ga" ],
|
||||||
|
Getopt.String (s_"METHOD", fun s -> List.push_front (`InjectQemuGA s) ops),
|
||||||
|
diff --git a/common/mlcustomize/customize_cmdline.mli b/common/mlcustomize/customize_cmdline.mli
|
||||||
|
index 51a156eae..ee62961a1 100644
|
||||||
|
--- a/common/mlcustomize/customize_cmdline.mli
|
||||||
|
+++ b/common/mlcustomize/customize_cmdline.mli
|
||||||
|
@@ -53,6 +53,8 @@ and op = [
|
||||||
|
(* --firstboot-install PKG,PKG.. *)
|
||||||
|
| `Hostname of string
|
||||||
|
(* --hostname HOSTNAME *)
|
||||||
|
+ | `InjectBalloonServer of string
|
||||||
|
+ (* --inject-blnsvr METHOD *)
|
||||||
|
| `InjectQemuGA of string
|
||||||
|
(* --inject-qemu-ga METHOD *)
|
||||||
|
| `InjectVirtioWin of string
|
||||||
|
diff --git a/common/mlcustomize/inject_virtio_win.ml b/common/mlcustomize/inject_virtio_win.ml
|
||||||
|
index 0a4b8dac0..afec1e456 100644
|
||||||
|
--- a/common/mlcustomize/inject_virtio_win.ml
|
||||||
|
+++ b/common/mlcustomize/inject_virtio_win.ml
|
||||||
|
@@ -24,6 +24,8 @@ open Common_gettext.Gettext
|
||||||
|
|
||||||
|
open Regedit
|
||||||
|
|
||||||
|
+let re_blnsvr = PCRE.compile ~caseless:true "\\bblnsvr\\.exe$"
|
||||||
|
+
|
||||||
|
type t = {
|
||||||
|
g : Guestfs.guestfs; (** guestfs handle *)
|
||||||
|
|
||||||
|
@@ -274,6 +276,25 @@ and inject_qemu_ga ({ g; root } as t) =
|
||||||
|
configure_qemu_ga t tempdir_win msi_files;
|
||||||
|
msi_files <> [] (* return true if we found some qemu-ga MSI files *)
|
||||||
|
|
||||||
|
+and inject_blnsvr ({ g; root } as t) =
|
||||||
|
+ (* Copy the files to the guest. *)
|
||||||
|
+ let dir, dir_win = Firstboot.firstboot_dir g root in
|
||||||
|
+ let dir_win = Option.value dir_win ~default:dir in
|
||||||
|
+ let tempdir = sprintf "%s/Temp" dir in
|
||||||
|
+ let tempdir_win = sprintf "%s\\Temp" dir_win in
|
||||||
|
+ g#mkdir_p tempdir;
|
||||||
|
+
|
||||||
|
+ let files = copy_blnsvr t tempdir in
|
||||||
|
+ match files with
|
||||||
|
+ | [] -> false (* Didn't find or install anything. *)
|
||||||
|
+
|
||||||
|
+ (* We usually find blnsvr.exe in two locations (drivers/by-os and
|
||||||
|
+ * drivers/by-driver). Pick the first.
|
||||||
|
+ *)
|
||||||
|
+ | blnsvr :: _ ->
|
||||||
|
+ configure_blnsvr t tempdir_win blnsvr;
|
||||||
|
+ true
|
||||||
|
+
|
||||||
|
and add_guestor_to_registry t ((g, root) as reg) drv_name drv_pciid =
|
||||||
|
let ddb_node = g#hivex_node_get_child root "DriverDatabase" in
|
||||||
|
|
||||||
|
@@ -358,6 +379,11 @@ and copy_qemu_ga t tempdir =
|
||||||
|
(fun () ->
|
||||||
|
error (f_"root directory ‘/’ is missing from the virtio-win directory or ISO.\n\nThis should not happen and may indicate that virtio-win or virt-v2v is broken in some way. Please report this as a bug with a full debug log."))
|
||||||
|
|
||||||
|
+and copy_blnsvr t tempdir =
|
||||||
|
+ copy_from_virtio_win t "/" tempdir (virtio_iso_path_matches_blnsvr t)
|
||||||
|
+ (fun () ->
|
||||||
|
+ error (f_"root directory ‘/’ is missing from the virtio-win directory or ISO.\n\nThis should not happen and may indicate that virtio-win or virt-v2v is broken in some way. Please report this as a bug with a full debug log."))
|
||||||
|
+
|
||||||
|
(* Copy all files from virtio_win directory/ISO located in [srcdir]
|
||||||
|
* subdirectory and all its subdirectories to the [destdir]. The directory
|
||||||
|
* hierarchy is not preserved, meaning all files will be directly in [destdir].
|
||||||
|
@@ -452,10 +478,7 @@ and virtio_iso_path_matches_guest_os t path =
|
||||||
|
* "./drivers/amd64/Win2012R2/netkvm.sys".
|
||||||
|
* Note we check lowercase paths.
|
||||||
|
*)
|
||||||
|
- let pathelem elem =
|
||||||
|
- String.find lc_path ("/" ^ elem ^ "/") >= 0 ||
|
||||||
|
- String.is_prefix lc_path (elem ^ "/")
|
||||||
|
- in
|
||||||
|
+ let pathelem elem = String.find lc_path ("/" ^ elem ^ "/") >= 0 in
|
||||||
|
let p_arch =
|
||||||
|
if pathelem "x86" || pathelem "i386" then "i386"
|
||||||
|
else if pathelem "amd64" then "x86_64"
|
||||||
|
@@ -499,11 +522,7 @@ and virtio_iso_path_matches_guest_os t path =
|
||||||
|
else
|
||||||
|
raise Not_found in
|
||||||
|
|
||||||
|
- let p_sriov = pathelem "sriov" in
|
||||||
|
-
|
||||||
|
- arch = p_arch &&
|
||||||
|
- not p_sriov && (* always ignored, see RHEL-56383 *)
|
||||||
|
- os_major = p_os_major && os_minor = p_os_minor &&
|
||||||
|
+ arch = p_arch && os_major = p_os_major && os_minor = p_os_minor &&
|
||||||
|
match_os_variant os_variant &&
|
||||||
|
match_osinfo osinfo
|
||||||
|
|
||||||
|
@@ -527,6 +546,10 @@ and virtio_iso_path_matches_qemu_ga t path =
|
||||||
|
| ("x86_64", "rhev-qga64.msi") -> true
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
+(* Find blnsvr for the current Windows version. *)
|
||||||
|
+and virtio_iso_path_matches_blnsvr t path =
|
||||||
|
+ virtio_iso_path_matches_guest_os t path && PCRE.matches re_blnsvr path
|
||||||
|
+
|
||||||
|
(* Look up in libosinfo for the OS, and copy all the locally
|
||||||
|
* available files specified as drivers for that OS to the [destdir].
|
||||||
|
*
|
||||||
|
@@ -591,3 +614,10 @@ and configure_qemu_ga t tempdir_win files =
|
||||||
|
) files;
|
||||||
|
|
||||||
|
Firstboot.add_firstboot_powershell t.g t.root "install-qemu-ga" !script
|
||||||
|
+
|
||||||
|
+and configure_blnsvr t tempdir_win blnsvr =
|
||||||
|
+ let cmd = sprintf "\
|
||||||
|
+ @echo off\n\
|
||||||
|
+ echo Installing %s\n\
|
||||||
|
+ \"%s\\%s\" -i\n" blnsvr tempdir_win blnsvr in
|
||||||
|
+ Firstboot.add_firstboot_script t.g t.root "install-blnsvr" cmd
|
||||||
|
diff --git a/common/mlcustomize/inject_virtio_win.mli b/common/mlcustomize/inject_virtio_win.mli
|
||||||
|
index d14f04973..d273c4dd3 100644
|
||||||
|
--- a/common/mlcustomize/inject_virtio_win.mli
|
||||||
|
+++ b/common/mlcustomize/inject_virtio_win.mli
|
||||||
|
@@ -93,3 +93,11 @@ val inject_qemu_ga : t -> bool
|
||||||
|
the MSI(s).
|
||||||
|
|
||||||
|
Returns [true] iff we were able to inject qemu-ga. *)
|
||||||
|
+
|
||||||
|
+val inject_blnsvr : t -> bool
|
||||||
|
+(** Inject the Balloon Server ([blnsvr.exe]) into a Windows guest.
|
||||||
|
+
|
||||||
|
+ A firstboot script is also injected which should install
|
||||||
|
+ the server by running [blnsvr -i].
|
||||||
|
+
|
||||||
|
+ Returns [true] iff we were able to inject the Balloon Server. *)
|
||||||
|
diff --git a/customize/customize_run.ml b/customize/customize_run.ml
|
||||||
|
index 1314d6e30..1d7c13eaf 100644
|
||||||
|
--- a/customize/customize_run.ml
|
||||||
|
+++ b/customize/customize_run.ml
|
||||||
|
@@ -113,8 +113,8 @@ let run (g : G.guestfs) root (ops : ops) =
|
||||||
|
Hashtbl.replace passwords user pw
|
||||||
|
in
|
||||||
|
|
||||||
|
- (* Helper function to convert --inject-qemu-ga/--inject-virtio-win
|
||||||
|
- * method parameter into a virtio-win handle.
|
||||||
|
+ (* Helper function to convert --inject-blnsvr/--inject-qemu-ga/
|
||||||
|
+ * --inject-virtio-win method parameter into a virtio-win handle.
|
||||||
|
*)
|
||||||
|
let get_virtio_win_handle op meth =
|
||||||
|
if g#inspect_get_type root <> "windows" then (
|
||||||
|
@@ -216,6 +216,15 @@ let run (g : G.guestfs) root (ops : ops) =
|
||||||
|
if not (Hostname.set_hostname g root hostname) then
|
||||||
|
warning (f_"hostname could not be set for this type of guest")
|
||||||
|
|
||||||
|
+ | `InjectBalloonServer meth ->
|
||||||
|
+ (match get_virtio_win_handle "--inject-blnsvr" meth with
|
||||||
|
+ | None -> ()
|
||||||
|
+ | Some t ->
|
||||||
|
+ if not (Inject_virtio_win.inject_blnsvr t) then
|
||||||
|
+ warning (f_"--inject-blnsvr: blnsvr.exe not found in \
|
||||||
|
+ virtio-win source that you specified")
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
| `InjectQemuGA meth ->
|
||||||
|
(match get_virtio_win_handle "--inject-qemu-ga" meth with
|
||||||
|
| None -> ()
|
33
SOURCES/0004-build-Add-new-dependency-on-json-c.patch
Normal file
33
SOURCES/0004-build-Add-new-dependency-on-json-c.patch
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
From 9cdb27fb0fde8b2eb57453480c4fed4746414aeb Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||||
|
Date: Tue, 22 Oct 2024 11:01:25 +0100
|
||||||
|
Subject: [PATCH] build: Add new dependency on json-c
|
||||||
|
|
||||||
|
This will eventually replace Jansson for all JSON parsing. However
|
||||||
|
this commit simply introduces the new dependency in the configure
|
||||||
|
script and documents it.
|
||||||
|
|
||||||
|
I chose json-c 0.14 as the baseline since that is the version in RHEL 9.
|
||||||
|
Probably earlier versions would work.
|
||||||
|
|
||||||
|
(cherry picked from libguestfs commit 53872a0a1a267040677572c30b68bd1e8b62ebe3)
|
||||||
|
|
||||||
|
(cherry picked from commit 0d7fe8a0b0b429152ea02fc7a7e4f5a1b0eba590)
|
||||||
|
---
|
||||||
|
m4/guestfs-libraries.m4 | 3 +++
|
||||||
|
1 file changed, 3 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/m4/guestfs-libraries.m4 b/m4/guestfs-libraries.m4
|
||||||
|
index 32f93afda..b76511982 100644
|
||||||
|
--- a/m4/guestfs-libraries.m4
|
||||||
|
+++ b/m4/guestfs-libraries.m4
|
||||||
|
@@ -167,6 +167,9 @@ LIBS="$old_LIBS"
|
||||||
|
dnl Check for Jansson JSON library (required).
|
||||||
|
PKG_CHECK_MODULES([JANSSON], [jansson >= 2.7])
|
||||||
|
|
||||||
|
+dnl Check for JSON-C library (required).
|
||||||
|
+PKG_CHECK_MODULES([JSON_C], [json-c >= 0.14])
|
||||||
|
+
|
||||||
|
dnl Check for libosinfo (mandatory)
|
||||||
|
PKG_CHECK_MODULES([LIBOSINFO], [libosinfo-1.0])
|
||||||
|
|
@ -1,536 +0,0 @@
|
|||||||
From 31b4b33ec87560182f338a088bd242d571bc79e7 Mon Sep 17 00:00:00 2001
|
|
||||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
|
||||||
Date: Tue, 27 Aug 2024 13:46:46 +0100
|
|
||||||
Subject: [PATCH] Update common submodule
|
|
||||||
|
|
||||||
Pick up the commits below. In particular this makes several
|
|
||||||
refinements to the Windows firstboot code to make it more reliable.
|
|
||||||
|
|
||||||
Fixes: https://issues.redhat.com/browse/RHEL-55824
|
|
||||||
|
|
||||||
Ben Brown (1):
|
|
||||||
Initialise bar->fp as NULL
|
|
||||||
|
|
||||||
Richard W.M. Jones (16):
|
|
||||||
mlcustomize: Update virt-customize generated files
|
|
||||||
options: Allow nbd+unix:// URIs
|
|
||||||
mlcustomize: Add virt-customize --inject-blnsvr generated files
|
|
||||||
mlcustomize: Add Inject_virtio_win.inject_blnsvr implementation
|
|
||||||
mlcustomize: firstboot: Use Linux path for Powershell script path
|
|
||||||
mlcustomize: firstboot: Use powershell.exe instead of path
|
|
||||||
mlcustomize: firstboot: Use Powershell -NoProfile flag
|
|
||||||
mlcustomize: Revert delay installation of qemu-ga MSI
|
|
||||||
mldrivers/linux_kernels.ml: Prefix general information with ^info:
|
|
||||||
mlcustomize: Use Start-Process -Wait to run qemu-ga installer
|
|
||||||
mlcustomize: Add Firstboot.firstboot_dir function
|
|
||||||
mlcustomize: Place powershell scripts into <firstboot_dir>\Temp
|
|
||||||
mlcustomize: Inject qemu-ga & blnsvr into <firstboot_dir>/Temp
|
|
||||||
mlcustomize: Write qemu-ga log file name to log.txt
|
|
||||||
mlcustomize: Add some comments to firstboot batch file
|
|
||||||
mlcustomize: Reboot Windows between each firstboot script
|
|
||||||
---
|
|
||||||
common | 2 +-
|
|
||||||
customize/customize_run.ml | 3 +++
|
|
||||||
2 files changed, 4 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
Submodule common 54869c987..a78839676:
|
|
||||||
diff --git a/common/mlcustomize/customize-synopsis.pod b/common/mlcustomize/customize-synopsis.pod
|
|
||||||
index bb0ce1255..957de8cf2 100644
|
|
||||||
--- a/common/mlcustomize/customize-synopsis.pod
|
|
||||||
+++ b/common/mlcustomize/customize-synopsis.pod
|
|
||||||
@@ -3,16 +3,16 @@
|
|
||||||
[--copy SOURCE:DEST] [--copy-in LOCALPATH:REMOTEDIR]
|
|
||||||
[--delete PATH] [--edit FILE:EXPR] [--firstboot SCRIPT]
|
|
||||||
[--firstboot-command 'CMD+ARGS'] [--firstboot-install PKG,PKG..]
|
|
||||||
- [--hostname HOSTNAME] [--inject-qemu-ga METHOD]
|
|
||||||
- [--inject-virtio-win METHOD] [--install PKG,PKG..]
|
|
||||||
- [--link TARGET:LINK[:LINK..]] [--mkdir DIR] [--move SOURCE:DEST]
|
|
||||||
- [--password USER:SELECTOR] [--root-password SELECTOR]
|
|
||||||
- [--run SCRIPT] [--run-command 'CMD+ARGS'] [--scrub FILE]
|
|
||||||
- [--sm-attach SELECTOR] [--sm-register] [--sm-remove]
|
|
||||||
- [--sm-unregister] [--ssh-inject USER[:SELECTOR]]
|
|
||||||
- [--tar-in TARFILE:REMOTEDIR] [--timezone TIMEZONE] [--touch FILE]
|
|
||||||
- [--truncate FILE] [--truncate-recursive PATH]
|
|
||||||
- [--uninstall PKG,PKG..] [--update] [--upload FILE:DEST]
|
|
||||||
- [--write FILE:CONTENT] [--no-logfile]
|
|
||||||
+ [--hostname HOSTNAME]
|
|
||||||
+ [--inject-qemu-ga METHOD] [--inject-virtio-win METHOD]
|
|
||||||
+ [--install PKG,PKG..] [--link TARGET:LINK[:LINK..]] [--mkdir DIR]
|
|
||||||
+ [--move SOURCE:DEST] [--password USER:SELECTOR]
|
|
||||||
+ [--root-password SELECTOR] [--run SCRIPT]
|
|
||||||
+ [--run-command 'CMD+ARGS'] [--scrub FILE] [--sm-attach SELECTOR]
|
|
||||||
+ [--sm-register] [--sm-remove] [--sm-unregister]
|
|
||||||
+ [--ssh-inject USER[:SELECTOR]] [--tar-in TARFILE:REMOTEDIR]
|
|
||||||
+ [--timezone TIMEZONE] [--touch FILE] [--truncate FILE]
|
|
||||||
+ [--truncate-recursive PATH] [--uninstall PKG,PKG..] [--update]
|
|
||||||
+ [--upload FILE:DEST] [--write FILE:CONTENT] [--no-logfile]
|
|
||||||
[--password-crypto md5|sha256|sha512] [--no-selinux-relabel]
|
|
||||||
[--selinux-relabel] [--sm-credentials SELECTOR]
|
|
||||||
diff --git a/common/mlcustomize/customize_cmdline.ml b/common/mlcustomize/customize_cmdline.ml
|
|
||||||
index 48ee33445..c4d6a77d5 100644
|
|
||||||
--- a/common/mlcustomize/customize_cmdline.ml
|
|
||||||
+++ b/common/mlcustomize/customize_cmdline.ml
|
|
||||||
@@ -61,6 +61,8 @@ and op = [
|
|
||||||
(* --firstboot-install PKG,PKG.. *)
|
|
||||||
| `Hostname of string
|
|
||||||
(* --hostname HOSTNAME *)
|
|
||||||
+ | `InjectBalloonServer of string
|
|
||||||
+ (* --inject-blnsvr METHOD *)
|
|
||||||
| `InjectQemuGA of string
|
|
||||||
(* --inject-qemu-ga METHOD *)
|
|
||||||
| `InjectVirtioWin of string
|
|
||||||
diff --git a/common/mlcustomize/customize_cmdline.mli b/common/mlcustomize/customize_cmdline.mli
|
|
||||||
index 51a156eae..ee62961a1 100644
|
|
||||||
--- a/common/mlcustomize/customize_cmdline.mli
|
|
||||||
+++ b/common/mlcustomize/customize_cmdline.mli
|
|
||||||
@@ -53,6 +53,8 @@ and op = [
|
|
||||||
(* --firstboot-install PKG,PKG.. *)
|
|
||||||
| `Hostname of string
|
|
||||||
(* --hostname HOSTNAME *)
|
|
||||||
+ | `InjectBalloonServer of string
|
|
||||||
+ (* --inject-blnsvr METHOD *)
|
|
||||||
| `InjectQemuGA of string
|
|
||||||
(* --inject-qemu-ga METHOD *)
|
|
||||||
| `InjectVirtioWin of string
|
|
||||||
diff --git a/common/mlcustomize/firstboot.ml b/common/mlcustomize/firstboot.ml
|
|
||||||
index 5dc012340..52e76401e 100644
|
|
||||||
--- a/common/mlcustomize/firstboot.ml
|
|
||||||
+++ b/common/mlcustomize/firstboot.ml
|
|
||||||
@@ -239,7 +239,22 @@ WantedBy=%s
|
|
||||||
end
|
|
||||||
|
|
||||||
module Windows = struct
|
|
||||||
- let rec install_service (g : Guestfs.guestfs) root =
|
|
||||||
+ (* Create and return the firstboot directory. *)
|
|
||||||
+ let create_firstboot_dir (g : Guestfs.guestfs) =
|
|
||||||
+ let rec loop firstboot_dir firstboot_dir_win = function
|
|
||||||
+ | [] -> firstboot_dir, firstboot_dir_win
|
|
||||||
+ | dir :: path ->
|
|
||||||
+ let firstboot_dir =
|
|
||||||
+ if firstboot_dir = "" then "/" ^ dir else firstboot_dir // dir in
|
|
||||||
+ let firstboot_dir_win = firstboot_dir_win ^ "\\" ^ dir in
|
|
||||||
+ let firstboot_dir = g#case_sensitive_path firstboot_dir in
|
|
||||||
+ g#mkdir_p firstboot_dir;
|
|
||||||
+ loop firstboot_dir firstboot_dir_win path
|
|
||||||
+ in
|
|
||||||
+ loop "" "C:" ["Program Files"; "Guestfs"; "Firstboot"]
|
|
||||||
+
|
|
||||||
+ let rec install_service (g : Guestfs.guestfs) root
|
|
||||||
+ firstboot_dir firstboot_dir_win =
|
|
||||||
(* Either rhsrvany.exe or pvvxsvc.exe must exist.
|
|
||||||
*
|
|
||||||
* (Check also that it's not a dangling symlink but a real file).
|
|
||||||
@@ -254,20 +269,7 @@ module Windows = struct
|
|
||||||
error (f_"One of rhsrvany.exe or pvvxsvc.exe is missing in %s. One of them is required in order to install Windows firstboot scripts. You can get one by building rhsrvany (https://github.com/rwmjones/rhsrvany)")
|
|
||||||
(virt_tools_data_dir ()) in
|
|
||||||
|
|
||||||
- (* Create a directory for firstboot files in the guest. *)
|
|
||||||
- let firstboot_dir, firstboot_dir_win =
|
|
||||||
- let rec loop firstboot_dir firstboot_dir_win = function
|
|
||||||
- | [] -> firstboot_dir, firstboot_dir_win
|
|
||||||
- | dir :: path ->
|
|
||||||
- let firstboot_dir =
|
|
||||||
- if firstboot_dir = "" then "/" ^ dir else firstboot_dir // dir in
|
|
||||||
- let firstboot_dir_win = firstboot_dir_win ^ "\\" ^ dir in
|
|
||||||
- let firstboot_dir = g#case_sensitive_path firstboot_dir in
|
|
||||||
- g#mkdir_p firstboot_dir;
|
|
||||||
- loop firstboot_dir firstboot_dir_win path
|
|
||||||
- in
|
|
||||||
- loop "" "C:" ["Program Files"; "Guestfs"; "Firstboot"] in
|
|
||||||
-
|
|
||||||
+ (* Create a directory for firstboot scripts in the guest. *)
|
|
||||||
g#mkdir_p (firstboot_dir // "scripts");
|
|
||||||
|
|
||||||
(* Copy pvvxsvc or rhsrvany to the guest. *)
|
|
||||||
@@ -276,6 +278,9 @@ module Windows = struct
|
|
||||||
(* Write a firstboot.bat control script which just runs the other
|
|
||||||
* scripts in the directory. Note we need to use CRLF line endings
|
|
||||||
* in this script.
|
|
||||||
+ *
|
|
||||||
+ * XXX It would be better to use powershell here. For some ideas see
|
|
||||||
+ * https://github.com/HCK-CI/HLK-Setup-Scripts/
|
|
||||||
*)
|
|
||||||
let firstboot_script = sprintf "\
|
|
||||||
@echo off
|
|
||||||
@@ -297,6 +302,7 @@ if not exist \"%%scripts_done%%\" (
|
|
||||||
mkdir \"%%scripts_done%%\"
|
|
||||||
)
|
|
||||||
|
|
||||||
+:: Pick the next script to run.
|
|
||||||
for %%%%f in (\"%%scripts%%\"\\*.bat) do (
|
|
||||||
echo running \"%%%%f\"
|
|
||||||
move \"%%%%f\" \"%%scripts_done%%\"
|
|
||||||
@@ -305,8 +311,17 @@ for %%%%f in (\"%%scripts%%\"\\*.bat) do (
|
|
||||||
set elvl=!errorlevel!
|
|
||||||
echo .... exit code !elvl!
|
|
||||||
popd
|
|
||||||
+
|
|
||||||
+ :: Reboot the computer. This is necessary to free any locked
|
|
||||||
+ :: files which may prevent later scripts from running.
|
|
||||||
+ shutdown /r /t 0 /y
|
|
||||||
+
|
|
||||||
+ :: Exit the script (in case shutdown returns before rebooting).
|
|
||||||
+ :: On next boot, the whole firstboot service will be called again.
|
|
||||||
+ exit /b
|
|
||||||
)
|
|
||||||
|
|
||||||
+:: Fallthrough here if there are no scripts.
|
|
||||||
echo uninstalling firstboot service
|
|
||||||
\"%%firstboot%%\\%s\" -s firstboot uninstall
|
|
||||||
" firstboot_dir_win srvany in
|
|
||||||
@@ -339,11 +354,25 @@ echo uninstalling firstboot service
|
|
||||||
"PWD", REG_SZ firstboot_dir_win ];
|
|
||||||
] in
|
|
||||||
reg_import reg regedits
|
|
||||||
- );
|
|
||||||
-
|
|
||||||
- firstboot_dir
|
|
||||||
+ )
|
|
||||||
end
|
|
||||||
|
|
||||||
+let firstboot_dir (g : Guestfs.guestfs) root =
|
|
||||||
+ let typ = g#inspect_get_type root in
|
|
||||||
+
|
|
||||||
+ match typ with
|
|
||||||
+ | "linux" ->
|
|
||||||
+ let dir = Linux.firstboot_dir in
|
|
||||||
+ g#mkdir_p dir;
|
|
||||||
+ dir, None
|
|
||||||
+
|
|
||||||
+ | "windows" ->
|
|
||||||
+ let dir, dir_win = Windows.create_firstboot_dir g in
|
|
||||||
+ dir, Some dir_win
|
|
||||||
+
|
|
||||||
+ | _ ->
|
|
||||||
+ error (f_"guest type %s is not supported") typ
|
|
||||||
+
|
|
||||||
let script_count = ref 0
|
|
||||||
|
|
||||||
let add_firstboot_script (g : Guestfs.guestfs) root ?(prio = 5000) name
|
|
||||||
@@ -363,7 +392,8 @@ let add_firstboot_script (g : Guestfs.guestfs) root ?(prio = 5000) name
|
|
||||||
g#chmod 0o755 filename
|
|
||||||
|
|
||||||
| "windows", _ ->
|
|
||||||
- let firstboot_dir = Windows.install_service g root in
|
|
||||||
+ let firstboot_dir, firstboot_dir_win = Windows.create_firstboot_dir g in
|
|
||||||
+ Windows.install_service g root firstboot_dir firstboot_dir_win;
|
|
||||||
let filename = firstboot_dir // "scripts" // filename ^ ".bat" in
|
|
||||||
g#write filename (String.unix2dos content)
|
|
||||||
|
|
||||||
@@ -382,21 +412,18 @@ let add_firstboot_powershell g root ?prio name code =
|
|
||||||
*)
|
|
||||||
assert (g#inspect_get_type root = "windows");
|
|
||||||
|
|
||||||
- let windows_systemroot = g#inspect_get_windows_systemroot root in
|
|
||||||
-
|
|
||||||
- (* Create the temporary directory to put the Powershell file. *)
|
|
||||||
- let tempdir = sprintf "%s/Temp" windows_systemroot in
|
|
||||||
+ (* Place the Powershell script into firstboot_dir/Temp *)
|
|
||||||
+ let firstboot_dir, firstboot_dir_win = Windows.create_firstboot_dir g in
|
|
||||||
+ let tempdir = sprintf "%s/Temp" firstboot_dir in
|
|
||||||
g#mkdir_p tempdir;
|
|
||||||
+
|
|
||||||
+ let ps_path = sprintf "%s/%s.ps1" tempdir name in
|
|
||||||
+ let ps_path_win = sprintf "%s\\Temp\\%s.ps1" firstboot_dir_win name in
|
|
||||||
let code = String.concat "\r\n" code ^ "\r\n" in
|
|
||||||
- g#write (sprintf "%s/%s" tempdir name) code;
|
|
||||||
+ g#write ps_path code;
|
|
||||||
|
|
||||||
- (* Powershell interpreter. Should we check this exists? XXX *)
|
|
||||||
- let ps_exe =
|
|
||||||
- windows_systemroot ^
|
|
||||||
- "\\System32\\WindowsPowerShell\\v1.0\\powershell.exe" in
|
|
||||||
-
|
|
||||||
- (* Windows path to the Powershell script. *)
|
|
||||||
- let ps_path = windows_systemroot ^ "\\Temp\\" ^ name in
|
|
||||||
-
|
|
||||||
- let fb = sprintf "%s -ExecutionPolicy ByPass -file %s" ps_exe ps_path in
|
|
||||||
+ (* Create a regular firstboot bat that just invokes powershell *)
|
|
||||||
+ let fb =
|
|
||||||
+ sprintf "powershell.exe -ExecutionPolicy ByPass -NoProfile -file \"%s\""
|
|
||||||
+ ps_path_win in
|
|
||||||
add_firstboot_script g root ?prio name fb
|
|
||||||
diff --git a/common/mlcustomize/firstboot.mli b/common/mlcustomize/firstboot.mli
|
|
||||||
index 8231af658..34ff06901 100644
|
|
||||||
--- a/common/mlcustomize/firstboot.mli
|
|
||||||
+++ b/common/mlcustomize/firstboot.mli
|
|
||||||
@@ -16,6 +16,23 @@
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*)
|
|
||||||
|
|
||||||
+val firstboot_dir : Guestfs.guestfs -> string -> string * string option
|
|
||||||
+(** [firstboot_dir g root]
|
|
||||||
+ returns the path of the firstboot directory, creating it in
|
|
||||||
+ the guest if necessary.
|
|
||||||
+
|
|
||||||
+ This returns the name of the directory as a guestfs path, and
|
|
||||||
+ optionally the name as a Windows path (only for Windows guests).
|
|
||||||
+
|
|
||||||
+ For Linux this could be [/usr/lib/virt-sysprep, None]
|
|
||||||
+
|
|
||||||
+ For Windows this could be ["/Program Files/Guestfs/Firstboot",
|
|
||||||
+ Some "C:\Program Files\Guestfs\Firstboot"]
|
|
||||||
+
|
|
||||||
+ Additional files that are used during firstboot can be placed
|
|
||||||
+ in this directory, but be careful not to conflict with files
|
|
||||||
+ and scripts added by the firstboot process itself. *)
|
|
||||||
+
|
|
||||||
val add_firstboot_script : Guestfs.guestfs -> string -> ?prio:int -> string ->
|
|
||||||
string -> unit
|
|
||||||
(** [add_firstboot_script g root prio name content] adds a firstboot
|
|
||||||
diff --git a/common/mlcustomize/inject_virtio_win.ml b/common/mlcustomize/inject_virtio_win.ml
|
|
||||||
index 2a30b2008..afec1e456 100644
|
|
||||||
--- a/common/mlcustomize/inject_virtio_win.ml
|
|
||||||
+++ b/common/mlcustomize/inject_virtio_win.ml
|
|
||||||
@@ -24,6 +24,8 @@ open Common_gettext.Gettext
|
|
||||||
|
|
||||||
open Regedit
|
|
||||||
|
|
||||||
+let re_blnsvr = PCRE.compile ~caseless:true "\\bblnsvr\\.exe$"
|
|
||||||
+
|
|
||||||
type t = {
|
|
||||||
g : Guestfs.guestfs; (** guestfs handle *)
|
|
||||||
|
|
||||||
@@ -261,12 +263,38 @@ let rec inject_virtio_win_drivers ({ g } as t) reg =
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
-and inject_qemu_ga t =
|
|
||||||
- let msi_files = copy_qemu_ga t in
|
|
||||||
+and inject_qemu_ga ({ g; root } as t) =
|
|
||||||
+ (* Copy the qemu-ga MSI(s) to the guest. *)
|
|
||||||
+ let dir, dir_win = Firstboot.firstboot_dir g root in
|
|
||||||
+ let dir_win = Option.value dir_win ~default:dir in
|
|
||||||
+ let tempdir = sprintf "%s/Temp" dir in
|
|
||||||
+ let tempdir_win = sprintf "%s\\Temp" dir_win in
|
|
||||||
+ g#mkdir_p tempdir;
|
|
||||||
+
|
|
||||||
+ let msi_files = copy_qemu_ga t tempdir in
|
|
||||||
if msi_files <> [] then
|
|
||||||
- configure_qemu_ga t msi_files;
|
|
||||||
+ configure_qemu_ga t tempdir_win msi_files;
|
|
||||||
msi_files <> [] (* return true if we found some qemu-ga MSI files *)
|
|
||||||
|
|
||||||
+and inject_blnsvr ({ g; root } as t) =
|
|
||||||
+ (* Copy the files to the guest. *)
|
|
||||||
+ let dir, dir_win = Firstboot.firstboot_dir g root in
|
|
||||||
+ let dir_win = Option.value dir_win ~default:dir in
|
|
||||||
+ let tempdir = sprintf "%s/Temp" dir in
|
|
||||||
+ let tempdir_win = sprintf "%s\\Temp" dir_win in
|
|
||||||
+ g#mkdir_p tempdir;
|
|
||||||
+
|
|
||||||
+ let files = copy_blnsvr t tempdir in
|
|
||||||
+ match files with
|
|
||||||
+ | [] -> false (* Didn't find or install anything. *)
|
|
||||||
+
|
|
||||||
+ (* We usually find blnsvr.exe in two locations (drivers/by-os and
|
|
||||||
+ * drivers/by-driver). Pick the first.
|
|
||||||
+ *)
|
|
||||||
+ | blnsvr :: _ ->
|
|
||||||
+ configure_blnsvr t tempdir_win blnsvr;
|
|
||||||
+ true
|
|
||||||
+
|
|
||||||
and add_guestor_to_registry t ((g, root) as reg) drv_name drv_pciid =
|
|
||||||
let ddb_node = g#hivex_node_get_child root "DriverDatabase" in
|
|
||||||
|
|
||||||
@@ -346,8 +374,13 @@ and copy_drivers t driverdir =
|
|
||||||
(fun () ->
|
|
||||||
error (f_"root directory ‘/’ is missing from the virtio-win directory or ISO.\n\nThis should not happen and may indicate that virtio-win or virt-v2v is broken in some way. Please report this as a bug with a full debug log."))
|
|
||||||
|
|
||||||
-and copy_qemu_ga t =
|
|
||||||
- copy_from_virtio_win t "/" "/" (virtio_iso_path_matches_qemu_ga t)
|
|
||||||
+and copy_qemu_ga t tempdir =
|
|
||||||
+ copy_from_virtio_win t "/" tempdir (virtio_iso_path_matches_qemu_ga t)
|
|
||||||
+ (fun () ->
|
|
||||||
+ error (f_"root directory ‘/’ is missing from the virtio-win directory or ISO.\n\nThis should not happen and may indicate that virtio-win or virt-v2v is broken in some way. Please report this as a bug with a full debug log."))
|
|
||||||
+
|
|
||||||
+and copy_blnsvr t tempdir =
|
|
||||||
+ copy_from_virtio_win t "/" tempdir (virtio_iso_path_matches_blnsvr t)
|
|
||||||
(fun () ->
|
|
||||||
error (f_"root directory ‘/’ is missing from the virtio-win directory or ISO.\n\nThis should not happen and may indicate that virtio-win or virt-v2v is broken in some way. Please report this as a bug with a full debug log."))
|
|
||||||
|
|
||||||
@@ -513,6 +546,10 @@ and virtio_iso_path_matches_qemu_ga t path =
|
|
||||||
| ("x86_64", "rhev-qga64.msi") -> true
|
|
||||||
| _ -> false
|
|
||||||
|
|
||||||
+(* Find blnsvr for the current Windows version. *)
|
|
||||||
+and virtio_iso_path_matches_blnsvr t path =
|
|
||||||
+ virtio_iso_path_matches_guest_os t path && PCRE.matches re_blnsvr path
|
|
||||||
+
|
|
||||||
(* Look up in libosinfo for the OS, and copy all the locally
|
|
||||||
* available files specified as drivers for that OS to the [destdir].
|
|
||||||
*
|
|
||||||
@@ -552,37 +589,35 @@ and copy_from_libosinfo { g; i_osinfo; i_arch } destdir =
|
|
||||||
) driver.Libosinfo.files
|
|
||||||
with Not_found -> []
|
|
||||||
|
|
||||||
-and configure_qemu_ga t files =
|
|
||||||
+(* Install qemu-ga. [files] is the non-empty list of possible qemu-ga
|
|
||||||
+ * installers we detected.
|
|
||||||
+ *)
|
|
||||||
+and configure_qemu_ga t tempdir_win files =
|
|
||||||
+ let script = ref [] in
|
|
||||||
+ let add = List.push_back script in
|
|
||||||
+
|
|
||||||
+ add "# Virt-v2v script which installs QEMU Guest Agent";
|
|
||||||
+ add "";
|
|
||||||
+ add "# Uncomment this line for lots of debug output.";
|
|
||||||
+ add "# Set-PSDebug -Trace 2";
|
|
||||||
+ add "";
|
|
||||||
+ add "Write-Host Installing QEMU Guest Agent";
|
|
||||||
+ add "";
|
|
||||||
+ add "# Run qemu-ga installers";
|
|
||||||
List.iter (
|
|
||||||
- fun msi_path ->
|
|
||||||
- (* Windows is a trashfire.
|
|
||||||
- * https://stackoverflow.com/a/18730884
|
|
||||||
- * https://bugzilla.redhat.com/show_bug.cgi?id=1895323
|
|
||||||
- *)
|
|
||||||
- let psh_script = ref [] in
|
|
||||||
- let add = List.push_back psh_script in
|
|
||||||
+ fun msi ->
|
|
||||||
+ add (sprintf "Write-Host \"Writing log to %s\\%s.log\""
|
|
||||||
+ tempdir_win msi);
|
|
||||||
+ (* [`] is an escape char for quotes *)
|
|
||||||
+ add (sprintf "Start-Process -Wait -FilePath \"%s\\%s\" -ArgumentList \"/norestart\",\"/qn\",\"/l+*vx\",\"`\"%s\\%s.log`\"\""
|
|
||||||
+ tempdir_win msi tempdir_win msi)
|
|
||||||
+ ) files;
|
|
||||||
|
|
||||||
- add "# Uncomment this line for lots of debug output.";
|
|
||||||
- add "# Set-PSDebug -Trace 2";
|
|
||||||
- add "";
|
|
||||||
- add "Write-Host Removing any previously scheduled qemu-ga installation";
|
|
||||||
- add "schtasks.exe /Delete /TN Firstboot-qemu-ga /F";
|
|
||||||
- add "";
|
|
||||||
- add (sprintf
|
|
||||||
- "Write-Host Scheduling delayed installation of qemu-ga from %s"
|
|
||||||
- msi_path);
|
|
||||||
- add "$d = (get-date).AddSeconds(120)";
|
|
||||||
- add "$dtfinfo = [System.Globalization.DateTimeFormatInfo]::CurrentInfo";
|
|
||||||
- add "$sdp = $dtfinfo.ShortDatePattern";
|
|
||||||
- add "$sdp = $sdp -replace 'y+', 'yyyy'";
|
|
||||||
- add "$sdp = $sdp -replace 'M+', 'MM'";
|
|
||||||
- add "$sdp = $sdp -replace 'd+', 'dd'";
|
|
||||||
- add "schtasks.exe /Create /SC ONCE `";
|
|
||||||
- add " /ST $d.ToString('HH:mm') /SD $d.ToString($sdp) `";
|
|
||||||
- add " /RU SYSTEM /TN Firstboot-qemu-ga `";
|
|
||||||
- add (sprintf " /TR \"C:\\%s /forcerestart /qn /l+*vx C:\\%s.log\""
|
|
||||||
- msi_path msi_path);
|
|
||||||
+ Firstboot.add_firstboot_powershell t.g t.root "install-qemu-ga" !script
|
|
||||||
|
|
||||||
- Firstboot.add_firstboot_powershell t.g t.root
|
|
||||||
- (sprintf "install-%s.ps1" msi_path) !psh_script;
|
|
||||||
- ) files
|
|
||||||
+and configure_blnsvr t tempdir_win blnsvr =
|
|
||||||
+ let cmd = sprintf "\
|
|
||||||
+ @echo off\n\
|
|
||||||
+ echo Installing %s\n\
|
|
||||||
+ \"%s\\%s\" -i\n" blnsvr tempdir_win blnsvr in
|
|
||||||
+ Firstboot.add_firstboot_script t.g t.root "install-blnsvr" cmd
|
|
||||||
diff --git a/common/mlcustomize/inject_virtio_win.mli b/common/mlcustomize/inject_virtio_win.mli
|
|
||||||
index d14f04973..d273c4dd3 100644
|
|
||||||
--- a/common/mlcustomize/inject_virtio_win.mli
|
|
||||||
+++ b/common/mlcustomize/inject_virtio_win.mli
|
|
||||||
@@ -93,3 +93,11 @@ val inject_qemu_ga : t -> bool
|
|
||||||
the MSI(s).
|
|
||||||
|
|
||||||
Returns [true] iff we were able to inject qemu-ga. *)
|
|
||||||
+
|
|
||||||
+val inject_blnsvr : t -> bool
|
|
||||||
+(** Inject the Balloon Server ([blnsvr.exe]) into a Windows guest.
|
|
||||||
+
|
|
||||||
+ A firstboot script is also injected which should install
|
|
||||||
+ the server by running [blnsvr -i].
|
|
||||||
+
|
|
||||||
+ Returns [true] iff we were able to inject the Balloon Server. *)
|
|
||||||
diff --git a/common/mldrivers/linux_kernels.ml b/common/mldrivers/linux_kernels.ml
|
|
||||||
index 23ff76a55..e0b6b8a00 100644
|
|
||||||
--- a/common/mldrivers/linux_kernels.ml
|
|
||||||
+++ b/common/mldrivers/linux_kernels.ml
|
|
||||||
@@ -102,7 +102,7 @@ let detect_kernels (g : G.guestfs) root bootloader apps =
|
|
||||||
) apps in
|
|
||||||
if verbose () then (
|
|
||||||
let names = List.map (fun { G.app2_name = name } -> name) kernel_pkgs in
|
|
||||||
- eprintf "candidate kernel packages in this guest: %s%!\n"
|
|
||||||
+ eprintf "info: candidate kernel packages in this guest: %s%!\n"
|
|
||||||
(String.concat " " names)
|
|
||||||
);
|
|
||||||
List.filter_map (
|
|
||||||
@@ -306,7 +306,7 @@ let detect_kernels (g : G.guestfs) root bootloader apps =
|
|
||||||
) kernel_pkgs in
|
|
||||||
|
|
||||||
if verbose () then (
|
|
||||||
- eprintf "installed kernel packages in this guest:\n";
|
|
||||||
+ eprintf "info: installed kernel packages in this guest:\n";
|
|
||||||
List.iter (print_kernel_info stderr "\t") installed_kernels;
|
|
||||||
flush stderr
|
|
||||||
);
|
|
||||||
@@ -343,7 +343,7 @@ let detect_kernels (g : G.guestfs) root bootloader apps =
|
|
||||||
) vmlinuzes in
|
|
||||||
|
|
||||||
if verbose () then (
|
|
||||||
- eprintf "kernels offered by the bootloader in this guest (first in list is default):\n";
|
|
||||||
+ eprintf "info: kernels offered by the bootloader in this guest (first in list is default):\n";
|
|
||||||
List.iter (print_kernel_info stderr "\t") bootloader_kernels;
|
|
||||||
flush stderr
|
|
||||||
);
|
|
||||||
diff --git a/common/options/uri.c b/common/options/uri.c
|
|
||||||
index 84d393c1e..9180d6a27 100644
|
|
||||||
--- a/common/options/uri.c
|
|
||||||
+++ b/common/options/uri.c
|
|
||||||
@@ -99,7 +99,7 @@ is_uri (const char *arg)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (p--; p >= arg; p--) {
|
|
||||||
- if (!c_islower (*p))
|
|
||||||
+ if (! (c_islower (*p) || *p == '+'))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -148,7 +148,10 @@ parse (const char *arg, char **path_ret, char **protocol_ret,
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
- *protocol_ret = strdup (uri->scheme);
|
|
||||||
+ if (STREQ (uri->scheme, "nbd+unix"))
|
|
||||||
+ *protocol_ret = strdup ("nbd");
|
|
||||||
+ else
|
|
||||||
+ *protocol_ret = strdup (uri->scheme);
|
|
||||||
if (*protocol_ret == NULL) {
|
|
||||||
perror ("strdup: protocol");
|
|
||||||
return -1;
|
|
||||||
@@ -194,7 +197,7 @@ parse (const char *arg, char **path_ret, char **protocol_ret,
|
|
||||||
if (path && path[0] == '/' &&
|
|
||||||
(STREQ (uri->scheme, "gluster") ||
|
|
||||||
STREQ (uri->scheme, "iscsi") ||
|
|
||||||
- STREQ (uri->scheme, "nbd") ||
|
|
||||||
+ STRPREFIX (uri->scheme, "nbd") ||
|
|
||||||
STREQ (uri->scheme, "rbd") ||
|
|
||||||
STREQ (uri->scheme, "sheepdog")))
|
|
||||||
path++;
|
|
||||||
diff --git a/common/progress/progress.c b/common/progress/progress.c
|
|
||||||
index e4b30663f..5848abd70 100644
|
|
||||||
--- a/common/progress/progress.c
|
|
||||||
+++ b/common/progress/progress.c
|
|
||||||
@@ -123,6 +123,7 @@ progress_bar_init (unsigned flags)
|
|
||||||
bar->machine_readable = 1;
|
|
||||||
bar->utf8_mode = 0;
|
|
||||||
bar->have_terminfo = 0;
|
|
||||||
+ bar->fp = NULL;
|
|
||||||
} else {
|
|
||||||
bar->machine_readable = 0;
|
|
||||||
|
|
||||||
diff --git a/customize/customize_run.ml b/customize/customize_run.ml
|
|
||||||
index 1314d6e30..afced8c84 100644
|
|
||||||
--- a/customize/customize_run.ml
|
|
||||||
+++ b/customize/customize_run.ml
|
|
||||||
@@ -216,6 +216,9 @@ let run (g : G.guestfs) root (ops : ops) =
|
|
||||||
if not (Hostname.set_hostname g root hostname) then
|
|
||||||
warning (f_"hostname could not be set for this type of guest")
|
|
||||||
|
|
||||||
+ | `InjectBalloonServer _ ->
|
|
||||||
+ error "injecting the balloon server is not supported in RHEL 9.4, use RHEL 9.5 or above"
|
|
||||||
+
|
|
||||||
| `InjectQemuGA meth ->
|
|
||||||
(match get_virtio_win_handle "--inject-qemu-ga" meth with
|
|
||||||
| None -> ()
|
|
267
SOURCES/0005-builder-Replace-jansson-with-json-c.patch
Normal file
267
SOURCES/0005-builder-Replace-jansson-with-json-c.patch
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
From 02a911960b5916df93bf896afc94c8d250797f17 Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||||
|
Date: Tue, 22 Oct 2024 11:07:01 +0100
|
||||||
|
Subject: [PATCH] builder: Replace jansson with json-c
|
||||||
|
|
||||||
|
This pulls in the following common module commit which ports the
|
||||||
|
JSON_parser module from jansson to json-c:
|
||||||
|
|
||||||
|
Richard W.M. Jones (1):
|
||||||
|
mltools: Replace jansson with json-c
|
||||||
|
|
||||||
|
(cherry picked from commit 12997768d231b80dc219a518c287ecf10c83ff0e)
|
||||||
|
---
|
||||||
|
builder/Makefile.am | 2 +-
|
||||||
|
common | 2 +-
|
||||||
|
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/builder/Makefile.am b/builder/Makefile.am
|
||||||
|
index b474f0c9d..0761eff4c 100644
|
||||||
|
--- a/builder/Makefile.am
|
||||||
|
+++ b/builder/Makefile.am
|
||||||
|
@@ -206,7 +206,7 @@ OCAMLCLIBS = \
|
||||||
|
$(LIBLZMA_LIBS) \
|
||||||
|
$(LIBXML2_LIBS) \
|
||||||
|
$(LIBOSINFO_LIBS) \
|
||||||
|
- $(JANSSON_LIBS) \
|
||||||
|
+ $(JSON_C_LIBS) \
|
||||||
|
$(LIBINTL) \
|
||||||
|
-lgnu
|
||||||
|
|
||||||
|
Submodule common a78839676..766384a45:
|
||||||
|
diff --git a/common/mltools/JSON_parser-c.c b/common/mltools/JSON_parser-c.c
|
||||||
|
index bf38dd1bf..fb67b4632 100644
|
||||||
|
--- a/common/mltools/JSON_parser-c.c
|
||||||
|
+++ b/common/mltools/JSON_parser-c.c
|
||||||
|
@@ -23,7 +23,7 @@
|
||||||
|
#include <caml/memory.h>
|
||||||
|
#include <caml/mlvalues.h>
|
||||||
|
|
||||||
|
-#include <jansson.h>
|
||||||
|
+#include <json.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
@@ -40,7 +40,7 @@ value virt_builder_json_parser_tree_parse (value stringv);
|
||||||
|
value virt_builder_json_parser_tree_parse_file (value stringv);
|
||||||
|
|
||||||
|
static value
|
||||||
|
-convert_json_t (json_t *val, int level)
|
||||||
|
+convert_json_t (json_object *val, int level)
|
||||||
|
{
|
||||||
|
CAMLparam0 ();
|
||||||
|
CAMLlocal5 (rv, v, tv, sv, consv);
|
||||||
|
@@ -48,9 +48,11 @@ convert_json_t (json_t *val, int level)
|
||||||
|
if (level > 20)
|
||||||
|
caml_invalid_argument ("too many levels of object/array nesting");
|
||||||
|
|
||||||
|
- if (json_is_object (val)) {
|
||||||
|
+ switch (json_object_get_type (val)) {
|
||||||
|
+ case json_type_object: {
|
||||||
|
+ struct json_object_iterator it, itend;
|
||||||
|
const char *key;
|
||||||
|
- json_t *jvalue;
|
||||||
|
+ json_object *jvalue;
|
||||||
|
|
||||||
|
rv = caml_alloc (1, JSON_DICT_TAG);
|
||||||
|
v = Val_int (0);
|
||||||
|
@@ -60,29 +62,39 @@ convert_json_t (json_t *val, int level)
|
||||||
|
* matter (eg. simplestreams which incorrectly uses a dict when it
|
||||||
|
* really should use an array).
|
||||||
|
*/
|
||||||
|
- json_object_foreach (val, key, jvalue) {
|
||||||
|
+ it = json_object_iter_begin (val);
|
||||||
|
+ itend = json_object_iter_end (val);
|
||||||
|
+ while (!json_object_iter_equal (&it, &itend)) {
|
||||||
|
+ key = json_object_iter_peek_name (&it);
|
||||||
|
tv = caml_alloc_tuple (2);
|
||||||
|
sv = caml_copy_string (key);
|
||||||
|
Store_field (tv, 0, sv);
|
||||||
|
+
|
||||||
|
+ jvalue = json_object_iter_peek_value (&it);
|
||||||
|
sv = convert_json_t (jvalue, level + 1);
|
||||||
|
Store_field (tv, 1, sv);
|
||||||
|
+
|
||||||
|
consv = caml_alloc (2, 0);
|
||||||
|
Store_field (consv, 1, v);
|
||||||
|
Store_field (consv, 0, tv);
|
||||||
|
v = consv;
|
||||||
|
+
|
||||||
|
+ json_object_iter_next (&it);
|
||||||
|
}
|
||||||
|
Store_field (rv, 0, v);
|
||||||
|
+ break;
|
||||||
|
}
|
||||||
|
- else if (json_is_array (val)) {
|
||||||
|
- const size_t len = json_array_size (val);
|
||||||
|
+
|
||||||
|
+ case json_type_array: {
|
||||||
|
+ const size_t len = json_object_array_length (val);
|
||||||
|
size_t i;
|
||||||
|
- json_t *jvalue;
|
||||||
|
+ json_object *jvalue;
|
||||||
|
|
||||||
|
rv = caml_alloc (1, JSON_LIST_TAG);
|
||||||
|
v = Val_int (0);
|
||||||
|
for (i = 0; i < len; ++i) {
|
||||||
|
/* Note we have to create the OCaml list backwards. */
|
||||||
|
- jvalue = json_array_get (val, len-i-1);
|
||||||
|
+ jvalue = json_object_array_get_idx (val, len-i-1);
|
||||||
|
tv = convert_json_t (jvalue, level + 1);
|
||||||
|
consv = caml_alloc (2, 0);
|
||||||
|
Store_field (consv, 1, v);
|
||||||
|
@@ -90,32 +102,36 @@ convert_json_t (json_t *val, int level)
|
||||||
|
v = consv;
|
||||||
|
}
|
||||||
|
Store_field (rv, 0, v);
|
||||||
|
+ break;
|
||||||
|
}
|
||||||
|
- else if (json_is_string (val)) {
|
||||||
|
+
|
||||||
|
+ case json_type_string:
|
||||||
|
rv = caml_alloc (1, JSON_STRING_TAG);
|
||||||
|
- v = caml_copy_string (json_string_value (val));
|
||||||
|
+ v = caml_copy_string (json_object_get_string (val));
|
||||||
|
Store_field (rv, 0, v);
|
||||||
|
- }
|
||||||
|
- else if (json_is_real (val)) {
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ case json_type_double:
|
||||||
|
rv = caml_alloc (1, JSON_FLOAT_TAG);
|
||||||
|
- v = caml_copy_double (json_real_value (val));
|
||||||
|
+ v = caml_copy_double (json_object_get_double (val));
|
||||||
|
Store_field (rv, 0, v);
|
||||||
|
- }
|
||||||
|
- else if (json_is_integer (val)) {
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ case json_type_int:
|
||||||
|
rv = caml_alloc (1, JSON_INT_TAG);
|
||||||
|
- v = caml_copy_int64 (json_integer_value (val));
|
||||||
|
+ v = caml_copy_int64 (json_object_get_int64 (val));
|
||||||
|
Store_field (rv, 0, v);
|
||||||
|
- }
|
||||||
|
- else if (json_is_true (val)) {
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ case json_type_boolean:
|
||||||
|
rv = caml_alloc (1, JSON_BOOL_TAG);
|
||||||
|
- Store_field (rv, 0, Val_true);
|
||||||
|
- }
|
||||||
|
- else if (json_is_false (val)) {
|
||||||
|
- rv = caml_alloc (1, JSON_BOOL_TAG);
|
||||||
|
- Store_field (rv, 0, Val_false);
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
+ Store_field (rv, 0, json_object_get_boolean (val) ? Val_true : Val_false);
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ case json_type_null:
|
||||||
|
rv = JSON_NULL;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
CAMLreturn (rv);
|
||||||
|
}
|
||||||
|
@@ -125,45 +141,28 @@ virt_builder_json_parser_tree_parse (value stringv)
|
||||||
|
{
|
||||||
|
CAMLparam1 (stringv);
|
||||||
|
CAMLlocal1 (rv);
|
||||||
|
- json_t *tree;
|
||||||
|
- json_error_t err;
|
||||||
|
+ json_object *tree = NULL;
|
||||||
|
+ json_tokener *tok = NULL;
|
||||||
|
+ enum json_tokener_error err;
|
||||||
|
|
||||||
|
- tree = json_loads (String_val (stringv), JSON_DECODE_ANY, &err);
|
||||||
|
- if (tree == NULL) {
|
||||||
|
- char buf[256 + JSON_ERROR_TEXT_LENGTH];
|
||||||
|
- if (strlen (err.text) > 0)
|
||||||
|
- snprintf (buf, sizeof buf, "JSON parse error: %s", err.text);
|
||||||
|
- else
|
||||||
|
- snprintf (buf, sizeof buf, "unknown JSON parse error");
|
||||||
|
+ tok = json_tokener_new ();
|
||||||
|
+ json_tokener_set_flags (tok,
|
||||||
|
+ JSON_TOKENER_STRICT | JSON_TOKENER_VALIDATE_UTF8);
|
||||||
|
+ tree = json_tokener_parse_ex (tok,
|
||||||
|
+ String_val (stringv),
|
||||||
|
+ caml_string_length (stringv));
|
||||||
|
+ err = json_tokener_get_error (tok);
|
||||||
|
+ if (err != json_tokener_success) {
|
||||||
|
+ char buf[256];
|
||||||
|
+ snprintf (buf, sizeof buf, "JSON parse error: %s",
|
||||||
|
+ json_tokener_error_desc (err));
|
||||||
|
+ json_tokener_free (tok);
|
||||||
|
caml_invalid_argument (buf);
|
||||||
|
}
|
||||||
|
+ json_tokener_free (tok);
|
||||||
|
|
||||||
|
rv = convert_json_t (tree, 1);
|
||||||
|
- json_decref (tree);
|
||||||
|
-
|
||||||
|
- CAMLreturn (rv);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-value
|
||||||
|
-virt_builder_json_parser_tree_parse_file (value filev)
|
||||||
|
-{
|
||||||
|
- CAMLparam1 (filev);
|
||||||
|
- CAMLlocal1 (rv);
|
||||||
|
- json_t *tree;
|
||||||
|
- json_error_t err;
|
||||||
|
-
|
||||||
|
- tree = json_load_file (String_val (filev), JSON_DECODE_ANY, &err);
|
||||||
|
- if (tree == NULL) {
|
||||||
|
- char buf[1024 + JSON_ERROR_TEXT_LENGTH];
|
||||||
|
- if (strlen (err.text) > 0)
|
||||||
|
- snprintf (buf, sizeof buf, "%s: JSON parse error: %s", String_val (filev), err.text);
|
||||||
|
- else
|
||||||
|
- snprintf (buf, sizeof buf, "%s: unknown JSON parse error", String_val (filev));
|
||||||
|
- caml_invalid_argument (buf);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- rv = convert_json_t (tree, 1);
|
||||||
|
- json_decref (tree);
|
||||||
|
+ json_object_put (tree);
|
||||||
|
|
||||||
|
CAMLreturn (rv);
|
||||||
|
}
|
||||||
|
diff --git a/common/mltools/JSON_parser.ml b/common/mltools/JSON_parser.ml
|
||||||
|
index 933057277..8bc35abdc 100644
|
||||||
|
--- a/common/mltools/JSON_parser.ml
|
||||||
|
+++ b/common/mltools/JSON_parser.ml
|
||||||
|
@@ -21,7 +21,10 @@ open Tools_utils
|
||||||
|
open Common_gettext.Gettext
|
||||||
|
|
||||||
|
external json_parser_tree_parse : string -> JSON.json_t = "virt_builder_json_parser_tree_parse"
|
||||||
|
-external json_parser_tree_parse_file : string -> JSON.json_t = "virt_builder_json_parser_tree_parse_file"
|
||||||
|
+
|
||||||
|
+let json_parser_tree_parse_file filename =
|
||||||
|
+ let content = read_whole_file filename in
|
||||||
|
+ json_parser_tree_parse content
|
||||||
|
|
||||||
|
let object_find_optional key = function
|
||||||
|
| JSON.Dict fields ->
|
||||||
|
diff --git a/common/mltools/Makefile.am b/common/mltools/Makefile.am
|
||||||
|
index f510a6747..684c26946 100644
|
||||||
|
--- a/common/mltools/Makefile.am
|
||||||
|
+++ b/common/mltools/Makefile.am
|
||||||
|
@@ -116,7 +116,7 @@ libmltools_a_CFLAGS = \
|
||||||
|
$(LIBVIRT_CFLAGS) \
|
||||||
|
$(LIBXML2_CFLAGS) \
|
||||||
|
$(LIBGUESTFS_CFLAGS) \
|
||||||
|
- $(JANSSON_CFLAGS) \
|
||||||
|
+ $(JSON_C_CFLAGS) \
|
||||||
|
$(LIBOSINFO_CFLAGS) \
|
||||||
|
-fPIC
|
||||||
|
|
||||||
|
@@ -148,7 +148,7 @@ OCAMLCLIBS = \
|
||||||
|
$(LIBCRYPT_LIBS) \
|
||||||
|
$(LIBVIRT_LIBS) \
|
||||||
|
$(LIBXML2_LIBS) \
|
||||||
|
- $(JANSSON_LIBS) \
|
||||||
|
+ $(JSON_C_LIBS) \
|
||||||
|
$(LIBOSINFO_LIBS) \
|
||||||
|
$(LIBINTL) \
|
||||||
|
-lgnu
|
27
SOURCES/0006-build-Remove-Jansson-dependency.patch
Normal file
27
SOURCES/0006-build-Remove-Jansson-dependency.patch
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
From 5879249a32d50ab746f515abc2679b91f64a2098 Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||||
|
Date: Tue, 22 Oct 2024 15:22:18 +0100
|
||||||
|
Subject: [PATCH] build: Remove Jansson dependency
|
||||||
|
|
||||||
|
After previous changes, this library is no longer used. We have
|
||||||
|
switched to json-c, for better compatibility with libvirt.
|
||||||
|
|
||||||
|
(cherry picked from commit e6dcf7e3a7e9170978e57ce6df1b34f92fac5ae3)
|
||||||
|
---
|
||||||
|
m4/guestfs-libraries.m4 | 3 ---
|
||||||
|
1 file changed, 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/m4/guestfs-libraries.m4 b/m4/guestfs-libraries.m4
|
||||||
|
index b76511982..80f9425f0 100644
|
||||||
|
--- a/m4/guestfs-libraries.m4
|
||||||
|
+++ b/m4/guestfs-libraries.m4
|
||||||
|
@@ -164,9 +164,6 @@ LIBS="$LIBS $LIBXML2_LIBS"
|
||||||
|
AC_CHECK_FUNCS([xmlBufferDetach])
|
||||||
|
LIBS="$old_LIBS"
|
||||||
|
|
||||||
|
-dnl Check for Jansson JSON library (required).
|
||||||
|
-PKG_CHECK_MODULES([JANSSON], [jansson >= 2.7])
|
||||||
|
-
|
||||||
|
dnl Check for JSON-C library (required).
|
||||||
|
PKG_CHECK_MODULES([JSON_C], [json-c >= 0.14])
|
||||||
|
|
@ -0,0 +1,151 @@
|
|||||||
|
From 065f95e7afa45bf465e8799baa11c019f9403bd6 Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||||
|
Date: Wed, 19 Feb 2025 15:15:30 +0000
|
||||||
|
Subject: [PATCH] test-data: phony fedora: Add simple static /bin/sh
|
||||||
|
|
||||||
|
This is able to do enough to run commands via g#sh and related calls
|
||||||
|
inside the phony Fedora image.
|
||||||
|
|
||||||
|
(cherry picked from commit 4c5854f54e1da0d96807acb1b047bbf34694a0bb)
|
||||||
|
---
|
||||||
|
cat/test-virt-ls.sh | 1 +
|
||||||
|
test-data/phony-guests/fedora.c | 76 +++++++++++++++++++++--
|
||||||
|
test-data/phony-guests/make-fedora-img.pl | 6 +-
|
||||||
|
3 files changed, 76 insertions(+), 7 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/cat/test-virt-ls.sh b/cat/test-virt-ls.sh
|
||||||
|
index e98faa42b..577a44860 100755
|
||||||
|
--- a/cat/test-virt-ls.sh
|
||||||
|
+++ b/cat/test-virt-ls.sh
|
||||||
|
@@ -24,6 +24,7 @@ skip_if_skipped
|
||||||
|
# Read out the test directory using virt-ls.
|
||||||
|
if [ "$($VG virt-ls --format=raw -a ../test-data/phony-guests/fedora.img /bin)" != "ls
|
||||||
|
rpm
|
||||||
|
+sh
|
||||||
|
test1
|
||||||
|
test2
|
||||||
|
test3
|
||||||
|
diff --git a/test-data/phony-guests/fedora.c b/test-data/phony-guests/fedora.c
|
||||||
|
index c57fa57cc..df097e9e6 100644
|
||||||
|
--- a/test-data/phony-guests/fedora.c
|
||||||
|
+++ b/test-data/phony-guests/fedora.c
|
||||||
|
@@ -16,13 +16,14 @@
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
-/* This is "just enough" of a binary to look like RPM and dracut, as
|
||||||
|
- * far as virt-v2v is concerned.
|
||||||
|
+/* This is "just enough" of a binary to look like /bin/sh, RPM and
|
||||||
|
+ * dracut, as far as virt-v2v is concerned.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
+#include <unistd.h>
|
||||||
|
|
||||||
|
/* NB: This is also defined in make-fedora-img.pl */
|
||||||
|
#define KVER "5.19.0-0.rc1.14.fc37.x86_64"
|
||||||
|
@@ -34,6 +35,27 @@ get_basename (const char *str)
|
||||||
|
return ret == NULL ? str : ret + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void
|
||||||
|
+add_str (char ***argv, size_t *argc, char *str)
|
||||||
|
+{
|
||||||
|
+ (*argc)++;
|
||||||
|
+ (*argv) = realloc (*argv, *argc * sizeof (char *));
|
||||||
|
+ (*argv)[*argc-1] = str;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+add_null (char ***argv, size_t *argc)
|
||||||
|
+{
|
||||||
|
+ add_str (argv, argc, NULL);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+add (char ***argv, size_t *argc, const char *s, size_t len)
|
||||||
|
+{
|
||||||
|
+ char *copy = strndup (s, len);
|
||||||
|
+ add_str (argv, argc, copy);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
@@ -57,10 +79,54 @@ main (int argc, char *argv[])
|
||||||
|
strcmp (get_basename (argv[0]), "dracut") == 0) {
|
||||||
|
// do nothing, pretend to rebuild the initramfs
|
||||||
|
}
|
||||||
|
+ else if (argc == 3 &&
|
||||||
|
+ strcmp (get_basename (argv[0]), "sh") == 0 &&
|
||||||
|
+ strcmp (argv[1], "-c") == 0) {
|
||||||
|
+ /* Split the command and execute it. Only handles trivial cases. */
|
||||||
|
+ char *cmd = argv[2];
|
||||||
|
+ char **cmdv = NULL;
|
||||||
|
+ size_t i, cmdvlen = 0, n;
|
||||||
|
+ const size_t len = strlen (cmd);
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < len;) {
|
||||||
|
+ switch (cmd[i]) {
|
||||||
|
+ case ' ': case '\t':
|
||||||
|
+ i++;
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ case '"':
|
||||||
|
+ n = strcspn (&cmd[i+1], "\"");
|
||||||
|
+ add (&cmdv, &cmdvlen, &cmd[i+1], n);
|
||||||
|
+ i += n+2;
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ case '\'':
|
||||||
|
+ n = strcspn (&cmd[i+1], "'");
|
||||||
|
+ add (&cmdv, &cmdvlen, &cmd[i+1], n);
|
||||||
|
+ i += n+2;
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ default:
|
||||||
|
+ n = strcspn (&cmd[i], " \t");
|
||||||
|
+ add (&cmdv, &cmdvlen, &cmd[i], n);
|
||||||
|
+ i += n;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ add_null (&cmdv, &cmdvlen);
|
||||||
|
+
|
||||||
|
+ execvp (cmdv[0], cmdv);
|
||||||
|
+ perror (cmdv[0]);
|
||||||
|
+ exit (EXIT_FAILURE);
|
||||||
|
+ }
|
||||||
|
else {
|
||||||
|
- fprintf (stderr, "phony Fedora: unknown command\n");
|
||||||
|
- exit (1);
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ fprintf (stderr, "ERROR: test-data/phony-guests/fedora.c: "
|
||||||
|
+ "unexpected command:\n");
|
||||||
|
+ for (i = 0; i < argc; ++i)
|
||||||
|
+ fprintf (stderr, "argv[%d] = %s\n", i, argv[i]);
|
||||||
|
+ exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
- exit (0);
|
||||||
|
+ exit (EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
diff --git a/test-data/phony-guests/make-fedora-img.pl b/test-data/phony-guests/make-fedora-img.pl
|
||||||
|
index 0de506324..fef8ce032 100755
|
||||||
|
--- a/test-data/phony-guests/make-fedora-img.pl
|
||||||
|
+++ b/test-data/phony-guests/make-fedora-img.pl
|
||||||
|
@@ -369,8 +369,10 @@ $g->ln_s ('/bin/test1', '/bin/test5');
|
||||||
|
$g->mkfifo (0777, '/bin/test6');
|
||||||
|
$g->mknod (0777, 10, 10, '/bin/test7');
|
||||||
|
|
||||||
|
-# Virt-v2v needs an RPM command, or at least something which acts
|
||||||
|
-# similarly, and also a dracut command.
|
||||||
|
+# Virt-v2v needs a /bin/sh, an RPM command and a dracut command, or at
|
||||||
|
+# least something which acts similarly to those.
|
||||||
|
+$g->upload ('fedora-static-bin', '/bin/sh');
|
||||||
|
+$g->chmod (0777, '/bin/sh');
|
||||||
|
$g->upload ('fedora-static-bin', '/bin/rpm');
|
||||||
|
$g->chmod (0777, '/bin/rpm');
|
||||||
|
$g->upload ('fedora-static-bin', '/sbin/dracut');
|
@ -0,0 +1,343 @@
|
|||||||
|
From 777f3ac82c20469c9e438b9fd88a57007fd2c2bb Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||||
|
Date: Wed, 19 Feb 2025 14:16:13 +0000
|
||||||
|
Subject: [PATCH] drivers: Handle large output from 'rpm -ql' command
|
||||||
|
|
||||||
|
This requires the new guestfs_sh_out API from libguestfs 1.55.6.
|
||||||
|
|
||||||
|
Update common submodule to include:
|
||||||
|
|
||||||
|
Richard W.M. Jones (3):
|
||||||
|
mlstdutils: Reimplement String.find, add String.find_from
|
||||||
|
mlstdutils: Reimplement String.nsplit tail recursively
|
||||||
|
mldrivers: Handle large output from 'rpm -ql' command
|
||||||
|
|
||||||
|
Fixes: https://issues.redhat.com/browse/RHEL-80214
|
||||||
|
Reported-by: Nijin Ashok
|
||||||
|
(cherry picked from commit 5520f1cfae55377c2fe1db3f2974f6006822e0ea)
|
||||||
|
---
|
||||||
|
common | 2 +-
|
||||||
|
m4/guestfs-libraries.m4 | 5 ++---
|
||||||
|
2 files changed, 3 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
Submodule common 766384a45..ee88791e1:
|
||||||
|
diff --git a/common/mldrivers/linux.ml b/common/mldrivers/linux.ml
|
||||||
|
index 4e30a8e1f..0dec15495 100644
|
||||||
|
--- a/common/mldrivers/linux.ml
|
||||||
|
+++ b/common/mldrivers/linux.ml
|
||||||
|
@@ -58,76 +58,84 @@ and do_remove g root packages =
|
||||||
|
|
||||||
|
let file_list_of_package (g : Guestfs.guestfs) root app =
|
||||||
|
let package_format = g#inspect_get_package_format root in
|
||||||
|
- match package_format with
|
||||||
|
- | "deb" ->
|
||||||
|
- let cmd = [| "dpkg"; "-L"; app.G.app2_name |] in
|
||||||
|
- debug "%s" (String.concat " " (Array.to_list cmd));
|
||||||
|
- let files = g#command_lines cmd in
|
||||||
|
- let files = Array.to_list files in
|
||||||
|
+
|
||||||
|
+ let cmd =
|
||||||
|
+ match package_format with
|
||||||
|
+ | "deb" -> sprintf "dpkg -L %s" (quote app.G.app2_name)
|
||||||
|
+
|
||||||
|
+ | "rpm" ->
|
||||||
|
+ (* Since RPM allows multiple packages installed with the same
|
||||||
|
+ * name, always check the full NEVR here (RHBZ#1161250).
|
||||||
|
+ *
|
||||||
|
+ * In RPM < 4.11 query commands that use the epoch number in the
|
||||||
|
+ * package name did not work.
|
||||||
|
+ *
|
||||||
|
+ * For example:
|
||||||
|
+ * RHEL 6 (rpm 4.8.0):
|
||||||
|
+ * $ rpm -q tar-2:1.23-11.el6.x86_64
|
||||||
|
+ * package tar-2:1.23-11.el6.x86_64 is not installed
|
||||||
|
+ * Fedora 20 (rpm 4.11.2):
|
||||||
|
+ * $ rpm -q tar-2:1.26-30.fc20.x86_64
|
||||||
|
+ * tar-1.26-30.fc20.x86_64
|
||||||
|
+ *)
|
||||||
|
+ let is_rpm_lt_4_11 () =
|
||||||
|
+ let ver =
|
||||||
|
+ try
|
||||||
|
+ (* Since we're going to run 'rpm' below anyway, seems safe
|
||||||
|
+ * to run it here and assume the binary works.
|
||||||
|
+ *)
|
||||||
|
+ let cmd = [| "rpm"; "--version" |] in
|
||||||
|
+ debug "%s" (String.concat " " (Array.to_list cmd));
|
||||||
|
+ let ver = g#command_lines cmd in
|
||||||
|
+ let ver =
|
||||||
|
+ if Array.length ver > 0 then ver.(0) else raise Not_found in
|
||||||
|
+ debug "%s" ver;
|
||||||
|
+ let ver = String.nsplit " " ver in
|
||||||
|
+ let ver =
|
||||||
|
+ match ver with
|
||||||
|
+ | [ "RPM"; "version"; ver ] -> ver
|
||||||
|
+ | _ -> raise Not_found in
|
||||||
|
+ if not (PCRE.matches re_version ver) then raise Not_found;
|
||||||
|
+ (int_of_string (PCRE.sub 1), int_of_string (PCRE.sub 2))
|
||||||
|
+ with Not_found ->
|
||||||
|
+ (* 'rpm' not installed? Hmm... *)
|
||||||
|
+ (0, 0) in
|
||||||
|
+ ver < (4, 11)
|
||||||
|
+ in
|
||||||
|
+ let pkg_name =
|
||||||
|
+ if app.G.app2_epoch = Int32.zero || is_rpm_lt_4_11 () then
|
||||||
|
+ sprintf "%s-%s-%s" app.G.app2_name app.G.app2_version
|
||||||
|
+ app.G.app2_release
|
||||||
|
+ else
|
||||||
|
+ sprintf "%s-%ld:%s-%s" app.G.app2_name app.G.app2_epoch
|
||||||
|
+ app.G.app2_version app.G.app2_release in
|
||||||
|
+ sprintf "rpm -ql %s" (quote pkg_name)
|
||||||
|
+
|
||||||
|
+ | format ->
|
||||||
|
+ error (f_"don’t know how to get list of files from package using %s")
|
||||||
|
+ format in
|
||||||
|
+
|
||||||
|
+ debug "file_list_of_package: running: %s" cmd;
|
||||||
|
+
|
||||||
|
+ (* Some packages have a lot of files, too many to list without
|
||||||
|
+ * breaking the maximum message size assumption in libguestfs.
|
||||||
|
+ * To cope with this, use guestfs_sh_out, added in 1.55.6.
|
||||||
|
+ * https://issues.redhat.com/browse/RHEL-80080
|
||||||
|
+ *)
|
||||||
|
+ let tmpfile = Filename.temp_file "v2vcmd" ".out" in
|
||||||
|
+ On_exit.unlink tmpfile;
|
||||||
|
+ g#sh_out cmd tmpfile;
|
||||||
|
+ let files = read_whole_file tmpfile in
|
||||||
|
+
|
||||||
|
+ (* RPM prints "(contains no files)" on stdout when a package
|
||||||
|
+ * has no files in it:
|
||||||
|
+ * https://github.com/rpm-software-management/rpm/issues/962
|
||||||
|
+ *)
|
||||||
|
+ if String.is_prefix files "(contains no files)" then []
|
||||||
|
+ else (
|
||||||
|
+ let files = String.nsplit "\n" files in
|
||||||
|
List.sort compare files
|
||||||
|
-
|
||||||
|
- | "rpm" ->
|
||||||
|
- (* Since RPM allows multiple packages installed with the same
|
||||||
|
- * name, always check the full NEVR here (RHBZ#1161250).
|
||||||
|
- *
|
||||||
|
- * In RPM < 4.11 query commands that use the epoch number in the
|
||||||
|
- * package name did not work.
|
||||||
|
- *
|
||||||
|
- * For example:
|
||||||
|
- * RHEL 6 (rpm 4.8.0):
|
||||||
|
- * $ rpm -q tar-2:1.23-11.el6.x86_64
|
||||||
|
- * package tar-2:1.23-11.el6.x86_64 is not installed
|
||||||
|
- * Fedora 20 (rpm 4.11.2):
|
||||||
|
- * $ rpm -q tar-2:1.26-30.fc20.x86_64
|
||||||
|
- * tar-1.26-30.fc20.x86_64
|
||||||
|
- *)
|
||||||
|
- let is_rpm_lt_4_11 () =
|
||||||
|
- let ver =
|
||||||
|
- try
|
||||||
|
- (* Since we're going to run 'rpm' below anyway, seems safe
|
||||||
|
- * to run it here and assume the binary works.
|
||||||
|
- *)
|
||||||
|
- let cmd = [| "rpm"; "--version" |] in
|
||||||
|
- debug "%s" (String.concat " " (Array.to_list cmd));
|
||||||
|
- let ver = g#command_lines cmd in
|
||||||
|
- let ver = if Array.length ver > 0 then ver.(0) else raise Not_found in
|
||||||
|
- debug "%s" ver;
|
||||||
|
- let ver = String.nsplit " " ver in
|
||||||
|
- let ver =
|
||||||
|
- match ver with
|
||||||
|
- | [ "RPM"; "version"; ver ] -> ver
|
||||||
|
- | _ -> raise Not_found in
|
||||||
|
- if not (PCRE.matches re_version ver) then raise Not_found;
|
||||||
|
- (int_of_string (PCRE.sub 1), int_of_string (PCRE.sub 2))
|
||||||
|
- with Not_found ->
|
||||||
|
- (* 'rpm' not installed? Hmm... *)
|
||||||
|
- (0, 0) in
|
||||||
|
- ver < (4, 11)
|
||||||
|
- in
|
||||||
|
- let pkg_name =
|
||||||
|
- if app.G.app2_epoch = Int32.zero || is_rpm_lt_4_11 () then
|
||||||
|
- sprintf "%s-%s-%s" app.G.app2_name app.G.app2_version
|
||||||
|
- app.G.app2_release
|
||||||
|
- else
|
||||||
|
- sprintf "%s-%ld:%s-%s" app.G.app2_name app.G.app2_epoch
|
||||||
|
- app.G.app2_version app.G.app2_release in
|
||||||
|
- let cmd = [| "rpm"; "-ql"; pkg_name |] in
|
||||||
|
- debug "%s" (String.concat " " (Array.to_list cmd));
|
||||||
|
- let files = g#command_lines cmd in
|
||||||
|
- (* RPM prints "(contains no files)" on stdout when a package
|
||||||
|
- * has no files in it:
|
||||||
|
- * https://github.com/rpm-software-management/rpm/issues/962
|
||||||
|
- *)
|
||||||
|
- if files = [| "(contains no files)" |] then
|
||||||
|
- []
|
||||||
|
- else (
|
||||||
|
- let files = Array.to_list files in
|
||||||
|
- List.sort compare files
|
||||||
|
- )
|
||||||
|
-
|
||||||
|
- | format ->
|
||||||
|
- error (f_"don’t know how to get list of files from package using %s")
|
||||||
|
- format
|
||||||
|
+ )
|
||||||
|
|
||||||
|
let is_file_owned (g : G.guestfs) root path =
|
||||||
|
let package_format = g#inspect_get_package_format root in
|
||||||
|
diff --git a/common/mlstdutils/std_utils.ml b/common/mlstdutils/std_utils.ml
|
||||||
|
index 86b21a7c5..1a36ab772 100644
|
||||||
|
--- a/common/mlstdutils/std_utils.ml
|
||||||
|
+++ b/common/mlstdutils/std_utils.ml
|
||||||
|
@@ -98,24 +98,27 @@ module String = struct
|
||||||
|
and len = length str in
|
||||||
|
len >= sufflen && sub str (len - sufflen) sufflen = suffix
|
||||||
|
|
||||||
|
- let rec find s sub =
|
||||||
|
- let len = length s in
|
||||||
|
+ let find_from str pos sub =
|
||||||
|
let sublen = length sub in
|
||||||
|
- let rec loop i =
|
||||||
|
- if i <= len-sublen then (
|
||||||
|
- let rec loop2 j =
|
||||||
|
- if j < sublen then (
|
||||||
|
- if s.[i+j] = sub.[j] then loop2 (j+1)
|
||||||
|
- else -1
|
||||||
|
- ) else
|
||||||
|
- i (* found *)
|
||||||
|
- in
|
||||||
|
- let r = loop2 0 in
|
||||||
|
- if r = -1 then loop (i+1) else r
|
||||||
|
- ) else
|
||||||
|
- -1 (* not found *)
|
||||||
|
- in
|
||||||
|
- loop 0
|
||||||
|
+ if sublen = 0 then
|
||||||
|
+ 0
|
||||||
|
+ else (
|
||||||
|
+ let found = ref 0 in
|
||||||
|
+ let len = length str in
|
||||||
|
+ try
|
||||||
|
+ for i = pos to len - sublen do
|
||||||
|
+ let j = ref 0 in
|
||||||
|
+ while unsafe_get str (i + !j) = unsafe_get sub !j do
|
||||||
|
+ incr j;
|
||||||
|
+ if !j = sublen then begin found := i; raise Exit; end;
|
||||||
|
+ done;
|
||||||
|
+ done;
|
||||||
|
+ -1
|
||||||
|
+ with
|
||||||
|
+ Exit -> !found
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ let find str sub = find_from str 0 sub
|
||||||
|
|
||||||
|
let rec replace s s1 s2 =
|
||||||
|
let len = length s in
|
||||||
|
@@ -145,7 +148,7 @@ module String = struct
|
||||||
|
else if n >= len then str, ""
|
||||||
|
else sub str 0 n, sub str n (len-n)
|
||||||
|
|
||||||
|
- let rec split sep str =
|
||||||
|
+ let split sep str =
|
||||||
|
let seplen = length sep in
|
||||||
|
let strlen = length str in
|
||||||
|
let i = find str sep in
|
||||||
|
@@ -154,20 +157,36 @@ module String = struct
|
||||||
|
sub str 0 i, sub str (i + seplen) (strlen - i - seplen)
|
||||||
|
)
|
||||||
|
|
||||||
|
- and nsplit ?(max = 0) sep str =
|
||||||
|
+ let nsplit ?(max = 0) sep str =
|
||||||
|
if max < 0 then
|
||||||
|
invalid_arg "String.nsplit: max parameter should not be negative";
|
||||||
|
|
||||||
|
- (* If we reached the limit, OR if the pattern does not match the string
|
||||||
|
- * at all, return the rest of the string as a single element list.
|
||||||
|
- *)
|
||||||
|
- if max = 1 || find str sep = -1 then
|
||||||
|
- [str]
|
||||||
|
- else (
|
||||||
|
- let s1, s2 = split sep str in
|
||||||
|
- let max = if max = 0 then 0 else max - 1 in
|
||||||
|
- s1 :: nsplit ~max sep s2
|
||||||
|
- )
|
||||||
|
+ let len = String.length str in
|
||||||
|
+ let seplen = String.length sep in
|
||||||
|
+
|
||||||
|
+ let rec loop iters posn acc =
|
||||||
|
+ (* If we reached the limit, OR if the pattern does not match
|
||||||
|
+ * the string at all, return the rest of the string.
|
||||||
|
+ *)
|
||||||
|
+ if max > 0 && iters = max then (
|
||||||
|
+ let rest =
|
||||||
|
+ if posn = 0 then str else String.sub str posn (len-posn) in
|
||||||
|
+ List.rev (rest :: acc)
|
||||||
|
+ )
|
||||||
|
+ else (
|
||||||
|
+ let end_ = find_from str posn sep in
|
||||||
|
+ if end_ = -1 then (
|
||||||
|
+ let rest =
|
||||||
|
+ if posn = 0 then str else String.sub str posn (len-posn) in
|
||||||
|
+ List.rev (rest :: acc)
|
||||||
|
+ )
|
||||||
|
+ else (
|
||||||
|
+ let acc = String.sub str posn (end_-posn) :: acc in
|
||||||
|
+ loop (iters+1) (end_+seplen) acc
|
||||||
|
+ )
|
||||||
|
+ )
|
||||||
|
+ in
|
||||||
|
+ loop 1 0 []
|
||||||
|
|
||||||
|
let rec lines_split str =
|
||||||
|
let buf = Buffer.create 16 in
|
||||||
|
diff --git a/common/mlstdutils/std_utils.mli b/common/mlstdutils/std_utils.mli
|
||||||
|
index a39ac5f3b..7bd55fbae 100644
|
||||||
|
--- a/common/mlstdutils/std_utils.mli
|
||||||
|
+++ b/common/mlstdutils/std_utils.mli
|
||||||
|
@@ -82,6 +82,10 @@ module String : sig
|
||||||
|
val find : string -> string -> int
|
||||||
|
(** [find str sub] searches for [sub] as a substring of [str]. If
|
||||||
|
found it returns the index. If not found, it returns [-1]. *)
|
||||||
|
+ val find_from : string -> int -> string -> int
|
||||||
|
+ (** [find_from str start sub] searches for [sub] as a substring of [str],
|
||||||
|
+ starting at index [start]. If found it returns the index.
|
||||||
|
+ If not found, it returns [-1]. *)
|
||||||
|
val replace : string -> string -> string -> string
|
||||||
|
(** [replace str s1 s2] replaces all instances of [s1] appearing in
|
||||||
|
[str] with [s2]. *)
|
||||||
|
diff --git a/common/mlstdutils/std_utils_tests.ml b/common/mlstdutils/std_utils_tests.ml
|
||||||
|
index 3f5bb1a86..4e368152f 100644
|
||||||
|
--- a/common/mlstdutils/std_utils_tests.ml
|
||||||
|
+++ b/common/mlstdutils/std_utils_tests.ml
|
||||||
|
@@ -113,13 +113,19 @@ let test_string_nsplit ctx =
|
||||||
|
assert_equal_stringlist [""] (String.nsplit " " "");
|
||||||
|
assert_equal_stringlist ["abc"] (String.nsplit " " "abc");
|
||||||
|
assert_equal_stringlist ["a"; "b"; "c"] (String.nsplit " " "a b c");
|
||||||
|
+ assert_equal_stringlist ["abc"; "d"; "e"] (String.nsplit " " "abc d e");
|
||||||
|
assert_equal_stringlist ["a"; "b"; "c"; ""] (String.nsplit " " "a b c ");
|
||||||
|
assert_equal_stringlist [""; "a"; "b"; "c"] (String.nsplit " " " a b c");
|
||||||
|
assert_equal_stringlist [""; "a"; "b"; "c"; ""] (String.nsplit " " " a b c ");
|
||||||
|
assert_equal_stringlist ["a b c d"] (String.nsplit ~max:1 " " "a b c d");
|
||||||
|
assert_equal_stringlist ["a"; "b c d"] (String.nsplit ~max:2 " " "a b c d");
|
||||||
|
assert_equal_stringlist ["a"; "b"; "c d"] (String.nsplit ~max:3 " " "a b c d");
|
||||||
|
- assert_equal_stringlist ["a"; "b"; "c"; "d"] (String.nsplit ~max:10 " " "a b c d")
|
||||||
|
+ assert_equal_stringlist ["a"; "b"; "c"; "d"] (String.nsplit ~max:10 " " "a b c d");
|
||||||
|
+
|
||||||
|
+ (* Test that nsplit can handle large strings. *)
|
||||||
|
+ let xs = Array.to_list (Array.make 10_000_000 "xyz") in
|
||||||
|
+ let xs_concat = String.concat " " xs in
|
||||||
|
+ assert_equal_stringlist xs (String.nsplit " " xs_concat)
|
||||||
|
|
||||||
|
(* Test Std_utils.String.lines_split. *)
|
||||||
|
let test_string_lines_split ctx =
|
||||||
|
diff --git a/m4/guestfs-libraries.m4 b/m4/guestfs-libraries.m4
|
||||||
|
index 80f9425f0..7c66853dd 100644
|
||||||
|
--- a/m4/guestfs-libraries.m4
|
||||||
|
+++ b/m4/guestfs-libraries.m4
|
||||||
|
@@ -19,9 +19,8 @@ dnl Any C libraries required by the libguestfs C library (not the daemon).
|
||||||
|
|
||||||
|
dnl Of course we need libguestfs.
|
||||||
|
dnl
|
||||||
|
-dnl We need libguestfs 1.49.8 for guestfs_inspect_get_build_id in
|
||||||
|
-dnl virt-drivers.
|
||||||
|
-PKG_CHECK_MODULES([LIBGUESTFS], [libguestfs >= 1.49.8])
|
||||||
|
+dnl We need libguestfs >= 1:1.54.0-4.el9_6 for guestfs_sh_out.
|
||||||
|
+PKG_CHECK_MODULES([LIBGUESTFS], [libguestfs >= 1.54.0])
|
||||||
|
|
||||||
|
dnl Test if it's GNU or XSI strerror_r.
|
||||||
|
AC_FUNC_STRERROR_R
|
2
SOURCES/copy-patches.sh
Normal file → Executable file
2
SOURCES/copy-patches.sh
Normal file → Executable file
@ -7,7 +7,7 @@ set -e
|
|||||||
# ./copy-patches.sh
|
# ./copy-patches.sh
|
||||||
|
|
||||||
project=guestfs-tools
|
project=guestfs-tools
|
||||||
rhel_version=9.4
|
rhel_version=9.6
|
||||||
|
|
||||||
# Check we're in the right directory.
|
# Check we're in the right directory.
|
||||||
if [ ! -f $project.spec ]; then
|
if [ ! -f $project.spec ]; then
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
-----BEGIN PGP SIGNATURE-----
|
|
||||||
|
|
||||||
iQJFBAABCAAvFiEE93dPsa0HSn6Mh2fqkXOPc+G3aKAFAmV0UtkRHHJpY2hAYW5u
|
|
||||||
ZXhpYS5vcmcACgkQkXOPc+G3aKArQQ/8DR2NMjDy8zyXfLSAoSPcChx+wS36RRhj
|
|
||||||
rYGSNzD2aNhMzB+WGZHomiW4ahLqj7OAuXQlmpUMjLVsAfyja8aNW7rsnfTM1l5u
|
|
||||||
p6GS3DFTk34XgVrZO01pEBLWk9blr+xhAFP+qNIwWKv76+xO0QjNa0D5gJvBojZf
|
|
||||||
J3ct9l1ibKqDh4eG9ReSSUh76WOxm97JwP80ZRBKCpcNJe+fceJGHdBhl5UJFw/N
|
|
||||||
lAKY+d7MESk9aKZCNy6BRrls6IeIlsOBB8HbG5mXqMv4IfwarB91zZTG9NJRpmSN
|
|
||||||
MzZ/GIwSCJy9U9hmG3dA/70xFu3HQkshaCisXb4FrzCnlTHZFNCvwdhY2k3qIzZr
|
|
||||||
PuvsA3ETQqYUj66AlOOD/3TqAu36kFEeeateH75cIiOYfkUUmrO7FF76hY2jNs+q
|
|
||||||
puTm14dg/MA0OROQv5ykcuN2ukvfsyEsCFao+76am5MG8CViy1tSnL/ZSBN0itLl
|
|
||||||
jalFbag3GbDCwVt+lpPQbrLDTWNVabAEeN9LlMMcsciIGWDiz99Ntmwe1yxwLLl3
|
|
||||||
kk8f9xFiWXU7C0yrPY4HzPGNjzklsaNlpzVnqgkWpR1gzpLr37HWx0E1Ct6OlJBJ
|
|
||||||
7vllv9L9bZErUwyvlSuGcY/6rHd+KnWSS0IBvEfE/eveQErzwgiuGiBUnvGB6NUT
|
|
||||||
l868E59pb84=
|
|
||||||
=cEbV
|
|
||||||
-----END PGP SIGNATURE-----
|
|
17
SOURCES/guestfs-tools-1.52.2.tar.gz.sig
Normal file
17
SOURCES/guestfs-tools-1.52.2.tar.gz.sig
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
-----BEGIN PGP SIGNATURE-----
|
||||||
|
|
||||||
|
iQJFBAABCAAvFiEE93dPsa0HSn6Mh2fqkXOPc+G3aKAFAmb+mWcRHHJpY2hAYW5u
|
||||||
|
ZXhpYS5vcmcACgkQkXOPc+G3aKBPWRAAmHJHvz8GRAsFEpZS6/6FjgxjASRTtMZO
|
||||||
|
02vo8KZLpF3pX0zjsgcYPsTgj90kQ8z9rsdXk70HbOvnJIuVShuT9Q/bGiYf60YB
|
||||||
|
CEvRy3b5HMgsk4Dk46Ux0RpOHTFmVKOxSdNrk1G0qRMjIYdy19KxRnMJyQXv4QRg
|
||||||
|
y6RYOt2Zm6Luj53Id+zTLiqnz5Z8PBkupWH3y1zSrN3OcASIvSKYnPUA/c63+Fzk
|
||||||
|
YZHGIf3DCHEAnzHfPMaF58L+Np3ZaC4vGBfnDfLiyTd/d2J/Ci18LcI9hC9l6SV1
|
||||||
|
ePlNBH/LV1+YYuWLhd9XPVsCiKi2zY3/DMxoxZcYhl+JalVTeK6FZk2Abe+0c9XZ
|
||||||
|
wAaQG+aLqweDHNiLJ0AxoPqinWsa2EpciZMKAzzCGM83IABm+pKSZlN077riiYNa
|
||||||
|
YRZIw/i6LFfuQSxBaav+/d6cOpxx4AklmaV1ymu4Xr2JTm4u93O72722oyhCzbAn
|
||||||
|
3DQac1H5XgJsBh6Un9Ybl3PkUGS2AlCCDTFbyWDB8i9aiWv5m/yuLD4c6hk9sRWQ
|
||||||
|
DNiH0AKaem/cPt33FV3C2viyppmGnhZDNrrKKzJCxCkRY7XU2rzEJ1SmU9CACCOj
|
||||||
|
ick58Flv52CYSeonC+7uO9jqlDcgVmJIDitCCHhIl1Kipr1mzCMQV1Vq0LP3Hv8f
|
||||||
|
MSbFdmbrh5I=
|
||||||
|
=Gu1k
|
||||||
|
-----END PGP SIGNATURE-----
|
@ -11,19 +11,23 @@
|
|||||||
%global patches_touch_autotools 1
|
%global patches_touch_autotools 1
|
||||||
|
|
||||||
# The source directory.
|
# The source directory.
|
||||||
%global source_directory 1.51-development
|
%global source_directory 1.52-stable
|
||||||
|
|
||||||
# Filter perl provides.
|
# Filter perl provides.
|
||||||
%{?perl_default_filter}
|
%{?perl_default_filter}
|
||||||
|
|
||||||
Summary: Tools to access and modify virtual machine disk images
|
Summary: Tools to access and modify virtual machine disk images
|
||||||
Name: guestfs-tools
|
Name: guestfs-tools
|
||||||
Version: 1.51.6
|
Version: 1.52.2
|
||||||
Release: 3%{?dist}.alma.1.kvm
|
Release: 3%{?dist}
|
||||||
License: GPL-2.0-or-later AND LGPL-2.0-or-later
|
License: GPL-2.0-or-later AND LGPL-2.0-or-later
|
||||||
|
|
||||||
# Build only for architectures that have a kernel
|
# Build only for architectures that have a kernel
|
||||||
ExclusiveArch: %{kernel_arches}
|
ExclusiveArch: %{kernel_arches}
|
||||||
|
%if 0%{?rhel}
|
||||||
|
# No qemu-kvm on POWER (RHBZ#1946532).
|
||||||
|
ExcludeArch: %{power64}
|
||||||
|
%endif
|
||||||
|
|
||||||
# Source and patches.
|
# Source and patches.
|
||||||
URL: http://libguestfs.org/
|
URL: http://libguestfs.org/
|
||||||
@ -41,14 +45,17 @@ Source2: libguestfs.keyring
|
|||||||
Source3: copy-patches.sh
|
Source3: copy-patches.sh
|
||||||
|
|
||||||
# Patches are maintained in the following repository:
|
# Patches are maintained in the following repository:
|
||||||
# https://github.com/rwmjones/guestfs-tools/commits/rhel-9.4
|
# https://github.com/rwmjones/guestfs-tools/commits/rhel-9.6
|
||||||
|
|
||||||
# Patches.
|
# Patches.
|
||||||
Patch0001: 0001-Update-common-submodule.patch
|
Patch0001: 0001-RHEL-Reject-use-of-libguestfs-winsupport-features-ex.patch
|
||||||
Patch0002: 0002-builder-Add-a-test-of-the-chown-parameter.patch
|
Patch0002: 0002-RHEL-builder-Disable-opensuse-repository.patch
|
||||||
Patch0003: 0003-RHEL-Reject-use-of-libguestfs-winsupport-features-ex.patch
|
Patch0003: 0003-customize-Implement-inject-blnsvr-operation.patch
|
||||||
Patch0004: 0004-RHEL-builder-Disable-opensuse-repository.patch
|
Patch0004: 0004-build-Add-new-dependency-on-json-c.patch
|
||||||
Patch0005: 0005-Update-common-submodule.patch
|
Patch0005: 0005-builder-Replace-jansson-with-json-c.patch
|
||||||
|
Patch0006: 0006-build-Remove-Jansson-dependency.patch
|
||||||
|
Patch0007: 0007-test-data-phony-fedora-Add-simple-static-bin-sh.patch
|
||||||
|
Patch0008: 0008-drivers-Handle-large-output-from-rpm-ql-command.patch
|
||||||
|
|
||||||
%if 0%{patches_touch_autotools}
|
%if 0%{patches_touch_autotools}
|
||||||
BuildRequires: autoconf, automake, libtool, gettext-devel
|
BuildRequires: autoconf, automake, libtool, gettext-devel
|
||||||
@ -57,7 +64,7 @@ BuildRequires: autoconf, automake, libtool, gettext-devel
|
|||||||
# Basic build requirements.
|
# Basic build requirements.
|
||||||
BuildRequires: gcc, gcc-c++
|
BuildRequires: gcc, gcc-c++
|
||||||
BuildRequires: make
|
BuildRequires: make
|
||||||
BuildRequires: libguestfs-devel >= 1:1.49.8-1
|
BuildRequires: libguestfs-devel >= 1:1.54.0-4.el9
|
||||||
BuildRequires: libguestfs-xfs
|
BuildRequires: libguestfs-xfs
|
||||||
BuildRequires: perl(Pod::Simple)
|
BuildRequires: perl(Pod::Simple)
|
||||||
BuildRequires: perl(Pod::Man)
|
BuildRequires: perl(Pod::Man)
|
||||||
@ -67,7 +74,7 @@ BuildRequires: /usr/bin/pod2text
|
|||||||
BuildRequires: po4a
|
BuildRequires: po4a
|
||||||
BuildRequires: pcre2-devel
|
BuildRequires: pcre2-devel
|
||||||
BuildRequires: libxml2-devel
|
BuildRequires: libxml2-devel
|
||||||
BuildRequires: jansson-devel
|
BuildRequires: json-c-devel
|
||||||
BuildRequires: libvirt-devel
|
BuildRequires: libvirt-devel
|
||||||
BuildRequires: libosinfo-devel
|
BuildRequires: libosinfo-devel
|
||||||
BuildRequires: libxcrypt-devel
|
BuildRequires: libxcrypt-devel
|
||||||
@ -106,9 +113,8 @@ BuildRequires: gnupg2
|
|||||||
%endif
|
%endif
|
||||||
|
|
||||||
# Ensure a minimum version of libguestfs is installed. This contains
|
# Ensure a minimum version of libguestfs is installed. This contains
|
||||||
# a workaround for openssl bug RHBZ#2133884 and the hang where we
|
# new APIs sh-out and command-out, required by virt-drivers.
|
||||||
# called setenv between fork and exec.
|
Requires: libguestfs >= 1:1.54.0-4.el9
|
||||||
Requires: libguestfs >= 1.49.6-1
|
|
||||||
|
|
||||||
# For virt-builder:
|
# For virt-builder:
|
||||||
Requires: curl
|
Requires: curl
|
||||||
@ -407,9 +413,25 @@ end
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
* Tue Aug 27 2024 Richard W.M. Jones <rjones@redhat.com> - 1.51.6-3
|
* Tue Feb 25 2025 Richard W.M. Jones <rjones@redhat.com> - 1.52.2-3
|
||||||
|
- Fix virt-drivers fails on opensuse guest if kernel-source is installed
|
||||||
|
resolves: RHEL-80214
|
||||||
|
|
||||||
|
* Wed Oct 30 2024 Richard W.M. Jones <rjones@redhat.com> - 1.52.2-2
|
||||||
|
- Rebase to guestfs-tools 1.52.2
|
||||||
|
resolves: RHEL-56811
|
||||||
|
- Replace Jansson with json-c
|
||||||
|
resolves: RHEL-65294
|
||||||
|
|
||||||
|
* Tue Aug 27 2024 Richard W.M. Jones <rjones@redhat.com> - 1.51.6-5
|
||||||
- Reboot Windows between each firstboot script to improve reliability
|
- Reboot Windows between each firstboot script to improve reliability
|
||||||
resolves: RHEL-55824
|
resolves: RHEL-55759
|
||||||
|
|
||||||
|
* Thu May 16 2024 Richard W.M. Jones <rjones@redhat.com> - 1.51.6-4
|
||||||
|
- Add support for nbd+unix:// URIs
|
||||||
|
resolves: RHEL-33956
|
||||||
|
- customize: Implement --inject-blnsvr operation
|
||||||
|
resolves: RHEL-36634
|
||||||
|
|
||||||
* Fri Jan 19 2024 Richard W.M. Jones <rjones@redhat.com> - 1.51.6-2
|
* Fri Jan 19 2024 Richard W.M. Jones <rjones@redhat.com> - 1.51.6-2
|
||||||
- Rebase to guestfs-tools 1.51.6
|
- Rebase to guestfs-tools 1.51.6
|
||||||
@ -431,9 +453,6 @@ end
|
|||||||
- Fix virt-drivers inspection of RHEL 9.2 guests
|
- Fix virt-drivers inspection of RHEL 9.2 guests
|
||||||
resolves: rhbz#2184963
|
resolves: rhbz#2184963
|
||||||
|
|
||||||
* Mon Dec 19 2022 Eduard Abdullin <eabdullin@almalinux.org> - 1.48.2-5.alma
|
|
||||||
- Enable for ppc64le
|
|
||||||
|
|
||||||
* Thu Nov 24 2022 Richard W.M. Jones <rjones@redhat.com> - 1.48.2-8
|
* Thu Nov 24 2022 Richard W.M. Jones <rjones@redhat.com> - 1.48.2-8
|
||||||
- Support Rocky Linux in virt-customize
|
- Support Rocky Linux in virt-customize
|
||||||
resolves: rhbz#2133443
|
resolves: rhbz#2133443
|
||||||
|
Loading…
Reference in New Issue
Block a user