Outputs are a little bit trickier than filters, because if user wants to change
the set of outputs that is currently defined for a different set that may
contain outputs that do already exist in the current set, opening a file
descriptor for that output would only work for files, but not for syslog or
journald, because that would overwrite the existing ones which might (and
probably will be in use by workers). So, we need a mechanism to find out, if
such an output is already defined and only copy its data. For files, the data
also include the already opened file descriptor. For journald, the file
descriptor is global, so nothing to copy there. Syslog is the most trickiest
one, since it keeps the open file descriptor to system daemon private and
cannot be reopened (to change the message prefix) until the very last moment
when the whole output set is ready to be swapped with the defined one.
This method is also used when deallocating a list of outputs (either the new
copy that is just being prepared or the global active set of outputs).
According to the paragraph above, the problem of changing data when it is
being used has been solved. It still needs to be ensured that when deallocating
the global active set of outputs after it was swap with the user-provided copy
does not close all file descriptors, since that would cause invalid references
in the copy that we just swapped. By issuing virLogOutputExist during
deallocation, the described scenario can be safely prevented.
---
src/libvirt_private.syms | 1 +
src/util/virlog.c | 36 ++++++++++++++++++++++++++++++++++++
src/util/virlog.h | 1 +
3 files changed, 38 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 5d6224e..13598d0 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1795,6 +1795,7 @@ virLogGetNbOutputs;
virLogGetOutputs;
virLogLock;
virLogMessage;
+virLogOutputExists;
virLogOutputFree;
virLogOutputListFree;
virLogOutputNew;
diff --git a/src/util/virlog.c b/src/util/virlog.c
index 9fe47fb..204372f 100644
--- a/src/util/virlog.c
+++ b/src/util/virlog.c
@@ -186,6 +186,42 @@ VIR_ONCE_GLOBAL_INIT(virLog)
/**
+ * virLogOutputExists:
+ * @dest: destination type
+ * @opaque: opaque data to the method
+ *
+ * Looks for an output of destination type @dest. If such output exists,
+ * a reference to the output is returned, unless the destination is of type
+ * file in which case a comparison of the output's data with @opaque needs to
+ * be done first.
+ *
+ * Returns a reference to an output if one was found or NULL if such output
+ * does not exist.
+ */
+virLogOutputPtr
+virLogOutputExists(virLogDestination dest, const void *opaque)
+{
+ size_t i;
+ const char *name = opaque;
+
+ for (i = 0; i < virLogNbOutputs; i++) {
+ if (!virLogOutputs[i])
+ continue;
+
+ if (dest == virLogOutputs[i]->dest) {
+ if (dest != VIR_LOG_TO_FILE)
+ return virLogOutputs[i];
+
+ if (STREQ(virLogOutputs[i]->name, name))
+ return virLogOutputs[i];
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
* virLogReset:
*
* Reset the logging module to its default initial state
diff --git a/src/util/virlog.h b/src/util/virlog.h
index 0102489..1c55a48 100644
--- a/src/util/virlog.h
+++ b/src/util/virlog.h
@@ -229,5 +229,6 @@ extern void virLogVMessage(virLogSourcePtr source,
bool virLogProbablyLogMessage(const char *str);
int virLogDefineOutputs(virLogOutputPtr *outputs, size_t noutputs);
int virLogDefineFilters(virLogFilterPtr *filters, size_t nfilters);
+virLogOutputPtr virLogOutputExists(virLogDestination dest, const void *opaque);
#endif
--
2.4.11