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