]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: introduce a qemuDomainLogContext object
authorDaniel P. Berrange <berrange@redhat.com>
Thu, 12 Nov 2015 12:43:29 +0000 (12:43 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Thu, 26 Nov 2015 14:30:15 +0000 (14:30 +0000)
Introduce a qemuDomainLogContext object to encapsulate
handling of I/O to/from the domain log file. This will
hide details of the log file implementation from the
rest of the driver, making it easier to introduce
support for virtlogd later.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
src/qemu/qemu_domain.c
src/qemu/qemu_domain.h

index 8436af71a7e31099c0259ccdb7defae883f1fdaa..cbf51d1710b49b12afeb170d7eac5c33dac18069 100644 (file)
@@ -40,6 +40,7 @@
 #include "virstoragefile.h"
 #include "virstring.h"
 #include "virthreadjob.h"
+#include "viratomic.h"
 
 #include "storage/storage_driver.h"
 
@@ -77,6 +78,13 @@ VIR_ENUM_IMPL(qemuDomainAsyncJob, QEMU_ASYNC_JOB_LAST,
 );
 
 
+struct _qemuDomainLogContext {
+    int refs;
+    int writefd;
+    int readfd;
+    off_t pos;
+};
+
 const char *
 qemuDomainAsyncJobPhaseToString(qemuDomainAsyncJob job,
                                 int phase ATTRIBUTE_UNUSED)
@@ -2249,6 +2257,183 @@ void qemuDomainObjCheckNetTaint(virQEMUDriverPtr driver,
 }
 
 
+qemuDomainLogContextPtr qemuDomainLogContextNew(virQEMUDriverPtr driver,
+                                                virDomainObjPtr vm,
+                                                qemuDomainLogContextMode mode)
+{
+    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    qemuDomainLogContextPtr ctxt = NULL;
+    char *logfile = NULL;
+
+    if (VIR_ALLOC(ctxt) < 0)
+        goto error;
+
+    ctxt->writefd = -1;
+    ctxt->readfd = -1;
+    virAtomicIntSet(&ctxt->refs, 1);
+
+    if (virAsprintf(&logfile, "%s/%s.log", cfg->logDir, vm->def->name) < 0)
+        goto error;
+
+    if ((ctxt->writefd = open(logfile, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR)) < 0) {
+        virReportSystemError(errno, _("failed to create logfile %s"),
+                             logfile);
+        goto error;
+    }
+    if (virSetCloseExec(ctxt->writefd) < 0) {
+        virReportSystemError(errno, _("failed to set close-on-exec flag on %s"),
+                             logfile);
+        goto error;
+    }
+
+    /* For unprivileged startup we must truncate the file since
+     * we can't rely on logrotate. We don't use O_TRUNC since
+     * it is better for SELinux policy if we truncate afterwards */
+    if (mode == QEMU_DOMAIN_LOG_CONTEXT_MODE_START &&
+        !virQEMUDriverIsPrivileged(driver) &&
+        ftruncate(ctxt->writefd, 0) < 0) {
+        virReportSystemError(errno, _("failed to truncate %s"),
+                             logfile);
+        goto error;
+    }
+
+    if (mode == QEMU_DOMAIN_LOG_CONTEXT_MODE_START) {
+        if ((ctxt->readfd = open(logfile, O_RDONLY, S_IRUSR | S_IWUSR)) < 0) {
+            virReportSystemError(errno, _("failed to open logfile %s"),
+                                 logfile);
+            goto error;
+        }
+        if (virSetCloseExec(ctxt->readfd) < 0) {
+            virReportSystemError(errno, _("failed to set close-on-exec flag on %s"),
+                                 logfile);
+            goto error;
+        }
+
+        if ((ctxt->pos = lseek(ctxt->writefd, 0, SEEK_END)) < 0) {
+            virReportSystemError(errno, _("failed to seek in log file %s"),
+                                 logfile);
+            goto error;
+        }
+    }
+
+    virObjectUnref(cfg);
+    return ctxt;
+
+ error:
+    virObjectUnref(cfg);
+    qemuDomainLogContextFree(ctxt);
+    return NULL;
+}
+
+
+int qemuDomainLogContextWrite(qemuDomainLogContextPtr ctxt,
+                              const char *fmt, ...)
+{
+    va_list argptr;
+    char *message = NULL;
+    int ret = -1;
+
+    va_start(argptr, fmt);
+
+    if (virVasprintf(&message, fmt, argptr) < 0)
+        goto cleanup;
+    if (lseek(ctxt->writefd, 0, SEEK_END) < 0) {
+        virReportSystemError(errno, "%s",
+                             _("Unable to see to end of domain logfile"));
+        goto cleanup;
+    }
+    if (safewrite(ctxt->writefd, message, strlen(message)) < 0) {
+        virReportSystemError(errno, "%s",
+                             _("Unable to write to domain logfile"));
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    va_end(argptr);
+    VIR_FREE(message);
+    return ret;
+}
+
+
+ssize_t qemuDomainLogContextRead(qemuDomainLogContextPtr ctxt,
+                                 char **msg)
+{
+    char *buf;
+    size_t buflen = 1024 * 128;
+    ssize_t got;
+
+    /* Best effort jump to start of messages */
+    ignore_value(lseek(ctxt->readfd, ctxt->pos, SEEK_SET));
+
+    if (VIR_ALLOC_N(buf, buflen) < 0)
+        return -1;
+
+    got = saferead(ctxt->readfd, buf, buflen - 1);
+    if (got < 0) {
+        VIR_FREE(buf);
+        virReportSystemError(errno, "%s",
+                             _("Unable to read from log file"));
+        return -1;
+    }
+
+    buf[got] = '\0';
+
+    ignore_value(VIR_REALLOC_N_QUIET(buf, got + 1));
+    *msg = buf;
+
+    return got;
+}
+
+
+int qemuDomainLogContextGetWriteFD(qemuDomainLogContextPtr ctxt)
+{
+    return ctxt->writefd;
+}
+
+
+int qemuDomainLogContextGetReadFD(qemuDomainLogContextPtr ctxt)
+{
+    return ctxt->readfd;
+}
+
+
+void qemuDomainLogContextMarkPosition(qemuDomainLogContextPtr ctxt)
+{
+    ctxt->pos = lseek(ctxt->writefd, 0, SEEK_END);
+}
+
+
+off_t qemuDomainLogContextGetPosition(qemuDomainLogContextPtr ctxt)
+{
+    return ctxt->pos;
+}
+
+
+void qemuDomainLogContextRef(qemuDomainLogContextPtr ctxt)
+{
+    virAtomicIntInc(&ctxt->refs);
+}
+
+
+void qemuDomainLogContextFree(qemuDomainLogContextPtr ctxt)
+{
+    bool lastRef;
+
+    if (!ctxt)
+        return;
+
+    lastRef = virAtomicIntDecAndTest(&ctxt->refs);
+    if (!lastRef)
+        return;
+
+    VIR_FORCE_CLOSE(ctxt->writefd);
+    VIR_FORCE_CLOSE(ctxt->readfd);
+    VIR_FREE(ctxt);
+}
+
+
 static int
 qemuDomainOpenLogHelper(virQEMUDriverConfigPtr cfg,
                         virDomainObjPtr vm,
index fffb8f3e817349290a1117573083b89196212a5f..9b9da13d3d8d51aa185d5df8e9b74b50c1d687ef 100644 (file)
@@ -245,6 +245,9 @@ struct qemuProcessEvent {
     void *data;
 };
 
+typedef struct _qemuDomainLogContext qemuDomainLogContext;
+typedef qemuDomainLogContext *qemuDomainLogContextPtr;
+
 const char *qemuDomainAsyncJobPhaseToString(qemuDomainAsyncJob job,
                                             int phase);
 int qemuDomainAsyncJobPhaseFromString(qemuDomainAsyncJob job,
@@ -349,6 +352,25 @@ void qemuDomainObjCheckNetTaint(virQEMUDriverPtr driver,
                                 virDomainNetDefPtr net,
                                 int logFD);
 
+typedef enum {
+    QEMU_DOMAIN_LOG_CONTEXT_MODE_START,
+    QEMU_DOMAIN_LOG_CONTEXT_MODE_ATTACH,
+    QEMU_DOMAIN_LOG_CONTEXT_MODE_STOP,
+} qemuDomainLogContextMode;
+
+qemuDomainLogContextPtr qemuDomainLogContextNew(virQEMUDriverPtr driver,
+                                                virDomainObjPtr vm,
+                                                qemuDomainLogContextMode mode);
+int qemuDomainLogContextWrite(qemuDomainLogContextPtr ctxt,
+                              const char *fmt, ...) ATTRIBUTE_FMT_PRINTF(2, 3);
+ssize_t qemuDomainLogContextRead(qemuDomainLogContextPtr ctxt,
+                                 char **msg);
+int qemuDomainLogContextGetWriteFD(qemuDomainLogContextPtr ctxt);
+int qemuDomainLogContextGetReadFD(qemuDomainLogContextPtr ctxt);
+void qemuDomainLogContextMarkPosition(qemuDomainLogContextPtr ctxt);
+off_t qemuDomainLogContextGetPosition(qemuDomainLogContextPtr ctxt);
+void qemuDomainLogContextRef(qemuDomainLogContextPtr ctxt);
+void qemuDomainLogContextFree(qemuDomainLogContextPtr ctxt);
 
 int qemuDomainCreateLog(virQEMUDriverPtr driver, virDomainObjPtr vm, bool append);
 int qemuDomainOpenLog(virQEMUDriverPtr driver, virDomainObjPtr vm);