mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 05:35:25 +00:00
qemu: Extract qemuDomainLogContext into a new file
This will allow us to use it for nbdkit logging in upcoming commits. Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com> Reviewed-by: Peter Krempa <pkrempa@redhat.com>
This commit is contained in:
parent
abdc4f2092
commit
b658b1a27e
@ -174,6 +174,7 @@ src/qemu/qemu_hostdev.c
|
||||
src/qemu/qemu_hotplug.c
|
||||
src/qemu/qemu_interface.c
|
||||
src/qemu/qemu_interop_config.c
|
||||
src/qemu/qemu_logcontext.c
|
||||
src/qemu/qemu_migration.c
|
||||
src/qemu/qemu_migration_cookie.c
|
||||
src/qemu/qemu_migration_params.c
|
||||
|
@ -21,6 +21,7 @@ qemu_driver_sources = [
|
||||
'qemu_hotplug.c',
|
||||
'qemu_interface.c',
|
||||
'qemu_interop_config.c',
|
||||
'qemu_logcontext.c',
|
||||
'qemu_migration.c',
|
||||
'qemu_migration_cookie.c',
|
||||
'qemu_migration_params.c',
|
||||
|
@ -455,21 +455,8 @@ qemuDomainObjFromDomain(virDomainPtr domain)
|
||||
}
|
||||
|
||||
|
||||
struct _qemuDomainLogContext {
|
||||
GObject parent;
|
||||
|
||||
int writefd;
|
||||
int readfd; /* Only used if manager == NULL */
|
||||
off_t pos;
|
||||
ino_t inode; /* Only used if manager != NULL */
|
||||
char *path;
|
||||
virLogManager *manager;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(qemuDomainLogContext, qemu_domain_log_context, G_TYPE_OBJECT);
|
||||
static virClass *qemuDomainSaveCookieClass;
|
||||
|
||||
static void qemuDomainLogContextFinalize(GObject *obj);
|
||||
static void qemuDomainSaveCookieDispose(void *obj);
|
||||
|
||||
|
||||
@ -482,32 +469,8 @@ qemuDomainOnceInit(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qemu_domain_log_context_init(qemuDomainLogContext *logctxt G_GNUC_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
static void qemu_domain_log_context_class_init(qemuDomainLogContextClass *klass)
|
||||
{
|
||||
GObjectClass *obj = G_OBJECT_CLASS(klass);
|
||||
|
||||
obj->finalize = qemuDomainLogContextFinalize;
|
||||
}
|
||||
|
||||
VIR_ONCE_GLOBAL_INIT(qemuDomain);
|
||||
|
||||
static void
|
||||
qemuDomainLogContextFinalize(GObject *object)
|
||||
{
|
||||
qemuDomainLogContext *ctxt = QEMU_DOMAIN_LOG_CONTEXT(object);
|
||||
VIR_DEBUG("ctxt=%p", ctxt);
|
||||
|
||||
virLogManagerFree(ctxt->manager);
|
||||
VIR_FREE(ctxt->path);
|
||||
VIR_FORCE_CLOSE(ctxt->writefd);
|
||||
VIR_FORCE_CLOSE(ctxt->readfd);
|
||||
G_OBJECT_CLASS(qemu_domain_log_context_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
/* qemuDomainGetMasterKeyFilePath:
|
||||
* @libDir: Directory path to domain lib files
|
||||
*
|
||||
@ -6867,7 +6830,7 @@ static void G_GNUC_PRINTF(5, 6)
|
||||
qemuDomainObjTaintMsg(virQEMUDriver *driver,
|
||||
virDomainObj *obj,
|
||||
virDomainTaintFlags taint,
|
||||
qemuDomainLogContext *logCtxt,
|
||||
qemuLogContext *logCtxt,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
virErrorPtr orig_err = NULL;
|
||||
@ -6920,12 +6883,12 @@ qemuDomainObjTaintMsg(virQEMUDriver *driver,
|
||||
goto cleanup;
|
||||
|
||||
if (logCtxt) {
|
||||
rc = qemuDomainLogContextWrite(logCtxt,
|
||||
"%s: Domain id=%d is tainted: %s%s%s%s\n",
|
||||
timestamp,
|
||||
obj->def->id,
|
||||
virDomainTaintTypeToString(taint),
|
||||
extraprefix, extramsg, extrasuffix);
|
||||
rc = qemuLogContextWrite(logCtxt,
|
||||
"%s: Domain id=%d is tainted: %s%s%s%s\n",
|
||||
timestamp,
|
||||
obj->def->id,
|
||||
virDomainTaintTypeToString(taint),
|
||||
extraprefix, extramsg, extrasuffix);
|
||||
} else {
|
||||
rc = qemuDomainLogAppendMessage(driver, obj,
|
||||
"%s: Domain id=%d is tainted: %s%s%s%s\n",
|
||||
@ -6946,7 +6909,7 @@ qemuDomainObjTaintMsg(virQEMUDriver *driver,
|
||||
void qemuDomainObjTaint(virQEMUDriver *driver,
|
||||
virDomainObj *obj,
|
||||
virDomainTaintFlags taint,
|
||||
qemuDomainLogContext *logCtxt)
|
||||
qemuLogContext *logCtxt)
|
||||
{
|
||||
qemuDomainObjTaintMsg(driver, obj, taint, logCtxt, NULL);
|
||||
qemuDomainSaveStatus(obj);
|
||||
@ -6955,7 +6918,7 @@ void qemuDomainObjTaint(virQEMUDriver *driver,
|
||||
static void
|
||||
qemuDomainObjCheckMachineTaint(virQEMUDriver *driver,
|
||||
virDomainObj *obj,
|
||||
qemuDomainLogContext *logCtxt)
|
||||
qemuLogContext *logCtxt)
|
||||
{
|
||||
qemuDomainObjPrivate *priv = obj->privateData;
|
||||
virQEMUCaps *qemuCaps = priv->qemuCaps;
|
||||
@ -6973,7 +6936,7 @@ qemuDomainObjCheckMachineTaint(virQEMUDriver *driver,
|
||||
static void
|
||||
qemuDomainObjCheckCPUTaint(virQEMUDriver *driver,
|
||||
virDomainObj *obj,
|
||||
qemuDomainLogContext *logCtxt,
|
||||
qemuLogContext *logCtxt,
|
||||
bool incomingMigration)
|
||||
{
|
||||
qemuDomainObjPrivate *priv = obj->privateData;
|
||||
@ -7005,7 +6968,7 @@ qemuDomainObjCheckCPUTaint(virQEMUDriver *driver,
|
||||
|
||||
void qemuDomainObjCheckTaint(virQEMUDriver *driver,
|
||||
virDomainObj *obj,
|
||||
qemuDomainLogContext *logCtxt,
|
||||
qemuLogContext *logCtxt,
|
||||
bool incomingMigration)
|
||||
{
|
||||
size_t i;
|
||||
@ -7061,7 +7024,7 @@ void qemuDomainObjCheckTaint(virQEMUDriver *driver,
|
||||
void qemuDomainObjCheckDiskTaint(virQEMUDriver *driver,
|
||||
virDomainObj *obj,
|
||||
virDomainDiskDef *disk,
|
||||
qemuDomainLogContext *logCtxt)
|
||||
qemuLogContext *logCtxt)
|
||||
{
|
||||
if (disk->rawio == VIR_TRISTATE_BOOL_YES)
|
||||
qemuDomainObjTaint(driver, obj, VIR_DOMAIN_TAINT_HIGH_PRIVILEGES,
|
||||
@ -7078,7 +7041,7 @@ void qemuDomainObjCheckDiskTaint(virQEMUDriver *driver,
|
||||
void qemuDomainObjCheckHostdevTaint(virQEMUDriver *driver,
|
||||
virDomainObj *obj,
|
||||
virDomainHostdevDef *hostdev,
|
||||
qemuDomainLogContext *logCtxt)
|
||||
qemuLogContext *logCtxt)
|
||||
{
|
||||
if (!virHostdevIsSCSIDevice(hostdev))
|
||||
return;
|
||||
@ -7091,7 +7054,7 @@ void qemuDomainObjCheckHostdevTaint(virQEMUDriver *driver,
|
||||
void qemuDomainObjCheckNetTaint(virQEMUDriver *driver,
|
||||
virDomainObj *obj,
|
||||
virDomainNetDef *net,
|
||||
qemuDomainLogContext *logCtxt)
|
||||
qemuLogContext *logCtxt)
|
||||
{
|
||||
/* script is only useful for NET_TYPE_ETHERNET (qemu) and
|
||||
* NET_TYPE_BRIDGE (xen), but could be (incorrectly) specified for
|
||||
@ -7103,163 +7066,6 @@ void qemuDomainObjCheckNetTaint(virQEMUDriver *driver,
|
||||
}
|
||||
|
||||
|
||||
qemuDomainLogContext *qemuDomainLogContextNew(virQEMUDriver *driver,
|
||||
virDomainObj *vm,
|
||||
const char *basename)
|
||||
{
|
||||
g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
|
||||
qemuDomainLogContext *ctxt = QEMU_DOMAIN_LOG_CONTEXT(g_object_new(QEMU_TYPE_DOMAIN_LOG_CONTEXT, NULL));
|
||||
|
||||
VIR_DEBUG("Context new %p stdioLogD=%d", ctxt, cfg->stdioLogD);
|
||||
ctxt->writefd = -1;
|
||||
ctxt->readfd = -1;
|
||||
|
||||
ctxt->path = g_strdup_printf("%s/%s.log", cfg->logDir, basename);
|
||||
|
||||
if (cfg->stdioLogD) {
|
||||
ctxt->manager = virLogManagerNew(driver->privileged);
|
||||
if (!ctxt->manager)
|
||||
goto error;
|
||||
|
||||
ctxt->writefd = virLogManagerDomainOpenLogFile(ctxt->manager,
|
||||
"qemu",
|
||||
vm->def->uuid,
|
||||
vm->def->name,
|
||||
ctxt->path,
|
||||
0,
|
||||
&ctxt->inode,
|
||||
&ctxt->pos);
|
||||
if (ctxt->writefd < 0)
|
||||
goto error;
|
||||
} else {
|
||||
if ((ctxt->writefd = open(ctxt->path, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR)) < 0) {
|
||||
virReportSystemError(errno, _("failed to create logfile %1$s"),
|
||||
ctxt->path);
|
||||
goto error;
|
||||
}
|
||||
if (virSetCloseExec(ctxt->writefd) < 0) {
|
||||
virReportSystemError(errno, _("failed to set close-on-exec flag on %1$s"),
|
||||
ctxt->path);
|
||||
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 (!driver->privileged &&
|
||||
ftruncate(ctxt->writefd, 0) < 0) {
|
||||
virReportSystemError(errno, _("failed to truncate %1$s"),
|
||||
ctxt->path);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((ctxt->readfd = open(ctxt->path, O_RDONLY)) < 0) {
|
||||
virReportSystemError(errno, _("failed to open logfile %1$s"),
|
||||
ctxt->path);
|
||||
goto error;
|
||||
}
|
||||
if (virSetCloseExec(ctxt->readfd) < 0) {
|
||||
virReportSystemError(errno, _("failed to set close-on-exec flag on %1$s"),
|
||||
ctxt->path);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((ctxt->pos = lseek(ctxt->writefd, 0, SEEK_END)) < 0) {
|
||||
virReportSystemError(errno, _("failed to seek in log file %1$s"),
|
||||
ctxt->path);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return ctxt;
|
||||
|
||||
error:
|
||||
g_clear_object(&ctxt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int qemuDomainLogContextWrite(qemuDomainLogContext *ctxt,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
g_autofree char *message = NULL;
|
||||
int ret = -1;
|
||||
|
||||
va_start(argptr, fmt);
|
||||
|
||||
message = g_strdup_vprintf(fmt, argptr);
|
||||
if (!ctxt->manager &&
|
||||
lseek(ctxt->writefd, 0, SEEK_END) < 0) {
|
||||
virReportSystemError(errno, "%s",
|
||||
_("Unable to seek 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);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ssize_t qemuDomainLogContextRead(qemuDomainLogContext *ctxt,
|
||||
char **msg)
|
||||
{
|
||||
char *buf;
|
||||
size_t buflen;
|
||||
|
||||
VIR_DEBUG("Context read %p manager=%p inode=%llu pos=%llu",
|
||||
ctxt, ctxt->manager,
|
||||
(unsigned long long)ctxt->inode,
|
||||
(unsigned long long)ctxt->pos);
|
||||
|
||||
if (ctxt->manager) {
|
||||
buf = virLogManagerDomainReadLogFile(ctxt->manager,
|
||||
ctxt->path,
|
||||
ctxt->inode,
|
||||
ctxt->pos,
|
||||
1024 * 128,
|
||||
0);
|
||||
if (!buf)
|
||||
return -1;
|
||||
buflen = strlen(buf);
|
||||
} else {
|
||||
ssize_t got;
|
||||
|
||||
buflen = 1024 * 128;
|
||||
|
||||
/* Best effort jump to start of messages */
|
||||
ignore_value(lseek(ctxt->readfd, ctxt->pos, SEEK_SET));
|
||||
|
||||
buf = g_new0(char, buflen);
|
||||
|
||||
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';
|
||||
|
||||
buf = g_renew(char, buf, got + 1);
|
||||
buflen = got;
|
||||
}
|
||||
|
||||
*msg = buf;
|
||||
|
||||
return buflen;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* qemuDomainLogAppendMessage:
|
||||
*
|
||||
@ -7317,31 +7123,6 @@ qemuDomainLogAppendMessage(virQEMUDriver *driver,
|
||||
}
|
||||
|
||||
|
||||
int qemuDomainLogContextGetWriteFD(qemuDomainLogContext *ctxt)
|
||||
{
|
||||
return ctxt->writefd;
|
||||
}
|
||||
|
||||
|
||||
void qemuDomainLogContextMarkPosition(qemuDomainLogContext *ctxt)
|
||||
{
|
||||
if (ctxt->manager)
|
||||
virLogManagerDomainGetLogFilePosition(ctxt->manager,
|
||||
ctxt->path,
|
||||
0,
|
||||
&ctxt->inode,
|
||||
&ctxt->pos);
|
||||
else
|
||||
ctxt->pos = lseek(ctxt->writefd, 0, SEEK_END);
|
||||
}
|
||||
|
||||
|
||||
virLogManager *qemuDomainLogContextGetManager(qemuDomainLogContext *ctxt)
|
||||
{
|
||||
return ctxt->manager;
|
||||
}
|
||||
|
||||
|
||||
/* Locate an appropriate 'qemu-img' binary. */
|
||||
const char *
|
||||
qemuFindQemuImgBinary(virQEMUDriver *driver)
|
||||
|
@ -32,13 +32,13 @@
|
||||
#include "qemu_domainjob.h"
|
||||
#include "qemu_conf.h"
|
||||
#include "qemu_capabilities.h"
|
||||
#include "qemu_logcontext.h"
|
||||
#include "qemu_migration_params.h"
|
||||
#include "qemu_nbdkit.h"
|
||||
#include "qemu_slirp.h"
|
||||
#include "qemu_fd.h"
|
||||
#include "virchrdev.h"
|
||||
#include "virobject.h"
|
||||
#include "logging/log_manager.h"
|
||||
#include "virdomainmomentobjlist.h"
|
||||
#include "virenum.h"
|
||||
#include "vireventthread.h"
|
||||
@ -479,9 +479,6 @@ struct qemuProcessEvent {
|
||||
|
||||
void qemuProcessEventFree(struct qemuProcessEvent *event);
|
||||
|
||||
#define QEMU_TYPE_DOMAIN_LOG_CONTEXT qemu_domain_log_context_get_type()
|
||||
G_DECLARE_FINAL_TYPE(qemuDomainLogContext, qemu_domain_log_context, QEMU, DOMAIN_LOG_CONTEXT, GObject);
|
||||
|
||||
typedef struct _qemuDomainSaveCookie qemuDomainSaveCookie;
|
||||
struct _qemuDomainSaveCookie {
|
||||
virObject parent;
|
||||
@ -634,39 +631,27 @@ char *qemuDomainDefFormatLive(virQEMUDriver *driver,
|
||||
void qemuDomainObjTaint(virQEMUDriver *driver,
|
||||
virDomainObj *obj,
|
||||
virDomainTaintFlags taint,
|
||||
qemuDomainLogContext *logCtxt);
|
||||
qemuLogContext *logCtxt);
|
||||
|
||||
char **qemuDomainObjGetTainting(virQEMUDriver *driver,
|
||||
virDomainObj *obj);
|
||||
|
||||
void qemuDomainObjCheckTaint(virQEMUDriver *driver,
|
||||
virDomainObj *obj,
|
||||
qemuDomainLogContext *logCtxt,
|
||||
qemuLogContext *logCtxt,
|
||||
bool incomingMigration);
|
||||
void qemuDomainObjCheckDiskTaint(virQEMUDriver *driver,
|
||||
virDomainObj *obj,
|
||||
virDomainDiskDef *disk,
|
||||
qemuDomainLogContext *logCtxt);
|
||||
qemuLogContext *logCtxt);
|
||||
void qemuDomainObjCheckHostdevTaint(virQEMUDriver *driver,
|
||||
virDomainObj *obj,
|
||||
virDomainHostdevDef *disk,
|
||||
qemuDomainLogContext *logCtxt);
|
||||
qemuLogContext *logCtxt);
|
||||
void qemuDomainObjCheckNetTaint(virQEMUDriver *driver,
|
||||
virDomainObj *obj,
|
||||
virDomainNetDef *net,
|
||||
qemuDomainLogContext *logCtxt);
|
||||
|
||||
qemuDomainLogContext *qemuDomainLogContextNew(virQEMUDriver *driver,
|
||||
virDomainObj *vm,
|
||||
const char *basename);
|
||||
int qemuDomainLogContextWrite(qemuDomainLogContext *ctxt,
|
||||
const char *fmt, ...) G_GNUC_PRINTF(2, 3);
|
||||
ssize_t qemuDomainLogContextRead(qemuDomainLogContext *ctxt,
|
||||
char **msg);
|
||||
int qemuDomainLogContextGetWriteFD(qemuDomainLogContext *ctxt);
|
||||
void qemuDomainLogContextMarkPosition(qemuDomainLogContext *ctxt);
|
||||
|
||||
virLogManager *qemuDomainLogContextGetManager(qemuDomainLogContext *ctxt);
|
||||
qemuLogContext *logCtxt);
|
||||
|
||||
int qemuDomainLogAppendMessage(virQEMUDriver *driver,
|
||||
virDomainObj *vm,
|
||||
|
264
src/qemu/qemu_logcontext.c
Normal file
264
src/qemu/qemu_logcontext.c
Normal file
@ -0,0 +1,264 @@
|
||||
/*
|
||||
* qemu_logcontext.c: QEMU log context
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "qemu_logcontext.h"
|
||||
#include "viralloc.h"
|
||||
#include "virlog.h"
|
||||
#include "virutil.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_QEMU
|
||||
|
||||
VIR_LOG_INIT("qemu.qemu_logcontext");
|
||||
|
||||
|
||||
struct _qemuLogContext {
|
||||
GObject parent;
|
||||
|
||||
int writefd;
|
||||
int readfd; /* Only used if manager == NULL */
|
||||
off_t pos;
|
||||
ino_t inode; /* Only used if manager != NULL */
|
||||
char *path;
|
||||
virLogManager *manager;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(qemuLogContext, qemu_log_context, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
qemuLogContextFinalize(GObject *obj);
|
||||
|
||||
|
||||
static void
|
||||
qemu_log_context_init(qemuLogContext *logctxt G_GNUC_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qemu_log_context_class_init(qemuLogContextClass *klass)
|
||||
{
|
||||
GObjectClass *obj = G_OBJECT_CLASS(klass);
|
||||
|
||||
obj->finalize = qemuLogContextFinalize;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qemuLogContextFinalize(GObject *object)
|
||||
{
|
||||
qemuLogContext *ctxt = QEMU_LOG_CONTEXT(object);
|
||||
VIR_DEBUG("ctxt=%p", ctxt);
|
||||
|
||||
virLogManagerFree(ctxt->manager);
|
||||
VIR_FREE(ctxt->path);
|
||||
VIR_FORCE_CLOSE(ctxt->writefd);
|
||||
VIR_FORCE_CLOSE(ctxt->readfd);
|
||||
G_OBJECT_CLASS(qemu_log_context_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
|
||||
qemuLogContext *
|
||||
qemuLogContextNew(virQEMUDriver *driver,
|
||||
virDomainObj *vm,
|
||||
const char *basename)
|
||||
{
|
||||
g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
|
||||
qemuLogContext *ctxt = QEMU_LOG_CONTEXT(g_object_new(QEMU_TYPE_LOG_CONTEXT, NULL));
|
||||
|
||||
VIR_DEBUG("Context new %p stdioLogD=%d", ctxt, cfg->stdioLogD);
|
||||
ctxt->writefd = -1;
|
||||
ctxt->readfd = -1;
|
||||
|
||||
ctxt->path = g_strdup_printf("%s/%s.log", cfg->logDir, basename);
|
||||
|
||||
if (cfg->stdioLogD) {
|
||||
ctxt->manager = virLogManagerNew(driver->privileged);
|
||||
if (!ctxt->manager)
|
||||
goto error;
|
||||
|
||||
ctxt->writefd = virLogManagerDomainOpenLogFile(ctxt->manager,
|
||||
"qemu",
|
||||
vm->def->uuid,
|
||||
vm->def->name,
|
||||
ctxt->path,
|
||||
0,
|
||||
&ctxt->inode,
|
||||
&ctxt->pos);
|
||||
if (ctxt->writefd < 0)
|
||||
goto error;
|
||||
} else {
|
||||
if ((ctxt->writefd = open(ctxt->path, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR)) < 0) {
|
||||
virReportSystemError(errno, _("failed to create logfile %1$s"),
|
||||
ctxt->path);
|
||||
goto error;
|
||||
}
|
||||
if (virSetCloseExec(ctxt->writefd) < 0) {
|
||||
virReportSystemError(errno, _("failed to set close-on-exec flag on %1$s"),
|
||||
ctxt->path);
|
||||
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 (!driver->privileged &&
|
||||
ftruncate(ctxt->writefd, 0) < 0) {
|
||||
virReportSystemError(errno, _("failed to truncate %1$s"),
|
||||
ctxt->path);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((ctxt->readfd = open(ctxt->path, O_RDONLY)) < 0) {
|
||||
virReportSystemError(errno, _("failed to open logfile %1$s"),
|
||||
ctxt->path);
|
||||
goto error;
|
||||
}
|
||||
if (virSetCloseExec(ctxt->readfd) < 0) {
|
||||
virReportSystemError(errno, _("failed to set close-on-exec flag on %1$s"),
|
||||
ctxt->path);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((ctxt->pos = lseek(ctxt->writefd, 0, SEEK_END)) < 0) {
|
||||
virReportSystemError(errno, _("failed to seek in log file %1$s"),
|
||||
ctxt->path);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return ctxt;
|
||||
|
||||
error:
|
||||
g_clear_object(&ctxt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
qemuLogContextWrite(qemuLogContext *ctxt,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
g_autofree char *message = NULL;
|
||||
int ret = -1;
|
||||
|
||||
va_start(argptr, fmt);
|
||||
|
||||
message = g_strdup_vprintf(fmt, argptr);
|
||||
if (!ctxt->manager &&
|
||||
lseek(ctxt->writefd, 0, SEEK_END) < 0) {
|
||||
virReportSystemError(errno, "%s",
|
||||
_("Unable to seek 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);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
qemuLogContextRead(qemuLogContext *ctxt,
|
||||
char **msg)
|
||||
{
|
||||
char *buf;
|
||||
size_t buflen;
|
||||
|
||||
VIR_DEBUG("Context read %p manager=%p inode=%llu pos=%llu",
|
||||
ctxt, ctxt->manager,
|
||||
(unsigned long long)ctxt->inode,
|
||||
(unsigned long long)ctxt->pos);
|
||||
|
||||
if (ctxt->manager) {
|
||||
buf = virLogManagerDomainReadLogFile(ctxt->manager,
|
||||
ctxt->path,
|
||||
ctxt->inode,
|
||||
ctxt->pos,
|
||||
1024 * 128,
|
||||
0);
|
||||
if (!buf)
|
||||
return -1;
|
||||
buflen = strlen(buf);
|
||||
} else {
|
||||
ssize_t got;
|
||||
|
||||
buflen = 1024 * 128;
|
||||
|
||||
/* Best effort jump to start of messages */
|
||||
ignore_value(lseek(ctxt->readfd, ctxt->pos, SEEK_SET));
|
||||
|
||||
buf = g_new0(char, buflen);
|
||||
|
||||
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';
|
||||
|
||||
buf = g_renew(char, buf, got + 1);
|
||||
buflen = got;
|
||||
}
|
||||
|
||||
*msg = buf;
|
||||
|
||||
return buflen;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
qemuLogContextGetWriteFD(qemuLogContext *ctxt)
|
||||
{
|
||||
return ctxt->writefd;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
qemuLogContextMarkPosition(qemuLogContext *ctxt)
|
||||
{
|
||||
if (ctxt->manager)
|
||||
virLogManagerDomainGetLogFilePosition(ctxt->manager,
|
||||
ctxt->path,
|
||||
0,
|
||||
&ctxt->inode,
|
||||
&ctxt->pos);
|
||||
else
|
||||
ctxt->pos = lseek(ctxt->writefd, 0, SEEK_END);
|
||||
}
|
||||
|
||||
|
||||
virLogManager *
|
||||
qemuLogContextGetManager(qemuLogContext *ctxt)
|
||||
{
|
||||
return ctxt->manager;
|
||||
}
|
38
src/qemu/qemu_logcontext.h
Normal file
38
src/qemu/qemu_logcontext.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* qemu_logcontext.h: QEMU log context
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-object.h>
|
||||
#include "qemu_conf.h"
|
||||
#include "logging/log_manager.h"
|
||||
|
||||
#define QEMU_TYPE_LOG_CONTEXT qemu_log_context_get_type()
|
||||
G_DECLARE_FINAL_TYPE(qemuLogContext, qemu_log_context, QEMU, LOG_CONTEXT, GObject);
|
||||
|
||||
qemuLogContext *qemuLogContextNew(virQEMUDriver *driver,
|
||||
virDomainObj *vm,
|
||||
const char *basename);
|
||||
int qemuLogContextWrite(qemuLogContext *ctxt,
|
||||
const char *fmt, ...) G_GNUC_PRINTF(2, 3);
|
||||
ssize_t qemuLogContextRead(qemuLogContext *ctxt,
|
||||
char **msg);
|
||||
int qemuLogContextGetWriteFD(qemuLogContext *ctxt);
|
||||
void qemuLogContextMarkPosition(qemuLogContext *ctxt);
|
||||
|
||||
virLogManager *qemuLogContextGetManager(qemuLogContext *ctxt);
|
@ -1831,7 +1831,7 @@ qemuProcessMonitorReportLogError(qemuMonitor *mon,
|
||||
static void
|
||||
qemuProcessMonitorLogFree(void *opaque)
|
||||
{
|
||||
qemuDomainLogContext *logCtxt = opaque;
|
||||
qemuLogContext *logCtxt = opaque;
|
||||
g_clear_object(&logCtxt);
|
||||
}
|
||||
|
||||
@ -1857,7 +1857,7 @@ static int
|
||||
qemuConnectMonitor(virQEMUDriver *driver,
|
||||
virDomainObj *vm,
|
||||
int asyncJob,
|
||||
qemuDomainLogContext *logCtxt,
|
||||
qemuLogContext *logCtxt,
|
||||
bool reconnect)
|
||||
{
|
||||
qemuDomainObjPrivate *priv = vm->privateData;
|
||||
@ -1921,7 +1921,7 @@ qemuConnectMonitor(virQEMUDriver *driver,
|
||||
* Returns 0 on success or -1 on error
|
||||
*/
|
||||
static int
|
||||
qemuProcessReadLog(qemuDomainLogContext *logCtxt,
|
||||
qemuProcessReadLog(qemuLogContext *logCtxt,
|
||||
char **msg,
|
||||
size_t max)
|
||||
{
|
||||
@ -1931,7 +1931,7 @@ qemuProcessReadLog(qemuDomainLogContext *logCtxt,
|
||||
char *filter_next;
|
||||
size_t skip;
|
||||
|
||||
if ((got = qemuDomainLogContextRead(logCtxt, &buf)) < 0)
|
||||
if ((got = qemuLogContextRead(logCtxt, &buf)) < 0)
|
||||
return -1;
|
||||
|
||||
/* Filter out debug messages from intermediate libvirt process */
|
||||
@ -1974,7 +1974,7 @@ qemuProcessReadLog(qemuDomainLogContext *logCtxt,
|
||||
|
||||
|
||||
static int
|
||||
qemuProcessReportLogError(qemuDomainLogContext *logCtxt,
|
||||
qemuProcessReportLogError(qemuLogContext *logCtxt,
|
||||
const char *msgprefix)
|
||||
{
|
||||
g_autofree char *logmsg = NULL;
|
||||
@ -1999,7 +1999,7 @@ qemuProcessMonitorReportLogError(qemuMonitor *mon G_GNUC_UNUSED,
|
||||
const char *msg,
|
||||
void *opaque)
|
||||
{
|
||||
qemuDomainLogContext *logCtxt = opaque;
|
||||
qemuLogContext *logCtxt = opaque;
|
||||
qemuProcessReportLogError(logCtxt, msg);
|
||||
}
|
||||
|
||||
@ -2300,7 +2300,7 @@ static int
|
||||
qemuProcessWaitForMonitor(virQEMUDriver *driver,
|
||||
virDomainObj *vm,
|
||||
int asyncJob,
|
||||
qemuDomainLogContext *logCtxt)
|
||||
qemuLogContext *logCtxt)
|
||||
{
|
||||
int ret = -1;
|
||||
g_autoptr(GHashTable) info = NULL;
|
||||
@ -4663,7 +4663,7 @@ static void
|
||||
qemuLogOperation(virDomainObj *vm,
|
||||
const char *msg,
|
||||
virCommand *cmd,
|
||||
qemuDomainLogContext *logCtxt)
|
||||
qemuLogContext *logCtxt)
|
||||
{
|
||||
g_autofree char *timestamp = NULL;
|
||||
qemuDomainObjPrivate *priv = vm->privateData;
|
||||
@ -4677,20 +4677,20 @@ qemuLogOperation(virDomainObj *vm,
|
||||
if ((timestamp = virTimeStringNow()) == NULL)
|
||||
return;
|
||||
|
||||
if (qemuDomainLogContextWrite(logCtxt,
|
||||
"%s: %s %s, qemu version: %d.%d.%d%s, kernel: %s, hostname: %s\n",
|
||||
timestamp, msg, VIR_LOG_VERSION_STRING,
|
||||
(qemuVersion / 1000000) % 1000,
|
||||
(qemuVersion / 1000) % 1000,
|
||||
qemuVersion % 1000,
|
||||
NULLSTR_EMPTY(package),
|
||||
uts.release,
|
||||
NULLSTR_EMPTY(hostname)) < 0)
|
||||
if (qemuLogContextWrite(logCtxt,
|
||||
"%s: %s %s, qemu version: %d.%d.%d%s, kernel: %s, hostname: %s\n",
|
||||
timestamp, msg, VIR_LOG_VERSION_STRING,
|
||||
(qemuVersion / 1000000) % 1000,
|
||||
(qemuVersion / 1000) % 1000,
|
||||
qemuVersion % 1000,
|
||||
NULLSTR_EMPTY(package),
|
||||
uts.release,
|
||||
NULLSTR_EMPTY(hostname)) < 0)
|
||||
return;
|
||||
|
||||
if (cmd) {
|
||||
g_autofree char *args = virCommandToString(cmd, true);
|
||||
qemuDomainLogContextWrite(logCtxt, "%s\n", args);
|
||||
qemuLogContextWrite(logCtxt, "%s\n", args);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7591,7 +7591,7 @@ qemuProcessLaunch(virConnectPtr conn,
|
||||
int ret = -1;
|
||||
int rv;
|
||||
int logfile = -1;
|
||||
g_autoptr(qemuDomainLogContext) logCtxt = NULL;
|
||||
g_autoptr(qemuLogContext) logCtxt = NULL;
|
||||
qemuDomainObjPrivate *priv = vm->privateData;
|
||||
g_autoptr(virCommand) cmd = NULL;
|
||||
struct qemuProcessHookData hookData;
|
||||
@ -7641,11 +7641,11 @@ qemuProcessLaunch(virConnectPtr conn,
|
||||
hookData.cfg = cfg;
|
||||
|
||||
VIR_DEBUG("Creating domain log file");
|
||||
if (!(logCtxt = qemuDomainLogContextNew(driver, vm, vm->def->name))) {
|
||||
if (!(logCtxt = qemuLogContextNew(driver, vm, vm->def->name))) {
|
||||
virLastErrorPrefixMessage("%s", _("can't connect to virtlogd"));
|
||||
goto cleanup;
|
||||
}
|
||||
logfile = qemuDomainLogContextGetWriteFD(logCtxt);
|
||||
logfile = qemuLogContextGetWriteFD(logCtxt);
|
||||
|
||||
if (qemuProcessGenID(vm, flags) < 0)
|
||||
goto cleanup;
|
||||
@ -7681,7 +7681,7 @@ qemuProcessLaunch(virConnectPtr conn,
|
||||
|
||||
qemuDomainObjCheckTaint(driver, vm, logCtxt, incoming != NULL);
|
||||
|
||||
qemuDomainLogContextMarkPosition(logCtxt);
|
||||
qemuLogContextMarkPosition(logCtxt);
|
||||
|
||||
if (qemuProcessEnableDomainNamespaces(driver, vm) < 0)
|
||||
goto cleanup;
|
||||
|
Loading…
Reference in New Issue
Block a user