diff --git a/Makefile.am b/Makefile.am index 4aafe946cb..9796069c8d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -40,6 +40,7 @@ EXTRA_DIST = \ libvirt.pc.in \ libvirt-qemu.pc.in \ libvirt-lxc.pc.in \ + libvirt-admin.pc.in \ autobuild.sh \ Makefile.nonreentrant \ autogen.sh \ @@ -49,7 +50,7 @@ EXTRA_DIST = \ $(XML_EXAMPLES) pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libvirt.pc libvirt-qemu.pc libvirt-lxc.pc +pkgconfig_DATA = libvirt.pc libvirt-qemu.pc libvirt-lxc.pc libvirt-admin.pc NEWS: $(top_srcdir)/docs/news.xsl $(top_srcdir)/docs/news.html.in $(AM_V_GEN)if [ -x $(XSLTPROC) ] ; then \ diff --git a/cfg.mk b/cfg.mk index ce13f0ec8b..f1b50242c6 100644 --- a/cfg.mk +++ b/cfg.mk @@ -304,6 +304,7 @@ sc_flags_usage: $(srcdir)/include/libvirt/virterror.h \ $(srcdir)/include/libvirt/libvirt-qemu.h \ $(srcdir)/include/libvirt/libvirt-lxc.h \ + $(srcdir)/include/libvirt/libvirt-admin.h \ | grep -c '\(long\|unsigned\) flags')" != 4 && \ { echo '$(ME): new API should use "unsigned int flags"' 1>&2; \ exit 1; } || : diff --git a/configure.ac b/configure.ac index 073624bde8..94f622f1ad 100644 --- a/configure.ac +++ b/configure.ac @@ -825,7 +825,6 @@ if test "$with_libvirtd" = "yes" ; then fi AM_CONDITIONAL([WITH_LIBVIRTD], [test "$with_libvirtd" = "yes"]) - old_LIBS="$LIBS" old_CFLAGS="$CFLAGS" LIBXENSERVER_LIBS="" @@ -2353,6 +2352,7 @@ WIN32_EXTRA_CFLAGS= dnl libvirt.syms is generated in builddir, but libvirt_qemu.syms is in git; dnl hence the asymmetric naming of these two symbol files. LIBVIRT_SYMBOL_FILE=libvirt.syms +LIBVIRT_ADMIN_SYMBOL_FILE='$(srcdir)/libvirt_admin.syms' LIBVIRT_LXC_SYMBOL_FILE='$(srcdir)/libvirt_lxc.syms' LIBVIRT_QEMU_SYMBOL_FILE='$(srcdir)/libvirt_qemu.syms' MSCOM_LIBS= @@ -2383,6 +2383,7 @@ case "$host" in # Also set the symbol file to .def, so src/Makefile generates libvirt.def # from libvirt.syms and passes libvirt.def instead of libvirt.syms to the linker LIBVIRT_SYMBOL_FILE=libvirt.def + LIBVIRT_ADMIN_SYMBOL_FILE=libvirt_admin.def LIBVIRT_LXC_SYMBOL_FILE=libvirt_lxc.def LIBVIRT_QEMU_SYMBOL_FILE=libvirt_qemu.def # mingw's ld has the --version-script parameter, but it requires a .def file @@ -2398,6 +2399,7 @@ AC_SUBST([CYGWIN_EXTRA_LIBADD]) AC_SUBST([MINGW_EXTRA_LDFLAGS]) AC_SUBST([WIN32_EXTRA_CFLAGS]) AC_SUBST([LIBVIRT_SYMBOL_FILE]) +AC_SUBST([LIBVIRT_ADMIN_SYMBOL_FILE]) AC_SUBST([LIBVIRT_LXC_SYMBOL_FILE]) AC_SUBST([LIBVIRT_QEMU_SYMBOL_FILE]) AC_SUBST([VERSION_SCRIPT_FLAGS]) @@ -2788,6 +2790,7 @@ AC_CONFIG_FILES([\ libvirt.pc \ libvirt-qemu.pc \ libvirt-lxc.pc \ + libvirt-admin.pc \ src/libvirt.pc \ src/libvirt-qemu.pc \ src/libvirt-lxc.pc \ diff --git a/include/libvirt/Makefile.am b/include/libvirt/Makefile.am index 8aee5d70d2..2b64b0db2a 100644 --- a/include/libvirt/Makefile.am +++ b/include/libvirt/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in -## Copyright (C) 2005-2011, 2013 Red Hat, Inc. +## Copyright (C) 2005-2011, 2013-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 @@ -34,6 +34,8 @@ virinc_HEADERS = libvirt.h \ libvirt-qemu.h \ virterror.h +virinc_HEADERS += libvirt-admin.h + install-exec-hook: $(mkinstalldirs) $(DESTDIR)$(virincdir) diff --git a/include/libvirt/libvirt-admin.h b/include/libvirt/libvirt-admin.h new file mode 100644 index 0000000000..b3cfc93fcb --- /dev/null +++ b/include/libvirt/libvirt-admin.h @@ -0,0 +1,62 @@ +/* + * libvirt-admin.h: Admin interface for libvirt + * Summary: Interfaces for handling server-related tasks + * Description: Provides the interfaces of the libvirt library to operate + * with the server itself, not any hypervisors. + * + * Copyright (C) 2014-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 + * . + * + * Author: Martin Kletzander + */ + +#ifndef __VIR_ADMIN_H__ +# define __VIR_ADMIN_H__ + +# include "internal.h" + +# ifdef __cplusplus +extern "C" { +# endif + + +/** + * virAdmConnect: + * + * a virAdmConnect is a private structure representing a connection to + * libvirt daemon. + */ +typedef struct _virAdmConnect virAdmConnect; + +/** + * virAdmConnectPtr: + * + * a virAdmConnectPtr is pointer to a virAdmConnect private structure, + * this is the type used to reference a connection to the daemon + * in the API. + */ +typedef virAdmConnect *virAdmConnectPtr; + +virAdmConnectPtr virAdmConnectOpen(const char *name, unsigned int flags); +int virAdmConnectClose(virAdmConnectPtr conn); + +int virAdmConnectRef(virAdmConnectPtr conn); + +# ifdef __cplusplus +} +# endif + +#endif /* __VIR_ADMIN_H__ */ diff --git a/libvirt-admin.pc.in b/libvirt-admin.pc.in new file mode 100644 index 0000000000..76126aefc1 --- /dev/null +++ b/libvirt-admin.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +datarootdir=@datarootdir@ + +libvirt_admin_api=@datadir@/libvirt/api/libvirt-admin-api.xml + +Name: libvirt-admin +Version: @VERSION@ +Description: libvirt admin library +Libs: -L${libdir} -lvirt-admin +Cflags: -I${includedir} diff --git a/libvirt.spec.in b/libvirt.spec.in index f16e0e51ff..9baf5ef7b4 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -1216,6 +1216,16 @@ Includes the Sanlock lock manager plugin for the QEMU driver %endif +%package admin +Summary: Client side library and binary for the libvirt admin interface +Group: Development/Libraries +Requires: readline +Requires: %{name}-client = %{version}-%{release} + +%description admin +Shared library and client for admin access to libvirt daemon + + %prep %setup -q @@ -2209,6 +2219,12 @@ exit 0 %attr(0755, root, root) %{_libexecdir}/libvirt_sanlock_helper %endif +%files admin +%defattr(-, root, root) +%{_mandir}/man1/virt-admin.1* +%{_bindir}/virt-admin +%{_libdir}/libvirt-admin.so.* + %files client -f %{name}.lang %defattr(-, root, root) %doc COPYING COPYING.LESSER @@ -2285,6 +2301,7 @@ exit 0 %{_libdir}/libvirt.so %{_libdir}/libvirt-qemu.so %{_libdir}/libvirt-lxc.so +%{_libdir}/libvirt-admin.so %dir %{_includedir}/libvirt %{_includedir}/libvirt/virterror.h %{_includedir}/libvirt/libvirt.h @@ -2301,15 +2318,18 @@ exit 0 %{_includedir}/libvirt/libvirt-stream.h %{_includedir}/libvirt/libvirt-qemu.h %{_includedir}/libvirt/libvirt-lxc.h +%{_includedir}/libvirt/libvirt-admin.h %{_libdir}/pkgconfig/libvirt.pc %{_libdir}/pkgconfig/libvirt-qemu.pc %{_libdir}/pkgconfig/libvirt-lxc.pc +%{_libdir}/pkgconfig/libvirt-admin.pc %dir %{_datadir}/libvirt/api/ %{_datadir}/libvirt/api/libvirt-api.xml %{_datadir}/libvirt/api/libvirt-qemu-api.xml %{_datadir}/libvirt/api/libvirt-lxc-api.xml + %doc docs/*.html docs/html docs/*.gif %doc docs/libvirt-api.xml %doc examples/hellolibvirt diff --git a/po/POTFILES.in b/po/POTFILES.in index ebb0482584..4afa2f9208 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -59,6 +59,7 @@ src/interface/interface_backend_netcf.c src/interface/interface_backend_udev.c src/internal.h src/libvirt.c +src/libvirt-admin.c src/libvirt-domain.c src/libvirt-domain-snapshot.c src/libvirt-host.c diff --git a/src/Makefile.am b/src/Makefile.am index ce8d8fa229..1e1b841ca9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -503,6 +503,7 @@ PROTOCOL_STRUCTS = \ $(srcdir)/virkeepaliveprotocol-structs \ $(srcdir)/lxc_monitor_protocol-structs \ $(srcdir)/lock_protocol-structs \ + $(srcdir)/admin_protocol-structs \ $(NULL) if WITH_REMOTE @@ -524,6 +525,9 @@ $(srcdir)/lxc_monitor_protocol-struct: \ $(srcdir)/lock_protocol-struct: \ $(srcdir)/%-struct: locking/lockd_la-%.lo $(PDWTAGS) +$(srcdir)/admin_protocol-struct: \ + $(srcdir)/%-struct: admin/libvirt_admin_la-%.lo + $(PDWTAGS) else !WITH_REMOTE # The $(PROTOCOL_STRUCTS) files must live in git, because they cannot be @@ -536,6 +540,7 @@ check-drivername: $(AM_V_GEN)$(PERL) $(srcdir)/check-drivername.pl \ $(srcdir)/driver.h \ $(srcdir)/libvirt_public.syms \ + $(srcdir)/libvirt_admin.syms \ $(srcdir)/libvirt_qemu.syms \ $(srcdir)/libvirt_lxc.syms @@ -1094,6 +1099,7 @@ USED_SYM_FILES = $(srcdir)/libvirt_private.syms GENERATED_SYM_FILES = \ $(ACCESS_DRIVER_SYM_FILES) \ libvirt.syms libvirt.def libvirt_qemu.def libvirt_lxc.def \ + libvirt_admin.def \ $(NULL) if WITH_TEST @@ -2003,6 +2009,7 @@ EXTRA_DIST += \ libvirt_public.syms \ libvirt_lxc.syms \ libvirt_qemu.syms \ + libvirt_admin.syms \ $(SYM_FILES) \ $(NULL) @@ -2030,6 +2037,49 @@ libvirt.syms: libvirt_public.syms $(USED_SYM_FILES) \ chmod a-w $@-tmp && \ mv $@-tmp $@ +lib_LTLIBRARIES += libvirt-admin.la +libvirt_admin_la_SOURCES = \ + libvirt-admin.c \ + $(ADMIN_PROTOCOL_GENERATED) \ + $(DATATYPES_SOURCES) + +libvirt_admin_la_LDFLAGS = \ + $(VERSION_SCRIPT_FLAGS)$(LIBVIRT_ADMIN_SYMBOL_FILE) \ + -version-info $(LIBVIRT_VERSION_INFO) \ + $(AM_LDFLAGS) \ + $(CYGWIN_EXTRA_LDFLAGS) \ + $(MINGW_EXTRA_LDFLAGS) + +libvirt_admin_la_LIBADD = \ + libvirt.la \ + $(CYGWIN_EXTRA_LIBADD) + +libvirt_admin_la_CFLAGS = \ + $(AM_CFLAGS) \ + -I$(srcdir)/remote \ + -I$(srcdir)/rpc \ + -I$(srcdir)/admin + +libvirt_admin_la_CFLAGS += \ + $(CAPNG_CFLAGS) \ + $(YAJL_CFLAGS) \ + $(SSH2_CFLAGS) \ + $(SASL_CFLAGS) \ + $(GNUTLS_CFLAGS) + +libvirt_admin_la_LIBADD += \ + $(CAPNG_LIBS) \ + $(YAJL_LIBS) \ + $(DEVMAPPER_LIBS) \ + $(LIBXML_LIBS) \ + $(SSH2_LIBS) \ + $(SASL_LIBS) \ + $(GNUTLS_LIBS) + +if WITH_DTRACE_PROBES +libvirt_admin_la_LIBADD += libvirt_probes.lo +endif WITH_DTRACE_PROBES + # Empty source list - it merely links a bunch of convenience libs together libvirt_la_SOURCES = libvirt_la_LDFLAGS = \ diff --git a/src/datatypes.c b/src/datatypes.c index 39f83d94df..12bcfc1963 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -59,6 +59,10 @@ static void virStreamDispose(void *obj); static void virStorageVolDispose(void *obj); static void virStoragePoolDispose(void *obj); +virClassPtr virAdmConnectClass; + +static void virAdmConnectDispose(void *obj); + static int virDataTypesOnceInit(void) { @@ -86,6 +90,8 @@ virDataTypesOnceInit(void) DECLARE_CLASS(virStorageVol); DECLARE_CLASS(virStoragePool); + DECLARE_CLASS_LOCKABLE(virAdmConnect); + #undef DECLARE_CLASS_COMMON #undef DECLARE_CLASS_LOCKABLE #undef DECLARE_CLASS @@ -803,3 +809,27 @@ virDomainSnapshotDispose(void *obj) VIR_FREE(snapshot->name); virObjectUnref(snapshot->domain); } + + +virAdmConnectPtr +virAdmConnectNew(void) +{ + virAdmConnectPtr ret; + + if (virDataTypesInitialize() < 0) + return NULL; + + if (!(ret = virObjectLockableNew(virAdmConnectClass))) + return NULL; + + return ret; +} + +static void +virAdmConnectDispose(void *obj) +{ + virAdmConnectPtr conn = obj; + + if (conn->privateDataFreeFunc) + conn->privateDataFreeFunc(conn); +} diff --git a/src/datatypes.h b/src/datatypes.h index f1d01d5a24..c498cb0ba2 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -41,6 +41,8 @@ extern virClassPtr virStreamClass; extern virClassPtr virStorageVolClass; extern virClassPtr virStoragePoolClass; +extern virClassPtr virAdmConnectClass; + # define virCheckConnectReturn(obj, retval) \ do { \ if (!virObjectIsClass(obj, virConnectClass)) { \ @@ -295,6 +297,26 @@ extern virClassPtr virStoragePoolClass; dom, NULLSTR(_domname), _uuidstr, __VA_ARGS__); \ } while (0) +# define virCheckAdmConnectReturn(obj, retval) \ + do { \ + if (!virObjectIsClass(obj, virAdmConnectClass)) { \ + virReportErrorHelper(VIR_FROM_THIS, VIR_ERR_INVALID_CONN, \ + __FILE__, __FUNCTION__, __LINE__, \ + __FUNCTION__); \ + virDispatchError(NULL); \ + return retval; \ + } \ + } while (0) +# define virCheckAdmConnectGoto(obj, label) \ + do { \ + if (!virObjectIsClass(obj, virAdmConnectClass)) { \ + virReportErrorHelper(VIR_FROM_THIS, VIR_ERR_INVALID_CONN, \ + __FILE__, __FUNCTION__, __LINE__, \ + __FUNCTION__); \ + goto label; \ + } \ + } while (0) + /** * VIR_DOMAIN_DEBUG: * @dom: domain @@ -368,6 +390,19 @@ struct _virConnect { virConnectCloseCallbackDataPtr closeCallback; }; +/** + * _virAdmConnect: + * + * Internal structure associated to an admin connection + */ +struct _virAdmConnect { + virObjectLockable object; + + void *privateData; + virFreeCallback privateDataFreeFunc; +}; + + /** * _virDomain: * @@ -549,4 +584,6 @@ virNWFilterPtr virGetNWFilter(virConnectPtr conn, virDomainSnapshotPtr virGetDomainSnapshot(virDomainPtr domain, const char *name); +virAdmConnectPtr virAdmConnectNew(void); + #endif /* __VIR_DATATYPES_H__ */ diff --git a/src/internal.h b/src/internal.h index 52e40d1fac..7c042e0dba 100644 --- a/src/internal.h +++ b/src/internal.h @@ -58,6 +58,7 @@ # include "libvirt/libvirt.h" # include "libvirt/libvirt-lxc.h" # include "libvirt/libvirt-qemu.h" +# include "libvirt/libvirt-admin.h" # include "libvirt/virterror.h" # include "c-strcase.h" diff --git a/src/libvirt-admin.c b/src/libvirt-admin.c new file mode 100644 index 0000000000..11b6fe3238 --- /dev/null +++ b/src/libvirt-admin.c @@ -0,0 +1,386 @@ +/* + * libvirt-admin.c + * + * Copyright (C) 2014-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 + * . + * + * Author: Martin Kletzander + */ + +#include + +#include + +#include "internal.h" +#include "configmake.h" +#include "datatypes.h" +#include "viralloc.h" +#include "virlog.h" +#include "virnetclient.h" +#include "virobject.h" +#include "virstring.h" +#include "viruri.h" +#include "virutil.h" +#include "viruuid.h" + +#define VIR_FROM_THIS VIR_FROM_ADMIN + +#define LIBVIRTD_ADMIN_SOCK_NAME "/libvirt-admin-sock" +#define LIBVIRTD_ADMIN_UNIX_SOCKET LOCALSTATEDIR "/run/libvirt" LIBVIRTD_ADMIN_SOCK_NAME + +VIR_LOG_INIT("libvirt-admin"); + + +typedef struct _remoteAdminPriv remoteAdminPriv; +typedef remoteAdminPriv *remoteAdminPrivPtr; + +struct _remoteAdminPriv { + virObjectLockable parent; + + int counter; + virNetClientPtr client; + virNetClientProgramPtr program; +}; + +static virClassPtr remoteAdminPrivClass; + +static void +remoteAdminPrivDispose(void *opaque) +{ + remoteAdminPrivPtr priv = opaque; + + virObjectUnref(priv->program); + virObjectUnref(priv->client); +} + + +static int +callFull(virAdmConnectPtr conn ATTRIBUTE_UNUSED, + remoteAdminPrivPtr priv, + int *fdin, + size_t fdinlen, + int **fdout, + size_t *fdoutlen, + int proc_nr, + xdrproc_t args_filter, char *args, + xdrproc_t ret_filter, char *ret) +{ + int rv; + virNetClientProgramPtr prog = priv->program; + int counter = priv->counter++; + virNetClientPtr client = priv->client; + + /* Unlock, so that if we get any async events/stream data + * while processing the RPC, we don't deadlock when our + * callbacks for those are invoked + */ + virObjectRef(priv); + virObjectUnlock(priv); + + rv = virNetClientProgramCall(prog, + client, + counter, + proc_nr, + fdinlen, fdin, + fdoutlen, fdout, + args_filter, args, + ret_filter, ret); + + virObjectLock(priv); + virObjectUnref(priv); + + return rv; +} + +static int +call(virAdmConnectPtr conn, + unsigned int flags, + int proc_nr, + xdrproc_t args_filter, char *args, + xdrproc_t ret_filter, char *ret) +{ + virCheckFlags(0, -1); + + return callFull(conn, conn->privateData, + NULL, 0, NULL, NULL, proc_nr, + args_filter, args, ret_filter, ret); +} + +#include "admin_protocol.h" +#include "admin_client.h" + +static bool virAdmGlobalError; +static virOnceControl virAdmGlobalOnce = VIR_ONCE_CONTROL_INITIALIZER; + +static void +remoteAdminPrivFree(void *opaque) +{ + virAdmConnectPtr conn = opaque; + + remoteAdminConnectClose(conn); +} + +static remoteAdminPrivPtr +remoteAdminPrivNew(const char *sock_path) +{ + remoteAdminPrivPtr priv = NULL; + + if (!(priv = virObjectLockableNew(remoteAdminPrivClass))) + goto error; + + if (!(priv->client = virNetClientNewUNIX(sock_path, false, NULL))) + goto error; + + if (!(priv->program = virNetClientProgramNew(ADMIN_PROGRAM, + ADMIN_PROTOCOL_VERSION, + NULL, 0, NULL))) + goto error; + + if (virNetClientAddProgram(priv->client, priv->program) < 0) + goto error; + + return priv; + error: + virObjectUnref(priv); + return NULL; +} + +static void +virAdmGlobalInit(void) +{ + /* It would be nice if we could trace the use of this call, to + * help diagnose in log files if a user calls something other than + * virAdmConnectOpen first. But we can't rely on VIR_DEBUG working + * until after initialization is complete, and since this is + * one-shot, we never get here again. */ + if (virThreadInitialize() < 0 || + virErrorInitialize() < 0) + goto error; + + virLogSetFromEnv(); + + if (!bindtextdomain(PACKAGE, LOCALEDIR)) + goto error; + + if (!(remoteAdminPrivClass = virClassNew(virClassForObjectLockable(), + "remoteAdminPriv", + sizeof(remoteAdminPriv), + remoteAdminPrivDispose))) + goto error; + + return; + error: + virAdmGlobalError = true; +} + +/** + * virAdmInitialize: + * + * Initialize the library. + * + * Returns 0 in case of success, -1 in case of error + */ +static int +virAdmInitialize(void) +{ + if (virOnce(&virAdmGlobalOnce, virAdmGlobalInit) < 0) + return -1; + + if (virAdmGlobalError) + return -1; + + return 0; +} + +static char * +getSocketPath(const char *name) +{ + char *rundir = virGetUserRuntimeDirectory(); + char *sock_path = NULL; + size_t i = 0; + virURIPtr uri = NULL; + + if (name) { + if (!(uri = virURIParse(name))) + goto error; + + if (STRNEQ(uri->scheme, "admin") || + uri->server || uri->user || uri->fragment) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Invalid connection name '%s'"), name); + goto error; + } + + for (i = 0; i < uri->paramsCount; i++) { + virURIParamPtr param = &uri->params[i]; + + if (STREQ(param->name, "socket")) { + VIR_FREE(sock_path); + if (VIR_STRDUP(sock_path, param->value) < 0) + goto error; + } else { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unknown URI parameter '%s'"), param->name); + goto error; + } + } + } + + if (!sock_path) { + if (!uri || !uri->path || STREQ(uri->path, "/system")) { + if (VIR_STRDUP(sock_path, LIBVIRTD_ADMIN_UNIX_SOCKET) < 0) + goto error; + } else if (STREQ_NULLABLE(uri->path, "/session")) { + if (!rundir) + goto error; + + if (virAsprintf(&sock_path, + "%s%s", rundir, LIBVIRTD_ADMIN_SOCK_NAME) < 0) + goto error; + } else { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Invalid URI path '%s'"), uri->path); + goto error; + } + } + + cleanup: + VIR_FREE(rundir); + virURIFree(uri); + return sock_path; + + error: + VIR_FREE(sock_path); + goto cleanup; +} + +/** + * virAdmConnectOpen: + * @name: uri of the daemon to connect to, NULL for default + * @flags: unused, must be 0 + * + * Opens connection to admin interface of the daemon. + * + * Returns @virAdmConnectPtr object or NULL on error + */ +virAdmConnectPtr +virAdmConnectOpen(const char *name, unsigned int flags) +{ + char *sock_path = NULL; + virAdmConnectPtr conn = NULL; + + if (virAdmInitialize() < 0) + goto error; + + VIR_DEBUG("flags=%x", flags); + virResetLastError(); + + if (!(conn = virAdmConnectNew())) + goto error; + + if (!(sock_path = getSocketPath(name))) + goto error; + + if (!(conn->privateData = remoteAdminPrivNew(sock_path))) + goto error; + + conn->privateDataFreeFunc = remoteAdminPrivFree; + + if (remoteAdminConnectOpen(conn, flags) < 0) + goto error; + + cleanup: + VIR_FREE(sock_path); + return conn; + + error: + virDispatchError(NULL); + virObjectUnref(conn); + conn = NULL; + goto cleanup; +} + +/** + * virAdmConnectClose: + * @conn: pointer to admin connection to close + * + * This function closes the admin connection to the Hypervisor. This should not + * be called if further interaction with the Hypervisor are needed especially if + * there is running domain which need further monitoring by the application. + * + * Connections are reference counted; the count is explicitly increased by the + * initial virAdmConnectOpen, as well as virAdmConnectRef; it is also temporarily + * increased by other API that depend on the connection remaining alive. The + * open and every virAdmConnectRef call should have a matching + * virAdmConnectClose, and all other references will be released after the + * corresponding operation completes. + * + * Returns a positive number if at least 1 reference remains on success. The + * returned value should not be assumed to be the total reference count. A + * return of 0 implies no references remain and the connection is closed and + * memory has been freed. A return of -1 implies a failure. + * + * It is possible for the last virAdmConnectClose to return a positive value if + * some other object still has a temporary reference to the connection, but the + * application should not try to further use a connection after the + * virAdmConnectClose that matches the initial open. + */ +int +virAdmConnectClose(virAdmConnectPtr conn) +{ + VIR_DEBUG("conn=%p", conn); + + virResetLastError(); + if (!conn) + return 0; + + virCheckAdmConnectReturn(conn, -1); + + if (!virObjectUnref(conn)) + return 0; + return 1; +} + + +/** + * virAdmConnectRef: + * @conn: the connection to hold a reference on + * + * Increment the reference count on the connection. For each additional call to + * this method, there shall be a corresponding call to virAdmConnectClose to + * release the reference count, once the caller no longer needs the reference to + * this object. + * + * This method is typically useful for applications where multiple threads are + * using a connection, and it is required that the connection remain open until + * all threads have finished using it. I.e., each new thread using a connection + * would increment the reference count. + * + * Returns 0 in case of success, -1 in case of failure + */ +int +virAdmConnectRef(virAdmConnectPtr conn) +{ + VIR_DEBUG("conn=%p refs=%d", conn, + conn ? conn->object.parent.u.s.refs : 0); + + virResetLastError(); + virCheckAdmConnectReturn(conn, -1); + + virObjectRef(conn); + + return 0; +} diff --git a/src/libvirt_admin.syms b/src/libvirt_admin.syms new file mode 100644 index 0000000000..d9e3c0b1b9 --- /dev/null +++ b/src/libvirt_admin.syms @@ -0,0 +1,18 @@ +# +# Officially exported symbols, for which header +# file definitions are installed in /usr/include/libvirt +# from libvirt-admin.h +# +# Versions here are *fixed* to match the libvirt version +# at which the symbol was introduced. This ensures that +# a new client app requiring symbol foo() can't accidentally +# run with old libvirt-admin.so not providing foo() - the global +# soname version info can't enforce this since we never +# change the soname +# +LIBVIRT_ADMIN_1.3.0 { + global: + virAdmConnectOpen; + virAdmConnectClose; + virAdmConnectRef; +};