import libguestfs-1.40.2-25.module+el8.3.0+7421+642fe24f

This commit is contained in:
CentOS Sources 2020-11-03 06:58:07 -05:00 committed by Andrew Lukoshko
parent efeedb8128
commit 893b57ed4a
151 changed files with 7594 additions and 9111 deletions

4
.gitignore vendored
View File

@ -1,4 +1,4 @@
SOURCES/RHEV-Application-Provisioning-Tool.exe_4.43-3
SOURCES/libguestfs-1.38.4.tar.gz
SOURCES/RHEV-Application-Provisioning-Tool.exe_4.43-5
SOURCES/libguestfs-1.40.2.tar.gz
SOURCES/libguestfs.keyring
SOURCES/rhsrvany.exe

View File

@ -1,4 +1,4 @@
ac8722917cc31c36836e241bd7a4beb5f8a8b0c8 SOURCES/RHEV-Application-Provisioning-Tool.exe_4.43-3
15c8f487ee163374cb7be9436fb1bb697cef7d9e SOURCES/libguestfs-1.38.4.tar.gz
130adbc011dc0af736465b813c2b22a600c128c1 SOURCES/RHEV-Application-Provisioning-Tool.exe_4.43-5
45755f0f73b503790974484053ff482f32665b13 SOURCES/libguestfs-1.40.2.tar.gz
1bbc40f501a7fef9eef2a39b701a71aee2fea7c4 SOURCES/libguestfs.keyring
2bd96e478fc004cd323b5bd754c856641877dac6 SOURCES/rhsrvany.exe

View File

@ -1,974 +0,0 @@
From 21f0a22072f0543c416c440665bcf75ae09e6233 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Mon, 12 Feb 2018 11:24:06 +0100
Subject: [PATCH] Switch from YAJL to Jansson
While YAJL mostly works fine, it did not see any active development in
the last 3 years. OTOH, Jansson is another JSON C implementation, with
a very liberal license, and a much nicer API.
Hence, switch all of libguestfs from YAJL to Jansson:
- configure checks, and buildsystem in general
- packages pulled in the appliance
- actual implementations
- contrib scripts
- documentation
This also makes use of the better APIs available (e.g. json_object_get,
json_array_foreach, and json_object_foreach). This does not change the
API of our OCaml Yajl module.
(cherry picked from commit bd1c5c9f4dcf38458099db8a0bf4659a07ef055d)
---
appliance/packagelist.in | 13 ++--
builder/Makefile.am | 4 +-
builder/yajl-c.c | 66 ++++++++--------
contrib/p2v/aux-scripts/do-build.sh | 8 +-
contrib/p2v/build-p2v-iso.sh | 3 +-
daemon/Makefile.am | 4 +-
daemon/ldm.c | 115 ++++++++++++----------------
docs/guestfs-building.pod | 2 +-
lib/Makefile.am | 4 +-
lib/info.c | 113 +++++++++++----------------
lib/qemu.c | 64 ++++++----------
m4/guestfs-libraries.m4 | 4 +-
12 files changed, 169 insertions(+), 231 deletions(-)
diff --git a/appliance/packagelist.in b/appliance/packagelist.in
index 8ded2588a..f92a6ce95 100644
--- a/appliance/packagelist.in
+++ b/appliance/packagelist.in
@@ -35,6 +35,7 @@ ifelse(REDHAT,1,
hivex
iproute
iputils
+ jansson
kernel
libcap
libldm
@@ -51,7 +52,6 @@ ifelse(REDHAT,1,
systemd dnl for /sbin/reboot and udevd
vim-minimal
xz
- yajl
yara
zfs-fuse
)
@@ -82,12 +82,12 @@ dnl iproute has been renamed to iproute2
libc-bin
libcap2
libhivex0
+ libjansson4
libpcre3
libsystemd0
libsystemd-id128-0
libsystemd-journal0
libtirpc1
- libyajl2
libyara3
linux-image
dnl syslinux 'suggests' mtools, but in reality it's a hard dependency:
@@ -116,6 +116,7 @@ ifelse(ARCHLINUX,1,
hivex
iproute2
iputils
+ jansson
libcap
libtirpc
linux
@@ -131,7 +132,6 @@ ifelse(ARCHLINUX,1,
systemd
vim
xz
- yajl
yara
)
@@ -153,9 +153,9 @@ ifelse(SUSE,1,
iputils
libcap2
libhivex0
+ libjansson4
libselinux1
libtirpc3
- libyajl2
libyara3
mkisofs
ntfsprogs
@@ -177,6 +177,7 @@ ifelse(FRUGALWARE,1,
hfsplus
iproute2
iputils
+ jansson
kernel
libcap
libtirpc
@@ -188,7 +189,6 @@ ifelse(FRUGALWARE,1,
systemd
vim
xz
- yajl
xfsprogs-acl
xfsprogs-attr
gptfdisk
@@ -209,9 +209,9 @@ ifelse(MAGEIA,1,
iproute2
iputils
libcap
+ libjansson4
libldm
libtirpc
- libyajl
dnl syslinux uses mtools without depending on it
mtools
nilfs-utils
@@ -224,7 +224,6 @@ ifelse(MAGEIA,1,
systemd /* for /sbin/reboot and udevd */
vim-minimal
xz
- yajl
)
acl
diff --git a/builder/Makefile.am b/builder/Makefile.am
index e5872bdd9..c7b50778a 100644
--- a/builder/Makefile.am
+++ b/builder/Makefile.am
@@ -157,7 +157,7 @@ virt_builder_CFLAGS = \
$(LIBLZMA_CFLAGS) \
$(LIBTINFO_CFLAGS) \
$(LIBXML2_CFLAGS) \
- $(YAJL_CFLAGS)
+ $(JANSSON_CFLAGS)
BOBJECTS = $(SOURCES_ML:.ml=.cmo)
XOBJECTS = $(BOBJECTS:.cmo=.cmx)
@@ -211,7 +211,7 @@ OCAMLCLIBS = \
$(LIBCRYPT_LIBS) \
$(LIBLZMA_LIBS) \
$(LIBXML2_LIBS) \
- $(YAJL_LIBS) \
+ $(JANSSON_LIBS) \
$(LIBINTL) \
-lgnu
diff --git a/builder/yajl-c.c b/builder/yajl-c.c
index 3c2402e42..e53755f55 100644
--- a/builder/yajl-c.c
+++ b/builder/yajl-c.c
@@ -23,24 +23,17 @@
#include <caml/memory.h>
#include <caml/mlvalues.h>
-#include <yajl/yajl_tree.h>
+#include <jansson.h>
#include <stdio.h>
#include <string.h>
-/* GCC can't work out that the YAJL_IS_<foo> test is sufficient to
- * ensure that YAJL_GET_<foo> later doesn't return NULL.
- */
-#if defined(__GNUC__) && __GNUC__ >= 6 /* gcc >= 6 */
-#pragma GCC diagnostic ignored "-Wnull-dereference"
-#endif
-
#define Val_none (Val_int (0))
value virt_builder_yajl_tree_parse (value stringv);
static value
-convert_yajl_value (yajl_val val, int level)
+convert_json_t (json_t *val, int level)
{
CAMLparam0 ();
CAMLlocal4 (rv, lv, v, sv);
@@ -48,46 +41,51 @@ convert_yajl_value (yajl_val val, int level)
if (level > 20)
caml_invalid_argument ("too many levels of object/array nesting");
- if (YAJL_IS_OBJECT (val)) {
- const size_t len = YAJL_GET_OBJECT(val)->len;
+ if (json_is_object (val)) {
+ const size_t len = json_object_size (val);
size_t i;
+ const char *key;
+ json_t *jvalue;
rv = caml_alloc (1, 3);
lv = caml_alloc_tuple (len);
- for (i = 0; i < len; ++i) {
+ i = 0;
+ json_object_foreach (val, key, jvalue) {
v = caml_alloc_tuple (2);
- sv = caml_copy_string (YAJL_GET_OBJECT(val)->keys[i]);
+ sv = caml_copy_string (key);
Store_field (v, 0, sv);
- sv = convert_yajl_value (YAJL_GET_OBJECT(val)->values[i], level + 1);
+ sv = convert_json_t (jvalue, level + 1);
Store_field (v, 1, sv);
Store_field (lv, i, v);
+ ++i;
}
Store_field (rv, 0, lv);
- } else if (YAJL_IS_ARRAY (val)) {
- const size_t len = YAJL_GET_ARRAY(val)->len;
+ } else if (json_is_array (val)) {
+ const size_t len = json_array_size (val);
size_t i;
+ json_t *jvalue;
rv = caml_alloc (1, 4);
lv = caml_alloc_tuple (len);
- for (i = 0; i < len; ++i) {
- v = convert_yajl_value (YAJL_GET_ARRAY(val)->values[i], level + 1);
+ json_array_foreach (val, i, jvalue) {
+ v = convert_json_t (jvalue, level + 1);
Store_field (lv, i, v);
}
Store_field (rv, 0, lv);
- } else if (YAJL_IS_STRING (val)) {
+ } else if (json_is_string (val)) {
rv = caml_alloc (1, 0);
- v = caml_copy_string (YAJL_GET_STRING(val));
+ v = caml_copy_string (json_string_value (val));
Store_field (rv, 0, v);
- } else if (YAJL_IS_DOUBLE (val)) {
+ } else if (json_is_real (val)) {
rv = caml_alloc (1, 2);
- v = caml_copy_double (YAJL_GET_DOUBLE(val));
+ v = caml_copy_double (json_real_value (val));
Store_field (rv, 0, v);
- } else if (YAJL_IS_INTEGER (val)) {
+ } else if (json_is_integer (val)) {
rv = caml_alloc (1, 1);
- v = caml_copy_int64 (YAJL_GET_INTEGER(val));
+ v = caml_copy_int64 (json_integer_value (val));
Store_field (rv, 0, v);
- } else if (YAJL_IS_TRUE (val)) {
+ } else if (json_is_true (val)) {
rv = caml_alloc (1, 5);
Store_field (rv, 0, Val_true);
- } else if (YAJL_IS_FALSE (val)) {
+ } else if (json_is_false (val)) {
rv = caml_alloc (1, 5);
Store_field (rv, 0, Val_false);
} else
@@ -101,21 +99,21 @@ virt_builder_yajl_tree_parse (value stringv)
{
CAMLparam1 (stringv);
CAMLlocal1 (rv);
- yajl_val tree;
- char error_buf[256];
+ json_t *tree;
+ json_error_t err;
- tree = yajl_tree_parse (String_val (stringv), error_buf, sizeof error_buf);
+ tree = json_loads (String_val (stringv), JSON_DECODE_ANY, &err);
if (tree == NULL) {
- char buf[256 + sizeof error_buf];
- if (strlen (error_buf) > 0)
- snprintf (buf, sizeof buf, "JSON parse error: %s", error_buf);
+ char buf[256 + JSON_ERROR_TEXT_LENGTH];
+ if (strlen (err.text) > 0)
+ snprintf (buf, sizeof buf, "JSON parse error: %s", err.text);
else
snprintf (buf, sizeof buf, "unknown JSON parse error");
caml_invalid_argument (buf);
}
- rv = convert_yajl_value (tree, 1);
- yajl_tree_free (tree);
+ rv = convert_json_t (tree, 1);
+ json_decref (tree);
CAMLreturn (rv);
}
diff --git a/contrib/p2v/aux-scripts/do-build.sh b/contrib/p2v/aux-scripts/do-build.sh
index 5edb53d0e..dd6424bb4 100644
--- a/contrib/p2v/aux-scripts/do-build.sh
+++ b/contrib/p2v/aux-scripts/do-build.sh
@@ -53,8 +53,8 @@ case $osversion in
# This just forces configure to ignore these missing dependencies.
export LIBTINFO_CFLAGS=-D_GNU_SOURCE
export LIBTINFO_LIBS=-lncurses
- export YAJL_CFLAGS=-D_GNU_SOURCE
- export YAJL_LIBS=-lyajl
+ export JANSSON_CFLAGS=-D_GNU_SOURCE
+ export JANSSON_LIBS=-ljansson
# Remove some unsupported flags that the configure script hard codes.
sed -i -e 's/-fno-strict-overflow//' configure
sed -i -e 's/-Wno-strict-overflow//' configure
@@ -66,8 +66,8 @@ case $osversion in
# This just forces configure to ignore these missing dependencies.
export LIBTINFO_CFLAGS=-D_GNU_SOURCE
export LIBTINFO_LIBS=-lncurses
- export YAJL_CFLAGS=-D_GNU_SOURCE
- export YAJL_LIBS=-lyajl
+ export JANSSON_CFLAGS=-D_GNU_SOURCE
+ export JANSSON_LIBS=-ljansson
;;
esac
diff --git a/contrib/p2v/build-p2v-iso.sh b/contrib/p2v/build-p2v-iso.sh
index c80a1b134..ae25cebc8 100755
--- a/contrib/p2v/build-p2v-iso.sh
+++ b/contrib/p2v/build-p2v-iso.sh
@@ -86,7 +86,6 @@ done
# Various hacks for different versions of RHEL.
if=virtio
netdev=virtio-net-pci
-pkgs="$pkgs,yajl-devel"
declare -a epel
case $osversion in
rhel-5.*|centos-5.*)
@@ -105,10 +104,12 @@ case $osversion in
rhel-6.*|centos-6.*)
epel[0]="--run-command"
epel[1]="yum install -y --nogpgcheck https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm"
+ pkgs="$pkgs,jansson-devel"
;;
rhel-7.*|centos-7.*)
epel[0]="--run-command"
epel[1]="yum install -y --nogpgcheck https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm"
+ pkgs="$pkgs,jansson-devel"
;;
esac
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 6240f517d..d9ed5625e 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -218,7 +218,7 @@ guestfsd_LDADD = \
camldaemon.o \
$(ACL_LIBS) \
$(CAP_LIBS) \
- $(YAJL_LIBS) \
+ $(JANSSON_LIBS) \
$(SELINUX_LIBS) \
$(AUGEAS_LIBS) \
$(HIVEX_LIBS) \
@@ -256,7 +256,7 @@ guestfsd_CFLAGS = \
$(AUGEAS_CFLAGS) \
$(HIVEX_CFLAGS) \
$(SD_JOURNAL_CFLAGS) \
- $(YAJL_CFLAGS) \
+ $(JANSSON_CFLAGS) \
$(PCRE_CFLAGS)
# Parts of the daemon are written in OCaml. These are linked into a
diff --git a/daemon/ldm.c b/daemon/ldm.c
index 2f4d2aef3..be4fb9701 100644
--- a/daemon/ldm.c
+++ b/daemon/ldm.c
@@ -25,19 +25,12 @@
#include <sys/stat.h>
#include <string.h>
-#include <yajl/yajl_tree.h>
+#include <jansson.h>
#include "daemon.h"
#include "actions.h"
#include "optgroups.h"
-/* GCC can't work out that the YAJL_IS_<foo> test is sufficient to
- * ensure that YAJL_GET_<foo> later doesn't return NULL.
- */
-#if defined(__GNUC__) && GUESTFS_GCC_VERSION >= 60000 /* gcc >= 6 */
-#pragma GCC diagnostic ignored "-Wnull-dereference"
-#endif
-
int
optgroup_ldm_available (void)
{
@@ -72,44 +65,42 @@ do_ldmtool_remove_all (void)
return 0;
}
-static yajl_val
+static json_t *
parse_json (const char *json, const char *func)
{
- yajl_val tree;
- char parse_error[1024];
+ json_t *tree;
+ json_error_t err;
if (verbose)
fprintf (stderr, "%s: parsing json: %s\n", func, json);
- tree = yajl_tree_parse (json, parse_error, sizeof parse_error);
+ tree = json_loads (json, 0, &err);
if (tree == NULL) {
reply_with_error ("parse error: %s",
- strlen (parse_error) ? parse_error : "unknown error");
+ strlen (err.text) ? err.text : "unknown error");
return NULL;
}
- /* Caller should free this by doing 'yajl_tree_free (tree);'. */
+ /* Caller should free this by doing 'json_decref (tree);'. */
return tree;
}
#define TYPE_ERROR ((char **) -1)
static char **
-json_value_to_string_list (yajl_val node)
+json_value_to_string_list (json_t *node)
{
CLEANUP_FREE_STRINGSBUF DECLARE_STRINGSBUF (strs);
- yajl_val n;
- size_t i, len;
+ json_t *n;
+ size_t i;
- if (! YAJL_IS_ARRAY (node))
+ if (!json_is_array (node))
return TYPE_ERROR;
- len = YAJL_GET_ARRAY (node)->len;
- for (i = 0; i < len; ++i) {
- n = YAJL_GET_ARRAY (node)->values[i];
- if (! YAJL_IS_STRING (n))
+ json_array_foreach (node, i, n) {
+ if (!json_is_string (n))
return TYPE_ERROR;
- if (add_string (&strs, YAJL_GET_STRING (n)) == -1)
+ if (add_string (&strs, json_string_value (n)) == -1)
return NULL;
}
if (end_stringsbuf (&strs) == -1)
@@ -123,14 +114,14 @@ parse_json_get_string_list (const char *json,
const char *func, const char *cmd)
{
char **ret;
- yajl_val tree = NULL;
+ json_t *tree = NULL;
tree = parse_json (json, func);
if (tree == NULL)
return NULL;
ret = json_value_to_string_list (tree);
- yajl_tree_free (tree);
+ json_decref (tree);
if (ret == TYPE_ERROR) {
reply_with_error ("output of '%s' was not a JSON array of strings", cmd);
return NULL;
@@ -144,43 +135,40 @@ static char *
parse_json_get_object_string (const char *json, const char *key, int flags,
const char *func, const char *cmd)
{
- char *str, *ret;
- yajl_val tree = NULL, node;
- size_t i, len;
+ const char *str;
+ char *ret;
+ json_t *tree = NULL, *node;
tree = parse_json (json, func);
if (tree == NULL)
return NULL;
- if (! YAJL_IS_OBJECT (tree))
+ if (!json_is_object (tree))
+ goto bad_type;
+
+ node = json_object_get (tree, key);
+ if (node == NULL)
goto bad_type;
- len = YAJL_GET_OBJECT (tree)->len;
- for (i = 0; i < len; ++i) {
- if (STREQ (YAJL_GET_OBJECT (tree)->keys[i], key)) {
- node = YAJL_GET_OBJECT (tree)->values[i];
-
- if ((flags & GET_STRING_NULL_TO_EMPTY) && YAJL_IS_NULL (node))
- ret = strdup ("");
- else {
- str = YAJL_GET_STRING (node);
- if (str == NULL)
- goto bad_type;
- ret = strdup (str);
- }
- if (ret == NULL)
- reply_with_perror ("strdup");
-
- yajl_tree_free (tree);
-
- return ret;
- }
+ if ((flags & GET_STRING_NULL_TO_EMPTY) && json_is_null (node))
+ ret = strdup ("");
+ else {
+ str = json_string_value (node);
+ if (str == NULL)
+ goto bad_type;
+ ret = strndup (str, json_string_length (node));
}
+ if (ret == NULL)
+ reply_with_perror ("strdup");
+
+ json_decref (tree);
+
+ return ret;
bad_type:
reply_with_error ("output of '%s' was not a JSON object "
"containing a key '%s' of type string", cmd, key);
- yajl_tree_free (tree);
+ json_decref (tree);
return NULL;
}
@@ -189,33 +177,30 @@ parse_json_get_object_string_list (const char *json, const char *key,
const char *func, const char *cmd)
{
char **ret;
- yajl_val tree, node;
- size_t i, len;
+ json_t *tree, *node;
tree = parse_json (json, func);
if (tree == NULL)
return NULL;
- if (! YAJL_IS_OBJECT (tree))
+ if (!json_is_object (tree))
goto bad_type;
- len = YAJL_GET_OBJECT (tree)->len;
- for (i = 0; i < len; ++i) {
- if (STREQ (YAJL_GET_OBJECT (tree)->keys[i], key)) {
- node = YAJL_GET_OBJECT (tree)->values[i];
- ret = json_value_to_string_list (node);
- if (ret == TYPE_ERROR)
- goto bad_type;
- yajl_tree_free (tree);
- return ret;
- }
- }
+ node = json_object_get (tree, key);
+ if (node == NULL)
+ goto bad_type;
+
+ ret = json_value_to_string_list (node);
+ if (ret == TYPE_ERROR)
+ goto bad_type;
+ json_decref (tree);
+ return ret;
bad_type:
reply_with_error ("output of '%s' was not a JSON object "
"containing a key '%s' of type array of strings",
cmd, key);
- yajl_tree_free (tree);
+ json_decref (tree);
return NULL;
}
diff --git a/docs/guestfs-building.pod b/docs/guestfs-building.pod
index d350b1d73..2029429fd 100644
--- a/docs/guestfs-building.pod
+++ b/docs/guestfs-building.pod
@@ -172,7 +172,7 @@ I<Required>.
I<Required>.
-=item yajl E<ge> 2.0.4
+=item Jansson
I<Required>.
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 91c4e0a2e..d075174d9 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -141,7 +141,7 @@ libguestfs_la_CFLAGS = \
$(PCRE_CFLAGS) \
$(LIBVIRT_CFLAGS) \
$(LIBXML2_CFLAGS) \
- $(YAJL_CFLAGS)
+ $(JANSSON_CFLAGS)
libguestfs_la_LIBADD = \
../common/errnostring/liberrnostring.la \
@@ -152,7 +152,7 @@ libguestfs_la_LIBADD = \
$(PCRE_LIBS) \
$(LIBVIRT_LIBS) $(LIBXML2_LIBS) \
$(SELINUX_LIBS) \
- $(YAJL_LIBS) \
+ $(JANSSON_LIBS) \
../gnulib/lib/libgnu.la \
$(GETADDRINFO_LIB) \
$(HOSTENT_LIB) \
diff --git a/lib/info.c b/lib/info.c
index 93fadcd39..2eadc1c11 100644
--- a/lib/info.c
+++ b/lib/info.c
@@ -37,53 +37,46 @@
#include <sys/resource.h>
#endif
-#include <yajl/yajl_tree.h>
+#include <jansson.h>
#include "guestfs.h"
#include "guestfs-internal.h"
#include "guestfs-internal-actions.h"
#ifdef HAVE_ATTRIBUTE_CLEANUP
-#define CLEANUP_YAJL_TREE_FREE __attribute__((cleanup(cleanup_yajl_tree_free)))
+#define CLEANUP_JSON_T_DECREF __attribute__((cleanup(cleanup_json_t_decref)))
static void
-cleanup_yajl_tree_free (void *ptr)
+cleanup_json_t_decref (void *ptr)
{
- yajl_tree_free (* (yajl_val *) ptr);
+ json_decref (* (json_t **) ptr);
}
#else
-#define CLEANUP_YAJL_TREE_FREE
+#define CLEANUP_JSON_T_DECREF
#endif
-static yajl_val get_json_output (guestfs_h *g, const char *filename);
+static json_t *get_json_output (guestfs_h *g, const char *filename);
static void set_child_rlimits (struct command *);
char *
guestfs_impl_disk_format (guestfs_h *g, const char *filename)
{
- size_t i, len;
- CLEANUP_YAJL_TREE_FREE yajl_val tree = get_json_output (g, filename);
+ CLEANUP_JSON_T_DECREF json_t *tree = get_json_output (g, filename);
+ json_t *node;
if (tree == NULL)
return NULL;
- if (! YAJL_IS_OBJECT (tree))
+ if (!json_is_object (tree))
goto bad_type;
- len = YAJL_GET_OBJECT(tree)->len;
- for (i = 0; i < len; ++i) {
- if (STREQ (YAJL_GET_OBJECT(tree)->keys[i], "format")) {
- const char *str;
- yajl_val node = YAJL_GET_OBJECT(tree)->values[i];
- if (YAJL_IS_NULL (node))
- goto bad_type;
- str = YAJL_GET_STRING (node);
- if (str == NULL)
- goto bad_type;
- return safe_strdup (g, str); /* caller frees */
- }
- }
+ node = json_object_get (tree, "format");
+ if (!json_is_string (node))
+ goto bad_type;
+
+ return safe_strndup (g, json_string_value (node),
+ json_string_length (node)); /* caller frees */
bad_type:
error (g, _("qemu-img info: JSON output did not contain format key"));
@@ -93,30 +86,20 @@ guestfs_impl_disk_format (guestfs_h *g, const char *filename)
int64_t
guestfs_impl_disk_virtual_size (guestfs_h *g, const char *filename)
{
- size_t i, len;
- CLEANUP_YAJL_TREE_FREE yajl_val tree = get_json_output (g, filename);
+ CLEANUP_JSON_T_DECREF json_t *tree = get_json_output (g, filename);
+ json_t *node;
if (tree == NULL)
return -1;
- if (! YAJL_IS_OBJECT (tree))
+ if (!json_is_object (tree))
goto bad_type;
- len = YAJL_GET_OBJECT(tree)->len;
- for (i = 0; i < len; ++i) {
- if (STREQ (YAJL_GET_OBJECT(tree)->keys[i], "virtual-size")) {
- yajl_val node = YAJL_GET_OBJECT(tree)->values[i];
- if (YAJL_IS_NULL (node))
- goto bad_type;
- if (! YAJL_IS_NUMBER (node))
- goto bad_type;
- if (! YAJL_IS_INTEGER (node)) {
- error (g, _("qemu-img info: virtual-size is not representable as a 64 bit integer"));
- return -1;
- }
- return YAJL_GET_INTEGER (node);
- }
- }
+ node = json_object_get (tree, "virtual-size");
+ if (!json_is_integer (node))
+ goto bad_type;
+
+ return json_integer_value (node);
bad_type:
error (g, _("qemu-img info: JSON output did not contain virtual-size key"));
@@ -126,29 +109,25 @@ guestfs_impl_disk_virtual_size (guestfs_h *g, const char *filename)
int
guestfs_impl_disk_has_backing_file (guestfs_h *g, const char *filename)
{
- size_t i, len;
- CLEANUP_YAJL_TREE_FREE yajl_val tree = get_json_output (g, filename);
+ CLEANUP_JSON_T_DECREF json_t *tree = get_json_output (g, filename);
+ json_t *node;
if (tree == NULL)
return -1;
- if (! YAJL_IS_OBJECT (tree))
+ if (!json_is_object (tree))
goto bad_type;
- len = YAJL_GET_OBJECT(tree)->len;
- for (i = 0; i < len; ++i) {
- if (STREQ (YAJL_GET_OBJECT(tree)->keys[i], "backing-filename")) {
- yajl_val node = YAJL_GET_OBJECT(tree)->values[i];
- /* Work on the assumption that if this field is null, it means
- * no backing file, rather than being an error.
- */
- if (YAJL_IS_NULL (node))
- return 0;
- return 1;
- }
- }
+ node = json_object_get (tree, "backing-filename");
+ if (node == NULL)
+ return 0; /* no backing-filename key means no backing file */
- return 0; /* no backing-filename key means no backing file */
+ /* Work on the assumption that if this field is null, it means
+ * no backing file, rather than being an error.
+ */
+ if (json_is_null (node))
+ return 0;
+ return 1;
bad_type:
error (g, _("qemu-img info: JSON output was not an object"));
@@ -161,12 +140,12 @@ guestfs_impl_disk_has_backing_file (guestfs_h *g, const char *filename)
static void parse_json (guestfs_h *g, void *treevp, const char *input, size_t len);
#define PARSE_JSON_NO_OUTPUT ((void *) -1)
-static yajl_val
+static json_t *
get_json_output (guestfs_h *g, const char *filename)
{
CLEANUP_CMD_CLOSE struct command *cmd = guestfs_int_new_command (g);
int r;
- yajl_val tree = NULL;
+ json_t *tree = NULL;
guestfs_int_cmd_add_arg (cmd, "qemu-img");
guestfs_int_cmd_add_arg (cmd, "info");
@@ -196,16 +175,15 @@ get_json_output (guestfs_h *g, const char *filename)
return NULL;
}
- return tree; /* caller must call yajl_tree_free (tree) */
+ return tree; /* caller must call json_decref (tree) */
}
/* Parse the JSON document printed by qemu-img info --output json. */
static void
parse_json (guestfs_h *g, void *treevp, const char *input, size_t len)
{
- yajl_val *tree_ret = treevp;
- CLEANUP_FREE char *input_copy = NULL;
- char parse_error[256];
+ json_t **tree_ret = treevp;
+ json_error_t err;
assert (*tree_ret == NULL);
@@ -218,15 +196,12 @@ parse_json (guestfs_h *g, void *treevp, const char *input, size_t len)
return;
}
- /* 'input' is not \0-terminated; we have to make it so. */
- input_copy = safe_strndup (g, input, len);
-
- debug (g, "%s: qemu-img info JSON output:\n%s\n", __func__, input_copy);
+ debug (g, "%s: qemu-img info JSON output:\n%.*s\n", __func__, (int) len, input);
- *tree_ret = yajl_tree_parse (input_copy, parse_error, sizeof parse_error);
+ *tree_ret = json_loadb (input, len, 0, &err);
if (*tree_ret == NULL) {
- if (strlen (parse_error) > 0)
- error (g, _("qemu-img info: JSON parse error: %s"), parse_error);
+ if (strlen (err.text) > 0)
+ error (g, _("qemu-img info: JSON parse error: %s"), err.text);
else
error (g, _("qemu-img info: unknown JSON parse error"));
}
diff --git a/lib/qemu.c b/lib/qemu.c
index 6159b5a52..a50eca988 100644
--- a/lib/qemu.c
+++ b/lib/qemu.c
@@ -37,7 +37,7 @@
#include <libxml/uri.h>
-#include <yajl/yajl_tree.h>
+#include <jansson.h>
#include "full-write.h"
#include "ignore-value.h"
@@ -57,7 +57,7 @@ struct qemu_data {
/* The following fields are derived from the fields above. */
struct version qemu_version; /* Parsed qemu version number. */
- yajl_val qmp_schema_tree; /* qmp_schema parsed into a JSON tree */
+ json_t *qmp_schema_tree; /* qmp_schema parsed into a JSON tree */
};
static char *cache_filename (guestfs_h *g, const char *cachedir, const struct stat *, const char *suffix);
@@ -73,7 +73,7 @@ static int write_cache_qmp_schema (guestfs_h *g, const struct qemu_data *data, c
static int read_cache_qemu_stat (guestfs_h *g, struct qemu_data *data, const char *filename);
static int write_cache_qemu_stat (guestfs_h *g, const struct qemu_data *data, const char *filename);
static void parse_qemu_version (guestfs_h *g, const char *, struct version *qemu_version);
-static void parse_json (guestfs_h *g, const char *, yajl_val *);
+static void parse_json (guestfs_h *g, const char *, json_t **);
static void read_all (guestfs_h *g, void *retv, const char *buf, size_t len);
static int generic_read_cache (guestfs_h *g, const char *filename, char **strp);
static int generic_write_cache (guestfs_h *g, const char *filename, const char *str);
@@ -405,17 +405,17 @@ parse_qemu_version (guestfs_h *g, const char *qemu_help,
* is not possible.
*/
static void
-parse_json (guestfs_h *g, const char *json, yajl_val *treep)
+parse_json (guestfs_h *g, const char *json, json_t **treep)
{
- char parse_error[256] = "";
+ json_error_t err;
if (!json)
return;
- *treep = yajl_tree_parse (json, parse_error, sizeof parse_error);
+ *treep = json_loads (json, 0, &err);
if (*treep == NULL) {
- if (strlen (parse_error) > 0)
- debug (g, "QMP parse error: %s (ignored)", parse_error);
+ if (strlen (err.text) > 0)
+ debug (g, "QMP parse error: %s (ignored)", err.text);
else
debug (g, "QMP unknown parse error (ignored)");
}
@@ -580,17 +580,6 @@ guestfs_int_qemu_supports_device (guestfs_h *g,
return strstr (data->qemu_devices, device_name) != NULL;
}
-/* GCC can't work out that the YAJL_IS_<foo> test is sufficient to
- * ensure that YAJL_GET_<foo> later doesn't return NULL.
- */
-#pragma GCC diagnostic push
-#if defined(__GNUC__) && __GNUC__ >= 6 /* gcc >= 6 */
-#pragma GCC diagnostic ignored "-Wnull-dereference"
-#endif
-#if defined(__GNUC__) && GUESTFS_GCC_VERSION >= 40800 /* gcc >= 4.8.0 */
-#pragma GCC diagnostic ignored "-Wnonnull"
-#endif
-
/**
* Test if the qemu binary uses mandatory file locking, added in
* QEMU >= 2.10 (but sometimes disabled).
@@ -599,11 +588,7 @@ int
guestfs_int_qemu_mandatory_locking (guestfs_h *g,
const struct qemu_data *data)
{
- const char *return_path[] = { "return", NULL };
- const char *meta_type_path[] = { "meta-type", NULL };
- const char *members_path[] = { "members", NULL };
- const char *name_path[] = { "name", NULL };
- yajl_val schema, v, meta_type, members, m, name;
+ json_t *schema, *v, *meta_type, *members, *m, *name;
size_t i, j;
/* If there's no QMP schema, fall back to checking the version. */
@@ -616,27 +601,24 @@ guestfs_int_qemu_mandatory_locking (guestfs_h *g,
* Extract the schema from the wrapper. Note the returned schema
* will be an array.
*/
- schema = yajl_tree_get (data->qmp_schema_tree, return_path, yajl_t_array);
- if (schema == NULL)
+ schema = json_object_get (data->qmp_schema_tree, "return");
+ if (!json_is_array (schema))
goto fallback;
- assert (YAJL_IS_ARRAY(schema));
/* Now look for any member of the array which has:
* { "meta-type": "object",
* "members": [ ... { "name": "locking", ... } ... ] ... }
*/
- for (i = 0; i < YAJL_GET_ARRAY(schema)->len; ++i) {
- v = YAJL_GET_ARRAY(schema)->values[i];
- meta_type = yajl_tree_get (v, meta_type_path, yajl_t_string);
- if (meta_type && YAJL_IS_STRING (meta_type) &&
- STREQ (YAJL_GET_STRING (meta_type), "object")) {
- members = yajl_tree_get (v, members_path, yajl_t_array);
- if (members) {
- for (j = 0; j < YAJL_GET_ARRAY(members)->len; ++j) {
- m = YAJL_GET_ARRAY(members)->values[j];
- name = yajl_tree_get (m, name_path, yajl_t_string);
- if (name && YAJL_IS_STRING (name) &&
- STREQ (YAJL_GET_STRING (name), "locking"))
+ json_array_foreach (schema, i, v) {
+ meta_type = json_object_get (v, "meta-type");
+ if (json_is_string (meta_type) &&
+ STREQ (json_string_value (meta_type), "object")) {
+ members = json_object_get (v, "members");
+ if (json_is_array (members)) {
+ json_array_foreach (members, j, m) {
+ name = json_object_get (v, "name");
+ if (json_is_string (name) &&
+ STREQ (json_string_value (name), "locking"))
return 1;
}
}
@@ -646,8 +628,6 @@ guestfs_int_qemu_mandatory_locking (guestfs_h *g,
return 0;
}
-#pragma GCC diagnostic pop
-
/**
* Escape a qemu parameter.
*
@@ -996,7 +976,7 @@ guestfs_int_free_qemu_data (struct qemu_data *data)
free (data->qemu_help);
free (data->qemu_devices);
free (data->qmp_schema);
- yajl_tree_free (data->qmp_schema_tree);
+ json_decref (data->qmp_schema_tree);
free (data);
}
}
diff --git a/m4/guestfs-libraries.m4 b/m4/guestfs-libraries.m4
index 78a9e792f..2fdbd9669 100644
--- a/m4/guestfs-libraries.m4
+++ b/m4/guestfs-libraries.m4
@@ -299,8 +299,8 @@ LIBS="$LIBS $LIBXML2_LIBS"
AC_CHECK_FUNCS([xmlBufferDetach])
LIBS="$old_LIBS"
-dnl Check for yajl JSON library (required).
-PKG_CHECK_MODULES([YAJL], [yajl >= 2.0.4])
+dnl Check for Jansson JSON library (required).
+PKG_CHECK_MODULES([JANSSON], [jansson])
dnl Check for C++ (optional, we just use this to test the header works).
AC_PROG_CXX
--
2.21.0

View File

@ -0,0 +1,126 @@
From 6e0dbefde3ddb0711e2b0961ee913084dc5e6a41 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Tue, 19 Feb 2019 10:50:01 +0100
Subject: [PATCH] common/mlpcre: add offset flag for PCRE.matches
This way it is possible to change where the matching start, instead of
always assuming it is the beginning.
(cherry picked from commit 0ed2e5c14a302d15fd3b75ee2c1cb808a06cb746)
---
common/mlpcre/PCRE.ml | 2 +-
common/mlpcre/PCRE.mli | 5 ++++-
common/mlpcre/pcre-c.c | 16 +++++++++++++---
common/mlpcre/pcre_tests.ml | 11 ++++++++---
4 files changed, 26 insertions(+), 8 deletions(-)
diff --git a/common/mlpcre/PCRE.ml b/common/mlpcre/PCRE.ml
index b054928f9..33074af1c 100644
--- a/common/mlpcre/PCRE.ml
+++ b/common/mlpcre/PCRE.ml
@@ -23,7 +23,7 @@ exception Error of string * int
type regexp
external compile : ?anchored:bool -> ?caseless:bool -> ?dotall:bool -> ?extended:bool -> ?multiline:bool -> string -> regexp = "guestfs_int_pcre_compile_byte" "guestfs_int_pcre_compile"
-external matches : regexp -> string -> bool = "guestfs_int_pcre_matches"
+external matches : ?offset:int -> regexp -> string -> bool = "guestfs_int_pcre_matches"
external sub : int -> string = "guestfs_int_pcre_sub"
external subi : int -> int * int = "guestfs_int_pcre_subi"
diff --git a/common/mlpcre/PCRE.mli b/common/mlpcre/PCRE.mli
index eacb6fd90..e10d512fc 100644
--- a/common/mlpcre/PCRE.mli
+++ b/common/mlpcre/PCRE.mli
@@ -62,7 +62,7 @@ val compile : ?anchored:bool -> ?caseless:bool -> ?dotall:bool -> ?extended:bool
See pcreapi(3) for details of what they do.
All flags default to false. *)
-val matches : regexp -> string -> bool
+val matches : ?offset:int -> regexp -> string -> bool
(** Test whether the regular expression matches the string. This
returns true if the regexp matches or false otherwise.
@@ -71,6 +71,9 @@ val matches : regexp -> string -> bool
or the thread/program exits. You can call {!sub} to return
these substrings.
+ The [?offset] flag is used to change the start of the search,
+ which by default is at the beginning of the string (position 0).
+
This can raise {!Error} if PCRE returns an error. *)
val sub : int -> string
diff --git a/common/mlpcre/pcre-c.c b/common/mlpcre/pcre-c.c
index 0762a8341..be054a004 100644
--- a/common/mlpcre/pcre-c.c
+++ b/common/mlpcre/pcre-c.c
@@ -121,6 +121,15 @@ is_Some_true (value v)
Bool_val (Field (v, 0)) /* Some true */;
}
+static int
+Optint_val (value intv, int defval)
+{
+ if (intv == Val_int (0)) /* None */
+ return defval;
+ else /* Some int */
+ return Int_val (Field (intv, 0));
+}
+
value
guestfs_int_pcre_compile (value anchoredv, value caselessv, value dotallv,
value extendedv, value multilinev,
@@ -165,9 +174,9 @@ guestfs_int_pcre_compile_byte (value *argv, int argn)
}
value
-guestfs_int_pcre_matches (value rev, value strv)
+guestfs_int_pcre_matches (value offsetv, value rev, value strv)
{
- CAMLparam2 (rev, strv);
+ CAMLparam3 (offsetv, rev, strv);
pcre *re = Regexp_val (rev);
struct last_match *m, *oldm;
size_t len = caml_string_length (strv);
@@ -205,7 +214,8 @@ guestfs_int_pcre_matches (value rev, value strv)
caml_raise_out_of_memory ();
}
- m->r = pcre_exec (re, NULL, m->subject, len, 0, 0, m->vec, veclen);
+ m->r = pcre_exec (re, NULL, m->subject, len, Optint_val (offsetv, 0), 0,
+ m->vec, veclen);
if (m->r < 0 && m->r != PCRE_ERROR_NOMATCH) {
int ret = m->r;
free_last_match (m);
diff --git a/common/mlpcre/pcre_tests.ml b/common/mlpcre/pcre_tests.ml
index 346019c40..3e5981107 100644
--- a/common/mlpcre/pcre_tests.ml
+++ b/common/mlpcre/pcre_tests.ml
@@ -30,9 +30,9 @@ let compile ?(anchored = false) ?(caseless = false)
patt;
PCRE.compile ~anchored ~caseless ~dotall ~extended ~multiline patt
-let matches re str =
- eprintf "PCRE.matches %s ->%!" str;
- let r = PCRE.matches re str in
+let matches ?(offset = 0) re str =
+ eprintf "PCRE.matches %s, %d ->%!" str offset;
+ let r = PCRE.matches ~offset re str in
eprintf " %b\n%!" r;
r
@@ -103,6 +103,11 @@ let () =
assert (subi 1 = (2, 3));
assert (subi 2 = (3, 3));
+ assert (matches ~offset:5 re0 "aaabcabc" = true);
+ assert (sub 0 = "ab");
+
+ assert (matches ~offset:5 re0 "aaabcbaac" = false);
+
assert (replace re0 "dd" "abcabcaabccca" = "ddcabcaabccca");
assert (replace ~global:true re0 "dd" "abcabcaabccca" = "ddcddcddccca");
--
2.26.2

View File

@ -1,31 +0,0 @@
From 898e6c1e39deb130566220a11a2eaf2dcb2cb733 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Thu, 29 Mar 2018 20:18:34 +0100
Subject: [PATCH] qemu: Fix transcription error in conversion of yajl to
jansson.
This broke qemu mandatory locking detection.
Fixes commit bd1c5c9f4dcf38458099db8a0bf4659a07ef055d.
(cherry picked from commit e79286f71738d9385157d9e87211be02645722c3)
---
lib/qemu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/qemu.c b/lib/qemu.c
index a50eca988..3e7f15946 100644
--- a/lib/qemu.c
+++ b/lib/qemu.c
@@ -616,7 +616,7 @@ guestfs_int_qemu_mandatory_locking (guestfs_h *g,
members = json_object_get (v, "members");
if (json_is_array (members)) {
json_array_foreach (members, j, m) {
- name = json_object_get (v, "name");
+ name = json_object_get (m, "name");
if (json_is_string (name) &&
STREQ (json_string_value (name), "locking"))
return 1;
--
2.21.0

View File

@ -0,0 +1,415 @@
From a98136d6ee36df15a226f853d47bd803a7a25329 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Tue, 19 Feb 2019 14:54:31 +0100
Subject: [PATCH] v2v: add Var_expander
This helper module provides a facility to replace %{FOO}-like variables
in text strings with user-provided content.
(cherry picked from commit a27748d7000f417c16045967497208d275a09ce8)
---
.gitignore | 1 +
v2v/Makefile.am | 32 ++++++++++-
v2v/dummy.c | 2 +
v2v/var_expander.ml | 72 ++++++++++++++++++++++++
v2v/var_expander.mli | 82 +++++++++++++++++++++++++++
v2v/var_expander_tests.ml | 113 ++++++++++++++++++++++++++++++++++++++
6 files changed, 300 insertions(+), 2 deletions(-)
create mode 100644 v2v/dummy.c
create mode 100644 v2v/var_expander.ml
create mode 100644 v2v/var_expander.mli
create mode 100644 v2v/var_expander_tests.ml
diff --git a/.gitignore b/.gitignore
index 637bf7765..f2efcdde2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -693,6 +693,7 @@ Makefile.in
/v2v/uefi.ml
/v2v/uefi.mli
/v2v/v2v_unit_tests
+/v2v/var_expander_tests
/v2v/virt-v2v
/v2v/virt-v2v.1
/v2v/virt-v2v-copy-to-local
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
index 2312812fb..f196be81d 100644
--- a/v2v/Makefile.am
+++ b/v2v/Makefile.am
@@ -98,6 +98,7 @@ SOURCES_MLI = \
utils.mli \
v2v.mli \
vCenter.mli \
+ var_expander.mli \
windows.mli \
windows_virtio.mli
@@ -106,6 +107,7 @@ SOURCES_ML = \
types.ml \
uefi.ml \
utils.ml \
+ var_expander.ml \
python_script.ml \
name_from_disk.ml \
vCenter.ml \
@@ -442,7 +444,7 @@ TESTS += \
endif
if HAVE_OCAML_PKG_OUNIT
-TESTS += v2v_unit_tests
+TESTS += v2v_unit_tests var_expander_tests
endif
if ENABLE_APPLIANCE
@@ -651,7 +653,7 @@ EXTRA_DIST += \
# Unit tests.
check_PROGRAMS =
if HAVE_OCAML_PKG_OUNIT
-check_PROGRAMS += v2v_unit_tests
+check_PROGRAMS += v2v_unit_tests var_expander_tests
endif
v2v_unit_tests_BOBJECTS = \
@@ -671,13 +673,28 @@ v2v_unit_tests_SOURCES = $(virt_v2v_SOURCES)
v2v_unit_tests_CPPFLAGS = $(virt_v2v_CPPFLAGS)
v2v_unit_tests_CFLAGS = $(virt_v2v_CFLAGS)
+var_expander_tests_BOBJECTS = \
+ var_expander.cmo \
+ var_expander_tests.cmo
+var_expander_tests_XOBJECTS = $(var_expander_tests_BOBJECTS:.cmo=.cmx)
+
+var_expander_tests_SOURCES = dummy.c
+var_expander_tests_CPPFLAGS = $(virt_v2v_CPPFLAGS)
+var_expander_tests_CFLAGS = $(virt_v2v_CFLAGS)
+
if !HAVE_OCAMLOPT
# Can't call this v2v_unit_tests_OBJECTS because automake gets confused.
v2v_unit_tests_THEOBJECTS = $(v2v_unit_tests_BOBJECTS)
v2v_unit_tests.cmo: OCAMLPACKAGES += -package oUnit
+
+var_expander_tests_THEOBJECTS = $(var_expander_tests_BOBJECTS)
+var_expander_tests.cmo: OCAMLPACKAGES += -package oUnit
else
v2v_unit_tests_THEOBJECTS = $(v2v_unit_tests_XOBJECTS)
v2v_unit_tests.cmx: OCAMLPACKAGES += -package oUnit
+
+var_expander_tests_THEOBJECTS = $(var_expander_tests_XOBJECTS)
+var_expander_tests.cmx: OCAMLPACKAGES += -package oUnit
endif
v2v_unit_tests_DEPENDENCIES = \
@@ -696,6 +713,17 @@ v2v_unit_tests_LINK = \
$(OCAMLLINKFLAGS) \
$(v2v_unit_tests_THEOBJECTS) -o $@
+var_expander_tests_DEPENDENCIES = \
+ $(var_expander_tests_THEOBJECTS) \
+ ../common/mlpcre/mlpcre.$(MLARCHIVE) \
+ $(top_srcdir)/ocaml-link.sh
+var_expander_tests_LINK = \
+ $(top_srcdir)/ocaml-link.sh -cclib '$(OCAMLCLIBS)' -- \
+ $(OCAMLFIND) $(BEST) $(OCAMLFLAGS) \
+ $(OCAMLPACKAGES) -package oUnit \
+ $(OCAMLLINKFLAGS) \
+ $(var_expander_tests_THEOBJECTS) -o $@
+
# Dependencies.
.depend: \
$(srcdir)/*.mli \
diff --git a/v2v/dummy.c b/v2v/dummy.c
new file mode 100644
index 000000000..ebab6198c
--- /dev/null
+++ b/v2v/dummy.c
@@ -0,0 +1,2 @@
+/* Dummy source, to be used for OCaml-based tools with no C sources. */
+enum { foo = 1 };
diff --git a/v2v/var_expander.ml b/v2v/var_expander.ml
new file mode 100644
index 000000000..24b9bafe3
--- /dev/null
+++ b/v2v/var_expander.ml
@@ -0,0 +1,72 @@
+(* virt-v2v
+ * Copyright (C) 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.
+ *)
+
+open Std_utils
+
+exception Invalid_variable of string
+
+let var_re = PCRE.compile "(^|[^%])%{([^}]+)}"
+
+let check_variable var =
+ String.iter (
+ function
+ | '0'..'9'
+ | 'a'..'z'
+ | 'A'..'Z'
+ | '_'
+ | '-' -> ()
+ | _ -> raise (Invalid_variable var)
+ ) var
+
+let scan_variables str =
+ let res = ref [] in
+ let offset = ref 0 in
+ while PCRE.matches ~offset:!offset var_re str; do
+ let var = PCRE.sub 2 in
+ check_variable var;
+ let _, end_ = PCRE.subi 0 in
+ List.push_back res var;
+ offset := end_
+ done;
+ List.remove_duplicates !res
+
+let replace_fn str fn =
+ let res = ref str in
+ let offset = ref 0 in
+ while PCRE.matches ~offset:!offset var_re !res; do
+ let var = PCRE.sub 2 in
+ check_variable var;
+ let start_, end_ = PCRE.subi 0 in
+ match fn var with
+ | None ->
+ offset := end_
+ | Some text ->
+ let prefix_len =
+ let prefix_start, prefix_end = PCRE.subi 1 in
+ prefix_end - prefix_start in
+ res := (String.sub !res 0 (start_ + prefix_len)) ^ text ^ (String.sub !res end_ (String.length !res - end_));
+ offset := start_ + prefix_len + String.length text
+ done;
+ !res
+
+let replace_list str lst =
+ let fn var =
+ try Some (List.assoc var lst)
+ with Not_found -> None
+ in
+ replace_fn str fn
diff --git a/v2v/var_expander.mli b/v2v/var_expander.mli
new file mode 100644
index 000000000..80aa33c2c
--- /dev/null
+++ b/v2v/var_expander.mli
@@ -0,0 +1,82 @@
+(* virt-v2v
+ * Copyright (C) 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.
+ *)
+
+(** Simple variable expander.
+
+ This module provides the support to expand variables in strings,
+ specified in the form of [%{name}].
+
+ For example:
+
+{v
+let str = "variable-%{INDEX} in %{INDEX} replaced %{INDEX} times"
+let index = ref 0
+let fn = function
+ | "INDEX" ->
+ incr index;
+ Some (string_of_int !index)
+ | _ -> None
+in
+let str = Var_expander.replace_fn str fn
+(* now str is "variable-1 in 2 replaced 3 times" *)
+v}
+
+ The names of variables can contain only ASCII letters (uppercase,
+ and lowercase), digits, underscores, and dashes.
+
+ The replacement is done in a single pass: this means that if a
+ variable is replaced with the text of a variable, that new text
+ is kept as is in the final output. In practice:
+
+{v
+let str = "%{VAR}"
+let str = Var_expander.replace_list str [("VAR", "%{VAR}")]
+(* now str is "%{VAR}" *)
+v}
+*)
+
+exception Invalid_variable of string
+(** Invalid variable name error.
+
+ In case a variable contains characters not allowed, then this
+ exception with the actual unacceptable variable. *)
+
+val scan_variables : string -> string list
+(** Scan the pattern string for all the variables available.
+
+ This can raise {!Invalid_variable} in case there are invalid
+ variable names. *)
+
+val replace_fn : string -> (string -> string option) -> string
+(** Replaces a string expanding all the variables.
+
+ The replacement function specify how a variable is replaced;
+ if [None] is returned, then that variable is not replaced.
+
+ This can raise {!Invalid_variable} in case there are invalid
+ variable names. *)
+
+val replace_list : string -> (string * string) list -> string
+(** Replaces a string expanding all the variables.
+
+ The replacement list specify how a variable is replaced;
+ if it is not specified in the list, then that variable is not
+ replaced.
+
+ This can raise {!Invalid_variable} in case there are invalid
+ variable names. *)
diff --git a/v2v/var_expander_tests.ml b/v2v/var_expander_tests.ml
new file mode 100644
index 000000000..35b628369
--- /dev/null
+++ b/v2v/var_expander_tests.ml
@@ -0,0 +1,113 @@
+(* virt-v2v
+ * Copyright (C) 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.
+ *)
+
+open Printf
+open OUnit
+
+open Std_utils
+
+let assert_equal_string = assert_equal ~printer:identity
+let assert_equal_stringlist = assert_equal ~printer:(fun x -> "(" ^ (String.escaped (String.concat "," x)) ^ ")")
+
+let replace_none_fn _ = None
+let replace_empty_fn _ = Some ""
+
+let test_no_replacement () =
+ assert_equal_string "" (Var_expander.replace_fn "" replace_none_fn);
+ assert_equal_string "x" (Var_expander.replace_fn "x" replace_none_fn);
+ assert_equal_string "%{}" (Var_expander.replace_fn "%{}" replace_none_fn);
+ assert_equal_string "%{EMPTY}" (Var_expander.replace_fn "%{EMPTY}" replace_none_fn);
+ assert_equal_string "%{EMPTY} %{no}" (Var_expander.replace_fn "%{EMPTY} %{no}" replace_none_fn);
+ assert_equal_string "a %{EMPTY} b" (Var_expander.replace_fn "a %{EMPTY} b" replace_none_fn);
+ ()
+
+let test_replacements () =
+ assert_equal_string "" (Var_expander.replace_fn "%{EMPTY}" replace_empty_fn);
+ assert_equal_string "x " (Var_expander.replace_fn "x %{EMPTY}" replace_empty_fn);
+ assert_equal_string "xy" (Var_expander.replace_fn "x%{EMPTY}y" replace_empty_fn);
+ assert_equal_string "x<->y" (Var_expander.replace_fn "x%{FOO}y" (function | "FOO" -> Some "<->" | _ -> None));
+ assert_equal_string "a x b" (Var_expander.replace_fn "a %{FOO} b" (function | "FOO" -> Some "x" | _ -> None));
+ assert_equal_string "%{FOO} x" (Var_expander.replace_fn "%{FOO} %{BAR}" (function | "BAR" -> Some "x" | _ -> None));
+ assert_equal_string "%{FOO}" (Var_expander.replace_fn "%{BAR}" (function | "BAR" -> Some "%{FOO}" | _ -> None));
+ assert_equal_string "%{FOO} x" (Var_expander.replace_fn "%{BAR} %{FOO}" (function | "BAR" -> Some "%{FOO}" | "FOO" -> Some "x" | _ -> None));
+ begin
+ let str = "%{INDEX}, %{INDEX}, %{INDEX}" in
+ let index = ref 0 in
+ let fn = function
+ | "INDEX" ->
+ incr index;
+ Some (string_of_int !index)
+ | _ -> None
+ in
+ assert_equal_string "1, 2, 3" (Var_expander.replace_fn str fn)
+ end;
+ ()
+
+let test_escape () =
+ assert_equal_string "%%{FOO}" (Var_expander.replace_fn "%%{FOO}" replace_empty_fn);
+ assert_equal_string "x %%{FOO} x" (Var_expander.replace_fn "%{FOO} %%{FOO} %{FOO}" (function | "FOO" -> Some "x" | _ -> None));
+ ()
+
+let test_list () =
+ assert_equal_string "x %{NONE}" (Var_expander.replace_list "%{FOO} %{NONE}" [("FOO", "x")]);
+ ()
+
+let test_scan_variables () =
+ let assert_invalid_variable var =
+ let str = "%{" ^ var ^ "}" in
+ assert_raises (Var_expander.Invalid_variable var)
+ (fun () -> Var_expander.scan_variables str)
+ in
+ assert_equal_stringlist [] (Var_expander.scan_variables "");
+ assert_equal_stringlist [] (Var_expander.scan_variables "foo");
+ assert_equal_stringlist ["FOO"] (Var_expander.scan_variables "%{FOO}");
+ assert_equal_stringlist ["FOO"; "BAR"] (Var_expander.scan_variables "%{FOO} %{BAR}");
+ assert_equal_stringlist ["FOO"; "BAR"] (Var_expander.scan_variables "%{FOO} %{BAR} %{FOO}");
+ assert_equal_stringlist ["FOO"; "BAR"] (Var_expander.scan_variables "%{FOO} %%{ESCAPED} %{BAR}");
+ assert_invalid_variable "FOO/BAR";
+ ()
+
+let test_errors () =
+ let assert_invalid_variable var =
+ let str = "%{" ^ var ^ "}" in
+ assert_raises (Var_expander.Invalid_variable var)
+ (fun () -> Var_expander.replace_fn str replace_none_fn)
+ in
+ assert_invalid_variable "FOO/BAR";
+ assert_invalid_variable "FOO:BAR";
+ assert_invalid_variable "FOO(BAR";
+ assert_invalid_variable "FOO)BAR";
+ assert_invalid_variable "FOO@BAR";
+ ()
+
+(* Suites declaration. *)
+let suite =
+ TestList ([
+ "basic" >::: [
+ "no_replacement" >:: test_no_replacement;
+ "replacements" >:: test_replacements;
+ "escape" >:: test_escape;
+ "list" >:: test_list;
+ "scan_variables" >:: test_scan_variables;
+ "errors" >:: test_errors;
+ ];
+ ])
+
+let () =
+ ignore (run_test_tt_main suite);
+ Printf.fprintf stderr "\n"
--
2.26.2

View File

@ -0,0 +1,785 @@
From 480c7169c341fc2f86609a13100c42e10f599b83 Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Mon, 25 Feb 2019 13:14:43 +0100
Subject: [PATCH] v2v: add -o json output mode
Add a new output mode to virt-v2v: similar to -o local, the written
metadata is a JSON file with the majority of the data that virt-v2v
knowns about (or collects) during the conversion.
This is meant to be used only when no existing output mode is usable,
and a guest needs to be converted to run on KVM anyway. The user of
this mode is supposed to use all the data in the JSON, as they contain
important details on how even run the guest (e.g. w.r.t. firmware,
drivers of disks/NICs, etc).
(cherry picked from commit f190e08d85556dac293ef15bfeee38e54471570f)
---
v2v/Makefile.am | 4 +
v2v/cmdline.ml | 29 +++
v2v/create_json.ml | 348 ++++++++++++++++++++++++++++++++++
v2v/create_json.mli | 29 +++
v2v/output_json.ml | 116 ++++++++++++
v2v/output_json.mli | 31 +++
v2v/virt-v2v-output-local.pod | 55 ++++++
v2v/virt-v2v.pod | 15 +-
8 files changed, 625 insertions(+), 2 deletions(-)
create mode 100644 v2v/create_json.ml
create mode 100644 v2v/create_json.mli
create mode 100644 v2v/output_json.ml
create mode 100644 v2v/output_json.mli
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
index f196be81d..53c137fc6 100644
--- a/v2v/Makefile.am
+++ b/v2v/Makefile.am
@@ -52,6 +52,7 @@ SOURCES_MLI = \
config.mli \
convert_linux.mli \
convert_windows.mli \
+ create_json.mli \
create_libvirt_xml.mli \
create_ovf.mli \
DOM.mli \
@@ -75,6 +76,7 @@ SOURCES_MLI = \
networks.mli \
openstack_image_properties.mli \
output_glance.mli \
+ output_json.mli \
output_libvirt.mli \
output_local.mli \
output_null.mli \
@@ -117,6 +119,7 @@ SOURCES_ML = \
parse_ovf_from_ova.ml \
parse_ova.ml \
create_ovf.ml \
+ create_json.ml \
linux.ml \
windows.ml \
windows_virtio.ml \
@@ -141,6 +144,7 @@ SOURCES_ML = \
convert_windows.ml \
output_null.ml \
output_glance.ml \
+ output_json.ml \
output_libvirt.ml \
output_local.ml \
output_qemu.ml \
diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
index 46f6910d0..4d390f249 100644
--- a/v2v/cmdline.ml
+++ b/v2v/cmdline.ml
@@ -138,6 +138,7 @@ let parse_cmdline () =
| "glance" -> output_mode := `Glance
| "libvirt" -> output_mode := `Libvirt
| "disk" | "local" -> output_mode := `Local
+ | "json" -> output_mode := `JSON
| "null" -> output_mode := `Null
| "openstack" | "osp" | "rhosp" -> output_mode := `Openstack
| "ovirt" | "rhv" | "rhev" -> output_mode := `RHV
@@ -413,6 +414,17 @@ read the man page virt-v2v(1).
| `RHV -> no_options (); `RHV
| `QEmu -> no_options (); `QEmu
+ | `JSON ->
+ if is_query then (
+ Output_json.print_output_options ();
+ exit 0
+ )
+ else (
+ let json_options =
+ Output_json.parse_output_options output_options in
+ `JSON json_options
+ )
+
| `Openstack ->
if is_query then (
Output_openstack.print_output_options ();
@@ -546,6 +558,23 @@ read the man page virt-v2v(1).
Output_libvirt.output_libvirt output_conn output_storage,
output_format, output_alloc
+ | `JSON json_options ->
+ if output_password <> None then
+ error_option_cannot_be_used_in_output_mode "json" "-op";
+ if output_conn <> None then
+ error_option_cannot_be_used_in_output_mode "json" "-oc";
+ let os =
+ match output_storage with
+ | None ->
+ error (f_"-o json: output directory was not specified, use '-os /dir'")
+ | Some d when not (is_directory d) ->
+ error (f_"-os %s: output directory does not exist or is not a directory") d
+ | Some d -> d in
+ if qemu_boot then
+ error_option_cannot_be_used_in_output_mode "json" "--qemu-boot";
+ Output_json.output_json os json_options,
+ output_format, output_alloc
+
| `Local ->
if output_password <> None then
error_option_cannot_be_used_in_output_mode "local" "-op";
diff --git a/v2v/create_json.ml b/v2v/create_json.ml
new file mode 100644
index 000000000..fdf7b12f5
--- /dev/null
+++ b/v2v/create_json.ml
@@ -0,0 +1,348 @@
+(* virt-v2v
+ * Copyright (C) 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.
+ *)
+
+open Std_utils
+open C_utils
+open Tools_utils
+
+open Types
+open Utils
+
+module G = Guestfs
+
+let json_list_of_string_list =
+ List.map (fun x -> JSON.String x)
+
+let json_list_of_string_string_list =
+ List.map (fun (x, y) -> x, JSON.String y)
+
+let push_optional_string lst name = function
+ | None -> ()
+ | Some v -> List.push_back lst (name, JSON.String v)
+
+let push_optional_int lst name = function
+ | None -> ()
+ | Some v -> List.push_back lst (name, JSON.Int (Int64.of_int v))
+
+let json_unknown_string = function
+ | "unknown" -> JSON.Null
+ | v -> JSON.String v
+
+let find_target_disk targets { s_disk_id = id } =