[libvirt] [PATCH v2 09/19] virudev: Parse virUdevMgr from JSON

Michal Privoznik mprivozn at redhat.com
Thu Nov 3 12:18:59 UTC 2016


Now that we are able to dump internal state into a JSON
file/string, we should be able to reverse the process and
reconstruct the internal state from a JSON file/string.

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 src/libvirt_private.syms |   2 +
 src/util/virudev.c       | 159 +++++++++++++++++++++++++++++++++++++++++++++++
 src/util/virudev.h       |   2 +
 tests/virudevtest.c      |  45 ++++++++++++++
 4 files changed, 208 insertions(+)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index ca64c80..0f08018 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2582,6 +2582,8 @@ virUdevMgrAddLabel;
 virUdevMgrDumpFile;
 virUdevMgrDumpStr;
 virUdevMgrNew;
+virUdevMgrNewFromFile;
+virUdevMgrNewFromStr;
 virUdevMgrRemoveAllLabels;
 
 
diff --git a/src/util/virudev.c b/src/util/virudev.c
index 7f52149..d60fbf9 100644
--- a/src/util/virudev.c
+++ b/src/util/virudev.c
@@ -28,6 +28,7 @@
 #include "virhash.h"
 #include "virjson.h"
 #include "virobject.h"
+#include "virstring.h"
 #include "virudev.h"
 
 #define VIR_FROM_THIS VIR_FROM_SECURITY
@@ -176,6 +177,49 @@ udevSeclabelsDump(void *payload,
 }
 
 
+static udevSeclabelPtr
+udevSeclabelRestore(virJSONValuePtr labels)
+{
+    udevSeclabelPtr ret = NULL;
+    size_t i;
+
+    if (VIR_ALLOC(ret) < 0)
+        goto error;
+
+    for (i = 0; i < virJSONValueArraySize(labels); i++) {
+        virJSONValuePtr labelJSON = virJSONValueArrayGet(labels, i);
+        virSecurityDeviceLabelDefPtr seclabel;
+        const char *model;
+        const char *label;
+
+        if (!(model = virJSONValueObjectGetString(labelJSON, "model"))) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("seclabel missing model in JSON"));
+            goto error;
+        }
+
+        if (!(label = virJSONValueObjectGetString(labelJSON, "label"))) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("seclabel missing label in JSON"));
+            goto error;
+        }
+
+        if (!(seclabel = virSecurityDeviceLabelDefNewLabel(model, label)) ||
+            udevSeclabelAppend(ret, seclabel) < 0) {
+            virSecurityDeviceLabelDefFree(seclabel);
+            goto error;
+        }
+        virSecurityDeviceLabelDefFree(seclabel);
+    }
+
+    return ret;
+
+ error:
+    udevSeclabelFree(ret, NULL);
+    return NULL;
+}
+
+
 static void
 virUdevMgrDispose(void *obj)
 {
@@ -359,3 +403,118 @@ virUdevMgrDumpFile(virUdevMgrPtr mgr,
     VIR_FREE(state);
     return ret;
 }
+
+
+static int
+virUdevRestoreLabels(virUdevMgrPtr mgr ATTRIBUTE_UNUSED,
+                     virJSONValuePtr labelsArray)
+{
+    int ret = -1;
+    size_t i;
+    udevSeclabelPtr list = NULL;
+
+    for (i = 0; i < virJSONValueArraySize(labelsArray); i++) {
+        virJSONValuePtr deviceJSON = virJSONValueArrayGet(labelsArray, i);
+        virJSONValuePtr labels;
+        const char *device;
+
+        if (!(device = virJSONValueObjectGetString(deviceJSON, "device"))) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Missing device name"));
+            goto cleanup;
+        }
+
+        if (!(labels = virJSONValueObjectGetArray(deviceJSON, "labels"))) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Missing device labels array"));
+            goto cleanup;
+        }
+
+        if (!(list = udevSeclabelRestore(labels))) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Malformed seclabels for device %s"), device);
+            goto cleanup;
+        }
+
+        if (virHashAddEntry(mgr->labels, device, list) < 0)
+            goto cleanup;
+        list = NULL;
+    }
+
+    ret = 0;
+ cleanup:
+    udevSeclabelFree(list, NULL);
+    return ret;
+}
+
+
+static int
+virUdevMgrNewFromStrInternal(virUdevMgrPtr mgr,
+                             const char *state)
+{
+    virJSONValuePtr object;
+    virJSONValuePtr child;
+    int ret = -1;
+
+    if (!(object = virJSONValueFromString(state)))
+        goto cleanup;
+
+    if (!(child = virJSONValueObjectGetArray(object, "labels"))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Missing 'labels' object in JSON document"));
+        goto cleanup;
+    }
+
+    if (virUdevRestoreLabels(mgr, child) < 0)
+        goto cleanup;
+
+    ret = 0;
+ cleanup:
+    virJSONValueFree(object);
+    return ret;
+}
+
+
+virUdevMgrPtr
+virUdevMgrNewFromStr(const char *str)
+{
+    virUdevMgrPtr mgr;
+
+    if (!(mgr = virUdevMgrNew()))
+        goto error;
+
+    if (virUdevMgrNewFromStrInternal(mgr, str) < 0)
+        goto error;
+
+    return mgr;
+ error:
+    virObjectUnref(mgr);
+    return NULL;
+}
+
+
+virUdevMgrPtr
+virUdevMgrNewFromFile(const char *filename)
+{
+    virUdevMgrPtr mgr;
+    char *state = NULL;
+
+    if (!(mgr = virUdevMgrNew()))
+        goto error;
+
+    if (virFileReadAll(filename,
+                       1024 * 1024 * 10, /* 10 MB */
+                       &state) < 0)
+        goto error;
+
+    if (virUdevMgrNewFromStrInternal(mgr, state) < 0)
+        goto error;
+
+    VIR_FREE(state);
+
+    return mgr;
+ error:
+    virObjectUnref(mgr);
+    VIR_FREE(state);
+    return NULL;
+}
diff --git a/src/util/virudev.h b/src/util/virudev.h
index 1d5a23e..82b2b4f 100644
--- a/src/util/virudev.h
+++ b/src/util/virudev.h
@@ -29,6 +29,8 @@ typedef struct _virUdevMgr virUdevMgr;
 typedef virUdevMgr *virUdevMgrPtr;
 
 virUdevMgrPtr virUdevMgrNew(void);
+virUdevMgrPtr virUdevMgrNewFromStr(const char *str);
+virUdevMgrPtr virUdevMgrNewFromFile(const char *filename);
 
 int virUdevMgrAddLabel(virUdevMgrPtr mgr,
                        const char *device,
diff --git a/tests/virudevtest.c b/tests/virudevtest.c
index 883d751..c395741 100644
--- a/tests/virudevtest.c
+++ b/tests/virudevtest.c
@@ -93,6 +93,37 @@ testDump(const void *opaque)
 
 
 static int
+testParse(const void *opaque)
+{
+    const struct testUdevData *data = opaque;
+    virUdevMgrPtr mgr = NULL;
+    char *filename = NULL;
+    char *state = NULL;
+    int ret = -1;
+
+    if (virAsprintf(&filename, "%s/virudevtestdata/%s.json",
+                    abs_srcdir, data->file) < 0)
+        goto cleanup;
+
+    if (!(mgr = virUdevMgrNewFromFile(filename)))
+        goto cleanup;
+
+    if (!(state = virUdevMgrDumpStr(mgr)))
+        goto cleanup;
+
+    if (virTestCompareToFile(state, filename))
+        goto cleanup;
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(state);
+    VIR_FREE(filename);
+    virObjectUnref(mgr);
+    return ret;
+}
+
+
+static int
 mymain(void)
 {
     int ret = 0;
@@ -107,6 +138,15 @@ mymain(void)
             ret = -1;                                               \
     } while (0)
 
+#define DO_TEST_PARSE(filename)                                     \
+    do {                                                            \
+        struct testUdevData data = {                                \
+            .file = filename,                                       \
+        };                                                          \
+        if (virTestRun("Parse " filename, testParse, &data) < 0)    \
+            ret = -1;                                               \
+    } while (0)
+
     DO_TEST_DUMP("empty", NULL);
     DO_TEST_DUMP("simple-selinux",
                  "/dev/sda", "selinux", "someSELinuxLabel");
@@ -118,6 +158,11 @@ mymain(void)
                  "/dev/sdb", "dac",     "otherDACLabel",
                  "/dev/sdb", "selinux", "otherSELinuxLabel");
 
+    DO_TEST_PARSE("empty");
+    DO_TEST_PARSE("simple-selinux");
+    DO_TEST_PARSE("simple-dac");
+    DO_TEST_PARSE("complex");
+
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
-- 
2.8.4




More information about the libvir-list mailing list