On 08/18/2016 07:47 AM, Erik Skultety wrote:
Another abstraction added on the top of parsing a single logging
output. This
method takes and parses the whole set of outputs, adding each single output
that has already been parsed into a caller-provided array. If the user-supplied
string contained duplicate outputs, only the last occurrence is taken into
account (all the others are removed from the list), so we silently avoid
duplicate logs and leaking journald fds.
Signed-off-by: Erik Skultety <eskultet(a)redhat.com>
---
src/libvirt_private.syms | 1 +
src/util/virlog.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++
src/util/virlog.h | 1 +
3 files changed, 81 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 1dfd7c8..b12ca92 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1869,6 +1869,7 @@ virLogParseAndDefineOutputs;
virLogParseDefaultPriority;
virLogParseFilter;
virLogParseOutput;
+virLogParseOutputs;
virLogPriorityFromSyslog;
virLogProbablyLogMessage;
virLogReset;
diff --git a/src/util/virlog.c b/src/util/virlog.c
index 43b3d75..89e58cd 100644
--- a/src/util/virlog.c
+++ b/src/util/virlog.c
@@ -1966,3 +1966,82 @@ virLogParseFilter(const char *filter)
virStringFreeList(tokens);
return ret;
}
+
+/**
+ * virLogParseOutputs:
+ * @src: string defining a (set of) output(s)
+ * @outputs: user-supplied list where parsed outputs from @src shall be stored
+ *
+ * The format for an output can be:
+ * x:stderr
+ * output goes to stderr
+ * x:syslog:name
+ * use syslog for the output and use the given name as the ident
+ * x:file:file_path
+ * output to a file, with the given filepath
+ * In all case the x prefix is the minimal level, acting as a filter
+ * 1: DEBUG
+ * 2: INFO
+ * 3: WARNING
+ * 4: ERROR
+ *
+ * Multiple outputs can be defined within @src string, they just need to be
+ * separated by spaces.
+ *
+ * If running in setuid mode, then only the 'stderr' output will
+ * be allowed
+ *
Much of this text would be moved to patch 9. This function doesn't do
any of those format checks.
+ * Returns the number of outputs parsed or -1 in case of error.
+ */
+int
+virLogParseOutputs(const char *src, virLogOutputPtr **outputs)
+{
+ int ret = -1;
+ int at = -1;
+ size_t noutputs = 0;
+ size_t i;
+ char **strings = NULL;
+ virLogOutputPtr output = NULL;
+ virLogOutputPtr *list = NULL;
+
+ if (!src)
+ return -1;
Again ATTRIBUTE_NONNULL(1) in the prototype
+
+ VIR_DEBUG("outputs=%s", src);
+
+ if (!(strings = virStringSplit(src, " ", 0)))
You could use the Count version and then...
+ goto cleanup;
+
+ for (i = 0; strings[i]; i++) {
...rather than strings[i], it's < count
+ /* virStringSplit may return empty strings */
+ if (STREQ(strings[i], ""))
+ continue;
+
+ if (!(output = virLogParseOutput(strings[i])))
+ goto cleanup;
+
+ /* let's check if a duplicate output does not already exist in which
+ * case we replace it with its last occurrence
+ */
+ if ((at = virLogFindOutput(list, noutputs, output->dest,
+ output->name)) >= 0) {
+ virLogOutputFree(list[at]);
+ VIR_DELETE_ELEMENT(list, at, noutputs);
+ }
+
+ if (VIR_APPEND_ELEMENT(list, noutputs, output) < 0) {
+ virLogOutputFree(output);
In this case, the old one is also gone... So we've effectively removed
it. Is that intentional? or should the DELETE of 'at' occur after this
successfully adds a new one?
IOW:
at = virLogFindOutput()
if (VIR_APPEND_ELEMENT() < 0)
...
}
if (at >= 0) {
virLogOutputFree(list[at]);
VIR_DELETE_ELEMENT();
}
+ goto cleanup;
+ }
+
+ virLogOutputFree(output);
Is this right? I don't think it's necessary unless you change to using
the _COPY append macro
+ }
+
+ ret = noutputs;
+ *outputs = list;
If you then set "list = NULL"...
+ cleanup:
+ if (ret < 0)
... the (ret < 0) is not necessary
+ virLogOutputListFree(list, noutputs);
+ virStringFreeList(strings);
+ return ret;
+}
diff --git a/src/util/virlog.h b/src/util/virlog.h
index e7f6b85..ed60c00 100644
--- a/src/util/virlog.h
+++ b/src/util/virlog.h
@@ -247,5 +247,6 @@ virLogOutputPtr virLogNewOutputToSyslog(virLogPriority priority,
virLogOutputPtr virLogNewOutputToJournald(int priority);
virLogOutputPtr virLogParseOutput(const char *src);
virLogFilterPtr virLogParseFilter(const char *src);
+int virLogParseOutputs(const char *src, virLogOutputPtr **outputs);
s/;/ATTRIBUTE_NONNULL(1);
Conditional ACK - guess I'm curious how the duplication and error path
issue falls out...
John
#endif