Introduce a new struct version with few helper functions for it: this
allows to "atomically" represent a version number, without different
variables to be used and checked together.
Add a initialization function from a libvirt-style version number, and
apply it for the qemu and libvirt versions in the direct and libvirt
backends.
---
src/Makefile.am | 1 +
src/guestfs-internal.h | 14 +++++++++++++-
src/launch-direct.c | 28 ++++++++++-----------------
src/launch-libvirt.c | 43 +++++++++++++++++++++++-------------------
src/version.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 99 insertions(+), 38 deletions(-)
create mode 100644 src/version.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 7a694ca..d2879f4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -133,6 +133,7 @@ libguestfs_la_SOURCES = \
umask.c \
wait.c \
whole-file.c \
+ version.c \
libguestfs.syms
libguestfs_la_CPPFLAGS = \
diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h
index d4e4e3c..098fe20 100644
--- a/src/guestfs-internal.h
+++ b/src/guestfs-internal.h
@@ -509,6 +509,12 @@ struct guestfs_h
size_t nr_features;
};
+struct version {
+ int v_major;
+ int v_minor;
+ int v_micro;
+};
+
/* Per-filesystem data stored for inspect_os. */
enum inspect_os_format {
OS_FORMAT_UNKNOWN = 0,
@@ -623,6 +629,12 @@ struct guestfs_message_header;
struct guestfs_message_error;
struct guestfs_progress;
+/* version.c */
+extern void guestfs_int_version_from_libvirt (struct version *v, int vernum);
+extern void guestfs_int_version_from_values (struct version *v, int maj, int min, int
mic);
+extern bool guestfs_int_version_is (const struct version *v, int maj, int min, int mic);
+#define version_init_null(v) guestfs_int_version_from_values (v, 0, 0, 0)
+
/* handle.c */
extern int guestfs_int_get_backend_setting_bool (guestfs_h *g, const char *name);
@@ -903,7 +915,7 @@ extern void guestfs_int_cleanup_cmd_close (struct command **);
/* launch-direct.c */
extern char *guestfs_int_drive_source_qemu_param (guestfs_h *g, const struct drive_source
*src);
-extern bool guestfs_int_discard_possible (guestfs_h *g, struct drive *drv, unsigned long
qemu_version);
+extern bool guestfs_int_discard_possible (guestfs_h *g, struct drive *drv, const struct
version *qemu_version);
extern char *guestfs_int_qemu_escape_param (guestfs_h *g, const char *param);
/* launch-*.c constructors */
diff --git a/src/launch-direct.c b/src/launch-direct.c
index 1b012cf..832b975 100644
--- a/src/launch-direct.c
+++ b/src/launch-direct.c
@@ -62,7 +62,7 @@ struct backend_direct_data {
char *qemu_devices; /* Output of qemu -device ? */
/* qemu version (0, 0 if unable to parse). */
- int qemu_version_major, qemu_version_minor;
+ struct version qemu_version;
int virtio_scsi; /* See function qemu_supports_virtio_scsi */
@@ -420,8 +420,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
if (qemu_supports (g, data, "-no-hpet")) {
ADD_CMDLINE ("-no-hpet");
}
- if (data->qemu_version_major < 1 ||
- (data->qemu_version_major == 1 && data->qemu_version_minor <= 2))
+ if (!guestfs_int_version_is (&data->qemu_version, 1, 3, 0))
ADD_CMDLINE ("-no-kvm-pit-reinjection");
else {
/* New non-deprecated way, added in qemu >= 1.3. */
@@ -472,8 +471,6 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
if (!drv->overlay) {
const char *discard_mode = "";
- int major = data->qemu_version_major, minor = data->qemu_version_minor;
- unsigned long qemu_version = major * 1000000 + minor * 1000;
switch (drv->discard) {
case discard_disable:
@@ -483,14 +480,14 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
*/
break;
case discard_enable:
- if (!guestfs_int_discard_possible (g, drv, qemu_version))
+ if (!guestfs_int_discard_possible (g, drv, &data->qemu_version))
goto cleanup0;
/*FALLTHROUGH*/
case discard_besteffort:
/* I believe from reading the code that this is always safe as
* long as qemu >= 1.5.
*/
- if (major > 1 || (major == 1 && minor >= 5))
+ if (guestfs_int_version_is (&data->qemu_version, 1, 5, 0))
discard_mode = ",discard=unmap";
break;
}
@@ -1002,8 +999,7 @@ parse_qemu_version (guestfs_h *g, struct backend_direct_data *data)
CLEANUP_FREE char *major_s = NULL, *minor_s = NULL;
int major_i, minor_i;
- data->qemu_version_major = 0;
- data->qemu_version_minor = 0;
+ version_init_null (&data->qemu_version);
if (!data->qemu_help)
return;
@@ -1023,8 +1019,7 @@ parse_qemu_version (guestfs_h *g, struct backend_direct_data *data)
if (minor_i == -1)
goto parse_failed;
- data->qemu_version_major = major_i;
- data->qemu_version_minor = minor_i;
+ guestfs_int_version_from_values (&data->qemu_version, major_i, minor_i, 0);
debug (g, "qemu version %d.%d", major_i, minor_i);
}
@@ -1094,7 +1089,7 @@ static int
old_or_broken_virtio_scsi (guestfs_h *g, struct backend_direct_data *data)
{
/* qemu 1.1 claims to support virtio-scsi but in reality it's broken. */
- if (data->qemu_version_major == 1 && data->qemu_version_minor < 2)
+ if (!guestfs_int_version_is (&data->qemu_version, 1, 2, 0))
return 1;
return 0;
@@ -1384,22 +1379,19 @@ guestfs_int_drive_source_qemu_param (guestfs_h *g, const struct
drive_source *sr
* It returns 0 if not possible and sets the error to the reason why.
*
* This function is called when the user set discard == "enable".
- *
- * qemu_version is the version of qemu in the form returned by libvirt:
- * major * 1,000,000 + minor * 1,000 + release
*/
bool
guestfs_int_discard_possible (guestfs_h *g, struct drive *drv,
- unsigned long qemu_version)
+ const struct version *qemu_version)
{
/* qemu >= 1.5. This was the first version that supported the
* discard option on -drive at all.
*/
- bool qemu15 = qemu_version >= 1005000;
+ bool qemu15 = guestfs_int_version_is (qemu_version, 1, 5, 0);
/* qemu >= 1.6. This was the first version that supported unmap on
* qcow2 backing files.
*/
- bool qemu16 = qemu_version >= 1006000;
+ bool qemu16 = guestfs_int_version_is (qemu_version, 1, 6, 0);
if (!qemu15)
NOT_SUPPORTED (g, false,
diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c
index dba28b4..6d6e162 100644
--- a/src/launch-libvirt.c
+++ b/src/launch-libvirt.c
@@ -118,8 +118,8 @@ struct backend_libvirt_data {
char *network_bridge;
char name[DOMAIN_NAME_LEN]; /* random name */
bool is_kvm; /* false = qemu, true = kvm (from capabilities)*/
- unsigned long libvirt_version; /* libvirt version */
- unsigned long qemu_version; /* qemu version (from libvirt) */
+ struct version libvirt_version; /* libvirt version */
+ struct version qemu_version; /* qemu version (from libvirt) */
struct secret *secrets; /* list of secrets */
size_t nr_secrets;
char *uefi_code; /* UEFI (firmware) code and variables. */
@@ -253,6 +253,7 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri)
int r;
uint32_t size;
CLEANUP_FREE void *buf = NULL;
+ unsigned long version_number;
params.current_proc_is_root = geteuid () == 0;
@@ -262,13 +263,16 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri)
return -1;
}
- virGetVersion (&data->libvirt_version, NULL, NULL);
- debug (g, "libvirt version = %lu (%lu.%lu.%lu)",
- data->libvirt_version,
- data->libvirt_version / 1000000UL,
- data->libvirt_version / 1000UL % 1000UL,
- data->libvirt_version % 1000UL);
- if (data->libvirt_version < MIN_LIBVIRT_VERSION) {
+ virGetVersion (&version_number, NULL, NULL);
+ guestfs_int_version_from_libvirt (&data->libvirt_version, version_number);
+ debug (g, "libvirt version = %lu (%d.%d.%d)",
+ version_number,
+ data->libvirt_version.v_major,
+ data->libvirt_version.v_minor,
+ data->libvirt_version.v_micro);
+ if (!guestfs_int_version_is (&data->libvirt_version,
+ MIN_LIBVIRT_MAJOR, MIN_LIBVIRT_MINOR,
+ MIN_LIBVIRT_MICRO)) {
error (g, _("you must have libvirt >= %d.%d.%d "
"to use the 'libvirt' backend"),
MIN_LIBVIRT_MAJOR, MIN_LIBVIRT_MINOR, MIN_LIBVIRT_MICRO);
@@ -315,16 +319,17 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri)
virConnSetErrorFunc (conn, NULL, ignore_errors);
/* Get hypervisor (hopefully qemu) version. */
- if (virConnectGetVersion (conn, &data->qemu_version) == 0) {
- debug (g, "qemu version (reported by libvirt) = %lu (%lu.%lu.%lu)",
- data->qemu_version,
- data->qemu_version / 1000000UL,
- data->qemu_version / 1000UL % 1000UL,
- data->qemu_version % 1000UL);
+ if (virConnectGetVersion (conn, &version_number) == 0) {
+ guestfs_int_version_from_libvirt (&data->qemu_version, version_number);
+ debug (g, "qemu version (reported by libvirt) = %lu (%d.%d.%d)",
+ version_number,
+ data->qemu_version.v_major,
+ data->qemu_version.v_minor,
+ data->qemu_version.v_micro);
}
else {
libvirt_debug (g, "unable to read qemu version from libvirt");
- data->qemu_version = 0;
+ version_init_null (&data->qemu_version);
}
debug (g, "get libvirt capabilities");
@@ -1259,7 +1264,7 @@ construct_libvirt_xml_devices (guestfs_h *g,
* requires Cole Robinson's patch to permit /dev/urandom to be
* used, which was added in libvirt 1.3.4.
*/
- if (params->data->libvirt_version >= 1003004) {
+ if (guestfs_int_version_is (¶ms->data->libvirt_version, 1, 3, 4)) {
start_element ("rng") {
attribute ("model", "virtio");
start_element ("backend") {
@@ -1574,14 +1579,14 @@ construct_libvirt_xml_disk_driver_qemu (guestfs_h *g,
*/
break;
case discard_enable:
- if (!guestfs_int_discard_possible (g, drv, data->qemu_version))
+ if (!guestfs_int_discard_possible (g, drv, &data->qemu_version))
return -1;
/*FALLTHROUGH*/
case discard_besteffort:
/* I believe from reading the code that this is always safe as
* long as qemu >= 1.5.
*/
- if (data->qemu_version >= 1005000)
+ if (guestfs_int_version_is (&data->qemu_version, 1, 5, 0))
discard_unmap = true;
break;
}
diff --git a/src/version.c b/src/version.c
new file mode 100644
index 0000000..2d0fe30
--- /dev/null
+++ b/src/version.c
@@ -0,0 +1,51 @@
+/* libguestfs
+ * Copyright (C) 2016 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 "guestfs.h"
+#include "guestfs-internal.h"
+
+/**
+ * This file provides simple version number management.
+ */
+
+#define VERSION_TO_NUMBER(maj, min, mic) ((maj) * 1000000 + (min) * 1000 + (mic))
+#define VERSION_STRUCT_TO_NUMBER(v) VERSION_TO_NUMBER((v)->v_major, (v)->v_minor,
(v)->v_micro)
+
+void
+guestfs_int_version_from_libvirt (struct version *v, int vernum)
+{
+ v->v_major = vernum / 1000000UL;
+ v->v_minor = vernum / 1000UL % 1000UL;
+ v->v_micro = vernum % 1000UL;
+}
+
+void
+guestfs_int_version_from_values (struct version *v, int maj, int min, int mic)
+{
+ v->v_major = maj;
+ v->v_minor = min;
+ v->v_micro = mic;
+}
+
+bool
+guestfs_int_version_is (const struct version *v, int maj, int min, int mic)
+{
+ return VERSION_STRUCT_TO_NUMBER(v) >= VERSION_TO_NUMBER(maj, min, mic);
+}
--
2.5.5