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