[RFC] cups systemd socket activation patch
(re-sending unsigned to debian-printing as the mail got bounced back to
me with reason: 550 5.6.0 invalid message/* or multipart/* encoding
domain. The original msgid was <2349193.fqyuyHJ08B@gyllingar> .
Hi dear systemd maintainers,
(please make sure to CC debian-printing and pkg-systemd-maintainers when
answering)
as suggested by Michael on IRC, here I am with my initial import of
Lennart's patch to enable socket activation in CUPS. The current status
can be fetched from the master-systemd branch on the cups packaging
repository:
http://anonscm.debian.org/gitweb/?p=pkg-cups/cups.git;a=commitdiff;h=refs/heads/master-systemd
I have also attached the quilt patch (but the commit has the currently
needed packaging tweaks to make this work.
As I mentionned in the patch header, I fetched this patch from Gentoo
because their version copes with systemd not being pid 1 (which Fedora's
version doesn't).
Does the patch look sane enough for inclusion? Is the packaging
machinery around it good?
Also, there are some open upgrading questions:
* /etc/default/cups handles LOAD_LP_MODULE to enable or disable the
loading of the "lp" module for parallel printers; how should this be
handled?
* /etc/init.d/cups handles a udev trigger which commit message was:
> debian/cups.init.d: Trigger udev event for all USB printers right
> after starting the CUPS daemon to run the udev callouts for the
> printers. This allows automatic print queue setup and re-enabling
> print queues also if the printer is cold-plugged (connected before
> CUPS and/or udev got started).
How would this be handled in the systemd scheme?
Besides that, there was nothing obvious that I could see and a test-
print here worked.
Thanks in advance for any comments, cheers,
OdyX
Description: systemd socket activation support.
This variation of the patch is Gentoo's and features the runtime
detection of systemd, to have cups continue to work without systemd
enabled. It has been slightly amended (mostly whitespace fixes) to
bring it as close as possible to Fedora's.
.
Original description:
Subject: [PATCH] systemd: add systemd socket activation and unit files
.
On newer Linux machines systemd supports launchd-style socket
activation. This patch adds support for this mechanism and also adds
systemd unit files as appropriate to hook this up with systemd.
.
This includes an MIT-licensed drop-in file that implements the most
basic interfaces needed to get the file descriptors from systemd. Most
of the systemd and Linux-specific code compiles to NOPs on other
systems.
.
Three triggers to start CUPS are defined: a) if new printer hardware is
plugged in, b) when a client accesses the CUPS socket and c) when a
spool file resides in /var/spool/cups.
Origin: http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/net-print/cups/files/cups-1.5.0-systemd-socket-2.patch?view=markup
Origin: http://pkgs.fedoraproject.org/cgit/cups.git/tree/cups-systemd-socket.patch?id=7048cf473bca56b13d3c2f140fd749d561490784
From: Lennart Poettering <lennart@poettering.net>
Author: Lennart Poettering <lennart@poettering.net>
Last-Update: 2014-02-18
--- a/config.h.in
+++ b/config.h.in
@@ -451,6 +451,13 @@
/*
+ * Do we have systemd support?
+ */
+
+#undef HAVE_SYSTEMD
+
+
+/*
* Various scripting languages...
*/
--- /dev/null
+++ b/config-scripts/cups-systemd.m4
@@ -0,0 +1,36 @@
+dnl
+dnl "$Id$"
+dnl
+dnl systemd stuff for CUPS.
+
+dnl Find whether systemd is available
+
+SDLIBS=""
+AC_ARG_WITH([systemdsystemunitdir],
+ AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]),
+ [], [with_systemdsystemunitdir=$($PKGCONFIG --variable=systemdsystemunitdir systemd)])
+if test "x$with_systemdsystemunitdir" != xno; then
+ AC_MSG_CHECKING(for libsystemd-daemon)
+ AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])
+ if $PKGCONFIG --exists libsystemd-daemon; then
+ AC_MSG_RESULT(yes)
+ SDCFLAGS=`$PKGCONFIG --cflags libsystemd-daemon`
+ SDLIBS=`$PKGCONFIG --libs libsystemd-daemon`
+ AC_DEFINE(HAVE_SYSTEMD)
+ else
+ AC_MSG_RESULT(no)
+ fi
+fi
+
+if test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ; then
+ SYSTEMD_UNITS="cups.service cups.socket cups.path"
+else
+ SYSTEMD_UNITS=""
+fi
+
+AC_SUBST(SYSTEMD_UNITS)
+AC_SUBST(SDLIBS)
+
+dnl
+dnl "$Id$"
+dnl
--- a/configure.in
+++ b/configure.in
@@ -33,6 +33,7 @@
sinclude(config-scripts/cups-largefile.m4)
sinclude(config-scripts/cups-dnssd.m4)
sinclude(config-scripts/cups-launchd.m4)
+sinclude(config-scripts/cups-systemd.m4)
sinclude(config-scripts/cups-defaults.m4)
sinclude(config-scripts/cups-scripting.m4)
@@ -67,6 +68,9 @@
conf/snmp.conf
cups-config
data/testprint
+ data/cups.service
+ data/cups.socket
+ data/cups.path
desktop/cups.desktop
doc/help/ref-cups-files-conf.html
doc/help/ref-cupsd-conf.html
--- a/cups/usersys.c
+++ b/cups/usersys.c
@@ -1045,7 +1045,7 @@
struct stat sockinfo; /* Domain socket information */
if (!stat(CUPS_DEFAULT_DOMAINSOCKET, &sockinfo) &&
- (sockinfo.st_mode & S_IRWXO) == S_IRWXO)
+ (sockinfo.st_mode & (S_IROTH | S_IWOTH)) == (S_IROTH | S_IWOTH))
cups_server = CUPS_DEFAULT_DOMAINSOCKET;
else
#endif /* CUPS_DEFAULT_DOMAINSOCKET */
--- /dev/null
+++ b/data/cups.path.in
@@ -0,0 +1,8 @@
+[Unit]
+Description=CUPS Printer Service Spool
+
+[Path]
+PathExistsGlob=@CUPS_REQUESTS@/d*
+
+[Install]
+WantedBy=multi-user.target
--- /dev/null
+++ b/data/cups.service.in
@@ -0,0 +1,10 @@
+[Unit]
+Description=CUPS Printing Service
+
+[Service]
+ExecStart=@sbindir@/cupsd -f
+PrivateTmp=true
+
+[Install]
+Also=cups.socket cups.path
+WantedBy=printer.target
--- /dev/null
+++ b/data/cups.socket.in
@@ -0,0 +1,11 @@
+[Unit]
+Description=CUPS Printing Service Sockets
+
+[Socket]
+ListenStream=@CUPS_DEFAULT_DOMAINSOCKET@
+ListenStream=631
+ListenDatagram=0.0.0.0:631
+BindIPv6Only=ipv6-only
+
+[Install]
+WantedBy=sockets.target
--- a/data/Makefile
+++ b/data/Makefile
@@ -100,6 +100,12 @@
$(INSTALL_DATA) $$file $(DATADIR)/ppdc; \
done
$(INSTALL_DIR) -m 755 $(DATADIR)/profiles
+ if test "x$(SYSTEMD_UNITS)" != "x" ; then \
+ $(INSTALL_DIR) -m 755 $(SYSTEMDUNITDIR); \
+ for file in $(SYSTEMD_UNITS); do \
+ $(INSTALL_DATA) $$file $(SYSTEMDUNITDIR); \
+ done; \
+ fi
#
@@ -143,6 +149,9 @@
-$(RMDIR) $(DATADIR)/data
-$(RMDIR) $(DATADIR)/banners
-$(RMDIR) $(DATADIR)
+ for file in $(SYSTEMD_UNITS); do \
+ $(RM) $(SYSTEMDUNITDIR)/$$file; \
+ done
#
--- a/Makedefs.in
+++ b/Makedefs.in
@@ -134,6 +134,7 @@
CXXLIBS = @CXXLIBS@
DBUS_NOTIFIER = @DBUS_NOTIFIER@
DBUS_NOTIFIERLIBS = @DBUS_NOTIFIERLIBS@
+SYSTEMD_UNITS = @SYSTEMD_UNITS@
DNSSD_BACKEND = @DNSSD_BACKEND@
DSOFLAGS = -L../cups @DSOFLAGS@
DSOLIBS = @DSOLIBS@ $(COMMONLIBS)
@@ -141,6 +142,7 @@
IPPFIND_BIN = @IPPFIND_BIN@
IPPFIND_MAN = @IPPFIND_MAN@
LAUNCHDLIBS = @LAUNCHDLIBS@
+SDLIBS = @SDLIBS@
LDFLAGS = -L../cgi-bin -L../cups -L../filter -L../ppdc \
-L../scheduler @LDARCHFLAGS@ \
@LDFLAGS@ @RELROFLAGS@ @PIEFLAGS@ $(OPTIM)
@@ -232,6 +234,7 @@
DEFAULT_LAUNCHD_CONF = @DEFAULT_LAUNCHD_CONF@
DBUSDIR = @DBUSDIR@
+SYSTEMDUNITDIR = $(BUILDROOT)@systemdsystemunitdir@
#
--- a/scheduler/client.h
+++ b/scheduler/client.h
@@ -79,6 +79,9 @@
int fd; /* File descriptor for this server */
http_addr_t address; /* Bind address of socket */
http_encryption_t encryption; /* To encrypt or not to encrypt... */
+#ifdef HAVE_SYSTEMD
+ int is_systemd; /* Is this a systemd socket? */
+#endif /* HAVE_SYSTEMD */
} cupsd_listener_t;
--- a/scheduler/listen.c
+++ b/scheduler/listen.c
@@ -401,7 +401,11 @@
lis;
lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
{
- if (lis->fd != -1)
+ if (lis->fd != -1
+#ifdef HAVE_SYSTEMD
+ && !lis->is_systemd
+#endif /* HAVE_SYSTEMD */
+ )
{
#ifdef WIN32
closesocket(lis->fd);
--- a/scheduler/main.c
+++ b/scheduler/main.c
@@ -26,6 +26,8 @@
* launchd_checkin() - Check-in with launchd and collect the listening
* fds.
* launchd_checkout() - Update the launchd KeepAlive file as needed.
+ * systemd_checkin() - Check-in with systemd and collect the
+ * listening fds.
* parent_handler() - Catch USR1/CHLD signals...
* process_children() - Process all dead children...
* select_timeout() - Calculate the select timeout value.
@@ -62,6 +64,10 @@
# endif /* !LAUNCH_JOBKEY_SERVICEIPC */
#endif /* HAVE_LAUNCH_H */
+#ifdef HAVE_SYSTEMD
+#include <systemd/sd-daemon.h>
+#endif /* HAVE_SYSTEMD */
+
#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
# include <malloc.h>
#endif /* HAVE_MALLOC_H && HAVE_MALLINFO */
@@ -83,6 +89,9 @@
static void launchd_checkin(void);
static void launchd_checkout(void);
#endif /* HAVE_LAUNCHD */
+#ifdef HAVE_SYSTEMD
+static int systemd_checkin(void);
+#endif /* HAVE_SYSTEMD */
static void parent_handler(int sig);
static void process_children(void);
static void sigchld_handler(int sig);
@@ -568,6 +577,14 @@
}
#endif /* HAVE_LAUNCHD */
+#ifdef HAVE_SYSTEMD
+ /*
+ * If we were started by systemd get the listen sockets file descriptors...
+ */
+ if (systemd_checkin() < 0)
+ exit(EXIT_FAILURE);
+#endif /* HAVE_SYSTEMD */
+
/*
* Startup the server...
*/
@@ -764,6 +781,16 @@
}
#endif /* HAVE_LAUNCHD */
+#ifdef HAVE_SYSTEMD
+ /*
+ * If we were started by systemd get the listen sockets file
+ * descriptors...
+ */
+
+ if (systemd_checkin() < 0)
+ exit(EXIT_FAILURE);
+#endif /* HAVE_SYSTEMD */
+
/*
* Startup the server...
*/
@@ -1523,6 +1550,104 @@
}
#endif /* HAVE_LAUNCHD */
+#ifdef HAVE_SYSTEMD
+static int
+systemd_checkin(void)
+{
+ int n, fd;
+
+ n = sd_listen_fds(0);
+ if (n < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "systemd_checkin: Failed to acquire sockets from systemd - %s"
+ " -- skipping systemd activation",
+ strerror(-n));
+ return (1);
+ }
+
+ if (n == 0)
+ return (0);
+
+ for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++)
+ {
+ http_addr_t addr;
+ socklen_t addrlen = sizeof (addr);
+ int r;
+ cupsd_listener_t *lis;
+ char s[256];
+
+ r = sd_is_socket(fd, AF_UNSPEC, SOCK_STREAM, 1);
+ if (r < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "systemd_checkin: Unable to verify socket type - %s",
+ strerror(-r));
+ continue;
+ }
+
+ if (!r)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "systemd_checkin: Socket not of the right type");
+ continue;
+ }
+
+ if (getsockname(fd, (struct sockaddr*) &addr, &addrlen))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "systemd_checkin: Unable to get local address - %s",
+ strerror(errno));
+ continue;
+ }
+
+ /*
+ * Try to match the systemd socket address to one of the listeners...
+ */
+
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ if (httpAddrEqual(&lis->address, &addr))
+ break;
+
+ if (lis)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "systemd_checkin: Matched existing listener %s with fd %d...",
+ httpAddrString(&(lis->address), s, sizeof(s)), fd);
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "systemd_checkin: Adding new listener %s with fd %d...",
+ httpAddrString(&addr, s, sizeof(s)), fd);
+
+ if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "systemd_checkin: Unable to allocate listener - "
+ "%s.", strerror(errno));
+ return (-ENOMEM);
+ }
+
+ cupsArrayAdd(Listeners, lis);
+
+ memcpy(&lis->address, &addr, sizeof(lis->address));
+ }
+
+ lis->fd = fd;
+ lis->is_systemd = 1;
+
+# ifdef HAVE_SSL
+ if (_httpAddrPort(&(lis->address)) == 443)
+ lis->encryption = HTTP_ENCRYPT_ALWAYS;
+# endif /* HAVE_SSL */
+ }
+
+ return (0);
+}
+#endif /* HAVE_SYSTEMD */
/*
* 'parent_handler()' - Catch USR1/CHLD signals...
--- a/scheduler/Makefile
+++ b/scheduler/Makefile
@@ -383,7 +383,7 @@
$(CC) $(LDFLAGS) -o cupsd $(CUPSDOBJS) -L. -lcupsmime \
$(LIBZ) $(SSLLIBS) $(LIBSLP) $(LIBLDAP) $(PAMLIBS) \
$(LIBPAPER) $(LIBMALLOC) $(SERVERLIBS) $(DNSSDLIBS) $(LIBS) \
- $(LIBGSSAPI) $(LIBWRAP)
+ $(LIBGSSAPI) $(LIBWRAP) $(SDLIBS)
cupsd-static: $(CUPSDOBJS) libcupsmime.a ../cups/$(LIBCUPSSTATIC)
echo Linking $@...
@@ -391,7 +391,7 @@
$(LIBZ) $(SSLLIBS) $(LIBSLP) $(LIBLDAP) $(PAMLIBS) \
../cups/$(LIBCUPSSTATIC) $(COMMONLIBS) $(LIBZ) $(LIBPAPER) \
$(LIBMALLOC) $(SERVERLIBS) $(DNSSDLIBS) $(LIBGSSAPI) \
- $(LIBWRAP)
+ $(LIBWRAP) $(SDLIBS)
tls.o: tls-darwin.c tls-gnutls.c tls-openssl.c
Reply to: