rpcbind/0010-Support-systemd-activation.patch

373 lines
9.4 KiB
Diff
Raw Normal View History

From c3ec796dd8f177a3c6ab9b76de490dbfe2c86476 Mon Sep 17 00:00:00 2001
From: Olaf Kirch <okir@suse.de>
Date: Tue, 20 Aug 2013 11:26:42 +0200
Subject: [PATCH 10/13] Support systemd activation.
This code is loosely based on previous work by Tom Gundersen <teg@jklm.no>.
Signed-off-by: Olaf Kirch <okir@suse.de>
---
Makefile.am | 15 ++++
configure.ac | 11 +++
src/rpcbind.c | 172 ++++++++++++++++++++++++++++++++++++---------
systemd/.gitignore | 1 +
systemd/rpcbind.service.in | 9 +++
systemd/rpcbind.socket | 12 ++++
6 files changed, 188 insertions(+), 32 deletions(-)
create mode 100644 systemd/.gitignore
create mode 100644 systemd/rpcbind.service.in
create mode 100644 systemd/rpcbind.socket
diff --git a/Makefile.am b/Makefile.am
index d10c906..df755dd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -38,6 +38,21 @@ rpcbind_SOURCES = \
src/warmstart.c
rpcbind_LDADD = $(TIRPC_LIBS)
+if SYSTEMD
+AM_CPPFLAGS += $(SYSTEMD_CFLAGS) -DSYSTEMD
+
+rpcbind_LDADD += $(SYSTEMD_LIBS)
+
+systemd/rpcbind.service: systemd/rpcbind.service.in Makefile
+ sed -e 's,@bindir\@,$(bindir),g' \
+ < $< > $@ || rm $@
+
+systemdsystemunit_DATA = \
+ systemd/rpcbind.service \
+ systemd/rpcbind.socket
+
+endif
+
rpcinfo_SOURCES = src/rpcinfo.c
rpcinfo_LDADD = $(TIRPC_LIBS)
diff --git a/configure.ac b/configure.ac
index 1cf42d3..a94933b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -29,6 +29,17 @@ AC_SUBST([rpcuser], [$with_rpcuser])
PKG_CHECK_MODULES([TIRPC], [libtirpc])
+PKG_PROG_PKG_CONFIG
+AC_ARG_WITH([systemdsystemunitdir],
+ AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]),
+ [], [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)])
+ if test "x$with_systemdsystemunitdir" != xno -a "x$with_systemdsystemunitdir" != "x"; then
+ AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])
+ PKG_CHECK_MODULES([SYSTEMD], [libsystemd-daemon])
+ fi
+AM_CONDITIONAL(SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ])
+
+
AS_IF([test x$enable_libwrap = xyes], [
AC_CHECK_LIB([wrap], [hosts_access], ,
AC_MSG_ERROR([libwrap support requested but unable to find libwrap]))
diff --git a/src/rpcbind.c b/src/rpcbind.c
index 1d59362..32e6deb 100644
--- a/src/rpcbind.c
+++ b/src/rpcbind.c
@@ -56,6 +56,9 @@
#include <netinet/in.h>
#endif
#include <arpa/inet.h>
+#ifdef SYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
#include <fcntl.h>
#include <netdb.h>
#include <stdio.h>
@@ -100,6 +103,9 @@ int runasdaemon = 0;
int insecure = 0;
int oldstyle_local = 0;
int verboselog = 0;
+#ifdef SYSTEMD
+int systemd_activation = 0;
+#endif
char **hosts = NULL;
int nhosts = 0;
@@ -123,6 +129,10 @@ static char superuser[] = "superuser";
int main __P((int, char *[]));
+static void init_transports_daemon __P((void));
+#ifdef SYSTEMD
+static void init_transports_systemd __P((void));
+#endif
static int init_transport __P((struct netconfig *));
static void rbllist_add __P((rpcprog_t, rpcvers_t, struct netconfig *,
struct netbuf *));
@@ -132,11 +142,15 @@ static void parseargs __P((int, char *[]));
int
main(int argc, char *argv[])
{
- struct netconfig *nconf;
- void *nc_handle; /* Net config handle */
struct rlimit rl;
int maxrec = RPC_MAXDATASIZE;
+#ifdef SYSTEMD
+ /* See whether we've been activated by systemd */
+ if (sd_listen_fds(0) > 0)
+ systemd_activation = 1;
+#endif
+
parseargs(argc, argv);
/* Check that another rpcbind isn't already running. */
@@ -167,29 +181,14 @@ main(int argc, char *argv[])
*/
__nss_configure_lookup("services", "files");
- nc_handle = setnetconfig(); /* open netconfig file */
- if (nc_handle == NULL) {
- syslog(LOG_ERR, "could not read /etc/netconfig");
- exit(1);
- }
-
- nconf = getnetconfigent("local");
- if (nconf == NULL)
- nconf = getnetconfigent("unix");
- if (nconf == NULL) {
- syslog(LOG_ERR, "%s: can't find local transport\n", argv[0]);
- exit(1);
- }
-
rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
- init_transport(nconf);
-
- while ((nconf = getnetconfig(nc_handle))) {
- if (nconf->nc_flag & NC_VISIBLE)
- init_transport(nconf);
- }
- endnetconfig(nc_handle);
+#ifdef SYSTEMD
+ if (systemd_activation)
+ init_transports_systemd();
+ else
+#endif
+ init_transports_daemon();
#ifdef PORTMAP
if (!udptrans)
@@ -571,17 +570,29 @@ rpcbind_register_transport(struct netconfig *nconf, SVCXPRT *xprt, struct netbuf
* <0: error - ignore this netid
*/
static int
-rpcbind_init_endpoint(struct netconfig *nconf, const char *hostname)
+rpcbind_init_endpoint(struct netconfig *nconf, const char *hostname, int fd)
{
struct t_bind taddr;
SVCXPRT *my_xprt = NULL;
- int r, fd = -1;
+ int r;
memset(&taddr, 0, sizeof(taddr));
- r = create_transport_socket(nconf, hostname, &taddr.addr, &fd);
- if (r <= 0)
- return r;
+ if (fd < 0) {
+ r = create_transport_socket(nconf, hostname, &taddr.addr, &fd);
+ if (r <= 0)
+ return r;
+ } else {
+ struct sockaddr_storage addr;
+ socklen_t alen = sizeof(addr);
+
+ if (getsockname(fd, (struct sockaddr *) &addr, &alen) < 0) {
+ syslog(LOG_ERR, "cannot get address for socket fd %d", fd);
+ exit(1);
+ }
+
+ sockaddr2netbuf((struct sockaddr *) &addr, alen, &taddr.addr);
+ }
my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
if (my_xprt == (SVCXPRT *)NULL) {
@@ -645,12 +656,12 @@ init_transport(struct netconfig *nconf)
/* Ensure that we always bind to loopback */
switch (si.si_af) {
case AF_INET:
- if (rpcbind_init_endpoint(nconf, "127.0.0.1") > 0)
+ if (rpcbind_init_endpoint(nconf, "127.0.0.1", -1) > 0)
numbound++;
break;
case AF_INET6:
- if (rpcbind_init_endpoint(nconf, "::1") > 0)
+ if (rpcbind_init_endpoint(nconf, "::1", -1) > 0)
numbound++;
break;
}
@@ -662,7 +673,7 @@ init_transport(struct netconfig *nconf)
if (strcmp("*", hostname) == 0)
hostname = NULL;
- r = rpcbind_init_endpoint(nconf, hostname);
+ r = rpcbind_init_endpoint(nconf, hostname, -1);
if (r < 0)
return 1;
if (r > 0)
@@ -672,7 +683,7 @@ init_transport(struct netconfig *nconf)
if (numbound == 0)
return 1;
} else {
- if (rpcbind_init_endpoint(nconf, NULL) <= 0)
+ if (rpcbind_init_endpoint(nconf, NULL, -1) <= 0)
return 1;
}
@@ -699,6 +710,103 @@ init_transport(struct netconfig *nconf)
}
static void
+init_transports_daemon(void)
+{
+ void *nc_handle;
+ struct netconfig *nconf;
+
+ nc_handle = setnetconfig(); /* open netconfig file */
+ if (nc_handle == NULL) {
+ syslog(LOG_ERR, "could not read /etc/netconfig");
+ exit(1);
+ }
+
+ nconf = getnetconfigent("local");
+ if (nconf == NULL)
+ nconf = getnetconfigent("unix");
+ if (nconf == NULL) {
+ syslog(LOG_ERR, "rpcbind: can't find local transport\n");
+ exit(1);
+ }
+
+ init_transport(nconf);
+
+ while ((nconf = getnetconfig(nc_handle))) {
+ if (nconf->nc_flag & NC_VISIBLE)
+ init_transport(nconf);
+ }
+ endnetconfig(nc_handle);
+}
+
+#ifdef SYSTEMD
+static struct netconfig *
+sockinfo2nconf(void **handlep, const struct __rpc_sockinfo *match)
+{
+ struct netconfig *nconf;
+
+ if (*handlep)
+ endnetconfig(*handlep);
+ *handlep = setnetconfig();
+
+ while ((nconf = getnetconfig(*handlep))) {
+ struct __rpc_sockinfo si;
+
+ if (!__rpc_nconf2sockinfo(nconf, &si))
+ continue;
+
+ if (si.si_af == match->si_af
+ && si.si_socktype == match->si_socktype
+ && si.si_proto == match->si_proto)
+ return nconf;
+ }
+ return NULL;
+}
+
+static void
+init_transports_systemd()
+{
+ void *nc_handle = NULL;
+ int nfds, n;
+
+ if ((nfds = sd_listen_fds(0)) < 0) {
+ syslog(LOG_ERR, "failed to acquire systemd sockets: %s", strerror(-nfds));
+ exit(1);
+ }
+ if (nfds >= 16) {
+ syslog(LOG_ERR, "too many sockets passed by systemd (%u)", nfds);
+ exit(1);
+ }
+
+ for (n = 0; n < nfds; ++n) {
+ struct netconfig *nconf;
+ struct __rpc_sockinfo si;
+ int fd;
+
+ fd = SD_LISTEN_FDS_START + n;
+
+ if (!__rpc_fd2sockinfo(fd, &si)) {
+ syslog(LOG_ERR, "cannot get socket information for fd %d", fd);
+ exit(1);
+ }
+
+ /* Now find the netconfig entry matching this transport */
+ if ((nconf = sockinfo2nconf(&nc_handle, &si)) == NULL) {
+ syslog(LOG_ERR, "not netconfig for socket fd %d", fd);
+ exit(1);
+ }
+
+ if (rpcbind_init_endpoint(nconf, NULL, fd) <= 0) {
+ syslog(LOG_ERR, "unable to create transport for socket fd %d", fd);
+ exit(1);
+ }
+ }
+
+ if (nc_handle)
+ endnetconfig(nc_handle);
+}
+#endif
+
+static void
rbllist_add(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf,
struct netbuf *addr)
{
diff --git a/systemd/.gitignore b/systemd/.gitignore
new file mode 100644
index 0000000..b7b4561
--- /dev/null
+++ b/systemd/.gitignore
@@ -0,0 +1 @@
+rpcbind.service
diff --git a/systemd/rpcbind.service.in b/systemd/rpcbind.service.in
new file mode 100644
index 0000000..58ae5de
--- /dev/null
+++ b/systemd/rpcbind.service.in
@@ -0,0 +1,9 @@
+[Unit]
+Description=RPC Bind
+
+[Service]
+ExecStart=@bindir@/rpcbind -w -f
+
+[Install]
+WantedBy=multi-user.target
+Also=rpcbind.socket
diff --git a/systemd/rpcbind.socket b/systemd/rpcbind.socket
new file mode 100644
index 0000000..ad5fd62
--- /dev/null
+++ b/systemd/rpcbind.socket
@@ -0,0 +1,12 @@
+[Unit]
+Description=RPCbind Server Activation Socket
+Wants=rpcbind.target
+Before=rpcbind.target
+
+[Socket]
+ListenStream=/var/run/rpcbind.sock
+ListenStream=111
+ListenDatagram=111
+
+[Install]
+WantedBy=sockets.target
--
1.7.12.4