[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen staging] tools: split libxenstore into new tools/libs/store directory



commit dd33fd2e81a0e83707cc203b974e501fa336590f
Author:     Juergen Gross <jgross@xxxxxxxx>
AuthorDate: Fri Aug 28 17:07:36 2020 +0200
Commit:     Wei Liu <wl@xxxxxxx>
CommitDate: Wed Sep 9 10:57:25 2020 +0000

    tools: split libxenstore into new tools/libs/store directory
    
    There is no reason why libxenstore is not placed in the tools/libs
    directory.
    
    The common files between libxenstore and xenstored are kept in the
    tools/xenstore directory to be easily accessible by xenstore-stubdom
    which needs the xenstored files to be built.
    
    Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
    Acked-by: Wei Liu <wl@xxxxxxx>
---
 .gitignore                               |    7 +-
 stubdom/mini-os.mk                       |    2 +-
 tools/Makefile                           |    2 +-
 tools/Rules.mk                           |    5 -
 tools/libs/Makefile                      |    1 +
 tools/libs/store/Makefile                |   64 ++
 tools/libs/store/include/compat/xs.h     |    2 +
 tools/libs/store/include/compat/xs_lib.h |    2 +
 tools/libs/store/include/xenstore.h      |  290 ++++++
 tools/libs/store/libxenstore.map         |   49 +
 tools/libs/store/xs.c                    | 1473 ++++++++++++++++++++++++++++++
 tools/libs/uselibs.mk                    |    2 +
 tools/python/setup.py                    |    2 +-
 tools/xenstore/Makefile                  |   86 +-
 tools/xenstore/include/compat/xs.h       |    2 -
 tools/xenstore/include/compat/xs_lib.h   |    2 -
 tools/xenstore/include/xenstore.h        |  290 ------
 tools/xenstore/include/xenstore_lib.h    |   94 --
 tools/xenstore/xenstore_lib.h            |   94 ++
 tools/xenstore/xs.c                      | 1473 ------------------------------
 20 files changed, 1990 insertions(+), 1952 deletions(-)

diff --git a/.gitignore b/.gitignore
index eb637a98e9..1335034fd3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -128,6 +128,12 @@ tools/libs/guest/xc_core.h
 tools/libs/guest/xc_core_arm.h
 tools/libs/guest/xc_core_x86.h
 tools/libs/guest/xc_private.h
+tools/libs/store/headers.chk
+tools/libs/store/list.h
+tools/libs/store/utils.h
+tools/libs/store/xenstore.pc
+tools/libs/store/xs_lib.c
+tools/libs/store/include/xenstore_lib.h
 tools/console/xenconsole
 tools/console/xenconsoled
 tools/console/client/_paths.h
@@ -282,7 +288,6 @@ tools/xenstore/xenstore-control
 tools/xenstore/xenstore-ls
 tools/xenstore/xenstored
 tools/xenstore/xenstored_test
-tools/xenstore/xenstore.pc
 tools/xenstore/xs_tdb_dump
 tools/xentrace/xentrace_setsize
 tools/xentrace/tbctl
diff --git a/stubdom/mini-os.mk b/stubdom/mini-os.mk
index e1640a7cbc..420e9a8771 100644
--- a/stubdom/mini-os.mk
+++ b/stubdom/mini-os.mk
@@ -5,7 +5,7 @@
 # XEN_ROOT
 # MINIOS_TARGET_ARCH
 
-XENSTORE_CPPFLAGS = -isystem $(XEN_ROOT)/tools/xenstore/include
+XENSTORE_CPPFLAGS = -isystem $(XEN_ROOT)/tools/libs/store/include
 TOOLCORE_PATH = $(XEN_ROOT)/stubdom/libs-$(MINIOS_TARGET_ARCH)/toolcore
 TOOLLOG_PATH = $(XEN_ROOT)/stubdom/libs-$(MINIOS_TARGET_ARCH)/toollog
 EVTCHN_PATH = $(XEN_ROOT)/stubdom/libs-$(MINIOS_TARGET_ARCH)/evtchn
diff --git a/tools/Makefile b/tools/Makefile
index f9b4012290..4a3646871c 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -43,7 +43,7 @@ SUBDIRS-y += pygrub
 SUBDIRS-$(OCAML_TOOLS) += ocaml
 
 ifeq ($(CONFIG_RUMP),y)
-SUBDIRS-y := libs xenstore
+SUBDIRS-y := libs
 endif
 
 # For the sake of linking, set the sys-root
diff --git a/tools/Rules.mk b/tools/Rules.mk
index e17ac3ecc6..21aa8ea844 100644
--- a/tools/Rules.mk
+++ b/tools/Rules.mk
@@ -18,7 +18,6 @@ include $(XEN_ROOT)/tools/libs/uselibs.mk
 XEN_libxenlight    = $(XEN_ROOT)/tools/libxl
 # Currently libxlutil lives in the same directory as libxenlight
 XEN_libxlutil      = $(XEN_libxenlight)
-XEN_libxenstore    = $(XEN_ROOT)/tools/xenstore
 XEN_libxenstat     = $(XEN_ROOT)/tools/xenstat/libxenstat/src
 XEN_libxenvchan    = $(XEN_ROOT)/tools/libvchan
 
@@ -106,10 +105,6 @@ $(foreach lib,$(LIBS_LIBS),$(eval $(call LIB_defs,$(lib))))
 CFLAGS_libxenctrl += $(CFLAGS_libxentoollog) $(CFLAGS_libxenforeignmemory) 
$(CFLAGS_libxendevicemodel) -D__XEN_TOOLS__
 CFLAGS_libxenguest += $(CFLAGS_libxenevtchn) $(CFLAGS_libxenforeignmemory)
 
-CFLAGS_libxenstore = -I$(XEN_libxenstore)/include $(CFLAGS_xeninclude)
-SHDEPS_libxenstore = $(SHLIB_libxentoolcore) $(SHLIB_libxenctrl)
-LDLIBS_libxenstore = $(SHDEPS_libxenstore) 
$(XEN_libxenstore)/libxenstore$(libextension)
-SHLIB_libxenstore  = $(SHDEPS_libxenstore) -Wl,-rpath-link=$(XEN_libxenstore)
 ifeq ($(CONFIG_Linux),y)
 LDLIBS_libxenstore += -ldl
 endif
diff --git a/tools/libs/Makefile b/tools/libs/Makefile
index f15c1688f7..62bd8f5292 100644
--- a/tools/libs/Makefile
+++ b/tools/libs/Makefile
@@ -12,6 +12,7 @@ SUBDIRS-y += devicemodel
 SUBDIRS-y += ctrl
 SUBDIRS-y += guest
 SUBDIRS-y += hypfs
+SUBDIRS-y += store
 
 ifeq ($(CONFIG_RUMP),y)
 SUBDIRS-y := toolcore
diff --git a/tools/libs/store/Makefile b/tools/libs/store/Makefile
new file mode 100644
index 0000000000..4da502646e
--- /dev/null
+++ b/tools/libs/store/Makefile
@@ -0,0 +1,64 @@
+XEN_ROOT=$(CURDIR)/../../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+MAJOR = 3.0
+MINOR = 3
+
+ifeq ($(CONFIG_Linux),y)
+APPEND_LDFLAGS += -ldl
+endif
+
+SRCS-y   += xs_lib.c
+SRCS-y   += xs.c
+
+LIBHEADER = xenstore.h xenstore_lib.h
+
+include ../libs.mk
+
+# Include configure output (config.h)
+CFLAGS += -include $(XEN_ROOT)/tools/config.h
+CFLAGS += $(CFLAGS_libxentoolcore)
+CFLAGS += -DXEN_LIB_STORED="\"$(XEN_LIB_STORED)\""
+CFLAGS += -DXEN_RUN_STORED="\"$(XEN_RUN_STORED)\""
+
+LINK_FILES = xs_lib.c include/xenstore_lib.h list.h utils.h
+
+$(LIB_OBJS): $(LINK_FILES)
+
+$(LINK_FILES):
+       ln -sf $(XEN_ROOT)/tools/xenstore/$(notdir $@) $@
+
+xs.opic: CFLAGS += -DUSE_PTHREAD
+ifeq ($(CONFIG_Linux),y)
+xs.opic: CFLAGS += -DUSE_DLSYM
+else
+PKG_CONFIG_REMOVE += -ldl
+endif
+
+$(PKG_CONFIG_LOCAL): PKG_CONFIG_INCDIR = $(XEN_libxenstore)/include
+$(PKG_CONFIG_LOCAL): PKG_CONFIG_CFLAGS_LOCAL = $(CFLAGS_xeninclude)
+
+.PHONY: install
+install: install-headers
+
+.PHONY: install-headers
+install-headers:
+       $(INSTALL_DIR) $(DESTDIR)$(includedir)
+       $(INSTALL_DIR) $(DESTDIR)$(includedir)/xenstore-compat
+       $(INSTALL_DATA) include/compat/xs.h 
$(DESTDIR)$(includedir)/xenstore-compat/xs.h
+       $(INSTALL_DATA) include/compat/xs_lib.h 
$(DESTDIR)$(includedir)/xenstore-compat/xs_lib.h
+       ln -sf xenstore-compat/xs.h  $(DESTDIR)$(includedir)/xs.h
+       ln -sf xenstore-compat/xs_lib.h $(DESTDIR)$(includedir)/xs_lib.h
+
+.PHONY: uninstall
+uninstall: uninstall-headers
+
+.PHONY: uninstall-headers
+uninstall-headers:
+       rm -f $(DESTDIR)$(includedir)/xs_lib.h
+       rm -f $(DESTDIR)$(includedir)/xs.h
+       rm -f $(DESTDIR)$(includedir)/xenstore-compat/xs_lib.h
+       rm -f $(DESTDIR)$(includedir)/xenstore-compat/xs.h
+       if [ -d $(DESTDIR)$(includedir)/xenstore-compat ]; then \
+               rmdir --ignore-fail-on-non-empty 
$(DESTDIR)$(includedir)/xenstore-compat; \
+       fi
diff --git a/tools/libs/store/include/compat/xs.h 
b/tools/libs/store/include/compat/xs.h
new file mode 100644
index 0000000000..99cf39bb1a
--- /dev/null
+++ b/tools/libs/store/include/compat/xs.h
@@ -0,0 +1,2 @@
+#warning xs.h is deprecated use xenstore.h instead
+#include <xenstore.h>
diff --git a/tools/libs/store/include/compat/xs_lib.h 
b/tools/libs/store/include/compat/xs_lib.h
new file mode 100644
index 0000000000..ad81b54c0e
--- /dev/null
+++ b/tools/libs/store/include/compat/xs_lib.h
@@ -0,0 +1,2 @@
+#warning xs_lib.h is deprecated use xenstore_lib.h instead
+#include <xenstore_lib.h>
diff --git a/tools/libs/store/include/xenstore.h 
b/tools/libs/store/include/xenstore.h
new file mode 100644
index 0000000000..25b31881c8
--- /dev/null
+++ b/tools/libs/store/include/xenstore.h
@@ -0,0 +1,290 @@
+/* 
+    Xen Store Daemon providing simple tree-like database.
+    Copyright (C) 2005 Rusty Russell IBM Corporation
+
+    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/>.
+*/
+
+#ifndef XENSTORE_H
+#define XENSTORE_H
+
+#include <xenstore_lib.h>
+
+#define XBT_NULL 0
+
+#define XS_OPEN_READONLY       (1UL<<0)
+#define XS_OPEN_SOCKETONLY      (1UL<<1)
+
+/*
+ * Setting XS_UNWATCH_FILTER arranges that after xs_unwatch, no
+ * related watch events will be delivered via xs_read_watch.  But
+ * this relies on the couple token, subpath is unique.
+ *
+ * XS_UNWATCH_FILTER clear          XS_UNWATCH_FILTER set
+ *
+ * Even after xs_unwatch, "stale"   After xs_unwatch returns, no
+ * instances of the watch event     watch events with the same
+ * may be delivered.                token and with the same subpath
+ *                                  will be delivered.
+ *
+ * A path and a subpath can be      The application must avoid
+ * register with the same token.    registering a path (/foo/) and
+ *                                  a subpath (/foo/bar) with the
+ *                                  same path until a successful
+ *                                  xs_unwatch for the first watch
+ *                                  has returned.
+ */
+#define XS_UNWATCH_FILTER     (1UL<<2)
+
+struct xs_handle;
+typedef uint32_t xs_transaction_t;
+
+/* IMPORTANT: For details on xenstore protocol limits, see
+ * docs/misc/xenstore.txt in the Xen public source repository, and use the
+ * XENSTORE_*_MAX limit macros defined in xen/io/xs_wire.h.
+ */
+
+/* On failure, these routines set errno. */
+
+/* Open a connection to the xs daemon.
+ * Attempts to make a connection over the socket interface,
+ * and if it fails, then over the  xenbus interface.
+ * Mode 0 specifies read-write access, XS_OPEN_READONLY for
+ * read-only access.
+ *
+ * * Connections made with xs_open(0) (which might be shared page or
+ *   socket based) are only guaranteed to work in the parent after
+ *   fork.
+ * * Connections made with xs_open(XS_OPEN_SOCKETONLY) will be usable
+ *   in either the parent or the child after fork, but not both.
+ * * xs_daemon_open*() and xs_domain_open() are deprecated synonyms
+ *   for xs_open(0).
+ * * XS_OPEN_READONLY has no bearing on any of this.
+ *
+ * Returns a handle or NULL.
+ */
+struct xs_handle *xs_open(unsigned long flags);
+
+/* Close the connection to the xs daemon. */
+void xs_close(struct xs_handle *xsh /* NULL ok */);
+
+/* Connect to the xs daemon.
+ * Returns a handle or NULL.
+ * Deprecated, please use xs_open(0) instead
+ */
+struct xs_handle *xs_daemon_open(void);
+struct xs_handle *xs_domain_open(void);
+
+/* Connect to the xs daemon (readonly for non-root clients).
+ * Returns a handle or NULL.
+ * Deprecated, please use xs_open(XS_OPEN_READONLY) instead
+ */
+struct xs_handle *xs_daemon_open_readonly(void);
+
+/* Close the connection to the xs daemon.
+ * Deprecated, please use xs_close() instead
+ */
+void xs_daemon_close(struct xs_handle *);
+
+/* Throw away the connection to the xs daemon, for use after fork(). */
+void xs_daemon_destroy_postfork(struct xs_handle *);
+
+/* Get contents of a directory.
+ * Returns a malloced array: call free() on it after use.
+ * Num indicates size.
+ * Returns NULL on failure.
+ */
+char **xs_directory(struct xs_handle *h, xs_transaction_t t,
+                   const char *path, unsigned int *num);
+
+/* Get the value of a single file, nul terminated.
+ * Returns a malloced value: call free() on it after use.
+ * len indicates length in bytes, not including terminator.
+ * Returns NULL on failure.
+ */
+void *xs_read(struct xs_handle *h, xs_transaction_t t,
+             const char *path, unsigned int *len);
+
+/* Write the value of a single file.
+ * Returns false on failure.
+ */
+bool xs_write(struct xs_handle *h, xs_transaction_t t,
+             const char *path, const void *data, unsigned int len);
+
+/* Create a new directory.
+ * Returns false on failure, or success if it already exists.
+ */
+bool xs_mkdir(struct xs_handle *h, xs_transaction_t t,
+             const char *path);
+
+/* Destroy a file or directory (and children).
+ * Returns false on failure, or if it doesn't exist.
+ */
+bool xs_rm(struct xs_handle *h, xs_transaction_t t,
+          const char *path);
+
+/* Fake function which will always return false (required to let
+ * libxenstore remain at 3.0 version.
+ */
+bool xs_restrict(struct xs_handle *h, unsigned domid);
+
+/* Get permissions of node (first element is owner, first perms is "other").
+ * Returns malloced array, or NULL: call free() after use.
+ */
+struct xs_permissions *xs_get_permissions(struct xs_handle *h,
+                                         xs_transaction_t t,
+                                         const char *path, unsigned int *num);
+
+/* Set permissions of node (must be owner).  Returns false on failure.
+ *
+ * Domain 0 may read / write anywhere in the store, regardless of
+ * permission settings.
+ *
+ * Note:
+ * The perms array is a list of (domid, permissions) pairs. The first
+ * element in the list specifies the owner of the list, plus the flags
+ * for every domain not explicitly specified subsequently. The
+ * subsequent entries are normal capabilities.
+ *
+ * Example C code:
+ *
+ *  struct xs_permissions perms[2];
+ *
+ *  perms[0].id = dm_domid;
+ *  perms[0].perms = XS_PERM_NONE;
+ *  perms[1].id = guest_domid;
+ *  perms[1].perms = XS_PERM_READ;
+ *
+ * It means the owner of the path is domain $dm_domid (hence it always
+ * has read and write permission), all other domains (unless specified
+ * in subsequent pair) can neither read from nor write to that
+ * path. It then specifies domain $guest_domid can read from that
+ * path.
+ */
+bool xs_set_permissions(struct xs_handle *h, xs_transaction_t t,
+                       const char *path, struct xs_permissions *perms,
+                       unsigned int num_perms);
+
+/* Watch a node for changes (poll on fd to detect, or call read_watch()).
+ * When the node (or any child) changes, fd will become readable.
+ * Token is returned when watch is read, to allow matching.
+ * Returns false on failure.
+ */
+bool xs_watch(struct xs_handle *h, const char *path, const char *token);
+
+/* Return the FD to poll on to see if a watch has fired. */
+int xs_fileno(struct xs_handle *h);
+
+/* Check for node changes.  On success, returns a non-NULL pointer ret
+ * such that ret[0] and ret[1] are valid C strings, namely the
+ * triggering path (see docs/misc/xenstore.txt) and the token (from
+ * xs_watch).  On error return value is NULL setting errno.
+ * 
+ * Callers should, after xs_fileno has become readable, repeatedly
+ * call xs_check_watch until it returns NULL and sets errno to EAGAIN.
+ * (If the fd became readable, xs_check_watch is allowed to make it no
+ * longer show up as readable even if future calls to xs_check_watch
+ * will return more watch events.)
+ *
+ * After the caller is finished with the returned information it
+ * should be freed all in one go with free(ret).
+ */
+char **xs_check_watch(struct xs_handle *h);
+
+/* Find out what node change was on (will block if nothing pending).
+ * Returns array containing the path and token, or NULL.
+ * Use XS_WATCH_* to access these elements.
+ * Call free() after use.
+ */
+char **xs_read_watch(struct xs_handle *h, unsigned int *num);
+
+/* Remove a watch on a node: implicitly acks any outstanding watch.
+ * Returns false on failure (no watch on that node).
+ */
+bool xs_unwatch(struct xs_handle *h, const char *path, const char *token);
+
+/* Start a transaction: changes by others will not be seen during this
+ * transaction, and changes will not be visible to others until end.
+ * Returns NULL on failure.
+ */
+xs_transaction_t xs_transaction_start(struct xs_handle *h);
+
+/* End a transaction.
+ * If abandon is true, transaction is discarded instead of committed.
+ * Returns false on failure: if errno == EAGAIN, you have to restart
+ * transaction.
+ */
+bool xs_transaction_end(struct xs_handle *h, xs_transaction_t t,
+                       bool abort);
+
+/* Introduce a new domain.
+ * This tells the store daemon about a shared memory page, event channel and
+ * store path associated with a domain: the domain uses these to communicate.
+ */
+bool xs_introduce_domain(struct xs_handle *h,
+                        unsigned int domid,
+                        unsigned long mfn,
+                         unsigned int eventchn); 
+
+/* Set the target of a domain
+ * This tells the store daemon that a domain is targetting another one, so
+ * it should let it tinker with it.
+ */
+bool xs_set_target(struct xs_handle *h,
+                  unsigned int domid,
+                  unsigned int target);
+
+/* Resume a domain.
+ * Clear the shutdown flag for this domain in the store.
+ */
+bool xs_resume_domain(struct xs_handle *h, unsigned int domid);
+
+/* Release a domain.
+ * Tells the store domain to release the memory page to the domain.
+ */
+bool xs_release_domain(struct xs_handle *h, unsigned int domid);
+
+/* Query the home path of a domain.  Call free() after use.
+ */
+char *xs_get_domain_path(struct xs_handle *h, unsigned int domid);
+
+/* Returns true if child is either equal to parent, or a node underneath
+ * parent; or false otherwise.  Done by string comparison, so relative and
+ * absolute pathnames never in a parent/child relationship by this
+ * definition.  Cannot fail.
+ */
+bool xs_path_is_subpath(const char *parent, const char *child);
+
+/* Return whether the domain specified has been introduced to xenstored.
+ */
+bool xs_is_domain_introduced(struct xs_handle *h, unsigned int domid);
+
+char *xs_control_command(struct xs_handle *h, const char *cmd,
+                        void *data, unsigned int len);
+/* Deprecated: use xs_control_command() instead. */
+char *xs_debug_command(struct xs_handle *h, const char *cmd,
+                      void *data, unsigned int len);
+
+int xs_suspend_evtchn_port(int domid);
+#endif /* XENSTORE_H */
+
+/*
+ * Local variables:
+ *  mode: C
+ *  c-file-style: "linux"
+ *  indent-tabs-mode: t
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/tools/libs/store/libxenstore.map b/tools/libs/store/libxenstore.map
new file mode 100644
index 0000000000..9854305a2c
--- /dev/null
+++ b/tools/libs/store/libxenstore.map
@@ -0,0 +1,49 @@
+VERS_3.0.3 {
+       global:
+               xs_open;
+               xs_close;
+               xs_daemon_open;
+               xs_domain_open;
+               xs_daemon_open_readonly;
+               xs_daemon_close;
+               xs_daemon_destroy_postfork;
+               xs_directory;
+               xs_read;
+               xs_write;
+               xs_mkdir;
+               xs_rm;
+               xs_restrict;
+               xs_get_permissions;
+               xs_set_permissions;
+               xs_watch;
+               xs_fileno;
+               xs_check_watch;
+               xs_read_watch;
+               xs_unwatch;
+               xs_transaction_start;
+               xs_transaction_end;
+               xs_introduce_domain;
+               xs_set_target;
+               xs_resume_domain;
+               xs_release_domain;
+               xs_get_domain_path;
+               xs_path_is_subpath;
+               xs_is_domain_introduced;
+               xs_control_command;
+               xs_debug_command;
+               xs_suspend_evtchn_port;
+               xs_daemon_rootdir;
+               xs_daemon_rundir;
+               xs_daemon_socket;
+               xs_daemon_socket_ro;
+               xs_domain_dev;
+               xs_daemon_tdb;
+               xs_write_all;
+               xs_strings_to_perms;
+               xs_perm_to_string;
+               xs_count_strings;
+               expanding_buffer_ensure;
+               sanitise_value;
+               unsanitise_value;
+       local: *; /* Do not expose anything by default */
+};
diff --git a/tools/libs/store/xs.c b/tools/libs/store/xs.c
new file mode 100644
index 0000000000..aa1d24b8b9
--- /dev/null
+++ b/tools/libs/store/xs.c
@@ -0,0 +1,1473 @@
+/* 
+    Xen Store Daemon interface providing simple tree-like database.
+    Copyright (C) 2005 Rusty Russell IBM Corporation
+
+    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/>.
+*/
+
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <signal.h>
+#include <stdint.h>
+#include <errno.h>
+#include "xenstore.h"
+#include "list.h"
+#include "utils.h"
+
+#include <xentoolcore_internal.h>
+
+struct xs_stored_msg {
+       struct list_head list;
+       struct xsd_sockmsg hdr;
+       char *body;
+};
+
+#ifdef USE_PTHREAD
+
+#include <pthread.h>
+
+#ifdef USE_DLSYM
+#include <dlfcn.h>
+#endif
+
+struct xs_handle {
+       /* Communications channel to xenstore daemon. */
+       int fd;
+       Xentoolcore__Active_Handle tc_ah; /* for restrict */
+
+       /*
+         * A read thread which pulls messages off the comms channel and
+         * signals waiters.
+         */
+       pthread_t read_thr;
+       int read_thr_exists;
+
+       /*
+         * A list of fired watch messages, protected by a mutex. Users can
+         * wait on the conditional variable until a watch is pending.
+         */
+       struct list_head watch_list;
+       pthread_mutex_t watch_mutex;
+       pthread_cond_t watch_condvar;
+
+       /* Clients can select() on this pipe to wait for a watch to fire. */
+       int watch_pipe[2];
+       /* Filtering watch event in unwatch function? */
+       bool unwatch_filter;
+
+       /*
+         * A list of replies. Currently only one will ever be outstanding
+         * because we serialise requests. The requester can wait on the
+         * conditional variable for its response.
+         */
+       struct list_head reply_list;
+       pthread_mutex_t reply_mutex;
+       pthread_cond_t reply_condvar;
+
+       /* One request at a time. */
+       pthread_mutex_t request_mutex;
+
+       /* Lock discipline:
+        *  Only holder of the request lock may write to h->fd.
+        *  Only holder of the request lock may access read_thr_exists.
+        *  If read_thr_exists==0, only holder of request lock may read h->fd;
+        *  If read_thr_exists==1, only the read thread may read h->fd.
+        *  Only holder of the reply lock may access reply_list.
+        *  Only holder of the watch lock may access watch_list.
+        * Lock hierarchy:
+        *  The order in which to acquire locks is
+        *     request_mutex
+        *     reply_mutex
+        *     watch_mutex
+        */
+};
+
+#define mutex_lock(m)          pthread_mutex_lock(m)
+#define mutex_unlock(m)                pthread_mutex_unlock(m)
+#define condvar_signal(c)      pthread_cond_signal(c)
+#define condvar_wait(c,m)      pthread_cond_wait(c,m)
+#define cleanup_push(f, a)     \
+    pthread_cleanup_push((void (*)(void *))(f), (void *)(a))
+/*
+ * Some definitions of pthread_cleanup_pop() are a macro starting with an
+ * end-brace. GCC then complains if we immediately precede that with a label.
+ * Hence we insert a dummy statement to appease the compiler in this situation.
+ */
+#define cleanup_pop(run)        ((void)0); pthread_cleanup_pop(run)
+
+#define read_thread_exists(h)  (h->read_thr_exists)
+
+/* Because pthread_cleanup_p* are not available when USE_PTHREAD is
+ * disabled, use these macros which convert appropriately. */
+#define cleanup_push_heap(p)        cleanup_push(free, p)
+#define cleanup_pop_heap(run, p)    cleanup_pop((run))
+
+static void *read_thread(void *arg);
+
+#else /* !defined(USE_PTHREAD) */
+
+struct xs_handle {
+       int fd;
+       Xentoolcore__Active_Handle tc_ah; /* for restrict */
+       struct list_head reply_list;
+       struct list_head watch_list;
+       /* Clients can select() on this pipe to wait for a watch to fire. */
+       int watch_pipe[2];
+       /* Filtering watch event in unwatch function? */
+       bool unwatch_filter;
+};
+
+#define mutex_lock(m)          ((void)0)
+#define mutex_unlock(m)                ((void)0)
+#define condvar_signal(c)      ((void)0)
+#define condvar_wait(c,m)      ((void)0)
+#define cleanup_push(f, a)     ((void)0)
+#define cleanup_pop(run)       ((void)0)
+#define read_thread_exists(h)  (0)
+
+#define cleanup_push_heap(p)        ((void)0)
+#define cleanup_pop_heap(run, p)    do { if ((run)) free(p); } while(0)
+
+#endif
+
+static int read_message(struct xs_handle *h, int nonblocking);
+
+static bool setnonblock(int fd, int nonblock) {
+       int flags = fcntl(fd, F_GETFL);
+       if (flags == -1)
+               return false;
+
+       if (nonblock)
+               flags |= O_NONBLOCK;
+       else
+               flags &= ~O_NONBLOCK;
+
+       if (fcntl(fd, F_SETFL, flags) == -1)
+               return false;
+
+       return true;
+}
+
+int xs_fileno(struct xs_handle *h)
+{
+       char c = 0;
+
+       mutex_lock(&h->watch_mutex);
+
+       if ((h->watch_pipe[0] == -1) && (pipe(h->watch_pipe) != -1)) {
+               /* Kick things off if the watch list is already non-empty. */
+               if (!list_empty(&h->watch_list))
+                       while (write(h->watch_pipe[1], &c, 1) != 1)
+                               continue;
+       }
+
+       mutex_unlock(&h->watch_mutex);
+
+       return h->watch_pipe[0];
+}
+
+static int get_socket(const char *connect_to)
+{
+       struct sockaddr_un addr;
+       int sock, saved_errno, flags;
+
+       sock = socket(PF_UNIX, SOCK_STREAM, 0);
+       if (sock < 0)
+               return -1;
+
+       if ((flags = fcntl(sock, F_GETFD)) < 0)
+               goto error;
+       flags |= FD_CLOEXEC;
+       if (fcntl(sock, F_SETFD, flags) < 0)
+               goto error;
+
+       addr.sun_family = AF_UNIX;
+       if(strlen(connect_to) >= sizeof(addr.sun_path)) {
+               errno = EINVAL;
+               goto error;
+       }
+       strcpy(addr.sun_path, connect_to);
+
+       if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != 0)
+               goto error;
+
+       return sock;
+
+error:
+       saved_errno = errno;
+       close(sock);
+       errno = saved_errno;
+       return -1;
+}
+
+static int get_dev(const char *connect_to)
+{
+       /* We cannot open read-only because requests are writes */
+       return open(connect_to, O_RDWR);
+}
+
+static int all_restrict_cb(Xentoolcore__Active_Handle *ah, domid_t domid) {
+    struct xs_handle *h = CONTAINER_OF(ah, *h, tc_ah);
+    return xentoolcore__restrict_by_dup2_null(h->fd);
+}
+
+static struct xs_handle *get_handle(const char *connect_to)
+{
+       struct stat buf;
+       struct xs_handle *h = NULL;
+       int saved_errno;
+
+       h = malloc(sizeof(*h));
+       if (h == NULL)
+               goto err;
+
+       memset(h, 0, sizeof(*h));
+       h->fd = -1;
+
+       h->tc_ah.restrict_callback = all_restrict_cb;
+       xentoolcore__register_active_handle(&h->tc_ah);
+
+       if (stat(connect_to, &buf) != 0)
+               goto err;
+
+       if (S_ISSOCK(buf.st_mode))
+               h->fd = get_socket(connect_to);
+       else
+               h->fd = get_dev(connect_to);
+
+       if (h->fd == -1)
+               goto err;
+
+       INIT_LIST_HEAD(&h->reply_list);
+       INIT_LIST_HEAD(&h->watch_list);
+
+       /* Watch pipe is allocated on demand in xs_fileno(). */
+       h->watch_pipe[0] = h->watch_pipe[1] = -1;
+
+       h->unwatch_filter = false;
+
+#ifdef USE_PTHREAD
+       pthread_mutex_init(&h->watch_mutex, NULL);
+       pthread_cond_init(&h->watch_condvar, NULL);
+
+       pthread_mutex_init(&h->reply_mutex, NULL);
+       pthread_cond_init(&h->reply_condvar, NULL);
+
+       pthread_mutex_init(&h->request_mutex, NULL);
+#endif
+
+       return h;
+
+err:
+       saved_errno = errno;
+
+       if (h) {
+               xentoolcore__deregister_active_handle(&h->tc_ah);
+               if (h->fd >= 0)
+                       close(h->fd);
+       }
+       free(h);
+
+       errno = saved_errno;
+       return NULL;
+}
+
+struct xs_handle *xs_daemon_open(void)
+{
+       return xs_open(0);
+}
+
+struct xs_handle *xs_daemon_open_readonly(void)
+{
+       return xs_open(XS_OPEN_READONLY);
+}
+
+struct xs_handle *xs_domain_open(void)
+{
+       return xs_open(0);
+}
+
+struct xs_handle *xs_open(unsigned long flags)
+{
+       struct xs_handle *xsh = NULL;
+
+       if (flags & XS_OPEN_READONLY)
+               xsh = get_handle(xs_daemon_socket_ro());
+       else
+               xsh = get_handle(xs_daemon_socket());
+
+       if (!xsh && !(flags & XS_OPEN_SOCKETONLY))
+               xsh = get_handle(xs_domain_dev());
+
+       if (xsh && (flags & XS_UNWATCH_FILTER))
+               xsh->unwatch_filter = true;
+
+       return xsh;
+}
+
+static void close_free_msgs(struct xs_handle *h) {
+       struct xs_stored_msg *msg, *tmsg;
+
+       list_for_each_entry_safe(msg, tmsg, &h->reply_list, list) {
+               free(msg->body);
+               free(msg);
+       }
+
+       list_for_each_entry_safe(msg, tmsg, &h->watch_list, list) {
+               free(msg->body);
+               free(msg);
+       }
+}
+
+static void close_fds_free(struct xs_handle *h) {
+       if (h->watch_pipe[0] != -1) {
+               close(h->watch_pipe[0]);
+               close(h->watch_pipe[1]);
+       }
+
+       xentoolcore__deregister_active_handle(&h->tc_ah);
+        close(h->fd);
+        
+       free(h);
+}
+
+void xs_daemon_destroy_postfork(struct xs_handle *h)
+{
+        close_free_msgs(h);
+        close_fds_free(h);
+}
+
+void xs_daemon_close(struct xs_handle *h)
+{
+#ifdef USE_PTHREAD
+       if (h->read_thr_exists) {
+               pthread_cancel(h->read_thr);
+               pthread_join(h->read_thr, NULL);
+       }
+#endif
+
+       mutex_lock(&h->request_mutex);
+       mutex_lock(&h->reply_mutex);
+       mutex_lock(&h->watch_mutex);
+
+        close_free_msgs(h);
+
+       mutex_unlock(&h->request_mutex);
+       mutex_unlock(&h->reply_mutex);
+       mutex_unlock(&h->watch_mutex);
+
+        close_fds_free(h);
+}
+
+void xs_close(struct xs_handle* xsh)
+{
+       if (xsh)
+               xs_daemon_close(xsh);
+}
+
+static bool read_all(int fd, void *data, unsigned int len, int nonblocking)
+       /* With nonblocking, either reads either everything requested,
+        * or nothing. */
+{
+       if (!len)
+               return true;
+
+       if (nonblocking && !setnonblock(fd, 1))
+               return false;
+
+       while (len) {
+               int done;
+
+               done = read(fd, data, len);
+               if (done < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       goto out_false;
+               }
+               if (done == 0) {
+                       /* It closed fd on us?  EBADF is appropriate. */
+                       errno = EBADF;
+                       goto out_false;
+               }
+               data += done;
+               len -= done;
+
+               if (nonblocking) {
+                       nonblocking = 0;
+                       if (!setnonblock(fd, 0))
+                               goto out_false;
+               }
+       }
+
+       return true;
+
+out_false:
+       if (nonblocking)
+               setnonblock(fd, 0);
+       return false;
+}
+
+#ifdef XSTEST
+#define read_all read_all_choice
+#define xs_write_all write_all_choice
+#endif
+
+static int get_error(const char *errorstring)
+{
+       unsigned int i;
+
+       for (i = 0; !streq(errorstring, xsd_errors[i].errstring); i++)
+               if (i == ARRAY_SIZE(xsd_errors) - 1)
+                       return EINVAL;
+       return xsd_errors[i].errnum;
+}
+
+/* Adds extra nul terminator, because we generally (always?) hold strings. */
+static void *read_reply(
+       struct xs_handle *h, enum xsd_sockmsg_type *type, unsigned int *len)
+{
+       struct xs_stored_msg *msg;
+       char *body;
+       int read_from_thread;
+
+       read_from_thread = read_thread_exists(h);
+
+       /* Read from comms channel ourselves if there is no reader thread. */
+       if (!read_from_thread && (read_message(h, 0) == -1))
+               return NULL;
+
+       mutex_lock(&h->reply_mutex);
+#ifdef USE_PTHREAD
+       while (list_empty(&h->reply_list) && read_from_thread && h->fd != -1)
+               condvar_wait(&h->reply_condvar, &h->reply_mutex);
+#endif
+       if (list_empty(&h->reply_list)) {
+               mutex_unlock(&h->reply_mutex);
+               errno = EINVAL;
+               return NULL;
+       }
+       msg = list_top(&h->reply_list, struct xs_stored_msg, list);
+       list_del(&msg->list);
+       assert(list_empty(&h->reply_list));
+       mutex_unlock(&h->reply_mutex);
+
+       *type = msg->hdr.type;
+       if (len)
+               *len = msg->hdr.len;
+       body = msg->body;
+
+       free(msg);
+
+       return body;
+}
+
+/* Send message to xs, get malloc'ed reply.  NULL and set errno on error. */
+static void *xs_talkv(struct xs_handle *h, xs_transaction_t t,
+                     enum xsd_sockmsg_type type,
+                     const struct iovec *iovec,
+                     unsigned int num_vecs,
+                     unsigned int *len)
+{
+       struct xsd_sockmsg msg;
+       void *ret = NULL;
+       int saved_errno;
+       unsigned int i;
+       struct sigaction ignorepipe, oldact;
+
+       msg.tx_id = t;
+       msg.req_id = 0;
+       msg.type = type;
+       msg.len = 0;
+       for (i = 0; i < num_vecs; i++)
+               msg.len += iovec[i].iov_len;
+
+       if (msg.len > XENSTORE_PAYLOAD_MAX) {
+               errno = E2BIG;
+               return 0;
+       }
+
+       ignorepipe.sa_handler = SIG_IGN;
+       sigemptyset(&ignorepipe.sa_mask);
+       ignorepipe.sa_flags = 0;
+       sigaction(SIGPIPE, &ignorepipe, &oldact);
+
+       mutex_lock(&h->request_mutex);
+
+       if (!xs_write_all(h->fd, &msg, sizeof(msg)))
+               goto fail;
+
+       for (i = 0; i < num_vecs; i++)
+               if (!xs_write_all(h->fd, iovec[i].iov_base, iovec[i].iov_len))
+                       goto fail;
+
+       ret = read_reply(h, &msg.type, len);
+       if (!ret)
+               goto fail;
+
+       mutex_unlock(&h->request_mutex);
+
+       sigaction(SIGPIPE, &oldact, NULL);
+       if (msg.type == XS_ERROR) {
+               saved_errno = get_error(ret);
+               free(ret);
+               errno = saved_errno;
+               return NULL;
+       }
+
+       if (msg.type != type) {
+               free(ret);
+               saved_errno = EBADF;
+               goto close_fd;
+       }
+       return ret;
+
+fail:
+       /* We're in a bad state, so close fd. */
+       saved_errno = errno;
+       mutex_unlock(&h->request_mutex);
+       sigaction(SIGPIPE, &oldact, NULL);
+close_fd:
+       close(h->fd);
+       h->fd = -1;
+       errno = saved_errno;
+       return NULL;
+}
+
+/* free(), but don't change errno. */
+static void free_no_errno(void *p)
+{
+       int saved_errno = errno;
+       free(p);
+       errno = saved_errno;
+}
+
+/* Simplified version of xs_talkv: single message. */
+static void *xs_single(struct xs_handle *h, xs_transaction_t t,
+                      enum xsd_sockmsg_type type,
+                      const char *string,
+                      unsigned int *len)
+{
+       struct iovec iovec;
+
+       iovec.iov_base = (void *)string;
+       iovec.iov_len = strlen(string) + 1;
+       return xs_talkv(h, t, type, &iovec, 1, len);
+}
+
+static bool xs_bool(char *reply)
+{
+       if (!reply)
+               return false;
+       free(reply);
+       return true;
+}
+
+static char **xs_directory_common(char *strings, unsigned int len,
+                                 unsigned int *num)
+{
+       char *p, **ret;
+
+       /* Count the strings. */
+       *num = xs_count_strings(strings, len);
+
+       /* Transfer to one big alloc for easy freeing. */
+       ret = malloc(*num * sizeof(char *) + len);
+       if (!ret) {
+               free_no_errno(strings);
+               return NULL;
+       }
+       memcpy(&ret[*num], strings, len);
+       free_no_errno(strings);
+
+       strings = (char *)&ret[*num];
+       for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1)
+               ret[(*num)++] = p;
+       return ret;
+}
+
+static char **xs_directory_part(struct xs_handle *h, xs_transaction_t t,
+                               const char *path, unsigned int *num)
+{
+       unsigned int off, result_len;
+       char gen[24], offstr[8];
+       struct iovec iovec[2];
+       char *result = NULL, *strings = NULL;
+
+       memset(gen, 0, sizeof(gen));
+       iovec[0].iov_base = (void *)path;
+       iovec[0].iov_len = strlen(path) + 1;
+
+       for (off = 0;;) {
+               snprintf(offstr, sizeof(offstr), "%u", off);
+               iovec[1].iov_base = (void *)offstr;
+               iovec[1].iov_len = strlen(offstr) + 1;
+               result = xs_talkv(h, t, XS_DIRECTORY_PART, iovec, 2,
+                                 &result_len);
+
+               /* If XS_DIRECTORY_PART isn't supported return E2BIG. */
+               if (!result) {
+                       if (errno == ENOSYS)
+                               errno = E2BIG;
+                       return NULL;
+               }
+
+               if (off) {
+                       if (strcmp(gen, result)) {
+                               free(result);
+                               free(strings);
+                               strings = NULL;
+                               off = 0;
+                               continue;
+                       }
+               } else
+                       strncpy(gen, result, sizeof(gen) - 1);
+
+               result_len -= strlen(result) + 1;
+               strings = realloc(strings, off + result_len);
+               memcpy(strings + off, result + strlen(result) + 1, result_len);
+               free(result);
+               off += result_len;
+
+               if (off <= 1 || strings[off - 2] == 0)
+                       break;
+       }
+
+       if (off > 1)
+               off--;
+
+       return xs_directory_common(strings, off, num);
+}
+
+char **xs_directory(struct xs_handle *h, xs_transaction_t t,
+                   const char *path, unsigned int *num)
+{
+       char *strings;
+       unsigned int len;
+
+       strings = xs_single(h, t, XS_DIRECTORY, path, &len);
+       if (!strings) {
+               if (errno != E2BIG)
+                       return NULL;
+               return xs_directory_part(h, t, path, num);
+       }
+
+       return xs_directory_common(strings, len, num);
+}
+
+/* Get the value of a single file, nul terminated.
+ * Returns a malloced value: call free() on it after use.
+ * len indicates length in bytes, not including the nul.
+ * Returns NULL on failure.
+ */
+void *xs_read(struct xs_handle *h, xs_transaction_t t,
+             const char *path, unsigned int *len)
+{
+       return xs_single(h, t, XS_READ, path, len);
+}
+
+/* Write the value of a single file.
+ * Returns false on failure.
+ */
+bool xs_write(struct xs_handle *h, xs_transaction_t t,
+             const char *path, const void *data, unsigned int len)
+{
+       struct iovec iovec[2];
+
+       iovec[0].iov_base = (void *)path;
+       iovec[0].iov_len = strlen(path) + 1;
+       iovec[1].iov_base = (void *)data;
+       iovec[1].iov_len = len;
+
+       return xs_bool(xs_talkv(h, t, XS_WRITE, iovec,
+                               ARRAY_SIZE(iovec), NULL));
+}
+
+/* Create a new directory.
+ * Returns false on failure, or success if it already exists.
+ */
+bool xs_mkdir(struct xs_handle *h, xs_transaction_t t,
+             const char *path)
+{
+       return xs_bool(xs_single(h, t, XS_MKDIR, path, NULL));
+}
+
+/* Destroy a file or directory (directories must be empty).
+ * Returns false on failure, or success if it doesn't exist.
+ */
+bool xs_rm(struct xs_handle *h, xs_transaction_t t,
+          const char *path)
+{
+       return xs_bool(xs_single(h, t, XS_RM, path, NULL));
+}
+
+/* Get permissions of node (first element is owner).
+ * Returns malloced array, or NULL: call free() after use.
+ */
+struct xs_permissions *xs_get_permissions(struct xs_handle *h,
+                                         xs_transaction_t t,
+                                         const char *path, unsigned int *num)
+{
+       char *strings;
+       unsigned int len;
+       struct xs_permissions *ret;
+
+       strings = xs_single(h, t, XS_GET_PERMS, path, &len);
+       if (!strings)
+               return NULL;
+
+       /* Count the strings: each one perms then domid. */
+       *num = xs_count_strings(strings, len);
+
+       /* Transfer to one big alloc for easy freeing. */
+       ret = malloc(*num * sizeof(struct xs_permissions));
+       if (!ret) {
+               free_no_errno(strings);
+               return NULL;
+       }
+
+       if (!xs_strings_to_perms(ret, *num, strings)) {
+               free_no_errno(ret);
+               ret = NULL;
+       }
+
+       free(strings);
+       return ret;
+}
+
+/* Set permissions of node (must be owner).
+ * Returns false on failure.
+ */
+bool xs_set_permissions(struct xs_handle *h,
+                       xs_transaction_t t,
+                       const char *path,
+                       struct xs_permissions *perms,
+                       unsigned int num_perms)
+{
+       unsigned int i;
+       struct iovec iov[1+num_perms];
+
+       iov[0].iov_base = (void *)path;
+       iov[0].iov_len = strlen(path) + 1;
+       
+       for (i = 0; i < num_perms; i++) {
+               char buffer[MAX_STRLEN(unsigned int)+1];
+
+               if (!xs_perm_to_string(&perms[i], buffer, sizeof(buffer)))
+                       goto unwind;
+
+               iov[i+1].iov_base = strdup(buffer);
+               iov[i+1].iov_len = strlen(buffer) + 1;
+               if (!iov[i+1].iov_base)
+                       goto unwind;
+       }
+
+       if (!xs_bool(xs_talkv(h, t, XS_SET_PERMS, iov, 1+num_perms, NULL)))
+               goto unwind;
+       for (i = 0; i < num_perms; i++)
+               free(iov[i+1].iov_base);
+       return true;
+
+unwind:
+       num_perms = i;
+       for (i = 0; i < num_perms; i++)
+               free_no_errno(iov[i+1].iov_base);
+       return false;
+}
+
+/* Always return false a functionality has been removed in Xen 4.9 */
+bool xs_restrict(struct xs_handle *h, unsigned domid)
+{
+       return false;
+}
+
+/* Watch a node for changes (poll on fd to detect, or call read_watch()).
+ * When the node (or any child) changes, fd will become readable.
+ * Token is returned when watch is read, to allow matching.
+ * Returns false on failure.
+ */
+bool xs_watch(struct xs_handle *h, const char *path, const char *token)
+{
+       struct iovec iov[2];
+
+#ifdef USE_PTHREAD
+#define DEFAULT_THREAD_STACKSIZE (16 * 1024)
+#define READ_THREAD_STACKSIZE                                  \
+       ((DEFAULT_THREAD_STACKSIZE < PTHREAD_STACK_MIN) ?       \
+       PTHREAD_STACK_MIN : DEFAULT_THREAD_STACKSIZE)
+
+       /* We dynamically create a reader thread on demand. */
+       mutex_lock(&h->request_mutex);
+       if (!h->read_thr_exists) {
+               sigset_t set, old_set;
+               pthread_attr_t attr;
+               static size_t stack_size;
+#ifdef USE_DLSYM
+               size_t (*getsz)(pthread_attr_t *attr);
+#endif
+
+               if (pthread_attr_init(&attr) != 0) {
+                       mutex_unlock(&h->request_mutex);
+                       return false;
+               }
+               if (!stack_size) {
+#ifdef USE_DLSYM
+                       getsz = dlsym(RTLD_DEFAULT, "__pthread_get_minstack");
+                       if (getsz)
+                               stack_size = getsz(&attr);
+#endif
+                       if (stack_size < READ_THREAD_STACKSIZE)
+                               stack_size = READ_THREAD_STACKSIZE;
+               }
+               if (pthread_attr_setstacksize(&attr, stack_size) != 0) {
+                       pthread_attr_destroy(&attr);
+                       mutex_unlock(&h->request_mutex);
+                       return false;
+               }
+
+               sigfillset(&set);
+               pthread_sigmask(SIG_SETMASK, &set, &old_set);
+
+               if (pthread_create(&h->read_thr, &attr, read_thread, h) != 0) {
+                       pthread_sigmask(SIG_SETMASK, &old_set, NULL);
+                       pthread_attr_destroy(&attr);
+                       mutex_unlock(&h->request_mutex);
+                       return false;
+               }
+               h->read_thr_exists = 1;
+               pthread_sigmask(SIG_SETMASK, &old_set, NULL);
+               pthread_attr_destroy(&attr);
+       }
+       mutex_unlock(&h->request_mutex);
+#endif
+
+       iov[0].iov_base = (void *)path;
+       iov[0].iov_len = strlen(path) + 1;
+       iov[1].iov_base = (void *)token;
+       iov[1].iov_len = strlen(token) + 1;
+
+       return xs_bool(xs_talkv(h, XBT_NULL, XS_WATCH, iov,
+                               ARRAY_SIZE(iov), NULL));
+}
+
+
+/* Clear the pipe token if there are no more pending watchs.
+ * We suppose the watch_mutex is already taken.
+ */
+static void xs_maybe_clear_watch_pipe(struct xs_handle *h)
+{
+       char c;
+
+       if (list_empty(&h->watch_list) && (h->watch_pipe[0] != -1))
+               while (read(h->watch_pipe[0], &c, 1) != 1)
+                       continue;
+}
+
+/* Find out what node change was on (will block if nothing pending).
+ * Returns array of two pointers: path and token, or NULL.
+ * Call free() after use.
+ */
+static char **read_watch_internal(struct xs_handle *h, unsigned int *num,
+                                 int nonblocking)
+{
+       struct xs_stored_msg *msg;
+       char **ret, *strings;
+       unsigned int num_strings, i;
+
+       mutex_lock(&h->watch_mutex);
+
+#ifdef USE_PTHREAD
+       /* Wait on the condition variable for a watch to fire.
+        * If the reader thread doesn't exist yet, then that's because
+        * we haven't called xs_watch.  Presumably the application
+        * will do so later; in the meantime we just block.
+        */
+       while (list_empty(&h->watch_list) && h->fd != -1) {
+               if (nonblocking) {
+                       mutex_unlock(&h->watch_mutex);
+                       errno = EAGAIN;
+                       return 0;
+               }
+               condvar_wait(&h->watch_condvar, &h->watch_mutex);
+       }
+#else /* !defined(USE_PTHREAD) */
+       /* Read from comms channel ourselves if there are no threads
+        * and therefore no reader thread. */
+
+       assert(!read_thread_exists(h)); /* not threadsafe but worth a check */
+       if ((read_message(h, nonblocking) == -1))
+               return NULL;
+
+#endif /* !defined(USE_PTHREAD) */
+
+       if (list_empty(&h->watch_list)) {
+               mutex_unlock(&h->watch_mutex);
+               errno = EINVAL;
+               return NULL;
+       }
+       msg = list_top(&h->watch_list, struct xs_stored_msg, list);
+       list_del(&msg->list);
+
+       xs_maybe_clear_watch_pipe(h);
+       mutex_unlock(&h->watch_mutex);
+
+       assert(msg->hdr.type == XS_WATCH_EVENT);
+
+       strings     = msg->body;
+       num_strings = xs_count_strings(strings, msg->hdr.len);
+
+       ret = malloc(sizeof(char*) * num_strings + msg->hdr.len);
+       if (!ret) {
+               free_no_errno(strings);
+               free_no_errno(msg);
+               return NULL;
+       }
+
+       ret[0] = (char *)(ret + num_strings);
+       memcpy(ret[0], strings, msg->hdr.len);
+
+       free(strings);
+       free(msg);
+
+       for (i = 1; i < num_strings; i++)
+               ret[i] = ret[i - 1] + strlen(ret[i - 1]) + 1;
+
+       *num = num_strings;
+
+       return ret;
+}
+
+char **xs_check_watch(struct xs_handle *h)
+{
+       unsigned int num;
+       char **ret;
+       ret = read_watch_internal(h, &num, 1);
+       if (ret) assert(num >= 2);
+       return ret;
+}
+
+/* Find out what node change was on (will block if nothing pending).
+ * Returns array of two pointers: path and token, or NULL.
+ * Call free() after use.
+ */
+char **xs_read_watch(struct xs_handle *h, unsigned int *num)
+{
+       return read_watch_internal(h, num, 0);
+}
+
+/* Remove a watch on a node.
+ * Returns false on failure (no watch on that node).
+ */
+bool xs_unwatch(struct xs_handle *h, const char *path, const char *token)
+{
+       struct iovec iov[2];
+       struct xs_stored_msg *msg, *tmsg;
+       bool res;
+       char *s, *p;
+       unsigned int i;
+       char *l_token, *l_path;
+
+       iov[0].iov_base = (char *)path;
+       iov[0].iov_len = strlen(path) + 1;
+       iov[1].iov_base = (char *)token;
+       iov[1].iov_len = strlen(token) + 1;
+
+       res = xs_bool(xs_talkv(h, XBT_NULL, XS_UNWATCH, iov,
+                              ARRAY_SIZE(iov), NULL));
+
+       if (!h->unwatch_filter) /* Don't filter the watch list */
+               return res;
+
+
+       /* Filter the watch list to remove potential message */
+       mutex_lock(&h->watch_mutex);
+
+       if (list_empty(&h->watch_list)) {
+               mutex_unlock(&h->watch_mutex);
+               return res;
+       }
+
+       list_for_each_entry_safe(msg, tmsg, &h->watch_list, list) {
+               assert(msg->hdr.type == XS_WATCH_EVENT);
+
+               s = msg->body;
+
+               l_token = NULL;
+               l_path = NULL;
+
+               for (p = s, i = 0; p < msg->body + msg->hdr.len; p++) {
+                       if (*p == '\0')
+                       {
+                               if (i == XS_WATCH_TOKEN)
+                                       l_token = s;
+                               else if (i == XS_WATCH_PATH)
+                                       l_path = s;
+                               i++;
+                               s = p + 1;
+                       }
+               }
+
+               if (l_token && !strcmp(token, l_token) &&
+                   l_path && xs_path_is_subpath(path, l_path)) {
+                       list_del(&msg->list);
+                       free(msg);
+               }
+       }
+
+       xs_maybe_clear_watch_pipe(h);
+
+       mutex_unlock(&h->watch_mutex);
+
+       return res;
+}
+
+/* Start a transaction: changes by others will not be seen during this
+ * transaction, and changes will not be visible to others until end.
+ * Returns XBT_NULL on failure.
+ */
+xs_transaction_t xs_transaction_start(struct xs_handle *h)
+{
+       char *id_str;
+       xs_transaction_t id;
+
+       id_str = xs_single(h, XBT_NULL, XS_TRANSACTION_START, "", NULL);
+       if (id_str == NULL)
+               return XBT_NULL;
+
+       id = strtoul(id_str, NULL, 0);
+       free(id_str);
+
+       return id;
+}
+
+/* End a transaction.
+ * If abandon is true, transaction is discarded instead of committed.
+ * Returns false on failure, which indicates an error: transactions will
+ * not fail spuriously.
+ */
+bool xs_transaction_end(struct xs_handle *h, xs_transaction_t t,
+                       bool abort)
+{
+       char abortstr[2];
+
+       if (abort)
+               strcpy(abortstr, "F");
+       else
+               strcpy(abortstr, "T");
+       
+       return xs_bool(xs_single(h, t, XS_TRANSACTION_END, abortstr, NULL));
+}
+
+/* Introduce a new domain.
+ * This tells the store daemon about a shared memory page and event channel
+ * associated with a domain: the domain uses these to communicate.
+ */
+bool xs_introduce_domain(struct xs_handle *h,
+                        unsigned int domid, unsigned long mfn,
+                        unsigned int eventchn)
+{
+       char domid_str[MAX_STRLEN(domid)];
+       char mfn_str[MAX_STRLEN(mfn)];
+       char eventchn_str[MAX_STRLEN(eventchn)];
+       struct iovec iov[3];
+
+       snprintf(domid_str, sizeof(domid_str), "%u", domid);
+       snprintf(mfn_str, sizeof(mfn_str), "%lu", mfn);
+       snprintf(eventchn_str, sizeof(eventchn_str), "%u", eventchn);
+
+       iov[0].iov_base = domid_str;
+       iov[0].iov_len = strlen(domid_str) + 1;
+       iov[1].iov_base = mfn_str;
+       iov[1].iov_len = strlen(mfn_str) + 1;
+       iov[2].iov_base = eventchn_str;
+       iov[2].iov_len = strlen(eventchn_str) + 1;
+
+       return xs_bool(xs_talkv(h, XBT_NULL, XS_INTRODUCE, iov,
+                               ARRAY_SIZE(iov), NULL));
+}
+
+bool xs_set_target(struct xs_handle *h,
+                        unsigned int domid, unsigned int target)
+{
+       char domid_str[MAX_STRLEN(domid)];
+       char target_str[MAX_STRLEN(target)];
+       struct iovec iov[2];
+
+       snprintf(domid_str, sizeof(domid_str), "%u", domid);
+       snprintf(target_str, sizeof(target_str), "%u", target);
+
+       iov[0].iov_base = domid_str;
+       iov[0].iov_len = strlen(domid_str) + 1;
+       iov[1].iov_base = target_str;
+       iov[1].iov_len = strlen(target_str) + 1;
+
+       return xs_bool(xs_talkv(h, XBT_NULL, XS_SET_TARGET, iov,
+                               ARRAY_SIZE(iov), NULL));
+}
+
+static void * single_with_domid(struct xs_handle *h,
+                               enum xsd_sockmsg_type type,
+                               unsigned int domid)
+{
+       char domid_str[MAX_STRLEN(domid)];
+
+       snprintf(domid_str, sizeof(domid_str), "%u", domid);
+
+       return xs_single(h, XBT_NULL, type, domid_str, NULL);
+}
+
+bool xs_release_domain(struct xs_handle *h, unsigned int domid)
+{
+       return xs_bool(single_with_domid(h, XS_RELEASE, domid));
+}
+
+/* clear the shutdown bit for the given domain */
+bool xs_resume_domain(struct xs_handle *h, unsigned int domid)
+{
+       return xs_bool(single_with_domid(h, XS_RESUME, domid));
+}
+
+char *xs_get_domain_path(struct xs_handle *h, unsigned int domid)
+{
+       char domid_str[MAX_STRLEN(domid)];
+
+       snprintf(domid_str, sizeof(domid_str), "%u", domid);
+
+       return xs_single(h, XBT_NULL, XS_GET_DOMAIN_PATH, domid_str, NULL);
+}
+
+bool xs_path_is_subpath(const char *parent, const char *child)
+{
+        size_t childlen = strlen(child);
+        size_t parentlen = strlen(parent);
+
+       if (childlen < parentlen)
+               return false;
+
+       if (memcmp(child, parent, parentlen))
+               return false;
+
+       if (childlen > parentlen && child[parentlen] != '/')
+               return false;
+
+       return true;
+}
+
+bool xs_is_domain_introduced(struct xs_handle *h, unsigned int domid)
+{
+       char *domain = single_with_domid(h, XS_IS_DOMAIN_INTRODUCED, domid);
+       int rc = strcmp("F", domain);
+
+       free(domain);
+       return rc;
+}
+
+int xs_suspend_evtchn_port(int domid)
+{
+    char path[128];
+    char *portstr;
+    int port;
+    unsigned int plen;
+    struct xs_handle *xs;
+
+    xs = xs_daemon_open();
+    if (!xs)
+        return -1;
+
+    sprintf(path, "/local/domain/%d/device/suspend/event-channel", domid);
+    portstr = xs_read(xs, XBT_NULL, path, &plen);
+    xs_daemon_close(xs);
+
+    if (!portstr || !plen) {
+        port = -1;
+        goto out;
+    }
+
+    port = atoi(portstr);
+
+out:
+    free(portstr);
+    return port;
+}
+
+char *xs_control_command(struct xs_handle *h, const char *cmd,
+                        void *data, unsigned int len)
+{
+       struct iovec iov[2];
+
+       iov[0].iov_base = (void *)cmd;
+       iov[0].iov_len = strlen(cmd) + 1;
+       iov[1].iov_base = data;
+       iov[1].iov_len = len;
+
+       return xs_talkv(h, XBT_NULL, XS_CONTROL, iov,
+                       ARRAY_SIZE(iov), NULL);
+}
+
+char *xs_debug_command(struct xs_handle *h, const char *cmd,
+                      void *data, unsigned int len)
+{
+       return xs_control_command(h, cmd, data, len);
+}
+
+static int read_message(struct xs_handle *h, int nonblocking)
+{
+       /* IMPORTANT: It is forbidden to call this function without
+        * acquiring the request lock and checking that h->read_thr_exists
+        * is false.  See "Lock discipline" in struct xs_handle, above. */
+
+       /* If nonblocking==1, this function will always read either
+        * nothing, returning -1 and setting errno==EAGAIN, or we read
+        * whole amount requested.  Ie as soon as we have the start of
+        * the message we block until we get all of it.
+        */
+         
+       struct xs_stored_msg *msg = NULL;
+       char *body = NULL;
+       int saved_errno = 0;
+       int ret = -1;
+
+       /* Allocate message structure and read the message header. */
+       msg = malloc(sizeof(*msg));
+       if (msg == NULL)
+               goto error;
+       cleanup_push_heap(msg);
+       if (!read_all(h->fd, &msg->hdr, sizeof(msg->hdr), nonblocking)) { /* 
Cancellation point */
+               saved_errno = errno;
+               goto error_freemsg;
+       }
+
+       /* Sanity check message body length. */
+       if (msg->hdr.len > XENSTORE_PAYLOAD_MAX) {
+               saved_errno = E2BIG;
+               goto error_freemsg;
+       }
+
+       /* Allocate and read the message body. */
+       body = msg->body = malloc(msg->hdr.len + 1);
+       if (body == NULL)
+               goto error_freemsg;
+       cleanup_push_heap(body);
+       if (!read_all(h->fd, body, msg->hdr.len, 0)) { /* Cancellation point */
+               saved_errno = errno;
+               goto error_freebody;
+       }
+
+       body[msg->hdr.len] = '\0';
+
+       if (msg->hdr.type == XS_WATCH_EVENT) {
+               mutex_lock(&h->watch_mutex);
+               cleanup_push(pthread_mutex_unlock, &h->watch_mutex);
+
+               /* Kick users out of their select() loop. */
+               if (list_empty(&h->watch_list) &&
+                   (h->watch_pipe[1] != -1))
+                       while (write(h->watch_pipe[1], body, 1) != 1) /* 
Cancellation point */
+                               continue;
+
+               list_add_tail(&msg->list, &h->watch_list);
+
+               condvar_signal(&h->watch_condvar);
+
+               cleanup_pop(1);
+       } else {
+               mutex_lock(&h->reply_mutex);
+
+               /* There should only ever be one response pending! */
+               if (!list_empty(&h->reply_list)) {
+                       mutex_unlock(&h->reply_mutex);
+                       saved_errno = EEXIST;
+                       goto error_freebody;
+               }
+
+               list_add_tail(&msg->list, &h->reply_list);
+               condvar_signal(&h->reply_condvar);
+
+               mutex_unlock(&h->reply_mutex);
+       }
+
+       ret = 0;
+
+error_freebody:
+       cleanup_pop_heap(ret == -1, body);
+error_freemsg:
+       cleanup_pop_heap(ret == -1, msg);
+error:
+       errno = saved_errno;
+
+       return ret;
+}
+
+#ifdef USE_PTHREAD
+static void *read_thread(void *arg)
+{
+       struct xs_handle *h = arg;
+       int fd;
+
+       while (read_message(h, 0) != -1)
+               continue;
+
+       /* An error return from read_message leaves the socket in an undefined
+        * state; we might have read only the header and not the message after
+        * it, or (more commonly) the other end has closed the connection.
+        * Since further communication is unsafe, close the socket.
+        */
+       fd = h->fd;
+       h->fd = -1;
+       close(fd);
+
+       /* wake up all waiters */
+       pthread_mutex_lock(&h->reply_mutex);
+       pthread_cond_broadcast(&h->reply_condvar);
+       pthread_mutex_unlock(&h->reply_mutex);
+
+       pthread_mutex_lock(&h->watch_mutex);
+       pthread_cond_broadcast(&h->watch_condvar);
+       pthread_mutex_unlock(&h->watch_mutex);
+
+       return NULL;
+}
+#endif
+
+char *expanding_buffer_ensure(struct expanding_buffer *ebuf, int min_avail)
+{
+       int want;
+       char *got;
+
+       if (ebuf->avail >= min_avail)
+               return ebuf->buf;
+
+       if (min_avail >= INT_MAX/3)
+               return 0;
+
+       want = ebuf->avail + min_avail + 10;
+       got = realloc(ebuf->buf, want);
+       if (!got)
+               return 0;
+
+       ebuf->buf = got;
+       ebuf->avail = want;
+       return ebuf->buf;
+}
+
+char *sanitise_value(struct expanding_buffer *ebuf,
+                    const char *val, unsigned len)
+{
+       int used, remain, c;
+       unsigned char *ip;
+
+#define ADD(c) (ebuf->buf[used++] = (c))
+#define ADDF(f,c) (used += sprintf(ebuf->buf+used, (f), (c)))
+
+       assert(len < INT_MAX/5);
+
+       ip = (unsigned char *)val;
+       used = 0;
+       remain = len;
+
+       if (!expanding_buffer_ensure(ebuf, remain + 1))
+               return NULL;
+
+       while (remain-- > 0) {
+               c= *ip++;
+
+               if (c >= ' ' && c <= '~' && c != '\\') {
+                       ADD(c);
+                       continue;
+               }
+
+               if (!expanding_buffer_ensure(ebuf, used + remain + 5))
+                       /* for "<used>\\nnn<remain>\0" */
+                       return 0;
+
+               ADD('\\');
+               switch (c) {
+               case '\t':  ADD('t');   break;
+               case '\n':  ADD('n');   break;
+               case '\r':  ADD('r');   break;
+               case '\\':  ADD('\\');  break;
+               default:
+                       if (c < 010) ADDF("%03o", c);
+                       else         ADDF("x%02x", c);
+               }
+       }
+
+       ADD(0);
+       assert(used <= ebuf->avail);
+       return ebuf->buf;
+
+#undef ADD
+#undef ADDF
+}
+
+void unsanitise_value(char *out, unsigned *out_len_r, const char *in)
+{
+       const char *ip;
+       char *op;
+       unsigned c;
+       int n;
+
+       for (ip = in, op = out; (c = *ip++); *op++ = c) {
+               if (c == '\\') {
+                       c = *ip++;
+
+#define GETF(f) do {                                   \
+                       n = 0;                          \
+                       sscanf(ip, f "%n", &c, &n);     \
+                       ip += n;                        \
+               } while (0)
+
+                       switch (c) {
+                       case 't':              c= '\t';            break;
+                       case 'n':              c= '\n';            break;
+                       case 'r':              c= '\r';            break;
+                       case '\\':             c= '\\';            break;
+                       case 'x':                    GETF("%2x");  break;
+                       case '0': case '4':
+                       case '1': case '5':
+                       case '2': case '6':
+                       case '3': case '7':    --ip; GETF("%3o");  break;
+                       case 0:                --ip;               break;
+                       default:;
+                       }
+#undef GETF
+               }
+       }
+
+       *op = 0;
+
+       if (out_len_r)
+               *out_len_r = op - out;
+}
+
+/*
+ * Local variables:
+ *  mode: C
+ *  c-file-style: "linux"
+ *  indent-tabs-mode: t
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/tools/libs/uselibs.mk b/tools/libs/uselibs.mk
index 9619c576ba..a0fe0402ff 100644
--- a/tools/libs/uselibs.mk
+++ b/tools/libs/uselibs.mk
@@ -20,3 +20,5 @@ LIBS_LIBS += ctrl
 USELIBS_ctrl := toollog call evtchn gnttab foreignmemory devicemodel
 LIBS_LIBS += guest
 USELIBS_guest := evtchn ctrl
+LIBS_LIBS += store
+USELIBS_store := toolcore
diff --git a/tools/python/setup.py b/tools/python/setup.py
index 24b284af39..8254464aff 100644
--- a/tools/python/setup.py
+++ b/tools/python/setup.py
@@ -11,7 +11,7 @@ PATH_LIBXENTOOLLOG = XEN_ROOT + "/tools/libs/toollog"
 PATH_LIBXENEVTCHN = XEN_ROOT + "/tools/libs/evtchn"
 PATH_LIBXENCTRL = XEN_ROOT + "/tools/libs/ctrl"
 PATH_LIBXL    = XEN_ROOT + "/tools/libxl"
-PATH_XENSTORE = XEN_ROOT + "/tools/xenstore"
+PATH_XENSTORE = XEN_ROOT + "/tools/libs/store"
 
 xc = Extension("xc",
                extra_compile_args = extra_compile_args,
diff --git a/tools/xenstore/Makefile b/tools/xenstore/Makefile
index 574be8d15c..9a0f0d012d 100644
--- a/tools/xenstore/Makefile
+++ b/tools/xenstore/Makefile
@@ -34,17 +34,7 @@ XENSTORED_OBJS_$(CONFIG_MiniOS) = xenstored_minios.o
 XENSTORED_OBJS += $(XENSTORED_OBJS_y)
 LDLIBS_xenstored += -lrt
 
-ifneq ($(XENSTORE_STATIC_CLIENTS),y)
-LIBXENSTORE := libxenstore.so
-else
-LIBXENSTORE := libxenstore.a
-xenstore xenstore-control: CFLAGS += -static
-endif
-
-ALL_TARGETS = libxenstore.a clients
-ifneq ($(nosharedlibs),y)
-ALL_TARGETS += libxenstore.so
-endif
+ALL_TARGETS = clients
 ifeq ($(XENSTORE_XENSTORED),y)
 ALL_TARGETS += xs_tdb_dump xenstored
 endif
@@ -87,64 +77,21 @@ xenstored.a: $(XENSTORED_OBJS)
 $(CLIENTS): xenstore
        ln -f xenstore $@
 
-xenstore: xenstore_client.o $(LIBXENSTORE)
+xenstore: xenstore_client.o
        $(CC) $< $(LDFLAGS) $(LDLIBS_libxenstore) $(LDLIBS_libxentoolcore) 
$(SOCKET_LIBS) -o $@ $(APPEND_LDFLAGS)
 
-xenstore-control: xenstore_control.o $(LIBXENSTORE)
+xenstore-control: xenstore_control.o
        $(CC) $< $(LDFLAGS) $(LDLIBS_libxenstore) $(LDLIBS_libxentoolcore) 
$(SOCKET_LIBS) -o $@ $(APPEND_LDFLAGS)
 
 xs_tdb_dump: xs_tdb_dump.o utils.o tdb.o talloc.o
        $(CC) $^ $(LDFLAGS) -o $@ $(APPEND_LDFLAGS)
 
-libxenstore.so: libxenstore.so.$(MAJOR)
-       ln -sf $< $@
-libxenstore.so.$(MAJOR): libxenstore.so.$(MAJOR).$(MINOR)
-       ln -sf $< $@
-
-xs.opic: CFLAGS += -DUSE_PTHREAD
-ifeq ($(CONFIG_Linux),y)
-xs.opic: CFLAGS += -DUSE_DLSYM
-libxenstore.so.$(MAJOR).$(MINOR): APPEND_LDFLAGS += -ldl
-PKG_CONFIG_LIBSPRIV := -ldl
-endif
-
-libxenstore.so.$(MAJOR).$(MINOR): xs.opic xs_lib.opic
-       $(CC) $(LDFLAGS) $(PTHREAD_LDFLAGS) -Wl,$(SONAME_LDFLAG) 
-Wl,libxenstore.so.$(MAJOR) $(SHLIB_LDFLAGS) -o $@ $^ $(LDLIBS_libxentoolcore) 
$(SOCKET_LIBS) $(PTHREAD_LIBS) $(APPEND_LDFLAGS)
-
-libxenstore.a: xs.o xs_lib.o
-       $(AR) rcs $@ $^
-
-PKG_CONFIG := xenstore.pc
-PKG_CONFIG_NAME := Xenstore
-PKG_CONFIG_DESC := The Xenstore library for Xen hypervisor
-PKG_CONFIG_VERSION := $(MAJOR).$(MINOR)
-PKG_CONFIG_USELIBS := $(SHLIB_libxenstore)
-PKG_CONFIG_LIB := xenstore
-PKG_CONFIG_REQPRIV := xenevtchn,xencontrol,xengnttab,xentoolcore
-
-ifneq ($(CONFIG_LIBXC_MINIOS),y)
-PKG_CONFIG_INST := $(PKG_CONFIG)
-$(PKG_CONFIG_INST): PKG_CONFIG_PREFIX = $(prefix)
-$(PKG_CONFIG_INST): PKG_CONFIG_INCDIR = $(includedir)
-$(PKG_CONFIG_INST): PKG_CONFIG_LIBDIR = $(libdir)
-endif
-
-PKG_CONFIG_LOCAL := $(foreach pc,$(PKG_CONFIG),$(PKG_CONFIG_DIR)/$(pc))
-
-$(PKG_CONFIG_LOCAL): PKG_CONFIG_PREFIX = $(XEN_ROOT)
-$(PKG_CONFIG_LOCAL): PKG_CONFIG_INCDIR = $(XEN_libxenstore)/include
-$(PKG_CONFIG_LOCAL): PKG_CONFIG_LIBDIR = $(CURDIR)
-$(PKG_CONFIG_LOCAL): PKG_CONFIG_CFLAGS_LOCAL = $(CFLAGS_xeninclude)
-
-$(LIBXENSTORE): $(PKG_CONFIG_INST) $(PKG_CONFIG_LOCAL)
-
 .PHONY: clean
 clean:
-       rm -f *.a *.o *.opic *.so* xenstored_probes.h
+       rm -f *.a *.o xenstored_probes.h
        rm -f xenstored xs_random xs_stress xs_crashme
        rm -f xs_tdb_dump xenstore-control init-xenstore-domain
        rm -f xenstore $(CLIENTS)
-       rm -f xenstore.pc
        $(RM) $(DEPS_RM)
 
 .PHONY: distclean
@@ -161,8 +108,6 @@ tarball: clean
 .PHONY: install
 install: all
        $(INSTALL_DIR) $(DESTDIR)$(bindir)
-       $(INSTALL_DIR) $(DESTDIR)$(includedir)
-       $(INSTALL_DIR) $(DESTDIR)$(includedir)/xenstore-compat
 ifeq ($(XENSTORE_XENSTORED),y)
        $(INSTALL_DIR) $(DESTDIR)$(sbindir)
        $(INSTALL_DIR) $(DESTDIR)$(XEN_LIB_STORED)
@@ -173,32 +118,9 @@ endif
        set -e ; for c in $(CLIENTS) ; do \
                ln -f $(DESTDIR)$(bindir)/xenstore $(DESTDIR)$(bindir)/$${c} ; \
        done
-       $(INSTALL_DIR) $(DESTDIR)$(libdir)
-       $(INSTALL_SHLIB) libxenstore.so.$(MAJOR).$(MINOR) $(DESTDIR)$(libdir)
-       ln -sf libxenstore.so.$(MAJOR).$(MINOR) 
$(DESTDIR)$(libdir)/libxenstore.so.$(MAJOR)
-       ln -sf libxenstore.so.$(MAJOR) $(DESTDIR)$(libdir)/libxenstore.so
-       $(INSTALL_DATA) libxenstore.a $(DESTDIR)$(libdir)
-       $(INSTALL_DATA) include/xenstore.h $(DESTDIR)$(includedir)
-       $(INSTALL_DATA) include/xenstore_lib.h $(DESTDIR)$(includedir)
-       $(INSTALL_DATA) include/compat/xs.h 
$(DESTDIR)$(includedir)/xenstore-compat/xs.h
-       $(INSTALL_DATA) include/compat/xs_lib.h 
$(DESTDIR)$(includedir)/xenstore-compat/xs_lib.h
-       ln -sf xenstore-compat/xs.h  $(DESTDIR)$(includedir)/xs.h
-       ln -sf xenstore-compat/xs_lib.h $(DESTDIR)$(includedir)/xs_lib.h
-       $(INSTALL_DATA) xenstore.pc $(DESTDIR)$(PKG_INSTALLDIR)
 
 .PHONY: uninstall
 uninstall:
-       rm -f $(DESTDIR)$(PKG_INSTALLDIR)/xenstore.pc
-       rm -f $(DESTDIR)$(includedir)/xs_lib.h
-       rm -f $(DESTDIR)$(includedir)/xs.h
-       rm -f $(DESTDIR)$(includedir)/xenstore-compat/xs_lib.h
-       rm -f $(DESTDIR)$(includedir)/xenstore-compat/xs.h
-       rm -f $(DESTDIR)$(includedir)/xenstore_lib.h
-       rm -f $(DESTDIR)$(includedir)/xenstore.h
-       rm -f $(DESTDIR)$(libdir)/libxenstore.a
-       rm -f $(DESTDIR)$(libdir)/libxenstore.so
-       rm -f $(DESTDIR)$(libdir)/libxenstore.so.$(MAJOR)
-       rm -f $(DESTDIR)$(libdir)/libxenstore.so.$(MAJOR).$(MINOR)
        rm -f $(addprefix $(DESTDIR)$(bindir)/, $(CLIENTS))
        rm -f $(DESTDIR)$(bindir)/xenstore
        rm -f $(DESTDIR)$(bindir)/xenstore-control
diff --git a/tools/xenstore/include/compat/xs.h 
b/tools/xenstore/include/compat/xs.h
deleted file mode 100644
index 99cf39bb1a..0000000000
--- a/tools/xenstore/include/compat/xs.h
+++ /dev/null
@@ -1,2 +0,0 @@
-#warning xs.h is deprecated use xenstore.h instead
-#include <xenstore.h>
diff --git a/tools/xenstore/include/compat/xs_lib.h 
b/tools/xenstore/include/compat/xs_lib.h
deleted file mode 100644
index ad81b54c0e..0000000000
--- a/tools/xenstore/include/compat/xs_lib.h
+++ /dev/null
@@ -1,2 +0,0 @@
-#warning xs_lib.h is deprecated use xenstore_lib.h instead
-#include <xenstore_lib.h>
diff --git a/tools/xenstore/include/xenstore.h 
b/tools/xenstore/include/xenstore.h
deleted file mode 100644
index 25b31881c8..0000000000
--- a/tools/xenstore/include/xenstore.h
+++ /dev/null
@@ -1,290 +0,0 @@
-/* 
-    Xen Store Daemon providing simple tree-like database.
-    Copyright (C) 2005 Rusty Russell IBM Corporation
-
-    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/>.
-*/
-
-#ifndef XENSTORE_H
-#define XENSTORE_H
-
-#include <xenstore_lib.h>
-
-#define XBT_NULL 0
-
-#define XS_OPEN_READONLY       (1UL<<0)
-#define XS_OPEN_SOCKETONLY      (1UL<<1)
-
-/*
- * Setting XS_UNWATCH_FILTER arranges that after xs_unwatch, no
- * related watch events will be delivered via xs_read_watch.  But
- * this relies on the couple token, subpath is unique.
- *
- * XS_UNWATCH_FILTER clear          XS_UNWATCH_FILTER set
- *
- * Even after xs_unwatch, "stale"   After xs_unwatch returns, no
- * instances of the watch event     watch events with the same
- * may be delivered.                token and with the same subpath
- *                                  will be delivered.
- *
- * A path and a subpath can be      The application must avoid
- * register with the same token.    registering a path (/foo/) and
- *                                  a subpath (/foo/bar) with the
- *                                  same path until a successful
- *                                  xs_unwatch for the first watch
- *                                  has returned.
- */
-#define XS_UNWATCH_FILTER     (1UL<<2)
-
-struct xs_handle;
-typedef uint32_t xs_transaction_t;
-
-/* IMPORTANT: For details on xenstore protocol limits, see
- * docs/misc/xenstore.txt in the Xen public source repository, and use the
- * XENSTORE_*_MAX limit macros defined in xen/io/xs_wire.h.
- */
-
-/* On failure, these routines set errno. */
-
-/* Open a connection to the xs daemon.
- * Attempts to make a connection over the socket interface,
- * and if it fails, then over the  xenbus interface.
- * Mode 0 specifies read-write access, XS_OPEN_READONLY for
- * read-only access.
- *
- * * Connections made with xs_open(0) (which might be shared page or
- *   socket based) are only guaranteed to work in the parent after
- *   fork.
- * * Connections made with xs_open(XS_OPEN_SOCKETONLY) will be usable
- *   in either the parent or the child after fork, but not both.
- * * xs_daemon_open*() and xs_domain_open() are deprecated synonyms
- *   for xs_open(0).
- * * XS_OPEN_READONLY has no bearing on any of this.
- *
- * Returns a handle or NULL.
- */
-struct xs_handle *xs_open(unsigned long flags);
-
-/* Close the connection to the xs daemon. */
-void xs_close(struct xs_handle *xsh /* NULL ok */);
-
-/* Connect to the xs daemon.
- * Returns a handle or NULL.
- * Deprecated, please use xs_open(0) instead
- */
-struct xs_handle *xs_daemon_open(void);
-struct xs_handle *xs_domain_open(void);
-
-/* Connect to the xs daemon (readonly for non-root clients).
- * Returns a handle or NULL.
- * Deprecated, please use xs_open(XS_OPEN_READONLY) instead
- */
-struct xs_handle *xs_daemon_open_readonly(void);
-
-/* Close the connection to the xs daemon.
- * Deprecated, please use xs_close() instead
- */
-void xs_daemon_close(struct xs_handle *);
-
-/* Throw away the connection to the xs daemon, for use after fork(). */
-void xs_daemon_destroy_postfork(struct xs_handle *);
-
-/* Get contents of a directory.
- * Returns a malloced array: call free() on it after use.
- * Num indicates size.
- * Returns NULL on failure.
- */
-char **xs_directory(struct xs_handle *h, xs_transaction_t t,
-                   const char *path, unsigned int *num);
-
-/* Get the value of a single file, nul terminated.
- * Returns a malloced value: call free() on it after use.
- * len indicates length in bytes, not including terminator.
- * Returns NULL on failure.
- */
-void *xs_read(struct xs_handle *h, xs_transaction_t t,
-             const char *path, unsigned int *len);
-
-/* Write the value of a single file.
- * Returns false on failure.
- */
-bool xs_write(struct xs_handle *h, xs_transaction_t t,
-             const char *path, const void *data, unsigned int len);
-
-/* Create a new directory.
- * Returns false on failure, or success if it already exists.
- */
-bool xs_mkdir(struct xs_handle *h, xs_transaction_t t,
-             const char *path);
-
-/* Destroy a file or directory (and children).
- * Returns false on failure, or if it doesn't exist.
- */
-bool xs_rm(struct xs_handle *h, xs_transaction_t t,
-          const char *path);
-
-/* Fake function which will always return false (required to let
- * libxenstore remain at 3.0 version.
- */
-bool xs_restrict(struct xs_handle *h, unsigned domid);
-
-/* Get permissions of node (first element is owner, first perms is "other").
- * Returns malloced array, or NULL: call free() after use.
- */
-struct xs_permissions *xs_get_permissions(struct xs_handle *h,
-                                         xs_transaction_t t,
-                                         const char *path, unsigned int *num);
-
-/* Set permissions of node (must be owner).  Returns false on failure.
- *
- * Domain 0 may read / write anywhere in the store, regardless of
- * permission settings.
- *
- * Note:
- * The perms array is a list of (domid, permissions) pairs. The first
- * element in the list specifies the owner of the list, plus the flags
- * for every domain not explicitly specified subsequently. The
- * subsequent entries are normal capabilities.
- *
- * Example C code:
- *
- *  struct xs_permissions perms[2];
- *
- *  perms[0].id = dm_domid;
- *  perms[0].perms = XS_PERM_NONE;
- *  perms[1].id = guest_domid;
- *  perms[1].perms = XS_PERM_READ;
- *
- * It means the owner of the path is domain $dm_domid (hence it always
- * has read and write permission), all other domains (unless specified
- * in subsequent pair) can neither read from nor write to that
- * path. It then specifies domain $guest_domid can read from that
- * path.
- */
-bool xs_set_permissions(struct xs_handle *h, xs_transaction_t t,
-                       const char *path, struct xs_permissions *perms,
-                       unsigned int num_perms);
-
-/* Watch a node for changes (poll on fd to detect, or call read_watch()).
- * When the node (or any child) changes, fd will become readable.
- * Token is returned when watch is read, to allow matching.
- * Returns false on failure.
- */
-bool xs_watch(struct xs_handle *h, const char *path, const char *token);
-
-/* Return the FD to poll on to see if a watch has fired. */
-int xs_fileno(struct xs_handle *h);
-
-/* Check for node changes.  On success, returns a non-NULL pointer ret
- * such that ret[0] and ret[1] are valid C strings, namely the
- * triggering path (see docs/misc/xenstore.txt) and the token (from
- * xs_watch).  On error return value is NULL setting errno.
- * 
- * Callers should, after xs_fileno has become readable, repeatedly
- * call xs_check_watch until it returns NULL and sets errno to EAGAIN.
- * (If the fd became readable, xs_check_watch is allowed to make it no
- * longer show up as readable even if future calls to xs_check_watch
- * will return more watch events.)
- *
- * After the caller is finished with the returned information it
- * should be freed all in one go with free(ret).
- */
-char **xs_check_watch(struct xs_handle *h);
-
-/* Find out what node change was on (will block if nothing pending).
- * Returns array containing the path and token, or NULL.
- * Use XS_WATCH_* to access these elements.
- * Call free() after use.
- */
-char **xs_read_watch(struct xs_handle *h, unsigned int *num);
-
-/* Remove a watch on a node: implicitly acks any outstanding watch.
- * Returns false on failure (no watch on that node).
- */
-bool xs_unwatch(struct xs_handle *h, const char *path, const char *token);
-
-/* Start a transaction: changes by others will not be seen during this
- * transaction, and changes will not be visible to others until end.
- * Returns NULL on failure.
- */
-xs_transaction_t xs_transaction_start(struct xs_handle *h);
-
-/* End a transaction.
- * If abandon is true, transaction is discarded instead of committed.
- * Returns false on failure: if errno == EAGAIN, you have to restart
- * transaction.
- */
-bool xs_transaction_end(struct xs_handle *h, xs_transaction_t t,
-                       bool abort);
-
-/* Introduce a new domain.
- * This tells the store daemon about a shared memory page, event channel and
- * store path associated with a domain: the domain uses these to communicate.
- */
-bool xs_introduce_domain(struct xs_handle *h,
-                        unsigned int domid,
-                        unsigned long mfn,
-                         unsigned int eventchn); 
-
-/* Set the target of a domain
- * This tells the store daemon that a domain is targetting another one, so
- * it should let it tinker with it.
- */
-bool xs_set_target(struct xs_handle *h,
-                  unsigned int domid,
-                  unsigned int target);
-
-/* Resume a domain.
- * Clear the shutdown flag for this domain in the store.
- */
-bool xs_resume_domain(struct xs_handle *h, unsigned int domid);
-
-/* Release a domain.
- * Tells the store domain to release the memory page to the domain.
- */
-bool xs_release_domain(struct xs_handle *h, unsigned int domid);
-
-/* Query the home path of a domain.  Call free() after use.
- */
-char *xs_get_domain_path(struct xs_handle *h, unsigned int domid);
-
-/* Returns true if child is either equal to parent, or a node underneath
- * parent; or false otherwise.  Done by string comparison, so relative and
- * absolute pathnames never in a parent/child relationship by this
- * definition.  Cannot fail.
- */
-bool xs_path_is_subpath(const char *parent, const char *child);
-
-/* Return whether the domain specified has been introduced to xenstored.
- */
-bool xs_is_domain_introduced(struct xs_handle *h, unsigned int domid);
-
-char *xs_control_command(struct xs_handle *h, const char *cmd,
-                        void *data, unsigned int len);
-/* Deprecated: use xs_control_command() instead. */
-char *xs_debug_command(struct xs_handle *h, const char *cmd,
-                      void *data, unsigned int len);
-
-int xs_suspend_evtchn_port(int domid);
-#endif /* XENSTORE_H */
-
-/*
- * Local variables:
- *  mode: C
- *  c-file-style: "linux"
- *  indent-tabs-mode: t
- *  c-basic-offset: 8
- *  tab-width: 8
- * End:
- */
diff --git a/tools/xenstore/include/xenstore_lib.h 
b/tools/xenstore/include/xenstore_lib.h
deleted file mode 100644
index 0ffbae9eb5..0000000000
--- a/tools/xenstore/include/xenstore_lib.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/* 
-    Common routines between Xen store user library and daemon.
-    Copyright (C) 2005 Rusty Russell IBM Corporation
-
-    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/>.
-*/
-
-#ifndef XENSTORE_LIB_H
-#define XENSTORE_LIB_H
-
-#include <stddef.h>
-#include <stdbool.h>
-#include <limits.h>
-#include <errno.h>
-#include <stdint.h>
-#include <xen/io/xs_wire.h>
-
-/* Bitmask of permissions. */
-enum xs_perm_type {
-       XS_PERM_NONE = 0,
-       XS_PERM_READ = 1,
-       XS_PERM_WRITE = 2,
-       /* Internal use. */
-       XS_PERM_ENOENT_OK = 4,
-       XS_PERM_OWNER = 8,
-};
-
-struct xs_permissions
-{
-       unsigned int id;
-       enum xs_perm_type perms;
-};
-
-/* Header of the node record in tdb. */
-struct xs_tdb_record_hdr {
-       uint64_t generation;
-       uint32_t num_perms;
-       uint32_t datalen;
-       uint32_t childlen;
-       struct xs_permissions perms[0];
-};
-
-/* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */
-#define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2)
-
-/* Path for various daemon things: env vars can override. */
-const char *xs_daemon_rootdir(void);
-const char *xs_daemon_rundir(void);
-const char *xs_daemon_socket(void);
-const char *xs_daemon_socket_ro(void);
-const char *xs_domain_dev(void);
-const char *xs_daemon_tdb(void);
-
-/* Simple write function: loops for you. */
-bool xs_write_all(int fd, const void *data, unsigned int len);
-
-/* Convert strings to permissions.  False if a problem. */
-bool xs_strings_to_perms(struct xs_permissions *perms, unsigned int num,
-                        const char *strings);
-
-/* Convert permissions to a string (up to len MAX_STRLEN(unsigned int)+1). */
-bool xs_perm_to_string(const struct xs_permissions *perm,
-                       char *buffer, size_t buf_len);
-
-/* Given a string and a length, count how many strings (nul terms). */
-unsigned int xs_count_strings(const char *strings, unsigned int len);
-
-/* Sanitising (quoting) possibly-binary strings. */
-struct expanding_buffer {
-       char *buf;
-       int avail;
-};
-
-/* Ensure that given expanding buffer has at least min_avail characters. */
-char *expanding_buffer_ensure(struct expanding_buffer *, int min_avail);
-
-/* sanitise_value() may return NULL if malloc fails. */
-char *sanitise_value(struct expanding_buffer *, const char *val, unsigned len);
-
-/* *out_len_r on entry is ignored; out must be at least strlen(in)+1 bytes. */
-void unsanitise_value(char *out, unsigned *out_len_r, const char *in);
-
-#endif /* XENSTORE_LIB_H */
diff --git a/tools/xenstore/xenstore_lib.h b/tools/xenstore/xenstore_lib.h
new file mode 100644
index 0000000000..0ffbae9eb5
--- /dev/null
+++ b/tools/xenstore/xenstore_lib.h
@@ -0,0 +1,94 @@
+/* 
+    Common routines between Xen store user library and daemon.
+    Copyright (C) 2005 Rusty Russell IBM Corporation
+
+    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/>.
+*/
+
+#ifndef XENSTORE_LIB_H
+#define XENSTORE_LIB_H
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdint.h>
+#include <xen/io/xs_wire.h>
+
+/* Bitmask of permissions. */
+enum xs_perm_type {
+       XS_PERM_NONE = 0,
+       XS_PERM_READ = 1,
+       XS_PERM_WRITE = 2,
+       /* Internal use. */
+       XS_PERM_ENOENT_OK = 4,
+       XS_PERM_OWNER = 8,
+};
+
+struct xs_permissions
+{
+       unsigned int id;
+       enum xs_perm_type perms;
+};
+
+/* Header of the node record in tdb. */
+struct xs_tdb_record_hdr {
+       uint64_t generation;
+       uint32_t num_perms;
+       uint32_t datalen;
+       uint32_t childlen;
+       struct xs_permissions perms[0];
+};
+
+/* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */
+#define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2)
+
+/* Path for various daemon things: env vars can override. */
+const char *xs_daemon_rootdir(void);
+const char *xs_daemon_rundir(void);
+const char *xs_daemon_socket(void);
+const char *xs_daemon_socket_ro(void);
+const char *xs_domain_dev(void);
+const char *xs_daemon_tdb(void);
+
+/* Simple write function: loops for you. */
+bool xs_write_all(int fd, const void *data, unsigned int len);
+
+/* Convert strings to permissions.  False if a problem. */
+bool xs_strings_to_perms(struct xs_permissions *perms, unsigned int num,
+                        const char *strings);
+
+/* Convert permissions to a string (up to len MAX_STRLEN(unsigned int)+1). */
+bool xs_perm_to_string(const struct xs_permissions *perm,
+                       char *buffer, size_t buf_len);
+
+/* Given a string and a length, count how many strings (nul terms). */
+unsigned int xs_count_strings(const char *strings, unsigned int len);
+
+/* Sanitising (quoting) possibly-binary strings. */
+struct expanding_buffer {
+       char *buf;
+       int avail;
+};
+
+/* Ensure that given expanding buffer has at least min_avail characters. */
+char *expanding_buffer_ensure(struct expanding_buffer *, int min_avail);
+
+/* sanitise_value() may return NULL if malloc fails. */
+char *sanitise_value(struct expanding_buffer *, const char *val, unsigned len);
+
+/* *out_len_r on entry is ignored; out must be at least strlen(in)+1 bytes. */
+void unsanitise_value(char *out, unsigned *out_len_r, const char *in);
+
+#endif /* XENSTORE_LIB_H */
diff --git a/tools/xenstore/xs.c b/tools/xenstore/xs.c
deleted file mode 100644
index aa1d24b8b9..0000000000
--- a/tools/xenstore/xs.c
+++ /dev/null
@@ -1,1473 +0,0 @@
-/* 
-    Xen Store Daemon interface providing simple tree-like database.
-    Copyright (C) 2005 Rusty Russell IBM Corporation
-
-    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/>.
-*/
-
-#define _GNU_SOURCE
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/uio.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <stdio.h>
-#include <signal.h>
-#include <stdint.h>
-#include <errno.h>
-#include "xenstore.h"
-#include "list.h"
-#include "utils.h"
-
-#include <xentoolcore_internal.h>
-
-struct xs_stored_msg {
-       struct list_head list;
-       struct xsd_sockmsg hdr;
-       char *body;
-};
-
-#ifdef USE_PTHREAD
-
-#include <pthread.h>
-
-#ifdef USE_DLSYM
-#include <dlfcn.h>
-#endif
-
-struct xs_handle {
-       /* Communications channel to xenstore daemon. */
-       int fd;
-       Xentoolcore__Active_Handle tc_ah; /* for restrict */
-
-       /*
-         * A read thread which pulls messages off the comms channel and
-         * signals waiters.
-         */
-       pthread_t read_thr;
-       int read_thr_exists;
-
-       /*
-         * A list of fired watch messages, protected by a mutex. Users can
-         * wait on the conditional variable until a watch is pending.
-         */
-       struct list_head watch_list;
-       pthread_mutex_t watch_mutex;
-       pthread_cond_t watch_condvar;
-
-       /* Clients can select() on this pipe to wait for a watch to fire. */
-       int watch_pipe[2];
-       /* Filtering watch event in unwatch function? */
-       bool unwatch_filter;
-
-       /*
-         * A list of replies. Currently only one will ever be outstanding
-         * because we serialise requests. The requester can wait on the
-         * conditional variable for its response.
-         */
-       struct list_head reply_list;
-       pthread_mutex_t reply_mutex;
-       pthread_cond_t reply_condvar;
-
-       /* One request at a time. */
-       pthread_mutex_t request_mutex;
-
-       /* Lock discipline:
-        *  Only holder of the request lock may write to h->fd.
-        *  Only holder of the request lock may access read_thr_exists.
-        *  If read_thr_exists==0, only holder of request lock may read h->fd;
-        *  If read_thr_exists==1, only the read thread may read h->fd.
-        *  Only holder of the reply lock may access reply_list.
-        *  Only holder of the watch lock may access watch_list.
-        * Lock hierarchy:
-        *  The order in which to acquire locks is
-        *     request_mutex
-        *     reply_mutex
-        *     watch_mutex
-        */
-};
-
-#define mutex_lock(m)          pthread_mutex_lock(m)
-#define mutex_unlock(m)                pthread_mutex_unlock(m)
-#define condvar_signal(c)      pthread_cond_signal(c)
-#define condvar_wait(c,m)      pthread_cond_wait(c,m)
-#define cleanup_push(f, a)     \
-    pthread_cleanup_push((void (*)(void *))(f), (void *)(a))
-/*
- * Some definitions of pthread_cleanup_pop() are a macro starting with an
- * end-brace. GCC then complains if we immediately precede that with a label.
- * Hence we insert a dummy statement to appease the compiler in this situation.
- */
-#define cleanup_pop(run)        ((void)0); pthread_cleanup_pop(run)
-
-#define read_thread_exists(h)  (h->read_thr_exists)
-
-/* Because pthread_cleanup_p* are not available when USE_PTHREAD is
- * disabled, use these macros which convert appropriately. */
-#define cleanup_push_heap(p)        cleanup_push(free, p)
-#define cleanup_pop_heap(run, p)    cleanup_pop((run))
-
-static void *read_thread(void *arg);
-
-#else /* !defined(USE_PTHREAD) */
-
-struct xs_handle {
-       int fd;
-       Xentoolcore__Active_Handle tc_ah; /* for restrict */
-       struct list_head reply_list;
-       struct list_head watch_list;
-       /* Clients can select() on this pipe to wait for a watch to fire. */
-       int watch_pipe[2];
-       /* Filtering watch event in unwatch function? */
-       bool unwatch_filter;
-};
-
-#define mutex_lock(m)          ((void)0)
-#define mutex_unlock(m)                ((void)0)
-#define condvar_signal(c)      ((void)0)
-#define condvar_wait(c,m)      ((void)0)
-#define cleanup_push(f, a)     ((void)0)
-#define cleanup_pop(run)       ((void)0)
-#define read_thread_exists(h)  (0)
-
-#define cleanup_push_heap(p)        ((void)0)
-#define cleanup_pop_heap(run, p)    do { if ((run)) free(p); } while(0)
-
-#endif
-
-static int read_message(struct xs_handle *h, int nonblocking);
-
-static bool setnonblock(int fd, int nonblock) {
-       int flags = fcntl(fd, F_GETFL);
-       if (flags == -1)
-               return false;
-
-       if (nonblock)
-               flags |= O_NONBLOCK;
-       else
-               flags &= ~O_NONBLOCK;
-
-       if (fcntl(fd, F_SETFL, flags) == -1)
-               return false;
-
-       return true;
-}
-
-int xs_fileno(struct xs_handle *h)
-{
-       char c = 0;
-
-       mutex_lock(&h->watch_mutex);
-
-       if ((h->watch_pipe[0] == -1) && (pipe(h->watch_pipe) != -1)) {
-               /* Kick things off if the watch list is already non-empty. */
-               if (!list_empty(&h->watch_list))
-                       while (write(h->watch_pipe[1], &c, 1) != 1)
-                               continue;
-       }
-
-       mutex_unlock(&h->watch_mutex);
-
-       return h->watch_pipe[0];
-}
-
-static int get_socket(const char *connect_to)
-{
-       struct sockaddr_un addr;
-       int sock, saved_errno, flags;
-
-       sock = socket(PF_UNIX, SOCK_STREAM, 0);
-       if (sock < 0)
-               return -1;
-
-       if ((flags = fcntl(sock, F_GETFD)) < 0)
-               goto error;
-       flags |= FD_CLOEXEC;
-       if (fcntl(sock, F_SETFD, flags) < 0)
-               goto error;
-
-       addr.sun_family = AF_UNIX;
-       if(strlen(connect_to) >= sizeof(addr.sun_path)) {
-               errno = EINVAL;
-               goto error;
-       }
-       strcpy(addr.sun_path, connect_to);
-
-       if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != 0)
-               goto error;
-
-       return sock;
-
-error:
-       saved_errno = errno;
-       close(sock);
-       errno = saved_errno;
-       return -1;
-}
-
-static int get_dev(const char *connect_to)
-{
-       /* We cannot open read-only because requests are writes */
-       return open(connect_to, O_RDWR);
-}
-
-static int all_restrict_cb(Xentoolcore__Active_Handle *ah, domid_t domid) {
-    struct xs_handle *h = CONTAINER_OF(ah, *h, tc_ah);
-    return xentoolcore__restrict_by_dup2_null(h->fd);
-}
-
-static struct xs_handle *get_handle(const char *connect_to)
-{
-       struct stat buf;
-       struct xs_handle *h = NULL;
-       int saved_errno;
-
-       h = malloc(sizeof(*h));
-       if (h == NULL)
-               goto err;
-
-       memset(h, 0, sizeof(*h));
-       h->fd = -1;
-
-       h->tc_ah.restrict_callback = all_restrict_cb;
-       xentoolcore__register_active_handle(&h->tc_ah);
-
-       if (stat(connect_to, &buf) != 0)
-               goto err;
-
-       if (S_ISSOCK(buf.st_mode))
-               h->fd = get_socket(connect_to);
-       else
-               h->fd = get_dev(connect_to);
-
-       if (h->fd == -1)
-               goto err;
-
-       INIT_LIST_HEAD(&h->reply_list);
-       INIT_LIST_HEAD(&h->watch_list);
-
-       /* Watch pipe is allocated on demand in xs_fileno(). */
-       h->watch_pipe[0] = h->watch_pipe[1] = -1;
-
-       h->unwatch_filter = false;
-
-#ifdef USE_PTHREAD
-       pthread_mutex_init(&h->watch_mutex, NULL);
-       pthread_cond_init(&h->watch_condvar, NULL);
-
-       pthread_mutex_init(&h->reply_mutex, NULL);
-       pthread_cond_init(&h->reply_condvar, NULL);
-
-       pthread_mutex_init(&h->request_mutex, NULL);



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.