On Thu, Nov 03, 2016 at 08:18:57PM +0800, Michal Privoznik wrote:
Now that we are able to store security labels for devices, next
step is to flush them into a file. For more convenience I've
chosen JSON format (as we have all the APIs needed for processing
the format).
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
po/POTFILES.in | 1 +
src/libvirt_private.syms | 2 +
src/util/virudev.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++
src/util/virudev.h | 5 ++
4 files changed, 165 insertions(+)
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1469240..dabc612 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -248,6 +248,7 @@ src/util/virthreadpool.c
src/util/virtime.c
src/util/virtpm.c
src/util/virtypedparam.c
+src/util/virudev.c
src/util/viruri.c
src/util/virusb.c
src/util/virutil.c
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 073b00f..ca64c80 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2579,6 +2579,8 @@ virTypedParamsValidate;
# util/virudev.h
virUdevMgrAddLabel;
+virUdevMgrDumpFile;
+virUdevMgrDumpStr;
virUdevMgrNew;
virUdevMgrRemoveAllLabels;
diff --git a/src/util/virudev.c b/src/util/virudev.c
index f4799e7..7f52149 100644
--- a/src/util/virudev.c
+++ b/src/util/virudev.c
@@ -24,7 +24,9 @@
#include "internal.h"
#include "viralloc.h"
+#include "virfile.h"
#include "virhash.h"
+#include "virjson.h"
#include "virobject.h"
#include "virudev.h"
@@ -112,6 +114,68 @@ udevSeclabelUpdate(udevSeclabelPtr list,
}
+static virJSONValuePtr
+udevSeclabelDump(const virSecurityDeviceLabelDef *seclabel)
+{
+ virJSONValuePtr object;
+
+ if (!(object = virJSONValueNewObject()) ||
+ virJSONValueObjectAppendString(object, "model", seclabel->model)
< 0 ||
+ virJSONValueObjectAppendString(object, "label", seclabel->label)
< 0)
+ goto error;
+
+ return object;
+
+ error:
+ virJSONValueFree(object);
+ return NULL;
+}
+
+
+static int
+udevSeclabelsDump(void *payload,
+ const void *name,
+ void *opaque)
+{
+ udevSeclabelPtr list = payload;
+ const char *device = name;
+ virJSONValuePtr seclabels = opaque;
+ virJSONValuePtr deviceLabels = NULL;
+ virJSONValuePtr deviceJSON = NULL;
+ size_t i;
+ int ret = -1;
+
+ if (!(deviceLabels = virJSONValueNewArray()))
+ return ret;
+
+ for (i = 0; i < list->nseclabels; i++) {
+ virJSONValuePtr seclabel = udevSeclabelDump(list->seclabels[i]);
+
+ if (!seclabel ||
+ virJSONValueArrayAppend(deviceLabels, seclabel) < 0) {
+ virJSONValueFree(seclabel);
+ goto cleanup;
+ }
+ }
+
+ if (!(deviceJSON = virJSONValueNewObject()) ||
+ virJSONValueObjectAppendString(deviceJSON, "device", device) < 0
||
+ virJSONValueObjectAppend(deviceJSON, "labels", deviceLabels) < 0)
+ goto cleanup;
+ deviceLabels = NULL;
+
+ if (virJSONValueArrayAppend(seclabels, deviceJSON) < 0)
+ goto cleanup;
+ deviceJSON = NULL;
+
+ ret = 0;
+ cleanup:
+ virJSONValueFree(deviceJSON);
+ virJSONValueFree(deviceLabels);
+ return ret;
+}
+
+
static void
virUdevMgrDispose(void *obj)
{
@@ -202,3 +266,96 @@ virUdevMgrRemoveAllLabels(virUdevMgrPtr mgr,
virObjectUnlock(mgr);
return ret;
}
+
+
+static virJSONValuePtr
+virUdevSeclabelDump(virUdevMgrPtr mgr)
+{
+ virJSONValuePtr seclabels;
+
+ if (!(seclabels = virJSONValueNewArray()))
+ return NULL;
+
+ if (virHashForEach(mgr->labels, udevSeclabelsDump, seclabels) < 0) {
+ virJSONValueFree(seclabels);
+ return NULL;
+ }
+
+ return seclabels;
+}
+
+
+static char *
+virUdevMgrDumpInternal(virUdevMgrPtr mgr)
+{
+ virJSONValuePtr object = NULL;
+ virJSONValuePtr child = NULL;
+ char *ret = NULL;
+
+ if (!(object = virJSONValueNewObject()))
+ goto cleanup;
+
+ if (!(child = virUdevSeclabelDump(mgr)))
+ goto cleanup;
+
+ if (virJSONValueObjectAppend(object, "labels", child) < 0) {
+ virJSONValueFree(child);
+ goto cleanup;
+ }
+
+ ret = virJSONValueToString(object, true);
+ cleanup:
+ virJSONValueFree(object);
+ return ret;
+}
+
+
+char *
+virUdevMgrDumpStr(virUdevMgrPtr mgr)
+{
+ char *ret;
+
+ virObjectLock(mgr);
+ ret = virUdevMgrDumpInternal(mgr);
+ virObjectUnlock(mgr);
+ return ret;
+}
+
+
+static int
+virUdevMgrRewriter(int fd, void *opaque)
+{
+ const char *str = opaque;
+
+ return safewrite(fd, str, strlen(str));
+}
+
+
+int
+virUdevMgrDumpFile(virUdevMgrPtr mgr,
+ const char *filename)
+{
+ int ret = -1;
+ char *state;
+
+ virObjectLock(mgr);
+
+ if (!(state = virUdevMgrDumpInternal(mgr)))
+ goto cleanup;
+
+ /* Here we shouldn't use pure virFileWriteStr() as that one is not atomic.
+ * We can be interrupted in the middle (e.g. due to a context switch) and
+ * thus leave the file partially written. */
+ if (virFileRewrite(filename, 0644, virUdevMgrRewriter, state) < 0) {
+ virReportSystemError(errno,
+ _("Unable to save state file %s"),
+ filename);
+ goto cleanup;
+ }
Dumping the entire DB as a single file is pretty inefficient when you consider
hosts with 1000's of guests with multiple disks attached. As suggested last
time, any database should be one-file per associated disk - there's no
compelling reason to require all disk info to be in a single file AFAICT.
Regards,
Daniel
--
|:
http://berrange.com -o-
http://www.flickr.com/photos/dberrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org :|
|:
http://entangle-photo.org -o-
http://search.cpan.org/~danberr/ :|