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

[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: