Pino Toscano
2019-Jul-09 14:05 UTC
[Libguestfs] [PATCH 0/5] Split virt-p2v in own repository
Hi, as it was already discussed on this list, here it is my attempt in splitting virt-p2v in an own repository. Sadly there are things that must be copied from libguestfs, as it cannot be avoided. The approach taken was to run a script (will send separately) to just get the "p2v" subdirectory with its history as own repository, and then add in few followup commits all the bits needed to build. The split repository I have is: https://github.com/ptoscano/virt-p2v-split And follow here in this series all the patches to make virt-p2v build, work, and with also "make dist" usable. Let me know what you think -- any kind of feedback is welcome. Pino Toscano (5): Import miniexpect library Import gnulib Copy C sources from libguestfs Add/adapt all the files to build Improve gitignore .gitignore | 17 +- .gitmodules | 3 + .gnulib | 1 + AUTHORS | 16 + Makefile.am | 54 ++- autogen.sh | 51 +++ bootstrap | 124 ++++++ configure.ac | 109 +++++ libguestfs/README | 4 + libguestfs/cleanups.c | 96 ++++ libguestfs/cleanups.h | 74 ++++ libguestfs/guestfs-utils.c | 247 +++++++++++ libguestfs/guestfs-utils.h | 85 ++++ libguestfs/libxml2-cleanups.c | 94 ++++ libguestfs/libxml2-writer-macros.h | 200 +++++++++ m4/p2v-c.m4 | 179 ++++++++ m4/p2v-libraries.m4 | 79 ++++ m4/p2v-progs.m4 | 63 +++ m4/p2v-tests.m4 | 45 ++ miniexpect/README | 31 ++ miniexpect/miniexpect.c | 489 +++++++++++++++++++++ miniexpect/miniexpect.h | 110 +++++ podcheck.pl | 273 ++++++++++++ podwrapper.pl.in | 678 +++++++++++++++++++++++++++++ run.in | 118 +++++ subdir-rules.mk | 60 +++ test-functions.sh | 120 +++++ 27 files changed, 3401 insertions(+), 19 deletions(-) create mode 100644 .gitmodules create mode 160000 .gnulib create mode 100644 AUTHORS create mode 100755 autogen.sh create mode 100755 bootstrap create mode 100644 configure.ac create mode 100644 libguestfs/README create mode 100644 libguestfs/cleanups.c create mode 100644 libguestfs/cleanups.h create mode 100644 libguestfs/guestfs-utils.c create mode 100644 libguestfs/guestfs-utils.h create mode 100644 libguestfs/libxml2-cleanups.c create mode 100644 libguestfs/libxml2-writer-macros.h create mode 100644 m4/p2v-c.m4 create mode 100644 m4/p2v-libraries.m4 create mode 100644 m4/p2v-progs.m4 create mode 100644 m4/p2v-tests.m4 create mode 100644 miniexpect/README create mode 100644 miniexpect/miniexpect.c create mode 100644 miniexpect/miniexpect.h create mode 100755 podcheck.pl create mode 100755 podwrapper.pl.in create mode 100755 run.in create mode 100644 subdir-rules.mk create mode 100755 test-functions.sh -- 2.21.0
Add a copy of the miniexpect library that can be found here: http://git.annexia.org/?p=miniexpect.git;a=summary It is imported at commit eba90008396f05e2c0fa752421793b797383fca7. --- Makefile.am | 1 + miniexpect/README | 31 +++ miniexpect/miniexpect.c | 489 ++++++++++++++++++++++++++++++++++++++++ miniexpect/miniexpect.h | 110 +++++++++ 4 files changed, 631 insertions(+) create mode 100644 miniexpect/README create mode 100644 miniexpect/miniexpect.c create mode 100644 miniexpect/miniexpect.h diff --git a/Makefile.am b/Makefile.am index 4e2405e..736b8fc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,6 +38,7 @@ EXTRA_DIST = \ kiwi-config.sh \ kiwi-config.xml.in \ launch-virt-p2v \ + miniexpect/README \ p2v.ks.in \ p2v.service \ test-virt-p2v-docs.sh \ diff --git a/miniexpect/README b/miniexpect/README new file mode 100644 index 0000000..f1f5a95 --- /dev/null +++ b/miniexpect/README @@ -0,0 +1,31 @@ +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. diff --git a/miniexpect/miniexpect.c b/miniexpect/miniexpect.c new file mode 100644 index 0000000..7debc02 --- /dev/null +++ b/miniexpect/miniexpect.c @@ -0,0 +1,489 @@ +/* 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++; + } +} diff --git a/miniexpect/miniexpect.h b/miniexpect/miniexpect.h new file mode 100644 index 0000000..14d8236 --- /dev/null +++ b/miniexpect/miniexpect.h @@ -0,0 +1,110 @@ +/* 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_ */ -- 2.21.0
virt-p2v uses gnulib, so import it. --- .gitmodules | 3 +++ .gnulib | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 .gnulib diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..f8d0cf3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "gnulib"] + path = .gnulib + url = https://git.savannah.gnu.org/git/gnulib.git diff --git a/.gnulib b/.gnulib new file mode 160000 index 0000000..b417a9c --- /dev/null +++ b/.gnulib @@ -0,0 +1 @@ +Subproject commit b417a9c02359cd1e9ed215e0896b36dd383fc47f -- 2.21.0
Pino Toscano
2019-Jul-09 14:05 UTC
[Libguestfs] [PATCH 3/5] Copy C sources from libguestfs
Copy some common C sources from libguestfs, trimmed to only what virt-p2v needs. --- Makefile.am | 1 + libguestfs/README | 4 + libguestfs/cleanups.c | 96 +++++++++++ libguestfs/cleanups.h | 74 +++++++++ libguestfs/guestfs-utils.c | 247 +++++++++++++++++++++++++++++ libguestfs/guestfs-utils.h | 85 ++++++++++ libguestfs/libxml2-cleanups.c | 94 +++++++++++ libguestfs/libxml2-writer-macros.h | 200 +++++++++++++++++++++++ 8 files changed, 801 insertions(+) create mode 100644 libguestfs/README create mode 100644 libguestfs/cleanups.c create mode 100644 libguestfs/cleanups.h create mode 100644 libguestfs/guestfs-utils.c create mode 100644 libguestfs/guestfs-utils.h create mode 100644 libguestfs/libxml2-cleanups.c create mode 100644 libguestfs/libxml2-writer-macros.h diff --git a/Makefile.am b/Makefile.am index 736b8fc..0d67dbf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,6 +38,7 @@ EXTRA_DIST = \ kiwi-config.sh \ kiwi-config.xml.in \ launch-virt-p2v \ + libguestfs/README \ miniexpect/README \ p2v.ks.in \ p2v.service \ diff --git a/libguestfs/README b/libguestfs/README new file mode 100644 index 0000000..fbf367b --- /dev/null +++ b/libguestfs/README @@ -0,0 +1,4 @@ +This directory contains sources mostly copied from libguestfs. +The sources were trimmed to contain only what is used by virt-p2v. + +Fixes ought to be sent also to libguestfs, to avoid diverging from libguestfs. diff --git a/libguestfs/cleanups.c b/libguestfs/cleanups.c new file mode 100644 index 0000000..dae75ee --- /dev/null +++ b/libguestfs/cleanups.c @@ -0,0 +1,96 @@ +/* libguestfs + * Copyright (C) 2013 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 + */ + +/** + * Libguestfs uses C<CLEANUP_*> macros to simplify temporary + * allocations. They are implemented using the + * C<__attribute__((cleanup))> feature of gcc and clang. Typical + * usage is: + * + * fn () + * { + * CLEANUP_FREE char *str = NULL; + * str = safe_asprintf (g, "foo"); + * // str is freed automatically when the function returns + * } + * + * There are a few catches to be aware of with the cleanup mechanism: + * + * =over 4 + * + * =item * + * + * If a cleanup variable is not initialized, then you can end up + * calling L<free(3)> with an undefined value, resulting in the + * program crashing. For this reason, you should usually initialize + * every cleanup variable with something, eg. C<NULL> + * + * =item * + * + * Don't mark variables holding return values as cleanup variables. + * + * =item * + * + * The C<main()> function shouldn't use cleanup variables since it is + * normally exited by calling L<exit(3)>, and that doesn't call the + * cleanup handlers. + * + * =back + * + * The functions in this file are used internally by the C<CLEANUP_*> + * macros. Don't call them directly. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> + +#include "guestfs-utils.h" + +/* Stdlib cleanups. */ + +void +guestfs_int_cleanup_free (void *ptr) +{ + free (* (void **) ptr); +} + +void +guestfs_int_cleanup_fclose (void *ptr) +{ + FILE *f = * (FILE **) ptr; + + if (f) + fclose (f); +} + +void +guestfs_int_cleanup_pclose (void *ptr) +{ + FILE *f = * (FILE **) ptr; + + if (f) + pclose (f); +} + +void +guestfs_int_cleanup_free_string_list (char ***ptr) +{ + guestfs_int_free_string_list (*ptr); +} diff --git a/libguestfs/cleanups.h b/libguestfs/cleanups.h new file mode 100644 index 0000000..4defdef --- /dev/null +++ b/libguestfs/cleanups.h @@ -0,0 +1,74 @@ +/* libguestfs + * Copyright (C) 2013-2019 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 + */ + +#ifndef GUESTFS_CLEANUPS_H_ +#define GUESTFS_CLEANUPS_H_ + +#ifdef HAVE_ATTRIBUTE_CLEANUP +#define CLEANUP_FREE \ + __attribute__((cleanup(guestfs_int_cleanup_free))) +#define CLEANUP_FCLOSE \ + __attribute__((cleanup(guestfs_int_cleanup_fclose))) +#define CLEANUP_PCLOSE \ + __attribute__((cleanup(guestfs_int_cleanup_pclose))) +#define CLEANUP_FREE_STRING_LIST \ + __attribute__((cleanup(guestfs_int_cleanup_free_string_list))) +#define CLEANUP_XMLFREE \ + __attribute__((cleanup(guestfs_int_cleanup_xmlFree))) +#define CLEANUP_XMLBUFFERFREE \ + __attribute__((cleanup(guestfs_int_cleanup_xmlBufferFree))) +#define CLEANUP_XMLFREEDOC \ + __attribute__((cleanup(guestfs_int_cleanup_xmlFreeDoc))) +#define CLEANUP_XMLFREEURI \ + __attribute__((cleanup(guestfs_int_cleanup_xmlFreeURI))) +#define CLEANUP_XMLFREETEXTWRITER \ + __attribute__((cleanup(guestfs_int_cleanup_xmlFreeTextWriter))) +#define CLEANUP_XMLXPATHFREECONTEXT \ + __attribute__((cleanup(guestfs_int_cleanup_xmlXPathFreeContext))) +#define CLEANUP_XMLXPATHFREEOBJECT \ + __attribute__((cleanup(guestfs_int_cleanup_xmlXPathFreeObject))) +#else +#define CLEANUP_FREE +#define CLEANUP_FCLOSE +#define CLEANUP_PCLOSE +#define CLEANUP_FREE_STRING_LIST +#define CLEANUP_XMLFREE +#define CLEANUP_XMLBUFFERFREE +#define CLEANUP_XMLFREEDOC +#define CLEANUP_XMLFREEURI +#define CLEANUP_XMLFREETEXTWRITER +#define CLEANUP_XMLXPATHFREECONTEXT +#define CLEANUP_XMLXPATHFREEOBJECT +#endif + +/* These functions are used internally by the CLEANUP_* macros. + * Don't call them directly. + */ +extern void guestfs_int_cleanup_free (void *ptr); +extern void guestfs_int_cleanup_fclose (void *ptr); +extern void guestfs_int_cleanup_pclose (void *ptr); +extern void guestfs_int_cleanup_free_string_list (char ***ptr); +extern void guestfs_int_cleanup_xmlFree (void *ptr); +extern void guestfs_int_cleanup_xmlBufferFree (void *ptr); +extern void guestfs_int_cleanup_xmlFreeDoc (void *ptr); +extern void guestfs_int_cleanup_xmlFreeURI (void *ptr); +extern void guestfs_int_cleanup_xmlFreeTextWriter (void *ptr); +extern void guestfs_int_cleanup_xmlXPathFreeContext (void *ptr); +extern void guestfs_int_cleanup_xmlXPathFreeObject (void *ptr); + +#endif /* GUESTFS_CLEANUPS_H_ */ diff --git a/libguestfs/guestfs-utils.c b/libguestfs/guestfs-utils.c new file mode 100644 index 0000000..505c9f6 --- /dev/null +++ b/libguestfs/guestfs-utils.c @@ -0,0 +1,247 @@ +/* libguestfs + * Copyright (C) 2009-2019 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 <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "guestfs-utils.h" + +void +guestfs_int_free_string_list (char **argv) +{ + size_t i; + + if (argv == NULL) + return; + + for (i = 0; argv[i] != NULL; ++i) + free (argv[i]); + free (argv); +} + +size_t +guestfs_int_count_strings (char *const *argv) +{ + size_t r; + + for (r = 0; argv[r]; ++r) + ; + + return r; +} + +char ** +guestfs_int_copy_string_list (char *const *argv) +{ + const size_t n = guestfs_int_count_strings (argv); + size_t i, j; + char **ret; + + ret = malloc ((n+1) * sizeof (char *)); + if (ret == NULL) + return NULL; + ret[n] = NULL; + + for (i = 0; i < n; ++i) { + ret[i] = strdup (argv[i]); + if (ret[i] == NULL) { + for (j = 0; j < i; ++j) + free (ret[j]); + free (ret); + return NULL; + } + } + + return ret; +} + +/** + * Split string at separator character C<sep>, returning the list of + * strings. Returns C<NULL> on memory allocation failure. + * + * Note (assuming C<sep> is C<:>): + * + * =over 4 + * + * =item C<str == NULL> + * + * aborts + * + * =item C<str == ""> + * + * returns C<[]> + * + * =item C<str == "abc"> + * + * returns C<["abc"]> + * + * =item C<str == ":"> + * + * returns C<["", ""]> + * + * =back + */ +char ** +guestfs_int_split_string (char sep, const char *str) +{ + size_t i, n, c; + const size_t len = strlen (str); + char reject[2] = { sep, '\0' }; + char **ret; + + /* We have to handle the empty string case differently else the code + * below will return [""]. + */ + if (str[0] == '\0') { + ret = malloc (1 * sizeof (char *)); + if (!ret) + return NULL; + ret[0] = NULL; + return ret; + } + + for (n = i = 0; i < len; ++i) + if (str[i] == sep) + n++; + + /* We always return a list of length 1 + (# separator characters). + * We also have to add a trailing NULL. + */ + ret = malloc ((n+2) * sizeof (char *)); + if (!ret) + return NULL; + ret[n+1] = NULL; + + for (n = i = 0; i <= len; ++i, ++n) { + c = strcspn (&str[i], reject); + ret[n] = strndup (&str[i], c); + if (ret[n] == NULL) { + for (i = 0; i < n; ++i) + free (ret[i]); + free (ret); + return NULL; + } + i += c; + if (str[i] == '\0') /* end of string? */ + break; + } + + return ret; +} + +/** + * Return a random string of characters. + * + * Notes: + * + * =over 4 + * + * =item * + * + * The C<ret> buffer must have length C<len+1> in order to store the + * final C<\0> character. + * + * =item * + * + * There is about 5 bits of randomness per output character (so about + * C<5*len> bits of randomness in the resulting string). + * + * =back + */ +int +guestfs_int_random_string (char *ret, size_t len) +{ + int fd; + size_t i; + unsigned char c; + int saved_errno; + + fd = open ("/dev/urandom", O_RDONLY|O_CLOEXEC); + if (fd == -1) + return -1; + + for (i = 0; i < len; ++i) { + if (read (fd, &c, 1) != 1) { + saved_errno = errno; + close (fd); + errno = saved_errno; + return -1; + } + /* Do not change this! */ + ret[i] = "0123456789abcdefghijklmnopqrstuvwxyz"[c % 36]; + } + ret[len] = '\0'; + + if (close (fd) == -1) + return -1; + + return 0; +} + +/** + * This turns a drive index (eg. C<27>) into a drive name + * (eg. C<"ab">). + * + * Drive indexes count from C<0>. The return buffer has to be large + * enough for the resulting string, and the returned pointer points to + * the *end* of the string. + * + * L<https://rwmj.wordpress.com/2011/01/09/how-are-linux-drives-named-beyond-drive-26-devsdz/> + */ +char * +guestfs_int_drive_name (size_t index, char *ret) +{ + if (index >= 26) + ret = guestfs_int_drive_name (index/26 - 1, ret); + index %= 26; + *ret++ = 'a' + index; + *ret = '\0'; + return ret; +} + +/** + * Similar to C<Tcl_GetBoolean>. + */ +int +guestfs_int_is_true (const char *str) +{ + if (STREQ (str, "1") || + STRCASEEQ (str, "true") || + STRCASEEQ (str, "t") || + STRCASEEQ (str, "yes") || + STRCASEEQ (str, "y") || + STRCASEEQ (str, "on")) + return 1; + + if (STREQ (str, "0") || + STRCASEEQ (str, "false") || + STRCASEEQ (str, "f") || + STRCASEEQ (str, "no") || + STRCASEEQ (str, "n") || + STRCASEEQ (str, "off")) + return 0; + + return -1; +} diff --git a/libguestfs/guestfs-utils.h b/libguestfs/guestfs-utils.h new file mode 100644 index 0000000..d5557a4 --- /dev/null +++ b/libguestfs/guestfs-utils.h @@ -0,0 +1,85 @@ +/* libguestfs + * Copyright (C) 2013-2019 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 + */ + +#ifndef GUESTFS_UTILS_H_ +#define GUESTFS_UTILS_H_ + +#include <string.h> + +#include "cleanups.h" + +#define _(str) dgettext(PACKAGE, (str)) + +#define STREQ(a,b) (strcmp((a),(b)) == 0) +#define STRCASEEQ(a,b) (strcasecmp((a),(b)) == 0) +#define STRNEQ(a,b) (strcmp((a),(b)) != 0) +#define STRPREFIX(a,b) (strncmp((a),(b),strlen((b))) == 0) + +/* A simple (indeed, simplistic) way to build up short lists of + * arguments. Your code must define MAX_ARGS to a suitable "larger + * than could ever be needed" value. (If the value is exceeded then + * your code will abort). For more complex needs, use something else + * more suitable. + */ +#define ADD_ARG(argv,i,v) \ + do { \ + if ((i) >= MAX_ARGS) { \ + fprintf (stderr, "%s: %d: internal error: exceeded MAX_ARGS (%zu) when constructing the command line\n", __FILE__, __LINE__, (size_t) MAX_ARGS); \ + abort (); \ + } \ + (argv)[(i)++] = (v); \ + } while (0) + +extern void guestfs_int_free_string_list (char **); +extern size_t guestfs_int_count_strings (char *const *); +extern char **guestfs_int_copy_string_list (char *const *); +extern char **guestfs_int_split_string (char sep, const char *); +extern int guestfs_int_random_string (char *ret, size_t len); +extern char *guestfs_int_drive_name (size_t index, char *ret); +extern int guestfs_int_is_true (const char *str); + +/* ANSI colours. These are defined as macros so that we don't have to + * define the force_colour global variable in the library. + */ +#define ansi_green(fp) \ + do { \ + if (force_colour || isatty (fileno (fp))) \ + fputs ("\033[0;32m", (fp)); \ + } while (0) +#define ansi_red(fp) \ + do { \ + if (force_colour || isatty (fileno (fp))) \ + fputs ("\033[1;31m", (fp)); \ + } while (0) +#define ansi_blue(fp) \ + do { \ + if (force_colour || isatty (fileno (fp))) \ + fputs ("\033[1;34m", (fp)); \ + } while (0) +#define ansi_magenta(fp) \ + do { \ + if (force_colour || isatty (fileno (fp))) \ + fputs ("\033[1;35m", (fp)); \ + } while (0) +#define ansi_restore(fp) \ + do { \ + if (force_colour || isatty (fileno (fp))) \ + fputs ("\033[0m", (fp)); \ + } while (0) + +#endif /* GUESTFS_UTILS_H_ */ diff --git a/libguestfs/libxml2-cleanups.c b/libguestfs/libxml2-cleanups.c new file mode 100644 index 0000000..829c620 --- /dev/null +++ b/libguestfs/libxml2-cleanups.c @@ -0,0 +1,94 @@ +/* libguestfs + * Copyright (C) 2013-2019 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 <unistd.h> +#include <string.h> + +#include <libxml/uri.h> +#include <libxml/tree.h> +#include <libxml/xpath.h> +#include <libxml/xmlwriter.h> + +#include "cleanups.h" + +void +guestfs_int_cleanup_xmlFree (void *ptr) +{ + xmlChar *buf = * (xmlChar **) ptr; + + if (buf) + xmlFree (buf); +} + +void +guestfs_int_cleanup_xmlBufferFree (void *ptr) +{ + xmlBufferPtr xb = * (xmlBufferPtr *) ptr; + + if (xb) + xmlBufferFree (xb); +} + +void +guestfs_int_cleanup_xmlFreeDoc (void *ptr) +{ + xmlDocPtr doc = * (xmlDocPtr *) ptr; + + if (doc) + xmlFreeDoc (doc); +} + +void +guestfs_int_cleanup_xmlFreeURI (void *ptr) +{ + xmlURIPtr uri = * (xmlURIPtr *) ptr; + + if (uri) + xmlFreeURI (uri); +} + +void +guestfs_int_cleanup_xmlFreeTextWriter (void *ptr) +{ + xmlTextWriterPtr xo = * (xmlTextWriterPtr *) ptr; + + if (xo) + xmlFreeTextWriter (xo); +} + +void +guestfs_int_cleanup_xmlXPathFreeContext (void *ptr) +{ + xmlXPathContextPtr ctx = * (xmlXPathContextPtr *) ptr; + + if (ctx) + xmlXPathFreeContext (ctx); +} + +void +guestfs_int_cleanup_xmlXPathFreeObject (void *ptr) +{ + xmlXPathObjectPtr obj = * (xmlXPathObjectPtr *) ptr; + + if (obj) + xmlXPathFreeObject (obj); +} diff --git a/libguestfs/libxml2-writer-macros.h b/libguestfs/libxml2-writer-macros.h new file mode 100644 index 0000000..66a7a8f --- /dev/null +++ b/libguestfs/libxml2-writer-macros.h @@ -0,0 +1,200 @@ +/* libguestfs + * Copyright (C) 2009-2019 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 + */ + +/** + * These macros make it easier to write XML. To use them correctly + * you must be aware of these assumptions: + * + * =over 4 + * + * =item * + * + * The C<xmlTextWriterPtr> is called C<xo>. It is used implicitly + * by all the macros. + * + * =item * + * + * On failure, a function called C<xml_error> is called which you must + * define (usually as a macro). You must use C<CLEANUP_*> macros in + * your functions if you want correct cleanup of local variables along + * the error path. + * + * =item * + * + * All the "bad" casting is hidden inside the macros. + * + * =back + */ + +#ifndef GUESTFS_LIBXML2_WRITER_MACROS_H_ +#define GUESTFS_LIBXML2_WRITER_MACROS_H_ + +#include <stdarg.h> + +/** + * To define an XML element use: + * + * start_element ("name") { + * ... + * } end_element (); + * + * which produces C<<< <name>...</name> >>> + */ +#define start_element(element) \ + if (xmlTextWriterStartElement (xo, BAD_CAST (element)) == -1) { \ + xml_error ("xmlTextWriterStartElement"); \ + } \ + do + +#define end_element() \ + while (0); \ + do { \ + if (xmlTextWriterEndElement (xo) == -1) { \ + xml_error ("xmlTextWriterEndElement"); \ + } \ + } while (0) + +/** + * To define an empty element: + * + * empty_element ("name"); + * + * which produces C<<< <name/> >>> + */ +#define empty_element(element) \ + do { start_element ((element)) {} end_element (); } while (0) + +/** + * To define a single element with no attributes containing some text: + * + * single_element ("name", text); + * + * which produces C<<< <name>text</name> >>> + */ +#define single_element(element,str) \ + do { \ + start_element ((element)) { \ + string ((str)); \ + } end_element (); \ + } while (0) + +/** + * To define a single element with no attributes containing some text + * using a format string: + * + * single_element_format ("cores", "%d", nr_cores); + * + * which produces C<<< <cores>4</cores> >>> + */ +#define single_element_format(element,fs,...) \ + do { \ + start_element ((element)) { \ + string_format ((fs), ##__VA_ARGS__); \ + } end_element (); \ + } while (0) + +/** + * To define an XML element with attributes, use: + * + * start_element ("name") { + * attribute ("foo", "bar"); + * attribute_format ("count", "%d", count); + * ... + * } end_element (); + * + * which produces C<<< <name foo="bar" count="123">...</name> >>> + */ +#define attribute(key,value) \ + do { \ + if (xmlTextWriterWriteAttribute (xo, BAD_CAST (key), \ + BAD_CAST (value)) == -1) { \ + xml_error ("xmlTextWriterWriteAttribute"); \ + } \ + } while (0) + +#define attribute_format(key,fs,...) \ + do { \ + if (xmlTextWriterWriteFormatAttribute (xo, BAD_CAST (key), \ + fs, ##__VA_ARGS__) == -1) { \ + xml_error ("xmlTextWriterWriteFormatAttribute"); \ + } \ + } while (0) + +/** + * C<attribute_ns (prefix, key, namespace_uri, value)> defines a + * namespaced attribute. + */ +#define attribute_ns(prefix,key,namespace_uri,value) \ + do { \ + if (xmlTextWriterWriteAttributeNS (xo, BAD_CAST (prefix), \ + BAD_CAST (key), \ + BAD_CAST (namespace_uri), \ + BAD_CAST (value)) == -1) { \ + xml_error ("xmlTextWriterWriteAttribute"); \ + } \ + } while (0) + +/** + * To define a verbatim string, use: + * + * string ("hello"); + */ +#define string(str) \ + do { \ + if (xmlTextWriterWriteString (xo, BAD_CAST(str)) == -1) { \ + xml_error ("xmlTextWriterWriteString"); \ + } \ + } while (0) + +/** + * To define a verbatim string using a format string, use: + * + * string ("%s, world", greeting); + */ +#define string_format(fs,...) \ + do { \ + if (xmlTextWriterWriteFormatString (xo, fs, ##__VA_ARGS__) == -1) { \ + xml_error ("xmlTextWriterWriteFormatString"); \ + } \ + } while (0) + +/** + * To write a string encoded as base64: + * + * base64 (data, size); + */ +#define base64(data, size) \ + do { \ + if (xmlTextWriterWriteBase64 (xo, (data), 0, (size)) == -1) { \ + xml_error ("xmlTextWriterWriteBase64"); \ + } \ + } while (0) + +/** + * To define a comment in the XML, use: + * + * comment ("number of items = %d", nr_items); + */ +#define comment(fs,...) \ + do { \ + if (xmlTextWriterWriteFormatComment (xo, fs, ##__VA_ARGS__) == -1) { \ + xml_error ("xmlTextWriterWriteFormatComment"); \ + } \ + } while (0) + +#endif /* GUESTFS_LIBXML2_WRITER_MACROS_H_ */ -- 2.21.0
Pino Toscano
2019-Jul-09 14:05 UTC
[Libguestfs] [PATCH 4/5] Add/adapt all the files to build
Add various files, and adapt the existing Makefile.am, to make virt-p2v build: - add all the various autotools files for bootstrapping, configuring, and building - add the POD build & checking scripts (imported from libguestfs) - add the scripts for testing (run script, and test macros) --- .gitignore | 1 - AUTHORS | 16 ++ Makefile.am | 52 ++-- autogen.sh | 51 ++++ bootstrap | 124 ++++++++ configure.ac | 109 +++++++ m4/p2v-c.m4 | 179 ++++++++++++ m4/p2v-libraries.m4 | 79 ++++++ m4/p2v-progs.m4 | 63 ++++ m4/p2v-tests.m4 | 45 +++ podcheck.pl | 273 ++++++++++++++++++ podwrapper.pl.in | 678 ++++++++++++++++++++++++++++++++++++++++++++ run.in | 118 ++++++++ subdir-rules.mk | 60 ++++ test-functions.sh | 120 ++++++++ 15 files changed, 1949 insertions(+), 19 deletions(-) create mode 100644 AUTHORS create mode 100755 autogen.sh create mode 100755 bootstrap create mode 100644 configure.ac create mode 100644 m4/p2v-c.m4 create mode 100644 m4/p2v-libraries.m4 create mode 100644 m4/p2v-progs.m4 create mode 100644 m4/p2v-tests.m4 create mode 100755 podcheck.pl create mode 100755 podwrapper.pl.in create mode 100755 run.in create mode 100644 subdir-rules.mk create mode 100755 test-functions.sh diff --git a/.gitignore b/.gitignore index 22ac25a..8495f6c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,6 @@ Makefile Makefile.in /about-authors.c -/AUTHORS /blank-part.img /config.c /dependencies.archlinux diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..2642291 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,16 @@ +Cédric Bosdonnat +John Eckersberg +Junqin Zhou +Kean Li +Kun Wei +Laura Bailey +Matthew Booth +Mike Latimer +Ming Xie +Pino Toscano +Richard W.M. Jones +Roman Kagan +Shahar Havivi +Tingting Zheng +Xiang Hua Chen +Yehuda Zimmerman diff --git a/Makefile.am b/Makefile.am index 0d67dbf..ac7e62f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,15 +17,19 @@ include $(top_srcdir)/subdir-rules.mk -generator_built = \ - AUTHORS +ACLOCAL_AMFLAGS = -I m4 -BUILT_SOURCES = \ - $(generator_built) +SUBDIRS = gnulib/lib +if ENABLE_GNULIB_TESTS +SUBDIRS += gnulib/tests +endif EXTRA_DIST = \ $(BUILT_SOURCES) \ - $(TESTS) $(APPLIANCE_TESTS) $(SLOW_TESTS) \ + $(TESTS) $(LIBGUESTFS_TESTS) $(SLOW_TESTS) \ + AUTHORS \ + autogen.sh \ + bootstrap \ contrib/aux-scripts/do-build.sh \ contrib/build-p2v-iso.sh \ contrib/patches/0001-RHEL-5-ONLY-DISABLE-AUTOMATIC-REMOTE-PORT-ALLOCATION.patch \ @@ -42,6 +46,8 @@ EXTRA_DIST = \ miniexpect/README \ p2v.ks.in \ p2v.service \ + podcheck.pl \ + test-functions.sh \ test-virt-p2v-docs.sh \ test-virt-p2v-pxe.sshd_config.in \ test-virt-p2v-scp.sh \ @@ -70,7 +76,8 @@ CLEANFILES += \ test-virt-p2v-pxe.sshd_config \ virt-p2v.img \ virt-p2v-kernel-config.pod \ - virt-p2v.xz + virt-p2v.xz \ + website/*.html # Although virt-p2v is a regular binary, it is not usually installed # in /usr/bin since it only functions when contained in an ISO or PXE @@ -90,6 +97,14 @@ virt-p2v.xz: virt-p2v noinst_PROGRAMS = virt-p2v virt_p2v_SOURCES = \ + miniexpect/miniexpect.c \ + miniexpect/miniexpect.h \ + libguestfs/cleanups.c \ + libguestfs/cleanups.h \ + libguestfs/guestfs-utils.c \ + libguestfs/guestfs-utils.h \ + libguestfs/libxml2-cleanups.c \ + libguestfs/libxml2-writer-macros.h \ conversion.c \ cpuid.c \ gui.c \ @@ -119,10 +134,9 @@ nodist_virt_p2v_SOURCES = \ virt_p2v_CPPFLAGS = \ -DLOCALEBASEDIR=\""$(datadir)/locale"\" \ - -I$(top_srcdir)/common/utils -I$(top_builddir)/common/utils \ - -I$(top_srcdir)/lib -I$(top_builddir)/lib \ - -I$(top_srcdir)/common/miniexpect -I$(top_builddir)/common/miniexpect \ - -I$(srcdir)/../gnulib/lib -I../gnulib/lib + -I$(srcdir)/libguestfs \ + -I$(srcdir)/miniexpect \ + -I$(srcdir)/gnulib/lib -Ignulib/lib virt_p2v_CFLAGS = \ -pthread \ @@ -133,13 +147,11 @@ virt_p2v_CFLAGS = \ $(DBUS_CFLAGS) virt_p2v_LDADD = \ - $(top_builddir)/common/utils/libutils.la \ - $(top_builddir)/common/miniexpect/libminiexpect.la \ $(PCRE_LIBS) \ $(LIBXML2_LIBS) \ $(GTK_LIBS) \ $(DBUS_LIBS) \ - ../gnulib/lib/libgnu.la \ + gnulib/lib/libgnu.a \ -lm $(generated_sources) virt-p2v-kernel-config.pod: $(srcdir)/generate-p2v-config.pl @@ -157,7 +169,7 @@ dependencies_files = \ dependencies.redhat \ dependencies.suse -$(dependencies_files): dependencies.m4 ../config.status +$(dependencies_files): dependencies.m4 config.status define=`echo $@ | $(SED) 's/dependencies.//;y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`; \ m4 -D$$define=1 -DGTK_VERSION=$(GTK_VERSION) $< > $@-t mv $@-t $@ @@ -239,8 +251,12 @@ PHYSICAL_MACHINE = $(abs_builddir)/fedora.img BLANK_DISK = blank-part.img check_DATA = \ + $(NULL) +if HAVE_LIBGUESTFS +check_DATA += \ $(PHYSICAL_MACHINE) \ $(BLANK_DISK) +endif HAVE_LIBGUESTFS run-virt-p2v-directly: $(PHYSICAL_MACHINE) $(top_builddir)/run virt-p2v --test-disk=$(PHYSICAL_MACHINE) @@ -290,15 +306,15 @@ TESTS = \ test-virt-p2v-cmdline.sh \ test-virt-p2v-docs.sh -APPLIANCE_TESTS = \ +LIBGUESTFS_TESTS = \ test-virt-p2v.sh \ test-virt-p2v-nbdkit.sh -if ENABLE_APPLIANCE +if HAVE_LIBGUESTFS TESTS += \ - $(APPLIANCE_TESTS) \ + $(LIBGUESTFS_TESTS) \ $(SLOW_TESTS) -endif ENABLE_APPLIANCE +endif HAVE_LIBGUESTFS check-valgrind: make VG="@VG@" check diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..fcdd0ce --- /dev/null +++ b/autogen.sh @@ -0,0 +1,51 @@ +#!/bin/bash - +# libguestfs +# Copyright (C) 2009 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. +# +# Rebuild the autotools environment. + +set -e +set -v + +# Ensure that whenever we pull in a gnulib update or otherwise change to a +# different version (i.e., when switching branches), we also rerun ./bootstrap. +curr_status=.git-module-status +t=$(git submodule status|sed 's/^[ +-]//;s/ .*//') +if test "$t" = "$(cat $curr_status 2>/dev/null)"; then + : # good, it's up to date +else + echo running bootstrap... + ./bootstrap && echo "$t" > $curr_status +fi + +CONFIGUREDIR=. + +# Run configure in BUILDDIR if it's set +if [ ! -z "$BUILDDIR" ]; then + mkdir -p $BUILDDIR + cd $BUILDDIR + + CONFIGUREDIR=.. +fi + +# If no arguments were specified and configure has run before, use the previous +# arguments +if test $# -eq 0 && test -x ./config.status; then + ./config.status --recheck +else + $CONFIGUREDIR/configure "$@" +fi diff --git a/bootstrap b/bootstrap new file mode 100755 index 0000000..db9c8e1 --- /dev/null +++ b/bootstrap @@ -0,0 +1,124 @@ +#!/bin/sh + +usage() { + echo >&2 "\ +Usage: $0 [OPTION]... +Bootstrap this package from the checked-out sources. + +Options: + --gnulib-srcdir=DIRNAME specify the local directory where gnulib + sources reside. Use this if you already + have gnulib sources on your machine, and + do not want to waste your bandwidth downloading + them again. Defaults to \$GNULIB_SRCDIR +" +} + +for option +do + case $option in + --help) + usage + exit;; + --gnulib-srcdir=*) + GNULIB_SRCDIR=${option#--gnulib-srcdir=};; + *) + echo >&2 "$0: $option: unknown option" + exit 1;; + esac +done + +cleanup_gnulib() { + status=$? + rm -fr "$gnulib_path" + exit $status +} + +git_modules_config () { + test -f .gitmodules && git config --file .gitmodules "$@" +} + +gnulib_path=$(git_modules_config submodule.gnulib.path) +test -z "$gnulib_path" && gnulib_path=gnulib + +# Get gnulib files. Populate $GNULIB_SRCDIR, possibly updating a +# submodule, for use in the rest of the script. + +case ${GNULIB_SRCDIR--} in +-) + if git_modules_config submodule.gnulib.url >/dev/null; then + echo "$0: getting gnulib files..." + git submodule init -- "$gnulib_path" || exit $? + git submodule update -- "$gnulib_path" || exit $? + + elif [ ! -d "$gnulib_path" ]; then + echo "$0: getting gnulib files..." + + trap cleanup_gnulib 1 2 13 15 + + shallow+ git clone -h 2>&1 | grep -- --depth > /dev/null && shallow='--depth 2' + git clone $shallow git://git.sv.gnu.org/gnulib "$gnulib_path" || + cleanup_gnulib + + trap - 1 2 13 15 + fi + GNULIB_SRCDIR=$gnulib_path + ;; +*) + # Use GNULIB_SRCDIR directly or as a reference. + if test -d "$GNULIB_SRCDIR"/.git && \ + git_modules_config submodule.gnulib.url >/dev/null; then + echo "$0: getting gnulib files..." + if git submodule -h|grep -- --reference > /dev/null; then + # Prefer the one-liner available in git 1.6.4 or newer. + git submodule update --init --reference "$GNULIB_SRCDIR" \ + "$gnulib_path" || exit $? + else + # This fallback allows at least git 1.5.5. + if test -f "$gnulib_path"/gnulib-tool; then + # Since file already exists, assume submodule init already complete. + git submodule update -- "$gnulib_path" || exit $? + else + # Older git can't clone into an empty directory. + rmdir "$gnulib_path" 2>/dev/null + git clone --reference "$GNULIB_SRCDIR" \ + "$(git_modules_config submodule.gnulib.url)" "$gnulib_path" \ + && git submodule init -- "$gnulib_path" \ + && git submodule update -- "$gnulib_path" \ + || exit $? + fi + fi + GNULIB_SRCDIR=$gnulib_path + fi + ;; +esac + +gnulib_tool=$GNULIB_SRCDIR/gnulib-tool +<$gnulib_tool || exit + +modules=' +c-ctype +error +getprogname +ignore-value +manywarnings +ptsname_r +sys_types +xstrtoll +' + +# If any tests fail, avoid including them by adding them to +# this list. +avoid="" + +$gnulib_tool \ + $avoid \ + --with-tests \ + --m4-base=m4 \ + --source-base=gnulib/lib \ + --tests-base=gnulib/tests \ + --import $modules + +# Disable autopoint, since it was already done above. +AUTOPOINT=true autoreconf --verbose --install diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..dbd46cb --- /dev/null +++ b/configure.ac @@ -0,0 +1,109 @@ +# 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. + +# The major, minor, and release fields MUST be numbers. Packagers can +# add extra information using --with-extra="..." which may be any +# freeform string. +m4_define([p2v_major], [1]) +m4_define([p2v_minor], [40]) +m4_define([p2v_release], [0]) + +AC_INIT([virt-p2v],p2v_major.p2v_minor.p2v_release) + +# Headings within the configure script output. +m4_define([HEADING], + [AS_ECHO + AS_ECHO(["--- $1 ---"])]) + +AC_CONFIG_AUX_DIR([build-aux]) + +AC_USE_SYSTEM_EXTENSIONS + +dnl Initialize automake. +AM_INIT_AUTOMAKE(foreign subdir-objects tar-pax) dnl NB: Do not [quote] this parameter. + +m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])]) +AM_SILENT_RULES([yes]) # make --enable-silent-rules the default. + +AC_CONFIG_MACRO_DIR([m4]) + +dnl Extra string, a freeform string defined by packagers. +AC_ARG_WITH([extra], + [AS_HELP_STRING([--with-extra], + [extra version string (for use by packagers)])], + [p2v_extra="$withval"], + [p2v_extra=] +) + +AC_MSG_NOTICE([virt-p2v version p2v_major.p2v_minor.p2v_release$p2v_extra]) + +dnl Split up the version string. +AC_DEFINE([PACKAGE_VERSION_MAJOR],[p2v_major],[Major version number.]) +AC_DEFINE([PACKAGE_VERSION_MINOR],[p2v_minor],[Minor version number.]) +AC_DEFINE([PACKAGE_VERSION_RELEASE],[p2v_release],[Release number.]) +AC_DEFINE_UNQUOTED([PACKAGE_VERSION_EXTRA],["$p2v_extra"],[Extra version string.]) +PACKAGE_VERSION_FULL="p2v_major.p2v_minor.p2v_release${p2v_extra}" +AC_DEFINE_UNQUOTED([PACKAGE_VERSION_FULL],["$PACKAGE_VERSION_FULL"],[Full version string.]) +AC_SUBST([PACKAGE_VERSION_FULL]) + +dnl Early gnulib initialization. +HEADING([Configuring Gnulib]) +gl_EARLY +gl_INIT + +dnl Check for external programs required to either build or run +dnl virt-p2v. +HEADING([Checking for external programs]) +m4_include([m4/p2v-progs.m4]) + +dnl The C compiler environment. +HEADING([Checking for the C compiler environment]) +m4_include([m4/p2v-c.m4]) + +dnl Any C libraries required by virt-p2v. +HEADING([Checking for libraries used by virt-p2v]) +m4_include([m4/p2v-libraries.m4]) + +dnl All the programs used for tests. +HEADING([Checking for programs for tests]) +m4_include([m4/p2v-tests.m4]) + +dnl Produce output files. +HEADING([Generating output files]) + +AC_CONFIG_HEADERS([config.h]) + +dnl http://www.mail-archive.com/automake@gnu.org/msg10204.html +AC_CONFIG_FILES([virt-p2v-make-disk], + [chmod +x,-w virt-p2v-make-disk]) +AC_CONFIG_FILES([virt-p2v-make-kickstart], + [chmod +x,-w virt-p2v-make-kickstart]) +AC_CONFIG_FILES([virt-p2v-make-kiwi], + [chmod +x,-w virt-p2v-make-kiwi]) +AC_CONFIG_FILES([podwrapper.pl], + [chmod +x,-w podwrapper.pl]) +AC_CONFIG_FILES([run], + [chmod +x,-w run]) + +AC_CONFIG_FILES([Makefile + gnulib/lib/Makefile + gnulib/tests/Makefile]) + +AC_CONFIG_COMMANDS([p2v-config.h], + [${ac_srcdir}/generate-p2v-config.pl --file=p2v-config.h --output=p2v-config.h]) + +AC_OUTPUT diff --git a/m4/p2v-c.m4 b/m4/p2v-c.m4 new file mode 100644 index 0000000..e3d045f --- /dev/null +++ b/m4/p2v-c.m4 @@ -0,0 +1,179 @@ +# libguestfs +# 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. + +dnl The C compiler environment. +dnl Define the host CPU architecture (defines 'host_cpu') +AC_CANONICAL_HOST + +dnl Check for basic C environment. +AC_PROG_CC_STDC +AC_PROG_INSTALL +AC_PROG_CPP + +AC_ARG_ENABLE([werror], + [AS_HELP_STRING([--enable-werror], + [turn GCC warnings into errors (for developers)])], + [case $enableval in + yes|no) ;; + *) AC_MSG_ERROR([bad value $enableval for werror option]) ;; + esac + gl_gcc_werror=$enableval], + [gl_gcc_werror=no] +) + +if test "$gl_gcc_werror" = yes; then + gl_WARN_ADD([-Werror], [WERROR_CFLAGS]) + AC_SUBST([WERROR_CFLAGS]) +fi + +dnl This, $nw, is the list of warnings we disable. +nw+nw="$nw -Waggregate-return" # anachronistic +nw="$nw -Wundef" # Warns on '#if GNULIB_FOO' etc in gnulib +nw="$nw -Wtraditional" # Warns on #elif which we use often +nw="$nw -Wsystem-headers" # Don't let system headers trigger warnings +nw="$nw -Wpadded" # Our structs are not padded +nw="$nw -Wvla" # Allow variable length arrays. +nw="$nw -Wvla-larger-than=4031" +nw="$nw -Winline" # inline functions in Python binding +nw="$nw -Wshadow" # Not useful, as it applies to global vars +nw="$nw -Wunsafe-loop-optimizations" # just a warning that an optimization + # was not possible, safe to ignore +nw="$nw -Wstack-protector" # Useless warning when stack protector + # cannot being used in a function. +nw="$nw -Wcast-align" # Useless warning on arm >= 7, intel +nw="$nw -Wabi" # Broken in GCC 8.1. +dnl things I might fix soon: +nw="$nw -Wpacked" # Allow attribute((packed)) on structs +nw="$nw -Wlong-long" # Allow long long since it's required + # by Python, Ruby and xstrtoll. +nw="$nw -Wsuggest-attribute=pure" # Don't suggest pure functions. +nw="$nw -Wsuggest-attribute=const" # Don't suggest const functions. +nw="$nw -Wsuggest-attribute=malloc" # Don't suggest malloc functions. +nw="$nw -Wunsuffixed-float-constants" # Don't care about these. +nw="$nw -Wswitch-default" # This warning is actively dangerous. +nw="$nw -Woverlength-strings" # Who cares about stupid ISO C99 limit. + +gl_MANYWARN_ALL_GCC([ws]) +gl_MANYWARN_COMPLEMENT([ws], [$ws], [$nw]) +for w in $ws; do + gl_WARN_ADD([$w]) +done + +dnl Normally we disable warnings in $nw above. However $nw only +dnl filters out exact matching warning strings from a list inside +dnl gnulib (see m4/manywarnings.m4). So we need to explicitly list a +dnl few disabled warnings below. + +dnl Unused parameters are not a bug. +gl_WARN_ADD([-Wno-unused-parameter]) + +dnl Missing field initializers is not a bug in C. +gl_WARN_ADD([-Wno-missing-field-initializers]) + +dnl Display the name of the warning option with the warning. +gl_WARN_ADD([-fdiagnostics-show-option]) + +dnl Now some warnings we want to enable and/or customize ... + +dnl Warn about large stack frames. This does not include alloca and +dnl variable length arrays. Coverity warns about 10000 byte frames. +gl_WARN_ADD([-Wframe-larger-than=5000]) + +dnl Warn about large stack frames, including estimates for alloca +dnl and variable length arrays. +dnl gl_WARN_ADD([-Wstack-usage=10000]) + +dnl Warn about implicit fallthrough in case statements, but suppress +dnl the warning if /*FALLTHROUGH*/ comment is used. +gl_WARN_ADD([-Wimplicit-fallthrough=4]) + +dnl GCC level 2 gives incorrect warnings, so use level 1. +gl_WARN_ADD([-Wformat-truncation=1]) + +dnl GCC 9 at level 2 gives apparently bogus errors when %.*s is used. +gl_WARN_ADD([-Wformat-overflow=1]) + +AC_SUBST([WARN_CFLAGS]) + +AC_DEFINE([lint], [1], [Define to 1 if the compiler is checking for lint.]) +AC_DEFINE([GNULIB_PORTCHECK], [1], [Enable some gnulib portability checks.]) + +AC_C_PROTOTYPES +test "x$U" != "x" && AC_MSG_ERROR([Compiler not ANSI compliant]) + +AM_PROG_CC_C_O + +# Provide a global place to set CFLAGS. (Note that setting AM_CFLAGS +# is no use because it doesn't override target_CFLAGS). +#--- +# Kill -fstrict-overflow which is a license for the C compiler to make +# dubious and often unsafe optimizations, in a time-wasting attempt to +# deal with CPU architectures that do not exist. +CFLAGS="$CFLAGS -fno-strict-overflow -Wno-strict-overflow" + +dnl Check support for 64 bit file offsets. +AC_SYS_LARGEFILE + +dnl Check sizeof long. +AC_CHECK_SIZEOF([long]) + +dnl Check if __attribute__((cleanup(...))) works. +dnl Set -Werror, otherwise gcc will only emit a warning for attributes +dnl that it doesn't understand. +acx_nbdkit_save_CFLAGS="${CFLAGS}" +CFLAGS="${CFLAGS} -Werror" +AC_MSG_CHECKING([if __attribute__((cleanup(...))) works with this compiler]) +AC_COMPILE_IFELSE([ +AC_LANG_SOURCE([[ +#include <stdio.h> +#include <stdlib.h> + +void +freep (void *ptr) +{ + exit (EXIT_SUCCESS); +} + +void +test (void) +{ + __attribute__((cleanup(freep))) char *ptr = malloc (100); +} + +int +main (int argc, char *argv[]) +{ + test (); + exit (EXIT_FAILURE); +} +]]) + ],[ + AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_ATTRIBUTE_CLEANUP],[1],[Define to 1 if '__attribute__((cleanup(...)))' works with this compiler.]) + ],[ + AC_MSG_WARN( +['__attribute__((cleanup(...)))' does not work. + +You may not be using a sufficiently recent version of GCC or CLANG, or +you may be using a C compiler which does not support this attribute, +or the configure test may be wrong. + +The code will still compile, but is likely to leak memory and other +resources when it runs.])]) +dnl restore CFLAGS +CFLAGS="${acx_nbdkit_save_CFLAGS}" diff --git a/m4/p2v-libraries.m4 b/m4/p2v-libraries.m4 new file mode 100644 index 0000000..3f85958 --- /dev/null +++ b/m4/p2v-libraries.m4 @@ -0,0 +1,79 @@ +# libguestfs +# 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. + +dnl Any C libraries required by virt-p2v. + +dnl Define a C symbol for the host CPU architecture. +AC_DEFINE_UNQUOTED([host_cpu],["$host_cpu"],[Host architecture.]) + +dnl Headers. +AC_CHECK_HEADERS([\ + linux/rtc.h]) + +dnl Which header file defines major, minor, makedev. +AC_HEADER_MAJOR + +dnl Check for PCRE (required) +PKG_CHECK_MODULES([PCRE], [libpcre], [], [ + AC_CHECK_PROGS([PCRE_CONFIG], [pcre-config pcre2-config], [no]) + AS_IF([test "x$PCRE_CONFIG" = "xno"], [ + AC_MSG_ERROR([Please install the pcre devel package]) + ]) + PCRE_CFLAGS=`$PCRE_CONFIG --cflags` + PCRE_LIBS=`$PCRE_CONFIG --libs` +]) + +dnl libxml2 (required) +PKG_CHECK_MODULES([LIBXML2], [libxml-2.0]) + +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]) +]) diff --git a/m4/p2v-progs.m4 b/m4/p2v-progs.m4 new file mode 100644 index 0000000..d54b391 --- /dev/null +++ b/m4/p2v-progs.m4 @@ -0,0 +1,63 @@ +# libguestfs +# 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. + +# Check for external programs required to either build or run +# virt-p2v. +# +# AC_CHECK_PROG(S) or AC_PATH_PROG(S)? +# +# Use AC_CHECK_PROG(S) for programs which are only used during build. +# +# Use AC_PATH_PROG(S) for program names which are compiled into the +# binary and used at run time. The reason is so that we know which +# programs the binary actually uses. + +# Define $(SED). +m4_ifdef([AC_PROG_SED],[ + AC_PROG_SED +],[ + dnl ... else hope for the best + AC_SUBST([SED], "sed") +]) + +# Define $(AWK). +AC_PROG_AWK + +AC_PROG_LN_S + +dnl Check for perl (required). +AC_CHECK_PROG([PERL],[perl],[perl],[no]) +test "x$PERL" = "xno" && + AC_MSG_ERROR([perl must be installed]) + +dnl Check for Pod::Man, Pod::Simple (for man pages). +AC_MSG_CHECKING([for Pod::Man]) +if ! $PERL -MPod::Man -e1 >&AS_MESSAGE_LOG_FD 2>&1; then + AC_MSG_ERROR([perl Pod::Man must be installed]) +else + AC_MSG_RESULT([yes]) +fi +AC_MSG_CHECKING([for Pod::Simple]) +if ! $PERL -MPod::Simple -e1 >&AS_MESSAGE_LOG_FD 2>&1; then + AC_MSG_ERROR([perl Pod::Simple must be installed]) +else + AC_MSG_RESULT([yes]) +fi + +dnl Define the path to the podwrapper program. +PODWRAPPER="\$(guestfs_am_v_podwrapper)$PERL $(pwd)/podwrapper.pl" +AC_SUBST([PODWRAPPER]) diff --git a/m4/p2v-tests.m4 b/m4/p2v-tests.m4 new file mode 100644 index 0000000..f679bc4 --- /dev/null +++ b/m4/p2v-tests.m4 @@ -0,0 +1,45 @@ +# libguestfs +# 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. + +dnl Should we run the gnulib tests? +AC_MSG_CHECKING([if we should run the GNUlib tests]) +AC_ARG_ENABLE([gnulib-tests], + [AS_HELP_STRING([--disable-gnulib-tests], + [disable running GNU Portability library tests @<:@default=yes@:>@])], + [ENABLE_GNULIB_TESTS="$enableval"], + [ENABLE_GNULIB_TESTS=yes]) +AM_CONDITIONAL([ENABLE_GNULIB_TESTS],[test "x$ENABLE_GNULIB_TESTS" = "xyes"]) +AC_MSG_RESULT([$ENABLE_GNULIB_TESTS]) + +dnl Check libguestfs tools (needed for create the test images). +AC_CHECK_PROG([GUESTFISH],[guestfish],[guestfish],[no]) +AC_CHECK_PROG([VIRT_BUILDER],[virt-builder],[virt-builder],[no]) +AM_CONDITIONAL([HAVE_LIBGUESTFS], + [test "x$GUESTFISH" != "xno" && test "x$VIRT_BUILDER" != "xno"]) + +dnl Check for valgrind +AC_CHECK_PROG([VALGRIND],[valgrind],[valgrind],[no]) +AS_IF([test "x$VALGRIND" != "xno"],[ + # Substitute the whole valgrind command. + # --read-inline-info=no is a temporary workaround for RHBZ#1662656. + VG='$(VALGRIND) --vgdb=no --log-file=$(abs_top_builddir)/valgrind-%q{T}-%p.log --leak-check=full --error-exitcode=119 --suppressions=$(abs_top_srcdir)/valgrind-suppressions --trace-children=no --child-silent-after-fork=yes --run-libc-freeres=no --read-inline-info=no' + ],[ + # No valgrind, so substitute VG with something that will break. + VG=VALGRIND_IS_NOT_INSTALLED +]) +AC_SUBST([VG]) +AM_SUBST_NOTMAKE([VG]) diff --git a/podcheck.pl b/podcheck.pl new file mode 100755 index 0000000..527a2e4 --- /dev/null +++ b/podcheck.pl @@ -0,0 +1,273 @@ +#!/usr/bin/env perl +# podcheck.pl +# Copyright (C) 2016 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use warnings; +use strict; + +use Pod::Usage; +use Getopt::Long; +use Pod::Man; + +=head1 NAME + +podcheck.pl - Compare man page and tools to check all arguments are documented + +=head1 SYNOPSIS + + podcheck.pl virt-foo.pod ./virt-foo [--ignore=--arg,--arg,...] + +=head1 DESCRIPTION + +This script compares a manual page (eg. C<virt-foo.pod>) and the +corresponding tool (eg. C<./virt-foo>) and checks that each command +line argument is documented in the manual, and that there is no rogue +documentation for arguments which do not exist. It works by running +the tool with the standard C<--long-options> and C<--short-options> +parameters and comparing their output with the man page. + +You can also ignore options, in case this script gets things wrong or +if there are options that you don't intend to document. + +=head1 OPTIONS + +=over 4 + +=cut + +my $help; + +=item B<--help> + +Display brief help. + +=cut + +my $ignore = ""; + +=item B<--ignore=--arg,--arg,...> + +Ignore the comma-separated list of arguments given. + +=cut + +my @inserts; + +=item B<--insert filename:__PATTERN__> + +This works like the L<podwrapper.pl(1)> I<--insert> option and should be +used where the POD includes patterns which podwrapper would substitute. + +=cut + +my @verbatims; + +=item B<--verbatim filename:__PATTERN__> + +This works like the podwrapper I<--verbatim> option and should be +used where the POD includes patterns which podwrapper would substitute. + +=cut + +# Clean up the program name. +my $progname = $0; +$progname =~ s{.*/}{}; + +# Parse options. +GetOptions ("help|?" => \$help, + "ignore=s" => \$ignore, + "insert=s" => \@inserts, + "verbatim=s" => \@verbatims, + ) or pod2usage (2); +pod2usage (1) if $help; + +die "$progname: missing argument: podcheck.pl input.pod tool\n" + unless @ARGV == 2; +my $input = $ARGV[0]; +my $tool = $ARGV[1]; + +my %ignore = (); +$ignore{$_} = 1 foreach (split /,/, $ignore); + +# Open the man page and slurp it in. +my $content = read_whole_file ($input); + +# Perform @inserts. +foreach (@inserts) { + my @a = split /:/, $_, 2; + die "$progname: $input: no colon in parameter of --insert\n" unless @a >= 2; + my $replacement = read_whole_file ($a[0]); + my $oldcontent = $content; + $content =~ s/$a[1]/$replacement/ge; + die "$progname: $input: could not find pattern '$a[1]' in input file\n" + if $content eq $oldcontent; +} + +# Perform @verbatims. +foreach (@verbatims) { + my @a = split /:/, $_, 2; + die "$progname: $input: no colon in parameter of --verbatim\n" unless @a >= 2; + my $replacement = read_verbatim_file ($a[0]); + my $oldcontent = $content; + $content =~ s/$a[1]/$replacement/ge; + die "$progname: $input: could not find pattern '$a[1]' in input file\n" + if $content eq $oldcontent; +} + +# Run the tool with --long-options and --short-options. +my @tool_options = (); +open PIPE, "$tool --long-options |" + or die "$progname: $tool --long-options: $!"; +while (<PIPE>) { + chomp; + push @tool_options, $_; +} +close PIPE; +open PIPE, "$tool --short-options |" + or die "$progname: $tool --short-options: $!"; +while (<PIPE>) { + chomp; + push @tool_options, $_; +} +close PIPE; + +my %tool_option_exists = (); +$tool_option_exists{$_} = 1 foreach @tool_options; + +# There are some tool options which we automatically ignore. +delete $tool_option_exists{"--color"}; +delete $tool_option_exists{"--colour"}; +delete $tool_option_exists{"--debug-gc"}; + +# Run the tool with --help. +my $help_content; +open PIPE, "LANG=C $tool --help |" + or die "$progname: $tool --help: $!"; +{ + local $/ = undef; + $help_content = <PIPE>; +} +close PIPE; + +# Do the tests. +my $errors = 0; + +# Check each option exists in the manual. +my $tool_options_checked = 0; + +foreach (sort keys %tool_option_exists) { + unless ($ignore{$_}) { + $tool_options_checked++; + unless ($content =~ /^=item.*B<$_(?:=.*)?>/m) { + $errors++; + warn "$progname: $input does not define $_\n"; + } + } +} + +# Check there are no extra options defined in the manual which +# don't exist in the tool. +my $pod_options_checked = 0; + +my %pod_options = (); +$pod_options{$_} = 1 foreach ( $content =~ /^=item.*B<(-[-\w]+)(?:=.*)?>/gm ); +foreach (sort keys %pod_options) { + unless ($ignore{$_}) { + $pod_options_checked++; + unless (exists $tool_option_exists{$_}) { + $errors++; + warn "$progname: $input defines option $_ which does not exist in the tool\n" + } + } +} + +# Check the tool's --help output mentions all the options. (For OCaml +# tools this is a waste of time since the --help output is generated, +# but for C tools it is a genuine test). +my $help_options_checked = 0; + +my %help_options = (); +$help_options{$_} = 1 foreach ( $help_content =~ /(?<!\w)(-[-\w]+)/g ); + +# There are some help options which we automatically ignore. +delete $help_options{"--color"}; +delete $help_options{"--colour"}; +# "[--options]" is used as a placeholder for options in the synopsis +# text, so ignore it. +delete $help_options{"--options"}; + +foreach (sort keys %tool_option_exists) { + unless ($ignore{$_}) { + unless (exists $help_options{$_}) { + $errors++; + warn "$progname: $tool: option $_ does not appear in --help output\n" + } + } +} + +foreach (sort keys %help_options) { + unless ($ignore{$_}) { + $help_options_checked++; + unless (exists $tool_option_exists{$_}) { + $errors++; + warn "$progname: $tool: unknown option $_ appears in --help output\n" + } + } +} + +exit 1 if $errors > 0; + +printf "$progname: $tool: checked $tool_options_checked tool options, $pod_options_checked documented options, $help_options_checked help options\n"; + +exit 0; + +sub read_whole_file +{ + my $input = shift; + local $/ = undef; + + open FILE, $input or die "$progname: $input: $!"; + $_ = <FILE>; + close FILE; + $_; +} + +sub read_verbatim_file +{ + my $input = shift; + my $r = ""; + + open FILE, $input or die "$progname: $input: $!"; + while (<FILE>) { + $r .= " $_"; + } + close FILE; + $r; +} + +=head1 SEE ALSO + +L<podwrapper.pl(1)>, +libguestfs.git/README. + +=head1 AUTHOR + +Richard W.M. Jones. + +=head1 COPYRIGHT + +Copyright (C) 2016 Red Hat Inc. diff --git a/podwrapper.pl.in b/podwrapper.pl.in new file mode 100755 index 0000000..2b276c4 --- /dev/null +++ b/podwrapper.pl.in @@ -0,0 +1,678 @@ +#!/usr/bin/env perl +# podwrapper.pl +# Copyright (C) 2010-2019 Red Hat Inc. +# @configure_input@ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use warnings; +use strict; + +use Pod::Usage; +use Getopt::Long; +use Pod::Man; +use Pod::Simple; +use Pod::Simple::Text; +use Pod::Simple::XHTML; +use File::Basename; + +# https://www.redhat.com/archives/libguestfs/2013-May/thread.html#00088 +eval { $Text::Wrap::huge = "overflow" }; + +=head1 NAME + +podwrapper.pl - Generate libguestfs documentation from POD input files + +=head1 SYNOPSIS + + man_MANS = virt-foo.1 + + virt-foo.1 $(top_builddir)/website/virt-foo.1.html: stamp-virt-foo.pod + + stamp-virt-foo.pod: virt-foo.pod + $(PODWRAPPER) \ + --section 1 \ + --man virt-foo.1 \ + --html $(top_builddir)/website/virt-foo.1.html \ + --license GPLv2+ \ + --warning general \ + $< + touch $@ + +=head1 DESCRIPTION + +podwrapper.pl is a Perl script that generates various output formats +from POD input files that libguestfs uses for most documentation. + +You must specify one input file, and one or more output formats. The +output options are I<--man>, I<--html> and I<--text> (see below). + +In C<Makefile.am> files, use a variation of the boilerplate shown in +the L</SYNOPSIS> section above. + +For information about the POD format, see L<perlpod(1)>. + +=head1 OPTIONS + +=over 4 + +=cut + +my $help; + +=item B<--help> + +Display brief help. + +=cut + +my $html; + +=item B<--html output.html> + +Write a web page to C<output.html>. If this option is not +given, then no web page output is produced. + +=cut + +my @inserts; + +=item B<--insert filename:__PATTERN__> + +In the input file, replace the literal text C<__PATTERN__> with the +replacement file C<filename>. You can give this option multiple +times. + +The contents of C<filename> are treated as POD. +Compare and contrast with I<--verbatim>. + +Although it is conventional to use C<__...__> (double underscores) for +patterns, in fact you can use any string as the pattern. + +=cut + +my @licenses; + +=item B<--license GPLv2+> + +=item B<--license LGPLv2+> + +=item B<--license examples> + +Add the given license to the end of the man page. This parameter +is required. The parameter may be given multiple times (eg. for +mixed content). + +=cut + +my $man; + +=item B<--man output.n> + +Write a man page to C<output.n> (C<n> is the manual section number). +If this option is not given, then no man page output is produced. + +=cut + +my $name; + +=item B<--name name> + +Set the name of the man page. If not set, defaults to the basename +of the input file. + +=cut + +my $section; + +=item B<--section N> + +Set the section of the man page (a number such as C<1> for +command line utilities or C<3> for C API documentation). If +not set, defaults to C<1>. + +=cut + +my $strict_checks = 1; + +=item B<--no-strict-checks> + +Disable strict checks of the man page. This is only used +when generating the translated man pages in the C<po-docs> +subdirectory. + +=cut + +my $text; + +=item B<--text output.txt> + +Write a text file to C<output.txt>. If this option is not +given, then no text output is produced. + +=cut + +my @verbatims; + +=item B<--verbatim filename:__PATTERN__> + +In the input file, replace the literal text C<__PATTERN__> with the +replacement file C<filename>. You can give this option multiple +times. + +The contents of C<filename> are inserted as verbatim text, and +are I<not> interpreted as POD. +Compare and contrast with I<--insert>. + +Although it is conventional to use C<__...__> (double underscores) for +patterns, in fact you can use any string as the pattern. + +=cut + +my $warning = "not-set"; + +=item B<--warning general> + +=item B<--warning ro-option> + +Add a standard warning section near the top of the manual page, +warning the user not to use the tool in write mode or concurrently. + +There are two variations of the warning: The I<--warning ro-option> +variation should be used with tools such as L<guestfish(1)> which have +an I<--ro> option. The I<--warning general> variation should be used +with other tools that open the disk image for writes, with no +read-only option. + +=item B<--warning custom> + +Use I<--warning custom> if there is already a warning section in the +manual page. + +=item B<--warning safe> + +Use I<--warning safe> for tools which are safe, ie. only open disk +images in read-only mode, or just don't need a warning section. + +=back + +=cut + +# Clean up the program name. +my $progname = $0; +$progname =~ s{.*/}{}; + +# Parse options. +GetOptions ("help|?" => \$help, + "html=s" => \$html, + "license=s" => \@licenses, + "insert=s" => \@inserts, + "man=s" => \$man, + "name=s" => \$name, + "section=s" => \$section, + "strict-checks!" => \$strict_checks, + "text=s" => \$text, + "verbatim=s" => \@verbatims, + "warning=s" => \$warning, + ) or pod2usage (2); +pod2usage (1) if $help; + +die "$progname: missing argument: podwrapper input.pod\n" unless @ARGV == 1; +my $input = $ARGV[0]; + +die "$progname: $input: missing argument: --license parameter is required\n" + if $strict_checks && @licenses == 0; + +# There should be at least one output. +die "$progname: $input: no output format specified. Use --man and/or --html and/or --text.\n" + unless defined $man || defined $html || defined $text; + +# Default for $name and $section. +$name = basename ($input, ".pod") unless defined $name; +$section = 1 unless defined $section; + +# Is it a user command line tool? +my $cli_tool = $section == 1 && $name !~ /^guestfs-/; + +# Warning parameter is mandatory for user tools in section 1. +if ($strict_checks && $cli_tool) { + die "$progname: $input: missing argument: --warning parameter is missing or invalid\n" + unless $warning eq "general" || $warning eq "ro-option" || + $warning eq "custom" || $warning eq "safe"; +} + +# Note that these @...@ are substituted by ./configure. +my $abs_top_srcdir = "@abs_top_srcdir@"; +my $abs_top_builddir = "@abs_top_builddir@"; +my $package_name = "@PACKAGE_NAME@"; +my $package_version = "@PACKAGE_VERSION@"; + +die "$progname: ./configure substitutions were not performed" + unless $abs_top_srcdir && $abs_top_builddir && + $package_name && $package_version; + +# Create a stable date (thanks Hilko Bengen). +my $date; +my $filename = "$abs_top_srcdir/ChangeLog"; +if (-r $filename) { + open FILE, $filename or die "$progname: $filename: $!"; + while (<FILE>) { + if (/^Date:\s+...\s+(...)\s+(\d+)\s+..:..:..\s+(\d{4})\s+.*$/) { + my $i = 0; + my %month + map { $_ => ++$i } + (qw< Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec >); + $date = sprintf '%04d-%02d-%02d', $3, $month{$1}, $2; + last; + } + } + close FILE; +} +$filename = "$abs_top_srcdir/.git"; +if (!$date && -d $filename) { + local $ENV{GIT_DIR} = $filename; + $_ = `git show -s --format=%ci`; + $date = $1 if /^(\d+-\d+-\d+)\s/; +} +if (!$date) { + my ($day, $month, $year) = (localtime)[3,4,5]; + $date = sprintf ("%04d-%02d-%02d", $year+1900, $month+1, $day); +} + +# Create a release string. +my $release = "$package_name-$package_version"; + +#print "input=$input\n"; +#print "name=$name\n"; +#print "section=$section\n"; +#print "date=$date\n"; +#print "warning=$warning\n"; + +# Read the input. +my $content = read_whole_file ($input); + +# Perform @inserts. +foreach (@inserts) { + my @a = split /:/, $_, 2; + die "$progname: $input: no colon in parameter of --insert\n" unless @a >= 2; + my $replacement = read_whole_file ($a[0]); + my $oldcontent = $content; + $content =~ s/$a[1]/$replacement/ge; + die "$progname: $input: could not find pattern '$a[1]' in input file\n" + if $content eq $oldcontent; +} + +# Turn external links to this man page into simple cross-section links. +$content =~ s,\QL<$name($section)/\E,L</,g; + +# Perform @verbatims. +foreach (@verbatims) { + my @a = split /:/, $_, 2; + die "$progname: $input: no colon in parameter of --verbatim\n" unless @a >= 2; + my $replacement = read_verbatim_file ($a[0]); + my $oldcontent = $content; + $content =~ s/$a[1]/$replacement/ge; + die "$progname: $input: could not find pattern '$a[1]' in input file\n" + if $content eq $oldcontent; +} + +# There should be no =encoding line present in the content (we will add one). +die "$progname: $input: =encoding must not be present in input\n" + if $content =~ /^=encoding/m; + +$content =~ s/^=(.*)/\n=encoding utf8\n\n=$1/m; + +if ($strict_checks) { + # Verify sections present / not present. + die "$progname: $input: missing DESCRIPTION section\n" + if $cli_tool && $content !~ /^=head1 DESCRIPTION/m; + die "$progname: $input: missing AUTHOR or AUTHORS section\n" + unless $content =~ /^=head1 AUTHOR/m; + die "$progname: $input: missing SEE ALSO section\n" + unless $content =~ /^=head1 SEE ALSO/m; + die "$progname: $input: missing COPYRIGHT section\n" + unless $content =~ /^=head1 COPYRIGHT/m; + die "$progname: $input: BUGS is now added automatically, do not add it to the POD file\n" + if $content =~ /^=head1 (REPORTING )?BUGS/m; + die "$progname: $input: LICENSE is now added automatically, do not add it to the POD file\n" + if $content =~ /^=head1 LICENSE/m; + die "$progname: $input: GPL/LGPL should be specified using the --license parameter, not included in the POD file\n" + if $content =~ /^This program is free software/ || + $content =~ /^This library is free software/; + if ($warning eq "general" || $warning eq "ro-option" || + $warning eq "safe") { + die "$progname: $input: WARNING is now added automatically using the --warning parameter\n" + if $content =~ /^=head1 WARNING/m + } + elsif ($warning eq "custom") { + die "$progname: $input: missing WARNING section\n" + unless $content =~ /^=head1 WARNING/m; + } +} + +# Add standard LICENSE, BUGS and WARNING sections. +my $LGPLv2plus +"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 +"; + +my $GPLv2plus +"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. +"; + +my $examples_license +"This manual page contains examples which we hope you will use in +your programs. The examples may be freely copied, modified and +distributed for any purpose without any restrictions. +"; + +my $reporting_bugs +"=head1 BUGS + +To get a list of bugs against libguestfs, use this link: +L<https://bugzilla.redhat.com/buglist.cgi?component=libguestfs&product=Virtualization+Tools> + +To report a new bug against libguestfs, use this link: +L<https://bugzilla.redhat.com/enter_bug.cgi?component=libguestfs&product=Virtualization+Tools> + +When reporting a bug, please supply: + +\=over 4 + +\=item * + +The version of libguestfs. + +\=item * + +Where you got libguestfs (eg. which Linux distro, compiled from source, etc) + +\=item * + +Describe the bug accurately and give a way to reproduce it. + +\=item * + +Run L<libguestfs-test-tool(1)> and paste the B<complete, unedited> +output into the bug report. + +\=back +"; + +my $warning_general +"Using C<$name> +on live virtual machines, or concurrently with other +disk editing tools, can be dangerous, potentially causing disk +corruption. The virtual machine must be shut down before you use this +command, and disk images must not be edited concurrently."; + +my $warning_ro_option +"Using C<$name> in write mode +on live virtual machines, or concurrently with other +disk editing tools, can be dangerous, potentially causing disk +corruption. The virtual machine must be shut down before you use this +command, and disk images must not be edited concurrently. + +Use the I<--ro> (read-only) option to use C<$name> safely if the disk +image or virtual machine might be live. You may see strange or +inconsistent results if running concurrently with other changes, but +with this option you won't risk disk corruption."; + +$content .= "\n\n=head1 LICENSE\n\n"; + +foreach (@licenses) { + if ($_ eq "LGPLv2+") { + $content .= $LGPLv2plus . "\n\n"; + } + elsif ($_ eq "GPLv2+") { + $content .= $GPLv2plus . "\n\n"; + } + elsif ($_ eq "examples") { + $content .= $examples_license . "\n\n"; + } + else { + die "$progname: $input: invalid --license parameter: $_\n"; + } +} + +$content .= "\n\n$reporting_bugs"; + +if ($warning eq "general") { + $content =~ s/^=head1 DESCRIPTION/=head1 WARNING\n\n$warning_general\n\n=head1 DESCRIPTION/m or die; +} +elsif ($warning eq "ro-option") { + $content =~ s/^=head1 DESCRIPTION/=head1 WARNING\n\n$warning_ro_option\n\n=head1 DESCRIPTION/m or die; +} +# else do nothing for $warning "custom", "safe" or "not-set" + +# Output man page. +SUBMAN: { + package Podwrapper::Man; + + use vars qw(@ISA $VERSION); + @ISA = qw(Pod::Man); + $VERSION = $package_version; + + # Override the L<> method. + sub cmd_l + { + my ($self, $attrs, $text) = @_; + return $text; + } +} + +if ($man) { + my $parser = Podwrapper::Man->new ( + name => $name, + release => $release, section => $section, + center => "Virtualization Support", + date => $date, + stderr => 1, utf8 => 1 + ); + my $output; + $parser->no_errata_section (1); + $parser->complain_stderr (1); + $parser->output_string (\$output); + $parser->parse_string_document ($content) + or die "$progname: could not parse input document"; + open OUT, ">$man" or die "$progname: $man: $!"; + print OUT $output or die "$progname: $man: $!"; + close OUT or die "$progname: $man: $!"; + if ($parser->any_errata_seen) { + unlink $man; + die "$input: errors or warnings in this POD file, see messages above\n" + } + #print "$progname: wrote $man\n"; +} + +# Output HTML. +SUBHTML: { + # Subclass Pod::Simple::XHTML. See the documentation. + package Podwrapper::XHTML; + + use vars qw(@ISA $VERSION); + @ISA = qw(Pod::Simple::XHTML); + $VERSION = $package_version; + + # Pod::Simple::XHTML returns uppercase identifiers, whereas the + # old pod2html returns lowercase ones. + sub idify + { + my $self = shift; + my $id = $self->SUPER::idify (@_); + lc ($id); + } + + sub is_a_libguestfs_page + { + local $_ = shift; + + return 1 if /^Sys::Guestfs/; + return 0 if /^virt-install/; + return 1 if /^virt-/; + return 1 if /^libguestf/; + return 1 if /^guestf/; + return 1 if /^guestmount/; + return 1 if /^guestunmount/; + return 1 if /^hivex/; + return 1 if /^supermin/; + return 1 if /^nbdkit/; + return 0; + } + + sub resolve_pod_page_link + { + my $self = shift; + my $podname = $_[0]; # eg. "Sys::Guestfs", can be undef + my $anchor = $_[1]; # eg. "SYNOPSIS", can be undef + my $r = ""; + if (defined $podname) { + return $self->SUPER::resolve_pod_page_link (@_) + unless is_a_libguestfs_page ($podname); + $r .= "$podname.3.html" + } + $r .= "#" . $self->idify ($anchor, 1) if defined $anchor; + $r; + } + + sub resolve_man_page_link + { + my $self = shift; + my $name = $_[0]; # eg. "virt-make-fs(1)", can be undef + my $anchor = $_[1]; # eg. "SYNOPSIS", can be undef + my $r = ""; + if (defined $name) { + return $self->SUPER::resolve_man_page_link (@_) + unless is_a_libguestfs_page ($name); + $name =~ s/\((.*)\)$/.$1/; + $r .= "$name.html"; + } + $r .= "#" . $self->idify ($anchor, 1) if defined $anchor; + $r; + } + + # For some reason Pod::Simple::XHTML usually cannot find a + # title for the page. This defaults the HTML <title> field + # to the same as the man page name. + sub default_title { $name } +} + +if ($html) { + mkdir "$abs_top_builddir/website"; + + my $parser = Podwrapper::XHTML->new; + my $output; + $parser->no_errata_section (1); + $parser->complain_stderr (1); + $parser->output_string (\$output); + # Added in Pod::Simple 3.16, 2011-03-14. + eval { $parser->html_charset ("UTF-8") }; + $parser->html_css ("pod.css"); + $parser->index (1); + $parser->parse_string_document ($content); + + # Hack for Perl 5.16. + $output =~ s{/>pod.css<}{/>\n<}; + + open OUT, ">$html" or die "$progname: $html: $!"; + print OUT $output or die "$progname: $html: $!"; + close OUT or die "$progname: $html: $!"; + if ($parser->any_errata_seen) { + unlink $html; + die "$input: errors or warnings in this POD file, see messages above\n" + } + #print "$progname: wrote $html\n"; +} + +# Output text. +if ($text) { + my $parser = Pod::Simple::Text->new; + my $output; + $parser->no_errata_section (1); + $parser->complain_stderr (1); + $parser->output_string (\$output); + $parser->parse_string_document ($content); + open OUT, ">$text" or die "$progname: $text: $!"; + binmode OUT, ":utf8"; + print OUT $output or die "$progname: $text: $!"; + close OUT or die "$progname: $text: $!"; + if ($parser->any_errata_seen) { + unlink $text; + die "$input: errors or warnings in this POD file, see messages above\n" + } + #print "$progname: wrote $text\n"; +} + +sub read_whole_file +{ + my $input = shift; + local $/ = undef; + + open FILE, $input or die "$progname: $input: $!"; + $_ = <FILE>; + close FILE; + $_; +} + +sub read_verbatim_file +{ + my $input = shift; + my $r = ""; + + open FILE, $input or die "$progname: $input: $!"; + while (<FILE>) { + $r .= " $_"; + } + close FILE; + $r; +} + +=head1 SEE ALSO + +L<perlpod(1)>, +L<Pod::Simple(3pm)>, +libguestfs.git/README. + +=head1 AUTHOR + +Richard W.M. Jones. + +=head1 COPYRIGHT + +Copyright (C) 2012-2019 Red Hat Inc. diff --git a/run.in b/run.in new file mode 100755 index 0000000..a3def1d --- /dev/null +++ b/run.in @@ -0,0 +1,118 @@ +#!/bin/bash - +# libguestfs 'run' programs locally script +# Copyright (C) 2011-2019 Red Hat Inc. +# +# @configure_input@ +# +# 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 + +#---------------------------------------------------------------------- + +# With this script you can run all the virt tools without needing to +# install them first. You just have to do for example: +# +# ./run virt-inspector [args ...] +# +# This works for any C program, virt tools, and most non-C bindings +# and programs in the libguestfs distribution. +# +# For lots more ways to use this script, see the libguestfs +# guestfs-building(1) man page. +# +# The script should also be used for tests like this: +# +# TESTS_ENVIRONMENT = ... $(top_builddir)/run --test +# +# The --test parameter introduces a timeout, stopping tests from +# running forever. + +#---------------------------------------------------------------------- + +if [ "$1" = "--test" ]; then + timeout_mode=1 + shift +fi + +# Function to intelligently prepend a path to an environment variable. +# See http://stackoverflow.com/a/9631350 +prepend() +{ + eval $1="$2\${$1:+:\$$1}" +} + +# Source and build directories (absolute paths so this works from any +# directory). +s="$(cd @abs_srcdir@ && pwd)" +b="$(cd @abs_builddir@ && pwd)" + +# Set T to current date & time (mainly for valgrind logfile name). +T=`date +%Y%m%d.%H.%M.%S` +export T + +prepend PATH "$b" +export PATH + +# virt-p2v-make-* data directory. +if [ -z "$VIRT_P2V_DATA_DIR" ]; then + VIRT_P2V_DATA_DIR="$s" + export VIRT_P2V_DATA_DIR +fi + +# This is a cheap way to find some use-after-free and uninitialized +# read problems when using glibc. +random_val="$(@AWK@ 'BEGIN{srand(); print 1+int(255*rand())}' < /dev/null)" +export MALLOC_PERTURB_=$random_val + +# Avoid GNOME keyring stupidity +export GNOME_KEYRING_CONTROL+export GNOME_KEYRING_PID+ +# Run the program. +if [ -z "$timeout_mode" ]; then + exec "$@" +fi + +# For tests (./run --test): +# - timeout if the test takes too long to run + +# Originally 1h, but that is not long enough to run the C API +# tests on Koji. +timeout_period=4h +timeout_kill=30s + +# Must use the --foreground option (RHBZ#1025269). +if timeout --foreground 2 sleep 0 >/dev/null 2>&1; then + # Does this version of timeout have the -k option? (Not on RHEL 6) + if timeout -k 10s 10s true >/dev/null 2>&1; then + timeout="timeout --foreground -k $timeout_kill $timeout_period" + fi +fi + +$timeout "$@" +fail=$? +if [ "$fail" -eq 0 ]; then + # Test successful. + : +elif [ "$fail" -eq 77 ]; then + # Tests return 77 to mean skipped. + : +elif [ "$fail" -eq 124 ]; then + # Timed out. + echo "$b/run: command timed out after $timeout_period" +else + # Test failed. + echo "$b/run: command failed with exit code $fail" +fi +exit $fail diff --git a/subdir-rules.mk b/subdir-rules.mk new file mode 100644 index 0000000..ce05874 --- /dev/null +++ b/subdir-rules.mk @@ -0,0 +1,60 @@ +# libguestfs +# Copyright (C) 2013 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# subdir-rules.mk should be included in every *subdirectory* Makefile.am. + +# Editor backup files +CLEANFILES = *~ *.bak + +# Patch original and reject files. +CLEANFILES += *.orig *.rej + +# Manual pages - these are all generated from *.pod, so the +# pages themselves should all be removed by 'make clean'. +CLEANFILES += *.1 *.3 *.5 *.8 + +# Stamp files used when generating man pages. +CLEANFILES += stamp-*.pod + +# Files that should be universally removed by 'make distclean'. +DISTCLEANFILES = stamp-* + +# custom silent rules +guestfs_am_v_podwrapper = $(guestfs_am_v_podwrapper_@AM_V@) +guestfs_am_v_podwrapper_ = $(guestfs_am_v_podwrapper_@AM_DEFAULT_V@) +guestfs_am_v_podwrapper_0 = @echo " POD " $@; + +# Test shell scripts should use '$TEST_FUNCTIONS' to get a predefined +# set of helper functions for running tests (see +# tests/test-functions.sh). +# +# Notes: +# +# (1) This is in fact a single command all on one line. The variables +# are evaluated in test-functions.sh. +# +# (2) We use absolute paths here and in test-functions.sh so that the +# test can change directory freely. But we also include the +# non-absolute values so they can be used by the test script itself. +export TEST_FUNCTIONS := \ + source $(abs_top_srcdir)/test-functions.sh \ + abs_srcdir="$(abs_srcdir)" \ + abs_builddir="$(abs_builddir)" \ + top_srcdir="$(top_srcdir)" \ + top_builddir="$(top_builddir)" \ + abs_top_srcdir="$(abs_top_srcdir)" \ + abs_top_builddir="$(abs_top_builddir)" diff --git a/test-functions.sh b/test-functions.sh new file mode 100755 index 0000000..609b356 --- /dev/null +++ b/test-functions.sh @@ -0,0 +1,120 @@ +#!/bin/bash - +# libguestfs +# Copyright (C) 2014-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. + +# Most of the tests written in shell script source this file for +# useful functions. +# +# To include this file, the test must do: +# +# $TEST_FUNCTIONS +# +# (this macro is defined in subdir-rules.mk). + +# Clean up the environment in every test script. +unset CDPATH +export LANG=C + +# When test-functions.sh is invoked, a list of variables is passed as +# parameters, so we eval those to define the variables. +while [ $# -ge 1 ]; do eval "$1"; shift; done + +# Skip if $SKIP_<script_name> environment variable is set. +# Every test should call this function first. +skip_if_skipped () +{ + local v + if [ -n "$1" ]; then + v="SKIP_$(basename $1 | tr a-z.- A-Z__)" + else + v="SKIP_$(basename $0 | tr a-z.- A-Z__)" + fi + if [ -n "${!v}" ]; then + echo "$(basename $0): test skipped because \$$v is set" + exit 77 + fi + echo "$(basename $0): info: you can skip this test by setting $v=1" +} + +# Skip if the current libguestfs backend is $1. +# eg. skip_if_backend uml +skip_if_backend () +{ + local b="$(guestfish get-backend)" + case "$1" in + # Some magic happens for $1 == libvirt. + libvirt) + if [ "$b" = "libvirt" ] || [[ "$b" =~ ^libvirt: ]]; then + echo "$(basename $0): test skipped because the current backend is $b" + exit 77 + fi + ;; + *) + if [ "$b" = "$1" ]; then + echo "$(basename $0): test skipped because the current backend is $b" + exit 77 + fi + ;; + esac +} + +# Skip if the current arch != $1. +skip_unless_arch () +{ + local m="$(uname -m)" + case "$1" in + # Some magic happens for some architectures. + arm) + if [[ ! "$m" =~ ^arm ]]; then + echo "$(basename $0): test skipped because the current architecture ($m) is not arm (32 bit)" + exit 77 + fi + ;; + i?86) + if [[ ! "$m" =~ ^i?86 ]]; then + echo "$(basename $0): test skipped because the current architecture ($m) is not $1" + exit 77 + fi + ;; + *) + if [ "$m" != "$1" ]; then + echo "$(basename $0): test skipped because the current architecture ($m) is not $1" + exit 77 + fi + ;; + esac +} + +# Run an external command and skip if the command fails. This can be +# used to test if a command exists. Normally you should use +# `cmd --help' or `cmd --version' or similar. +skip_unless () +{ + if ! "$@"; then + echo "$(basename $0): test skipped because $1 is not available" + exit 77 + fi +} + +# Slow tests should always call this function. (See guestfs-hacking(1)). +slow_test () +{ + if [ -z "$SLOW" ]; then + echo "$(basename $0): use 'make check-slow' to run this test" + exit 77 + fi +} -- 2.21.0
Add all the generated files to it. --- .gitignore | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.gitignore b/.gitignore index 8495f6c..e1d27b7 100644 --- a/.gitignore +++ b/.gitignore @@ -3,20 +3,35 @@ *.o *.trs .deps +.dirstamp .libs Makefile Makefile.in +/.git-module-status /about-authors.c +/aclocal.m4 +/autom4te.cache/ /blank-part.img +/build-aux/ /config.c +/config.h +/config.h.in +/config.status +/configure /dependencies.archlinux /dependencies.debian /dependencies.redhat /dependencies.suse /fedora.img +/gnulib/ /kernel-config.c +/m4/.gitignore +/m4/gnulib-cache.m4 /p2v-config.h +/podwrapper.pl +/run +/stamp-h1 /stamp-test-virt-p2v-pxe-data-files /stamp-test-virt-p2v-pxe-hostkey /stamp-test-virt-p2v-pxe-kernel @@ -46,3 +61,4 @@ Makefile.in /virt-p2v-make-kiwi /virt-p2v-make-kiwi.1 /virt-p2v.xz +/website/*.html -- 2.21.0
Pino Toscano
2019-Jul-09 15:50 UTC
Re: [Libguestfs] [PATCH 0/5] Split virt-p2v in own repository
On Tuesday, 9 July 2019 16:05:13 CEST Pino Toscano wrote:> The approach taken was to run a script (will send separately) to just > get the "p2v" subdirectory with its history as own repository, and then > add in few followup commits all the bits needed to build.Attached is the script I used. -- Pino Toscano
Richard W.M. Jones
2019-Jul-10 10:17 UTC
Re: [Libguestfs] [PATCH 0/5] Split virt-p2v in own repository
Yes this is all fine. Where are we going to put the new repository? Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com libguestfs lets you edit virtual machines. Supports shell scripting, bindings from many languages. http://libguestfs.org
Seemingly Similar Threads
- Re: [PATCH 0/5] Split virt-p2v in own repository
- Re: [PATCH] p2v: Allow virt-v2v input and output drivers containing '-' (RHBZ#1590220).
- Re: 1.39 proposal: Let's split up the libguestfs git repo and tarballs
- Re: [PATCH 0/5] Split virt-p2v in own repository
- Re: [PATCH] p2v: Allow virt-v2v input and output drivers containing '-' (RHBZ#1590220).