/configure
/configure.lineno
/conftest.*
-/daemon/*_dispatch.h
-/daemon/libvirt_qemud
-/daemon/libvirtd
/daemon/libvirtd*.logrotate
/daemon/libvirtd.policy
/daemon/test_libvirtd.aug
/src/libvirt_*helper
/src/libvirt_*probes.h
/src/libvirt_lxc
+/src/libvirtd
/src/locking/libxl-lockd.conf
/src/locking/libxl-sanlock.conf
/src/locking/lock_daemon_dispatch_stubs.h
/src/qemu/test_libvirtd_qemu.aug
/src/remote/*_client_bodies.h
/src/remote/*_protocol.[ch]
+/src/remote/*_stubs.h
/src/rpc/virkeepaliveprotocol.[ch]
/src/rpc/virnetprotocol.[ch]
/src/test_libvirt*.aug
# List of additional files that we want to pick up in our POTFILES.in
# This is all gnulib files, as well as generated files for RPC code.
generated_files = \
- $(srcdir)/daemon/{lxc,qemu,remote}_dispatch.h \
- $(srcdir)/src/*/{admin_server,log_daemon,lock_daemon}_dispatch_stubs.h \
+ $(srcdir)/src/*/{remote_daemon,admin_server,log_daemon,lock_daemon}_dispatch_*stubs.h \
$(srcdir)/src/lxc/{lxc_monitor,lxc_controller}_dispatch.h \
$(srcdir)/src/remote/*_client_bodies.h \
$(srcdir)/src/*/*_protocol.[ch] \
# sc_po_check can fail if generated files are not built first
sc_po_check: \
- $(srcdir)/daemon/remote_dispatch.h \
- $(srcdir)/daemon/qemu_dispatch.h \
+ $(srcdir)/src/remote/remote_daemon_dispatch_stubs.h \
+ $(srcdir)/src/remote/remote_daemon_dispatch_qemu_stubs.h \
$(srcdir)/src/remote/remote_client_bodies.h \
$(srcdir)/src/admin/admin_server_dispatch_stubs.h \
$(srcdir)/src/admin/admin_client.h
-$(srcdir)/daemon/remote_dispatch.h: $(srcdir)/src/remote/remote_protocol.x
- $(MAKE) -C daemon remote_dispatch.h
-$(srcdir)/daemon/qemu_dispatch.h: $(srcdir)/src/remote/qemu_protocol.x
- $(MAKE) -C daemon qemu_dispatch.h
+$(srcdir)/src/remote/remote_daemon_dispatch_stubs.h: $(srcdir)/src/remote/remote_protocol.x
+ $(MAKE) -C src remote/remote_daemon_dispatch_stubs.h
+$(srcdir)/src/remote/remote_daemon_dispatch_qemu_stubs.h: $(srcdir)/src/remote/qemu_protocol.x
+ $(MAKE) -C src remote/remote_daemon_dispatch_qemu_stubs.h
$(srcdir)/src/remote/remote_client_bodies.h: $(srcdir)/src/remote/remote_protocol.x
$(MAKE) -C src remote/remote_client_bodies.h
$(srcdir)/src/admin/admin_server_dispatch_stubs.h: $(srcdir)/src/admin/admin_protocol.x
_src1=libvirt-stream|qemu/qemu_monitor|util/vir(command|file|fdstream)|xen/xend_internal|rpc/virnetsocket|lxc/lxc_controller|locking/lock_daemon|logging/log_daemon
_test1=shunloadtest|virnettlscontexttest|virnettlssessiontest|vircgroupmock|commandhelper
exclude_file_name_regexp--sc_avoid_write = \
- ^(src/($(_src1))|daemon/libvirtd|tools/virsh-console|tests/($(_test1)))\.c$$
+ ^(src/($(_src1))|tools/virsh-console|tests/($(_test1)))\.c$$
exclude_file_name_regexp--sc_bindtextdomain = .*
exclude_file_name_regexp--sc_po_check = ^(docs/|src/rpc/gendispatch\.pl$$)
exclude_file_name_regexp--sc_prohibit_VIR_ERR_NO_MEMORY = \
- ^(cfg\.mk|include/libvirt/virterror\.h|daemon/dispatch\.c|src/util/virerror\.c|docs/internals/oomtesting\.html\.in)$$
+ ^(cfg\.mk|include/libvirt/virterror\.h|src/remote/remote_daemon_dispatch\.c|src/util/virerror\.c|docs/internals/oomtesting\.html\.in)$$
exclude_file_name_regexp--sc_prohibit_PATH_MAX = \
^cfg\.mk$$
exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF = \
(^tests/(qemuhelp|virhostcpu|virpcitest)data/|docs/js/.*\.js|docs/fonts/.*\.woff|\.diff|tests/virconfdata/no-newline\.conf$$)
-_src2=src/(util/vircommand|libvirt|lxc/lxc_controller|locking/lock_daemon|logging/log_daemon)
+_src2=src/(util/vircommand|libvirt|lxc/lxc_controller|locking/lock_daemon|logging/log_daemon|remote/remote_daemon)
exclude_file_name_regexp--sc_prohibit_fork_wrappers = \
- (^($(_src2)|tests/testutils|daemon/libvirtd)\.c$$)
+ (^($(_src2)|tests/testutils)\.c$$)
exclude_file_name_regexp--sc_prohibit_gethostname = ^src/util/vir(util|log)\.c$$
## License along with this library. If not, see
## <http://www.gnu.org/licenses/>.
-INCLUDES = \
- -I$(top_builddir)/gnulib/lib -I$(top_srcdir)/gnulib/lib \
- -I$(top_srcdir) \
- -I$(top_builddir)/include -I$(top_srcdir)/include \
- -I$(top_builddir)/src -I$(top_srcdir)/src \
- -I$(top_srcdir)/src/util \
- -I$(top_srcdir)/src/conf \
- -I$(top_srcdir)/src/rpc \
- -I$(top_srcdir)/src/remote \
- -I$(top_srcdir)/src/admin \
- -I$(top_srcdir)/src/access \
- $(GETTEXT_CPPFLAGS)
-
CLEANFILES =
-WARN_CFLAGS += $(STRICT_FRAME_LIMIT_CFLAGS)
-
-DAEMON_GENERATED = \
- remote_dispatch.h \
- lxc_dispatch.h \
- qemu_dispatch.h \
- $(NULL)
-
-DAEMON_SOURCES = \
- libvirtd.c libvirtd.h \
- remote.c remote.h \
- stream.c stream.h \
- $(DAEMON_GENERATED)
-
-LIBVIRTD_CONF_SOURCES = libvirtd-config.c libvirtd-config.h
-
PODFILES = \
libvirtd.pod \
$(NULL)
DISTCLEANFILES =
EXTRA_DIST = \
- remote_dispatch.h \
- lxc_dispatch.h \
- qemu_dispatch.h \
libvirtd.conf \
libvirtd.init.in \
libvirtd.upstart \
test_libvirtd.aug.in \
$(PODFILES) \
$(MANINFILES) \
- $(DAEMON_SOURCES) \
- $(LIBVIRTD_CONF_SOURCES) \
$(NULL)
BUILT_SOURCES =
-REMOTE_PROTOCOL = $(top_srcdir)/src/remote/remote_protocol.x
-LXC_PROTOCOL = $(top_srcdir)/src/remote/lxc_protocol.x
-QEMU_PROTOCOL = $(top_srcdir)/src/remote/qemu_protocol.x
-ADMIN_PROTOCOL = $(top_srcdir)/src/admin/admin_protocol.x
-
-remote_dispatch.h: $(top_srcdir)/src/rpc/gendispatch.pl \
- $(REMOTE_PROTOCOL) Makefile.am
- $(AM_V_GEN)$(PERL) -w $(top_srcdir)/src/rpc/gendispatch.pl \
- --mode=server remote REMOTE $(REMOTE_PROTOCOL) \
- > $(srcdir)/remote_dispatch.h
-
-lxc_dispatch.h: $(top_srcdir)/src/rpc/gendispatch.pl \
- $(LXC_PROTOCOL) Makefile.am
- $(AM_V_GEN)$(PERL) -w $(top_srcdir)/src/rpc/gendispatch.pl \
- --mode=server lxc LXC $(LXC_PROTOCOL) \
- > $(srcdir)/lxc_dispatch.h
-
-qemu_dispatch.h: $(top_srcdir)/src/rpc/gendispatch.pl \
- $(QEMU_PROTOCOL) Makefile.am
- $(AM_V_GEN)$(PERL) -w $(top_srcdir)/src/rpc/gendispatch.pl \
- --mode=server qemu QEMU $(QEMU_PROTOCOL) \
- > $(srcdir)/qemu_dispatch.h
-
if WITH_LIBVIRTD
-# Build a convenience library, for reuse in tests/libvirtdconftest
-noinst_LTLIBRARIES = libvirtd_conf.la
-libvirtd_conf_la_SOURCES = $(LIBVIRTD_CONF_SOURCES)
-libvirtd_conf_la_CFLAGS = \
- $(LIBXML_CFLAGS) \
- $(XDR_CFLAGS) \
- $(WARN_CFLAGS) $(PIE_CFLAGS) \
- $(COVERAGE_CFLAGS) \
- $(NULL)
-libvirtd_conf_la_LDFLAGS = \
- $(RELRO_LDFLAGS) \
- $(PIE_LDFLAGS) \
- $(COVERAGE_LDFLAGS) \
- $(NO_INDIRECT_LDFLAGS) \
- $(NO_UNDEFINED_LDFLAGS) \
- $(NULL)
-libvirtd_conf_la_LIBADD = $(LIBXML_LIBS)
-
man8_MANS = libvirtd.8
-sbin_PROGRAMS = libvirtd
-
confdir = $(sysconfdir)/libvirt/
conf_DATA = libvirtd.conf
CLEANFILES += test_libvirtd.aug
-libvirtd_SOURCES = $(DAEMON_SOURCES)
-
-#-D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_POSIX_C_SOURCE=199506L
-libvirtd_CFLAGS = \
- $(LIBXML_CFLAGS) $(GNUTLS_CFLAGS) $(SASL_CFLAGS) \
- $(XDR_CFLAGS) $(DBUS_CFLAGS) $(LIBNL_CFLAGS) \
- $(WARN_CFLAGS) $(PIE_CFLAGS) \
- $(COVERAGE_CFLAGS) \
- -DQEMUD_PID_FILE="\"$(QEMUD_PID_FILE)\""
-
-libvirtd_LDFLAGS = \
- $(RELRO_LDFLAGS) \
- $(PIE_LDFLAGS) \
- $(COVERAGE_LDFLAGS) \
- $(NO_INDIRECT_LDFLAGS) \
- $(NO_UNDEFINED_LDFLAGS) \
- $(NULL)
-
-libvirtd_LDADD = \
- $(LIBXML_LIBS) \
- $(GNUTLS_LIBS) \
- $(SASL_LIBS) \
- $(DBUS_LIBS) \
- $(LIBNL_LIBS)
-
-if WITH_DTRACE_PROBES
-libvirtd_LDADD += ../src/libvirt_probes.lo
-endif WITH_DTRACE_PROBES
-
-libvirtd_LDADD += \
- libvirtd_conf.la \
- ../src/libvirt_driver_admin.la \
- ../src/libvirt-lxc.la \
- ../src/libvirt-qemu.la \
- $(NULL)
-
-libvirtd_LDADD += ../src/libvirt.la
-
if WITH_POLKIT
if WITH_POLKIT0
policydir = $(datadir)/PolicyKit/policy
uninstall-data-polkit::
endif ! WITH_POLKIT
-remote.c: $(DAEMON_GENERATED)
-remote.h: $(DAEMON_GENERATED)
-
LOGROTATE_CONFS = libvirtd.qemu.logrotate libvirtd.lxc.logrotate \
libvirtd.libxl.logrotate libvirtd.uml.logrotate \
libvirtd.logrotate
'$(AUGPARSE)' -I $(srcdir) test_libvirtd.aug; \
fi
-
-# This must be added last, since functions it provides/replaces
-# are used by nearly every other library.
-libvirtd_LDADD += ../gnulib/lib/libgnu.la $(LIBSOCKET)
-
else ! WITH_LIBVIRTD
install-data-local: install-data-sasl
uninstall-local:: uninstall-data-sasl
CLEANFILES += $(BUILT_SOURCES) $(man8_MANS)
CLEANFILES += *.cov *.gcov .libs/*.gcda .libs/*.gcno *.gcno *.gcda
-MAINTAINERCLEANFILES = $(MANINFILES) $(DAEMON_GENERATED)
+MAINTAINERCLEANFILES = $(MANINFILES)
+++ /dev/null
-/*
- * libvirtd-config.c: daemon start of day, guest process & i/o management
- *
- * Copyright (C) 2006-2012, 2014, 2015 Red Hat, Inc.
- * Copyright (C) 2006 Daniel P. Berrange
- *
- * 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 "libvirtd-config.h"
-#include "virconf.h"
-#include "viralloc.h"
-#include "virerror.h"
-#include "virlog.h"
-#include "rpc/virnetserver.h"
-#include "configmake.h"
-#include "remote/remote_protocol.h"
-#include "remote/remote_driver.h"
-#include "util/virnetdevopenvswitch.h"
-#include "virstring.h"
-#include "virutil.h"
-
-#define VIR_FROM_THIS VIR_FROM_CONF
-
-VIR_LOG_INIT("daemon.libvirtd-config");
-
-
-static int
-remoteConfigGetAuth(virConfPtr conf,
- const char *filename,
- const char *key,
- int *auth)
-{
- char *authstr = NULL;
-
- if (virConfGetValueString(conf, key, &authstr) < 0)
- return -1;
-
- if (!authstr)
- return 0;
-
- if (STREQ(authstr, "none")) {
- *auth = VIR_NET_SERVER_SERVICE_AUTH_NONE;
-#if WITH_SASL
- } else if (STREQ(authstr, "sasl")) {
- *auth = VIR_NET_SERVER_SERVICE_AUTH_SASL;
-#endif
- } else if (STREQ(authstr, "polkit")) {
- *auth = VIR_NET_SERVER_SERVICE_AUTH_POLKIT;
- } else {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("%s: %s: unsupported auth %s"),
- filename, key, authstr);
- VIR_FREE(authstr);
- return -1;
- }
-
- VIR_FREE(authstr);
- return 0;
-}
-
-int
-daemonConfigFilePath(bool privileged, char **configfile)
-{
- if (privileged) {
- if (VIR_STRDUP(*configfile, SYSCONFDIR "/libvirt/libvirtd.conf") < 0)
- goto error;
- } else {
- char *configdir = NULL;
-
- if (!(configdir = virGetUserConfigDirectory()))
- goto error;
-
- if (virAsprintf(configfile, "%s/libvirtd.conf", configdir) < 0) {
- VIR_FREE(configdir);
- goto error;
- }
- VIR_FREE(configdir);
- }
-
- return 0;
-
- error:
- return -1;
-}
-
-struct daemonConfig*
-daemonConfigNew(bool privileged ATTRIBUTE_UNUSED)
-{
- struct daemonConfig *data;
- char *localhost;
- int ret;
-
- if (VIR_ALLOC(data) < 0)
- return NULL;
-
- data->listen_tls = 1;
- data->listen_tcp = 0;
-
- if (VIR_STRDUP(data->tls_port, LIBVIRTD_TLS_PORT) < 0 ||
- VIR_STRDUP(data->tcp_port, LIBVIRTD_TCP_PORT) < 0)
- goto error;
-
- /* Only default to PolicyKit if running as root */
-#if WITH_POLKIT
- if (privileged) {
- data->auth_unix_rw = REMOTE_AUTH_POLKIT;
- data->auth_unix_ro = REMOTE_AUTH_POLKIT;
- } else {
-#endif
- data->auth_unix_rw = REMOTE_AUTH_NONE;
- data->auth_unix_ro = REMOTE_AUTH_NONE;
-#if WITH_POLKIT
- }
-#endif
-
- if (VIR_STRDUP(data->unix_sock_rw_perms,
- data->auth_unix_rw == REMOTE_AUTH_POLKIT ? "0777" : "0700") < 0 ||
- VIR_STRDUP(data->unix_sock_ro_perms, "0777") < 0 ||
- VIR_STRDUP(data->unix_sock_admin_perms, "0700") < 0)
- goto error;
-
-#if WITH_SASL
- data->auth_tcp = REMOTE_AUTH_SASL;
-#else
- data->auth_tcp = REMOTE_AUTH_NONE;
-#endif
- data->auth_tls = REMOTE_AUTH_NONE;
-
- data->mdns_adv = 0;
-
- data->min_workers = 5;
- data->max_workers = 20;
- data->max_clients = 5000;
- data->max_queued_clients = 1000;
- data->max_anonymous_clients = 20;
-
- data->prio_workers = 5;
-
- data->max_client_requests = 5;
-
- data->audit_level = 1;
- data->audit_logging = 0;
-
- data->keepalive_interval = 5;
- data->keepalive_count = 5;
-
- data->admin_min_workers = 5;
- data->admin_max_workers = 20;
- data->admin_max_clients = 5000;
- data->admin_max_queued_clients = 20;
- data->admin_max_client_requests = 5;
-
- data->admin_keepalive_interval = 5;
- data->admin_keepalive_count = 5;
-
- data->ovs_timeout = VIR_NETDEV_OVS_DEFAULT_TIMEOUT;
-
- localhost = virGetHostname();
- if (localhost == NULL) {
- /* we couldn't resolve the hostname; assume that we are
- * running in disconnected operation, and report a less
- * useful Avahi string
- */
- ret = VIR_STRDUP(data->mdns_name, "Virtualization Host");
- } else {
- char *tmp;
- /* Extract the host part of the potentially FQDN */
- if ((tmp = strchr(localhost, '.')))
- *tmp = '\0';
- ret = virAsprintf(&data->mdns_name, "Virtualization Host %s",
- localhost);
- }
- VIR_FREE(localhost);
- if (ret < 0)
- goto error;
-
- return data;
-
- error:
- daemonConfigFree(data);
- return NULL;
-}
-
-void
-daemonConfigFree(struct daemonConfig *data)
-{
- char **tmp;
-
- if (!data)
- return;
-
- VIR_FREE(data->listen_addr);
- VIR_FREE(data->tls_port);
- VIR_FREE(data->tcp_port);
- tmp = data->access_drivers;
- while (tmp && *tmp) {
- VIR_FREE(*tmp);
- tmp++;
- }
- VIR_FREE(data->access_drivers);
-
- VIR_FREE(data->unix_sock_admin_perms);
- VIR_FREE(data->unix_sock_ro_perms);
- VIR_FREE(data->unix_sock_rw_perms);
- VIR_FREE(data->unix_sock_group);
- VIR_FREE(data->unix_sock_dir);
- VIR_FREE(data->mdns_name);
-
- tmp = data->tls_allowed_dn_list;
- while (tmp && *tmp) {
- VIR_FREE(*tmp);
- tmp++;
- }
- VIR_FREE(data->tls_allowed_dn_list);
-
- tmp = data->sasl_allowed_username_list;
- while (tmp && *tmp) {
- VIR_FREE(*tmp);
- tmp++;
- }
- VIR_FREE(data->sasl_allowed_username_list);
- VIR_FREE(data->tls_priority);
-
- VIR_FREE(data->key_file);
- VIR_FREE(data->ca_file);
- VIR_FREE(data->cert_file);
- VIR_FREE(data->crl_file);
-
- VIR_FREE(data->host_uuid);
- VIR_FREE(data->host_uuid_source);
- VIR_FREE(data->log_filters);
- VIR_FREE(data->log_outputs);
-
- VIR_FREE(data);
-}
-
-static int
-daemonConfigLoadOptions(struct daemonConfig *data,
- const char *filename,
- virConfPtr conf)
-{
- if (virConfGetValueBool(conf, "listen_tcp", &data->listen_tcp) < 0)
- goto error;
- if (virConfGetValueBool(conf, "listen_tls", &data->listen_tls) < 0)
- goto error;
- if (virConfGetValueString(conf, "tls_port", &data->tls_port) < 0)
- goto error;
- if (virConfGetValueString(conf, "tcp_port", &data->tcp_port) < 0)
- goto error;
- if (virConfGetValueString(conf, "listen_addr", &data->listen_addr) < 0)
- goto error;
-
- if (remoteConfigGetAuth(conf, filename, "auth_unix_rw", &data->auth_unix_rw) < 0)
- goto error;
-#if WITH_POLKIT
- /* Change default perms to be wide-open if PolicyKit is enabled.
- * Admin can always override in config file
- */
- if (data->auth_unix_rw == REMOTE_AUTH_POLKIT) {
- VIR_FREE(data->unix_sock_rw_perms);
- if (VIR_STRDUP(data->unix_sock_rw_perms, "0777") < 0)
- goto error;
- }
-#endif
- if (remoteConfigGetAuth(conf, filename, "auth_unix_ro", &data->auth_unix_ro) < 0)
- goto error;
- if (remoteConfigGetAuth(conf, filename, "auth_tcp", &data->auth_tcp) < 0)
- goto error;
- if (remoteConfigGetAuth(conf, filename, "auth_tls", &data->auth_tls) < 0)
- goto error;
-
- if (virConfGetValueStringList(conf, "access_drivers", false,
- &data->access_drivers) < 0)
- goto error;
-
- if (virConfGetValueString(conf, "unix_sock_group", &data->unix_sock_group) < 0)
- goto error;
- if (virConfGetValueString(conf, "unix_sock_admin_perms", &data->unix_sock_admin_perms) < 0)
- goto error;
- if (virConfGetValueString(conf, "unix_sock_ro_perms", &data->unix_sock_ro_perms) < 0)
- goto error;
- if (virConfGetValueString(conf, "unix_sock_rw_perms", &data->unix_sock_rw_perms) < 0)
- goto error;
-
- if (virConfGetValueString(conf, "unix_sock_dir", &data->unix_sock_dir) < 0)
- goto error;
-
- if (virConfGetValueBool(conf, "mdns_adv", &data->mdns_adv) < 0)
- goto error;
- if (virConfGetValueString(conf, "mdns_name", &data->mdns_name) < 0)
- goto error;
-
- if (virConfGetValueBool(conf, "tls_no_sanity_certificate", &data->tls_no_sanity_certificate) < 0)
- goto error;
- if (virConfGetValueBool(conf, "tls_no_verify_certificate", &data->tls_no_verify_certificate) < 0)
- goto error;
-
- if (virConfGetValueString(conf, "key_file", &data->key_file) < 0)
- goto error;
- if (virConfGetValueString(conf, "cert_file", &data->cert_file) < 0)
- goto error;
- if (virConfGetValueString(conf, "ca_file", &data->ca_file) < 0)
- goto error;
- if (virConfGetValueString(conf, "crl_file", &data->crl_file) < 0)
- goto error;
-
- if (virConfGetValueStringList(conf, "tls_allowed_dn_list", false,
- &data->tls_allowed_dn_list) < 0)
- goto error;
-
-
- if (virConfGetValueStringList(conf, "sasl_allowed_username_list", false,
- &data->sasl_allowed_username_list) < 0)
- goto error;
-
- if (virConfGetValueString(conf, "tls_priority", &data->tls_priority) < 0)
- goto error;
-
- if (virConfGetValueUInt(conf, "min_workers", &data->min_workers) < 0)
- goto error;
- if (virConfGetValueUInt(conf, "max_workers", &data->max_workers) < 0)
- goto error;
- if (virConfGetValueUInt(conf, "max_clients", &data->max_clients) < 0)
- goto error;
- if (virConfGetValueUInt(conf, "max_queued_clients", &data->max_queued_clients) < 0)
- goto error;
- if (virConfGetValueUInt(conf, "max_anonymous_clients", &data->max_anonymous_clients) < 0)
- goto error;
-
- if (virConfGetValueUInt(conf, "prio_workers", &data->prio_workers) < 0)
- goto error;
-
- if (virConfGetValueUInt(conf, "max_client_requests", &data->max_client_requests) < 0)
- goto error;
-
- if (virConfGetValueUInt(conf, "admin_min_workers", &data->admin_min_workers) < 0)
- goto error;
- if (virConfGetValueUInt(conf, "admin_max_workers", &data->admin_max_workers) < 0)
- goto error;
- if (virConfGetValueUInt(conf, "admin_max_clients", &data->admin_max_clients) < 0)
- goto error;
- if (virConfGetValueUInt(conf, "admin_max_queued_clients", &data->admin_max_queued_clients) < 0)
- goto error;
- if (virConfGetValueUInt(conf, "admin_max_client_requests", &data->admin_max_client_requests) < 0)
- goto error;
-
- if (virConfGetValueUInt(conf, "audit_level", &data->audit_level) < 0)
- goto error;
- if (virConfGetValueBool(conf, "audit_logging", &data->audit_logging) < 0)
- goto error;
-
- if (virConfGetValueString(conf, "host_uuid", &data->host_uuid) < 0)
- goto error;
- if (virConfGetValueString(conf, "host_uuid_source", &data->host_uuid_source) < 0)
- goto error;
-
- if (virConfGetValueUInt(conf, "log_level", &data->log_level) < 0)
- goto error;
- if (virConfGetValueString(conf, "log_filters", &data->log_filters) < 0)
- goto error;
- if (virConfGetValueString(conf, "log_outputs", &data->log_outputs) < 0)
- goto error;
-
- if (virConfGetValueInt(conf, "keepalive_interval", &data->keepalive_interval) < 0)
- goto error;
- if (virConfGetValueUInt(conf, "keepalive_count", &data->keepalive_count) < 0)
- goto error;
-
- if (virConfGetValueInt(conf, "admin_keepalive_interval", &data->admin_keepalive_interval) < 0)
- goto error;
- if (virConfGetValueUInt(conf, "admin_keepalive_count", &data->admin_keepalive_count) < 0)
- goto error;
-
- if (virConfGetValueUInt(conf, "ovs_timeout", &data->ovs_timeout) < 0)
- goto error;
-
- return 0;
-
- error:
- return -1;
-}
-
-
-/* Read the config file if it exists.
- * Only used in the remote case, hence the name.
- */
-int
-daemonConfigLoadFile(struct daemonConfig *data,
- const char *filename,
- bool allow_missing)
-{
- virConfPtr conf;
- int ret;
-
- if (allow_missing &&
- access(filename, R_OK) == -1 &&
- errno == ENOENT)
- return 0;
-
- conf = virConfReadFile(filename, 0);
- if (!conf)
- return -1;
-
- ret = daemonConfigLoadOptions(data, filename, conf);
- virConfFree(conf);
- return ret;
-}
-
-int daemonConfigLoadData(struct daemonConfig *data,
- const char *filename,
- const char *filedata)
-{
- virConfPtr conf;
- int ret;
-
- conf = virConfReadString(filedata, 0);
- if (!conf)
- return -1;
-
- ret = daemonConfigLoadOptions(data, filename, conf);
- virConfFree(conf);
- return ret;
-}
+++ /dev/null
-/*
- * libvirtd-config.h: daemon start of day, guest process & i/o management
- *
- * Copyright (C) 2006-2012, 2015 Red Hat, Inc.
- * Copyright (C) 2006 Daniel P. Berrange
- *
- * 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 __LIBVIRTD_CONFIG_H__
-# define __LIBVIRTD_CONFIG_H__
-
-# include "internal.h"
-
-struct daemonConfig {
- char *host_uuid;
- char *host_uuid_source;
-
- bool listen_tls;
- bool listen_tcp;
- char *listen_addr;
- char *tls_port;
- char *tcp_port;
-
- char *unix_sock_admin_perms;
- char *unix_sock_ro_perms;
- char *unix_sock_rw_perms;
- char *unix_sock_group;
- char *unix_sock_dir;
-
- int auth_unix_rw;
- int auth_unix_ro;
- int auth_tcp;
- int auth_tls;
-
- char **access_drivers;
-
- bool mdns_adv;
- char *mdns_name;
-
- bool tls_no_verify_certificate;
- bool tls_no_sanity_certificate;
- char **tls_allowed_dn_list;
- char **sasl_allowed_username_list;
- char *tls_priority;
-
- char *key_file;
- char *cert_file;
- char *ca_file;
- char *crl_file;
-
- unsigned int min_workers;
- unsigned int max_workers;
- unsigned int max_clients;
- unsigned int max_queued_clients;
- unsigned int max_anonymous_clients;
-
- unsigned int prio_workers;
-
- unsigned int max_client_requests;
-
- unsigned int log_level;
- char *log_filters;
- char *log_outputs;
-
- unsigned int audit_level;
- bool audit_logging;
-
- int keepalive_interval;
- unsigned int keepalive_count;
-
- unsigned int admin_min_workers;
- unsigned int admin_max_workers;
- unsigned int admin_max_clients;
- unsigned int admin_max_queued_clients;
- unsigned int admin_max_client_requests;
-
- int admin_keepalive_interval;
- unsigned int admin_keepalive_count;
-
- unsigned int ovs_timeout;
-};
-
-
-int daemonConfigFilePath(bool privileged, char **configfile);
-struct daemonConfig* daemonConfigNew(bool privileged);
-void daemonConfigFree(struct daemonConfig *data);
-int daemonConfigLoadFile(struct daemonConfig *data,
- const char *filename,
- bool allow_missing);
-int daemonConfigLoadData(struct daemonConfig *data,
- const char *filename,
- const char *filedata);
-
-#endif /* __LIBVIRTD_CONFIG_H__ */
+++ /dev/null
-/*
- * libvirtd.c: daemon start of day, guest process & i/o management
- *
- * Copyright (C) 2006-2015 Red Hat, Inc.
- * Copyright (C) 2006 Daniel P. Berrange
- *
- * 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 <unistd.h>
-#include <fcntl.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <grp.h>
-
-#include "libvirt_internal.h"
-#include "virerror.h"
-#include "virfile.h"
-#include "virlog.h"
-#include "virpidfile.h"
-#include "virprocess.h"
-
-#define VIR_FROM_THIS VIR_FROM_QEMU
-
-#include "libvirtd.h"
-#include "libvirtd-config.h"
-
-#include "admin/admin_server_dispatch.h"
-#include "viruuid.h"
-#include "remote_driver.h"
-#include "viralloc.h"
-#include "virconf.h"
-#include "virnetlink.h"
-#include "virnetdaemon.h"
-#include "remote.h"
-#include "virhook.h"
-#include "viraudit.h"
-#include "virstring.h"
-#include "locking/lock_manager.h"
-#include "viraccessmanager.h"
-#include "virutil.h"
-#include "virgettext.h"
-#include "util/virnetdevopenvswitch.h"
-
-#include "driver.h"
-
-#include "configmake.h"
-
-#include "virdbus.h"
-
-VIR_LOG_INIT("daemon.libvirtd");
-
-#if WITH_SASL
-virNetSASLContextPtr saslCtxt = NULL;
-#endif
-virNetServerProgramPtr remoteProgram = NULL;
-virNetServerProgramPtr adminProgram = NULL;
-virNetServerProgramPtr qemuProgram = NULL;
-virNetServerProgramPtr lxcProgram = NULL;
-
-volatile bool driversInitialized = false;
-
-enum {
- VIR_DAEMON_ERR_NONE = 0,
- VIR_DAEMON_ERR_PIDFILE,
- VIR_DAEMON_ERR_RUNDIR,
- VIR_DAEMON_ERR_INIT,
- VIR_DAEMON_ERR_SIGNAL,
- VIR_DAEMON_ERR_PRIVS,
- VIR_DAEMON_ERR_NETWORK,
- VIR_DAEMON_ERR_CONFIG,
- VIR_DAEMON_ERR_HOOKS,
- VIR_DAEMON_ERR_AUDIT,
-
- VIR_DAEMON_ERR_LAST
-};
-
-VIR_ENUM_DECL(virDaemonErr)
-VIR_ENUM_IMPL(virDaemonErr, VIR_DAEMON_ERR_LAST,
- "Initialization successful",
- "Unable to obtain pidfile",
- "Unable to create rundir",
- "Unable to initialize libvirt",
- "Unable to setup signal handlers",
- "Unable to drop privileges",
- "Unable to initialize network sockets",
- "Unable to load configuration file",
- "Unable to look for hook scripts",
- "Unable to initialize audit system")
-
-static int daemonForkIntoBackground(const char *argv0)
-{
- int statuspipe[2];
- if (pipe(statuspipe) < 0)
- return -1;
-
- pid_t pid = fork();
- switch (pid) {
- case 0:
- {
- /* intermediate child */
- int stdinfd = -1;
- int stdoutfd = -1;
- int nextpid;
-
- VIR_FORCE_CLOSE(statuspipe[0]);
-
- if ((stdinfd = open("/dev/null", O_RDONLY)) <= STDERR_FILENO)
- goto cleanup;
- if ((stdoutfd = open("/dev/null", O_WRONLY)) <= STDERR_FILENO)
- goto cleanup;
- if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
- goto cleanup;
- if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO)
- goto cleanup;
- if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO)
- goto cleanup;
- if (VIR_CLOSE(stdinfd) < 0)
- goto cleanup;
- if (VIR_CLOSE(stdoutfd) < 0)
- goto cleanup;
-
- if (setsid() < 0)
- goto cleanup;
-
- nextpid = fork();
- switch (nextpid) {
- case 0: /* grandchild */
- return statuspipe[1];
- case -1: /* error */
- goto cleanup;
- default: /* intermediate child succeeded */
- _exit(EXIT_SUCCESS);
- }
-
- cleanup:
- VIR_FORCE_CLOSE(stdoutfd);
- VIR_FORCE_CLOSE(stdinfd);
- VIR_FORCE_CLOSE(statuspipe[1]);
- _exit(EXIT_FAILURE);
-
- }
-
- case -1: /* error in parent */
- goto error;
-
- default:
- {
- /* parent */
- int ret;
- char status;
-
- VIR_FORCE_CLOSE(statuspipe[1]);
-
- /* We wait to make sure the first child forked successfully */
- if (virProcessWait(pid, NULL, false) < 0)
- goto error;
-
- /* If we get here, then the grandchild was spawned, so we
- * must exit. Block until the second child initializes
- * successfully */
- again:
- ret = read(statuspipe[0], &status, 1);
- if (ret == -1 && errno == EINTR)
- goto again;
-
- VIR_FORCE_CLOSE(statuspipe[0]);
-
- if (ret != 1) {
- char ebuf[1024];
-
- fprintf(stderr,
- _("%s: error: unable to determine if daemon is "
- "running: %s\n"), argv0,
- virStrerror(errno, ebuf, sizeof(ebuf)));
- exit(EXIT_FAILURE);
- } else if (status != 0) {
- fprintf(stderr,
- _("%s: error: %s. Check /var/log/messages or run "
- "without --daemon for more info.\n"), argv0,
- virDaemonErrTypeToString(status));
- exit(EXIT_FAILURE);
- }
- _exit(EXIT_SUCCESS);
- }
- }
-
- error:
- VIR_FORCE_CLOSE(statuspipe[0]);
- VIR_FORCE_CLOSE(statuspipe[1]);
- return -1;
-}
-
-
-static int
-daemonUnixSocketPaths(struct daemonConfig *config,
- bool privileged,
- char **sockfile,
- char **rosockfile,
- char **admsockfile)
-{
- int ret = -1;
- char *rundir = NULL;
-
- if (config->unix_sock_dir) {
- if (virAsprintf(sockfile, "%s/libvirt-sock", config->unix_sock_dir) < 0)
- goto cleanup;
-
- if (privileged) {
- if (virAsprintf(rosockfile, "%s/libvirt-sock-ro", config->unix_sock_dir) < 0 ||
- virAsprintf(admsockfile, "%s/libvirt-admin-sock", config->unix_sock_dir) < 0)
- goto cleanup;
- }
- } else {
- if (privileged) {
- if (VIR_STRDUP(*sockfile, LOCALSTATEDIR "/run/libvirt/libvirt-sock") < 0 ||
- VIR_STRDUP(*rosockfile, LOCALSTATEDIR "/run/libvirt/libvirt-sock-ro") < 0 ||
- VIR_STRDUP(*admsockfile, LOCALSTATEDIR "/run/libvirt/libvirt-admin-sock") < 0)
- goto cleanup;
- } else {
- mode_t old_umask;
-
- if (!(rundir = virGetUserRuntimeDirectory()))
- goto cleanup;
-
- old_umask = umask(077);
- if (virFileMakePath(rundir) < 0) {
- umask(old_umask);
- goto cleanup;
- }
- umask(old_umask);
-
- if (virAsprintf(sockfile, "%s/libvirt-sock", rundir) < 0 ||
- virAsprintf(admsockfile, "%s/libvirt-admin-sock", rundir) < 0)
- goto cleanup;
- }
- }
-
- ret = 0;
- cleanup:
- VIR_FREE(rundir);
- return ret;
-}
-
-
-static void daemonErrorHandler(void *opaque ATTRIBUTE_UNUSED,
- virErrorPtr err ATTRIBUTE_UNUSED)
-{
- /* Don't do anything, since logging infrastructure already
- * took care of reporting the error */
-}
-
-static int daemonErrorLogFilter(virErrorPtr err, int priority)
-{
- /* These error codes don't really reflect real errors. They
- * are expected events that occur when an app tries to check
- * whether a particular guest already exists. This filters
- * them to a lower log level to prevent pollution of syslog
- */
- switch (err->code) {
- case VIR_ERR_NO_DOMAIN:
- case VIR_ERR_NO_NETWORK:
- case VIR_ERR_NO_STORAGE_POOL:
- case VIR_ERR_NO_STORAGE_VOL:
- case VIR_ERR_NO_NODE_DEVICE:
- case VIR_ERR_NO_INTERFACE:
- case VIR_ERR_NO_NWFILTER:
- case VIR_ERR_NO_SECRET:
- case VIR_ERR_NO_DOMAIN_SNAPSHOT:
- case VIR_ERR_OPERATION_INVALID:
- case VIR_ERR_NO_DOMAIN_METADATA:
- case VIR_ERR_NO_SERVER:
- case VIR_ERR_NO_CLIENT:
- return VIR_LOG_DEBUG;
- }
-
- return priority;
-}
-
-
-#define VIR_DAEMON_LOAD_MODULE(func, module) \
- virDriverLoadModule(module, #func)
-static void daemonInitialize(void)
-{
- /*
- * Note that the order is important: the first ones have a higher
- * priority when calling virStateInitialize. We must register the
- * network, storage and nodedev drivers before any stateful domain
- * driver, since their resources must be auto-started before any
- * domains can be auto-started.
- */
- /* We don't care if any of these fail, because the whole point
- * is to allow users to only install modules they want to use.
- * If they try to open a connection for a module that
- * is not loaded they'll get a suitable error at that point
- */
-#ifdef WITH_NETWORK
- VIR_DAEMON_LOAD_MODULE(networkRegister, "network");
-#endif
-#ifdef WITH_INTERFACE
- VIR_DAEMON_LOAD_MODULE(interfaceRegister, "interface");
-#endif
-#ifdef WITH_STORAGE
- VIR_DAEMON_LOAD_MODULE(storageRegister, "storage");
-#endif
-#ifdef WITH_NODE_DEVICES
- VIR_DAEMON_LOAD_MODULE(nodedevRegister, "nodedev");
-#endif
-#ifdef WITH_SECRETS
- VIR_DAEMON_LOAD_MODULE(secretRegister, "secret");
-#endif
-#ifdef WITH_NWFILTER
- VIR_DAEMON_LOAD_MODULE(nwfilterRegister, "nwfilter");
-#endif
-#ifdef WITH_XEN
- VIR_DAEMON_LOAD_MODULE(xenRegister, "xen");
-#endif
-#ifdef WITH_LIBXL
- VIR_DAEMON_LOAD_MODULE(libxlRegister, "libxl");
-#endif
-#ifdef WITH_QEMU
- VIR_DAEMON_LOAD_MODULE(qemuRegister, "qemu");
-#endif
-#ifdef WITH_LXC
- VIR_DAEMON_LOAD_MODULE(lxcRegister, "lxc");
-#endif
-#ifdef WITH_UML
- VIR_DAEMON_LOAD_MODULE(umlRegister, "uml");
-#endif
-#ifdef WITH_VBOX
- VIR_DAEMON_LOAD_MODULE(vboxRegister, "vbox");
-#endif
-#ifdef WITH_BHYVE
- VIR_DAEMON_LOAD_MODULE(bhyveRegister, "bhyve");
-#endif
-#ifdef WITH_VZ
- VIR_DAEMON_LOAD_MODULE(vzRegister, "vz");
-#endif
-}
-#undef VIR_DAEMON_LOAD_MODULE
-
-
-static int ATTRIBUTE_NONNULL(3)
-daemonSetupNetworking(virNetServerPtr srv,
- virNetServerPtr srvAdm,
- struct daemonConfig *config,
- const char *sock_path,
- const char *sock_path_ro,
- const char *sock_path_adm,
- bool ipsock,
- bool privileged)
-{
- virNetServerServicePtr svc = NULL;
- virNetServerServicePtr svcAdm = NULL;
- virNetServerServicePtr svcRO = NULL;
- virNetServerServicePtr svcTCP = NULL;
-#if WITH_GNUTLS
- virNetServerServicePtr svcTLS = NULL;
-#endif
- gid_t unix_sock_gid = 0;
- int unix_sock_ro_mask = 0;
- int unix_sock_rw_mask = 0;
- int unix_sock_adm_mask = 0;
- int ret = -1;
-
- unsigned int cur_fd = STDERR_FILENO + 1;
- unsigned int nfds = virGetListenFDs();
-
- if (config->unix_sock_group) {
- if (virGetGroupID(config->unix_sock_group, &unix_sock_gid) < 0)
- return ret;
- }
-
- if (nfds > (sock_path_ro ? 2 : 1)) {
- VIR_ERROR(_("Too many (%u) FDs passed from caller"), nfds);
- return ret;
- }
-
- if (virStrToLong_i(config->unix_sock_ro_perms, NULL, 8, &unix_sock_ro_mask) != 0) {
- VIR_ERROR(_("Failed to parse mode '%s'"), config->unix_sock_ro_perms);
- goto cleanup;
- }
-
- if (virStrToLong_i(config->unix_sock_admin_perms, NULL, 8, &unix_sock_adm_mask) != 0) {
- VIR_ERROR(_("Failed to parse mode '%s'"), config->unix_sock_admin_perms);
- goto cleanup;
- }
-
- if (virStrToLong_i(config->unix_sock_rw_perms, NULL, 8, &unix_sock_rw_mask) != 0) {
- VIR_ERROR(_("Failed to parse mode '%s'"), config->unix_sock_rw_perms);
- goto cleanup;
- }
-
- if (!(svc = virNetServerServiceNewFDOrUNIX(sock_path,
- unix_sock_rw_mask,
- unix_sock_gid,
- config->auth_unix_rw,
-#if WITH_GNUTLS
- NULL,
-#endif
- false,
- config->max_queued_clients,
- config->max_client_requests,
- nfds, &cur_fd)))
- goto cleanup;
- if (sock_path_ro) {
- if (!(svcRO = virNetServerServiceNewFDOrUNIX(sock_path_ro,
- unix_sock_ro_mask,
- unix_sock_gid,
- config->auth_unix_ro,
-#if WITH_GNUTLS
- NULL,
-#endif
- true,
- config->max_queued_clients,
- config->max_client_requests,
- nfds, &cur_fd)))
- goto cleanup;
- }
-
- if (virNetServerAddService(srv, svc,
- config->mdns_adv && !ipsock ?
- "_libvirt._tcp" :
- NULL) < 0)
- goto cleanup;
-
- if (svcRO &&
- virNetServerAddService(srv, svcRO, NULL) < 0)
- goto cleanup;
-
- if (sock_path_adm) {
- VIR_DEBUG("Registering unix socket %s", sock_path_adm);
- if (!(svcAdm = virNetServerServiceNewUNIX(sock_path_adm,
- unix_sock_adm_mask,
- unix_sock_gid,
- REMOTE_AUTH_NONE,
-#if WITH_GNUTLS
- NULL,
-#endif
- false,
- config->admin_max_queued_clients,
- config->admin_max_client_requests)))
- goto cleanup;
-
- if (virNetServerAddService(srvAdm, svcAdm, NULL) < 0)
- goto cleanup;
- }
-
- if (ipsock) {
- if (config->listen_tcp) {
- VIR_DEBUG("Registering TCP socket %s:%s",
- config->listen_addr, config->tcp_port);
- if (!(svcTCP = virNetServerServiceNewTCP(config->listen_addr,
- config->tcp_port,
- AF_UNSPEC,
- config->auth_tcp,
-#if WITH_GNUTLS
- NULL,
-#endif
- false,
- config->max_queued_clients,
- config->max_client_requests)))
- goto cleanup;
-
- if (virNetServerAddService(srv, svcTCP,
- config->mdns_adv ? "_libvirt._tcp" : NULL) < 0)
- goto cleanup;
- }
-
-#if WITH_GNUTLS
- if (config->listen_tls) {
- virNetTLSContextPtr ctxt = NULL;
-
- if (config->ca_file ||
- config->cert_file ||
- config->key_file) {
- if (!config->ca_file) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("No CA certificate path set to match server key/cert"));
- goto cleanup;
- }
- if (!config->cert_file) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("No server certificate path set to match server key"));
- goto cleanup;
- }
- if (!config->key_file) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("No server key path set to match server cert"));
- goto cleanup;
- }
- VIR_DEBUG("Using CA='%s' cert='%s' key='%s'",
- config->ca_file, config->cert_file, config->key_file);
- if (!(ctxt = virNetTLSContextNewServer(config->ca_file,
- config->crl_file,
- config->cert_file,
- config->key_file,
- (const char *const*)config->tls_allowed_dn_list,
- config->tls_priority,
- config->tls_no_sanity_certificate ? false : true,
- config->tls_no_verify_certificate ? false : true)))
- goto cleanup;
- } else {
- if (!(ctxt = virNetTLSContextNewServerPath(NULL,
- !privileged,
- (const char *const*)config->tls_allowed_dn_list,
- config->tls_priority,
- config->tls_no_sanity_certificate ? false : true,
- config->tls_no_verify_certificate ? false : true)))
- goto cleanup;
- }
-
- VIR_DEBUG("Registering TLS socket %s:%s",
- config->listen_addr, config->tls_port);
- if (!(svcTLS =
- virNetServerServiceNewTCP(config->listen_addr,
- config->tls_port,
- AF_UNSPEC,
- config->auth_tls,
- ctxt,
- false,
- config->max_queued_clients,
- config->max_client_requests))) {
- virObjectUnref(ctxt);
- goto cleanup;
- }
- if (virNetServerAddService(srv, svcTLS,
- config->mdns_adv &&
- !config->listen_tcp ? "_libvirt._tcp" : NULL) < 0)
- goto cleanup;
-
- virObjectUnref(ctxt);
- }
-#else
- (void)privileged;
- if (config->listen_tls) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("This libvirtd build does not support TLS"));
- goto cleanup;
- }
-#endif
- }
-
-#if WITH_SASL
- if (config->auth_unix_rw == REMOTE_AUTH_SASL ||
- (sock_path_ro && config->auth_unix_ro == REMOTE_AUTH_SASL) ||
-# if WITH_GNUTLS
- (ipsock && config->listen_tls && config->auth_tls == REMOTE_AUTH_SASL) ||
-# endif
- (ipsock && config->listen_tcp && config->auth_tcp == REMOTE_AUTH_SASL)) {
- saslCtxt = virNetSASLContextNewServer(
- (const char *const*)config->sasl_allowed_username_list);
- if (!saslCtxt)
- goto cleanup;
- }
-#endif
-
- ret = 0;
-
- cleanup:
-#if WITH_GNUTLS
- virObjectUnref(svcTLS);
-#endif
- virObjectUnref(svcTCP);
- virObjectUnref(svcRO);
- virObjectUnref(svcAdm);
- virObjectUnref(svc);
- return ret;
-}
-
-
-/*
- * Set up the openvswitch timeout
- */
-static void
-daemonSetupNetDevOpenvswitch(struct daemonConfig *config)
-{
- virNetDevOpenvswitchSetTimeout(config->ovs_timeout);
-}
-
-
-/*
- * Set up the logging environment
- * By default if daemonized all errors go to the logfile libvirtd.log,
- * but if verbose or error debugging is asked for then also output
- * informational and debug messages. Default size if 64 kB.
- */
-static int
-daemonSetupLogging(struct daemonConfig *config,
- bool privileged,
- bool verbose,
- bool godaemon)
-{
- virLogReset();
-
- /*
- * Libvirtd's order of precedence is:
- * cmdline > environment > config
- *
- * Given the precedence, we must process the variables in the opposite
- * order, each one overriding the previous.
- */
- if (config->log_level != 0)
- virLogSetDefaultPriority(config->log_level);
-
- /* In case the config is empty, both filters and outputs will become empty,
- * however we can't start with empty outputs, thus we'll need to define and
- * setup a default one.
- */
- ignore_value(virLogSetFilters(config->log_filters));
- ignore_value(virLogSetOutputs(config->log_outputs));
-
- /* If there are some environment variables defined, use those instead */
- virLogSetFromEnv();
-
- /*
- * Command line override for --verbose
- */
- if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO))
- virLogSetDefaultPriority(VIR_LOG_INFO);
-
- /* Define the default output. This is only applied if there was no setting
- * from either the config or the environment.
- */
- if (virLogSetDefaultOutput("libvirtd.log", godaemon, privileged) < 0)
- return -1;
-
- if (virLogGetNbOutputs() == 0)
- virLogSetOutputs(virLogGetDefaultOutput());
-
- return 0;
-}
-
-
-static int
-daemonSetupAccessManager(struct daemonConfig *config)
-{
- virAccessManagerPtr mgr;
- const char *none[] = { "none", NULL };
- const char **drv = (const char **)config->access_drivers;
-
- if (!drv ||
- !drv[0])
- drv = none;
-
- if (!(mgr = virAccessManagerNewStack(drv)))
- return -1;
-
- virAccessManagerSetDefault(mgr);
- virObjectUnref(mgr);
- return 0;
-}
-
-
-/* Display version information. */
-static void
-daemonVersion(const char *argv0)
-{
- printf("%s (%s) %s\n", argv0, PACKAGE_NAME, PACKAGE_VERSION);
-}
-
-#ifdef __sun
-static int
-daemonSetupPrivs(void)
-{
- chown("/var/run/libvirt", SYSTEM_UID, SYSTEM_UID);
-
- if (__init_daemon_priv(PU_RESETGROUPS | PU_CLEARLIMITSET,
- SYSTEM_UID, SYSTEM_UID, PRIV_XVM_CONTROL, NULL)) {
- VIR_ERROR(_("additional privileges are required"));
- return -1;
- }
-
- if (priv_set(PRIV_OFF, PRIV_ALLSETS, PRIV_FILE_LINK_ANY, PRIV_PROC_INFO,
- PRIV_PROC_SESSION, PRIV_PROC_EXEC, PRIV_PROC_FORK, NULL)) {
- VIR_ERROR(_("failed to set reduced privileges"));
- return -1;
- }
-
- return 0;
-}
-#else
-# define daemonSetupPrivs() 0
-#endif
-
-
-static void daemonShutdownHandler(virNetDaemonPtr dmn,
- siginfo_t *sig ATTRIBUTE_UNUSED,
- void *opaque ATTRIBUTE_UNUSED)
-{
- virNetDaemonQuit(dmn);
-}
-
-static void daemonReloadHandler(virNetDaemonPtr dmn ATTRIBUTE_UNUSED,
- siginfo_t *sig ATTRIBUTE_UNUSED,
- void *opaque ATTRIBUTE_UNUSED)
-{
- if (!driversInitialized) {
- VIR_WARN("Drivers are not initialized, reload ignored");
- return;
- }
-
- VIR_INFO("Reloading configuration on SIGHUP");
- virHookCall(VIR_HOOK_DRIVER_DAEMON, "-",
- VIR_HOOK_DAEMON_OP_RELOAD, SIGHUP, "SIGHUP", NULL, NULL);
- if (virStateReload() < 0)
- VIR_WARN("Error while reloading drivers");
-}
-
-static int daemonSetupSignals(virNetDaemonPtr dmn)
-{
- if (virNetDaemonAddSignalHandler(dmn, SIGINT, daemonShutdownHandler, NULL) < 0)
- return -1;
- if (virNetDaemonAddSignalHandler(dmn, SIGQUIT, daemonShutdownHandler, NULL) < 0)
- return -1;
- if (virNetDaemonAddSignalHandler(dmn, SIGTERM, daemonShutdownHandler, NULL) < 0)
- return -1;
- if (virNetDaemonAddSignalHandler(dmn, SIGHUP, daemonReloadHandler, NULL) < 0)
- return -1;
- return 0;
-}
-
-
-static void daemonInhibitCallback(bool inhibit, void *opaque)
-{
- virNetDaemonPtr dmn = opaque;
-
- if (inhibit)
- virNetDaemonAddShutdownInhibition(dmn);
- else
- virNetDaemonRemoveShutdownInhibition(dmn);
-}
-
-
-#ifdef WITH_DBUS
-static DBusConnection *sessionBus;
-static DBusConnection *systemBus;
-
-static void daemonStopWorker(void *opaque)
-{
- virNetDaemonPtr dmn = opaque;
-
- VIR_DEBUG("Begin stop dmn=%p", dmn);
-
- ignore_value(virStateStop());
-
- VIR_DEBUG("Completed stop dmn=%p", dmn);
-
- /* Exit libvirtd cleanly */
- virNetDaemonQuit(dmn);
-}
-
-
-/* We do this in a thread to not block the main loop */
-static void daemonStop(virNetDaemonPtr dmn)
-{
- virThread thr;
- virObjectRef(dmn);
- if (virThreadCreate(&thr, false, daemonStopWorker, dmn) < 0)
- virObjectUnref(dmn);
-}
-
-
-static DBusHandlerResult
-handleSessionMessageFunc(DBusConnection *connection ATTRIBUTE_UNUSED,
- DBusMessage *message,
- void *opaque)
-{
- virNetDaemonPtr dmn = opaque;
-
- VIR_DEBUG("dmn=%p", dmn);
-
- if (dbus_message_is_signal(message,
- DBUS_INTERFACE_LOCAL,
- "Disconnected"))
- daemonStop(dmn);
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-
-static DBusHandlerResult
-handleSystemMessageFunc(DBusConnection *connection ATTRIBUTE_UNUSED,
- DBusMessage *message,
- void *opaque)
-{
- virNetDaemonPtr dmn = opaque;
-
- VIR_DEBUG("dmn=%p", dmn);
-
- if (dbus_message_is_signal(message,
- "org.freedesktop.login1.Manager",
- "PrepareForShutdown"))
- daemonStop(dmn);
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-#endif
-
-
-static void daemonRunStateInit(void *opaque)
-{
- virNetDaemonPtr dmn = opaque;
- virIdentityPtr sysident = virIdentityGetSystem();
-
- virIdentitySetCurrent(sysident);
-
- /* Since driver initialization can take time inhibit daemon shutdown until
- we're done so clients get a chance to connect */
- daemonInhibitCallback(true, dmn);
-
- /* Start the stateful HV drivers
- * This is deliberately done after telling the parent process
- * we're ready, since it can take a long time and this will
- * seriously delay OS bootup process */
- if (virStateInitialize(virNetDaemonIsPrivileged(dmn),
- daemonInhibitCallback,
- dmn) < 0) {
- VIR_ERROR(_("Driver state initialization failed"));
- /* Ensure the main event loop quits */
- kill(getpid(), SIGTERM);
- goto cleanup;
- }
-
- driversInitialized = true;
-
-#ifdef WITH_DBUS
- /* Tie the non-privileged libvirtd to the session/shutdown lifecycle */
- if (!virNetDaemonIsPrivileged(dmn)) {
-
- sessionBus = virDBusGetSessionBus();
- if (sessionBus != NULL)
- dbus_connection_add_filter(sessionBus,
- handleSessionMessageFunc, dmn, NULL);
-
- systemBus = virDBusGetSystemBus();
- if (systemBus != NULL) {
- dbus_connection_add_filter(systemBus,
- handleSystemMessageFunc, dmn, NULL);
- dbus_bus_add_match(systemBus,
- "type='signal',sender='org.freedesktop.login1', interface='org.freedesktop.login1.Manager'",
- NULL);
- }
- }
-#endif
- /* Only now accept clients from network */
- virNetDaemonUpdateServices(dmn, true);
- cleanup:
- daemonInhibitCallback(false, dmn);
- virObjectUnref(dmn);
- virObjectUnref(sysident);
- virIdentitySetCurrent(NULL);
-}
-
-static int daemonStateInit(virNetDaemonPtr dmn)
-{
- virThread thr;
- virObjectRef(dmn);
- if (virThreadCreate(&thr, false, daemonRunStateInit, dmn) < 0) {
- virObjectUnref(dmn);
- return -1;
- }
- return 0;
-}
-
-static int migrateProfile(void)
-{
- char *old_base = NULL;
- char *updated = NULL;
- char *home = NULL;
- char *xdg_dir = NULL;
- char *config_dir = NULL;
- const char *config_home;
- int ret = -1;
- mode_t old_umask;
-
- VIR_DEBUG("Checking if user profile needs migrating");
-
- if (!(home = virGetUserDirectory()))
- goto cleanup;
-
- if (virAsprintf(&old_base, "%s/.libvirt", home) < 0)
- goto cleanup;
-
- /* if the new directory is there or the old one is not: do nothing */
- if (!(config_dir = virGetUserConfigDirectory()))
- goto cleanup;
-
- if (!virFileIsDir(old_base) || virFileExists(config_dir)) {
- VIR_DEBUG("No old profile in '%s' / "
- "new profile directory already present '%s'",
- old_base, config_dir);
- ret = 0;
- goto cleanup;
- }
-
- /* test if we already attempted to migrate first */
- if (virAsprintf(&updated, "%s/DEPRECATED-DIRECTORY", old_base) < 0)
- goto cleanup;
- if (virFileExists(updated))
- goto cleanup;
-
- config_home = virGetEnvBlockSUID("XDG_CONFIG_HOME");
- if (config_home && config_home[0] != '\0') {
- if (VIR_STRDUP(xdg_dir, config_home) < 0)
- goto cleanup;
- } else {
- if (virAsprintf(&xdg_dir, "%s/.config", home) < 0)
- goto cleanup;
- }
-
- old_umask = umask(077);
- if (virFileMakePath(xdg_dir) < 0) {
- umask(old_umask);
- goto cleanup;
- }
- umask(old_umask);
-
- if (rename(old_base, config_dir) < 0) {
- int fd = creat(updated, 0600);
- VIR_FORCE_CLOSE(fd);
- VIR_ERROR(_("Unable to migrate %s to %s"), old_base, config_dir);
- goto cleanup;
- }
-
- VIR_DEBUG("Profile migrated from %s to %s", old_base, config_dir);
- ret = 0;
-
- cleanup:
- VIR_FREE(home);
- VIR_FREE(old_base);
- VIR_FREE(xdg_dir);
- VIR_FREE(config_dir);
- VIR_FREE(updated);
-
- return ret;
-}
-
-static int
-daemonSetupHostUUID(const struct daemonConfig *config)
-{
- static const char *machine_id = "/etc/machine-id";
- char buf[VIR_UUID_STRING_BUFLEN];
- const char *uuid;
-
- if (config->host_uuid) {
- uuid = config->host_uuid;
- } else if (!config->host_uuid_source ||
- STREQ(config->host_uuid_source, "smbios")) {
- /* smbios UUID is fetched on demand in virGetHostUUID */
- return 0;
- } else if (STREQ(config->host_uuid_source, "machine-id")) {
- if (virFileReadBufQuiet(machine_id, buf, sizeof(buf)) < 0) {
- VIR_ERROR(_("Can't read %s"), machine_id);
- return -1;
- }
-
- uuid = buf;
- } else {
- VIR_ERROR(_("invalid UUID source: %s"), config->host_uuid_source);
- return -1;
- }
-
- if (virSetHostUUIDStr(uuid)) {
- VIR_ERROR(_("invalid host UUID: %s"), uuid);
- return -1;
- }
-
- return 0;
-}
-
-/* Print command-line usage. */
-static void
-daemonUsage(const char *argv0, bool privileged)
-{
- fprintf(stderr,
- _("\n"
- "Usage:\n"
- " %s [options]\n"
- "\n"
- "Options:\n"
- " -h | --help Display program help:\n"
- " -v | --verbose Verbose messages.\n"
- " -d | --daemon Run as a daemon & write PID file.\n"
- " -l | --listen Listen for TCP/IP connections.\n"
- " -t | --timeout <secs> Exit after timeout period.\n"
- " -f | --config <file> Configuration file.\n"
- " -V | --version Display version information.\n"
- " -p | --pid-file <file> Change name of PID file.\n"
- "\n"
- "libvirt management daemon:\n"),
- argv0);
-
- if (privileged) {
- fprintf(stderr,
- _("\n"
- " Default paths:\n"
- "\n"
- " Configuration file (unless overridden by -f):\n"
- " %s\n"
- "\n"
- " Sockets:\n"
- " %s\n"
- " %s\n"
- "\n"
- " TLS:\n"
- " CA certificate: %s\n"
- " Server certificate: %s\n"
- " Server private key: %s\n"
- "\n"
- " PID file (unless overridden by -p):\n"
- " %s/run/libvirtd.pid\n"
- "\n"),
- LIBVIRTD_CONFIGURATION_FILE,
- LIBVIRTD_PRIV_UNIX_SOCKET,
- LIBVIRTD_PRIV_UNIX_SOCKET_RO,
- LIBVIRT_CACERT,
- LIBVIRT_SERVERCERT,
- LIBVIRT_SERVERKEY,
- LOCALSTATEDIR);
- } else {
- fprintf(stderr, "%s",
- _("\n"
- " Default paths:\n"
- "\n"
- " Configuration file (unless overridden by -f):\n"
- " $XDG_CONFIG_HOME/libvirt/libvirtd.conf\n"
- "\n"
- " Sockets:\n"
- " $XDG_RUNTIME_DIR/libvirt/libvirt-sock\n"
- "\n"
- " TLS:\n"
- " CA certificate: $HOME/.pki/libvirt/cacert.pem\n"
- " Server certificate: $HOME/.pki/libvirt/servercert.pem\n"
- " Server private key: $HOME/.pki/libvirt/serverkey.pem\n"
- "\n"
- " PID file:\n"
- " $XDG_RUNTIME_DIR/libvirt/libvirtd.pid\n"
- "\n"));
- }
-}
-
-int main(int argc, char **argv) {
- virNetDaemonPtr dmn = NULL;
- virNetServerPtr srv = NULL;
- virNetServerPtr srvAdm = NULL;
- char *remote_config_file = NULL;
- int statuswrite = -1;
- int ret = 1;
- int pid_file_fd = -1;
- char *pid_file = NULL;
- char *sock_file = NULL;
- char *sock_file_ro = NULL;
- char *sock_file_adm = NULL;
- int timeout = -1; /* -t: Shutdown timeout */
- int verbose = 0;
- int godaemon = 0;
- int ipsock = 0;
- struct daemonConfig *config;
- bool privileged = geteuid() == 0 ? true : false;
- bool implicit_conf = false;
- char *run_dir = NULL;
- mode_t old_umask;
-
- struct option opts[] = {
- { "verbose", no_argument, &verbose, 'v'},
- { "daemon", no_argument, &godaemon, 'd'},
- { "listen", no_argument, &ipsock, 'l'},
- { "config", required_argument, NULL, 'f'},
- { "timeout", required_argument, NULL, 't'},
- { "pid-file", required_argument, NULL, 'p'},
- { "version", no_argument, NULL, 'V' },
- { "help", no_argument, NULL, 'h' },
- {0, 0, 0, 0}
- };
-
- if (virGettextInitialize() < 0 ||
- virInitialize() < 0) {
- fprintf(stderr, _("%s: initialization failed\n"), argv[0]);
- exit(EXIT_FAILURE);
- }
-
- virUpdateSelfLastChanged(argv[0]);
-
- virFileActivateDirOverride(argv[0]);
-
- while (1) {
- int optidx = 0;
- int c;
- char *tmp;
-
- c = getopt_long(argc, argv, "ldf:p:t:vVh", opts, &optidx);
-
- if (c == -1)
- break;
-
- switch (c) {
- case 0:
- /* Got one of the flags */
- break;
- case 'v':
- verbose = 1;
- break;
- case 'd':
- godaemon = 1;
- break;
- case 'l':
- ipsock = 1;
- break;
-
- case 't':
- if (virStrToLong_i(optarg, &tmp, 10, &timeout) != 0
- || timeout <= 0
- /* Ensure that we can multiply by 1000 without overflowing. */
- || timeout > INT_MAX / 1000) {
- VIR_ERROR(_("Invalid value for timeout"));
- exit(EXIT_FAILURE);
- }
- break;
-
- case 'p':
- VIR_FREE(pid_file);
- if (VIR_STRDUP_QUIET(pid_file, optarg) < 0) {
- VIR_ERROR(_("Can't allocate memory"));
- exit(EXIT_FAILURE);
- }
- break;
-
- case 'f':
- VIR_FREE(remote_config_file);
- if (VIR_STRDUP_QUIET(remote_config_file, optarg) < 0) {
- VIR_ERROR(_("Can't allocate memory"));
- exit(EXIT_FAILURE);
- }
- break;
-
- case 'V':
- daemonVersion(argv[0]);
- exit(EXIT_SUCCESS);
-
- case 'h':
- daemonUsage(argv[0], privileged);
- exit(EXIT_SUCCESS);
-
- case '?':
- default:
- daemonUsage(argv[0], privileged);
- exit(EXIT_FAILURE);
- }
- }
-
- if (optind != argc) {
- fprintf(stderr, "%s: unexpected, non-option, command line arguments\n",
- argv[0]);
- exit(EXIT_FAILURE);
- }
-
- if (!(config = daemonConfigNew(privileged))) {
- VIR_ERROR(_("Can't create initial configuration"));
- exit(EXIT_FAILURE);
- }
-
- /* No explicit config, so try and find a default one */
- if (remote_config_file == NULL) {
- implicit_conf = true;
- if (daemonConfigFilePath(privileged,
- &remote_config_file) < 0) {
- VIR_ERROR(_("Can't determine config path"));
- exit(EXIT_FAILURE);
- }
- }
-
- /* Read the config file if it exists*/
- if (remote_config_file &&
- daemonConfigLoadFile(config, remote_config_file, implicit_conf) < 0) {
- VIR_ERROR(_("Can't load config file: %s: %s"),
- virGetLastErrorMessage(), remote_config_file);
- exit(EXIT_FAILURE);
- }
-
- if (!privileged &&
- migrateProfile() < 0) {
- VIR_ERROR(_("Exiting due to failure to migrate profile"));
- exit(EXIT_FAILURE);
- }
-
- if (daemonSetupHostUUID(config) < 0) {
- VIR_ERROR(_("Can't setup host uuid"));
- exit(EXIT_FAILURE);
- }
-
- if (daemonSetupLogging(config, privileged, verbose, godaemon) < 0) {
- VIR_ERROR(_("Can't initialize logging"));
- exit(EXIT_FAILURE);
- }
-
- daemonSetupNetDevOpenvswitch(config);
-
- if (daemonSetupAccessManager(config) < 0) {
- VIR_ERROR(_("Can't initialize access manager"));
- exit(EXIT_FAILURE);
- }
-
- if (!pid_file &&
- virPidFileConstructPath(privileged,
- LOCALSTATEDIR,
- "libvirtd",
- &pid_file) < 0) {
- VIR_ERROR(_("Can't determine pid file path."));
- exit(EXIT_FAILURE);
- }
- VIR_DEBUG("Decided on pid file path '%s'", NULLSTR(pid_file));
-
- if (daemonUnixSocketPaths(config,
- privileged,
- &sock_file,
- &sock_file_ro,
- &sock_file_adm) < 0) {
- VIR_ERROR(_("Can't determine socket paths"));
- exit(EXIT_FAILURE);
- }
- VIR_DEBUG("Decided on socket paths '%s', '%s' and '%s'",
- sock_file,
- NULLSTR(sock_file_ro),
- NULLSTR(sock_file_adm));
-
- if (godaemon) {
- char ebuf[1024];
-
- if (chdir("/") < 0) {
- VIR_ERROR(_("cannot change to root directory: %s"),
- virStrerror(errno, ebuf, sizeof(ebuf)));
- goto cleanup;
- }
-
- if ((statuswrite = daemonForkIntoBackground(argv[0])) < 0) {
- VIR_ERROR(_("Failed to fork as daemon: %s"),
- virStrerror(errno, ebuf, sizeof(ebuf)));
- goto cleanup;
- }
- }
-
- /* Try to claim the pidfile, exiting if we can't */
- if ((pid_file_fd = virPidFileAcquirePath(pid_file, false, getpid())) < 0) {
- ret = VIR_DAEMON_ERR_PIDFILE;
- goto cleanup;
- }
-
- /* Ensure the rundir exists (on tmpfs on some systems) */
- if (privileged) {
- if (VIR_STRDUP_QUIET(run_dir, LOCALSTATEDIR "/run/libvirt") < 0) {
- VIR_ERROR(_("Can't allocate memory"));
- goto cleanup;
- }
- } else {
- run_dir = virGetUserRuntimeDirectory();
-
- if (!run_dir) {
- VIR_ERROR(_("Can't determine user directory"));
- goto cleanup;
- }
- }
- if (privileged)
- old_umask = umask(022);
- else
- old_umask = umask(077);
- VIR_DEBUG("Ensuring run dir '%s' exists", run_dir);
- if (virFileMakePath(run_dir) < 0) {
- char ebuf[1024];
- VIR_ERROR(_("unable to create rundir %s: %s"), run_dir,
- virStrerror(errno, ebuf, sizeof(ebuf)));
- ret = VIR_DAEMON_ERR_RUNDIR;
- goto cleanup;
- }
- umask(old_umask);
-
- if (virNetlinkStartup() < 0) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
-
- if (!(dmn = virNetDaemonNew())) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
-
- if (!(srv = virNetServerNew("libvirtd", 1,
- config->min_workers,
- config->max_workers,
- config->prio_workers,
- config->max_clients,
- config->max_anonymous_clients,
- config->keepalive_interval,
- config->keepalive_count,
- config->mdns_adv ? config->mdns_name : NULL,
- remoteClientNew,
- NULL,
- remoteClientFree,
- NULL))) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
-
- if (virNetDaemonAddServer(dmn, srv) < 0) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
-
- /* Beyond this point, nothing should rely on using
- * getuid/geteuid() == 0, for privilege level checks.
- */
- VIR_DEBUG("Dropping privileges (if required)");
- if (daemonSetupPrivs() < 0) {
- ret = VIR_DAEMON_ERR_PRIVS;
- goto cleanup;
- }
-
- daemonInitialize();
-
- remoteProcs[REMOTE_PROC_AUTH_LIST].needAuth = false;
- remoteProcs[REMOTE_PROC_AUTH_SASL_INIT].needAuth = false;
- remoteProcs[REMOTE_PROC_AUTH_SASL_STEP].needAuth = false;
- remoteProcs[REMOTE_PROC_AUTH_SASL_START].needAuth = false;
- remoteProcs[REMOTE_PROC_AUTH_POLKIT].needAuth = false;
- if (!(remoteProgram = virNetServerProgramNew(REMOTE_PROGRAM,
- REMOTE_PROTOCOL_VERSION,
- remoteProcs,
- remoteNProcs))) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
- if (virNetServerAddProgram(srv, remoteProgram) < 0) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
-
- if (!(lxcProgram = virNetServerProgramNew(LXC_PROGRAM,
- LXC_PROTOCOL_VERSION,
- lxcProcs,
- lxcNProcs))) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
- if (virNetServerAddProgram(srv, lxcProgram) < 0) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
-
- if (!(qemuProgram = virNetServerProgramNew(QEMU_PROGRAM,
- QEMU_PROTOCOL_VERSION,
- qemuProcs,
- qemuNProcs))) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
- if (virNetServerAddProgram(srv, qemuProgram) < 0) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
-
- if (!(srvAdm = virNetServerNew("admin", 1,
- config->admin_min_workers,
- config->admin_max_workers,
- 0,
- config->admin_max_clients,
- 0,
- config->admin_keepalive_interval,
- config->admin_keepalive_count,
- NULL,
- remoteAdmClientNew,
- NULL,
- remoteAdmClientFree,
- dmn))) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
-
- if (virNetDaemonAddServer(dmn, srvAdm) < 0) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
-
- if (!(adminProgram = virNetServerProgramNew(ADMIN_PROGRAM,
- ADMIN_PROTOCOL_VERSION,
- adminProcs,
- adminNProcs))) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
- if (virNetServerAddProgram(srvAdm, adminProgram) < 0) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
-
- if (timeout != -1) {
- VIR_DEBUG("Registering shutdown timeout %d", timeout);
- virNetDaemonAutoShutdown(dmn, timeout);
- }
-
- if ((daemonSetupSignals(dmn)) < 0) {
- ret = VIR_DAEMON_ERR_SIGNAL;
- goto cleanup;
- }
-
- if (config->audit_level) {
- VIR_DEBUG("Attempting to configure auditing subsystem");
- if (virAuditOpen(config->audit_level) < 0) {
- if (config->audit_level > 1) {
- ret = VIR_DAEMON_ERR_AUDIT;
- goto cleanup;
- }
- VIR_DEBUG("Proceeding without auditing");
- }
- }
- virAuditLog(config->audit_logging > 0);
-
- /* setup the hooks if any */
- if (virHookInitialize() < 0) {
- ret = VIR_DAEMON_ERR_HOOKS;
- goto cleanup;
- }
-
- /* Disable error func, now logging is setup */
- virSetErrorFunc(NULL, daemonErrorHandler);
- virSetErrorLogPriorityFunc(daemonErrorLogFilter);
-
- /*
- * Call the daemon startup hook
- * TODO: should we abort the daemon startup if the script returned
- * an error ?
- */
- virHookCall(VIR_HOOK_DRIVER_DAEMON, "-", VIR_HOOK_DAEMON_OP_START,
- 0, "start", NULL, NULL);
-
- if (daemonSetupNetworking(srv, srvAdm,
- config,
- sock_file,
- sock_file_ro,
- sock_file_adm,
- ipsock, privileged) < 0) {
- ret = VIR_DAEMON_ERR_NETWORK;
- goto cleanup;
- }
-
- /* Tell parent of daemon that basic initialization is complete
- * In particular we're ready to accept net connections & have
- * written the pidfile
- */
- if (statuswrite != -1) {
- char status = 0;
- while (write(statuswrite, &status, 1) == -1 &&
- errno == EINTR)
- ;
- VIR_FORCE_CLOSE(statuswrite);
- }
-
- /* Initialize drivers & then start accepting new clients from network */
- if (daemonStateInit(dmn) < 0) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
-
-#if defined(__linux__) && defined(NETLINK_ROUTE)
- /* Register the netlink event service for NETLINK_ROUTE */
- if (virNetlinkEventServiceStart(NETLINK_ROUTE, 0) < 0) {
- ret = VIR_DAEMON_ERR_NETWORK;
- goto cleanup;
- }
-#endif
-
-#if defined(__linux__) && defined(NETLINK_KOBJECT_UEVENT)
- /* Register the netlink event service for NETLINK_KOBJECT_UEVENT */
- if (virNetlinkEventServiceStart(NETLINK_KOBJECT_UEVENT, 1) < 0) {
- ret = VIR_DAEMON_ERR_NETWORK;
- goto cleanup;
- }
-#endif
-
- /* Run event loop. */
- virNetDaemonRun(dmn);
-
- ret = 0;
-
- virHookCall(VIR_HOOK_DRIVER_DAEMON, "-", VIR_HOOK_DAEMON_OP_SHUTDOWN,
- 0, "shutdown", NULL, NULL);
-
- cleanup:
- /* Keep cleanup order in inverse order of startup */
- virNetDaemonClose(dmn);
-
- virNetlinkEventServiceStopAll();
-
- if (driversInitialized) {
- /* NB: Possible issue with timing window between driversInitialized
- * setting if virNetlinkEventServerStart fails */
- driversInitialized = false;
- virStateCleanup();
- }
-
- virObjectUnref(adminProgram);
- virObjectUnref(srvAdm);
- virObjectUnref(qemuProgram);
- virObjectUnref(lxcProgram);
- virObjectUnref(remoteProgram);
- virObjectUnref(srv);
- virObjectUnref(dmn);
-
- virNetlinkShutdown();
-
- if (pid_file_fd != -1)
- virPidFileReleasePath(pid_file, pid_file_fd);
-
- VIR_FREE(run_dir);
-
- if (statuswrite != -1) {
- if (ret != 0) {
- /* Tell parent of daemon what failed */
- char status = ret;
- while (write(statuswrite, &status, 1) == -1 &&
- errno == EINTR)
- ;
- }
- VIR_FORCE_CLOSE(statuswrite);
- }
-
- VIR_FREE(sock_file);
- VIR_FREE(sock_file_ro);
- VIR_FREE(sock_file_adm);
-
- VIR_FREE(pid_file);
-
- VIR_FREE(remote_config_file);
- daemonConfigFree(config);
-
- return ret;
-}
+++ /dev/null
-/*
- * libvirtd.h: daemon data structure definitions
- *
- * Copyright (C) 2006-2015 Red Hat, Inc.
- * Copyright (C) 2006 Daniel P. Berrange
- *
- * 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 LIBVIRTD_H__
-# define LIBVIRTD_H__
-
-# define VIR_ENUM_SENTINELS
-
-# include <rpc/types.h>
-# include <rpc/xdr.h>
-# include "remote_protocol.h"
-# include "lxc_protocol.h"
-# include "qemu_protocol.h"
-# include "virthread.h"
-
-# if WITH_SASL
-# include "virnetsaslcontext.h"
-# endif
-# include "virnetserverprogram.h"
-
-typedef struct daemonClientStream daemonClientStream;
-typedef daemonClientStream *daemonClientStreamPtr;
-typedef struct daemonClientPrivate daemonClientPrivate;
-typedef daemonClientPrivate *daemonClientPrivatePtr;
-typedef struct daemonClientEventCallback daemonClientEventCallback;
-typedef daemonClientEventCallback *daemonClientEventCallbackPtr;
-
-/* Stores the per-client connection state */
-struct daemonClientPrivate {
- /* Hold while accessing any data except conn */
- virMutex lock;
-
- daemonClientEventCallbackPtr *domainEventCallbacks;
- size_t ndomainEventCallbacks;
- daemonClientEventCallbackPtr *networkEventCallbacks;
- size_t nnetworkEventCallbacks;
- daemonClientEventCallbackPtr *qemuEventCallbacks;
- size_t nqemuEventCallbacks;
- daemonClientEventCallbackPtr *storageEventCallbacks;
- size_t nstorageEventCallbacks;
- daemonClientEventCallbackPtr *nodeDeviceEventCallbacks;
- size_t nnodeDeviceEventCallbacks;
- daemonClientEventCallbackPtr *secretEventCallbacks;
- size_t nsecretEventCallbacks;
- bool closeRegistered;
-
-# if WITH_SASL
- virNetSASLSessionPtr sasl;
-# endif
-
- /* This is only valid if a remote open call has been made on this
- * connection, otherwise it will be NULL. Also if remote close is
- * called, it will be set back to NULL if that succeeds.
- */
- virConnectPtr conn;
-
- daemonClientStreamPtr streams;
-};
-
-
-# if WITH_SASL
-extern virNetSASLContextPtr saslCtxt;
-# endif
-extern virNetServerProgramPtr remoteProgram;
-extern virNetServerProgramPtr qemuProgram;
-
-#endif
+++ /dev/null
-/*
- * remote.c: handlers for RPC method calls
- *
- * Copyright (C) 2007-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: Richard W.M. Jones <rjones@redhat.com>
- */
-
-#include <config.h>
-
-#include "virerror.h"
-
-#include "remote.h"
-#include "libvirtd.h"
-#include "libvirt_internal.h"
-#include "datatypes.h"
-#include "viralloc.h"
-#include "virlog.h"
-#include "stream.h"
-#include "viruuid.h"
-#include "vircommand.h"
-#include "intprops.h"
-#include "virnetserverservice.h"
-#include "virnetserver.h"
-#include "virfile.h"
-#include "virtypedparam.h"
-#include "virdbus.h"
-#include "virprocess.h"
-#include "remote_protocol.h"
-#include "qemu_protocol.h"
-#include "lxc_protocol.h"
-#include "virstring.h"
-#include "object_event.h"
-#include "domain_conf.h"
-#include "network_conf.h"
-#include "virprobe.h"
-#include "viraccessapicheck.h"
-#include "viraccessapicheckqemu.h"
-#include "virpolkit.h"
-#include "virthreadjob.h"
-
-#define VIR_FROM_THIS VIR_FROM_RPC
-
-VIR_LOG_INIT("daemon.remote");
-
-#if SIZEOF_LONG < 8
-# define HYPER_TO_TYPE(_type, _to, _from) \
- do { \
- if ((_from) != (_type)(_from)) { \
- virReportError(VIR_ERR_OVERFLOW, \
- _("conversion from hyper to %s overflowed"), \
- #_type); \
- goto cleanup; \
- } \
- (_to) = (_from); \
- } while (0)
-
-# define HYPER_TO_LONG(_to, _from) HYPER_TO_TYPE(long, _to, _from)
-# define HYPER_TO_ULONG(_to, _from) HYPER_TO_TYPE(unsigned long, _to, _from)
-#else
-# define HYPER_TO_LONG(_to, _from) (_to) = (_from)
-# define HYPER_TO_ULONG(_to, _from) (_to) = (_from)
-#endif
-
-struct daemonClientEventCallback {
- virNetServerClientPtr client;
- int eventID;
- int callbackID;
- bool legacy;
-};
-
-static virDomainPtr get_nonnull_domain(virConnectPtr conn, remote_nonnull_domain domain);
-static virNetworkPtr get_nonnull_network(virConnectPtr conn, remote_nonnull_network network);
-static virInterfacePtr get_nonnull_interface(virConnectPtr conn, remote_nonnull_interface iface);
-static virStoragePoolPtr get_nonnull_storage_pool(virConnectPtr conn, remote_nonnull_storage_pool pool);
-static virStorageVolPtr get_nonnull_storage_vol(virConnectPtr conn, remote_nonnull_storage_vol vol);
-static virSecretPtr get_nonnull_secret(virConnectPtr conn, remote_nonnull_secret secret);
-static virNWFilterPtr get_nonnull_nwfilter(virConnectPtr conn, remote_nonnull_nwfilter nwfilter);
-static virDomainSnapshotPtr get_nonnull_domain_snapshot(virDomainPtr dom, remote_nonnull_domain_snapshot snapshot);
-static virNodeDevicePtr get_nonnull_node_device(virConnectPtr conn, remote_nonnull_node_device dev);
-static void make_nonnull_domain(remote_nonnull_domain *dom_dst, virDomainPtr dom_src);
-static void make_nonnull_network(remote_nonnull_network *net_dst, virNetworkPtr net_src);
-static void make_nonnull_interface(remote_nonnull_interface *interface_dst, virInterfacePtr interface_src);
-static void make_nonnull_storage_pool(remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr pool_src);
-static void make_nonnull_storage_vol(remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src);
-static void make_nonnull_node_device(remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src);
-static void make_nonnull_secret(remote_nonnull_secret *secret_dst, virSecretPtr secret_src);
-static void make_nonnull_nwfilter(remote_nonnull_nwfilter *net_dst, virNWFilterPtr nwfilter_src);
-static void make_nonnull_domain_snapshot(remote_nonnull_domain_snapshot *snapshot_dst, virDomainSnapshotPtr snapshot_src);
-
-static int
-remoteSerializeDomainDiskErrors(virDomainDiskErrorPtr errors,
- int nerrors,
- remote_domain_disk_error **ret_errors_val,
- u_int *ret_errors_len);
-
-#include "remote_dispatch.h"
-#include "qemu_dispatch.h"
-#include "lxc_dispatch.h"
-
-
-/* Prototypes */
-static void
-remoteDispatchObjectEventSend(virNetServerClientPtr client,
- virNetServerProgramPtr program,
- int procnr,
- xdrproc_t proc,
- void *data);
-
-static void
-remoteEventCallbackFree(void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- if (!callback)
- return;
- virObjectUnref(callback->client);
- VIR_FREE(callback);
-}
-
-
-static bool
-remoteRelayDomainEventCheckACL(virNetServerClientPtr client,
- virConnectPtr conn, virDomainPtr dom)
-{
- virDomainDef def;
- virIdentityPtr identity = NULL;
- bool ret = false;
-
- /* For now, we just create a virDomainDef with enough contents to
- * satisfy what viraccessdriverpolkit.c references. This is a bit
- * fragile, but I don't know of anything better. */
- memset(&def, 0, sizeof(def));
- def.name = dom->name;
- memcpy(def.uuid, dom->uuid, VIR_UUID_BUFLEN);
-
- if (!(identity = virNetServerClientGetIdentity(client)))
- goto cleanup;
- if (virIdentitySetCurrent(identity) < 0)
- goto cleanup;
- ret = virConnectDomainEventRegisterAnyCheckACL(conn, &def);
-
- cleanup:
- ignore_value(virIdentitySetCurrent(NULL));
- virObjectUnref(identity);
- return ret;
-}
-
-
-static bool
-remoteRelayNetworkEventCheckACL(virNetServerClientPtr client,
- virConnectPtr conn, virNetworkPtr net)
-{
- virNetworkDef def;
- virIdentityPtr identity = NULL;
- bool ret = false;
-
- /* For now, we just create a virNetworkDef with enough contents to
- * satisfy what viraccessdriverpolkit.c references. This is a bit
- * fragile, but I don't know of anything better. */
- def.name = net->name;
- memcpy(def.uuid, net->uuid, VIR_UUID_BUFLEN);
-
- if (!(identity = virNetServerClientGetIdentity(client)))
- goto cleanup;
- if (virIdentitySetCurrent(identity) < 0)
- goto cleanup;
- ret = virConnectNetworkEventRegisterAnyCheckACL(conn, &def);
-
- cleanup:
- ignore_value(virIdentitySetCurrent(NULL));
- virObjectUnref(identity);
- return ret;
-}
-
-static bool
-remoteRelayStoragePoolEventCheckACL(virNetServerClientPtr client,
- virConnectPtr conn,
- virStoragePoolPtr pool)
-{
- virStoragePoolDef def;
- virIdentityPtr identity = NULL;
- bool ret = false;
-
- /* For now, we just create a virStoragePoolDef with enough contents to
- * satisfy what viraccessdriverpolkit.c references. This is a bit
- * fragile, but I don't know of anything better. */
- def.name = pool->name;
- memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN);
-
- if (!(identity = virNetServerClientGetIdentity(client)))
- goto cleanup;
- if (virIdentitySetCurrent(identity) < 0)
- goto cleanup;
- ret = virConnectStoragePoolEventRegisterAnyCheckACL(conn, &def);
-
- cleanup:
- ignore_value(virIdentitySetCurrent(NULL));
- virObjectUnref(identity);
- return ret;
-}
-
-static bool
-remoteRelayNodeDeviceEventCheckACL(virNetServerClientPtr client,
- virConnectPtr conn,
- virNodeDevicePtr dev)
-{
- virNodeDeviceDef def;
- virIdentityPtr identity = NULL;
- bool ret = false;
-
- /* For now, we just create a virNodeDeviceDef with enough contents to
- * satisfy what viraccessdriverpolkit.c references. This is a bit
- * fragile, but I don't know of anything better. */
- def.name = dev->name;
-
- if (!(identity = virNetServerClientGetIdentity(client)))
- goto cleanup;
- if (virIdentitySetCurrent(identity) < 0)
- goto cleanup;
- ret = virConnectNodeDeviceEventRegisterAnyCheckACL(conn, &def);
-
- cleanup:
- ignore_value(virIdentitySetCurrent(NULL));
- virObjectUnref(identity);
- return ret;
-}
-
-static bool
-remoteRelaySecretEventCheckACL(virNetServerClientPtr client,
- virConnectPtr conn,
- virSecretPtr secret)
-{
- virSecretDef def;
- virIdentityPtr identity = NULL;
- bool ret = false;
-
- /* For now, we just create a virSecretDef with enough contents to
- * satisfy what viraccessdriverpolkit.c references. This is a bit
- * fragile, but I don't know of anything better. */
- memcpy(def.uuid, secret->uuid, VIR_UUID_BUFLEN);
- def.usage_type = secret->usageType;
- def.usage_id = secret->usageID;
-
- if (!(identity = virNetServerClientGetIdentity(client)))
- goto cleanup;
- if (virIdentitySetCurrent(identity) < 0)
- goto cleanup;
- ret = virConnectSecretEventRegisterAnyCheckACL(conn, &def);
-
- cleanup:
- ignore_value(virIdentitySetCurrent(NULL));
- virObjectUnref(identity);
- return ret;
-}
-
-static bool
-remoteRelayDomainQemuMonitorEventCheckACL(virNetServerClientPtr client,
- virConnectPtr conn, virDomainPtr dom)
-{
- virDomainDef def;
- virIdentityPtr identity = NULL;
- bool ret = false;
-
- /* For now, we just create a virDomainDef with enough contents to
- * satisfy what viraccessdriverpolkit.c references. This is a bit
- * fragile, but I don't know of anything better. */
- def.name = dom->name;
- memcpy(def.uuid, dom->uuid, VIR_UUID_BUFLEN);
-
- if (!(identity = virNetServerClientGetIdentity(client)))
- goto cleanup;
- if (virIdentitySetCurrent(identity) < 0)
- goto cleanup;
- ret = virConnectDomainQemuMonitorEventRegisterCheckACL(conn, &def);
-
- cleanup:
- ignore_value(virIdentitySetCurrent(NULL));
- virObjectUnref(identity);
- return ret;
-}
-
-
-static int
-remoteRelayDomainEventLifecycle(virConnectPtr conn,
- virDomainPtr dom,
- int event,
- int detail,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_lifecycle_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain lifecycle event %d %d, callback %d legacy %d",
- event, detail, callback->callbackID, callback->legacy);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- make_nonnull_domain(&data.dom, dom);
- data.event = event;
- data.detail = detail;
-
- if (callback->legacy) {
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE,
- (xdrproc_t)xdr_remote_domain_event_lifecycle_msg,
- &data);
- } else {
- remote_domain_event_callback_lifecycle_msg msg = { callback->callbackID,
- data };
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_LIFECYCLE,
- (xdrproc_t)xdr_remote_domain_event_callback_lifecycle_msg,
- &msg);
- }
-
- return 0;
-}
-
-static int
-remoteRelayDomainEventReboot(virConnectPtr conn,
- virDomainPtr dom,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_reboot_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain reboot event %s %d, callback %d legacy %d",
- dom->name, dom->id, callback->callbackID, callback->legacy);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- make_nonnull_domain(&data.dom, dom);
-
- if (callback->legacy) {
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_REBOOT,
- (xdrproc_t)xdr_remote_domain_event_reboot_msg, &data);
- } else {
- remote_domain_event_callback_reboot_msg msg = { callback->callbackID,
- data };
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_REBOOT,
- (xdrproc_t)xdr_remote_domain_event_callback_reboot_msg, &msg);
- }
-
- return 0;
-}
-
-
-static int
-remoteRelayDomainEventRTCChange(virConnectPtr conn,
- virDomainPtr dom,
- long long offset,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_rtc_change_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain rtc change event %s %d %lld, callback %d legacy %d",
- dom->name, dom->id, offset,
- callback->callbackID, callback->legacy);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- make_nonnull_domain(&data.dom, dom);
- data.offset = offset;
-
- if (callback->legacy) {
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
- (xdrproc_t)xdr_remote_domain_event_rtc_change_msg, &data);
- } else {
- remote_domain_event_callback_rtc_change_msg msg = { callback->callbackID,
- data };
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_RTC_CHANGE,
- (xdrproc_t)xdr_remote_domain_event_callback_rtc_change_msg, &msg);
- }
-
- return 0;
-}
-
-
-static int
-remoteRelayDomainEventWatchdog(virConnectPtr conn,
- virDomainPtr dom,
- int action,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_watchdog_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain watchdog event %s %d %d, callback %d",
- dom->name, dom->id, action, callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- make_nonnull_domain(&data.dom, dom);
- data.action = action;
-
- if (callback->legacy) {
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_WATCHDOG,
- (xdrproc_t)xdr_remote_domain_event_watchdog_msg, &data);
- } else {
- remote_domain_event_callback_watchdog_msg msg = { callback->callbackID,
- data };
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_WATCHDOG,
- (xdrproc_t)xdr_remote_domain_event_callback_watchdog_msg, &msg);
- }
-
- return 0;
-}
-
-
-static int
-remoteRelayDomainEventIOError(virConnectPtr conn,
- virDomainPtr dom,
- const char *srcPath,
- const char *devAlias,
- int action,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_io_error_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain io error %s %d %s %s %d, callback %d",
- dom->name, dom->id, srcPath, devAlias, action,
- callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- if (VIR_STRDUP(data.srcPath, srcPath) < 0 ||
- VIR_STRDUP(data.devAlias, devAlias) < 0)
- goto error;
- make_nonnull_domain(&data.dom, dom);
- data.action = action;
-
- if (callback->legacy) {
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_IO_ERROR,
- (xdrproc_t)xdr_remote_domain_event_io_error_msg, &data);
- } else {
- remote_domain_event_callback_io_error_msg msg = { callback->callbackID,
- data };
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_IO_ERROR,
- (xdrproc_t)xdr_remote_domain_event_callback_io_error_msg, &msg);
- }
-
- return 0;
- error:
- VIR_FREE(data.srcPath);
- VIR_FREE(data.devAlias);
- return -1;
-}
-
-
-static int
-remoteRelayDomainEventIOErrorReason(virConnectPtr conn,
- virDomainPtr dom,
- const char *srcPath,
- const char *devAlias,
- int action,
- const char *reason,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_io_error_reason_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain io error %s %d %s %s %d %s, callback %d",
- dom->name, dom->id, srcPath, devAlias, action, reason,
- callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- if (VIR_STRDUP(data.srcPath, srcPath) < 0 ||
- VIR_STRDUP(data.devAlias, devAlias) < 0 ||
- VIR_STRDUP(data.reason, reason) < 0)
- goto error;
- data.action = action;
-
- make_nonnull_domain(&data.dom, dom);
-
- if (callback->legacy) {
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON,
- (xdrproc_t)xdr_remote_domain_event_io_error_reason_msg, &data);
- } else {
- remote_domain_event_callback_io_error_reason_msg msg = { callback->callbackID,
- data };
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_IO_ERROR_REASON,
- (xdrproc_t)xdr_remote_domain_event_callback_io_error_reason_msg, &msg);
- }
-
- return 0;
-
- error:
- VIR_FREE(data.srcPath);
- VIR_FREE(data.devAlias);
- VIR_FREE(data.reason);
- return -1;
-}
-
-
-static int
-remoteRelayDomainEventGraphics(virConnectPtr conn,
- virDomainPtr dom,
- int phase,
- virDomainEventGraphicsAddressPtr local,
- virDomainEventGraphicsAddressPtr remote,
- const char *authScheme,
- virDomainEventGraphicsSubjectPtr subject,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_graphics_msg data;
- size_t i;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain graphics event %s %d %d - %d %s %s - %d %s %s - %s, callback %d",
- dom->name, dom->id, phase,
- local->family, local->service, local->node,
- remote->family, remote->service, remote->node,
- authScheme, callback->callbackID);
-
- VIR_DEBUG("Subject %d", subject->nidentity);
- for (i = 0; i < subject->nidentity; i++)
- VIR_DEBUG(" %s=%s", subject->identities[i].type, subject->identities[i].name);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- data.phase = phase;
- data.local.family = local->family;
- data.remote.family = remote->family;
- if (VIR_STRDUP(data.authScheme, authScheme) < 0 ||
- VIR_STRDUP(data.local.node, local->node) < 0 ||
- VIR_STRDUP(data.local.service, local->service) < 0 ||
- VIR_STRDUP(data.remote.node, remote->node) < 0 ||
- VIR_STRDUP(data.remote.service, remote->service) < 0)
- goto error;
-
- data.subject.subject_len = subject->nidentity;
- if (VIR_ALLOC_N(data.subject.subject_val, data.subject.subject_len) < 0)
- goto error;
-
- for (i = 0; i < data.subject.subject_len; i++) {
- if (VIR_STRDUP(data.subject.subject_val[i].type, subject->identities[i].type) < 0 ||
- VIR_STRDUP(data.subject.subject_val[i].name, subject->identities[i].name) < 0)
- goto error;
- }
- make_nonnull_domain(&data.dom, dom);
-
- if (callback->legacy) {
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_GRAPHICS,
- (xdrproc_t)xdr_remote_domain_event_graphics_msg, &data);
- } else {
- remote_domain_event_callback_graphics_msg msg = { callback->callbackID,
- data };
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_GRAPHICS,
- (xdrproc_t)xdr_remote_domain_event_callback_graphics_msg, &msg);
- }
-
- return 0;
-
- error:
- VIR_FREE(data.authScheme);
- VIR_FREE(data.local.node);
- VIR_FREE(data.local.service);
- VIR_FREE(data.remote.node);
- VIR_FREE(data.remote.service);
- if (data.subject.subject_val != NULL) {
- for (i = 0; i < data.subject.subject_len; i++) {
- VIR_FREE(data.subject.subject_val[i].type);
- VIR_FREE(data.subject.subject_val[i].name);
- }
- VIR_FREE(data.subject.subject_val);
- }
- return -1;
-}
-
-static int
-remoteRelayDomainEventBlockJob(virConnectPtr conn,
- virDomainPtr dom,
- const char *path,
- int type,
- int status,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_block_job_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain block job event %s %d %s %i, %i, callback %d",
- dom->name, dom->id, path, type, status, callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- if (VIR_STRDUP(data.path, path) < 0)
- return -1;
- data.type = type;
- data.status = status;
- make_nonnull_domain(&data.dom, dom);
-
- if (callback->legacy) {
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB,
- (xdrproc_t)xdr_remote_domain_event_block_job_msg, &data);
- } else {
- remote_domain_event_callback_block_job_msg msg = { callback->callbackID,
- data };
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_BLOCK_JOB,
- (xdrproc_t)xdr_remote_domain_event_callback_block_job_msg, &msg);
- }
-
- return 0;
-}
-
-
-static int
-remoteRelayDomainEventControlError(virConnectPtr conn,
- virDomainPtr dom,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_control_error_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain control error %s %d, callback %d",
- dom->name, dom->id, callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- make_nonnull_domain(&data.dom, dom);
-
- if (callback->legacy) {
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR,
- (xdrproc_t)xdr_remote_domain_event_control_error_msg, &data);
- } else {
- remote_domain_event_callback_control_error_msg msg = { callback->callbackID,
- data };
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_CONTROL_ERROR,
- (xdrproc_t)xdr_remote_domain_event_callback_control_error_msg, &msg);
- }
-
- return 0;
-}
-
-
-static int
-remoteRelayDomainEventDiskChange(virConnectPtr conn,
- virDomainPtr dom,
- const char *oldSrcPath,
- const char *newSrcPath,
- const char *devAlias,
- int reason,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_disk_change_msg data;
- char **oldSrcPath_p = NULL, **newSrcPath_p = NULL;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain %s %d disk change %s %s %s %d, callback %d",
- dom->name, dom->id, oldSrcPath, newSrcPath, devAlias, reason,
- callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- if (oldSrcPath &&
- ((VIR_ALLOC(oldSrcPath_p) < 0) ||
- VIR_STRDUP(*oldSrcPath_p, oldSrcPath) < 0))
- goto error;
-
- if (newSrcPath &&
- ((VIR_ALLOC(newSrcPath_p) < 0) ||
- VIR_STRDUP(*newSrcPath_p, newSrcPath) < 0))
- goto error;
-
- data.oldSrcPath = oldSrcPath_p;
- data.newSrcPath = newSrcPath_p;
- if (VIR_STRDUP(data.devAlias, devAlias) < 0)
- goto error;
- data.reason = reason;
-
- make_nonnull_domain(&data.dom, dom);
-
- if (callback->legacy) {
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_DISK_CHANGE,
- (xdrproc_t)xdr_remote_domain_event_disk_change_msg, &data);
- } else {
- remote_domain_event_callback_disk_change_msg msg = { callback->callbackID,
- data };
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DISK_CHANGE,
- (xdrproc_t)xdr_remote_domain_event_callback_disk_change_msg, &msg);
- }
-
- return 0;
-
- error:
- VIR_FREE(oldSrcPath_p);
- VIR_FREE(newSrcPath_p);
- return -1;
-}
-
-
-static int
-remoteRelayDomainEventTrayChange(virConnectPtr conn,
- virDomainPtr dom,
- const char *devAlias,
- int reason,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_tray_change_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain %s %d tray change devAlias: %s reason: %d, callback %d",
- dom->name, dom->id, devAlias, reason, callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
-
- if (VIR_STRDUP(data.devAlias, devAlias) < 0)
- return -1;
- data.reason = reason;
-
- make_nonnull_domain(&data.dom, dom);
-
- if (callback->legacy) {
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_TRAY_CHANGE,
- (xdrproc_t)xdr_remote_domain_event_tray_change_msg, &data);
- } else {
- remote_domain_event_callback_tray_change_msg msg = { callback->callbackID,
- data };
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_TRAY_CHANGE,
- (xdrproc_t)xdr_remote_domain_event_callback_tray_change_msg, &msg);
- }
-
- return 0;
-}
-
-static int
-remoteRelayDomainEventPMWakeup(virConnectPtr conn,
- virDomainPtr dom,
- int reason,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_pmwakeup_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain %s %d system pmwakeup, callback %d",
- dom->name, dom->id, callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- make_nonnull_domain(&data.dom, dom);
-
- if (callback->legacy) {
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_PMWAKEUP,
- (xdrproc_t)xdr_remote_domain_event_pmwakeup_msg, &data);
- } else {
- remote_domain_event_callback_pmwakeup_msg msg = { callback->callbackID,
- reason, data };
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMWAKEUP,
- (xdrproc_t)xdr_remote_domain_event_callback_pmwakeup_msg, &msg);
- }
-
- return 0;
-}
-
-static int
-remoteRelayDomainEventPMSuspend(virConnectPtr conn,
- virDomainPtr dom,
- int reason,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_pmsuspend_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain %s %d system pmsuspend, callback %d",
- dom->name, dom->id, callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- make_nonnull_domain(&data.dom, dom);
-
- if (callback->legacy) {
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND,
- (xdrproc_t)xdr_remote_domain_event_pmsuspend_msg, &data);
- } else {
- remote_domain_event_callback_pmsuspend_msg msg = { callback->callbackID,
- reason, data };
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMSUSPEND,
- (xdrproc_t)xdr_remote_domain_event_callback_pmsuspend_msg, &msg);
- }
-
- return 0;
-}
-
-static int
-remoteRelayDomainEventBalloonChange(virConnectPtr conn,
- virDomainPtr dom,
- unsigned long long actual,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_balloon_change_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain balloon change event %s %d %lld, callback %d",
- dom->name, dom->id, actual, callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- make_nonnull_domain(&data.dom, dom);
- data.actual = actual;
-
- if (callback->legacy) {
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE,
- (xdrproc_t)xdr_remote_domain_event_balloon_change_msg, &data);
- } else {
- remote_domain_event_callback_balloon_change_msg msg = { callback->callbackID,
- data };
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_BALLOON_CHANGE,
- (xdrproc_t)xdr_remote_domain_event_callback_balloon_change_msg, &msg);
- }
-
- return 0;
-}
-
-
-static int
-remoteRelayDomainEventPMSuspendDisk(virConnectPtr conn,
- virDomainPtr dom,
- int reason,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_pmsuspend_disk_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain %s %d system pmsuspend-disk, callback %d",
- dom->name, dom->id, callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- make_nonnull_domain(&data.dom, dom);
-
- if (callback->legacy) {
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND_DISK,
- (xdrproc_t)xdr_remote_domain_event_pmsuspend_disk_msg, &data);
- } else {
- remote_domain_event_callback_pmsuspend_disk_msg msg = { callback->callbackID,
- reason, data };
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMSUSPEND_DISK,
- (xdrproc_t)xdr_remote_domain_event_callback_pmsuspend_disk_msg, &msg);
- }
-
- return 0;
-}
-
-static int
-remoteRelayDomainEventDeviceRemoved(virConnectPtr conn,
- virDomainPtr dom,
- const char *devAlias,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_device_removed_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain device removed event %s %d %s, callback %d",
- dom->name, dom->id, devAlias, callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
-
- if (VIR_STRDUP(data.devAlias, devAlias) < 0)
- return -1;
-
- make_nonnull_domain(&data.dom, dom);
-
- if (callback->legacy) {
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED,
- (xdrproc_t)xdr_remote_domain_event_device_removed_msg,
- &data);
- } else {
- remote_domain_event_callback_device_removed_msg msg = { callback->callbackID,
- data };
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVED,
- (xdrproc_t)xdr_remote_domain_event_callback_device_removed_msg,
- &msg);
- }
-
- return 0;
-}
-
-
-static int
-remoteRelayDomainEventBlockJob2(virConnectPtr conn,
- virDomainPtr dom,
- const char *dst,
- int type,
- int status,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_block_job_2_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain block job 2 event %s %d %s %i, %i, callback %d",
- dom->name, dom->id, dst, type, status, callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- data.callbackID = callback->callbackID;
- if (VIR_STRDUP(data.dst, dst) < 0)
- return -1;
- data.type = type;
- data.status = status;
- make_nonnull_domain(&data.dom, dom);
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB_2,
- (xdrproc_t)xdr_remote_domain_event_block_job_2_msg, &data);
-
- return 0;
-}
-
-
-static int
-remoteRelayDomainEventTunable(virConnectPtr conn,
- virDomainPtr dom,
- virTypedParameterPtr params,
- int nparams,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_callback_tunable_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain tunable event %s %d, callback %d, params %p %d",
- dom->name, dom->id, callback->callbackID, params, nparams);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- data.callbackID = callback->callbackID;
- make_nonnull_domain(&data.dom, dom);
-
- if (virTypedParamsSerialize(params, nparams,
- (virTypedParameterRemotePtr *) &data.params.params_val,
- &data.params.params_len,
- VIR_TYPED_PARAM_STRING_OKAY) < 0) {
- VIR_FREE(data.dom.name);
- return -1;
- }
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_TUNABLE,
- (xdrproc_t)xdr_remote_domain_event_callback_tunable_msg,
- &data);
-
- return 0;
-}
-
-
-static int
-remoteRelayDomainEventAgentLifecycle(virConnectPtr conn,
- virDomainPtr dom,
- int state,
- int reason,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_callback_agent_lifecycle_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain agent lifecycle event %s %d, callback %d, "
- " state %d, reason %d",
- dom->name, dom->id, callback->callbackID, state, reason);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- data.callbackID = callback->callbackID;
- make_nonnull_domain(&data.dom, dom);
-
- data.state = state;
- data.reason = reason;
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_AGENT_LIFECYCLE,
- (xdrproc_t)xdr_remote_domain_event_callback_agent_lifecycle_msg,
- &data);
-
- return 0;
-}
-
-
-static int
-remoteRelayDomainEventDeviceAdded(virConnectPtr conn,
- virDomainPtr dom,
- const char *devAlias,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_callback_device_added_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain device added event %s %d %s, callback %d",
- dom->name, dom->id, devAlias, callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
-
- if (VIR_STRDUP(data.devAlias, devAlias) < 0)
- return -1;
-
- make_nonnull_domain(&data.dom, dom);
- data.callbackID = callback->callbackID;
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_ADDED,
- (xdrproc_t)xdr_remote_domain_event_callback_device_added_msg,
- &data);
-
- return 0;
-}
-
-
-static int
-remoteRelayDomainEventMigrationIteration(virConnectPtr conn,
- virDomainPtr dom,
- int iteration,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_callback_migration_iteration_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain migration pass event %s %d, "
- "callback %d, iteration %d",
- dom->name, dom->id, callback->callbackID, iteration);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- data.callbackID = callback->callbackID;
- make_nonnull_domain(&data.dom, dom);
-
- data.iteration = iteration;
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_MIGRATION_ITERATION,
- (xdrproc_t)xdr_remote_domain_event_callback_migration_iteration_msg,
- &data);
-
- return 0;
-}
-
-
-static int
-remoteRelayDomainEventJobCompleted(virConnectPtr conn,
- virDomainPtr dom,
- virTypedParameterPtr params,
- int nparams,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_callback_job_completed_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain migration completed event %s %d, "
- "callback %d, params %p %d",
- dom->name, dom->id, callback->callbackID, params, nparams);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- data.callbackID = callback->callbackID;
- make_nonnull_domain(&data.dom, dom);
-
- if (virTypedParamsSerialize(params, nparams,
- (virTypedParameterRemotePtr *) &data.params.params_val,
- &data.params.params_len,
- VIR_TYPED_PARAM_STRING_OKAY) < 0) {
- VIR_FREE(data.dom.name);
- return -1;
- }
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_JOB_COMPLETED,
- (xdrproc_t)xdr_remote_domain_event_callback_job_completed_msg,
- &data);
- return 0;
-}
-
-
-static int
-remoteRelayDomainEventDeviceRemovalFailed(virConnectPtr conn,
- virDomainPtr dom,
- const char *devAlias,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_callback_device_removal_failed_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain device removal failed event %s %d %s, callback %d",
- dom->name, dom->id, devAlias, callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
-
- if (VIR_STRDUP(data.devAlias, devAlias) < 0)
- return -1;
-
- make_nonnull_domain(&data.dom, dom);
- data.callbackID = callback->callbackID;
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVAL_FAILED,
- (xdrproc_t)xdr_remote_domain_event_callback_device_removal_failed_msg,
- &data);
-
- return 0;
-}
-
-
-static int
-remoteRelayDomainEventMetadataChange(virConnectPtr conn,
- virDomainPtr dom,
- int type,
- const char *nsuri,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_callback_metadata_change_msg data;
- char **nsurip;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain metadata change %s %d %d %s, callback %d",
- dom->name, dom->id, type, NULLSTR(nsuri), callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
-
- data.type = type;
- if (nsuri) {
- if (VIR_ALLOC(nsurip) < 0)
- return -1;
- if (VIR_STRDUP(*nsurip, nsuri) < 0) {
- VIR_FREE(nsurip);
- return -1;
- }
- data.nsuri = nsurip;
- }
-
- make_nonnull_domain(&data.dom, dom);
- data.callbackID = callback->callbackID;
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_METADATA_CHANGE,
- (xdrproc_t)xdr_remote_domain_event_callback_metadata_change_msg,
- &data);
-
- return 0;
-}
-
-
-static int
-remoteRelayDomainEventBlockThreshold(virConnectPtr conn,
- virDomainPtr dom,
- const char *dev,
- const char *path,
- unsigned long long threshold,
- unsigned long long excess,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_domain_event_block_threshold_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
- return -1;
-
- VIR_DEBUG("Relaying domain block threshold event %s %d %s %s %llu %llu, callback %d",
- dom->name, dom->id, dev, NULLSTR(path), threshold, excess, callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- data.callbackID = callback->callbackID;
- if (VIR_STRDUP(data.dev, dev) < 0)
- goto error;
- if (path) {
- if (VIR_ALLOC(data.path) < 0)
- goto error;
- if (VIR_STRDUP(*(data.path), path) < 0)
- goto error;
- }
- data.threshold = threshold;
- data.excess = excess;
- make_nonnull_domain(&data.dom, dom);
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_DOMAIN_EVENT_BLOCK_THRESHOLD,
- (xdrproc_t)xdr_remote_domain_event_block_threshold_msg, &data);
-
- return 0;
- error:
- VIR_FREE(data.dev);
- return -1;
-}
-
-
-static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventRTCChange),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventWatchdog),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventIOError),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventGraphics),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventIOErrorReason),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventControlError),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDiskChange),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventTrayChange),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMWakeup),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMSuspend),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBalloonChange),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMSuspendDisk),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceRemoved),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob2),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventTunable),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventAgentLifecycle),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceAdded),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMigrationIteration),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventJobCompleted),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceRemovalFailed),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMetadataChange),
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockThreshold),
-};
-
-verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
-
-static int
-remoteRelayNetworkEventLifecycle(virConnectPtr conn,
- virNetworkPtr net,
- int event,
- int detail,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_network_event_lifecycle_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayNetworkEventCheckACL(callback->client, conn, net))
- return -1;
-
- VIR_DEBUG("Relaying network lifecycle event %d, detail %d, callback %d",
- event, detail, callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- make_nonnull_network(&data.net, net);
- data.callbackID = callback->callbackID;
- data.event = event;
- data.detail = detail;
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_NETWORK_EVENT_LIFECYCLE,
- (xdrproc_t)xdr_remote_network_event_lifecycle_msg, &data);
-
- return 0;
-}
-
-static virConnectNetworkEventGenericCallback networkEventCallbacks[] = {
- VIR_NETWORK_EVENT_CALLBACK(remoteRelayNetworkEventLifecycle),
-};
-
-verify(ARRAY_CARDINALITY(networkEventCallbacks) == VIR_NETWORK_EVENT_ID_LAST);
-
-static int
-remoteRelayStoragePoolEventLifecycle(virConnectPtr conn,
- virStoragePoolPtr pool,
- int event,
- int detail,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_storage_pool_event_lifecycle_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayStoragePoolEventCheckACL(callback->client, conn, pool))
- return -1;
-
- VIR_DEBUG("Relaying storage pool lifecycle event %d, detail %d, callback %d",
- event, detail, callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- make_nonnull_storage_pool(&data.pool, pool);
- data.callbackID = callback->callbackID;
- data.event = event;
- data.detail = detail;
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_STORAGE_POOL_EVENT_LIFECYCLE,
- (xdrproc_t)xdr_remote_storage_pool_event_lifecycle_msg,
- &data);
-
- return 0;
-}
-
-static int
-remoteRelayStoragePoolEventRefresh(virConnectPtr conn,
- virStoragePoolPtr pool,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_storage_pool_event_refresh_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayStoragePoolEventCheckACL(callback->client, conn, pool))
- return -1;
-
- VIR_DEBUG("Relaying storage pool refresh event callback %d",
- callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- make_nonnull_storage_pool(&data.pool, pool);
- data.callbackID = callback->callbackID;
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_STORAGE_POOL_EVENT_REFRESH,
- (xdrproc_t)xdr_remote_storage_pool_event_refresh_msg,
- &data);
-
- return 0;
-}
-
-static virConnectStoragePoolEventGenericCallback storageEventCallbacks[] = {
- VIR_STORAGE_POOL_EVENT_CALLBACK(remoteRelayStoragePoolEventLifecycle),
- VIR_STORAGE_POOL_EVENT_CALLBACK(remoteRelayStoragePoolEventRefresh),
-};
-
-verify(ARRAY_CARDINALITY(storageEventCallbacks) == VIR_STORAGE_POOL_EVENT_ID_LAST);
-
-static int
-remoteRelayNodeDeviceEventLifecycle(virConnectPtr conn,
- virNodeDevicePtr dev,
- int event,
- int detail,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_node_device_event_lifecycle_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayNodeDeviceEventCheckACL(callback->client, conn, dev))
- return -1;
-
- VIR_DEBUG("Relaying node device lifecycle event %d, detail %d, callback %d",
- event, detail, callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- make_nonnull_node_device(&data.dev, dev);
- data.callbackID = callback->callbackID;
- data.event = event;
- data.detail = detail;
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_NODE_DEVICE_EVENT_LIFECYCLE,
- (xdrproc_t)xdr_remote_node_device_event_lifecycle_msg,
- &data);
-
- return 0;
-}
-
-static int
-remoteRelayNodeDeviceEventUpdate(virConnectPtr conn,
- virNodeDevicePtr dev,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_node_device_event_update_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelayNodeDeviceEventCheckACL(callback->client, conn, dev))
- return -1;
-
- VIR_DEBUG("Relaying node device update event callback %d",
- callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- make_nonnull_node_device(&data.dev, dev);
- data.callbackID = callback->callbackID;
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_NODE_DEVICE_EVENT_UPDATE,
- (xdrproc_t)xdr_remote_node_device_event_update_msg,
- &data);
-
- return 0;
-}
-
-static virConnectNodeDeviceEventGenericCallback nodeDeviceEventCallbacks[] = {
- VIR_NODE_DEVICE_EVENT_CALLBACK(remoteRelayNodeDeviceEventLifecycle),
- VIR_NODE_DEVICE_EVENT_CALLBACK(remoteRelayNodeDeviceEventUpdate),
-};
-
-verify(ARRAY_CARDINALITY(nodeDeviceEventCallbacks) == VIR_NODE_DEVICE_EVENT_ID_LAST);
-
-static int
-remoteRelaySecretEventLifecycle(virConnectPtr conn,
- virSecretPtr secret,
- int event,
- int detail,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_secret_event_lifecycle_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelaySecretEventCheckACL(callback->client, conn, secret))
- return -1;
-
- VIR_DEBUG("Relaying node secretice lifecycle event %d, detail %d, callback %d",
- event, detail, callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- make_nonnull_secret(&data.secret, secret);
- data.callbackID = callback->callbackID;
- data.event = event;
- data.detail = detail;
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_SECRET_EVENT_LIFECYCLE,
- (xdrproc_t)xdr_remote_secret_event_lifecycle_msg,
- &data);
-
- return 0;
-}
-
-static int
-remoteRelaySecretEventValueChanged(virConnectPtr conn,
- virSecretPtr secret,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- remote_secret_event_value_changed_msg data;
-
- if (callback->callbackID < 0 ||
- !remoteRelaySecretEventCheckACL(callback->client, conn, secret))
- return -1;
-
- VIR_DEBUG("Relaying node secret value changed callback %d",
- callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- make_nonnull_secret(&data.secret, secret);
- data.callbackID = callback->callbackID;
-
- remoteDispatchObjectEventSend(callback->client, remoteProgram,
- REMOTE_PROC_SECRET_EVENT_VALUE_CHANGED,
- (xdrproc_t)xdr_remote_secret_event_value_changed_msg,
- &data);
-
- return 0;
-}
-
-static virConnectSecretEventGenericCallback secretEventCallbacks[] = {
- VIR_SECRET_EVENT_CALLBACK(remoteRelaySecretEventLifecycle),
- VIR_SECRET_EVENT_CALLBACK(remoteRelaySecretEventValueChanged),
-};
-
-verify(ARRAY_CARDINALITY(secretEventCallbacks) == VIR_SECRET_EVENT_ID_LAST);
-
-static void
-remoteRelayDomainQemuMonitorEvent(virConnectPtr conn,
- virDomainPtr dom,
- const char *event,
- long long seconds,
- unsigned int micros,
- const char *details,
- void *opaque)
-{
- daemonClientEventCallbackPtr callback = opaque;
- qemu_domain_monitor_event_msg data;
- char **details_p = NULL;
-
- if (callback->callbackID < 0 ||
- !remoteRelayDomainQemuMonitorEventCheckACL(callback->client, conn,
- dom))
- return;
-
- VIR_DEBUG("Relaying qemu monitor event %s %s, callback %d",
- event, details, callback->callbackID);
-
- /* build return data */
- memset(&data, 0, sizeof(data));
- data.callbackID = callback->callbackID;
- if (VIR_STRDUP(data.event, event) < 0)
- goto error;
- data.seconds = seconds;
- data.micros = micros;
- if (details &&
- ((VIR_ALLOC(details_p) < 0) ||
- VIR_STRDUP(*details_p, details) < 0))
- goto error;
- data.details = details_p;
- make_nonnull_domain(&data.dom, dom);
-
- remoteDispatchObjectEventSend(callback->client, qemuProgram,
- QEMU_PROC_DOMAIN_MONITOR_EVENT,
- (xdrproc_t)xdr_qemu_domain_monitor_event_msg,
- &data);
- return;
-
- error:
- VIR_FREE(data.event);
- VIR_FREE(details_p);
-}
-
-static
-void remoteRelayConnectionClosedEvent(virConnectPtr conn ATTRIBUTE_UNUSED, int reason, void *opaque)
-{
- virNetServerClientPtr client = opaque;
-
- VIR_DEBUG("Relaying connection closed event, reason %d", reason);
-
- remote_connect_event_connection_closed_msg msg = { reason };
- remoteDispatchObjectEventSend(client, remoteProgram,
- REMOTE_PROC_CONNECT_EVENT_CONNECTION_CLOSED,
- (xdrproc_t)xdr_remote_connect_event_connection_closed_msg,
- &msg);
-}
-
-#define DEREG_CB(conn, eventCallbacks, neventCallbacks, deregFcn, name) \
- do { \
- size_t i; \
- for (i = 0; i < neventCallbacks; i++) { \
- int callbackID = eventCallbacks[i]->callbackID; \
- if (callbackID < 0) { \
- VIR_WARN("unexpected incomplete %s callback %zu", name, i); \
- continue; \
- } \
- VIR_DEBUG("Deregistering remote %s event relay %d", \
- name, callbackID); \
- eventCallbacks[i]->callbackID = -1; \
- if (deregFcn(conn, callbackID) < 0) \
- VIR_WARN("unexpected %s event deregister failure", name); \
- } \
- VIR_FREE(eventCallbacks); \
- neventCallbacks = 0; \
- } while (0);
-
-
-static void
-remoteClientFreePrivateCallbacks(struct daemonClientPrivate *priv)
-{
- virIdentityPtr sysident = virIdentityGetSystem();
- virIdentitySetCurrent(sysident);
-
- DEREG_CB(priv->conn, priv->domainEventCallbacks,
- priv->ndomainEventCallbacks,
- virConnectDomainEventDeregisterAny, "domain");
- DEREG_CB(priv->conn, priv->networkEventCallbacks,
- priv->nnetworkEventCallbacks,
- virConnectNetworkEventDeregisterAny, "network");
- DEREG_CB(priv->conn, priv->storageEventCallbacks,
- priv->nstorageEventCallbacks,
- virConnectStoragePoolEventDeregisterAny, "storage");
- DEREG_CB(priv->conn, priv->nodeDeviceEventCallbacks,
- priv->nnodeDeviceEventCallbacks,
- virConnectNodeDeviceEventDeregisterAny, "node device");
- DEREG_CB(priv->conn, priv->secretEventCallbacks,
- priv->nsecretEventCallbacks,
- virConnectSecretEventDeregisterAny, "secret");
- DEREG_CB(priv->conn, priv->qemuEventCallbacks,
- priv->nqemuEventCallbacks,
- virConnectDomainQemuMonitorEventDeregister, "qemu monitor");
-
- if (priv->closeRegistered) {
- if (virConnectUnregisterCloseCallback(priv->conn,
- remoteRelayConnectionClosedEvent) < 0)
- VIR_WARN("unexpected close callback event deregister failure");
- }
-
- virIdentitySetCurrent(NULL);
- virObjectUnref(sysident);
-}
-#undef DEREG_CB
-
-
-/*
- * You must hold lock for at least the client
- * We don't free stuff here, merely disconnect the client's
- * network socket & resources.
- * We keep the libvirt connection open until any async
- * jobs have finished, then clean it up elsewhere
- */
-void remoteClientFree(void *data)
-{
- struct daemonClientPrivate *priv = data;
-
- if (priv->conn)
- virConnectClose(priv->conn);
-
- VIR_FREE(priv);
-}
-
-
-static void remoteClientCloseFunc(virNetServerClientPtr client)
-{
- struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
-
- daemonRemoveAllClientStreams(priv->streams);
-
- /* Deregister event delivery callback */
- if (priv->conn)
- remoteClientFreePrivateCallbacks(priv);
-}
-
-
-void *remoteClientNew(virNetServerClientPtr client,
- void *opaque ATTRIBUTE_UNUSED)
-{
- struct daemonClientPrivate *priv;
-
- if (VIR_ALLOC(priv) < 0)
- return NULL;
-
- if (virMutexInit(&priv->lock) < 0) {
- VIR_FREE(priv);
- virReportSystemError(errno, "%s", _("unable to init mutex"));
- return NULL;
- }
-
- virNetServerClientSetCloseHook(client, remoteClientCloseFunc);
- return priv;
-}
-
-/*----- Functions. -----*/
-
-static int
-remoteDispatchConnectOpen(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- struct remote_connect_open_args *args)
-{
- const char *name;
- unsigned int flags;
- struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
- int rv = -1;
-
- VIR_DEBUG("priv=%p conn=%p", priv, priv->conn);
- virMutexLock(&priv->lock);
- /* Already opened? */
- if (priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection already open"));
- goto cleanup;
- }
-
- name = args->name ? *args->name : NULL;
-
- /* If this connection arrived on a readonly socket, force
- * the connection to be readonly.
- */
- flags = args->flags;
- if (virNetServerClientGetReadonly(client))
- flags |= VIR_CONNECT_RO;
-
- priv->conn =
- flags & VIR_CONNECT_RO
- ? virConnectOpenReadOnly(name)
- : virConnectOpen(name);
-
- if (priv->conn == NULL)
- goto cleanup;
-
- /* force update the @readonly attribute which was inherited from the
- * virNetServerService object - this is important for sockets that are RW
- * by default, but do accept RO flags, e.g. TCP
- */
- virNetServerClientSetReadonly(client, (flags & VIR_CONNECT_RO));
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virMutexUnlock(&priv->lock);
- return rv;
-}
-
-
-static int
-remoteDispatchConnectClose(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED)
-{
- virNetServerClientDelayedClose(client);
- return 0;
-}
-
-
-static int
-remoteDispatchDomainGetSchedulerType(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_scheduler_type_args *args,
- remote_domain_get_scheduler_type_ret *ret)
-{
- virDomainPtr dom = NULL;
- char *type;
- int nparams;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (!(type = virDomainGetSchedulerType(dom, &nparams)))
- goto cleanup;
-
- ret->type = type;
- ret->nparams = nparams;
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- return rv;
-}
-
-static int
-remoteDispatchDomainGetSchedulerParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_scheduler_parameters_args *args,
- remote_domain_get_scheduler_parameters_ret *ret)
-{
- virDomainPtr dom = NULL;
- virTypedParameterPtr params = NULL;
- int nparams = 0;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (args->nparams > REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
- goto cleanup;
- }
- if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
- goto cleanup;
- nparams = args->nparams;
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (virDomainGetSchedulerParameters(dom, params, &nparams) < 0)
- goto cleanup;
-
- if (virTypedParamsSerialize(params, nparams,
- (virTypedParameterRemotePtr *) &ret->params.params_val,
- &ret->params.params_len,
- 0) < 0)
- goto cleanup;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virTypedParamsFree(params, nparams);
- virObjectUnref(dom);
- return rv;
-}
-
-static int
-remoteDispatchDomainGetSchedulerParametersFlags(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_scheduler_parameters_flags_args *args,
- remote_domain_get_scheduler_parameters_flags_ret *ret)
-{
- virDomainPtr dom = NULL;
- virTypedParameterPtr params = NULL;
- int nparams = 0;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (args->nparams > REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
- goto cleanup;
- }
- if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
- goto cleanup;
- nparams = args->nparams;
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (virDomainGetSchedulerParametersFlags(dom, params, &nparams,
- args->flags) < 0)
- goto cleanup;
-
- if (virTypedParamsSerialize(params, nparams,
- (virTypedParameterRemotePtr *) &ret->params.params_val,
- &ret->params.params_len,
- args->flags) < 0)
- goto cleanup;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virTypedParamsFree(params, nparams);
- virObjectUnref(dom);
- return rv;
-}
-
-static int
-remoteDispatchDomainMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_memory_stats_args *args,
- remote_domain_memory_stats_ret *ret)
-{
- virDomainPtr dom = NULL;
- virDomainMemoryStatPtr stats = NULL;
- int nr_stats;
- size_t i;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (args->maxStats > REMOTE_DOMAIN_MEMORY_STATS_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("maxStats > REMOTE_DOMAIN_MEMORY_STATS_MAX"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- /* Allocate stats array for making dispatch call */
- if (VIR_ALLOC_N(stats, args->maxStats) < 0)
- goto cleanup;
-
- nr_stats = virDomainMemoryStats(dom, stats, args->maxStats, args->flags);
- if (nr_stats < 0)
- goto cleanup;
-
- /* Allocate return buffer */
- if (VIR_ALLOC_N(ret->stats.stats_val, args->maxStats) < 0)
- goto cleanup;
-
- /* Copy the stats into the xdr return structure */
- for (i = 0; i < nr_stats; i++) {
- ret->stats.stats_val[i].tag = stats[i].tag;
- ret->stats.stats_val[i].val = stats[i].val;
- }
- ret->stats.stats_len = nr_stats;
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- VIR_FREE(stats);
- return rv;
-}
-
-static int
-remoteDispatchDomainBlockPeek(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_block_peek_args *args,
- remote_domain_block_peek_ret *ret)
-{
- virDomainPtr dom = NULL;
- char *path;
- unsigned long long offset;
- size_t size;
- unsigned int flags;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
- path = args->path;
- offset = args->offset;
- size = args->size;
- flags = args->flags;
-
- if (size > REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("size > maximum buffer size"));
- goto cleanup;
- }
-
- ret->buffer.buffer_len = size;
- if (VIR_ALLOC_N(ret->buffer.buffer_val, size) < 0)
- goto cleanup;
-
- if (virDomainBlockPeek(dom, path, offset, size,
- ret->buffer.buffer_val, flags) < 0)
- goto cleanup;
-
- rv = 0;
-
- cleanup:
- if (rv < 0) {
- virNetMessageSaveError(rerr);
- VIR_FREE(ret->buffer.buffer_val);
- }
- virObjectUnref(dom);
- return rv;
-}
-
-static int
-remoteDispatchDomainBlockStatsFlags(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_block_stats_flags_args *args,
- remote_domain_block_stats_flags_ret *ret)
-{
- virTypedParameterPtr params = NULL;
- virDomainPtr dom = NULL;
- const char *path = args->path;
- int nparams = 0;
- unsigned int flags;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
- flags = args->flags;
-
- if (args->nparams > REMOTE_DOMAIN_BLOCK_STATS_PARAMETERS_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
- goto cleanup;
- }
- if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
- goto cleanup;
- nparams = args->nparams;
-
- if (virDomainBlockStatsFlags(dom, path, params, &nparams, flags) < 0)
- goto cleanup;
-
- /* In this case, we need to send back the number of parameters
- * supported
- */
- if (args->nparams == 0) {
- ret->nparams = nparams;
- goto success;
- }
-
- /* Serialize the block stats. */
- if (virTypedParamsSerialize(params, nparams,
- (virTypedParameterRemotePtr *) &ret->params.params_val,
- &ret->params.params_len,
- args->flags) < 0)
- goto cleanup;
-
- success:
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virTypedParamsFree(params, nparams);
- virObjectUnref(dom);
- return rv;
-}
-
-static int
-remoteDispatchDomainMemoryPeek(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_memory_peek_args *args,
- remote_domain_memory_peek_ret *ret)
-{
- virDomainPtr dom = NULL;
- unsigned long long offset;
- size_t size;
- unsigned int flags;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
- offset = args->offset;
- size = args->size;
- flags = args->flags;
-
- if (size > REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("size > maximum buffer size"));
- goto cleanup;
- }
-
- ret->buffer.buffer_len = size;
- if (VIR_ALLOC_N(ret->buffer.buffer_val, size) < 0)
- goto cleanup;
-
- if (virDomainMemoryPeek(dom, offset, size,
- ret->buffer.buffer_val, flags) < 0)
- goto cleanup;
-
- rv = 0;
-
- cleanup:
- if (rv < 0) {
- virNetMessageSaveError(rerr);
- VIR_FREE(ret->buffer.buffer_val);
- }
- virObjectUnref(dom);
- return rv;
-}
-
-static int
-remoteDispatchDomainGetSecurityLabel(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_security_label_args *args,
- remote_domain_get_security_label_ret *ret)
-{
- virDomainPtr dom = NULL;
- virSecurityLabelPtr seclabel = NULL;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (VIR_ALLOC(seclabel) < 0)
- goto cleanup;
-
- if (virDomainGetSecurityLabel(dom, seclabel) < 0)
- goto cleanup;
-
- ret->label.label_len = strlen(seclabel->label) + 1;
- if (VIR_ALLOC_N(ret->label.label_val, ret->label.label_len) < 0)
- goto cleanup;
- strcpy(ret->label.label_val, seclabel->label);
- ret->enforcing = seclabel->enforcing;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- VIR_FREE(seclabel);
- return rv;
-}
-
-static int
-remoteDispatchDomainGetSecurityLabelList(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_security_label_list_args *args,
- remote_domain_get_security_label_list_ret *ret)
-{
- virDomainPtr dom = NULL;
- virSecurityLabelPtr seclabels = NULL;
- int len, rv = -1;
- size_t i;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if ((len = virDomainGetSecurityLabelList(dom, &seclabels)) < 0) {
- ret->ret = len;
- ret->labels.labels_len = 0;
- ret->labels.labels_val = NULL;
- goto done;
- }
-
- if (VIR_ALLOC_N(ret->labels.labels_val, len) < 0)
- goto cleanup;
-
- for (i = 0; i < len; i++) {
- size_t label_len = strlen(seclabels[i].label) + 1;
- remote_domain_get_security_label_ret *cur = &ret->labels.labels_val[i];
- if (VIR_ALLOC_N(cur->label.label_val, label_len) < 0)
- goto cleanup;
- if (virStrcpy(cur->label.label_val, seclabels[i].label, label_len) == NULL) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("failed to copy security label"));
- goto cleanup;
- }
- cur->label.label_len = label_len;
- cur->enforcing = seclabels[i].enforcing;
- }
- ret->labels.labels_len = ret->ret = len;
-
- done:
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- VIR_FREE(seclabels);
- return rv;
-}
-
-static int
-remoteDispatchNodeGetSecurityModel(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_node_get_security_model_ret *ret)
-{
- virSecurityModel secmodel;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- memset(&secmodel, 0, sizeof(secmodel));
- if (virNodeGetSecurityModel(priv->conn, &secmodel) < 0)
- goto cleanup;
-
- ret->model.model_len = strlen(secmodel.model) + 1;
- if (VIR_ALLOC_N(ret->model.model_val, ret->model.model_len) < 0)
- goto cleanup;
- strcpy(ret->model.model_val, secmodel.model);
-
- ret->doi.doi_len = strlen(secmodel.doi) + 1;
- if (VIR_ALLOC_N(ret->doi.doi_val, ret->doi.doi_len) < 0)
- goto cleanup;
- strcpy(ret->doi.doi_val, secmodel.doi);
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- return rv;
-}
-
-static int
-remoteDispatchDomainGetVcpuPinInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_vcpu_pin_info_args *args,
- remote_domain_get_vcpu_pin_info_ret *ret)
-{
- virDomainPtr dom = NULL;
- unsigned char *cpumaps = NULL;
- int num;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (args->ncpumaps > REMOTE_VCPUINFO_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("ncpumaps > REMOTE_VCPUINFO_MAX"));
- goto cleanup;
- }
-
- if (INT_MULTIPLY_OVERFLOW(args->ncpumaps, args->maplen) ||
- args->ncpumaps * args->maplen > REMOTE_CPUMAPS_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maxinfo * maplen > REMOTE_CPUMAPS_MAX"));
- goto cleanup;
- }
-
- /* Allocate buffers to take the results. */
- if (args->maplen > 0 &&
- VIR_ALLOC_N(cpumaps, args->ncpumaps * args->maplen) < 0)
- goto cleanup;
-
- if ((num = virDomainGetVcpuPinInfo(dom,
- args->ncpumaps,
- cpumaps,
- args->maplen,
- args->flags)) < 0)
- goto cleanup;
-
- ret->num = num;
- /* Don't need to allocate/copy the cpumaps if we make the reasonable
- * assumption that unsigned char and char are the same size.
- * Note that remoteDispatchClientRequest will free.
- */
- ret->cpumaps.cpumaps_len = args->ncpumaps * args->maplen;
- ret->cpumaps.cpumaps_val = (char *) cpumaps;
- cpumaps = NULL;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- VIR_FREE(cpumaps);
- virObjectUnref(dom);
- return rv;
-}
-
-static int
-remoteDispatchDomainPinEmulator(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_pin_emulator_args *args)
-{
- int rv = -1;
- virDomainPtr dom = NULL;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (virDomainPinEmulator(dom,
- (unsigned char *) args->cpumap.cpumap_val,
- args->cpumap.cpumap_len,
- args->flags) < 0)
- goto cleanup;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- return rv;
-}
-
-
-static int
-remoteDispatchDomainGetEmulatorPinInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_emulator_pin_info_args *args,
- remote_domain_get_emulator_pin_info_ret *ret)
-{
- virDomainPtr dom = NULL;
- unsigned char *cpumaps = NULL;
- int r;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- /* Allocate buffers to take the results */
- if (args->maplen > 0 &&
- VIR_ALLOC_N(cpumaps, args->maplen) < 0)
- goto cleanup;
-
- if ((r = virDomainGetEmulatorPinInfo(dom,
- cpumaps,
- args->maplen,
- args->flags)) < 0)
- goto cleanup;
-
- ret->ret = r;
- ret->cpumaps.cpumaps_len = args->maplen;
- ret->cpumaps.cpumaps_val = (char *) cpumaps;
- cpumaps = NULL;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- VIR_FREE(cpumaps);
- virObjectUnref(dom);
- return rv;
-}
-
-static int
-remoteDispatchDomainGetVcpus(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_vcpus_args *args,
- remote_domain_get_vcpus_ret *ret)
-{
- virDomainPtr dom = NULL;
- virVcpuInfoPtr info = NULL;
- unsigned char *cpumaps = NULL;
- int info_len;
- size_t i;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (args->maxinfo > REMOTE_VCPUINFO_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maxinfo > REMOTE_VCPUINFO_MAX"));
- goto cleanup;
- }
-
- if (INT_MULTIPLY_OVERFLOW(args->maxinfo, args->maplen) ||
- args->maxinfo * args->maplen > REMOTE_CPUMAPS_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maxinfo * maplen > REMOTE_CPUMAPS_MAX"));
- goto cleanup;
- }
-
- /* Allocate buffers to take the results. */
- if (VIR_ALLOC_N(info, args->maxinfo) < 0)
- goto cleanup;
- if (args->maplen > 0 &&
- VIR_ALLOC_N(cpumaps, args->maxinfo * args->maplen) < 0)
- goto cleanup;
-
- if ((info_len = virDomainGetVcpus(dom,
- info, args->maxinfo,
- cpumaps, args->maplen)) < 0)
- goto cleanup;
-
- /* Allocate the return buffer for info. */
- ret->info.info_len = info_len;
- if (VIR_ALLOC_N(ret->info.info_val, info_len) < 0)
- goto cleanup;
-
- for (i = 0; i < info_len; ++i) {
- ret->info.info_val[i].number = info[i].number;
- ret->info.info_val[i].state = info[i].state;
- ret->info.info_val[i].cpu_time = info[i].cpuTime;
- ret->info.info_val[i].cpu = info[i].cpu;
- }
-
- /* Don't need to allocate/copy the cpumaps if we make the reasonable
- * assumption that unsigned char and char are the same size.
- * Note that remoteDispatchClientRequest will free.
- */
- ret->cpumaps.cpumaps_len = args->maxinfo * args->maplen;
- ret->cpumaps.cpumaps_val = (char *) cpumaps;
- cpumaps = NULL;
-
- rv = 0;
-
- cleanup:
- if (rv < 0) {
- virNetMessageSaveError(rerr);
- VIR_FREE(ret->info.info_val);
- }
- VIR_FREE(cpumaps);
- VIR_FREE(info);
- virObjectUnref(dom);
- return rv;
-}
-
-static int
-remoteDispatchDomainGetIOThreadInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_iothread_info_args *args,
- remote_domain_get_iothread_info_ret *ret)
-{
- int rv = -1;
- size_t i;
- struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
- virDomainIOThreadInfoPtr *info = NULL;
- virDomainPtr dom = NULL;
- remote_domain_iothread_info *dst;
- int ninfo = 0;
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if ((ninfo = virDomainGetIOThreadInfo(dom, &info, args->flags)) < 0)
- goto cleanup;
-
- if (ninfo > REMOTE_IOTHREAD_INFO_MAX) {
- virReportError(VIR_ERR_RPC,
- _("Too many IOThreads in info: %d for limit %d"),
- ninfo, REMOTE_IOTHREAD_INFO_MAX);
- goto cleanup;
- }
-
- if (ninfo) {
- if (VIR_ALLOC_N(ret->info.info_val, ninfo) < 0)
- goto cleanup;
-
- ret->info.info_len = ninfo;
-
- for (i = 0; i < ninfo; i++) {
- dst = &ret->info.info_val[i];
- dst->iothread_id = info[i]->iothread_id;
-
- /* No need to allocate/copy the cpumap if we make the reasonable
- * assumption that unsigned char and char are the same size.
- */
- dst->cpumap.cpumap_len = info[i]->cpumaplen;
- dst->cpumap.cpumap_val = (char *)info[i]->cpumap;
- info[i]->cpumap = NULL;
- }
- } else {
- ret->info.info_len = 0;
- ret->info.info_val = NULL;
- }
-
- ret->ret = ninfo;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- if (ninfo >= 0)
- for (i = 0; i < ninfo; i++)
- virDomainIOThreadInfoFree(info[i]);
- VIR_FREE(info);
-
- return rv;
-}
-
-static int
-remoteDispatchDomainMigratePrepare(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_migrate_prepare_args *args,
- remote_domain_migrate_prepare_ret *ret)
-{
- char *cookie = NULL;
- int cookielen = 0;
- char *uri_in;
- char **uri_out;
- char *dname;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- uri_in = args->uri_in == NULL ? NULL : *args->uri_in;
- dname = args->dname == NULL ? NULL : *args->dname;
-
- /* Wacky world of XDR ... */
- if (VIR_ALLOC(uri_out) < 0)
- goto cleanup;
-
- if (virDomainMigratePrepare(priv->conn, &cookie, &cookielen,
- uri_in, uri_out,
- args->flags, dname, args->resource) < 0)
- goto cleanup;
-
- /* remoteDispatchClientRequest will free cookie, uri_out and
- * the string if there is one.
- */
- ret->cookie.cookie_len = cookielen;
- ret->cookie.cookie_val = cookie;
- if (*uri_out == NULL) {
- ret->uri_out = NULL;
- } else {
- ret->uri_out = uri_out;
- uri_out = NULL;
- }
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- VIR_FREE(uri_out);
- return rv;
-}
-
-static int
-remoteDispatchDomainMigratePrepare2(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_migrate_prepare2_args *args,
- remote_domain_migrate_prepare2_ret *ret)
-{
- char *cookie = NULL;
- int cookielen = 0;
- char *uri_in;
- char **uri_out;
- char *dname;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- uri_in = args->uri_in == NULL ? NULL : *args->uri_in;
- dname = args->dname == NULL ? NULL : *args->dname;
-
- /* Wacky world of XDR ... */
- if (VIR_ALLOC(uri_out) < 0)
- goto cleanup;
-
- if (virDomainMigratePrepare2(priv->conn, &cookie, &cookielen,
- uri_in, uri_out,
- args->flags, dname, args->resource,
- args->dom_xml) < 0)
- goto cleanup;
-
- /* remoteDispatchClientRequest will free cookie, uri_out and
- * the string if there is one.
- */
- ret->cookie.cookie_len = cookielen;
- ret->cookie.cookie_val = cookie;
- ret->uri_out = *uri_out == NULL ? NULL : uri_out;
-
- rv = 0;
-
- cleanup:
- if (rv < 0) {
- virNetMessageSaveError(rerr);
- VIR_FREE(uri_out);
- }
- return rv;
-}
-
-static int
-remoteDispatchDomainGetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_memory_parameters_args *args,
- remote_domain_get_memory_parameters_ret *ret)
-{
- virDomainPtr dom = NULL;
- virTypedParameterPtr params = NULL;
- int nparams = 0;
- unsigned int flags;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- flags = args->flags;
-
- if (args->nparams > REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
- goto cleanup;
- }
- if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
- goto cleanup;
- nparams = args->nparams;
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (virDomainGetMemoryParameters(dom, params, &nparams, flags) < 0)
- goto cleanup;
-
- /* In this case, we need to send back the number of parameters
- * supported
- */
- if (args->nparams == 0) {
- ret->nparams = nparams;
- goto success;
- }
-
- if (virTypedParamsSerialize(params, nparams,
- (virTypedParameterRemotePtr *) &ret->params.params_val,
- &ret->params.params_len,
- args->flags) < 0)
- goto cleanup;
-
- success:
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virTypedParamsFree(params, nparams);
- virObjectUnref(dom);
- return rv;
-}
-
-static int
-remoteDispatchDomainGetNumaParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_numa_parameters_args *args,
- remote_domain_get_numa_parameters_ret *ret)
-{
- virDomainPtr dom = NULL;
- virTypedParameterPtr params = NULL;
- int nparams = 0;
- unsigned int flags;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- flags = args->flags;
-
- if (args->nparams > REMOTE_DOMAIN_NUMA_PARAMETERS_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
- goto cleanup;
- }
- if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
- goto cleanup;
- nparams = args->nparams;
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (virDomainGetNumaParameters(dom, params, &nparams, flags) < 0)
- goto cleanup;
-
- /* In this case, we need to send back the number of parameters
- * supported
- */
- if (args->nparams == 0) {
- ret->nparams = nparams;
- goto success;
- }
-
- if (virTypedParamsSerialize(params, nparams,
- (virTypedParameterRemotePtr *) &ret->params.params_val,
- &ret->params.params_len,
- flags) < 0)
- goto cleanup;
-
- success:
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virTypedParamsFree(params, nparams);
- virObjectUnref(dom);
- return rv;
-}
-
-static int
-remoteDispatchDomainGetBlkioParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_blkio_parameters_args *args,
- remote_domain_get_blkio_parameters_ret *ret)
-{
- virDomainPtr dom = NULL;
- virTypedParameterPtr params = NULL;
- int nparams = 0;
- unsigned int flags;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- flags = args->flags;
-
- if (args->nparams > REMOTE_DOMAIN_BLKIO_PARAMETERS_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
- goto cleanup;
- }
- if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
- goto cleanup;
- nparams = args->nparams;
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (virDomainGetBlkioParameters(dom, params, &nparams, flags) < 0)
- goto cleanup;
-
- /* In this case, we need to send back the number of parameters
- * supported
- */
- if (args->nparams == 0) {
- ret->nparams = nparams;
- goto success;
- }
-
- if (virTypedParamsSerialize(params, nparams,
- (virTypedParameterRemotePtr *) &ret->params.params_val,
- &ret->params.params_len,
- args->flags) < 0)
- goto cleanup;
-
- success:
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virTypedParamsFree(params, nparams);
- virObjectUnref(dom);
- return rv;
-}
-
-static int
-remoteDispatchNodeGetCPUStats(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_node_get_cpu_stats_args *args,
- remote_node_get_cpu_stats_ret *ret)
-{
- virNodeCPUStatsPtr params = NULL;
- size_t i;
- int cpuNum = args->cpuNum;
- int nparams = 0;
- unsigned int flags;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- flags = args->flags;
-
- if (args->nparams > REMOTE_NODE_CPU_STATS_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
- goto cleanup;
- }
- if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
- goto cleanup;
- nparams = args->nparams;
-
- if (virNodeGetCPUStats(priv->conn, cpuNum, params, &nparams, flags) < 0)
- goto cleanup;
-
- /* In this case, we need to send back the number of stats
- * supported
- */
- if (args->nparams == 0) {
- ret->nparams = nparams;
- goto success;
- }
-
- /* Serialise the memory parameters. */
- ret->params.params_len = nparams;
- if (VIR_ALLOC_N(ret->params.params_val, nparams) < 0)
- goto cleanup;
-
- for (i = 0; i < nparams; ++i) {
- /* remoteDispatchClientRequest will free this: */
- if (VIR_STRDUP(ret->params.params_val[i].field, params[i].field) < 0)
- goto cleanup;
-
- ret->params.params_val[i].value = params[i].value;
- }
-
- success:
- rv = 0;
-
- cleanup:
- if (rv < 0) {
- virNetMessageSaveError(rerr);
- if (ret->params.params_val) {
- for (i = 0; i < nparams; i++)
- VIR_FREE(ret->params.params_val[i].field);
- VIR_FREE(ret->params.params_val);
- }
- }
- VIR_FREE(params);
- return rv;
-}
-
-static int
-remoteDispatchNodeGetMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_node_get_memory_stats_args *args,
- remote_node_get_memory_stats_ret *ret)
-{
- virNodeMemoryStatsPtr params = NULL;
- size_t i;
- int cellNum = args->cellNum;
- int nparams = 0;
- unsigned int flags;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- flags = args->flags;
-
- if (args->nparams > REMOTE_NODE_MEMORY_STATS_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
- goto cleanup;
- }
- if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
- goto cleanup;
- nparams = args->nparams;
-
- if (virNodeGetMemoryStats(priv->conn, cellNum, params, &nparams, flags) < 0)
- goto cleanup;
-
- /* In this case, we need to send back the number of parameters
- * supported
- */
- if (args->nparams == 0) {
- ret->nparams = nparams;
- goto success;
- }
-
- /* Serialise the memory parameters. */
- ret->params.params_len = nparams;
- if (VIR_ALLOC_N(ret->params.params_val, nparams) < 0)
- goto cleanup;
-
- for (i = 0; i < nparams; ++i) {
- /* remoteDispatchClientRequest will free this: */
- if (VIR_STRDUP(ret->params.params_val[i].field, params[i].field) < 0)
- goto cleanup;
-
- ret->params.params_val[i].value = params[i].value;
- }
-
- success:
- rv = 0;
-
- cleanup:
- if (rv < 0) {
- virNetMessageSaveError(rerr);
- if (ret->params.params_val) {
- for (i = 0; i < nparams; i++)
- VIR_FREE(ret->params.params_val[i].field);
- VIR_FREE(ret->params.params_val);
- }
- }
- VIR_FREE(params);
- return rv;
-}
-
-static int
-remoteDispatchDomainGetPerfEvents(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_perf_events_args *args,
- remote_domain_get_perf_events_ret *ret)
-{
- virDomainPtr dom = NULL;
- virTypedParameterPtr params = NULL;
- int nparams = 0;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (virDomainGetPerfEvents(dom, ¶ms, &nparams, args->flags) < 0)
- goto cleanup;
-
- if (nparams > REMOTE_DOMAIN_PERF_EVENTS_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
- goto cleanup;
- }
-
- if (virTypedParamsSerialize(params, nparams,
- (virTypedParameterRemotePtr *) &ret->params.params_val,
- &ret->params.params_len,
- 0) < 0)
- goto cleanup;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virTypedParamsFree(params, nparams);
- virObjectUnref(dom);
- return rv;
-}
-
-static int
-remoteDispatchDomainGetBlockJobInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_block_job_info_args *args,
- remote_domain_get_block_job_info_ret *ret)
-{
- virDomainPtr dom = NULL;
- virDomainBlockJobInfo tmp;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- rv = virDomainGetBlockJobInfo(dom, args->path, &tmp, args->flags);
- if (rv <= 0)
- goto cleanup;
-
- ret->type = tmp.type;
- ret->bandwidth = tmp.bandwidth;
- ret->cur = tmp.cur;
- ret->end = tmp.end;
- ret->found = 1;
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- return rv;
-}
-
-static int
-remoteDispatchDomainGetBlockIoTune(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr hdr ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_block_io_tune_args *args,
- remote_domain_get_block_io_tune_ret *ret)
-{
- virDomainPtr dom = NULL;
- int rv = -1;
- virTypedParameterPtr params = NULL;
- int nparams = 0;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (args->nparams > REMOTE_DOMAIN_BLOCK_IO_TUNE_PARAMETERS_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
- goto cleanup;
- }
-
- if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
- goto cleanup;
- nparams = args->nparams;
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (virDomainGetBlockIoTune(dom, args->disk ? *args->disk : NULL,
- params, &nparams, args->flags) < 0)
- goto cleanup;
-
- /* In this case, we need to send back the number of parameters
- * supported
- */
- if (args->nparams == 0) {
- ret->nparams = nparams;
- goto success;
- }
-
- /* Serialize the block I/O tuning parameters. */
- if (virTypedParamsSerialize(params, nparams,
- (virTypedParameterRemotePtr *) &ret->params.params_val,
- &ret->params.params_len,
- args->flags) < 0)
- goto cleanup;
-
- success:
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virTypedParamsFree(params, nparams);
- virObjectUnref(dom);
- return rv;
-}
-
-/*-------------------------------------------------------------*/
-
-static int
-remoteDispatchAuthList(virNetServerPtr server,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_auth_list_ret *ret)
-{
- int rv = -1;
- int auth = virNetServerClientGetAuth(client);
- uid_t callerUid;
- gid_t callerGid;
- pid_t callerPid;
- unsigned long long timestamp;
-
- /* If the client is root then we want to bypass the
- * policykit auth to avoid root being denied if
- * some piece of polkit isn't present/running
- */
- if (auth == VIR_NET_SERVER_SERVICE_AUTH_POLKIT) {
- if (virNetServerClientGetUNIXIdentity(client, &callerUid, &callerGid,
- &callerPid, ×tamp) < 0) {
- /* Don't do anything on error - it'll be validated at next
- * phase of auth anyway */
- virResetLastError();
- } else if (callerUid == 0) {
- char *ident;
- if (virAsprintf(&ident, "pid:%lld,uid:%d",
- (long long) callerPid, (int) callerUid) < 0)
- goto cleanup;
- VIR_INFO("Bypass polkit auth for privileged client %s", ident);
- virNetServerSetClientAuthenticated(server, client);
- auth = VIR_NET_SERVER_SERVICE_AUTH_NONE;
- VIR_FREE(ident);
- }
- }
-
- ret->types.types_len = 1;
- if (VIR_ALLOC_N(ret->types.types_val, ret->types.types_len) < 0)
- goto cleanup;
-
- switch ((virNetServerServiceAuthMethods) auth) {
- case VIR_NET_SERVER_SERVICE_AUTH_NONE:
- ret->types.types_val[0] = REMOTE_AUTH_NONE;
- break;
- case VIR_NET_SERVER_SERVICE_AUTH_POLKIT:
- ret->types.types_val[0] = REMOTE_AUTH_POLKIT;
- break;
- case VIR_NET_SERVER_SERVICE_AUTH_SASL:
- ret->types.types_val[0] = REMOTE_AUTH_SASL;
- break;
- }
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- return rv;
-}
-
-
-#ifdef WITH_SASL
-/*
- * Initializes the SASL session in prepare for authentication
- * and gives the client a list of allowed mechanisms to choose
- */
-static int
-remoteDispatchAuthSaslInit(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_auth_sasl_init_ret *ret)
-{
- virNetSASLSessionPtr sasl = NULL;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- virMutexLock(&priv->lock);
-
- VIR_DEBUG("Initialize SASL auth %d", virNetServerClientGetFD(client));
- if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL ||
- priv->sasl != NULL) {
- VIR_ERROR(_("client tried invalid SASL init request"));
- goto authfail;
- }
-
- sasl = virNetSASLSessionNewServer(saslCtxt,
- "libvirt",
- virNetServerClientLocalAddrStringSASL(client),
- virNetServerClientRemoteAddrStringSASL(client));
- if (!sasl)
- goto authfail;
-
-# if WITH_GNUTLS
- /* Inform SASL that we've got an external SSF layer from TLS */
- if (virNetServerClientHasTLSSession(client)) {
- int ssf;
-
- if ((ssf = virNetServerClientGetTLSKeySize(client)) < 0)
- goto authfail;
-
- ssf *= 8; /* key size is bytes, sasl wants bits */
-
- VIR_DEBUG("Setting external SSF %d", ssf);
- if (virNetSASLSessionExtKeySize(sasl, ssf) < 0)
- goto authfail;
- }
-# endif
-
- if (virNetServerClientIsSecure(client))
- /* If we've got TLS or UNIX domain sock, we don't care about SSF */
- virNetSASLSessionSecProps(sasl, 0, 0, true);
- else
- /* Plain TCP, better get an SSF layer */
- virNetSASLSessionSecProps(sasl,
- 56, /* Good enough to require kerberos */
- 100000, /* Arbitrary big number */
- false); /* No anonymous */
-
- if (!(ret->mechlist = virNetSASLSessionListMechanisms(sasl)))
- goto authfail;
- VIR_DEBUG("Available mechanisms for client: '%s'", ret->mechlist);
-
- priv->sasl = sasl;
- virMutexUnlock(&priv->lock);
- return 0;
-
- authfail:
- virResetLastError();
- virReportError(VIR_ERR_AUTH_FAILED, "%s",
- _("authentication failed"));
- virNetMessageSaveError(rerr);
- PROBE(RPC_SERVER_CLIENT_AUTH_FAIL,
- "client=%p auth=%d",
- client, REMOTE_AUTH_SASL);
- virObjectUnref(sasl);
- virMutexUnlock(&priv->lock);
- return -1;
-}
-
-/*
- * Returns 0 if ok, -1 on error, -2 if rejected
- */
-static int
-remoteSASLFinish(virNetServerPtr server,
- virNetServerClientPtr client)
-{
- virIdentityPtr clnt_identity = NULL;
- const char *identity;
- struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
- int ssf;
-
- /* TLS or UNIX domain sockets trivially OK */
- if (!virNetServerClientIsSecure(client)) {
- if ((ssf = virNetSASLSessionGetKeySize(priv->sasl)) < 0)
- goto error;
-
- VIR_DEBUG("negotiated an SSF of %d", ssf);
- if (ssf < 56) { /* 56 is good for Kerberos */
- VIR_ERROR(_("negotiated SSF %d was not strong enough"), ssf);
- return -2;
- }
- }
-
- if (!(identity = virNetSASLSessionGetIdentity(priv->sasl)))
- return -2;
-
- if (!virNetSASLContextCheckIdentity(saslCtxt, identity))
- return -2;
-
- if (!(clnt_identity = virNetServerClientGetIdentity(client)))
- goto error;
-
- virNetServerSetClientAuthenticated(server, client);
- virNetServerClientSetSASLSession(client, priv->sasl);
- virIdentitySetSASLUserName(clnt_identity, identity);
-
- VIR_DEBUG("Authentication successful %d", virNetServerClientGetFD(client));
-
- PROBE(RPC_SERVER_CLIENT_AUTH_ALLOW,
- "client=%p auth=%d identity=%s",
- client, REMOTE_AUTH_SASL, identity);
-
- virObjectUnref(clnt_identity);
- virObjectUnref(priv->sasl);
- priv->sasl = NULL;
-
- return 0;
-
- error:
- return -1;
-}
-
-/*
- * This starts the SASL authentication negotiation.
- */
-static int
-remoteDispatchAuthSaslStart(virNetServerPtr server,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_auth_sasl_start_args *args,
- remote_auth_sasl_start_ret *ret)
-{
- const char *serverout;
- size_t serveroutlen;
- int err;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
- const char *identity;
-
- virMutexLock(&priv->lock);
-
- VIR_DEBUG("Start SASL auth %d", virNetServerClientGetFD(client));
- if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL ||
- priv->sasl == NULL) {
- VIR_ERROR(_("client tried invalid SASL start request"));
- goto authfail;
- }
-
- VIR_DEBUG("Using SASL mechanism %s. Data %d bytes, nil: %d",
- args->mech, args->data.data_len, args->nil);
- err = virNetSASLSessionServerStart(priv->sasl,
- args->mech,
- /* NB, distinction of NULL vs "" is *critical* in SASL */
- args->nil ? NULL : args->data.data_val,
- args->data.data_len,
- &serverout,
- &serveroutlen);
- if (err != VIR_NET_SASL_COMPLETE &&
- err != VIR_NET_SASL_CONTINUE)
- goto authfail;
-
- if (serveroutlen > REMOTE_AUTH_SASL_DATA_MAX) {
- VIR_ERROR(_("sasl start reply data too long %d"), (int)serveroutlen);
- goto authfail;
- }
-
- /* NB, distinction of NULL vs "" is *critical* in SASL */
- if (serverout) {
- if (VIR_ALLOC_N(ret->data.data_val, serveroutlen) < 0)
- goto authfail;
- memcpy(ret->data.data_val, serverout, serveroutlen);
- } else {
- ret->data.data_val = NULL;
- }
- ret->nil = serverout ? 0 : 1;
- ret->data.data_len = serveroutlen;
-
- VIR_DEBUG("SASL return data %d bytes, nil; %d", ret->data.data_len, ret->nil);
- if (err == VIR_NET_SASL_CONTINUE) {
- ret->complete = 0;
- } else {
- /* Check username whitelist ACL */
- if ((err = remoteSASLFinish(server, client)) < 0) {
- if (err == -2)
- goto authdeny;
- else
- goto authfail;
- }
-
- ret->complete = 1;
- }
-
- virMutexUnlock(&priv->lock);
- return 0;
-
- authfail:
- PROBE(RPC_SERVER_CLIENT_AUTH_FAIL,
- "client=%p auth=%d",
- client, REMOTE_AUTH_SASL);
- goto error;
-
- authdeny:
- identity = virNetSASLSessionGetIdentity(priv->sasl);
- PROBE(RPC_SERVER_CLIENT_AUTH_DENY,
- "client=%p auth=%d identity=%s",
- client, REMOTE_AUTH_SASL, identity);
- goto error;
-
- error:
- virObjectUnref(priv->sasl);
- priv->sasl = NULL;
- virResetLastError();
- virReportError(VIR_ERR_AUTH_FAILED, "%s",
- _("authentication failed"));
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virMutexUnlock(&priv->lock);
- return -1;
-}
-
-
-static int
-remoteDispatchAuthSaslStep(virNetServerPtr server,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_auth_sasl_step_args *args,
- remote_auth_sasl_step_ret *ret)
-{
- const char *serverout;
- size_t serveroutlen;
- int err;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
- const char *identity;
-
- virMutexLock(&priv->lock);
-
- VIR_DEBUG("Step SASL auth %d", virNetServerClientGetFD(client));
- if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL ||
- priv->sasl == NULL) {
- VIR_ERROR(_("client tried invalid SASL start request"));
- goto authfail;
- }
-
- VIR_DEBUG("Step using SASL Data %d bytes, nil: %d",
- args->data.data_len, args->nil);
- err = virNetSASLSessionServerStep(priv->sasl,
- /* NB, distinction of NULL vs "" is *critical* in SASL */
- args->nil ? NULL : args->data.data_val,
- args->data.data_len,
- &serverout,
- &serveroutlen);
- if (err != VIR_NET_SASL_COMPLETE &&
- err != VIR_NET_SASL_CONTINUE)
- goto authfail;
-
- if (serveroutlen > REMOTE_AUTH_SASL_DATA_MAX) {
- VIR_ERROR(_("sasl step reply data too long %d"),
- (int)serveroutlen);
- goto authfail;
- }
-
- /* NB, distinction of NULL vs "" is *critical* in SASL */
- if (serverout) {
- if (VIR_ALLOC_N(ret->data.data_val, serveroutlen) < 0)
- goto authfail;
- memcpy(ret->data.data_val, serverout, serveroutlen);
- } else {
- ret->data.data_val = NULL;
- }
- ret->nil = serverout ? 0 : 1;
- ret->data.data_len = serveroutlen;
-
- VIR_DEBUG("SASL return data %d bytes, nil; %d", ret->data.data_len, ret->nil);
- if (err == VIR_NET_SASL_CONTINUE) {
- ret->complete = 0;
- } else {
- /* Check username whitelist ACL */
- if ((err = remoteSASLFinish(server, client)) < 0) {
- if (err == -2)
- goto authdeny;
- else
- goto authfail;
- }
-
- ret->complete = 1;
- }
-
- virMutexUnlock(&priv->lock);
- return 0;
-
- authfail:
- PROBE(RPC_SERVER_CLIENT_AUTH_FAIL,
- "client=%p auth=%d",
- client, REMOTE_AUTH_SASL);
- goto error;
-
- authdeny:
- identity = virNetSASLSessionGetIdentity(priv->sasl);
- PROBE(RPC_SERVER_CLIENT_AUTH_DENY,
- "client=%p auth=%d identity=%s",
- client, REMOTE_AUTH_SASL, identity);
- goto error;
-
- error:
- virObjectUnref(priv->sasl);
- priv->sasl = NULL;
- virResetLastError();
- virReportError(VIR_ERR_AUTH_FAILED, "%s",
- _("authentication failed"));
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virMutexUnlock(&priv->lock);
- return -1;
-}
-#else
-static int
-remoteDispatchAuthSaslInit(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_auth_sasl_init_ret *ret ATTRIBUTE_UNUSED)
-{
- VIR_WARN("Client tried unsupported SASL auth");
- virReportError(VIR_ERR_AUTH_FAILED, "%s",
- _("authentication failed"));
- virNetMessageSaveError(rerr);
- return -1;
-}
-static int
-remoteDispatchAuthSaslStart(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_auth_sasl_start_args *args ATTRIBUTE_UNUSED,
- remote_auth_sasl_start_ret *ret ATTRIBUTE_UNUSED)
-{
- VIR_WARN("Client tried unsupported SASL auth");
- virReportError(VIR_ERR_AUTH_FAILED, "%s",
- _("authentication failed"));
- virNetMessageSaveError(rerr);
- return -1;
-}
-static int
-remoteDispatchAuthSaslStep(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_auth_sasl_step_args *args ATTRIBUTE_UNUSED,
- remote_auth_sasl_step_ret *ret ATTRIBUTE_UNUSED)
-{
- VIR_WARN("Client tried unsupported SASL auth");
- virReportError(VIR_ERR_AUTH_FAILED, "%s",
- _("authentication failed"));
- virNetMessageSaveError(rerr);
- return -1;
-}
-#endif
-
-
-
-static int
-remoteDispatchAuthPolkit(virNetServerPtr server,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_auth_polkit_ret *ret)
-{
- pid_t callerPid = -1;
- gid_t callerGid = -1;
- uid_t callerUid = -1;
- unsigned long long timestamp;
- const char *action;
- char *ident = NULL;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
- int rv;
-
- virMutexLock(&priv->lock);
- action = virNetServerClientGetReadonly(client) ?
- "org.libvirt.unix.monitor" :
- "org.libvirt.unix.manage";
-
- VIR_DEBUG("Start PolicyKit auth %d", virNetServerClientGetFD(client));
- if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_POLKIT) {
- VIR_ERROR(_("client tried invalid PolicyKit init request"));
- goto authfail;
- }
-
- if (virNetServerClientGetUNIXIdentity(client, &callerUid, &callerGid,
- &callerPid, ×tamp) < 0) {
- goto authfail;
- }
-
- if (timestamp == 0) {
- VIR_WARN("Failing polkit auth due to missing client (pid=%lld) start time",
- (long long)callerPid);
- goto authfail;
- }
-
- VIR_INFO("Checking PID %lld running as %d",
- (long long) callerPid, callerUid);
-
- rv = virPolkitCheckAuth(action,
- callerPid,
- timestamp,
- callerUid,
- NULL,
- true);
- if (rv == -1)
- goto authfail;
- else if (rv == -2)
- goto authdeny;
-
- PROBE(RPC_SERVER_CLIENT_AUTH_ALLOW,
- "client=%p auth=%d identity=%s",
- client, REMOTE_AUTH_POLKIT, ident);
- VIR_INFO("Policy allowed action %s from pid %lld, uid %d",
- action, (long long) callerPid, callerUid);
- ret->complete = 1;
-
- virNetServerSetClientAuthenticated(server, client);
- virMutexUnlock(&priv->lock);
-
- return 0;
-
- error:
- virNetMessageSaveError(rerr);
- virMutexUnlock(&priv->lock);
- return -1;
-
- authfail:
- PROBE(RPC_SERVER_CLIENT_AUTH_FAIL,
- "client=%p auth=%d",
- client, REMOTE_AUTH_POLKIT);
- goto error;
-
- authdeny:
- PROBE(RPC_SERVER_CLIENT_AUTH_DENY,
- "client=%p auth=%d identity=%s",
- client, REMOTE_AUTH_POLKIT, ident);
- goto error;
-}
-
-
-static int
-remoteDispatchNodeDeviceGetParent(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_node_device_get_parent_args *args,
- remote_node_device_get_parent_ret *ret)
-{
- virNodeDevicePtr dev = NULL;
- const char *parent = NULL;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dev = virNodeDeviceLookupByName(priv->conn, args->name)))
- goto cleanup;
-
- parent = virNodeDeviceGetParent(dev);
-
- if (parent == NULL) {
- ret->parent = NULL;
- } else {
- /* remoteDispatchClientRequest will free this. */
- char **parent_p;
- if (VIR_ALLOC(parent_p) < 0)
- goto cleanup;
- if (VIR_STRDUP(*parent_p, parent) < 0) {
- VIR_FREE(parent_p);
- goto cleanup;
- }
- ret->parent = parent_p;
- }
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dev);
- return rv;
-}
-
-static int
-remoteDispatchConnectRegisterCloseCallback(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr)
-{
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- virMutexLock(&priv->lock);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (virConnectRegisterCloseCallback(priv->conn,
- remoteRelayConnectionClosedEvent,
- client, NULL) < 0)
- goto cleanup;
-
- priv->closeRegistered = true;
- rv = 0;
-
- cleanup:
- virMutexUnlock(&priv->lock);
- if (rv < 0)
- virNetMessageSaveError(rerr);
- return rv;
-}
-
-static int
-remoteDispatchConnectUnregisterCloseCallback(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr)
-{
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- virMutexLock(&priv->lock);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (virConnectUnregisterCloseCallback(priv->conn,
- remoteRelayConnectionClosedEvent) < 0)
- goto cleanup;
-
- priv->closeRegistered = false;
- rv = 0;
-
- cleanup:
- virMutexUnlock(&priv->lock);
- if (rv < 0)
- virNetMessageSaveError(rerr);
- return rv;
-}
-
-static int
-remoteDispatchConnectDomainEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
- remote_connect_domain_event_register_ret *ret ATTRIBUTE_UNUSED)
-{
- int callbackID;
- int rv = -1;
- daemonClientEventCallbackPtr callback = NULL;
- daemonClientEventCallbackPtr ref;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- virMutexLock(&priv->lock);
-
- /* If we call register first, we could append a complete callback
- * to our array, but on OOM append failure, we'd have to then hope
- * deregister works to undo our register. So instead we append an
- * incomplete callback to our array, then register, then fix up
- * our callback; or you can use VIR_APPEND_ELEMENT_COPY to avoid
- * clearing 'callback' and having to juggle the pointer
- * between 'ref' and 'callback'.
- */
- if (VIR_ALLOC(callback) < 0)
- goto cleanup;
- callback->client = virObjectRef(client);
- callback->eventID = VIR_DOMAIN_EVENT_ID_LIFECYCLE;
- callback->callbackID = -1;
- callback->legacy = true;
- ref = callback;
- if (VIR_APPEND_ELEMENT(priv->domainEventCallbacks,
- priv->ndomainEventCallbacks,
- callback) < 0)
- goto cleanup;
-
- if ((callbackID = virConnectDomainEventRegisterAny(priv->conn,
- NULL,
- VIR_DOMAIN_EVENT_ID_LIFECYCLE,
- VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
- ref,
- remoteEventCallbackFree)) < 0) {
- VIR_SHRINK_N(priv->domainEventCallbacks,
- priv->ndomainEventCallbacks, 1);
- callback = ref;
- goto cleanup;
- }
-
- ref->callbackID = callbackID;
-
- rv = 0;
-
- cleanup:
- remoteEventCallbackFree(callback);
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virMutexUnlock(&priv->lock);
- return rv;
-}
-
-static int
-remoteDispatchConnectDomainEventDeregister(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
- remote_connect_domain_event_deregister_ret *ret ATTRIBUTE_UNUSED)
-{
- int callbackID = -1;
- int rv = -1;
- size_t i;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- virMutexLock(&priv->lock);
-
- for (i = 0; i < priv->ndomainEventCallbacks; i++) {
- if (priv->domainEventCallbacks[i]->eventID == VIR_DOMAIN_EVENT_ID_LIFECYCLE) {
- callbackID = priv->domainEventCallbacks[i]->callbackID;
- break;
- }
- }
-
- if (callbackID < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("domain event %d not registered"),
- VIR_DOMAIN_EVENT_ID_LIFECYCLE);
- goto cleanup;
- }
-
- if (virConnectDomainEventDeregisterAny(priv->conn, callbackID) < 0)
- goto cleanup;
-
- VIR_DELETE_ELEMENT(priv->domainEventCallbacks, i,
- priv->ndomainEventCallbacks);
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virMutexUnlock(&priv->lock);
- return rv;
-}
-
-static void
-remoteDispatchObjectEventSend(virNetServerClientPtr client,
- virNetServerProgramPtr program,
- int procnr,
- xdrproc_t proc,
- void *data)
-{
- virNetMessagePtr msg;
-
- if (!(msg = virNetMessageNew(false)))
- goto cleanup;
-
- msg->header.prog = virNetServerProgramGetID(program);
- msg->header.vers = virNetServerProgramGetVersion(program);
- msg->header.proc = procnr;
- msg->header.type = VIR_NET_MESSAGE;
- msg->header.serial = 1;
- msg->header.status = VIR_NET_OK;
-
- if (virNetMessageEncodeHeader(msg) < 0)
- goto cleanup;
-
- if (virNetMessageEncodePayload(msg, proc, data) < 0)
- goto cleanup;
-
- VIR_DEBUG("Queue event %d %zu", procnr, msg->bufferLength);
- virNetServerClientSendMessage(client, msg);
-
- xdr_free(proc, data);
- return;
-
- cleanup:
- virNetMessageFree(msg);
- xdr_free(proc, data);
-}
-
-static int
-remoteDispatchSecretGetValue(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_secret_get_value_args *args,
- remote_secret_get_value_ret *ret)
-{
- virSecretPtr secret = NULL;
- size_t value_size;
- unsigned char *value;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(secret = get_nonnull_secret(priv->conn, args->secret)))
- goto cleanup;
-
- if (!(value = virSecretGetValue(secret, &value_size, args->flags)))
- goto cleanup;
-
- ret->value.value_len = value_size;
- ret->value.value_val = (char *)value;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(secret);
- return rv;
-}
-
-static int
-remoteDispatchDomainGetState(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_state_args *args,
- remote_domain_get_state_ret *ret)
-{
- virDomainPtr dom = NULL;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (virDomainGetState(dom, &ret->state, &ret->reason, args->flags) < 0)
- goto cleanup;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- return rv;
-}
-
-
-/* Due to back-compat reasons, two RPC calls map to the same libvirt
- * API of virConnectDomainEventRegisterAny. A client should only use
- * the new call if they have probed
- * VIR_DRV_SUPPORTS_FEATURE(VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK),
- * and must not mix the two styles. */
-static int
-remoteDispatchConnectDomainEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
- remote_connect_domain_event_register_any_args *args)
-{
- int callbackID;
- int rv = -1;
- daemonClientEventCallbackPtr callback = NULL;
- daemonClientEventCallbackPtr ref;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- virMutexLock(&priv->lock);
-
- /* We intentionally do not use VIR_DOMAIN_EVENT_ID_LAST here; any
- * new domain events added after this point should only use the
- * modern callback style of RPC. */
- if (args->eventID > VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED ||
- args->eventID < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR, _("unsupported event ID %d"),
- args->eventID);
- goto cleanup;
- }
-
- /* If we call register first, we could append a complete callback
- * to our array, but on OOM append failure, we'd have to then hope
- * deregister works to undo our register. So instead we append an
- * incomplete callback to our array, then register, then fix up
- * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
- * success, we use 'ref' to save a copy of the pointer. */
- if (VIR_ALLOC(callback) < 0)
- goto cleanup;
- callback->client = virObjectRef(client);
- callback->eventID = args->eventID;
- callback->callbackID = -1;
- callback->legacy = true;
- ref = callback;
- if (VIR_APPEND_ELEMENT(priv->domainEventCallbacks,
- priv->ndomainEventCallbacks,
- callback) < 0)
- goto cleanup;
-
- if ((callbackID = virConnectDomainEventRegisterAny(priv->conn,
- NULL,
- args->eventID,
- domainEventCallbacks[args->eventID],
- ref,
- remoteEventCallbackFree)) < 0) {
- VIR_SHRINK_N(priv->domainEventCallbacks,
- priv->ndomainEventCallbacks, 1);
- callback = ref;
- goto cleanup;
- }
-
- ref->callbackID = callbackID;
-
- rv = 0;
-
- cleanup:
- remoteEventCallbackFree(callback);
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virMutexUnlock(&priv->lock);
- return rv;
-}
-
-
-static int
-remoteDispatchConnectDomainEventCallbackRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
- remote_connect_domain_event_callback_register_any_args *args,
- remote_connect_domain_event_callback_register_any_ret *ret)
-{
- int callbackID;
- int rv = -1;
- daemonClientEventCallbackPtr callback = NULL;
- daemonClientEventCallbackPtr ref;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
- virDomainPtr dom = NULL;
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- virMutexLock(&priv->lock);
-
- if (args->dom &&
- !(dom = get_nonnull_domain(priv->conn, *args->dom)))
- goto cleanup;
-
- if (args->eventID >= VIR_DOMAIN_EVENT_ID_LAST || args->eventID < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR, _("unsupported event ID %d"),
- args->eventID);
- goto cleanup;
- }
-
- /* If we call register first, we could append a complete callback
- * to our array, but on OOM append failure, we'd have to then hope
- * deregister works to undo our register. So instead we append an
- * incomplete callback to our array, then register, then fix up
- * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
- * success, we use 'ref' to save a copy of the pointer. */
- if (VIR_ALLOC(callback) < 0)
- goto cleanup;
- callback->client = virObjectRef(client);
- callback->eventID = args->eventID;
- callback->callbackID = -1;
- ref = callback;
- if (VIR_APPEND_ELEMENT(priv->domainEventCallbacks,
- priv->ndomainEventCallbacks,
- callback) < 0)
- goto cleanup;
-
- if ((callbackID = virConnectDomainEventRegisterAny(priv->conn,
- dom,
- args->eventID,
- domainEventCallbacks[args->eventID],
- ref,
- remoteEventCallbackFree)) < 0) {
- VIR_SHRINK_N(priv->domainEventCallbacks,
- priv->ndomainEventCallbacks, 1);
- callback = ref;
- goto cleanup;
- }
-
- ref->callbackID = callbackID;
- ret->callbackID = callbackID;
-
- rv = 0;
-
- cleanup:
- remoteEventCallbackFree(callback);
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- virMutexUnlock(&priv->lock);
- return rv;
-}
-
-
-static int
-remoteDispatchConnectDomainEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
- remote_connect_domain_event_deregister_any_args *args)
-{
- int callbackID = -1;
- int rv = -1;
- size_t i;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- virMutexLock(&priv->lock);
-
- /* We intentionally do not use VIR_DOMAIN_EVENT_ID_LAST here; any
- * new domain events added after this point should only use the
- * modern callback style of RPC. */
- if (args->eventID > VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED ||
- args->eventID < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR, _("unsupported event ID %d"),
- args->eventID);
- goto cleanup;
- }
-
- for (i = 0; i < priv->ndomainEventCallbacks; i++) {
- if (priv->domainEventCallbacks[i]->eventID == args->eventID) {
- callbackID = priv->domainEventCallbacks[i]->callbackID;
- break;
- }
- }
- if (callbackID < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("domain event %d not registered"), args->eventID);
- goto cleanup;
- }
-
- if (virConnectDomainEventDeregisterAny(priv->conn, callbackID) < 0)
- goto cleanup;
-
- VIR_DELETE_ELEMENT(priv->domainEventCallbacks, i,
- priv->ndomainEventCallbacks);
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virMutexUnlock(&priv->lock);
- return rv;
-}
-
-
-static int
-remoteDispatchConnectDomainEventCallbackDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
- remote_connect_domain_event_callback_deregister_any_args *args)
-{
- int rv = -1;
- size_t i;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- virMutexLock(&priv->lock);
-
- for (i = 0; i < priv->ndomainEventCallbacks; i++) {
- if (priv->domainEventCallbacks[i]->callbackID == args->callbackID)
- break;
- }
- if (i == priv->ndomainEventCallbacks) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("domain event callback %d not registered"),
- args->callbackID);
- goto cleanup;
- }
-
- if (virConnectDomainEventDeregisterAny(priv->conn, args->callbackID) < 0)
- goto cleanup;
-
- VIR_DELETE_ELEMENT(priv->domainEventCallbacks, i,
- priv->ndomainEventCallbacks);
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virMutexUnlock(&priv->lock);
- return rv;
-}
-
-
-static int
-qemuDispatchDomainMonitorCommand(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- qemu_domain_monitor_command_args *args,
- qemu_domain_monitor_command_ret *ret)
-{
- virDomainPtr dom = NULL;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (virDomainQemuMonitorCommand(dom, args->cmd, &ret->result,
- args->flags) < 0)
- goto cleanup;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- return rv;
-}
-
-
-static int
-remoteDispatchDomainMigrateBegin3(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_migrate_begin3_args *args,
- remote_domain_migrate_begin3_ret *ret)
-{
- char *xml = NULL;
- virDomainPtr dom = NULL;
- char *dname;
- char *xmlin;
- char *cookieout = NULL;
- int cookieoutlen = 0;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- xmlin = args->xmlin == NULL ? NULL : *args->xmlin;
- dname = args->dname == NULL ? NULL : *args->dname;
-
- if (!(xml = virDomainMigrateBegin3(dom, xmlin,
- &cookieout, &cookieoutlen,
- args->flags, dname, args->resource)))
- goto cleanup;
-
- /* remoteDispatchClientRequest will free cookie and
- * the xml string if there is one.
- */
- ret->cookie_out.cookie_out_len = cookieoutlen;
- ret->cookie_out.cookie_out_val = cookieout;
- ret->xml = xml;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- return rv;
-}
-
-
-static int
-remoteDispatchDomainMigratePrepare3(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_migrate_prepare3_args *args,
- remote_domain_migrate_prepare3_ret *ret)
-{
- char *cookieout = NULL;
- int cookieoutlen = 0;
- char *uri_in;
- char **uri_out;
- char *dname;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- uri_in = args->uri_in == NULL ? NULL : *args->uri_in;
- dname = args->dname == NULL ? NULL : *args->dname;
-
- /* Wacky world of XDR ... */
- if (VIR_ALLOC(uri_out) < 0)
- goto cleanup;
-
- if (virDomainMigratePrepare3(priv->conn,
- args->cookie_in.cookie_in_val,
- args->cookie_in.cookie_in_len,
- &cookieout, &cookieoutlen,
- uri_in, uri_out,
- args->flags, dname, args->resource,
- args->dom_xml) < 0)
- goto cleanup;
-
- /* remoteDispatchClientRequest will free cookie, uri_out and
- * the string if there is one.
- */
- ret->cookie_out.cookie_out_len = cookieoutlen;
- ret->cookie_out.cookie_out_val = cookieout;
- ret->uri_out = *uri_out == NULL ? NULL : uri_out;
-
- rv = 0;
-
- cleanup:
- if (rv < 0) {
- virNetMessageSaveError(rerr);
- VIR_FREE(uri_out);
- }
- return rv;
-}
-
-
-static int
-remoteDispatchDomainMigratePerform3(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_migrate_perform3_args *args,
- remote_domain_migrate_perform3_ret *ret)
-{
- virDomainPtr dom = NULL;
- char *xmlin;
- char *dname;
- char *uri;
- char *dconnuri;
- char *cookieout = NULL;
- int cookieoutlen = 0;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- xmlin = args->xmlin == NULL ? NULL : *args->xmlin;
- dname = args->dname == NULL ? NULL : *args->dname;
- uri = args->uri == NULL ? NULL : *args->uri;
- dconnuri = args->dconnuri == NULL ? NULL : *args->dconnuri;
-
- if (virDomainMigratePerform3(dom, xmlin,
- args->cookie_in.cookie_in_val,
- args->cookie_in.cookie_in_len,
- &cookieout, &cookieoutlen,
- dconnuri, uri,
- args->flags, dname, args->resource) < 0)
- goto cleanup;
-
- /* remoteDispatchClientRequest will free cookie
- */
- ret->cookie_out.cookie_out_len = cookieoutlen;
- ret->cookie_out.cookie_out_val = cookieout;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- return rv;
-}
-
-
-static int
-remoteDispatchDomainMigrateFinish3(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_migrate_finish3_args *args,
- remote_domain_migrate_finish3_ret *ret)
-{
- virDomainPtr dom = NULL;
- char *cookieout = NULL;
- int cookieoutlen = 0;
- char *uri;
- char *dconnuri;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- uri = args->uri == NULL ? NULL : *args->uri;
- dconnuri = args->dconnuri == NULL ? NULL : *args->dconnuri;
-
- if (!(dom = virDomainMigrateFinish3(priv->conn, args->dname,
- args->cookie_in.cookie_in_val,
- args->cookie_in.cookie_in_len,
- &cookieout, &cookieoutlen,
- dconnuri, uri,
- args->flags,
- args->cancelled)))
- goto cleanup;
-
- make_nonnull_domain(&ret->dom, dom);
-
- /* remoteDispatchClientRequest will free cookie
- */
- ret->cookie_out.cookie_out_len = cookieoutlen;
- ret->cookie_out.cookie_out_val = cookieout;
-
- rv = 0;
-
- cleanup:
- if (rv < 0) {
- virNetMessageSaveError(rerr);
- VIR_FREE(cookieout);
- }
- virObjectUnref(dom);
- return rv;
-}
-
-
-static int
-remoteDispatchDomainMigrateConfirm3(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_migrate_confirm3_args *args)
-{
- virDomainPtr dom = NULL;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (virDomainMigrateConfirm3(dom,
- args->cookie_in.cookie_in_val,
- args->cookie_in.cookie_in_len,
- args->flags, args->cancelled) < 0)
- goto cleanup;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- return rv;
-}
-
-
-static int remoteDispatchConnectSupportsFeature(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_connect_supports_feature_args *args,
- remote_connect_supports_feature_ret *ret)
-{
- int rv = -1;
- int supported;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- /* This feature is checked before opening the connection, thus we must
- * check it first.
- */
- if (args->feature == VIR_DRV_FEATURE_PROGRAM_KEEPALIVE) {
- if (virNetServerClientStartKeepAlive(client) < 0)
- goto cleanup;
- supported = 1;
- goto done;
- }
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- switch (args->feature) {
- case VIR_DRV_FEATURE_FD_PASSING:
- case VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK:
- case VIR_DRV_FEATURE_REMOTE_CLOSE_CALLBACK:
- supported = 1;
- break;
-
- default:
- if ((supported = virConnectSupportsFeature(priv->conn, args->feature)) < 0)
- goto cleanup;
- break;
- }
-
- done:
- ret->supported = supported;
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- return rv;
-}
-
-
-static int
-remoteDispatchDomainOpenGraphics(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg,
- virNetMessageErrorPtr rerr,
- remote_domain_open_graphics_args *args)
-{
- virDomainPtr dom = NULL;
- int rv = -1;
- int fd = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if ((fd = virNetMessageDupFD(msg, 0)) < 0)
- goto cleanup;
-
- if (virDomainOpenGraphics(dom,
- args->idx,
- fd,
- args->flags) < 0)
- goto cleanup;
-
- rv = 0;
-
- cleanup:
- VIR_FORCE_CLOSE(fd);
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- return rv;
-}
-
-
-static int
-remoteDispatchDomainOpenGraphicsFd(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg,
- virNetMessageErrorPtr rerr,
- remote_domain_open_graphics_fd_args *args)
-{
- virDomainPtr dom = NULL;
- int rv = -1;
- int fd = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if ((fd = virDomainOpenGraphicsFD(dom,
- args->idx,
- args->flags)) < 0)
- goto cleanup;
-
- if (virNetMessageAddFD(msg, fd) < 0)
- goto cleanup;
-
- /* return 1 here to let virNetServerProgramDispatchCall know
- * we are passing a FD */
- rv = 1;
-
- cleanup:
- VIR_FORCE_CLOSE(fd);
- if (rv < 0)
- virNetMessageSaveError(rerr);
-
- virObjectUnref(dom);
- return rv;
-}
-
-
-static int
-remoteDispatchDomainGetInterfaceParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_interface_parameters_args *args,
- remote_domain_get_interface_parameters_ret *ret)
-{
- virDomainPtr dom = NULL;
- virTypedParameterPtr params = NULL;
- const char *device = args->device;
- int nparams = 0;
- unsigned int flags;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- flags = args->flags;
-
- if (args->nparams > REMOTE_DOMAIN_INTERFACE_PARAMETERS_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
- goto cleanup;
- }
- if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
- goto cleanup;
- nparams = args->nparams;
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (virDomainGetInterfaceParameters(dom, device, params, &nparams, flags) < 0)
- goto cleanup;
-
- /* In this case, we need to send back the number of parameters
- * supported
- */
- if (args->nparams == 0) {
- ret->nparams = nparams;
- goto success;
- }
-
- if (virTypedParamsSerialize(params, nparams,
- (virTypedParameterRemotePtr *) &ret->params.params_val,
- &ret->params.params_len,
- flags) < 0)
- goto cleanup;
-
- success:
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virTypedParamsFree(params, nparams);
- virObjectUnref(dom);
- return rv;
-}
-
-static int
-remoteDispatchDomainGetCPUStats(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr hdr ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_cpu_stats_args *args,
- remote_domain_get_cpu_stats_ret *ret)
-{
- virDomainPtr dom = NULL;
- struct daemonClientPrivate *priv;
- virTypedParameterPtr params = NULL;
- int rv = -1;
- int percpu_len = 0;
-
- priv = virNetServerClientGetPrivateData(client);
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (args->nparams > REMOTE_NODE_CPU_STATS_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
- goto cleanup;
- }
- if (args->ncpus > REMOTE_DOMAIN_GET_CPU_STATS_NCPUS_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("ncpus too large"));
- goto cleanup;
- }
-
- if (args->nparams > 0 &&
- VIR_ALLOC_N(params, args->ncpus * args->nparams) < 0)
- goto cleanup;
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- percpu_len = virDomainGetCPUStats(dom, params, args->nparams,
- args->start_cpu, args->ncpus,
- args->flags);
- if (percpu_len < 0)
- goto cleanup;
- /* If nparams == 0, the function returns a single value */
- if (args->nparams == 0)
- goto success;
-
- if (virTypedParamsSerialize(params, args->nparams * args->ncpus,
- (virTypedParameterRemotePtr *) &ret->params.params_val,
- &ret->params.params_len,
- args->flags) < 0)
- goto cleanup;
-
- success:
- rv = 0;
- ret->nparams = percpu_len;
- if (args->nparams && !(args->flags & VIR_TYPED_PARAM_STRING_OKAY)) {
- size_t i;
-
- for (i = 0; i < percpu_len; i++) {
- if (params[i].type == VIR_TYPED_PARAM_STRING)
- ret->nparams--;
- }
- }
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virTypedParamsFree(params, args->ncpus * args->nparams);
- virObjectUnref(dom);
- return rv;
-}
-
-static int
-remoteDispatchDomainGetDiskErrors(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_disk_errors_args *args,
- remote_domain_get_disk_errors_ret *ret)
-{
- int rv = -1;
- virDomainPtr dom = NULL;
- virDomainDiskErrorPtr errors = NULL;
- int len = 0;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (args->maxerrors > REMOTE_DOMAIN_DISK_ERRORS_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("maxerrors too large"));
- goto cleanup;
- }
-
- if (args->maxerrors &&
- VIR_ALLOC_N(errors, args->maxerrors) < 0)
- goto cleanup;
-
- if ((len = virDomainGetDiskErrors(dom, errors,
- args->maxerrors,
- args->flags)) < 0)
- goto cleanup;
-
- ret->nerrors = len;
- if (errors &&
- remoteSerializeDomainDiskErrors(errors, len,
- &ret->errors.errors_val,
- &ret->errors.errors_len) < 0)
- goto cleanup;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- if (errors && len > 0) {
- size_t i;
- for (i = 0; i < len; i++)
- VIR_FREE(errors[i].disk);
- }
- VIR_FREE(errors);
- return rv;
-}
-
-
-static int
-remoteDispatchNodeGetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_node_get_memory_parameters_args *args,
- remote_node_get_memory_parameters_ret *ret)
-{
- virTypedParameterPtr params = NULL;
- int nparams = 0;
- unsigned int flags;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- flags = args->flags;
-
- if (args->nparams > REMOTE_NODE_MEMORY_PARAMETERS_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
- goto cleanup;
- }
- if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
- goto cleanup;
- nparams = args->nparams;
-
- if (virNodeGetMemoryParameters(priv->conn, params, &nparams, flags) < 0)
- goto cleanup;
-
- /* In this case, we need to send back the number of parameters
- * supported
- */
- if (args->nparams == 0) {
- ret->nparams = nparams;
- goto success;
- }
-
- if (virTypedParamsSerialize(params, nparams,
- (virTypedParameterRemotePtr *) &ret->params.params_val,
- &ret->params.params_len,
- args->flags) < 0)
- goto cleanup;
-
- success:
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virTypedParamsFree(params, nparams);
- return rv;
-}
-
-static int
-remoteDispatchNodeGetCPUMap(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_node_get_cpu_map_args *args,
- remote_node_get_cpu_map_ret *ret)
-{
- unsigned char *cpumap = NULL;
- unsigned int online = 0;
- unsigned int flags;
- int cpunum;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- flags = args->flags;
-
- cpunum = virNodeGetCPUMap(priv->conn, args->need_map ? &cpumap : NULL,
- args->need_online ? &online : NULL, flags);
- if (cpunum < 0)
- goto cleanup;
-
- /* 'serialize' return cpumap */
- if (args->need_map) {
- ret->cpumap.cpumap_len = VIR_CPU_MAPLEN(cpunum);
- ret->cpumap.cpumap_val = (char *) cpumap;
- cpumap = NULL;
- }
-
- ret->online = online;
- ret->ret = cpunum;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- VIR_FREE(cpumap);
- return rv;
-}
-
-static int
-lxcDispatchDomainOpenNamespace(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- lxc_domain_open_namespace_args *args)
-{
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
- int *fdlist = NULL;
- int ret;
- virDomainPtr dom = NULL;
- size_t i;
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- ret = virDomainLxcOpenNamespace(dom,
- &fdlist,
- args->flags);
- if (ret < 0)
- goto cleanup;
-
- /* We shouldn't have received any from the client,
- * but in case they're playing games with us, prevent
- * a resource leak
- */
- for (i = 0; i < msg->nfds; i++)
- VIR_FORCE_CLOSE(msg->fds[i]);
- VIR_FREE(msg->fds);
- msg->nfds = 0;
-
- msg->fds = fdlist;
- msg->nfds = ret;
-
- rv = 1;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- return rv;
-}
-
-static int
-remoteDispatchDomainGetJobStats(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_job_stats_args *args,
- remote_domain_get_job_stats_ret *ret)
-{
- virDomainPtr dom = NULL;
- virTypedParameterPtr params = NULL;
- int nparams = 0;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (virDomainGetJobStats(dom, &ret->type, ¶ms,
- &nparams, args->flags) < 0)
- goto cleanup;
-
- if (nparams > REMOTE_DOMAIN_JOB_STATS_MAX) {
- virReportError(VIR_ERR_RPC,
- _("Too many job stats '%d' for limit '%d'"),
- nparams, REMOTE_DOMAIN_JOB_STATS_MAX);
- goto cleanup;
- }
-
- if (virTypedParamsSerialize(params, nparams,
- (virTypedParameterRemotePtr *) &ret->params.params_val,
- &ret->params.params_len,
- 0) < 0)
- goto cleanup;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virTypedParamsFree(params, nparams);
- virObjectUnref(dom);
- return rv;
-}
-
-static int
-remoteDispatchDomainMigrateBegin3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_migrate_begin3_params_args *args,
- remote_domain_migrate_begin3_params_ret *ret)
-{
- char *xml = NULL;
- virDomainPtr dom = NULL;
- virTypedParameterPtr params = NULL;
- int nparams = 0;
- char *cookieout = NULL;
- int cookieoutlen = 0;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (args->params.params_len > REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX) {
- virReportError(VIR_ERR_RPC,
- _("Too many migration parameters '%d' for limit '%d'"),
- args->params.params_len, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX);
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val,
- args->params.params_len,
- 0, ¶ms, &nparams) < 0)
- goto cleanup;
-
- if (!(xml = virDomainMigrateBegin3Params(dom, params, nparams,
- &cookieout, &cookieoutlen,
- args->flags)))
- goto cleanup;
-
- ret->cookie_out.cookie_out_len = cookieoutlen;
- ret->cookie_out.cookie_out_val = cookieout;
- ret->xml = xml;
-
- rv = 0;
-
- cleanup:
- virTypedParamsFree(params, nparams);
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- return rv;
-}
-
-static int
-remoteDispatchDomainMigratePrepare3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_migrate_prepare3_params_args *args,
- remote_domain_migrate_prepare3_params_ret *ret)
-{
- virTypedParameterPtr params = NULL;
- int nparams = 0;
- char *cookieout = NULL;
- int cookieoutlen = 0;
- char **uri_out;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (args->params.params_len > REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX) {
- virReportError(VIR_ERR_RPC,
- _("Too many migration parameters '%d' for limit '%d'"),
- args->params.params_len, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX);
- goto cleanup;
- }
-
- if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val,
- args->params.params_len,
- 0, ¶ms, &nparams) < 0)
- goto cleanup;
-
- /* Wacky world of XDR ... */
- if (VIR_ALLOC(uri_out) < 0)
- goto cleanup;
-
- if (virDomainMigratePrepare3Params(priv->conn, params, nparams,
- args->cookie_in.cookie_in_val,
- args->cookie_in.cookie_in_len,
- &cookieout, &cookieoutlen,
- uri_out, args->flags) < 0)
- goto cleanup;
-
- ret->cookie_out.cookie_out_len = cookieoutlen;
- ret->cookie_out.cookie_out_val = cookieout;
- ret->uri_out = !*uri_out ? NULL : uri_out;
-
- rv = 0;
-
- cleanup:
- virTypedParamsFree(params, nparams);
- if (rv < 0) {
- virNetMessageSaveError(rerr);
- VIR_FREE(uri_out);
- }
- return rv;
-}
-
-static int
-remoteDispatchDomainMigratePrepareTunnel3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg,
- virNetMessageErrorPtr rerr,
- remote_domain_migrate_prepare_tunnel3_params_args *args,
- remote_domain_migrate_prepare_tunnel3_params_ret *ret)
-{
- virTypedParameterPtr params = NULL;
- int nparams = 0;
- char *cookieout = NULL;
- int cookieoutlen = 0;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
- virStreamPtr st = NULL;
- daemonClientStreamPtr stream = NULL;
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (args->params.params_len > REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX) {
- virReportError(VIR_ERR_RPC,
- _("Too many migration parameters '%d' for limit '%d'"),
- args->params.params_len, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX);
- goto cleanup;
- }
-
- if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val,
- args->params.params_len,
- 0, ¶ms, &nparams) < 0)
- goto cleanup;
-
- if (!(st = virStreamNew(priv->conn, VIR_STREAM_NONBLOCK)) ||
- !(stream = daemonCreateClientStream(client, st, remoteProgram,
- &msg->header, false)))
- goto cleanup;
-
- if (virDomainMigratePrepareTunnel3Params(priv->conn, st, params, nparams,
- args->cookie_in.cookie_in_val,
- args->cookie_in.cookie_in_len,
- &cookieout, &cookieoutlen,
- args->flags) < 0)
- goto cleanup;
-
- if (daemonAddClientStream(client, stream, false) < 0)
- goto cleanup;
-
- ret->cookie_out.cookie_out_val = cookieout;
- ret->cookie_out.cookie_out_len = cookieoutlen;
- rv = 0;
-
- cleanup:
- virTypedParamsFree(params, nparams);
- if (rv < 0) {
- virNetMessageSaveError(rerr);
- VIR_FREE(cookieout);
- if (stream) {
- virStreamAbort(st);
- daemonFreeClientStream(client, stream);
- } else {
- virObjectUnref(st);
- }
- }
- return rv;
-}
-
-
-static int
-remoteDispatchDomainMigratePerform3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_migrate_perform3_params_args *args,
- remote_domain_migrate_perform3_params_ret *ret)
-{
- virTypedParameterPtr params = NULL;
- int nparams = 0;
- virDomainPtr dom = NULL;
- char *cookieout = NULL;
- int cookieoutlen = 0;
- char *dconnuri;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (args->params.params_len > REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX) {
- virReportError(VIR_ERR_RPC,
- _("Too many migration parameters '%d' for limit '%d'"),
- args->params.params_len, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX);
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val,
- args->params.params_len,
- 0, ¶ms, &nparams) < 0)
- goto cleanup;
-
- dconnuri = args->dconnuri == NULL ? NULL : *args->dconnuri;
-
- if (virDomainMigratePerform3Params(dom, dconnuri, params, nparams,
- args->cookie_in.cookie_in_val,
- args->cookie_in.cookie_in_len,
- &cookieout, &cookieoutlen,
- args->flags) < 0)
- goto cleanup;
-
- ret->cookie_out.cookie_out_len = cookieoutlen;
- ret->cookie_out.cookie_out_val = cookieout;
-
- rv = 0;
-
- cleanup:
- virTypedParamsFree(params, nparams);
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- return rv;
-}
-
-
-static int
-remoteDispatchDomainMigrateFinish3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_migrate_finish3_params_args *args,
- remote_domain_migrate_finish3_params_ret *ret)
-{
- virTypedParameterPtr params = NULL;
- int nparams = 0;
- virDomainPtr dom = NULL;
- char *cookieout = NULL;
- int cookieoutlen = 0;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (args->params.params_len > REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX) {
- virReportError(VIR_ERR_RPC,
- _("Too many migration parameters '%d' for limit '%d'"),
- args->params.params_len, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX);
- goto cleanup;
- }
-
- if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val,
- args->params.params_len,
- 0, ¶ms, &nparams) < 0)
- goto cleanup;
-
- dom = virDomainMigrateFinish3Params(priv->conn, params, nparams,
- args->cookie_in.cookie_in_val,
- args->cookie_in.cookie_in_len,
- &cookieout, &cookieoutlen,
- args->flags, args->cancelled);
- if (!dom)
- goto cleanup;
-
- make_nonnull_domain(&ret->dom, dom);
-
- ret->cookie_out.cookie_out_len = cookieoutlen;
- ret->cookie_out.cookie_out_val = cookieout;
-
- rv = 0;
-
- cleanup:
- virTypedParamsFree(params, nparams);
- if (rv < 0) {
- virNetMessageSaveError(rerr);
- VIR_FREE(cookieout);
- }
- virObjectUnref(dom);
- return rv;
-}
-
-
-static int
-remoteDispatchDomainMigrateConfirm3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_migrate_confirm3_params_args *args)
-{
- virTypedParameterPtr params = NULL;
- int nparams = 0;
- virDomainPtr dom = NULL;
- int rv = -1;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (args->params.params_len > REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX) {
- virReportError(VIR_ERR_RPC,
- _("Too many migration parameters '%d' for limit '%d'"),
- args->params.params_len, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX);
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val,
- args->params.params_len,
- 0, ¶ms, &nparams) < 0)
- goto cleanup;
-
- if (virDomainMigrateConfirm3Params(dom, params, nparams,
- args->cookie_in.cookie_in_val,
- args->cookie_in.cookie_in_len,
- args->flags, args->cancelled) < 0)
- goto cleanup;
-
- rv = 0;
-
- cleanup:
- virTypedParamsFree(params, nparams);
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- return rv;
-}
-
-
-static int
-remoteDispatchConnectGetCPUModelNames(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_connect_get_cpu_model_names_args *args,
- remote_connect_get_cpu_model_names_ret *ret)
-{
- int len, rv = -1;
- char **models = NULL;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- len = virConnectGetCPUModelNames(priv->conn, args->arch,
- args->need_results ? &models : NULL,
- args->flags);
- if (len < 0)
- goto cleanup;
-
- if (len > REMOTE_CONNECT_CPU_MODELS_MAX) {
- virReportError(VIR_ERR_RPC,
- _("Too many CPU models '%d' for limit '%d'"),
- len, REMOTE_CONNECT_CPU_MODELS_MAX);
- goto cleanup;
- }
-
- if (len && models) {
- ret->models.models_val = models;
- ret->models.models_len = len;
- models = NULL;
- } else {
- ret->models.models_val = NULL;
- ret->models.models_len = 0;
- }
-
- ret->ret = len;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virStringListFree(models);
- return rv;
-}
-
-
-static int
-remoteDispatchDomainCreateXMLWithFiles(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_create_xml_with_files_args *args,
- remote_domain_create_xml_with_files_ret *ret)
-{
- int rv = -1;
- virDomainPtr dom = NULL;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
- int *files = NULL;
- unsigned int nfiles = 0;
- size_t i;
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (VIR_ALLOC_N(files, msg->nfds) < 0)
- goto cleanup;
- for (i = 0; i < msg->nfds; i++) {
- if ((files[i] = virNetMessageDupFD(msg, i)) < 0)
- goto cleanup;
- nfiles++;
- }
-
- if ((dom = virDomainCreateXMLWithFiles(priv->conn, args->xml_desc,
- nfiles, files,
- args->flags)) == NULL)
- goto cleanup;
-
- make_nonnull_domain(&ret->dom, dom);
- rv = 0;
-
- cleanup:
- for (i = 0; i < nfiles; i++)
- VIR_FORCE_CLOSE(files[i]);
- VIR_FREE(files);
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- return rv;
-}
-
-
-static int remoteDispatchDomainCreateWithFiles(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_create_with_files_args *args,
- remote_domain_create_with_files_ret *ret)
-{
- int rv = -1;
- virDomainPtr dom = NULL;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
- int *files = NULL;
- unsigned int nfiles = 0;
- size_t i;
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (VIR_ALLOC_N(files, msg->nfds) < 0)
- goto cleanup;
- for (i = 0; i < msg->nfds; i++) {
- if ((files[i] = virNetMessageDupFD(msg, i)) < 0)
- goto cleanup;
- nfiles++;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (virDomainCreateWithFiles(dom,
- nfiles, files,
- args->flags) < 0)
- goto cleanup;
-
- make_nonnull_domain(&ret->dom, dom);
- rv = 0;
-
- cleanup:
- for (i = 0; i < nfiles; i++)
- VIR_FORCE_CLOSE(files[i]);
- VIR_FREE(files);
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- return rv;
-}
-
-
-static int
-remoteDispatchConnectNetworkEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
- remote_connect_network_event_register_any_args *args,
- remote_connect_network_event_register_any_ret *ret)
-{
- int callbackID;
- int rv = -1;
- daemonClientEventCallbackPtr callback = NULL;
- daemonClientEventCallbackPtr ref;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
- virNetworkPtr net = NULL;
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- virMutexLock(&priv->lock);
-
- if (args->net &&
- !(net = get_nonnull_network(priv->conn, *args->net)))
- goto cleanup;
-
- if (args->eventID >= VIR_NETWORK_EVENT_ID_LAST || args->eventID < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unsupported network event ID %d"), args->eventID);
- goto cleanup;
- }
-
- /* If we call register first, we could append a complete callback
- * to our array, but on OOM append failure, we'd have to then hope
- * deregister works to undo our register. So instead we append an
- * incomplete callback to our array, then register, then fix up
- * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
- * success, we use 'ref' to save a copy of the pointer. */
- if (VIR_ALLOC(callback) < 0)
- goto cleanup;
- callback->client = virObjectRef(client);
- callback->eventID = args->eventID;
- callback->callbackID = -1;
- ref = callback;
- if (VIR_APPEND_ELEMENT(priv->networkEventCallbacks,
- priv->nnetworkEventCallbacks,
- callback) < 0)
- goto cleanup;
-
- if ((callbackID = virConnectNetworkEventRegisterAny(priv->conn,
- net,
- args->eventID,
- networkEventCallbacks[args->eventID],
- ref,
- remoteEventCallbackFree)) < 0) {
- VIR_SHRINK_N(priv->networkEventCallbacks,
- priv->nnetworkEventCallbacks, 1);
- callback = ref;
- goto cleanup;
- }
-
- ref->callbackID = callbackID;
- ret->callbackID = callbackID;
-
- rv = 0;
-
- cleanup:
- remoteEventCallbackFree(callback);
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(net);
- virMutexUnlock(&priv->lock);
- return rv;
-}
-
-
-static int
-remoteDispatchConnectNetworkEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
- remote_connect_network_event_deregister_any_args *args)
-{
- int rv = -1;
- size_t i;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- virMutexLock(&priv->lock);
-
- for (i = 0; i < priv->nnetworkEventCallbacks; i++) {
- if (priv->networkEventCallbacks[i]->callbackID == args->callbackID)
- break;
- }
- if (i == priv->nnetworkEventCallbacks) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("network event callback %d not registered"),
- args->callbackID);
- goto cleanup;
- }
-
- if (virConnectNetworkEventDeregisterAny(priv->conn, args->callbackID) < 0)
- goto cleanup;
-
- VIR_DELETE_ELEMENT(priv->networkEventCallbacks, i,
- priv->nnetworkEventCallbacks);
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virMutexUnlock(&priv->lock);
- return rv;
-}
-
-static int
-remoteDispatchConnectStoragePoolEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
- remote_connect_storage_pool_event_register_any_args *args,
- remote_connect_storage_pool_event_register_any_ret *ret)
-{
- int callbackID;
- int rv = -1;
- daemonClientEventCallbackPtr callback = NULL;
- daemonClientEventCallbackPtr ref;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
- virStoragePoolPtr pool = NULL;
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- virMutexLock(&priv->lock);
-
- if (args->pool &&
- !(pool = get_nonnull_storage_pool(priv->conn, *args->pool)))
- goto cleanup;
-
- if (args->eventID >= VIR_STORAGE_POOL_EVENT_ID_LAST || args->eventID < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unsupported storage pool event ID %d"), args->eventID);
- goto cleanup;
- }
-
- /* If we call register first, we could append a complete callback
- * to our array, but on OOM append failure, we'd have to then hope
- * deregister works to undo our register. So instead we append an
- * incomplete callback to our array, then register, then fix up
- * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
- * success, we use 'ref' to save a copy of the pointer. */
- if (VIR_ALLOC(callback) < 0)
- goto cleanup;
- callback->client = virObjectRef(client);
- callback->eventID = args->eventID;
- callback->callbackID = -1;
- ref = callback;
- if (VIR_APPEND_ELEMENT(priv->storageEventCallbacks,
- priv->nstorageEventCallbacks,
- callback) < 0)
- goto cleanup;
-
- if ((callbackID = virConnectStoragePoolEventRegisterAny(priv->conn,
- pool,
- args->eventID,
- storageEventCallbacks[args->eventID],
- ref,
- remoteEventCallbackFree)) < 0) {
- VIR_SHRINK_N(priv->storageEventCallbacks,
- priv->nstorageEventCallbacks, 1);
- callback = ref;
- goto cleanup;
- }
-
- ref->callbackID = callbackID;
- ret->callbackID = callbackID;
-
- rv = 0;
-
- cleanup:
- remoteEventCallbackFree(callback);
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(pool);
- virMutexUnlock(&priv->lock);
- return rv;
-}
-
-static int
-remoteDispatchConnectStoragePoolEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
- remote_connect_storage_pool_event_deregister_any_args *args)
-{
- int rv = -1;
- size_t i;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- virMutexLock(&priv->lock);
-
- for (i = 0; i < priv->nstorageEventCallbacks; i++) {
- if (priv->storageEventCallbacks[i]->callbackID == args->callbackID)
- break;
- }
- if (i == priv->nstorageEventCallbacks) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("storage pool event callback %d not registered"),
- args->callbackID);
- goto cleanup;
- }
-
- if (virConnectStoragePoolEventDeregisterAny(priv->conn, args->callbackID) < 0)
- goto cleanup;
-
- VIR_DELETE_ELEMENT(priv->storageEventCallbacks, i,
- priv->nstorageEventCallbacks);
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virMutexUnlock(&priv->lock);
- return rv;
-}
-
-static int
-remoteDispatchConnectNodeDeviceEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
- remote_connect_node_device_event_register_any_args *args,
- remote_connect_node_device_event_register_any_ret *ret)
-{
- int callbackID;
- int rv = -1;
- daemonClientEventCallbackPtr callback = NULL;
- daemonClientEventCallbackPtr ref;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
- virNodeDevicePtr dev = NULL;
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- virMutexLock(&priv->lock);
-
- if (args->dev &&
- !(dev = get_nonnull_node_device(priv->conn, *args->dev)))
- goto cleanup;
-
- if (args->eventID >= VIR_NODE_DEVICE_EVENT_ID_LAST || args->eventID < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unsupported node device event ID %d"), args->eventID);
- goto cleanup;
- }
-
- /* If we call register first, we could append a complete callback
- * to our array, but on OOM append failure, we'd have to then hope
- * deregister works to undo our register. So instead we append an
- * incomplete callback to our array, then register, then fix up
- * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
- * success, we use 'ref' to save a copy of the pointer. */
- if (VIR_ALLOC(callback) < 0)
- goto cleanup;
- callback->client = virObjectRef(client);
- callback->eventID = args->eventID;
- callback->callbackID = -1;
- ref = callback;
- if (VIR_APPEND_ELEMENT(priv->nodeDeviceEventCallbacks,
- priv->nnodeDeviceEventCallbacks,
- callback) < 0)
- goto cleanup;
-
- if ((callbackID = virConnectNodeDeviceEventRegisterAny(priv->conn,
- dev,
- args->eventID,
- nodeDeviceEventCallbacks[args->eventID],
- ref,
- remoteEventCallbackFree)) < 0) {
- VIR_SHRINK_N(priv->nodeDeviceEventCallbacks,
- priv->nnodeDeviceEventCallbacks, 1);
- callback = ref;
- goto cleanup;
- }
-
- ref->callbackID = callbackID;
- ret->callbackID = callbackID;
-
- rv = 0;
-
- cleanup:
- remoteEventCallbackFree(callback);
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dev);
- virMutexUnlock(&priv->lock);
- return rv;
-}
-
-static int
-remoteDispatchConnectNodeDeviceEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
- remote_connect_node_device_event_deregister_any_args *args)
-{
- int rv = -1;
- size_t i;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- virMutexLock(&priv->lock);
-
- for (i = 0; i < priv->nnodeDeviceEventCallbacks; i++) {
- if (priv->nodeDeviceEventCallbacks[i]->callbackID == args->callbackID)
- break;
- }
- if (i == priv->nnodeDeviceEventCallbacks) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("node device event callback %d not registered"),
- args->callbackID);
- goto cleanup;
- }
-
- if (virConnectNodeDeviceEventDeregisterAny(priv->conn, args->callbackID) < 0)
- goto cleanup;
-
- VIR_DELETE_ELEMENT(priv->nodeDeviceEventCallbacks, i,
- priv->nnodeDeviceEventCallbacks);
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virMutexUnlock(&priv->lock);
- return rv;
-}
-
-static int
-remoteDispatchConnectSecretEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
- remote_connect_secret_event_register_any_args *args,
- remote_connect_secret_event_register_any_ret *ret)
-{
- int callbackID;
- int rv = -1;
- daemonClientEventCallbackPtr callback = NULL;
- daemonClientEventCallbackPtr ref;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
- virSecretPtr secret = NULL;
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- virMutexLock(&priv->lock);
-
- if (args->secret &&
- !(secret = get_nonnull_secret(priv->conn, *args->secret)))
- goto cleanup;
-
- if (args->eventID >= VIR_SECRET_EVENT_ID_LAST || args->eventID < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unsupported secret event ID %d"), args->eventID);
- goto cleanup;
- }
-
- /* If we call register first, we could append a complete callback
- * to our array, but on OOM append failure, we'd have to then hope
- * deregister works to undo our register. So instead we append an
- * incomplete callback to our array, then register, then fix up
- * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
- * success, we use 'ref' to save a copy of the pointer. */
- if (VIR_ALLOC(callback) < 0)
- goto cleanup;
- callback->client = virObjectRef(client);
- callback->eventID = args->eventID;
- callback->callbackID = -1;
- ref = callback;
- if (VIR_APPEND_ELEMENT(priv->secretEventCallbacks,
- priv->nsecretEventCallbacks,
- callback) < 0)
- goto cleanup;
-
- if ((callbackID = virConnectSecretEventRegisterAny(priv->conn,
- secret,
- args->eventID,
- secretEventCallbacks[args->eventID],
- ref,
- remoteEventCallbackFree)) < 0) {
- VIR_SHRINK_N(priv->secretEventCallbacks,
- priv->nsecretEventCallbacks, 1);
- callback = ref;
- goto cleanup;
- }
-
- ref->callbackID = callbackID;
- ret->callbackID = callbackID;
-
- rv = 0;
-
- cleanup:
- remoteEventCallbackFree(callback);
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(secret);
- virMutexUnlock(&priv->lock);
- return rv;
-}
-
-static int
-remoteDispatchConnectSecretEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
- remote_connect_secret_event_deregister_any_args *args)
-{
- int rv = -1;
- size_t i;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- virMutexLock(&priv->lock);
-
- for (i = 0; i < priv->nsecretEventCallbacks; i++) {
- if (priv->secretEventCallbacks[i]->callbackID == args->callbackID)
- break;
- }
- if (i == priv->nsecretEventCallbacks) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("node device event callback %d not registered"),
- args->callbackID);
- goto cleanup;
- }
-
- if (virConnectSecretEventDeregisterAny(priv->conn, args->callbackID) < 0)
- goto cleanup;
-
- VIR_DELETE_ELEMENT(priv->secretEventCallbacks, i,
- priv->nsecretEventCallbacks);
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virMutexUnlock(&priv->lock);
- return rv;
-}
-
-static int
-qemuDispatchConnectDomainMonitorEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
- qemu_connect_domain_monitor_event_register_args *args,
- qemu_connect_domain_monitor_event_register_ret *ret)
-{
- int callbackID;
- int rv = -1;
- daemonClientEventCallbackPtr callback = NULL;
- daemonClientEventCallbackPtr ref;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
- virDomainPtr dom = NULL;
- const char *event = args->event ? *args->event : NULL;
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- virMutexLock(&priv->lock);
-
- if (args->dom &&
- !(dom = get_nonnull_domain(priv->conn, *args->dom)))
- goto cleanup;
-
- /* If we call register first, we could append a complete callback
- * to our array, but on OOM append failure, we'd have to then hope
- * deregister works to undo our register. So instead we append an
- * incomplete callback to our array, then register, then fix up
- * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
- * success, we use 'ref' to save a copy of the pointer. */
- if (VIR_ALLOC(callback) < 0)
- goto cleanup;
- callback->client = virObjectRef(client);
- callback->callbackID = -1;
- ref = callback;
- if (VIR_APPEND_ELEMENT(priv->qemuEventCallbacks,
- priv->nqemuEventCallbacks,
- callback) < 0)
- goto cleanup;
-
- if ((callbackID = virConnectDomainQemuMonitorEventRegister(priv->conn,
- dom,
- event,
- remoteRelayDomainQemuMonitorEvent,
- ref,
- remoteEventCallbackFree,
- args->flags)) < 0) {
- VIR_SHRINK_N(priv->qemuEventCallbacks,
- priv->nqemuEventCallbacks, 1);
- callback = ref;
- goto cleanup;
- }
-
- ref->callbackID = callbackID;
- ret->callbackID = callbackID;
-
- rv = 0;
-
- cleanup:
- remoteEventCallbackFree(callback);
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- virMutexUnlock(&priv->lock);
- return rv;
-}
-
-
-static int
-qemuDispatchConnectDomainMonitorEventDeregister(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
- qemu_connect_domain_monitor_event_deregister_args *args)
-{
- int rv = -1;
- size_t i;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- virMutexLock(&priv->lock);
-
- for (i = 0; i < priv->nqemuEventCallbacks; i++) {
- if (priv->qemuEventCallbacks[i]->callbackID == args->callbackID)
- break;
- }
- if (i == priv->nqemuEventCallbacks) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("qemu monitor event callback %d not registered"),
- args->callbackID);
- goto cleanup;
- }
-
- if (virConnectDomainQemuMonitorEventDeregister(priv->conn,
- args->callbackID) < 0)
- goto cleanup;
-
- VIR_DELETE_ELEMENT(priv->qemuEventCallbacks, i,
- priv->nqemuEventCallbacks);
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virMutexUnlock(&priv->lock);
- return rv;
-}
-
-static int
-remoteDispatchDomainGetTime(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_time_args *args,
- remote_domain_get_time_ret *ret)
-{
- int rv = -1;
- virDomainPtr dom = NULL;
- long long seconds;
- unsigned int nseconds;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if (virDomainGetTime(dom, &seconds, &nseconds, args->flags) < 0)
- goto cleanup;
-
- ret->seconds = seconds;
- ret->nseconds = nseconds;
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(dom);
- return rv;
-}
-
-
-static int
-remoteDispatchNodeGetFreePages(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_node_get_free_pages_args *args,
- remote_node_get_free_pages_ret *ret)
-{
- int rv = -1;
- int len;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (args->pages.pages_len * args->cellCount > REMOTE_NODE_MAX_CELLS) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("the result won't fit into REMOTE_NODE_MAX_CELLS"));
- goto cleanup;
- }
-
- /* Allocate return buffer. */
- if (VIR_ALLOC_N(ret->counts.counts_val,
- args->pages.pages_len * args->cellCount) < 0)
- goto cleanup;
-
- if ((len = virNodeGetFreePages(priv->conn,
- args->pages.pages_len,
- args->pages.pages_val,
- args->startCell,
- args->cellCount,
- (unsigned long long *) ret->counts.counts_val,
- args->flags)) <= 0)
- goto cleanup;
-
- ret->counts.counts_len = len;
- rv = 0;
-
- cleanup:
- if (rv < 0) {
- virNetMessageSaveError(rerr);
- VIR_FREE(ret->counts.counts_val);
- }
- return rv;
-}
-
-/* Copy contents of virNetworkDHCPLeasePtr to remote_network_dhcp_lease */
-static int
-remoteSerializeDHCPLease(remote_network_dhcp_lease *lease_dst, virNetworkDHCPLeasePtr lease_src)
-{
- char **mac_tmp = NULL;
- char **iaid_tmp = NULL;
- char **hostname_tmp = NULL;
- char **clientid_tmp = NULL;
-
- lease_dst->expirytime = lease_src->expirytime;
- lease_dst->type = lease_src->type;
- lease_dst->prefix = lease_src->prefix;
-
- if (VIR_STRDUP(lease_dst->iface, lease_src->iface) < 0 ||
- VIR_STRDUP(lease_dst->ipaddr, lease_src->ipaddr) < 0)
- goto error;
-
- if (lease_src->mac) {
- if (VIR_ALLOC(mac_tmp) < 0 ||
- VIR_STRDUP(*mac_tmp, lease_src->mac) < 0)
- goto error;
- }
- if (lease_src->iaid) {
- if (VIR_ALLOC(iaid_tmp) < 0 ||
- VIR_STRDUP(*iaid_tmp, lease_src->iaid) < 0)
- goto error;
- }
- if (lease_src->hostname) {
- if (VIR_ALLOC(hostname_tmp) < 0 ||
- VIR_STRDUP(*hostname_tmp, lease_src->hostname) < 0)
- goto error;
- }
- if (lease_src->clientid) {
- if (VIR_ALLOC(clientid_tmp) < 0 ||
- VIR_STRDUP(*clientid_tmp, lease_src->clientid) < 0)
- goto error;
- }
-
- lease_dst->mac = mac_tmp;
- lease_dst->iaid = iaid_tmp;
- lease_dst->hostname = hostname_tmp;
- lease_dst->clientid = clientid_tmp;
-
- return 0;
-
- error:
- if (mac_tmp)
- VIR_FREE(*mac_tmp);
- if (iaid_tmp)
- VIR_FREE(*iaid_tmp);
- if (hostname_tmp)
- VIR_FREE(*hostname_tmp);
- if (clientid_tmp)
- VIR_FREE(*clientid_tmp);
- VIR_FREE(mac_tmp);
- VIR_FREE(iaid_tmp);
- VIR_FREE(hostname_tmp);
- VIR_FREE(clientid_tmp);
- VIR_FREE(lease_dst->ipaddr);
- VIR_FREE(lease_dst->iface);
- return -1;
-}
-
-
-static int
-remoteDispatchNetworkGetDHCPLeases(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_network_get_dhcp_leases_args *args,
- remote_network_get_dhcp_leases_ret *ret)
-{
- int rv = -1;
- size_t i;
- struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
- virNetworkDHCPLeasePtr *leases = NULL;
- virNetworkPtr net = NULL;
- int nleases = 0;
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(net = get_nonnull_network(priv->conn, args->net)))
- goto cleanup;
-
- if ((nleases = virNetworkGetDHCPLeases(net,
- args->mac ? *args->mac : NULL,
- args->need_results ? &leases : NULL,
- args->flags)) < 0)
- goto cleanup;
-
- if (nleases > REMOTE_NETWORK_DHCP_LEASES_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Number of leases is %d, which exceeds max limit: %d"),
- nleases, REMOTE_NETWORK_DHCP_LEASES_MAX);
- goto cleanup;
- }
-
- if (leases && nleases) {
- if (VIR_ALLOC_N(ret->leases.leases_val, nleases) < 0)
- goto cleanup;
-
- ret->leases.leases_len = nleases;
-
- for (i = 0; i < nleases; i++) {
- if (remoteSerializeDHCPLease(ret->leases.leases_val + i, leases[i]) < 0)
- goto cleanup;
- }
-
- } else {
- ret->leases.leases_len = 0;
- ret->leases.leases_val = NULL;
- }
-
- ret->ret = nleases;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- if (leases && nleases > 0)
- for (i = 0; i < nleases; i++)
- virNetworkDHCPLeaseFree(leases[i]);
- VIR_FREE(leases);
- virObjectUnref(net);
- return rv;
-}
-
-
-static int
-remoteDispatchConnectGetAllDomainStats(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_connect_get_all_domain_stats_args *args,
- remote_connect_get_all_domain_stats_ret *ret)
-{
- int rv = -1;
- size_t i;
- struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
- virDomainStatsRecordPtr *retStats = NULL;
- int nrecords = 0;
- virDomainPtr *doms = NULL;
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (args->doms.doms_len) {
- if (VIR_ALLOC_N(doms, args->doms.doms_len + 1) < 0)
- goto cleanup;
-
- for (i = 0; i < args->doms.doms_len; i++) {
- if (!(doms[i] = get_nonnull_domain(priv->conn, args->doms.doms_val[i])))
- goto cleanup;
- }
-
- if ((nrecords = virDomainListGetStats(doms,
- args->stats,
- &retStats,
- args->flags)) < 0)
- goto cleanup;
- } else {
- if ((nrecords = virConnectGetAllDomainStats(priv->conn,
- args->stats,
- &retStats,
- args->flags)) < 0)
- goto cleanup;
- }
-
- if (nrecords > REMOTE_CONNECT_GET_ALL_DOMAIN_STATS_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Number of domain stats records is %d, "
- "which exceeds max limit: %d"),
- nrecords, REMOTE_CONNECT_GET_ALL_DOMAIN_STATS_MAX);
- goto cleanup;
- }
-
- if (nrecords) {
- if (VIR_ALLOC_N(ret->retStats.retStats_val, nrecords) < 0)
- goto cleanup;
-
- ret->retStats.retStats_len = nrecords;
-
- for (i = 0; i < nrecords; i++) {
- remote_domain_stats_record *dst = ret->retStats.retStats_val + i;
-
- make_nonnull_domain(&dst->dom, retStats[i]->dom);
-
- if (virTypedParamsSerialize(retStats[i]->params,
- retStats[i]->nparams,
- (virTypedParameterRemotePtr *) &dst->params.params_val,
- &dst->params.params_len,
- VIR_TYPED_PARAM_STRING_OKAY) < 0)
- goto cleanup;
- }
- } else {
- ret->retStats.retStats_len = 0;
- ret->retStats.retStats_val = NULL;
- }
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
-
- virDomainStatsRecordListFree(retStats);
- virObjectListFree(doms);
-
- return rv;
-}
-
-
-static int
-remoteDispatchNodeAllocPages(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_node_alloc_pages_args *args,
- remote_node_alloc_pages_ret *ret)
-{
- int rv = -1;
- int len;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if ((len = virNodeAllocPages(priv->conn,
- args->pageSizes.pageSizes_len,
- args->pageSizes.pageSizes_val,
- (unsigned long long *) args->pageCounts.pageCounts_val,
- args->startCell,
- args->cellCount,
- args->flags)) < 0)
- goto cleanup;
-
- ret->ret = len;
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- return rv;
-}
-
-
-static int
-remoteDispatchDomainGetFSInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_get_fsinfo_args *args,
- remote_domain_get_fsinfo_ret *ret)
-{
- int rv = -1;
- size_t i, j;
- struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
- virDomainFSInfoPtr *info = NULL;
- virDomainPtr dom = NULL;
- remote_domain_fsinfo *dst;
- int ninfo = 0;
- size_t ndisk;
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if ((ninfo = virDomainGetFSInfo(dom, &info, args->flags)) < 0)
- goto cleanup;
-
- if (ninfo > REMOTE_DOMAIN_FSINFO_MAX) {
- virReportError(VIR_ERR_RPC,
- _("Too many mountpoints in fsinfo: %d for limit %d"),
- ninfo, REMOTE_DOMAIN_FSINFO_MAX);
- goto cleanup;
- }
-
- if (ninfo) {
- if (VIR_ALLOC_N(ret->info.info_val, ninfo) < 0)
- goto cleanup;
-
- ret->info.info_len = ninfo;
-
- for (i = 0; i < ninfo; i++) {
- dst = &ret->info.info_val[i];
- if (VIR_STRDUP(dst->mountpoint, info[i]->mountpoint) < 0)
- goto cleanup;
-
- if (VIR_STRDUP(dst->name, info[i]->name) < 0)
- goto cleanup;
-
- if (VIR_STRDUP(dst->fstype, info[i]->fstype) < 0)
- goto cleanup;
-
- ndisk = info[i]->ndevAlias;
- if (ndisk > REMOTE_DOMAIN_FSINFO_DISKS_MAX) {
- virReportError(VIR_ERR_RPC,
- _("Too many disks in fsinfo: %zd for limit %d"),
- ndisk, REMOTE_DOMAIN_FSINFO_DISKS_MAX);
- goto cleanup;
- }
-
- if (ndisk > 0) {
- if (VIR_ALLOC_N(dst->dev_aliases.dev_aliases_val, ndisk) < 0)
- goto cleanup;
-
- for (j = 0; j < ndisk; j++) {
- if (VIR_STRDUP(dst->dev_aliases.dev_aliases_val[j],
- info[i]->devAlias[j]) < 0)
- goto cleanup;
- }
-
- dst->dev_aliases.dev_aliases_len = ndisk;
- } else {
- dst->dev_aliases.dev_aliases_val = NULL;
- dst->dev_aliases.dev_aliases_len = 0;
- }
- }
-
- } else {
- ret->info.info_len = 0;
- ret->info.info_val = NULL;
- }
-
- ret->ret = ninfo;
-
- rv = 0;
-
- cleanup:
- if (rv < 0) {
- virNetMessageSaveError(rerr);
-
- if (ret->info.info_val && ninfo > 0) {
- for (i = 0; i < ninfo; i++) {
- dst = &ret->info.info_val[i];
- VIR_FREE(dst->mountpoint);
- if (dst->dev_aliases.dev_aliases_val) {
- for (j = 0; j < dst->dev_aliases.dev_aliases_len; j++)
- VIR_FREE(dst->dev_aliases.dev_aliases_val[j]);
- VIR_FREE(dst->dev_aliases.dev_aliases_val);
- }
- }
- VIR_FREE(ret->info.info_val);
- }
- }
- virObjectUnref(dom);
- if (ninfo >= 0)
- for (i = 0; i < ninfo; i++)
- virDomainFSInfoFree(info[i]);
- VIR_FREE(info);
-
- return rv;
-}
-
-
-static int
-remoteSerializeDomainInterface(virDomainInterfacePtr *ifaces,
- unsigned int ifaces_count,
- remote_domain_interface_addresses_ret *ret)
-{
- size_t i, j;
-
- if (ifaces_count > REMOTE_DOMAIN_INTERFACE_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Number of interfaces, %d exceeds the max limit: %d"),
- ifaces_count, REMOTE_DOMAIN_INTERFACE_MAX);
- return -1;
- }
-
- if (VIR_ALLOC_N(ret->ifaces.ifaces_val, ifaces_count) < 0)
- return -1;
-
- ret->ifaces.ifaces_len = ifaces_count;
-
- for (i = 0; i < ifaces_count; i++) {
- virDomainInterfacePtr iface = ifaces[i];
- remote_domain_interface *iface_ret = &(ret->ifaces.ifaces_val[i]);
-
- if ((VIR_STRDUP(iface_ret->name, iface->name)) < 0)
- goto cleanup;
-
- if (iface->hwaddr &&
- (VIR_ALLOC(iface_ret->hwaddr) < 0 ||
- VIR_STRDUP(*iface_ret->hwaddr, iface->hwaddr) < 0))
- goto cleanup;
-
- if (iface->naddrs > REMOTE_DOMAIN_IP_ADDR_MAX) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Number of interfaces, %d exceeds the max limit: %d"),
- iface->naddrs, REMOTE_DOMAIN_IP_ADDR_MAX);
- goto cleanup;
- }
-
- if (VIR_ALLOC_N(iface_ret->addrs.addrs_val,
- iface->naddrs) < 0)
- goto cleanup;
-
- iface_ret->addrs.addrs_len = iface->naddrs;
-
- for (j = 0; j < iface->naddrs; j++) {
- virDomainIPAddressPtr ip_addr = &(iface->addrs[j]);
- remote_domain_ip_addr *ip_addr_ret =
- &(iface_ret->addrs.addrs_val[j]);
-
- if (VIR_STRDUP(ip_addr_ret->addr, ip_addr->addr) < 0)
- goto cleanup;
-
- ip_addr_ret->prefix = ip_addr->prefix;
- ip_addr_ret->type = ip_addr->type;
- }
- }
-
- return 0;
-
- cleanup:
- if (ret->ifaces.ifaces_val) {
- for (i = 0; i < ifaces_count; i++) {
- remote_domain_interface *iface_ret = &(ret->ifaces.ifaces_val[i]);
- VIR_FREE(iface_ret->name);
- if (iface_ret->hwaddr) {
- VIR_FREE(*iface_ret->hwaddr);
- VIR_FREE(iface_ret->hwaddr);
- }
- for (j = 0; j < iface_ret->addrs.addrs_len; j++) {
- remote_domain_ip_addr *ip_addr =
- &(iface_ret->addrs.addrs_val[j]);
- VIR_FREE(ip_addr->addr);
- }
- }
- VIR_FREE(ret->ifaces.ifaces_val);
- }
-
- return -1;
-}
-
-
-static int
-remoteDispatchDomainInterfaceAddresses(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_domain_interface_addresses_args *args,
- remote_domain_interface_addresses_ret *ret)
-{
- size_t i;
- int rv = -1;
- virDomainPtr dom = NULL;
- virDomainInterfacePtr *ifaces = NULL;
- int ifaces_count = 0;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
- goto cleanup;
-
- if ((ifaces_count = virDomainInterfaceAddresses(dom, &ifaces, args->source, args->flags)) < 0)
- goto cleanup;
-
- if (remoteSerializeDomainInterface(ifaces, ifaces_count, ret) < 0)
- goto cleanup;
-
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
-
- virObjectUnref(dom);
-
- if (ifaces && ifaces_count > 0) {
- for (i = 0; i < ifaces_count; i++)
- virDomainInterfaceFree(ifaces[i]);
- }
- VIR_FREE(ifaces);
-
- return rv;
-}
-
-
-static int
-remoteDispatchStorageVolGetInfoFlags(virNetServerPtr server ATTRIBUTE_UNUSED,
- virNetServerClientPtr client,
- virNetMessagePtr msg ATTRIBUTE_UNUSED,
- virNetMessageErrorPtr rerr,
- remote_storage_vol_get_info_flags_args *args,
- remote_storage_vol_get_info_flags_ret *ret)
-{
- int rv = -1;
- virStorageVolPtr vol = NULL;
- virStorageVolInfo tmp;
- struct daemonClientPrivate *priv =
- virNetServerClientGetPrivateData(client);
-
- if (!priv->conn) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
- goto cleanup;
- }
-
- if (!(vol = get_nonnull_storage_vol(priv->conn, args->vol)))
- goto cleanup;
-
- if (virStorageVolGetInfoFlags(vol, &tmp, args->flags) < 0)
- goto cleanup;
-
- ret->type = tmp.type;
- ret->capacity = tmp.capacity;
- ret->allocation = tmp.allocation;
- rv = 0;
-
- cleanup:
- if (rv < 0)
- virNetMessageSaveError(rerr);
- virObjectUnref(vol);
- return rv;
-}
-
-
-/*----- Helpers. -----*/
-
-/* get_nonnull_domain and get_nonnull_network turn an on-wire
- * (name, uuid) pair into virDomainPtr or virNetworkPtr object.
- * virDomainPtr or virNetworkPtr cannot be NULL.
- *
- * NB. If these return NULL then the caller must return an error.
- */
-static virDomainPtr
-get_nonnull_domain(virConnectPtr conn, remote_nonnull_domain domain)
-{
- /* Should we believe the domain.id sent by the client? Maybe
- * this should be a check rather than an assignment? XXX
- */
- return virGetDomain(conn, domain.name, BAD_CAST domain.uuid, domain.id);
-}
-
-static virNetworkPtr
-get_nonnull_network(virConnectPtr conn, remote_nonnull_network network)
-{
- return virGetNetwork(conn, network.name, BAD_CAST network.uuid);
-}
-
-static virInterfacePtr
-get_nonnull_interface(virConnectPtr conn, remote_nonnull_interface iface)
-{
- return virGetInterface(conn, iface.name, iface.mac);
-}
-
-static virStoragePoolPtr
-get_nonnull_storage_pool(virConnectPtr conn, remote_nonnull_storage_pool pool)
-{
- return virGetStoragePool(conn, pool.name, BAD_CAST pool.uuid,
- NULL, NULL);
-}
-
-static virStorageVolPtr
-get_nonnull_storage_vol(virConnectPtr conn, remote_nonnull_storage_vol vol)
-{
- virStorageVolPtr ret;
- ret = virGetStorageVol(conn, vol.pool, vol.name, vol.key,
- NULL, NULL);
- return ret;
-}
-
-static virSecretPtr
-get_nonnull_secret(virConnectPtr conn, remote_nonnull_secret secret)
-{
- return virGetSecret(conn, BAD_CAST secret.uuid, secret.usageType, secret.usageID);
-}
-
-static virNWFilterPtr
-get_nonnull_nwfilter(virConnectPtr conn, remote_nonnull_nwfilter nwfilter)
-{
- return virGetNWFilter(conn, nwfilter.name, BAD_CAST nwfilter.uuid);
-}
-
-static virDomainSnapshotPtr
-get_nonnull_domain_snapshot(virDomainPtr dom, remote_nonnull_domain_snapshot snapshot)
-{
- return virGetDomainSnapshot(dom, snapshot.name);
-}
-
-static virNodeDevicePtr
-get_nonnull_node_device(virConnectPtr conn, remote_nonnull_node_device dev)
-{
- return virGetNodeDevice(conn, dev.name);
-}
-
-/* Make remote_nonnull_domain and remote_nonnull_network. */
-static void
-make_nonnull_domain(remote_nonnull_domain *dom_dst, virDomainPtr dom_src)
-{
- dom_dst->id = dom_src->id;
- ignore_value(VIR_STRDUP_QUIET(dom_dst->name, dom_src->name));
- memcpy(dom_dst->uuid, dom_src->uuid, VIR_UUID_BUFLEN);
-}
-
-static void
-make_nonnull_network(remote_nonnull_network *net_dst, virNetworkPtr net_src)
-{
- ignore_value(VIR_STRDUP_QUIET(net_dst->name, net_src->name));
- memcpy(net_dst->uuid, net_src->uuid, VIR_UUID_BUFLEN);
-}
-
-static void
-make_nonnull_interface(remote_nonnull_interface *interface_dst,
- virInterfacePtr interface_src)
-{
- ignore_value(VIR_STRDUP_QUIET(interface_dst->name, interface_src->name));
- ignore_value(VIR_STRDUP_QUIET(interface_dst->mac, interface_src->mac));
-}
-
-static void
-make_nonnull_storage_pool(remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr pool_src)
-{
- ignore_value(VIR_STRDUP_QUIET(pool_dst->name, pool_src->name));
- memcpy(pool_dst->uuid, pool_src->uuid, VIR_UUID_BUFLEN);
-}
-
-static void
-make_nonnull_storage_vol(remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src)
-{
- ignore_value(VIR_STRDUP_QUIET(vol_dst->pool, vol_src->pool));
- ignore_value(VIR_STRDUP_QUIET(vol_dst->name, vol_src->name));
- ignore_value(VIR_STRDUP_QUIET(vol_dst->key, vol_src->key));
-}
-
-static void
-make_nonnull_node_device(remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src)
-{
- ignore_value(VIR_STRDUP_QUIET(dev_dst->name, dev_src->name));
-}
-
-static void
-make_nonnull_secret(remote_nonnull_secret *secret_dst, virSecretPtr secret_src)
-{
- memcpy(secret_dst->uuid, secret_src->uuid, VIR_UUID_BUFLEN);
- secret_dst->usageType = secret_src->usageType;
- ignore_value(VIR_STRDUP_QUIET(secret_dst->usageID, secret_src->usageID));
-}
-
-static void
-make_nonnull_nwfilter(remote_nonnull_nwfilter *nwfilter_dst, virNWFilterPtr nwfilter_src)
-{
- ignore_value(VIR_STRDUP_QUIET(nwfilter_dst->name, nwfilter_src->name));
- memcpy(nwfilter_dst->uuid, nwfilter_src->uuid, VIR_UUID_BUFLEN);
-}
-
-static void
-make_nonnull_domain_snapshot(remote_nonnull_domain_snapshot *snapshot_dst, virDomainSnapshotPtr snapshot_src)
-{
- ignore_value(VIR_STRDUP_QUIET(snapshot_dst->name, snapshot_src->name));
- make_nonnull_domain(&snapshot_dst->dom, snapshot_src->domain);
-}
-
-static int
-remoteSerializeDomainDiskErrors(virDomainDiskErrorPtr errors,
- int nerrors,
- remote_domain_disk_error **ret_errors_val,
- u_int *ret_errors_len)
-{
- remote_domain_disk_error *val = NULL;
- size_t i = 0;
-
- if (VIR_ALLOC_N(val, nerrors) < 0)
- goto error;
-
- for (i = 0; i < nerrors; i++) {
- if (VIR_STRDUP(val[i].disk, errors[i].disk) < 0)
- goto error;
- val[i].error = errors[i].error;
- }
-
- *ret_errors_len = nerrors;
- *ret_errors_val = val;
-
- return 0;
-
- error:
- if (val) {
- size_t j;
- for (j = 0; j < i; j++)
- VIR_FREE(val[j].disk);
- VIR_FREE(val);
- }
- return -1;
-}
+++ /dev/null
-/*
- * remote.h: handlers for RPC method calls
- *
- * Copyright (C) 2007, 2008, 2009 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: Richard W.M. Jones <rjones@redhat.com>
- * Author: Daniel P. Berrange <berrange@redhat.com>
- */
-
-#ifndef __LIBVIRTD_REMOTE_H__
-# define __LIBVIRTD_REMOTE_H__
-
-# include "remote_protocol.h"
-# include "rpc/virnetserverprogram.h"
-# include "rpc/virnetserverclient.h"
-
-
-extern virNetServerProgramProc remoteProcs[];
-extern size_t remoteNProcs;
-
-extern virNetServerProgramProc lxcProcs[];
-extern size_t lxcNProcs;
-
-extern virNetServerProgramProc qemuProcs[];
-extern size_t qemuNProcs;
-
-void remoteClientFree(void *data);
-void *remoteClientNew(virNetServerClientPtr client,
- void *opaque);
-
-#endif /* __LIBVIRTD_REMOTE_H__ */
+++ /dev/null
-/*
- * stream.c: APIs for managing client streams
- *
- * Copyright (C) 2009-2014 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 "stream.h"
-#include "remote.h"
-#include "viralloc.h"
-#include "virlog.h"
-#include "virnetserverclient.h"
-#include "virerror.h"
-#include "libvirt_internal.h"
-
-#define VIR_FROM_THIS VIR_FROM_STREAMS
-
-VIR_LOG_INIT("daemon.stream");
-
-struct daemonClientStream {
- daemonClientPrivatePtr priv;
- int refs;
-
- virNetServerProgramPtr prog;
-
- virStreamPtr st;
- int procedure;
- unsigned int serial;
-
- bool recvEOF;
- bool closed;
-
- int filterID;
-
- virNetMessagePtr rx;
- bool tx;
-
- bool allowSkip;
- size_t dataLen; /* How much data is there remaining until we see a hole */
-
- daemonClientStreamPtr next;
-};
-
-static int
-daemonStreamHandleWrite(virNetServerClientPtr client,
- daemonClientStream *stream);
-static int
-daemonStreamHandleRead(virNetServerClientPtr client,
- daemonClientStream *stream);
-static int
-daemonStreamHandleFinish(virNetServerClientPtr client,
- daemonClientStream *stream,
- virNetMessagePtr msg);
-static int
-daemonStreamHandleAbort(virNetServerClientPtr client,
- daemonClientStream *stream,
- virNetMessagePtr msg);
-
-
-
-static void
-daemonStreamUpdateEvents(daemonClientStream *stream)
-{
- int newEvents = 0;
- if (stream->closed)
- return;
- if (stream->rx)
- newEvents |= VIR_STREAM_EVENT_WRITABLE;
- if (stream->tx && !stream->recvEOF)
- newEvents |= VIR_STREAM_EVENT_READABLE;
-
- virStreamEventUpdateCallback(stream->st, newEvents);
-}
-
-/*
- * Invoked when an outgoing data packet message has been fully sent.
- * This simply re-enables TX of further data.
- *
- * The idea is to stop the daemon growing without bound due to
- * fast stream, but slow client
- */
-static void
-daemonStreamMessageFinished(virNetMessagePtr msg,
- void *opaque)
-{
- daemonClientStream *stream = opaque;
- VIR_DEBUG("stream=%p proc=%d serial=%u",
- stream, msg->header.proc, msg->header.serial);
-
- stream->tx = true;
- daemonStreamUpdateEvents(stream);
-
- daemonFreeClientStream(NULL, stream);
-}
-
-
-/*
- * Callback that gets invoked when a stream becomes writable/readable
- */
-static void
-daemonStreamEvent(virStreamPtr st, int events, void *opaque)
-{
- virNetServerClientPtr client = opaque;
- daemonClientStream *stream;
- daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
-
- virMutexLock(&priv->lock);
-
- stream = priv->streams;
- while (stream) {
- if (stream->st == st)
- break;
- stream = stream->next;
- }
-
- if (!stream) {
- VIR_WARN("event for client=%p stream st=%p, but missing stream state", client, st);
- virStreamEventRemoveCallback(st);
- goto cleanup;
- }
-
- VIR_DEBUG("st=%p events=%d EOF=%d closed=%d", st, events, stream->recvEOF, stream->closed);
-
- if (!stream->closed &&
- (events & VIR_STREAM_EVENT_WRITABLE)) {
- if (daemonStreamHandleWrite(client, stream) < 0) {
- daemonRemoveClientStream(client, stream);
- virNetServerClientClose(client);
- goto cleanup;
- }
- }
-
- if (!stream->closed && !stream->recvEOF &&
- (events & (VIR_STREAM_EVENT_READABLE))) {
- events = events & ~(VIR_STREAM_EVENT_READABLE);
- if (daemonStreamHandleRead(client, stream) < 0) {
- daemonRemoveClientStream(client, stream);
- virNetServerClientClose(client);
- goto cleanup;
- }
- /* If we detected EOF during read processing,
- * then clear hangup/error conditions, since
- * we want the client to see the EOF message
- * we just sent them
- */
- if (stream->recvEOF)
- events = events & ~(VIR_STREAM_EVENT_HANGUP |
- VIR_STREAM_EVENT_ERROR);
- }
-
- /* If we have a completion/abort message, always process it */
- if (stream->rx) {
- virNetMessagePtr msg = stream->rx;
- switch (msg->header.status) {
- case VIR_NET_CONTINUE:
- /* nada */
- break;
- case VIR_NET_OK:
- virNetMessageQueueServe(&stream->rx);
- if (daemonStreamHandleFinish(client, stream, msg) < 0) {
- virNetMessageFree(msg);
- daemonRemoveClientStream(client, stream);
- virNetServerClientClose(client);
- goto cleanup;
- }
- break;
- case VIR_NET_ERROR:
- default:
- virNetMessageQueueServe(&stream->rx);
- if (daemonStreamHandleAbort(client, stream, msg) < 0) {
- virNetMessageFree(msg);
- daemonRemoveClientStream(client, stream);
- virNetServerClientClose(client);
- goto cleanup;
- }
- break;
- }
- }
-
-
- /* If we got HANGUP, we need to only send an empty
- * packet so the client sees an EOF and cleans up
- */
- if (!stream->closed && !stream->recvEOF &&
- (events & VIR_STREAM_EVENT_HANGUP)) {
- virNetMessagePtr msg;
- events &= ~(VIR_STREAM_EVENT_HANGUP);
- stream->tx = false;
- stream->recvEOF = true;
- if (!(msg = virNetMessageNew(false))) {
- daemonRemoveClientStream(client, stream);
- virNetServerClientClose(client);
- goto cleanup;
- }
- msg->cb = daemonStreamMessageFinished;
- msg->opaque = stream;
- stream->refs++;
- if (virNetServerProgramSendStreamData(remoteProgram,
- client,
- msg,
- stream->procedure,
- stream->serial,
- "", 0) < 0) {
- virNetMessageFree(msg);
- daemonRemoveClientStream(client, stream);
- virNetServerClientClose(client);
- goto cleanup;
- }
- }
-
- if (!stream->closed &&
- (events & (VIR_STREAM_EVENT_ERROR | VIR_STREAM_EVENT_HANGUP))) {
- int ret;
- virNetMessagePtr msg;
- virNetMessageError rerr;
- virErrorPtr origErr = virSaveLastError();
-
- memset(&rerr, 0, sizeof(rerr));
- stream->closed = true;
- virStreamEventRemoveCallback(stream->st);
- virStreamAbort(stream->st);
- if (origErr && origErr->code != VIR_ERR_OK) {
- virSetError(origErr);
- } else {
- if (events & VIR_STREAM_EVENT_HANGUP)
- virReportError(VIR_ERR_RPC,
- "%s", _("stream had unexpected termination"));
- else
- virReportError(VIR_ERR_RPC,
- "%s", _("stream had I/O failure"));
- }
- virFreeError(origErr);
-
- msg = virNetMessageNew(false);
- if (!msg) {
- ret = -1;
- } else {
- ret = virNetServerProgramSendStreamError(remoteProgram,
- client,
- msg,
- &rerr,
- stream->procedure,
- stream->serial);
- }
- daemonRemoveClientStream(client, stream);
- if (ret < 0)
- virNetServerClientClose(client);
- goto cleanup;
- }
-
- if (stream->closed) {
- daemonRemoveClientStream(client, stream);
- } else {
- daemonStreamUpdateEvents(stream);
- }
-
- cleanup:
- virMutexUnlock(&priv->lock);
-}
-
-
-/*
- * @client: a locked client object
- *
- * Invoked by the main loop when filtering incoming messages.
- *
- * Returns 1 if the message was processed, 0 if skipped,
- * -1 on fatal client error
- */
-static int
-daemonStreamFilter(virNetServerClientPtr client ATTRIBUTE_UNUSED,
- virNetMessagePtr msg,
- void *opaque)
-{
- daemonClientStream *stream = opaque;
- int ret = 0;
-
- virMutexLock(&stream->priv->lock);
-
- if (msg->header.type != VIR_NET_STREAM &&
- msg->header.type != VIR_NET_STREAM_HOLE)
- goto cleanup;
-
- if (!virNetServerProgramMatches(stream->prog, msg))
- goto cleanup;
-
- if (msg->header.proc != stream->procedure ||
- msg->header.serial != stream->serial)
- goto cleanup;
-
- VIR_DEBUG("Incoming client=%p, rx=%p, serial=%u, proc=%d, status=%d",
- client, stream->rx, msg->header.proc,
- msg->header.serial, msg->header.status);
-
- virNetMessageQueuePush(&stream->rx, msg);
- daemonStreamUpdateEvents(stream);
- ret = 1;
-
- cleanup:
- virMutexUnlock(&stream->priv->lock);
- return ret;
-}
-
-
-/*
- * @conn: a connection object to associate the stream with
- * @header: the method call to associate with the stream
- *
- * Creates a new stream for this conn
- *
- * Returns a new stream object, or NULL upon OOM
- */
-daemonClientStream *
-daemonCreateClientStream(virNetServerClientPtr client,
- virStreamPtr st,
- virNetServerProgramPtr prog,
- virNetMessageHeaderPtr header,
- bool allowSkip)
-{
- daemonClientStream *stream;
- daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
-
- VIR_DEBUG("client=%p, proc=%d, serial=%u, st=%p",
- client, header->proc, header->serial, st);
-
- if (VIR_ALLOC(stream) < 0)
- return NULL;
-
- stream->refs = 1;
- stream->priv = priv;
- stream->prog = virObjectRef(prog);
- stream->procedure = header->proc;
- stream->serial = header->serial;
- stream->filterID = -1;
- stream->st = st;
- stream->allowSkip = allowSkip;
-
- return stream;
-}
-
-/*
- * @stream: an unused client stream
- *
- * Frees the memory associated with this inactive client
- * stream
- */
-int daemonFreeClientStream(virNetServerClientPtr client,
- daemonClientStream *stream)
-{
- virNetMessagePtr msg;
- int ret = 0;
-
- if (!stream)
- return 0;
-
- stream->refs--;
- if (stream->refs)
- return 0;
-
- VIR_DEBUG("client=%p, proc=%d, serial=%u",
- client, stream->procedure, stream->serial);
-
- virObjectUnref(stream->prog);
-
- msg = stream->rx;
- while (msg) {
- virNetMessagePtr tmp = msg->next;
- if (client) {
- /* Send a dummy reply to free up 'msg' & unblock client rx */
- virNetMessageClear(msg);
- msg->header.type = VIR_NET_REPLY;
- if (virNetServerClientSendMessage(client, msg) < 0) {
- virNetServerClientImmediateClose(client);
- virNetMessageFree(msg);
- ret = -1;
- }
- } else {
- virNetMessageFree(msg);
- }
- msg = tmp;
- }
-
- virObjectUnref(stream->st);
- VIR_FREE(stream);
-
- return ret;
-}
-
-
-/*
- * @client: a locked client to add the stream to
- * @stream: a stream to add
- */
-int daemonAddClientStream(virNetServerClientPtr client,
- daemonClientStream *stream,
- bool transmit)
-{
- VIR_DEBUG("client=%p, proc=%d, serial=%u, st=%p, transmit=%d",
- client, stream->procedure, stream->serial, stream->st, transmit);
- daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
-
- if (stream->filterID != -1) {
- VIR_WARN("Filter already added to client %p", client);
- return -1;
- }
-
- if (virStreamEventAddCallback(stream->st, 0,
- daemonStreamEvent, client,
- virObjectFreeCallback) < 0)
- return -1;
-
- virObjectRef(client);
-
- if ((stream->filterID = virNetServerClientAddFilter(client,
- daemonStreamFilter,
- stream)) < 0) {
- virStreamEventRemoveCallback(stream->st);
- return -1;
- }
-
- if (transmit)
- stream->tx = true;
-
- virMutexLock(&priv->lock);
- stream->next = priv->streams;
- priv->streams = stream;
-
- daemonStreamUpdateEvents(stream);
-
- virMutexUnlock(&priv->lock);
-
- return 0;
-}
-
-
-/*
- * @client: a locked client object
- * @stream: an inactive, closed stream object
- *
- * Removes a stream from the list of active streams for the client
- *
- * Returns 0 if the stream was removed, -1 if it doesn't exist
- */
-int
-daemonRemoveClientStream(virNetServerClientPtr client,
- daemonClientStream *stream)
-{
- VIR_DEBUG("client=%p, proc=%d, serial=%u, st=%p",
- client, stream->procedure, stream->serial, stream->st);
- daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
- daemonClientStream *curr = priv->streams;
- daemonClientStream *prev = NULL;
-
- if (stream->filterID != -1) {
- virNetServerClientRemoveFilter(client,
- stream->filterID);
- stream->filterID = -1;
- }
-
- if (!stream->closed) {
- stream->closed = true;
- virStreamEventRemoveCallback(stream->st);
- virStreamAbort(stream->st);
- }
-
- while (curr) {
- if (curr == stream) {
- if (prev)
- prev->next = curr->next;
- else
- priv->streams = curr->next;
- return daemonFreeClientStream(client, stream);
- }
- prev = curr;
- curr = curr->next;
- }
- return -1;
-}
-
-
-void
-daemonRemoveAllClientStreams(daemonClientStream *stream)
-{
- daemonClientStream *tmp;
-
- VIR_DEBUG("stream=%p", stream);
-
- while (stream) {
- tmp = stream->next;
-
- if (!stream->closed) {
- stream->closed = true;
- virStreamEventRemoveCallback(stream->st);
- virStreamAbort(stream->st);
- }
-
- daemonFreeClientStream(NULL, stream);
-
- VIR_DEBUG("next stream=%p", tmp);
- stream = tmp;
- }
-}
-
-/*
- * Returns:
- * -1 if fatal error occurred
- * 0 if message was fully processed
- * 1 if message is still being processed
- */
-static int
-daemonStreamHandleWriteData(virNetServerClientPtr client,
- daemonClientStream *stream,
- virNetMessagePtr msg)
-{
- int ret;
-
- VIR_DEBUG("client=%p, stream=%p, proc=%d, serial=%u, len=%zu, offset=%zu",
- client, stream, msg->header.proc, msg->header.serial,
- msg->bufferLength, msg->bufferOffset);
-
- ret = virStreamSend(stream->st,
- msg->buffer + msg->bufferOffset,
- msg->bufferLength - msg->bufferOffset);
-
- if (ret > 0) {
- msg->bufferOffset += ret;
-
- /* Partial write, so indicate we have more todo later */
- if (msg->bufferOffset < msg->bufferLength)
- return 1;
- } else if (ret == -2) {
- /* Blocking, so indicate we have more todo later */
- return 1;
- } else {
- virNetMessageError rerr;
-
- memset(&rerr, 0, sizeof(rerr));
-
- VIR_INFO("Stream send failed");
- stream->closed = true;
- virStreamEventRemoveCallback(stream->st);
- virStreamAbort(stream->st);
-
- return virNetServerProgramSendReplyError(stream->prog,
- client,
- msg,
- &rerr,
- &msg->header);
- }
-
- return 0;
-}
-
-
-/*
- * Process a finish handshake from the client.
- *
- * Returns a VIR_NET_OK confirmation if successful, or a VIR_NET_ERROR
- * if there was a stream error
- *
- * Returns 0 if successfully sent RPC reply, -1 upon fatal error
- */
-static int
-daemonStreamHandleFinish(virNetServerClientPtr client,
- daemonClientStream *stream,
- virNetMessagePtr msg)
-{
- int ret;
-
- VIR_DEBUG("client=%p, stream=%p, proc=%d, serial=%u",
- client, stream, msg->header.proc, msg->header.serial);
-
- stream->closed = true;
- virStreamEventRemoveCallback(stream->st);
- ret = virStreamFinish(stream->st);
-
- if (ret < 0) {
- virNetMessageError rerr;
- memset(&rerr, 0, sizeof(rerr));
- return virNetServerProgramSendReplyError(stream->prog,
- client,
- msg,
- &rerr,
- &msg->header);
- } else {
- /* Send zero-length confirm */
- return virNetServerProgramSendStreamData(stream->prog,
- client,
- msg,
- stream->procedure,
- stream->serial,
- NULL, 0);
- }
-}
-
-
-/*
- * Process an abort request from the client.
- *
- * Returns 0 if successfully aborted, -1 upon error
- */
-static int
-daemonStreamHandleAbort(virNetServerClientPtr client,
- daemonClientStream *stream,
- virNetMessagePtr msg)
-{
- VIR_DEBUG("client=%p, stream=%p, proc=%d, serial=%u",
- client, stream, msg->header.proc, msg->header.serial);
- int ret;
- bool raise_error = false;
-
- stream->closed = true;
- virStreamEventRemoveCallback(stream->st);
- ret = virStreamAbort(stream->st);
-
- if (msg->header.status == VIR_NET_ERROR) {
- VIR_INFO("stream aborted at client request");
- raise_error = (ret < 0);
- } else {
- virReportError(VIR_ERR_RPC,
- _("stream aborted with unexpected status %d"),
- msg->header.status);
- raise_error = true;
- }
-
- if (raise_error) {
- virNetMessageError rerr;
- memset(&rerr, 0, sizeof(rerr));
- return virNetServerProgramSendReplyError(remoteProgram,
- client,
- msg,
- &rerr,
- &msg->header);
- } else {
- /* Send zero-length confirm */
- return virNetServerProgramSendStreamData(stream->prog,
- client,
- msg,
- stream->procedure,
- stream->serial,
- NULL, 0);
- }
-}
-
-
-static int
-daemonStreamHandleHole(virNetServerClientPtr client,
- daemonClientStream *stream,
- virNetMessagePtr msg)
-{
- int ret;
- virNetStreamHole data;
-
- VIR_DEBUG("client=%p, stream=%p, proc=%d, serial=%u",
- client, stream, msg->header.proc, msg->header.serial);
-
- /* Let's check if client plays nicely and advertised usage of
- * sparse stream upfront. */
- if (!stream->allowSkip) {
- virReportError(VIR_ERR_RPC, "%s",
- _("Unexpected stream hole"));
- return -1;
- }
-
- if (virNetMessageDecodePayload(msg,
- (xdrproc_t) xdr_virNetStreamHole,
- &data) < 0)
- return -1;
-
- ret = virStreamSendHole(stream->st, data.length, data.flags);
-
- if (ret < 0) {
- virNetMessageError rerr;
-
- memset(&rerr, 0, sizeof(rerr));
-
- VIR_INFO("Stream send hole failed");
- stream->closed = true;
- virStreamEventRemoveCallback(stream->st);
- virStreamAbort(stream->st);
-
- return virNetServerProgramSendReplyError(stream->prog,
- client,
- msg,
- &rerr,
- &msg->header);
- }
-
- return 0;
-}
-
-
-/*
- * Called when the stream is signalled has being able to accept
- * data writes. Will process all pending incoming messages
- * until they're all gone, or I/O blocks
- *
- * Returns 0 on success, or -1 upon fatal error
- */
-static int
-daemonStreamHandleWrite(virNetServerClientPtr client,
- daemonClientStream *stream)
-{
- VIR_DEBUG("client=%p, stream=%p", client, stream);
-
- while (stream->rx && !stream->closed) {
- virNetMessagePtr msg = stream->rx;
- int ret;
-
- if (msg->header.type == VIR_NET_STREAM_HOLE) {
- /* Handle special case when the client sent us a hole.
- * Otherwise just carry on with processing stream
- * data. */
- ret = daemonStreamHandleHole(client, stream, msg);
- } else if (msg->header.type == VIR_NET_STREAM) {
- switch (msg->header.status) {
- case VIR_NET_OK:
- ret = daemonStreamHandleFinish(client, stream, msg);
- break;
-
- case VIR_NET_CONTINUE:
- ret = daemonStreamHandleWriteData(client, stream, msg);
- break;
-
- case VIR_NET_ERROR:
- default:
- ret = daemonStreamHandleAbort(client, stream, msg);
- break;
- }
- } else {
- virReportError(VIR_ERR_RPC,
- _("Unexpected message type: %d"),
- msg->header.type);
- ret = -1;
- }
-
- if (ret > 0)
- break; /* still processing data from msg */
-
- virNetMessageQueueServe(&stream->rx);
- if (ret < 0) {
- virNetMessageFree(msg);
- virNetServerClientImmediateClose(client);
- return -1;
- }
-
- /* 'CONTINUE' messages don't send a reply (unless error
- * occurred), so to release the 'msg' object we need to
- * send a fake zero-length reply. Nothing actually gets
- * onto the wire, but this causes the client to reset
- * its active request count / throttling
- */
- if (msg->header.status == VIR_NET_CONTINUE) {
- virNetMessageClear(msg);
- msg->header.type = VIR_NET_REPLY;
- if (virNetServerClientSendMessage(client, msg) < 0) {
- virNetMessageFree(msg);
- virNetServerClientImmediateClose(client);
- return -1;
- }
- }
- }
-
- return 0;
-}
-
-
-
-/*
- * Invoked when a stream is signalled as having data
- * available to read. This reads up to one message
- * worth of data, and then queues that for transmission
- * to the client.
- *
- * Returns 0 if data was queued for TX, or an error RPC
- * was sent, or -1 on fatal error, indicating client should
- * be killed
- */
-static int
-daemonStreamHandleRead(virNetServerClientPtr client,
- daemonClientStream *stream)
-{
- virNetMessagePtr msg = NULL;
- virNetMessageError rerr;
- char *buffer;
- size_t bufferLen = VIR_NET_MESSAGE_LEGACY_PAYLOAD_MAX;
- int ret = -1;
- int rv;
- int inData = 0;
- long long length = 0;
-
- VIR_DEBUG("client=%p, stream=%p tx=%d closed=%d",
- client, stream, stream->tx, stream->closed);
-
- /* We might have had an event pending before we shut
- * down the stream, so if we're marked as closed,
- * then do nothing
- */
- if (stream->closed)
- return 0;
-
- /* Shouldn't ever be called unless we're marked able to
- * transmit, but doesn't hurt to check */
- if (!stream->tx)
- return 0;
-
- memset(&rerr, 0, sizeof(rerr));
-
- if (VIR_ALLOC_N(buffer, bufferLen) < 0)
- return -1;
-
- if (!(msg = virNetMessageNew(false)))
- goto cleanup;
-
- if (stream->allowSkip && stream->dataLen == 0) {
- /* Handle skip. We want to send some data to the client. But we might
- * be in a hole. Seek to next data. But if we are in data already, just
- * carry on. */
-
- rv = virStreamInData(stream->st, &inData, &length);
- VIR_DEBUG("rv=%d inData=%d length=%lld", rv, inData, length);
-
- if (rv < 0) {
- if (virNetServerProgramSendStreamError(remoteProgram,
- client,
- msg,
- &rerr,
- stream->procedure,
- stream->serial) < 0)
- goto cleanup;
- msg = NULL;
-
- /* We're done with this call */
- goto done;
- } else {
- if (!inData && length) {
- stream->tx = false;
- msg->cb = daemonStreamMessageFinished;
- msg->opaque = stream;
- stream->refs++;
- if (virNetServerProgramSendStreamHole(remoteProgram,
- client,
- msg,
- stream->procedure,
- stream->serial,
- length,
- 0) < 0)
- goto cleanup;
-
- msg = NULL;
-
- /* We have successfully sent stream skip to the other side.
- * To keep streams in sync seek locally too. */
- virStreamSendHole(stream->st, length, 0);
- /* We're done with this call */
- goto done;
- }
- }
-
- stream->dataLen = length;
- }
-
- if (stream->allowSkip &&
- bufferLen > stream->dataLen)
- bufferLen = stream->dataLen;
-
- rv = virStreamRecv(stream->st, buffer, bufferLen);
- if (rv == -2) {
- /* Should never get this, since we're only called when we know
- * we're readable, but hey things change... */
- } else if (rv < 0) {
- if (virNetServerProgramSendStreamError(remoteProgram,
- client,
- msg,
- &rerr,
- stream->procedure,
- stream->serial) < 0)
- goto cleanup;
- msg = NULL;
- } else {
- if (stream->allowSkip)
- stream->dataLen -= rv;
-
- stream->tx = false;
- if (rv == 0)
- stream->recvEOF = true;
-
- msg->cb = daemonStreamMessageFinished;
- msg->opaque = stream;
- stream->refs++;
- if (virNetServerProgramSendStreamData(remoteProgram,
- client,
- msg,
- stream->procedure,
- stream->serial,
- buffer, rv) < 0)
- goto cleanup;
- msg = NULL;
- }
-
- done:
- ret = 0;
- cleanup:
- VIR_FREE(buffer);
- virNetMessageFree(msg);
- return ret;
-}
+++ /dev/null
-/*
- * stream.h: APIs for managing client streams
- *
- * Copyright (C) 2009 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 __LIBVIRTD_STREAM_H__
-# define __LIBVIRTD_STREAM_H__
-
-# include "libvirtd.h"
-
-daemonClientStream *
-daemonCreateClientStream(virNetServerClientPtr client,
- virStreamPtr st,
- virNetServerProgramPtr prog,
- virNetMessageHeaderPtr hdr,
- bool allowSkip);
-
-int daemonFreeClientStream(virNetServerClientPtr client,
- daemonClientStream *stream);
-
-int daemonAddClientStream(virNetServerClientPtr client,
- daemonClientStream *stream,
- bool transmit);
-
-int
-daemonRemoveClientStream(virNetServerClientPtr client,
- daemonClientStream *stream);
-
-void
-daemonRemoveAllClientStreams(daemonClientStream *stream);
-
-#endif /* __LIBVIRTD_STREAM_H__ */
-daemon/libvirtd-config.c
-daemon/libvirtd.c
-daemon/qemu_dispatch.h
-daemon/remote.c
-daemon/remote_dispatch.h
-daemon/stream.c
gnulib/lib/gai_strerror.c
gnulib/lib/getopt.c
gnulib/lib/regcomp.c
src/qemu/qemu_parse_command.c
src/qemu/qemu_process.c
src/remote/remote_client_bodies.h
+src/remote/remote_daemon.c
+src/remote/remote_daemon_config.c
+src/remote/remote_daemon_dispatch.c
+src/remote/remote_daemon_dispatch_stubs.h
+src/remote/remote_daemon_dispatch_qemu_stubs.h
+src/remote/remote_daemon_stream.c
src/remote/remote_driver.c
src/rpc/virkeepalive.c
src/rpc/virnetclient.c
moddir = $(libdir)/libvirt/connection-driver
mod_LTLIBRARIES =
+sbin_PROGRAMS =
confdir = $(sysconfdir)/libvirt
conf_DATA = libvirt.conf libvirt-admin.conf
qemu QEMU $(QEMU_PROTOCOL) \
> $(srcdir)/remote/qemu_client_bodies.h
+remote/remote_daemon_dispatch_stubs.h: $(srcdir)/rpc/gendispatch.pl \
+ $(REMOTE_PROTOCOL) Makefile.am
+ $(AM_V_GEN)$(PERL) -w $(top_srcdir)/src/rpc/gendispatch.pl \
+ --mode=server remote REMOTE $(REMOTE_PROTOCOL) \
+ > $(srcdir)/remote/remote_daemon_dispatch_stubs.h
+
+remote/remote_daemon_dispatch_lxc_stubs.h: $(srcdir)/rpc/gendispatch.pl \
+ $(LXC_PROTOCOL) Makefile.am
+ $(AM_V_GEN)$(PERL) -w $(top_srcdir)/src/rpc/gendispatch.pl \
+ --mode=server lxc LXC $(LXC_PROTOCOL) \
+ > $(srcdir)/remote/remote_daemon_dispatch_lxc_stubs.h
+
+remote/remote_daemon_dispatch_qemu_stubs.h: $(srcdir)/rpc/gendispatch.pl \
+ $(QEMU_PROTOCOL) Makefile.am
+ $(AM_V_GEN)$(PERL) -w $(top_srcdir)/src/rpc/gendispatch.pl \
+ --mode=server qemu QEMU $(QEMU_PROTOCOL) \
+ > $(srcdir)/remote/remote_daemon_dispatch_qemu_stubs.h
+
REMOTE_DRIVER_SOURCES = \
remote/remote_driver.c remote/remote_driver.h \
$(REMOTE_DRIVER_GENERATED)
+LIBVIRTD_GENERATED = \
+ remote/remote_daemon_dispatch_stubs.h \
+ remote/remote_daemon_dispatch_lxc_stubs.h \
+ remote/remote_daemon_dispatch_qemu_stubs.h \
+ $(NULL)
+
+LIBVIRTD_SOURCES = \
+ remote/remote_daemon.c remote/remote_daemon.h \
+ remote/remote_daemon_config.c remote/remote_daemon_config.h \
+ remote/remote_daemon_dispatch.c remote/remote_daemon_dispatch.h \
+ remote/remote_daemon_stream.c remote/remote_daemon_stream.h \
+ $(LIBVIRTD_GENERATED)
+
EXTRA_DIST += $(REMOTE_DRIVER_PROTOCOL) \
- $(REMOTE_DRIVER_GENERATED)
+ $(REMOTE_DRIVER_GENERATED) \
+ $(LIBVIRTD_SOURCES) \
+ $(NULL)
ADMIN_PROTOCOL = $(srcdir)/admin/admin_protocol.x
endif WITH_REMOTE
+
+if WITH_LIBVIRTD
+
+sbin_PROGRAMS += libvirtd
+
+BUILT_SOURCES += $(LIBVIRTD_GENERATED)
+
+libvirtd_SOURCES = $(LIBVIRTD_SOURCES)
+
+libvirtd_CFLAGS = \
+ $(LIBXML_CFLAGS) $(GNUTLS_CFLAGS) $(SASL_CFLAGS) \
+ $(XDR_CFLAGS) $(DBUS_CFLAGS) $(LIBNL_CFLAGS) \
+ $(WARN_CFLAGS) $(PIE_CFLAGS) \
+ $(COVERAGE_CFLAGS) \
+ -I$(srcdir)/access \
+ -I$(srcdir)/conf \
+ -I$(srcdir)/rpc \
+ $(NULL)
+
+libvirtd_LDFLAGS = \
+ $(RELRO_LDFLAGS) \
+ $(PIE_LDFLAGS) \
+ $(COVERAGE_LDFLAGS) \
+ $(NO_INDIRECT_LDFLAGS) \
+ $(NO_UNDEFINED_LDFLAGS) \
+ $(NULL)
+
+libvirtd_LDADD = \
+ $(LIBXML_LIBS) \
+ $(GNUTLS_LIBS) \
+ $(SASL_LIBS) \
+ $(DBUS_LIBS) \
+ $(LIBNL_LIBS) \
+ $(NULL)
+
+if WITH_DTRACE_PROBES
+libvirtd_LDADD += ../src/libvirt_probes.lo
+endif WITH_DTRACE_PROBES
+
+libvirtd_LDADD += \
+ libvirt_driver_admin.la \
+ libvirt-lxc.la \
+ libvirt-qemu.la \
+ libvirt.la \
+ ../gnulib/lib/libgnu.la $(LIBSOCKET) \
+ $(NULL)
+
+endif WITH_LIBVIRTD
+
%protocol.c: %protocol.x %protocol.h $(srcdir)/rpc/genprotocol.pl
$(AM_V_GEN)$(PERL) -w $(srcdir)/rpc/genprotocol.pl $(RPCGEN) -c \
$< $(srcdir)/$(subst $(srcdir)/,,$@)
cp $< $@
-sbin_PROGRAMS = virtlockd virtlogd
+sbin_PROGRAMS += virtlockd virtlogd
virtlockd_SOURCES = \
$(LOCK_DAEMON_SOURCES) \
CLEANFILES += *.gcov .libs/*.gcda .libs/*.gcno *.gcno *.gcda *.i *.s
DISTCLEANFILES += $(GENERATED_SYM_FILES)
-MAINTAINERCLEANFILES += $(REMOTE_DRIVER_GENERATED) $(VIR_NET_RPC_GENERATED)
+MAINTAINERCLEANFILES += \
+ $(REMOTE_DRIVER_GENERATED) \
+ $(LIBVIRTD_GENERATED) \
+ $(VIR_NET_RPC_GENERATED) \
+ $(NULL)
--- /dev/null
+/*
+ * remote_daemon.c: daemon start of day, guest process & i/o management
+ *
+ * Copyright (C) 2006-2018 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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 <unistd.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <grp.h>
+
+#include "libvirt_internal.h"
+#include "virerror.h"
+#include "virfile.h"
+#include "virlog.h"
+#include "virpidfile.h"
+#include "virprocess.h"
+
+#define VIR_FROM_THIS VIR_FROM_QEMU
+
+#include "remote_daemon.h"
+#include "remote_daemon_config.h"
+
+#include "admin/admin_server_dispatch.h"
+#include "viruuid.h"
+#include "remote_driver.h"
+#include "viralloc.h"
+#include "virconf.h"
+#include "virnetlink.h"
+#include "virnetdaemon.h"
+#include "remote_daemon_dispatch.h"
+#include "virhook.h"
+#include "viraudit.h"
+#include "virstring.h"
+#include "locking/lock_manager.h"
+#include "viraccessmanager.h"
+#include "virutil.h"
+#include "virgettext.h"
+#include "util/virnetdevopenvswitch.h"
+
+#include "driver.h"
+
+#include "configmake.h"
+
+#include "virdbus.h"
+
+VIR_LOG_INIT("daemon.libvirtd");
+
+#if WITH_SASL
+virNetSASLContextPtr saslCtxt = NULL;
+#endif
+virNetServerProgramPtr remoteProgram = NULL;
+virNetServerProgramPtr adminProgram = NULL;
+virNetServerProgramPtr qemuProgram = NULL;
+virNetServerProgramPtr lxcProgram = NULL;
+
+volatile bool driversInitialized = false;
+
+enum {
+ VIR_DAEMON_ERR_NONE = 0,
+ VIR_DAEMON_ERR_PIDFILE,
+ VIR_DAEMON_ERR_RUNDIR,
+ VIR_DAEMON_ERR_INIT,
+ VIR_DAEMON_ERR_SIGNAL,
+ VIR_DAEMON_ERR_PRIVS,
+ VIR_DAEMON_ERR_NETWORK,
+ VIR_DAEMON_ERR_CONFIG,
+ VIR_DAEMON_ERR_HOOKS,
+ VIR_DAEMON_ERR_AUDIT,
+
+ VIR_DAEMON_ERR_LAST
+};
+
+VIR_ENUM_DECL(virDaemonErr)
+VIR_ENUM_IMPL(virDaemonErr, VIR_DAEMON_ERR_LAST,
+ "Initialization successful",
+ "Unable to obtain pidfile",
+ "Unable to create rundir",
+ "Unable to initialize libvirt",
+ "Unable to setup signal handlers",
+ "Unable to drop privileges",
+ "Unable to initialize network sockets",
+ "Unable to load configuration file",
+ "Unable to look for hook scripts",
+ "Unable to initialize audit system")
+
+static int daemonForkIntoBackground(const char *argv0)
+{
+ int statuspipe[2];
+ if (pipe(statuspipe) < 0)
+ return -1;
+
+ pid_t pid = fork();
+ switch (pid) {
+ case 0:
+ {
+ /* intermediate child */
+ int stdinfd = -1;
+ int stdoutfd = -1;
+ int nextpid;
+
+ VIR_FORCE_CLOSE(statuspipe[0]);
+
+ if ((stdinfd = open("/dev/null", O_RDONLY)) <= STDERR_FILENO)
+ goto cleanup;
+ if ((stdoutfd = open("/dev/null", O_WRONLY)) <= STDERR_FILENO)
+ goto cleanup;
+ if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
+ goto cleanup;
+ if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO)
+ goto cleanup;
+ if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO)
+ goto cleanup;
+ if (VIR_CLOSE(stdinfd) < 0)
+ goto cleanup;
+ if (VIR_CLOSE(stdoutfd) < 0)
+ goto cleanup;
+
+ if (setsid() < 0)
+ goto cleanup;
+
+ nextpid = fork();
+ switch (nextpid) {
+ case 0: /* grandchild */
+ return statuspipe[1];
+ case -1: /* error */
+ goto cleanup;
+ default: /* intermediate child succeeded */
+ _exit(EXIT_SUCCESS);
+ }
+
+ cleanup:
+ VIR_FORCE_CLOSE(stdoutfd);
+ VIR_FORCE_CLOSE(stdinfd);
+ VIR_FORCE_CLOSE(statuspipe[1]);
+ _exit(EXIT_FAILURE);
+
+ }
+
+ case -1: /* error in parent */
+ goto error;
+
+ default:
+ {
+ /* parent */
+ int ret;
+ char status;
+
+ VIR_FORCE_CLOSE(statuspipe[1]);
+
+ /* We wait to make sure the first child forked successfully */
+ if (virProcessWait(pid, NULL, false) < 0)
+ goto error;
+
+ /* If we get here, then the grandchild was spawned, so we
+ * must exit. Block until the second child initializes
+ * successfully */
+ again:
+ ret = read(statuspipe[0], &status, 1);
+ if (ret == -1 && errno == EINTR)
+ goto again;
+
+ VIR_FORCE_CLOSE(statuspipe[0]);
+
+ if (ret != 1) {
+ char ebuf[1024];
+
+ fprintf(stderr,
+ _("%s: error: unable to determine if daemon is "
+ "running: %s\n"), argv0,
+ virStrerror(errno, ebuf, sizeof(ebuf)));
+ exit(EXIT_FAILURE);
+ } else if (status != 0) {
+ fprintf(stderr,
+ _("%s: error: %s. Check /var/log/messages or run "
+ "without --daemon for more info.\n"), argv0,
+ virDaemonErrTypeToString(status));
+ exit(EXIT_FAILURE);
+ }
+ _exit(EXIT_SUCCESS);
+ }
+ }
+
+ error:
+ VIR_FORCE_CLOSE(statuspipe[0]);
+ VIR_FORCE_CLOSE(statuspipe[1]);
+ return -1;
+}
+
+
+static int
+daemonUnixSocketPaths(struct daemonConfig *config,
+ bool privileged,
+ char **sockfile,
+ char **rosockfile,
+ char **admsockfile)
+{
+ int ret = -1;
+ char *rundir = NULL;
+
+ if (config->unix_sock_dir) {
+ if (virAsprintf(sockfile, "%s/libvirt-sock", config->unix_sock_dir) < 0)
+ goto cleanup;
+
+ if (privileged) {
+ if (virAsprintf(rosockfile, "%s/libvirt-sock-ro", config->unix_sock_dir) < 0 ||
+ virAsprintf(admsockfile, "%s/libvirt-admin-sock", config->unix_sock_dir) < 0)
+ goto cleanup;
+ }
+ } else {
+ if (privileged) {
+ if (VIR_STRDUP(*sockfile, LOCALSTATEDIR "/run/libvirt/libvirt-sock") < 0 ||
+ VIR_STRDUP(*rosockfile, LOCALSTATEDIR "/run/libvirt/libvirt-sock-ro") < 0 ||
+ VIR_STRDUP(*admsockfile, LOCALSTATEDIR "/run/libvirt/libvirt-admin-sock") < 0)
+ goto cleanup;
+ } else {
+ mode_t old_umask;
+
+ if (!(rundir = virGetUserRuntimeDirectory()))
+ goto cleanup;
+
+ old_umask = umask(077);
+ if (virFileMakePath(rundir) < 0) {
+ umask(old_umask);
+ goto cleanup;
+ }
+ umask(old_umask);
+
+ if (virAsprintf(sockfile, "%s/libvirt-sock", rundir) < 0 ||
+ virAsprintf(admsockfile, "%s/libvirt-admin-sock", rundir) < 0)
+ goto cleanup;
+ }
+ }
+
+ ret = 0;
+ cleanup:
+ VIR_FREE(rundir);
+ return ret;
+}
+
+
+static void daemonErrorHandler(void *opaque ATTRIBUTE_UNUSED,
+ virErrorPtr err ATTRIBUTE_UNUSED)
+{
+ /* Don't do anything, since logging infrastructure already
+ * took care of reporting the error */
+}
+
+static int daemonErrorLogFilter(virErrorPtr err, int priority)
+{
+ /* These error codes don't really reflect real errors. They
+ * are expected events that occur when an app tries to check
+ * whether a particular guest already exists. This filters
+ * them to a lower log level to prevent pollution of syslog
+ */
+ switch (err->code) {
+ case VIR_ERR_NO_DOMAIN:
+ case VIR_ERR_NO_NETWORK:
+ case VIR_ERR_NO_STORAGE_POOL:
+ case VIR_ERR_NO_STORAGE_VOL:
+ case VIR_ERR_NO_NODE_DEVICE:
+ case VIR_ERR_NO_INTERFACE:
+ case VIR_ERR_NO_NWFILTER:
+ case VIR_ERR_NO_SECRET:
+ case VIR_ERR_NO_DOMAIN_SNAPSHOT:
+ case VIR_ERR_OPERATION_INVALID:
+ case VIR_ERR_NO_DOMAIN_METADATA:
+ case VIR_ERR_NO_SERVER:
+ case VIR_ERR_NO_CLIENT:
+ return VIR_LOG_DEBUG;
+ }
+
+ return priority;
+}
+
+
+#define VIR_DAEMON_LOAD_MODULE(func, module) \
+ virDriverLoadModule(module, #func)
+static void daemonInitialize(void)
+{
+ /*
+ * Note that the order is important: the first ones have a higher
+ * priority when calling virStateInitialize. We must register the
+ * network, storage and nodedev drivers before any stateful domain
+ * driver, since their resources must be auto-started before any
+ * domains can be auto-started.
+ */
+ /* We don't care if any of these fail, because the whole point
+ * is to allow users to only install modules they want to use.
+ * If they try to open a connection for a module that
+ * is not loaded they'll get a suitable error at that point
+ */
+#ifdef WITH_NETWORK
+ VIR_DAEMON_LOAD_MODULE(networkRegister, "network");
+#endif
+#ifdef WITH_INTERFACE
+ VIR_DAEMON_LOAD_MODULE(interfaceRegister, "interface");
+#endif
+#ifdef WITH_STORAGE
+ VIR_DAEMON_LOAD_MODULE(storageRegister, "storage");
+#endif
+#ifdef WITH_NODE_DEVICES
+ VIR_DAEMON_LOAD_MODULE(nodedevRegister, "nodedev");
+#endif
+#ifdef WITH_SECRETS
+ VIR_DAEMON_LOAD_MODULE(secretRegister, "secret");
+#endif
+#ifdef WITH_NWFILTER
+ VIR_DAEMON_LOAD_MODULE(nwfilterRegister, "nwfilter");
+#endif
+#ifdef WITH_XEN
+ VIR_DAEMON_LOAD_MODULE(xenRegister, "xen");
+#endif
+#ifdef WITH_LIBXL
+ VIR_DAEMON_LOAD_MODULE(libxlRegister, "libxl");
+#endif
+#ifdef WITH_QEMU
+ VIR_DAEMON_LOAD_MODULE(qemuRegister, "qemu");
+#endif
+#ifdef WITH_LXC
+ VIR_DAEMON_LOAD_MODULE(lxcRegister, "lxc");
+#endif
+#ifdef WITH_UML
+ VIR_DAEMON_LOAD_MODULE(umlRegister, "uml");
+#endif
+#ifdef WITH_VBOX
+ VIR_DAEMON_LOAD_MODULE(vboxRegister, "vbox");
+#endif
+#ifdef WITH_BHYVE
+ VIR_DAEMON_LOAD_MODULE(bhyveRegister, "bhyve");
+#endif
+#ifdef WITH_VZ
+ VIR_DAEMON_LOAD_MODULE(vzRegister, "vz");
+#endif
+}
+#undef VIR_DAEMON_LOAD_MODULE
+
+
+static int ATTRIBUTE_NONNULL(3)
+daemonSetupNetworking(virNetServerPtr srv,
+ virNetServerPtr srvAdm,
+ struct daemonConfig *config,
+ const char *sock_path,
+ const char *sock_path_ro,
+ const char *sock_path_adm,
+ bool ipsock,
+ bool privileged)
+{
+ virNetServerServicePtr svc = NULL;
+ virNetServerServicePtr svcAdm = NULL;
+ virNetServerServicePtr svcRO = NULL;
+ virNetServerServicePtr svcTCP = NULL;
+#if WITH_GNUTLS
+ virNetServerServicePtr svcTLS = NULL;
+#endif
+ gid_t unix_sock_gid = 0;
+ int unix_sock_ro_mask = 0;
+ int unix_sock_rw_mask = 0;
+ int unix_sock_adm_mask = 0;
+ int ret = -1;
+
+ unsigned int cur_fd = STDERR_FILENO + 1;
+ unsigned int nfds = virGetListenFDs();
+
+ if (config->unix_sock_group) {
+ if (virGetGroupID(config->unix_sock_group, &unix_sock_gid) < 0)
+ return ret;
+ }
+
+ if (nfds > (sock_path_ro ? 2 : 1)) {
+ VIR_ERROR(_("Too many (%u) FDs passed from caller"), nfds);
+ return ret;
+ }
+
+ if (virStrToLong_i(config->unix_sock_ro_perms, NULL, 8, &unix_sock_ro_mask) != 0) {
+ VIR_ERROR(_("Failed to parse mode '%s'"), config->unix_sock_ro_perms);
+ goto cleanup;
+ }
+
+ if (virStrToLong_i(config->unix_sock_admin_perms, NULL, 8, &unix_sock_adm_mask) != 0) {
+ VIR_ERROR(_("Failed to parse mode '%s'"), config->unix_sock_admin_perms);
+ goto cleanup;
+ }
+
+ if (virStrToLong_i(config->unix_sock_rw_perms, NULL, 8, &unix_sock_rw_mask) != 0) {
+ VIR_ERROR(_("Failed to parse mode '%s'"), config->unix_sock_rw_perms);
+ goto cleanup;
+ }
+
+ if (!(svc = virNetServerServiceNewFDOrUNIX(sock_path,
+ unix_sock_rw_mask,
+ unix_sock_gid,
+ config->auth_unix_rw,
+#if WITH_GNUTLS
+ NULL,
+#endif
+ false,
+ config->max_queued_clients,
+ config->max_client_requests,
+ nfds, &cur_fd)))
+ goto cleanup;
+ if (sock_path_ro) {
+ if (!(svcRO = virNetServerServiceNewFDOrUNIX(sock_path_ro,
+ unix_sock_ro_mask,
+ unix_sock_gid,
+ config->auth_unix_ro,
+#if WITH_GNUTLS
+ NULL,
+#endif
+ true,
+ config->max_queued_clients,
+ config->max_client_requests,
+ nfds, &cur_fd)))
+ goto cleanup;
+ }
+
+ if (virNetServerAddService(srv, svc,
+ config->mdns_adv && !ipsock ?
+ "_libvirt._tcp" :
+ NULL) < 0)
+ goto cleanup;
+
+ if (svcRO &&
+ virNetServerAddService(srv, svcRO, NULL) < 0)
+ goto cleanup;
+
+ if (sock_path_adm) {
+ VIR_DEBUG("Registering unix socket %s", sock_path_adm);
+ if (!(svcAdm = virNetServerServiceNewUNIX(sock_path_adm,
+ unix_sock_adm_mask,
+ unix_sock_gid,
+ REMOTE_AUTH_NONE,
+#if WITH_GNUTLS
+ NULL,
+#endif
+ false,
+ config->admin_max_queued_clients,
+ config->admin_max_client_requests)))
+ goto cleanup;
+
+ if (virNetServerAddService(srvAdm, svcAdm, NULL) < 0)
+ goto cleanup;
+ }
+
+ if (ipsock) {
+ if (config->listen_tcp) {
+ VIR_DEBUG("Registering TCP socket %s:%s",
+ config->listen_addr, config->tcp_port);
+ if (!(svcTCP = virNetServerServiceNewTCP(config->listen_addr,
+ config->tcp_port,
+ AF_UNSPEC,
+ config->auth_tcp,
+#if WITH_GNUTLS
+ NULL,
+#endif
+ false,
+ config->max_queued_clients,
+ config->max_client_requests)))
+ goto cleanup;
+
+ if (virNetServerAddService(srv, svcTCP,
+ config->mdns_adv ? "_libvirt._tcp" : NULL) < 0)
+ goto cleanup;
+ }
+
+#if WITH_GNUTLS
+ if (config->listen_tls) {
+ virNetTLSContextPtr ctxt = NULL;
+
+ if (config->ca_file ||
+ config->cert_file ||
+ config->key_file) {
+ if (!config->ca_file) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("No CA certificate path set to match server key/cert"));
+ goto cleanup;
+ }
+ if (!config->cert_file) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("No server certificate path set to match server key"));
+ goto cleanup;
+ }
+ if (!config->key_file) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("No server key path set to match server cert"));
+ goto cleanup;
+ }
+ VIR_DEBUG("Using CA='%s' cert='%s' key='%s'",
+ config->ca_file, config->cert_file, config->key_file);
+ if (!(ctxt = virNetTLSContextNewServer(config->ca_file,
+ config->crl_file,
+ config->cert_file,
+ config->key_file,
+ (const char *const*)config->tls_allowed_dn_list,
+ config->tls_priority,
+ config->tls_no_sanity_certificate ? false : true,
+ config->tls_no_verify_certificate ? false : true)))
+ goto cleanup;
+ } else {
+ if (!(ctxt = virNetTLSContextNewServerPath(NULL,
+ !privileged,
+ (const char *const*)config->tls_allowed_dn_list,
+ config->tls_priority,
+ config->tls_no_sanity_certificate ? false : true,
+ config->tls_no_verify_certificate ? false : true)))
+ goto cleanup;
+ }
+
+ VIR_DEBUG("Registering TLS socket %s:%s",
+ config->listen_addr, config->tls_port);
+ if (!(svcTLS =
+ virNetServerServiceNewTCP(config->listen_addr,
+ config->tls_port,
+ AF_UNSPEC,
+ config->auth_tls,
+ ctxt,
+ false,
+ config->max_queued_clients,
+ config->max_client_requests))) {
+ virObjectUnref(ctxt);
+ goto cleanup;
+ }
+ if (virNetServerAddService(srv, svcTLS,
+ config->mdns_adv &&
+ !config->listen_tcp ? "_libvirt._tcp" : NULL) < 0)
+ goto cleanup;
+
+ virObjectUnref(ctxt);
+ }
+#else
+ (void)privileged;
+ if (config->listen_tls) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("This libvirtd build does not support TLS"));
+ goto cleanup;
+ }
+#endif
+ }
+
+#if WITH_SASL
+ if (config->auth_unix_rw == REMOTE_AUTH_SASL ||
+ (sock_path_ro && config->auth_unix_ro == REMOTE_AUTH_SASL) ||
+# if WITH_GNUTLS
+ (ipsock && config->listen_tls && config->auth_tls == REMOTE_AUTH_SASL) ||
+# endif
+ (ipsock && config->listen_tcp && config->auth_tcp == REMOTE_AUTH_SASL)) {
+ saslCtxt = virNetSASLContextNewServer(
+ (const char *const*)config->sasl_allowed_username_list);
+ if (!saslCtxt)
+ goto cleanup;
+ }
+#endif
+
+ ret = 0;
+
+ cleanup:
+#if WITH_GNUTLS
+ virObjectUnref(svcTLS);
+#endif
+ virObjectUnref(svcTCP);
+ virObjectUnref(svcRO);
+ virObjectUnref(svcAdm);
+ virObjectUnref(svc);
+ return ret;
+}
+
+
+/*
+ * Set up the openvswitch timeout
+ */
+static void
+daemonSetupNetDevOpenvswitch(struct daemonConfig *config)
+{
+ virNetDevOpenvswitchSetTimeout(config->ovs_timeout);
+}
+
+
+/*
+ * Set up the logging environment
+ * By default if daemonized all errors go to the logfile libvirtd.log,
+ * but if verbose or error debugging is asked for then also output
+ * informational and debug messages. Default size if 64 kB.
+ */
+static int
+daemonSetupLogging(struct daemonConfig *config,
+ bool privileged,
+ bool verbose,
+ bool godaemon)
+{
+ virLogReset();
+
+ /*
+ * Libvirtd's order of precedence is:
+ * cmdline > environment > config
+ *
+ * Given the precedence, we must process the variables in the opposite
+ * order, each one overriding the previous.
+ */
+ if (config->log_level != 0)
+ virLogSetDefaultPriority(config->log_level);
+
+ /* In case the config is empty, both filters and outputs will become empty,
+ * however we can't start with empty outputs, thus we'll need to define and
+ * setup a default one.
+ */
+ ignore_value(virLogSetFilters(config->log_filters));
+ ignore_value(virLogSetOutputs(config->log_outputs));
+
+ /* If there are some environment variables defined, use those instead */
+ virLogSetFromEnv();
+
+ /*
+ * Command line override for --verbose
+ */
+ if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO))
+ virLogSetDefaultPriority(VIR_LOG_INFO);
+
+ /* Define the default output. This is only applied if there was no setting
+ * from either the config or the environment.
+ */
+ if (virLogSetDefaultOutput("libvirtd.log", godaemon, privileged) < 0)
+ return -1;
+
+ if (virLogGetNbOutputs() == 0)
+ virLogSetOutputs(virLogGetDefaultOutput());
+
+ return 0;
+}
+
+
+static int
+daemonSetupAccessManager(struct daemonConfig *config)
+{
+ virAccessManagerPtr mgr;
+ const char *none[] = { "none", NULL };
+ const char **drv = (const char **)config->access_drivers;
+
+ if (!drv ||
+ !drv[0])
+ drv = none;
+
+ if (!(mgr = virAccessManagerNewStack(drv)))
+ return -1;
+
+ virAccessManagerSetDefault(mgr);
+ virObjectUnref(mgr);
+ return 0;
+}
+
+
+/* Display version information. */
+static void
+daemonVersion(const char *argv0)
+{
+ printf("%s (%s) %s\n", argv0, PACKAGE_NAME, PACKAGE_VERSION);
+}
+
+#ifdef __sun
+static int
+daemonSetupPrivs(void)
+{
+ chown("/var/run/libvirt", SYSTEM_UID, SYSTEM_UID);
+
+ if (__init_daemon_priv(PU_RESETGROUPS | PU_CLEARLIMITSET,
+ SYSTEM_UID, SYSTEM_UID, PRIV_XVM_CONTROL, NULL)) {
+ VIR_ERROR(_("additional privileges are required"));
+ return -1;
+ }
+
+ if (priv_set(PRIV_OFF, PRIV_ALLSETS, PRIV_FILE_LINK_ANY, PRIV_PROC_INFO,
+ PRIV_PROC_SESSION, PRIV_PROC_EXEC, PRIV_PROC_FORK, NULL)) {
+ VIR_ERROR(_("failed to set reduced privileges"));
+ return -1;
+ }
+
+ return 0;
+}
+#else
+# define daemonSetupPrivs() 0
+#endif
+
+
+static void daemonShutdownHandler(virNetDaemonPtr dmn,
+ siginfo_t *sig ATTRIBUTE_UNUSED,
+ void *opaque ATTRIBUTE_UNUSED)
+{
+ virNetDaemonQuit(dmn);
+}
+
+static void daemonReloadHandler(virNetDaemonPtr dmn ATTRIBUTE_UNUSED,
+ siginfo_t *sig ATTRIBUTE_UNUSED,
+ void *opaque ATTRIBUTE_UNUSED)
+{
+ if (!driversInitialized) {
+ VIR_WARN("Drivers are not initialized, reload ignored");
+ return;
+ }
+
+ VIR_INFO("Reloading configuration on SIGHUP");
+ virHookCall(VIR_HOOK_DRIVER_DAEMON, "-",
+ VIR_HOOK_DAEMON_OP_RELOAD, SIGHUP, "SIGHUP", NULL, NULL);
+ if (virStateReload() < 0)
+ VIR_WARN("Error while reloading drivers");
+}
+
+static int daemonSetupSignals(virNetDaemonPtr dmn)
+{
+ if (virNetDaemonAddSignalHandler(dmn, SIGINT, daemonShutdownHandler, NULL) < 0)
+ return -1;
+ if (virNetDaemonAddSignalHandler(dmn, SIGQUIT, daemonShutdownHandler, NULL) < 0)
+ return -1;
+ if (virNetDaemonAddSignalHandler(dmn, SIGTERM, daemonShutdownHandler, NULL) < 0)
+ return -1;
+ if (virNetDaemonAddSignalHandler(dmn, SIGHUP, daemonReloadHandler, NULL) < 0)
+ return -1;
+ return 0;
+}
+
+
+static void daemonInhibitCallback(bool inhibit, void *opaque)
+{
+ virNetDaemonPtr dmn = opaque;
+
+ if (inhibit)
+ virNetDaemonAddShutdownInhibition(dmn);
+ else
+ virNetDaemonRemoveShutdownInhibition(dmn);
+}
+
+
+#ifdef WITH_DBUS
+static DBusConnection *sessionBus;
+static DBusConnection *systemBus;
+
+static void daemonStopWorker(void *opaque)
+{
+ virNetDaemonPtr dmn = opaque;
+
+ VIR_DEBUG("Begin stop dmn=%p", dmn);
+
+ ignore_value(virStateStop());
+
+ VIR_DEBUG("Completed stop dmn=%p", dmn);
+
+ /* Exit libvirtd cleanly */
+ virNetDaemonQuit(dmn);
+}
+
+
+/* We do this in a thread to not block the main loop */
+static void daemonStop(virNetDaemonPtr dmn)
+{
+ virThread thr;
+ virObjectRef(dmn);
+ if (virThreadCreate(&thr, false, daemonStopWorker, dmn) < 0)
+ virObjectUnref(dmn);
+}
+
+
+static DBusHandlerResult
+handleSessionMessageFunc(DBusConnection *connection ATTRIBUTE_UNUSED,
+ DBusMessage *message,
+ void *opaque)
+{
+ virNetDaemonPtr dmn = opaque;
+
+ VIR_DEBUG("dmn=%p", dmn);
+
+ if (dbus_message_is_signal(message,
+ DBUS_INTERFACE_LOCAL,
+ "Disconnected"))
+ daemonStop(dmn);
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+
+static DBusHandlerResult
+handleSystemMessageFunc(DBusConnection *connection ATTRIBUTE_UNUSED,
+ DBusMessage *message,
+ void *opaque)
+{
+ virNetDaemonPtr dmn = opaque;
+
+ VIR_DEBUG("dmn=%p", dmn);
+
+ if (dbus_message_is_signal(message,
+ "org.freedesktop.login1.Manager",
+ "PrepareForShutdown"))
+ daemonStop(dmn);
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+#endif
+
+
+static void daemonRunStateInit(void *opaque)
+{
+ virNetDaemonPtr dmn = opaque;
+ virIdentityPtr sysident = virIdentityGetSystem();
+
+ virIdentitySetCurrent(sysident);
+
+ /* Since driver initialization can take time inhibit daemon shutdown until
+ we're done so clients get a chance to connect */
+ daemonInhibitCallback(true, dmn);
+
+ /* Start the stateful HV drivers
+ * This is deliberately done after telling the parent process
+ * we're ready, since it can take a long time and this will
+ * seriously delay OS bootup process */
+ if (virStateInitialize(virNetDaemonIsPrivileged(dmn),
+ daemonInhibitCallback,
+ dmn) < 0) {
+ VIR_ERROR(_("Driver state initialization failed"));
+ /* Ensure the main event loop quits */
+ kill(getpid(), SIGTERM);
+ goto cleanup;
+ }
+
+ driversInitialized = true;
+
+#ifdef WITH_DBUS
+ /* Tie the non-privileged libvirtd to the session/shutdown lifecycle */
+ if (!virNetDaemonIsPrivileged(dmn)) {
+
+ sessionBus = virDBusGetSessionBus();
+ if (sessionBus != NULL)
+ dbus_connection_add_filter(sessionBus,
+ handleSessionMessageFunc, dmn, NULL);
+
+ systemBus = virDBusGetSystemBus();
+ if (systemBus != NULL) {
+ dbus_connection_add_filter(systemBus,
+ handleSystemMessageFunc, dmn, NULL);
+ dbus_bus_add_match(systemBus,
+ "type='signal',sender='org.freedesktop.login1', interface='org.freedesktop.login1.Manager'",
+ NULL);
+ }
+ }
+#endif
+ /* Only now accept clients from network */
+ virNetDaemonUpdateServices(dmn, true);
+ cleanup:
+ daemonInhibitCallback(false, dmn);
+ virObjectUnref(dmn);
+ virObjectUnref(sysident);
+ virIdentitySetCurrent(NULL);
+}
+
+static int daemonStateInit(virNetDaemonPtr dmn)
+{
+ virThread thr;
+ virObjectRef(dmn);
+ if (virThreadCreate(&thr, false, daemonRunStateInit, dmn) < 0) {
+ virObjectUnref(dmn);
+ return -1;
+ }
+ return 0;
+}
+
+static int migrateProfile(void)
+{
+ char *old_base = NULL;
+ char *updated = NULL;
+ char *home = NULL;
+ char *xdg_dir = NULL;
+ char *config_dir = NULL;
+ const char *config_home;
+ int ret = -1;
+ mode_t old_umask;
+
+ VIR_DEBUG("Checking if user profile needs migrating");
+
+ if (!(home = virGetUserDirectory()))
+ goto cleanup;
+
+ if (virAsprintf(&old_base, "%s/.libvirt", home) < 0)
+ goto cleanup;
+
+ /* if the new directory is there or the old one is not: do nothing */
+ if (!(config_dir = virGetUserConfigDirectory()))
+ goto cleanup;
+
+ if (!virFileIsDir(old_base) || virFileExists(config_dir)) {
+ VIR_DEBUG("No old profile in '%s' / "
+ "new profile directory already present '%s'",
+ old_base, config_dir);
+ ret = 0;
+ goto cleanup;
+ }
+
+ /* test if we already attempted to migrate first */
+ if (virAsprintf(&updated, "%s/DEPRECATED-DIRECTORY", old_base) < 0)
+ goto cleanup;
+ if (virFileExists(updated))
+ goto cleanup;
+
+ config_home = virGetEnvBlockSUID("XDG_CONFIG_HOME");
+ if (config_home && config_home[0] != '\0') {
+ if (VIR_STRDUP(xdg_dir, config_home) < 0)
+ goto cleanup;
+ } else {
+ if (virAsprintf(&xdg_dir, "%s/.config", home) < 0)
+ goto cleanup;
+ }
+
+ old_umask = umask(077);
+ if (virFileMakePath(xdg_dir) < 0) {
+ umask(old_umask);
+ goto cleanup;
+ }
+ umask(old_umask);
+
+ if (rename(old_base, config_dir) < 0) {
+ int fd = creat(updated, 0600);
+ VIR_FORCE_CLOSE(fd);
+ VIR_ERROR(_("Unable to migrate %s to %s"), old_base, config_dir);
+ goto cleanup;
+ }
+
+ VIR_DEBUG("Profile migrated from %s to %s", old_base, config_dir);
+ ret = 0;
+
+ cleanup:
+ VIR_FREE(home);
+ VIR_FREE(old_base);
+ VIR_FREE(xdg_dir);
+ VIR_FREE(config_dir);
+ VIR_FREE(updated);
+
+ return ret;
+}
+
+static int
+daemonSetupHostUUID(const struct daemonConfig *config)
+{
+ static const char *machine_id = "/etc/machine-id";
+ char buf[VIR_UUID_STRING_BUFLEN];
+ const char *uuid;
+
+ if (config->host_uuid) {
+ uuid = config->host_uuid;
+ } else if (!config->host_uuid_source ||
+ STREQ(config->host_uuid_source, "smbios")) {
+ /* smbios UUID is fetched on demand in virGetHostUUID */
+ return 0;
+ } else if (STREQ(config->host_uuid_source, "machine-id")) {
+ if (virFileReadBufQuiet(machine_id, buf, sizeof(buf)) < 0) {
+ VIR_ERROR(_("Can't read %s"), machine_id);
+ return -1;
+ }
+
+ uuid = buf;
+ } else {
+ VIR_ERROR(_("invalid UUID source: %s"), config->host_uuid_source);
+ return -1;
+ }
+
+ if (virSetHostUUIDStr(uuid)) {
+ VIR_ERROR(_("invalid host UUID: %s"), uuid);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Print command-line usage. */
+static void
+daemonUsage(const char *argv0, bool privileged)
+{
+ fprintf(stderr,
+ _("\n"
+ "Usage:\n"
+ " %s [options]\n"
+ "\n"
+ "Options:\n"
+ " -h | --help Display program help:\n"
+ " -v | --verbose Verbose messages.\n"
+ " -d | --daemon Run as a daemon & write PID file.\n"
+ " -l | --listen Listen for TCP/IP connections.\n"
+ " -t | --timeout <secs> Exit after timeout period.\n"
+ " -f | --config <file> Configuration file.\n"
+ " -V | --version Display version information.\n"
+ " -p | --pid-file <file> Change name of PID file.\n"
+ "\n"
+ "libvirt management daemon:\n"),
+ argv0);
+
+ if (privileged) {
+ fprintf(stderr,
+ _("\n"
+ " Default paths:\n"
+ "\n"
+ " Configuration file (unless overridden by -f):\n"
+ " %s\n"
+ "\n"
+ " Sockets:\n"
+ " %s\n"
+ " %s\n"
+ "\n"
+ " TLS:\n"
+ " CA certificate: %s\n"
+ " Server certificate: %s\n"
+ " Server private key: %s\n"
+ "\n"
+ " PID file (unless overridden by -p):\n"
+ " %s/run/libvirtd.pid\n"
+ "\n"),
+ LIBVIRTD_CONFIGURATION_FILE,
+ LIBVIRTD_PRIV_UNIX_SOCKET,
+ LIBVIRTD_PRIV_UNIX_SOCKET_RO,
+ LIBVIRT_CACERT,
+ LIBVIRT_SERVERCERT,
+ LIBVIRT_SERVERKEY,
+ LOCALSTATEDIR);
+ } else {
+ fprintf(stderr, "%s",
+ _("\n"
+ " Default paths:\n"
+ "\n"
+ " Configuration file (unless overridden by -f):\n"
+ " $XDG_CONFIG_HOME/libvirt/libvirtd.conf\n"
+ "\n"
+ " Sockets:\n"
+ " $XDG_RUNTIME_DIR/libvirt/libvirt-sock\n"
+ "\n"
+ " TLS:\n"
+ " CA certificate: $HOME/.pki/libvirt/cacert.pem\n"
+ " Server certificate: $HOME/.pki/libvirt/servercert.pem\n"
+ " Server private key: $HOME/.pki/libvirt/serverkey.pem\n"
+ "\n"
+ " PID file:\n"
+ " $XDG_RUNTIME_DIR/libvirt/libvirtd.pid\n"
+ "\n"));
+ }
+}
+
+int main(int argc, char **argv) {
+ virNetDaemonPtr dmn = NULL;
+ virNetServerPtr srv = NULL;
+ virNetServerPtr srvAdm = NULL;
+ char *remote_config_file = NULL;
+ int statuswrite = -1;
+ int ret = 1;
+ int pid_file_fd = -1;
+ char *pid_file = NULL;
+ char *sock_file = NULL;
+ char *sock_file_ro = NULL;
+ char *sock_file_adm = NULL;
+ int timeout = -1; /* -t: Shutdown timeout */
+ int verbose = 0;
+ int godaemon = 0;
+ int ipsock = 0;
+ struct daemonConfig *config;
+ bool privileged = geteuid() == 0 ? true : false;
+ bool implicit_conf = false;
+ char *run_dir = NULL;
+ mode_t old_umask;
+
+ struct option opts[] = {
+ { "verbose", no_argument, &verbose, 'v'},
+ { "daemon", no_argument, &godaemon, 'd'},
+ { "listen", no_argument, &ipsock, 'l'},
+ { "config", required_argument, NULL, 'f'},
+ { "timeout", required_argument, NULL, 't'},
+ { "pid-file", required_argument, NULL, 'p'},
+ { "version", no_argument, NULL, 'V' },
+ { "help", no_argument, NULL, 'h' },
+ {0, 0, 0, 0}
+ };
+
+ if (virGettextInitialize() < 0 ||
+ virInitialize() < 0) {
+ fprintf(stderr, _("%s: initialization failed\n"), argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ virUpdateSelfLastChanged(argv[0]);
+
+ virFileActivateDirOverride(argv[0]);
+
+ while (1) {
+ int optidx = 0;
+ int c;
+ char *tmp;
+
+ c = getopt_long(argc, argv, "ldf:p:t:vVh", opts, &optidx);
+
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 0:
+ /* Got one of the flags */
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'd':
+ godaemon = 1;
+ break;
+ case 'l':
+ ipsock = 1;
+ break;
+
+ case 't':
+ if (virStrToLong_i(optarg, &tmp, 10, &timeout) != 0
+ || timeout <= 0
+ /* Ensure that we can multiply by 1000 without overflowing. */
+ || timeout > INT_MAX / 1000) {
+ VIR_ERROR(_("Invalid value for timeout"));
+ exit(EXIT_FAILURE);
+ }
+ break;
+
+ case 'p':
+ VIR_FREE(pid_file);
+ if (VIR_STRDUP_QUIET(pid_file, optarg) < 0) {
+ VIR_ERROR(_("Can't allocate memory"));
+ exit(EXIT_FAILURE);
+ }
+ break;
+
+ case 'f':
+ VIR_FREE(remote_config_file);
+ if (VIR_STRDUP_QUIET(remote_config_file, optarg) < 0) {
+ VIR_ERROR(_("Can't allocate memory"));
+ exit(EXIT_FAILURE);
+ }
+ break;
+
+ case 'V':
+ daemonVersion(argv[0]);
+ exit(EXIT_SUCCESS);
+
+ case 'h':
+ daemonUsage(argv[0], privileged);
+ exit(EXIT_SUCCESS);
+
+ case '?':
+ default:
+ daemonUsage(argv[0], privileged);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (optind != argc) {
+ fprintf(stderr, "%s: unexpected, non-option, command line arguments\n",
+ argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (!(config = daemonConfigNew(privileged))) {
+ VIR_ERROR(_("Can't create initial configuration"));
+ exit(EXIT_FAILURE);
+ }
+
+ /* No explicit config, so try and find a default one */
+ if (remote_config_file == NULL) {
+ implicit_conf = true;
+ if (daemonConfigFilePath(privileged,
+ &remote_config_file) < 0) {
+ VIR_ERROR(_("Can't determine config path"));
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /* Read the config file if it exists*/
+ if (remote_config_file &&
+ daemonConfigLoadFile(config, remote_config_file, implicit_conf) < 0) {
+ VIR_ERROR(_("Can't load config file: %s: %s"),
+ virGetLastErrorMessage(), remote_config_file);
+ exit(EXIT_FAILURE);
+ }
+
+ if (!privileged &&
+ migrateProfile() < 0) {
+ VIR_ERROR(_("Exiting due to failure to migrate profile"));
+ exit(EXIT_FAILURE);
+ }
+
+ if (daemonSetupHostUUID(config) < 0) {
+ VIR_ERROR(_("Can't setup host uuid"));
+ exit(EXIT_FAILURE);
+ }
+
+ if (daemonSetupLogging(config, privileged, verbose, godaemon) < 0) {
+ VIR_ERROR(_("Can't initialize logging"));
+ exit(EXIT_FAILURE);
+ }
+
+ daemonSetupNetDevOpenvswitch(config);
+
+ if (daemonSetupAccessManager(config) < 0) {
+ VIR_ERROR(_("Can't initialize access manager"));
+ exit(EXIT_FAILURE);
+ }
+
+ if (!pid_file &&
+ virPidFileConstructPath(privileged,
+ LOCALSTATEDIR,
+ "libvirtd",
+ &pid_file) < 0) {
+ VIR_ERROR(_("Can't determine pid file path."));
+ exit(EXIT_FAILURE);
+ }
+ VIR_DEBUG("Decided on pid file path '%s'", NULLSTR(pid_file));
+
+ if (daemonUnixSocketPaths(config,
+ privileged,
+ &sock_file,
+ &sock_file_ro,
+ &sock_file_adm) < 0) {
+ VIR_ERROR(_("Can't determine socket paths"));
+ exit(EXIT_FAILURE);
+ }
+ VIR_DEBUG("Decided on socket paths '%s', '%s' and '%s'",
+ sock_file,
+ NULLSTR(sock_file_ro),
+ NULLSTR(sock_file_adm));
+
+ if (godaemon) {
+ char ebuf[1024];
+
+ if (chdir("/") < 0) {
+ VIR_ERROR(_("cannot change to root directory: %s"),
+ virStrerror(errno, ebuf, sizeof(ebuf)));
+ goto cleanup;
+ }
+
+ if ((statuswrite = daemonForkIntoBackground(argv[0])) < 0) {
+ VIR_ERROR(_("Failed to fork as daemon: %s"),
+ virStrerror(errno, ebuf, sizeof(ebuf)));
+ goto cleanup;
+ }
+ }
+
+ /* Try to claim the pidfile, exiting if we can't */
+ if ((pid_file_fd = virPidFileAcquirePath(pid_file, false, getpid())) < 0) {
+ ret = VIR_DAEMON_ERR_PIDFILE;
+ goto cleanup;
+ }
+
+ /* Ensure the rundir exists (on tmpfs on some systems) */
+ if (privileged) {
+ if (VIR_STRDUP_QUIET(run_dir, LOCALSTATEDIR "/run/libvirt") < 0) {
+ VIR_ERROR(_("Can't allocate memory"));
+ goto cleanup;
+ }
+ } else {
+ run_dir = virGetUserRuntimeDirectory();
+
+ if (!run_dir) {
+ VIR_ERROR(_("Can't determine user directory"));
+ goto cleanup;
+ }
+ }
+ if (privileged)
+ old_umask = umask(022);
+ else
+ old_umask = umask(077);
+ VIR_DEBUG("Ensuring run dir '%s' exists", run_dir);
+ if (virFileMakePath(run_dir) < 0) {
+ char ebuf[1024];
+ VIR_ERROR(_("unable to create rundir %s: %s"), run_dir,
+ virStrerror(errno, ebuf, sizeof(ebuf)));
+ ret = VIR_DAEMON_ERR_RUNDIR;
+ goto cleanup;
+ }
+ umask(old_umask);
+
+ if (virNetlinkStartup() < 0) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
+ }
+
+ if (!(dmn = virNetDaemonNew())) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
+ }
+
+ if (!(srv = virNetServerNew("libvirtd", 1,
+ config->min_workers,
+ config->max_workers,
+ config->prio_workers,
+ config->max_clients,
+ config->max_anonymous_clients,
+ config->keepalive_interval,
+ config->keepalive_count,
+ config->mdns_adv ? config->mdns_name : NULL,
+ remoteClientNew,
+ NULL,
+ remoteClientFree,
+ NULL))) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
+ }
+
+ if (virNetDaemonAddServer(dmn, srv) < 0) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
+ }
+
+ /* Beyond this point, nothing should rely on using
+ * getuid/geteuid() == 0, for privilege level checks.
+ */
+ VIR_DEBUG("Dropping privileges (if required)");
+ if (daemonSetupPrivs() < 0) {
+ ret = VIR_DAEMON_ERR_PRIVS;
+ goto cleanup;
+ }
+
+ daemonInitialize();
+
+ remoteProcs[REMOTE_PROC_AUTH_LIST].needAuth = false;
+ remoteProcs[REMOTE_PROC_AUTH_SASL_INIT].needAuth = false;
+ remoteProcs[REMOTE_PROC_AUTH_SASL_STEP].needAuth = false;
+ remoteProcs[REMOTE_PROC_AUTH_SASL_START].needAuth = false;
+ remoteProcs[REMOTE_PROC_AUTH_POLKIT].needAuth = false;
+ if (!(remoteProgram = virNetServerProgramNew(REMOTE_PROGRAM,
+ REMOTE_PROTOCOL_VERSION,
+ remoteProcs,
+ remoteNProcs))) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
+ }
+ if (virNetServerAddProgram(srv, remoteProgram) < 0) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
+ }
+
+ if (!(lxcProgram = virNetServerProgramNew(LXC_PROGRAM,
+ LXC_PROTOCOL_VERSION,
+ lxcProcs,
+ lxcNProcs))) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
+ }
+ if (virNetServerAddProgram(srv, lxcProgram) < 0) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
+ }
+
+ if (!(qemuProgram = virNetServerProgramNew(QEMU_PROGRAM,
+ QEMU_PROTOCOL_VERSION,
+ qemuProcs,
+ qemuNProcs))) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
+ }
+ if (virNetServerAddProgram(srv, qemuProgram) < 0) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
+ }
+
+ if (!(srvAdm = virNetServerNew("admin", 1,
+ config->admin_min_workers,
+ config->admin_max_workers,
+ 0,
+ config->admin_max_clients,
+ 0,
+ config->admin_keepalive_interval,
+ config->admin_keepalive_count,
+ NULL,
+ remoteAdmClientNew,
+ NULL,
+ remoteAdmClientFree,
+ dmn))) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
+ }
+
+ if (virNetDaemonAddServer(dmn, srvAdm) < 0) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
+ }
+
+ if (!(adminProgram = virNetServerProgramNew(ADMIN_PROGRAM,
+ ADMIN_PROTOCOL_VERSION,
+ adminProcs,
+ adminNProcs))) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
+ }
+ if (virNetServerAddProgram(srvAdm, adminProgram) < 0) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
+ }
+
+ if (timeout != -1) {
+ VIR_DEBUG("Registering shutdown timeout %d", timeout);
+ virNetDaemonAutoShutdown(dmn, timeout);
+ }
+
+ if ((daemonSetupSignals(dmn)) < 0) {
+ ret = VIR_DAEMON_ERR_SIGNAL;
+ goto cleanup;
+ }
+
+ if (config->audit_level) {
+ VIR_DEBUG("Attempting to configure auditing subsystem");
+ if (virAuditOpen(config->audit_level) < 0) {
+ if (config->audit_level > 1) {
+ ret = VIR_DAEMON_ERR_AUDIT;
+ goto cleanup;
+ }
+ VIR_DEBUG("Proceeding without auditing");
+ }
+ }
+ virAuditLog(config->audit_logging > 0);
+
+ /* setup the hooks if any */
+ if (virHookInitialize() < 0) {
+ ret = VIR_DAEMON_ERR_HOOKS;
+ goto cleanup;
+ }
+
+ /* Disable error func, now logging is setup */
+ virSetErrorFunc(NULL, daemonErrorHandler);
+ virSetErrorLogPriorityFunc(daemonErrorLogFilter);
+
+ /*
+ * Call the daemon startup hook
+ * TODO: should we abort the daemon startup if the script returned
+ * an error ?
+ */
+ virHookCall(VIR_HOOK_DRIVER_DAEMON, "-", VIR_HOOK_DAEMON_OP_START,
+ 0, "start", NULL, NULL);
+
+ if (daemonSetupNetworking(srv, srvAdm,
+ config,
+ sock_file,
+ sock_file_ro,
+ sock_file_adm,
+ ipsock, privileged) < 0) {
+ ret = VIR_DAEMON_ERR_NETWORK;
+ goto cleanup;
+ }
+
+ /* Tell parent of daemon that basic initialization is complete
+ * In particular we're ready to accept net connections & have
+ * written the pidfile
+ */
+ if (statuswrite != -1) {
+ char status = 0;
+ ignore_value(safewrite(statuswrite, &status, 1));
+ VIR_FORCE_CLOSE(statuswrite);
+ }
+
+ /* Initialize drivers & then start accepting new clients from network */
+ if (daemonStateInit(dmn) < 0) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
+ }
+
+#if defined(__linux__) && defined(NETLINK_ROUTE)
+ /* Register the netlink event service for NETLINK_ROUTE */
+ if (virNetlinkEventServiceStart(NETLINK_ROUTE, 0) < 0) {
+ ret = VIR_DAEMON_ERR_NETWORK;
+ goto cleanup;
+ }
+#endif
+
+#if defined(__linux__) && defined(NETLINK_KOBJECT_UEVENT)
+ /* Register the netlink event service for NETLINK_KOBJECT_UEVENT */
+ if (virNetlinkEventServiceStart(NETLINK_KOBJECT_UEVENT, 1) < 0) {
+ ret = VIR_DAEMON_ERR_NETWORK;
+ goto cleanup;
+ }
+#endif
+
+ /* Run event loop. */
+ virNetDaemonRun(dmn);
+
+ ret = 0;
+
+ virHookCall(VIR_HOOK_DRIVER_DAEMON, "-", VIR_HOOK_DAEMON_OP_SHUTDOWN,
+ 0, "shutdown", NULL, NULL);
+
+ cleanup:
+ /* Keep cleanup order in inverse order of startup */
+ virNetDaemonClose(dmn);
+
+ virNetlinkEventServiceStopAll();
+
+ if (driversInitialized) {
+ /* NB: Possible issue with timing window between driversInitialized
+ * setting if virNetlinkEventServerStart fails */
+ driversInitialized = false;
+ virStateCleanup();
+ }
+
+ virObjectUnref(adminProgram);
+ virObjectUnref(srvAdm);
+ virObjectUnref(qemuProgram);
+ virObjectUnref(lxcProgram);
+ virObjectUnref(remoteProgram);
+ virObjectUnref(srv);
+ virObjectUnref(dmn);
+
+ virNetlinkShutdown();
+
+ if (pid_file_fd != -1)
+ virPidFileReleasePath(pid_file, pid_file_fd);
+
+ VIR_FREE(run_dir);
+
+ if (statuswrite != -1) {
+ if (ret != 0) {
+ /* Tell parent of daemon what failed */
+ char status = ret;
+ ignore_value(safewrite(statuswrite, &status, 1));
+ }
+ VIR_FORCE_CLOSE(statuswrite);
+ }
+
+ VIR_FREE(sock_file);
+ VIR_FREE(sock_file_ro);
+ VIR_FREE(sock_file_adm);
+
+ VIR_FREE(pid_file);
+
+ VIR_FREE(remote_config_file);
+ daemonConfigFree(config);
+
+ return ret;
+}
--- /dev/null
+/*
+ * remote_daemon.h: daemon data structure definitions
+ *
+ * Copyright (C) 2006-2018 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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 __REMOTE_DAEMON_H__
+# define __REMOTE_DAEMON_H__
+
+# define VIR_ENUM_SENTINELS
+
+# include <rpc/types.h>
+# include <rpc/xdr.h>
+# include "remote_protocol.h"
+# include "lxc_protocol.h"
+# include "qemu_protocol.h"
+# include "virthread.h"
+
+# if WITH_SASL
+# include "virnetsaslcontext.h"
+# endif
+# include "virnetserverprogram.h"
+
+typedef struct daemonClientStream daemonClientStream;
+typedef daemonClientStream *daemonClientStreamPtr;
+typedef struct daemonClientPrivate daemonClientPrivate;
+typedef daemonClientPrivate *daemonClientPrivatePtr;
+typedef struct daemonClientEventCallback daemonClientEventCallback;
+typedef daemonClientEventCallback *daemonClientEventCallbackPtr;
+
+/* Stores the per-client connection state */
+struct daemonClientPrivate {
+ /* Hold while accessing any data except conn */
+ virMutex lock;
+
+ daemonClientEventCallbackPtr *domainEventCallbacks;
+ size_t ndomainEventCallbacks;
+ daemonClientEventCallbackPtr *networkEventCallbacks;
+ size_t nnetworkEventCallbacks;
+ daemonClientEventCallbackPtr *qemuEventCallbacks;
+ size_t nqemuEventCallbacks;
+ daemonClientEventCallbackPtr *storageEventCallbacks;
+ size_t nstorageEventCallbacks;
+ daemonClientEventCallbackPtr *nodeDeviceEventCallbacks;
+ size_t nnodeDeviceEventCallbacks;
+ daemonClientEventCallbackPtr *secretEventCallbacks;
+ size_t nsecretEventCallbacks;
+ bool closeRegistered;
+
+# if WITH_SASL
+ virNetSASLSessionPtr sasl;
+# endif
+
+ /* This is only valid if a remote open call has been made on this
+ * connection, otherwise it will be NULL. Also if remote close is
+ * called, it will be set back to NULL if that succeeds.
+ */
+ virConnectPtr conn;
+
+ daemonClientStreamPtr streams;
+};
+
+
+# if WITH_SASL
+extern virNetSASLContextPtr saslCtxt;
+# endif
+extern virNetServerProgramPtr remoteProgram;
+extern virNetServerProgramPtr qemuProgram;
+
+#endif /* __REMOTE_DAEMON_H__ */
--- /dev/null
+/*
+ * remote_daemon_config.c: libvirtd config file handling
+ *
+ * Copyright (C) 2006-2018 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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 "remote_daemon_config.h"
+#include "virconf.h"
+#include "viralloc.h"
+#include "virerror.h"
+#include "virlog.h"
+#include "rpc/virnetserver.h"
+#include "configmake.h"
+#include "remote_protocol.h"
+#include "remote_driver.h"
+#include "util/virnetdevopenvswitch.h"
+#include "virstring.h"
+#include "virutil.h"
+
+#define VIR_FROM_THIS VIR_FROM_CONF
+
+VIR_LOG_INIT("daemon.libvirtd-config");
+
+
+static int
+remoteConfigGetAuth(virConfPtr conf,
+ const char *filename,
+ const char *key,
+ int *auth)
+{
+ char *authstr = NULL;
+
+ if (virConfGetValueString(conf, key, &authstr) < 0)
+ return -1;
+
+ if (!authstr)
+ return 0;
+
+ if (STREQ(authstr, "none")) {
+ *auth = VIR_NET_SERVER_SERVICE_AUTH_NONE;
+#if WITH_SASL
+ } else if (STREQ(authstr, "sasl")) {
+ *auth = VIR_NET_SERVER_SERVICE_AUTH_SASL;
+#endif
+ } else if (STREQ(authstr, "polkit")) {
+ *auth = VIR_NET_SERVER_SERVICE_AUTH_POLKIT;
+ } else {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("%s: %s: unsupported auth %s"),
+ filename, key, authstr);
+ VIR_FREE(authstr);
+ return -1;
+ }
+
+ VIR_FREE(authstr);
+ return 0;
+}
+
+int
+daemonConfigFilePath(bool privileged, char **configfile)
+{
+ if (privileged) {
+ if (VIR_STRDUP(*configfile, SYSCONFDIR "/libvirt/libvirtd.conf") < 0)
+ goto error;
+ } else {
+ char *configdir = NULL;
+
+ if (!(configdir = virGetUserConfigDirectory()))
+ goto error;
+
+ if (virAsprintf(configfile, "%s/libvirtd.conf", configdir) < 0) {
+ VIR_FREE(configdir);
+ goto error;
+ }
+ VIR_FREE(configdir);
+ }
+
+ return 0;
+
+ error:
+ return -1;
+}
+
+struct daemonConfig*
+daemonConfigNew(bool privileged ATTRIBUTE_UNUSED)
+{
+ struct daemonConfig *data;
+ char *localhost;
+ int ret;
+
+ if (VIR_ALLOC(data) < 0)
+ return NULL;
+
+ data->listen_tls = 1;
+ data->listen_tcp = 0;
+
+ if (VIR_STRDUP(data->tls_port, LIBVIRTD_TLS_PORT) < 0 ||
+ VIR_STRDUP(data->tcp_port, LIBVIRTD_TCP_PORT) < 0)
+ goto error;
+
+ /* Only default to PolicyKit if running as root */
+#if WITH_POLKIT
+ if (privileged) {
+ data->auth_unix_rw = REMOTE_AUTH_POLKIT;
+ data->auth_unix_ro = REMOTE_AUTH_POLKIT;
+ } else {
+#endif
+ data->auth_unix_rw = REMOTE_AUTH_NONE;
+ data->auth_unix_ro = REMOTE_AUTH_NONE;
+#if WITH_POLKIT
+ }
+#endif
+
+ if (VIR_STRDUP(data->unix_sock_rw_perms,
+ data->auth_unix_rw == REMOTE_AUTH_POLKIT ? "0777" : "0700") < 0 ||
+ VIR_STRDUP(data->unix_sock_ro_perms, "0777") < 0 ||
+ VIR_STRDUP(data->unix_sock_admin_perms, "0700") < 0)
+ goto error;
+
+#if WITH_SASL
+ data->auth_tcp = REMOTE_AUTH_SASL;
+#else
+ data->auth_tcp = REMOTE_AUTH_NONE;
+#endif
+ data->auth_tls = REMOTE_AUTH_NONE;
+
+ data->mdns_adv = 0;
+
+ data->min_workers = 5;
+ data->max_workers = 20;
+ data->max_clients = 5000;
+ data->max_queued_clients = 1000;
+ data->max_anonymous_clients = 20;
+
+ data->prio_workers = 5;
+
+ data->max_client_requests = 5;
+
+ data->audit_level = 1;
+ data->audit_logging = 0;
+
+ data->keepalive_interval = 5;
+ data->keepalive_count = 5;
+
+ data->admin_min_workers = 5;
+ data->admin_max_workers = 20;
+ data->admin_max_clients = 5000;
+ data->admin_max_queued_clients = 20;
+ data->admin_max_client_requests = 5;
+
+ data->admin_keepalive_interval = 5;
+ data->admin_keepalive_count = 5;
+
+ data->ovs_timeout = VIR_NETDEV_OVS_DEFAULT_TIMEOUT;
+
+ localhost = virGetHostname();
+ if (localhost == NULL) {
+ /* we couldn't resolve the hostname; assume that we are
+ * running in disconnected operation, and report a less
+ * useful Avahi string
+ */
+ ret = VIR_STRDUP(data->mdns_name, "Virtualization Host");
+ } else {
+ char *tmp;
+ /* Extract the host part of the potentially FQDN */
+ if ((tmp = strchr(localhost, '.')))
+ *tmp = '\0';
+ ret = virAsprintf(&data->mdns_name, "Virtualization Host %s",
+ localhost);
+ }
+ VIR_FREE(localhost);
+ if (ret < 0)
+ goto error;
+
+ return data;
+
+ error:
+ daemonConfigFree(data);
+ return NULL;
+}
+
+void
+daemonConfigFree(struct daemonConfig *data)
+{
+ char **tmp;
+
+ if (!data)
+ return;
+
+ VIR_FREE(data->listen_addr);
+ VIR_FREE(data->tls_port);
+ VIR_FREE(data->tcp_port);
+ tmp = data->access_drivers;
+ while (tmp && *tmp) {
+ VIR_FREE(*tmp);
+ tmp++;
+ }
+ VIR_FREE(data->access_drivers);
+
+ VIR_FREE(data->unix_sock_admin_perms);
+ VIR_FREE(data->unix_sock_ro_perms);
+ VIR_FREE(data->unix_sock_rw_perms);
+ VIR_FREE(data->unix_sock_group);
+ VIR_FREE(data->unix_sock_dir);
+ VIR_FREE(data->mdns_name);
+
+ tmp = data->tls_allowed_dn_list;
+ while (tmp && *tmp) {
+ VIR_FREE(*tmp);
+ tmp++;
+ }
+ VIR_FREE(data->tls_allowed_dn_list);
+
+ tmp = data->sasl_allowed_username_list;
+ while (tmp && *tmp) {
+ VIR_FREE(*tmp);
+ tmp++;
+ }
+ VIR_FREE(data->sasl_allowed_username_list);
+ VIR_FREE(data->tls_priority);
+
+ VIR_FREE(data->key_file);
+ VIR_FREE(data->ca_file);
+ VIR_FREE(data->cert_file);
+ VIR_FREE(data->crl_file);
+
+ VIR_FREE(data->host_uuid);
+ VIR_FREE(data->host_uuid_source);
+ VIR_FREE(data->log_filters);
+ VIR_FREE(data->log_outputs);
+
+ VIR_FREE(data);
+}
+
+static int
+daemonConfigLoadOptions(struct daemonConfig *data,
+ const char *filename,
+ virConfPtr conf)
+{
+ if (virConfGetValueBool(conf, "listen_tcp", &data->listen_tcp) < 0)
+ goto error;
+ if (virConfGetValueBool(conf, "listen_tls", &data->listen_tls) < 0)
+ goto error;
+ if (virConfGetValueString(conf, "tls_port", &data->tls_port) < 0)
+ goto error;
+ if (virConfGetValueString(conf, "tcp_port", &data->tcp_port) < 0)
+ goto error;
+ if (virConfGetValueString(conf, "listen_addr", &data->listen_addr) < 0)
+ goto error;
+
+ if (remoteConfigGetAuth(conf, filename, "auth_unix_rw", &data->auth_unix_rw) < 0)
+ goto error;
+#if WITH_POLKIT
+ /* Change default perms to be wide-open if PolicyKit is enabled.
+ * Admin can always override in config file
+ */
+ if (data->auth_unix_rw == REMOTE_AUTH_POLKIT) {
+ VIR_FREE(data->unix_sock_rw_perms);
+ if (VIR_STRDUP(data->unix_sock_rw_perms, "0777") < 0)
+ goto error;
+ }
+#endif
+ if (remoteConfigGetAuth(conf, filename, "auth_unix_ro", &data->auth_unix_ro) < 0)
+ goto error;
+ if (remoteConfigGetAuth(conf, filename, "auth_tcp", &data->auth_tcp) < 0)
+ goto error;
+ if (remoteConfigGetAuth(conf, filename, "auth_tls", &data->auth_tls) < 0)
+ goto error;
+
+ if (virConfGetValueStringList(conf, "access_drivers", false,
+ &data->access_drivers) < 0)
+ goto error;
+
+ if (virConfGetValueString(conf, "unix_sock_group", &data->unix_sock_group) < 0)
+ goto error;
+ if (virConfGetValueString(conf, "unix_sock_admin_perms", &data->unix_sock_admin_perms) < 0)
+ goto error;
+ if (virConfGetValueString(conf, "unix_sock_ro_perms", &data->unix_sock_ro_perms) < 0)
+ goto error;
+ if (virConfGetValueString(conf, "unix_sock_rw_perms", &data->unix_sock_rw_perms) < 0)
+ goto error;
+
+ if (virConfGetValueString(conf, "unix_sock_dir", &data->unix_sock_dir) < 0)
+ goto error;
+
+ if (virConfGetValueBool(conf, "mdns_adv", &data->mdns_adv) < 0)
+ goto error;
+ if (virConfGetValueString(conf, "mdns_name", &data->mdns_name) < 0)
+ goto error;
+
+ if (virConfGetValueBool(conf, "tls_no_sanity_certificate", &data->tls_no_sanity_certificate) < 0)
+ goto error;
+ if (virConfGetValueBool(conf, "tls_no_verify_certificate", &data->tls_no_verify_certificate) < 0)
+ goto error;
+
+ if (virConfGetValueString(conf, "key_file", &data->key_file) < 0)
+ goto error;
+ if (virConfGetValueString(conf, "cert_file", &data->cert_file) < 0)
+ goto error;
+ if (virConfGetValueString(conf, "ca_file", &data->ca_file) < 0)
+ goto error;
+ if (virConfGetValueString(conf, "crl_file", &data->crl_file) < 0)
+ goto error;
+
+ if (virConfGetValueStringList(conf, "tls_allowed_dn_list", false,
+ &data->tls_allowed_dn_list) < 0)
+ goto error;
+
+
+ if (virConfGetValueStringList(conf, "sasl_allowed_username_list", false,
+ &data->sasl_allowed_username_list) < 0)
+ goto error;
+
+ if (virConfGetValueString(conf, "tls_priority", &data->tls_priority) < 0)
+ goto error;
+
+ if (virConfGetValueUInt(conf, "min_workers", &data->min_workers) < 0)
+ goto error;
+ if (virConfGetValueUInt(conf, "max_workers", &data->max_workers) < 0)
+ goto error;
+ if (virConfGetValueUInt(conf, "max_clients", &data->max_clients) < 0)
+ goto error;
+ if (virConfGetValueUInt(conf, "max_queued_clients", &data->max_queued_clients) < 0)
+ goto error;
+ if (virConfGetValueUInt(conf, "max_anonymous_clients", &data->max_anonymous_clients) < 0)
+ goto error;
+
+ if (virConfGetValueUInt(conf, "prio_workers", &data->prio_workers) < 0)
+ goto error;
+
+ if (virConfGetValueUInt(conf, "max_client_requests", &data->max_client_requests) < 0)
+ goto error;
+
+ if (virConfGetValueUInt(conf, "admin_min_workers", &data->admin_min_workers) < 0)
+ goto error;
+ if (virConfGetValueUInt(conf, "admin_max_workers", &data->admin_max_workers) < 0)
+ goto error;
+ if (virConfGetValueUInt(conf, "admin_max_clients", &data->admin_max_clients) < 0)
+ goto error;
+ if (virConfGetValueUInt(conf, "admin_max_queued_clients", &data->admin_max_queued_clients) < 0)
+ goto error;
+ if (virConfGetValueUInt(conf, "admin_max_client_requests", &data->admin_max_client_requests) < 0)
+ goto error;
+
+ if (virConfGetValueUInt(conf, "audit_level", &data->audit_level) < 0)
+ goto error;
+ if (virConfGetValueBool(conf, "audit_logging", &data->audit_logging) < 0)
+ goto error;
+
+ if (virConfGetValueString(conf, "host_uuid", &data->host_uuid) < 0)
+ goto error;
+ if (virConfGetValueString(conf, "host_uuid_source", &data->host_uuid_source) < 0)
+ goto error;
+
+ if (virConfGetValueUInt(conf, "log_level", &data->log_level) < 0)
+ goto error;
+ if (virConfGetValueString(conf, "log_filters", &data->log_filters) < 0)
+ goto error;
+ if (virConfGetValueString(conf, "log_outputs", &data->log_outputs) < 0)
+ goto error;
+
+ if (virConfGetValueInt(conf, "keepalive_interval", &data->keepalive_interval) < 0)
+ goto error;
+ if (virConfGetValueUInt(conf, "keepalive_count", &data->keepalive_count) < 0)
+ goto error;
+
+ if (virConfGetValueInt(conf, "admin_keepalive_interval", &data->admin_keepalive_interval) < 0)
+ goto error;
+ if (virConfGetValueUInt(conf, "admin_keepalive_count", &data->admin_keepalive_count) < 0)
+ goto error;
+
+ if (virConfGetValueUInt(conf, "ovs_timeout", &data->ovs_timeout) < 0)
+ goto error;
+
+ return 0;
+
+ error:
+ return -1;
+}
+
+
+/* Read the config file if it exists.
+ * Only used in the remote case, hence the name.
+ */
+int
+daemonConfigLoadFile(struct daemonConfig *data,
+ const char *filename,
+ bool allow_missing)
+{
+ virConfPtr conf;
+ int ret;
+
+ if (allow_missing &&
+ access(filename, R_OK) == -1 &&
+ errno == ENOENT)
+ return 0;
+
+ conf = virConfReadFile(filename, 0);
+ if (!conf)
+ return -1;
+
+ ret = daemonConfigLoadOptions(data, filename, conf);
+ virConfFree(conf);
+ return ret;
+}
+
+int daemonConfigLoadData(struct daemonConfig *data,
+ const char *filename,
+ const char *filedata)
+{
+ virConfPtr conf;
+ int ret;
+
+ conf = virConfReadString(filedata, 0);
+ if (!conf)
+ return -1;
+
+ ret = daemonConfigLoadOptions(data, filename, conf);
+ virConfFree(conf);
+ return ret;
+}
--- /dev/null
+/*
+ * remote_daemon_config.h: libvirtd config file handling
+ *
+ * Copyright (C) 2006-2018 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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 __REMOTE_DAEMON_CONFIG_H__
+# define __REMOTE_DAEMON_CONFIG_H__
+
+# include "internal.h"
+
+struct daemonConfig {
+ char *host_uuid;
+ char *host_uuid_source;
+
+ bool listen_tls;
+ bool listen_tcp;
+ char *listen_addr;
+ char *tls_port;
+ char *tcp_port;
+
+ char *unix_sock_admin_perms;
+ char *unix_sock_ro_perms;
+ char *unix_sock_rw_perms;
+ char *unix_sock_group;
+ char *unix_sock_dir;
+
+ int auth_unix_rw;
+ int auth_unix_ro;
+ int auth_tcp;
+ int auth_tls;
+
+ char **access_drivers;
+
+ bool mdns_adv;
+ char *mdns_name;
+
+ bool tls_no_verify_certificate;
+ bool tls_no_sanity_certificate;
+ char **tls_allowed_dn_list;
+ char **sasl_allowed_username_list;
+ char *tls_priority;
+
+ char *key_file;
+ char *cert_file;
+ char *ca_file;
+ char *crl_file;
+
+ unsigned int min_workers;
+ unsigned int max_workers;
+ unsigned int max_clients;
+ unsigned int max_queued_clients;
+ unsigned int max_anonymous_clients;
+
+ unsigned int prio_workers;
+
+ unsigned int max_client_requests;
+
+ unsigned int log_level;
+ char *log_filters;
+ char *log_outputs;
+
+ unsigned int audit_level;
+ bool audit_logging;
+
+ int keepalive_interval;
+ unsigned int keepalive_count;
+
+ unsigned int admin_min_workers;
+ unsigned int admin_max_workers;
+ unsigned int admin_max_clients;
+ unsigned int admin_max_queued_clients;
+ unsigned int admin_max_client_requests;
+
+ int admin_keepalive_interval;
+ unsigned int admin_keepalive_count;
+
+ unsigned int ovs_timeout;
+};
+
+
+int daemonConfigFilePath(bool privileged, char **configfile);
+struct daemonConfig* daemonConfigNew(bool privileged);
+void daemonConfigFree(struct daemonConfig *data);
+int daemonConfigLoadFile(struct daemonConfig *data,
+ const char *filename,
+ bool allow_missing);
+int daemonConfigLoadData(struct daemonConfig *data,
+ const char *filename,
+ const char *filedata);
+
+#endif /* __REMOTE_DAEMON_CONFIG_H__ */
--- /dev/null
+/*
+ * remote_daemon_dispatch.c: handlers for RPC method calls
+ *
+ * Copyright (C) 2007-2018 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: Richard W.M. Jones <rjones@redhat.com>
+ */
+
+#include <config.h>
+
+#include "virerror.h"
+
+#include "remote_daemon_dispatch.h"
+#include "remote_daemon.h"
+#include "libvirt_internal.h"
+#include "datatypes.h"
+#include "viralloc.h"
+#include "virlog.h"
+#include "remote_daemon_stream.h"
+#include "viruuid.h"
+#include "vircommand.h"
+#include "intprops.h"
+#include "virnetserverservice.h"
+#include "virnetserver.h"
+#include "virfile.h"
+#include "virtypedparam.h"
+#include "virdbus.h"
+#include "virprocess.h"
+#include "remote_protocol.h"
+#include "qemu_protocol.h"
+#include "lxc_protocol.h"
+#include "virstring.h"
+#include "object_event.h"
+#include "domain_conf.h"
+#include "network_conf.h"
+#include "virprobe.h"
+#include "viraccessapicheck.h"
+#include "viraccessapicheckqemu.h"
+#include "virpolkit.h"
+#include "virthreadjob.h"
+
+#define VIR_FROM_THIS VIR_FROM_RPC
+
+VIR_LOG_INIT("daemon.remote");
+
+#if SIZEOF_LONG < 8
+# define HYPER_TO_TYPE(_type, _to, _from) \
+ do { \
+ if ((_from) != (_type)(_from)) { \
+ virReportError(VIR_ERR_OVERFLOW, \
+ _("conversion from hyper to %s overflowed"), \
+ #_type); \
+ goto cleanup; \
+ } \
+ (_to) = (_from); \
+ } while (0)
+
+# define HYPER_TO_LONG(_to, _from) HYPER_TO_TYPE(long, _to, _from)
+# define HYPER_TO_ULONG(_to, _from) HYPER_TO_TYPE(unsigned long, _to, _from)
+#else
+# define HYPER_TO_LONG(_to, _from) (_to) = (_from)
+# define HYPER_TO_ULONG(_to, _from) (_to) = (_from)
+#endif
+
+struct daemonClientEventCallback {
+ virNetServerClientPtr client;
+ int eventID;
+ int callbackID;
+ bool legacy;
+};
+
+static virDomainPtr get_nonnull_domain(virConnectPtr conn, remote_nonnull_domain domain);
+static virNetworkPtr get_nonnull_network(virConnectPtr conn, remote_nonnull_network network);
+static virInterfacePtr get_nonnull_interface(virConnectPtr conn, remote_nonnull_interface iface);
+static virStoragePoolPtr get_nonnull_storage_pool(virConnectPtr conn, remote_nonnull_storage_pool pool);
+static virStorageVolPtr get_nonnull_storage_vol(virConnectPtr conn, remote_nonnull_storage_vol vol);
+static virSecretPtr get_nonnull_secret(virConnectPtr conn, remote_nonnull_secret secret);
+static virNWFilterPtr get_nonnull_nwfilter(virConnectPtr conn, remote_nonnull_nwfilter nwfilter);
+static virDomainSnapshotPtr get_nonnull_domain_snapshot(virDomainPtr dom, remote_nonnull_domain_snapshot snapshot);
+static virNodeDevicePtr get_nonnull_node_device(virConnectPtr conn, remote_nonnull_node_device dev);
+static void make_nonnull_domain(remote_nonnull_domain *dom_dst, virDomainPtr dom_src);
+static void make_nonnull_network(remote_nonnull_network *net_dst, virNetworkPtr net_src);
+static void make_nonnull_interface(remote_nonnull_interface *interface_dst, virInterfacePtr interface_src);
+static void make_nonnull_storage_pool(remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr pool_src);
+static void make_nonnull_storage_vol(remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src);
+static void make_nonnull_node_device(remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src);
+static void make_nonnull_secret(remote_nonnull_secret *secret_dst, virSecretPtr secret_src);
+static void make_nonnull_nwfilter(remote_nonnull_nwfilter *net_dst, virNWFilterPtr nwfilter_src);
+static void make_nonnull_domain_snapshot(remote_nonnull_domain_snapshot *snapshot_dst, virDomainSnapshotPtr snapshot_src);
+
+static int
+remoteSerializeDomainDiskErrors(virDomainDiskErrorPtr errors,
+ int nerrors,
+ remote_domain_disk_error **ret_errors_val,
+ u_int *ret_errors_len);
+
+#include "remote_daemon_dispatch_stubs.h"
+#include "remote_daemon_dispatch_qemu_stubs.h"
+#include "remote_daemon_dispatch_lxc_stubs.h"
+
+
+/* Prototypes */
+static void
+remoteDispatchObjectEventSend(virNetServerClientPtr client,
+ virNetServerProgramPtr program,
+ int procnr,
+ xdrproc_t proc,
+ void *data);
+
+static void
+remoteEventCallbackFree(void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ if (!callback)
+ return;
+ virObjectUnref(callback->client);
+ VIR_FREE(callback);
+}
+
+
+static bool
+remoteRelayDomainEventCheckACL(virNetServerClientPtr client,
+ virConnectPtr conn, virDomainPtr dom)
+{
+ virDomainDef def;
+ virIdentityPtr identity = NULL;
+ bool ret = false;
+
+ /* For now, we just create a virDomainDef with enough contents to
+ * satisfy what viraccessdriverpolkit.c references. This is a bit
+ * fragile, but I don't know of anything better. */
+ memset(&def, 0, sizeof(def));
+ def.name = dom->name;
+ memcpy(def.uuid, dom->uuid, VIR_UUID_BUFLEN);
+
+ if (!(identity = virNetServerClientGetIdentity(client)))
+ goto cleanup;
+ if (virIdentitySetCurrent(identity) < 0)
+ goto cleanup;
+ ret = virConnectDomainEventRegisterAnyCheckACL(conn, &def);
+
+ cleanup:
+ ignore_value(virIdentitySetCurrent(NULL));
+ virObjectUnref(identity);
+ return ret;
+}
+
+
+static bool
+remoteRelayNetworkEventCheckACL(virNetServerClientPtr client,
+ virConnectPtr conn, virNetworkPtr net)
+{
+ virNetworkDef def;
+ virIdentityPtr identity = NULL;
+ bool ret = false;
+
+ /* For now, we just create a virNetworkDef with enough contents to
+ * satisfy what viraccessdriverpolkit.c references. This is a bit
+ * fragile, but I don't know of anything better. */
+ def.name = net->name;
+ memcpy(def.uuid, net->uuid, VIR_UUID_BUFLEN);
+
+ if (!(identity = virNetServerClientGetIdentity(client)))
+ goto cleanup;
+ if (virIdentitySetCurrent(identity) < 0)
+ goto cleanup;
+ ret = virConnectNetworkEventRegisterAnyCheckACL(conn, &def);
+
+ cleanup:
+ ignore_value(virIdentitySetCurrent(NULL));
+ virObjectUnref(identity);
+ return ret;
+}
+
+static bool
+remoteRelayStoragePoolEventCheckACL(virNetServerClientPtr client,
+ virConnectPtr conn,
+ virStoragePoolPtr pool)
+{
+ virStoragePoolDef def;
+ virIdentityPtr identity = NULL;
+ bool ret = false;
+
+ /* For now, we just create a virStoragePoolDef with enough contents to
+ * satisfy what viraccessdriverpolkit.c references. This is a bit
+ * fragile, but I don't know of anything better. */
+ def.name = pool->name;
+ memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN);
+
+ if (!(identity = virNetServerClientGetIdentity(client)))
+ goto cleanup;
+ if (virIdentitySetCurrent(identity) < 0)
+ goto cleanup;
+ ret = virConnectStoragePoolEventRegisterAnyCheckACL(conn, &def);
+
+ cleanup:
+ ignore_value(virIdentitySetCurrent(NULL));
+ virObjectUnref(identity);
+ return ret;
+}
+
+static bool
+remoteRelayNodeDeviceEventCheckACL(virNetServerClientPtr client,
+ virConnectPtr conn,
+ virNodeDevicePtr dev)
+{
+ virNodeDeviceDef def;
+ virIdentityPtr identity = NULL;
+ bool ret = false;
+
+ /* For now, we just create a virNodeDeviceDef with enough contents to
+ * satisfy what viraccessdriverpolkit.c references. This is a bit
+ * fragile, but I don't know of anything better. */
+ def.name = dev->name;
+
+ if (!(identity = virNetServerClientGetIdentity(client)))
+ goto cleanup;
+ if (virIdentitySetCurrent(identity) < 0)
+ goto cleanup;
+ ret = virConnectNodeDeviceEventRegisterAnyCheckACL(conn, &def);
+
+ cleanup:
+ ignore_value(virIdentitySetCurrent(NULL));
+ virObjectUnref(identity);
+ return ret;
+}
+
+static bool
+remoteRelaySecretEventCheckACL(virNetServerClientPtr client,
+ virConnectPtr conn,
+ virSecretPtr secret)
+{
+ virSecretDef def;
+ virIdentityPtr identity = NULL;
+ bool ret = false;
+
+ /* For now, we just create a virSecretDef with enough contents to
+ * satisfy what viraccessdriverpolkit.c references. This is a bit
+ * fragile, but I don't know of anything better. */
+ memcpy(def.uuid, secret->uuid, VIR_UUID_BUFLEN);
+ def.usage_type = secret->usageType;
+ def.usage_id = secret->usageID;
+
+ if (!(identity = virNetServerClientGetIdentity(client)))
+ goto cleanup;
+ if (virIdentitySetCurrent(identity) < 0)
+ goto cleanup;
+ ret = virConnectSecretEventRegisterAnyCheckACL(conn, &def);
+
+ cleanup:
+ ignore_value(virIdentitySetCurrent(NULL));
+ virObjectUnref(identity);
+ return ret;
+}
+
+static bool
+remoteRelayDomainQemuMonitorEventCheckACL(virNetServerClientPtr client,
+ virConnectPtr conn, virDomainPtr dom)
+{
+ virDomainDef def;
+ virIdentityPtr identity = NULL;
+ bool ret = false;
+
+ /* For now, we just create a virDomainDef with enough contents to
+ * satisfy what viraccessdriverpolkit.c references. This is a bit
+ * fragile, but I don't know of anything better. */
+ def.name = dom->name;
+ memcpy(def.uuid, dom->uuid, VIR_UUID_BUFLEN);
+
+ if (!(identity = virNetServerClientGetIdentity(client)))
+ goto cleanup;
+ if (virIdentitySetCurrent(identity) < 0)
+ goto cleanup;
+ ret = virConnectDomainQemuMonitorEventRegisterCheckACL(conn, &def);
+
+ cleanup:
+ ignore_value(virIdentitySetCurrent(NULL));
+ virObjectUnref(identity);
+ return ret;
+}
+
+
+static int
+remoteRelayDomainEventLifecycle(virConnectPtr conn,
+ virDomainPtr dom,
+ int event,
+ int detail,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_lifecycle_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain lifecycle event %d %d, callback %d legacy %d",
+ event, detail, callback->callbackID, callback->legacy);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_domain(&data.dom, dom);
+ data.event = event;
+ data.detail = detail;
+
+ if (callback->legacy) {
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE,
+ (xdrproc_t)xdr_remote_domain_event_lifecycle_msg,
+ &data);
+ } else {
+ remote_domain_event_callback_lifecycle_msg msg = { callback->callbackID,
+ data };
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_LIFECYCLE,
+ (xdrproc_t)xdr_remote_domain_event_callback_lifecycle_msg,
+ &msg);
+ }
+
+ return 0;
+}
+
+static int
+remoteRelayDomainEventReboot(virConnectPtr conn,
+ virDomainPtr dom,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_reboot_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain reboot event %s %d, callback %d legacy %d",
+ dom->name, dom->id, callback->callbackID, callback->legacy);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_domain(&data.dom, dom);
+
+ if (callback->legacy) {
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_REBOOT,
+ (xdrproc_t)xdr_remote_domain_event_reboot_msg, &data);
+ } else {
+ remote_domain_event_callback_reboot_msg msg = { callback->callbackID,
+ data };
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_REBOOT,
+ (xdrproc_t)xdr_remote_domain_event_callback_reboot_msg, &msg);
+ }
+
+ return 0;
+}
+
+
+static int
+remoteRelayDomainEventRTCChange(virConnectPtr conn,
+ virDomainPtr dom,
+ long long offset,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_rtc_change_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain rtc change event %s %d %lld, callback %d legacy %d",
+ dom->name, dom->id, offset,
+ callback->callbackID, callback->legacy);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_domain(&data.dom, dom);
+ data.offset = offset;
+
+ if (callback->legacy) {
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
+ (xdrproc_t)xdr_remote_domain_event_rtc_change_msg, &data);
+ } else {
+ remote_domain_event_callback_rtc_change_msg msg = { callback->callbackID,
+ data };
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_RTC_CHANGE,
+ (xdrproc_t)xdr_remote_domain_event_callback_rtc_change_msg, &msg);
+ }
+
+ return 0;
+}
+
+
+static int
+remoteRelayDomainEventWatchdog(virConnectPtr conn,
+ virDomainPtr dom,
+ int action,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_watchdog_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain watchdog event %s %d %d, callback %d",
+ dom->name, dom->id, action, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_domain(&data.dom, dom);
+ data.action = action;
+
+ if (callback->legacy) {
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_WATCHDOG,
+ (xdrproc_t)xdr_remote_domain_event_watchdog_msg, &data);
+ } else {
+ remote_domain_event_callback_watchdog_msg msg = { callback->callbackID,
+ data };
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_WATCHDOG,
+ (xdrproc_t)xdr_remote_domain_event_callback_watchdog_msg, &msg);
+ }
+
+ return 0;
+}
+
+
+static int
+remoteRelayDomainEventIOError(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *srcPath,
+ const char *devAlias,
+ int action,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_io_error_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain io error %s %d %s %s %d, callback %d",
+ dom->name, dom->id, srcPath, devAlias, action,
+ callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ if (VIR_STRDUP(data.srcPath, srcPath) < 0 ||
+ VIR_STRDUP(data.devAlias, devAlias) < 0)
+ goto error;
+ make_nonnull_domain(&data.dom, dom);
+ data.action = action;
+
+ if (callback->legacy) {
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_IO_ERROR,
+ (xdrproc_t)xdr_remote_domain_event_io_error_msg, &data);
+ } else {
+ remote_domain_event_callback_io_error_msg msg = { callback->callbackID,
+ data };
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_IO_ERROR,
+ (xdrproc_t)xdr_remote_domain_event_callback_io_error_msg, &msg);
+ }
+
+ return 0;
+ error:
+ VIR_FREE(data.srcPath);
+ VIR_FREE(data.devAlias);
+ return -1;
+}
+
+
+static int
+remoteRelayDomainEventIOErrorReason(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *srcPath,
+ const char *devAlias,
+ int action,
+ const char *reason,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_io_error_reason_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain io error %s %d %s %s %d %s, callback %d",
+ dom->name, dom->id, srcPath, devAlias, action, reason,
+ callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ if (VIR_STRDUP(data.srcPath, srcPath) < 0 ||
+ VIR_STRDUP(data.devAlias, devAlias) < 0 ||
+ VIR_STRDUP(data.reason, reason) < 0)
+ goto error;
+ data.action = action;
+
+ make_nonnull_domain(&data.dom, dom);
+
+ if (callback->legacy) {
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON,
+ (xdrproc_t)xdr_remote_domain_event_io_error_reason_msg, &data);
+ } else {
+ remote_domain_event_callback_io_error_reason_msg msg = { callback->callbackID,
+ data };
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_IO_ERROR_REASON,
+ (xdrproc_t)xdr_remote_domain_event_callback_io_error_reason_msg, &msg);
+ }
+
+ return 0;
+
+ error:
+ VIR_FREE(data.srcPath);
+ VIR_FREE(data.devAlias);
+ VIR_FREE(data.reason);
+ return -1;
+}
+
+
+static int
+remoteRelayDomainEventGraphics(virConnectPtr conn,
+ virDomainPtr dom,
+ int phase,
+ virDomainEventGraphicsAddressPtr local,
+ virDomainEventGraphicsAddressPtr remote,
+ const char *authScheme,
+ virDomainEventGraphicsSubjectPtr subject,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_graphics_msg data;
+ size_t i;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain graphics event %s %d %d - %d %s %s - %d %s %s - %s, callback %d",
+ dom->name, dom->id, phase,
+ local->family, local->service, local->node,
+ remote->family, remote->service, remote->node,
+ authScheme, callback->callbackID);
+
+ VIR_DEBUG("Subject %d", subject->nidentity);
+ for (i = 0; i < subject->nidentity; i++)
+ VIR_DEBUG(" %s=%s", subject->identities[i].type, subject->identities[i].name);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ data.phase = phase;
+ data.local.family = local->family;
+ data.remote.family = remote->family;
+ if (VIR_STRDUP(data.authScheme, authScheme) < 0 ||
+ VIR_STRDUP(data.local.node, local->node) < 0 ||
+ VIR_STRDUP(data.local.service, local->service) < 0 ||
+ VIR_STRDUP(data.remote.node, remote->node) < 0 ||
+ VIR_STRDUP(data.remote.service, remote->service) < 0)
+ goto error;
+
+ data.subject.subject_len = subject->nidentity;
+ if (VIR_ALLOC_N(data.subject.subject_val, data.subject.subject_len) < 0)
+ goto error;
+
+ for (i = 0; i < data.subject.subject_len; i++) {
+ if (VIR_STRDUP(data.subject.subject_val[i].type, subject->identities[i].type) < 0 ||
+ VIR_STRDUP(data.subject.subject_val[i].name, subject->identities[i].name) < 0)
+ goto error;
+ }
+ make_nonnull_domain(&data.dom, dom);
+
+ if (callback->legacy) {
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_GRAPHICS,
+ (xdrproc_t)xdr_remote_domain_event_graphics_msg, &data);
+ } else {
+ remote_domain_event_callback_graphics_msg msg = { callback->callbackID,
+ data };
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_GRAPHICS,
+ (xdrproc_t)xdr_remote_domain_event_callback_graphics_msg, &msg);
+ }
+
+ return 0;
+
+ error:
+ VIR_FREE(data.authScheme);
+ VIR_FREE(data.local.node);
+ VIR_FREE(data.local.service);
+ VIR_FREE(data.remote.node);
+ VIR_FREE(data.remote.service);
+ if (data.subject.subject_val != NULL) {
+ for (i = 0; i < data.subject.subject_len; i++) {
+ VIR_FREE(data.subject.subject_val[i].type);
+ VIR_FREE(data.subject.subject_val[i].name);
+ }
+ VIR_FREE(data.subject.subject_val);
+ }
+ return -1;
+}
+
+static int
+remoteRelayDomainEventBlockJob(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *path,
+ int type,
+ int status,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_block_job_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain block job event %s %d %s %i, %i, callback %d",
+ dom->name, dom->id, path, type, status, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ if (VIR_STRDUP(data.path, path) < 0)
+ return -1;
+ data.type = type;
+ data.status = status;
+ make_nonnull_domain(&data.dom, dom);
+
+ if (callback->legacy) {
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB,
+ (xdrproc_t)xdr_remote_domain_event_block_job_msg, &data);
+ } else {
+ remote_domain_event_callback_block_job_msg msg = { callback->callbackID,
+ data };
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_BLOCK_JOB,
+ (xdrproc_t)xdr_remote_domain_event_callback_block_job_msg, &msg);
+ }
+
+ return 0;
+}
+
+
+static int
+remoteRelayDomainEventControlError(virConnectPtr conn,
+ virDomainPtr dom,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_control_error_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain control error %s %d, callback %d",
+ dom->name, dom->id, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_domain(&data.dom, dom);
+
+ if (callback->legacy) {
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR,
+ (xdrproc_t)xdr_remote_domain_event_control_error_msg, &data);
+ } else {
+ remote_domain_event_callback_control_error_msg msg = { callback->callbackID,
+ data };
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_CONTROL_ERROR,
+ (xdrproc_t)xdr_remote_domain_event_callback_control_error_msg, &msg);
+ }
+
+ return 0;
+}
+
+
+static int
+remoteRelayDomainEventDiskChange(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *oldSrcPath,
+ const char *newSrcPath,
+ const char *devAlias,
+ int reason,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_disk_change_msg data;
+ char **oldSrcPath_p = NULL, **newSrcPath_p = NULL;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain %s %d disk change %s %s %s %d, callback %d",
+ dom->name, dom->id, oldSrcPath, newSrcPath, devAlias, reason,
+ callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ if (oldSrcPath &&
+ ((VIR_ALLOC(oldSrcPath_p) < 0) ||
+ VIR_STRDUP(*oldSrcPath_p, oldSrcPath) < 0))
+ goto error;
+
+ if (newSrcPath &&
+ ((VIR_ALLOC(newSrcPath_p) < 0) ||
+ VIR_STRDUP(*newSrcPath_p, newSrcPath) < 0))
+ goto error;
+
+ data.oldSrcPath = oldSrcPath_p;
+ data.newSrcPath = newSrcPath_p;
+ if (VIR_STRDUP(data.devAlias, devAlias) < 0)
+ goto error;
+ data.reason = reason;
+
+ make_nonnull_domain(&data.dom, dom);
+
+ if (callback->legacy) {
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_DISK_CHANGE,
+ (xdrproc_t)xdr_remote_domain_event_disk_change_msg, &data);
+ } else {
+ remote_domain_event_callback_disk_change_msg msg = { callback->callbackID,
+ data };
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DISK_CHANGE,
+ (xdrproc_t)xdr_remote_domain_event_callback_disk_change_msg, &msg);
+ }
+
+ return 0;
+
+ error:
+ VIR_FREE(oldSrcPath_p);
+ VIR_FREE(newSrcPath_p);
+ return -1;
+}
+
+
+static int
+remoteRelayDomainEventTrayChange(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *devAlias,
+ int reason,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_tray_change_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain %s %d tray change devAlias: %s reason: %d, callback %d",
+ dom->name, dom->id, devAlias, reason, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+
+ if (VIR_STRDUP(data.devAlias, devAlias) < 0)
+ return -1;
+ data.reason = reason;
+
+ make_nonnull_domain(&data.dom, dom);
+
+ if (callback->legacy) {
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_TRAY_CHANGE,
+ (xdrproc_t)xdr_remote_domain_event_tray_change_msg, &data);
+ } else {
+ remote_domain_event_callback_tray_change_msg msg = { callback->callbackID,
+ data };
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_TRAY_CHANGE,
+ (xdrproc_t)xdr_remote_domain_event_callback_tray_change_msg, &msg);
+ }
+
+ return 0;
+}
+
+static int
+remoteRelayDomainEventPMWakeup(virConnectPtr conn,
+ virDomainPtr dom,
+ int reason,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_pmwakeup_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain %s %d system pmwakeup, callback %d",
+ dom->name, dom->id, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_domain(&data.dom, dom);
+
+ if (callback->legacy) {
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_PMWAKEUP,
+ (xdrproc_t)xdr_remote_domain_event_pmwakeup_msg, &data);
+ } else {
+ remote_domain_event_callback_pmwakeup_msg msg = { callback->callbackID,
+ reason, data };
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMWAKEUP,
+ (xdrproc_t)xdr_remote_domain_event_callback_pmwakeup_msg, &msg);
+ }
+
+ return 0;
+}
+
+static int
+remoteRelayDomainEventPMSuspend(virConnectPtr conn,
+ virDomainPtr dom,
+ int reason,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_pmsuspend_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain %s %d system pmsuspend, callback %d",
+ dom->name, dom->id, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_domain(&data.dom, dom);
+
+ if (callback->legacy) {
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND,
+ (xdrproc_t)xdr_remote_domain_event_pmsuspend_msg, &data);
+ } else {
+ remote_domain_event_callback_pmsuspend_msg msg = { callback->callbackID,
+ reason, data };
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMSUSPEND,
+ (xdrproc_t)xdr_remote_domain_event_callback_pmsuspend_msg, &msg);
+ }
+
+ return 0;
+}
+
+static int
+remoteRelayDomainEventBalloonChange(virConnectPtr conn,
+ virDomainPtr dom,
+ unsigned long long actual,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_balloon_change_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain balloon change event %s %d %lld, callback %d",
+ dom->name, dom->id, actual, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_domain(&data.dom, dom);
+ data.actual = actual;
+
+ if (callback->legacy) {
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE,
+ (xdrproc_t)xdr_remote_domain_event_balloon_change_msg, &data);
+ } else {
+ remote_domain_event_callback_balloon_change_msg msg = { callback->callbackID,
+ data };
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_BALLOON_CHANGE,
+ (xdrproc_t)xdr_remote_domain_event_callback_balloon_change_msg, &msg);
+ }
+
+ return 0;
+}
+
+
+static int
+remoteRelayDomainEventPMSuspendDisk(virConnectPtr conn,
+ virDomainPtr dom,
+ int reason,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_pmsuspend_disk_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain %s %d system pmsuspend-disk, callback %d",
+ dom->name, dom->id, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_domain(&data.dom, dom);
+
+ if (callback->legacy) {
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND_DISK,
+ (xdrproc_t)xdr_remote_domain_event_pmsuspend_disk_msg, &data);
+ } else {
+ remote_domain_event_callback_pmsuspend_disk_msg msg = { callback->callbackID,
+ reason, data };
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMSUSPEND_DISK,
+ (xdrproc_t)xdr_remote_domain_event_callback_pmsuspend_disk_msg, &msg);
+ }
+
+ return 0;
+}
+
+static int
+remoteRelayDomainEventDeviceRemoved(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *devAlias,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_device_removed_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain device removed event %s %d %s, callback %d",
+ dom->name, dom->id, devAlias, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+
+ if (VIR_STRDUP(data.devAlias, devAlias) < 0)
+ return -1;
+
+ make_nonnull_domain(&data.dom, dom);
+
+ if (callback->legacy) {
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED,
+ (xdrproc_t)xdr_remote_domain_event_device_removed_msg,
+ &data);
+ } else {
+ remote_domain_event_callback_device_removed_msg msg = { callback->callbackID,
+ data };
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVED,
+ (xdrproc_t)xdr_remote_domain_event_callback_device_removed_msg,
+ &msg);
+ }
+
+ return 0;
+}
+
+
+static int
+remoteRelayDomainEventBlockJob2(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *dst,
+ int type,
+ int status,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_block_job_2_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain block job 2 event %s %d %s %i, %i, callback %d",
+ dom->name, dom->id, dst, type, status, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ data.callbackID = callback->callbackID;
+ if (VIR_STRDUP(data.dst, dst) < 0)
+ return -1;
+ data.type = type;
+ data.status = status;
+ make_nonnull_domain(&data.dom, dom);
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB_2,
+ (xdrproc_t)xdr_remote_domain_event_block_job_2_msg, &data);
+
+ return 0;
+}
+
+
+static int
+remoteRelayDomainEventTunable(virConnectPtr conn,
+ virDomainPtr dom,
+ virTypedParameterPtr params,
+ int nparams,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_callback_tunable_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain tunable event %s %d, callback %d, params %p %d",
+ dom->name, dom->id, callback->callbackID, params, nparams);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ data.callbackID = callback->callbackID;
+ make_nonnull_domain(&data.dom, dom);
+
+ if (virTypedParamsSerialize(params, nparams,
+ (virTypedParameterRemotePtr *) &data.params.params_val,
+ &data.params.params_len,
+ VIR_TYPED_PARAM_STRING_OKAY) < 0) {
+ VIR_FREE(data.dom.name);
+ return -1;
+ }
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_TUNABLE,
+ (xdrproc_t)xdr_remote_domain_event_callback_tunable_msg,
+ &data);
+
+ return 0;
+}
+
+
+static int
+remoteRelayDomainEventAgentLifecycle(virConnectPtr conn,
+ virDomainPtr dom,
+ int state,
+ int reason,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_callback_agent_lifecycle_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain agent lifecycle event %s %d, callback %d, "
+ " state %d, reason %d",
+ dom->name, dom->id, callback->callbackID, state, reason);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ data.callbackID = callback->callbackID;
+ make_nonnull_domain(&data.dom, dom);
+
+ data.state = state;
+ data.reason = reason;
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_AGENT_LIFECYCLE,
+ (xdrproc_t)xdr_remote_domain_event_callback_agent_lifecycle_msg,
+ &data);
+
+ return 0;
+}
+
+
+static int
+remoteRelayDomainEventDeviceAdded(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *devAlias,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_callback_device_added_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain device added event %s %d %s, callback %d",
+ dom->name, dom->id, devAlias, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+
+ if (VIR_STRDUP(data.devAlias, devAlias) < 0)
+ return -1;
+
+ make_nonnull_domain(&data.dom, dom);
+ data.callbackID = callback->callbackID;
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_ADDED,
+ (xdrproc_t)xdr_remote_domain_event_callback_device_added_msg,
+ &data);
+
+ return 0;
+}
+
+
+static int
+remoteRelayDomainEventMigrationIteration(virConnectPtr conn,
+ virDomainPtr dom,
+ int iteration,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_callback_migration_iteration_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain migration pass event %s %d, "
+ "callback %d, iteration %d",
+ dom->name, dom->id, callback->callbackID, iteration);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ data.callbackID = callback->callbackID;
+ make_nonnull_domain(&data.dom, dom);
+
+ data.iteration = iteration;
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_MIGRATION_ITERATION,
+ (xdrproc_t)xdr_remote_domain_event_callback_migration_iteration_msg,
+ &data);
+
+ return 0;
+}
+
+
+static int
+remoteRelayDomainEventJobCompleted(virConnectPtr conn,
+ virDomainPtr dom,
+ virTypedParameterPtr params,
+ int nparams,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_callback_job_completed_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain migration completed event %s %d, "
+ "callback %d, params %p %d",
+ dom->name, dom->id, callback->callbackID, params, nparams);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ data.callbackID = callback->callbackID;
+ make_nonnull_domain(&data.dom, dom);
+
+ if (virTypedParamsSerialize(params, nparams,
+ (virTypedParameterRemotePtr *) &data.params.params_val,
+ &data.params.params_len,
+ VIR_TYPED_PARAM_STRING_OKAY) < 0) {
+ VIR_FREE(data.dom.name);
+ return -1;
+ }
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_JOB_COMPLETED,
+ (xdrproc_t)xdr_remote_domain_event_callback_job_completed_msg,
+ &data);
+ return 0;
+}
+
+
+static int
+remoteRelayDomainEventDeviceRemovalFailed(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *devAlias,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_callback_device_removal_failed_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain device removal failed event %s %d %s, callback %d",
+ dom->name, dom->id, devAlias, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+
+ if (VIR_STRDUP(data.devAlias, devAlias) < 0)
+ return -1;
+
+ make_nonnull_domain(&data.dom, dom);
+ data.callbackID = callback->callbackID;
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVAL_FAILED,
+ (xdrproc_t)xdr_remote_domain_event_callback_device_removal_failed_msg,
+ &data);
+
+ return 0;
+}
+
+
+static int
+remoteRelayDomainEventMetadataChange(virConnectPtr conn,
+ virDomainPtr dom,
+ int type,
+ const char *nsuri,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_callback_metadata_change_msg data;
+ char **nsurip;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain metadata change %s %d %d %s, callback %d",
+ dom->name, dom->id, type, NULLSTR(nsuri), callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+
+ data.type = type;
+ if (nsuri) {
+ if (VIR_ALLOC(nsurip) < 0)
+ return -1;
+ if (VIR_STRDUP(*nsurip, nsuri) < 0) {
+ VIR_FREE(nsurip);
+ return -1;
+ }
+ data.nsuri = nsurip;
+ }
+
+ make_nonnull_domain(&data.dom, dom);
+ data.callbackID = callback->callbackID;
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_METADATA_CHANGE,
+ (xdrproc_t)xdr_remote_domain_event_callback_metadata_change_msg,
+ &data);
+
+ return 0;
+}
+
+
+static int
+remoteRelayDomainEventBlockThreshold(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *dev,
+ const char *path,
+ unsigned long long threshold,
+ unsigned long long excess,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_block_threshold_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain block threshold event %s %d %s %s %llu %llu, callback %d",
+ dom->name, dom->id, dev, NULLSTR(path), threshold, excess, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ data.callbackID = callback->callbackID;
+ if (VIR_STRDUP(data.dev, dev) < 0)
+ goto error;
+ if (path) {
+ if (VIR_ALLOC(data.path) < 0)
+ goto error;
+ if (VIR_STRDUP(*(data.path), path) < 0)
+ goto error;
+ }
+ data.threshold = threshold;
+ data.excess = excess;
+ make_nonnull_domain(&data.dom, dom);
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_BLOCK_THRESHOLD,
+ (xdrproc_t)xdr_remote_domain_event_block_threshold_msg, &data);
+
+ return 0;
+ error:
+ VIR_FREE(data.dev);
+ return -1;
+}
+
+
+static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventRTCChange),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventWatchdog),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventIOError),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventGraphics),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventIOErrorReason),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventControlError),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDiskChange),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventTrayChange),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMWakeup),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMSuspend),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBalloonChange),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMSuspendDisk),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceRemoved),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob2),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventTunable),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventAgentLifecycle),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceAdded),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMigrationIteration),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventJobCompleted),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceRemovalFailed),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMetadataChange),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockThreshold),
+};
+
+verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
+
+static int
+remoteRelayNetworkEventLifecycle(virConnectPtr conn,
+ virNetworkPtr net,
+ int event,
+ int detail,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_network_event_lifecycle_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayNetworkEventCheckACL(callback->client, conn, net))
+ return -1;
+
+ VIR_DEBUG("Relaying network lifecycle event %d, detail %d, callback %d",
+ event, detail, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_network(&data.net, net);
+ data.callbackID = callback->callbackID;
+ data.event = event;
+ data.detail = detail;
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_NETWORK_EVENT_LIFECYCLE,
+ (xdrproc_t)xdr_remote_network_event_lifecycle_msg, &data);
+
+ return 0;
+}
+
+static virConnectNetworkEventGenericCallback networkEventCallbacks[] = {
+ VIR_NETWORK_EVENT_CALLBACK(remoteRelayNetworkEventLifecycle),
+};
+
+verify(ARRAY_CARDINALITY(networkEventCallbacks) == VIR_NETWORK_EVENT_ID_LAST);
+
+static int
+remoteRelayStoragePoolEventLifecycle(virConnectPtr conn,
+ virStoragePoolPtr pool,
+ int event,
+ int detail,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_storage_pool_event_lifecycle_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayStoragePoolEventCheckACL(callback->client, conn, pool))
+ return -1;
+
+ VIR_DEBUG("Relaying storage pool lifecycle event %d, detail %d, callback %d",
+ event, detail, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_storage_pool(&data.pool, pool);
+ data.callbackID = callback->callbackID;
+ data.event = event;
+ data.detail = detail;
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_STORAGE_POOL_EVENT_LIFECYCLE,
+ (xdrproc_t)xdr_remote_storage_pool_event_lifecycle_msg,
+ &data);
+
+ return 0;
+}
+
+static int
+remoteRelayStoragePoolEventRefresh(virConnectPtr conn,
+ virStoragePoolPtr pool,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_storage_pool_event_refresh_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayStoragePoolEventCheckACL(callback->client, conn, pool))
+ return -1;
+
+ VIR_DEBUG("Relaying storage pool refresh event callback %d",
+ callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_storage_pool(&data.pool, pool);
+ data.callbackID = callback->callbackID;
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_STORAGE_POOL_EVENT_REFRESH,
+ (xdrproc_t)xdr_remote_storage_pool_event_refresh_msg,
+ &data);
+
+ return 0;
+}
+
+static virConnectStoragePoolEventGenericCallback storageEventCallbacks[] = {
+ VIR_STORAGE_POOL_EVENT_CALLBACK(remoteRelayStoragePoolEventLifecycle),
+ VIR_STORAGE_POOL_EVENT_CALLBACK(remoteRelayStoragePoolEventRefresh),
+};
+
+verify(ARRAY_CARDINALITY(storageEventCallbacks) == VIR_STORAGE_POOL_EVENT_ID_LAST);
+
+static int
+remoteRelayNodeDeviceEventLifecycle(virConnectPtr conn,
+ virNodeDevicePtr dev,
+ int event,
+ int detail,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_node_device_event_lifecycle_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayNodeDeviceEventCheckACL(callback->client, conn, dev))
+ return -1;
+
+ VIR_DEBUG("Relaying node device lifecycle event %d, detail %d, callback %d",
+ event, detail, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_node_device(&data.dev, dev);
+ data.callbackID = callback->callbackID;
+ data.event = event;
+ data.detail = detail;
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_NODE_DEVICE_EVENT_LIFECYCLE,
+ (xdrproc_t)xdr_remote_node_device_event_lifecycle_msg,
+ &data);
+
+ return 0;
+}
+
+static int
+remoteRelayNodeDeviceEventUpdate(virConnectPtr conn,
+ virNodeDevicePtr dev,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_node_device_event_update_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayNodeDeviceEventCheckACL(callback->client, conn, dev))
+ return -1;
+
+ VIR_DEBUG("Relaying node device update event callback %d",
+ callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_node_device(&data.dev, dev);
+ data.callbackID = callback->callbackID;
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_NODE_DEVICE_EVENT_UPDATE,
+ (xdrproc_t)xdr_remote_node_device_event_update_msg,
+ &data);
+
+ return 0;
+}
+
+static virConnectNodeDeviceEventGenericCallback nodeDeviceEventCallbacks[] = {
+ VIR_NODE_DEVICE_EVENT_CALLBACK(remoteRelayNodeDeviceEventLifecycle),
+ VIR_NODE_DEVICE_EVENT_CALLBACK(remoteRelayNodeDeviceEventUpdate),
+};
+
+verify(ARRAY_CARDINALITY(nodeDeviceEventCallbacks) == VIR_NODE_DEVICE_EVENT_ID_LAST);
+
+static int
+remoteRelaySecretEventLifecycle(virConnectPtr conn,
+ virSecretPtr secret,
+ int event,
+ int detail,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_secret_event_lifecycle_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelaySecretEventCheckACL(callback->client, conn, secret))
+ return -1;
+
+ VIR_DEBUG("Relaying node secretice lifecycle event %d, detail %d, callback %d",
+ event, detail, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_secret(&data.secret, secret);
+ data.callbackID = callback->callbackID;
+ data.event = event;
+ data.detail = detail;
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_SECRET_EVENT_LIFECYCLE,
+ (xdrproc_t)xdr_remote_secret_event_lifecycle_msg,
+ &data);
+
+ return 0;
+}
+
+static int
+remoteRelaySecretEventValueChanged(virConnectPtr conn,
+ virSecretPtr secret,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_secret_event_value_changed_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelaySecretEventCheckACL(callback->client, conn, secret))
+ return -1;
+
+ VIR_DEBUG("Relaying node secret value changed callback %d",
+ callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_secret(&data.secret, secret);
+ data.callbackID = callback->callbackID;
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_SECRET_EVENT_VALUE_CHANGED,
+ (xdrproc_t)xdr_remote_secret_event_value_changed_msg,
+ &data);
+
+ return 0;
+}
+
+static virConnectSecretEventGenericCallback secretEventCallbacks[] = {
+ VIR_SECRET_EVENT_CALLBACK(remoteRelaySecretEventLifecycle),
+ VIR_SECRET_EVENT_CALLBACK(remoteRelaySecretEventValueChanged),
+};
+
+verify(ARRAY_CARDINALITY(secretEventCallbacks) == VIR_SECRET_EVENT_ID_LAST);
+
+static void
+remoteRelayDomainQemuMonitorEvent(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *event,
+ long long seconds,
+ unsigned int micros,
+ const char *details,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ qemu_domain_monitor_event_msg data;
+ char **details_p = NULL;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainQemuMonitorEventCheckACL(callback->client, conn,
+ dom))
+ return;
+
+ VIR_DEBUG("Relaying qemu monitor event %s %s, callback %d",
+ event, details, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ data.callbackID = callback->callbackID;
+ if (VIR_STRDUP(data.event, event) < 0)
+ goto error;
+ data.seconds = seconds;
+ data.micros = micros;
+ if (details &&
+ ((VIR_ALLOC(details_p) < 0) ||
+ VIR_STRDUP(*details_p, details) < 0))
+ goto error;
+ data.details = details_p;
+ make_nonnull_domain(&data.dom, dom);
+
+ remoteDispatchObjectEventSend(callback->client, qemuProgram,
+ QEMU_PROC_DOMAIN_MONITOR_EVENT,
+ (xdrproc_t)xdr_qemu_domain_monitor_event_msg,
+ &data);
+ return;
+
+ error:
+ VIR_FREE(data.event);
+ VIR_FREE(details_p);
+}
+
+static
+void remoteRelayConnectionClosedEvent(virConnectPtr conn ATTRIBUTE_UNUSED, int reason, void *opaque)
+{
+ virNetServerClientPtr client = opaque;
+
+ VIR_DEBUG("Relaying connection closed event, reason %d", reason);
+
+ remote_connect_event_connection_closed_msg msg = { reason };
+ remoteDispatchObjectEventSend(client, remoteProgram,
+ REMOTE_PROC_CONNECT_EVENT_CONNECTION_CLOSED,
+ (xdrproc_t)xdr_remote_connect_event_connection_closed_msg,
+ &msg);
+}
+
+#define DEREG_CB(conn, eventCallbacks, neventCallbacks, deregFcn, name) \
+ do { \
+ size_t i; \
+ for (i = 0; i < neventCallbacks; i++) { \
+ int callbackID = eventCallbacks[i]->callbackID; \
+ if (callbackID < 0) { \
+ VIR_WARN("unexpected incomplete %s callback %zu", name, i); \
+ continue; \
+ } \
+ VIR_DEBUG("Deregistering remote %s event relay %d", \
+ name, callbackID); \
+ eventCallbacks[i]->callbackID = -1; \
+ if (deregFcn(conn, callbackID) < 0) \
+ VIR_WARN("unexpected %s event deregister failure", name); \
+ } \
+ VIR_FREE(eventCallbacks); \
+ neventCallbacks = 0; \
+ } while (0);
+
+
+static void
+remoteClientFreePrivateCallbacks(struct daemonClientPrivate *priv)
+{
+ virIdentityPtr sysident = virIdentityGetSystem();
+ virIdentitySetCurrent(sysident);
+
+ DEREG_CB(priv->conn, priv->domainEventCallbacks,
+ priv->ndomainEventCallbacks,
+ virConnectDomainEventDeregisterAny, "domain");
+ DEREG_CB(priv->conn, priv->networkEventCallbacks,
+ priv->nnetworkEventCallbacks,
+ virConnectNetworkEventDeregisterAny, "network");
+ DEREG_CB(priv->conn, priv->storageEventCallbacks,
+ priv->nstorageEventCallbacks,
+ virConnectStoragePoolEventDeregisterAny, "storage");
+ DEREG_CB(priv->conn, priv->nodeDeviceEventCallbacks,
+ priv->nnodeDeviceEventCallbacks,
+ virConnectNodeDeviceEventDeregisterAny, "node device");
+ DEREG_CB(priv->conn, priv->secretEventCallbacks,
+ priv->nsecretEventCallbacks,
+ virConnectSecretEventDeregisterAny, "secret");
+ DEREG_CB(priv->conn, priv->qemuEventCallbacks,
+ priv->nqemuEventCallbacks,
+ virConnectDomainQemuMonitorEventDeregister, "qemu monitor");
+
+ if (priv->closeRegistered) {
+ if (virConnectUnregisterCloseCallback(priv->conn,
+ remoteRelayConnectionClosedEvent) < 0)
+ VIR_WARN("unexpected close callback event deregister failure");
+ }
+
+ virIdentitySetCurrent(NULL);
+ virObjectUnref(sysident);
+}
+#undef DEREG_CB
+
+
+/*
+ * You must hold lock for at least the client
+ * We don't free stuff here, merely disconnect the client's
+ * network socket & resources.
+ * We keep the libvirt connection open until any async
+ * jobs have finished, then clean it up elsewhere
+ */
+void remoteClientFree(void *data)
+{
+ struct daemonClientPrivate *priv = data;
+
+ if (priv->conn)
+ virConnectClose(priv->conn);
+
+ VIR_FREE(priv);
+}
+
+
+static void remoteClientCloseFunc(virNetServerClientPtr client)
+{
+ struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
+
+ daemonRemoveAllClientStreams(priv->streams);
+
+ /* Deregister event delivery callback */
+ if (priv->conn)
+ remoteClientFreePrivateCallbacks(priv);
+}
+
+
+void *remoteClientNew(virNetServerClientPtr client,
+ void *opaque ATTRIBUTE_UNUSED)
+{
+ struct daemonClientPrivate *priv;
+
+ if (VIR_ALLOC(priv) < 0)
+ return NULL;
+
+ if (virMutexInit(&priv->lock) < 0) {
+ VIR_FREE(priv);
+ virReportSystemError(errno, "%s", _("unable to init mutex"));
+ return NULL;
+ }
+
+ virNetServerClientSetCloseHook(client, remoteClientCloseFunc);
+ return priv;
+}
+
+/*----- Functions. -----*/
+
+static int
+remoteDispatchConnectOpen(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ struct remote_connect_open_args *args)
+{
+ const char *name;
+ unsigned int flags;
+ struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
+ int rv = -1;
+
+ VIR_DEBUG("priv=%p conn=%p", priv, priv->conn);
+ virMutexLock(&priv->lock);
+ /* Already opened? */
+ if (priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection already open"));
+ goto cleanup;
+ }
+
+ name = args->name ? *args->name : NULL;
+
+ /* If this connection arrived on a readonly socket, force
+ * the connection to be readonly.
+ */
+ flags = args->flags;
+ if (virNetServerClientGetReadonly(client))
+ flags |= VIR_CONNECT_RO;
+
+ priv->conn =
+ flags & VIR_CONNECT_RO
+ ? virConnectOpenReadOnly(name)
+ : virConnectOpen(name);
+
+ if (priv->conn == NULL)
+ goto cleanup;
+
+ /* force update the @readonly attribute which was inherited from the
+ * virNetServerService object - this is important for sockets that are RW
+ * by default, but do accept RO flags, e.g. TCP
+ */
+ virNetServerClientSetReadonly(client, (flags & VIR_CONNECT_RO));
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+
+static int
+remoteDispatchConnectClose(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED)
+{
+ virNetServerClientDelayedClose(client);
+ return 0;
+}
+
+
+static int
+remoteDispatchDomainGetSchedulerType(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_scheduler_type_args *args,
+ remote_domain_get_scheduler_type_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ char *type;
+ int nparams;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (!(type = virDomainGetSchedulerType(dom, &nparams)))
+ goto cleanup;
+
+ ret->type = type;
+ ret->nparams = nparams;
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetSchedulerParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_scheduler_parameters_args *args,
+ remote_domain_get_scheduler_parameters_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ virTypedParameterPtr params = NULL;
+ int nparams = 0;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (args->nparams > REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
+ goto cleanup;
+ }
+ if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
+ goto cleanup;
+ nparams = args->nparams;
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (virDomainGetSchedulerParameters(dom, params, &nparams) < 0)
+ goto cleanup;
+
+ if (virTypedParamsSerialize(params, nparams,
+ (virTypedParameterRemotePtr *) &ret->params.params_val,
+ &ret->params.params_len,
+ 0) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virTypedParamsFree(params, nparams);
+ virObjectUnref(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetSchedulerParametersFlags(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_scheduler_parameters_flags_args *args,
+ remote_domain_get_scheduler_parameters_flags_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ virTypedParameterPtr params = NULL;
+ int nparams = 0;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (args->nparams > REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
+ goto cleanup;
+ }
+ if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
+ goto cleanup;
+ nparams = args->nparams;
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (virDomainGetSchedulerParametersFlags(dom, params, &nparams,
+ args->flags) < 0)
+ goto cleanup;
+
+ if (virTypedParamsSerialize(params, nparams,
+ (virTypedParameterRemotePtr *) &ret->params.params_val,
+ &ret->params.params_len,
+ args->flags) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virTypedParamsFree(params, nparams);
+ virObjectUnref(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_memory_stats_args *args,
+ remote_domain_memory_stats_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ virDomainMemoryStatPtr stats = NULL;
+ int nr_stats;
+ size_t i;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (args->maxStats > REMOTE_DOMAIN_MEMORY_STATS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("maxStats > REMOTE_DOMAIN_MEMORY_STATS_MAX"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ /* Allocate stats array for making dispatch call */
+ if (VIR_ALLOC_N(stats, args->maxStats) < 0)
+ goto cleanup;
+
+ nr_stats = virDomainMemoryStats(dom, stats, args->maxStats, args->flags);
+ if (nr_stats < 0)
+ goto cleanup;
+
+ /* Allocate return buffer */
+ if (VIR_ALLOC_N(ret->stats.stats_val, args->maxStats) < 0)
+ goto cleanup;
+
+ /* Copy the stats into the xdr return structure */
+ for (i = 0; i < nr_stats; i++) {
+ ret->stats.stats_val[i].tag = stats[i].tag;
+ ret->stats.stats_val[i].val = stats[i].val;
+ }
+ ret->stats.stats_len = nr_stats;
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ VIR_FREE(stats);
+ return rv;
+}
+
+static int
+remoteDispatchDomainBlockPeek(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_block_peek_args *args,
+ remote_domain_block_peek_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ char *path;
+ unsigned long long offset;
+ size_t size;
+ unsigned int flags;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+ path = args->path;
+ offset = args->offset;
+ size = args->size;
+ flags = args->flags;
+
+ if (size > REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("size > maximum buffer size"));
+ goto cleanup;
+ }
+
+ ret->buffer.buffer_len = size;
+ if (VIR_ALLOC_N(ret->buffer.buffer_val, size) < 0)
+ goto cleanup;
+
+ if (virDomainBlockPeek(dom, path, offset, size,
+ ret->buffer.buffer_val, flags) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0) {
+ virNetMessageSaveError(rerr);
+ VIR_FREE(ret->buffer.buffer_val);
+ }
+ virObjectUnref(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainBlockStatsFlags(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_block_stats_flags_args *args,
+ remote_domain_block_stats_flags_ret *ret)
+{
+ virTypedParameterPtr params = NULL;
+ virDomainPtr dom = NULL;
+ const char *path = args->path;
+ int nparams = 0;
+ unsigned int flags;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+ flags = args->flags;
+
+ if (args->nparams > REMOTE_DOMAIN_BLOCK_STATS_PARAMETERS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
+ goto cleanup;
+ }
+ if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
+ goto cleanup;
+ nparams = args->nparams;
+
+ if (virDomainBlockStatsFlags(dom, path, params, &nparams, flags) < 0)
+ goto cleanup;
+
+ /* In this case, we need to send back the number of parameters
+ * supported
+ */
+ if (args->nparams == 0) {
+ ret->nparams = nparams;
+ goto success;
+ }
+
+ /* Serialize the block stats. */
+ if (virTypedParamsSerialize(params, nparams,
+ (virTypedParameterRemotePtr *) &ret->params.params_val,
+ &ret->params.params_len,
+ args->flags) < 0)
+ goto cleanup;
+
+ success:
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virTypedParamsFree(params, nparams);
+ virObjectUnref(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainMemoryPeek(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_memory_peek_args *args,
+ remote_domain_memory_peek_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ unsigned long long offset;
+ size_t size;
+ unsigned int flags;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+ offset = args->offset;
+ size = args->size;
+ flags = args->flags;
+
+ if (size > REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("size > maximum buffer size"));
+ goto cleanup;
+ }
+
+ ret->buffer.buffer_len = size;
+ if (VIR_ALLOC_N(ret->buffer.buffer_val, size) < 0)
+ goto cleanup;
+
+ if (virDomainMemoryPeek(dom, offset, size,
+ ret->buffer.buffer_val, flags) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0) {
+ virNetMessageSaveError(rerr);
+ VIR_FREE(ret->buffer.buffer_val);
+ }
+ virObjectUnref(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetSecurityLabel(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_security_label_args *args,
+ remote_domain_get_security_label_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ virSecurityLabelPtr seclabel = NULL;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (VIR_ALLOC(seclabel) < 0)
+ goto cleanup;
+
+ if (virDomainGetSecurityLabel(dom, seclabel) < 0)
+ goto cleanup;
+
+ ret->label.label_len = strlen(seclabel->label) + 1;
+ if (VIR_ALLOC_N(ret->label.label_val, ret->label.label_len) < 0)
+ goto cleanup;
+ strcpy(ret->label.label_val, seclabel->label);
+ ret->enforcing = seclabel->enforcing;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ VIR_FREE(seclabel);
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetSecurityLabelList(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_security_label_list_args *args,
+ remote_domain_get_security_label_list_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ virSecurityLabelPtr seclabels = NULL;
+ int len, rv = -1;
+ size_t i;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if ((len = virDomainGetSecurityLabelList(dom, &seclabels)) < 0) {
+ ret->ret = len;
+ ret->labels.labels_len = 0;
+ ret->labels.labels_val = NULL;
+ goto done;
+ }
+
+ if (VIR_ALLOC_N(ret->labels.labels_val, len) < 0)
+ goto cleanup;
+
+ for (i = 0; i < len; i++) {
+ size_t label_len = strlen(seclabels[i].label) + 1;
+ remote_domain_get_security_label_ret *cur = &ret->labels.labels_val[i];
+ if (VIR_ALLOC_N(cur->label.label_val, label_len) < 0)
+ goto cleanup;
+ if (virStrcpy(cur->label.label_val, seclabels[i].label, label_len) == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to copy security label"));
+ goto cleanup;
+ }
+ cur->label.label_len = label_len;
+ cur->enforcing = seclabels[i].enforcing;
+ }
+ ret->labels.labels_len = ret->ret = len;
+
+ done:
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ VIR_FREE(seclabels);
+ return rv;
+}
+
+static int
+remoteDispatchNodeGetSecurityModel(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_node_get_security_model_ret *ret)
+{
+ virSecurityModel secmodel;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ memset(&secmodel, 0, sizeof(secmodel));
+ if (virNodeGetSecurityModel(priv->conn, &secmodel) < 0)
+ goto cleanup;
+
+ ret->model.model_len = strlen(secmodel.model) + 1;
+ if (VIR_ALLOC_N(ret->model.model_val, ret->model.model_len) < 0)
+ goto cleanup;
+ strcpy(ret->model.model_val, secmodel.model);
+
+ ret->doi.doi_len = strlen(secmodel.doi) + 1;
+ if (VIR_ALLOC_N(ret->doi.doi_val, ret->doi.doi_len) < 0)
+ goto cleanup;
+ strcpy(ret->doi.doi_val, secmodel.doi);
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetVcpuPinInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_vcpu_pin_info_args *args,
+ remote_domain_get_vcpu_pin_info_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ unsigned char *cpumaps = NULL;
+ int num;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (args->ncpumaps > REMOTE_VCPUINFO_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("ncpumaps > REMOTE_VCPUINFO_MAX"));
+ goto cleanup;
+ }
+
+ if (INT_MULTIPLY_OVERFLOW(args->ncpumaps, args->maplen) ||
+ args->ncpumaps * args->maplen > REMOTE_CPUMAPS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maxinfo * maplen > REMOTE_CPUMAPS_MAX"));
+ goto cleanup;
+ }
+
+ /* Allocate buffers to take the results. */
+ if (args->maplen > 0 &&
+ VIR_ALLOC_N(cpumaps, args->ncpumaps * args->maplen) < 0)
+ goto cleanup;
+
+ if ((num = virDomainGetVcpuPinInfo(dom,
+ args->ncpumaps,
+ cpumaps,
+ args->maplen,
+ args->flags)) < 0)
+ goto cleanup;
+
+ ret->num = num;
+ /* Don't need to allocate/copy the cpumaps if we make the reasonable
+ * assumption that unsigned char and char are the same size.
+ * Note that remoteDispatchClientRequest will free.
+ */
+ ret->cpumaps.cpumaps_len = args->ncpumaps * args->maplen;
+ ret->cpumaps.cpumaps_val = (char *) cpumaps;
+ cpumaps = NULL;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ VIR_FREE(cpumaps);
+ virObjectUnref(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainPinEmulator(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_pin_emulator_args *args)
+{
+ int rv = -1;
+ virDomainPtr dom = NULL;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (virDomainPinEmulator(dom,
+ (unsigned char *) args->cpumap.cpumap_val,
+ args->cpumap.cpumap_len,
+ args->flags) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ return rv;
+}
+
+
+static int
+remoteDispatchDomainGetEmulatorPinInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_emulator_pin_info_args *args,
+ remote_domain_get_emulator_pin_info_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ unsigned char *cpumaps = NULL;
+ int r;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ /* Allocate buffers to take the results */
+ if (args->maplen > 0 &&
+ VIR_ALLOC_N(cpumaps, args->maplen) < 0)
+ goto cleanup;
+
+ if ((r = virDomainGetEmulatorPinInfo(dom,
+ cpumaps,
+ args->maplen,
+ args->flags)) < 0)
+ goto cleanup;
+
+ ret->ret = r;
+ ret->cpumaps.cpumaps_len = args->maplen;
+ ret->cpumaps.cpumaps_val = (char *) cpumaps;
+ cpumaps = NULL;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ VIR_FREE(cpumaps);
+ virObjectUnref(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetVcpus(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_vcpus_args *args,
+ remote_domain_get_vcpus_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ virVcpuInfoPtr info = NULL;
+ unsigned char *cpumaps = NULL;
+ int info_len;
+ size_t i;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (args->maxinfo > REMOTE_VCPUINFO_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maxinfo > REMOTE_VCPUINFO_MAX"));
+ goto cleanup;
+ }
+
+ if (INT_MULTIPLY_OVERFLOW(args->maxinfo, args->maplen) ||
+ args->maxinfo * args->maplen > REMOTE_CPUMAPS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maxinfo * maplen > REMOTE_CPUMAPS_MAX"));
+ goto cleanup;
+ }
+
+ /* Allocate buffers to take the results. */
+ if (VIR_ALLOC_N(info, args->maxinfo) < 0)
+ goto cleanup;
+ if (args->maplen > 0 &&
+ VIR_ALLOC_N(cpumaps, args->maxinfo * args->maplen) < 0)
+ goto cleanup;
+
+ if ((info_len = virDomainGetVcpus(dom,
+ info, args->maxinfo,
+ cpumaps, args->maplen)) < 0)
+ goto cleanup;
+
+ /* Allocate the return buffer for info. */
+ ret->info.info_len = info_len;
+ if (VIR_ALLOC_N(ret->info.info_val, info_len) < 0)
+ goto cleanup;
+
+ for (i = 0; i < info_len; ++i) {
+ ret->info.info_val[i].number = info[i].number;
+ ret->info.info_val[i].state = info[i].state;
+ ret->info.info_val[i].cpu_time = info[i].cpuTime;
+ ret->info.info_val[i].cpu = info[i].cpu;
+ }
+
+ /* Don't need to allocate/copy the cpumaps if we make the reasonable
+ * assumption that unsigned char and char are the same size.
+ * Note that remoteDispatchClientRequest will free.
+ */
+ ret->cpumaps.cpumaps_len = args->maxinfo * args->maplen;
+ ret->cpumaps.cpumaps_val = (char *) cpumaps;
+ cpumaps = NULL;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0) {
+ virNetMessageSaveError(rerr);
+ VIR_FREE(ret->info.info_val);
+ }
+ VIR_FREE(cpumaps);
+ VIR_FREE(info);
+ virObjectUnref(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetIOThreadInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_iothread_info_args *args,
+ remote_domain_get_iothread_info_ret *ret)
+{
+ int rv = -1;
+ size_t i;
+ struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
+ virDomainIOThreadInfoPtr *info = NULL;
+ virDomainPtr dom = NULL;
+ remote_domain_iothread_info *dst;
+ int ninfo = 0;
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if ((ninfo = virDomainGetIOThreadInfo(dom, &info, args->flags)) < 0)
+ goto cleanup;
+
+ if (ninfo > REMOTE_IOTHREAD_INFO_MAX) {
+ virReportError(VIR_ERR_RPC,
+ _("Too many IOThreads in info: %d for limit %d"),
+ ninfo, REMOTE_IOTHREAD_INFO_MAX);
+ goto cleanup;
+ }
+
+ if (ninfo) {
+ if (VIR_ALLOC_N(ret->info.info_val, ninfo) < 0)
+ goto cleanup;
+
+ ret->info.info_len = ninfo;
+
+ for (i = 0; i < ninfo; i++) {
+ dst = &ret->info.info_val[i];
+ dst->iothread_id = info[i]->iothread_id;
+
+ /* No need to allocate/copy the cpumap if we make the reasonable
+ * assumption that unsigned char and char are the same size.
+ */
+ dst->cpumap.cpumap_len = info[i]->cpumaplen;
+ dst->cpumap.cpumap_val = (char *)info[i]->cpumap;
+ info[i]->cpumap = NULL;
+ }
+ } else {
+ ret->info.info_len = 0;
+ ret->info.info_val = NULL;
+ }
+
+ ret->ret = ninfo;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ if (ninfo >= 0)
+ for (i = 0; i < ninfo; i++)
+ virDomainIOThreadInfoFree(info[i]);
+ VIR_FREE(info);
+
+ return rv;
+}
+
+static int
+remoteDispatchDomainMigratePrepare(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_migrate_prepare_args *args,
+ remote_domain_migrate_prepare_ret *ret)
+{
+ char *cookie = NULL;
+ int cookielen = 0;
+ char *uri_in;
+ char **uri_out;
+ char *dname;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ uri_in = args->uri_in == NULL ? NULL : *args->uri_in;
+ dname = args->dname == NULL ? NULL : *args->dname;
+
+ /* Wacky world of XDR ... */
+ if (VIR_ALLOC(uri_out) < 0)
+ goto cleanup;
+
+ if (virDomainMigratePrepare(priv->conn, &cookie, &cookielen,
+ uri_in, uri_out,
+ args->flags, dname, args->resource) < 0)
+ goto cleanup;
+
+ /* remoteDispatchClientRequest will free cookie, uri_out and
+ * the string if there is one.
+ */
+ ret->cookie.cookie_len = cookielen;
+ ret->cookie.cookie_val = cookie;
+ if (*uri_out == NULL) {
+ ret->uri_out = NULL;
+ } else {
+ ret->uri_out = uri_out;
+ uri_out = NULL;
+ }
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ VIR_FREE(uri_out);
+ return rv;
+}
+
+static int
+remoteDispatchDomainMigratePrepare2(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_migrate_prepare2_args *args,
+ remote_domain_migrate_prepare2_ret *ret)
+{
+ char *cookie = NULL;
+ int cookielen = 0;
+ char *uri_in;
+ char **uri_out;
+ char *dname;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ uri_in = args->uri_in == NULL ? NULL : *args->uri_in;
+ dname = args->dname == NULL ? NULL : *args->dname;
+
+ /* Wacky world of XDR ... */
+ if (VIR_ALLOC(uri_out) < 0)
+ goto cleanup;
+
+ if (virDomainMigratePrepare2(priv->conn, &cookie, &cookielen,
+ uri_in, uri_out,
+ args->flags, dname, args->resource,
+ args->dom_xml) < 0)
+ goto cleanup;
+
+ /* remoteDispatchClientRequest will free cookie, uri_out and
+ * the string if there is one.
+ */
+ ret->cookie.cookie_len = cookielen;
+ ret->cookie.cookie_val = cookie;
+ ret->uri_out = *uri_out == NULL ? NULL : uri_out;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0) {
+ virNetMessageSaveError(rerr);
+ VIR_FREE(uri_out);
+ }
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_memory_parameters_args *args,
+ remote_domain_get_memory_parameters_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ virTypedParameterPtr params = NULL;
+ int nparams = 0;
+ unsigned int flags;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ flags = args->flags;
+
+ if (args->nparams > REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
+ goto cleanup;
+ }
+ if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
+ goto cleanup;
+ nparams = args->nparams;
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (virDomainGetMemoryParameters(dom, params, &nparams, flags) < 0)
+ goto cleanup;
+
+ /* In this case, we need to send back the number of parameters
+ * supported
+ */
+ if (args->nparams == 0) {
+ ret->nparams = nparams;
+ goto success;
+ }
+
+ if (virTypedParamsSerialize(params, nparams,
+ (virTypedParameterRemotePtr *) &ret->params.params_val,
+ &ret->params.params_len,
+ args->flags) < 0)
+ goto cleanup;
+
+ success:
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virTypedParamsFree(params, nparams);
+ virObjectUnref(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetNumaParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_numa_parameters_args *args,
+ remote_domain_get_numa_parameters_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ virTypedParameterPtr params = NULL;
+ int nparams = 0;
+ unsigned int flags;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ flags = args->flags;
+
+ if (args->nparams > REMOTE_DOMAIN_NUMA_PARAMETERS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
+ goto cleanup;
+ }
+ if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
+ goto cleanup;
+ nparams = args->nparams;
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (virDomainGetNumaParameters(dom, params, &nparams, flags) < 0)
+ goto cleanup;
+
+ /* In this case, we need to send back the number of parameters
+ * supported
+ */
+ if (args->nparams == 0) {
+ ret->nparams = nparams;
+ goto success;
+ }
+
+ if (virTypedParamsSerialize(params, nparams,
+ (virTypedParameterRemotePtr *) &ret->params.params_val,
+ &ret->params.params_len,
+ flags) < 0)
+ goto cleanup;
+
+ success:
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virTypedParamsFree(params, nparams);
+ virObjectUnref(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetBlkioParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_blkio_parameters_args *args,
+ remote_domain_get_blkio_parameters_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ virTypedParameterPtr params = NULL;
+ int nparams = 0;
+ unsigned int flags;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ flags = args->flags;
+
+ if (args->nparams > REMOTE_DOMAIN_BLKIO_PARAMETERS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
+ goto cleanup;
+ }
+ if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
+ goto cleanup;
+ nparams = args->nparams;
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (virDomainGetBlkioParameters(dom, params, &nparams, flags) < 0)
+ goto cleanup;
+
+ /* In this case, we need to send back the number of parameters
+ * supported
+ */
+ if (args->nparams == 0) {
+ ret->nparams = nparams;
+ goto success;
+ }
+
+ if (virTypedParamsSerialize(params, nparams,
+ (virTypedParameterRemotePtr *) &ret->params.params_val,
+ &ret->params.params_len,
+ args->flags) < 0)
+ goto cleanup;
+
+ success:
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virTypedParamsFree(params, nparams);
+ virObjectUnref(dom);
+ return rv;
+}
+
+static int
+remoteDispatchNodeGetCPUStats(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_node_get_cpu_stats_args *args,
+ remote_node_get_cpu_stats_ret *ret)
+{
+ virNodeCPUStatsPtr params = NULL;
+ size_t i;
+ int cpuNum = args->cpuNum;
+ int nparams = 0;
+ unsigned int flags;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ flags = args->flags;
+
+ if (args->nparams > REMOTE_NODE_CPU_STATS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
+ goto cleanup;
+ }
+ if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
+ goto cleanup;
+ nparams = args->nparams;
+
+ if (virNodeGetCPUStats(priv->conn, cpuNum, params, &nparams, flags) < 0)
+ goto cleanup;
+
+ /* In this case, we need to send back the number of stats
+ * supported
+ */
+ if (args->nparams == 0) {
+ ret->nparams = nparams;
+ goto success;
+ }
+
+ /* Serialise the memory parameters. */
+ ret->params.params_len = nparams;
+ if (VIR_ALLOC_N(ret->params.params_val, nparams) < 0)
+ goto cleanup;
+
+ for (i = 0; i < nparams; ++i) {
+ /* remoteDispatchClientRequest will free this: */
+ if (VIR_STRDUP(ret->params.params_val[i].field, params[i].field) < 0)
+ goto cleanup;
+
+ ret->params.params_val[i].value = params[i].value;
+ }
+
+ success:
+ rv = 0;
+
+ cleanup:
+ if (rv < 0) {
+ virNetMessageSaveError(rerr);
+ if (ret->params.params_val) {
+ for (i = 0; i < nparams; i++)
+ VIR_FREE(ret->params.params_val[i].field);
+ VIR_FREE(ret->params.params_val);
+ }
+ }
+ VIR_FREE(params);
+ return rv;
+}
+
+static int
+remoteDispatchNodeGetMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_node_get_memory_stats_args *args,
+ remote_node_get_memory_stats_ret *ret)
+{
+ virNodeMemoryStatsPtr params = NULL;
+ size_t i;
+ int cellNum = args->cellNum;
+ int nparams = 0;
+ unsigned int flags;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ flags = args->flags;
+
+ if (args->nparams > REMOTE_NODE_MEMORY_STATS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
+ goto cleanup;
+ }
+ if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
+ goto cleanup;
+ nparams = args->nparams;
+
+ if (virNodeGetMemoryStats(priv->conn, cellNum, params, &nparams, flags) < 0)
+ goto cleanup;
+
+ /* In this case, we need to send back the number of parameters
+ * supported
+ */
+ if (args->nparams == 0) {
+ ret->nparams = nparams;
+ goto success;
+ }
+
+ /* Serialise the memory parameters. */
+ ret->params.params_len = nparams;
+ if (VIR_ALLOC_N(ret->params.params_val, nparams) < 0)
+ goto cleanup;
+
+ for (i = 0; i < nparams; ++i) {
+ /* remoteDispatchClientRequest will free this: */
+ if (VIR_STRDUP(ret->params.params_val[i].field, params[i].field) < 0)
+ goto cleanup;
+
+ ret->params.params_val[i].value = params[i].value;
+ }
+
+ success:
+ rv = 0;
+
+ cleanup:
+ if (rv < 0) {
+ virNetMessageSaveError(rerr);
+ if (ret->params.params_val) {
+ for (i = 0; i < nparams; i++)
+ VIR_FREE(ret->params.params_val[i].field);
+ VIR_FREE(ret->params.params_val);
+ }
+ }
+ VIR_FREE(params);
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetPerfEvents(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_perf_events_args *args,
+ remote_domain_get_perf_events_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ virTypedParameterPtr params = NULL;
+ int nparams = 0;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (virDomainGetPerfEvents(dom, ¶ms, &nparams, args->flags) < 0)
+ goto cleanup;
+
+ if (nparams > REMOTE_DOMAIN_PERF_EVENTS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
+ goto cleanup;
+ }
+
+ if (virTypedParamsSerialize(params, nparams,
+ (virTypedParameterRemotePtr *) &ret->params.params_val,
+ &ret->params.params_len,
+ 0) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virTypedParamsFree(params, nparams);
+ virObjectUnref(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetBlockJobInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_block_job_info_args *args,
+ remote_domain_get_block_job_info_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ virDomainBlockJobInfo tmp;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ rv = virDomainGetBlockJobInfo(dom, args->path, &tmp, args->flags);
+ if (rv <= 0)
+ goto cleanup;
+
+ ret->type = tmp.type;
+ ret->bandwidth = tmp.bandwidth;
+ ret->cur = tmp.cur;
+ ret->end = tmp.end;
+ ret->found = 1;
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetBlockIoTune(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_block_io_tune_args *args,
+ remote_domain_get_block_io_tune_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ int rv = -1;
+ virTypedParameterPtr params = NULL;
+ int nparams = 0;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (args->nparams > REMOTE_DOMAIN_BLOCK_IO_TUNE_PARAMETERS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
+ goto cleanup;
+ }
+
+ if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
+ goto cleanup;
+ nparams = args->nparams;
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (virDomainGetBlockIoTune(dom, args->disk ? *args->disk : NULL,
+ params, &nparams, args->flags) < 0)
+ goto cleanup;
+
+ /* In this case, we need to send back the number of parameters
+ * supported
+ */
+ if (args->nparams == 0) {
+ ret->nparams = nparams;
+ goto success;
+ }
+
+ /* Serialize the block I/O tuning parameters. */
+ if (virTypedParamsSerialize(params, nparams,
+ (virTypedParameterRemotePtr *) &ret->params.params_val,
+ &ret->params.params_len,
+ args->flags) < 0)
+ goto cleanup;
+
+ success:
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virTypedParamsFree(params, nparams);
+ virObjectUnref(dom);
+ return rv;
+}
+
+/*-------------------------------------------------------------*/
+
+static int
+remoteDispatchAuthList(virNetServerPtr server,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_auth_list_ret *ret)
+{
+ int rv = -1;
+ int auth = virNetServerClientGetAuth(client);
+ uid_t callerUid;
+ gid_t callerGid;
+ pid_t callerPid;
+ unsigned long long timestamp;
+
+ /* If the client is root then we want to bypass the
+ * policykit auth to avoid root being denied if
+ * some piece of polkit isn't present/running
+ */
+ if (auth == VIR_NET_SERVER_SERVICE_AUTH_POLKIT) {
+ if (virNetServerClientGetUNIXIdentity(client, &callerUid, &callerGid,
+ &callerPid, ×tamp) < 0) {
+ /* Don't do anything on error - it'll be validated at next
+ * phase of auth anyway */
+ virResetLastError();
+ } else if (callerUid == 0) {
+ char *ident;
+ if (virAsprintf(&ident, "pid:%lld,uid:%d",
+ (long long) callerPid, (int) callerUid) < 0)
+ goto cleanup;
+ VIR_INFO("Bypass polkit auth for privileged client %s", ident);
+ virNetServerSetClientAuthenticated(server, client);
+ auth = VIR_NET_SERVER_SERVICE_AUTH_NONE;
+ VIR_FREE(ident);
+ }
+ }
+
+ ret->types.types_len = 1;
+ if (VIR_ALLOC_N(ret->types.types_val, ret->types.types_len) < 0)
+ goto cleanup;
+
+ switch ((virNetServerServiceAuthMethods) auth) {
+ case VIR_NET_SERVER_SERVICE_AUTH_NONE:
+ ret->types.types_val[0] = REMOTE_AUTH_NONE;
+ break;
+ case VIR_NET_SERVER_SERVICE_AUTH_POLKIT:
+ ret->types.types_val[0] = REMOTE_AUTH_POLKIT;
+ break;
+ case VIR_NET_SERVER_SERVICE_AUTH_SASL:
+ ret->types.types_val[0] = REMOTE_AUTH_SASL;
+ break;
+ }
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ return rv;
+}
+
+
+#ifdef WITH_SASL
+/*
+ * Initializes the SASL session in prepare for authentication
+ * and gives the client a list of allowed mechanisms to choose
+ */
+static int
+remoteDispatchAuthSaslInit(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_auth_sasl_init_ret *ret)
+{
+ virNetSASLSessionPtr sasl = NULL;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ virMutexLock(&priv->lock);
+
+ VIR_DEBUG("Initialize SASL auth %d", virNetServerClientGetFD(client));
+ if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL ||
+ priv->sasl != NULL) {
+ VIR_ERROR(_("client tried invalid SASL init request"));
+ goto authfail;
+ }
+
+ sasl = virNetSASLSessionNewServer(saslCtxt,
+ "libvirt",
+ virNetServerClientLocalAddrStringSASL(client),
+ virNetServerClientRemoteAddrStringSASL(client));
+ if (!sasl)
+ goto authfail;
+
+# if WITH_GNUTLS
+ /* Inform SASL that we've got an external SSF layer from TLS */
+ if (virNetServerClientHasTLSSession(client)) {
+ int ssf;
+
+ if ((ssf = virNetServerClientGetTLSKeySize(client)) < 0)
+ goto authfail;
+
+ ssf *= 8; /* key size is bytes, sasl wants bits */
+
+ VIR_DEBUG("Setting external SSF %d", ssf);
+ if (virNetSASLSessionExtKeySize(sasl, ssf) < 0)
+ goto authfail;
+ }
+# endif
+
+ if (virNetServerClientIsSecure(client))
+ /* If we've got TLS or UNIX domain sock, we don't care about SSF */
+ virNetSASLSessionSecProps(sasl, 0, 0, true);
+ else
+ /* Plain TCP, better get an SSF layer */
+ virNetSASLSessionSecProps(sasl,
+ 56, /* Good enough to require kerberos */
+ 100000, /* Arbitrary big number */
+ false); /* No anonymous */
+
+ if (!(ret->mechlist = virNetSASLSessionListMechanisms(sasl)))
+ goto authfail;
+ VIR_DEBUG("Available mechanisms for client: '%s'", ret->mechlist);
+
+ priv->sasl = sasl;
+ virMutexUnlock(&priv->lock);
+ return 0;
+
+ authfail:
+ virResetLastError();
+ virReportError(VIR_ERR_AUTH_FAILED, "%s",
+ _("authentication failed"));
+ virNetMessageSaveError(rerr);
+ PROBE(RPC_SERVER_CLIENT_AUTH_FAIL,
+ "client=%p auth=%d",
+ client, REMOTE_AUTH_SASL);
+ virObjectUnref(sasl);
+ virMutexUnlock(&priv->lock);
+ return -1;
+}
+
+/*
+ * Returns 0 if ok, -1 on error, -2 if rejected
+ */
+static int
+remoteSASLFinish(virNetServerPtr server,
+ virNetServerClientPtr client)
+{
+ virIdentityPtr clnt_identity = NULL;
+ const char *identity;
+ struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
+ int ssf;
+
+ /* TLS or UNIX domain sockets trivially OK */
+ if (!virNetServerClientIsSecure(client)) {
+ if ((ssf = virNetSASLSessionGetKeySize(priv->sasl)) < 0)
+ goto error;
+
+ VIR_DEBUG("negotiated an SSF of %d", ssf);
+ if (ssf < 56) { /* 56 is good for Kerberos */
+ VIR_ERROR(_("negotiated SSF %d was not strong enough"), ssf);
+ return -2;
+ }
+ }
+
+ if (!(identity = virNetSASLSessionGetIdentity(priv->sasl)))
+ return -2;
+
+ if (!virNetSASLContextCheckIdentity(saslCtxt, identity))
+ return -2;
+
+ if (!(clnt_identity = virNetServerClientGetIdentity(client)))
+ goto error;
+
+ virNetServerSetClientAuthenticated(server, client);
+ virNetServerClientSetSASLSession(client, priv->sasl);
+ virIdentitySetSASLUserName(clnt_identity, identity);
+
+ VIR_DEBUG("Authentication successful %d", virNetServerClientGetFD(client));
+
+ PROBE(RPC_SERVER_CLIENT_AUTH_ALLOW,
+ "client=%p auth=%d identity=%s",
+ client, REMOTE_AUTH_SASL, identity);
+
+ virObjectUnref(clnt_identity);
+ virObjectUnref(priv->sasl);
+ priv->sasl = NULL;
+
+ return 0;
+
+ error:
+ return -1;
+}
+
+/*
+ * This starts the SASL authentication negotiation.
+ */
+static int
+remoteDispatchAuthSaslStart(virNetServerPtr server,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_auth_sasl_start_args *args,
+ remote_auth_sasl_start_ret *ret)
+{
+ const char *serverout;
+ size_t serveroutlen;
+ int err;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+ const char *identity;
+
+ virMutexLock(&priv->lock);
+
+ VIR_DEBUG("Start SASL auth %d", virNetServerClientGetFD(client));
+ if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL ||
+ priv->sasl == NULL) {
+ VIR_ERROR(_("client tried invalid SASL start request"));
+ goto authfail;
+ }
+
+ VIR_DEBUG("Using SASL mechanism %s. Data %d bytes, nil: %d",
+ args->mech, args->data.data_len, args->nil);
+ err = virNetSASLSessionServerStart(priv->sasl,
+ args->mech,
+ /* NB, distinction of NULL vs "" is *critical* in SASL */
+ args->nil ? NULL : args->data.data_val,
+ args->data.data_len,
+ &serverout,
+ &serveroutlen);
+ if (err != VIR_NET_SASL_COMPLETE &&
+ err != VIR_NET_SASL_CONTINUE)
+ goto authfail;
+
+ if (serveroutlen > REMOTE_AUTH_SASL_DATA_MAX) {
+ VIR_ERROR(_("sasl start reply data too long %d"), (int)serveroutlen);
+ goto authfail;
+ }
+
+ /* NB, distinction of NULL vs "" is *critical* in SASL */
+ if (serverout) {
+ if (VIR_ALLOC_N(ret->data.data_val, serveroutlen) < 0)
+ goto authfail;
+ memcpy(ret->data.data_val, serverout, serveroutlen);
+ } else {
+ ret->data.data_val = NULL;
+ }
+ ret->nil = serverout ? 0 : 1;
+ ret->data.data_len = serveroutlen;
+
+ VIR_DEBUG("SASL return data %d bytes, nil; %d", ret->data.data_len, ret->nil);
+ if (err == VIR_NET_SASL_CONTINUE) {
+ ret->complete = 0;
+ } else {
+ /* Check username whitelist ACL */
+ if ((err = remoteSASLFinish(server, client)) < 0) {
+ if (err == -2)
+ goto authdeny;
+ else
+ goto authfail;
+ }
+
+ ret->complete = 1;
+ }
+
+ virMutexUnlock(&priv->lock);
+ return 0;
+
+ authfail:
+ PROBE(RPC_SERVER_CLIENT_AUTH_FAIL,
+ "client=%p auth=%d",
+ client, REMOTE_AUTH_SASL);
+ goto error;
+
+ authdeny:
+ identity = virNetSASLSessionGetIdentity(priv->sasl);
+ PROBE(RPC_SERVER_CLIENT_AUTH_DENY,
+ "client=%p auth=%d identity=%s",
+ client, REMOTE_AUTH_SASL, identity);
+ goto error;
+
+ error:
+ virObjectUnref(priv->sasl);
+ priv->sasl = NULL;
+ virResetLastError();
+ virReportError(VIR_ERR_AUTH_FAILED, "%s",
+ _("authentication failed"));
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return -1;
+}
+
+
+static int
+remoteDispatchAuthSaslStep(virNetServerPtr server,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_auth_sasl_step_args *args,
+ remote_auth_sasl_step_ret *ret)
+{
+ const char *serverout;
+ size_t serveroutlen;
+ int err;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+ const char *identity;
+
+ virMutexLock(&priv->lock);
+
+ VIR_DEBUG("Step SASL auth %d", virNetServerClientGetFD(client));
+ if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL ||
+ priv->sasl == NULL) {
+ VIR_ERROR(_("client tried invalid SASL start request"));
+ goto authfail;
+ }
+
+ VIR_DEBUG("Step using SASL Data %d bytes, nil: %d",
+ args->data.data_len, args->nil);
+ err = virNetSASLSessionServerStep(priv->sasl,
+ /* NB, distinction of NULL vs "" is *critical* in SASL */
+ args->nil ? NULL : args->data.data_val,
+ args->data.data_len,
+ &serverout,
+ &serveroutlen);
+ if (err != VIR_NET_SASL_COMPLETE &&
+ err != VIR_NET_SASL_CONTINUE)
+ goto authfail;
+
+ if (serveroutlen > REMOTE_AUTH_SASL_DATA_MAX) {
+ VIR_ERROR(_("sasl step reply data too long %d"),
+ (int)serveroutlen);
+ goto authfail;
+ }
+
+ /* NB, distinction of NULL vs "" is *critical* in SASL */
+ if (serverout) {
+ if (VIR_ALLOC_N(ret->data.data_val, serveroutlen) < 0)
+ goto authfail;
+ memcpy(ret->data.data_val, serverout, serveroutlen);
+ } else {
+ ret->data.data_val = NULL;
+ }
+ ret->nil = serverout ? 0 : 1;
+ ret->data.data_len = serveroutlen;
+
+ VIR_DEBUG("SASL return data %d bytes, nil; %d", ret->data.data_len, ret->nil);
+ if (err == VIR_NET_SASL_CONTINUE) {
+ ret->complete = 0;
+ } else {
+ /* Check username whitelist ACL */
+ if ((err = remoteSASLFinish(server, client)) < 0) {
+ if (err == -2)
+ goto authdeny;
+ else
+ goto authfail;
+ }
+
+ ret->complete = 1;
+ }
+
+ virMutexUnlock(&priv->lock);
+ return 0;
+
+ authfail:
+ PROBE(RPC_SERVER_CLIENT_AUTH_FAIL,
+ "client=%p auth=%d",
+ client, REMOTE_AUTH_SASL);
+ goto error;
+
+ authdeny:
+ identity = virNetSASLSessionGetIdentity(priv->sasl);
+ PROBE(RPC_SERVER_CLIENT_AUTH_DENY,
+ "client=%p auth=%d identity=%s",
+ client, REMOTE_AUTH_SASL, identity);
+ goto error;
+
+ error:
+ virObjectUnref(priv->sasl);
+ priv->sasl = NULL;
+ virResetLastError();
+ virReportError(VIR_ERR_AUTH_FAILED, "%s",
+ _("authentication failed"));
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return -1;
+}
+#else
+static int
+remoteDispatchAuthSaslInit(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_auth_sasl_init_ret *ret ATTRIBUTE_UNUSED)
+{
+ VIR_WARN("Client tried unsupported SASL auth");
+ virReportError(VIR_ERR_AUTH_FAILED, "%s",
+ _("authentication failed"));
+ virNetMessageSaveError(rerr);
+ return -1;
+}
+static int
+remoteDispatchAuthSaslStart(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_auth_sasl_start_args *args ATTRIBUTE_UNUSED,
+ remote_auth_sasl_start_ret *ret ATTRIBUTE_UNUSED)
+{
+ VIR_WARN("Client tried unsupported SASL auth");
+ virReportError(VIR_ERR_AUTH_FAILED, "%s",
+ _("authentication failed"));
+ virNetMessageSaveError(rerr);
+ return -1;
+}
+static int
+remoteDispatchAuthSaslStep(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_auth_sasl_step_args *args ATTRIBUTE_UNUSED,
+ remote_auth_sasl_step_ret *ret ATTRIBUTE_UNUSED)
+{
+ VIR_WARN("Client tried unsupported SASL auth");
+ virReportError(VIR_ERR_AUTH_FAILED, "%s",
+ _("authentication failed"));
+ virNetMessageSaveError(rerr);
+ return -1;
+}
+#endif
+
+
+
+static int
+remoteDispatchAuthPolkit(virNetServerPtr server,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_auth_polkit_ret *ret)
+{
+ pid_t callerPid = -1;
+ gid_t callerGid = -1;
+ uid_t callerUid = -1;
+ unsigned long long timestamp;
+ const char *action;
+ char *ident = NULL;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+ int rv;
+
+ virMutexLock(&priv->lock);
+ action = virNetServerClientGetReadonly(client) ?
+ "org.libvirt.unix.monitor" :
+ "org.libvirt.unix.manage";
+
+ VIR_DEBUG("Start PolicyKit auth %d", virNetServerClientGetFD(client));
+ if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_POLKIT) {
+ VIR_ERROR(_("client tried invalid PolicyKit init request"));
+ goto authfail;
+ }
+
+ if (virNetServerClientGetUNIXIdentity(client, &callerUid, &callerGid,
+ &callerPid, ×tamp) < 0) {
+ goto authfail;
+ }
+
+ if (timestamp == 0) {
+ VIR_WARN("Failing polkit auth due to missing client (pid=%lld) start time",
+ (long long)callerPid);
+ goto authfail;
+ }
+
+ VIR_INFO("Checking PID %lld running as %d",
+ (long long) callerPid, callerUid);
+
+ rv = virPolkitCheckAuth(action,
+ callerPid,
+ timestamp,
+ callerUid,
+ NULL,
+ true);
+ if (rv == -1)
+ goto authfail;
+ else if (rv == -2)
+ goto authdeny;
+
+ PROBE(RPC_SERVER_CLIENT_AUTH_ALLOW,
+ "client=%p auth=%d identity=%s",
+ client, REMOTE_AUTH_POLKIT, ident);
+ VIR_INFO("Policy allowed action %s from pid %lld, uid %d",
+ action, (long long) callerPid, callerUid);
+ ret->complete = 1;
+
+ virNetServerSetClientAuthenticated(server, client);
+ virMutexUnlock(&priv->lock);
+
+ return 0;
+
+ error:
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return -1;
+
+ authfail:
+ PROBE(RPC_SERVER_CLIENT_AUTH_FAIL,
+ "client=%p auth=%d",
+ client, REMOTE_AUTH_POLKIT);
+ goto error;
+
+ authdeny:
+ PROBE(RPC_SERVER_CLIENT_AUTH_DENY,
+ "client=%p auth=%d identity=%s",
+ client, REMOTE_AUTH_POLKIT, ident);
+ goto error;
+}
+
+
+static int
+remoteDispatchNodeDeviceGetParent(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_node_device_get_parent_args *args,
+ remote_node_device_get_parent_ret *ret)
+{
+ virNodeDevicePtr dev = NULL;
+ const char *parent = NULL;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dev = virNodeDeviceLookupByName(priv->conn, args->name)))
+ goto cleanup;
+
+ parent = virNodeDeviceGetParent(dev);
+
+ if (parent == NULL) {
+ ret->parent = NULL;
+ } else {
+ /* remoteDispatchClientRequest will free this. */
+ char **parent_p;
+ if (VIR_ALLOC(parent_p) < 0)
+ goto cleanup;
+ if (VIR_STRDUP(*parent_p, parent) < 0) {
+ VIR_FREE(parent_p);
+ goto cleanup;
+ }
+ ret->parent = parent_p;
+ }
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dev);
+ return rv;
+}
+
+static int
+remoteDispatchConnectRegisterCloseCallback(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr)
+{
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ virMutexLock(&priv->lock);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (virConnectRegisterCloseCallback(priv->conn,
+ remoteRelayConnectionClosedEvent,
+ client, NULL) < 0)
+ goto cleanup;
+
+ priv->closeRegistered = true;
+ rv = 0;
+
+ cleanup:
+ virMutexUnlock(&priv->lock);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ return rv;
+}
+
+static int
+remoteDispatchConnectUnregisterCloseCallback(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr)
+{
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ virMutexLock(&priv->lock);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (virConnectUnregisterCloseCallback(priv->conn,
+ remoteRelayConnectionClosedEvent) < 0)
+ goto cleanup;
+
+ priv->closeRegistered = false;
+ rv = 0;
+
+ cleanup:
+ virMutexUnlock(&priv->lock);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ return rv;
+}
+
+static int
+remoteDispatchConnectDomainEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ remote_connect_domain_event_register_ret *ret ATTRIBUTE_UNUSED)
+{
+ int callbackID;
+ int rv = -1;
+ daemonClientEventCallbackPtr callback = NULL;
+ daemonClientEventCallbackPtr ref;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ /* If we call register first, we could append a complete callback
+ * to our array, but on OOM append failure, we'd have to then hope
+ * deregister works to undo our register. So instead we append an
+ * incomplete callback to our array, then register, then fix up
+ * our callback; or you can use VIR_APPEND_ELEMENT_COPY to avoid
+ * clearing 'callback' and having to juggle the pointer
+ * between 'ref' and 'callback'.
+ */
+ if (VIR_ALLOC(callback) < 0)
+ goto cleanup;
+ callback->client = virObjectRef(client);
+ callback->eventID = VIR_DOMAIN_EVENT_ID_LIFECYCLE;
+ callback->callbackID = -1;
+ callback->legacy = true;
+ ref = callback;
+ if (VIR_APPEND_ELEMENT(priv->domainEventCallbacks,
+ priv->ndomainEventCallbacks,
+ callback) < 0)
+ goto cleanup;
+
+ if ((callbackID = virConnectDomainEventRegisterAny(priv->conn,
+ NULL,
+ VIR_DOMAIN_EVENT_ID_LIFECYCLE,
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
+ ref,
+ remoteEventCallbackFree)) < 0) {
+ VIR_SHRINK_N(priv->domainEventCallbacks,
+ priv->ndomainEventCallbacks, 1);
+ callback = ref;
+ goto cleanup;
+ }
+
+ ref->callbackID = callbackID;
+
+ rv = 0;
+
+ cleanup:
+ remoteEventCallbackFree(callback);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+static int
+remoteDispatchConnectDomainEventDeregister(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ remote_connect_domain_event_deregister_ret *ret ATTRIBUTE_UNUSED)
+{
+ int callbackID = -1;
+ int rv = -1;
+ size_t i;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ for (i = 0; i < priv->ndomainEventCallbacks; i++) {
+ if (priv->domainEventCallbacks[i]->eventID == VIR_DOMAIN_EVENT_ID_LIFECYCLE) {
+ callbackID = priv->domainEventCallbacks[i]->callbackID;
+ break;
+ }
+ }
+
+ if (callbackID < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("domain event %d not registered"),
+ VIR_DOMAIN_EVENT_ID_LIFECYCLE);
+ goto cleanup;
+ }
+
+ if (virConnectDomainEventDeregisterAny(priv->conn, callbackID) < 0)
+ goto cleanup;
+
+ VIR_DELETE_ELEMENT(priv->domainEventCallbacks, i,
+ priv->ndomainEventCallbacks);
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+static void
+remoteDispatchObjectEventSend(virNetServerClientPtr client,
+ virNetServerProgramPtr program,
+ int procnr,
+ xdrproc_t proc,
+ void *data)
+{
+ virNetMessagePtr msg;
+
+ if (!(msg = virNetMessageNew(false)))
+ goto cleanup;
+
+ msg->header.prog = virNetServerProgramGetID(program);
+ msg->header.vers = virNetServerProgramGetVersion(program);
+ msg->header.proc = procnr;
+ msg->header.type = VIR_NET_MESSAGE;
+ msg->header.serial = 1;
+ msg->header.status = VIR_NET_OK;
+
+ if (virNetMessageEncodeHeader(msg) < 0)
+ goto cleanup;
+
+ if (virNetMessageEncodePayload(msg, proc, data) < 0)
+ goto cleanup;
+
+ VIR_DEBUG("Queue event %d %zu", procnr, msg->bufferLength);
+ virNetServerClientSendMessage(client, msg);
+
+ xdr_free(proc, data);
+ return;
+
+ cleanup:
+ virNetMessageFree(msg);
+ xdr_free(proc, data);
+}
+
+static int
+remoteDispatchSecretGetValue(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_secret_get_value_args *args,
+ remote_secret_get_value_ret *ret)
+{
+ virSecretPtr secret = NULL;
+ size_t value_size;
+ unsigned char *value;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(secret = get_nonnull_secret(priv->conn, args->secret)))
+ goto cleanup;
+
+ if (!(value = virSecretGetValue(secret, &value_size, args->flags)))
+ goto cleanup;
+
+ ret->value.value_len = value_size;
+ ret->value.value_val = (char *)value;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(secret);
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetState(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_state_args *args,
+ remote_domain_get_state_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (virDomainGetState(dom, &ret->state, &ret->reason, args->flags) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ return rv;
+}
+
+
+/* Due to back-compat reasons, two RPC calls map to the same libvirt
+ * API of virConnectDomainEventRegisterAny. A client should only use
+ * the new call if they have probed
+ * VIR_DRV_SUPPORTS_FEATURE(VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK),
+ * and must not mix the two styles. */
+static int
+remoteDispatchConnectDomainEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ remote_connect_domain_event_register_any_args *args)
+{
+ int callbackID;
+ int rv = -1;
+ daemonClientEventCallbackPtr callback = NULL;
+ daemonClientEventCallbackPtr ref;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ /* We intentionally do not use VIR_DOMAIN_EVENT_ID_LAST here; any
+ * new domain events added after this point should only use the
+ * modern callback style of RPC. */
+ if (args->eventID > VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED ||
+ args->eventID < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, _("unsupported event ID %d"),
+ args->eventID);
+ goto cleanup;
+ }
+
+ /* If we call register first, we could append a complete callback
+ * to our array, but on OOM append failure, we'd have to then hope
+ * deregister works to undo our register. So instead we append an
+ * incomplete callback to our array, then register, then fix up
+ * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
+ * success, we use 'ref' to save a copy of the pointer. */
+ if (VIR_ALLOC(callback) < 0)
+ goto cleanup;
+ callback->client = virObjectRef(client);
+ callback->eventID = args->eventID;
+ callback->callbackID = -1;
+ callback->legacy = true;
+ ref = callback;
+ if (VIR_APPEND_ELEMENT(priv->domainEventCallbacks,
+ priv->ndomainEventCallbacks,
+ callback) < 0)
+ goto cleanup;
+
+ if ((callbackID = virConnectDomainEventRegisterAny(priv->conn,
+ NULL,
+ args->eventID,
+ domainEventCallbacks[args->eventID],
+ ref,
+ remoteEventCallbackFree)) < 0) {
+ VIR_SHRINK_N(priv->domainEventCallbacks,
+ priv->ndomainEventCallbacks, 1);
+ callback = ref;
+ goto cleanup;
+ }
+
+ ref->callbackID = callbackID;
+
+ rv = 0;
+
+ cleanup:
+ remoteEventCallbackFree(callback);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+
+static int
+remoteDispatchConnectDomainEventCallbackRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ remote_connect_domain_event_callback_register_any_args *args,
+ remote_connect_domain_event_callback_register_any_ret *ret)
+{
+ int callbackID;
+ int rv = -1;
+ daemonClientEventCallbackPtr callback = NULL;
+ daemonClientEventCallbackPtr ref;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+ virDomainPtr dom = NULL;
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ if (args->dom &&
+ !(dom = get_nonnull_domain(priv->conn, *args->dom)))
+ goto cleanup;
+
+ if (args->eventID >= VIR_DOMAIN_EVENT_ID_LAST || args->eventID < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, _("unsupported event ID %d"),
+ args->eventID);
+ goto cleanup;
+ }
+
+ /* If we call register first, we could append a complete callback
+ * to our array, but on OOM append failure, we'd have to then hope
+ * deregister works to undo our register. So instead we append an
+ * incomplete callback to our array, then register, then fix up
+ * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
+ * success, we use 'ref' to save a copy of the pointer. */
+ if (VIR_ALLOC(callback) < 0)
+ goto cleanup;
+ callback->client = virObjectRef(client);
+ callback->eventID = args->eventID;
+ callback->callbackID = -1;
+ ref = callback;
+ if (VIR_APPEND_ELEMENT(priv->domainEventCallbacks,
+ priv->ndomainEventCallbacks,
+ callback) < 0)
+ goto cleanup;
+
+ if ((callbackID = virConnectDomainEventRegisterAny(priv->conn,
+ dom,
+ args->eventID,
+ domainEventCallbacks[args->eventID],
+ ref,
+ remoteEventCallbackFree)) < 0) {
+ VIR_SHRINK_N(priv->domainEventCallbacks,
+ priv->ndomainEventCallbacks, 1);
+ callback = ref;
+ goto cleanup;
+ }
+
+ ref->callbackID = callbackID;
+ ret->callbackID = callbackID;
+
+ rv = 0;
+
+ cleanup:
+ remoteEventCallbackFree(callback);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+
+static int
+remoteDispatchConnectDomainEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ remote_connect_domain_event_deregister_any_args *args)
+{
+ int callbackID = -1;
+ int rv = -1;
+ size_t i;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ /* We intentionally do not use VIR_DOMAIN_EVENT_ID_LAST here; any
+ * new domain events added after this point should only use the
+ * modern callback style of RPC. */
+ if (args->eventID > VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED ||
+ args->eventID < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, _("unsupported event ID %d"),
+ args->eventID);
+ goto cleanup;
+ }
+
+ for (i = 0; i < priv->ndomainEventCallbacks; i++) {
+ if (priv->domainEventCallbacks[i]->eventID == args->eventID) {
+ callbackID = priv->domainEventCallbacks[i]->callbackID;
+ break;
+ }
+ }
+ if (callbackID < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("domain event %d not registered"), args->eventID);
+ goto cleanup;
+ }
+
+ if (virConnectDomainEventDeregisterAny(priv->conn, callbackID) < 0)
+ goto cleanup;
+
+ VIR_DELETE_ELEMENT(priv->domainEventCallbacks, i,
+ priv->ndomainEventCallbacks);
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+
+static int
+remoteDispatchConnectDomainEventCallbackDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ remote_connect_domain_event_callback_deregister_any_args *args)
+{
+ int rv = -1;
+ size_t i;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ for (i = 0; i < priv->ndomainEventCallbacks; i++) {
+ if (priv->domainEventCallbacks[i]->callbackID == args->callbackID)
+ break;
+ }
+ if (i == priv->ndomainEventCallbacks) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("domain event callback %d not registered"),
+ args->callbackID);
+ goto cleanup;
+ }
+
+ if (virConnectDomainEventDeregisterAny(priv->conn, args->callbackID) < 0)
+ goto cleanup;
+
+ VIR_DELETE_ELEMENT(priv->domainEventCallbacks, i,
+ priv->ndomainEventCallbacks);
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+
+static int
+qemuDispatchDomainMonitorCommand(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ qemu_domain_monitor_command_args *args,
+ qemu_domain_monitor_command_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (virDomainQemuMonitorCommand(dom, args->cmd, &ret->result,
+ args->flags) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ return rv;
+}
+
+
+static int
+remoteDispatchDomainMigrateBegin3(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_migrate_begin3_args *args,
+ remote_domain_migrate_begin3_ret *ret)
+{
+ char *xml = NULL;
+ virDomainPtr dom = NULL;
+ char *dname;
+ char *xmlin;
+ char *cookieout = NULL;
+ int cookieoutlen = 0;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ xmlin = args->xmlin == NULL ? NULL : *args->xmlin;
+ dname = args->dname == NULL ? NULL : *args->dname;
+
+ if (!(xml = virDomainMigrateBegin3(dom, xmlin,
+ &cookieout, &cookieoutlen,
+ args->flags, dname, args->resource)))
+ goto cleanup;
+
+ /* remoteDispatchClientRequest will free cookie and
+ * the xml string if there is one.
+ */
+ ret->cookie_out.cookie_out_len = cookieoutlen;
+ ret->cookie_out.cookie_out_val = cookieout;
+ ret->xml = xml;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ return rv;
+}
+
+
+static int
+remoteDispatchDomainMigratePrepare3(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_migrate_prepare3_args *args,
+ remote_domain_migrate_prepare3_ret *ret)
+{
+ char *cookieout = NULL;
+ int cookieoutlen = 0;
+ char *uri_in;
+ char **uri_out;
+ char *dname;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ uri_in = args->uri_in == NULL ? NULL : *args->uri_in;
+ dname = args->dname == NULL ? NULL : *args->dname;
+
+ /* Wacky world of XDR ... */
+ if (VIR_ALLOC(uri_out) < 0)
+ goto cleanup;
+
+ if (virDomainMigratePrepare3(priv->conn,
+ args->cookie_in.cookie_in_val,
+ args->cookie_in.cookie_in_len,
+ &cookieout, &cookieoutlen,
+ uri_in, uri_out,
+ args->flags, dname, args->resource,
+ args->dom_xml) < 0)
+ goto cleanup;
+
+ /* remoteDispatchClientRequest will free cookie, uri_out and
+ * the string if there is one.
+ */
+ ret->cookie_out.cookie_out_len = cookieoutlen;
+ ret->cookie_out.cookie_out_val = cookieout;
+ ret->uri_out = *uri_out == NULL ? NULL : uri_out;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0) {
+ virNetMessageSaveError(rerr);
+ VIR_FREE(uri_out);
+ }
+ return rv;
+}
+
+
+static int
+remoteDispatchDomainMigratePerform3(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_migrate_perform3_args *args,
+ remote_domain_migrate_perform3_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ char *xmlin;
+ char *dname;
+ char *uri;
+ char *dconnuri;
+ char *cookieout = NULL;
+ int cookieoutlen = 0;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ xmlin = args->xmlin == NULL ? NULL : *args->xmlin;
+ dname = args->dname == NULL ? NULL : *args->dname;
+ uri = args->uri == NULL ? NULL : *args->uri;
+ dconnuri = args->dconnuri == NULL ? NULL : *args->dconnuri;
+
+ if (virDomainMigratePerform3(dom, xmlin,
+ args->cookie_in.cookie_in_val,
+ args->cookie_in.cookie_in_len,
+ &cookieout, &cookieoutlen,
+ dconnuri, uri,
+ args->flags, dname, args->resource) < 0)
+ goto cleanup;
+
+ /* remoteDispatchClientRequest will free cookie
+ */
+ ret->cookie_out.cookie_out_len = cookieoutlen;
+ ret->cookie_out.cookie_out_val = cookieout;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ return rv;
+}
+
+
+static int
+remoteDispatchDomainMigrateFinish3(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_migrate_finish3_args *args,
+ remote_domain_migrate_finish3_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ char *cookieout = NULL;
+ int cookieoutlen = 0;
+ char *uri;
+ char *dconnuri;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ uri = args->uri == NULL ? NULL : *args->uri;
+ dconnuri = args->dconnuri == NULL ? NULL : *args->dconnuri;
+
+ if (!(dom = virDomainMigrateFinish3(priv->conn, args->dname,
+ args->cookie_in.cookie_in_val,
+ args->cookie_in.cookie_in_len,
+ &cookieout, &cookieoutlen,
+ dconnuri, uri,
+ args->flags,
+ args->cancelled)))
+ goto cleanup;
+
+ make_nonnull_domain(&ret->dom, dom);
+
+ /* remoteDispatchClientRequest will free cookie
+ */
+ ret->cookie_out.cookie_out_len = cookieoutlen;
+ ret->cookie_out.cookie_out_val = cookieout;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0) {
+ virNetMessageSaveError(rerr);
+ VIR_FREE(cookieout);
+ }
+ virObjectUnref(dom);
+ return rv;
+}
+
+
+static int
+remoteDispatchDomainMigrateConfirm3(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_migrate_confirm3_args *args)
+{
+ virDomainPtr dom = NULL;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (virDomainMigrateConfirm3(dom,
+ args->cookie_in.cookie_in_val,
+ args->cookie_in.cookie_in_len,
+ args->flags, args->cancelled) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ return rv;
+}
+
+
+static int remoteDispatchConnectSupportsFeature(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_connect_supports_feature_args *args,
+ remote_connect_supports_feature_ret *ret)
+{
+ int rv = -1;
+ int supported;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ /* This feature is checked before opening the connection, thus we must
+ * check it first.
+ */
+ if (args->feature == VIR_DRV_FEATURE_PROGRAM_KEEPALIVE) {
+ if (virNetServerClientStartKeepAlive(client) < 0)
+ goto cleanup;
+ supported = 1;
+ goto done;
+ }
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ switch (args->feature) {
+ case VIR_DRV_FEATURE_FD_PASSING:
+ case VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK:
+ case VIR_DRV_FEATURE_REMOTE_CLOSE_CALLBACK:
+ supported = 1;
+ break;
+
+ default:
+ if ((supported = virConnectSupportsFeature(priv->conn, args->feature)) < 0)
+ goto cleanup;
+ break;
+ }
+
+ done:
+ ret->supported = supported;
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ return rv;
+}
+
+
+static int
+remoteDispatchDomainOpenGraphics(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg,
+ virNetMessageErrorPtr rerr,
+ remote_domain_open_graphics_args *args)
+{
+ virDomainPtr dom = NULL;
+ int rv = -1;
+ int fd = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if ((fd = virNetMessageDupFD(msg, 0)) < 0)
+ goto cleanup;
+
+ if (virDomainOpenGraphics(dom,
+ args->idx,
+ fd,
+ args->flags) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+ cleanup:
+ VIR_FORCE_CLOSE(fd);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ return rv;
+}
+
+
+static int
+remoteDispatchDomainOpenGraphicsFd(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg,
+ virNetMessageErrorPtr rerr,
+ remote_domain_open_graphics_fd_args *args)
+{
+ virDomainPtr dom = NULL;
+ int rv = -1;
+ int fd = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if ((fd = virDomainOpenGraphicsFD(dom,
+ args->idx,
+ args->flags)) < 0)
+ goto cleanup;
+
+ if (virNetMessageAddFD(msg, fd) < 0)
+ goto cleanup;
+
+ /* return 1 here to let virNetServerProgramDispatchCall know
+ * we are passing a FD */
+ rv = 1;
+
+ cleanup:
+ VIR_FORCE_CLOSE(fd);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+
+ virObjectUnref(dom);
+ return rv;
+}
+
+
+static int
+remoteDispatchDomainGetInterfaceParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_interface_parameters_args *args,
+ remote_domain_get_interface_parameters_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ virTypedParameterPtr params = NULL;
+ const char *device = args->device;
+ int nparams = 0;
+ unsigned int flags;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ flags = args->flags;
+
+ if (args->nparams > REMOTE_DOMAIN_INTERFACE_PARAMETERS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
+ goto cleanup;
+ }
+ if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
+ goto cleanup;
+ nparams = args->nparams;
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (virDomainGetInterfaceParameters(dom, device, params, &nparams, flags) < 0)
+ goto cleanup;
+
+ /* In this case, we need to send back the number of parameters
+ * supported
+ */
+ if (args->nparams == 0) {
+ ret->nparams = nparams;
+ goto success;
+ }
+
+ if (virTypedParamsSerialize(params, nparams,
+ (virTypedParameterRemotePtr *) &ret->params.params_val,
+ &ret->params.params_len,
+ flags) < 0)
+ goto cleanup;
+
+ success:
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virTypedParamsFree(params, nparams);
+ virObjectUnref(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetCPUStats(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_cpu_stats_args *args,
+ remote_domain_get_cpu_stats_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ struct daemonClientPrivate *priv;
+ virTypedParameterPtr params = NULL;
+ int rv = -1;
+ int percpu_len = 0;
+
+ priv = virNetServerClientGetPrivateData(client);
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (args->nparams > REMOTE_NODE_CPU_STATS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
+ goto cleanup;
+ }
+ if (args->ncpus > REMOTE_DOMAIN_GET_CPU_STATS_NCPUS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("ncpus too large"));
+ goto cleanup;
+ }
+
+ if (args->nparams > 0 &&
+ VIR_ALLOC_N(params, args->ncpus * args->nparams) < 0)
+ goto cleanup;
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ percpu_len = virDomainGetCPUStats(dom, params, args->nparams,
+ args->start_cpu, args->ncpus,
+ args->flags);
+ if (percpu_len < 0)
+ goto cleanup;
+ /* If nparams == 0, the function returns a single value */
+ if (args->nparams == 0)
+ goto success;
+
+ if (virTypedParamsSerialize(params, args->nparams * args->ncpus,
+ (virTypedParameterRemotePtr *) &ret->params.params_val,
+ &ret->params.params_len,
+ args->flags) < 0)
+ goto cleanup;
+
+ success:
+ rv = 0;
+ ret->nparams = percpu_len;
+ if (args->nparams && !(args->flags & VIR_TYPED_PARAM_STRING_OKAY)) {
+ size_t i;
+
+ for (i = 0; i < percpu_len; i++) {
+ if (params[i].type == VIR_TYPED_PARAM_STRING)
+ ret->nparams--;
+ }
+ }
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virTypedParamsFree(params, args->ncpus * args->nparams);
+ virObjectUnref(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetDiskErrors(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_disk_errors_args *args,
+ remote_domain_get_disk_errors_ret *ret)
+{
+ int rv = -1;
+ virDomainPtr dom = NULL;
+ virDomainDiskErrorPtr errors = NULL;
+ int len = 0;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (args->maxerrors > REMOTE_DOMAIN_DISK_ERRORS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("maxerrors too large"));
+ goto cleanup;
+ }
+
+ if (args->maxerrors &&
+ VIR_ALLOC_N(errors, args->maxerrors) < 0)
+ goto cleanup;
+
+ if ((len = virDomainGetDiskErrors(dom, errors,
+ args->maxerrors,
+ args->flags)) < 0)
+ goto cleanup;
+
+ ret->nerrors = len;
+ if (errors &&
+ remoteSerializeDomainDiskErrors(errors, len,
+ &ret->errors.errors_val,
+ &ret->errors.errors_len) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ if (errors && len > 0) {
+ size_t i;
+ for (i = 0; i < len; i++)
+ VIR_FREE(errors[i].disk);
+ }
+ VIR_FREE(errors);
+ return rv;
+}
+
+
+static int
+remoteDispatchNodeGetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_node_get_memory_parameters_args *args,
+ remote_node_get_memory_parameters_ret *ret)
+{
+ virTypedParameterPtr params = NULL;
+ int nparams = 0;
+ unsigned int flags;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ flags = args->flags;
+
+ if (args->nparams > REMOTE_NODE_MEMORY_PARAMETERS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
+ goto cleanup;
+ }
+ if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
+ goto cleanup;
+ nparams = args->nparams;
+
+ if (virNodeGetMemoryParameters(priv->conn, params, &nparams, flags) < 0)
+ goto cleanup;
+
+ /* In this case, we need to send back the number of parameters
+ * supported
+ */
+ if (args->nparams == 0) {
+ ret->nparams = nparams;
+ goto success;
+ }
+
+ if (virTypedParamsSerialize(params, nparams,
+ (virTypedParameterRemotePtr *) &ret->params.params_val,
+ &ret->params.params_len,
+ args->flags) < 0)
+ goto cleanup;
+
+ success:
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virTypedParamsFree(params, nparams);
+ return rv;
+}
+
+static int
+remoteDispatchNodeGetCPUMap(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_node_get_cpu_map_args *args,
+ remote_node_get_cpu_map_ret *ret)
+{
+ unsigned char *cpumap = NULL;
+ unsigned int online = 0;
+ unsigned int flags;
+ int cpunum;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ flags = args->flags;
+
+ cpunum = virNodeGetCPUMap(priv->conn, args->need_map ? &cpumap : NULL,
+ args->need_online ? &online : NULL, flags);
+ if (cpunum < 0)
+ goto cleanup;
+
+ /* 'serialize' return cpumap */
+ if (args->need_map) {
+ ret->cpumap.cpumap_len = VIR_CPU_MAPLEN(cpunum);
+ ret->cpumap.cpumap_val = (char *) cpumap;
+ cpumap = NULL;
+ }
+
+ ret->online = online;
+ ret->ret = cpunum;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ VIR_FREE(cpumap);
+ return rv;
+}
+
+static int
+lxcDispatchDomainOpenNamespace(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ lxc_domain_open_namespace_args *args)
+{
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+ int *fdlist = NULL;
+ int ret;
+ virDomainPtr dom = NULL;
+ size_t i;
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ ret = virDomainLxcOpenNamespace(dom,
+ &fdlist,
+ args->flags);
+ if (ret < 0)
+ goto cleanup;
+
+ /* We shouldn't have received any from the client,
+ * but in case they're playing games with us, prevent
+ * a resource leak
+ */
+ for (i = 0; i < msg->nfds; i++)
+ VIR_FORCE_CLOSE(msg->fds[i]);
+ VIR_FREE(msg->fds);
+ msg->nfds = 0;
+
+ msg->fds = fdlist;
+ msg->nfds = ret;
+
+ rv = 1;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetJobStats(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_job_stats_args *args,
+ remote_domain_get_job_stats_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ virTypedParameterPtr params = NULL;
+ int nparams = 0;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (virDomainGetJobStats(dom, &ret->type, ¶ms,
+ &nparams, args->flags) < 0)
+ goto cleanup;
+
+ if (nparams > REMOTE_DOMAIN_JOB_STATS_MAX) {
+ virReportError(VIR_ERR_RPC,
+ _("Too many job stats '%d' for limit '%d'"),
+ nparams, REMOTE_DOMAIN_JOB_STATS_MAX);
+ goto cleanup;
+ }
+
+ if (virTypedParamsSerialize(params, nparams,
+ (virTypedParameterRemotePtr *) &ret->params.params_val,
+ &ret->params.params_len,
+ 0) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virTypedParamsFree(params, nparams);
+ virObjectUnref(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainMigrateBegin3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_migrate_begin3_params_args *args,
+ remote_domain_migrate_begin3_params_ret *ret)
+{
+ char *xml = NULL;
+ virDomainPtr dom = NULL;
+ virTypedParameterPtr params = NULL;
+ int nparams = 0;
+ char *cookieout = NULL;
+ int cookieoutlen = 0;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (args->params.params_len > REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX) {
+ virReportError(VIR_ERR_RPC,
+ _("Too many migration parameters '%d' for limit '%d'"),
+ args->params.params_len, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX);
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val,
+ args->params.params_len,
+ 0, ¶ms, &nparams) < 0)
+ goto cleanup;
+
+ if (!(xml = virDomainMigrateBegin3Params(dom, params, nparams,
+ &cookieout, &cookieoutlen,
+ args->flags)))
+ goto cleanup;
+
+ ret->cookie_out.cookie_out_len = cookieoutlen;
+ ret->cookie_out.cookie_out_val = cookieout;
+ ret->xml = xml;
+
+ rv = 0;
+
+ cleanup:
+ virTypedParamsFree(params, nparams);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainMigratePrepare3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_migrate_prepare3_params_args *args,
+ remote_domain_migrate_prepare3_params_ret *ret)
+{
+ virTypedParameterPtr params = NULL;
+ int nparams = 0;
+ char *cookieout = NULL;
+ int cookieoutlen = 0;
+ char **uri_out;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (args->params.params_len > REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX) {
+ virReportError(VIR_ERR_RPC,
+ _("Too many migration parameters '%d' for limit '%d'"),
+ args->params.params_len, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX);
+ goto cleanup;
+ }
+
+ if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val,
+ args->params.params_len,
+ 0, ¶ms, &nparams) < 0)
+ goto cleanup;
+
+ /* Wacky world of XDR ... */
+ if (VIR_ALLOC(uri_out) < 0)
+ goto cleanup;
+
+ if (virDomainMigratePrepare3Params(priv->conn, params, nparams,
+ args->cookie_in.cookie_in_val,
+ args->cookie_in.cookie_in_len,
+ &cookieout, &cookieoutlen,
+ uri_out, args->flags) < 0)
+ goto cleanup;
+
+ ret->cookie_out.cookie_out_len = cookieoutlen;
+ ret->cookie_out.cookie_out_val = cookieout;
+ ret->uri_out = !*uri_out ? NULL : uri_out;
+
+ rv = 0;
+
+ cleanup:
+ virTypedParamsFree(params, nparams);
+ if (rv < 0) {
+ virNetMessageSaveError(rerr);
+ VIR_FREE(uri_out);
+ }
+ return rv;
+}
+
+static int
+remoteDispatchDomainMigratePrepareTunnel3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg,
+ virNetMessageErrorPtr rerr,
+ remote_domain_migrate_prepare_tunnel3_params_args *args,
+ remote_domain_migrate_prepare_tunnel3_params_ret *ret)
+{
+ virTypedParameterPtr params = NULL;
+ int nparams = 0;
+ char *cookieout = NULL;
+ int cookieoutlen = 0;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+ virStreamPtr st = NULL;
+ daemonClientStreamPtr stream = NULL;
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (args->params.params_len > REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX) {
+ virReportError(VIR_ERR_RPC,
+ _("Too many migration parameters '%d' for limit '%d'"),
+ args->params.params_len, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX);
+ goto cleanup;
+ }
+
+ if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val,
+ args->params.params_len,
+ 0, ¶ms, &nparams) < 0)
+ goto cleanup;
+
+ if (!(st = virStreamNew(priv->conn, VIR_STREAM_NONBLOCK)) ||
+ !(stream = daemonCreateClientStream(client, st, remoteProgram,
+ &msg->header, false)))
+ goto cleanup;
+
+ if (virDomainMigratePrepareTunnel3Params(priv->conn, st, params, nparams,
+ args->cookie_in.cookie_in_val,
+ args->cookie_in.cookie_in_len,
+ &cookieout, &cookieoutlen,
+ args->flags) < 0)
+ goto cleanup;
+
+ if (daemonAddClientStream(client, stream, false) < 0)
+ goto cleanup;
+
+ ret->cookie_out.cookie_out_val = cookieout;
+ ret->cookie_out.cookie_out_len = cookieoutlen;
+ rv = 0;
+
+ cleanup:
+ virTypedParamsFree(params, nparams);
+ if (rv < 0) {
+ virNetMessageSaveError(rerr);
+ VIR_FREE(cookieout);
+ if (stream) {
+ virStreamAbort(st);
+ daemonFreeClientStream(client, stream);
+ } else {
+ virObjectUnref(st);
+ }
+ }
+ return rv;
+}
+
+
+static int
+remoteDispatchDomainMigratePerform3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_migrate_perform3_params_args *args,
+ remote_domain_migrate_perform3_params_ret *ret)
+{
+ virTypedParameterPtr params = NULL;
+ int nparams = 0;
+ virDomainPtr dom = NULL;
+ char *cookieout = NULL;
+ int cookieoutlen = 0;
+ char *dconnuri;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (args->params.params_len > REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX) {
+ virReportError(VIR_ERR_RPC,
+ _("Too many migration parameters '%d' for limit '%d'"),
+ args->params.params_len, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX);
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val,
+ args->params.params_len,
+ 0, ¶ms, &nparams) < 0)
+ goto cleanup;
+
+ dconnuri = args->dconnuri == NULL ? NULL : *args->dconnuri;
+
+ if (virDomainMigratePerform3Params(dom, dconnuri, params, nparams,
+ args->cookie_in.cookie_in_val,
+ args->cookie_in.cookie_in_len,
+ &cookieout, &cookieoutlen,
+ args->flags) < 0)
+ goto cleanup;
+
+ ret->cookie_out.cookie_out_len = cookieoutlen;
+ ret->cookie_out.cookie_out_val = cookieout;
+
+ rv = 0;
+
+ cleanup:
+ virTypedParamsFree(params, nparams);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ return rv;
+}
+
+
+static int
+remoteDispatchDomainMigrateFinish3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_migrate_finish3_params_args *args,
+ remote_domain_migrate_finish3_params_ret *ret)
+{
+ virTypedParameterPtr params = NULL;
+ int nparams = 0;
+ virDomainPtr dom = NULL;
+ char *cookieout = NULL;
+ int cookieoutlen = 0;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (args->params.params_len > REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX) {
+ virReportError(VIR_ERR_RPC,
+ _("Too many migration parameters '%d' for limit '%d'"),
+ args->params.params_len, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX);
+ goto cleanup;
+ }
+
+ if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val,
+ args->params.params_len,
+ 0, ¶ms, &nparams) < 0)
+ goto cleanup;
+
+ dom = virDomainMigrateFinish3Params(priv->conn, params, nparams,
+ args->cookie_in.cookie_in_val,
+ args->cookie_in.cookie_in_len,
+ &cookieout, &cookieoutlen,
+ args->flags, args->cancelled);
+ if (!dom)
+ goto cleanup;
+
+ make_nonnull_domain(&ret->dom, dom);
+
+ ret->cookie_out.cookie_out_len = cookieoutlen;
+ ret->cookie_out.cookie_out_val = cookieout;
+
+ rv = 0;
+
+ cleanup:
+ virTypedParamsFree(params, nparams);
+ if (rv < 0) {
+ virNetMessageSaveError(rerr);
+ VIR_FREE(cookieout);
+ }
+ virObjectUnref(dom);
+ return rv;
+}
+
+
+static int
+remoteDispatchDomainMigrateConfirm3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_migrate_confirm3_params_args *args)
+{
+ virTypedParameterPtr params = NULL;
+ int nparams = 0;
+ virDomainPtr dom = NULL;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (args->params.params_len > REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX) {
+ virReportError(VIR_ERR_RPC,
+ _("Too many migration parameters '%d' for limit '%d'"),
+ args->params.params_len, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX);
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val,
+ args->params.params_len,
+ 0, ¶ms, &nparams) < 0)
+ goto cleanup;
+
+ if (virDomainMigrateConfirm3Params(dom, params, nparams,
+ args->cookie_in.cookie_in_val,
+ args->cookie_in.cookie_in_len,
+ args->flags, args->cancelled) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+ cleanup:
+ virTypedParamsFree(params, nparams);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ return rv;
+}
+
+
+static int
+remoteDispatchConnectGetCPUModelNames(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_connect_get_cpu_model_names_args *args,
+ remote_connect_get_cpu_model_names_ret *ret)
+{
+ int len, rv = -1;
+ char **models = NULL;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ len = virConnectGetCPUModelNames(priv->conn, args->arch,
+ args->need_results ? &models : NULL,
+ args->flags);
+ if (len < 0)
+ goto cleanup;
+
+ if (len > REMOTE_CONNECT_CPU_MODELS_MAX) {
+ virReportError(VIR_ERR_RPC,
+ _("Too many CPU models '%d' for limit '%d'"),
+ len, REMOTE_CONNECT_CPU_MODELS_MAX);
+ goto cleanup;
+ }
+
+ if (len && models) {
+ ret->models.models_val = models;
+ ret->models.models_len = len;
+ models = NULL;
+ } else {
+ ret->models.models_val = NULL;
+ ret->models.models_len = 0;
+ }
+
+ ret->ret = len;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virStringListFree(models);
+ return rv;
+}
+
+
+static int
+remoteDispatchDomainCreateXMLWithFiles(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_create_xml_with_files_args *args,
+ remote_domain_create_xml_with_files_ret *ret)
+{
+ int rv = -1;
+ virDomainPtr dom = NULL;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+ int *files = NULL;
+ unsigned int nfiles = 0;
+ size_t i;
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC_N(files, msg->nfds) < 0)
+ goto cleanup;
+ for (i = 0; i < msg->nfds; i++) {
+ if ((files[i] = virNetMessageDupFD(msg, i)) < 0)
+ goto cleanup;
+ nfiles++;
+ }
+
+ if ((dom = virDomainCreateXMLWithFiles(priv->conn, args->xml_desc,
+ nfiles, files,
+ args->flags)) == NULL)
+ goto cleanup;
+
+ make_nonnull_domain(&ret->dom, dom);
+ rv = 0;
+
+ cleanup:
+ for (i = 0; i < nfiles; i++)
+ VIR_FORCE_CLOSE(files[i]);
+ VIR_FREE(files);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ return rv;
+}
+
+
+static int remoteDispatchDomainCreateWithFiles(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_create_with_files_args *args,
+ remote_domain_create_with_files_ret *ret)
+{
+ int rv = -1;
+ virDomainPtr dom = NULL;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+ int *files = NULL;
+ unsigned int nfiles = 0;
+ size_t i;
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC_N(files, msg->nfds) < 0)
+ goto cleanup;
+ for (i = 0; i < msg->nfds; i++) {
+ if ((files[i] = virNetMessageDupFD(msg, i)) < 0)
+ goto cleanup;
+ nfiles++;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (virDomainCreateWithFiles(dom,
+ nfiles, files,
+ args->flags) < 0)
+ goto cleanup;
+
+ make_nonnull_domain(&ret->dom, dom);
+ rv = 0;
+
+ cleanup:
+ for (i = 0; i < nfiles; i++)
+ VIR_FORCE_CLOSE(files[i]);
+ VIR_FREE(files);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ return rv;
+}
+
+
+static int
+remoteDispatchConnectNetworkEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ remote_connect_network_event_register_any_args *args,
+ remote_connect_network_event_register_any_ret *ret)
+{
+ int callbackID;
+ int rv = -1;
+ daemonClientEventCallbackPtr callback = NULL;
+ daemonClientEventCallbackPtr ref;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+ virNetworkPtr net = NULL;
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ if (args->net &&
+ !(net = get_nonnull_network(priv->conn, *args->net)))
+ goto cleanup;
+
+ if (args->eventID >= VIR_NETWORK_EVENT_ID_LAST || args->eventID < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unsupported network event ID %d"), args->eventID);
+ goto cleanup;
+ }
+
+ /* If we call register first, we could append a complete callback
+ * to our array, but on OOM append failure, we'd have to then hope
+ * deregister works to undo our register. So instead we append an
+ * incomplete callback to our array, then register, then fix up
+ * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
+ * success, we use 'ref' to save a copy of the pointer. */
+ if (VIR_ALLOC(callback) < 0)
+ goto cleanup;
+ callback->client = virObjectRef(client);
+ callback->eventID = args->eventID;
+ callback->callbackID = -1;
+ ref = callback;
+ if (VIR_APPEND_ELEMENT(priv->networkEventCallbacks,
+ priv->nnetworkEventCallbacks,
+ callback) < 0)
+ goto cleanup;
+
+ if ((callbackID = virConnectNetworkEventRegisterAny(priv->conn,
+ net,
+ args->eventID,
+ networkEventCallbacks[args->eventID],
+ ref,
+ remoteEventCallbackFree)) < 0) {
+ VIR_SHRINK_N(priv->networkEventCallbacks,
+ priv->nnetworkEventCallbacks, 1);
+ callback = ref;
+ goto cleanup;
+ }
+
+ ref->callbackID = callbackID;
+ ret->callbackID = callbackID;
+
+ rv = 0;
+
+ cleanup:
+ remoteEventCallbackFree(callback);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(net);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+
+static int
+remoteDispatchConnectNetworkEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ remote_connect_network_event_deregister_any_args *args)
+{
+ int rv = -1;
+ size_t i;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ for (i = 0; i < priv->nnetworkEventCallbacks; i++) {
+ if (priv->networkEventCallbacks[i]->callbackID == args->callbackID)
+ break;
+ }
+ if (i == priv->nnetworkEventCallbacks) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("network event callback %d not registered"),
+ args->callbackID);
+ goto cleanup;
+ }
+
+ if (virConnectNetworkEventDeregisterAny(priv->conn, args->callbackID) < 0)
+ goto cleanup;
+
+ VIR_DELETE_ELEMENT(priv->networkEventCallbacks, i,
+ priv->nnetworkEventCallbacks);
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+static int
+remoteDispatchConnectStoragePoolEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ remote_connect_storage_pool_event_register_any_args *args,
+ remote_connect_storage_pool_event_register_any_ret *ret)
+{
+ int callbackID;
+ int rv = -1;
+ daemonClientEventCallbackPtr callback = NULL;
+ daemonClientEventCallbackPtr ref;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+ virStoragePoolPtr pool = NULL;
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ if (args->pool &&
+ !(pool = get_nonnull_storage_pool(priv->conn, *args->pool)))
+ goto cleanup;
+
+ if (args->eventID >= VIR_STORAGE_POOL_EVENT_ID_LAST || args->eventID < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unsupported storage pool event ID %d"), args->eventID);
+ goto cleanup;
+ }
+
+ /* If we call register first, we could append a complete callback
+ * to our array, but on OOM append failure, we'd have to then hope
+ * deregister works to undo our register. So instead we append an
+ * incomplete callback to our array, then register, then fix up
+ * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
+ * success, we use 'ref' to save a copy of the pointer. */
+ if (VIR_ALLOC(callback) < 0)
+ goto cleanup;
+ callback->client = virObjectRef(client);
+ callback->eventID = args->eventID;
+ callback->callbackID = -1;
+ ref = callback;
+ if (VIR_APPEND_ELEMENT(priv->storageEventCallbacks,
+ priv->nstorageEventCallbacks,
+ callback) < 0)
+ goto cleanup;
+
+ if ((callbackID = virConnectStoragePoolEventRegisterAny(priv->conn,
+ pool,
+ args->eventID,
+ storageEventCallbacks[args->eventID],
+ ref,
+ remoteEventCallbackFree)) < 0) {
+ VIR_SHRINK_N(priv->storageEventCallbacks,
+ priv->nstorageEventCallbacks, 1);
+ callback = ref;
+ goto cleanup;
+ }
+
+ ref->callbackID = callbackID;
+ ret->callbackID = callbackID;
+
+ rv = 0;
+
+ cleanup:
+ remoteEventCallbackFree(callback);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(pool);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+static int
+remoteDispatchConnectStoragePoolEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ remote_connect_storage_pool_event_deregister_any_args *args)
+{
+ int rv = -1;
+ size_t i;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ for (i = 0; i < priv->nstorageEventCallbacks; i++) {
+ if (priv->storageEventCallbacks[i]->callbackID == args->callbackID)
+ break;
+ }
+ if (i == priv->nstorageEventCallbacks) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("storage pool event callback %d not registered"),
+ args->callbackID);
+ goto cleanup;
+ }
+
+ if (virConnectStoragePoolEventDeregisterAny(priv->conn, args->callbackID) < 0)
+ goto cleanup;
+
+ VIR_DELETE_ELEMENT(priv->storageEventCallbacks, i,
+ priv->nstorageEventCallbacks);
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+static int
+remoteDispatchConnectNodeDeviceEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ remote_connect_node_device_event_register_any_args *args,
+ remote_connect_node_device_event_register_any_ret *ret)
+{
+ int callbackID;
+ int rv = -1;
+ daemonClientEventCallbackPtr callback = NULL;
+ daemonClientEventCallbackPtr ref;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+ virNodeDevicePtr dev = NULL;
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ if (args->dev &&
+ !(dev = get_nonnull_node_device(priv->conn, *args->dev)))
+ goto cleanup;
+
+ if (args->eventID >= VIR_NODE_DEVICE_EVENT_ID_LAST || args->eventID < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unsupported node device event ID %d"), args->eventID);
+ goto cleanup;
+ }
+
+ /* If we call register first, we could append a complete callback
+ * to our array, but on OOM append failure, we'd have to then hope
+ * deregister works to undo our register. So instead we append an
+ * incomplete callback to our array, then register, then fix up
+ * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
+ * success, we use 'ref' to save a copy of the pointer. */
+ if (VIR_ALLOC(callback) < 0)
+ goto cleanup;
+ callback->client = virObjectRef(client);
+ callback->eventID = args->eventID;
+ callback->callbackID = -1;
+ ref = callback;
+ if (VIR_APPEND_ELEMENT(priv->nodeDeviceEventCallbacks,
+ priv->nnodeDeviceEventCallbacks,
+ callback) < 0)
+ goto cleanup;
+
+ if ((callbackID = virConnectNodeDeviceEventRegisterAny(priv->conn,
+ dev,
+ args->eventID,
+ nodeDeviceEventCallbacks[args->eventID],
+ ref,
+ remoteEventCallbackFree)) < 0) {
+ VIR_SHRINK_N(priv->nodeDeviceEventCallbacks,
+ priv->nnodeDeviceEventCallbacks, 1);
+ callback = ref;
+ goto cleanup;
+ }
+
+ ref->callbackID = callbackID;
+ ret->callbackID = callbackID;
+
+ rv = 0;
+
+ cleanup:
+ remoteEventCallbackFree(callback);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dev);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+static int
+remoteDispatchConnectNodeDeviceEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ remote_connect_node_device_event_deregister_any_args *args)
+{
+ int rv = -1;
+ size_t i;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ for (i = 0; i < priv->nnodeDeviceEventCallbacks; i++) {
+ if (priv->nodeDeviceEventCallbacks[i]->callbackID == args->callbackID)
+ break;
+ }
+ if (i == priv->nnodeDeviceEventCallbacks) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("node device event callback %d not registered"),
+ args->callbackID);
+ goto cleanup;
+ }
+
+ if (virConnectNodeDeviceEventDeregisterAny(priv->conn, args->callbackID) < 0)
+ goto cleanup;
+
+ VIR_DELETE_ELEMENT(priv->nodeDeviceEventCallbacks, i,
+ priv->nnodeDeviceEventCallbacks);
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+static int
+remoteDispatchConnectSecretEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ remote_connect_secret_event_register_any_args *args,
+ remote_connect_secret_event_register_any_ret *ret)
+{
+ int callbackID;
+ int rv = -1;
+ daemonClientEventCallbackPtr callback = NULL;
+ daemonClientEventCallbackPtr ref;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+ virSecretPtr secret = NULL;
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ if (args->secret &&
+ !(secret = get_nonnull_secret(priv->conn, *args->secret)))
+ goto cleanup;
+
+ if (args->eventID >= VIR_SECRET_EVENT_ID_LAST || args->eventID < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unsupported secret event ID %d"), args->eventID);
+ goto cleanup;
+ }
+
+ /* If we call register first, we could append a complete callback
+ * to our array, but on OOM append failure, we'd have to then hope
+ * deregister works to undo our register. So instead we append an
+ * incomplete callback to our array, then register, then fix up
+ * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
+ * success, we use 'ref' to save a copy of the pointer. */
+ if (VIR_ALLOC(callback) < 0)
+ goto cleanup;
+ callback->client = virObjectRef(client);
+ callback->eventID = args->eventID;
+ callback->callbackID = -1;
+ ref = callback;
+ if (VIR_APPEND_ELEMENT(priv->secretEventCallbacks,
+ priv->nsecretEventCallbacks,
+ callback) < 0)
+ goto cleanup;
+
+ if ((callbackID = virConnectSecretEventRegisterAny(priv->conn,
+ secret,
+ args->eventID,
+ secretEventCallbacks[args->eventID],
+ ref,
+ remoteEventCallbackFree)) < 0) {
+ VIR_SHRINK_N(priv->secretEventCallbacks,
+ priv->nsecretEventCallbacks, 1);
+ callback = ref;
+ goto cleanup;
+ }
+
+ ref->callbackID = callbackID;
+ ret->callbackID = callbackID;
+
+ rv = 0;
+
+ cleanup:
+ remoteEventCallbackFree(callback);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(secret);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+static int
+remoteDispatchConnectSecretEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ remote_connect_secret_event_deregister_any_args *args)
+{
+ int rv = -1;
+ size_t i;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ for (i = 0; i < priv->nsecretEventCallbacks; i++) {
+ if (priv->secretEventCallbacks[i]->callbackID == args->callbackID)
+ break;
+ }
+ if (i == priv->nsecretEventCallbacks) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("node device event callback %d not registered"),
+ args->callbackID);
+ goto cleanup;
+ }
+
+ if (virConnectSecretEventDeregisterAny(priv->conn, args->callbackID) < 0)
+ goto cleanup;
+
+ VIR_DELETE_ELEMENT(priv->secretEventCallbacks, i,
+ priv->nsecretEventCallbacks);
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+static int
+qemuDispatchConnectDomainMonitorEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ qemu_connect_domain_monitor_event_register_args *args,
+ qemu_connect_domain_monitor_event_register_ret *ret)
+{
+ int callbackID;
+ int rv = -1;
+ daemonClientEventCallbackPtr callback = NULL;
+ daemonClientEventCallbackPtr ref;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+ virDomainPtr dom = NULL;
+ const char *event = args->event ? *args->event : NULL;
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ if (args->dom &&
+ !(dom = get_nonnull_domain(priv->conn, *args->dom)))
+ goto cleanup;
+
+ /* If we call register first, we could append a complete callback
+ * to our array, but on OOM append failure, we'd have to then hope
+ * deregister works to undo our register. So instead we append an
+ * incomplete callback to our array, then register, then fix up
+ * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
+ * success, we use 'ref' to save a copy of the pointer. */
+ if (VIR_ALLOC(callback) < 0)
+ goto cleanup;
+ callback->client = virObjectRef(client);
+ callback->callbackID = -1;
+ ref = callback;
+ if (VIR_APPEND_ELEMENT(priv->qemuEventCallbacks,
+ priv->nqemuEventCallbacks,
+ callback) < 0)
+ goto cleanup;
+
+ if ((callbackID = virConnectDomainQemuMonitorEventRegister(priv->conn,
+ dom,
+ event,
+ remoteRelayDomainQemuMonitorEvent,
+ ref,
+ remoteEventCallbackFree,
+ args->flags)) < 0) {
+ VIR_SHRINK_N(priv->qemuEventCallbacks,
+ priv->nqemuEventCallbacks, 1);
+ callback = ref;
+ goto cleanup;
+ }
+
+ ref->callbackID = callbackID;
+ ret->callbackID = callbackID;
+
+ rv = 0;
+
+ cleanup:
+ remoteEventCallbackFree(callback);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+
+static int
+qemuDispatchConnectDomainMonitorEventDeregister(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ qemu_connect_domain_monitor_event_deregister_args *args)
+{
+ int rv = -1;
+ size_t i;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ for (i = 0; i < priv->nqemuEventCallbacks; i++) {
+ if (priv->qemuEventCallbacks[i]->callbackID == args->callbackID)
+ break;
+ }
+ if (i == priv->nqemuEventCallbacks) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("qemu monitor event callback %d not registered"),
+ args->callbackID);
+ goto cleanup;
+ }
+
+ if (virConnectDomainQemuMonitorEventDeregister(priv->conn,
+ args->callbackID) < 0)
+ goto cleanup;
+
+ VIR_DELETE_ELEMENT(priv->qemuEventCallbacks, i,
+ priv->nqemuEventCallbacks);
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetTime(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_time_args *args,
+ remote_domain_get_time_ret *ret)
+{
+ int rv = -1;
+ virDomainPtr dom = NULL;
+ long long seconds;
+ unsigned int nseconds;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (virDomainGetTime(dom, &seconds, &nseconds, args->flags) < 0)
+ goto cleanup;
+
+ ret->seconds = seconds;
+ ret->nseconds = nseconds;
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dom);
+ return rv;
+}
+
+
+static int
+remoteDispatchNodeGetFreePages(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_node_get_free_pages_args *args,
+ remote_node_get_free_pages_ret *ret)
+{
+ int rv = -1;
+ int len;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (args->pages.pages_len * args->cellCount > REMOTE_NODE_MAX_CELLS) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("the result won't fit into REMOTE_NODE_MAX_CELLS"));
+ goto cleanup;
+ }
+
+ /* Allocate return buffer. */
+ if (VIR_ALLOC_N(ret->counts.counts_val,
+ args->pages.pages_len * args->cellCount) < 0)
+ goto cleanup;
+
+ if ((len = virNodeGetFreePages(priv->conn,
+ args->pages.pages_len,
+ args->pages.pages_val,
+ args->startCell,
+ args->cellCount,
+ (unsigned long long *) ret->counts.counts_val,
+ args->flags)) <= 0)
+ goto cleanup;
+
+ ret->counts.counts_len = len;
+ rv = 0;
+
+ cleanup:
+ if (rv < 0) {
+ virNetMessageSaveError(rerr);
+ VIR_FREE(ret->counts.counts_val);
+ }
+ return rv;
+}
+
+/* Copy contents of virNetworkDHCPLeasePtr to remote_network_dhcp_lease */
+static int
+remoteSerializeDHCPLease(remote_network_dhcp_lease *lease_dst, virNetworkDHCPLeasePtr lease_src)
+{
+ char **mac_tmp = NULL;
+ char **iaid_tmp = NULL;
+ char **hostname_tmp = NULL;
+ char **clientid_tmp = NULL;
+
+ lease_dst->expirytime = lease_src->expirytime;
+ lease_dst->type = lease_src->type;
+ lease_dst->prefix = lease_src->prefix;
+
+ if (VIR_STRDUP(lease_dst->iface, lease_src->iface) < 0 ||
+ VIR_STRDUP(lease_dst->ipaddr, lease_src->ipaddr) < 0)
+ goto error;
+
+ if (lease_src->mac) {
+ if (VIR_ALLOC(mac_tmp) < 0 ||
+ VIR_STRDUP(*mac_tmp, lease_src->mac) < 0)
+ goto error;
+ }
+ if (lease_src->iaid) {
+ if (VIR_ALLOC(iaid_tmp) < 0 ||
+ VIR_STRDUP(*iaid_tmp, lease_src->iaid) < 0)
+ goto error;
+ }
+ if (lease_src->hostname) {
+ if (VIR_ALLOC(hostname_tmp) < 0 ||
+ VIR_STRDUP(*hostname_tmp, lease_src->hostname) < 0)
+ goto error;
+ }
+ if (lease_src->clientid) {
+ if (VIR_ALLOC(clientid_tmp) < 0 ||
+ VIR_STRDUP(*clientid_tmp, lease_src->clientid) < 0)
+ goto error;
+ }
+
+ lease_dst->mac = mac_tmp;
+ lease_dst->iaid = iaid_tmp;
+ lease_dst->hostname = hostname_tmp;
+ lease_dst->clientid = clientid_tmp;
+
+ return 0;
+
+ error:
+ if (mac_tmp)
+ VIR_FREE(*mac_tmp);
+ if (iaid_tmp)
+ VIR_FREE(*iaid_tmp);
+ if (hostname_tmp)
+ VIR_FREE(*hostname_tmp);
+ if (clientid_tmp)
+ VIR_FREE(*clientid_tmp);
+ VIR_FREE(mac_tmp);
+ VIR_FREE(iaid_tmp);
+ VIR_FREE(hostname_tmp);
+ VIR_FREE(clientid_tmp);
+ VIR_FREE(lease_dst->ipaddr);
+ VIR_FREE(lease_dst->iface);
+ return -1;
+}
+
+
+static int
+remoteDispatchNetworkGetDHCPLeases(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_network_get_dhcp_leases_args *args,
+ remote_network_get_dhcp_leases_ret *ret)
+{
+ int rv = -1;
+ size_t i;
+ struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
+ virNetworkDHCPLeasePtr *leases = NULL;
+ virNetworkPtr net = NULL;
+ int nleases = 0;
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(net = get_nonnull_network(priv->conn, args->net)))
+ goto cleanup;
+
+ if ((nleases = virNetworkGetDHCPLeases(net,
+ args->mac ? *args->mac : NULL,
+ args->need_results ? &leases : NULL,
+ args->flags)) < 0)
+ goto cleanup;
+
+ if (nleases > REMOTE_NETWORK_DHCP_LEASES_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Number of leases is %d, which exceeds max limit: %d"),
+ nleases, REMOTE_NETWORK_DHCP_LEASES_MAX);
+ goto cleanup;
+ }
+
+ if (leases && nleases) {
+ if (VIR_ALLOC_N(ret->leases.leases_val, nleases) < 0)
+ goto cleanup;
+
+ ret->leases.leases_len = nleases;
+
+ for (i = 0; i < nleases; i++) {
+ if (remoteSerializeDHCPLease(ret->leases.leases_val + i, leases[i]) < 0)
+ goto cleanup;
+ }
+
+ } else {
+ ret->leases.leases_len = 0;
+ ret->leases.leases_val = NULL;
+ }
+
+ ret->ret = nleases;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ if (leases && nleases > 0)
+ for (i = 0; i < nleases; i++)
+ virNetworkDHCPLeaseFree(leases[i]);
+ VIR_FREE(leases);
+ virObjectUnref(net);
+ return rv;
+}
+
+
+static int
+remoteDispatchConnectGetAllDomainStats(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_connect_get_all_domain_stats_args *args,
+ remote_connect_get_all_domain_stats_ret *ret)
+{
+ int rv = -1;
+ size_t i;
+ struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
+ virDomainStatsRecordPtr *retStats = NULL;
+ int nrecords = 0;
+ virDomainPtr *doms = NULL;
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (args->doms.doms_len) {
+ if (VIR_ALLOC_N(doms, args->doms.doms_len + 1) < 0)
+ goto cleanup;
+
+ for (i = 0; i < args->doms.doms_len; i++) {
+ if (!(doms[i] = get_nonnull_domain(priv->conn, args->doms.doms_val[i])))
+ goto cleanup;
+ }
+
+ if ((nrecords = virDomainListGetStats(doms,
+ args->stats,
+ &retStats,
+ args->flags)) < 0)
+ goto cleanup;
+ } else {
+ if ((nrecords = virConnectGetAllDomainStats(priv->conn,
+ args->stats,
+ &retStats,
+ args->flags)) < 0)
+ goto cleanup;
+ }
+
+ if (nrecords > REMOTE_CONNECT_GET_ALL_DOMAIN_STATS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Number of domain stats records is %d, "
+ "which exceeds max limit: %d"),
+ nrecords, REMOTE_CONNECT_GET_ALL_DOMAIN_STATS_MAX);
+ goto cleanup;
+ }
+
+ if (nrecords) {
+ if (VIR_ALLOC_N(ret->retStats.retStats_val, nrecords) < 0)
+ goto cleanup;
+
+ ret->retStats.retStats_len = nrecords;
+
+ for (i = 0; i < nrecords; i++) {
+ remote_domain_stats_record *dst = ret->retStats.retStats_val + i;
+
+ make_nonnull_domain(&dst->dom, retStats[i]->dom);
+
+ if (virTypedParamsSerialize(retStats[i]->params,
+ retStats[i]->nparams,
+ (virTypedParameterRemotePtr *) &dst->params.params_val,
+ &dst->params.params_len,
+ VIR_TYPED_PARAM_STRING_OKAY) < 0)
+ goto cleanup;
+ }
+ } else {
+ ret->retStats.retStats_len = 0;
+ ret->retStats.retStats_val = NULL;
+ }
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+
+ virDomainStatsRecordListFree(retStats);
+ virObjectListFree(doms);
+
+ return rv;
+}
+
+
+static int
+remoteDispatchNodeAllocPages(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_node_alloc_pages_args *args,
+ remote_node_alloc_pages_ret *ret)
+{
+ int rv = -1;
+ int len;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if ((len = virNodeAllocPages(priv->conn,
+ args->pageSizes.pageSizes_len,
+ args->pageSizes.pageSizes_val,
+ (unsigned long long *) args->pageCounts.pageCounts_val,
+ args->startCell,
+ args->cellCount,
+ args->flags)) < 0)
+ goto cleanup;
+
+ ret->ret = len;
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ return rv;
+}
+
+
+static int
+remoteDispatchDomainGetFSInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_fsinfo_args *args,
+ remote_domain_get_fsinfo_ret *ret)
+{
+ int rv = -1;
+ size_t i, j;
+ struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
+ virDomainFSInfoPtr *info = NULL;
+ virDomainPtr dom = NULL;
+ remote_domain_fsinfo *dst;
+ int ninfo = 0;
+ size_t ndisk;
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if ((ninfo = virDomainGetFSInfo(dom, &info, args->flags)) < 0)
+ goto cleanup;
+
+ if (ninfo > REMOTE_DOMAIN_FSINFO_MAX) {
+ virReportError(VIR_ERR_RPC,
+ _("Too many mountpoints in fsinfo: %d for limit %d"),
+ ninfo, REMOTE_DOMAIN_FSINFO_MAX);
+ goto cleanup;
+ }
+
+ if (ninfo) {
+ if (VIR_ALLOC_N(ret->info.info_val, ninfo) < 0)
+ goto cleanup;
+
+ ret->info.info_len = ninfo;
+
+ for (i = 0; i < ninfo; i++) {
+ dst = &ret->info.info_val[i];
+ if (VIR_STRDUP(dst->mountpoint, info[i]->mountpoint) < 0)
+ goto cleanup;
+
+ if (VIR_STRDUP(dst->name, info[i]->name) < 0)
+ goto cleanup;
+
+ if (VIR_STRDUP(dst->fstype, info[i]->fstype) < 0)
+ goto cleanup;
+
+ ndisk = info[i]->ndevAlias;
+ if (ndisk > REMOTE_DOMAIN_FSINFO_DISKS_MAX) {
+ virReportError(VIR_ERR_RPC,
+ _("Too many disks in fsinfo: %zd for limit %d"),
+ ndisk, REMOTE_DOMAIN_FSINFO_DISKS_MAX);
+ goto cleanup;
+ }
+
+ if (ndisk > 0) {
+ if (VIR_ALLOC_N(dst->dev_aliases.dev_aliases_val, ndisk) < 0)
+ goto cleanup;
+
+ for (j = 0; j < ndisk; j++) {
+ if (VIR_STRDUP(dst->dev_aliases.dev_aliases_val[j],
+ info[i]->devAlias[j]) < 0)
+ goto cleanup;
+ }
+
+ dst->dev_aliases.dev_aliases_len = ndisk;
+ } else {
+ dst->dev_aliases.dev_aliases_val = NULL;
+ dst->dev_aliases.dev_aliases_len = 0;
+ }
+ }
+
+ } else {
+ ret->info.info_len = 0;
+ ret->info.info_val = NULL;
+ }
+
+ ret->ret = ninfo;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0) {
+ virNetMessageSaveError(rerr);
+
+ if (ret->info.info_val && ninfo > 0) {
+ for (i = 0; i < ninfo; i++) {
+ dst = &ret->info.info_val[i];
+ VIR_FREE(dst->mountpoint);
+ if (dst->dev_aliases.dev_aliases_val) {
+ for (j = 0; j < dst->dev_aliases.dev_aliases_len; j++)
+ VIR_FREE(dst->dev_aliases.dev_aliases_val[j]);
+ VIR_FREE(dst->dev_aliases.dev_aliases_val);
+ }
+ }
+ VIR_FREE(ret->info.info_val);
+ }
+ }
+ virObjectUnref(dom);
+ if (ninfo >= 0)
+ for (i = 0; i < ninfo; i++)
+ virDomainFSInfoFree(info[i]);
+ VIR_FREE(info);
+
+ return rv;
+}
+
+
+static int
+remoteSerializeDomainInterface(virDomainInterfacePtr *ifaces,
+ unsigned int ifaces_count,
+ remote_domain_interface_addresses_ret *ret)
+{
+ size_t i, j;
+
+ if (ifaces_count > REMOTE_DOMAIN_INTERFACE_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Number of interfaces, %d exceeds the max limit: %d"),
+ ifaces_count, REMOTE_DOMAIN_INTERFACE_MAX);
+ return -1;
+ }
+
+ if (VIR_ALLOC_N(ret->ifaces.ifaces_val, ifaces_count) < 0)
+ return -1;
+
+ ret->ifaces.ifaces_len = ifaces_count;
+
+ for (i = 0; i < ifaces_count; i++) {
+ virDomainInterfacePtr iface = ifaces[i];
+ remote_domain_interface *iface_ret = &(ret->ifaces.ifaces_val[i]);
+
+ if ((VIR_STRDUP(iface_ret->name, iface->name)) < 0)
+ goto cleanup;
+
+ if (iface->hwaddr &&
+ (VIR_ALLOC(iface_ret->hwaddr) < 0 ||
+ VIR_STRDUP(*iface_ret->hwaddr, iface->hwaddr) < 0))
+ goto cleanup;
+
+ if (iface->naddrs > REMOTE_DOMAIN_IP_ADDR_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Number of interfaces, %d exceeds the max limit: %d"),
+ iface->naddrs, REMOTE_DOMAIN_IP_ADDR_MAX);
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC_N(iface_ret->addrs.addrs_val,
+ iface->naddrs) < 0)
+ goto cleanup;
+
+ iface_ret->addrs.addrs_len = iface->naddrs;
+
+ for (j = 0; j < iface->naddrs; j++) {
+ virDomainIPAddressPtr ip_addr = &(iface->addrs[j]);
+ remote_domain_ip_addr *ip_addr_ret =
+ &(iface_ret->addrs.addrs_val[j]);
+
+ if (VIR_STRDUP(ip_addr_ret->addr, ip_addr->addr) < 0)
+ goto cleanup;
+
+ ip_addr_ret->prefix = ip_addr->prefix;
+ ip_addr_ret->type = ip_addr->type;
+ }
+ }
+
+ return 0;
+
+ cleanup:
+ if (ret->ifaces.ifaces_val) {
+ for (i = 0; i < ifaces_count; i++) {
+ remote_domain_interface *iface_ret = &(ret->ifaces.ifaces_val[i]);
+ VIR_FREE(iface_ret->name);
+ if (iface_ret->hwaddr) {
+ VIR_FREE(*iface_ret->hwaddr);
+ VIR_FREE(iface_ret->hwaddr);
+ }
+ for (j = 0; j < iface_ret->addrs.addrs_len; j++) {
+ remote_domain_ip_addr *ip_addr =
+ &(iface_ret->addrs.addrs_val[j]);
+ VIR_FREE(ip_addr->addr);
+ }
+ }
+ VIR_FREE(ret->ifaces.ifaces_val);
+ }
+
+ return -1;
+}
+
+
+static int
+remoteDispatchDomainInterfaceAddresses(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_interface_addresses_args *args,
+ remote_domain_interface_addresses_ret *ret)
+{
+ size_t i;
+ int rv = -1;
+ virDomainPtr dom = NULL;
+ virDomainInterfacePtr *ifaces = NULL;
+ int ifaces_count = 0;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if ((ifaces_count = virDomainInterfaceAddresses(dom, &ifaces, args->source, args->flags)) < 0)
+ goto cleanup;
+
+ if (remoteSerializeDomainInterface(ifaces, ifaces_count, ret) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+
+ virObjectUnref(dom);
+
+ if (ifaces && ifaces_count > 0) {
+ for (i = 0; i < ifaces_count; i++)
+ virDomainInterfaceFree(ifaces[i]);
+ }
+ VIR_FREE(ifaces);
+
+ return rv;
+}
+
+
+static int
+remoteDispatchStorageVolGetInfoFlags(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_storage_vol_get_info_flags_args *args,
+ remote_storage_vol_get_info_flags_ret *ret)
+{
+ int rv = -1;
+ virStorageVolPtr vol = NULL;
+ virStorageVolInfo tmp;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(vol = get_nonnull_storage_vol(priv->conn, args->vol)))
+ goto cleanup;
+
+ if (virStorageVolGetInfoFlags(vol, &tmp, args->flags) < 0)
+ goto cleanup;
+
+ ret->type = tmp.type;
+ ret->capacity = tmp.capacity;
+ ret->allocation = tmp.allocation;
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(vol);
+ return rv;
+}
+
+
+/*----- Helpers. -----*/
+
+/* get_nonnull_domain and get_nonnull_network turn an on-wire
+ * (name, uuid) pair into virDomainPtr or virNetworkPtr object.
+ * virDomainPtr or virNetworkPtr cannot be NULL.
+ *
+ * NB. If these return NULL then the caller must return an error.
+ */
+static virDomainPtr
+get_nonnull_domain(virConnectPtr conn, remote_nonnull_domain domain)
+{
+ /* Should we believe the domain.id sent by the client? Maybe
+ * this should be a check rather than an assignment? XXX
+ */
+ return virGetDomain(conn, domain.name, BAD_CAST domain.uuid, domain.id);
+}
+
+static virNetworkPtr
+get_nonnull_network(virConnectPtr conn, remote_nonnull_network network)
+{
+ return virGetNetwork(conn, network.name, BAD_CAST network.uuid);
+}
+
+static virInterfacePtr
+get_nonnull_interface(virConnectPtr conn, remote_nonnull_interface iface)
+{
+ return virGetInterface(conn, iface.name, iface.mac);
+}
+
+static virStoragePoolPtr
+get_nonnull_storage_pool(virConnectPtr conn, remote_nonnull_storage_pool pool)
+{
+ return virGetStoragePool(conn, pool.name, BAD_CAST pool.uuid,
+ NULL, NULL);
+}
+
+static virStorageVolPtr
+get_nonnull_storage_vol(virConnectPtr conn, remote_nonnull_storage_vol vol)
+{
+ virStorageVolPtr ret;
+ ret = virGetStorageVol(conn, vol.pool, vol.name, vol.key,
+ NULL, NULL);
+ return ret;
+}
+
+static virSecretPtr
+get_nonnull_secret(virConnectPtr conn, remote_nonnull_secret secret)
+{
+ return virGetSecret(conn, BAD_CAST secret.uuid, secret.usageType, secret.usageID);
+}
+
+static virNWFilterPtr
+get_nonnull_nwfilter(virConnectPtr conn, remote_nonnull_nwfilter nwfilter)
+{
+ return virGetNWFilter(conn, nwfilter.name, BAD_CAST nwfilter.uuid);
+}
+
+static virDomainSnapshotPtr
+get_nonnull_domain_snapshot(virDomainPtr dom, remote_nonnull_domain_snapshot snapshot)
+{
+ return virGetDomainSnapshot(dom, snapshot.name);
+}
+
+static virNodeDevicePtr
+get_nonnull_node_device(virConnectPtr conn, remote_nonnull_node_device dev)
+{
+ return virGetNodeDevice(conn, dev.name);
+}
+
+/* Make remote_nonnull_domain and remote_nonnull_network. */
+static void
+make_nonnull_domain(remote_nonnull_domain *dom_dst, virDomainPtr dom_src)
+{
+ dom_dst->id = dom_src->id;
+ ignore_value(VIR_STRDUP_QUIET(dom_dst->name, dom_src->name));
+ memcpy(dom_dst->uuid, dom_src->uuid, VIR_UUID_BUFLEN);
+}
+
+static void
+make_nonnull_network(remote_nonnull_network *net_dst, virNetworkPtr net_src)
+{
+ ignore_value(VIR_STRDUP_QUIET(net_dst->name, net_src->name));
+ memcpy(net_dst->uuid, net_src->uuid, VIR_UUID_BUFLEN);
+}
+
+static void
+make_nonnull_interface(remote_nonnull_interface *interface_dst,
+ virInterfacePtr interface_src)
+{
+ ignore_value(VIR_STRDUP_QUIET(interface_dst->name, interface_src->name));
+ ignore_value(VIR_STRDUP_QUIET(interface_dst->mac, interface_src->mac));
+}
+
+static void
+make_nonnull_storage_pool(remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr pool_src)
+{
+ ignore_value(VIR_STRDUP_QUIET(pool_dst->name, pool_src->name));
+ memcpy(pool_dst->uuid, pool_src->uuid, VIR_UUID_BUFLEN);
+}
+
+static void
+make_nonnull_storage_vol(remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src)
+{
+ ignore_value(VIR_STRDUP_QUIET(vol_dst->pool, vol_src->pool));
+ ignore_value(VIR_STRDUP_QUIET(vol_dst->name, vol_src->name));
+ ignore_value(VIR_STRDUP_QUIET(vol_dst->key, vol_src->key));
+}
+
+static void
+make_nonnull_node_device(remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src)
+{
+ ignore_value(VIR_STRDUP_QUIET(dev_dst->name, dev_src->name));
+}
+
+static void
+make_nonnull_secret(remote_nonnull_secret *secret_dst, virSecretPtr secret_src)
+{
+ memcpy(secret_dst->uuid, secret_src->uuid, VIR_UUID_BUFLEN);
+ secret_dst->usageType = secret_src->usageType;
+ ignore_value(VIR_STRDUP_QUIET(secret_dst->usageID, secret_src->usageID));
+}
+
+static void
+make_nonnull_nwfilter(remote_nonnull_nwfilter *nwfilter_dst, virNWFilterPtr nwfilter_src)
+{
+ ignore_value(VIR_STRDUP_QUIET(nwfilter_dst->name, nwfilter_src->name));
+ memcpy(nwfilter_dst->uuid, nwfilter_src->uuid, VIR_UUID_BUFLEN);
+}
+
+static void
+make_nonnull_domain_snapshot(remote_nonnull_domain_snapshot *snapshot_dst, virDomainSnapshotPtr snapshot_src)
+{
+ ignore_value(VIR_STRDUP_QUIET(snapshot_dst->name, snapshot_src->name));
+ make_nonnull_domain(&snapshot_dst->dom, snapshot_src->domain);
+}
+
+static int
+remoteSerializeDomainDiskErrors(virDomainDiskErrorPtr errors,
+ int nerrors,
+ remote_domain_disk_error **ret_errors_val,
+ u_int *ret_errors_len)
+{
+ remote_domain_disk_error *val = NULL;
+ size_t i = 0;
+
+ if (VIR_ALLOC_N(val, nerrors) < 0)
+ goto error;
+
+ for (i = 0; i < nerrors; i++) {
+ if (VIR_STRDUP(val[i].disk, errors[i].disk) < 0)
+ goto error;
+ val[i].error = errors[i].error;
+ }
+
+ *ret_errors_len = nerrors;
+ *ret_errors_val = val;
+
+ return 0;
+
+ error:
+ if (val) {
+ size_t j;
+ for (j = 0; j < i; j++)
+ VIR_FREE(val[j].disk);
+ VIR_FREE(val);
+ }
+ return -1;
+}
--- /dev/null
+/*
+ * remote_daemon_dispatch.h: handlers for RPC method calls
+ *
+ * Copyright (C) 2007-2018 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: Richard W.M. Jones <rjones@redhat.com>
+ * Author: Daniel P. Berrange <berrange@redhat.com>
+ */
+
+#ifndef __REMOTE_DAEMON_DISPATCH_H__
+# define __REMOTE_DAEMON_DISPATCH_H__
+
+# include "remote_protocol.h"
+# include "rpc/virnetserverprogram.h"
+# include "rpc/virnetserverclient.h"
+
+
+extern virNetServerProgramProc remoteProcs[];
+extern size_t remoteNProcs;
+
+extern virNetServerProgramProc lxcProcs[];
+extern size_t lxcNProcs;
+
+extern virNetServerProgramProc qemuProcs[];
+extern size_t qemuNProcs;
+
+void remoteClientFree(void *data);
+void *remoteClientNew(virNetServerClientPtr client,
+ void *opaque);
+
+#endif /* __REMOTE_DAEMON_DISPATCH_H__ */
--- /dev/null
+/*
+ * remote_daemon_stream.c: APIs for managing client streams
+ *
+ * Copyright (C) 2009-2018 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 "remote_daemon_stream.h"
+#include "remote_daemon_dispatch.h"
+#include "viralloc.h"
+#include "virlog.h"
+#include "virnetserverclient.h"
+#include "virerror.h"
+#include "libvirt_internal.h"
+
+#define VIR_FROM_THIS VIR_FROM_STREAMS
+
+VIR_LOG_INIT("daemon.stream");
+
+struct daemonClientStream {
+ daemonClientPrivatePtr priv;
+ int refs;
+
+ virNetServerProgramPtr prog;
+
+ virStreamPtr st;
+ int procedure;
+ unsigned int serial;
+
+ bool recvEOF;
+ bool closed;
+
+ int filterID;
+
+ virNetMessagePtr rx;
+ bool tx;
+
+ bool allowSkip;
+ size_t dataLen; /* How much data is there remaining until we see a hole */
+
+ daemonClientStreamPtr next;
+};
+
+static int
+daemonStreamHandleWrite(virNetServerClientPtr client,
+ daemonClientStream *stream);
+static int
+daemonStreamHandleRead(virNetServerClientPtr client,
+ daemonClientStream *stream);
+static int
+daemonStreamHandleFinish(virNetServerClientPtr client,
+ daemonClientStream *stream,
+ virNetMessagePtr msg);
+static int
+daemonStreamHandleAbort(virNetServerClientPtr client,
+ daemonClientStream *stream,
+ virNetMessagePtr msg);
+
+
+
+static void
+daemonStreamUpdateEvents(daemonClientStream *stream)
+{
+ int newEvents = 0;
+ if (stream->closed)
+ return;
+ if (stream->rx)
+ newEvents |= VIR_STREAM_EVENT_WRITABLE;
+ if (stream->tx && !stream->recvEOF)
+ newEvents |= VIR_STREAM_EVENT_READABLE;
+
+ virStreamEventUpdateCallback(stream->st, newEvents);
+}
+
+/*
+ * Invoked when an outgoing data packet message has been fully sent.
+ * This simply re-enables TX of further data.
+ *
+ * The idea is to stop the daemon growing without bound due to
+ * fast stream, but slow client
+ */
+static void
+daemonStreamMessageFinished(virNetMessagePtr msg,
+ void *opaque)
+{
+ daemonClientStream *stream = opaque;
+ VIR_DEBUG("stream=%p proc=%d serial=%u",
+ stream, msg->header.proc, msg->header.serial);
+
+ stream->tx = true;
+ daemonStreamUpdateEvents(stream);
+
+ daemonFreeClientStream(NULL, stream);
+}
+
+
+/*
+ * Callback that gets invoked when a stream becomes writable/readable
+ */
+static void
+daemonStreamEvent(virStreamPtr st, int events, void *opaque)
+{
+ virNetServerClientPtr client = opaque;
+ daemonClientStream *stream;
+ daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
+
+ virMutexLock(&priv->lock);
+
+ stream = priv->streams;
+ while (stream) {
+ if (stream->st == st)
+ break;
+ stream = stream->next;
+ }
+
+ if (!stream) {
+ VIR_WARN("event for client=%p stream st=%p, but missing stream state", client, st);
+ virStreamEventRemoveCallback(st);
+ goto cleanup;
+ }
+
+ VIR_DEBUG("st=%p events=%d EOF=%d closed=%d", st, events, stream->recvEOF, stream->closed);
+
+ if (!stream->closed &&
+ (events & VIR_STREAM_EVENT_WRITABLE)) {
+ if (daemonStreamHandleWrite(client, stream) < 0) {
+ daemonRemoveClientStream(client, stream);
+ virNetServerClientClose(client);
+ goto cleanup;
+ }
+ }
+
+ if (!stream->closed && !stream->recvEOF &&
+ (events & (VIR_STREAM_EVENT_READABLE))) {
+ events = events & ~(VIR_STREAM_EVENT_READABLE);
+ if (daemonStreamHandleRead(client, stream) < 0) {
+ daemonRemoveClientStream(client, stream);
+ virNetServerClientClose(client);
+ goto cleanup;
+ }
+ /* If we detected EOF during read processing,
+ * then clear hangup/error conditions, since
+ * we want the client to see the EOF message
+ * we just sent them
+ */
+ if (stream->recvEOF)
+ events = events & ~(VIR_STREAM_EVENT_HANGUP |
+ VIR_STREAM_EVENT_ERROR);
+ }
+
+ /* If we have a completion/abort message, always process it */
+ if (stream->rx) {
+ virNetMessagePtr msg = stream->rx;
+ switch (msg->header.status) {
+ case VIR_NET_CONTINUE:
+ /* nada */
+ break;
+ case VIR_NET_OK:
+ virNetMessageQueueServe(&stream->rx);
+ if (daemonStreamHandleFinish(client, stream, msg) < 0) {
+ virNetMessageFree(msg);
+ daemonRemoveClientStream(client, stream);
+ virNetServerClientClose(client);
+ goto cleanup;
+ }
+ break;
+ case VIR_NET_ERROR:
+ default:
+ virNetMessageQueueServe(&stream->rx);
+ if (daemonStreamHandleAbort(client, stream, msg) < 0) {
+ virNetMessageFree(msg);
+ daemonRemoveClientStream(client, stream);
+ virNetServerClientClose(client);
+ goto cleanup;
+ }
+ break;
+ }
+ }
+
+
+ /* If we got HANGUP, we need to only send an empty
+ * packet so the client sees an EOF and cleans up
+ */
+ if (!stream->closed && !stream->recvEOF &&
+ (events & VIR_STREAM_EVENT_HANGUP)) {
+ virNetMessagePtr msg;
+ events &= ~(VIR_STREAM_EVENT_HANGUP);
+ stream->tx = false;
+ stream->recvEOF = true;
+ if (!(msg = virNetMessageNew(false))) {
+ daemonRemoveClientStream(client, stream);
+ virNetServerClientClose(client);
+ goto cleanup;
+ }
+ msg->cb = daemonStreamMessageFinished;
+ msg->opaque = stream;
+ stream->refs++;
+ if (virNetServerProgramSendStreamData(remoteProgram,
+ client,
+ msg,
+ stream->procedure,
+ stream->serial,
+ "", 0) < 0) {
+ virNetMessageFree(msg);
+ daemonRemoveClientStream(client, stream);
+ virNetServerClientClose(client);
+ goto cleanup;
+ }
+ }
+
+ if (!stream->closed &&
+ (events & (VIR_STREAM_EVENT_ERROR | VIR_STREAM_EVENT_HANGUP))) {
+ int ret;
+ virNetMessagePtr msg;
+ virNetMessageError rerr;
+ virErrorPtr origErr = virSaveLastError();
+
+ memset(&rerr, 0, sizeof(rerr));
+ stream->closed = true;
+ virStreamEventRemoveCallback(stream->st);
+ virStreamAbort(stream->st);
+ if (origErr && origErr->code != VIR_ERR_OK) {
+ virSetError(origErr);
+ } else {
+ if (events & VIR_STREAM_EVENT_HANGUP)
+ virReportError(VIR_ERR_RPC,
+ "%s", _("stream had unexpected termination"));
+ else
+ virReportError(VIR_ERR_RPC,
+ "%s", _("stream had I/O failure"));
+ }
+ virFreeError(origErr);
+
+ msg = virNetMessageNew(false);
+ if (!msg) {
+ ret = -1;
+ } else {
+ ret = virNetServerProgramSendStreamError(remoteProgram,
+ client,
+ msg,
+ &rerr,
+ stream->procedure,
+ stream->serial);
+ }
+ daemonRemoveClientStream(client, stream);
+ if (ret < 0)
+ virNetServerClientClose(client);
+ goto cleanup;
+ }
+
+ if (stream->closed) {
+ daemonRemoveClientStream(client, stream);
+ } else {
+ daemonStreamUpdateEvents(stream);
+ }
+
+ cleanup:
+ virMutexUnlock(&priv->lock);
+}
+
+
+/*
+ * @client: a locked client object
+ *
+ * Invoked by the main loop when filtering incoming messages.
+ *
+ * Returns 1 if the message was processed, 0 if skipped,
+ * -1 on fatal client error
+ */
+static int
+daemonStreamFilter(virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg,
+ void *opaque)
+{
+ daemonClientStream *stream = opaque;
+ int ret = 0;
+
+ virMutexLock(&stream->priv->lock);
+
+ if (msg->header.type != VIR_NET_STREAM &&
+ msg->header.type != VIR_NET_STREAM_HOLE)
+ goto cleanup;
+
+ if (!virNetServerProgramMatches(stream->prog, msg))
+ goto cleanup;
+
+ if (msg->header.proc != stream->procedure ||
+ msg->header.serial != stream->serial)
+ goto cleanup;
+
+ VIR_DEBUG("Incoming client=%p, rx=%p, serial=%u, proc=%d, status=%d",
+ client, stream->rx, msg->header.proc,
+ msg->header.serial, msg->header.status);
+
+ virNetMessageQueuePush(&stream->rx, msg);
+ daemonStreamUpdateEvents(stream);
+ ret = 1;
+
+ cleanup:
+ virMutexUnlock(&stream->priv->lock);
+ return ret;
+}
+
+
+/*
+ * @conn: a connection object to associate the stream with
+ * @header: the method call to associate with the stream
+ *
+ * Creates a new stream for this conn
+ *
+ * Returns a new stream object, or NULL upon OOM
+ */
+daemonClientStream *
+daemonCreateClientStream(virNetServerClientPtr client,
+ virStreamPtr st,
+ virNetServerProgramPtr prog,
+ virNetMessageHeaderPtr header,
+ bool allowSkip)
+{
+ daemonClientStream *stream;
+ daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
+
+ VIR_DEBUG("client=%p, proc=%d, serial=%u, st=%p",
+ client, header->proc, header->serial, st);
+
+ if (VIR_ALLOC(stream) < 0)
+ return NULL;
+
+ stream->refs = 1;
+ stream->priv = priv;
+ stream->prog = virObjectRef(prog);
+ stream->procedure = header->proc;
+ stream->serial = header->serial;
+ stream->filterID = -1;
+ stream->st = st;
+ stream->allowSkip = allowSkip;
+
+ return stream;
+}
+
+/*
+ * @stream: an unused client stream
+ *
+ * Frees the memory associated with this inactive client
+ * stream
+ */
+int daemonFreeClientStream(virNetServerClientPtr client,
+ daemonClientStream *stream)
+{
+ virNetMessagePtr msg;
+ int ret = 0;
+
+ if (!stream)
+ return 0;
+
+ stream->refs--;
+ if (stream->refs)
+ return 0;
+
+ VIR_DEBUG("client=%p, proc=%d, serial=%u",
+ client, stream->procedure, stream->serial);
+
+ virObjectUnref(stream->prog);
+
+ msg = stream->rx;
+ while (msg) {
+ virNetMessagePtr tmp = msg->next;
+ if (client) {
+ /* Send a dummy reply to free up 'msg' & unblock client rx */
+ virNetMessageClear(msg);
+ msg->header.type = VIR_NET_REPLY;
+ if (virNetServerClientSendMessage(client, msg) < 0) {
+ virNetServerClientImmediateClose(client);
+ virNetMessageFree(msg);
+ ret = -1;
+ }
+ } else {
+ virNetMessageFree(msg);
+ }
+ msg = tmp;
+ }
+
+ virObjectUnref(stream->st);
+ VIR_FREE(stream);
+
+ return ret;
+}
+
+
+/*
+ * @client: a locked client to add the stream to
+ * @stream: a stream to add
+ */
+int daemonAddClientStream(virNetServerClientPtr client,
+ daemonClientStream *stream,
+ bool transmit)
+{
+ VIR_DEBUG("client=%p, proc=%d, serial=%u, st=%p, transmit=%d",
+ client, stream->procedure, stream->serial, stream->st, transmit);
+ daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
+
+ if (stream->filterID != -1) {
+ VIR_WARN("Filter already added to client %p", client);
+ return -1;
+ }
+
+ if (virStreamEventAddCallback(stream->st, 0,
+ daemonStreamEvent, client,
+ virObjectFreeCallback) < 0)
+ return -1;
+
+ virObjectRef(client);
+
+ if ((stream->filterID = virNetServerClientAddFilter(client,
+ daemonStreamFilter,
+ stream)) < 0) {
+ virStreamEventRemoveCallback(stream->st);
+ return -1;
+ }
+
+ if (transmit)
+ stream->tx = true;
+
+ virMutexLock(&priv->lock);
+ stream->next = priv->streams;
+ priv->streams = stream;
+
+ daemonStreamUpdateEvents(stream);
+
+ virMutexUnlock(&priv->lock);
+
+ return 0;
+}
+
+
+/*
+ * @client: a locked client object
+ * @stream: an inactive, closed stream object
+ *
+ * Removes a stream from the list of active streams for the client
+ *
+ * Returns 0 if the stream was removed, -1 if it doesn't exist
+ */
+int
+daemonRemoveClientStream(virNetServerClientPtr client,
+ daemonClientStream *stream)
+{
+ VIR_DEBUG("client=%p, proc=%d, serial=%u, st=%p",
+ client, stream->procedure, stream->serial, stream->st);
+ daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
+ daemonClientStream *curr = priv->streams;
+ daemonClientStream *prev = NULL;
+
+ if (stream->filterID != -1) {
+ virNetServerClientRemoveFilter(client,
+ stream->filterID);
+ stream->filterID = -1;
+ }
+
+ if (!stream->closed) {
+ stream->closed = true;
+ virStreamEventRemoveCallback(stream->st);
+ virStreamAbort(stream->st);
+ }
+
+ while (curr) {
+ if (curr == stream) {
+ if (prev)
+ prev->next = curr->next;
+ else
+ priv->streams = curr->next;
+ return daemonFreeClientStream(client, stream);
+ }
+ prev = curr;
+ curr = curr->next;
+ }
+ return -1;
+}
+
+
+void
+daemonRemoveAllClientStreams(daemonClientStream *stream)
+{
+ daemonClientStream *tmp;
+
+ VIR_DEBUG("stream=%p", stream);
+
+ while (stream) {
+ tmp = stream->next;
+
+ if (!stream->closed) {
+ stream->closed = true;
+ virStreamEventRemoveCallback(stream->st);
+ virStreamAbort(stream->st);
+ }
+
+ daemonFreeClientStream(NULL, stream);
+
+ VIR_DEBUG("next stream=%p", tmp);
+ stream = tmp;
+ }
+}
+
+/*
+ * Returns:
+ * -1 if fatal error occurred
+ * 0 if message was fully processed
+ * 1 if message is still being processed
+ */
+static int
+daemonStreamHandleWriteData(virNetServerClientPtr client,
+ daemonClientStream *stream,
+ virNetMessagePtr msg)
+{
+ int ret;
+
+ VIR_DEBUG("client=%p, stream=%p, proc=%d, serial=%u, len=%zu, offset=%zu",
+ client, stream, msg->header.proc, msg->header.serial,
+ msg->bufferLength, msg->bufferOffset);
+
+ ret = virStreamSend(stream->st,
+ msg->buffer + msg->bufferOffset,
+ msg->bufferLength - msg->bufferOffset);
+
+ if (ret > 0) {
+ msg->bufferOffset += ret;
+
+ /* Partial write, so indicate we have more todo later */
+ if (msg->bufferOffset < msg->bufferLength)
+ return 1;
+ } else if (ret == -2) {
+ /* Blocking, so indicate we have more todo later */
+ return 1;
+ } else {
+ virNetMessageError rerr;
+
+ memset(&rerr, 0, sizeof(rerr));
+
+ VIR_INFO("Stream send failed");
+ stream->closed = true;
+ virStreamEventRemoveCallback(stream->st);
+ virStreamAbort(stream->st);
+
+ return virNetServerProgramSendReplyError(stream->prog,
+ client,
+ msg,
+ &rerr,
+ &msg->header);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Process a finish handshake from the client.
+ *
+ * Returns a VIR_NET_OK confirmation if successful, or a VIR_NET_ERROR
+ * if there was a stream error
+ *
+ * Returns 0 if successfully sent RPC reply, -1 upon fatal error
+ */
+static int
+daemonStreamHandleFinish(virNetServerClientPtr client,
+ daemonClientStream *stream,
+ virNetMessagePtr msg)
+{
+ int ret;
+
+ VIR_DEBUG("client=%p, stream=%p, proc=%d, serial=%u",
+ client, stream, msg->header.proc, msg->header.serial);
+
+ stream->closed = true;
+ virStreamEventRemoveCallback(stream->st);
+ ret = virStreamFinish(stream->st);
+
+ if (ret < 0) {
+ virNetMessageError rerr;
+ memset(&rerr, 0, sizeof(rerr));
+ return virNetServerProgramSendReplyError(stream->prog,
+ client,
+ msg,
+ &rerr,
+ &msg->header);
+ } else {
+ /* Send zero-length confirm */
+ return virNetServerProgramSendStreamData(stream->prog,
+ client,
+ msg,
+ stream->procedure,
+ stream->serial,
+ NULL, 0);
+ }
+}
+
+
+/*
+ * Process an abort request from the client.
+ *
+ * Returns 0 if successfully aborted, -1 upon error
+ */
+static int
+daemonStreamHandleAbort(virNetServerClientPtr client,
+ daemonClientStream *stream,
+ virNetMessagePtr msg)
+{
+ VIR_DEBUG("client=%p, stream=%p, proc=%d, serial=%u",
+ client, stream, msg->header.proc, msg->header.serial);
+ int ret;
+ bool raise_error = false;
+
+ stream->closed = true;
+ virStreamEventRemoveCallback(stream->st);
+ ret = virStreamAbort(stream->st);
+
+ if (msg->header.status == VIR_NET_ERROR) {
+ VIR_INFO("stream aborted at client request");
+ raise_error = (ret < 0);
+ } else {
+ virReportError(VIR_ERR_RPC,
+ _("stream aborted with unexpected status %d"),
+ msg->header.status);
+ raise_error = true;
+ }
+
+ if (raise_error) {
+ virNetMessageError rerr;
+ memset(&rerr, 0, sizeof(rerr));
+ return virNetServerProgramSendReplyError(remoteProgram,
+ client,
+ msg,
+ &rerr,
+ &msg->header);
+ } else {
+ /* Send zero-length confirm */
+ return virNetServerProgramSendStreamData(stream->prog,
+ client,
+ msg,
+ stream->procedure,
+ stream->serial,
+ NULL, 0);
+ }
+}
+
+
+static int
+daemonStreamHandleHole(virNetServerClientPtr client,
+ daemonClientStream *stream,
+ virNetMessagePtr msg)
+{
+ int ret;
+ virNetStreamHole data;
+
+ VIR_DEBUG("client=%p, stream=%p, proc=%d, serial=%u",
+ client, stream, msg->header.proc, msg->header.serial);
+
+ /* Let's check if client plays nicely and advertised usage of
+ * sparse stream upfront. */
+ if (!stream->allowSkip) {
+ virReportError(VIR_ERR_RPC, "%s",
+ _("Unexpected stream hole"));
+ return -1;
+ }
+
+ if (virNetMessageDecodePayload(msg,
+ (xdrproc_t) xdr_virNetStreamHole,
+ &data) < 0)
+ return -1;
+
+ ret = virStreamSendHole(stream->st, data.length, data.flags);
+
+ if (ret < 0) {
+ virNetMessageError rerr;
+
+ memset(&rerr, 0, sizeof(rerr));
+
+ VIR_INFO("Stream send hole failed");
+ stream->closed = true;
+ virStreamEventRemoveCallback(stream->st);
+ virStreamAbort(stream->st);
+
+ return virNetServerProgramSendReplyError(stream->prog,
+ client,
+ msg,
+ &rerr,
+ &msg->header);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Called when the stream is signalled has being able to accept
+ * data writes. Will process all pending incoming messages
+ * until they're all gone, or I/O blocks
+ *
+ * Returns 0 on success, or -1 upon fatal error
+ */
+static int
+daemonStreamHandleWrite(virNetServerClientPtr client,
+ daemonClientStream *stream)
+{
+ VIR_DEBUG("client=%p, stream=%p", client, stream);
+
+ while (stream->rx && !stream->closed) {
+ virNetMessagePtr msg = stream->rx;
+ int ret;
+
+ if (msg->header.type == VIR_NET_STREAM_HOLE) {
+ /* Handle special case when the client sent us a hole.
+ * Otherwise just carry on with processing stream
+ * data. */
+ ret = daemonStreamHandleHole(client, stream, msg);
+ } else if (msg->header.type == VIR_NET_STREAM) {
+ switch (msg->header.status) {
+ case VIR_NET_OK:
+ ret = daemonStreamHandleFinish(client, stream, msg);
+ break;
+
+ case VIR_NET_CONTINUE:
+ ret = daemonStreamHandleWriteData(client, stream, msg);
+ break;
+
+ case VIR_NET_ERROR:
+ default:
+ ret = daemonStreamHandleAbort(client, stream, msg);
+ break;
+ }
+ } else {
+ virReportError(VIR_ERR_RPC,
+ _("Unexpected message type: %d"),
+ msg->header.type);
+ ret = -1;
+ }
+
+ if (ret > 0)
+ break; /* still processing data from msg */
+
+ virNetMessageQueueServe(&stream->rx);
+ if (ret < 0) {
+ virNetMessageFree(msg);
+ virNetServerClientImmediateClose(client);
+ return -1;
+ }
+
+ /* 'CONTINUE' messages don't send a reply (unless error
+ * occurred), so to release the 'msg' object we need to
+ * send a fake zero-length reply. Nothing actually gets
+ * onto the wire, but this causes the client to reset
+ * its active request count / throttling
+ */
+ if (msg->header.status == VIR_NET_CONTINUE) {
+ virNetMessageClear(msg);
+ msg->header.type = VIR_NET_REPLY;
+ if (virNetServerClientSendMessage(client, msg) < 0) {
+ virNetMessageFree(msg);
+ virNetServerClientImmediateClose(client);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * Invoked when a stream is signalled as having data
+ * available to read. This reads up to one message
+ * worth of data, and then queues that for transmission
+ * to the client.
+ *
+ * Returns 0 if data was queued for TX, or an error RPC
+ * was sent, or -1 on fatal error, indicating client should
+ * be killed
+ */
+static int
+daemonStreamHandleRead(virNetServerClientPtr client,
+ daemonClientStream *stream)
+{
+ virNetMessagePtr msg = NULL;
+ virNetMessageError rerr;
+ char *buffer;
+ size_t bufferLen = VIR_NET_MESSAGE_LEGACY_PAYLOAD_MAX;
+ int ret = -1;
+ int rv;
+ int inData = 0;
+ long long length = 0;
+
+ VIR_DEBUG("client=%p, stream=%p tx=%d closed=%d",
+ client, stream, stream->tx, stream->closed);
+
+ /* We might have had an event pending before we shut
+ * down the stream, so if we're marked as closed,
+ * then do nothing
+ */
+ if (stream->closed)
+ return 0;
+
+ /* Shouldn't ever be called unless we're marked able to
+ * transmit, but doesn't hurt to check */
+ if (!stream->tx)
+ return 0;
+
+ memset(&rerr, 0, sizeof(rerr));
+
+ if (VIR_ALLOC_N(buffer, bufferLen) < 0)
+ return -1;
+
+ if (!(msg = virNetMessageNew(false)))
+ goto cleanup;
+
+ if (stream->allowSkip && stream->dataLen == 0) {
+ /* Handle skip. We want to send some data to the client. But we might
+ * be in a hole. Seek to next data. But if we are in data already, just
+ * carry on. */
+
+ rv = virStreamInData(stream->st, &inData, &length);
+ VIR_DEBUG("rv=%d inData=%d length=%lld", rv, inData, length);
+
+ if (rv < 0) {
+ if (virNetServerProgramSendStreamError(remoteProgram,
+ client,
+ msg,
+ &rerr,
+ stream->procedure,
+ stream->serial) < 0)
+ goto cleanup;
+ msg = NULL;
+
+ /* We're done with this call */
+ goto done;
+ } else {
+ if (!inData && length) {
+ stream->tx = false;
+ msg->cb = daemonStreamMessageFinished;
+ msg->opaque = stream;
+ stream->refs++;
+ if (virNetServerProgramSendStreamHole(remoteProgram,
+ client,
+ msg,
+ stream->procedure,
+ stream->serial,
+ length,
+ 0) < 0)
+ goto cleanup;
+
+ msg = NULL;
+
+ /* We have successfully sent stream skip to the other side.
+ * To keep streams in sync seek locally too. */
+ virStreamSendHole(stream->st, length, 0);
+ /* We're done with this call */
+ goto done;
+ }
+ }
+
+ stream->dataLen = length;
+ }
+
+ if (stream->allowSkip &&
+ bufferLen > stream->dataLen)
+ bufferLen = stream->dataLen;
+
+ rv = virStreamRecv(stream->st, buffer, bufferLen);
+ if (rv == -2) {
+ /* Should never get this, since we're only called when we know
+ * we're readable, but hey things change... */
+ } else if (rv < 0) {
+ if (virNetServerProgramSendStreamError(remoteProgram,
+ client,
+ msg,
+ &rerr,
+ stream->procedure,
+ stream->serial) < 0)
+ goto cleanup;
+ msg = NULL;
+ } else {
+ if (stream->allowSkip)
+ stream->dataLen -= rv;
+
+ stream->tx = false;
+ if (rv == 0)
+ stream->recvEOF = true;
+
+ msg->cb = daemonStreamMessageFinished;
+ msg->opaque = stream;
+ stream->refs++;
+ if (virNetServerProgramSendStreamData(remoteProgram,
+ client,
+ msg,
+ stream->procedure,
+ stream->serial,
+ buffer, rv) < 0)
+ goto cleanup;
+ msg = NULL;
+ }
+
+ done:
+ ret = 0;
+ cleanup:
+ VIR_FREE(buffer);
+ virNetMessageFree(msg);
+ return ret;
+}
--- /dev/null
+/*
+ * remote_daemon_stream.h: APIs for managing client streams
+ *
+ * Copyright (C) 2009-2018 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 __REMOTE_DAEMON_STREAM_H__
+# define __REMOTE_DAEMON_STREAM_H__
+
+# include "remote_daemon.h"
+
+daemonClientStream *
+daemonCreateClientStream(virNetServerClientPtr client,
+ virStreamPtr st,
+ virNetServerProgramPtr prog,
+ virNetMessageHeaderPtr hdr,
+ bool allowSkip);
+
+int daemonFreeClientStream(virNetServerClientPtr client,
+ daemonClientStream *stream);
+
+int daemonAddClientStream(virNetServerClientPtr client,
+ daemonClientStream *stream,
+ bool transmit);
+
+int
+daemonRemoveClientStream(virNetServerClientPtr client,
+ daemonClientStream *stream);
+
+void
+daemonRemoveAllClientStreams(daemonClientStream *stream);
+
+#endif /* __REMOTE_DAEMON_STREAM_H__ */