Copy disabled (too large)
Download .txt
Showing preview only (15,328K chars total). Download the full file to get everything.
Repository: libguestfs/virt-v2v
Branch: master
Commit: 6a4c8d827d46
Files: 463
Total size: 14.4 MB
Directory structure:
gitextract_gtcdlbtn/
├── .github/
│ └── workflows/
│ └── main.yml
├── .gitignore
├── .gitmodules
├── COPYING
├── Makefile.am
├── README
├── TODO
├── bash/
│ ├── Makefile.am
│ ├── README
│ ├── test-complete-in-script.sh
│ └── virt-v2v
├── bugs-in-changelog.sh
├── check-mli.sh
├── common-rules.mk
├── config.sh.in
├── configure.ac
├── contrib/
│ └── remove-guestor.reg
├── convert/
│ ├── Makefile.am
│ ├── choose_root.ml
│ ├── choose_root.mli
│ ├── convert.ml
│ ├── convert.mli
│ ├── convert_linux.ml
│ ├── convert_linux.mli
│ ├── convert_types.ml
│ ├── convert_types.mli
│ ├── convert_windows.ml
│ ├── convert_windows.mli
│ ├── dummy.c
│ ├── mount_filesystems.ml
│ ├── mount_filesystems.mli
│ ├── target_bus_assignment.ml
│ └── target_bus_assignment.mli
├── docs/
│ ├── Makefile.am
│ ├── test-docs.sh
│ ├── virt-v2v-hacking.pod
│ ├── virt-v2v-input-vmware.pod
│ ├── virt-v2v-input-xen.pod
│ ├── virt-v2v-output-local.pod
│ ├── virt-v2v-output-openstack.pod
│ ├── virt-v2v-output-ovirt.pod
│ ├── virt-v2v-release-notes-1.42.pod
│ ├── virt-v2v-release-notes-2.0.pod
│ ├── virt-v2v-release-notes-2.10.pod
│ ├── virt-v2v-release-notes-2.2.pod
│ ├── virt-v2v-release-notes-2.4.pod
│ ├── virt-v2v-release-notes-2.6.pod
│ ├── virt-v2v-release-notes-2.8.pod
│ ├── virt-v2v-support.pod
│ ├── virt-v2v.pod
│ └── vm-generation-id-across-hypervisors.txt
├── gnulib/
│ └── lib/
│ ├── Makefile.am
│ ├── bitrotate.h
│ ├── c-ctype.h
│ ├── getprogname.h
│ ├── hash.c
│ ├── hash.h
│ ├── ignore-value.h
│ ├── xalloc-oversized.h
│ ├── xstrtol.c
│ ├── xstrtol.h
│ ├── xstrtoll.c
│ ├── xstrtoul.c
│ ├── xstrtoull.c
│ └── xstrtoumax.c
├── in-place/
│ ├── Makefile.am
│ ├── dummy.c
│ ├── in_place.ml
│ ├── in_place.mli
│ ├── test-docs.sh
│ └── virt-v2v-in-place.pod
├── input/
│ ├── Makefile.am
│ ├── OVA.ml
│ ├── OVA.mli
│ ├── OVF.ml
│ ├── OVF.mli
│ ├── VMX.ml
│ ├── VMX.mli
│ ├── dummy.c
│ ├── input.ml
│ ├── input.mli
│ ├── input_disk.ml
│ ├── input_disk.mli
│ ├── input_libvirt.ml
│ ├── input_libvirt.mli
│ ├── input_ova.ml
│ ├── input_ova.mli
│ ├── input_vcenter_https.ml
│ ├── input_vcenter_https.mli
│ ├── input_vddk.ml
│ ├── input_vddk.mli
│ ├── input_vmx.ml
│ ├── input_vmx.mli
│ ├── input_xen_ssh.ml
│ ├── input_xen_ssh.mli
│ ├── nbdkit_curl.ml
│ ├── nbdkit_curl.mli
│ ├── nbdkit_ssh.ml
│ ├── nbdkit_ssh.mli
│ ├── parse_domain_from_vmx.ml
│ ├── parse_domain_from_vmx.mli
│ ├── parse_libvirt_xml.ml
│ ├── parse_libvirt_xml.mli
│ ├── select_input.ml
│ ├── select_input.mli
│ ├── ssh.ml
│ ├── ssh.mli
│ ├── vCenter.ml
│ └── vCenter.mli
├── inspector/
│ ├── Makefile.am
│ ├── create_inspector_xml.ml
│ ├── create_inspector_xml.mli
│ ├── dummy.c
│ ├── inspector.ml
│ ├── inspector.mli
│ ├── test-docs.sh
│ └── virt-v2v-inspector.pod
├── installcheck.sh.in
├── lib/
│ ├── Makefile.am
│ ├── NBD_URI.ml
│ ├── NBD_URI.mli
│ ├── YAML.ml
│ ├── YAML.mli
│ ├── config.ml.in
│ ├── config.mli
│ ├── create_ovf.ml
│ ├── create_ovf.mli
│ ├── dummy.c
│ ├── guestfs-internal-all.h
│ ├── libvirt_utils.ml
│ ├── libvirt_utils.mli
│ ├── nbdkit.ml
│ ├── nbdkit.mli
│ ├── networks.ml
│ ├── networks.mli
│ ├── qemuNBD.ml
│ ├── qemuNBD.mli
│ ├── types.ml
│ ├── types.mli
│ ├── utils.ml
│ └── utils.mli
├── m4/
│ ├── guestfs-bash-completion.m4
│ ├── guestfs-c.m4
│ ├── guestfs-libraries.m4
│ ├── guestfs-ocaml-gettext.m4
│ ├── guestfs-ocaml.m4
│ ├── guestfs-perl.m4
│ ├── guestfs-progs.m4
│ └── ocaml.m4
├── ocaml-dep.sh.in
├── ocaml-link.sh.in
├── open/
│ ├── Makefile.am
│ ├── dummy.c
│ ├── open.ml
│ ├── open.mli
│ ├── test-docs.sh
│ └── virt-v2v-open.pod
├── output/
│ ├── Makefile.am
│ ├── changeuid.ml
│ ├── changeuid.mli
│ ├── create_kubevirt_yaml.ml
│ ├── create_kubevirt_yaml.mli
│ ├── create_libvirt_xml.ml
│ ├── create_libvirt_xml.mli
│ ├── embed.sh
│ ├── openstack_image_properties.ml
│ ├── openstack_image_properties.mli
│ ├── output.ml
│ ├── output.mli
│ ├── output_disk.ml
│ ├── output_disk.mli
│ ├── output_glance.ml
│ ├── output_glance.mli
│ ├── output_kubevirt.ml
│ ├── output_kubevirt.mli
│ ├── output_libvirt.ml
│ ├── output_libvirt.mli
│ ├── output_null.ml
│ ├── output_null.mli
│ ├── output_openstack.ml
│ ├── output_openstack.mli
│ ├── output_ovirt.ml
│ ├── output_ovirt.mli
│ ├── output_ovirt_upload.ml
│ ├── output_ovirt_upload.mli
│ ├── output_ovirt_upload_cancel_source.mli
│ ├── output_ovirt_upload_createvm_source.mli
│ ├── output_ovirt_upload_finalize_source.mli
│ ├── output_ovirt_upload_plugin_source.mli
│ ├── output_ovirt_upload_precheck_source.mli
│ ├── output_ovirt_upload_transfer_source.mli
│ ├── output_ovirt_upload_vmcheck_source.mli
│ ├── output_qemu.ml
│ ├── output_qemu.mli
│ ├── output_vdsm.ml
│ ├── output_vdsm.mli
│ ├── ovirt-upload-cancel.py
│ ├── ovirt-upload-createvm.py
│ ├── ovirt-upload-finalize.py
│ ├── ovirt-upload-plugin.py
│ ├── ovirt-upload-precheck.py
│ ├── ovirt-upload-transfer.py
│ ├── ovirt-upload-vmcheck.py
│ ├── python_script.ml
│ ├── python_script.mli
│ ├── qemuopts-c.c
│ ├── qemuopts.ml
│ ├── qemuopts.mli
│ ├── select_output.ml
│ ├── select_output.mli
│ └── test-python-syntax.sh
├── po/
│ ├── LINGUAS
│ ├── Makefile.am
│ ├── POTFILES
│ ├── POTFILES-ml
│ ├── cs.po
│ ├── de.po
│ ├── en_GB.po
│ ├── es.po
│ ├── eu.po
│ ├── fi.po
│ ├── fr.po
│ ├── gu.po
│ ├── hi.po
│ ├── id.po
│ ├── it.po
│ ├── ja.po
│ ├── ka.po
│ ├── kn.po
│ ├── ml.po
│ ├── mr.po
│ ├── nl.po
│ ├── or.po
│ ├── pa.po
│ ├── pl.po
│ ├── pt_BR.po
│ ├── ru.po
│ ├── si.po
│ ├── ta.po
│ ├── te.po
│ ├── tg.po
│ ├── uk.po
│ ├── virt-v2v.pot
│ └── zh_CN.po
├── po-docs/
│ ├── LINGUAS
│ ├── Makefile.am
│ ├── cs.po
│ ├── de.po
│ ├── en_GB.po
│ ├── es.po
│ ├── eu.po
│ ├── fi.po
│ ├── fr.po
│ ├── gu.po
│ ├── hi.po
│ ├── id.po
│ ├── it.po
│ ├── ja/
│ │ └── Makefile.am
│ ├── ja.po
│ ├── ka.po
│ ├── kn.po
│ ├── language.mk
│ ├── ml.po
│ ├── mr.po
│ ├── nl.po
│ ├── or.po
│ ├── pa.po
│ ├── pl.po
│ ├── podfiles
│ ├── pt_BR.po
│ ├── ru.po
│ ├── si.po
│ ├── ta.po
│ ├── te.po
│ ├── tg.po
│ ├── uk/
│ │ └── Makefile.am
│ ├── uk.po
│ ├── virt-v2v-docs.pot
│ └── zh_CN.po
├── podcheck.pl
├── podwrapper.pl.in
├── run.in
├── scripts/
│ └── git.orderfile
├── subdir-rules.mk
├── test-data/
│ ├── Makefile.am
│ ├── binaries/
│ │ ├── Makefile.am
│ │ ├── README
│ │ └── bin-x86_64-dynamic
│ ├── fake-virt-tools/
│ │ └── Makefile.am
│ ├── fake-virtio-win/
│ │ ├── Makefile.am
│ │ ├── virtio-win-drivers-list.txt
│ │ └── virtio-win-iso-list.txt
│ └── phony-guests/
│ ├── Makefile.am
│ ├── archlinux-package
│ ├── debian-packages
│ ├── debian-syslog
│ ├── fedora-db.sql.xz
│ ├── fedora-journal.tar.xz
│ ├── fedora.c
│ ├── guests.xml.in
│ ├── make-archlinux-img.sh
│ ├── make-coreos-img.sh
│ ├── make-debian-img.sh
│ ├── make-fedora-img.pl
│ ├── make-guests-all-good.pl
│ ├── make-ubuntu-img.sh
│ ├── make-windows-img.sh
│ ├── minimal-hive
│ ├── win10-software.reg
│ ├── win11-software.reg
│ ├── win2k22-software.reg
│ ├── win2k25-software.reg
│ ├── win7-32-software.reg
│ ├── windows-bcd.reg
│ ├── windows-software-all.reg
│ ├── windows-system.reg
│ └── winxp-32-software.reg
├── tests/
│ ├── Makefile.am
│ ├── functions.sh.in
│ ├── libvirt-is-version.c
│ ├── test-bad-networks-and-bridges.sh
│ ├── test-block-driver.sh
│ ├── test-cdrom.expected
│ ├── test-cdrom.sh
│ ├── test-cdrom.xml.in
│ ├── 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-floppy.xml.in
│ ├── test-i-disk-nbd.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-xml.sh
│ ├── test-in-place.sh
│ ├── test-inspector.sh
│ ├── test-it-vddk-io-query.sh
│ ├── test-mac-expected.xml
│ ├── test-mac.sh
│ ├── test-mac.xml.in
│ ├── test-machine-readable.sh
│ ├── test-networks-and-bridges-expected.xml
│ ├── test-networks-and-bridges.sh
│ ├── test-networks-and-bridges.xml.in
│ ├── test-no-fstrim.sh
│ ├── test-o-glance.sh
│ ├── test-o-kubevirt-fedora.sh
│ ├── test-o-kubevirt-fedora.yaml.expected
│ ├── test-o-kubevirt-oo-disk.sh
│ ├── 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-ovirt-upload-module/
│ │ ├── imageio.py
│ │ └── ovirtsdk4/
│ │ ├── __init__.py
│ │ └── types.py
│ ├── test-o-ovirt-upload-oo-query.sh
│ ├── test-o-ovirt-upload.sh
│ ├── test-o-ovirt.ovf.expected
│ ├── test-o-ovirt.sh
│ ├── test-o-qemu.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-open-encrypted.sh
│ ├── test-open.sh
│ ├── test-phony-win10-ls.txt
│ ├── test-phony-win11-ls.txt
│ ├── test-phony-win2k22-ls.txt
│ ├── test-phony-win2k25-ls.txt
│ ├── test-phony-win7-32-ls.txt
│ ├── test-phony-winxp-32-ls.txt
│ ├── test-print-source.expected
│ ├── test-print-source.sh
│ ├── test-print-source.xml.in
│ ├── test-reject-blank-disk.sh
│ ├── test-rhbz1232192.sh
│ ├── test-rhbz1232192.xml.in
│ ├── test-sound.sh
│ ├── test-sound.xml.in
│ ├── test-trim.sh
│ ├── test-virtio-win-iso.sh
│ ├── test-windows-conversion-ls.txt
│ ├── test-windows-conversion.sh
│ ├── test-windows-phony.sh
│ └── test-windows-uefi-conversion.sh
├── tmp/
│ └── .gitignore
├── v2v/
│ ├── Makefile.am
│ ├── dummy.c
│ ├── v2v.ml
│ ├── v2v.mli
│ └── v2v_unit_tests.ml
├── valgrind-suppressions
└── website/
├── easytoread.css
├── feed.css
├── index.css
├── index.html.in
├── pod.css
└── standard.css
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/main.yml
================================================
# Run the jobs below on every push to master branch and pull request.
on:
push:
branches:
- master
- 'ci/**' # Allow automatic CI testing on ci/* branches
pull_request:
branches:
- master
workflow_dispatch: # Allow manual triggering on any branch
# Runs basic configure, make and make check.
jobs:
# ubuntu:
# name: Ubuntu
# runs-on: ubuntu-${{ matrix.release }}
# continue-on-error: true
# strategy:
# fail-fast: false
# matrix:
# release:
# - 24.04
# steps:
# - name: Identify the system
# run: |
# cat /etc/os-release
# - name: Enable source repositories
# run: |
# sudo sed -i 's/Types: deb$/Types: deb deb-src/g' \
# /etc/apt/sources.list.d/ubuntu.sources
# - name: Install build dependencies
# run: |
# sudo apt-get update
# sudo apt-get -y build-dep virt-v2v
# - name: Install extra dependencies
# run: |
# # Git is needed to run git submodule command.
# sudo apt-get -y install git
# - name: Fix broken Ubuntu kernel permissions
# run: |
# # https://bugs.launchpad.net/ubuntu/+source/linux/+bug/759725
# sudo chmod 0644 /boot/vmlinuz*
# - name: Enable KVM
# run: |
# sudo chmod 0666 /dev/kvm
# - name: Checkout sources
# uses: actions/checkout@v5
# - name: Checkout submodule
# run: |
# git submodule update --init
# - name: Compile the code
# run: |
# autoreconf -fiv
# ./configure --enable-werror
# make -j
# - name: Run the full tests
# run: |
# if ! make check; then
# find -name test-suite.log -exec cat {} \;
# exit 1
# fi
fedora:
name: Fedora
runs-on: ubuntu-latest # VM where the container runs
strategy:
fail-fast: false
matrix:
release:
- 43
container:
image: quay.io/fedora/fedora:${{ matrix.release }}
options: --privileged
steps:
- name: Identify the system
run: |
cat /etc/os-release
- name: Install build dependencies
run: |
dnf builddep -y virt-v2v libguestfs
# Install a bunch of bits to enable more tests
dnf install -y \
git kernel sqlite perl-hivex \
mingw-srvany-redistributable nbdkit-\* virt-v2v \
guestfs-tools\*
# Hides 'multiple definition' warnings
dnf remove -y ocaml-libguestfs\*
- name: Checkout sources
uses: actions/checkout@v5
- name: Checkout and build libguestfs
run: |
git clone --depth=1 https://github.com/libguestfs/libguestfs
cd libguestfs
git submodule update --init
autoreconf -fiv
./configure CFLAGS="-fPIC -g -O2" --enable-werror
make -j
cd ..
- name: Compile the code
run: |
git config --global --add safe.directory $PWD
git submodule update --init
autoreconf -fiv
./libguestfs/run ./configure CFLAGS="-fPIC -g -O2" --enable-werror
./libguestfs/run make -j
# feb2026: tests mostly run but random bits fail with
# part_to_partnum_stub: /dev/sda2: No such file or directory
# Possibly this is systemd udev issue which is fixed in v260.
# Let's try enabling again when fedora-44 is out
# Some discussion: https://github.com/libguestfs/virt-v2v/pull/135
#
# - name: Run the full tests
# run: |
# ./libguestfs/run libguestfs-test-tool
#
# # Busted on root:
# # virt-v2v: changeuid: test-o-ovirt.d/12345678-1234-1234-1234-123456789abc/x8gdeog2: Sys_error("test-o-ovirt.d/12345678-1234-1234-1234-123456789abc/x8gdeog2: Permission denied")
# export SKIP_TEST_O_OVIRT_SH=1
#
# if ! ./libguestfs/run make check; then
# find -name test-suite.log -exec cat {} \;
# exit 1
# fi
================================================
FILE: .gitignore
================================================
*~
*.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
.gdb_history
.libs
Makefile
Makefile.in
/aclocal.m4
/autom4te.cache/
/build-aux/
/compile
/config.cache
/config.guess
/config.h
/config.h.in
/config.log
/config.sh
/config.status
/config.sub
/configure
/convert/.depend
/depcomp
/docs/stamp-virt-v2v*.pod
/docs/virt-v2v.1
/docs/virt-v2v-hacking.1
/docs/virt-v2v-input-vmware.1
/docs/virt-v2v-input-xen.1
/docs/virt-v2v-output-local.1
/docs/virt-v2v-output-openstack.1
/docs/virt-v2v-output-ovirt.1
/docs/virt-v2v-release-notes-1.42.1
/docs/virt-v2v-release-notes-2.*.1
/docs/virt-v2v-support.1
/.gitattributes
/.git-module-status
/in-place/.depend
/in-place/stamp-virt-v2v-in-place.pod
/in-place/virt-v2v-in-place
/in-place/virt-v2v-in-place.1
/input/.depend
/inspector/.depend
/inspector/stamp-virt-v2v-inspector.pod
/inspector/virt-v2v-inspector
/inspector/virt-v2v-inspector.1
/installcheck.sh
/install-sh
/libtool
/lib/.depend
/lib/config.ml
/local*
/ltmain.sh
/m4/libtool.m4
/m4/lt~obsolete.m4
/m4/ltoptions.m4
/m4/ltsugar.m4
/m4/ltversion.m4
/maint.mk
/missing
/ocaml-dep.sh
/ocaml-link.sh
/open/.depend
/open/stamp-virt-v2v-open.pod
/open/virt-v2v-open
/open/virt-v2v-open.1
/output/.depend
/output/output_ovirt_upload_*_source.ml
/output/var_expander_tests
/po-docs/*/*.1
/po-docs/*/*.3
/po-docs/*/*.5
/po-docs/*/*.8
/po-docs/*/*.pod
/podwrapper.1
/podwrapper.pl
/po/*.gmo
/run
/stamp-h1
/test-data/fake-virtio-win/cd
/test-data/fake-virtio-win/drivers
/test-data/fake-virtio-win/fake-virtio-win.iso
/test-data/phony-guests/archlinux.img
/test-data/phony-guests/blank-*.img
/test-data/phony-guests/coreos.img
/test-data/phony-guests/debian.img
/test-data/phony-guests/fedora.img
/test-data/phony-guests/fedora-btrfs.img
/test-data/phony-guests/fedora-luks-on-lvm.img
/test-data/phony-guests/fedora-lvm-on-luks.img
/test-data/phony-guests/fedora-md1.img
/test-data/phony-guests/fedora-md2.img
/test-data/phony-guests/fedora-static-bin
/test-data/phony-guests/fedora.db
/test-data/phony-guests/guests.xml
/test-data/phony-guests/guests-all-good.xml
/test-data/phony-guests/stamp-fedora-md.img
/test-data/phony-guests/ubuntu.img
/test-data/phony-guests/win*.img
/test-data/phony-guests/*.reg.bin
/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-phony-win*.sh
/tests/test-print-source.xml
/tests/test-rhbz1232192.xml
/tests/test-sound.xml
/tests/windows.vmdk
/v2v/.depend
/v2v/real-*.d/
/v2v/real-*.img
/v2v/real-*.xml
/v2v/v2v_unit_tests
/v2v/virt-v2v
/virt-v2v-*.tar.gz
/virt-v2v-*.tar.gz.sig
/website/*.html
/website/README.txt
/website/TODO.txt
================================================
FILE: .gitmodules
================================================
[submodule "common"]
path = common
url = https://github.com/libguestfs/libguestfs-common
================================================
FILE: COPYING
================================================
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
================================================
FILE: Makefile.am
================================================
# libguestfs
# Copyright (C) 2009-2025 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)/common-rules.mk
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = common/mlstdutils
# Files and other test data used by the tests. Must be before any
# tests run, except tests/qemu.
SUBDIRS += test-data
SUBDIRS += gnulib/lib
SUBDIRS += common/qemuopts
SUBDIRS += common/utils
SUBDIRS += common/mlutils
SUBDIRS += common/mlpcre
SUBDIRS += common/options
SUBDIRS += common/mlgettext
SUBDIRS += common/mlxml
SUBDIRS += common/mltools
SUBDIRS += common/mlcustomize
SUBDIRS += common/mldrivers
SUBDIRS += lib
SUBDIRS += input
SUBDIRS += output
SUBDIRS += convert
SUBDIRS += v2v
SUBDIRS += inspector
SUBDIRS += in-place
SUBDIRS += open
SUBDIRS += tests
# bash-completion
SUBDIRS += bash
# Documentation
SUBDIRS += docs
# After all source files were used we can generate the translation strings
SUBDIRS += po
# po-docs must come after tools, inspector.
if HAVE_PO4A
SUBDIRS += po-docs
endif
EXTRA_DIST = \
.github/workflows/main.yml \
.gitignore \
bugs-in-changelog.sh \
check-mli.sh \
common/.gitignore \
common/README \
common/update-submodule.sh \
contrib/remove-guestor.reg \
COPYING \
ocaml-link.sh \
podcheck.pl \
scripts/git.orderfile \
tmp/.gitignore \
valgrind-suppressions \
website/bugs.png \
website/communicate.png \
website/documentation.png \
website/download.png \
website/draft.png \
website/draft.svg \
website/easytoread.css \
website/feed.css \
website/fish-5yrs.svg \
website/fish.png \
website/git.png \
website/index.css \
website/index.html.in \
website/pod.css \
website/standard.css \
$(NULL)
# When doing 'make dist' update a few files automatically.
#
# po/POTFILES - files with ordinary extensions, but not OCaml files
# po/POTFILES-ml - OCaml files, which need a special tool to translate
# po-docs/virt-v2v-docs.pot
# - combined list of strings from documentation
dist-hook: po/POTFILES po/POTFILES-ml
rm -f po-docs/virt-v2v-docs.pot
$(MAKE) -C po-docs virt-v2v-docs.pot
# For more information about translations, see po/Makefile.am.
po/POTFILES: configure.ac
rm -f $@ $@-t
cd $(srcdir); \
find $(DIST_SUBDIRS) -name '*.c' | \
grep -v -E '^(po-docs|tests|test-data)/' | \
grep -v -E '/(dummy\.c)$$' | \
grep -v -E '.*-(tests)\.c$$' | \
LC_ALL=C sort -u > $@-t
mv $@-t $@
po/POTFILES-ml: configure.ac
rm -f $@ $@-t
cd $(srcdir); \
find common/ml* lib in-place input inspector open output v2v \
-name '*.ml' | \
grep -v '^common/mlprogress/' | \
grep -v '^common/mlvisit/' | \
grep -v '^lib/config.ml$$' | \
grep -v -E '.*_tests\.ml$$' | \
LC_ALL=C sort > $@-t
mv $@-t $@
# NB. podwrapper is an internal tool, so the man page mustn't be installed.
# It should be noinst_MANS but that doesn't work.
noinst_DATA = podwrapper.1
podwrapper.1: podwrapper.pl
$(AM_V_GEN) $(PODWRAPPER) \
--section 1 \
--man $@-t \
--license GPLv2+ \
--warning safe \
$<
$(AM_V_at) mv $@-t $@
# Make clean.
CLEANFILES += \
pod2htm?.tmp \
tmp/disk* \
tmp/run-* \
tmp/valgrind-*.log \
$(NULL)
clean-local:
-rm -rf tmp/libguestfs??????
-rm -rf tmp/guestfs.*
-rm -rf tmp/.guestfs-*
-rm -rf tmp/null.*
-find tmp -type s -delete
-find . -name '*~' -delete
check-valgrind: build-test-guests
@errors=0; \
for f in `grep -l '^$@:' $(SUBDIRS:%=%/Makefile.am)`; do \
echo $(MAKE) -C `dirname $$f` $@; \
$(MAKE) -C `dirname $$f` $@ || (( errors++ )); \
done; \
exit $$(( $$errors ? 1 : 0 ))
check-slow: build-test-guests
@errors=0; \
for f in `grep -l '^$@:' $(SUBDIRS:%=%/Makefile.am)`; do \
echo $(MAKE) -C `dirname $$f` $@; \
$(MAKE) -C `dirname $$f` $@ || (( errors++ )); \
done; \
exit $$(( $$errors ? 1 : 0 ))
build-test-guests:
$(MAKE) -C test-data/phony-guests check
# Some tests which run at the top level.
TESTS = check-mli.sh
# Commit everything in current directory to HEAD, and set commit
# message to current version (only for maintainer).
maintainer-commit:
git commit -a -m "Version $(VERSION)."
# Tag HEAD with current version (only for maintainer).
maintainer-tag:
git tag -a "v$(VERSION)" -m "Version $(VERSION) ($(BRANCH_TYPE))" -f
# Maintainer only: check no files are missing from EXTRA_DIST rules,
# and that all generated files have been included in the tarball.
# (Note you must have done 'make dist')
maintainer-check-extra-dist:
zcat $(PACKAGE_NAME)-$(VERSION).tar.gz | tar tf - | sort | \
sed 's,^$(PACKAGE_NAME)-$(VERSION)/,,' > tmp/tarfiles
( git ls-files ; \
cd common; git ls-files | sed 's,^,common/,' ) | \
grep -v '^common$$' | \
grep -v '^common/edit/' | \
grep -v '^common/errnostring/' | \
grep -v '^common/mlprogress/' | \
grep -v '^common/mlvisit/' | \
grep -v '^common/parallel/' | \
grep -v '^common/progress/' | \
grep -v '^common/protocol/' | \
grep -v '^common/structs/' | \
grep -v '^common/visit/' | \
grep -v '^common/windows/' | \
grep -v '^intltool-.*\.in' | \
grep -v '^\.gitmodules' | \
sort > tmp/gitfiles
comm -13 tmp/tarfiles tmp/gitfiles > tmp/comm-out
@echo Checking for differences between EXTRA_DIST and git ...
cat tmp/comm-out
[ ! -s tmp/comm-out ]
rm tmp/tarfiles tmp/gitfiles tmp/comm-out
@echo PASS: EXTRA_DIST tests
================================================
FILE: README
================================================
Virt-v2v is a program that 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 or several
other targets. It can modify the guest to make it bootable on KVM and
install virtio drivers so it will run quickly.
There is also a companion front-end called virt-p2v
(https://github.com/libguestfs/virt-p2v) which comes as an ISO, CD or
PXE image that can be booted on physical machines to virtualize those
machines (physical to virtual, or p2v).
Virt-v2v and virt-p2v have been in continuous development since 2007.
For more information about virt-v2v and virt-p2v please read the
respective manual pages. For virt-v2v, see the docs/ subdirectory in
the source tree.
BUILDING FROM SOURCE
======================================================================
To build from git:
git submodule update --init
autoreconf -i
./configure
make
To build from tarball:
./configure
make
You can run virt-v2v without installing it:
./run virt-v2v ...
To run the tests:
make check
REQUIREMENTS
======================================================================
* libguestfs (https://libguestfs.org)
* OCaml bindings for libguestfs
* OCaml bindings for libvirt (https://gitlab.com/libvirt/libvirt-ocaml)
* libnbd >= 1.14 (https://gitlab.com/nbdkit/libnbd)
* The 'nbdinfo' and 'nbdcopy' programs from libnbd.
* OCaml bindings for libnbd
* nbdkit >= 1.45.11 (https://gitlab.com/nbdkit/nbdkit)
* These nbdkit plugins and filters:
+ nbdkit-curl-plugin
+ nbdkit-file-plugin
+ nbdkit-nbd-plugin
+ nbdkit-null-plugin
+ nbdkit-python-plugin
+ nbdkit-ssh-plugin
+ nbdkit-vddk-plugin
+ nbdkit-blocksize-filter
+ nbdkit-count-filter
+ nbdkit-cow-filter
+ nbdkit-multi-conn-filter
+ nbdkit-rate-filter
+ nbdkit-retry-filter
* qemu-nbd
* qemu-img
Optional, for enhancements to the basic program:
* OCaml gettext
* virtio-win (Windows virtio device drivers)
Optional, used by the test suite:
* guestfish
================================================
FILE: TODO
================================================
To-do list for virt-v2v
======================================================================
We open the input NBD endpoint up to 5 times per disk during a
conversion (especially if --verbose mode is used):
* Once for conversion
* nbdinfo opens the connection twice (because we're using --content)
* The output side opens the input connection just to get the virtual
size of the disk, so it knows how large to create the output disk.
(Could be avoided if conversion kept this information, but that's a
layering violation.)
* once for nbdcopy
This has quite a lot of overhead for some inputs. For VDDK, opening a
connection is very slow. In one conversion of a guest with 5 disks I
measured 10% of the total run time of virt-v2v being spent simply
opening VDDK connections (5 x 5 = 25 times in all).
--
In virt-v2v -o openstack Use the metadata service to find the -oo
server-id setting. It would no longer need to be specified on the
command line. Note there are two variations of metadata service in
OpenStack, either the config disk or link-local network address. We
would need to support both, or the possibility that there is no
metadata service.
================================================
FILE: bash/Makefile.am
================================================
# libguestfs
# Copyright (C) 2013-2025 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
scripts = \
virt-v2v
EXTRA_DIST = \
README \
$(scripts) \
$(TESTS) \
$(NULL)
if HAVE_BASH_COMPLETION
# Bash completion script.
bashcompletiondir = $(BASH_COMPLETIONS_DIR)
#bashcompletion_DATA = $(scripts)
all-local: $(scripts)
$(AM_V_at)test $(srcdir) = $(builddir) || { cd $(srcdir) && cp $(scripts) $(abs_builddir)/; }
install-data-local:
$(mkdir_p) $(DESTDIR)$(bashcompletiondir)
cp -P $(scripts) $(DESTDIR)$(bashcompletiondir)
clean-local:
-test $(srcdir) != $(builddir) && rm -f $(scripts)
endif
# Tests.
TESTS_ENVIRONMENT = \
scripts="$(scripts)" \
commands="$(scripts)" \
$(top_builddir)/run --test
TESTS = \
test-complete-in-script.sh
================================================
FILE: bash/README
================================================
This directory contains the scripts for tab-completing commands in
bash. Note these new-style demand-loaded scripts require
'bash-completion' >= 1.99.
Tip: To test the bash completions without having to install them,
simply start a new shell and 'source ./virt-foo'.
================================================
FILE: bash/test-complete-in-script.sh
================================================
#!/bin/bash -
# libguestfs bash completion test script
# 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.
# Test that the correct 'complete' command is included in the script.
# Mainly prevents symlinking errors and some omissions.
source ../tests/functions.sh
set -e
set -x
skip_if_skipped
if [ -z "$commands" ]; then
echo "$0: \$commands is not defined. Use 'make check' to run this test."
exit 1
fi
for cmd in $commands; do
if [ ! -f $cmd ]; then
echo "$0: script '$cmd' is missing"
exit 1
fi
if ! grep "^complete.*$cmd\$" $cmd; then
echo "$0: script '$cmd' does not have"
echo "a 'complete' rule for '$cmd'"
exit 1
fi
done
================================================
FILE: bash/virt-v2v
================================================
# virt-v2v bash completion script -*- shell-script -*-
# Copyright (C) 2014 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
_virt_v2v ()
{
local cur prev words cword split
local shortopts longopts items
_init_completion -s || return
case "$prev" in
-i)
items="$(virt-v2v --machine-readable | awk -F':' '/input:/ {print $2;}')"
COMPREPLY=( $( compgen -W "$items" -- "$cur") )
return ;;
-o)
items="$(virt-v2v --machine-readable | awk -F':' '/output:/ {print $2;}')"
COMPREPLY=( $( compgen -W "$items" -- "$cur") )
return ;;
-oa)
COMPREPLY=( $( compgen -W "sparse preallocated" -- "$cur") )
return ;;
esac
case "$cur" in
--*)
# --options
longopts="$(virt-v2v --long-options)"
COMPREPLY=( $(compgen -W "$longopts" -- "$cur") )
return ;;
-*)
# -o and --options
shortopts="$(virt-v2v --short-options)"
longopts="$(virt-v2v --long-options)"
COMPREPLY=( $(compgen -W "$shortopts $longopts" -- "$cur") )
return ;;
*)
COMPREPLY=( $(compgen "$cur") )
return ;;
esac
} &&
complete -o default -F _virt_v2v virt-v2v
================================================
FILE: bugs-in-changelog.sh
================================================
#!/bin/bash -
# bugs-in-changelog.sh
# Copyright (C) 2009-2025 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.
# Used when preparing the release notes. This script looks at the
# bugs noted in the git changelog since the last stable release (or
# any release). To use it, the only parameter should be the git
# commit range, eg:
#
# ./bugs-in-changelog.sh "1.0.89.."
if [ -z "$1" ]; then
echo "$0 git-commit-range"
exit 1
fi
# Comma-separated list of Bugzilla IDs.
bugids=$(
git log "$1" |
grep -Eio 'RHBZ#[0-9]+|https?://bugzilla.redhat.com/[a-z\.\?/_=]*[0-9]+' |
sed 's/^[^0-9]*//' |
sort -u |
tr '\n' ',' |
sed 's/,$//'
)
#echo bugids "$bugids"
# Filter out any bugs which may still be in NEW or ASSIGNED.
#
# Ensure user is logged in, otherwise bugzilla will silently truncate
# the number of responses. To log in, see "API KEYS" in bugzilla(1).
bugzilla \
--ensure-logged-in \
query \
-b "$bugids" \
-s MODIFIED,POST,ON_QA,PASSES_QA,VERIFIED,RELEASE_PENDING,CLOSED \
--component virt-v2v \
--outputformat='%{bug_id} %{short_desc}' |
sort -n -r |
perl -pe '
s{([0-9]+)\s+(.*)}{
sprintf ("=item L<https://bugzilla.redhat.com/%s>\n\n%s\n",
$1, $2)
}xe'
# We can't fetch Jira subjects or github issues, but we can at least
# list them.
jiraids=$(
git log "$1" |
grep -Eio '(RHEL|MTV)-[0-9]{3,}' |
sort -u
)
for id in $jiraids ; do
echo "=item L<https://issues.redhat.com/browse/$id>"
echo
echo "XXX"
echo
done
issues=$(
git log "$1" |
grep -Eio 'https?://github\.com/libguestfs/virt-v2v/issues/[0-9]+' |
sort -u
)
for issue in $issues ; do
echo "=item L<$issue>"
echo
echo "XXX"
echo
done
================================================
FILE: check-mli.sh
================================================
#!/bin/bash -
# Check every .ml file has a corresponding .mli file.
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
# OCaml itself doesn't require it, but getting Makefile dependencies
# correct is impossible when some .ml files don't have a corresponding
# .mli file.
exitcode=0
for f in $(
find -name '*.ml' |
grep -v builder/templates |
grep -v contrib/ |
grep -v ocaml/examples/ |
grep -v ocaml/t/ |
grep -v 'tests/automake2junit.ml$' |
grep -v 'bindtests.ml$' |
grep -v '_tests.ml$' |
sort
); do
if [ ! -f "${f}i" ]; then
echo $f: missing ${f}i
exitcode=1
fi
done
exit $exitcode
================================================
FILE: common-rules.mk
================================================
# 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'
-include $(top_builddir)/localenv
# Convenient way to terminate lists in Makefiles, so that we avoid
# problems with dangling backslashes.
NULL =
# 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
CLEANFILES = *~ *.bak
# Patch original and reject files.
CLEANFILES += *.orig *.rej
# OCaml intermediate and generated files.
CLEANFILES += *.cmi *.cmo *.cma *.cmx *.cmxa dll*.so *.a
# OCaml -annot files (used for displaying types in some IDEs).
CLEANFILES += *.annot
# Manual pages - these are all generated from *.pod, so the
# pages themselves should all be removed by 'make clean'.
CLEANFILES += *.1 *.3 *.5 *.8
# Stamp files used when generating man pages.
CLEANFILES += stamp-*.pod
# Bindtests temporary files used in many language bindings.
CLEANFILES += bindtests.tmp
# Files that should be universally removed by 'make distclean'.
DISTCLEANFILES = .depend stamp-*
# Special suffixes used by OCaml.
SUFFIXES = .cmo .cmi .cmx .ml .mli .mll .mly
# Special suffixes used by PO files.
SUFFIXES += .po .gmo
================================================
FILE: config.sh.in
================================================
#!/bin/bash -
# (C) Copyright 2019 Red Hat Inc.
# @configure_input@
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
# This shell script contains the results of some configure checks,
# mostly used in other shell scripts.
export PYCODESTYLE="@PYCODESTYLE@"
================================================
FILE: configure.ac
================================================
# virt-v2v
# Copyright (C) 2009-2026 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# The major, minor, and release fields MUST be numbers. Packagers can
# add extra information using --with-extra="..." which may be any
# freeform string.
m4_define([v2v_major], [2])
m4_define([v2v_minor], [11])
m4_define([v2v_release], [8])
AC_INIT([virt-v2v],v2v_major.v2v_minor.v2v_release)
# Headings within the configure script output.
term_bold=""
term_red=""
term_green=""
term_restore=""
AS_IF([test -t 1], [
AS_CASE(["$TERM"],
[xterm*|vt220*], [
term_bold="$(printf "\e@<:@1m")"
term_red="$(printf "\e@<:@22;31m")"
term_green="$(printf "\e@<:@22;32m")"
term_restore="$(printf "\e@<:@0m")"
])
])
m4_define([HEADING],
[AS_ECHO
AS_ECHO(["${term_bold}$1${term_restore}"])])
HEADING([Checking for C compiler and basic build environment])
m4_include([m4/guestfs-c.m4])
AC_CONFIG_AUX_DIR([build-aux])
AC_USE_SYSTEM_EXTENSIONS
dnl Initialize automake.
AM_INIT_AUTOMAKE(foreign subdir-objects tar-pax) dnl NB: Do not [quote] this parameter.
m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])])
AM_SILENT_RULES([yes]) # make --enable-silent-rules the default.
AC_CONFIG_MACRO_DIR([m4])
dnl Initialize libtool.
LT_INIT
HEADING([Checking for version and optional features])
dnl Stable or development version?
BRANCH_NUMBER=v2v_major.v2v_minor
AC_SUBST([BRANCH_NUMBER])
AC_MSG_CHECKING([if $BRANCH_NUMBER is a stable or development branch of virt-v2v])
AS_IF([test "$((v2v_minor % 2))" -eq 0 ],[
BRANCH_TYPE=stable
AC_MSG_RESULT([$BRANCH_TYPE])
],[
BRANCH_TYPE=development
AC_MSG_RESULT([$BRANCH_TYPE])
])
AC_SUBST([BRANCH_TYPE])
dnl Extra string, a freeform string defined by packagers.
AC_ARG_WITH([extra],
[AS_HELP_STRING([--with-extra],
[extra version string (for use by packagers)])],
[v2v_extra="$withval"],
[v2v_extra=]
)
AC_MSG_NOTICE([virt-v2v version v2v_major.v2v_minor.v2v_release$v2v_extra])
dnl Split up the version string.
AC_DEFINE([PACKAGE_VERSION_MAJOR],[v2v_major],[Major version number.])
AC_DEFINE([PACKAGE_VERSION_MINOR],[v2v_minor],[Minor version number.])
AC_DEFINE([PACKAGE_VERSION_RELEASE],[v2v_release],[Release number.])
AC_DEFINE_UNQUOTED([PACKAGE_VERSION_EXTRA],["$v2v_extra"],[Extra version string.])
PACKAGE_VERSION_FULL="v2v_major.v2v_minor.v2v_release${v2v_extra}"
AC_DEFINE_UNQUOTED([PACKAGE_VERSION_FULL],["$PACKAGE_VERSION_FULL"],[Full version string.])
AC_SUBST([PACKAGE_VERSION_FULL])
AC_ARG_ENABLE([block-driver],
[AS_HELP_STRING([--disable-block-driver],
[disable --block-driver feature])],
[case $enableval in
yes|no) ;;
*) AC_MSG_ERROR([bad value $enableval for --enable-block-driver option]) ;;
esac
ENABLE_BLOCK_DRIVER=$enableval],
[ENABLE_BLOCK_DRIVER=yes]
)
AC_SUBST([ENABLE_BLOCK_DRIVER])
AM_CONDITIONAL([ENABLE_BLOCK_DRIVER], [test "x$ENABLE_BLOCK_DRIVER" = "xyes"])
dnl Allow some input modes to be disabled.
AC_ARG_ENABLE([xen],
[AS_HELP_STRING([--disable-xen],
[disable Xen input mode])],
[case $enableval in
yes|no) ;;
*) AC_MSG_ERROR([bad value $enableval for --enable-xen option]) ;;
esac
ENABLE_XEN=$enableval],
[ENABLE_XEN=yes]
)
AC_SUBST([ENABLE_XEN])
AM_CONDITIONAL([ENABLE_XEN], [test "x$ENABLE_XEN" = "xyes"])
dnl Allow some output modes to be disabled.
AC_ARG_ENABLE([glance],
[AS_HELP_STRING([--disable-glance],
[disable -o glance output mode])],
[case $enableval in
yes|no) ;;
*) AC_MSG_ERROR([bad value $enableval for --enable-glance option]) ;;
esac
ENABLE_GLANCE=$enableval],
[ENABLE_GLANCE=yes]
)
AC_SUBST([ENABLE_GLANCE])
AM_CONDITIONAL([ENABLE_GLANCE], [test "x$ENABLE_GLANCE" = "xyes"])
AC_ARG_ENABLE([ovirt],
[AS_HELP_STRING([--disable-ovirt],
[disable all oVirt output modes])],
[case $enableval in
yes|no) ;;
*) AC_MSG_ERROR([bad value $enableval for --enable-ovirt option]) ;;
esac
ENABLE_OVIRT=$enableval],
[ENABLE_OVIRT=yes]
)
AC_SUBST([ENABLE_OVIRT])
AM_CONDITIONAL([ENABLE_OVIRT], [test "x$ENABLE_OVIRT" = "xyes"])
dnl Check for external programs required to either build or run
dnl virt-v2v.
HEADING([Checking for external programs])
m4_include([m4/guestfs-progs.m4])
dnl Any C libraries required by virt-v2v.
HEADING([Checking for libraries used by virt-v2v])
m4_include([m4/guestfs-libraries.m4])
dnl OCaml.
HEADING([Checking for OCaml])
m4_include([m4/guestfs-ocaml.m4])
dnl Perl, used for running mllibvirt generator, and man pages.
HEADING([Checking for Perl])
m4_include([m4/guestfs-perl.m4])
dnl Bash completion.
HEADING([Checking for bash completion])
m4_include([m4/guestfs-bash-completion.m4])
dnl This are required to get common/*/Makefile.am files to work. We
dnl should further decouple these in future XXX
AM_CONDITIONAL([HAVE_PYTHON],[false]) dnl Disables a test
dnl Produce output files.
HEADING([Generating output files])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([installcheck.sh],
[chmod +x,-w installcheck.sh])
AC_CONFIG_FILES([ocaml-dep.sh],
[chmod +x,-w ocaml-dep.sh])
AC_CONFIG_FILES([ocaml-link.sh],
[chmod +x,-w ocaml-link.sh])
AC_CONFIG_FILES([podwrapper.pl],
[chmod +x,-w podwrapper.pl])
AC_CONFIG_FILES([run],
[chmod +x,-w run])
dnl NB: Remove common/mlstdutils/guestfs_config.ml in future XXX
AC_CONFIG_FILES([Makefile
bash/Makefile
common/options/Makefile
common/mlcustomize/Makefile
common/mldrivers/Makefile
common/mlgettext/Makefile
common/mlpcre/Makefile
common/mlstdutils/Makefile
common/mlstdutils/guestfs_config.ml
common/mltools/Makefile
common/mlutils/Makefile
common/mlxml/Makefile
common/qemuopts/Makefile
common/utils/Makefile
config.sh
convert/Makefile
docs/Makefile
gnulib/lib/Makefile
in-place/Makefile
input/Makefile
inspector/Makefile
lib/Makefile
lib/config.ml
open/Makefile
output/Makefile
po-docs/Makefile
po-docs/ja/Makefile
po-docs/uk/Makefile
po/Makefile
test-data/Makefile
test-data/binaries/Makefile
test-data/fake-virtio-win/Makefile
test-data/fake-virt-tools/Makefile
test-data/phony-guests/Makefile
test-data/phony-guests/guests.xml
tests/functions.sh
tests/Makefile
tests/test-cdrom.xml
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
v2v/Makefile])
AC_OUTPUT
dnl Produce summary.
echo
echo
echo "------------------------------------------------------------"
HEADING([Thank you for downloading $PACKAGE_STRING])
echo
echo "This is how we have configured the optional components for you today:"
echo
print ()
{
printf ' %.40s %s\n' \
"$1 ........................................" "$2"
}
feature ()
{
feat="$1"
shift
if "$@"; then
printf "$term_green"
print "$feat" "yes"
else
printf "$term_red"
print "$feat" "no"
fi
printf "$term_restore"
}
feature "OCaml gettext (for translations)" \
test "x$HAVE_OCAML_PKG_GETTEXT_TRUE" = "x"
feature "--block-driver feature" test "x$ENABLE_BLOCK_DRIVER" = "xyes"
feature "Xen input mode" test "x$ENABLE_XEN" = "xyes"
feature "-o glance output mode" test "x$ENABLE_GLANCE" = "xyes"
feature "oVirt output modes" test "x$ENABLE_OVIRT" = "xyes"
echo
echo "Please report bugs back to the mailing list:"
echo "https://lists.libguestfs.org"
echo
echo "Next you should type 'make' to build the package,"
echo "then 'make check' to run the tests."
echo "------------------------------------------------------------"
================================================
FILE: contrib/remove-guestor.reg
================================================
; Remove guestor registry entries
; See virt-v2v(1) and https://issues.redhat.com/browse/MTV-2256
[-HKEY_LOCAL_MACHINE\SYSTEM\DriverDatabase\DeviceIds\PCI\VEN_1AF4&DEV_1001&REV_00]
[-HKEY_LOCAL_MACHINE\SYSTEM\DriverDatabase\DeviceIds\PCI\VEN_1AF4&DEV_1042&REV_01]
[-HKEY_LOCAL_MACHINE\SYSTEM\DriverDatabase\DriverInfFiles\guestor.inf]
[-HKEY_LOCAL_MACHINE\SYSTEM\DriverDatabase\DriverPackages\guestor.inf_tmp]
================================================
FILE: convert/Makefile.am
================================================
# helper-v2v-convert tool
# Copyright (C) 2009-2025 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) \
$(NULL)
SOURCES_MLI = \
choose_root.mli \
convert.mli \
convert_linux.mli \
convert_types.mli \
convert_windows.mli \
mount_filesystems.mli \
target_bus_assignment.mli \
$(NULL)
SOURCES_ML = \
convert_types.ml \
convert_linux.ml \
convert_windows.ml \
choose_root.ml \
mount_filesystems.ml \
target_bus_assignment.ml \
convert.ml \
$(NULL)
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 = libmlconvert.a
if !HAVE_OCAMLOPT
MLCONVERT_CMA = mlconvert.cma
else
MLCONVERT_CMA = mlconvert.cmxa
endif
noinst_DATA = $(MLCONVERT_CMA)
libmlconvert_a_SOURCES = $(SOURCES_C)
libmlconvert_a_CPPFLAGS = \
-DCAML_NAME_SPACE \
-I. \
-I$(top_builddir) \
-I$(shell $(OCAMLC) -where) \
-I$(top_srcdir)/lib \
$(NULL)
libmlconvert_a_CFLAGS = \
-pthread \
-fPIC \
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
$(LIBGUESTFS_CFLAGS) \
$(NULL)
BOBJECTS = $(SOURCES_ML:.ml=.cmo)
XOBJECTS = $(BOBJECTS:.cmo=.cmx)
OCAMLPACKAGES = \
-package str,unix,guestfs,nbd \
-I $(top_builddir)/common/utils/.libs \
-I $(top_builddir)/gnulib/lib/.libs \
-I $(top_builddir)/lib \
-I $(top_builddir)/common/mlcustomize \
-I $(top_builddir)/common/mlstdutils \
-I $(top_builddir)/common/mlutils \
-I $(top_builddir)/common/mlgettext \
-I $(top_builddir)/common/mlpcre \
-I $(top_builddir)/common/mltools \
-I $(top_builddir)/common/mldrivers \
-I $(top_builddir)/common/mlxml \
$(NULL)
if HAVE_OCAML_PKG_GETTEXT
OCAMLPACKAGES += -package gettext-stub
endif
OCAMLCLIBS = \
-pthread \
$(LIBGUESTFS_LIBS) \
$(LIBXML2_LIBS) \
$(LIBNBD_LIBS) \
-lgnu \
$(NULL)
OCAMLFLAGS = $(OCAML_FLAGS) $(OCAML_WARN_ERROR) -ccopt '$(CFLAGS)'
if !HAVE_OCAMLOPT
OBJECTS = $(BOBJECTS)
else
OBJECTS = $(XOBJECTS)
endif
OCAMLLINKFLAGS = \
mlstdutils.$(MLARCHIVE) \
mlcutils.$(MLARCHIVE) \
mlgettext.$(MLARCHIVE) \
mlpcre.$(MLARCHIVE) \
mlxml.$(MLARCHIVE) \
mltools.$(MLARCHIVE) \
mlcustomize.$(MLARCHIVE) \
mldrivers.$(MLARCHIVE) \
mlv2vlib.$(MLARCHIVE) \
$(LINK_CUSTOM_OCAMLC_ONLY) \
$(NULL)
libmlconvert_a_DEPENDENCIES = \
$(OBJECTS)
$(MLCONVERT_CMA): $(OBJECTS) libmlconvert.a
$(AM_V_GEN) $(OCAMLFIND) mklib $(OCAMLPACKAGES) \
$(OBJECTS) $(libmlconvert_a_OBJECTS) -o mlconvert
# Dependencies.
.depend: \
$(srcdir)/*.mli \
$(srcdir)/*.ml
$(top_builddir)/ocaml-dep.sh $^
-include .depend
================================================
FILE: convert/choose_root.ml
================================================
(* virt-v2v
* Copyright (C) 2009-2025 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
open Types
let choose_root root_choice g =
let roots = g#inspect_os () in
let roots = Array.to_list roots in
match roots with
| [] ->
error (f_"inspection could not detect the source guest \
(or physical machine) operating system.\n\n\
Assuming that you are running virt-v2v/virt-p2v \
on a source which is supported (and not, for example, \
a blank disk), then this should not happen.\n\n\
No root device found in this operating system image.");
| [root] -> root (* only one root, so return it *)
| roots ->
(* If there are multiple roots, use the [--root] option supplied
* by the user to help us choose what we should do next.
*)
match root_choice with
| AskRoot ->
(* List out the roots and ask the user to choose. *)
printf "\n***\n";
printf (f_"Dual- or multi-boot operating system detected. \
Choose the root filesystem\nthat contains the main \
operating system from the list below:\n");
printf "\n";
List.iteri (
fun i root ->
let prod = g#inspect_get_product_name root in
match prod with
| "unknown" -> printf " [%d] %s\n" (i+1) root
| prod -> printf " [%d] %s (%s)\n" (i+1) root prod
) roots;
printf "\n";
let i = ref 0 in
let n = List.length roots in
while !i < 1 || !i > n do
printf (f_"Enter a number between 1 and %d, or ‘exit’: ") n;
let input = read_line () in
if input = "exit" || input = "q" || input = "quit" then
exit 1
else (
try i := int_of_string input
with
| End_of_file -> error (f_"connection closed")
| Failure _ -> ()
)
done;
List.nth roots (!i - 1)
| SingleRoot ->
error (f_"multi-boot operating systems are not supported by \
virt-v2v. Use the --root option to change how virt-v2v \
handles this.")
| FirstRoot ->
let root = List.hd roots in
info (f_"Picked %s because '--root first' was used.") root;
root
| RootDev dev ->
let root =
if List.mem dev roots then dev
else
error (f_"root device %s not found. Roots found were: %s")
dev (String.concat " " roots) in
info (f_"Picked %s because '--root %s' was used.") root dev;
root
================================================
FILE: convert/choose_root.mli
================================================
(* virt-v2v
* Copyright (C) 2009-2025 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.
*)
(** Choose which root device to convert.
This handles the [--root] command line option. *)
val choose_root : Types.root_choice -> Guestfs.guestfs -> string
(** Do libguestfs inspection on the guest.
Before calling this, the disks must be added to the handle
and the handle must be launched.
Depending on the contents of [root_choice] (the [--root] command
line option) choose which root device to convert. A single
root device is returned.
Note that this function may be interactive ([--root ask]). *)
================================================
FILE: convert/convert.ml
================================================
(* helper-v2v-convert
* Copyright (C) 2009-2025 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 Unix
open Std_utils
open Tools_utils
open Unix_utils
open Common_gettext.Gettext
open Getopt.OptionName
open Types
open Utils
module G = Guestfs
type options = {
block_driver : guestcaps_block_type;
keep_serial_console : bool;
ks : key_store;
memsize : int option;
network_map : Networks.t;
root_choice : root_choice;
smp : int option;
static_ips : static_ip list;
customize_ops : Customize_cmdline.ops;
no_fstrim : bool;
}
(* Mountpoint stats, used for free space estimation. *)
type mpstat = {
mp_dev : string; (* Filesystem device (eg. /dev/sda1) *)
mp_path : string; (* Guest mountpoint (eg. /boot) *)
mp_statvfs : Guestfs.statvfs; (* Free space stats. *)
mp_vfs : string; (* VFS type (eg. "ext4") *)
}
let rec convert input_disks options source =
let target_nics = List.map (Networks.map options.network_map) source.s_nics in
message (f_"Opening the source");
let g = open_guestfs ~identifier:"v2v" () in
let memsize =
match options.memsize with
| None ->
(* Default (if [--memsize] option is not used) is to calculate
* some multiple of the libguestfs default memory size.
*)
g#get_memsize () * 2
| Some memsize -> memsize in
g#set_memsize memsize;
let smp =
match options.smp with
| None ->
(* Default (if [--smp] option is not used) is to set the number
* according to the number of physical CPUs available (on the
* host or in the current cgroup). But limit it because each
* vCPU consumes guest RAM. This is necessary to allow parallel
* mkinitrd which greatly improves performance.
*)
min 8 (Cgroup.nr_cpus_available ())
| Some smp -> smp in
g#set_smp smp;
(* The network is used by the unconfigure_vmware () function, and the "--key
* ID:clevis" command line options (if any). *)
g#set_network true;
List.iter (
fun uri ->
(* NB: Old virt-v2v used copyonread here, when it was using a
* qcow2 file as overlay. We MUST NOT use copyonread! It
* doesn't do anything if there is no backing chain, but worse
* than that I observed a huge (33x!) slow down.
*)
let socket, export =
match uri with NBD_URI.Unix (socket, export) ->
sprintf "unix:%s" socket, Option.value export ~default:"" in
g#add_drive_opts export
~format:"raw" ~protocol:"nbd" ~server:[| socket |]
~cachemode:"unsafe" ~discard:"besteffort"
) input_disks;
g#launch ();
(* Decrypt the disks. *)
inspect_decrypt g options.ks;
(* Check (fsck) the filesystems before conversion. *)
message (f_"Checking filesystem integrity before conversion");
do_fsck ~before:true g;
(* Detect firmware. *)
message (f_"Detecting if this guest uses BIOS or UEFI to boot");
let i_firmware = Firmware.detect_firmware g in
(* Inspect the source, choose root and mount up the filesystems. *)
message (f_"Inspecting the source");
let root = Choose_root.choose_root options.root_choice g in
let inspect = Mount_filesystems.mount_filesystems g root in
(* Detect boot device. *)
message (f_"Detecting the boot device");
let target_boot_device = get_target_boot_device g inspect in
let mpstats = get_mpstats g in
check_guest_free_space inspect mpstats;
(* Choose which conversion module we will use. *)
let (module Conversion_module) =
match inspect with
| { i_type = "linux";
i_distro = ("fedora"
| "rhel" | "centos" | "circle" | "scientificlinux"
| "redhat-based" | "oraclelinux" | "rocky"
| "sles" | "suse-based" | "opensuse"
| "altlinux"
| "debian" | "ubuntu" | "linuxmint" | "kalilinux"
| "kylin" | "neokylin" | "anolis" ) } ->
(module Convert_linux.Convert_linux : Convert_types.CONVERT)
| { i_type = "windows" } ->
(module Convert_windows.Convert_windows : Convert_types.CONVERT)
| _ ->
error (f_"virt-v2v is unable to convert this guest type (%s/%s)")
inspect.i_type inspect.i_distro in
debug "picked conversion module %s" Conversion_module.name;
(* Conversion. *)
let guestcaps =
do_convert g source inspect i_firmware
options.block_driver options.keep_serial_console options.static_ips
Conversion_module.convert in
(* Run virt-customize options. *)
Customize_run.run g inspect.i_root options.customize_ops;
g#umount_all ();
(* Post-conversion steps that run with filesystems unmounted. *)
Conversion_module.post_convert g inspect;
(* Doing fstrim on all the filesystems reduces the transfer size
* because unused blocks are marked in the overlay and thus do
* not have to be copied.
*)
if not options.no_fstrim then (
message
(f_"Mapping filesystem data to avoid copying unused and blank areas");
do_fstrim g inspect
) else (
message (f_"Skipping fstrim (--no-fstrim specified)")
);
(* Check (fsck) the filesystems after conversion. *)
g#umount_all ();
message (f_"Checking filesystem integrity after conversion");
do_fsck g;
message (f_"Closing the overlay");
g#umount_all ();
g#shutdown ();
g#close ();
(* Prepare the target metadata. *)
message (f_"Assigning disks to buses");
let target_buses =
Target_bus_assignment.target_bus_assignment
source.s_disks source.s_removables guestcaps in
debug "%s" (string_of_target_buses target_buses);
let target_firmware =
get_target_firmware i_firmware guestcaps source output in
(* Create target metadata file. *)
let target_meta = { guestcaps; target_buses; target_nics;
target_firmware; target_boot_device } in
(* This is a good place to dump everything we know about the guest. *)
if verbose () then debug_info source inspect target_meta mpstats;
(* Return inspection data and target metadata. *)
inspect, target_meta
(* Collect statvfs information from the guest mountpoints. *)
and get_mpstats g =
let mpstats = List.map (
fun (dev, path) ->
let statvfs = g#statvfs path in
let vfs = g#vfs_type dev in
{ mp_dev = dev; mp_path = path; mp_statvfs = statvfs; mp_vfs = vfs }
) (g#mountpoints ()) in
mpstats
(* Conversion can fail if there is no space on the guest filesystems
* (RHBZ#1139543). To avoid this situation, check there is some
* headroom. Mainly we care about the root filesystem.
*
* Also make sure filesystems have available inodes. (RHBZ#1764569)
*)
and check_guest_free_space inspect mpstats =
message (f_"Checking for sufficient free disk space in the guest");
(* Check whether /boot has its own mount point. *)
let has_boot = List.exists (fun { mp_path } -> mp_path = "/boot") mpstats in
let is_windows = inspect.i_distro = "windows" in
let needed_megabytes_for_mp = function
(* We usually regenerate the initramfs, which has a
* typical size of 20-30MB. Hence:
*)
| "/boot" | "/" when not has_boot && not is_windows -> 50
(* Both Linux and Windows require installation of files,
* device drivers and guest agents.
* https://bugzilla.redhat.com/1949147
* https://bugzilla.redhat.com/1764569#c16
*)
| "/" -> 100
(* For everything else, just make sure there is some free space. *)
| _ -> 10
in
(* Reasonable headroom for conversion operations. *)
let needed_inodes = 100L in
List.iter (
fun { mp_path; mp_statvfs = { G.bfree; bsize; files; ffree } } ->
(* bfree = free blocks for root user *)
let free_bytes = bfree *^ bsize in
let needed_megabytes = needed_megabytes_for_mp mp_path in
let needed_bytes = Int64.of_int needed_megabytes *^ 1024L *^ 1024L in
if free_bytes < needed_bytes then (
let mb i = Int64.to_float i /. 1024. /. 1024. in
error (f_"not enough free space for conversion on filesystem ‘%s’. \
%.1f MB free < %d MB needed")
mp_path (mb free_bytes) needed_megabytes
);
(* Not all the filesystems have inode counts. *)
if files > 0L && ffree < needed_inodes then
error (f_"not enough available inodes for conversion on \
filesystem ‘%s’. %Ld inodes available < %Ld inodes needed")
mp_path ffree needed_inodes
) mpstats
(* Perform the fstrim. *)
and do_fstrim g inspect =
(* Get all filesystems. *)
let fses = g#list_filesystems () in
let fses = List.filter_map (
function (_, ("unknown"|"swap")) -> None | (dev, _) -> Some dev
) fses in
(* Trim the filesystems. *)
List.iter (
fun dev ->
g#umount_all ();
let mounted =
try g#mount_options "discard" dev "/"; true
with G.Error _ -> false in
if mounted then (
debug "info: trimming %s" dev;
try g#fstrim "/"
with G.Error msg ->
warning (f_"fstrim on guest filesystem %s failed. Usually you \
can ignore this message. To find out more read \
\"Trimming\" in virt-v2v(1).\n\n\
Original message: %s") dev msg
)
) fses
(* Perform fsck before and after conversion.
*
* If fsck returns an error then the conversion will fail. We do not
* attempt to do any repairs.
*)
and do_fsck ?(before=false) g =
let fses = g#list_filesystems () in
List.iter (function
| dev, _ when String.starts_with "btrfsvol:" dev ->
(* Ignore btrfs volumes, since we should see the btrfs device
* somewhere else in the list and checking that is sufficient.
*)
()
| dev, "btrfs" ->
(* btrfs-check would be the obvious thing, but the general
* opinion seems to be that it's broken, and you should use
* btrfs scrub instead.
*)
Fun.protect ~finally:g#umount_all (
fun () ->
g#mount_ro dev "/";
g#btrfs_scrub_full "/" ~readonly:true;
);
| dev, "ext4" ->
if before then (
(* Replay and hence repair a dirty log (RHEL-97600) *)
Fun.protect ~finally:g#umount_all (fun () -> g#mount_ro dev "/");
);
g#e2fsck ~forceno:true dev
| dev, "xfs" ->
if before then (
(* xfs_repair cannot replay the dirty log, only the kernel can,
* so we must first mount then unmount the filesystem, and then
* we can run xfs_repair. Unlike what is documented, xfs_repair
* doesn't return 2 in this case. Mount r/o is fine as that
* will still replay the log (RHEL-95365)
*)
Fun.protect ~finally:g#umount_all (fun () -> g#mount_ro dev "/");
);
(* Must specify the -n flag because we are not attempting to
* fix the filesystem here.
*)
let nomodify = true
(* xfs_repair runs out of memory in the low memory environment
* of the appliance unless we disable prefetch.
*)
and noprefetch = true in
if g#xfs_repair ~noprefetch ~nomodify dev <> 0 then
error (f_"detected errors on the XFS filesystem on %s") dev
| _, _ ->
(* Ignore other filesystem types. *)
()
) fses
(* Conversion. *)
and do_convert g source inspect i_firmware
block_driver keep_serial_console interfaces
convert =
(* Create the "Converting..." message. Complicated! *)
let () =
let what_guest =
match inspect.i_product_name, inspect.i_osinfo with
| "unknown", "unknown" -> s_"the guest"
| "unknown", osinfo -> sprintf (f_"%s guest") osinfo
| prod, "unknown" -> prod
| prod, osinfo -> sprintf "%s (%s)" prod osinfo in
message (f_"Converting %s to run on KVM") what_guest in
let guestcaps =
convert g source inspect i_firmware
block_driver keep_serial_console interfaces in
debug "%s" (string_of_guestcaps guestcaps);
(* Did we manage to install virtio drivers? *)
if not (quiet ()) then (
match guestcaps.gcaps_block_bus with
| Virtio_blk | Virtio_SCSI ->
info (f_"This guest has virtio drivers installed.")
| IDE ->
info (f_"This guest does not have virtio drivers installed.")
);
guestcaps
(* Does the guest require UEFI on the target? *)
and get_target_firmware i_firmware guestcaps source output =
message (f_"Checking if the guest needs BIOS or UEFI to boot");
let target_firmware =
match source.s_firmware with
| BIOS -> TargetBIOS
| UEFI -> TargetUEFI
| UnknownFirmware ->
match i_firmware with
| I_BIOS -> TargetBIOS
| I_UEFI _ -> TargetUEFI
in
(match target_firmware with
| TargetBIOS -> ()
| TargetUEFI -> info (f_"This guest requires UEFI on the target to boot."));
target_firmware
and get_target_boot_device g inspect =
with_return (fun {return} ->
(* We only do it for Linux, as most likely Windows never(?) boots
* from any drive other than C:. We can revisit this decision
* if someone reports a bug.
*)
if inspect.i_type <> "linux" then return None;
(* Look for "GRUB" signature in the boot sector of each disk.
* If we find it, choose that disk.
*)
let devices = g#list_devices () |> Array.to_list in
let boot_device = List.find_opt (has_grub_signature g) devices in
let boot_device = Option.map g#device_index boot_device in
if boot_device <> None then return boot_device;
(* If that fails, in sane cases, the Grub stage1/boot.img (ie. the boot
* sector) is always on the same drive as /boot. So we can just find
* out where /boot is mounted and use that.
*)
get_device_of_boot_filesystem g inspect
)
and has_grub_signature g dev =
let boot_sector = g#pread_device dev 512 0_L in
let r = String.find boot_sector "GRUB" >= 0 in
debug "has_grub_signature: \"GRUB\" signature on %s? %b" dev r;
r
and get_device_of_boot_filesystem g inspect =
try
let boot_mountpoint = List.assoc "/boot" inspect.i_mountpoints in
let boot_device = g#part_to_dev boot_mountpoint in
debug "get_device_of_boot_filesystem: found /boot filesystem on device %s"
boot_device;
let boot_device = g#device_index boot_device in
Some boot_device
with
| Not_found -> None
(* Returned by part_to_dev if the /boot mountpoint is not
* a partition name.
*)
| G.Error msg
when String.find msg "device name is not a partition" >= 0 -> None
(* Returned by device_index if the /boot device is not
* a normal drive name (eg. /dev/mdX).
*)
| G.Error msg
when String.find msg "device not found" >= 0 -> None
(* After conversion we dump as much information about the guest
* as we can in one place. Note this is only called when verbose
* is enabled.
*)
and debug_info source inspect
{ guestcaps; target_buses; target_nics;
target_firmware; target_boot_device }
mpstats =
eprintf "info:\n";
eprintf "%s\n" (string_of_source source);
eprintf "%s\n" (string_of_inspect inspect);
eprintf "%s\n" (string_of_guestcaps guestcaps);
eprintf "%s\n" (string_of_target_buses target_buses);
eprintf "target firmware: %s\n" (string_of_target_firmware target_firmware);
eprintf "target boot device: %s\n"
(match target_boot_device with None -> "" | Some i -> string_of_int i);
eprintf "target NICs:\n";
List.iter (fun nic -> eprintf "%s\n" (string_of_source_nic nic))
target_nics;
eprintf "mountpoint stats:\n";
eprintf "%20s %-16s %-16s %-16s %s\n" "" "Size" "Used" "Available" "Use%";
List.iter debug_mpstat mpstats;
flush Stdlib.stderr
(* The calculations here are similar to virt-df df/output.c *)
and debug_mpstat { mp_dev = dev; mp_path = path;
mp_statvfs = { G.bsize; G.blocks; G.bfree; G.bavail };
mp_vfs = vfs } =
let label = sprintf "%s %s (%s):" dev path vfs
and size = blocks *^ bsize
and used = (blocks -^ bfree) *^ bsize
and avail = bavail *^ bsize
and percent =
if blocks <> 0_L then
100. -. 100. *. (Int64.to_float bfree /. Int64.to_float blocks)
else
0. in
if String.length label > 20 then
eprintf "%s\n%20s " label ""
else
eprintf "%-20s " label;
eprintf "%-16Ld %-16Ld %-16Ld\n" size used avail;
eprintf "%20s %-16s %-16s %-16s %.1f%%\n"
"" (human_size size) (human_size used) (human_size avail) percent
================================================
FILE: convert/convert.mli
================================================
(* virt-v2v
* Copyright (C) 2009-2025 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 options = {
block_driver : Types.guestcaps_block_type; (** [--block-driver] option *)
keep_serial_console : bool;
ks : Tools_utils.key_store; (** [--key] option *)
memsize : int option; (** [--memsize] option *)
network_map : Networks.t; (** [-b] and [-n] options *)
root_choice : Types.root_choice; (** [--root] option *)
smp : int option; (** [--smp] option *)
static_ips : Types.static_ip list; (** [--mac :ip:] option *)
customize_ops : Customize_cmdline.ops; (** virt-customize options *)
no_fstrim : bool; (** [--no-fstrim] option *)
}
(** Command line options that get passed through to the conversion code. *)
val convert : NBD_URI.t list -> options -> Types.source ->
Types.inspect * Types.target_meta
(** The function that is called from virt-v2v to perform the actual
conversion of a guest to run on KVM.
The first parameter is the list of disks (as NBD URIs).
As a side-effect of conversion we inspect the guest, so this
function returns the inspection data, as well as the target
metadata determined by the conversion process. *)
================================================
FILE: convert/convert_linux.ml
================================================
(* virt-v2v
* Copyright (C) 2009-2025 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.
*)
(* Convert a Linux guest to run on KVM. *)
(* < mdbooth> It's all in there for a reason :/ *)
open Printf
open C_utils
open Std_utils
open Tools_utils
open Common_gettext.Gettext
open Utils
open Types
open Linux_kernels
module G = Guestfs
(* The conversion function. *)
let convert (g : G.guestfs) source inspect i_firmware _ keep_serial_console _ =
(*----------------------------------------------------------------------*)
(* Inspect the guest first. We already did some basic inspection in
* the common v2v.ml code, but that has to deal with generic guests
* (anything common to Linux and Windows). Here we do more detailed
* inspection which can make the assumption that we are dealing with
* a Linux guest using RPM or Debian packages.
*)
(* Basic inspection data available as local variables. *)
assert (inspect.i_type = "linux");
let family =
match inspect.i_distro with
| "fedora"
| "rhel" | "centos" | "circle" | "scientificlinux" | "redhat-based"
| "oraclelinux" | "rocky" | "kylin" | "neokylin" | "anolis" -> `RHEL_family
| "altlinux" -> `ALT_family
| "sles" | "suse-based" | "opensuse" -> `SUSE_family
| "debian" | "ubuntu" | "linuxmint" | "kalilinux" -> `Debian_family
| _ -> assert false in
(* map the OS family name to the qemu-guest-agent package name *)
let qga_pkg_of_family =
function
| `RHEL_family
| `ALT_family
| `SUSE_family
| `Debian_family -> Some "qemu-guest-agent"
| _ -> None
in
let qga_svc_start_cmd family distro major =
match family, distro, major with
| `RHEL_family, ( "rhel" | "centos" | "circle" | "scientificlinux" |
"redhat-based" | "oraclelinux" | "rocky" ), 6 ->
(* https://bugzilla.redhat.com/show_bug.cgi?id=2028764#c52 *)
Some "service qemu-ga start"
| `RHEL_family, _, _ ->
(* https://bugzilla.redhat.com/show_bug.cgi?id=2028764#c52 *)
Some "systemctl start qemu-guest-agent"
| `ALT_family, _, _ ->
(* https://bugzilla.redhat.com/show_bug.cgi?id=2028764#c45 *)
Some "systemctl start qemu-guest-agent"
| `SUSE_family, _, _ ->
(* https://bugzilla.redhat.com/show_bug.cgi?id=2028764#c51 *)
None
| `Debian_family, _, _ ->
(* https://bugzilla.redhat.com/show_bug.cgi?id=2028764#c42 *)
Some "service qemu-guest-agent start"
| _ ->
(* should never be called when "qga_pkg_of_family" returns None *)
assert false
in
assert (inspect.i_package_format = "rpm" || inspect.i_package_format = "deb");
(* Fail early if i_apps is empty. Certain steps such as kernel
* detection won't work without this. If the list is empty it
* likely indicates that libguestfs inspection is broken for
* this guest. See for example RHBZ#1965147.
*)
if inspect.i_apps = [] then
error (f_"inspection of the package database failed for this Linux \
guest. Rerun virt-v2v with -v -x and see earlier errors. \
This is an internal error which probably means that this guest \
is not supported by libguestfs inspection. If the guest should \
work with virt-v2v (see virt-v2v docs) then a fix will be \
required in libguestfs.");
(* We use Augeas for inspection and conversion, so initialize it early.
*)
let () =
let aug_save_backup = 1
and aug_no_load = 32 in
g#aug_init "/" (aug_save_backup + aug_no_load);
(* Exclude some lense includes which are problematic on a case-by-case
* basis. Note the double quotes are part of the incl, and the incl
* must exactly match the definition in the Augeas lens file.
* - "/etc/lvm/archive/*.vg" because of RHEL-113820
*)
let removed_incls = [ {|"/etc/lvm/archive/*.vg"|} ] in
List.iter (
fun incl ->
let augpath = sprintf "/augeas/load//incl[%s]" incl in
let n = g#aug_rm augpath in
debug "convert_linux: removed %d incl(s) matching %s" n incl;
) removed_incls;
g#aug_load ();
(* Calling debug_augeas_errors will display any //error nodes in
* debugging output if verbose (but otherwise it does nothing).
*)
debug_augeas_errors g in
(* Clean RPM database. This must be done early to avoid RHBZ#1143866. *)
Array.iter g#rm_f (g#glob_expand "/var/lib/rpm/__db.00?");
(* Detect the installed bootloader. *)
let bootloader =
Linux_bootloaders.detect_bootloader g inspect.i_root i_firmware in
Linux.augeas_reload g;
(* Detect which kernels are installed and offered by the bootloader. *)
let bootloader_kernels =
Linux_kernels.detect_kernels g inspect.i_root bootloader inspect.i_apps in
(*----------------------------------------------------------------------*)
(* Conversion step. *)
let rec do_convert () =
augeas_grub_configuration ();
unconfigure_xen ();
unconfigure_vbox ();
unconfigure_vmware ();
unconfigure_citrix ();
unconfigure_kudzu ();
unconfigure_prltools ();
install_linux_tools ();
let kernel = configure_kernel () in
if keep_serial_console then (
configure_console ();
bootloader#configure_console ();
) else (
remove_console ();
bootloader#remove_console ();
);
let block_type =
if kernel.ki_supports_virtio_blk then Virtio_blk else IDE in
let net_type =
if kernel.ki_supports_virtio_net then Virtio_net else E1000 in
configure_display_driver ();
remap_block_devices block_type;
configure_kernel_modules block_type net_type;
rebuild_initrd kernel;
let machine, virtio_1_0 =
match inspect.i_arch with
| ("i386"|"x86_64") ->
(match Libosinfo_utils.get_os_by_short_id inspect.i_osinfo with
| Some os ->
let devices = os#get_devices () in
debug "libosinfo devices for OS \"%s\":\n%s" inspect.i_osinfo
(Libosinfo_utils.string_of_osinfo_device_list devices);
((if Libosinfo_utils.os_devices_supports_q35 devices
then Q35 else I440FX),
Libosinfo_utils.os_devices_supports_vio10 devices)
| None ->
(* Pivot on the year 2007. Any Linux distro from earlier than 2007
* should use i440fx, anything 2007 or newer should use q35.
*)
(match inspect.i_distro, inspect.i_major_version with
| "fedora", _ -> Q35
| ("rhel"|"centos"|"circle"|"scientificlinux"|"redhat-based"|
"oraclelinux"|"rocky"), major ->
if major <= 4 then I440FX else Q35
| ("sles"|"suse-based"|"opensuse"), major ->
if major < 10 then I440FX else Q35
| ("debian"|"ubuntu"|"linuxmint"|"kalilinux"), major ->
if major < 4 then I440FX else Q35
(* reasonable default for all modern Linux kernels *)
| _, _ -> Q35
), true
)
| _ -> Virt, true
in
(* RHEL >= 9.0 on x86_64 requires the processor to support the "x86-64-v2"
* microarchitecture level, which the default QEMU VCPU model does not
* satisfy. Refer to RHBZ#2076013 RHBZ#2166619.
*)
let arch_min_version =
if family <> `RHEL_family || inspect.i_arch <> "x86_64" ||
inspect.i_major_version < 9
then 0 else 2 in
(* Return guest capabilities from the convert () function. *)
let guestcaps = {
gcaps_block_bus = block_type;
gcaps_net_bus = net_type;
gcaps_virtio_rng = kernel.ki_supports_virtio_rng;
gcaps_virtio_balloon = kernel.ki_supports_virtio_balloon;
gcaps_isa_pvpanic = kernel.ki_supports_isa_pvpanic;
gcaps_virtio_socket = kernel.ki_supports_virtio_socket;
gcaps_machine = machine;
gcaps_arch = Utils.kvm_arch inspect.i_arch;
gcaps_arch_min_version = arch_min_version;
gcaps_virtio_1_0 = virtio_1_0;
gcaps_rtc_utc = true; (* almost all Linux expect RTC to be UTC *)
} in
guestcaps
and augeas_grub_configuration () =
if bootloader#set_augeas_configuration () then
Linux.augeas_reload g
and unconfigure_xen () =
if family = `SUSE_family then (
(* Remove xen modules from INITRD_MODULES and DOMU_INITRD_MODULES. *)
let variables = ["INITRD_MODULES"; "DOMU_INITRD_MODULES"] in
let xen_modules = ["xennet"; "xen-vnif"; "xenblk"; "xen-vbd"] in
let modified = ref false in
List.iter (
fun var ->
List.iter (
fun xen_mod ->
let expr =
sprintf "/file/etc/sysconfig/kernel/%s/value[. = '%s']"
var xen_mod in
let entries = g#aug_match expr in
let entries = Array.to_list entries in
if entries <> [] then (
List.iter (fun e -> ignore (g#aug_rm e)) entries;
modified := true
)
) xen_modules
) variables;
if !modified then g#aug_save ()
);
and unconfigure_vbox () =
(* Uninstall VirtualBox Guest Additions. *)
let package_name = "virtualbox-guest-additions" in
let has_guest_additions =
List.exists (
fun { G.app2_name = name } -> name = package_name
) inspect.i_apps in
if has_guest_additions then
uninstall_packages_nonfatal [package_name];
(* Guest Additions might have been installed from a tarball. The
* above code won't detect this case. Look for the uninstall tool
* and try running it.
*
* Note that it's important we do this early in the conversion
* process, as this uninstallation script naively overwrites
* configuration files with versions it cached prior to
* installation.
*)
let vboxconfig = "/var/lib/VBoxGuestAdditions/config" in
if g#is_file ~followsymlinks:true vboxconfig then (
let lines = g#read_lines vboxconfig in
let lines = Array.to_list lines in
let rex = PCRE.compile "^INSTALL_DIR=(.*)$" in
let lines = List.filter_map (
fun line ->
if PCRE.matches rex line then (
let path = PCRE.sub 1 in
let path = shell_unquote path in
if String.length path >= 1 && path.[0] = '/' then (
let vboxuninstall = path ^ "/uninstall.sh" in
Some vboxuninstall
)
else None
)
else None
) lines in
let lines = List.filter (g#is_file ~followsymlinks:true) lines in
match lines with
| [] -> ()
| vboxuninstall :: _ ->
try
ignore (g#command [| vboxuninstall |]);
(* Reload Augeas to detect changes made by vbox tools uninst. *)
Linux.augeas_reload g
with
G.Error msg ->
warning (f_"VirtualBox Guest Additions were detected, but \
uninstallation failed. The error message was: %s \
(ignored)") msg
)
and unconfigure_vmware () =
(* Look for any configured VMware yum repos and disable them. *)
let repos =
g#aug_match "/files/etc/yum.repos.d/*/*[baseurl =~ \
regexp('https?://([^/]+\\.)?vmware\\.com/.*')]" in
let repos = Array.to_list repos in
List.iter (
fun repo ->
g#aug_set (repo ^ "/enabled") "0";
g#aug_save ()
) repos;
(* Uninstall VMware Tools. *)
let remove = ref [] and libraries = ref [] in
(* On Ubuntu, the ubuntu-server metapackage depends on
* open-vm-tools, and thus any attempt to remove it will cause
* dependency issues. Hence, special case this situation, and
* leave open-vm-tools installed in this case.
*)
let has_ubuntu_server =
if family = `Debian_family then
List.exists (
fun { G.app2_name = name } ->
name = "ubuntu-server"
) inspect.i_apps
else false in
List.iter (
fun { G.app2_name = name } ->
if String.starts_with "vmware-tools-libraries-" name then
List.push_front name libraries
else if String.starts_with "vmware-tools-" name then
List.push_front name remove
else if name = "VMwareTools" then
List.push_front name remove
else if String.starts_with "kmod-vmware-tools" name then
List.push_front name remove
else if String.starts_with "open-vm-tools-" name then
List.push_front name remove
else if name = "open-vm-tools" && not has_ubuntu_server then
List.push_front name remove
) inspect.i_apps;
let libraries = !libraries in
(* VMware tools includes 'libraries' packages which provide custom
* versions of core functionality. We need to install non-custom
* versions of everything provided by these packages before
* attempting to uninstall them, or we'll hit dependency
* issues.
*)
if libraries <> [] then (
(* We only support removal of libraries on systems which use yum. *)
if inspect.i_package_management = "yum" then (
List.iter (
fun library ->
let provides =
g#command_lines [| "rpm"; "-q"; "--provides"; library |] in
let provides = Array.to_list provides in
(* The packages provide themselves, filter this out. *)
let provides =
List.filter (
fun s ->
not (library = s || String.starts_with (library ^ " = ") s)
) provides in
(* If the package provides something other than itself, then
* proceed installing the replacements; in the other case,
* just mark the package for removal, as it means no other
* package can depend on something provided.
*)
if provides <> [] then (
(* Trim whitespace. *)
let provides = List.map String.trim provides in
(* Install the dependencies with yum. Use yum explicitly
* because we don't have package names and local install is
* impractical.
*)
let cmd = ["yum"; "-q"; "resolvedep"] @ provides in
let cmd = Array.of_list cmd in
let replacements = g#command_lines cmd in
let replacements = Array.to_list replacements in
let cmd = [ "yum"; "install"; "-y" ] @ replacements in
let cmd = Array.of_list cmd in
(try
ignore (g#command cmd);
List.push_front library remove
with G.Error msg ->
eprintf "%s: could not install replacement for %s. Error \
was: %s. %s was not removed.\n"
prog library msg library
);
) else (
List.push_front library remove;
);
) libraries
)
);
uninstall_packages_nonfatal !remove;
(* VMware Tools may have been installed from a tarball, so the
* above code won't remove it. Look for the uninstall tool and run
* if present.
*)
let uninstaller = "/usr/bin/vmware-uninstall-tools.pl" in
if g#is_file ~followsymlinks:true uninstaller then (
try
(* The VMware tools uninstaller will rebuild the ramdisk for
* the kernels present either at installation time, or at
* later time (when the tools are applied to newly
* installed kernels). Since we do not want to potentially
* rebuilt all the available kernels, trick the "database"
* of the VMware tools installation to not do any ramdisk
* restore. In any case, we will rebuilt the ramdisk of the
* default kernel already.
*)
let locations = "/etc/vmware-tools/locations" in
if g#is_file ~followsymlinks:true locations then (
g#write_append locations "remove_answer RESTORE_RAMDISK_CMD\n";
g#write_append locations "remove_answer RESTORE_RAMDISK_KERNELS\n";
g#write_append locations "remove_answer RESTORE_RAMDISK_ONECALL\n";
);
if family = `SUSE_family then
ignore (g#command [| "/usr/bin/env";
"rootdev=" ^ inspect.i_root;
uninstaller |])
else
ignore (g#command [| uninstaller |]);
(* Reload Augeas to detect changes made by vbox tools uninst. *)
Linux.augeas_reload g
with
G.Error msg ->
warning (f_"VMware tools was detected, but uninstallation failed. \
The error message was: %s (ignored)") msg
)
and unconfigure_citrix () =
let pkgs =
List.filter (
fun { G.app2_name = name } ->
String.starts_with "xe-guest-utilities" name
) inspect.i_apps in
let pkgs = List.map (fun { G.app2_name = name } -> name) pkgs in
if pkgs <> [] then (
uninstall_packages_nonfatal pkgs;
(* Installing these guest utilities automatically unconfigures
* ttys in /etc/inittab if the system uses it. We need to put
* them back.
*)
let rex = PCRE.compile "^([1-6]):([2-5]+):respawn:(.*)" in
let updated = ref false in
let rec loop () =
let comments = g#aug_match "/files/etc/inittab/#comment" in
let comments = Array.to_list comments in
match comments with
| [] -> ()
| commentp :: _ ->
let comment = g#aug_get commentp in
if PCRE.matches rex comment then (
let name = PCRE.sub 1
and runlevels = PCRE.sub 2
and process = PCRE.sub 3 in
if String.find process "getty" >= 0 then (
updated := true;
(* Create a new entry immediately after the comment. *)
g#aug_insert commentp name false;
g#aug_set ("/files/etc/inittab/" ^ name ^ "/runlevels") runlevels;
g#aug_set ("/files/etc/inittab/" ^ name ^ "/action") "respawn";
g#aug_set ("/files/etc/inittab/" ^ name ^ "/process") process;
(* Delete the comment node. *)
ignore (g#aug_rm commentp);
(* As the aug_rm invalidates the output of aug_match, we
* now have to restart the whole loop.
*)
loop ()
)
)
in
loop ();
if !updated then g#aug_save ();
)
and unconfigure_kudzu () =
(* Disable kudzu in the guest
* Kudzu will detect the changed network hardware at boot time and
* either:
* - require manual intervention, or
* - disable the network interface
* Neither of these behaviours is desirable.
*)
if g#is_file ~followsymlinks:true "/etc/init.d/kudzu"
&& g#is_file ~followsymlinks:true "/sbin/chkconfig" then (
ignore (g#command [| "/sbin/chkconfig"; "kudzu"; "off" |])
)
and unconfigure_prltools () =
let prltools_path = "/usr/lib/parallels-tools/install" in
if g#is_file ~followsymlinks:true prltools_path then (
try
ignore (g#command [| prltools_path; "-r" |]);
(* Reload Augeas to detect changes made by prltools uninst. *)
Linux.augeas_reload g
with
G.Error msg ->
warning (f_"Parallels tools was detected, but uninstallation \
failed. The error message was: %s (ignored)") msg
)
and install_linux_tools () =
(* It is not fatal if we fail to install the QEMU guest agent. *)
match qga_pkg_of_family family with
| None -> warning (f_"The name of the package that provides the QEMU Guest \
Agent for this guest OS is unknown. The guest agent \
will not be installed. Please consider reporting a \
bug according to the BUGS section of the virt-v2v(1) \
manual.")
| Some qga_pkg ->
let has_qemu_guest_agent =
List.exists (
fun { G.app2_name = name } ->
name = qga_pkg
) inspect.i_apps in
if not has_qemu_guest_agent then
try
let inst_cmd = Guest_packages.install_command [qga_pkg]
inspect.i_package_management in
(* Use only the portable filename character set in this. *)
let selinux_enforcing = "/root/virt-v2v-fb-selinux-enforcing"
and timeout = 30 in
let fbs =
Firstboot.add_firstboot_script g inspect.i_root
in
info (f_"The QEMU Guest Agent will be installed for this guest at \
first boot.");
(* Wait for the network to come online in the guest (best effort).
*)
fbs "wait online"
(sprintf {|#!/bin/sh
if conn=$(nmcli networking connectivity); then
tries=0
while
test $tries -lt %d &&
test full != "$conn"
do
sleep 1
tries=$((tries + 1))
conn=$(nmcli networking connectivity)
done
elif systemctl -q is-active systemd-networkd; then
/usr/lib/systemd/systemd-networkd-wait-online \
-q --timeout=%d
fi
|} timeout timeout);
(* Disable SELinux temporarily around package installation. Refer to
* <https://bugzilla.redhat.com/show_bug.cgi?id=2028764#c7> and
* <https://bugzilla.redhat.com/show_bug.cgi?id=2028764#c8>.
*)
fbs "setenforce 0"
(sprintf {|#!/bin/sh
rm -f %s
if command -v getenforce >/dev/null &&
test Enforcing = "$(getenforce)"
then
touch %s
setenforce 0
fi
|} selinux_enforcing selinux_enforcing);
fbs "install qga" inst_cmd;
fbs "setenforce restore"
(sprintf {|#!/bin/sh
if test -f %s; then
setenforce 1
rm -f %s
fi
|} selinux_enforcing selinux_enforcing);
(* On all the distro families covered by "qga_pkg_of_family" and
* "qga_svc_start_cmd", the QEMU guest agent service is always
* enabled by package installation for *subsequent* boots. Package
* installation may or may not enable the service for the current
* (i.e., first) boot, however, so try that here manually.
*)
match qga_svc_start_cmd family inspect.i_distro inspect.i_major_version
with
| None -> ()
| Some start_cmd ->
fbs "start qga"
(sprintf "#!/bin/sh\n\
%s\n" start_cmd)
with
| Guest_packages.Unknown_package_manager msg
| Guest_packages.Unimplemented_package_manager msg ->
warning (f_"The QEMU Guest Agent will not be installed. The \
install command for package ‘%s’ could not be created: \
%s.") qga_pkg msg
and add_initramfs_option_to_crypttab () =
(* For debian based distros that use update-initramfs, an initrd
* rebuilt under libguestfs likely won't populate configure
* boot time crypttab correctly. We work around it by adding
* `initramfs` option to every /etc/crypttab entry.
*)
(* Get all crypttab entries *)
let entries = g#aug_match "/files/etc/crypttab/*" in
let entries = Array.to_list entries in
let changed = ref false in
List.iter (
fun entry_path ->
(* Check if this entry already has the initramfs option *)
let opts = g#aug_match (sprintf "%s/opt" entry_path) in
let opts = Array.to_list opts in
let has_initramfs = List.exists (
fun opt_path ->
let opt_name = g#aug_get opt_path in
opt_name = "initramfs"
) opts in
if not has_initramfs then (
(* Add the initramfs option *)
let new_opt_path = sprintf "%s/opt[last()+1]" entry_path in
g#aug_set new_opt_path "initramfs";
changed := true;
let target = g#aug_get (sprintf "%s/target" entry_path) in
debug "convert_linux: added 'initramfs' option to crypttab entry '%s'" target
)
) entries;
(* Save changes if any were made *)
if !changed then (
g#aug_save ();
Linux.augeas_reload g
)
and configure_kernel () =
(* Previously this function would try to install kernels, but we
* don't do that any longer.
*)
(* Check a non-Xen kernel exists. *)
let only_xen_kernels = List.for_all (
fun { ki_is_xen_pv_only_kernel = pv_only } -> pv_only
) bootloader_kernels in
if only_xen_kernels then
error (f_"only Xen kernels are installed in this guest.\n\n\
Read the %s(1) manual, section \"Xen paravirtualized \
guests\", to see what to do.") prog;
(* Enable the best non-Xen kernel, where "best" means the one with
* the highest version, preferring non-debug kernels which support
* virtio.
*)
let best_kernel =
let compare_best_kernels k1 k2 =
let i = compare k1.ki_supports_virtio_net k2.ki_supports_virtio_net in
if i <> 0 then i
else (
let i = compare_app2_versions k1.ki_app k2.ki_app in
if i <> 0 then i
(* Favour non-debug kernels over debug kernels (RHBZ#1170073). *)
else compare k2.ki_is_debug k1.ki_is_debug
)
in
let kernels = bootloader_kernels in
let kernels =
List.filter (fun { ki_is_xen_pv_only_kernel = pv_only } -> not pv_only)
kernels in
let kernels = List.sort compare_best_kernels kernels in
let kernels = List.rev kernels (* so best is first *) in
List.hd kernels in
if verbose () then (
eprintf "info: best kernel for this guest:\n";
print_kernel_info stderr "\t" best_kernel;
flush stderr
);
if best_kernel <> List.hd bootloader_kernels then (
debug "best kernel is not the bootloader default, \
setting bootloader default ...";
bootloader#set_default_kernel best_kernel.ki_vmlinuz
);
(* Update /etc/sysconfig/kernel DEFAULTKERNEL (RHBZ#1176801). *)
if g#is_file ~followsymlinks:true "/etc/sysconfig/kernel" then (
let entries =
g#aug_match "/files/etc/sysconfig/kernel/DEFAULTKERNEL/value" in
let entries = Array.to_list entries in
if entries <> [] then (
List.iter (fun path -> g#aug_set path best_kernel.ki_name) entries;
g#aug_save ()
)
);
best_kernel
(* Even though the kernel was already installed (this version of
* virt-v2v does not install new kernels), it could have an
* initrd that does not have support virtio. Therefore rebuild
* the initrd.
*)
and rebuild_initrd kernel =
match kernel.ki_initrd with
| None -> ()
| Some initrd ->
(* Enable the basic virtio modules in the kernel.
*
* Also forcibly include the "xts" module; see RHBZ#1658126.
*
* Include the BOCHS DRM paravirt video driver; see RHBZ#2131123. This
* driver is known under two names -- "bochs-drm" and "bochs".
*)
let modules =
let modules =
(* The order of modules here is deliberately the same as the
* order specified in the postinstall script of kmod-virtio in
* RHEL3. The reason is that the probing order determines the
* major number of vdX block devices. If we change it, RHEL 3
* KVM guests won't boot.
*)
List.filter (fun m -> List.mem m kernel.ki_modules)
[ "virtio"; "virtio_ring"; "virtio_blk";
"virtio_scsi"; "virtio_net"; "virtio_pci"; "xts";
"bochs-drm"; "bochs" ] in
if modules <> [] then modules
else
(* Fallback copied from old virt-v2v. XXX Why not "ide"? *)
[ "sym53c8xx" ] in
(* Move the old initrd file out of the way. Note that dracut/mkinitrd
* will refuse to overwrite an old file so we have to do this.
*)
g#mv initrd (initrd ^ ".pre-v2v");
(* dracut and mkinitrd want what they call the "kernel version". What
* they actually mean is the last element of the module path
* (eg. /lib/modules/2.6.32-496.el6.x86_64 -> 2.6.32-496.el6.x86_64)
* which might include the arch. Get that here.
*)
let mkinitrd_kv =
let modpath = kernel.ki_modpath in
match last_part_of modpath '/' with
| Some x -> x
| None -> invalid_arg (sprintf "invalid module path: %s" modpath) in
let run_dracut_command dracut_path =
(* Dracut. *)
let args =
dracut_path ::
(if verbose () then [ "--verbose" ] else [])
@ [ "--add-drivers"; String.concat " " modules; initrd; mkinitrd_kv ]
in
ignore (g#command (Array.of_list args))
in
let run_update_initramfs_command () =
let args =
"/usr/sbin/update-initramfs" ::
(if verbose () then [ "-v" ] else [])
@ [ "-c"; "-k"; mkinitrd_kv ]
in
ignore (g#command (Array.of_list args))
in
if g#is_file ~followsymlinks:true "/sbin/dracut" then
run_dracut_command "/sbin/dracut"
else if g#is_file ~followsymlinks:true "/usr/bin/dracut" then
run_dracut_command "/usr/bin/dracut"
else if family = `SUSE_family
&& g#is_file ~followsymlinks:true "/sbin/mkinitrd" then (
ignore (
g#command [| "/usr/bin/env";
"rootdev=" ^ inspect.i_root;
"/sbin/mkinitrd";
"-m"; String.concat " " modules;
"-i"; initrd;
"-k"; kernel.ki_vmlinuz;
"-d"; inspect.i_root |]
)
)
else if family = `Debian_family then (
if not (g#is_file ~followsymlinks:true
"/usr/sbin/update-initramfs") then
error (f_"unable to rebuild initrd (%s) because update-initramfs \
was not found in the guest")
initrd;
if List.length modules > 0 then (
(* The modules to add to initrd are defined in:
* /etc/initramfs-tools/modules
* File format is same as modules(5).
*)
let path = "/files/etc/initramfs-tools/modules" in
g#aug_transform "modules" "/etc/initramfs-tools/modules";
Linux.augeas_reload g;
g#aug_set (sprintf "%s/#comment[last()+1]" path)
"The following modules were added by virt-v2v";
List.iter (
fun m -> g#aug_clear (sprintf "%s/%s" path m)
) modules;
g#aug_save ();
);
(* Add initramfs option to crypttab entries *)
add_initramfs_option_to_crypttab ();
run_update_initramfs_command ()
)
else if g#is_file ~followsymlinks:true "/usr/sbin/make-initrd" then (
ignore (
g#command [|
(* by default make-initrd running in vm add virtio and other
* needed to boot modules
*)
"/usr/sbin/make-initrd";
"-k"; kernel.ki_version;
|]
)
)
else if g#is_file ~followsymlinks:true "/sbin/mkinitrd" then (
let module_args = List.map (sprintf "--with=%s") modules in
let args =
[ "/sbin/mkinitrd" ] @ module_args @ [ initrd; mkinitrd_kv ] in
(* We explicitly modprobe ext2 here. This is required by
* mkinitrd on RHEL 3, and shouldn't hurt on other OSs. We
* don't care if this fails.
*)
(try g#modprobe "ext2" with G.Error _ -> ());
(* loop is a module in RHEL 5. Try to load it. Doesn't matter
* for other OSs if it doesn't exist, but RHEL 5 will complain:
* "All of your loopback devices are in use."
*)
(try g#modprobe "loop" with G.Error _ -> ());
(* RHEL 4 mkinitrd determines if the root filesystem is on LVM
* by checking if the device name (after following symlinks)
* starts with /dev/mapper. However, on recent kernels/udevs,
* /dev/mapper/foo is just a symlink to /dev/dm-X. This means
* that RHEL 4 mkinitrd running in the appliance fails to
* detect root on LVM. We check ourselves if root is on LVM,
* and frig RHEL 4's mkinitrd if it is by setting root_lvm=1 in
* its environment. This overrides an internal variable in
* mkinitrd, and is therefore extremely nasty and applicable
* only to a particular version of mkinitrd.
*)
let env =
if family = `RHEL_family && inspect.i_major_version = 4 then
Some "root_lvm=1"
else
None in
match env with
| None -> ignore (g#command (Array.of_list args))
| Some env ->
let cmd = sprintf "sh -c '%s %s'" env (String.concat " " args) in
ignore (g#sh cmd)
)
else (
error (f_"unable to rebuild initrd (%s) because mkinitrd or dracut \
was not found in the guest") initrd
)
(* We configure a console on ttyS0. Make sure existing console
* references use it. N.B. Note that the RHEL 6 xen guest kernel
* presents a console device called /dev/hvc0, whereas previous xen
* guest kernels presented /dev/xvc0. The regular kernel running
* under KVM also presents a virtio console device called /dev/hvc0,
* so ideally we would just leave it alone. However, RHEL 6 libvirt
* doesn't yet support this device so we can't attach to it. We
* therefore use /dev/ttyS0 for RHEL 6 anyway.
*)
and configure_console () =
(* Look for gettys using xvc0 or hvc0. RHEL 6 doesn't use inittab
* but this still works.
*)
let paths = g#aug_match "/files/etc/inittab/*/process" in
let paths = Array.to_list paths in
let rex = PCRE.compile "\\b([xh]vc0)\\b" in
List.iter (
fun path ->
let proc = g#aug_get path in
let proc' = PCRE.replace ~global:true rex "ttyS0" proc in
if proc <> proc' then g#aug_set path proc'
) paths;
let paths = g#aug_match "/files/etc/securetty/*" in
let paths = Array.to_list paths in
List.iter (
fun path ->
let tty = g#aug_get path in
if tty = "xvc0" || tty = "hvc0" then
g#aug_set path "ttyS0"
) paths;
g#aug_save ()
(* If the target doesn't support a serial console, we want to remove
* all references to it instead.
*)
and remove_console () =
(* Look for gettys using xvc0 or hvc0. RHEL 6 doesn't use inittab
* but this still works.
*)
let paths = g#aug_match "/files/etc/inittab/*/process" in
let paths = Array.to_list paths in
let rex = PCRE.compile "\\b([xh]vc0|ttyS0)\\b" in
List.iter (
fun path ->
let proc = g#aug_get path in
if PCRE.matches rex proc then
ignore (g#aug_rm (path ^ "/.."))
) paths;
let paths = g#aug_match "/files/etc/securetty/*" in
let paths = Array.to_list paths in
List.iter (
fun path ->
let tty = g#aug_get path in
if tty = "xvc0" || tty = "hvc0" then
ignore (g#aug_rm path)
) paths;
g#aug_save ()
and configure_display_driver () =
let video_driver = "modesetting" in
let updated = ref false in
let xorg_conf =
if not (g#is_file ~followsymlinks:true "/etc/X11/xorg.conf") &&
g#is_file ~followsymlinks:true "/etc/X11/XF86Config"
then (
g#aug_set "/augeas/load/Xorg/incl[last()+1]" "/etc/X11/XF86Config";
g#aug_load ();
"/etc/X11/XF86Config"
)
else
"/etc/X11/xorg.conf" in
let paths = g#aug_match ("/files" ^ xorg_conf ^ "/Device/Driver") in
Array.iter (
fun path ->
g#aug_set path video_driver;
updated := true
) paths;
(* Remove VendorName and BoardName if present. *)
let paths = g#aug_match ("/files" ^ xorg_conf ^ "/Device/VendorName") in
Array.iter (fun path -> ignore (g#aug_rm path)) paths;
let paths = g#aug_match ("/files" ^ xorg_conf ^ "/Device/BoardName") in
Array.iter (fun path -> ignore (g#aug_rm path)) paths;
g#aug_save ();
(* If we updated the X driver, check that X itself is installed,
* and warn if not. Old virt-v2v used to attempt to install X here
* but that way lies insanity and ruin.
*)
if !updated &&
not (g#is_file ~followsymlinks:true "/usr/bin/X") &&
not (g#is_file ~followsymlinks:true "/usr/bin/X11/X") then
warning (f_"The display driver was updated to ‘%s’, but X11 does not \
seem to be installed in the guest. X may not function \
correctly.") video_driver
and configure_kernel_modules block_type net_type =
(* This function modifies modules.conf (and its various aliases). *)
let augeas_modprobe query =
(* Execute g#aug_match, but against every known location of
modules.conf. *)
let paths = [
"/files/etc/conf.modules/alias"; (* modules_conf.aug *)
"/files/etc/modules.conf/alias";
"/files/etc/modprobe.conf/alias"; (* modprobe.aug *)
"/files/etc/modprobe.conf.local/alias";
"/files/etc/modprobe.d/*/alias";
] in
let paths =
List.map (
fun p ->
let p = sprintf "%s[%s]" p query in
Array.to_list (g#aug_match p)
) paths in
List.flatten paths
and discover_modpath () =
(* Find what /etc/modprobe.conf is called today. *)
if g#is_dir ~followsymlinks:true "/etc/modprobe.d" then (
(* Create a new file /etc/modprobe.d/virt-v2v-added.conf. *)
"/etc/modprobe.d/virt-v2v-added.conf"
) else (
(* List of methods, in order of preference. *)
let paths = [
"/etc/modprobe.conf.local";
"/etc/modprobe.conf";
"/etc/modules.conf";
"/etc/conf.modules"
] in
try List.find (g#is_file ~followsymlinks:true) paths
with Not_found ->
error (f_"unable to find any valid modprobe configuration file such \
as /etc/modprobe.conf");
)
in
(* Update 'alias eth0 ...'. *)
let paths = augeas_modprobe ". =~ regexp('eth[0-9]+')" in
let net_device =
match net_type with
| Virtio_net -> "virtio_net"
| E1000 -> "e1000"
| RTL8139 -> "rtl8139cp"
in
List.iter (
fun path -> g#aug_set (path ^ "/modulename") net_device
) paths;
(* Update 'alias scsi_hostadapter ...' *)
let paths = augeas_modprobe ". =~ regexp('scsi_hostadapter.*')" in
(match block_type with
| Virtio_blk | Virtio_SCSI ->
let block_module =
match block_type with
| Virtio_blk -> "virtio_blk"
| Virtio_SCSI -> "virtio_scsi"
| IDE -> assert false in
if paths <> [] then (
(* There's only 1 scsi controller in the converted guest.
* Convert only the first scsi_hostadapter entry to virtio
* and delete other scsi_hostadapter entries.
*)
let path, paths_to_delete = List.hd paths, List.tl paths in
(* Note that we delete paths in reverse order. This means we don't
* have to worry about alias indices being changed.
*)
List.iter (fun path -> ignore (g#aug_rm path))
(List.rev paths_to_delete);
g#aug_set (path ^ "/modulename") block_module
) else (
(* We have to add a scsi_hostadapter. *)
let modpath = discover_modpath () in
g#aug_set (sprintf "/files%s/alias[last()+1]" modpath)
"scsi_hostadapter";
g#aug_set (sprintf "/files%s/alias[last()]/modulename" modpath)
block_module
)
| IDE ->
(* There is no scsi controller in an IDE guest. *)
List.iter (fun path -> ignore (g#aug_rm path)) (List.rev paths)
);
(* Display a warning about any leftover Xen modules which we
* haven't converted. These are likely to cause an error when
* we run mkinitrd.
*)
let xen_modules = [ "xennet"; "xen-vnif"; "xenblk"; "xen-vbd" ] in
let query =
"modulename =~ regexp('" ^ String.concat "|" xen_modules ^ "')" in
let paths = augeas_modprobe query in
List.iter (
fun path ->
let device = g#aug_get path in
let module_ = g#aug_get (path ^ "/modulename") in
warning (f_"don’t know how to update %s which loads the %s module")
device module_;
) paths;
(* Update files. *)
g#aug_save ()
and remap_block_devices block_type =
(* This function's job is to iterate over boot configuration
* files, replacing "hda" with "vda" or whatever is appropriate.
* This is mostly applicable to old guests, since newer OSes use
* LABEL or UUID where possible.
*
* The original Convert::Linux::_remap_block_devices function was
* very complex indeed. This drops most of the complexity. In
* particular it assumes all non-removable source disks will be
* added to the target in the order they appear in the libvirt XML.
*)
let ide_block_prefix =
match family, inspect.i_major_version with
| `RHEL_family, v when v < 5 ->
(* RHEL < 5 used old ide driver *) "hd"
| `RHEL_family, 5 ->
(* RHEL 5 uses libata, but udev still uses: *) "hd"
| `SUSE_family, _ ->
(* SUSE uses libata, but still presents IDE disks as: *) "hd"
| _, _ ->
(* All modern distros use libata: *) "sd" in
let block_prefix_after_conversion =
match block_type with
| Virtio_blk -> "vd"
| Virtio_SCSI -> "sd"
| IDE -> ide_block_prefix in
let map =
List.mapi (
fun i { s_controller } ->
let device_name_before_conversion i =
match s_controller with
| None (* If we don't have a controller, guess. Assumes the
* source used IDE.
*)
| Some Source_IDE ->
ide_block_prefix ^ drive_name i
| Some (Source_virtio_SCSI | Source_SCSI | Source_SATA) ->
"sd" ^ drive_name i
| Some Source_virtio_blk -> "vd" ^ drive_name i
(* For NVMe assume no one is using namespaces. *)
| Some Source_NVME -> sprintf "nvme%dn1" i in
let source_dev = device_name_before_conversion i in
let target_dev = block_prefix_after_conversion ^ drive_name i in
source_dev, target_dev
) source.s_disks in
(* If a Xen guest has non-PV devices, Xen also simultaneously
* presents these as xvd devices. i.e. hdX and xvdX both exist and
* are the same device.
*
* This mapping is also useful for P2V conversion of Citrix
* Xenserver guests done in HVM mode. Disks are detected as sdX,
* although the guest uses xvdX natively.
*)
let map = map @
List.mapi (
fun i disk ->
"xvd" ^ drive_name i, block_prefix_after_conversion ^ drive_name i
) source.s_disks in
(* Check the first CD-ROM. If its controller is IDE, and the OS is RHEL<=5,
* then translate the CD-ROM from "/dev/hd[SLOT]" to "/dev/cdrom". See
* RHBZ#1637857 for details.
*)
let cdroms = List.filter
(fun removable -> removable.s_removable_type = CDROM)
source.s_removables in
if List.length cdroms >= 2 then
warning (f_"multiple CD-ROMs found; translation of CD-ROM references \
may be inexact");
let map = map @
(match cdroms with
| { s_removable_controller = Some Source_IDE;
s_removable_slot = Some slot } :: _
when family = `RHEL_family && inspect.i_major_version <= 5 ->
[("hd" ^ drive_name slot, "cdrom")]
| _ -> []
) in
if verbose () then (
eprintf "info: block device map:\n";
List.iter (
fun (source_dev, target_dev) ->
eprintf "\t%s\t-> %s\n" source_dev target_dev
) (List.sort (fun (a,_) (b,_) -> compare a b) map);
flush stderr
);
(* Possible Augeas paths to search for device names. *)
let paths = [
(* /etc/fstab *)
"/files/etc/fstab/*/spec";
"/files/etc/crypttab/*/device";
] in
(* Bootloader config *)
let paths = paths @ bootloader#augeas_device_patterns in
(* Which of these paths actually exist? *)
let paths =
List.flatten (List.map Array.to_list (List.map g#aug_match paths)) in
(* Map device names for each entry. *)
let rex_resume = PCRE.compile "^resume=(/dev/[-a-z\\d/_]+)(.*)$"
and rex_device_cciss = PCRE.compile "^/dev/(cciss/c\\d+d\\d+)(?:p(\\d+))?$"
and rex_device_nvme = PCRE.compile "^/dev/(nvme\\d+n1)(?:p(\\d+))?$"
and rex_device = PCRE.compile "^/dev/([a-z]+)(\\d*)?$" in
let rec replace_if_device path value =
let replace device =
try List.assoc device map
with Not_found ->
if not (String.starts_with "md" device) &&
not (String.starts_with "fd" device) &&
not (String.starts_with "sr" device) &&
not (String.starts_with "scd" device) &&
device <> "cdrom" then
warning (f_"%s references unknown device \"%s\". You may have to \
fix this entry manually after conversion.")
path device;
device
in
if PCRE.matches rex_device_cciss value ||
PCRE.matches rex_device_nvme value ||
PCRE.matches rex_device value then (
let device = PCRE.sub 1
and part = try PCRE.sub 2 with Not_found -> "" in
let adjusted_dev = "/dev/" ^ replace device ^ part in
(* On sles12sp5, the installer puts a non-stable path into
/etc/crypttab, like /dev/sda2. If we replace it with eg. /dev/vda2,
and then regenerate dracut initrd, systemd cryptab integration
doesn't happen correctly, because it all expects /dev/vda2 to
exist at initrd creation time..
We can avoid this by filling in a stable `UUID=<luks UUID>` value.
This depends on /dev/sdXX in the guest having the same /dev/sdXX
name in the appliance.
*)
if String.starts_with "/files/etc/crypttab" path &&
String.starts_with "/dev/sd" value then (
try
let uuid = g#vfs_uuid value in
"UUID=" ^ uuid
with ex ->
warning (f_"failed to translate encrypted device name %s to a UUID \
in /etc/crypttab. This may prevent the guest from booting \
after conversion. You may have to manually change the file and \
reconvert. The original error was: %s")
value (Printexc.to_string ex);
adjusted_dev
) else
adjusted_dev
)
else (* doesn't look like a known device name *)
value
in
let changed = ref false in
List.iter (
fun path ->
let value = g#aug_get path in
let new_value =
if String.find path "GRUB_CMDLINE" >= 0 then (
(* Handle grub2 resume=<dev> specially. *)
let rec loop str =
let index = String.find str "resume=" in
if index >= 0 then (
let part = String.sub str index (String.length str - index) in
if PCRE.matches rex_resume part then (
let start = String.sub str 0 (index + 7 (* "resume=" *))
and device = PCRE.sub 1
and end_ = PCRE.sub 2 in
let device = replace_if_device path device in
start ^ device ^ loop end_
)
else str
)
else str
in
loop value
)
else
replace_if_device path value in
if value <> new_value then (
g#aug_set path new_value;
changed := true
)
) paths;
if !changed then (
g#aug_save ();
(* Make sure the bootloader is up-to-date. *)
bootloader#update ();
Linux.augeas_reload g
);
(* Some linux uefi setups can't boot after conversion because of
lost uefi boot entries. The uefi boot entries are stored in uefi
NVRAM. The NVRAM content isn't a part of vm disk content and
usually can't be converted alongside the vm.
If a vm doesn't have uefi fallback path (/EFI/BOOT/BOOT<arch>.efi)
the vm is unbootable after conversion.
The following code tries to make an uefi fallback path for
a uefi linux vm.
*)
(match i_firmware with
| Firmware.I_BIOS -> ()
| I_UEFI _ ->
(* Standard uefi fallback path *)
let uefi_fallback_path = "/boot/efi/EFI/BOOT/" in
let cant_fix_uefi () =
info (f_"Can't fix UEFI bootloader. VM may not boot.")
in
match get_uefi_arch_suffix inspect.i_arch with
| None -> cant_fix_uefi ()
| Some suffix -> (
let uefi_fallback_name =
sprintf "%sBOOT%s.EFI" uefi_fallback_path suffix in
let file_exists file =
if g#exists file then
true
else (
info (f_"Can't find file: '%s' needed for UEFI fixing")
file;
false )
in
let grub_config = bootloader#get_config_file () in
let grub_path =
String.sub grub_config 0 (String.rindex grub_config '/') in
if g#exists uefi_fallback_name then
(* don't do anything if uefi fallback exists *)
()
else (
info (f_"Fixing UEFI bootloader.");
match inspect.i_distro, inspect.i_major_version with
| "centos", 6 ->
(* to make a bootable uefi centos 6 we need to
* copy grub.efi and grub.conf to UEFI fallback path
* and rename them to BOOT<arch>.efi and BOOT<arch>.conf
* correspondingly *)
let uefi_grub_name = String.concat "" [grub_path; "/grub.efi"] in
let uefi_grub_conf = String.concat "" [
String.sub uefi_fallback_name 0
(String.rindex uefi_fallback_name '.');
".conf" ] in
if file_exists uefi_grub_name && file_exists grub_config then (
g#mkdir_p uefi_fallback_path;
g#cp uefi_grub_name uefi_fallback_name;
g#cp grub_config uefi_grub_conf;
let fix_script =
sprintf
"#!/bin/bash\n\
efibootmgr -c -L \"CentOS 6\"\n\
rm -rf %s"
uefi_fallback_path in
Firstboot.add_firstboot_script
g inspect.i_root "fix uefi boot" fix_script)
else
cant_fix_uefi ()
| ("ubuntu", 14) | ("debian", 12)->
(* to make a bootable uefi ubuntu 14 we need to
* copy shim<arch>.efi to UEFI fallback path
* and rename it to BOOT<arch>.efi, also we copy
* grub.efi and grub.cfg to UEFI fallback path without renaming *)
let arch_suffix = String.lowercase_ascii suffix in
let distro = inspect.i_distro in
let shim =
String.concat "" [grub_path; "/shim"; arch_suffix; ".efi"] in
let uefi_grub_name =
String.concat "" [grub_path; "/grub"; arch_suffix; ".efi"] in
if file_exists shim && file_exists uefi_grub_name
&& file_exists grub_config then (
g#mkdir_p uefi_fallback_path;
g#cp shim uefi_fallback_name;
g#cp uefi_grub_name uefi_fallback_path;
g#cp grub_config uefi_fallback_path;
(* if the shim is at the standard path, clean up uefi fixing
* if not, then just don't clean up and leave the temp loader
* at UEFI fallback path for simplicity
*)
if String.find shim (sprintf "/boot/efi/EFI/%s/shim" distro) >= 0 then
let fix_script =
sprintf
"#!/bin/bash\n\
sudo efibootmgr -c -L %s \
-l \\\\EFI\\\\%s\\\\shim%s.efi\n\
rm -rf %s"
distro distro arch_suffix uefi_fallback_path in
Firstboot.add_firstboot_script
g inspect.i_root "fix uefi boot" fix_script
else
()
)
else
cant_fix_uefi ()
| _, _ ->
info (f_"No UEFI fix rule for %s %d")
inspect.i_distro inspect.i_major_version;
cant_fix_uefi ()
)
)
); (* inspect.i_firmware == I_UEFI *)
(* Delete blkid caches if they exist, since they will refer to the old
* device names. blkid will rebuild these on demand.
*
* Delete the LVM cache since it will contain references to the
* old devices (RHBZ#1164853, RHBZ#2112801).
*)
List.iter g#rm_f [
"/etc/blkid/blkid.tab"; "/etc/blkid.tab";
"/etc/lvm/cache/.cache"; "/etc/lvm/devices/system.devices"
];
(* This is a wrapper around Guestfs_packages.uninstall_command
* which catches errors and turns them into warnings, since
* uninstalling packages is best effort in virt-v2v. It also
* reloads the Augeas configuration since removing packages might
* change /etc files.
*)
and uninstall_packages_nonfatal pkgs =
if pkgs <> [] then (
let cmd =
try Guest_packages.uninstall_command pkgs inspect.i_package_management
with
| Guest_packages.Unknown_package_manager msg
| Guest_packages.Unimplemented_package_manager msg ->
error "%s" msg
in
(try ignore (g#sh cmd)
with G.Error msg ->
warning (f_"could not uninstall packages ‘%s’: %s (ignored)")
(String.concat " " pkgs) msg
);
(* Reload Augeas in case anything changed. *)
Linux.augeas_reload g
)
in
do_convert ()
module Convert_linux = struct
let name = "linux"
let convert = convert
let post_convert _ _ = ()
end
================================================
FILE: convert/convert_linux.mli
================================================
(* virt-v2v
* Copyright (C) 2009-2025 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.
*)
(** Convert a Linux guest to run on KVM.
This module converts certain Enterprise Linux guests to run on
KVM. RHEL, SuSE, Fedora, CentOS, OracleLinux, ALT, Debian, Ubuntu,
Mint and Kali are supported by this module. *)
module Convert_linux : Convert_types.CONVERT
================================================
FILE: convert/convert_types.ml
================================================
(* helper-v2v-convert
* Copyright (C) 2009-2025 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.
*)
module type CONVERT = sig
val name : string
val convert : Guestfs.guestfs -> Types.source -> Types.inspect ->
Firmware.i_firmware -> Types.guestcaps_block_type ->
bool -> Types.static_ip list ->
Types.guestcaps
val post_convert : Guestfs.guestfs -> Types.inspect -> unit
end
================================================
FILE: convert/convert_types.mli
================================================
(* virt-v2v
* Copyright (C) 2009-2025 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.
*)
module type CONVERT = sig
val name : string
(** Module name (only used in debugging). *)
val convert : Guestfs.guestfs -> Types.source -> Types.inspect ->
Firmware.i_firmware -> Types.guestcaps_block_type ->
bool -> Types.static_ip list ->
Types.guestcaps
(** Perform the guest-specific conversion for Linux or Windows.
This function is called with the guest disks mounted. *)
val post_convert : Guestfs.guestfs -> Types.inspect -> unit
(** Perform "post-conversion" operations. This is only used for
Windows, where some operations must be done after the disks
have been unmounted. For Linux it does nothing. *)
end
(** Conversion modules for Linux and Windows are provided separately.
They both provide this interface. *)
================================================
FILE: convert/convert_windows.ml
================================================
(* virt-v2v
* Copyright (C) 2009-2025 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 Utils
open Types
module G = Guestfs
(* Convert Windows guests.
*
* This only does a "pre-conversion", the steps needed to get the
* Windows guest to boot on KVM. Unlike the [Convert_linux] module,
* this is not a full conversion. Instead it just installs the
* [viostor] (Windows virtio block) driver, so that the Windows guest
* will be able to boot on the target. A [RunOnce] script is also
* added to the VM which does all the rest of the conversion the first
* time the Windows VM is booted on KVM.
*)
let convert (g : G.guestfs) source inspect i_firmware
block_driver _ static_ips =
(*----------------------------------------------------------------------*)
(* Inspect the Windows guest. *)
(* Locate virtio-win ISO or directory using the [VIRTIO_WIN]
* environment variable.
*)
let virtio_win =
Inject_virtio_win.from_environment g inspect.i_root Config.datadir in
(match block_driver with
| Virtio_blk -> () (* the default, no need to do anything *)
| Virtio_SCSI ->
let drivers = Inject_virtio_win.get_block_driver_priority virtio_win in
let drivers = "vioscsi" :: drivers in
Inject_virtio_win.set_block_driver_priority virtio_win drivers
| IDE -> assert false (* not possible - but maybe ...? *)
);
(* If the Windows guest has AV installed. *)
let has_antivirus =
List.exists (fun { G.app2_class } -> app2_class = "antivirus")
inspect.i_apps in
(* Does the guest expect the RTC to be set to UTC or localtime?
* See https://wiki.archlinux.org/title/System_time#UTC_in_Microsoft_Windows
* Note this might be a QWORD on 64 bit Windows instances.
*)
let rtc_utc =
Registry.with_hive_readonly g inspect.i_windows_system_hive
(fun reg ->
try
let key_path = [ "Control"; "TimeZoneInformation" ] in
let path = inspect.i_windows_current_control_set :: key_path in
let node =
match Registry.get_node reg path with
| None -> raise Not_found
| Some node -> node in
let valueh = g#hivex_node_get_value node "RealTimeIsUniversal" in
if valueh = 0L then raise Not_found;
let t = g#hivex_value_type valueh in
let data = g#hivex_value_value valueh in
let is_utc =
match t with
| 0_L (* REG_NONE *) -> false (* localtime *)
| 4_L (* REG_DWORD *) -> data = "\001\000\000\000"
| 11_L (* REG_QWORD *) -> data = "\001\000\000\000\000\000\000\000"
| _ (* who knows ... *) ->
warning (f_"unknown CurrentControlSet\\Control\\\
TimeZoneInformation key RealTimeIsUniversal \
type 0x%Lx, assuming RTC set to UTC") t;
true in
is_utc
with Not_found ->
(* If the key is not found then by default we assume
* that Windows is expecting the RTC to be set to localtime.
*)
false
) in
(* Open the software hive (readonly) and find the Xen PV uninstaller,
* if it exists.
*)
let xenpv_uninst =
let xenpvreg = "Red Hat Paravirtualized Xen Drivers for Windows(R)" in
Registry.with_hive_readonly g inspect.i_windows_software_hive
(fun reg ->
try
let path = ["Microsoft"; "Windows"; "CurrentVersion"; "Uninstall";
xenpvreg] in
let node =
match Registry.get_node reg path with
| None -> raise Not_found
| Some node -> node in
let uninstkey = "UninstallString" in
let valueh = g#hivex_node_get_value node uninstkey in
if valueh = 0L then (
warning (f_"cannot uninstall Xen PV drivers: registry key ‘HKLM\\\
SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\\
Uninstall\\%s’ does not contain an ‘%s’ key")
xenpvreg uninstkey;
raise Not_found
);
let data = g#hivex_value_value valueh in
let data = Registry.decode_utf16le data in
(* The uninstall program will be uninst.exe. This is a wrapper
* around _uninst.exe which prompts the user. As we don't want
* the user to be prompted, we run _uninst.exe explicitly.
*)
let len = String.length data in
let data =
if len >= 8 &&
String.lowercase_ascii (String.sub data (len-8) 8) = "uninst.exe"
then
(String.sub data 0 (len-8)) ^ "_uninst.exe"
else
data in
Some data
with
Not_found -> None
) in
(* Locate and retrieve all the uninstallation commands for installed
* applications.
*)
let uninstallation_commands pretty_name matchfn modfn extra_uninstall_params =
let path = ["Microsoft"; "Windows"; "CurrentVersion"; "Uninstall"] in
let uninstval = "UninstallString" in
let ret = ref [] in
Registry.with_hive_readonly g inspect.i_windows_software_hive (
fun reg ->
match Registry.get_node reg path with
| None -> ()
| Some node ->
let uninstnodes = g#hivex_node_children node in
Array.iter (
fun { G.hivex_node_h = uninstnode } ->
let valueh = g#hivex_node_get_value uninstnode "DisplayName" in
if valueh <> 0L then (
let dispname = g#hivex_value_string valueh in
if matchfn dispname then (
let valueh = g#hivex_node_get_value uninstnode uninstval in
if valueh <> 0L then (
let reg_cmd = g#hivex_value_string valueh in
let reg_cmd = modfn reg_cmd in
let cmd =
sprintf "%s /quiet /norestart /l*v+ \"%%~dpn0.log\" \
REBOOT=ReallySuppress REMOVE=ALL %s"
reg_cmd extra_uninstall_params in
List.push_front cmd ret
)
else
let name = g#hivex_node_name uninstnode in
warning (f_"cannot uninstall %s: registry key \
‘HKLM\\SOFTWARE\\%s\\%s’ with DisplayName \
‘%s’ doesn't contain value ‘%s’")
pretty_name (String.concat "\\" path) name
dispname uninstval
)
)
) uninstnodes
) (* with_hive_readonly *);
!ret
in
(* Locate and retrieve all uninstallation commands for Parallels Tools. *)
let prltools_uninsts =
let matchfn s =
String.find s "Parallels Tools" != -1 ||
String.find s "Virtuozzo Tools" != -1
in
(* Without these custom Parallels-specific MSI properties the
* uninstaller still shows a no-way-out reboot dialog.
*)
let extra_uninstall_params =
"PREVENT_REBOOT=Yes LAUNCHED_BY_SETUP_EXE=Yes" in
uninstallation_commands "Parallels Tools" matchfn Fun.id
extra_uninstall_params in
(* Locate and retrieve all uninstallation commands for VMware Tools. *)
let vmwaretools_uninst =
let matchfn s =
String.find s "VMware Tools" != -1
in
(* VMware Tools writes the install command (MsiExec /I) into the
* UninstallString key in the registry, rather than the uninstall
* command. Try to spot this and rewrite. (RHBZ#1917760).
*)
let re1 = PCRE.compile ~caseless:true "msiexec" in
let re2 = PCRE.compile ~caseless:true "/i" in
let msifn s = if PCRE.matches re1 s then PCRE.replace re2 "/x" s else s in
uninstallation_commands "VMware Tools" matchfn msifn "" in
(*----------------------------------------------------------------------*)
(* Perform the conversion of the Windows guest. *)
let rec do_convert () =
(* Firstboot configuration. *)
configure_firstboot ();
(* Open the system hive for writes and update it. *)
let { Inject_virtio_win.block_driver; net_driver} as virtio_win_installed =
Registry.with_hive_write g inspect.i_windows_system_hive
update_system_hive in
(* Open the software hive for writes and update it. *)
Registry.with_hive_write g inspect.i_windows_software_hive
update_software_hive;
configure_online_disks block_driver;
configure_network_interfaces net_driver;
fix_ntfs_heads ();
fix_win_esp ();
(* Warn if installation of virtio block drivers might conflict with
* group policy or AV software causing a boot 0x7B error (RHBZ#1260689).
*)
if block_driver = Virtio_blk then (
if inspect.i_windows_group_policy then
warning (f_"this guest has Windows Group Policy Objects (GPO) and a \
new virtio block device driver was installed. In some \
circumstances, Group Policy may prevent new drivers from \
working (resulting in a 7B boot error). If this happens, \
try disabling Group Policy before doing the conversion.");
if has_antivirus then
warning (f_"this guest has Anti-Virus (AV) software and a new virtio \
block device driver was installed. In some \
circumstances, AV may prevent new drivers from working \
(resulting in a 7B boot error). If this happens, try \
disabling AV before doing the conversion.");
);
(* Return guest capabilities from the convert () function. *)
let guestcaps = {
gcaps_block_bus = of_virtio_win_block_type block_driver;
gcaps_net_bus = of_virtio_win_net_type net_driver;
gcaps_virtio_rng = virtio_win_installed.Inject_virtio_win.virtio_rng;
gcaps_virtio_balloon =
virtio_win_installed.Inject_virtio_win.virtio_balloon;
gcaps_isa_pvpanic = virtio_win_installed.Inject_virtio_win.isa_pvpanic;
gcaps_virtio_socket =
virtio_win_installed.Inject_virtio_win.virtio_socket;
gcaps_machine = of_virtio_win_machine_type
virtio_win_installed.Inject_virtio_win.machine;
gcaps_arch = Utils.kvm_arch inspect.i_arch;
gcaps_arch_min_version = 0;
gcaps_virtio_1_0 = virtio_win_installed.Inject_virtio_win.virtio_1_0;
gcaps_rtc_utc = rtc_utc;
} in
guestcaps
and of_virtio_win_block_type = function
| Inject_virtio_win.Virtio_blk -> Virtio_blk
| Virtio_SCSI -> Virtio_SCSI
| IDE -> IDE
and of_virtio_win_net_type = function
| Inject_virtio_win.Virtio_net -> Virtio_net
| E1000 -> E1000
| RTL8139 -> RTL8139
and of_virtio_win_machine_type = function
| Inject_virtio_win.I440FX -> I440FX
| Q35 -> Q35
| Virt -> Virt
and configure_firstboot () =
(* Run the firstboot script with pnputil.exe before the one with
* pnp_wait.exe as the latter suppresses PnP for all following scripts.
*)
configure_pnputil_install ();
let tool_path = virt_tools_data_dir () // "pnp_wait.exe" in
if Sys.file_exists tool_path then
configure_wait_pnp tool_path
else
debug (f_"%s is missing. Firstboot scripts may conflict with PnP.")
tool_path;
(* Install VMDP unconditionally, if available, but don't
* warn about it if not.
*)
let tool_path = virt_tools_data_dir () // "vmdp.exe" in
if Sys.file_exists tool_path then
configure_vmdp tool_path;
(* Install QEMU Guest Agent unconditionally and warn if missing *)
if not (Inject_virtio_win.inject_qemu_ga virtio_win) then
warning (f_"QEMU Guest Agent MSI not found on tools ISO/directory. You \
may want to install the guest agent manually after \
conversion.");
(* Install Balloon Server unconditionally and warn if missing *)
if not (Inject_virtio_win.inject_blnsvr virtio_win) then
warning (f_"Balloon Server (blnsvr.exe) not found on tools \
ISO/directory. You may want to install this component \
manually after conversion.");
unconfigure_xenpv ();
unconfigure_prltools ();
unconfigure_vmwaretools ()
(* [set_reg_val_dword_1 path name] creates a registry key
* called [name = dword:1] in the registry [path].
* Intermediate nodes are created along the path if required.
*
* It returns the old value, if there was one, else [None].
*)
and set_reg_val_dword_1 ((g, root) as reg) path name =
let node = Registry.create_path reg path in
let valueh = g#hivex_node_get_value node name in
let value =
match valueh with
| 0L -> None
| _ -> Some (int_of_le32 (g#hivex_value_value valueh)) in
g#hivex_node_set_value node name 4_L (le32_of_int 1_L);
value
and reg_restore key name value =
let strkey = String.concat "\\" key in
match value with
| Some value -> sprintf "reg add \"%s\" /v %s /t REG_DWORD /d %Ld /f"
strkey name value
| None -> sprintf "reg delete \"%s\" /v %s /f" strkey name
and configure_pnputil_install () =
let fb_script = {|@echo off
setlocal EnableDelayedExpansion
set inf_dir=%systemroot%\Drivers\Virtio\
echo Installing drivers from %inf_dir%
set REBOOT_PENDING=0
reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired"
if %errorlevel%==0 (
echo Windows Update: Reboot required.
set REBOOT_PENDING=1
)
reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending"
if %errorlevel%==0 (
echo CBS: Reboot required.
set REBOOT_PENDING=1
)
reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager" /v PendingFileRenameOperations
if %errorlevel%==0 (
echo Session Manager: Reboot required.
set REBOOT_PENDING=1
)
if "%REBOOT_PENDING%"=="1" (
echo A reboot is pending.
exit /b 249
) else (
echo No pending reboot detected.
)
for %%f in ("%inf_dir%*.inf") do (
echo Installing: %%~nxf.
%systemroot%\Sysnative\PnPutil -i -a "%%f"
if !errorlevel! neq 0 if !errorlevel! neq 259 (
echo Failed to install %%~nxf.
exit /b 249
) else (
echo Successfully installed %%~nxf.
)
)
echo All drivers installed successfully.
exit /b 0
)|} in
(* Set priority higher than that of "network-configure" firstboot script. *)
Firstboot.add_firstboot_script g inspect.i_root ~prio:2000
"pnputil install drivers" fb_script;
and configure_wait_pnp tool_path =
(* Prevent destructive interactions of firstboot with PnP. *)
(* Suppress "New Hardware Wizard" until PnP settles (see
* https://support.microsoft.com/en-us/kb/938596) and restore it
* afterwards.
*)
let reg_restore_str =
match inspect.i_major_version, inspect.i_minor_version with
(* WinXP 32bit *)
| 5, 1 ->
let key_path = ["Policies"; "Microsoft"; "Windows"; "DeviceInstall";
"Settings"] in
let name = "SuppressNewHWUI" in
let value =
Registry.with_hive_write g inspect.i_windows_software_hive (
fun reg -> set_reg_val_dword_1 reg key_path name
) in
reg_restore ("HKLM\\Software" :: key_path) name value
(* WinXP 64bit / Win2k3 *)
| 5, 2 ->
let key_path = ["Services"; "PlugPlay"; "Parameters"] in
let name = "SuppressUI" in
let value =
Registry.with_hive_write g inspect.i_windows_system_hive (
fun reg ->
let path = inspect.i_windows_current_control_set :: key_path in
set_reg_val_dword_1 reg path name
) in
reg_restore ("HKLM\\SYSTEM\\CurrentControlSet" :: key_path) name
value
(* any later Windows *)
| _ -> "" in
let pnp_wait_path = "/Program Files/Guestfs/Firstboot/pnp_wait.exe" in
let fb_script = sprintf
{|@echo off
echo Wait for PnP to complete
"%s"
%s|}
(String.replace_char pnp_wait_path '/' '\\')
reg_restore_str in
Firstboot.add_firstboot_script g inspect.i_root "wait pnp" fb_script;
(* add_firstboot_script has created the path already. *)
g#upload tool_path (g#case_sensitive_path pnp_wait_path)
and configure_vmdp tool_path =
(* Configure VMDP if possible *)
g#upload tool_path "/vmdp.exe";
let fb_script = {|echo V2V first boot script started
echo Decompressing VMDP installer
"\vmdp.exe"
pushd "VMDP-*"
echo Installing VMDP
setup.exe /eula_accepted /no_reboot
popd
|} in
let fb_recover_script = {|echo Finishing VMDP installation
if not exist VMDP-* (
"\vmdp.exe"
)
pushd "VMDP-*"
setup.exe /eula_accepted /no_reboot
popd
|} in
Firstboot.add_firstboot_script g inspect.i_root
"configure vmdp" fb_script;
Firstboot.add_firstboot_script g inspect.i_root
"finish vmdp setup" fb_recover_script
and unconfigure_xenpv () =
match xenpv_uninst with
| None -> () (* nothing to be uninstalled *)
| Some uninst ->
let fb_script = sprintf
{|@echo off
echo uninstalling Xen PV driver
"%s"
|}
uninst in
Firstboot.add_firstboot_script g inspect.i_root
"uninstall Xen PV" fb_script
and unconfigure_prltools () =
let regkey =
"HKLM\\System\\CurrentControlSet\\Services\\prl_strg\\DriverInfo" in
List.iter (
fun uninst ->
let fb_script = sprintf
{|@echo off
REG DELETE %s /v RefCount /f
echo uninstalling Parallels guest tools
rem ERROR_SUCCESS_REBOOT_REQUIRED (3010) is OK too
%s
if errorlevel 3010 exit /b 0
|}
regkey uninst in
Firstboot.add_firstboot_script g inspect.i_root
"uninstall Parallels tools" fb_script
) prltools_uninsts
and unconfigure_vmwaretools () =
List.iter (
fun uninst ->
let fb_script = sprintf
{|@echo off
echo uninstalling VMware Tools
rem ERROR_SUCCESS_REBOOT_REQUIRED (3010) is OK too
%s
if errorlevel 3010 exit /b 0
|}
uninst in
Firstboot.add_firstboot_script g inspect.i_root
"uninstall VMware Tools" fb_script
) vmwaretools_uninst
and update_system_hive reg =
(* Update the SYSTEM hive. When this function is called the hive has
* already been opened as a hivex handle inside guestfs.
*)
disable_xenpv_win_drivers reg;
disable_prl_drivers reg;
disable_autoreboot reg;
Inject_virtio_win.inject_virtio_win_drivers virtio_win reg
and disable_xenpv_win_drivers reg =
(* Disable xenpv-win service (RHBZ#809273). *)
let services =
Registry.get_node reg
[inspect.i_windows_current_control_set; "Services"] in
match services with
| None -> ()
| Some services ->
let node = g#hivex_node_get_child services "rhelscsi" in
if node <> 0L then
g#hivex_node_set_value node "Start" 4_L (le32_of_int 4_L)
and disable_prl_drivers reg =
(* Prevent Parallels drivers from loading at boot. *)
let services =
Registry.get_node reg
[inspect.i_windows_current_control_set; "Services"] in
let prl_svcs = [ "prl_boot"; "prl_dd"; "prl_eth5"; "prl_fs"; "prl_memdev";
"prl_mouf"; "prl_pv32"; "prl_pv64"; "prl_scsi";
"prl_sound"; "prl_strg"; "prl_tg"; "prl_time";
"prl_uprof"; "prl_va" ] in
match services with
| None -> ()
| Some services ->
List.iter (
fun svc ->
let svc_node = g#hivex_node_get_child services svc in
if svc_node <> 0L then (
(* Disable the service rather than delete the node as it would
* confuse the uninstaller called from firstboot script. *)
g#hivex_node_set_value svc_node "Start" 4_L (le32_of_int 4_L)
)
) prl_svcs;
(* perform the equivalent of DelReg from prl_strg.inf:
* HKLM, System\CurrentControlSet\Control\Class\{4d36e967-e325-11ce-bfc1-08002be10318}, LowerFilters, 0x00018002, prl_strg
*)
let strg_cls = Registry.get_node reg
[inspect.i_windows_current_control_set;
"Control"; "Class";
"{4d36e967-e325-11ce-bfc1-08002be10318}"] in
match strg_cls with
| None -> ()
| Some strg_cls ->
let lfkey = "LowerFilters" in
let valueh = g#hivex_node_get_value strg_cls lfkey in
if valueh <> 0L then (
let data = g#hivex_value_value valueh in
let filters = String.nsplit "\000" (Registry.decode_utf16le data) in
let filters = List.filter (
fun x -> x <> "prl_strg" && x <> ""
) filters in
let filters = List.map (
fun x -> Registry.encode_utf16le x ^ "\000\000"
) (filters @ [""]) in
let data = String.concat "" filters in
g#hivex_node_set_value strg_cls lfkey 7_L data
)
and disable_autoreboot reg =
(* If the guest reboots after a crash, it's hard to see the original
* error (eg. the infamous 0x0000007B). Turn off autoreboot.
*)
let crash_control =
Registry.get_node reg [inspect.i_windows_current_control_set;
"Control"; "CrashControl"] in
match crash_control with
| None -> ()
| Some crash_control ->
g#hivex_node_set_value crash_control "AutoReboot" 4_L (le32_of_int 0_L)
and update_software_hive reg =
(* Update the SOFTWARE hive. When this function is called the
* hive has already been opened as a hivex handle inside
* guestfs.
*)
(* Find the node \Microsoft\Windows\CurrentVersion. If the node
* has a key called DevicePath then append the virtio driver
* path to this key.
*
* Note that simply adding the directory to DevicePath doesn't
* seem to be a 100% reliable way of enabling the drivers. In
* particular it does not work for my self-built Windows Server Core
* 2012 + R2 releases (although that might be an artifact of
* the way I build them). In any case I had to add a firstboot
* batch file which did this single command:
*
* %systemroot%\Sysnative\PnPutil -i -a %systemroot%\Drivers\Virtio\*.inf
*)
let node =
Registry.get_node reg ["Microsoft"; "Windows"; "CurrentVersion"] in
(match node with
| Some node ->
let append = Registry.encode_utf16le ";%SystemRoot%\\Drivers\\VirtIO" in
let values = Array.to_list (g#hivex_node_values node) in
let rec loop = function
| [] -> () (* DevicePath not found -- ignore this case *)
| { G.hivex_value_h = valueh } :: values ->
let key = g#hivex_value_key valueh in
if key <> "DevicePath" then
loop values
else (
let data = g#hivex_value_value valueh in
let len = String.length data in
let t = g#hivex_value_type valueh in
(* Only add the appended path if it doesn't exist already. *)
if String.find data append = -1 then (
(* Remove the explicit [\0\0] at the end of the string.
* This is the UTF-16LE NUL-terminator.
*)
let data =
if len >= 2 && String.sub data (len-2) 2 = "\000\000" then
String.sub data 0 (len-2)
else
data in
(* Append the path and the explicit NUL. *)
let data = data ^ append ^ "\000\000" in
g#hivex_node_set_value node key t data
)
)
in
loop values
| None ->
warning (f_"could not find registry key \
HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion")
);
(* If you have trouble installing drivers, try increasing the
* verboseness by uncommenting this section.
* https://learn.microsoft.com/en-us/windows-hardware/drivers/install/setting-setupapi-logging-levels
* The additional logs are written to C:\Windows\INF\setupapi.*.log
*)
(*
let node =
Registry.get_node reg ["Microsoft"; "Windows"; "CurrentVersion";
"Setup"] in
(match node with
| Some node ->
g#hivex_node_set_value node "LogLevel" 4_L (le32_of_int 0xff_L)
| None ->
warning (f_"could not find registry key \
HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup")
);
*)
and configure_online_disks block_driver =
(* If there are > 1 disks, run a script which will force Windows
* to bring them all online. Windows 2022 will offline non-boot disks
* where the bus changes as some sort of "security" mitigation.
* https://issues.redhat.com/browse/RHEL-55837
* https://issues.redhat.com/browse/MTV-1299
* https://bugzilla.redhat.com/show_bug.cgi?id=1662286
*)
let virtio_installed =
match block_driver with
| Inject_virtio_win.Virtio_blk | Virtio_SCSI -> true
| IDE -> false in
let more_than_one_disk = List.length source.s_disks > 1 in
if virtio_installed && more_than_one_disk then (
let psh_filename = "online-disks" in
let psh = ref [] in
let add = List.push_back psh in
add "# Uncomment this line for lots of debug output.";
add "# Set-PSDebug -Trace 1";
add "";
add "Write-Host \"Online all virtio disks\"";
add "";
add "Get-Disk | Where { $_.FriendlyName -like '*VirtIO*' } | % {";
add " Write-Host (' - ' + $_.Number + ': ' + $_.FriendlyName + '(' + [math]::Round($_.Size/1GB,2) + 'GB)')";
add " $_ | Set-Disk -IsOffline $false";
add " $_ | Set-Disk -IsReadOnly $false";
add "}";
(* Install the Powershell script to run late at firstboot. *)
Firstboot.add_firstboot_powershell g inspect.i_root psh_filename !psh
)
and configure_network_interfaces net_driver =
(* If we were asked to force network interfaces to have particular
* static IP addresses then it is done here by installing a
* Powershell script which runs at boot.
*)
if static_ips <> [] then (
let psh_filename = "network-configure" in
let psh = ref [] in
let add = List.push_back psh in
add "# Uncomment this line for lots of debug output.";
add "# Set-PSDebug -Trace 1";
add "";
(* If virtio-net was added to the registry, we must wait for
* it to be installed at runtime.
*)
if net_driver = Virtio_net then (
add "# Wait for the netkvm (virtio-net) driver to become active.";
add "$startdate = Get-Date";
add "$adapters = @()";
add "While (-Not $adapters -and \
$startdate.AddMinutes(5) -gt (Get-Date)) {";
add " Start-Sleep -Seconds 5";
add " $adapters = Get-NetAdapter -Physical \
| Where DriverFileName -eq \"netkvm.sys\"";
add " Write-Host \"adapters = '$adapters'\"";
add "}";
add "# In the timeout case $ifindex will not be set below.";
add ""
);
List.iter (
fun { if_mac_addr; if_ip_address; if_default_gateway;
if_prefix_length; if_nameservers } ->
add (sprintf "$mac_address = '%s'"
(String.replace if_mac_addr ":" "-"));
add "$ifindex = (Get-NetAdapter -Physical \
| Where MacAddress -eq $mac_address).ifIndex";
add "if ($ifindex) {";
add " Write-Host \"setting IP address of adapter at $ifindex\"";
(* New-NetIPAddress command *)
let args = ref [] in
List.push_back args "-InterfaceIndex";
List.push_back args "$ifindex";
List.push_back args "-IPAddress";
List.push_back args (sprintf "'%s'" if_ip_address);
(match if_default_gateway with
| None -> ()
| Some gw ->
List.push_back args "-DefaultGateway";
List.push_back args (sprintf "'%s'" gw)
);
(match if_prefix_length with
| None -> ()
| Some len ->
List.push_back args "-PrefixLength";
List.push_back args (string_of_int len)
);
let cmd1 = "New-NetIPAddress " ^ String.concat " " !args in
add (" " ^ cmd1);
(* Set-DnsClientServerAddress command *)
if if_nameservers <> [] then (
add (sprintf " Set-DnsClientServerAddress \
-InterfaceIndex $ifindex \
-ServerAddresses (%s)"
(String.concat ","
(List.map (sprintf "'%s'") if_nameservers)))
);
add "}";
add ""
) static_ips;
(* Install the Powershell script to run at firstboot.
*
* Place it first among the firstboot scripts (RHBZ#1788823).
*)
Firstboot.add_firstboot_powershell g inspect.i_root ~prio:2500
psh_filename !psh
) (* static_ips <> [] *)
and fix_ntfs_heads () =
(* NTFS hardcodes the number of heads on the drive which created
it in the filesystem header. Modern versions of Windows
sensibly ignore it, but both Windows XP and Windows 2000
require it to be correct in order to boot from the drive. If it
isn't you get:
'A disk read error occurred. Press Ctrl+Alt+Del to restart'
QEMU has some code in block.c:guess_disk_lchs() which on the face
of it appears to infer the drive geometry from the MBR if it's
valid. However, my tests have shown that a Windows XP guest
hosted on both RHEL 5 and F14 requires the heads field in NTFS to
be the following, based solely on drive size:
Range Heads
size < 2114445312 0x40
2114445312 <= size < 4228374780 0x80
4228374780 <= size 0xFF
I have not tested drive sizes less than 1G, which require fewer
heads, as this limitation applies only to the boot device and it
is not possible to install XP on a drive this size.
The following page has good information on the layout of NTFS in
Windows XP/2000:
http://mirror.href.com/thestarman/asm/mbr/NTFSBR.htm
Technet has this:
http://technet.microsoft.com/en-us/library/cc781134(WS.10).aspx#w2k3tr_ntfs_how_dhao
however, as this is specific to Windows 2003 it lists location
0x1A as unused.
*)
if inspect.i_major_version < 6 (* is Windows 2000/XP *) then (
let rootpart = inspect.i_root in
(* Ignore if the rootpart is something like /dev/sda. RHBZ#1276540. *)
if not (g#is_whole_device rootpart) then (
(* Check that the root device contains NTFS magic. *)
let magic = g#pread_device rootpart 8 3L in
if magic = "NTFS " then (
(* Get the size of the whole disk containing the root partition. *)
let rootdev = g#part_to_dev rootpart in (* eg. /dev/sda *)
let size = g#blockdev_getsize64 rootdev in
let heads = (* refer to the table above *)
if size < 2114445312L then 0x40
else if size < 4228374780L then 0x80
else 0xff in
(* Update NTFS's idea of the number of heads. This is an
* unsigned 16 bit little-endian integer, offset 0x1a from the
* beginning of the partition.
*)
let b = Bytes.create 2 in
Bytes.unsafe_set b 0 (Char.chr heads);
Bytes.unsafe_set b 1 '\000';
ignore (g#pwrite_device rootpart (Bytes.to_string b) 0x1a_L)
)
)
)
and fix_win_esp () =
let fix_win_uefi_bcd esp_path =
try
let bcd_path = "/EFI/Microsoft/Boot/BCD" in
Registry.with_hive_write g (esp_path ^ bcd_path) (
(* Remove the 'graphicsmodedisabled' key in BCD *)
fun reg ->
let path = ["Objects"; "{9dea862c-5cdd-4e70-acc1-f32b344d4795}";
"Elements"; "23000003"] in
let boot_mgr_default_link =
match Registry.get_node reg path with
| None -> raise Not_found
| Some node -> node in
let current_boot_entry = g#hivex_value_string (
g#hivex_node_get_value boot_mgr_default_link "Element") in
let path = ["Objects"; current_boot_entry; "Elements"; "16000046"] in
match Registry.get_node reg path with
| None -> raise Not_found
| Some graphics_mode_disabled ->
g#hivex_node_delete_child graphics_mode_disabled
);
with
Not_found -> ()
and fix_win_uefi_fallback esp_path uefi_arch =
(* [esp_path] is on NTFS, and therefore it is considered case-sensitive;
* refer to
* <https://libguestfs.org/guestfs.3.html#guestfs_case_sensitive_path>.
* However, the EFI system partition mounted under [esp_path] is FAT32 per
* UEFI spec, and the Linux vfat driver in the libguestfs appliance treats
* pathnames case-insensitively. Therefore, we're free to use any case in
* the ESP-relative pathnames below.
*)
let bootmgfw = sprintf "%s/efi/microsoft/boot/bootmgfw.efi" esp_path in
if g#is_file bootmgfw then
let bootdir = sprintf "%s/efi/boot" esp_path in
let fallback = sprintf "%s/boot%s.efi" bootdir uefi_arch in
if not (g#is_file fallback) || not (g#equal fallback bootmgfw) then (
info (f_"Fixing UEFI bootloader.");
g#rm_rf bootdir;
g#mkdir_p bootdir;
g#cp_a bootmgfw fallback
)
in
match i_firmware with
| Firmware.I_BIOS -> ()
| I_UEFI esp_list ->
let esp_temp_path =
let temp = inspect.i_windows_systemroot ^ "/Temp" in
let mp = g#case_sensitive_path temp in
let template = mp ^ "/ESP_XXXXXX" in
g#mkdtemp template in
let uefi_arch = get_uefi_arch_suffix inspect.i_arch in
List.iter (
fun dev_path ->
g#mount dev_path esp_temp_path;
fix_win_uefi_bcd esp_temp_path;
(match uefi_arch with
| Some uefi_arch -> fix_win_uefi_fallback esp_temp_path uefi_arch
| None -> ()
);
g#umount esp_temp_path;
) esp_list;
g#rmdir esp_temp_path
in
do_convert ()
(* Post-conversion steps that run with filesystems unmounted *)
let post_convert (g : G.guestfs) inspect =
(* Lock down firstboot dir permissions for windows guests *)
message (f_"Fixing NTFS permissions");
(* XXX It would be more correct to use g#case_sensitive_path
* here, but we cannot do that since the guest filesystem is
* not mounted. As fixing permissions is best-effort, let's
* not worry about it.
*)
let path = "/Program Files/Guestfs" in
debug "info: fixing NTFS permissions on %s" path;
try g#ntfs_chmod inspect.i_root 0o755 path ~recursive:true
with G.Error msg ->
warning (f_"ntfs_chmod on %s failed: %s") path msg
module Convert_windows = struct
let name = "windows"
let convert = convert
let post_convert = post_convert
end
================================================
FILE: convert/convert_windows.mli
================================================
(* virt-v2v
* Copyright (C) 2009-2025 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.
*)
(** Convert a Windows guest to run on KVM.
This module converts a Windows guest to run on KVM. *)
module Convert_windows : Convert_types.CONVERT
================================================
FILE: convert/dummy.c
================================================
/* Dummy source, to be used for OCaml-based tools with no C sources. */
enum { foo = 1 };
================================================
FILE: convert/mount_filesystems.ml
================================================
(* virt-v2v
* Copyright (C) 2009-2025 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
open Types
let rec mount_filesystems g root =
reject_if_not_installed_image g root;
reject_if_unknown_fields g root;
(* Get the list of filesystems. This is not actually used by
* virt-v2v (only used by virt-v2v-inspector) so try hard not
* to fail here.
*)
let fses = g#inspect_get_filesystems root in
let fses = Array.to_list fses in
let fses = List.sort compare fses in
let fses =
List.map (
fun dev ->
let dev = g#canonical_device_name dev
and fs_type = ref None
and fs_version = ref None
and fs_label = ref None
and fs_uuid = ref None in
(try
let v = g#vfs_type dev in
if v <> "" then (
fs_type := Some v;
fs_version := get_filesystem_version g dev v;
)
with G.Error msg -> debug "vfs_type: %s: %s (ignored)" dev msg);
(try
let v = g#vfs_label dev in
if v <> "" then fs_label := Some v
with G.Error msg -> debug "vfs_label: %s: %s (ignored)" dev msg);
(try
let v = g#vfs_uuid dev in
if v <> "" then fs_uuid := Some v
with G.Error msg -> debug "vfs_uuid: %s: %s (ignored)" dev msg);
{ fs_dev = dev; fs_type = !fs_type; fs_version = !fs_version;
fs_label = !fs_label; fs_uuid = !fs_uuid }
) fses in
(* Mount up the filesystems. *)
let mps = g#inspect_get_mountpoints root in
let cmp (a,_) (b,_) = compare (String.length a) (String.length b) in
let mps = List.sort cmp mps in
List.iter (
fun (mp, dev) ->
(try g#mount dev mp
with G.Error msg ->
if mp = "/" then ( (* RHBZ#1145995 *)
if String.find msg "Windows" >= 0 &&
String.find msg "NTFS partition is in an unsafe state" >= 0 then
error (f_"unable to mount the disk image for writing. This has \
probably happened because Windows Hibernation or \
Fast Restart is being used in this guest. You have \
to disable this (in the guest) in order to use \
virt-v2v.\n\nOriginal error message: %s") msg
else
error "%s" msg
)
else
warning (f_"%s (ignored)") msg
);
(* Some filesystems (hello, ntfs-3g) can silently fall back to
* a read-only mount. Check the root filesystem is really writable.
* RHBZ#1567763
*)
if mp = "/" then (
let file = sprintf "/%s" (String.random8 ()) in
(try g#touch file
with G.Error msg ->
if g#last_errno () = G.Errno.errno_EROFS then
error (f_"filesystem was mounted read-only, even though we \
asked for it to be mounted read-write. This usually \
means that the filesystem was not cleanly unmounted. \
Possible causes include trying to convert a guest \
which is running, or using Windows Hibernation or \
Fast Restart.\n\nOriginal error message: %s") msg
else
error (f_"could not write to the guest filesystem: %s") msg
);
g#rm file
)
) mps;
(* Get list of applications/packages installed. *)
let package_format = g#inspect_get_package_format root in
let apps = list_applications g root package_format in
let apps = Array.to_list apps in
(* A map of app2_name -> application2, for easier lookups. Note
* that app names are not unique! (eg. 'kernel' can appear multiple
* times)
*)
let apps_map = List.fold_left (
fun map app ->
let name = app.G.app2_name in
let vs = try StringMap.find name map with Not_found -> [] in
StringMap.add name (app :: vs) map
) StringMap.empty apps in
let drive_mappings = g#inspect_get_drive_mappings root in
(* If the guest is Windows, get some Windows-specific inspection
* data, else (for simplicity when accessing) use empty strings.
*)
let typ = g#inspect_get_type root in
let systemroot, software_hive, system_hive, current_cs, group_policy =
match typ with
| "windows" ->
g#inspect_get_windows_systemroot root,
g#inspect_get_windows_software_hive root,
g#inspect_get_windows_system_hive root,
g#inspect_get_windows_current_control_set root,
g#inspect_get_windows_group_policy root
| _ ->
"", "", "", "", false in
let inspect = {
i_root = root;
i_type = typ;
i_distro = g#inspect_get_distro root;
i_osinfo = g#inspect_get_osinfo root;
i_arch = g#inspect_get_arch root;
i_major_version = g#inspect_get_major_version root;
i_minor_version = g#inspect_get_minor_version root;
i_package_format = package_format;
i_package_management = g#inspect_get_package_management root;
i_product_name = g#inspect_get_product_name root;
i_product_variant = g#inspect_get_product_variant root;
i_mountpoints = mps;
i_filesystems = fses;
i_apps = apps;
i_apps_map = apps_map;
i_windows_systemroot = systemroot;
i_windows_software_hive = software_hive;
i_windows_system_hive = system_hive;
i_windows_current_control_set = current_cs;
i_windows_group_policy = group_policy;
i_drive_mappings = drive_mappings;
} in
debug "%s" (string_of_inspect inspect);
inspect
(* Reject this OS if it doesn't look like an installed image. *)
and reject_if_not_installed_image g root =
let fmt = g#inspect_get_format root in
if fmt <> "installed" then
error (f_"libguestfs thinks this is not an installed operating \
system (it might be, for example, an installer disk \
or live CD). If this is wrong, it is probably a bug \
in libguestfs. root=%s fmt=%s") root fmt
(* If some inspection fields are "unknown", then that indicates a
* failure in inspection, and we shouldn't continue. For an example
* of this, see RHBZ#1278371. However don't "assert" here, since
* the user might have pointed virt-v2v at a blank disk. Give an
* error message instead.
*)
and reject_if_unknown_fields g root =
error_if_unknown "i_type" (g#inspect_get_type root);
error_if_unknown "i_distro" (g#inspect_get_distro root);
error_if_unknown "i_arch" (g#inspect_get_arch root)
and error_if_unknown fieldname value =
if value = "unknown" then
error (f_"inspection could not detect the source guest (or \
physical machine) operating system.\n\n\
Assuming that you are running virt-v2v/virt-p2v \
on a source which is supported (and not, for example, \
a blank disk), then this should not happen.\n\n\
Inspection field ‘%s’ was ‘unknown’.")
fieldname
(* See equivalent function in guestfs-tools.git:inspector/inspector.c *)
and get_filesystem_version g dev = function
| "xfs" ->
let hash = g#xfs_info2 dev in
(match List.assoc_opt "meta-data.crc" hash with
| None -> None
| Some "0" -> (* XFS version *) Some "4"
| Some "1" -> (* XFS version *) Some "5"
| Some _ -> None
)
| _ -> None
(* Wrapper around g#inspect_list_applications2 which, for RPM
* guests, on failure tries to rebuild the RPM database before
* repeating the operation.
*)
and list_applications g root = function
| "rpm" ->
(* RPM guest.
*
* In libguestfs before commit 488245ed6c ("daemon: rpm: Check
* return values from librpm calls"), a corrupt RPM database
* would return an empty array here with no exception. Hence
* the check below which turns empty array => exception. In
* libguestfs after that commit, inspect_list_applications2
* will raise an exception if it detects a corrupt RPM database.
*)
(try
let apps = g#inspect_list_applications2 root in
if apps = [||] then raise (G.Error "no applications returned");
apps
with G.Error msg ->
debug "%s" msg;
debug "rebuilding RPM database and retrying ...";
ignore (g#sh "rpmdb --rebuilddb");
g#inspect_list_applications2 root
)
| _ ->
(* Non-RPM guest, just do it. *)
g#inspect_list_applications2 root
================================================
FILE: convert/mount_filesystems.mli
================================================
(* virt-v2v
* Copyright (C) 2009-2025 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.
*)
(** Mount up the filesystems. *)
val mount_filesystems : Guestfs.guestfs -> string -> Types.inspect
(** Mount up the filesystems and return inspection data for the root
disk, plus some other checks.
{!Choose_root.choose_root} should have been called already
(which actually does libguestfs inspection).
After calling this, the filesystems are mounted up. *)
================================================
FILE: convert/target_bus_assignment.ml
================================================
(* virt-v2v
* Copyright (C) 2009-2025 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 Types
let rec target_bus_assignment source_disks source_removables guestcaps =
let virtio_blk_bus = ref [| |]
and ide_bus = ref [| |]
and scsi_bus = ref [| |]
and floppy_bus = ref [| |] in
(* Assign the fixed disks (source_disks) to either the virtio-blk or
* IDE bus, depending on whether the guest has virtio drivers or not.
*)
let () =
let bus =
match guestcaps.gcaps_block_bus with
| Virtio_blk -> virtio_blk_bus
| Virtio_SCSI -> scsi_bus
| IDE -> ide_bus in
List.iteri (
fun i d ->
let d = BusSlotDisk d in
insert bus i d
) source_disks in
(* Now we have to assign the removable disks. These go in the
* same slot they originally occupied, except in two cases: (1) That
* slot is now occupied by a target disk, or (2) we don't
* have information about the original slot. In these cases
* insert the disk in the next empty slot in that bus.
*)
(* Split the removables into a list of devices that desire a
* particular slot, and those that don't care. Assign the first
* group first so they have a greater chance of getting the
* desired slot.
*)
let removables_desire, removables_no_desire =
List.partition (
function
| { s_removable_slot = Some _ } -> true
| { s_removable_slot = None } -> false
) source_removables in
let assign_removables removables =
List.iter (
fun r ->
let t = BusSlotRemovable r in
let bus =
match r.s_removable_type with
| Floppy -> floppy_bus
| CDROM ->
match r.s_removable_controller with
| None -> ide_bus (* Wild guess, but should be safe. *)
| Some Source_virtio_blk -> virtio_blk_bus
| Some Source_IDE -> ide_bus
| Some (Source_virtio_SCSI | Source_SCSI | Source_SATA |
Source_NVME) -> scsi_bus in
match r.s_removable_slot with
| None ->
ignore (insert_after bus 0 t)
| Some desired_slot_nr ->
if not (insert_after bus desired_slot_nr t) then
warning (f_"removable %s device in slot %d clashes with another \
disk, so it has been moved to a higher numbered slot \
on the same bus. This may mean that this removable \
device has a different name inside the guest (for \
example a CD-ROM originally called /dev/hdc might \
move to /dev/hdd, or from D: to E: on a Windows \
guest).")
(match r.s_removable_type with
| CDROM -> s_"CD-ROM"
| Floppy -> s_"floppy disk")
desired_slot_nr
) removables
in
assign_removables removables_desire;
assign_removables removables_no_desire;
{ target_virtio_blk_bus = !virtio_blk_bus;
target_ide_bus = !ide_bus;
target_scsi_bus = !scsi_bus;
target_floppy_bus = !floppy_bus }
(* Insert a slot into the bus array, making the array bigger if necessary. *)
and insert bus i slot =
let oldbus = !bus in
let oldlen = Array.length oldbus in
if i >= oldlen then (
bus := Array.make (i+1) BusSlotEmpty;
Array.blit oldbus 0 !bus 0 oldlen
);
assert (!bus.(i) = BusSlotEmpty);
!bus.(i) <- slot
(* Insert a slot into the bus, but if the desired slot is not empty, then
* increment the slot number until we find an empty one. Returns
* true if we got the desired slot.
*)
and insert_after bus i slot =
if slot_is_empty bus i then (
insert bus i slot; true
) else (
ignore (insert_after bus (i+1) slot); false
)
(* Return true if slot i is empty in the bus. *)
and slot_is_empty bus i = i >= Array.length !bus || !bus.(i) = BusSlotEmpty
================================================
FILE: convert/target_bus_assignment.mli
================================================
(* virt-v2v
* Copyright (C) 2009-2025 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.
*)
(** Assign fixed and removable disks to target buses.
Do this as best we can. This is not solvable for all guests,
but at least avoid overlapping disks (RHBZ#1238053). *)
val target_bus_assignment : Types.source_disk list -> Types.source_removable list -> Types.guestcaps -> Types.target_buses
================================================
gitextract_gtcdlbtn/
├── .github/
│ └── workflows/
│ └── main.yml
├── .gitignore
├── .gitmodules
├── COPYING
├── Makefile.am
├── README
├── TODO
├── bash/
│ ├── Makefile.am
│ ├── README
│ ├── test-complete-in-script.sh
│ └── virt-v2v
├── bugs-in-changelog.sh
├── check-mli.sh
├── common-rules.mk
├── config.sh.in
├── configure.ac
├── contrib/
│ └── remove-guestor.reg
├── convert/
│ ├── Makefile.am
│ ├── choose_root.ml
│ ├── choose_root.mli
│ ├── convert.ml
│ ├── convert.mli
│ ├── convert_linux.ml
│ ├── convert_linux.mli
│ ├── convert_types.ml
│ ├── convert_types.mli
│ ├── convert_windows.ml
│ ├── convert_windows.mli
│ ├── dummy.c
│ ├── mount_filesystems.ml
│ ├── mount_filesystems.mli
│ ├── target_bus_assignment.ml
│ └── target_bus_assignment.mli
├── docs/
│ ├── Makefile.am
│ ├── test-docs.sh
│ ├── virt-v2v-hacking.pod
│ ├── virt-v2v-input-vmware.pod
│ ├── virt-v2v-input-xen.pod
│ ├── virt-v2v-output-local.pod
│ ├── virt-v2v-output-openstack.pod
│ ├── virt-v2v-output-ovirt.pod
│ ├── virt-v2v-release-notes-1.42.pod
│ ├── virt-v2v-release-notes-2.0.pod
│ ├── virt-v2v-release-notes-2.10.pod
│ ├── virt-v2v-release-notes-2.2.pod
│ ├── virt-v2v-release-notes-2.4.pod
│ ├── virt-v2v-release-notes-2.6.pod
│ ├── virt-v2v-release-notes-2.8.pod
│ ├── virt-v2v-support.pod
│ ├── virt-v2v.pod
│ └── vm-generation-id-across-hypervisors.txt
├── gnulib/
│ └── lib/
│ ├── Makefile.am
│ ├── bitrotate.h
│ ├── c-ctype.h
│ ├── getprogname.h
│ ├── hash.c
│ ├── hash.h
│ ├── ignore-value.h
│ ├── xalloc-oversized.h
│ ├── xstrtol.c
│ ├── xstrtol.h
│ ├── xstrtoll.c
│ ├── xstrtoul.c
│ ├── xstrtoull.c
│ └── xstrtoumax.c
├── in-place/
│ ├── Makefile.am
│ ├── dummy.c
│ ├── in_place.ml
│ ├── in_place.mli
│ ├── test-docs.sh
│ └── virt-v2v-in-place.pod
├── input/
│ ├── Makefile.am
│ ├── OVA.ml
│ ├── OVA.mli
│ ├── OVF.ml
│ ├── OVF.mli
│ ├── VMX.ml
│ ├── VMX.mli
│ ├── dummy.c
│ ├── input.ml
│ ├── input.mli
│ ├── input_disk.ml
│ ├── input_disk.mli
│ ├── input_libvirt.ml
│ ├── input_libvirt.mli
│ ├── input_ova.ml
│ ├── input_ova.mli
│ ├── input_vcenter_https.ml
│ ├── input_vcenter_https.mli
│ ├── input_vddk.ml
│ ├── input_vddk.mli
│ ├── input_vmx.ml
│ ├── input_vmx.mli
│ ├── input_xen_ssh.ml
│ ├── input_xen_ssh.mli
│ ├── nbdkit_curl.ml
│ ├── nbdkit_curl.mli
│ ├── nbdkit_ssh.ml
│ ├── nbdkit_ssh.mli
│ ├── parse_domain_from_vmx.ml
│ ├── parse_domain_from_vmx.mli
│ ├── parse_libvirt_xml.ml
│ ├── parse_libvirt_xml.mli
│ ├── select_input.ml
│ ├── select_input.mli
│ ├── ssh.ml
│ ├── ssh.mli
│ ├── vCenter.ml
│ └── vCenter.mli
├── inspector/
│ ├── Makefile.am
│ ├── create_inspector_xml.ml
│ ├── create_inspector_xml.mli
│ ├── dummy.c
│ ├── inspector.ml
│ ├── inspector.mli
│ ├── test-docs.sh
│ └── virt-v2v-inspector.pod
├── installcheck.sh.in
├── lib/
│ ├── Makefile.am
│ ├── NBD_URI.ml
│ ├── NBD_URI.mli
│ ├── YAML.ml
│ ├── YAML.mli
│ ├── config.ml.in
│ ├── config.mli
│ ├── create_ovf.ml
│ ├── create_ovf.mli
│ ├── dummy.c
│ ├── guestfs-internal-all.h
│ ├── libvirt_utils.ml
│ ├── libvirt_utils.mli
│ ├── nbdkit.ml
│ ├── nbdkit.mli
│ ├── networks.ml
│ ├── networks.mli
│ ├── qemuNBD.ml
│ ├── qemuNBD.mli
│ ├── types.ml
│ ├── types.mli
│ ├── utils.ml
│ └── utils.mli
├── m4/
│ ├── guestfs-bash-completion.m4
│ ├── guestfs-c.m4
│ ├── guestfs-libraries.m4
│ ├── guestfs-ocaml-gettext.m4
│ ├── guestfs-ocaml.m4
│ ├── guestfs-perl.m4
│ ├── guestfs-progs.m4
│ └── ocaml.m4
├── ocaml-dep.sh.in
├── ocaml-link.sh.in
├── open/
│ ├── Makefile.am
│ ├── dummy.c
│ ├── open.ml
│ ├── open.mli
│ ├── test-docs.sh
│ └── virt-v2v-open.pod
├── output/
│ ├── Makefile.am
│ ├── changeuid.ml
│ ├── changeuid.mli
│ ├── create_kubevirt_yaml.ml
│ ├── create_kubevirt_yaml.mli
│ ├── create_libvirt_xml.ml
│ ├── create_libvirt_xml.mli
│ ├── embed.sh
│ ├── openstack_image_properties.ml
│ ├── openstack_image_properties.mli
│ ├── output.ml
│ ├── output.mli
│ ├── output_disk.ml
│ ├── output_disk.mli
│ ├── output_glance.ml
│ ├── output_glance.mli
│ ├── output_kubevirt.ml
│ ├── output_kubevirt.mli
│ ├── output_libvirt.ml
│ ├── output_libvirt.mli
│ ├── output_null.ml
│ ├── output_null.mli
│ ├── output_openstack.ml
│ ├── output_openstack.mli
│ ├── output_ovirt.ml
│ ├── output_ovirt.mli
│ ├── output_ovirt_upload.ml
│ ├── output_ovirt_upload.mli
│ ├── output_ovirt_upload_cancel_source.mli
│ ├── output_ovirt_upload_createvm_source.mli
│ ├── output_ovirt_upload_finalize_source.mli
│ ├── output_ovirt_upload_plugin_source.mli
│ ├── output_ovirt_upload_precheck_source.mli
│ ├── output_ovirt_upload_transfer_source.mli
│ ├── output_ovirt_upload_vmcheck_source.mli
│ ├── output_qemu.ml
│ ├── output_qemu.mli
│ ├── output_vdsm.ml
│ ├── output_vdsm.mli
│ ├── ovirt-upload-cancel.py
│ ├── ovirt-upload-createvm.py
│ ├── ovirt-upload-finalize.py
│ ├── ovirt-upload-plugin.py
│ ├── ovirt-upload-precheck.py
│ ├── ovirt-upload-transfer.py
│ ├── ovirt-upload-vmcheck.py
│ ├── python_script.ml
│ ├── python_script.mli
│ ├── qemuopts-c.c
│ ├── qemuopts.ml
│ ├── qemuopts.mli
│ ├── select_output.ml
│ ├── select_output.mli
│ └── test-python-syntax.sh
├── po/
│ ├── LINGUAS
│ ├── Makefile.am
│ ├── POTFILES
│ ├── POTFILES-ml
│ ├── cs.po
│ ├── de.po
│ ├── en_GB.po
│ ├── es.po
│ ├── eu.po
│ ├── fi.po
│ ├── fr.po
│ ├── gu.po
│ ├── hi.po
│ ├── id.po
│ ├── it.po
│ ├── ja.po
│ ├── ka.po
│ ├── kn.po
│ ├── ml.po
│ ├── mr.po
│ ├── nl.po
│ ├── or.po
│ ├── pa.po
│ ├── pl.po
│ ├── pt_BR.po
│ ├── ru.po
│ ├── si.po
│ ├── ta.po
│ ├── te.po
│ ├── tg.po
│ ├── uk.po
│ ├── virt-v2v.pot
│ └── zh_CN.po
├── po-docs/
│ ├── LINGUAS
│ ├── Makefile.am
│ ├── cs.po
│ ├── de.po
│ ├── en_GB.po
│ ├── es.po
│ ├── eu.po
│ ├── fi.po
│ ├── fr.po
│ ├── gu.po
│ ├── hi.po
│ ├── id.po
│ ├── it.po
│ ├── ja/
│ │ └── Makefile.am
│ ├── ja.po
│ ├── ka.po
│ ├── kn.po
│ ├── language.mk
│ ├── ml.po
│ ├── mr.po
│ ├── nl.po
│ ├── or.po
│ ├── pa.po
│ ├── pl.po
│ ├── podfiles
│ ├── pt_BR.po
│ ├── ru.po
│ ├── si.po
│ ├── ta.po
│ ├── te.po
│ ├── tg.po
│ ├── uk/
│ │ └── Makefile.am
│ ├── uk.po
│ ├── virt-v2v-docs.pot
│ └── zh_CN.po
├── podcheck.pl
├── podwrapper.pl.in
├── run.in
├── scripts/
│ └── git.orderfile
├── subdir-rules.mk
├── test-data/
│ ├── Makefile.am
│ ├── binaries/
│ │ ├── Makefile.am
│ │ ├── README
│ │ └── bin-x86_64-dynamic
│ ├── fake-virt-tools/
│ │ └── Makefile.am
│ ├── fake-virtio-win/
│ │ ├── Makefile.am
│ │ ├── virtio-win-drivers-list.txt
│ │ └── virtio-win-iso-list.txt
│ └── phony-guests/
│ ├── Makefile.am
│ ├── archlinux-package
│ ├── debian-packages
│ ├── debian-syslog
│ ├── fedora-db.sql.xz
│ ├── fedora-journal.tar.xz
│ ├── fedora.c
│ ├── guests.xml.in
│ ├── make-archlinux-img.sh
│ ├── make-coreos-img.sh
│ ├── make-debian-img.sh
│ ├── make-fedora-img.pl
│ ├── make-guests-all-good.pl
│ ├── make-ubuntu-img.sh
│ ├── make-windows-img.sh
│ ├── minimal-hive
│ ├── win10-software.reg
│ ├── win11-software.reg
│ ├── win2k22-software.reg
│ ├── win2k25-software.reg
│ ├── win7-32-software.reg
│ ├── windows-bcd.reg
│ ├── windows-software-all.reg
│ ├── windows-system.reg
│ └── winxp-32-software.reg
├── tests/
│ ├── Makefile.am
│ ├── functions.sh.in
│ ├── libvirt-is-version.c
│ ├── test-bad-networks-and-bridges.sh
│ ├── test-block-driver.sh
│ ├── test-cdrom.expected
│ ├── test-cdrom.sh
│ ├── test-cdrom.xml.in
│ ├── 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-floppy.xml.in
│ ├── test-i-disk-nbd.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-xml.sh
│ ├── test-in-place.sh
│ ├── test-inspector.sh
│ ├── test-it-vddk-io-query.sh
│ ├── test-mac-expected.xml
│ ├── test-mac.sh
│ ├── test-mac.xml.in
│ ├── test-machine-readable.sh
│ ├── test-networks-and-bridges-expected.xml
│ ├── test-networks-and-bridges.sh
│ ├── test-networks-and-bridges.xml.in
│ ├── test-no-fstrim.sh
│ ├── test-o-glance.sh
│ ├── test-o-kubevirt-fedora.sh
│ ├── test-o-kubevirt-fedora.yaml.expected
│ ├── test-o-kubevirt-oo-disk.sh
│ ├── 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-ovirt-upload-module/
│ │ ├── imageio.py
│ │ └── ovirtsdk4/
│ │ ├── __init__.py
│ │ └── types.py
│ ├── test-o-ovirt-upload-oo-query.sh
│ ├── test-o-ovirt-upload.sh
│ ├── test-o-ovirt.ovf.expected
│ ├── test-o-ovirt.sh
│ ├── test-o-qemu.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-open-encrypted.sh
│ ├── test-open.sh
│ ├── test-phony-win10-ls.txt
│ ├── test-phony-win11-ls.txt
│ ├── test-phony-win2k22-ls.txt
│ ├── test-phony-win2k25-ls.txt
│ ├── test-phony-win7-32-ls.txt
│ ├── test-phony-winxp-32-ls.txt
│ ├── test-print-source.expected
│ ├── test-print-source.sh
│ ├── test-print-source.xml.in
│ ├── test-reject-blank-disk.sh
│ ├── test-rhbz1232192.sh
│ ├── test-rhbz1232192.xml.in
│ ├── test-sound.sh
│ ├── test-sound.xml.in
│ ├── test-trim.sh
│ ├── test-virtio-win-iso.sh
│ ├── test-windows-conversion-ls.txt
│ ├── test-windows-conversion.sh
│ ├── test-windows-phony.sh
│ └── test-windows-uefi-conversion.sh
├── tmp/
│ └── .gitignore
├── v2v/
│ ├── Makefile.am
│ ├── dummy.c
│ ├── v2v.ml
│ ├── v2v.mli
│ └── v2v_unit_tests.ml
├── valgrind-suppressions
└── website/
├── easytoread.css
├── feed.css
├── index.css
├── index.html.in
├── pod.css
└── standard.css
SYMBOL INDEX (221 symbols across 19 files)
FILE: gnulib/lib/bitrotate.h
function rotl64 (line 37) | static inline uint64_t
function rotr64 (line 46) | static inline uint64_t
function rotl32 (line 56) | static inline uint32_t
function rotr32 (line 65) | static inline uint32_t
function rotl_sz (line 74) | static inline size_t
function rotr_sz (line 83) | static inline size_t
function rotl16 (line 94) | static inline uint16_t
function rotr16 (line 106) | static inline uint16_t
function rotl8 (line 118) | static inline uint8_t
function rotr8 (line 129) | static inline uint8_t
FILE: gnulib/lib/c-ctype.h
function c_isalnum (line 167) | static inline bool
function c_isalpha (line 181) | static inline bool
function c_isascii (line 196) | static inline bool
function c_isblank (line 213) | static inline bool
function c_iscntrl (line 219) | static inline bool
function c_isdigit (line 231) | static inline bool
function c_isgraph (line 243) | static inline bool
function c_islower (line 258) | static inline bool
function c_isprint (line 270) | static inline bool
function c_ispunct (line 286) | static inline bool
function c_isspace (line 298) | static inline bool
function c_isupper (line 310) | static inline bool
function c_isxdigit (line 322) | static inline bool
function c_tolower (line 335) | static inline int
function c_toupper (line 347) | static inline int
FILE: gnulib/lib/hash.c
type hash_entry (line 53) | struct hash_entry
type hash_table (line 59) | struct hash_table
function hash_get_n_buckets (line 148) | size_t
function hash_get_n_buckets_used (line 154) | size_t
function hash_get_n_entries (line 160) | size_t
function hash_get_max_bucket_length (line 166) | size_t
function hash_table_ok (line 190) | bool
function hash_print_statistics (line 219) | void
type hash_entry (line 238) | struct hash_entry
type hash_entry (line 250) | struct hash_entry
type hash_entry (line 251) | struct hash_entry
type hash_entry (line 268) | struct hash_entry
type hash_entry (line 283) | struct hash_entry
type hash_entry (line 284) | struct hash_entry
function hash_get_entries (line 305) | size_t
function hash_do_for_each (line 329) | size_t
function hash_string (line 363) | size_t
function hash_string (line 386) | size_t
function is_prime (line 402) | static bool
function next_prime (line 421) | static size_t
function hash_reset_tuning (line 437) | void
function raw_hasher (line 444) | static size_t
function raw_comparator (line 457) | static bool
function check_tuning (line 470) | static bool
function compute_bucket_size (line 502) | static size_t
function Hash_table (line 518) | Hash_table *
function hash_clear (line 573) | void
function hash_free (line 611) | void
type hash_entry (line 666) | struct hash_entry
type hash_entry (line 669) | struct hash_entry
function free_entry (line 691) | static void
type hash_entry (line 707) | struct hash_entry
type hash_entry (line 709) | struct hash_entry
type hash_entry (line 710) | struct hash_entry
type hash_entry (line 727) | struct hash_entry
type hash_entry (line 753) | struct hash_entry
function transfer_entries (line 775) | static bool
function hash_rehash (line 850) | bool
function hash_insert_if_absent (line 929) | int
type hash_entry (line 1025) | struct hash_entry
type hash_entry (line 1063) | struct hash_entry
type hash_entry (line 1064) | struct hash_entry
function hash_print (line 1091) | void
FILE: gnulib/lib/hash.h
type hash_tuning (line 41) | struct hash_tuning
type Hash_tuning (line 53) | typedef struct hash_tuning Hash_tuning;
type hash_table (line 55) | struct hash_table
type Hash_table (line 57) | typedef struct hash_table Hash_table;
FILE: gnulib/lib/xalloc-oversized.h
type __xalloc_count_type (line 41) | typedef ptrdiff_t __xalloc_count_type;
type __xalloc_count_type (line 43) | typedef size_t __xalloc_count_type;
FILE: gnulib/lib/xstrtol.c
function strtol_error (line 46) | static strtol_error
function strtol_error (line 63) | static strtol_error
function strtol_error (line 74) | strtol_error
FILE: gnulib/lib/xstrtol.h
type strtol_error (line 25) | enum strtol_error
type strtol_error (line 38) | typedef enum strtol_error strtol_error;
FILE: lib/guestfs-internal-all.h
function is_zero (line 98) | static inline int
type mountable_type_t (line 149) | typedef enum {
FILE: output/ovirt-upload-cancel.py
function debug (line 29) | def debug(s):
FILE: output/ovirt-upload-createvm.py
function debug (line 31) | def debug(s):
function jobs_completed (line 37) | def jobs_completed(system_service, correlation_id):
FILE: output/ovirt-upload-finalize.py
function debug (line 33) | def debug(s):
function finalize_transfer (line 39) | def finalize_transfer(connection, transfer_id, disk_id):
FILE: output/ovirt-upload-plugin.py
function config (line 65) | def config(key, value):
function config_complete (line 82) | def config_complete():
function after_fork (line 90) | def after_fork():
function cleanup (line 112) | def cleanup():
function thread_model (line 118) | def thread_model():
function open (line 126) | def open(readonly):
function can_trim (line 130) | def can_trim(h):
function can_flush (line 134) | def can_flush(h):
function can_fua (line 138) | def can_fua(h):
function can_multi_conn (line 143) | def can_multi_conn(h):
function get_size (line 150) | def get_size(h):
function request_failed (line 156) | def request_failed(r, msg):
function pread (line 178) | def pread(h, buf, offset, flags):
function pwrite (line 210) | def pwrite(h, buf, offset, flags):
function zero (line 238) | def zero(h, count, offset, flags):
function emulate_zero (line 269) | def emulate_zero(h, count, offset, flags):
function flush (line 297) | def flush(h, flags):
function send_flush (line 319) | def send_flush(http):
class UnixHTTPConnection (line 339) | class UnixHTTPConnection(HTTPConnection):
method __init__ (line 340) | def __init__(self, path, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
method connect (line 344) | def connect(self):
class PoolItem (line 351) | class PoolItem:
method __init__ (line 353) | def __init__(self, http):
function create_http_pool (line 359) | def create_http_pool(url, options):
function pool_keeper (line 377) | def pool_keeper():
function http_context (line 427) | def http_context(pool):
function close_http_pool (line 443) | def close_http_pool(pool):
function create_http (line 461) | def create_http(url, unix_socket=None):
function get_options (line 494) | def get_options(http, url):
FILE: output/ovirt-upload-transfer.py
function debug (line 35) | def debug(s):
function find_host (line 41) | def find_host(connection):
function create_disk (line 94) | def create_disk(connection):
function create_transfer (line 148) | def create_transfer(connection, disk, host):
function transfer_supports_format (line 219) | def transfer_supports_format():
function get_transfer_url (line 231) | def get_transfer_url(transfer):
FILE: output/qemuopts-c.c
function qopts_finalize (line 52) | static void
type custom_operations (line 61) | struct custom_operations
function value (line 71) | value
function value (line 89) | value
function value (line 101) | value
function value (line 119) | value
function value (line 131) | value
function value (line 143) | value
function value (line 156) | value
function value (line 179) | value
function value (line 191) | value
function value (line 203) | value
FILE: test-data/phony-guests/fedora.c
function add_str (line 38) | static void
function add_null (line 46) | static void
function add (line 52) | static void
function main (line 59) | int
FILE: tests/libvirt-is-version.c
function main (line 34) | int
function argtoint (line 67) | static unsigned int
FILE: tests/test-o-ovirt-upload-module/imageio.py
class RequestHandler (line 26) | class RequestHandler(BaseHTTPRequestHandler):
method do_OPTIONS (line 29) | def do_OPTIONS(self):
method do_PATCH (line 43) | def do_PATCH(self):
method do_PUT (line 50) | def do_PUT(self):
method discard_request (line 56) | def discard_request(self):
FILE: tests/test-o-ovirt-upload-module/ovirtsdk4/__init__.py
class Error (line 21) | class Error(Exception):
class NotFoundError (line 25) | class NotFoundError(Error):
class Connection (line 29) | class Connection(object):
method __init__ (line 30) | def __init__(
method close (line 42) | def close(self):
method follow_link (line 45) | def follow_link(self, objs):
method system_service (line 48) | def system_service(self):
class SystemService (line 52) | class SystemService(object):
method clusters_service (line 53) | def clusters_service(self):
method data_centers_service (line 56) | def data_centers_service(self):
method disks_service (line 59) | def disks_service(self):
method jobs_service (line 62) | def jobs_service(self):
method image_transfers_service (line 65) | def image_transfers_service(self):
method storage_domains_service (line 68) | def storage_domains_service(self):
method vms_service (line 71) | def vms_service(self):
class ClusterService (line 75) | class ClusterService(object):
method get (line 76) | def get(self):
class ClustersService (line 80) | class ClustersService(object):
method cluster_service (line 81) | def cluster_service(self, id):
class DataCentersService (line 85) | class DataCentersService(object):
method list (line 86) | def list(self, search=None, case_sensitive=False):
class DiskService (line 90) | class DiskService(object):
method __init__ (line 91) | def __init__(self, disk_id):
method get (line 94) | def get(self):
method remove (line 97) | def remove(self):
class DisksService (line 101) | class DisksService(object):
method add (line 102) | def add(self, disk=None):
method disk_service (line 106) | def disk_service(self, disk_id):
class JobsService (line 110) | class JobsService(object):
method list (line 111) | def list(self, search=None):
class ImageTransferService (line 115) | class ImageTransferService(object):
method __init__ (line 116) | def __init__(self):
method cancel (line 119) | def cancel(self):
method get (line 122) | def get(self):
method finalize (line 128) | def finalize(self):
class ImageTransfersService (line 132) | class ImageTransfersService(object):
method add (line 133) | def add(self, transfer):
method image_transfer_service (line 136) | def image_transfer_service(self, id):
class StorageDomainsService (line 140) | class StorageDomainsService(object):
method list (line 141) | def list(self, search=None, case_sensitive=False):
class VmsService (line 145) | class VmsService(object):
method add (line 146) | def add(self, vm, query=None):
method list (line 149) | def list(self, search=None):
FILE: tests/test-o-ovirt-upload-module/ovirtsdk4/types.py
class Architecture (line 28) | class Architecture(Enum):
method __init__ (line 32) | def __init__(self, arch):
method __str__ (line 35) | def __str__(self):
class Cpu (line 39) | class Cpu(object):
class Cluster (line 43) | class Cluster(object):
class Configuration (line 49) | class Configuration(object):
method __init__ (line 50) | def __init__(self, type=None, data=None):
class ConfigurationType (line 54) | class ConfigurationType(Enum):
method __init__ (line 58) | def __init__(self, image):
method __str__ (line 61) | def __str__(self):
class DiskFormat (line 65) | class DiskFormat(Enum):
method __init__ (line 69) | def __init__(self, image):
method __str__ (line 72) | def __str__(self):
class DiskStatus (line 76) | class DiskStatus(Enum):
method __init__ (line 81) | def __init__(self, image):
method __str__ (line 84) | def __str__(self):
class Disk (line 88) | class Disk(object):
method __init__ (line 89) | def __init__(
class ImageTransferPhase (line 105) | class ImageTransferPhase(Enum):
method __init__ (line 118) | def __init__(self, image):
method __str__ (line 121) | def __str__(self):
class ImageTransfer (line 125) | class ImageTransfer(object):
method __init__ (line 126) | def __init__(
class Initialization (line 139) | class Initialization(object):
method __init__ (line 140) | def __init__(self, configuration):
class JobStatus (line 144) | class JobStatus(Enum):
method __init__ (line 151) | def __init__(self, image):
method __str__ (line 154) | def __str__(self):
class Job (line 158) | class Job(object):
class StorageDomain (line 163) | class StorageDomain(object):
method __init__ (line 164) | def __init__(self, name=None):
class Vm (line 171) | class Vm(object):
method __init__ (line 172) | def __init__(
class DataCenter (line 180) | class DataCenter(object):
Copy disabled (too large)
Download .json
Condensed preview — 463 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (16,369K chars).
[
{
"path": ".github/workflows/main.yml",
"chars": 4203,
"preview": "# Run the jobs below on every push to master branch and pull request.\non:\n push:\n branches:\n - master\n - '"
},
{
"path": ".gitignore",
"chars": 2805,
"preview": "*~\n*.a\n*.annot\n*.bak\n*.class\n*.cma\n*.cmi\n*.cmo\n*.cmx\n*.cmxa\n*.diff\n*.eml\n*.hi\n*.jar\n*.la\n*.lo\n*.log\n*.o\n*.orig\n*.pyc\n*.r"
},
{
"path": ".gitmodules",
"chars": 91,
"preview": "[submodule \"common\"]\n\tpath = common\n\turl = https://github.com/libguestfs/libguestfs-common\n"
},
{
"path": "COPYING",
"chars": 18092,
"preview": " GNU GENERAL PUBLIC LICENSE\n Version 2, June 1991\n\n Copyright (C) 1989, 1991 Fr"
},
{
"path": "Makefile.am",
"chars": 5946,
"preview": "# libguestfs\n# Copyright (C) 2009-2025 Red Hat Inc.\n#\n# This program is free software; you can redistribute it and/or mo"
},
{
"path": "README",
"chars": 2122,
"preview": "Virt-v2v is a program that converts a single guest from a foreign\nhypervisor to run on KVM. It can read Linux and Windo"
},
{
"path": "TODO",
"chars": 1179,
"preview": "To-do list for virt-v2v\n======================================================================\n\nWe open the input NBD en"
},
{
"path": "bash/Makefile.am",
"chars": 1464,
"preview": "# libguestfs\n# Copyright (C) 2013-2025 Red Hat Inc.\n#\n# This program is free software; you can redistribute it and/or mo"
},
{
"path": "bash/README",
"chars": 269,
"preview": "This directory contains the scripts for tab-completing commands in\nbash. Note these new-style demand-loaded scripts req"
},
{
"path": "bash/test-complete-in-script.sh",
"chars": 1386,
"preview": "#!/bin/bash -\n# libguestfs bash completion test script\n# Copyright (C) 2016 Red Hat Inc.\n#\n# This program is free softwa"
},
{
"path": "bash/virt-v2v",
"chars": 1981,
"preview": "# virt-v2v bash completion script -*- shell-script -*-\n# Copyright (C) 2014 Red Hat Inc.\n#\n# This program is free softwa"
},
{
"path": "bugs-in-changelog.sh",
"chars": 2436,
"preview": "#!/bin/bash -\n# bugs-in-changelog.sh\n# Copyright (C) 2009-2025 Red Hat Inc.\n#\n# This program is free software; you can r"
},
{
"path": "check-mli.sh",
"chars": 1286,
"preview": "#!/bin/bash -\n# Check every .ml file has a corresponding .mli file.\n#\n# This program is free software; you can redistrib"
},
{
"path": "common-rules.mk",
"chars": 2023,
"preview": "# libguestfs\n# Copyright (C) 2013 Red Hat Inc.\n#\n# This program is free software; you can redistribute it and/or modify\n"
},
{
"path": "config.sh.in",
"chars": 896,
"preview": "#!/bin/bash -\n# (C) Copyright 2019 Red Hat Inc.\n# @configure_input@\n#\n# This program is free software; you can redistrib"
},
{
"path": "configure.ac",
"chars": 9159,
"preview": "# virt-v2v\n# Copyright (C) 2009-2026 Red Hat Inc.\n#\n# This program is free software; you can redistribute it and/or modi"
},
{
"path": "contrib/remove-guestor.reg",
"chars": 414,
"preview": "; Remove guestor registry entries\n; See virt-v2v(1) and https://issues.redhat.com/browse/MTV-2256\n\n[-HKEY_LOCAL_MACHINE\\"
},
{
"path": "convert/Makefile.am",
"chars": 3392,
"preview": "# helper-v2v-convert tool\n# Copyright (C) 2009-2025 Red Hat Inc.\n#\n# This program is free software; you can redistribute"
},
{
"path": "convert/choose_root.ml",
"chars": 3415,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "convert/choose_root.mli",
"chars": 1313,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "convert/convert.ml",
"chars": 17364,
"preview": "(* helper-v2v-convert\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute "
},
{
"path": "convert/convert.mli",
"chars": 1935,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "convert/convert_linux.ml",
"chars": 55441,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "convert/convert_linux.mli",
"chars": 1055,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "convert/convert_types.ml",
"chars": 1116,
"preview": "(* helper-v2v-convert\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute "
},
{
"path": "convert/convert_types.mli",
"chars": 1586,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "convert/convert_windows.ml",
"chars": 36348,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "convert/convert_windows.mli",
"chars": 928,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "convert/dummy.c",
"chars": 90,
"preview": "/* Dummy source, to be used for OCaml-based tools with no C sources. */\nenum { foo = 1 };\n"
},
{
"path": "convert/mount_filesystems.ml",
"chars": 9138,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "convert/mount_filesystems.mli",
"chars": 1154,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "convert/target_bus_assignment.ml",
"chars": 4680,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "convert/target_bus_assignment.mli",
"chars": 1082,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "docs/Makefile.am",
"chars": 8783,
"preview": "# libguestfs virt-v2v tool\n# Copyright (C) 2009-2025 Red Hat Inc.\n#\n# This program is free software; you can redistribut"
},
{
"path": "docs/test-docs.sh",
"chars": 1070,
"preview": "#!/bin/bash -\n# libguestfs\n# Copyright (C) 2016-2025 Red Hat Inc.\n#\n# This program is free software; you can redistribut"
},
{
"path": "docs/virt-v2v-hacking.pod",
"chars": 1602,
"preview": "=head1 NAME\n\nvirt-v2v-hacking - \n\n=head1 DESCRIPTION\n\nFirst a little history. Virt-v2v has been through at least two\nco"
},
{
"path": "docs/virt-v2v-input-vmware.pod",
"chars": 21824,
"preview": "=head1 NAME\n\nvirt-v2v-input-vmware - Using virt-v2v to convert guests from VMware\n\n=head1 SYNOPSIS\n\n virt-v2v -i vmx GUE"
},
{
"path": "docs/virt-v2v-input-xen.pod",
"chars": 5127,
"preview": "=head1 NAME\n\nvirt-v2v-input-xen - Using virt-v2v to convert guests from Xen\n\n=head1 SYNOPSIS\n\n virt-v2v -ic 'xen+ssh://r"
},
{
"path": "docs/virt-v2v-output-local.pod",
"chars": 3612,
"preview": "=head1 NAME\n\nvirt-v2v-output-local - Using virt-v2v to convert guests to local files\nor libvirt\n\n=head1 SYNOPSIS\n\n virt-"
},
{
"path": "docs/virt-v2v-output-openstack.pod",
"chars": 8192,
"preview": "=head1 NAME\n\nvirt-v2v-output-openstack - Using virt-v2v to convert guests to OpenStack\n\n=head1 SYNOPSIS\n\n virt-v2v [-i* "
},
{
"path": "docs/virt-v2v-output-ovirt.pod",
"chars": 7188,
"preview": "=head1 NAME\n\nvirt-v2v-output-ovirt - Using virt-v2v to convert guests to oVirt\n\n=head1 SYNOPSIS\n\n virt-v2v [-i* options]"
},
{
"path": "docs/virt-v2v-release-notes-1.42.pod",
"chars": 6957,
"preview": "=head1 NAME\n\nvirt-v2v-release-notes - virt-v2v release notes for 1.42\n\n=head1 DESCRIPTION\n\nThese are the release notes f"
},
{
"path": "docs/virt-v2v-release-notes-2.0.pod",
"chars": 12373,
"preview": "=head1 NAME\n\nvirt-v2v-release-notes - virt-v2v release notes for 2.0\n\n=head1 DESCRIPTION\n\nThese are the release notes fo"
},
{
"path": "docs/virt-v2v-release-notes-2.10.pod",
"chars": 7913,
"preview": "=head1 NAME\n\nvirt-v2v-release-notes - virt-v2v release notes for 2.10\n\n=head1 DESCRIPTION\n\nThese are the release notes f"
},
{
"path": "docs/virt-v2v-release-notes-2.2.pod",
"chars": 8925,
"preview": "=head1 NAME\n\nvirt-v2v-release-notes - virt-v2v release notes for 2.2\n\n=head1 DESCRIPTION\n\nThese are the release notes fo"
},
{
"path": "docs/virt-v2v-release-notes-2.4.pod",
"chars": 4900,
"preview": "=head1 NAME\n\nvirt-v2v-release-notes - virt-v2v release notes for 2.4\n\n=head1 DESCRIPTION\n\nThese are the release notes fo"
},
{
"path": "docs/virt-v2v-release-notes-2.6.pod",
"chars": 5529,
"preview": "=head1 NAME\n\nvirt-v2v-release-notes - virt-v2v release notes for 2.6\n\n=head1 DESCRIPTION\n\nThese are the release notes fo"
},
{
"path": "docs/virt-v2v-release-notes-2.8.pod",
"chars": 9745,
"preview": "=head1 NAME\n\nvirt-v2v-release-notes - virt-v2v release notes for 2.8\n\n=head1 DESCRIPTION\n\nThese are the release notes fo"
},
{
"path": "docs/virt-v2v-support.pod",
"chars": 2864,
"preview": "=head1 NAME\n\nvirt-v2v-support - Supported hypervisors, virtualization management\nsystems and guests in virt-v2v\n\n=head1 "
},
{
"path": "docs/virt-v2v.pod",
"chars": 64475,
"preview": "=head1 NAME\n\nvirt-v2v - Convert a guest to use KVM\n\n=head1 SYNOPSIS\n\n virt-v2v [-i mode] [other -i* options]\n ["
},
{
"path": "docs/vm-generation-id-across-hypervisors.txt",
"chars": 6855,
"preview": "VM Generation ID is a hypervisor feature which exposes a 128 bit (16 byte)\nrandom string of bytes to the guest. The gen"
},
{
"path": "gnulib/lib/Makefile.am",
"chars": 1301,
"preview": "# libguestfs\n# Copyright (C) 2017-2021 Red Hat Inc.\n#\n# This program is free software; you can redistribute it and/or mo"
},
{
"path": "gnulib/lib/bitrotate.h",
"chars": 4733,
"preview": "/* bitrotate.h - Rotate bits in integers\n Copyright (C) 2008-2021 Free Software Foundation, Inc.\n\n (NB: I modified t"
},
{
"path": "gnulib/lib/c-ctype.h",
"chars": 9647,
"preview": "/* Character handling in C locale.\n\n These functions work like the corresponding functions in <ctype.h>,\n except tha"
},
{
"path": "gnulib/lib/getprogname.h",
"chars": 1000,
"preview": "/* libguestfs\n * Copyright (C) 2013-2020 Red Hat Inc.\n *\n * This library is free software; you can redistribute it and/o"
},
{
"path": "gnulib/lib/hash.c",
"chars": 33124,
"preview": "/* hash - hashing table processing.\n\n Copyright (C) 1998-2004, 2006-2007, 2009-2021 Free Software Foundation, Inc.\n\n "
},
{
"path": "gnulib/lib/hash.h",
"chars": 11643,
"preview": "/* hash - hashing table processing.\n Copyright (C) 1998-1999, 2001, 2003, 2009-2021 Free Software Foundation,\n Inc.\n"
},
{
"path": "gnulib/lib/ignore-value.h",
"chars": 2617,
"preview": "/* ignore a function return without a compiler warning. -*- coding: utf-8 -*-\n\n Copyright (C) 2008-2021 Free Software"
},
{
"path": "gnulib/lib/xalloc-oversized.h",
"chars": 2692,
"preview": "/* xalloc-oversized.h -- memory allocation size checking\n\n Copyright (C) 1990-2000, 2003-2004, 2006-2021 Free Software"
},
{
"path": "gnulib/lib/xstrtol.c",
"chars": 6174,
"preview": "/* A more useful interface to strtol.\n\n Copyright (C) 1995-1996, 1998-2001, 2003-2007, 2009-2021 Free Software\n Foun"
},
{
"path": "gnulib/lib/xstrtol.h",
"chars": 1701,
"preview": "/* A more useful interface to strtol.\n\n Copyright (C) 1995-1996, 1998-1999, 2001-2004, 2006-2021 Free Software\n Foun"
},
{
"path": "gnulib/lib/xstrtoll.c",
"chars": 303,
"preview": "/* Note the license of this file is \"GPL\". It is used in the daemon\n * and in guestfish which have a compatible license"
},
{
"path": "gnulib/lib/xstrtoul.c",
"chars": 172,
"preview": "#define __strtol strtoul\n#define __strtol_t unsigned long int\n#define __xstrtol xstrtoul\n#define STRTOL_T_MINIMUM 0\n#def"
},
{
"path": "gnulib/lib/xstrtoull.c",
"chars": 180,
"preview": "#define __strtol strtoull\n#define __strtol_t unsigned long long int\n#define __xstrtol xstrtoull\n#define STRTOL_T_MINIMUM"
},
{
"path": "gnulib/lib/xstrtoumax.c",
"chars": 170,
"preview": "#define __strtol strtoumax\n#define __strtol_t uintmax_t\n#define __xstrtol xstrtoumax\n#define STRTOL_T_MINIMUM 0\n#define "
},
{
"path": "in-place/Makefile.am",
"chars": 4301,
"preview": "# libguestfs virt-v2v-in-place tool\n# Copyright (C) 2009-2025 Red Hat Inc.\n#\n# This program is free software; you can re"
},
{
"path": "in-place/dummy.c",
"chars": 90,
"preview": "/* Dummy source, to be used for OCaml-based tools with no C sources. */\nenum { foo = 1 };\n"
},
{
"path": "in-place/in_place.ml",
"chars": 14587,
"preview": "(* virt-v2v-in-place\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute i"
},
{
"path": "in-place/in_place.mli",
"chars": 848,
"preview": "(* virt-v2v-in-place\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute i"
},
{
"path": "in-place/test-docs.sh",
"chars": 1057,
"preview": "#!/bin/bash -\n# libguestfs\n# Copyright (C) 2016-2025 Red Hat Inc.\n#\n# This program is free software; you can redistribut"
},
{
"path": "in-place/virt-v2v-in-place.pod",
"chars": 10650,
"preview": "=head1 NAME\n\nvirt-v2v-in-place - Convert a guest to use KVM in-place\n\n=head1 SYNOPSIS\n\n virt-v2v-in-place -i disk [other"
},
{
"path": "input/Makefile.am",
"chars": 3529,
"preview": "# helper-v2v-input tool\n# Copyright (C) 2009-2025 Red Hat Inc.\n#\n# This program is free software; you can redistribute i"
},
{
"path": "input/OVA.ml",
"chars": 16374,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/OVA.mli",
"chars": 3136,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/OVF.ml",
"chars": 9953,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/OVF.mli",
"chars": 1585,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/VMX.ml",
"chars": 11401,
"preview": "(* virt-v2v\n * Copyright (C) 2017 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or modif"
},
{
"path": "input/VMX.mli",
"chars": 3370,
"preview": "(* virt-v2v\n * Copyright (C) 2017 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or modif"
},
{
"path": "input/dummy.c",
"chars": 90,
"preview": "/* Dummy source, to be used for OCaml-based tools with no C sources. */\nenum { foo = 1 };\n"
},
{
"path": "input/input.ml",
"chars": 1294,
"preview": "(* helper-v2v-input\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it"
},
{
"path": "input/input.mli",
"chars": 1929,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/input_disk.ml",
"chars": 6830,
"preview": "(* helper-v2v-input\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it"
},
{
"path": "input/input_disk.mli",
"chars": 832,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/input_libvirt.ml",
"chars": 8427,
"preview": "(* helper-v2v-input\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it"
},
{
"path": "input/input_libvirt.mli",
"chars": 892,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/input_ova.ml",
"chars": 8378,
"preview": "(* helper-v2v-input\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it"
},
{
"path": "input/input_ova.mli",
"chars": 830,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/input_vcenter_https.ml",
"chars": 4718,
"preview": "(* helper-v2v-input\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it"
},
{
"path": "input/input_vcenter_https.mli",
"chars": 849,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/input_vddk.ml",
"chars": 18891,
"preview": "(* helper-v2v-input\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it"
},
{
"path": "input/input_vddk.mli",
"chars": 848,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/input_vmx.ml",
"chars": 4953,
"preview": "(* helper-v2v-input\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it"
},
{
"path": "input/input_vmx.mli",
"chars": 830,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/input_xen_ssh.ml",
"chars": 4265,
"preview": "(* helper-v2v-input\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it"
},
{
"path": "input/input_xen_ssh.mli",
"chars": 837,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/nbdkit_curl.ml",
"chars": 3443,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/nbdkit_curl.mli",
"chars": 1433,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/nbdkit_ssh.ml",
"chars": 4326,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/nbdkit_ssh.mli",
"chars": 1624,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/parse_domain_from_vmx.ml",
"chars": 14620,
"preview": "(* virt-v2v\n * Copyright (C) 2017-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/parse_domain_from_vmx.mli",
"chars": 1239,
"preview": "(* virt-v2v\n * Copyright (C) 2017-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/parse_libvirt_xml.ml",
"chars": 21203,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/parse_libvirt_xml.mli",
"chars": 2322,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/select_input.ml",
"chars": 3680,
"preview": "(* helper-v2v-input\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it"
},
{
"path": "input/select_input.mli",
"chars": 1537,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/ssh.ml",
"chars": 2590,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/ssh.mli",
"chars": 1601,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/vCenter.ml",
"chars": 6505,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "input/vCenter.mli",
"chars": 1709,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "inspector/Makefile.am",
"chars": 4066,
"preview": "# libguestfs virt-v2v-inspector tool\n# Copyright (C) 2009-2025 Red Hat Inc.\n#\n# This program is free software; you can r"
},
{
"path": "inspector/create_inspector_xml.ml",
"chars": 5764,
"preview": "(* virt-v2v-inspector\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute "
},
{
"path": "inspector/create_inspector_xml.mli",
"chars": 1045,
"preview": "(* virt-v2v-in-place\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute i"
},
{
"path": "inspector/dummy.c",
"chars": 90,
"preview": "/* Dummy source, to be used for OCaml-based tools with no C sources. */\nenum { foo = 1 };\n"
},
{
"path": "inspector/inspector.ml",
"chars": 13238,
"preview": "(* virt-v2v-inspector\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute "
},
{
"path": "inspector/inspector.mli",
"chars": 850,
"preview": "(* virt-v2v-inspector\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute "
},
{
"path": "inspector/test-docs.sh",
"chars": 1005,
"preview": "#!/bin/bash -\n# libguestfs\n# Copyright (C) 2016 Red Hat Inc.\n#\n# This program is free software; you can redistribute it "
},
{
"path": "inspector/virt-v2v-inspector.pod",
"chars": 5798,
"preview": "=head1 NAME\n\nvirt-v2v-inspector - Estimate disk space needed before virt-v2v conversion\n\n=head1 SYNOPSIS\n\n virt-v2v-insp"
},
{
"path": "installcheck.sh.in",
"chars": 3780,
"preview": "#!/bin/bash\n# @configure_input@\n#\n# (C) Copyright 2015 Red Hat Inc.\n#\n# This program is free software; you can redistrib"
},
{
"path": "lib/Makefile.am",
"chars": 2985,
"preview": "# Library code used by virt-v2v and helpers.\n# Copyright (C) 2011-2025 Red Hat Inc.\n#\n# This program is free software; y"
},
{
"path": "lib/NBD_URI.ml",
"chars": 1204,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "lib/NBD_URI.mli",
"chars": 974,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "lib/YAML.ml",
"chars": 6323,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "lib/YAML.mli",
"chars": 1548,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "lib/config.ml.in",
"chars": 1270,
"preview": "(* virt-v2v\n * Copyright (C) 2019 Red Hat Inc.\n * @configure_input@\n *\n * This program is free software; you can redistr"
},
{
"path": "lib/config.mli",
"chars": 1909,
"preview": "(* virt-v2v\n * Copyright (C) 2019 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or modif"
},
{
"path": "lib/create_ovf.ml",
"chars": 37096,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "lib/create_ovf.mli",
"chars": 2769,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "lib/dummy.c",
"chars": 90,
"preview": "/* Dummy source, to be used for OCaml-based tools with no C sources. */\nenum { foo = 1 };\n"
},
{
"path": "lib/guestfs-internal-all.h",
"chars": 6346,
"preview": "/* libguestfs\n * Copyright (C) 2013-2025 Red Hat Inc.\n *\n * This library is free software; you can redistribute it and/o"
},
{
"path": "lib/libvirt_utils.ml",
"chars": 4245,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "lib/libvirt_utils.mli",
"chars": 2406,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "lib/nbdkit.ml",
"chars": 7610,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "lib/nbdkit.mli",
"chars": 4630,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "lib/networks.ml",
"chars": 3751,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "lib/networks.mli",
"chars": 1977,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "lib/qemuNBD.ml",
"chars": 4570,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "lib/qemuNBD.mli",
"chars": 2066,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "lib/types.ml",
"chars": 14990,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "lib/types.mli",
"chars": 15388,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "lib/utils.ml",
"chars": 8758,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "lib/utils.mli",
"chars": 4673,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "m4/guestfs-bash-completion.m4",
"chars": 1239,
"preview": "# libguestfs\n# Copyright (C) 2009-2025 Red Hat Inc.\n#\n# This program is free software; you can redistribute it and/or mo"
},
{
"path": "m4/guestfs-c.m4",
"chars": 3031,
"preview": "# libguestfs\n# Copyright (C) 2009-2025 Red Hat Inc.\n#\n# This program is free software; you can redistribute it and/or mo"
},
{
"path": "m4/guestfs-libraries.m4",
"chars": 4458,
"preview": "# virt-v2v\n# Copyright (C) 2009-2025 Red Hat Inc.\n#\n# This program is free software; you can redistribute it and/or modi"
},
{
"path": "m4/guestfs-ocaml-gettext.m4",
"chars": 2040,
"preview": "# libguestfs\n# Copyright (C) 2009-2025 Red Hat Inc.\n#\n# This program is free software; you can redistribute it and/or mo"
},
{
"path": "m4/guestfs-ocaml.m4",
"chars": 4335,
"preview": "# libguestfs\n# Copyright (C) 2009-2025 Red Hat Inc.\n#\n# This program is free software; you can redistribute it and/or mo"
},
{
"path": "m4/guestfs-perl.m4",
"chars": 2182,
"preview": "# libguestfs\n# Copyright (C) 2009-2025 Red Hat Inc.\n#\n# This program is free software; you can redistribute it and/or mo"
},
{
"path": "m4/guestfs-progs.m4",
"chars": 3687,
"preview": "# libguestfs\n# Copyright (C) 2009-2025 Red Hat Inc.\n#\n# This program is free software; you can redistribute it and/or mo"
},
{
"path": "m4/ocaml.m4",
"chars": 5552,
"preview": "dnl autoconf macros for OCaml\ndnl\ndnl Copyright © 2009 Richard W.M. Jones\ndnl Copyright © 2009 Stefano Zacchir"
},
{
"path": "ocaml-dep.sh.in",
"chars": 2859,
"preview": "#!/bin/bash -\n# (C) Copyright 2009-2025 Red Hat Inc.\n# @configure_input@\n#\n# This program is free software; you can redi"
},
{
"path": "ocaml-link.sh.in",
"chars": 2365,
"preview": "#!/bin/bash -\n# Script used to link OCaml programs.\n# @configure_input@\n# (C) Copyright 2015-2025 Red Hat Inc.\n#\n# This "
},
{
"path": "open/Makefile.am",
"chars": 3791,
"preview": "# libguestfs virt-v2v-open tool\n# Copyright (C) 2009-2025 Red Hat Inc.\n#\n# This program is free software; you can redist"
},
{
"path": "open/dummy.c",
"chars": 90,
"preview": "/* Dummy source, to be used for OCaml-based tools with no C sources. */\nenum { foo = 1 };\n"
},
{
"path": "open/open.ml",
"chars": 8423,
"preview": "(* virt-v2v-open\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it an"
},
{
"path": "open/open.mli",
"chars": 848,
"preview": "(* virt-v2v-open\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it an"
},
{
"path": "open/test-docs.sh",
"chars": 980,
"preview": "#!/bin/bash -\n# libguestfs\n# Copyright (C) 2016 Red Hat Inc.\n#\n# This program is free software; you can redistribute it "
},
{
"path": "open/virt-v2v-open.pod",
"chars": 3642,
"preview": "=head1 NAME\n\nvirt-v2v-open - Open the virt-v2v input and run a program on it\n\n=head1 SYNOPSIS\n\n virt-v2v-open [-i* optio"
},
{
"path": "output/Makefile.am",
"chars": 5845,
"preview": "# helper-v2v-output\n# Copyright (C) 2009-2025 Red Hat Inc.\n#\n# This program is free software; you can redistribute it an"
},
{
"path": "output/changeuid.ml",
"chars": 2291,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/changeuid.mli",
"chars": 2780,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/create_kubevirt_yaml.ml",
"chars": 8722,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/create_kubevirt_yaml.mli",
"chars": 1215,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/create_libvirt_xml.ml",
"chars": 14928,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/create_libvirt_xml.mli",
"chars": 1292,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/embed.sh",
"chars": 1384,
"preview": "#!/bin/bash -\n# Embed code or other content into an OCaml file.\n# Copyright (C) 2018 Red Hat Inc.\n#\n# This program is fr"
},
{
"path": "output/openstack_image_properties.ml",
"chars": 3112,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/openstack_image_properties.mli",
"chars": 1629,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output.ml",
"chars": 7984,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output.mli",
"chars": 5304,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_disk.ml",
"chars": 3760,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_disk.mli",
"chars": 836,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_glance.ml",
"chars": 5329,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_glance.mli",
"chars": 840,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_kubevirt.ml",
"chars": 5404,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_kubevirt.mli",
"chars": 844,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_libvirt.ml",
"chars": 9585,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_libvirt.mli",
"chars": 843,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_null.ml",
"chars": 2979,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_null.mli",
"chars": 836,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_openstack.ml",
"chars": 17388,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_openstack.mli",
"chars": 846,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_ovirt.ml",
"chars": 12313,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_ovirt.mli",
"chars": 838,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_ovirt_upload.ml",
"chars": 20455,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_ovirt_upload.mli",
"chars": 851,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_ovirt_upload_cancel_source.mli",
"chars": 790,
"preview": "(* virt-v2v\n * Copyright (C) 2019 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or modif"
},
{
"path": "output/output_ovirt_upload_createvm_source.mli",
"chars": 790,
"preview": "(* virt-v2v\n * Copyright (C) 2018 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or modif"
},
{
"path": "output/output_ovirt_upload_finalize_source.mli",
"chars": 790,
"preview": "(* virt-v2v\n * Copyright (C) 2019 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or modif"
},
{
"path": "output/output_ovirt_upload_plugin_source.mli",
"chars": 790,
"preview": "(* virt-v2v\n * Copyright (C) 2018 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or modif"
},
{
"path": "output/output_ovirt_upload_precheck_source.mli",
"chars": 790,
"preview": "(* virt-v2v\n * Copyright (C) 2019 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or modif"
},
{
"path": "output/output_ovirt_upload_transfer_source.mli",
"chars": 790,
"preview": "(* virt-v2v\n * Copyright (C) 2019 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or modif"
},
{
"path": "output/output_ovirt_upload_vmcheck_source.mli",
"chars": 790,
"preview": "(* virt-v2v\n * Copyright (C) 2018 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or modif"
},
{
"path": "output/output_qemu.ml",
"chars": 18387,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_qemu.mli",
"chars": 836,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_vdsm.ml",
"chars": 8652,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/output_vdsm.mli",
"chars": 836,
"preview": "(* virt-v2v\n * Copyright (C) 2009-2025 Red Hat Inc.\n *\n * This program is free software; you can redistribute it and/or "
},
{
"path": "output/ovirt-upload-cancel.py",
"chars": 3261,
"preview": "# -*- python -*-\n# oVirt upload cancel used by ‘virt-v2v -o ovirt-upload’\n# Copyright (C) 2019-2025 Red Hat Inc.\n#\n# Thi"
},
{
"path": "output/ovirt-upload-createvm.py",
"chars": 4379,
"preview": "# -*- python -*-\n# oVirt upload create VM used by ‘virt-v2v -o ovirt-upload’\n# Copyright (C) 2018 Red Hat Inc.\n#\n# This "
},
{
"path": "output/ovirt-upload-finalize.py",
"chars": 6467,
"preview": "# -*- python -*-\n# oVirt upload finalize used by ‘virt-v2v -o ovirt-upload’\n# Copyright (C) 2018-2025 Red Hat Inc.\n#\n# T"
},
{
"path": "output/ovirt-upload-plugin.py",
"chars": 15519,
"preview": "# -*- python -*-\n# oVirt upload nbdkit plugin used by ‘virt-v2v -o ovirt-upload’\n# Copyright (C) 2018-2025 Red Hat Inc.\n"
}
]
// ... and 263 more files (download for full content)
About this extraction
This page contains the full source code of the libguestfs/virt-v2v GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 463 files (14.4 MB), approximately 3.8M tokens, and a symbol index with 221 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.