Compare commits
No commits in common. "v2.7.4" and "sisyphus" have entirely different histories.
29
.gear/cronbuild-update-source
Executable file
29
.gear/cronbuild-update-source
Executable file
@ -0,0 +1,29 @@
|
||||
#!/bin/bash -vue
|
||||
|
||||
SPEC="$1"
|
||||
|
||||
PKG_NAME="$(gear --command sh -- -c 'printf %s "$gear_pkg_name"')"
|
||||
OLD_VERSION="$(gear --command sh -- -c 'printf %s "$gear_pkg_version"')"
|
||||
git fetch upstream
|
||||
# Only even minor versions are stable
|
||||
NEW_VERSION="$(git tag | sed -En 's/^v([0-9]+\.[0-9]*[02468]\.[0-9]+)$/\1/p' | tail -1)"
|
||||
if [ "$OLD_VERSION" = "$NEW_VERSION" ]; then
|
||||
exit 0
|
||||
fi
|
||||
MINOR_VERSION="$(echo "$NEW_VERSION" | sed -E 's/(.*\..*)\..*/\1/')"
|
||||
|
||||
tmpdir=
|
||||
atexit() {
|
||||
[ -z "$tmpdir" ] || rm -rf -- "$tmpdir"
|
||||
exit "$@"
|
||||
}
|
||||
|
||||
tmpdir=$(mktemp -dt "update_$PKG_NAME.XXXXXXXX")
|
||||
trap 'atexit $?' EXIT
|
||||
trap 'exit 143' HUP INT QUIT PIPE TERM
|
||||
|
||||
pushd "$tmpdir"
|
||||
wget "https://download.libguestfs.org/virt-v2v/$MINOR_VERSION-stable/virt-v2v-$NEW_VERSION.tar.gz"
|
||||
popd
|
||||
|
||||
gear-uupdate "$tmpdir/virt-v2v-$NEW_VERSION.tar.gz" "$NEW_VERSION"
|
2
.gear/rules
Normal file
2
.gear/rules
Normal file
@ -0,0 +1,2 @@
|
||||
copy: *.patch
|
||||
tar.gz: virt name=virt-v2v-@version@
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
||||
[submodule "common"]
|
||||
path = common
|
||||
url = https://github.com/libguestfs/libguestfs-common
|
1
common
1
common
@ -1 +0,0 @@
|
||||
Subproject commit 4b0f1890a41444fdacc71e418e56f6d78b46aa26
|
24
fixes-common.patch
Normal file
24
fixes-common.patch
Normal file
@ -0,0 +1,24 @@
|
||||
diff --git a/mlpcre/Makefile.am b/mlpcre/Makefile.am
|
||||
index a1d8b02..fbf53de 100644
|
||||
--- a/mlpcre/Makefile.am
|
||||
+++ b/mlpcre/Makefile.am
|
||||
@@ -58,6 +58,7 @@ libmlpcre_a_CPPFLAGS = \
|
||||
libmlpcre_a_CFLAGS = \
|
||||
-pthread \
|
||||
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
|
||||
+ $(PCRE_CFLAGS) \
|
||||
-fPIC
|
||||
|
||||
BOBJECTS = $(SOURCES_ML:.ml=.cmo)
|
||||
diff --git a/mltools/Makefile.am b/mltools/Makefile.am
|
||||
index f510a67..c55eb97 100644
|
||||
--- a/mltools/Makefile.am
|
||||
+++ b/mltools/Makefile.am
|
||||
@@ -118,6 +118,7 @@ libmltools_a_CFLAGS = \
|
||||
$(LIBGUESTFS_CFLAGS) \
|
||||
$(JANSSON_CFLAGS) \
|
||||
$(LIBOSINFO_CFLAGS) \
|
||||
+ $(PCRE_CFLAGS) \
|
||||
-fPIC
|
||||
|
||||
BOBJECTS = $(SOURCES_ML:.ml=.cmo)
|
@ -1,167 +0,0 @@
|
||||
(* virt-v2v-inspector
|
||||
* Copyright (C) 2009-2022 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 Types
|
||||
open Utils
|
||||
open DOM
|
||||
|
||||
(* This is where we construct the final XML document based on
|
||||
* these inputs:
|
||||
* - Global configuration like the version of v2v etc.
|
||||
* - The NBD input sockets: v2vdir // "in0", "in1", etc
|
||||
* - The inspection data (Types.inspect)
|
||||
*)
|
||||
let rec create_inspector_xml v2vdir inspect target_meta =
|
||||
let body = ref [] in
|
||||
|
||||
(* Record the version of virt-v2v etc, mainly for debugging. *)
|
||||
List.push_back_list body [
|
||||
Comment generated_by;
|
||||
e "program" [] [PCData "virt-v2v-inspector"];
|
||||
e "package" [] [PCData Config.package_name];
|
||||
e "version" [] [PCData Config.package_version];
|
||||
];
|
||||
|
||||
(* The disks. *)
|
||||
let disks = ref [] in
|
||||
|
||||
List.iter (
|
||||
fun (i, virtual_size) ->
|
||||
let elems = ref [] in
|
||||
List.push_back elems (e "virtual-size" []
|
||||
[PCData (Int64.to_string virtual_size)]);
|
||||
(match get_input_disk_allocated v2vdir i with
|
||||
| None -> ()
|
||||
| Some real_size ->
|
||||
List.push_back elems (e "allocated" [ "estimated", "true" ]
|
||||
[PCData (Int64.to_string real_size)])
|
||||
);
|
||||
|
||||
List.push_back disks (e "disk" [ "index", string_of_int i ] !elems)
|
||||
) (get_disks v2vdir);
|
||||
List.push_back body (e "disks" [] !disks);
|
||||
|
||||
(* The <firmware> field is outside the <operatingsystem> element,
|
||||
* since firmware is not part of the OS, and also because this is
|
||||
* consistent with virt-drivers output.
|
||||
*)
|
||||
List.push_back body
|
||||
(e "firmware"
|
||||
["type",
|
||||
string_of_target_firmware target_meta.target_firmware]
|
||||
[]);
|
||||
|
||||
(* The inspection data. *)
|
||||
(* NB: Keep these field names compatible with virt-inspector! *)
|
||||
let os = ref [] in
|
||||
List.push_back os (e "name" [] [PCData inspect.i_type]);
|
||||
List.push_back os (e "distro" [] [PCData inspect.i_distro]);
|
||||
List.push_back os (e "osinfo" [] [PCData inspect.i_osinfo]);
|
||||
List.push_back os (e "arch" [] [PCData inspect.i_arch]);
|
||||
List.push_back os (e "major_version" []
|
||||
[PCData (string_of_int inspect.i_major_version)]);
|
||||
List.push_back os (e "minor_version" []
|
||||
[PCData (string_of_int inspect.i_minor_version)]);
|
||||
if inspect.i_package_format <> "" then
|
||||
List.push_back os (e "package_format" []
|
||||
[PCData inspect.i_package_format]);
|
||||
if inspect.i_package_management <> "" then
|
||||
List.push_back os (e "package_management" []
|
||||
[PCData inspect.i_package_management]);
|
||||
if inspect.i_product_name <> "" then
|
||||
List.push_back os (e "product_name" [] [PCData inspect.i_product_name]);
|
||||
if inspect.i_product_variant <> "" then
|
||||
List.push_back os (e "product_variant" []
|
||||
[PCData inspect.i_product_variant]);
|
||||
|
||||
if inspect.i_windows_systemroot <> "" then
|
||||
List.push_back os (e "windows_systemroot" []
|
||||
[PCData inspect.i_windows_systemroot]);
|
||||
if inspect.i_windows_software_hive <> "" then
|
||||
List.push_back os (e "windows_software_hive" []
|
||||
[PCData inspect.i_windows_software_hive]);
|
||||
if inspect.i_windows_systemroot <> "" then
|
||||
List.push_back os (e "windows_system_hive" []
|
||||
[PCData inspect.i_windows_system_hive]);
|
||||
if inspect.i_windows_current_control_set <> "" then
|
||||
List.push_back os (e "windows_current_control_set" []
|
||||
[PCData inspect.i_windows_current_control_set]);
|
||||
|
||||
List.push_back os (e "root" [] [PCData inspect.i_root]);
|
||||
let mps = ref [] in
|
||||
List.iter (
|
||||
fun (fs, dev) ->
|
||||
List.push_back mps (e "mountpoint" [ "dev", dev ] [PCData fs])
|
||||
) inspect.i_mountpoints;
|
||||
List.push_back os (e "mountpoints" [] !mps);
|
||||
|
||||
List.push_back body (e "operatingsystem" [] !os);
|
||||
|
||||
(* Construct the final document. *)
|
||||
(doc "v2v-inspection" [] !body : DOM.doc)
|
||||
|
||||
|
||||
(* This is a copy of {!Output.get_disks}. *)
|
||||
and get_disks dir =
|
||||
let rec loop acc i =
|
||||
let socket = sprintf "%s/in%d" dir i in
|
||||
if Sys.file_exists socket then (
|
||||
let size = Utils.with_nbd_connect_unix ~socket NBD.get_size in
|
||||
loop ((i, size) :: acc) (i+1)
|
||||
)
|
||||
else
|
||||
List.rev acc
|
||||
in
|
||||
loop [] 0
|
||||
|
||||
(* This is like {!Utils.get_disk_allocated} but works on the input disks. *)
|
||||
and get_input_disk_allocated dir i =
|
||||
let socket = sprintf "%s/in%d" dir i
|
||||
and alloc_ctx = "base:allocation" in
|
||||
with_nbd_connect_unix ~socket ~meta_contexts:[alloc_ctx]
|
||||
(fun nbd ->
|
||||
if NBD.can_meta_context nbd alloc_ctx then (
|
||||
(* Get the list of extents, using a 2GiB chunk size as hint. *)
|
||||
let size = NBD.get_size nbd
|
||||
and allocated = ref 0_L
|
||||
and fetch_offset = ref 0_L in
|
||||
while !fetch_offset < size do
|
||||
let remaining = size -^ !fetch_offset in
|
||||
let fetch_size = min 0x8000_0000_L remaining in
|
||||
NBD.block_status nbd fetch_size !fetch_offset
|
||||
(fun ctx offset entries err ->
|
||||
assert (ctx = alloc_ctx);
|
||||
for i = 0 to Array.length entries / 2 - 1 do
|
||||
let len = entries.(i * 2)
|
||||
and typ = entries.(i * 2 + 1) in
|
||||
assert (len > 0_L);
|
||||
if typ &^ 1_L = 0_L then
|
||||
allocated := !allocated +^ len;
|
||||
fetch_offset := !fetch_offset +^ len
|
||||
done;
|
||||
0
|
||||
)
|
||||
done;
|
||||
Some !allocated
|
||||
) else None
|
||||
)
|
@ -1,297 +0,0 @@
|
||||
# libguestfs tests
|
||||
# Copyright (C) 2009-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.
|
||||
|
||||
include $(top_srcdir)/subdir-rules.mk
|
||||
|
||||
EXTRA_DIST = functions.sh.in
|
||||
check_DATA = functions.sh
|
||||
|
||||
# Small utility to check for a needed libvirt version;
|
||||
# to be used in shell/script-based tests.
|
||||
noinst_PROGRAMS = libvirt-is-version
|
||||
|
||||
libvirt_is_version_SOURCES = libvirt-is-version.c
|
||||
|
||||
libvirt_is_version_LDADD = \
|
||||
$(LIBVIRT_LIBS) \
|
||||
$(LTLIBINTL)
|
||||
|
||||
libvirt_is_version_CPPFLAGS = \
|
||||
-DLOCALEBASEDIR=\""$(datadir)/locale"\"
|
||||
|
||||
libvirt_is_version_CFLAGS = \
|
||||
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
|
||||
$(LIBVIRT_CFLAGS)
|
||||
|
||||
# Tests.
|
||||
|
||||
# The virt-v2v tests here are not meant to be thorough tests of guest
|
||||
# conversion. There is a test suite used to test conversion which is
|
||||
# kept outside libguestfs because it contains lots of proprietary
|
||||
# unredistributable guests like Windows.
|
||||
#
|
||||
# The tests here instead are testing:
|
||||
#
|
||||
# - virt-v2v command line arguments
|
||||
# - virt-v2v reads and writes files to the correct places
|
||||
# - valgrind & memory leaks
|
||||
# - any conversion properties that can be tested using just the
|
||||
# phony guests (but we don't go out of our way here)
|
||||
# - that up to date guests don't crash virt-v2v
|
||||
|
||||
TESTS_ENVIRONMENT = $(top_builddir)/run --test
|
||||
|
||||
TESTS = \
|
||||
test-bad-networks-and-bridges.sh \
|
||||
test-block-driver.sh \
|
||||
test-cdrom.sh \
|
||||
test-checksum-bad.sh \
|
||||
test-checksum-good-qcow2.sh \
|
||||
test-checksum-good.sh \
|
||||
test-checksum-print.sh \
|
||||
test-customize.sh \
|
||||
test-fedora-btrfs-conversion.sh \
|
||||
test-fedora-conversion.sh \
|
||||
test-fedora-luks-on-lvm-conversion.sh \
|
||||
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-ova-bad-sha1.sh \
|
||||
test-i-ova-bad-sha256.sh \
|
||||
test-i-ova-directory.sh \
|
||||
test-i-ova-formats.sh \
|
||||
test-i-ova-good-checksums.sh \
|
||||
test-i-ova-gz.sh \
|
||||
test-i-ova-invalid-manifest1.sh \
|
||||
test-i-ova-invalid-manifest2.sh \
|
||||
test-i-ova-snapshots.sh \
|
||||
test-i-ova-subfolders.sh \
|
||||
test-i-ova-tar.sh \
|
||||
test-i-ova-two-disks.sh \
|
||||
test-i-ova.sh \
|
||||
test-i-vmx.sh \
|
||||
test-in-place.sh \
|
||||
test-in-place-xml.sh \
|
||||
test-inspector.sh \
|
||||
test-it-vddk-io-query.sh \
|
||||
test-mac.sh \
|
||||
test-machine-readable.sh \
|
||||
test-networks-and-bridges.sh \
|
||||
test-o-glance.sh \
|
||||
test-o-kubevirt-fedora.sh \
|
||||
test-o-kubevirt-windows.sh \
|
||||
test-o-libvirt.sh \
|
||||
test-o-local-qcow2-compressed.sh \
|
||||
test-o-null.sh \
|
||||
test-o-openstack.sh \
|
||||
test-o-qemu.sh \
|
||||
test-o-rhv-upload-oo-query.sh \
|
||||
test-o-rhv-upload.sh \
|
||||
test-o-rhv.sh \
|
||||
test-o-vdsm-oo-query.sh \
|
||||
test-o-vdsm-options.sh \
|
||||
test-oa-option-qcow2.sh \
|
||||
test-oa-option-raw.sh \
|
||||
test-of-option.sh \
|
||||
test-on-option.sh \
|
||||
test-print-source.sh \
|
||||
test-rhbz1232192.sh \
|
||||
test-sound.sh \
|
||||
test-virtio-win-iso.sh \
|
||||
test-windows-conversion.sh \
|
||||
$(SLOW_TESTS) \
|
||||
$(ROOT_TESTS)
|
||||
|
||||
# The VMDK file is used for some -i ova tests.
|
||||
check_DATA += windows.vmdk
|
||||
windows.vmdk: ../test-data/phony-guests/windows.img
|
||||
rm -f $@ $@-t
|
||||
if [ -s $< ]; then \
|
||||
qemu-img convert -f raw $< -O vmdk $@-t; \
|
||||
mv $@-t $@; \
|
||||
else \
|
||||
touch $@; \
|
||||
fi
|
||||
|
||||
DISTCLEANFILES += \
|
||||
windows.vmdk
|
||||
|
||||
check-valgrind:
|
||||
$(MAKE) VG="@VG@" check
|
||||
|
||||
SLOW_TESTS = \
|
||||
$(real_guests_scripts) \
|
||||
test-trim.sh
|
||||
|
||||
check-slow:
|
||||
$(MAKE) check TESTS="$(SLOW_TESTS)" SLOW=1
|
||||
|
||||
ROOT_TESTS = \
|
||||
test-i-ova-as-root.sh
|
||||
|
||||
check-root:
|
||||
$(MAKE) check TESTS="$(ROOT_TESTS)"
|
||||
|
||||
# A selection of real guests that test-conversion-of.sh will
|
||||
# try to convert. This is only used by 'make check-slow'.
|
||||
|
||||
real_guests_scripts = \
|
||||
test-conversion-of-centos-7.0.sh \
|
||||
test-conversion-of-debian-6.sh \
|
||||
test-conversion-of-debian-7.sh \
|
||||
test-conversion-of-debian-8.sh \
|
||||
test-conversion-of-debian-9.sh \
|
||||
test-conversion-of-fedora-37.sh \
|
||||
test-conversion-of-opensuse-13.1.sh \
|
||||
test-conversion-of-opensuse-13.2.sh \
|
||||
test-conversion-of-opensuse-42.1.sh \
|
||||
test-conversion-of-rhel-5.11.sh \
|
||||
test-conversion-of-rhel-6.10.sh \
|
||||
test-conversion-of-rhel-7.9.sh \
|
||||
test-conversion-of-rhel-8.7.sh \
|
||||
test-conversion-of-ubuntu-16.04.sh \
|
||||
test-conversion-of-ubuntu-18.04.sh \
|
||||
test-conversion-of-ubuntu-20.04.sh \
|
||||
test-conversion-of-windows-6.2-server.sh \
|
||||
test-conversion-of-windows-6.3-server.sh \
|
||||
test-conversion-of-windows-10.0-server.sh
|
||||
|
||||
test-conversion-of-%.sh:
|
||||
rm -f $@ $@-t
|
||||
f=`echo "$@" | $(SED) 's/test-conversion-of-\(.*\).sh/\1/'`; \
|
||||
echo 'script=$@ exec $$srcdir/test-conversion-of.sh' "$$f" > $@-t
|
||||
chmod 0755 $@-t
|
||||
mv $@-t $@
|
||||
|
||||
DISTCLEANFILES += \
|
||||
$(real_guests_scripts)
|
||||
|
||||
CLEANFILES += \
|
||||
real-*.img \
|
||||
real-*.xml
|
||||
|
||||
EXTRA_DIST += \
|
||||
test-bad-networks-and-bridges.sh \
|
||||
test-block-driver.sh \
|
||||
test-cdrom.expected \
|
||||
test-cdrom.sh \
|
||||
test-checksum-bad.sh \
|
||||
test-checksum-good-qcow2.sh \
|
||||
test-checksum-good.sh \
|
||||
test-checksum-print.sh \
|
||||
test-conversion-of.sh \
|
||||
test-customize.sh \
|
||||
test-fedora-btrfs-conversion.sh \
|
||||
test-fedora-conversion.sh \
|
||||
test-fedora-luks-on-lvm-conversion.sh \
|
||||
test-fedora-lvm-on-luks-conversion.sh \
|
||||
test-fedora-md-conversion.sh \
|
||||
test-floppy.expected \
|
||||
test-floppy.sh \
|
||||
test-i-disk-parallel.sh \
|
||||
test-i-disk.sh \
|
||||
test-i-ova-as-root.ovf \
|
||||
test-i-ova-as-root.sh \
|
||||
test-i-ova-bad-sha1.sh \
|
||||
test-i-ova-bad-sha256.sh \
|
||||
test-i-ova-checksums.ovf \
|
||||
test-i-ova-directory.sh \
|
||||
test-i-ova-formats.expected \
|
||||
test-i-ova-formats.ovf \
|
||||
test-i-ova-formats.sh \
|
||||
test-i-ova-good-checksums.sh \
|
||||
test-i-ova-gz.expected \
|
||||
test-i-ova-gz.ovf \
|
||||
test-i-ova-gz.sh \
|
||||
test-i-ova-invalid-manifest1.sh \
|
||||
test-i-ova-invalid-manifest2.sh \
|
||||
test-i-ova-snapshots.expected \
|
||||
test-i-ova-snapshots.expected2 \
|
||||
test-i-ova-snapshots.ovf \
|
||||
test-i-ova-snapshots.sh \
|
||||
test-i-ova-subfolders.expected \
|
||||
test-i-ova-subfolders.expected2 \
|
||||
test-i-ova-subfolders.ovf \
|
||||
test-i-ova-subfolders.sh \
|
||||
test-i-ova-tar.expected \
|
||||
test-i-ova-tar.expected2 \
|
||||
test-i-ova-tar.ovf \
|
||||
test-i-ova-tar.sh \
|
||||
test-i-ova-two-disks.expected \
|
||||
test-i-ova-two-disks.expected2 \
|
||||
test-i-ova-two-disks.ovf \
|
||||
test-i-ova-two-disks.sh \
|
||||
test-i-ova.ovf \
|
||||
test-i-ova.sh \
|
||||
test-i-ova.xml \
|
||||
test-i-vmx-1.expected \
|
||||
test-i-vmx-1.vmx \
|
||||
test-i-vmx-2.expected \
|
||||
test-i-vmx-2.vmx \
|
||||
test-i-vmx-3.expected \
|
||||
test-i-vmx-3.vmx \
|
||||
test-i-vmx-4.expected \
|
||||
test-i-vmx-4.vmx \
|
||||
test-i-vmx-5.expected \
|
||||
test-i-vmx-5.vmx \
|
||||
test-i-vmx-6.expected \
|
||||
test-i-vmx-6.vmx \
|
||||
test-i-vmx-7.expected \
|
||||
test-i-vmx-7.vmx \
|
||||
test-i-vmx.sh \
|
||||
test-in-place.sh \
|
||||
test-in-place-xml.sh \
|
||||
test-inspector.sh \
|
||||
test-it-vddk-io-query.sh \
|
||||
test-mac-expected.xml \
|
||||
test-mac.sh \
|
||||
test-machine-readable.sh \
|
||||
test-networks-and-bridges-expected.xml \
|
||||
test-networks-and-bridges.sh \
|
||||
test-o-glance.sh \
|
||||
test-o-kubevirt-fedora.sh \
|
||||
test-o-kubevirt-fedora.yaml.expected \
|
||||
test-o-kubevirt-windows.sh \
|
||||
test-o-kubevirt-windows.yaml.expected \
|
||||
test-o-libvirt.sh \
|
||||
test-o-local-qcow2-compressed.sh \
|
||||
test-o-null.sh \
|
||||
test-o-openstack.sh \
|
||||
test-o-qemu.sh \
|
||||
test-o-rhv-upload-module/imageio.py \
|
||||
test-o-rhv-upload-module/ovirtsdk4/__init__.py \
|
||||
test-o-rhv-upload-module/ovirtsdk4/types.py \
|
||||
test-o-rhv-upload-oo-query.sh \
|
||||
test-o-rhv-upload.sh \
|
||||
test-o-rhv.ovf.expected \
|
||||
test-o-rhv.sh \
|
||||
test-o-vdsm-oo-query.sh \
|
||||
test-o-vdsm-options.ovf.expected \
|
||||
test-o-vdsm-options.sh \
|
||||
test-oa-option-qcow2.sh \
|
||||
test-oa-option-raw.sh \
|
||||
test-of-option.sh \
|
||||
test-on-option.sh \
|
||||
test-print-source.expected \
|
||||
test-print-source.sh \
|
||||
test-rhbz1232192.sh \
|
||||
test-sound.sh \
|
||||
test-trim.sh \
|
||||
test-virtio-win-iso.sh \
|
||||
test-windows-conversion.sh
|
@ -1,73 +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 virt-v2v-in-place with the <checksum> section.
|
||||
|
||||
unset CDPATH
|
||||
export LANG=C
|
||||
set -e
|
||||
|
||||
source ./functions.sh
|
||||
set -e
|
||||
set -x
|
||||
|
||||
skip_if_skipped
|
||||
requires test -f ../test-data/phony-guests/windows.img
|
||||
|
||||
img_base="$abs_top_builddir/test-data/phony-guests/windows.img"
|
||||
|
||||
export VIRT_TOOLS_DATA_DIR="$srcdir/../test-data/fake-virt-tools"
|
||||
export VIRTIO_WIN="$srcdir/../test-data/fake-virtio-win"
|
||||
|
||||
d=$PWD/test-checksum-bad.d
|
||||
rm -rf $d
|
||||
cleanup_fn rm -r $d
|
||||
mkdir $d
|
||||
|
||||
img="$d/test.img"
|
||||
rm -f $img
|
||||
cp $img_base $img
|
||||
md5="$(do_md5 $img)"
|
||||
|
||||
libvirt_xml="$d/test.xml"
|
||||
rm -f $libvirt_xml
|
||||
cat > $libvirt_xml <<EOF
|
||||
<domain type='kvm'>
|
||||
<name>windows</name>
|
||||
<memory>1048576</memory>
|
||||
<os>
|
||||
<type>hvm</type>
|
||||
<boot dev='hd'/>
|
||||
</os>
|
||||
<devices>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='raw'/>
|
||||
<source file='$img'/>
|
||||
<target dev='vda' bus='virtio'/>
|
||||
<checksum method='md5' fail='error'> 123123 </checksum>
|
||||
</disk>
|
||||
</devices>
|
||||
</domain>
|
||||
EOF
|
||||
|
||||
# Expect this command to fail.
|
||||
if $VG virt-v2v-in-place --debug-gc -i libvirtxml $libvirt_xml ; then
|
||||
echo "ERROR: expected virt-v2v-in-place to fail with a checksum error"
|
||||
exit 1
|
||||
fi
|
@ -1,73 +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 virt-v2v-in-place with the <checksum> section.
|
||||
#
|
||||
# This tests a qcow2 format disk to ensure that (a) we are checking
|
||||
# the content and (b) that the different (NBD-based) code path used
|
||||
# for this works.
|
||||
|
||||
unset CDPATH
|
||||
export LANG=C
|
||||
set -e
|
||||
|
||||
source ./functions.sh
|
||||
set -e
|
||||
set -x
|
||||
|
||||
skip_if_skipped
|
||||
requires test -f ../test-data/phony-guests/windows.img
|
||||
|
||||
img_base="$abs_top_builddir/test-data/phony-guests/windows.img"
|
||||
|
||||
export VIRT_TOOLS_DATA_DIR="$srcdir/../test-data/fake-virt-tools"
|
||||
export VIRTIO_WIN="$srcdir/../test-data/fake-virtio-win"
|
||||
|
||||
d=$PWD/test-checksum-good-qcow2.d
|
||||
rm -rf $d
|
||||
cleanup_fn rm -r $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
|
||||
cat > $libvirt_xml <<EOF
|
||||
<domain type='kvm'>
|
||||
<name>windows</name>
|
||||
<memory>1048576</memory>
|
||||
<os>
|
||||
<type>hvm</type>
|
||||
<boot dev='hd'/>
|
||||
</os>
|
||||
<devices>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='qcow2'/>
|
||||
<source file='$img'/>
|
||||
<target dev='vda' bus='virtio'/>
|
||||
<checksum method='md5' fail='error'> $md5 </checksum>
|
||||
</disk>
|
||||
</devices>
|
||||
</domain>
|
||||
EOF
|
||||
|
||||
$VG virt-v2v-in-place --debug-gc -i libvirtxml $libvirt_xml
|
@ -1,69 +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 virt-v2v-in-place with the <checksum> section.
|
||||
|
||||
unset CDPATH
|
||||
export LANG=C
|
||||
set -e
|
||||
|
||||
source ./functions.sh
|
||||
set -e
|
||||
set -x
|
||||
|
||||
skip_if_skipped
|
||||
requires test -f ../test-data/phony-guests/windows.img
|
||||
|
||||
img_base="$abs_top_builddir/test-data/phony-guests/windows.img"
|
||||
|
||||
export VIRT_TOOLS_DATA_DIR="$srcdir/../test-data/fake-virt-tools"
|
||||
export VIRTIO_WIN="$srcdir/../test-data/fake-virtio-win"
|
||||
|
||||
d=$PWD/test-checksum-good.d
|
||||
rm -rf $d
|
||||
cleanup_fn rm -r $d
|
||||
mkdir $d
|
||||
|
||||
img="$d/test.img"
|
||||
rm -f $img
|
||||
cp $img_base $img
|
||||
md5="$(do_md5 $img)"
|
||||
|
||||
libvirt_xml="$d/test.xml"
|
||||
rm -f $libvirt_xml
|
||||
cat > $libvirt_xml <<EOF
|
||||
<domain type='kvm'>
|
||||
<name>windows</name>
|
||||
<memory>1048576</memory>
|
||||
<os>
|
||||
<type>hvm</type>
|
||||
<boot dev='hd'/>
|
||||
</os>
|
||||
<devices>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='raw'/>
|
||||
<source file='$img'/>
|
||||
<target dev='vda' bus='virtio'/>
|
||||
<checksum method='md5' fail='error'> $md5 </checksum>
|
||||
</disk>
|
||||
</devices>
|
||||
</domain>
|
||||
EOF
|
||||
|
||||
$VG virt-v2v-in-place --debug-gc -i libvirtxml $libvirt_xml
|
@ -1,75 +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 virt-v2v-in-place with the <checksum> section.
|
||||
|
||||
unset CDPATH
|
||||
export LANG=C
|
||||
set -e
|
||||
|
||||
source ./functions.sh
|
||||
set -e
|
||||
set -x
|
||||
|
||||
skip_if_skipped
|
||||
requires test -f ../test-data/phony-guests/windows.img
|
||||
|
||||
img_base="$abs_top_builddir/test-data/phony-guests/windows.img"
|
||||
|
||||
export VIRT_TOOLS_DATA_DIR="$srcdir/../test-data/fake-virt-tools"
|
||||
export VIRTIO_WIN="$srcdir/../test-data/fake-virtio-win"
|
||||
|
||||
d=$PWD/test-checksum-print.d
|
||||
rm -rf $d
|
||||
cleanup_fn rm -r $d
|
||||
mkdir $d
|
||||
|
||||
img="$d/test.img"
|
||||
rm -f $img
|
||||
cp $img_base $img
|
||||
md5="$(do_md5 $img)"
|
||||
|
||||
out="$d/out"
|
||||
|
||||
libvirt_xml="$d/test.xml"
|
||||
rm -f $libvirt_xml
|
||||
cat > $libvirt_xml <<EOF
|
||||
<domain type='kvm'>
|
||||
<name>windows</name>
|
||||
<memory>1048576</memory>
|
||||
<os>
|
||||
<type>hvm</type>
|
||||
<boot dev='hd'/>
|
||||
</os>
|
||||
<devices>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='raw'/>
|
||||
<source file='$img'/>
|
||||
<target dev='vda' bus='virtio'/>
|
||||
<checksum method='md5' fail='print'/>
|
||||
</disk>
|
||||
</devices>
|
||||
</domain>
|
||||
EOF
|
||||
|
||||
$VG virt-v2v-in-place --debug-gc -i libvirtxml $libvirt_xml > $out
|
||||
cat $out
|
||||
|
||||
# The checksum must appear in the output.
|
||||
grep $md5 $out
|
@ -1,54 +0,0 @@
|
||||
#!/bin/bash -
|
||||
# libguestfs virt-v2v test script
|
||||
# Copyright (C) 2014-2024 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 --parallel option.
|
||||
|
||||
set -e
|
||||
|
||||
source ./functions.sh
|
||||
set -e
|
||||
set -x
|
||||
|
||||
skip_if_skipped
|
||||
windows=../test-data/phony-guests/windows.img
|
||||
requires test -f $windows
|
||||
|
||||
export VIRT_TOOLS_DATA_DIR="$srcdir/../test-data/fake-virt-tools"
|
||||
|
||||
d=test-i-disk-parallel.d
|
||||
rm -rf $d
|
||||
cleanup_fn rm -rf $d
|
||||
mkdir $d
|
||||
|
||||
truncate -s $((100*1024*1024)) $d/disk-2.img $d/disk-3.img $d/disk-4.img
|
||||
|
||||
$VG virt-v2v --debug-gc \
|
||||
--parallel=2 \
|
||||
-i disk \
|
||||
$windows \
|
||||
$d/disk-2.img \
|
||||
$d/disk-3.img \
|
||||
$d/disk-4.img \
|
||||
-o local -os $d
|
||||
|
||||
# Test the libvirt XML metadata and output disks were created.
|
||||
test -f $d/windows.xml
|
||||
test -f $d/windows-sda
|
||||
test -f $d/windows-sdb
|
||||
test -f $d/windows-sdc
|
||||
test -f $d/windows-sdd
|
@ -1,81 +0,0 @@
|
||||
#!/bin/bash -
|
||||
# libguestfs virt-v2v test script
|
||||
# Copyright (C) 2014-2024 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 virt-v2v-in-place -O option.
|
||||
|
||||
unset CDPATH
|
||||
export LANG=C
|
||||
set -e
|
||||
|
||||
source ./functions.sh
|
||||
set -e
|
||||
set -x
|
||||
|
||||
skip_if_skipped
|
||||
requires test -f ../test-data/phony-guests/windows.img
|
||||
|
||||
img_base="$abs_top_builddir/test-data/phony-guests/windows.img"
|
||||
|
||||
export VIRT_TOOLS_DATA_DIR="$srcdir/../test-data/fake-virt-tools"
|
||||
export VIRTIO_WIN="$srcdir/../test-data/fake-virtio-win"
|
||||
|
||||
d=$PWD/test-v2v-in-place-xml.d
|
||||
rm -rf $d
|
||||
cleanup_fn rm -r $d
|
||||
mkdir $d
|
||||
|
||||
img="$d/test.qcow2"
|
||||
qemu-img convert -f raw $img_base -O qcow2 $img
|
||||
|
||||
out="$d/out.xml"
|
||||
|
||||
libvirt_xml="$d/test.xml"
|
||||
rm -f $libvirt_xml
|
||||
n=windows
|
||||
cat > $libvirt_xml <<EOF
|
||||
<node>
|
||||
<domain type='test'>
|
||||
<name>$n</name>
|
||||
<memory>1048576</memory>
|
||||
<os>
|
||||
<type>hvm</type>
|
||||
<boot dev='hd'/>
|
||||
</os>
|
||||
<devices>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='qcow2'/>
|
||||
<source file='$img'/>
|
||||
<target dev='vda' bus='virtio'/>
|
||||
</disk>
|
||||
</devices>
|
||||
</domain>
|
||||
</node>
|
||||
EOF
|
||||
|
||||
$VG virt-v2v-in-place --debug-gc -i libvirt -ic "test://$libvirt_xml" \
|
||||
$n -O $out
|
||||
cat $out
|
||||
|
||||
# Expect certain elements to be present.
|
||||
grep '^<v2v-inspection' $out
|
||||
grep '<program>virt-v2v-inspector</program>' $out
|
||||
grep '<disks>' $out
|
||||
grep "<disk index='0'>" $out
|
||||
grep '<distro>windows</distro>' $out
|
||||
grep '<osinfo>win2k22</osinfo>' $out
|
114
virt-v2v.spec
Normal file
114
virt-v2v.spec
Normal file
@ -0,0 +1,114 @@
|
||||
# The source directory.
|
||||
%global source_directory 2.6-stable
|
||||
|
||||
Name: virt-v2v
|
||||
Version: 2.6.0
|
||||
Release: alt1
|
||||
Summary: Convert a virtual machine to run on KVM
|
||||
Group: Development/Other
|
||||
License: GPLv2+
|
||||
Url: https://github.com/libguestfs/virt-v2v
|
||||
|
||||
Source0: http://download.libguestfs.org/virt-v2v/%source_directory/%name-%version.tar.gz
|
||||
Patch1: fixes-common.patch
|
||||
|
||||
BuildRequires(pre): rpm-build-ocaml
|
||||
BuildRequires: /usr/bin/pod2man
|
||||
BuildRequires: gcc
|
||||
BuildRequires: ocaml >= 4.01 ocaml-findlib ocaml-ocamlbuild
|
||||
BuildRequires: ocaml-libguestfs-devel ocaml-libvirt-devel ocaml-libnbd-devel
|
||||
BuildRequires: ocaml-gettext-devel
|
||||
BuildRequires: ocaml-fileutils-devel
|
||||
BuildRequires: ocaml-ounit-devel
|
||||
BuildRequires: libguestfs-devel
|
||||
BuildRequires: libnbd-devel
|
||||
BuildRequires: libaugeas-devel
|
||||
BuildRequires: bash-completion
|
||||
BuildRequires: gettext-tools
|
||||
BuildRequires: libjansson-devel
|
||||
BuildRequires: libosinfo-devel
|
||||
BuildRequires: libvirt-devel
|
||||
BuildRequires: libvirt-kvm
|
||||
BuildRequires: libxml2-devel
|
||||
BuildRequires: libpcre2-devel
|
||||
BuildRequires: perl-Sys-Guestfs
|
||||
BuildRequires: /usr/bin/virsh
|
||||
BuildRequires: genisoimage zip unzip db4-utils
|
||||
#BuildRequires: nbdkit-python-plugin
|
||||
BuildRequires:libnbd
|
||||
|
||||
|
||||
Requires: guestfs-tools
|
||||
Requires: gawk
|
||||
Requires: gzip
|
||||
Requires: unzip
|
||||
Requires: curl
|
||||
Requires: /usr/bin/virsh
|
||||
Requires: qemu-kvm-core >= 5.2.0
|
||||
Requires: libnbd
|
||||
|
||||
%description
|
||||
Virt-v2v converts a single guest from a foreign hypervisor to run on
|
||||
KVM. It can read Linux and Windows guests running on VMware, Xen,
|
||||
Hyper-V and some other hypervisors, and convert them to KVM managed by
|
||||
libvirt, OpenStack, oVirt, Red Hat Virtualisation (RHV) or several
|
||||
other targets. It can modify the guest to make it bootable on KVM and
|
||||
install virtio drivers so it will run quickly.
|
||||
|
||||
|
||||
%prep
|
||||
%setup
|
||||
pushd common
|
||||
%patch1 -p1
|
||||
popd
|
||||
|
||||
%build
|
||||
%autoreconf
|
||||
%configure
|
||||
%make_build
|
||||
|
||||
%install
|
||||
%makeinstall_std
|
||||
|
||||
# Delete libtool crap.
|
||||
find %buildroot -name '*.la' -delete
|
||||
|
||||
# Find locale files.
|
||||
%find_lang %name
|
||||
|
||||
%files -f %name.lang
|
||||
%doc COPYING README
|
||||
%_bindir/virt-v2v*
|
||||
%_man1dir/virt-v2v*
|
||||
#%%_datadir/virt-tools
|
||||
%_datadir/bash-completion/completions/virt-v2v*
|
||||
|
||||
%changelog
|
||||
* Mon Jan 13 2025 Vladislav Tsarev <tyaplyapych@altlinux.org> 2.6.0-alt1
|
||||
- new version 2.6.0
|
||||
|
||||
* Fri Jan 12 2024 Alexey Shabalin <shaba@altlinux.org> 2.4.0-alt1
|
||||
- new version 2.4.0
|
||||
|
||||
* Tue Mar 01 2022 Mikhail Gordeev <obirvalger@altlinux.org> 1.44.2-alt1
|
||||
- new version 1.44.2
|
||||
|
||||
* Tue Sep 07 2021 Mikhail Gordeev <obirvalger@altlinux.org> 1.44.0-alt1
|
||||
- new version 1.44.0
|
||||
|
||||
* Wed Apr 07 2021 Mikhail Gordeev <obirvalger@altlinux.org> 1.43.4-alt1
|
||||
- new version 1.43.4
|
||||
|
||||
* Tue Dec 08 2020 Mikhail Gordeev <obirvalger@altlinux.org> 1.43.1-alt3
|
||||
- Set LANG=C in parse_ova (Closes: 39366)
|
||||
- Fix qemu options used in --qemu-boot
|
||||
|
||||
* Thu Sep 03 2020 Mikhail Gordeev <obirvalger@altlinux.org> 1.43.1-alt2
|
||||
- Refactor (after discussions with upstream) ALT support
|
||||
|
||||
* Mon Aug 24 2020 Mikhail Gordeev <obirvalger@altlinux.org> 1.43.1-alt1
|
||||
- update to 1.43.1
|
||||
- Add ALT support
|
||||
|
||||
* Sun May 10 2020 Alexey Shabalin <shaba@altlinux.org> 1.42.0-alt1
|
||||
- Initial release of separate virt-v2v program, was part of libguestfs.
|
16
.gitignore → virt/.gitignore
vendored
16
.gitignore → virt/.gitignore
vendored
@ -121,14 +121,14 @@ Makefile.in
|
||||
/test-data/phony-guests/windows-system
|
||||
/tests/functions.sh
|
||||
/tests/libvirt-is-version
|
||||
/tests/test-cdrom.xml
|
||||
/tests/test-conversion-of-*.sh
|
||||
/tests/test-floppy.xml
|
||||
/tests/test-mac.xml
|
||||
/tests/test-networks-and-bridges.xml
|
||||
/tests/test-print-source.xml
|
||||
/tests/test-rhbz1232192.xml
|
||||
/tests/test-sound.xml
|
||||
/tests/rhbz1232192.xml
|
||||
/tests/test-v2v-cdrom.xml
|
||||
/tests/test-v2v-conversion-of-*.sh
|
||||
/tests/test-v2v-floppy.xml
|
||||
/tests/test-v2v-mac.xml
|
||||
/tests/test-v2v-networks-and-bridges.xml
|
||||
/tests/test-v2v-print-source.xml
|
||||
/tests/test-v2v-sound.xml
|
||||
/tests/windows.vmdk
|
||||
/v2v/.depend
|
||||
/v2v/oUnit-virt-v2v.cache
|
@ -37,6 +37,7 @@ SUBDIRS += common/mlxml
|
||||
SUBDIRS += common/mltools
|
||||
SUBDIRS += common/mlcustomize
|
||||
SUBDIRS += common/mldrivers
|
||||
SUBDIRS += common/mlv2v
|
||||
SUBDIRS += lib
|
||||
SUBDIRS += input
|
||||
SUBDIRS += output
|
1560
virt/Makefile.in
Normal file
1560
virt/Makefile.in
Normal file
File diff suppressed because it is too large
Load Diff
@ -51,7 +51,7 @@ REQUIREMENTS
|
||||
|
||||
* OCaml bindings for libvirt (https://gitlab.com/libvirt/libvirt-ocaml)
|
||||
|
||||
* libnbd >= 1.14 (https://gitlab.com/nbdkit/libnbd)
|
||||
* libnbd >= 1.10 (https://gitlab.com/nbdkit/libnbd)
|
||||
|
||||
* The 'nbdinfo' and 'nbdcopy' programs from libnbd.
|
||||
|
4776
virt/aclocal.m4
vendored
Normal file
4776
virt/aclocal.m4
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1109
virt/bash/Makefile.in
Normal file
1109
virt/bash/Makefile.in
Normal file
File diff suppressed because it is too large
Load Diff
348
virt/build-aux/compile
Executable file
348
virt/build-aux/compile
Executable file
@ -0,0 +1,348 @@
|
||||
#! /bin/sh
|
||||
# Wrapper for compilers which do not understand '-c -o'.
|
||||
|
||||
scriptversion=2018-03-07.03; # UTC
|
||||
|
||||
# Copyright (C) 1999-2021 Free Software Foundation, Inc.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
#
|
||||
# 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, 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
nl='
|
||||
'
|
||||
|
||||
# We need space, tab and new line, in precisely that order. Quoting is
|
||||
# there to prevent tools from complaining about whitespace usage.
|
||||
IFS=" "" $nl"
|
||||
|
||||
file_conv=
|
||||
|
||||
# func_file_conv build_file lazy
|
||||
# Convert a $build file to $host form and store it in $file
|
||||
# Currently only supports Windows hosts. If the determined conversion
|
||||
# type is listed in (the comma separated) LAZY, no conversion will
|
||||
# take place.
|
||||
func_file_conv ()
|
||||
{
|
||||
file=$1
|
||||
case $file in
|
||||
/ | /[!/]*) # absolute file, and not a UNC file
|
||||
if test -z "$file_conv"; then
|
||||
# lazily determine how to convert abs files
|
||||
case `uname -s` in
|
||||
MINGW*)
|
||||
file_conv=mingw
|
||||
;;
|
||||
CYGWIN* | MSYS*)
|
||||
file_conv=cygwin
|
||||
;;
|
||||
*)
|
||||
file_conv=wine
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
case $file_conv/,$2, in
|
||||
*,$file_conv,*)
|
||||
;;
|
||||
mingw/*)
|
||||
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
|
||||
;;
|
||||
cygwin/* | msys/*)
|
||||
file=`cygpath -m "$file" || echo "$file"`
|
||||
;;
|
||||
wine/*)
|
||||
file=`winepath -w "$file" || echo "$file"`
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# func_cl_dashL linkdir
|
||||
# Make cl look for libraries in LINKDIR
|
||||
func_cl_dashL ()
|
||||
{
|
||||
func_file_conv "$1"
|
||||
if test -z "$lib_path"; then
|
||||
lib_path=$file
|
||||
else
|
||||
lib_path="$lib_path;$file"
|
||||
fi
|
||||
linker_opts="$linker_opts -LIBPATH:$file"
|
||||
}
|
||||
|
||||
# func_cl_dashl library
|
||||
# Do a library search-path lookup for cl
|
||||
func_cl_dashl ()
|
||||
{
|
||||
lib=$1
|
||||
found=no
|
||||
save_IFS=$IFS
|
||||
IFS=';'
|
||||
for dir in $lib_path $LIB
|
||||
do
|
||||
IFS=$save_IFS
|
||||
if $shared && test -f "$dir/$lib.dll.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.dll.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/$lib.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/lib$lib.a"; then
|
||||
found=yes
|
||||
lib=$dir/lib$lib.a
|
||||
break
|
||||
fi
|
||||
done
|
||||
IFS=$save_IFS
|
||||
|
||||
if test "$found" != yes; then
|
||||
lib=$lib.lib
|
||||
fi
|
||||
}
|
||||
|
||||
# func_cl_wrapper cl arg...
|
||||
# Adjust compile command to suit cl
|
||||
func_cl_wrapper ()
|
||||
{
|
||||
# Assume a capable shell
|
||||
lib_path=
|
||||
shared=:
|
||||
linker_opts=
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.[oO][bB][jJ])
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fo"$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fe"$file"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
-I)
|
||||
eat=1
|
||||
func_file_conv "$2" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-I*)
|
||||
func_file_conv "${1#-I}" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-l)
|
||||
eat=1
|
||||
func_cl_dashl "$2"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-l*)
|
||||
func_cl_dashl "${1#-l}"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-L)
|
||||
eat=1
|
||||
func_cl_dashL "$2"
|
||||
;;
|
||||
-L*)
|
||||
func_cl_dashL "${1#-L}"
|
||||
;;
|
||||
-static)
|
||||
shared=false
|
||||
;;
|
||||
-Wl,*)
|
||||
arg=${1#-Wl,}
|
||||
save_ifs="$IFS"; IFS=','
|
||||
for flag in $arg; do
|
||||
IFS="$save_ifs"
|
||||
linker_opts="$linker_opts $flag"
|
||||
done
|
||||
IFS="$save_ifs"
|
||||
;;
|
||||
-Xlinker)
|
||||
eat=1
|
||||
linker_opts="$linker_opts $2"
|
||||
;;
|
||||
-*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
|
||||
func_file_conv "$1"
|
||||
set x "$@" -Tp"$file"
|
||||
shift
|
||||
;;
|
||||
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
|
||||
func_file_conv "$1" mingw
|
||||
set x "$@" "$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
if test -n "$linker_opts"; then
|
||||
linker_opts="-link$linker_opts"
|
||||
fi
|
||||
exec "$@" $linker_opts
|
||||
exit 1
|
||||
}
|
||||
|
||||
eat=
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: compile [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Wrapper for compilers which do not understand '-c -o'.
|
||||
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
|
||||
arguments, and rename the output as expected.
|
||||
|
||||
If you are trying to build a whole package this is not the
|
||||
right script to run: please start by reading the file 'INSTALL'.
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "compile $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
|
||||
icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
|
||||
func_cl_wrapper "$@" # Doesn't return...
|
||||
;;
|
||||
esac
|
||||
|
||||
ofile=
|
||||
cfile=
|
||||
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
# So we strip '-o arg' only if arg is an object.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.obj)
|
||||
ofile=$2
|
||||
;;
|
||||
*)
|
||||
set x "$@" -o "$2"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*.c)
|
||||
cfile=$1
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
if test -z "$ofile" || test -z "$cfile"; then
|
||||
# If no '-o' option was seen then we might have been invoked from a
|
||||
# pattern rule where we don't need one. That is ok -- this is a
|
||||
# normal compilation that the losing compiler can handle. If no
|
||||
# '.c' file was seen then we are probably linking. That is also
|
||||
# ok.
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
# Name of file we expect compiler to create.
|
||||
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
|
||||
|
||||
# Create the lock directory.
|
||||
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
|
||||
# that we are using for the .o file. Also, base the name on the expected
|
||||
# object file name, since that is what matters with a parallel build.
|
||||
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
|
||||
while true; do
|
||||
if mkdir "$lockdir" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
# FIXME: race condition here if user kills between mkdir and trap.
|
||||
trap "rmdir '$lockdir'; exit 1" 1 2 15
|
||||
|
||||
# Run the compile.
|
||||
"$@"
|
||||
ret=$?
|
||||
|
||||
if test -f "$cofile"; then
|
||||
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
|
||||
elif test -f "${cofile}bj"; then
|
||||
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
|
||||
fi
|
||||
|
||||
rmdir "$lockdir"
|
||||
exit $ret
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
1812
virt/build-aux/config.guess
vendored
Executable file
1812
virt/build-aux/config.guess
vendored
Executable file
File diff suppressed because it is too large
Load Diff
1971
virt/build-aux/config.sub
vendored
Executable file
1971
virt/build-aux/config.sub
vendored
Executable file
File diff suppressed because it is too large
Load Diff
791
virt/build-aux/depcomp
Executable file
791
virt/build-aux/depcomp
Executable file
@ -0,0 +1,791 @@
|
||||
#! /bin/sh
|
||||
# depcomp - compile a program generating dependencies as side-effects
|
||||
|
||||
scriptversion=2018-03-07.03; # UTC
|
||||
|
||||
# Copyright (C) 1999-2021 Free Software Foundation, 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, 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Run PROGRAMS ARGS to compile a file, generating dependencies
|
||||
as side-effects.
|
||||
|
||||
Environment variables:
|
||||
depmode Dependency tracking mode.
|
||||
source Source file read by 'PROGRAMS ARGS'.
|
||||
object Object file output by 'PROGRAMS ARGS'.
|
||||
DEPDIR directory where to store dependencies.
|
||||
depfile Dependency file to output.
|
||||
tmpdepfile Temporary file to use when outputting dependencies.
|
||||
libtool Whether libtool is used (yes/no).
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "depcomp $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
esac
|
||||
|
||||
# Get the directory component of the given path, and save it in the
|
||||
# global variables '$dir'. Note that this directory component will
|
||||
# be either empty or ending with a '/' character. This is deliberate.
|
||||
set_dir_from ()
|
||||
{
|
||||
case $1 in
|
||||
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
|
||||
*) dir=;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Get the suffix-stripped basename of the given path, and save it the
|
||||
# global variable '$base'.
|
||||
set_base_from ()
|
||||
{
|
||||
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
|
||||
}
|
||||
|
||||
# If no dependency file was actually created by the compiler invocation,
|
||||
# we still have to create a dummy depfile, to avoid errors with the
|
||||
# Makefile "include basename.Plo" scheme.
|
||||
make_dummy_depfile ()
|
||||
{
|
||||
echo "#dummy" > "$depfile"
|
||||
}
|
||||
|
||||
# Factor out some common post-processing of the generated depfile.
|
||||
# Requires the auxiliary global variable '$tmpdepfile' to be set.
|
||||
aix_post_process_depfile ()
|
||||
{
|
||||
# If the compiler actually managed to produce a dependency file,
|
||||
# post-process it.
|
||||
if test -f "$tmpdepfile"; then
|
||||
# Each line is of the form 'foo.o: dependency.h'.
|
||||
# Do two passes, one to just change these to
|
||||
# $object: dependency.h
|
||||
# and one to simply output
|
||||
# dependency.h:
|
||||
# which is needed to avoid the deleted-header problem.
|
||||
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
|
||||
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
|
||||
} > "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
}
|
||||
|
||||
# A tabulation character.
|
||||
tab=' '
|
||||
# A newline character.
|
||||
nl='
|
||||
'
|
||||
# Character ranges might be problematic outside the C locale.
|
||||
# These definitions help.
|
||||
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
lower=abcdefghijklmnopqrstuvwxyz
|
||||
digits=0123456789
|
||||
alpha=${upper}${lower}
|
||||
|
||||
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
|
||||
echo "depcomp: Variables source, object and depmode must be set" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
|
||||
depfile=${depfile-`echo "$object" |
|
||||
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
|
||||
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
|
||||
|
||||
rm -f "$tmpdepfile"
|
||||
|
||||
# Avoid interferences from the environment.
|
||||
gccflag= dashmflag=
|
||||
|
||||
# Some modes work just like other modes, but use different flags. We
|
||||
# parameterize here, but still list the modes in the big case below,
|
||||
# to make depend.m4 easier to write. Note that we *cannot* use a case
|
||||
# here, because this file can only contain one case statement.
|
||||
if test "$depmode" = hp; then
|
||||
# HP compiler uses -M and no extra arg.
|
||||
gccflag=-M
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
if test "$depmode" = dashXmstdout; then
|
||||
# This is just like dashmstdout with a different argument.
|
||||
dashmflag=-xM
|
||||
depmode=dashmstdout
|
||||
fi
|
||||
|
||||
cygpath_u="cygpath -u -f -"
|
||||
if test "$depmode" = msvcmsys; then
|
||||
# This is just like msvisualcpp but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvisualcpp
|
||||
fi
|
||||
|
||||
if test "$depmode" = msvc7msys; then
|
||||
# This is just like msvc7 but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvc7
|
||||
fi
|
||||
|
||||
if test "$depmode" = xlc; then
|
||||
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
|
||||
gccflag=-qmakedep=gcc,-MF
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
case "$depmode" in
|
||||
gcc3)
|
||||
## gcc 3 implements dependency tracking that does exactly what
|
||||
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
|
||||
## it if -MD -MP comes after the -MF stuff. Hmm.
|
||||
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
|
||||
## the command line argument order; so add the flags where they
|
||||
## appear in depend2.am. Note that the slowdown incurred here
|
||||
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
|
||||
*) set fnord "$@" "$arg" ;;
|
||||
esac
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
done
|
||||
"$@"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
mv "$tmpdepfile" "$depfile"
|
||||
;;
|
||||
|
||||
gcc)
|
||||
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
|
||||
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
|
||||
## (see the conditional assignment to $gccflag above).
|
||||
## There are various ways to get dependency output from gcc. Here's
|
||||
## why we pick this rather obscure method:
|
||||
## - Don't want to use -MD because we'd like the dependencies to end
|
||||
## up in a subdir. Having to rename by hand is ugly.
|
||||
## (We might end up doing this anyway to support other compilers.)
|
||||
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
|
||||
## -MM, not -M (despite what the docs say). Also, it might not be
|
||||
## supported by the other compilers which use the 'gcc' depmode.
|
||||
## - Using -M directly means running the compiler twice (even worse
|
||||
## than renaming).
|
||||
if test -z "$gccflag"; then
|
||||
gccflag=-MD,
|
||||
fi
|
||||
"$@" -Wp,"$gccflag$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The second -e expression handles DOS-style file names with drive
|
||||
# letters.
|
||||
sed -e 's/^[^:]*: / /' \
|
||||
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
|
||||
## This next piece of magic avoids the "deleted header file" problem.
|
||||
## The problem is that when a header file which appears in a .P file
|
||||
## is deleted, the dependency causes make to die (because there is
|
||||
## typically no way to rebuild the header). We avoid this by adding
|
||||
## dummy dependencies for each header file. Too bad gcc doesn't do
|
||||
## this for us directly.
|
||||
## Some versions of gcc put a space before the ':'. On the theory
|
||||
## that the space means something, we add a space to the output as
|
||||
## well. hp depmode also adds that space, but also prefixes the VPATH
|
||||
## to the object. Take care to not repeat it in the output.
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
sgi)
|
||||
if test "$libtool" = yes; then
|
||||
"$@" "-Wp,-MDupdate,$tmpdepfile"
|
||||
else
|
||||
"$@" -MDupdate "$tmpdepfile"
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
|
||||
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
|
||||
echo "$object : \\" > "$depfile"
|
||||
# Clip off the initial element (the dependent). Don't try to be
|
||||
# clever and replace this with sed code, as IRIX sed won't handle
|
||||
# lines with more than a fixed number of characters (4096 in
|
||||
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
|
||||
# the IRIX cc adds comments like '#:fec' to the end of the
|
||||
# dependency line.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
|
||||
| tr "$nl" ' ' >> "$depfile"
|
||||
echo >> "$depfile"
|
||||
# The second pass generates a dummy entry for each header file.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
|
||||
>> "$depfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
xlc)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
aix)
|
||||
# The C for AIX Compiler uses -M and outputs the dependencies
|
||||
# in a .u file. In older versions, this file always lives in the
|
||||
# current directory. Also, the AIX compiler puts '$object:' at the
|
||||
# start of each line; $object doesn't have directory information.
|
||||
# Version 6 uses the directory in both cases.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$base.u
|
||||
tmpdepfile3=$dir.libs/$base.u
|
||||
"$@" -Wc,-M
|
||||
else
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$dir$base.u
|
||||
tmpdepfile3=$dir$base.u
|
||||
"$@" -M
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
aix_post_process_depfile
|
||||
;;
|
||||
|
||||
tcc)
|
||||
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
|
||||
# FIXME: That version still under development at the moment of writing.
|
||||
# Make that this statement remains true also for stable, released
|
||||
# versions.
|
||||
# It will wrap lines (doesn't matter whether long or short) with a
|
||||
# trailing '\', as in:
|
||||
#
|
||||
# foo.o : \
|
||||
# foo.c \
|
||||
# foo.h \
|
||||
#
|
||||
# It will put a trailing '\' even on the last line, and will use leading
|
||||
# spaces rather than leading tabs (at least since its commit 0394caf7
|
||||
# "Emit spaces for -MD").
|
||||
"$@" -MD -MF "$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
|
||||
# We have to change lines of the first kind to '$object: \'.
|
||||
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
|
||||
# And for each line of the second kind, we have to emit a 'dep.h:'
|
||||
# dummy dependency, to avoid the deleted-header problem.
|
||||
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
## The order of this option in the case statement is important, since the
|
||||
## shell code in configure will try each of these formats in the order
|
||||
## listed in this file. A plain '-MD' option would be understood by many
|
||||
## compilers, so we must ensure this comes after the gcc and icc options.
|
||||
pgcc)
|
||||
# Portland's C compiler understands '-MD'.
|
||||
# Will always output deps to 'file.d' where file is the root name of the
|
||||
# source file under compilation, even if file resides in a subdirectory.
|
||||
# The object file name does not affect the name of the '.d' file.
|
||||
# pgcc 10.2 will output
|
||||
# foo.o: sub/foo.c sub/foo.h
|
||||
# and will wrap long lines using '\' :
|
||||
# foo.o: sub/foo.c ... \
|
||||
# sub/foo.h ... \
|
||||
# ...
|
||||
set_dir_from "$object"
|
||||
# Use the source, not the object, to determine the base name, since
|
||||
# that's sadly what pgcc will do too.
|
||||
set_base_from "$source"
|
||||
tmpdepfile=$base.d
|
||||
|
||||
# For projects that build the same source file twice into different object
|
||||
# files, the pgcc approach of using the *source* file root name can cause
|
||||
# problems in parallel builds. Use a locking strategy to avoid stomping on
|
||||
# the same $tmpdepfile.
|
||||
lockdir=$base.d-lock
|
||||
trap "
|
||||
echo '$0: caught signal, cleaning up...' >&2
|
||||
rmdir '$lockdir'
|
||||
exit 1
|
||||
" 1 2 13 15
|
||||
numtries=100
|
||||
i=$numtries
|
||||
while test $i -gt 0; do
|
||||
# mkdir is a portable test-and-set.
|
||||
if mkdir "$lockdir" 2>/dev/null; then
|
||||
# This process acquired the lock.
|
||||
"$@" -MD
|
||||
stat=$?
|
||||
# Release the lock.
|
||||
rmdir "$lockdir"
|
||||
break
|
||||
else
|
||||
# If the lock is being held by a different process, wait
|
||||
# until the winning process is done or we timeout.
|
||||
while test -d "$lockdir" && test $i -gt 0; do
|
||||
sleep 1
|
||||
i=`expr $i - 1`
|
||||
done
|
||||
fi
|
||||
i=`expr $i - 1`
|
||||
done
|
||||
trap - 1 2 13 15
|
||||
if test $i -le 0; then
|
||||
echo "$0: failed to acquire lock after $numtries attempts" >&2
|
||||
echo "$0: check lockdir '$lockdir'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each line is of the form `foo.o: dependent.h',
|
||||
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp2)
|
||||
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
|
||||
# compilers, which have integrated preprocessors. The correct option
|
||||
# to use with these is +Maked; it writes dependencies to a file named
|
||||
# 'foo.d', which lands next to the object file, wherever that
|
||||
# happens to be.
|
||||
# Much of this is similar to the tru64 case; see comments there.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir.libs/$base.d
|
||||
"$@" -Wc,+Maked
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
"$@" +Maked
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
|
||||
# Add 'dependent.h:' lines.
|
||||
sed -ne '2,${
|
||||
s/^ *//
|
||||
s/ \\*$//
|
||||
s/$/:/
|
||||
p
|
||||
}' "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
rm -f "$tmpdepfile" "$tmpdepfile2"
|
||||
;;
|
||||
|
||||
tru64)
|
||||
# The Tru64 compiler uses -MD to generate dependencies as a side
|
||||
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
|
||||
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
|
||||
# dependencies in 'foo.d' instead, so we check for that too.
|
||||
# Subdirectories are respected.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
|
||||
if test "$libtool" = yes; then
|
||||
# Libtool generates 2 separate objects for the 2 libraries. These
|
||||
# two compilations output dependencies in $dir.libs/$base.o.d and
|
||||
# in $dir$base.o.d. We have to check for both files, because
|
||||
# one of the two compilations can be disabled. We should prefer
|
||||
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
|
||||
# automatically cleaned when .libs/ is deleted, while ignoring
|
||||
# the former would cause a distcleancheck panic.
|
||||
tmpdepfile1=$dir$base.o.d # libtool 1.5
|
||||
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
|
||||
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
|
||||
"$@" -Wc,-MD
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
tmpdepfile3=$dir$base.d
|
||||
"$@" -MD
|
||||
fi
|
||||
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
# Same post-processing that is required for AIX mode.
|
||||
aix_post_process_depfile
|
||||
;;
|
||||
|
||||
msvc7)
|
||||
if test "$libtool" = yes; then
|
||||
showIncludes=-Wc,-showIncludes
|
||||
else
|
||||
showIncludes=-showIncludes
|
||||
fi
|
||||
"$@" $showIncludes > "$tmpdepfile"
|
||||
stat=$?
|
||||
grep -v '^Note: including file: ' "$tmpdepfile"
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The first sed program below extracts the file names and escapes
|
||||
# backslashes for cygpath. The second sed program outputs the file
|
||||
# name when reading, but also accumulates all include files in the
|
||||
# hold buffer in order to output them again at the end. This only
|
||||
# works with sed implementations that can handle large buffers.
|
||||
sed < "$tmpdepfile" -n '
|
||||
/^Note: including file: *\(.*\)/ {
|
||||
s//\1/
|
||||
s/\\/\\\\/g
|
||||
p
|
||||
}' | $cygpath_u | sort -u | sed -n '
|
||||
s/ /\\ /g
|
||||
s/\(.*\)/'"$tab"'\1 \\/p
|
||||
s/.\(.*\) \\/\1:/
|
||||
H
|
||||
$ {
|
||||
s/.*/'"$tab"'/
|
||||
G
|
||||
p
|
||||
}' >> "$depfile"
|
||||
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvc7msys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
#nosideeffect)
|
||||
# This comment above is used by automake to tell side-effect
|
||||
# dependency tracking mechanisms from slower ones.
|
||||
|
||||
dashmstdout)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout, regardless of -o.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
test -z "$dashmflag" && dashmflag=-M
|
||||
# Require at least two characters before searching for ':'
|
||||
# in the target name. This is to cope with DOS-style filenames:
|
||||
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
|
||||
"$@" $dashmflag |
|
||||
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this sed invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
dashXmstdout)
|
||||
# This case only exists to satisfy depend.m4. It is never actually
|
||||
# run, as this mode is specially recognized in the preamble.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
makedepend)
|
||||
"$@" || exit $?
|
||||
# Remove any Libtool call
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
# X makedepend
|
||||
shift
|
||||
cleared=no eat=no
|
||||
for arg
|
||||
do
|
||||
case $cleared in
|
||||
no)
|
||||
set ""; shift
|
||||
cleared=yes ;;
|
||||
esac
|
||||
if test $eat = yes; then
|
||||
eat=no
|
||||
continue
|
||||
fi
|
||||
case "$arg" in
|
||||
-D*|-I*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
# Strip any option that makedepend may not understand. Remove
|
||||
# the object too, otherwise makedepend will parse it as a source file.
|
||||
-arch)
|
||||
eat=yes ;;
|
||||
-*|$object)
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
esac
|
||||
done
|
||||
obj_suffix=`echo "$object" | sed 's/^.*\././'`
|
||||
touch "$tmpdepfile"
|
||||
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
|
||||
rm -f "$depfile"
|
||||
# makedepend may prepend the VPATH from the source file name to the object.
|
||||
# No need to regex-escape $object, excess matching of '.' is harmless.
|
||||
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process the last invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed '1,2d' "$tmpdepfile" \
|
||||
| tr ' ' "$nl" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile" "$tmpdepfile".bak
|
||||
;;
|
||||
|
||||
cpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
"$@" -E \
|
||||
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
| sed '$ s: \\$::' > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
cat < "$tmpdepfile" >> "$depfile"
|
||||
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvisualcpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case "$arg" in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
|
||||
set fnord "$@"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
"$@" -E 2>/dev/null |
|
||||
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
|
||||
echo "$tab" >> "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvcmsys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
none)
|
||||
exec "$@"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown depmode $depmode" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
541
virt/build-aux/install-sh
Executable file
541
virt/build-aux/install-sh
Executable file
@ -0,0 +1,541 @@
|
||||
#!/usr/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2023-11-23.18; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# 'make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
tab=' '
|
||||
nl='
|
||||
'
|
||||
IFS=" $tab$nl"
|
||||
|
||||
# Set DOITPROG to "echo" to test this script.
|
||||
|
||||
doit=${DOITPROG-}
|
||||
doit_exec=${doit:-exec}
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
# Create dirs (including intermediate dirs) using mode 755.
|
||||
# This is like GNU 'install' as of coreutils 8.32 (2020).
|
||||
mkdir_umask=22
|
||||
|
||||
backupsuffix=
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
is_target_a_directory=possibly
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-p pass -p to $cpprog.
|
||||
-s $stripprog installed files.
|
||||
-S SUFFIX attempt to back up existing files, with suffix SUFFIX.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
|
||||
By default, rm is invoked with -f; when overridden with RMPROG,
|
||||
it's up to you to specify -f if you want it.
|
||||
|
||||
If -S is not specified, no backups are attempted.
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
GNU Automake home page: <https://www.gnu.org/software/automake/>.
|
||||
General help using GNU software: <https://www.gnu.org/gethelp/>."
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-p) cpprog="$cpprog -p";;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-S) backupsuffix="$2"
|
||||
shift;;
|
||||
|
||||
-t)
|
||||
is_target_a_directory=always
|
||||
dst_arg=$2
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) is_target_a_directory=never;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# We allow the use of options -d and -T together, by making -d
|
||||
# take the precedence; this is for compatibility with GNU install.
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
if test -n "$dst_arg"; then
|
||||
echo "$0: target directory not allowed when installing a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call 'install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
if test $# -gt 1 || test "$is_target_a_directory" = always; then
|
||||
if test ! -d "$dst_arg"; then
|
||||
echo "$0: $dst_arg: Is not a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $src in
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
# Don't chown directories that already exist.
|
||||
if test $dstdir_status = 0; then
|
||||
chowncmd=""
|
||||
fi
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
dst=$dst_arg
|
||||
|
||||
# If destination is a directory, append the input filename.
|
||||
if test -d "$dst"; then
|
||||
if test "$is_target_a_directory" = never; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dstbase=`basename "$src"`
|
||||
case $dst in
|
||||
*/) dst=$dst$dstbase;;
|
||||
*) dst=$dst/$dstbase;;
|
||||
esac
|
||||
dstdir_status=0
|
||||
else
|
||||
dstdir=`dirname "$dst"`
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
case $dstdir in
|
||||
*/) dstdirslash=$dstdir;;
|
||||
*) dstdirslash=$dstdir/;;
|
||||
esac
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
# The $RANDOM variable is not portable (e.g., dash). Use it
|
||||
# here however when possible just to lower collision chance.
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
|
||||
trap '
|
||||
ret=$?
|
||||
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
|
||||
exit $ret
|
||||
' 0
|
||||
|
||||
# Because "mkdir -p" follows existing symlinks and we likely work
|
||||
# directly in world-writeable /tmp, make sure that the '$tmpdir'
|
||||
# directory is successfully created first before we actually test
|
||||
# 'mkdir -p'.
|
||||
if (umask $mkdir_umask &&
|
||||
$mkdirprog $mkdir_mode "$tmpdir" &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
test_tmpdir="$tmpdir/a"
|
||||
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=${dstdirslash}_inst.$$_
|
||||
rmtmp=${dstdirslash}_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask &&
|
||||
{ test -z "$stripcmd" || {
|
||||
# Create $dsttmp read-write so that cp doesn't create it read-only,
|
||||
# which would cause strip to fail.
|
||||
if test -z "$doit"; then
|
||||
: >"$dsttmp" # No need to fork-exec 'touch'.
|
||||
else
|
||||
$doit touch "$dsttmp"
|
||||
fi
|
||||
}
|
||||
} &&
|
||||
$doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
set +f &&
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# If $backupsuffix is set, and the file being installed
|
||||
# already exists, attempt a backup. Don't worry if it fails,
|
||||
# e.g., if mv doesn't support -f.
|
||||
if test -n "$backupsuffix" && test -f "$dst"; then
|
||||
$doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
|
||||
fi
|
||||
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
11429
virt/build-aux/ltmain.sh
Normal file
11429
virt/build-aux/ltmain.sh
Normal file
File diff suppressed because it is too large
Load Diff
215
virt/build-aux/missing
Executable file
215
virt/build-aux/missing
Executable file
@ -0,0 +1,215 @@
|
||||
#! /bin/sh
|
||||
# Common wrapper for a few potentially missing GNU programs.
|
||||
|
||||
scriptversion=2018-03-07.03; # UTC
|
||||
|
||||
# Copyright (C) 1996-2021 Free Software Foundation, Inc.
|
||||
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
|
||||
|
||||
# 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, 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
if test $# -eq 0; then
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
|
||||
--is-lightweight)
|
||||
# Used by our autoconf macros to check whether the available missing
|
||||
# script is modern enough.
|
||||
exit 0
|
||||
;;
|
||||
|
||||
--run)
|
||||
# Back-compat with the calling convention used by older automake.
|
||||
shift
|
||||
;;
|
||||
|
||||
-h|--h|--he|--hel|--help)
|
||||
echo "\
|
||||
$0 [OPTION]... PROGRAM [ARGUMENT]...
|
||||
|
||||
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
|
||||
to PROGRAM being missing or too old.
|
||||
|
||||
Options:
|
||||
-h, --help display this help and exit
|
||||
-v, --version output version information and exit
|
||||
|
||||
Supported PROGRAM values:
|
||||
aclocal autoconf autoheader autom4te automake makeinfo
|
||||
bison yacc flex lex help2man
|
||||
|
||||
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
|
||||
'g' are ignored when checking the name.
|
||||
|
||||
Send bug reports to <bug-automake@gnu.org>."
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "missing $scriptversion (GNU Automake)"
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-*)
|
||||
echo 1>&2 "$0: unknown '$1' option"
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
# Run the given program, remember its exit status.
|
||||
"$@"; st=$?
|
||||
|
||||
# If it succeeded, we are done.
|
||||
test $st -eq 0 && exit 0
|
||||
|
||||
# Also exit now if we it failed (or wasn't found), and '--version' was
|
||||
# passed; such an option is passed most likely to detect whether the
|
||||
# program is present and works.
|
||||
case $2 in --version|--help) exit $st;; esac
|
||||
|
||||
# Exit code 63 means version mismatch. This often happens when the user
|
||||
# tries to use an ancient version of a tool on a file that requires a
|
||||
# minimum version.
|
||||
if test $st -eq 63; then
|
||||
msg="probably too old"
|
||||
elif test $st -eq 127; then
|
||||
# Program was missing.
|
||||
msg="missing on your system"
|
||||
else
|
||||
# Program was found and executed, but failed. Give up.
|
||||
exit $st
|
||||
fi
|
||||
|
||||
perl_URL=https://www.perl.org/
|
||||
flex_URL=https://github.com/westes/flex
|
||||
gnu_software_URL=https://www.gnu.org/software
|
||||
|
||||
program_details ()
|
||||
{
|
||||
case $1 in
|
||||
aclocal|automake)
|
||||
echo "The '$1' program is part of the GNU Automake package:"
|
||||
echo "<$gnu_software_URL/automake>"
|
||||
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/autoconf>"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
autoconf|autom4te|autoheader)
|
||||
echo "The '$1' program is part of the GNU Autoconf package:"
|
||||
echo "<$gnu_software_URL/autoconf/>"
|
||||
echo "It also requires GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
give_advice ()
|
||||
{
|
||||
# Normalize program name to check for.
|
||||
normalized_program=`echo "$1" | sed '
|
||||
s/^gnu-//; t
|
||||
s/^gnu//; t
|
||||
s/^g//; t'`
|
||||
|
||||
printf '%s\n' "'$1' is $msg."
|
||||
|
||||
configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
|
||||
case $normalized_program in
|
||||
autoconf*)
|
||||
echo "You should only need it if you modified 'configure.ac',"
|
||||
echo "or m4 files included by it."
|
||||
program_details 'autoconf'
|
||||
;;
|
||||
autoheader*)
|
||||
echo "You should only need it if you modified 'acconfig.h' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'autoheader'
|
||||
;;
|
||||
automake*)
|
||||
echo "You should only need it if you modified 'Makefile.am' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'automake'
|
||||
;;
|
||||
aclocal*)
|
||||
echo "You should only need it if you modified 'acinclude.m4' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'aclocal'
|
||||
;;
|
||||
autom4te*)
|
||||
echo "You might have modified some maintainer files that require"
|
||||
echo "the 'autom4te' program to be rebuilt."
|
||||
program_details 'autom4te'
|
||||
;;
|
||||
bison*|yacc*)
|
||||
echo "You should only need it if you modified a '.y' file."
|
||||
echo "You may want to install the GNU Bison package:"
|
||||
echo "<$gnu_software_URL/bison/>"
|
||||
;;
|
||||
lex*|flex*)
|
||||
echo "You should only need it if you modified a '.l' file."
|
||||
echo "You may want to install the Fast Lexical Analyzer package:"
|
||||
echo "<$flex_URL>"
|
||||
;;
|
||||
help2man*)
|
||||
echo "You should only need it if you modified a dependency" \
|
||||
"of a man page."
|
||||
echo "You may want to install the GNU Help2man package:"
|
||||
echo "<$gnu_software_URL/help2man/>"
|
||||
;;
|
||||
makeinfo*)
|
||||
echo "You should only need it if you modified a '.texi' file, or"
|
||||
echo "any other file indirectly affecting the aspect of the manual."
|
||||
echo "You might want to install the Texinfo package:"
|
||||
echo "<$gnu_software_URL/texinfo/>"
|
||||
echo "The spurious makeinfo call might also be the consequence of"
|
||||
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
|
||||
echo "want to install GNU make:"
|
||||
echo "<$gnu_software_URL/make/>"
|
||||
;;
|
||||
*)
|
||||
echo "You might have modified some files without having the proper"
|
||||
echo "tools for further handling them. Check the 'README' file, it"
|
||||
echo "often tells you about the needed prerequisites for installing"
|
||||
echo "this package. You may also peek at any GNU archive site, in"
|
||||
echo "case some other package contains this missing '$1' program."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
give_advice "$1" | sed -e '1s/^/WARNING: /' \
|
||||
-e '2,$s/^/ /' >&2
|
||||
|
||||
# Propagate the correct exit status (expected to be 127 for a program
|
||||
# not found, 63 for a program that failed due to version mismatch).
|
||||
exit $st
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
153
virt/build-aux/test-driver
Executable file
153
virt/build-aux/test-driver
Executable file
@ -0,0 +1,153 @@
|
||||
#! /bin/sh
|
||||
# test-driver - basic testsuite driver script.
|
||||
|
||||
scriptversion=2018-03-07.03; # UTC
|
||||
|
||||
# Copyright (C) 2011-2021 Free Software Foundation, 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, 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
# Make unconditional expansion of undefined variables an error. This
|
||||
# helps a lot in preventing typo-related bugs.
|
||||
set -u
|
||||
|
||||
usage_error ()
|
||||
{
|
||||
echo "$0: $*" >&2
|
||||
print_usage >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
print_usage ()
|
||||
{
|
||||
cat <<END
|
||||
Usage:
|
||||
test-driver --test-name NAME --log-file PATH --trs-file PATH
|
||||
[--expect-failure {yes|no}] [--color-tests {yes|no}]
|
||||
[--enable-hard-errors {yes|no}] [--]
|
||||
TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
|
||||
|
||||
The '--test-name', '--log-file' and '--trs-file' options are mandatory.
|
||||
See the GNU Automake documentation for information.
|
||||
END
|
||||
}
|
||||
|
||||
test_name= # Used for reporting.
|
||||
log_file= # Where to save the output of the test script.
|
||||
trs_file= # Where to save the metadata of the test run.
|
||||
expect_failure=no
|
||||
color_tests=no
|
||||
enable_hard_errors=yes
|
||||
while test $# -gt 0; do
|
||||
case $1 in
|
||||
--help) print_usage; exit $?;;
|
||||
--version) echo "test-driver $scriptversion"; exit $?;;
|
||||
--test-name) test_name=$2; shift;;
|
||||
--log-file) log_file=$2; shift;;
|
||||
--trs-file) trs_file=$2; shift;;
|
||||
--color-tests) color_tests=$2; shift;;
|
||||
--expect-failure) expect_failure=$2; shift;;
|
||||
--enable-hard-errors) enable_hard_errors=$2; shift;;
|
||||
--) shift; break;;
|
||||
-*) usage_error "invalid option: '$1'";;
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
missing_opts=
|
||||
test x"$test_name" = x && missing_opts="$missing_opts --test-name"
|
||||
test x"$log_file" = x && missing_opts="$missing_opts --log-file"
|
||||
test x"$trs_file" = x && missing_opts="$missing_opts --trs-file"
|
||||
if test x"$missing_opts" != x; then
|
||||
usage_error "the following mandatory options are missing:$missing_opts"
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
usage_error "missing argument"
|
||||
fi
|
||||
|
||||
if test $color_tests = yes; then
|
||||
# Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
|
||||
red='[0;31m' # Red.
|
||||
grn='[0;32m' # Green.
|
||||
lgn='[1;32m' # Light green.
|
||||
blu='[1;34m' # Blue.
|
||||
mgn='[0;35m' # Magenta.
|
||||
std='[m' # No color.
|
||||
else
|
||||
red= grn= lgn= blu= mgn= std=
|
||||
fi
|
||||
|
||||
do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
|
||||
trap "st=129; $do_exit" 1
|
||||
trap "st=130; $do_exit" 2
|
||||
trap "st=141; $do_exit" 13
|
||||
trap "st=143; $do_exit" 15
|
||||
|
||||
# Test script is run here. We create the file first, then append to it,
|
||||
# to ameliorate tests themselves also writing to the log file. Our tests
|
||||
# don't, but others can (automake bug#35762).
|
||||
: >"$log_file"
|
||||
"$@" >>"$log_file" 2>&1
|
||||
estatus=$?
|
||||
|
||||
if test $enable_hard_errors = no && test $estatus -eq 99; then
|
||||
tweaked_estatus=1
|
||||
else
|
||||
tweaked_estatus=$estatus
|
||||
fi
|
||||
|
||||
case $tweaked_estatus:$expect_failure in
|
||||
0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
|
||||
0:*) col=$grn res=PASS recheck=no gcopy=no;;
|
||||
77:*) col=$blu res=SKIP recheck=no gcopy=yes;;
|
||||
99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;;
|
||||
*:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;;
|
||||
*:*) col=$red res=FAIL recheck=yes gcopy=yes;;
|
||||
esac
|
||||
|
||||
# Report the test outcome and exit status in the logs, so that one can
|
||||
# know whether the test passed or failed simply by looking at the '.log'
|
||||
# file, without the need of also peaking into the corresponding '.trs'
|
||||
# file (automake bug#11814).
|
||||
echo "$res $test_name (exit status: $estatus)" >>"$log_file"
|
||||
|
||||
# Report outcome to console.
|
||||
echo "${col}${res}${std}: $test_name"
|
||||
|
||||
# Register the test result, and other relevant metadata.
|
||||
echo ":test-result: $res" > $trs_file
|
||||
echo ":global-test-result: $res" >> $trs_file
|
||||
echo ":recheck: $recheck" >> $trs_file
|
||||
echo ":copy-in-global-log: $gcopy" >> $trs_file
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
68
virt/common/.gitignore
vendored
Normal file
68
virt/common/.gitignore
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
*~
|
||||
*.a
|
||||
*.annot
|
||||
*.bak
|
||||
*.class
|
||||
*.cma
|
||||
*.cmi
|
||||
*.cmo
|
||||
*.cmx
|
||||
*.cmxa
|
||||
*.diff
|
||||
*.eml
|
||||
*.hi
|
||||
*.jar
|
||||
*.la
|
||||
*.lo
|
||||
*.log
|
||||
*.o
|
||||
*.orig
|
||||
*.pyc
|
||||
*.rej
|
||||
*.swp
|
||||
*.trs
|
||||
|
||||
.deps
|
||||
.dirstamp
|
||||
dll*.so
|
||||
.libs
|
||||
Makefile
|
||||
Makefile.in
|
||||
|
||||
/errnostring/errnostring.c
|
||||
/errnostring/errnostring-gperf.c
|
||||
/errnostring/errnostring-gperf.gperf
|
||||
/errnostring/errnostring.h
|
||||
/mlcustomize/.depend
|
||||
/mlcustomize/test-firstboot-*.sh
|
||||
/mldrivers/.depend
|
||||
/mlgettext/.depend
|
||||
/mlgettext/common_gettext.ml
|
||||
/mlpcre/.depend
|
||||
/mlpcre/pcre_tests
|
||||
/mlprogress/.depend
|
||||
/mlstdutils/.depend
|
||||
/mlstdutils/bytes.ml
|
||||
/mlstdutils/bytes.mli
|
||||
/mlstdutils/guestfs_config.ml
|
||||
/mlstdutils/oUnit-*
|
||||
/mlstdutils/std_utils_tests
|
||||
/mltools/.depend
|
||||
/mltools/getopt_tests
|
||||
/mltools/JSON_tests
|
||||
/mltools/JSON_parser_tests
|
||||
/mltools/machine_readable_tests
|
||||
/mltools/tools_messages_tests
|
||||
/mltools/tools_utils_tests
|
||||
/mltools/oUnit-*
|
||||
/mlutils/.depend
|
||||
/mlutils/c_utils_unit_tests
|
||||
/mlutils/oUnit-*
|
||||
/mlv2v/.depend
|
||||
/mlvisit/.depend
|
||||
/mlvisit/visit_tests
|
||||
/mlxml/.depend
|
||||
/protocol/guestfs_protocol.c
|
||||
/protocol/guestfs_protocol.h
|
||||
/protocol/guestfs_protocol.x
|
||||
/qemuopts/qemuopts-tests
|
6
virt/common/README
Normal file
6
virt/common/README
Normal file
@ -0,0 +1,6 @@
|
||||
This is a git module which contains common code shared between
|
||||
libguestfs and the tools. It is referenced as a submodule from here:
|
||||
|
||||
https://github.com/libguestfs/libguestfs
|
||||
https://github.com/libguestfs/guestfs-tools
|
||||
https://github.com/libguestfs/virt-v2v
|
348
virt/common/edit/file-edit.c
Normal file
348
virt/common/edit/file-edit.c
Normal file
@ -0,0 +1,348 @@
|
||||
/* libguestfs - shared file editing
|
||||
* Copyright (C) 2009-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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file implements common file editing in a range of utilities
|
||||
* including L<guestfish(1)>, L<virt-edit(1)>, L<virt-customize(1)>
|
||||
* and L<virt-builder(1)>.
|
||||
*
|
||||
* It contains the code for both interactive-(editor-)based editing
|
||||
* and non-interactive editing using Perl snippets.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <locale.h>
|
||||
#include <langinfo.h>
|
||||
#include <libintl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <assert.h>
|
||||
#include <utime.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "guestfs-utils.h"
|
||||
|
||||
#include "file-edit.h"
|
||||
|
||||
static int do_download (guestfs_h *g, const char *filename, char **tempfile);
|
||||
static int do_upload (guestfs_h *g, const char *filename, const char *tempfile,
|
||||
const char *backup_extension);
|
||||
static char *generate_random_name (const char *filename);
|
||||
static char *generate_backup_name (const char *filename,
|
||||
const char *backup_extension);
|
||||
|
||||
/**
|
||||
* Edit C<filename> using the specified C<editor> application.
|
||||
*
|
||||
* If C<backup_extension> is not null, then a copy of C<filename> is
|
||||
* saved with C<backup_extension> appended to its file name.
|
||||
*
|
||||
* If C<editor> is null, then the C<$EDITOR> environment variable will
|
||||
* be queried for the editor application, leaving C<vi> as fallback if
|
||||
* not set.
|
||||
*
|
||||
* Returns C<-1> for failure, C<0> on success, C<1> if the editor did
|
||||
* not change the file (e.g. the user closed the editor without
|
||||
* saving).
|
||||
*/
|
||||
int
|
||||
edit_file_editor (guestfs_h *g, const char *filename, const char *editor,
|
||||
const char *backup_extension, int verbose)
|
||||
{
|
||||
CLEANUP_UNLINK_FREE char *tmpfilename = NULL;
|
||||
CLEANUP_FREE char *cmd = NULL;
|
||||
struct stat oldstat, newstat;
|
||||
int r;
|
||||
struct utimbuf times;
|
||||
|
||||
if (editor == NULL) {
|
||||
editor = getenv ("EDITOR");
|
||||
if (editor == NULL)
|
||||
editor = "vi";
|
||||
}
|
||||
|
||||
/* Download the file and write it to a temporary. */
|
||||
if (do_download (g, filename, &tmpfilename) == -1)
|
||||
return -1;
|
||||
|
||||
/* Set the time back a few seconds on the original file. This is so
|
||||
* that if the user is very fast at editing, or if EDITOR is an
|
||||
* automatic editor, then the edit might happen within the 1 second
|
||||
* granularity of mtime, and we would think the file hasn't changed.
|
||||
*/
|
||||
if (stat (tmpfilename, &oldstat) == -1) {
|
||||
perror (tmpfilename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
times.actime = oldstat.st_atime - 5;
|
||||
times.modtime = oldstat.st_mtime - 5;
|
||||
if (utime (tmpfilename, ×) == -1) {
|
||||
perror ("utimes");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the old stat. */
|
||||
if (stat (tmpfilename, &oldstat) == -1) {
|
||||
perror (tmpfilename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Edit it. */
|
||||
if (asprintf (&cmd, "%s %s", editor, tmpfilename) == -1) {
|
||||
perror ("asprintf");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
fprintf (stderr, "%s\n", cmd);
|
||||
|
||||
r = system (cmd);
|
||||
if (r == -1 || WEXITSTATUS (r) != 0) {
|
||||
perror (cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the new stat. */
|
||||
if (stat (tmpfilename, &newstat) == -1) {
|
||||
perror (tmpfilename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Changed? */
|
||||
if (oldstat.st_ctime == newstat.st_ctime &&
|
||||
oldstat.st_size == newstat.st_size)
|
||||
return 1;
|
||||
|
||||
if (do_upload (g, filename, tmpfilename, backup_extension) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit C<filename> running the specified C<perl_expr> using Perl.
|
||||
*
|
||||
* If C<backup_extension> is not null, then a copy of C<filename> is
|
||||
* saved with C<backup_extension> appended to its file name.
|
||||
*
|
||||
* Returns C<-1> for failure, C<0> on success.
|
||||
*/
|
||||
int
|
||||
edit_file_perl (guestfs_h *g, const char *filename, const char *perl_expr,
|
||||
const char *backup_extension, int verbose)
|
||||
{
|
||||
CLEANUP_UNLINK_FREE char *tmpfilename = NULL;
|
||||
CLEANUP_FREE char *cmd = NULL;
|
||||
CLEANUP_FREE char *outfile = NULL;
|
||||
int r;
|
||||
|
||||
/* Download the file and write it to a temporary. */
|
||||
if (do_download (g, filename, &tmpfilename) == -1)
|
||||
return -1;
|
||||
|
||||
if (asprintf (&outfile, "%s.out", tmpfilename) == -1) {
|
||||
perror ("asprintf");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Pass the expression to Perl via the environment. This sidesteps
|
||||
* any quoting problems with the already complex Perl command line.
|
||||
*/
|
||||
setenv ("virt_edit_expr", perl_expr, 1);
|
||||
|
||||
/* Call out to a canned Perl script. */
|
||||
if (asprintf (&cmd,
|
||||
"perl -e '"
|
||||
"$lineno = 0; "
|
||||
"$expr = $ENV{virt_edit_expr}; "
|
||||
"while (<STDIN>) { "
|
||||
" $lineno++; "
|
||||
" eval $expr; "
|
||||
" die if $@; "
|
||||
" print STDOUT $_ or die \"print: $!\"; "
|
||||
"} "
|
||||
"close STDOUT or die \"close: $!\"; "
|
||||
"' < %s > %s",
|
||||
tmpfilename, outfile) == -1) {
|
||||
perror ("asprintf");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
fprintf (stderr, "%s\n", cmd);
|
||||
|
||||
r = system (cmd);
|
||||
if (r == -1 || WEXITSTATUS (r) != 0)
|
||||
return -1;
|
||||
|
||||
if (rename (outfile, tmpfilename) == -1) {
|
||||
perror ("rename");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (do_upload (g, filename, tmpfilename, backup_extension) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_download (guestfs_h *g, const char *filename, char **tempfile)
|
||||
{
|
||||
CLEANUP_FREE char *tmpdir = guestfs_get_tmpdir (g);
|
||||
CLEANUP_UNLINK_FREE char *tmpfilename = NULL;
|
||||
char buf[256];
|
||||
int fd;
|
||||
|
||||
/* Download the file and write it to a temporary. */
|
||||
if (asprintf (&tmpfilename, "%s/libguestfsXXXXXX", tmpdir) == -1) {
|
||||
perror ("asprintf");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = mkstemp (tmpfilename);
|
||||
if (fd == -1) {
|
||||
perror ("mkstemp");
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf (buf, sizeof buf, "/dev/fd/%d", fd);
|
||||
|
||||
if (guestfs_download (g, filename, buf) == -1) {
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (close (fd) == -1) {
|
||||
perror (tmpfilename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Hand over the temporary file. */
|
||||
*tempfile = tmpfilename;
|
||||
tmpfilename = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_upload (guestfs_h *g, const char *fn, const char *tempfile,
|
||||
const char *backup_extension)
|
||||
{
|
||||
CLEANUP_FREE char *filename = NULL;
|
||||
CLEANUP_FREE char *newname = NULL;
|
||||
|
||||
/* Resolve the file name and write to the actual target, since
|
||||
* that is the file it was opened earlier; otherwise, if it is
|
||||
* a symlink it will be overwritten by a regular file with the
|
||||
* new content.
|
||||
*
|
||||
* Theoretically realpath should work, but just check again
|
||||
* to be safe.
|
||||
*/
|
||||
filename = guestfs_realpath (g, fn);
|
||||
if (filename == NULL)
|
||||
return -1;
|
||||
|
||||
/* Upload to a new file in the same directory, so if it fails we
|
||||
* don't end up with a partially written file. Give the new file
|
||||
* a completely random name so we have only a tiny chance of
|
||||
* overwriting some existing file.
|
||||
*/
|
||||
newname = generate_random_name (filename);
|
||||
if (!newname)
|
||||
return -1;
|
||||
|
||||
/* Write new content. */
|
||||
if (guestfs_upload (g, tempfile, newname) == -1)
|
||||
return -1;
|
||||
|
||||
/* Set the permissions, UID, GID and SELinux context of the new
|
||||
* file to match the old file (RHBZ#788641).
|
||||
*/
|
||||
if (guestfs_copy_attributes (g, filename, newname,
|
||||
GUESTFS_COPY_ATTRIBUTES_ALL, 1, -1) == -1)
|
||||
return -1;
|
||||
|
||||
/* Backup or overwrite the file. */
|
||||
if (backup_extension) {
|
||||
CLEANUP_FREE char *backupname = NULL;
|
||||
|
||||
backupname = generate_backup_name (filename, backup_extension);
|
||||
if (backupname == NULL)
|
||||
return -1;
|
||||
|
||||
if (guestfs_mv (g, filename, backupname) == -1)
|
||||
return -1;
|
||||
}
|
||||
if (guestfs_mv (g, newname, filename) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *
|
||||
generate_random_name (const char *filename)
|
||||
{
|
||||
char *ret, *p;
|
||||
|
||||
ret = malloc (strlen (filename) + 16);
|
||||
if (!ret) {
|
||||
perror ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
strcpy (ret, filename);
|
||||
|
||||
p = strrchr (ret, '/');
|
||||
assert (p);
|
||||
p++;
|
||||
|
||||
/* Because of "+ 16" above, there should be enough space in the
|
||||
* output buffer to write 8 random characters here plus the
|
||||
* trailing \0.
|
||||
*/
|
||||
if (guestfs_int_random_string (p, 8) == -1) {
|
||||
perror ("guestfs_int_random_string");
|
||||
free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret; /* caller will free */
|
||||
}
|
||||
|
||||
static char *
|
||||
generate_backup_name (const char *filename, const char *backup_extension)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
assert (backup_extension != NULL);
|
||||
|
||||
if (asprintf (&ret, "%s%s", filename, backup_extension) == -1) {
|
||||
perror ("asprintf");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret; /* caller will free */
|
||||
}
|
32
virt/common/edit/file-edit.h
Normal file
32
virt/common/edit/file-edit.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* libguestfs - shared file editing
|
||||
* Copyright (C) 2009-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.
|
||||
*/
|
||||
|
||||
#ifndef FISH_FILE_EDIT_H
|
||||
#define FISH_FILE_EDIT_H
|
||||
|
||||
#include <guestfs.h>
|
||||
|
||||
extern int edit_file_editor (guestfs_h *g, const char *filename,
|
||||
const char *editor, const char *backup_extension,
|
||||
int verbose);
|
||||
|
||||
extern int edit_file_perl (guestfs_h *g, const char *filename,
|
||||
const char *perl_expr,
|
||||
const char *backup_extension, int verbose);
|
||||
|
||||
#endif
|
207
virt/common/mlcustomize/Makefile.am
Normal file
207
virt/common/mlcustomize/Makefile.am
Normal file
@ -0,0 +1,207 @@
|
||||
# libguestfs OCaml virt-customize common code
|
||||
# Copyright (C) 2011-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.
|
||||
|
||||
include $(top_srcdir)/subdir-rules.mk
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(generator_built) \
|
||||
$(SOURCES_MLI) \
|
||||
$(SOURCES_ML) \
|
||||
$(SOURCES_C) \
|
||||
test-firstboot.sh \
|
||||
test-selinuxrelabel.sh
|
||||
|
||||
generator_built = \
|
||||
customize_cmdline.mli \
|
||||
customize_cmdline.ml \
|
||||
customize-options.pod \
|
||||
customize-synopsis.pod \
|
||||
v2v-customize-options.pod \
|
||||
v2v-customize-synopsis.pod
|
||||
|
||||
SOURCES_MLI = \
|
||||
append_line.mli \
|
||||
crypt.mli \
|
||||
customize_cmdline.mli \
|
||||
customize_run.mli \
|
||||
firstboot.mli \
|
||||
guest_packages.mli \
|
||||
hostname.mli \
|
||||
inject_virtio_win.mli \
|
||||
password.mli \
|
||||
perl_edit.mli \
|
||||
random_seed.mli \
|
||||
SELinux_relabel.mli \
|
||||
ssh_key.mli \
|
||||
subscription_manager.mli \
|
||||
timezone.mli
|
||||
|
||||
# This list must be in dependency order.
|
||||
SOURCES_ML = \
|
||||
firstboot.ml \
|
||||
append_line.ml \
|
||||
hostname.ml \
|
||||
perl_edit.ml \
|
||||
random_seed.ml \
|
||||
ssh_key.ml \
|
||||
subscription_manager.ml \
|
||||
timezone.ml \
|
||||
crypt.ml \
|
||||
password.ml \
|
||||
guest_packages.ml \
|
||||
inject_virtio_win.ml \
|
||||
SELinux_relabel.ml \
|
||||
customize_cmdline.ml \
|
||||
customize_run.ml
|
||||
|
||||
SOURCES_C = \
|
||||
../edit/file-edit.c \
|
||||
../edit/file-edit.h \
|
||||
crypt-c.c \
|
||||
perl_edit-c.c
|
||||
|
||||
if HAVE_OCAML
|
||||
|
||||
# We pretend that we're building a C library. automake handles the
|
||||
# compilation of the C sources for us. At the end we take the C
|
||||
# objects and OCaml objects and link them into the OCaml library.
|
||||
# This C library is never used.
|
||||
|
||||
noinst_LIBRARIES = libmlcustomize.a
|
||||
|
||||
if !HAVE_OCAMLOPT
|
||||
MLCUSTOMIZE_CMA = mlcustomize.cma
|
||||
else
|
||||
MLCUSTOMIZE_CMA = mlcustomize.cmxa
|
||||
endif
|
||||
|
||||
noinst_DATA = $(MLCUSTOMIZE_CMA)
|
||||
|
||||
libmlcustomize_a_SOURCES = $(SOURCES_C)
|
||||
libmlcustomize_a_CPPFLAGS = \
|
||||
-DCAML_NAME_SPACE \
|
||||
-I. \
|
||||
-I$(top_builddir) \
|
||||
-I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \
|
||||
-I$(shell $(OCAMLC) -where) \
|
||||
-I$(top_srcdir)/common/utils \
|
||||
-I$(top_srcdir)/lib \
|
||||
-I$(top_srcdir)/common/edit \
|
||||
-I$(top_srcdir)/common/mlstdutils \
|
||||
-I$(top_srcdir)/common/mlgettext \
|
||||
-I$(top_srcdir)/common/mlpcre \
|
||||
-I$(top_srcdir)/common/mltools \
|
||||
-I$(top_srcdir)/common/mlxml
|
||||
libmlcustomize_a_CFLAGS = \
|
||||
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
|
||||
-fPIC
|
||||
|
||||
BOBJECTS = $(SOURCES_ML:.ml=.cmo)
|
||||
XOBJECTS = $(BOBJECTS:.cmo=.cmx)
|
||||
|
||||
OCAMLPACKAGES = \
|
||||
-package str,unix,guestfs \
|
||||
-I $(top_builddir)/common/utils/.libs \
|
||||
-I $(top_builddir)/ocaml \
|
||||
-I $(top_builddir)/common/mlstdutils \
|
||||
-I $(top_builddir)/common/mlgettext \
|
||||
-I $(top_builddir)/common/mlpcre \
|
||||
-I $(top_builddir)/common/mltools \
|
||||
-I $(top_builddir)/common/mlxml \
|
||||
-I $(builddir)
|
||||
OCAMLPACKAGES_TESTS = $(MLCUSTOMIZE_CMA)
|
||||
if HAVE_OCAML_PKG_GETTEXT
|
||||
OCAMLPACKAGES += -package gettext-stub
|
||||
endif
|
||||
|
||||
OCAMLCLIBS = \
|
||||
-lutils \
|
||||
$(LIBINTL) \
|
||||
-lgnu
|
||||
|
||||
OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
|
||||
|
||||
if !HAVE_OCAMLOPT
|
||||
OBJECTS = $(BOBJECTS)
|
||||
else
|
||||
OBJECTS = $(XOBJECTS)
|
||||
endif
|
||||
|
||||
libmlcustomize_a_DEPENDENCIES = $(OBJECTS)
|
||||
|
||||
$(MLCUSTOMIZE_CMA): $(OBJECTS) libmlcustomize.a
|
||||
$(OCAMLFIND) mklib $(OCAMLPACKAGES) \
|
||||
$(OBJECTS) $(libmlcustomize_a_OBJECTS) -o mlcustomize
|
||||
|
||||
# Tests.
|
||||
|
||||
TESTS_ENVIRONMENT = $(top_builddir)/run --test
|
||||
|
||||
TESTS = $(SLOW_TESTS)
|
||||
|
||||
check-valgrind:
|
||||
$(MAKE) VG="@VG@" check
|
||||
|
||||
# Slow tests of virt-customize functionality in real guests.
|
||||
|
||||
SLOW_TESTS = \
|
||||
$(firstboot_test_scripts) \
|
||||
test-selinuxrelabel.sh
|
||||
|
||||
check-slow:
|
||||
$(MAKE) check TESTS="$(SLOW_TESTS)" SLOW=1
|
||||
|
||||
firstboot_test_scripts := \
|
||||
test-firstboot-rhel-4.9.sh \
|
||||
test-firstboot-rhel-5.11.sh \
|
||||
test-firstboot-rhel-6.8.sh \
|
||||
test-firstboot-rhel-7.2.sh \
|
||||
test-firstboot-debian-6.sh \
|
||||
test-firstboot-debian-7.sh \
|
||||
test-firstboot-debian-8.sh \
|
||||
test-firstboot-fedora-26.sh \
|
||||
test-firstboot-fedora-27.sh \
|
||||
test-firstboot-ubuntu-10.04.sh \
|
||||
test-firstboot-ubuntu-12.04.sh \
|
||||
test-firstboot-ubuntu-14.04.sh \
|
||||
test-firstboot-ubuntu-16.04.sh \
|
||||
test-firstboot-ubuntu-18.04.sh \
|
||||
test-firstboot-windows-6.2-server.sh \
|
||||
test-firstboot-windows-6.3-server.sh \
|
||||
test-firstboot-windows-10.0-server.sh
|
||||
# Firstboot is known-broken on RHEL 3:
|
||||
# test-firstboot-rhel-3.9.sh
|
||||
|
||||
test-firstboot-%.sh:
|
||||
rm -f $@ $@-t
|
||||
f=`echo "$@" | $(SED) 's/test-firstboot-\(.*\).sh/\1/'`; \
|
||||
echo 'script=$@ exec $$srcdir/test-firstboot.sh' "$$f" > $@-t
|
||||
chmod 0755 $@-t
|
||||
mv $@-t $@
|
||||
|
||||
CLEANFILES += \
|
||||
$(firstboot_test_scripts) \
|
||||
firstboot-*.img
|
||||
|
||||
# Dependencies.
|
||||
.depend: $(srcdir)/*.mli $(srcdir)/*.ml
|
||||
$(top_builddir)/ocaml-dep.sh $^
|
||||
-include .depend
|
||||
|
||||
endif
|
||||
|
||||
.PHONY: docs
|
1583
virt/common/mlcustomize/Makefile.in
Normal file
1583
virt/common/mlcustomize/Makefile.in
Normal file
File diff suppressed because it is too large
Load Diff
113
virt/common/mlcustomize/SELinux_relabel.ml
Normal file
113
virt/common/mlcustomize/SELinux_relabel.ml
Normal file
@ -0,0 +1,113 @@
|
||||
(* virt-customize
|
||||
* Copyright (C) 2016 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 Tools_utils
|
||||
open Common_gettext.Gettext
|
||||
|
||||
open Printf
|
||||
|
||||
module G = Guestfs
|
||||
|
||||
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"
|
||||
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;
|
||||
|
||||
let config_path = "/files/etc/selinux/config" in
|
||||
let config_keys = g#aug_ls config_path in
|
||||
(* SELinux may be disabled via a setting in config file *)
|
||||
let selinux_disabled =
|
||||
let selinuxmode_path = config_path ^ "/SELINUX" in
|
||||
if Array.mem selinuxmode_path config_keys then
|
||||
g#aug_get selinuxmode_path = "disabled"
|
||||
else
|
||||
false in
|
||||
if selinux_disabled then
|
||||
failwith "selinux disabled";
|
||||
|
||||
(* Get the SELinux policy name, eg. "targeted", "minimum".
|
||||
* Use "targeted" if not specified, just like libselinux does.
|
||||
*)
|
||||
let policy =
|
||||
let selinuxtype_path = config_path ^ "/SELINUXTYPE" in
|
||||
if Array.mem selinuxtype_path config_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 "/"
|
29
virt/common/mlcustomize/SELinux_relabel.mli
Normal file
29
virt/common/mlcustomize/SELinux_relabel.mli
Normal file
@ -0,0 +1,29 @@
|
||||
(* virt-customize
|
||||
* Copyright (C) 2016 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.
|
||||
*)
|
||||
|
||||
(** SELinux-relabel the filesystem. *)
|
||||
|
||||
val relabel : Guestfs.guestfs -> unit
|
||||
(** Relabel the mounted guestfs filesystem using the current SELinux
|
||||
policy that applies to the guest.
|
||||
|
||||
If the guest does not look like it uses SELinux, this does nothing.
|
||||
|
||||
In case relabelling is not possible (since it is an optional
|
||||
feature which requires the setfiles(8) program), instead we
|
||||
fall back to touching [/.autorelabel]. *)
|
72
virt/common/mlcustomize/append_line.ml
Normal file
72
virt/common/mlcustomize/append_line.ml
Normal file
@ -0,0 +1,72 @@
|
||||
(* virt-customize
|
||||
* Copyright (C) 2016 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 Tools_utils
|
||||
open Common_gettext.Gettext
|
||||
|
||||
module G = Guestfs
|
||||
|
||||
let append_line (g : G.guestfs) root path line =
|
||||
(* The default line ending for this guest type. This is only
|
||||
* used when we don't know anything more about the file.
|
||||
*)
|
||||
let default_newline () =
|
||||
match g#inspect_get_type root with
|
||||
| "windows" -> "\r\n"
|
||||
| _ -> "\n"
|
||||
in
|
||||
|
||||
if not (g#exists path) then (
|
||||
g#write path (line ^ default_newline ())
|
||||
)
|
||||
else (
|
||||
(* Stat the file. We want to know it's a regular file, and
|
||||
* also its size.
|
||||
*)
|
||||
let { G.st_mode; st_size = size } = g#statns path in
|
||||
if Int64.logand st_mode 0o170000_L <> 0o100000_L then
|
||||
error (f_"append_line: %s is not a file") path;
|
||||
|
||||
(* Guess the line ending from the first part of the file, else
|
||||
* use the default for this guest type.
|
||||
*)
|
||||
let newline =
|
||||
let content = g#pread path 8192 0L in
|
||||
if String.find content "\r\n" >= 0 then "\r\n"
|
||||
else if String.find content "\n" >= 0 then "\n"
|
||||
else if String.find content "\r" >= 0 then "\r"
|
||||
else default_newline () in
|
||||
|
||||
let line = line ^ newline in
|
||||
|
||||
(* Do we need to append a newline to the existing file? *)
|
||||
let last_chars =
|
||||
let len = String.length newline in
|
||||
if size <= 0L then newline (* empty file ends in virtual newline *)
|
||||
else if size >= Int64.of_int len then
|
||||
g#pread path len (size -^ Int64.of_int len)
|
||||
else
|
||||
g#pread path len 0L in
|
||||
let line =
|
||||
if last_chars = newline then line
|
||||
else newline ^ line in
|
||||
|
||||
(* Finally, append. *)
|
||||
g#write_append path line
|
||||
)
|
@ -1,5 +1,5 @@
|
||||
(* virt-v2v-in-place
|
||||
* Copyright (C) 2009-2024 Red Hat Inc.
|
||||
(* virt-customize
|
||||
* Copyright (C) 2016 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
|
||||
@ -16,7 +16,5 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*)
|
||||
|
||||
val create_inspector_xml : string -> Types.inspect -> Types.target_meta ->
|
||||
DOM.doc
|
||||
(** Create the XML output of virt-v2v-inspector which contains the
|
||||
post-conversion metadata. *)
|
||||
val append_line : Guestfs.guestfs -> string -> string -> string -> unit
|
||||
(** append_line [g root file line] appends a single line to a text file. *)
|
54
virt/common/mlcustomize/crypt-c.c
Normal file
54
virt/common/mlcustomize/crypt-c.c
Normal file
@ -0,0 +1,54 @@
|
||||
/* virt-sysprep - interface to crypt(3)
|
||||
* Copyright (C) 2013 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 <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if HAVE_CRYPT_H
|
||||
#include <crypt.h>
|
||||
#endif
|
||||
|
||||
#include <caml/alloc.h>
|
||||
#include <caml/memory.h>
|
||||
#include <caml/mlvalues.h>
|
||||
#include <caml/unixsupport.h>
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
|
||||
|
||||
value
|
||||
virt_customize_crypt (value keyv, value saltv)
|
||||
{
|
||||
CAMLparam2 (keyv, saltv);
|
||||
CAMLlocal1 (rv);
|
||||
char *r;
|
||||
|
||||
/* Note that crypt returns a pointer to a statically allocated
|
||||
* buffer in glibc. For this and other reasons, this function
|
||||
* is not thread safe.
|
||||
*/
|
||||
r = crypt (String_val (keyv), String_val (saltv));
|
||||
if (r == NULL)
|
||||
unix_error (errno, (char *) "crypt", Nothing);
|
||||
rv = caml_copy_string (r);
|
||||
|
||||
CAMLreturn (rv);
|
||||
}
|
19
virt/common/mlcustomize/crypt.ml
Normal file
19
virt/common/mlcustomize/crypt.ml
Normal file
@ -0,0 +1,19 @@
|
||||
(* virt-sysprep
|
||||
* Copyright (C) 2013 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.
|
||||
*)
|
||||
|
||||
external crypt : string -> string -> string = "virt_customize_crypt"
|
22
virt/common/mlcustomize/crypt.mli
Normal file
22
virt/common/mlcustomize/crypt.mli
Normal file
@ -0,0 +1,22 @@
|
||||
(* virt-sysprep
|
||||
* Copyright (C) 2013 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.
|
||||
*)
|
||||
|
||||
(** Wrapper around glibc crypt(3) function. *)
|
||||
|
||||
val crypt : string -> string -> string
|
||||
(** [crypt key salt] returns the password ([key]) encrypted. *)
|
505
virt/common/mlcustomize/customize-options.pod
Normal file
505
virt/common/mlcustomize/customize-options.pod
Normal file
@ -0,0 +1,505 @@
|
||||
=begin comment
|
||||
|
||||
libguestfs generated file
|
||||
WARNING: THIS FILE IS GENERATED FROM THE FOLLOWING FILES:
|
||||
generator/customize.ml
|
||||
and from the code in the generator/ subdirectory.
|
||||
ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.
|
||||
|
||||
Copyright (C) 2009-2023 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.
|
||||
|
||||
=end comment
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<--append-line> FILE:LINE
|
||||
|
||||
Append a single line of text to the C<FILE>. If the file does not already
|
||||
end with a newline, then one is added before the appended
|
||||
line. Also a newline is added to the end of the C<LINE> string
|
||||
automatically.
|
||||
|
||||
For example (assuming ordinary shell quoting) this command:
|
||||
|
||||
--append-line '/etc/hosts:10.0.0.1 foo'
|
||||
|
||||
will add either C<10.0.0.1 foo⏎> or C<⏎10.0.0.1 foo⏎> to
|
||||
the file, the latter only if the existing file does not
|
||||
already end with a newline.
|
||||
|
||||
C<⏎> represents a newline character, which is guessed by
|
||||
looking at the existing content of the file, so this command
|
||||
does the right thing for files using Unix or Windows line endings.
|
||||
It also works for empty or non-existent files.
|
||||
|
||||
To insert several lines, use the same option several times:
|
||||
|
||||
--append-line '/etc/hosts:10.0.0.1 foo'
|
||||
--append-line '/etc/hosts:10.0.0.2 bar'
|
||||
|
||||
To insert a blank line before the appended line, do:
|
||||
|
||||
--append-line '/etc/hosts:'
|
||||
--append-line '/etc/hosts:10.0.0.1 foo'
|
||||
|
||||
=item B<--chmod> PERMISSIONS:FILE
|
||||
|
||||
Change the permissions of C<FILE> to C<PERMISSIONS>.
|
||||
|
||||
I<Note>: C<PERMISSIONS> by default would be decimal, unless you prefix
|
||||
it with C<0> to get octal, ie. use C<0700> not C<700>.
|
||||
|
||||
=item B<--chown> UID:GID:PATH
|
||||
|
||||
Change the owner user and group ID of a file or directory in the guest.
|
||||
Note:
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
Only numeric UIDs and GIDs will work, and these may not be the same
|
||||
inside the guest as on the host.
|
||||
|
||||
=item *
|
||||
|
||||
This will not work with Windows guests.
|
||||
|
||||
=back
|
||||
|
||||
For example:
|
||||
|
||||
virt-customize --chown '0:0:/var/log/audit.log'
|
||||
|
||||
See also: I<--upload>.
|
||||
|
||||
=item B<--commands-from-file> FILENAME
|
||||
|
||||
Read the customize commands from a file, one (and its arguments)
|
||||
each line.
|
||||
|
||||
Each line contains a single customization command and its arguments,
|
||||
for example:
|
||||
|
||||
delete /some/file
|
||||
install some-package
|
||||
password some-user:password:its-new-password
|
||||
|
||||
Empty lines are ignored, and lines starting with C<#> are comments
|
||||
and are ignored as well. Furthermore, arguments can be spread across
|
||||
multiple lines, by adding a C<\> (continuation character) at the of
|
||||
a line, for example
|
||||
|
||||
edit /some/file:\
|
||||
s/^OPT=.*/OPT=ok/
|
||||
|
||||
The commands are handled in the same order as they are in the file,
|
||||
as if they were specified as I<--delete /some/file> on the command
|
||||
line.
|
||||
|
||||
=item B<--copy> SOURCE:DEST
|
||||
|
||||
Copy files or directories recursively inside the guest.
|
||||
|
||||
Wildcards cannot be used.
|
||||
|
||||
=item B<--copy-in> LOCALPATH:REMOTEDIR
|
||||
|
||||
Copy local files or directories recursively into the disk image,
|
||||
placing them in the directory C<REMOTEDIR> (which must exist).
|
||||
|
||||
Wildcards cannot be used.
|
||||
|
||||
=item B<--delete> PATH
|
||||
|
||||
Delete a file from the guest. Or delete a directory (and all its
|
||||
contents, recursively).
|
||||
|
||||
You can use shell glob characters in the specified path. Be careful
|
||||
to escape glob characters from the host shell, if that is required.
|
||||
For example:
|
||||
|
||||
virt-customize --delete '/var/log/*.log'.
|
||||
|
||||
See also: I<--upload>, I<--scrub>.
|
||||
|
||||
=item B<--edit> FILE:EXPR
|
||||
|
||||
Edit C<FILE> using the Perl expression C<EXPR>.
|
||||
|
||||
Be careful to properly quote the expression to prevent it from
|
||||
being altered by the shell.
|
||||
|
||||
Note that this option is only available when Perl 5 is installed.
|
||||
|
||||
See L<virt-edit(1)/NON-INTERACTIVE EDITING>.
|
||||
|
||||
=item B<--firstboot> SCRIPT
|
||||
|
||||
Install C<SCRIPT> inside the guest, so that when the guest first boots
|
||||
up, the script runs (as root, late in the boot process).
|
||||
|
||||
The script is automatically chmod +x after installation in the guest.
|
||||
|
||||
The alternative version I<--firstboot-command> is the same, but it
|
||||
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<virt-builder(1)/FIRST BOOT SCRIPTS> for more
|
||||
information and caveats about the first boot scripts.
|
||||
|
||||
See also I<--run>.
|
||||
|
||||
=item B<--firstboot-command> 'CMD+ARGS'
|
||||
|
||||
Run command (and arguments) inside the guest when the guest first
|
||||
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<virt-builder(1)/FIRST BOOT SCRIPTS> for more
|
||||
information and caveats about the first boot scripts.
|
||||
|
||||
See also I<--run>.
|
||||
|
||||
=item B<--firstboot-install> PKG,PKG..
|
||||
|
||||
Install the named packages (a comma-separated list). These are
|
||||
installed when the guest first boots using the guest’s package manager
|
||||
(eg. apt, yum, etc.) and the guest’s network connection.
|
||||
|
||||
For an overview on the different ways to install packages, see
|
||||
L<virt-builder(1)/INSTALLING PACKAGES>.
|
||||
|
||||
=item B<--hostname> HOSTNAME
|
||||
|
||||
Set the hostname of the guest to C<HOSTNAME>. You can use a
|
||||
dotted hostname.domainname (FQDN) if you want.
|
||||
|
||||
=item B<--inject-blnsvr> METHOD
|
||||
|
||||
Inject the Balloon Server (F<blnsvr.exe>) into a Windows guest.
|
||||
This operation also injects a firstboot script so that the Balloon
|
||||
Server is installed when the guest boots.
|
||||
|
||||
The parameter is the same as used by the I<--inject-virtio-win> operation.
|
||||
|
||||
Note that to do a full conversion of a Windows guest from a
|
||||
foreign hypervisor like VMware (which involves many other operations)
|
||||
you should use the L<virt-v2v(1)> tool instead of this.
|
||||
|
||||
=item B<--inject-qemu-ga> METHOD
|
||||
|
||||
Inject the QEMU Guest Agent into a Windows guest. The guest
|
||||
agent communicates with qemu through a socket in order to
|
||||
provide enhanced features (see L<qemu-ga(8)>). This operation
|
||||
also injects a firstboot script so that the Guest Agent is
|
||||
installed when the guest boots.
|
||||
|
||||
The parameter is the same as used by the I<--inject-virtio-win> operation.
|
||||
|
||||
Note that to do a full conversion of a Windows guest from a
|
||||
foreign hypervisor like VMware (which involves many other operations)
|
||||
you should use the L<virt-v2v(1)> tool instead of this.
|
||||
|
||||
=item B<--inject-virtio-win> METHOD
|
||||
|
||||
Inject virtio-win drivers into a Windows guest. These drivers
|
||||
add virtio accelerated drivers suitable when running on top of
|
||||
a hypervisor that supports virtio (such as qemu/KVM). The
|
||||
operation also adjusts the Windows Registry so that the drivers
|
||||
are installed when the guest boots.
|
||||
|
||||
The parameter can be one of:
|
||||
|
||||
=over 4
|
||||
|
||||
=item ISO
|
||||
|
||||
The path to the ISO image containing the virtio-win drivers
|
||||
(eg. F</usr/share/virtio-win/virtio-win.iso>).
|
||||
|
||||
=item DIR
|
||||
|
||||
The directory containing the unpacked virtio-win drivers
|
||||
(eg. F</usr/share/virtio-win>).
|
||||
|
||||
=item B<"osinfo">
|
||||
|
||||
The literal string C<"osinfo"> means to use the
|
||||
libosinfo database to locate the drivers. (See
|
||||
L<osinfo-query(1)>.
|
||||
|
||||
=back
|
||||
|
||||
Note that to do a full conversion of a Windows guest from a
|
||||
foreign hypervisor like VMware (which involves many other operations)
|
||||
you should use the L<virt-v2v(1)> tool instead of this.
|
||||
|
||||
=item B<--install> PKG,PKG..
|
||||
|
||||
Install the named packages (a comma-separated list). These are
|
||||
installed during the image build using the guest’s package manager
|
||||
(eg. apt, yum, etc.) and the host’s network connection.
|
||||
|
||||
For an overview on the different ways to install packages, see
|
||||
L<virt-builder(1)/INSTALLING PACKAGES>.
|
||||
|
||||
See also I<--update>, I<--uninstall>.
|
||||
|
||||
=item B<--link> TARGET:LINK[:LINK..]
|
||||
|
||||
Create symbolic link(s) in the guest, starting at C<LINK> and
|
||||
pointing at C<TARGET>.
|
||||
|
||||
=item B<--mkdir> DIR
|
||||
|
||||
Create a directory in the guest.
|
||||
|
||||
This uses S<C<mkdir -p>> so any intermediate directories are created,
|
||||
and it also works if the directory already exists.
|
||||
|
||||
=item B<--move> SOURCE:DEST
|
||||
|
||||
Move files or directories inside the guest.
|
||||
|
||||
Wildcards cannot be used.
|
||||
|
||||
=item B<--no-logfile>
|
||||
|
||||
Scrub C<builder.log> (log file from build commands) from the image
|
||||
after building is complete. If you don't want to reveal precisely how
|
||||
the image was built, use this option.
|
||||
|
||||
See also: L</LOG FILE>.
|
||||
|
||||
=item B<--no-selinux-relabel>
|
||||
|
||||
Do not attempt to correct the SELinux labels of files in the guest.
|
||||
|
||||
In such guests that support SELinux, customization automatically
|
||||
relabels files so that they have the correct SELinux label. (The
|
||||
relabeling is performed immediately, but if the operation fails,
|
||||
customization will instead touch F</.autorelabel> on the image to
|
||||
schedule a relabel operation for the next time the image boots.) This
|
||||
option disables the automatic relabeling.
|
||||
|
||||
The option is a no-op for guests that do not support SELinux.
|
||||
|
||||
=item B<--password> USER:SELECTOR
|
||||
|
||||
Set the password for C<USER>. (Note this option does I<not>
|
||||
create the user account).
|
||||
|
||||
See L<virt-builder(1)/USERS AND PASSWORDS> for the format of
|
||||
the C<SELECTOR> field, and also how to set up user accounts.
|
||||
|
||||
=item B<--password-crypto> md5|sha256|sha512
|
||||
|
||||
When the virt tools change or set a password in the guest, this
|
||||
option sets the password encryption of that password to
|
||||
C<md5>, C<sha256> or C<sha512>.
|
||||
|
||||
C<sha256> and C<sha512> require glibc E<ge> 2.7 (check crypt(3) inside
|
||||
the guest).
|
||||
|
||||
C<md5> will work with relatively old Linux guests (eg. RHEL 3), but
|
||||
is not secure against modern attacks.
|
||||
|
||||
The default is C<sha512> unless libguestfs detects an old guest that
|
||||
didn't have support for SHA-512, in which case it will use C<md5>.
|
||||
You can override libguestfs by specifying this option.
|
||||
|
||||
Note this does not change the default password encryption used
|
||||
by the guest when you create new user accounts inside the guest.
|
||||
If you want to do that, then you should use the I<--edit> option
|
||||
to modify C</etc/sysconfig/authconfig> (Fedora, RHEL) or
|
||||
C</etc/pam.d/common-password> (Debian, Ubuntu).
|
||||
|
||||
=item B<--root-password> SELECTOR
|
||||
|
||||
Set the root password.
|
||||
|
||||
See L<virt-builder(1)/USERS AND PASSWORDS> for the format of
|
||||
the C<SELECTOR> field, and also how to set up user accounts.
|
||||
|
||||
Note: In virt-builder, if you I<don't> set I<--root-password>
|
||||
then the guest is given a I<random> root password.
|
||||
|
||||
=item B<--run> SCRIPT
|
||||
|
||||
Run the shell script (or any program) called C<SCRIPT> on the disk
|
||||
image. The script runs virtualized inside a small appliance, chrooted
|
||||
into the guest filesystem.
|
||||
|
||||
The script is automatically chmod +x.
|
||||
|
||||
If libguestfs supports it then a limited network connection is
|
||||
available but it only allows outgoing network connections. You can
|
||||
also attach data disks (eg. ISO files) as another way to provide data
|
||||
(eg. software packages) to the script without needing a network
|
||||
connection (I<--attach>). You can also upload data files (I<--upload>).
|
||||
|
||||
You can have multiple I<--run> options. They run
|
||||
in the same order that they appear on the command line.
|
||||
|
||||
See also: I<--firstboot>, I<--attach>, I<--upload>.
|
||||
|
||||
=item B<--run-command> 'CMD+ARGS'
|
||||
|
||||
Run the command and arguments on the disk image. The command runs
|
||||
virtualized inside a small appliance, chrooted into the guest filesystem.
|
||||
|
||||
If libguestfs supports it then a limited network connection is
|
||||
available but it only allows outgoing network connections. You can
|
||||
also attach data disks (eg. ISO files) as another way to provide data
|
||||
(eg. software packages) to the script without needing a network
|
||||
connection (I<--attach>). You can also upload data files (I<--upload>).
|
||||
|
||||
You can have multiple I<--run-command> options. They run
|
||||
in the same order that they appear on the command line.
|
||||
|
||||
See also: I<--firstboot>, I<--attach>, I<--upload>.
|
||||
|
||||
=item B<--scrub> FILE
|
||||
|
||||
Scrub a file from the guest. This is like I<--delete> except that:
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
It scrubs the data so a guest could not recover it.
|
||||
|
||||
=item *
|
||||
|
||||
It cannot delete directories, only regular files.
|
||||
|
||||
=back
|
||||
|
||||
=item B<--selinux-relabel>
|
||||
|
||||
This is a compatibility option that does nothing.
|
||||
|
||||
=item B<--sm-attach> SELECTOR
|
||||
|
||||
Attach to a pool using C<subscription-manager>.
|
||||
|
||||
See L<virt-builder(1)/SUBSCRIPTION-MANAGER> for the format of
|
||||
the C<SELECTOR> field.
|
||||
|
||||
=item B<--sm-credentials> SELECTOR
|
||||
|
||||
Set the credentials for C<subscription-manager>.
|
||||
|
||||
See L<virt-builder(1)/SUBSCRIPTION-MANAGER> for the format of
|
||||
the C<SELECTOR> field.
|
||||
|
||||
=item B<--sm-register>
|
||||
|
||||
Register the guest using C<subscription-manager>.
|
||||
|
||||
This requires credentials being set using I<--sm-credentials>.
|
||||
|
||||
=item B<--sm-remove>
|
||||
|
||||
Remove all the subscriptions from the guest using
|
||||
C<subscription-manager>.
|
||||
|
||||
=item B<--sm-unregister>
|
||||
|
||||
Unregister the guest using C<subscription-manager>.
|
||||
|
||||
=item B<--ssh-inject> USER[:SELECTOR]
|
||||
|
||||
Inject an ssh key so the given C<USER> will be able to log in over
|
||||
ssh without supplying a password. The C<USER> must exist already
|
||||
in the guest.
|
||||
|
||||
See L<virt-builder(1)/SSH KEYS> for the format of
|
||||
the C<SELECTOR> field.
|
||||
|
||||
You can have multiple I<--ssh-inject> options, for different users
|
||||
and also for more keys for each user.
|
||||
|
||||
=item B<--tar-in> TARFILE:REMOTEDIR
|
||||
|
||||
Copy local files or directories from a local tar file
|
||||
called C<TARFILE> into the disk image, placing them in the
|
||||
directory C<REMOTEDIR> (which must exist). Note that
|
||||
the tar file must be uncompressed (F<.tar.gz> files will not work
|
||||
here)
|
||||
|
||||
=item B<--timezone> TIMEZONE
|
||||
|
||||
Set the default timezone of the guest to C<TIMEZONE>. Use a location
|
||||
string like C<Europe/London>
|
||||
|
||||
=item B<--touch> FILE
|
||||
|
||||
This command performs a L<touch(1)>-like operation on C<FILE>.
|
||||
|
||||
=item B<--truncate> FILE
|
||||
|
||||
This command truncates C<FILE> to a zero-length file. The file must exist
|
||||
already.
|
||||
|
||||
=item B<--truncate-recursive> PATH
|
||||
|
||||
This command recursively truncates all files under C<PATH> to zero-length.
|
||||
|
||||
=item B<--uninstall> PKG,PKG..
|
||||
|
||||
Uninstall the named packages (a comma-separated list). These are
|
||||
removed during the image build using the guest’s package manager
|
||||
(eg. apt, yum, etc.). Dependent packages may also need to be
|
||||
uninstalled to satisfy the request.
|
||||
|
||||
See also I<--install>, I<--update>.
|
||||
|
||||
=item B<--update>
|
||||
|
||||
Do the equivalent of C<yum update>, C<apt-get upgrade>, or whatever
|
||||
command is required to update the packages already installed in the
|
||||
template to their latest versions.
|
||||
|
||||
See also I<--install>, I<--uninstall>.
|
||||
|
||||
=item B<--upload> FILE:DEST
|
||||
|
||||
Upload local file C<FILE> to destination C<DEST> in the disk image.
|
||||
File owner and permissions from the original are preserved, so you
|
||||
should set them to what you want them to be in the disk image.
|
||||
|
||||
C<DEST> could be the final filename. This can be used to rename
|
||||
the file on upload.
|
||||
|
||||
If C<DEST> is a directory name (which must already exist in the guest)
|
||||
then the file is uploaded into that directory, and it keeps the same
|
||||
name as on the local filesystem.
|
||||
|
||||
See also: I<--mkdir>, I<--delete>, I<--scrub>.
|
||||
|
||||
=item B<--write> FILE:CONTENT
|
||||
|
||||
Write C<CONTENT> to C<FILE>.
|
||||
|
||||
=back
|
||||
|
18
virt/common/mlcustomize/customize-synopsis.pod
Normal file
18
virt/common/mlcustomize/customize-synopsis.pod
Normal file
@ -0,0 +1,18 @@
|
||||
[--append-line FILE:LINE] [--chmod PERMISSIONS:FILE]
|
||||
[--chown UID:GID:PATH] [--commands-from-file FILENAME]
|
||||
[--copy SOURCE:DEST] [--copy-in LOCALPATH:REMOTEDIR]
|
||||
[--delete PATH] [--edit FILE:EXPR] [--firstboot SCRIPT]
|
||||
[--firstboot-command 'CMD+ARGS'] [--firstboot-install PKG,PKG..]
|
||||
[--hostname HOSTNAME] [--inject-blnsvr METHOD]
|
||||
[--inject-qemu-ga METHOD] [--inject-virtio-win METHOD]
|
||||
[--install PKG,PKG..] [--link TARGET:LINK[:LINK..]] [--mkdir DIR]
|
||||
[--move SOURCE:DEST] [--password USER:SELECTOR]
|
||||
[--root-password SELECTOR] [--run SCRIPT]
|
||||
[--run-command 'CMD+ARGS'] [--scrub FILE] [--sm-attach SELECTOR]
|
||||
[--sm-register] [--sm-remove] [--sm-unregister]
|
||||
[--ssh-inject USER[:SELECTOR]] [--tar-in TARFILE:REMOTEDIR]
|
||||
[--timezone TIMEZONE] [--touch FILE] [--truncate FILE]
|
||||
[--truncate-recursive PATH] [--uninstall PKG,PKG..] [--update]
|
||||
[--upload FILE:DEST] [--write FILE:CONTENT] [--no-logfile]
|
||||
[--password-crypto md5|sha256|sha512] [--no-selinux-relabel]
|
||||
[--selinux-relabel] [--sm-credentials SELECTOR]
|
589
virt/common/mlcustomize/customize_cmdline.ml
Normal file
589
virt/common/mlcustomize/customize_cmdline.ml
Normal file
@ -0,0 +1,589 @@
|
||||
(* libguestfs generated file
|
||||
* WARNING: THIS FILE IS GENERATED FROM THE FOLLOWING FILES:
|
||||
* generator/customize.ml
|
||||
* and from the code in the generator/ subdirectory.
|
||||
* ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.
|
||||
*
|
||||
* Copyright (C) 2009-2023 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.
|
||||
*)
|
||||
|
||||
(* Command line argument parsing, both for the virt-customize binary
|
||||
* and for the other tools that share the same code.
|
||||
*)
|
||||
|
||||
open Printf
|
||||
|
||||
open Std_utils
|
||||
open Tools_utils
|
||||
open Common_gettext.Gettext
|
||||
open Getopt.OptionName
|
||||
|
||||
type ops = {
|
||||
ops : op list;
|
||||
flags : flags;
|
||||
}
|
||||
and op = [
|
||||
| `AppendLine of string * string
|
||||
(* --append-line FILE:LINE *)
|
||||
| `Chmod of string * string
|
||||
(* --chmod PERMISSIONS:FILE *)
|
||||
| `Chown of string * string * string
|
||||
(* --chown UID:GID:PATH *)
|
||||
| `CommandsFromFile of string
|
||||
(* --commands-from-file FILENAME *)
|
||||
| `Copy of string * string
|
||||
(* --copy SOURCE:DEST *)
|
||||
| `CopyIn of string * string
|
||||
(* --copy-in LOCALPATH:REMOTEDIR *)
|
||||
| `Delete of string
|
||||
(* --delete PATH *)
|
||||
| `Edit of string * string
|
||||
(* --edit FILE:EXPR *)
|
||||
| `FirstbootScript of string
|
||||
(* --firstboot SCRIPT *)
|
||||
| `FirstbootCommand of string
|
||||
(* --firstboot-command 'CMD+ARGS' *)
|
||||
| `FirstbootPackages of string list
|
||||
(* --firstboot-install PKG,PKG.. *)
|
||||
| `Hostname of string
|
||||
(* --hostname HOSTNAME *)
|
||||
| `InjectBalloonServer of string
|
||||
(* --inject-blnsvr METHOD *)
|
||||
| `InjectQemuGA of string
|
||||
(* --inject-qemu-ga METHOD *)
|
||||
| `InjectVirtioWin of string
|
||||
(* --inject-virtio-win METHOD *)
|
||||
| `InstallPackages of string list
|
||||
(* --install PKG,PKG.. *)
|
||||
| `Link of string * string list
|
||||
(* --link TARGET:LINK[:LINK..] *)
|
||||
| `Mkdir of string
|
||||
(* --mkdir DIR *)
|
||||
| `Move of string * string
|
||||
(* --move SOURCE:DEST *)
|
||||
| `Password of string * Password.password_selector
|
||||
(* --password USER:SELECTOR *)
|
||||
| `RootPassword of Password.password_selector
|
||||
(* --root-password SELECTOR *)
|
||||
| `Script of string
|
||||
(* --run SCRIPT *)
|
||||
| `Command of string
|
||||
(* --run-command 'CMD+ARGS' *)
|
||||
| `Scrub of string
|
||||
(* --scrub FILE *)
|
||||
| `SMAttach of Subscription_manager.sm_pool
|
||||
(* --sm-attach SELECTOR *)
|
||||
| `SMRegister
|
||||
(* --sm-register *)
|
||||
| `SMRemove
|
||||
(* --sm-remove *)
|
||||
| `SMUnregister
|
||||
(* --sm-unregister *)
|
||||
| `SSHInject of string * Ssh_key.ssh_key_selector
|
||||
(* --ssh-inject USER[:SELECTOR] *)
|
||||
| `TarIn of string * string
|
||||
(* --tar-in TARFILE:REMOTEDIR *)
|
||||
| `Timezone of string
|
||||
(* --timezone TIMEZONE *)
|
||||
| `Touch of string
|
||||
(* --touch FILE *)
|
||||
| `Truncate of string
|
||||
(* --truncate FILE *)
|
||||
| `TruncateRecursive of string
|
||||
(* --truncate-recursive PATH *)
|
||||
| `UninstallPackages of string list
|
||||
(* --uninstall PKG,PKG.. *)
|
||||
| `Update
|
||||
(* --update *)
|
||||
| `Upload of string * string
|
||||
(* --upload FILE:DEST *)
|
||||
| `Write of string * string
|
||||
(* --write FILE:CONTENT *)
|
||||
]
|
||||
and flags = {
|
||||
scrub_logfile : bool;
|
||||
(* --no-logfile *)
|
||||
password_crypto : Password.password_crypto option;
|
||||
(* --password-crypto md5|sha256|sha512 *)
|
||||
no_selinux_relabel : bool;
|
||||
(* --no-selinux-relabel *)
|
||||
selinux_relabel_ignored : bool;
|
||||
(* --selinux-relabel *)
|
||||
sm_credentials : Subscription_manager.sm_credentials option;
|
||||
(* --sm-credentials SELECTOR *)
|
||||
}
|
||||
|
||||
type argspec = Getopt.keys * Getopt.spec * Getopt.doc
|
||||
|
||||
let rec argspec ?(v2v = false) () =
|
||||
let ops = ref [] in
|
||||
let scrub_logfile = ref false in
|
||||
let password_crypto = ref None in
|
||||
let no_selinux_relabel = ref false in
|
||||
let selinux_relabel_ignored = ref false in
|
||||
let sm_credentials = ref None in
|
||||
|
||||
let rec get_ops () = {
|
||||
ops = List.rev !ops;
|
||||
flags = get_flags ();
|
||||
}
|
||||
and get_flags () = {
|
||||
scrub_logfile = !scrub_logfile;
|
||||
password_crypto = !password_crypto;
|
||||
no_selinux_relabel = !no_selinux_relabel;
|
||||
selinux_relabel_ignored = !selinux_relabel_ignored;
|
||||
sm_credentials = !sm_credentials;
|
||||
}
|
||||
in
|
||||
|
||||
let split_string_pair option_name arg =
|
||||
let i =
|
||||
try String.index arg ':'
|
||||
with Not_found ->
|
||||
error (f_"invalid format for '--%s' parameter, see the man page")
|
||||
option_name in
|
||||
let len = String.length arg in
|
||||
String.sub arg 0 i, String.sub arg (i+1) (len-(i+1))
|
||||
and split_string_triplet option_name arg =
|
||||
match String.nsplit ~max:3 ":" arg with
|
||||
| [a; b; c] -> a, b, c
|
||||
| _ ->
|
||||
error (f_"invalid format for '--%s' parameter, see the man page")
|
||||
option_name
|
||||
and split_string_list arg =
|
||||
String.nsplit "," arg
|
||||
in
|
||||
let split_links_list option_name arg =
|
||||
match String.nsplit ":" arg with
|
||||
| [] | [_] ->
|
||||
error (f_"invalid format for '--%s' parameter, see the man page")
|
||||
option_name
|
||||
| target :: lns -> target, lns
|
||||
in
|
||||
|
||||
let rec argspec = [
|
||||
(
|
||||
[ L"append-line" ],
|
||||
Getopt.String (
|
||||
s_"FILE:LINE",
|
||||
fun s ->
|
||||
let p = split_string_pair "append-line" s in
|
||||
List.push_front (`AppendLine p) ops
|
||||
),
|
||||
s_"Append line(s) to the file"
|
||||
),
|
||||
Some "FILE:LINE", "Append a single line of text to the C<FILE>. If the file does not already\nend with a newline, then one is added before the appended\nline. Also a newline is added to the end of the C<LINE> string\nautomatically.\n\nFor example (assuming ordinary shell quoting) this command:\n\n --append-line '/etc/hosts:10.0.0.1 foo'\n\nwill add either C<10.0.0.1 foo\226\143\142> or C<\226\143\14210.0.0.1 foo\226\143\142> to\nthe file, the latter only if the existing file does not\nalready end with a newline.\n\nC<\226\143\142> represents a newline character, which is guessed by\nlooking at the existing content of the file, so this command\ndoes the right thing for files using Unix or Windows line endings.\nIt also works for empty or non-existent files.\n\nTo insert several lines, use the same option several times:\n\n --append-line '/etc/hosts:10.0.0.1 foo'\n --append-line '/etc/hosts:10.0.0.2 bar'\n\nTo insert a blank line before the appended line, do:\n\n --append-line '/etc/hosts:'\n --append-line '/etc/hosts:10.0.0.1 foo'", false;
|
||||
(
|
||||
[ L"chmod" ],
|
||||
Getopt.String (
|
||||
s_"PERMISSIONS:FILE",
|
||||
fun s ->
|
||||
let p = split_string_pair "chmod" s in
|
||||
List.push_front (`Chmod p) ops
|
||||
),
|
||||
s_"Change the permissions of a file"
|
||||
),
|
||||
Some "PERMISSIONS:FILE", "Change the permissions of C<FILE> to C<PERMISSIONS>.\n\nI<Note>: C<PERMISSIONS> by default would be decimal, unless you prefix\nit with C<0> to get octal, ie. use C<0700> not C<700>.", false;
|
||||
(
|
||||
[ L"chown" ],
|
||||
Getopt.String (
|
||||
s_"UID:GID:PATH",
|
||||
fun s ->
|
||||
let p = split_string_triplet "chown" s in
|
||||
List.push_front (`Chown p) ops
|
||||
),
|
||||
s_"Change the owner user and group ID of a file or directory"
|
||||
),
|
||||
Some "UID:GID:PATH", "Change the owner user and group ID of a file or directory in the guest.\nNote:\n\n=over 4\n\n=item *\n\nOnly numeric UIDs and GIDs will work, and these may not be the same\ninside the guest as on the host.\n\n=item *\n\nThis will not work with Windows guests.\n\n=back\n\nFor example:\n\n virt-customize --chown '0:0:/var/log/audit.log'\n\nSee also: I<--upload>.", false;
|
||||
(
|
||||
[ L"commands-from-file" ],
|
||||
Getopt.String (
|
||||
s_"FILENAME",
|
||||
fun s ->
|
||||
customize_read_from_file s;
|
||||
List.push_front (`CommandsFromFile s) ops
|
||||
),
|
||||
s_"Read customize commands from file"
|
||||
),
|
||||
Some "FILENAME", "Read the customize commands from a file, one (and its arguments)\neach line.\n\nEach line contains a single customization command and its arguments,\nfor example:\n\n delete /some/file\n install some-package\n password some-user:password:its-new-password\n\nEmpty lines are ignored, and lines starting with C<#> are comments\nand are ignored as well. Furthermore, arguments can be spread across\nmultiple lines, by adding a C<\\> (continuation character) at the of\na line, for example\n\n edit /some/file:\\\n s/^OPT=.*/OPT=ok/\n\nThe commands are handled in the same order as they are in the file,\nas if they were specified as I<--delete /some/file> on the command\nline.", false;
|
||||
(
|
||||
[ L"copy" ],
|
||||
Getopt.String (
|
||||
s_"SOURCE:DEST",
|
||||
fun s ->
|
||||
let p = split_string_pair "copy" s in
|
||||
List.push_front (`Copy p) ops
|
||||
),
|
||||
s_"Copy files in disk image"
|
||||
),
|
||||
Some "SOURCE:DEST", "Copy files or directories recursively inside the guest.\n\nWildcards cannot be used.", false;
|
||||
(
|
||||
[ L"copy-in" ],
|
||||
Getopt.String (
|
||||
s_"LOCALPATH:REMOTEDIR",
|
||||
fun s ->
|
||||
let p = split_string_pair "copy-in" s in
|
||||
List.push_front (`CopyIn p) ops
|
||||
),
|
||||
s_"Copy local files or directories into image"
|
||||
),
|
||||
Some "LOCALPATH:REMOTEDIR", "Copy local files or directories recursively into the disk image,\nplacing them in the directory C<REMOTEDIR> (which must exist).\n\nWildcards cannot be used.", false;
|
||||
(
|
||||
[ L"delete" ],
|
||||
Getopt.String (s_"PATH", fun s -> List.push_front (`Delete s) ops),
|
||||
s_"Delete a file or directory"
|
||||
),
|
||||
Some "PATH", "Delete a file from the guest. Or delete a directory (and all its\ncontents, recursively).\n\nYou can use shell glob characters in the specified path. Be careful\nto escape glob characters from the host shell, if that is required.\nFor example:\n\n virt-customize --delete '/var/log/*.log'.\n\nSee also: I<--upload>, I<--scrub>.", false;
|
||||
(
|
||||
[ L"edit" ],
|
||||
Getopt.String (
|
||||
s_"FILE:EXPR",
|
||||
fun s ->
|
||||
let p = split_string_pair "edit" s in
|
||||
List.push_front (`Edit p) ops
|
||||
),
|
||||
s_"Edit file using Perl expression"
|
||||
),
|
||||
Some "FILE:EXPR", "Edit C<FILE> using the Perl expression C<EXPR>.\n\nBe careful to properly quote the expression to prevent it from\nbeing altered by the shell.\n\nNote that this option is only available when Perl 5 is installed.\n\nSee L<virt-edit(1)/NON-INTERACTIVE EDITING>.", false;
|
||||
(
|
||||
[ L"firstboot" ],
|
||||
Getopt.String (s_"SCRIPT", fun s -> List.push_front (`FirstbootScript s) ops),
|
||||
s_"Run script at first guest boot"
|
||||
),
|
||||
Some "SCRIPT", "Install C<SCRIPT> inside the guest, so that when the guest first boots\nup, the script runs (as root, late in the boot process).\n\nThe script is automatically chmod +x after installation in the guest.\n\nThe alternative version I<--firstboot-command> is the same, but it\nconveniently wraps the command up in a single line script for you.\n\nYou can have multiple I<--firstboot> options. They run in the same\norder that they appear on the command line.\n\nPlease take a look at L<virt-builder(1)/FIRST BOOT SCRIPTS> for more\ninformation and caveats about the first boot scripts.\n\nSee also I<--run>.", false;
|
||||
(
|
||||
[ L"firstboot-command" ],
|
||||
Getopt.String (s_"'CMD+ARGS'", fun s -> List.push_front (`FirstbootCommand s) ops),
|
||||
s_"Run command at first guest boot"
|
||||
),
|
||||
Some "'CMD+ARGS'", "Run command (and arguments) inside the guest when the guest first\nboots up (as root, late in the boot process).\n\nYou can have multiple I<--firstboot> options. They run in the same\norder that they appear on the command line.\n\nPlease take a look at L<virt-builder(1)/FIRST BOOT SCRIPTS> for more\ninformation and caveats about the first boot scripts.\n\nSee also I<--run>.", false;
|
||||
(
|
||||
[ L"firstboot-install" ],
|
||||
Getopt.String (
|
||||
s_"PKG,PKG..",
|
||||
fun s ->
|
||||
let ss = split_string_list s in
|
||||
List.push_front (`FirstbootPackages ss) ops
|
||||
),
|
||||
s_"Add package(s) to install at first boot"
|
||||
),
|
||||
Some "PKG,PKG..", "Install the named packages (a comma-separated list). These are\ninstalled when the guest first boots using the guest\226\128\153s package manager\n(eg. apt, yum, etc.) and the guest\226\128\153s network connection.\n\nFor an overview on the different ways to install packages, see\nL<virt-builder(1)/INSTALLING PACKAGES>.", false;
|
||||
(
|
||||
[ L"hostname" ],
|
||||
Getopt.String (s_"HOSTNAME", fun s -> List.push_front (`Hostname s) ops),
|
||||
s_"Set the hostname"
|
||||
),
|
||||
Some "HOSTNAME", "Set the hostname of the guest to C<HOSTNAME>. You can use a\ndotted hostname.domainname (FQDN) if you want.", false;
|
||||
(
|
||||
[ L"inject-blnsvr" ],
|
||||
Getopt.String (s_"METHOD", fun s -> List.push_front (`InjectBalloonServer s) ops),
|
||||
s_"Inject the Balloon Server into a Windows guest"
|
||||
),
|
||||
Some "METHOD", "Inject the Balloon Server (F<blnsvr.exe>) into a Windows guest.\nThis operation also injects a firstboot script so that the Balloon\nServer is installed when the guest boots.\n\nThe parameter is the same as used by the I<--inject-virtio-win> operation.\n\nNote that to do a full conversion of a Windows guest from a\nforeign hypervisor like VMware (which involves many other operations)\nyou should use the L<virt-v2v(1)> tool instead of this.", true;
|
||||
(
|
||||
[ L"inject-qemu-ga" ],
|
||||
Getopt.String (s_"METHOD", fun s -> List.push_front (`InjectQemuGA s) ops),
|
||||
s_"Inject the QEMU Guest Agent into a Windows guest"
|
||||
),
|
||||
Some "METHOD", "Inject the QEMU Guest Agent into a Windows guest. The guest\nagent communicates with qemu through a socket in order to\nprovide enhanced features (see L<qemu-ga(8)>). This operation\nalso injects a firstboot script so that the Guest Agent is\ninstalled when the guest boots.\n\nThe parameter is the same as used by the I<--inject-virtio-win> operation.\n\nNote that to do a full conversion of a Windows guest from a\nforeign hypervisor like VMware (which involves many other operations)\nyou should use the L<virt-v2v(1)> tool instead of this.", true;
|
||||
(
|
||||
[ L"inject-virtio-win" ],
|
||||
Getopt.String (s_"METHOD", fun s -> List.push_front (`InjectVirtioWin s) ops),
|
||||
s_"Inject virtio-win drivers into a Windows guest"
|
||||
),
|
||||
Some "METHOD", "Inject virtio-win drivers into a Windows guest. These drivers\nadd virtio accelerated drivers suitable when running on top of\na hypervisor that supports virtio (such as qemu/KVM). The\noperation also adjusts the Windows Registry so that the drivers\nare installed when the guest boots.\n\nThe parameter can be one of:\n\n=over 4\n\n=item ISO\n\nThe path to the ISO image containing the virtio-win drivers\n(eg. F</usr/share/virtio-win/virtio-win.iso>).\n\n=item DIR\n\nThe directory containing the unpacked virtio-win drivers\n(eg. F</usr/share/virtio-win>).\n\n=item B<\"osinfo\">\n\nThe literal string C<\"osinfo\"> means to use the\nlibosinfo database to locate the drivers. (See\nL<osinfo-query(1)>.\n\n=back\n\nNote that to do a full conversion of a Windows guest from a\nforeign hypervisor like VMware (which involves many other operations)\nyou should use the L<virt-v2v(1)> tool instead of this.", true;
|
||||
(
|
||||
[ L"install" ],
|
||||
Getopt.String (
|
||||
s_"PKG,PKG..",
|
||||
fun s ->
|
||||
let ss = split_string_list s in
|
||||
List.push_front (`InstallPackages ss) ops
|
||||
),
|
||||
s_"Add package(s) to install"
|
||||
),
|
||||
Some "PKG,PKG..", "Install the named packages (a comma-separated list). These are\ninstalled during the image build using the guest\226\128\153s package manager\n(eg. apt, yum, etc.) and the host\226\128\153s network connection.\n\nFor an overview on the different ways to install packages, see\nL<virt-builder(1)/INSTALLING PACKAGES>.\n\nSee also I<--update>, I<--uninstall>.", false;
|
||||
(
|
||||
[ L"link" ],
|
||||
Getopt.String (
|
||||
s_"TARGET:LINK[:LINK..]",
|
||||
fun s ->
|
||||
let ss = split_links_list "link" s in
|
||||
List.push_front (`Link ss) ops
|
||||
),
|
||||
s_"Create symbolic links"
|
||||
),
|
||||
Some "TARGET:LINK[:LINK..]", "Create symbolic link(s) in the guest, starting at C<LINK> and\npointing at C<TARGET>.", false;
|
||||
(
|
||||
[ L"mkdir" ],
|
||||
Getopt.String (s_"DIR", fun s -> List.push_front (`Mkdir s) ops),
|
||||
s_"Create a directory"
|
||||
),
|
||||
Some "DIR", "Create a directory in the guest.\n\nThis uses S<C<mkdir -p>> so any intermediate directories are created,\nand it also works if the directory already exists.", false;
|
||||
(
|
||||
[ L"move" ],
|
||||
Getopt.String (
|
||||
s_"SOURCE:DEST",
|
||||
fun s ->
|
||||
let p = split_string_pair "move" s in
|
||||
List.push_front (`Move p) ops
|
||||
),
|
||||
s_"Move files in disk image"
|
||||
),
|
||||
Some "SOURCE:DEST", "Move files or directories inside the guest.\n\nWildcards cannot be used.", false;
|
||||
(
|
||||
[ L"password" ],
|
||||
Getopt.String (
|
||||
s_"USER:SELECTOR",
|
||||
fun s ->
|
||||
let user, sel = split_string_pair "password" s in
|
||||
let sel = Password.parse_selector sel in
|
||||
List.push_front (`Password (user, sel)) ops
|
||||
),
|
||||
s_"Set user password"
|
||||
),
|
||||
Some "USER:SELECTOR", "Set the password for C<USER>. (Note this option does I<not>\ncreate the user account).\n\nSee L<virt-builder(1)/USERS AND PASSWORDS> for the format of\nthe C<SELECTOR> field, and also how to set up user accounts.", false;
|
||||
(
|
||||
[ L"root-password" ],
|
||||
Getopt.String (
|
||||
s_"SELECTOR",
|
||||
fun s ->
|
||||
let sel = Password.parse_selector s in
|
||||
List.push_front (`RootPassword sel) ops
|
||||
),
|
||||
s_"Set root password"
|
||||
),
|
||||
Some "SELECTOR", "Set the root password.\n\nSee L<virt-builder(1)/USERS AND PASSWORDS> for the format of\nthe C<SELECTOR> field, and also how to set up user accounts.\n\nNote: In virt-builder, if you I<don't> set I<--root-password>\nthen the guest is given a I<random> root password.", false;
|
||||
(
|
||||
[ L"run" ],
|
||||
Getopt.String (s_"SCRIPT", fun s -> List.push_front (`Script s) ops),
|
||||
s_"Run script in disk image"
|
||||
),
|
||||
Some "SCRIPT", "Run the shell script (or any program) called C<SCRIPT> on the disk\nimage. The script runs virtualized inside a small appliance, chrooted\ninto the guest filesystem.\n\nThe script is automatically chmod +x.\n\nIf libguestfs supports it then a limited network connection is\navailable but it only allows outgoing network connections. You can\nalso attach data disks (eg. ISO files) as another way to provide data\n(eg. software packages) to the script without needing a network\nconnection (I<--attach>). You can also upload data files (I<--upload>).\n\nYou can have multiple I<--run> options. They run\nin the same order that they appear on the command line.\n\nSee also: I<--firstboot>, I<--attach>, I<--upload>.", false;
|
||||
(
|
||||
[ L"run-command" ],
|
||||
Getopt.String (s_"'CMD+ARGS'", fun s -> List.push_front (`Command s) ops),
|
||||
s_"Run command in disk image"
|
||||
),
|
||||
Some "'CMD+ARGS'", "Run the command and arguments on the disk image. The command runs\nvirtualized inside a small appliance, chrooted into the guest filesystem.\n\nIf libguestfs supports it then a limited network connection is\navailable but it only allows outgoing network connections. You can\nalso attach data disks (eg. ISO files) as another way to provide data\n(eg. software packages) to the script without needing a network\nconnection (I<--attach>). You can also upload data files (I<--upload>).\n\nYou can have multiple I<--run-command> options. They run\nin the same order that they appear on the command line.\n\nSee also: I<--firstboot>, I<--attach>, I<--upload>.", false;
|
||||
(
|
||||
[ L"scrub" ],
|
||||
Getopt.String (s_"FILE", fun s -> List.push_front (`Scrub s) ops),
|
||||
s_"Scrub a file"
|
||||
),
|
||||
Some "FILE", "Scrub a file from the guest. This is like I<--delete> except that:\n\n=over 4\n\n=item *\n\nIt scrubs the data so a guest could not recover it.\n\n=item *\n\nIt cannot delete directories, only regular files.\n\n=back", false;
|
||||
(
|
||||
[ L"sm-attach" ],
|
||||
Getopt.String (
|
||||
s_"SELECTOR",
|
||||
fun s ->
|
||||
let sel = Subscription_manager.parse_pool_selector s in
|
||||
List.push_front (`SMAttach sel) ops
|
||||
),
|
||||
s_"Attach to a subscription-manager pool"
|
||||
),
|
||||
Some "SELECTOR", "Attach to a pool using C<subscription-manager>.\n\nSee L<virt-builder(1)/SUBSCRIPTION-MANAGER> for the format of\nthe C<SELECTOR> field.", false;
|
||||
(
|
||||
[ L"sm-register" ],
|
||||
Getopt.Unit (fun () -> List.push_front `SMRegister ops),
|
||||
s_"Register using subscription-manager"
|
||||
),
|
||||
None, "Register the guest using C<subscription-manager>.\n\nThis requires credentials being set using I<--sm-credentials>.", false;
|
||||
(
|
||||
[ L"sm-remove" ],
|
||||
Getopt.Unit (fun () -> List.push_front `SMRemove ops),
|
||||
s_"Remove all the subscriptions"
|
||||
),
|
||||
None, "Remove all the subscriptions from the guest using\nC<subscription-manager>.", false;
|
||||
(
|
||||
[ L"sm-unregister" ],
|
||||
Getopt.Unit (fun () -> List.push_front `SMUnregister ops),
|
||||
s_"Unregister using subscription-manager"
|
||||
),
|
||||
None, "Unregister the guest using C<subscription-manager>.", false;
|
||||
(
|
||||
[ L"ssh-inject" ],
|
||||
Getopt.String (
|
||||
s_"USER[:SELECTOR]",
|
||||
fun s ->
|
||||
let user, selstr = String.split ":" s in
|
||||
let sel = Ssh_key.parse_selector selstr in
|
||||
List.push_front (`SSHInject (user, sel)) ops
|
||||
),
|
||||
s_"Inject a public key into the guest"
|
||||
),
|
||||
Some "USER[:SELECTOR]", "Inject an ssh key so the given C<USER> will be able to log in over\nssh without supplying a password. The C<USER> must exist already\nin the guest.\n\nSee L<virt-builder(1)/SSH KEYS> for the format of\nthe C<SELECTOR> field.\n\nYou can have multiple I<--ssh-inject> options, for different users\nand also for more keys for each user.", false;
|
||||
(
|
||||
[ L"tar-in" ],
|
||||
Getopt.String (
|
||||
s_"TARFILE:REMOTEDIR",
|
||||
fun s ->
|
||||
let p = split_string_pair "tar-in" s in
|
||||
List.push_front (`TarIn p) ops
|
||||
),
|
||||
s_"Copy local files or directories from a tarball into image"
|
||||
),
|
||||
Some "TARFILE:REMOTEDIR", "Copy local files or directories from a local tar file\ncalled C<TARFILE> into the disk image, placing them in the\ndirectory C<REMOTEDIR> (which must exist). Note that\nthe tar file must be uncompressed (F<.tar.gz> files will not work\nhere)", false;
|
||||
(
|
||||
[ L"timezone" ],
|
||||
Getopt.String (s_"TIMEZONE", fun s -> List.push_front (`Timezone s) ops),
|
||||
s_"Set the default timezone"
|
||||
),
|
||||
Some "TIMEZONE", "Set the default timezone of the guest to C<TIMEZONE>. Use a location\nstring like C<Europe/London>", false;
|
||||
(
|
||||
[ L"touch" ],
|
||||
Getopt.String (s_"FILE", fun s -> List.push_front (`Touch s) ops),
|
||||
s_"Run touch on a file"
|
||||
),
|
||||
Some "FILE", "This command performs a L<touch(1)>-like operation on C<FILE>.", false;
|
||||
(
|
||||
[ L"truncate" ],
|
||||
Getopt.String (s_"FILE", fun s -> List.push_front (`Truncate s) ops),
|
||||
s_"Truncate a file to zero size"
|
||||
),
|
||||
Some "FILE", "This command truncates C<FILE> to a zero-length file. The file must exist\nalready.", false;
|
||||
(
|
||||
[ L"truncate-recursive" ],
|
||||
Getopt.String (s_"PATH", fun s -> List.push_front (`TruncateRecursive s) ops),
|
||||
s_"Recursively truncate all files in directory"
|
||||
),
|
||||
Some "PATH", "This command recursively truncates all files under C<PATH> to zero-length.", false;
|
||||
(
|
||||
[ L"uninstall" ],
|
||||
Getopt.String (
|
||||
s_"PKG,PKG..",
|
||||
fun s ->
|
||||
let ss = split_string_list s in
|
||||
List.push_front (`UninstallPackages ss) ops
|
||||
),
|
||||
s_"Uninstall package(s)"
|
||||
),
|
||||
Some "PKG,PKG..", "Uninstall the named packages (a comma-separated list). These are\nremoved during the image build using the guest\226\128\153s package manager\n(eg. apt, yum, etc.). Dependent packages may also need to be\nuninstalled to satisfy the request.\n\nSee also I<--install>, I<--update>.", false;
|
||||
(
|
||||
[ L"update" ],
|
||||
Getopt.Unit (fun () -> List.push_front `Update ops),
|
||||
s_"Update packages"
|
||||
),
|
||||
None, "Do the equivalent of C<yum update>, C<apt-get upgrade>, or whatever\ncommand is required to update the packages already installed in the\ntemplate to their latest versions.\n\nSee also I<--install>, I<--uninstall>.", false;
|
||||
(
|
||||
[ L"upload" ],
|
||||
Getopt.String (
|
||||
s_"FILE:DEST",
|
||||
fun s ->
|
||||
let p = split_string_pair "upload" s in
|
||||
List.push_front (`Upload p) ops
|
||||
),
|
||||
s_"Upload local file to destination"
|
||||
),
|
||||
Some "FILE:DEST", "Upload local file C<FILE> to destination C<DEST> in the disk image.\nFile owner and permissions from the original are preserved, so you\nshould set them to what you want them to be in the disk image.\n\nC<DEST> could be the final filename. This can be used to rename\nthe file on upload.\n\nIf C<DEST> is a directory name (which must already exist in the guest)\nthen the file is uploaded into that directory, and it keeps the same\nname as on the local filesystem.\n\nSee also: I<--mkdir>, I<--delete>, I<--scrub>.", false;
|
||||
(
|
||||
[ L"write" ],
|
||||
Getopt.String (
|
||||
s_"FILE:CONTENT",
|
||||
fun s ->
|
||||
let p = split_string_pair "write" s in
|
||||
List.push_front (`Write p) ops
|
||||
),
|
||||
s_"Write file"
|
||||
),
|
||||
Some "FILE:CONTENT", "Write C<CONTENT> to C<FILE>.", false;
|
||||
(
|
||||
[ L"no-logfile" ],
|
||||
Getopt.Set scrub_logfile,
|
||||
s_"Scrub build log file"
|
||||
),
|
||||
None, "Scrub C<builder.log> (log file from build commands) from the image\nafter building is complete. If you don't want to reveal precisely how\nthe image was built, use this option.\n\nSee also: L</LOG FILE>.", false;
|
||||
(
|
||||
[ L"password-crypto" ],
|
||||
Getopt.String (
|
||||
s_"md5|sha256|sha512",
|
||||
fun s ->
|
||||
password_crypto := Some (Password.password_crypto_of_string s)
|
||||
),
|
||||
s_"Set password crypto"
|
||||
),
|
||||
Some "md5|sha256|sha512", "When the virt tools change or set a password in the guest, this\noption sets the password encryption of that password to\nC<md5>, C<sha256> or C<sha512>.\n\nC<sha256> and C<sha512> require glibc E<ge> 2.7 (check crypt(3) inside\nthe guest).\n\nC<md5> will work with relatively old Linux guests (eg. RHEL 3), but\nis not secure against modern attacks.\n\nThe default is C<sha512> unless libguestfs detects an old guest that\ndidn't have support for SHA-512, in which case it will use C<md5>.\nYou can override libguestfs by specifying this option.\n\nNote this does not change the default password encryption used\nby the guest when you create new user accounts inside the guest.\nIf you want to do that, then you should use the I<--edit> option\nto modify C</etc/sysconfig/authconfig> (Fedora, RHEL) or\nC</etc/pam.d/common-password> (Debian, Ubuntu).", false;
|
||||
(
|
||||
[ L"no-selinux-relabel" ],
|
||||
Getopt.Set no_selinux_relabel,
|
||||
s_"Do not relabel files with correct SELinux labels"
|
||||
),
|
||||
None, "Do not attempt to correct the SELinux labels of files in the guest.\n\nIn such guests that support SELinux, customization automatically\nrelabels files so that they have the correct SELinux label. (The\nrelabeling is performed immediately, but if the operation fails,\ncustomization will instead touch F</.autorelabel> on the image to\nschedule a relabel operation for the next time the image boots.) This\noption disables the automatic relabeling.\n\nThe option is a no-op for guests that do not support SELinux.", false;
|
||||
(
|
||||
[ L"selinux-relabel" ],
|
||||
Getopt.Set selinux_relabel_ignored,
|
||||
s_"Compatibility option doing nothing"
|
||||
),
|
||||
None, "This is a compatibility option that does nothing.", false;
|
||||
(
|
||||
[ L"sm-credentials" ],
|
||||
Getopt.String (
|
||||
s_"SELECTOR",
|
||||
fun s ->
|
||||
sm_credentials := Some (Subscription_manager.parse_credentials_selector s)
|
||||
),
|
||||
s_"Credentials for subscription-manager"
|
||||
),
|
||||
Some "SELECTOR", "Set the credentials for C<subscription-manager>.\n\nSee L<virt-builder(1)/SUBSCRIPTION-MANAGER> for the format of\nthe C<SELECTOR> field.", false;
|
||||
]
|
||||
and customize_read_from_file filename =
|
||||
let forbidden_commands = [
|
||||
"commands-from-file";
|
||||
] 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] <> '#'
|
||||
) lines in
|
||||
let cmds = List.map (fun line -> String.split " " line) lines in
|
||||
(* Check for commands not allowed in files containing commands. *)
|
||||
List.iter (
|
||||
fun (cmd, _) ->
|
||||
if List.mem cmd forbidden_commands then
|
||||
error (f_"command '%s' cannot be used in command files, see the man page")
|
||||
cmd
|
||||
) cmds;
|
||||
List.iter (
|
||||
fun (cmd, arg) ->
|
||||
try
|
||||
let ((_, spec, _), _, _, _) = List.find (
|
||||
fun ((keys, _, _), _, _, _) ->
|
||||
List.mem (L cmd) keys
|
||||
) argspec in
|
||||
(match spec with
|
||||
| Getopt.Unit fn -> fn ()
|
||||
| Getopt.String (_, fn) -> fn arg
|
||||
| Getopt.Set varref -> varref := true
|
||||
| _ -> error "INTERNAL error: spec not handled for %s" cmd
|
||||
)
|
||||
with Not_found ->
|
||||
error (f_"command '%s' not valid, see the man page")
|
||||
cmd
|
||||
) cmds
|
||||
in
|
||||
|
||||
(* If we're in virt-v2v, drop the excluded from virt-v2v args. *)
|
||||
let argspec =
|
||||
List.filter_map (
|
||||
fun (keys, spec, doc, exclude_v2v) ->
|
||||
if v2v && exclude_v2v then None
|
||||
else Some (keys, spec, doc)
|
||||
) argspec in
|
||||
|
||||
argspec, get_ops
|
133
virt/common/mlcustomize/customize_cmdline.mli
Normal file
133
virt/common/mlcustomize/customize_cmdline.mli
Normal file
@ -0,0 +1,133 @@
|
||||
(* libguestfs generated file
|
||||
* WARNING: THIS FILE IS GENERATED FROM THE FOLLOWING FILES:
|
||||
* generator/customize.ml
|
||||
* and from the code in the generator/ subdirectory.
|
||||
* ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.
|
||||
*
|
||||
* Copyright (C) 2009-2023 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.
|
||||
*)
|
||||
|
||||
(** Command line argument parsing, both for the virt-customize binary
|
||||
and for the other tools that share the same code. *)
|
||||
|
||||
type ops = {
|
||||
ops : op list;
|
||||
flags : flags;
|
||||
}
|
||||
and op = [
|
||||
| `AppendLine of string * string
|
||||
(* --append-line FILE:LINE *)
|
||||
| `Chmod of string * string
|
||||
(* --chmod PERMISSIONS:FILE *)
|
||||
| `Chown of string * string * string
|
||||
(* --chown UID:GID:PATH *)
|
||||
| `CommandsFromFile of string
|
||||
(* --commands-from-file FILENAME *)
|
||||
| `Copy of string * string
|
||||
(* --copy SOURCE:DEST *)
|
||||
| `CopyIn of string * string
|
||||
(* --copy-in LOCALPATH:REMOTEDIR *)
|
||||
| `Delete of string
|
||||
(* --delete PATH *)
|
||||
| `Edit of string * string
|
||||
(* --edit FILE:EXPR *)
|
||||
| `FirstbootScript of string
|
||||
(* --firstboot SCRIPT *)
|
||||
| `FirstbootCommand of string
|
||||
(* --firstboot-command 'CMD+ARGS' *)
|
||||
| `FirstbootPackages of string list
|
||||
(* --firstboot-install PKG,PKG.. *)
|
||||
| `Hostname of string
|
||||
(* --hostname HOSTNAME *)
|
||||
| `InjectBalloonServer of string
|
||||
(* --inject-blnsvr METHOD *)
|
||||
| `InjectQemuGA of string
|
||||
(* --inject-qemu-ga METHOD *)
|
||||
| `InjectVirtioWin of string
|
||||
(* --inject-virtio-win METHOD *)
|
||||
| `InstallPackages of string list
|
||||
(* --install PKG,PKG.. *)
|
||||
| `Link of string * string list
|
||||
(* --link TARGET:LINK[:LINK..] *)
|
||||
| `Mkdir of string
|
||||
(* --mkdir DIR *)
|
||||
| `Move of string * string
|
||||
(* --move SOURCE:DEST *)
|
||||
| `Password of string * Password.password_selector
|
||||
(* --password USER:SELECTOR *)
|
||||
| `RootPassword of Password.password_selector
|
||||
(* --root-password SELECTOR *)
|
||||
| `Script of string
|
||||
(* --run SCRIPT *)
|
||||
| `Command of string
|
||||
(* --run-command 'CMD+ARGS' *)
|
||||
| `Scrub of string
|
||||
(* --scrub FILE *)
|
||||
| `SMAttach of Subscription_manager.sm_pool
|
||||
(* --sm-attach SELECTOR *)
|
||||
| `SMRegister
|
||||
(* --sm-register *)
|
||||
| `SMRemove
|
||||
(* --sm-remove *)
|
||||
| `SMUnregister
|
||||
(* --sm-unregister *)
|
||||
| `SSHInject of string * Ssh_key.ssh_key_selector
|
||||
(* --ssh-inject USER[:SELECTOR] *)
|
||||
| `TarIn of string * string
|
||||
(* --tar-in TARFILE:REMOTEDIR *)
|
||||
| `Timezone of string
|
||||
(* --timezone TIMEZONE *)
|
||||
| `Touch of string
|
||||
(* --touch FILE *)
|
||||
| `Truncate of string
|
||||
(* --truncate FILE *)
|
||||
| `TruncateRecursive of string
|
||||
(* --truncate-recursive PATH *)
|
||||
| `UninstallPackages of string list
|
||||
(* --uninstall PKG,PKG.. *)
|
||||
| `Update
|
||||
(* --update *)
|
||||
| `Upload of string * string
|
||||
(* --upload FILE:DEST *)
|
||||
| `Write of string * string
|
||||
(* --write FILE:CONTENT *)
|
||||
]
|
||||
and flags = {
|
||||
scrub_logfile : bool;
|
||||
(* --no-logfile *)
|
||||
password_crypto : Password.password_crypto option;
|
||||
(* --password-crypto md5|sha256|sha512 *)
|
||||
no_selinux_relabel : bool;
|
||||
(* --no-selinux-relabel *)
|
||||
selinux_relabel_ignored : bool;
|
||||
(* --selinux-relabel *)
|
||||
sm_credentials : Subscription_manager.sm_credentials option;
|
||||
(* --sm-credentials SELECTOR *)
|
||||
}
|
||||
|
||||
type argspec = Getopt.keys * Getopt.spec * Getopt.doc
|
||||
val argspec : ?v2v:bool -> unit -> (argspec * string option * string) list * (unit -> ops)
|
||||
(** This returns a pair [(list, get_ops)].
|
||||
|
||||
[list] is a list of the command line arguments, plus some extra data.
|
||||
|
||||
[get_ops] is a function you can call {i after} command line parsing
|
||||
which will return the actual operations specified by the user on the
|
||||
command line.
|
||||
|
||||
If the parameter [~v2v] is true then this excludes parameters
|
||||
that should be excluded from virt-v2v. *)
|
437
virt/common/mlcustomize/customize_run.ml
Normal file
437
virt/common/mlcustomize/customize_run.ml
Normal file
@ -0,0 +1,437 @@
|
||||
(* virt-customize
|
||||
* 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.
|
||||
*)
|
||||
|
||||
open Unix
|
||||
open Printf
|
||||
|
||||
open Std_utils
|
||||
open Tools_utils
|
||||
open Common_gettext.Gettext
|
||||
|
||||
open Customize_cmdline
|
||||
open Password
|
||||
open Append_line
|
||||
|
||||
module G = Guestfs
|
||||
|
||||
let run (g : G.guestfs) root (ops : ops) =
|
||||
(* Based on the guest type, choose a log file location. *)
|
||||
let logfile =
|
||||
match g#inspect_get_type root with
|
||||
| "windows" | "dos" ->
|
||||
if g#is_dir ~followsymlinks:true "/Temp" then "/Temp/builder.log"
|
||||
else "/builder.log"
|
||||
| _ ->
|
||||
if g#is_dir ~followsymlinks:true "/tmp" then "/tmp/builder.log"
|
||||
else "/builder.log" in
|
||||
|
||||
(* Function to cat the log file, for debugging and error messages. *)
|
||||
let debug_logfile () =
|
||||
try g#download logfile "/dev/stderr"
|
||||
with exn ->
|
||||
warning (f_"log file %s: %s (ignored)") logfile (Printexc.to_string exn) in
|
||||
|
||||
(* Useful wrapper for scripts. *)
|
||||
let do_run ~display ?(warn_failed_no_network = false) cmd =
|
||||
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
|
||||
in
|
||||
|
||||
try
|
||||
run_in_guest_command g root ~logfile ~incompatible_fn cmd
|
||||
with
|
||||
G.Error msg ->
|
||||
debug_logfile ();
|
||||
if warn_failed_no_network && not (g#get_network ()) then (
|
||||
prerr_newline ();
|
||||
warning (f_"the command may have failed because the network is \
|
||||
disabled. Try either removing ‘--no-network’ or \
|
||||
adding ‘--network’ on the command line.");
|
||||
prerr_newline ()
|
||||
);
|
||||
error (f_"%s: command exited with an error") display
|
||||
in
|
||||
|
||||
let guest_pkgs_command f =
|
||||
try f (g#inspect_get_package_management root) with
|
||||
| Guest_packages.Unknown_package_manager msg
|
||||
| Guest_packages.Unimplemented_package_manager msg ->
|
||||
error "%s" msg
|
||||
in
|
||||
|
||||
(* Set the random seed. *)
|
||||
message (f_"Setting a random seed");
|
||||
if not (Random_seed.set_random_seed g root) then
|
||||
warning (f_"random seed could not be set for this type of guest");
|
||||
|
||||
(* Set the systemd machine ID. This must be set before performing
|
||||
* --install/--update since (at least in Fedora) the kernel %post
|
||||
* script requires a machine ID and will fail if it is not set.
|
||||
*)
|
||||
let () =
|
||||
let etc_machine_id = "/etc/machine-id" in
|
||||
let statbuf =
|
||||
try Some (g#lstatns etc_machine_id) with G.Error _ -> None in
|
||||
(match statbuf with
|
||||
| Some { G.st_size = 0L; G.st_mode = mode }
|
||||
when (Int64.logand mode 0o170000_L) = 0o100000_L ->
|
||||
message (f_"Setting the machine ID in %s") etc_machine_id;
|
||||
let id = Urandom.urandom_bytes 16 in
|
||||
let id = String.map_chars (fun c -> sprintf "%02x" (Char.code c)) id in
|
||||
let id = String.concat "" id in
|
||||
let id = id ^ "\n" in
|
||||
g#write etc_machine_id id
|
||||
| _ -> ()
|
||||
) in
|
||||
|
||||
(* Store the passwords and set them all at the end. *)
|
||||
let passwords = Hashtbl.create 13 in
|
||||
let set_password user pw =
|
||||
if Hashtbl.mem passwords user then
|
||||
error (f_"multiple --root-password/--password options set the \
|
||||
password for user ‘%s’ twice") user;
|
||||
Hashtbl.replace passwords user pw
|
||||
in
|
||||
|
||||
(* Helper function to convert --inject-blnsvr/--inject-qemu-ga/
|
||||
* --inject-virtio-win method parameter into a virtio-win handle.
|
||||
*)
|
||||
let get_virtio_win_handle op meth =
|
||||
if g#inspect_get_type root <> "windows" then (
|
||||
warning (f_"%s ignored for non-Windows guest") op;
|
||||
None
|
||||
)
|
||||
else (
|
||||
match meth with
|
||||
| "osinfo" | "libosinfo" ->
|
||||
Some (Inject_virtio_win.from_libosinfo g root)
|
||||
| path ->
|
||||
Some (Inject_virtio_win.from_path g root path)
|
||||
)
|
||||
in
|
||||
|
||||
(* Perform the remaining customizations in command-line order. *)
|
||||
List.iter (
|
||||
function
|
||||
| `AppendLine (path, line) ->
|
||||
(* It's an error if it's not a single line. This is
|
||||
* to prevent incorrect line endings being added to a file.
|
||||
*)
|
||||
if String.contains line '\n' then
|
||||
error (f_"--append-line: line must not contain newline characters. \
|
||||
Use the --append-line option multiple times to add \
|
||||
several lines.");
|
||||
|
||||
message (f_"Appending line to %s") path;
|
||||
append_line g root path line
|
||||
|
||||
| `Chmod (mode, path) ->
|
||||
message (f_"Changing permissions of %s to %s") path mode;
|
||||
(* If the mode string is octal, add the OCaml prefix for octal values
|
||||
* so it is properly converted as octal integer.
|
||||
*)
|
||||
let mode = if String.is_prefix mode "0" then "0o" ^ mode else mode in
|
||||
g#chmod (int_of_string mode) path
|
||||
|
||||
| `Chown (uid, gid, path) ->
|
||||
let uid, gid =
|
||||
try int_of_string uid, int_of_string gid
|
||||
with Failure _ ->
|
||||
error (f_"--chown: could not parse numeric UID:GID from \
|
||||
%s:%s") uid gid in
|
||||
|
||||
message (f_"Changing owner of %s to %d:%d") path uid gid;
|
||||
g#chown uid gid path
|
||||
|
||||
| `Command cmd ->
|
||||
message (f_"Running: %s") cmd;
|
||||
do_run ~display:cmd cmd
|
||||
|
||||
| `CommandsFromFile _ ->
|
||||
(* Nothing to do, the files with customize commands are already
|
||||
* read when their arguments are met. *)
|
||||
()
|
||||
|
||||
| `Copy (src, dest) ->
|
||||
message (f_"Copying (in image): %s to %s") src dest;
|
||||
g#cp_a src dest
|
||||
|
||||
| `CopyIn (localpath, remotedir) ->
|
||||
message (f_"Copying: %s to %s") localpath remotedir;
|
||||
g#copy_in localpath remotedir
|
||||
|
||||
| `Delete path ->
|
||||
message (f_"Deleting: %s") path;
|
||||
Array.iter g#rm_rf (g#glob_expand ~directoryslash:false path)
|
||||
|
||||
| `Edit (path, expr) ->
|
||||
message (f_"Editing: %s") path;
|
||||
|
||||
if not (g#exists path) then
|
||||
error (f_"%s does not exist in the guest") path;
|
||||
|
||||
if not (g#is_file ~followsymlinks:true path) then
|
||||
error (f_"%s is not a regular file in the guest") path;
|
||||
|
||||
Perl_edit.edit_file g#ocaml_handle path expr
|
||||
|
||||
| `FirstbootCommand cmd ->
|
||||
message (f_"Installing firstboot command: %s") cmd;
|
||||
Firstboot.add_firstboot_script g root cmd cmd
|
||||
|
||||
| `FirstbootPackages pkgs ->
|
||||
message (f_"Installing firstboot packages: %s")
|
||||
(String.concat " " pkgs);
|
||||
let cmd = guest_pkgs_command (Guest_packages.install_command pkgs) in
|
||||
let name = String.concat " " ("install" :: pkgs) in
|
||||
Firstboot.add_firstboot_script g root name cmd
|
||||
|
||||
| `FirstbootScript script ->
|
||||
message (f_"Installing firstboot script: %s") script;
|
||||
let cmd = read_whole_file script in
|
||||
Firstboot.add_firstboot_script g root script cmd
|
||||
|
||||
| `Hostname hostname ->
|
||||
message (f_"Setting the hostname: %s") hostname;
|
||||
if not (Hostname.set_hostname g root hostname) then
|
||||
warning (f_"hostname could not be set for this type of guest")
|
||||
|
||||
| `InjectBalloonServer meth ->
|
||||
(match get_virtio_win_handle "--inject-blnsvr" meth with
|
||||
| None -> ()
|
||||
| Some t ->
|
||||
if not (Inject_virtio_win.inject_blnsvr t) then
|
||||
warning (f_"--inject-blnsvr: blnsvr.exe not found in \
|
||||
virtio-win source that you specified")
|
||||
)
|
||||
|
||||
| `InjectQemuGA meth ->
|
||||
(match get_virtio_win_handle "--inject-qemu-ga" meth with
|
||||
| None -> ()
|
||||
| Some t ->
|
||||
if not (Inject_virtio_win.inject_qemu_ga t) then
|
||||
warning (f_"--inject-qemu-ga: QEMU Guest Agent MSI not found in \
|
||||
virtio-win source that you specified")
|
||||
)
|
||||
|
||||
| `InjectVirtioWin meth ->
|
||||
(match get_virtio_win_handle "--inject-virtio-win" meth with
|
||||
| None -> ()
|
||||
| Some t ->
|
||||
let windows_system_hive = g#inspect_get_windows_system_hive root in
|
||||
Registry.with_hive_write g windows_system_hive (
|
||||
fun reg ->
|
||||
let installed =
|
||||
Inject_virtio_win.inject_virtio_win_drivers t reg in
|
||||
|
||||
(* Warn if we didn't install at least the virtio-blk driver. *)
|
||||
if installed.block_driver <> Inject_virtio_win.Virtio_blk then
|
||||
warning (f_"--inject-virtio-win: virtio drivers were not \
|
||||
found for this Windows version in the \
|
||||
virtio-win source that you specified")
|
||||
)
|
||||
)
|
||||
|
||||
| `InstallPackages pkgs ->
|
||||
message (f_"Installing packages: %s") (String.concat " " pkgs);
|
||||
let cmd = guest_pkgs_command (Guest_packages.install_command pkgs) in
|
||||
do_run ~display:cmd ~warn_failed_no_network:true cmd
|
||||
|
||||
| `Link (target, links) ->
|
||||
List.iter (
|
||||
fun link ->
|
||||
message (f_"Linking: %s -> %s") link target;
|
||||
g#ln_sf target link
|
||||
) links
|
||||
|
||||
| `Mkdir dir ->
|
||||
message (f_"Making directory: %s") dir;
|
||||
g#mkdir_p dir
|
||||
|
||||
| `Move (src, dest) ->
|
||||
message (f_"Moving: %s -> %s") src dest;
|
||||
g#mv src dest
|
||||
|
||||
| `Password (user, pw) ->
|
||||
set_password user pw
|
||||
|
||||
| `RootPassword pw ->
|
||||
set_password "root" pw
|
||||
|
||||
| `Script script ->
|
||||
message (f_"Running: %s") script;
|
||||
let cmd = read_whole_file script in
|
||||
do_run ~display:script cmd
|
||||
|
||||
| `Scrub path ->
|
||||
message (f_"Scrubbing: %s") path;
|
||||
g#scrub_file path
|
||||
|
||||
| `SMAttach pool ->
|
||||
(match pool with
|
||||
| Subscription_manager.PoolAuto ->
|
||||
message (f_"Attaching to compatible subscriptions");
|
||||
let cmd = "subscription-manager attach --auto" in
|
||||
do_run ~display:cmd ~warn_failed_no_network:true cmd
|
||||
| Subscription_manager.PoolId id ->
|
||||
message (f_"Attaching to the pool %s") id;
|
||||
let cmd = sprintf "subscription-manager attach --pool=%s" (quote id) in
|
||||
do_run ~display:cmd ~warn_failed_no_network:true cmd
|
||||
)
|
||||
|
||||
| `SMRegister ->
|
||||
message (f_"Registering with subscription-manager");
|
||||
let creds =
|
||||
match ops.flags.sm_credentials with
|
||||
| None ->
|
||||
error (f_"subscription-manager credentials required for \
|
||||
--sm-register")
|
||||
| Some c -> c in
|
||||
let cmd = sprintf "subscription-manager register \
|
||||
--username=%s --password=%s"
|
||||
(quote creds.Subscription_manager.sm_username)
|
||||
(quote creds.Subscription_manager.sm_password) in
|
||||
do_run ~display:"subscription-manager register"
|
||||
~warn_failed_no_network:true cmd
|
||||
|
||||
| `SMRemove ->
|
||||
message (f_"Removing all the subscriptions");
|
||||
let cmd = "subscription-manager remove --all" in
|
||||
do_run ~display:cmd ~warn_failed_no_network:true cmd
|
||||
|
||||
| `SMUnregister ->
|
||||
message (f_"Unregistering with subscription-manager");
|
||||
let cmd = "subscription-manager unregister" in
|
||||
do_run ~display:cmd ~warn_failed_no_network:true cmd
|
||||
|
||||
| `SSHInject (user, selector) ->
|
||||
if unix_like (g#inspect_get_type root) then (
|
||||
message (f_"SSH key inject: %s") user;
|
||||
Ssh_key.do_ssh_inject_unix g user selector
|
||||
) else
|
||||
warning (f_"SSH key could not be injected for this type of guest")
|
||||
|
||||
| `TarIn (tarfile, remotedir) ->
|
||||
message (f_"Unpack tar file: %s to %s") tarfile remotedir;
|
||||
g#tar_in tarfile remotedir
|
||||
|
||||
| `Truncate path ->
|
||||
message (f_"Truncating: %s") path;
|
||||
g#truncate path
|
||||
|
||||
| `TruncateRecursive path ->
|
||||
message (f_"Recursively truncating: %s") path;
|
||||
truncate_recursive g path
|
||||
|
||||
| `Timezone tz ->
|
||||
message (f_"Setting the timezone: %s") tz;
|
||||
if not (Timezone.set_timezone g root tz) then
|
||||
warning (f_"timezone could not be set for this type of guest")
|
||||
|
||||
| `Touch path ->
|
||||
message (f_"Running touch: %s") path;
|
||||
g#touch path
|
||||
|
||||
| `UninstallPackages pkgs ->
|
||||
message (f_"Uninstalling packages: %s") (String.concat " " pkgs);
|
||||
let cmd = guest_pkgs_command (Guest_packages.uninstall_command pkgs) in
|
||||
do_run ~display:cmd cmd
|
||||
|
||||
| `Update ->
|
||||
message (f_"Updating packages");
|
||||
let cmd = guest_pkgs_command Guest_packages.update_command in
|
||||
do_run ~display:cmd ~warn_failed_no_network:true cmd
|
||||
|
||||
| `Upload (path, dest) ->
|
||||
message (f_"Uploading: %s to %s") path dest;
|
||||
let dest =
|
||||
if g#is_dir ~followsymlinks:true dest then
|
||||
dest ^ "/" ^ Filename.basename path
|
||||
else
|
||||
dest in
|
||||
(* Do the file upload. *)
|
||||
g#upload path dest;
|
||||
|
||||
(* Copy (some of) the permissions from the local file to the
|
||||
* uploaded file.
|
||||
*)
|
||||
let statbuf = stat path in
|
||||
let perms = statbuf.st_perm land 0o7777 (* sticky & set*id *) in
|
||||
g#chmod perms dest;
|
||||
let uid, gid = statbuf.st_uid, statbuf.st_gid in
|
||||
let chown () =
|
||||
try g#chown uid gid dest
|
||||
with G.Error m as e ->
|
||||
if g#last_errno () = G.Errno.errno_EPERM
|
||||
then warning "%s" m
|
||||
else raise e in
|
||||
chown ()
|
||||
|
||||
| `Write (path, content) ->
|
||||
message (f_"Writing: %s") path;
|
||||
g#write path content
|
||||
) ops.ops;
|
||||
|
||||
(* Set all the passwords at the end. *)
|
||||
if Hashtbl.length passwords > 0 then (
|
||||
match g#inspect_get_type root with
|
||||
| "linux" ->
|
||||
message (f_"Setting passwords");
|
||||
let password_crypto = ops.flags.password_crypto in
|
||||
set_linux_passwords ?password_crypto g root passwords
|
||||
|
||||
| _ ->
|
||||
warning (f_"passwords could not be set for this type of guest")
|
||||
);
|
||||
|
||||
if not ops.flags.no_selinux_relabel then (
|
||||
message (f_"SELinux relabelling");
|
||||
SELinux_relabel.relabel g
|
||||
);
|
||||
|
||||
(* Clean up the log file:
|
||||
*
|
||||
* If debugging, dump out the log file.
|
||||
* Then if asked, scrub the log file.
|
||||
*)
|
||||
if verbose () then debug_logfile ();
|
||||
if ops.flags.scrub_logfile && g#exists logfile then (
|
||||
message (f_"Scrubbing the log file");
|
||||
|
||||
(* Try various methods with decreasing complexity. *)
|
||||
try g#scrub_file logfile
|
||||
with _ -> g#rm_f logfile
|
||||
);
|
||||
|
||||
(* Kill any daemons (eg. started by newly installed packages) using
|
||||
* the sysroot.
|
||||
* XXX How to make this nicer?
|
||||
* XXX fuser returns an error if it doesn't kill any processes, which
|
||||
* is not very useful.
|
||||
*)
|
||||
(try ignore (g#debug "sh" [| "fuser"; "-k"; "/sysroot" |])
|
||||
with exn ->
|
||||
if verbose () then
|
||||
warning (f_"%s (ignored)") (Printexc.to_string exn)
|
||||
);
|
||||
g#ping_daemon () (* tiny delay after kill *)
|
26
virt/common/mlcustomize/customize_run.mli
Normal file
26
virt/common/mlcustomize/customize_run.mli
Normal file
@ -0,0 +1,26 @@
|
||||
(* virt-customize
|
||||
* 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.
|
||||
*)
|
||||
|
||||
(* After command line arguments have been parsed, call this function
|
||||
* to perform the operations on a guest handle.
|
||||
*
|
||||
* Note that inspection must have been done on the handle, and
|
||||
* filesystems must be mounted up.
|
||||
*)
|
||||
|
||||
val run : Guestfs.guestfs -> string -> Customize_cmdline.ops -> unit
|
429
virt/common/mlcustomize/firstboot.ml
Normal file
429
virt/common/mlcustomize/firstboot.ml
Normal file
@ -0,0 +1,429 @@
|
||||
(* virt-customize
|
||||
* Copyright (C) 2012-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 Regedit
|
||||
|
||||
let sanitize_name =
|
||||
let rex = PCRE.compile ~caseless:true "[^a-z0-9_]" in
|
||||
fun n ->
|
||||
let n = PCRE.replace ~global:true rex "-" n in
|
||||
let len = String.length n and max = 60 in
|
||||
if len >= max then String.sub n 0 max else n
|
||||
|
||||
(* For Linux guests. *)
|
||||
module Linux = struct
|
||||
let firstboot_dir = "/usr/lib/virt-sysprep"
|
||||
|
||||
let firstboot_sh = sprintf "\
|
||||
#!/bin/sh -
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: virt-sysprep
|
||||
# Required-Start: $null
|
||||
# Should-Start: $all
|
||||
# Required-Stop: $null
|
||||
# Should-Stop: $all
|
||||
# Default-Start: 2 3 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Start scripts to run once at next boot
|
||||
# Description: Start scripts to run once at next boot
|
||||
# These scripts run the first time the guest boots,
|
||||
# and then are deleted. Output or errors from the scripts
|
||||
# are written to ~root/virt-sysprep-firstboot.log.
|
||||
### END INIT INFO
|
||||
|
||||
d=%s/scripts
|
||||
d_done=%s/scripts-done
|
||||
logfile=~root/virt-sysprep-firstboot.log
|
||||
|
||||
echo \"$0\" \"$@\" 2>&1 | tee -a $logfile
|
||||
echo \"Scripts dir: $d\" 2>&1 | tee -a $logfile
|
||||
|
||||
if test \"$1\" = \"start\"
|
||||
then
|
||||
mkdir -p $d_done
|
||||
for f in $d/* ; do
|
||||
if test -x \"$f\"
|
||||
then
|
||||
# move the script to the 'scripts-done' directory, so it is not
|
||||
# executed again at the next boot
|
||||
mv $f $d_done
|
||||
echo '=== Running' $f '===' 2>&1 | tee -a $logfile
|
||||
$d_done/$(basename $f) 2>&1 | tee -a $logfile
|
||||
fi
|
||||
done
|
||||
rm -f $d_done/*
|
||||
fi
|
||||
" firstboot_dir firstboot_dir
|
||||
|
||||
let systemd_target = "multi-user.target"
|
||||
|
||||
let firstboot_service = sprintf "\
|
||||
[Unit]
|
||||
Description=libguestfs firstboot service
|
||||
After=network.target
|
||||
Before=prefdm.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=%s/firstboot.sh start
|
||||
RemainAfterExit=yes
|
||||
StandardOutput=journal+console
|
||||
StandardError=inherit
|
||||
|
||||
[Install]
|
||||
WantedBy=%s
|
||||
" firstboot_dir systemd_target
|
||||
|
||||
let rec install_service (g : Guestfs.guestfs) root distro major =
|
||||
g#mkdir_p firstboot_dir;
|
||||
g#mkdir_p (sprintf "%s/scripts" firstboot_dir);
|
||||
g#write (sprintf "%s/firstboot.sh" firstboot_dir) firstboot_sh;
|
||||
g#chmod 0o755 (sprintf "%s/firstboot.sh" firstboot_dir);
|
||||
|
||||
(* Note we install both systemd and sysvinit services. This is
|
||||
* because init systems can be switched at runtime, and it's easy to
|
||||
* tell if systemd is installed (eg. Ubuntu uses upstart but installs
|
||||
* systemd configuration directories). There is no danger of a
|
||||
* firstboot script running twice because they disable themselves
|
||||
* after running.
|
||||
*)
|
||||
if g#is_dir "/etc/systemd/system" then
|
||||
install_systemd_service g;
|
||||
if g#is_dir "/etc/rc.d" || g#is_dir "/etc/init.d" then
|
||||
install_sysvinit_service g root distro major
|
||||
|
||||
(* Install the systemd firstboot service, if not installed already. *)
|
||||
and install_systemd_service g =
|
||||
(* RHBZ#1250955: systemd will only recognize unit files located
|
||||
* in /usr/lib/systemd/system/
|
||||
*)
|
||||
let unitdir = "/usr/lib/systemd/system" in
|
||||
g#mkdir_p unitdir;
|
||||
let unitfile = sprintf "%s/guestfs-firstboot.service" unitdir in
|
||||
g#write unitfile firstboot_service;
|
||||
g#mkdir_p (sprintf "/etc/systemd/system/%s.wants"
|
||||
systemd_target);
|
||||
g#ln_sf unitfile (sprintf "/etc/systemd/system/%s.wants"
|
||||
systemd_target);
|
||||
|
||||
(* Try to remove the old firstboot.service files. *)
|
||||
let oldunitfile = sprintf "%s/firstboot.service" unitdir in
|
||||
if g#is_file oldunitfile then (
|
||||
g#rm_f "/etc/systemd/system/default.target.wants/firstboot.service";
|
||||
(* Remove the old firstboot.service only if it is one of our
|
||||
* versions. *)
|
||||
match g#checksum "md5" oldunitfile with
|
||||
| "6923781f7a1851b40b32b4960eb9a0fc" (* < 1.23.24 *)
|
||||
| "56fafd8c990fc9d24e5b8497f3582e8d" (* < 1.23.32 *)
|
||||
| "a83767e01cf398e2fd7c8f59d65d320a" (* < 1.25.2 *)
|
||||
| "39aeb10df29104797e3a9aca4db37a6e" ->
|
||||
g#rm oldunitfile
|
||||
| csum ->
|
||||
warning (f_"firstboot: unknown version for old firstboot.service file %s (md5=%s), it will not be removed")
|
||||
oldunitfile csum
|
||||
);
|
||||
(* And the old default.target.wants/guestfs-firstboot.service from
|
||||
* libguestfs <= 1.37.17.
|
||||
*)
|
||||
g#rm_f "/etc/systemd/system/default.target.wants/guestfs-firstboot.service"
|
||||
|
||||
and install_sysvinit_service g root distro major =
|
||||
match distro with
|
||||
| "fedora"|"rhel"|"centos"|"scientificlinux"|"oraclelinux"|"rocky"|
|
||||
"redhat-based" ->
|
||||
install_sysvinit_redhat g
|
||||
| "opensuse"|"sles"|"suse-based" ->
|
||||
install_sysvinit_suse g
|
||||
| ("debian"|"kalilinux") ->
|
||||
install_sysvinit_debian g;
|
||||
if major <= 7 then try_update_rc_d g root
|
||||
| "ubuntu" ->
|
||||
install_sysvinit_debian g
|
||||
| distro ->
|
||||
error (f_"guest type %s is not supported") distro
|
||||
|
||||
and install_sysvinit_redhat g =
|
||||
g#mkdir_p "/etc/rc.d/rc2.d";
|
||||
g#mkdir_p "/etc/rc.d/rc3.d";
|
||||
g#mkdir_p "/etc/rc.d/rc5.d";
|
||||
g#ln_sf (sprintf "%s/firstboot.sh" firstboot_dir)
|
||||
"/etc/rc.d/rc2.d/S99guestfs-firstboot";
|
||||
g#ln_sf (sprintf "%s/firstboot.sh" firstboot_dir)
|
||||
"/etc/rc.d/rc3.d/S99guestfs-firstboot";
|
||||
g#ln_sf (sprintf "%s/firstboot.sh" firstboot_dir)
|
||||
"/etc/rc.d/rc5.d/S99guestfs-firstboot";
|
||||
|
||||
(* Try to remove the files of the old service. *)
|
||||
g#rm_f "/etc/rc.d/rc2.d/S99virt-sysprep-firstboot";
|
||||
g#rm_f "/etc/rc.d/rc3.d/S99virt-sysprep-firstboot";
|
||||
g#rm_f "/etc/rc.d/rc5.d/S99virt-sysprep-firstboot"
|
||||
|
||||
(* Make firstboot.sh look like a runlevel script to avoid insserv warnings. *)
|
||||
and install_sysvinit_suse g =
|
||||
g#mkdir_p "/etc/init.d/rc2.d";
|
||||
g#mkdir_p "/etc/init.d/rc3.d";
|
||||
g#mkdir_p "/etc/init.d/rc5.d";
|
||||
g#ln_sf (sprintf "%s/firstboot.sh" firstboot_dir)
|
||||
"/etc/init.d/guestfs-firstboot";
|
||||
g#ln_sf "../guestfs-firstboot"
|
||||
"/etc/init.d/rc2.d/S99guestfs-firstboot";
|
||||
g#ln_sf "../guestfs-firstboot"
|
||||
"/etc/init.d/rc3.d/S99guestfs-firstboot";
|
||||
g#ln_sf "../guestfs-firstboot"
|
||||
"/etc/init.d/rc5.d/S99guestfs-firstboot";
|
||||
|
||||
(* Try to remove the files of the old service. *)
|
||||
g#rm_f "/etc/init.d/virt-sysprep-firstboot";
|
||||
g#rm_f "/etc/init.d/rc2.d/S99virt-sysprep-firstboot";
|
||||
g#rm_f "/etc/init.d/rc3.d/S99virt-sysprep-firstboot";
|
||||
g#rm_f "/etc/init.d/rc5.d/S99virt-sysprep-firstboot"
|
||||
|
||||
and install_sysvinit_debian g =
|
||||
g#mkdir_p "/etc/init.d";
|
||||
g#mkdir_p "/etc/rc2.d";
|
||||
g#mkdir_p "/etc/rc3.d";
|
||||
g#mkdir_p "/etc/rc5.d";
|
||||
g#ln_sf (sprintf "%s/firstboot.sh" firstboot_dir)
|
||||
"/etc/init.d/guestfs-firstboot";
|
||||
g#ln_sf "../init.d/guestfs-firstboot"
|
||||
"/etc/rc2.d/S99guestfs-firstboot";
|
||||
g#ln_sf "../init.d/guestfs-firstboot"
|
||||
"/etc/rc3.d/S99guestfs-firstboot";
|
||||
g#ln_sf "../init.d/guestfs-firstboot"
|
||||
"/etc/rc5.d/S99guestfs-firstboot";
|
||||
|
||||
(* Try to remove the files of the old service. *)
|
||||
g#rm_f "/etc/init.d/virt-sysprep-firstboot";
|
||||
g#rm_f "/etc/rc2.d/S99virt-sysprep-firstboot";
|
||||
g#rm_f "/etc/rc3.d/S99virt-sysprep-firstboot";
|
||||
g#rm_f "/etc/rc5.d/S99virt-sysprep-firstboot"
|
||||
|
||||
(* On Debian 6 & 7 you have to run: update-rc.d guestfs-firstboot defaults
|
||||
* RHBZ#1019388.
|
||||
*)
|
||||
and try_update_rc_d g root =
|
||||
let guest_arch = g#inspect_get_arch root in
|
||||
let guest_arch_compatible = guest_arch_compatible guest_arch in
|
||||
let cmd = "update-rc.d guestfs-firstboot defaults" in
|
||||
if guest_arch_compatible then
|
||||
try ignore (g#sh cmd)
|
||||
with Guestfs.Error msg ->
|
||||
warning (f_"could not finish firstboot installation by running ‘%s’ because the command failed: %s")
|
||||
cmd msg
|
||||
else (
|
||||
warning (f_"cannot finish firstboot installation by running ‘%s’ because host cpu (%s) and guest arch (%s) are not compatible. The firstboot service may not run at boot.")
|
||||
cmd Guestfs_config.host_cpu guest_arch
|
||||
)
|
||||
end
|
||||
|
||||
module Windows = struct
|
||||
(* Create and return the firstboot directory. *)
|
||||
let create_firstboot_dir (g : Guestfs.guestfs) =
|
||||
let rec loop firstboot_dir firstboot_dir_win = function
|
||||
| [] -> firstboot_dir, firstboot_dir_win
|
||||
| dir :: path ->
|
||||
let firstboot_dir =
|
||||
if firstboot_dir = "" then "/" ^ dir else firstboot_dir // dir in
|
||||
let firstboot_dir_win = firstboot_dir_win ^ "\\" ^ dir in
|
||||
let firstboot_dir = g#case_sensitive_path firstboot_dir in
|
||||
g#mkdir_p firstboot_dir;
|
||||
loop firstboot_dir firstboot_dir_win path
|
||||
in
|
||||
loop "" "C:" ["Program Files"; "Guestfs"; "Firstboot"]
|
||||
|
||||
let rec install_service (g : Guestfs.guestfs) root
|
||||
firstboot_dir firstboot_dir_win =
|
||||
(* Either rhsrvany.exe or pvvxsvc.exe must exist.
|
||||
*
|
||||
* (Check also that it's not a dangling symlink but a real file).
|
||||
*)
|
||||
let services = ["rhsrvany.exe"; "pvvxsvc.exe"] in
|
||||
let srvany =
|
||||
try
|
||||
List.find (
|
||||
fun service -> Sys.file_exists (virt_tools_data_dir () // service)
|
||||
) services
|
||||
with Not_found ->
|
||||
error (f_"One of rhsrvany.exe or pvvxsvc.exe is missing in %s. One of them is required in order to install Windows firstboot scripts. You can get one by building rhsrvany (https://github.com/rwmjones/rhsrvany)")
|
||||
(virt_tools_data_dir ()) in
|
||||
|
||||
(* Create a directory for firstboot scripts in the guest. *)
|
||||
g#mkdir_p (firstboot_dir // "scripts");
|
||||
|
||||
(* Copy pvvxsvc or rhsrvany to the guest. *)
|
||||
g#upload (virt_tools_data_dir () // srvany) (firstboot_dir // srvany);
|
||||
|
||||
(* Write a firstboot.bat control script which just runs the other
|
||||
* scripts in the directory. Note we need to use CRLF line endings
|
||||
* in this script.
|
||||
*
|
||||
* XXX It would be better to use powershell here. For some ideas see
|
||||
* https://github.com/HCK-CI/HLK-Setup-Scripts/
|
||||
*)
|
||||
let firstboot_script = sprintf "\
|
||||
@echo off
|
||||
|
||||
setlocal EnableDelayedExpansion
|
||||
set firstboot=%s
|
||||
set log=%%firstboot%%\\log.txt
|
||||
|
||||
set scripts=%%firstboot%%\\scripts
|
||||
set scripts_done=%%firstboot%%\\scripts-done
|
||||
|
||||
call :main >> \"%%log%%\" 2>&1
|
||||
exit /b
|
||||
|
||||
:main
|
||||
echo starting firstboot service
|
||||
|
||||
if not exist \"%%scripts_done%%\" (
|
||||
mkdir \"%%scripts_done%%\"
|
||||
)
|
||||
|
||||
:: Pick the next script to run.
|
||||
for %%%%f in (\"%%scripts%%\"\\*.bat) do (
|
||||
echo running \"%%%%f\"
|
||||
move \"%%%%f\" \"%%scripts_done%%\"
|
||||
pushd \"%%scripts_done%%\"
|
||||
call \"%%%%~nf\"
|
||||
set elvl=!errorlevel!
|
||||
echo .... exit code !elvl!
|
||||
popd
|
||||
|
||||
:: Reboot the computer. This is necessary to free any locked
|
||||
:: files which may prevent later scripts from running.
|
||||
shutdown /r /t 0 /y
|
||||
|
||||
:: Exit the script (in case shutdown returns before rebooting).
|
||||
:: On next boot, the whole firstboot service will be called again.
|
||||
exit /b
|
||||
)
|
||||
|
||||
:: Fallthrough here if there are no scripts.
|
||||
echo uninstalling firstboot service
|
||||
\"%%firstboot%%\\%s\" -s firstboot uninstall
|
||||
" firstboot_dir_win srvany in
|
||||
|
||||
g#write (firstboot_dir // "firstboot.bat")
|
||||
(String.unix2dos firstboot_script);
|
||||
|
||||
(* Open the SYSTEM hive. *)
|
||||
Registry.with_hive_write g (g#inspect_get_windows_system_hive root)
|
||||
(fun reg ->
|
||||
let current_cs = g#inspect_get_windows_current_control_set root in
|
||||
|
||||
(* Add a new rhsrvany service to the system registry to execute
|
||||
* firstboot. NB: All these edits are in the HKLM\SYSTEM hive.
|
||||
* No other hive may be modified here.
|
||||
*)
|
||||
let regedits = [
|
||||
[ current_cs; "services"; "firstboot" ],
|
||||
[ "Type", REG_DWORD 0x10_l;
|
||||
"Start", REG_DWORD 0x2_l;
|
||||
"ErrorControl", REG_DWORD 0x1_l;
|
||||
"ImagePath",
|
||||
REG_SZ (sprintf "%s\\%s -s firstboot" firstboot_dir_win srvany);
|
||||
"DisplayName", REG_SZ "Virt tools firstboot service";
|
||||
"ObjectName", REG_SZ "LocalSystem" ];
|
||||
|
||||
[ current_cs; "services"; "firstboot"; "Parameters" ],
|
||||
[ "CommandLine",
|
||||
REG_SZ ("cmd /c \"" ^ firstboot_dir_win ^ "\\firstboot.bat\"");
|
||||
"PWD", REG_SZ firstboot_dir_win ];
|
||||
] in
|
||||
reg_import reg regedits
|
||||
)
|
||||
end
|
||||
|
||||
let firstboot_dir (g : Guestfs.guestfs) root =
|
||||
let typ = g#inspect_get_type root in
|
||||
|
||||
match typ with
|
||||
| "linux" ->
|
||||
let dir = Linux.firstboot_dir in
|
||||
g#mkdir_p dir;
|
||||
dir, None
|
||||
|
||||
| "windows" ->
|
||||
let dir, dir_win = Windows.create_firstboot_dir g in
|
||||
dir, Some dir_win
|
||||
|
||||
| _ ->
|
||||
error (f_"guest type %s is not supported") typ
|
||||
|
||||
let script_count = ref 0
|
||||
|
||||
let add_firstboot_script (g : Guestfs.guestfs) root ?(prio = 5000) name
|
||||
content =
|
||||
assert (prio >= 0 && prio <= 9999);
|
||||
let typ = g#inspect_get_type root in
|
||||
let distro = g#inspect_get_distro root in
|
||||
let major = g#inspect_get_major_version root in
|
||||
incr script_count;
|
||||
let filename = sprintf "%04d-%04d-%s" prio !script_count
|
||||
(sanitize_name name) in
|
||||
match typ, distro with
|
||||
| "linux", _ ->
|
||||
Linux.install_service g root distro major;
|
||||
let filename = Linux.firstboot_dir // "scripts" // filename in
|
||||
g#write filename content;
|
||||
g#chmod 0o755 filename
|
||||
|
||||
| "windows", _ ->
|
||||
let firstboot_dir, firstboot_dir_win = Windows.create_firstboot_dir g in
|
||||
Windows.install_service g root firstboot_dir firstboot_dir_win;
|
||||
let filename = firstboot_dir // "scripts" // filename ^ ".bat" in
|
||||
g#write filename (String.unix2dos content)
|
||||
|
||||
| _ ->
|
||||
error (f_"guest type %s/%s is not supported") typ distro
|
||||
|
||||
(* 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 add_firstboot_powershell g root ?prio name code =
|
||||
(* Fail hard if inspection hasn't been done or it's not a Windows
|
||||
* guest. If it happens it indicates an internal error in the
|
||||
* calling code.
|
||||
*)
|
||||
assert (g#inspect_get_type root = "windows");
|
||||
|
||||
(* Place the Powershell script into firstboot_dir/Temp *)
|
||||
let firstboot_dir, firstboot_dir_win = Windows.create_firstboot_dir g in
|
||||
let tempdir = sprintf "%s/Temp" firstboot_dir in
|
||||
g#mkdir_p tempdir;
|
||||
|
||||
let ps_path = sprintf "%s/%s.ps1" tempdir name in
|
||||
let ps_path_win = sprintf "%s\\Temp\\%s.ps1" firstboot_dir_win name in
|
||||
let code = String.concat "\r\n" code ^ "\r\n" in
|
||||
g#write ps_path code;
|
||||
|
||||
(* Create a regular firstboot bat that just invokes powershell *)
|
||||
let fb =
|
||||
sprintf "powershell.exe -ExecutionPolicy ByPass -NoProfile -file \"%s\""
|
||||
ps_path_win in
|
||||
add_firstboot_script g root ?prio name fb
|
70
virt/common/mlcustomize/firstboot.mli
Normal file
70
virt/common/mlcustomize/firstboot.mli
Normal file
@ -0,0 +1,70 @@
|
||||
(* virt-customize
|
||||
* Copyright (C) 2012-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.
|
||||
*)
|
||||
|
||||
val firstboot_dir : Guestfs.guestfs -> string -> string * string option
|
||||
(** [firstboot_dir g root]
|
||||
returns the path of the firstboot directory, creating it in
|
||||
the guest if necessary.
|
||||
|
||||
This returns the name of the directory as a guestfs path, and
|
||||
optionally the name as a Windows path (only for Windows guests).
|
||||
|
||||
For Linux this could be [/usr/lib/virt-sysprep, None]
|
||||
|
||||
For Windows this could be ["/Program Files/Guestfs/Firstboot",
|
||||
Some "C:\Program Files\Guestfs\Firstboot"]
|
||||
|
||||
Additional files that are used during firstboot can be placed
|
||||
in this directory, but be careful not to conflict with files
|
||||
and scripts added by the firstboot process itself. *)
|
||||
|
||||
val add_firstboot_script : Guestfs.guestfs -> string -> ?prio:int -> string ->
|
||||
string -> unit
|
||||
(** [add_firstboot_script g root prio name content] adds a firstboot
|
||||
script called [name] containing [content] with priority [prio].
|
||||
|
||||
[g] is the guestfs handle. The disks must be mounted up and
|
||||
inspection data must be available.
|
||||
|
||||
[content] is the contents of the script, {b not} a filename.
|
||||
|
||||
The script is running using the shell (usually [/bin/sh]) on Linux
|
||||
or as a Windows batch file. To use Windows Powershell, see
|
||||
{!add_firstboot_powershell} instead.
|
||||
|
||||
The actual name of the script on the guest filesystem is made of [name]
|
||||
with all characters but alphanumeric replaced with dashes.
|
||||
|
||||
Within a given priority, the scripts are run in the order they are
|
||||
registered. A group of scripts with a numerically lower priority is run
|
||||
before a group with a numerically greater priority. If [prio] is omitted,
|
||||
it is taken as 5000. If [prio] is smaller than 0 or greater than 9999, an
|
||||
Assert_failure is raised (the [prio] parameter is not expected to depend
|
||||
on user input).
|
||||
|
||||
For Linux guests using SELinux you should make sure the
|
||||
filesystem is relabelled after calling this. *)
|
||||
|
||||
val add_firstboot_powershell : Guestfs.guestfs -> string ->
|
||||
?prio:int -> string -> string list -> unit
|
||||
(** [add_firstboot_powershell] is like {!add_firstboot_script} except
|
||||
that it adds a Windows Powershell script instead of a batch
|
||||
file.
|
||||
|
||||
The parameters are: [g root prio name lines] (where the Powershell
|
||||
script is passed in as lines of code). *)
|
132
virt/common/mlcustomize/guest_packages.ml
Normal file
132
virt/common/mlcustomize/guest_packages.ml
Normal file
@ -0,0 +1,132 @@
|
||||
(* virt-customize
|
||||
* Copyright (C) 2012-2023 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 Common_gettext.Gettext
|
||||
open Std_utils
|
||||
|
||||
exception Unknown_package_manager of string
|
||||
exception Unimplemented_package_manager of string
|
||||
|
||||
(* Windows has package_management == "unknown". *)
|
||||
let error_unknown_package_manager flag =
|
||||
let msg = sprintf (f_"cannot use ‘%s’ because no package manager has been \
|
||||
detected for this guest OS.\n\nIf this guest OS is a \
|
||||
common one with ordinary package management then this \
|
||||
may have been caused by a failure of libguestfs \
|
||||
inspection.\n\nFor OSes such as Windows that lack \
|
||||
package management, this is not possible. Try using \
|
||||
one of the ‘--firstboot*’ flags instead (described in \
|
||||
the virt-customize(1) manual).") flag in
|
||||
raise (Unknown_package_manager msg)
|
||||
|
||||
let error_unimplemented_package_manager flag pm =
|
||||
let msg = sprintf (f_"sorry, ‘%s’ with the ‘%s’ package manager has not \
|
||||
been implemented yet.\n\nYou can work around this by \
|
||||
using one of the ‘--run*’ or ‘--firstboot*’ options \
|
||||
instead (described in the virt-customize(1) manual).")
|
||||
flag pm in
|
||||
raise (Unimplemented_package_manager msg)
|
||||
|
||||
(* http://distrowatch.com/dwres.php?resource=package-management *)
|
||||
let install_command packages package_management =
|
||||
let quoted_args = String.concat " " (List.map quote packages) in
|
||||
match package_management with
|
||||
| "apk" ->
|
||||
sprintf "
|
||||
apk update
|
||||
apk add %s
|
||||
" quoted_args
|
||||
| "apt" ->
|
||||
(* http://unix.stackexchange.com/questions/22820 *)
|
||||
sprintf "
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt_opts='-q -y -o Dpkg::Options::=--force-confnew'
|
||||
apt-get $apt_opts update
|
||||
apt-get $apt_opts install %s
|
||||
" quoted_args
|
||||
| "dnf" ->
|
||||
sprintf "dnf%s -y install %s"
|
||||
(if verbose () then " --verbose" else "")
|
||||
quoted_args
|
||||
| "pisi" -> sprintf "pisi it %s" quoted_args
|
||||
| "pacman" -> sprintf "pacman -S --noconfirm %s" quoted_args
|
||||
| "urpmi" -> sprintf "urpmi %s" quoted_args
|
||||
| "xbps" -> sprintf "xbps-install -Sy %s" quoted_args
|
||||
| "yum" -> sprintf "yum -y install %s" quoted_args
|
||||
| "zypper" -> sprintf "zypper -n in -l %s" quoted_args
|
||||
|
||||
| "unknown" ->
|
||||
error_unknown_package_manager "--install"
|
||||
| pm ->
|
||||
error_unimplemented_package_manager "--install" pm
|
||||
|
||||
let update_command package_management =
|
||||
match package_management with
|
||||
| "apk" ->
|
||||
"
|
||||
apk update
|
||||
apk upgrade
|
||||
"
|
||||
| "apt" ->
|
||||
(* http://unix.stackexchange.com/questions/22820 *)
|
||||
"
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt_opts='-q -y -o Dpkg::Options::=--force-confnew'
|
||||
apt-get $apt_opts update
|
||||
apt-get $apt_opts upgrade
|
||||
"
|
||||
| "dnf" ->
|
||||
sprintf "dnf%s -y --best upgrade"
|
||||
(if verbose () then " --verbose" else "")
|
||||
| "pisi" -> "pisi upgrade"
|
||||
| "pacman" -> "pacman -Su"
|
||||
| "urpmi" -> "urpmi --auto-select"
|
||||
| "xbps" -> "xbps-install -Suy"
|
||||
| "yum" -> "yum -y update"
|
||||
| "zypper" -> "zypper -n dup -l"
|
||||
|
||||
| "unknown" ->
|
||||
error_unknown_package_manager "--update"
|
||||
| pm ->
|
||||
error_unimplemented_package_manager "--update" pm
|
||||
|
||||
let uninstall_command packages package_management =
|
||||
let quoted_args = String.concat " " (List.map quote packages) in
|
||||
match package_management with
|
||||
| "apk" -> sprintf "apk del %s" quoted_args
|
||||
| "apt" ->
|
||||
(* http://unix.stackexchange.com/questions/22820 *)
|
||||
sprintf "
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt_opts='-q -y -o Dpkg::Options::=--force-confnew'
|
||||
apt-get $apt_opts remove %s
|
||||
" quoted_args
|
||||
| "dnf" -> sprintf "dnf -y remove %s" quoted_args
|
||||
| "pisi" -> sprintf "pisi rm %s" quoted_args
|
||||
| "pacman" -> sprintf "pacman -R %s" quoted_args
|
||||
| "urpmi" -> sprintf "urpme %s" quoted_args
|
||||
| "xbps" -> sprintf "xbps-remove -Sy %s" quoted_args
|
||||
| "yum" -> sprintf "yum -y remove %s" quoted_args
|
||||
| "zypper" -> sprintf "zypper -n rm %s" quoted_args
|
||||
|
||||
| "unknown" ->
|
||||
error_unknown_package_manager "--uninstall"
|
||||
| pm ->
|
||||
error_unimplemented_package_manager "--uninstall" pm
|
44
virt/common/mlcustomize/guest_packages.mli
Normal file
44
virt/common/mlcustomize/guest_packages.mli
Normal file
@ -0,0 +1,44 @@
|
||||
(* virt-customize
|
||||
* Copyright (C) 2012-2023 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.
|
||||
*)
|
||||
|
||||
exception Unknown_package_manager of string
|
||||
exception Unimplemented_package_manager of string
|
||||
(** For all three functions below, [package_management] determines the package
|
||||
management system in use by the guest; commonly it should be filled in from
|
||||
[Guestfs.inspect_get_package_management], or the equivalent guestfs object
|
||||
method.
|
||||
|
||||
If [package_management] is unknown or unimplemented, the functions raise
|
||||
[Unknown_package_manager "error message"] or [Unimplemented_package_manager
|
||||
"error message"], correspondingly. *)
|
||||
|
||||
val install_command : string list -> string -> string
|
||||
(** [install_command packages package_management] produces a properly quoted
|
||||
shell command string suitable for execution in the guest (directly or via a
|
||||
Firstboot script) for installing the OS packages listed in [packages]. *)
|
||||
|
||||
val update_command : string -> string
|
||||
(** [update_command package_management] produces a properly quoted shell command
|
||||
string suitable for execution in the guest (directly or via a Firstboot
|
||||
script) for updating the OS packages that are currently installed in the
|
||||
guest. *)
|
||||
|
||||
val uninstall_command : string list -> string -> string
|
||||
(** [uninstall_command packages package_management] produces a properly quoted
|
||||
shell command string suitable for execution in the guest (directly or via a
|
||||
Firstboot script) for uninstalling the OS packages listed in [packages]. *)
|
137
virt/common/mlcustomize/hostname.ml
Normal file
137
virt/common/mlcustomize/hostname.ml
Normal file
@ -0,0 +1,137 @@
|
||||
(* virt-sysprep
|
||||
* Copyright (C) 2012-2023 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 Tools_utils
|
||||
|
||||
open Printf
|
||||
|
||||
let rec set_hostname (g : Guestfs.guestfs) root hostname =
|
||||
let typ = g#inspect_get_type root in
|
||||
let distro = g#inspect_get_distro root in
|
||||
let major_version = g#inspect_get_major_version root in
|
||||
|
||||
match typ, distro, major_version with
|
||||
(* Fedora 18 (hence RHEL 7+) changed to using /etc/hostname
|
||||
* (RHBZ#881953, RHBZ#858696). We may also need to modify
|
||||
* /etc/machine-info (RHBZ#890027).
|
||||
*)
|
||||
| "linux", "fedora", v when v >= 18 ->
|
||||
update_etc_hostname g hostname;
|
||||
update_etc_machine_info g hostname;
|
||||
true
|
||||
|
||||
| "linux", ("rhel"|"centos"|"scientificlinux"|"oraclelinux"|"rocky"|
|
||||
"redhat-based"), v
|
||||
when v >= 7 ->
|
||||
update_etc_hostname g hostname;
|
||||
update_etc_machine_info g hostname;
|
||||
true
|
||||
|
||||
| "linux", ("debian"|"ubuntu"|"kalilinux"), _ ->
|
||||
let old_hostname = read_etc_hostname g in
|
||||
update_etc_hostname g hostname;
|
||||
replace_host_in_etc_hosts g old_hostname hostname;
|
||||
true
|
||||
|
||||
| "linux", ("fedora"|"rhel"|"centos"|"scientificlinux"|"oraclelinux"|
|
||||
"redhat-based"), _ ->
|
||||
replace_line_in_file g "/etc/sysconfig/network" "HOSTNAME" hostname;
|
||||
true
|
||||
|
||||
| "linux", ("opensuse"|"sles"|"suse-based"), _ ->
|
||||
g#write "/etc/HOSTNAME" hostname;
|
||||
true
|
||||
|
||||
| _ ->
|
||||
false
|
||||
|
||||
(* Replace <key>=... entry in file. The code assumes it's a small,
|
||||
* plain text file.
|
||||
*)
|
||||
and replace_line_in_file g filename key value =
|
||||
let content =
|
||||
if g#is_file filename then (
|
||||
let lines = Array.to_list (g#read_lines filename) in
|
||||
let lines = List.filter (
|
||||
fun line -> not (String.is_prefix line (key ^ "="))
|
||||
) lines in
|
||||
let lines = lines @ [sprintf "%s=%s" key value] in
|
||||
String.concat "\n" lines ^ "\n"
|
||||
) else (
|
||||
sprintf "%s=%s\n" key value
|
||||
) in
|
||||
g#write filename content
|
||||
|
||||
and update_etc_hostname g hostname =
|
||||
g#write "/etc/hostname" (hostname ^ "\n")
|
||||
|
||||
and update_etc_machine_info g hostname =
|
||||
replace_line_in_file g "/etc/machine-info" "PRETTY_HOSTNAME" hostname
|
||||
|
||||
and read_etc_hostname g =
|
||||
let filename = "/etc/hostname" in
|
||||
if g#is_file filename then (
|
||||
let lines = Array.to_list (g#read_lines filename) in
|
||||
match lines with
|
||||
| hd :: _ -> Some hd
|
||||
| [] -> None
|
||||
) else
|
||||
None
|
||||
|
||||
and aug_hosts_expr =
|
||||
(* Matches everything in /etc/hosts except the IP address and comments. *)
|
||||
"/files/etc/hosts/*[label() != '#comment']/*[label() != 'ipaddr']"
|
||||
|
||||
and replace_host_in_etc_hosts g oldhost newhost =
|
||||
if g#is_file "/etc/hosts" then (
|
||||
let oldshortname, olddomainname =
|
||||
match oldhost with
|
||||
| None -> None, None
|
||||
| Some oldhost ->
|
||||
let s, d = String.split "." oldhost in Some s, Some d in
|
||||
let newshortname, newdomainname = String.split "." newhost in
|
||||
|
||||
g#aug_init "/" 0;
|
||||
let matches = Array.to_list (g#aug_match aug_hosts_expr) in
|
||||
|
||||
List.iter (
|
||||
fun m ->
|
||||
let value = g#aug_get m in
|
||||
|
||||
(* Replace either "oldhostname" or "oldhostname.olddomainname". *)
|
||||
if oldhost = Some value then
|
||||
g#aug_set m newhost
|
||||
|
||||
else if oldshortname = Some value then
|
||||
g#aug_set m newshortname
|
||||
|
||||
(* On Debian/Ubuntu we also may find "unassigned-hostname"
|
||||
* which has to be replaced with the short hostname.
|
||||
*)
|
||||
else if value = "unassigned-hostname" then
|
||||
g#aug_set m newshortname
|
||||
|
||||
(* Or we may find "unassigned-hostname.unassigned-domain". *)
|
||||
else if value = "unassigned-hostname.unassigned-domain" &&
|
||||
newdomainname <> "" then
|
||||
g#aug_set m newhost
|
||||
) matches;
|
||||
|
||||
g#aug_save ()
|
||||
)
|
21
virt/common/mlcustomize/hostname.mli
Normal file
21
virt/common/mlcustomize/hostname.mli
Normal file
@ -0,0 +1,21 @@
|
||||
(* virt-sysprep
|
||||
* Copyright (C) 2012-2023 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 set_hostname : Guestfs.guestfs -> string -> string -> bool
|
||||
(** Set the hostname in a guest. Returns true if it was able to
|
||||
do set it, false if not. *)
|
630
virt/common/mlcustomize/inject_virtio_win.ml
Normal file
630
virt/common/mlcustomize/inject_virtio_win.ml
Normal file
@ -0,0 +1,630 @@
|
||||
(* virt-v2v
|
||||
* Copyright (C) 2009-2023 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 Regedit
|
||||
|
||||
let re_blnsvr = PCRE.compile ~caseless:true "\\bblnsvr\\.exe$"
|
||||
|
||||
type t = {
|
||||
g : Guestfs.guestfs; (** guestfs handle *)
|
||||
|
||||
root : string; (** root of inspection *)
|
||||
|
||||
i_arch : string;
|
||||
i_major_version : int;
|
||||
i_minor_version : int;
|
||||
i_osinfo : string;
|
||||
i_product_variant : string;
|
||||
i_windows_current_control_set : string;
|
||||
i_windows_systemroot : string;
|
||||
(** Inspection data needed by this module. *)
|
||||
|
||||
virtio_win : string;
|
||||
(** Path to the virtio-win ISO or directory. *)
|
||||
|
||||
was_set : bool;
|
||||
(** If the virtio_win path was explicitly set, for example by
|
||||
the user setting an environment variable.
|
||||
|
||||
This is used to "show intention" to use virtio-win instead
|
||||
of libosinfo. Although this behaviour is documented, IMHO it has
|
||||
always been a bad idea. We should change this in future to allow
|
||||
the user to select where they want to get drivers from. XXX *)
|
||||
|
||||
mutable block_driver_priority : string list
|
||||
(** List of block drivers *)
|
||||
}
|
||||
|
||||
type block_type = Virtio_blk | Virtio_SCSI | IDE
|
||||
and net_type = Virtio_net | E1000 | RTL8139
|
||||
and machine_type = I440FX | Q35 | Virt
|
||||
|
||||
type virtio_win_installed = {
|
||||
block_driver : block_type;
|
||||
net_driver : net_type;
|
||||
virtio_rng : bool;
|
||||
virtio_balloon : bool;
|
||||
isa_pvpanic : bool;
|
||||
virtio_socket : bool;
|
||||
machine : machine_type;
|
||||
virtio_1_0 : bool;
|
||||
}
|
||||
|
||||
let rec from_environment g root datadir =
|
||||
let t = get_inspection g root in
|
||||
|
||||
let virtio_win, was_set =
|
||||
try Sys.getenv "VIRTIO_WIN", true
|
||||
with Not_found ->
|
||||
try Sys.getenv "VIRTIO_WIN_DIR" (* old name for VIRTIO_WIN *), true
|
||||
with Not_found ->
|
||||
let iso = datadir // "virtio-win" // "virtio-win.iso" in
|
||||
(if Sys.file_exists iso then iso
|
||||
else datadir // "virtio-win"), false in
|
||||
|
||||
{ t with virtio_win; was_set }
|
||||
|
||||
and from_path g root path =
|
||||
let t = get_inspection g root in
|
||||
{ t with virtio_win = path; was_set = true }
|
||||
|
||||
and from_libosinfo g root =
|
||||
let t = get_inspection g root in
|
||||
{ t with virtio_win = ""; was_set = false }
|
||||
|
||||
and get_inspection g root =
|
||||
(* Fail hard if inspection hasn't been done or it's not a Windows
|
||||
* guest. If it happens it indicates an internal error in the
|
||||
* calling code.
|
||||
*)
|
||||
assert (g#inspect_get_type root = "windows");
|
||||
|
||||
let i_arch = g#inspect_get_arch root in
|
||||
let i_major_version = g#inspect_get_major_version root in
|
||||
let i_minor_version = g#inspect_get_minor_version root in
|
||||
let i_osinfo = g#inspect_get_osinfo root in
|
||||
let i_product_variant = g#inspect_get_product_variant root in
|
||||
let i_windows_current_control_set =
|
||||
g#inspect_get_windows_current_control_set root in
|
||||
let i_windows_systemroot = g#inspect_get_windows_systemroot root in
|
||||
|
||||
{ g; root;
|
||||
i_arch; i_major_version; i_minor_version; i_osinfo;
|
||||
i_product_variant; i_windows_current_control_set; i_windows_systemroot;
|
||||
virtio_win = ""; was_set = false;
|
||||
block_driver_priority = ["virtio_blk"; "vrtioblk"; "viostor"] }
|
||||
|
||||
let get_block_driver_priority t = t.block_driver_priority
|
||||
let set_block_driver_priority t v = t.block_driver_priority <- v
|
||||
|
||||
let scsi_class_guid = "{4D36E97B-E325-11CE-BFC1-08002BE10318}"
|
||||
let viostor_legacy_pciid = "VEN_1AF4&DEV_1001&REV_00"
|
||||
let viostor_modern_pciid = "VEN_1AF4&DEV_1042&REV_01"
|
||||
let vioscsi_legacy_pciid = "VEN_1AF4&DEV_1004&REV_00"
|
||||
let vioscsi_modern_pciid = "VEN_1AF4&DEV_1048&REV_01"
|
||||
|
||||
let rec inject_virtio_win_drivers ({ g } as t) reg =
|
||||
(* Copy the virtio drivers to the guest. *)
|
||||
let driverdir = sprintf "%s/Drivers/VirtIO" t.i_windows_systemroot in
|
||||
g#mkdir_p driverdir;
|
||||
|
||||
(* XXX Inelegant hack copied originally from [Convert_windows].
|
||||
* We should be able to work this into the code properly later.
|
||||
*)
|
||||
let (machine : machine_type), virtio_1_0 =
|
||||
match t.i_arch with
|
||||
| ("i386"|"x86_64") ->
|
||||
(try
|
||||
(* Fall back to the decision that's based on the year that the OS
|
||||
* was released in under three circumstances:
|
||||
* - the user specified the location of the Windows virtio drivers
|
||||
* through an environment variable, or
|
||||
* - "Libosinfo_utils.get_os_by_short_id" fails to look up the OS,
|
||||
* or
|
||||
* - "Libosinfo_utils.best_driver" cannot find any matching driver.
|
||||
* In each of these cases, a "Not_found" exception is raised. This
|
||||
* behavior exactly mirrors that of "Windows_virtio.copy_drivers".
|
||||
*)
|
||||
if t.was_set then raise Not_found;
|
||||
let os = Libosinfo_utils.get_os_by_short_id t.i_osinfo in
|
||||
let devices = os#get_devices ()
|
||||
and drivers = os#get_device_drivers () in
|
||||
let best_drv_devs =
|
||||
(Libosinfo_utils.best_driver drivers t.i_arch).devices in
|
||||
debug "libosinfo internal devices for OS \"%s\":\n%s"
|
||||
t.i_osinfo
|
||||
(Libosinfo_utils.string_of_osinfo_device_list devices);
|
||||
debug "libosinfo \"best driver\" devices for OS \"%s\":\n%s"
|
||||
t.i_osinfo
|
||||
(Libosinfo_utils.string_of_osinfo_device_list best_drv_devs);
|
||||
let { Libosinfo_utils.q35; vio10 } =
|
||||
Libosinfo_utils.os_support_of_osinfo_device_list
|
||||
(devices @ best_drv_devs) in
|
||||
(if q35 then Q35 else I440FX), vio10
|
||||
with
|
||||
| Not_found ->
|
||||
(* Pivot on the year 2007. Any Windows version from earlier than
|
||||
* 2007 should use i440fx, anything 2007 or newer should use q35.
|
||||
* Luckily this coincides almost exactly with the release of NT 6.
|
||||
*)
|
||||
(if t.i_major_version < 6 then I440FX else Q35), true
|
||||
)
|
||||
| _ -> Virt, true
|
||||
in
|
||||
|
||||
if not (copy_drivers t driverdir) then (
|
||||
warning (f_"there are no virtio drivers available for this version of Windows (%d.%d %s %s %s). virt-v2v looks for drivers in %s\n\nThe guest will be configured to use slower emulated devices.")
|
||||
t.i_major_version t.i_minor_version t.i_arch
|
||||
t.i_product_variant t.i_osinfo t.virtio_win;
|
||||
{ block_driver = IDE; net_driver = RTL8139;
|
||||
virtio_rng = false; virtio_balloon = false;
|
||||
isa_pvpanic = false; virtio_socket = false;
|
||||
machine; virtio_1_0; }
|
||||
)
|
||||
else (
|
||||
(* Can we install the block driver? *)
|
||||
let block : block_type =
|
||||
let viostor_driver = try (
|
||||
Some (
|
||||
List.find (
|
||||
fun driver_file ->
|
||||
let source = driverdir // driver_file ^ ".sys" in
|
||||
g#exists source
|
||||
) t.block_driver_priority
|
||||
)
|
||||
) with Not_found -> None in
|
||||
match viostor_driver with
|
||||
| None ->
|
||||
warning (f_"there is no virtio block device driver for this version of Windows (%d.%d %s). virt-v2v looks for this driver in %s\n\nThe guest will be configured to use a slower emulated device.")
|
||||
t.i_major_version t.i_minor_version
|
||||
t.i_arch t.virtio_win;
|
||||
IDE
|
||||
|
||||
| Some driver_name ->
|
||||
(* Block driver needs tweaks to allow booting;
|
||||
* the rest is set up by PnP manager.
|
||||
*)
|
||||
let source = driverdir // (driver_name ^ ".sys") in
|
||||
let target = sprintf "%s/system32/drivers/%s.sys"
|
||||
t.i_windows_systemroot driver_name in
|
||||
let target = g#case_sensitive_path target in
|
||||
let installed_block_type, legacy_pciid, modern_pciid =
|
||||
match driver_name with
|
||||
| "vioscsi" -> Virtio_SCSI, vioscsi_legacy_pciid, vioscsi_modern_pciid
|
||||
| _ -> Virtio_blk, viostor_legacy_pciid, viostor_modern_pciid
|
||||
in
|
||||
g#cp source target;
|
||||
add_guestor_to_registry t reg driver_name legacy_pciid;
|
||||
add_guestor_to_registry t reg driver_name modern_pciid;
|
||||
installed_block_type in
|
||||
|
||||
(* Can we install the virtio-net driver? *)
|
||||
let net : net_type =
|
||||
let filenames = ["virtio_net.inf"; "netkvm.inf"] in
|
||||
let has_netkvm =
|
||||
List.exists (
|
||||
fun driver_file -> g#exists (driverdir // driver_file)
|
||||
) filenames in
|
||||
if not has_netkvm then (
|
||||
warning (f_"there is no virtio network driver for this version of Windows (%d.%d %s). virt-v2v looks for this driver in %s\n\nThe guest will be configured to use a slower emulated device.")
|
||||
t.i_major_version t.i_minor_version
|
||||
t.i_arch t.virtio_win;
|
||||
RTL8139
|
||||
)
|
||||
else
|
||||
Virtio_net in
|
||||
|
||||
(* The "fwcfg" driver binds the fw_cfg device for real, and provides three
|
||||
* files -- ".cat", ".inf", ".sys". (Possibly ".pdb" too.)
|
||||
*
|
||||
* The "qemufwcfg" driver is only a stub driver; it placates Device Manager
|
||||
* (hides the "unknown device" question mark) but does not actually drive
|
||||
* the fw_cfg device. It provides two files only -- ".cat", ".inf".
|
||||
*
|
||||
* These drivers conflict with each other (RHBZ#2151752). If we've copied
|
||||
* both (either from libosinfo of virtio-win), let "fwcfg" take priority:
|
||||
* remove "qemufwcfg".
|
||||
*)
|
||||
if g#exists (driverdir // "fwcfg.inf") &&
|
||||
g#exists (driverdir // "qemufwcfg.inf") then (
|
||||
debug "windows: skipping qemufwcfg stub driver in favor of fwcfg driver";
|
||||
Array.iter g#rm (g#glob_expand (driverdir // "qemufwcfg.*"))
|
||||
);
|
||||
|
||||
(* Did we install the miscellaneous drivers? *)
|
||||
{ block_driver = block;
|
||||
net_driver = net;
|
||||
virtio_rng = g#exists (driverdir // "viorng.inf");
|
||||
virtio_balloon = g#exists (driverdir // "balloon.inf");
|
||||
isa_pvpanic = g#exists (driverdir // "pvpanic.inf");
|
||||
virtio_socket = g#exists (driverdir // "viosock.inf");
|
||||
machine; virtio_1_0;
|
||||
}
|
||||
)
|
||||
|
||||
and inject_qemu_ga ({ g; root } as t) =
|
||||
(* Copy the qemu-ga MSI(s) to the guest. *)
|
||||
let dir, dir_win = Firstboot.firstboot_dir g root in
|
||||
let dir_win = Option.value dir_win ~default:dir in
|
||||
let tempdir = sprintf "%s/Temp" dir in
|
||||
let tempdir_win = sprintf "%s\\Temp" dir_win in
|
||||
g#mkdir_p tempdir;
|
||||
|
||||
let msi_files = copy_qemu_ga t tempdir in
|
||||
if msi_files <> [] then
|
||||
configure_qemu_ga t tempdir_win msi_files;
|
||||
msi_files <> [] (* return true if we found some qemu-ga MSI files *)
|
||||
|
||||
and inject_blnsvr ({ g; root } as t) =
|
||||
(* Copy the files to the guest. *)
|
||||
let dir, dir_win = Firstboot.firstboot_dir g root in
|
||||
let dir_win = Option.value dir_win ~default:dir in
|
||||
let tempdir = sprintf "%s/Temp" dir in
|
||||
let tempdir_win = sprintf "%s\\Temp" dir_win in
|
||||
g#mkdir_p tempdir;
|
||||
|
||||
let files = copy_blnsvr t tempdir in
|
||||
match files with
|
||||
| [] -> false (* Didn't find or install anything. *)
|
||||
|
||||
(* We usually find blnsvr.exe in two locations (drivers/by-os and
|
||||
* drivers/by-driver). Pick the first.
|
||||
*)
|
||||
| blnsvr :: _ ->
|
||||
configure_blnsvr t tempdir_win blnsvr;
|
||||
true
|
||||
|
||||
and add_guestor_to_registry t ((g, root) as reg) drv_name drv_pciid =
|
||||
let ddb_node = g#hivex_node_get_child root "DriverDatabase" in
|
||||
|
||||
let regedits =
|
||||
if ddb_node = 0L then
|
||||
cdb_regedits t drv_name drv_pciid
|
||||
else
|
||||
ddb_regedits t drv_name drv_pciid in
|
||||
|
||||
let drv_sys_path = sprintf "system32\\drivers\\%s.sys" drv_name in
|
||||
let common_regedits = [
|
||||
[ t.i_windows_current_control_set; "Services"; drv_name ],
|
||||
[ "Type", REG_DWORD 0x1_l;
|
||||
"Start", REG_DWORD 0x0_l;
|
||||
"Group", REG_SZ "SCSI miniport";
|
||||
"ErrorControl", REG_DWORD 0x1_l;
|
||||
"ImagePath", REG_EXPAND_SZ drv_sys_path ];
|
||||
] in
|
||||
|
||||
reg_import reg (regedits @ common_regedits)
|
||||
|
||||
and cdb_regedits t drv_name drv_pciid =
|
||||
(* See http://rwmj.wordpress.com/2010/04/30/tip-install-a-device-driver-in-a-windows-vm/
|
||||
* NB: All these edits are in the HKLM\SYSTEM hive. No other
|
||||
* hive may be modified here.
|
||||
*)
|
||||
[
|
||||
[ t.i_windows_current_control_set;
|
||||
"Control"; "CriticalDeviceDatabase";
|
||||
"PCI#" ^ drv_pciid ],
|
||||
[ "Service", REG_SZ drv_name;
|
||||
"ClassGUID", REG_SZ scsi_class_guid ];
|
||||
]
|
||||
|
||||
and ddb_regedits inspect drv_name drv_pciid =
|
||||
(* Windows >= 8 doesn't use the CriticalDeviceDatabase. Instead
|
||||
* one must add keys into the DriverDatabase.
|
||||
*)
|
||||
|
||||
let drv_inf = "guestor.inf" in
|
||||
let drv_inf_label = drv_inf ^ "_tmp" in
|
||||
let drv_config = "guestor_conf" in
|
||||
|
||||
[
|
||||
[ "DriverDatabase"; "DriverInfFiles"; drv_inf ],
|
||||
[ "", REG_MULTI_SZ [ drv_inf_label ];
|
||||
"Active", REG_SZ drv_inf_label;
|
||||
"Configurations", REG_MULTI_SZ [ drv_config ] ];
|
||||
|
||||
[ "DriverDatabase"; "DeviceIds"; "PCI"; drv_pciid ],
|
||||
[ drv_inf, REG_BINARY "\x01\xff\x00\x00" ];
|
||||
|
||||
[ "DriverDatabase"; "DriverPackages"; drv_inf_label ],
|
||||
[ "Version", REG_BINARY ("\x00\xff\x09\x00\x00\x00\x00\x00" ^
|
||||
"\x7b\xe9\x36\x4d\x25\xe3\xce\x11" ^
|
||||
"\xbf\xc1\x08\x00\x2b\xe1\x03\x18" ^
|
||||
(String.make 24 '\x00')) ];
|
||||
(* Version is necessary for Windows-Kernel-Pnp in w10/w2k16 *)
|
||||
|
||||
[ "DriverDatabase"; "DriverPackages"; drv_inf_label;
|
||||
"Configurations"; drv_config ],
|
||||
[ "ConfigFlags", REG_DWORD 0_l;
|
||||
"Service", REG_SZ drv_name ];
|
||||
|
||||
[ "DriverDatabase"; "DriverPackages"; drv_inf_label;
|
||||
"Descriptors"; "PCI"; drv_pciid ],
|
||||
[ "Configuration", REG_SZ drv_config ];
|
||||
]
|
||||
|
||||
(* Copy the matching drivers to the driverdir; return true if any have
|
||||
* been copied.
|
||||
*)
|
||||
and copy_drivers t driverdir =
|
||||
(not t.was_set && [] <> copy_from_libosinfo t driverdir) ||
|
||||
[] <> copy_from_virtio_win t "/" driverdir
|
||||
(virtio_iso_path_matches_guest_os t)
|
||||
(fun () ->
|
||||
error (f_"root directory ‘/’ is missing from the virtio-win directory or ISO.\n\nThis should not happen and may indicate that virtio-win or virt-v2v is broken in some way. Please report this as a bug with a full debug log."))
|
||||
|
||||
and copy_qemu_ga t tempdir =
|
||||
copy_from_virtio_win t "/" tempdir (virtio_iso_path_matches_qemu_ga t)
|
||||
(fun () ->
|
||||
error (f_"root directory ‘/’ is missing from the virtio-win directory or ISO.\n\nThis should not happen and may indicate that virtio-win or virt-v2v is broken in some way. Please report this as a bug with a full debug log."))
|
||||
|
||||
and copy_blnsvr t tempdir =
|
||||
copy_from_virtio_win t "/" tempdir (virtio_iso_path_matches_blnsvr t)
|
||||
(fun () ->
|
||||
error (f_"root directory ‘/’ is missing from the virtio-win directory or ISO.\n\nThis should not happen and may indicate that virtio-win or virt-v2v is broken in some way. Please report this as a bug with a full debug log."))
|
||||
|
||||
(* 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].
|
||||
* The file list is filtered based on [filter] function.
|
||||
*
|
||||
* If [srcdir] is missing from the ISO then [missing ()] is called
|
||||
* which might give a warning or error.
|
||||
*
|
||||
* Returns list of copied files.
|
||||
*)
|
||||
and copy_from_virtio_win ({ g } as t) srcdir destdir filter missing =
|
||||
let ret = ref [] in
|
||||
if is_directory t.virtio_win then (
|
||||
debug "windows: copy_from_virtio_win: guest tools source directory %s"
|
||||
t.virtio_win;
|
||||
|
||||
let dir = t.virtio_win // srcdir in
|
||||
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
|
||||
List.iter (
|
||||
fun path ->
|
||||
if filter path then (
|
||||
let source = dir // path in
|
||||
let target_name = String.lowercase_ascii (Filename.basename path) in
|
||||
let target = destdir // target_name in
|
||||
debug "windows: copying guest tools bits: 'host:%s' -> '%s'"
|
||||
source target;
|
||||
|
||||
g#write target (read_whole_file source);
|
||||
List.push_front target_name ret
|
||||
)
|
||||
) paths
|
||||
)
|
||||
)
|
||||
else if is_regular_file t.virtio_win || is_block_device t.virtio_win then (
|
||||
debug "windows: copy_from_virtio_win: guest tools source ISO %s"
|
||||
t.virtio_win;
|
||||
|
||||
let g2 =
|
||||
try
|
||||
let g2 = open_guestfs ~identifier:"virtio_win" () in
|
||||
g2#add_drive_opts t.virtio_win ~readonly:true;
|
||||
g2#launch ();
|
||||
g2
|
||||
with Guestfs.Error msg ->
|
||||
error (f_"%s: cannot open virtio-win ISO file: %s") t.virtio_win msg in
|
||||
(* Note we are mounting this as root on the *second*
|
||||
* handle, not the main handle containing the guest.
|
||||
*)
|
||||
g2#mount_ro "/dev/sda" "/";
|
||||
let srcdir = "/" ^ srcdir in
|
||||
if not (g2#is_dir srcdir) then missing ()
|
||||
else (
|
||||
let paths = g2#find srcdir in
|
||||
Array.iter (
|
||||
fun path ->
|
||||
let source = srcdir ^ "/" ^ path in
|
||||
if g2#is_file source ~followsymlinks:false && filter path then (
|
||||
let target_name = String.lowercase_ascii (Filename.basename path) in
|
||||
let target = destdir ^ "/" ^ target_name in
|
||||
debug "windows: copying guest tools bits: '%s:%s' -> '%s'"
|
||||
t.virtio_win path target;
|
||||
|
||||
g#write target (g2#read_file source);
|
||||
List.push_front target_name ret
|
||||
)
|
||||
) paths;
|
||||
);
|
||||
g2#close()
|
||||
);
|
||||
!ret
|
||||
|
||||
(* 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_guest_os t path =
|
||||
let { i_major_version = os_major; i_minor_version = os_minor;
|
||||
i_arch = arch; i_product_variant = os_variant;
|
||||
i_osinfo = osinfo } = t in
|
||||
try
|
||||
(* Lowercased path, since the ISO may contain upper or lowercase path
|
||||
* elements.
|
||||
*)
|
||||
let lc_path = String.lowercase_ascii path in
|
||||
|
||||
(* Using the full path, work out what version of Windows
|
||||
* this driver is for. Paths can be things like:
|
||||
* "NetKVM/2k12R2/amd64/netkvm.sys" or
|
||||
* "./drivers/amd64/Win2012R2/netkvm.sys".
|
||||
* Note we check lowercase paths.
|
||||
*)
|
||||
let pathelem elem =
|
||||
String.find lc_path ("/" ^ elem ^ "/") >= 0 ||
|
||||
String.is_prefix lc_path (elem ^ "/")
|
||||
in
|
||||
let p_arch =
|
||||
if pathelem "x86" || pathelem "i386" then "i386"
|
||||
else if pathelem "amd64" then "x86_64"
|
||||
else raise Not_found in
|
||||
|
||||
let is_client os_variant = os_variant = "Client"
|
||||
and not_client os_variant = os_variant <> "Client"
|
||||
and any_variant os_variant = true
|
||||
and any_osinfo osinfo = true in
|
||||
let p_os_major, p_os_minor, match_os_variant, match_osinfo =
|
||||
if pathelem "xp" || pathelem "winxp" then
|
||||
(5, 1, any_variant, any_osinfo)
|
||||
else if pathelem "2k3" || pathelem "win2003" then
|
||||
(5, 2, any_variant, any_osinfo)
|
||||
else if pathelem "vista" then
|
||||
(6, 0, is_client, any_osinfo)
|
||||
else if pathelem "2k8" || pathelem "win2008" then
|
||||
(6, 0, not_client, any_osinfo)
|
||||
else if pathelem "w7" || pathelem "win7" then
|
||||
(6, 1, is_client, any_osinfo)
|
||||
else if pathelem "2k8r2" || pathelem "win2008r2" then
|
||||
(6, 1, not_client, any_osinfo)
|
||||
else if pathelem "w8" || pathelem "win8" then
|
||||
(6, 2, is_client, any_osinfo)
|
||||
else if pathelem "2k12" || pathelem "win2012" then
|
||||
(6, 2, not_client, any_osinfo)
|
||||
else if pathelem "w8.1" || pathelem "win8.1" then
|
||||
(6, 3, is_client, any_osinfo)
|
||||
else if pathelem "2k12r2" || pathelem "win2012r2" then
|
||||
(6, 3, not_client, any_osinfo)
|
||||
else if pathelem "w10" || pathelem "win10" then
|
||||
(10, 0, is_client, ((=) "win10"))
|
||||
else if pathelem "w11" || pathelem "win11" then
|
||||
(10, 0, is_client, ((=) "win11"))
|
||||
else if pathelem "2k16" || pathelem "win2016" then
|
||||
(10, 0, not_client, ((=) "win2k16"))
|
||||
else if pathelem "2k19" || pathelem "win2019" then
|
||||
(10, 0, not_client, ((=) "win2k19"))
|
||||
else if pathelem "2k22" || pathelem "win2022" then
|
||||
(10, 0, not_client, ((=) "win2k22"))
|
||||
else
|
||||
raise Not_found in
|
||||
|
||||
let p_sriov = pathelem "sriov" in
|
||||
|
||||
arch = p_arch &&
|
||||
not p_sriov && (* always ignored, see RHEL-56383 *)
|
||||
os_major = p_os_major && os_minor = p_os_minor &&
|
||||
match_os_variant os_variant &&
|
||||
match_osinfo osinfo
|
||||
|
||||
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 t path =
|
||||
(* Lowercased path, since the ISO may contain upper or lowercase path
|
||||
* elements.
|
||||
*)
|
||||
let lc_name = String.lowercase_ascii (Filename.basename path) in
|
||||
match t.i_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
|
||||
|
||||
(* Find blnsvr for the current Windows version. *)
|
||||
and virtio_iso_path_matches_blnsvr t path =
|
||||
virtio_iso_path_matches_guest_os t path && PCRE.matches re_blnsvr path
|
||||
|
||||
(* Look up in libosinfo for the OS, and copy all the locally
|
||||
* available files specified as drivers for that OS to the [destdir].
|
||||
*
|
||||
* This function does nothing in case either:
|
||||
* - the osinfo short ID is not found in the libosinfo DB
|
||||
* - the OS does not have any driver for the architecture of the guest
|
||||
* - the location of the drivers is not a local directory
|
||||
*
|
||||
* Files that do not exist are silently skipped.
|
||||
*
|
||||
* Returns list of copied files.
|
||||
*)
|
||||
and copy_from_libosinfo { g; i_osinfo; i_arch } destdir =
|
||||
try
|
||||
let os = Libosinfo_utils.get_os_by_short_id i_osinfo in
|
||||
let drivers = os#get_device_drivers () in
|
||||
let driver = Libosinfo_utils.best_driver drivers i_arch in
|
||||
let uri = Xml.parse_uri driver.Libosinfo.location in
|
||||
let basedir =
|
||||
match uri.Xml.uri_path with
|
||||
| Some p -> p
|
||||
| None -> assert false in
|
||||
List.filter_map (
|
||||
fun f ->
|
||||
let source = basedir // f in
|
||||
if not (Sys.file_exists source) then
|
||||
None
|
||||
else (
|
||||
let target_name = String.lowercase_ascii (Filename.basename f) in
|
||||
let target = destdir ^ "/" ^ target_name in
|
||||
debug "windows: copying guest tools bits (via libosinfo): 'host:%s' -> '%s'"
|
||||
source target;
|
||||
|
||||
g#write target (read_whole_file source);
|
||||
Some target_name
|
||||
)
|
||||
) driver.Libosinfo.files
|
||||
with Not_found -> []
|
||||
|
||||
(* Install qemu-ga. [files] is the non-empty list of possible qemu-ga
|
||||
* installers we detected.
|
||||
*)
|
||||
and configure_qemu_ga t tempdir_win files =
|
||||
let script = ref [] in
|
||||
let add = List.push_back script in
|
||||
|
||||
add "# Virt-v2v script which installs QEMU Guest Agent";
|
||||
add "";
|
||||
add "# Uncomment this line for lots of debug output.";
|
||||
add "# Set-PSDebug -Trace 2";
|
||||
add "";
|
||||
add "Write-Host Installing QEMU Guest Agent";
|
||||
add "";
|
||||
add "# Run qemu-ga installers";
|
||||
List.iter (
|
||||
fun msi ->
|
||||
add (sprintf "Write-Host \"Writing log to %s\\%s.log\""
|
||||
tempdir_win msi);
|
||||
(* [`] is an escape char for quotes *)
|
||||
add (sprintf "Start-Process -Wait -FilePath \"%s\\%s\" -ArgumentList \"/norestart\",\"/qn\",\"/l+*vx\",\"`\"%s\\%s.log`\"\""
|
||||
tempdir_win msi tempdir_win msi)
|
||||
) files;
|
||||
|
||||
Firstboot.add_firstboot_powershell t.g t.root "install-qemu-ga" !script
|
||||
|
||||
and configure_blnsvr t tempdir_win blnsvr =
|
||||
let cmd = sprintf "\
|
||||
@echo off\n\
|
||||
echo Installing %s\n\
|
||||
\"%s\\%s\" -i\n" blnsvr tempdir_win blnsvr in
|
||||
Firstboot.add_firstboot_script t.g t.root "install-blnsvr" cmd
|
103
virt/common/mlcustomize/inject_virtio_win.mli
Normal file
103
virt/common/mlcustomize/inject_virtio_win.mli
Normal file
@ -0,0 +1,103 @@
|
||||
(* virt-v2v
|
||||
* Copyright (C) 2009-2023 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.
|
||||
*)
|
||||
|
||||
(** Values and functions for installing Windows virtio drivers. *)
|
||||
|
||||
type t (** Handle *)
|
||||
|
||||
type block_type = Virtio_blk | Virtio_SCSI | IDE
|
||||
and net_type = Virtio_net | E1000 | RTL8139
|
||||
and machine_type = I440FX | Q35 | Virt
|
||||
|
||||
type virtio_win_installed = {
|
||||
block_driver : block_type;
|
||||
net_driver : net_type;
|
||||
virtio_rng : bool;
|
||||
virtio_balloon : bool;
|
||||
isa_pvpanic : bool;
|
||||
virtio_socket : bool;
|
||||
machine : machine_type;
|
||||
virtio_1_0 : bool;
|
||||
}
|
||||
(** After calling {!install_drivers}, this describes what virtio-win
|
||||
drivers we were able to install (and hence, what the guest requires).
|
||||
eg. if [virtio_rng] is true then we installed the virtio RNG
|
||||
device, otherwise we didn't. *)
|
||||
|
||||
val from_path : Guestfs.guestfs -> string -> string -> t
|
||||
(** Create a new virtio-win handle. The parameters are [g root path].
|
||||
|
||||
The [path] should point to either the virtio-win ISO
|
||||
(eg. F</usr/share/virtio-win/virtio-win.iso>) or the unpacked
|
||||
directory (eg. F</usr/share/virtio-win>).
|
||||
|
||||
The libosinfo database is ignored if you use this method. *)
|
||||
|
||||
val from_libosinfo : Guestfs.guestfs -> string -> t
|
||||
(** Create a new virtio-win handle. The parameters are [g root].
|
||||
|
||||
The libosinfo database will be used as the source for drivers.
|
||||
The virtio-win ISO or unpacked directory is ignored if you use
|
||||
this method. *)
|
||||
|
||||
val from_environment : Guestfs.guestfs -> string -> string -> t
|
||||
(** Using the [VIRTIO_WIN] environment variable (if present), set up
|
||||
the injection handle.
|
||||
|
||||
The parameters are: [g root datadir]. The [datadir] is the path
|
||||
from ./configure (eg. {!Config.datadir}).
|
||||
|
||||
This should only be used by [virt-v2v] and is considered a legacy method. *)
|
||||
|
||||
val get_block_driver_priority : t -> string list
|
||||
val set_block_driver_priority : t -> string list -> unit
|
||||
(** Get or set the current block driver priority list. This is
|
||||
a list of virtio-win block driver names (eg. ["viostor"]) that
|
||||
we search until we come to the first [name ^ ".sys"] that
|
||||
we find, and that is the block driver which gets installed.
|
||||
|
||||
This module contains a default priority list which should
|
||||
be suitable for most use cases. *)
|
||||
|
||||
val inject_virtio_win_drivers : t -> Registry.t -> virtio_win_installed
|
||||
(** [inject_virtio_win_drivers t reg]
|
||||
installs virtio drivers from the driver directory or driver
|
||||
ISO into the guest driver directory and updates the registry
|
||||
so that the [viostor.sys] driver gets loaded by Windows at boot.
|
||||
|
||||
[reg] is the system hive which is open for writes when this
|
||||
function is called.
|
||||
|
||||
This returns a {!virtio_win_installed} struct reflecting what devices
|
||||
are now required by the guest, either virtio devices if we managed to
|
||||
install those, or legacy devices if we didn't. *)
|
||||
|
||||
val inject_qemu_ga : t -> bool
|
||||
(** Inject MSIs (ideally just one) with QEMU Guest Agent into a Windows
|
||||
guest. A firstboot script is also injected which should install
|
||||
the MSI(s).
|
||||
|
||||
Returns [true] iff we were able to inject qemu-ga. *)
|
||||
|
||||
val inject_blnsvr : t -> bool
|
||||
(** Inject the Balloon Server ([blnsvr.exe]) into a Windows guest.
|
||||
|
||||
A firstboot script is also injected which should install
|
||||
the server by running [blnsvr -i].
|
||||
|
||||
Returns [true] iff we were able to inject the Balloon Server. *)
|
201
virt/common/mlcustomize/password.ml
Normal file
201
virt/common/mlcustomize/password.ml
Normal file
@ -0,0 +1,201 @@
|
||||
(* virt-sysprep
|
||||
* Copyright (C) 2012-2023 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 Tools_utils
|
||||
open Common_gettext.Gettext
|
||||
|
||||
open Printf
|
||||
|
||||
type password_crypto = [ `MD5 | `SHA256 | `SHA512 | `YESCRYPT ]
|
||||
|
||||
type password_selector = {
|
||||
pw_password : password;
|
||||
pw_locked : bool;
|
||||
}
|
||||
and password =
|
||||
| Password of string
|
||||
| Random_password
|
||||
| Disabled_password
|
||||
|
||||
type password_map = (string, password_selector) Hashtbl.t
|
||||
|
||||
let make_random_password =
|
||||
(* Get random characters from the set [A-Za-z0-9] with some
|
||||
* homoglyphs removed.
|
||||
*)
|
||||
let chars = "ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz0123456789" in
|
||||
fun () -> Urandom.urandom_uniform 16 chars
|
||||
|
||||
let password_crypto_of_string = function
|
||||
| "md5" -> `MD5
|
||||
| "sha256" -> `SHA256
|
||||
| "sha512" -> `SHA512
|
||||
| "yescrypt" -> `YESCRYPT
|
||||
| arg ->
|
||||
error (f_"password-crypto: unknown algorithm %s, \
|
||||
use \"md5\", \"sha256\", \"sha512\" or \"yescrypt\"") arg
|
||||
|
||||
let rec parse_selector arg =
|
||||
parse_selector_list arg (String.nsplit ":" arg)
|
||||
|
||||
and parse_selector_list orig_arg = function
|
||||
| [ "lock"|"locked" ] ->
|
||||
{ pw_locked = true; pw_password = Disabled_password }
|
||||
| ("lock"|"locked") :: rest ->
|
||||
let pw = parse_selector_list orig_arg rest in
|
||||
{ pw with pw_locked = true }
|
||||
| [ "file"; filename ] ->
|
||||
{ pw_password = Password (read_first_line_from_file filename);
|
||||
pw_locked = false }
|
||||
| "password" :: password ->
|
||||
{ pw_password = Password (String.concat ":" password); pw_locked = false }
|
||||
| [ "random" ] ->
|
||||
{ pw_password = Random_password; pw_locked = false }
|
||||
| [ "disable"|"disabled" ] ->
|
||||
{ pw_password = Disabled_password; pw_locked = false }
|
||||
| _ ->
|
||||
error (f_"invalid password selector ‘%s’; see the man page") orig_arg
|
||||
|
||||
(* Permissible characters in a salt. *)
|
||||
let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./"
|
||||
|
||||
let rec set_linux_passwords ?password_crypto (g : Guestfs.guestfs)
|
||||
root passwords =
|
||||
let crypto =
|
||||
match password_crypto with
|
||||
| None -> default_crypto g root
|
||||
| Some c -> c in
|
||||
|
||||
(* Create a (almost) empty temporary file with the attributes of
|
||||
* /etc/shadow, so we can restore them later.
|
||||
*)
|
||||
let tempfile = g#mktemp "/etc/shadow.guestfsXXXXXX" in
|
||||
g#write tempfile "*";
|
||||
g#copy_attributes ~all:true "/etc/shadow" tempfile;
|
||||
|
||||
g#aug_init "/" 0;
|
||||
let users = Array.to_list (g#aug_ls "/files/etc/shadow") in
|
||||
List.iter (
|
||||
fun userpath ->
|
||||
let user =
|
||||
match last_part_of userpath '/' with
|
||||
| Some x -> x
|
||||
| None -> error "password: missing '/' in %s" userpath in
|
||||
try
|
||||
(* Each line is: "user:[!!]password:..."
|
||||
* !! at the front of the password field means the account is locked.
|
||||
*)
|
||||
let selector = Hashtbl.find passwords user in
|
||||
let pwfield =
|
||||
match selector with
|
||||
| { pw_locked = locked;
|
||||
pw_password = Password password } ->
|
||||
(if locked then "!!" else "") ^ encrypt password crypto
|
||||
| { pw_locked = locked;
|
||||
pw_password = Random_password } ->
|
||||
let password = make_random_password () in
|
||||
info (f_"Setting random password of %s to %s") user password;
|
||||
(if locked then "!!" else "") ^ encrypt password crypto
|
||||
| { pw_locked = true; pw_password = Disabled_password } -> "!!*"
|
||||
| { pw_locked = false; pw_password = Disabled_password } -> "*" in
|
||||
g#aug_set (userpath ^ "/password") pwfield
|
||||
with Not_found -> ()
|
||||
) users;
|
||||
g#aug_save ();
|
||||
g#aug_close ();
|
||||
|
||||
(* Restore all the attributes from the temporary file, and remove it. *)
|
||||
g#copy_attributes ~all:true tempfile "/etc/shadow";
|
||||
g#rm tempfile
|
||||
|
||||
(* Encrypt each password. Use glibc (on the host). See:
|
||||
* https://rwmj.wordpress.com/2013/07/09/setting-the-root-or-other-passwords-in-a-linux-guest/
|
||||
*)
|
||||
and encrypt password crypto =
|
||||
(* Get random characters from the set [A-Za-z0-9./]
|
||||
*
|
||||
* 24 characters gives a 144 bits (18 bytes) salt. Unlike the more
|
||||
* traditional 128 bits (16 bytes) salt, this 144 bits salt is always
|
||||
* represented by the same number of base64 characters without any
|
||||
* padding issues, where 128 bits can be represented by 22 or 23
|
||||
* (depending on padding) base64-encoded characters, even with a
|
||||
* non-standard base64 encoding scheme.
|
||||
*
|
||||
* We need it this way, because the yescrypt hashing methods requires
|
||||
* at least 128 bits of salt to work properly.
|
||||
*)
|
||||
let salt = Urandom.urandom_uniform 24 chars in
|
||||
let salt =
|
||||
(match crypto with
|
||||
| `MD5 -> "$1$"
|
||||
| `SHA256 -> "$5$"
|
||||
| `SHA512 -> "$6$"
|
||||
| `YESCRYPT -> "$y$j9T$") ^ salt ^ "$" in
|
||||
let r = Crypt.crypt password salt in
|
||||
(*printf "password: encrypt %s with salt %s -> %s\n" password salt r;*)
|
||||
r
|
||||
|
||||
(* glibc 2.7 was released in Oct 2007. Approximately, all guests that
|
||||
* precede this date only support md5, whereas all guests after this
|
||||
* date can support sha512.
|
||||
*
|
||||
* Most distros released in 2020 or later ship with libxcrypt >= 4.3,
|
||||
* and are able to handle yescrypt hashes.
|
||||
*)
|
||||
and default_crypto g root =
|
||||
let distro = g#inspect_get_distro root in
|
||||
let major = g#inspect_get_major_version root in
|
||||
match distro, major with
|
||||
| ("rhel"|"centos"|"scientificlinux"|"oraclelinux"|"rocky"|
|
||||
"redhat-based"), v when v >= 9 ->
|
||||
`YESCRYPT
|
||||
| ("rhel"|"centos"|"scientificlinux"|"oraclelinux"|"redhat-based"), v
|
||||
when v >= 6 ->
|
||||
`SHA512
|
||||
| ("rhel"|"centos"|"scientificlinux"|"oraclelinux"|"redhat-based"), _ ->
|
||||
`MD5 (* RHEL 5 does not appear to support SHA512, according to crypt(3) *)
|
||||
|
||||
| "fedora", v when v >= 30 -> `YESCRYPT
|
||||
| "fedora", v when v >= 9 -> `SHA512
|
||||
| "fedora", _ -> `MD5
|
||||
|
||||
| "debian", v when v >= 11 -> `YESCRYPT
|
||||
| "debian", v when v >= 5 -> `SHA512
|
||||
| "debian", _ -> `MD5
|
||||
|
||||
| "ubuntu", v when v >= 20 -> `YESCRYPT
|
||||
| "ubuntu", v when v >= 10 -> `SHA512
|
||||
| "ubuntu", _ -> `MD5
|
||||
|
||||
| ("opensuse"|"sles"), v when v >= 15 -> `YESCRYPT
|
||||
| ("opensuse"|"sles"), v when v >= 11 -> `SHA512
|
||||
| ("opensuse"|"sles"), _ -> `MD5
|
||||
|
||||
(* Rolling distributions, which hopefully should be updated enough. *)
|
||||
| ("archlinux"|"kalilinux"), _ -> `YESCRYPT
|
||||
| ("voidlinux"), _ -> `SHA512
|
||||
|
||||
| _, _ ->
|
||||
let minor = g#inspect_get_minor_version root in
|
||||
warning (f_"password: using insecure md5 password encryption for \
|
||||
guest of type %s version %d.%d.\n\
|
||||
If this is incorrect, use --password-crypto option \
|
||||
and file a bug.")
|
||||
distro major minor;
|
||||
`MD5
|
42
virt/common/mlcustomize/password.mli
Normal file
42
virt/common/mlcustomize/password.mli
Normal file
@ -0,0 +1,42 @@
|
||||
(* virt-sysprep
|
||||
* Copyright (C) 2012-2023 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.
|
||||
*)
|
||||
|
||||
type password_crypto = [ `MD5 | `SHA256 | `SHA512 | `YESCRYPT ]
|
||||
|
||||
val password_crypto_of_string : string -> password_crypto
|
||||
(** Parse --password-crypto parameter on command line. *)
|
||||
|
||||
type password_selector = {
|
||||
pw_password : password; (** The password. *)
|
||||
pw_locked : bool; (** If the account should be locked. *)
|
||||
}
|
||||
and password =
|
||||
| Password of string (** Password (literal string). *)
|
||||
| Random_password (** Choose a random password. *)
|
||||
| Disabled_password (** [*] in the password field. *)
|
||||
|
||||
val parse_selector : string -> password_selector
|
||||
(** Parse the selector field in --password/--root-password. Note this
|
||||
doesn't parse the username part. Exits if the format is not valid. *)
|
||||
|
||||
type password_map = (string, password_selector) Hashtbl.t
|
||||
(** A map of username -> selector. *)
|
||||
|
||||
val set_linux_passwords : ?password_crypto:password_crypto -> Guestfs.guestfs -> string -> password_map -> unit
|
||||
(** Adjust the passwords of a Linux guest according to the
|
||||
password map. *)
|
48
virt/common/mlcustomize/perl_edit-c.c
Normal file
48
virt/common/mlcustomize/perl_edit-c.c
Normal file
@ -0,0 +1,48 @@
|
||||
/* virt-customize - interface to edit_file_perl
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <caml/alloc.h>
|
||||
#include <caml/memory.h>
|
||||
#include <caml/mlvalues.h>
|
||||
#include <caml/fail.h>
|
||||
|
||||
#include "file-edit.h"
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
|
||||
|
||||
value
|
||||
virt_customize_edit_file_perl (value verbosev, value gv, value gpv,
|
||||
value filev, value exprv)
|
||||
{
|
||||
CAMLparam5 (verbosev, gv, gpv, filev, exprv);
|
||||
int r;
|
||||
guestfs_h *g = (guestfs_h *) (intptr_t) Int64_val (gpv);
|
||||
|
||||
r = edit_file_perl (g, String_val (filev), String_val (exprv), NULL,
|
||||
Bool_val (verbosev));
|
||||
if (r == -1)
|
||||
caml_failwith (guestfs_last_error (g) ? : "edit_file_perl: unknown error");
|
||||
|
||||
CAMLreturn (Val_unit);
|
||||
}
|
31
virt/common/mlcustomize/perl_edit.ml
Normal file
31
virt/common/mlcustomize/perl_edit.ml
Normal file
@ -0,0 +1,31 @@
|
||||
(* virt-builder
|
||||
* Copyright (C) 2013 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 Tools_utils
|
||||
|
||||
external c_edit_file : verbose:bool -> Guestfs.t -> int64 -> string -> string
|
||||
-> unit
|
||||
= "virt_customize_edit_file_perl"
|
||||
let edit_file g file expr =
|
||||
(* Note we pass original 'g' even though it is not used by the
|
||||
* callee. This is so that 'g' is kept as a root on the stack, and
|
||||
* so cannot be garbage collected while we are in the c_edit_file
|
||||
* function.
|
||||
*)
|
||||
c_edit_file (verbose ()) g (Guestfs.c_pointer g) file expr
|
19
virt/common/mlcustomize/perl_edit.mli
Normal file
19
virt/common/mlcustomize/perl_edit.mli
Normal file
@ -0,0 +1,19 @@
|
||||
(* virt-builder
|
||||
* Copyright (C) 2013 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 edit_file : Guestfs.t -> string -> string -> unit
|
109
virt/common/mlcustomize/random_seed.ml
Normal file
109
virt/common/mlcustomize/random_seed.ml
Normal file
@ -0,0 +1,109 @@
|
||||
(* virt-sysprep
|
||||
* Copyright (C) 2012-2023 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.
|
||||
*)
|
||||
|
||||
(* It's important that we write a random seed if we possibly can.
|
||||
* Unfortunately some installers (hello, Debian) don't include the file
|
||||
* in the basic guest, so we have to work out where to create it.
|
||||
*)
|
||||
let rec set_random_seed (g : Guestfs.guestfs) root =
|
||||
let typ = g#inspect_get_type root in
|
||||
let created = ref false in
|
||||
|
||||
if typ = "linux" then (
|
||||
let files = [
|
||||
"/var/lib/random-seed"; (* Fedora *)
|
||||
"/var/lib/systemd/random-seed"; (* Fedora after F20? *)
|
||||
"/var/lib/urandom/random-seed"; (* Debian *)
|
||||
"/var/lib/misc/random-seed"; (* SuSE *)
|
||||
"/etc/random-seed"; (* CirrOS *)
|
||||
] in
|
||||
List.iter (
|
||||
fun file ->
|
||||
if g#is_file file then (
|
||||
make_random_seed_file g file ~exists:true;
|
||||
created := true
|
||||
)
|
||||
) files;
|
||||
);
|
||||
|
||||
if not !created then (
|
||||
(* Backup plan: Try to create a new file. *)
|
||||
|
||||
let distro = g#inspect_get_distro root in
|
||||
let file =
|
||||
match typ, distro with
|
||||
| "linux", ("fedora"|"rhel"|"centos"|"scientificlinux"|"oraclelinux"|
|
||||
"rocky"|"redhat-based") ->
|
||||
Some "/var/lib/random-seed"
|
||||
| "linux", ("debian"|"ubuntu"|"kalilinux") ->
|
||||
Some "/var/lib/urandom/random-seed"
|
||||
| "linux", ("opensuse"|"sles"|"suse-based") ->
|
||||
Some "/var/lib/misc/random-seed"
|
||||
| "linux", "cirros" ->
|
||||
Some "/etc/random-seed"
|
||||
| _ ->
|
||||
None in
|
||||
match file with
|
||||
| Some file ->
|
||||
let dir =
|
||||
let i = String.rindex file '/' in
|
||||
String.sub file 0 i in
|
||||
if g#is_dir dir then (
|
||||
make_random_seed_file g file;
|
||||
created := true
|
||||
)
|
||||
| None -> ()
|
||||
);
|
||||
|
||||
!created
|
||||
|
||||
and make_random_seed_file ?exists g file =
|
||||
let file_exists =
|
||||
match exists with
|
||||
| None -> g#is_file file
|
||||
| Some b -> b in
|
||||
let n =
|
||||
if file_exists then (
|
||||
let n = Int64.to_int (g#filesize file) in
|
||||
|
||||
(* This file is usually 512 bytes in size. However during
|
||||
* guest creation of some guests it can be just 8 bytes long.
|
||||
* Cap the file size to [512, 8192] bytes.
|
||||
*)
|
||||
min (max n 512) 8192
|
||||
)
|
||||
else
|
||||
(* Default to 512 bytes of randomness. *)
|
||||
512 in
|
||||
|
||||
(* Get n bytes of randomness from the host. *)
|
||||
let entropy = Urandom.urandom_bytes n in
|
||||
|
||||
if file_exists then (
|
||||
(* Truncate the original file and append, in order to
|
||||
* preserve original permissions.
|
||||
*)
|
||||
g#truncate file;
|
||||
g#write_append file entropy
|
||||
)
|
||||
else (
|
||||
(* Create a new file, set the permissions restrictively. *)
|
||||
g#write file entropy;
|
||||
g#chown 0 0 file;
|
||||
g#chmod 0o600 file
|
||||
)
|
21
virt/common/mlcustomize/random_seed.mli
Normal file
21
virt/common/mlcustomize/random_seed.mli
Normal file
@ -0,0 +1,21 @@
|
||||
(* virt-sysprep
|
||||
* Copyright (C) 2012-2023 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 set_random_seed : Guestfs.guestfs -> string -> bool
|
||||
(** Set the random seed in the guest. Returns true if it was able to
|
||||
do set it, false if not. *)
|
137
virt/common/mlcustomize/ssh_key.ml
Normal file
137
virt/common/mlcustomize/ssh_key.ml
Normal file
@ -0,0 +1,137 @@
|
||||
(* virt-customize
|
||||
* 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.
|
||||
*)
|
||||
|
||||
open Printf
|
||||
open Sys
|
||||
open Unix
|
||||
|
||||
open Std_utils
|
||||
open Tools_utils
|
||||
open Common_gettext.Gettext
|
||||
|
||||
module G = Guestfs
|
||||
|
||||
type ssh_key_selector =
|
||||
| SystemKey
|
||||
| KeyFile of string
|
||||
| KeyString of string
|
||||
|
||||
let rec parse_selector arg =
|
||||
parse_selector_list arg (String.nsplit ":" arg)
|
||||
|
||||
and parse_selector_list orig_arg = function
|
||||
| [] | [ "" ] ->
|
||||
SystemKey
|
||||
| [ "file"; f ] ->
|
||||
KeyFile f
|
||||
| [ "string"; s ] ->
|
||||
KeyString s
|
||||
| _ ->
|
||||
error (f_"invalid ssh-inject selector ‘%s’; see the man page") orig_arg
|
||||
|
||||
(* Find the local [on the host] user's SSH public key. See
|
||||
* ssh-copy-id(1) default_ID_file for rationale.
|
||||
*)
|
||||
let pubkey_re = PCRE.compile "^id.*\\.pub$"
|
||||
let pubkey_ignore_re = PCRE.compile ".*-cert\\.pub$"
|
||||
|
||||
let local_user_ssh_pubkey () =
|
||||
let home_dir =
|
||||
try getenv "HOME"
|
||||
with Not_found ->
|
||||
error (f_"ssh-inject: $HOME environment variable is not set") in
|
||||
let ssh_dir = home_dir // ".ssh" in
|
||||
let files = Sys.readdir ssh_dir in
|
||||
let files = Array.to_list files in
|
||||
let files = List.filter (
|
||||
fun file ->
|
||||
PCRE.matches pubkey_re file && not (PCRE.matches pubkey_ignore_re file)
|
||||
) files in
|
||||
if files = [] then
|
||||
error (f_"ssh-inject: no public key file found in %s") ssh_dir;
|
||||
|
||||
(* Newest file. *)
|
||||
let files = List.map (
|
||||
fun file ->
|
||||
let file = ssh_dir // file in
|
||||
let stat = stat file in
|
||||
(file, stat.st_mtime)
|
||||
) files in
|
||||
let files = List.sort (fun (_,m1) (_,m2) -> compare m2 m1) files in
|
||||
|
||||
fst (List.hd files)
|
||||
|
||||
let read_key file =
|
||||
(* Read and return the public key. *)
|
||||
let key = read_whole_file file in
|
||||
if key = "" then
|
||||
error (f_"ssh-inject: public key file (%s) is empty") file;
|
||||
key
|
||||
|
||||
let key_string_from_selector = function
|
||||
| SystemKey ->
|
||||
read_key (local_user_ssh_pubkey ())
|
||||
| KeyFile f ->
|
||||
read_key f
|
||||
| KeyString s ->
|
||||
if String.length s < 1 then
|
||||
error (f_"ssh-inject: key is an empty string");
|
||||
s
|
||||
|
||||
(* Inject SSH key, where possible. *)
|
||||
let do_ssh_inject_unix (g : Guestfs.guestfs) user selector =
|
||||
let key = key_string_from_selector selector in
|
||||
assert (String.length key > 0);
|
||||
|
||||
(* If the key doesn't have \n at the end, add it. *)
|
||||
let len = String.length key in
|
||||
let key = if key.[len-1] = '\n' then key else key ^ "\n" in
|
||||
|
||||
(* Get user's home directory. *)
|
||||
g#aug_init "/" 0;
|
||||
let read_user_detail what =
|
||||
try
|
||||
let expr = sprintf "/files/etc/passwd/%s/%s" user what in
|
||||
g#aug_get expr
|
||||
with G.Error _ ->
|
||||
error (f_"ssh-inject: the user %s does not exist on the guest")
|
||||
user
|
||||
in
|
||||
let home_dir = read_user_detail "home" in
|
||||
let uid = int_of_string (read_user_detail "uid") in
|
||||
let gid = int_of_string (read_user_detail "gid") in
|
||||
g#aug_close ();
|
||||
|
||||
(* Create ~user/.ssh if it doesn't exist. *)
|
||||
let ssh_dir = sprintf "%s/.ssh" home_dir in
|
||||
if not (g#exists ssh_dir) then (
|
||||
g#mkdir ssh_dir;
|
||||
g#chmod 0o700 ssh_dir;
|
||||
g#chown uid gid ssh_dir;
|
||||
);
|
||||
|
||||
(* Create ~user/.ssh/authorized_keys if it doesn't exist. *)
|
||||
let auth_keys = sprintf "%s/authorized_keys" ssh_dir in
|
||||
if not (g#exists auth_keys) then (
|
||||
g#touch auth_keys;
|
||||
g#chmod 0o600 auth_keys;
|
||||
g#chown uid gid auth_keys;
|
||||
);
|
||||
|
||||
(* Append the key. *)
|
||||
g#write_append auth_keys key
|
32
virt/common/mlcustomize/ssh_key.mli
Normal file
32
virt/common/mlcustomize/ssh_key.mli
Normal file
@ -0,0 +1,32 @@
|
||||
(* virt-customize
|
||||
* 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.
|
||||
*)
|
||||
|
||||
type ssh_key_selector =
|
||||
| SystemKey (* Default key from the user in the system, in
|
||||
* the style of ssh-copy-id(1)/default_ID_file.
|
||||
*)
|
||||
| KeyFile of string (* Key from the specified file. *)
|
||||
| KeyString of string (* Key specified as string. *)
|
||||
|
||||
val parse_selector : string -> ssh_key_selector
|
||||
(** Parse the selector field in --ssh-inject. Note this
|
||||
doesn't parse the username part. Exits if the format is not valid. *)
|
||||
|
||||
val do_ssh_inject_unix : Guestfs.guestfs -> string -> ssh_key_selector -> unit
|
||||
(** Inject on a generic Unix system (Linux, FreeBSD, etc) the ssh key
|
||||
for the specified user. *)
|
54
virt/common/mlcustomize/subscription_manager.ml
Normal file
54
virt/common/mlcustomize/subscription_manager.ml
Normal file
@ -0,0 +1,54 @@
|
||||
(* virt-customize
|
||||
* Copyright (C) 2015 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 Tools_utils
|
||||
open Common_gettext.Gettext
|
||||
|
||||
type sm_credentials = {
|
||||
sm_username : string;
|
||||
sm_password : string;
|
||||
}
|
||||
|
||||
type sm_pool =
|
||||
| PoolAuto
|
||||
| PoolId of string
|
||||
|
||||
let rec parse_credentials_selector arg =
|
||||
parse_credentials_selector_list arg (String.nsplit ":" arg)
|
||||
|
||||
and parse_credentials_selector_list orig_arg = function
|
||||
| [ username; "password"; password ] ->
|
||||
{ sm_username = username; sm_password = password }
|
||||
| [ username; "file"; filename ] ->
|
||||
{ sm_username = username; sm_password = read_first_line_from_file filename }
|
||||
| _ ->
|
||||
error (f_"invalid sm-credentials selector ‘%s’; see the man page") orig_arg
|
||||
|
||||
let rec parse_pool_selector arg =
|
||||
parse_pool_selector_list arg (String.nsplit ":" arg)
|
||||
|
||||
and parse_pool_selector_list orig_arg = function
|
||||
| [ "auto" ] ->
|
||||
PoolAuto
|
||||
| [ "pool"; pool ] ->
|
||||
PoolId pool
|
||||
| [ "file"; filename ] ->
|
||||
PoolId (read_first_line_from_file filename)
|
||||
| _ ->
|
||||
error (f_"invalid sm-attach selector ‘%s’; see the man page") orig_arg
|
34
virt/common/mlcustomize/subscription_manager.mli
Normal file
34
virt/common/mlcustomize/subscription_manager.mli
Normal file
@ -0,0 +1,34 @@
|
||||
(* virt-customize
|
||||
* Copyright (C) 2015 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.
|
||||
*)
|
||||
|
||||
type sm_credentials = {
|
||||
sm_username : string;
|
||||
sm_password : string;
|
||||
}
|
||||
|
||||
type sm_pool =
|
||||
| PoolAuto (** Automatic entitlements. *)
|
||||
| PoolId of string (** Specific pool. *)
|
||||
|
||||
val parse_credentials_selector : string -> sm_credentials
|
||||
(** Parse the selector field in --sm-credentials. Exits if the format
|
||||
is not valid. *)
|
||||
|
||||
val parse_pool_selector : string -> sm_pool
|
||||
(** Parse the selector field in --sm-attach. Exits if the format
|
||||
is not valid. *)
|
143
virt/common/mlcustomize/test-firstboot.sh
Executable file
143
virt/common/mlcustomize/test-firstboot.sh
Executable file
@ -0,0 +1,143 @@
|
||||
#!/bin/bash -
|
||||
# Test firstboot functionality.
|
||||
# Copyright (C) 2016-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.
|
||||
|
||||
# This slow test checks that firstboot works.
|
||||
#
|
||||
# NB. 'test-firstboot.sh' runs the tests, but the various tests are
|
||||
# run via the 'test-firstboot-GUESTNAME.sh' wrappers.
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
$TEST_FUNCTIONS
|
||||
slow_test
|
||||
skip_if_skipped "$script"
|
||||
|
||||
guestname="$1"
|
||||
if [ -z "$guestname" ]; then
|
||||
echo "$script: guestname parameter not set, don't run this test directly."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
disk="firstboot-$guestname.img"
|
||||
rm -f "$disk"
|
||||
|
||||
# Undefine this which is set by ./run script, since we want to use the
|
||||
# public virt-builder templates.
|
||||
unset VIRT_BUILDER_DIRS
|
||||
|
||||
# If the guest doesn't exist in virt-builder, skip. This is because
|
||||
# we test some RHEL guests which most users won't have access to.
|
||||
skip_unless_virt_builder_guest "$guestname"
|
||||
|
||||
# We can only run the tests on x86_64.
|
||||
skip_unless_arch x86_64
|
||||
|
||||
# Check qemu is installed.
|
||||
qemu=qemu-system-x86_64
|
||||
skip_unless $qemu -help
|
||||
|
||||
# Some guests need special virt-builder parameters.
|
||||
# See virt-builder --notes "$guestname"
|
||||
declare -a extra
|
||||
case "$guestname" in
|
||||
debian-6|debian-7)
|
||||
extra[${#extra[*]}]='--edit'
|
||||
extra[${#extra[*]}]='/etc/inittab:
|
||||
s,^#([1-9].*respawn.*/sbin/getty.*),$1,'
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
||||
# Make the firstboot commands appropriate for the guest OS.
|
||||
#
|
||||
# We should test FreeBSD in future (XXX).
|
||||
declare -a commands
|
||||
case "$guestname" in
|
||||
windows-*)
|
||||
# Windows batch commands. Best to put them in a batch script.
|
||||
bat1=`mktemp`
|
||||
echo 'mkdir \fb1' > $bat1
|
||||
echo 'timeout 5' >> $bat1
|
||||
commands[${#commands[*]}]='--firstboot'
|
||||
commands[${#commands[*]}]=$bat1
|
||||
bat2=`mktemp`
|
||||
echo 'copy nul \fb1\fb2' > $bat2
|
||||
echo 'timeout 5' >> $bat2
|
||||
commands[${#commands[*]}]='--firstboot'
|
||||
commands[${#commands[*]}]=$bat2
|
||||
commands[${#commands[*]}]='--firstboot-command'
|
||||
commands[${#commands[*]}]='shutdown /s'
|
||||
|
||||
logfile="/Program Files/Guestfs/Firstboot/log.txt"
|
||||
;;
|
||||
*)
|
||||
# Assume any other guest is Linux.
|
||||
commands[${#commands[*]}]='--firstboot-command'
|
||||
commands[${#commands[*]}]='mkdir /fb1; sleep 5'
|
||||
commands[${#commands[*]}]='--firstboot-command'
|
||||
commands[${#commands[*]}]='touch /fb1/fb2; sleep 5'
|
||||
commands[${#commands[*]}]='--firstboot-command'
|
||||
commands[${#commands[*]}]='poweroff'
|
||||
|
||||
logfile="/root/virt-sysprep-firstboot.log"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Build a guest (using virt-builder) with some firstboot commands.
|
||||
virt-builder "$guestname" \
|
||||
--quiet \
|
||||
-o "$disk" \
|
||||
"${commands[@]}" \
|
||||
"${extra[@]}"
|
||||
|
||||
rm -f $bat1 $bat2
|
||||
|
||||
# Boot the guest in qemu and wait for the firstboot scripts to run.
|
||||
#
|
||||
# Use IDE because some ancient guests and Windows don't support
|
||||
# anything else.
|
||||
#
|
||||
# Adding a network device is not strictly necessary, but makes
|
||||
# the Debian 7 guest happier.
|
||||
$qemu \
|
||||
-no-user-config \
|
||||
-display none \
|
||||
-machine accel=kvm:tcg \
|
||||
-m 2048 \
|
||||
-boot c \
|
||||
-drive file="$disk",format=raw,if=ide \
|
||||
-netdev user,id=usernet \
|
||||
-device rtl8139,netdev=usernet \
|
||||
-serial stdio ||:
|
||||
|
||||
# Did the firstboot scripts run? And in the right order? We can tell
|
||||
# because the directory and file are created and so the 'stat'
|
||||
# commands should not fail in guestfish.
|
||||
guestfish --ro -a "$disk" -i \
|
||||
statns /fb1 : \
|
||||
statns /fb1/fb2 || failed=yes
|
||||
|
||||
# Get the log from the guest which may help debugging in case there
|
||||
# was an error.
|
||||
virt-cat -a "$disk" "$logfile"
|
||||
|
||||
if [ "$failed" = yes ]; then exit 1; fi
|
||||
|
||||
rm "$disk"
|
52
virt/common/mlcustomize/test-selinuxrelabel.sh
Executable file
52
virt/common/mlcustomize/test-selinuxrelabel.sh
Executable file
@ -0,0 +1,52 @@
|
||||
#!/bin/bash -
|
||||
# Test SELinux relabel functionality.
|
||||
# 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.
|
||||
|
||||
# This slow test checks that SELinux relabel works.
|
||||
|
||||
set -e
|
||||
|
||||
$TEST_FUNCTIONS
|
||||
slow_test
|
||||
|
||||
guestname="fedora-27"
|
||||
|
||||
disk="selinuxrelabel.img"
|
||||
disk_overlay="selinuxrelabel-overlay.qcow2"
|
||||
rm -f "$disk"
|
||||
|
||||
# Undefine this which is set by ./run script, since we want to use the
|
||||
# public virt-builder templates.
|
||||
unset VIRT_BUILDER_DIRS
|
||||
|
||||
skip_unless_virt_builder_guest "$guestname"
|
||||
|
||||
# Build a guest (using virt-builder).
|
||||
virt-builder "$guestname" --quiet -o "$disk"
|
||||
|
||||
# Test #1: relabel with the default configuration works.
|
||||
rm -f "$disk_overlay"
|
||||
guestfish -- disk-create "$disk_overlay" qcow2 -1 backingfile:"$disk"
|
||||
virt-customize -a "$disk"
|
||||
|
||||
# Test #2: relabel with no SELINUXTYPE in the configuration.
|
||||
rm -f "$disk_overlay"
|
||||
guestfish -- disk-create "$disk_overlay" qcow2 -1 backingfile:"$disk"
|
||||
virt-customize -a "$disk" \
|
||||
--edit /etc/selinux/config:"s,^SELINUXTYPE=,#&,g"
|
||||
|
||||
rm "$disk" "$disk_overlay"
|
41
virt/common/mlcustomize/timezone.ml
Normal file
41
virt/common/mlcustomize/timezone.ml
Normal file
@ -0,0 +1,41 @@
|
||||
(* Set timezone in virt-sysprep and virt-builder.
|
||||
* 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.
|
||||
*)
|
||||
|
||||
open Tools_utils
|
||||
open Common_gettext.Gettext
|
||||
|
||||
open Printf
|
||||
|
||||
let set_timezone (g : Guestfs.guestfs) root timezone =
|
||||
let typ = g#inspect_get_type root in
|
||||
|
||||
match typ with
|
||||
(* Every known Linux has /etc/localtime be either a copy of or a
|
||||
* symlink to a timezone file in /usr/share/zoneinfo.
|
||||
* Even systemd didn't fuck this up.
|
||||
*)
|
||||
| "linux" ->
|
||||
let target = sprintf "/usr/share/zoneinfo/%s" timezone in
|
||||
if not (g#exists target) then
|
||||
error (f_"timezone '%s' does not exist, use a location like \
|
||||
'Europe/London'") timezone;
|
||||
g#ln_sf target "/etc/localtime";
|
||||
true
|
||||
|
||||
| _ ->
|
||||
false
|
22
virt/common/mlcustomize/timezone.mli
Normal file
22
virt/common/mlcustomize/timezone.mli
Normal file
@ -0,0 +1,22 @@
|
||||
(* Set timezone in virt-sysprep and virt-builder.
|
||||
* 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.
|
||||
*)
|
||||
|
||||
val set_timezone : Guestfs.guestfs -> string -> string -> bool
|
||||
(** [set_timezone g root "Europe/London"] sets the default timezone
|
||||
of the guest. Returns [true] if it was able to set the
|
||||
timezone or [false] if not. *)
|
445
virt/common/mlcustomize/v2v-customize-options.pod
Normal file
445
virt/common/mlcustomize/v2v-customize-options.pod
Normal file
@ -0,0 +1,445 @@
|
||||
=begin comment
|
||||
|
||||
libguestfs generated file
|
||||
WARNING: THIS FILE IS GENERATED FROM THE FOLLOWING FILES:
|
||||
generator/customize.ml
|
||||
and from the code in the generator/ subdirectory.
|
||||
ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.
|
||||
|
||||
Copyright (C) 2009-2023 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.
|
||||
|
||||
=end comment
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<--append-line> FILE:LINE
|
||||
|
||||
Append a single line of text to the C<FILE>. If the file does not already
|
||||
end with a newline, then one is added before the appended
|
||||
line. Also a newline is added to the end of the C<LINE> string
|
||||
automatically.
|
||||
|
||||
For example (assuming ordinary shell quoting) this command:
|
||||
|
||||
--append-line '/etc/hosts:10.0.0.1 foo'
|
||||
|
||||
will add either C<10.0.0.1 foo⏎> or C<⏎10.0.0.1 foo⏎> to
|
||||
the file, the latter only if the existing file does not
|
||||
already end with a newline.
|
||||
|
||||
C<⏎> represents a newline character, which is guessed by
|
||||
looking at the existing content of the file, so this command
|
||||
does the right thing for files using Unix or Windows line endings.
|
||||
It also works for empty or non-existent files.
|
||||
|
||||
To insert several lines, use the same option several times:
|
||||
|
||||
--append-line '/etc/hosts:10.0.0.1 foo'
|
||||
--append-line '/etc/hosts:10.0.0.2 bar'
|
||||
|
||||
To insert a blank line before the appended line, do:
|
||||
|
||||
--append-line '/etc/hosts:'
|
||||
--append-line '/etc/hosts:10.0.0.1 foo'
|
||||
|
||||
=item B<--chmod> PERMISSIONS:FILE
|
||||
|
||||
Change the permissions of C<FILE> to C<PERMISSIONS>.
|
||||
|
||||
I<Note>: C<PERMISSIONS> by default would be decimal, unless you prefix
|
||||
it with C<0> to get octal, ie. use C<0700> not C<700>.
|
||||
|
||||
=item B<--chown> UID:GID:PATH
|
||||
|
||||
Change the owner user and group ID of a file or directory in the guest.
|
||||
Note:
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
Only numeric UIDs and GIDs will work, and these may not be the same
|
||||
inside the guest as on the host.
|
||||
|
||||
=item *
|
||||
|
||||
This will not work with Windows guests.
|
||||
|
||||
=back
|
||||
|
||||
For example:
|
||||
|
||||
virt-customize --chown '0:0:/var/log/audit.log'
|
||||
|
||||
See also: I<--upload>.
|
||||
|
||||
=item B<--commands-from-file> FILENAME
|
||||
|
||||
Read the customize commands from a file, one (and its arguments)
|
||||
each line.
|
||||
|
||||
Each line contains a single customization command and its arguments,
|
||||
for example:
|
||||
|
||||
delete /some/file
|
||||
install some-package
|
||||
password some-user:password:its-new-password
|
||||
|
||||
Empty lines are ignored, and lines starting with C<#> are comments
|
||||
and are ignored as well. Furthermore, arguments can be spread across
|
||||
multiple lines, by adding a C<\> (continuation character) at the of
|
||||
a line, for example
|
||||
|
||||
edit /some/file:\
|
||||
s/^OPT=.*/OPT=ok/
|
||||
|
||||
The commands are handled in the same order as they are in the file,
|
||||
as if they were specified as I<--delete /some/file> on the command
|
||||
line.
|
||||
|
||||
=item B<--copy> SOURCE:DEST
|
||||
|
||||
Copy files or directories recursively inside the guest.
|
||||
|
||||
Wildcards cannot be used.
|
||||
|
||||
=item B<--copy-in> LOCALPATH:REMOTEDIR
|
||||
|
||||
Copy local files or directories recursively into the disk image,
|
||||
placing them in the directory C<REMOTEDIR> (which must exist).
|
||||
|
||||
Wildcards cannot be used.
|
||||
|
||||
=item B<--delete> PATH
|
||||
|
||||
Delete a file from the guest. Or delete a directory (and all its
|
||||
contents, recursively).
|
||||
|
||||
You can use shell glob characters in the specified path. Be careful
|
||||
to escape glob characters from the host shell, if that is required.
|
||||
For example:
|
||||
|
||||
virt-customize --delete '/var/log/*.log'.
|
||||
|
||||
See also: I<--upload>, I<--scrub>.
|
||||
|
||||
=item B<--edit> FILE:EXPR
|
||||
|
||||
Edit C<FILE> using the Perl expression C<EXPR>.
|
||||
|
||||
Be careful to properly quote the expression to prevent it from
|
||||
being altered by the shell.
|
||||
|
||||
Note that this option is only available when Perl 5 is installed.
|
||||
|
||||
See L<virt-edit(1)/NON-INTERACTIVE EDITING>.
|
||||
|
||||
=item B<--firstboot> SCRIPT
|
||||
|
||||
Install C<SCRIPT> inside the guest, so that when the guest first boots
|
||||
up, the script runs (as root, late in the boot process).
|
||||
|
||||
The script is automatically chmod +x after installation in the guest.
|
||||
|
||||
The alternative version I<--firstboot-command> is the same, but it
|
||||
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<virt-builder(1)/FIRST BOOT SCRIPTS> for more
|
||||
information and caveats about the first boot scripts.
|
||||
|
||||
See also I<--run>.
|
||||
|
||||
=item B<--firstboot-command> 'CMD+ARGS'
|
||||
|
||||
Run command (and arguments) inside the guest when the guest first
|
||||
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<virt-builder(1)/FIRST BOOT SCRIPTS> for more
|
||||
information and caveats about the first boot scripts.
|
||||
|
||||
See also I<--run>.
|
||||
|
||||
=item B<--firstboot-install> PKG,PKG..
|
||||
|
||||
Install the named packages (a comma-separated list). These are
|
||||
installed when the guest first boots using the guest’s package manager
|
||||
(eg. apt, yum, etc.) and the guest’s network connection.
|
||||
|
||||
For an overview on the different ways to install packages, see
|
||||
L<virt-builder(1)/INSTALLING PACKAGES>.
|
||||
|
||||
=item B<--hostname> HOSTNAME
|
||||
|
||||
Set the hostname of the guest to C<HOSTNAME>. You can use a
|
||||
dotted hostname.domainname (FQDN) if you want.
|
||||
|
||||
=item B<--install> PKG,PKG..
|
||||
|
||||
Install the named packages (a comma-separated list). These are
|
||||
installed during the image build using the guest’s package manager
|
||||
(eg. apt, yum, etc.) and the host’s network connection.
|
||||
|
||||
For an overview on the different ways to install packages, see
|
||||
L<virt-builder(1)/INSTALLING PACKAGES>.
|
||||
|
||||
See also I<--update>, I<--uninstall>.
|
||||
|
||||
=item B<--link> TARGET:LINK[:LINK..]
|
||||
|
||||
Create symbolic link(s) in the guest, starting at C<LINK> and
|
||||
pointing at C<TARGET>.
|
||||
|
||||
=item B<--mkdir> DIR
|
||||
|
||||
Create a directory in the guest.
|
||||
|
||||
This uses S<C<mkdir -p>> so any intermediate directories are created,
|
||||
and it also works if the directory already exists.
|
||||
|
||||
=item B<--move> SOURCE:DEST
|
||||
|
||||
Move files or directories inside the guest.
|
||||
|
||||
Wildcards cannot be used.
|
||||
|
||||
=item B<--no-logfile>
|
||||
|
||||
Scrub C<builder.log> (log file from build commands) from the image
|
||||
after building is complete. If you don't want to reveal precisely how
|
||||
the image was built, use this option.
|
||||
|
||||
See also: L</LOG FILE>.
|
||||
|
||||
=item B<--no-selinux-relabel>
|
||||
|
||||
Do not attempt to correct the SELinux labels of files in the guest.
|
||||
|
||||
In such guests that support SELinux, customization automatically
|
||||
relabels files so that they have the correct SELinux label. (The
|
||||
relabeling is performed immediately, but if the operation fails,
|
||||
customization will instead touch F</.autorelabel> on the image to
|
||||
schedule a relabel operation for the next time the image boots.) This
|
||||
option disables the automatic relabeling.
|
||||
|
||||
The option is a no-op for guests that do not support SELinux.
|
||||
|
||||
=item B<--password> USER:SELECTOR
|
||||
|
||||
Set the password for C<USER>. (Note this option does I<not>
|
||||
create the user account).
|
||||
|
||||
See L<virt-builder(1)/USERS AND PASSWORDS> for the format of
|
||||
the C<SELECTOR> field, and also how to set up user accounts.
|
||||
|
||||
=item B<--password-crypto> md5|sha256|sha512
|
||||
|
||||
When the virt tools change or set a password in the guest, this
|
||||
option sets the password encryption of that password to
|
||||
C<md5>, C<sha256> or C<sha512>.
|
||||
|
||||
C<sha256> and C<sha512> require glibc E<ge> 2.7 (check crypt(3) inside
|
||||
the guest).
|
||||
|
||||
C<md5> will work with relatively old Linux guests (eg. RHEL 3), but
|
||||
is not secure against modern attacks.
|
||||
|
||||
The default is C<sha512> unless libguestfs detects an old guest that
|
||||
didn't have support for SHA-512, in which case it will use C<md5>.
|
||||
You can override libguestfs by specifying this option.
|
||||
|
||||
Note this does not change the default password encryption used
|
||||
by the guest when you create new user accounts inside the guest.
|
||||
If you want to do that, then you should use the I<--edit> option
|
||||
to modify C</etc/sysconfig/authconfig> (Fedora, RHEL) or
|
||||
C</etc/pam.d/common-password> (Debian, Ubuntu).
|
||||
|
||||
=item B<--root-password> SELECTOR
|
||||
|
||||
Set the root password.
|
||||
|
||||
See L<virt-builder(1)/USERS AND PASSWORDS> for the format of
|
||||
the C<SELECTOR> field, and also how to set up user accounts.
|
||||
|
||||
Note: In virt-builder, if you I<don't> set I<--root-password>
|
||||
then the guest is given a I<random> root password.
|
||||
|
||||
=item B<--run> SCRIPT
|
||||
|
||||
Run the shell script (or any program) called C<SCRIPT> on the disk
|
||||
image. The script runs virtualized inside a small appliance, chrooted
|
||||
into the guest filesystem.
|
||||
|
||||
The script is automatically chmod +x.
|
||||
|
||||
If libguestfs supports it then a limited network connection is
|
||||
available but it only allows outgoing network connections. You can
|
||||
also attach data disks (eg. ISO files) as another way to provide data
|
||||
(eg. software packages) to the script without needing a network
|
||||
connection (I<--attach>). You can also upload data files (I<--upload>).
|
||||
|
||||
You can have multiple I<--run> options. They run
|
||||
in the same order that they appear on the command line.
|
||||
|
||||
See also: I<--firstboot>, I<--attach>, I<--upload>.
|
||||
|
||||
=item B<--run-command> 'CMD+ARGS'
|
||||
|
||||
Run the command and arguments on the disk image. The command runs
|
||||
virtualized inside a small appliance, chrooted into the guest filesystem.
|
||||
|
||||
If libguestfs supports it then a limited network connection is
|
||||
available but it only allows outgoing network connections. You can
|
||||
also attach data disks (eg. ISO files) as another way to provide data
|
||||
(eg. software packages) to the script without needing a network
|
||||
connection (I<--attach>). You can also upload data files (I<--upload>).
|
||||
|
||||
You can have multiple I<--run-command> options. They run
|
||||
in the same order that they appear on the command line.
|
||||
|
||||
See also: I<--firstboot>, I<--attach>, I<--upload>.
|
||||
|
||||
=item B<--scrub> FILE
|
||||
|
||||
Scrub a file from the guest. This is like I<--delete> except that:
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
It scrubs the data so a guest could not recover it.
|
||||
|
||||
=item *
|
||||
|
||||
It cannot delete directories, only regular files.
|
||||
|
||||
=back
|
||||
|
||||
=item B<--selinux-relabel>
|
||||
|
||||
This is a compatibility option that does nothing.
|
||||
|
||||
=item B<--sm-attach> SELECTOR
|
||||
|
||||
Attach to a pool using C<subscription-manager>.
|
||||
|
||||
See L<virt-builder(1)/SUBSCRIPTION-MANAGER> for the format of
|
||||
the C<SELECTOR> field.
|
||||
|
||||
=item B<--sm-credentials> SELECTOR
|
||||
|
||||
Set the credentials for C<subscription-manager>.
|
||||
|
||||
See L<virt-builder(1)/SUBSCRIPTION-MANAGER> for the format of
|
||||
the C<SELECTOR> field.
|
||||
|
||||
=item B<--sm-register>
|
||||
|
||||
Register the guest using C<subscription-manager>.
|
||||
|
||||
This requires credentials being set using I<--sm-credentials>.
|
||||
|
||||
=item B<--sm-remove>
|
||||
|
||||
Remove all the subscriptions from the guest using
|
||||
C<subscription-manager>.
|
||||
|
||||
=item B<--sm-unregister>
|
||||
|
||||
Unregister the guest using C<subscription-manager>.
|
||||
|
||||
=item B<--ssh-inject> USER[:SELECTOR]
|
||||
|
||||
Inject an ssh key so the given C<USER> will be able to log in over
|
||||
ssh without supplying a password. The C<USER> must exist already
|
||||
in the guest.
|
||||
|
||||
See L<virt-builder(1)/SSH KEYS> for the format of
|
||||
the C<SELECTOR> field.
|
||||
|
||||
You can have multiple I<--ssh-inject> options, for different users
|
||||
and also for more keys for each user.
|
||||
|
||||
=item B<--tar-in> TARFILE:REMOTEDIR
|
||||
|
||||
Copy local files or directories from a local tar file
|
||||
called C<TARFILE> into the disk image, placing them in the
|
||||
directory C<REMOTEDIR> (which must exist). Note that
|
||||
the tar file must be uncompressed (F<.tar.gz> files will not work
|
||||
here)
|
||||
|
||||
=item B<--timezone> TIMEZONE
|
||||
|
||||
Set the default timezone of the guest to C<TIMEZONE>. Use a location
|
||||
string like C<Europe/London>
|
||||
|
||||
=item B<--touch> FILE
|
||||
|
||||
This command performs a L<touch(1)>-like operation on C<FILE>.
|
||||
|
||||
=item B<--truncate> FILE
|
||||
|
||||
This command truncates C<FILE> to a zero-length file. The file must exist
|
||||
already.
|
||||
|
||||
=item B<--truncate-recursive> PATH
|
||||
|
||||
This command recursively truncates all files under C<PATH> to zero-length.
|
||||
|
||||
=item B<--uninstall> PKG,PKG..
|
||||
|
||||
Uninstall the named packages (a comma-separated list). These are
|
||||
removed during the image build using the guest’s package manager
|
||||
(eg. apt, yum, etc.). Dependent packages may also need to be
|
||||
uninstalled to satisfy the request.
|
||||
|
||||
See also I<--install>, I<--update>.
|
||||
|
||||
=item B<--update>
|
||||
|
||||
Do the equivalent of C<yum update>, C<apt-get upgrade>, or whatever
|
||||
command is required to update the packages already installed in the
|
||||
template to their latest versions.
|
||||
|
||||
See also I<--install>, I<--uninstall>.
|
||||
|
||||
=item B<--upload> FILE:DEST
|
||||
|
||||
Upload local file C<FILE> to destination C<DEST> in the disk image.
|
||||
File owner and permissions from the original are preserved, so you
|
||||
should set them to what you want them to be in the disk image.
|
||||
|
||||
C<DEST> could be the final filename. This can be used to rename
|
||||
the file on upload.
|
||||
|
||||
If C<DEST> is a directory name (which must already exist in the guest)
|
||||
then the file is uploaded into that directory, and it keeps the same
|
||||
name as on the local filesystem.
|
||||
|
||||
See also: I<--mkdir>, I<--delete>, I<--scrub>.
|
||||
|
||||
=item B<--write> FILE:CONTENT
|
||||
|
||||
Write C<CONTENT> to C<FILE>.
|
||||
|
||||
=back
|
||||
|
17
virt/common/mlcustomize/v2v-customize-synopsis.pod
Normal file
17
virt/common/mlcustomize/v2v-customize-synopsis.pod
Normal file
@ -0,0 +1,17 @@
|
||||
[--append-line FILE:LINE] [--chmod PERMISSIONS:FILE]
|
||||
[--chown UID:GID:PATH] [--commands-from-file FILENAME]
|
||||
[--copy SOURCE:DEST] [--copy-in LOCALPATH:REMOTEDIR]
|
||||
[--delete PATH] [--edit FILE:EXPR] [--firstboot SCRIPT]
|
||||
[--firstboot-command 'CMD+ARGS'] [--firstboot-install PKG,PKG..]
|
||||
[--hostname HOSTNAME] [--install PKG,PKG..]
|
||||
[--link TARGET:LINK[:LINK..]] [--mkdir DIR] [--move SOURCE:DEST]
|
||||
[--password USER:SELECTOR] [--root-password SELECTOR]
|
||||
[--run SCRIPT] [--run-command 'CMD+ARGS'] [--scrub FILE]
|
||||
[--sm-attach SELECTOR] [--sm-register] [--sm-remove]
|
||||
[--sm-unregister] [--ssh-inject USER[:SELECTOR]]
|
||||
[--tar-in TARFILE:REMOTEDIR] [--timezone TIMEZONE] [--touch FILE]
|
||||
[--truncate FILE] [--truncate-recursive PATH]
|
||||
[--uninstall PKG,PKG..] [--update] [--upload FILE:DEST]
|
||||
[--write FILE:CONTENT] [--no-logfile]
|
||||
[--password-crypto md5|sha256|sha512] [--no-selinux-relabel]
|
||||
[--selinux-relabel] [--sm-credentials SELECTOR]
|
102
virt/common/mldrivers/Makefile.am
Normal file
102
virt/common/mldrivers/Makefile.am
Normal file
@ -0,0 +1,102 @@
|
||||
# Common code for driver detection used by virt-drivers and virt-v2v
|
||||
# Copyright (C) 2011-2023 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 $(top_srcdir)/subdir-rules.mk
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(SOURCES_MLI) \
|
||||
$(SOURCES_ML) \
|
||||
$(SOURCES_C)
|
||||
|
||||
SOURCES_MLI = \
|
||||
firmware.mli \
|
||||
linux.mli \
|
||||
linux_bootloaders.mli \
|
||||
linux_kernels.mli \
|
||||
windows_drivers.mli
|
||||
|
||||
SOURCES_ML = \
|
||||
firmware.ml \
|
||||
linux.ml \
|
||||
linux_bootloaders.ml \
|
||||
linux_kernels.ml \
|
||||
windows_drivers.ml
|
||||
|
||||
SOURCES_C = \
|
||||
dummy.c
|
||||
|
||||
# We pretend that we're building a C library. automake handles the
|
||||
# compilation of the C sources for us. At the end we take the C
|
||||
# objects and OCaml objects and link them into the OCaml library.
|
||||
# This C library is never used.
|
||||
|
||||
noinst_LIBRARIES = libmldrivers.a
|
||||
|
||||
if !HAVE_OCAMLOPT
|
||||
MLDRIVERS_CMA = mldrivers.cma
|
||||
else
|
||||
MLDRIVERS_CMA = mldrivers.cmxa
|
||||
endif
|
||||
|
||||
noinst_DATA = $(MLDRIVERS_CMA)
|
||||
|
||||
libmldrivers_a_SOURCES = $(SOURCES_C)
|
||||
libmldrivers_a_CPPFLAGS = \
|
||||
-DCAML_NAME_SPACE \
|
||||
-I. \
|
||||
-I$(top_builddir) \
|
||||
-I$(shell $(OCAMLC) -where) \
|
||||
-I$(top_srcdir)/common/mlgettext \
|
||||
-I$(top_srcdir)/common/mlpcre \
|
||||
-I$(top_srcdir)/common/mlstdutils \
|
||||
-I$(top_srcdir)/common/mltools
|
||||
libmldrivers_a_CFLAGS = \
|
||||
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
|
||||
-fPIC
|
||||
|
||||
BOBJECTS = $(SOURCES_ML:.ml=.cmo)
|
||||
XOBJECTS = $(BOBJECTS:.cmo=.cmx)
|
||||
|
||||
OCAMLPACKAGES = \
|
||||
-package str,unix,guestfs \
|
||||
-I $(top_builddir)/common/mlgettext \
|
||||
-I $(top_builddir)/common/mlpcre \
|
||||
-I $(top_builddir)/common/mlstdutils \
|
||||
-I $(top_builddir)/common/mltools \
|
||||
-I $(builddir)
|
||||
OCAMLPACKAGES_TESTS = $(MLDRIVERS_CMA)
|
||||
|
||||
OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
|
||||
|
||||
if !HAVE_OCAMLOPT
|
||||
OBJECTS = $(BOBJECTS)
|
||||
else
|
||||
OBJECTS = $(XOBJECTS)
|
||||
endif
|
||||
|
||||
libmldrivers_a_DEPENDENCIES = $(OBJECTS)
|
||||
|
||||
$(MLDRIVERS_CMA): $(OBJECTS) libmldrivers.a
|
||||
$(OCAMLFIND) mklib $(OCAMLPACKAGES) \
|
||||
$(OBJECTS) $(libmldrivers_a_OBJECTS) -o mldrivers
|
||||
|
||||
# OCaml dependencies.
|
||||
.depend: $(srcdir)/*.mli $(srcdir)/*.ml
|
||||
$(top_builddir)/ocaml-dep.sh $^
|
||||
-include .depend
|
||||
|
||||
.PHONY: docs
|
942
virt/common/mldrivers/Makefile.in
Normal file
942
virt/common/mldrivers/Makefile.in
Normal file
@ -0,0 +1,942 @@
|
||||
# Makefile.in generated by automake 1.16.5 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
# Common code for driver detection used by virt-drivers and virt-v2v
|
||||
# Copyright (C) 2011-2023 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.
|
||||
|
||||
# libguestfs
|
||||
# Copyright (C) 2009-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.
|
||||
|
||||
# subdir-rules.mk should be included in every *subdirectory* Makefile.am.
|
||||
|
||||
# libguestfs
|
||||
# Copyright (C) 2013 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.
|
||||
|
||||
# 'common-rules.mk' should be included in every Makefile.am.
|
||||
# cf. 'subdir-rules.mk'
|
||||
|
||||
|
||||
VPATH = @srcdir@
|
||||
am__is_gnu_make = { \
|
||||
if test -z '$(MAKELEVEL)'; then \
|
||||
false; \
|
||||
elif test -n '$(MAKE_HOST)'; then \
|
||||
true; \
|
||||
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
||||
true; \
|
||||
else \
|
||||
false; \
|
||||
fi; \
|
||||
}
|
||||
am__make_running_with_option = \
|
||||
case $${target_option-} in \
|
||||
?) ;; \
|
||||
*) echo "am__make_running_with_option: internal error: invalid" \
|
||||
"target option '$${target_option-}' specified" >&2; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
has_opt=no; \
|
||||
sane_makeflags=$$MAKEFLAGS; \
|
||||
if $(am__is_gnu_make); then \
|
||||
sane_makeflags=$$MFLAGS; \
|
||||
else \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
bs=\\; \
|
||||
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
|
||||
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
|
||||
esac; \
|
||||
fi; \
|
||||
skip_next=no; \
|
||||
strip_trailopt () \
|
||||
{ \
|
||||
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
|
||||
}; \
|
||||
for flg in $$sane_makeflags; do \
|
||||
test $$skip_next = yes && { skip_next=no; continue; }; \
|
||||
case $$flg in \
|
||||
*=*|--*) continue;; \
|
||||
-*I) strip_trailopt 'I'; skip_next=yes;; \
|
||||
-*I?*) strip_trailopt 'I';; \
|
||||
-*O) strip_trailopt 'O'; skip_next=yes;; \
|
||||
-*O?*) strip_trailopt 'O';; \
|
||||
-*l) strip_trailopt 'l'; skip_next=yes;; \
|
||||
-*l?*) strip_trailopt 'l';; \
|
||||
-[dEDm]) skip_next=yes;; \
|
||||
-[JT]) skip_next=yes;; \
|
||||
esac; \
|
||||
case $$flg in \
|
||||
*$$target_option*) has_opt=yes; break;; \
|
||||
esac; \
|
||||
done; \
|
||||
test $$has_opt = yes
|
||||
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
|
||||
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
subdir = common/mldrivers
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/guestfs-ocaml-gettext.m4 \
|
||||
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
|
||||
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
|
||||
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ocaml.m4 \
|
||||
$(top_srcdir)/m4/guestfs-progs.m4 \
|
||||
$(top_srcdir)/m4/guestfs-c.m4 \
|
||||
$(top_srcdir)/m4/guestfs-libraries.m4 \
|
||||
$(top_srcdir)/m4/guestfs-ocaml.m4 \
|
||||
$(top_srcdir)/m4/guestfs-perl.m4 \
|
||||
$(top_srcdir)/m4/guestfs-v2v.m4 \
|
||||
$(top_srcdir)/m4/guestfs-bash-completion.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
LIBRARIES = $(noinst_LIBRARIES)
|
||||
ARFLAGS = cru
|
||||
AM_V_AR = $(am__v_AR_@AM_V@)
|
||||
am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
|
||||
am__v_AR_0 = @echo " AR " $@;
|
||||
am__v_AR_1 =
|
||||
libmldrivers_a_AR = $(AR) $(ARFLAGS)
|
||||
libmldrivers_a_LIBADD =
|
||||
am__objects_1 = libmldrivers_a-dummy.$(OBJEXT)
|
||||
am_libmldrivers_a_OBJECTS = $(am__objects_1)
|
||||
libmldrivers_a_OBJECTS = $(am_libmldrivers_a_OBJECTS)
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
|
||||
am__v_P_0 = false
|
||||
am__v_P_1 = :
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
am__v_GEN_1 =
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
am__v_at_1 =
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
|
||||
depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
|
||||
am__maybe_remake_depfiles = depfiles
|
||||
am__depfiles_remade = ./$(DEPDIR)/libmldrivers_a-dummy.Po
|
||||
am__mv = mv -f
|
||||
AM_V_lt = $(am__v_lt_@AM_V@)
|
||||
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
|
||||
am__v_lt_0 = --silent
|
||||
am__v_lt_1 =
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
|
||||
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
|
||||
$(AM_CFLAGS) $(CFLAGS)
|
||||
AM_V_CC = $(am__v_CC_@AM_V@)
|
||||
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
|
||||
am__v_CC_0 = @echo " CC " $@;
|
||||
am__v_CC_1 =
|
||||
CCLD = $(CC)
|
||||
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
$(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
|
||||
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
|
||||
am__v_CCLD_0 = @echo " CCLD " $@;
|
||||
am__v_CCLD_1 =
|
||||
SOURCES = $(libmldrivers_a_SOURCES)
|
||||
DIST_SOURCES = $(libmldrivers_a_SOURCES)
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
DATA = $(noinst_DATA)
|
||||
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
|
||||
# Read a list of newline-separated strings from the standard input,
|
||||
# and print each of them once, without duplicates. Input order is
|
||||
# *not* preserved.
|
||||
am__uniquify_input = $(AWK) '\
|
||||
BEGIN { nonempty = 0; } \
|
||||
{ items[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in items) print i; }; } \
|
||||
'
|
||||
# Make sure the list of sources is unique. This is necessary because,
|
||||
# e.g., the same source file might be shared among _SOURCES variables
|
||||
# for different programs/libraries.
|
||||
am__define_uniq_tagged_files = \
|
||||
list='$(am__tagged_files)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | $(am__uniquify_input)`
|
||||
am__DIST_COMMON = $(srcdir)/Makefile.in \
|
||||
$(top_srcdir)/build-aux/depcomp $(top_srcdir)/common-rules.mk \
|
||||
$(top_srcdir)/subdir-rules.mk
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
BASH_COMPLETIONS_DIR = @BASH_COMPLETIONS_DIR@
|
||||
BASH_COMPLETION_CFLAGS = @BASH_COMPLETION_CFLAGS@
|
||||
BASH_COMPLETION_LIBS = @BASH_COMPLETION_LIBS@
|
||||
BRANCH_NUMBER = @BRANCH_NUMBER@
|
||||
BRANCH_TYPE = @BRANCH_TYPE@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CSCOPE = @CSCOPE@
|
||||
CTAGS = @CTAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
ETAGS = @ETAGS@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
FILECMD = @FILECMD@
|
||||
GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
|
||||
GMSGFMT = @GMSGFMT@
|
||||
GMSGFMT_015 = @GMSGFMT_015@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
INTLLIBS = @INTLLIBS@
|
||||
INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
|
||||
JANSSON_CFLAGS = @JANSSON_CFLAGS@
|
||||
JANSSON_LIBS = @JANSSON_LIBS@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBCRYPT_CFLAGS = @LIBCRYPT_CFLAGS@
|
||||
LIBCRYPT_LIBS = @LIBCRYPT_LIBS@
|
||||
LIBGUESTFS_CFLAGS = @LIBGUESTFS_CFLAGS@
|
||||
LIBGUESTFS_LIBS = @LIBGUESTFS_LIBS@
|
||||
LIBICONV = @LIBICONV@
|
||||
LIBINTL = @LIBINTL@
|
||||
LIBNBD_CFLAGS = @LIBNBD_CFLAGS@
|
||||
LIBNBD_LIBS = @LIBNBD_LIBS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBOSINFO_CFLAGS = @LIBOSINFO_CFLAGS@
|
||||
LIBOSINFO_LIBS = @LIBOSINFO_LIBS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIBVIRT_CFLAGS = @LIBVIRT_CFLAGS@
|
||||
LIBVIRT_LIBS = @LIBVIRT_LIBS@
|
||||
LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
|
||||
LIBXML2_LIBS = @LIBXML2_LIBS@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBICONV = @LTLIBICONV@
|
||||
LTLIBINTL = @LTLIBINTL@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
MKISOFS = @MKISOFS@
|
||||
MSGCAT = @MSGCAT@
|
||||
MSGFMT = @MSGFMT@
|
||||
MSGMERGE = @MSGMERGE@
|
||||
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
|
||||
NBDCOPY = @NBDCOPY@
|
||||
NBDINFO = @NBDINFO@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OCAMLBEST = @OCAMLBEST@
|
||||
OCAMLBUILD = @OCAMLBUILD@
|
||||
OCAMLC = @OCAMLC@
|
||||
OCAMLCDOTOPT = @OCAMLCDOTOPT@
|
||||
OCAMLDEP = @OCAMLDEP@
|
||||
OCAMLDOC = @OCAMLDOC@
|
||||
OCAMLFIND = @OCAMLFIND@
|
||||
OCAMLLIB = @OCAMLLIB@
|
||||
OCAMLMKLIB = @OCAMLMKLIB@
|
||||
OCAMLMKTOP = @OCAMLMKTOP@
|
||||
OCAMLOPT = @OCAMLOPT@
|
||||
OCAMLOPTDOTOPT = @OCAMLOPTDOTOPT@
|
||||
OCAMLVERSION = @OCAMLVERSION@
|
||||
OCAML_FLAGS = @OCAML_FLAGS@
|
||||
OCAML_GETTEXT = @OCAML_GETTEXT@
|
||||
OCAML_PKG_gettext = @OCAML_PKG_gettext@
|
||||
OCAML_PKG_guestfs = @OCAML_PKG_guestfs@
|
||||
OCAML_PKG_libvirt = @OCAML_PKG_libvirt@
|
||||
OCAML_PKG_nbd = @OCAML_PKG_nbd@
|
||||
OCAML_PKG_ounit2 = @OCAML_PKG_ounit2@
|
||||
OCAML_RUNTIME_VARIANT_PIC_OPTION = @OCAML_RUNTIME_VARIANT_PIC_OPTION@
|
||||
OCAML_WARN_ERROR = @OCAML_WARN_ERROR@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PACKAGE_VERSION_FULL = @PACKAGE_VERSION_FULL@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PCRE2_CFLAGS = @PCRE2_CFLAGS@
|
||||
PCRE2_CONFIG = @PCRE2_CONFIG@
|
||||
PCRE2_LIBS = @PCRE2_LIBS@
|
||||
PERL = @PERL@
|
||||
PKG_CONFIG = @PKG_CONFIG@
|
||||
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
|
||||
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
|
||||
PO4A_GETTEXTIZE = @PO4A_GETTEXTIZE@
|
||||
PO4A_TRANSLATE = @PO4A_TRANSLATE@
|
||||
PODWRAPPER = @PODWRAPPER@
|
||||
POSUB = @POSUB@
|
||||
PYCODESTYLE = @PYCODESTYLE@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
SQLITE3 = @SQLITE3@
|
||||
STRIP = @STRIP@
|
||||
UNZIP = @UNZIP@
|
||||
USE_NLS = @USE_NLS@
|
||||
VALGRIND = @VALGRIND@
|
||||
VERSION = @VERSION@
|
||||
VIRT_V2V_NBDKIT_PYTHON_PLUGIN = @VIRT_V2V_NBDKIT_PYTHON_PLUGIN@
|
||||
WARN_CFLAGS = @WARN_CFLAGS@
|
||||
WERROR_CFLAGS = @WERROR_CFLAGS@
|
||||
XGETTEXT = @XGETTEXT@
|
||||
XGETTEXT_015 = @XGETTEXT_015@
|
||||
XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
|
||||
ZIP = @ZIP@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
libvirt_ro_uri = @libvirt_ro_uri@
|
||||
localedir = @localedir@
|
||||
localedir_c = @localedir_c@
|
||||
localedir_c_make = @localedir_c_make@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
ounit_is_v2 = @ounit_is_v2@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
|
||||
# Files that should universally be removed by 'make clean'. Note if
|
||||
# there is any case in any subdirectory where a file should not be
|
||||
# removed by 'make clean', it should not be listed here!
|
||||
|
||||
# Editor backup files
|
||||
|
||||
# Patch original and reject files.
|
||||
|
||||
# OCaml intermediate and generated files.
|
||||
|
||||
# OCaml -annot files (used for displaying types in some IDEs).
|
||||
|
||||
# OCaml oUnit generated files.
|
||||
|
||||
# Manual pages - these are all generated from *.pod, so the
|
||||
# pages themselves should all be removed by 'make clean'.
|
||||
|
||||
# Stamp files used when generating man pages.
|
||||
|
||||
# Bindtests temporary files used in many language bindings.
|
||||
CLEANFILES = *~ *.bak *.orig *.rej *.cmi *.cmo *.cma *.cmx *.cmxa \
|
||||
dll*.so *.a *.annot oUnit-*.cache oUnit-*.log *.1 *.3 *.5 *.8 \
|
||||
stamp-*.pod bindtests.tmp
|
||||
|
||||
# Files that should be universally removed by 'make distclean'.
|
||||
DISTCLEANFILES = .depend stamp-*
|
||||
|
||||
# Special suffixes used by OCaml.
|
||||
|
||||
# Special suffixes used by PO files.
|
||||
SUFFIXES = .cmo .cmi .cmx .ml .mli .mll .mly .po .gmo
|
||||
|
||||
# Rules for building OCaml objects.
|
||||
# See also:
|
||||
# guestfs-hacking(1) section "HOW OCAML PROGRAMS ARE COMPILED AND LINKED"
|
||||
@HAVE_OCAMLOPT_FALSE@MLARCHIVE = cma
|
||||
@HAVE_OCAMLOPT_TRUE@MLARCHIVE = cmxa
|
||||
@HAVE_OCAMLOPT_FALSE@LINK_CUSTOM_OCAMLC_ONLY = -output-complete-exe
|
||||
@HAVE_OCAMLOPT_FALSE@BEST = c
|
||||
@HAVE_OCAMLOPT_TRUE@BEST = opt
|
||||
|
||||
# custom silent rules
|
||||
guestfs_am_v_ocamlc = $(guestfs_am_v_ocamlc_@AM_V@)
|
||||
guestfs_am_v_ocamlc_ = $(guestfs_am_v_ocamlc_@AM_DEFAULT_V@)
|
||||
guestfs_am_v_ocamlc_0 = @echo " OCAMLC " $@;
|
||||
guestfs_am_v_ocamlcmi = $(guestfs_am_v_ocamlcmi_@AM_V@)
|
||||
guestfs_am_v_ocamlcmi_ = $(guestfs_am_v_ocamlcmi_@AM_DEFAULT_V@)
|
||||
guestfs_am_v_ocamlcmi_0 = @echo " OCAMLCMI" $@;
|
||||
guestfs_am_v_ocamlopt = $(guestfs_am_v_ocamlopt_@AM_V@)
|
||||
guestfs_am_v_ocamlopt_ = $(guestfs_am_v_ocamlopt_@AM_DEFAULT_V@)
|
||||
guestfs_am_v_ocamlopt_0 = @echo " OCAMLOPT" $@;
|
||||
guestfs_am_v_javac = $(guestfs_am_v_javac_@AM_V@)
|
||||
guestfs_am_v_javac_ = $(guestfs_am_v_javac_@AM_DEFAULT_V@)
|
||||
guestfs_am_v_javac_0 = @echo " JAVAC " $@;
|
||||
guestfs_am_v_erlc = $(guestfs_am_v_erlc_@AM_V@)
|
||||
guestfs_am_v_erlc_ = $(guestfs_am_v_erlc_@AM_DEFAULT_V@)
|
||||
guestfs_am_v_erlc_0 = @echo " ERLC " $@;
|
||||
guestfs_am_v_podwrapper = $(guestfs_am_v_podwrapper_@AM_V@)
|
||||
guestfs_am_v_podwrapper_ = $(guestfs_am_v_podwrapper_@AM_DEFAULT_V@)
|
||||
guestfs_am_v_podwrapper_0 = @echo " POD " $@;
|
||||
guestfs_am_v_jar = $(guestfs_am_v_jar_@AM_V@)
|
||||
guestfs_am_v_jar_ = $(guestfs_am_v_jar_@AM_DEFAULT_V@)
|
||||
guestfs_am_v_jar_0 = @echo " JAR " $@;
|
||||
guestfs_am_v_po4a_translate = $(guestfs_am_v_po4a_translate_@AM_V@)
|
||||
guestfs_am_v_po4a_translate_ = $(guestfs_am_v_po4a_translate_@AM_DEFAULT_V@)
|
||||
guestfs_am_v_po4a_translate_0 = @echo " PO4A-T " $@;
|
||||
EXTRA_DIST = \
|
||||
$(SOURCES_MLI) \
|
||||
$(SOURCES_ML) \
|
||||
$(SOURCES_C)
|
||||
|
||||
SOURCES_MLI = \
|
||||
firmware.mli \
|
||||
linux.mli \
|
||||
linux_bootloaders.mli \
|
||||
linux_kernels.mli \
|
||||
windows_drivers.mli
|
||||
|
||||
SOURCES_ML = \
|
||||
firmware.ml \
|
||||
linux.ml \
|
||||
linux_bootloaders.ml \
|
||||
linux_kernels.ml \
|
||||
windows_drivers.ml
|
||||
|
||||
SOURCES_C = \
|
||||
dummy.c
|
||||
|
||||
|
||||
# We pretend that we're building a C library. automake handles the
|
||||
# compilation of the C sources for us. At the end we take the C
|
||||
# objects and OCaml objects and link them into the OCaml library.
|
||||
# This C library is never used.
|
||||
noinst_LIBRARIES = libmldrivers.a
|
||||
@HAVE_OCAMLOPT_FALSE@MLDRIVERS_CMA = mldrivers.cma
|
||||
@HAVE_OCAMLOPT_TRUE@MLDRIVERS_CMA = mldrivers.cmxa
|
||||
noinst_DATA = $(MLDRIVERS_CMA)
|
||||
libmldrivers_a_SOURCES = $(SOURCES_C)
|
||||
libmldrivers_a_CPPFLAGS = \
|
||||
-DCAML_NAME_SPACE \
|
||||
-I. \
|
||||
-I$(top_builddir) \
|
||||
-I$(shell $(OCAMLC) -where) \
|
||||
-I$(top_srcdir)/common/mlgettext \
|
||||
-I$(top_srcdir)/common/mlpcre \
|
||||
-I$(top_srcdir)/common/mlstdutils \
|
||||
-I$(top_srcdir)/common/mltools
|
||||
|
||||
libmldrivers_a_CFLAGS = \
|
||||
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
|
||||
-fPIC
|
||||
|
||||
BOBJECTS = $(SOURCES_ML:.ml=.cmo)
|
||||
XOBJECTS = $(BOBJECTS:.cmo=.cmx)
|
||||
OCAMLPACKAGES = \
|
||||
-package str,unix,guestfs \
|
||||
-I $(top_builddir)/common/mlgettext \
|
||||
-I $(top_builddir)/common/mlpcre \
|
||||
-I $(top_builddir)/common/mlstdutils \
|
||||
-I $(top_builddir)/common/mltools \
|
||||
-I $(builddir)
|
||||
|
||||
OCAMLPACKAGES_TESTS = $(MLDRIVERS_CMA)
|
||||
OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
|
||||
@HAVE_OCAMLOPT_FALSE@OBJECTS = $(BOBJECTS)
|
||||
@HAVE_OCAMLOPT_TRUE@OBJECTS = $(XOBJECTS)
|
||||
libmldrivers_a_DEPENDENCIES = $(OBJECTS)
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .cmo .cmi .cmx .ml .mli .mll .mly .po .gmo .c .lo .o .obj
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/subdir-rules.mk $(top_srcdir)/common-rules.mk $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign common/mldrivers/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign common/mldrivers/Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
|
||||
esac;
|
||||
$(top_srcdir)/subdir-rules.mk $(top_srcdir)/common-rules.mk $(am__empty):
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
clean-noinstLIBRARIES:
|
||||
-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
|
||||
|
||||
libmldrivers.a: $(libmldrivers_a_OBJECTS) $(libmldrivers_a_DEPENDENCIES) $(EXTRA_libmldrivers_a_DEPENDENCIES)
|
||||
$(AM_V_at)-rm -f libmldrivers.a
|
||||
$(AM_V_AR)$(libmldrivers_a_AR) libmldrivers.a $(libmldrivers_a_OBJECTS) $(libmldrivers_a_LIBADD)
|
||||
$(AM_V_at)$(RANLIB) libmldrivers.a
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmldrivers_a-dummy.Po@am__quote@ # am--include-marker
|
||||
|
||||
$(am__depfiles_remade):
|
||||
@$(MKDIR_P) $(@D)
|
||||
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
|
||||
|
||||
am--depfiles: $(am__depfiles_remade)
|
||||
|
||||
.c.o:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
|
||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
|
||||
|
||||
.c.obj:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
|
||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
|
||||
.c.lo:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
|
||||
@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
|
||||
|
||||
libmldrivers_a-dummy.o: dummy.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmldrivers_a_CPPFLAGS) $(CPPFLAGS) $(libmldrivers_a_CFLAGS) $(CFLAGS) -MT libmldrivers_a-dummy.o -MD -MP -MF $(DEPDIR)/libmldrivers_a-dummy.Tpo -c -o libmldrivers_a-dummy.o `test -f 'dummy.c' || echo '$(srcdir)/'`dummy.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmldrivers_a-dummy.Tpo $(DEPDIR)/libmldrivers_a-dummy.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dummy.c' object='libmldrivers_a-dummy.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmldrivers_a_CPPFLAGS) $(CPPFLAGS) $(libmldrivers_a_CFLAGS) $(CFLAGS) -c -o libmldrivers_a-dummy.o `test -f 'dummy.c' || echo '$(srcdir)/'`dummy.c
|
||||
|
||||
libmldrivers_a-dummy.obj: dummy.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmldrivers_a_CPPFLAGS) $(CPPFLAGS) $(libmldrivers_a_CFLAGS) $(CFLAGS) -MT libmldrivers_a-dummy.obj -MD -MP -MF $(DEPDIR)/libmldrivers_a-dummy.Tpo -c -o libmldrivers_a-dummy.obj `if test -f 'dummy.c'; then $(CYGPATH_W) 'dummy.c'; else $(CYGPATH_W) '$(srcdir)/dummy.c'; fi`
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmldrivers_a-dummy.Tpo $(DEPDIR)/libmldrivers_a-dummy.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dummy.c' object='libmldrivers_a-dummy.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmldrivers_a_CPPFLAGS) $(CPPFLAGS) $(libmldrivers_a_CFLAGS) $(CFLAGS) -c -o libmldrivers_a-dummy.obj `if test -f 'dummy.c'; then $(CYGPATH_W) 'dummy.c'; else $(CYGPATH_W) '$(srcdir)/dummy.c'; fi`
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
ID: $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); mkid -fID $$unique
|
||||
tags: tags-am
|
||||
TAGS: tags
|
||||
|
||||
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
$(am__define_uniq_tagged_files); \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: ctags-am
|
||||
|
||||
CTAGS: ctags
|
||||
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
cscopelist: cscopelist-am
|
||||
|
||||
cscopelist-am: $(am__tagged_files)
|
||||
list='$(am__tagged_files)'; \
|
||||
case "$(srcdir)" in \
|
||||
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
|
||||
*) sdir=$(subdir)/$(srcdir) ;; \
|
||||
esac; \
|
||||
for i in $$list; do \
|
||||
if test -f "$$i"; then \
|
||||
echo "$(subdir)/$$i"; \
|
||||
else \
|
||||
echo "$$sdir/$$i"; \
|
||||
fi; \
|
||||
done >> $(top_builddir)/cscope.files
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
distdir: $(BUILT_SOURCES)
|
||||
$(MAKE) $(AM_MAKEFLAGS) distdir-am
|
||||
|
||||
distdir-am: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(LIBRARIES) $(DATA)
|
||||
installdirs:
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
|
||||
mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -f ./$(DEPDIR)/libmldrivers_a-dummy.Po
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -f ./$(DEPDIR)/libmldrivers_a-dummy.Po
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
|
||||
mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am:
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
|
||||
clean-generic clean-libtool clean-noinstLIBRARIES \
|
||||
cscopelist-am ctags ctags-am distclean distclean-compile \
|
||||
distclean-generic distclean-libtool distclean-tags distdir dvi \
|
||||
dvi-am html html-am info info-am install install-am \
|
||||
install-data install-data-am install-dvi install-dvi-am \
|
||||
install-exec install-exec-am install-html install-html-am \
|
||||
install-info install-info-am install-man install-pdf \
|
||||
install-pdf-am install-ps install-ps-am install-strip \
|
||||
installcheck installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-compile \
|
||||
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||
tags tags-am uninstall uninstall-am
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
||||
|
||||
-include $(top_builddir)/localenv
|
||||
|
||||
# Individual Makefile.am's should define generator_built if that
|
||||
# subdirectory contains any files which are built by the generator.
|
||||
# Set generator_built to the list of those files.
|
||||
|
||||
$(generator_built): $(top_builddir)/generator/stamp-generator
|
||||
|
||||
$(top_builddir)/generator/stamp-generator: $(top_builddir)/generator/generator
|
||||
@if test -f $(top_builddir)/generator/Makefile; then \
|
||||
$(MAKE) -C $(top_builddir)/generator stamp-generator; \
|
||||
else \
|
||||
echo "warning: Run 'make' at the top level to build $(generator_built)"; \
|
||||
fi
|
||||
|
||||
# If this file doesn't exist, just print a warning and continue.
|
||||
# During 'make distclean' we can end up deleting this file.
|
||||
$(top_builddir)/generator/generator:
|
||||
@if test -f $(top_builddir)/generator/Makefile; then \
|
||||
$(MAKE) -C $(top_builddir)/generator generator; \
|
||||
else \
|
||||
echo "warning: Run 'make' at the top level to build $@"; \
|
||||
fi
|
||||
|
||||
%.cmi: %.mli
|
||||
$(guestfs_am_v_ocamlcmi)$(OCAMLFIND) ocamlc -package guestfs $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@
|
||||
%.cmo: %.ml
|
||||
$(guestfs_am_v_ocamlc)$(OCAMLFIND) ocamlc -package guestfs $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@
|
||||
@HAVE_OCAMLOPT_TRUE@%.cmx: %.ml
|
||||
@HAVE_OCAMLOPT_TRUE@ $(guestfs_am_v_ocamlopt)$(OCAMLFIND) ocamlopt -package guestfs $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@
|
||||
|
||||
# A few parts of the common/ submodule use $TEST_FUNCTIONS expecting
|
||||
# it to be replaced with the old hacky test-functions.sh script and
|
||||
# some local variables (as happens in libguestfs). Until we can
|
||||
# replace that. use this for now.
|
||||
export TEST_FUNCTIONS := exit 77
|
||||
|
||||
$(MLDRIVERS_CMA): $(OBJECTS) libmldrivers.a
|
||||
$(OCAMLFIND) mklib $(OCAMLPACKAGES) \
|
||||
$(OBJECTS) $(libmldrivers_a_OBJECTS) -o mldrivers
|
||||
|
||||
# OCaml dependencies.
|
||||
.depend: $(srcdir)/*.mli $(srcdir)/*.ml
|
||||
$(top_builddir)/ocaml-dep.sh $^
|
||||
-include .depend
|
||||
|
||||
.PHONY: docs
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
62
virt/common/mldrivers/firmware.ml
Normal file
62
virt/common/mldrivers/firmware.ml
Normal file
@ -0,0 +1,62 @@
|
||||
(* virt-v2v
|
||||
* Copyright (C) 2009-2023 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 Tools_utils
|
||||
|
||||
module G = Guestfs
|
||||
|
||||
type i_firmware =
|
||||
| I_BIOS
|
||||
| I_UEFI of string list
|
||||
|
||||
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
|
||||
in
|
||||
let accumulate_partition (esp_parts, bboot) part =
|
||||
let dev = g#part_to_dev part in
|
||||
if parttype_is_gpt dev then
|
||||
let partnum = g#part_to_partnum part in
|
||||
let part_type_guid = g#part_get_gpt_type dev partnum in
|
||||
match part_type_guid with
|
||||
(* EFI system partition *)
|
||||
| "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" -> part :: esp_parts, bboot
|
||||
(* BIOS boot partition *)
|
||||
| "21686148-6449-6E6F-744E-656564454649" -> esp_parts, true
|
||||
| _ -> esp_parts, bboot
|
||||
else esp_parts, bboot
|
||||
in
|
||||
|
||||
let esp_partitions, bios_boot =
|
||||
Array.fold_left accumulate_partition ([], false) (g#list_partitions ()) in
|
||||
|
||||
(* If there's a BIOS boot partition present (0xef02 type for gdisk,
|
||||
* "bios_grub" flag for parted), then this is likely a BIOS+GPT setup.
|
||||
* In this case we prioritize BIOS boot partition and detect BIOS firmware,
|
||||
* no matter how many ESPs we've found.
|
||||
*)
|
||||
match esp_partitions, bios_boot with
|
||||
| _ :: _, false -> I_UEFI esp_partitions
|
||||
| _ -> I_BIOS
|
35
virt/common/mldrivers/firmware.mli
Normal file
35
virt/common/mldrivers/firmware.mli
Normal file
@ -0,0 +1,35 @@
|
||||
(* virt-v2v
|
||||
* Copyright (C) 2009-2023 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.
|
||||
*)
|
||||
|
||||
type i_firmware =
|
||||
| I_BIOS
|
||||
| I_UEFI of string list
|
||||
(** Firmware type returned through inspection (as opposed to source
|
||||
hypervisor information which could be different or missing). *)
|
||||
|
||||
val detect_firmware : Guestfs.guestfs -> i_firmware
|
||||
(** [detect_firmware g] sees if this guest could use UEFI to boot. It
|
||||
should use GPT and it should have an EFI System Partition (ESP).
|
||||
|
||||
If the guest has BIOS boot partition present, this is likely a BIOS+GPT
|
||||
setup, so [I_BIOS] is returned.
|
||||
|
||||
If it has ESP(s), then [I_UEFI devs] is returned where [devs] is the
|
||||
list of at least one ESP.
|
||||
|
||||
Otherwise, [I_BIOS] is returned. *)
|
181
virt/common/mldrivers/linux.ml
Normal file
181
virt/common/mldrivers/linux.ml
Normal file
@ -0,0 +1,181 @@
|
||||
(* virt-v2v
|
||||
* Copyright (C) 2009-2023 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
|
||||
|
||||
module G = Guestfs
|
||||
|
||||
let re_version = PCRE.compile "(\\d+)\\.(\\d+)"
|
||||
|
||||
let augeas_reload g =
|
||||
g#aug_load ();
|
||||
debug_augeas_errors g
|
||||
|
||||
let rec remove g root packages =
|
||||
if packages <> [] then (
|
||||
do_remove g root packages;
|
||||
(* Reload Augeas in case anything changed. *)
|
||||
augeas_reload g
|
||||
)
|
||||
|
||||
and do_remove g root packages =
|
||||
assert (List.length packages > 0);
|
||||
|
||||
let package_format = g#inspect_get_package_format root in
|
||||
match package_format with
|
||||
| "deb" ->
|
||||
let cmd = [ "dpkg"; "--purge" ] @ packages in
|
||||
let cmd = Array.of_list cmd in
|
||||
ignore (g#command cmd);
|
||||
|
||||
| "rpm" ->
|
||||
let cmd = [ "rpm"; "-e"; "--allmatches" ] @ packages in
|
||||
let cmd = Array.of_list cmd in
|
||||
ignore (g#command cmd)
|
||||
|
||||
| format ->
|
||||
error (f_"don’t know how to remove packages using %s: packages: %s")
|
||||
format (String.concat " " packages)
|
||||
|
||||
let file_list_of_package (g : Guestfs.guestfs) root app =
|
||||
let package_format = g#inspect_get_package_format root in
|
||||
match package_format with
|
||||
| "deb" ->
|
||||
let cmd = [| "dpkg"; "-L"; app.G.app2_name |] in
|
||||
debug "%s" (String.concat " " (Array.to_list cmd));
|
||||
let files = g#command_lines cmd in
|
||||
let files = Array.to_list files in
|
||||
List.sort compare files
|
||||
|
||||
| "rpm" ->
|
||||
(* Since RPM allows multiple packages installed with the same
|
||||
* name, always check the full NEVR here (RHBZ#1161250).
|
||||
*
|
||||
* In RPM < 4.11 query commands that use the epoch number in the
|
||||
* package name did not work.
|
||||
*
|
||||
* For example:
|
||||
* RHEL 6 (rpm 4.8.0):
|
||||
* $ rpm -q tar-2:1.23-11.el6.x86_64
|
||||
* package tar-2:1.23-11.el6.x86_64 is not installed
|
||||
* Fedora 20 (rpm 4.11.2):
|
||||
* $ rpm -q tar-2:1.26-30.fc20.x86_64
|
||||
* tar-1.26-30.fc20.x86_64
|
||||
*)
|
||||
let is_rpm_lt_4_11 () =
|
||||
let ver =
|
||||
try
|
||||
(* Since we're going to run 'rpm' below anyway, seems safe
|
||||
* to run it here and assume the binary works.
|
||||
*)
|
||||
let cmd = [| "rpm"; "--version" |] in
|
||||
debug "%s" (String.concat " " (Array.to_list cmd));
|
||||
let ver = g#command_lines cmd in
|
||||
let ver = if Array.length ver > 0 then ver.(0) else raise Not_found in
|
||||
debug "%s" ver;
|
||||
let ver = String.nsplit " " ver in
|
||||
let ver =
|
||||
match ver with
|
||||
| [ "RPM"; "version"; ver ] -> ver
|
||||
| _ -> raise Not_found in
|
||||
if not (PCRE.matches re_version ver) then raise Not_found;
|
||||
(int_of_string (PCRE.sub 1), int_of_string (PCRE.sub 2))
|
||||
with Not_found ->
|
||||
(* 'rpm' not installed? Hmm... *)
|
||||
(0, 0) in
|
||||
ver < (4, 11)
|
||||
in
|
||||
let pkg_name =
|
||||
if app.G.app2_epoch = Int32.zero || is_rpm_lt_4_11 () then
|
||||
sprintf "%s-%s-%s" app.G.app2_name app.G.app2_version
|
||||
app.G.app2_release
|
||||
else
|
||||
sprintf "%s-%ld:%s-%s" app.G.app2_name app.G.app2_epoch
|
||||
app.G.app2_version app.G.app2_release in
|
||||
let cmd = [| "rpm"; "-ql"; pkg_name |] in
|
||||
debug "%s" (String.concat " " (Array.to_list cmd));
|
||||
let files = g#command_lines cmd in
|
||||
(* RPM prints "(contains no files)" on stdout when a package
|
||||
* has no files in it:
|
||||
* https://github.com/rpm-software-management/rpm/issues/962
|
||||
*)
|
||||
if files = [| "(contains no files)" |] then
|
||||
[]
|
||||
else (
|
||||
let files = Array.to_list files in
|
||||
List.sort compare files
|
||||
)
|
||||
|
||||
| format ->
|
||||
error (f_"don’t know how to get list of files from package using %s")
|
||||
format
|
||||
|
||||
let is_file_owned (g : G.guestfs) root path =
|
||||
let package_format = g#inspect_get_package_format root in
|
||||
match package_format with
|
||||
| "deb" ->
|
||||
(* With dpkg usually the directories are owned by all the packages
|
||||
* that install anything in them. Also with multiarch the same
|
||||
* package is allowed (although with different architectures).
|
||||
* This function returns only one package in all the cases.
|
||||
*)
|
||||
let cmd = [| "dpkg"; "-S"; path |] in
|
||||
debug "%s" (String.concat " " (Array.to_list cmd));
|
||||
(try
|
||||
let lines = g#command_lines cmd in
|
||||
if Array.length lines = 0 then
|
||||
error (f_"internal error: is_file_owned: dpkg command returned no output");
|
||||
(* Just check the output looks something like "pkg: filename". *)
|
||||
if String.find lines.(0) ": " >= 0 then
|
||||
true
|
||||
else
|
||||
error (f_"internal error: is_file_owned: unexpected output from dpkg command: %s")
|
||||
lines.(0)
|
||||
with Guestfs.Error msg as exn ->
|
||||
if String.find msg "no path found matching pattern" >= 0 then
|
||||
false
|
||||
else
|
||||
raise exn
|
||||
)
|
||||
|
||||
| "rpm" ->
|
||||
(* Run rpm -qf and print a magic string if the file is owned.
|
||||
* If not owned, rpm will print "... is not owned by any package"
|
||||
* and exit with an error. Unfortunately the string is sent to
|
||||
* stdout, so here we ignore the exit status of rpm and just
|
||||
* look for one of the two strings.
|
||||
*)
|
||||
let magic = "FILE_OWNED_TEST" in
|
||||
let cmd = sprintf "rpm -qf --qf %s %s 2>&1 ||:"
|
||||
(quote (magic ^ "\n")) (quote path) in
|
||||
let r = g#sh cmd in
|
||||
if String.find r magic >= 0 then true
|
||||
else if String.find r "is not owned" >= 0 then false
|
||||
else failwithf "RPM file owned test failed: %s" r
|
||||
|
||||
| format ->
|
||||
error (f_"don’t know how to find file owner using %s") format
|
||||
|
||||
let is_package_manager_save_file filename =
|
||||
(* Recognized suffixes of package managers. *)
|
||||
let suffixes = [ ".dpkg-old"; ".dpkg-new"; ".rpmsave"; ".rpmnew"; ] in
|
||||
List.exists (Filename.check_suffix filename) suffixes
|
40
virt/common/mldrivers/linux.mli
Normal file
40
virt/common/mldrivers/linux.mli
Normal file
@ -0,0 +1,40 @@
|
||||
(* virt-v2v
|
||||
* Copyright (C) 2009-2023 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.
|
||||
*)
|
||||
|
||||
(** Common Linux functions. *)
|
||||
|
||||
val augeas_reload : Guestfs.guestfs -> unit
|
||||
(** Wrapper around [g#aug_load], which (if verbose) provides
|
||||
additional debugging information about parsing problems
|
||||
that augeas found. *)
|
||||
|
||||
val remove : Guestfs.guestfs -> string -> string list -> unit
|
||||
(** [remove g root pkgs] uninstalls the package(s). *)
|
||||
|
||||
val file_list_of_package : Guestfs.guestfs -> string ->
|
||||
Guestfs.application2 -> string list
|
||||
(** [file_list_of_package g root app] returns the list of files
|
||||
owned by a package. *)
|
||||
|
||||
val is_file_owned : Guestfs.guestfs -> string -> string -> bool
|
||||
(** [is_file_owned g root path] returns true if the file is owned
|
||||
by any installed package. *)
|
||||
|
||||
val is_package_manager_save_file : string -> bool
|
||||
(** Return true if the filename is something like [*.rpmsave], ie.
|
||||
a package manager save-file. *)
|
418
virt/common/mldrivers/linux_bootloaders.ml
Normal file
418
virt/common/mldrivers/linux_bootloaders.ml
Normal file
@ -0,0 +1,418 @@
|
||||
(* virt-v2v
|
||||
* Copyright (C) 2009-2023 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
|
||||
|
||||
module G = Guestfs
|
||||
|
||||
class virtual bootloader = object
|
||||
method virtual name : string
|
||||
method virtual augeas_device_patterns : string list
|
||||
method virtual list_kernels : string list
|
||||
method virtual set_default_kernel : string -> unit
|
||||
method set_augeas_configuration () = false
|
||||
method virtual configure_console : unit -> unit
|
||||
method virtual remove_console : unit -> unit
|
||||
method update () = ()
|
||||
method virtual get_config_file : unit -> string
|
||||
end
|
||||
|
||||
(* Helper function for SUSE: remove (hdX,X) prefix from a path. *)
|
||||
let remove_hd_prefix =
|
||||
let rex = PCRE.compile "^\\(hd.*\\)" in
|
||||
PCRE.replace rex ""
|
||||
|
||||
(* Grub1 (AKA grub-legacy) representation. *)
|
||||
class bootloader_grub1 (g : G.guestfs) root grub_config =
|
||||
let () =
|
||||
(* Apply the "grub" lens if it is not handling the file
|
||||
* already -- Augeas < 1.7.0 will error out otherwise.
|
||||
*)
|
||||
if g#aug_ls ("/files" ^ grub_config) = [||] then
|
||||
g#aug_transform "grub" grub_config in
|
||||
|
||||
(* Grub prefix? Usually "/boot". *)
|
||||
let grub_prefix =
|
||||
let mounts = g#inspect_get_mountpoints root in
|
||||
try
|
||||
List.find (
|
||||
fun path -> List.mem_assoc path mounts
|
||||
) [ "/boot/grub"; "/boot" ]
|
||||
with Not_found -> "" in
|
||||
object
|
||||
inherit bootloader
|
||||
|
||||
method name = "grub1"
|
||||
|
||||
method augeas_device_patterns = [
|
||||
"/files" ^ grub_config ^ "/*/kernel/root";
|
||||
"/files" ^ grub_config ^ "/*/kernel/resume";
|
||||
"/files/boot/grub/device.map/*[label() != \"#comment\"]";
|
||||
"/files/etc/sysconfig/grub/boot";
|
||||
]
|
||||
|
||||
method list_kernels =
|
||||
let paths =
|
||||
let expr = sprintf "/files%s/title/kernel" grub_config in
|
||||
let paths = g#aug_match expr in
|
||||
let paths = Array.to_list paths in
|
||||
|
||||
(* Remove duplicates. *)
|
||||
let paths = List.remove_duplicates paths in
|
||||
|
||||
(* Get the default kernel from grub if it's set. *)
|
||||
let default =
|
||||
let expr = sprintf "/files%s/default" grub_config in
|
||||
try
|
||||
let idx = g#aug_get expr in
|
||||
let idx = int_of_string idx in
|
||||
(* Grub indices are zero-based, augeas is 1-based. *)
|
||||
let expr =
|
||||
sprintf "/files%s/title[%d]/kernel" grub_config (idx+1) in
|
||||
Some expr
|
||||
with G.Error msg
|
||||
when String.find msg "aug_get: no matching node" >= 0 ->
|
||||
None in
|
||||
|
||||
(* If a default kernel was set, put it at the beginning of the paths
|
||||
* list. If not set, assume the first kernel always boots (?)
|
||||
*)
|
||||
match default with
|
||||
| None -> paths
|
||||
| Some p -> p :: List.filter ((<>) p) paths in
|
||||
|
||||
(* Resolve the Augeas paths to kernel filenames. *)
|
||||
let vmlinuzes = List.map g#aug_get paths in
|
||||
|
||||
(* Make sure kernel does not begin with (hdX,X). *)
|
||||
let vmlinuzes = List.map remove_hd_prefix vmlinuzes in
|
||||
|
||||
(* Prepend grub filesystem. *)
|
||||
List.map ((^) grub_prefix) vmlinuzes
|
||||
|
||||
method set_default_kernel vmlinuz =
|
||||
if not (String.is_prefix vmlinuz grub_prefix) then
|
||||
error (f_"kernel %s is not under grub tree %s")
|
||||
vmlinuz grub_prefix;
|
||||
let kernel_under_grub_prefix =
|
||||
let prefix_len = String.length grub_prefix in
|
||||
let kernel_len = String.length vmlinuz in
|
||||
String.sub vmlinuz prefix_len (kernel_len - prefix_len) in
|
||||
|
||||
(* Find the grub entry for the given kernel. *)
|
||||
let paths = g#aug_match (sprintf "/files%s/title/kernel[. = '%s']"
|
||||
grub_config kernel_under_grub_prefix) in
|
||||
let paths = Array.to_list paths in
|
||||
if paths = [] then
|
||||
error (f_"didn't find grub entry for kernel %s") vmlinuz;
|
||||
let path = List.hd paths in
|
||||
let rex = PCRE.compile "/title(?:\\[(\\d+)\\])?/kernel" in
|
||||
if not (PCRE.matches rex path) then
|
||||
error (f_"internal error: regular expression did not match ‘%s’")
|
||||
path;
|
||||
let index = try int_of_string (PCRE.sub 1) - 1 with Not_found -> 0 in
|
||||
g#aug_set (sprintf "/files%s/default" grub_config) (string_of_int index);
|
||||
g#aug_save ()
|
||||
|
||||
method set_augeas_configuration () =
|
||||
let incls = g#aug_match "/augeas/load/Grub/incl" in
|
||||
let incls = Array.to_list incls in
|
||||
let incls_contains_conf =
|
||||
List.exists (fun incl -> g#aug_get incl = grub_config) incls in
|
||||
if not incls_contains_conf then (
|
||||
g#aug_set "/augeas/load/Grub/incl[last()+1]" grub_config;
|
||||
true
|
||||
) else
|
||||
false
|
||||
|
||||
method configure_console () =
|
||||
let rex = PCRE.compile "\\b([xh]vc0)\\b" in
|
||||
let expr = sprintf "/files%s/title/kernel/console" grub_config in
|
||||
|
||||
let paths = g#aug_match expr in
|
||||
let paths = Array.to_list paths in
|
||||
List.iter (
|
||||
fun path ->
|
||||
let console = g#aug_get path in
|
||||
let console' = PCRE.replace ~global:true rex "ttyS0" console in
|
||||
if console <> console' then g#aug_set path console'
|
||||
) paths;
|
||||
|
||||
g#aug_save ()
|
||||
|
||||
method remove_console () =
|
||||
let rex = PCRE.compile "\\b([xh]vc0)\\b" in
|
||||
let expr = sprintf "/files%s/title/kernel/console" grub_config in
|
||||
|
||||
let rec loop = function
|
||||
| [] -> ()
|
||||
| path :: paths ->
|
||||
let console = g#aug_get path in
|
||||
if PCRE.matches rex console then (
|
||||
ignore (g#aug_rm path);
|
||||
(* All the paths are invalid, restart the loop. *)
|
||||
let paths = g#aug_match expr in
|
||||
let paths = Array.to_list paths in
|
||||
loop paths
|
||||
)
|
||||
else
|
||||
loop paths
|
||||
in
|
||||
let paths = g#aug_match expr in
|
||||
let paths = Array.to_list paths in
|
||||
loop paths;
|
||||
|
||||
g#aug_save ()
|
||||
|
||||
method get_config_file () =
|
||||
grub_config
|
||||
end
|
||||
|
||||
(** The method used to get and set the default kernel in Grub2. *)
|
||||
type default_kernel_method =
|
||||
| MethodGrubby (** Use the 'grubby' tool. *)
|
||||
| MethodPerlBootloader (** Use the 'Bootloader::Tools' Perl module. *)
|
||||
| MethodNone (** No known way. *)
|
||||
|
||||
(* Grub2 representation. *)
|
||||
class bootloader_grub2 (g : G.guestfs) grub_config =
|
||||
|
||||
let grub2_mkconfig_cmd =
|
||||
let elems = [
|
||||
"/sbin/grub2-mkconfig";
|
||||
"/usr/sbin/grub2-mkconfig";
|
||||
"/sbin/grub-mkconfig";
|
||||
"/usr/sbin/grub-mkconfig"
|
||||
] in
|
||||
try List.find (g#is_file ~followsymlinks:true) elems
|
||||
with Not_found ->
|
||||
error (f_"failed to find grub2-mkconfig binary (but Grub2 was detected on guest)")
|
||||
in
|
||||
|
||||
let get_default_method =
|
||||
let has_perl_bootloader () =
|
||||
try
|
||||
ignore (g#command [| "/usr/bin/perl"; "-MBootloader::Tools"; "-e1" |]);
|
||||
true
|
||||
with G.Error _ -> false
|
||||
in
|
||||
if g#exists "/sbin/grubby" then MethodGrubby
|
||||
else if has_perl_bootloader () then MethodPerlBootloader
|
||||
else (
|
||||
warning (f_"could not determine a way to update the configuration of Grub2");
|
||||
MethodNone
|
||||
) in
|
||||
|
||||
object (self)
|
||||
inherit bootloader
|
||||
|
||||
method name = "grub2"
|
||||
|
||||
method augeas_device_patterns = [
|
||||
"/files/etc/sysconfig/grub/GRUB_CMDLINE_LINUX";
|
||||
"/files/etc/default/grub/GRUB_CMDLINE_LINUX";
|
||||
"/files/etc/default/grub/GRUB_CMDLINE_LINUX_DEFAULT";
|
||||
"/files/boot/grub2/device.map/*[label() != \"#comment\"]";
|
||||
"/files/boot/grub/device.map/*[label() != \"#comment\"]";
|
||||
]
|
||||
|
||||
method list_kernels =
|
||||
let get_default_image () =
|
||||
let res =
|
||||
match get_default_method with
|
||||
| MethodGrubby ->
|
||||
let res = g#command [| "grubby"; "--default-kernel" |] in
|
||||
(match res with
|
||||
| "" -> None
|
||||
| _ -> Some res)
|
||||
| MethodPerlBootloader ->
|
||||
let cmd =
|
||||
[| "/usr/bin/perl"; "-MBootloader::Tools"; "-e"; "
|
||||
InitLibrary();
|
||||
my $default = Bootloader::Tools::GetDefaultSection ();
|
||||
if (!defined $default) {
|
||||
print 'NODEFAULTSECTION'
|
||||
}
|
||||
elsif (exists $default->{image}) {
|
||||
print $default->{image}
|
||||
}
|
||||
else {
|
||||
die 'no $default->{image}' # should never happen
|
||||
}
|
||||
" |] in
|
||||
let res = g#command cmd in
|
||||
(match res with
|
||||
| "NODEFAULTSECTION" -> None
|
||||
| _ -> Some res)
|
||||
| MethodNone ->
|
||||
None in
|
||||
match res with
|
||||
| None -> None
|
||||
| Some k ->
|
||||
let k = String.chomp k in
|
||||
Some (remove_hd_prefix k)
|
||||
in
|
||||
|
||||
let vmlinuzes =
|
||||
(match get_default_image () with
|
||||
| None -> []
|
||||
| Some k -> [k]) @
|
||||
(* This is how the grub2 config generator enumerates kernels. *)
|
||||
Array.to_list (g#glob_expand "/boot/kernel-*") @
|
||||
Array.to_list (g#glob_expand "/boot/vmlinuz-*") @
|
||||
Array.to_list (g#glob_expand "/vmlinuz-*") in
|
||||
let vmlinuzes = List.filter (
|
||||
fun filename -> not (Linux.is_package_manager_save_file filename)
|
||||
) vmlinuzes in
|
||||
vmlinuzes
|
||||
|
||||
method set_default_kernel vmlinuz =
|
||||
match get_default_method with
|
||||
| MethodGrubby ->
|
||||
ignore (g#command [| "grubby"; "--set-default"; vmlinuz |])
|
||||
| MethodPerlBootloader ->
|
||||
let cmd =
|
||||
[| "/usr/bin/perl"; "-MBootloader::Tools"; "-e"; sprintf "
|
||||
InitLibrary();
|
||||
my @sections = GetSectionList(type=>image, image=>\"%s\");
|
||||
my $section = GetSection(@sections);
|
||||
my $newdefault = $section->{name};
|
||||
SetGlobals(default, \"$newdefault\");
|
||||
" vmlinuz |] in
|
||||
ignore (g#command cmd)
|
||||
| MethodNone -> ()
|
||||
|
||||
method private grub2_update_console ~remove () =
|
||||
let rex = PCRE.compile "\\bconsole=[xh]vc0\\b" in
|
||||
|
||||
let paths = [
|
||||
"/files/etc/sysconfig/grub/GRUB_CMDLINE_LINUX";
|
||||
"/files/etc/default/grub/GRUB_CMDLINE_LINUX";
|
||||
"/files/etc/default/grub/GRUB_CMDLINE_LINUX_DEFAULT"
|
||||
] in
|
||||
let paths = List.map g#aug_match paths in
|
||||
let paths = List.map Array.to_list paths in
|
||||
let paths = List.flatten paths in
|
||||
match paths with
|
||||
| [] ->
|
||||
if not remove then
|
||||
warning (f_"could not add grub2 serial console (ignored)")
|
||||
else
|
||||
warning (f_"could not remove grub2 serial console (ignored)")
|
||||
| path :: _ ->
|
||||
let grub_cmdline = g#aug_get path in
|
||||
if PCRE.matches rex grub_cmdline then (
|
||||
let new_grub_cmdline =
|
||||
if not remove then
|
||||
PCRE.replace ~global:true rex "console=ttyS0" grub_cmdline
|
||||
else
|
||||
PCRE.replace ~global:true rex "" grub_cmdline in
|
||||
g#aug_set path new_grub_cmdline;
|
||||
g#aug_save ();
|
||||
|
||||
try
|
||||
self#update ()
|
||||
with
|
||||
G.Error msg ->
|
||||
warning (f_"could not rebuild grub2 configuration file (%s). This may mean that grub output will not be sent to the serial port, but otherwise should be harmless. Original error message: %s")
|
||||
grub_config msg
|
||||
)
|
||||
|
||||
method configure_console = self#grub2_update_console ~remove:false
|
||||
|
||||
method remove_console = self#grub2_update_console ~remove:true
|
||||
|
||||
method update () =
|
||||
ignore (g#command [| grub2_mkconfig_cmd; "-o"; grub_config |]);
|
||||
|
||||
(* Grub2 runs osprober which sometimes leaves around read-only
|
||||
* device-mapper maps covering existing filesystems. These
|
||||
* confuse later steps (especially fstrim). So just delete
|
||||
* any if found. (RHBZ#2003503).
|
||||
*)
|
||||
ignore (g#command [| "sh"; "-c"; "rm -f /dev/mapper/osprober-linux-*" |])
|
||||
|
||||
method get_config_file () =
|
||||
grub_config
|
||||
end
|
||||
|
||||
(* Helper type used in detect_bootloader. *)
|
||||
type bootloader_type =
|
||||
| Grub1
|
||||
| Grub2
|
||||
|
||||
let detect_bootloader (g : G.guestfs) root i_firmware =
|
||||
(* Where to start searching for bootloaders. *)
|
||||
let mp =
|
||||
match i_firmware with
|
||||
| Firmware.I_BIOS -> "/boot"
|
||||
| I_UEFI _ -> "/boot/efi/EFI" in
|
||||
|
||||
(* Find all paths below the mountpoint, then filter them to find
|
||||
* the grub config file.
|
||||
*)
|
||||
let paths =
|
||||
try List.map ((^) mp) (Array.to_list (g#find mp))
|
||||
with G.Error msg ->
|
||||
error (f_"could not find bootloader mount point (%s): %s") mp msg in
|
||||
|
||||
(*
|
||||
* Workaround for older UEFI-based Debian which may not have
|
||||
* /boot/efi/EFI/debian/grub.cfg.
|
||||
*)
|
||||
let paths =
|
||||
if g#exists "/boot/grub/grub.cfg" then
|
||||
match i_firmware with
|
||||
| Firmware.I_BIOS -> paths
|
||||
| I_UEFI _ -> paths @ ["/boot/grub/grub.cfg"]
|
||||
else paths
|
||||
in
|
||||
|
||||
(* We can determine if the bootloader config file is grub 1 or
|
||||
* grub 2 just by looking at the filename.
|
||||
*)
|
||||
let bootloader_type_of_filename path =
|
||||
match last_part_of path '/' with
|
||||
| Some "grub.cfg" -> Some Grub2
|
||||
| Some ("grub.conf" | "menu.lst") -> Some Grub1
|
||||
| Some _
|
||||
| None -> None
|
||||
in
|
||||
|
||||
let grub_config, typ =
|
||||
let rec loop = function
|
||||
| [] -> error (f_"no bootloader detected")
|
||||
| path :: paths ->
|
||||
match bootloader_type_of_filename path with
|
||||
| None -> loop paths
|
||||
| Some typ ->
|
||||
if not (g#is_file ~followsymlinks:true path) then loop paths
|
||||
else path, typ
|
||||
in
|
||||
loop paths in
|
||||
|
||||
let bl =
|
||||
match typ with
|
||||
| Grub1 -> new bootloader_grub1 g root grub_config
|
||||
| Grub2 -> new bootloader_grub2 g grub_config in
|
||||
debug "detected bootloader %s at %s" bl#name grub_config;
|
||||
bl
|
57
virt/common/mldrivers/linux_bootloaders.mli
Normal file
57
virt/common/mldrivers/linux_bootloaders.mli
Normal file
@ -0,0 +1,57 @@
|
||||
(* virt-v2v
|
||||
* Copyright (C) 2009-2023 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.
|
||||
*)
|
||||
|
||||
class virtual bootloader : object
|
||||
method virtual name : string
|
||||
(** The name of the bootloader, for debugging messages. *)
|
||||
|
||||
method virtual augeas_device_patterns : string list
|
||||
(** A list of Augeas patterns to search for device names when we
|
||||
need to rewrite device names (eg. [/dev/hda] to [/dev/vda]). *)
|
||||
|
||||
method virtual list_kernels : string list
|
||||
(** Lists all the kernels configured in the bootloader. *)
|
||||
|
||||
method virtual set_default_kernel : string -> unit
|
||||
(** Sets the specified vmlinuz path as default bootloader entry. *)
|
||||
|
||||
method set_augeas_configuration : unit -> bool
|
||||
(** Checks whether the bootloader configuration file is included
|
||||
in Augeas load list, and if it is not, then include it.
|
||||
|
||||
Returns true if Augeas needs to be reloaded. *)
|
||||
|
||||
method virtual configure_console : unit -> unit
|
||||
method virtual remove_console : unit -> unit
|
||||
(** Adds or removes a serial console to all the available kernels. *)
|
||||
|
||||
method update : unit -> unit
|
||||
(** Update the bootloader: For grub2 only this runs the
|
||||
[grub2-mkconfig] command to rebuild the configuration. This
|
||||
is not necessary for grub-legacy. *)
|
||||
|
||||
method virtual get_config_file : unit -> string
|
||||
(** Returns the path to the bootloader config file,
|
||||
e.g /boot/grub/grub.cfg *)
|
||||
end
|
||||
(** Encapsulates a Linux boot loader as object. *)
|
||||
|
||||
val detect_bootloader : Guestfs.guestfs -> string -> Firmware.i_firmware ->
|
||||
bootloader
|
||||
(** [detect_bootloader g root i_firmware] detects the bootloader on the
|
||||
guest, and creates the object representing it. *)
|
355
virt/common/mldrivers/linux_kernels.ml
Normal file
355
virt/common/mldrivers/linux_kernels.ml
Normal file
@ -0,0 +1,355 @@
|
||||
(* virt-v2v
|
||||
* Copyright (C) 2009-2023 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.
|
||||
*)
|
||||
|
||||
(* Detect which kernels are installed and offered by the bootloader. *)
|
||||
|
||||
open Printf
|
||||
|
||||
open Std_utils
|
||||
open Tools_utils
|
||||
open Common_gettext.Gettext
|
||||
|
||||
module G = Guestfs
|
||||
|
||||
(* Kernel information. *)
|
||||
type kernel_info = {
|
||||
ki_app : G.application2;
|
||||
ki_name : string;
|
||||
ki_version : string;
|
||||
ki_arch : string;
|
||||
ki_vmlinuz : string;
|
||||
ki_vmlinuz_stat : G.statns;
|
||||
ki_initrd : string option;
|
||||
ki_modpath : string;
|
||||
ki_modules : string list;
|
||||
ki_supports_virtio_blk : bool;
|
||||
ki_supports_virtio_net : bool;
|
||||
ki_supports_virtio_rng : bool;
|
||||
ki_supports_virtio_balloon : bool;
|
||||
ki_supports_isa_pvpanic : bool;
|
||||
ki_supports_virtio_socket : bool;
|
||||
ki_is_xen_pv_only_kernel : bool;
|
||||
ki_is_debug : bool;
|
||||
ki_config_file : string option;
|
||||
}
|
||||
|
||||
let print_kernel_info chan prefix ki =
|
||||
let fpf fs = output_string chan prefix; fprintf chan fs in
|
||||
fprintf chan "* %s %s (%s)\n" ki.ki_name ki.ki_version ki.ki_arch;
|
||||
fpf "%s\n" ki.ki_vmlinuz;
|
||||
fpf "%s\n" (match ki.ki_initrd with None -> "no initrd" | Some s -> s);
|
||||
fpf "%s\n" (match ki.ki_config_file with None -> "no config" | Some s -> s);
|
||||
fpf "%s\n" ki.ki_modpath;
|
||||
fpf "%d modules found\n" (List.length ki.ki_modules);
|
||||
fpf "virtio: blk=%b net=%b rng=%b balloon=%b\n"
|
||||
ki.ki_supports_virtio_blk ki.ki_supports_virtio_net
|
||||
ki.ki_supports_virtio_rng ki.ki_supports_virtio_balloon;
|
||||
fpf "pvpanic=%b vsock=%b xen=%b debug=%b\n"
|
||||
ki.ki_supports_isa_pvpanic ki.ki_supports_virtio_socket
|
||||
ki.ki_is_xen_pv_only_kernel ki.ki_is_debug
|
||||
|
||||
let rex_ko = PCRE.compile "\\.k?o(?:\\.(?:xz|zst))?$"
|
||||
let rex_ko_extract = PCRE.compile "/([^/]+)\\.k?o(?:\\.(?:xz|zst))?$"
|
||||
|
||||
let detect_kernels (g : G.guestfs) root bootloader apps =
|
||||
(* What kernel/kernel-like packages are installed on the current guest? *)
|
||||
let installed_kernels : kernel_info list =
|
||||
let check_config feature = function
|
||||
| None -> false
|
||||
| Some config ->
|
||||
let prefix = "^CONFIG_" ^ String.uppercase_ascii feature ^ "=" in
|
||||
let lines = g#grep ~extended:true prefix config in
|
||||
let lines = Array.to_list lines in
|
||||
match lines with
|
||||
| [] -> false
|
||||
| line :: _ ->
|
||||
let kind = snd (String.split "=" line) in
|
||||
(match kind with
|
||||
| "m" | "y" -> true
|
||||
| _ -> false
|
||||
)
|
||||
in
|
||||
let rex_initrd =
|
||||
let is_debian_family =
|
||||
let distro = g#inspect_get_distro root in
|
||||
match distro with
|
||||
| "debian" | "ubuntu" | "linuxmint" | "kalilinux" -> true
|
||||
| _ -> false in
|
||||
if is_debian_family then
|
||||
PCRE.compile "^initrd.img-.*$"
|
||||
else
|
||||
PCRE.compile "^initr(?:d|amfs)-.*(?:\\.img)?$" in
|
||||
let kernel_pkgs = List.filter (
|
||||
fun { G.app2_name = name } ->
|
||||
name = "kernel"
|
||||
|| (String.is_prefix name "kernel-" && not (String.is_suffix name "-devel"))
|
||||
|| String.is_prefix name "linux-image-"
|
||||
) apps in
|
||||
if verbose () then (
|
||||
let names = List.map (fun { G.app2_name = name } -> name) kernel_pkgs in
|
||||
eprintf "info: candidate kernel packages in this guest: %s%!\n"
|
||||
(String.concat " " names)
|
||||
);
|
||||
List.filter_map (
|
||||
fun ({ G.app2_name = name } as app) ->
|
||||
(try
|
||||
(* For each kernel, list the files directly owned by the kernel. *)
|
||||
let files = Linux.file_list_of_package g root app in
|
||||
|
||||
(* Which of these is the kernel itself? Also, make sure to check
|
||||
* it exists by stat'ing it.
|
||||
*)
|
||||
let vmlinuz = List.find (
|
||||
fun filename -> String.is_prefix filename "/boot/vmlinuz-"
|
||||
) files in
|
||||
let vmlinuz_stat =
|
||||
try g#statns vmlinuz with G.Error _ -> raise Not_found in
|
||||
|
||||
(* Determine the modpath from the package, falling back to the
|
||||
* version in the vmlinuz file name.
|
||||
*)
|
||||
let modpath, version =
|
||||
let prefix = "/lib/modules/" in
|
||||
let prefix_len = String.length prefix in
|
||||
try
|
||||
let modpath, version = List.find_map (
|
||||
fun filename ->
|
||||
let filename_len = String.length filename in
|
||||
if filename_len > prefix_len &&
|
||||
String.is_prefix filename prefix then (
|
||||
let version = String.sub filename prefix_len
|
||||
(filename_len - prefix_len) in
|
||||
Some (filename, version)
|
||||
) else
|
||||
None
|
||||
) files in
|
||||
(* Fall back to the version in the vmlinuz file name not only if
|
||||
* a candidate pathname couldn't be found under /lib/modules/,
|
||||
* but also in case the candidate pathname doesn't reference a
|
||||
* directory. See RHBZ#2175703.
|
||||
*
|
||||
* Note that this "is_dir" check is deliberately kept outside of
|
||||
* the "find_map"'s mapper function above: we want the first
|
||||
* candidate *to be* a directory, and not the first candidate
|
||||
* *that is* a directory.
|
||||
*)
|
||||
if not (g#is_dir ~followsymlinks:true modpath) then
|
||||
raise Not_found;
|
||||
modpath, version
|
||||
with Not_found ->
|
||||
let version =
|
||||
String.sub vmlinuz 14 (String.length vmlinuz - 14) in
|
||||
let modpath = prefix ^ version in
|
||||
(* Check that the modpath exists. *)
|
||||
if not (g#is_dir ~followsymlinks:true modpath) then
|
||||
raise Not_found;
|
||||
modpath, version in
|
||||
|
||||
(* Find the initramfs which corresponds to the kernel.
|
||||
* Since the initramfs is built at runtime, and doesn't have
|
||||
* to be covered by the RPM file list, this is basically
|
||||
* guesswork.
|
||||
*)
|
||||
let initrd =
|
||||
let files = g#ls "/boot" in
|
||||
let files = Array.to_list files in
|
||||
let files =
|
||||
List.filter (fun n -> PCRE.matches rex_initrd n) files in
|
||||
let files =
|
||||
List.filter (
|
||||
fun n ->
|
||||
String.find n version >= 0
|
||||
) files in
|
||||
(* Don't consider kdump initramfs images (RHBZ#1138184). *)
|
||||
let files =
|
||||
List.filter (fun n -> String.find n "kdump" == -1) files in
|
||||
(* If several files match, take the shortest match. This
|
||||
* handles the case where we have a mix of same-version non-Xen
|
||||
* and Xen kernels:
|
||||
* initrd-2.6.18-308.el5.img
|
||||
* initrd-2.6.18-308.el5xen.img
|
||||
* and kernel 2.6.18-308.el5 (non-Xen) will match both
|
||||
* (RHBZ#1141145).
|
||||
*)
|
||||
let cmp a b = compare (String.length a) (String.length b) in
|
||||
let files = List.sort cmp files in
|
||||
match files with
|
||||
| [] ->
|
||||
warning (f_"no initrd was found in /boot matching %s %s.")
|
||||
name version;
|
||||
None
|
||||
| x :: _ -> Some ("/boot/" ^ x) in
|
||||
|
||||
(* Get all modules, which might include custom-installed
|
||||
* modules that don't appear in 'files' list above.
|
||||
*)
|
||||
let modules = g#find modpath in
|
||||
let modules = Array.to_list modules in
|
||||
let modules =
|
||||
List.filter (fun m -> PCRE.matches rex_ko m) modules in
|
||||
assert (List.length modules > 0);
|
||||
|
||||
(* Determine the kernel architecture by looking at the
|
||||
* 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 =
|
||||
(* 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";
|
||||
"/" ^ f ^ ".ko.zst";
|
||||
]
|
||||
) 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 (
|
||||
fun m ->
|
||||
if PCRE.matches rex_ko_extract m then
|
||||
Some (PCRE.sub 1)
|
||||
else
|
||||
None
|
||||
) modules in
|
||||
assert (List.length modules > 0);
|
||||
|
||||
let config_file =
|
||||
let cfg = "/boot/config-" ^ version in
|
||||
if g#is_file ~followsymlinks:true cfg then Some cfg
|
||||
else None in
|
||||
|
||||
let kernel_supports what kconf =
|
||||
List.mem what modules || check_config kconf config_file in
|
||||
|
||||
let supports_virtio_blk =
|
||||
kernel_supports "virtio_blk" "VIRTIO_BLK" in
|
||||
let supports_virtio_net =
|
||||
kernel_supports "virtio_net" "VIRTIO_NET" in
|
||||
let supports_virtio_rng =
|
||||
kernel_supports "virtio-rng" "HW_RANDOM_VIRTIO" in
|
||||
let supports_virtio_balloon =
|
||||
kernel_supports "virtio_balloon" "VIRTIO_BALLOON" in
|
||||
let supports_isa_pvpanic =
|
||||
kernel_supports "pvpanic" "PVPANIC" in
|
||||
let supports_virtio_socket =
|
||||
kernel_supports "vmw_vsock_virtio_transport" "VIRTIO_VSOCKETS" in
|
||||
let is_xen_pv_only_kernel =
|
||||
check_config "X86_XEN" config_file ||
|
||||
check_config "X86_64_XEN" config_file in
|
||||
|
||||
(* If the package name is like "kernel-debug", then it's
|
||||
* a debug kernel.
|
||||
*)
|
||||
let is_debug =
|
||||
String.is_suffix app.G.app2_name "-debug" ||
|
||||
String.is_suffix app.G.app2_name "-dbg" in
|
||||
|
||||
Some {
|
||||
ki_app = app;
|
||||
ki_name = name;
|
||||
ki_version = version;
|
||||
ki_arch = arch;
|
||||
ki_vmlinuz = vmlinuz;
|
||||
ki_vmlinuz_stat = vmlinuz_stat;
|
||||
ki_initrd = initrd;
|
||||
ki_modpath = modpath;
|
||||
ki_modules = modules;
|
||||
ki_supports_virtio_blk = supports_virtio_blk;
|
||||
ki_supports_virtio_net = supports_virtio_net;
|
||||
ki_supports_virtio_rng = supports_virtio_rng;
|
||||
ki_supports_virtio_balloon = supports_virtio_balloon;
|
||||
ki_supports_isa_pvpanic = supports_isa_pvpanic;
|
||||
ki_supports_virtio_socket = supports_virtio_socket;
|
||||
ki_is_xen_pv_only_kernel = is_xen_pv_only_kernel;
|
||||
ki_is_debug = is_debug;
|
||||
ki_config_file = config_file;
|
||||
}
|
||||
|
||||
with Not_found -> None
|
||||
)
|
||||
) kernel_pkgs in
|
||||
|
||||
if verbose () then (
|
||||
eprintf "info: installed kernel packages in this guest:\n";
|
||||
List.iter (print_kernel_info stderr "\t") installed_kernels;
|
||||
flush stderr
|
||||
);
|
||||
|
||||
if installed_kernels = [] then
|
||||
error (f_"no installed kernel packages were found.\n\nThis probably indicates that %s was unable to inspect this guest properly.")
|
||||
prog;
|
||||
|
||||
(* Now the difficult bit. Get the bootloader kernels. The first in this
|
||||
* list is the default booting kernel.
|
||||
*)
|
||||
let bootloader_kernels : kernel_info list =
|
||||
let vmlinuzes = bootloader#list_kernels in
|
||||
|
||||
(* Map these to installed kernels. *)
|
||||
List.filter_map (
|
||||
fun vmlinuz ->
|
||||
try
|
||||
let statbuf = g#statns vmlinuz in
|
||||
let kernel =
|
||||
List.find (
|
||||
fun { ki_vmlinuz_stat = s } ->
|
||||
statbuf.G.st_dev = s.G.st_dev && statbuf.G.st_ino = s.G.st_ino
|
||||
) installed_kernels in
|
||||
Some kernel
|
||||
with
|
||||
| Not_found -> None
|
||||
| G.Error msg as exn ->
|
||||
(* If it isn't "no such file or directory", then re-raise it. *)
|
||||
if g#last_errno () <> G.Errno.errno_ENOENT then raise exn;
|
||||
warning (f_"ignoring kernel %s in bootloader, as it does not exist.")
|
||||
vmlinuz;
|
||||
None
|
||||
) vmlinuzes in
|
||||
|
||||
if verbose () then (
|
||||
eprintf "info: kernels offered by the bootloader in this guest (first in list is default):\n";
|
||||
List.iter (print_kernel_info stderr "\t") bootloader_kernels;
|
||||
flush stderr
|
||||
);
|
||||
|
||||
if bootloader_kernels = [] then
|
||||
error (f_"no kernels were found in the bootloader configuration.\n\nThis probably indicates that %s was unable to parse the bootloader configuration of this guest.")
|
||||
prog;
|
||||
|
||||
bootloader_kernels
|
57
virt/common/mldrivers/linux_kernels.mli
Normal file
57
virt/common/mldrivers/linux_kernels.mli
Normal file
@ -0,0 +1,57 @@
|
||||
(* virt-v2v
|
||||
* Copyright (C) 2009-2023 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.
|
||||
*)
|
||||
|
||||
(** Detect which kernels are installed and offered by the bootloader. *)
|
||||
|
||||
type kernel_info = {
|
||||
ki_app : Guestfs.application2; (** The RPM package data. *)
|
||||
ki_name : string; (** eg. "kernel-PAE" *)
|
||||
ki_version : string; (** version-release *)
|
||||
ki_arch : string; (** Kernel architecture. *)
|
||||
ki_vmlinuz : string; (** The path of the vmlinuz file. *)
|
||||
ki_vmlinuz_stat : Guestfs.statns;(** stat(2) of vmlinuz *)
|
||||
ki_initrd : string option; (** Path of initramfs, if found. *)
|
||||
ki_modpath : string; (** The module path. *)
|
||||
ki_modules : string list; (** The list of module names. *)
|
||||
ki_supports_virtio_blk : bool; (** Kernel supports virtio-blk? *)
|
||||
ki_supports_virtio_net : bool; (** Kernel supports virtio-net? *)
|
||||
ki_supports_virtio_rng : bool; (** Kernel supports virtio-rng? *)
|
||||
ki_supports_virtio_balloon : bool; (** Kernel supports memory balloon? *)
|
||||
ki_supports_isa_pvpanic : bool; (** Kernel supports ISA pvpanic device? *)
|
||||
ki_supports_virtio_socket : bool; (** Kernel supports virtio-socket? *)
|
||||
ki_is_xen_pv_only_kernel : bool; (** Is a Xen paravirt-only kernel? *)
|
||||
ki_is_debug : bool; (** Is debug kernel? *)
|
||||
ki_config_file : string option; (** Path of config file, if found. *)
|
||||
}
|
||||
(** Kernel information. *)
|
||||
|
||||
val detect_kernels : Guestfs.guestfs -> string ->
|
||||
Linux_bootloaders.bootloader ->
|
||||
Guestfs.application2 list ->
|
||||
kernel_info list
|
||||
(** [detect_kernels g root bootloader apps] detects the kernels offered
|
||||
by the Linux bootloader (eg. grub).
|
||||
|
||||
It will only return the intersection of kernels that are
|
||||
installed and kernels that the bootloader knows about. The
|
||||
first kernel in the returned list is the default boot option,
|
||||
ie. what the guest would boot without interaction or overrides. *)
|
||||
|
||||
val print_kernel_info : out_channel -> string -> kernel_info -> unit
|
||||
(** Print a kernel_info struct to the given output channel. The
|
||||
second parameter is a prefix for indentation etc. *)
|
261
virt/common/mldrivers/windows_drivers.ml
Normal file
261
virt/common/mldrivers/windows_drivers.ml
Normal file
@ -0,0 +1,261 @@
|
||||
(* virt-drivers
|
||||
* Copyright (C) 2009-2023 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.
|
||||
*)
|
||||
|
||||
(* Detect which drivers are installed in the Windows Registry. *)
|
||||
|
||||
open Printf
|
||||
open Scanf
|
||||
|
||||
open Std_utils
|
||||
open Tools_utils
|
||||
open Common_gettext.Gettext
|
||||
|
||||
module G = Guestfs
|
||||
|
||||
type driver = {
|
||||
name : string; (** Driver name, eg. ["usbport"] *)
|
||||
hwassoc : hardware list; (** Associated list of hardware *)
|
||||
}
|
||||
and hardware =
|
||||
| PCI of pci_device
|
||||
| HID of hid_device
|
||||
| USB of usb_device
|
||||
| Other of string list (** Anything that could not be parsed. *)
|
||||
and pci_device = {
|
||||
pci_class : int64 option;
|
||||
pci_vendor : int64 option;
|
||||
pci_device : int64 option;
|
||||
pci_subsys : int64 option;
|
||||
pci_rev : int64 option;
|
||||
}
|
||||
and hid_device = {
|
||||
hid_vendor : int64 option;
|
||||
hid_product : int64 option;
|
||||
hid_rev : int64 option;
|
||||
hid_col : int64 option;
|
||||
hid_multi : int64 option;
|
||||
}
|
||||
and usb_device = {
|
||||
usb_vendor : int64 option;
|
||||
usb_product : int64 option;
|
||||
usb_rev : int64 option;
|
||||
usb_multi : int64 option;
|
||||
}
|
||||
|
||||
let re_inf = PCRE.compile ~caseless:true "^(.*)\\.inf$"
|
||||
|
||||
let re_pci_cc = PCRE.compile ~caseless:true "^cc_([[:xdigit:]]{4,6})$"
|
||||
let re_pci_ven = PCRE.compile ~caseless:true "^ven_([[:xdigit:]]{4})$"
|
||||
let re_pci_dev = PCRE.compile ~caseless:true "^dev_([[:xdigit:]]{4})$"
|
||||
let re_pci_subsys = PCRE.compile ~caseless:true "^subsys_([[:xdigit:]]{8})$"
|
||||
let re_pci_rev = PCRE.compile ~caseless:true "^rev_([[:xdigit:]]{2})$"
|
||||
|
||||
let re_hid_vid = PCRE.compile ~caseless:true "^vid_([[:xdigit:]]{4})$"
|
||||
let re_hid_pid = PCRE.compile ~caseless:true "^pid_([[:xdigit:]]{4})$"
|
||||
let re_hid_rev = PCRE.compile ~caseless:true "^rev_([[:xdigit:]]{2})$"
|
||||
let re_hid_col = PCRE.compile ~caseless:true "^col([[:xdigit:]]{2})$"
|
||||
let re_hid_multi = PCRE.compile ~caseless:true "^mi_([[:xdigit:]]{2})$"
|
||||
|
||||
let re_usb_vid = PCRE.compile ~caseless:true "^vid_([[:xdigit:]]{4})$"
|
||||
let re_usb_pid = PCRE.compile ~caseless:true "^pid_([[:xdigit:]]{4})$"
|
||||
let re_usb_rev = PCRE.compile ~caseless:true "^rev_([[:xdigit:]]{2})$"
|
||||
let re_usb_multi = PCRE.compile ~caseless:true "^mi_([[:xdigit:]]{2})$"
|
||||
|
||||
let rec detect_drivers (g : G.guestfs) root =
|
||||
assert (g#inspect_get_type root = "windows");
|
||||
|
||||
let windows_system_hive = g#inspect_get_windows_system_hive root in
|
||||
let drivers =
|
||||
Registry.with_hive_readonly g windows_system_hive (
|
||||
fun reg ->
|
||||
let path = [ "DriverDatabase"; "DeviceIds" ] in
|
||||
let deviceids_node =
|
||||
match Registry.get_node reg path with
|
||||
| Some node -> node
|
||||
| None ->
|
||||
error (f_"could not find registry entry \
|
||||
HKEY_LOCAL_MACHINE\\SYSTEM\\DriverDatabase\\DeviceIds \
|
||||
in this Windows guest. It may be either a very old \
|
||||
or very new version of Windows \
|
||||
that we cannot process.") in
|
||||
|
||||
(* inf_name path node *)
|
||||
let children : (string * (string list * int64)) list =
|
||||
get_inf_nodes reg deviceids_node in
|
||||
|
||||
let children =
|
||||
List.map (fun (name, (path, node)) ->
|
||||
String.lowercase_ascii name, (path, node)) children in
|
||||
|
||||
(* Group by inf_name. *)
|
||||
let children = List.sort compare children in
|
||||
let children : (string * (string list * int64) list) list=
|
||||
List.group_by children in
|
||||
|
||||
(* Convert to a final list of drivers. *)
|
||||
List.map (
|
||||
fun (inf_name, hwassoc) ->
|
||||
let hwassoc = List.map path_to_hardware hwassoc in
|
||||
{ name = inf_name; hwassoc }
|
||||
) children
|
||||
) in
|
||||
drivers
|
||||
|
||||
(* Find recursively all child nodes containing a key
|
||||
* "<foo>.inf" = hex(3):01,ff,00,00
|
||||
*
|
||||
* Returns the list of [inf_name * (path * node)] where
|
||||
* [inf_name] is the <foo> part of "<foo>.inf",
|
||||
* [path] is the list of strings (node names) leading to this node,
|
||||
* [node] is the hivex node number of the child node.
|
||||
*)
|
||||
and get_inf_nodes reg root =
|
||||
let nodes : (string list * int64) list = find_all_nodes reg root in
|
||||
List.filter_map (
|
||||
fun (path, h) ->
|
||||
match is_inf_node reg h with
|
||||
| None -> None
|
||||
| Some inf_name -> Some (inf_name, (path, h))
|
||||
) nodes
|
||||
|
||||
and find_all_nodes ((g, _) as reg) node =
|
||||
(* Find all children of [node]. *)
|
||||
let children = g#hivex_node_children node in
|
||||
let children = Array.to_list children in
|
||||
let children =
|
||||
List.map (fun { G.hivex_node_h = h } -> [ g#hivex_node_name h ], h)
|
||||
children in
|
||||
|
||||
(* Add any grandchild nodes below these children. *)
|
||||
let grandchildren =
|
||||
List.map (
|
||||
fun (child_path, child) ->
|
||||
let nodes = find_all_nodes reg child in
|
||||
(* Need to prefix the path returned with the child path. *)
|
||||
List.map (fun (path, h) -> child_path @ path, h) nodes
|
||||
) children in
|
||||
|
||||
children @ List.flatten grandchildren
|
||||
|
||||
(* Does any value under the node satisfy is_inf_value below? *)
|
||||
and is_inf_node ((g, _) as reg) h =
|
||||
(* Get the values in the registry key. *)
|
||||
let values = g#hivex_node_values h in
|
||||
let values = Array.to_list values in
|
||||
let rec loop = function
|
||||
| [] -> None
|
||||
| { G.hivex_value_h = v } :: values ->
|
||||
match is_inf_value reg v with
|
||||
| None -> loop values
|
||||
| Some inf_name -> Some inf_name
|
||||
in
|
||||
loop values
|
||||
|
||||
(* Does the key name end in "<name>.inf" (case insensitive), and have
|
||||
* an associated value which is data type 3, value 01 ff 00 00?
|
||||
* Returns None if no, or Some name if yes.
|
||||
*)
|
||||
and is_inf_value (g, _) v =
|
||||
let typ = g#hivex_value_type v in
|
||||
if typ <> 3L then None
|
||||
else (
|
||||
let key = g#hivex_value_key v in
|
||||
if not (PCRE.matches re_inf key) then None
|
||||
else (
|
||||
let data = g#hivex_value_value v in
|
||||
if data <> "\001\xff\000\000" then None
|
||||
else Some (PCRE.sub 1) (* Return name of .inf file from re_inf above. *)
|
||||
)
|
||||
)
|
||||
|
||||
(* Convert the \DeviceIds\... path to a hardware type, where possible. *)
|
||||
and path_to_hardware (path, _) =
|
||||
match path with
|
||||
| pci :: path when String.lowercase_ascii pci = "pci" ->
|
||||
pci_to_hardware path
|
||||
| hid :: path when String.lowercase_ascii hid = "hid" ->
|
||||
hid_to_hardware path
|
||||
| usb :: path when String.lowercase_ascii usb = "usb" ->
|
||||
usb_to_hardware path
|
||||
| _ -> Other path
|
||||
|
||||
and pci_to_hardware = function
|
||||
| keys :: _ ->
|
||||
let keys = String.nsplit "&" keys in
|
||||
let empty = { pci_class = None; pci_vendor = None; pci_device = None;
|
||||
pci_subsys = None; pci_rev = None } in
|
||||
let f pci key =
|
||||
if PCRE.matches re_pci_cc key then
|
||||
{ pci with pci_class = Some (sscanf (PCRE.sub 1) "%Lx" identity) }
|
||||
else if PCRE.matches re_pci_ven key then
|
||||
{ pci with pci_vendor = Some (sscanf (PCRE.sub 1) "%Lx" identity) }
|
||||
else if PCRE.matches re_pci_dev key then
|
||||
{ pci with pci_device = Some (sscanf (PCRE.sub 1) "%Lx" identity) }
|
||||
else if PCRE.matches re_pci_subsys key then
|
||||
{ pci with pci_subsys = Some (sscanf (PCRE.sub 1) "%Lx" identity) }
|
||||
else if PCRE.matches re_pci_rev key then
|
||||
{ pci with pci_rev = Some (sscanf (PCRE.sub 1) "%Lx" identity) }
|
||||
else
|
||||
pci
|
||||
in
|
||||
PCI (List.fold_left f empty keys)
|
||||
| path -> Other ("PCI" :: path)
|
||||
|
||||
and hid_to_hardware = function
|
||||
| keys :: _ ->
|
||||
let keys = String.nsplit "&" keys in
|
||||
let empty = { hid_vendor = None; hid_product = None;
|
||||
hid_rev = None; hid_col = None; hid_multi = None } in
|
||||
let f hid key =
|
||||
if PCRE.matches re_hid_vid key then
|
||||
{ hid with hid_vendor = Some (sscanf (PCRE.sub 1) "%Lx" identity) }
|
||||
else if PCRE.matches re_hid_pid key then
|
||||
{ hid with hid_product = Some (sscanf (PCRE.sub 1) "%Lx" identity) }
|
||||
else if PCRE.matches re_hid_rev key then
|
||||
{ hid with hid_rev = Some (sscanf (PCRE.sub 1) "%Lx" identity) }
|
||||
else if PCRE.matches re_hid_col key then
|
||||
{ hid with hid_col = Some (sscanf (PCRE.sub 1) "%Lx" identity) }
|
||||
else if PCRE.matches re_hid_multi key then
|
||||
{ hid with hid_multi = Some (sscanf (PCRE.sub 1) "%Lx" identity) }
|
||||
else
|
||||
hid
|
||||
in
|
||||
HID (List.fold_left f empty keys)
|
||||
|
||||
| path -> Other ("HID" :: path)
|
||||
|
||||
and usb_to_hardware = function
|
||||
| keys :: _ ->
|
||||
let keys = String.nsplit "&" keys in
|
||||
let empty = { usb_vendor = None; usb_product = None;
|
||||
usb_rev = None; usb_multi = None } in
|
||||
let f usb key =
|
||||
if PCRE.matches re_usb_vid key then
|
||||
{ usb with usb_vendor = Some (sscanf (PCRE.sub 1) "%Lx" identity) }
|
||||
else if PCRE.matches re_usb_pid key then
|
||||
{ usb with usb_product = Some (sscanf (PCRE.sub 1) "%Lx" identity) }
|
||||
else if PCRE.matches re_usb_rev key then
|
||||
{ usb with usb_rev = Some (sscanf (PCRE.sub 1) "%Lx" identity) }
|
||||
else if PCRE.matches re_usb_multi key then
|
||||
{ usb with usb_multi = Some (sscanf (PCRE.sub 1) "%Lx" identity) }
|
||||
else
|
||||
usb
|
||||
in
|
||||
USB (List.fold_left f empty keys)
|
||||
|
||||
| path -> Other ("USB" :: path)
|
58
virt/common/mldrivers/windows_drivers.mli
Normal file
58
virt/common/mldrivers/windows_drivers.mli
Normal file
@ -0,0 +1,58 @@
|
||||
(* virt-drivers
|
||||
* Copyright (C) 2009-2023 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.
|
||||
*)
|
||||
|
||||
(** Detect which drivers are installed in the Windows Registry. *)
|
||||
|
||||
type driver = {
|
||||
name : string; (** Driver name, eg. ["usbport"] *)
|
||||
hwassoc : hardware list; (** Associated list of hardware *)
|
||||
}
|
||||
and hardware =
|
||||
| PCI of pci_device
|
||||
| HID of hid_device
|
||||
| USB of usb_device
|
||||
| Other of string list (** Anything that could not be parsed. *)
|
||||
and pci_device = {
|
||||
pci_class : int64 option;
|
||||
pci_vendor : int64 option;
|
||||
pci_device : int64 option;
|
||||
pci_subsys : int64 option;
|
||||
pci_rev : int64 option;
|
||||
}
|
||||
and hid_device = {
|
||||
hid_vendor : int64 option;
|
||||
hid_product : int64 option;
|
||||
hid_rev : int64 option;
|
||||
hid_col : int64 option;
|
||||
hid_multi : int64 option;
|
||||
}
|
||||
and usb_device = {
|
||||
usb_vendor : int64 option;
|
||||
usb_product : int64 option;
|
||||
usb_rev : int64 option;
|
||||
usb_multi : int64 option;
|
||||
}
|
||||
|
||||
val detect_drivers : Guestfs.guestfs -> string -> driver list
|
||||
(** [detect_kernels g root] detects the drivers installed in
|
||||
the Windows guest, returning their names and the hardware
|
||||
associations.
|
||||
|
||||
The information is retrieved from the
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\DriverDatabase\DeviceIds\]
|
||||
key in the system registry. *)
|
86
virt/common/mlgettext/Makefile.am
Normal file
86
virt/common/mlgettext/Makefile.am
Normal file
@ -0,0 +1,86 @@
|
||||
# Wrapper around ocaml-gettext.
|
||||
# Copyright (C) 2009-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.
|
||||
|
||||
include $(top_srcdir)/subdir-rules.mk
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(SOURCES_MLI) \
|
||||
$(SOURCES_ML)
|
||||
|
||||
SOURCES_MLI = \
|
||||
common_gettext.mli
|
||||
|
||||
SOURCES_ML = \
|
||||
common_gettext.ml
|
||||
|
||||
if HAVE_OCAML
|
||||
|
||||
# We pretend that we're building a C library. automake handles the
|
||||
# compilation of the C sources for us. At the end we take the C
|
||||
# objects and OCaml objects and link them into the OCaml library.
|
||||
# This C library is never used.
|
||||
|
||||
noinst_LIBRARIES = libmlgettext.a
|
||||
|
||||
if !HAVE_OCAMLOPT
|
||||
MLGETTEXT_CMA = mlgettext.cma
|
||||
else
|
||||
MLGETTEXT_CMA = mlgettext.cmxa
|
||||
endif
|
||||
|
||||
noinst_DATA = $(MLGETTEXT_CMA)
|
||||
|
||||
libmlgettext_a_SOURCES = dummy.c
|
||||
libmlgettext_a_CPPFLAGS = \
|
||||
-I. \
|
||||
-I$(top_builddir)
|
||||
libmlgettext_a_CFLAGS = \
|
||||
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
|
||||
-fPIC
|
||||
|
||||
BOBJECTS = $(SOURCES_ML:.ml=.cmo)
|
||||
XOBJECTS = $(BOBJECTS:.cmo=.cmx)
|
||||
|
||||
OCAMLPACKAGES = -I $(builddir)
|
||||
if HAVE_OCAML_PKG_GETTEXT
|
||||
OCAMLPACKAGES += -package gettext-stub
|
||||
endif
|
||||
|
||||
OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
|
||||
|
||||
if !HAVE_OCAMLOPT
|
||||
OBJECTS = $(BOBJECTS)
|
||||
else
|
||||
OBJECTS = $(XOBJECTS)
|
||||
endif
|
||||
|
||||
libmlgettext_a_DEPENDENCIES = $(OBJECTS)
|
||||
|
||||
mlgettext.cma: $(BOBJECTS)
|
||||
$(OCAMLFIND) ocamlc $(OCAMLPACKAGES) -a $^ -o $@
|
||||
|
||||
if HAVE_OCAMLOPT
|
||||
mlgettext.cmxa: $(XOBJECTS)
|
||||
$(OCAMLFIND) ocamlopt $(OCAMLPACKAGES) -a $^ -o $@
|
||||
endif
|
||||
|
||||
# Dependencies.
|
||||
.depend: $(srcdir)/*.mli $(srcdir)/*.ml
|
||||
$(top_builddir)/ocaml-dep.sh $^
|
||||
-include .depend
|
||||
|
||||
endif
|
918
virt/common/mlgettext/Makefile.in
Normal file
918
virt/common/mlgettext/Makefile.in
Normal file
@ -0,0 +1,918 @@
|
||||
# Makefile.in generated by automake 1.16.5 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
# Wrapper around ocaml-gettext.
|
||||
# Copyright (C) 2009-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.
|
||||
|
||||
# libguestfs
|
||||
# Copyright (C) 2009-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.
|
||||
|
||||
# subdir-rules.mk should be included in every *subdirectory* Makefile.am.
|
||||
|
||||
# libguestfs
|
||||
# Copyright (C) 2013 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.
|
||||
|
||||
# 'common-rules.mk' should be included in every Makefile.am.
|
||||
# cf. 'subdir-rules.mk'
|
||||
|
||||
|
||||
VPATH = @srcdir@
|
||||
am__is_gnu_make = { \
|
||||
if test -z '$(MAKELEVEL)'; then \
|
||||
false; \
|
||||
elif test -n '$(MAKE_HOST)'; then \
|
||||
true; \
|
||||
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
||||
true; \
|
||||
else \
|
||||
false; \
|
||||
fi; \
|
||||
}
|
||||
am__make_running_with_option = \
|
||||
case $${target_option-} in \
|
||||
?) ;; \
|
||||
*) echo "am__make_running_with_option: internal error: invalid" \
|
||||
"target option '$${target_option-}' specified" >&2; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
has_opt=no; \
|
||||
sane_makeflags=$$MAKEFLAGS; \
|
||||
if $(am__is_gnu_make); then \
|
||||
sane_makeflags=$$MFLAGS; \
|
||||
else \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
bs=\\; \
|
||||
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
|
||||
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
|
||||
esac; \
|
||||
fi; \
|
||||
skip_next=no; \
|
||||
strip_trailopt () \
|
||||
{ \
|
||||
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
|
||||
}; \
|
||||
for flg in $$sane_makeflags; do \
|
||||
test $$skip_next = yes && { skip_next=no; continue; }; \
|
||||
case $$flg in \
|
||||
*=*|--*) continue;; \
|
||||
-*I) strip_trailopt 'I'; skip_next=yes;; \
|
||||
-*I?*) strip_trailopt 'I';; \
|
||||
-*O) strip_trailopt 'O'; skip_next=yes;; \
|
||||
-*O?*) strip_trailopt 'O';; \
|
||||
-*l) strip_trailopt 'l'; skip_next=yes;; \
|
||||
-*l?*) strip_trailopt 'l';; \
|
||||
-[dEDm]) skip_next=yes;; \
|
||||
-[JT]) skip_next=yes;; \
|
||||
esac; \
|
||||
case $$flg in \
|
||||
*$$target_option*) has_opt=yes; break;; \
|
||||
esac; \
|
||||
done; \
|
||||
test $$has_opt = yes
|
||||
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
|
||||
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
@HAVE_OCAML_PKG_GETTEXT_TRUE@@HAVE_OCAML_TRUE@am__append_1 = -package gettext-stub
|
||||
subdir = common/mlgettext
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/guestfs-ocaml-gettext.m4 \
|
||||
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
|
||||
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
|
||||
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/ocaml.m4 \
|
||||
$(top_srcdir)/m4/guestfs-progs.m4 \
|
||||
$(top_srcdir)/m4/guestfs-c.m4 \
|
||||
$(top_srcdir)/m4/guestfs-libraries.m4 \
|
||||
$(top_srcdir)/m4/guestfs-ocaml.m4 \
|
||||
$(top_srcdir)/m4/guestfs-perl.m4 \
|
||||
$(top_srcdir)/m4/guestfs-v2v.m4 \
|
||||
$(top_srcdir)/m4/guestfs-bash-completion.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
LIBRARIES = $(noinst_LIBRARIES)
|
||||
ARFLAGS = cru
|
||||
AM_V_AR = $(am__v_AR_@AM_V@)
|
||||
am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
|
||||
am__v_AR_0 = @echo " AR " $@;
|
||||
am__v_AR_1 =
|
||||
libmlgettext_a_AR = $(AR) $(ARFLAGS)
|
||||
libmlgettext_a_LIBADD =
|
||||
am__libmlgettext_a_SOURCES_DIST = dummy.c
|
||||
@HAVE_OCAML_TRUE@am_libmlgettext_a_OBJECTS = \
|
||||
@HAVE_OCAML_TRUE@ libmlgettext_a-dummy.$(OBJEXT)
|
||||
libmlgettext_a_OBJECTS = $(am_libmlgettext_a_OBJECTS)
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
|
||||
am__v_P_0 = false
|
||||
am__v_P_1 = :
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
am__v_GEN_1 =
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
am__v_at_1 =
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
|
||||
depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
|
||||
am__maybe_remake_depfiles = depfiles
|
||||
am__depfiles_remade = ./$(DEPDIR)/libmlgettext_a-dummy.Po
|
||||
am__mv = mv -f
|
||||
AM_V_lt = $(am__v_lt_@AM_V@)
|
||||
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
|
||||
am__v_lt_0 = --silent
|
||||
am__v_lt_1 =
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
|
||||
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
|
||||
$(AM_CFLAGS) $(CFLAGS)
|
||||
AM_V_CC = $(am__v_CC_@AM_V@)
|
||||
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
|
||||
am__v_CC_0 = @echo " CC " $@;
|
||||
am__v_CC_1 =
|
||||
CCLD = $(CC)
|
||||
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
$(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
|
||||
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
|
||||
am__v_CCLD_0 = @echo " CCLD " $@;
|
||||
am__v_CCLD_1 =
|
||||
SOURCES = $(libmlgettext_a_SOURCES)
|
||||
DIST_SOURCES = $(am__libmlgettext_a_SOURCES_DIST)
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
DATA = $(noinst_DATA)
|
||||
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
|
||||
# Read a list of newline-separated strings from the standard input,
|
||||
# and print each of them once, without duplicates. Input order is
|
||||
# *not* preserved.
|
||||
am__uniquify_input = $(AWK) '\
|
||||
BEGIN { nonempty = 0; } \
|
||||
{ items[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in items) print i; }; } \
|
||||
'
|
||||
# Make sure the list of sources is unique. This is necessary because,
|
||||
# e.g., the same source file might be shared among _SOURCES variables
|
||||
# for different programs/libraries.
|
||||
am__define_uniq_tagged_files = \
|
||||
list='$(am__tagged_files)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | $(am__uniquify_input)`
|
||||
am__DIST_COMMON = $(srcdir)/Makefile.in \
|
||||
$(top_srcdir)/build-aux/depcomp $(top_srcdir)/common-rules.mk \
|
||||
$(top_srcdir)/subdir-rules.mk
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
BASH_COMPLETIONS_DIR = @BASH_COMPLETIONS_DIR@
|
||||
BASH_COMPLETION_CFLAGS = @BASH_COMPLETION_CFLAGS@
|
||||
BASH_COMPLETION_LIBS = @BASH_COMPLETION_LIBS@
|
||||
BRANCH_NUMBER = @BRANCH_NUMBER@
|
||||
BRANCH_TYPE = @BRANCH_TYPE@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CSCOPE = @CSCOPE@
|
||||
CTAGS = @CTAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
ETAGS = @ETAGS@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
FILECMD = @FILECMD@
|
||||
GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
|
||||
GMSGFMT = @GMSGFMT@
|
||||
GMSGFMT_015 = @GMSGFMT_015@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
INTLLIBS = @INTLLIBS@
|
||||
INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
|
||||
JANSSON_CFLAGS = @JANSSON_CFLAGS@
|
||||
JANSSON_LIBS = @JANSSON_LIBS@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBCRYPT_CFLAGS = @LIBCRYPT_CFLAGS@
|
||||
LIBCRYPT_LIBS = @LIBCRYPT_LIBS@
|
||||
LIBGUESTFS_CFLAGS = @LIBGUESTFS_CFLAGS@
|
||||
LIBGUESTFS_LIBS = @LIBGUESTFS_LIBS@
|
||||
LIBICONV = @LIBICONV@
|
||||
LIBINTL = @LIBINTL@
|
||||
LIBNBD_CFLAGS = @LIBNBD_CFLAGS@
|
||||
LIBNBD_LIBS = @LIBNBD_LIBS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBOSINFO_CFLAGS = @LIBOSINFO_CFLAGS@
|
||||
LIBOSINFO_LIBS = @LIBOSINFO_LIBS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIBVIRT_CFLAGS = @LIBVIRT_CFLAGS@
|
||||
LIBVIRT_LIBS = @LIBVIRT_LIBS@
|
||||
LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
|
||||
LIBXML2_LIBS = @LIBXML2_LIBS@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBICONV = @LTLIBICONV@
|
||||
LTLIBINTL = @LTLIBINTL@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
MKISOFS = @MKISOFS@
|
||||
MSGCAT = @MSGCAT@
|
||||
MSGFMT = @MSGFMT@
|
||||
MSGMERGE = @MSGMERGE@
|
||||
MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
|
||||
NBDCOPY = @NBDCOPY@
|
||||
NBDINFO = @NBDINFO@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OCAMLBEST = @OCAMLBEST@
|
||||
OCAMLBUILD = @OCAMLBUILD@
|
||||
OCAMLC = @OCAMLC@
|
||||
OCAMLCDOTOPT = @OCAMLCDOTOPT@
|
||||
OCAMLDEP = @OCAMLDEP@
|
||||
OCAMLDOC = @OCAMLDOC@
|
||||
OCAMLFIND = @OCAMLFIND@
|
||||
OCAMLLIB = @OCAMLLIB@
|
||||
OCAMLMKLIB = @OCAMLMKLIB@
|
||||
OCAMLMKTOP = @OCAMLMKTOP@
|
||||
OCAMLOPT = @OCAMLOPT@
|
||||
OCAMLOPTDOTOPT = @OCAMLOPTDOTOPT@
|
||||
OCAMLVERSION = @OCAMLVERSION@
|
||||
OCAML_FLAGS = @OCAML_FLAGS@
|
||||
OCAML_GETTEXT = @OCAML_GETTEXT@
|
||||
OCAML_PKG_gettext = @OCAML_PKG_gettext@
|
||||
OCAML_PKG_guestfs = @OCAML_PKG_guestfs@
|
||||
OCAML_PKG_libvirt = @OCAML_PKG_libvirt@
|
||||
OCAML_PKG_nbd = @OCAML_PKG_nbd@
|
||||
OCAML_PKG_ounit2 = @OCAML_PKG_ounit2@
|
||||
OCAML_RUNTIME_VARIANT_PIC_OPTION = @OCAML_RUNTIME_VARIANT_PIC_OPTION@
|
||||
OCAML_WARN_ERROR = @OCAML_WARN_ERROR@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PACKAGE_VERSION_FULL = @PACKAGE_VERSION_FULL@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PCRE2_CFLAGS = @PCRE2_CFLAGS@
|
||||
PCRE2_CONFIG = @PCRE2_CONFIG@
|
||||
PCRE2_LIBS = @PCRE2_LIBS@
|
||||
PERL = @PERL@
|
||||
PKG_CONFIG = @PKG_CONFIG@
|
||||
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
|
||||
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
|
||||
PO4A_GETTEXTIZE = @PO4A_GETTEXTIZE@
|
||||
PO4A_TRANSLATE = @PO4A_TRANSLATE@
|
||||
PODWRAPPER = @PODWRAPPER@
|
||||
POSUB = @POSUB@
|
||||
PYCODESTYLE = @PYCODESTYLE@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
SQLITE3 = @SQLITE3@
|
||||
STRIP = @STRIP@
|
||||
UNZIP = @UNZIP@
|
||||
USE_NLS = @USE_NLS@
|
||||
VALGRIND = @VALGRIND@
|
||||
VERSION = @VERSION@
|
||||
VIRT_V2V_NBDKIT_PYTHON_PLUGIN = @VIRT_V2V_NBDKIT_PYTHON_PLUGIN@
|
||||
WARN_CFLAGS = @WARN_CFLAGS@
|
||||
WERROR_CFLAGS = @WERROR_CFLAGS@
|
||||
XGETTEXT = @XGETTEXT@
|
||||
XGETTEXT_015 = @XGETTEXT_015@
|
||||
XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
|
||||
ZIP = @ZIP@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
libvirt_ro_uri = @libvirt_ro_uri@
|
||||
localedir = @localedir@
|
||||
localedir_c = @localedir_c@
|
||||
localedir_c_make = @localedir_c_make@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
ounit_is_v2 = @ounit_is_v2@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
|
||||
# Files that should universally be removed by 'make clean'. Note if
|
||||
# there is any case in any subdirectory where a file should not be
|
||||
# removed by 'make clean', it should not be listed here!
|
||||
|
||||
# Editor backup files
|
||||
|
||||
# Patch original and reject files.
|
||||
|
||||
# OCaml intermediate and generated files.
|
||||
|
||||
# OCaml -annot files (used for displaying types in some IDEs).
|
||||
|
||||
# OCaml oUnit generated files.
|
||||
|
||||
# Manual pages - these are all generated from *.pod, so the
|
||||
# pages themselves should all be removed by 'make clean'.
|
||||
|
||||
# Stamp files used when generating man pages.
|
||||
|
||||
# Bindtests temporary files used in many language bindings.
|
||||
CLEANFILES = *~ *.bak *.orig *.rej *.cmi *.cmo *.cma *.cmx *.cmxa \
|
||||
dll*.so *.a *.annot oUnit-*.cache oUnit-*.log *.1 *.3 *.5 *.8 \
|
||||
stamp-*.pod bindtests.tmp
|
||||
|
||||
# Files that should be universally removed by 'make distclean'.
|
||||
DISTCLEANFILES = .depend stamp-*
|
||||
|
||||
# Special suffixes used by OCaml.
|
||||
|
||||
# Special suffixes used by PO files.
|
||||
SUFFIXES = .cmo .cmi .cmx .ml .mli .mll .mly .po .gmo
|
||||
|
||||
# Rules for building OCaml objects.
|
||||
# See also:
|
||||
# guestfs-hacking(1) section "HOW OCAML PROGRAMS ARE COMPILED AND LINKED"
|
||||
@HAVE_OCAMLOPT_FALSE@MLARCHIVE = cma
|
||||
@HAVE_OCAMLOPT_TRUE@MLARCHIVE = cmxa
|
||||
@HAVE_OCAMLOPT_FALSE@LINK_CUSTOM_OCAMLC_ONLY = -output-complete-exe
|
||||
@HAVE_OCAMLOPT_FALSE@BEST = c
|
||||
@HAVE_OCAMLOPT_TRUE@BEST = opt
|
||||
|
||||
# custom silent rules
|
||||
guestfs_am_v_ocamlc = $(guestfs_am_v_ocamlc_@AM_V@)
|
||||
guestfs_am_v_ocamlc_ = $(guestfs_am_v_ocamlc_@AM_DEFAULT_V@)
|
||||
guestfs_am_v_ocamlc_0 = @echo " OCAMLC " $@;
|
||||
guestfs_am_v_ocamlcmi = $(guestfs_am_v_ocamlcmi_@AM_V@)
|
||||
guestfs_am_v_ocamlcmi_ = $(guestfs_am_v_ocamlcmi_@AM_DEFAULT_V@)
|
||||
guestfs_am_v_ocamlcmi_0 = @echo " OCAMLCMI" $@;
|
||||
guestfs_am_v_ocamlopt = $(guestfs_am_v_ocamlopt_@AM_V@)
|
||||
guestfs_am_v_ocamlopt_ = $(guestfs_am_v_ocamlopt_@AM_DEFAULT_V@)
|
||||
guestfs_am_v_ocamlopt_0 = @echo " OCAMLOPT" $@;
|
||||
guestfs_am_v_javac = $(guestfs_am_v_javac_@AM_V@)
|
||||
guestfs_am_v_javac_ = $(guestfs_am_v_javac_@AM_DEFAULT_V@)
|
||||
guestfs_am_v_javac_0 = @echo " JAVAC " $@;
|
||||
guestfs_am_v_erlc = $(guestfs_am_v_erlc_@AM_V@)
|
||||
guestfs_am_v_erlc_ = $(guestfs_am_v_erlc_@AM_DEFAULT_V@)
|
||||
guestfs_am_v_erlc_0 = @echo " ERLC " $@;
|
||||
guestfs_am_v_podwrapper = $(guestfs_am_v_podwrapper_@AM_V@)
|
||||
guestfs_am_v_podwrapper_ = $(guestfs_am_v_podwrapper_@AM_DEFAULT_V@)
|
||||
guestfs_am_v_podwrapper_0 = @echo " POD " $@;
|
||||
guestfs_am_v_jar = $(guestfs_am_v_jar_@AM_V@)
|
||||
guestfs_am_v_jar_ = $(guestfs_am_v_jar_@AM_DEFAULT_V@)
|
||||
guestfs_am_v_jar_0 = @echo " JAR " $@;
|
||||
guestfs_am_v_po4a_translate = $(guestfs_am_v_po4a_translate_@AM_V@)
|
||||
guestfs_am_v_po4a_translate_ = $(guestfs_am_v_po4a_translate_@AM_DEFAULT_V@)
|
||||
guestfs_am_v_po4a_translate_0 = @echo " PO4A-T " $@;
|
||||
EXTRA_DIST = \
|
||||
$(SOURCES_MLI) \
|
||||
$(SOURCES_ML)
|
||||
|
||||
SOURCES_MLI = \
|
||||
common_gettext.mli
|
||||
|
||||
SOURCES_ML = \
|
||||
common_gettext.ml
|
||||
|
||||
|
||||
# We pretend that we're building a C library. automake handles the
|
||||
# compilation of the C sources for us. At the end we take the C
|
||||
# objects and OCaml objects and link them into the OCaml library.
|
||||
# This C library is never used.
|
||||
@HAVE_OCAML_TRUE@noinst_LIBRARIES = libmlgettext.a
|
||||
@HAVE_OCAMLOPT_FALSE@@HAVE_OCAML_TRUE@MLGETTEXT_CMA = mlgettext.cma
|
||||
@HAVE_OCAMLOPT_TRUE@@HAVE_OCAML_TRUE@MLGETTEXT_CMA = mlgettext.cmxa
|
||||
@HAVE_OCAML_TRUE@noinst_DATA = $(MLGETTEXT_CMA)
|
||||
@HAVE_OCAML_TRUE@libmlgettext_a_SOURCES = dummy.c
|
||||
@HAVE_OCAML_TRUE@libmlgettext_a_CPPFLAGS = \
|
||||
@HAVE_OCAML_TRUE@ -I. \
|
||||
@HAVE_OCAML_TRUE@ -I$(top_builddir)
|
||||
|
||||
@HAVE_OCAML_TRUE@libmlgettext_a_CFLAGS = \
|
||||
@HAVE_OCAML_TRUE@ $(WARN_CFLAGS) $(WERROR_CFLAGS) \
|
||||
@HAVE_OCAML_TRUE@ -fPIC
|
||||
|
||||
@HAVE_OCAML_TRUE@BOBJECTS = $(SOURCES_ML:.ml=.cmo)
|
||||
@HAVE_OCAML_TRUE@XOBJECTS = $(BOBJECTS:.cmo=.cmx)
|
||||
@HAVE_OCAML_TRUE@OCAMLPACKAGES = -I $(builddir) $(am__append_1)
|
||||
@HAVE_OCAML_TRUE@OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
|
||||
@HAVE_OCAMLOPT_FALSE@@HAVE_OCAML_TRUE@OBJECTS = $(BOBJECTS)
|
||||
@HAVE_OCAMLOPT_TRUE@@HAVE_OCAML_TRUE@OBJECTS = $(XOBJECTS)
|
||||
@HAVE_OCAML_TRUE@libmlgettext_a_DEPENDENCIES = $(OBJECTS)
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .cmo .cmi .cmx .ml .mli .mll .mly .po .gmo .c .lo .o .obj
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/subdir-rules.mk $(top_srcdir)/common-rules.mk $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign common/mlgettext/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign common/mlgettext/Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
|
||||
esac;
|
||||
$(top_srcdir)/subdir-rules.mk $(top_srcdir)/common-rules.mk $(am__empty):
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
clean-noinstLIBRARIES:
|
||||
-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
|
||||
|
||||
libmlgettext.a: $(libmlgettext_a_OBJECTS) $(libmlgettext_a_DEPENDENCIES) $(EXTRA_libmlgettext_a_DEPENDENCIES)
|
||||
$(AM_V_at)-rm -f libmlgettext.a
|
||||
$(AM_V_AR)$(libmlgettext_a_AR) libmlgettext.a $(libmlgettext_a_OBJECTS) $(libmlgettext_a_LIBADD)
|
||||
$(AM_V_at)$(RANLIB) libmlgettext.a
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmlgettext_a-dummy.Po@am__quote@ # am--include-marker
|
||||
|
||||
$(am__depfiles_remade):
|
||||
@$(MKDIR_P) $(@D)
|
||||
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
|
||||
|
||||
am--depfiles: $(am__depfiles_remade)
|
||||
|
||||
.c.o:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
|
||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
|
||||
|
||||
.c.obj:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
|
||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
|
||||
.c.lo:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
|
||||
@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
|
||||
|
||||
libmlgettext_a-dummy.o: dummy.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmlgettext_a_CPPFLAGS) $(CPPFLAGS) $(libmlgettext_a_CFLAGS) $(CFLAGS) -MT libmlgettext_a-dummy.o -MD -MP -MF $(DEPDIR)/libmlgettext_a-dummy.Tpo -c -o libmlgettext_a-dummy.o `test -f 'dummy.c' || echo '$(srcdir)/'`dummy.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmlgettext_a-dummy.Tpo $(DEPDIR)/libmlgettext_a-dummy.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dummy.c' object='libmlgettext_a-dummy.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmlgettext_a_CPPFLAGS) $(CPPFLAGS) $(libmlgettext_a_CFLAGS) $(CFLAGS) -c -o libmlgettext_a-dummy.o `test -f 'dummy.c' || echo '$(srcdir)/'`dummy.c
|
||||
|
||||
libmlgettext_a-dummy.obj: dummy.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmlgettext_a_CPPFLAGS) $(CPPFLAGS) $(libmlgettext_a_CFLAGS) $(CFLAGS) -MT libmlgettext_a-dummy.obj -MD -MP -MF $(DEPDIR)/libmlgettext_a-dummy.Tpo -c -o libmlgettext_a-dummy.obj `if test -f 'dummy.c'; then $(CYGPATH_W) 'dummy.c'; else $(CYGPATH_W) '$(srcdir)/dummy.c'; fi`
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmlgettext_a-dummy.Tpo $(DEPDIR)/libmlgettext_a-dummy.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dummy.c' object='libmlgettext_a-dummy.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmlgettext_a_CPPFLAGS) $(CPPFLAGS) $(libmlgettext_a_CFLAGS) $(CFLAGS) -c -o libmlgettext_a-dummy.obj `if test -f 'dummy.c'; then $(CYGPATH_W) 'dummy.c'; else $(CYGPATH_W) '$(srcdir)/dummy.c'; fi`
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
ID: $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); mkid -fID $$unique
|
||||
tags: tags-am
|
||||
TAGS: tags
|
||||
|
||||
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
$(am__define_uniq_tagged_files); \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: ctags-am
|
||||
|
||||
CTAGS: ctags
|
||||
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
cscopelist: cscopelist-am
|
||||
|
||||
cscopelist-am: $(am__tagged_files)
|
||||
list='$(am__tagged_files)'; \
|
||||
case "$(srcdir)" in \
|
||||
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
|
||||
*) sdir=$(subdir)/$(srcdir) ;; \
|
||||
esac; \
|
||||
for i in $$list; do \
|
||||
if test -f "$$i"; then \
|
||||
echo "$(subdir)/$$i"; \
|
||||
else \
|
||||
echo "$$sdir/$$i"; \
|
||||
fi; \
|
||||
done >> $(top_builddir)/cscope.files
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
distdir: $(BUILT_SOURCES)
|
||||
$(MAKE) $(AM_MAKEFLAGS) distdir-am
|
||||
|
||||
distdir-am: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(LIBRARIES) $(DATA)
|
||||
installdirs:
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
|
||||
mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -f ./$(DEPDIR)/libmlgettext_a-dummy.Po
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -f ./$(DEPDIR)/libmlgettext_a-dummy.Po
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
|
||||
mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am:
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
|
||||
clean-generic clean-libtool clean-noinstLIBRARIES \
|
||||
cscopelist-am ctags ctags-am distclean distclean-compile \
|
||||
distclean-generic distclean-libtool distclean-tags distdir dvi \
|
||||
dvi-am html html-am info info-am install install-am \
|
||||
install-data install-data-am install-dvi install-dvi-am \
|
||||
install-exec install-exec-am install-html install-html-am \
|
||||
install-info install-info-am install-man install-pdf \
|
||||
install-pdf-am install-ps install-ps-am install-strip \
|
||||
installcheck installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-compile \
|
||||
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||
tags tags-am uninstall uninstall-am
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
||||
|
||||
-include $(top_builddir)/localenv
|
||||
|
||||
# Individual Makefile.am's should define generator_built if that
|
||||
# subdirectory contains any files which are built by the generator.
|
||||
# Set generator_built to the list of those files.
|
||||
|
||||
$(generator_built): $(top_builddir)/generator/stamp-generator
|
||||
|
||||
$(top_builddir)/generator/stamp-generator: $(top_builddir)/generator/generator
|
||||
@if test -f $(top_builddir)/generator/Makefile; then \
|
||||
$(MAKE) -C $(top_builddir)/generator stamp-generator; \
|
||||
else \
|
||||
echo "warning: Run 'make' at the top level to build $(generator_built)"; \
|
||||
fi
|
||||
|
||||
# If this file doesn't exist, just print a warning and continue.
|
||||
# During 'make distclean' we can end up deleting this file.
|
||||
$(top_builddir)/generator/generator:
|
||||
@if test -f $(top_builddir)/generator/Makefile; then \
|
||||
$(MAKE) -C $(top_builddir)/generator generator; \
|
||||
else \
|
||||
echo "warning: Run 'make' at the top level to build $@"; \
|
||||
fi
|
||||
|
||||
%.cmi: %.mli
|
||||
$(guestfs_am_v_ocamlcmi)$(OCAMLFIND) ocamlc -package guestfs $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@
|
||||
%.cmo: %.ml
|
||||
$(guestfs_am_v_ocamlc)$(OCAMLFIND) ocamlc -package guestfs $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@
|
||||
@HAVE_OCAMLOPT_TRUE@%.cmx: %.ml
|
||||
@HAVE_OCAMLOPT_TRUE@ $(guestfs_am_v_ocamlopt)$(OCAMLFIND) ocamlopt -package guestfs $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@
|
||||
|
||||
# A few parts of the common/ submodule use $TEST_FUNCTIONS expecting
|
||||
# it to be replaced with the old hacky test-functions.sh script and
|
||||
# some local variables (as happens in libguestfs). Until we can
|
||||
# replace that. use this for now.
|
||||
export TEST_FUNCTIONS := exit 77
|
||||
|
||||
@HAVE_OCAML_TRUE@mlgettext.cma: $(BOBJECTS)
|
||||
@HAVE_OCAML_TRUE@ $(OCAMLFIND) ocamlc $(OCAMLPACKAGES) -a $^ -o $@
|
||||
|
||||
@HAVE_OCAMLOPT_TRUE@@HAVE_OCAML_TRUE@mlgettext.cmxa: $(XOBJECTS)
|
||||
@HAVE_OCAMLOPT_TRUE@@HAVE_OCAML_TRUE@ $(OCAMLFIND) ocamlopt $(OCAMLPACKAGES) -a $^ -o $@
|
||||
|
||||
# Dependencies.
|
||||
@HAVE_OCAML_TRUE@.depend: $(srcdir)/*.mli $(srcdir)/*.ml
|
||||
@HAVE_OCAML_TRUE@ $(top_builddir)/ocaml-dep.sh $^
|
||||
@HAVE_OCAML_TRUE@-include .depend
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
10
virt/common/mlgettext/common_gettext.ml
Normal file
10
virt/common/mlgettext/common_gettext.ml
Normal file
@ -0,0 +1,10 @@
|
||||
(* This file is generated automatically by ./configure. *)
|
||||
|
||||
module Gettext = Gettext.Program (
|
||||
struct
|
||||
let textdomain = "virt-v2v"
|
||||
let codeset = None
|
||||
let dir = None
|
||||
let dependencies = []
|
||||
end
|
||||
) (GettextStub.Native)
|
59
virt/common/mlgettext/common_gettext.mli
Normal file
59
virt/common/mlgettext/common_gettext.mli
Normal file
@ -0,0 +1,59 @@
|
||||
(* Wrapper around ocaml-gettext.
|
||||
* Copyright (C) 2009-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.
|
||||
*)
|
||||
|
||||
(** Gettext functions for OCaml virt tools.
|
||||
|
||||
The Common_gettext module provides gettext functions, or dummy
|
||||
functions if ocaml-gettext was not available at configure time.
|
||||
|
||||
{b Note}: Don't translate debug strings, or strings which are
|
||||
meant to be read/written only by machine.
|
||||
|
||||
There are two ways to translate constant strings in OCaml programs.
|
||||
|
||||
For ordinary strings, replace ["string"] with [s_"string"]. Since
|
||||
this is a function call to a function called [s_], you may have
|
||||
to put parentheses around the expression.
|
||||
|
||||
For format strings, use:
|
||||
|
||||
{v
|
||||
printf (f_"zeroing filesystem %s") filename;
|
||||
v}
|
||||
|
||||
Note for format strings, the parentheses are almost always required,
|
||||
and they just go around the [(f_"string")], {i not} around the other
|
||||
arguments of the printf function.
|
||||
|
||||
At build time, a program parses the OCaml code into an abstract
|
||||
syntax tree and statically determines all calls to the special
|
||||
[s_] and [f_] functions, which means: (a) You can be very loose
|
||||
with syntax, unlike ordinary xgettext, but (b) you cannot rename
|
||||
these functions.
|
||||
*)
|
||||
|
||||
module Gettext : sig
|
||||
val s_ : string -> string
|
||||
val f_ :
|
||||
('a, 'b, 'c, 'c, 'c, 'd) format6 -> ('a, 'b, 'c, 'c, 'c, 'd) format6
|
||||
val sn_ : string -> string -> int -> string
|
||||
val fn_ :
|
||||
('a, 'b, 'c, 'c, 'c, 'd) format6 ->
|
||||
('a, 'b, 'c, 'c, 'c, 'd) format6 ->
|
||||
int -> ('a, 'b, 'c, 'c, 'c, 'd) format6
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user