提交 19e5db4a 编写于 作者: D Daniel P. Berrange

logging: introduce log handling protocol

Define a new RPC protocol for the virtlogd daemon that provides
for handling of logs. The initial RPC method defined allows a
client to obtain a file handle to use for writing to a log
file for a guest domain. The file handle passed back will not
actually refer to the log file, but rather an anonymous pipe.
The virtlogd daemon will forward I/O between them, ensuring
file rotation happens when required.

Initially the log setup is hardcoded to cap log files at
128 KB, and keep 3 backups when rolling over, which gives
a max usage of 512 KB per guest.
Signed-off-by: NDaniel P. Berrange <berrange@redhat.com>
上级 323a329b
......@@ -80,6 +80,8 @@ src/locking/lock_manager.c
src/locking/sanlock_helper.c
src/logging/log_daemon.c
src/logging/log_daemon_config.c
src/logging/log_daemon_dispatch.c
src/logging/log_handler.c
src/lxc/lxc_cgroup.c
src/lxc/lxc_fuse.c
src/lxc/lxc_hostdev.c
......
......@@ -268,6 +268,8 @@ LOG_PROTOCOL_GENERATED = \
logging/log_protocol.c \
$(NULL)
DRIVER_SOURCES += $(LOG_PROTOCOL_GENERATED)
LOG_PROTOCOL = $(srcdir)/logging/log_protocol.x
EXTRA_DIST += $(LOG_PROTOCOL) \
$(LOG_PROTOCOL_GENERATED)
......@@ -289,6 +291,8 @@ LOG_DAEMON_SOURCES = \
logging/log_daemon_config.c \
logging/log_daemon_dispatch.c \
logging/log_daemon_dispatch.h \
logging/log_handler.c \
logging/log_handler.h \
$(NULL)
logging/log_daemon_dispatch_stubs.h: $(LOG_PROTOCOL) \
......
......@@ -60,6 +60,7 @@ struct _virLogDaemon {
virMutex lock;
virNetDaemonPtr dmn;
virNetServerPtr srv;
virLogHandlerPtr handler;
};
virLogDaemonPtr logDaemon = NULL;
......@@ -114,6 +115,7 @@ virLogDaemonFree(virLogDaemonPtr logd)
if (!logd)
return;
virObjectUnref(logd->handler);
virMutexDestroy(&logd->lock);
virObjectUnref(logd->srv);
virObjectUnref(logd->dmn);
......@@ -150,6 +152,9 @@ virLogDaemonNew(virLogDaemonConfigPtr config, bool privileged)
virNetDaemonAddServer(logd->dmn, logd->srv) < 0)
goto error;
if (!(logd->handler = virLogHandlerNew(privileged)))
goto error;
return logd;
error:
......@@ -158,6 +163,13 @@ virLogDaemonNew(virLogDaemonConfigPtr config, bool privileged)
}
virLogHandlerPtr
virLogDaemonGetHandler(virLogDaemonPtr daemon)
{
return daemon->handler;
}
static virLogDaemonPtr
virLogDaemonNewPostExecRestart(virJSONValuePtr object, bool privileged)
{
......@@ -191,6 +203,16 @@ virLogDaemonNewPostExecRestart(virJSONValuePtr object, bool privileged)
(void*)(intptr_t)(privileged ? 0x1 : 0x0))))
goto error;
if (!(child = virJSONValueObjectGet(object, "handler"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Malformed daemon data from JSON file"));
goto error;
}
if (!(logd->handler = virLogHandlerNewPostExecRestart(child,
privileged)))
goto error;
return logd;
error:
......@@ -774,6 +796,15 @@ virLogDaemonPreExecRestart(const char *state_file,
goto cleanup;
}
if (!(child = virLogHandlerPreExecRestart(logDaemon->handler)))
goto cleanup;
if (virJSONValueObjectAppend(object, "handler", child) < 0) {
virJSONValueFree(child);
goto cleanup;
}
if (!(state = virJSONValueToString(object, true)))
goto cleanup;
......
......@@ -24,6 +24,7 @@
# define __VIR_LOG_DAEMON_H__
# include "virthread.h"
# include "log_handler.h"
typedef struct _virLogDaemon virLogDaemon;
typedef virLogDaemon *virLogDaemonPtr;
......@@ -39,4 +40,6 @@ struct _virLogDaemonClient {
extern virLogDaemonPtr logDaemon;
virLogHandlerPtr virLogDaemonGetHandler(virLogDaemonPtr daemon);
#endif /* __VIR_LOG_DAEMON_H__ */
......@@ -29,9 +29,115 @@
#include "log_daemon.h"
#include "log_protocol.h"
#include "virerror.h"
#include "virthreadjob.h"
#include "virfile.h"
#define VIR_FROM_THIS VIR_FROM_RPC
VIR_LOG_INIT("logging.log_daemon_dispatch");
#include "log_daemon_dispatch_stubs.h"
static int
virLogManagerProtocolDispatchDomainOpenLogFile(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client ATTRIBUTE_UNUSED,
virNetMessagePtr msg,
virNetMessageErrorPtr rerr,
virLogManagerProtocolDomainOpenLogFileArgs *args,
virLogManagerProtocolDomainOpenLogFileRet *ret)
{
int fd = -1;
int rv = -1;
off_t offset;
ino_t inode;
if ((fd = virLogHandlerDomainOpenLogFile(virLogDaemonGetHandler(logDaemon),
args->driver,
(unsigned char *)args->dom.uuid,
args->dom.name,
&inode, &offset)) < 0)
goto cleanup;
ret->pos.inode = inode;
ret->pos.offset = offset;
if (virNetMessageAddFD(msg, fd) < 0)
goto cleanup;
rv = 1; /* '1' tells caller we added some FDs */
cleanup:
VIR_FORCE_CLOSE(fd);
if (rv < 0)
virNetMessageSaveError(rerr);
return rv;
}
static int
virLogManagerProtocolDispatchDomainGetLogFilePosition(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client ATTRIBUTE_UNUSED,
virNetMessagePtr msg ATTRIBUTE_UNUSED,
virNetMessageErrorPtr rerr,
virLogManagerProtocolDomainGetLogFilePositionArgs *args,
virLogManagerProtocolDomainGetLogFilePositionRet *ret)
{
int rv = -1;
off_t offset;
ino_t inode;
if (virLogHandlerDomainGetLogFilePosition(virLogDaemonGetHandler(logDaemon),
args->driver,
(unsigned char *)args->dom.uuid,
args->dom.name,
&inode, &offset) < 0)
goto cleanup;
ret->pos.inode = inode;
ret->pos.offset = offset;
rv = 0;
cleanup:
if (rv < 0)
virNetMessageSaveError(rerr);
return rv;
}
static int
virLogManagerProtocolDispatchDomainReadLogFile(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client ATTRIBUTE_UNUSED,
virNetMessagePtr msg ATTRIBUTE_UNUSED,
virNetMessageErrorPtr rerr,
virLogManagerProtocolDomainReadLogFileArgs *args,
virLogManagerProtocolDomainReadLogFileRet *ret)
{
int rv = -1;
char *data;
if (args->maxlen > VIR_LOG_MANAGER_PROTOCOL_STRING_MAX) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Requested data len %zu is larger than maximum %d"),
args->maxlen, VIR_LOG_MANAGER_PROTOCOL_STRING_MAX);
goto cleanup;
}
if ((data = virLogHandlerDomainReadLogFile(virLogDaemonGetHandler(logDaemon),
args->driver,
(unsigned char *)args->dom.uuid,
args->dom.name,
args->pos.inode,
args->pos.offset,
args->maxlen)) == NULL)
goto cleanup;
ret->data = data;
rv = 0;
cleanup:
if (rv < 0)
virNetMessageSaveError(rerr);
return rv;
}
/*
* log_handler.c: log management daemon handler
*
* Copyright (C) 2015 Red Hat, Inc.
*
* 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/>.
*
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
#include <config.h>
#include "log_handler.h"
#include "virerror.h"
#include "virobject.h"
#include "virfile.h"
#include "viralloc.h"
#include "virstring.h"
#include "virlog.h"
#include "virrotatingfile.h"
#include <unistd.h>
#include <fcntl.h>
#include "configmake.h"
VIR_LOG_INIT("logging.log_handler");
#define VIR_FROM_THIS VIR_FROM_LOGGING
#define DEFAULT_FILE_SIZE (128 * 1024)
#define DEFAULT_MAX_BACKUP 3
#define DEFAULT_MODE 0600
typedef struct _virLogHandlerLogFile virLogHandlerLogFile;
typedef virLogHandlerLogFile *virLogHandlerLogFilePtr;
struct _virLogHandlerLogFile {
virRotatingFileWriterPtr file;
int watch;
int pipefd; /* Read from QEMU via this */
};
struct _virLogHandler {
virObjectLockable parent;
bool privileged;
virLogHandlerLogFilePtr *files;
size_t nfiles;
};
static virClassPtr virLogHandlerClass;
static void virLogHandlerDispose(void *obj);
static int
virLogHandlerOnceInit(void)
{
if (!(virLogHandlerClass = virClassNew(virClassForObjectLockable(),
"virLogHandler",
sizeof(virLogHandler),
virLogHandlerDispose)))
return -1;
return 0;
}
VIR_ONCE_GLOBAL_INIT(virLogHandler)
static void
virLogHandlerLogFileFree(virLogHandlerLogFilePtr file)
{
if (!file)
return;
VIR_FORCE_CLOSE(file->pipefd);
virRotatingFileWriterFree(file->file);
if (file->watch != -1)
virEventRemoveHandle(file->watch);
VIR_FREE(file);
}
static void
virLogHandlerLogFileClose(virLogHandlerPtr handler,
virLogHandlerLogFilePtr file)
{
size_t i;
for (i = 0; i < handler->nfiles; i++) {
if (handler->files[i] == file) {
VIR_DELETE_ELEMENT(handler->files, i, handler->nfiles);
virLogHandlerLogFileFree(file);
break;
}
}
}
static virLogHandlerLogFilePtr
virLogHandlerGetLogFileFromWatch(virLogHandlerPtr handler,
int watch)
{
size_t i;
for (i = 0; i < handler->nfiles; i++) {
if (handler->files[i]->watch == watch)
return handler->files[i];
}
return NULL;
}
static void
virLogHandlerDomainLogFileEvent(int watch,
int fd,
int events,
void *opaque)
{
virLogHandlerPtr handler = opaque;
virLogHandlerLogFilePtr logfile;
char buf[1024];
ssize_t len;
virObjectLock(handler);
logfile = virLogHandlerGetLogFileFromWatch(handler, watch);
if (!logfile || logfile->pipefd != fd) {
virEventRemoveHandle(watch);
virObjectUnlock(handler);
return;
}
reread:
len = read(fd, buf, sizeof(buf));
if (len < 0) {
if (errno == EINTR)
goto reread;
virReportSystemError(errno, "%s",
_("Unable to read from log pipe"));
goto error;
}
if (virRotatingFileWriterAppend(logfile->file, buf, len) != len)
goto error;
if (events & VIR_EVENT_HANDLE_HANGUP)
goto error;
virObjectUnlock(handler);
return;
error:
virLogHandlerLogFileClose(handler, logfile);
virObjectUnlock(handler);
}
virLogHandlerPtr
virLogHandlerNew(bool privileged)
{
virLogHandlerPtr handler;
if (virLogHandlerInitialize() < 0)
goto error;
if (!(handler = virObjectLockableNew(virLogHandlerClass)))
goto error;
handler->privileged = privileged;
return handler;
error:
return NULL;
}
static virLogHandlerLogFilePtr
virLogHandlerLogFilePostExecRestart(virJSONValuePtr object)
{
virLogHandlerLogFilePtr file;
const char *path;
if (VIR_ALLOC(file) < 0)
return NULL;
if ((path = virJSONValueObjectGetString(object, "path")) == NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Missing file path in JSON document"));
goto error;
}
if ((file->file = virRotatingFileWriterNew(path,
DEFAULT_FILE_SIZE,
DEFAULT_MAX_BACKUP,
false,
DEFAULT_MODE)) == NULL)
goto error;
if (virJSONValueObjectGetNumberInt(object, "pipefd", &file->pipefd) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Missing file pipefd in JSON document"));
goto error;
}
if (virSetInherit(file->pipefd, false) < 0) {
virReportSystemError(errno, "%s",
_("Cannot enable close-on-exec flag"));
goto error;
}
return file;
error:
virLogHandlerLogFileFree(file);
return NULL;
}
virLogHandlerPtr
virLogHandlerNewPostExecRestart(virJSONValuePtr object,
bool privileged)
{
virLogHandlerPtr handler;
virJSONValuePtr files;
ssize_t n;
size_t i;
if (!(handler = virLogHandlerNew(privileged)))
return NULL;
if (!(files = virJSONValueObjectGet(object, "files"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Missing files data from JSON file"));
goto error;
}
if ((n = virJSONValueArraySize(files)) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Malformed files data from JSON file"));
goto error;
}
for (i = 0; i < n; i++) {
virLogHandlerLogFilePtr file;
virJSONValuePtr child = virJSONValueArrayGet(files, i);
if (!(file = virLogHandlerLogFilePostExecRestart(child)))
goto error;
if (VIR_APPEND_ELEMENT_COPY(handler->files, handler->nfiles, file) < 0)
goto error;
if ((file->watch = virEventAddHandle(file->pipefd,
VIR_EVENT_HANDLE_READABLE,
virLogHandlerDomainLogFileEvent,
handler,
NULL)) < 0) {
VIR_DELETE_ELEMENT(handler->files, handler->nfiles - 1, handler->nfiles);
goto error;
}
}
return handler;
error:
virObjectUnref(handler);
return NULL;
}
static void
virLogHandlerDispose(void *obj)
{
virLogHandlerPtr handler = obj;
size_t i;
for (i = 0; i < handler->nfiles; i++)
virLogHandlerLogFileFree(handler->files[i]);
VIR_FREE(handler->files);
}
static char *
virLogHandlerGetLogFilePathForDomain(virLogHandlerPtr handler,
const char *driver,
const unsigned char *domuuid ATTRIBUTE_UNUSED,
const char *domname)
{
char *path;
if (handler->privileged) {
if (virAsprintf(&path,
LOCALSTATEDIR "/log/libvirt/%s/%s.log",
driver, domname) < 0)
return NULL;
} else {
char *cachedir;
cachedir = virGetUserCacheDirectory();
if (!cachedir)
return NULL;
if (virAsprintf(&path,
"%s/%s/log/%s.log", cachedir, driver, domname) < 0) {
VIR_FREE(cachedir);
return NULL;
}
}
return path;
}
int
virLogHandlerDomainOpenLogFile(virLogHandlerPtr handler,
const char *driver,
const unsigned char *domuuid ATTRIBUTE_UNUSED,
const char *domname,
ino_t *inode,
off_t *offset)
{
size_t i;
virLogHandlerLogFilePtr file = NULL;
int pipefd[2] = { -1, -1 };
char *path;
virObjectLock(handler);
if (!(path = virLogHandlerGetLogFilePathForDomain(handler,
driver,
domuuid,
domname)))
goto error;
for (i = 0; i < handler->nfiles; i++) {
if (STREQ(virRotatingFileWriterGetPath(handler->files[i]->file),
path)) {
virReportSystemError(EBUSY,
_("Cannot open log file: '%s'"),
path);
goto error;
}
}
if (pipe(pipefd) < 0) {
virReportSystemError(errno, "%s",
_("Cannot open fifo pipe"));
goto error;
}
if (VIR_ALLOC(file) < 0)
goto error;
file->watch = -1;
file->pipefd = pipefd[0];
pipefd[0] = -1;
if ((file->file = virRotatingFileWriterNew(path,
DEFAULT_FILE_SIZE,
DEFAULT_MAX_BACKUP,
false,
DEFAULT_MODE)) == NULL)
goto error;
if (VIR_APPEND_ELEMENT_COPY(handler->files, handler->nfiles, file) < 0)
goto error;
if ((file->watch = virEventAddHandle(file->pipefd,
VIR_EVENT_HANDLE_READABLE,
virLogHandlerDomainLogFileEvent,
handler,
NULL)) < 0) {
VIR_DELETE_ELEMENT(handler->files, handler->nfiles - 1, handler->nfiles);
goto error;
}
VIR_FREE(path);
*inode = virRotatingFileWriterGetINode(file->file);
*offset = virRotatingFileWriterGetOffset(file->file);
virObjectUnlock(handler);
return pipefd[1];
error:
VIR_FREE(path);
VIR_FORCE_CLOSE(pipefd[0]);
VIR_FORCE_CLOSE(pipefd[1]);
virLogHandlerLogFileFree(file);
virObjectUnlock(handler);
return -1;
}
int
virLogHandlerDomainGetLogFilePosition(virLogHandlerPtr handler,
const char *driver,
const unsigned char *domuuid,
const char *domname,
ino_t *inode,
off_t *offset)
{
char *path;
virLogHandlerLogFilePtr file = NULL;
int ret = -1;
size_t i;
virObjectLock(handler);
if (!(path = virLogHandlerGetLogFilePathForDomain(handler,
driver,
domuuid,
domname)))
goto cleanup;
for (i = 0; i < handler->nfiles; i++) {
if (STREQ(virRotatingFileWriterGetPath(handler->files[i]->file),
path)) {
file = handler->files[i];
break;
}
}
if (!file) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("No open log file for domain %s"),
domname);
goto cleanup;
}
*inode = virRotatingFileWriterGetINode(file->file);
*offset = virRotatingFileWriterGetOffset(file->file);
ret = 0;
cleanup:
VIR_FREE(path);
virObjectUnlock(handler);
return ret;
}
char *
virLogHandlerDomainReadLogFile(virLogHandlerPtr handler,
const char *driver,
const unsigned char *domuuid,
const char *domname,
ino_t inode,
off_t offset,
size_t maxlen)
{
char *path;
virRotatingFileReaderPtr file = NULL;
char *data = NULL;
ssize_t got;
virObjectLock(handler);
if (!(path = virLogHandlerGetLogFilePathForDomain(handler,
driver,
domuuid,
domname)))
goto error;
if (!(file = virRotatingFileReaderNew(path, DEFAULT_MAX_BACKUP)))
goto error;
if (virRotatingFileReaderSeek(file, inode, offset) < 0)
goto error;
if (VIR_ALLOC_N(data, maxlen + 1) < 0)
goto error;
got = virRotatingFileReaderConsume(file, data, maxlen);
if (got < 0)
goto error;
data[got] = '\0';
virRotatingFileReaderFree(file);
virObjectUnlock(handler);
VIR_FREE(path);
return data;
error:
VIR_FREE(path);
VIR_FREE(data);
virRotatingFileReaderFree(file);
virObjectUnlock(handler);
return NULL;
}
virJSONValuePtr
virLogHandlerPreExecRestart(virLogHandlerPtr handler)
{
virJSONValuePtr ret = virJSONValueNewObject();
virJSONValuePtr files;
size_t i;
if (!ret)
return NULL;
if (!(files = virJSONValueNewArray()))
goto error;
if (virJSONValueObjectAppend(ret, "files", files) < 0) {
virJSONValueFree(files);
goto error;
}
for (i = 0; i < handler->nfiles; i++) {
virJSONValuePtr file = virJSONValueNewObject();
if (!file)
goto error;
if (virJSONValueArrayAppend(files, file) < 0) {
virJSONValueFree(file);
goto error;
}
if (virJSONValueObjectAppendNumberInt(file, "pipefd",
handler->files[i]->pipefd) < 0)
goto error;
if (virJSONValueObjectAppendString(file, "path",
virRotatingFileWriterGetPath(handler->files[i]->file)) < 0)
goto error;
if (virSetInherit(handler->files[i]->pipefd, true) < 0) {
virReportSystemError(errno, "%s",
_("Cannot disable close-on-exec flag"));
goto error;
}
}
return ret;
error:
virJSONValueFree(ret);
return NULL;
}
/*
* log_handler.h: log management daemon handler
*
* Copyright (C) 2015 Red Hat, Inc.
*
* 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/>.
*
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
#ifndef __VIR_LOG_HANDLER_H__
# define __VIR_LOG_HANDLER_H__
# include "internal.h"
# include "virjson.h"
typedef struct _virLogHandler virLogHandler;
typedef virLogHandler *virLogHandlerPtr;
virLogHandlerPtr virLogHandlerNew(bool privileged);
virLogHandlerPtr virLogHandlerNewPostExecRestart(virJSONValuePtr child,
bool privileged);
void virLogHandlerFree(virLogHandlerPtr handler);
int virLogHandlerDomainOpenLogFile(virLogHandlerPtr handler,
const char *driver,
const unsigned char *domuuid,
const char *domname,
ino_t *inode,
off_t *offset);
int virLogHandlerDomainGetLogFilePosition(virLogHandlerPtr handler,
const char *driver,
const unsigned char *domuuid,
const char *domname,
ino_t *inode,
off_t *offset);
char *virLogHandlerDomainReadLogFile(virLogHandlerPtr handler,
const char *driver,
const unsigned char *domuuid,
const char *domname,
ino_t inode,
off_t offset,
size_t maxlen);
virJSONValuePtr virLogHandlerPreExecRestart(virLogHandlerPtr handler);
#endif /** __VIR_LOG_HANDLER_H__ */
......@@ -17,6 +17,99 @@ typedef string virLogManagerProtocolNonNullString<VIR_LOG_MANAGER_PROTOCOL_STRIN
/* A long string, which may be NULL. */
typedef virLogManagerProtocolNonNullString *virLogManagerProtocolString;
struct virLogManagerProtocolDomain {
virLogManagerProtocolUUID uuid;
virLogManagerProtocolNonNullString name;
};
typedef struct virLogManagerProtocolDomain virLogManagerProtocolDomain;
struct virLogManagerProtocolLogFilePosition {
unsigned hyper inode;
unsigned hyper offset;
};
typedef struct virLogManagerProtocolLogFilePosition virLogManagerProtocolLogFilePosition;
/* Obtain a file handle suitable for writing to a
* log file for a domain
*/
struct virLogManagerProtocolDomainOpenLogFileArgs {
virLogManagerProtocolNonNullString driver;
virLogManagerProtocolDomain dom;
unsigned int flags;
};
struct virLogManagerProtocolDomainOpenLogFileRet {
virLogManagerProtocolLogFilePosition pos;
};
struct virLogManagerProtocolDomainGetLogFilePositionArgs {
virLogManagerProtocolNonNullString driver;
virLogManagerProtocolDomain dom;
unsigned int flags;
};
struct virLogManagerProtocolDomainGetLogFilePositionRet {
virLogManagerProtocolLogFilePosition pos;
};
struct virLogManagerProtocolDomainReadLogFileArgs {
virLogManagerProtocolNonNullString driver;
virLogManagerProtocolDomain dom;
virLogManagerProtocolLogFilePosition pos;
unsigned hyper maxlen;
unsigned int flags;
};
struct virLogManagerProtocolDomainReadLogFileRet {
virLogManagerProtocolNonNullString data;
};
/* Define the program number, protocol version and procedure numbers here. */
const VIR_LOG_MANAGER_PROTOCOL_PROGRAM = 0x87539319;
const VIR_LOG_MANAGER_PROTOCOL_PROGRAM_VERSION = 1;
enum virLogManagerProtocolProcedure {
/* Each function must be preceded by a comment providing one or
* more annotations:
*
* - @generate: none|client|server|both
*
* Whether to generate the dispatch stubs for the server
* and/or client code.
*
* - @readstream: paramnumber
* - @writestream: paramnumber
*
* The @readstream or @writestream annotations let daemon and src/remote
* create a stream. The direction is defined from the src/remote point
* of view. A readstream transfers data from daemon to src/remote. The
* <paramnumber> specifies at which offset the stream parameter is inserted
* in the function parameter list.
*
* - @priority: low|high
*
* Each API that might eventually access hypervisor's monitor (and thus
* block) MUST fall into low priority. However, there are some exceptions
* to this rule, e.g. domainDestroy. Other APIs MAY be marked as high
* priority. If in doubt, it's safe to choose low. Low is taken as default,
* and thus can be left out.
*/
/**
* @generate: none
* @acl: none
*/
VIR_LOG_MANAGER_PROTOCOL_PROC_DOMAIN_OPEN_LOG_FILE = 1,
/**
* @generate: none
* @acl: none
*/
VIR_LOG_MANAGER_PROTOCOL_PROC_DOMAIN_GET_LOG_FILE_POSITION = 2,
/**
* @generate: none
* @acl: none
*/
VIR_LOG_MANAGER_PROTOCOL_PROC_DOMAIN_READ_LOG_FILE = 3
};
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册