]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/main.c
Merge changes from CUPS 1.5svn-r9641
[thirdparty/cups.git] / scheduler / main.c
index 28ae983f01d6fb699acaf098306b384224bbadcf..d043875cc46a09d1ededadbc78542f06c9921f22 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: main.c 7925 2008-09-10 17:47:26Z mike $"
  *
- *   Scheduler main loop for the Common UNIX Printing System (CUPS).
+ *   Main loop for the CUPS scheduler.
  *
- *   Copyright 2007-2009 by Apple Inc.
+ *   Copyright 2007-2011 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
  *
  * Contents:
  *
- *   main()                    - Main entry for the CUPS scheduler.
- *   cupsdClosePipe()          - Close a pipe as necessary.
- *   cupsdOpenPipe()           - Create a pipe which is closed on exec.
- *   cupsdHoldSignals()        - Hold child and termination signals.
- *   cupsdReleaseSignals()     - Release signals for delivery.
- *   cupsdSetString()          - Set a string value.
- *   cupsdSetStringf()         - Set a formatted string value.
- *   launchd_checkin()         - Check-in with launchd and collect the
- *                               listening fds.
- *   launchd_checkout()        - Check-out with launchd.
- *   parent_handler()          - Catch USR1/CHLD signals...
- *   process_children()        - Process all dead children...
- *   select_timeout()          - Calculate the select timeout value.
- *   sigchld_handler()         - Handle 'child' signals from old processes.
- *   sighup_handler()          - Handle 'hangup' signals to reconfigure the
- *                               scheduler.
- *   sigterm_handler()         - Handle 'terminate' signals that stop the
- *                               scheduler.
- *   usage()                   - Show scheduler usage.
+ *   main()                - Main entry for the CUPS scheduler.
+ *   cupsdAddString()      - Copy and add a string to an array.
+ *   cupsdCheckProcess()   - Tell the main loop to check for dead children.
+ *   cupsdClearString()    - Clear a string.
+ *   cupsdClosePipe()      - Close a pipe as necessary.
+ *   cupsdFreeStrings()    - Free an array of strings.
+ *   cupsdHoldSignals()    - Hold child and termination signals.
+ *   cupsdMakeUUID()       - Make a UUID URI conforming to RFC 4122.
+ *   cupsdOpenPipe()       - Create a pipe which is closed on exec.
+ *   cupsdReleaseSignals() - Release signals for delivery.
+ *   cupsdSetString()      - Set a string value.
+ *   cupsdSetStringf()     - Set a formatted string value.
+ *   cupsd_clean_files()   - Clean out old files.
+ *   launchd_checkin()     - Check-in with launchd and collect the listening
+ *                           fds.
+ *   launchd_checkout()    - Update the launchd KeepAlive file as needed.
+ *   parent_handler()      - Catch USR1/CHLD signals...
+ *   process_children()    - Process all dead children...
+ *   select_timeout()      - Calculate the select timeout value.
+ *   sigchld_handler()     - Handle 'child' signals from old processes.
+ *   sighup_handler()      - Handle 'hangup' signals to reconfigure the
+ *                           scheduler.
+ *   sigterm_handler()     - Handle 'terminate' signals that stop the scheduler.
+ *   usage()               - Show scheduler usage.
  */
 
 /*
 #include <syslog.h>
 #include <grp.h>
 #include <cups/dir.h>
+#include <fnmatch.h>
 
 #ifdef HAVE_LAUNCH_H
 #  include <launch.h>
 #  include <libgen.h>
-#  define CUPS_KEEPALIVE       CUPS_CACHEDIR "/org.cups.cupsd"
+#  define CUPS_KEEPALIVE CUPS_CACHEDIR "/org.cups.cupsd"
                                        /* Name of the launchd KeepAlive file */
 #  ifndef LAUNCH_JOBKEY_KEEPALIVE
 #    define LAUNCH_JOBKEY_KEEPALIVE "KeepAlive"
 #  include <notify.h>
 #endif /* HAVE_NOTIFY_H */
 
-#if defined(__APPLE__) && defined(HAVE_DLFCN_H)
-#  include <dlfcn.h>
-#endif /* __APPLE__ && HAVE_DLFCN_H */
-
 
 /*
  * Local functions...
  */
 
+static void            cupsd_clean_files(const char *path,
+                                         const char *pattern);
 #ifdef HAVE_LAUNCHD
 static void            launchd_checkin(void);
 static void            launchd_checkout(void);
@@ -106,12 +110,6 @@ static int         dead_children = 0;
 static int             stop_scheduler = 0;
                                        /* Should the scheduler stop? */
 
-#if defined(__APPLE__) && defined(HAVE_DLFCN_H)
-static const char *PSQLibPath = "/usr/lib/libPrintServiceQuota.dylib";
-static const char *PSQLibFuncName = "PSQUpdateQuota";
-static void *PSQLibRef;                        /* libPrintServiceQuota.dylib */
-#endif /* HAVE_DLFCN_H */
-
 
 /*
  * 'main()' - Main entry for the CUPS scheduler.
@@ -134,7 +132,7 @@ main(int  argc,                             /* I - Number of command-line args */
                        senddoc_time,   /* Send-Document time */
                        expire_time,    /* Subscription expire time */
                        report_time,    /* Malloc/client/job report time */
-                       event_time;     /* Last time an event notification was done */
+                       event_time;     /* Last event notification time */
   long                 timeout;        /* Timeout for cupsdDoSelect() */
   struct rlimit                limit;          /* Runtime limit */
 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
@@ -198,7 +196,7 @@ main(int  argc,                             /* I - Number of command-line args */
              if (i >= argc)
              {
                _cupsLangPuts(stderr, _("cupsd: Expected config filename "
-                                       "after \"-c\" option\n"));
+                                       "after \"-c\" option."));
                usage(1);
              }
 
@@ -229,14 +227,14 @@ main(int  argc,                           /* I - Number of command-line args */
                 if ((current = malloc(1024)) == NULL)
                {
                  _cupsLangPuts(stderr,
-                               _("cupsd: Unable to get current directory\n"));
+                               _("cupsd: Unable to get current directory."));
                   return (1);
                }
 
                if (!getcwd(current, 1024))
                {
                  _cupsLangPuts(stderr,
-                               _("cupsd: Unable to get current directory\n"));
+                               _("cupsd: Unable to get current directory."));
                   free(current);
                  return (1);
                }
@@ -264,25 +262,28 @@ main(int  argc,                           /* I - Number of command-line args */
              fg      = 1;
 #else
              _cupsLangPuts(stderr, _("cupsd: launchd(8) support not compiled "
-                                     "in, running in normal mode.\n"));
+                                     "in, running in normal mode."));
               fg = 0;
 #endif /* HAVE_LAUNCHD */
              break;
 
           case 'p' : /* Stop immediately for profiling */
-              puts("Warning: -p (startup profiling) is for internal testing use only!");
+              fputs("cupsd: -p (startup profiling) is for internal testing "
+                    "use only!\n", stderr);
              stop_scheduler = 1;
              fg             = 1;
              break;
 
           case 'P' : /* Disable security profiles */
-              puts("Warning: -P (disable security profiles) is for internal testing use only!");
+              fputs("cupsd: -P (disable security profiles) is for internal "
+                    "testing use only!\n", stderr);
              UseProfiles = 0;
              break;
 
 #ifdef __APPLE__
           case 'S' : /* Disable system management functions */
-              puts("Warning: -S (disable system management) for internal testing use only!");
+              fputs("cupsd: -S (disable system management) for internal "
+                    "testing use only!\n", stderr);
              use_sysman = 0;
              break;
 #endif /* __APPLE__ */
@@ -294,13 +295,13 @@ main(int  argc,                           /* I - Number of command-line args */
 
          default : /* Unknown option */
               _cupsLangPrintf(stderr, _("cupsd: Unknown option \"%c\" - "
-                                       "aborting\n"), *opt);
+                                       "aborting."), *opt);
              usage(1);
              break;
        }
     else
     {
-      _cupsLangPrintf(stderr, _("cupsd: Unknown argument \"%s\" - aborting\n"),
+      _cupsLangPrintf(stderr, _("cupsd: Unknown argument \"%s\" - aborting."),
                       argv[i]);
       usage(1);
     }
@@ -505,42 +506,14 @@ main(int  argc,                           /* I - Number of command-line args */
     return (0);
   }
 
-  if (!strncmp(TempDir, RequestRoot, strlen(RequestRoot)))
-  {
-   /*
-    * Clean out the temporary directory...
-    */
-
-    cups_dir_t         *dir;           /* Temporary directory */
-    cups_dentry_t      *dent;          /* Directory entry */
-    char               tempfile[1024]; /* Temporary filename */
-
-
-    if ((dir = cupsDirOpen(TempDir)) != NULL)
-    {
-      cupsdLogMessage(CUPSD_LOG_INFO,
-                      "Cleaning out old temporary files in \"%s\"...", TempDir);
-
-      while ((dent = cupsDirRead(dir)) != NULL)
-      {
-        snprintf(tempfile, sizeof(tempfile), "%s/%s", TempDir, dent->filename);
+ /*
+  * Clean out old temp files and printer cache data.
+  */
 
-       if (unlink(tempfile))
-         cupsdLogMessage(CUPSD_LOG_ERROR,
-                         "Unable to remove temporary file \"%s\" - %s",
-                         tempfile, strerror(errno));
-        else
-         cupsdLogMessage(CUPSD_LOG_DEBUG, "Removed temporary file \"%s\"...",
-                         tempfile);
-      }
+  if (!strncmp(TempDir, RequestRoot, strlen(RequestRoot)))
+    cupsd_clean_files(TempDir, NULL);
 
-      cupsDirClose(dir);
-    }
-    else
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "Unable to open temporary directory \"%s\" - %s",
-                      TempDir, strerror(errno));
-  }
+  cupsd_clean_files(CacheDir, "*.ipp");
 
 #if HAVE_LAUNCHD
   if (Launchd)
@@ -554,21 +527,12 @@ main(int  argc,                           /* I - Number of command-line args */
   }
 #endif /* HAVE_LAUNCHD */
 
-#if defined(__APPLE__) && defined(HAVE_DLFCN_H)
- /*
-  * Load Print Service quota enforcement library (X Server only)
-  */
-
-  PSQLibRef = dlopen(PSQLibPath, RTLD_LAZY);
-
-  if (PSQLibRef)
-    PSQUpdateQuotaProc = dlsym(PSQLibRef, PSQLibFuncName);
-#endif /* __APPLE__ && HAVE_DLFCN_H */
-
  /*
   * Startup the server...
   */
 
+  httpInitialize();
+
   cupsdStartServer();
 
  /*
@@ -746,6 +710,8 @@ main(int  argc,                             /* I - Number of command-line args */
        * Shutdown the server...
        */
 
+        DoingShutdown = 1;
+
        cupsdStopServer();
 
        /*
@@ -763,7 +729,8 @@ main(int  argc,                             /* I - Number of command-line args */
        if (Launchd)
        {
         /*
-         * If we were started by launchd get the listen sockets file descriptors...
+         * If we were started by launchd, get the listen socket file
+         * descriptors...
          */
 
          launchd_checkin();
@@ -775,6 +742,8 @@ main(int  argc,                             /* I - Number of command-line args */
         * Startup the server...
         */
 
+        DoingShutdown = 0;
+
         cupsdStartServer();
 
        /*
@@ -809,8 +778,7 @@ main(int  argc,                             /* I - Number of command-line args */
         !cupsArrayCount(ActiveJobs) &&
        (!Browsing ||
         (!BrowseRemoteProtocols &&
-         (!NumBrowsers || !BrowseLocalProtocols ||
-          cupsArrayCount(Printers) == 0))))
+         (!BrowseLocalProtocols || !cupsArrayCount(Printers)))))
     {
       timeout          = LaunchdTimeout;
       launchd_idle_exit = 1;
@@ -900,7 +868,7 @@ main(int  argc,                             /* I - Number of command-line args */
         cupsArrayCount(PrintingJobs) > 0)
     {
       SleepJobs = 0;
-      cupsdStopAllJobs(CUPSD_JOB_DEFAULT, 10);
+      cupsdStopAllJobs(CUPSD_JOB_DEFAULT, 5);
     }
 #endif /* __APPLE__ */
 
@@ -1151,6 +1119,8 @@ main(int  argc,                           /* I - Number of command-line args */
   * Close all network clients...
   */
 
+  DoingShutdown = 1;
+
   cupsdStopServer();
 
 #ifdef HAVE_LAUNCHD
@@ -1194,19 +1164,6 @@ main(int  argc,                          /* I - Number of command-line args */
     krb5_free_context(KerberosContext);
 #endif /* HAVE_GSSAPI */
 
-#if defined(__APPLE__) && defined(HAVE_DLFCN_H)
- /*
-  * Unload Print Service quota enforcement library (X Server only)
-  */
-
-  PSQUpdateQuotaProc = NULL;
-  if (PSQLibRef)
-  {
-    dlclose(PSQLibRef);
-    PSQLibRef = NULL;
-  }
-#endif /* __APPLE__ && HAVE_DLFCN_H */
-
 #ifdef __sgi
  /*
   * Remove the fake IRIX lpsched lock file, but only if the existing
@@ -1225,6 +1182,24 @@ main(int  argc,                          /* I - Number of command-line args */
 }
 
 
+/*
+ * 'cupsdAddString()' - Copy and add a string to an array.
+ */
+
+int                                    /* O  - 1 on success, 0 on failure */
+cupsdAddString(cups_array_t **a,       /* IO - String array */
+               const char   *s)                /* I  - String to copy and add */
+{
+  if (!*a)
+    *a = cupsArrayNew3((cups_array_func_t)strcmp, NULL,
+                      (cups_ahash_func_t)NULL, 0,
+                      (cups_acopy_func_t)_cupsStrAlloc,
+                      (cups_afree_func_t)_cupsStrFree);
+
+  return (cupsArrayAdd(*a, (char *)s));
+}
+
+
 /*
  * 'cupsdCheckProcess()' - Tell the main loop to check for dead children.
  */
@@ -1240,6 +1215,21 @@ cupsdCheckProcess(void)
 }
 
 
+/*
+ * 'cupsdClearString()' - Clear a string.
+ */
+
+void
+cupsdClearString(char **s)             /* O - String value */
+{
+  if (s && *s)
+  {
+    _cupsStrFree(*s);
+    *s = NULL;
+  }
+}
+
+
 /*
  * 'cupsdClosePipe()' - Close a pipe as necessary.
  */
@@ -1265,6 +1255,97 @@ cupsdClosePipe(int *fds)         /* I - Pipe file descriptors (2) */
 }
 
 
+/*
+ * 'cupsdFreeStrings()' - Free an array of strings.
+ */
+
+void
+cupsdFreeStrings(cups_array_t **a)     /* IO - String array */
+{
+  if (*a)
+  {
+    cupsArrayDelete(*a);
+    *a = NULL;
+  }
+}
+
+
+/*
+ * 'cupsdHoldSignals()' - Hold child and termination signals.
+ */
+
+void
+cupsdHoldSignals(void)
+{
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+  sigset_t             newmask;        /* New POSIX signal mask */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+  holdcount ++;
+  if (holdcount > 1)
+    return;
+
+#ifdef HAVE_SIGSET
+  sighold(SIGTERM);
+  sighold(SIGCHLD);
+#elif defined(HAVE_SIGACTION)
+  sigemptyset(&newmask);
+  sigaddset(&newmask, SIGTERM);
+  sigaddset(&newmask, SIGCHLD);
+  sigprocmask(SIG_BLOCK, &newmask, &holdmask);
+#endif /* HAVE_SIGSET */
+}
+
+
+/*
+ * 'cupsdMakeUUID()' - Make a UUID URI conforming to RFC 4122.
+ *
+ * The buffer needs to be at least 46 bytes in size.
+ */
+
+char *                                 /* I - UUID string */
+cupsdMakeUUID(const char *name,                /* I - Object name */
+              int        number,       /* I - Object number */
+             char       *buffer,       /* I - String buffer */
+             size_t     bufsize)       /* I - Size of buffer */
+{
+  char                 data[1024];     /* Source string for MD5 */
+  _cups_md5_state_t    md5state;       /* MD5 state */
+  unsigned char                md5sum[16];     /* MD5 digest/sum */
+
+
+ /*
+  * Build a version 3 UUID conforming to RFC 4122.
+  *
+  * Start with the MD5 sum of the ServerName, RemotePort, object name and
+  * number, and some random data on the end.
+  */
+
+  snprintf(data, sizeof(data), "%s:%d:%s:%d:%04x:%04x", ServerName,
+           RemotePort, name ? name : ServerName, number,
+          CUPS_RAND() & 0xffff, CUPS_RAND() & 0xffff);
+
+  _cupsMD5Init(&md5state);
+  _cupsMD5Append(&md5state, (unsigned char *)data, strlen(data));
+  _cupsMD5Finish(&md5state, md5sum);
+
+ /*
+  * Generate the UUID from the MD5...
+  */
+
+  snprintf(buffer, bufsize,
+           "urn:uuid:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
+          "%02x%02x%02x%02x%02x%02x",
+          md5sum[0], md5sum[1], md5sum[2], md5sum[3], md5sum[4], md5sum[5],
+          (md5sum[6] & 15) | 0x30, md5sum[7], (md5sum[8] & 0x3f) | 0x40,
+          md5sum[9], md5sum[10], md5sum[11], md5sum[12], md5sum[13],
+          md5sum[14], md5sum[15]);
+
+  return (buffer);
+}
+
+
 /*
  * 'cupsdOpenPipe()' - Create a pipe which is closed on exec.
  */
@@ -1318,49 +1399,6 @@ cupsdOpenPipe(int *fds)                  /* O - Pipe file descriptors (2) */
 }
 
 
-/*
- * 'cupsdClearString()' - Clear a string.
- */
-
-void
-cupsdClearString(char **s)             /* O - String value */
-{
-  if (s && *s)
-  {
-    _cupsStrFree(*s);
-    *s = NULL;
-  }
-}
-
-
-/*
- * 'cupsdHoldSignals()' - Hold child and termination signals.
- */
-
-void
-cupsdHoldSignals(void)
-{
-#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
-  sigset_t             newmask;        /* New POSIX signal mask */
-#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
-
-
-  holdcount ++;
-  if (holdcount > 1)
-    return;
-
-#ifdef HAVE_SIGSET
-  sighold(SIGTERM);
-  sighold(SIGCHLD);
-#elif defined(HAVE_SIGACTION)
-  sigemptyset(&newmask);
-  sigaddset(&newmask, SIGTERM);
-  sigaddset(&newmask, SIGCHLD);
-  sigprocmask(SIG_BLOCK, &newmask, &holdmask);
-#endif /* HAVE_SIGSET */
-}
-
-
 /*
  * 'cupsdReleaseSignals()' - Release signals for delivery.
  */
@@ -1437,6 +1475,60 @@ cupsdSetStringf(char       **s,          /* O - New string */
 }
 
 
+/*
+ * 'cupsd_clean_files()' - Clean out old files.
+ */
+static void
+cupsd_clean_files(const char *path,    /* I - Directory to clean */
+                  const char *pattern) /* I - Filename pattern or NULL */
+{
+  cups_dir_t   *dir;                   /* Directory */
+  cups_dentry_t        *dent;                  /* Directory entry */
+  char         filename[1024];         /* Filename */
+  int          status;                 /* Status from unlink/rmdir */
+
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG,
+                  "cupsd_clean_files(path=\"%s\", pattern=\"%s\")", path,
+                 pattern ? pattern : "(null)");
+
+  if ((dir = cupsDirOpen(path)) == NULL)
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open directory \"%s\" - %s",
+                   path, strerror(errno));
+    return;
+  }
+
+  cupsdLogMessage(CUPSD_LOG_INFO, "Cleaning out old files in \"%s\"...", path);
+
+  while ((dent = cupsDirRead(dir)) != NULL)
+  {
+    if (pattern && fnmatch(pattern, dent->filename, 0))
+      continue;
+
+    snprintf(filename, sizeof(filename), "%s/%s", path, dent->filename);
+
+    if (S_ISDIR(dent->fileinfo.st_mode))
+    {
+      cupsd_clean_files(filename, pattern);
+
+      status = rmdir(filename);
+    }
+    else
+      status = unlink(filename);
+
+    if (status)
+      cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove \"%s\" - %s", filename,
+                     strerror(errno));
+    else
+      cupsdLogMessage(CUPSD_LOG_DEBUG, "Removed \"%s\"...", filename);
+  }
+
+  cupsDirClose(dir);
+}
+
+
 #ifdef HAVE_LAUNCHD
 /*
  * 'launchd_checkin()' - Check-in with launchd and collect the listening fds.
@@ -1446,8 +1538,10 @@ static void
 launchd_checkin(void)
 {
   size_t               i,              /* Looping var */
-                       count;          /* Numebr of listeners */
+                       count;          /* Number of listeners */
+#  ifdef HAVE_SSL
   int                  portnum;        /* Port number */
+#  endif /* HAVE_SSL */
   launch_data_t                ld_msg,         /* Launch data message */
                        ld_resp,        /* Launch data response */
                        ld_array,       /* Launch data array */
@@ -1566,8 +1660,8 @@ launchd_checkin(void)
          if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
          {
            cupsdLogMessage(CUPSD_LOG_ERROR,
-                           "launchd_checkin: Unable to allocate listener - %s.",
-                           strerror(errno));
+                           "launchd_checkin: Unable to allocate listener - "
+                           "%s.", strerror(errno));
            exit(EXIT_FAILURE);
          }
 
@@ -1617,13 +1711,14 @@ launchd_checkout(void)
   * shared printers to advertise...
   */
 
-  if ((cupsArrayCount(ActiveJobs) || NumPolled ||
-       (Browsing &&
-       (BrowseRemoteProtocols ||
-        (BrowseLocalProtocols && NumBrowsers && cupsArrayCount(Printers))))))
+  if (cupsArrayCount(ActiveJobs) || NumPolled ||
+      (Browsing &&
+       (BrowseRemoteProtocols || 
+        (BrowseLocalProtocols && cupsArrayCount(Printers)))))
   {
     cupsdLogMessage(CUPSD_LOG_DEBUG,
-                    "Creating launchd keepalive file \"" CUPS_KEEPALIVE "\"...");
+                    "Creating launchd keepalive file \"" CUPS_KEEPALIVE
+                    "\"...");
 
     if ((fd = open(CUPS_KEEPALIVE, O_RDONLY | O_CREAT | O_EXCL, S_IRUSR)) >= 0)
       close(fd);
@@ -1631,7 +1726,8 @@ launchd_checkout(void)
   else
   {
     cupsdLogMessage(CUPSD_LOG_DEBUG,
-                    "Removing launchd keepalive file \"" CUPS_KEEPALIVE "\"...");
+                    "Removing launchd keepalive file \"" CUPS_KEEPALIVE
+                    "\"...");
 
     unlink(CUPS_KEEPALIVE);
   }
@@ -1724,7 +1820,7 @@ process_children(void)
          job->backend = -pid;
 
        if (status && status != SIGTERM && status != SIGKILL &&
-           job->status >= 0)
+           status != SIGPIPE && job->status >= 0)
        {
         /*
          * An error occurred; save the exit status so we know to stop
@@ -1753,7 +1849,6 @@ process_children(void)
            {
              strlcpy(job->printer->state_message, message,
                       sizeof(job->printer->state_message));
-             cupsdAddPrinterHistory(job->printer);
            }
 
            if (!job->attrs)
@@ -1767,7 +1862,7 @@ process_children(void)
                job->printer_message = ippAddString(job->attrs, IPP_TAG_JOB,
                                                    IPP_TAG_TEXT,
                                                    "job-printer-state-message",
-                                                   NULL, "");
+                                                   NULL, NULL);
            }
 
            if (job->printer_message)
@@ -1781,11 +1876,13 @@ process_children(void)
        * filters are done, and if so move to the next file.
        */
 
-       if (job->current_file < job->num_files)
+       if (job->current_file < job->num_files && job->printer)
        {
          for (i = 0; job->filters[i] < 0; i ++);
 
-         if (!job->filters[i])
+         if (!job->filters[i] &&
+             (!job->printer->pc || !job->printer->pc->single_file ||
+              job->backend <= 0))
          {
           /*
            * Process the next file...
@@ -1794,7 +1891,7 @@ process_children(void)
            cupsdContinueJob(job);
          }
        }
-       else if (job->state_value == IPP_JOB_CANCELED)
+       else if (job->state_value >= IPP_JOB_CANCELED)
        {
         /*
          * Remove the job from the active list if there are no processes still
@@ -1820,6 +1917,12 @@ process_children(void)
                       "PID %d (%s) was terminated normally with signal %d.",
                       pid, name, status);
     }
+    else if (status == SIGPIPE)
+    {
+      cupsdLogMessage(CUPSD_LOG_DEBUG,
+                      "PID %d (%s) did not catch or ignore signal %d.",
+                      pid, name, status);
+    }
     else if (status)
     {
       if (WIFEXITED(status))
@@ -2137,14 +2240,21 @@ sigterm_handler(int sig)                /* I - Signal number */
 static void
 usage(int status)                      /* O - Exit status */
 {
-  _cupsLangPuts(status ? stderr : stdout,
-                _("Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
-                 "\n"
-                 "-c config-file      Load alternate configuration file\n"
-                 "-f                  Run in the foreground\n"
-                 "-F                  Run in the foreground but detach\n"
-                 "-h                  Show this usage message\n"
-                 "-l                  Run cupsd from launchd(8)\n"));
+  FILE *fp = status ? stderr : stdout; /* Output file */
+
+
+  _cupsLangPuts(fp, _("Usage: cupsd [options]"));
+  _cupsLangPuts(fp, _("Options:"));
+  _cupsLangPuts(fp, _("  -c config-file          Load alternate configuration "
+                      "file."));
+  _cupsLangPuts(fp, _("  -f                      Run in the foreground."));
+  _cupsLangPuts(fp, _("  -F                      Run in the foreground but "
+                      "detach from console."));
+  _cupsLangPuts(fp, _("  -h                      Show this usage message."));
+  _cupsLangPuts(fp, _("  -l                      Run cupsd from launchd(8)."));
+  _cupsLangPuts(fp, _("  -t                      Test the configuration "
+                      "file."));
+
   exit(status);
 }