mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
Remove remaining virt-p2v bits
Remove (almost) all the remaining bits related to virt-p2v.
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -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
|
||||
|
||||
@@ -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$$' | \
|
||||
|
||||
@@ -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 $@
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 $@
|
||||
@@ -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.
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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.
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)>,
|
||||
|
||||
@@ -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 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 -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 miniexpect’s upstream too:
|
||||
F<http://git.annexia.org/?p=miniexpect.git;a=summary>)
|
||||
|
||||
=head1 MAINTAINER TASKS
|
||||
|
||||
=head2 MAINTAINER MAKEFILE TARGETS
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"])
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
7
run.in
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user