@@ -24,6 +24,7 @@ multipathd/multipathd
multipathd/multipathd.8
multipathd/multipathc
multipathd/multipathd.service
+multipathd/multipathd.socket
mpathpersist/mpathpersist
mpathpersist/mpathpersist.8
abi.tar.gz
@@ -79,8 +79,11 @@ libudev_incdir := $(or $(shell $(PKG_CONFIG) --variable=includedir libudev),/usr
kernel_incdir := /usr/include
sysdir_bin := $(sys_execprefix)bin
+use_regular_socket :=
+regular_socket_path := /run/multipathd.socket
abstract_socket_path := /org/kernel/linux/storage/multipathd
-mpath_socket := $(abstract_socket_path)
+mpath_socket := $(if $(use_regular_socket),$(regular_socket_path),$(abstract_socket_path))
+mpath_socket_systemd := $(if $(use_regular_socket),$(regular_socket_path),@$(abstract_socket_path))
ifeq ($(V),)
Q := @
@@ -118,7 +121,8 @@ CPPFLAGS := $(FORTIFY_OPT) $(CPPFLAGS) $(D_URCU_VERSION) \
-DRUNTIME_DIR=\"$(runtimedir)\" -DCONFIG_DIR=\"$(TGTDIR)$(configdir)\" \
-DDEFAULT_CONFIGFILE=\"$(TGTDIR)$(configfile)\" -DSTATE_DIR=\"$(TGTDIR)$(statedir)\" \
-DEXTRAVERSION=\"$(EXTRAVERSION)\" \
- -DDEFAULT_SOCKET=\"$(mpath_socket)\" -MMD -MP
+ -DDEFAULT_SOCKET=\"$(mpath_socket)\" -DUSE_REGULAR_SOCKET=$(if $(use_regular_socket),1,0) \
+ -MMD -MP
CFLAGS := -std=gnu99 $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe \
-fexceptions
BIN_CFLAGS := -fPIE -DPIE
@@ -171,4 +175,5 @@ NV_VERSION_SCRIPT = $(DEVLIB:%.so=%-nv.version)
-e 's:@SYSDIR_BIN@:'$(sysdir_bin)': g' \
-e 's:@RUNTIME_DIR@:'$(runtimedir)':g' \
-e 's/@MODPROBE_UNIT@/'$(MODPROBE_UNIT)'/g' \
+ -e 's,@MPATH_SOCKET@,'$(mpath_socket_systemd)',g' \
$< >$@
@@ -121,6 +121,10 @@ The following variables can be passed to the `make` command line:
stores run-time settings that need persist between reboots, such as known
WWIDs, user-friendly names, and persistent reservation keys.
The default is `$(etc_prefix)/etc/multipath`.
+ * `use_regular_socket`: if unset (default), use an abstract socket, which is
+ invisible in the file system. Otherwise, if set to 1, use the regular unix socket
+ `/run/multipathd.socket`. Setting this to 1 is necessary in order to
+ communicate with **multipathd** from containers.
* `READLINE=libedit` or `READLINE=libreadline`: enable command line history
and TAB completion in the interactive mode *(which is entered with `multipathd -k` or `multipathc`)*.
The respective development package will be required for building.
@@ -27,3 +27,8 @@ LIBMPATHCMD_1.1.0 {
global:
mpath_connect__;
} LIBMPATHCMD_1.0.0;
+
+LIBMPATHCMD_1.2.0 {
+global:
+ mpath_fill_sockaddr;
+} LIBMPATHCMD_1.1.0;
@@ -91,6 +91,24 @@ static size_t write_all(int fd, const void *buf, size_t len)
return total;
}
+size_t mpath_fill_sockaddr(struct sockaddr_un *addr, const char *name)
+{
+ size_t len;
+
+ addr->sun_family = AF_LOCAL;
+
+#if USE_REGULAR_SOCKET
+ strncpy(&addr->sun_path[0], name, sizeof(addr->sun_path) - 1);
+ len = offsetof(struct sockaddr_un, sun_path) + strlen(name) + 1;
+#else
+ addr->sun_path[0] = '\0';
+ strncpy(&addr->sun_path[1], name, sizeof(addr->sun_path) - 2);
+ len = offsetof(struct sockaddr_un, sun_path) + strlen(name) + 2;
+#endif
+ addr->sun_path[sizeof(addr->sun_path) - 1] = '\0';
+ return len > sizeof(*addr) ? sizeof(*addr) : len;
+}
+
/*
* connect to a unix domain socket
*/
@@ -101,14 +119,6 @@ int mpath_connect__(int nonblocking)
struct sockaddr_un addr;
int flags = 0;
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_LOCAL;
- addr.sun_path[0] = '\0';
- strncpy(&addr.sun_path[1], DEFAULT_SOCKET, sizeof(addr.sun_path) - 1);
- len = strlen(DEFAULT_SOCKET) + 1 + sizeof(sa_family_t);
- if (len > sizeof(struct sockaddr_un))
- len = sizeof(struct sockaddr_un);
-
fd = socket(AF_LOCAL, SOCK_STREAM, 0);
if (fd == -1)
return -1;
@@ -119,6 +129,7 @@ int mpath_connect__(int nonblocking)
(void)fcntl(fd, F_SETFL, flags|O_NONBLOCK);
}
+ len = mpath_fill_sockaddr(&addr, DEFAULT_SOCKET);
if (connect(fd, (struct sockaddr *)&addr, len) == -1) {
int err = errno;
@@ -19,6 +19,7 @@
#ifndef MPATH_CMD_H_INCLUDED
#define MPATH_CMD_H_INCLUDED
+#include <sys/un.h>
/*
* This should be sufficient for json output for >10000 maps,
@@ -32,6 +33,11 @@ extern "C" {
#define DEFAULT_REPLY_TIMEOUT 4000
+/*
+ * DESCRIPTION:
+ * Helper to fill in the socket name.
+ */
+size_t mpath_fill_sockaddr(struct sockaddr_un *addr, const char *name);
/*
* DESCRIPTION:
@@ -12,6 +12,7 @@
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/stat.h>
#include <sys/un.h>
#include <poll.h>
#include <signal.h>
@@ -56,6 +57,11 @@ int ux_socket_listen(const char *name)
condlog(3, "using fd %d from sd_listen_fds", fd);
return fd;
}
+#endif
+#if USE_REGULAR_SOCKET
+ /* This is after the PID check, so unlinking should be fine */
+ if (unlink(name) == -1 && errno != ENOENT)
+ condlog(1, "Failed to unlink %s", name);
#endif
fd = socket(AF_LOCAL, SOCK_STREAM, 0);
if (fd == -1) {
@@ -63,21 +69,21 @@ int ux_socket_listen(const char *name)
return -1;
}
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_LOCAL;
- addr.sun_path[0] = '\0';
- len = strlen(name) + 1;
- if (len >= sizeof(addr.sun_path))
- len = sizeof(addr.sun_path) - 1;
- memcpy(&addr.sun_path[1], name, len);
-
- len += sizeof(sa_family_t);
+ len = mpath_fill_sockaddr(&addr, name);
if (bind(fd, (struct sockaddr *)&addr, len) == -1) {
condlog(3, "Couldn't bind to ux_socket, error %d", errno);
close(fd);
return -1;
}
+#if USE_REGULAR_SOCKET
+ /*
+ * Socket needs to have rw permissions for everone.
+ * SO_PEERCRED makes sure that only root can modify things.
+ */
+ if (chmod(name, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) == -1)
+ condlog(3, "failed to set permissions on %s: %s", name, strerror(errno));
+#endif
if (listen(fd, 10) == -1) {
condlog(3, "Couldn't listen to ux_socket, error %d", errno);
close(fd);
@@ -41,7 +41,7 @@ ifeq ($(FPIN_SUPPORT),1)
OBJS += fpin_handlers.o
endif
-all : $(EXEC) $(CLI) $(MANPAGES) $(EXEC).service
+all : $(EXEC) $(CLI) $(MANPAGES) $(EXEC).service $(EXEC).socket
$(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so
@echo building $@ because of $?
@@ -74,11 +74,10 @@ uninstall:
$(Q)$(RM) $(DESTDIR)$(bindir)/$(EXEC) $(DESTDIR)$(bindir)/$(CLI)
$(Q)$(RM) $(DESTDIR)$(mandir)/man8/$(EXEC).8
$(Q)$(RM) $(DESTDIR)$(mandir)/man8/$(CLI).8
- $(Q)$(RM) $(DESTDIR)$(unitdir)/$(EXEC).service
- $(Q)$(RM) $(DESTDIR)$(unitdir)/$(EXEC).socket
+ $(Q)$(RM) $(DESTDIR)$(unitdir)/$(EXEC).socket $(EXEC).service
clean: dep_clean
- $(Q)$(RM) core *.o $(EXEC) $(CLI) $(MANPAGES) $(EXEC).service
+ $(Q)$(RM) core *.o $(EXEC) $(CLI) $(MANPAGES) $(EXEC).service $(EXEC).socket
include $(wildcard $(OBJS:.o=.d) $(CLI_OBJS:.o=.d))
similarity index 87%
rename from multipathd/multipathd.socket
rename to multipathd/multipathd.socket.in
@@ -7,7 +7,7 @@ ConditionVirtualization=!container
Before=sockets.target
[Socket]
-ListenStream=@/org/kernel/linux/storage/multipathd
+ListenStream=@MPATH_SOCKET@
[Install]
# Socket activation for multipathd is disabled by default.
Accessing multipathd's socket from a different network namespace (e.g. from a container) is impossible with an abstract socket. Add the option to compile multipathd using a regular Unix socket instead, by compiling with the flag "use_regular_socket=1". By default, the socket path is /run/multipathd. While at it, introduce a common helper function for filling in the struct sockaddr_un correctly, and make sure the socket name is properly NULL-terminated. [1] https://github.com/opensvc/multipath-tools/issues/111 Signed-off-by: Martin Wilck <mwilck@suse.com> --- .gitignore | 1 + Makefile.inc | 9 +++++-- README.md | 4 +++ libmpathcmd/libmpathcmd.version | 5 ++++ libmpathcmd/mpath_cmd.c | 27 +++++++++++++------ libmpathcmd/mpath_cmd.h | 6 +++++ libmpathutil/uxsock.c | 24 ++++++++++------- multipathd/Makefile | 7 +++-- ...multipathd.socket => multipathd.socket.in} | 2 +- 9 files changed, 61 insertions(+), 24 deletions(-) rename multipathd/{multipathd.socket => multipathd.socket.in} (87%)