=head1 NAME

p2v-hacking - extending and contributing to virt-p2v

=head1 DESCRIPTION

This manual page is for hackers who want to extend virt-p2v itself.

Virt-p2v is a front end on virt-v2v.  ie. All it does is act as a GUI
front end, and it calls out to virt-v2v to perform the actual
conversion.  Therefore most of the C code
is Gtk (GUI) code, or supporting code for talking to the remote
conversion server.  There is no special support for physical machines
in virt-v2v.  They are converted in the same way as foreign VMs.

=head1 THE SOURCE CODE

Virt-p2v source is located in the github repository
L<https://github.com/libguestfs/virt-p2v>

Virt-p2v uses an autotools-based build system, with the main files
being F<configure.ac> and F<Makefile.am>.  See L</THE BUILD SYSTEM>.

To build from source, first read the L<p2v-building(1)>.

=head2 SOURCE CODE SUBDIRECTORIES

The majority of the source code is directly in the top level directory
of the sources.  There are also some subdirectories that contain some
specific sub-parts of virt-p2v.

=over 4

=item F<bash>

Bash tab-completion scripts.

=item F<build-aux>

Various build scripts used by autotools.

=item F<miniexpect>

A copy of the miniexpect library from
L<http://git.annexia.org/?p=miniexpect.git;a=summary>.

=item F<contrib>

Outside contributions, experimental parts.

=item F<docs>

Miscellaneous manual pages.

=item F<libguestfs>

Some sources (mostly with utilities) copied from libguestfs.  Changes
to the sources there ought to be forwarded to libguestfs as well.

=item F<m4>

M4 macros used by autoconf.  See L</THE BUILD SYSTEM>.

=item F<website>

The virt-p2v files of the L<http://libguestfs.org> website.

=back

=head2 THE BUILD SYSTEM

Virt-p2v uses the GNU autotools build system (autoconf, automake).

The F<./configure> script is generated from F<configure.ac> and
F<m4/p2v-*.m4>.  Most of the configure script is split over many
m4 macro files by topic, for example F<m4/p2v-libraries.m4> deals
with the libraries required by virt-p2v.

F<subdir-rules.mk> is included in every F<Makefile.am> (top level and
subdirectories).

=head2 UNDERSTANDING THE CODE

I<See also:> L<virt-p2v(1)/HOW VIRT-P2V WORKS>

There are two paths through the code, GUI or non-GUI (parsing the
kernel command line):

 main.c ──────┬─────▶ gui.c ──────┬─────▶ conversion.c
              │                   │
              │                   │
              └────▶ kernel.c ────┘

but both paths call back to the F<conversion.c> function
C<start_conversion> to run the remote virt-v2v.

The main task of F<gui.c>/F<kernel.c> is to populate the virt-v2v
configuration (F<config.c>).

During conversion, we need to establish ssh connections, and that is
done using two libraries:

 conversion.c ──────▶ ssh.c ──────▶ miniexpect.c

where F<ssh.c> is responsible for managing ssh connections overall,
and F<miniexpect.c> implements "expect-like" functionality for talking
interactively to the remote virt-v2v conversion server.

(Note that miniexpect is a separate library with its own upstream, so
if you patch miniexpect.c, then please make sure the changes get
reflected in miniexpect’s upstream too:
F<http://git.annexia.org/?p=miniexpect.git;a=summary>)

=head1 RUNNING VIRT-P2V

You can run the F<virt-p2v> binary directly, but it will try to
convert your machine’s real F</dev/sda> which is unlikely to work
well.  However virt-p2v also has a test mode in which you can supply a
test disk:

 make run-virt-p2v-directly

This is a wrapper around the L<virt-p2v(1)> I<--test-disk> option.
You can control the "physical machine" disk by setting
C<PHYSICAL_MACHINE> to point to a disk image.

A more realistic test is to run virt-p2v inside a VM on the local
machine.  To do that, do:

 make run-virt-p2v-in-a-vm
 make run-virt-p2v-in-an-nvme-vm

These also run qemu with the "physical machine" disk (which you can
set by setting C<PHYSICAL_MACHINE>), a virtual CD, and a variety of
network cards for testing.  The second target exposes the "physical
machine" disk as an NVMe controller, plus adds two blank disks as
distinct namespaces of another NVMe controller.  You can change the
qemu binary and add extra qemu options by setting C<QEMU> and/or
C<QEMU_OPTIONS> on the make commandline.

A third way to run virt-p2v simulates fairly accurately the program
being downloaded over PXE and then doing an automatic conversion of
the source physical machine (the non-GUI path -- see next section
below):

 make run-virt-p2v-non-gui-conversion

=head1 EXTENDING VIRT-P2V

=head2 FORMATTING CODE

Our C source code generally adheres to some basic code-formatting
conventions.  The existing code base is not totally consistent on this
front, but we do prefer that contributed code be formatted similarly.
In short, use spaces-not-TABs for indentation, use 2 spaces for each
indentation level, and other than that, follow the K&R style.

If you use Emacs, add the following to one of your start-up files
(e.g., ~/.emacs), to help ensure that you get indentation right:

 ;;; In virt-p2v, indent with spaces everywhere (not TABs).
 ;;; Exceptions: Makefile and ChangeLog modes.
 (add-hook 'find-file-hook
     '(lambda () (if (and buffer-file-name
                          (string-match "/virt-p2v\\>"
                              (buffer-file-name))
                          (not (string-equal mode-name "Change Log"))
                          (not (string-equal mode-name "Makefile")))
                     (setq indent-tabs-mode nil))))
 
 ;;; When editing C sources in virt-p2v, use this style.
 (defun virt-p2v-c-mode ()
   "C mode with adjusted defaults for use with virt-p2v."
   (interactive)
   (c-set-style "K&R")
   (setq c-indent-level 2)
   (setq c-basic-offset 2))
 (add-hook 'c-mode-hook
           '(lambda () (if (string-match "/virt-p2v\\>"
                               (buffer-file-name))
                           (virt-p2v-c-mode))))

=head2 TESTING YOUR CHANGES

Turn warnings into errors when developing to make warnings hard to
ignore:

 ./configure --enable-werror

Useful targets are:

=over 4

=item C<make check>

Runs the regular test suite.

This is implemented using the regular automake C<TESTS> target.  See
the automake documentation for details.

=item C<make check-valgrind>

Runs a subset of the test suite under valgrind.

=item C<make check-slow>

Runs some slow/long-running tests which are not run by default.

To mark a test as slow/long-running:

=over 4

=item *

Add it to the list of C<TESTS> in the F<Makefile.am>, just like a
normal test.

=item *

Modify the test so it checks if the C<SLOW=1> environment variable is
set, and if I<not> set it skips (ie. returns with exit code 77).  If
using C<$TEST_FUNCTIONS>, you can call the function C<slow_test> for
this.

=item *

Add a variable C<SLOW_TESTS> to the F<Makefile.am> listing the slow
tests.

=item *

Add a rule to the F<Makefile.am>:

 check-slow:
   $(MAKE) check TESTS="$(SLOW_TESTS)" SLOW=1

=back

=back

=head2 VALGRIND

When you do C<make check-valgrind>, it searches for any F<Makefile.am>
in the tree that has a C<check-valgrind:> target and runs it.

Writing the F<Makefile.am> and tests correctly to use valgrind and
working with automake parallel tests is subtle.

If your tests are run via a shell script wrapper, then in the wrapper
use:

 $VG virt-foo

and in the F<Makefile.am> use:

 check-valgrind:
     make VG="@VG@" check

However, if your binaries run directly from the C<TESTS> rule, you
have to modify the F<Makefile.am> like this:

 LOG_COMPILER = $(VG)
 
 check-valgrind:
     make VG="@VG@" check

In either case, check that the right program is being tested by
examining the F<valgrind*> log files carefully.

=head2 SUBMITTING PATCHES

Submit patches to the mailing list:
L<http://www.redhat.com/mailman/listinfo/libguestfs>
and CC to L<rjones@redhat.com>.

You do not need to subscribe to the mailing list if you don’t want to.
There may be a short delay while your message is moderated.

=head1 SEE ALSO

L<p2v-building(1)>,
L<p2v-release-notes(1)>,
L<http://libguestfs.org/>.

=head1 AUTHORS

Richard W.M. Jones (C<rjones at redhat dot com>)

=head1 COPYRIGHT

Copyright (C) 2009-2019 Red Hat Inc.
