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;
+};