[Dovecot] add basic systemd support to dovecot

Christophe Fergeau cfergeau at gmail.com
Sun Nov 14 23:44:21 EET 2010


Hi,

Sorry for the delay in replying, I was away for a few weeks :) I have finally
reworked the patch according to your feedback.

On Mon, Oct 25, 2010 at 05:47:20PM +0100, Timo Sirainen wrote:
> You can simplify the environment preserving with these changes:
> 
> http://hg.dovecot.org/dovecot-2.0/rev/e0a97842182f
> http://hg.dovecot.org/dovecot-2.0/rev/d1fd5b84d410

Ah, that indeed makes things much simpler, thanks!

> 
> I don't think this is portable. You could do it instead like:

Ok, I changed it even after reading your other email.

> 
> > +        AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]),
> > +        [], [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)])
> 
> Is this a common name for this option? If not, I'd prefer a shorter
> name.

I asked upstream about it, and I was told it's the usual way of naming options
with the autotools, so they'd prefer if it was kept this way. But I don't mind
changing it to something else if you prefer, I have a patch changing it to
--with-systemd if needed.

Here is the updated patch, if you want I also have it as a patch series:
systemd: Add proper systemd configure.in blob (from daemon(7))
systemd: Preserve LISTEN_FDS and LISTEN_PID during env cleanup when systemd is used
systemd: Use sockets provided by systemd if possible
systemd: When systemd didn't provide a suitable socket, fallback to the regular socket creation code
systemd: Add systemd unit files

Christophe
-------------- next part --------------
diff --git a/Makefile.am b/Makefile.am
index d037258..8a6000a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -49,6 +49,17 @@ dovecot-config: dovecot-config.in Makefile
 	-e "s|^\(dovecot_moduledir\)=|\1=$(moduledir)|" \
 	> dovecot-config
 
+if HAVE_SYSTEMD
+%.service: %.service.in
+	$(AM_V_GEN)sed -e 's, at sbindir\@,$(sbindir),g' $< > $@
+
+systemdsystemunit_DATA = \
+        dovecot.socket \
+        dovecot.service
+else
+EXTRA_DIST+= dovecot.socket dovecot.service.in
+endif
+
 install-exec-hook:
 	rm $(DESTDIR)$(pkglibdir)/dovecot-config && \
 	grep -v '^LIBDOVECOT_.*_INCLUDE' dovecot-config | \
@@ -62,6 +73,9 @@ install-exec-hook:
 	> $(DESTDIR)$(pkglibdir)/dovecot-config
 
 CLEANFILES = $(datafiles)
+if HAVE_SYSTEMD
+CLEANFILES += $systedmsystemunit_DATA
+endif
 
 DISTCLEANFILES = $(top_builddir)/dovecot-version.h
 
diff --git a/configure.in b/configure.in
index 348f441..ecb3046 100644
--- a/configure.in
+++ b/configure.in
@@ -2628,6 +2628,16 @@ fi
 AC_SUBST(RUN_TEST)
 AC_SUBST(abs_top_builddir)
 
+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; then
+        AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])
+        AC_DEFINE(HAVE_SYSTEMD,, Define if you want to use systemd socket activation)
+fi
+AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ])
+
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_FILES([
 Makefile
diff --git a/dovecot.service.in b/dovecot.service.in
new file mode 100644
index 0000000..db03946
--- /dev/null
+++ b/dovecot.service.in
@@ -0,0 +1,8 @@
+[Unit]
+Description=Dovecot IMAP/POP3 email server
+After=local-fs.target network.target
+
+[Service]
+Type=simple
+ExecStart=@sbindir@/dovecot -F
+NonBlocking=yes
diff --git a/dovecot.socket b/dovecot.socket
new file mode 100644
index 0000000..0fdef6f
--- /dev/null
+++ b/dovecot.socket
@@ -0,0 +1,15 @@
+[Unit]
+Description=Dovecot IMAP/POP3 email server activation socket
+
+[Socket]
+#dovecot expects separate IPv4 and IPv6 sockets
+BindIPv6Only=ipv6-only
+ListenStream=0.0.0.0:143
+ListenStream=[::]:143
+ListenStream=0.0.0.0:993
+ListenStream=[::]:993
+KeepAlive=true
+
+[Install]
+WantedBy=sockets.target
+
diff --git a/src/lib-master/master-service.c b/src/lib-master/master-service.c
index e2dc98d..5925bb6 100644
--- a/src/lib-master/master-service.c
+++ b/src/lib-master/master-service.c
@@ -400,6 +400,10 @@ void master_service_env_clean(bool preserve_home)
 #ifdef DEBUG
 		"GDB",
 #endif
+#ifdef HAVE_SYSTEMD
+		"LISTEN_PID",
+		"LISTEN_FDS",
+#endif
 		NULL
 	};
 	env_clean_except(preserve_envs + (preserve_home ? 0 : 1));
diff --git a/src/master/Makefile.am b/src/master/Makefile.am
index 526b75b..9d3ad78 100644
--- a/src/master/Makefile.am
+++ b/src/master/Makefile.am
@@ -2,6 +2,11 @@ pkglibexecdir = $(libexecdir)/dovecot
 
 sbin_PROGRAMS = dovecot
 
+if HAVE_SYSTEMD
+SYSTEMD_SOURCES = sd-daemon.c
+endif
+
+
 AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/lib \
 	-I$(top_srcdir)/src/lib-settings \
@@ -27,13 +32,15 @@ dovecot_SOURCES = \
 	service-monitor.c \
 	service-process.c \
 	service-process-notify.c \
-	service.c
+	service.c \
+	$(SYSTEMD_SOURCES)
 
 noinst_HEADERS = \
 	capabilities.h \
 	common.h \
 	dup2-array.h \
 	master-settings.h \
+	sd-daemon.h \
 	service-anvil.h \
 	service-listen.h \
 	service-log.h \
@@ -41,3 +48,4 @@ noinst_HEADERS = \
 	service-process.h \
 	service-process-notify.h \
 	service.h
+
diff --git a/src/master/main.c b/src/master/main.c
index 5e390d6..2d862a0 100644
--- a/src/master/main.c
+++ b/src/master/main.c
@@ -601,6 +601,10 @@ int main(int argc, char *argv[])
 	static const char *preserve_envs[] = {
 		/* AIX depends on TZ to get the timezone correctly. */
 		"TZ",
+#ifdef HAVE_SYSTEMD
+		"LISTEN_PID",
+		"LISTEN_FDS",
+#endif
 		NULL
 	};
 	struct master_settings *set;
diff --git a/src/master/service-listen.c b/src/master/service-listen.c
index 318c098..976036b 100644
--- a/src/master/service-listen.c
+++ b/src/master/service-listen.c
@@ -5,6 +5,9 @@
 #include "fd-set-nonblock.h"
 #include "fd-close-on-exec.h"
 #include "network.h"
+#ifdef HAVE_SYSTEMD
+#include "sd-daemon.h"
+#endif
 #include "service.h"
 #include "service-listen.h"
 
@@ -147,20 +150,47 @@ static int service_inet_listener_listen(struct service_listener *l)
         struct service *service = l->service;
 	const struct inet_listener_settings *set = l->set.inetset.set;
 	unsigned int port = set->port;
-	int fd;
-
-	fd = net_listen(&l->set.inetset.ip, &port,
-			service_get_backlog(service));
-	if (fd < 0) {
-		service_error(service, "listen(%s, %u) failed: %m",
-			      l->inet_address, set->port);
-		return errno == EADDRINUSE ? 0 : -1;
+	int fd = -1;
+#ifdef HAVE_SYSTEMD
+	int n;
+
+	n = sd_listen_fds(0);
+	if (n < 0) {
+		errno = -n;
+		goto failure;
+	} else if (n > 0) {
+		for (fd = SD_LISTEN_FDS_START;
+		     fd <= SD_LISTEN_FDS_START + n - 1;
+		     fd++) {
+			if (sd_is_socket_inet(fd, l->set.inetset.ip.family,
+					      SOCK_STREAM, 1, port))
+				break;
+		}
+		if (fd > SD_LISTEN_FDS_START + n - 1) {
+			/* when systemd didn't provide a usable socket,
+			 * fall back to the regular socket creation code
+			 */
+			fd = -1;
+		}
+	}
+#endif
+
+	if (fd == -1) {
+		fd = net_listen(&l->set.inetset.ip, &port,
+				service_get_backlog(service));
+		if (fd < 0)
+			goto failure;
+		net_set_nonblock(fd, TRUE);
+		fd_close_on_exec(fd, TRUE);
 	}
-	net_set_nonblock(fd, TRUE);
-	fd_close_on_exec(fd, TRUE);
 
 	l->fd = fd;
 	return 1;
+
+failure:
+	service_error(service, "listen(%s, %u) failed: %m",
+		      l->inet_address, set->port);
+	return errno == EADDRINUSE ? 0 : -1;
 }
 
 static int service_listen(struct service *service)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
Url : http://dovecot.org/pipermail/dovecot/attachments/20101114/777eaa8d/attachment.bin 


More information about the dovecot mailing list