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

[Xen-devel] [PATCH v5 02/14] libxenstore.so: add support for systemd



From: "Luis R. Rodriguez" <mcgrof@xxxxxxxx>

This adds support for systemd into libxenstore.so to enable usage
through cxenstored and oxenstored. The way we provide support for
systemd is to *not* compile systemd with -lsystemd-daemon but instead
to look for libsystemd-daemon.so at run time if the binary was compiled
with support for systemd. Before using systemd though we check if the
system was booted with systemd as the init process by using sd_booted()
and only if this is true will we assume that's the only mechanism
allowed. For systems that do not have systemd present or that have systemd
libraries present but did not boot with systemd the old init unix socket
creation mechanism will be used.

Systems that do not use unix sockets at all will continue to chug on as
they used to skipping all this unix socket actication and relying on the
kernel ring interface, used for exampl when CONFIG_STUBDOM=y which sets
CFLAGS += -DNO_SOCKETS=1 on tools/xenstore/Makefile and also by the
oxenstored --disable_socket run time flag.

This enables Linux distributions to ship and support one binary for both
systemd and non-systemd type of environments.

Signed-off-by: Luis R. Rodriguez <mcgrof@xxxxxxxx>
---
 tools/xenstore/Makefile     |   7 +-
 tools/xenstore/xenstore.h   |  11 ++
 tools/xenstore/xs_systemd.c | 321 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 337 insertions(+), 2 deletions(-)
 create mode 100644 tools/xenstore/xs_systemd.c

diff --git a/tools/xenstore/Makefile b/tools/xenstore/Makefile
index 55ca7a3..c361d84 100644
--- a/tools/xenstore/Makefile
+++ b/tools/xenstore/Makefile
@@ -9,10 +9,13 @@ CFLAGS += -I.
 CFLAGS += -I$(XEN_ROOT)/tools/
 CFLAGS += $(CFLAGS_libxenctrl)
 
+LDFLAGS += -ldl -rdynamic
+
 CLIENTS := xenstore-exists xenstore-list xenstore-read xenstore-rm 
xenstore-chmod
 CLIENTS += xenstore-write xenstore-ls xenstore-watch
 
 XENSTORED_OBJS = xenstored_core.o xenstored_watch.o xenstored_domain.o 
xenstored_transaction.o xs_lib.o talloc.o utils.o tdb.o hashtable.o
+XENSTORED_OBJS += xs_systemd.o
 
 XENSTORED_OBJS_$(CONFIG_Linux) = xenstored_linux.o xenstored_posix.o
 XENSTORED_OBJS_$(CONFIG_SunOS) = xenstored_solaris.o xenstored_posix.o 
xenstored_probes.o
@@ -86,10 +89,10 @@ libxenstore.so.$(MAJOR): libxenstore.so.$(MAJOR).$(MINOR)
 
 xs.opic: CFLAGS += -DUSE_PTHREAD
 
-libxenstore.so.$(MAJOR).$(MINOR): xs.opic xs_lib.opic
+libxenstore.so.$(MAJOR).$(MINOR): xs.opic xs_lib.opic xs_systemd.opic
        $(CC) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxenstore.so.$(MAJOR) 
$(SHLIB_LDFLAGS) -o $@ $^ $(SOCKET_LIBS) -lpthread $(APPEND_LDFLAGS)
 
-libxenstore.a: xs.o xs_lib.o
+libxenstore.a: xs.o xs_lib.o xs_systemd.o
        $(AR) rcs $@ $^
 
 .PHONY: clean
diff --git a/tools/xenstore/xenstore.h b/tools/xenstore/xenstore.h
index fdf5e76..11daee4 100644
--- a/tools/xenstore/xenstore.h
+++ b/tools/xenstore/xenstore.h
@@ -49,6 +49,7 @@
 #define XS_UNWATCH_FILTER     1UL<<2
 
 struct xs_handle;
+struct xs_sd_ctx;
 typedef uint32_t xs_transaction_t;
 
 /* IMPORTANT: For details on xenstore protocol limits, see
@@ -244,6 +245,16 @@ char *xs_debug_command(struct xs_handle *h, const char 
*cmd,
                       void *data, unsigned int len);
 
 int xs_suspend_evtchn_port(int domid);
+
+struct xs_sd_ctx *xs_get_sd_ctx(void);
+void xs_free_sd_ctx(struct xs_sd_ctx *ctx);
+
+bool xs_load_sd_required(struct xs_sd_ctx *ctx);
+
+int xs_claim_active_socket(struct xs_sd_ctx *ctx, const char *connect_to);
+
+int xs_sd_notify_ready(struct xs_sd_ctx *ctx);
+
 #endif /* XENSTORE_H */
 
 /*
diff --git a/tools/xenstore/xs_systemd.c b/tools/xenstore/xs_systemd.c
new file mode 100644
index 0000000..814e0fc
--- /dev/null
+++ b/tools/xenstore/xs_systemd.c
@@ -0,0 +1,321 @@
+/*
+    xenstored shared interface
+    Copyright (C) 2014 Luis R. Rodriguez <mcgrof@xxxxxxxx>
+
+    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, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <stdio.h>
+#include <errno.h>
+#include <config.h>
+
+#ifndef NO_SOCKETS
+#if defined(HAVE_SYSTEMD)
+#define XEN_SYSTEMD_ENABLED 1
+#endif
+#endif
+
+#if defined(XEN_SYSTEMD_ENABLED)
+#include <systemd/sd-daemon.h>
+#include <dlfcn.h>
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(ar) (sizeof(ar)/sizeof(ar[0]))
+#endif
+
+/*
+ * Xen supports both systemd and old init style initialization. Xen supports
+ * distributions to ship only one binary to support both systemd and non
+ * systemd systems. We accomplish this by not requiring to link libxenstore.so
+ * with -lsystemd-daemon at compile time but instead having libxenstore.so
+ * ask for libsystemd-daemon.so through run time. Furthremore even if
+ * libsystemd-daemon.so is present it does not mean that a system was booted
+ * with systemd as its init system so we check sd_booted() before assuming
+ * the goal was to require systemd. In a system that did not boot with systemd
+ * as its init daemon but has libsystemd-daemon.so available we'll only require
+ * sd_booted() to verify if init is systemd. Below we explain a bit further how
+ * we accomplish runtime loading of systemd libraries in a portable way.
+ *
+ * dlsym() returns a void pointer, however a void pointer is not required
+ * to even have the same size as an object pointer, and therefore a valid
+ * conversion between type void* and a pointer to a function may not exist
+ * on all platforms. You also may end up with strict-aliasing complaints, so
+ * we use a union. For more details refer to:
+ *
+ * http://en.wikipedia.org/wiki/Dynamic_loading#UNIX_.28POSIX.29
+ *
+ * The strategy taken here is to use a builder for initial assignment
+ * to address issues with different systems with a range of known
+ * expected routines from the library, by usng a macro helper we with
+ * a builder we can enforce only assignment to expected routines from
+ * the library.
+ *
+ * In order to avoid a sloppy union access we upkeep on our own xen
+ * data structure the actual callbacks that we know exist, and leave
+ * the void union trick only for the builder, this requires defining the
+ * expected routines twice, on the builder and our own cached copy of
+ * the symbol dereferences.
+ */
+
+#define XEN_SYSTEMD_FUNCS                                                      
                        \
+       int (*sd_booted)(void);                                                 
                        \
+       int (*sd_listen_fds)(int unset_environment);                            
                        \
+       int (*sd_is_fifo)(int fd, const char *path);                            
                        \
+       int (*sd_is_socket)(int fd, int family, int type, int listening);       
                        \
+       int (*sd_is_socket_inet)(int fd, int family, int type, int listening, 
uint16_t port);           \
+       int (*sd_is_socket_unix)(int fd, int type, int listening, const char* 
path, size_t length);     \
+       int (*sd_is_mq)(int fd, const char *path);                              
                        \
+       int (*sd_notify)(int unset_environment, const char *state);             
                        \
+       int (*sd_notifyf)(int unset_environment, const char *format, ...);
+
+union u_sd_funcs {
+       void *f;
+       XEN_SYSTEMD_FUNCS
+};
+
+struct xs_sd_ctx {
+       void *handle;
+       XEN_SYSTEMD_FUNCS
+};
+
+#define xen_load_sd_func(__xs_sd_lib, __libfunc, __builder) do {               
\
+       __builder.f = NULL;                                             \
+       __builder.f = dlsym(__xs_sd_lib->handle, #__libfunc);           \
+       if (!__builder.f)                                               \
+               return false;                                           \
+       __xs_sd_lib->__libfunc = builder.__libfunc;                     \
+} while (0)
+
+struct xs_sd_ctx *xs_get_sd_ctx(void)
+{
+       struct xs_sd_ctx *ctx;
+       ctx = malloc(sizeof(struct xs_sd_ctx));
+       if (!ctx)
+               return NULL;
+       memset(ctx, 0, sizeof(struct xs_sd_ctx));
+       return ctx;
+}
+
+void xs_free_sd_ctx(struct xs_sd_ctx *ctx)
+{
+       if (!ctx)
+               return;
+       free(ctx);
+}
+
+bool xs_load_sd_required(struct xs_sd_ctx *ctx)
+{
+       union u_sd_funcs builder;
+
+       if (!ctx)
+               return false;
+
+       memset(&builder, 0, sizeof(union u_sd_funcs));
+
+       ctx->handle = dlopen("libsystemd-daemon.so", RTLD_LAZY);
+       if (!ctx->handle)
+               return false;
+
+       xen_load_sd_func(ctx, sd_booted, builder);
+
+       if (!ctx->sd_booted())
+               return false;
+
+       xen_load_sd_func(ctx, sd_listen_fds, builder);
+       xen_load_sd_func(ctx, sd_is_socket_unix, builder);
+       xen_load_sd_func(ctx, sd_notify, builder);
+       xen_load_sd_func(ctx, sd_notifyf, builder);
+
+       return true;
+}
+
+/* Conforms to what we should send sd_is_socket_unix() but we add mode */
+struct xen_systemd_active_socket {
+       int fd;
+       int type;
+       int listening;
+       const char *path;
+       int mode;
+       size_t length;
+};
+
+/*
+ * We list stdin, stdout and stderr simply for documentation purposes
+ * and to help our array size fit the number of expected sockets we
+ * as sd_listen_fds() will return 5 for example if you set the socket
+ * service with 2 sockets.
+ */
+static const struct xen_systemd_active_socket xenstore_active_sockets[] = {
+       {
+               .fd = SD_LISTEN_FDS_START -3,
+               .type = 0,
+               .listening = 0,
+               .path = "stdin",
+               .mode = 0600,
+               .length = 0,
+       },
+       {
+               .fd = SD_LISTEN_FDS_START - 2,
+               .type = 0,
+               .listening = 0,
+               .path = "stderr",
+               .mode = 0600,
+               .length = 0,
+       },
+       {
+               .fd = SD_LISTEN_FDS_START - 1,
+               .type = 0,
+               .listening = 0,
+               .path = "stderr",
+               .mode = 0600,
+               .length = 0,
+       },
+       {
+               .fd = SD_LISTEN_FDS_START,
+               .type = SOCK_STREAM,
+               .listening = -1,
+               .path = "/var/run/xenstored/socket",
+               .mode = 0600,
+               .length = 0,
+       },
+       {
+               .fd = SD_LISTEN_FDS_START + 1,
+               .type = SOCK_STREAM,
+               .listening = -1,
+               .path = "/var/run/xenstored/socket_ro",
+               .mode = 0660,
+               .length = 0,
+       },
+};
+
+static const struct xen_systemd_active_socket *get_xen_active_socket(const 
char *connect_to)
+{
+       unsigned int i;
+
+       for (i=0; i<ARRAY_SIZE(xenstore_active_sockets); i++) {
+               if (!strcmp(connect_to, xenstore_active_sockets[i].path)) {
+                       if (!xenstore_active_sockets[i].type)
+                               return NULL;
+                       return &xenstore_active_sockets[i];
+               }
+       }
+
+       return NULL;
+}
+
+int xs_claim_active_socket(struct xs_sd_ctx *ctx, const char *connect_to)
+{
+       int n, r;
+       const struct xen_systemd_active_socket *active_socket;
+
+       if (!ctx)
+               return -EINVAL;
+
+       if (!ctx->sd_listen_fds)
+               return -EINVAL;
+
+       if (!ctx->sd_is_socket_unix)
+               return -EINVAL;
+
+       active_socket = get_xen_active_socket(connect_to);
+       if (!active_socket)
+               return -EINVAL;
+
+       n = ctx->sd_listen_fds(0);
+       if (n <= 0) {
+               ctx->sd_notifyf(0, "STATUS=Failed to get any active sockets: 
%s\n"
+                               "ERRNO=%i",
+                               strerror(errno),
+                               errno);
+               return -errno;
+       } else if (n >= (ARRAY_SIZE(xenstore_active_sockets))) {
+               fprintf(stderr, SD_ERR "Expected %d fds but given %d\n",
+                       (int) ARRAY_SIZE(xenstore_active_sockets)-1,
+                       n);
+               ctx->sd_notifyf(0, "STATUS=Mismatch on number (%d): %s\n"
+                               "ERRNO=%d",
+                               (int) ARRAY_SIZE(xenstore_active_sockets),
+                               strerror(EBADR),
+                               EBADR);
+               return -EBADR;
+       }
+
+       r = ctx->sd_is_socket_unix(active_socket->fd,
+                                  active_socket->type,
+                                  active_socket->listening,
+                                  active_socket->path,
+                                  active_socket->length);
+       if (r <= 0)
+               return -EBADR;
+
+       r = chmod(active_socket->path, active_socket->mode);
+       if (r != 0)
+               return -errno;
+
+       fprintf(stderr, SD_NOTICE "%s socket claimed\n", active_socket->path);
+
+       return active_socket->fd;
+}
+
+void xs_sd_notify_ready(struct xs_sd_ctx *ctx)
+{
+       if (!ctx)
+               return;
+
+       ctx->sd_notify(1, "READY=1");
+       fprintf(stderr, SD_NOTICE "xenstored is ready\n");
+}
+#else
+
+struct xs_sd_ctx {
+       void *handle;
+};
+
+struct xs_sd_ctx *xs_get_sd_ctx(void)
+{
+       return NULL;
+}
+
+void xs_free_sd_ctx(struct xs_sd_ctx *ctx)
+{
+       return;
+}
+
+int xs_claim_active_socket(struct xs_sd_ctx *ctx, const char *connect_to)
+{
+       return -1;
+}
+
+bool xs_load_sd_required(struct xs_sd_ctx *ctx)
+{
+       return false;
+}
+
+void xs_sd_notify_ready(struct xs_sd_ctx *ctx)
+{
+       return;
+}
+#endif /* XEN_SYSTEMD */
-- 
2.0.0.rc3.18.g00a5b79


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

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