Remove remaining virt-p2v bits

Remove (almost) all the remaining bits related to virt-p2v.
This commit is contained in:
Pino Toscano
2019-07-10 18:45:44 +02:00
parent 2c02adb8ba
commit dea9636c59
20 changed files with 6 additions and 1420 deletions

4
.gitignore vendored
View File

@@ -64,9 +64,6 @@ Makefile.in
/bash/virt-inspector
/bash/virt-log
/bash/virt-ls
/bash/virt-p2v-make-disk
/bash/virt-p2v-make-kickstart
/bash/virt-p2v-make-kiwi
/bash/virt-resize
/bash/virt-sysprep
/bash/virt-sparsify
@@ -129,7 +126,6 @@ Makefile.in
/common/errnostring/errnostring-gperf.c
/common/errnostring/errnostring-gperf.gperf
/common/errnostring/errnostring.h
/common/miniexpect/miniexpect.3
/common/mlaugeas/.depend
/common/mlgettext/.depend
/common/mlgettext/common_gettext.ml

View File

@@ -328,7 +328,7 @@ ChangeLog: configure.ac
docs/C_SOURCE_FILES: configure.ac
rm -f $@ $@-t
find $(DIST_SUBDIRS) -name '*.[ch]' | \
grep -v -E '^(builder/index-parse\.|builder/index-scan\.|common/mllibvirt/libvirt_c\.c|examples/|gnulib/|gobject/|java/com_redhat_et_libguestfs|perl/|p2v/|php/extension/config\.h|ruby/ext/guestfs/extconf\.h|tests/|test-data/)' | \
grep -v -E '^(builder/index-parse\.|builder/index-scan\.|common/mllibvirt/libvirt_c\.c|examples/|gnulib/|gobject/|java/com_redhat_et_libguestfs|perl/|php/extension/config\.h|ruby/ext/guestfs/extconf\.h|tests/|test-data/)' | \
grep -v -E '/(guestfs|rc)_protocol\.' | \
grep -v -E '.*/errnostring\.' | \
grep -v -E '.*-gperf\.' | \
@@ -340,7 +340,7 @@ po/POTFILES: configure.ac
rm -f $@ $@-t
cd $(srcdir); \
find $(DIST_SUBDIRS) -name '*.c' -o -name '*.pl' -o -name '*.pm' | \
grep -v -E '^(examples|gnulib|perl/(blib|examples)|p2v|po-docs|tests|test-data)/' | \
grep -v -E '^(examples|gnulib|perl/(blib|examples)|po-docs|tests|test-data)/' | \
grep -v -E '/((guestfs|rc)_protocol\.c)$$' | \
grep -v -E '^python/utils\.c$$' | \
grep -v -E '^perl/lib/Sys/Guestfs\.c$$' | \

View File

@@ -44,9 +44,6 @@ symlinks = \
virt-inspector \
virt-log \
virt-ls \
virt-p2v-make-disk \
virt-p2v-make-kickstart \
virt-p2v-make-kiwi \
virt-resize \
virt-sparsify \
virt-sysprep \
@@ -79,7 +76,6 @@ guestunmount \
virt-builder virt-cat virt-customize virt-df virt-dib virt-diff \
virt-edit virt-filesystems virt-format virt-get-kernel virt-inspector \
virt-log virt-ls \
virt-p2v-make-disk virt-p2v-make-kickstart virt-p2v-make-kiwi \
virt-resize virt-sparsify virt-sysprep \
virt-tail:
rm -f $@

View File

@@ -169,24 +169,6 @@ _virt_ls ()
} &&
complete -o default -F _virt_ls virt-ls
_virt_p2v_make_disk ()
{
_guestfs_virttools "virt-p2v-make-disk" 1
} &&
complete -o default -F _virt_p2v_make_disk virt-p2v-make-disk
_virt_p2v_make_kickstart ()
{
_guestfs_virttools "virt-p2v-make-kickstart" 1
} &&
complete -o default -F _virt_p2v_make_kickstart virt-p2v-make-kickstart
_virt_p2v_make_kiwi ()
{
_guestfs_virttools "virt-p2v-make-kiwi" 1
} &&
complete -o default -F _virt_p2v_make_kiwi virt-p2v-make-kiwi
_virt_resize ()
{
_guestfs_virttools "virt-resize" 0

View File

@@ -1,51 +0,0 @@
# libguestfs virt-p2v
# Copyright (C) 2009-2019 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# This directory contains a copy of the miniexpect library from
# http://git.annexia.org/?p=miniexpect.git;a=summary
# This is used in virt-p2v.
include $(top_srcdir)/subdir-rules.mk
EXTRA_DIST = \
miniexpect.pod \
README
noinst_LTLIBRARIES = libminiexpect.la
libminiexpect_la_SOURCES = \
miniexpect.c \
miniexpect.h
libminiexpect_la_CFLAGS = \
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
$(PCRE_CFLAGS)
libminiexpect_la_LIBADD = \
$(PCRE_LIBS)
# It should be noinst_MANS but that doesn't work.
noinst_DATA = miniexpect.3
# podwrapper cannot parse this page because it's not in the POD format
# expected by libguestfs. Just use pod2man, but don't fail if we
# can't generate it.
miniexpect.3: miniexpect.pod
rm -f $@ $@-t
-pod2man --utf8 --stderr \
--center=miniexpect --release=miniexpect --name=miniexpect \
--section=3 \
$< $@-t
mv $@-t $@ || touch $@

View File

@@ -1,31 +0,0 @@
miniexpect is a very simple expect-like library for C.
It has a saner interface than libexpect, and doesn't depend on Tcl.
It is also thread safe, const-correct and uses modern C standards.
It is standalone, except that it requires the PCRE (Perl Compatible
Regular Expressions) library from http://www.pcre.org/. The PCRE
dependency is fundamental because we want to offer the most powerful
regular expression syntax to match on, but more importantly because
PCRE has a convenient way to detect partial matches which made this
library very simple to implement.
License
-------
The library was written by Richard W.M. Jones <rjones@redhat.com>
and is licensed under the Library GPL (LGPL) version 2 or above.
Source is available from: http://git.annexia.org/?p=miniexpect.git;a=summary
Using the library
-----------------
If you wanted to copy the library into your own code (instead of
linking to it as a dependency), you only need to copy the two files:
miniexpect.h, miniexpect.c.
The API is documented in the manual page (miniexpect.pod / miniexpect.3).
For examples of how to use the API in reality, see the examples and
tests in the source directory.

View File

@@ -1,489 +0,0 @@
/* miniexpect
* Copyright (C) 2014 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <poll.h>
#include <errno.h>
#include <termios.h>
#include <time.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <pcre.h>
/* RHEL 6 pcre did not define PCRE_PARTIAL_SOFT. However PCRE_PARTIAL
* is a synonym so use that.
*/
#ifndef PCRE_PARTIAL_SOFT
#define PCRE_PARTIAL_SOFT PCRE_PARTIAL
#endif
#include "miniexpect.h"
static void debug_buffer (FILE *, const char *);
static mexp_h *
create_handle (void)
{
mexp_h *h = malloc (sizeof *h);
if (h == NULL)
return NULL;
/* Initialize the fields to default values. */
h->fd = -1;
h->pid = 0;
h->timeout = 60000;
h->read_size = 1024;
h->pcre_error = 0;
h->buffer = NULL;
h->len = h->alloc = 0;
h->next_match = -1;
h->debug_fp = NULL;
h->user1 = h->user2 = h->user3 = NULL;
return h;
}
static void
clear_buffer (mexp_h *h)
{
free (h->buffer);
h->buffer = NULL;
h->alloc = h->len = 0;
h->next_match = -1;
}
int
mexp_close (mexp_h *h)
{
int status = 0;
free (h->buffer);
if (h->fd >= 0)
close (h->fd);
if (h->pid > 0) {
if (waitpid (h->pid, &status, 0) == -1)
return -1;
}
free (h);
return status;
}
mexp_h *
mexp_spawnlf (unsigned flags, const char *file, const char *arg, ...)
{
char **argv, **new_argv;
size_t i;
va_list args;
mexp_h *h;
argv = malloc (sizeof (char *));
if (argv == NULL)
return NULL;
argv[0] = (char *) arg;
va_start (args, arg);
for (i = 1; arg != NULL; ++i) {
arg = va_arg (args, const char *);
new_argv = realloc (argv, sizeof (char *) * (i+1));
if (new_argv == NULL) {
free (argv);
va_end (args);
return NULL;
}
argv = new_argv;
argv[i] = (char *) arg;
}
h = mexp_spawnvf (flags, file, argv);
free (argv);
va_end (args);
return h;
}
mexp_h *
mexp_spawnvf (unsigned flags, const char *file, char **argv)
{
mexp_h *h = NULL;
int fd = -1;
int err;
char slave[1024];
pid_t pid = 0;
fd = posix_openpt (O_RDWR|O_NOCTTY);
if (fd == -1)
goto error;
if (grantpt (fd) == -1)
goto error;
if (unlockpt (fd) == -1)
goto error;
/* Get the slave pty name now, but don't open it in the parent. */
if (ptsname_r (fd, slave, sizeof slave) != 0)
goto error;
/* Create the handle last before we fork. */
h = create_handle ();
if (h == NULL)
goto error;
pid = fork ();
if (pid == -1)
goto error;
if (pid == 0) { /* Child. */
int slave_fd;
if (!(flags & MEXP_SPAWN_KEEP_SIGNALS)) {
struct sigaction sa;
int i;
/* Remove all signal handlers. See the justification here:
* https://www.redhat.com/archives/libvir-list/2008-August/msg00303.html
* We don't mask signal handlers yet, so this isn't completely
* race-free, but better than not doing it at all.
*/
memset (&sa, 0, sizeof sa);
sa.sa_handler = SIG_DFL;
sa.sa_flags = 0;
sigemptyset (&sa.sa_mask);
for (i = 1; i < NSIG; ++i)
sigaction (i, &sa, NULL);
}
setsid ();
/* Open the slave side of the pty. We must do this in the child
* after setsid so it becomes our controlling tty.
*/
slave_fd = open (slave, O_RDWR);
if (slave_fd == -1)
goto error;
if (!(flags & MEXP_SPAWN_COOKED_MODE)) {
struct termios termios;
/* Set raw mode. */
tcgetattr (slave_fd, &termios);
cfmakeraw (&termios);
tcsetattr (slave_fd, TCSANOW, &termios);
}
/* Set up stdin, stdout, stderr to point to the pty. */
dup2 (slave_fd, 0);
dup2 (slave_fd, 1);
dup2 (slave_fd, 2);
close (slave_fd);
/* Close the master side of the pty - do this late to avoid a
* kernel bug, see sshpass source code.
*/
close (fd);
if (!(flags & MEXP_SPAWN_KEEP_FDS)) {
int i, max_fd;
/* Close all other file descriptors. This ensures that we don't
* hold open (eg) pipes from the parent process.
*/
max_fd = sysconf (_SC_OPEN_MAX);
if (max_fd == -1)
max_fd = 1024;
if (max_fd > 65536)
max_fd = 65536; /* bound the amount of work we do here */
for (i = 3; i < max_fd; ++i)
close (i);
}
/* Run the subprocess. */
execvp (file, argv);
perror (file);
_exit (EXIT_FAILURE);
}
/* Parent. */
h->fd = fd;
h->pid = pid;
return h;
error:
err = errno;
if (fd >= 0)
close (fd);
if (pid > 0)
waitpid (pid, NULL, 0);
if (h != NULL)
mexp_close (h);
errno = err;
return NULL;
}
enum mexp_status
mexp_expect (mexp_h *h, const mexp_regexp *regexps, int *ovector, int ovecsize)
{
time_t start_t, now_t;
int timeout;
struct pollfd pfds[1];
int r;
ssize_t rs;
time (&start_t);
if (h->next_match == -1) {
/* Fully clear the buffer, then read. */
clear_buffer (h);
} else {
/* See the comment in the manual about h->next_match. We have
* some data remaining in the buffer, so begin by matching that.
*/
memmove (&h->buffer[0], &h->buffer[h->next_match], h->len - h->next_match);
h->len -= h->next_match;
h->buffer[h->len] = '\0';
h->next_match = -1;
goto try_match;
}
for (;;) {
/* If we've got a timeout then work out how many seconds are left.
* Timeout == 0 is not particularly well-defined, but it probably
* means "return immediately if there's no data to be read".
*/
if (h->timeout >= 0) {
time (&now_t);
timeout = h->timeout - ((now_t - start_t) * 1000);
if (timeout < 0)
timeout = 0;
}
else
timeout = 0;
pfds[0].fd = h->fd;
pfds[0].events = POLLIN;
pfds[0].revents = 0;
r = poll (pfds, 1, timeout);
if (h->debug_fp)
fprintf (h->debug_fp, "DEBUG: poll returned %d\n", r);
if (r == -1)
return MEXP_ERROR;
if (r == 0)
return MEXP_TIMEOUT;
/* Otherwise we expect there is something to read from the file
* descriptor.
*/
if (h->alloc - h->len <= h->read_size) {
char *new_buffer;
/* +1 here allows us to store \0 after the data read */
new_buffer = realloc (h->buffer, h->alloc + h->read_size + 1);
if (new_buffer == NULL)
return MEXP_ERROR;
h->buffer = new_buffer;
h->alloc += h->read_size;
}
rs = read (h->fd, h->buffer + h->len, h->read_size);
if (h->debug_fp)
fprintf (h->debug_fp, "DEBUG: read returned %zd\n", rs);
if (rs == -1) {
/* Annoyingly on Linux (I'm fairly sure this is a bug) if the
* writer closes the connection, the entire pty is destroyed,
* and read returns -1 / EIO. Handle that special case here.
*/
if (errno == EIO)
return MEXP_EOF;
return MEXP_ERROR;
}
if (rs == 0)
return MEXP_EOF;
/* We read something. */
h->len += rs;
h->buffer[h->len] = '\0';
if (h->debug_fp) {
fprintf (h->debug_fp, "DEBUG: read %zd bytes from pty\n", rs);
fprintf (h->debug_fp, "DEBUG: buffer content: ");
debug_buffer (h->debug_fp, h->buffer);
fprintf (h->debug_fp, "\n");
}
try_match:
/* See if there is a full or partial match against any regexp. */
if (regexps) {
size_t i;
int can_clear_buffer = 1;
assert (h->buffer != NULL);
for (i = 0; regexps[i].r > 0; ++i) {
const int options = regexps[i].options | PCRE_PARTIAL_SOFT;
r = pcre_exec (regexps[i].re, regexps[i].extra,
h->buffer, (int)h->len, 0,
options,
ovector, ovecsize);
h->pcre_error = r;
if (r >= 0) {
/* A full match. */
if (ovector != NULL && ovecsize >= 1 && ovector[1] >= 0)
h->next_match = ovector[1];
else
h->next_match = -1;
return regexps[i].r;
}
else if (r == PCRE_ERROR_NOMATCH) {
/* No match at all. */
/* (nothing here) */
}
else if (r == PCRE_ERROR_PARTIAL) {
/* Partial match. Keep the buffer and keep reading. */
can_clear_buffer = 0;
}
else {
/* An actual PCRE error. */
return MEXP_PCRE_ERROR;
}
}
/* If none of the regular expressions matched (not partially)
* then we can clear the buffer. This is an optimization.
*/
if (can_clear_buffer)
clear_buffer (h);
} /* if (regexps) */
}
}
static int mexp_vprintf (mexp_h *h, int password, const char *fs, va_list args)
__attribute__((format(printf,3,0)));
static int
mexp_vprintf (mexp_h *h, int password, const char *fs, va_list args)
{
char *msg;
int len;
size_t n;
ssize_t r;
char *p;
len = vasprintf (&msg, fs, args);
if (len < 0)
return -1;
if (h->debug_fp) {
if (!password) {
fprintf (h->debug_fp, "DEBUG: writing: ");
debug_buffer (h->debug_fp, msg);
fprintf (h->debug_fp, "\n");
}
else
fprintf (h->debug_fp, "DEBUG: writing the password\n");
}
n = len;
p = msg;
while (n > 0) {
r = write (h->fd, p, n);
if (r == -1) {
free (msg);
return -1;
}
n -= r;
p += r;
}
free (msg);
return len;
}
int
mexp_printf (mexp_h *h, const char *fs, ...)
{
int r;
va_list args;
va_start (args, fs);
r = mexp_vprintf (h, 0, fs, args);
va_end (args);
return r;
}
int
mexp_printf_password (mexp_h *h, const char *fs, ...)
{
int r;
va_list args;
va_start (args, fs);
r = mexp_vprintf (h, 1, fs, args);
va_end (args);
return r;
}
int
mexp_send_interrupt (mexp_h *h)
{
return write (h->fd, "\003", 1);
}
/* Print escaped buffer to fp. */
static void
debug_buffer (FILE *fp, const char *buf)
{
while (*buf) {
if (isprint (*buf))
fputc (*buf, fp);
else {
switch (*buf) {
case '\0': fputs ("\\0", fp); break;
case '\a': fputs ("\\a", fp); break;
case '\b': fputs ("\\b", fp); break;
case '\f': fputs ("\\f", fp); break;
case '\n': fputs ("\\n", fp); break;
case '\r': fputs ("\\r", fp); break;
case '\t': fputs ("\\t", fp); break;
case '\v': fputs ("\\v", fp); break;
default:
fprintf (fp, "\\x%x", (unsigned char) *buf);
}
}
buf++;
}
}

View File

@@ -1,110 +0,0 @@
/* miniexpect
* Copyright (C) 2014 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* ** NOTE ** All API documentation is in the manual page.
*
* To read the manual page from the source directory, do:
* man ./miniexpect.3
* If you have installed miniexpect, do:
* man 3 miniexpect
*
* The source for the manual page is miniexpect.pod.
*/
#ifndef MINIEXPECT_H_
#define MINIEXPECT_H_
#include <stdio.h>
#include <unistd.h>
#include <pcre.h>
/* This handle is created per subprocess that is spawned. */
struct mexp_h {
int fd;
pid_t pid;
int timeout;
char *buffer;
size_t len;
size_t alloc;
ssize_t next_match;
size_t read_size;
int pcre_error;
FILE *debug_fp;
void *user1;
void *user2;
void *user3;
};
typedef struct mexp_h mexp_h;
/* Methods to access (some) fields in the handle. */
#define mexp_get_fd(h) ((h)->fd)
#define mexp_get_pid(h) ((h)->pid)
#define mexp_get_timeout_ms(h) ((h)->timeout)
#define mexp_set_timeout_ms(h, ms) ((h)->timeout = (ms))
/* If secs == -1, then this sets h->timeout to -1000, but the main
* code handles this since it only checks for h->timeout < 0.
*/
#define mexp_set_timeout(h, secs) ((h)->timeout = 1000 * (secs))
#define mexp_get_read_size(h) ((h)->read_size)
#define mexp_set_read_size(h, size) ((h)->read_size = (size))
#define mexp_get_pcre_error(h) ((h)->pcre_error)
#define mexp_set_debug_file(h, fp) ((h)->debug_fp = (fp))
#define mexp_get_debug_file(h) ((h)->debug_fp)
/* Spawn a subprocess. */
extern mexp_h *mexp_spawnvf (unsigned flags, const char *file, char **argv);
extern mexp_h *mexp_spawnlf (unsigned flags, const char *file, const char *arg, ...);
#define mexp_spawnv(file,argv) mexp_spawnvf (0, (file), (argv))
#define mexp_spawnl(file,...) mexp_spawnlf (0, (file), __VA_ARGS__)
#define MEXP_SPAWN_KEEP_SIGNALS 1
#define MEXP_SPAWN_KEEP_FDS 2
#define MEXP_SPAWN_COOKED_MODE 4
#define MEXP_SPAWN_RAW_MODE 0
/* Close the handle. */
extern int mexp_close (mexp_h *h);
/* Expect. */
struct mexp_regexp {
int r;
const pcre *re;
const pcre_extra *extra;
int options;
};
typedef struct mexp_regexp mexp_regexp;
enum mexp_status {
MEXP_EOF = 0,
MEXP_ERROR = -1,
MEXP_PCRE_ERROR = -2,
MEXP_TIMEOUT = -3,
};
extern int mexp_expect (mexp_h *h, const mexp_regexp *regexps,
int *ovector, int ovecsize);
/* Sending commands, keypresses. */
extern int mexp_printf (mexp_h *h, const char *fs, ...)
__attribute__((format(printf,2,3)));
extern int mexp_printf_password (mexp_h *h, const char *fs, ...)
__attribute__((format(printf,2,3)));
extern int mexp_send_interrupt (mexp_h *h);
#endif /* MINIEXPECT_H_ */

View File

@@ -1,496 +0,0 @@
=encoding utf8
=head1 NAME
miniexpect - A very simple expect library for C.
=head1 SYNOPSIS
#include <errno.h>
#include <sys/wait.h>
#include <pcre.h>
#include <miniexpect.h>
mexp_h *h;
h = mexp_spawnl ("ssh", "ssh", "host", NULL);
switch (mexp_expect (h, regexps, ovector, ovecsize)) {
...
}
mexp_close (h);
cc prog.c -o prog -lminiexpect -lpcre
=head1 DESCRIPTION
Miniexpect is a very simple expect-like library for C. Expect is a
way to control an external program that wants to be run interactively.
Miniexpect has a saner interface than libexpect, and doesn't depend on
Tcl. It is also thread safe, const-correct and uses modern C
standards.
Miniexpect is a standalone library, except for a single dependency: it
requires the PCRE (Perl Compatible Regular Expressions) library from
L<http://www.pcre.org/>. The PCRE dependency is fundamental because
we want to offer the most powerful regular expression syntax to match
on, but more importantly because PCRE has a convenient way to detect
partial matches which made this library very simple to implement.
This manual page documents the API. Examples of how to use the API
can be found in the source directory.
=head1 CONCEPTS
Miniexpect lets you start up an external program, control it (by
sending commands to it), and close it down gracefully. Two things
make this different from other APIs like L<popen(3)> and L<system(3)>:
Firstly miniexpect creates a pseudoterminal (pty). Secondly
miniexpect lets you match the output of the program using regular
expressions. Both of these are handy for controlling interactive
programs that might (for example) ask for passwords, but you can use
miniexpect on just about any external program.
You can control multiple programs at the same time.
=head1 SPAWNING THE SUBPROCESS
There are four calls for creating a subprocess:
B<mexp_h *mexp_spawnl (const char *file, const char *arg, ...);>
This creates a subprocess running the external program C<file> (the
current C<$PATH> is searched unless you give an absolute path).
C<arg, ...> are the arguments to the program. You should terminate
the list of arguments with C<NULL>. Usually the first argument should
be the name of the program.
The return value is a handle (see next section).
If there was an error running the subprocess, C<NULL> is returned and
the error is available in C<errno>.
For example, to run an ssh subprocess you could do:
h = mexp_spawnl ("ssh", "ssh", "-l", "root", "host", NULL);
or to run a particular ssh binary:
h = mexp_spawnl ("/usr/local/bin/ssh", "ssh", "-l", "root", "host", NULL);
An alternative to C<mexp_spawnl> is:
B<mexp_h *mexp_spawnv (const char *file, char **argv);>
This is the same as C<mexp_spawnl> except that you pass the arguments
in a NULL-terminated array.
There are also two versions of the above calls which take flags:
B<mexp_h *mexp_spawnlf (unsigned flags, const char *file, const char *arg, ...);>
B<mexp_h *mexp_spawnvf (unsigned flags, const char *file, char **argv);>
The flags may contain the following values, logically ORed together:
=over 4
=item B<MEXP_SPAWN_KEEP_SIGNALS>
Do not reset signal handlers to C<SIG_DFL> in the subprocess.
=item B<MEXP_SPAWN_KEEP_FDS>
Do not close file descriptors E<ge> 3 in the subprocess.
=item B<MEXP_SPAWN_COOKED_MODE> or B<MEXP_SPAWN_RAW_MODE>
Configure the pty in cooked mode or raw mode. Raw mode is the
default.
=back
=head1 HANDLES
After spawning a subprocess, you get back a handle which is a pointer
to a struct:
struct mexp_h;
typedef struct mexp_h mexp_h;
Various methods can be used on the handle:
B<int mexp_get_fd (mexp_h *h);>
Return the file descriptor of the pty of the subprocess. You can read
and write to this if you want, although convenience functions are also
provided (see below).
B<pid_t mexp_get_pid (mexp_h *h);>
Return the process ID of the subprocess. You can send it signals if
you want.
B<int mexp_get_timeout_ms (mexp_h *h);>
B<void mexp_set_timeout_ms (mexp_h *h, int millisecs);>
B<void mexp_set_timeout (mexp_h *h, int secs);>
Get or set the timeout used by C<mexp_expect> [see below]. The
resolution is milliseconds (1/1000th of a second). Set this before
calling C<mexp_expect>. Passing -1 to either of the C<set_> methods
means no timeout. The default setting is 60000 milliseconds (60
seconds).
B<size_t mexp_get_read_size (mexp *h);>
B<void mexp_set_read_size (mexp *h, size_t read_size);>
Get or set the natural size (in bytes) for reads from the subprocess.
The default is 1024. Most callers will not need to change this.
B<int mexp_get_pcre_error (mexp *h);>
When C<mexp_expect> [see below] calls the PCRE function
L<pcre_exec(3)>, it stashes the return value in the C<pcre_error>
field in the handle, and that field is returned by this method.
There are two uses for this:
=over 4
=item 1.
If C<mexp_expect> returns C<MEXP_PCRE_ERROR>, then the actual PCRE
error code returned by L<pcre_exec(3)> is available by calling this
method. For a list of PCRE error codes, see L<pcreapi(3)>.
=item 2.
A more unusual use is if you ever need to get the captured substrings
from your regular expression (calling L<pcre_get_substring(3)>). The
third parameter of that function (C<stringcount>) is the value
returned by L<pcre_exec(3)>, and so you can call it like this:
pcre_get_substring (h->buffer, ovector,
mexp_get_pcre_error (h), 1, &matched);
=back
B<void mexp_set_debug_file (mexp *h, FILE *fp);>
B<FILE *mexp_get_debug_file (mexp *h);>
Set or get the debug file of the handle. To enable debugging, pass a
non-C<NULL> file handle, eg. C<stderr>. To disable debugging, pass
C<NULL>. Debugging messages are printed on the file handle.
Note that all output and input gets printed, including passwords. To
prevent passwords from being printed, modify your code to call
C<mexp_printf_password> instead of C<mexp_printf>.
The following fields in the handle do not have methods, but can be
accessed directly instead:
char *buffer;
size_t len;
size_t alloc;
If C<mexp_expect> returns a match then these variables contain the
read buffer. Note this buffer does not contain the full input from
the process, but it will contain at least the part matched by the
regular expression (and maybe some more). C<buffer> is the read
buffer and C<len> is the number of bytes of data in the buffer.
ssize_t next_match;
If C<mexp_expect> returns a match, then C<next_match> points to the
first byte in the buffer I<after> the fully matched expression. (It
may be C<-1> which means it is invalid). The next time that
C<mexp_expect> is called, it will start by consuming the data
C<buffer[next_match...len-1]>. Callers may also need to read from
that point in the buffer before calling L<read(2)> on the file
descriptor. Callers may also set this, for example setting it to
C<-1> in order to ignore the remainder of the buffer. In most cases
callers can ignore this field, and C<mexp_expect> will just do the
right thing when called repeatedly.
void *user1;
void *user2;
void *user3;
Opaque pointers for use by the caller. The library will not touch
these.
=head1 CLOSING THE HANDLE
To close the handle and clean up the subprocess, call:
B<int mexp_close (mexp_h *h);>
This returns the status code from the subprocess. This is in the form
of a L<waitpid(2)>/L<system(3)> status so you have to use the macros
C<WIFEXITED>, C<WEXITSTATUS>, C<WIFSIGNALED>, C<WTERMSIG> etc defined
in C<E<lt>sys/wait.hE<gt>> to parse it.
If there was a system call error, then C<-1> is returned. The error
will be in C<errno>.
Notes:
=over 4
=item *
Even in error cases, the handle is always closed and its memory is
freed by this call.
=item *
It is normal for the kernel to send SIGHUP to the subprocess.
If the subprocess doesn't catch the SIGHUP, then it will die
with status:
WIFSIGNALED (status) && WTERMSIG (status) == SIGHUP
This case should not necessarily be considered an error.
=back
This is how code should check for and print errors from C<mexp_close>:
status = mexp_close (h);
if (status == -1) {
perror ("mexp_close");
return -1;
}
if (WIFSIGNALED (status) && WTERMSIG (status) == SIGHUP)
goto ignore; /* not an error */
if (!WIFEXITED (status) || WEXITSTATUS (status) != 0)
/* You could use the W* macros to print a better error message. */
fprintf (stderr, "error: subprocess failed, status = %d", status);
return -1;
}
ignore:
/* no error case */
=head1 EXPECT FUNCTION
Miniexpect contains a powerful regular expression matching function
based on L<pcre(3)>:
B<int mexp_expect (mexp_h *h, const mexp_regexp *regexps,
int *ovector, int ovecsize);>
The output of the subprocess is matched against the list of PCRE
regular expressions in C<regexps>. C<regexps> is a list of regular
expression structures:
struct mexp_regexp {
int r;
const pcre *re;
const pcre_extra *extra;
int options;
};
typedef struct mexp_regexp mexp_regexp;
C<r> is the integer code returned from C<mexp_expect> if this regular
expression matches. It B<must> be E<gt> 0. C<r == 0> indicates the
end of the list of regular expressions. C<re> is the compiled regular
expression.
Possible return values are:
=over 4
=item C<MEXP_TIMEOUT>
No input matched before the timeout (C<h-E<gt>timeout>) was
reached.
=item C<MEXP_EOF>
The subprocess closed the connection.
=item C<MEXP_ERROR>
There was a system call error (eg. from the read call). The error is
returned in C<errno>.
=item C<MEXP_PCRE_ERROR>
There was a C<pcre_exec> error. C<h-E<gt>pcre_error> is set to the
error code. See L<pcreapi(3)> for a list of the C<PCRE_*> error codes
and what they mean.
=item C<r> E<gt> 0
If any regexp matches, the associated integer code (C<regexps[].r>)
is returned.
=back
Notes:
=over 4
=item *
C<regexps> may be NULL or an empty list, which means we don't match
against a regular expression. This is useful if you just want to wait
for EOF or timeout.
=item *
C<regexps[].re>, C<regexps[].extra>, C<regexps[].options>, C<ovector>
and C<ovecsize> are passed through to the L<pcre_exec(3)> function.
=item *
If multiple regular expressions are passed, then they are checked in
turn and the I<first> regular expression that matches is returned
I<even if the match happens later in the input than another regular
expression>.
For example if the input is C<"hello world"> and you pass the two
regular expressions:
regexps[0].re = world
regexps[1].re = hello
then the first regular expression (C<"world">) may match and the
C<"hello"> part of the input may be ignored.
In some cases this can even lead to unpredictable matching. In the
case above, if we only happened to read C<"hello wor">, then the
second regular expression (C<"hello">) I<would> match.
If this is a concern, combine your regular expressions into a single
one, eg. C<(hello)|(world)>.
=back
=head2 mexp_expect example
It is easier to understand C<mexp_expect> by considering a simple
example.
In this example we are waiting for ssh to either send us a password
prompt, or (if no password was required) a command prompt, and based
on the output we will either send back a password or a command.
The unusual C<(mexp_regexp[]){...}> syntax is called a "compound
literal" and is available in C99. If you need to use an older
compiler, you can just use a local variable instead.
mexp_h *h;
char *errptr;
int offset;
pcre *password_re, *prompt_re;
const int ovecsize = 12;
int ovector[ovecsize];
password_re = pcre_compile ("assword", 0, &errptr, &offset, NULL);
prompt_re = pcre_compile ("[$#] ", 0, &errptr, &offset, NULL);
switch (mexp_expect (h,
(mexp_regexp[]) {
{ 100, .re = password_re },
{ 101, .re = prompt_re },
{ 0 },
}, ovector, ovecsize)) {
case 100:
/* here you would send a password */
break;
case 101:
/* here you would send a command */
break;
case MEXP_EOF:
fprintf (stderr, "error: ssh closed the connection unexpectedly\n");
exit (EXIT_FAILURE);
case MEXP_TIMEOUT:
fprintf (stderr, "error: timeout before reaching the prompt\n");
exit (EXIT_FAILURE);
case MEXP_ERROR:
perror ("mexp_expect");
exit (EXIT_FAILURE);
case MEXP_PCRE_ERROR:
fprintf (stderr, "error: PCRE error: %d\n", h->pcre_error);
exit (EXIT_FAILURE);
}
=head1 SENDING COMMANDS TO THE SUBPROCESS
You can write to the subprocess simply by writing to C<h-E<gt>fd>.
However we also provide a convenience function:
B<int mexp_printf (mexp_h *h, const char *fs, ...);>
B<int mexp_printf_password (mexp_h *h, const char *fs, ...);>
This returns the number of bytes, if the whole message was written OK.
If there was an error, -1 is returned and the error is available in
C<errno>.
Notes:
=over 4
=item *
C<mexp_printf> will not do a partial write. If it cannot write all
the data, then it will return an error.
=item *
This function does not write a newline automatically. If you want to
send a command followed by a newline you have to do something like:
mexp_printf (h, "exit\n");
=item *
C<mexp_printf_password> works identically to C<mexp_printf> except
that the output is I<not> sent to the debugging file if debugging is
enabled. As the name suggests, use this for passwords so that they
don't appear in debugging output.
=back
B<int mexp_send_interrupt (mexp_h *h);>
Send the interrupt character (C<^C>, Ctrl-C, C<\003>). This is like
pressing C<^C> - the subprocess (or remote process, if using C<ssh>)
is gracefully killed.
Note this only works if the pty is in cooked mode
(ie. C<MEXP_SPAWN_COOKED_MODE> was passed to C<mexp_spawnlf> or
C<mexp_spawnvf>). In raw mode, all characters are passed through
without any special interpretation.
=head1 SOURCE
Source is available from:
L<http://git.annexia.org/?p=miniexpect.git;a=summary>
=head1 SEE ALSO
L<pcre(3)>,
L<pcre_exec(3)>,
L<pcreapi(3)>,
L<waitpid(2)>,
L<system(3)>.
=head1 AUTHORS
Richard W.M. Jones (C<rjones at redhat dot com>)
=head1 LICENSE
The library is released under the Library GPL (LGPL) version 2 or at
your option any later version.
=head1 COPYRIGHT
Copyright (C) 2014 Red Hat Inc.

View File

@@ -166,8 +166,8 @@ m4_include([m4/guestfs-rust.m4])
HEADING([Checking for Vala])
VAPIGEN_CHECK
dnl virt-v2v, virt-p2v.
HEADING([Checking the virt-v2v and virt-p2v dependencies])
dnl virt-v2v.
HEADING([Checking the virt-v2v dependencies])
m4_include([m4/guestfs-v2v.m4])
dnl Bash completion.
@@ -236,7 +236,6 @@ AC_CONFIG_FILES([Makefile
cat/Makefile
common/errnostring/Makefile
common/edit/Makefile
common/miniexpect/Makefile
common/mlaugeas/Makefile
common/mlgettext/Makefile
common/mllibvirt/Makefile

View File

@@ -18,9 +18,6 @@ make-check-on-installed.pl
we release them. Note that a checked out copy of the source
from git is required. Read the top of the file before using.
p2v/ Hacky script to build virt-p2v ISO on top of RHEL 5/6/7,
for 32 bit (i686) and 64 bit (x86-64).
windows-icons.pl
This script lets you extract all the icons from a Windows
guest. We use this to locate the Windows logo in new releases

View File

@@ -12,8 +12,6 @@ cat/ls.c
cat/tail.c
common/edit/file-edit.c
common/edit/file-edit.h
common/miniexpect/miniexpect.c
common/miniexpect/miniexpect.h
common/mlaugeas/augeas-c.c
common/mlgettext/dummy.c
common/mllibvirt/libvirt_c_epilogue.c

View File

@@ -76,7 +76,7 @@ I<Required>.
=item qemu-img E<ge> 1.3.0
I<Required>. Virt-p2v and virt-v2v requires qemu-img E<ge> 2.2.0.
I<Required>. Virt-v2v requires qemu-img E<ge> 2.2.0.
=item kernel E<ge> 2.6.34
@@ -272,10 +272,6 @@ Optional. Used only for testing.
Optional. qemu-nbd is used for testing.
L<virt-p2v(1)> requires either qemu-nbd or nbdkit, but these only need
to be present on the virt-p2v ISO, they do not need to be installed at
compile time.
=item uml_mkcow
Optional. For the L<UML backend|guestfs(3)/BACKEND>.
@@ -293,27 +289,6 @@ Optional. Used by virt-builder for checking digital signatures.
Optional. If available, virt-builder will use this library
for fast, parallel uncompression of templates.
=item Gtk E<ge> 2.24, or 3
Optional.
Used by the virt-p2v graphical user interface.
Either Gtk 2 or Gtk 3 can be used. If you want to select a specific
version of Gtk, use S<C<./configure --with-gtk=2>> or
S<C<./configure --with-gtk=3>>.
=item D-Bus
Optional.
If the D-Bus low level C API is available, virt-p2v can send a D-Bus
message to logind to inhibit power saving (sleep, suspend, etc) during
P2V conversions.
If this API is not available at build time, then very long conversions
might be interrupted if the physical machine goes to sleep.
=item zip
=item unzip
@@ -688,11 +663,6 @@ indicate this is I<not> a distro build.
Compile libguestfs without libvirt support, even if libvirt
development libraries are installed.
=item B<--with-gtk=2>
This option forces virt-p2v to be built against Gtk 2, which is
currently the most widely tested configuration.
=item B<--with-qemu=">bin1 bin2 ...B<">
Provide an alternate qemu binary (or list of binaries). This can be
@@ -843,29 +813,6 @@ The sources and spec files for RHEL versions of libguestfs are
available on L<https://git.centos.org/project/rpms>, and see also
L<https://wiki.centos.org/Sources>.
=head1 BUILDING i686 32 BIT VIRT-P2V
I<(This section only applies on the x86-64 architecture.)>
Building a 32 bit virt-p2v (i686) binary improves compatibility with
older hardware. See L<virt-p2v-make-disk(1)> for details. Although
virt-p2v is a simple Gtk application, it is not especially easy to
build just virt-p2v as a 32 bit application on a 64 bit host. Usually
the simplest way is to use a 32 bit chroot or even a 32 bit virtual
machine to build libguestfs.
On Fedora you can use the L<mock(1)> tool. For example:
fedpkg mockbuild --root fedora-23-i386
This will result in a F<virt-v2v-*.i686.rpm> file which can be
unpacked to extract the 32 bit virt-p2v binary.
The binary may be compressed to either F<p2v/virt-p2v.i686.xz>, or
F<$libdir/virt-p2v/virt-p2v.i686.xz> or
F<$VIRT_P2V_DATA_DIR/virt-p2v.i686.xz> as appropriate. This enables
the L<virt-p2v-make-disk(1)> I<--arch> option.
=head1 SEE ALSO
L<guestfs(3)>,

View File

@@ -94,12 +94,6 @@ The communication protocol used between the library and the daemon
running inside the appliance has to encode errnos as strings, which is
handled by this library.
=item F<common/miniexpect>
A copy of the miniexpect library from
L<http://git.annexia.org/?p=miniexpect.git;a=summary>. This is used
in virt-p2v.
=item F<common/mlaugeas>
Bindings for the Augeas library. These come from the ocaml-augeas
@@ -267,11 +261,6 @@ M4 macros used by autoconf. See L</THE BUILD SYSTEM>.
L<virt-make-fs(1)> command and documentation.
=item F<p2v>
L<virt-p2v(1)> command, documentation and scripts for building the
virt-p2v ISO or disk image.
=item F<po>
Translations of simple gettext strings.
@@ -986,78 +975,6 @@ Every other file in this directory is a support module / library of
some sort. Some code is written in C, especially where we want to use
an external C library such as libxml2.
=head2 VIRT-P2V
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 in the F<p2v/> subdirectory
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.
=head3 Running virt-p2v
You can run the F<p2v/virt-p2v> binary directly, but it will try to
convert your machines 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 -C p2v 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 -C p2v run-virt-p2v-in-a-vm
This also runs 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. 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 -C p2v run-virt-p2v-non-gui-conversion
=head3 Understanding the virt-p2v 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 miniexpects upstream too:
F<http://git.annexia.org/?p=miniexpect.git;a=summary>)
=head1 MAINTAINER TASKS
=head2 MAINTAINER MAKEFILE TARGETS

View File

@@ -134,12 +134,3 @@ let authors = [
let generate_authors () =
List.iter (fun (name, _, _) -> pr "%s\n" name) authors
let generate_p2v_authors () =
let p2v_authors =
List.filter_map (
fun (name, _, roles) ->
if List.mem V2V_and_P2V roles then Some name
else None
) authors in
List.iter (pr "%s\n") p2v_authors

View File

@@ -23,4 +23,3 @@ val authors : (string * string list * role list) list
(** List of authors, their aliases, and their roles. *)
val generate_authors : unit -> unit
val generate_p2v_authors : unit -> unit

View File

@@ -15,7 +15,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
dnl Virt-v2v and virt-p2v.
dnl Virt-v2v.
dnl nbdkit python plugin.
AC_MSG_CHECKING([for the nbdkit python plugin name])
@@ -26,53 +26,3 @@ AC_ARG_WITH([virt-v2v-nbdkit-python-plugin],
[VIRT_V2V_NBDKIT_PYTHON_PLUGIN=python])
AC_MSG_RESULT([$VIRT_V2V_NBDKIT_PYTHON_PLUGIN])
AC_SUBST([VIRT_V2V_NBDKIT_PYTHON_PLUGIN])
dnl Check for Gtk 2 or 3 library, used by virt-p2v.
AC_MSG_CHECKING([for --with-gtk option])
AC_ARG_WITH([gtk],
[AS_HELP_STRING([--with-gtk=2|3|check|no],
[prefer Gtk version 2 or 3. @<:@default=check@:>@])],
[with_gtk="$withval"
AC_MSG_RESULT([$withval])],
[with_gtk="check"
AC_MSG_RESULT([not set, will check for installed Gtk])]
)
if test "x$with_gtk" = "x3"; then
PKG_CHECK_MODULES([GTK], [gtk+-3.0], [
GTK_VERSION=3
])
elif test "x$with_gtk" = "x2"; then
PKG_CHECK_MODULES([GTK], [gtk+-2.0], [
GTK_VERSION=2
], [])
elif test "x$with_gtk" = "xcheck"; then
PKG_CHECK_MODULES([GTK], [gtk+-3.0], [
GTK_VERSION=3
], [
PKG_CHECK_MODULES([GTK], [gtk+-2.0], [
GTK_VERSION=2
], [:])
])
fi
dnl D-Bus is an optional dependency of virt-p2v.
PKG_CHECK_MODULES([DBUS], [dbus-1], [
AC_SUBST([DBUS_CFLAGS])
AC_SUBST([DBUS_LIBS])
AC_DEFINE([HAVE_DBUS],[1],[D-Bus found at compile time.])
],[
AC_MSG_WARN([D-Bus not found, virt-p2v will not be able to inhibit power saving during P2V conversions])
])
dnl Can we build virt-p2v?
AC_MSG_CHECKING([if we can build virt-p2v])
if test "x$GTK_LIBS" != "x"; then
AC_MSG_RESULT([yes, with Gtk $GTK_VERSION])
AC_SUBST([GTK_CFLAGS])
AC_SUBST([GTK_LIBS])
AC_SUBST([GTK_VERSION])
else
AC_MSG_RESULT([no])
fi
AM_CONDITIONAL([HAVE_P2V], [test "x$GTK_LIBS" != "x"])

View File

@@ -8,7 +8,6 @@
../cat/virt-log.pod
../cat/virt-ls.pod
../cat/virt-tail.pod
../common/miniexpect/miniexpect.pod
../customize/customize-options.pod
../customize/customize-synopsis.pod
../customize/virt-customize.pod

View File

@@ -14,7 +14,6 @@ cat/tail.c
common/edit/file-edit.c
common/errnostring/errnostring-gperf.c
common/errnostring/errnostring.c
common/miniexpect/miniexpect.c
common/mlaugeas/augeas-c.c
common/mlgettext/dummy.c
common/mllibvirt/generator.pl

7
run.in
View File

@@ -98,7 +98,6 @@ prepend PATH "$b/fuse"
prepend PATH "$b/get-kernel"
prepend PATH "$b/inspector"
prepend PATH "$b/make-fs"
prepend PATH "$b/p2v"
prepend PATH "$b/rescue"
prepend PATH "$b/resize"
prepend PATH "$b/sparsify"
@@ -125,12 +124,6 @@ if [ -z "$XDG_CONFIG_DIRS" ]; then
export XDG_CONFIG_DIRS
fi
# virt-p2v-make-* data directory.
if [ -z "$VIRT_P2V_DATA_DIR" ]; then
VIRT_P2V_DATA_DIR="$b/p2v"
export VIRT_P2V_DATA_DIR
fi
# For Perl.
prepend PERL5LIB "$b/perl/blib/arch"
prepend PERL5LIB "$b/perl/blib/lib"