In future commits, we will optionally use nbdkit to serve some remote
disk sources. This patch queries to see whether nbdkit is installed on
the host and queries it for capabilities. The data will be used in later
commits.

Signed-off-by: Jonathon Jongsma <jjong...@redhat.com>
---
 po/POTFILES            |   1 +
 src/qemu/meson.build   |   1 +
 src/qemu/qemu_conf.h   |   1 +
 src/qemu/qemu_nbdkit.c | 203 +++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_nbdkit.h |  52 +++++++++++
 5 files changed, 258 insertions(+)
 create mode 100644 src/qemu/qemu_nbdkit.c
 create mode 100644 src/qemu/qemu_nbdkit.h

diff --git a/po/POTFILES b/po/POTFILES
index 169e2a41dc..d96ce4415a 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -180,6 +180,7 @@ src/qemu/qemu_monitor.c
 src/qemu/qemu_monitor_json.c
 src/qemu/qemu_monitor_text.c
 src/qemu/qemu_namespace.c
+src/qemu/qemu_nbdkit.c
 src/qemu/qemu_process.c
 src/qemu/qemu_qapi.c
 src/qemu/qemu_saveimage.c
diff --git a/src/qemu/meson.build b/src/qemu/meson.build
index 96952cc52d..101cf3591f 100644
--- a/src/qemu/meson.build
+++ b/src/qemu/meson.build
@@ -28,6 +28,7 @@ qemu_driver_sources = [
   'qemu_monitor_json.c',
   'qemu_monitor_text.c',
   'qemu_namespace.c',
+  'qemu_nbdkit.c',
   'qemu_process.c',
   'qemu_qapi.c',
   'qemu_saveimage.c',
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 8cf2dd2ec5..a39510b0b1 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -36,6 +36,7 @@
 #include "virthreadpool.h"
 #include "locking/lock_manager.h"
 #include "qemu_capabilities.h"
+#include "qemu_nbdkit.h"
 #include "virclosecallbacks.h"
 #include "virhostdev.h"
 #include "virfile.h"
diff --git a/src/qemu/qemu_nbdkit.c b/src/qemu/qemu_nbdkit.c
new file mode 100644
index 0000000000..7a7248c1ef
--- /dev/null
+++ b/src/qemu/qemu_nbdkit.c
@@ -0,0 +1,203 @@
+/*
+ * qemu_nbdkit.c: helpers for using nbdkit
+ *
+ * Copyright (C) 2021 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.1 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, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+#include <glib.h>
+
+#include "vircommand.h"
+#include "virerror.h"
+#include "virlog.h"
+#include "virpidfile.h"
+#include "virutil.h"
+#include "qemu_block.h"
+#include "qemu_conf.h"
+#include "qemu_domain.h"
+#include "qemu_driver.h"
+#include "qemu_extdevice.h"
+#include "qemu_nbdkit.h"
+#include "qemu_security.h"
+
+#include <fcntl.h>
+
+#define VIR_FROM_THIS VIR_FROM_QEMU
+
+VIR_LOG_INIT("qemu.nbdkit");
+
+VIR_ENUM_IMPL(qemuNbdkitCaps,
+    QEMU_NBDKIT_CAPS_LAST,
+    /* 0 */
+    "plugin-curl", /* QEMU_NBDKIT_CAPS_PLUGIN_CURL */
+    "plugin-ssh", /* QEMU_NBDKIT_CAPS_PLUGIN_SSH */
+    "filter-readahead", /* QEMU_NBDKIT_CAPS_FILTER_READAHEAD */
+);
+
+struct _qemuNbdkitCaps {
+    GObject parent;
+
+    char *path;
+    char *version;
+
+    virBitmap *flags;
+};
+G_DEFINE_TYPE(qemuNbdkitCaps, qemu_nbdkit_caps, G_TYPE_OBJECT);
+
+
+static void
+qemuNbdkitCheckCommandCap(qemuNbdkitCaps *nbdkit,
+                          virCommand *cmd,
+                          qemuNbdkitCapsFlags cap)
+{
+    if (virCommandRun(cmd, NULL) != 0)
+        return;
+
+    VIR_DEBUG("Setting nbdkit capability %i", cap);
+    ignore_value(virBitmapSetBit(nbdkit->flags, cap));
+}
+
+
+static void
+qemuNbdkitQueryFilter(qemuNbdkitCaps *nbdkit,
+                      const char *filter,
+                      qemuNbdkitCapsFlags cap)
+{
+    g_autoptr(virCommand) cmd = virCommandNewArgList(nbdkit->path,
+                                                     "--version",
+                                                     NULL);
+
+    virCommandAddArgPair(cmd, "--filter", filter);
+
+    /* use null plugin to check for filter */
+    virCommandAddArg(cmd, "null");
+
+    qemuNbdkitCheckCommandCap(nbdkit, cmd, cap);
+}
+
+
+static void
+qemuNbdkitQueryPlugin(qemuNbdkitCaps *nbdkit,
+                      const char *plugin,
+                      qemuNbdkitCapsFlags cap)
+{
+    g_autoptr(virCommand) cmd = virCommandNewArgList(nbdkit->path,
+                                                     plugin,
+                                                     "--version",
+                                                     NULL);
+
+    qemuNbdkitCheckCommandCap(nbdkit, cmd, cap);
+}
+
+
+static void
+qemuNbdkitCapsQueryPlugins(qemuNbdkitCaps *nbdkit)
+{
+    qemuNbdkitQueryPlugin(nbdkit, "curl", QEMU_NBDKIT_CAPS_PLUGIN_CURL);
+    qemuNbdkitQueryPlugin(nbdkit, "ssh", QEMU_NBDKIT_CAPS_PLUGIN_SSH);
+}
+
+
+static void
+qemuNbdkitCapsQueryFilters(qemuNbdkitCaps *nbdkit)
+{
+    qemuNbdkitQueryFilter(nbdkit, "readahead",
+                          QEMU_NBDKIT_CAPS_FILTER_READAHEAD);
+}
+
+
+static int
+qemuNbdkitCapsQueryVersion(qemuNbdkitCaps *nbdkit)
+{
+    g_autoptr(virCommand) cmd = virCommandNewArgList(nbdkit->path,
+                                                     "--version",
+                                                     NULL);
+
+    virCommandSetOutputBuffer(cmd, &nbdkit->version);
+
+    if (virCommandRun(cmd, NULL) != 0)
+        return -1;
+
+    VIR_DEBUG("Got nbdkit version %s", nbdkit->version);
+    return 0;
+}
+
+
+static void
+qemuNbdkitCapsFinalize(GObject *object)
+{
+    qemuNbdkitCaps *nbdkit = QEMU_NBDKIT_CAPS(object);
+
+    g_clear_pointer(&nbdkit->path, g_free);
+    g_clear_pointer(&nbdkit->version, g_free);
+    g_clear_pointer(&nbdkit->flags, virBitmapFree);
+
+    G_OBJECT_CLASS(qemu_nbdkit_caps_parent_class)->finalize(object);
+}
+
+
+void
+qemu_nbdkit_caps_init(qemuNbdkitCaps *caps)
+{
+    caps->flags = virBitmapNew(QEMU_NBDKIT_CAPS_LAST);
+    caps->version = NULL;
+}
+
+
+static void
+qemu_nbdkit_caps_class_init(qemuNbdkitCapsClass *klass)
+{
+    GObjectClass *obj = G_OBJECT_CLASS(klass);
+
+    obj->finalize = qemuNbdkitCapsFinalize;
+}
+
+
+qemuNbdkitCaps *
+qemuNbdkitCapsNew(const char *path)
+{
+    qemuNbdkitCaps *caps = g_object_new(QEMU_TYPE_NBDKIT_CAPS, NULL);
+    caps->path = g_strdup(path);
+
+    return caps;
+}
+
+
+G_GNUC_UNUSED static void
+qemuNbdkitCapsQuery(qemuNbdkitCaps *caps)
+{
+    qemuNbdkitCapsQueryPlugins(caps);
+    qemuNbdkitCapsQueryFilters(caps);
+    qemuNbdkitCapsQueryVersion(caps);
+}
+
+
+bool
+qemuNbdkitCapsGet(qemuNbdkitCaps *nbdkitCaps,
+                  qemuNbdkitCapsFlags flag)
+{
+    return virBitmapIsBitSet(nbdkitCaps->flags, flag);
+}
+
+
+void
+qemuNbdkitCapsSet(qemuNbdkitCaps *nbdkitCaps,
+                  qemuNbdkitCapsFlags flag)
+{
+    ignore_value(virBitmapSetBit(nbdkitCaps->flags, flag));
+}
diff --git a/src/qemu/qemu_nbdkit.h b/src/qemu/qemu_nbdkit.h
new file mode 100644
index 0000000000..8ffb0f7044
--- /dev/null
+++ b/src/qemu/qemu_nbdkit.h
@@ -0,0 +1,52 @@
+/*
+ * qemu_nbdkit.h: helpers for using nbdkit
+ *
+ * Copyright (C) 2021 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.1 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, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include "internal.h"
+#include "virenum.h"
+
+typedef struct _qemuNbdkitCaps qemuNbdkitCaps;
+
+typedef enum {
+    /* 0 */
+    QEMU_NBDKIT_CAPS_PLUGIN_CURL,
+    QEMU_NBDKIT_CAPS_PLUGIN_SSH,
+    QEMU_NBDKIT_CAPS_FILTER_READAHEAD,
+
+    QEMU_NBDKIT_CAPS_LAST,
+} qemuNbdkitCapsFlags;
+
+VIR_ENUM_DECL(qemuNbdkitCaps);
+
+qemuNbdkitCaps *
+qemuNbdkitCapsNew(const char *path);
+
+bool
+qemuNbdkitCapsGet(qemuNbdkitCaps *nbdkitCaps,
+                  qemuNbdkitCapsFlags flag);
+
+void
+qemuNbdkitCapsSet(qemuNbdkitCaps *nbdkitCaps,
+                  qemuNbdkitCapsFlags flag);
+
+#define QEMU_TYPE_NBDKIT_CAPS qemu_nbdkit_caps_get_type()
+G_DECLARE_FINAL_TYPE(qemuNbdkitCaps, qemu_nbdkit_caps, QEMU, NBDKIT_CAPS, 
GObject);
-- 
2.37.3

Reply via email to