mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 05:35:25 +00:00
lib: Introduce 'virDomainQemuMonitorCommandWithFiles'
This API has the same semantics as 'virDomainQemuMonitorCommand' but accepts file descriptors which are then forwarded to qemu. Signed-off-by: Peter Krempa <pkrempa@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com>
This commit is contained in:
parent
7cfbfe66fc
commit
f87fa77ca9
@ -37,6 +37,14 @@ typedef enum {
|
||||
|
||||
int virDomainQemuMonitorCommand(virDomainPtr domain, const char *cmd,
|
||||
char **result, unsigned int flags);
|
||||
int virDomainQemuMonitorCommandWithFiles(virDomainPtr domain,
|
||||
const char *cmd,
|
||||
unsigned int ninfiles,
|
||||
int *infiles,
|
||||
unsigned int *noutfiles,
|
||||
int **outfiles,
|
||||
char **result,
|
||||
unsigned int flags);
|
||||
|
||||
virDomainPtr virDomainQemuAttach(virConnectPtr domain,
|
||||
unsigned int pid_value,
|
||||
|
@ -874,6 +874,15 @@ typedef int
|
||||
const char *cmd,
|
||||
char **result,
|
||||
unsigned int flags);
|
||||
typedef int
|
||||
(*virDrvDomainQemuMonitorCommandWithFiles)(virDomainPtr domain,
|
||||
const char *cmd,
|
||||
unsigned int ninfiles,
|
||||
int *infiles,
|
||||
unsigned int *noutfiles,
|
||||
int **outfiles,
|
||||
char **result,
|
||||
unsigned int flags);
|
||||
|
||||
typedef char *
|
||||
(*virDrvDomainQemuAgentCommand)(virDomainPtr domain,
|
||||
@ -1597,6 +1606,7 @@ struct _virHypervisorDriver {
|
||||
virDrvDomainRevertToSnapshot domainRevertToSnapshot;
|
||||
virDrvDomainSnapshotDelete domainSnapshotDelete;
|
||||
virDrvDomainQemuMonitorCommand domainQemuMonitorCommand;
|
||||
virDrvDomainQemuMonitorCommandWithFiles domainQemuMonitorCommandWithFiles;
|
||||
virDrvDomainQemuAttach domainQemuAttach;
|
||||
virDrvDomainQemuAgentCommand domainQemuAgentCommand;
|
||||
virDrvConnectDomainQemuMonitorEventRegister connectDomainQemuMonitorEventRegister;
|
||||
|
@ -96,6 +96,95 @@ virDomainQemuMonitorCommand(virDomainPtr domain, const char *cmd,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* virDomainQemuMonitorCommandWithFiles:
|
||||
* @domain: a domain object
|
||||
* @cmd: the qemu monitor command string
|
||||
* @ninfiles: number of filedescriptors passed in @infiles
|
||||
* @infiles: filedescriptors to be passed to qemu with the command
|
||||
* @noutfiles: if non-NULL filled with number of returned file descriptors
|
||||
* @outfiles: if non-NULL filled with an array of returned file descriptors
|
||||
* @result: a string returned by @cmd
|
||||
* @flags: bitwise-or of supported virDomainQemuMonitorCommandFlags
|
||||
*
|
||||
* This API is QEMU specific, so it will only work with hypervisor
|
||||
* connections to the QEMU driver with local connections using the unix socket.
|
||||
*
|
||||
* Send an arbitrary monitor command @cmd with file descriptors @infiles to
|
||||
* @domain through the qemu monitor and optionally return file descriptors via
|
||||
* @outfiles. There are several requirements to safely and successfully use
|
||||
* this API:
|
||||
*
|
||||
* - A @cmd that queries state without making any modifications is safe
|
||||
* - A @cmd that alters state that is also tracked by libvirt is unsafe,
|
||||
* and may cause libvirtd to crash
|
||||
* - A @cmd that alters state not tracked by the current version of
|
||||
* libvirt is possible as a means to test new qemu features before
|
||||
* they have support in libvirt, but no guarantees are made to safety
|
||||
*
|
||||
* If VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP is set, the command is
|
||||
* considered to be a human monitor command and libvirt will automatically
|
||||
* convert it into QMP if needed. In that case the @result will also
|
||||
* be converted back from QMP.
|
||||
*
|
||||
* If successful, @result will be filled with the string output of the
|
||||
* @cmd, and the caller must free this string.
|
||||
*
|
||||
* Returns 0 in case of success, -1 in case of failure
|
||||
*/
|
||||
int
|
||||
virDomainQemuMonitorCommandWithFiles(virDomainPtr domain,
|
||||
const char *cmd,
|
||||
unsigned int ninfiles,
|
||||
int *infiles,
|
||||
unsigned int *noutfiles,
|
||||
int **outfiles,
|
||||
char **result,
|
||||
unsigned int flags)
|
||||
{
|
||||
virConnectPtr conn;
|
||||
|
||||
VIR_DOMAIN_DEBUG(domain,
|
||||
"cmd=%s, ninfiles=%u, infiles=%p, noutfiles=%p, outfiles=%p, result=%p, flags=0x%x",
|
||||
cmd, ninfiles, infiles, noutfiles, outfiles, result, flags);
|
||||
|
||||
virResetLastError();
|
||||
|
||||
virCheckDomainReturn(domain, -1);
|
||||
conn = domain->conn;
|
||||
|
||||
if (ninfiles > 0 || outfiles) {
|
||||
int rc;
|
||||
if ((rc = VIR_DRV_SUPPORTS_FEATURE(conn->driver, conn,
|
||||
VIR_DRV_FEATURE_FD_PASSING) <= 0)) {
|
||||
if (rc == 0)
|
||||
virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
|
||||
_("fd passing is not supported by this connection"));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
virCheckNonNullArgGoto(result, error);
|
||||
virCheckReadOnlyGoto(conn->flags, error);
|
||||
|
||||
if (conn->driver->domainQemuMonitorCommandWithFiles) {
|
||||
int ret;
|
||||
ret = conn->driver->domainQemuMonitorCommandWithFiles(domain, cmd,
|
||||
ninfiles, infiles,
|
||||
noutfiles, outfiles,
|
||||
result, flags);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
return ret;
|
||||
}
|
||||
|
||||
virReportUnsupportedError();
|
||||
|
||||
error:
|
||||
virDispatchError(conn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* virDomainQemuAttach:
|
||||
* @conn: pointer to a hypervisor connection
|
||||
|
@ -30,3 +30,8 @@ LIBVIRT_QEMU_1.2.3 {
|
||||
virConnectDomainQemuMonitorEventDeregister;
|
||||
virConnectDomainQemuMonitorEventRegister;
|
||||
} LIBVIRT_QEMU_0.10.0;
|
||||
|
||||
LIBVIRT_QEMU_8.2.0 {
|
||||
global:
|
||||
virDomainQemuMonitorCommandWithFiles;
|
||||
} LIBVIRT_QEMU_1.2.3;
|
||||
|
@ -47,6 +47,14 @@ struct qemu_domain_monitor_event_msg {
|
||||
u_int micros;
|
||||
remote_string details;
|
||||
};
|
||||
struct qemu_domain_monitor_command_with_files_args {
|
||||
remote_nonnull_domain dom;
|
||||
remote_nonnull_string cmd;
|
||||
u_int flags;
|
||||
};
|
||||
struct qemu_domain_monitor_command_with_files_ret {
|
||||
remote_nonnull_string result;
|
||||
};
|
||||
enum qemu_procedure {
|
||||
QEMU_PROC_DOMAIN_MONITOR_COMMAND = 1,
|
||||
QEMU_PROC_DOMAIN_ATTACH = 2,
|
||||
@ -54,4 +62,5 @@ enum qemu_procedure {
|
||||
QEMU_PROC_CONNECT_DOMAIN_MONITOR_EVENT_REGISTER = 4,
|
||||
QEMU_PROC_CONNECT_DOMAIN_MONITOR_EVENT_DEREGISTER = 5,
|
||||
QEMU_PROC_DOMAIN_MONITOR_EVENT = 6,
|
||||
QEMU_PROC_DOMAIN_MONITOR_COMMAND_WITH_FILES = 7,
|
||||
};
|
||||
|
@ -79,6 +79,17 @@ struct qemu_domain_monitor_event_msg {
|
||||
remote_string details;
|
||||
};
|
||||
|
||||
struct qemu_domain_monitor_command_with_files_args {
|
||||
remote_nonnull_domain dom;
|
||||
remote_nonnull_string cmd;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
struct qemu_domain_monitor_command_with_files_ret {
|
||||
remote_nonnull_string result;
|
||||
};
|
||||
|
||||
|
||||
/* Define the program number, protocol version and procedure numbers here. */
|
||||
const QEMU_PROGRAM = 0x20008087;
|
||||
const QEMU_PROTOCOL_VERSION = 1;
|
||||
@ -151,5 +162,12 @@ enum qemu_procedure {
|
||||
* @generate: both
|
||||
* @acl: none
|
||||
*/
|
||||
QEMU_PROC_DOMAIN_MONITOR_EVENT = 6
|
||||
QEMU_PROC_DOMAIN_MONITOR_EVENT = 6,
|
||||
|
||||
/**
|
||||
* @generate: none
|
||||
* @priority: low
|
||||
* @acl: domain:write
|
||||
*/
|
||||
QEMU_PROC_DOMAIN_MONITOR_COMMAND_WITH_FILES = 7
|
||||
};
|
||||
|
@ -4684,6 +4684,68 @@ qemuDispatchDomainMonitorCommand(virNetServer *server G_GNUC_UNUSED,
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qemuDispatchDomainMonitorCommandWithFiles(virNetServer *server G_GNUC_UNUSED,
|
||||
virNetServerClient *client,
|
||||
virNetMessage *msg,
|
||||
struct virNetMessageError *rerr,
|
||||
qemu_domain_monitor_command_with_files_args *args,
|
||||
qemu_domain_monitor_command_with_files_ret *ret)
|
||||
{
|
||||
virDomainPtr dom = NULL;
|
||||
int *infiles = NULL;
|
||||
unsigned int ninfiles = 0;
|
||||
int *outfiles = NULL;
|
||||
unsigned int noutfiles = 0;
|
||||
int rv = -1;
|
||||
virConnectPtr conn = remoteGetHypervisorConn(client);
|
||||
size_t i;
|
||||
|
||||
if (!conn)
|
||||
goto cleanup;
|
||||
|
||||
if (!(dom = get_nonnull_domain(conn, args->dom)))
|
||||
goto cleanup;
|
||||
|
||||
infiles = g_new0(int, msg->nfds);
|
||||
for (i = 0; i < msg->nfds; i++) {
|
||||
if ((infiles[i] = virNetMessageDupFD(msg, i)) < 0)
|
||||
goto cleanup;
|
||||
ninfiles++;
|
||||
}
|
||||
|
||||
/* This API can both receive FDs from the client and send FDs back, but 'msg'
|
||||
* is being reused. Thus we must clear the list of FDs in it to prevent
|
||||
* us sending back the FDs client sent us. */
|
||||
virNetMessageClearFDs(msg);
|
||||
|
||||
if (virDomainQemuMonitorCommandWithFiles(dom, args->cmd, ninfiles, infiles,
|
||||
&noutfiles, &outfiles,
|
||||
&ret->result, args->flags) < 0)
|
||||
goto cleanup;
|
||||
|
||||
for (i = 0; i < noutfiles; i++) {
|
||||
if (virNetMessageAddFD(msg, outfiles[i]) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* return 1 here to let virNetServerProgramDispatchCall know we are passing fds */
|
||||
if (noutfiles > 0)
|
||||
rv = 1;
|
||||
else
|
||||
rv = 0;
|
||||
|
||||
cleanup:
|
||||
for (i = 0; i < noutfiles; i++)
|
||||
VIR_FORCE_CLOSE(outfiles[i]);
|
||||
|
||||
if (rv < 0)
|
||||
virNetMessageSaveError(rerr);
|
||||
virObjectUnref(dom);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
remoteDispatchDomainMigrateBegin3(virNetServer *server G_GNUC_UNUSED,
|
||||
virNetServerClient *client,
|
||||
|
@ -5931,6 +5931,62 @@ remoteDomainQemuMonitorCommand(virDomainPtr domain, const char *cmd,
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
remoteDomainQemuMonitorCommandWithFiles(virDomainPtr domain,
|
||||
const char *cmd,
|
||||
unsigned int ninfiles,
|
||||
int *infiles,
|
||||
unsigned int *noutfiles,
|
||||
int **outfiles,
|
||||
char **result,
|
||||
unsigned int flags)
|
||||
{
|
||||
int rv = -1;
|
||||
qemu_domain_monitor_command_with_files_args args;
|
||||
qemu_domain_monitor_command_with_files_ret ret;
|
||||
struct private_data *priv = domain->conn->privateData;
|
||||
size_t rpc_noutfiles = 0;
|
||||
g_autofree int *rpc_outfiles = NULL;
|
||||
size_t i;
|
||||
|
||||
remoteDriverLock(priv);
|
||||
|
||||
make_nonnull_domain(&args.dom, domain);
|
||||
args.cmd = (char *)cmd;
|
||||
args.flags = flags;
|
||||
|
||||
memset(&ret, 0, sizeof(ret));
|
||||
if (callFull(domain->conn, priv, REMOTE_CALL_QEMU,
|
||||
infiles, ninfiles, &rpc_outfiles, &rpc_noutfiles,
|
||||
QEMU_PROC_DOMAIN_MONITOR_COMMAND_WITH_FILES,
|
||||
(xdrproc_t) xdr_qemu_domain_monitor_command_with_files_args, (char *) &args,
|
||||
(xdrproc_t) xdr_qemu_domain_monitor_command_with_files_ret, (char *) &ret) == -1)
|
||||
goto done;
|
||||
|
||||
if (outfiles)
|
||||
*outfiles = g_steal_pointer(&rpc_outfiles);
|
||||
|
||||
if (noutfiles)
|
||||
*noutfiles = rpc_noutfiles;
|
||||
|
||||
*result = g_strdup(ret.result);
|
||||
|
||||
rv = 0;
|
||||
|
||||
xdr_free((xdrproc_t) xdr_qemu_domain_monitor_command_with_files_ret, (char *) &ret);
|
||||
|
||||
done:
|
||||
if (rpc_outfiles) {
|
||||
for (i = 0; rpc_noutfiles < i; i++) {
|
||||
VIR_FORCE_CLOSE(rpc_outfiles[i]);
|
||||
}
|
||||
}
|
||||
|
||||
remoteDriverUnlock(priv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
remoteDomainMigrateBegin3(virDomainPtr domain,
|
||||
const char *xmlin,
|
||||
@ -8506,6 +8562,7 @@ static virHypervisorDriver hypervisor_driver = {
|
||||
.domainSnapshotHasMetadata = remoteDomainSnapshotHasMetadata, /* 0.9.13 */
|
||||
.domainSnapshotDelete = remoteDomainSnapshotDelete, /* 0.8.0 */
|
||||
.domainQemuMonitorCommand = remoteDomainQemuMonitorCommand, /* 0.8.3 */
|
||||
.domainQemuMonitorCommandWithFiles = remoteDomainQemuMonitorCommandWithFiles, /* 8.2.0 */
|
||||
.domainQemuAttach = remoteDomainQemuAttach, /* 0.9.4 */
|
||||
.domainQemuAgentCommand = remoteDomainQemuAgentCommand, /* 0.10.0 */
|
||||
.connectDomainQemuMonitorEventRegister = remoteConnectDomainQemuMonitorEventRegister, /* 1.2.3 */
|
||||
|
Loading…
Reference in New Issue
Block a user