2f9214744a
- Don't comment out patch 0029 (the common submodule update). - Use a common/.gitattributes trick to exclude files from the common patch that are not included in virt-v2v tarball. This also requires some sed hacking. NB: I tried using ':(exclude)...' stuff and it does not work for submodules, at least not with the git version in RHEL 8. For more info see private email thread "Customer case requiring our assistance" in 2023. Reviewed-by: Laszlo Ersek <lersek@redhat.com> resolves: rhbz#2184183
448 lines
16 KiB
Diff
448 lines
16 KiB
Diff
From 9292a4637e8f4d534f4dde70e8e5451f61ad0162 Mon Sep 17 00:00:00 2001
|
|
From: "Richard W.M. Jones" <rjones@redhat.com>
|
|
Date: Tue, 19 Jan 2021 14:22:33 +0000
|
|
Subject: [PATCH] Update common/ submodule to latest upstream.
|
|
|
|
Only for RHEL AV 8.4.0, allowing this branch to be compiled
|
|
from git with libguestfs 1.44.
|
|
---
|
|
common | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
Submodule common 9338df5e...be09523d:
|
|
diff --git a/common/mlcustomize/SELinux_relabel.ml b/common/mlcustomize/SELinux_relabel.ml
|
|
index 44995df6..5ecf7bd7 100644
|
|
--- a/common/mlcustomize/SELinux_relabel.ml
|
|
+++ b/common/mlcustomize/SELinux_relabel.ml
|
|
@@ -28,65 +28,80 @@ 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
|
|
+
|
|
+ (* 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
|
|
+ * 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 "/"
|
|
diff --git a/common/mltools/Makefile.am b/common/mltools/Makefile.am
|
|
index 3b4172db..aea2dce9 100644
|
|
--- a/common/mltools/Makefile.am
|
|
+++ b/common/mltools/Makefile.am
|
|
@@ -95,6 +95,7 @@ libmltools_a_CPPFLAGS = \
|
|
-I$(shell $(OCAMLC) -where) \
|
|
-I$(top_srcdir)/common/utils \
|
|
-I$(top_srcdir)/lib \
|
|
+ $(INCLUDE_DIRECTORY) \
|
|
-I$(top_srcdir)/common/options \
|
|
-I$(top_srcdir)/common/mlgettext \
|
|
-I$(top_srcdir)/common/mlpcre \
|
|
diff --git a/common/mltools/tools_utils.ml b/common/mltools/tools_utils.ml
|
|
index 12718022..d54ec581 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 ab70f583..1d1ac8a8 100644
|
|
--- a/common/mltools/tools_utils.mli
|
|
+++ b/common/mltools/tools_utils.mli
|
|
@@ -195,9 +195,8 @@ val is_btrfs_subvolume : Guestfs.guestfs -> string -> bool
|
|
(** Checks if a filesystem is a btrfs subvolume. *)
|
|
|
|
val inspect_decrypt : Guestfs.guestfs -> key_store -> unit
|
|
-(** Simple implementation of decryption: look for any [crypto_LUKS]
|
|
- partitions and decrypt them, then rescan for VGs. This only works
|
|
- for Fedora whole-disk encryption. *)
|
|
+(** Simple implementation of decryption: look for any encrypted
|
|
+ partitions and decrypt them, then rescan for VGs. *)
|
|
|
|
val with_timeout : string -> int -> ?sleep:int -> (unit -> 'a option) -> 'a
|
|
(** [with_timeout op timeout ?sleep fn] implements a timeout loop.
|
|
@@ -212,3 +211,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. *)
|
|
diff --git a/common/mlutils/unix_utils-c.c b/common/mlutils/unix_utils-c.c
|
|
index 33099611..8acf0395 100644
|
|
--- a/common/mlutils/unix_utils-c.c
|
|
+++ b/common/mlutils/unix_utils-c.c
|
|
@@ -77,6 +77,7 @@ extern value guestfs_int_mllib_mkdtemp (value val_pattern);
|
|
extern value guestfs_int_mllib_realpath (value pathv);
|
|
extern value guestfs_int_mllib_statvfs_statvfs (value pathv);
|
|
extern value guestfs_int_mllib_statvfs_is_network_filesystem (value pathv);
|
|
+extern value guestfs_int_mllib_sysconf_nr_processors_online (value unitv);
|
|
|
|
/* NB: This is a "noalloc" call. */
|
|
value
|
|
@@ -368,3 +369,17 @@ guestfs_int_mllib_statvfs_is_network_filesystem (value pathv)
|
|
return Val_bool (0);
|
|
#endif
|
|
}
|
|
+
|
|
+/* NB: This is a "noalloc" call. */
|
|
+value
|
|
+guestfs_int_mllib_sysconf_nr_processors_online (value unitv)
|
|
+{
|
|
+#ifdef _SC_NPROCESSORS_ONLN
|
|
+ long n;
|
|
+
|
|
+ n = sysconf (_SC_NPROCESSORS_ONLN);
|
|
+ if (n > 0) return Val_int (n);
|
|
+#endif
|
|
+ /* Return a safe value so that callers don't need to deal with errors. */
|
|
+ return Val_int (1);
|
|
+}
|
|
diff --git a/common/mlutils/unix_utils.ml b/common/mlutils/unix_utils.ml
|
|
index 52eb824d..2bdda12a 100644
|
|
--- a/common/mlutils/unix_utils.ml
|
|
+++ b/common/mlutils/unix_utils.ml
|
|
@@ -84,3 +84,8 @@ module StatVFS = struct
|
|
external is_network_filesystem : string -> bool =
|
|
"guestfs_int_mllib_statvfs_is_network_filesystem" "noalloc"
|
|
end
|
|
+
|
|
+module Sysconf = struct
|
|
+ external nr_processors_online : unit -> int =
|
|
+ "guestfs_int_mllib_sysconf_nr_processors_online" "noalloc"
|
|
+end
|
|
diff --git a/common/mlutils/unix_utils.mli b/common/mlutils/unix_utils.mli
|
|
index 4fcea4a3..aead4df2 100644
|
|
--- a/common/mlutils/unix_utils.mli
|
|
+++ b/common/mlutils/unix_utils.mli
|
|
@@ -121,3 +121,12 @@ module StatVFS : sig
|
|
(** [is_network_filesystem path] returns true if [path] is located on
|
|
a network filesystem such as NFS or CIFS. *)
|
|
end
|
|
+
|
|
+module Sysconf : sig
|
|
+ val nr_processors_online : unit -> int
|
|
+ (** [nr_processors_online ()] returns the number of processors
|
|
+ currently online, from [sysconf (_SC_NPROCESSORS_ONLN)].
|
|
+
|
|
+ Note this never fails. In case we cannot get the number of
|
|
+ cores it returns 1. *)
|
|
+end
|
|
diff --git a/common/options/Makefile.am b/common/options/Makefile.am
|
|
index f7ea7493..162d143b 100644
|
|
--- a/common/options/Makefile.am
|
|
+++ b/common/options/Makefile.am
|
|
@@ -41,8 +41,9 @@ liboptions_la_SOURCES = \
|
|
liboptions_la_CPPFLAGS = \
|
|
-DGUESTFS_NO_DEPRECATED=1 \
|
|
-I$(top_srcdir)/common/utils -I$(top_builddir)/common/utils \
|
|
+ -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \
|
|
-I$(top_srcdir)/lib -I$(top_builddir)/lib \
|
|
- -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib
|
|
+ $(INCLUDE_DIRECTORY)
|
|
liboptions_la_CFLAGS = \
|
|
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
|
|
$(LIBCONFIG_CFLAGS) \
|
|
diff --git a/common/options/decrypt.c b/common/options/decrypt.c
|
|
index 683cf5ed..434b7d58 100644
|
|
--- a/common/options/decrypt.c
|
|
+++ b/common/options/decrypt.c
|
|
@@ -25,6 +25,7 @@
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
+#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <libintl.h>
|
|
#include <error.h>
|
|
@@ -38,18 +39,18 @@
|
|
|
|
/**
|
|
* Make a LUKS map name from the partition name,
|
|
- * eg. C<"/dev/vda2" =E<gt> "luksvda2">
|
|
+ * eg. C<"/dev/vda2" =E<gt> "cryptvda2">
|
|
*/
|
|
static void
|
|
make_mapname (const char *device, char *mapname, size_t len)
|
|
{
|
|
size_t i = 0;
|
|
|
|
- if (len < 5)
|
|
+ if (len < 6)
|
|
abort ();
|
|
- strcpy (mapname, "luks");
|
|
- mapname += 4;
|
|
- len -= 4;
|
|
+ strcpy (mapname, "crypt");
|
|
+ mapname += 5;
|
|
+ len -= 5;
|
|
|
|
if (STRPREFIX (device, "/dev/"))
|
|
i = 5;
|
|
@@ -65,10 +66,8 @@ make_mapname (const char *device, char *mapname, size_t len)
|
|
}
|
|
|
|
/**
|
|
- * Simple implementation of decryption: look for any C<crypto_LUKS>
|
|
- * partitions and decrypt them, then rescan for VGs. This only works
|
|
- * for Fedora whole-disk encryption. WIP to make this work for other
|
|
- * encryption schemes.
|
|
+ * Simple implementation of decryption: look for any encrypted
|
|
+ * partitions and decrypt them, then rescan for VGs.
|
|
*/
|
|
void
|
|
inspect_do_decrypt (guestfs_h *g, struct key_store *ks)
|
|
@@ -82,12 +81,21 @@ inspect_do_decrypt (guestfs_h *g, struct key_store *ks)
|
|
|
|
for (i = 0; partitions[i] != NULL; ++i) {
|
|
CLEANUP_FREE char *type = guestfs_vfs_type (g, partitions[i]);
|
|
- if (type && STREQ (type, "crypto_LUKS")) {
|
|
+ if (type &&
|
|
+ (STREQ (type, "crypto_LUKS") || STREQ (type, "BitLocker"))) {
|
|
+ bool is_bitlocker = STREQ (type, "BitLocker");
|
|
char mapname[32];
|
|
make_mapname (partitions[i], mapname, sizeof mapname);
|
|
|
|
#ifdef GUESTFS_HAVE_LUKS_UUID
|
|
- CLEANUP_FREE char *uuid = guestfs_luks_uuid (g, partitions[i]);
|
|
+ CLEANUP_FREE char *uuid = NULL;
|
|
+
|
|
+ /* This fails for Windows BitLocker disks because cryptsetup
|
|
+ * luksUUID cannot read a UUID (unclear if this is a limitation
|
|
+ * of the format or cryptsetup).
|
|
+ */
|
|
+ if (!is_bitlocker)
|
|
+ uuid = guestfs_luks_uuid (g, partitions[i]);
|
|
#else
|
|
const char *uuid = NULL;
|
|
#endif
|
|
@@ -97,11 +105,15 @@ inspect_do_decrypt (guestfs_h *g, struct key_store *ks)
|
|
|
|
/* Try each key in turn. */
|
|
for (j = 0; keys[j] != NULL; ++j) {
|
|
- /* XXX Should we call guestfs_luks_open_ro if readonly flag
|
|
+ /* XXX Should we set GUESTFS_CRYPTSETUP_OPEN_READONLY if readonly
|
|
* is set? This might break 'mount_ro'.
|
|
*/
|
|
guestfs_push_error_handler (g, NULL, NULL);
|
|
+#ifdef GUESTFS_HAVE_CRYPTSETUP_OPEN
|
|
+ r = guestfs_cryptsetup_open (g, partitions[i], keys[j], mapname, -1);
|
|
+#else
|
|
r = guestfs_luks_open (g, partitions[i], keys[j], mapname);
|
|
+#endif
|
|
guestfs_pop_error_handler (g);
|
|
if (r == 0)
|
|
goto opened;
|
|
diff --git a/common/options/uri.c b/common/options/uri.c
|
|
index ac36bccb..6b696fc2 100644
|
|
--- a/common/options/uri.c
|
|
+++ b/common/options/uri.c
|
|
@@ -194,6 +194,7 @@ parse (const char *arg, char **path_ret, char **protocol_ret,
|
|
if (path && path[0] == '/' &&
|
|
(STREQ (uri->scheme, "gluster") ||
|
|
STREQ (uri->scheme, "iscsi") ||
|
|
+ STREQ (uri->scheme, "nbd") ||
|
|
STREQ (uri->scheme, "rbd") ||
|
|
STREQ (uri->scheme, "sheepdog")))
|
|
path++;
|
|
diff --git a/common/utils/guestfs-stringlists-utils.h b/common/utils/guestfs-stringlists-utils.h
|
|
index 0bac1587..ade3b6f3 100644
|
|
--- a/common/utils/guestfs-stringlists-utils.h
|
|
+++ b/common/utils/guestfs-stringlists-utils.h
|
|
@@ -21,7 +21,8 @@
|
|
|
|
/* stringlists-utils.c */
|
|
extern void guestfs_int_free_string_list (char **);
|
|
-extern size_t guestfs_int_count_strings (char *const *);
|
|
+extern size_t guestfs_int_count_strings (char *const *)
|
|
+ __attribute__((__nonnull__ (1)));
|
|
extern char *guestfs_int_concat_strings (char *const *);
|
|
extern char **guestfs_int_copy_string_list (char *const *);
|
|
extern char *guestfs_int_join_strings (const char *sep, char *const *);
|