diff --git a/.gitignore b/.gitignore index 10fd57f..3a9a398 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,2 @@ -SOURCES/RHEV-Application-Provisioning-Tool.exe_4.43-5 -SOURCES/libguestfs-1.40.2.tar.gz +SOURCES/libguestfs-1.44.0.tar.gz SOURCES/libguestfs.keyring -SOURCES/rhsrvany.exe diff --git a/.libguestfs.metadata b/.libguestfs.metadata index 355ef3d..a285f57 100644 --- a/.libguestfs.metadata +++ b/.libguestfs.metadata @@ -1,4 +1,2 @@ -130adbc011dc0af736465b813c2b22a600c128c1 SOURCES/RHEV-Application-Provisioning-Tool.exe_4.43-5 -45755f0f73b503790974484053ff482f32665b13 SOURCES/libguestfs-1.40.2.tar.gz +99d241dc4a5ba0dc6111954ed7a872e0b0bb6944 SOURCES/libguestfs-1.44.0.tar.gz 1bbc40f501a7fef9eef2a39b701a71aee2fea7c4 SOURCES/libguestfs.keyring -2bd96e478fc004cd323b5bd754c856641877dac6 SOURCES/rhsrvany.exe diff --git a/SOURCES/0075-RHEL-8-Remove-libguestfs-live-RHBZ-798980.patch b/SOURCES/0001-RHEL-8-Remove-libguestfs-live-RHBZ-798980.patch similarity index 54% rename from SOURCES/0075-RHEL-8-Remove-libguestfs-live-RHBZ-798980.patch rename to SOURCES/0001-RHEL-8-Remove-libguestfs-live-RHBZ-798980.patch index 707bf1c..19dfe77 100644 --- a/SOURCES/0075-RHEL-8-Remove-libguestfs-live-RHBZ-798980.patch +++ b/SOURCES/0001-RHEL-8-Remove-libguestfs-live-RHBZ-798980.patch @@ -1,15 +1,18 @@ -From a7fefab912d97962fb77f0f57799b7b70634376c Mon Sep 17 00:00:00 2001 +From 5b6d2b05fe0c4035b9791a751e3133d26c7baa2d Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 21 Dec 2012 15:50:11 +0000 Subject: [PATCH] RHEL 8: Remove libguestfs live (RHBZ#798980). This isn't supported in RHEL 8. + +Disable daemon tests that require the 'unix' backend. --- - lib/launch-unix.c | 7 +++++++ - 1 file changed, 7 insertions(+) + lib/launch-unix.c | 7 +++++++ + tests/daemon/Makefile.am | 4 +--- + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/launch-unix.c b/lib/launch-unix.c -index 4794a7b13..993b83601 100644 +index 0d344f9df..74dd1bb4a 100644 --- a/lib/launch-unix.c +++ b/lib/launch-unix.c @@ -37,6 +37,12 @@ @@ -33,6 +36,21 @@ index 4794a7b13..993b83601 100644 } static int +diff --git a/tests/daemon/Makefile.am b/tests/daemon/Makefile.am +index 921e6d1df..8b2887247 100644 +--- a/tests/daemon/Makefile.am ++++ b/tests/daemon/Makefile.am +@@ -23,9 +23,7 @@ include $(top_srcdir)/subdir-rules.mk + + check_DATA = captive-daemon.pm + +-TESTS = \ +- test-daemon-start.pl \ +- test-btrfs.pl ++TESTS = + + TESTS_ENVIRONMENT = $(top_builddir)/run --test + -- -2.18.4 +2.31.1 diff --git a/SOURCES/0001-daemon-lib-Replace-deprecated-security_context_t-wit.patch b/SOURCES/0001-daemon-lib-Replace-deprecated-security_context_t-wit.patch deleted file mode 100644 index dacbba7..0000000 --- a/SOURCES/0001-daemon-lib-Replace-deprecated-security_context_t-wit.patch +++ /dev/null @@ -1,56 +0,0 @@ -From a5e8afb4ed8576a1b3398add2ede49a1f90ad01a Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 30 Jul 2020 13:57:45 +0100 -Subject: [PATCH] daemon, lib: Replace deprecated security_context_t with char - *. - -This gives deprecation warnings. It always was simply a char *, and -the recommendation upstream is to replace uses with char *: - -https://github.com/SELinuxProject/selinux/commit/9eb9c9327563014ad6a807814e7975424642d5b9 -(cherry picked from commit eb78e990ac5277a4282293f8787af871a1420b61) ---- - daemon/selinux.c | 3 +-- - lib/launch-libvirt.c | 5 ++--- - 2 files changed, 3 insertions(+), 5 deletions(-) - -diff --git a/daemon/selinux.c b/daemon/selinux.c -index 1c1446d30..f4d839c19 100644 ---- a/daemon/selinux.c -+++ b/daemon/selinux.c -@@ -63,8 +63,7 @@ char * - do_getcon (void) - { - #if defined(HAVE_GETCON) -- security_context_t context; -- char *r; -+ char *context, *r; - - if (getcon (&context) == -1) { - reply_with_perror ("getcon"); -diff --git a/lib/launch-libvirt.c b/lib/launch-libvirt.c -index bc5978cc4..4a47bbb29 100644 ---- a/lib/launch-libvirt.c -+++ b/lib/launch-libvirt.c -@@ -288,8 +288,7 @@ create_cow_overlay_libvirt (guestfs_h *g, void *datav, struct drive *drv) - if (data->selinux_imagelabel) { - debug (g, "setting SELinux label on %s to %s", - overlay, data->selinux_imagelabel); -- if (setfilecon (overlay, -- (security_context_t) data->selinux_imagelabel) == -1) -+ if (setfilecon (overlay, data->selinux_imagelabel) == -1) - selinux_warning (g, __func__, "setfilecon", overlay); - } - #endif -@@ -840,7 +839,7 @@ is_custom_hv (guestfs_h *g) - static void - set_socket_create_context (guestfs_h *g) - { -- security_context_t scon; /* this is actually a 'char *' */ -+ char *scon; - context_t con; - - if (getcon (&scon) == -1) { --- -2.18.4 - diff --git a/SOURCES/0076-RHEL-8-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch b/SOURCES/0002-RHEL-8-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch similarity index 79% rename from SOURCES/0076-RHEL-8-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch rename to SOURCES/0002-RHEL-8-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch index c854812..4e2ee11 100644 --- a/SOURCES/0076-RHEL-8-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch +++ b/SOURCES/0002-RHEL-8-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch @@ -1,22 +1,22 @@ -From 683153015b95a7b6d4979d48736c80e366986c72 Mon Sep 17 00:00:00 2001 +From 91b2a6e50211c58ea31a36351ec63c358f708bf9 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 18 Jul 2013 18:31:53 +0100 Subject: [PATCH] RHEL 8: Remove 9p APIs from RHEL (RHBZ#921710). --- Makefile.am | 2 +- - daemon/9p.c | 224 -------------------------------------- + daemon/9p.c | 182 -------------------------------------- daemon/Makefile.am | 1 - docs/C_SOURCE_FILES | 1 - - generator/actions_core.ml | 21 ---- + generator/actions_core.ml | 21 ----- generator/proc_nr.ml | 2 - gobject/Makefile.inc | 2 - po/POTFILES | 2 - - 8 files changed, 1 insertion(+), 254 deletions(-) + 8 files changed, 1 insertion(+), 212 deletions(-) delete mode 100644 daemon/9p.c diff --git a/Makefile.am b/Makefile.am -index 0067d7b7b..e9351eadc 100644 +index 3df1b6a7a..36e44dfd5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -78,7 +78,7 @@ SUBDIRS += tests/xfs @@ -30,10 +30,10 @@ index 0067d7b7b..e9351eadc 100644 SUBDIRS += tests/disk-labels diff --git a/daemon/9p.c b/daemon/9p.c deleted file mode 100644 -index 55644249d..000000000 +index 743a96abd..000000000 --- a/daemon/9p.c +++ /dev/null -@@ -1,224 +0,0 @@ +@@ -1,182 +0,0 @@ -/* libguestfs - the guestfsd daemon - * Copyright (C) 2011 Red Hat Inc. - * @@ -65,21 +65,32 @@ index 55644249d..000000000 -#include -#include - +-#include "ignore-value.h" +- -#include "daemon.h" -#include "actions.h" - -#define BUS_PATH "/sys/bus/virtio/drivers/9pnet_virtio" - --static char *read_whole_file (const char *filename); +-static void +-modprobe_9pnet_virtio (void) +-{ +- /* Required with Linux 5.6 and maybe earlier kernels. For unclear +- * reasons the module is not an automatic dependency of the 9p +- * module so doesn't get loaded automatically. +- */ +- ignore_value (command (NULL, NULL, "modprobe", "9pnet_virtio", NULL)); +-} - -/* https://bugzilla.redhat.com/show_bug.cgi?id=714981#c1 */ -char ** -do_list_9p (void) -{ - CLEANUP_FREE_STRINGSBUF DECLARE_STRINGSBUF (r); -- - DIR *dir; - +- modprobe_9pnet_virtio (); +- - dir = opendir (BUS_PATH); - if (!dir) { - perror ("opendir: " BUS_PATH); @@ -118,7 +129,7 @@ index 55644249d..000000000 - * the mount tag length to be unlimited (or up to 65536 bytes). - * See: linux/include/linux/virtio_9p.h - */ -- CLEANUP_FREE char *mount_tag = read_whole_file (mount_tag_path); +- CLEANUP_FREE char *mount_tag = read_whole_file (mount_tag_path, NULL); - if (mount_tag == 0) - continue; - @@ -153,60 +164,6 @@ index 55644249d..000000000 - return take_stringsbuf (&r); -} - --/* Read whole file into dynamically allocated array. If there is an -- * error, DON'T call reply_with_perror, just return NULL. Returns a -- * \0-terminated string. -- */ --static char * --read_whole_file (const char *filename) --{ -- char *r = NULL; -- size_t alloc = 0, size = 0; -- int fd; -- -- fd = open (filename, O_RDONLY|O_CLOEXEC); -- if (fd == -1) { -- perror (filename); -- return NULL; -- } -- -- while (1) { -- alloc += 256; -- char *r2 = realloc (r, alloc); -- if (r2 == NULL) { -- perror ("realloc"); -- free (r); -- close (fd); -- return NULL; -- } -- r = r2; -- -- /* The '- 1' in the size calculation ensures there is space below -- * to add \0 to the end of the input. -- */ -- ssize_t n = read (fd, r + size, alloc - size - 1); -- if (n == -1) { -- fprintf (stderr, "read: %s: %m\n", filename); -- free (r); -- close (fd); -- return NULL; -- } -- if (n == 0) -- break; -- size += n; -- } -- -- if (close (fd) == -1) { -- fprintf (stderr, "close: %s: %m\n", filename); -- free (r); -- return NULL; -- } -- -- r[size] = '\0'; -- -- return r; --} -- -/* Takes optional arguments, consult optargs_bitmask. */ -int -do_mount_9p (const char *mount_tag, const char *mountpoint, const char *options) @@ -249,6 +206,7 @@ index 55644249d..000000000 - } - } - +- modprobe_9pnet_virtio (); - r = command (NULL, &err, - "mount", "-o", opts, "-t", "9p", mount_tag, mp, NULL); - if (r == -1) { @@ -259,10 +217,10 @@ index 55644249d..000000000 - return 0; -} diff --git a/daemon/Makefile.am b/daemon/Makefile.am -index 5d1c222db..a9b40be25 100644 +index 038be592c..df9dcc4ee 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am -@@ -76,7 +76,6 @@ guestfsd_SOURCES = \ +@@ -82,7 +82,6 @@ guestfsd_SOURCES = \ ../common/protocol/guestfs_protocol.h \ ../common/utils/cleanups.h \ ../common/utils/guestfs-utils.h \ @@ -271,22 +229,22 @@ index 5d1c222db..a9b40be25 100644 actions.h \ available.c \ diff --git a/docs/C_SOURCE_FILES b/docs/C_SOURCE_FILES -index 7f1c60b30..f45e7124d 100644 +index cd5bd2924..831b7e25a 100644 --- a/docs/C_SOURCE_FILES +++ b/docs/C_SOURCE_FILES -@@ -71,7 +71,6 @@ common/windows/windows.h +@@ -63,7 +63,6 @@ common/windows/windows.c + common/windows/windows.h customize/crypt-c.c - customize/dummy.c customize/perl_edit-c.c -daemon/9p.c daemon/acl.c daemon/actions.h daemon/augeas.c diff --git a/generator/actions_core.ml b/generator/actions_core.ml -index deda483a9..f466600df 100644 +index 806565b19..37476c93e 100644 --- a/generator/actions_core.ml +++ b/generator/actions_core.ml -@@ -6167,27 +6167,6 @@ This returns true iff the device exists and contains all zero bytes. +@@ -6157,27 +6157,6 @@ This returns true iff the device exists and contains all zero bytes. Note that for large devices this can take a long time to run." }; @@ -315,7 +273,7 @@ index deda483a9..f466600df 100644 name = "list_dm_devices"; added = (1, 11, 15); style = RStringList (RDevice, "devices"), [], []; diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml -index 11a557076..1ef5ba0b7 100644 +index 30e42864f..57976be36 100644 --- a/generator/proc_nr.ml +++ b/generator/proc_nr.ml @@ -295,8 +295,6 @@ let proc_nr = [ @@ -328,10 +286,10 @@ index 11a557076..1ef5ba0b7 100644 288, "ntfsresize"; 289, "btrfs_filesystem_resize"; diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc -index 067f861a9..7afe83c59 100644 +index 650f8ddac..c4e735967 100644 --- a/gobject/Makefile.inc +++ b/gobject/Makefile.inc -@@ -93,7 +93,6 @@ guestfs_gobject_headers= \ +@@ -94,7 +94,6 @@ guestfs_gobject_headers= \ include/guestfs-gobject/optargs-mksquashfs.h \ include/guestfs-gobject/optargs-mkswap.h \ include/guestfs-gobject/optargs-mktemp.h \ @@ -339,7 +297,7 @@ index 067f861a9..7afe83c59 100644 include/guestfs-gobject/optargs-mount_local.h \ include/guestfs-gobject/optargs-ntfsclone_out.h \ include/guestfs-gobject/optargs-ntfsfix.h \ -@@ -186,7 +185,6 @@ guestfs_gobject_sources= \ +@@ -188,7 +187,6 @@ guestfs_gobject_sources= \ src/optargs-mksquashfs.c \ src/optargs-mkswap.c \ src/optargs-mktemp.c \ @@ -348,18 +306,18 @@ index 067f861a9..7afe83c59 100644 src/optargs-ntfsclone_out.c \ src/optargs-ntfsfix.c \ diff --git a/po/POTFILES b/po/POTFILES -index 79f4b8c56..b99333d0d 100644 +index 69ea7134a..0782e8ceb 100644 --- a/po/POTFILES +++ b/po/POTFILES -@@ -58,7 +58,6 @@ customize/crypt-c.c - customize/dummy.c +@@ -47,7 +47,6 @@ common/visit/visit.c + common/windows/windows.c + customize/crypt-c.c customize/perl_edit-c.c - customize/test-password.pl -daemon/9p.c daemon/acl.c daemon/augeas.c daemon/available.c -@@ -291,7 +290,6 @@ gobject/src/optargs-mkfs_btrfs.c +@@ -277,7 +276,6 @@ gobject/src/optargs-mkfs_btrfs.c gobject/src/optargs-mksquashfs.c gobject/src/optargs-mkswap.c gobject/src/optargs-mktemp.c @@ -368,5 +326,5 @@ index 79f4b8c56..b99333d0d 100644 gobject/src/optargs-ntfsclone_out.c gobject/src/optargs-ntfsfix.c -- -2.18.4 +2.31.1 diff --git a/SOURCES/0002-caml_named_value-returns-const-value-pointer-in-OCam.patch b/SOURCES/0002-caml_named_value-returns-const-value-pointer-in-OCam.patch deleted file mode 100644 index ce3a12a..0000000 --- a/SOURCES/0002-caml_named_value-returns-const-value-pointer-in-OCam.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 524b0c748a3a2d47b4c76e3aa546b9d4af144e6c Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Sat, 7 Dec 2019 11:08:54 +0000 -Subject: [PATCH] caml_named_value returns const value pointer in OCaml 4.09+ - -(cherry picked from ocaml-augeas -commit 1cf5aef99b26a46529ca797547c0b49627fffe78) ---- - common/mlaugeas/augeas-c.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/common/mlaugeas/augeas-c.c b/common/mlaugeas/augeas-c.c -index 3e0ba67ba..3b1dc2551 100644 ---- a/common/mlaugeas/augeas-c.c -+++ b/common/mlaugeas/augeas-c.c -@@ -77,7 +77,7 @@ static const int error_map_len = sizeof error_map / sizeof error_map[0]; - static void - raise_error (augeas_t t, const char *msg) - { -- value *exn = caml_named_value ("Augeas.Error"); -+ const value *exn = caml_named_value ("Augeas.Error"); - value args[4]; - const int code = aug_error (t); - const char *aug_err_minor; -@@ -113,7 +113,7 @@ raise_error (augeas_t t, const char *msg) - static void - raise_init_error (const char *msg) - { -- value *exn = caml_named_value ("Augeas.Error"); -+ const value *exn = caml_named_value ("Augeas.Error"); - value args[4]; - - args[0] = caml_alloc (1, 0); --- -2.18.4 - diff --git a/SOURCES/0077-RHEL-8-Disable-unsupported-remote-drive-protocols-RH.patch b/SOURCES/0003-RHEL-8-Disable-unsupported-remote-drive-protocols-RH.patch similarity index 94% rename from SOURCES/0077-RHEL-8-Disable-unsupported-remote-drive-protocols-RH.patch rename to SOURCES/0003-RHEL-8-Disable-unsupported-remote-drive-protocols-RH.patch index 187be93..91159d2 100644 --- a/SOURCES/0077-RHEL-8-Disable-unsupported-remote-drive-protocols-RH.patch +++ b/SOURCES/0003-RHEL-8-Disable-unsupported-remote-drive-protocols-RH.patch @@ -1,4 +1,4 @@ -From 336961659225584add638442cc0cf933803e008e Mon Sep 17 00:00:00 2001 +From 4dd2f3f56a39411a255ad0a8f38081d46620dbd8 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Mon, 29 Jul 2013 14:47:56 +0100 Subject: [PATCH] RHEL 8: Disable unsupported remote drive protocols @@ -62,7 +62,7 @@ index f558964bf..8f264ed17 100644 Run L on guests or disk images: diff --git a/fish/guestfish.pod b/fish/guestfish.pod -index f1fdf094d..bacb60e0b 100644 +index 9f086f110..bb4167b06 100644 --- a/fish/guestfish.pod +++ b/fish/guestfish.pod @@ -131,9 +131,9 @@ To list what is available do: @@ -77,7 +77,7 @@ index f1fdf094d..bacb60e0b 100644 =head2 Remote control -@@ -1145,12 +1145,12 @@ L>. +@@ -1134,12 +1134,12 @@ L>. On the command line, you can use the I<-a> option to add network block devices using a URI-style format, for example: @@ -92,7 +92,7 @@ index f1fdf094d..bacb60e0b 100644 The possible I<-a URI> formats are described below. -@@ -1160,40 +1160,6 @@ The possible I<-a URI> formats are described below. +@@ -1149,40 +1149,6 @@ The possible I<-a URI> formats are described below. Add the local disk image (or device) called F. @@ -133,7 +133,7 @@ index f1fdf094d..bacb60e0b 100644 =head2 B<-a nbd://example.com[:port]> =head2 B<-a nbd://example.com[:port]/exportname> -@@ -1228,35 +1194,13 @@ The equivalent API command would be: +@@ -1217,35 +1183,13 @@ The equivalent API command would be: > add pool/disk protocol:rbd server:tcp:example.com:port @@ -171,7 +171,7 @@ index f1fdf094d..bacb60e0b 100644 In this case, the password is C. diff --git a/fish/test-add-uri.sh b/fish/test-add-uri.sh -index 756df997b..8f84fd31b 100755 +index 21d424984..ddabeb639 100755 --- a/fish/test-add-uri.sh +++ b/fish/test-add-uri.sh @@ -40,14 +40,6 @@ function fail () @@ -220,7 +220,7 @@ index 756df997b..8f84fd31b 100755 rm test-add-uri.out rm test-add-uri.img diff --git a/generator/actions_core.ml b/generator/actions_core.ml -index f466600df..3893d0e8d 100644 +index 37476c93e..9f0402510 100644 --- a/generator/actions_core.ml +++ b/generator/actions_core.ml @@ -297,29 +297,6 @@ F is interpreted as a local file or device. @@ -305,10 +305,10 @@ index f466600df..3893d0e8d 100644 example if using the libvirt backend and if the libvirt backend is configured to start the qemu appliance as a special user such as C. If in doubt, diff --git a/lib/drives.c b/lib/drives.c -index 82ef30093..3d712c6e4 100644 +index 46af66db4..c81ded5d7 100644 --- a/lib/drives.c +++ b/lib/drives.c -@@ -165,6 +165,7 @@ create_drive_non_file (guestfs_h *g, +@@ -168,6 +168,7 @@ create_drive_non_file (guestfs_h *g, return drv; } @@ -316,7 +316,7 @@ index 82ef30093..3d712c6e4 100644 static struct drive * create_drive_curl (guestfs_h *g, const struct drive_create_data *data) -@@ -223,6 +224,7 @@ create_drive_gluster (guestfs_h *g, +@@ -226,6 +227,7 @@ create_drive_gluster (guestfs_h *g, return create_drive_non_file (g, data); } @@ -324,7 +324,7 @@ index 82ef30093..3d712c6e4 100644 static int nbd_port (void) -@@ -291,6 +293,7 @@ create_drive_rbd (guestfs_h *g, +@@ -294,6 +296,7 @@ create_drive_rbd (guestfs_h *g, return create_drive_non_file (g, data); } @@ -332,7 +332,7 @@ index 82ef30093..3d712c6e4 100644 static struct drive * create_drive_sheepdog (guestfs_h *g, const struct drive_create_data *data) -@@ -391,6 +394,7 @@ create_drive_iscsi (guestfs_h *g, +@@ -394,6 +397,7 @@ create_drive_iscsi (guestfs_h *g, return create_drive_non_file (g, data); } @@ -340,7 +340,7 @@ index 82ef30093..3d712c6e4 100644 /** * Create the special F drive. -@@ -826,6 +830,7 @@ guestfs_impl_add_drive_opts (guestfs_h *g, const char *filename, +@@ -856,6 +860,7 @@ guestfs_impl_add_drive_opts (guestfs_h *g, const char *filename, drv = create_drive_file (g, &data); } } @@ -348,7 +348,7 @@ index 82ef30093..3d712c6e4 100644 else if (STREQ (protocol, "ftp")) { data.protocol = drive_protocol_ftp; drv = create_drive_curl (g, &data); -@@ -850,6 +855,7 @@ guestfs_impl_add_drive_opts (guestfs_h *g, const char *filename, +@@ -880,6 +885,7 @@ guestfs_impl_add_drive_opts (guestfs_h *g, const char *filename, data.protocol = drive_protocol_iscsi; drv = create_drive_iscsi (g, &data); } @@ -356,7 +356,7 @@ index 82ef30093..3d712c6e4 100644 else if (STREQ (protocol, "nbd")) { data.protocol = drive_protocol_nbd; drv = create_drive_nbd (g, &data); -@@ -858,6 +864,7 @@ guestfs_impl_add_drive_opts (guestfs_h *g, const char *filename, +@@ -888,6 +894,7 @@ guestfs_impl_add_drive_opts (guestfs_h *g, const char *filename, data.protocol = drive_protocol_rbd; drv = create_drive_rbd (g, &data); } @@ -364,7 +364,7 @@ index 82ef30093..3d712c6e4 100644 else if (STREQ (protocol, "sheepdog")) { data.protocol = drive_protocol_sheepdog; drv = create_drive_sheepdog (g, &data); -@@ -870,6 +877,7 @@ guestfs_impl_add_drive_opts (guestfs_h *g, const char *filename, +@@ -900,6 +907,7 @@ guestfs_impl_add_drive_opts (guestfs_h *g, const char *filename, data.protocol = drive_protocol_tftp; drv = create_drive_curl (g, &data); } @@ -373,10 +373,10 @@ index 82ef30093..3d712c6e4 100644 error (g, _("unknown protocol ‘%s’"), protocol); drv = NULL; /*FALLTHROUGH*/ diff --git a/lib/guestfs.pod b/lib/guestfs.pod -index af944ddb7..58559a6b4 100644 +index bce9eb79f..2bb13b875 100644 --- a/lib/guestfs.pod +++ b/lib/guestfs.pod -@@ -714,70 +714,6 @@ servers. The server string is documented in +@@ -715,70 +715,6 @@ servers. The server string is documented in L. The C and C parameters are also optional, and if not given, then no authentication will be used. @@ -447,7 +447,7 @@ index af944ddb7..58559a6b4 100644 =head3 NETWORK BLOCK DEVICE Libguestfs can access Network Block Device (NBD) disks remotely. -@@ -840,42 +776,6 @@ L +@@ -841,42 +777,6 @@ L =back @@ -491,7 +491,7 @@ index af944ddb7..58559a6b4 100644 Libguestfs has APIs for inspecting an unknown disk image to find out diff --git a/tests/disks/test-qemu-drive-libvirt.sh b/tests/disks/test-qemu-drive-libvirt.sh -index e49c69b43..9b1abc4ec 100755 +index 3c5aa592e..f73827bd6 100755 --- a/tests/disks/test-qemu-drive-libvirt.sh +++ b/tests/disks/test-qemu-drive-libvirt.sh @@ -64,34 +64,6 @@ check_output @@ -605,5 +605,5 @@ index 19dd60a2f..583e031bd 100755 -grep -sq -- '-drive file=ssh://rich@example.com/disk.img,' "$DEBUG_QEMU_FILE" || fail -rm "$DEBUG_QEMU_FILE" -- -2.18.4 +2.31.1 diff --git a/SOURCES/0003-ocaml-Change-calls-to-caml_named_value-to-cope-with-.patch b/SOURCES/0003-ocaml-Change-calls-to-caml_named_value-to-cope-with-.patch deleted file mode 100644 index 09efa19..0000000 --- a/SOURCES/0003-ocaml-Change-calls-to-caml_named_value-to-cope-with-.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 3860ab78d9fe5c34785aabc2227ebc8687b1171b Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 5 Sep 2019 09:00:14 +0100 -Subject: [PATCH] ocaml: Change calls to caml_named_value() to cope with const - value* return. - -In OCaml >= 4.09 the return value pointer of caml_named_value is -declared const. - -Based on Pino Toscano's original patch to ocaml-augeas. - -(cherry picked from commit 9788fa50601ad4f1eab56d0b763591268026e536) ---- - common/mlpcre/pcre-c.c | 3 +-- - common/mltools/uri-c.c | 6 ++---- - common/mlvisit/visit-c.c | 4 +--- - 3 files changed, 4 insertions(+), 9 deletions(-) - -diff --git a/common/mlpcre/pcre-c.c b/common/mlpcre/pcre-c.c -index 0762a8341..07f99b8d6 100644 ---- a/common/mlpcre/pcre-c.c -+++ b/common/mlpcre/pcre-c.c -@@ -73,12 +73,11 @@ init (void) - static void - raise_pcre_error (const char *msg, int errcode) - { -- value *exn = caml_named_value ("PCRE.Error"); - value args[2]; - - args[0] = caml_copy_string (msg); - args[1] = Val_int (errcode); -- caml_raise_with_args (*exn, 2, args); -+ caml_raise_with_args (*caml_named_value ("PCRE.Error"), 2, args); - } - - /* Wrap and unwrap pcre regular expression handles, with a finalizer. */ -diff --git a/common/mltools/uri-c.c b/common/mltools/uri-c.c -index 2a8837cd9..e03647c7b 100644 ---- a/common/mltools/uri-c.c -+++ b/common/mltools/uri-c.c -@@ -46,10 +46,8 @@ guestfs_int_mllib_parse_uri (value argv /* arg value, not an array! */) - int r; - - r = parse_uri (String_val (argv), &uri); -- if (r == -1) { -- value *exn = caml_named_value ("URI.Parse_failed"); -- caml_raise (*exn); -- } -+ if (r == -1) -+ caml_raise (*caml_named_value ("URI.Parse_failed")); - - /* Convert the struct into an OCaml tuple. */ - rv = caml_alloc_tuple (5); -diff --git a/common/mlvisit/visit-c.c b/common/mlvisit/visit-c.c -index 7137c4998..201f6d762 100644 ---- a/common/mlvisit/visit-c.c -+++ b/common/mlvisit/visit-c.c -@@ -53,7 +53,6 @@ value - guestfs_int_mllib_visit (value gv, value dirv, value fv) - { - CAMLparam3 (gv, dirv, fv); -- value *visit_failure_exn; - guestfs_h *g = (guestfs_h *) (intptr_t) Int64_val (gv); - struct visitor_function_wrapper_args args; - /* The dir string could move around when we call the -@@ -84,8 +83,7 @@ guestfs_int_mllib_visit (value gv, value dirv, value fv) - * already printed the error to stderr (XXX - fix), so we raise a - * generic exception. - */ -- visit_failure_exn = caml_named_value ("Visit.Failure"); -- caml_raise (*visit_failure_exn); -+ caml_raise (*caml_named_value ("Visit.Failure")); - } - free (dir); - --- -2.18.4 - diff --git a/SOURCES/0078-RHEL-8-Remove-User-Mode-Linux-RHBZ-1144197.patch b/SOURCES/0004-RHEL-8-Remove-User-Mode-Linux-RHBZ-1144197.patch similarity index 85% rename from SOURCES/0078-RHEL-8-Remove-User-Mode-Linux-RHBZ-1144197.patch rename to SOURCES/0004-RHEL-8-Remove-User-Mode-Linux-RHBZ-1144197.patch index fb4d77a..bb2f9e9 100644 --- a/SOURCES/0078-RHEL-8-Remove-User-Mode-Linux-RHBZ-1144197.patch +++ b/SOURCES/0004-RHEL-8-Remove-User-Mode-Linux-RHBZ-1144197.patch @@ -1,4 +1,4 @@ -From cbb6a42b9074ed78c74ddefee4ec7571132a4d24 Mon Sep 17 00:00:00 2001 +From 34f8c6a5eb0eabfba4ab1831b45e2baa73a4b501 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 19 Sep 2014 13:38:20 +0100 Subject: [PATCH] RHEL 8: Remove User-Mode Linux (RHBZ#1144197). @@ -9,7 +9,7 @@ This isn't supported in RHEL 8. 1 file changed, 13 insertions(+) diff --git a/lib/launch-uml.c b/lib/launch-uml.c -index da20c17d9..a5e0e8179 100644 +index 5aec50a57..8b9fcd770 100644 --- a/lib/launch-uml.c +++ b/lib/launch-uml.c @@ -44,7 +44,9 @@ struct backend_uml_data { @@ -30,7 +30,7 @@ index da20c17d9..a5e0e8179 100644 /* Test for features which are not supported by the UML backend. * Possibly some of these should just be warnings, not errors. */ -@@ -128,10 +131,17 @@ uml_supported (guestfs_h *g) +@@ -133,10 +136,17 @@ uml_supported (guestfs_h *g) return true; } @@ -48,7 +48,7 @@ index da20c17d9..a5e0e8179 100644 struct backend_uml_data *data = datav; CLEANUP_FREE_STRINGSBUF DECLARE_STRINGSBUF (cmdline); int console_sock = -1, daemon_sock = -1; -@@ -491,8 +501,10 @@ launch_uml (guestfs_h *g, void *datav, const char *arg) +@@ -496,8 +506,10 @@ launch_uml (guestfs_h *g, void *datav, const char *arg) } g->state = CONFIG; return -1; @@ -59,7 +59,7 @@ index da20c17d9..a5e0e8179 100644 /* This is called from the forked subprocess just before vmlinux runs, * so it can just print the message straight to stderr, where it will * be picked up and funnelled through the usual appliance event API. -@@ -522,6 +534,7 @@ print_vmlinux_command_line (guestfs_h *g, char **argv) +@@ -527,6 +539,7 @@ print_vmlinux_command_line (guestfs_h *g, char **argv) fputc ('\n', stderr); } @@ -68,5 +68,5 @@ index da20c17d9..a5e0e8179 100644 static int shutdown_uml (guestfs_h *g, void *datav, int check_for_errors) -- -2.18.4 +2.31.1 diff --git a/SOURCES/0004-ocaml-Use-caml_alloc_initialized_string-instead-of-m.patch b/SOURCES/0004-ocaml-Use-caml_alloc_initialized_string-instead-of-m.patch deleted file mode 100644 index 6b6c1c4..0000000 --- a/SOURCES/0004-ocaml-Use-caml_alloc_initialized_string-instead-of-m.patch +++ /dev/null @@ -1,121 +0,0 @@ -From 5c5cc8b7bc2588c04dd0d0472b466f978f8ac55c Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 6 Feb 2020 10:17:35 +0000 -Subject: [PATCH] ocaml: Use caml_alloc_initialized_string instead of memcpy. - -See this commit in libguestfs-common: -https://github.com/libguestfs/libguestfs-common/commit/398dc56a6cb5d6d01506338fa94ef580e668d5e9 - -(cherry picked from commit 9f3148c791a970b7d6adf249e949a1b7e0b4b0c1) ---- - generator/OCaml.ml | 10 ++++------ - m4/guestfs-ocaml.m4 | 18 ++++++++++++++++++ - ocaml/guestfs-c.c | 3 +-- - ocaml/guestfs-c.h | 18 ++++++++++++++++++ - 4 files changed, 41 insertions(+), 8 deletions(-) - -diff --git a/generator/OCaml.ml b/generator/OCaml.ml -index bd4f73b85..1b6970f6d 100644 ---- a/generator/OCaml.ml -+++ b/generator/OCaml.ml -@@ -504,12 +504,11 @@ copy_table (char * const * argv) - | name, FString -> - pr " v = caml_copy_string (%s->%s);\n" typ name - | name, FBuffer -> -- pr " v = caml_alloc_string (%s->%s_len);\n" typ name; -- pr " memcpy (String_val (v), %s->%s, %s->%s_len);\n" -+ pr " v = caml_alloc_initialized_string (%s->%s_len, %s->%s);\n" - typ name typ name - | name, FUUID -> -- pr " v = caml_alloc_string (32);\n"; -- pr " memcpy (String_val (v), %s->%s, 32);\n" typ name -+ pr " v = caml_alloc_initialized_string (32, %s->%s);\n" -+ typ name - | name, (FBytes|FInt64|FUInt64) -> - pr " v = caml_copy_int64 (%s->%s);\n" typ name - | name, (FInt32|FUInt32) -> -@@ -757,8 +756,7 @@ copy_table (char * const * argv) - pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n"; - pr " free (r);\n"; - | RBufferOut _ -> -- pr " rv = caml_alloc_string (size);\n"; -- pr " memcpy (String_val (rv), r, size);\n"; -+ pr " rv = caml_alloc_initialized_string (size, r);\n"; - pr " free (r);\n" - ); - -diff --git a/m4/guestfs-ocaml.m4 b/m4/guestfs-ocaml.m4 -index 3c504ce7e..90658e8c5 100644 ---- a/m4/guestfs-ocaml.m4 -+++ b/m4/guestfs-ocaml.m4 -@@ -221,6 +221,24 @@ AS_IF([test "x$have_Hivex_OPEN_UNSAFE" = "xno"],[ - ]) - AC_SUBST([HIVEX_OPEN_UNSAFE_FLAG]) - -+dnl Check if OCaml has caml_alloc_initialized_string (added 2017). -+AS_IF([test "x$OCAMLC" != "xno" && test "x$OCAMLFIND" != "xno" && \ -+ test "x$enable_ocaml" = "xyes"],[ -+ AC_MSG_CHECKING([for caml_alloc_initialized_string]) -+ cat >conftest.c <<'EOF' -+#include -+int main () { char *p = (void *) caml_alloc_initialized_string; return 0; } -+EOF -+ AS_IF([$OCAMLC conftest.c >&AS_MESSAGE_LOG_FD 2>&1],[ -+ AC_MSG_RESULT([yes]) -+ AC_DEFINE([HAVE_CAML_ALLOC_INITIALIZED_STRING],[1], -+ [caml_alloc_initialized_string found at compile time.]) -+ ],[ -+ AC_MSG_RESULT([no]) -+ ]) -+ rm -f conftest.c conftest.o -+]) -+ - dnl Flags we want to pass to every OCaml compiler call. - OCAML_WARN_ERROR="-warn-error CDEFLMPSUVYZX+52-3" - AC_SUBST([OCAML_WARN_ERROR]) -diff --git a/ocaml/guestfs-c.c b/ocaml/guestfs-c.c -index 3b5fb198f..18d7dd978 100644 ---- a/ocaml/guestfs-c.c -+++ b/ocaml/guestfs-c.c -@@ -360,8 +360,7 @@ event_callback_wrapper_locked (guestfs_h *g, - - ehv = Val_int (event_handle); - -- bufv = caml_alloc_string (buf_len); -- memcpy (String_val (bufv), buf, buf_len); -+ bufv = caml_alloc_initialized_string (buf_len, buf); - - arrayv = caml_alloc (array_len, 0); - for (i = 0; i < array_len; ++i) { -diff --git a/ocaml/guestfs-c.h b/ocaml/guestfs-c.h -index f05dbd8e7..93ad3e2bf 100644 ---- a/ocaml/guestfs-c.h -+++ b/ocaml/guestfs-c.h -@@ -19,6 +19,24 @@ - #ifndef GUESTFS_OCAML_C_H - #define GUESTFS_OCAML_C_H - -+#include "config.h" -+ -+#include -+#include -+ -+/* Replacement if caml_alloc_initialized_string is missing, added -+ * to OCaml runtime in 2017. -+ */ -+#ifndef HAVE_CAML_ALLOC_INITIALIZED_STRING -+static inline value -+caml_alloc_initialized_string (mlsize_t len, const char *p) -+{ -+ value sv = caml_alloc_string (len); -+ memcpy ((char *) String_val (sv), p, len); -+ return sv; -+} -+#endif -+ - #define Guestfs_val(v) (*((guestfs_h **)Data_custom_val(v))) - extern void guestfs_int_ocaml_raise_error (guestfs_h *g, const char *func) - Noreturn; --- -2.18.4 - diff --git a/SOURCES/0005-RHEL-8-Reject-use-of-libguestfs-winsupport-features-.patch b/SOURCES/0005-RHEL-8-Reject-use-of-libguestfs-winsupport-features-.patch new file mode 100644 index 0000000..ecdd554 --- /dev/null +++ b/SOURCES/0005-RHEL-8-Reject-use-of-libguestfs-winsupport-features-.patch @@ -0,0 +1,69 @@ +From cb2ac63562447e2780bd7103ed060fd6013b9054 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 7 Jul 2015 09:28:03 -0400 +Subject: [PATCH] RHEL 8: Reject use of libguestfs-winsupport features except + for virt-* tools (RHBZ#1240276). + +Fix the tests: it doesn't let us use guestfish for arbitrary Windows +edits. +--- + generator/c.ml | 16 ++++++++++++++++ + test-data/phony-guests/make-windows-img.sh | 1 + + tests/charsets/test-charset-fidelity.c | 2 ++ + 3 files changed, 19 insertions(+) + +diff --git a/generator/c.ml b/generator/c.ml +index 86d3b26f8..a625361a9 100644 +--- a/generator/c.ml ++++ b/generator/c.ml +@@ -1846,6 +1846,22 @@ and generate_client_actions actions () = + check_args_validity c_name style; + trace_call name c_name style; + ++ (* RHEL 8 *) ++ if name = "mount" || name = "mount_ro" || name = "mount_options" || ++ name = "mount_vfs" then ( ++ pr " if (g->program && !STRPREFIX (g->program, \"virt-\")) {\n"; ++ pr " CLEANUP_FREE char *vfs_type = guestfs_vfs_type (g, mountable);\n"; ++ pr " if (vfs_type && STREQ (vfs_type, \"ntfs\")) {\n"; ++ pr " error (g, \"mount: unsupported filesystem type\");\n"; ++ pr " if (trace_flag)\n"; ++ pr " guestfs_int_trace (g, \"%%s = %%s (error)\",\n"; ++ pr " \"%s\", \"-1\");\n" name; ++ pr " return %s;\n" (string_of_errcode errcode); ++ pr " }\n"; ++ pr " }\n"; ++ pr "\n"; ++ ); ++ + (* Calculate the total size of all FileIn arguments to pass + * as a progress bar hint. + *) +diff --git a/test-data/phony-guests/make-windows-img.sh b/test-data/phony-guests/make-windows-img.sh +index 30908a918..73cf5144e 100755 +--- a/test-data/phony-guests/make-windows-img.sh ++++ b/test-data/phony-guests/make-windows-img.sh +@@ -37,6 +37,7 @@ fi + + # Create a disk image. + guestfish < -Date: Thu, 6 Feb 2020 10:15:29 +0000 -Subject: [PATCH] ocaml: Use caml_alloc_initialized_string instead of memcpy. - -Since about 2017 OCaml has had a function for creating an initialized -string. This uses the function instead of caml_alloc_string + memcpy -(which doesn't work for OCaml 4.10) and defines a replacement if the -function is missing. - -Note this requires configure.ac in libguestfs.git and virt-v2v.git to -define HAVE_CAML_ALLOC_INITIALIZED_STRING. - -(cherry picked from commit 398dc56a6cb5d6d01506338fa94ef580e668d5e9) ---- - common/mlpcre/pcre-c.c | 16 ++++++++++++++-- - common/mlvisit/visit-c.c | 16 ++++++++++++++-- - common/mlxml/xml-c.c | 16 ++++++++++++++-- - 3 files changed, 42 insertions(+), 6 deletions(-) - -diff --git a/common/mlpcre/pcre-c.c b/common/mlpcre/pcre-c.c -index 07f99b8d6..7dbba5857 100644 ---- a/common/mlpcre/pcre-c.c -+++ b/common/mlpcre/pcre-c.c -@@ -39,6 +39,19 @@ - - #pragma GCC diagnostic ignored "-Wmissing-prototypes" - -+/* Replacement if caml_alloc_initialized_string is missing, added -+ * to OCaml runtime in 2017. -+ */ -+#ifndef HAVE_CAML_ALLOC_INITIALIZED_STRING -+static inline value -+caml_alloc_initialized_string (mlsize_t len, const char *p) -+{ -+ value sv = caml_alloc_string (len); -+ memcpy ((char *) String_val (sv), p, len); -+ return sv; -+} -+#endif -+ - /* Data on the most recent match is stored in this thread-local - * variable. It is freed either by the next call to PCRE.matches or - * by (clean) thread exit. -@@ -257,8 +270,7 @@ guestfs_int_pcre_sub (value nv) - if (len < 0) - raise_pcre_error ("pcre_get_substring", len); - -- strv = caml_alloc_string (len); -- memcpy (String_val (strv), str, len); -+ strv = caml_alloc_initialized_string (len, str); - CAMLreturn (strv); - } - -diff --git a/common/mlvisit/visit-c.c b/common/mlvisit/visit-c.c -index 201f6d762..d5585ca94 100644 ---- a/common/mlvisit/visit-c.c -+++ b/common/mlvisit/visit-c.c -@@ -35,6 +35,19 @@ - - #pragma GCC diagnostic ignored "-Wmissing-prototypes" - -+/* Replacement if caml_alloc_initialized_string is missing, added -+ * to OCaml runtime in 2017. -+ */ -+#ifndef HAVE_CAML_ALLOC_INITIALIZED_STRING -+static inline value -+caml_alloc_initialized_string (mlsize_t len, const char *p) -+{ -+ value sv = caml_alloc_string (len); -+ memcpy ((char *) String_val (sv), p, len); -+ return sv; -+} -+#endif -+ - struct visitor_function_wrapper_args { - /* In both case we are pointing to local roots, hence why these are - * value* not value. -@@ -198,8 +211,7 @@ copy_xattr (const struct guestfs_xattr *xattr) - rv = caml_alloc (2, 0); - v = caml_copy_string (xattr->attrname); - Store_field (rv, 0, v); -- v = caml_alloc_string (xattr->attrval_len); -- memcpy (String_val (v), xattr->attrval, xattr->attrval_len); -+ v = caml_alloc_initialized_string (xattr->attrval_len, xattr->attrval); - Store_field (rv, 1, v); - CAMLreturn (rv); - } -diff --git a/common/mlxml/xml-c.c b/common/mlxml/xml-c.c -index d3db7e227..a0fa0fc3d 100644 ---- a/common/mlxml/xml-c.c -+++ b/common/mlxml/xml-c.c -@@ -40,6 +40,19 @@ - - #pragma GCC diagnostic ignored "-Wmissing-prototypes" - -+/* Replacement if caml_alloc_initialized_string is missing, added -+ * to OCaml runtime in 2017. -+ */ -+#ifndef HAVE_CAML_ALLOC_INITIALIZED_STRING -+static inline value -+caml_alloc_initialized_string (mlsize_t len, const char *p) -+{ -+ value sv = caml_alloc_string (len); -+ memcpy ((char *) String_val (sv), p, len); -+ return sv; -+} -+#endif -+ - /* xmlDocPtr type */ - #define docptr_val(v) (*((xmlDocPtr *)Data_custom_val(v))) - -@@ -183,8 +196,7 @@ mllib_xml_to_string (value docv, value formatv) - doc = docptr_val (docv); - xmlDocDumpFormatMemory (doc, &mem, &size, Bool_val (formatv)); - -- strv = caml_alloc_string (size); -- memcpy (String_val (strv), mem, size); -+ strv = caml_alloc_initialized_string (size, mem); - free (mem); - - CAMLreturn (strv); --- -2.18.4 - diff --git a/SOURCES/0006-build-Avoid-warnings-about-unknown-pragmas.patch b/SOURCES/0006-build-Avoid-warnings-about-unknown-pragmas.patch new file mode 100644 index 0000000..b322d8d --- /dev/null +++ b/SOURCES/0006-build-Avoid-warnings-about-unknown-pragmas.patch @@ -0,0 +1,37 @@ +From dbd1eaab6a478cf0c3ea093a56b3d04c29278615 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 12 Jan 2021 10:23:11 +0000 +Subject: [PATCH] build: Avoid warnings about unknown pragmas. + +In commit 4bbbf03b8bc266ed2b63c461cd0945250bb134fe we started to +ignore bogus GCC 11 warnings. Unfortunately earlier versions of GCC +don't know about those pragmas so give warnings [hence errors in +developer builds] like: + +tsk.c:75:32: error: unknown option after '#pragma GCC diagnostic' kind [-Werror=pragmas] + +Turn off these warnings. + +Updates: commit 4bbbf03b8bc266ed2b63c461cd0945250bb134fe +(cherry picked from commit 812f837c97f48ce0c26a0e02286fb9180c282923) +--- + m4/guestfs-c.m4 | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/m4/guestfs-c.m4 b/m4/guestfs-c.m4 +index 25ffea0d9..bbb4db464 100644 +--- a/m4/guestfs-c.m4 ++++ b/m4/guestfs-c.m4 +@@ -108,6 +108,9 @@ gl_WARN_ADD([-Wformat-truncation=1]) + dnl GCC 9 at level 2 gives apparently bogus errors when %.*s is used. + gl_WARN_ADD([-Wformat-overflow=1]) + ++dnl GCC < 11 gives warnings when disabling GCC 11 warnings. ++gl_WARN_ADD([-Wno-pragmas]) ++ + AC_SUBST([WARN_CFLAGS]) + + NO_SNV_CFLAGS= +-- +2.31.1 + diff --git a/SOURCES/0006-ocaml-Change-calls-to-caml_named_value-to-cope-with-.patch b/SOURCES/0006-ocaml-Change-calls-to-caml_named_value-to-cope-with-.patch deleted file mode 100644 index 76e8119..0000000 --- a/SOURCES/0006-ocaml-Change-calls-to-caml_named_value-to-cope-with-.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 96462b30d5ca6e45601512609cedfc874739137d Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 5 Sep 2019 09:00:14 +0100 -Subject: [PATCH] ocaml: Change calls to caml_named_value() to cope with const - value* return. - -In OCaml >= 4.09 the return value pointer of caml_named_value is -declared const. - -Based on Pino Toscano's original patch to ocaml-augeas. - -(cherry picked from commit 74ce7332dbb9bab2a69737257f0d07c93eb9bab4) ---- - generator/daemon.ml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/generator/daemon.ml b/generator/daemon.ml -index a4e136aaa..b67c4d20b 100644 ---- a/generator/daemon.ml -+++ b/generator/daemon.ml -@@ -746,7 +746,7 @@ let generate_daemon_caml_stubs () = - let nr_args = List.length args_do_function in - - pr "{\n"; -- pr " static value *cb = NULL;\n"; -+ pr " static const value *cb = NULL;\n"; - pr " CAMLparam0 ();\n"; - pr " CAMLlocal2 (v, retv);\n"; - pr " CAMLlocalN (args, %d);\n" --- -2.18.4 - diff --git a/SOURCES/0007-cat-Fix-GCC-10-warning.patch b/SOURCES/0007-cat-Fix-GCC-10-warning.patch deleted file mode 100644 index 4cc5aba..0000000 --- a/SOURCES/0007-cat-Fix-GCC-10-warning.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 93422725a0a8248d97b67cdbc20e065f5164e089 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 6 Feb 2020 10:27:48 +0000 -Subject: [PATCH] cat: Fix GCC 10 warning. - -I believe this warning is bogus, but simply initializing the local -variable is enough to avoid it. - -log.c: In function 'do_log': -log.c:390:7: error: 'comm_len' may be used uninitialized in this function [-Werror=maybe-uninitialized] - 390 | printf (" %.*s", (int) comm_len, comm); - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -(cherry picked from commit 4e199494c41d3240aa5c0708887b7a7513c6b6f2) ---- - cat/log.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/cat/log.c b/cat/log.c -index 25107e25f..f8a5c85f2 100644 ---- a/cat/log.c -+++ b/cat/log.c -@@ -337,7 +337,7 @@ do_log_journal (void) - while ((r = guestfs_journal_next (g)) > 0) { - CLEANUP_FREE_XATTR_LIST struct guestfs_xattr_list *xattrs = NULL; - const char *priority_str, *identifier, *comm, *pid, *message; -- size_t priority_len, identifier_len, comm_len, pid_len, message_len; -+ size_t priority_len, identifier_len, comm_len = 0, pid_len, message_len; - int priority = LOG_INFO; - int64_t ts; - --- -2.18.4 - diff --git a/SOURCES/0096-daemon-lvm-Use-lvcreate-yes-to-avoid-interactive-pro.patch b/SOURCES/0007-daemon-lvm-Use-lvcreate-yes-to-avoid-interactive-pro.patch similarity index 91% rename from SOURCES/0096-daemon-lvm-Use-lvcreate-yes-to-avoid-interactive-pro.patch rename to SOURCES/0007-daemon-lvm-Use-lvcreate-yes-to-avoid-interactive-pro.patch index a370479..54275ce 100644 --- a/SOURCES/0096-daemon-lvm-Use-lvcreate-yes-to-avoid-interactive-pro.patch +++ b/SOURCES/0007-daemon-lvm-Use-lvcreate-yes-to-avoid-interactive-pro.patch @@ -1,4 +1,4 @@ -From 4e87c9e46f9a82f4b1c65a34602a939dcaa125eb Mon Sep 17 00:00:00 2001 +From 22416a2329ec531b9608c21b11ff3d53275fe7a0 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Mon, 22 Feb 2021 10:18:45 +0000 Subject: [PATCH] daemon: lvm: Use lvcreate --yes to avoid interactive prompts. @@ -6,6 +6,7 @@ Subject: [PATCH] daemon: lvm: Use lvcreate --yes to avoid interactive prompts. See https://bugzilla.redhat.com/show_bug.cgi?id=1930996#c1 Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1930996 +(cherry picked from commit 21cd97732c4973db835b8b6540c8ad582ebd2bda) --- daemon/lvm.c | 2 +- tests/regressions/Makefile.am | 2 ++ @@ -14,7 +15,7 @@ Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1930996 create mode 100755 tests/regressions/rhbz1930996.sh diff --git a/daemon/lvm.c b/daemon/lvm.c -index fa815e5c1..2911c1279 100644 +index 841dc4b6b..72c59c3a1 100644 --- a/daemon/lvm.c +++ b/daemon/lvm.c @@ -219,7 +219,7 @@ do_lvcreate (const char *logvol, const char *volgroup, int mbytes) @@ -27,10 +28,10 @@ index fa815e5c1..2911c1279 100644 if (r == -1) { reply_with_error ("%s", err); diff --git a/tests/regressions/Makefile.am b/tests/regressions/Makefile.am -index fbd5c0ed7..7007bf167 100644 +index ecb0d68a7..c1e0ee8a9 100644 --- a/tests/regressions/Makefile.am +++ b/tests/regressions/Makefile.am -@@ -51,6 +51,7 @@ EXTRA_DIST = \ +@@ -49,6 +49,7 @@ EXTRA_DIST = \ rhbz1370424.sh \ rhbz1370424.xml \ rhbz1477623.sh \ @@ -38,7 +39,7 @@ index fbd5c0ed7..7007bf167 100644 test-noexec-stack.pl TESTS = \ -@@ -82,6 +83,7 @@ TESTS = \ +@@ -79,6 +80,7 @@ TESTS = \ rhbz1285847.sh \ rhbz1370424.sh \ rhbz1477623.sh \ @@ -89,5 +90,5 @@ index 000000000..27089beaa + +rm $f -- -2.18.4 +2.31.1 diff --git a/SOURCES/0008-builder-Fix-const-correctness-for-OCaml-4.10.patch b/SOURCES/0008-builder-Fix-const-correctness-for-OCaml-4.10.patch deleted file mode 100644 index 654dcd9..0000000 --- a/SOURCES/0008-builder-Fix-const-correctness-for-OCaml-4.10.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 17df30b82007073a40deb37ff7f840d56a1b5bf1 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 6 Feb 2020 10:33:39 +0000 -Subject: [PATCH] builder: Fix const correctness for OCaml 4.10. - -String_val now returns a const char *. - -(cherry picked from commit d6fcf519f2d860fe3167629f042f5ff6a4ccc40d) ---- - builder/setlocale-c.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/builder/setlocale-c.c b/builder/setlocale-c.c -index f2ad85352..6d877e7ac 100644 ---- a/builder/setlocale-c.c -+++ b/builder/setlocale-c.c -@@ -44,7 +44,8 @@ virt_builder_setlocale (value val_category, value val_name) - { - CAMLparam2 (val_category, val_name); - CAMLlocal2 (rv, rv2); -- char *ret, *locstring; -+ const char *locstring; -+ char *ret; - int category; - - category = lc_string_table[Int_val (val_category)]; --- -2.18.4 - diff --git a/SOURCES/0008-inspection-More-reliable-detection-of-Linux-split-us.patch b/SOURCES/0008-inspection-More-reliable-detection-of-Linux-split-us.patch new file mode 100644 index 0000000..5b14b93 --- /dev/null +++ b/SOURCES/0008-inspection-More-reliable-detection-of-Linux-split-us.patch @@ -0,0 +1,113 @@ +From e1b339688e5f8f2a14fe0c7e9d02ad68004e4655 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 15 Apr 2021 09:18:22 +0100 +Subject: [PATCH] inspection: More reliable detection of Linux split /usr + configurations + +In RHEL 8+, /usr/etc no longer exists. Since we were looking for this +directory in order to detect a separate /usr partition, those were no +longer detected, so the merging of /usr data into the root was not +being done. The result was incomplete inspection data and failure of +virt-v2v. + +All Linux systems since forever have had /usr/src but not /src, so +detect this instead. + +Furthermore the merging code didn't work, because we expected that the +root filesystem had a distro assigned, but in this configuration we +may need to look for that information in /usr/lib/os-release (not on +the root filesystem). This change makes the merging work even if we +have incomplete information about the root filesystem, so long as we +have an /etc/fstab entry pointing to the /usr mountpoint. + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1949683 +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1930133 +Fixes: commit 394d11be49121884295e61964ed47f5a8488c252 +(cherry picked from commit 26427b9ecc64e7e5e53a1d577cef9dc080d08877) +--- + daemon/inspect.ml | 33 +++++++++++++++------------------ + daemon/inspect_fs.ml | 6 +++--- + 2 files changed, 18 insertions(+), 21 deletions(-) + +diff --git a/daemon/inspect.ml b/daemon/inspect.ml +index 945a476f6..fb75b4a6c 100644 +--- a/daemon/inspect.ml ++++ b/daemon/inspect.ml +@@ -182,11 +182,9 @@ and check_for_duplicated_bsd_root fses = + and collect_linux_inspection_info fses = + List.map ( + function +- | { role = RoleRoot { distro = Some d } } as root -> +- if d <> DISTRO_COREOS then +- collect_linux_inspection_info_for fses root +- else +- root ++ | { role = RoleRoot { distro = Some DISTRO_COREOS } } as root -> root ++ | { role = RoleRoot _ } as root -> ++ collect_linux_inspection_info_for fses root + | fs -> fs + ) fses + +@@ -196,29 +194,28 @@ and collect_linux_inspection_info fses = + * or other ways to identify the OS). + *) + and collect_linux_inspection_info_for fses root = +- let root_distro, root_fstab = ++ let root_fstab = + match root with +- | { role = RoleRoot { distro = Some d; fstab = f } } -> d, f ++ | { role = RoleRoot { fstab = f } } -> f + | _ -> assert false in + + try + let usr = + List.find ( + function +- | { role = RoleUsr { distro = d } } +- when d = Some root_distro || d = None -> true ++ | { role = RoleUsr _; fs_location = usr_mp } -> ++ (* This checks that this usr is found in the fstab of ++ * the root filesystem. ++ *) ++ List.exists ( ++ fun (mountable, _) -> ++ usr_mp.mountable = mountable ++ ) root_fstab + | _ -> false + ) fses in + +- let usr_mountable = usr.fs_location.mountable in +- +- (* This checks that [usr] is found in the fstab of the root +- * filesystem. If not, [Not_found] is thrown. +- *) +- ignore ( +- List.find (fun (mountable, _) -> usr_mountable = mountable) root_fstab +- ); +- ++ eprintf "collect_linux_inspection_info_for: merging:\n%sinto:\n%s" ++ (string_of_fs usr) (string_of_fs root); + merge usr root; + root + with +diff --git a/daemon/inspect_fs.ml b/daemon/inspect_fs.ml +index 6e00c7083..02b5a0470 100644 +--- a/daemon/inspect_fs.ml ++++ b/daemon/inspect_fs.ml +@@ -164,10 +164,10 @@ and check_filesystem mountable = + () + ) + (* Linux /usr? *) +- else if Is.is_dir "/etc" && +- Is.is_dir "/bin" && +- Is.is_dir "/share" && ++ else if Is.is_dir "/bin" && + Is.is_dir "/local" && ++ Is.is_dir "/share" && ++ Is.is_dir "/src" && + not (Is.is_file "/etc/fstab") then ( + debug_matching "Linux /usr"; + role := `Usr; +-- +2.31.1 + diff --git a/SOURCES/0009-lib-Autodetect-backing-format-for-qemu-img-create-b.patch b/SOURCES/0009-lib-Autodetect-backing-format-for-qemu-img-create-b.patch new file mode 100644 index 0000000..6cc2f94 --- /dev/null +++ b/SOURCES/0009-lib-Autodetect-backing-format-for-qemu-img-create-b.patch @@ -0,0 +1,49 @@ +From 791a16b049ea1ce2c450acd367fce774d9aab5b1 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 31 Aug 2021 08:27:15 +0100 +Subject: [PATCH] lib: Autodetect backing format for qemu-img create -b + +qemu 6.1 has decided to change qemu-img create so that a backing +format (-F) is required if a backing file (-b) is specified. Since we +don't want to change the libguestfs API to force callers to specify +this because that would be an API break, autodetect it. + +This is similar to commit c8c181e8d9 ("launch: libvirt: Autodetect +backing format for readonly drive overlays"). + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1998820 +(cherry picked from commit 45de287447bb18d59749fbfc1ec5072413090109) +--- + lib/create.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/lib/create.c b/lib/create.c +index 44a7df25f..75a4d3a28 100644 +--- a/lib/create.c ++++ b/lib/create.c +@@ -255,6 +255,7 @@ disk_create_qcow2 (guestfs_h *g, const char *filename, int64_t size, + const struct guestfs_disk_create_argv *optargs) + { + const char *backingformat = NULL; ++ CLEANUP_FREE char *backingformat_free = NULL; + const char *preallocation = NULL; + const char *compat = NULL; + int clustersize = -1; +@@ -270,6 +271,14 @@ disk_create_qcow2 (guestfs_h *g, const char *filename, int64_t size, + return -1; + } + } ++ else if (backingfile) { ++ /* Since qemu 6.1, qemu-img create has requires a backing format (-F) ++ * parameter if backing file (-b) is used (RHBZ#1998820). ++ */ ++ backingformat = backingformat_free = guestfs_disk_format (g, backingfile); ++ if (!backingformat) ++ return -1; ++ } + if (optargs->bitmask & GUESTFS_DISK_CREATE_PREALLOCATION_BITMASK) { + if (STREQ (optargs->preallocation, "off") || + STREQ (optargs->preallocation, "sparse")) +-- +2.31.1 + diff --git a/SOURCES/0009-mlxml-Fix-pointed-target-signedness.patch b/SOURCES/0009-mlxml-Fix-pointed-target-signedness.patch deleted file mode 100644 index d1bce94..0000000 --- a/SOURCES/0009-mlxml-Fix-pointed-target-signedness.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 8eb9f06b156c6362a17712cfed9c629dec297a2c Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 6 Feb 2020 10:22:42 +0000 -Subject: [PATCH] mlxml: Fix pointed target signedness. - -xml-c.c: In function 'mllib_xml_to_string': -xml-c.c:199:47: error: pointer targets in passing argument 2 of 'caml_alloc_initialized_string' differ in signedness [-Werror=pointer-sign] - 199 | strv = caml_alloc_initialized_string (size, mem); - | ^~~ - | | - | xmlChar * {aka unsigned char *} - -(cherry picked from commit ea10827b4cfb3cfe5f782421c01d2902e5f73f90) ---- - common/mlxml/xml-c.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/common/mlxml/xml-c.c b/common/mlxml/xml-c.c -index a0fa0fc3d..715c3bb24 100644 ---- a/common/mlxml/xml-c.c -+++ b/common/mlxml/xml-c.c -@@ -196,7 +196,7 @@ mllib_xml_to_string (value docv, value formatv) - doc = docptr_val (docv); - xmlDocDumpFormatMemory (doc, &mem, &size, Bool_val (formatv)); - -- strv = caml_alloc_initialized_string (size, mem); -+ strv = caml_alloc_initialized_string (size, (const char *) mem); - free (mem); - - CAMLreturn (strv); --- -2.18.4 - diff --git a/SOURCES/0010-common-mlpcre-add-offset-flag-for-PCRE.matches.patch b/SOURCES/0010-common-mlpcre-add-offset-flag-for-PCRE.matches.patch deleted file mode 100644 index 16d1443..0000000 --- a/SOURCES/0010-common-mlpcre-add-offset-flag-for-PCRE.matches.patch +++ /dev/null @@ -1,126 +0,0 @@ -From 83c76b6c610df17e0b9bfd9cd11deb43ebc40411 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Tue, 19 Feb 2019 10:50:01 +0100 -Subject: [PATCH] common/mlpcre: add offset flag for PCRE.matches - -This way it is possible to change where the matching start, instead of -always assuming it is the beginning. - -(cherry picked from commit 0ed2e5c14a302d15fd3b75ee2c1cb808a06cb746) ---- - common/mlpcre/PCRE.ml | 2 +- - common/mlpcre/PCRE.mli | 5 ++++- - common/mlpcre/pcre-c.c | 16 +++++++++++++--- - common/mlpcre/pcre_tests.ml | 11 ++++++++--- - 4 files changed, 26 insertions(+), 8 deletions(-) - -diff --git a/common/mlpcre/PCRE.ml b/common/mlpcre/PCRE.ml -index b054928f9..33074af1c 100644 ---- a/common/mlpcre/PCRE.ml -+++ b/common/mlpcre/PCRE.ml -@@ -23,7 +23,7 @@ exception Error of string * int - type regexp - - external compile : ?anchored:bool -> ?caseless:bool -> ?dotall:bool -> ?extended:bool -> ?multiline:bool -> string -> regexp = "guestfs_int_pcre_compile_byte" "guestfs_int_pcre_compile" --external matches : regexp -> string -> bool = "guestfs_int_pcre_matches" -+external matches : ?offset:int -> regexp -> string -> bool = "guestfs_int_pcre_matches" - external sub : int -> string = "guestfs_int_pcre_sub" - external subi : int -> int * int = "guestfs_int_pcre_subi" - -diff --git a/common/mlpcre/PCRE.mli b/common/mlpcre/PCRE.mli -index eacb6fd90..e10d512fc 100644 ---- a/common/mlpcre/PCRE.mli -+++ b/common/mlpcre/PCRE.mli -@@ -62,7 +62,7 @@ val compile : ?anchored:bool -> ?caseless:bool -> ?dotall:bool -> ?extended:bool - See pcreapi(3) for details of what they do. - All flags default to false. *) - --val matches : regexp -> string -> bool -+val matches : ?offset:int -> regexp -> string -> bool - (** Test whether the regular expression matches the string. This - returns true if the regexp matches or false otherwise. - -@@ -71,6 +71,9 @@ val matches : regexp -> string -> bool - or the thread/program exits. You can call {!sub} to return - these substrings. - -+ The [?offset] flag is used to change the start of the search, -+ which by default is at the beginning of the string (position 0). -+ - This can raise {!Error} if PCRE returns an error. *) - - val sub : int -> string -diff --git a/common/mlpcre/pcre-c.c b/common/mlpcre/pcre-c.c -index 7dbba5857..ec3a6f00d 100644 ---- a/common/mlpcre/pcre-c.c -+++ b/common/mlpcre/pcre-c.c -@@ -133,6 +133,15 @@ is_Some_true (value v) - Bool_val (Field (v, 0)) /* Some true */; - } - -+static int -+Optint_val (value intv, int defval) -+{ -+ if (intv == Val_int (0)) /* None */ -+ return defval; -+ else /* Some int */ -+ return Int_val (Field (intv, 0)); -+} -+ - value - guestfs_int_pcre_compile (value anchoredv, value caselessv, value dotallv, - value extendedv, value multilinev, -@@ -177,9 +186,9 @@ guestfs_int_pcre_compile_byte (value *argv, int argn) - } - - value --guestfs_int_pcre_matches (value rev, value strv) -+guestfs_int_pcre_matches (value offsetv, value rev, value strv) - { -- CAMLparam2 (rev, strv); -+ CAMLparam3 (offsetv, rev, strv); - pcre *re = Regexp_val (rev); - struct last_match *m, *oldm; - size_t len = caml_string_length (strv); -@@ -217,7 +226,8 @@ guestfs_int_pcre_matches (value rev, value strv) - caml_raise_out_of_memory (); - } - -- m->r = pcre_exec (re, NULL, m->subject, len, 0, 0, m->vec, veclen); -+ m->r = pcre_exec (re, NULL, m->subject, len, Optint_val (offsetv, 0), 0, -+ m->vec, veclen); - if (m->r < 0 && m->r != PCRE_ERROR_NOMATCH) { - int ret = m->r; - free_last_match (m); -diff --git a/common/mlpcre/pcre_tests.ml b/common/mlpcre/pcre_tests.ml -index 346019c40..3e5981107 100644 ---- a/common/mlpcre/pcre_tests.ml -+++ b/common/mlpcre/pcre_tests.ml -@@ -30,9 +30,9 @@ let compile ?(anchored = false) ?(caseless = false) - patt; - PCRE.compile ~anchored ~caseless ~dotall ~extended ~multiline patt - --let matches re str = -- eprintf "PCRE.matches %s ->%!" str; -- let r = PCRE.matches re str in -+let matches ?(offset = 0) re str = -+ eprintf "PCRE.matches %s, %d ->%!" str offset; -+ let r = PCRE.matches ~offset re str in - eprintf " %b\n%!" r; - r - -@@ -103,6 +103,11 @@ let () = - assert (subi 1 = (2, 3)); - assert (subi 2 = (3, 3)); - -+ assert (matches ~offset:5 re0 "aaabcabc" = true); -+ assert (sub 0 = "ab"); -+ -+ assert (matches ~offset:5 re0 "aaabcbaac" = false); -+ - assert (replace re0 "dd" "abcabcaabccca" = "ddcabcaabccca"); - assert (replace ~global:true re0 "dd" "abcabcaabccca" = "ddcddcddccca"); - --- -2.18.4 - diff --git a/SOURCES/0010-daemon-chroot-Fix-long-standing-possible-deadlock.patch b/SOURCES/0010-daemon-chroot-Fix-long-standing-possible-deadlock.patch new file mode 100644 index 0000000..d606eae --- /dev/null +++ b/SOURCES/0010-daemon-chroot-Fix-long-standing-possible-deadlock.patch @@ -0,0 +1,44 @@ +From 3435938f43ca3737ec1d73da4d8cad756b5c9508 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 26 Mar 2021 16:04:43 +0000 +Subject: [PATCH] daemon: chroot: Fix long-standing possible deadlock. + +The child (chrooted) process wrote its answer on the pipe and then +exited. Meanwhile the parent waiting for the child to exit before +reading from the pipe. Thus if the output was larger than a Linux +pipebuffer then the whole thing would deadlock. + +(cherry picked from commit 94e64b28bee3b8dc7ed354a366d6a8f7ba5f245c) +--- + daemon/chroot.ml | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/daemon/chroot.ml b/daemon/chroot.ml +index 5e856c91f..7da8ae29e 100644 +--- a/daemon/chroot.ml ++++ b/daemon/chroot.ml +@@ -62,6 +62,10 @@ let f t func arg = + (* Parent. *) + close wfd; + ++ let chan = in_channel_of_descr rfd in ++ let ret = input_value chan in ++ close_in chan; ++ + let _, status = waitpid [] pid in + (match status with + | WEXITED 0 -> () +@@ -76,10 +80,6 @@ let f t func arg = + failwithf "chroot ‘%s’ stopped by signal %d" t.name i + ); + +- let chan = in_channel_of_descr rfd in +- let ret = input_value chan in +- close_in chan; +- + match ret with + | Either ret -> ret + | Or exn -> raise exn +-- +2.31.1 + diff --git a/SOURCES/0011-inspection-Fix-inspection-of-recent-RPM-guests-using.patch b/SOURCES/0011-inspection-Fix-inspection-of-recent-RPM-guests-using.patch new file mode 100644 index 0000000..49f0938 --- /dev/null +++ b/SOURCES/0011-inspection-Fix-inspection-of-recent-RPM-guests-using.patch @@ -0,0 +1,1064 @@ +From 2ff8ad25680373997c2975d7ca51f3af7115eb01 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 26 Mar 2021 12:19:28 +0000 +Subject: [PATCH] inspection: Fix inspection of recent RPM guests using + non-BDB. + +Recent RPM-based guests have switched from using Berkeley DB (BDB) to +sqlite. In order to inspect these guests (and earlier ones) we need +to stop using the hokey parsing of the BDB and use librpm APIs +instead. + +This commit adds a new internal API so we can call librpm from the +daemon, and changes the library part to use the new API for RPM-based +guests. + +This change removes the requirement for BDB tools like db_dump. + +See also: +http://lists.rpm.org/pipermail/rpm-ecosystem/2021-March/000751.html +http://lists.rpm.org/pipermail/rpm-ecosystem/2021-March/000754.html +https://blog.fpmurphy.com/2011/08/programmatically-retrieve-rpm-package-details.html + +This breaks the virt-inspector test (now in the separate guestfs-tools +repository). However this is not a bug in libguestfs, but a bug in +the phoney Fedora guest that we use for testing - we created a +BDB-style RPM database which was supposed to be just enough to make +the old code work. The new code using real librpm needs +/usr/lib/rpm/rpmrc (not present in the phoney image) and also cannot +parse the phoney database, so we will need to separately rework that +test. + +Thanks: Panu Matilainen +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1766487 +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1409024 +(cherry picked from commit c9ee831affed55abe0f928134cbbd2ed83b2f510) +--- + .gitignore | 1 + + appliance/packagelist.in | 2 + + daemon/Makefile.am | 8 +- + daemon/rpm-c.c | 161 ++++++++++++++++++++ + daemon/rpm.ml | 58 +++++++ + docs/C_SOURCE_FILES | 2 +- + docs/guestfs-building.pod | 9 +- + generator/actions_inspection.ml | 10 ++ + generator/proc_nr.ml | 1 + + lib/MAX_PROC_NR | 2 +- + lib/Makefile.am | 1 - + lib/dbdump.c | 229 ---------------------------- + lib/guestfs-internal.h | 4 - + lib/inspect-apps.c | 259 +------------------------------- + m4/guestfs-daemon.m4 | 8 + + m4/guestfs-progs.m4 | 10 -- + 16 files changed, 258 insertions(+), 507 deletions(-) + create mode 100644 daemon/rpm-c.c + create mode 100644 daemon/rpm.ml + delete mode 100644 lib/dbdump.c + +diff --git a/.gitignore b/.gitignore +index 7a4696b90..c8b53cac9 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -176,6 +176,7 @@ Makefile.in + /daemon/optgroups.mli + /daemon/parted.mli + /daemon/realpath.mli ++/daemon/rpm.mli + /daemon/stamp-guestfsd.pod + /daemon/statvfs.mli + /daemon/structs-cleanups.c +diff --git a/appliance/packagelist.in b/appliance/packagelist.in +index 25f2645d2..15af4284a 100644 +--- a/appliance/packagelist.in ++++ b/appliance/packagelist.in +@@ -41,6 +41,7 @@ ifelse(REDHAT,1, + openssh-clients + policycoreutils + reiserfs-utils ++ rpm-libs + syslinux-extlinux + systemd dnl for /sbin/reboot and udevd + vim-minimal +@@ -71,6 +72,7 @@ dnl iproute has been renamed to iproute2 + isc-dhcp-client + ldmtool + libc-bin ++ librpm9 + linux-image + dnl syslinux 'suggests' mtools, but in reality it's a hard dependency: + mtools +diff --git a/daemon/Makefile.am b/daemon/Makefile.am +index df9dcc4ee..7f2d13414 100644 +--- a/daemon/Makefile.am ++++ b/daemon/Makefile.am +@@ -57,6 +57,7 @@ generator_built = \ + optgroups.mli \ + parted.mli \ + realpath.mli \ ++ rpm.mli \ + statvfs.mli \ + structs.ml \ + structs.mli +@@ -167,6 +168,7 @@ guestfsd_SOURCES = \ + proto.c \ + readdir.c \ + rename.c \ ++ rpm-c.c \ + rsync.c \ + scrub.c \ + selinux.c \ +@@ -231,6 +233,7 @@ guestfsd_LDADD = \ + $(LIB_CLOCK_GETTIME) \ + $(LIBINTL) \ + $(PCRE_LIBS) \ ++ $(LIBRPM_LIBS) \ + $(TSK_LIBS) \ + $(RPC_LIBS) \ + $(YARA_LIBS) \ +@@ -260,7 +263,8 @@ guestfsd_CFLAGS = \ + $(HIVEX_CFLAGS) \ + $(SD_JOURNAL_CFLAGS) \ + $(JANSSON_CFLAGS) \ +- $(PCRE_CFLAGS) ++ $(PCRE_CFLAGS) \ ++ $(LIBRPM_CFLAGS) + + # Parts of the daemon are written in OCaml. These are linked into a + # library and then linked to the daemon. See +@@ -298,6 +302,7 @@ SOURCES_MLI = \ + optgroups.mli \ + parted.mli \ + realpath.mli \ ++ rpm.mli \ + statvfs.mli \ + structs.mli \ + sysroot.mli \ +@@ -338,6 +343,7 @@ SOURCES_ML = \ + inspect_fs_windows.ml \ + inspect_fs.ml \ + inspect.ml \ ++ rpm.ml \ + callbacks.ml \ + daemon.ml + +diff --git a/daemon/rpm-c.c b/daemon/rpm-c.c +new file mode 100644 +index 000000000..92a3abf58 +--- /dev/null ++++ b/daemon/rpm-c.c +@@ -0,0 +1,161 @@ ++/* libguestfs - the guestfsd daemon ++ * Copyright (C) 2021 Red Hat Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#ifdef HAVE_LIBRPM ++#include ++#include ++#include ++#include ++#endif ++ ++#include "daemon.h" ++#include "actions.h" ++ ++/* Very lightweight OCaml bindings for librpm. */ ++ ++#pragma GCC diagnostic ignored "-Wimplicit-function-declaration" ++#pragma GCC diagnostic ignored "-Wmissing-prototypes" ++ ++#ifndef HAVE_LIBRPM ++ ++value __attribute__((noreturn)) ++guestfs_int_daemon_rpm_init (value unitv) ++{ ++ CAMLparam1 (unitv); ++ caml_failwith ("no support for RPM guests because " ++ "librpm was missing at compile time"); ++} ++ ++value __attribute__((noreturn)) ++guestfs_int_daemon_rpm_start_iterator (value unitv) ++{ ++ guestfs_int_daemon_rpm_init (unitv); ++} ++ ++value __attribute__((noreturn)) ++guestfs_int_daemon_rpm_next_application (value unitv) ++{ ++ guestfs_int_daemon_rpm_init (unitv); ++} ++ ++value __attribute__((noreturn)) ++guestfs_int_daemon_rpm_end_iterator (value unitv) ++{ ++ guestfs_int_daemon_rpm_init (unitv); ++} ++ ++#else /* HAVE_LIBRPM */ ++ ++value ++guestfs_int_daemon_rpm_init (value unitv) ++{ ++ CAMLparam1 (unitv); ++ rpmReadConfigFiles (NULL, NULL); ++ CAMLreturn (Val_unit); ++} ++ ++static rpmts ts; ++static rpmdbMatchIterator iter; ++ ++value ++guestfs_int_daemon_rpm_start_iterator (value unitv) ++{ ++ CAMLparam1 (unitv); ++ ts = rpmtsCreate (); ++ iter = rpmtsInitIterator (ts, RPMDBI_PACKAGES, NULL, 0); ++ CAMLreturn (Val_unit); ++} ++ ++value ++guestfs_int_daemon_rpm_next_application (value unitv) ++{ ++ CAMLparam1 (unitv); ++ CAMLlocal2 (rv, sv); ++ Header h; ++ guestfs_int_application2 app = { 0 }; ++ ++ h = rpmdbNextIterator (iter); ++ if (h == NULL) caml_raise_not_found (); ++ ++ h = headerLink (h); ++ app.app2_name = headerFormat (h, "%{NAME}", NULL); ++ // XXXapp.app2_epoch = headerFormat (h, "%{NAME}", NULL); ++ app.app2_version = headerFormat (h, "%{VERSION}", NULL); ++ app.app2_release = headerFormat (h, "%{RELEASE}", NULL); ++ app.app2_arch = headerFormat (h, "%{ARCH}", NULL); ++ app.app2_url = headerFormat (h, "%{URL}", NULL); ++ app.app2_summary = headerFormat (h, "%{SUMMARY}", NULL); ++ app.app2_description = headerFormat (h, "%{DESCRIPTION}", NULL); ++ headerFree (h); ++ ++ /* Convert this to an OCaml struct. Any NULL fields must be turned ++ * into empty string. ++ */ ++ rv = caml_alloc (17, 0); ++#define TO_CAML_STRING(i, name) \ ++ sv = caml_copy_string (app.name ? app.name : ""); \ ++ Store_field (rv, i, sv); \ ++ free (app.name) ++ ++ TO_CAML_STRING (0, app2_name); ++ TO_CAML_STRING (1, app2_display_name); ++ sv = caml_copy_int32 (app.app2_epoch); ++ Store_field (rv, 2, sv); ++ TO_CAML_STRING (3, app2_version); ++ TO_CAML_STRING (4, app2_release); ++ TO_CAML_STRING (5, app2_arch); ++ TO_CAML_STRING (6, app2_install_path); ++ TO_CAML_STRING (7, app2_trans_path); ++ TO_CAML_STRING (8, app2_publisher); ++ TO_CAML_STRING (9, app2_url); ++ TO_CAML_STRING (10, app2_source_package); ++ TO_CAML_STRING (11, app2_summary); ++ TO_CAML_STRING (12, app2_description); ++ TO_CAML_STRING (13, app2_spare1); ++ TO_CAML_STRING (14, app2_spare2); ++ TO_CAML_STRING (15, app2_spare3); ++ TO_CAML_STRING (16, app2_spare4); ++#undef TO_CAML_STRING ++ ++ CAMLreturn (rv); ++} ++ ++value ++guestfs_int_daemon_rpm_end_iterator (value unitv) ++{ ++ CAMLparam1 (unitv); ++ rpmdbFreeIterator (iter); ++ rpmtsFree (ts); ++ CAMLreturn (Val_unit); ++} ++ ++#endif /* HAVE_LIBRPM */ +diff --git a/daemon/rpm.ml b/daemon/rpm.ml +new file mode 100644 +index 000000000..f61ce41c5 +--- /dev/null ++++ b/daemon/rpm.ml +@@ -0,0 +1,58 @@ ++(* guestfs-inspection ++ * Copyright (C) 2009-2021 Red Hat Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ *) ++ ++open Printf ++ ++open Std_utils ++ ++external rpm_init : unit -> unit = "guestfs_int_daemon_rpm_init" ++external rpm_start_iterator : unit -> unit = "guestfs_int_daemon_rpm_start_iterator" ++external rpm_next_application : unit -> Structs.application2 = "guestfs_int_daemon_rpm_next_application" ++external rpm_end_iterator : unit -> unit = "guestfs_int_daemon_rpm_end_iterator" ++ ++(* librpm is troublesome when run from the main process. In ++ * particular it holds open some glibc NSS files. Therefore we fork ++ * before doing the chroot and any librpm operations. ++ * ++ * We could also consider in future limiting the time taken to run the ++ * subprocess since it's unclear that parsing RPM config files from ++ * the guest in particular is safe. ++ *) ++let rec internal_list_rpm_applications () = ++ let chroot = Chroot.create ~name:"librpm" () in ++ let apps = Chroot.f chroot list_rpm_applications () in ++ eprintf "librpm returned %d installed packages\n%!" (List.length apps); ++ apps ++ ++and list_rpm_applications () = ++ rpm_init (); ++ rpm_start_iterator (); ++ let ret = ref [] in ++ let rec loop () = ++ try ++ let app = rpm_next_application () in ++ List.push_front app ret; ++ loop () ++ with Not_found -> () ++ in ++ loop (); ++ rpm_end_iterator (); ++ List.sort ++ (fun { Structs.app2_name = n1 } { Structs.app2_name = n2 } -> ++ compare n1 n2) ++ !ret +diff --git a/docs/C_SOURCE_FILES b/docs/C_SOURCE_FILES +index 831b7e25a..8b6aa8896 100644 +--- a/docs/C_SOURCE_FILES ++++ b/docs/C_SOURCE_FILES +@@ -149,6 +149,7 @@ daemon/pingdaemon.c + daemon/proto.c + daemon/readdir.c + daemon/rename.c ++daemon/rpm-c.c + daemon/rsync.c + daemon/scrub.c + daemon/selinux-relabel.c +@@ -293,7 +294,6 @@ lib/command.c + lib/conn-socket.c + lib/copy-in-out.c + lib/create.c +-lib/dbdump.c + lib/drives.c + lib/errors.c + lib/event-string.c +diff --git a/docs/guestfs-building.pod b/docs/guestfs-building.pod +index 28c761ce4..4d75772d0 100644 +--- a/docs/guestfs-building.pod ++++ b/docs/guestfs-building.pod +@@ -210,11 +210,6 @@ eg. F. + Optional. Used by the L to + securely confine the appliance (sVirt). + +-=item Berkeley DB utils (db_dump, db_load, etc) +- +-Optional. Usually found in a package called C, +-C, C etc. +- + =item systemtap + + Optional. For userspace probes. +@@ -252,6 +247,10 @@ Optional. Render icons from guests. + + Optional. Render icons from Windows guests. + ++=item librpm ++ ++Optional. To parse the list of applications from RPM-based guests. ++ + =item Perl C + + Optional. Perl module used to test L. +diff --git a/generator/actions_inspection.ml b/generator/actions_inspection.ml +index e2098cb00..690afd460 100644 +--- a/generator/actions_inspection.ml ++++ b/generator/actions_inspection.ml +@@ -607,6 +607,16 @@ Please read L for more details. + See also C, + C." }; + ++ { defaults with ++ name = "internal_list_rpm_applications"; added = (1, 45, 3); ++ style = RStructList ("applications2", "application2"), [], []; ++ visibility = VInternal; ++ impl = OCaml "Rpm.internal_list_rpm_applications"; ++ shortdesc = "get applications from RPM guest"; ++ longdesc = "\ ++This internal function is used by C ++to list the applications for RPM guests."}; ++ + ] + + let non_daemon_functions = [ +diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml +index 57976be36..6b6cb7353 100644 +--- a/generator/proc_nr.ml ++++ b/generator/proc_nr.ml +@@ -514,6 +514,7 @@ let proc_nr = [ + 507, "luks_uuid"; + 508, "cryptsetup_open"; + 509, "cryptsetup_close"; ++510, "internal_list_rpm_applications"; + ] + + (* End of list. If adding a new entry, add it at the end of the list +diff --git a/lib/MAX_PROC_NR b/lib/MAX_PROC_NR +index 77afe238f..2bc4cd64b 100644 +--- a/lib/MAX_PROC_NR ++++ b/lib/MAX_PROC_NR +@@ -1 +1 @@ +-509 ++510 +diff --git a/lib/Makefile.am b/lib/Makefile.am +index f9cc53df1..7f36ae515 100644 +--- a/lib/Makefile.am ++++ b/lib/Makefile.am +@@ -81,7 +81,6 @@ libguestfs_la_SOURCES = \ + conn-socket.c \ + copy-in-out.c \ + create.c \ +- dbdump.c \ + drives.c \ + errors.c \ + event-string.c \ +diff --git a/lib/dbdump.c b/lib/dbdump.c +deleted file mode 100644 +index 7c17ce6b3..000000000 +--- a/lib/dbdump.c ++++ /dev/null +@@ -1,229 +0,0 @@ +-/* libguestfs +- * Copyright (C) 2010-2012 Red Hat Inc. +- * +- * This library is free software; you can redistribute it and/or +- * modify it under the terms of the GNU Lesser General Public +- * License as published by the Free Software Foundation; either +- * version 2 of the License, or (at your option) any later version. +- * +- * This library is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- * Lesser General Public License for more details. +- * +- * You should have received a copy of the GNU Lesser General Public +- * License along with this library; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-#include +- +-#include +-#include +-#include +-#include +-#include +- +-#ifdef HAVE_ENDIAN_H +-#include +-#endif +- +-#include "guestfs.h" +-#include "guestfs-internal.h" +- +-#if defined(DB_DUMP) +- +-static void read_db_dump_line (guestfs_h *g, void *datav, const char *line, size_t len); +-static unsigned char *convert_hex_to_binary (guestfs_h *g, const char *hex, size_t hexlen, size_t *binlen_rtn); +- +-struct cb_data { +- guestfs_int_db_dump_callback callback; +- void *opaque; +- enum { reading_header, +- reading_key, reading_value, +- reading_finished, +- reading_failed } state; +- unsigned char *key; +- size_t keylen; +-}; +- +-/* This helper function is specialized to just reading the hash-format +- * output from db_dump/db4_dump. It's just enough to support the RPM +- * database format. +- */ +-int +-guestfs_int_read_db_dump (guestfs_h *g, +- const char *dumpfile, void *opaque, +- guestfs_int_db_dump_callback callback) +-{ +- struct cb_data data; +- CLEANUP_CMD_CLOSE struct command *cmd = guestfs_int_new_command (g); +- int r; +- +- data.callback = callback; +- data.opaque = opaque; +- data.state = reading_header; +- data.key = NULL; +- +- guestfs_int_cmd_add_arg (cmd, DB_DUMP); +- guestfs_int_cmd_add_arg (cmd, "-k"); +- guestfs_int_cmd_add_arg (cmd, dumpfile); +- guestfs_int_cmd_set_stdout_callback (cmd, read_db_dump_line, &data, 0); +- +- r = guestfs_int_cmd_run (cmd); +- free (data.key); +- +- if (r == -1) +- return -1; +- if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) { +- guestfs_int_external_command_failed (g, r, DB_DUMP, NULL); +- return -1; +- } +- if (data.state != reading_finished) { +- error (g, _("%s: unexpected error or end of output"), DB_DUMP); +- return -1; +- } +- +- return 0; +-} +- +-static void +-read_db_dump_line (guestfs_h *g, void *datav, const char *line, size_t len) +-{ +- struct cb_data *data = datav; +- +- switch (data->state) { +- case reading_finished: +- case reading_failed: +- return; +- +- case reading_header: +- /* Ignore everything to end-of-header marker. */ +- if (STRPREFIX (line, "HEADER=END")) +- data->state = reading_key; +- return; +- +- /* Read the key, value pairs using a state machine. They are +- * prefixed with a space and printed as hex strings, so convert +- * those strings to binary. Pass the strings up to the callback +- * function. +- */ +- case reading_key: +- if (STRPREFIX (line, "DATA=END")) { +- data->state = reading_finished; +- return; +- } +- +- if (len < 1 || line[0] != ' ') { +- debug (g, _("unexpected line from db_dump command, no space prefix")); +- data->state = reading_failed; +- return; +- } +- +- data->key = convert_hex_to_binary (g, &line[1], len-1, &data->keylen); +- if (data->key == NULL) { +- data->state = reading_failed; +- return; +- } +- +- data->state = reading_value; +- return; +- +- case reading_value: { +- CLEANUP_FREE unsigned char *value = NULL; +- size_t valuelen; +- +- if (len < 1 || line[0] != ' ') { +- debug (g, _("unexpected line from db_dump command, no space prefix")); +- data->state = reading_failed; +- return; +- } +- +- value = convert_hex_to_binary (g, &line[1], len-1, &valuelen); +- if (value == NULL) { +- data->state = reading_failed; +- return; +- } +- +- if (data->callback (g, data->key, data->keylen, +- value, valuelen, data->opaque) == -1) { +- data->state = reading_failed; +- return; +- } +- +- free (data->key); +- data->key = NULL; +- +- data->state = reading_key; +- return; +- } +- } +-} +- +-static int +-convert_hex_octet (const char *h) +-{ +- int r; +- +- switch (h[0]) { +- case 'a'...'f': +- r = (h[0] - 'a' + 10) << 4; +- break; +- case 'A'...'F': +- r = (h[0] - 'A' + 10) << 4; +- break; +- case '0'...'9': +- r = (h[0] - '0') << 4; +- break; +- default: +- return -1; +- } +- +- switch (h[1]) { +- case 'a'...'f': +- r |= h[1] - 'a' + 10; +- break; +- case 'A'...'F': +- r |= h[1] - 'A' + 10; +- break; +- case '0'...'9': +- r |= h[1] - '0'; +- break; +- default: +- return -1; +- } +- +- return r; +-} +- +-static unsigned char * +-convert_hex_to_binary (guestfs_h *g, const char *hex, size_t hexlen, +- size_t *binlen_rtn) +-{ +- unsigned char *bin; +- size_t binlen; +- size_t i, o; +- int b; +- +- if (hexlen > 0 && hex[hexlen-1] == '\n') +- hexlen--; +- +- binlen = hexlen / 2; +- bin = safe_malloc (g, binlen); +- +- for (i = o = 0; i+1 < hexlen && o < binlen; i += 2, ++o) { +- b = convert_hex_octet (&hex[i]); +- if (b >= 0) +- bin[o] = b; +- else { +- error (g, _("unexpected non-hex digits in output of db_dump command")); +- free (bin); +- return NULL; +- } +- } +- +- *binlen_rtn = binlen; +- return bin; +-} +- +-#endif /* defined(DB_DUMP) */ +diff --git a/lib/guestfs-internal.h b/lib/guestfs-internal.h +index d7ec7215d..4799ee0a1 100644 +--- a/lib/guestfs-internal.h ++++ b/lib/guestfs-internal.h +@@ -719,10 +719,6 @@ extern int guestfs_int_set_backend (guestfs_h *g, const char *method); + /* inspect.c */ + extern char *guestfs_int_download_to_tmp (guestfs_h *g, const char *filename, const char *extension, uint64_t max_size); + +-/* dbdump.c */ +-typedef int (*guestfs_int_db_dump_callback) (guestfs_h *g, const unsigned char *key, size_t keylen, const unsigned char *value, size_t valuelen, void *opaque); +-extern int guestfs_int_read_db_dump (guestfs_h *g, const char *dumpfile, void *opaque, guestfs_int_db_dump_callback callback); +- + /* lpj.c */ + extern int guestfs_int_get_lpj (guestfs_h *g); + +diff --git a/lib/inspect-apps.c b/lib/inspect-apps.c +index dbc9d968c..da0003672 100644 +--- a/lib/inspect-apps.c ++++ b/lib/inspect-apps.c +@@ -47,22 +47,12 @@ + + /* Some limits on what the inspection code will read, for safety. */ + +-/* Maximum RPM 'Packages' file we will download to /tmp. This file +- * can get very large: 70 MB is roughly the standard size for a new +- * Fedora install, and after lots of package installation/removal +- * I have seen well over 400 MB databases. +- */ +-#define MAX_RPM_PACKAGES_SIZE (500 * 1000 * 1000) +-/* Maximum RPM 'Name' file we will download to /tmp. */ +-#define MAX_RPM_NAME_SIZE (50 * 1000 * 1000) + /* Maximum dpkg 'status' file we will download to /tmp. */ + #define MAX_DPKG_STATUS_SIZE (50 * 1000 * 1000) + /* Maximum APK 'installed' file we will download to /tmp. */ + #define MAX_APK_INSTALLED_SIZE (50 * 1000 * 1000) + +-#ifdef DB_DUMP + static struct guestfs_application2_list *list_applications_rpm (guestfs_h *g, const char *root); +-#endif + static struct guestfs_application2_list *list_applications_deb (guestfs_h *g, const char *root); + static struct guestfs_application2_list *list_applications_pacman (guestfs_h *g, const char *root); + static struct guestfs_application2_list *list_applications_apk (guestfs_h *g, const char *root); +@@ -136,11 +126,9 @@ guestfs_impl_inspect_list_applications2 (guestfs_h *g, const char *root) + + if (STREQ (type, "linux") || STREQ (type, "hurd")) { + if (STREQ (package_format, "rpm")) { +-#ifdef DB_DUMP + ret = list_applications_rpm (g, root); + if (ret == NULL) + return NULL; +-#endif + } + else if (STREQ (package_format, "deb")) { + ret = list_applications_deb (g, root); +@@ -178,254 +166,15 @@ guestfs_impl_inspect_list_applications2 (guestfs_h *g, const char *root) + return ret; + } + +-#ifdef DB_DUMP +- +-/* This data comes from the Name database, and contains the application +- * names and the first 4 bytes of each link field. +- */ +-struct rpm_names_list { +- struct rpm_name *names; +- size_t len; +-}; +-struct rpm_name { +- char *name; +- char link[4]; +-}; +- +-static void +-free_rpm_names_list (struct rpm_names_list *list) +-{ +- size_t i; +- +- for (i = 0; i < list->len; ++i) +- free (list->names[i].name); +- free (list->names); +-} +- +-static int +-compare_links (const void *av, const void *bv) +-{ +- const struct rpm_name *a = av; +- const struct rpm_name *b = bv; +- return memcmp (a->link, b->link, 4); +-} +- +-static int +-read_rpm_name (guestfs_h *g, +- const unsigned char *key, size_t keylen, +- const unsigned char *value, size_t valuelen, +- void *listv) +-{ +- struct rpm_names_list *list = listv; +- const unsigned char *link_p; +- char *name; +- +- /* Ignore bogus entries. */ +- if (keylen == 0 || valuelen < 4) +- return 0; +- +- /* A name entry will have as many links as installed instances of +- * that package. For example, if glibc.i686 and glibc.x86_64 are +- * both installed, then there will be a link for each Packages +- * entry. Add an entry onto list for all installed instances. +- */ +- for (link_p = value; link_p < value + valuelen; link_p += 8) { +- name = safe_strndup (g, (const char *) key, keylen); +- +- list->names = safe_realloc (g, list->names, +- (list->len + 1) * sizeof (struct rpm_name)); +- list->names[list->len].name = name; +- memcpy (list->names[list->len].link, link_p, 4); +- list->len++; +- } +- +- return 0; +-} +- +-#pragma GCC diagnostic push +-#pragma GCC diagnostic ignored "-Wcast-align" +- +-/* tag constants, see rpmtag.h in RPM for complete list */ +-#define RPMTAG_VERSION 1001 +-#define RPMTAG_RELEASE 1002 +-#define RPMTAG_EPOCH 1003 +-#define RPMTAG_ARCH 1022 +-#define RPMTAG_URL 1020 +-#define RPMTAG_SUMMARY 1004 +-#define RPMTAG_DESCRIPTION 1005 +- +-static char * +-get_rpm_header_tag (guestfs_h *g, const unsigned char *header_start, +- size_t header_len, uint32_t tag, char type) +-{ +- uint32_t num_fields, offset; +- const unsigned char *cursor = header_start + 8, *store, *header_end; +- size_t max_len; +- char iv[4]; +- +- /* This function parses the RPM header structure to pull out various +- * tag strings (version, release, arch, etc.). For more detail on the +- * header format, see: +- * http://www.rpm.org/max-rpm/s1-rpm-file-format-rpm-file-format.html#S2-RPM-FILE-FORMAT-HEADER +- */ +- +- /* The minimum header size that makes sense here is 24 bytes. Four +- * bytes for number of fields, followed by four bytes denoting the +- * size of the store, then 16 bytes for the first index entry. +- */ +- if (header_len < 24) +- return NULL; +- +- num_fields = be32toh (*(uint32_t *) header_start); +- store = header_start + 8 + (16 * num_fields); +- +- /* The first byte *after* the buffer. If you are here, you've gone +- * too far! */ +- header_end = header_start + header_len; +- +- while (cursor < store && cursor <= header_end - 16) { +- if (be32toh (*(uint32_t *) cursor) == tag) { +- offset = be32toh(*(uint32_t *) (cursor + 8)); +- +- if (store + offset >= header_end) +- return NULL; +- max_len = header_end - (store + offset); +- +- switch (type) { +- case 's': +- return safe_strndup (g, (const char *) (store + offset), max_len); +- +- case 'i': +- memset (iv, 0, sizeof iv); +- memcpy (iv, (void *) (store + offset), +- max_len > sizeof iv ? sizeof iv : max_len); +- return safe_memdup (g, iv, sizeof iv); +- +- default: +- abort (); +- } +- } +- cursor += 16; +- } +- +- return NULL; +-} +- +-struct read_package_data { +- struct rpm_names_list *list; +- struct guestfs_application2_list *apps; +-}; +- +-static int +-read_package (guestfs_h *g, +- const unsigned char *key, size_t keylen, +- const unsigned char *value, size_t valuelen, +- void *datav) +-{ +- struct read_package_data *data = datav; +- struct rpm_name nkey, *entry; +- CLEANUP_FREE char *version = NULL, *release = NULL, +- *epoch_str = NULL, *arch = NULL, *url = NULL, *summary = NULL, +- *description = NULL; +- int32_t epoch; +- +- /* This function reads one (key, value) pair from the Packages +- * database. The key is the link field (see struct rpm_name). The +- * value is a long binary string, but we can extract the header data +- * from it as below. First we have to look up the link field in the +- * list of links (which is sorted by link field). +- */ +- +- /* Ignore bogus entries. */ +- if (keylen < 4 || valuelen == 0) +- return 0; +- +- /* Look up the link (key) in the list. */ +- memcpy (nkey.link, key, 4); +- entry = bsearch (&nkey, data->list->names, data->list->len, +- sizeof (struct rpm_name), compare_links); +- if (!entry) +- return 0; /* Not found - ignore it. */ +- +- /* We found a matching link entry, so that gives us the application +- * name (entry->name). Now we can get other data for this +- * application out of the binary value string. +- */ +- +- version = get_rpm_header_tag (g, value, valuelen, RPMTAG_VERSION, 's'); +- release = get_rpm_header_tag (g, value, valuelen, RPMTAG_RELEASE, 's'); +- epoch_str = get_rpm_header_tag (g, value, valuelen, RPMTAG_EPOCH, 'i'); +- arch = get_rpm_header_tag (g, value, valuelen, RPMTAG_ARCH, 's'); +- url = get_rpm_header_tag (g, value, valuelen, RPMTAG_URL, 's'); +- summary = get_rpm_header_tag (g, value, valuelen, RPMTAG_SUMMARY, 's'); +- description = get_rpm_header_tag (g, value, valuelen, RPMTAG_DESCRIPTION, 's'); +- +- /* The epoch is stored as big-endian integer. */ +- if (epoch_str) +- epoch = be32toh (*(int32_t *) epoch_str); +- else +- epoch = 0; +- +- /* Add the application and what we know. */ +- if (version && release) +- add_application (g, data->apps, entry->name, "", epoch, version, release, +- arch ? arch : "", "", "", url ? : "", "", +- summary ? : "", description ? : ""); +- +- return 0; +-} +- +-#pragma GCC diagnostic pop +- + static struct guestfs_application2_list * + list_applications_rpm (guestfs_h *g, const char *root) + { +- CLEANUP_FREE char *Name = NULL, *Packages = NULL; +- struct rpm_names_list list = { .names = NULL, .len = 0 }; +- struct guestfs_application2_list *apps = NULL; +- struct read_package_data data; +- +- Name = guestfs_int_download_to_tmp (g, "/var/lib/rpm/Name", NULL, +- MAX_RPM_NAME_SIZE); +- if (Name == NULL) +- goto error; +- +- Packages = guestfs_int_download_to_tmp (g, "/var/lib/rpm/Packages", NULL, +- MAX_RPM_PACKAGES_SIZE); +- if (Packages == NULL) +- goto error; +- +- /* Read Name database. */ +- if (guestfs_int_read_db_dump (g, Name, &list, read_rpm_name) == -1) +- goto error; +- +- /* Sort the names by link field for fast searching. */ +- qsort (list.names, list.len, sizeof (struct rpm_name), compare_links); +- +- /* Allocate 'apps' list. */ +- apps = safe_malloc (g, sizeof *apps); +- apps->len = 0; +- apps->val = NULL; +- +- /* Read Packages database. */ +- data.list = &list; +- data.apps = apps; +- if (guestfs_int_read_db_dump (g, Packages, &data, read_package) == -1) +- goto error; +- +- free_rpm_names_list (&list); +- +- return apps; +- +- error: +- free_rpm_names_list (&list); +- guestfs_free_application2_list (apps); +- +- return NULL; ++ /* We don't need the ‘root’ parameter here. The caller is supposed ++ * to have mounted the guest up before calling the public API. ++ */ ++ return guestfs_internal_list_rpm_applications (g); + } + +-#endif /* defined DB_DUMP */ +- + static struct guestfs_application2_list * + list_applications_deb (guestfs_h *g, const char *root) + { +diff --git a/m4/guestfs-daemon.m4 b/m4/guestfs-daemon.m4 +index aa90268b4..1728249a5 100644 +--- a/m4/guestfs-daemon.m4 ++++ b/m4/guestfs-daemon.m4 +@@ -102,6 +102,14 @@ PKG_CHECK_MODULES([HIVEX], [hivex],[ + [AC_MSG_FAILURE([hivex library is required])]) + AM_CONDITIONAL([HAVE_HIVEX],[test "x$HIVEX_LIBS" != "x"]) + ++dnl librpm library (optional) ++PKG_CHECK_MODULES([LIBRPM], [rpm >= 4.6.0],[ ++ AC_SUBST([LIBRPM_CFLAGS]) ++ AC_SUBST([LIBRPM_LIBS]) ++ AC_DEFINE([HAVE_LIBRPM],[1],[librpm library found at compile time.]) ++],[AC_MSG_WARN([librpm library not found])] ++) ++ + dnl systemd journal library (optional) + PKG_CHECK_MODULES([SD_JOURNAL], [libsystemd],[ + AC_SUBST([SD_JOURNAL_CFLAGS]) +diff --git a/m4/guestfs-progs.m4 b/m4/guestfs-progs.m4 +index bf1f83c9d..f90bda04e 100644 +--- a/m4/guestfs-progs.m4 ++++ b/m4/guestfs-progs.m4 +@@ -63,16 +63,6 @@ AC_CHECK_PROG([PO4A_GETTEXTIZE],[po4a-gettextize],[po4a-gettextize],[no]) + AC_CHECK_PROG([PO4A_TRANSLATE],[po4a-translate],[po4a-translate],[no]) + AM_CONDITIONAL([HAVE_PO4A], [test "x$PO4A_GETTEXTIZE" != "xno" && test "x$PO4A_TRANSLATE" != "xno"]) + +-dnl Check for db_dump, db_load (optional). +-GUESTFS_FIND_DB_TOOL([DB_DUMP], [dump]) +-GUESTFS_FIND_DB_TOOL([DB_LOAD], [load]) +-if test "x$DB_DUMP" != "xno"; then +- AC_DEFINE_UNQUOTED([DB_DUMP],["$DB_DUMP"],[Name of db_dump program.]) +-fi +-if test "x$DB_LOAD" != "xno"; then +- AC_DEFINE_UNQUOTED([DB_LOAD],["$DB_LOAD"],[Name of db_load program.]) +-fi +- + dnl Check for netpbm programs (optional). + AC_PATH_PROGS([PBMTEXT],[pbmtext],[no]) + AC_PATH_PROGS([PNMTOPNG],[pnmtopng],[no]) +-- +2.31.1 + diff --git a/SOURCES/0011-v2v-add-Var_expander.patch b/SOURCES/0011-v2v-add-Var_expander.patch deleted file mode 100644 index e9f77a5..0000000 --- a/SOURCES/0011-v2v-add-Var_expander.patch +++ /dev/null @@ -1,415 +0,0 @@ -From 8b7c559f6c619bab8a708358db15b2959623c833 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Tue, 19 Feb 2019 14:54:31 +0100 -Subject: [PATCH] v2v: add Var_expander - -This helper module provides a facility to replace %{FOO}-like variables -in text strings with user-provided content. - -(cherry picked from commit a27748d7000f417c16045967497208d275a09ce8) ---- - .gitignore | 1 + - v2v/Makefile.am | 32 ++++++++++- - v2v/dummy.c | 2 + - v2v/var_expander.ml | 72 ++++++++++++++++++++++++ - v2v/var_expander.mli | 82 +++++++++++++++++++++++++++ - v2v/var_expander_tests.ml | 113 ++++++++++++++++++++++++++++++++++++++ - 6 files changed, 300 insertions(+), 2 deletions(-) - create mode 100644 v2v/dummy.c - create mode 100644 v2v/var_expander.ml - create mode 100644 v2v/var_expander.mli - create mode 100644 v2v/var_expander_tests.ml - -diff --git a/.gitignore b/.gitignore -index 637bf7765..f2efcdde2 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -693,6 +693,7 @@ Makefile.in - /v2v/uefi.ml - /v2v/uefi.mli - /v2v/v2v_unit_tests -+/v2v/var_expander_tests - /v2v/virt-v2v - /v2v/virt-v2v.1 - /v2v/virt-v2v-copy-to-local -diff --git a/v2v/Makefile.am b/v2v/Makefile.am -index 2312812fb..f196be81d 100644 ---- a/v2v/Makefile.am -+++ b/v2v/Makefile.am -@@ -98,6 +98,7 @@ SOURCES_MLI = \ - utils.mli \ - v2v.mli \ - vCenter.mli \ -+ var_expander.mli \ - windows.mli \ - windows_virtio.mli - -@@ -106,6 +107,7 @@ SOURCES_ML = \ - types.ml \ - uefi.ml \ - utils.ml \ -+ var_expander.ml \ - python_script.ml \ - name_from_disk.ml \ - vCenter.ml \ -@@ -442,7 +444,7 @@ TESTS += \ - endif - - if HAVE_OCAML_PKG_OUNIT --TESTS += v2v_unit_tests -+TESTS += v2v_unit_tests var_expander_tests - endif - - if ENABLE_APPLIANCE -@@ -651,7 +653,7 @@ EXTRA_DIST += \ - # Unit tests. - check_PROGRAMS = - if HAVE_OCAML_PKG_OUNIT --check_PROGRAMS += v2v_unit_tests -+check_PROGRAMS += v2v_unit_tests var_expander_tests - endif - - v2v_unit_tests_BOBJECTS = \ -@@ -671,13 +673,28 @@ v2v_unit_tests_SOURCES = $(virt_v2v_SOURCES) - v2v_unit_tests_CPPFLAGS = $(virt_v2v_CPPFLAGS) - v2v_unit_tests_CFLAGS = $(virt_v2v_CFLAGS) - -+var_expander_tests_BOBJECTS = \ -+ var_expander.cmo \ -+ var_expander_tests.cmo -+var_expander_tests_XOBJECTS = $(var_expander_tests_BOBJECTS:.cmo=.cmx) -+ -+var_expander_tests_SOURCES = dummy.c -+var_expander_tests_CPPFLAGS = $(virt_v2v_CPPFLAGS) -+var_expander_tests_CFLAGS = $(virt_v2v_CFLAGS) -+ - if !HAVE_OCAMLOPT - # Can't call this v2v_unit_tests_OBJECTS because automake gets confused. - v2v_unit_tests_THEOBJECTS = $(v2v_unit_tests_BOBJECTS) - v2v_unit_tests.cmo: OCAMLPACKAGES += -package oUnit -+ -+var_expander_tests_THEOBJECTS = $(var_expander_tests_BOBJECTS) -+var_expander_tests.cmo: OCAMLPACKAGES += -package oUnit - else - v2v_unit_tests_THEOBJECTS = $(v2v_unit_tests_XOBJECTS) - v2v_unit_tests.cmx: OCAMLPACKAGES += -package oUnit -+ -+var_expander_tests_THEOBJECTS = $(var_expander_tests_XOBJECTS) -+var_expander_tests.cmx: OCAMLPACKAGES += -package oUnit - endif - - v2v_unit_tests_DEPENDENCIES = \ -@@ -696,6 +713,17 @@ v2v_unit_tests_LINK = \ - $(OCAMLLINKFLAGS) \ - $(v2v_unit_tests_THEOBJECTS) -o $@ - -+var_expander_tests_DEPENDENCIES = \ -+ $(var_expander_tests_THEOBJECTS) \ -+ ../common/mlpcre/mlpcre.$(MLARCHIVE) \ -+ $(top_srcdir)/ocaml-link.sh -+var_expander_tests_LINK = \ -+ $(top_srcdir)/ocaml-link.sh -cclib '$(OCAMLCLIBS)' -- \ -+ $(OCAMLFIND) $(BEST) $(OCAMLFLAGS) \ -+ $(OCAMLPACKAGES) -package oUnit \ -+ $(OCAMLLINKFLAGS) \ -+ $(var_expander_tests_THEOBJECTS) -o $@ -+ - # Dependencies. - .depend: \ - $(srcdir)/*.mli \ -diff --git a/v2v/dummy.c b/v2v/dummy.c -new file mode 100644 -index 000000000..ebab6198c ---- /dev/null -+++ b/v2v/dummy.c -@@ -0,0 +1,2 @@ -+/* Dummy source, to be used for OCaml-based tools with no C sources. */ -+enum { foo = 1 }; -diff --git a/v2v/var_expander.ml b/v2v/var_expander.ml -new file mode 100644 -index 000000000..24b9bafe3 ---- /dev/null -+++ b/v2v/var_expander.ml -@@ -0,0 +1,72 @@ -+(* virt-v2v -+ * Copyright (C) 2019 Red Hat Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ *) -+ -+open Std_utils -+ -+exception Invalid_variable of string -+ -+let var_re = PCRE.compile "(^|[^%])%{([^}]+)}" -+ -+let check_variable var = -+ String.iter ( -+ function -+ | '0'..'9' -+ | 'a'..'z' -+ | 'A'..'Z' -+ | '_' -+ | '-' -> () -+ | _ -> raise (Invalid_variable var) -+ ) var -+ -+let scan_variables str = -+ let res = ref [] in -+ let offset = ref 0 in -+ while PCRE.matches ~offset:!offset var_re str; do -+ let var = PCRE.sub 2 in -+ check_variable var; -+ let _, end_ = PCRE.subi 0 in -+ List.push_back res var; -+ offset := end_ -+ done; -+ List.remove_duplicates !res -+ -+let replace_fn str fn = -+ let res = ref str in -+ let offset = ref 0 in -+ while PCRE.matches ~offset:!offset var_re !res; do -+ let var = PCRE.sub 2 in -+ check_variable var; -+ let start_, end_ = PCRE.subi 0 in -+ match fn var with -+ | None -> -+ offset := end_ -+ | Some text -> -+ let prefix_len = -+ let prefix_start, prefix_end = PCRE.subi 1 in -+ prefix_end - prefix_start in -+ res := (String.sub !res 0 (start_ + prefix_len)) ^ text ^ (String.sub !res end_ (String.length !res - end_)); -+ offset := start_ + prefix_len + String.length text -+ done; -+ !res -+ -+let replace_list str lst = -+ let fn var = -+ try Some (List.assoc var lst) -+ with Not_found -> None -+ in -+ replace_fn str fn -diff --git a/v2v/var_expander.mli b/v2v/var_expander.mli -new file mode 100644 -index 000000000..80aa33c2c ---- /dev/null -+++ b/v2v/var_expander.mli -@@ -0,0 +1,82 @@ -+(* virt-v2v -+ * Copyright (C) 2019 Red Hat Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ *) -+ -+(** Simple variable expander. -+ -+ This module provides the support to expand variables in strings, -+ specified in the form of [%{name}]. -+ -+ For example: -+ -+{v -+let str = "variable-%{INDEX} in %{INDEX} replaced %{INDEX} times" -+let index = ref 0 -+let fn = function -+ | "INDEX" -> -+ incr index; -+ Some (string_of_int !index) -+ | _ -> None -+in -+let str = Var_expander.replace_fn str fn -+(* now str is "variable-1 in 2 replaced 3 times" *) -+v} -+ -+ The names of variables can contain only ASCII letters (uppercase, -+ and lowercase), digits, underscores, and dashes. -+ -+ The replacement is done in a single pass: this means that if a -+ variable is replaced with the text of a variable, that new text -+ is kept as is in the final output. In practice: -+ -+{v -+let str = "%{VAR}" -+let str = Var_expander.replace_list str [("VAR", "%{VAR}")] -+(* now str is "%{VAR}" *) -+v} -+*) -+ -+exception Invalid_variable of string -+(** Invalid variable name error. -+ -+ In case a variable contains characters not allowed, then this -+ exception with the actual unacceptable variable. *) -+ -+val scan_variables : string -> string list -+(** Scan the pattern string for all the variables available. -+ -+ This can raise {!Invalid_variable} in case there are invalid -+ variable names. *) -+ -+val replace_fn : string -> (string -> string option) -> string -+(** Replaces a string expanding all the variables. -+ -+ The replacement function specify how a variable is replaced; -+ if [None] is returned, then that variable is not replaced. -+ -+ This can raise {!Invalid_variable} in case there are invalid -+ variable names. *) -+ -+val replace_list : string -> (string * string) list -> string -+(** Replaces a string expanding all the variables. -+ -+ The replacement list specify how a variable is replaced; -+ if it is not specified in the list, then that variable is not -+ replaced. -+ -+ This can raise {!Invalid_variable} in case there are invalid -+ variable names. *) -diff --git a/v2v/var_expander_tests.ml b/v2v/var_expander_tests.ml -new file mode 100644 -index 000000000..35b628369 ---- /dev/null -+++ b/v2v/var_expander_tests.ml -@@ -0,0 +1,113 @@ -+(* virt-v2v -+ * Copyright (C) 2019 Red Hat Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ *) -+ -+open Printf -+open OUnit -+ -+open Std_utils -+ -+let assert_equal_string = assert_equal ~printer:identity -+let assert_equal_stringlist = assert_equal ~printer:(fun x -> "(" ^ (String.escaped (String.concat "," x)) ^ ")") -+ -+let replace_none_fn _ = None -+let replace_empty_fn _ = Some "" -+ -+let test_no_replacement () = -+ assert_equal_string "" (Var_expander.replace_fn "" replace_none_fn); -+ assert_equal_string "x" (Var_expander.replace_fn "x" replace_none_fn); -+ assert_equal_string "%{}" (Var_expander.replace_fn "%{}" replace_none_fn); -+ assert_equal_string "%{EMPTY}" (Var_expander.replace_fn "%{EMPTY}" replace_none_fn); -+ assert_equal_string "%{EMPTY} %{no}" (Var_expander.replace_fn "%{EMPTY} %{no}" replace_none_fn); -+ assert_equal_string "a %{EMPTY} b" (Var_expander.replace_fn "a %{EMPTY} b" replace_none_fn); -+ () -+ -+let test_replacements () = -+ assert_equal_string "" (Var_expander.replace_fn "%{EMPTY}" replace_empty_fn); -+ assert_equal_string "x " (Var_expander.replace_fn "x %{EMPTY}" replace_empty_fn); -+ assert_equal_string "xy" (Var_expander.replace_fn "x%{EMPTY}y" replace_empty_fn); -+ assert_equal_string "x<->y" (Var_expander.replace_fn "x%{FOO}y" (function | "FOO" -> Some "<->" | _ -> None)); -+ assert_equal_string "a x b" (Var_expander.replace_fn "a %{FOO} b" (function | "FOO" -> Some "x" | _ -> None)); -+ assert_equal_string "%{FOO} x" (Var_expander.replace_fn "%{FOO} %{BAR}" (function | "BAR" -> Some "x" | _ -> None)); -+ assert_equal_string "%{FOO}" (Var_expander.replace_fn "%{BAR}" (function | "BAR" -> Some "%{FOO}" | _ -> None)); -+ assert_equal_string "%{FOO} x" (Var_expander.replace_fn "%{BAR} %{FOO}" (function | "BAR" -> Some "%{FOO}" | "FOO" -> Some "x" | _ -> None)); -+ begin -+ let str = "%{INDEX}, %{INDEX}, %{INDEX}" in -+ let index = ref 0 in -+ let fn = function -+ | "INDEX" -> -+ incr index; -+ Some (string_of_int !index) -+ | _ -> None -+ in -+ assert_equal_string "1, 2, 3" (Var_expander.replace_fn str fn) -+ end; -+ () -+ -+let test_escape () = -+ assert_equal_string "%%{FOO}" (Var_expander.replace_fn "%%{FOO}" replace_empty_fn); -+ assert_equal_string "x %%{FOO} x" (Var_expander.replace_fn "%{FOO} %%{FOO} %{FOO}" (function | "FOO" -> Some "x" | _ -> None)); -+ () -+ -+let test_list () = -+ assert_equal_string "x %{NONE}" (Var_expander.replace_list "%{FOO} %{NONE}" [("FOO", "x")]); -+ () -+ -+let test_scan_variables () = -+ let assert_invalid_variable var = -+ let str = "%{" ^ var ^ "}" in -+ assert_raises (Var_expander.Invalid_variable var) -+ (fun () -> Var_expander.scan_variables str) -+ in -+ assert_equal_stringlist [] (Var_expander.scan_variables ""); -+ assert_equal_stringlist [] (Var_expander.scan_variables "foo"); -+ assert_equal_stringlist ["FOO"] (Var_expander.scan_variables "%{FOO}"); -+ assert_equal_stringlist ["FOO"; "BAR"] (Var_expander.scan_variables "%{FOO} %{BAR}"); -+ assert_equal_stringlist ["FOO"; "BAR"] (Var_expander.scan_variables "%{FOO} %{BAR} %{FOO}"); -+ assert_equal_stringlist ["FOO"; "BAR"] (Var_expander.scan_variables "%{FOO} %%{ESCAPED} %{BAR}"); -+ assert_invalid_variable "FOO/BAR"; -+ () -+ -+let test_errors () = -+ let assert_invalid_variable var = -+ let str = "%{" ^ var ^ "}" in -+ assert_raises (Var_expander.Invalid_variable var) -+ (fun () -> Var_expander.replace_fn str replace_none_fn) -+ in -+ assert_invalid_variable "FOO/BAR"; -+ assert_invalid_variable "FOO:BAR"; -+ assert_invalid_variable "FOO(BAR"; -+ assert_invalid_variable "FOO)BAR"; -+ assert_invalid_variable "FOO@BAR"; -+ () -+ -+(* Suites declaration. *) -+let suite = -+ TestList ([ -+ "basic" >::: [ -+ "no_replacement" >:: test_no_replacement; -+ "replacements" >:: test_replacements; -+ "escape" >:: test_escape; -+ "list" >:: test_list; -+ "scan_variables" >:: test_scan_variables; -+ "errors" >:: test_errors; -+ ]; -+ ]) -+ -+let () = -+ ignore (run_test_tt_main suite); -+ Printf.fprintf stderr "\n" --- -2.18.4 - diff --git a/SOURCES/0012-inspection-Return-RPM-epoch.patch b/SOURCES/0012-inspection-Return-RPM-epoch.patch new file mode 100644 index 0000000..9e50561 --- /dev/null +++ b/SOURCES/0012-inspection-Return-RPM-epoch.patch @@ -0,0 +1,36 @@ +From 3ce392c9870a589cc50d2270fcf07b4d129c3dc3 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 27 Mar 2021 09:31:00 +0000 +Subject: [PATCH] inspection: Return RPM epoch. + +Fixes: commit c9ee831affed55abe0f928134cbbd2ed83b2f510 +(cherry picked from commit fef73bce7eec0ce0753a2e150e4e088020d38643) +--- + daemon/rpm-c.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/daemon/rpm-c.c b/daemon/rpm-c.c +index 92a3abf58..be0e81e22 100644 +--- a/daemon/rpm-c.c ++++ b/daemon/rpm-c.c +@@ -108,13 +108,16 @@ guestfs_int_daemon_rpm_next_application (value unitv) + + h = headerLink (h); + app.app2_name = headerFormat (h, "%{NAME}", NULL); +- // XXXapp.app2_epoch = headerFormat (h, "%{NAME}", NULL); + app.app2_version = headerFormat (h, "%{VERSION}", NULL); + app.app2_release = headerFormat (h, "%{RELEASE}", NULL); + app.app2_arch = headerFormat (h, "%{ARCH}", NULL); + app.app2_url = headerFormat (h, "%{URL}", NULL); + app.app2_summary = headerFormat (h, "%{SUMMARY}", NULL); + app.app2_description = headerFormat (h, "%{DESCRIPTION}", NULL); ++ ++ /* epoch is special as the only int field. */ ++ app.app2_epoch = headerGetNumber (h, RPMTAG_EPOCH); ++ + headerFree (h); + + /* Convert this to an OCaml struct. Any NULL fields must be turned +-- +2.31.1 + diff --git a/SOURCES/0012-v2v-add-o-json-output-mode.patch b/SOURCES/0012-v2v-add-o-json-output-mode.patch deleted file mode 100644 index 0b11b25..0000000 --- a/SOURCES/0012-v2v-add-o-json-output-mode.patch +++ /dev/null @@ -1,785 +0,0 @@ -From 87df9bcb99bdb60d5cedf52e155361826e700816 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Mon, 25 Feb 2019 13:14:43 +0100 -Subject: [PATCH] v2v: add -o json output mode - -Add a new output mode to virt-v2v: similar to -o local, the written -metadata is a JSON file with the majority of the data that virt-v2v -knowns about (or collects) during the conversion. - -This is meant to be used only when no existing output mode is usable, -and a guest needs to be converted to run on KVM anyway. The user of -this mode is supposed to use all the data in the JSON, as they contain -important details on how even run the guest (e.g. w.r.t. firmware, -drivers of disks/NICs, etc). - -(cherry picked from commit f190e08d85556dac293ef15bfeee38e54471570f) ---- - v2v/Makefile.am | 4 + - v2v/cmdline.ml | 29 +++ - v2v/create_json.ml | 348 ++++++++++++++++++++++++++++++++++ - v2v/create_json.mli | 29 +++ - v2v/output_json.ml | 116 ++++++++++++ - v2v/output_json.mli | 31 +++ - v2v/virt-v2v-output-local.pod | 55 ++++++ - v2v/virt-v2v.pod | 15 +- - 8 files changed, 625 insertions(+), 2 deletions(-) - create mode 100644 v2v/create_json.ml - create mode 100644 v2v/create_json.mli - create mode 100644 v2v/output_json.ml - create mode 100644 v2v/output_json.mli - -diff --git a/v2v/Makefile.am b/v2v/Makefile.am -index f196be81d..53c137fc6 100644 ---- a/v2v/Makefile.am -+++ b/v2v/Makefile.am -@@ -52,6 +52,7 @@ SOURCES_MLI = \ - config.mli \ - convert_linux.mli \ - convert_windows.mli \ -+ create_json.mli \ - create_libvirt_xml.mli \ - create_ovf.mli \ - DOM.mli \ -@@ -75,6 +76,7 @@ SOURCES_MLI = \ - networks.mli \ - openstack_image_properties.mli \ - output_glance.mli \ -+ output_json.mli \ - output_libvirt.mli \ - output_local.mli \ - output_null.mli \ -@@ -117,6 +119,7 @@ SOURCES_ML = \ - parse_ovf_from_ova.ml \ - parse_ova.ml \ - create_ovf.ml \ -+ create_json.ml \ - linux.ml \ - windows.ml \ - windows_virtio.ml \ -@@ -141,6 +144,7 @@ SOURCES_ML = \ - convert_windows.ml \ - output_null.ml \ - output_glance.ml \ -+ output_json.ml \ - output_libvirt.ml \ - output_local.ml \ - output_qemu.ml \ -diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml -index 46f6910d0..4d390f249 100644 ---- a/v2v/cmdline.ml -+++ b/v2v/cmdline.ml -@@ -138,6 +138,7 @@ let parse_cmdline () = - | "glance" -> output_mode := `Glance - | "libvirt" -> output_mode := `Libvirt - | "disk" | "local" -> output_mode := `Local -+ | "json" -> output_mode := `JSON - | "null" -> output_mode := `Null - | "openstack" | "osp" | "rhosp" -> output_mode := `Openstack - | "ovirt" | "rhv" | "rhev" -> output_mode := `RHV -@@ -413,6 +414,17 @@ read the man page virt-v2v(1). - | `RHV -> no_options (); `RHV - | `QEmu -> no_options (); `QEmu - -+ | `JSON -> -+ if is_query then ( -+ Output_json.print_output_options (); -+ exit 0 -+ ) -+ else ( -+ let json_options = -+ Output_json.parse_output_options output_options in -+ `JSON json_options -+ ) -+ - | `Openstack -> - if is_query then ( - Output_openstack.print_output_options (); -@@ -546,6 +558,23 @@ read the man page virt-v2v(1). - Output_libvirt.output_libvirt output_conn output_storage, - output_format, output_alloc - -+ | `JSON json_options -> -+ if output_password <> None then -+ error_option_cannot_be_used_in_output_mode "json" "-op"; -+ if output_conn <> None then -+ error_option_cannot_be_used_in_output_mode "json" "-oc"; -+ let os = -+ match output_storage with -+ | None -> -+ error (f_"-o json: output directory was not specified, use '-os /dir'") -+ | Some d when not (is_directory d) -> -+ error (f_"-os %s: output directory does not exist or is not a directory") d -+ | Some d -> d in -+ if qemu_boot then -+ error_option_cannot_be_used_in_output_mode "json" "--qemu-boot"; -+ Output_json.output_json os json_options, -+ output_format, output_alloc -+ - | `Local -> - if output_password <> None then - error_option_cannot_be_used_in_output_mode "local" "-op"; -diff --git a/v2v/create_json.ml b/v2v/create_json.ml -new file mode 100644 -index 000000000..fdf7b12f5 ---- /dev/null -+++ b/v2v/create_json.ml -@@ -0,0 +1,348 @@ -+(* virt-v2v -+ * Copyright (C) 2019 Red Hat Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ *) -+ -+open Std_utils -+open C_utils -+open Tools_utils -+ -+open Types -+open Utils -+ -+module G = Guestfs -+ -+let json_list_of_string_list = -+ List.map (fun x -> JSON.String x) -+ -+let json_list_of_string_string_list = -+ List.map (fun (x, y) -> x, JSON.String y) -+ -+let push_optional_string lst name = function -+ | None -> () -+ | Some v -> List.push_back lst (name, JSON.String v) -+ -+let push_optional_int lst name = function -+ | None -> () -+ | Some v -> List.push_back lst (name, JSON.Int (Int64.of_int v)) -+ -+let json_unknown_string = function -+ | "unknown" -> JSON.Null -+ | v -> JSON.String v -+ -+let find_target_disk targets { s_disk_id = id } = -+ try List.find (fun t -> t.target_overlay.ov_source.s_disk_id = id) targets -+ with Not_found -> assert false -+ -+let create_json_metadata source targets target_buses -+ guestcaps inspect target_firmware = -+ let doc = ref [ -+ "version", JSON.Int 1L; -+ "name", JSON.String source.s_name; -+ "memory", JSON.Int source.s_memory; -+ "vcpu", JSON.Int (Int64.of_int source.s_vcpu); -+ ] in -+ -+ (match source.s_genid with -+ | None -> () -+ | Some genid -> List.push_back doc ("genid", JSON.String genid) -+ ); -+ -+ if source.s_cpu_vendor <> None || source.s_cpu_model <> None || -+ source.s_cpu_topology <> None then ( -+ let cpu = ref [] in -+ -+ push_optional_string cpu "vendor" source.s_cpu_vendor; -+ push_optional_string cpu "model" source.s_cpu_model; -+ (match source.s_cpu_topology with -+ | None -> () -+ | Some { s_cpu_sockets; s_cpu_cores; s_cpu_threads } -> -+ let attrs = [ -+ "sockets", JSON.Int (Int64.of_int s_cpu_sockets); -+ "cores", JSON.Int (Int64.of_int s_cpu_cores); -+ "threads", JSON.Int (Int64.of_int s_cpu_threads); -+ ] in -+ List.push_back cpu ("topology", JSON.Dict attrs) -+ ); -+ -+ List.push_back doc ("cpu", JSON.Dict !cpu); -+ ); -+ -+ let firmware = -+ let firmware_type = -+ match target_firmware with -+ | TargetBIOS -> "bios" -+ | TargetUEFI -> "uefi" in -+ -+ let fw = ref [ -+ "type", JSON.String firmware_type; -+ ] in -+ -+ (match target_firmware with -+ | TargetBIOS -> () -+ | TargetUEFI -> -+ let uefi_firmware = find_uefi_firmware guestcaps.gcaps_arch in -+ let flags = -+ List.map ( -+ function -+ | Uefi.UEFI_FLAG_SECURE_BOOT_REQUIRED -> "secure_boot_required" -+ ) uefi_firmware.Uefi.flags in -+ -+ let uefi = ref [ -+ "code", JSON.String uefi_firmware.Uefi.code; -+ "vars", JSON.String uefi_firmware.Uefi.vars; -+ "flags", JSON.List (json_list_of_string_list flags); -+ ] in -+ -+ push_optional_string uefi "code-debug" uefi_firmware.Uefi.code_debug; -+ -+ List.push_back fw ("uefi", JSON.Dict !uefi) -+ ); -+ -+ !fw in -+ List.push_back doc ("firmware", JSON.Dict firmware); -+ -+ List.push_back doc ("features", -+ JSON.List (json_list_of_string_list source.s_features)); -+ -+ let machine = -+ match guestcaps.gcaps_machine with -+ | I440FX -> "pc" -+ | Q35 -> "q35" -+ | Virt -> "virt" in -+ List.push_back doc ("machine", JSON.String machine); -+ -+ let disks, removables = -+ let disks = ref [] -+ and removables = ref [] in -+ -+ let iter_bus bus_name drive_prefix i = function -+ | BusSlotEmpty -> () -+ | BusSlotDisk d -> -+ (* Find the corresponding target disk. *) -+ let t = find_target_disk targets d in -+ -+ let target_file = -+ match t.target_file with -+ | TargetFile s -> s -+ | TargetURI _ -> assert false in -+ -+ let disk = [ -+ "dev", JSON.String (drive_prefix ^ drive_name i); -+ "bus", JSON.String bus_name; -+ "format", JSON.String t.target_format; -+ "file", JSON.String (absolute_path target_file); -+ ] in -+ -+ List.push_back disks (JSON.Dict disk) -+ -+ | BusSlotRemovable { s_removable_type = CDROM } -> -+ let cdrom = [ -+ "type", JSON.String "cdrom"; -+ "dev", JSON.String (drive_prefix ^ drive_name i); -+ "bus", JSON.String bus_name; -+ ] in -+ -+ List.push_back removables (JSON.Dict cdrom) -+ -+ | BusSlotRemovable { s_removable_type = Floppy } -> -+ let floppy = [ -+ "type", JSON.String "floppy"; -+ "dev", JSON.String (drive_prefix ^ drive_name i); -+ ] in -+ -+ List.push_back removables (JSON.Dict floppy) -+ in -+ -+ Array.iteri (iter_bus "virtio" "vd") target_buses.target_virtio_blk_bus; -+ Array.iteri (iter_bus "ide" "hd") target_buses.target_ide_bus; -+ Array.iteri (iter_bus "scsi" "sd") target_buses.target_scsi_bus; -+ Array.iteri (iter_bus "floppy" "fd") target_buses.target_floppy_bus; -+ -+ !disks, !removables in -+ List.push_back doc ("disks", JSON.List disks); -+ List.push_back doc ("removables", JSON.List removables); -+ -+ let nics = -+ List.map ( -+ fun { s_mac = mac; s_vnet_type = vnet_type; s_nic_model = nic_model; -+ s_vnet = vnet; } -> -+ let vnet_type_str = -+ match vnet_type with -+ | Bridge -> "bridge" -+ | Network -> "network" in -+ -+ let nic = ref [ -+ "vnet", JSON.String vnet; -+ "vnet-type", JSON.String vnet_type_str; -+ ] in -+ -+ let nic_model_str = Option.map string_of_nic_model nic_model in -+ push_optional_string nic "model" nic_model_str; -+ -+ push_optional_string nic "mac" mac; -+ -+ JSON.Dict !nic -+ ) source.s_nics in -+ List.push_back doc ("nics", JSON.List nics); -+ -+ let guestcaps_dict = -+ let block_bus = -+ match guestcaps.gcaps_block_bus with -+ | Virtio_blk -> "virtio-blk" -+ | Virtio_SCSI -> "virtio-scsi" -+ | IDE -> "ide" in -+ let net_bus = -+ match guestcaps.gcaps_net_bus with -+ | Virtio_net -> "virtio-net" -+ | E1000 -> "e1000" -+ | RTL8139 -> "rtl8139" in -+ let video = -+ match guestcaps.gcaps_video with -+ | QXL -> "qxl" -+ | Cirrus -> "cirrus" in -+ let machine = -+ match guestcaps.gcaps_machine with -+ | I440FX -> "i440fx" -+ | Q35 -> "q35" -+ | Virt -> "virt" in -+ -+ [ -+ "block-bus", JSON.String block_bus; -+ "net-bus", JSON.String net_bus; -+ "video", JSON.String video; -+ "machine", JSON.String machine; -+ "arch", JSON.String guestcaps.gcaps_arch; -+ "virtio-rng", JSON.Bool guestcaps.gcaps_virtio_rng; -+ "virtio-balloon", JSON.Bool guestcaps.gcaps_virtio_balloon; -+ "isa-pvpanic", JSON.Bool guestcaps.gcaps_isa_pvpanic; -+ "acpi", JSON.Bool guestcaps.gcaps_acpi; -+ ] in -+ List.push_back doc ("guestcaps", JSON.Dict guestcaps_dict); -+ -+ (match source.s_sound with -+ | None -> () -+ | Some { s_sound_model = model } -> -+ let sound = [ -+ "model", JSON.String (string_of_source_sound_model model); -+ ] in -+ List.push_back doc ("sound", JSON.Dict sound) -+ ); -+ -+ (match source.s_display with -+ | None -> () -+ | Some d -> -+ let display_type = -+ match d.s_display_type with -+ | Window -> "window" -+ | VNC -> "vnc" -+ | Spice -> "spice" in -+ -+ let display = ref [ -+ "type", JSON.String display_type; -+ ] in -+ -+ push_optional_string display "keymap" d.s_keymap; -+ push_optional_string display "password" d.s_password; -+ -+ let listen = -+ match d.s_listen with -+ | LNoListen -> None -+ | LAddress address -> -+ Some [ -+ "type", JSON.String "address"; -+ "address", JSON.String address; -+ ] -+ | LNetwork network -> -+ Some [ -+ "type", JSON.String "network"; -+ "network", JSON.String network; -+ ] -+ | LSocket None -> -+ Some [ -+ "type", JSON.String "socket"; -+ "socket", JSON.Null; -+ ] -+ | LSocket (Some socket) -> -+ Some [ -+ "type", JSON.String "socket"; -+ "socket", JSON.String socket; -+ ] -+ | LNone -> -+ Some [ -+ "type", JSON.String "none"; -+ ] in -+ (match listen with -+ | None -> () -+ | Some l -> List.push_back display ("listen", JSON.Dict l) -+ ); -+ -+ push_optional_int display "port" d.s_port; -+ -+ List.push_back doc ("display", JSON.Dict !display) -+ ); -+ -+ let inspect_dict = -+ let apps = -+ List.map ( -+ fun { G.app2_name = name; app2_display_name = display_name; -+ app2_epoch = epoch; app2_version = version; -+ app2_release = release; app2_arch = arch; } -> -+ JSON.Dict [ -+ "name", JSON.String name; -+ "display-name", JSON.String display_name; -+ "epoch", JSON.Int (Int64.of_int32 epoch); -+ "version", JSON.String version; -+ "release", JSON.String release; -+ "arch", JSON.String arch; -+ ] -+ ) inspect.i_apps in -+ -+ let firmware_dict = -+ match inspect.i_firmware with -+ | I_BIOS -> -+ [ -+ "type", JSON.String "bios"; -+ ] -+ | I_UEFI devices -> -+ [ -+ "type", JSON.String "uefi"; -+ "devices", JSON.List (json_list_of_string_list devices); -+ ] in -+ -+ [ -+ "root", JSON.String inspect.i_root; -+ "type", JSON.String inspect.i_type; -+ "distro", json_unknown_string inspect.i_distro; -+ "osinfo", json_unknown_string inspect.i_osinfo; -+ "arch", JSON.String inspect.i_arch; -+ "major-version", JSON.Int (Int64.of_int inspect.i_major_version); -+ "minor-version", JSON.Int (Int64.of_int inspect.i_minor_version); -+ "package-format", json_unknown_string inspect.i_package_format; -+ "package-management", json_unknown_string inspect.i_package_management; -+ "product-name", json_unknown_string inspect.i_product_name; -+ "product-variant", json_unknown_string inspect.i_product_variant; -+ "mountpoints", JSON.Dict (json_list_of_string_string_list inspect.i_mountpoints); -+ "applications", JSON.List apps; -+ "windows-systemroot", JSON.String inspect.i_windows_systemroot; -+ "windows-software-hive", JSON.String inspect.i_windows_software_hive; -+ "windows-system-hive", JSON.String inspect.i_windows_system_hive; -+ "windows-current-control-set", JSON.String inspect.i_windows_current_control_set; -+ "firmware", JSON.Dict firmware_dict; -+ ] in -+ List.push_back doc ("inspect", JSON.Dict inspect_dict); -+ -+ !doc -diff --git a/v2v/create_json.mli b/v2v/create_json.mli -new file mode 100644 -index 000000000..6dbb6e48b ---- /dev/null -+++ b/v2v/create_json.mli -@@ -0,0 +1,29 @@ -+(* virt-v2v -+ * Copyright (C) 2019 Red Hat Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ *) -+ -+(** Create JSON metadata for [-o json]. *) -+ -+val create_json_metadata : Types.source -> Types.target list -> -+ Types.target_buses -> -+ Types.guestcaps -> -+ Types.inspect -> -+ Types.target_firmware -> -+ JSON.doc -+(** [create_json_metadata source targets target_buses guestcaps -+ inspect target_firmware] creates the JSON with the majority -+ of the data that virt-v2v used for the conversion. *) -diff --git a/v2v/output_json.ml b/v2v/output_json.ml -new file mode 100644 -index 000000000..ca0bda978 ---- /dev/null -+++ b/v2v/output_json.ml -@@ -0,0 +1,116 @@ -+(* virt-v2v -+ * Copyright (C) 2019 Red Hat Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ *) -+ -+open Printf -+ -+open Std_utils -+open Tools_utils -+open Common_gettext.Gettext -+ -+open Types -+open Utils -+ -+type json_options = { -+ json_disks_pattern : string; -+} -+ -+let print_output_options () = -+ printf (f_"Output options (-oo) which can be used with -o json: -+ -+ -oo json-disks-pattern=PATTERN Pattern for the disks. -+") -+ -+let known_pattern_variables = ["DiskNo"; "DiskDeviceName"; "GuestName"] -+ -+let parse_output_options options = -+ let json_disks_pattern = ref None in -+ -+ List.iter ( -+ function -+ | "json-disks-pattern", v -> -+ if !json_disks_pattern <> None then -+ error (f_"-o json: -oo json-disks-pattern set more than once"); -+ let vars = -+ try Var_expander.scan_variables v -+ with Var_expander.Invalid_variable var -> -+ error (f_"-o json: -oo json-disks-pattern: invalid variable %%{%s}") -+ var in -+ List.iter ( -+ fun var -> -+ if not (List.mem var known_pattern_variables) then -+ error (f_"-o json: -oo json-disks-pattern: unhandled variable %%{%s}") -+ var -+ ) vars; -+ json_disks_pattern := Some v -+ | k, _ -> -+ error (f_"-o json: unknown output option ‘-oo %s’") k -+ ) options; -+ -+ let json_disks_pattern = -+ Option.default "%{GuestName}-%{DiskDeviceName}" !json_disks_pattern in -+ -+ { json_disks_pattern } -+ -+class output_json dir json_options = object -+ inherit output -+ -+ method as_options = sprintf "-o json -os %s" dir -+ -+ method prepare_targets source overlays _ _ _ _ = -+ List.mapi ( -+ fun i (_, ov) -> -+ let outname = -+ let vars_fn = function -+ | "DiskNo" -> Some (string_of_int (i+1)) -+ | "DiskDeviceName" -> Some ov.ov_sd -+ | "GuestName" -> Some source.s_name -+ | _ -> assert false -+ in -+ Var_expander.replace_fn json_options.json_disks_pattern vars_fn in -+ let destname = dir // outname in -+ mkdir_p (Filename.dirname destname) 0o755; -+ TargetFile destname -+ ) overlays -+ -+ method supported_firmware = [ TargetBIOS; TargetUEFI ] -+ -+ method create_metadata source targets -+ target_buses guestcaps inspect target_firmware = -+ let doc = -+ Create_json.create_json_metadata source targets target_buses -+ guestcaps inspect target_firmware in -+ let doc_string = JSON.string_of_doc ~fmt:JSON.Indented doc in -+ -+ if verbose () then ( -+ eprintf "resulting JSON:\n"; -+ output_string stderr doc_string; -+ eprintf "\n\n%!"; -+ ); -+ -+ let name = source.s_name in -+ let file = dir // name ^ ".json" in -+ -+ with_open_out file ( -+ fun chan -> -+ output_string chan doc_string; -+ output_char chan '\n' -+ ) -+end -+ -+let output_json = new output_json -+let () = Modules_list.register_output_module "json" -diff --git a/v2v/output_json.mli b/v2v/output_json.mli -new file mode 100644 -index 000000000..52f58f2d1 ---- /dev/null -+++ b/v2v/output_json.mli -@@ -0,0 +1,31 @@ -+(* virt-v2v -+ * Copyright (C) 2019 Red Hat Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ *) -+ -+(** [-o json] target. *) -+ -+type json_options -+(** Miscellaneous extra command line parameters used by json. *) -+ -+val print_output_options : unit -> unit -+val parse_output_options : (string * string) list -> json_options -+(** Print and parse json -oo options. *) -+ -+val output_json : string -> json_options -> Types.output -+(** [output_json directory json_options] creates and returns a new -+ {!Types.output} object specialized for writing output to local -+ files with JSON metadata. *) -diff --git a/v2v/virt-v2v-output-local.pod b/v2v/virt-v2v-output-local.pod -index 7427b1ed7..7c397c0a4 100644 ---- a/v2v/virt-v2v-output-local.pod -+++ b/v2v/virt-v2v-output-local.pod -@@ -11,6 +11,9 @@ or libvirt - - virt-v2v [-i* options] -o qemu -os DIRECTORY [--qemu-boot] - -+ virt-v2v [-i* options] -o json -os DIRECTORY -+ [-oo json-disks-pattern=PATTERN] -+ - virt-v2v [-i* options] -o null - - =head1 DESCRIPTION -@@ -54,6 +57,13 @@ above, a shell script is created which contains the raw qemu command - you would need to boot the guest. However the shell script is not - run, I you also add the I<--qemu-boot> option. - -+=item B<-o json -os> C -+ -+This converts the guest to files in C. The metadata -+produced is a JSON file containing the majority of the data virt-v2v -+gathers during the conversion. -+See L below. -+ - =item B<-o null> - - The guest is converted, but the final result is thrown away and no -@@ -140,6 +150,51 @@ Define the final guest in libvirt: - - =back - -+=head1 OUTPUT TO JSON -+ -+The I<-o json> option produces the following files by default: -+ -+ NAME.json JSON metadata. -+ NAME-sda, NAME-sdb, etc. Guest disk(s). -+ -+where C is the guest name. -+ -+It is possible to change the pattern of the disks using the -+I<-oo json-disks-pattern=...> option: it allows parameters in form of -+C<%{...}> variables, for example: -+ -+ -oo json-disks-pattern=disk%{DiskNo}.img -+ -+Recognized variables are: -+ -+=over 4 -+ -+=item C<%{DiskNo}> -+ -+The index of the disk, starting from 1. -+ -+=item C<%{DiskDeviceName}> -+ -+The destination device of the disk, e.g. C, C, etc. -+ -+=item C<%{GuestName}> -+ -+The name of the guest. -+ -+=back -+ -+Using a pattern it is possible use subdirectories for the disks, -+even with names depending on variables; for example: -+ -+ -oo json-disks-pattern=%{GuestName}-%{DiskNo}/disk.img -+ -+The default pattern is C<%{GuestName}-%{DiskDeviceName}>. -+ -+If the literal C<%{...}> text is needed, it is possible to avoid the -+escape it with a leading C<%>; for example, -+C<%%{GuestName}-%{DiskNo}.img> will create file names for the -+disks like C<%%{GuestName}-1.img>, C<%%{GuestName}-2.img>, etc. -+ - =head1 SEE ALSO - - L. -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index cf9464834..9a555c3be 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -425,6 +425,17 @@ instead. - Set the output method to OpenStack Glance. In this mode the converted - guest is uploaded to Glance. See L. - -+=item B<-o> B -+ -+Set the output method to I. -+ -+In this mode, the converted guest is written to a local directory -+specified by I<-os /dir> (the directory must exist), with a JSON file -+containing the majority of the metadata that virt-v2v gathered during -+the conversion. -+ -+See L. -+ - =item B<-o> B - - Set the output method to I. This is the default. -@@ -696,8 +707,8 @@ The location of the storage for the converted guest. - For I<-o libvirt>, this is a libvirt directory pool - (see S>) or pool UUID. - --For I<-o local> and I<-o qemu>, this is a directory name. The --directory must exist. -+For I<-o json>, I<-o local> and I<-o qemu>, this is a directory name. -+The directory must exist. - - For I<-o rhv-upload>, this is the name of the destination Storage - Domain. --- -2.18.4 - diff --git a/SOURCES/0013-inspect-fix-icon-of-RHEL.patch b/SOURCES/0013-inspect-fix-icon-of-RHEL.patch deleted file mode 100644 index 27b0ce1..0000000 --- a/SOURCES/0013-inspect-fix-icon-of-RHEL.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 9ff9ddf3c372acee3a31a9d9435b1f32e0932943 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Mon, 11 Feb 2019 19:28:00 +0100 -Subject: [PATCH] inspect: fix icon of RHEL - -Use a better icon for RHEL guests, still provided by redhat-logos (or -equivalent in downstream distributions), and which fits a better -definition of logo for the distribution. - -Thanks to Ray Strode for the hints. - -(cherry picked from commit c648052690a4a07a59c741308e0e8497d6f18057) ---- - lib/inspect-icon.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/lib/inspect-icon.c b/lib/inspect-icon.c -index 623591aa6..19f3f87af 100644 ---- a/lib/inspect-icon.c -+++ b/lib/inspect-icon.c -@@ -317,7 +317,7 @@ icon_rhel (guestfs_h *g, int major, size_t *size_r) - if (major < 7) - shadowman = "/usr/share/pixmaps/redhat/shadowman-transparent.png"; - else -- shadowman = "/usr/share/pixmaps/fedora-logo-sprite.png"; -+ shadowman = "/usr/share/icons/hicolor/96x96/apps/system-logo-icon.png"; - - return get_png (g, shadowman, size_r, 102400); - } --- -2.18.4 - diff --git a/SOURCES/0013-test-data-phony-guests-Fix-phony-RPM-database-fix-vi.patch b/SOURCES/0013-test-data-phony-guests-Fix-phony-RPM-database-fix-vi.patch new file mode 100644 index 0000000..91fa8ef --- /dev/null +++ b/SOURCES/0013-test-data-phony-guests-Fix-phony-RPM-database-fix-vi.patch @@ -0,0 +1,4664 @@ +From 87917f9bb911dd11c2f78b7a1a84a053e9e4e133 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 29 Mar 2021 12:22:12 +0100 +Subject: [PATCH] test-data/phony-guests: Fix phony RPM database, fix + virt-inspector test. + +libguestfs 1.45.3 now reads the RPM database using librpm, which means +our old phony database created by db_dump can no longer work. Instead +provide a real (but very minimal) sqlite database. + +This commit also fixes the virt-inspector test since the RPM database +contents are now different. + +(cherry picked from commit 42e5e7cfdbca01b2e9bd50c63a9fc65b6da9192f) +--- + .gitignore | 3 +- + m4/guestfs-progs.m4 | 3 ++ + test-data/phony-guests/Makefile.am | 30 ++++++------------ + test-data/phony-guests/fedora-db.sql.xz | Bin 0 -> 231272 bytes + test-data/phony-guests/fedora-name.db.txt | 13 -------- + test-data/phony-guests/fedora-packages.db.txt | 13 -------- + test-data/phony-guests/make-fedora-img.pl | 9 ++++-- + 7 files changed, 20 insertions(+), 51 deletions(-) + create mode 100644 test-data/phony-guests/fedora-db.sql.xz + delete mode 100644 test-data/phony-guests/fedora-name.db.txt + delete mode 100644 test-data/phony-guests/fedora-packages.db.txt + +diff --git a/.gitignore b/.gitignore +index c8b53cac9..27279396f 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -580,8 +580,7 @@ Makefile.in + /test-data/phony-guests/fedora-luks.img + /test-data/phony-guests/fedora-md1.img + /test-data/phony-guests/fedora-md2.img +-/test-data/phony-guests/fedora-name.db +-/test-data/phony-guests/fedora-packages.db ++/test-data/phony-guests/fedora.db + /test-data/phony-guests/guests.xml + /test-data/phony-guests/guests-all-good.xml + /test-data/phony-guests/stamp-fedora-md.img +diff --git a/m4/guestfs-progs.m4 b/m4/guestfs-progs.m4 +index f90bda04e..4819df627 100644 +--- a/m4/guestfs-progs.m4 ++++ b/m4/guestfs-progs.m4 +@@ -63,6 +63,9 @@ AC_CHECK_PROG([PO4A_GETTEXTIZE],[po4a-gettextize],[po4a-gettextize],[no]) + AC_CHECK_PROG([PO4A_TRANSLATE],[po4a-translate],[po4a-translate],[no]) + AM_CONDITIONAL([HAVE_PO4A], [test "x$PO4A_GETTEXTIZE" != "xno" && test "x$PO4A_TRANSLATE" != "xno"]) + ++dnl Check for sqlite3 (optional). ++AC_CHECK_PROG([SQLITE3],[sqlite3],[sqlite3],[no]) ++ + dnl Check for netpbm programs (optional). + AC_PATH_PROGS([PBMTEXT],[pbmtext],[no]) + AC_PATH_PROGS([PNMTOPNG],[pnmtopng],[no]) +diff --git a/test-data/phony-guests/Makefile.am b/test-data/phony-guests/Makefile.am +index 0d74ab110..60313548a 100644 +--- a/test-data/phony-guests/Makefile.am ++++ b/test-data/phony-guests/Makefile.am +@@ -23,10 +23,8 @@ EXTRA_DIST = \ + debian-syslog \ + make-fedora-img.pl \ + fedora-journal.tar.xz \ +- fedora-name.db.txt \ +- fedora-name.db \ +- fedora-packages.db.txt \ +- fedora-packages.db \ ++ fedora-db.sql.xz \ ++ fedora.db \ + make-ubuntu-img.sh \ + make-archlinux-img.sh \ + archlinux-package \ +@@ -78,8 +76,7 @@ blank-%.img: + # Make a (dummy) Fedora image. + fedora.img: make-fedora-img.pl \ + fedora-journal.tar.xz \ +- fedora-name.db \ +- fedora-packages.db ++ fedora.db + SRCDIR=$(srcdir) LAYOUT=partitions $(top_builddir)/run --test ./$< + + # Make a (dummy) Fedora image using md devices +@@ -87,8 +84,7 @@ fedora-md1.img fedora-md2.img: stamp-fedora-md.img + + stamp-fedora-md.img: make-fedora-img.pl \ + fedora-journal.tar.xz \ +- fedora-name.db \ +- fedora-packages.db ++ fedora.db + rm -f $@ + SRCDIR=$(srcdir) LAYOUT=partitions-md $(top_builddir)/run --test ./$< + touch $@ +@@ -97,15 +93,13 @@ stamp-fedora-md.img: make-fedora-img.pl \ + # for root and home. + fedora-btrfs.img: make-fedora-img.pl \ + fedora-journal.tar.xz \ +- fedora-name.db \ +- fedora-packages.db ++ fedora.db + SRCDIR=$(srcdir) LAYOUT=btrfs $(top_builddir)/run --test ./$< + + # Make a (dummy) Fedora image with LVM encrypted with LUKS. + fedora-luks.img: make-fedora-img.pl \ + fedora-journal.tar.xz \ +- fedora-name.db \ +- fedora-packages.db ++ fedora.db + SRCDIR=$(srcdir) LAYOUT=lvm-luks $(top_builddir)/run --test ./$< + + # Make a (dummy) Debian image. +@@ -138,14 +132,9 @@ guests-all-good.xml: make-guests-all-good.pl $(disk_images) + # Since users might not have the tools needed to create this, we also + # distribute these files and they are only cleaned by 'make distclean' + # not regular 'make clean'. +-fedora-name.db: fedora-name.db.txt ++fedora.db: fedora-db.sql.xz + rm -f $@ $@-t +- $(DB_LOAD) $@-t < $< +- mv $@-t $@ +- +-fedora-packages.db: fedora-packages.db.txt +- rm -f $@ $@-t +- $(DB_LOAD) $@-t < $< ++ xzcat $< | $(SQLITE3) $@-t + mv $@-t $@ + + windows-software: windows-software.reg +@@ -161,8 +150,7 @@ windows-system: windows-system.reg + mv $@-t $@ + + DISTCLEANFILES += \ +- fedora-name.db \ +- fedora-packages.db \ ++ fedora.db \ + windows-software \ + windows-system + +diff --git a/test-data/phony-guests/fedora-db.sql.xz b/test-data/phony-guests/fedora-db.sql.xz +new file mode 100644 +index 0000000000000000000000000000000000000000..be3a4f3ef8c829e35d455d5c4f61be61f4a09f94 +GIT binary patch +literal 231272 +zcmV(pK=8l)H+ooF000E$*0e?f03iV!0000G&sfap{xa|WT>uu~eAsC)98QuB00R)4 +zwXu}%-J?Fz1LCsojVu0HySRr|UR~ZdOYPPRlDK|+?x7p)ThjIji8?#vvN*Y5BMW)*CxV2nuVp1+fqfd)i|J#L2-23aSO&-{pq?a-X +zN#SY-YvhmSotN)g3EmDFcLnMwEQo~{$@>H7GAvzjr6b+-AS$4R8@PPPBY@ImUG)tF#~W`@3jPH-3UdGK6dgj&fz2Kk9BJ5ex#p^FAzpQ5qf +z(ZM^I;FcF=bA2e6PL^(0^leTr)h|c&bEJi?OJSYljSo8?4uI4rb6@O3(83{?t60P@ +z3dBh)5?a_k#RBA_Ui{C$o%y4qOMtz@Vg5O2Y?YzY^K9^61WhU)y)@X%!UNI;nd{`23PWM_B!%nJW3($UF378;k_Wph!lo%<*N7$ +zif2)S7D-;k`n`QN)`%BZ`1gNJSWHUPT9l6L)V!GZycL_FT5d@2RYc*Th~MT#1Lm4Y +z#r8hiyM!pQfwiH!3eEEM^c`^%9y_BoH0`Veo%j%e7y!blfKt(`-y9c<6X|18BhZ;9 +zi&N9VevHnPbKtZ&UL1jGYa{u`SV)DDkUKvGHsb#tNZh5Zmn3wOr1@L1=>>>&N0z%f +z=5Bob0@>$hZO6#RHbTp0JDQZjp=dL8FL752ME^8%UAd$x0x(WmaB`}*_i39%$q~YZ +z-U_OsgIx}Uj9?GlA{+`MinQ_pB-1E_=DO{$f{?u45z8jQ^cS9FOB1XWJ-$f29ub^@ +zA+XXRfTsw`IC +zaUi|rmO3s%qBTxvV<|F=p?S{&Qp#>M4mL)3Zz53EEXDa9H`%;lv!&MrW?B&3OP}b+d5LS1jAP>B*3ep97*Et1!!pHiFJr7q8c=@(*GkD>>p4ySSJh)05>P)^)2LCPtXZP19(7 +zSP=+Yi<+eYICR}GLGV%=$ +zrm1$LbZ7R&hmi7TMUHSn7cHbz$IMLZP5u`14=*#IAAM)uq<*-o5F&OgGz0iWev%w@im(~5FfAn~kJt1N1< +z_k9tmBtys00DQFcmk}f@5k+oitkDiNL=DBeFr(5)nvB=4_n`f8oQAbtcX?T_`S4YY +z!L-!nNt#gJVJ$Xj9Bbr7QFpzFV)MDaBtJt$l(Og}47JL$=@!vz +zDDXWAuAHQxq<%c}cjSlsW>ZfrUWZ0JqF)DjX}}2J-|V*+eQ#(c6nq!>O3*rTkfuNF +zBJWStPD|M`&FoU|@zIj;!Oj52u;clZ!qUR4AEzm`C&ZJPTQ11X4tT+&Ui@VoA%#o< +zl04j$U(;EJ#^>P<7qxN +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 +zjR5KFMm(Z(&Y@u;y$A(%+wiH7xv*@ +z1xhWSkJcHzgB{QOQnFR^(4Mci9{Qk5s+G#%gn1|N5%Zy)J4a1xX+aK#u3-7;NeLSH +z*iC1woXa?ee|s+*7tdzAj#x|**vI5CUVkzQC)sK!P7yMsXo=c;>yx+#&>WD+-&-pj +z@LC6qcJp9@H5Qj42__B*GP>cbWFx#j!-d`msYJ|>-Fh_MtqWykX_2@;reSE|7|kA_ +z*dZ+k42xI{K+$%Mo#HDJXi!>_o#xjY5~PHg_rVavc-~;*>l@*c%Z=KpNn{($658 +zZt1@>guyh%nCM;?r(k1`+!P +zdB+eOykMn_30oT!$Alp!s#ZBLx>HiK^i=%@U}^M +z{Q#HCPc`xO`%Z^x1R_4!^iG=MZ){=mGtMJY +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 +zQ0S+X4vi(`WkkX`ZY7B5vqy+xPAL +zW~It8M`#AW&9J^~Iss3GkKthvg?Ta=)Xq*?>uj&pSqB1?>Z)3& +z<^&GxE=kQSO!`;gj1O^RVi|)~Rkr-9i`6}6aRWIR6O4`)!I}C;_^L+T<7tWbCw)v( +zaLuRk3#d-#DGY1LU?~ABpHWA}-Q@cI$!tj2+pyX-IjkN4ha}w*acAZjz^D4hJl4w6 +zyb&b+C<(*9`I1^-H(Usxj(Pj6TLJr3leaqat}_n-Oc}G7leGL?tl@}9!2%mjUTcwL +zAEhRnR=U>I#y~6B6|-ndP=B?5Bns|+Zdr8jXs6bOa^L9%`m6u3rDruo=5jCl4aW2) +zxR2C~=r{t!cY8MIHQ!-5(^67nKz*JzihxVKiMR>Xt~S0(9WK$eXn6(n3+jswH*UE{ +zuj0j*Z)-_G;sDcxDG#BwiTVcoPsZM$&nm$x?5q?q +zc8UjB?-Y?yHmjtrm-QqR3WOB5EkuKBFUozO+0Exdbr{7hM@{#i0s+@}s}FM}GgtYU +z9iVQ-`qD9dY^h3Vhvok&a;qn)o`NWn4qeh0-t7lx1s3*GHL1InWRo%myg$DEV(bsY +z$Oz#)hGxE;EQr5|(q +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 +zUXBH?;KChM&Fe@5J;qo)4^8}2Ag=5Fp` +zLc;x<*bSXA*y6NRpt-JkD)w+9aY**rbH#~^G*{g&27_SzrRv(PZEt~ +zCH^5M+CSK7diNukr}a-_<@mR~)JolSoCwRYch2IG$xol4w-cc`g+C!M;qT2^hwIL4 +zO+K)^B0!%{WAfjo-t7PeWqTrb{d#ax`(xhQr>hLhHrLV|hi24D6OYpj{fmP?2N?+d}&9AS~i@1H@@kAf# +z1bCFhv^~2t<@&Z7WSt-s5wyt&iPFW!MA^J4*G*a_v1<2GM4woU-YoFM_Lr?Tojw +zA@lCfc0_9ns+DBzgbZm5@fPXkeq!2Y6sTT`OOI(^Z{SIjKEy@gO=k`;^{Yr+aBNy; +zpvk?dzMa(E%V#~@;}i~GdUJ@C{~nEtH@Cx`gi)$6UK1pc``o)dTpEsb!0qA0@UYOD +zB%uaxF@K;ab=dxu7yeTj+jQ>1-raAnswP%9kZWG5+3k4+6K2>uqO?z4JC|*^SJi~v +z3L{c0U`8y2%R)nS?$%_H7O?moCOn^%d&%ywE!xfvJ`uv)C*4gK2kzTgBU7q*FQ>Lz +z{JX*qHSq*UA1_&SsAft_kQP?-@E~$jJ$U=)z8{fGmh5~%wxO@tYtH#mrhuibI +z*EA*0*KZ%-?G9!H_5a`iuBMYhz}<6F13-a2JLI5?mcK`M}T$dvQFV`!6weFb6)HZ$gef +zhFo5>vjy@m5M@uM;5ur$8(a6aO2nkqH+{kUQ;j*9$E{v>;{?v@@b4glp|45QNf%1J +z|B!5$WWFV}ii9L*(LxmV!r*j +zdJ>A`%#G&2^}U<-#-{Y+x#&FwH3+H={d9$S_(m5L_KvY;E^_Ngk`)*6z@YYs5(Hmo +zj&KWgloX46!9FS~8IA1&EQIb^Se-n2+1GDg?B;ppgFY}$oXVHVcypcE>NZ7_ANhJ) +z=DTZBt5#J2yBwajW!Aw|_y?tkxC3Ggo7{~q>}JYK4%63fOILF|hs)N5C*1mK}zKb#{cqX?4l_eyg+#$|Y|VsjKPqzj)J +zCk~lcj$RhFt34dfd=o~y^j1^`a62BD^wEI0rt11m%bD-+`^u)C5;0V_#&4uhL6Oyp +z5tQ!o7cP4^4R~sVVjGc_>GB;YO{W#k +zaY>`fq#tm7D@!;(Nxlq6)v5EA_I2Zf{)k9jqI`*hvFF4f4+% +zfI%Qe(hh>PjLA#&1G7L5GOeU&dwMf2WFS&*qTc@zo9&6xF2&b6OjM +zEAsyRJn^CAN{h_2W(f8bUGW+4b0h-$9!^OqNNNhlqbClAYL +zYOos3AXUnXFSL$9$P~nOqE+jNQP}6jj^H{AC#sC;x~RtuU1=0w8u9uu!4Z^ka4(#s +zR-)i^Oy=-U4j03XV=vlUp4}xeq~6LeVngvsOmY{hocplA_1J0zd{84wYi`T!l*<(3 +zR8JIb%fn$5=k_5>#rrplHR;{RU7)~OU?P^fDzsmNK7LhG_x5jH^-{1~NFQy1TsmE` +z<=~!I%y3}t=6yYwDLN~SSrXZquz}=9L1S@Px;|6{lw}D+7!0jKL{zgPbUxe%3*#^1 +z?34PYJ@W;zDN{ejMZB5fy)VX@HQ!!!F8DSANS!;KZgQ&pZpK5>i +z#^ez!koa0uCK0Ww33x*!j`bGWCswnE!&o^{BM{+%f;AZpY1Zgahz%K0q^&rZ$4BwJ +z;3!|_zlZwYYRmYZIbZ4;r04kG_81dKFI{1{95ORi!&t%!09)5 +z^=l+I%5rW_v2S1>iD6MXRVMC@vRPocPTYn;5r12muWPA2`yiiht;cusZHrs#*~NyY +z85G-WT{eY{oHSQI$74nE>0diwIX&GLg43L6dnOJ?(gyH~BwqPJHo;|dTJ8K%>Ssj+ +znz69B8#UoX{-w69dUx!$?A6*u?vno;&ntj45PFKg^ijACVwp(h3v7Kz2s}sK_j)@! +z{r#oB-=Hks)JoY;&0-zp2LjKgk~TF5(9B&Q;KKvn8vX`rM`;|j=E|c2ppn`=qr2);3x-Z5Ud8UF`OvMtqMNCmPIxLS;mt& +zXG4H`u?Lxeen-HkHGgU!V>fnj8o9WvPGpl-Ig+CBTG)!xw*`ED>s2y>T^Yt +z_O%=Ir&Mv)rTGJa-Uw80Z=e@j4=b!?9YCt`=?<)e!|J@#Y@>4PXqineRUj2CC0TrX +z3ZR5V3(>Q0)ZvxN%W7BzsPFv$@orDYgxf`!Vs)+Q65uwJu2U{+;t@2)e(cGcodp65 +z3eb$?%xb7#Xbb}jT6H(lh!G#airiBn@m^hCWu(i-Gm*GWDL7~`=^XA|x+_o8pTq=r +z@FXWGA2ob?_nOT(V059|XY$@IDrKv6Jx@OS&Od&!0H?Hiwz909e|E4lJjrUF`ZML- +zUqmD3JooP#e{M{T!5%d+-UmEa{S3o+t|{?0sR*-S68)apM5;2K=A5rjAw_bZX%WQR +zD!jz9wseoH+Yq&wX8FX>bZ^WEN9}s0nFrnA{{gK^_RJ>gO@t>cQ0OLp +z_J)Upr2grVA~=+B8$?c*lt^Ycbz@!U7KCqp^QxX6>Eaty40U_3_TSV +ziztViJS{f*>`n~2Ho;4ZQ`LP~m;G|qhWDm}lddFukHo@n@?UlFHhp9fT+j=aB16k= +z_K{@;(?>B>OErq}zjM6`L`3fcX7>zn9plN{tEVt21r8dc3+Z>xm3@qW8A!aSF%}Y) +zPiIiZ7*e)N_Tg`%I-GM`I@(T5;m;(VBPvmpDxVG(M?+I^c3LDi%qfB2;PSsJ1BNgvPyY1 +ziNIzJ16_jC>KPQH%OgD6w;j&n9d2$R?iB^ndJ!ShF%dY}{UXoM>1j4n$-{p~5bsq) +zUhKlmb=rv2(oV*qYO>mXdvIP_C2nb7C-Xpum +zMj~xTl1HvuAT4c3I%EmWetQCG?!-VydJQ0M$?H=d-a-3<}2BV9P&xG-qVsI}m3UO!rGN8!{1IuK(E +z8d~vmMnlQL(7mIjP6+tQgzb+zBu=L%*eX2G#xYhDE^#7oI6oj5VW%?6G+%=Bmc^1! +zFGWrx@Khp%g5w)&T9knVtRJ-$+j&9T>hYvnmhhEWQnD;sIUtE-Er3ZCh=rL=qbPxY +zX#vAVyjnZ=R~JkET+=Fr!}5dO2&eSKuWOZnw$b$+&RVJ_zZDD|4mU7zZ%2YQ?q{RD +zL^W!T5;dq#3pg)=OKVS1)%;{GxYd$T#{F~INgLi5zNa)=8|?D@EqOSThMCGjIlQOW +zleCC%+K@D}AiHPj$f8gMGQCQ} +z-;h;F=-GuD*%OiSv@;pAV*b&Ex)asKzFXI +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 +zYvi!7*Z{QDlOtdq>RM|1q|q&+_mT%xIWed@`t +zav@Ab>TKrQcpXN`x*YgFYC%}bJc(qfJm +zWC&?05AY-yVl9Q7@OfwX+CDBVKH=Aq2y!n8UXAUg98_2eoTqC6bg(Vst7hB +zlpBoK+2?+gzW%(Lg_^URerwPh39c8Y^P3TW6DOQd0k1}&o8Uh0K3#Vyq%0M=T&qvQ +zuG=qx(0LixIQ6EV0;x3}thN0IJ>AWFPqu>5G_*1?CbMHu<Q(qY9;ZRaaB=H6 +z(Zbgu)_o5p9~?9ao`j)|`jX6)5qq`+-AASZt7(;%*m{`&_)S6p`!v-nZ!rHI6QEbd +zUN89@gyQv)p +z-^=5QRS-h3Wdgec$#{w +z8fmovv^&N{hSd51ij?-C!R4JIm(=N*=${w`%KMl`+Xtkj>xfZXJ2iN}eXm;?@Bk{rhnklG0gp +zlfcbc-nEMtoOjW;Rz;z^?gYy^Xs9K1H(5Fjt!vfV{th!`TTYj6N`F__=}p8aK!WHeh92VkpdyIK=+YD|FGF%J+qA$r +zNdyb?66VcGL0YYDm3C4%E)NK%HTo!Lqs0A{A +z)KR~r?mC43<;YzqctVd=j8G>xV}0^tWQE%IQKi~$!H!0A)Hn`>Uh1dL1DRVN8eMj+ +zN4_-~lQXlRxYNu;-HmDEF^;b1y~#ZLJnlDVlXF#MBsv_v_Z6c8DY;Aq%m<4siJ5lF +z?2z&;HXBGILl8*i8VuYmR@;kd4B0*BYu9g?AROHf`?}*ikINzYmL)t&daVYidWxhu +zZnk)lLqFKqu61I*?(Gvp5@whA +z^@`%@zF5(>NE%n6Pi_E*-#06R!rHHOvkgX9yG|wQShI15|Jx|2gtR5)=vt&Z%p6-gCwI%Mv=u(t79oa2!4wHXlM=@dEU)J5&Gm)Hjfjt4KQD1PO2I#hlGSa?b-DClwaRQ_}R +zUmAF&bMn-jXZ@nA!|lOJ4$s$*HO@xpSjxL2b0no_#sC$dB$IN`k0MO(3!&Wvs7Al> +zE1jR97X!0j)|q?h$02LJjEiOX_|lig0A@&}^+$y@bS)EaP9s0U#wgY3mN~F}qVcQ_ +zTWNcaDvUFc^u<@6OV`oRGDu=2*`GMp&C41c{xDl>FC~Vu#nRFe$t|%(w2~v&ojUZZ +zxYI7^OoWh(Vd1~)1nD`8HCZhVEXt36$xG&?Dxi$()YioOhuh}iv^!Y~&0;;f0X6ip1Q;|1w#7C;=ajO9yM%5FN0UpXm2OjG4-CiFJYO#ue187!=&T7Z3g +zg+)-3D-k)}FJtolh)P_{=D=K|34$3x)!<)Q1u$62N7l>+14@BPfr#6wGA`ntFe&^-8-YQLn~P%7o1R+IHKVXQg3KrTl}R&Ge+s7-ms +zWxC6OU~03zWBvR$`eIvV9)^9+-l_)q4rH9(4*qlcVI0MO3L~h-oj7vMo}8HMew@o(slkGxE4b +z=c<%avOnJXI!jLv1}g2u1cTC3%sApAvTfqH)PCKotM+XQ1UBPgH8dS{W!dYavZiqJ?WyjeTc%dBWjtW6r$ +z=8!np^N-4JouVghSfiMgf1n)Lf4(tc#4IyPp +zP5FBfRbznl7hPA^Q=RApKww*>4;sHUPZUpMO$)7k&a{f$i~n(WYr>dHJao +zZ2Kx=Rg9DyWiCIFVrD~F#Ktsu(w8hE4>5l437oc;RtOgCgEw%Qu+JtMC&>Yq@_>3L +z+coWQUbc=A*{i{Gysv@Cn}=`G{0Hi0y?1x!y*vFfnGAhaiKz9YTB*+GS$g-Dwo!Z? +z(P@-PHasus>Nb`U0A;XBqgbxkQLgcN!$Tgm*+T<*3Fntb3VI&fiskD@q_bW#_w$3Q +zMLkpiwMfm6M(`gork_avR!za`s@KNbW$KctQdFV7!_s;rnBf!d#I*`D +zb!)gKj9Dtq-%-LW1_nZrWaO4PMXEr>UKgMidtVaJ1Y1~5eCM@R^v{{$2jSO +zK3RNzv%;xSeDHj@z`DKz>SY1~74(a-z@DFf1+WN`iPo;rQ-8oixK4x+;Lv=*LBeKR7(Igo%PF=N9`&I9C%mV(N5qc^MQTEMc4f!osZJU#RnhJQqYMx +zSc+W?Xlvm1>Ov6nWNvosjpKlkriesgp(DN?abi{hyy3+?o3YSRa$0(&27vYJV-j3VP;X{GYf|Ac}^WWc2vLS;k*#1?>0 +z>(xS>{0p~;N%BgHU+psQ +z`mtd>5iHXBI)dkKD;-p``7&!%0}vl{?vK!4rU{R_0(z1^Ky)WX&bR-xZUVebgPN>4 +zrTGAbGXMji`vJ9;9d}9N6xm3fZl5a-jAd;)A15KfLMcmOuuJ9X^2dAlO~?ttYhhql +zL&)LRtBgG2i(5$S{F({JCWgYxOB-@aC*{sKQu!4=I`LNI;+a|$HS+yHstF5E@Kd?q +zfrLg*E(I%B(58N2qkXpkfJv;6wHY)+UL{|CVS2(Nyn#B8z7iGAn> +zlpCoto+(@e{X2P5cDUBv%{`59-}}SzkxP2s#fDyG>FX?780FAeJd@u4e3R=UO<3KD +zY0(PyUfTbL)Nk@xmGkuA6x8mwc;+AOWe6geYhZH;W8;|Ou%a9F+fL*0N=0D(f>o5^ +zoo+<+Cy`rSu-B*Pd7{evN7f(<<$O{}h(viE^HSez0_QyX-|$;i#?u%ec@^?Q_E)yn +zti2u)J-d>G>HUu&qG@#l0 +z{G~ep{kqUQl{Z?Ac?U*hyFfQ4H``Ne0`f3wi<=qq1Pq0BQUa|8f%|vWfK}Yh0SRrO +zCOBYO3=QqG9nKn*puD4A*G=q{-BxpTWGgChTA#)>eUnNZvF8=HrxOezSLv5JIQeJC=n!0eq+#jUKl0P +zOfriLnp@^qsC398f(ZF0`Q+m3Za|aWX$KLXYegN~x>hi*yy^c?nWB4zquOXjo?rAUWDKI}DTsGA1$UVK=GlkqB0*2v&D +z`~c!Zz6Rt0_${z9Un4y^tm(vnwN~rulrzlro{08j=}7?yQ5^xpme9^bfagbriPbRS +zyc!l80D1k#4?6B4ob`!~nsRG%C56BLaW`Gr-Mn&KqJp{sI~?p|GLlVGH6xp}Y%r8E +zi*{VT4PN#9UyN}(V%DV3SHE8X?r+w1NI6Xtfr#qfrZH#UnpWs?tjhA4hTykZ#X5>! +zMNjG&NPvx9$UG=0)p+m_3ufGy98S;KcXi*C$ky+?ndhtvNDYJsKueLh<%0i5twku* +z&2NcCvm6N$XcDX?1&3o>a@!_wlxULpuT@kCn=>a#h&bbT#7MGg)o%l)(pks +zZqpM<9XRcc7hD}?2E)RGraImUMW4SpwP66UlNKrisg8z3Ewh +zgU5Ze9SP`x<`AUVmd%_R?IpcMf-)9yNC6EUsbF)AM& +znJoN1Gcux|&Up6a2pLKxp;f8@(q)&iG8?2}!e-uwnCX~!H7(wgVn@o)9tz!M>&j7Cawni1 +zfZAUX{#pH-Aj$2EI@h2|3p_L;S$micHT{4@>Vlsh;NWB4oYSPTIW`|kPMfG31(OGR +zo{zt}W(;~@M^2iYw8%4HFZJ_T7o1~(ih5e$>qHlg7>E*Ts}3n@4i{?WWud7pNf_PL +za;tzcv+RUC1Aji7FrE!Zd(o2Z1LY231-p +zK{vhSZ@ivGrT-I6zxew2$bpUMBD6E2Q;F_tHIvO^9Ws@&DY~MCL4)ZYIKgw3_50PI +z=&Ub7D5IT(*1kl2NWQ9QM;aYGuS)2XW;(S_Wg;r$$%EqMQ16aHj9zGrp}k#ovugtX +z^}n+9G#z4##^4&5p`hp&0qi_dE=ow_?t`h~!MSpgatCuu>61~g>An8X$=38tx_)0* +z)4PIL94j$Cb%er~5dhplQ-kDC5JB)L)>gzo-#gvT~ko3NO1&zw>7%fFUzt*F3nhh!smSceyqG9qFI|Af{L=XS{HZH1Z$_ru)V1(S3ykRJc&l3r{GjxgifM1 +zAdZ9@wwmEeT}L;N{T&!1kQ-%}rKfXuI9tEtUO`lD`c+8)1f;gVjmFEh^VVGs*n2!d +z+`?n-#rxH(Ss1q}Vw6vQnFx$-UGv#9h(ni!T(D>k;wPI?WsueW4I!z|w^R3cx4JcM +zN;ZBAb9qY>`yy}KVc)|%$Y%AcRFR5Y+txv391LXx8SVt=DRsld4-^}k#IOFXF2TMA +zlkNLRMJX#Ub(C*HGxPU4*yikjI!j;JIKqhS1oAktQUO3&;)224Du5?9Cii6_?Xkmd +zvX3QMv3949D#?Gw^KfCzwsr^ja*Q##ZJmb{ +z@{5+YWr<(ZaeB^?eMPVWM35k_=;qQ~D_(7hDFlBkF6}1oiQyh6^e=~4q!&ijLtw@f>dSxx`O(C1II2}5l`-_ +zt-J%RjyU2~e8ajrmt%5ZzmwY8FMOObt!ePK(@L%uP-}J%XmH5PGn{4`mp0)7;0Xrk +zKglphKAF9M0i}E-WOZ4!^)FFA4ULf~?vJ!dd1`>YaTIGz9Z2_KXnDW2xYwYV3-|b0 +z)pGxw!2w?;98fU~c98^8a7wb60ri9g?)FtbFAfosg1$J%n#h6ZoF4Ql?Kvy5fL4{@ +zooX~zP1~soYD_VCA=(SbFw2NX+qW5)e$YQAbgx3X3BP~*Z<{unr-Xd;i~dX7CTcTh +zJ$PWw)Z#IZ3C{^Cx5pX3MfTPB!FAZ3@dX}$Q(FkvYKXB6eUu@_aw6D!l +zoBUf%XC+K^Em%NmS&2P{{V1a)H1B^;ux66ZwW%5)WC&`{t!RW{%g!6(PM$QKXrLBg +z_D^&eO<2+enS#gTWueyst8y;0d~hho)|67}8juKT6|xh0Jipn?2(!YHL>G5`SBdW! +z@6*Vi6rg*xW_r2rQL{5?1VZccPQXAj#RbGEM7}0S?Q|WqNy4;&%&?}F@jaILn-!p( +zeioM_h23Xclf^knzcXESYU-b{uEBepIUO5&1Fmj8;y)iS^K5qcfZ)Z^-a_zUf5jlO +z0{#xMdkr4<&tQR|7L)^z?@3`jKkOr_Ngh&w3(dm{2lYvU`Woo*>p6Db{HLCi +zbi;AN^ul4%YKo`UQxa5TxTj~pdvs-TLNvXSbRPuDEsJ}6k~})Vo*}Up3ytBY_&{Fr5)yg``P=5Wrfb$>EX6swNvEBuTx3Y1Ik0kZ-QG|3 +zE+Freg+`W^CT^1jA??w3b>x+UWHvpLUVXtpEQUXWi6DW}eG33xIG{pGk1#V`cDzBu +zW4^wQ0Y=kS!7pELNV)pAL+LrWJpuB8;lH<@%i@Q$=(VqN3t<4 +z4Uqp4C*Bp)KJJDwkNZXPJQRvzbIEDzX;&80M0H7R%+UQRKvi@vD*R^RG-Wq9zQMMr +z_kJG`5rx(5dd?1cL;4WZyy@$BTV0b8Y#1YCdT8{yNO4E_^$737V0%=i1;}Os#-971ra7q=nnaHII}dA53o>T +zn8N*IGlx~OG+GeH!W*9B&NJq~W@w~7!kn{M8?G%dYWKOE?TcY$;1lWsyIw6h_L7d( +zHU_n4wi%qt*I=oLrDDwLsq3W3Jjydkp4qfhB>&!L93&DCX3d}^>Ia%CQS-7HEiZ|^ +z@sazt_j5HmKN_>pne#ae!PPNGstq#u9W{~to5gdDL}qUC^N?lyB3%w}FA>zni;-8A +zkAtv!oYAd8x1L5eIDrMG!O{`Q2?2l;)jGnnf=2$i0d2~f$u&3twjZ=D2JZzB`ch7D +zeW%?|Rthk8)GKJZD6hA}C3dqUVL2LF^&avk)`RScH)mXYC7FL|>!7KDxaUgEZTz<4 +zj~P{^yE$Y`QgA?fyUpR_Oba!KJ^WSE;ZWY?DlsN +zQ`!1tWq{GTS|~8e50PVyAdgi9Y|4amTNYete@+pX$!$?$!L?8sYO``dFE(BKKg629f2g#qXI;+ZHe>X|y|PH5{)K3(6UZ9#K5nw&3Ua9a +zF6pBIxk0v!%5L^cZ7_cJ-1!&>`{-}Xu +zTCtjyE8nq%(70!Flz(~8J~*6Mr3g0U3qO(=5~zmk%rOc4QY^u#U@k>X-Qyr$TcJg@ +zDOQPjKTis;kOu_9#=H_9d&+$yqg2NLjnC=Jb;yJU55ghz2~GMR%B>Q9X0!7@8F9dD +zQg?_O2F+&%Y!}A>?h&;4Z=JyjTMeyLT12MomPdy0)6-a@!<;bO_{Nv3l% +zBTq6tmY~u=XTENQk(VKhU3`l)!*jOVv;zP5twy(9_3ZB@oNTK`yH(kqC%kabO6a!= +zpy6Dq>kJCJ+)6eeXXHNdJAf%}9DU2o=J7b5^o)^`ujot +zL0aswQjq)sjBR&FaeY8D`S_&UAb!+Ge!w|~AF9l+zI@wN_FUy%+bs{9V53*(%Y4S` +zdtRw$CAUla$jE?RICe7~8s4eqMbKgW;=ll<=wbdt0^qMTAq5y##s?I;7z?r?iGUtW +z2TbMV9h>gL6+t%5Yfl@)pn#Vru-1ID7tv;EpRW?u{M@?Omv_G>5FnO}FB=;P!?_?` +z0?ELcpp2lniiXIp;DjS%8;re(<*r3gd*reRUR?72Al|ztDjhka7=lf7SoYC&!U?TH +z@CuBACH8qF9mEUW9?2umy=B`Ew>*;+!MPJ9aA?wPr9`O?ljs*fd9+QpV6aHUG`T#ly`XX_OoCecT$XPPc?&a1ju!ooXFDnWkdGzqPLC1n|LL7{?dhdgT +z=kXkNha4YwXWpgkalGwJNn=&OxonPGkPh(>kec;Vt>GTBPhyAARTa@{qPtz*;G +zy@F=eoNP4_y3Q7qwP>)kE$i2xOPa}ezq_iEhPax1fC@!7CjnPE+~40f(8w0fh+*Z0 +zGgV;f;+^1m1e%tdw?>+I +zUQ)yINQWLCP`~Dgq1l-luFmDfB^FrC%wf=Xg3`H#JvNT;k~W0^O#K^_0)8;kp9#RS +z%tE`-ti8IqdWIZ~ulJ^tk#jR-RVaOYZdDLX<2z$m4oF>GlZGBPtEVZ+d%h7LWK9w$ +zrmY@IW6BB0!Vi}Rl9)V58u%sGz*cPmiEx)9sYxZU#KlOKEXGAMmPGO-i*J1uMW~$S +zU0P%$6?GmkKi9TvWIj``?=hXA(KdGNU)Pl28JS~N8?%Y>LN(R-^C($g!pl6C={+L2 +z(hO?`i`k68I0|~=-jAk|&^)r7Bk>2w7uD&j{YJo)VJ^3cZV}uDiWHLEl +zV`~ZPVQ;^0#J;EMd?|dvkJ&VnR(I3G_OJ|( +zbCDowkDp7DZ)K9{ck8~B^O6iiNZFB}=h(^dqs@alQR69MK%BmZjay2nP$QSMK8#?KfJuSP8)SfVrV!JsIS?F({5%ZU+U|!+NKafWi$Ip#8n!ESfV?_?Y2cejvH5 +z|NY66bj9DIU(^k!BfqjFyr{H5?vZcy>@cbD$eG|4ta$4zfi|U5 +zy1A18Cl`Wo=g>rh+uh6Q!dhUh`({{|>@?OF&+fp@C7qYlhOC@nx>u!-4dZ$W#a@?I +zkaZZ-2;)JAG$LjQ`Gz|vsl=%lcpdkStq!n^X7j-1SQ= +z*W-xAoMq<0me2a$Tyy;$7i%eOglFS%)_1a2r^bE!TU>`Ux@S5(PaW~*Ui-H-6KC}o +zrMI2pbD(h#CuWBC2RNN-v3^dpDF8zcgKjl;pBHzZEcacc+jw;M +z=eo?KrRmPAg_!Cot6t|vC_IOnCMZA`l}J%y=Elc|er}Dt@rpSz$yBbZmiu+gm@7K~ +zA8kJ39KVAO4TGuTDC6?|l#Rxgzcg?AsyYci3#Lf1qe7a$VThwBj*5-;+8N4@p(X7& +ze~1}aC0ZOk=Kegp6nZ*&tTz*v@ZS*pz+MEEt5V|Qf5r`u1Ao6!b^#)llwggp!*e9> +zQ8O((z*N;v(*7w$jzrl3u7y+(+NA^R&B0Rw*WO%@>VTU_7?3Sjd(a7sU`#%KE1p(< +z;-mOjYi%@IA~}We=ooWCVq=vKG|Q~gyp*I?cw>uu +za91<;c2PLxItkBO5T!V4Y^pm#){&&Ue(^0w;N$1pl6=vNemsz@A5IM(N|O8?2$M_@12hqcigsj^8Ne1G}BeRo7% +z0tq>BLr#=8)9UjEwVeYlBb=&82$|5?-QXD&H#c=%F`0O>f!`b8r??%#%)p;hLgI7< +zO1LdIx_Jig)1x4`be!Pe=iXZBrjiW+gInGInRitgo9;{~787>So)U_8-zr&Yfl-l6 +zei>s(JB!VDWu|iugfm3ss&PMz94udGT?>0Bv!K7!I1jm#3e%Fr7Uwv(t6pckFlNy> +zcQq*-|7nx2Q;cB$oKz(WnC@9&IZ*D;nCnQ)FAu+0V +zJvVX8c}NtU(IX<9{swr!>A&_N5)W1jvJZfi>5vJC1K=fGO|xO#4Q#q2&a^V{c&{_~ +z(u=jQrq}5H6%|g3w;{T1MX$S&XJu!1!66wg7~VITAP2K6$!3#Q)})WsA|NJ`q*Itj +zu}u%FOdxOMzKRK^h{CxrKMrF;L=E-yxK(yR5G=|KBxt-oZPZ(Gd;gGl#7d~Q|A +z&1tKnKMTw_zCgG%76$vCD1d-zmF4@L?p1g8-E<0V)KfT25D{y1^{Bf#3o(A#CFvB* +z93%b%E2p`h4=q+|mWz`so6@u`R(=(3eYhrx9JB@1YK*bB>lz~eOweL6;f^BmpP~_l +z!sB$UJKPcQII=fdEnur8vR=|Xfv5Z$PG>kPcGHD%DRRQ+zSKWdx$1d$KB8vHA1}t+ +zw-1W2UH2;7qjkjCOH{w8Uv+ybd}HRfvbLbJ=1IO#20Nc22__A-w*akprWV?!ez}=` +zdE1sIPENPoO6>8mdWLzN$dwJWe7Tk{_OOjKQ0u `t?^XxhVOtnv`^JYkZaT+737 +z4FvGs&*8<@-eJ<(ilW=QbD`XNiyR!{GWplWE7=837xy~t0*z17N?r-nTcC^RH{9~h +zcWo%cJ|2MQVS5{m9w~Qj69qg$bm2jaV;ZHLU`}ndp>^J!oB<2+(~9cVsGPQuKOO6U +z&=17`3L}B{@)Z^QGWaG7y5}lrhR~|OtEDtqChtpJv9hw#+i}=!q;8$TQ3W~9R?DB1 +zcfk>nIqwq~d!_G*4~tB9^t@5~zD9*T`Il9cB+7>4e;ziCl;sE?Sxqpmgig4NgqGv& +zqN1MWHP?G2QJ-gp8N0JcC1UILYUNLh`Ap-}Ls(-D1BZK+)`JgxP(y07wM7X?$oVpE_BgLcgG^z?` +z{x?FwR^^!B4{@BcoHWcf?FY>3y{%_e8WzoQq}q{>gM<~40a6HhHyisHHHrBI?=xZGjB>=~*d8{z3B<8<_^rh1nJ@3|d6 +zcis{~+ZZSGTuC0;6Ef+QS&>6hs9GVg4Su({jB5w2Knl56RH9}&JU#>tTuJMjg9 +z7JQZ`iWn^!e9upqsjms{(@Y89jNfH81@-XDj0Df$ +zrBqo6SPynF2-r)3!HZT9^;l5ev(=#D^{mT~mLog?Abm@+M_(749cz8daajlR5AVb= +z%l5(&6d%^(i_Q%<6zw5*dwXeq=B`TwRvED8@3iN|;@z!A;LjLYMY%2KJ|*y*e!C37 +zS%7A}Rv!Q{BdU=0Q6yPj^gLr|24^lEeHtR0ec4L9)k|lzAv(az5wE +zL>)FU2=ZgTZWV>zPSYX(V?h%?jmTsRyjbeU1cfqSX|)YpOtB?(IUaq4izV8EYjv$Q +z$6nIOr6Npv25-JDOQ>Rgr(3GB&UyE*9heg55^UQ7P_6p|0viYVZmG`cJg!=2 +z_^<-485}NZKNYtaF!cFqR=qFh*N>2jCt?X=-2N%%Sc8H+c3icGv;}mTZl96IXZdl@ +zZn3f~8!v$8%ZJBcF!g9=@YgA%j8xow3JZBtIHUg?z4RSR{J3n28*6USFGifpdSGGG +zQ8X}-+?X*UF|SjW#FjX4!8waLrXWRjb$1rLt4!{C18!y0HHU;$&L5jHQ$Lbpj5HMb +zlcj$%-E+IY#S7zc4^g?^%9tj6O9W)eYAqFKtKyov^5k6Ilkb(15I5`MdktrZ2Ac7Z +zUhbhK+@xnW036hIZqS$bwV;}8hNlZq2r?^;#8`x$R0lWCzYjhe?{U}e%v{EU42AfD +z5GoNa8X1bFKic4 +zwGaX~1N{bLJ==rfhh&QO@}O$CkA|Te74h>t@pn5Tz@{vSshQu$mO90K&5&nyv4fT8 +zP+;ZpqV+XolK=vSyUvqj{%&+^SA@}+^J+lpLHZZbfs-5x)%uGqK$Y_S=7ntnfY)R^ +zkp7^i_EZ}$-&M7byHvmjO)STOsd)DD^I4G!1gUS&E2h3T&AXpMkY+12Z+yh8;rgiO +z+u4W(NBYvY+$DQU0qZaWLVsMly;BNC;FVgAb_~Nui{j(l#r!{kBuX(p;G8m$;v9P5 +zue~oitFLT)k09{BDf_JcQGq*w{Y@kP-R1yj)&@JTmC##klaEGUhH;39cqavlj3k;m +z&1@$_5iFHi=M}IuzZNds+$7`6Vay|Mo>BDWk6>d>ANMcFE6tb<3zS(au&eu!C)8zQ +zcmXl#d2jYc_dsgu@>8_v_U_Cs>QZFwtAkd)h1{MQlIr%2Uh3(M1!cJ|?Jj$*y4%0X +zgdQ&$IA{}L@*kNb*W@febuJ9HmfQa!)<(RjVp!`DkJV%;U_PgVnknv`hv3dK +zc(RT1QDCcvEGPC$6BLHlO441zW~b%gGoUUvf0xV539@hD1<%_3Z(mCrw+0N9*=U>> +zK)h*?NeBawqJiG>IjTg5qWy>xgnYs;7tnL}9;4b{CNQKZQOOW^@190&AKZ6vCy!ku +zvSN3<;L$oR8ZEq83tH7Em9Y;7x1V(l%jo2 +z$S{53Cxnt68r8-Zc5+e5{Us~+pmcd>BkoY#Z9ips-{WVUuTshTiFxj=Jm(8*5$;dB +z5?vjC%|-9`ACUi9Xl^K@JwV&I#+r*(=uZ#;Lwoc24e=X6ABa@B4$QnUOR}j>x?!Vy;Uf6Mu_FHvzpG0y`ZN3n4-?9p~Y2{{NC~^uHMPB;` +zp8lCIkl%&8{Kh&?oTLlWT?{23`JBFoaXI^94hscrJf^OE|K!|_m>ceYTdyNq0=hsH +z2}!HY^`rxg*W`{om}NNE-57L~*whyglqWsq03avPdTpKoiFh6pVWdvUxW!Qnw(ilR|WVX-z+?ov-!u7<*3Rz8vSmc^zE(9>mGxhZ44h_yH +zre8Y`t?t{lcw;bG-dpD~QsO-UeQFLpwvnUFuJ|HUesZgiV6RNpA&Xr2Iyi?2cbi%W +zH*c8Je=MVkHh?K+xNm-+-FE|dJQ5$^i)kf?uI%v|avN-L>#npNOY?1%iLNO%jdnEo +zF@hnXfh%!CLXyFpsSPI6jj3^AKKZPd+{L_{mAT=?bwqCKaYmzU1e_9lUQx4;df+>h +zgC3QhbSZ=#7&!G|fYIagAnK`23e8ud#8!RXJe0~xy!wyHU>$iI{^1Ee@&=w-kRW@> +zPjs5JD5G?@srstUTPI6yC4NUjL88 +zPi>5QAr`4G!`7(5SvUcsBq+cGzntjuR7dzrNdz0{j=>WM8Sf#OtlcWx%5K;QYx4Z) +zCLB$2L1i-d*r3Jr=`L-^1IovfN%C@Ez1V(= +zRB)2A7UUzm4lu9ei%crX4oLd-uHz)Y&wgQ;eB&D8}G +z#l!gMFhmiQ6e-!vR^5&*Bcc#$p4sd=9%7MNNQ^d_*Y3rDQ=KaxYFgB?U`!ZD`{Dyn +zlgj1FIQ^jOJSO?5>eJ5>x;ze>SP&cO;(XhxYd@@xzJ^(_mkR{}^vKZFm|}nWNZcfY +z4MIZNBm)dt47%y)yeutY8M)s&~ebKpXKEY%Ejo< +zZNjC7Qw@8We)BUdkOTnRs)5ETx1N6QjvT}dTZ+Wag}Xh&oRAdGpLxWq{e3#;MAPIR +z8g6)F^WTH5RY(3A^=A?2CJQ-1MEKG(M08+gV~kwJ>~rYG8J=ll +z;k6d#>mzUc!^M?H2FIM<2} +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 +za6!FwgBLERiM_dLk62s2!VK2gTF%! +zEX^V-bY1YkowV$D#ssj7ns*b&lVEz|V|xM?PeBCH9XAiahm0cg@+i!78xSGgMBlZ?{T8nA<~;MJR2Q#_xoAxJV|a +z#m^luoz%#E)xxaLKsL;T`*MMYwk5Ei3&7#Yj_X8(rQP&^6s@@hkHL)|ELTQQ#wAFS +z9qXY;USkbLLxA>;)ndw2?)g%FA=at)_kAZ!5jN)IX3|JPIbFR`Vhivt_h=RdUa`L# +zckYjhcH%hdEyj%M*WnkI_rG7SDeDem^4RH?FzV&d{%q#=dKTAy5ej__r>p`iXd>Zg +zXCsHBJ*Cd813dD+aJMh0Es)hmj{FeDas?4)cfkEH8J8;5CBNp{_Fi!8q2>7c&DJlN +z&_4C24_ALeIWdaTqqd7c6`y6)Gl@-`(q#3D-?7Z9zl@7q6X;+P+MuRf$f3 +z34m}<3m%qPwIbhkIu;w-E7wc^IVc1-y4)K|Z!1&;m|WusTA%GZ%uR46K(p?QEw#gL +zzWysyh7Whni`WR}+;rJD7A;5^BHbYo-FEoA-~eg#rGyYG%p+5wZ-E&43Ar(4};J7tcwUaJu_cOrmtP0LeQ6mme8+#2* +zQ&yhfnj?Y*`)s*tg=HU}Pd)Hf-bu>$c3O76VlN9fEeQ;M&~=O@`+N*}@d-b!ekS_a +zR`B0sO|wM7+(^VQIwLmR3jXWyaEhTL++-DoY#+AGKiJ@0<@FQu#SqG*OKISy(-!7|sO1ZB+R6C~`g;`#q)IFUa7`kKo*_bGBNqWFu{;s68Y*xKg~YElJk +zPZ~}Hf(tdb5q1Ki!M%(M7{j8ZF`ztYe}49LjvIa!UYmzISu3Uzhz!GIR}A-wtzlbK +zNX)6yN;q)SvN%Z4M%>thyJctyyK}INiG?}dSaxsHB4wnnOgI$Afj6H;+ZL%#hGiq& +zZIb{tuWyBg{516`OYMl_0E;fXqykwUP4CLgdm9EYPu%0sTQ0$|Ucmv$D0%6Dy6 +zP2u)W?r3IOzMk>)1^}hFf^F`YePH!-D;*_F%kc^Z4ZkjLAvQq(TrY(D=2kxEyWeqd +z_#Y1q*JQJWoAP0qw1%Wo^X1*&l!5$^mzzo&-zwzwKxI+?xFP3$=m1Pr>X+qe14?%6 +z)IMb!U02)qmTdE%&c=0UJw}p3zyD(`hw%oO*@WmJm{YEnL-!$`m4^I2a@-4jYn)yp~iI&vO6Xw!?vFY0Qk$fZfu+8aa+RK*h9%jqx# +z`YGFo9x^;XU7a1m@1$JXKEdk^e_P~i(W$=wa;p^Tvp)Xbw6VWkrBsF1vCka99T}cV +zZ>Mk{6Nb&3GLFBUx?V^_c%x)f90uCSu=B$Jsr>pj|A~F>R?T&#`m!3J!|0jtzeLE6 +zr2dRLgg2gd-#Z#mW~PjW07U}uzXhoFjkIu0)M`yN8i}}>rw2J2qM#XNlYp&=gbNSqA3B14v=k0nyIX@u;hZ^AF&gaD +zHw+?5Oovr6%~D1RPEAL9wPwsGuwZdSPuDO7H6G!L`9buq;L5`mdVCcOGS!90`xH#E +zuD%;6GANKzFvfK(=7JeZkcYGLf||bU2CgWiqzZAz8=5PWII&3e5x?Nxhzk`Z7?aW_ +zo8p1}!~LFy-yl#G<8g^CgS>^~Ft${6mKZLn +z+>GS_%UO;zs-u$fOY0|+*O#UeOBF=$(#nb5=4TnJqT4pTeRf-!`nv@EL)8isq$I(JR +zIC6mSzU~~dcEF%^vzbYWQ7wn95inRbHR=ZaTkdkFGciMi{Om0W;(C(K-H~$vvXMTZ +zbeF00A@wR6TfS$m)QfZWR5I`d_Y(bkq(7SsM;OcVWwUEe*US&8D!w><-ii(H66v~< +z6q==;zn+#{+G7>r6|%QKYwxd>#gu3bTroIuj^i93YzLKCW5E)XpiP{}L +zdv`wQYC|QEE2xn{6u`(+=!&Tiul}>U-)BD+>OtpQ +zklCO_S(R?bztF7OS8jPfq5oD=Mh*8OB{V5jQIOblHMmlGFvwvY7T}72Yc5=!53R3a +z85vOGulQF2?qI>rJs@Z!9H<>}5z=j;X^{fe7LcEful)!$g7HpBpC;csKLU@dfCI_= +zypT5tYy%9JpaYPUp6;yEA5=}@ti-zFSl_!Hwa97LLZ`<#1HWAS&nuAfYss@GvVj*V +zM27d~dXSNU^V;Ha1SwTVcdPwMW+>rtRLIkIhq?<2xi)gEPEt3YGi<5jI@!5}w=HRf +zXu(-*?(15uuGhjebO25y)e=As9&3l4 +z-mxfAFo8ii7OHp)+hCUFF$785CCn==>}>@*e|yi?w&9Bl_s7Br`t4SMshzHiHq +z>l3ol^xeW#yIcv}O@~)Y=6xA{n!Zs9%rH{X!N_S}W8kBDTU=L*NViMDaHJ~@W3czivP+ktC)Yoo^F~jyE#Y+iMgEIjMQ$mwedH&-wPU1(%Drw!A)EmNW86 +zCEeXRc+@M0jS>pA~`++Liod#-7aEa0>K +zwviA!*PYu?>U+8O4XFO{%xCw|)4896Ut!U+0Fgq`RumF)247~2cu +z+X|VZOjmx4w5t!_HJ$vqxPe*04~88h{VeHAILNDUm|H$}+lT2m>_Qu*7Zb;w=40JB +zydTwqpbxl^b(W7GBes%~e)K@o+_342+vj;RW +zT8s+cycF69p^@-T#J#(e*{>5D|1B7|KP!HbEW%!ZkZWfh +zt7IhAAqv4uHIDDJipD+r?$nowL0;ZrHOE$Q=Dbg8SU(BU?~0z2dzRLF8)MwOwcxBw +zLM&cifhlT}h2pQ+Yzqis#w>nar^T0oG*A+-n+uFypbCjH#H#G*RKlJNqm@SL|Eu|0 +zp~suNPiKEAj3WOtyR}qa{0K~#5TqJDwU_PEhfaxMI+lZ>N-(9xggZLbl68>=c7rLPsrF>}W;GJYO$w;~lgB>%#} +z>oO7El1Q|E=a~(5C0XGpt3cjMGYRoRn?#lM%OT?Ly|^R_(Q}QXW_?5s-v)0rD5TC8 +zVG7iJIZ4_;Cp?vKV?Oc+f?;bVm90>Qc^ +zFz*>$1zOq;T8t4r4Rk^|6#ng}vi*I_U~lbNU1DSE$25?~keppqYb#fSQIO_UC)wa= +zN=`CY*TiXhTLx^r&a5A;U0+js)`{ +zd5kQ*cw0-b^{|^hfkqVWutQ0skD-_Mh|VWtibu=ob)LqOa(|3_kPyTOc|_VK8qw=D +zNb4H$SfMYXn3{+_bn8*xB!jj;jbx0kV<+pfB7G93u)pLd>xQNK92IR_IWvY)F}wxx +zz}gWn!YH(e$IN^h*q9Br?@cuh?~VXOlR>#(rcVZUk;W&Z!);6S#6h`W9A3*8yCCNg +zb|O(l-nS22&i=`l3tq*<5(u$Q(NrAyrrK)-O1r+U$k_canAJo0Zsl7l`i19ONqc>l +zR}qh{2&WntytSyh_l2`%MJJ{|>ZEvrIvZ>uL>^e_o@e8Cc!leQF!tDG-7cMhC&naY +zvqZ&v-+9RkVN#7(bqsQPV*@m6J$W=5XDykQb?USHM&X`Nz>qBD8=gTIu!FloVVk&K +zBeq~NfiSXe=Eo?y5N8M#h+W~85oYWyR@NhCPd)d2zYE6~>N`KUnj1;m7RLM1mF0b& +z_i1w&l4mbpnHx~E??n_K95nq%D&kq!v6|nwml(%JfUIzY$Rs7m80*cgd(X_#f11gU +zdU4Y#LX;stNAxv%vf8D{!C667}3|Ku*26}PLP)RwWbIg +zAAjXvu661D1UP3PAjN3vR$yw-`k}lo`?v~LliBQjD{v?+4qT}SK`gl70{=Bv#{eqv +zQ2=p_8>&yy6t`e<(WFX +zG7^>3ZEPCOgdQGg-rif&ecA4XudOlxSBAW#)bUFD +zaJrh*aB6Zps9m71UPdlC4yHQc5izrhNdD|R +zx-9YV8*#r9PB6ndEI%sAP3|1Zr&#tx4Ig+BBvjrV!c05Z_8j{tVy$krFT|TfO00Yi +zn?=xq+Mf}8RTIeS)L$DuyP%oV?E-mB^Zd9u9~hG&qR8@`Jj8xbhyIwMTekxf8)781 +zB!OJN-VXxvcn6)6wS_Z7x9&V>MAdjMA^uV(1V_REHrY%mtOV_5+{!VbtxiOGBcQ +zo@;-rz2HQ`T->}=ll{XcVv|((3PsZkWYQ&xY$&xQn@Uj%=8+cwL1tiT{fC5yAjart6)nD8q-sq7kl9S7ZJ4>!CRe=}01 +z{D(C0Fc65q*c%kL3UQjuAlhK*mQ9XDr!^Km7FKBG3ZQ{7dGBm%AaI#aaTqg7ju}n^ +z9@W+M{0W;r<=??ie*zIX=vB;FMr?PBd?xJI6k?q?=0OnvwPw3!bp{zkD9kBt@Sw@L +zG=r@S7vgx)`K#;$Gm8G=6(xq3P0LuypmZ5b`O{h46;`GYru2&YYKem0Ai&?n4zFSM=Up9073`3CM%1ptL_6 +z>6+w~B<^ISVQA^2IOp$Ui_Vytc@(f{#S|q**0i(x#M`J~VmmXh_`hUAJ;N#=EP|ds +z!5Td&wPqdKgxu1(=l6#Ju;>Amcl>HOszzt^bRl^&RN1W<9C +z?$;W5KKwP#@1%BP(F+nfnNbpgs1r8Y+QF%{hdYFzm5I_Md5@6tx~H;1K`D%DJ}IJq +z{=1Zd=@=4D@RJOwSn|r}>Y3Or*A-aw$YvN@*Z}(6Z90^d$YMq~ybHOOK>*$W*l~*k +zA2Leazx7G3ic$+xADnP(%a8Tw&yTwgp9Sul@=68laW4BE$ +zwpL%{(NwH&wIdl@*f0#haFusSc5RQH;(NGOeg>2j+}0?d*A|5;*{{sT?*mvF4~*k{#7q&=51G`!PT8=3QCuZ3cs +zX*mw>`f88FmSOHm*>_98FD6nCsyvxmFqQCFsGSRnRrfPQ_5oWmMFa2B>8-;-gkXDQ +z5kVeja7 +zxw)8l?Ox@;@Bq=pX#{QPe_{HWqS +zoJ1^=b4*SpF2)%Lg&&+jw3i!bI}o30uT}8JfH$er{K#q~z;5Pbj7c#N>rZWEzb5R0 +z_8?iOyXLA%b=y}#p8^@crFpCkEj)}$3)62NQ*RWV_g(W$ +zLfuoG9W90<;$aPc-e)vHnCNH4tj*XxVIGwLUS@RMUmtH!u>D4pweIlKx+;sz>AHw-lTcVW1YLQ%Usz}z>v5&JP0nJbT=+P1ILFaA0;pX)9n!Zx@eoCrf#M*&#o +z&y42f4S{~{AYbV)(vq;W+#P3tb6tQF5(FLTYsQ77^cKA%JktsM1iIF~qhau6`Qsm% +zBLOCag4tZRuJqL-{2dXAVZ#=KE6h{yOJ0q{ox;h5K)!tdLqNR0^o|17b0I}_5ZO=@ +zZ6W&&EX4c&VaXXyn#A`OL+yFR%iwZKz6i!MPl%I$fNA`0DvY5FfCHdT*Gy;DLj#2q +zuY6mLt(0ipG?Yz5>YLR)CbD`Z&P%OZZ|;t1%T?aBntG&Zk-o!U5<>9DLIhaocE2`s +z{Nf_}OZ|0G%a^dVv~-?jWcW|7@_9vxOq6GvW;BIC`kl>bTUeb1zHe9WI@(58;XOR+ +z!EOKfoyL^$5xBzS5q`lMdM~djz(f$I-hvho1ox}wY^QIjUr9=8lKA|mep2tq5~`oG +zB|DKi!^fg1wtIbw0m56JBTHFwAj0~Mm6%Iy=wmmmWVBQCyJshv)whGHfPIg% +zrK!9%3vBrArI+!|5rIYdwDat6Uc3Lb#!Gcd`rZsa-jG68Vz7ADYVSxU0Dp!m>G +zh=2U5w8R@DlEZk%<~qhyvj+`x)+D=eWKq94;i&PPTceL8B +z2sRb+GG{H|*_{P~(c74IeKb>UB~Xcx`4#X41lar+k)`=?&7YMP=%^0W6YyyFVeVFU7XTMX|-9E#4d$uBI)Cv0L +zaf#xM2G-2>{TAV)I?#`5e<5igdN*XdKJaFbj!?;Jmj;*#Cix$gC=aW8pYp^rhh1$( +zv3@lZ+dEJE#7*edf8G#Y)#y8`urA?)wOQ}r5#FN|;f2tLMwjuMQKoviCEg$T{6}BKPpq+k#o +zO_}z_(4vrN(i7^dy{FgAA3XT-pB +z@M0`KMz;(UCJ_oPPM8nH3nL@ELu&S694Qfo39V$O@eVycD0Ic_Qu(|U4-Dcdj@1_k +zY`siiG17uCP3*c9Dn5-dY02XV!=BIuP}b`l4lrb-VQD{HxT!8Y8|Kp!dTO(_oS6@= +z*DL&RJg4G+yoGx?br}kR(BMh0O{JRJaHsk8OhSw^``Y;e1>)?GRyI6%>UM*_H8==k +ztOnCp115hYT9~rZ;&sG5mM^#d$4PeWL+QbS8wCx_%GTLC41JM|7{<3)w9bCAM*#>T +z&3lH(MhyDqUAUR(#tnF<)2Q&Gk!{Ij5KU3C%Vnt@3Z4^I$))HSsJ}#@NZttuF7E1e +z2Q|jhaQpkkbUg=b>$Wi3J}IkAz1*=Mk)xXF1+NMiPeYNta!nKln#(1J9G*{9*`|Y`oaU>Ouk?i^-_U+$I5O43o +zwDWs|dfUry1AHhCFu_y(VF!s?j19|x;>ez2{|oThJJxy7Bq+i38<9z4mlFe2=1y`K +z1fTrB^i}I1neKg$9_8qdddWTX&Ycpu)mifj`r%wR%@h%|r!`GK2A#haH*h=R%!IAh +zST506?rPu>ot0=If85Tf!rBcoa(UL{%a>aJmw<#YMkkJ{C#79w&H0@ZY7VbyVN`=tpSRIo-vZqHO4)s1po +z$K5s&=Ies~v%U0^JQ$nEJ$>k!3)qK<7H0S7`|zH<6WV@8R@%^-M!1)b8F|_)_b&j) +z`GggiEYQx^W=7PdC}=^~$k60JaewgV9Erea_+QY>uOy=AX$AhON^D6m=sG#ye@6Do{$FGx@`voFe6Nx_(CLBT2mPkG6T5l= +zun?!ReP@>dTFX3Lkk!S!ifKWuVW>`2_BKsxkb~zL(24IBJF!r~$m^pi>j|Vth?7O4Krv*pr#HmAAV_uj +zF?Oq>Dj?cL`s^7+D<-g0H`IFU&J9=KLXgchs`OaFu2}8aW+^Nk)YEj2DK(P~B{-$M +zSJs@*#W~Xts^OedsW2x+hq4WybS!towwS!%5T-_% +z6lfZIASNu~zR`-+``<l@$A +z9HydMn;!PaOVFhejvrdGy!tvu=WMAbUk|;`W()N@;)-G5A^*xRL8@xDN8j(NT&7C +z1ubJ0P3p1yA|s}(imj%20QeCIOVtYUlE+&GDO)-KqTMF?oP5tBnA(nqR&PvtY5~&c +z?d2)^Bo+(1S#za*%s$nOBCF(S;-X`bJ68-wVd@5<6()I +zSGs(xqCvcj%z0&CTnkT}o*69O&;L?k##zN;*;oQZWK;I9T{rsVQBuDFtY!2xQyRgB +zmHorjVlRe9gEH>x^uiwN*JyR{H1M&y{$j5e?_G$kb!@{@$a#85DL@LB=iR#lw6a36 +zJ0`1mv|Lgm&Atw|{mkBCz16nKe(THp+m-C8N`QYH+t;9AfP#_!saW+dtq@RAgzB-F +zHOXLahoje4bZAJfe?R)sZMP*_h`TB=uJEiOlc6z3IgxVIGg896wc%ueP5M`{Y|!G6 +zh1en6Nkr5`B�b?g&HRKvj0K1tXh$alrg^SoK< +zqU75MKYo2Dt7i!xRn8FdS>?V0f!rlJ6$hL{1O2&5k?v4R^8^ds&Ckgy(Lh37U}|OJ +z@kXAk@xkN}=MNs0FMHA0O*}dgz)#;T^Jy1RwV$wAwJ-gj1xEP?A?JP^Zc$ZEY0AAJvJ($Bb_ +zpn}I1K3~zjmt{_|eo$V)(=gjWewSQGhoJ34st&6ggS35joOWM2o{F2d+Vt%kyphM^ +zDpQfpKkkgiSk^SYDBlLVB>8g(9?pZpI27GH;HxaP73w#qrD{YFMij&4LPfdsL^Odq#9o|Ueb0c`r~taKy26p61)4X{ +z3ZWKHtUEpvXMrg1q(}hG9Bv`Ho7C`zvxDc6%RE=VtBie=nmt3-H5c9;2DNcIW#&9BT@}_15zJ;p&G0DTwN7Gule-zU +z38jYafK9X$1_bjscgDvFKodZ{xi_Za8_^Z^a_jK&&IaJNWJa5ceKvX{VMhvM`I*o^tC8f~Py=iu4f<$t#xn9X1g3R6`m?N$RRqORP`e2_(gQt8|4n_^^D}hp#^0FZKl1uDaRLSFb4G)vjmM;&X$d +zdB2=BZF|aEN)!ozJi92#MsNTqLoz~T{`jHimIZvZp0dxKmlZF(XtKLUe@&_VKmjxh +zqVqm5__#c_01`UM44$erIMwn1e7kb8l>u^$&ZWjqIrptfpF>GrbwVW?B+;MrAxox3 +zMp*B8lxM`YH3OnPm-?(KGpZEco)djiI8)i4E@{9Vl%D}9IsiVV*a$EUkssE;rcdBz +zkY?&NZ1QYI-aF~GWvoJNvEPMUR^_8CWDWQ<^a}nCS{d5Ippf*TZr{y$^a&snRYDSFu{U`s&3dYim +z$?fkooApe9-QQUux}1EGOM%4?)`CO*=p`fW&}1O;E+bQnd#IycYxuG7QH$AY9V +zlghL-*85f*)UEz(h%4{P91RmLeNXD3tT@2NR9 +z*@a|>f#knmzQFCGaas>hE(Yu$2fCqA{G1grJJS)u{tb?0hw9^l;{1ckkn`MpH~xha(d#2eiRZ3IYD!{RFkTWT|;g +z#wd&p^^X!|;*8Duj!c)ZV9z)juY9GXkp7{=h?x{-dtA6ibBRu?E0(m^x5EO?{?mXl +zc{*SKK94~*yJ7)@T%b!d1F$}m4jRxuGLYBJT^KsLODIHfgAKQ>Z-(C40QiDQxT!Oq +zYw=13%q4Z-$B`f`i8J)gwBXW;K(i^2Fz>V3L^F|=;?W80KzqI#X4H)!vcEZDv@mun +z0fHl*4Q#X%$p01Kv6bMJfZ0#6u(H{e-;6}jtfZnL;7V}5u`{&hPokcZMoTT$i~7X)5^kr3FO9hlj?dXLjZe9{Cbn#q}av$o}CXV|W+6zm_5 +z=Ik2b@q8crF5Qz7V?#G++8Y{u7FlkTPD<@cSO%ApNBCOdMa&<`avR~gj4TKxZI_lT +zuBr@)QfuM~xD;s#2mvMgV24_!Y5pKGedWtM+N0KkGK)i9&`c3~AD|9(g1O)95W7)o +zY2#6#7X*`3c*#VQlU^g)>O`Y}h96W5u>aYTON!#~uF6Mi)yb*GQw@_h +zk4C2Md|?6#BFweJsDqNYzev&m?+=`|M}5$gg|w2KKeWNCv@3MJ>4*i85N;(+4R?o7I8u$u;R4~zw`kq6d<5+De(|8 +zvv|J6vGb5YYvn`xI8skxA!g#_tc4cDs{^cqJRI6n2lTtKiiKAJ|LPh4U{a~FK3l;*m%ph#+hg1aLK|L0vfP%6n +zuNIWdzYlSjkg^%!li)UYVaXU7EH^fi3&*| +zuf;dKKcWgE6diwn03&gFO-QV|IVOLuU81{-B1~#X=d&M9hx^?w5R7WnjAujmKlfPJ|}mMhIG2Y2l7sBy<2dCDi0Biw4ZlksL(J3w!#3*md@SdL%^m4 +z4DA}8IFqN6nP|&BWMBM`Vog^(s~B|6?G;42by?Gaa@X^S0vIM})DRcyUS+LP5A-oz +z`ORZhJ}v;>`~cbi*_flUdGrAZgBbp*2Byx%$jA{)`&KCFJseUar?=8i6mzh3IjZW8 +z`cxlYuc>&`i|CoQxozuvyA4TdDF}=@X`=2bf`rHlVF_GnHBa0rr&?CyTNiy&6(cmf +zkxu%1*x1|V+LNMjDMsg#&vGR+LM`gmsf!R$Usu!dN843F6UVj-s+N=Q70)Ru)7i~I +zj(1`6WN(-qDrzT$pcyOm-7D_GsIcOY==_1Rsq(mOjn^%qMJHvbYF>Hbr+S*QG1~D_ +zbKKhguOG4^Q!0eSlGH4EbaSI`WrM~y^(PAkS;$mL;Ez8|W_F})EPy{Jp}( +z@d?G^EzCo}EPnZ?}U30+8TCCQcaRsIt3BobqHB`WkQgy +zO-%jZ8)o!qAm;PkXhswp>9ZyC@TPEwMnpgGo>l~lEDxG11@MPG-(~6@x2##U9B7i& +z31FoHEdN$|b)CeJeFr#?|4m4Ck&C{?Xo9ghv!;%Ys6WlHs;u}w?i_NojeY~qRGdx) +zOp&=|jTg)(u-l>S5FJa0k^U#LH2PW#lE-mPG(1!tG^;aF?jZV+fy7J@(}<9JFsY9?g+_Y&XT0qQgYQAJ)=h0INd^z^OUDg%b*jdDD2B;X7BTVemrk}(!wf> +zRSN5+6xWrAX_YhC(n`KQ4Upefs%~P28^d0E_5Ax5kgkedRc{{j72nf$lKF~rll>7& +zFAW;u`^ZYk+lAYlTu5KZ1?w;!2mw}8fg2V0sf1)oPuU3>1i`8lk(uQS?SF2Kss(-T +zErYc460hBonPBn?Qy(-B|*?J1KX_+z_ud2 +z9l||fxFk**w(_G5Te{r67a#o8c1GP5_tIct9oVK?%I!eT4Ym}d7?5sEl`R0`VY}9J +z(^BT(paR!rM7f6oY7J5cvyEkZlH64qWkM=gknhmxACSUG`rsrEHkE*ALrLqbrzxr4 +z6=Nv766be~Pq0+e{afofklws{GfR4=GAdlfc-e^^aDD9DhoHHk*mndLrNC_6Ja6Sl +zU5&UgE!cz@nDq8xS$KEO$cKpg(!=l=sr2h;%%*}|1NV97bR$Snv(Lz3R*R=iN|Ti4 +z&^!@9zJYg6F{6b}hPZXZ0v+dae#)c2iLaXsfb!|==7w;v>=4$-4S9{x4o%p*i$*jY +z+Jckbum8tjRA3OM5E6Tx&Tgi;+}UPvCe&Yglx!fJ&f9Ett2fNtHq*TY`VkTm>ahPxWV22| +zIhHea!IQZp0g^;GmO)xpaOP_KvFp;CLk|q}O`v_N8r8>AM%^(T +z$!2!lScLCpy0h~+t^PAg?k4*J%33)!1H2^!cOI@J5#h5zEyvO72al-_YTkgQ&#tz~ +zb2i#y$n3%WT8tnQYJuI37U!SVq|{xk8b0FecLqRy!;H$Ji62TMQE?`YqLa4&4 +zd&4~M6iGGo!|9wzQmywnynzEStAu%5c>d>E_apL0a06ZN28m&C^>{L`$#bd-zz*V5 +zhTxt^xTF!P?YDCKn3Nr+#*Cz1tdj=)dUG_+`MJxaV6KJDa=jv(D*lMxQrG +z$Y%1|wc~m=svYL2CwiwcRyyLf^c(}tMUE3^T39ggYUHKQU7VB|NFtCDA(=vo=RLr) +z(cq527bmGXOW4VoC(>WI&4-ia!FAXZaNz7|d|2h|5LpQmn}G)YBH7;xFU!hYpna$) +z}7xprwwso2iE`9aa?lZjOIBFeGkYAQO2E{ +zdQrLj99d&KD!w@QDHR(f|Ec6l0=d +zBejRJYFpu!$LDiWCx;n{xBfb};@3B@3c-2d45;w=FYFJ8swG}pUEDqiNyC>>p`5-$ +zzem5G)SeIw2{TaN5gDFqO6$@O(0O~0XA2r8LBiy3y;1U1hUXl{X}ym2g^N)u9zBCW +zHC1wn%8_7|H@?4j5w07Xk+wsUnqG?YN}v)5u*jcmao!Gk-rmuU9@c^G&V$*?iU1q46|_yuncU^uh(h119AjRhg{7pU{~< +z&38K&WTs1iyWHwY;Jo%r8-GzF{0EXFU;eoVnjg9hK}Rm6%s`5brZfSCuS;-@unrtQ +zLfohnnH$6aKQT@0>eBFoozYB3c<9dFGndfLeadd|2>G}3%7L=P7*aGrpiCD`K3M?% +z*}cPe5(n?et@@7-+?Rgao`o5kkW+wDO`q4rT>iuurhx8n;Axbw5|vHMFz+LBmT7ai +z2cbtIt*=*!Voy8ZkMz#LS^26)#;pMv8urSFpwmObU|8zJ8VRfv?5iONISK@*(Ao?Z +z2{tlJ-H%rS3NgE2Bv1VV2uNKOt_Cvf^{<}u-!(<0JZ~4(1<=OLdzoj)+owZZvaK-h +z^@7xnzjmEhX-rh6&HG@+z$rNDC|l784xkjU`yX5&{&+|ZxXMf`P;#RijqBtnzLxK8<+GFMGW-IP_pahewzk4 +zw{4DCqcMX_DdPS_Qc!f7S!~&bN(~>xbn5bv^hSL(;ifgle%QtJav~@~Rd5rfs?3dM +zKzyPG`UlUil1N0rWr%DS*Y!nU(k4IyP&3u#1*#{m+1#B{!h4;0Tgz!oj_Fy{m&*|8 +z-T27lY##Q*`CQxqX~!{ySwfud^-9q-r2ix(sFE6+vpQbr-40Ca<=}0yKM;3VD8lU| +z=LS@jgo(t#_YpkJ(6!~3){g}z_kAre +zJwO}}ehwTZV4orDPd@>7>BZAIs6esfLbsii^IsB65RG+ds?*{K9Hm7}u)WSHYgshC +zo3Br%?R_2jarw{ +z@d4tTu^xnX`1ZMERc3vCzJvitw`o6yVSOxV8J1*Z;%85EOU|8~5?XS=r?QXMu#Ve)g)Dvm~vmrD$5Kw@v +zP00%izb`JF0!eJM0vY+1!X0fSx?&A=6#t$zR@@k<&JvUMhX_x$rUHde4W|G>F$9I= +zp7lCV2uWiA1ro4fNa7jOe-UO|`H8cq|Te-PtqyoTH%Ad+>OwsGL@Cb!rKM +z_9BF{_i2c9UITU9Ru`1K9g{Rj6u$HhEP&J-xALzCNY1t)OgP+plQ`Kd*C8gLY{@9v +zyPhY?0TQvU8ujJ#)m_B|{?uzzRP7mXHmz}{TdOvW(`e~zD~sn;Tyt%+7+W5v@9WLT +zbeGya@x9_35Gr}UV0L-MnI3fCyrr=!RyiST(-`9CjlD`|4{n2~fn`P_pjrm4m0HSj +zqgjb&#O`;f?)t{QU8}>#_44{6z`?niU+7*xzS#@4%*;!!0gDZx5@>(X`wf@PBc@5exKkk-(bWi#053 +zWDnT5M5ha6%9GKH8Vu_wumK`9oJL!QBbq2|)b^bKF6tFzGM8PVpj$uGxIXVVAx=HE +zou_2nrtHgW1SFRu@j;cX2+rGFWGlSJb*o?lzP^u~*aKZ$w~b&Og-$e`m~afSG^eoT +zoGR>dYa)1xsrYUMjfOyn9-&W-7Ji~Rs7FhhbPC&6zIUkKZF{AeBX==4Pvy+QZTJO8aVg6oFys=Q$HZ+eX(NP +zhz-v8zLVfL-!7+v@(%Uj*S8*9*nH%(^!PB>Bji5y87Ed4<=vyzG*y=0=dq1T46)YNT}Q!7D6fJ9mq$fQp&J;4@0VDvdf|o&YsC*~{Vv&GaCT2t +zm5+X6pF4kOXdH@lWwS~%RShi7SrAdKE1v{K93{^IzZk^y=98C|{a17vO_z0a5|p}b +zrpc%3e4Tc~XHRUb5z-q$`=6JfLNl1Y$dFv$`o^vS_Ncjpvk_*m%TvHlN8LyhIUnJ+ +zzC^_M~sGp7{$ACRNiyEQML +zKZ@XD>ZBuYKd0Qtm$1Xu*;3VhitQ1#;x~R6_VH2yVlD!_1Lv(l;?7aq~4u`7i-wa2E(i1^#r#r?>IKD7UgSZ +zso_!2KrKX5jQ(g8jVj@(ah$Wkl@Iu>tFqO1tBJrPfez7E!9!Z%iMohp5Rnw0Ev7*` +zWIV-OQM?KRXzYOYvHwl;V^=L}{TlNF`~9K1gD#u^Bv*1PKgwZOF1_c;>PT+Oz0B1) +z#|^B?9^DnvA0sZnSZIAJAX|i6+UJQ07YCK$Ype}BndyE??R}()Ohd?CPT=V>-p11T +zK7ezw+HxFv({vzM!#P#V`yk}|N}ch#PnpPQsa>3#`r_oC_o21ube9;CM6U`J?bjT5 +zkk76NYYpC|ILkGu|2r6LO))dV=m{DzxIPB;XWyz +zm+)aH&ISvRV+4@Q3xrI2-HGjZdS8^wjX357x4J#YpB4=-I#`8~o)6I_Pv0o8<9b09 +z%=7JWYDT^kqJE>21RF;fzN@i@0Zm$y+jDbzOMZdN!&pPtEtGYE*?K2YM;PJNZ}Xwj +z^nBRV2CT1%bT`N1=__qkj#2iwRg`b*+9+wYxN2qh5N_=PFn!1Hr+LW>Rhjba6As^d +zHax+y%JI^Cm@y%!vD`phAd_yEn8ybst+(Mr^aFW&`^>?vPVA7DLy*h@GiyfwgaEbo +z^V-$X*_U&4(QMp4BO`kfq}Gsrr)F7IU3JnljW^oQP~S|lK*kg!N1rO1(jGEO{o$#X1!j2QbLJnp{trQ=^)gMRQt&VE +zAG}tTc8}1xt4RFfACV&MnrdR*a#`z?NYC(Y0#V()Vl3u;13GEw|Nd`g_%OIaB_j9O`P?Jksm;^6r!g +z`0+gyZKUUbITF)cS=fqGbK=mqolKNU6xYV0&AfG!=f$1tWJdn!Qf$EJUroZoVV7UJ +zg_G6i11jM+uzH5x^Ef8rZC{P3qmvli1gkG%Qu_`iUE#w4($EC!l%=h +zm#_ABe3iBEx4q?n(yRc@jL{ei>S}^gkDOF4 +zC>3bh2Z`nC=V;vn;jEAWtsQI9{L1{46gIi}sJKRPsT-}WoOd=R!jE!Gtae+tGBl!B +zK{oVN8V>XMi*#84Ig(ZX3k)OuQPjoV)JIjXy#StT?*vf=$bF0myjTr`SH!y}2tf=L +z=w4VfFGtVBz%U4cW8f~#;E2E!Ga-kBA}Be7XZ51SaS`mQ3*}||@pLTYR8~v0?}DM< +zlhDZ3*IIljn(w8jjcJ*OO-Y{QDiNZhlw4BZYkgG*ZBUiM-ZODbhptmZinGSJ$q<6p +zSN?4e1;DPilH~fHJ~nZc7@po8w4k#8>27_>^A8Pe7~_`2q)ki~V?`Dk=w51eCe8g> +zORLwz2 +zBvt`$pt399M~qW&T#5d1!`|i+m0LLWa91dMIabr#hx;BJCl?ocS*J0pUeZ}UcdS7P +z>O9k4QRqM1@3A>&B!g`Wc2r;U>|9U3hC{r;0GxY~DX{ +z;_g^}J6sxqQKxA2vKws><9M7D-ZCfBCnB(G=lgm$UNxJHaB_i_KvJy%h6ptMXc8&x +z*yuTLJF))LWdf^eBkjdTof{6CdXiS)4_6Zz{ub=v^UplL)hN7#DoFv>AL$@6MCrY`=iN=m8}CZRsgM+V +z+n(UQP@GaR&L9urWk;Xs*||8-K#apZ6}W4NDxR_dwLvclwAQAtG}_Ea&*YyBTTX9BP~&Di +z3@1$$O-3jnid951RAm&Y4EQol<%$&xU!*ZQtO#szeuwG0fw%cpcZs_WIQ)^z%^JL< +zfF|zRxw~I{B!^m&^9R1Yo=ePfl5HRXwOp`(4=OLs)M1<1O6EU<{8a%o;B6ez1@^XB +z{pjLQ1x(0n(qOvIhVe9Y$Z`U&@lHDPJVJ?zrkT*2;Lp1ewRj9ICb_THepj_Tu)NuR +z*`-pt=+U&$kKi+Ef3=59yQvyUF=t=hg0a6InEtdIB6}l4U)+wl +z?J#bz_1os8s3(IjSoOL4ShTN{Shx+R<=CyC{{Wa-0HZH@?pV1p8vD7^jclp$vzWsW +z3)MJEKjV;4R5E%pE~bGk8~BuKN3OiNbW9FiQFF_o*zwcXm;DW!M0s__04Qg& +z#KXbFeo(#bGkZmO>z&I^A1h-mY4S?~js=t9w})DtI`g_rGVLCdas#_;lTUqRL1`UJ +zho#!XiUer*%Y2H}ya9|vC-c$Wq-4bD&J<_5+S*8ZPlRECfL9-8y0a@4x=dR`_AP1w +z|3w}g1EoXzF1&!WU(qt;imH12eTcRU!6gD@!v0$!-o)m57l2`-(Ehjq0WNPXWN*%{ +z7RZmI+h2Psj14C}zJaJjnZJKnxZw-Qytt7*eA@_;QeE5lWWM~F{55##%S`Q>TIb5v +zAi&=3)Z+EEX6Cy8nbD0rf#NR@}!sZ3}b06*kf0xu)Yb3-{sRz0(DD(x>u(bft& +zm^)NYX5c!LUY%eD%j|;dRto&iS*osT3>B0(haLS!0glyZ<(G0I2`TEGR^1fxOme6 +zZu%5$Vg2rb4Sbh&$BD>$;*r7U6RobDyjwM>jhcMC9=7j`Rg2L9e*WbwExWG?n8H%2 +zgj7YfQ6yq91H@~Fq#zx1T{lV7ziJ=h08Jy06d*C1g* +z4M+%HZ#Q%vMHKA-T6~YjJ1!}euf-HDUOZp(&N0_p2#_Wy7R;aLDg19K8A=8LzTVX~ +z9MtntL@6@OGo{(9_|jk-gjiR@pkjsJZN0)f+zi#=hKVxI=T +zg}exi$zQ38?Zc}eYSS!^s=xO3>5M&I_neTHP4@_;ck-ltbxIzb!r%)yi$IOWkb1P~z*`A+0n +zwMhM3-P|1P)D*YH{W)3 +zO3yyR7!fxJ7RUW)HZ!i+sg-R5`Sv84+y{L6c3rNi?KYfN`Ob)>{#VbBA}YLOGZjI=1I3-)R#h+1@&ny9s^{?9>TW+_ddVR`g^kw1 +z0rywZKk*%A_qVu_FAS@EU*{c3hwfVn<2iD +z$2RL!*YPmu(Kvl$a_-6(NZiNKXFCb +zD>8TXxF;nyqNDNTpW0J|2a$$9(<~&fY{x3dI~}Wr8c=iz0pZ@X_o0NIp-VTfg}vpx +z|0tU+V^+@Gx}8EO{$I|MfnHbjxZjG5topE5EX>{^c`am{IQTQ;j+>B(=0pjSDiD^M +z5^lKd5eT}H|&KH +zQz}5Nu3>>At)%WLq=%uin1I7TIVmow(ig7t1?)k)y|Z7|TOjoZ<|=ano7iW&kFiE>_7cC2CAgb +zRrILpPKE3@GRT_x(w~DAhds-cqEgT?B=2$U)ymA#j!=o2ocgP>s5o8A3&Iu-#e159 +z1V1&lc#I19Z^_|Wk}|kJ@KXWKiFnuEPy`B$IM;Gu&*Q8vkL0lQ$&$Y$l60kbXcJ>$i2@`;f{#FAzXDO~$M +z8z!oOzi1omp@OEJ&J$W#3fvKepS#XCqf7Yd`7a;wI}xdJWkn@XR^Tj94wqzt`wM$A +zhqZoiR#4iC!->3$cQ*BF2PwMu<@*y;zau0%uH@mOjOacKiIpOqFtah#vw(Mz%)d8h +zZjrYe)0<_^e24q>h2l4e@{M&goa`GIFZVBwKz=$kYpscJBI>1y3pFi_*Bbg^LZxUE +z>s$)ULF5%wlP10ZfRXlx_j%p@iKQnq9cpITxZ~Thr7@Qbs*yPghr63Qng`u$G+NlG +zv)AyHrw%-k-ig=MlKz%yJvQtRLNqAi_+cHCLEM6#*^Vg*#HHce%jmU%>z7K}&=(9U +z@Ds$-Mw6tev&%xDfl`%?^cpi~VJ_w_zF)j(PNk++!GBL}Vo(6xuXn9ue2zJk$3(CM +zm}DRm2&+gFgmm|F66-);yLCxgkHtDUSMUq&Jn0 +zS7{B<4>nP?++~!w +zQ43`T>fZylrn#)Ab&{qL^8iE~LQiDnN96IDn!S4KwaAjZgfYKGO)!zPcycc=68#R4 +zuycT&OjX@fzob>!;)knR>k3hSxjO<7MNq?x5xC{`TTt8-2_`eW_%~G$tpt{U84#jL +z{-Y_J@!8x!=a9r9uem(+PK})z3~=RAXZq5pFI6ZT>kgkmWvVkNqmo}i{*8uvQwJJ%ZA}H;2Sa#o!(a!3ySKLXr&~e5;0F;p;y#jWq2&h*qu8<22P`qv2 +zbCNk1)|PKqsas^JZiYnq*(x1$z%?n_VI==O0da0bxKfwb4(ynRUCrpC)pW03`|JK#Izugso@AJIkY3+P +z&tf73fP1AiQ$?Zm#?1L1C;Aa}hFn&cy(fHiaIz +zIRw7N(!15tI!b|V75!?gfo9Hl2r~#5*FjpJUk2uI!o-Kq{t^!2kBZOv{S;GRJ1@NDc{d4xb +zrjb%su#h%0OMqbMasIkZ2oXSh(~~iy!pl_pvUaVG>dLBQKE&!l8#-(;g5Vgb0o#Cr +zv+`)P<$lD)muN2nNp}6l4n&^dn21Gi7Qf&uMdwrt+LQSUMqCzs +zBkE`H9D_sXT3k|LiO9CdWSHvGEBv@0ZMCv8B>Ru7OMKJGB&|)K%S3}ly&Tvt2PX+T +z2FCR@5sF1FM`~%Kp4nzX-{hF&?aYF1wU0QFBe~+M(8ivr)3pb4`qOqUw-^oyB~e0x +z^#ru(<=18#@^dCH@pd39{?x<(>!A)Z*PbJ1Ot>#29@Z5?zCo=<^6I7cYobd!fj=e_nQoTf +zkykrcRG1V!Zj+FF*N$e?!R;JZNIZL(GabrJwo_E1&C11JZO`tpy>R(GwVw@NYC~&z +zR{PH(-)J9#e8YpUw1&sHvUMGF)ZW!%&)Gsz(O`p+f;_ac)j@6B7u*iN(h8BNm1%+q +z(rU2n!MFjDZ-?l7ibs^U`>WMkRTySExt;giaKWM($I>OM?GpC`DF2hmQXt-XxS@3r +zFLcrwa)00MH(8SSw0vOH;bKTNT@_&9kB}mr+W;X~z>ZoLu`Y3VUO;|Z5MF^UTr(B@ +z7}4f8c@~o-_yv3#)NXO@F74)ya?o`=MM~tCiD<1DJL5eRYT~d~bTBE=yDP+0x$+ +z8#M=QdEWSpT|7A35JtB4v=gMZOC7bBW7JJl?qJ+H{k%a1xqs88pg2{J5DKPK6P`wh +z79v43K`WiQlB;}-f1PU9ZqDm18l$|ER;MBd27$f| +zCpQzhE0@MEzhOOf{|L@p;?b +zDoRB=1a6l6ib)qGz!FX~6fT^h8A0_t`CQ!jq(0>ROTWM;!!VZg#30q|4yhQk{*k)+ +z&-}9=kFl4i8`mkFlC#Rh41$`W@}jXN!FsudJfYUmdx}h;($GRO6J#_54}vj>QeVW< +zn1}`Yovp23i5`oiCjn%@9e&QO;{O=uCJZHB<_dAaRXS@`SD{Jf=Ig^eX)@b +zYcpXeZT>tdHdElUK;j53ZM8XcfBn`?Ja!_m)2;lx +z)kVUs-U0!rHk*MXqNt~nUdK$1Q1PS4h&-5n?bbFt6Yctk=ZCXrB~&xwL^(``dC%Y0 +zNPf#LSsI#M12vkdDyjB*lVp{@_1c2yZ6dSw;d`4`mW62~;tn1`QsACB0e-b`thA#L +zjxm?mSVvpOsp*PxjQT-gdhvDLvIyi_S9yx_4M_1hCN3_+PX262>`S2h#VpMQ*^65J +zLGv6Oiwh~lphuC;99uq#vC58dP{xpFI;`pBAKeI44rozSq`H!YRijn5Ad$Zy5#?MQ +zN+s@vR|&i9w*3_&uMWs%BcnaSwl~y#lku?rZPi22Q#KCoT*urHhlH^e350GOj +zYj|#>USlTaz*QOlQSzk>(m*Q#dMiqZ@Dd*Tu}Hh+kPDjJ(Z7zjZH-PFzNK(%S^yKK +zr4-q7AyyS53gItNa)tll7(5UJJA0IgYvJq|cj09AQ=m%|8mRt~P*fY7TCqt9DP`-7QJ0XRw=Zi2SoIBqx<(Uyqm5(dcy}7Am;)rITfIGsZt3d=11$v0)w&C8 +zyJvf(bd5i_neUTyJuxW^j2W#fV%CQ6zt|@_Y|Lo_i!kCCLL~UR53a!K=PPOk(R{$0+o$@gK>B +zn824Z9yMxQ7{-Ollbbk0(pkHbzzA8qiE4v785@3n^yEB*i}6TEz8x@VqzA$1`!~f2 +zgluxiftol7TYBX{%rTE1Fs8v;Lxnmz%;b9O&t<)ieL>RixN|Jr&On2ubKP?DD#FZk +z+NRcFcz2~{%)UL(7R6?ikg*KA=m>eCFZ-!90oi2JAYwgq9Gne>nDuC^0k~VH(-0e_ +zW}$|yyTsa5P=`K_9w#PdIi1tCOr}J>p5}f-%)SDlP@}Mls;KQr3UPjh?1AZe955JQ +zz9K%Lt9yh_$VOAu8*g*BYbfpP?4{VV{k}t%Xixb{5A33|&XNk+_nbR%K_&q(#9Xh@ +z2Al|h3qckGxtxn_^jVFok5g$JH67x3tl~#3gcsl2~07{_^vJn1KkUK5$P=RWiItu%jGumH6 +z)ix5nP}mwJ2F|kU1^Cm4j8!8MU_EQIg*Pz6ShJ*pB=vl0Qec>uRc}<`Zo;b!j(ju$ +z`R?-ov1%OeZqs}(g1H>kBvTok2w;=1)D{v>R)7@{u*@N1)rAspM~}WcL>i3PaYHND +zZ=q)BvFG_pq>v1=c#(R?{;J=9WoQn8m*#K?6$(vp978V8U+jGxP^Z8ge3(P&ldghC +zIFZ!c;??zDIOqjpw!6OQ*Hi+pk?$jPtL%WH=2=@faq|V0=29jzxG&}}M}l}sh&j<4 +zFWc>t6vy3MDUsm&=vUQ=2Pf%`7StZjw!M!rJBadA@MXuXOFIzR_uc?d@Q|I!V?i+- +z;3T%;C2K|X`<+{H?B6%NH5#IyLZ3j3mGGJPCc807&x_0|HmMfaFf00yD@(ei^G!=#wAj;@JxfLXg4u+)k5%YRvUnx +zo5%=NR=pqzs#t!!s&;~&i0&m9Z1U)hTL4F61`=7C21BElfY +zC=IxQ11AhqPo~pOxaN@$}|z)5|Y$Jn_`#k +zfg@aUCa_>es9g(WSn9VSbpo5M#4F(}G@Ri7+`W6Aq9>pn9eXXK&P{I?M;JX(=U +z5qw3Wfs#zD7p>`#XraGG=n{G_tOZwqNJ8zh?H)yS$7V`+y+ZDylzzc2)UZH=a6(i} +zQVZ+p6#W1W7cQReDwp-25QE)^m-L&(*I>NA9##1U@=6xoE()&dXC0>! +zGqpRyW%V0%u|?m0!n;6DJUA%PC(!u{1VT`&E8QmTE#QlFrwweFH4t6$MWY*am?(R@ +z|EMQED1j3fc(p?z@cwLT7FW=^wDO_dn4BL=E +zBR1%^SVBK=vm2^f-6vft*DJ)NOH+H0&QfE`Ai)}sD!*|f?HCYF?&tfo^duov{@aA( +z!fn}TZIyfY;ffv=trCqegp>XPT1si@wGemSE>MBVJ2o1&(@kLO;@RZ9jsk6P5Ojij +zj;sDt7XkU}p4bl;h(B+oOp9RA8l{mnHRpuL1aO8)t!^M%ZYK7Mi!54<@(qUH<_i=m +zCxEpe;d4B`wL0H+`~q4e^%_p?W>0%2zLk_|_;nZ=o>DxO4_ttZs7a>f#o{qFVn`&v +z-XMQ-s`6p43%5d>zK{4M_q$;2yV0iB6yiE<=62v^R11WnweCd!+|G2ejeZRPK!?P& +zy=10?QeH5QTWM3WRbjYU{_rW~2^jW9Th`hi{*G1k)_>6lzA9KkK5DLrGdo%MyWIOs +z>XO~@w`~+sfJ2yr!-v;HC@m9%=nM;xl~Jo=-BWnkLMY|(ZQ@J4dAx(Sfe_P_ru?=A +zX);3vc4cqLfhmb}Mg9d3!ojc*z95t=R$8+?YMy&E@3l$cyL#nBIY<&d@xGL{*@bH9 +zgg*vIblA04q~(LU((9V|3qSJSyNz^KUDxNiNOdu%&-Fe^h&*$DP*GV*?X4_7o}rGg +z|1E5*kzKdU%wLoSXgYrZOK72{gT$ExL9j(F_GcFzDH}~#X=QpBR%n(~J&J>JVkDn9 +z^1PeW)Obp)K_rqsntqEk=08N{9%>xE=wcc^RytPMs?6xB##H7xC4E(V*^;teI}mUY +zMiV7nMcSff@D{936KtDY!LUf%j1t7FPr`Gj_;=D;ZAEAzH_*t>AJPOLcv1W4^*J;j +z&%a3krcof|VN{sCZ3agXem`)S(&7zcAk-Nuse}pvSp7t(y=Mmia}5NF6 +z9-CPki`7bsCEa*3Hcs^QH@g-~6&YE68{p&D*Xb>XOyTU-d-~|7`x4@%dD14yR+N*WU)dGRQVXt=X6*$hywlEV8a9Q1lF&;uTH{2(XPn(` +za0IvjLD7P-W?Z-$;94IqknZWHQDcU!m3S+C3yK>wBw>zIA)rK336qK_b$fGqJDVvD +zzSz{s+Yc>}!~U)y{mgNVn$#3|~^(sx_>0o5!@&pI63t!V6CMZL%D325s=IT9w| +zP42Xxx9c1<%54}%75w_a^OnGAF +zXrLT*w4LK!)kG!%!g}OOMG{KKpGD5A;_YSe5I7nlXWN@8UDQ%?7&J{sI|)lSMA4Rj +z*H+0ZpQA%=6 +zE=-+AM1MPN;yiLSk1?Zxs?3GYT#n_=86{zhwwbUxZSM^9|J<`ytg{kPZ#5J|dt!KZ +zV8$@SDLt0fHKNQ2nCM^>IU%r$fk#I^U +ziA+{IQBe}yO^Q@Fs&n>7Ns58bz|MRiJkBcirK$N^AT?deaXs=7?sj{i3 +zFE1uBQ(_uZSuB!6`vG1PWO(&hRl9|G<@E>ydJ@PAFqPsa@&2xO{ubm5H*fJ9p94p9|L$!KI-P@k1c;>r&9<6OBKOO{Qwox7|e@@aWysh7r*!(!P|&DIPYY1 +zV|@e&YTCn7Tw@{2O0`p}xuC@S#pkp(R3-m{#QEvuCk47YRo>V=)Vf)83jOe{P%}QE +zNAxP^93^vEzx}xcW4a-4iYZdFfy@UWf7dmO=~bRdx4A9DK(4}FR@ua+Sxc*fDmqns +z#Y>6@Uwe_%VCHh!pE2PZ&0!72`z8jr=g-hS-7l_?5gi!ONN`Va6;H)TFYOLB-zsF0 +z7;g62qe3sGJfXjGuS!q(IME`(8aA&*ib>_pU-u;Q)WYD{r5Iu6Wmu;!Gwq3&3;D&` +zi7^CFt(EOK!)Aib`EzItr+$n`*zQ!@@g*;S4CKTSua~I8n2(#>*a*2F%qb8Urm=V9 +z%!0hAXPg!2K~#);^rbBpJdH}F-;`&eWlXZ%BU_Dw0)ku;zxj$D+f_wbM`cF#Y>Ubq +zZ9Q|!Xg*sCSc+~$3SG)|-Q6SP0P&QWF|m731QPIbsp6EOHG1DksdbHVFD6Utw^BvZ +zBAizk>O{931KRil;TK3jq@`F(g$oBP6PnFc=y3 +z%ZU{~hnCB(GXUMtHxEhE#Ys3+<5aB<-U<-{LSxvI*6LvEcp*>&B%(pKDX^??UgxbM +za~mqwn^%S9#&-qv;C@KOktM8_LE~KhwXzp_fBzWeB}Lr0_HFzeefP;57TP(2+xSNW +zv5N`14I$=FlnayU#;5!#BUNV?gBDA-4_>9%Zn64V@bz!j)Hn(L8P~txN1~T2hVz5!p+y$95$R9Kmd(OSR2dfrY?}Vwt!s%w;%^DeX9r;(5_5oz +z=K-Y|6n(dsFW49co*03Lm!mMTVG3`&M0N$nd3p|Pa3Bltu#m@cli=re>WZ$YqNy;s +z4CBDG*US#TVV3Hn^4q4i?Zxh_ki0Ea(D!joOx}S_o75@~3KDJxRLDB&QvFQJa*vFI?o!DdA=1Miu%8xPF5Ix&hn +zT~)hBe}Gliz3LiLa#o@$!JZ&X5G2sex}Yh_!ExZY3ch+*CXQnb?+E(y?HeV~b)38x +zqxI0$>~a^tdH>k{klEGwWLDN>N3kLd9REX0uGo%+(|vVg95D7sl*iIndt*Y(dKZ?H +z?N1*SsI*`I)JKool>})F=KPc@N)X1`Skhas-;#<5UN2Zzz%g;$bRy9OVq`$}9)vZr +z{ET%@y*gpYv~i)zyfki8{$^<|+~O73-7oyo4hYn-Rg3;)t&A)8pjMCdIJ*lVux3GO +zcpt#LjoTL^=CeH84>`oo6yDIVn!fN~WWJsCHFH_R3VsS-T1VKRU@`ez&byeV^z)t;(7kZ~JgNb9A +zzZ`16cYg-qMFsyJMXFh+RIB~6KEE&*7=rHhx_&r5ILV26bWbCfww{Kqv)>Oz55C0+ +z1X!J5DYGePqmn4(0p3I&cO(En>_*vEKVI-RFwy6;%6(Qx6Yd@!g&BH$>o|` +zQN}1cVM4SdfSD0<2PW3h^^HKc(bZh4o}Sw%y@TuA?|AH_uV=8*a6vGN%e9sKyrg-1n76asAZtwX!C{ +z28kt#@4R_YGyVcLLzRN5*VlwQvcB3S^AT*<&Z8ZQwbw +z9YAH$R^;6|Z%$>C23wKc-oTRGm7e~UfclT(1ZX~y0%QU$OmU2dj>UWk(q29ppTGKj +zjDP7k2;q>G*A(xvwy_P{s!=rwn?^H=0CCSf{P(rsv1xlydcbAHeWRa*(8rX^*EKQjre_6+=F?mk*tF`A`oLP#NBbtt-$Y=ND +z50Y0rF*apjlff829t~^%{516Ms_+1uw9#lKfyASpj9#J=7*n^_o0Z4)66Qi!mGdUrdJBgfvyKpEOkiwz~UqweoqD7-*J0W +zGJ8?$zkS(T^xWN()fTlwfjBkayQ_k$zutZKH>VQmqQD{i`Gs;q*~Lu*|)su6qbac7^&9&k#lRIyj|(FE;Qyg +z4KjuB+awyb8}d4#qm`rEC2XLkDBOp74DhMgphxQ=$0!*q!;lOU%J~{(^-#ob;{si; +zBwMtXLY@MK~Yf?a=d=U1$O@h^i64gEFvAbF0*0*gzY>d3$(r!LlC4VNK{hrqD{3sJAxz@k`Xo2 +zf4Vab*L=TIvW^Mnp$GsnoSgFS>-wO|C0&USd__=p!9t!j@p0iX3&K>9ybjv!pc>lS}7=>OXS +z2@sKeCjZ(UU&~>aO1`H{q!mQo;y5ppA69*f9L=O%GD=`1Hm(6$ax^fLNsB@|_(S?j +zZ9!wFB21|WpR?OH6<9Bz^@`+thTb!{MI|HmW2N?|piWCZMbZPBnHScpgkmAUthFR- +z3ffJ>r?vaQx&NkHWmPtSR4m5;PH{3ujIr_5UfEO3jCZ7ch?&a^e%dvuPj1b-;N~4P +zLZL1Tta)K~ccZ;p03vIuO(+2jA}DmU7^~XYmEfFA>6jNKQ_LPM2;jzp(@FPF75AhA(!B|m}* +z#-WJ+PyD}h?k%O8f_#mFj+SU3lc>WtbT1FYEi1?qj6+%cxVF2R=PY7P)t=VxL;~>Y +zT)9)m2Jv#?1(vjtMT!Pnhm!_{}tl6*zlatdF$EA +ziGaFbsw2{xbGRsD_bd@BxzS`)?FHK+CP%QnQtezAAE!>`)9%$DZiSi5L$lIFru(5r +z6kI=-cfO%r&Q}0dDwQoIy?*KV9P-PJ)hOOJ3BHU4x!^7o2QONt`tMc9YE2CAeHuU= +z#L3l%npK&N0mUDMce$^orY6;oId8VA62_`Y_o^a`_;SNGHEI7v0__*0I!?G7_JV!2 +z)V6(SytI9{@hL`qOmkZe(s4IwS3N8|t?=!hp$nowD{9m7`pSWGUorZF3$g!EQ=0bE +z+5aHoCti5nk#83Otf@I6^9XofV$_z{y7lGX?>Y_{wEGA^KLD`)bbIa(2NYW`hvXB>AqGbqySbURg;-(}j1X+0?M2A3>H5C98 +zyyC}Ph)Dw@-~P>GM1~NS6gE0N%rsjPy%0yhX4ZRvpInmWC{Be2Jbm=;dikuic!BlT +zeJvhmjKdwZ(Jt+8Jx)G##>|fY1q>&l(Nb)5r1-M1=W;pFzzD+!jd1L3DQb-418V8s +zF(PzOHOxoYHW6)BvJ3Ty@)p_F0Y^Q1hUZ;|5G_>Bk0L1{fd5Ff5!GoU33Ua$P9I4#pfuvjdOxXqAW1TBlrwT*&9G-5mGGVPvA2>YZ6yadqC`O%YV+8u%YWcyx9pes&H +zPisbP4UA;yDq^sumD_Y!9GR%R4v&V=f#% +zeaF(1HOE{-xAK)?kO#P649mb?4>?;ckm2`VK*VjMTeAK-J({9&ZW?VEO){!u?X;_0 +zme6<>UJkZ>GKzP=t#Jw;I8*(r2FI36>+zK?X>KOFyQMa4wR8dBnCHfFo&On-%w!VI +ztx=viO0dN5CSC-zuII}`tmgf_XMnq<8=#(LNuFF9`DFD)*0u3L4$Owy5Q6QhmFpv3}Ap2 +zEMvX(*EFKYSb!U8BYqRV+N)ZtVxp`%JUT(mstw1K)&ij&#qzjP +zFt%2b9Zi}}CZ!yyQIlf*&a}mGAU-g;Q!PF1F`#HjX+Esumlpu(Fh&V#=>XSC47kR>Ma9n{q-(?JY^eUIeuChibwgr!bEf&K{oc +zlhpM8njn$yF-OwaCDxynkuO*-jV}ERslm5)>-w|Xz|)%js`8oqnQ^%Twz1iLDDA|} +zXY;&i7VDAM%(qYCK@|1=^~FJPxH$(b(OItX6s9o76G*&}5QT +zXje85NCAiF==yp2_1++ZFaAw5vvKc19ZLz-_!S=);b8XTv`~4lCHq^49EE=}vxIob +ziTYM(#6Ci3`OTgG5;s-TEkA?MhOEcY@wzxM2J +z@LYl1ccC)1n8fB1FA4xNA)S##ximFrY3-g*L+2utP)D4%B +zYMRlRS4lF7M@7Ql8{{Bsh$A2re7DF~9R*M@TXd +z)xMl3PPsjAHl1r$QRMAeRtd!dy}aV;@D$4abA6rf;S9Yo$IiJX(c{Y29i< +zZOHY%_Sv@sFXDVei>YWLeVxrvjXv?F0D+aqFL!aOE;nD>-T#&0 +zkDM-{%9gnnUofX~9rWXIqAXhKb_(ciQ1X%ePdJ{8_M}WIbp|sV-lR$dSL>rr{Nwa? +zto-&hE7Jn2UVamO))51)WX02Um58)3(>0o9o)dj=;+$hZEu(_CCcBTe-n?lc=DsO? +z8~a6o;o`O1FVXLIS?at~33Ix?RVzrbc=hT7cc-lXxfe#d7S*C=8jI|=Bk;)w#w2$MdpsqB@9rpu*aJM01(NfebGd*4v%f` +z*YXz*thh{1;mj~5{!++M+-LrKKPKxeEXRzE!^tMIA% +zmqKl@Ur5nWm;L*YBrojgk!;I49NwMu<=Ou}K1-H!#NgFF$}Hh$8X=9IZxstdVEj(X +z(hlT1OOC(5VSO!_ORnm3Jo3YmRCG+BGb3JR1imYB0 +zG~frkNbzhR5fS9AHmphycf!PZrRba)_8X3_Ep=ZkAe>kgU==y-`L-D +zPKn_W0lU%+hd`vAN8#2PAjzCue6#=sJCk2`gOJ`maV7hxZs;C_SRIn+Q`PJSHBW2a +z_n#8x2%La`4dS(kK>>J=l5S~@Ir!%NNWIbt_gnmXc%R8>=ThTZ{vq-~cvYy=-c6yG +zW`8hn0o(NStDl2CyRuz50N!FxGOd-O50&QS2u}!b8=48dgUulK&ses*%5eQ){Cn~z +zu)j?{eHcBw|`ZRm@N^+^qYcAv*4-CHurKd-g0y3FS{_0%Ilhi%22a|c8K}+QlFDau;O%8 +z-{{?5@yL}@iz3V+oQ)qgB|pLKWY6l3Lt?IqlQL`2i3eMb!*<$Cf%ir6``!{g;&Rv?V=?CjO +zb-`}!3G=0CQ^>icODDk_v0TD)QWoX>A0WrlnK7_W2jtcyrHr;IUjb#oi%+otFzbiQ +z7y@F0m#$ZPl}BjW8Z%AtZSuj+YELq|ft6_l1E_q&WH9kbAq?-?TGWN{NSRHuO%RV+ +zl+a(f??jg(5jg6>9NbK={Z&0Q|2mVB;xC8G*O4EpCYv%0A+6E8@$t3QBfto{xAK?X +z$t(2Ym*x8LHA5DoIy>J=4wZu13?2oFkz`Qo +z=C-hI)lt<}zjw43@_m`h!kgsbnAw;GT;t9vUZ0l#sLz2fT?kG2F))F6*rF|1wr(yL +zf?XbAKa|O3jBL2~*S(f6&g^vkr*&n$9BwlSO8A3)3BBgg%g1ONFgswVlhLUZ-s!KJhWFb}48kh$$QG}B +zW(iFJy0HEs*}JSu;-nilV8F7;)Iux2yNbZI(RkkjS2Z5XV<7H50xNLRuHDpo@w7+8 +zoJ(qEZlM;)*c`lqXRu +z^)YI`B6;Es#voR)BRtc3RE6I)#%&A-kOmKl?(d`dC}S1#l0C4aZ4WX(_NDGBxCV;^ +zC0CpdemeunnQ(vp&?Hanb;00B{lfYk{LQxJPKZ_{d#a*y_VV(qpKF@3^^kreEa4_O +z)zCJ5OD5#mkd1JRb}_BOD6BurUJ6 +zD{`#>s+jTCA&+f$tZuSsqkRZ=a4L@8r3G6*g+IamOd0vk2*N_><9HbMLp(jEl)G|u +z@DKDd=+%lrpGA09uI#VfNIsJeW^i-);<~iF%8TPiA4`N_6?p3J?N6+iE*ekI->HLQ +z@Ixd#d;i0B@f)$6B>Z0yq88@L0Rg$x(1FWozBG;*Thi_o8{2^dV@BnnrLkqbqvXrK +zC16vU4Q#+2Ya1?|-XZrt@gb(5#=uQ5f@y)zR*y@vQSLT7VNFH3Y#zc4*p&}*Put2k +zD0;tQT(2GCN4XIh@ +zpG1Z|Z;M!uT5gU|hfJc^m^X+4G3*S3a?+udBNFP5Fd#M`j*c;meBF~qnEWgs8m0YG +z_y^_e?8Nz(B^zlnSxMZnc6`5 +ztUysr;=Y2)x=i+gy1A%q(E|l&qiZ-~P=0qD&>f8uc@d($+|x>uOOFs6vjt7K18fv& +zso&AKgSLa(2$pG87KG~B^fED`|K9*j&dIdy>Vm{rybF(t+QlrytxDbHYMUaYco266 +zzhpX^Pu?ON6VC(a-IV%Gzk{Of7V3h2Tcn9!B|97Zqf|JbZx`%s~YC{98)oI0b0wl6mg(pyPz8R+pHQ$ +zSU)y@TF{K`I9W+hu4oMSvwqIFhzP*`^`3Y!76O=xxFPtJnvcNpR|oO>Q^*fMqYpx1 +zQ?pbF4HcZG@ClI{i-I9bDmAi8t*z07FXnNu`+lkLq8nO2>6olQdJ=L*T7Y<+r9ac354LFM{Q5Fl&~Y-%JumSq$KNQM%C9{KM%Fl=jR(jh+f*;F^B +zn~bGS)VqOAk;tj?q~fEw)SuyP(iN23sfda%bm#{6#y4)Tysk6f)U)fzBVGrZOz5El +zen>O}!y+g^E~1L~Rp8_ObA#DQy>#~-@Bh}&NUy=t%u%4R3}@^>o8-5GHGs744rlTO +z(*?tgtQ|$-5U_SmJ&hL0tV8q;#TJn+tf}Wx%=x0v4G3q>dRU(K+UKBG+qHsRH-DFFR1 +z&r`KjH4@ajMIDG(U?BkWYl6R!&!lkhM@R%wfZzQ3SEIxge0yr-&~uV%pKM$Ei+OBHZxv*!>88RIIPj{RCyhu7Iv21+Lkk}**Sz>SEN*!x- +zF9i!Ji(#5+`$!N7M@_RZf*kt+6&FY8QpDt_zyAl8gOu+iL^xRgJ)}`FPO+p{hyNH$ +zlY7uw8A4k@XyV_(hMXNnr3=!s^&Q%=6TaW-1fGMgL6Bv~T$|{+nt_`AZ};PfHJoO@ +zyD8RZVW^JfEcSsOf-~LLf>)+|qbPiIVUP6qDgsW)1rpjWk6jHkqxSIt8DGe+DS4A(L=f&B12LrTSDYlAYNabpMXus)(OJos_LN_$ +zx~?8}jnkuwdM5mD52U5vSVBjDU3BR&mq9tWpDR799%c#CGLv}7f}Jv2!C +ziRF)x#FEd-v&1=qX^irmd4O$MHMt85%ALk@yJo~%orCt&x=T}fD53k6Ew;I9|4)R^ +zz(0{3PLljv@A>61*`2L*;e7j^4VqZV63Z{*5`G`(^maEmQ_cBZ5+-e!Bxd6Ue%yUgUG?H(B%9Fr$ehcok5J4UhyE#C|)I +z&S|65{B{}cLQIr+#ey&;50Xlw^?5KWSe%JdCHvO8eR^%4UO_^?I{yTJsEZNB-@t(e +z>kT)r)T%W(lIl7ae(($w(;fR$$)|*n8PxlZpf;a9gKc8|V_nW$Hp6Jj?XOKqo+9d} +zm8oYr_ukO!>RzZ*N3I#sVpT(-OxunFkDHuB0KpBJ9|V5mfsl{8fIv}hdl0tfyxkuy +z0qgxCOHwqKEpL&?h6j>h6#z67fne_@#}c#IkS^VS?@%Q@hcj1b`C1l#pcSznhmisO +zZG{bu-mYqSbE>Vs;GA%%%L(0Tp0DRdqYW5EQ%_kx{3)k*5SS$LBmG?9?zBtspVu4) +zMPqX2h*VgG;B*FiSl*lEUS`}DRDhk{JnNv+^ItqiK@2B?v5aW@NQdwb|1r{QbrR-96qwgd?g{w=BX$O>|7LW-u|=qiXd7uCeh~V8 +ztmLDMn|}%ZM9?BE8JWMHojUVhh{7DBoI59&Xj0&KVFVp@?H}Uj8MIaEM6D!dB_8(P +z9XZiU8+thD{KQV@C%#TtAE5p!vjT51>3ThHpEYkVUn{g|5dP_U9{SK#MyB*2$L_(b +zsb8NIsl*~Q9h>U|6H7* +z6R0Vvwu6HH&uYUh1~cX>cslDvx;|EdjJvj0ZK2ex>*m_r7(N~5K7=-@x*_NtZzdvU +z=G^AR!&J+hvp@3Y-8mB)#MbL`Qb5Z!7jM9h#dd3A!2Y +z*rWDAbjQ3%OvAi8lUWg$SLcV}b|b$62FmeKwzP|fgBr73EzFZiZ9DYs2rGQHNDmV{ +z2JAz!4upOsFrD(?hZqGgZ(sY4R8#+VeaoLmjo2}KE9CRme2Mea_3{WwD7YyAqp5?J +zjHBib#e#=z+bEyOn8L~23&h*SaEG&>#B_PZ+`qOm7u`PdiQXvCI=^yNzUN|5A%m5c +zbXX@kxAJF|#GHXHPUdlB;Aj9U{)tqHWDzV>;l&Lpa-|!xJZX%!qp?@72QQrf-7q%B +z6x0!#sW&Y1foc3RG;!@)LA-m0P^+%=W3GsP++q;A=O3UAf=~L(ycy5dq66AdViVS{CE=LUYnwG*)huYi#MWY<4Z%htb)5^KJ)j1_r>2FnQ2NF3+Oxcjo%h?ng}GA*?Jte +zEDm|!C_XUf~R@xuBnr~VcP5PAlGb6j*GO7=N2C?$Lh0EERyW>tx{(YFUTB(YSFh58Y(v$( +z+FrXu;>I$GLZ@DhyYi{!!n}VpkObDmda?gR5_A;c?4`BQXb%yitJyK2{pX;=jcROP +zOKBZDrUdSX8Qa+L>If0<)7`V@Ox7mj`Hm^DTj{t;7ayhJh1SIw^W6;;LXXjig}X=& +zgD2dQynAV%?RS}qcHgo283<6koqSaPqv%Z)L1>&32v5-U`Na>EBrIA|iuU>Rvf(VC%xk9MQYmW2ry$ +zdBhe#tWP#bdR6}x&sP9_As*Dn9wc?;`fV}1{;^UKQ-{`v9pgluef=6K)b1x3hWq~ +z*7=`2rx5>_lmRrZ4hS^X{nL<4zl8)2&wPqmX8qz*ns!Bc`A9XPI76F3`NqiY>xo68 +zvps48LmPo9fK!e5>c<1y|BI|6%^+`qJ_h3Rn~MU9642T{wRe|%(WIfO9cm+@zqSF+ +zMeDX&)vgJdu!TeFtFyj;vo^4hEmv!zsKOx_0XC~A?)XH@P~xD(pwwdm(>7q^jO@1| +zixYgc{q3oi7CE1F_e5R#3VkXA<_*JOMmbO!B9n0$3vCPoAOMnU;#wV*lGqnlqQ{4n +zX3xMNCX85cLj+ywVi-9nh|eFFBPG}O2Cw)Xw7k%O|LBWI@bJtzSDGpT&EI)P!eU`KI +zvH<=6ea_}%;>95M?y0WR)*4Lt4r-SBkF~bO*P|(~Jq3#?tCQ8llmZAXe+I(Urzxny +z5lF>`@GSV%u;=mDgb)DmQDCoKIq;$rU +zlT&!|vYQvV6YXvm=5hwQOL?2N1R5YnO%K&$bZz?Pz +z(|M}6aEk*R#%C0BO#wO>=l4YU%#dS57=$Oqfa^i~p`hw~>r^%dpprhSjlOBDAcBYB +zdjeY6*Yx+DKhu5FW#|xPn0aczKydH!u(0s?_b_?Gp2ymg714$EnHoKik0MWhZ0)Mn) +zToj$3ZPK+%J-EyMtc=M-k2FhcV*}vy&_c1s?Twxic~$%8ZHlZ`+$@%`@-o#8?HE{e +zeIS3oh3*`$Us3f?)e%&4srgN;%zIyJgbN#2IK&J#@+N=AA1}YDY>xev1`?`xq9ZH9MqzvERkO +zP?8AD>m(cp%-Vb9?QzlM0h^#lCqSN^^8E?SWM9u!%IpDVd^_!?NDXVaxqa`@(6aFx +zSF&b-FTUZm +zQ@Ccez0a~*X%QE{28Y7g%I)&9(^^~=;Zz-0R-KW{V-UQ6W|1%AxQkqP1%J^!xd1Z- +z(d`PBS8DmkDoh-Tf2C-+JWcl#J{kjQRE6}w-Hz+5Ghd*qDx#byxp2J*E5X>IOaY#I +zT3d1-(1bwL%#q&`In%9eNFJsIbe1w(ujm{ld#GpESi+iEBo5Z#s|L{BFn43pycAia +z5KA9&nhd*rGMHDWhyKu#20h*Y~zFN@)(vZT%KU@f5sNv}bKnF7D0@us8(?dpw=qHMn +zx2xa!CJJ8{DzrE@4n*urY78^3?vbySU+hcGg3o69f=oK95tPy^IQUT{pN*E0-?1j> +zhAL&k_J$g*qs7R7D)eg3O+h3Y)_Z@C+<2M^O87zhdoJoGoh>G{I|*<8V)2By;{qf& +z1AQ5lT<}2pWjA9q9X2WPp}NDmV~J%H)33gM_?my0-!y4j7sv|nTjw5N%! +z%mLHGx)gpSCx`_cW?}Id2&4@g3V_Z``ky9h%h8ZTOc@Fp0y9 +zqz^c#f>bRRoh(%2#uH+rsrq{6qOS>61{d(OCMGZK6@R(ecAqP#FqogaeEeLLBcbnY +zb*6%VU#z!?#NQxnc}ff@m`LSLJVFED<)1VPHTftL$8=h%sQ +z9dfBP%euxT#yfJRby~JG`mThOkchop*&@c{|2}NRNt4y8)OuyW$Vl3Pz^B(P2sXF* +zM7ChOn5y0 +zAr`IzM4em1g!8AC?tI0Wsnw1RX@(4Notg6^z$vgLt8nR2kZ6k*!`$958BR +zFR)T67xY>`TyVy?r->|QAXcrt&CZaN8V`(7!N +zrb1{6E!bh$BsyzG4U+{&MhaEI*t$y;U?pY@1mUYl +z`sc{W+KO3eiPl1S2jlO~rr7*kRCcFS9wGGixb{|)jE4@&uYQ(1y5nST1-BZ +zzv@JOdCFqXysD;3Pf@Kx-y$&{pS$_(s%ICR$<3r;;Y!%3;!U~`+CrfmgB{QC5>7y^ +z>AZq>mk`X*AIwK~){l}+IrM@UK<#c_cAeC-C>y?7?J`6QUe<;y<8;u5S_(66af!O@ +zgz9f=K$9XSQ9@O{3jEMp)Ww!I!%DGa>zp3CqbaXg4AiQ62q+cKP&14bQ{#;O0JI$R +zKVure;_OGjW~uj$p@uyqHk^Nk-x4&_c%sreTm@_JC4W70ZyMuc?Q2uN9pFJ)>cxoz +zW!Lmm1Nl}-GufT4zSXzK;C{;F*b#E+B8<()udcE5TWlUo6@|?|n)QDF@Qr;|d-DC~ +zaWSoriz7sB0!R|WvQpg|{nD3CZUXK^I@VWV8EF6U`7WwC0lO+{DiQ6e0_KWE$3ZlP +zJkI4~*ktO|G!Fq`Pz!xH+EBz()m-Iu=IU^c=~q~TZ>?2qUb)(+TU +zoq+>3;|ulLlg9!s6}!qYC05-8^}ptt{K*myz#2{~f}w)6qMLrmB~lChf_mdoi)r)N +z1Uv*FHe1p{_^BIj+57A*F|E=6%kqNL#)s>+DI&)+p`#7kT*Q!`#Hw4#;E7rEDuHbp +z&71^|2HUFZ!Z!6dce<9ZX=r)X3cfYsuwPNK!26jZK2Yc*Y+aU1WA{Fx2pQAgiCgF- +z>{0qyCXRuEukjz^HjK1R$ank;_`?SA^~KkT(gJ&ws@lJR>APH#@3-2awzU&BYLWfw +z+k3a8*f=1tS1bW&Lf$Rcb_;tkmI1<$sN|zbm9V5UuR6Z>^mj2V2xQ401OI&1aAt7! +zuCJWp-`O<0`Ag!&$$mEF5Dm_`NG1<7&JjSL%;@#cu}QZ^NpJ+VmJ*Sd)3DtnCa#2? +zRx5zmZ~8X3(MT=g7nLHQQ#La}QC2RF0+A`QcGv0j{0gVtr&-W|qGo)K(AaABhD;*! +z_SGQU9ux@zE5Mi~(8||Ucub%)55FDr;&0)i#qu;&X +zv%!KA#K1e*{9I5%#4{Gst!^^ +zs{Y&F@`uS&;W-eW5nN0vAOl`)omV4T*%8B8G|(;A?PCJ3&^d@b8x!xt-%OOCZ{eq; +zx~44`J>*<^KSd2{I<2(MPnc}q>GA7fFpMbl8SyAD&2DEE^v;4%Mjl|PawNm*WXsTA +zGp{W2S2l!*d?*(z4AWfD@Z2MAL1tWK48{Rd&@TL)bM=I>BY(lLm +z%2XqL+q*tLyX;I5(*zS7MzjLqY(#36wuvD2QvL+6D9bR*v>m^Y3+!%+NGI#~V$L4s +zWHbV^s?enr{kl4C+*SryXOX)_G#S2&c9^HNrb2OAA+!YmG3w$wxBtaF89~EwKKyKw +ze(Y(yZmqJhMCjrN@HNJZLBpX{5Apz$$u5<7^p@hj@UIDY4yK|a<0lOE_jzcTSD +zoQ-TL)>}f;BtpdiApUdhv6X7B<|6K*n(`9^x5E6 +z3OU?-l9Pr4e4HaGu42}PZ#KsAH?H6jdf~#aUjxpn>{!&P&(hj2*`rD$o4WW}&khB; +z?|h6cT}1u2nISbx#U7N0&dR|Q(qnc?xCvBa2y7y2kLUu6uJapH44#vt9awIm=IA+0 +zv}JeHRM{~Rjx4)N@eCt8qJrHKx;*MD7vE@9BUX{(fxY{*l4U?N?i5t$7FQ_;-xjOv +zH}=?ct1%LQ0XqYWEN-=&W?lv20Sr(Ky55J_>Z94(-)Uw+6n>`uK__HJVbT%1ht2uS +zn?5snItW4GYy3@YxZXbW$yQgGd!=LbOpI=M3it|MwuH7U5$Z>y9Y; +z=nJB#MP-G-QDc}X77dg$IJN}N<|rD!w|3+&*$M?fx7Z|}kcx=30Tk{rL)<ct! +z44DpvLiv`YA7J=6BFJe#KMf`Kase++;iw68s48&Q^l1O9uYLLuJ9=rasD)%^PoD3N +zj}EqnB83wL3Mp1NYAb`Lee?$JXJL;p5;LK(-L|O(SH;=>P--Sjdr-u|D0h)`br)sl7lLu +z_riE#I#J}INx?RMYO3<3N!8xcE>I+nwReUdW@ +zDR@4aRudQr@uh(u%-OCbMKM5jQ!V?uY{O74-lNs)FZC{8Nea-q!vTh}tfm2`BZQMl +zXri(48A%#WUMfDp6vr|Hb?~5aThgon2(rt8ydz!ot2#2e3=%%xO4NMi>V(*e&y8WO +zAQ-&nmb5q@IZ~Lnt%#mQuU$J2+nkdpi$kb +z0$SYv-!7}=I`N-RHaUKenZs0aN%#t;4`?wH+Fg_E_sSS^vtQj=sOH1ip +zchVI_c@SGsmlf>&MhKU$+nGyFPBynwyE#A)2N6Kj#Kt5>nUllIp;bKXTt1o=%v +z7dxxt;KUE&WIy{>9j`D?`q7*d*q9(-DtA;@LOU#dAjXI5F8Yuje0pMS&fp=(7gUZX#9mqb-I`%@^N-`{{Z+SJ2Qo{0ZfrB~M~7$Y+s!u9uw +z?sJ)M^|KH`SI43RgGDaP$R5kZ^&dEcfIkfIq_m2hUfsB(Z}3KAti;By>{-L1vd~C$ +zXMONe+!E7?_&-dhHg|63)HxEp;~!EkFtFW7Pd4bp6SHNh3AP}g{60+oP!MPOJSDWu +ze+^A(`(?_i3aMGMsaQ}ybUhRlo%l{A=I24-b#|P;tQy<44Afgxpv*n9pxJt-HIFek +zIE(T~Rn&A}>JQ&U4Kt4O9$ro&mAQO9m}$?Wjh{%me;9s@AKe>Pj@HZXD4}gp4szDv|p|bf9Jjx)-Owj~tCC05{fx3G4 +zJROLf6tVw)wFK;58SPevfx`SxUg6IC8YfbfqtNsnKE{(hk!r%pfeyGSgbf$0aof3n +z)WKzyXocRArs@nq`V?%I)TwAkAZLXQ#@|~JXL|zi$Sf0Ey@Uz7#%t()flA +zb{djkX3juCPZJSY8|?KHm4=lQn2IvF!@UKx13U7QN=YWsd;MV{AEd=^I +z^hM$%trwXngQsqM#V0lul%0fBS`?VbSWSyTKS=A2hv5tv-kWAjbs^^7{V0Ba9CqMZ +zLO*B5Nep_KVj8-2y6#zhK56N_SrLu01oFR7g7TvPxe5!`w3~a^cX@)@B8junwb12) +zJ_0K|-iOgqn`Ir2s`7L){xbv+yZU}mK7vJPa9S|VxU&!h^OBW188Hv(Ml;UbQyg_2 +zl!M;-y6wMZcH7>KE$``iC2E#WfH2<~zh5oDK9@Y$>g^m!q%sGq(TG3#0-zcj)ZE`y +z1cjUaLzbDQ$zLM$_pxw*XV_FEcatoWY!t*RV9uQZz54Zj{v4Ch@Zj_vz0cW4`W-dm +zjkF~q{FZa6^0H3YH09L6Evxs{>U3T{#XTx|B26pN)uS_nL?n7#ZC%_c->ol_jx7Iz +z_xBBu=JjtAHsX?7yERez=#lPI5+!t?_)=r=Vl2%-vJwFd#~khcFQK#p?2^2mi`*!D +z6-#&I5r!`G<5phRe^a0?3xjj547@hV6rJDl7~3mkHWRy~-d3NCKst`IW{a{-w1ZXA +zE;bgCkCawhIa~IVq>UG{WbF;GF_5^Nt$c*EJNf9Pp9Pixrq_I1zWi-0`=txq4btZbrfnmc+YR4llQ%3T! +z)69-lXVF|sLMje350al}`>1$IgQ#)$SK%kZe^CH4Eveb_+yMJMF)-vY+RqbU=qa{` +zE(FiDyqkZP4zC3G{%xDFW!~oTp2kkYKW# +zRIyi5t9lT#V>sPX-y@)ebd(BJDm}*^IP{s24bSAYghHhUTrN=dGcDxNA4dpYR?xuM +z)QK;Mdst)8F6J^~>UrqvMLBsmok#S4)xPB&Z99^=#j{a?5Rb_PY&y8u_Q}j`a9nQ2AER(>z*Yz%OB{t0L%0paDZ0zlfROk4z249$?Q+B}v!*nl0O^ +zblbu!6@1^MSpUK(o5DJ8BFgVJ9X!d$|;-0(wr9 +z=NpJ9-A4jyh=gUcEqaiI^4~_fx?mH-i%R4M3I;G1Ei%Evs+L^XWQ}qtYj7L@@Uke& +zq#ykxotKz@mkv#C6VIAoKXK<%A!+zv1Fco`0N4JjuAK=hMDKES;x=Jih;h*9Kv<>< +z>4KOvi6Cd&V$zzFrIF6s&zrq +zfhhFn6;0?|!TkdY4iv=QZw*ZIyPRH6*YplBEXRv-5GXEtiEf=Q{*&n=a53v}oZRG0;8K?ESoKuDXDLvg3gSDO$s{&MPqwG!5K +zhsH_ID$U_@c>^rXsk4<_EvWpjP5&uOkn)Y0*jnPFtw80I<;n7Lwo&qe!M$=y4v-rF}$)k@!;RgqlqcA3;S&k1!mevBV8Q)P4Y(ARmaAR%4HrU9O +z8V>*Luw@`BLsW0ZsQ~Z|S9Z7!0Ajn}4GF>J*s;I9|s)cHvTC}IZ9nbT+R#O-DPAXzUBlrk+Io?beZCoJ*s=YSW%#B6+$ZQp-=);(n+kf&$ESK3Ve#p`=s+vfM^`u4!bJ^?_R& +z8xI?hvrE~doqyk}P>D%?Pyo28t&C+lWR$Aj4I&f4-Y-%*LHB!k4O<*|tf?Tea{RM9 +zb5`gUbR2mA&Dtffp$|Rttb=jJKTN?u;aA=Ph9UF8clVqnkg$PKV#Kk~)Fi&+6lJD8 +z1N$r`=ySvY#{t%!;Z<6=v*S{kuG+Lfd?u?-FZ4eaaj()*@FG^;u}JM+eVzJwPVWES +z>`V^Js7VMS_`^qcG9bXHS}KMqU+)M(sLBMQzL +zTY0oShyklO2V%DSmP?4sDC8?PrHn{s0COMpp?r>uX(E?{i6kuZgQ3}+AE>KTqW>_q +z!@ordhUTv5z#R;g(nSXLqoJ?|cm^=TmCxV^tD>}d*A{UMk2C3T4J>0!mZIuA>_6Bm +zCCIE3fX~-UfLA|L^{@Y%uFNRwK@v=#PY%4}Ck1Zr(Dw2^XDIxx3$K>DYirN02ynI| +zLYn}Fw>Ud6<;lbT5P3~V2m5S;wmlzdQ}}C@U-@w)=<+?ZWESyI4Q-ul&bUdk_9cE}&oq%OJvAGs}CEmn*w?jPUA8~_$i{%;}{Vzfyk@S2!IG^9$A +zUvICaoNhMfIT_B1!i>H>w^)cMtcN-3eUmHsu0>hm_8x3=ez%faS{Z1pdwOgR&ByT@ +z)zZ9Z4P@1QAn$&`*g})uRzcn_?;$=Bvg$6!BDMGbEQ%uC#@_jqv!xT9sV#vIwaFdF +zavCRSC3%=w=9t*;BAfmkRzl^e99jI}2xo4@hy%pSe=>#33PdCx#hWbl%Y79tex?x5 +zP4LOoL9^BxApf~X?jdwyhlg+_2s3w2bca!^Q(0p64#1I*c@_~A!78aPje*$OD!jZ& +z2qbJXzxMI}b9BlGLuh6|gB^GeCNFVS=bdx2_tIX`#b& +z4$9u0o`t(H5>gNKe^S!YUGYGjP!=*1LwtU5Uqm>E@Y~rq(3~hqe2ff0X?uK7NPl2h +zbF;>J#*5>7VBkdIw-=kml9v!k%9^5bE^waEQ-{^Y$`&q|jM;B(sH1^Iesy(v)+tTO +z9|e~iWNd4qX~!b`LGKi?h{_6jSe1lRs{m=cX%>xR9WbpbF;++{(lmvHAFpf&oC@oj +z)pz0!ND-LvmDW-B5fc5O`l)3bSkJ?4*nbH)^AG{`K%oBBNw_60k$`{X-+(=yf8bhG +z$gi|bE$8+@tSIMC$c#YpeaZ^ST823i_yQf+4_#tNBYLPzYU(vT5<`r}xe&)m@^(nh +zuyl%I_n`;0Ww-@B}C+_n$< +zNtN!A_{sW0i@6wws)uK+ChcwU;JOLI(1H5-AhQ9)^8?wNRez*m0AwLnAw0;ZDfLdY485ntM+ +zwnc8a+R7##yA^D*n6Jk+i=k$%0p%cRDa01mPu1A*hEkIEj_|yVn2~n5u)>y(HlrlM +z;4`-V9`sJW`bh3L_$c+=Xf`S1YD^7^#Dh)ZU3$a{Ch3L0O`LrEW;gy9M5p$ExXkkq +zkFBzk_#W`6wJ<<2x~)YgsqabD^n8skrL6QVJH&BJVSXz#Q>*WXbcS6!1l!A}kUgd+ +zbH5LcJrhXS!O*9|;51~T%9_^UAK>*>N6gn3c$TU($BB5T+4c+>K()HOj^`$s&@qh_ +zo*T9%l!{t^(QFN@3JIYi{05NEu{_KA$N!<)JdYOqQVovh!8&#pXate4a~k7EQf`N~ +z)r3g*oWwENMz=$K_AVTOW*fR`T@@f*8{`4jZXaC4pm|%#jw_+9J{}r4@syBVeFmKC +z&xKT>^1z9ZZTrCU2Nzd#$css!0M9b#t4EoIq5w>VjkaqNSpTw3?O6@J&6HYcB=zJx +z7u(XyWyu`Z;e{fFij{i!HSHL)%Cbus5CKE#$b&<9j4Kb{hT_wRQ_U_dh9z0ocr7H4 +zU|<^@Njrq^+&!Q~!t~(9)MlhuT#}RmZOLvYa0xGJhbHk@lPu#1yZ}VHfc`2Fq*r=1 +zNVzAY@fd`(72ZQN>fi~$@kbC=s+mhbp2j`X5hdHcVat@Tw$bV@98(M4F{e_NU7OZL +zs203;d=Pa1jt+o^w41&ChEf~!L6y3075jBE0be`wuOR9_2%4tA8XJ*gz=CVrc95SD +z@Bak4kk^5CphLZM$z*~_V`KO!#7Zd{1`9~=m1N=J!!cD<|EQ3kb~o%EbqEheG`M=t +z_*ig~gdinZ*ixK_mYE?K(?WA#Z1*t&OkUj}#EfrdZryZ!zOP!F@iTQ_iH;kOO-x!~ +z_*e0NaYY)f*GPH=5J3i(M&U=z$MPjzYp>`83^U@LDAV(cuxzT0v-Jt*8(59V^tD=H +zS4XWX4Ul?SePeLn;WX|$u0^HULj#pwPv#%UvIB1Q41AoN7o|tKgset4P6u +z<{z!iA+3%p#BP4GE_~j1M8|XFi{dtnGga0(0I~_r5Y4VcMd%W +zR4ES_^(_X61kbD85p1Yp^JAe~@EhXtvf3As1wRjN{;vFNLcJ^#>-<##z*BIh`kfTz +z?biUBprEYV2Ns1vS^pV^Wq6)>UnKyU7GU2uQUwqmSPaUdxP4{j^Ki@CgLBmO^|OfX +zdOZP++?B36CdKmP5Ac-SW@BX((z#{?L9B~BHk`*Irccx1n1<;&Y>{(y;ZJ{T18dCj +zNGVeju&PMX^Qn#7E5?}S>kk?;Z1JkPX5r|+;)h=3_25VJlg4rw2H5t9GGY(ba*=*T +zJ%7Dd>1{N*i@EHu;zHn>B#of?CBcC_k4!q*I-`*m=6~r$rA%UqH)_*ZjEfD;d$d`Z +zKmRL5OOi6l&>kOngZ&48EF!JQZAcc%?&i2^F;V&9OTyLL*w2GB08RpxW<8UVW4Z?V +z$xR;t{W=$Hv{QE*o$1HL$xQY}dXpU%-GQ-yRTvc_?=C2EYomtzZXsbBtNcu^G~+%* +zY6vUZBTm9i1Vlvc#?J`QnHuCML{ +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 +z;rA01ED93qgx^Zw+u +zc~cn-`z{q|l2g_RVnRXo3BrnR>vC*suIVjswe^!sy5r4=`0#=T5!#Ek8GWDP9c;&E?cq+&ZQYR +zgGYoQX|TroR_AH9@YLS_N=)Rx+>6o-1@=9X*A5RZ{jl~dYo4@cp7**6z-9|1F*xz_ +z<+B@_5xox}82nT8y3y@0 +z4(6vmM$Rqt?F#wds;IirKF}jp=ntpfxYnnD(MGpz9j~S)fX3DG|*d3Dhhw2a&;2`$6i2dMzu +zB|Bc-SEqEzQV#2Kq{(F&3#Ql&3;5YWFw%)u*(^rQWW#kwS9vX4sGoa{o!ZJPK!p^e +zn)z`BhqIEHs^F&f=PpPC8UI1}OWo)%+Jw43@~`i6M~Y#rX(pBTyOH3-hjZq31!K=| +z*)Pj#0Pak&t_wc((oVpMJr$7AwAMbm_A(|cZeQBiQMcoNOH1^!s!vn>oH=7iFJ~I& +z_T*xUMUbczCl$0DZQYiS`8&Jh|9eSEc1&hG#B#}K%`535E<|xj-Pv_-+yi4zfc*&9 +zWapY;dzC{>jUcFc&y$0yX!P8hr@84zUs1~)P@M~+Y<)qs?}lyG*ga8D2Q$GISE5Qt +zgWAMX&-+Uhd~F0F5Qk=7qy(I0;c_Zl-bfZg&Yf!*KUaez;=VIVe_Bcdy=k +zTM^5jaA(bETT%Xq6knpCG6>H6k6zpWlVHYacAt-neiBZ7p$b8LB`&?{)CT^4c~%ttdSv +z-ps{Mm<5-HdV)tSFCY`x-6gfKsF!JUezQs*Xuvnu6B4L03>l2oI1ULNd9&Z&8RKuW +zMFyr~f}*CYytaM9HkciMLiTkYPD<1-MmacTaIZN*`DC#%HaAqsCVsd#ez+X9f{8Yj +z5AwA^IO}tG%pM)}5%Qk;PJx7RpE;ah(-ub{EYBzm#g%MSHK%S5mC7wd6Nzr=()h$h +z&5tV#Nrk>^)k;D^t%qWZ1RU2HURd^+;wv;OOqUSgbxts0EN +zN_IH1*!#ab#X%3A5Y&d{5i#DI)K@vpo0hqO6ZJ%&AAYmr3R?Uv?PsU8dGoIm9m?XA +zZqayC)~EwvRz-D{F1CxtT6WnYeYD_OqR||G^6P^#id|0+YAwI#OPC%|Tcai$J +z#^v*;+zbW0ZME;m9o?e;*{STGf&KwzQVA^}pmTsPyYAp(20=#$Uo!{7qq&6JH}u!e +z`}!dkuR`Khn-rn{^;u~{=~vVE^k5qiZNaR}g<_$qr22cM{OkVFs#IsL@zhFvogd&( +z0cq~lIoPq8>=`lXV{NQ*QDgK5lhyBd#)+~n3_`aOtueG;*up~KG{iCoA&Pj_v=R(N +z2WZ=-EhTTgFSBq=IV=VLEZ^M-4V;{kW`wWbmsgi$Y!-;ib&s_J(Yh{Et<)msemt=U +z$5w+f_j_#>b`Wa|?Ky8Oj?q#`owBrYNK7$B*HKAj1Zo|j0>s`_lp|=>NPcTvaGdhy +zC3{7T9IBP=h031+9_E!ajPN7w;NQQD({}W;|4RrD?gc2Gh!1f% +zJI}eU>!YsTO&~id;A=r>ypf>$XnA>DmstxSzAJ2KKxzt5L-iKAAWP@kl@RB_z^UZ8 +z67FayZ2cOz{Q#F+U}WIz^;80Z*Sfp1t+A1fvuF;+B`{wf>{Q4mA22}3GZL9GsAw~e +z6?te5f}x +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 +zxZ;1y=zY>=oXSohYxzu7~)_WhWtfbyLXzW +z=L#5nn_<=C!d!rNRreASP9}GpLGQ8?tckgK!_jy_M9=hEY2V;=wTy$ +zQ-0X-srKbAn1`6RGR<#)f=daPXBv(O<7;4Q8QAUKC6^FyM{i_I`-A0~koxZ#gvdAA +zDt||LA>NfDPV-QC=@O(P=u`ges{eN?@nM_@A(S$ZPsu-gF_DfC?xeB$ShA9wh65Zr +z#mKwMFhh0x6?G=?YUdr#mvOAn9jcThVYKs1nrU^VO9;XF7b6&0mJ +z5D5_A*2M^?27s_?6D7fz)`8#ZY1qj^6RvvwjA`eP&G4s8_G|2tqZg5PA6nb^k*U9% +zifF6QYDm%s8LsVGf$Nofy5B4teY82{1m_fDe1c~QhGRARqUHkGq|&6*m>&^V!_JKw +zJ0wWGIgvU=bor|ukU1Li0tg(iE=tiYOxh`i_5%|A<-WG1X||0T;f|JShK{=P^*zDB +z_X6xp#d&@j08GM!ki~aB;-3v73Cdo^ZF=^c9(W0yWrW@>a1SD!a$Tc+0fh(()BI~! +z@CXQMU{P@ae1Yb;-k_sTPCpV;`epZC4B3S^Bb5I;{d#e3JeC66nbnuS6HETtN3n?U +zOfY6~uG|ly>*Cv&9NlPf!(>ryw6E7Si050Oci6_=afV)FIRtIBGbL0HiriD$g?kHk +z{^}MK+C+Of_%zTLrx+z@fofy1gRlwp;%gsk;?Ur*`92uCLb+8})uZsXQbbh%33De! +zL-$RL&wTqG(SGN-<91_+#5f_sS%%ZsGPX&i!CMI_toU?q0iLm~?y=!#F-8~~Hw>Tc +z*jTuo#ltmaXU@}Ra$#{_oAilsn6wDWdI%fMDh0-EyTf +zHivWbN(B}x;kXEhaHJaaSK|DxLm9a3<}W=-`ggHYf~XoBciS0|nZYVOz3F(Lt)F7b +ztP5Y+J(?!Yz>lDYpYo?Y8r7UYYS}xCUxZV#J&`b)Iw#@ZQJ2AKgU*H+zh4@VX_Sz) +ziy#OY)SgF1gE(Zx1G0u7k6QhFzc)xG4(GQ@GpQR_M$X;$-Q!$i7S+1u9W&hAv{UM) +z?!-?Zm_~C#Vx={j5VzhyGcw_2-n!l}Hr2~)cgpx|t8h^n0S%;0GdCDfQxcAJL0skz +zwxLpjuZ8x{TXosynkDGwQHY)?+WOsqM$(}mT^bVLw@SJG`sApJq(kc{CdaZ8O~Wr_ +zhtW#-^nIpV$*fAblc+sw?O{E~s?{T?@L +zDN~-iRvy2JJtMX3`MHX6p6?tMDg0zFk191eXFCX%_=}NT#FUiR;wzLu%4Jj}@VL7c +zK{DWrjlCHAa$kBNG?>MO@^M;V*$=qSdsK(xSy`_UAm%wm!53PR*3< +zLWO!&PHl)hnfsrxeDg#c)=NDDtjEjAYJSyAZ`|PTQ;Zc|W%#Ey-sovy5BG6Hv#a{Xty|5|%(?h4 +zzO#)H-1$o;iTFzEtd*jX+W@YZ8_u@eW36%dl?Pj~qt8&&G +z2K_ILK%U}d%ub6r*+sEE8uin4vge@ay>u6SWWFts=`;_mx&W2MYPBQeoT5MzX^SjZ +z${wm7_t^ZN4C0#dRkGr8gP9=OGE72S +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 +z{y0rxn|IPO#-O3{NttHGL(@;=b3m#5a77yTLD +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 +zKC`-ZRpnSeBr%LYlnn<(f`Fu +zRuu!AW8Z-S@x6vlj&Y`?-SzFei|x|=w=f?#{yGY-Kd;Bkv-#|-SS;v)SH0Ot1h{?i +zB;KVu$2kce2C~o9A~$nLW^4kXsHA5S4fmA-8huaw2C-bh&P-&^HzukJ2!%!ulcsfN +zfCKFzvmPyl0tCMwhPNA+6&-rpE#L~o)<_4NehZti`@!YQG^#9<8P=YL!Pjmyr(U+V +zaU+yL{4%hM)O?e~y4~+-@*xsq?+0m@3vEYkPSVxO2FemL5>LmbW%gwK64EyS0|Q@6Es^C!^Rd2K?qK4;(`YdG +zRhl{D1Pewds?<_Gf7z{olP?Ayb~=7lp1EV$EHqS3Muz##S3`e)xTuJad)0TekZsM5 +zZ8_h6XwtIjnd3}-76F!0(byjqE%@Egvx@VXWeBo{rJE!QiUzrz#xOS%y{rVWO`SvZ +zR7C&+dI&va?`L!3asEgw8!fcD74YGGWupTjVSt{AZFfDWnQJ~gvEms*wH_cf-Dg>a +z9K7!o6@W(V&+vO9e8>|5;eTu+`Gf%3+mc-_<5qoT!BrE>9hJSZpr5U=ah&HZeo3pp +z@?5-@Kz~|&f%Rm320e2Db18Q4ku}u_FLM%ENL9xu>*QURH +zB$=$+Vu9>H1z*KW4hhiZugZThM_S_;)4n=Fyhw+9&#RjP_(-HR#c}7!g-BMkdNCJN +zZwrIRx(4pp|DCfdio%r?#Z6!XcLJI2BXLgu<5w^s%jzcLa5NX|?ScdZ=+AEJ3AQKD +z3T>wBb5b25 +z!<`4cm)aguQ6Qx^!Yw1dCBSw(ub0sT?$5nt&nO^4V6YG!FixvbX$^ChW?OW$(D56g +z$UQ1WfC{jT=Iw|w +zcSBJc1Xf|bi*rO~)_8At +z5^Y_iBSEdrko5v~+cfyObbpldjv*#ebPO1FQkCMcemnJPf+dOYdB4#5=uRg}pN-wi +zPuEi2{r$>v6#61?D$KN?fr`I++~Z)W+*Afs;&7$quB`V2`BaT1i2r?8 +zk6ko9E%oURNgOVyX5CsyC^ySRck$B6SEm$GPKn0(`VMYHBu%~nx;UR +ze1tShsjv;Hhzl9KYrB#S?H@5a;n4qh?sE~bgk#O^bZ(Z0OM$`-AL +z3!FtsydAFIZ39Q)wfX-?<-vNy)9>`#q2Oo?*L-N=aJ?eKa%tYzBxYiEvB9M$nJx6K +z73J*rV)+ox*hIKexdmkT`Yi_4VtQeV>(e#xJ|8G!OI*byg!+m|&PcJNqlDw{%Q2lH +zfi}Ypqiu7IAh;W9oLb^*%t$D)H|yp+Y)k2k8(#k#w&%#=);0;H_?cQ|!oUcrv|$jL +z);97h^^I3X@naywV#yPhW{EHPFVmuZ)lVbMF3~Ac+lw>g^q6j?2`eq$71+_p{ug~5 +zJk!*EziC6)GBOAPQc{L6X=FRr#ieG!a^XFQ4PKkhg1E6Xo!O=FdlF$4(D4yo3FC91 +zflG0|vzl*Yt!I~-F&QFR^8~T2lM@wc<7SGo(UC8x@yLX?jqQ$~Hsc$q(&*E%Q0?K3 +zH}mQKBei9cH;Y{)!@Rcxeqh90UR@}%V<_)RX5S-RSwDN_7eIsN)x(SLQZLA?ss-h? +z^9}#}`gW;)l*@;~?1wNP$!`g*`r+H{lCT57y)AlHM3+Q8mTxtwgfe$_IiNaz3jsKI +zm*u7XJ*Iw{VByEc;Eqb@9COJ=Lmpc)fEm3&qb&z{u4H`w6JE|}kgxs@3BwwvkdN0R +z+j8ktAqk#qf)KBMs^R*)6~tHq1W +z#8-i3(RfA}$mX{BNst|z(|yu3X;*DW=qV3(ew2`fIF_{~i8g|tC7nsZ%vqh;7rIw9 +zGo1EJb)V--`YT?tzt#cj&y(&yhVZ}d3};~=@8UArFA24&_lp`2i;U4ToJ(=Tb5p4L +zjWA4^<9eX6uGqX}nOufCv&BQ;YzxM9gOiC2=PNzwqi|K2i-+>%1Uy^a<$5w4%o@+E +zMf(XzxFf}1(r4Tvo=sq6YqZ9SEu62-Z^fxY-@qbFi7?m&Wh6Q9Uh8^LOI8qNwm+qy +zWs9k=DXa;}1yG`K;biy&FDaV6+8g%opsn`7>O!w^rjY*;yvt1qi-_5-$vd-&e%;pp +z{>W-X!5yV-nq(L_bbOC`q9X7i7q9Hl;^T#eTYLIlaayv4ot1nDlltt_iB$oidy)RzLO9pVrBsO0Jaw}qTjQ0SGv3iOi^2kd +z@@kq?7AjmYihg?UJfuI#xR1|2z~vImaBrp*S55-5VJD`29pZ%On>7tmEq9c|FWOuY +zpQ`Ff)tZ)#CuX&2V(f<62ZdGlouc3S7Be-$G530`Bf9h>3OvNF%c?YO3f=*aMh%1b +ztSl&`Sn~pbx9d2=y+SqfQ`s8KP*aA(koM$A;<3G)n8%L90`Wy#&zJDmqi+_}aE$*cyw9U9~=*NM?oV(TkS +z0Jmp@*>TFLA^EUoV!UB1ht$;dx^Ki2`x5x6pIIvRB)JNy{vT;_ytks?!`Yvz+7ci5 +zp8-L26N)(i$%&Hu`8dvyrJCbMgu76Bg)}0YIrK1PV+C|P +z-!=Ox2=drIl9r1xAdFb400{bB^dra3O*;6>Pek$$T;RBm!hz;z>M<9S_vWZ;W&aQ! +z?2W36G+*#bnCZCqFLW|nlu4yKg*m$n#{Z>eRnJn;hkd8p^}c)

#G?rWT2@cGdaN +z;YKX}JU9;Go6RgI-3o_Tn6MXijm~)f#heqcBU1qRq=Vz=$6|n!Q_#^Qbg~l&sMIsJ +zyw65+=L#jAD$hBbuBH-S$V2d2D@0&M$AvNX)`zWi{Z9uT?M233ZP9;!-suOfA +zSJgoZI%9;?Q#;5P%(6=)uUPF)n}ZDo05jAx_i4)#W5RA^UbpFF3)HL2&M6VdXtZsv +zd4&3=ND +z%EuFdt$ndzc2brDf#co4BhpdU9vCL4H;`zS^6N&a24_v|A5fN)D+=YrU$#Te%-rGD +ze6wZj_xI1xXH>yZ9(J0;weJwIf#UQ_%Vf@nDjfFqEH_LCbpRGsrvRxxIFIEh!-R@?)C5oarF+TW|@$6*9`+V|vCI9pJV5VO6HOuHWhX=Mgw +z2~Iv=${F1X>3kNZWBiq%6(IY%T+w1+V!L8Kq>L) +z;B=vPS7mFSazy!yfGwiZV4#)1_6(j-Yf}Vmv4_dU-~pADA&rF1j{iUuq^#D3RRn?x +zT7#kgdW^PVH!rp=A&Ht9x;Q4>=gM36Gjn31RUR-pQ@zXQ#CNF8BKN`O*t(GcB>$Ft +zLhzT@`<6q!LZ!RYF6OMv3DT2$7np7_7YCWgv=QIl4?48BUE8D`a&^aTfsqfgyN@qlw +z5Qr7_+|rH!1Ia04LA4O+wc`&`rSq5dp1wN#8PZ8z?qoLW5cBB?o!&h+OtI+hav^u9 +z%Sln0k#1Ij*o&lLE~8cHy4Jf`JXpT%C^Hu9UWFQ@*PQb$7V)>Mk9n%vQi7?WgCFjG +z)c1aVt{ZP|$(fX>C(TeK%)$H%u!W1Co_QC{VI +zv`klr&7C2m&Gw-fjx1pU+}MA<@oXkC$&A{s{jr1A_N0;A@|win4f8&r#pdAf=s+)@ +z1O0(C0sS;)*zxt99z+=5KfP{-Mg;{H=l8_3(|{MF>?e0!O6ATc<8-KoxJi}K{Z1PM +z0*NeOzx0QLdn6B%YGoQ@;0X1G|Iunna6FkWj8n(8(5_9Kpxl^cD%R?XMJoaxYFJTD +z>H2>rq22erdizob{w+A%n08PxhUvd=`U&vn`!~(69(M@P--k +z)3gDCE)au@{wC(7Aad)b*aLYc^|QWkD*W}+6%M$OddcU+-w+CV>2=BrORnq;wO?=+ +zh30o&OIwd(eTEA+r24;K7a_)bsAXMzC(;hh^yU^pK_kENnxTu7*SnExz6+rGN*;{q +zpevvtKTn$8Q7NSz8`lYHs+;LH^NwmfcMLI>tiQx*P?HI94L0Cl;e9k%XmH^}FWLvn +z6v0U+a6Hym@L&TYSlfeG+z(+b#hz_0EWJr-Zs9E#Vy$r(5CIsV9bQ>%-nC&|Rd-W1 +z%V%j;dRIl?o=4mu&7&T-OE;T2*x1U8n%R(n*C6@YsgBu6IsYg0e#g7y1_P2~+C;DS +zsO`+@r5kBPfmgE16ce5|wqs*IJAMB?078zZdLB+P?-%CG9A@?oToj@LG2Q^*Szs9X&8Cf_^DX%grJ3kS3vjy*z)+Ac}FKubA1s2 +zJwU?0p96cUO~4aHRpJWw$HJ(X-y<*WcaP1VAem;VA_BNQz?eNcJwrtI;bcUo<7O;| +zIm5f~DTd}lf7a1=$tnNHDa04Lov-Ia>O?1=R3f4qniks_yU4C)`^T6tMn;0{&R3Ve +zDOBJYTlr2EYOlE=r=J=>5HEx`jk8q68zB}Qjm&W2-~UxfS!~LnLxh&R`vkEk5H92P +z!+}Lexf4J5yUQgvnprM~`32*Ealr5^G37UbrbYOLcO|OTjcvH5=!tiC?wJ+y!Rfm3 +zh-)O5mqG9btruK$kdq)50t_JQb*+J=qE5!wkvl7ZlfqdJI~R=R2^)l_;^BHz5@xb5 +z04G7rM61~*uNpvtk@EpV+x%AAnc9*C_*1{0=S!##%n%k{)a;JVX;w2`em|J0NOE7D +z>s=Cu+)g5a31Nq~zOYFLZ6{rHo8_c(#O{aVXI8pyC+&PWJJKxZNJnl;c}Xn*8BH`K +zhDhm?P0hE+m2+dE_@^epF~ZJ?yT{c3Y2=^%6bg9*;00>h5i;dtefA9O$uWq7NMtao +z<=h@R{N@0{Ufc(HCrs=@QTVFg(cc|-)6BaMEo=)yBSZy)(E_O}C3uk}EW0_j1Wr0x +zpS=0Cua4MLA?(6@{c +zC?v|6)GT&b5>#@J8P9JioS5SMuT!L~>Q6tWI8QQDHL#JaCIu_x!1gEYXqwG7VCh>! +z7vIGxC3BcIGEeG;3%@;f+&koi7g&GGF4@AU!b2y7IHLHhIE8fLKo{=w*@Qu%Ijtjb +zfxTM!o{i3^u~qOg5MBf;)Fw>`2DLkfgz=BQ3x3D2e +zlgcdtE)FU^>%ac133Af_;8nxVi~kErqEqid;$Y@g%W +z?%1bW6-Ynhf~{~+UjnSeu;xF1mx-oN6{ +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 +zqH@GI0rUQ|xceQe09~Krb1ZBj6L_(w +z$@3vq3Kyc!Uzp^4L#Z+1j&UJePawE3wEjBf4fcA0DUyidP<@foji=5l&s9PDK53BPu%T%LXA-=lAb3E5z5u_c%|TU=eygclxkuY&b%|myJ@C8DHas +zi8`=lX$1v^b9xH`7-{jZ+G%fF==7%!s>-FjyUx@QtC!Owjus-C6o(>gZTe*KV|h#^ +zDs9rbGwwaF9ml%;t2x1xmd-gR-(VkofHKg2+!aubS-%Km>lK(oijv}XARobWF%0zK +z^jGII!Sl`Q$vtBU<(zE^;@+j3;>;a;J@Ar1d;2laDxfk+mM<$GV#CErmcUzy+Wa$Z +zYUfWj1B?fVN447z1)?m+f}EkBU720bDKLd#rlV$C!XL?0-eq|@)+kKxKf=uWTo-@7 +z@DxjX9x>;K=9c5|(9@ZMGd8y;x|~D%_NL?EUt})XB^1ct`2Nd4t8aF&KE39{O=~7j +z`TUEheGa+1mW^L^YNKZ4;h0EV)|p}y3=ixq@pOsaA$9^mY5sCa6=Ub}`D{)kHGclNS5zvgF{LFCA2x(ULZQ_9;E*H10)ei{zr6Rx+KFEg&agH1SD +zDKdLXchoXii{a%bk5YYFIFYY=zfd##1e-2hxxS#HzNcL9tR%sPQkp~bfKxWtIy8Sm +zJpw-dvk9f_0EiExhO25j)ihx(d?`85>2BqF-27Bk`JFU!UKOF2xZ+nyjE3=mXRw3{ +zz#2RsUP>O3pq$0i!6Q-P*@LPCU#pzBJ8?#%jEN3Ww=}e*?_jj-zGHuC6rglA_&f7^ +zKs)RDgG3fmj&|BOW^}y>z>F^bM$TMIyZa%-<^&u!Rev&lYevIzRFt)?FyQ$^4)hfF80g +zXoV2?YEFoSh2`SbTMEINd5 +zO33Sb)q`GcM`g|S3#O#Wfp**|ql9Rp<%fs`0Xx&0(zOum#C3mo_WJ +zsWOep>80&Bo_dULogmH&T-FS+$XN{?X9S3cyM1ImMLn>F8kw_)vICa`AODQ=p-+4a +zM$R9b`JO29>E)2pa6!S*1x|um(Ik3?zMB=Kr*`%JvaMPm)TXdazxO!3-5xxp5O#6b +z=q6+gg(dZkB!B&IQ_AAv{6+WOLNI-VEN!aJFN9cQ-}a&*GIbLH=kZZ6YB!bE>v{FS +z(gi+V|JeRD@-b_LH_?|d-66u1l3?)FVdp*5(e*7h(*OXgwR*&-J5DM0(P +zOWju3L=Sc{U;%~td8>7kLqvQ40%cMs=_rn$uN)()BIX2E8X9_t>Eq4Z>cXJ{p9}$H +zYb%9Fra@QsEw?+u4W@>d1)UOD;kPW1KjdN6u(EpI^xb-u-8ITE+u{Yb(Khqx^UrQ{ +z-xWv05x?zZT_6`uL$Sray)xJX@Mr?MN-|20RX~W&;WUY<;?GR#sz-#$wGXy#!f`h% +zYoH)aHC+&TrZrSYKOR_HRSyx9gY{%-Fe=N{4fuBJ!c(3`C!8+{zF|U3xBuPDx>9gr +z43&2}&(zm?BAO}rkRdr6HFWG%1FcB0>fQI^lr^4#Ew^zmzj@P}jDlTy2H5kj32YwD +zWYD|UrWs`-n`x5#xY%N%JN!>P$TwY}Qmwd!&y53irY!qDkfpQ%B{ZX%G!rLf2IqN& +ziE1FbXIKgV`kHGljOmNr7_DMA(moRZ)a*UAbjYUl$yPuTrWy^Ape*Jj_w_vUs;uzF +zS$OA*SYmU^U%Zi+9+Pzaxdp#GXVi4&{)oRBJ0z+UFtc? +zT&QYh@2|7GuydVDiuwM2D8bqyqhBkQoDj##7k2slvD~%F7ILHsB7FbvAC2130rv}};-$aRLECiK+?+qG7IVlRMDN6$tZ?WSCzI~N5)T6j^ZO!cb +zZ(fwRLi$(SgI_n*BYfz2E^xRz_aE}$Ax{Ye#bxNye^~Yptq#+cEFSFWD_21a6acy| +z63B-Balp4A1~X|xZHBZ4d`<*N?XzF5I;a=YJpPk#vuk>^+bar7dKBvFMsT00?_iH^ +zTAzl<4plbcAB*5ht=h~|s3M+#;g)>69}_19d#Xfep+zs!86y{PFjymVyL@>B65Q&B +za1Py9aa}>Tb2@<~KUkv7rYwPfsne8gToH$h#19^tOW9JFYGC+w#$Vw)6fYQqxpvjC +zNDAM{`A47TfY*shj#95|JWgS(t(POw8Y!TlBpdb0m_6y#*Mmum9sxF+udCKO0h@WP +z<#p;vGjQ1#T{?wM@f8tdCx8|-Z6#f^=n#d#lZ8;HXq|gb?MN}@UA=`s>gfgOlxW1h +zw_s;&2R*^T +zwVU8qIJX>%f~~SbV=P>Yh=g9Yw(FWe*pr!HdU@OKke9Gi~~68#s@hd(-^reZ?DXUXI%F +z3Z4@kr2bBz4C{yT8Q5{NLr?^u)*#Zr0wyR5Fs>r{8I?vU)e=73ETqPEL$Vg>Gdg4? +z4-#jFIE0SXoLT5S@*6^8g{tC*0h-C;y-7=T2ip#EcwV#7n` +zxt!Gfe1wRt+M30WqcX=^U8xN*GG-`3M@`~4D>bHJauX^R$(x^;%)JNL8SR}t)QGtC +zN1y;Ex{6@(5gV*Uvd5JqBCqm%%di&rW_kqnykPC2HoxL&5A2K4uv-pk7fCDt9J*N%R5dsMXAd&jw?i2X0%wvo4~SM9*rs2^XCT +z99J9yrH^`x?%;KL3bFG+#kCpf`c4^>3ID$EXj=PXl%$?(4nf;3Y>O^Qs2b~27HU +zeL>-yL~M#E#MrQ6Rs4VAiMUFPh7({p(d)>ik*-zgK*5W@+HI{$h1vJE9Q4hy3lB7M +zlQ4Jz8q{ID54#F)m$xwbBmklR@vjNc6}N!ZJ6|yW%0m&oH>@DEwrAGc)=Qv2w1&Ga +z0T-*ch$aOGsE890rMo#acs^F3F@!?w((emf>-Hg?%W`u?-T@qL{nK`f2r +zHb#r^WCbNqiH6fyc0PU+54ucbO36ku6Lx3qOXAfv*gm1EypLU;ia&IJVhn6|YnD@# +z%LZro%DN$TuZiBQ_QII~$X27GNG<+A*`y*KGcNVP&WIaMW8Rj6UvxVXGPQ>dow<#q +z6qPWiZ$XEyUU4uuL2YZ=IF)%XfYklA5O6GLBP7iw3gRIp?iO4efb?M|i2SKDaJ<4N +z)$%G6_Aot|{4is)lXU9MnnAqbIXE~8exsQ*Th1=>s! +zOh^eT4B_qDIx+CJRS?Zncgi++B{9q*ZB76`>}K^%N(>Ew-#jYw;U51Fd#acMXQy(F +z&30Wnn7aUQllv=QHbIrI76YaOE+V`t#auRBI{kvBA|P<~`%L(U`-|NG(w}q%;~ZP9>o;I}6?jE!2XN>9B?4LZ#cPPTo0nLC{MJ|_7#oigiHwAhqz03H6)g# +zw*Fda9}S%%FXti>p3#aC=Q0TQf3>%V +zkAH1Jf5*wX6%ZM|5D1B2cR1{Q14#hJ5CoY?6Kn&xE%GgM%w{fOVND_At>TI=*!l~* +zjyNH>_E0a!vE~PqJ`s$&=?p5pc>era7Bgh+F}~6MKg!y>IRCiIB7iXNR>2y&^o&3| +z9+d|o0-PFIr6{RgBE0yn(;5SH8ZwaVSqP^cz8?oi~tT%>0&<#H{TCt;pm1Auyu!uuF +z2-BX82j`SuyGsGCDksABR)BCk&D1VyQk;t!UyA``S)p9t^bw~LppqDXfzzxnAG+JtmA6D)898UqxgpArSM5!a)wtEh|)MU`M`)}6oNXTppQ0m)g(lyYl)AY +z8*xh~j>F<8JGwi23yD$yxmk2Fd5-A*+jO3z +zLoDnb7wO{;ZyW!Va0ZbciMbZl;X +zF=C{KMPBp@!TtQ3sHYjzOQtnj3pzOnV%YJ!G7(LC_V!@v@g3^vW5C0`-Dt$BLRQ+n +z?i}Su{PU<@m=-8WZHX`fYTsqRKRI;_kqPwMKMkk?V7OkxJNIuvFD&0BCfP`ow-*+r(hpl~+MuQ!a!O +z?9#CNdpj$6*2bwpp`%IM{t;0sag+dG#B|xEX +zk(92_nX&++i>?qpd;y9n$hX!8pe)41k}Hp|b{)z;{8yU!G~_e# +z)Y!~H!K^pRD|Y%AJ!WBROLMfDwC)#t*XTW|3Ims&^Toz{F84sZAL7%E%L1oiabzjp +zWX6U9%-3&x88JOfrc*?-0*W(e +zd+8#6>40zIu>!b%(C0tBHF51~)-^Urx$1DcR+a`yKYz2bgYZ2Eu{u|W99T(D45`rJ +z7G72}V&uj^^d{9dgGXn0pWQEtOUeh{f4*sS@L~>XN&Tm45Zj$5g~0Ng+`T*pB9Y +zMoU!Tm8*@7&s{TV2!@}Sd4z&XN7~;fjtg4*35=`UHp~f4kVeZqnB%ZEa{K{G>3&2l +z8df<1P1fr!2TIKI7)D*sleR&p+jDsujVjogyK>CYs1zR{?;F;ZdCZ$%yC@E(XCiRq_!3)Wu(u@$Pa@#F0-35`Z`aibU{x#7Vys!nMJ}Odjb)4_YuykrQ^H?=^?JlaX3h +zW|2$QEy3*}5Um(T-+}yx1rD&r6!C_k`qXFhUkJQ52hc>m`q*O8F6j0OSb#I=UD|Mh +z +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 +zwcQ#Th72uU^tZ~Izwr-0J5r8qho +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 +z9@?wA_L+lXAi#Eik|)>dKT8 +z{$4>oChiC8gU>2^Cc=?lBI%OgF-eH-cNG8PU?25@so!YOH)3hQM`b9ZkY6a +zZ1a&hbeA+ewgC{_y5iXo<02ZqxxU9aQQVY1txi^1NrMhF7>2OQe4y9ADJZGwgq@<= +zB#bE}QjB{zeD!DRwW_xx78Y8%69gu8g)CO+(S6~lv)2RvFRSW1+1}q5{&=<=8fX{n +zJ*)CDMRuQD?~F=Ny&g%^Z~nBE2&_ZD?^p1T?h(;}zbq35HqzrJ +z{R=XWcnHaJC*k38A=wE2-ZpCh(VtX*yUZ@u*OA{aH7alwIDXVcQ`DAT_qzH+@(l&a +zdA5~!2l?3#uko)H5vhl?)Os}K^_uCOChEPHX1m_jpc;_p70;cr3Iiyv`xazU*bW_7 +zR0fLsbI63LBf=twHe*!vPK_Q#Ql6mftU4}kzv~x5T|L6 +z+?q?`BA<*D&jqYpg~+L5KB%nG?Knl)tfrsA@(z2n=!14qg&}nu{9Rr87i2(koo2&U +z`N4-sN>V82i>$41WdLc@q1jV~DiFU^WPIq^Wvjle3X6i`_5!l1EtEqU6isGYuK9~T +zi-QZ@ZeBxP@2rm|d{MS{&bLo}hNw76ahFG7xKD%OHq@^{Lo2X=1dvT1L)8nGKBj8e +zBwOx?mKS7!xo84ms@#MQjuw?ZH`7xHQL}Dl-hYj`k|}YKW;LidBveVE;LTv4904hd6`00Xwr6uV +zt5%t0EtX}TW6ogfB~34rrXp!*vkAWYQ&H#!rdDk-wAE|)= +z#^m2zv+&Yd;j=G~w7SIma#9}&gWl!C*@b=!KU_4LKgl%?5kAUB`*H-sy5n1;Bv;fV +zw_9m=SnLm6-+kGB>IZ)f@~Zh(Z295h9tcL@WtS8$vubaCpd>Z&RV*alZzUnXTgCIF +zc%u)pfV=E5PL6T?r^wdXJ5ndTVzHc+jH2M#&2_Xuw@BGOvq08__{us*UWirpy^Y|0>paPx#{!ir^7h_j0wJFCE0_654r>}F#OWm}nxDs274 +zy=_M+q9UgQ^bOLP>Z})18=jBx@(dJkB>-hOw|;OnP=<_Q(X>Q4rV;)doEG%2qcw2N +zJ?S508G0fE?yDHu&B5))jMM*n88T=C&5)^0{^UJS2-h|V6tJ}Wv_%fm{U+Cd923%J +zScR;?Z}x`qQPHW+^m7iL1*aL|BP%XjAi}qeV(b-r=k|~VslS*u_*163)`}HDt!gYo +z+JIS`t(f_yti(YinHhQz5hR*!7pN2bc|sD=XJUw$Dys#t>PDxa+p|gfko&H*c7yR& +z1GfS)FhemCKLS;z76T +znYkiI&%@e?VWUy`o*2XY!iD7@MnNn5^T(f-9~$6!E6k20AL`Z%D8Z96>h^?n1*A{&==Rx?@q$etVM*?z~I^9pMS7Qr*S#H!)8V$Wcp +zfCRPYXUZwdhKsBC)^R=22CP!H;U_SyWRvKGI7T)j+Mx97#KXIm!1@}&S!;*H(3%)v +z=ra^dek{(d{8wf{nLmpXPE1+xEOYjx{j{V;8?v{2%mPRR%<$qbZQiN!$|R_AYB`(0 +zfrVzZo&~jFmk@>V6qj1rV*)gYh2lpr!Hx2vHXt7$TIxw=;CJkKx03*HY^aywmI+Jk5B|)x+MoqKij=poL%(d8&Qk +zq;wi9Xt%h2Sy!A6CQ{Hd&X7=d)P|_f--mslBeXLqE0L|P2j3_A4=5xudJV&zsNtd1 +zd&nJpaHGALv@UId&ufy}bh-6Rl;0edpxAR4;313V{0P+7K=@~j83csn2z4)lDS?=t +zh&}?m#D9L?cGC6QWrru1h&aHV7^^|e%-2ehNOqky(W$L(X}Hv}iHYTfR}`S#!c&FG +zWJYt(*WBP*Zrx;q5)Kp7zyk_}XTbN)b8*v61*~#lH8kK69(O|D4=m#he!;X|7+r|6 +zIu-b9!%om((jq!BjQYe>lQuN%z;)XWD|NTi)t&O)6Ll>%X^j)`?;u8A2CvS}MpBw! +z-#XX@b!@JO;s}4hj7mKrD>4Kli$nqbeI!;jI2xDHwL5g()W9jj1~2u(EfbBpeR`q( +z@gZD^H__%{w}H&t7dA8%@1nLN5wvZU8&q7X&S%lr^knD_^QDk9yYcZVkXWr3v!7rH +zz-XGJn?&o6%dj;%NwW&QE{pu}S5ZQ7dFo&L{)ouz6hnt2k$JT11FCH6wt-U?o9>|e +z+3nL6=B>vuop!?|qk^|R*SCG>**!AWB=lC)KeG@OC0zqK=g&DykuEAt4hK#IA6tc; +z#`vW&)CF=4kuM6*C3zhwqJucM)|OLq4S}M-#a^7)r5V4btFnC34WMC)YND7-qy&d% +z4NC|gGVuhm;@%z?|?d7%U1X6Lt|BgWFgL +zv><{?Ym05uDc?(In<1Zu>UJ{=8svi*HxbS3so9dYdR5QC&PDIT13nnG4k3vAuzJT1~27Lf^|E~Y?AcQ~)zFG`S?!UhT^#W2Vw96WZ +zt_+Aq3OGCW6Lv5|lCp1ccY{aI)tsMeHa@WxxuHELt|^XB9E17a8l4`Kz4#bo9t1TI +zCJmAE&D&5KB6>xjX(Z&jm=okL$2aL8ucyvD%2|*rNx%~j9^JJ5Npt}L&0F%^H=Cpbun@w@}PJ)Vr%cnDa@sI{c-^O1%JvbLo +ztbYM(G5ovW{MY2rW+w~&Gc~*sfb)PDmp9K|#rph0@~KO588z8=Gw^;Nr!udaBR&5g +zOieVsh{Cp(M5}xSe^eZAa|M--3pPh>i)s57bc*%fM9is4l0IaWWZo~|&@>_tSJsI} +zp(J{?UnYNEF=!8--*fhXowq{8*-W48=g8+=K5^7RRj9=W5>;$L~og&e;4t;bmRz +z{ZpQwGMgt!OjRHZklD0(5FDn^*TyJO69xt~t6$IU!eo2@iy`G@P#~UM7WFm?&ELt6 +z*T}i1cBBIn0=OPj=h7kaaXwk(9yaTP5mCi}leLw53Fs?VCw=jstWF%6iMP^{)-aL_TXb7cbub%%8bIcbEFiP1!=bW|Z4}Zrw +z(!X1R)lJ<3!o_t=fCRik#K``a&ABx&Z4)t&g7;Zc&lnoaspERty6(PuT81{M;0%|f +z>B6~R&Jb!F)M*_BPCJE3{x(>0xxj&N0;Dxj#3R*wSIG$upGK?|5`%4Z +zHo#Qu8Z!nA)XAy5gGhz>oemd~Jb>=j#w$*a%1++IYb&TY)AG>JY&LXk3q;xfG_JFY +zVPA+CglRQMi|Pp90k{O~p`*(QHLv#M4d^x|av^y|PH5)4abY1^(PheMu6`tNv=7=- +zxv7{lJ+L7-=*cS-&s^eoRy!o1;a!ZbN+VbzvMUqzs41wjH|pUr#kd)Nv{5-mRigI{ +zKot0QkMsvQ4JYE5#UnA0M3`7q%hBe3ke9W2{<04*phTgtZ+pM!-+#_o&oQyiY9yt; +zAPG8JS*!w71vREr0N5QLRh}B3aa!o^hku{d6{l?OvGj;d3K$(~}cu`<-Egsyk8G!;K*?cl&sA>p@ +z8e}8lfFFV5)>`aOon=%pe`+X0VAx1eLQ?D|P~EN=-`~n^@S%qKx$o|OyONbnmn7q4 +zjJ#_!!>Hi4GkZZyssdG5e8eVk7{2np?dgxKGH?-K$X>~%wG&r8R3^x)&|fY7KD1&X +zUjRD{Bl>qbn&LguSt0}I#51t7%ToRm0=>vZCoY{Wte%hEC9IIluH-TNEnmg6TW|pcW?D +zFvF#%vaWPxFY%bSe($<=SDrkIo<7zPf+2d0R^3CKcE-4>+GTYBDxdegW(qr^TLfMM +zegToT>eO{9WgX|7?^VwIA$|6_&ecA6IMdCp35oI_`~L+22~`L2#6XjtBJTQ|E+cPt +z{xC8ak~nC~XKp+}v9{xAMpq67=r5A^sE(X9B* +zkvEDXLo(m^#DwAvDrBTUKSWlx3?pLF)`hl9jJhhynwY7zd$6e+CVb?qv>6`W@oWrmeBH1ER4NG9Z=7IfF6SJyrdEptn;NX3#>6JEE!gwK3{uX$e| +zu>qO);l2=MUUcDDkleWysBg!CsWM}Gwr#kt#ab!SuCjO)QTZLOp)xGg>46g0{=uP!Lp;{lnmiq +zd?~HZfP8@9O_J0sS*X +zc+Odm)#FNo5XbzgQ0y8(T>E)VqW1I3#w#ObEA +zy6l36ZhN&98TF3h)VAwcYFDBs+V_0^g%d?eFAkS>~+j;S2ti7s+8b|+ +z?*{QVSFXAu36>LBNyMKjn*8HY!6J7D^@Hb|(?{IK=HOQ8F@+8=kx~k4Lioy(y&*{F +ztXtiZ!TM%~_a5V~7niEJrEZw&oT9t^{_Gu~XnFn(nb(KtrEPM2!q}srvkA70jKJ>p +z=3#%j1!&kk+@R{F`zL0WSxWylv{DdoF&S?9k7ZwY&W#T)bdhKKsOQ1I@`iO`UC1Fmbv^YA3To@g2oS)om*ioZbw;z*m +z91=3wB__3LkK6s#4D=zz*|_WSy7_c#on!8kwV6DzKk1)cjVsMG%7Ao1u5^Jh4TiCp +z78D`m*Xjt@Lq=z*QhOeI_yeu^CC4HLdXf1wHT!Xwa?4>bS+8k*2Wd>bO1V&=K8~`k +zkfcT4K0{E@nMS-~7nVt>hIQvu3vA28m}#l9J=&Leo~~#g8ez=gszhoOW3BN&*!-o^ +z1>=sLtyU|m_wI7}DN@Xy6vR}Unqb)ITX0?I(iUiDs0T;z9Sa%m-1THvkX8ldoaClnb +z#qt2@MsSS9R5eF$m2^0_4aVJRk|Sn#Gw`X4zpqWZ?w_HBdO!CXsj4EEP6?{i2LULE +zx}U(D{1g>5B~8hbG_W%b>R?bc?52NU`%TRG_m-HGI>qSNs(6txH^tw>{+MTtm2Nnb%i +zPaKbPj~hyY{<~NM#zzURDzb=+;eRa;{BmCETs7ZUQI +z3=8REGMit`NJF=a(+0SQm2~I8k^_(W2P>l+u31KZXXAn#PtU_P_ejncVo6=eFb$$6=>Ifi +zhpz-~s$6j#J-IG>`jNdt+U_^oO$e)iT9SLm{87o_cjkk~RcIw;DJygo!zUw(Sbx67 +zdK^^5ZJZv6L;L{L=$E!)bo?dZKoWmbH6U4h@d;65_WAdWID;G#firIDp=N|kQz{|4 +zg@o^E0w?RfwifNd#@ut&vEIbZy022k1>gFhYp-O<_W_hVTeH(6gWJY!02mY)H#WKN +z`@*sn&|S)hBKtPgkura*NJq+$GvhJ@&hdvB_)Uih^IbE_pi_q}_p%zi?{W{B> +zwY9mSxRU@Da%?7K?{h9FC5MC#xr%6J6AxkSP@z)>-IhWyqKh2Bx(ZdSkM&TQo{d}h +z(_2XvQA2+yVQ-!h@wmqz4VB`nV>nDTPfd|$#99bUzxV-{_G3u`AXDW1D^+ihO*sQz +z4oMFqH7!+EpUvAIP3blIo +z@6jd{`cnhESXx@+Gs&S;UJ|!xqql=ffcmI~WJT|P4AwI&4dEOa$2D_)G +zxuV==TUD#0g!0lYf1qIdDfn~HUw@Xj=#W19=Pzrj0g77I@+I_3)84KK~D(_kZ$YL1b`n*pd3hefIr%7j@i& +z4%20KcF!7R>V)rYkl{XN!A-tw(9Q%@L|)(2V}180As#4}Id&^D7;Q|X^vQ`=6)rN-z9*i9WaX>!=AYH+^cNbs-R+tDAg)xLvf;( +zoq1jWV>2;l1RBujHRlPF8wvcBpGd$lv#49=J#cp>=F55Md~S +zMgHGid<(AL#_t4h%cDuUs~s`na0QU#A*;c_g2#U{v>${2X6@4rv%ay5bIWzx9wZ(^ +zH-Df5Q{hz0dtG3fzv(X^IWv&{l}}XbBdd$T_xFI=Z4H*`Ubdiwm^;oH@a6l-D7vGv +zRzLDUbkCH&A?Wvuct}E +zks)om!IpH`{_4*H=-*dP#iW^;%NOK_pSp8bt|SybY#dyE6P`kYWL)v&%|&AKDRrjx +z)};>Ib-3tyua{&YOCn26Z`Y^#=#Q=V#~D*b|DVlhG!6%~WXVY^O`Kx^!@@N=il><8 +zaM-)DZj!F&u*G>p#~BA6+tDIcni>S?fYy#Cf){9?48Bz~#av +zRuRyL9qe*9rNEH|Hlu8wm4xee+CFnvkl{ZBTuV8A{)3<_f#hHCta7Z{?-Kq3D-(DC +zTt5{r?b>eLCCNQ$)aP76FY0AaFwB_6W?!UYa+Zf2T9e^Gd8fj|?&Zu!tce2NEO*lM +zX3%+OehJC1qlz)=1vdiK*}n!)^ozYda4EuIIb9QPtYgVbN2M?5IAeo8YC;xngaP+> +z&K9D-{jG_A&8i90l{M2=_8;&3Z`cJ&xg6Icn4shDx$tjs6i*U7ixSu{sJnPYOtmM$T-wew4k*k8%V9 +z9-I{9eumxepqn2FiKPmod^))p;13|x53@1V!O<{32HAa!TYZyJd!U>1*zs=4)P$8b +zX1|in=lHWnWHf(;bqpm@sEYq6vNQcxz;`W7!|)^6IibOe?P)kc2M9L{9^<-V3Rzbm +zJ~*Jcf7)>vkFC~cOzXt`hFkWdBI=&2y8o*=VgL#{_d#JXKQ!<$E6eO>abOBi<(TMH +zveU4Ag;vNoEqEN^)Ap$p@V3FTQ3! +z7;LbAhW&~<2B%9iWUZj;ToGbaW#btiCYl_m+Kr{A&cKI5?H` +z>6C?k-7q?v11xxJm268xI%a4!5=pdWkZTe!Z0ug6z=2Ec8r*^n71jb7mbUCse?M+x +z*W?;10*2|G#JcWypv~_Q@hGkC@`WS;Sb=IM@e=q5nlD#?CCmVc4M|bki0{HXu=*4@ +zKB0gEB>B=g{1oEUH`wZ;y4FYpz0wQ?6FHk`7S7`M-cgnLg#ZXXsR<&iJz%AO +z#-YE~18$G(YBm1y|GoOzz^yQeK>AsDT(T#9doOmlwWC`{>5M;@x)d@7;3{h2i(=~9 +z&5W0_5liPq_R5PQN94C2;nQ~GOjhqm)-?4$g`5fnVFh)n;l5lS(h*pRnCGD6?es>uC0 +z7$!nisx8NSBTu89M}2(KhAgUT1rhz1%9nbrfaf(Fv^Z|B@{o+;w(jvpg({6mIMnvo +zHT&;60=AvtV+NI5ip2wUsZha+1kh2`9})LlhTG +zA8K?C@#PVU9O!KSh&BdE3i8H)hbMbf$S)xUQuw{!9xYx-W*AN>gJnEh=*x{DOFvLs +z4V9v~x3#$JSqxK2)YKBemrX9+=^uaFJ)_l8Cm|dT%6FDmd1;>DC3(^=ADsaH95kDJ +zz~t8EV_C7#X*N|rej(XoGm=?}B-s+(!)r|Ilb&eL6fbdkwCKS_%XcRHoHPB!TcYLA2G; +z!?_iRi$C70{)Ivar+Ih&K)3eKKy1hXEkY}N&QX6@Xz2p}FgLF`e9Z}F>w$Ufo~K!D +zmmB673{=nUc+MYK3;0O`)XB5eaVp^Kqn~_)HM69S!ns6isW1VV>~F +zp0z*s5eXUh0iq&BaHbIJaCja%`vUxYjaoTjX)S6)1mHT(!`)@u6ERk{yZ~1Fvkb=U +zBO@n;d#B5ANQd}S*25`r0nqAwx*}sm6L2P70H-7_3FUgc%`jpL+@VgEkNTTzwYH86 +z*Ke(mX#0Dp)4@_a^e&@;QwJ}%6OV_|fzl5ce9?&h9~0`EweWoMe!-=TCIeBHrb7wP +zQ|uk2<275Q2O&EE71_P@+a`5stx7Q8BS}fiDEmBumb<<}(7)kBlTtJSaT*IQF`RxZ +z$7JhY9cUiodi0%LU!__mJr0HO9`1jvd46;^#`I|YUIQ#WbWWS7+LenAYB3YIo4yGU +z=*IO;3Kz2H9 +zNnlYi^ZDa>_tuaS1b(lqjrOzqOEM{fSL +z^d&J{UsO4qPr4iUmMy}QR8CfJ?UC9cR7B?R&ive~_WCHEeHuQf|D3q;9|AKc!n(s^ +zkdeItr(%e|OuUqQ`eje{-6~(9Ll{{K;X^3~nvM#J??%;(fQ(*szC7%*e=Jf){t-Fh +zS>VU&REyai`7~5VL`!=EG+KX%Wu)kq=rCJ^ +zBQ>|G>`(wcnSiM5&{dy3`rvM|0-o)3q`#}v7VL5u3mJ8<$GTsnrNIQqX7x}x>1h0@ +z(|k7jDNOXJWB_WXzc;{dTr>`B{!SRd{(-G)p +zr?}bDDNl1Tw$U0LR3tYFGCm!Vi)6M4f70uMirw4Lbb3(%C^C;=H&_-9HKv`(c>i9) +z>q=1TZp-v;M~(F!m(rrLSeskT4*TzZ1Y{U<>}9430kQOs@%4~(AXceTIe +z9mq4AoWeEclbrCd1YKiQwJ@3>&h)R)E)66cXkaNBX~N?K`_ni?)}NE%5g-Oi46*P4 +z%U@G>joqE4>9rPXU=1)_lDtUn +z^~8&YMm5fnlJZ~1`Z_9ydB0WhVwZL74OZxDAtGrin#G%sii6QkU-~)Km4z)cqLD$9 +z&RL&kWO_rhOXHrE5%mon8zGmJB}k@F(R_fy#GR%@sMVo +z1xL`tpY)FG33#o`gWn~#Q!u@o^mI-9&8EQ7i}(P*i?I^V*q1%CKYg*46(?A +zJJG24zK3W?efVmPd#Lqc{^3Jy>w6a7Qa6t!8St4@RaEG9Ol5)HrKTBjJ&O?Z+q*At +znVFdvx}JFD8|abSzV!tz>nLcE=)(4BDD2zh=r`||+|{+pQ^WbSF!pSresN2!Uysp2 +zCbi2q8(@gK7r~l2Q8^0Knx>ozA`~n3S&F@nUq_F+;T?h30;yu@LEIb?5<+jM(7p{A +zWcdJ~!k^$D8E2%hww`D2`8{a_z +zb`1F*%%caWs=bn4aKK#YYUPL>E*(%+R>&dA1sW>Td5e=Efpd5EV*++S5o%jG|Vw=}Woo{e~6!7=Ym{3Mo|FZE1K0BU?+pI`sslHs~MI;oi(FCxDy7bPYB^#Kw@Sm%T2^pSI}} +z>EoQ?aYnn%O%2&2-WPKR&u|(VDPzX%;SO6M&<<9E=1%?F2bTcwxSgB|MD-HuC#@}; +zUJbixw_o^@O42(fY)e4frY{eY8g$vaDl4AE}Gz38(L*(qWez^6eT0%+G}P>(;<1_i(21bvXAa}3c*4B`8RhL@|o_-7&g}pVpv-EhheB5dcAMedx=ynzRUpV(;5F1DBp3FkBI{dQ45A7nSZN +z-EhCZ!MRZH2xHY78%_>c`Yv|m{F%%7!&Cv#W{8smN(ZT<;6Dm{5zquSi}m8EH(Tn% +zDZ$iNEsm^o!KKpN4;IBAJl5Rxh9huB-3iXx`HPXe`uu1%!0yCMeko%6PY9jbPg+3` +z(P!VfO)t_#Y0RJ4KnywD+LvKisCD5u-|$|2x*64Rr%c>0vNYr~Z28YWAHbV96d!?2HFLSn6}#YP?5aB4<1-J( +zygAfqrETKF$P*|QrH+sC>4O5Mx{LLSKRbGUypi!_l>=Pj<9Vv0XhL|plj7zVo@L8S +zehkSg^#(C>cfg34GH(m@@yQej^fX+IEY;CPO358ROILmG=D)|kDGOU5FlLFCOiFLP +z=AvyN^VUNjb`apyS?|HT9G{~4eV#GU6fI5XucE6Q)kv-3d_hiq_uO3F71QfM2#2Mp +zGLrgy_lYrC@=E8z)hW9mqG^!GNZF$chp#&`_*@Zs(Se`sRf*@}43{G$t!&E^F+#P5)eV&v%&V8kMpVF!p2}H{}9Un&X9`UI(kg)*aSp$k%n=%E3ijI|( +zwei+fX3^?FwCmM7i|Ihv91mYC`+N8ZSmQL5$Jf(j)ucdmNf};0*}h{*$98CC5s1@0 +z5RGX<;=Eh!KmZWNY)7*f0U;iE8zdLTOi5NJ-MF3f`rZ&mxgmDlUFd3D%P=WLAF!pV +z>9fYD*zV<6+mC(px$bFxJ~o>&SkX7_mhjB%YW-)A%?74fY5F|t>T|!X=T%p7`-ou& +z&4Lw?LKD@aj@gC0Hg)Ce@ogI1^J%|6?5f<(vYV5u&xWn41Ab-igdt2urEoKeqO-m) +zyH+!}sD!(SqoICLqv!;AhO`4Krbse%m=cWJ+%NDj=8>1{EXqg!sjDrAwh@=HU+JOa +z+TZg$QU+DA7)1uw_BuAmRv&%o1C8c)|vyFg291ruHaQRymEhv@si7fKw( +zzEJ$7RjO*ZxIg0qJz@oeB-z2O7TZumP_!!pxl5;N+Bj=K;W|76Ix5_`pZ#Xxz9KK# +z6LtG5*zIN$6%n-IPIpc!fIpC=eTTw5qk;v=r|KPN$z)bQa}EWw8~IBsdS&;#FcZ5^ +zjtf1vR-G@irT +z#3h8v3cJa8;LYoQpeTIJ#!mzW@cBh4_}-e3rDl|v1)z5`041i#Uw0M&z-kM?U)<6< +zqSrgfIpMM_-`bChebo`cnu+)8voRZ?%qhCKLyN#!pi3ZSpgty?A?^PoTPAA^W;lWi +zo08sQ7QcL7fZKA)O5G_edZ_lXg7u4>#xXDE0}E4EzRq{de7ljTXDY~ws??U6*uaq! +z#N#`lQ9+usorwJNL9vIZ6%6uXZ|1`##4LkfJ7ZbL?1tXGHA;MwT?Ela0AkC$9WbG( +zuR51qh?L0?0RH6Efzh7MbrSD=c7Eo_EuhGbQ08%FGqO&yXLORx*m>vO +zSk1!t%2!))PFfhTrT(K4|BgFS^J;@>)Xqi +zwJ(P*LV4vT_;s<*Pqeb5Ds8V1PBSfEM@1-6Mq{us-0R5<$)Z&>L5bfC5%fx2eq23R +zI1pVdN&Vof^ML$?xnreUy0MHrWiqSCH(wN^sfm?wC3)Ekl3vS*SIkq3DfRsxdOM#f +z6=23E904R$-jbGC#}Vn*dNU0AeJ)DCpW5g~@|Z!{3^^)zmtmk_F9SN@Z2b93YtY8SIvo`j2XE0&F(8w4S$2y$lWQJ1(GVPjB-eLN# +z_vXSJVK%Y4drk%{J~ +zR+i#p4H!=O+#$Y4iF@@RBPTJ%t4O{(Ieuk&;Z){Ntyl5Ej$ICe60ID)fEHKjOc*W) +zK$fnxjOY*Aoco_a{}z%cz`V3LJg#8*fqF0j8H8wnXjrfkxNAhvZG>nC&pf3b +z8%s1&<{;whYs>P5hh9l_M{XTgsU{X2S6?pb +zK7Pr5k!;_Zi`WemHK?+)(|-K5!TW@3C9&wXSVa1$^f68UCkM~)X8~3EH1MkCNE+uk +zP&v(>GqEB2(jsqLu+Iu+Rf?NBDyPN>1YeEZtHFW;phg79qhc72c0q)NH-4=$V!?WDv3}bc8CcfS~9Iqq5k+F_PH{>G%ZTKXLXyU +z$J)v+dZc7Z_lp6$x~24&J$NkgqQh$0G_2>I63_^XnMMHA*bJQ*KQz&qoh7(PfFzQc +zp$w~XiJEQ0Duq&Q9ZPaO7Lk5SzYc_S+xXoM=AqxD`KaFLP+~`;r$b?=sAm`oQ9TFon +zjnTl|@SbhZ+boYaw9}d=L$`b~F1J%k)tz(v26)B>mBjDja0lW>om_~9f4U<$yQI== +zR5xZ8`OzBudo~2$Ds!tV5AG{o`&@o`aKX95dv3-yp2FKen!w+5F?GKCuNA1L19cmW +z8E>v?%R-6pl@g^#Wnp6}AZLYvxq7SdP@_!*zYBY3u>)H+qaJgVjC-Xh_&@1%#o4 +z;lF-XD9y01mUhNyN~`nczPM(C7J=cY6r9efMA40!e`in!x}AYS?z9+-YSx0pOYdf< +zD6;M~@T+##Ek*lwS_Bg;&_d6h?S|L46TWSTkKn=$Z;}rS*a~3UZ4qJ_3E`@i3`%`& +zGp`wU#lR{r@TjV(3)ON++rJ(!Cq(m-nu{wq0StWCnr~=pTB5-g0s>gf^f)Bc&UBrj +z9y}I|02ib`oCPmlW)CttTva};h3dqQ1_<1=g~ZAWiKiT7iOyh1IFHow_^CblUF|5ZSK?IqIZ4jg0Txl7Kw3Z7@H&c8)*CuLRz$qI~Qx{T2sR-YR5;>Jb +zs+X!L>paKY=+>1zOA?(Qz{(7hV};0~rVC`H@%)5a;@_4UrIb%n@KB~bwyC3b{Y +z7EC1M| +zEQ=8@Aa1qhp$%EBAIoQ#OAP?+E{dZ4LrA-*zUmm-EM!MXcGL-EDb~a}1Gfcb6uJxk +zBsqLui5=y18k|Bm6<=+?U|Hcgfmw;ptb%kEz)8sfy>y#hd0vJFoJ`UIfn)+biiPU> +z4>@cQA;~PILxJHi+8K3celdhDxJTQhqTqwrNj>Rz_-reui{2IjC8H{`T#OfHc2}?K +zw^1XV`>x-r18%8k&0+YhCx2iz+8Z1;>hEMW2=x!E&qy!C0@mEzCPRN0wOCZCPOd(r +z!@@okh?MY#>9He%N(yWbbWNP+u{vPb$|sefUI|{>O|eA*aMt!35(GMEGbFi^1*KDy +zxqmTx@E=ubUilT)#PSrTwF1DYaFA4KE2Vvhm3cYCxJQ$i#GE5mlbU&~{Q$0Y`1B+h +zO`Pn0Wq@WyUYI@cX*+Een6AG$gsC0_cdJ6oy@_0}S!F=)RC(#u1L%(+J`0Y|hg~z2 +z?L{_8TUDMfgwSd=EyB7SKPKQi7KkrC^ +zgaF)apna3JioHwQIj6>=k1SM`*+P5<*3R1Z03)FRj>k|q*xAThnkQRjQudvh`}rsy +zLiWKu5nKtz^-L@Gx`l);6_|Rw^4EE#Hb`m#N)~|f#HL7xver5JBo0l*q(Mc<|G!!r +zZx1)rS^W*xl*VvBL|n77&Os&qnoq8;m{?iy!uhY1?mekyr8OuQRM)M|?XVGOh#A4M +zk@6QC+9)$AvyV6o@!<0V{LAGed +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 +zMCvP`1M4jMJJ%rQY{RDIV&%49yTK3?2cwPW~O +z#4^7L)|KTI*NCV|8!`a6k#C34k&Nj8@f*DLK-jZ?(|?DQNcC+FKh*cpP%H9hNjhE= +z4Nqw!_=SeHu#{7rv^ib14N^y0!#X%DwTy-x8$4ZugUxlqOJEw*UrX77<5d9w|Ho*Kd%SmfSDi{-=DznRa65Zm8~nC +zHz-OrKyG{RH=6~|wBAL@=A0Zts-_XetGRSORMyy6r+%Onk*bTB&F(8{rPUEX!(U#f +z`orvv1WJ|Fj}Fg;hK!gN5HEUs^tnBR>T@Byp=)y5BQ*&xU +z8nWDSvfDlY$3Eng)ZuGz&Hq&WS#~B)NgWmOC`UDTZhehre2i^u +z#o|c#(th-WYjm<*C#}h?1_3&1&phNSAvZga`{T^7a5zDStBxIrD_RORs#~es0@;!Z +zzjbrl3+e#w3cmMb+YQY*)H#-)5SUwXEH!O$(@Aw2{fbZV2J$d6W^E5R-=z6aoN2@Y +z%vbq?=b?0W!Mz8jNs#FqA@^{1rFvF*l4u@y&eR&FYd?MgibBE16gGJTWxm=efOxo@ +zwNriKM5x0cWn;c`d|cQ)Ju`}R5TaJhJZK`x(tp2^7%w<79p< +zv~a|&P9R?TvW4Xwf1)Nhkyc1be^iAdX@u3)0N^404^6^ORAL-ISZC0oKkF|13ioD{ +zriBN}7bNsq9vnRZP;ZQaY1Ch&n>t1`3jx;9KZ@&a(a=$H);U&8vavnjm8&crt+ +z2F$&l$;dt$=onGjf(ku_G +zQ*9l1S713g{h21xnrDZDz1y%FTNKR(n&^nph4z==pA?kLOy`IRB@5X92R~<|E-^~b +z*%SSq?HjpFoY$xQwV(!7VAH{I+VfCC|1oa +zx#pN2{c}N6pKWtUniY?|A*La;%xwv7rU;e@$we{zx3ifhZX_p1rD{N`i+d|UPJ&$; +zph^)l9jkd5AO(SOk-lXEl@?^eHU;$eXRxvqkX{lCx1_BUcP{PZMdzA<`> +z_cm}?oE&c5J~AJ~2JtCm3|sclJm=qb|BtcVUZGKd0rz_3oC~hz8|*bj7S)F9Iaq1* +z{Qi#Yq{A1*3`wN*4+8|!JO}Xb{QQXneV=LNur-cHheDZo7vITiPMOT*E0|ZOJR7JV%{8S$np#@XWp_Z?$6Pg|Jj}b#_r^)fn}P +z*CnTC@<_O?{&U2vQvVXmb&77wWI6-~9!z~K%|~*yNWj}3%Nfxqo|wFa*ymqUJLxGf +z1Ri;dzbYolEBL`j_@}(X}rZ``1Kc +zUzp7%#NaL-d@VFVB%O)PDk5bv0dRX_2nQ}NUXWs$5qKY_J-+_b63%Goz=b(>6DC^^ +zp;zW`nZ#Pc6HHi>;jYdxozc|x8ghB(<2^GplkW1_d$G_k`_)uOW=^K|9md7!KZFXD +zIr}7PDD!tl@4!`~(zx$sOxCV}bx+!(=+>p}dbZhuB3*VvKgL14l8;(+;LyeRk_#GY +zEhDPeKeJY2k!rJgDiMs?<)AEn?FB{nJUMVQk|@oXwQ&P04}QQSI0C6K!bT41;s{9W +zC=P0Dxe)&D&(YWiL;ef +z!)HtQ!9GH=mFSJaAOot3ZP)2PyO2K0p=~P2iTUi}M+a16%&e?f9_4G#p-bGjw*P^W +zcbR!?edCY5KBz*FN}0*@hM;UgF~Q^9^Nkmy31D^q$@uvsPG^+ffxjHCL6JD?^3HaT +zlbX4a$zF^0ce%ydPF^6T#E1v#bEtEQ#tsB~8-So=-JGBQFAIFF(xeR`JOrU8@{w(4 +zDwh9ianPD(a@-5-8NL)N!$d5H@PdwPT>ZM9`}j|&i@7gj5EWgnmgbk27e~nt!W3RC +z`Q_Gn$hwBQuj`#5$Mcnl3Jclk0XNSgM4PSPdjVKx3Qh1xP^Q+&KA6=9XUn$MN_8Wl +zItmX5u@ft)R4O;f{d*6XrZ1bV2ICDQjzMDQuDz +z2UC++Yer>{O}ut_ur*=XU{)ywug*aoi5_;B$*gH5SxHmRMSqnwB;#)x#iTC0>+znF +z3NwT?xe@Mi(c@kct%?O6Jm}=PPi7;@XOX-?k-V&1vJe%?r +zXCYwBBn4NIXp@-trx89CAt|Ym$h!`_qECay;NdX{HkMHp(@!k}hQL!*iXw>aZ-+{} +z+rLQ#l|#z@6;`L<6XXjEKrv^&br_-4phxQ`+Ljyh16Gx_ +z%(4Fu{;jZdTsR>DJ>h +z`c2z<@@9Hpd&`lgn}dL3%Ps&Nv+p*l!tq2^YLr&ttWS#3@!#i!@XMAfw>jL2D8z_1 +zX=x1jGT(liRrjWne?x2C`ZRYQ^FI8i5lnX*OG?!1c$=|dRL4z0!TkW+VF)a&; +z%x}|U&mDDG;~XUrmoI&x0NfOXODuJE8gGNfNgVDma{R`)nBEoi9=JyRzH{9Tj7%Hi +z^T7LNR#u)Q0|5UHti9aYvXpBrvWX5vJx>hv6tEN+krOl{DwVK2mUttoPac%^1w)!{!!m}mbNgEq8ER|yte6=R*B|?8l*yD^X#h`##2#|Hr|930DSGdraEUQK +zgxp2m}rItyuaWC(!9X0TuJ8n}ug0FsuKb6v> +z_Pauio-JJJI!YFA&pN;3toOAoXD|dQMI}v0NM38oOvn3LDwp3;Hwk-r_49c7Ywgy= +zFIcz_tRL?%1{fzNG+5U;pdzb8qQJ*iwm4X5@YL9Z?wGym;SBe8ym`p-_4(lCmvvWv +z0%JdeBFf5oIXUA`yV@O|N9)vSCSQCtzFr+yZU>rfc1BQZXvj6Hc_@(4oNwj`2Ju@Hh^Kf=zaZAc66io +zve0A1GgOX15kC`wpFW;cCeMsyW>8paL}+m}d^NM9@&_LEsplQ#{;t~k^x8p^N<;6_ +ztOMLtv!)rx6;!31ZoJo(N>o1FIbPtH4$-NgCg3f+CTqYpJwJP#1iR(LBC0Fq=bC4f +z8p;fH61JomgfuzUI8G`8aKwkb5!{JsY6^xgiv9&TJ0p5%d+wt@2|^B_g_5hn?ZcIc +zM0-kec!8krxB~+0QLtc6<%sya-+6hKajz%;+mbu^pX$HXha(cQraG7dYsE&0s5h_i +zvPd|!PU8YxgcTjd*HF-l>?E0pW$OaytwUXp9LKW+7||ikaK&t{RLX;tZd85VCd675 +z(_F;O@~=nCT(wQ5B$u4{ILfmc`wWN1lI?RWp(7%OT%SWuW$<8OLskKW5Zw$8Z-J4< +z^lSbmx5ahQ@{mhdj)?ap9IVsJr*$Gy+-V}kK>FezG76&7oC25vJfEb{7}gU+1il;8 +zkaN$NJVJ<(`JMK-mC1JIw#*cJQ5)D>XjjFBIYC4EbG5YP5v$6AJe$6oR5HrJ`pHdu +zr>`YyBxPcBaUSDx$>SA;o|l_HCbwTTyh4IK%?@fkO%ffTgV*v{Xv}fK>|C>o)LJTV +z-t4ck_MHqVJ_;9~G<@sp&?9^(T&Q+42>aHcvEm6gCAu{p?)9jD9OWxp(~sLPf{~4g +zgXFy17FyfeOR3!Q3ZlB*E2wm#gwy*2zK +znKR<<)5pZEEs!D4GLunKw#O=QR>~+@4ig484g;Ts`*UZFC_ncq9WQ*?ZLXQ~2I!=! +z!yC+kiI$?t)9(YX){$YJbYre?b#%4~pp@!f9pUH_Z3EX^x9fg=W+DWxGPJ)nI)c`V +zb;^aR_Y3!@E{usN%w~QZ^I0wMnQ6lyxIx$~&O5@duVmWojvtJlajz&_JB!KeMBP>n +zQBae?E6j%mQL_l=K?AgiUtE((8E7dmY3V@TGF&f56^={rzLz*0BBB99W6*{oxb;Xf +zWupr_4HPEvy56m@i*GG>4LNn`LYii^&Q*Q3ZdNGfWy1Se#F@R*iT}+vU8ov@u{%5Y +z=`&;I0j{h&&fRiJswLW~oK&akn+HGd{}8N_lS^A{(VNNZO3x1HG*0K7fkNT|KG#bJ +zk^+5=8EIRME3ACV3*S8d6CNcUA%{#K<$fm(jWJ_V6@)ZZM(FA$B36m7pFN(L!3$0% +zie9ZuXY6qCiaExss3yyv={hQsXW9{jIka>*J6F8@21X)vtI9<+?xE~{kR-n-Zr*hi +za4u-iDGp>yX$gwYH6wh>i>dk9BD6X-1yFBR!W}d%r*^!z7QRL1Mr@@gJP+PwdeLjK +za@!^fn?mta2fV7Lff8om*_#T8BG)m2Z6Jq8jZT +zietyWr=eqpQ%{qPlx2zj1>dS79C_BtJAz^z=J{;~l|;5C^y7EW=Q25tO-LS@B2DGN +zNv_^$Q~KJCFClS|n3@V5xd9U-1;MLolkWt;(I#eClxKOdZ4mZBiMD<`d8`%86wUVka#hmjg$63a(~20w8nb0FroFi6?D)R*WFM@7&ZdtfI6o( +zK!QYiM-v;z5X~jsN?lbbRM6*;-j<(-Z=82!PTCdJI|aK>B4G<^X@A_{uRNVzd`^Js +z;RSlMVUpL;%VZ~N@c!4b;LhZ!uXA?hWg3V$x5jbJF957dwgWrdgW|e>#Ncx#FmxIb8X-LndxtdF0d6* +zAlx_i)EX~aFcU8{&) +z4exc(F2g!M)tqW7vK1B(Yi{d1CE$b$<=X~Ed_jphq_p29rai=M;njzEGPZI43x%r% +zF)!O}tEG^`=Rg^3*vv&4fF~M^W5JllkX83B`*HT>L&`pIOKDKmXW`Qs_A38d1o+P& +z=8)U5i2rSITxtuLK&aK11H#C=rMp8OyRK-vMvPq^lY}ftiraL9Ltc&OndfX*o6>D} +zmG!DMcgyMhQCdA9a3GE8fAb;Fx)*k1jfz3H*~G>-4{+%b7ZGS4?fyTD41n-ZBdsw!|$f)tdxi!_pS +zn-P6gCe$o_d~Q(!R=d^hcd8TWP#c +zW%9FKe9|dbqcH8sQ^>+La8wY%=8io|?)!LOlreROFzohz?kPJOGB(9xDqkjN@O_|9 +zw!uE4v9z7yrlXXtekb<-m!#WYQMWBqs2DC15XlkNfEZL*NnE}XwZ5gai7LFYdFcu# +z3nFbL`xw1X*Y%Rr6FZE|6%>Q +zhjqB8{r3i;>OT_WuY0jkFd|Ob1vDV^Y55O?T8kspOW$qCUlrj`|K$6FBKmNT7xKGz +zYmSPv2P`4E%hsv0oQ&KegBpWp*ovrD +z!!M-{;uRR&BQar(m031f4CUfk!XqM@`H?;PzSdM01TFXXn~hXtv$=@OeXa@LLY({i +zu>zT)s3l{xj$Y_8)uYU)AKmXmUl`B7W);`nadl3c21lRR#tXk0udIrFECbL8l8Y$_ +zQBjy|Q?}(5TZYzDJxv17hesxjZd7tW;_z7)njX^$4~S)?o-JI*^5f`8JRMNxs%h>5T|np`^XC;3XOL%#r%BZr0PKdiuM6w3V*#RLy1H)sNMFxsnmJ=yZWuV^nk +z^L)7Qw2#q8Mj!4rD3>^a9Z4<>3l+MC{6Z>N0WxdKFW}R6zt?ff%l||*PX*S$SZ3bJ +z`B4BgtO^bO-R%3YVGoF})d3Z$)-H16Wh5iwg4{+hm2BMphj9y7JJrF#ymqF&Pmbv^ +zOZlYDEoth=E~xJXqUZ#NaUb6}5pw^!)s}}m`i%U&ZnI8K?%sABL3|Hxw9$fiZ-7Q@ +z|4*vb3Ophq57e*mzNnjpE|WpdUuOl8!f;>ms>hwqb}p^_e>o1N1q7Xw1=!`@{qCAj +zlm~s*@+4X(ynJSO+j-GyYqGpSzNw;i9z{fe5PDV0HL>v<5>!ye&Ia9B^b^6O-GUU~ +z*8YiIs9MV_TB0#g)^(qZp#RqLnMuqfdk#V<&>tzd9t`e0K{xmsipJeQ4&2Vt#W(QK +zC*uMUvp7N28t)vkY=0+D+n}wxz@emmqZy4b2U3QGOG4>KMNSMU_aQ0&f#At~+ZHfg +z{tF{(D@Xlj{3*kBqnOGH;>7#=JVtE2zWm%P*;QGY&v$L= +zU~fbbL}Y+qvR$XzVj;9$uN}kGn+*s9hq$fqDBq)iH(&n`-c&3s0TA3^(NuQ)K-W0r +z03B7AP27L>_8?^IVg89-;5GjLz=G0BWLPIvn=z~~== +zyzzXoSFxog>c9J3>1%b|uc(SQ{qkeZt~A5xfB5juqIQ~($;P49{mX8~A&7jfEe{Bu +zDwedL+^g~OX+x}>mBd?Sq75XT5EA{kZN?R%doatx0oHd!G_?f$eSo{ay-AZ39B*2N +z7h&DzO%7nbs3}im+%Iuo7L?BHy)JLqJXGyKI~@tdgDE#C@$aa1qJUk&orG^pmMV9@ +zKuZ7pK+ocVce=GziYw(IG1C5Fd?34%4jrnxq$GisOIKQ{vFr8cgtxf&kHK2jieq%+ +z+!YiYsXOpOvgsC;Yp@eOI2X}$bdyncrgHK0H*`_{11EMz>W+t;c(B;-=j>T_F1Z@= +zW1;3bssW!y_O9}D05?TGxapN)5f)=t^;N{$|t`5Z=ot>5UL;V>q5{ +zS+uY~w7F`1w(70yx(XJFJz;Lj#QbB$oKNPw-LQgvE +zVwKpj{#c!kGvtf7g+d~M4pqa$QMHMls=e{WcJs!*+kRjC<8;yj^NGL +zzy$!GT_FZg)!35FwB5&^o}<=e4-6EAsWxrlOx_*(%cC4euc#=nlYg~&Li=i;APy6_ +zu9c@q?IKe1e$cZ@pqQ&NB|}nJWHcPz3F+*-BFfAz05v4g-bd0n7w5MhLWsFt(|>Bp +zX$AQ#9TOsg7}|d)-$QZL9qQ)4u}#B^8JE?NjStw@B9m@?gqsvWv~QHO=uzx5WChH? +zg4QD$(44wjp6%Ap1xU#t$XjHW{lzwo9>G&KDYqll+Qmak^Tj9~Nt-^}NA2JU$DZZ_qqpvjG +zfM9fxNGOE*QT>O5Q*h^>Y?Kz_-0BCf(ar26fiK;z(N}J<#hqV6rUgsn^Z|xpNjtNI +zBAEb*Maq3qdzJ`d3cCt<1b!)yhFSIjqo +zj5QN?>%eT*2Fhmfo$2IE?Nj@%hL$Q_bib@)GmGW(psBaPVi>b%dz+0V{Z@~r7XZJu +z{9ZmR^}L)V!U&a$?7Gj5QHP!*@}kMB&gIc?lfLfMjSbcm8vZ`W=L=?ROeod0PCYJ( +zQBv%sgA*@TDi$eH=FC2TkTY~YKn|9#=ee3Q!+AD^inLv`SOZWQ%z1dqq@vAATB7dQ +zJ0AoSI2ui1W`Sa$s4kyt0|gNbi-APuYQz&|Uhe=h`!I;$;jxJHP42BgP+sS=im&{2 +zy;>2)=-n^$bJ$u3u7skrMb)BLMzJsvGYH!ve52O$+s>?iiA^W&wYzMMBgNk6HtUbT +zsH0WFFzeUiPViVt!@9vcpJl7;I)%eD!4pz$YixT9Ul-}$J&=XxP`Ck%$~CsbOk{gB +z)OM{5>o4mT!*CkDPlsj?nfA>Nz^_nDX8T}C!v>m%Pm+yR-yLk4PKzykrj7RSOccO3 +z>DK=E61GD*aVFJfnD=>|7klS=uYJRAD@~(ZRBL8(TO`px%Jnh>ck;MaiGgKJQNFp& +zn|Zgxy|ejU3maUNTVt!JMChD35FnzyeMvYzy5*a*O8})nzH0i?0hjK*4Ww7l6fd8q +zUNPss4xoL_bxcd8dLLrPd7F0<9vGwOT^qc8iiZ&#>{w*R==P8Uqw|$^}=gN)(k#;y;8rh$=fXue%FciBj!{`Kyi(x`Y^ZLI_k@GH^`FfnttuYDvpi!-zVL +zW#5d04XU9D6u6&I=V2JeqhW6&dwE&_B<{w1xWi)$+F&d8(+vH#RuLKKMfsunv^u`QYto>km) +zXb~*dgmF1A4>6zFrtpT2Nh&^vZ!}kF*^c(=lN6s(KIkU1ja1LXiWkRJjQG$g0IG3c +za3@oU>2zN#`KxjJ{K*d|yzqI(Nqq_0xz!f$Q7CCA@>rl3mo)Qzlw{#fZ40>3p>T%& +zB)tvY{)fQAgTnFIOd|q|ype1xtzDMz($#VIyOS0h_NQMr(y5T-Eq(VPl=hB4S4jj% +z6V!T+2SYov77~y}@4$&U0%8%~NGsDzVc;fP6$yRw-57dR9!>V8)ZmQ|^7%Pm_hBEa +zf!9Wnh8`K2TqO+!VYE(k>igDTKWgxG)H0BXdvjF~)i%4=eX@O%x!XqMUner5>>-j` +zgEhvgMMJUYC1KuXjenU&{(q!X@C4RY4|Pzb4^df2kNzLvnP>E0zOBpC=LaD +zRL_j&gTPicJ9*D|%%hb37e~&vy$^ZHG5+8rvXwO2UZo{6{Cyd+G1A42MlC0*hyPM= +zsR&3})%_>uu@7$X%N|!=#)l?XkPGR5Oq^$ +z*tzZr5VRcH528?pT!B1qbl75!6M6)qLE)}P%L^PkqaVgo7+@7WGxb?V!JWWz*Y1wJ +zaQJGlIFL*7|M{#Ny2zCUruSN+l5rvV=50!@?!gxI6!Wy}-SG=>PWCVX>iWq4)?K?W +zVxpgDG0+iqx)OJCIlea6S;QJbhaA}1ycs`^%DRhKgFJm#xq6-k5vqsV5HEl#FALzt +z%PMKUK{lGrEO!uwK`6m763ewXKBT@fS#+nPF*Wd935Q#?Zi!(wX)qKlpqBR3NDAQq +zAu`D~y;9wx$)f9t{ByY;I^_wO4(Ds=nMa`kNAaOxSMp6TxS$+Hq{R~~$}7+7>>qhh +z1qYTUNoD6>0>u~f7hsyo?4t`Ps=*z(+jnS+^KLfAL(u0|S$JAeW?`|66|=-)4sgF~ +zE8}$;{Uf4~k}*BnOps00&2bJ`K8oXbb_qAA&Yi?|<+H3q=^9%h$6utn`G#-MeXP`- +z&a)S<1pJah-|v&wAhiR?nb2!MdP+W{bG>7q6q=WKlyy925H$RL8n0G(=G-k)1J@rP +z{n3m|vs4N&q?T)H&Z1w{pKjLe$f@Ji`za02gg-TmU7v6z6hz*{oi-Y&{R` +z=pJ-7V=@^G{R}|cDt`|c_jjD0nVfO2!m5xR6j2XXaPI`RiS4;ZN~8EMrz$}O%Q&Pp +zkc@axi~_C&-QG4nds6-{y{>65jszXK-K9NCS(9Z5v$I#smA~cs-HplC>)1LsHC%@BANk|xmwd@LXQtQfud0v53kyAb-a7wSN}(Y +zCOMA*j_2Yj>(E|QWXlSh0nru`kc%}q4<~`WntBiI^h-j6gu#0jN{;AJsHp7iaU97C +zHF>Ct8~ysm>yB817g7r6PBnAnOb +z?7-f?f2+skD@8Z6@2d1z8}70WI!D`LSA;?|6|DFo +zYB;p{D9I8&JQC3XX$^iVC;0NdcV$=`c%EB9-g0+nH<<0ZqOunZi|$~6*blMpdqrg$ +zr?k_)_R?~&R-O(iwlE6%s)$7D7SJz0!I +z4_~cMCJt6d7^}`J*lF=0G}+HEVoB9b-FDWuIOu+zT&rCBl;e*jBh67X*lWap#<8wyh7J^O!{>|jW +z_s3~7DtM;QGH-6lx5d|4g74NaRyB^TaZVhi4rU;p02hsgD68wR*MPjxp@?pktq2sE +z{~P*ix|O>0>H$+Y=U)z^F*B#_0QbHn02fBT=?)QlR)`%(bVbI_p$wMRdEouG|DwQZ +zxDFCFIU$y%%eJYy8K#$XzseDY-XI0{nik~z`7SfKQyjpxqRxzViK#sG#g0@heO`9Y +zRy2gd)uE!f3x_e=_p5ufz+CyJN{@!EC}(*NzbYOt(WaP_fU;$d-OJ$lnbwkz;SMNu +z#&%ZmgyB9_chkX2>tt5!w=@lUAGmIIYLWhlrq2hAKmjr1!;LNO*S;EvV7bS1SH +zz7U3zkq_j4_4Wz1`j{%>7OMkZaa+UPJ2&YS4FsM$H7y6q$|kl4ER!!EB8{UemPhj; +zp?026Ur{xyyj%f)?G-%z$=lGC6A`N?E)WOdB{4eXDr +z-Ow9Ej`>7w*{`;UwstRKdxh9(<}urj`tSLlr##!0wkBSRDt*JB=uZ(0f_ +zqHvR{lxM0O9<+07CkZ#Ce|=EAXmem38NCl7GLbo{BArHkQ_2fDm;!b|k{!3!kTh3M +za5|!5;xm#FMdD5BY`M^*_3I-~ZG%&$RETFgygpJ=-Q;UlEN6- +z&vbm6tLc2-j=fGLg;2%Op%+?~$HeO5G%dF{>pW4o3Y?Y+Q_y(bu$aqkw>l&wFo$Bi +zBlRfpj@?9xp9D4J`WLjO#*a(#OI+i|5Cz^}1Qv?nMP1?({gBc3FZ^QL#ck|<9MVGv +zDy}iPB$?Y-aLGKwD-4M`hV2r9F3u*;DayS}Iz_epWLJELSdTEm1a1!`INzhUpaqd~ +ztNawiVpe?RI-Y)xIx-Th<&UbM7WTjNyfB|q`MGLQ#L}(SPZA3evGR9Ql(Wjks}8gc +zn@Lw$O?nW~3##4OC;?hEXKccsWTNPaE-z2MdNy;6e-4=2%!f +z@8C5ZzaPkin))|GAQCCF^Vmyn%9oMpg}N!qJ+XvcEA$7_JBm8=AQZz|ni$GPT-72Y +zsCzxhXIu%QFg_iP3af9nk!hI9;-%qZ!jEwYaxA-gCCo^ym$bpXOve0IuWxm-BC>?j +z^jkXw3Os!Ewv(xX7bvghB*UvLPkEZa@P1>i?=bd!H&+Q@Hj>J6ipe+VweO(HmB~vX +z;%}(sk}@Z6xQe?S{(+O8?;dHlZrc@uIX`-eljD8d;bE&>2D8v$ufK!DUV{v11||&l +zV7l?dG?yQjH6bINL& +z^y}ekYUi`nx+e1A_mtvei@Krk=r4a= +zzigH_xZ*x@nF>p4t|A&XJ40SXP4Nh8+aD;Q(ZZDoOFVkKPGLIMelf_20!$=sQ{}bX +zGZQW+Z06u08kBAY3PM(sAb9(nZBWKVJ@fe9oj<=?FzbMbL`w3@V%q?7OqItFxmS$5 +z1&)&>@dIY^Lr7z_ze<)m{4nP$@7^z}XpIWcS}*D=euA9Q4BMGnsw+W^S#&uY2|^E) +zC5}C6vCQ5d#5fRUpgq`hs>%ob7);^}sA+tf-$D;as%x0G10hxK`F9)j@WZGf!q@05 +z*-nC*Y0=QLZSX*KA1P%o$erAi#gYrux=94K+}$C(XJ2|N=XTN^MFhaDwt9=~QXzLA +zeV$$^s)1_NOVIa8pKTb_j~R*7kDme|okX4>of1(33xT}$b*X|JqNl?Qm20c-{s1rH +zu*58l<<}qnk&Tv1{ZIJ)bwyxb6t}?&VXU$7I6N~eYDqI~;s2#wh~afPK+|T=Vp##Kj;J+e|JD7-YeUVM +zN`XGU`uV}#OYtmri9VFW(HZ+8Dcdssqpk?|qxFd0ks-gll2J2mB9vm)JaLnCvPtz>I3bF&k*v; +z>JaGTQ6o=QsEv|k3QI}CnxMM2p|TLKj@omW +zDVcLE3Z4gi9gQ^)t-qtCoumVbP_ +z@UVcB_o)-NMo^u^cr>+qajg5FNlSG$`bMjwf#*l&2`Jp6P%$QU#E+03MVv02V1BYw +z3qkyl5LF(bK5s?*2X(S02j+SAO*bs~?<2!O3iTJuUK~Z7dBuk(!lz!^_ose{Y}|3g +zDXpAN*8r?*Reb&~!vmKcX`u1pj~I$LZ>?Q`1`3LWM!`NktBMh$1AkC6$<>xQ`mU@D +z697@&fn%S?h-htBdG_&ri`Xph(pm>LEQlo;5yL{F;^ih@vXKqy&`$CurcsCK5tr*? +zDQHGWk&`j~KXUchBLhcTQju +z7@rG>PPQoEoL6!3Y@~~b0;(TWGw)=Z@ws&cXG|Wh^4MXL;ej_gNTcQVj@-$=Bc6Xt +z@-OHJ=Ez~0_1()_PIDFP8?&L7$~cJUsC*RBws1PJt`Y#gw+sbUy0gIBE~`9zwzW1p +zJivKdnol~yr@iv1u0Ykn^|}~!jbYW-beC5X(0TFjYxt&SjHrT`x;$yI<(v +z+~Iw>oyD=D&Cp@0%AnxB%xCWC`Ba*c&@R)$el+wH#o)xd8UL)Hv5g`+W@9_UlARFp +z8dA_2g$<-4Fb}WYCvp5i2@~c`DDQkN<9heu-XHA`G(}i+K*Qx_j2!CgJ1#QclZGx9 +z{?0`9xptbk09As^7k!Z1V5Xadhg5%hrM{+bK^-1f?^2n$yiqf^=yug}1(x?!x{uD` +zf@vWpPq(0AV~-YyVSm?-m7J1}ch!V<(Cp5ToQtOgHL +zxpXU5GgqtDzSS?vAD|mO-L5# +z3>Br3?WralM7tv3@9P|ga~TK6HG!0v`zH_onmuXo&8Ql8xO^@qp3qRnZpU)NQNaO9 +z-n4!I9b=>oWH%xq_}xAbUec9V)q +z?Pd`xB0E^N*2=tb*1)&|yGC&r4XW5#Z^6`?FKeTCx30x%N^$H4rTjGYVRSoP@1yus +zN@uhBZij%|abYQGltw*4Xz;yk<5VpdWEDi!`dWHY1%N(cR=y}LS&#dYjIyP@8Fm@o +zN6|`sHqS6}^3*3kdKH7RddGE#e7SacM8(Y472rMTlKj%_LHFiKMPY*cF#IFvfQW*a +z;V?9i+)*~sWv+FamQ>Y!=yoaI5f_errug=*2NrnTK@OSoy>0nLj1|SN^F@LrEDt$g +zNHo($uz|0Kx|X5H+@0>H4KoLC0Or`z9vaT#8sUR0%YDs>pBPBLua?DLVo7*%Z{VU@ +z&=BGmn#PUF3}#_N$V%XchSLxnhUj>DegPXm74DbGydlDWgRT6FhRgb*me*ioQGdK4r=)TH +zv9BtE9EZlDw67{jHh#y#UFt^bvynA>+07aTNFt4?PeRTkmaqkEZ_PJZ1TFl{^Vrar +zBL2|x|K6jR?wZ|N+}*4QkaP^eLQ)x9KG7tm?!&{}^<)JRbbd_6G=_KnXkNJbw8KcI +z&hf3sK>1ORlRJ2c$7u3=`)C}Uq$!G&d%HXyuMoWr8mvq;MWzH+MJF@(DWwP61=yf! +z#U@W+!qD-;O9$mE8!?yPxZ>^xFhM#jCJ^0rUduC=j#a^}h`|sp^;zGsqQV@h1Njn- +zbel#c<_t~6{Wkgk$=qLtH}c$IXMHj`@j+8Dve77j(hR=6QIZju6IM`3EkFhEGjF~A +z+Mp9S<{x3Dx09VXf#;r{yoiV7=j}b@fVk-03gVneor+AP#wh*HKGaCIuJpM>;vu-E +zKAhZ(^vm}WkO?i)aPnxG+jxsGO+je2#_UidOh +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 +zQeGTis@@PBLm{<_2aG;^DYMr8)`IXr +zfPGZ`M5=(=0N{Qm$xZW`#6MYU5<6B5TIMI2%pEE(=)n2yIJD4wRN}QTe0}`vJ89|S +z*1WE#qRmoUpJ0YvJQl7s_M_)C;R4kNpTlYz*X1N!M~gV*$ks3K)nC^DCaSed+wN> +zY_w*MiaiLP!tnt?xZ|3v=eb!6CuGp@Lvk%8hs^rbZQIQWaPmjVK8ernq!qPNtC*G1 +zER~o1C5iN&y( +z``b5MVb(BdF$b?6-EC^HuwuZFXVzS6L&9@|VIt90(Au{WI5*EI=Zc)+5zzJ<#*ysz +zhp#V +zVymfw^|p|1v-J1JUk#w{qN{%>yPlaL_I(1GJ`301-I`FD;PbHH?R{kyZ7SLEQ`i0} +zRXnlAw?U~%J!c?lxR|~T*7Bcau>9jOM-W(GM`Lw=D%j!|kyf+4j;?P&DD@1Mu8>Syk^X4haiqd|r>#mhhN;_QXMWZBvB6N^*co$gDaFCCW`DBR +zE|7pTx!Gv>?up328r$i(F10isIX7<)a9ZegS`Tp0lil4x=k4U%HJ;z6v~_Rj70p%W +z{L<&96llL0q$GJ{=s=8=ow&s_=CF9a?)3p8n|@9_5RFF +zH)wb-jAKX7ndNXE6-t49B|s3%^hw<@PkgbCV}w!L5XzROKZW2hTqv{6)7u7t1>9=@ +zaXsUdGGoHC;oyLYx^ueYM0%$;@~+7m8+)kYoQy}^R;>S|%P4N`uvXmtjuTA;gVAG; +z+m{jywPQW}ay*&oO8RO8QAY36YPq7i7ng35T_!teTE~jD4nNu`ln*{Ef|UDgs_8nk +zUgIq?ScB|h58=kq{oI@cFJXo?Jm1MUU)u0mi?zqrZG#$vh;qO{CK-9h^AOLPoZSkd +zs0x2l4Vf_Lz_1l9ZkC+Bp>G+_OAMO$*;0AuCIrdI +zOQlf2z!}VW*$Hbp?@+F>NK1n}~{DWmaeVT--wdygaDX09Di&-c^oQTgCxN-Gyz- +zKZ@q(LAWb3nAX~U^FViOz%usjo7!l++@Rx^k53AOixR(A +zaGmI1nfKGNoc~#Ni;xN&ntD*(-oF8&D%Mn`4((aC0jRv2skkP3BP-hyU9s+6Skbhb +z;$E}%M|WWo-(ip#DIIsWefQ_3tB- +zY^G?^Qc3S_)~=Y6mx2QCO^Iw@q)LJ9osJc0rDI35C`1%Hk|I%mHkwJKr}Pu8Q%qd+ +zUY};ChR_CY==3mlHZ%{LjiDQl9OI93ir(F}!vHQR{D~~j@bt8EK555m38|vno{2kl +zLAOv#Uy_KsXXQDMDxXNIdl}2Izb~>aqY1)S!FAhKpBf9XBt?I7rHfXV)cd@8+3m@5 +zhqDMJENiEslOn?VmyEzY9t=vbozBU3EJZVq&?( +zRtc69{rgx>t$0aaj@1YV87kE-3u+Z9crl9vVOyQX69CleFnRU+%c*_bFP7~rnx?2& +z0_wT>T#jz^i=K{j6*Z-hRbP(pw|V%ML+j +z&3NY-4SBBJ)^pY{TlbIYY}Ri){3=TtpM5KvLV4eZTg{rR|EX|2P%JL9tag)x{Z${< +z0E+Bg3zya?t~W0n5NLly`a!bSqmG&dH_p=jnucSyrlgXAGN0KHGMn&&4Id+TTj*>~ +zNE=T70wd(vulh@CI@X*;^1iyN14{*lWY}uCmg3j_Ix**O4ALgTsa6mx~!=Lb>+0?c%%vwNGmJHiSve4^j=#sIN*T10^ +zHl6nywWY?<^PvR4bf-iQ3GTMzmE#p`_q?@2IG?8GOXxaclzM7f_$%boNVI0`C~OD{86 +z7OWRegKA<=i7VeKwlipuvhV`C!mX;Z)3dH%+XrMz*M=7k3aq;|O +z7UT|@*)$wkpP|=vI%xz!^9HQwTB+tPY?zYw_}G7Ae)XuNl+)4G59Bv)gl)bO;IT96 +z9PWt2oMARrHx5RJvb#q!{#5Sydz3%iIj%Tj7ar@U3|%Ah}mh`a&gj5}kJ +z+?ROaZP(fi?uYu)*ct6<3;PMvZMe{hG~FCaYhNh@Gv#=~gaPap9W0(?*COjiL*8Nk +z4pw3f?lF?JnP)OXRRbyQTPRPEC9tpsYE}ziKyVQ%{D*x}vh6xH_jopOzZdY~`%3-K +zo+3~Y*30RSzETblY9z6GY94&*!#qg$QwWdEIAJN$!Aj(V$$(vr4l9fbdFkK|0~EAm +zBQpQz@Q7flsa7?%g@pG#gOjh{_y)|pw-(^R#d|$)m0B4^xCcquQI2;JEvmA~+~@7+ +z5_@n|a$e9KX*G*sacDGmxy7XKEqy&B2uw?Lny?o}B>KprcVNZUZ?kM&ghhxL9uYyu +zHpt2F|3UJXJiIv<#F}IG9`YDq2pE-;0=au67L-PD7?VZ%QHY@}3#u)_O=SU(MqR$)K!NhX4*nV(x#XoLjhv$z!! +zDtkbZKJ6vH +zXp81SFM9RYYkym0E|!99@4$GEY$%J#Y1@iZwlpGMW +z?;2~$YBcNu$JAnR+XbRyueTOWrAgn?*EJ#JPkj$Uj?GwQkgK(VGP{@;8~_@TknCBt +zW5qxY{ECoiW0W%Ai2gUblOD_nnrtrc+|*qN&x5w84{S8rf(@~69WHPO$NU9!bRR?p +zA*Ok0a+DDfj5xLlo?Eo~Vsg?#v?vl@N)g&Mdw#O=RLjGg1A+o8A2$$!Xp8i +z%aks_k+gyghGvNvMv)$oS#?V8N{#^t4Eg%o!RcOE#9R*%34d~W5`7Mct9`w@p4_UA +zTN`MLb%A0~J?Nm>6fJ4sm;jhnvU6HpDF*c7T3YC2Y2FaWRY}rBmKKwyxFD=O?&(c1 +zvAWWl+`n=8t9yhi!;4#@b3+UinhvZfvc~g{y6yL~*-8+(w)71m2k0l+ohT%M-eAv= +z0rI@#sBEQYrd7BZPHTQnS9n|&Iqt8U)=3Yf&jOw#yW)n$7Ja +z^L2*r$p0ix4{!qw$((MiWOi9 +zLphHYH*4}{4R=pf1ioQ6zMn0ll*t~53XCbb((WX?t~7t;|5SIn;A2wxFe=mzPWC&v +z1mnmpp&DV|On0db#Xxrhq0g-h0V*4-?zSLI%sc*79J+=pKtP|NaBMI +zTSHZCcy<^&eRykyS_o*f2Y+!7G32hNF+1VuKCi9GtbOIa*UIEJJ&|`5ADwGbkB)=Z +z>zI%CNU@P@Or@V(Is1kflNU!x9vxa#J55u@forXO)VfQn7FYcon0&4@JK67YDNF$7#(@WI +zr^YL+@o@o^&$+Dm+wc^fmxxlS_ZM4_~FWuySZuzlGRsPJeE!8qCVM?NwUI +zT&jcti#y(jJi8)?ZvxGcO!@a`c@XY7CA>e7$ZcC2pDt1G*TC4*Yc1|Mv6@UrR{?K4 +zzh9VFQ>aaDqU;-x0T|)6M?OEuH*(~GmF617?W!cZ&a31(ZDe|F5-I2>r(Xfg7_;+q +zf8v$t|NYkl02^0#c~OAzin*wv+E`eeX;2Hudfc;)1uc?~ykRfTc{jQbJPjkjB{mOD +z`HyIyme~dT<1?0S6W4rb??bWC2DBB4vE?LF +zgSIzyY15}nbD#}uI8)h|hMV^9utw4&A_v&0Fo((`J>ke|tzq!uzHaBtbh;}@zRj&y +zP?ddJw!ZxNdw1@%diCZocGEZ +z?vG*VszKHL@25X#VrCAN?PMQA=}C%|s3Ahsa|IEWmp%p44u)uXNdkFNxJeB64kIKG +zgYu!2t|#^OR1_NNICuThaX9Npt3kecL!9;>}tvHx#5y#&8agkXh7Ih<#-Dz1!M!L__1hl^mZTwu} +z>;i(K>#Ss%->lCSU^Y(VY>A6CY#BNl=wwq{dqYMWGR+GgVG{OHt=u8}hFYw12MOI%B02-aP$j +z3_}dDsL`Mmvak(1oBPlczo^b91iPHC9U<>Gxo?xk*0rQZfzQvmI$`*3cJy)@s&PIl +zO^jKS3+F0yy1hpd3CA41itqc3sw>esXPXAy*<#Qi$Et#me4|82f7G5Y$sgLuDOm-aXT}L9kA+ZXoG`{}4JtHqMuR#)m +z@i%B7ZP1RO=edoV%?Ug-OkH@AgtY=2b`W+;o1Ui`QS1Mf1HCmDUy{X>xkwA>L6e>w +zgL@{N`1bmjCBk?|{|$4I3Zh~q~+b$?#&`(Y}233-tkL1Nn&??7#A9cbE$ +zVr}T0P1Ic}gRqm08i3lb?ZS4{Fp6;8$pS85)en?TbN +zUyaueR0AxE-96x1QPfn-50%r5rKw3CEOwl=t +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 +zZTFhc-eFv`!R|*d?v-{hW5ovvK8KKblF|7 +zeJX}e1|!lVdR$WT6F^~Kgvw>pRUU5>%M|zv2DdJW&+B==^#=h*c{8HekL>@su!i&M +zePHqi36lwAvNhL!Xj!&+C2~dA$U@=C7tA3-xOdiGu{H$_A8>DdzGu;?C0&g9&Eu4D +zcJ&u>d%(-Uu7WK&O1?!v?wwBNl=Z$5T>YUtO^(xS;~X(C>|%n`m1F|L1#wx;ZIG6f +z|DZ*LJRU@^jbxT0%He!#*6hk5z1I%Enm$kMTkYVwPZt?r +zNPqzCl1<;9zG!p?WMcOnE%>e_|C{q_rqSYv4eB +z*zePRHuML)X@~S>gezW!c~6}e2G?+B{1?zV0l;hYjjC#)*Oqz$nu|>3mvfQz>GsoE +zkZ#A3+JNu`d-Q^H%DX1r +zVLrD_h~)jP=KGX_6JjgTMY;R(&^7LM08b3U4YHKBVz$PZz}UXd)vp9yov?I@OZTkH +z;Ma5a{mpSt_lx*Bqe<1jd*=4xd#;`_lievriBF|lUeE$h@f63brWVGM-w;`PMcI_& +zif$Z?NJz0-xP?pcQ)O%_t(1_9?R^^ +zi!nF1pKce`rcy!69xJxg@_0tQISK0|aQ!>8XUD +z=n|PasxOF$0< +z0m_bK;Vi8XLTWCsRfMmp*du9MurD36LKN!>Zb_tsP|Y_Hy-v^|p@QHR8CG^ypp5sy +zW+HaZJ|(K@+kR2!^0{80rnJg8WRh_`V@c*2pepi9@=2xov1ui!Wx&9SDHzRSO%=@E +z=GFhuopNGMSo$Bx5M6Q*ql){Yg$Yt%i#V~Gpma(fOM7VBg`Cm0>lS3*%*0Xz`;0%c +z;Vm(<#`P^V?k&0H2k-ycNeV-{Bb*(m%k0aL=m+P*gd{)s9>*SB`CYbRw +z?`(QxS@3KyQSjqHp;Q}jNEaa6X=2*(Q}v77{33JAv^2mcI^I!}a;@u1fIpaR7xKz1 +zY?U)~TsdjBcQYFq{gMLd$PqXXo|3E9O*c6BF*74Do^eP5)Fl|McK*i#x2=@EkhmUw +zH{^`W9H;JfQW2inQ)fFx_M~r(N1$sdTV1ZVlJ+r7juBC_@^q0d-=@~c_GWSu0K&!p +zteZMpLau$l2bQ$8qnYauS6&rT3gf0iv8gy72Yl4!Yd!97>`mNQyw=6l0NDLrvB>hm +z!#JigaMErjE~aN(OPh!)N-kB;RAQAB!6j7xM?1h!!AUNE<$!n01Xe+I|2*g5)G=`M +zt$*8qc-Hxyo;a5LU|*sHUaSMH4bhk-Ag~pYavS@u@NiQxn&5_K!jP57UpZbG)k*2> +zeb$qEZ1J`5bfi#_qT!G7XR`@8iy12%8bDDcl87igFDy=^Ait0(zlKO)xk(aFe`6Mv +z^GiRVZj!>Usp#GSH$ce07b@Qm>*PXA(k-gzu*)EqUD7_WZ2=oste}!BW~tKcVA}l| +z)cDe#Rt_Hm{cGE~(>-Ra&wfHrz>RMbCY{py?XKp29xlR1A&pV-op;1j5ap~zNeS=D +z>HZ}RlzaI7?)q;mxY#oJILAzzotk-OV(~MGQn?ECTM13)VcLbIkG;gu6@Oil4yC94 +zioEi&n6kK*Hg7M6jmE>70#{Mel`^ciyVdCpK+`i&7TOwMq~K^u=t?3bUi=-zuImhW +z0uU-Ik5<-A^bRExa!v?i+&dT}laiDN8>~LK*ux^YBy=p5GvEs$@PqoqC)H0c-Jb6t +zHs}CUtf(pM)O*AV?<&pljs3p^U9OIw?ul?hiBsoJ*;ko#Hcf)8k{KfCy&hW&$?f;! +zt1W$x2c1H6Lubo;^hKH_V^FGlv>nH)DJ&v5;if0gUKjum}SpC99k{!vQkp{Het +z^KSe_J++zxtdOl2ZAA4l%H1ouc-iwAMAO_3vs<2|J2?xtzzvFu>@;h+CjKyaDMfAJ +z-ci(bz>jKfDOISZIC4&$zy0AmrW*M$MZD8x^Tt5iag|0X&QTS0Kx +zQR4hSv!asfb*e1Ix3t*v@BxYMZK{>IF>uw&C~=JJ!I|U??v4LqwWQc-iGultcP!Vk +z6GkWcT8mH+D7opU?9Y)~@lwpW{L3S&Sy{=16VKaYs}SGmts-ry@XoBboA;;lSFC(z +zJW@6*k|VL{jWVSh@W)==&|1l$Asj;(U4pipSy2Whu>Ze5aW&>X08svDn?jLs!ANzN +zp3IY7wc?4XRM-3-U!5G#?hoCKCQydSWczL~r=IYWhS*f|`e20e;uO!i1!4Q>hPfb1 +zLHF0_CkKe!o@*^C-kTga!GPPQZD}JL7`0KwxCM#1BfQCs-g402z1?Da9$&$Fa6vp? +zte!-fKA8hpO@_p2uP22&`_mUXsOqcb=^Q#k!QBN(uk~Y&O;!$av@=DJWSlx>fKek6T^z;^^!|nwc-^pI_r2u +z8s1_}BM`cL%ST^aW5nU# +zgiyvTH4Tt+)ztk!Odg>ZP)(yPMu#IGt2<2X{HjC0@kA}?S1_HCU+v&iTf+kl8Ads( +zdcB)DHyc-k9cwd{h!?cH+PaWm1RIT5_U^x}!`R29*^4BcQJpO1IPygn(4-L4w^rjj +zd~HncF~Be2mXD}FTe26c!y`m$%^%zS#Xc!Ohof+n+ZRCWEM@ +zOHn!+1!E2u#}cO1fwF0`oYhI&Ixc6aJE8Csnp_a?NG85~yHXgewr|=*mWg>Xet|s8 +z?@vY>U3Xd0*Pk_TVYQ|Y2w3_}A(48>af?%1wj~q{ys8Tt+OB~izgB8Bl=@LybPXQw +zyD{3)>DoR9&B9jJOqQ4ASSA_teND|Ev8))U2AxhxL53lWi%=OQ-!J#@QW}LX9j{1 +zs`#3)cBl<0IX-?BjOR-{`7~0S;9T)BS;(cJBiNMm}Bk;~lf3R-w~_@j)yu?N#a7kp5~2eG|Xv +zgfdta*t(NYqu6IM%UlNqq$XMqYNcq3p|&jNS>WF*PTT+%XSyU@V`>Bls~L5;8#4DC +zQ=+0RFUFQTN24{k=4vkC<{(rNEU`HyuUDP&d7D>Rj5*hO{^tXx%vRbj7Grh|k7u#s +z?XHRhz`MSuG4$agNGe&+!=}AAR9tMgQ`CG`KFiRTOI*j7S +zy6nrl4%qKus8=B@TUeoMYrG6bn4)!HaYvYIX@VjpKfX>f{cAs!3c@ +z3FfNz-&FwEvPnK{(@U99%c(7T8TBXW(miF3ktXbeyq3UjNKz(ezYX=hJ(&X5Es^oO +z$dLw~SVl%PU>B>ZSbQNTn(zp#zMQL#n;d(yVMdR==c6JnhSlmjAOn1_bxf_rq?RQ# +zX9d|SlyG5)4>szWa*OJoL;xN`Q9aN!SN&>0pVBirTyQUuy#Lu`0biJrDB`Vl3n3;2 +zHp1XxMT&>--OQl0Qb2C-x&f)HkIXL7gNGf4?vmaj@2r+vFXn4bjQ#csK<~i2A<)#N +z^PF7=b_Cd*1?N4btWeqR%90-W>h>FS3BQg0Xe8;vsg!uc4khj|v1UFX6&7-&Sn@6W +z{MC;oATZ03N0psiP7YD5`5*^t5Gs*4g4^7D`!xLkh@k~GuF5uIli)Z@Ku#wa$m;$% +z%de@dsi8E*Y!O0LiuB*g0dhxP(z&tU*T67UefEww;;&R6B5-9b+D07SsbeMUUy7Lxk`UD +zojfWA-RSRa(y0O9s9-)8&tNg2CT^5wTnRbxUs+LTn0_?>?HZFCyd +zRXS +zZkTXA4Ctl2gkVEWsE0)l*nhUZDNPN>GN~n=f{u_g0GnhcX7~8P$kR^!YyP?DVqO3K +z%VD$~Ek&fFFXJUmS!|W}tkcN?yu*=WFiTMRQZo%WMpOhgIikC_LNVGDz$6}uh-D!S +zby({6qboUw@RTuM_2Qpra({-eQh6fNnbDTtw&u2ghgTxFEA#28!<%#e4(N^5LPRT~ +zTip_U#Wtn=RiJ@OcKZJr52IwyLw$sJ6YxBi22t@{gO(shK)(a>4@QsA*vb9JU8jx6 +zPK+Le?YZNNIZLS`yQj5_ACbOC+1sP9{=8ZRA5moQ>JT+793Gqg^^({|@66vdqP+IHN2$w>fMONjI^47p+nW?@Y)gn+XBry@dkmt6Cu-c%@ +z0|IVqGn$fLV@sI_4%R~}4kdRe@Tjgr;GwE;cNsf}AU|b7OGWYM58PHEg8)LUw55qV +zP0Y`>BS5Ky2}(!0laPaLaCB$-%@j=uL}t(SU?iSWbyTSxOa&daT2?<1-{k$c1+s;% +zWsS2kb)8pmkP-u}A+e0TrpKa<$D68J&l1H4{uch=HDrk|$FYb~Bx5o@b85GAfJKr1 +z2~}7&?Rg6ZyRz;8GD4qI*}Y-$QtjEV#W09jFo-i4I}(C9o@6H~2`@)%cXOTo+%c^5 +zfnf;5Of7ymz#YXby>htbLM}l00?gAREr(}oseF0RFZ~%MME*gNs+Jk@nwSQpPW5N` +z(^`l}4_w;rlOau-m1q$RU6rlnT^-SqB7^ZSqA1Xb{3c!{pR5C=qxn`5ojq7Jy@F6I +zBV4W#iUn9z6k9V{YvnJ$iRnDbbe94a{Cg&gj9rLrOG#<_?V@J${WBk1B;pMy{Zk;@ +z!t(5R;A%UmNxLs61xBv*V~I)u?&%+VlmQ(8iK91nXK38^dCtO;poSWblDw!!23osS +zE$byKwx&LELMfe`Sw6U`Jz8_L=JCWx^-yX)NEXzT5?tZzOHHQEe#Ug1(NH~d5;W#XIhlZ3mQGkOnMzGlxHjE_R?bp`i! +zX+<0Mh+Go*YrknZSBVoqy7~EtVAqmb8RreSt--d`F34n763d>T0vSIGh|*-1e%{k- +z(XSe4(H6&&8?7&Y%qiHWJRbDcItx>ue7mLBe7hd96weI^COfSsSt4z^EFvr^M7}Z? +z=92ZDYzSKf(B(ONP@LCA!+7TTfWkfM@f`x@&PzY$hm^G(pzy*2n_!lK)5A4G?{dAE +za}M^vzqkZI3{n*ig}D!uA+vb};Q_9DKK=046vgy<3b+GQ?w)CbJ?>}3G+ogi&sexMsIkDhzl0}@K;`R}y +zl(7_oD;crU3?=ccYfC6 +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 +z9V4h^f}eiF#i4&VToL!7%iKn-G +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 +zKqTB+UBgY0nk_q|Z3Yk-l$ +z=}+WYYoP@JP(T~k0Fu`Cd}3m#rZhvT3$*;wn81XJTr6dLr!%?zH`AXP*KIeu%viN| +znb?n`@;C4-g+-pZ+@N{D+LhVIL!BMGT^h+{n5`wEl1qVhl?^BdTt+m*C5o9r^iCNH +z%s6$W2>6*3=H?aHXM@18K*)}W`2@j+hn2IGY>RWJ@efo%5u!7CURqT)BjtBwVwZa5 +zIBN9U!g7G}`Y=fxqz&0xQG^^(Z7|_Xo$>(+0CcfPrpKI67@~3suG-Ux?88kt2hcWy +z0L&;QOaH@bv;+HL9S{dpy*AL11JWr&z!X*7)S#zu1eds(%M`rSe!93{7plnI4|*({ +zDLGj#ZOS;nr1g$2p2wSCTV>!U(sQ(Q#@Wxk?xjb=^Oy<47;Y+G{GaX^ZXsp^PMau15r87ev~Y9L4#O9?>KeJ3G047+od48^0_QX +zNPE<5r*$=)9d6S#=2jnl-{d)%NL72BGSlWwLWqIm(M!mF2fdV@b5bnTr49^j +z=`-m5%o%YQzADYQilet*Q0jE$)FhZIYY#&GA*;^P6o}+?)P*C>6Mi}T%TuGXY{bJ= +z4n7i?X9@B1+EM^(Cb`Ue_dG4dRQC=1$Sc|P!i#T3i~^aa|IF}cMr}tYZurPeI$Xz! +zsAMAuFcIh~KAv-OOZ@D)_&OKJJ|;}@;my8ozM%|YXfYz~6QTRJEJfGff^yNr +zGM@1!%@7kVS&*6&&%y&ZWOtSMC$0V3v-%$C&#Y&#pBSxUBd2$_D!T2!QcN?vz-q`( +zDghIgGj}dUHMD6{qBCm+rQYAdSm%2leKC2n;e)qHaEP<{Pk{=oBuZBK&}`l&$V)YL +zE+d{w?y}Ce(u(|WJM3egVUqMR*FndI(KwNvF|{L|Ez0V>WZ!Z{p2$x9no;1T=)<`U +z%OK*=90(eCPUM_r#ZwmbC-Fze4)?juvrQ$7a?o4ijtugbl`fKr2FegJiW!N7R;~X& +z(HiRL)zP%7+se +zU?J?m|BJaC=wIRDgq*QgAFF0T_Llgw!J4EtLTa+Y7IXNbJ=5C=noiJGi3GYj``dJs +z8FYRm*_=S&2hSREbUY!Ks=c)4W!D~X +zy-Plh3WT1ul?yU|HY=SEeUSgx!CW-C@5(f1aL@X*2$V0+#Cc^g!Rc3$mZWLD0R4Q+ +z8*CHld~mxfbZ-B5WW5a3{7yLIv$sXcXxK7kOb+)ujI%Vea9$BkBd+k~=rW3+0>j=z +zD`1EeR;JY?|#UR~ITuk`Rrx_yvJku79Rqf#9gFme}~*~E)VxyAf2W|zY+ +zgj0u*04f9&D*G<&7E=wG3sAnhbv}lQJNde9e6?s1bDEan#f+C7)k<23 +zKi8a~l4YICHUu~HQwZS}Lh^Jj=r+RNK%MhNj|@*ebP0AEgeh%YEiVpP`-Gvnf0(TT +zN<4Y<49SJ-G!9%VX$K>z=cg~%2|Y~JdffC}#1`8?!f4mqVsCLilh5EI?`RXOT +z729R#x+jLA4);npd91K@)d2QyaLJ-vA$~}W!}x8`*S1q +z_;>GJQY*1t`W=I=`ge)FrTCXn=NpJ9AHT|L`C#kpW>K7;k% +z!zInH#?ts+5gmTvC|-kX#hVa(G7xP}Vp$8#Dsy?i0O2Z=%Ud_j5ewqPdgF(?BNKdh +zemq#@Lh(1c($!_1>VvTYhbB3#Rw_k0(cY@_IEx;Ec&ev9k~3@Os9$+kKtta4?2qN% +zH7clCSHyAD<4XKtHm*Cpe((1|*&_%ok(w1x;0mEU-021}GdiHGgK<_Ep^3i%Kj;Q% +z4F-JC>SaUstH=&E<%Y +zAf5F5Nvq6GRbqd{k}=e;G^F~?0=p6a;0(2 +zhe7yBg&kgrk_gSF1_TyOlmtS)(wtn-O1x(BD@Y!>FEEtxktm6{VK&VDY)6?SsEO +zZjKbD8g_V_ZMAzFqp8xFW^U(qI}8iV+D4%8D9&#&2VbjrMcTyX%oAdl6+z?8GllNs+L4P2P;M;BDz%rfgv2zg+v4aegs*r5&?^q=|7`kpOi38q +zEw}ZRi_n9zH2?sjRj3u9+Ma7O(_B0mdx&ZV7u7|shd&4?6 +z<^pdLsU$&D%2bk57T~z2UV&YX7ULj{9_j+98U#|jIuDLerA`o~|9itSI;$z*!plr> +z;rYefr+GXiFI-F_o{<}22fofh6TzJZjC7(8u^<`_VYrS|_N5DoCciD5I%t1vEhq8g +za8KWspLw((SSDPysR$rpx+=*`pkrtocpnNIbX#yq{v@-3Xfh82$(U3mE`usSTerrq +z0Sa;JV5gW#Q82~WISo~5mBRR>N!-0uR)!{)Q?iWj%6JzyGH`X|oVZ$hT}}d&)FS2+ +zHvsGh8s;6Zo{4E4n?1u1=|Ia8~gmxUyjEKEt<5LhTy!6m#ex_1?R9%UxKYTa2 +zy_gdwnbOhzW8#o&O3W;D{obO%-(B?ySj0|Rt4lXy!f@M%eNP(GHeoD!`!>=^!Wb3F +z{wk%C;@S4X!wip&v;ShYIH6>>AQ1=A)_Lx~vuq?r5F|0OQGd4X;PuNQeGVg_S~5hu +zz@sR*5$5gF`w(1X{&_f8YX5Pl*OE6W$J&4mQake4lhRza*G^s~GHi?l +zeJrQ3ue^Rz$i-!d)R!IhJ-wWSA+HmobZ+*^C^}BRzae$W2}+) +zVfB8GRZUO!bM%`~uO&oxqk?SIOOPFr(LjCY>IYH%CCdQg4o>tklksacB}&;Qv$!T2 +z4hu==b2CmMGrQYJ8xj)oNwz(YQ0FDZAg4VJ^Ash9i1ORu-=`Zz+WxQ5*CYG0&=m?BH^hBlkk^o=AM893t +zk(aAY#YK&7?3ki&wj@dB65aZXsx>2GhDCh5T9tMeEBey%$6O-&U5gkEESzbQOFgVx +zFS>_!rv(Ioz%Q+z!qJ{^IVF3VOY?Cr=2{GsXSENWIQ5k6ERpfX}+-FdSY((^kdsG3bEE>y1Ee2^kXa70ypCjrluQjP<1u!f1WZKRz$# +zj!xF10V(|%bb}gr)r@=OPmFNN`!xzr~)Za~Y1%72N14w1 +z!ZJ_s+DaFdQxWWr5=34&#b~@!N1-x0ZxGmORyE##6Wbd5!c9! +z9$0_^+1B=;SW}`OkC26t8(M&|2H7miO1o|yq8Ct)q{YYF{fz|Gb6{v4&zSCW&IvG| +zP14w#ChG6MC-_QxLmj%5GMGWNhf6``Lj=~#^yyw9qepJDjGu2#ZnU7S+p5Gi1PV%? +zaR;r`XRiJEox|oGAUK44T$-DiXPi;d1n@>;P>n5_v7jRa>mLHWW-W~fyKZnyE|E7> +zMC`DnXJc2HwQw1Ls0IT8otwBWk^!BhI*OJg4qa4xfwAZv1w+xsL8P7Hn6$DgS!nS% +z2Uz=M%Xe^4yZ1?=Cr*P4YPIzI2zDOf{ZFT5&kEyPpFH=^9FsBH4J*nOTC%|UGYV+(vbCja)$#@LazXRC#?ZFfJ?*3$-EZU#hZ2V%f8)A&WTD9 +z2qpJ{S57zlgsG>do+gonNddH^m|b6BvqBw+CFod0iqRD9gw|F^`j#nEb?BM`>DJOzAPwkp+0zaU~l +zt2X4_u*QtKs6w_+6)FiVODPC +z8GCC|uVk`?#nRiCC*{X(_(;i5B^g0xF5~8QUfg)D#fjdOTXnT)0gq!@j+ozZmB2=w +z@%T0eQHTSx{9NI+y)T9tH_DEQI(^K}yS&FVn8n>jG^8$Mdt6iS<+i8hur(eM`OD&V +z4;1-iyatID2I;||tp!4R-+O3>^$TGRS#?L(;0Jp`d)6x#GmbRpi3ZUHUl$FntC2C{ +z07s967$wGb_9-YZKlTn|F}Do_$goh|CQjN}8CcWK%Pu@?6?7c>9}nkJ#jRX~|1v*d +za{$f179UDEXUlq~!T3rV-?F&UaN=fa?K*A^!TcGFvPgts+~eCcxc!YNz1&10J_0r7 +zkqeFlH8maT))$w?de*odxSQHhSM&opr;|t+auu`kx*_dy0lTg8T7?}A_sZETB6=gx +zky-s;MuTj7tJbM*C;6PXnofaSr~0p1{$`!7!1un=(?u6Kau4YA^W@0Y-We<9Iy +z>V&dR6?yGpTO&LdQ_gsp!QCL3tIg>_#Zm2-i7-mBGI;6kXmMgGFpYafFKizqxUGTx +zioU(C{&3QF-~lWfW*xEu$sTxfETdrnKtR902*|z_7Z9UAgSY^owdiJ#U}ne-OM$W; +zo*Wd~Sp}?T1z;?w=xE@_-mh}Km&u<^7{RW3f5PXXT{s-(?KS};1R^uovHx|3p*Vjs +zG}^9>TUc?;Pl-kzDvws92s?2X8jn-l3Vj_dd9Rn|jm_3(4j^y997ucNBB@mU1nc|P +zA{%($(M9P(d%1SXO8IQks;Giy`*{H6Xv!LN&>1%T&y=N7n`tS@8W|nD6`!M`p)oL| +zWrK(a-X-#{b)^Pu0USXFNG5e0anG7c^S@gB)^kbEXdcMI8@iGAfGnUDxSap;LudE> +z!ZOBQs+}&*`q}-0Q1}x?WcCmP%jqdj0BZ`(ekcmZ3-}=cZz@35a!dvnN9x`36TgFH +zDA}4(Q3k9?Ki4xDfRgwCuAI(0DoPO2Ggb9y*jI^ +zaItZRI_d^Qd-rcd;B6I}iy87AZKxl_(CT-nl+&ffZSU*yRtKor&2x)9-#osd$8$-G +zi@v&_F`S}cUcLE)kBFQ-6kl17BcweqHR`zaxa!%~Sfa;TqgZJc5q2JfME^OU(~87p +zkkef5fx$E-e#N9)ax$?_50om{Hnohuh_wq`RH-*|cE3Dkttat8vwTRwH9lv`qKP&x +zg+y*T`Hpr}y(=Aim`UDbZEyUCgJW6${$rqCj4NS$A+^aegIZhq(wkd@1p}qK`TTB9VfgtA(TWqE2pZ<*41&NImylV +zQ<@~|a}lbQd#dp~5@lIOV^7HH?dFP{_RLMylHh26FbYfHOH-GKF1&#Vd;gEzz2nD> +z2nNqmHpEXc4Np$R@6e#N{@tzflPkLRDQ!?G*iI>*(?j9{DUyXSc?- +zbAQ;-wjG!Mzu(8}yh#5jstp8C#7Kpj)s#Bx(aw*74AV3rQb=2%5C{y5Z-c)w)kUjl +zAxw)`(*xfxDo%y{?%y;jjcDGS8%wJ +z<+0~bs*oG8?-1b0{#sds+eiJ^0CvCn!nQezop~=g!3azW;;YVN2`a7$mgYQY`=WGV +zNl%Jzr~MRDiKV=UM(3b?0W+ +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 +zXxO+a +zJ}GxRn6lnW#d`Cf(BJwkE9u_>(r%1rBcgPp1&MqQiQ!d=19cce&fgYi^^_as03`D^ +z^+oVLuj4u{Dl0U(GVqwRuIwdig8TZ86_Ej|_V4HV!|^Ug!1U(<5f777D2n4YSoe`V +zJIk$^cbK6XXgaTE27B9tzP+j#f$s4?VQh~zOD2&%hxdW-E35!{1s694`G`=DSeVe +zvKBD`+srT`gi8ZH9BUm5gNJgVqU_KR51XBElKnNgYY4@zbrM2SwPG%0Xc( +zCa=UyI!K7vqMLHKPl0dQ1T;dUo>_U@iEB#>F9hABn#i|gsWXp4I3u8%J*BG_IyYCi +zC_gW0;^Sp$BL~vaqEN3L|Mf>Nu7UmwG=b;A(pt(sBZ;?QrFZF#h62J@Jn^S=+NM8T +zu*f}xvf*G_qTtkuGjar??OSAf>yse0{QJwIGC`u`m*>^)W{q&EoSOYdG_C%B +zOYcP9&D|^R#jX`X5#gdGmFSU+q6ES}11DpL>IF%E&wPZy~q#xp_ +zbH2&Eesh?1PlbgtI*y(nAg+YSDe(7^8rZQL7N3jm+*hssA&y8|FnYr$omtd?tZ-PM +zY@*2Ytg8j-eTAAAF6iyK-8(6CfMJFXE{F@&3^3<6Uv>O-z#F^BePx~OAkgC9O?q3z +zp=zoR?KN9Z?*)PzEl6w3B>gMEf^W41JL*@}fl0=dK|zM2*KIw?WH?KtXbdoWT^Z8( +zk8Y_R(${1gm{8KeRvH+{@wbNlq~zgWClS6^>{?T2PGU#Nfz5ol1xY<}ZP@G3E7Jqd +z>eaDiTlPepiTkZiN~dBdG%jt*fkf``_Z+nwhP{}UzDDMu(8)yXb`>F&F)Kkt`Z%({ +z=y&?&6f%iPC3$JUe|BN&#;TtzW91PE1XjbbwZ9f>(phydI-Yr+<5q^BBOhEzr^EB;e`VG1fqYnr +zrloYQb0e4Zky&9|9`HK_EMA7PoOZd@A%)Oa0qUjwhqx9G+q;2Xmk^f`iLbee +zo +zqKg7C(HpMePC%YT9ZcC`cNp!j|6ZMr4UknBFKSg+H~Z`1Uz$vTHEajVe|Vzx6Tjwz +z6>=>@#?EFgZ|UXGmX8Nd6N?jYC~rilmU2%F%t>ws)F95OHj>3=f9S{Qpep4nDJ5$C +z>CvXZwHHD=0*Ko7)nI!qg8UIyUb-$J8f6v?U~_p$##&`Rh?ku)~DmNZ>2dFT4Gy)tQe;vw#6BzVQ9p0LFwZVXAhdXLE24JSPyES +zLydorNHD#qvvq3Yvsf*qz +zj8~$`pZLgN9fp`beBIO_->0rSR->^7e#)-r3p9-}(1rkLb!EO%lJX0ir2!Hmp?Ju* +zsq&1OB8l=vYWoJjeDV)CBvrv25TB?6+Pr`0D(5W>WsycHWEA*zYumMTmP)ILC7~ly +z0tvzfaIBJ{nU0FjSD=9k80G9=cxt*B`oeFKHsF2q6?D4Oaz>&Bpk`ixY`hJ`Z|mS$ +z-yXVI&?IvZXQ-m_k5QN-=4t*~t(~|*bM$}-CFP+PDzml708r|!A!os%7U#i|X +zJ#?L`H+#d{sY62pcnfg1HYd;fLiMTE=j*uyNQ!Tq^l+l)&!K)1UoS6&#_=h?ggRZCmw!fgtzr8E)vE( +z)VLQqWZkN)1znZ^)(B+a)Y>854u;iqC~O5T&sEoYE3sS>Z86X%c%gsO2+_$UPHcL0 +zwZN+N9me;c`Lp_E>w(rk!Fy}z@@$RMG85eX5Gh9myy6r+ymxmr4&>b +z)+4h$-!8xa?md`;T}V?Aq5$Hy`QpBqTMLs6WNL&LIPLJ!! +zgPoeZiy_0Wc1gTa_h4KXS@_FD21;1#!v1N;NijvD;@@cZZh)A;fefIXBM)NU&W*eX +zkl|=-vQ0HKM|<;=xEy8+0fFh7IQTxWr3AxdCl2a5L8SmbNQTj?TYnOsWB6J0 +zo_9;M$7aAXbWU@o(O&)h9~)YOh=v2M?K-E_T*bl3yljzHR}P?w#zcj`u9B!#HyUY}VrfHF^ol_IYrU1HQ84 +z#A>P{x8Umk?Z~|3Vt-c`X=j2!4|d+E +z*;&e5=sr|zHo>JGOmV(V1|Fhj4cG*}db-+i0Z{XF@nL*UG13J*=t($uhb9!DS)qb< +z+Is|nTUp%GSq1&pH;H9+zH&$CL%bsnj)Qt}obyQHqyx2ih#7*Y$^F7l>SZ2R34E%Y +zy*YwHAcWEW8JXI2Ule!UsKv#c8`BAYoOQ9+{iXwYH-*aIDr?}e#(J>9M}Rl(5#T3Z%cUJXHaTuknxdFlkuB0Fo|ahoGV{TyU8J$dqtk0|7k2km5{#aH-TFNTvtazE%C;ZxWpk+_wNFbX}^FJDeVn54xNWy +zK?ID2bX;;#cT)>+$+t^Hv`eH_R+kO7F%-YV=@g)@c(7EQ^yg +zyG|#KluZ;C^rpR_R74)@tTSjTddlRPhAlAcG(A7tY8Ta;@c0)4SQd>Lu{JXvpsp;T +zMY7sv-gy)=ZBsbtWCP7_pH4_j5_V;MDdh-R2801wxDnR{CYCS}YLO6n+e)I(+eDe~ +z;!ce5E#b;cI`*R(?ls4~1(v!yU#QLzX#GFk-p@AVB5Z~qN6d||-+{Nu+s;Cs$|r8Y +z0R)4W~Sqv%=NahJy|JmCDFqq2oNFtVRDbSDDPIVpWNJR*n-keCC8WoUM~E +zoZZUCz8u6iJ54Z>9O!9(zK(1C_C_jScCL=eg7%L&D4Szv>2 +z3q~yy&}s-4J^%w)jF=a&45*5ZJ3)22Rnj}OK&&Kym2U-Ub%>PP=VbfbP^u)_hjjod +ztvLJr*4_>D4mBF)J*q}AkfCx2zt(X(cFHXMIubmz6c+fVNed+a%b@R?1rfn-onFQI +zsvNcM!LI30pH)Bc?HE9!(l1-eEfoSXS$x0_;${EJ8({>dC`+F9}c#!?%^vL$ID(z?^l_HtQxtz&behA{pkBWr^~h8)iw+Qwe)-a!*!l#$B=Y +zIm8Sn0qiJX?6&~F5qkoKv20zA(P>R!I; +zu3v7dze3_@{Sz1iQ9~wggoc6NWVu$>fG|4w{8kumNU#*ob!@?Cji5Yq%J^QgHo8I4 +z#SzR;Hunoy;-9YP+c2^fBi85W^-v2sB$NVn +zfG(fCF=j~rCn$!QPgv%b7SW>bWd9m+>^9O&NXzEQt(i#NMc*zNQGu?U$JwtprZ_!M +zk%$oCalme~AdSprr_GAKpo{)+!+k1cduxK+L-j9~kAARK8_4k6j%!)seE2@LNJ1x6 +zpU>A5Z<~E#DxPVuwwc!wO9_@&Ta9sv%J&v18k1(4Yc2xY&wysbWYDt9T40*hkK`Yik9lKw +z!)5{wwo50r9qp}k!C>NeaObop(>=%GlYp=7p~()-PRVc(qs$Iz{+*Tyr9iu!3nm>- +zr;y3w(>9`wvFk^_^ZU<68yX4?jS2i7XVd1HY{C}47W_f&vsW})7`qNY=*#L9+d6&# +z@A(pdM6p-&!!@&qqyVxijxb)fLI5mG(R&xs5{kwzFS?s1W$NvWw2PjIkG;8Vz{qgN +z#IT|hp_SEqA@IHtwF@%c@_gmO?YxEfBzCWq9g;l +zp*Wy7YSg!vil91RM|r$5FQU_n+>(3VOWJzF^)yAwKQ7-3|ACW3hG$rtGALu9w2={- +zHaf2kSun-s(ravVh<9Uzl9q330L-yO +zE)u00{*UzVe3oI+qk;SzQ^{gd<$t6Au=s1Ee9E; +z)!%Fu1!cXp{)~P)WEP##{>S$|f|QR$#K0Cxt%ke~XTERNh)y!uJv2^x*)OJ-EJ;Kn +z!UN>eVgPb+?iG}`cR&RxBRDL+YT=a}B+%VO>lhT@D2Geuy#1sxZCDHbnCeHrHZQO< +z$)4^TcJOANg8sAzh$=Ojc6PjF4N&`av)P+zgQ5x7Kcqdh`+zYNv1he2j6yUGPvkepjvpKn)^|k$RYa_N(j*{mKLFY6vUBNnI)wN=&Eh)i +zwOcBC2Vgx{!(-c~A@Q28aS|Q@E1NQ=KcJr`T{4KmR~S&k_Dee4l{E0bmQx>;(SEp< +z&$r7+)C=&-!*`Y7CM;S-&NG>j(UT=JH-0wDav#46tJ2td7tmfXJYeJ`$DU^#Z9a$L +zD#8Q)$M0o*N8L07B`!UK#*m6|#<>c~;1>}32zLV!jy?fFFAn|)sNP%+r8M{}_1Bi> +zG3FJ1yL+xv_gDq%c5YYv=a2h{1>uNpL!uTseLXMdFw4|JCs9e@1@>`pdsc0Xcd&1O +zA|+(+AlKQkN=^3Z3mD%5nAu(*L~zAdcpE#L#QdWZTL2R$)#k=JD*V<$CwtV^1rSEL +zk4w1Aa0T*ayA78n%QVznBaBzG^m+kGudd%fxHuUbBp3tol^PVh5gZONUc#FBrC}Dz +z4)R^dPom1dot?TYY(&3S9uxXo*YONSp-80bXCbgW2$$sye}^uk`AAMaPP+t0W+0pD3vI?dusy +zW8jUQ{Qb}h`*^U1j}$(wRGbL*0XJb9qHVpM0Y$Y}i0gFRALyhua~f@NRj5Oq2G|Sd +z#ir&sPXLF>DvX8BXK+(s;m0a()NyBST$Fthc^f68EkLXi($Aqr5D=Q(=5AV|0)f`6 +z8fvhsbyu{OWr4>*ug4YnQAS?$E1-#AXj7)SR!3&L2U;%SJ_&}brHNjBKhY-WhZ5w| +ztV!3VbW~Pj`f&0%99R#cn`6^U_3wX5uwl?C|M?@4<}w08u;x!(D?R#BHtH@6c^QY@{nSHuuU&B9pJT&%?rQiN5@N&*LO1AdstU~!_6g#jSSj^U +z7Wk{NYZ-()1HzLu*kjxj7Wk~#o2rmUtH8wZ*11+QT`p$AThc +ztQ|ea=@YF%KPHr!v}9yEnJR1gl|t5}oLM0k=KI>A-s_WPQ%RN4m&OCInf`~kk{$O} +zddAH6YZ1imOu^lS^Umw{bAlFgV>}jLY%Ja9Xwd|hq;iVTAC#pAG57_VvHUz-}l((Alds?Un@WG +zB#5|ks1@KMDKF`%ZH*;@&;ZEgDA%2phV~g19lKikJfiXwC;ivz4zcogz~Tz1H{!!O +z2S&~1LFB#3ZFF`QjtP9VeD1F`w6OC6X*(rV)0YaAke$UT8lMfaWDo}4AiwgU?0VI$ +z{^V9j{~Z{3RTGHjw9zT|3o#AKa&(Y3B1~%1K1oKgkkW{~lUJ7ME@%_|Z4@RvMXw&( +z-k{_YXt^jy?UpOnNHC~+{7H{ +zfWPIBDlY0_Y7hk_^ZV}oEfn+2u{XmBfLPw+vN5d;)F;l4#exgv-adzYBGC~hc*@4{ +z6i<-JWiPie$E=(DU%IwFC*mNG%G~>T-$#J?YMaQ29pCUk6kD3;nZJtC&;I!5K-| +z72Qc`5K;{V<9(IDflh^{zHwXQCINc@FvwoXG5&l|cG*z0P;CG?0Id+aubNA({dH+4 +zrV&V)WI{H@1y)WrNa{Yd9m})D%=wr#($KzAqcO!my*HXaqD6~jXyz^Lx^E@H=Iuja +zc{aFvEe+c@KF-WINw2y-F94ymU7-Z>D-I^0A##e8NY;^XJ$~vk^|Rx#w?+X4J3o;Q +z;f*L^E1BAzc17+L-Tcss_>g>DPO)cETUN9;CnmOkZXeJ%=uHb1+v|%^2LMix0{KqO +z$p6E^RSAv@f-@BD-a>e|+?`+CPQ|~$IKD7;<_feM!yBB|k^;l^Kz{mn;x1M!yX_-? +zpfcn|c%SE1MLElTlkng&%5khG=$&2oRxUxkXdUCX97USahIFPnbO7)!Kwq9vKtkFx +z%`^277bJ9D%RK$bTcu#2b1harMa*`{5; +zFN(+6z0=PrmLSQ^cP${*l9*l@rQwMX3L +z^i*3>m$MN_-!0s(mo=+-Cm?6FZ#&>uB*sUz`nTy8axY5$A)Wbf{;YZA2SKarGB +z;XxF;QY+^nK>zD~zRHovRfa%Ov~^0`>XfY=o~VF7EfDSOB}g3QC2ILI}M*{ok-cK9wiF*rD6A^H +zs?JPCBeMq3x_NyDx(r||gcAp;z0}Ahvr|}9TwTs$X1}#FX>>NFaRPe@5mW8-U+Trz +zdDjk82D38CG)1^!(Q^3(T~BL +zPj*{{sMz(B%~=dM9nv*%FH=d+kgq#XjUTTzSF!3^aDHX$-UbqixJf^m@Lq+8_R94B +zH(^ul#eSwGvwBBbMOl}e2v~@(T$fqKxj;fVT^2YyUY^*s%>Yt2JknNAOp`%jgm&oG +zoWd0KXt520>-&%9+28-U1-mp9J*rn7xW20UMo`x|)mhH+a4m)RXR%Z!6+YYY!*At4 +zrQ*3zb-eJ#wO&7grec#R?2oz7sw!lK;x`6#p(z2tYWk)xc9Yiq +zS!IPz8{l_cT{9C*2*Q*n#gL>lqM_z-PEVdixnT9ZPH8>n-o% +zH4)ZTm*cFOO=)J|(2mS=`8oDH0BJ6#JrCH8|}`qa~cSvu120`@Y2$HH}RPihuh( +zg`1kNa3;_skPt0cV?1O&LS@Vlrp-=f0vIE*?T|y#Il!c&I=--BZ5+Q?*`dmef6K0u +zqc|=2{_8_mF0i5KhHb(m2uhQ0m{vdSx|{e#X={mYRJ_@iO<-$O<-5GfhRi8+>z^NY +zl4anK%v)=!K)`MA;F&(;R#xIuNM}1V&ky#PKGpD#?+Bq)31RN4^&j!x3h1)6Jf`ge7@N+x!XR-=?ThA=Sy{w|w-?rJ3?>9x>f#$y;+zU}Z?5^YNL +z;ZYmHrU#oFPA&#a1PQdmDHT(l>u7%Z2921tcuN+4`IxuVE|;z{m9s`KNE3&+#lY1S +z?JI4@slk;&yxg1Mg?+$<+DF`?^)_0s=&ouwb;G1uBTDPgwF6ju(JVq67B5lFBO|Ss +z0quS}no8{;cTYgXoE)a`$7V#Y@B~+h%c`{Ayn^quyVJrP=o+EUUq4`spPbl2B15?} +z2$~Z_ZLH&YYFEjMv^lO=?c;-RtGi|OR-+uMQMkr|24Y>WU8tV{!7mA +z`o8ZFmA1A7NMSZS#c=7n(XnVYw?RFeKbWfu@mMt!JjN=Zio=>$l$pZ90ue!rNcdCE +z)Q*2iFdAkWY5^aA=F_9MbOh5>7=GFlY+6u;FnZWNw^46Q6{2IQY9Zw&+jg&ACdaQE +zj9tV0f#feACfw9GC*tQ+N6`al!nuO$xC}unm?l4?nKxzCp&QK1g*3pW@&j<(Q&}lB +zuJ^~UN7vl6;q-#-?|sW$bKZ4^?}#t5EMOFhZzy}lV**d*nRy^gGxPr$cchcr&dn0ueA{47a9spDJ4G!a +zAGnX8y-0HqkqOfB1pp4;ur&q4wMb~seQ}w6rJAiCl}XS<%1IzKMuUm(6l!ttRmz&0 +zlSto{m+-ihCXH|AGcl?bBR_L_hIu#yU5I5Y$~}s&a5yfSERuJE`6KshLAg8Zj1EZg?1Dt{8a2FH7#V!rE%Ol9+cHZE>QaJUiKXge +zTS+({uD3Il6ODe$MT>uJXkGpo*|Zf@V_(aI9opp^_;^D&WAI-AfT1zoVjODN_*TW- +zsz%?`PROpcw^FN+6nO;2BCIvr8&&%IJ^l?|MdKZGCM0m`90Y(==uuzKa8}N{c#Glu +zyfoM)V*oy^R)YLv;`Zxiv6rPm$fvcJ7g}UKbnIz8fY|65!@QEaBzEbo!(`Y^K=eJu +zA3^(F30OQF*K=L;6}D>={UE{>$Yddy*FMxyEEF>S?Lr0>R<%lhX5!X5eUlMGVZRfU +z6$L`}-70%ic#i+ewemicXK`#b~Y_Q4{ +zNg4)r_nWslO*0#DjtgH&5Q3wlXt4MACjb#5qk~Ud9-<=pMk}_6$au +z(6~#a!CF2{KW`s&{fRIa_{Z`eNTTW>uaHyt?v_52*<_vtEY)P4@c^7`>tCXs!o&NW +zXUOEZH?e#0Hk}#6hjT6qe-ge6>JtWpYB)s7=67vbb)JD!6pLB0ojQDKoiN>&$JPzx +z&p}HQ*2Am5nyURx_I`JP-|2qKdZbdKU_vu@Tu*{)K35M($z%E+MZhWln9~-8n4Xz$ +znle`!1<^w#y99{P>N(;Sp!vpYUfMkLFju-_Yg&L)ARf^2J;$GK-%~hCO3ao!tRYrV +zbjR5Yp`3u^dot!CB8%HF6@V-E-!tarVsO&?Ii;}XMIO2Hq*jI|#loD*V0<3bQQ@SUO*iQ@#}DkxM6pAe@keGB+$B`m +z^rwxLzVtCA7*s6op-8=t=1S)OTZt21`y*qHu*GoiXsXU2B~^n%jY~9JQzXuoGC4L` +zqMqn$LQgji4qBlVo$B>#ei*&8Qg}6xJacC)cl|eyT=Xz*LV?NgrekHzLHB656%~+t +z4O6w|75tCmJ(p*?`#)le3~`D-y&J8uW5B>IQ<_H$0oHgFtq15#PX@%E;TvKuXRJ;< +z(9F+-pDJEnIXfI|Oi^{=QA9>ybOAmzNF(6Uyig=yp^Ss~1ScSHW$N2AXCRMs +zL%78xy3r!;-ttxDL;sznHRwn2VKu%_7*hlVaVRp1-pfO!R8 +zQ&QeL$&RKF7o*0K^fGTeP{a4~d@8**G5|@t0Vl#g21FSMI^KJ=-YmV8=3pjL&X_3C +zgGixJZi_~Zl<*kzbv$ZfD3=&yr>lhLe+bf4vaRhu*Ds(fJo+_hWe+6&A`=`#m=5cI +zUA)VN5?;tU%cwa3@cZ&8S();q;+$TQkTtC-kyXbQM|6lU)5?pK0%+L09_>@gEKxm) +z=h^n1^(OvJ_lX_edKesbnxO<&YS4G&fF$>hjN$@%!G>k4=bFNsy-HXXaxlE_0N>Aj +zV*y8%nY-X}?5$&FB#8uUGCEfnOc?JqUaqA}tF}A35#j)_ +z;Vpl_qFQZw#GJG`{Q0G@gUmf!9d|-gPahh%><@XVfXTKj1BWG<+yep`)%9?iKdn=W +zNt7Chl|0#ZRL<+TmG1+;K%EA?U4U@v7bwnM&LpkRE?|C#mfR<>1_0{j2@~^jZM!A` +zUoGxbQSG2FRvnS$A8RK{Ya|J!6t0s+BJO4vBY0u7pAGvNmp$=0YKu(<~-Fw5w! +z#lyOz%x0?5Q)5^cet6ou{@2w6>clLe+5tXgvH*5bj)1vE=koYpB!POWp)dn}q&jsE +z67>6S6o~N^`j`3rh-1+}Hdmr;V~;$_a2;dLN=OZqO%xbQrhkJ32p)3_plipz&s9H+ +zLg>OPN~rr}ES;O|Kw^IdQ)qSlT3BlNm78w|ABQA<63P_iA@3h5P=u1}j>w`=A`^@o +zI{14LEbrHDNQn@8ox~M7m-~!(ve0Pmr8j#!A`iOMLw|bd;S;*Tj6oEo?FszfwL)U> +z*^lnkq}Z7O2dCOn)S>V9v!gLhZf@{T7Fn{flj5j#hS^s1DEa!jq!t2b3_0<0?UX8%c5LbSP4N@yYgww9fL> +zgwq@`~=2E4`p(f;kcCgmG{zd6= +zwo(T%3oyg-C1vXlNM +zU;IN(C*f`OwS9>jlKW|iM&ko_qSZk7(dh{b08bfO3MLPM_f#fwP$Tatd4!8Ez54kO +zWWL%;pI{aYBlTP28s?*2w=*$gcAg$tf+zqWv+WO9b2ZYX$!)AlO8M+8r96)D&n +zT4m&80tQmKHoBcP8QK=qQ3n}1lVf+BmJ!6PE~^qiBnzCeolorg)|y#3>L(=?f^uL5 +zF7~Qt*OYsZ9ydBhAcS4X-~jG47y`=vQ>d(gEkrSK>Cp@;yoTi{i4MbsXYxzIKjnH7 +zwIh>x67R$w1O%p#}X2f-Z1+I3mlT+kMU{R#07gK$zx(j- +zrVGdzsyovS?Rr{DmLgMP!3G=1*1$*(JmfA(+N(c^G4m$z+_O(2^y3*r@%0fm#`q4H +z0pL|<<`C!fF7&!12;ap9Jx|*nanCeOjG+uyk|&#oXE2?Vua*U3rgpO2W21a{ +zfhh`b@=`H0En&%a{yd&38669RGc(O(=+6aoFS=r +zkaXU_XcU^-AjAVhE>V#jM*tU=m+rsB^C$kzjAeXeF#k?7DN@s=wrx*s5U4Ib{R`sH +zo+HzkW3jz(tPE6PJt!BrGV5VarW6`Mg*0(!fC3=Xe}9g$|R%6VWli +z6p_iH?ERcMH)1TcY~UZOvoc|xP|*R&bO$0`5fR@=|KS&thrc4g0eahgA3BR8ds87d +zUrFhFEH!E)x; +z$d-ZN9V~?o+y;NjPfP~SUQMZLPk|$4gf41O)^gbJPaLJF_ykdk0D>=5VD)X_{cjAvsQpJ}4_gZ{P3;?U5BhKT`ChmKm`ZRr_0lzd5YI@M +zuQ~NlCb>0@Lv^wTCMJY{9i0t>NmDmKn3cqvM0Vq($ +zylROx)<0OpP00J7+XRw_X*Oty8f@<`i%sky{J+G{(PkIT+ct$1o>op~;GTS0{{h{n +zzIZ9TNseq~rX7C2QBlJ18;}g-sWpSz!oR~VXlCiH)r8$qEOUQ0t2l_^A^=}&N?6fv +zv^kBJdS*h@n)rVjB4UwYs2JDZtvxt~6Co(ZE@un%tpvl2rlQUpd(GKXV^LmZl@I?4 +zz1}re32yng5#UyOESp#Z%B-Vh2pI@z4 +z*XedK#KcOU1d&C1Kpcd16?Q%CF;LWYJa)xp4zAAV75LqMC>>UdDrFWTUxRB$Mkrkr +z>M(Zc!VWh7rNoI*fa=L+@&mkUb!Y_IRd1rr=ZeD=+;M9r=}s;|KY1?U +zt*bZlu5t@pH0Rb1X??YE93>KLBia?#o&9!4#yH&cZ%}p8i>FMT +z7qYHId#wP-##j&JQW(h+BNm#_MW-AL2}N<_{@<%-iRj1?N|Q=&jXG-uW?3MRgGeHk +zvvsWie827Jd)vmLpPRFn?+%**)~lkA?3v8QW#YikGR7>K-&%*>5S_I35N8Z{n0 +z2((%6>ve1+K7OHA$LwyzmX`?YL-Z00lDj$xP)m*dgh*J+SBQ^V?woW)eC2|R2{25< +z#IUYF4dU|3W%5Xt$CFUh-oFc_7F>$T$-n}iU5%RrC@SU!GlP*`F^l(*sY2?MI+NNI +zf33-oi2EC`QuW*(;{336!R~6TWq_9UeI9dF+nk>GnLeKj7IRsKu!1FWrJRrHIpt9S +z_ydPOLvWawLcPdRIrx2O$7bm;BIT*?O+BN$hyGqnbp_7<>RgynQ%=Y34@?0v-Nw~$ +zwF7}ZpE7|qEUYM;rBZ_VPAN{*xW;SXJ|MK4?NAv((CPWznDquUJpp>f|v`W1bC +zhFeQ3Bp>*SR$Z)8t6BN#58X*(UP>x7&{ +z^Cnx6Ma_?0%vXR*R2ktcCW2F@+cEe%OmuhJ +z7nRa%0y12hWP{gLj`jW}%;uLN<~`)NDrh;C(3*0Rrp5w*Cd%sC;FS5I(S`{VqT-l^ +zUY2J<%<|}X&A6WZbKvgnc4s64GHvIc0gcLQ!O#O%;YhOy8cb2q(%9IMEVRqPb(6`A +zE4nwJ!v@0<$R-u3TmPPbl{k+Bq>Ti7L2=hp*%VgI{)1&z4e4)%f%xOn_Whxf +zKiVz9FEpR&oGg3%&JKI*=+x}hHfF=^(;9JH2Xc&ANFb9zgOn&|yJWP#-8!*2*Tc5V +zF#Imz6c_zWe$ia!5T8KeWIWW-Y4>u%tIevc7;|AUAZQe;_Nqnd9F8 +zJpRt=1)D;(@{k0(EMBkH504})1oY)dfLU5on$`m`ErkRLC1+i@>LLCpYgWVMqJVk? +zsV3kc7$C)^`NDWdoA#{>DLgIddY7z!EHYm2QHSy8*aj3oO+JUFEFmR~7rTFrllA%$ +zX8dr)3|rA^j-1ASHJnh={T}A{6=TrvqmtiAXDdbAC%C%J>MduAk}4zgdV*{FUPR7~ +zf|T|LcI9CJQde2hr_j|@ZX_OWw@}{pC1eEz!FBc`{X8;w +z4^7tVsgtUwM)51*-4}Ol7=})!R-&{vDtSa=)uO(#aH$Iz%InbOFXB19RHiAj6AmauF0)H +z{FeLqk@ZRC5E43-B0Ex}GU)mwZAlPvS5Gxu;*VL5!0mZ(F|b{Hx+@ycC_1A1^4pve7{nLQz_Zfs8esuP#{IcT#=(OuzK#};OFwUluwst?vJ=XgiG$-`4{!=evcB9jLzMoD=#*u_c})j`80tpAz6(v`G* +zOx`ZzjVue;I2Pr49giI}E~#cgE3=uZc3Fm16C>laA?UlIYBIy28wJ7D93-Iw(ceU}s1XY^;{?x5-n|R9w$v=J9&c$6D=J+oDem{4EKQC<+v6Mg10%2g#hU +zKbSes0mifQ1^~pI5G0@#qn3EHWI+=5sdEcdlsNrPC90A#ajh2d?%i5dieC$_eT&U# +z{4gE*)$O=E&Hx7>wJu20k(^}1ibjlgad0==0&+(AV&n`#Xs(A3?52n255fL@cK&6; +zqvg82HB|7kELLZ?bOVyG$(u^w23TN{6J5KBI2*V--Lwtm;LlSyddFhA`U5r05I=>L +z#YeGl5tieDxiyOnz~XXF`|!Z~=O~Vwz6FRS@f{X{FN8D%QxyA-*Ify%uef3~V^a=_ +zy9Hk6*&U0kW-REK147TGPe8(Tm}Vnsg;7CYA)xCK-UlGGeGum!rS%)Eu)@Jc9r1D_ +zb1o;5)t|00W`uotfp53Oc*K@t%NiZWYpa_bz$|PZZA5KA>G0gGooFMGcxHdP4g)Nt +z<@6^cY|)2H3&bEnq@l4`d9?~pMF3q24zJo~6ZXTH@DcZSWzN>{n~|x2BrH+^ITaw< +zNW0SR^PGZ>99e6TeUcJ2#`>os!Y=j~<&`)@2|vk+)4Hy2#^7rc;blwAf<-~ACvy0w +zmQT`do4n81<2yeHciGnXHgp_lvoRoXKJ+C+3jD?$=l%5NmkYnCQ~cNN|No(?m+;Fr +zcEdb9D$nij@Z|KT)ES=5N0(>h!ui(S%HXqVIeseJV-~@J=SQ5(?|eeHNSy8#u?W8R +zuQs187#IWp(CfP&P4K)^`$G?P(Z9PwyxlB-JaPqk2NT%GaE}eptL%4YNW? +zq-4sC1D?h<%{T(`AbDBwUr%xxQ{N+q8T#nbTPeo3rNp7a>8YDDvQUub|a(+jGtx%Il>`k)a;0t4Y^5JZB9}bxZaBQ%@zjIDH5E +z%n7oe@Ds-sZ_-p2%K1`o;Eve@!8d0-u)w_wvY80he+sI4;^pAXJx}1sDH&+o?^M%+ +zN(?|wEWDN_Kou27(U)|7acCRrgh0H> +z>Bx$vGxY~v<+BZ_F-R~K=JS^!(8tHl-69AXk~PFnBbwP!zB-(!4}mT{LlBJlG|R?E +z>jU&}S(jaDTjqcEQeY*e<=mTB?}lnC$8p +z(vS*!9m*^$D^)YdCNc^~D?B|*u^7;qYQ5=HlL?L(|6VqO2)60OYMTyA2Jh4Y{8O4P +zEfo+_mhy{byzLDLK!Acnj@Pr;ho>FGWjc4t3X`unu{LSjv@7|~IsT8SI3;%s +z*evZ1xV$F?qX=T~e(N~WN(%fqi|A^wQ`b1?l5?aUklJQJud2~~#Z_1if?alPE#K4K +zN%V0dfhjeC;`NkC_q_+xE=3>dK%2C +zzH&e$oUWsmDwmTrEaPw2J#ZeW!a}E5vGy(RBSeoMwmBfqj_$H55~vUF`-ei1?O+CJ +zw|FkdC*cT#lArXZpQ-IEPHe%S@^M)XJ_iN1Mcoi7*~QSnqgj-dg%bXYUTK5m37&Qq +z++;6hynu2K7mp_us(*~7md345QvGLAPg5;(&8d8(p#W;ArejCqFS9neE4gG(g2quWZGu +zT##(!y=Wb}@GD;a_~GxV>o8?d35DFuOanz+OX~?SvdlImu~;I1-u*?K;0Gym*lHtc +zMLbzXx}Z8rvR-bb?9YFI$mjstcg|l?%_`Y54`|3u@2V3%?>$2A*d{N|g}zCW2}%8N +zYFrtMyQI%*Q0A$!JIZlq4Hw)B3Qg$vCZ{Hfshr{6;}T^8SR4!xoLi%Z;{vR&WM}YN1`gN5bYb~=8x>|73n9~IJ1w{hp(eM +z4_Dl5jzH^BS&T!Psf7XJfBD`nagwBXu6u5mfo`BcC(DDvTJBGy# +z6L{-pPr>NOTjf*Q!5q+8*em1Fjmz*=|}h$=*u +zAgQs2vJoqnQVbiIDLeN=;*;0d&6hn6-#v7!Xnoe_T&oTv3f`b%mlncC{hAIvYjND; +zBR$*lw8PTkMow;#Wgq5&&_{}pW+WiONe)HgFwmd0C8ob5E#Lq}kUt-UxhF#iz(-;DftC`d)p~#T7l|sw5A4Kg#=>5^E?Q+O-ttO@ +z)?0Emdv8@4$fY5E4Dqt}hWNoxlWLM*HpPpV{Q3CQfJgjeVS)f%jZBz_ZG&ycRVrk0-5$pc$I^MMnsGk(F@^FgAX +z+nf|1&gs>>NPXA|QN5?XrijhS!iRaerGa1T;@El&H=|p)5Um?4TUn>TRajt4_Bd|= +zpCB~sy<&CeWDyzMxo_&>_O-PH_!Z9|T-aIUPBzmJ)K>plrhmqur?gc*QnUVkl}wwE~xXiP?Lq-i(HC)~yqIE8yxw +zPxz^saA3srQjWRz(i^Orp(b_Fc_R{Qc@pM$)p1q$RI-HqdB)TG>Ys^MPnk6exJA{n6C;lH`` +zT#GItLWWoU-7YMAlnoJF&e*0niUaei5w(hk)tT)MdMvsU(LK=9gY7Ih7s8+z&Up8v +zH>@TVvKVz$)xSe{d7f7;QeU%8xTej~sMiXD`qp@x+Qv7`y4`1K6BJMgh_ +z-H}egVNuN(^6$LrHT>E>Y~XaBfoMV=B1LMik}ReScLq+U2ew?jVHOf@D4dD>=iE3k +zYwlP5NE9S7zB5smM|3EX`$Jc85ryiYckBs%%{@_-om`zabwP}^ +z|I5mvKLHm%4)I};umgzU#*so_D=PWU75ruL`_Fl8TvHFu-PHd#u`8YEd~O6~IfTA4 +z4NQc&;BMnLF=*x3xmBbtx(zr2OQlrT6S=qN2HpD6C9bP}U@O4KRjvCCr;$DJp^4*N +zTu9=B;GDq-mIZvqWh0wv?PQUT^fl0L$$A;UY6UIV=>Ud70zN>St$GDdTvRvZM@3vZ +zmNs(-gzG7}kBz;~-yK#53qu2+Y1jI+6-j23;t&4WTjZA;vLBSwl$KCH8p5O%rcR$r +zpsH{y`bn!r<)=2zrECNKMJ=CBU%r~5&x(6IM(F`Zq<1!P2@aBbhmXcKHS=b%gpD~_ +z>v{eHOdiRjxngJ%^+Fe7?k_z-;I8J_-CSlRPS(riLpkHu-_&blJ5^8yWo@+#=Bn$; +zlW827wC0;%>EpOUV4Was!(a;oeX^d)bfsnbxyX`{U`=|p$Og}^ly=v&&$}ajwI*zx +zd$%Sn78kjwc4(T|gnBcxDIZ9u-Rz!Jw`AWiZ0;};%UmH77_AWqSoHi-^;LKUjEn@+ +za|W!WQWF?;7b$G3-cZuziU3T;Q7?-M#QC +zuJQx>iuxX+{$c%6zZLc}BvKplys;BGM98V&r_v4`GYr<3{)}bWpN8f!+A9L|i0nJw +zL%oDXoXb}}7*!G&v0TvG&5yg_i|~!8xoA8rYx>!h;_leB(D9P%0AaL>W)O177gO(j +zjw764UQ5noVA~SosX3r|{AZP{SOPI%7a2q|t0RMh+s>|ABf4DE)t~O#8Sx;uScS0B +zazA*fYQuVHPSOmEZ-Y!Isynx?r+)kfvA{VPApChAiYe_Dorwel)fB2ZMd#>C*uHBd +zU2Q6^L|De;YEiWPgy_Yp3b6uOwE1(AZJTK_Z{`#G$GrBYNj0m?R6gsn5R+O#?wfwh +zCii-zTng8wB4=k2vL*aQ!r(sJe?A&{=j29d3@;qsrOyKWw=VK{FVR?~=o5hh2|K$b +zy^$H=EckZrz?I_=kK;zn$7tx~J%Xz{R?&P=iESJ!Ttb;TZ-wb2=bdQ6W1KRy^RE|G +zH>;FAZ&DyK3uIMxpnvNuE~*4Hx`Ju()6zDwGtBbA$A@t9>;lgK=`$At4 +zP^8{%kZ;xK+v6@(*E)NDJ`3A|z>>_}PLmm*jZK=HjS$AlmC-*Z+dOKM5;j~<4=Fp2jbP4Pk8w1z4RPIG=W{@Spfy=Uww^QKNoZ4!=*rEO9NVK*6mvz)PA9eN`g0%}i+u$HT-u1f&w9 +zEO3$CT_Qk~%w32KvG@GF{7K2_9_qn>7+l@w9XgE2>P@RaKw;i7edFkii)@FIe9p&WxWiia{b@Qweo$O{rbhFvG_EiGMzOiZEDlseA +zSd>8E_#j`g`FMpAITg0PJBhKV{gG=9ZJ*glaD?3(3JA{-+khdRG{0fs%81x?T4e1( +z#oceyN-}b-^ddW8Iv^60nKn)#GfYi>J_PRjLXBUsImEr870N`^o=zXR;@WXpoqGcb +z(DoAiE)H0d)5t0yC7{t6blQF!k>E4Sr{UP3vN~Sgc%l9L7Ubg(KQA@l{-mG>I|@hQ +z#1UiuE4Y&&XgIonrc?xC8!TiVppKDpyAbSB4nOcfvMIBe{%^t(vJN-j3VdRuKqkJu +zc?7_Ubq8DD^Clkq}GSsVpxhogm+ +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 +zj(z#wH|Xxq#UCAP@xe%|`aa5*sWB1X|d +zd5{PjMM8^6YrAS^qyH{Cb|Q)=sHs8znSevKCo}2Eg~3MkQ@smga4Ze*bRLeoKI7Bk +zop|nB+F#qHO*J}DNk2OUX0a&W;sF;fu3C?rv+0jC88e;OWmoToU#A@s2uo*%aBGPi +z;jT9FyfCkpTDZU}Mmb_%Nvj09m_>gqTa>lPFW6HwjYv&Vlf{wNgDGNd*!Q%`c|X@Z +zY#GA~FD=#A!2_W)fOWST8|p)ekdhSKRdEAQGZ@6|%JqAeaUwdAFL}Zn*Qm#oFluP6 +zlFN1VVkpDK&-P|X^knScMR*`dzK5@;bc1G9JM?#6<9}T1RK|Y)`g; +z+xor<)US9j1XwDRq7u9$aJ3@t%B}&abk>Y`|0U^#C8T=OGv9;a7;MnsSdg?^GH?H| +zy_s+QTt~4_t-Jp;_fLbqB_y&?n*WroVjZxozln>_Gq(|H8V3#P9*Sfg@kuJ5MsEkY +z(8Cs2w$f=8V>W!?8_LQ=b!Bq@_f}ARtZtuf +z*YXUgifM!Ly*q(gF+N9H*&mggx#<27_)+QIJd3{U7HK>19jDUdKlF^jy63RuWKkB% +zBa@9Kj9e%)DHQP};rFg~OW}f;>~sPwxj~Hy=Ws?|f}pR{Qol7#LHD9o)$wm!QRITm +zG4?i*bV~{n)PEHmT%Hr|JZh9eVR8!_mxlgXaU7zccw52W-^GmY`x%+Ou +z8}CwslOG@nC2Og0@!Xm}&6X8%HMJZG`pZ +zk4n60Mte5MdoH8tuQC|PLp8loDL2AZ6HWb@6#16*Y$8y?43feAO_i(*`RSIzi~@Bh +zQ~sET2`kC~Vw}Cp>?n$VTUnK$>9S<9PHt9^9~H?-Ve>8*MZV$d{m}TKUsp+Rc5OsE2Yr4Z;CK +z+)KLfJLKU-==(?27D+f-Xo&3wu$U?VRIW9_tnanI&!HXQ-~R6f1Zt-(hHB{~1}=~K +z{x+%Ndz?O@IN@+=7FP(?B)$jfiyEA%A)4j5`D(8;Wydr`sgqt)8qd2h_{*Ozt +zR41w(W=VO82e)MAHje3K>3!NJbz&oT&jVM3eL6#St2o7R9j>SNyBC{3JERo)9p!eH`UEt +z_6`G^G^zn0q$u7pm|I`5BWZ)X$jyYm02KoaDbtZ#0_tAnPP^T2bKi$L(C}wWMhTz7 +zMlamvEV(rRdJ)?2Od2q*w&AW&UhiZ=5rbg)Bxul%%ZIgAc>idLRwr}~W3;e_15C7m +zG4gHHp~x%`go9Qu-@(>o%KBXPI@^ZqmaP`j;4u +z?Nr{(VqpThZ`%F_=2T6z^`fPd@%ZFKkWPiB9H8j9gMef1D=nJF-Gm1)s^ASdo=b~m +zmx_JqK<}}or#v#o`lK{F@d<1Q`13CW05u?nN*@C;#-7WDdpShpO4%4ND*VJfp#V3`i +zmXMm5)WQj^v3R^pcwqw-N)H`crcv46X&%Uqwssx~%Q+&_;uAHm8JB#%5hQv?cdX86 +z4%z@oEmOyYfISl7rWiw2U7nph=QT{n>CAN)c5YZp5P%V9Cu@d{Hf@;hP3PIqUnp2j +zPq-(zT0?lf0UI+=FN1@4^IU22h-S9Und(mmXhc+pjw1aAJjzam^P#4dBfHVXhJ^QB +zXY%e6=m>P*^s8zhh##1=VY0M0==Bjg@%~e}2W+_N0joTuTpC`=9qYLHGnk!=Ld^^U +z%EI;!MYuISMQ`e`L>~k~O-1}Hs*oj4-}OzFbL(Cs<^{&k5=b15LG}@*UnIiSj)O}y +zlYHl*WCPV2EHO~bV`WlPS&o3YUy(F +zoTm;&cz7G0UCF!tWqtlVMI5?YIb_=eS%U14}T|;cRZrF2y +z+;vd69iIl*fW!;v^e=EyF?{guJw}=^L19EU|JrAcYWSzi>ge_f!MhVA%p|kOFnKc- +zmAejY-F&-6{^njb^F@bFoV#WR^rTD6a{g&c-tD0lksmR);a3zIz9 +z70mQw+6>lLBjXmdUS4G>^G|vKeBrM +zjUhrE?|H>7uxa1dD9XIxFqBJLOh3C0^B6s?fD?!?__OUPJG-n$gJi`!BQh{lVF6{l +zsz<6@WioF7oMIA>o=qHraFgJNJ%^}a9f_STUN&0 +zje1-DEVHnn%~5oEB#TSba~0mxbZNg(l~8t*t`-gSx1gMgY{~fR(SvpgOiy{!wp$p@ +ziz?$I5^pImxb5`<>TUks%P?0cV~!u^`uUSTmQpLw7K|_q*{5H<0BMA?5kaXuI4us~Z&3ykL})3i-l$xRS-FkO=KtjNFKA_?OODX`82R*AAKT@$G2jY7 +zDXSsM$b!a|Iu|f+6}9Z)0D==CD%`8CTr3jom>p;qi<;j)kT@&UyuqX!TbhKrQf~}< +zq0HS$T)582Whmz%hb^;|(8I84W=B!Y4jflD!=i%Wm8e@5+y~>Inm~epA|3OO*XSbE +zE6YWN00UYA!~$$K#CI57GhqT}N085q74*@YpsaMP6F{P2{*Fcg^M5f=MfE+YaC$%Sq^+)L +zPd6&HIU21Cjn!dy_uA@YmBLtK7#vx<;3C +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 +zb|g|$D#P#@iJ7wlw~CSKVg5B+BdU7(P#sY& +z(nKb08w?XDOGoF{r0^`cMiG-JC~ePk%J74d1w=wulzu8k4zW4UKgQDt%>!R5rlhS5 +zceGnsK=pv>2$yzk>(tsbPCvbXEiV1(n~6Lt!N=#+`&n1unPkGRu* +z^a_~O*$Lt{y!eUu%go;Mje^QtqG=fS6R@3#%{+k}4-!RvJdZG^2{N_OJ?iWFO7*Bj +zQfx=h&|x}!XMj*1Of3e`kPh;WRz84`#52*X8& +zF#T=?P5SV`&9@hJyKXa4ZNwigwfLC*WnU9}q3KTj6+~rY&cT?n^^SfgMD*?Eb}!f_ +zRtozk_l{K}Kd3~d`*suk0q;aKnF>8Ysf5J(;aU$AFCTgTZPkQ{W>W3`XY!{hC|ihF +z684WA@4|FHl709S*3c*$E~_5cCCjt=eDv;qJC0M+JuvlJIQFarPp000D8 +ETDHEJ(EtDd + +literal 0 +HcmV?d00001 + +diff --git a/test-data/phony-guests/fedora-name.db.txt b/test-data/phony-guests/fedora-name.db.txt +deleted file mode 100644 +index 8456097e4..000000000 +--- a/test-data/phony-guests/fedora-name.db.txt ++++ /dev/null +@@ -1,13 +0,0 @@ +-VERSION=3 +-format=print +-type=hash +-h_nelem=3 +-db_pagesize=4096 +-HEADER=END +- test1 +- \01\00\00\00\00\00\00\00 +- test2 +- \02\00\00\00\00\00\00\00 +- test3 +- \03\00\00\00\00\00\00\00 +-DATA=END +diff --git a/test-data/phony-guests/fedora-packages.db.txt b/test-data/phony-guests/fedora-packages.db.txt +deleted file mode 100644 +index f16a5aa76..000000000 +--- a/test-data/phony-guests/fedora-packages.db.txt ++++ /dev/null +@@ -1,13 +0,0 @@ +-VERSION=3 +-format=print +-type=hash +-h_nelem=3 +-db_pagesize=4096 +-HEADER=END +- \01\00\00\00 +- \00\00\00\03\00\00\00\11\00\00\03\e9\00\00\00\00\00\00\00\00\00\00\00\00\00\00\03\ea\00\00\00\00\00\00\00\04\00\00\00\00\00\00\03\fe\00\00\00\00\00\00\00\0b\00\00\00\001.0\001.fc14\00x86_64\00 +- \02\00\00\00 +- \00\00\00\03\00\00\00\11\00\00\03\e9\00\00\00\00\00\00\00\00\00\00\00\00\00\00\03\ea\00\00\00\00\00\00\00\04\00\00\00\00\00\00\03\fe\00\00\00\00\00\00\00\0b\00\00\00\002.0\002.fc14\00x86_64\00 +- \03\00\00\00 +- \00\00\00\03\00\00\00\11\00\00\03\e9\00\00\00\00\00\00\00\00\00\00\00\00\00\00\03\ea\00\00\00\00\00\00\00\04\00\00\00\00\00\00\03\fe\00\00\00\00\00\00\00\0b\00\00\00\003.0\003.fc14\00x86_64\00 +-DATA=END +diff --git a/test-data/phony-guests/make-fedora-img.pl b/test-data/phony-guests/make-fedora-img.pl +index 28b9c1db0..90492b814 100755 +--- a/test-data/phony-guests/make-fedora-img.pl ++++ b/test-data/phony-guests/make-fedora-img.pl +@@ -246,6 +246,7 @@ $g->mkdir ('/usr/share/zoneinfo'); + $g->mkdir ('/usr/share/zoneinfo/Europe'); + $g->touch ('/usr/share/zoneinfo/Europe/London'); + $g->mkdir_p ('/var/lib/rpm'); ++$g->mkdir_p ('/usr/lib/rpm'); + $g->mkdir_p ('/var/log/journal'); + + $g->write ('/etc/shadow', "root::15440:0:99999:7:::\n"); +@@ -264,8 +265,12 @@ if (-f "fedora.mdadm") { + unlink ("fedora.mdadm") or die; + } + +-$g->upload ($ENV{SRCDIR}.'/fedora-name.db', '/var/lib/rpm/Name'); +-$g->upload ($ENV{SRCDIR}.'/fedora-packages.db', '/var/lib/rpm/Packages'); ++$g->upload ($ENV{SRCDIR}.'/fedora.db', '/var/lib/rpm/rpmdb.sqlite'); ++$g->touch ('/usr/lib/rpm/rpmrc'); ++$g->write ('/usr/lib/rpm/macros', <upload ($ENV{SRCDIR}.'/../binaries/bin-x86_64-dynamic', '/bin/ls'); + +-- +2.31.1 + diff --git a/SOURCES/0014-po-POTFILES-Fix-list-of-files-for-translation.patch b/SOURCES/0014-po-POTFILES-Fix-list-of-files-for-translation.patch new file mode 100644 index 0000000..2cc1fd6 --- /dev/null +++ b/SOURCES/0014-po-POTFILES-Fix-list-of-files-for-translation.patch @@ -0,0 +1,34 @@ +From 9664527c107d04aab416be87cc4fcd76dcbe5927 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 29 Mar 2021 18:25:13 +0100 +Subject: [PATCH] po/POTFILES: Fix list of files for translation. + +Fixes: commit c9ee831affed55abe0f928134cbbd2ed83b2f510 +(cherry picked from commit df983200d76bac37c811fbd2fb67e7ebe830e759) +--- + po/POTFILES | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/po/POTFILES b/po/POTFILES +index 0782e8ceb..fdc6e8062 100644 +--- a/po/POTFILES ++++ b/po/POTFILES +@@ -128,6 +128,7 @@ daemon/pingdaemon.c + daemon/proto.c + daemon/readdir.c + daemon/rename.c ++daemon/rpm-c.c + daemon/rsync.c + daemon/scrub.c + daemon/selinux-relabel.c +@@ -353,7 +354,6 @@ lib/command.c + lib/conn-socket.c + lib/copy-in-out.c + lib/create.c +-lib/dbdump.c + lib/drives.c + lib/errors.c + lib/event-string.c +-- +2.31.1 + diff --git a/SOURCES/0014-v2v-warn-when-the-guest-has-direct-network-interface.patch b/SOURCES/0014-v2v-warn-when-the-guest-has-direct-network-interface.patch deleted file mode 100644 index 14b277c..0000000 --- a/SOURCES/0014-v2v-warn-when-the-guest-has-direct-network-interface.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 573f551ff8ced48f4ea21ec7bbbad235092f36f2 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Fri, 12 Apr 2019 17:28:12 +0200 -Subject: [PATCH] v2v: warn when the guest has direct network interfaces - (RHBZ#1518539) - -virt-v2v obviously cannot convert this kind of devices, since they are -specific to the host of the hypervisor. Thus, emit a warning about the -presence of direct network interfaces, so at least this can be noticed -when converting a guest. - -(cherry picked from commit 1629ec6a5639cf5e226e80bcee749ae8851b1fae) ---- - v2v/parse_libvirt_xml.ml | 18 ++++++++++++++++++ - 1 file changed, 18 insertions(+) - -diff --git a/v2v/parse_libvirt_xml.ml b/v2v/parse_libvirt_xml.ml -index d5d78d367..b9970cee8 100644 ---- a/v2v/parse_libvirt_xml.ml -+++ b/v2v/parse_libvirt_xml.ml -@@ -492,6 +492,24 @@ let parse_libvirt_xml ?conn xml = - ) - in - -+ (* Check for direct attachments to physical network interfaces. -+ * (RHBZ#1518539) -+ *) -+ let () = -+ let obj = Xml.xpath_eval_expression xpathctx "/domain/devices/interface[@type='direct']" in -+ let nr_nodes = Xml.xpathobj_nr_nodes obj in -+ if nr_nodes > 0 then ( -+ (* Sadly fn_ in ocaml-gettext seems broken, and always returns the -+ * singular string no matter what. Work around this by using a simple -+ * string with sn_ (which works), and outputting it as a whole. -+ *) -+ let msg = sn_ "this guest has a direct network interface which will be ignored" -+ "this guest has direct network interfaces which will be ignored" -+ nr_nodes in -+ warning "%s" msg -+ ) -+ in -+ - ({ - s_hypervisor = hypervisor; - s_name = name; s_orig_name = name; --- -2.18.4 - diff --git a/SOURCES/0015-m4-guestfs-find-db-tool.m4-Remove-unused-file.patch b/SOURCES/0015-m4-guestfs-find-db-tool.m4-Remove-unused-file.patch new file mode 100644 index 0000000..e8c3050 --- /dev/null +++ b/SOURCES/0015-m4-guestfs-find-db-tool.m4-Remove-unused-file.patch @@ -0,0 +1,64 @@ +From 083856d9f9c8fccc629bf0f3a5237d26434c8940 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 29 Mar 2021 18:35:48 +0100 +Subject: [PATCH] m4/guestfs-find-db-tool.m4: Remove unused file. + +Fixes: commit 42e5e7cfdbca01b2e9bd50c63a9fc65b6da9192f +(cherry picked from commit 8317279c3539562ebad9de13c7ac515dded74e4d) +--- + m4/guestfs-find-db-tool.m4 | 43 -------------------------------------- + 1 file changed, 43 deletions(-) + delete mode 100644 m4/guestfs-find-db-tool.m4 + +diff --git a/m4/guestfs-find-db-tool.m4 b/m4/guestfs-find-db-tool.m4 +deleted file mode 100644 +index b404148c6..000000000 +--- a/m4/guestfs-find-db-tool.m4 ++++ /dev/null +@@ -1,43 +0,0 @@ +-# libguestfs +-# Copyright (C) 2014 Red Hat Inc. +-# +-# This program is free software; you can redistribute it and/or modify +-# it under the terms of the GNU General Public License as published by +-# the Free Software Foundation; either version 2 of the License, or +-# (at your option) any later version. +-# +-# This program is distributed in the hope that it will be useful, +-# but WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-# GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License +-# along with this program; if not, write to the Free Software +-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +- +-AC_DEFUN([GUESTFS_FIND_DB_TOOL],[ +- pushdef([VARIABLE],$1) +- TOOL=$2 +- +- db_tool_name="db_$TOOL" +- db_versions="53 5.3 5.2 5.1 4.8 4.7 4.6" +- db_tool_patterns="dbX_$TOOL dbX.Y_$TOOL" +- db_tool_patterns="dbX_$TOOL db_$TOOL-X dbX.Y_$TOOL db_$TOOL-X.Y" +- +- AC_ARG_VAR(VARIABLE, [Absolute path to $db_tool_name executable]) +- +- AS_IF(test -z "$VARIABLE", [ +- exe_list="db_$TOOL" +- for ver in $db_versions ; do +- ver_maj=`echo $ver | cut -d. -f1` +- ver_min=`echo $ver | cut -d. -f2` +- for pattern in $db_tool_patterns ; do +- exe=`echo "$pattern" | sed -e "s/X/$ver_maj/g;s/Y/$ver_min/g"` +- exe_list="$exe_list $exe" +- done +- done +- AC_PATH_PROGS([]VARIABLE[], [$exe_list], [no]) +- ]) +- +- popdef([VARIABLE]) +-]) +-- +2.31.1 + diff --git a/SOURCES/0015-v2v-update-documentation-on-nbdkit-RHBZ-1605242.patch b/SOURCES/0015-v2v-update-documentation-on-nbdkit-RHBZ-1605242.patch deleted file mode 100644 index 2becf46..0000000 --- a/SOURCES/0015-v2v-update-documentation-on-nbdkit-RHBZ-1605242.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 31ffb01b14ef809d4c5836e9244eb114e971c36e Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Fri, 12 Apr 2019 16:19:43 +0200 -Subject: [PATCH] v2v: update documentation on nbdkit (RHBZ#1605242) - -nbdkit >= 1.6 ships a VDDK plugin always built, so recommend that -version instead of recommending to build nbdkit from sources. - -(cherry picked from commit 0704d8eb0bcc8139886eb4291f75a3ca49a91e58) ---- - v2v/virt-v2v-input-vmware.pod | 28 ++-------------------------- - 1 file changed, 2 insertions(+), 26 deletions(-) - -diff --git a/v2v/virt-v2v-input-vmware.pod b/v2v/virt-v2v-input-vmware.pod -index 2b6dbaeec..b3ebda182 100644 ---- a/v2v/virt-v2v-input-vmware.pod -+++ b/v2v/virt-v2v-input-vmware.pod -@@ -197,32 +197,8 @@ library is permitted by the license. - - =item 2. - --You must also compile nbdkit, enabling the VDDK plugin. nbdkit E --1.1.25 is recommended, but it is usually best to compile from the git --tree. -- --=over 4 -- --=item * -- --L -- --=item * -- --L -- --=back -- --Compile nbdkit as described in the sources (see link above). -- --You do B need to run C because you can run nbdkit --from its source directory. The source directory has a shell script --called F which runs the locally built copy of nbdkit and its --plugins. So set C<$PATH> to point to the nbdkit top build directory --(that is, the directory containing the shell script called F), --eg: -- -- export PATH=/path/to/nbdkit-1.1.x:$PATH -+nbdkit E 1.6 is recommended, as it ships with the VDDK plugin -+enabled unconditionally. - - =item 3. - --- -2.18.4 - diff --git a/SOURCES/0016-test-data-phony-guests-Fix-phony-RPM-database-fix-vi.patch b/SOURCES/0016-test-data-phony-guests-Fix-phony-RPM-database-fix-vi.patch new file mode 100644 index 0000000..ca169bd --- /dev/null +++ b/SOURCES/0016-test-data-phony-guests-Fix-phony-RPM-database-fix-vi.patch @@ -0,0 +1,474 @@ +From f8ccce2c7a0c1323e0721f503322df525dd5b139 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 29 Mar 2021 12:22:12 +0100 +Subject: [PATCH] test-data/phony-guests: Fix phony RPM database, fix + virt-inspector test. + +libguestfs 1.45.3 now reads the RPM database using librpm, which means +our old phony database created by db_dump can no longer work. Instead +provide a real (but very minimal) sqlite database. + +This commit also fixes the virt-inspector test since the RPM database +contents are now different. + +(cherry picked from commit 46bf6fb473889ed28bd7220476120edcda47ae07) +--- + inspector/expected-fedora-luks.img.xml | 208 +++++++++++++++++++++++-- + inspector/expected-fedora.img.xml | 208 +++++++++++++++++++++++-- + 2 files changed, 398 insertions(+), 18 deletions(-) + +diff --git a/inspector/expected-fedora-luks.img.xml b/inspector/expected-fedora-luks.img.xml +index df6060a73..72cddaf88 100644 +--- a/inspector/expected-fedora-luks.img.xml ++++ b/inspector/expected-fedora-luks.img.xml +@@ -30,22 +30,212 @@ + + + +- test1 +- 1.0 +- 1.fc14 ++ basesystem ++ 11 ++ 10.fc33 ++ noarch ++ (none) ++

The skeleton package which defines a simple Fedora system ++ Basesystem defines the components of a basic Fedora system ++(for example, the package installation order to use during bootstrapping). ++Basesystem should be in every installation of a system, and it ++should never be removed. ++ ++ ++ bash ++ 5.0.17 ++ 2.fc33 ++ x86_64 ++ https://www.gnu.org/software/bash ++ The GNU Bourne Again shell ++ The GNU Bourne Again shell (Bash) is a shell or command language ++interpreter that is compatible with the Bourne shell (sh). Bash ++incorporates useful features from the Korn shell (ksh) and the C shell ++(csh). Most sh scripts can be run by bash without modification. ++ ++ ++ fedora-gpg-keys ++ 33 ++ 3 ++ noarch ++ https://fedoraproject.org/ ++ Fedora RPM keys ++ This package provides the RPM signature keys. ++ ++ ++ fedora-release ++ 33 ++ 3 ++ noarch ++ https://fedoraproject.org/ ++ Fedora release files ++ Fedora release files such as various /etc/ files that define the release ++and systemd preset files that determine which services are enabled by default. ++ ++ ++ fedora-release-common ++ 33 ++ 3 ++ noarch ++ https://fedoraproject.org/ ++ Fedora release files ++ Release files common to all Editions and Spins of Fedora ++ ++ ++ fedora-release-identity-basic ++ 33 ++ 3 ++ noarch ++ https://fedoraproject.org/ ++ Package providing the basic Fedora identity ++ Provides the necessary files for a Fedora installation that is not identifying ++itself as a particular Edition or Spin. ++ ++ ++ fedora-repos ++ 33 ++ 3 ++ noarch ++ https://fedoraproject.org/ ++ Fedora package repositories ++ Fedora package repository files for yum and dnf along with gpg public keys. ++ ++ ++ filesystem ++ 3.14 ++ 3.fc33 ++ x86_64 ++ https://pagure.io/filesystem ++ The basic directory layout for a Linux system ++ The filesystem package is one of the basic packages that is installed ++on a Linux system. Filesystem contains the basic directory layout ++for a Linux operating system, including the correct permissions for ++the directories. ++ ++ ++ glibc ++ 2.32 ++ 4.fc33 ++ x86_64 ++ http://www.gnu.org/software/glibc/ ++ The GNU libc libraries ++ The glibc package contains standard libraries which are used by ++multiple programs on the system. In order to save disk space and ++memory, as well as to make upgrading easier, common system code is ++kept in one place and shared between programs. This particular package ++contains the most important sets of shared libraries: the standard C ++library and the standard math library. Without these two libraries, a ++Linux system will not function. ++ ++ ++ glibc-all-langpacks ++ 2.32 ++ 4.fc33 ++ x86_64 ++ http://www.gnu.org/software/glibc/ ++ All language packs for glibc. ++ ++ ++ glibc-common ++ 2.32 ++ 4.fc33 + x86_64 ++ http://www.gnu.org/software/glibc/ ++ Common binaries and locale data for glibc ++ The glibc-common package includes common binaries for the GNU libc ++libraries, as well as national language (locale) support. + + +- test2 +- 2.0 +- 2.fc14 ++ gpg-pubkey ++ 9570ff31 ++ 5e3006fb ++ (none) ++ (none) ++ Fedora (33) <fedora-33-primary@fedoraproject.org> public key ++ -----BEGIN PGP PUBLIC KEY BLOCK----- ++Version: rpm-4.16.1.2 (NSS-3) ++ ++mQINBF4wBvsBEADQmcGbVUbDRUoXADReRmOOEMeydHghtKC9uRs9YNpGYZIB+bie ++bGYZmflQayfh/wEpO2W/IZfGpHPL42V7SbyvqMjwNls/fnXsCtf4LRofNK8Qd9fN ++kYargc9R7BEz/mwXKMiRQVx+DzkmqGWy2gq4iD0/mCyf5FdJCE40fOWoIGJXaOI1 ++Tz1vWqKwLS5T0dfmi9U4Tp/XsKOZGvN8oi5h0KmqFk7LEZr1MXarhi2Va86sgxsF ++QcZEKfu5tgD0r00vXzikoSjn3qA5JW5FW07F1pGP4bF5f9J3CZbQyOjTSWMmmfTm ++2d2BURWzaDiJN9twY2yjzkoOMuPdXXvovg7KxLcQerKT+FbKbq8DySJX2rnOA77k ++UG4c9BGf/L1uBkAT8dpHLk6Uf5BfmypxUkydSWT1xfTDnw1MqxO0MsLlAHOR3J7c ++oW9kLcOLuCQn1hBEwfZv7VSWBkGXSmKfp0LLIxAFgRtv+Dh+rcMMRdJgKr1V3FU+ ++rZ1+ZAfYiBpQJFPjv70vx+rGEgS801D3PJxBZUEy4Ic4ZYaKNhK9x9PRQuWcIBuW ++6eTe/6lKWZeyxCumLLdiS75mF2oTcBaWeoc3QxrPRV15eDKeYJMbhnUai/7lSrhs ++EWCkKR1RivgF4slYmtNE5ZPGZ/d61zjwn2xi4xNJVs8q9WRPMpHp0vCyMwARAQAB ++tDFGZWRvcmEgKDMzKSA8ZmVkb3JhLTMzLXByaW1hcnlAZmVkb3JhcHJvamVjdC5v ++cmc+iQI4BBMBAgAiBQJeMAb7AhsPBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAK ++CRBJ/XdJlXD/MZm2D/9kriL43vd3+0DNMeA82n2v9mSR2PQqKny39xNlYPyy/1yZ ++P/KXoa4NYSCA971LSd7lv4n/h5bEKgGHxZfttfOzOnWMVSSTfjRyM/df/NNzTUEV ++7ORA5GW18g8PEtS7uRxVBf3cLvWu5q+8jmqES5HqTAdGVcuIFQeBXFN8Gy1Jinuz ++AH8rJSdkUeZ0cehWbERq80BWM9dhad5dW+/+Gv0foFBvP15viwhWqajr8V0B8es+ ++2/tHI0k86FAujV5i0rrXl5UOoLilO57QQNDZH/qW9GsHwVI+2yecLstpUNLq+EZC ++GqTZCYoxYRpl0gAMbDLztSL/8Bc0tJrCRG3tavJotFYlgUK60XnXlQzRkh9rgsfT ++EXbQifWdQMMogzjCJr0hzJ+V1d0iozdUxB2ZEgTjukOvatkB77DY1FPZRkSFIQs+ ++fdcjazDIBLIxwJu5QwvTNW8lOLnJ46g4sf1WJoUdNTbR0BaC7HHj1inVWi0p7IuN ++66EPGzJOSjLK+vW+J0ncPDEgLCV74RF/0nR5fVTdrmiopPrzFuguHf9S9gYI3Zun ++Yl8FJUu4kRO6JPPTicUXWX+8XZmE94aK14RCJL23nOSi8T1eW8JLW43dCBRO8QUE ++Aso1t2pypm/1zZexJdOV8yGME3g5l2W6PLgpz58DBECgqc/kda+VWgEAp7rO2A== ++=EPL3 ++-----END PGP PUBLIC KEY BLOCK----- ++ ++ ++ ++ libgcc ++ 10.2.1 ++ 9.fc33 + x86_64 ++ http://gcc.gnu.org ++ GCC version 10 shared support library ++ This package contains GCC shared support library which is needed ++e.g. for exception handling support. ++ ++ ++ ncurses-base ++ 6.2 ++ 3.20200222.fc33 ++ noarch ++ https://invisible-island.net/ncurses/ncurses.html ++ Descriptions of common terminals ++ This package contains descriptions of common terminals. Other terminal ++descriptions are included in the ncurses-term package. + + +- test3 +- 3.0 +- 3.fc14 ++ ncurses-libs ++ 6.2 ++ 3.20200222.fc33 + x86_64 ++ https://invisible-island.net/ncurses/ncurses.html ++ Ncurses libraries ++ The curses library routines are a terminal-independent method of ++updating character screens with reasonable optimization. The ncurses ++(new curses) library is a freely distributable replacement for the ++discontinued 4.4 BSD classic curses library. ++ ++This package contains the ncurses libraries. ++ ++ ++ setup ++ 2.13.7 ++ 2.fc33 ++ noarch ++ https://pagure.io/setup/ ++ A set of system configuration and setup files ++ The setup package contains a set of important system configuration and ++setup files, such as passwd, group, and profile. ++ ++ ++ tzdata ++ 2021a ++ 1.fc33 ++ noarch ++ https://www.iana.org/time-zones ++ Timezone data ++ This package contains data files with rules for various timezones around ++the world. + + + +diff --git a/inspector/expected-fedora.img.xml b/inspector/expected-fedora.img.xml +index df6060a73..72cddaf88 100644 +--- a/inspector/expected-fedora.img.xml ++++ b/inspector/expected-fedora.img.xml +@@ -30,22 +30,212 @@ + + + +- test1 +- 1.0 +- 1.fc14 ++ basesystem ++ 11 ++ 10.fc33 ++ noarch ++ (none) ++ The skeleton package which defines a simple Fedora system ++ Basesystem defines the components of a basic Fedora system ++(for example, the package installation order to use during bootstrapping). ++Basesystem should be in every installation of a system, and it ++should never be removed. ++ ++ ++ bash ++ 5.0.17 ++ 2.fc33 ++ x86_64 ++ https://www.gnu.org/software/bash ++ The GNU Bourne Again shell ++ The GNU Bourne Again shell (Bash) is a shell or command language ++interpreter that is compatible with the Bourne shell (sh). Bash ++incorporates useful features from the Korn shell (ksh) and the C shell ++(csh). Most sh scripts can be run by bash without modification. ++ ++ ++ fedora-gpg-keys ++ 33 ++ 3 ++ noarch ++ https://fedoraproject.org/ ++ Fedora RPM keys ++ This package provides the RPM signature keys. ++ ++ ++ fedora-release ++ 33 ++ 3 ++ noarch ++ https://fedoraproject.org/ ++ Fedora release files ++ Fedora release files such as various /etc/ files that define the release ++and systemd preset files that determine which services are enabled by default. ++ ++ ++ fedora-release-common ++ 33 ++ 3 ++ noarch ++ https://fedoraproject.org/ ++ Fedora release files ++ Release files common to all Editions and Spins of Fedora ++ ++ ++ fedora-release-identity-basic ++ 33 ++ 3 ++ noarch ++ https://fedoraproject.org/ ++ Package providing the basic Fedora identity ++ Provides the necessary files for a Fedora installation that is not identifying ++itself as a particular Edition or Spin. ++ ++ ++ fedora-repos ++ 33 ++ 3 ++ noarch ++ https://fedoraproject.org/ ++ Fedora package repositories ++ Fedora package repository files for yum and dnf along with gpg public keys. ++ ++ ++ filesystem ++ 3.14 ++ 3.fc33 ++ x86_64 ++ https://pagure.io/filesystem ++ The basic directory layout for a Linux system ++ The filesystem package is one of the basic packages that is installed ++on a Linux system. Filesystem contains the basic directory layout ++for a Linux operating system, including the correct permissions for ++the directories. ++ ++ ++ glibc ++ 2.32 ++ 4.fc33 ++ x86_64 ++ http://www.gnu.org/software/glibc/ ++ The GNU libc libraries ++ The glibc package contains standard libraries which are used by ++multiple programs on the system. In order to save disk space and ++memory, as well as to make upgrading easier, common system code is ++kept in one place and shared between programs. This particular package ++contains the most important sets of shared libraries: the standard C ++library and the standard math library. Without these two libraries, a ++Linux system will not function. ++ ++ ++ glibc-all-langpacks ++ 2.32 ++ 4.fc33 ++ x86_64 ++ http://www.gnu.org/software/glibc/ ++ All language packs for glibc. ++ ++ ++ glibc-common ++ 2.32 ++ 4.fc33 + x86_64 ++ http://www.gnu.org/software/glibc/ ++ Common binaries and locale data for glibc ++ The glibc-common package includes common binaries for the GNU libc ++libraries, as well as national language (locale) support. + + +- test2 +- 2.0 +- 2.fc14 ++ gpg-pubkey ++ 9570ff31 ++ 5e3006fb ++ (none) ++ (none) ++ Fedora (33) <fedora-33-primary@fedoraproject.org> public key ++ -----BEGIN PGP PUBLIC KEY BLOCK----- ++Version: rpm-4.16.1.2 (NSS-3) ++ ++mQINBF4wBvsBEADQmcGbVUbDRUoXADReRmOOEMeydHghtKC9uRs9YNpGYZIB+bie ++bGYZmflQayfh/wEpO2W/IZfGpHPL42V7SbyvqMjwNls/fnXsCtf4LRofNK8Qd9fN ++kYargc9R7BEz/mwXKMiRQVx+DzkmqGWy2gq4iD0/mCyf5FdJCE40fOWoIGJXaOI1 ++Tz1vWqKwLS5T0dfmi9U4Tp/XsKOZGvN8oi5h0KmqFk7LEZr1MXarhi2Va86sgxsF ++QcZEKfu5tgD0r00vXzikoSjn3qA5JW5FW07F1pGP4bF5f9J3CZbQyOjTSWMmmfTm ++2d2BURWzaDiJN9twY2yjzkoOMuPdXXvovg7KxLcQerKT+FbKbq8DySJX2rnOA77k ++UG4c9BGf/L1uBkAT8dpHLk6Uf5BfmypxUkydSWT1xfTDnw1MqxO0MsLlAHOR3J7c ++oW9kLcOLuCQn1hBEwfZv7VSWBkGXSmKfp0LLIxAFgRtv+Dh+rcMMRdJgKr1V3FU+ ++rZ1+ZAfYiBpQJFPjv70vx+rGEgS801D3PJxBZUEy4Ic4ZYaKNhK9x9PRQuWcIBuW ++6eTe/6lKWZeyxCumLLdiS75mF2oTcBaWeoc3QxrPRV15eDKeYJMbhnUai/7lSrhs ++EWCkKR1RivgF4slYmtNE5ZPGZ/d61zjwn2xi4xNJVs8q9WRPMpHp0vCyMwARAQAB ++tDFGZWRvcmEgKDMzKSA8ZmVkb3JhLTMzLXByaW1hcnlAZmVkb3JhcHJvamVjdC5v ++cmc+iQI4BBMBAgAiBQJeMAb7AhsPBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAK ++CRBJ/XdJlXD/MZm2D/9kriL43vd3+0DNMeA82n2v9mSR2PQqKny39xNlYPyy/1yZ ++P/KXoa4NYSCA971LSd7lv4n/h5bEKgGHxZfttfOzOnWMVSSTfjRyM/df/NNzTUEV ++7ORA5GW18g8PEtS7uRxVBf3cLvWu5q+8jmqES5HqTAdGVcuIFQeBXFN8Gy1Jinuz ++AH8rJSdkUeZ0cehWbERq80BWM9dhad5dW+/+Gv0foFBvP15viwhWqajr8V0B8es+ ++2/tHI0k86FAujV5i0rrXl5UOoLilO57QQNDZH/qW9GsHwVI+2yecLstpUNLq+EZC ++GqTZCYoxYRpl0gAMbDLztSL/8Bc0tJrCRG3tavJotFYlgUK60XnXlQzRkh9rgsfT ++EXbQifWdQMMogzjCJr0hzJ+V1d0iozdUxB2ZEgTjukOvatkB77DY1FPZRkSFIQs+ ++fdcjazDIBLIxwJu5QwvTNW8lOLnJ46g4sf1WJoUdNTbR0BaC7HHj1inVWi0p7IuN ++66EPGzJOSjLK+vW+J0ncPDEgLCV74RF/0nR5fVTdrmiopPrzFuguHf9S9gYI3Zun ++Yl8FJUu4kRO6JPPTicUXWX+8XZmE94aK14RCJL23nOSi8T1eW8JLW43dCBRO8QUE ++Aso1t2pypm/1zZexJdOV8yGME3g5l2W6PLgpz58DBECgqc/kda+VWgEAp7rO2A== ++=EPL3 ++-----END PGP PUBLIC KEY BLOCK----- ++ ++ ++ ++ libgcc ++ 10.2.1 ++ 9.fc33 + x86_64 ++ http://gcc.gnu.org ++ GCC version 10 shared support library ++ This package contains GCC shared support library which is needed ++e.g. for exception handling support. ++ ++ ++ ncurses-base ++ 6.2 ++ 3.20200222.fc33 ++ noarch ++ https://invisible-island.net/ncurses/ncurses.html ++ Descriptions of common terminals ++ This package contains descriptions of common terminals. Other terminal ++descriptions are included in the ncurses-term package. + + +- test3 +- 3.0 +- 3.fc14 ++ ncurses-libs ++ 6.2 ++ 3.20200222.fc33 + x86_64 ++ https://invisible-island.net/ncurses/ncurses.html ++ Ncurses libraries ++ The curses library routines are a terminal-independent method of ++updating character screens with reasonable optimization. The ncurses ++(new curses) library is a freely distributable replacement for the ++discontinued 4.4 BSD classic curses library. ++ ++This package contains the ncurses libraries. ++ ++ ++ setup ++ 2.13.7 ++ 2.fc33 ++ noarch ++ https://pagure.io/setup/ ++ A set of system configuration and setup files ++ The setup package contains a set of important system configuration and ++setup files, such as passwd, group, and profile. ++ ++ ++ tzdata ++ 2021a ++ 1.fc33 ++ noarch ++ https://www.iana.org/time-zones ++ Timezone data ++ This package contains data files with rules for various timezones around ++the world. + + + +-- +2.31.1 + diff --git a/SOURCES/0016-v2v-linux-do-not-uninstall-open-vm-tools-w-ubuntu-se.patch b/SOURCES/0016-v2v-linux-do-not-uninstall-open-vm-tools-w-ubuntu-se.patch deleted file mode 100644 index 94b6803..0000000 --- a/SOURCES/0016-v2v-linux-do-not-uninstall-open-vm-tools-w-ubuntu-se.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 9857aa4f951dd289b54e5693946b3f7adbe5c98b Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Wed, 27 Feb 2019 17:51:59 +0100 -Subject: [PATCH] v2v: linux: do not uninstall open-vm-tools w/ ubuntu-server - -ubuntu-server depends on open-vm-tools on Ubuntu, so if v2v tries to -uninstall open-vm-tools then dpkg will (rightfully) fail with a -dependency issue. - -Since open-vm-tools is harmless after the conversion anyway (it will -not even run), then do not attempt to uninstall it if ubuntu-server is -installed too. - -Followup of commit 2bebacf8bf611f0f80a66915f78653ce30b38129. - -Thanks to: Ming Xie. - -(cherry picked from commit 1a4fd822ef057764f809cddce642b3223756629e) ---- - v2v/convert_linux.ml | 14 +++++++++++++- - 1 file changed, 13 insertions(+), 1 deletion(-) - -diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml -index 3d61400b5..b4b2f24c4 100644 ---- a/v2v/convert_linux.ml -+++ b/v2v/convert_linux.ml -@@ -289,6 +289,18 @@ let convert (g : G.guestfs) inspect source output rcaps = - - (* Uninstall VMware Tools. *) - let remove = ref [] and libraries = ref [] in -+ (* On Ubuntu, the ubuntu-server metapackage depends on -+ * open-vm-tools, and thus any attempt to remove it will cause -+ * dependency issues. Hence, special case this situation, and -+ * leave open-vm-tools installed in this case. -+ *) -+ let has_ubuntu_server = -+ if family = `Debian_family then -+ List.exists ( -+ fun { G.app2_name = name } -> -+ name = "ubuntu-server" -+ ) inspect.i_apps -+ else false in - List.iter ( - fun { G.app2_name = name } -> - if String.is_prefix name "vmware-tools-libraries-" then -@@ -301,7 +313,7 @@ let convert (g : G.guestfs) inspect source output rcaps = - List.push_front name remove - else if String.is_prefix name "open-vm-tools-" then - List.push_front name remove -- else if name = "open-vm-tools" then -+ else if name = "open-vm-tools" && not has_ubuntu_server then - List.push_front name remove - ) inspect.i_apps; - let libraries = !libraries in --- -2.18.4 - diff --git a/SOURCES/0017-launch-libvirt-place-our-virtio-net-pci-device-in-sl.patch b/SOURCES/0017-launch-libvirt-place-our-virtio-net-pci-device-in-sl.patch new file mode 100644 index 0000000..ccedd9b --- /dev/null +++ b/SOURCES/0017-launch-libvirt-place-our-virtio-net-pci-device-in-sl.patch @@ -0,0 +1,65 @@ +From 6657d0c1018ab44ae680376463ac3f0421548fb4 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Thu, 23 Dec 2021 11:36:59 +0100 +Subject: [PATCH] launch-libvirt: place our virtio-net-pci device in slot 0x1e + +The trick we use for adding our virtio-net-pci device +in the libvirt backend can conflict with libvirtd's and QEMU's PCI address +assignment. Try to mitigate that by placing our device in slot 0x1e on the +root bus. In practice this could only conflict with a "dmi-to-pci-bridge" +device model, which libvirtd itself places in slot 0x1e. However, given +the XMLs we generate, and modern QEMU versions, libvirtd has no reason to +auto-add "dmi-to-pci-bridge". Refer to +. + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2034160 +Signed-off-by: Laszlo Ersek +Message-Id: <20211223103701.12702-2-lersek@redhat.com> +Reviewed-by: Richard W.M. Jones +Tested-by: Richard W.M. Jones +(cherry picked from commit 5ce5ef6a97a58c5e906083ad4e944545712b3f3f) +--- + lib/guestfs-internal.h | 11 +++++++++++ + lib/launch-libvirt.c | 4 +++- + 2 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/lib/guestfs-internal.h b/lib/guestfs-internal.h +index 4799ee0a1..0b46f0070 100644 +--- a/lib/guestfs-internal.h ++++ b/lib/guestfs-internal.h +@@ -147,6 +147,17 @@ + #define VIRTIO_DEVICE_NAME(type) type "-pci" + #endif + ++/* Place the virtio-net controller in slot 0x1e on the root bus, on normal ++ * hardware with PCI. Refer to RHBZ#2034160. ++ */ ++#ifdef HAVE_LIBVIRT_BACKEND ++#if defined(__arm__) || defined(__s390x__) ++#define VIRTIO_NET_PCI_ADDR "" ++#else ++#define VIRTIO_NET_PCI_ADDR ",addr=1e.0" ++#endif ++#endif ++ + /* Guestfs handle and associated structures. */ + + /* State. */ +diff --git a/lib/launch-libvirt.c b/lib/launch-libvirt.c +index 026dc6b26..5842319df 100644 +--- a/lib/launch-libvirt.c ++++ b/lib/launch-libvirt.c +@@ -1834,7 +1834,9 @@ construct_libvirt_xml_qemu_cmdline (guestfs_h *g, + } end_element (); + + start_element ("qemu:arg") { +- attribute ("value", VIRTIO_DEVICE_NAME ("virtio-net") ",netdev=usernet"); ++ attribute ("value", (VIRTIO_DEVICE_NAME ("virtio-net") ++ ",netdev=usernet" ++ VIRTIO_NET_PCI_ADDR)); + } end_element (); + } + +-- +2.31.1 + diff --git a/SOURCES/0017-v2v-linux-canonicalize-module-path-for-arch-detectio.patch b/SOURCES/0017-v2v-linux-canonicalize-module-path-for-arch-detectio.patch deleted file mode 100644 index c856771..0000000 --- a/SOURCES/0017-v2v-linux-canonicalize-module-path-for-arch-detectio.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 999180eca864baf0a82267448de120d2ed0e4787 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Wed, 20 Mar 2019 16:55:05 +0100 -Subject: [PATCH] v2v: linux: canonicalize module path for arch detection - (RHBZ#1690574) - -Kernel modules can be also symlinks to files available outside the -"canonical" module directory; the "file" API, used by the -"file-architecture" API, return the actual type of a file (so symlinks, -block devices, etc), and thus "file-architecture" fails on symlinks. - -To prevent this situation, canonicalize the path of the module picked -for architecture detection: this way, "file-architecture" will act on a -real file. - -(cherry picked from commit 0a093035d485b3c2e66d56541ebe159f1b632ba6) ---- - v2v/linux_kernels.ml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/v2v/linux_kernels.ml b/v2v/linux_kernels.ml -index 3313aabc7..889ec2f2a 100644 ---- a/v2v/linux_kernels.ml -+++ b/v2v/linux_kernels.ml -@@ -189,7 +189,7 @@ let detect_kernels (g : G.guestfs) inspect family bootloader = - *) - let arch = - let any_module = modpath ^ List.hd modules in -- g#file_architecture any_module in -+ g#file_architecture (g#realpath any_module) in - - (* Just return the module names, without path or extension. *) - let modules = List.filter_map ( --- -2.18.4 - diff --git a/SOURCES/0018-lib-extract-NETWORK_ADDRESS-and-NETWORK_PREFIX-as-ma.patch b/SOURCES/0018-lib-extract-NETWORK_ADDRESS-and-NETWORK_PREFIX-as-ma.patch new file mode 100644 index 0000000..389df1d --- /dev/null +++ b/SOURCES/0018-lib-extract-NETWORK_ADDRESS-and-NETWORK_PREFIX-as-ma.patch @@ -0,0 +1,70 @@ +From 4b9eac11db3e2cc9ace397ed4c804356a7d9adbf Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Thu, 23 Dec 2021 11:37:00 +0100 +Subject: [PATCH] lib: extract NETWORK_ADDRESS and NETWORK_PREFIX as macros + +The 169.254.0.0/16 network specification (for the appliance) is currently +duplicated between the direct backend and the libvirt backend. In a +subsequent patch, we're going to need the network specification in yet +another spot; extract it now to the NETWORK_ADDRESS and NETWORK_PREFIX +macros (simply as strings). + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2034160 +Signed-off-by: Laszlo Ersek +Message-Id: <20211223103701.12702-3-lersek@redhat.com> +Reviewed-by: Richard W.M. Jones +Tested-by: Richard W.M. Jones +(cherry picked from commit 216de164e091a5c36403f24901698044a43ae0d9) +--- + lib/guestfs-internal.h | 6 ++++++ + lib/launch-direct.c | 2 +- + lib/launch-libvirt.c | 3 ++- + 3 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/lib/guestfs-internal.h b/lib/guestfs-internal.h +index 0b46f0070..97a13ff2c 100644 +--- a/lib/guestfs-internal.h ++++ b/lib/guestfs-internal.h +@@ -158,6 +158,12 @@ + #endif + #endif + ++/* Network address and network mask (expressed as address prefix) that the ++ * appliance will see (if networking is enabled). ++ */ ++#define NETWORK_ADDRESS "169.254.0.0" ++#define NETWORK_PREFIX "16" ++ + /* Guestfs handle and associated structures. */ + + /* State. */ +diff --git a/lib/launch-direct.c b/lib/launch-direct.c +index b6ed9766f..de17d2167 100644 +--- a/lib/launch-direct.c ++++ b/lib/launch-direct.c +@@ -681,7 +681,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg) + start_list ("-netdev") { + append_list ("user"); + append_list ("id=usernet"); +- append_list ("net=169.254.0.0/16"); ++ append_list ("net=" NETWORK_ADDRESS "/" NETWORK_PREFIX); + } end_list (); + start_list ("-device") { + append_list (VIRTIO_DEVICE_NAME ("virtio-net")); +diff --git a/lib/launch-libvirt.c b/lib/launch-libvirt.c +index 5842319df..0f38f0aec 100644 +--- a/lib/launch-libvirt.c ++++ b/lib/launch-libvirt.c +@@ -1826,7 +1826,8 @@ construct_libvirt_xml_qemu_cmdline (guestfs_h *g, + } end_element (); + + start_element ("qemu:arg") { +- attribute ("value", "user,id=usernet,net=169.254.0.0/16"); ++ attribute ("value", ++ "user,id=usernet,net=" NETWORK_ADDRESS "/" NETWORK_PREFIX); + } end_element (); + + start_element ("qemu:arg") { +-- +2.31.1 + diff --git a/SOURCES/0018-v2v-linux-improve-arch-detection-from-modules-RHBZ-1.patch b/SOURCES/0018-v2v-linux-improve-arch-detection-from-modules-RHBZ-1.patch deleted file mode 100644 index e1e1c66..0000000 --- a/SOURCES/0018-v2v-linux-improve-arch-detection-from-modules-RHBZ-1.patch +++ /dev/null @@ -1,61 +0,0 @@ -From de9ebcaf0784c464a3ca3b2686935ce2bddcc281 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Wed, 20 Mar 2019 12:32:02 +0100 -Subject: [PATCH] v2v: linux: improve arch detection from modules - (RHBZ#1690574) - -Try to look for a well known kernel module (so far only virtio, or kvm) -to use for detecting the architecture of a kernel. This way, we can -avoid picking 3rd party modules that cause troubles. - -(cherry picked from commit 363b5e0b4ecebe861a9aafe8bce5a8390b54571c) ---- - v2v/linux_kernels.ml | 30 +++++++++++++++++++++++++++--- - 1 file changed, 27 insertions(+), 3 deletions(-) - -diff --git a/v2v/linux_kernels.ml b/v2v/linux_kernels.ml -index 889ec2f2a..30160f0da 100644 ---- a/v2v/linux_kernels.ml -+++ b/v2v/linux_kernels.ml -@@ -185,11 +185,35 @@ let detect_kernels (g : G.guestfs) inspect family bootloader = - assert (List.length modules > 0); - - (* Determine the kernel architecture by looking at the -- * architecture of an arbitrary kernel module. -+ * architecture of a kernel module. -+ * -+ * To avoid architecture detection issues with 3rd party -+ * modules (RHBZ#1690574), try to pick one of the well -+ * known modules, if available. Otherwise, an arbitrary -+ * module is used. - *) - let arch = -- let any_module = modpath ^ List.hd modules in -- g#file_architecture (g#realpath any_module) in -+ (* Well known kernel modules. *) -+ let candidates = [ "virtio"; "kvm" ] in -+ let all_candidates = List.flatten ( -+ List.map ( -+ fun f -> -+ [ "/" ^ f ^ ".o"; "/" ^ f ^ ".ko"; "/" ^ f ^ ".ko.xz" ] -+ ) candidates -+ ) in -+ let candidate = -+ try -+ List.find ( -+ fun m -> -+ List.exists (String.is_suffix m) all_candidates -+ ) modules -+ with Not_found -> -+ (* No known module found, pick an arbitrary one -+ * (the first). -+ *) -+ List.hd modules in -+ let candidate = modpath ^ candidate in -+ g#file_architecture (g#realpath candidate) in - - (* Just return the module names, without path or extension. *) - let modules = List.filter_map ( --- -2.18.4 - diff --git a/SOURCES/0019-Use-proper-label-for-nbdkit-sockets.patch b/SOURCES/0019-Use-proper-label-for-nbdkit-sockets.patch deleted file mode 100644 index 9ba82b9..0000000 --- a/SOURCES/0019-Use-proper-label-for-nbdkit-sockets.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 19c52dffc48af65eb07e6e1f8a85fc093ede9eb2 Mon Sep 17 00:00:00 2001 -From: Martin Kletzander -Date: Mon, 27 May 2019 13:30:05 +0200 -Subject: [PATCH] Use proper label for nbdkit sockets - -While svirt_t can be used for sockets it does not always guarantee that it will -be accessible from a virtual machine. The VM might be running under svirt_tcg_t -context which will need a svirt_tcg_t label on the socket in order to access it. - -There is, however, another label, svirt_socket_t, which is accessible from -virt_domain: - - # sesearch -A -s svirt_t -c unix_stream_socket -p connectto - ... - allow virt_domain svirt_socket_t:unix_stream_socket { ... connectto ... }; - ... - -And virt_domain is a type attribute of both svirt_t and svirt_tcg_t: - - # seinfo -x -a virt_domain - Type Attributes: 1 - attribute virt_domain; - svirt_t - svirt_tcg_t - -Resolves: https://bugzilla.redhat.com/1698437 - -Signed-off-by: Martin Kletzander -(cherry picked from commit c2918b8b74506523a723b804d452816a059c5e50) ---- - v2v/input_libvirt_vddk.ml | 2 +- - v2v/output_rhv_upload.ml | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml -index 97c7cb532..567233d58 100644 ---- a/v2v/input_libvirt_vddk.ml -+++ b/v2v/input_libvirt_vddk.ml -@@ -290,7 +290,7 @@ object - add_arg "--newstyle"; (* use newstyle NBD protocol *) - add_arg "--exportname"; add_arg "/"; - if have_selinux then ( (* label the socket so qemu can open it *) -- add_arg "--selinux-label"; add_arg "system_u:object_r:svirt_t:s0" -+ add_arg "--selinux-label"; add_arg "system_u:object_r:svirt_socket_t:s0" - ); - - (* Name of the plugin. Everything following is a plugin parameter. *) -diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml -index 77c39107e..c2a5c72c7 100644 ---- a/v2v/output_rhv_upload.ml -+++ b/v2v/output_rhv_upload.ml -@@ -217,7 +217,7 @@ See also the virt-v2v-output-rhv(1) manual.") - let args = - (* label the socket so qemu can open it *) - if have_selinux then -- args @ ["--selinux-label"; "system_u:object_r:svirt_t:s0"] -+ args @ ["--selinux-label"; "system_u:object_r:svirt_socket_t:s0"] - else args in - args in - --- -2.18.4 - diff --git a/SOURCES/0019-launch-libvirt-add-virtio-net-via-the-standard-inter.patch b/SOURCES/0019-launch-libvirt-add-virtio-net-via-the-standard-inter.patch new file mode 100644 index 0000000..fd48ba9 --- /dev/null +++ b/SOURCES/0019-launch-libvirt-add-virtio-net-via-the-standard-inter.patch @@ -0,0 +1,91 @@ +From 8570de6e766297e4c9feab1c54ae05037f33edeb Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Thu, 23 Dec 2021 11:37:01 +0100 +Subject: [PATCH] launch-libvirt: add virtio-net via the standard + element + +Starting with version 3.8.0, libvirt allows us to specify the network +address and network mask (as prefix) for SLIRP directly via the + element in the domain XML: +. This means +we don't need the hack for virtio-net on such versions. + +Restrict the hack in construct_libvirt_xml_qemu_cmdline() to +libvirt<3.8.0, and generate the proper element in +construct_libvirt_xml_devices() on libvirt>=3.8.0. + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2034160 +Suggested-by: Richard W.M. Jones +Signed-off-by: Laszlo Ersek +Message-Id: <20211223103701.12702-4-lersek@redhat.com> +Reviewed-by: Richard W.M. Jones +Tested-by: Richard W.M. Jones +(cherry picked from commit 5858c2cf6c24b3776e3867eafd9d86a1f4912d9c) +--- + lib/guestfs-internal.h | 3 ++- + lib/launch-libvirt.c | 27 +++++++++++++++++++++++++-- + 2 files changed, 27 insertions(+), 3 deletions(-) + +diff --git a/lib/guestfs-internal.h b/lib/guestfs-internal.h +index 97a13ff2c..b11c945e9 100644 +--- a/lib/guestfs-internal.h ++++ b/lib/guestfs-internal.h +@@ -148,7 +148,8 @@ + #endif + + /* Place the virtio-net controller in slot 0x1e on the root bus, on normal +- * hardware with PCI. Refer to RHBZ#2034160. ++ * hardware with PCI. Necessary only before libvirt 3.8.0. Refer to ++ * RHBZ#2034160. + */ + #ifdef HAVE_LIBVIRT_BACKEND + #if defined(__arm__) || defined(__s390x__) +diff --git a/lib/launch-libvirt.c b/lib/launch-libvirt.c +index 0f38f0aec..f6bb39d99 100644 +--- a/lib/launch-libvirt.c ++++ b/lib/launch-libvirt.c +@@ -1396,6 +1396,28 @@ construct_libvirt_xml_devices (guestfs_h *g, + } end_element (); + } end_element (); + ++ /* Virtio-net NIC with SLIRP (= userspace) back-end, if networking is ++ * enabled. Starting with libvirt 3.8.0, we can specify the network address ++ * and prefix for SLIRP in the domain XML. Therefore, we can add the NIC ++ * via the standard element rather than , and ++ * so libvirt can manage the PCI address of the virtio-net NIC like the PCI ++ * addresses of all other devices. Refer to RHBZ#2034160. ++ */ ++ if (g->enable_network && ++ guestfs_int_version_ge (¶ms->data->libvirt_version, 3, 8, 0)) { ++ start_element ("interface") { ++ attribute ("type", "user"); ++ start_element ("model") { ++ attribute ("type", "virtio"); ++ } end_element (); ++ start_element ("ip") { ++ attribute ("family", "ipv4"); ++ attribute ("address", NETWORK_ADDRESS); ++ attribute ("prefix", NETWORK_PREFIX); ++ } end_element (); ++ } end_element (); ++ } ++ + /* Libvirt adds some devices by default. Indicate to libvirt + * that we don't want them. + */ +@@ -1818,9 +1840,10 @@ construct_libvirt_xml_qemu_cmdline (guestfs_h *g, + } end_element (); + + /* Workaround because libvirt user networking cannot specify "net=" +- * parameter. ++ * parameter. Necessary only before libvirt 3.8.0; refer to RHBZ#2034160. + */ +- if (g->enable_network) { ++ if (g->enable_network && ++ !guestfs_int_version_ge (¶ms->data->libvirt_version, 3, 8, 0)) { + start_element ("qemu:arg") { + attribute ("value", "-netdev"); + } end_element (); +-- +2.31.1 + diff --git a/SOURCES/0020-v2v-start-reading-the-new-libvirt-firmware-autoselec.patch b/SOURCES/0020-v2v-start-reading-the-new-libvirt-firmware-autoselec.patch deleted file mode 100644 index 76ba3cf..0000000 --- a/SOURCES/0020-v2v-start-reading-the-new-libvirt-firmware-autoselec.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 3fe15743f316f1576115e30ebd0a512b3667e2f1 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Mon, 8 Apr 2019 18:23:27 +0200 -Subject: [PATCH] v2v: start reading the new libvirt firmware autoselect - -Starting with 5.2.0, libvirt has a way to select automatically the -firmware for a guest using an attribute of the tag. Hence, use -this information (when available, of course) to flag the firmware used -by the guest. - -(cherry picked from commit fb7983f999004c1f8100776819ea65b21990956d) ---- - v2v/parse_libvirt_xml.ml | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/v2v/parse_libvirt_xml.ml b/v2v/parse_libvirt_xml.ml -index b9970cee8..14cd82afd 100644 ---- a/v2v/parse_libvirt_xml.ml -+++ b/v2v/parse_libvirt_xml.ml -@@ -476,6 +476,13 @@ let parse_libvirt_xml ?conn xml = - done; - List.rev !nics in - -+ (* Firmware. *) -+ let firmware = -+ match xpath_string "/domain/os/@firmware" with -+ | Some "bios" -> BIOS -+ | Some "efi" -> UEFI -+ | None | Some _ -> UnknownFirmware in -+ - (* Check for hostdev devices. (RHBZ#1472719) *) - let () = - let obj = Xml.xpath_eval_expression xpathctx "/domain/devices/hostdev" in -@@ -520,7 +527,7 @@ let parse_libvirt_xml ?conn xml = - s_cpu_model = cpu_model; - s_cpu_topology = cpu_topology; - s_features = features; -- s_firmware = UnknownFirmware; (* XXX until RHBZ#1217444 is fixed *) -+ s_firmware = firmware; - s_display = display; - s_video = video; - s_sound = sound; --- -2.18.4 - diff --git a/SOURCES/0021-common-mltools-move-the-code-for-machine-readable-up.patch b/SOURCES/0021-common-mltools-move-the-code-for-machine-readable-up.patch deleted file mode 100644 index 5a539bd..0000000 --- a/SOURCES/0021-common-mltools-move-the-code-for-machine-readable-up.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 7ac3289d64b37348f29de9db4d71c3286836066b Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Thu, 21 Mar 2019 17:16:37 +0100 -Subject: [PATCH] common/mltools: move the code for machine readable up - -Move the code for handling machine readable up in the file, so it can be -used by other functions. - -Only code motion, no behaviour changes. - -(cherry picked from commit 8b06ea0ebc9534e4fda9cc9a33c98f939401af79) ---- - common/mltools/tools_utils.ml | 60 +++++++++++++++++------------------ - 1 file changed, 30 insertions(+), 30 deletions(-) - -diff --git a/common/mltools/tools_utils.ml b/common/mltools/tools_utils.ml -index 24641369e..5a35708cd 100644 ---- a/common/mltools/tools_utils.ml -+++ b/common/mltools/tools_utils.ml -@@ -33,6 +33,36 @@ external c_inspect_decrypt : Guestfs.t -> int64 -> (string * key_store_key) list - external c_set_echo_keys : unit -> unit = "guestfs_int_mllib_set_echo_keys" "noalloc" - external c_set_keys_from_stdin : unit -> unit = "guestfs_int_mllib_set_keys_from_stdin" "noalloc" - -+type machine_readable_fn = { -+ pr : 'a. ('a, unit, string, unit) format4 -> 'a; -+} (* [@@unboxed] *) -+ -+type machine_readable_output_type = -+ | NoOutput -+ | Channel of out_channel -+ | File of string -+let machine_readable_output = ref NoOutput -+let machine_readable_channel = ref None -+let machine_readable () = -+ let chan = -+ if !machine_readable_channel = None then ( -+ let chan = -+ match !machine_readable_output with -+ | NoOutput -> None -+ | Channel chan -> Some chan -+ | File f -> Some (open_out f) in -+ machine_readable_channel := chan -+ ); -+ !machine_readable_channel -+ in -+ match chan with -+ | None -> None -+ | Some chan -> -+ let pr fs = -+ ksprintf (output_string chan) fs -+ in -+ Some { pr } -+ - (* ANSI terminal colours. *) - let istty chan = - Unix.isatty (Unix.descr_of_out_channel chan) -@@ -236,36 +266,6 @@ let human_size i = - ) - ) - --type machine_readable_fn = { -- pr : 'a. ('a, unit, string, unit) format4 -> 'a; --} (* [@@unboxed] *) -- --type machine_readable_output_type = -- | NoOutput -- | Channel of out_channel -- | File of string --let machine_readable_output = ref NoOutput --let machine_readable_channel = ref None --let machine_readable () = -- let chan = -- if !machine_readable_channel = None then ( -- let chan = -- match !machine_readable_output with -- | NoOutput -> None -- | Channel chan -> Some chan -- | File f -> Some (open_out f) in -- machine_readable_channel := chan -- ); -- !machine_readable_channel -- in -- match chan with -- | None -> None -- | Some chan -> -- let pr fs = -- ksprintf (output_string chan) fs -- in -- Some { pr } -- - type cmdline_options = { - getopt : Getopt.t; - ks : key_store; --- -2.18.4 - diff --git a/SOURCES/0022-common-mltools-make-sure-machine-readable-output-is-.patch b/SOURCES/0022-common-mltools-make-sure-machine-readable-output-is-.patch deleted file mode 100644 index afbc879..0000000 --- a/SOURCES/0022-common-mltools-make-sure-machine-readable-output-is-.patch +++ /dev/null @@ -1,34 +0,0 @@ -From d60ef2eca9c0e51944a9c17806d6936af45907f5 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Fri, 22 Mar 2019 11:36:41 +0100 -Subject: [PATCH] common/mltools: make sure machine readable output is flushed - -Enhance the helper printf function for machine readable output to always -flush after each string: this way, readers of the machine readable -stream can get the output as soon as it is outputted. - -(cherry picked from commit abf1607f46ddc3d829a3688b9499a9bcd2319d19) ---- - common/mltools/tools_utils.ml | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/common/mltools/tools_utils.ml b/common/mltools/tools_utils.ml -index 5a35708cd..ade4cb37f 100644 ---- a/common/mltools/tools_utils.ml -+++ b/common/mltools/tools_utils.ml -@@ -59,7 +59,11 @@ let machine_readable () = - | None -> None - | Some chan -> - let pr fs = -- ksprintf (output_string chan) fs -+ let out s = -+ output_string chan s; -+ flush chan -+ in -+ ksprintf out fs - in - Some { pr } - --- -2.18.4 - diff --git a/SOURCES/0023-common-mltools-allow-fd-for-machine-readable-output.patch b/SOURCES/0023-common-mltools-allow-fd-for-machine-readable-output.patch deleted file mode 100644 index 52e1b86..0000000 --- a/SOURCES/0023-common-mltools-allow-fd-for-machine-readable-output.patch +++ /dev/null @@ -1,87 +0,0 @@ -From f7acb14822f1a962a211c0d11488ffceadde2b68 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Fri, 22 Mar 2019 12:59:11 +0100 -Subject: [PATCH] common/mltools: allow fd for machine readable output - -Allow to specify a file descriptor for the machine readable output. - -Use the same assumption as done in v2v, i.e. that Unix.file_descr is -simply the int file descriptor. - -(cherry picked from commit 70514dfaf1e45b5ad34f20f3297af9782099cf80) ---- - common/mltools/test-machine-readable.sh | 7 +++++++ - common/mltools/tools_utils.ml | 11 ++++++++++- - lib/guestfs.pod | 5 +++++ - 3 files changed, 22 insertions(+), 1 deletion(-) - -diff --git a/common/mltools/test-machine-readable.sh b/common/mltools/test-machine-readable.sh -index 1162c58e9..824460e6d 100755 ---- a/common/mltools/test-machine-readable.sh -+++ b/common/mltools/test-machine-readable.sh -@@ -65,3 +65,10 @@ test $($t --machine-readable=stream:stdout |& wc -l) -eq 3 - # Output "stream:stderr". - $t --machine-readable=stream:stderr 2>&1 >/dev/null | grep 'machine-readable' - test $($t --machine-readable=stream:stderr 2>&1 >/dev/null | wc -l) -eq 2 -+ -+# Output "fd:". -+fn="$tmpdir/fdfile" -+exec 4>"$fn" -+$t --machine-readable=fd:4 -+exec 4>&- -+test $(cat "$fn" | wc -l) -eq 1 -diff --git a/common/mltools/tools_utils.ml b/common/mltools/tools_utils.ml -index ade4cb37f..35478f39e 100644 ---- a/common/mltools/tools_utils.ml -+++ b/common/mltools/tools_utils.ml -@@ -41,6 +41,7 @@ type machine_readable_output_type = - | NoOutput - | Channel of out_channel - | File of string -+ | Fd of int - let machine_readable_output = ref NoOutput - let machine_readable_channel = ref None - let machine_readable () = -@@ -50,7 +51,10 @@ let machine_readable () = - match !machine_readable_output with - | NoOutput -> None - | Channel chan -> Some chan -- | File f -> Some (open_out f) in -+ | File f -> Some (open_out f) -+ | Fd fd -> -+ (* Note that Unix.file_descr is really just an int. *) -+ Some (Unix.out_channel_of_descr (Obj.magic fd)) in - machine_readable_channel := chan - ); - !machine_readable_channel -@@ -296,6 +300,11 @@ let create_standard_options argspec ?anon_fun ?(key_opts = false) ?(machine_read - | n -> - error (f_"invalid output stream for --machine-readable: %s") fmt in - machine_readable_output := Channel chan -+ | "fd" -> -+ (try -+ machine_readable_output := Fd (int_of_string outname) -+ with Failure _ -> -+ error (f_"invalid output fd for --machine-readable: %s") fmt) - | n -> - error (f_"invalid output for --machine-readable: %s") fmt - ) -diff --git a/lib/guestfs.pod b/lib/guestfs.pod -index 53cece2da..f11028466 100644 ---- a/lib/guestfs.pod -+++ b/lib/guestfs.pod -@@ -3287,6 +3287,11 @@ The possible values are: - - =over 4 - -+=item BI -+ -+The output goes to the specified I, which is a file descriptor -+already opened for writing. -+ - =item BF - - The output goes to the specified F. --- -2.18.4 - diff --git a/SOURCES/0024-OCaml-tools-output-messages-into-JSON-for-machine-re.patch b/SOURCES/0024-OCaml-tools-output-messages-into-JSON-for-machine-re.patch deleted file mode 100644 index 0b00a0d..0000000 --- a/SOURCES/0024-OCaml-tools-output-messages-into-JSON-for-machine-re.patch +++ /dev/null @@ -1,514 +0,0 @@ -From e34b3a6aca9e7e51888416c57f768522597a2df1 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Fri, 22 Mar 2019 16:24:25 +0100 -Subject: [PATCH] OCaml tools: output messages into JSON for machine readable - -When the machine readable mode is enabled, print all the messages -(progress, info, warning, and errors) also as JSON in the machine -readable stream: this way, users can easily parse the status of the -OCaml tool, and report that back. - -The formatting of the current date time into the RFC 3999 format is done -in C, because of the lack of OCaml APIs for this. - -(cherry picked from commit f79129b8dc92470e3a5597daf53c84038bd6859e) ---- - .gitignore | 1 + - common/mltools/Makefile.am | 39 ++++++- - common/mltools/parse_tools_messages_test.py | 118 ++++++++++++++++++++ - common/mltools/test-tools-messages.sh | 28 +++++ - common/mltools/tools_messages_tests.ml | 46 ++++++++ - common/mltools/tools_utils-c.c | 51 +++++++++ - common/mltools/tools_utils.ml | 16 +++ - lib/guestfs.pod | 19 ++++ - 8 files changed, 316 insertions(+), 2 deletions(-) - create mode 100644 common/mltools/parse_tools_messages_test.py - create mode 100755 common/mltools/test-tools-messages.sh - create mode 100644 common/mltools/tools_messages_tests.ml - -diff --git a/.gitignore b/.gitignore -index f2efcdde2..db1dbb7cc 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -147,6 +147,7 @@ Makefile.in - /common/mltools/JSON_tests - /common/mltools/JSON_parser_tests - /common/mltools/machine_readable_tests -+/common/mltools/tools_messages_tests - /common/mltools/tools_utils_tests - /common/mltools/oUnit-* - /common/mlutils/.depend -diff --git a/common/mltools/Makefile.am b/common/mltools/Makefile.am -index 37d10e610..ae78b84b7 100644 ---- a/common/mltools/Makefile.am -+++ b/common/mltools/Makefile.am -@@ -27,6 +27,8 @@ EXTRA_DIST = \ - machine_readable_tests.ml \ - test-getopt.sh \ - test-machine-readable.sh \ -+ test-tools-messages.sh \ -+ tools_messages_tests.ml \ - tools_utils_tests.ml - - SOURCES_MLI = \ -@@ -45,12 +47,12 @@ SOURCES_MLI = \ - - SOURCES_ML = \ - getopt.ml \ -+ JSON.ml \ - tools_utils.ml \ - URI.ml \ - planner.ml \ - registry.ml \ - regedit.ml \ -- JSON.ml \ - JSON_parser.ml \ - curl.ml \ - checksums.ml \ -@@ -196,6 +198,15 @@ machine_readable_tests_CPPFLAGS = \ - machine_readable_tests_BOBJECTS = machine_readable_tests.cmo - machine_readable_tests_XOBJECTS = $(machine_readable_tests_BOBJECTS:.cmo=.cmx) - -+tools_messages_tests_SOURCES = dummy.c -+tools_messages_tests_CPPFLAGS = \ -+ -I. \ -+ -I$(top_builddir) \ -+ -I$(shell $(OCAMLC) -where) \ -+ -I$(top_srcdir)/lib -+tools_messages_tests_BOBJECTS = tools_messages_tests.cmo -+tools_messages_tests_XOBJECTS = $(tools_messages_tests_BOBJECTS:.cmo=.cmx) -+ - # Can't call the following as _OBJECTS because automake gets confused. - if !HAVE_OCAMLOPT - tools_utils_tests_THEOBJECTS = $(tools_utils_tests_BOBJECTS) -@@ -212,6 +223,9 @@ JSON_parser_tests.cmo: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS) - - machine_readable_tests_THEOBJECTS = $(machine_readable_tests_BOBJECTS) - machine_readable_tests.cmo: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS) -+ -+tools_messages_tests_THEOBJECTS = $(tools_messages_tests_tests_BOBJECTS) -+tools_messages_tests.cmo: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS) - else - tools_utils_tests_THEOBJECTS = $(tools_utils_tests_XOBJECTS) - tools_utils_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS) -@@ -227,6 +241,9 @@ JSON_parser_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS) - - machine_readable_tests_THEOBJECTS = $(machine_readable_tests_XOBJECTS) - machine_readable_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS) -+ -+tools_messages_tests_THEOBJECTS = $(tools_messages_tests_XOBJECTS) -+tools_messages_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS) - endif - - OCAMLLINKFLAGS = \ -@@ -302,14 +319,32 @@ machine_readable_tests_LINK = \ - $(OCAMLPACKAGES) $(OCAMLPACKAGES_TESTS) \ - $(machine_readable_tests_THEOBJECTS) -o $@ - -+tools_messages_tests_DEPENDENCIES = \ -+ $(tools_messages_tests_THEOBJECTS) \ -+ ../mlstdutils/mlstdutils.$(MLARCHIVE) \ -+ ../mlgettext/mlgettext.$(MLARCHIVE) \ -+ ../mlpcre/mlpcre.$(MLARCHIVE) \ -+ $(MLTOOLS_CMA) \ -+ $(top_srcdir)/ocaml-link.sh -+tools_messages_tests_LINK = \ -+ $(top_srcdir)/ocaml-link.sh -cclib '-lutils -lgnu' -- \ -+ $(OCAMLFIND) $(BEST) $(OCAMLFLAGS) $(OCAMLLINKFLAGS) \ -+ $(OCAMLPACKAGES) $(OCAMLPACKAGES_TESTS) \ -+ $(tools_messages_tests_THEOBJECTS) -o $@ -+ - TESTS_ENVIRONMENT = $(top_builddir)/run --test - - TESTS = \ - test-getopt.sh \ - test-machine-readable.sh -+if HAVE_PYTHON -+TESTS += \ -+ test-tools-messages.sh -+endif - check_PROGRAMS = \ - getopt_tests \ -- machine_readable_tests -+ machine_readable_tests \ -+ tools_messages_tests - - if HAVE_OCAML_PKG_OUNIT - check_PROGRAMS += JSON_tests JSON_parser_tests tools_utils_tests -diff --git a/common/mltools/parse_tools_messages_test.py b/common/mltools/parse_tools_messages_test.py -new file mode 100644 -index 000000000..9dcd6cae6 ---- /dev/null -+++ b/common/mltools/parse_tools_messages_test.py -@@ -0,0 +1,118 @@ -+# Copyright (C) 2019 Red Hat Inc. -+# -+# This program is free software; you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation; either version 2 of the License, or -+# (at your option) any later version. -+# -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program; if not, write to the Free Software -+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ -+import datetime -+import json -+import os -+import sys -+import unittest -+ -+exe = "tools_messages_tests" -+ -+if sys.version_info >= (3, 4): -+ def set_fd_inheritable(fd): -+ os.set_inheritable(fd, True) -+else: -+ def set_fd_inheritable(fd): -+ pass -+ -+ -+if sys.version_info >= (3, 0): -+ def fdopen(fd, mode): -+ return open(fd, mode) -+ -+ def isModuleInstalled(mod): -+ import importlib -+ return bool(importlib.util.find_spec(mod)) -+else: -+ def fdopen(fd, mode): -+ return os.fdopen(fd, mode) -+ -+ def isModuleInstalled(mod): -+ import imp -+ try: -+ imp.find_module(mod) -+ return True -+ except ImportError: -+ return False -+ -+ -+def skipUnlessHasModule(mod): -+ if not isModuleInstalled(mod): -+ return unittest.skip("%s not available" % mod) -+ return lambda func: func -+ -+ -+def iterload(stream): -+ dec = json.JSONDecoder() -+ for line in stream: -+ yield dec.raw_decode(line) -+ -+ -+def loadJsonFromCommand(extraargs): -+ r, w = os.pipe() -+ set_fd_inheritable(r) -+ r = fdopen(r, "r") -+ set_fd_inheritable(w) -+ w = fdopen(w, "w") -+ pid = os.fork() -+ if pid: -+ w.close() -+ l = list(iterload(r)) -+ l = [o[0] for o in l] -+ r.close() -+ return l -+ else: -+ r.close() -+ args = ["tools_messages_tests", -+ "--machine-readable=fd:%d" % w.fileno()] + extraargs -+ os.execvp("./" + exe, args) -+ -+ -+@skipUnlessHasModule('iso8601') -+class TestParseToolsMessages(unittest.TestCase): -+ def check_json(self, json, typ, msg): -+ import iso8601 -+ # Check the type. -+ jsontype = json.pop("type") -+ self.assertEqual(jsontype, typ) -+ # Check the message. -+ jsonmsg = json.pop("message") -+ self.assertEqual(jsonmsg, msg) -+ # Check the timestamp. -+ jsonts = json.pop("timestamp") -+ dt = iso8601.parse_date(jsonts) -+ now = datetime.datetime.now(dt.tzinfo) -+ self.assertGreater(now, dt) -+ # Check there are no more keys left (and thus not previously tested). -+ self.assertEqual(len(json), 0) -+ -+ def test_messages(self): -+ objects = loadJsonFromCommand([]) -+ self.assertEqual(len(objects), 4) -+ self.check_json(objects[0], "message", "Starting") -+ self.check_json(objects[1], "info", "An information message") -+ self.check_json(objects[2], "warning", "Warning: message here") -+ self.check_json(objects[3], "message", "Finishing") -+ -+ def test_error(self): -+ objects = loadJsonFromCommand(["--error"]) -+ self.assertEqual(len(objects), 1) -+ self.check_json(objects[0], "error", "Error!") -+ -+ -+if __name__ == '__main__': -+ unittest.main() -diff --git a/common/mltools/test-tools-messages.sh b/common/mltools/test-tools-messages.sh -new file mode 100755 -index 000000000..0e24d6ce9 ---- /dev/null -+++ b/common/mltools/test-tools-messages.sh -@@ -0,0 +1,28 @@ -+#!/bin/bash - -+# libguestfs -+# Copyright (C) 2019 Red Hat Inc. -+# -+# This program is free software; you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation; either version 2 of the License, or -+# (at your option) any later version. -+# -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program; if not, write to the Free Software -+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ -+# Test the --machine-readable functionality of the module Tools_utils. -+# See also: machine_readable_tests.ml -+ -+set -e -+set -x -+ -+$TEST_FUNCTIONS -+skip_if_skipped -+ -+$PYTHON parse_tools_messages_test.py -diff --git a/common/mltools/tools_messages_tests.ml b/common/mltools/tools_messages_tests.ml -new file mode 100644 -index 000000000..d5f9be89b ---- /dev/null -+++ b/common/mltools/tools_messages_tests.ml -@@ -0,0 +1,46 @@ -+(* -+ * Copyright (C) 2019 Red Hat Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ *) -+ -+(* Test the message output for tools of the module Tools_utils. -+ * The tests are controlled by the test-tools-messages.sh script. -+ *) -+ -+open Printf -+ -+open Std_utils -+open Tools_utils -+open Getopt.OptionName -+ -+let is_error = ref false -+ -+let args = [ -+ [ L "error" ], Getopt.Set is_error, "Only print the error"; -+] -+let usage_msg = sprintf "%s: test the message outputs" prog -+ -+let opthandle = create_standard_options args ~machine_readable:true usage_msg -+let () = -+ Getopt.parse opthandle.getopt; -+ -+ if !is_error then -+ error "Error!"; -+ -+ message "Starting"; -+ info "An information message"; -+ warning "Warning: message here"; -+ message "Finishing" -diff --git a/common/mltools/tools_utils-c.c b/common/mltools/tools_utils-c.c -index c88c95082..b015dcace 100644 ---- a/common/mltools/tools_utils-c.c -+++ b/common/mltools/tools_utils-c.c -@@ -23,6 +23,8 @@ - #include - #include - #include -+#include -+#include - - #include - #include -@@ -37,6 +39,7 @@ - extern value guestfs_int_mllib_inspect_decrypt (value gv, value gpv, value keysv); - extern value guestfs_int_mllib_set_echo_keys (value unitv); - extern value guestfs_int_mllib_set_keys_from_stdin (value unitv); -+extern value guestfs_int_mllib_rfc3999_date_time_string (value unitv); - - /* Interface with the guestfish inspection and decryption code. */ - int echo_keys = 0; -@@ -103,3 +106,51 @@ guestfs_int_mllib_set_keys_from_stdin (value unitv) - keys_from_stdin = 1; - return Val_unit; - } -+ -+value -+guestfs_int_mllib_rfc3999_date_time_string (value unitv) -+{ -+ CAMLparam1 (unitv); -+ char buf[64]; -+ struct timespec ts; -+ struct tm tm; -+ size_t ret; -+ size_t total = 0; -+ -+ if (clock_gettime (CLOCK_REALTIME, &ts) == -1) -+ unix_error (errno, (char *) "clock_gettime", Val_unit); -+ -+ if (localtime_r (&ts.tv_sec, &tm) == NULL) -+ unix_error (errno, (char *) "localtime_r", caml_copy_int64 (ts.tv_sec)); -+ -+ /* Sadly strftime does not support nanoseconds, so what we do is: -+ * - stringify everything before the nanoseconds -+ * - print the nanoseconds -+ * - stringify the rest (i.e. the timezone) -+ * then place ':' between the hours, and the minutes of the -+ * timezone offset. -+ */ -+ -+ ret = strftime (buf, sizeof (buf), "%Y-%m-%dT%H:%M:%S.", &tm); -+ if (ret == 0) -+ unix_error (errno, (char *) "strftime", Val_unit); -+ total += ret; -+ -+ ret = snprintf (buf + total, sizeof (buf) - total, "%09ld", ts.tv_nsec); -+ if (ret == 0) -+ unix_error (errno, (char *) "sprintf", caml_copy_int64 (ts.tv_nsec)); -+ total += ret; -+ -+ ret = strftime (buf + total, sizeof (buf) - total, "%z", &tm); -+ if (ret == 0) -+ unix_error (errno, (char *) "strftime", Val_unit); -+ total += ret; -+ -+ /* Move the timezone minutes one character to the right, moving the -+ * null character too. -+ */ -+ memmove (buf + total - 1, buf + total - 2, 3); -+ buf[total - 2] = ':'; -+ -+ CAMLreturn (caml_copy_string (buf)); -+} -diff --git a/common/mltools/tools_utils.ml b/common/mltools/tools_utils.ml -index 35478f39e..de42df600 100644 ---- a/common/mltools/tools_utils.ml -+++ b/common/mltools/tools_utils.ml -@@ -32,6 +32,7 @@ and key_store_key = - external c_inspect_decrypt : Guestfs.t -> int64 -> (string * key_store_key) list -> unit = "guestfs_int_mllib_inspect_decrypt" - external c_set_echo_keys : unit -> unit = "guestfs_int_mllib_set_echo_keys" "noalloc" - external c_set_keys_from_stdin : unit -> unit = "guestfs_int_mllib_set_keys_from_stdin" "noalloc" -+external c_rfc3999_date_time_string : unit -> string = "guestfs_int_mllib_rfc3999_date_time_string" - - type machine_readable_fn = { - pr : 'a. ('a, unit, string, unit) format4 -> 'a; -@@ -86,12 +87,24 @@ let ansi_magenta ?(chan = stdout) () = - let ansi_restore ?(chan = stdout) () = - if colours () || istty chan then output_string chan "\x1b[0m" - -+let log_as_json msgtype msg = -+ match machine_readable () with -+ | None -> () -+ | Some { pr } -> -+ let json = [ -+ "message", JSON.String msg; -+ "timestamp", JSON.String (c_rfc3999_date_time_string ()); -+ "type", JSON.String msgtype; -+ ] in -+ pr "%s\n" (JSON.string_of_doc ~fmt:JSON.Compact json) -+ - (* Timestamped progress messages, used for ordinary messages when not - * --quiet. - *) - let start_t = Unix.gettimeofday () - let message fs = - let display str = -+ log_as_json "message" str; - if not (quiet ()) then ( - let t = sprintf "%.1f" (Unix.gettimeofday () -. start_t) in - printf "[%6s] " t; -@@ -106,6 +119,7 @@ let message fs = - (* Error messages etc. *) - let error ?(exit_code = 1) fs = - let display str = -+ log_as_json "error" str; - let chan = stderr in - ansi_red ~chan (); - wrap ~chan (sprintf (f_"%s: error: %s") prog str); -@@ -124,6 +138,7 @@ let error ?(exit_code = 1) fs = - - let warning fs = - let display str = -+ log_as_json "warning" str; - let chan = stdout in - ansi_blue ~chan (); - wrap ~chan (sprintf (f_"%s: warning: %s") prog str); -@@ -134,6 +149,7 @@ let warning fs = - - let info fs = - let display str = -+ log_as_json "info" str; - let chan = stdout in - ansi_magenta ~chan (); - wrap ~chan (sprintf (f_"%s: %s") prog str); -diff --git a/lib/guestfs.pod b/lib/guestfs.pod -index f11028466..3c1d635c5 100644 ---- a/lib/guestfs.pod -+++ b/lib/guestfs.pod -@@ -3279,6 +3279,25 @@ Some of the tools support a I<--machine-readable> option, which is - generally used to make the output more machine friendly, for easier - parsing for example. By default, this output goes to stdout. - -+When using the I<--machine-readable> option, the progress, -+information, warning, and error messages are also printed in JSON -+format for easier log tracking. Thus, it is highly recommended to -+redirect the machine-readable output to a different stream. The -+format of these JSON messages is like the following (actually printed -+within a single line, below it is indented for readability): -+ -+ { -+ "message": "Finishing off", -+ "timestamp": "2019-03-22T14:46:49.067294446+01:00", -+ "type": "message" -+ } -+ -+C can be: C for progress messages, C for -+information messages, C for warning messages, and C -+for error message. -+C is the L -+timestamp of the message. -+ - In addition to that, a subset of these tools support an extra string - passed to the I<--machine-readable> option: this string specifies - where the machine-readable output will go. --- -2.18.4 - diff --git a/SOURCES/0025-OCaml-tools-fix-3999-3339-typo.patch b/SOURCES/0025-OCaml-tools-fix-3999-3339-typo.patch deleted file mode 100644 index 796867d..0000000 --- a/SOURCES/0025-OCaml-tools-fix-3999-3339-typo.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 1d6f775d8826915f9547c7dcac0fd10e702c3d80 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Mon, 1 Apr 2019 17:01:44 +0200 -Subject: [PATCH] OCaml tools: fix 3999 -> 3339 typo - -RFC 3339 is the actual RFC for date/time strings. -Typo found by Martin 'eagle eyes' Kletzander. - -Fixes commit f79129b8dc92470e3a5597daf53c84038bd6859e. - -(cherry picked from commit 1086599ad8eeb8be299d5ffbcb2efb1024ff9ab8) ---- - common/mltools/tools_utils-c.c | 4 ++-- - common/mltools/tools_utils.ml | 4 ++-- - lib/guestfs.pod | 2 +- - 3 files changed, 5 insertions(+), 5 deletions(-) - -diff --git a/common/mltools/tools_utils-c.c b/common/mltools/tools_utils-c.c -index b015dcace..3b80091c0 100644 ---- a/common/mltools/tools_utils-c.c -+++ b/common/mltools/tools_utils-c.c -@@ -39,7 +39,7 @@ - extern value guestfs_int_mllib_inspect_decrypt (value gv, value gpv, value keysv); - extern value guestfs_int_mllib_set_echo_keys (value unitv); - extern value guestfs_int_mllib_set_keys_from_stdin (value unitv); --extern value guestfs_int_mllib_rfc3999_date_time_string (value unitv); -+extern value guestfs_int_mllib_rfc3339_date_time_string (value unitv); - - /* Interface with the guestfish inspection and decryption code. */ - int echo_keys = 0; -@@ -108,7 +108,7 @@ guestfs_int_mllib_set_keys_from_stdin (value unitv) - } - - value --guestfs_int_mllib_rfc3999_date_time_string (value unitv) -+guestfs_int_mllib_rfc3339_date_time_string (value unitv) - { - CAMLparam1 (unitv); - char buf[64]; -diff --git a/common/mltools/tools_utils.ml b/common/mltools/tools_utils.ml -index de42df600..127180225 100644 ---- a/common/mltools/tools_utils.ml -+++ b/common/mltools/tools_utils.ml -@@ -32,7 +32,7 @@ and key_store_key = - external c_inspect_decrypt : Guestfs.t -> int64 -> (string * key_store_key) list -> unit = "guestfs_int_mllib_inspect_decrypt" - external c_set_echo_keys : unit -> unit = "guestfs_int_mllib_set_echo_keys" "noalloc" - external c_set_keys_from_stdin : unit -> unit = "guestfs_int_mllib_set_keys_from_stdin" "noalloc" --external c_rfc3999_date_time_string : unit -> string = "guestfs_int_mllib_rfc3999_date_time_string" -+external c_rfc3339_date_time_string : unit -> string = "guestfs_int_mllib_rfc3339_date_time_string" - - type machine_readable_fn = { - pr : 'a. ('a, unit, string, unit) format4 -> 'a; -@@ -93,7 +93,7 @@ let log_as_json msgtype msg = - | Some { pr } -> - let json = [ - "message", JSON.String msg; -- "timestamp", JSON.String (c_rfc3999_date_time_string ()); -+ "timestamp", JSON.String (c_rfc3339_date_time_string ()); - "type", JSON.String msgtype; - ] in - pr "%s\n" (JSON.string_of_doc ~fmt:JSON.Compact json) -diff --git a/lib/guestfs.pod b/lib/guestfs.pod -index 3c1d635c5..af944ddb7 100644 ---- a/lib/guestfs.pod -+++ b/lib/guestfs.pod -@@ -3295,7 +3295,7 @@ within a single line, below it is indented for readability): - C can be: C for progress messages, C for - information messages, C for warning messages, and C - for error message. --C is the L -+C is the L - timestamp of the message. - - In addition to that, a subset of these tools support an extra string --- -2.18.4 - diff --git a/SOURCES/0026-v2v-remove-extra-nbdkit-bit-from-documentation-RHBZ-.patch b/SOURCES/0026-v2v-remove-extra-nbdkit-bit-from-documentation-RHBZ-.patch deleted file mode 100644 index e3e707a..0000000 --- a/SOURCES/0026-v2v-remove-extra-nbdkit-bit-from-documentation-RHBZ-.patch +++ /dev/null @@ -1,31 +0,0 @@ -From ee414298417aa570df4f1c77a5d47672c2871629 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Thu, 18 Jul 2019 15:38:53 +0200 -Subject: [PATCH] v2v: remove extra nbdkit bit from documentation - (RHBZ#1723305) - -Since there is no more need to build nbdkit from sources, then there is -no need to set $PATH with a custom build of nbdkit. - -Followup of commit 0704d8eb0bcc8139886eb4291f75a3ca49a91e58. - -(cherry picked from commit 6d251e3828ff94deac7589b5892df174430e01f9) ---- - v2v/virt-v2v-input-vmware.pod | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/v2v/virt-v2v-input-vmware.pod b/v2v/virt-v2v-input-vmware.pod -index b3ebda182..3acdd773e 100644 ---- a/v2v/virt-v2v-input-vmware.pod -+++ b/v2v/virt-v2v-input-vmware.pod -@@ -293,7 +293,6 @@ To import a particular guest from vCenter server or ESXi hypervisor, - use a command like the following, substituting the URI, guest name and - SSL thumbprint: - -- $ export PATH=/path/to/nbdkit-1.1.x:$PATH - $ virt-v2v \ - -ic 'vpx://root@vcenter.example.com/Datacenter/esxi?no_verify=1' \ - -it vddk \ --- -2.18.4 - diff --git a/SOURCES/0027-v2v-i-vmx-Use-scp-T-option-if-available-to-unbreak-s.patch b/SOURCES/0027-v2v-i-vmx-Use-scp-T-option-if-available-to-unbreak-s.patch deleted file mode 100644 index a45bf92..0000000 --- a/SOURCES/0027-v2v-i-vmx-Use-scp-T-option-if-available-to-unbreak-s.patch +++ /dev/null @@ -1,49 +0,0 @@ -From f36bb1b9c44cda46afa1a34522202a5319fd0a5a Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 25 Jul 2019 14:52:42 +0100 -Subject: [PATCH] v2v: -i vmx: Use scp -T option if available to unbreak scp - (RHBZ#1733168). - -Tested using: - -cd v2v -LIBGUESTFS_BACKEND=direct ../run virt-v2v -i vmx -it ssh "ssh://localhost/$PWD/test-v2v-i-vmx-1.vmx" -o null -v -x - -and manually examining the debug output. - -Thanks: Ming Xie, Jakub Jelen. -(cherry picked from commit 7692c31494f7b1d37e380eed9eb99c5952940dbf) ---- - v2v/input_vmx.ml | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/v2v/input_vmx.ml b/v2v/input_vmx.ml -index b169b2537..e3469308d 100644 ---- a/v2v/input_vmx.ml -+++ b/v2v/input_vmx.ml -@@ -61,6 +61,11 @@ let server_of_uri { Xml.uri_server } = - let path_of_uri { Xml.uri_path } = - match uri_path with None -> assert false | Some p -> p - -+let scp_supports_T_option = lazy ( -+ let cmd = "LANG=C scp -T |& grep \"unknown option\"" in -+ shell_command cmd <> 0 -+) -+ - (* 'scp' a remote file into a temporary local file, returning the path - * of the temporary local file. - *) -@@ -68,8 +73,9 @@ let scp_from_remote_to_temporary uri tmpdir filename = - let localfile = tmpdir // filename in - - let cmd = -- sprintf "scp%s%s %s%s:%s %s" -+ sprintf "scp%s%s%s %s%s:%s %s" - (if verbose () then "" else " -q") -+ (if Lazy.force scp_supports_T_option then " -T" else "") - (match port_of_uri uri with - | None -> "" - | Some port -> sprintf " -P %d" port) --- -2.18.4 - diff --git a/SOURCES/0028-v2v-Allow-Windows-virtio-ISO-to-be-a-block-device-as.patch b/SOURCES/0028-v2v-Allow-Windows-virtio-ISO-to-be-a-block-device-as.patch deleted file mode 100644 index 82e592c..0000000 --- a/SOURCES/0028-v2v-Allow-Windows-virtio-ISO-to-be-a-block-device-as.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 9a9270b0156cf30d98c26eaffb8b12c98d0d9bf4 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 4 Jul 2019 15:51:25 +0100 -Subject: [PATCH] v2v: Allow Windows virtio ISO to be a block device as well as - a regular file. - -Thanks: Steven Rosenberg -(cherry picked from commit c22a8b68fe5729d3a8907b41eef287cd9f3a55c0) ---- - v2v/windows_virtio.ml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/v2v/windows_virtio.ml b/v2v/windows_virtio.ml -index 92bf3ec60..a6dc29f2c 100644 ---- a/v2v/windows_virtio.ml -+++ b/v2v/windows_virtio.ml -@@ -330,7 +330,7 @@ and copy_from_virtio_win g inspect srcdir destdir filter missing = - ) paths - ) - ) -- else if is_regular_file virtio_win then ( -+ else if is_regular_file virtio_win || is_block_device virtio_win then ( - debug "windows: copy_from_virtio_win: guest tools source ISO %s" virtio_win; - - try --- -2.18.4 - diff --git a/SOURCES/0029-v2v-Set-DISKTYPE-2-in-RHV-and-VDSM-meta-files-RHBZ-1.patch b/SOURCES/0029-v2v-Set-DISKTYPE-2-in-RHV-and-VDSM-meta-files-RHBZ-1.patch deleted file mode 100644 index 76aa6a3..0000000 --- a/SOURCES/0029-v2v-Set-DISKTYPE-2-in-RHV-and-VDSM-meta-files-RHBZ-1.patch +++ /dev/null @@ -1,46 +0,0 @@ -From c49492cf218f4e6c1e90979c8d50ce3557642c42 Mon Sep 17 00:00:00 2001 -From: Nir Soffer -Date: Mon, 2 Sep 2019 17:45:13 +0100 -Subject: [PATCH] v2v: Set DISKTYPE=2 in RHV and VDSM meta files - (RHBZ#1746699). - -Added in virt-p2v commit: - - commit e83b6f50af34ce650063ecc520bfabab400e8e73 - Author: Matthew Booth - Date: Fri Mar 26 09:40:20 2010 +0000 - - Add export to RHEV - - Allow guests to be written to a RHEV NFS export storage domain. - - Add 'rhev' output method and -osd command-line option. - Example command line: - - virt-v2v -f virt-v2v.conf -ic 'esx://yellow.rhev.marston/' \ - -o rhev -osd blue:/export/export RHEL3-32 - - This will connect to an ESX server and write the guest 'RHEL3-32' to - blue:/export/export, which is a pre-initialised RHEV export storage domain. - -(cherry picked from commit fcfdbc9420b07e3003df38481afb9ccd22045e1a) ---- - v2v/create_ovf.ml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/v2v/create_ovf.ml b/v2v/create_ovf.ml -index 91ff5198d..9aad5dd15 100644 ---- a/v2v/create_ovf.ml -+++ b/v2v/create_ovf.ml -@@ -501,7 +501,7 @@ let create_meta_files output_alloc sd_uuid image_uuids overlays = - bpf "CTIME=%.0f\n" time; - bpf "MTIME=%.0f\n" time; - bpf "IMAGE=%s\n" image_uuid; -- bpf "DISKTYPE=1\n"; -+ bpf "DISKTYPE=2\n"; - bpf "PUUID=00000000-0000-0000-0000-000000000000\n"; - bpf "LEGALITY=LEGAL\n"; - bpf "POOL_UUID=\n"; --- -2.18.4 - diff --git a/SOURCES/0030-v2v-rhv-upload-plugin-improve-wait-logic-after-final.patch b/SOURCES/0030-v2v-rhv-upload-plugin-improve-wait-logic-after-final.patch deleted file mode 100644 index 11e4ed6..0000000 --- a/SOURCES/0030-v2v-rhv-upload-plugin-improve-wait-logic-after-final.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 1a601b248f347b2237ff458376a010eeb46d005d Mon Sep 17 00:00:00 2001 -From: Daniel Erez -Date: Mon, 18 Mar 2019 18:51:26 +0200 -Subject: [PATCH] v2v: rhv-upload-plugin - improve wait logic after finalize - (RHBZ#1680361) - -After invoking transfer_service.finalize, check operation status by -examining DiskStatus. This is done instead of failing after a -predefined timeout regardless the status. - -Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=1680361 -Signed-off-by: Richard W.M. Jones -Tested-by: Ilanit Stein -(cherry picked from commit eeabb3fdc7756887b53106f455a7b54309130637) ---- - v2v/rhv-upload-plugin.py | 19 +++++++++++++------ - 1 file changed, 13 insertions(+), 6 deletions(-) - -diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py -index 2a950c5ed..4d61a089b 100644 ---- a/v2v/rhv-upload-plugin.py -+++ b/v2v/rhv-upload-plugin.py -@@ -523,16 +523,23 @@ def close(h): - # waiting for the transfer object to cease to exist, which - # falls through to the exception case and then we can - # continue. -- endt = time.time() + timeout -+ disk_id = disk.id -+ start = time.time() - try: - while True: - time.sleep(1) -- tmp = transfer_service.get() -- if time.time() > endt: -- raise RuntimeError("timed out waiting for transfer " -- "to finalize") -+ disk_service = h['disk_service'] -+ disk = disk_service.get() -+ if disk.status == types.DiskStatus.LOCKED: -+ if time.time() > start + timeout: -+ raise RuntimeError("timed out waiting for transfer " -+ "to finalize") -+ continue -+ if disk.status == types.DiskStatus.OK: -+ debug("finalized after %s seconds" % (time.time() - start)) -+ break - except sdk.NotFoundError: -- pass -+ raise RuntimeError("transfer failed: disk %s not found" % disk_id) - - # Write the disk ID file. Only do this on successful completion. - with builtins.open(params['diskid_file'], 'w') as fp: --- -2.18.4 - diff --git a/SOURCES/0031-v2v-o-rhv-upload-check-whether-the-cluster-exists.patch b/SOURCES/0031-v2v-o-rhv-upload-check-whether-the-cluster-exists.patch deleted file mode 100644 index 9079b85..0000000 --- a/SOURCES/0031-v2v-o-rhv-upload-check-whether-the-cluster-exists.patch +++ /dev/null @@ -1,61 +0,0 @@ -From fed5b4195b1b220e43964aa61d01634b307f09a4 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Mon, 15 Apr 2019 17:24:42 +0200 -Subject: [PATCH] v2v: -o rhv-upload: check whether the cluster exists - -In the precheck script, check that the target cluster actually exists. -This will avoid errors when creating the VM after the data copying. - -(cherry picked from commit 05e559549dab75f17e147f4a4eafbac868a7aa5d) ---- - v2v/rhv-upload-precheck.py | 10 ++++++++++ - v2v/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py | 7 +++++++ - 2 files changed, 17 insertions(+) - -diff --git a/v2v/rhv-upload-precheck.py b/v2v/rhv-upload-precheck.py -index 2798a29dd..b79f91b4a 100644 ---- a/v2v/rhv-upload-precheck.py -+++ b/v2v/rhv-upload-precheck.py -@@ -70,4 +70,14 @@ if len(vms) > 0: - raise RuntimeError("VM already exists with name ‘%s’, id ‘%s’" % - (params['output_name'], vm.id)) - -+# Check whether the specified cluster exists. -+clusters_service = system_service.clusters_service() -+clusters = clusters_service.list( -+ search='name=%s' % params['rhv_cluster'], -+ case_sensitive=True, -+) -+if len(clusters) == 0: -+ raise RuntimeError("The cluster ‘%s’ does not exist" % -+ (params['rhv_cluster'])) -+ - # Otherwise everything is OK, exit with no error. -diff --git a/v2v/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py b/v2v/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py -index 8d1058d67..cc4224ccd 100644 ---- a/v2v/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py -+++ b/v2v/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py -@@ -39,6 +39,9 @@ class Connection(object): - return SystemService() - - class SystemService(object): -+ def clusters_service(self): -+ return ClustersService() -+ - def data_centers_service(self): - return DataCentersService() - -@@ -54,6 +57,10 @@ class SystemService(object): - def vms_service(self): - return VmsService() - -+class ClustersService(object): -+ def list(self, search=None, case_sensitive=False): -+ return ["Default"] -+ - class DataCentersService(object): - def list(self, search=None, case_sensitive=False): - return [] --- -2.18.4 - diff --git a/SOURCES/0032-v2v-o-rhv-upload-split-vmcheck-out-of-precheck.patch b/SOURCES/0032-v2v-o-rhv-upload-split-vmcheck-out-of-precheck.patch deleted file mode 100644 index 1bc6c82..0000000 --- a/SOURCES/0032-v2v-o-rhv-upload-split-vmcheck-out-of-precheck.patch +++ /dev/null @@ -1,264 +0,0 @@ -From fb5e3592a94b535abe686b65e51577ad0e36fcd0 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Thu, 12 Sep 2019 13:19:48 +0200 -Subject: [PATCH] v2v: -o rhv-upload: split vmcheck out of precheck - -Split the VM existance check out of the precheck script to a new vmcheck -script, and invoke that in #prepare_targets. Invoke the precheck script -in #precheck, as now it can be run with only values of command line -options. - -This does not change which checks are performed; however, an invalid -cluster name will make virt-v2v fail way earlier (even before connecting -to the source). - -(cherry picked from commit 6499fdc199790619745eee28fcae3421c32c4735) ---- - v2v/Makefile.am | 8 ++- - v2v/output_rhv_upload.ml | 14 +++-- - v2v/output_rhv_upload_precheck_source.mli | 2 +- - v2v/output_rhv_upload_vmcheck_source.mli | 19 ++++++ - v2v/rhv-upload-precheck.py | 12 +--- - v2v/rhv-upload-vmcheck.py | 73 +++++++++++++++++++++++ - 6 files changed, 111 insertions(+), 17 deletions(-) - create mode 100644 v2v/output_rhv_upload_vmcheck_source.mli - create mode 100644 v2v/rhv-upload-vmcheck.py - -diff --git a/v2v/Makefile.am b/v2v/Makefile.am -index 53c137fc6..30f040d3e 100644 ---- a/v2v/Makefile.am -+++ b/v2v/Makefile.am -@@ -26,7 +26,8 @@ BUILT_SOURCES = \ - config.ml \ - output_rhv_upload_createvm_source.ml \ - output_rhv_upload_plugin_source.ml \ -- output_rhv_upload_precheck_source.ml -+ output_rhv_upload_precheck_source.ml \ -+ output_rhv_upload_vmcheck_source.ml - - EXTRA_DIST = \ - $(SOURCES_MLI) $(SOURCES_ML) $(SOURCES_C) \ -@@ -36,6 +37,7 @@ EXTRA_DIST = \ - rhv-upload-createvm.py \ - rhv-upload-plugin.py \ - rhv-upload-precheck.py \ -+ rhv-upload-vmcheck.py \ - v2v_unit_tests.ml \ - virt-v2v.pod \ - virt-v2v-copy-to-local.pod \ -@@ -87,6 +89,7 @@ SOURCES_MLI = \ - output_rhv_upload_createvm_source.mli \ - output_rhv_upload_plugin_source.mli \ - output_rhv_upload_precheck_source.mli \ -+ output_rhv_upload_vmcheck_source.mli \ - output_vdsm.mli \ - parse_ova.mli \ - parse_ovf_from_ova.mli \ -@@ -152,6 +155,7 @@ SOURCES_ML = \ - output_rhv_upload_createvm_source.ml \ - output_rhv_upload_plugin_source.ml \ - output_rhv_upload_precheck_source.ml \ -+ output_rhv_upload_vmcheck_source.ml \ - output_rhv_upload.ml \ - output_vdsm.ml \ - output_openstack.ml \ -@@ -173,6 +177,8 @@ output_rhv_upload_plugin_source.ml: $(srcdir)/rhv-upload-plugin.py - $(srcdir)/embed.sh code $^ $@ - output_rhv_upload_precheck_source.ml: $(srcdir)/rhv-upload-precheck.py - $(srcdir)/embed.sh code $^ $@ -+output_rhv_upload_vmcheck_source.ml: $(srcdir)/rhv-upload-vmcheck.py -+ $(srcdir)/embed.sh code $^ $@ - - if HAVE_OCAML - -diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml -index c2a5c72c7..adcbdf25f 100644 ---- a/v2v/output_rhv_upload.ml -+++ b/v2v/output_rhv_upload.ml -@@ -94,10 +94,13 @@ class output_rhv_upload output_alloc output_conn - - let diskid_file_of_id id = tmpdir // sprintf "diskid.%d" id in - -- (* Create Python scripts for precheck, plugin and create VM. *) -+ (* Create Python scripts for precheck, vmcheck, plugin and create VM. *) - let precheck_script = - Python_script.create ~name:"rhv-upload-precheck.py" - Output_rhv_upload_precheck_source.code in -+ let vmcheck_script = -+ Python_script.create ~name:"rhv-upload-vmcheck.py" -+ Output_rhv_upload_vmcheck_source.code in - let plugin_script = - Python_script.create ~name:"rhv-upload-plugin.py" - Output_rhv_upload_plugin_source.code in -@@ -230,6 +233,9 @@ object - error_unless_nbdkit_working (); - error_unless_nbdkit_python_plugin_working (); - error_unless_output_alloc_sparse (); -+ (* Python code prechecks. *) -+ if Python_script.run_command precheck_script json_params [] <> 0 then -+ error (f_"failed server prechecks, see earlier errors"); - if have_selinux then - error_unless_nbdkit_compiled_with_selinux () - -@@ -251,11 +257,11 @@ object - let json_params = - ("output_name", JSON.String output_name) :: json_params in - -- (* Python code prechecks. These can't run in #precheck because -+ (* Check that the VM does not exist. This can't run in #precheck because - * we need to know the name of the virtual machine. - *) -- if Python_script.run_command precheck_script json_params [] <> 0 then -- error (f_"failed server prechecks, see earlier errors"); -+ if Python_script.run_command vmcheck_script json_params [] <> 0 then -+ error (f_"failed vmchecks, see earlier errors"); - - (* Create an nbdkit instance for each disk and set the - * target URI to point to the NBD socket. -diff --git a/v2v/output_rhv_upload_precheck_source.mli b/v2v/output_rhv_upload_precheck_source.mli -index c1bafa15b..aa33bc548 100644 ---- a/v2v/output_rhv_upload_precheck_source.mli -+++ b/v2v/output_rhv_upload_precheck_source.mli -@@ -1,5 +1,5 @@ - (* virt-v2v -- * Copyright (C) 2018 Red Hat Inc. -+ * Copyright (C) 2019 Red Hat Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/v2v/output_rhv_upload_vmcheck_source.mli b/v2v/output_rhv_upload_vmcheck_source.mli -new file mode 100644 -index 000000000..c1bafa15b ---- /dev/null -+++ b/v2v/output_rhv_upload_vmcheck_source.mli -@@ -0,0 +1,19 @@ -+(* virt-v2v -+ * Copyright (C) 2018 Red Hat Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ *) -+ -+val code : string -diff --git a/v2v/rhv-upload-precheck.py b/v2v/rhv-upload-precheck.py -index b79f91b4a..d6a58f0fc 100644 ---- a/v2v/rhv-upload-precheck.py -+++ b/v2v/rhv-upload-precheck.py -@@ -1,6 +1,6 @@ - # -*- python -*- - # oVirt or RHV pre-upload checks used by ‘virt-v2v -o rhv-upload’ --# Copyright (C) 2018 Red Hat Inc. -+# Copyright (C) 2018-2019 Red Hat Inc. - # - # This program is free software; you can redistribute it and/or modify - # it under the terms of the GNU General Public License as published by -@@ -60,16 +60,6 @@ connection = sdk.Connection( - - system_service = connection.system_service() - --# Find if a virtual machine already exists with that name. --vms_service = system_service.vms_service() --vms = vms_service.list( -- search = ("name=%s" % params['output_name']), --) --if len(vms) > 0: -- vm = vms[0] -- raise RuntimeError("VM already exists with name ‘%s’, id ‘%s’" % -- (params['output_name'], vm.id)) -- - # Check whether the specified cluster exists. - clusters_service = system_service.clusters_service() - clusters = clusters_service.list( -diff --git a/v2v/rhv-upload-vmcheck.py b/v2v/rhv-upload-vmcheck.py -new file mode 100644 -index 000000000..fbb884b94 ---- /dev/null -+++ b/v2v/rhv-upload-vmcheck.py -@@ -0,0 +1,73 @@ -+# -*- python -*- -+# oVirt or RHV VM existance check used by ‘virt-v2v -o rhv-upload’ -+# Copyright (C) 2018-2019 Red Hat Inc. -+# -+# This program is free software; you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation; either version 2 of the License, or -+# (at your option) any later version. -+# -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License along -+# with this program; if not, write to the Free Software Foundation, Inc., -+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ -+import json -+import logging -+import sys -+import time -+ -+from http.client import HTTPSConnection -+from urllib.parse import urlparse -+ -+import ovirtsdk4 as sdk -+import ovirtsdk4.types as types -+ -+# Parameters are passed in via a JSON doc from the OCaml code. -+# Because this Python code ships embedded inside virt-v2v there -+# is no formal API here. -+params = None -+ -+if len(sys.argv) != 2: -+ raise RuntimeError("incorrect number of parameters") -+ -+# Parameters are passed in via a JSON document. -+with open(sys.argv[1], 'r') as fp: -+ params = json.load(fp) -+ -+# What is passed in is a password file, read the actual password. -+with open(params['output_password'], 'r') as fp: -+ output_password = fp.read() -+output_password = output_password.rstrip() -+ -+# Parse out the username from the output_conn URL. -+parsed = urlparse(params['output_conn']) -+username = parsed.username or "admin@internal" -+ -+# Connect to the server. -+connection = sdk.Connection( -+ url = params['output_conn'], -+ username = username, -+ password = output_password, -+ ca_file = params['rhv_cafile'], -+ log = logging.getLogger(), -+ insecure = params['insecure'], -+) -+ -+system_service = connection.system_service() -+ -+# Find if a virtual machine already exists with that name. -+vms_service = system_service.vms_service() -+vms = vms_service.list( -+ search = ("name=%s" % params['output_name']), -+) -+if len(vms) > 0: -+ vm = vms[0] -+ raise RuntimeError("VM already exists with name ‘%s’, id ‘%s’" % -+ (params['output_name'], vm.id)) -+ -+# Otherwise everything is OK, exit with no error. --- -2.18.4 - diff --git a/SOURCES/0033-v2v-o-rhv-upload-change-precheck-script-to-return-a-.patch b/SOURCES/0033-v2v-o-rhv-upload-change-precheck-script-to-return-a-.patch deleted file mode 100644 index 72a82f9..0000000 --- a/SOURCES/0033-v2v-o-rhv-upload-change-precheck-script-to-return-a-.patch +++ /dev/null @@ -1,53 +0,0 @@ -From bb04eba9683c4143f9b5880238f006af3b13c05c Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Thu, 12 Sep 2019 14:17:36 +0200 -Subject: [PATCH] v2v: -o rhv-upload: change precheck script to return a JSON - -This way it is possible to communicate data from the precheck script -back to virt-v2v. - -For now there are no results, so the resulting JSON is discarded. - -(cherry picked from commit cc6e2a7f9ea53258c2edb758e3ec9beb7baa1fc6) ---- - v2v/output_rhv_upload.ml | 8 +++++++- - v2v/rhv-upload-precheck.py | 6 +++++- - 2 files changed, 12 insertions(+), 2 deletions(-) - -diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml -index adcbdf25f..fd6f2e3e6 100644 ---- a/v2v/output_rhv_upload.ml -+++ b/v2v/output_rhv_upload.ml -@@ -234,8 +234,14 @@ object - error_unless_nbdkit_python_plugin_working (); - error_unless_output_alloc_sparse (); - (* Python code prechecks. *) -- if Python_script.run_command precheck_script json_params [] <> 0 then -+ let precheck_fn = tmpdir // "v2vprecheck.json" in -+ let fd = Unix.openfile precheck_fn [O_WRONLY; O_CREAT] 0o600 in -+ if Python_script.run_command ~stdout_fd:fd -+ precheck_script json_params [] <> 0 then - error (f_"failed server prechecks, see earlier errors"); -+ let json = JSON_parser.json_parser_tree_parse_file precheck_fn in -+ debug "precheck output parsed as: %s" -+ (JSON.string_of_doc ~fmt:JSON.Indented ["", json]); - if have_selinux then - error_unless_nbdkit_compiled_with_selinux () - -diff --git a/v2v/rhv-upload-precheck.py b/v2v/rhv-upload-precheck.py -index d6a58f0fc..de8a66c05 100644 ---- a/v2v/rhv-upload-precheck.py -+++ b/v2v/rhv-upload-precheck.py -@@ -70,4 +70,8 @@ if len(clusters) == 0: - raise RuntimeError("The cluster ‘%s’ does not exist" % - (params['rhv_cluster'])) - --# Otherwise everything is OK, exit with no error. -+# Otherwise everything is OK, print a JSON with the results. -+results = { -+} -+ -+json.dump(results, sys.stdout) --- -2.18.4 - diff --git a/SOURCES/0034-v2v-o-rhv-upload-improve-lookup-of-specified-resourc.patch b/SOURCES/0034-v2v-o-rhv-upload-improve-lookup-of-specified-resourc.patch deleted file mode 100644 index cde9b5b..0000000 --- a/SOURCES/0034-v2v-o-rhv-upload-improve-lookup-of-specified-resourc.patch +++ /dev/null @@ -1,169 +0,0 @@ -From 07348a7d9a7533b11513706a91d8eb8b91ce8518 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Thu, 12 Sep 2019 15:21:26 +0200 -Subject: [PATCH] v2v: -o rhv-upload: improve lookup of specified resources - (RHBZ#1612653) - -Improve the way the precheck script checks for the specified resources: -- look directly for a data center with the specified storage domain -- get the storage domain object from the storage domains attached to the - data center found -- similarly, look for the specified cluster among the ones attached to - the data center found -When everything is found, return the UUID of the storage domain, and of -the cluster back to virt-v2v, which will store them. - -Similarly, rework the createvm script to directly get the requested -cluster, instead of looking for it once again. Also, since the UUID of -the storage domain is available in virt-v2v already, use it directly -instead of using a placeholder. - -This should fix a number of issues: -- unexisting/unattached storage domains are rejected outright -- the cluster is rejected if not part of the same data center of the - selected storage domain -- renaming the specified storage domain during the data copying will not - cause the conversion to fail (which will still use the specified - storage domain, no matter the new name) - -Based on the hints by Daniel Erez in RHBZ#1612653. - -(cherry picked from commit c49aa4fe01aac82d4776dd2a3524ce16e6deed06) ---- - v2v/output_rhv_upload.ml | 24 +++++++++++++++++++----- - v2v/rhv-upload-createvm.py | 11 ++++------- - v2v/rhv-upload-precheck.py | 30 ++++++++++++++++++++++++------ - 3 files changed, 47 insertions(+), 18 deletions(-) - -diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml -index fd6f2e3e6..19bdfcf05 100644 ---- a/v2v/output_rhv_upload.ml -+++ b/v2v/output_rhv_upload.ml -@@ -227,6 +227,11 @@ See also the virt-v2v-output-rhv(1) manual.") - object - inherit output - -+ (* The storage domain UUID. *) -+ val mutable rhv_storagedomain_uuid = None -+ (* The cluster UUID. *) -+ val mutable rhv_cluster_uuid = None -+ - method precheck () = - Python_script.error_unless_python_interpreter_found (); - error_unless_ovirtsdk4_module_available (); -@@ -242,6 +247,10 @@ object - let json = JSON_parser.json_parser_tree_parse_file precheck_fn in - debug "precheck output parsed as: %s" - (JSON.string_of_doc ~fmt:JSON.Indented ["", json]); -+ rhv_storagedomain_uuid <- -+ Some (JSON_parser.object_get_string "rhv_storagedomain_uuid" json); -+ rhv_cluster_uuid <- -+ Some (JSON_parser.object_get_string "rhv_cluster_uuid" json); - if have_selinux then - error_unless_nbdkit_compiled_with_selinux () - -@@ -388,11 +397,11 @@ If the messages above are not sufficient to diagnose the problem then add the - diskid - ) targets in - -- (* We don't have the storage domain UUID, but instead we write -- * in a magic value which the Python code (which can get it) -- * will substitute. -- *) -- let sd_uuid = "@SD_UUID@" in -+ (* The storage domain UUID. *) -+ let sd_uuid = -+ match rhv_storagedomain_uuid with -+ | None -> assert false -+ | Some uuid -> uuid in - - (* The volume and VM UUIDs are made up. *) - let vol_uuids = List.map (fun _ -> uuidgen ()) targets -@@ -406,6 +415,11 @@ If the messages above are not sufficient to diagnose the problem then add the - OVirt in - let ovf = DOM.doc_to_string ovf in - -+ let json_params = -+ match rhv_cluster_uuid with -+ | None -> assert false -+ | Some uuid -> ("rhv_cluster_uuid", JSON.String uuid) :: json_params in -+ - let ovf_file = tmpdir // "vm.ovf" in - with_open_out ovf_file (fun chan -> output_string chan ovf); - if Python_script.run_command createvm_script json_params [ovf_file] <> 0 -diff --git a/v2v/rhv-upload-createvm.py b/v2v/rhv-upload-createvm.py -index 1d0e8c95d..ed57a9b20 100644 ---- a/v2v/rhv-upload-createvm.py -+++ b/v2v/rhv-upload-createvm.py -@@ -65,17 +65,14 @@ connection = sdk.Connection( - - system_service = connection.system_service() - --# Get the storage domain UUID and substitute it into the OVF doc. --sds_service = system_service.storage_domains_service() --sd = sds_service.list(search=("name=%s" % params['output_storage']))[0] --sd_uuid = sd.id -- --ovf = ovf.replace("@SD_UUID@", sd_uuid) -+# Get the cluster. -+cluster = system_service.clusters_service().cluster_service(params['rhv_cluster_uuid']) -+cluster = cluster.get() - - vms_service = system_service.vms_service() - vm = vms_service.add( - types.Vm( -- cluster=types.Cluster(name = params['rhv_cluster']), -+ cluster=cluster, - initialization=types.Initialization( - configuration = types.Configuration( - type = types.ConfigurationType.OVA, -diff --git a/v2v/rhv-upload-precheck.py b/v2v/rhv-upload-precheck.py -index de8a66c05..725a8dc9e 100644 ---- a/v2v/rhv-upload-precheck.py -+++ b/v2v/rhv-upload-precheck.py -@@ -60,18 +60,36 @@ connection = sdk.Connection( - - system_service = connection.system_service() - --# Check whether the specified cluster exists. --clusters_service = system_service.clusters_service() --clusters = clusters_service.list( -- search='name=%s' % params['rhv_cluster'], -+# Check whether there is a datacenter for the specified storage. -+data_centers = system_service.data_centers_service().list( -+ search='storage.name=%s' % params['output_storage'], - case_sensitive=True, - ) -+if len(data_centers) == 0: -+ # The storage domain is not attached to a datacenter -+ # (shouldn't happen, would fail on disk creation). -+ raise RuntimeError("The storage domain ‘%s’ is not attached to a DC" % -+ (params['output_storage'])) -+datacenter = data_centers[0] -+ -+# Get the storage domain. -+storage_domains = connection.follow_link(datacenter.storage_domains) -+storage_domain = [sd for sd in storage_domains if sd.name == params['output_storage']][0] -+ -+# Get the cluster. -+clusters = connection.follow_link(datacenter.clusters) -+clusters = [cluster for cluster in clusters if cluster.name == params['rhv_cluster']] - if len(clusters) == 0: -- raise RuntimeError("The cluster ‘%s’ does not exist" % -- (params['rhv_cluster'])) -+ raise RuntimeError("The cluster ‘%s’ is not part of the DC ‘%s’, " -+ "where the storage domain ‘%s’ is" % -+ (params['rhv_cluster'], datacenter.name, -+ params['output_storage'])) -+cluster = clusters[0] - - # Otherwise everything is OK, print a JSON with the results. - results = { -+ "rhv_storagedomain_uuid": storage_domain.id, -+ "rhv_cluster_uuid": cluster.id, - } - - json.dump(results, sys.stdout) --- -2.18.4 - diff --git a/SOURCES/0035-v2v-o-rhv-upload-tell-whether-a-SD-actually-exists.patch b/SOURCES/0035-v2v-o-rhv-upload-tell-whether-a-SD-actually-exists.patch deleted file mode 100644 index 4cfbbb8..0000000 --- a/SOURCES/0035-v2v-o-rhv-upload-tell-whether-a-SD-actually-exists.patch +++ /dev/null @@ -1,36 +0,0 @@ -From e7b94193f29d7a2715a860deb6db0708eef8c107 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Fri, 13 Sep 2019 12:40:34 +0200 -Subject: [PATCH] v2v: -o rhv-upload: tell whether a SD actually exists - -If there is no DC with the specified storage domain attached to it, it -can mean that the SD does not exist. - -(cherry picked from commit 2b39c27b7f1e72f3a3bf3a616e4576af691beb88) ---- - v2v/rhv-upload-precheck.py | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/v2v/rhv-upload-precheck.py b/v2v/rhv-upload-precheck.py -index 725a8dc9e..1b344ba27 100644 ---- a/v2v/rhv-upload-precheck.py -+++ b/v2v/rhv-upload-precheck.py -@@ -66,6 +66,15 @@ data_centers = system_service.data_centers_service().list( - case_sensitive=True, - ) - if len(data_centers) == 0: -+ storage_domains = system_service.storage_domains_service().list( -+ search='name=%s' % params['output_storage'], -+ case_sensitive=True, -+ ) -+ if len(storage_domains) == 0: -+ # The storage domain does not even exist. -+ raise RuntimeError("The storage domain ‘%s’ does not exist" % -+ (params['output_storage'])) -+ - # The storage domain is not attached to a datacenter - # (shouldn't happen, would fail on disk creation). - raise RuntimeError("The storage domain ‘%s’ is not attached to a DC" % --- -2.18.4 - diff --git a/SOURCES/0036-v2v-add-output-disk_copied-hook.patch b/SOURCES/0036-v2v-add-output-disk_copied-hook.patch deleted file mode 100644 index 5f37ed2..0000000 --- a/SOURCES/0036-v2v-add-output-disk_copied-hook.patch +++ /dev/null @@ -1,76 +0,0 @@ -From fbb0daf1ee29cda6d9117be2430c7d5d66463eca Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Mon, 16 Sep 2019 14:01:14 +0200 -Subject: [PATCH] v2v: add output#disk_copied hook - -Add a simple method in the Output class to do work right after a disk -was successfully copied. - -(cherry picked from commit 74ee936505acf56d01f9b819588e7902a9401e81) ---- - v2v/types.ml | 1 + - v2v/types.mli | 8 ++++++++ - v2v/v2v.ml | 9 ++++++++- - 3 files changed, 17 insertions(+), 1 deletion(-) - -diff --git a/v2v/types.ml b/v2v/types.ml -index 77f879200..714b30014 100644 ---- a/v2v/types.ml -+++ b/v2v/types.ml -@@ -521,6 +521,7 @@ class virtual output = object - method override_output_format (_ : overlay) = (None : string option) - method virtual prepare_targets : source -> (string * overlay) list -> target_buses -> guestcaps -> inspect -> target_firmware -> target_file list - method disk_create = (open_guestfs ())#disk_create -+ method disk_copied (_ : target) (_ : int) (_ : int) = () - method virtual create_metadata : source -> target list -> target_buses -> guestcaps -> inspect -> target_firmware -> unit - method keep_serial_console = true - method install_rhev_apt = false -diff --git a/v2v/types.mli b/v2v/types.mli -index be9406100..f595ab0ef 100644 ---- a/v2v/types.mli -+++ b/v2v/types.mli -@@ -441,6 +441,10 @@ end - │ by running ‘qemu-img convert’. - │ - ▼ -+ output#disk_copied The output mode is notified about the -+ │ successful copy of each disk. -+ │ -+ ▼ - output#create_metadata VM should be created from the metadata - supplied. Also any finalization can - be done here. -@@ -485,6 +489,10 @@ class virtual output : object - (** Called in order to create disks on the target. The method has the - same signature as Guestfs#disk_create. Normally you should {b not} - define this since the default method calls Guestfs#disk_create. *) -+ method disk_copied : target -> int -> int -> unit -+ (** Called after a disk was successfully copied on the target. -+ The second parameter is the index of the copied disk (starting -+ from 0), and the third is the number of disks in total. *) - method virtual create_metadata : source -> target list -> target_buses -> guestcaps -> inspect -> target_firmware -> unit - (** Called after conversion and copying to create metadata and - do any finalization. *) -diff --git a/v2v/v2v.ml b/v2v/v2v.ml -index 277d8f2c7..63e809030 100644 ---- a/v2v/v2v.ml -+++ b/v2v/v2v.ml -@@ -798,7 +798,14 @@ and copy_targets cmdline targets input output = - pc; - if pc < 0. then eprintf " ! ESTIMATE TOO LOW !"; - eprintf "\n%!"; -- ) -+ ); -+ -+ (* Let the output mode know that the disk was copied successfully, -+ * so it can perform any operations without waiting for all the -+ * other disks to be copied (i.e. before the metadata is actually -+ * created). -+ *) -+ output#disk_copied t i nr_disks - ) targets - - (* Update the target_actual_size field in the target structure. *) --- -2.18.4 - diff --git a/SOURCES/0037-v2v-o-rhv-upload-collect-disks-UUIDs-right-after-cop.patch b/SOURCES/0037-v2v-o-rhv-upload-collect-disks-UUIDs-right-after-cop.patch deleted file mode 100644 index 3891ef7..0000000 --- a/SOURCES/0037-v2v-o-rhv-upload-collect-disks-UUIDs-right-after-cop.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 8f8fbe96bfcb6f284590ddd17b960247ec87bde9 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Mon, 16 Sep 2019 14:07:22 +0200 -Subject: [PATCH] v2v: -o rhv-upload: collect disks UUIDs right after copy - -Instead of waiting for the completion of the nbdkit transfers to get the -UUIDs of the disks, use the new #disk_copied hook to do that after each -disk is copied. - -This has almost no behaviour on rhv-upload, except for the --no-copy -mode: -- previously it used to hit the 5 minute timeout while waiting for the - finalization of the first disk -- now it asserts on the different number of collected UUIDs vs the - actual targets; at the moment there is nothing else that can be done, - as this assumption is needed e.g. when creating the OVF file - -(cherry picked from commit 7b93ad6a32f09043bf870202b59bea83d47e0c3a) ---- - v2v/output_rhv_upload.ml | 32 ++++++++++++++++---------------- - 1 file changed, 16 insertions(+), 16 deletions(-) - -diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml -index 19bdfcf05..382ad0d93 100644 ---- a/v2v/output_rhv_upload.ml -+++ b/v2v/output_rhv_upload.ml -@@ -231,6 +231,8 @@ object - val mutable rhv_storagedomain_uuid = None - (* The cluster UUID. *) - val mutable rhv_cluster_uuid = None -+ (* List of disk UUIDs. *) -+ val mutable disks_uuids = [] - - method precheck () = - Python_script.error_unless_python_interpreter_found (); -@@ -379,23 +381,21 @@ If the messages above are not sufficient to diagnose the problem then add the - TargetURI ("json:" ^ JSON.string_of_doc json_params) - ) overlays - -- method create_metadata source targets _ guestcaps inspect target_firmware = -- (* Get the UUIDs of each disk image. These files are written -- * out by the nbdkit plugins on successful finalization of the -+ method disk_copied t i nr_disks = -+ (* Get the UUID of the disk image. This file is written -+ * out by the nbdkit plugin on successful finalization of the - * transfer. - *) -- let nr_disks = List.length targets in -- let image_uuids = -- List.mapi ( -- fun i t -> -- let id = t.target_overlay.ov_source.s_disk_id in -- let diskid_file = diskid_file_of_id id in -- if not (wait_for_file diskid_file finalization_timeout) then -- error (f_"transfer of disk %d/%d failed, see earlier error messages") -- (i+1) nr_disks; -- let diskid = read_whole_file diskid_file in -- diskid -- ) targets in -+ let id = t.target_overlay.ov_source.s_disk_id in -+ let diskid_file = diskid_file_of_id id in -+ if not (wait_for_file diskid_file finalization_timeout) then -+ error (f_"transfer of disk %d/%d failed, see earlier error messages") -+ (i+1) nr_disks; -+ let diskid = read_whole_file diskid_file in -+ disks_uuids <- disks_uuids @ [diskid]; -+ -+ method create_metadata source targets _ guestcaps inspect target_firmware = -+ assert (List.length disks_uuids = List.length targets); - - (* The storage domain UUID. *) - let sd_uuid = -@@ -411,7 +411,7 @@ If the messages above are not sufficient to diagnose the problem then add the - let ovf = - Create_ovf.create_ovf source targets guestcaps inspect - target_firmware output_alloc -- sd_uuid image_uuids vol_uuids vm_uuid -+ sd_uuid disks_uuids vol_uuids vm_uuid - OVirt in - let ovf = DOM.doc_to_string ovf in - --- -2.18.4 - diff --git a/SOURCES/0038-v2v-o-rhv-upload-add-oo-rhv-disk-uuid-option.patch b/SOURCES/0038-v2v-o-rhv-upload-add-oo-rhv-disk-uuid-option.patch deleted file mode 100644 index d2483bd..0000000 --- a/SOURCES/0038-v2v-o-rhv-upload-add-oo-rhv-disk-uuid-option.patch +++ /dev/null @@ -1,201 +0,0 @@ -From 9d7b3e53fd4346bbb2abfb046df224de03f5b92f Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Thu, 19 Sep 2019 12:19:09 +0200 -Subject: [PATCH] v2v: -o rhv-upload: add -oo rhv-disk-uuid option - -This way it is possible to override the UUIDs of the uploaded disks, -instead of letting RHV generate them. - -This can be useful to force certain UUIDs, and to specify the disks in ---no-copy mode (which now can be used). - -(cherry picked from commit 537ba8357e44ca3aa8878a2ac98e9476a570d3f4) ---- - v2v/output_rhv_upload.ml | 43 ++++++++++++++++++++++++++++++++----- - v2v/rhv-upload-plugin.py | 2 ++ - v2v/virt-v2v-output-rhv.pod | 24 +++++++++++++++++++++ - 3 files changed, 64 insertions(+), 5 deletions(-) - -diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml -index 382ad0d93..206657a2b 100644 ---- a/v2v/output_rhv_upload.ml -+++ b/v2v/output_rhv_upload.ml -@@ -32,6 +32,7 @@ type rhv_options = { - rhv_cluster : string option; - rhv_direct : bool; - rhv_verifypeer : bool; -+ rhv_disk_uuids : string list option; - } - - let print_output_options () = -@@ -41,6 +42,11 @@ let print_output_options () = - -oo rhv-cluster=CLUSTERNAME Set RHV cluster name. - -oo rhv-direct[=true|false] Use direct transfer mode (default: false). - -oo rhv-verifypeer[=true|false] Verify server identity (default: false). -+ -+You can override the UUIDs of the disks, instead of using autogenerated UUIDs -+after their uploads (if you do, you must supply one for each disk): -+ -+ -oo rhv-disk-uuid=UUID Disk UUID - ") - - let parse_output_options options = -@@ -48,6 +54,7 @@ let parse_output_options options = - let rhv_cluster = ref None in - let rhv_direct = ref false in - let rhv_verifypeer = ref false in -+ let rhv_disk_uuids = ref None in - - List.iter ( - function -@@ -63,6 +70,8 @@ let parse_output_options options = - | "rhv-direct", v -> rhv_direct := bool_of_string v - | "rhv-verifypeer", "" -> rhv_verifypeer := true - | "rhv-verifypeer", v -> rhv_verifypeer := bool_of_string v -+ | "rhv-disk-uuid", v -> -+ rhv_disk_uuids := Some (v :: (Option.default [] !rhv_disk_uuids)) - | k, _ -> - error (f_"-o rhv-upload: unknown output option ‘-oo %s’") k - ) options; -@@ -75,8 +84,9 @@ let parse_output_options options = - let rhv_cluster = !rhv_cluster in - let rhv_direct = !rhv_direct in - let rhv_verifypeer = !rhv_verifypeer in -+ let rhv_disk_uuids = Option.map List.rev !rhv_disk_uuids in - -- { rhv_cafile; rhv_cluster; rhv_direct; rhv_verifypeer } -+ { rhv_cafile; rhv_cluster; rhv_direct; rhv_verifypeer; rhv_disk_uuids } - - let nbdkit_python_plugin = Config.virt_v2v_nbdkit_python_plugin - let pidfile_timeout = 30 -@@ -270,6 +280,16 @@ object - method install_rhev_apt = true - - method prepare_targets source overlays _ _ _ _ = -+ let uuids = -+ match rhv_options.rhv_disk_uuids with -+ | None -> -+ List.map (fun _ -> None) overlays -+ | Some uuids -> -+ if List.length uuids <> List.length overlays then -+ error (f_"the number of ‘-oo rhv-disk-uuid’ parameters passed on the command line has to match the number of guest disk images (for this guest: %d)") -+ (List.length overlays); -+ List.map (fun uuid -> Some uuid) uuids in -+ - let output_name = source.s_name in - let json_params = - ("output_name", JSON.String output_name) :: json_params in -@@ -284,7 +304,7 @@ object - * target URI to point to the NBD socket. - *) - List.map ( -- fun (target_format, ov) -> -+ fun ((target_format, ov), uuid) -> - let id = ov.ov_source.s_disk_id in - let disk_name = sprintf "%s-%03d" output_name id in - let json_params = -@@ -310,6 +330,12 @@ object - let json_params = - ("diskid_file", JSON.String diskid_file) :: json_params in - -+ let json_params = -+ match uuid with -+ | None -> json_params -+ | Some uuid -> -+ ("rhv_disk_uuid", JSON.String uuid) :: json_params in -+ - (* Write the JSON parameters to a file. *) - let json_param_file = tmpdir // sprintf "params%d.json" id in - with_open_out -@@ -379,7 +405,7 @@ If the messages above are not sufficient to diagnose the problem then add the - "file.export", JSON.String "/"; - ] in - TargetURI ("json:" ^ JSON.string_of_doc json_params) -- ) overlays -+ ) (List.combine overlays uuids) - - method disk_copied t i nr_disks = - (* Get the UUID of the disk image. This file is written -@@ -395,7 +421,14 @@ If the messages above are not sufficient to diagnose the problem then add the - disks_uuids <- disks_uuids @ [diskid]; - - method create_metadata source targets _ guestcaps inspect target_firmware = -- assert (List.length disks_uuids = List.length targets); -+ let image_uuids = -+ match rhv_options.rhv_disk_uuids, disks_uuids with -+ | None, [] -> -+ error (f_"there must be ‘-oo rhv-disk-uuid’ parameters passed on the command line to specify the UUIDs of guest disk images (for this guest: %d)") -+ (List.length targets) -+ | Some uuids, _ -> uuids -+ | None, uuids -> uuids in -+ assert (List.length image_uuids = List.length targets); - - (* The storage domain UUID. *) - let sd_uuid = -@@ -411,7 +444,7 @@ If the messages above are not sufficient to diagnose the problem then add the - let ovf = - Create_ovf.create_ovf source targets guestcaps inspect - target_firmware output_alloc -- sd_uuid disks_uuids vol_uuids vm_uuid -+ sd_uuid image_uuids vol_uuids vm_uuid - OVirt in - let ovf = DOM.doc_to_string ovf in - -diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py -index 4d61a089b..6ec74a5d4 100644 ---- a/v2v/rhv-upload-plugin.py -+++ b/v2v/rhv-upload-plugin.py -@@ -135,6 +135,8 @@ def open(readonly): - disk_format = types.DiskFormat.COW - disk = disks_service.add( - disk = types.Disk( -+ # The ID is optional. -+ id = params.get('rhv_disk_uuid'), - name = params['disk_name'], - description = "Uploaded by virt-v2v", - format = disk_format, -diff --git a/v2v/virt-v2v-output-rhv.pod b/v2v/virt-v2v-output-rhv.pod -index 651f61dae..e840ca78d 100644 ---- a/v2v/virt-v2v-output-rhv.pod -+++ b/v2v/virt-v2v-output-rhv.pod -@@ -9,6 +9,7 @@ virt-v2v-output-rhv - Using virt-v2v to convert guests to oVirt or RHV - [-oo rhv-cafile=FILE] - [-oo rhv-cluster=CLUSTER] - [-oo rhv-direct] -+ [-oo rhv-disk-uuid=UUID ...] - [-oo rhv-verifypeer] - - virt-v2v [-i* options] -o rhv -os [esd:/path|/path] -@@ -104,6 +105,29 @@ F on the oVirt engine. - - Set the RHV Cluster Name. If not given it uses C. - -+=item I<-oo rhv-disk-uuid=>C -+ -+This option can used to manually specify UUIDs for the disks when -+creating the virtual machine. If not specified, the oVirt engine will -+generate random UUIDs for the disks. Please note that: -+ -+=over 4 -+ -+=item * -+ -+you B pass as many I<-oo rhv-disk-uuid=UUID> options as the -+amount of disks in the guest -+ -+=item * -+ -+the specified UUIDs are used as they are, without checking whether -+they are already used by other disks -+ -+=back -+ -+This option is considered advanced, and to be used mostly in -+combination with I<--no-copy>. -+ - =item I<-oo rhv-direct> - - If this option is given then virt-v2v will attempt to directly upload --- -2.18.4 - diff --git a/SOURCES/0039-v2v-o-rhv-upload-make-oo-rhv-cafile-optional.patch b/SOURCES/0039-v2v-o-rhv-upload-make-oo-rhv-cafile-optional.patch deleted file mode 100644 index e58ab1a..0000000 --- a/SOURCES/0039-v2v-o-rhv-upload-make-oo-rhv-cafile-optional.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 971f3c3239a9d6433fa351ceb983db9cce2ab4ac Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Fri, 27 Sep 2019 13:56:42 +0200 -Subject: [PATCH] v2v: -o rhv-upload: make -oo rhv-cafile optional - -It makes little sense to require the oVirt certificate, especially when -the verification of the connection (-oo rhv-verifypeer) is disabled by -default. The only work done with the certificate in that case is -checking that it is a valid certificate file. - -Hence, make -oo rhv-cafile optional, requiring it only when --oo rhv-verifypeer is enabled. - -(cherry picked from commit 0a5eaad7db3c9b9a03fa88102a9e6142c855bfd1) ---- - v2v/output_rhv_upload.ml | 16 +++++++++------- - v2v/virt-v2v-output-rhv.pod | 2 ++ - 2 files changed, 11 insertions(+), 7 deletions(-) - -diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml -index 206657a2b..2c8c18732 100644 ---- a/v2v/output_rhv_upload.ml -+++ b/v2v/output_rhv_upload.ml -@@ -28,7 +28,7 @@ open Types - open Utils - - type rhv_options = { -- rhv_cafile : string; -+ rhv_cafile : string option; - rhv_cluster : string option; - rhv_direct : bool; - rhv_verifypeer : bool; -@@ -76,15 +76,13 @@ let parse_output_options options = - error (f_"-o rhv-upload: unknown output option ‘-oo %s’") k - ) options; - -- let rhv_cafile = -- match !rhv_cafile with -- | Some s -> s -- | None -> -- error (f_"-o rhv-upload: must use ‘-oo rhv-cafile’ to supply the path to the oVirt or RHV user’s ‘ca.pem’ file") in -+ let rhv_cafile = !rhv_cafile in - let rhv_cluster = !rhv_cluster in - let rhv_direct = !rhv_direct in - let rhv_verifypeer = !rhv_verifypeer in - let rhv_disk_uuids = Option.map List.rev !rhv_disk_uuids in -+ if rhv_verifypeer && rhv_cafile = None then -+ error (f_"-o rhv-upload: must use ‘-oo rhv-cafile’ to supply the path to the oVirt or RHV user’s ‘ca.pem’ file"); - - { rhv_cafile; rhv_cluster; rhv_direct; rhv_verifypeer; rhv_disk_uuids } - -@@ -92,6 +90,10 @@ let nbdkit_python_plugin = Config.virt_v2v_nbdkit_python_plugin - let pidfile_timeout = 30 - let finalization_timeout = 5*60 - -+let json_optstring = function -+ | Some s -> JSON.String s -+ | None -> JSON.Null -+ - class output_rhv_upload output_alloc output_conn - output_password output_storage - rhv_options = -@@ -200,7 +202,7 @@ See also the virt-v2v-output-rhv(1) manual.") - "output_sparse", JSON.Bool (match output_alloc with - | Sparse -> true - | Preallocated -> false); -- "rhv_cafile", JSON.String rhv_options.rhv_cafile; -+ "rhv_cafile", json_optstring rhv_options.rhv_cafile; - "rhv_cluster", - JSON.String (Option.default "Default" rhv_options.rhv_cluster); - "rhv_direct", JSON.Bool rhv_options.rhv_direct; -diff --git a/v2v/virt-v2v-output-rhv.pod b/v2v/virt-v2v-output-rhv.pod -index e840ca78d..04a894268 100644 ---- a/v2v/virt-v2v-output-rhv.pod -+++ b/v2v/virt-v2v-output-rhv.pod -@@ -101,6 +101,8 @@ The storage domain. - The F file (Certificate Authority), copied from - F on the oVirt engine. - -+This option must be specified if I<-oo rhv-verifypeer> is enabled. -+ - =item I<-oo rhv-cluster=>C - - Set the RHV Cluster Name. If not given it uses C. --- -2.18.4 - diff --git a/SOURCES/0040-v2v-Fix-default-graphics-driver-for-SUSE-guests.patch b/SOURCES/0040-v2v-Fix-default-graphics-driver-for-SUSE-guests.patch deleted file mode 100644 index 9abbfc0..0000000 --- a/SOURCES/0040-v2v-Fix-default-graphics-driver-for-SUSE-guests.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 14f47e2084688af0d67807f2a5cfbd90759d8e7f Mon Sep 17 00:00:00 2001 -From: Mike Latimer -Date: Mon, 25 Mar 2019 14:38:00 +0000 -Subject: [PATCH] v2v: Fix default graphics driver for SUSE guests. - -See discussion in this upstream thread: -https://www.redhat.com/archives/libguestfs/2019-February/thread.html#00047 - -Thanks: Mike Latimer, Pino Toscano. -(cherry picked from commit 612f170e6062f2ff74643b6096b7e0765b52cfbd) ---- - v2v/convert_linux.ml | 5 +---- - 1 file changed, 1 insertion(+), 4 deletions(-) - -diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml -index b4b2f24c4..f9e811c8d 100644 ---- a/v2v/convert_linux.ml -+++ b/v2v/convert_linux.ml -@@ -104,7 +104,7 @@ let convert (g : G.guestfs) inspect source output rcaps = - - let video = - match rcaps.rcaps_video with -- | None -> get_display_driver () -+ | None -> QXL - | Some video -> video in - - let block_type = -@@ -783,9 +783,6 @@ let convert (g : G.guestfs) inspect source output rcaps = - else - true - -- and get_display_driver () = -- if family = `SUSE_family then Cirrus else QXL -- - and configure_display_driver video = - let video_driver = match video with QXL -> "qxl" | Cirrus -> "cirrus" in - --- -2.18.4 - diff --git a/SOURCES/0041-v2v-windows-Add-a-helper-function-for-installing-Pow.patch b/SOURCES/0041-v2v-windows-Add-a-helper-function-for-installing-Pow.patch deleted file mode 100644 index 07ca8ee..0000000 --- a/SOURCES/0041-v2v-windows-Add-a-helper-function-for-installing-Pow.patch +++ /dev/null @@ -1,73 +0,0 @@ -From d875df20c30868db210396b64f6dcec2cb6d57b4 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 4 Dec 2018 16:09:42 +0000 -Subject: [PATCH] v2v: windows: Add a helper function for installing Powershell - firstboot scripts. - -(cherry picked from commit e1e9b3845e76a4bb406d16b96283ac38677cd91f) ---- - v2v/Makefile.am | 1 + - v2v/windows.ml | 23 +++++++++++++++++++++++ - v2v/windows.mli | 6 ++++++ - 3 files changed, 30 insertions(+) - -diff --git a/v2v/Makefile.am b/v2v/Makefile.am -index 30f040d3e..6568c9a6b 100644 ---- a/v2v/Makefile.am -+++ b/v2v/Makefile.am -@@ -667,6 +667,7 @@ check_PROGRAMS += v2v_unit_tests var_expander_tests - endif - - v2v_unit_tests_BOBJECTS = \ -+ $(top_builddir)/customize/firstboot.cmo \ - types.cmo \ - uefi.cmo \ - utils.cmo \ -diff --git a/v2v/windows.ml b/v2v/windows.ml -index 23d589b00..d83f77b7f 100644 ---- a/v2v/windows.ml -+++ b/v2v/windows.ml -@@ -45,3 +45,26 @@ and check_app { Guestfs.app2_name = name; - publisher =~ rex_avg_tech - - and (=~) str rex = PCRE.matches rex str -+ -+(* Unfortunately Powershell scripts cannot be directly executed -+ * (unless some system config changes are made which for other -+ * reasons we don't want to do) and so we have to run this via -+ * a regular batch file. -+ *) -+let install_firstboot_powershell g { Types.i_windows_systemroot; i_root } -+ filename code = -+ let tempdir = sprintf "%s/Temp" i_windows_systemroot in -+ g#mkdir_p tempdir; -+ let code = String.concat "\r\n" code ^ "\r\n" in -+ g#write (sprintf "%s/%s" tempdir filename) code; -+ -+ (* Powershell interpreter. Should we check this exists? XXX *) -+ let ps_exe = -+ i_windows_systemroot ^ -+ "\\System32\\WindowsPowerShell\\v1.0\\powershell.exe" in -+ -+ (* Windows path to the Powershell script. *) -+ let ps_path = i_windows_systemroot ^ "\\Temp\\" ^ filename in -+ -+ let fb = sprintf "%s -ExecutionPolicy ByPass -file %s" ps_exe ps_path in -+ Firstboot.add_firstboot_script g i_root filename fb -diff --git a/v2v/windows.mli b/v2v/windows.mli -index 016ef2a78..6db7874b0 100644 ---- a/v2v/windows.mli -+++ b/v2v/windows.mli -@@ -21,3 +21,9 @@ - val detect_antivirus : Types.inspect -> bool - (** Return [true] if anti-virus (AV) software was detected in - this Windows guest. *) -+ -+val install_firstboot_powershell : Guestfs.guestfs -> Types.inspect -> -+ string -> string list -> unit -+(** [install_powershell_firstboot g inspect filename code] installs a -+ Powershell script (the lines of code) as a firstboot script in -+ the Windows VM. *) --- -2.18.4 - diff --git a/SOURCES/0042-v2v-Copy-static-IP-address-information-over-for-Wind.patch b/SOURCES/0042-v2v-Copy-static-IP-address-information-over-for-Wind.patch deleted file mode 100644 index c72d967..0000000 --- a/SOURCES/0042-v2v-Copy-static-IP-address-information-over-for-Wind.patch +++ /dev/null @@ -1,423 +0,0 @@ -From 77606e831f8891b65350effb6502d233d74f8cfc Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 4 Dec 2018 16:09:42 +0000 -Subject: [PATCH] v2v: Copy static IP address information over for Windows - guests (RHBZ#1626503). - -For Linux the guest itself remembers the IP address associated with -each MAC address. Thus it doesn't matter if the interface type -changes (ie. to virtio-net), because as long as we preserve the MAC -address the guest will use the same IP address or the same DHCP -configuration. - -However on Windows this association is not maintained by MAC address. -In fact the MAC address isn't saved anywhere in the guest registry. -(It seems instead this is likely done through PCI device type and -address which we don't record at the moment and is almost impossible -to preserve.) When a guest which doesn't use DHCP is migrated, the -guest sees the brand new virtio-net devices and doesn't know what to -do with them, and meanwhile the right static IPs are still associated -with the old and now-defunct interfaces in the registry. - -We cannot collect the required information from within the guest. -However we can collect it outside the tool by some other means -(eg. using VMware Tools APIs) and present this information to virt-v2v -which then writes it into the Windows guest at firstboot time. - -This commit adds the --mac ..:ip:.. sub-option which creates a -Powershell script to set network adapters at firstboot. An option -such as: - - --mac 00:0c:29:e6:3d:9d:ip:192.168.0.89,192.168.0.1,24,192.168.0.254 - -approximately turns into this script: - - # Wait for the netkvm (virtio-net) driver to become active. - $adapters = @() - While (-Not $adapters) { - Start-Sleep -Seconds 5 - $adapters = Get-NetAdapter -Physical | - Where DriverFileName -eq "netkvm.sys" - } - $mac_address = '00-0c-29-e6-3d-9d' - $ifindex = (Get-NetAdapter -Physical | - Where MacAddress -eq $mac_address).ifIndex - if ($ifindex) { - New-NetIPAddress -InterfaceIndex $ifindex - -IPAddress '192.168.0.89' - -DefaultGateway '192.168.0.1' - -PrefixLength 24 - Set-DnsClientServerAddress -InterfaceIndex $ifindex - -ServerAddresses ('192.168.0.254') - } - -Thanks: Brett Thurber for diagnosing the problem and suggesting paths -towards a fix. - -(cherry picked from commit dfd9fac7435cf2f9293961b6cc1fe316af4feebc) ---- - v2v/cmdline.ml | 41 ++++++++++++++++++----- - v2v/cmdline.mli | 1 + - v2v/convert_linux.ml | 2 +- - v2v/convert_windows.ml | 76 +++++++++++++++++++++++++++++++++++++++++- - v2v/modules_list.ml | 2 +- - v2v/modules_list.mli | 2 +- - v2v/types.ml | 8 +++++ - v2v/types.mli | 9 +++++ - v2v/v2v.ml | 7 ++-- - v2v/virt-v2v.pod | 18 ++++++++++ - 10 files changed, 150 insertions(+), 16 deletions(-) - -diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml -index 4d390f249..686631271 100644 ---- a/v2v/cmdline.ml -+++ b/v2v/cmdline.ml -@@ -40,11 +40,12 @@ type cmdline = { - print_estimate : bool; - print_source : bool; - root_choice : root_choice; -+ static_ips : static_ip list; - ks : Tools_utils.key_store; - } - - (* Matches --mac command line parameters. *) --let mac_re = PCRE.compile ~anchored:true "([[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}):(network|bridge):(.*)" -+let mac_re = PCRE.compile ~anchored:true "([[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}):(network|bridge|ip):(.*)" - - let parse_cmdline () = - let compressed = ref false in -@@ -97,6 +98,7 @@ let parse_cmdline () = - in - - let network_map = Networks.create () in -+ let static_ips = ref [] in - let add_network str = - match String.split ":" str with - | "", "" -> -@@ -119,11 +121,30 @@ let parse_cmdline () = - if not (PCRE.matches mac_re str) then - error (f_"cannot parse --mac \"%s\" parameter") str; - let mac = PCRE.sub 1 and out = PCRE.sub 3 in -- let vnet_type = -- match PCRE.sub 2 with -- | "network" -> Network | "bridge" -> Bridge -- | _ -> assert false in -- Networks.add_mac network_map mac vnet_type out -+ match PCRE.sub 2 with -+ | "network" -> -+ Networks.add_mac network_map mac Network out -+ | "bridge" -> -+ Networks.add_mac network_map mac Bridge out -+ | "ip" -> -+ let add if_mac_addr if_ip_address if_default_gateway -+ if_prefix_length if_nameservers = -+ List.push_back static_ips -+ { if_mac_addr; if_ip_address; if_default_gateway; -+ if_prefix_length; if_nameservers } -+ in -+ (match String.nsplit "," out with -+ | [] -> -+ error (f_"invalid --mac ip option") -+ | [ip] -> add mac ip None None [] -+ | [ip; gw] -> add mac ip (Some gw) None [] -+ | ip :: gw :: len :: nameservers -> -+ let len = -+ try int_of_string len with -+ | Failure _ -> error (f_"cannot parse --mac ip prefix length field as an integer: %s") len in -+ add mac ip (Some gw) (Some len) nameservers -+ ); -+ | _ -> assert false - in - - let no_trim_warning _ = -@@ -211,8 +232,8 @@ let parse_cmdline () = - s_"Input transport"; - [ L"in-place" ], Getopt.Set in_place, - s_"Only tune the guest in the input VM"; -- [ L"mac" ], Getopt.String ("mac:network|bridge:out", add_mac), -- s_"Map NIC to network or bridge"; -+ [ L"mac" ], Getopt.String ("mac:network|bridge|ip:out", add_mac), -+ s_"Map NIC to network or bridge or assign static IP"; - [ S 'n'; L"network" ], Getopt.String ("in:out", add_network), - s_"Map network ‘in’ to ‘out’"; - [ L"no-copy" ], Getopt.Clear do_copy, -@@ -335,6 +356,7 @@ read the man page virt-v2v(1). - let print_source = !print_source in - let qemu_boot = !qemu_boot in - let root_choice = !root_choice in -+ let static_ips = !static_ips in - - (* No arguments and machine-readable mode? Print out some facts - * about what this binary supports. -@@ -351,6 +373,7 @@ read the man page virt-v2v(1). - pr "in-place\n"; - pr "io/oo\n"; - pr "mac-option\n"; -+ pr "mac-ip-option\n"; - List.iter (pr "input:%s\n") (Modules_list.input_modules ()); - List.iter (pr "output:%s\n") (Modules_list.output_modules ()); - List.iter (pr "convert:%s\n") (Modules_list.convert_modules ()); -@@ -685,7 +708,7 @@ read the man page virt-v2v(1). - { - compressed; debug_overlays; do_copy; in_place; network_map; - output_alloc; output_format; output_name; -- print_estimate; print_source; root_choice; -+ print_estimate; print_source; root_choice; static_ips; - ks = opthandle.ks; - }, - input, output -diff --git a/v2v/cmdline.mli b/v2v/cmdline.mli -index 78601e191..a009e9888 100644 ---- a/v2v/cmdline.mli -+++ b/v2v/cmdline.mli -@@ -30,6 +30,7 @@ type cmdline = { - print_estimate : bool; - print_source : bool; - root_choice : Types.root_choice; -+ static_ips : Types.static_ip list; - ks : Tools_utils.key_store; - } - -diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml -index f9e811c8d..1ada36115 100644 ---- a/v2v/convert_linux.ml -+++ b/v2v/convert_linux.ml -@@ -34,7 +34,7 @@ open Linux_kernels - module G = Guestfs - - (* The conversion function. *) --let convert (g : G.guestfs) inspect source output rcaps = -+let convert (g : G.guestfs) inspect source output rcaps _ = - (*----------------------------------------------------------------------*) - (* Inspect the guest first. We already did some basic inspection in - * the common v2v.ml code, but that has to deal with generic guests -diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml -index 1db3c0ea6..75e609d61 100644 ---- a/v2v/convert_windows.ml -+++ b/v2v/convert_windows.ml -@@ -38,7 +38,7 @@ module G = Guestfs - * time the Windows VM is booted on KVM. - *) - --let convert (g : G.guestfs) inspect source output rcaps = -+let convert (g : G.guestfs) inspect source output rcaps static_ips = - (*----------------------------------------------------------------------*) - (* Inspect the Windows guest. *) - -@@ -228,6 +228,8 @@ let convert (g : G.guestfs) inspect source output rcaps = - Registry.with_hive_write g inspect.i_windows_software_hive - update_software_hive; - -+ configure_network_interfaces net_driver; -+ - fix_ntfs_heads (); - - fix_win_esp (); -@@ -603,6 +605,78 @@ if errorlevel 3010 exit /b 0 - | None -> - warning (f_"could not find registry key HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion") - -+ and configure_network_interfaces net_driver = -+ (* If we were asked to force network interfaces to have particular -+ * static IP addresses then it is done here by installing a -+ * Powershell script which runs at boot. -+ *) -+ if static_ips <> [] then ( -+ let psh_filename = "v2vnetcf.ps1" in -+ let psh = ref [] in -+ let add = List.push_back psh in -+ -+ add "# Uncomment this line for lots of debug output."; -+ add "# Set-PSDebug -Trace 1"; -+ add ""; -+ -+ (* If virtio-net was added to the registry, we must wait for -+ * it to be installed at runtime. -+ *) -+ if net_driver = Virtio_net then ( -+ add "# Wait for the netkvm (virtio-net) driver to become active."; -+ add "$adapters = @()"; -+ add "While (-Not $adapters) {"; -+ add " Start-Sleep -Seconds 5"; -+ add " $adapters = Get-NetAdapter -Physical | Where DriverFileName -eq \"netkvm.sys\""; -+ add " Write-Host \"adapters = '$adapters'\""; -+ add "}"; -+ add "" -+ ); -+ -+ List.iter ( -+ fun { if_mac_addr; if_ip_address; if_default_gateway; -+ if_prefix_length; if_nameservers } -> -+ add (sprintf "$mac_address = '%s'" -+ (String.replace if_mac_addr ":" "-")); -+ add "$ifindex = (Get-NetAdapter -Physical | Where MacAddress -eq $mac_address).ifIndex"; -+ add "if ($ifindex) {"; -+ -+ add " Write-Host \"setting IP address of adapter at $ifindex\""; -+ -+ (* New-NetIPAddress command *) -+ let args = ref [] in -+ List.push_back args "-InterfaceIndex"; -+ List.push_back args "$ifindex"; -+ List.push_back args "-IPAddress"; -+ List.push_back args (sprintf "'%s'" if_ip_address); -+ (match if_default_gateway with -+ | None -> () -+ | Some gw -> -+ List.push_back args "-DefaultGateway"; -+ List.push_back args (sprintf "'%s'" gw) -+ ); -+ (match if_prefix_length with -+ | None -> () -+ | Some len -> -+ List.push_back args "-PrefixLength"; -+ List.push_back args (string_of_int len) -+ ); -+ let cmd1 = "New-NetIPAddress " ^ String.concat " " !args in -+ add (" " ^ cmd1); -+ -+ (* Set-DnsClientServerAddress command *) -+ if if_nameservers <> [] then ( -+ add (sprintf " Set-DnsClientServerAddress -InterfaceIndex $ifindex -ServerAddresses (%s)" -+ (String.concat "," (List.map (sprintf "'%s'") if_nameservers))) -+ ); -+ add "}"; -+ add "" -+ ) static_ips; -+ -+ (* Install the Powershell script to run at firstboot. *) -+ Windows.install_firstboot_powershell g inspect psh_filename !psh -+ ) (* static_ips <> [] *) -+ - and fix_ntfs_heads () = - (* NTFS hardcodes the number of heads on the drive which created - it in the filesystem header. Modern versions of Windows -diff --git a/v2v/modules_list.ml b/v2v/modules_list.ml -index a0a74aaf2..76b3def5d 100644 ---- a/v2v/modules_list.ml -+++ b/v2v/modules_list.ml -@@ -38,7 +38,7 @@ type inspection_fn = Types.inspect -> bool - - type conversion_fn = - Guestfs.guestfs -> Types.inspect -> Types.source -> Types.output_settings -> -- Types.requested_guestcaps -> Types.guestcaps -+ Types.requested_guestcaps -> Types.static_ip list -> Types.guestcaps - - let convert_modules = ref [] - -diff --git a/v2v/modules_list.mli b/v2v/modules_list.mli -index 3e80d3e23..ad2024755 100644 ---- a/v2v/modules_list.mli -+++ b/v2v/modules_list.mli -@@ -34,7 +34,7 @@ type inspection_fn = Types.inspect -> bool - - type conversion_fn = - Guestfs.guestfs -> Types.inspect -> Types.source -> Types.output_settings -> -- Types.requested_guestcaps -> Types.guestcaps -+ Types.requested_guestcaps -> Types.static_ip list -> Types.guestcaps - - val register_convert_module : inspection_fn -> string -> conversion_fn -> unit - (** [register_convert_module inspect_fn name fn] registers a -diff --git a/v2v/types.ml b/v2v/types.ml -index 714b30014..4ba6117fd 100644 ---- a/v2v/types.ml -+++ b/v2v/types.ml -@@ -506,6 +506,14 @@ type root_choice = AskRoot | SingleRoot | FirstRoot | RootDev of string - - type output_allocation = Sparse | Preallocated - -+type static_ip = { -+ if_mac_addr : string; -+ if_ip_address : string; -+ if_default_gateway : string option; -+ if_prefix_length : int option; -+ if_nameservers : string list; -+} -+ - class virtual input = object - method precheck () = () - method virtual as_options : string -diff --git a/v2v/types.mli b/v2v/types.mli -index f595ab0ef..528d77965 100644 ---- a/v2v/types.mli -+++ b/v2v/types.mli -@@ -361,6 +361,15 @@ type root_choice = AskRoot | SingleRoot | FirstRoot | RootDev of string - type output_allocation = Sparse | Preallocated - (** Type of [-oa] (output allocation) option. *) - -+type static_ip = { -+ if_mac_addr : string; -+ if_ip_address : string; -+ if_default_gateway : string option; -+ if_prefix_length : int option; -+ if_nameservers : string list; -+} -+(** [--mac ..:ip:..] option. *) -+ - (** {2 Input object} - - This is subclassed for the various input [-i] options. -diff --git a/v2v/v2v.ml b/v2v/v2v.ml -index 63e809030..d7a868659 100644 ---- a/v2v/v2v.ml -+++ b/v2v/v2v.ml -@@ -133,7 +133,7 @@ let rec main () = - | In_place -> - rcaps_from_source source in - -- do_convert g inspect source output rcaps in -+ do_convert g inspect source output rcaps cmdline.static_ips in - - g#umount_all (); - -@@ -556,7 +556,7 @@ and estimate_target_size mpstats overlays = - ) - - (* Conversion. *) --and do_convert g inspect source output rcaps = -+and do_convert g inspect source output rcaps interfaces = - (match inspect.i_product_name with - | "unknown" -> - message (f_"Converting the guest to run on KVM") -@@ -572,7 +572,8 @@ and do_convert g inspect source output rcaps = - debug "picked conversion module %s" conversion_name; - debug "requested caps: %s" (string_of_requested_guestcaps rcaps); - let guestcaps = -- convert g inspect source (output :> Types.output_settings) rcaps in -+ convert g inspect source (output :> Types.output_settings) rcaps -+ interfaces in - debug "%s" (string_of_guestcaps guestcaps); - - (* Did we manage to install virtio drivers? *) -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index 9a555c3be..0642d158f 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -368,6 +368,24 @@ Map source NIC MAC address to a network or bridge. - - See L below. - -+=item B<--mac> aa:bb:cc:dd:ee:ffB<:ip:>ipaddr[,gw[,len[,ns,ns,...]]] -+ -+Force a particular interface (controlled by its MAC address) to have a -+static IP address after boot. -+ -+The fields in the parameter are: C is the IP address. C -+is the optional gateway IP address. C is the subnet mask length -+(an integer). The final parameters are zero or more nameserver IP -+addresses. -+ -+This option can be supplied zero or more times. -+ -+You only need to use this option for certain broken guests such as -+Windows which are unable to preserve MAC to static IP address mappings -+automatically. You don't need to use it if Windows is using DHCP. It -+is currently ignored for Linux guests since they do not have this -+problem. -+ - =item B<--machine-readable> - - =item B<--machine-readable>=format --- -2.18.4 - diff --git a/SOURCES/0043-New-API-luks_uuid.patch b/SOURCES/0043-New-API-luks_uuid.patch deleted file mode 100644 index 1d2b80d..0000000 --- a/SOURCES/0043-New-API-luks_uuid.patch +++ /dev/null @@ -1,87 +0,0 @@ -From c31eaba4d6b36d90cfd835a4750e50f6a5256b73 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Fri, 29 Nov 2019 11:48:59 +0100 -Subject: [PATCH] New API: luks_uuid - -Return the UUID of a LUKS device. - -(cherry picked from commit 206ce8bbf1bc3332dc019e553d17d6a36f74b725) ---- - daemon/luks.c | 25 +++++++++++++++++++++++++ - generator/actions_core.ml | 8 ++++++++ - generator/proc_nr.ml | 1 + - lib/MAX_PROC_NR | 2 +- - 4 files changed, 35 insertions(+), 1 deletion(-) - -diff --git a/daemon/luks.c b/daemon/luks.c -index 5c48a91eb..d631cb100 100644 ---- a/daemon/luks.c -+++ b/daemon/luks.c -@@ -292,3 +292,28 @@ do_luks_kill_slot (const char *device, const char *key, int keyslot) - - return 0; - } -+ -+char * -+do_luks_uuid (const char *device) -+{ -+ const char *argv[MAX_ARGS]; -+ size_t i = 0; -+ -+ ADD_ARG (argv, i, "cryptsetup"); -+ ADD_ARG (argv, i, "luksUUID"); -+ ADD_ARG (argv, i, device); -+ ADD_ARG (argv, i, NULL); -+ -+ char *out = NULL; -+ CLEANUP_FREE char *err = NULL; -+ int r = commandv (&out, &err, (const char * const *) argv); -+ -+ if (r == -1) { -+ reply_with_error ("%s", err); -+ return NULL; -+ } -+ -+ trim (out); -+ -+ return out; -+} -diff --git a/generator/actions_core.ml b/generator/actions_core.ml -index 7b6568b90..deda483a9 100644 ---- a/generator/actions_core.ml -+++ b/generator/actions_core.ml -@@ -9728,4 +9728,12 @@ it is useful when you have added a new device or deleted an - existing device (such as when the C API - is used)." }; - -+ { defaults with -+ name = "luks_uuid"; added = (1, 41, 9); -+ style = RString (RPlainString, "uuid"), [String (Device, "device")], []; -+ optional = Some "luks"; -+ shortdesc = "get the UUID of a LUKS device"; -+ longdesc = "\ -+This returns the UUID of the LUKS device C." }; -+ - ] -diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml -index efa8c5d21..11a557076 100644 ---- a/generator/proc_nr.ml -+++ b/generator/proc_nr.ml -@@ -514,6 +514,7 @@ let proc_nr = [ - 504, "part_get_gpt_attributes"; - 505, "f2fs_expand"; - 506, "lvm_scan"; -+507, "luks_uuid"; - ] - - (* End of list. If adding a new entry, add it at the end of the list -diff --git a/lib/MAX_PROC_NR b/lib/MAX_PROC_NR -index 80e3e6eab..055b6671a 100644 ---- a/lib/MAX_PROC_NR -+++ b/lib/MAX_PROC_NR -@@ -1 +1 @@ --506 -+507 --- -2.18.4 - diff --git a/SOURCES/0044-options-Fix-segfault-when-multiple-key-parameters-gi.patch b/SOURCES/0044-options-Fix-segfault-when-multiple-key-parameters-gi.patch deleted file mode 100644 index 1d44585..0000000 --- a/SOURCES/0044-options-Fix-segfault-when-multiple-key-parameters-gi.patch +++ /dev/null @@ -1,47 +0,0 @@ -From a7fe83c678520aca2289eab2af6d8aebdf225bb7 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 12 Nov 2019 18:15:44 +0000 -Subject: [PATCH] options: Fix segfault when multiple --key parameters given. - -Easily reproducible using: - - $ guestfish --key dev1:key:key1 --key dev2:key:key2 - -causing this stack trace (or others depending on where the memory -corruption was caught): - - Program received signal SIGABRT, Aborted. - 0x00007ffff7905625 in raise () from /lib64/libc.so.6 - (gdb) bt - #0 0x00007ffff7905625 in raise () from /lib64/libc.so.6 - #1 0x00007ffff78ee8d9 in abort () from /lib64/libc.so.6 - #2 0x00007ffff79494af in __libc_message () from /lib64/libc.so.6 - #3 0x00007ffff7950a6c in malloc_printerr () from /lib64/libc.so.6 - #4 0x00007ffff79528d0 in _int_free () from /lib64/libc.so.6 - #5 0x00005555555bdd6e in free_key_store () - #6 0x0000555555589027 in main () - (gdb) quit - -(cherry picked from commit 8c42f772614b44a8cb974afa904ec9f518431ab2 -in libguestfs-common) ---- - common/options/keys.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/common/options/keys.c b/common/options/keys.c -index 7f689866b..f783066ff 100644 ---- a/common/options/keys.c -+++ b/common/options/keys.c -@@ -216,7 +216,8 @@ key_store_import_key (struct key_store *ks, const struct key_store_key *key) - } - assert (ks != NULL); - -- new_keys = realloc (ks->keys, sizeof (*ks->keys) + 1); -+ new_keys = realloc (ks->keys, -+ (ks->nr_keys + 1) * sizeof (struct key_store_key)); - if (!new_keys) - error (EXIT_FAILURE, errno, "realloc"); - --- -2.18.4 - diff --git a/SOURCES/0045-options-Simplify-selector-parsing-for-key-options.patch b/SOURCES/0045-options-Simplify-selector-parsing-for-key-options.patch deleted file mode 100644 index d449c1a..0000000 --- a/SOURCES/0045-options-Simplify-selector-parsing-for-key-options.patch +++ /dev/null @@ -1,85 +0,0 @@ -From c74aa1326061723bd87e599699096d1085472772 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 26 Nov 2019 12:12:45 +0000 -Subject: [PATCH] options: Simplify selector parsing for --key options. - -Refactor this code to use guestfs_int_split_string function which -slightly simplifies it. This should have no effect. - -(cherry picked from commit 530d0beef74d48617717463a5b585f21e2ed62be -in libguestfs-common) ---- - common/options/keys.c | 35 ++++++++++++++--------------------- - 1 file changed, 14 insertions(+), 21 deletions(-) - -diff --git a/common/options/keys.c b/common/options/keys.c -index f783066ff..74b549731 100644 ---- a/common/options/keys.c -+++ b/common/options/keys.c -@@ -153,49 +153,42 @@ get_key (struct key_store *ks, const char *device) - } - - struct key_store * --key_store_add_from_selector (struct key_store *ks, const char *selector_orig) -+key_store_add_from_selector (struct key_store *ks, const char *selector) - { -- CLEANUP_FREE char *selector = strdup (selector_orig); -- const char *elem; -- char *saveptr; -+ CLEANUP_FREE_STRING_LIST char **fields = -+ guestfs_int_split_string (':', selector); - struct key_store_key key; - -- if (!selector) -- error (EXIT_FAILURE, errno, "strdup"); -+ if (!fields) -+ error (EXIT_FAILURE, errno, "guestfs_int_split_string"); - -- /* 1: device */ -- elem = strtok_r (selector, ":", &saveptr); -- if (!elem) { -+ if (guestfs_int_count_strings (fields) != 3) { - invalid_selector: -- error (EXIT_FAILURE, 0, "invalid selector for --key: %s", selector_orig); -+ error (EXIT_FAILURE, 0, "invalid selector for --key: %s", selector); - } -- key.device = strdup (elem); -+ -+ /* 1: device */ -+ key.device = strdup (fields[0]); - if (!key.device) - error (EXIT_FAILURE, errno, "strdup"); - - /* 2: key type */ -- elem = strtok_r (NULL, ":", &saveptr); -- if (!elem) -- goto invalid_selector; -- else if (STREQ (elem, "key")) -+ if (STREQ (fields[1], "key")) - key.type = key_string; -- else if (STREQ (elem, "file")) -+ else if (STREQ (fields[1], "file")) - key.type = key_file; - else - goto invalid_selector; - - /* 3: actual key */ -- elem = strtok_r (NULL, ":", &saveptr); -- if (!elem) -- goto invalid_selector; - switch (key.type) { - case key_string: -- key.string.s = strdup (elem); -+ key.string.s = strdup (fields[2]); - if (!key.string.s) - error (EXIT_FAILURE, errno, "strdup"); - break; - case key_file: -- key.file.name = strdup (elem); -+ key.file.name = strdup (fields[2]); - if (!key.file.name) - error (EXIT_FAILURE, errno, "strdup"); - break; --- -2.18.4 - diff --git a/SOURCES/0046-options-Allow-multiple-key-parameters.patch b/SOURCES/0046-options-Allow-multiple-key-parameters.patch deleted file mode 100644 index 78900c7..0000000 --- a/SOURCES/0046-options-Allow-multiple-key-parameters.patch +++ /dev/null @@ -1,180 +0,0 @@ -From 0267ad921c3be8a780342b052264666cef2cc1b1 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 12 Nov 2019 17:50:17 +0000 -Subject: [PATCH] options: Allow multiple --key parameters. - -This allows multiple --key parameters on the command line to match a -single device. For example: - - tool --key /dev/sda1:key:trykey1 --key /dev/sda1:key:trykey2 - -would try "trykey1" and "trykey2" against /dev/sda1. - -(cherry picked from commit c10c8baedb88e7c2988a01b70fc5f81fa8e4885c -in libguestfs-common) ---- - common/options/decrypt.c | 35 ++++++++++++++++++++++++------- - common/options/keys.c | 45 +++++++++++++++++++++++++++++++--------- - common/options/options.h | 6 ++++-- - 3 files changed, 66 insertions(+), 20 deletions(-) - -diff --git a/common/options/decrypt.c b/common/options/decrypt.c -index 234163d8c..3511d9fe9 100644 ---- a/common/options/decrypt.c -+++ b/common/options/decrypt.c -@@ -26,6 +26,9 @@ - #include - #include - #include -+#include -+#include -+#include - - #include "c-ctype.h" - -@@ -74,21 +77,37 @@ inspect_do_decrypt (guestfs_h *g, struct key_store *ks) - if (partitions == NULL) - exit (EXIT_FAILURE); - -- int need_rescan = 0; -- size_t i; -+ int need_rescan = 0, r; -+ size_t i, j; -+ - for (i = 0; partitions[i] != NULL; ++i) { - CLEANUP_FREE char *type = guestfs_vfs_type (g, partitions[i]); - if (type && STREQ (type, "crypto_LUKS")) { - char mapname[32]; - make_mapname (partitions[i], mapname, sizeof mapname); - -- CLEANUP_FREE char *key = get_key (ks, partitions[i]); -- /* XXX Should we call guestfs_luks_open_ro if readonly flag -- * is set? This might break 'mount_ro'. -- */ -- if (guestfs_luks_open (g, partitions[i], key, mapname) == -1) -- exit (EXIT_FAILURE); -+ CLEANUP_FREE_STRING_LIST char **keys = get_keys (ks, partitions[i]); -+ assert (guestfs_int_count_strings (keys) > 0); - -+ /* Try each key in turn. */ -+ for (j = 0; keys[j] != NULL; ++j) { -+ /* XXX Should we call guestfs_luks_open_ro if readonly flag -+ * is set? This might break 'mount_ro'. -+ */ -+ guestfs_push_error_handler (g, NULL, NULL); -+ r = guestfs_luks_open (g, partitions[i], keys[j], mapname); -+ guestfs_pop_error_handler (g); -+ if (r == 0) -+ goto opened; -+ } -+ error (EXIT_FAILURE, 0, -+ _("could not find key to open LUKS encrypted %s.\n\n" -+ "Try using --key on the command line.\n\n" -+ "Original error: %s (%d)"), -+ partitions[i], guestfs_last_error (g), -+ guestfs_last_errno (g)); -+ -+ opened: - need_rescan = 1; - } - } -diff --git a/common/options/keys.c b/common/options/keys.c -index 74b549731..782bdb67f 100644 ---- a/common/options/keys.c -+++ b/common/options/keys.c -@@ -121,15 +121,32 @@ read_first_line_from_file (const char *filename) - return ret; - } - --char * --get_key (struct key_store *ks, const char *device) -+/* Return the key(s) matching this particular device from the -+ * keystore. There may be multiple. If none are read from the -+ * keystore, ask the user. -+ */ -+char ** -+get_keys (struct key_store *ks, const char *device) - { -- size_t i; -+ size_t i, j, len; -+ char **r; -+ char *s; -+ -+ /* We know the returned list must have at least one element and not -+ * more than ks->nr_keys. -+ */ -+ len = 1; -+ if (ks) -+ len = MIN (1, ks->nr_keys); -+ r = calloc (len+1, sizeof (char *)); -+ if (r == NULL) -+ error (EXIT_FAILURE, errno, "calloc"); -+ -+ j = 0; - - if (ks) { - for (i = 0; i < ks->nr_keys; ++i) { - struct key_store_key *key = &ks->keys[i]; -- char *s; - - if (STRNEQ (key->device, device)) - continue; -@@ -139,17 +156,25 @@ get_key (struct key_store *ks, const char *device) - s = strdup (key->string.s); - if (!s) - error (EXIT_FAILURE, errno, "strdup"); -- return s; -+ r[j++] = s; -+ break; - case key_file: -- return read_first_line_from_file (key->file.name); -+ s = read_first_line_from_file (key->file.name); -+ r[j++] = s; -+ break; - } -- -- /* Key not found in the key store, ask the user for it. */ -- break; - } - } - -- return read_key (device); -+ if (j == 0) { -+ /* Key not found in the key store, ask the user for it. */ -+ s = read_key (device); -+ if (!s) -+ error (EXIT_FAILURE, 0, _("could not read key from user")); -+ r[0] = s; -+ } -+ -+ return r; - } - - struct key_store * -diff --git a/common/options/options.h b/common/options/options.h -index 6fadf1e76..510e8a8a9 100644 ---- a/common/options/options.h -+++ b/common/options/options.h -@@ -104,7 +104,9 @@ struct mp { - - /* A key in the key store. */ - struct key_store_key { -- /* The device this key refers to. */ -+ /* The device this key refers to. There may be multiple matching -+ * devices in the list. -+ */ - char *device; - - enum { -@@ -146,7 +148,7 @@ extern void print_inspect_prompt (void); - - /* in key.c */ - extern char *read_key (const char *param); --extern char *get_key (struct key_store *ks, const char *device); -+extern char **get_keys (struct key_store *ks, const char *device); - extern struct key_store *key_store_add_from_selector (struct key_store *ks, const char *selector); - extern struct key_store *key_store_import_key (struct key_store *ks, const struct key_store_key *key); - extern void free_key_store (struct key_store *ks); --- -2.18.4 - diff --git a/SOURCES/0047-options-rename-key.device-as-key.id.patch b/SOURCES/0047-options-rename-key.device-as-key.id.patch deleted file mode 100644 index e67cbf2..0000000 --- a/SOURCES/0047-options-rename-key.device-as-key.id.patch +++ /dev/null @@ -1,437 +0,0 @@ -From dd28c27df30c5a41bec97181a297d4df95aad0ab Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Fri, 29 Nov 2019 12:06:20 +0100 -Subject: [PATCH] options: rename key.device as key.id - -In the future it will be also something else other than the device name. - -(cherry picked from commit c863ee5e1df5e1eca7ad6821bd2db3796277a6bd -in libguestfs-common) - -PT: the documentation was amended manually. ---- - cat/virt-cat.pod | 7 ++++--- - cat/virt-log.pod | 7 ++++--- - cat/virt-ls.pod | 7 ++++--- - cat/virt-tail.pod | 7 ++++--- - common/mltools/tools_utils-c.c | 4 ++-- - common/options/keys.c | 8 ++++---- - common/options/options.h | 8 +++++--- - customize/virt-customize.pod | 7 ++++--- - diff/virt-diff.pod | 7 ++++--- - edit/virt-edit.pod | 7 ++++--- - fish/guestfish.pod | 7 ++++--- - fuse/guestmount.pod | 7 ++++--- - get-kernel/virt-get-kernel.pod | 7 ++++--- - inspector/virt-inspector.pod | 7 ++++--- - sparsify/virt-sparsify.pod | 7 ++++--- - sysprep/virt-sysprep.pod | 7 ++++--- - v2v/virt-v2v.pod | 7 ++++--- - 17 files changed, 67 insertions(+), 51 deletions(-) - -diff --git a/cat/virt-cat.pod b/cat/virt-cat.pod -index 745d4a4b6..b0301d636 100644 ---- a/cat/virt-cat.pod -+++ b/cat/virt-cat.pod -@@ -124,15 +124,16 @@ security problem with malicious guests (CVE-2010-3851). - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C can be in one of the following formats: -+the inspection. C must be the libguestfs device name of the LUKS -+device. - - =over 4 - --=item B<--key> C:key:KEY_STRING -+=item B<--key> C:key:KEY_STRING - - Use the specified C as passphrase. - --=item B<--key> C:file:FILENAME -+=item B<--key> C:file:FILENAME - - Read the passphrase from F. - -diff --git a/cat/virt-log.pod b/cat/virt-log.pod -index 8de000c5f..0d447b3b5 100644 ---- a/cat/virt-log.pod -+++ b/cat/virt-log.pod -@@ -108,15 +108,16 @@ security problem with malicious guests (CVE-2010-3851). - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C can be in one of the following formats: -+the inspection. C must be the libguestfs device name of the LUKS -+device. - - =over 4 - --=item B<--key> C:key:KEY_STRING -+=item B<--key> C:key:KEY_STRING - - Use the specified C as passphrase. - --=item B<--key> C:file:FILENAME -+=item B<--key> C:file:FILENAME - - Read the passphrase from F. - -diff --git a/cat/virt-ls.pod b/cat/virt-ls.pod -index 8d6a9fe37..de02a473d 100644 ---- a/cat/virt-ls.pod -+++ b/cat/virt-ls.pod -@@ -355,15 +355,16 @@ L above. - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C can be in one of the following formats: -+the inspection. C must be the libguestfs device name of the LUKS -+device. - - =over 4 - --=item B<--key> C:key:KEY_STRING -+=item B<--key> C:key:KEY_STRING - - Use the specified C as passphrase. - --=item B<--key> C:file:FILENAME -+=item B<--key> C:file:FILENAME - - Read the passphrase from F. - -diff --git a/cat/virt-tail.pod b/cat/virt-tail.pod -index cf8700d1a..f00384f5d 100644 ---- a/cat/virt-tail.pod -+++ b/cat/virt-tail.pod -@@ -126,15 +126,16 @@ security problem with malicious guests (CVE-2010-3851). - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C can be in one of the following formats: -+the inspection. C must be the libguestfs device name of the LUKS -+device. - - =over 4 - --=item B<--key> C:key:KEY_STRING -+=item B<--key> C:key:KEY_STRING - - Use the specified C as passphrase. - --=item B<--key> C:file:FILENAME -+=item B<--key> C:file:FILENAME - - Read the passphrase from F. - -diff --git a/common/mltools/tools_utils-c.c b/common/mltools/tools_utils-c.c -index 3b80091c0..6c43b8d74 100644 ---- a/common/mltools/tools_utils-c.c -+++ b/common/mltools/tools_utils-c.c -@@ -57,8 +57,8 @@ guestfs_int_mllib_inspect_decrypt (value gv, value gpv, value keysv) - struct key_store_key key; - - elemv = Field (keysv, 0); -- key.device = strdup (String_val (Field (elemv, 0))); -- if (!key.device) -+ key.id = strdup (String_val (Field (elemv, 0))); -+ if (!key.id) - caml_raise_out_of_memory (); - - v = Field (elemv, 1); -diff --git a/common/options/keys.c b/common/options/keys.c -index 782bdb67f..7c391acde 100644 ---- a/common/options/keys.c -+++ b/common/options/keys.c -@@ -148,7 +148,7 @@ get_keys (struct key_store *ks, const char *device) - for (i = 0; i < ks->nr_keys; ++i) { - struct key_store_key *key = &ks->keys[i]; - -- if (STRNEQ (key->device, device)) -+ if (STRNEQ (key->id, device)) - continue; - - switch (key->type) { -@@ -193,8 +193,8 @@ key_store_add_from_selector (struct key_store *ks, const char *selector) - } - - /* 1: device */ -- key.device = strdup (fields[0]); -- if (!key.device) -+ key.id = strdup (fields[0]); -+ if (!key.id) - error (EXIT_FAILURE, errno, "strdup"); - - /* 2: key type */ -@@ -265,6 +265,6 @@ free_key_store (struct key_store *ks) - free (key->file.name); - break; - } -- free (key->device); -+ free (key->id); - } - } -diff --git a/common/options/options.h b/common/options/options.h -index 510e8a8a9..b83a92b06 100644 ---- a/common/options/options.h -+++ b/common/options/options.h -@@ -104,10 +104,12 @@ struct mp { - - /* A key in the key store. */ - struct key_store_key { -- /* The device this key refers to. There may be multiple matching -- * devices in the list. -+ /* An ID for the device this key refers to. It must be the libguestfs -+ * device name. -+ * -+ * There may be multiple matching devices in the list. - */ -- char *device; -+ char *id; - - enum { - key_string, /* key specified as string */ -diff --git a/customize/virt-customize.pod b/customize/virt-customize.pod -index d1b568040..491606591 100644 ---- a/customize/virt-customize.pod -+++ b/customize/virt-customize.pod -@@ -141,15 +141,16 @@ security problem with malicious guests (CVE-2010-3851). - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C can be in one of the following formats: -+the inspection. C must be the libguestfs device name of the LUKS -+device. - - =over 4 - --=item B<--key> C:key:KEY_STRING -+=item B<--key> C:key:KEY_STRING - - Use the specified C as passphrase. - --=item B<--key> C:file:FILENAME -+=item B<--key> C:file:FILENAME - - Read the passphrase from F. - -diff --git a/diff/virt-diff.pod b/diff/virt-diff.pod -index 36ee10ced..22658072d 100644 ---- a/diff/virt-diff.pod -+++ b/diff/virt-diff.pod -@@ -169,15 +169,16 @@ Display file sizes in human-readable format. - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C can be in one of the following formats: -+the inspection. C must be the libguestfs device name of the LUKS -+device. - - =over 4 - --=item B<--key> C:key:KEY_STRING -+=item B<--key> C:key:KEY_STRING - - Use the specified C as passphrase. - --=item B<--key> C:file:FILENAME -+=item B<--key> C:file:FILENAME - - Read the passphrase from F. - -diff --git a/edit/virt-edit.pod b/edit/virt-edit.pod -index 3cb3ce6da..5a63cd05f 100644 ---- a/edit/virt-edit.pod -+++ b/edit/virt-edit.pod -@@ -156,15 +156,16 @@ security problem with malicious guests (CVE-2010-3851). - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C can be in one of the following formats: -+the inspection. C must be the libguestfs device name of the LUKS -+device. - - =over 4 - --=item B<--key> C:key:KEY_STRING -+=item B<--key> C:key:KEY_STRING - - Use the specified C as passphrase. - --=item B<--key> C:file:FILENAME -+=item B<--key> C:file:FILENAME - - Read the passphrase from F. - -diff --git a/fish/guestfish.pod b/fish/guestfish.pod -index 06644c5b8..ccb57b159 100644 ---- a/fish/guestfish.pod -+++ b/fish/guestfish.pod -@@ -283,15 +283,16 @@ were found. - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C can be in one of the following formats: -+the inspection. C must be the libguestfs device name of the LUKS -+device. - - =over 4 - --=item B<--key> C:key:KEY_STRING -+=item B<--key> C:key:KEY_STRING - - Use the specified C as passphrase. - --=item B<--key> C:file:FILENAME -+=item B<--key> C:file:FILENAME - - Read the passphrase from F. - -diff --git a/fuse/guestmount.pod b/fuse/guestmount.pod -index 9319d093c..d9e957b8b 100644 ---- a/fuse/guestmount.pod -+++ b/fuse/guestmount.pod -@@ -249,15 +249,16 @@ mounted on the real virtual machine. - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C can be in one of the following formats: -+the inspection. C must be the libguestfs device name of the LUKS -+device. - - =over 4 - --=item B<--key> C:key:KEY_STRING -+=item B<--key> C:key:KEY_STRING - - Use the specified C as passphrase. - --=item B<--key> C:file:FILENAME -+=item B<--key> C:file:FILENAME - - Read the passphrase from F. - -diff --git a/get-kernel/virt-get-kernel.pod b/get-kernel/virt-get-kernel.pod -index 3802412e2..f0ace2d6d 100644 ---- a/get-kernel/virt-get-kernel.pod -+++ b/get-kernel/virt-get-kernel.pod -@@ -92,15 +92,16 @@ security problem with malicious guests (CVE-2010-3851). - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C can be in one of the following formats: -+the inspection. C must be the libguestfs device name of the LUKS -+device. - - =over 4 - --=item B<--key> C:key:KEY_STRING -+=item B<--key> C:key:KEY_STRING - - Use the specified C as passphrase. - --=item B<--key> C:file:FILENAME -+=item B<--key> C:file:FILENAME - - Read the passphrase from F. - -diff --git a/inspector/virt-inspector.pod b/inspector/virt-inspector.pod -index 98b278f26..eac9dc3cd 100644 ---- a/inspector/virt-inspector.pod -+++ b/inspector/virt-inspector.pod -@@ -117,15 +117,16 @@ ensure the format is always specified. - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C can be in one of the following formats: -+the inspection. C must be the libguestfs device name of the LUKS -+device. - - =over 4 - --=item B<--key> C:key:KEY_STRING -+=item B<--key> C:key:KEY_STRING - - Use the specified C as passphrase. - --=item B<--key> C:file:FILENAME -+=item B<--key> C:file:FILENAME - - Read the passphrase from F. - -diff --git a/sparsify/virt-sparsify.pod b/sparsify/virt-sparsify.pod -index 3f5f9995f..cf7970a5f 100644 ---- a/sparsify/virt-sparsify.pod -+++ b/sparsify/virt-sparsify.pod -@@ -233,15 +233,16 @@ See L below. - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C can be in one of the following formats: -+the inspection. C must be the libguestfs device name of the LUKS -+device. - - =over 4 - --=item B<--key> C:key:KEY_STRING -+=item B<--key> C:key:KEY_STRING - - Use the specified C as passphrase. - --=item B<--key> C:file:FILENAME -+=item B<--key> C:file:FILENAME - - Read the passphrase from F. - -diff --git a/sysprep/virt-sysprep.pod b/sysprep/virt-sysprep.pod -index 8d248db94..d7ad7ee33 100644 ---- a/sysprep/virt-sysprep.pod -+++ b/sysprep/virt-sysprep.pod -@@ -189,15 +189,16 @@ security problem with malicious guests (CVE-2010-3851). - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C can be in one of the following formats: -+the inspection. C must be the libguestfs device name of the LUKS -+device. - - =over 4 - --=item B<--key> C:key:KEY_STRING -+=item B<--key> C:key:KEY_STRING - - Use the specified C as passphrase. - --=item B<--key> C:file:FILENAME -+=item B<--key> C:file:FILENAME - - Read the passphrase from F. - -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index 0642d158f..8c2867814 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -337,15 +337,16 @@ through VDDK. - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C can be in one of the following formats: -+the inspection. C must be the libguestfs device name of the LUKS -+device. - - =over 4 - --=item B<--key> C:key:KEY_STRING -+=item B<--key> C:key:KEY_STRING - - Use the specified C as passphrase. - --=item B<--key> C:file:FILENAME -+=item B<--key> C:file:FILENAME - - Read the passphrase from F. - --- -2.18.4 - diff --git a/SOURCES/0048-options-allow-a-UUID-as-identifier-for-key.patch b/SOURCES/0048-options-allow-a-UUID-as-identifier-for-key.patch deleted file mode 100644 index 80402a2..0000000 --- a/SOURCES/0048-options-allow-a-UUID-as-identifier-for-key.patch +++ /dev/null @@ -1,313 +0,0 @@ -From 88c4dc1e5b9f9e545c89e8b8ee6878f57df3139c Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Fri, 29 Nov 2019 12:07:13 +0100 -Subject: [PATCH] options: allow a UUID as identifier for --key - -This way it is possible to specify the UUID of the LUKS device instead -of the libguestfs device name to decrypt a device during the inspection. - -Make the usage of the new luks_uuid API conditional, so other projects -using the common submodule do not require a libguestfs version bump. - -(cherry picked from commit bb4a2dc17a78b53437896d4215ae82df8e11b788 -in libguestfs-common) - -PT: the documentation was amended manually. ---- - cat/virt-cat.pod | 4 ++-- - cat/virt-log.pod | 4 ++-- - cat/virt-ls.pod | 4 ++-- - cat/virt-tail.pod | 4 ++-- - common/options/decrypt.c | 8 +++++++- - common/options/keys.c | 4 ++-- - common/options/options.h | 6 +++--- - customize/virt-customize.pod | 4 ++-- - diff/virt-diff.pod | 4 ++-- - edit/virt-edit.pod | 4 ++-- - fish/guestfish.pod | 4 ++-- - fuse/guestmount.pod | 4 ++-- - get-kernel/virt-get-kernel.pod | 4 ++-- - inspector/virt-inspector.pod | 4 ++-- - sparsify/virt-sparsify.pod | 4 ++-- - sysprep/virt-sysprep.pod | 4 ++-- - v2v/virt-v2v.pod | 4 ++-- - 17 files changed, 40 insertions(+), 34 deletions(-) - -diff --git a/cat/virt-cat.pod b/cat/virt-cat.pod -index b0301d636..2cea291ac 100644 ---- a/cat/virt-cat.pod -+++ b/cat/virt-cat.pod -@@ -124,8 +124,8 @@ security problem with malicious guests (CVE-2010-3851). - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C must be the libguestfs device name of the LUKS --device. -+the inspection. C can be either the libguestfs device name, or -+the UUID of the LUKS device. - - =over 4 - -diff --git a/cat/virt-log.pod b/cat/virt-log.pod -index 0d447b3b5..888108d5f 100644 ---- a/cat/virt-log.pod -+++ b/cat/virt-log.pod -@@ -108,8 +108,8 @@ security problem with malicious guests (CVE-2010-3851). - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C must be the libguestfs device name of the LUKS --device. -+the inspection. C can be either the libguestfs device name, or -+the UUID of the LUKS device. - - =over 4 - -diff --git a/cat/virt-ls.pod b/cat/virt-ls.pod -index de02a473d..307e79395 100644 ---- a/cat/virt-ls.pod -+++ b/cat/virt-ls.pod -@@ -355,8 +355,8 @@ L above. - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C must be the libguestfs device name of the LUKS --device. -+the inspection. C can be either the libguestfs device name, or -+the UUID of the LUKS device. - - =over 4 - -diff --git a/cat/virt-tail.pod b/cat/virt-tail.pod -index f00384f5d..a804f4cf3 100644 ---- a/cat/virt-tail.pod -+++ b/cat/virt-tail.pod -@@ -126,8 +126,8 @@ security problem with malicious guests (CVE-2010-3851). - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C must be the libguestfs device name of the LUKS --device. -+the inspection. C can be either the libguestfs device name, or -+the UUID of the LUKS device. - - =over 4 - -diff --git a/common/options/decrypt.c b/common/options/decrypt.c -index 3511d9fe9..683cf5ed4 100644 ---- a/common/options/decrypt.c -+++ b/common/options/decrypt.c -@@ -86,7 +86,13 @@ inspect_do_decrypt (guestfs_h *g, struct key_store *ks) - char mapname[32]; - make_mapname (partitions[i], mapname, sizeof mapname); - -- CLEANUP_FREE_STRING_LIST char **keys = get_keys (ks, partitions[i]); -+#ifdef GUESTFS_HAVE_LUKS_UUID -+ CLEANUP_FREE char *uuid = guestfs_luks_uuid (g, partitions[i]); -+#else -+ const char *uuid = NULL; -+#endif -+ -+ CLEANUP_FREE_STRING_LIST char **keys = get_keys (ks, partitions[i], uuid); - assert (guestfs_int_count_strings (keys) > 0); - - /* Try each key in turn. */ -diff --git a/common/options/keys.c b/common/options/keys.c -index 7c391acde..798315c2e 100644 ---- a/common/options/keys.c -+++ b/common/options/keys.c -@@ -126,7 +126,7 @@ read_first_line_from_file (const char *filename) - * keystore, ask the user. - */ - char ** --get_keys (struct key_store *ks, const char *device) -+get_keys (struct key_store *ks, const char *device, const char *uuid) - { - size_t i, j, len; - char **r; -@@ -148,7 +148,7 @@ get_keys (struct key_store *ks, const char *device) - for (i = 0; i < ks->nr_keys; ++i) { - struct key_store_key *key = &ks->keys[i]; - -- if (STRNEQ (key->id, device)) -+ if (STRNEQ (key->id, device) && (uuid && STRNEQ (key->id, uuid))) - continue; - - switch (key->type) { -diff --git a/common/options/options.h b/common/options/options.h -index b83a92b06..9b7830220 100644 ---- a/common/options/options.h -+++ b/common/options/options.h -@@ -104,8 +104,8 @@ struct mp { - - /* A key in the key store. */ - struct key_store_key { -- /* An ID for the device this key refers to. It must be the libguestfs -- * device name. -+ /* An ID for the device this key refers to. It can be either the libguestfs -+ * device name, or the UUID. - * - * There may be multiple matching devices in the list. - */ -@@ -150,7 +150,7 @@ extern void print_inspect_prompt (void); - - /* in key.c */ - extern char *read_key (const char *param); --extern char **get_keys (struct key_store *ks, const char *device); -+extern char **get_keys (struct key_store *ks, const char *device, const char *uuid); - extern struct key_store *key_store_add_from_selector (struct key_store *ks, const char *selector); - extern struct key_store *key_store_import_key (struct key_store *ks, const struct key_store_key *key); - extern void free_key_store (struct key_store *ks); -diff --git a/customize/virt-customize.pod b/customize/virt-customize.pod -index 491606591..5d92486a2 100644 ---- a/customize/virt-customize.pod -+++ b/customize/virt-customize.pod -@@ -141,8 +141,8 @@ security problem with malicious guests (CVE-2010-3851). - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C must be the libguestfs device name of the LUKS --device. -+the inspection. C can be either the libguestfs device name, or -+the UUID of the LUKS device. - - =over 4 - -diff --git a/diff/virt-diff.pod b/diff/virt-diff.pod -index 22658072d..e67d09101 100644 ---- a/diff/virt-diff.pod -+++ b/diff/virt-diff.pod -@@ -169,8 +169,8 @@ Display file sizes in human-readable format. - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C must be the libguestfs device name of the LUKS --device. -+the inspection. C can be either the libguestfs device name, or -+the UUID of the LUKS device. - - =over 4 - -diff --git a/edit/virt-edit.pod b/edit/virt-edit.pod -index 5a63cd05f..918fa66f2 100644 ---- a/edit/virt-edit.pod -+++ b/edit/virt-edit.pod -@@ -156,8 +156,8 @@ security problem with malicious guests (CVE-2010-3851). - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C must be the libguestfs device name of the LUKS --device. -+the inspection. C can be either the libguestfs device name, or -+the UUID of the LUKS device. - - =over 4 - -diff --git a/fish/guestfish.pod b/fish/guestfish.pod -index ccb57b159..f1fdf094d 100644 ---- a/fish/guestfish.pod -+++ b/fish/guestfish.pod -@@ -283,8 +283,8 @@ were found. - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C must be the libguestfs device name of the LUKS --device. -+the inspection. C can be either the libguestfs device name, or -+the UUID of the LUKS device. - - =over 4 - -diff --git a/fuse/guestmount.pod b/fuse/guestmount.pod -index d9e957b8b..3a02c087c 100644 ---- a/fuse/guestmount.pod -+++ b/fuse/guestmount.pod -@@ -249,8 +249,8 @@ mounted on the real virtual machine. - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C must be the libguestfs device name of the LUKS --device. -+the inspection. C can be either the libguestfs device name, or -+the UUID of the LUKS device. - - =over 4 - -diff --git a/get-kernel/virt-get-kernel.pod b/get-kernel/virt-get-kernel.pod -index f0ace2d6d..78fe66df4 100644 ---- a/get-kernel/virt-get-kernel.pod -+++ b/get-kernel/virt-get-kernel.pod -@@ -92,8 +92,8 @@ security problem with malicious guests (CVE-2010-3851). - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C must be the libguestfs device name of the LUKS --device. -+the inspection. C can be either the libguestfs device name, or -+the UUID of the LUKS device. - - =over 4 - -diff --git a/inspector/virt-inspector.pod b/inspector/virt-inspector.pod -index eac9dc3cd..625da876c 100644 ---- a/inspector/virt-inspector.pod -+++ b/inspector/virt-inspector.pod -@@ -117,8 +117,8 @@ ensure the format is always specified. - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C must be the libguestfs device name of the LUKS --device. -+the inspection. C can be either the libguestfs device name, or -+the UUID of the LUKS device. - - =over 4 - -diff --git a/sparsify/virt-sparsify.pod b/sparsify/virt-sparsify.pod -index cf7970a5f..0767d07e6 100644 ---- a/sparsify/virt-sparsify.pod -+++ b/sparsify/virt-sparsify.pod -@@ -233,8 +233,8 @@ See L below. - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C must be the libguestfs device name of the LUKS --device. -+the inspection. C can be either the libguestfs device name, or -+the UUID of the LUKS device. - - =over 4 - -diff --git a/sysprep/virt-sysprep.pod b/sysprep/virt-sysprep.pod -index d7ad7ee33..b38c76c70 100644 ---- a/sysprep/virt-sysprep.pod -+++ b/sysprep/virt-sysprep.pod -@@ -189,8 +189,8 @@ security problem with malicious guests (CVE-2010-3851). - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C must be the libguestfs device name of the LUKS --device. -+the inspection. C can be either the libguestfs device name, or -+the UUID of the LUKS device. - - =over 4 - -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index 8c2867814..25041d0ec 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -337,8 +337,8 @@ through VDDK. - =item B<--key> SELECTOR - - Specify a key for LUKS, to automatically open a LUKS device when using --the inspection. C must be the libguestfs device name of the LUKS --device. -+the inspection. C can be either the libguestfs device name, or -+the UUID of the LUKS device. - - =over 4 - --- -2.18.4 - diff --git a/SOURCES/0049-docs-remove-paragraph-about-VMware-tools-on-Windows-.patch b/SOURCES/0049-docs-remove-paragraph-about-VMware-tools-on-Windows-.patch deleted file mode 100644 index 4301fbb..0000000 --- a/SOURCES/0049-docs-remove-paragraph-about-VMware-tools-on-Windows-.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 14c456c0f5d9caad9aedc5abb7b6a025ac09e7bd Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Wed, 18 Dec 2019 12:12:26 +0100 -Subject: [PATCH] docs: remove paragraph about VMware tools on Windows - (RHBZ#1785528) - -Starting from libguestfs/virt-v2v 1.39.12, virt-v2v attempts to -uninstall the VMware tools from Windows guests, so there is no need to -remove them manually before the conversion. - -Thanks to: Ming Xie. - -(cherry picked from commit 397b4a90d16f4eb116d55605cbdf3bd844108315 -in virt-v2v) ---- - v2v/virt-v2v-input-vmware.pod | 36 ----------------------------------- - 1 file changed, 36 deletions(-) - -diff --git a/v2v/virt-v2v-input-vmware.pod b/v2v/virt-v2v-input-vmware.pod -index 3acdd773e..16ddb045f 100644 ---- a/v2v/virt-v2v-input-vmware.pod -+++ b/v2v/virt-v2v-input-vmware.pod -@@ -106,18 +106,6 @@ If you find a folder of files called F.vmx>, - F.vmxf>, F.nvram> and one or more F<.vmdk> disk - images, then you can use this method. - --=head2 VMX: Remove VMware tools from Windows guests -- --For Windows guests, you should remove VMware tools before conversion. --Although this is not strictly necessary, and the guest will still be --able to run, if you don't do this then the converted guest will --complain on every boot. The tools cannot be removed after conversion --because the uninstaller checks if it is running on VMware and refuses --to start (which is also the reason that virt-v2v cannot remove them). -- --This is not necessary for Linux guests, as virt-v2v is able to remove --VMware tools. -- - =head2 VMX: Guest must be shut down - - B. If you don't -@@ -319,18 +307,6 @@ Virt-v2v is able to import guests from VMware’s OVA (Open - Virtualization Appliance) files. Only OVAs exported from VMware - vSphere will work. - --=head2 OVA: Remove VMware tools from Windows guests -- --For Windows guests, you should remove VMware tools before conversion. --Although this is not strictly necessary, and the guest will still be --able to run, if you don't do this then the converted guest will --complain on every boot. The tools cannot be removed after conversion --because the uninstaller checks if it is running on VMware and refuses --to start (which is also the reason that virt-v2v cannot remove them). -- --This is not necessary for Linux guests, as virt-v2v is able to remove --VMware tools. -- - =head2 OVA: Create OVA - - To create an OVA in vSphere, use the "Export OVF Template" option -@@ -383,18 +359,6 @@ Virt-v2v uses libvirt for access to vCenter, and therefore the input - mode should be I<-i libvirt>. As this is the default, you don't need - to specify it on the command line. - --=head2 vCenter: Remove VMware tools from Windows guests -- --For Windows guests, you should remove VMware tools before conversion. --Although this is not strictly necessary, and the guest will still be --able to run, if you don't do this then the converted guest will --complain on every boot. The tools cannot be removed after conversion --because the uninstaller checks if it is running on VMware and refuses --to start (which is also the reason that virt-v2v cannot remove them). -- --This is not necessary for Linux guests, as virt-v2v is able to remove --VMware tools. -- - =head2 vCenter: URI - - The libvirt URI of a vCenter server looks something like this: --- -2.18.4 - diff --git a/SOURCES/0050-mlcustomize-Trim-whitespaces-from-commands-read-from.patch b/SOURCES/0050-mlcustomize-Trim-whitespaces-from-commands-read-from.patch deleted file mode 100644 index 6a41357..0000000 --- a/SOURCES/0050-mlcustomize-Trim-whitespaces-from-commands-read-from.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 931846b8f08e5e763141cadfc5e9b194b69303e3 Mon Sep 17 00:00:00 2001 -From: Martin Kletzander -Date: Mon, 24 Feb 2020 13:12:03 +0100 -Subject: [PATCH] mlcustomize: Trim whitespaces from commands read from file - (RHBZ#1351000) - -The first split does not care about the whole string, it is just trying to get -the command name in front, so triml is just right. - -Signed-off-by: Martin Kletzander ---- - generator/customize.ml | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/generator/customize.ml b/generator/customize.ml -index c278347c1..0b256e2d2 100644 ---- a/generator/customize.ml -+++ b/generator/customize.ml -@@ -873,6 +873,7 @@ let rec argspec () = - pr " ] in - let lines = read_whole_file filename in - let lines = String.lines_split lines in -+ let lines = List.map String.triml lines in - let lines = List.filter ( - fun line -> - String.length line > 0 && line.[0] <> '#' --- -2.18.4 - diff --git a/SOURCES/0051-openstack-Increase-Cinder-volume-attach-timeout-to-5.patch b/SOURCES/0051-openstack-Increase-Cinder-volume-attach-timeout-to-5.patch deleted file mode 100644 index b0b2d88..0000000 --- a/SOURCES/0051-openstack-Increase-Cinder-volume-attach-timeout-to-5.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 7cfbc1e0fac86b1139c59945f74eab8906ec18bc Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 4 Feb 2020 14:39:39 +0000 -Subject: [PATCH] openstack: Increase Cinder volume attach timeout to 5 minutes - (RHBZ#1685032). - -In some cases we have observed the time taken for a Cinder volume to -attach to the conversion appliance can be longer than the current 60 -seconds. Increase the timeout to 5 minutes. - -Thanks: Ming Xie. - -(cherry picked from commit e2ce290f6e366716f857eeaddc1dc680e5608c80 -in virt-v2v) ---- - v2v/output_openstack.ml | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/v2v/output_openstack.ml b/v2v/output_openstack.ml -index d187f1d5d..bebf9af18 100644 ---- a/v2v/output_openstack.ml -+++ b/v2v/output_openstack.ml -@@ -38,7 +38,7 @@ let openstack_binary = "openstack" - let available_timeout = 300 (* seconds *) - - (* Timeout waiting for Cinder volumes to attach to the appliance. *) --let attach_timeout = 60 (* seconds *) -+let attach_timeout = 300 (* seconds *) - - (* The -oo options supported by this output method. *) - type os_options = { -@@ -336,7 +336,7 @@ class output_openstack output_conn output_password output_storage - if String.length id > prefix_len then String.sub id 0 prefix_len - else id in - -- with_timeout -+ with_timeout ~sleep:5 - (sprintf (f_"waiting for cinder volume %s to attach to the conversion appliance") id) - attach_timeout - (fun () -> --- -2.18.4 - diff --git a/SOURCES/0052-v2v-o-rhv-upload-check-for-a-valid-image-transfer-ri.patch b/SOURCES/0052-v2v-o-rhv-upload-check-for-a-valid-image-transfer-ri.patch deleted file mode 100644 index 039d151..0000000 --- a/SOURCES/0052-v2v-o-rhv-upload-check-for-a-valid-image-transfer-ri.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 303ecfdf662a2fd80b115a1e2f20560e6f97d953 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Thu, 19 Sep 2019 09:52:41 +0200 -Subject: [PATCH] v2v: -o rhv-upload: check for a valid image transfer right - away - -Check for the INITIALIZING state of the image transfer right away, -without waiting 5 seconds even before the first time: this way, if the -transfer is already in the right state then there is no need to wait. ---- - v2v/rhv-upload-plugin.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py -index 6ec74a5d4..7f62b4e3b 100644 ---- a/v2v/rhv-upload-plugin.py -+++ b/v2v/rhv-upload-plugin.py -@@ -190,13 +190,13 @@ def open(readonly): - # actual transfer can start when its status is "Transferring". - endt = time.time() + timeout - while True: -- time.sleep(5) - transfer = transfer_service.get() - if transfer.phase != types.ImageTransferPhase.INITIALIZING: - break - if time.time() > endt: - raise RuntimeError("timed out waiting for transfer status " - "!= INITIALIZING") -+ time.sleep(5) - - # Now we have permission to start the transfer. - if params['rhv_direct']: --- -2.18.4 - diff --git a/SOURCES/0053-rhv-upload-Check-status-more-frequently.patch b/SOURCES/0053-rhv-upload-Check-status-more-frequently.patch deleted file mode 100644 index 4e69981..0000000 --- a/SOURCES/0053-rhv-upload-Check-status-more-frequently.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 7a4b425471223234fde5a65ca5fe5abc87fb0276 Mon Sep 17 00:00:00 2001 -From: Nir Soffer -Date: Mon, 18 Nov 2019 01:04:24 +0200 -Subject: [PATCH] rhv-upload: Check status more frequently - -Checking status more frequently save a couple of seconds. Here is -an example flow tested with oVirt upload_disk.py example: - -With 5 seconds wait: - -Created disk in 11.085111 seconds -Created transfer in 1.857502 seconds - -With 1 second wait: - -Created disk in 4.991227 seconds -Created transfer in 1.961243 seconds - -(cherry picked from commit 8816c5db220f518ef70beec7ac543290e3d5c0c7 -in virt-v2v) ---- - v2v/rhv-upload-plugin.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py -index 7f62b4e3b..f13405df1 100644 ---- a/v2v/rhv-upload-plugin.py -+++ b/v2v/rhv-upload-plugin.py -@@ -161,7 +161,7 @@ def open(readonly): - - endt = time.time() + timeout - while True: -- time.sleep(5) -+ time.sleep(1) - disk = disk_service.get() - if disk.status == types.DiskStatus.OK: - break -@@ -196,7 +196,7 @@ def open(readonly): - if time.time() > endt: - raise RuntimeError("timed out waiting for transfer status " - "!= INITIALIZING") -- time.sleep(5) -+ time.sleep(1) - - # Now we have permission to start the transfer. - if params['rhv_direct']: --- -2.18.4 - diff --git a/SOURCES/0054-rhv-upload-Show-transfer-id-in-error-message.patch b/SOURCES/0054-rhv-upload-Show-transfer-id-in-error-message.patch deleted file mode 100644 index 477d6c2..0000000 --- a/SOURCES/0054-rhv-upload-Show-transfer-id-in-error-message.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 8659766f3559177edf60f7ed6e1ed834f5d4d4a0 Mon Sep 17 00:00:00 2001 -From: Nir Soffer -Date: Mon, 18 Nov 2019 23:53:46 +0200 -Subject: [PATCH] rhv-upload: Show transfer id in error message - -(cherry picked from commit d4ca9b6ca42d4ad3c717f5c59402ca6ff5d322bb -in virt-v2v) ---- - v2v/rhv-upload-plugin.py | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py -index f13405df1..9b83d1cfa 100644 ---- a/v2v/rhv-upload-plugin.py -+++ b/v2v/rhv-upload-plugin.py -@@ -194,8 +194,10 @@ def open(readonly): - if transfer.phase != types.ImageTransferPhase.INITIALIZING: - break - if time.time() > endt: -- raise RuntimeError("timed out waiting for transfer status " -- "!= INITIALIZING") -+ raise RuntimeError( -+ "timed out waiting for transfer %s status != INITIALIZING" -+ % transfer.id) -+ - time.sleep(1) - - # Now we have permission to start the transfer. --- -2.18.4 - diff --git a/SOURCES/0055-rhv-upload-Fix-waiting-for-transfer.patch b/SOURCES/0055-rhv-upload-Fix-waiting-for-transfer.patch deleted file mode 100644 index cb4b91d..0000000 --- a/SOURCES/0055-rhv-upload-Fix-waiting-for-transfer.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 79a7e239ca55bffb2af059e1cfe07206d37cb858 Mon Sep 17 00:00:00 2001 -From: Nir Soffer -Date: Thu, 28 Nov 2019 20:36:32 +0200 -Subject: [PATCH] rhv-upload: Fix waiting for transfer - -We were not considering failures while initializing the transfer. In -this case the transfer phase can change to PAUSED_SYSTEM or -FINISHED_FAILURE, and transfer_url will be None, which failed the -upload with a misleading error: - - RuntimeError: direct upload to host not supported, requires - ovirt-engine >= 4.2 and only works when virt-v2v is run within the - oVirt/RHV environment, eg. on an oVirt node - -Change the wait loop to consider all cases: -- Transfer failed and was removed -- Transfer failed and will be removed soon -- Transfer paused by the system (cancel required) -- Unexpected transfer phase (cancel required) -- Timeout waiting for TRANSFERRING state (cancel required) - -Reported-by: Xiaodai Wang - -(cherry picked from commit 40e1844827e4d096b1919a2159f9effc41915a73 -in virt-v2v) ---- - v2v/rhv-upload-plugin.py | 41 +++++++++++++++++++++++++++++++--------- - 1 file changed, 32 insertions(+), 9 deletions(-) - -diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py -index 9b83d1cfa..14d4e37fb 100644 ---- a/v2v/rhv-upload-plugin.py -+++ b/v2v/rhv-upload-plugin.py -@@ -185,20 +185,43 @@ def open(readonly): - # Get a reference to the created transfer service. - transfer_service = transfers_service.image_transfer_service(transfer.id) - -- # After adding a new transfer for the disk, the transfer's status -- # will be INITIALIZING. Wait until the init phase is over. The -- # actual transfer can start when its status is "Transferring". -+ # Wait until transfer's phase change from INITIALIZING to TRANSFERRING. On -+ # errors transfer's phase can change to PAUSED_SYSTEM or FINISHED_FAILURE. -+ # If the transfer was paused, we need to cancel it to remove the disk, -+ # otherwise the system will remove the disk and transfer shortly after. -+ - endt = time.time() + timeout - while True: -- transfer = transfer_service.get() -+ time.sleep(1) -+ try: -+ transfer = transfer_service.get() -+ except sdk.NotFoundError: -+ # The system has removed the disk and the transfer. -+ raise RuntimeError("transfer %s was removed" % transfer.id) -+ -+ if transfer.phase == types.ImageTransferPhase.FINISHED_FAILURE: -+ # The system will remove the disk and the transfer soon. -+ raise RuntimeError( -+ "transfer %s has failed" % transfer.id) -+ -+ if transfer.phase == types.ImageTransferPhase.PAUSED_SYSTEM: -+ transfer_service.cancel() -+ raise RuntimeError( -+ "transfer %s was paused by system" % transfer.id) -+ -+ if transfer.phase == types.ImageTransferPhase.TRANSFERRING: -+ break -+ - if transfer.phase != types.ImageTransferPhase.INITIALIZING: -- break -- if time.time() > endt: -+ transfer_service.cancel() - raise RuntimeError( -- "timed out waiting for transfer %s status != INITIALIZING" -- % transfer.id) -+ "unexpected transfer %s phase %s" -+ % (transfer.id, transfer.phase)) - -- time.sleep(1) -+ if time.time() > endt: -+ transfer_service.cancel() -+ raise RuntimeError( -+ "timed out waiting for transfer %s" % transfer.id) - - # Now we have permission to start the transfer. - if params['rhv_direct']: --- -2.18.4 - diff --git a/SOURCES/0056-v2v-Optimize-convert-for-images-with-small-holes.patch b/SOURCES/0056-v2v-Optimize-convert-for-images-with-small-holes.patch deleted file mode 100644 index c7ce346..0000000 --- a/SOURCES/0056-v2v-Optimize-convert-for-images-with-small-holes.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 48718639cc7fc5f93260b00553397ccb3faa7bbc Mon Sep 17 00:00:00 2001 -From: Nir Soffer -Date: Fri, 1 Nov 2019 22:56:18 +0100 -Subject: [PATCH] v2v: Optimize convert for images with small holes -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -"qemu-img convert" detects zeroes in allocated areas and punch holes in -the destination image. This may save space on the destination image, but -slows down conversion when using outputs such as rhv-upload, which have -very large overhead per requests. - -Using the -S flag, we can treat small areas filled with zeroes as data, -limiting the number of requests, and speeding the operation. - -Here is an example converting Fedora 30 image: - -$ virt-builder fedora-30 -o src.img -... - -$ qemu-img map -f raw --output json src.img | wc -l -213 - -$ qemu-img convert -f raw -O raw -t none -T none src.img dst.img - -$ qemu-img map -f raw --output json dst.img | wc -l -1443 - -$ ls -lhs *.img -1.2G -rw-r--r--. 1 nsoffer nsoffer 6.0G Nov  1 21:48 dst.img -1.2G -rw-r--r--. 1 nsoffer nsoffer 6.0G Nov  1 21:46 src.img - -Qemu did 1443 writes instead of 213 (5.8X). Lets repeat this conversion -with the -S option: - -$ qemu-img convert -f raw -O raw -t none -T none -S 64k src.img dst.img - -$ qemu-img map -f raw --output json dst.img | wc -l -213 - -$ ls -lhs *.img -1.2G -rw-r--r--. 1 nsoffer nsoffer 6.0G Nov  1 21:48 dst.img -1.2G -rw-r--r--. 1 nsoffer nsoffer 6.0G Nov  1 21:46 src.img - -Picking a good value for -S is not easy. Testing show that 64k is best -value for this test image for limiting the number of requests: - -$ for size in 4k 8k 16k 32k 64k; do \ - printf "%5s: " $size; \ - qemu-img convert -f raw -O raw -t none -T none -S $size src.img dst.img; \ - qemu-img map -f raw --output json dst.img | wc -l; \ -done -   4k: 1443 -   8k: 731 -  16k: 521 -  32k: 387 -  64k: 213 - -We need more testing with oVirt to measure the performance improvement -and pick a good value. This should probably be an option, but lets start -with a minimal change. - -(cherry picked from commit 2aa78ade2d48e926b7b04050338ebd8a0c5e3f05 -in virt-v2v) ---- - v2v/v2v.ml | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/v2v/v2v.ml b/v2v/v2v.ml -index d7a868659..a81a2320a 100644 ---- a/v2v/v2v.ml -+++ b/v2v/v2v.ml -@@ -754,6 +754,7 @@ and copy_targets cmdline targets input output = - (if not (quiet ()) then [ "-p" ] else []) @ - [ "-n"; "-f"; "qcow2"; "-O"; t.target_format ] @ - (if cmdline.compressed then [ "-c" ] else []) @ -+ [ "-S"; "64k" ] @ - [ overlay_file; filename ] in - let start_time = gettimeofday () in - if run_command cmd <> 0 then --- -2.18.4 - diff --git a/SOURCES/0057-v2v-o-rhv-upload-Make-oo-rhv-cafile-optional-in-all-.patch b/SOURCES/0057-v2v-o-rhv-upload-Make-oo-rhv-cafile-optional-in-all-.patch deleted file mode 100644 index e839d50..0000000 --- a/SOURCES/0057-v2v-o-rhv-upload-Make-oo-rhv-cafile-optional-in-all-.patch +++ /dev/null @@ -1,49 +0,0 @@ -From fdf461e88c464de697c14adea2e8e61644811844 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Wed, 15 Jan 2020 11:12:17 +0000 -Subject: [PATCH] v2v: -o rhv-upload: Make -oo rhv-cafile optional in all cases - (RHBZ#1791240). - -This is actually not required, because ovirtsdk4 will use the system's -global trust store if necessary. Therefore we can make it optional in -all cases. - -(cherry picked from commit 65ee9387d4be0e3c5cd214b967fef7a1a8841233 -in virt-v2v) ---- - v2v/output_rhv_upload.ml | 2 -- - v2v/virt-v2v-output-rhv.pod | 5 ++++- - 2 files changed, 4 insertions(+), 3 deletions(-) - -diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml -index 2c8c18732..e1d06867b 100644 ---- a/v2v/output_rhv_upload.ml -+++ b/v2v/output_rhv_upload.ml -@@ -81,8 +81,6 @@ let parse_output_options options = - let rhv_direct = !rhv_direct in - let rhv_verifypeer = !rhv_verifypeer in - let rhv_disk_uuids = Option.map List.rev !rhv_disk_uuids in -- if rhv_verifypeer && rhv_cafile = None then -- error (f_"-o rhv-upload: must use ‘-oo rhv-cafile’ to supply the path to the oVirt or RHV user’s ‘ca.pem’ file"); - - { rhv_cafile; rhv_cluster; rhv_direct; rhv_verifypeer; rhv_disk_uuids } - -diff --git a/v2v/virt-v2v-output-rhv.pod b/v2v/virt-v2v-output-rhv.pod -index 04a894268..4520c9184 100644 ---- a/v2v/virt-v2v-output-rhv.pod -+++ b/v2v/virt-v2v-output-rhv.pod -@@ -101,7 +101,10 @@ The storage domain. - The F file (Certificate Authority), copied from - F on the oVirt engine. - --This option must be specified if I<-oo rhv-verifypeer> is enabled. -+If I<-oo rhv-verifypeer> is enabled then this option can -+be used to control which CA is used to verify the client’s -+identity. If this option is not used then the system’s -+global trust store is used. - - =item I<-oo rhv-cluster=>C - --- -2.18.4 - diff --git a/SOURCES/0058-docs-Fix-update-crypto-policies-command-RHBZ-1791257.patch b/SOURCES/0058-docs-Fix-update-crypto-policies-command-RHBZ-1791257.patch deleted file mode 100644 index d13f36c..0000000 --- a/SOURCES/0058-docs-Fix-update-crypto-policies-command-RHBZ-1791257.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 99de55c364d95ae50a6d6cd6865e52a6737738c5 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Wed, 15 Jan 2020 10:55:27 +0000 -Subject: [PATCH] docs: Fix update-crypto-policies command (RHBZ#1791257). - -The command as documented was wrong. We need to use the --set option -to change the policy. - -Fixes commit d5cbe7b4bee5dec9e28b1db03e933c97ef6d11e0. -Thanks: Xiaodai Wang - -(cherry picked from commit 0edf419e983fe75daef9eaa7bd0578cbcada2e73 -in virt-v2v) ---- - v2v/virt-v2v-input-xen.pod | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/v2v/virt-v2v-input-xen.pod b/v2v/virt-v2v-input-xen.pod -index 4bb5d2dc2..9fd5065f1 100644 ---- a/v2v/virt-v2v-input-xen.pod -+++ b/v2v/virt-v2v-input-xen.pod -@@ -37,7 +37,7 @@ to interoperate with RHEL 5 sshd are disabled. To enable them you may - need to run this command on the conversion server (ie. ssh client), - but read L first: - -- # update-crypto-policies LEGACY -+ # update-crypto-policies --set LEGACY - - =head2 Test libvirt connection to remote Xen host - --- -2.18.4 - diff --git a/SOURCES/0059-add-versioned-directory-for-guest-agent-on-EL8.patch b/SOURCES/0059-add-versioned-directory-for-guest-agent-on-EL8.patch deleted file mode 100644 index 3481439..0000000 --- a/SOURCES/0059-add-versioned-directory-for-guest-agent-on-EL8.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 2a08f0f71b92a2489b873c7cef5aae2b2cec88d2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Golembiovsk=C3=BD?= -Date: Thu, 16 Jan 2020 16:05:10 +0100 -Subject: [PATCH] add versioned directory for guest agent on EL8 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -There was no source directory for EL8 guest agent (only EL6 and EL7). - -RHBZ#1791802 - -Signed-off-by: Tomáš Golembiovský - -(cherry picked from commit 79dd6a6bbb7e95691be18f54d601318d7d713702 -in virt-v2v) ---- - v2v/windows_virtio.ml | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/v2v/windows_virtio.ml b/v2v/windows_virtio.ml -index a6dc29f2c..7be63a316 100644 ---- a/v2v/windows_virtio.ml -+++ b/v2v/windows_virtio.ml -@@ -192,6 +192,7 @@ and install_linux_tools g inspect = - (match inspect.i_major_version with - | 6 -> Some "el6" - | 7 -> Some "el7" -+ | 8 -> Some "el8" - | _ -> None) - | "sles" | "suse-based" | "opensuse" -> Some "lp151" - | _ -> None in --- -2.18.4 - diff --git a/SOURCES/0060-v2v-fix-path-to-source-when-copying-files-from-guest.patch b/SOURCES/0060-v2v-fix-path-to-source-when-copying-files-from-guest.patch deleted file mode 100644 index 316ddb3..0000000 --- a/SOURCES/0060-v2v-fix-path-to-source-when-copying-files-from-guest.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 66cd34e84e41d3f70e95fa745637ba6eb4779aec Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Golembiovsk=C3=BD?= -Date: Fri, 8 Feb 2019 11:44:41 +0100 -Subject: [PATCH] v2v: fix path to source when copying files from guest tools - directory -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The debug message was slightly changed too to better match the similar -message for ISO case. It refers to the root directory instead of the -specific subdirectory inside guest tools. - -Signed-off-by: Tomáš Golembiovský -(cherry picked from commit f4bda5571a36da42bdc800c10f2c85cf20bf5c85) ---- - v2v/windows_virtio.ml | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/v2v/windows_virtio.ml b/v2v/windows_virtio.ml -index 7be63a316..70f0bf09d 100644 ---- a/v2v/windows_virtio.ml -+++ b/v2v/windows_virtio.ml -@@ -309,10 +309,11 @@ and copy_drivers g inspect driverdir = - and copy_from_virtio_win g inspect srcdir destdir filter missing = - let ret = ref [] in - if is_directory virtio_win then ( -+ debug "windows: copy_from_virtio_win: guest tools source directory %s" -+ virtio_win; -+ - let dir = virtio_win // srcdir in -- debug "windows: copy_from_virtio_win: guest tools source directory %s" dir; -- -- if not (is_directory srcdir) then missing () -+ if not (is_directory dir) then missing () - else ( - let cmd = sprintf "cd %s && find -L -type f" (quote dir) in - let paths = external_command cmd in --- -2.18.4 - diff --git a/SOURCES/0061-v2v-windows-install-QEMU-Guest-Agent-MSI.patch b/SOURCES/0061-v2v-windows-install-QEMU-Guest-Agent-MSI.patch deleted file mode 100644 index f37b2e5..0000000 --- a/SOURCES/0061-v2v-windows-install-QEMU-Guest-Agent-MSI.patch +++ /dev/null @@ -1,119 +0,0 @@ -From cf06f1d264a8832aa31265da5b2a28547b0faf49 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Golembiovsk=C3=BD?= -Date: Tue, 8 Oct 2019 13:16:38 +0200 -Subject: [PATCH] v2v: windows: install QEMU Guest Agent MSI -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Use firstboot script to install MSI with QEMU-GA from virtio-win ISO or -oVirt/RHV guest tools ISO. - -Signed-off-by: Tomáš Golembiovský -(cherry picked from commit 00b4ed312b0ba179e9901b73c099724c3f6606b4) ---- - v2v/convert_windows.ml | 19 +++++++++++++++++++ - v2v/windows_virtio.ml | 27 +++++++++++++++++++++++++++ - v2v/windows_virtio.mli | 4 ++++ - 3 files changed, 50 insertions(+) - -diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml -index 75e609d61..bdb0092c3 100644 ---- a/v2v/convert_windows.ml -+++ b/v2v/convert_windows.ml -@@ -293,6 +293,13 @@ let convert (g : G.guestfs) inspect source output rcaps static_ips = - if Sys.file_exists tool_path then - configure_vmdp tool_path; - -+ (* Install QEMU Guest Agent unconditionally and warn if missing *) -+ let qemu_ga_files = Windows_virtio.copy_qemu_ga g inspect in -+ if qemu_ga_files <> [] then -+ configure_qemu_ga qemu_ga_files -+ else -+ warning (f_"QEMU Guest Agent MSI not found on tools ISO/directory. You may want to install the guest agent manually after conversion."); -+ - unconfigure_xenpv (); - unconfigure_prltools (); - unconfigure_vmwaretools () -@@ -418,6 +425,18 @@ popd - Firstboot.add_firstboot_script g inspect.i_root - "finish vmdp setup" fb_recover_script - -+ and configure_qemu_ga files = -+ List.iter ( -+ fun msi_path -> -+ let fb_script = "\ -+echo Installing qemu-ga from " ^ msi_path ^ " -+\"\\" ^ msi_path ^ "\" /qn /forcerestart /l+*vx \"%cd%\\qemu-ga.log\" -+" in -+ Firstboot.add_firstboot_script g inspect.i_root -+ ("install " ^ msi_path) fb_script; -+ ) files -+ -+ - and unconfigure_xenpv () = - match xenpv_uninst with - | None -> () (* nothing to be uninstalled *) -diff --git a/v2v/windows_virtio.ml b/v2v/windows_virtio.ml -index 70f0bf09d..ea7e5c02d 100644 ---- a/v2v/windows_virtio.ml -+++ b/v2v/windows_virtio.ml -@@ -296,6 +296,13 @@ and copy_drivers g inspect 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 g inspect = -+ copy_from_virtio_win g inspect "/" "/" -+ virtio_iso_path_matches_qemu_ga -+ (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]. -@@ -427,6 +434,26 @@ and virtio_iso_path_matches_guest_os path inspect = - - with Not_found -> false - -+(* Given a path of a file relative to the root of the directory tree -+ * with virtio-win drivers, figure out if it's suitable for the -+ * specific Windows flavor of the current guest. -+ *) -+and virtio_iso_path_matches_qemu_ga path inspect = -+ let { i_arch = arch } = inspect in -+ (* Lowercased path, since the ISO may contain upper or lowercase path -+ * elements. -+ *) -+ let lc_name = String.lowercase_ascii (Filename.basename path) in -+ lc_name = "rhev-qga.msi" || -+ match arch, lc_name with -+ | ("i386", "qemu-ga-x86.msi") -+ | ("i386", "qemu-ga-i386.msi") -+ | ("i386", "RHEV-QGA.msi") -+ | ("x86_64", "qemu-ga-x64.msi") -+ | ("x86_64", "qemu-ga-x86_64.msi") -+ | ("x86_64", "RHEV-QGA64.msi") -> true -+ | _ -> false -+ - (* The following function is only exported for unit tests. *) - module UNIT_TESTS = struct - let virtio_iso_path_matches_guest_os = virtio_iso_path_matches_guest_os -diff --git a/v2v/windows_virtio.mli b/v2v/windows_virtio.mli -index ae3b7e865..731dbd6f0 100644 ---- a/v2v/windows_virtio.mli -+++ b/v2v/windows_virtio.mli -@@ -44,6 +44,10 @@ val install_linux_tools : Guestfs.guestfs -> Types.inspect -> unit - (** installs QEMU Guest Agent on Linux guest OS from the driver directory or - driver ISO. It is not fatal if we fail to install the agent. *) - -+val copy_qemu_ga : Guestfs.guestfs -> Types.inspect -> string list -+(** copy MSIs (idealy just one) with QEMU Guest Agent to Windows guest. The -+ MSIs are not installed by this function. *) -+ - (**/**) - - (* The following function is only exported for unit tests. *) --- -2.18.4 - diff --git a/SOURCES/0062-windows-small-tweaks-of-qemu-ga-firstboot-script.patch b/SOURCES/0062-windows-small-tweaks-of-qemu-ga-firstboot-script.patch deleted file mode 100644 index 178545b..0000000 --- a/SOURCES/0062-windows-small-tweaks-of-qemu-ga-firstboot-script.patch +++ /dev/null @@ -1,42 +0,0 @@ -From ab6076b6fe33cfe9a7b5d29bea5b8c24553894cc Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Golembiovsk=C3=BD?= -Date: Wed, 5 Feb 2020 14:11:36 +0100 -Subject: [PATCH] windows: small tweaks of qemu-ga firstboot script -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -- match log file with script name -- restart manually only after successfull install, this also helps - debugging because we can log the installer return code - -Signed-off-by: Tomáš Golembiovský - -(cherry picked from commit 59f9ff40621240a6eed28c4425d3d69d8b21bc0e -in virt-v2v) ---- - v2v/convert_windows.ml | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml -index bdb0092c3..43c1f85de 100644 ---- a/v2v/convert_windows.ml -+++ b/v2v/convert_windows.ml -@@ -430,7 +430,13 @@ popd - fun msi_path -> - let fb_script = "\ - echo Installing qemu-ga from " ^ msi_path ^ " --\"\\" ^ msi_path ^ "\" /qn /forcerestart /l+*vx \"%cd%\\qemu-ga.log\" -+\"\\" ^ msi_path ^ "\" /norestart /qn /l+*vx \"%~dpn0.log\" -+set elvl=!errorlevel! -+echo Done installing qemu-ga error_level=!elvl! -+if !elvl! == 0 ( -+ echo Restarting Windows... -+ shutdown /r /f /c \"rebooted by firstboot script\" -+) - " in - Firstboot.add_firstboot_script g inspect.i_root - ("install " ^ msi_path) fb_script; --- -2.18.4 - diff --git a/SOURCES/0063-windows-fix-detection-of-qemu-ga-installer-on-RHV.patch b/SOURCES/0063-windows-fix-detection-of-qemu-ga-installer-on-RHV.patch deleted file mode 100644 index fe2934c..0000000 --- a/SOURCES/0063-windows-fix-detection-of-qemu-ga-installer-on-RHV.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 52a4f93f1d8bb150167885c94df890af0d00d76d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Golembiovsk=C3=BD?= -Date: Wed, 5 Feb 2020 14:11:35 +0100 -Subject: [PATCH] windows: fix detection of qemu-ga installer on RHV -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The detection was incorrectly matching only 32-bit installer on all -architectures. - -Signed-off-by: Tomáš Golembiovský - -(cherry picked from commit 45acf8d0557bee948c035305a6bafc6c9963a467 -in virt-v2v) ---- - v2v/windows_virtio.ml | 5 ++--- - 1 file changed, 2 insertions(+), 3 deletions(-) - -diff --git a/v2v/windows_virtio.ml b/v2v/windows_virtio.ml -index ea7e5c02d..9a7297344 100644 ---- a/v2v/windows_virtio.ml -+++ b/v2v/windows_virtio.ml -@@ -444,14 +444,13 @@ and virtio_iso_path_matches_qemu_ga path inspect = - * elements. - *) - let lc_name = String.lowercase_ascii (Filename.basename path) in -- lc_name = "rhev-qga.msi" || - match arch, lc_name with - | ("i386", "qemu-ga-x86.msi") - | ("i386", "qemu-ga-i386.msi") -- | ("i386", "RHEV-QGA.msi") -+ | ("i386", "rhev-qga.msi") - | ("x86_64", "qemu-ga-x64.msi") - | ("x86_64", "qemu-ga-x86_64.msi") -- | ("x86_64", "RHEV-QGA64.msi") -> true -+ | ("x86_64", "rhev-qga64.msi") -> true - | _ -> false - - (* The following function is only exported for unit tests. *) --- -2.18.4 - diff --git a/SOURCES/0064-windows-delay-installation-of-qemu-ga-MSI.patch b/SOURCES/0064-windows-delay-installation-of-qemu-ga-MSI.patch deleted file mode 100644 index bbca2bc..0000000 --- a/SOURCES/0064-windows-delay-installation-of-qemu-ga-MSI.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 898b0654a0c4ef55af147a5ca081d2399ce05855 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Golembiovsk=C3=BD?= -Date: Thu, 5 Mar 2020 15:37:13 +0100 -Subject: [PATCH] windows: delay installation of qemu-ga MSI -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Instead of running firstboot script during early boot schedule a task -delayed for 2 minutes. - -During the first boot, after virt-v2v conversion, Windows installs the -drivers injected by virt-v2v. When this installation is finished -Windows enforces some kind of internal reboot. This unfortunately -terminates any running firstboot scripts thus killing the installation -of qemu-ga MSI. - -This is just a best-effort mitigation. It can still happen (e.g. with -slow disk drives) that the drivers are not yet installed when the -delayed installation starts. On the other hand we cannot delay it too -much otherwise we risk that the users logs in and will be doing some -work when the MSI installation starts. After MSI installation finishes -the VM needs to be rebooted which would be annoying if that would happen -under users hands. Although this is not a best fix (that may come later -as it is more complex, e.g. introducing waiting mechanism), the delay as -it is defined works in most cases. And it dramaticaly improves the -situations -- originaly I experienced more than 90% failure rate. - -Signed-off-by: Tomáš Golembiovský - -(cherry picked from commit dc66e78fa37db33e3c7358b7f7c7fa809cf62f9d -in virt-v2v) ---- - v2v/convert_windows.ml | 17 +++++++---------- - 1 file changed, 7 insertions(+), 10 deletions(-) - -diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml -index 43c1f85de..088cd33d9 100644 ---- a/v2v/convert_windows.ml -+++ b/v2v/convert_windows.ml -@@ -428,16 +428,13 @@ popd - and configure_qemu_ga files = - List.iter ( - fun msi_path -> -- let fb_script = "\ --echo Installing qemu-ga from " ^ msi_path ^ " --\"\\" ^ msi_path ^ "\" /norestart /qn /l+*vx \"%~dpn0.log\" --set elvl=!errorlevel! --echo Done installing qemu-ga error_level=!elvl! --if !elvl! == 0 ( -- echo Restarting Windows... -- shutdown /r /f /c \"rebooted by firstboot script\" --) --" in -+ let fb_script = sprintf "\ -+echo Removing any previously scheduled qemu-ga installation -+schtasks.exe /Delete /TN Firstboot-qemu-ga /F -+echo Scheduling delayed installation of qemu-ga from %s -+powershell.exe -command \"$d = (get-date).AddSeconds(120); schtasks.exe /Create /SC ONCE /ST $d.ToString('HH:mm') /SD $d.ToString('MM/dd/yyyy') /RU SYSTEM /TN Firstboot-qemu-ga /TR \\\"C:\\%s /forcerestart /qn /l+*vx C:\\%s.log\\\"\" -+ " -+ msi_path msi_path msi_path in - Firstboot.add_firstboot_script g inspect.i_root - ("install " ^ msi_path) fb_script; - ) files --- -2.18.4 - diff --git a/SOURCES/0065-daemon-xattr-Refactor-code-which-splits-attr-names-f.patch b/SOURCES/0065-daemon-xattr-Refactor-code-which-splits-attr-names-f.patch deleted file mode 100644 index 1aab555..0000000 --- a/SOURCES/0065-daemon-xattr-Refactor-code-which-splits-attr-names-f.patch +++ /dev/null @@ -1,283 +0,0 @@ -From a13f9b06370a6fef6f671f5aa7c23df0f0fd542e Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 12 Mar 2020 13:57:06 +0000 -Subject: [PATCH] daemon: xattr: Refactor code which splits attr names from the - kernel. - -The kernel returns xattr names in a slightly peculiar format. We -parsed this format several times in the code. Refactor this parsing -so we only do it in one place. - -(cherry picked from commit 5c175fe73264bbf1d3ef79bb066dfb6aff902ad1) ---- - daemon/xattr.c | 127 ++++++++++++++++++++++++++++++------------------- - 1 file changed, 79 insertions(+), 48 deletions(-) - -diff --git a/daemon/xattr.c b/daemon/xattr.c -index bc5c2df97..3e1144963 100644 ---- a/daemon/xattr.c -+++ b/daemon/xattr.c -@@ -89,6 +89,36 @@ do_lremovexattr (const char *xattr, const char *path) - return _removexattr (xattr, path, lremovexattr); - } - -+/** -+ * L returns the string C<"foo\0bar\0baz"> of length -+ * C. (The last string in the list is \0-terminated but the \0 -+ * is not included in C). -+ * -+ * This function splits it into a regular list of strings. -+ * -+ * B that the returned list contains pointers to the original -+ * strings in C so be careful that you do not double-free them. -+ */ -+static char ** -+split_attr_names (char *buf, size_t len) -+{ -+ size_t i; -+ DECLARE_STRINGSBUF (ret); -+ -+ for (i = 0; i < len; i += strlen (&buf[i]) + 1) { -+ if (add_string_nodup (&ret, &buf[i]) == -1) { -+ free (ret.argv); -+ return NULL; -+ } -+ } -+ if (end_stringsbuf (&ret) == -1) { -+ free (ret.argv); -+ return NULL; -+ } -+ -+ return take_stringsbuf (&ret); -+} -+ - static int - compare_xattrs (const void *vxa1, const void *vxa2) - { -@@ -106,7 +136,8 @@ getxattrs (const char *path, - { - ssize_t len, vlen; - CLEANUP_FREE char *buf = NULL; -- size_t i, j; -+ CLEANUP_FREE /* not string list */ char **names = NULL; -+ size_t i; - guestfs_int_xattr_list *r = NULL; - - buf = _listxattrs (path, listxattr, &len); -@@ -114,18 +145,17 @@ getxattrs (const char *path, - /* _listxattrs issues reply_with_perror already. */ - goto error; - -+ names = split_attr_names (buf, len); -+ if (names == NULL) -+ goto error; -+ - r = calloc (1, sizeof (*r)); - if (r == NULL) { - reply_with_perror ("calloc"); - goto error; - } - -- /* What we get from the kernel is a string "foo\0bar\0baz" of length -- * len. First count the strings. -- */ -- r->guestfs_int_xattr_list_len = 0; -- for (i = 0; i < (size_t) len; i += strlen (&buf[i]) + 1) -- r->guestfs_int_xattr_list_len++; -+ r->guestfs_int_xattr_list_len = guestfs_int_count_strings (names); - - r->guestfs_int_xattr_list_val = - calloc (r->guestfs_int_xattr_list_len, sizeof (guestfs_int_xattr)); -@@ -134,34 +164,34 @@ getxattrs (const char *path, - goto error; - } - -- for (i = 0, j = 0; i < (size_t) len; i += strlen (&buf[i]) + 1, ++j) { -+ for (i = 0; names[i] != NULL; ++i) { - CHROOT_IN; -- vlen = getxattr (path, &buf[i], NULL, 0); -+ vlen = getxattr (path, names[i], NULL, 0); - CHROOT_OUT; - if (vlen == -1) { -- reply_with_perror ("getxattr"); -+ reply_with_perror ("getxattr: %s", names[i]); - goto error; - } - - if (vlen > XATTR_SIZE_MAX) { - /* The next call to getxattr will fail anyway, so ... */ -- reply_with_error ("extended attribute is too large"); -+ reply_with_error ("%s: extended attribute is too large", names[i]); - goto error; - } - -- r->guestfs_int_xattr_list_val[j].attrname = strdup (&buf[i]); -- r->guestfs_int_xattr_list_val[j].attrval.attrval_val = malloc (vlen); -- r->guestfs_int_xattr_list_val[j].attrval.attrval_len = vlen; -+ r->guestfs_int_xattr_list_val[i].attrname = strdup (names[i]); -+ r->guestfs_int_xattr_list_val[i].attrval.attrval_val = malloc (vlen); -+ r->guestfs_int_xattr_list_val[i].attrval.attrval_len = vlen; - -- if (r->guestfs_int_xattr_list_val[j].attrname == NULL || -- r->guestfs_int_xattr_list_val[j].attrval.attrval_val == NULL) { -+ if (r->guestfs_int_xattr_list_val[i].attrname == NULL || -+ r->guestfs_int_xattr_list_val[i].attrval.attrval_val == NULL) { - reply_with_perror ("malloc"); - goto error; - } - - CHROOT_IN; -- vlen = getxattr (path, &buf[i], -- r->guestfs_int_xattr_list_val[j].attrval.attrval_val, -+ vlen = getxattr (path, names[i], -+ r->guestfs_int_xattr_list_val[i].attrval.attrval_val, - vlen); - CHROOT_OUT; - if (vlen == -1) { -@@ -276,7 +306,7 @@ guestfs_int_xattr_list * - do_internal_lxattrlist (const char *path, char *const *names) - { - guestfs_int_xattr_list *ret = NULL; -- size_t i, j; -+ size_t i; - size_t k, m, nr_attrs; - ssize_t len, vlen; - -@@ -293,6 +323,7 @@ do_internal_lxattrlist (const char *path, char *const *names) - void *newptr; - CLEANUP_FREE char *pathname = NULL; - CLEANUP_FREE char *buf = NULL; -+ CLEANUP_FREE /* not string list */ char **attrnames = NULL; - - /* Be careful in this loop about which errors cause the whole call - * to abort, and which errors allow us to continue processing -@@ -350,12 +381,10 @@ do_internal_lxattrlist (const char *path, char *const *names) - if (len == -1) - continue; /* not fatal */ - -- /* What we get from the kernel is a string "foo\0bar\0baz" of length -- * len. First count the strings. -- */ -- nr_attrs = 0; -- for (i = 0; i < (size_t) len; i += strlen (&buf[i]) + 1) -- nr_attrs++; -+ attrnames = split_attr_names (buf, len); -+ if (attrnames == NULL) -+ goto error; -+ nr_attrs = guestfs_int_count_strings (attrnames); - - newptr = - realloc (ret->guestfs_int_xattr_list_val, -@@ -378,36 +407,36 @@ do_internal_lxattrlist (const char *path, char *const *names) - entry[m].attrval.attrval_val = NULL; - } - -- for (i = 0, j = 0; i < (size_t) len; i += strlen (&buf[i]) + 1, ++j) { -+ for (i = 0; attrnames[i] != NULL; ++i) { - CHROOT_IN; -- vlen = lgetxattr (pathname, &buf[i], NULL, 0); -+ vlen = lgetxattr (pathname, attrnames[i], NULL, 0); - CHROOT_OUT; - if (vlen == -1) { -- reply_with_perror ("getxattr"); -+ reply_with_perror ("getxattr: %s", attrnames[i]); - goto error; - } - - if (vlen > XATTR_SIZE_MAX) { -- reply_with_error ("extended attribute is too large"); -+ reply_with_error ("%s: extended attribute is too large", attrnames[i]); - goto error; - } - -- entry[j+1].attrname = strdup (&buf[i]); -- entry[j+1].attrval.attrval_val = malloc (vlen); -- entry[j+1].attrval.attrval_len = vlen; -+ entry[i+1].attrname = strdup (attrnames[i]); -+ entry[i+1].attrval.attrval_val = malloc (vlen); -+ entry[i+1].attrval.attrval_len = vlen; - -- if (entry[j+1].attrname == NULL || -- entry[j+1].attrval.attrval_val == NULL) { -+ if (entry[i+1].attrname == NULL || -+ entry[i+1].attrval.attrval_val == NULL) { - reply_with_perror ("malloc"); - goto error; - } - - CHROOT_IN; -- vlen = lgetxattr (pathname, &buf[i], -- entry[j+1].attrval.attrval_val, vlen); -+ vlen = lgetxattr (pathname, attrnames[i], -+ entry[i+1].attrval.attrval_val, vlen); - CHROOT_OUT; - if (vlen == -1) { -- reply_with_perror ("getxattr"); -+ reply_with_perror ("getxattr: %s", attrnames[i]); - goto error; - } - } -@@ -510,6 +539,7 @@ copy_xattrs (const char *src, const char *dest) - { - ssize_t len, vlen, ret, attrval_len = 0; - CLEANUP_FREE char *buf = NULL, *attrval = NULL; -+ CLEANUP_FREE /* not string list */ char **names = NULL; - size_t i; - - buf = _listxattrs (src, listxattr, &len); -@@ -517,21 +547,22 @@ copy_xattrs (const char *src, const char *dest) - /* _listxattrs issues reply_with_perror already. */ - goto error; - -- /* What we get from the kernel is a string "foo\0bar\0baz" of length -- * len. -- */ -- for (i = 0; i < (size_t) len; i += strlen (&buf[i]) + 1) { -+ names = split_attr_names (buf, len); -+ if (names == NULL) -+ goto error; -+ -+ for (i = 0; names[i] != NULL; ++i) { - CHROOT_IN; -- vlen = getxattr (src, &buf[i], NULL, 0); -+ vlen = getxattr (src, names[i], NULL, 0); - CHROOT_OUT; - if (vlen == -1) { -- reply_with_perror ("getxattr: %s, %s", src, &buf[i]); -+ reply_with_perror ("getxattr: %s, %s", src, names[i]); - goto error; - } - - if (vlen > XATTR_SIZE_MAX) { - /* The next call to getxattr will fail anyway, so ... */ -- reply_with_error ("extended attribute is too large"); -+ reply_with_error ("%s: extended attribute is too large", names[i]); - goto error; - } - -@@ -546,18 +577,18 @@ copy_xattrs (const char *src, const char *dest) - } - - CHROOT_IN; -- vlen = getxattr (src, &buf[i], attrval, vlen); -+ vlen = getxattr (src, names[i], attrval, vlen); - CHROOT_OUT; - if (vlen == -1) { -- reply_with_perror ("getxattr: %s, %s", src, &buf[i]); -+ reply_with_perror ("getxattr: %s, %s", src, names[i]); - goto error; - } - - CHROOT_IN; -- ret = setxattr (dest, &buf[i], attrval, vlen, 0); -+ ret = setxattr (dest, names[i], attrval, vlen, 0); - CHROOT_OUT; - if (ret == -1) { -- reply_with_perror ("setxattr: %s, %s", dest, &buf[i]); -+ reply_with_perror ("setxattr: %s, %s", dest, names[i]); - goto error; - } - } --- -2.18.4 - diff --git a/SOURCES/0066-daemon-Add-filter_list-utility-function.patch b/SOURCES/0066-daemon-Add-filter_list-utility-function.patch deleted file mode 100644 index 11cdb18..0000000 --- a/SOURCES/0066-daemon-Add-filter_list-utility-function.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 2e5a8775941b5767abcfcf93f9f84c9560e0f378 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 12 Mar 2020 13:59:05 +0000 -Subject: [PATCH] daemon: Add filter_list utility function. - -For filtering lists of strings based on a predicate. - -(cherry picked from commit af8ed266a282bb20882a9ffb611bd64243d19218) ---- - daemon/daemon.h | 2 ++ - daemon/utils.c | 30 ++++++++++++++++++++++++++++++ - 2 files changed, 32 insertions(+) - -diff --git a/daemon/daemon.h b/daemon/daemon.h -index 66bfdc49e..115591728 100644 ---- a/daemon/daemon.h -+++ b/daemon/daemon.h -@@ -22,6 +22,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -74,6 +75,7 @@ extern void free_stringsbuf (struct stringsbuf *sb); - extern struct stringsbuf split_lines_sb (char *str); - extern char **split_lines (char *str); - extern char **empty_list (void); -+extern char **filter_list (bool (*p) (const char *), char **strs); - extern int is_power_of_2 (unsigned long v); - extern void trim (char *str); - extern int parse_btrfsvol (const char *desc, mountable_t *mountable); -diff --git a/daemon/utils.c b/daemon/utils.c -index c3f88bcab..e87233d0f 100644 ---- a/daemon/utils.c -+++ b/daemon/utils.c -@@ -24,6 +24,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -482,6 +483,35 @@ empty_list (void) - return ret.argv; - } - -+/** -+ * Filter a list of strings. Returns a newly allocated list of only -+ * the strings where C

. -+ * -+ * B it does not copy the strings, be careful not to double-free -+ * them. -+ */ -+char ** -+filter_list (bool (*p) (const char *str), char **strs) -+{ -+ DECLARE_STRINGSBUF (ret); -+ size_t i; -+ -+ for (i = 0; strs[i] != NULL; ++i) { -+ if (p (strs[i])) { -+ if (add_string_nodup (&ret, strs[i]) == -1) { -+ free (ret.argv); -+ return NULL; -+ } -+ } -+ } -+ if (end_stringsbuf (&ret) == -1) { -+ free (ret.argv); -+ return NULL; -+ } -+ -+ return take_stringsbuf (&ret); -+} -+ - /** - * Skip leading and trailing whitespace, updating the original string - * in-place. --- -2.18.4 - diff --git a/SOURCES/0067-daemon-xattr-Filter-out-user.WofCompressedData-from-.patch b/SOURCES/0067-daemon-xattr-Filter-out-user.WofCompressedData-from-.patch deleted file mode 100644 index 542fd05..0000000 --- a/SOURCES/0067-daemon-xattr-Filter-out-user.WofCompressedData-from-.patch +++ /dev/null @@ -1,120 +0,0 @@ -From fb3136e8abe5fec9e8a749e5879b75c696f7ba0e Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 12 Mar 2020 14:40:05 +0000 -Subject: [PATCH] daemon: xattr: Filter out user.WofCompressedData from xattrs - (RHBZ#1811539). - -See comment in code for justification. - -Thanks: Yongkui Guo for finding the bug. -(cherry picked from commit c2c11382bbeb4500f3388a31ffd08cfc18b0de40) ---- - daemon/xattr.c | 43 ++++++++++++++++++++++++++++++++++++++++--- - 1 file changed, 40 insertions(+), 3 deletions(-) - -diff --git a/daemon/xattr.c b/daemon/xattr.c -index 3e1144963..43e49384f 100644 ---- a/daemon/xattr.c -+++ b/daemon/xattr.c -@@ -19,6 +19,8 @@ - #include - - #include -+#include -+#include - #include - #include - -@@ -119,6 +121,29 @@ split_attr_names (char *buf, size_t len) - return take_stringsbuf (&ret); - } - -+/* We hide one extended attribute automatically. This is used by NTFS -+ * to store the compressed contents of a file when using "CompactOS" -+ * (per-file compression). I justify this by: -+ * -+ * (1) The attribute is only used internally by NTFS. The actual file -+ * contents are still available. -+ * -+ * (2) It's probably not valid to copy this attribute when copying the -+ * other attributes of a file. ntfs-3g-system-compression doesn't -+ * support writing compressed files. -+ * -+ * (3) This file isn't readable by the Linux kernel. Reading it will -+ * always return -E2BIG (RHBZ#1811539). So we can't read it even if -+ * we wanted to. -+ * -+ * (4) The Linux kernel itself hides other attributes. -+ */ -+static bool -+not_hidden_xattr (const char *attrname) -+{ -+ return STRNEQ (attrname, "user.WofCompressedData"); -+} -+ - static int - compare_xattrs (const void *vxa1, const void *vxa2) - { -@@ -136,6 +161,7 @@ getxattrs (const char *path, - { - ssize_t len, vlen; - CLEANUP_FREE char *buf = NULL; -+ CLEANUP_FREE /* not string list */ char **names_unfiltered = NULL; - CLEANUP_FREE /* not string list */ char **names = NULL; - size_t i; - guestfs_int_xattr_list *r = NULL; -@@ -145,7 +171,10 @@ getxattrs (const char *path, - /* _listxattrs issues reply_with_perror already. */ - goto error; - -- names = split_attr_names (buf, len); -+ names_unfiltered = split_attr_names (buf, len); -+ if (names_unfiltered == NULL) -+ goto error; -+ names = filter_list (not_hidden_xattr, names_unfiltered); - if (names == NULL) - goto error; - -@@ -323,6 +352,7 @@ do_internal_lxattrlist (const char *path, char *const *names) - void *newptr; - CLEANUP_FREE char *pathname = NULL; - CLEANUP_FREE char *buf = NULL; -+ CLEANUP_FREE /* not string list */ char **attrnames_unfiltered = NULL; - CLEANUP_FREE /* not string list */ char **attrnames = NULL; - - /* Be careful in this loop about which errors cause the whole call -@@ -381,7 +411,10 @@ do_internal_lxattrlist (const char *path, char *const *names) - if (len == -1) - continue; /* not fatal */ - -- attrnames = split_attr_names (buf, len); -+ attrnames_unfiltered = split_attr_names (buf, len); -+ if (attrnames_unfiltered == NULL) -+ goto error; -+ attrnames = filter_list (not_hidden_xattr, attrnames_unfiltered); - if (attrnames == NULL) - goto error; - nr_attrs = guestfs_int_count_strings (attrnames); -@@ -539,6 +572,7 @@ copy_xattrs (const char *src, const char *dest) - { - ssize_t len, vlen, ret, attrval_len = 0; - CLEANUP_FREE char *buf = NULL, *attrval = NULL; -+ CLEANUP_FREE /* not string list */ char **names_unfiltered = NULL; - CLEANUP_FREE /* not string list */ char **names = NULL; - size_t i; - -@@ -547,7 +581,10 @@ copy_xattrs (const char *src, const char *dest) - /* _listxattrs issues reply_with_perror already. */ - goto error; - -- names = split_attr_names (buf, len); -+ names_unfiltered = split_attr_names (buf, len); -+ if (names_unfiltered == NULL) -+ goto error; -+ names = filter_list (not_hidden_xattr, names_unfiltered); - if (names == NULL) - goto error; - --- -2.18.4 - diff --git a/SOURCES/0068-mltools-add-run_in_guest_command-helper.patch b/SOURCES/0068-mltools-add-run_in_guest_command-helper.patch deleted file mode 100644 index 655db0b..0000000 --- a/SOURCES/0068-mltools-add-run_in_guest_command-helper.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 9a8246e91ac0fa38d96691dc6025cb8b117f9cb2 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Mon, 4 May 2020 15:14:46 +0200 -Subject: [PATCH] mltools: add run_in_guest_command helper - -Add an helper function to run a command in the guest, checking for the -host/guest compatibility. This is mostly extracted from the internal -do_run helper currently in the Customize_run module of virt-customize. - -(cherry picked from commit e73eca3b73f7d0a54615c5dc55eadd09dc170035 -in libguestfs-common) ---- - common/mltools/tools_utils.ml | 50 ++++++++++++++++++++++++++++++++++ - common/mltools/tools_utils.mli | 10 +++++++ - 2 files changed, 60 insertions(+) - -diff --git a/common/mltools/tools_utils.ml b/common/mltools/tools_utils.ml -index 127180225..d54ec581e 100644 ---- a/common/mltools/tools_utils.ml -+++ b/common/mltools/tools_utils.ml -@@ -679,3 +679,53 @@ let with_timeout op timeout ?(sleep = 2) fn = - loop () - in - loop () -+ -+let run_in_guest_command g root ?logfile ?incompatible_fn cmd = -+ (* Is the host_cpu compatible with the guest arch? ie. Can we -+ * run commands in this guest? -+ *) -+ let guest_arch = g#inspect_get_arch root in -+ let guest_arch_compatible = guest_arch_compatible guest_arch in -+ if not guest_arch_compatible then ( -+ match incompatible_fn with -+ | None -> () -+ | Some fn -> fn () -+ ) -+ else ( -+ (* Add a prologue to the scripts: -+ * - Pass environment variables through from the host. -+ * - Optionally send stdout and stderr to a log file so we capture -+ * all output in error messages. -+ * - Use setarch when running x86_64 host + i686 guest. -+ *) -+ let env_vars = -+ List.filter_map ( -+ fun name -> -+ try Some (sprintf "export %s=%s" name (quote (Sys.getenv name))) -+ with Not_found -> None -+ ) [ "http_proxy"; "https_proxy"; "ftp_proxy"; "no_proxy" ] in -+ let env_vars = String.concat "\n" env_vars ^ "\n" in -+ -+ let cmd = -+ match Guestfs_config.host_cpu, guest_arch with -+ | "x86_64", ("i386"|"i486"|"i586"|"i686") -> -+ sprintf "setarch i686 <<\"__EOCMD\" -+%s -+__EOCMD -+" cmd -+ | _ -> cmd in -+ -+ let logfile_redirect = -+ match logfile with -+ | None -> "" -+ | Some logfile -> sprintf "exec >>%s 2>&1" (quote logfile) in -+ -+ let cmd = sprintf "\ -+%s -+%s -+%s -+" (logfile_redirect) env_vars cmd in -+ -+ debug "running command:\n%s" cmd; -+ ignore (g#sh cmd) -+ ) -diff --git a/common/mltools/tools_utils.mli b/common/mltools/tools_utils.mli -index ab70f583e..102abff4d 100644 ---- a/common/mltools/tools_utils.mli -+++ b/common/mltools/tools_utils.mli -@@ -212,3 +212,13 @@ val with_timeout : string -> int -> ?sleep:int -> (unit -> 'a option) -> 'a - calls {!error} and the program exits. The error message will - contain the diagnostic string [op] to identify the operation - which timed out. *) -+ -+val run_in_guest_command : Guestfs.guestfs -> string -> ?logfile:string -> ?incompatible_fn:(unit -> unit) -> string -> unit -+(** [run_in_guest_command g root ?incompatible_archs_fn cmd] -+ runs a command in the guest, which is already mounted for the -+ specified [root]. The command is run directly in case the -+ architecture of the host and the guest are compatible, optionally -+ calling [?incompatible_fn] in case they are not. -+ -+ [?logfile] is an optional file in the guest to where redirect -+ stdout and stderr of the command. *) --- -2.18.4 - diff --git a/SOURCES/0069-customize-port-do_run-to-run_in_guest_command.patch b/SOURCES/0069-customize-port-do_run-to-run_in_guest_command.patch deleted file mode 100644 index 1ec70cc..0000000 --- a/SOURCES/0069-customize-port-do_run-to-run_in_guest_command.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 02f8969558ecadc13726068ccb732595c5d29565 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Mon, 4 May 2020 11:55:41 +0200 -Subject: [PATCH] customize: port do_run to run_in_guest_command - -Make use of the new helper function in Tools_utils to run commands in -the guest. - -(cherry picked from commit b25e3495f522378f59d201526d7d2d02c2bf6f3f) ---- - customize/customize_run.ml | 46 +++++--------------------------------- - 1 file changed, 6 insertions(+), 40 deletions(-) - -diff --git a/customize/customize_run.ml b/customize/customize_run.ml -index 3eacdaca0..f2ee20413 100644 ---- a/customize/customize_run.ml -+++ b/customize/customize_run.ml -@@ -30,12 +30,6 @@ open Append_line - module G = Guestfs - - let run (g : G.guestfs) root (ops : ops) = -- (* Is the host_cpu compatible with the guest arch? ie. Can we -- * run commands in this guest? -- *) -- let guest_arch = g#inspect_get_arch root in -- let guest_arch_compatible = guest_arch_compatible guest_arch in -- - (* Based on the guest type, choose a log file location. *) - let logfile = - match g#inspect_get_type root with -@@ -54,42 +48,14 @@ let run (g : G.guestfs) root (ops : ops) = - - (* Useful wrapper for scripts. *) - let do_run ~display ?(warn_failed_no_network = false) cmd = -- if not guest_arch_compatible then -+ let incompatible_fn () = -+ let guest_arch = g#inspect_get_arch root in - error (f_"host cpu (%s) and guest arch (%s) are not compatible, so you cannot use command line options that involve running commands in the guest. Use --firstboot scripts instead.") -- Guestfs_config.host_cpu guest_arch; -+ Guestfs_config.host_cpu guest_arch -+ in - -- (* Add a prologue to the scripts: -- * - Pass environment variables through from the host. -- * - Send stdout and stderr to a log file so we capture all output -- * in error messages. -- * - Use setarch when running x86_64 host + i686 guest. -- * Also catch errors and dump the log file completely on error. -- *) -- let env_vars = -- List.filter_map ( -- fun name -> -- try Some (sprintf "export %s=%s" name (quote (Sys.getenv name))) -- with Not_found -> None -- ) [ "http_proxy"; "https_proxy"; "ftp_proxy"; "no_proxy" ] in -- let env_vars = String.concat "\n" env_vars ^ "\n" in -- -- let cmd = -- match Guestfs_config.host_cpu, guest_arch with -- | "x86_64", ("i386"|"i486"|"i586"|"i686") -> -- sprintf "setarch i686 <<\"__EOCMD\" --%s --__EOCMD --" cmd -- | _ -> cmd in -- -- let cmd = sprintf "\ --exec >>%s 2>&1 --%s --%s --" (quote logfile) env_vars cmd in -- -- debug "running command:\n%s" cmd; -- try ignore (g#sh cmd) -+ try -+ run_in_guest_command g root ~logfile ~incompatible_fn cmd - with - G.Error msg -> - debug_logfile (); --- -2.18.4 - diff --git a/SOURCES/0070-sysprep-add-a-update_system_ca_store-side-effect.patch b/SOURCES/0070-sysprep-add-a-update_system_ca_store-side-effect.patch deleted file mode 100644 index e8ad4ff..0000000 --- a/SOURCES/0070-sysprep-add-a-update_system_ca_store-side-effect.patch +++ /dev/null @@ -1,138 +0,0 @@ -From f4613f408e4584741d08aa39c950de304f5e18db Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Mon, 4 May 2020 12:05:18 +0200 -Subject: [PATCH] sysprep: add a update_system_ca_store side effect - -Add a simple side effect to make operation flag that a regeneration of -the system CA store is needed. In case it is flagged, regenerate the -system CA store directly, or using a firstboot script in case of -incompatible architectures. - -This change is almost a no-op, since no operation requires the -regeneration of the system CA store yet. - -(cherry picked from commit bb7fc6d0a1ed670d16a92d2afd9ff2f876edc595) ---- - sysprep/main.ml | 5 +++++ - sysprep/sysprep_operation.ml | 3 +++ - sysprep/sysprep_operation.mli | 2 ++ - sysprep/utils.ml | 32 ++++++++++++++++++++++++++++++++ - sysprep/utils.mli | 4 ++++ - 5 files changed, 46 insertions(+) - -diff --git a/sysprep/main.ml b/sysprep/main.ml -index 04fd7b23c..4b03d5b48 100644 ---- a/sysprep/main.ml -+++ b/sysprep/main.ml -@@ -25,6 +25,7 @@ open Common_gettext.Gettext - open Getopt.OptionName - - open Sysprep_operation -+open Utils - - module G = Guestfs - -@@ -236,6 +237,10 @@ read the man page virt-sysprep(1). - Sysprep_operation.perform_operations_on_filesystems - ?operations g root side_effects; - -+ (* Do we need to update the system CA store? *) -+ if side_effects#get_update_system_ca_store then -+ update_system_ca_store g root; -+ - (* Unmount everything in this guest. *) - g#umount_all (); - -diff --git a/sysprep/sysprep_operation.ml b/sysprep/sysprep_operation.ml -index 0013ff504..53f042402 100644 ---- a/sysprep/sysprep_operation.ml -+++ b/sysprep/sysprep_operation.ml -@@ -27,10 +27,13 @@ class filesystem_side_effects = - object - val mutable m_created_file = false - val mutable m_changed_file = false -+ val mutable m_update_system_ca_store = false - method created_file () = m_created_file <- true - method get_created_file = m_created_file - method changed_file () = m_changed_file <- true - method get_changed_file = m_changed_file -+ method update_system_ca_store () = m_update_system_ca_store <- true -+ method get_update_system_ca_store = m_update_system_ca_store - end - - class device_side_effects = object end -diff --git a/sysprep/sysprep_operation.mli b/sysprep/sysprep_operation.mli -index 3d9f12550..2a02d5e79 100644 ---- a/sysprep/sysprep_operation.mli -+++ b/sysprep/sysprep_operation.mli -@@ -23,6 +23,8 @@ class filesystem_side_effects : object - method get_created_file : bool - method changed_file : unit -> unit - method get_changed_file : bool -+ method update_system_ca_store : unit -> unit -+ method get_update_system_ca_store : bool - end - (** The callback should indicate if it has side effects by calling - methods in this class. *) -diff --git a/sysprep/utils.ml b/sysprep/utils.ml -index 4c45d42de..29460b3c0 100644 ---- a/sysprep/utils.ml -+++ b/sysprep/utils.ml -@@ -20,6 +20,9 @@ - - open Printf - -+open Tools_utils -+open Common_gettext.Gettext -+ - let rec pod_of_list ?(style = `Dot) xs = - match style with - | `Verbatim -> String.concat "\n" (List.map ((^) " ") xs) -@@ -31,3 +34,32 @@ and _pod_of_list delim xs = - "=over 4\n\n" ^ - String.concat "" (List.map (sprintf "=item %s\n\n%s\n\n" delim) xs) ^ - "=back" -+ -+let rec update_system_ca_store g root = -+ let cmd = update_system_ca_store_command g root in -+ match cmd with -+ | None -> () -+ | Some cmd -> -+ (* Try to run the command directly if possible, adding it as -+ * firstboot script in case of incompatible architectures. -+ *) -+ let cmd = String.concat " " cmd in -+ let incompatible_fn () = -+ Firstboot.add_firstboot_script g root cmd cmd -+ in -+ -+ run_in_guest_command g root ~incompatible_fn cmd -+ -+and update_system_ca_store_command g root = -+ let typ = g#inspect_get_type root in -+ let distro = g#inspect_get_distro root in -+ match typ, distro with -+ | "linux", ("fedora"|"rhel"|"centos"|"scientificlinux"|"oraclelinux"|"redhat-based") -> -+ Some [ "update-ca-trust"; "extract" ] -+ -+ | "linux", ("debian"|"ubuntu"|"kalilinux") -> -+ Some [ "update-ca-certificates" ] -+ -+ | _, _ -> -+ warning (f_"updating the system CA store on this guest %s/%s is not supported") typ distro; -+ None -diff --git a/sysprep/utils.mli b/sysprep/utils.mli -index a57a0d876..82779620e 100644 ---- a/sysprep/utils.mli -+++ b/sysprep/utils.mli -@@ -26,3 +26,7 @@ val pod_of_list : ?style:[`Verbatim|`Star|`Dash|`Dot] -> string list -> string - use a space-indented (verbatim) block. [`Star], [`Dash] or [`Dot] - meaning use a real list with [*], [-] or [·]. The default - style is [·] ([`Dot]). *) -+ -+val update_system_ca_store : Guestfs.guestfs -> string -> unit -+(** Update the system CA store on the guest for the specified root -+ (which is fully mounted). *) --- -2.18.4 - diff --git a/SOURCES/0071-sysprep-ca-certificates-request-system-CA-store-upda.patch b/SOURCES/0071-sysprep-ca-certificates-request-system-CA-store-upda.patch deleted file mode 100644 index 128bd01..0000000 --- a/SOURCES/0071-sysprep-ca-certificates-request-system-CA-store-upda.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 315bf96d182d5626e5935aaf57b0787fedffc62b Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Mon, 4 May 2020 12:15:43 +0200 -Subject: [PATCH] sysprep: ca-certificates: request system CA store update - -In case any certificate is removed from the guest, regenerate the system -CA store. - -(cherry picked from commit b9065fa7adc93123c53f4827e11dad6b210b7d4b) ---- - sysprep/sysprep_operation_ca_certificates.ml | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/sysprep/sysprep_operation_ca_certificates.ml b/sysprep/sysprep_operation_ca_certificates.ml -index e481cebf8..a2b7986c1 100644 ---- a/sysprep/sysprep_operation_ca_certificates.ml -+++ b/sysprep/sysprep_operation_ca_certificates.ml -@@ -39,7 +39,11 @@ let ca_certificates_perform (g : Guestfs.guestfs) root side_effects = - let set = StringSet.diff set excepts in - StringSet.iter ( - fun filename -> -- try g#rm filename with G.Error _ -> () -+ try -+ g#rm filename; -+ side_effects#update_system_ca_store () -+ with -+ G.Error _ -> () - ) set - ) - -@@ -48,6 +52,8 @@ let op = { - name = "ca-certificates"; - enabled_by_default = false; - heading = s_"Remove CA certificates in the guest"; -+ pod_description = Some (s_"\ -+In case any certificate is removed, the system CA store is updated."); - perform_on_filesystems = Some ca_certificates_perform; - } - --- -2.18.4 - diff --git a/SOURCES/0072-sysprep-add-IPA-offline-unenrollment-RHBZ-1789592.patch b/SOURCES/0072-sysprep-add-IPA-offline-unenrollment-RHBZ-1789592.patch deleted file mode 100644 index 13105f7..0000000 --- a/SOURCES/0072-sysprep-add-IPA-offline-unenrollment-RHBZ-1789592.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 90bb3cd1793275da50d509570d07d279989e2c45 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Thu, 7 May 2020 13:53:21 +0200 -Subject: [PATCH] sysprep: add IPA offline unenrollment (RHBZ#1789592) -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This new operation unenrolls the guest from a IPA server offline, by -removing the configuration files and certificates. - -Thanks to Christian Heimes and François Cami for the hints. - -(cherry picked from commit 0a53e2c7fc4fe2aa69052134230db0804849b470) ---- - sysprep/Makefile.am | 1 + - sysprep/sysprep_operation_ipa_client.ml | 66 +++++++++++++++++++++++++ - 2 files changed, 67 insertions(+) - create mode 100644 sysprep/sysprep_operation_ipa_client.ml - -diff --git a/sysprep/Makefile.am b/sysprep/Makefile.am -index e6269c3f7..79266314b 100644 ---- a/sysprep/Makefile.am -+++ b/sysprep/Makefile.am -@@ -43,6 +43,7 @@ operations = \ - flag_reconfiguration \ - firewall_rules \ - fs_uuids \ -+ ipa_client \ - kerberos_data \ - lvm_uuids \ - logfiles \ -diff --git a/sysprep/sysprep_operation_ipa_client.ml b/sysprep/sysprep_operation_ipa_client.ml -new file mode 100644 -index 000000000..6e64a754a ---- /dev/null -+++ b/sysprep/sysprep_operation_ipa_client.ml -@@ -0,0 +1,66 @@ -+(* virt-sysprep -+ * Copyright (C) 2020 Red Hat Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ *) -+ -+open Sysprep_operation -+open Common_gettext.Gettext -+ -+module G = Guestfs -+ -+let ipa_client_perform (g : Guestfs.guestfs) root side_effects = -+ let typ = g#inspect_get_type root in -+ if typ = "linux" then ( -+ (* Simple paths with no side effects. *) -+ let paths = [ "/etc/ipa/ca.crt"; -+ "/etc/ipa/default.conf"; -+ "/var/lib/ipa-client/sysrestore/*"; -+ "/var/lib/ipa-client/pki/*" ] in -+ let paths = List.concat (List.map Array.to_list (List.map g#glob_expand paths)) in -+ List.iter ( -+ fun filename -> -+ try g#rm filename with G.Error _ -> () -+ ) paths; -+ -+ (* Certificates in the system CA store. *) -+ let certs = [ "/etc/pki/ca-trust/source/anchors/ipa-ca.crt"; -+ "/usr/local/share/ca-certificates/ipa-ca.crt"; -+ "/etc/pki/ca-trust/source/ipa.p11-kit" ] in -+ List.iter ( -+ fun filename -> -+ try -+ g#rm filename; -+ side_effects#update_system_ca_store () -+ with -+ G.Error _ -> () -+ ) certs -+ ) -+ -+let op = { -+ defaults with -+ name = "ipa-client"; -+ enabled_by_default = true; -+ heading = s_"Remove the IPA files"; -+ pod_description = Some (s_"\ -+Remove all the files related to an IPA (Identity, Policy, Audit) system. -+This effectively unenrolls the guest from an IPA server without interacting -+with it. -+ -+This operation does not run C."); -+ perform_on_filesystems = Some ipa_client_perform; -+} -+ -+let () = register_operation op --- -2.18.4 - diff --git a/SOURCES/0073-sysprep-add-Kerberos-keytab-file-removal.patch b/SOURCES/0073-sysprep-add-Kerberos-keytab-file-removal.patch deleted file mode 100644 index 844fef8..0000000 --- a/SOURCES/0073-sysprep-add-Kerberos-keytab-file-removal.patch +++ /dev/null @@ -1,81 +0,0 @@ -From c8dc0b229b3cbcb72ca90ddf025087586a7d2e38 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Thu, 7 May 2020 14:02:30 +0200 -Subject: [PATCH] sysprep: add Kerberos keytab file removal -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This new operation removes the Kerberos /etc/krb5.keytab file from the -guest. - -Thanks to Christian Heimes and François Cami for the hints. - -Related to RHBZ#1789592. - -(cherry picked from commit faa5d8507f552e05435312f16d9e50f613a13615) ---- - sysprep/Makefile.am | 1 + - .../sysprep_operation_kerberos_hostkeytab.ml | 38 +++++++++++++++++++ - 2 files changed, 39 insertions(+) - create mode 100644 sysprep/sysprep_operation_kerberos_hostkeytab.ml - -diff --git a/sysprep/Makefile.am b/sysprep/Makefile.am -index 79266314b..a99957306 100644 ---- a/sysprep/Makefile.am -+++ b/sysprep/Makefile.am -@@ -45,6 +45,7 @@ operations = \ - fs_uuids \ - ipa_client \ - kerberos_data \ -+ kerberos_hostkeytab \ - lvm_uuids \ - logfiles \ - machine_id \ -diff --git a/sysprep/sysprep_operation_kerberos_hostkeytab.ml b/sysprep/sysprep_operation_kerberos_hostkeytab.ml -new file mode 100644 -index 000000000..cb3023353 ---- /dev/null -+++ b/sysprep/sysprep_operation_kerberos_hostkeytab.ml -@@ -0,0 +1,38 @@ -+(* virt-sysprep -+ * Copyright (C) 2020 Red Hat Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ *) -+ -+open Sysprep_operation -+open Common_gettext.Gettext -+ -+module G = Guestfs -+ -+let kerberos_hostkeytab_perform (g : Guestfs.guestfs) root side_effects = -+ let typ = g#inspect_get_type root in -+ if typ <> "windows" then ( -+ (try g#rm "/etc/krb5.keytab" with G.Error _ -> ()) -+ ) -+ -+let op = { -+ defaults with -+ name = "kerberos-hostkeytab"; -+ enabled_by_default = true; -+ heading = s_"Remove the Kerberos host keytab file in the guest"; -+ perform_on_filesystems = Some kerberos_hostkeytab_perform; -+} -+ -+let () = register_operation op --- -2.18.4 - diff --git a/SOURCES/0074-vCenter-fix-parsing-of-HTTP-status-string-RHBZ-18373.patch b/SOURCES/0074-vCenter-fix-parsing-of-HTTP-status-string-RHBZ-18373.patch deleted file mode 100644 index 3387816..0000000 --- a/SOURCES/0074-vCenter-fix-parsing-of-HTTP-status-string-RHBZ-18373.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 318aa975b212c9b8778606ce440c95682f99c700 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Tue, 19 May 2020 12:14:18 +0200 -Subject: [PATCH] vCenter: fix parsing of HTTP status string (RHBZ#1837328) - -vCenter 7 answers with an HTTP/2 status string, so we cannot extract -the status code from it by using fixed positions in that string. -Hence, pick the status code by reading what's after the whitespace. - -Tested with vCenter 6.5 and 7. - -(cherry picked from commit d2aa82317964d62fcc8dc7b6737773003d04b998 -in virt-v2v) ---- - v2v/vCenter.ml | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml -index b1b9f9b15..b15e2f7d0 100644 ---- a/v2v/vCenter.ml -+++ b/v2v/vCenter.ml -@@ -213,7 +213,9 @@ and fetch_headers_from_url password_file uri sslverify https_url = - | [] -> - dump_response stderr; - error (f_"vcenter: no status code in output of ‘curl’ command. Is ‘curl’ installed?") -- | ss -> String.sub (List.hd (List.rev ss)) 9 3 in -+ | ss -> -+ let s = List.hd (List.rev ss) in -+ String.sub s (String.index s ' ' + 1) 3 in - - let headers = - List.map ( --- -2.18.4 - diff --git a/SOURCES/0079-RHEL-8-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch b/SOURCES/0079-RHEL-8-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch deleted file mode 100644 index e538c96..0000000 --- a/SOURCES/0079-RHEL-8-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch +++ /dev/null @@ -1,33 +0,0 @@ -From a2c0ccac7b1bcb451987b6c1b85e3a5ee48b8949 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Sun, 28 Sep 2014 19:14:43 +0100 -Subject: [PATCH] RHEL 8: v2v: Select correct qemu binary for -o qemu mode - (RHBZ#1147313). - -RHEL 8 does not have qemu-system-x86_64 (etc), and in addition the -qemu binary is located in /usr/libexec. Encode the path to this -binary directly in the script. - -Note that we don't support people running qemu directly like this. -It's just for quick testing of converted VMs, and to help us with -support cases. ---- - v2v/output_qemu.ml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/v2v/output_qemu.ml b/v2v/output_qemu.ml -index 1f6798aaf..8665d7b5c 100644 ---- a/v2v/output_qemu.ml -+++ b/v2v/output_qemu.ml -@@ -81,7 +81,7 @@ object - * module deals with shell and qemu comma quoting. - *) - let cmd = Qemuopts.create () in -- Qemuopts.set_binary_by_arch cmd (Some guestcaps.gcaps_arch); -+ Qemuopts.set_binary cmd "/usr/libexec/qemu-kvm"; - - let flag = Qemuopts.flag cmd - and arg = Qemuopts.arg cmd --- -2.18.4 - diff --git a/SOURCES/0080-RHEL-8-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch b/SOURCES/0080-RHEL-8-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch deleted file mode 100644 index 68db0b0..0000000 --- a/SOURCES/0080-RHEL-8-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch +++ /dev/null @@ -1,105 +0,0 @@ -From 4190aec225ec3bf4d1e39fbde89131d4c8a6a9a7 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 30 Sep 2014 10:50:27 +0100 -Subject: [PATCH] RHEL 8: v2v: Disable the --qemu-boot option (RHBZ#1147313). - -This cannot work because there is no Gtk or SDL output mode -in RHEL 8's qemu-kvm. - -In addition you will have to edit the -display option in the -qemu script. ---- - v2v/cmdline.ml | 3 ++- - v2v/virt-v2v-output-local.pod | 6 ++---- - v2v/virt-v2v.pod | 13 ------------- - 3 files changed, 4 insertions(+), 18 deletions(-) - -diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml -index 686631271..e3578ddcb 100644 ---- a/v2v/cmdline.ml -+++ b/v2v/cmdline.ml -@@ -262,7 +262,6 @@ let parse_cmdline () = - s_"Estimate size of source and stop"; - [ L"print-source" ], Getopt.Set print_source, - s_"Print source and stop"; -- [ L"qemu-boot" ], Getopt.Set qemu_boot, s_"Boot in qemu (-o qemu only)"; - [ L"root" ], Getopt.String ("ask|... ", set_root_choice), - s_"How to choose root filesystem"; - [ L"vddk-config" ], Getopt.String ("filename", set_input_option_compat "vddk-config"), -@@ -640,6 +639,8 @@ read the man page virt-v2v(1). - | Some d when not (is_directory d) -> - error (f_"-os %s: output directory does not exist or is not a directory") d - | Some d -> d in -+ if qemu_boot then -+ error (f_"-o qemu: the --qemu-boot option cannot be used in RHEL"); - Output_qemu.output_qemu os qemu_boot, - output_format, output_alloc - -diff --git a/v2v/virt-v2v-output-local.pod b/v2v/virt-v2v-output-local.pod -index 7c397c0a4..09a11a7b0 100644 ---- a/v2v/virt-v2v-output-local.pod -+++ b/v2v/virt-v2v-output-local.pod -@@ -9,7 +9,7 @@ or libvirt - - virt-v2v [-i* options] -o local -os DIRECTORY - -- virt-v2v [-i* options] -o qemu -os DIRECTORY [--qemu-boot] -+ virt-v2v [-i* options] -o qemu -os DIRECTORY - - virt-v2v [-i* options] -o json -os DIRECTORY - [-oo json-disks-pattern=PATTERN] -@@ -50,12 +50,10 @@ where C is the guest name. - - =item B<-o qemu -os> C - --=item B<-o qemu -os> C B<--qemu-boot> -- - This converts the guest to files in C. Unlike I<-o local> - above, a shell script is created which contains the raw qemu command - you would need to boot the guest. However the shell script is not --run, I you also add the I<--qemu-boot> option. -+run. - - =item B<-o json -os> C - -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index 25041d0ec..bd606592b 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -142,11 +142,6 @@ Since F contains the path(s) to the guest disk - image(s) you do not need to specify the name of the disk image on the - command line. - --To convert a local disk image and immediately boot it in local --qemu, do: -- -- virt-v2v -i disk disk.img -o qemu -os /var/tmp --qemu-boot -- - =head1 OPTIONS - - =over 4 -@@ -510,9 +505,6 @@ This is similar to I<-o local>, except that a shell script is written - which you can use to boot the guest in qemu. The converted disks and - shell script are written to the directory specified by I<-os>. - --When using this output mode, you can also specify the I<--qemu-boot> --option which boots the guest under qemu immediately. -- - =item B<-o> B - - This is the same as I<-o rhv>. -@@ -788,11 +780,6 @@ Print information about the source guest and stop. This option is - useful when you are setting up network and bridge maps. - See L. - --=item B<--qemu-boot> -- --When using I<-o qemu> only, this boots the guest immediately after --virt-v2v finishes. -- - =item B<-q> - - =item B<--quiet> --- -2.18.4 - diff --git a/SOURCES/0081-RHEL-8-Disable-alternate-Augeas-lenses.patch b/SOURCES/0081-RHEL-8-Disable-alternate-Augeas-lenses.patch deleted file mode 100644 index 28b3ee1..0000000 --- a/SOURCES/0081-RHEL-8-Disable-alternate-Augeas-lenses.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 1b819b67c2cc39e4728c4299749f1dd439937743 Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Fri, 24 Oct 2014 16:33:50 +0100 -Subject: [PATCH] RHEL 8: Disable alternate Augeas lenses. - -These are included in the RHEL augeas package, and therefore not -required. - -See: -https://www.redhat.com/archives/libguestfs/2014-October/msg00220.html ---- - appliance/Makefile.am | 1 - - daemon/augeas.c | 5 ++++- - 2 files changed, 4 insertions(+), 2 deletions(-) - -diff --git a/appliance/Makefile.am b/appliance/Makefile.am -index fc424b1d0..5efc5c036 100644 ---- a/appliance/Makefile.am -+++ b/appliance/Makefile.am -@@ -91,7 +91,6 @@ supermin.d/daemon.tar.gz: ../daemon/guestfsd guestfs_shadow.aug - rm -rf tmp-d - mkdir -p tmp-d$(DAEMON_SUPERMIN_DIR) tmp-d/etc tmp-d/usr/share/guestfs - ln ../daemon/guestfsd tmp-d$(DAEMON_SUPERMIN_DIR)/guestfsd -- ln $(srcdir)/guestfs_shadow.aug tmp-d/usr/share/guestfs/guestfs_shadow.aug - ( cd tmp-d && tar zcf - * ) > $@-t - rm -r tmp-d - mv $@-t $@ -diff --git a/daemon/augeas.c b/daemon/augeas.c -index 453251337..5bbfffa2d 100644 ---- a/daemon/augeas.c -+++ b/daemon/augeas.c -@@ -134,7 +134,7 @@ do_aug_init (const char *root, int flags) - } - - /* Pass AUG_NO_ERR_CLOSE so we can display detailed errors. */ -- aug = aug_init (buf, "/usr/share/guestfs/", flags | AUG_NO_ERR_CLOSE); -+ aug = aug_init (buf, NULL, flags | AUG_NO_ERR_CLOSE); - - if (!aug) { - reply_with_error ("augeas initialization failed"); -@@ -148,6 +148,8 @@ do_aug_init (const char *root, int flags) - return -1; - } - -+ /* We already have the needed lenses in RHEL 8 */ -+#if 0 - if (!augeas_is_version (1, 2, 1)) { - int r = aug_transform (aug, "guestfs_shadow", "/etc/shadow", - 0 /* = included */); -@@ -166,6 +168,7 @@ do_aug_init (const char *root, int flags) - } - } - } -+#endif - - return 0; - } --- -2.18.4 - diff --git a/SOURCES/0082-RHEL-8-Fix-list-of-supported-sound-cards-to-match-RH.patch b/SOURCES/0082-RHEL-8-Fix-list-of-supported-sound-cards-to-match-RH.patch deleted file mode 100644 index d487184..0000000 --- a/SOURCES/0082-RHEL-8-Fix-list-of-supported-sound-cards-to-match-RH.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 74d6c774c52ad7d6dd1746a4d11eb7668e826374 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Fri, 24 Apr 2015 09:45:41 -0400 -Subject: [PATCH] RHEL 8: Fix list of supported sound cards to match RHEL qemu - (RHBZ#1176493). - ---- - v2v/utils.ml | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/v2v/utils.ml b/v2v/utils.ml -index 74b501f81..21e9c9c15 100644 ---- a/v2v/utils.ml -+++ b/v2v/utils.ml -@@ -51,13 +51,14 @@ let kvm_arch = function - (* Does qemu support the given sound card? *) - let qemu_supports_sound_card = function - | Types.AC97 -- | Types.ES1370 - | Types.ICH6 - | Types.ICH9 - | Types.PCSpeaker -+ -> true -+ | Types.ES1370 - | Types.SB16 - | Types.USBAudio -- -> true -+ -> false - - (* Find the UEFI firmware. *) - let find_uefi_firmware guest_arch = --- -2.18.4 - diff --git a/SOURCES/0083-RHEL-8-Reject-use-of-libguestfs-winsupport-features-.patch b/SOURCES/0083-RHEL-8-Reject-use-of-libguestfs-winsupport-features-.patch deleted file mode 100644 index 7d7967b..0000000 --- a/SOURCES/0083-RHEL-8-Reject-use-of-libguestfs-winsupport-features-.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 434dd6ac0634211a48dd8d46c6efa68ef1270ae5 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 7 Jul 2015 09:28:03 -0400 -Subject: [PATCH] RHEL 8: Reject use of libguestfs-winsupport features except - for virt-* tools (RHBZ#1240276). - ---- - generator/c.ml | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/generator/c.ml b/generator/c.ml -index 86f7d89a3..b5bb99f53 100644 ---- a/generator/c.ml -+++ b/generator/c.ml -@@ -1832,6 +1832,22 @@ and generate_client_actions actions () = - check_args_validity c_name style; - trace_call name c_name style; - -+ (* RHEL 8 *) -+ if name = "mount" || name = "mount_ro" || name = "mount_options" || -+ name = "mount_vfs" then ( -+ pr " if (g->program && !STRPREFIX (g->program, \"virt-\")) {\n"; -+ pr " CLEANUP_FREE char *vfs_type = guestfs_vfs_type (g, mountable);\n"; -+ pr " if (vfs_type && STREQ (vfs_type, \"ntfs\")) {\n"; -+ pr " error (g, \"mount: unsupported filesystem type\");\n"; -+ pr " if (trace_flag)\n"; -+ pr " guestfs_int_trace (g, \"%%s = %%s (error)\",\n"; -+ pr " \"%s\", \"-1\");\n" name; -+ pr " return %s;\n" (string_of_errcode errcode); -+ pr " }\n"; -+ pr " }\n"; -+ pr "\n"; -+ ); -+ - (* Calculate the total size of all FileIn arguments to pass - * as a progress bar hint. - *) --- -2.18.4 - diff --git a/SOURCES/0084-RHEL-8-Fix-tests-for-libguestfs-winsupport.patch b/SOURCES/0084-RHEL-8-Fix-tests-for-libguestfs-winsupport.patch deleted file mode 100644 index cb324e4..0000000 --- a/SOURCES/0084-RHEL-8-Fix-tests-for-libguestfs-winsupport.patch +++ /dev/null @@ -1,93 +0,0 @@ -From dbbd9c3d94eeb1ad700bc0745a245da1fb71e1b7 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Sun, 30 Aug 2015 03:21:57 -0400 -Subject: [PATCH] RHEL 8: Fix tests for libguestfs-winsupport. - -It doesn't let us use guestfish for arbitrary Windows edits. ---- - test-data/phony-guests/make-windows-img.sh | 1 + - tests/charsets/test-charset-fidelity.c | 2 ++ - v2v/test-v2v-virtio-win-iso.sh | 8 +++++++- - v2v/test-v2v-windows-conversion.sh | 8 +++++++- - 4 files changed, 17 insertions(+), 2 deletions(-) - -diff --git a/test-data/phony-guests/make-windows-img.sh b/test-data/phony-guests/make-windows-img.sh -index 8676b5ac0..1a88d9fc9 100755 ---- a/test-data/phony-guests/make-windows-img.sh -+++ b/test-data/phony-guests/make-windows-img.sh -@@ -37,6 +37,7 @@ fi - - # Create a disk image. - guestfish < "$script" - :> "$expected" - -+cat >> "$script" < "$response" -+guestfish --ro -a "$d/windows-sda" < "$script" > "$response" - diff -u "$expected" "$response" - - rm -r $d -diff --git a/v2v/test-v2v-windows-conversion.sh b/v2v/test-v2v-windows-conversion.sh -index f1da222a9..ff94fe39b 100755 ---- a/v2v/test-v2v-windows-conversion.sh -+++ b/v2v/test-v2v-windows-conversion.sh -@@ -73,6 +73,12 @@ mktest () - :> "$script" - :> "$expected" - -+cat >> "$script" < "$response" -+guestfish --ro -a "$d/windows-sda" < "$script" > "$response" - diff -u "$expected" "$response" - - # We also update the Registry several times, for firstboot, and (ONLY --- -2.18.4 - diff --git a/SOURCES/0085-RHEL-8-tests-Disable-daemon-tests-that-require-the-u.patch b/SOURCES/0085-RHEL-8-tests-Disable-daemon-tests-that-require-the-u.patch deleted file mode 100644 index 7cd91cb..0000000 --- a/SOURCES/0085-RHEL-8-tests-Disable-daemon-tests-that-require-the-u.patch +++ /dev/null @@ -1,28 +0,0 @@ -From e6a6af387981b849349c72e7d5c367b944dbd317 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 21 Sep 2015 13:12:43 -0400 -Subject: [PATCH] RHEL 8: tests: Disable daemon tests that require the 'unix' - backend. - ---- - tests/daemon/Makefile.am | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/tests/daemon/Makefile.am b/tests/daemon/Makefile.am -index 053cad3e1..0d723fee4 100644 ---- a/tests/daemon/Makefile.am -+++ b/tests/daemon/Makefile.am -@@ -23,9 +23,7 @@ include $(top_srcdir)/subdir-rules.mk - - check_DATA = captive-daemon.pm - --TESTS = \ -- test-daemon-start.pl \ -- test-btrfs.pl -+TESTS = - - TESTS_ENVIRONMENT = $(top_builddir)/run --test - --- -2.18.4 - diff --git a/SOURCES/0086-RHEL-8-v2v-Disable-the-virt-v2v-in-place-option.patch b/SOURCES/0086-RHEL-8-v2v-Disable-the-virt-v2v-in-place-option.patch deleted file mode 100644 index 47d311f..0000000 --- a/SOURCES/0086-RHEL-8-v2v-Disable-the-virt-v2v-in-place-option.patch +++ /dev/null @@ -1,286 +0,0 @@ -From 153dc4ea922875c582490bc4e0ccad227aa62558 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 14 Jan 2016 11:53:42 -0500 -Subject: [PATCH] RHEL 8: v2v: Disable the virt-v2v --in-place option. - -This disables the virt-v2v --in-place option which we do not -wish to support in RHEL. -(See commit d0069559a939e47e5f29973ed9a69a13f0b58301). ---- - v2v/Makefile.am | 2 - - v2v/cmdline.ml | 8 +-- - v2v/test-v2v-docs.sh | 1 + - v2v/test-v2v-in-place.sh | 108 --------------------------------------- - v2v/virt-v2v.pod | 48 +---------------- - 5 files changed, 7 insertions(+), 160 deletions(-) - delete mode 100755 v2v/test-v2v-in-place.sh - -diff --git a/v2v/Makefile.am b/v2v/Makefile.am -index 6568c9a6b..affa6f7e9 100644 ---- a/v2v/Makefile.am -+++ b/v2v/Makefile.am -@@ -469,7 +469,6 @@ if HAVE_LIBVIRT - TESTS += \ - test-v2v-cdrom.sh \ - test-v2v-floppy.sh \ -- test-v2v-in-place.sh \ - test-v2v-mac.sh \ - test-v2v-networks-and-bridges.sh \ - test-v2v-no-copy.sh \ -@@ -621,7 +620,6 @@ EXTRA_DIST += \ - test-v2v-i-vmx-3.vmx \ - test-v2v-i-vmx-4.vmx \ - test-v2v-i-vmx-5.vmx \ -- test-v2v-in-place.sh \ - test-v2v-it-vddk-io-query.sh \ - test-v2v-machine-readable.sh \ - test-v2v-mac-expected.xml \ -diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml -index e3578ddcb..19c5a269b 100644 ---- a/v2v/cmdline.ml -+++ b/v2v/cmdline.ml -@@ -230,8 +230,7 @@ let parse_cmdline () = - s_"Use password from file to connect to input hypervisor"; - [ M"it" ], Getopt.String ("transport", set_string_option_once "-it" input_transport), - s_"Input transport"; -- [ L"in-place" ], Getopt.Set in_place, -- s_"Only tune the guest in the input VM"; -+ [ L"in-place" ], Getopt.Set in_place, Getopt.hidden_option_description; - [ L"mac" ], Getopt.String ("mac:network|bridge|ip:out", add_mac), - s_"Map NIC to network or bridge or assign static IP"; - [ S 'n'; L"network" ], Getopt.String ("in:out", add_network), -@@ -369,7 +368,6 @@ read the man page virt-v2v(1). - pr "vddk\n"; - pr "colours-option\n"; - pr "vdsm-compat-option\n"; -- pr "in-place\n"; - pr "io/oo\n"; - pr "mac-option\n"; - pr "mac-ip-option\n"; -@@ -544,6 +542,10 @@ read the man page virt-v2v(1). - error (f_"only ‘-it ssh’ can be used here") in - Input_vmx.input_vmx input_transport arg in - -+ (* Prevent use of --in-place option in RHEL. *) -+ if in_place then -+ error (f_"--in-place cannot be used in RHEL"); -+ - (* Common error message. *) - let error_option_cannot_be_used_in_output_mode mode opt = - error (f_"-o %s: %s option cannot be used in this output mode") mode opt -diff --git a/v2v/test-v2v-docs.sh b/v2v/test-v2v-docs.sh -index dfb12bb14..2e45705a3 100755 ---- a/v2v/test-v2v-docs.sh -+++ b/v2v/test-v2v-docs.sh -@@ -26,6 +26,7 @@ $top_srcdir/podcheck.pl virt-v2v.pod virt-v2v \ - --debug-overlay,\ - --ic,\ - --if,\ -+--in-place,\ - --io,\ - --ip,\ - --it,\ -diff --git a/v2v/test-v2v-in-place.sh b/v2v/test-v2v-in-place.sh -deleted file mode 100755 -index 6f7d78f39..000000000 ---- a/v2v/test-v2v-in-place.sh -+++ /dev/null -@@ -1,108 +0,0 @@ --#!/bin/bash - --# libguestfs virt-v2v test script --# Copyright (C) 2014 Red Hat Inc. --# Copyright (C) 2015 Parallels IP Holdings GmbH. --# --# This program is free software; you can redistribute it and/or modify --# it under the terms of the GNU General Public License as published by --# the Free Software Foundation; either version 2 of the License, or --# (at your option) any later version. --# --# This program is distributed in the hope that it will be useful, --# but WITHOUT ANY WARRANTY; without even the implied warranty of --# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --# GNU General Public License for more details. --# --# You should have received a copy of the GNU General Public License --# along with this program; if not, write to the Free Software --# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -- --# Test --in-place. -- --unset CDPATH --export LANG=C --set -e -- --$TEST_FUNCTIONS --skip_if_skipped --skip_if_backend uml --skip_unless_phony_guest windows.img -- --img_base="$abs_top_builddir/test-data/phony-guests/windows.img" -- --export VIRT_TOOLS_DATA_DIR="$top_srcdir/test-data/fake-virt-tools" --export VIRTIO_WIN="$top_srcdir/test-data/fake-virtio-win" -- --d=$PWD/test-v2v-in-place.d --rm -rf $d --mkdir $d -- --img="$d/test.qcow2" --rm -f $img --qemu-img create -f qcow2 -b $img_base -o compat=1.1,backing_fmt=raw $img --md5="$(do_md5 $img_base)" -- --libvirt_xml="$d/test.xml" --rm -f $libvirt_xml --n=windows-overlay --cat > $libvirt_xml < -- -- $n -- 1048576 -- -- hvm -- -- -- -- -- -- -- -- -- -- -- --EOF -- --$VG virt-v2v --debug-gc -i libvirt -ic "test://$libvirt_xml" $n --in-place -- --# Test that the drivers have been copied over into the guest --script="$d/test.fish" --expected="$d/expected" --response="$d/response" -- --mktest () --{ -- local cmd="$1" exp="$2" -- -- echo "echo '$cmd'" >> "$script" -- echo "$cmd" >> "$expected" -- -- echo "$cmd" >> "$script" -- echo "$exp" >> "$expected" --} -- --:> "$script" --:> "$expected" -- --firstboot_dir="/Program Files/Guestfs/Firstboot" --mktest "is-dir \"$firstboot_dir\"" true --mktest "is-file \"$firstboot_dir/firstboot.bat\"" true --mktest "is-dir \"$firstboot_dir/scripts\"" true --virtio_dir="/Windows/Drivers/VirtIO" --mktest "is-dir \"$virtio_dir\"" true --for drv in netkvm qxl vioscsi viostor; do -- for sfx in cat inf sys; do -- mktest "is-file \"$virtio_dir/$drv.$sfx\"" true -- done --done -- --guestfish --ro -a "$img" -i < "$script" > "$response" --diff -u "$expected" "$response" -- --# Test the base image remained untouched --test "$md5" = "$(do_md5 $img_base)" -- --# Clean up. --rm -r $d -diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod -index bd606592b..092d88635 100644 ---- a/v2v/virt-v2v.pod -+++ b/v2v/virt-v2v.pod -@@ -8,10 +8,6 @@ virt-v2v - Convert a guest to use KVM - [-o mode] [other -o* options] - [guest|filename] - -- virt-v2v --in-place -- [-i mode] [other -i* options] -- [guest|filename] -- - =head1 DESCRIPTION - - Virt-v2v converts a single guest from a foreign hypervisor to run on -@@ -39,9 +35,6 @@ these sides of virt-v2v are documented separately in this manual. - - Virt-v2v normally copies from the input to the output, called "copying - mode". In this case the source guest is always left unchanged. --In-place conversion (I<--in-place>) only uses the I<-i*> options and --modifies the source guest in-place. (See L --below.) - - =head2 Other virt-v2v topics - -@@ -255,20 +248,6 @@ For I<-i disk> only, this specifies the format of the input disk - image. For other input methods you should specify the input - format in the metadata. - --=item B<--in-place> -- --Do not create an output virtual machine in the target hypervisor. --Instead, adjust the guest OS in the source VM to run in the input --hypervisor. -- --This mode is meant for integration with other toolsets, which take the --responsibility of converting the VM configuration, providing for --rollback in case of errors, transforming the storage, etc. -- --See L below. -- --Conflicts with all I<-o *> options. -- - =item B<-io> OPTION=VALUE - - Set input option(s) related to the current input mode or transport. -@@ -1300,7 +1279,7 @@ Minimum free space: 10 MB - =head3 Minimum free space check in the host - - You must have sufficient free space in the host directory used to --store temporary overlays (except in I<--in-place> mode). To find out -+store temporary overlays. To find out - which directory this is, use: - - $ df -h "`guestfish get-cachedir`" -@@ -1403,31 +1382,6 @@ that instead. - - - --=head2 In-place conversion -- --It is also possible to use virt-v2v in scenarios where a foreign VM --has already been imported into a KVM-based hypervisor, but still needs --adjustments in the guest to make it run in the new virtual hardware. -- --In that case it is assumed that a third-party tool has created the --target VM in the supported KVM-based hypervisor based on the source VM --configuration and contents, but using virtual devices more appropriate --for KVM (e.g. virtio storage and network, etc.). -- --Then, to make the guest OS boot and run in the changed environment, --one can use: -- -- virt-v2v -ic qemu:///system converted_vm --in-place -- --Virt-v2v will analyze the configuration of C in the --C libvirt instance, and apply various fixups to the --guest OS configuration to make it match the VM configuration. This --may include installing virtio drivers, configuring the bootloader, the --mountpoints, the network interfaces, and so on. -- --Should an error occur during the operation, virt-v2v exits with an --error code leaving the VM in an undefined state. -- - =head2 Machine readable output - - The I<--machine-readable> option can be used to make the output more --- -2.18.4 - diff --git a/SOURCES/0087-RHEL-8-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch b/SOURCES/0087-RHEL-8-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch deleted file mode 100644 index fc18897..0000000 --- a/SOURCES/0087-RHEL-8-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 68d6b9b268ccc6fd12c94acc7e0d3aa130eaee95 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 2 Mar 2017 14:21:37 +0100 -Subject: [PATCH] RHEL 8: v2v: -i disk: force VNC as display (RHBZ#1372671) - -The SDL output mode is not supported in RHEL 8's qemu-kvm. ---- - v2v/input_disk.ml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/v2v/input_disk.ml b/v2v/input_disk.ml -index 8321a2a8c..6bd9f43f8 100644 ---- a/v2v/input_disk.ml -+++ b/v2v/input_disk.ml -@@ -89,7 +89,7 @@ class input_disk input_format disk = object - s_features = [ "acpi"; "apic"; "pae" ]; - s_firmware = UnknownFirmware; (* causes virt-v2v to autodetect *) - s_display = -- Some { s_display_type = Window; s_keymap = None; s_password = None; -+ Some { s_display_type = VNC; s_keymap = None; s_password = None; - s_listen = LNoListen; s_port = None }; - s_video = None; - s_sound = None; --- -2.18.4 - diff --git a/SOURCES/0088-RHEL-8-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch b/SOURCES/0088-RHEL-8-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch deleted file mode 100644 index 8fba832..0000000 --- a/SOURCES/0088-RHEL-8-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 9c3434985b67dd6387f7d358753b289ae43e54fe Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Wed, 8 Mar 2017 11:03:40 +0100 -Subject: [PATCH] RHEL 8: v2v: do not mention SUSE Xen hosts (RHBZ#1430203) - -They are not supported in RHEL 8. ---- - v2v/virt-v2v-input-xen.pod | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/v2v/virt-v2v-input-xen.pod b/v2v/virt-v2v-input-xen.pod -index 9fd5065f1..c3c20a6b6 100644 ---- a/v2v/virt-v2v-input-xen.pod -+++ b/v2v/virt-v2v-input-xen.pod -@@ -10,7 +10,7 @@ virt-v2v-input-xen - Using virt-v2v to convert guests from Xen - =head1 DESCRIPTION - - This page documents how to use L to convert guests from --RHEL 5 Xen, or SLES and OpenSUSE Xen hosts. -+RHEL 5 Xen hosts. - - =head1 INPUT FROM XEN - --- -2.18.4 - diff --git a/SOURCES/0089-RHEL-8-v2v-rhv-upload-Remove-restriction-on-oa-spars.patch b/SOURCES/0089-RHEL-8-v2v-rhv-upload-Remove-restriction-on-oa-spars.patch deleted file mode 100644 index 462763e..0000000 --- a/SOURCES/0089-RHEL-8-v2v-rhv-upload-Remove-restriction-on-oa-spars.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 24c75d5ae2ca66fc683e98d32f7949a35caf6260 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Mon, 14 May 2018 10:16:58 +0100 -Subject: [PATCH] RHEL 8: v2v: rhv-upload: Remove restriction on -oa sparse. - -See: https://bugzilla.redhat.com/show_bug.cgi?id=1565681 -and the v2v-devel private thread "Do we already support migration using FC?" ---- - v2v/output_rhv_upload.ml | 11 +---------- - v2v/rhv-upload-plugin.py | 4 +--- - v2v/virt-v2v-output-rhv.pod | 8 +------- - 3 files changed, 3 insertions(+), 20 deletions(-) - -diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml -index e1d06867b..3f078157a 100644 ---- a/v2v/output_rhv_upload.ml -+++ b/v2v/output_rhv_upload.ml -@@ -177,19 +177,11 @@ See also the virt-v2v-output-rhv(1) manual.") - error (f_"nbdkit was compiled without SELinux support. You will have to recompile nbdkit with libselinux-devel installed, or else set SELinux to Permissive mode while doing the conversion.") - in - -- (* Output format/sparse must be raw/sparse. We may be able to -- * lift this limitation in future, but it requires changes on the -- * RHV side. See TODO file for details. XXX -- *) -+ (* Output format must be raw. *) - let error_current_limitation required_param = - error (f_"rhv-upload: currently you must use ‘%s’. This restriction will be loosened in a future version.") required_param - in - -- let error_unless_output_alloc_sparse () = -- if output_alloc <> Sparse then -- error_current_limitation "-oa sparse" -- in -- - (* JSON parameters which are invariant between disks. *) - let json_params = [ - "verbose", JSON.Bool (verbose ()); -@@ -249,7 +241,6 @@ object - error_unless_ovirtsdk4_module_available (); - error_unless_nbdkit_working (); - error_unless_nbdkit_python_plugin_working (); -- error_unless_output_alloc_sparse (); - (* Python code prechecks. *) - let precheck_fn = tmpdir // "v2vprecheck.json" in - let fd = Unix.openfile precheck_fn [O_WRONLY; O_CREAT] 0o600 in -diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py -index 14d4e37fb..c7f7a5e8b 100644 ---- a/v2v/rhv-upload-plugin.py -+++ b/v2v/rhv-upload-plugin.py -@@ -142,10 +142,8 @@ def open(readonly): - format = disk_format, - initial_size = params['disk_size'], - provisioned_size = params['disk_size'], -- # XXX Ignores params['output_sparse']. -- # Handling this properly will be complex, see: - # https://www.redhat.com/archives/libguestfs/2018-March/msg00177.html -- sparse = True, -+ sparse = params['output_sparse'], - storage_domains = [ - types.StorageDomain( - name = params['output_storage'], -diff --git a/v2v/virt-v2v-output-rhv.pod b/v2v/virt-v2v-output-rhv.pod -index 4520c9184..f6579a48e 100644 ---- a/v2v/virt-v2v-output-rhv.pod -+++ b/v2v/virt-v2v-output-rhv.pod -@@ -5,7 +5,7 @@ virt-v2v-output-rhv - Using virt-v2v to convert guests to oVirt or RHV - =head1 SYNOPSIS - - virt-v2v [-i* options] -o rhv-upload [-oc ENGINE_URL] -os STORAGE -- [-op PASSWORD] [-of raw] -+ [-op PASSWORD] - [-oo rhv-cafile=FILE] - [-oo rhv-cluster=CLUSTER] - [-oo rhv-direct] -@@ -79,12 +79,6 @@ username is not specified then virt-v2v defaults to using - C which is the typical superuser account for oVirt - instances. - --=item I<-of raw> -- --Currently you must use I<-of raw> and you cannot use I<-oa preallocated>. -- --These restrictions will be loosened in a future version. -- - =item I<-op> F - - A file containing a password to be used when connecting to the oVirt --- -2.18.4 - diff --git a/SOURCES/0090-RHEL-8-use-platform-python.patch b/SOURCES/0090-RHEL-8-use-platform-python.patch deleted file mode 100644 index 0b73995..0000000 --- a/SOURCES/0090-RHEL-8-use-platform-python.patch +++ /dev/null @@ -1,27 +0,0 @@ -From cb6f386f75f210bdc97133a026e2fdb29a2fe28d Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Sun, 16 Dec 2018 16:42:46 +0100 -Subject: [PATCH] RHEL 8: use platform-python - -Use the stable platform-python provided in BaseOS, instead of relying on -some arbitrary version installed by the user. ---- - v2v/python_script.ml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/v2v/python_script.ml b/v2v/python_script.ml -index 3159373a1..f2c00c40f 100644 ---- a/v2v/python_script.ml -+++ b/v2v/python_script.ml -@@ -24,7 +24,7 @@ open Unix_utils - - open Common_gettext.Gettext - --let python = "python3" (* Defined by PEP 394 *) -+let python = "/usr/libexec/platform-python" - - type script = { - tmpdir : string; (* Temporary directory. *) --- -2.18.4 - diff --git a/SOURCES/0091-RHEL-8-point-to-KB-for-supported-v2v-hypervisors-gue.patch b/SOURCES/0091-RHEL-8-point-to-KB-for-supported-v2v-hypervisors-gue.patch deleted file mode 100644 index 5302c62..0000000 --- a/SOURCES/0091-RHEL-8-point-to-KB-for-supported-v2v-hypervisors-gue.patch +++ /dev/null @@ -1,125 +0,0 @@ -From ada9209ada5511a7876ca9c0e1183bde217adbae Mon Sep 17 00:00:00 2001 -From: Pino Toscano -Date: Tue, 26 Mar 2019 09:42:25 +0100 -Subject: [PATCH] RHEL 8: point to KB for supported v2v hypervisors/guests - ---- - v2v/virt-v2v-support.pod | 102 ++------------------------------------- - 1 file changed, 4 insertions(+), 98 deletions(-) - -diff --git a/v2v/virt-v2v-support.pod b/v2v/virt-v2v-support.pod -index a22506068..4ec1a07c1 100644 ---- a/v2v/virt-v2v-support.pod -+++ b/v2v/virt-v2v-support.pod -@@ -8,104 +8,10 @@ systems and guests in virt-v2v - This page documents which foreign hypervisors, virtualization - management systems and guest types that L can support. - --Note this page applies to upstream virt-v2v from --L and in downstream distributions of virt-v2v --sometimes features are intentionally removed, or are present but not --supported. -- --=head2 Hypervisors (Input) -- --=over 4 -- --=item VMware ESXi -- --Must be managed by VMware vCenter E 5.0 unless VDDK is available. -- --=item OVA exported from VMware -- --OVAs from other hypervisors will not work. -- --=item VMX from VMware -- --VMX files generated by other hypervisors will not work. -- --=item RHEL 5 Xen -- --=item SUSE Xen -- --=item Citrix Xen -- --Citrix Xen has not been recently tested. -- --=item Hyper-V -- --Not recently tested. Requires that you export the disk or use --L on Hyper-V. -- --=item Direct from disk images -- --Only disk images exported from supported hypervisors, and using --container formats supported by qemu. -- --=item Physical machines -- --Using the L tool. -- --=back -- --=head2 Hypervisors (Output) -- --QEMU and KVM only. -- --=head2 Virtualization management systems (Output) -- --=over 4 -- --=item OpenStack -- --=item Red Hat Virtualization (RHV) 4.1 and up -- --=item Local libvirt -- --And hence L, L, and similar tools. -- --=item Local disk -- --=back -- --=head2 Guests -- --=over 4 -- --=item Red Hat Enterprise Linux 3, 4, 5, 6, 7 -- --=item CentOS 3, 4, 5, 6, 7 -- --=item Scientific Linux 3, 4, 5, 6, 7 -- --=item Oracle Linux -- --=item Fedora -- --=item SLES 10 and up -- --=item OpenSUSE 10 and up -- --=item Debian 6 and up -- --=item Ubuntu 10.04, 12.04, 14.04, 16.04, and up -- --=item Windows XP to Windows 10 / Windows Server 2016 -- --We use Windows internal version numbers, see --L -- --Currently NT 5.2 to NT 6.3 are supported. -- --See L below for additional notes on converting Windows --guests. -- --=back -+For more information on supported hypervisors, and guest types in -+RHEL, please consult the following Knowledgebase article on these -+Red Hat Customer Portal: -+L. - - =head2 Guest firmware - --- -2.18.4 - diff --git a/SOURCES/0092-lib-Increase-default-memsize-to-1280-RHBZ-1837765.patch b/SOURCES/0092-lib-Increase-default-memsize-to-1280-RHBZ-1837765.patch deleted file mode 100644 index 00edfd0..0000000 --- a/SOURCES/0092-lib-Increase-default-memsize-to-1280-RHBZ-1837765.patch +++ /dev/null @@ -1,66 +0,0 @@ -From ee88832841e82a407c9df44a82b87270ec0d492b Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 30 Jun 2020 17:34:47 +0100 -Subject: [PATCH] lib: Increase default memsize to 1280 (RHBZ#1837765). - -Argon2 is the default LUKS Password-Based Key Derivation Function -(PBKDF) for some new guests such as RHEL 8.2 and Fedora. It is -designed to be "memory hard", meaning that by design it requires large -amounts of memory, making it expensive to brute-force. Unfortunately -the default for guests which had more than a few GB of RAM at install -time is to require about 1 GB of RAM to decrypt the block device, -which is considerably larger than the default available in the -libguestfs appliance. - -To make it possible to open these encrypted disks we need to make the -appliance larger. This could be done as a one-off, and the current -workaround is simply to set LIBGUESTFS_MEMSIZE=2048 or a similar -amount. However since we don't know in advance whether we could be -dealing with an encrypted disk, partition, etc. or what PBKDF it uses, -the only way to deal with this in all circumstances is to increase the -default memsize. This commit increases it quite a lot (768 -> 1280) -which is unfortunate. - -Note as there is some confusion on this point: Since libguestfs does -not attempt to decrypt disks in parallel, you only need ~ 1GB in -total, not per encrypted disk. - -For a reproducer, see: -https://bugzilla.redhat.com/show_bug.cgi?id=1837765#c14 - -(cherry picked from commit 224f373043302845122bf701ffc6e3416e0168fa) ---- - lib/guestfs-internal.h | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/lib/guestfs-internal.h b/lib/guestfs-internal.h -index 75b8a5c8e..30553d7c0 100644 ---- a/lib/guestfs-internal.h -+++ b/lib/guestfs-internal.h -@@ -94,7 +94,7 @@ - * creating device nodes. - */ - #ifdef __powerpc__ --# define DEFAULT_MEMSIZE 1024 -+# define DEFAULT_MEMSIZE 1280 - #endif - - /* Kernel 3.19 is unable to uncompress the initramfs on aarch64 unless -@@ -103,12 +103,12 @@ - * common on aarch64, treat this like the ppc case above. - */ - #ifdef __aarch64__ --# define DEFAULT_MEMSIZE 1024 -+# define DEFAULT_MEMSIZE 1280 - #endif - - /* The default and minimum memory size for most users. */ - #ifndef DEFAULT_MEMSIZE --# define DEFAULT_MEMSIZE 768 -+# define DEFAULT_MEMSIZE 1280 - #endif - #ifndef MIN_MEMSIZE - # define MIN_MEMSIZE 256 --- -2.18.4 - diff --git a/SOURCES/0093-tar-in-Add-workaround-because-tar-doesn-t-restore-ca.patch b/SOURCES/0093-tar-in-Add-workaround-because-tar-doesn-t-restore-ca.patch deleted file mode 100644 index fe7ecd5..0000000 --- a/SOURCES/0093-tar-in-Add-workaround-because-tar-doesn-t-restore-ca.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 38ecae6c0298943b4bc74d6d3d5c888ca0853dec Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Thu, 13 Oct 2016 12:47:43 +0100 -Subject: [PATCH] tar-in: Add workaround because tar doesn't restore - capabilities (RHBZ#1384241). - -Current GNU tar does not restore all extended attributes. In -particular only user.* capabilities are restored (although all -are saved in the tarball). - -To restore capabilities, SELinux security attributes, and other things -we need to use --xattrs-include=* - -For further information on the tar bug, see: -https://bugzilla.redhat.com/show_bug.cgi?id=771927 - -(cherry picked from commit 6d0ab14b56743679638ead0829ff3131749ac59b) ---- - daemon/tar.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/daemon/tar.c b/daemon/tar.c -index 300e99448..9464d7105 100644 ---- a/daemon/tar.c -+++ b/daemon/tar.c -@@ -188,7 +188,11 @@ do_tar_in (const char *dir, const char *compress, int xattrs, int selinux, int a - "tar", - dir, filter, - chown_supported ? "" : "--no-same-owner ", -- xattrs ? "--xattrs " : "", -+ /* --xattrs-include=* is a workaround for a bug -+ * in tar, and hopefully won't be required -+ * forever. See RHBZ#771927. -+ */ -+ xattrs ? "--xattrs --xattrs-include='*' " : "", - selinux ? "--selinux " : "", - acls ? "--acls " : "", - error_file) == -1) { --- -2.18.4 - diff --git a/SOURCES/0094-mlcustomize-Refactor-SELinux_relabel-code.patch b/SOURCES/0094-mlcustomize-Refactor-SELinux_relabel-code.patch deleted file mode 100644 index 4f641ae..0000000 --- a/SOURCES/0094-mlcustomize-Refactor-SELinux_relabel-code.patch +++ /dev/null @@ -1,155 +0,0 @@ -From 3bceb391d14aeebb21dd9742108fa98945a32c5c Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 5 May 2020 16:44:14 +0100 -Subject: [PATCH] mlcustomize: Refactor SELinux_relabel code. - -This shouldn't change the effect of this code. - -Cherry picked from libguestfs-common -commit 3493d9fcaab6de1c09528e55a01bc24f0fb6c03c and backported -to libguestfs 1.40 branch (which predates the common submodule). ---- - customize/SELinux_relabel.ml | 127 +++++++++++++++++++---------------- - 1 file changed, 68 insertions(+), 59 deletions(-) - -diff --git a/customize/SELinux_relabel.ml b/customize/SELinux_relabel.ml -index 44995df6b..5df1f0895 100644 ---- a/customize/SELinux_relabel.ml -+++ b/customize/SELinux_relabel.ml -@@ -28,65 +28,74 @@ module G = Guestfs - let array_find a l = - List.mem a (Array.to_list l) - --let relabel (g : G.guestfs) = -- (* Is the guest using SELinux? *) -- if g#is_file ~followsymlinks:true "/usr/sbin/load_policy" && -- g#is_file ~followsymlinks:true "/etc/selinux/config" then ( -- (* Is setfiles / SELinux relabelling functionality available? *) -- if g#feature_available [| "selinuxrelabel" |] then ( -- (* Use Augeas to parse /etc/selinux/config. *) -- g#aug_init "/" (16+32) (* AUG_SAVE_NOOP | AUG_NO_LOAD *); -- (* See: https://bugzilla.redhat.com/show_bug.cgi?id=975412#c0 *) -- ignore (g#aug_rm "/augeas/load/*[\"/etc/selinux/config/\" !~ regexp('^') + glob(incl) + regexp('/.*')]"); -- g#aug_load (); -- debug_augeas_errors g; -- -- (* Get the SELinux policy name, eg. "targeted", "minimum". -- * Use "targeted" if not specified, just like libselinux does. -- *) -- let policy = -- let config_path = "/files/etc/selinux/config" in -- let selinuxtype_path = config_path ^ "/SELINUXTYPE" in -- let keys = g#aug_ls config_path in -- if array_find selinuxtype_path keys then -- g#aug_get selinuxtype_path -- else -- "targeted" in -- -- g#aug_close (); -- -- (* Get the spec file name. *) -- let specfile = -- sprintf "/etc/selinux/%s/contexts/files/file_contexts" policy in -- -- (* RHEL 6.2 - 6.5 had a malformed specfile that contained the -- * invalid regular expression "/var/run/spice-vdagentd.\pid" -- * (instead of "\.p"). This stops setfiles from working on -- * the guest. -- * -- * Because an SELinux relabel writes all over the filesystem, -- * it seems reasonable to fix this problem in the specfile -- * at the same time. (RHBZ#1374232) -- *) -- if g#grep ~fixed:true "vdagentd.\\pid" specfile <> [||] then ( -- debug "fixing invalid regular expression in %s" specfile; -- let old_specfile = specfile ^ "~" in -- g#mv specfile old_specfile; -- let content = g#read_file old_specfile in -- let content = -- String.replace content "vdagentd.\\pid" "vdagentd\\.pid" in -- g#write specfile content; -- g#copy_attributes ~all:true old_specfile specfile -- ); -- -- (* Relabel everything. *) -- g#selinux_relabel ~force:true specfile "/"; -- -- (* If that worked, we don't need to autorelabel. *) -+let rec relabel (g : G.guestfs) = -+ (* Is the guest using SELinux? (Otherwise this is a no-op). *) -+ if is_selinux_guest g then ( -+ try -+ use_setfiles g; -+ (* That worked, so we don't need to autorelabel. *) - g#rm_f "/.autorelabel" -- ) -- else ( -- (* SELinux guest, but not SELinux host. Fallback to this. *) -+ with Failure _ -> -+ (* This is the fallback in case something in the setfiles -+ * method didn't work. That includes the case where a non-SELinux -+ * host is processing an SELinux guest, and other things. -+ *) - g#touch "/.autorelabel" -- ) - ) -+ -+and is_selinux_guest g = -+ g#is_file ~followsymlinks:true "/usr/sbin/load_policy" && -+ g#is_file ~followsymlinks:true "/etc/selinux/config" -+ -+and use_setfiles g = -+ (* Is setfiles / SELinux relabelling functionality available? *) -+ if not (g#feature_available [| "selinuxrelabel" |]) then -+ failwith "no selinux relabel feature"; -+ -+ (* Use Augeas to parse /etc/selinux/config. *) -+ g#aug_init "/" (16+32) (* AUG_SAVE_NOOP | AUG_NO_LOAD *); -+ (* See: https://bugzilla.redhat.com/show_bug.cgi?id=975412#c0 *) -+ ignore (g#aug_rm "/augeas/load/*[\"/etc/selinux/config/\" !~ regexp('^') + glob(incl) + regexp('/.*')]"); -+ g#aug_load (); -+ debug_augeas_errors g; -+ -+ (* Get the SELinux policy name, eg. "targeted", "minimum". -+ * Use "targeted" if not specified, just like libselinux does. -+ *) -+ let policy = -+ let config_path = "/files/etc/selinux/config" in -+ let selinuxtype_path = config_path ^ "/SELINUXTYPE" in -+ let keys = g#aug_ls config_path in -+ if array_find selinuxtype_path keys then -+ g#aug_get selinuxtype_path -+ else -+ "targeted" in -+ -+ g#aug_close (); -+ -+ (* Get the spec file name. *) -+ let specfile = -+ sprintf "/etc/selinux/%s/contexts/files/file_contexts" policy in -+ -+ (* RHEL 6.2 - 6.5 had a malformed specfile that contained the -+ * invalid regular expression "/var/run/spice-vdagentd.\pid" -+ * (instead of "\.p"). This stops setfiles from working on -+ * the guest. -+ * -+ * Because an SELinux relabel writes all over the filesystem, -+ * it seems reasonable to fix this problem in the specfile -+ * at the same time. (RHBZ#1374232) -+ *) -+ if g#grep ~fixed:true "vdagentd.\\pid" specfile <> [||] then ( -+ debug "fixing invalid regular expression in %s" specfile; -+ let old_specfile = specfile ^ "~" in -+ g#mv specfile old_specfile; -+ let content = g#read_file old_specfile in -+ let content = -+ String.replace content "vdagentd.\\pid" "vdagentd\\.pid" in -+ g#write specfile content; -+ g#copy_attributes ~all:true old_specfile specfile -+ ); -+ -+ (* Relabel everything. *) -+ g#selinux_relabel ~force:true specfile "/" --- -2.18.4 - diff --git a/SOURCES/0095-mlcustomize-Fall-back-to-autorelabel-if-specfile-doe.patch b/SOURCES/0095-mlcustomize-Fall-back-to-autorelabel-if-specfile-doe.patch deleted file mode 100644 index b2be0f3..0000000 --- a/SOURCES/0095-mlcustomize-Fall-back-to-autorelabel-if-specfile-doe.patch +++ /dev/null @@ -1,41 +0,0 @@ -From a5e6e764c8753c254e801b32059530fbc2e86e8d Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 5 May 2020 16:44:15 +0100 -Subject: [PATCH] mlcustomize: Fall back to autorelabel if specfile does not - exist (RHBZ#1828952). - -https://bugzilla.redhat.com/show_bug.cgi?id=1828952#c2 - -Cherry picked from libguestfs-common -commit 101dac2eac8c61f0081c343b5d69cfa4efbc2a98 and backported -to libguestfs 1.40 branch (which predates the common submodule). - -If SELINUXTYPE is set to some value other than targeted then we look -for a directory /etc/selinux/ which does not exist. -However this should not cause a fatal error. Using setfiles to do the -relabelling immediately is a nice-to-have, but we can fallback to -using autorelabel if we're unable to achieve it. ---- - customize/SELinux_relabel.ml | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/customize/SELinux_relabel.ml b/customize/SELinux_relabel.ml -index 5df1f0895..5ecf7bd7e 100644 ---- a/customize/SELinux_relabel.ml -+++ b/customize/SELinux_relabel.ml -@@ -77,6 +77,12 @@ and use_setfiles g = - let specfile = - sprintf "/etc/selinux/%s/contexts/files/file_contexts" policy in - -+ (* If the spec file doesn't exist then fall back to using -+ * autorelabel (RHBZ#1828952). -+ *) -+ if not (g#is_file ~followsymlinks:true specfile) then -+ failwith "no spec file"; -+ - (* RHEL 6.2 - 6.5 had a malformed specfile that contained the - * invalid regular expression "/var/run/spice-vdagentd.\pid" - * (instead of "\.p"). This stops setfiles from working on --- -2.18.4 - diff --git a/SOURCES/brew-overrides.sh b/SOURCES/brew-overrides.sh deleted file mode 100755 index 5b72490..0000000 --- a/SOURCES/brew-overrides.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - - -# This script is used when we build libguestfs from brew, as sometimes -# we require packages which are not available in the current version -# of RHEL. Normally these updated packages would be released along -# with libguestfs in the next RHEL, although unfortunately sometimes -# that doesn't happen (eg. RHBZ#1199605). - -set -x - -pkgs=" -" - -for pkg in $pkgs ; do - brew tag-pkg rhel-8.0-temp-override $pkg -done - -for pkg in $pkgs ; do - brew wait-repo rhel-8.0-build --build=$pkg -done diff --git a/SOURCES/copy-patches.sh b/SOURCES/copy-patches.sh index 7a3ae91..0fc8036 100755 --- a/SOURCES/copy-patches.sh +++ b/SOURCES/copy-patches.sh @@ -6,7 +6,7 @@ set -e # directory. Use it like this: # ./copy-patches.sh -rhel_version=8.5.0 +rhel_version=8.6.0 # Check we're in the right directory. if [ ! -f libguestfs.spec ]; then @@ -31,7 +31,7 @@ git rm -f [0-9]*.patch ||: rm -f [0-9]*.patch # Get the patches. -(cd $git_checkout; rm -f [0-9]*.patch; git format-patch -N $tag) +(cd $git_checkout; rm -f [0-9]*.patch; git format-patch -N --submodule=diff $tag) mv $git_checkout/[0-9]*.patch . # Remove any not to be applied. diff --git a/SOURCES/libguestfs-1.40.2.tar.gz.sig b/SOURCES/libguestfs-1.40.2.tar.gz.sig deleted file mode 100644 index 016e22b..0000000 --- a/SOURCES/libguestfs-1.40.2.tar.gz.sig +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN PGP SIGNATURE----- - -iQJFBAABCAAvFiEE93dPsa0HSn6Mh2fqkXOPc+G3aKAFAlxdivwRHHJpY2hAYW5u -ZXhpYS5vcmcACgkQkXOPc+G3aKC8SRAAotTR3nvV2lUeABLn8uiv5CjmeEEm++C4 -754zGkOb7bRSQzcQ12XC0e4WQwcS/fHHSRhT2ABc1VeLn8ehyEEQ3T3NfDpnpaKR -NYolsI3l8iae4QI0wo85/Wb/k7pXg1uWFZ9t286d1e/NYudMEZ6hiVXsUNlSu0lR -rU5Xr/XGDV01Vlalo1qcVI1p3b3zBFGcNLv5Myc0+Q+RWVYcyrm270VJYmD0OOnh -zzRgb1fBW4rVIbYEhmmhNgbL3758Qaef/jsTxU/tH83LOdJUpxWYvLD7ec3DzsHr -xcNgDCZxCtn4ObdfxJGzVbWO96nmVPxNnVMeDol+PDsrVkQnpSPMPrU/oth5Xh19 -+JeP22SSDahCIbO9YlL3AoA3l1gpLq2f9yTz9JIHm4ytBZmQPD8QU2KBQFsz+/ZE -Gulc0j/3mzlRyoesuVGb79OWBfSDCHittKVFPXqokzNu0jWZVd7GxfJ2DQqUprJd -eK4LDJpInS+Vdohjko8uuC9AfGB68hWbuazjdWLhTNQb3/8EzX5Xu2N88xlWuBQK -HRu8NPp601uI6qdjj38VUXGY5BryDIJdvqf5hoRNe/2scf3OomaMpdck59gLT4LB -/yaNbfPSRenXQ1IM3mU9Opktvm48cpJQ8B80OEmWenhhjXrHrgplVNkXK7inZ7vu -TKia/N90ugY= -=kgC8 ------END PGP SIGNATURE----- diff --git a/SOURCES/libguestfs-1.44.0.tar.gz.sig b/SOURCES/libguestfs-1.44.0.tar.gz.sig new file mode 100644 index 0000000..131c279 --- /dev/null +++ b/SOURCES/libguestfs-1.44.0.tar.gz.sig @@ -0,0 +1,17 @@ +-----BEGIN PGP SIGNATURE----- + +iQJFBAABCAAvFiEE93dPsa0HSn6Mh2fqkXOPc+G3aKAFAl/1jrcRHHJpY2hAYW5u +ZXhpYS5vcmcACgkQkXOPc+G3aKCBcQ/+JwE8JTm3PdTPGoKxCqSgAOirbqE4ZvMY +p/3y5mexagcWXx6X2Y+u6dlybS06jFR8TkbjdE3VAhhJo0C8l1vfvUTWKVDZoBhG +3jZ6e+exff3VEUY4nFIVvYPNP+/J1BCiexMO0/2f1MDKwnJ73je9GlzwPEpdqPj/ +jSxaAy1G/rA5qV5rWQd4n5S9m8zRnf1lnM7YI7I0PunC2Wt/U6BZidL/FVVWVBxV +DGKTIy7GgWnfGWdqJ+Wi9o9QCJH/9FGTP35xonyQEM/7GI+jLz+a9g2xgvv584Ni +FF0Gqywrp5QFd13Nj3MPM7MXjGjUY5vB964k3mgE4fH91CnVvisRWfUCCo+c/9wG +odS0YTrveWJpm0oYU2tL3AjahRclskAxXEIxx9kbnWMUTrpXG0r8G4+vE+estCjb +mbyK5FQh2KASqNgmeopjK9DAEwD7SfPyHmPQ07Q76Pgl8X+FfBX2uyXBjaR5IJJJ +qVVamdVtPilqwWqQ8hGkKE0qVKqZHGCOJ8+AkQjHjUtSVegT6zHmCG/bM4im1dGV +r9fv6oQ7kWViz8mBluoETWr5sd2AfLOdLS8A42JaOnU7ASJUX/9eN0Y9u4BYC9P3 +l+QXikyq6T/4iC+tADOYGBr9uNitksLwSSUYScpnN+4AY+M+qjXTBq38MEHmwcgK +5mwscgQefcY= +=UrAA +-----END PGP SIGNATURE----- diff --git a/SPECS/libguestfs.spec b/SPECS/libguestfs.spec index ff06bc1..6cf69fb 100644 --- a/SPECS/libguestfs.spec +++ b/SPECS/libguestfs.spec @@ -12,152 +12,65 @@ # (none) %global test_arches aarch64 %{power64} s390x x86_64 -# Architectures where virt-v2v is shipped. -# -# not on aarch64 because it is not useful there -# not on %%{power64} because of RHBZ#1287826 -# not on s390x because it is not useful there -%global v2v_arches x86_64 - -# Architectures where the benchmarking tools are shipped. -%global benchmark_arches aarch64 x86_64 - # Trim older changelog entries. # https://lists.fedoraproject.org/pipermail/devel/2013-April/thread.html#181627 %global _changelog_trimtime %(date +%s -d "2 years ago") -# Verify tarball signature with GPGv2 (only possible for stable branches). +# Verify tarball signature with GPGv2. %global verify_tarball_signature 1 +# If there are patches which touch autotools files, set this to 1. +%global patches_touch_autotools 1 + +# The source directory. +%global source_directory 1.44-stable + # Filter perl provides. %{?perl_default_filter} Summary: Access and modify virtual machine disk images Name: libguestfs Epoch: 1 -Version: 1.40.2 -Release: 28%{?dist} +Version: 1.44.0 +Release: 5%{?dist} License: LGPLv2+ -# Source and patches. -URL: http://libguestfs.org/ -Source0: http://libguestfs.org/download/1.40-stable/%{name}-%{version}.tar.gz -%if 0%{verify_tarball_signature} -Source1: http://libguestfs.org/download/1.40-stable/%{name}-%{version}.tar.gz.sig -%endif - ExclusiveArch: x86_64 %{power64} aarch64 s390x +# Source and patches. +URL: http://libguestfs.org/ +Source0: http://libguestfs.org/download/%{source_directory}/%{name}-%{version}.tar.gz +%if 0%{verify_tarball_signature} +Source1: http://libguestfs.org/download/%{source_directory}/%{name}-%{version}.tar.gz.sig +%endif + # RHEL 8 git repository is: -# https://github.com/libguestfs/libguestfs/tree/rhel-8.3.0 +# https://github.com/libguestfs/libguestfs/tree/rhel-8.6.0 # Use 'copy-patches.sh' to copy the patches from the git repo # to the current directory. # Patches. -Patch0001: 0001-daemon-lib-Replace-deprecated-security_context_t-wit.patch -Patch0002: 0002-caml_named_value-returns-const-value-pointer-in-OCam.patch -Patch0003: 0003-ocaml-Change-calls-to-caml_named_value-to-cope-with-.patch -Patch0004: 0004-ocaml-Use-caml_alloc_initialized_string-instead-of-m.patch -Patch0005: 0005-ocaml-Use-caml_alloc_initialized_string-instead-of-m.patch -Patch0006: 0006-ocaml-Change-calls-to-caml_named_value-to-cope-with-.patch -Patch0007: 0007-cat-Fix-GCC-10-warning.patch -Patch0008: 0008-builder-Fix-const-correctness-for-OCaml-4.10.patch -Patch0009: 0009-mlxml-Fix-pointed-target-signedness.patch -Patch0010: 0010-common-mlpcre-add-offset-flag-for-PCRE.matches.patch -Patch0011: 0011-v2v-add-Var_expander.patch -Patch0012: 0012-v2v-add-o-json-output-mode.patch -Patch0013: 0013-inspect-fix-icon-of-RHEL.patch -Patch0014: 0014-v2v-warn-when-the-guest-has-direct-network-interface.patch -Patch0015: 0015-v2v-update-documentation-on-nbdkit-RHBZ-1605242.patch -Patch0016: 0016-v2v-linux-do-not-uninstall-open-vm-tools-w-ubuntu-se.patch -Patch0017: 0017-v2v-linux-canonicalize-module-path-for-arch-detectio.patch -Patch0018: 0018-v2v-linux-improve-arch-detection-from-modules-RHBZ-1.patch -Patch0019: 0019-Use-proper-label-for-nbdkit-sockets.patch -Patch0020: 0020-v2v-start-reading-the-new-libvirt-firmware-autoselec.patch -Patch0021: 0021-common-mltools-move-the-code-for-machine-readable-up.patch -Patch0022: 0022-common-mltools-make-sure-machine-readable-output-is-.patch -Patch0023: 0023-common-mltools-allow-fd-for-machine-readable-output.patch -Patch0024: 0024-OCaml-tools-output-messages-into-JSON-for-machine-re.patch -Patch0025: 0025-OCaml-tools-fix-3999-3339-typo.patch -Patch0026: 0026-v2v-remove-extra-nbdkit-bit-from-documentation-RHBZ-.patch -Patch0027: 0027-v2v-i-vmx-Use-scp-T-option-if-available-to-unbreak-s.patch -Patch0028: 0028-v2v-Allow-Windows-virtio-ISO-to-be-a-block-device-as.patch -Patch0029: 0029-v2v-Set-DISKTYPE-2-in-RHV-and-VDSM-meta-files-RHBZ-1.patch -Patch0030: 0030-v2v-rhv-upload-plugin-improve-wait-logic-after-final.patch -Patch0031: 0031-v2v-o-rhv-upload-check-whether-the-cluster-exists.patch -Patch0032: 0032-v2v-o-rhv-upload-split-vmcheck-out-of-precheck.patch -Patch0033: 0033-v2v-o-rhv-upload-change-precheck-script-to-return-a-.patch -Patch0034: 0034-v2v-o-rhv-upload-improve-lookup-of-specified-resourc.patch -Patch0035: 0035-v2v-o-rhv-upload-tell-whether-a-SD-actually-exists.patch -Patch0036: 0036-v2v-add-output-disk_copied-hook.patch -Patch0037: 0037-v2v-o-rhv-upload-collect-disks-UUIDs-right-after-cop.patch -Patch0038: 0038-v2v-o-rhv-upload-add-oo-rhv-disk-uuid-option.patch -Patch0039: 0039-v2v-o-rhv-upload-make-oo-rhv-cafile-optional.patch -Patch0040: 0040-v2v-Fix-default-graphics-driver-for-SUSE-guests.patch -Patch0041: 0041-v2v-windows-Add-a-helper-function-for-installing-Pow.patch -Patch0042: 0042-v2v-Copy-static-IP-address-information-over-for-Wind.patch -Patch0043: 0043-New-API-luks_uuid.patch -Patch0044: 0044-options-Fix-segfault-when-multiple-key-parameters-gi.patch -Patch0045: 0045-options-Simplify-selector-parsing-for-key-options.patch -Patch0046: 0046-options-Allow-multiple-key-parameters.patch -Patch0047: 0047-options-rename-key.device-as-key.id.patch -Patch0048: 0048-options-allow-a-UUID-as-identifier-for-key.patch -Patch0049: 0049-docs-remove-paragraph-about-VMware-tools-on-Windows-.patch -Patch0050: 0050-mlcustomize-Trim-whitespaces-from-commands-read-from.patch -Patch0051: 0051-openstack-Increase-Cinder-volume-attach-timeout-to-5.patch -Patch0052: 0052-v2v-o-rhv-upload-check-for-a-valid-image-transfer-ri.patch -Patch0053: 0053-rhv-upload-Check-status-more-frequently.patch -Patch0054: 0054-rhv-upload-Show-transfer-id-in-error-message.patch -Patch0055: 0055-rhv-upload-Fix-waiting-for-transfer.patch -Patch0056: 0056-v2v-Optimize-convert-for-images-with-small-holes.patch -Patch0057: 0057-v2v-o-rhv-upload-Make-oo-rhv-cafile-optional-in-all-.patch -Patch0058: 0058-docs-Fix-update-crypto-policies-command-RHBZ-1791257.patch -Patch0059: 0059-add-versioned-directory-for-guest-agent-on-EL8.patch -Patch0060: 0060-v2v-fix-path-to-source-when-copying-files-from-guest.patch -Patch0061: 0061-v2v-windows-install-QEMU-Guest-Agent-MSI.patch -Patch0062: 0062-windows-small-tweaks-of-qemu-ga-firstboot-script.patch -Patch0063: 0063-windows-fix-detection-of-qemu-ga-installer-on-RHV.patch -Patch0064: 0064-windows-delay-installation-of-qemu-ga-MSI.patch -Patch0065: 0065-daemon-xattr-Refactor-code-which-splits-attr-names-f.patch -Patch0066: 0066-daemon-Add-filter_list-utility-function.patch -Patch0067: 0067-daemon-xattr-Filter-out-user.WofCompressedData-from-.patch -Patch0068: 0068-mltools-add-run_in_guest_command-helper.patch -Patch0069: 0069-customize-port-do_run-to-run_in_guest_command.patch -Patch0070: 0070-sysprep-add-a-update_system_ca_store-side-effect.patch -Patch0071: 0071-sysprep-ca-certificates-request-system-CA-store-upda.patch -Patch0072: 0072-sysprep-add-IPA-offline-unenrollment-RHBZ-1789592.patch -Patch0073: 0073-sysprep-add-Kerberos-keytab-file-removal.patch -Patch0074: 0074-vCenter-fix-parsing-of-HTTP-status-string-RHBZ-18373.patch -Patch0075: 0075-RHEL-8-Remove-libguestfs-live-RHBZ-798980.patch -Patch0076: 0076-RHEL-8-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch -Patch0077: 0077-RHEL-8-Disable-unsupported-remote-drive-protocols-RH.patch -Patch0078: 0078-RHEL-8-Remove-User-Mode-Linux-RHBZ-1144197.patch -Patch0079: 0079-RHEL-8-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch -Patch0080: 0080-RHEL-8-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch -Patch0081: 0081-RHEL-8-Disable-alternate-Augeas-lenses.patch -Patch0082: 0082-RHEL-8-Fix-list-of-supported-sound-cards-to-match-RH.patch -Patch0083: 0083-RHEL-8-Reject-use-of-libguestfs-winsupport-features-.patch -Patch0084: 0084-RHEL-8-Fix-tests-for-libguestfs-winsupport.patch -Patch0085: 0085-RHEL-8-tests-Disable-daemon-tests-that-require-the-u.patch -Patch0086: 0086-RHEL-8-v2v-Disable-the-virt-v2v-in-place-option.patch -Patch0087: 0087-RHEL-8-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch -Patch0088: 0088-RHEL-8-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch -Patch0089: 0089-RHEL-8-v2v-rhv-upload-Remove-restriction-on-oa-spars.patch -Patch0090: 0090-RHEL-8-use-platform-python.patch -Patch0091: 0091-RHEL-8-point-to-KB-for-supported-v2v-hypervisors-gue.patch -Patch0092: 0092-lib-Increase-default-memsize-to-1280-RHBZ-1837765.patch -Patch0093: 0093-tar-in-Add-workaround-because-tar-doesn-t-restore-ca.patch -Patch0094: 0094-mlcustomize-Refactor-SELinux_relabel-code.patch -Patch0095: 0095-mlcustomize-Fall-back-to-autorelabel-if-specfile-doe.patch -Patch0096: 0096-daemon-lvm-Use-lvcreate-yes-to-avoid-interactive-pro.patch +Patch0001: 0001-RHEL-8-Remove-libguestfs-live-RHBZ-798980.patch +Patch0002: 0002-RHEL-8-Remove-9p-APIs-from-RHEL-RHBZ-921710.patch +Patch0003: 0003-RHEL-8-Disable-unsupported-remote-drive-protocols-RH.patch +Patch0004: 0004-RHEL-8-Remove-User-Mode-Linux-RHBZ-1144197.patch +Patch0005: 0005-RHEL-8-Reject-use-of-libguestfs-winsupport-features-.patch +Patch0006: 0006-build-Avoid-warnings-about-unknown-pragmas.patch +Patch0007: 0007-daemon-lvm-Use-lvcreate-yes-to-avoid-interactive-pro.patch +Patch0008: 0008-inspection-More-reliable-detection-of-Linux-split-us.patch +Patch0009: 0009-lib-Autodetect-backing-format-for-qemu-img-create-b.patch +Patch0010: 0010-daemon-chroot-Fix-long-standing-possible-deadlock.patch +Patch0011: 0011-inspection-Fix-inspection-of-recent-RPM-guests-using.patch +Patch0012: 0012-inspection-Return-RPM-epoch.patch +Patch0013: 0013-test-data-phony-guests-Fix-phony-RPM-database-fix-vi.patch +Patch0014: 0014-po-POTFILES-Fix-list-of-files-for-translation.patch +Patch0015: 0015-m4-guestfs-find-db-tool.m4-Remove-unused-file.patch +Patch0016: 0016-test-data-phony-guests-Fix-phony-RPM-database-fix-vi.patch +Patch0017: 0017-launch-libvirt-place-our-virtio-net-pci-device-in-sl.patch +Patch0018: 0018-lib-extract-NETWORK_ADDRESS-and-NETWORK_PREFIX-as-ma.patch +Patch0019: 0019-launch-libvirt-add-virtio-net-via-the-standard-inter.patch -# Use git for patch management. -BuildRequires: git - -# Run autotools after applying the patches. -BuildRequires: autoconf, automake, libtool, gettext-devel - -# Replacement README file for RHEL users. +# Replacement README file. Source4: README-replacement.in # Guestfish colour prompts. @@ -171,29 +84,29 @@ Source6: yum.conf.in Source7: libguestfs.keyring %endif -# RHSRVANY and RHEV-APT, used for Windows virt-v2v conversions. -# RHSRVANY is built from source under Fedora from -# mingw32-srvany-1.0-15.20150115gitfd659e77.fc23.noarch -# RHEV-APT is taken from the RHEV Tools CD -# See https://bugzilla.redhat.com/show_bug.cgi?id=1186850 -Source96: rhsrvany.exe -Source97: RHEV-Application-Provisioning-Tool.exe_4.43-5 +# Maintainer script which helps with handling patches. +Source8: copy-patches.sh -Source98: brew-overrides.sh -Source99: copy-patches.sh +%if 0%{patches_touch_autotools} +BuildRequires: autoconf, automake, libtool, gettext-devel +%endif + +# Used to apply the patches. +BuildRequires: git # Basic build requirements for the library and virt tools. BuildRequires: gcc, gcc-c++ +BuildRequires: make BuildRequires: rpcgen BuildRequires: libtirpc-devel -BuildRequires: supermin-devel >= 5.1.16-2 +BuildRequires: supermin-devel >= 5.1.18 BuildRequires: hivex-devel >= 1.3.10-5.8.el7 BuildRequires: ocaml-hivex-devel BuildRequires: perl(Pod::Simple) BuildRequires: perl(Pod::Man) BuildRequires: /usr/bin/pod2text BuildRequires: po4a -BuildRequires: augeas-devel +BuildRequires: augeas-devel >= 1.7.0 BuildRequires: readline-devel BuildRequires: genisoimage BuildRequires: libxml2-devel @@ -212,8 +125,6 @@ BuildRequires: libdb-utils BuildRequires: cpio BuildRequires: libconfig-devel BuildRequires: xz-devel -BuildRequires: zip -BuildRequires: unzip BuildRequires: systemd-units BuildRequires: netpbm-progs BuildRequires: icoutils @@ -221,6 +132,8 @@ BuildRequires: icoutils BuildRequires: libvirt-daemon-kvm >= 5.3.0 BuildRequires: libacl-devel BuildRequires: libcap-devel +# https://bugzilla.redhat.com/show_bug.cgi?id=1836094 +BuildRequires: rpm-devel >= 4.14.3-18.el8 BuildRequires: jansson-devel BuildRequires: systemd-devel BuildRequires: bash-completion @@ -274,13 +187,115 @@ BuildRequires: gjs # for f in `cat appliance/packagelist`; do echo $f; done | sort -u # However you have to edit the list down to packages which exist in # current RHEL, since supermin ignores non-existent packages. -BuildRequires: acl attr augeas-libs bash binutils bzip2 coreutils cpio cryptsetup curl dhclient diffutils dosfstools e2fsprogs file findutils gawk gdisk genisoimage gfs2-utils grep gzip hivex iproute iputils jansson kernel kmod kpartx less libcap libselinux libxml2 lsof lsscsi lvm2 lzop mdadm openssh-clients parted pciutils pcre policycoreutils procps psmisc qemu-img rsync scrub sed squashfs-tools strace systemd tar udev util-linux vim-minimal which xfsprogs xz + +BuildRequires: acl +BuildRequires: attr +BuildRequires: augeas-libs +BuildRequires: bash +BuildRequires: binutils +%if !0%{?rhel} +BuildRequires: btrfs-progs +%endif +BuildRequires: bzip2 +BuildRequires: coreutils +BuildRequires: cpio +BuildRequires: cryptsetup +BuildRequires: curl +%if !0%{?rhel} +BuildRequires: debootstrap +%endif +BuildRequires: dhclient +BuildRequires: diffutils +BuildRequires: dosfstools +BuildRequires: e2fsprogs +BuildRequires: file +BuildRequires: findutils +BuildRequires: gawk +BuildRequires: gdisk +BuildRequires: genisoimage +BuildRequires: gfs2-utils +BuildRequires: grep +BuildRequires: gzip +%if !0%{?rhel} +%ifnarch ppc +BuildRequires: hfsplus-tools +%endif +%endif +BuildRequires: hivex +BuildRequires: iproute +BuildRequires: iputils +%if !0%{?rhel} +BuildRequires: jfsutils +%endif +BuildRequires: kernel +BuildRequires: kmod +BuildRequires: kpartx +BuildRequires: less +BuildRequires: libcap +%if !0%{?rhel} +BuildRequires: libldm +%endif +BuildRequires: libselinux +BuildRequires: libxml2 +BuildRequires: lsof +BuildRequires: lsscsi +BuildRequires: lvm2 +BuildRequires: lzop +BuildRequires: mdadm +%if !0%{?rhel} +BuildRequires: nilfs-utils +%endif +%if !0%{?rhel} +BuildRequires: ntfs-3g ntfsprogs ntfs-3g-system-compression +%endif +BuildRequires: openssh-clients +BuildRequires: parted +BuildRequires: pciutils +BuildRequires: pcre +BuildRequires: policycoreutils +BuildRequires: procps +BuildRequires: psmisc +BuildRequires: qemu-img +%if !0%{?rhel} +BuildRequires: reiserfs-utils +%endif +BuildRequires: rsync +BuildRequires: scrub +BuildRequires: sed +%if !0%{?rhel} +BuildRequires: sleuthkit +%endif +BuildRequires: squashfs-tools +BuildRequires: strace %ifarch %{ix86} x86_64 BuildRequires: syslinux syslinux-extlinux %endif +BuildRequires: systemd +BuildRequires: tar +BuildRequires: udev +BuildRequires: util-linux +BuildRequires: vim-minimal +BuildRequires: which +BuildRequires: xfsprogs +BuildRequires: xz +BuildRequires: yajl +%if !0%{?rhel} +BuildRequires: zerofree +%endif +%if !0%{?rhel} +%ifnarch %{arm} aarch64 s390 s390x riscv64 +# http://zfs-fuse.net/issues/94 +BuildRequires: zfs-fuse +%endif +%endif -# For building the appliance. -Requires: supermin >= 5.1.16-2 +# Main package requires the appliance. This allows the appliance to +# be replaced if there exists a package called +# "libguestfs-noappliance". This package is not provided anywhere, +# you have to provide the dependency or make the package yourself. If +# you do then libguestfs won't install the appliance and you are free +# to replace it with (eg) a fixed appliance. +Requires: (%{name}-appliance = %{epoch}:%{version}-%{release} or %{name}-noappliance) # The daemon dependencies are not included automatically, because it # is buried inside the appliance, so list them here. @@ -289,6 +304,8 @@ Requires: libacl%{?_isa} Requires: libcap%{?_isa} Requires: hivex%{?_isa} >= 1.3.10-5.8.el7 Requires: pcre%{?_isa} +# https://bugzilla.redhat.com/show_bug.cgi?id=1836094 +Requires: rpm-libs%{?_isa} >= 4.14.3-18.el8 Requires: libselinux%{?_isa} Requires: systemd-libs%{?_isa} Requires: yajl%{?_isa} @@ -362,7 +379,6 @@ For enhanced features, install: For developers: libguestfs-devel C/C++ header files and library - libguestfs-benchmarking Benchmarking utilities Language bindings: @@ -375,18 +391,13 @@ Language bindings: ruby-libguestfs Ruby bindings -%ifarch %{benchmark_arches} -%package benchmarking -Summary: Benchmarking utilities for %{name} -Requires: %{name}%{?_isa} = %{epoch}:%{version}-%{release} +%package appliance +Summary: Appliance for %{name} +Requires: supermin >= 5.1.18 -%description benchmarking -%{name}-benchmarking contains utilities for benchmarking and -performance analysis of %{name}, and also for general -understanding of the performance of the kernel and qemu when booting -small appliances. -%endif +%description appliance +%{name}-appliance provides the appliance used by libguestfs. %package devel @@ -508,10 +519,6 @@ BuildArch: noarch Requires: %{name} = %{epoch}:%{version}-%{release} Requires: %{name}-tools-c = %{epoch}:%{version}-%{release} -# NB: Only list deps here which are not picked up automatically. -Requires: perl(Sys::Virt) -Requires: perl(Win::Hivex) >= 1.2.7 - %description tools This package contains miscellaneous system administrator command line @@ -606,50 +613,6 @@ diskimage-builder command. It is compatible with most diskimage-builder elements. -%ifarch %{v2v_arches} -%package -n virt-v2v -Summary: Convert a virtual machine to run on KVM -License: GPLv2+ - -Requires: %{name}%{?_isa} = %{epoch}:%{version}-%{release} -Requires: %{name}-tools-c = %{epoch}:%{version}-%{release} -# First version that added support for ssh, curl, json: URLs. -# (RHBZ#1226683, RHBZ#1226684, RHBZ#1226697). -Requires: qemu-kvm >= 1.5.3-92.el7 - -# For Windows conversions. -Requires: libguestfs-winsupport >= 7.2 - -Requires: gawk -Requires: gzip -Requires: unzip -Requires: curl -Requires: /usr/bin/virsh - -# Ensure the UEFI firmware is available, to properly convert -# EFI guests (RHBZ#1429643). -%ifarch x86_64 -Requires: edk2-ovmf -%endif -%ifarch aarch64 -Requires: edk2-aarch64 -%endif - -# Needed for -it vddk, and -o rhv-upload. -Requires: nbdkit -Requires: nbdkit-python-plugin -Requires: nbdkit-vddk-plugin -Requires: platform-python - - -%description -n virt-v2v -Virt-v2v converts virtual machines from non-KVM hypervisors -to run under KVM. - -To convert physical machines, see the virt-p2v-maker package. -%endif - - %package bash-completion Summary: Bash tab-completion scripts for %{name} tools BuildArch: noarch @@ -810,7 +773,11 @@ for %{name}. tmphome="$(mktemp -d)" gpgv2 --homedir "$tmphome" --keyring %{SOURCE7} %{SOURCE1} %{SOURCE0} %endif -%setup -q +%autosetup -p1 -S git + +%if 0%{patches_touch_autotools} +autoreconf -i +%endif # For sVirt to work, the local temporary directory we use in the tests # must be labelled the same way as /tmp. This doesn't work if either @@ -821,18 +788,6 @@ if [ "$(stat -f -L -c %T .)" != "nfs" ] && \ chcon --reference=/tmp tmp fi -# Use git to manage patches. -# http://rwmj.wordpress.com/2011/08/09/nice-rpm-git-patch-management-trick/ -git init -git config user.email "libguestfs@redhat.com" -git config user.name "libguestfs" -git add . -git commit -a -q -m "%{version} baseline" -git am %{patches} - -# Patches affect Makefile.am and configure.ac, so rerun autotools. -autoreconf -fi - # Replace developer-centric README that ships with libguestfs, with # our replacement file. mv README README.orig @@ -866,7 +821,6 @@ export PYTHON=%{__python3} --disable-haskell \ --disable-erlang \ --disable-golang \ - --with-gtk=no \ $extra # Building index-parse.c by hand works around a race condition in the @@ -936,6 +890,7 @@ gzip --best installed-docs/*.xml # Split up the monolithic packages file in the supermin appliance so # we can install dependencies in subpackages. pushd $RPM_BUILD_ROOT%{_libdir}/guestfs/supermin.d + function move_to { if ! grep -Esq "^$1$" packages; then @@ -946,6 +901,7 @@ function move_to mv packages-t packages echo "$1" >> "$2" } + move_to curl zz-packages-dib move_to kpartx zz-packages-dib move_to qemu-img zz-packages-dib @@ -976,40 +932,9 @@ popd mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/profile.d install -m 0644 %{SOURCE5} $RPM_BUILD_ROOT%{_sysconfdir}/profile.d -# Virt-tools data directory. -mkdir -p $RPM_BUILD_ROOT%{_datadir}/virt-tools -cp %{SOURCE96} $RPM_BUILD_ROOT%{_datadir}/virt-tools/rhsrvany.exe -cp %{SOURCE97} $RPM_BUILD_ROOT%{_datadir}/virt-tools/rhev-apt.exe - -%ifnarch %{v2v_arches} -rm $RPM_BUILD_ROOT%{_bindir}/virt-v2v* -rm $RPM_BUILD_ROOT%{_mandir}/man1/virt-v2v* -rm -r $RPM_BUILD_ROOT%{_datadir}/virt-tools -%endif - -# Delete the v2v test harness. (This might or might not exist -# depending on extra BRs installed when the package is built, so use -# '-f' option here.) -rm -rf $RPM_BUILD_ROOT%{_libdir}/ocaml/v2v_test_harness -rm -rf $RPM_BUILD_ROOT%{_libdir}/ocaml/stublibs/dllv2v_test_harness* -rm -f $RPM_BUILD_ROOT%{_mandir}/man1/virt-v2v-test-harness.1* - # Remove the .gitignore file from ocaml/html which will be copied to docdir. rm ocaml/html/.gitignore -# Delete virt-p2v bash completion files, as virt-p2v was moved -# to its own source. -rm $RPM_BUILD_ROOT%{_datadir}/bash-completion/completions/virt-p2v-* - -%ifarch %{benchmark_arches} -# Copy the benchmarking tools and man pages, since upstream doesn't -# install them by default. NB Don't install the libtool wrapper scripts. -libtool --mode=install install -m 0755 utils/boot-analysis/boot-analysis $RPM_BUILD_ROOT%{_bindir}/libguestfs-boot-analysis -libtool --mode=install install -m 0755 utils/boot-benchmark/boot-benchmark $RPM_BUILD_ROOT%{_bindir}/libguestfs-boot-benchmark -install -m 0755 utils/boot-benchmark/boot-benchmark-range.pl $RPM_BUILD_ROOT%{_bindir}/libguestfs-boot-benchmark-range.pl -install -m 0644 utils/boot-analysis/boot-analysis.1 $RPM_BUILD_ROOT%{_mandir}/man1/libguestfs-boot-analysis.1 -install -m 0644 utils/boot-benchmark/boot-benchmark.1 $RPM_BUILD_ROOT%{_mandir}/man1/libguestfs-boot-benchmark.1 -%endif # Find locale files. %find_lang %{name} @@ -1027,25 +952,19 @@ install -m 0644 utils/boot-benchmark/boot-benchmark.1 $RPM_BUILD_ROOT%{_mandir}/ %files -f %{name}.lang %doc COPYING README %{_bindir}/libguestfs-test-tool -%{_libdir}/guestfs/ -%exclude %{_libdir}/guestfs/supermin.d/zz-packages-* %{_libdir}/libguestfs.so.* %{_mandir}/man1/guestfs-faq.1* %{_mandir}/man1/guestfs-performance.1* %{_mandir}/man1/guestfs-recipes.1* -%{_mandir}/man1/guestfs-release-notes.1* +%{_mandir}/man1/guestfs-release-notes-1*.1* +%{_mandir}/man1/guestfs-release-notes-historical.1* %{_mandir}/man1/guestfs-security.1* %{_mandir}/man1/libguestfs-test-tool.1* -%ifarch %{benchmark_arches} -%files benchmarking -%{_bindir}/libguestfs-boot-analysis -%{_bindir}/libguestfs-boot-benchmark -%{_bindir}/libguestfs-boot-benchmark-range.pl -%{_mandir}/man1/libguestfs-boot-analysis.1* -%{_mandir}/man1/libguestfs-boot-benchmark.1* -%endif +%files appliance +%{_libdir}/guestfs/ +%exclude %{_libdir}/guestfs/supermin.d/zz-packages-* %files devel @@ -1162,23 +1081,6 @@ install -m 0644 utils/boot-benchmark/boot-benchmark.1 $RPM_BUILD_ROOT%{_mandir}/ %{_libdir}/guestfs/supermin.d/zz-packages-dib -%ifarch %{v2v_arches} -%files -n virt-v2v -%doc COPYING README -%{_bindir}/virt-v2v -%{_bindir}/virt-v2v-copy-to-local -%{_mandir}/man1/virt-v2v.1* -%{_mandir}/man1/virt-v2v-copy-to-local.1* -%{_mandir}/man1/virt-v2v-input-vmware.1* -%{_mandir}/man1/virt-v2v-input-xen.1* -%{_mandir}/man1/virt-v2v-output-local.1* -%{_mandir}/man1/virt-v2v-output-openstack.1* -%{_mandir}/man1/virt-v2v-output-rhv.1* -%{_mandir}/man1/virt-v2v-support.1* -%{_datadir}/virt-tools -%endif - - %files bash-completion %dir %{_datadir}/bash-completion/completions %{_datadir}/bash-completion/completions/guestfish @@ -1280,6 +1182,20 @@ install -m 0644 utils/boot-benchmark/boot-benchmark.1 $RPM_BUILD_ROOT%{_mandir}/ %changelog +* Fri Dec 24 2021 Richard W.M. Jones - 1:1.44.0-5 +- Fix libguestfs failure with qemu 6.2, libvirt 7.10 + resolves: rhbz#2035177 + +* Thu Oct 14 2021 Richard W.M. Jones - 1:1.44.0-4 +- Autodetect backing format for qemu-img create -b +- Move appliance to separate subpackage +- Read rpm database through librpm + resolves: rhbz#2013916, rhbz#1989520, rhbz#1836094 + +* Thu Sep 2 2021 Danilo C. L. de Paula - 1.44.0-3.el8 +- Resolves: bz#2000225 + (Rebase virt:rhel module:stream based on AV-8.6) + * Tue Apr 20 2021 Richard W.M. Jones - 1:1.40.2-28 - daemon: lvm: Use lvcreate --yes to avoid interactive prompts resolves: rhbz#1933640