Compare commits

...

No commits in common. "v2.7.4" and "sisyphus" have entirely different histories.

1323 changed files with 121246 additions and 1760 deletions

29
.gear/cronbuild-update-source Executable file
View 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
View File

@ -0,0 +1,2 @@
copy: *.patch
tar.gz: virt name=virt-v2v-@version@

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "common"]
path = common
url = https://github.com/libguestfs/libguestfs-common

1
common

@ -1 +0,0 @@
Subproject commit 4b0f1890a41444fdacc71e418e56f6d78b46aa26

24
fixes-common.patch Normal file
View 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)

View File

@ -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
)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
View 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.

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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.

View 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

File diff suppressed because it is too large Load Diff

348
virt/build-aux/compile Executable file
View 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

File diff suppressed because it is too large Load Diff

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
View 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
View 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

File diff suppressed because it is too large Load Diff

215
virt/build-aux/missing Executable file
View 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
View 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='' # Red.
grn='' # Green.
lgn='' # Light green.
blu='' # Blue.
mgn='' # Magenta.
std='' # 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:

View File

68
virt/common/.gitignore vendored Normal file
View 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
View 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

View 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, &times) == -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 */
}

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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 "/"

View 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]. *)

View 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
)

View File

@ -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. *)

View 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);
}

View 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"

View 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. *)

View 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 guests package manager
(eg. apt, yum, etc.) and the guests 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 guests package manager
(eg. apt, yum, etc.) and the hosts 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 guests 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

View 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]

View 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

View 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. *)

View 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 *)

View 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

View 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

View 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). *)

View 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

View 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]. *)

View 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 ()
)

View 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. *)

View 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

View 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. *)

View 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

View 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. *)

View 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);
}

View 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

View 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

View 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
)

View 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. *)

View 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

View 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. *)

View 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

View 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. *)

View 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"

View 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"

View 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

View 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. *)

View 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 guests package manager
(eg. apt, yum, etc.) and the guests 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 guests package manager
(eg. apt, yum, etc.) and the hosts 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 guests 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

View 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]

View 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

View 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:

View 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

View 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. *)

View 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_"dont 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_"dont 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_"dont 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

View 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. *)

View 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

View 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. *)

View 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

View 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. *)

View 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)

View 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. *)

View 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

View 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:

View 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)

View 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