commit de54dc7b6030c06e24e06f122e3c47da28853e0d
Author: Didier Raboud <odyx@debian.org>
Date:   Tue Mar 4 18:26:41 2014 +0100

    WIP for 740382
---
 debian/cups-daemon.links                           |   1 +
 debian/cups-daemon.postinst                        |  28 ++
 debian/patches/cupsd-write-systemd-Port.patch      | 294 +++++++++++++++++++++
 debian/patches/series                              |   1 +
 .../systemd-optional-socket-activation.patch       |   4 +-
 5 files changed, 325 insertions(+), 3 deletions(-)

diff --git a/debian/cups-daemon.links b/debian/cups-daemon.links
new file mode 100644
index 0000000..182edc1
--- /dev/null
+++ b/debian/cups-daemon.links
@@ -0,0 +1 @@
+etc/cups/cupsd-systemd-listen.conf etc/systemd/system/cups.socket.d/cupsd-listen.conf
diff --git a/debian/cups-daemon.postinst b/debian/cups-daemon.postinst
index 258e61f..25ab95b 100644
--- a/debian/cups-daemon.postinst
+++ b/debian/cups-daemon.postinst
@@ -8,6 +8,34 @@ if [ "$1" = configure ]; then
 	addgroup --system lpadmin
     fi
 
+    if [ ! -f /etc/cups/cupsd-systemd-listen.conf ]; then
+	cat >/etc/cups/cupsd-systemd-listen.conf <<EOF
+[Socket]
+# This file was generated by CUPS and _WILL_ be deleted or overwritten by it!
+# It has to be kept in sync with the Port and Listen stanzas in /etc/cups/cupsd.conf
+# It is by default symlinked as cups-listen.conf in the
+# /etc/systemd/system/cups.socket.d/ directory. Remove the symlink
+# and write your own file there if you don't want this. See systemd.socket(5).
+EOF
+        if grep -q '^\s*Listen localhost:' /etc/cups/cupsd.conf 2>/dev/null; then
+            localport=`grep '^\s*Listen localhost:' /etc/cups/cupsd.conf | head -n1 | sed -e 's/.*localhost\:\([[:digit:]]*\)$/\1/'`
+            cat >>/etc/cups/cupsd-systemd-listen.conf <<EOF
+# Matches 'Listen localhost:$localport' from cupsd.conf
+ListenStream=127.0.0.1:$localport
+ListenStream=[::1]:$localport
+EOF
+        fi
+
+        if grep -q '^\s*Port' /etc/cups/cupsd.conf 2>/dev/null; then
+            localport=`grep '^\s*Port' /etc/cups/cupsd.conf | head -n1 | sed -e 's/.*Port \([[:digit:]]*\)$/\1/'`
+            cat >>/etc/cups/cupsd-systemd-listen.conf <<EOF
+# Matches 'Port $localport' from cupsd.conf
+ListenStream=0.0.0.0:$localport
+ListenStream=[::]:$localport
+EOF
+        fi
+    fi
+
     for i in /etc/cups/classes.conf /etc/cups/printers.conf
     do
         if [ -f $i ] && ! dpkg-statoverride --list $i > /dev/null; then
diff --git a/debian/patches/cupsd-write-systemd-Port.patch b/debian/patches/cupsd-write-systemd-Port.patch
new file mode 100644
index 0000000..e4b3f2b
--- /dev/null
+++ b/debian/patches/cupsd-write-systemd-Port.patch
@@ -0,0 +1,294 @@
+Description: When using the webinterface to widen or shrink the range of
+ IPs that cupsd will listen to, also write systemd-compatible socket
+ unit configuration.
+ .
+ When this file is written by the scheduler, also reload the systemd
+ daemon and let systemd restart the cups.socket. This makes sure that
+ systemd is always the owner of the ports and enables socket activation
+ through all the ports that cupsd listens to.
+ .
+ This is enabled throught the cupsd-listen.conf symlink to
+ /etc/cups/cupsd-systemd-listen.conf in the
+ /etc/systemd/system/cups.socket.d/ directory.
+Author: Didier Raboud <odyx@debian.org>
+Last-Update: 2014-03-05
+--- a/cups/adminutil.c
++++ b/cups/adminutil.c
+@@ -1209,6 +1209,8 @@
+   cups_option_t	*cupsd_settings,	/* New settings */
+ 		*setting;		/* Current setting */
+   _cups_globals_t *cg = _cupsGlobals();	/* Global data */
++  char		tempfiled[1024];	/* Temporary new cupsd-systemd-listen.conf */
++  cups_file_t	*systemdlistenconf;	/* cupsd-systemd-listen.conf file */
+ 
+ 
+  /*
+@@ -1403,6 +1405,15 @@
+   }
+ 
+  /*
++  * Create a temporary file for the new cupsd-systemd-listen.conf...
++  */
++  if ((systemdlistenconf = cupsTempFile2(tempfiled, sizeof(tempfiled))) == NULL)
++  {
++    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, NULL, 0);
++    return (0);
++  }
++
++ /*
+   * Copy the old file to the new, making changes along the way...
+   */
+ 
+@@ -1444,16 +1455,35 @@
+       {
+         wrote_port_listen = 1;
+ 
++        cupsFilePuts(systemdlistenconf,"[Socket]\n");
++        cupsFilePuts(systemdlistenconf,"# This file was generated by CUPS and _WILL_ be deleted or overwritten by it!\n");
++        cupsFilePuts(systemdlistenconf,"# It has to be kept in sync with the Port and Listen stanzas in /etc/cups/cupsd.conf\n");
++        cupsFilePuts(systemdlistenconf,"# It is by default symlinked as cups-listen.conf in the\n");
++        cupsFilePuts(systemdlistenconf,"# /etc/systemd/system/cups.socket.d/ directory. Remove the symlink\n");
++        cupsFilePuts(systemdlistenconf,"# and write your own file there if you don't want this. See systemd.socket(5).\n");
++
+ 	if (remote_admin > 0 || remote_any > 0 || share_printers > 0)
+ 	{
+ 	  cupsFilePuts(temp, "# Allow remote access\n");
+ 	  cupsFilePrintf(temp, "Port %d\n", server_port);
++
++	  /* Let systemd's socket configuration listen on all port numbers */
++	  cupsFilePuts(systemdlistenconf,   "# Allow remote access\n");
++	  cupsFilePrintf(systemdlistenconf, "# Matches 'Port %d' from cupsd.conf.\n",ippPort());
++	  cupsFilePrintf(systemdlistenconf, "ListenStream=0.0.0.0:%d\n", server_port);
++	  cupsFilePrintf(systemdlistenconf, "ListenStream=[::]:%d\n", server_port);
+ 	}
+ 	else
+ 	{
+ 	  cupsFilePuts(temp, "# Only listen for connections from the local "
+ 	                     "machine.\n");
+ 	  cupsFilePrintf(temp, "Listen localhost:%d\n", server_port);
++
++	  /* Let systemd's socket configuration listen only on local IP addresses */
++	  cupsFilePuts(systemdlistenconf,   "# Only listen for connections from the local machine.\n");
++	  cupsFilePrintf(systemdlistenconf, "# Matches 'Listen localhost:%d' from cupsd.conf.\n",ippPort());
++	  cupsFilePrintf(systemdlistenconf, "ListenStream=127.0.0.1:%d\n", server_port);
++	  cupsFilePrintf(systemdlistenconf, "ListenStream=[::1]:%d\n", server_port);
+ 	}
+ 
+ #ifdef CUPS_DEFAULT_DOMAINSOCKET
+@@ -1801,16 +1831,35 @@
+   if (!wrote_port_listen &&
+       (remote_admin >= 0 || remote_any > 0 || share_printers >= 0))
+   {
++    cupsFilePuts(systemdlistenconf,"[Socket]\n");
++    cupsFilePuts(systemdlistenconf,"# This file was generated by CUPS and _WILL_ be deleted or overwritten by it!\n");
++    cupsFilePuts(systemdlistenconf,"# It has to be kept in sync with the Port and Listen stanzas in /etc/cups/cupsd.conf\n");
++    cupsFilePuts(systemdlistenconf,"# It is by default symlinked as cups-listen.conf in the\n");
++    cupsFilePuts(systemdlistenconf,"# /etc/systemd/system/cups.socket.d/ directory. Remove the symlink\n");
++    cupsFilePuts(systemdlistenconf,"# and write your own file there if you don't want this. See systemd.socket(5).\n\n");
++
+     if (remote_admin > 0 || remote_any > 0 || share_printers > 0)
+     {
+       cupsFilePuts(temp, "# Allow remote access\n");
+       cupsFilePrintf(temp, "Port %d\n", ippPort());
++
++      /* Let systemd's socket configuration listen on all port numbers */
++      cupsFilePuts(systemdlistenconf,   "# Allow remote access\n");
++      cupsFilePrintf(systemdlistenconf, "# Matches 'Port %d' from cupsd.conf.\n",ippPort());
++      cupsFilePrintf(systemdlistenconf, "ListenStream=0.0.0.0:%d\n", ippPort());
++      cupsFilePrintf(systemdlistenconf, "ListenStream=[::]:%d\n", ippPort());
+     }
+     else
+     {
+       cupsFilePuts(temp,
+                    "# Only listen for connections from the local machine.\n");
+       cupsFilePrintf(temp, "Listen localhost:%d\n", ippPort());
++
++      /* Let systemd's socket configuration listen only on local IP addresses */
++      cupsFilePuts(systemdlistenconf,   "# Only listen for connections from the local machine.\n");
++      cupsFilePrintf(systemdlistenconf, "# Matches 'Listen localhost:%d' from cupsd.conf.\n",ippPort());
++      cupsFilePrintf(systemdlistenconf, "ListenStream=127.0.0.1:%d\n", ippPort());
++      cupsFilePrintf(systemdlistenconf, "ListenStream=[::1]:%d\n", ippPort());
+     }
+ 
+ #ifdef CUPS_DEFAULT_DOMAINSOCKET
+@@ -1947,6 +1996,16 @@
+ 
+   cupsFileClose(cupsd);
+   cupsFileClose(temp);
++  cupsFileClose(systemdlistenconf);
++
++ /*
++  * Upload the systemd configuration file to the server...
++  */
++
++  status = cupsPutFile(http, "/admin/conf/cupsd-systemd-listen.conf", tempfiled);
++
++  if (status == HTTP_STATUS_CREATED)
++  {
+ 
+  /*
+   * Upload the configuration file to the server...
+@@ -2015,6 +2074,7 @@
+   else
+     cupsFreeOptions(cupsd_num_settings, cupsd_settings);
+ 
++  }
+  /*
+   * Remote our temp files and return...
+   */
+@@ -2023,6 +2083,7 @@
+     unlink(cupsdconf);
+ 
+   unlink(tempfile);
++  unlink(tempfiled);
+ 
+   return (status == HTTP_STATUS_CREATED);
+ }
+--- a/scheduler/client.c
++++ b/scheduler/client.c
+@@ -1768,10 +1768,10 @@
+ 	    * Validate the resource name...
+ 	    */
+ 
+-            if (strcmp(con->uri, "/admin/conf/cupsd.conf"))
++            if (strcmp(con->uri, "/admin/conf/cupsd.conf") && strcmp(con->uri, "/admin/conf/cupsd-systemd-listen.conf"))
+ 	    {
+ 	     /*
+-	      * PUT can only be done to the cupsd.conf file...
++	      * PUT can only be done to the cupsd.conf and cupsd-systemd-listen.conf files...
+ 	      */
+ 
+ 	      cupsdLogMessage(CUPSD_LOG_ERROR,
+@@ -3468,6 +3468,7 @@
+ 		*out;			/* Output file */
+   char		buffer[16384];		/* Copy buffer */
+   ssize_t	bytes;			/* Number of bytes */
++  char		*conffile;		/* Configuration file */
+ 
+ 
+  /*
+@@ -3482,17 +3483,30 @@
+   }
+ 
+  /*
++  * Determine which configuration file we're writing
++  */
++
++  if (strcmp(con->uri, "/admin/conf/cupsd.conf") == 0)
++  {
++    conffile = ConfigurationFile;
++  }
++  else if(strcmp(con->uri, "/admin/conf/cupsd-systemd-listen.conf") == 0)
++  {
++    conffile = SystemdConfigurationFile;
++  }
++
++ /*
+   * Open the new config file...
+   */
+ 
+-  if ((out = cupsdCreateConfFile(ConfigurationFile, ConfigFilePerm)) == NULL)
++  if ((out = cupsdCreateConfFile(conffile, ConfigFilePerm)) == NULL)
+   {
+     cupsFileClose(in);
+     return (HTTP_SERVER_ERROR);
+   }
+ 
+   cupsdLogMessage(CUPSD_LOG_INFO, "Installing config file \"%s\"...",
+-                  ConfigurationFile);
++                  conffile);
+ 
+  /*
+   * Copy from the request to the new config file...
+@@ -3503,12 +3517,12 @@
+     {
+       cupsdLogMessage(CUPSD_LOG_ERROR,
+                       "Unable to copy to config file \"%s\": %s",
+-        	      ConfigurationFile, strerror(errno));
++        	      conffile, strerror(errno));
+ 
+       cupsFileClose(in);
+       cupsFileClose(out);
+ 
+-      snprintf(filename, sizeof(filename), "%s.N", ConfigurationFile);
++      snprintf(filename, sizeof(filename), "%s.N", conffile);
+       cupsdUnlinkOrRemoveFile(filename);
+ 
+       return (HTTP_SERVER_ERROR);
+@@ -3520,7 +3534,7 @@
+ 
+   cupsFileClose(in);
+ 
+-  if (cupsdCloseCreatedConfFile(out, ConfigurationFile))
++  if (cupsdCloseCreatedConfFile(out, conffile))
+     return (HTTP_SERVER_ERROR);
+ 
+  /*
+@@ -3534,8 +3548,15 @@
+   * Set the NeedReload flag...
+   */
+ 
+-  NeedReload = RELOAD_CUPSD;
+-  ReloadTime = time(NULL);
++  if(conffile == ConfigurationFile)
++  {
++    NeedReload = RELOAD_CUPSD;
++    ReloadTime = time(NULL);
++  }
++  else if(conffile == SystemdConfigurationFile)
++  {
++    NeedSystemdReload = 1;
++  }
+ 
+  /*
+   * Return that the file was created successfully...
+--- a/scheduler/conf.h
++++ b/scheduler/conf.h
+@@ -100,6 +100,8 @@
+ 					/* cupsd.conf file to use */
+ 			*CupsFilesFile		VALUE(NULL),
+ 					/* cups-files.conf file to use */
++			*SystemdConfigurationFile		VALUE(NULL),
++					/* cupsd-systemd-listen.conf file to use */
+ 			*ServerName		VALUE(NULL),
+ 					/* FQDN for server */
+ 			*ServerAdmin		VALUE(NULL),
+--- a/scheduler/main.c
++++ b/scheduler/main.c
+@@ -352,6 +352,9 @@
+   if (!ConfigurationFile)
+     cupsdSetString(&ConfigurationFile, CUPS_SERVERROOT "/cupsd.conf");
+ 
++  if (!SystemdConfigurationFile)
++    cupsdSetString(&SystemdConfigurationFile, CUPS_SERVERROOT "/cupsd-systemd-listen.conf");
++
+   if (!CupsFilesFile)
+   {
+     char	*filename,		/* Copy of cupsd.conf filename */
+@@ -811,6 +814,15 @@
+ 
+ #ifdef HAVE_SYSTEMD
+        /*
++        * If systemd is the init system, reload the systemd configuration
++        */
++        if (NeedSystemdReload) {
++          cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsd changed the systemd sockets, reload systemd and restart cups.socket");
++          system("test -d /run/systemd/system -a -x /bin/systemctl && /bin/systemctl --system daemon-reload && /bin/systemctl restart cups.socket");
++          NeedSystemdReload = 0;
++        }
++
++       /*
+ 	* If we were started by systemd get the listen sockets file
+ 	* descriptors...
+         */
+--- a/scheduler/cupsd.h
++++ b/scheduler/cupsd.h
+@@ -155,6 +155,8 @@
+ 					/* Time of reload request... */
+ VAR int			NeedReload	VALUE(RELOAD_ALL),
+ 					/* Need to load configuration? */
++			NeedSystemdReload	VALUE(0),
++					/* Need to reload systemd? */
+ 			DoingShutdown	VALUE(0);
+ 					/* Shutting down the scheduler? */
+ VAR void		*DefaultProfile	VALUE(0);
diff --git a/debian/patches/series b/debian/patches/series
index f206f7b..78d1b82 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -54,6 +54,7 @@ cupsd-idleexittimeout-systemd.patch
 # Disabled in 1.6.1-1 as it breaks the tests. It addresses #593338
 # pstops-based-workflow-only-for-printing-ps-on-a-ps-printer.patch
 
+cupsd-write-systemd-Port.patch
 # This one has been submitted upstream but no answer has been given yet,
 # po4a might not be appropriate. It also needs to be high on the patch
 # queue to catch all Debian-specific changes
diff --git a/debian/patches/systemd-optional-socket-activation.patch b/debian/patches/systemd-optional-socket-activation.patch
index b3e5b5a..a584ba5 100644
--- a/debian/patches/systemd-optional-socket-activation.patch
+++ b/debian/patches/systemd-optional-socket-activation.patch
@@ -137,14 +137,12 @@ Last-Update: 2014-03-03
 +WantedBy=printer.target
 --- /dev/null
 +++ b/data/cups.socket.in
-@@ -0,0 +1,11 @@
+@@ -0,0 +1,9 @@
 +[Unit]
 +Description=CUPS Printing Service Sockets
 +
 +[Socket]
 +ListenStream=@CUPS_DEFAULT_DOMAINSOCKET@
-+ListenStream=0.0.0.0:631
-+ListenStream=[::]:631
 +BindIPv6Only=ipv6-only
 +
 +[Install]
