diff --git a/0029-Update-common-submodule.patch b/0020-Update-common-submodule.patch similarity index 86% rename from 0029-Update-common-submodule.patch rename to 0020-Update-common-submodule.patch index f71d402..996ac0c 100644 --- a/0029-Update-common-submodule.patch +++ b/0020-Update-common-submodule.patch @@ -1,11 +1,7 @@ -From 2666493010b1b82d5b8dbb517c9976727b05184f Mon Sep 17 00:00:00 2001 -Message-ID: <2666493010b1b82d5b8dbb517c9976727b05184f.1770914130.git.crobinso@redhat.com> -In-Reply-To: <859c43b1eb81cfdcb5f481b571e2c387860f8a27.1770914130.git.crobinso@redhat.com> -References: <859c43b1eb81cfdcb5f481b571e2c387860f8a27.1770914130.git.crobinso@redhat.com> +From 63b2ed3a1d3381a5674ff885d28e1104814d52ef Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Wed, 11 Feb 2026 19:09:26 -0500 Subject: [PATCH] Update common submodule -Content-type: text/plain Update to fix: https://issues.redhat.com/browse/RHEL-148423 diff --git a/0030-convert-linux-properly-match-etc-crypttab.patch b/0021-convert-linux-properly-match-etc-crypttab.patch similarity index 76% rename from 0030-convert-linux-properly-match-etc-crypttab.patch rename to 0021-convert-linux-properly-match-etc-crypttab.patch index 3176b0c..c1fb40e 100644 --- a/0030-convert-linux-properly-match-etc-crypttab.patch +++ b/0021-convert-linux-properly-match-etc-crypttab.patch @@ -1,7 +1,4 @@ -From 4e06515083d7effdee91195dbf93082e544a6283 Mon Sep 17 00:00:00 2001 -Message-ID: <4e06515083d7effdee91195dbf93082e544a6283.1771345004.git.crobinso@redhat.com> -In-Reply-To: <859c43b1eb81cfdcb5f481b571e2c387860f8a27.1771345004.git.crobinso@redhat.com> -References: <859c43b1eb81cfdcb5f481b571e2c387860f8a27.1771345004.git.crobinso@redhat.com> +From 0ff94fda02a55353f6ff15ad974e12bc9e31bf3e Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Mon, 16 Feb 2026 13:58:08 -0500 Subject: [PATCH] convert: linux: properly match /etc/crypttab diff --git a/0022-Update-common-submodule.patch b/0022-Update-common-submodule.patch new file mode 100644 index 0000000..8c67cb7 --- /dev/null +++ b/0022-Update-common-submodule.patch @@ -0,0 +1,180 @@ +From 0082abe25fbad04ad22f0e6a555142e93b2cdd45 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 3 Mar 2026 21:11:39 +0000 +Subject: [PATCH] Update common submodule + + Richard W.M. Jones (2): + mlcustomize/firstboot.ml: Be more careful about quoting + mlcustomize: Create a sentinel file when firstboot completes + +Fixes: https://issues.redhat.com/browse/RHEL-152939 + +For RHEL 10.2: +Cherry picked from commit 45b486f5493575717bce93d00adcaefd99af0c10 + +For the cherry pick, we end up with this extra commit from the +submodule. This seems harmless, and better than creating a new +rhel-10.2-virt-v2v branch in the submodule. + + Cole Robinson (1): + build: mark some ocaml commands with $(AM_V_GEN) +--- + common | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Submodule common 22b583b9..cb0e19b7: +diff --git a/common/mlcustomize/Makefile.am b/common/mlcustomize/Makefile.am +index 351524c8..3bdff2a6 100644 +--- a/common/mlcustomize/Makefile.am ++++ b/common/mlcustomize/Makefile.am +@@ -142,7 +142,7 @@ endif + libmlcustomize_a_DEPENDENCIES = $(OBJECTS) + + $(MLCUSTOMIZE_CMA): $(OBJECTS) libmlcustomize.a +- $(OCAMLFIND) mklib $(OCAMLPACKAGES) \ ++ $(AM_V_GEN) $(OCAMLFIND) mklib $(OCAMLPACKAGES) \ + $(OBJECTS) $(libmlcustomize_a_OBJECTS) -o mlcustomize + + # Tests. +diff --git a/common/mlcustomize/firstboot.ml b/common/mlcustomize/firstboot.ml +index f29884c8..5e23a64b 100644 +--- a/common/mlcustomize/firstboot.ml ++++ b/common/mlcustomize/firstboot.ml +@@ -271,6 +271,9 @@ module Windows = struct + (* Create a directory for firstboot scripts in the guest. *) + g#mkdir_p (firstboot_dir // "scripts"); + ++ (* Remove the sentinel file if it exists from a previous run. *) ++ g#rm_f (firstboot_dir // "complete"); ++ + (* Copy pvvxsvc or rhsrvany to the guest. *) + g#upload (virt_tools_data_dir () // srvany) (firstboot_dir // srvany); + +@@ -284,11 +287,11 @@ module Windows = struct + let firstboot_script = sprintf {|@echo off + + setlocal EnableDelayedExpansion +-set firstboot=%s +-set log=%%firstboot%%\log.txt ++set "firstboot=%s" ++set "log=%%firstboot%%\log.txt" + +-set scripts=%%firstboot%%\scripts +-set scripts_done=%%firstboot%%\scripts-done ++set "scripts=%%firstboot%%\scripts" ++set "scripts_done=%%firstboot%%\scripts-done" + + call :main >> "%%log%%" 2>&1 + exit /b +@@ -327,6 +330,10 @@ for %%%%f in ("%%scripts%%"\*.bat) do ( + ) + + :: Fallthrough here if there are no scripts. ++ ++:: Touch a sentinel file to say we have finished. ++type nul > "%%firstboot%%\complete" ++ + echo uninstalling firstboot service + "%%firstboot%%\%s" -s firstboot uninstall + |} firstboot_dir_win srvany in +diff --git a/common/mldrivers/Makefile.am b/common/mldrivers/Makefile.am +index 714fc9f7..aac3da4f 100644 +--- a/common/mldrivers/Makefile.am ++++ b/common/mldrivers/Makefile.am +@@ -94,7 +94,7 @@ endif + libmldrivers_a_DEPENDENCIES = $(OBJECTS) + + $(MLDRIVERS_CMA): $(OBJECTS) libmldrivers.a +- $(OCAMLFIND) mklib $(OCAMLPACKAGES) \ ++ $(AM_V_GEN) $(OCAMLFIND) mklib $(OCAMLPACKAGES) \ + $(OBJECTS) $(libmldrivers_a_OBJECTS) -o mldrivers + + # OCaml dependencies. +diff --git a/common/mlgettext/Makefile.am b/common/mlgettext/Makefile.am +index 712feb11..275b15fa 100644 +--- a/common/mlgettext/Makefile.am ++++ b/common/mlgettext/Makefile.am +@@ -71,11 +71,11 @@ endif + libmlgettext_a_DEPENDENCIES = $(OBJECTS) + + mlgettext.cma: $(BOBJECTS) +- $(OCAMLFIND) ocamlc $(OCAMLPACKAGES) -a $^ -o $@ ++ $(AM_V_GEN) $(OCAMLFIND) ocamlc $(OCAMLPACKAGES) -a $^ -o $@ + + if HAVE_OCAMLOPT + mlgettext.cmxa: $(XOBJECTS) +- $(OCAMLFIND) ocamlopt $(OCAMLPACKAGES) -a $^ -o $@ ++ $(AM_V_GEN) $(OCAMLFIND) ocamlopt $(OCAMLPACKAGES) -a $^ -o $@ + endif + + # Dependencies. +diff --git a/common/mlpcre/Makefile.am b/common/mlpcre/Makefile.am +index a1d8b029..30a60f64 100644 +--- a/common/mlpcre/Makefile.am ++++ b/common/mlpcre/Makefile.am +@@ -83,7 +83,7 @@ endif + libmlpcre_a_DEPENDENCIES = $(OBJECTS) + + $(MLPCRE_CMA): $(OBJECTS) libmlpcre.a +- $(OCAMLFIND) mklib $(OCAMLPACKAGES) \ ++ $(AM_V_GEN) $(OCAMLFIND) mklib $(OCAMLPACKAGES) \ + $(OBJECTS) $(libmlpcre_a_OBJECTS) -cclib -lpcre2-8 -o mlpcre + + # Tests. +diff --git a/common/mlstdutils/Makefile.am b/common/mlstdutils/Makefile.am +index b9632b07..0f881907 100644 +--- a/common/mlstdutils/Makefile.am ++++ b/common/mlstdutils/Makefile.am +@@ -84,11 +84,11 @@ endif + libmlstdutils_a_DEPENDENCIES = $(OBJECTS) + + mlstdutils.cma: $(BOBJECTS) +- $(OCAMLFIND) ocamlc $(OCAMLPACKAGES) -a $^ -o $@ ++ $(AM_V_GEN) $(OCAMLFIND) ocamlc $(OCAMLPACKAGES) -a $^ -o $@ + + if HAVE_OCAMLOPT + mlstdutils.cmxa: $(XOBJECTS) +- $(OCAMLFIND) ocamlopt $(OCAMLPACKAGES) -a $^ -o $@ ++ $(AM_V_GEN) $(OCAMLFIND) ocamlopt $(OCAMLPACKAGES) -a $^ -o $@ + endif + + # Tests. +diff --git a/common/mltools/Makefile.am b/common/mltools/Makefile.am +index e9e0398c..44cfbb1b 100644 +--- a/common/mltools/Makefile.am ++++ b/common/mltools/Makefile.am +@@ -161,7 +161,7 @@ endif + libmltools_a_DEPENDENCIES = $(OBJECTS) + + $(MLTOOLS_CMA): $(OBJECTS) libmltools.a +- $(OCAMLFIND) mklib $(OCAMLPACKAGES) \ ++ $(AM_V_GEN) $(OCAMLFIND) mklib $(OCAMLPACKAGES) \ + $(OBJECTS) $(libmltools_a_OBJECTS) -o mltools + + # Tests. +diff --git a/common/mlutils/Makefile.am b/common/mlutils/Makefile.am +index d52cb9c8..084ce630 100644 +--- a/common/mlutils/Makefile.am ++++ b/common/mlutils/Makefile.am +@@ -86,7 +86,7 @@ endif + libmlcutils_a_DEPENDENCIES = $(OBJECTS) + + $(MLCUTILS_CMA): $(OBJECTS) libmlcutils.a +- $(OCAMLFIND) mklib $(OCAMLPACKAGES) \ ++ $(AM_V_GEN) $(OCAMLFIND) mklib $(OCAMLPACKAGES) \ + $(OBJECTS) $(libmlcutils_a_OBJECTS) \ + -cclib -lutils \ + -o mlcutils +diff --git a/common/mlxml/Makefile.am b/common/mlxml/Makefile.am +index e56b6fd5..db131ab3 100644 +--- a/common/mlxml/Makefile.am ++++ b/common/mlxml/Makefile.am +@@ -84,7 +84,7 @@ endif + libmlxml_a_DEPENDENCIES = $(OBJECTS) + + $(MLXML_CMA): $(OBJECTS) libmlxml.a +- $(OCAMLFIND) mklib $(OCAMLPACKAGES) \ ++ $(AM_V_GEN) $(OCAMLFIND) mklib $(OCAMLPACKAGES) \ + $(OBJECTS) $(libmlxml_a_OBJECTS) \ + -o mlxml + diff --git a/0023-Add-no-fstrim-option-to-disable-fstrim-during-conver.patch b/0023-Add-no-fstrim-option-to-disable-fstrim-during-conver.patch new file mode 100644 index 0000000..7e2f9fa --- /dev/null +++ b/0023-Add-no-fstrim-option-to-disable-fstrim-during-conver.patch @@ -0,0 +1,303 @@ +From 78edeef5dabb46b4354d4708c4fb35901a771a23 Mon Sep 17 00:00:00 2001 +From: sarika +Date: Tue, 9 Dec 2025 16:12:14 +0530 +Subject: [PATCH] Add --no-fstrim option to disable fstrim during conversion + +In particular, fstrim on NTFS is a serialized operation which can be +very slow on large partitions. + +Closes: https://github.com/libguestfs/virt-v2v/pull/121 +Fixes: https://redhat.atlassian.net/browse/RHEL-164271 + +RWMJ: Added documentation, a test, and larger commit message. +(cherry picked from commit 251639458907f06148ecdd5acbac5c43136e7662) +(cherry picked from commit f937f290a4c032c971ad78d1b07e8aefe15eab8a) +--- + convert/convert.ml | 10 ++++++-- + convert/convert.mli | 1 + + docs/virt-v2v.pod | 6 +++++ + in-place/in_place.ml | 5 ++++ + in-place/virt-v2v-in-place.pod | 4 +++ + inspector/inspector.ml | 6 +++++ + inspector/virt-v2v-inspector.pod | 2 ++ + tests/Makefile.am | 2 ++ + tests/test-no-fstrim.sh | 44 ++++++++++++++++++++++++++++++++ + v2v/v2v.ml | 6 +++++ + 10 files changed, 84 insertions(+), 2 deletions(-) + create mode 100755 tests/test-no-fstrim.sh + +diff --git a/convert/convert.ml b/convert/convert.ml +index e3fd41b8..1c1ad2b4 100644 +--- a/convert/convert.ml ++++ b/convert/convert.ml +@@ -40,6 +40,7 @@ type options = { + smp : int option; + static_ips : static_ip list; + customize_ops : Customize_cmdline.ops; ++ no_fstrim : bool; + } + + (* Mountpoint stats, used for free space estimation. *) +@@ -156,8 +157,13 @@ let rec convert input_disks options source = + * because unused blocks are marked in the overlay and thus do + * not have to be copied. + *) +- message (f_"Mapping filesystem data to avoid copying unused and blank areas"); +- do_fstrim g inspect; ++ if not options.no_fstrim then ( ++ message ++ (f_"Mapping filesystem data to avoid copying unused and blank areas"); ++ do_fstrim g inspect ++ ) else ( ++ message (f_"Skipping fstrim (--no-fstrim specified)") ++ ); + + (* Check (fsck) the filesystems after conversion. *) + g#umount_all (); +diff --git a/convert/convert.mli b/convert/convert.mli +index f2a8d662..faf671fc 100644 +--- a/convert/convert.mli ++++ b/convert/convert.mli +@@ -26,6 +26,7 @@ type options = { + smp : int option; (** [--smp] option *) + static_ips : Types.static_ip list; (** [--mac :ip:] option *) + customize_ops : Customize_cmdline.ops; (** virt-customize options *) ++ no_fstrim : bool; (** [--no-fstrim] option *) + } + (** Command line options that get passed through to the conversion code. *) + +diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod +index 04764832..f1bda76a 100644 +--- a/docs/virt-v2v.pod ++++ b/docs/virt-v2v.pod +@@ -473,6 +473,10 @@ are mapped to C. + + See L below. + ++=item B<--no-fstrim> ++ ++Do not trim the filesystem. See L below. ++ + =item B<-o> B + + This is the same as I<-o local>. +@@ -1039,6 +1043,8 @@ fstrim support in the Linux kernel is improving gradually, so over + time some of these restrictions will be lifted and virt-v2v will work + faster. + ++Use I<--no-fstrim> to disable trimming. ++ + =head2 Free space for conversion + + =head3 Free space in the guest +diff --git a/in-place/in_place.ml b/in-place/in_place.ml +index 7e490867..e84266ab 100644 +--- a/in-place/in_place.ml ++++ b/in-place/in_place.ml +@@ -151,6 +151,7 @@ let rec main () = + let set_root_choice = Types.set_root_choice root_choice in + + (* Other options that we handle here. *) ++ let no_fstrim = ref false in + let print_source = ref false in + + let input_modes = +@@ -185,6 +186,8 @@ let rec main () = + s_"Map network ‘in’ to ‘out’"; + [ S 'O' ], Getopt.String ("output.xml", set_output_xml_option), + s_"Set the output filename"; ++ [ L"no-fstrim" ], Getopt.Set no_fstrim, ++ s_"Don't trim filesystems before conversion"; + [ L"print-source" ], Getopt.Set print_source, + s_"Print source and stop"; + [ L"root" ], Getopt.String ("ask|... ", set_root_choice), +@@ -254,6 +257,7 @@ read the man page virt-v2v-in-place(1). + let customize_ops = get_customize_ops () in + let input_conn = !input_conn in + let input_mode = !input_mode in ++ let no_fstrim = !no_fstrim in + let memsize = !memsize in + let output_xml = !output_xml in + let print_source = !print_source in +@@ -326,6 +330,7 @@ read the man page virt-v2v-in-place(1). + smp; + static_ips; + customize_ops; ++ no_fstrim; + } in + + (* Before starting the input module, check there is sufficient +diff --git a/in-place/virt-v2v-in-place.pod b/in-place/virt-v2v-in-place.pod +index 69d2092e..333a6827 100644 +--- a/in-place/virt-v2v-in-place.pod ++++ b/in-place/virt-v2v-in-place.pod +@@ -235,6 +235,10 @@ are mapped to C. + + See L. + ++=item B<--no-fstrim> ++ ++Do not trim the filesystem. See L. ++ + =item B<-O> output.xml + + =item B<-O -> +diff --git a/inspector/inspector.ml b/inspector/inspector.ml +index 752a5c1c..137d5f61 100644 +--- a/inspector/inspector.ml ++++ b/inspector/inspector.ml +@@ -70,6 +70,8 @@ let rec main () = + let smp = ref None in + let set_smp arg = smp := Some arg in + ++ let no_fstrim = ref false in ++ + let network_map = Networks.create () in + let static_ips = ref [] in + let rec add_network str = +@@ -171,6 +173,8 @@ let rec main () = + s_"Map NIC to network or bridge or assign static IP"; + [ S 'm'; L"memsize" ], Getopt.Int ("mb", set_memsize), + s_"Set memory size"; ++ [ L"no-fstrim" ], Getopt.Set no_fstrim, ++ s_"Don't trim filesystems before conversion"; + [ S 'n'; L"network" ], Getopt.String ("in:out", add_network), + s_"Map network ‘in’ to ‘out’"; + [ S 'O' ], Getopt.String ("output.xml", set_output_file_option), +@@ -233,6 +237,7 @@ read the man page virt-v2v-inspector(1). + | Some transport -> + error (f_"unknown input transport ‘-it %s’") transport in + let memsize = !memsize in ++ let no_fstrim = !no_fstrim in + let root_choice = !root_choice in + let smp = !smp in + let static_ips = !static_ips in +@@ -293,6 +298,7 @@ read the man page virt-v2v-inspector(1). + smp; + static_ips; + customize_ops; ++ no_fstrim; + } in + + (* Before starting the input module, check there is sufficient +diff --git a/inspector/virt-v2v-inspector.pod b/inspector/virt-v2v-inspector.pod +index 26770459..65ce71ce 100644 +--- a/inspector/virt-v2v-inspector.pod ++++ b/inspector/virt-v2v-inspector.pod +@@ -202,6 +202,8 @@ virt-v2v-inspector. + + =item B<--network> ... + ++=item B<--no-fstrim> ++ + =item B<-q> + + =item B<--quiet> +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 54cfd124..036cd3bb 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -93,6 +93,7 @@ TESTS = \ + test-mac.sh \ + test-machine-readable.sh \ + test-networks-and-bridges.sh \ ++ test-no-fstrim.sh \ + test-o-glance.sh \ + test-o-kubevirt-fedora.sh \ + test-o-kubevirt-oo-disk.sh \ +@@ -292,6 +293,7 @@ EXTRA_DIST += \ + test-machine-readable.sh \ + test-networks-and-bridges-expected.xml \ + test-networks-and-bridges.sh \ ++ test-no-fstrim.sh \ + test-o-glance.sh \ + test-o-kubevirt-fedora.sh \ + test-o-kubevirt-fedora.yaml.expected \ +diff --git a/tests/test-no-fstrim.sh b/tests/test-no-fstrim.sh +new file mode 100755 +index 00000000..ba84ad96 +--- /dev/null ++++ b/tests/test-no-fstrim.sh +@@ -0,0 +1,44 @@ ++#!/bin/bash - ++# libguestfs virt-v2v test script ++# Copyright (C) 2014-2026 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 --no-fstrim option. ++ ++source ./functions.sh ++set -e ++set -x ++ ++skip_if_skipped ++requires test -s ../test-data/phony-guests/windows.img ++ ++export VIRT_TOOLS_DATA_DIR="$srcdir/../test-data/fake-virt-tools" ++ ++d=test-no-fstrim.d ++rm -rf $d ++cleanup_fn rm -rf $d ++mkdir $d ++ ++$VG virt-v2v --debug-gc \ ++ -i disk ../test-data/phony-guests/windows.img \ ++ --no-fstrim \ ++ -o local -os $d ++ ++# Test the libvirt XML metadata and a disk was created. ++test -f $d/windows.xml ++test -f $d/windows-sda ++ ++cat $d/windows.xml +diff --git a/v2v/v2v.ml b/v2v/v2v.ml +index dd224b40..480fa81a 100644 +--- a/v2v/v2v.ml ++++ b/v2v/v2v.ml +@@ -80,6 +80,8 @@ let rec main () = + let smp = ref None in + let set_smp arg = smp := Some arg in + ++ let no_fstrim = ref false in ++ + let network_map = Networks.create () in + let static_ips = ref [] in + let rec add_network str = +@@ -242,6 +244,8 @@ let rec main () = + s_"Use password from file to connect to output hypervisor"; + [ M"os" ], Getopt.String ("storage", set_string_option_once "-os" output_storage), + s_"Set output storage location"; ++ [ L"no-fstrim" ], Getopt.Set no_fstrim, ++ s_"Don't trim filesystems before conversion"; + [ L"parallel" ], Getopt.Set_int ("N", parallel), + s_"Run up to N instances of nbdcopy in parallel"; + [ L"print-source" ], Getopt.Set print_source, +@@ -324,6 +328,7 @@ read the man page virt-v2v(1). + | Some transport -> + error (f_"unknown input transport ‘-it %s’") transport in + let memsize = !memsize in ++ let no_fstrim = !no_fstrim in + let output_alloc = + match !output_alloc with + | `Not_set | `Sparse -> Types.Sparse +@@ -440,6 +445,7 @@ read the man page virt-v2v(1). + smp; + static_ips; + customize_ops; ++ no_fstrim; + } in + + (* Before starting the input module, check there is sufficient diff --git a/0024-convert-Stop-using-maxmem-xfs_repair-m-option.patch b/0024-convert-Stop-using-maxmem-xfs_repair-m-option.patch new file mode 100644 index 0000000..b6ac8e5 --- /dev/null +++ b/0024-convert-Stop-using-maxmem-xfs_repair-m-option.patch @@ -0,0 +1,52 @@ +From bb9ddf65787ec5e04a465da8d2eee303640b5f5f Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 15 Apr 2026 11:22:34 +0100 +Subject: [PATCH] convert: Stop using maxmem (xfs_repair -m option) + +We originally introduced this option in commit dba4f0d3ba ("convert: +Limit the amount of memory used by xfs_repair"). In the same commit +we also started to use noprefetch (xfs_repair -P). This was to avoid +xfs_repair taking too much memory, causing OOM errors. + +However the -m option turns out to be deprecated. It has a number of +problems and sharp edges, including that it overestimates the amount +of memory required (often, greatly), its estimates are not very +accurate, and it prints a localized error message that libguestfs +needs to parse to obtain useful information. + +xfs_repair has internal logic already to find the available physical +memory and limit memory usage. This also operates even if the -m +option is not used. + +The beneficial option is noprefetch (-P) which limits the caching that +xfs_repair does. Leave that one alone. + +Reported-by: Ming Xie +Thanks: Eric Sandeen, Dave Chinner +Related: https://redhat.atlassian.net/browse/RHEL-165677 +(cherry picked from commit 788bd68663cfc4535753623faa25180fd35f0893) +--- + convert/convert.ml | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/convert/convert.ml b/convert/convert.ml +index 1c1ad2b4..1df8699a 100644 +--- a/convert/convert.ml ++++ b/convert/convert.ml +@@ -333,13 +333,11 @@ and do_fsck ?(before=false) g = + *) + let nomodify = true + (* xfs_repair runs out of memory in the low memory environment +- * of the appliance unless we limit the amount of memory it will +- * use here. ++ * of the appliance unless we disable prefetch. + *) +- and noprefetch = true +- and maxmem = Int64.of_int (g#get_memsize () / 2) in ++ and noprefetch = true in + +- if g#xfs_repair ~maxmem ~noprefetch ~nomodify dev <> 0 then ++ if g#xfs_repair ~noprefetch ~nomodify dev <> 0 then + error (f_"detected errors on the XFS filesystem on %s") dev + + | _, _ -> diff --git a/0025-Update-common-submodule.patch b/0025-Update-common-submodule.patch new file mode 100644 index 0000000..bdaf224 --- /dev/null +++ b/0025-Update-common-submodule.patch @@ -0,0 +1,53 @@ +From 5dd78362a45ed3d64811a606b49eba5435361912 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 23 Apr 2026 15:41:31 +0100 +Subject: [PATCH] Update common submodule + + Richard W.M. Jones (1): + mldrivers/firmware.ml: Ignore CHS geometry error from parted +--- + common | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Submodule common cb0e19b7..29176db2: +diff --git a/common/mldrivers/firmware.ml b/common/mldrivers/firmware.ml +index ee0a7caf..6698b073 100644 +--- a/common/mldrivers/firmware.ml ++++ b/common/mldrivers/firmware.ml +@@ -18,6 +18,7 @@ + + open Printf + ++open Std_utils + open Tools_utils + + module G = Guestfs +@@ -28,12 +29,22 @@ type i_firmware = + + let detect_firmware g = + let parttype_is_gpt dev = +- try g#part_get_parttype dev = "gpt" +- with G.Error msg as exn -> +- (* If it's _not_ "unrecognised disk label" then re-raise it. *) +- if g#last_errno () <> G.Errno.errno_EINVAL then raise exn; +- debug "%s (ignored)" msg; +- false ++ try ++ g#part_get_parttype dev = "gpt" ++ with ++ | G.Error msg when String.find msg "CHS geometry" >= 0 -> ++ (* Parted has poor handling of "sun" partition types, always ++ * issuing a warning because the CHS doesn't match the physical ++ * geometry. Ignore this as we don't care about it in this ++ * function (RHEL-165220). ++ *) ++ debug "%s (ignored)" msg; ++ false ++ | G.Error msg as exn -> ++ (* If it's _not_ "unrecognised disk label" then re-raise it. *) ++ if g#last_errno () <> G.Errno.errno_EINVAL then raise exn; ++ debug "%s (ignored)" msg; ++ false + in + let accumulate_partition (esp_parts, bboot) part = + let dev = g#part_to_dev part in diff --git a/0026-docs-Show-input-parameters-for-i-input-methods.patch b/0026-docs-Show-input-parameters-for-i-input-methods.patch new file mode 100644 index 0000000..5587003 --- /dev/null +++ b/0026-docs-Show-input-parameters-for-i-input-methods.patch @@ -0,0 +1,68 @@ +From d26ac59e9c5b1d8d3d4175c9ef88212c7727f0d3 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 18 Apr 2026 09:08:15 +0100 +Subject: [PATCH] docs: Show input parameters for -i input methods + +Show what input parameters (eg. list of disk images, XML file) should +be used for each input method. This is an attempt to make the +documentation a little clearer. + +(cherry picked from commit 6cb43b899a52aa02d99b385fb270a421d58ce084) +--- + docs/virt-v2v.pod | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod +index f1bda76a..945e8dfc 100644 +--- a/docs/virt-v2v.pod ++++ b/docs/virt-v2v.pod +@@ -266,7 +266,7 @@ Note this options only applies to keys and passphrases for encrypted + devices and partitions, not for passwords used to connect to remote + servers. + +-=item B<-i> B ++=item B<-i> B disk [disk ...] + + Set the input method to I. + +@@ -276,7 +276,7 @@ usually adequate but you can get finer control (eg. of memory and + vCPUs) by using I<-i libvirtxml> instead. Only guests that use a single + disk can be imported this way. + +-=item B<-i> B ++=item B<-i> B name|UUID + + Set the input method to I. This is the default. + +@@ -286,7 +286,7 @@ I<-ic>). + + See L below. + +-=item B<-i> B ++=item B<-i> B guestB<.xml> + + Set the input method to I. + +@@ -295,11 +295,11 @@ This file is read in order to get metadata about the source guest + (such as its name, amount of memory), and also to locate the input + disks. See L below. + +-=item B<-i> B ++=item B<-i> B disk [disk ...] + + This is the same as I<-i disk>. + +-=item B<-i> B ++=item B<-i> B guestB<.ova> + + Set the input method to I. + +@@ -308,7 +308,7 @@ ova manifest file and check the vmdk volumes for validity (checksums) + as well as analyzing the ovf file, and then convert the guest. See + L. + +-=item B<-i> B ++=item B<-i> B guestB<.vmx>|B... + + Set the input method to I. + diff --git a/0027-docs-i-disk-allows-multiple-disk-images.patch b/0027-docs-i-disk-allows-multiple-disk-images.patch new file mode 100644 index 0000000..5ca0fb3 --- /dev/null +++ b/0027-docs-i-disk-allows-multiple-disk-images.patch @@ -0,0 +1,32 @@ +From 58103554de82a24b55b79e8319027b19c66f7e14 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 18 Apr 2026 09:09:04 +0100 +Subject: [PATCH] docs: -i disk allows multiple disk images + +Commit 255722cbf3 ("v2v: Modular virt-v2v") which modularized the +-i disk code silently added the ability to read from multiple disks. +The documentation was not updated and still stated that only a single +disk could be used. + +Remove incorrect statement in the documentation. + +Fixes: commit 255722cbf39afc0b012e2ac00d16fa6ba2f8c21f +(cherry picked from commit 9b758f808710490ccdb4c35d58b0861b32d295d8) +--- + docs/virt-v2v.pod | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod +index 945e8dfc..63d5814e 100644 +--- a/docs/virt-v2v.pod ++++ b/docs/virt-v2v.pod +@@ -273,8 +273,7 @@ Set the input method to I. + In this mode you can read a virtual machine disk image with no + metadata. virt-v2v tries to guess the best default metadata. This is + usually adequate but you can get finer control (eg. of memory and +-vCPUs) by using I<-i libvirtxml> instead. Only guests that use a single +-disk can be imported this way. ++vCPUs) by using I<-i libvirtxml> instead. + + =item B<-i> B name|UUID + diff --git a/0028-i-disk-Allow-nbd-URIs-for-input-disks.patch b/0028-i-disk-Allow-nbd-URIs-for-input-disks.patch new file mode 100644 index 0000000..f5d811e --- /dev/null +++ b/0028-i-disk-Allow-nbd-URIs-for-input-disks.patch @@ -0,0 +1,277 @@ +From f748458503b327aedd6af47583f35533db2b472d Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 18 Apr 2026 09:54:27 +0100 +Subject: [PATCH] -i disk: Allow nbd:// URIs for input disks + +As well as converting from local files, you can now convert from NBD +URIs. This feature lets you do things like converting from local +xz-compressed disk images (thus saving space), or from remote NBD +servers, eg: + + $ nbdkit -r --filter=xz file windows.xz + $ virt-v2v -i disk nbd://localhost -o ... + +or: + + $ virt-v2v -i disk nbd+ssh://server/ -o ... + +This requires nbdkit-nbd-plugin to proxy to connection. (In future we +could optimize this as noted in comments.) + +This is mainly useful for testing, so I didn't yet document or test it +fully. Once we have more confidence in it we can extend the +documentation. + +(cherry picked from commit a153d3e66eb3ce2f08c949f6dde483991aa4bd28) +--- + docs/virt-v2v.pod | 4 + + input/Makefile.am | 2 +- + input/input_disk.ml | 192 +++++++++++++++++++++++++++----------------- + 3 files changed, 124 insertions(+), 74 deletions(-) + +diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod +index 63d5814e..ecb29771 100644 +--- a/docs/virt-v2v.pod ++++ b/docs/virt-v2v.pod +@@ -275,6 +275,10 @@ metadata. virt-v2v tries to guess the best default metadata. This is + usually adequate but you can get finer control (eg. of memory and + vCPUs) by using I<-i libvirtxml> instead. + ++Each disk can be a local file or an C URI if you want to pull ++the guest disk from an NBD server (see L for the ++supported URI formats). ++ + =item B<-i> B name|UUID + + Set the input method to I. This is the default. +diff --git a/input/Makefile.am b/input/Makefile.am +index 0726b9a1..df116c69 100644 +--- a/input/Makefile.am ++++ b/input/Makefile.am +@@ -98,7 +98,7 @@ BOBJECTS = $(SOURCES_ML:.ml=.cmo) + XOBJECTS = $(BOBJECTS:.cmo=.cmx) + + OCAMLPACKAGES = \ +- -package str,unix,guestfs,libvirt \ ++ -package str,unix,guestfs,libvirt,nbd \ + -I $(top_builddir)/common/utils/.libs \ + -I $(top_builddir)/gnulib/lib/.libs \ + -I $(top_builddir)/lib \ +diff --git a/input/input_disk.ml b/input/input_disk.ml +index a5291031..20cd8214 100644 +--- a/input/input_disk.ml ++++ b/input/input_disk.ml +@@ -38,23 +38,134 @@ module Disk = struct + if options.input_options <> [] then + error (f_"no -io (input options) are allowed here"); + +- if args = [] then ++ let nr_disks = List.length args in ++ if nr_disks = 0 then + error (f_"-i disk: expecting a disk image (filename) \ + on the command line"); + +- (* Check the input files exist and are readable. *) +- List.iter (fun disk -> access disk [R_OK]) args; ++ (* Check nbdkit is installed. *) ++ if not (Nbdkit.is_installed ()) then ++ error (f_"nbdkit is not installed or not working. It is required to \ ++ use ‘-i disk’."); ++ if not (Nbdkit.probe_plugin "file") then ++ error (f_"nbdkit-file-plugin is not installed or not working"); ++ if options.read_only && not (Nbdkit.probe_filter "cow") then ++ error (f_"nbdkit-cow-filter is not installed or not working"); ++ ++ (* Each disk on the command line can be a local file or an NBD URI. *) ++ let is_nbd_uri = ++ let h = lazy (NBD.create ()) in ++ fun str -> NBD.is_uri (Lazy.force h) str ++ in ++ ++ (* Function for detecting input format, using guestfs_disk_format. *) ++ let detect_input_format = ++ let g = lazy (open_guestfs ()) in ++ fun disk -> (Lazy.force g)#disk_format disk ++ in ++ ++ (* If there are any NBD URIs on the command line, nbdkit-nbd-plugin ++ * must be available too. ++ *) ++ if List.exists is_nbd_uri args && not (Nbdkit.probe_plugin "nbd") then ++ error (f_"nbdkit-nbd-plugin is not installed or not working"); + + (* What name should we use for the guest? We try to derive it from +- * the first filename passed in. Users can override this using the +- * `-on name' option. ++ * the first filename passed in. If there are no filenames then ++ * we use "unknown". ++ * ++ * Users can override this using the '-on name' option. + *) +- let name = name_from_disk (List.hd args) in ++ let name = ++ let rec loop = function ++ | [] -> ++(* XXX can't print this because we don't know if the user set '-on' ++ warning (f_"-i disk: no local filenames given so we set \ ++ the guest name to \"unknown\". Use ‘-on name’ to \ ++ override the guest name."); ++*) ++ "unknown" ++ | x :: xs when is_nbd_uri x -> ++ loop xs ++ | x :: _ -> ++ name_from_disk x ++ in ++ loop args in ++ ++ (* Convert the command line disks to NBD URIs. *) ++ let uris = ++ List.mapi ( ++ fun i disk -> ++ let sockname = sprintf "in%d" i in ++ let socket = sprintf "%s/%s" dir sockname in ++ On_exit.unlink socket; ++ ++ if is_nbd_uri disk then ( ++ (* For nbd:// on the command line, proxy through ++ * nbdkit-nbd-plugin. This is not ideal. We could ++ * catch special cases here, such as nbd+unix:// ++ * and convert them directly to NBD_URI objects. ++ * That would require parsing NBD URIs ourselves ++ * but would avoid needing an extra nbdkit proxy. ++ * XXX ++ *) ++ let cmd = Nbdkit.create ~name:sockname "nbd" in ++ if options.read_only then ++ Nbdkit.add_filter cmd "cow"; ++ Nbdkit.add_arg cmd "uri" disk; ++ let _, pid = Nbdkit.run_unix socket cmd in ++ ++ (* --exit-with-parent should ensure nbdkit is cleaned ++ * up when we exit, but it's not supported everywhere. ++ *) ++ On_exit.kill pid ++ ) ++ else ( ++ (* Local filename. Use nbdkit-file-plugin for raw, ++ * or qemu-nbd for other formats. ++ * ++ * virt-v2v < 2.12 used to enforce that all disks ++ * had the same format, but that seems unnecessary. ++ *) ++ ++ (* Check the input file exists and is readable. *) ++ access disk [R_OK]; ++ ++ let format = ++ match options.input_format with ++ | Some fmt -> fmt (* -if option overrides everything *) ++ | None -> detect_input_format disk in ++ ++ match format with ++ | "raw" -> ++ let cmd = Nbdkit.create ~name:sockname "file" in ++ if options.read_only then ++ Nbdkit.add_filter cmd "cow"; ++ Nbdkit.add_arg cmd "file" disk; ++ Nbdkit.reduce_memory_pressure cmd; ++ let _, pid = Nbdkit.run_unix socket cmd in ++ ++ (* --exit-with-parent should ensure nbdkit is cleaned ++ * up when we exit, but it's not supported everywhere. ++ *) ++ On_exit.kill pid ++ ++ | format -> ++ let cmd = QemuNBD.create disk in ++ QemuNBD.set_snapshot cmd options.read_only; ++ QemuNBD.set_format cmd (Some format); ++ let _, pid = QemuNBD.run_unix socket cmd in ++ On_exit.kill pid ++ ); ++ ++ NBD_URI.Unix (socket, None) ++ ) args in + + let s_disks = ++ List.make nr_disks () |> + List.mapi ( +- fun i _ -> { s_disk_id = i; s_controller = None } +- ) args in ++ fun i () -> { s_disk_id = i; s_controller = None } ++ ) in + + (* Give the guest a simple generic network interface. *) + let s_nic = { +@@ -85,70 +196,5 @@ module Disk = struct + s_nics = [s_nic]; + } in + +- let input_format = detect_local_input_format options args in +- +- (* Check nbdkit is installed. *) +- if not (Nbdkit.is_installed ()) then +- error (f_"nbdkit is not installed or not working. It is required to \ +- use ‘-i disk’."); +- +- if not (Nbdkit.probe_plugin "file") then +- error (f_"nbdkit-file-plugin is not installed or not working"); +- if options.read_only && not (Nbdkit.probe_filter "cow") then +- error (f_"nbdkit-cow-filter is not installed or not working"); +- +- let uris = +- List.mapi ( +- fun i disk -> +- let sockname = sprintf "in%d" i in +- let socket = sprintf "%s/%s" dir sockname in +- On_exit.unlink socket; +- +- (match input_format with +- | "raw" -> +- let cmd = Nbdkit.create ~name:sockname "file" in +- if options.read_only then +- Nbdkit.add_filter cmd "cow"; +- Nbdkit.add_arg cmd "file" disk; +- Nbdkit.reduce_memory_pressure cmd; +- let _, pid = Nbdkit.run_unix socket cmd in +- +- (* --exit-with-parent should ensure nbdkit is cleaned +- * up when we exit, but it's not supported everywhere. +- *) +- On_exit.kill pid +- +- | format -> +- let cmd = QemuNBD.create disk in +- QemuNBD.set_snapshot cmd options.read_only; +- QemuNBD.set_format cmd (Some format); +- let _, pid = QemuNBD.run_unix socket cmd in +- On_exit.kill pid +- ); +- +- NBD_URI.Unix (socket, None) +- ) args in +- + source, uris +- +- (* For a list of local disks, try to detect the input format if +- * the [-if] option was not used on the command line. If the +- * formats of the disks are different, that is an error. +- *) +- and detect_local_input_format { input_format } filenames = +- match input_format with +- | Some fmt -> fmt +- | None -> +- let formats = +- let g = open_guestfs () in +- List.map g#disk_format filenames in +- +- let rec get_format = function +- | [] -> error (f_"expected >= 1 disk name on the command line") +- | [x] -> x +- | x :: y :: xs when compare x y = 0 -> get_format (y :: xs) +- | _ -> error (f_"disks on the command line have mixed formats") +- in +- +- get_format formats + end diff --git a/0029-tests-Add-test-for-i-disk-nbd-URI.patch b/0029-tests-Add-test-for-i-disk-nbd-URI.patch new file mode 100644 index 0000000..1fa30f8 --- /dev/null +++ b/0029-tests-Add-test-for-i-disk-nbd-URI.patch @@ -0,0 +1,123 @@ +From a4a65048989da029da637a1f6554c391ffe52fcf Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 18 Apr 2026 22:30:27 +0100 +Subject: [PATCH] tests: Add test for -i disk nbd:// URI + +Updates: commit a153d3e66eb3ce2f08c949f6dde483991aa4bd28 +(cherry picked from commit 79d39ec12acfd5c90a2326ef417b948a2154adf4) +--- + tests/Makefile.am | 6 ++-- + tests/test-i-disk-nbd.sh | 78 ++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 82 insertions(+), 2 deletions(-) + create mode 100755 tests/test-i-disk-nbd.sh + +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 036cd3bb..19a60f73 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -70,8 +70,9 @@ TESTS = \ + test-fedora-lvm-on-luks-conversion.sh \ + test-fedora-md-conversion.sh \ + test-floppy.sh \ +- test-i-disk-parallel.sh \ + test-i-disk.sh \ ++ test-i-disk-nbd.sh \ ++ test-i-disk-parallel.sh \ + test-i-ova-bad-sha1.sh \ + test-i-ova-bad-sha256.sh \ + test-i-ova-directory.sh \ +@@ -233,8 +234,9 @@ EXTRA_DIST += \ + test-fedora-md-conversion.sh \ + test-floppy.expected \ + test-floppy.sh \ +- test-i-disk-parallel.sh \ + test-i-disk.sh \ ++ test-i-disk-nbd.sh \ ++ test-i-disk-parallel.sh \ + test-i-ova-as-root.ovf \ + test-i-ova-as-root.sh \ + test-i-ova-bad-sha1.sh \ +diff --git a/tests/test-i-disk-nbd.sh b/tests/test-i-disk-nbd.sh +new file mode 100755 +index 00000000..12a23d7f +--- /dev/null ++++ b/tests/test-i-disk-nbd.sh +@@ -0,0 +1,78 @@ ++#!/bin/bash - ++# libguestfs virt-v2v test script ++# 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. ++ ++# Test -i disk with nbd URIs. ++ ++source ./functions.sh ++set -e ++set -x ++ ++skip_if_skipped ++ ++b=fedora.img ++f=../test-data/phony-guests/$b ++requires test -f $f ++ ++requires xz --version ++ ++# Check we have nbdkit and the plugins and filters required. ++requires nbdkit --version ++requires nbdkit file --version ++requires nbdkit nbd --version ++requires nbdkit null --version ++requires nbdkit null --filter=cow --version ++requires nbdkit null --filter=xz --version ++ ++# Check --exit-with-parent option will work. ++requires nbdkit --exit-with-parent --version ++ ++d=test-i-disk-nbd.d ++rm -rf $d ++cleanup_fn rm -rf $d ++mkdir $d ++ ++cp $f $d/$b ++xz $d/$b ++ ++# Start nbdkit connected to the compressed file. ++nbdkit -r -f --exit-with-parent \ ++ -U $d/sock -P $d/pid \ ++ --filter=xz file $d/$b.xz & ++ ++# Wait for the pidfile to appear. ++for i in {1..60}; do ++ if test -s "$d/pid"; then ++ break ++ fi ++ sleep 1 ++done ++if ! test -s "$d/pid"; then ++ echo "$0: nbdkit: PID file $d/pid was not created" ++ exit 1 ++fi ++cleanup_fn kill "$(cat $d/pid)" ++ ++$VG virt-v2v --debug-gc \ ++ -i disk nbd+unix:///?socket=$d/sock \ ++ -o local -os $d ++ ++# Test the libvirt XML metadata and a disk was created. ++test -f $d/unknown.xml ++test -f $d/unknown-sda ++ ++cat $d/unknown.xml diff --git a/0030-common-update-submodule.patch b/0030-common-update-submodule.patch new file mode 100644 index 0000000..7cdf3d0 --- /dev/null +++ b/0030-common-update-submodule.patch @@ -0,0 +1,331 @@ +From e342104e305251911ed4e769659fc708a9ab4d64 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 28 Apr 2026 17:01:26 +0100 +Subject: [PATCH] common: update submodule + + Richard W.M. Jones (4): + utils: Add read_whole_file function + options/keys.c: When reading key from user, prefix with "text:" + options/keys.c: When using --key :key:, prefix with "text:" + options/keys.c: When reading the key from a file, encode it with base64 + +Also this now requires libguestfs >= 1.59.7 because we rely on text: +and base64: prefixes in LUKS functions. + +Fixes: https://redhat.atlassian.net/browse/RHEL-170864 +(cherry picked from commit 020fb2cdd145ae24f9d84ea60e0e3df15afdb0ff) +--- + common | 2 +- + m4/guestfs-libraries.m4 | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +Submodule common 29176db2..31d0d6d4: +diff --git a/common/options/keys.c b/common/options/keys.c +index 7027104a..432e26dc 100644 +--- a/common/options/keys.c ++++ b/common/options/keys.c +@@ -37,17 +37,23 @@ + * Read a passphrase ('Key') from F with echo off. + * + * The caller (F) will call free on the string +- * afterwards. Based on the code in cryptsetup file F. ++ * afterwards. ++ * ++ * The entered string is prefixed with "text:..." to avoid ambiguity ++ * (with libguestfs >= 1.60). Base64 encoding cannot be used here. ++ * ++ * Based on the code in cryptsetup file F. + */ + char * + read_key (const char *param) + { + FILE *infp, *outfp; + struct termios orig, temp; ++ CLEANUP_FREE char *key = NULL; ++ size_t keysize = 0; + char *ret = NULL; + int tty; + int tcset = 0; +- size_t allocsize = 0; + ssize_t len; + + /* Read and write to /dev/tty if available. */ +@@ -75,16 +81,21 @@ read_key (const char *param) + } + } + +- len = getline (&ret, &allocsize, infp); ++ len = getline (&key, &keysize, infp); + if (len == -1) { + perror ("getline"); +- ret = NULL; + goto error; + } + + /* Remove the terminating \n if there is one. */ +- if (len > 0 && ret[len-1] == '\n') +- ret[len-1] = '\0'; ++ if (len > 0 && key[len-1] == '\n') ++ key[len-1] = '\0'; ++ ++ /* Prefix with "text:". */ ++ if (asprintf (&ret, "text:%s", key) == -1) { ++ perror ("asprintf"); ++ goto error; ++ } + + error: + /* Restore echo, close file descriptor. */ +@@ -99,27 +110,60 @@ read_key (const char *param) + return ret; + } + ++/* Read a key from a file and base64 encode it, returning "base64:..." */ + static char * +-read_first_line_from_file (const char *filename) ++read_key_and_base64_encode (const char *filename) + { +- CLEANUP_FCLOSE FILE *fp = NULL; +- char *ret = NULL; +- size_t allocsize = 0; +- ssize_t len; +- +- fp = fopen (filename, "r"); +- if (!fp) +- error (EXIT_FAILURE, errno, "fopen: %s", filename); +- +- len = getline (&ret, &allocsize, fp); +- if (len == -1) +- error (EXIT_FAILURE, errno, "getline: %s", filename); ++ CLEANUP_FREE char *inp = NULL; ++ char *out; ++ size_t inplen, outlen, i, j; ++ ++ if (read_whole_file (filename, &inp, &inplen) == -1) ++ error (EXIT_FAILURE, 0, "read_key_and_base64_encode: read_whole_file: %s", ++ filename); ++ ++ /* From https://stackoverflow.com/a/6782480 */ ++ static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', ++ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', ++ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', ++ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', ++ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', ++ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', ++ 'w', 'x', 'y', 'z', '0', '1', '2', '3', ++ '4', '5', '6', '7', '8', '9', '+', '/'}; ++ static int mod_table[] = {0, 2, 1}; ++ ++ outlen = 4 * ((inplen + 2) / 3); ++ out = malloc (outlen + 7 + 1); ++ if (!out) ++ error (EXIT_FAILURE, errno, "read_key_and_base64_encode: %s: malloc", ++ filename); ++ ++ /* Add prefix and NUL-termination, then adjust 'out' to make the ++ * rest of the code simpler. ++ */ ++ memcpy (out, "base64:", 7); ++ out[7 + outlen] = '\0'; ++ out += 7; ++ ++ for (i = 0, j = 0; i < inplen;) { ++ uint32_t octet_a = i < inplen ? (unsigned char) inp[i++] : 0; ++ uint32_t octet_b = i < inplen ? (unsigned char) inp[i++] : 0; ++ uint32_t octet_c = i < inplen ? (unsigned char) inp[i++] : 0; ++ ++ uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; ++ ++ assert (j <= outlen-4); ++ out[j++] = encoding_table[(triple >> 3 * 6) & 0x3F]; ++ out[j++] = encoding_table[(triple >> 2 * 6) & 0x3F]; ++ out[j++] = encoding_table[(triple >> 1 * 6) & 0x3F]; ++ out[j++] = encoding_table[(triple >> 0 * 6) & 0x3F]; ++ } + +- /* Remove the terminating \n if there is one. */ +- if (len > 0 && ret[len-1] == '\n') +- ret[len-1] = '\0'; ++ for (i = 0; i < mod_table[inplen % 3]; i++) ++ out[outlen - 1 - i] = '='; + +- return ret; ++ return out - 7 /* see above */; + } + + /* Return the key(s) matching this particular device from the +@@ -163,15 +207,14 @@ get_keys (struct key_store *ks, const char *device, const char *uuid, + + switch (key->type) { + case key_string: +- s = strdup (key->string.s); +- if (!s) +- error (EXIT_FAILURE, errno, "strdup"); ++ if (asprintf (&s, "text:%s", key->string.s) == -1) ++ error (EXIT_FAILURE, errno, "asprintf"); + match->clevis = false; + match->passphrase = s; + ++match; + break; + case key_file: +- s = read_first_line_from_file (key->file.name); ++ s = read_key_and_base64_encode (key->file.name); + match->clevis = false; + match->passphrase = s; + ++match; +diff --git a/common/utils/Makefile.am b/common/utils/Makefile.am +index 25c6100b..f328dcad 100644 +--- a/common/utils/Makefile.am ++++ b/common/utils/Makefile.am +@@ -30,6 +30,7 @@ libutils_la_SOURCES = \ + libxml2-writer-macros.h \ + pcre2-cleanups.c \ + stringlists-utils.c \ ++ whole-file.c \ + utils.c + libutils_la_CPPFLAGS = \ + -DGUESTFS_NO_DEPRECATED=1 \ +diff --git a/common/utils/guestfs-utils.h b/common/utils/guestfs-utils.h +index e861e7db..a8bd9ac2 100644 +--- a/common/utils/guestfs-utils.h ++++ b/common/utils/guestfs-utils.h +@@ -113,4 +113,8 @@ extern const char *guestfs_int_strerror (int errnum, char *buf, size_t buflen); + /* environ.c */ + extern char **guestfs_int_copy_environ (char **env, ...); + ++/* whole-file.c */ ++extern int read_whole_file (const char *filename, ++ char **data_r, size_t *size_r); ++ + #endif /* GUESTFS_UTILS_H_ */ +diff --git a/common/utils/whole-file.c b/common/utils/whole-file.c +new file mode 100644 +index 00000000..a896e024 +--- /dev/null ++++ b/common/utils/whole-file.c +@@ -0,0 +1,111 @@ ++/* libguestfs ++ * Copyright (C) 2011-2026 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 ++#include ++ ++#include "guestfs-utils.h" ++ ++/** ++ * Read the whole file C into a memory buffer. ++ * ++ * The memory buffer is initialized and returned in C. The ++ * size of the file in bytes is returned in C. The return ++ * buffer must be freed by the caller. ++ * ++ * On error this prints an error on C and returns -1. Unlike ++ * the similar C this does not use the ++ * libguestfs handle or call C. ++ * ++ * For the convenience of callers, the returned buffer is ++ * NUL-terminated (the NUL is not included in the size). ++ * ++ * The file must be a B, B, B file. In ++ * particular, do not use this function to read files that might be ++ * under control of an untrusted user since that will lead to a ++ * denial-of-service attack. ++ */ ++int ++read_whole_file (const char *filename, char **data_r, size_t *size_r) ++{ ++ int fd; ++ char *data; ++ off_t size; ++ off_t n; ++ ssize_t r; ++ struct stat statbuf; ++ ++ fd = open (filename, O_RDONLY|O_CLOEXEC); ++ if (fd == -1) { ++ perror (filename); ++ return -1; ++ } ++ ++ if (fstat (fd, &statbuf) == -1) { ++ perror (filename); ++ close (fd); ++ return -1; ++ } ++ ++ size = statbuf.st_size; ++ data = malloc (size + 1); ++ if (data == NULL) { ++ perror ("malloc"); ++ close (fd); ++ return -1; ++ } ++ ++ n = 0; ++ while (n < size) { ++ r = read (fd, &data[n], size - n); ++ if (r == -1) { ++ perror (filename); ++ free (data); ++ close (fd); ++ return -1; ++ } ++ if (r == 0) { ++ fprintf (stderr, "%s: unexpected end of input", filename); ++ free (data); ++ close (fd); ++ return -1; ++ } ++ n += r; ++ } ++ ++ if (close (fd) == -1) { ++ perror (filename); ++ free (data); ++ return -1; ++ } ++ ++ /* For convenience of callers, \0-terminate the data. */ ++ data[size] = '\0'; ++ ++ *data_r = data; ++ if (size_r != NULL) ++ *size_r = size; ++ ++ return 0; ++} +diff --git a/m4/guestfs-libraries.m4 b/m4/guestfs-libraries.m4 +index 11c9974c..22af5db7 100644 +--- a/m4/guestfs-libraries.m4 ++++ b/m4/guestfs-libraries.m4 +@@ -19,7 +19,8 @@ dnl Any C libraries required by virt-v2v. + + dnl Of course we need libguestfs. + dnl +-dnl We need libguestfs >= 1.58.1-2.el10 for guestfs_xfs_info2. ++dnl We need libguestfs >= 1.58.1-6.el10 for guestfs_xfs_info2 ++dnl and for text: and base64: prefix in LUKS funcs. + PKG_CHECK_MODULES([LIBGUESTFS], [libguestfs >= 1.58.1]) + printf "libguestfs version is "; $PKG_CONFIG --modversion libguestfs + diff --git a/0031-common-update-submodule.patch b/0031-common-update-submodule.patch new file mode 100644 index 0000000..a88cd39 --- /dev/null +++ b/0031-common-update-submodule.patch @@ -0,0 +1,122 @@ +From bd5e315f274994bd0a537631ad80a1bcf2911647 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 5 May 2026 12:40:49 +0100 +Subject: [PATCH] common: update submodule + + Richard W.M. Jones (1): + mlcustomize: Update generated files + + Srihari Parimi (1): + mlcustomize: firstboot.bat must not reboot VM on error code 250 + +(cherry picked from commit 463d0bbd471bc49df7dfb37231a468bfb0510fdc) +--- + common | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Submodule common 31d0d6d4..763a2102: +diff --git a/common/mlcustomize/customize-options.pod b/common/mlcustomize/customize-options.pod +index c8de3953..95767cc7 100644 +--- a/common/mlcustomize/customize-options.pod ++++ b/common/mlcustomize/customize-options.pod +@@ -161,10 +161,7 @@ conveniently wraps the command up in a single line script for you. + You can have multiple I<--firstboot> options. They run in the same + order that they appear on the command line. + +-Please take a look at L for more +-information and caveats about the first boot scripts. +- +-See also I<--run>. ++See also: L, I<--run>. + + =item B<--firstboot-command> 'CMD+ARGS' + +@@ -174,10 +171,7 @@ boots up (as root, late in the boot process). + You can have multiple I<--firstboot> options. They run in the same + order that they appear on the command line. + +-Please take a look at L for more +-information and caveats about the first boot scripts. +- +-See also I<--run>. ++See also: L, I<--run>. + + =item B<--firstboot-install> PKG,PKG.. + +diff --git a/common/mlcustomize/customize_cmdline.ml b/common/mlcustomize/customize_cmdline.ml +index 786f4ee4..b8eda519 100644 +--- a/common/mlcustomize/customize_cmdline.ml ++++ b/common/mlcustomize/customize_cmdline.ml +@@ -252,13 +252,13 @@ let rec argspec ?(v2v = false) () = + Getopt.String (s_"SCRIPT", fun s -> List.push_front (`FirstbootScript s) ops), + s_"Run script at first guest boot" + ), +- Some "SCRIPT", "Install C