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@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list