Start using the method that was introduced and described by commit 29d0068b.
---
src/util/virlog.c | 83 ++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 58 insertions(+), 25 deletions(-)
diff --git a/src/util/virlog.c b/src/util/virlog.c
index 204372f..62533b1 100644
--- a/src/util/virlog.c
+++ b/src/util/virlog.c
@@ -344,10 +344,17 @@ virLogResetOutputs(void)
void
virLogOutputFree(virLogOutputPtr output)
{
+ virLogOutputPtr tmp = NULL;
+
if (!output)
return;
- if (output->c)
+ /* @output shall be closed only if such output does not already exist
+ * in the global list of outputs or @output itself is part of the global
+ * list of outputs
+ */
+ tmp = virLogOutputExists(output->dest, output->name);
+ if (output->c && (!tmp || tmp == output))
output->c(output->data);
VIR_FREE(output->name);
VIR_FREE(output);
@@ -733,16 +740,21 @@ virLogNewOutputToFile(virLogPriority priority,
const char *file)
{
int fd;
- virLogOutputPtr ret = NULL;
+ virLogOutputPtr gref, ret = NULL;
- fd = open(file, O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR);
- if (fd < 0)
- return NULL;
+ if ((gref = virLogOutputExists(VIR_LOG_TO_FILE, file))) {
+ fd = (intptr_t) gref->data;
+ } else {
+ fd = open(file, O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR);
+ if (fd < 0)
+ return NULL;
+ }
if (!(ret = virLogOutputNew(virLogOutputToFd, virLogCloseFd,
(void *)(intptr_t)fd,
priority, VIR_LOG_TO_FILE, file))) {
- VIR_LOG_CLOSE(fd);
+ if (!gref)
+ VIR_LOG_CLOSE(fd);
return NULL;
}
return ret;
@@ -818,21 +830,39 @@ static virLogOutputPtr
virLogNewOutputToSyslog(virLogPriority priority,
const char *ident)
{
- virLogOutputPtr ret = NULL;
-
- /*
- * ident needs to be kept around on Solaris
+ virLogOutputPtr gref, ret = NULL;
+
+ /* syslog suffers from several issues:
+ * 1) Every other call to openlog would be a NOOP, but we can't close the
+ * existing connection just yet, because we're not holding the lock and
+ * the output cannot be changed until we're sure nothing can go wrong and
+ * we just swap our new list of outputs with the old global one.
+ *
+ * 2) Syslog keeps the open file descriptor private, so we can't just copy
+ * it like we do it with files if an output to syslog already exists and
+ * even if it did, there is no other way than to issue openlog if user
+ * wants to change ident.
+ *
+ * Therefore, dealing with syslog has to be special-cased and postponed
+ * until the very last moment.
*/
- VIR_FREE(current_ident);
- if (VIR_STRDUP(current_ident, ident) < 0)
- return NULL;
+ if (!(gref = virLogOutputExists(VIR_LOG_TO_SYSLOG, NULL))) {
+ /*
+ * rather than copying @ident, syslog uses caller's reference instead
+ */
+ VIR_FREE(current_ident);
+ if (VIR_STRDUP(current_ident, ident) < 0)
+ return NULL;
+
+ openlog(current_ident, 0, 0);
+ }
- openlog(current_ident, 0, 0);
if (!(ret = virLogOutputNew(virLogOutputToSyslog, virLogCloseSyslog,
- NULL, priority, VIR_LOG_TO_SYSLOG,
- ident))) {
- closelog();
- VIR_FREE(current_ident);
+ NULL, priority, VIR_LOG_TO_SYSLOG, ident))) {
+ if (!gref) {
+ closelog();
+ VIR_FREE(current_ident);
+ }
return NULL;
}
return ret;
@@ -1043,19 +1073,22 @@ static void virLogCloseJournald(void *data ATTRIBUTE_UNUSED)
static virLogOutputPtr virLogNewOutputToJournald(int priority)
{
- virLogOutputPtr ret = NULL;
+ virLogOutputPtr gref, ret = NULL;
- if ((journalfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
- return NULL;
- if (virSetInherit(journalfd, false) < 0) {
- VIR_LOG_CLOSE(journalfd);
- return NULL;
+ if (!(gref = virLogOutputExists(VIR_LOG_TO_JOURNALD, NULL))) {
+ if ((journalfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
+ return NULL;
+ if (virSetInherit(journalfd, false) < 0) {
+ VIR_LOG_CLOSE(journalfd);
+ return NULL;
+ }
}
if (!(ret = virLogOutputNew(virLogOutputToJournald,
virLogCloseJournald, NULL,
priority, VIR_LOG_TO_JOURNALD, NULL))) {
- VIR_LOG_CLOSE(journalfd);
+ if (!gref)
+ VIR_LOG_CLOSE(journalfd);
return NULL;
}
--
2.4.3