]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/job.c
Merge changes from CUPS 1.5svn-r8849.
[thirdparty/cups.git] / scheduler / job.c
index c0aa5b0d610c2aece718d9434608ff69f0d1d83a..8624b4fe60de8f2396226c54ef739bac14c423b7 100644 (file)
@@ -45,6 +45,8 @@
  *   compare_active_jobs()      - Compare the job IDs and priorities of two
  *                                jobs.
  *   compare_jobs()             - Compare the job IDs of two jobs.
+ *   dump_job_history()         - Dump any debug messages for a job.
+ *   free_job_history()         - Free any log history.
  *   finalize_job()             - Cleanup after job filter processes and support
  *                                data.
  *   get_options()              - Get a string containing the job options.
@@ -165,7 +167,9 @@ static mime_filter_t        gziptoany_filter =
 
 static int     compare_active_jobs(void *first, void *second, void *data);
 static int     compare_jobs(void *first, void *second, void *data);
+static void    dump_job_history(cupsd_job_t *job);
 static void    finalize_job(cupsd_job_t *job);
+static void    free_job_history(cupsd_job_t *job);
 static char    *get_options(cupsd_job_t *job, int banner_page, char *copies,
                             size_t copies_size, char *title,
                             size_t title_size);
@@ -458,7 +462,7 @@ cupsdContinueJob(cupsd_job_t *job)  /* I - Job */
   ipp_attribute_t      *attr;          /* Current attribute */
   const char           *ptr,           /* Pointer into value */
                        *abort_message; /* Abort message */
-  ipp_jstate_t         abort_state = IPP_JOB_ABORTED;
+  ipp_jstate_t         abort_state = IPP_JOB_STOPPED;
                                        /* New job state on abort */
   struct stat          backinfo;       /* Backend file information */
   int                  backroot;       /* Run backend as root? */
@@ -545,6 +549,8 @@ cupsdContinueJob(cupsd_job_t *job)  /* I - Job */
                  job->current_file);
 
       abort_message = "Aborting job because it cannot be printed.";
+      abort_state   = IPP_JOB_ABORTED;
+
       goto abort_job;
     }
 
@@ -649,7 +655,6 @@ cupsdContinueJob(cupsd_job_t *job)  /* I - Job */
 
       cupsArrayDelete(filters);
 
-      abort_state = IPP_JOB_STOPPED;
       abort_message = "Stopping job because the scheduler ran out of memory.";
 
       goto abort_job;
@@ -681,7 +686,6 @@ cupsdContinueJob(cupsd_job_t *job)  /* I - Job */
       cupsdLogJob(job, CUPSD_LOG_DEBUG,
                  "Unable to add port monitor - %s", strerror(errno));
 
-      abort_state   = IPP_JOB_STOPPED;
       abort_message = "Stopping job because the scheduler ran out of memory.";
 
       goto abort_job;
@@ -699,6 +703,8 @@ cupsdContinueJob(cupsd_job_t *job)  /* I - Job */
                cupsArrayCount(filters), MAX_FILTERS);
 
     abort_message = "Aborting job because it needs too many filters to print.";
+    abort_state   = IPP_JOB_ABORTED;
+
     goto abort_job;
   }
 
@@ -739,7 +745,6 @@ cupsdContinueJob(cupsd_job_t *job)  /* I - Job */
   if ((options = get_options(job, banner_page, copies, sizeof(copies), title,
                              sizeof(title))) == NULL)
   {
-    abort_state   = IPP_JOB_STOPPED;
     abort_message = "Stopping job because the scheduler ran out of memory.";
 
     goto abort_job;
@@ -773,7 +778,6 @@ cupsdContinueJob(cupsd_job_t *job)  /* I - Job */
     cupsdLogMessage(CUPSD_LOG_DEBUG, "Unable to allocate argument array - %s",
                     strerror(errno));
 
-    abort_state   = IPP_JOB_STOPPED;
     abort_message = "Stopping job because the scheduler ran out of memory.";
 
     goto abort_job;
@@ -1048,7 +1052,7 @@ cupsdContinueJob(cupsd_job_t *job)        /* I - Job */
       cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to start filter \"%s\" - %s.",
                  filter->filter, strerror(errno));
 
-      abort_message = "Stopped job because the scheduler could not execute a "
+      abort_message = "Stopping job because the scheduler could not execute a "
                      "filter.";
 
       goto abort_job;
@@ -1206,6 +1210,9 @@ cupsdContinueJob(cupsd_job_t *job)        /* I - Job */
   cupsdSetPrinterState(job->printer, IPP_PRINTER_IDLE, 0);
   update_job_attrs(job, 0);
 
+  if (job->history)
+    free_job_history(job);
+
   cupsArrayRemove(PrintingJobs, job);
 
  /*
@@ -1269,6 +1276,9 @@ cupsdDeleteJob(cupsd_job_t       *job,    /* I - Job */
     job->num_files = 0;
   }
 
+  if (job->history)
+    free_job_history(job);
+
   unload_job(job);
 
   cupsArrayRemove(Jobs, job);
@@ -2287,17 +2297,32 @@ cupsdSetJobState(
     case IPP_JOB_ABORTED :
     case IPP_JOB_CANCELED :
     case IPP_JOB_COMPLETED :
-       /*
-        * Expire job subscriptions since the job is now "completed"...
-       */
+        if (newstate == IPP_JOB_CANCELED)
+       {
+        /*
+         * Remove the job from the active list if there are no processes still
+         * running for it...
+         */
 
-        cupsdExpireSubscriptions(NULL, job);
+         for (i = 0; job->filters[i] < 0; i++);
+
+         if (!job->filters[i] && job->backend <= 0)
+           cupsArrayRemove(ActiveJobs, job);
+       }
+       else
+       {
+        /*
+         * Otherwise just remove the job from the active list immediately...
+         */
+
+         cupsArrayRemove(ActiveJobs, job);
+       }
 
        /*
-       * Remove the job from the active list...
+        * Expire job subscriptions since the job is now "completed"...
        */
 
-       cupsArrayRemove(ActiveJobs, job);
+        cupsdExpireSubscriptions(NULL, job);
 
 #ifdef __APPLE__
        /*
@@ -2477,6 +2502,140 @@ compare_jobs(void *first,               /* I - First job */
 }
 
 
+/*
+ * 'dump_job_history()' - Dump any debug messages for a job.
+ */
+
+static void
+dump_job_history(cupsd_job_t *job)     /* I - Job */
+{
+  int                  i,              /* Looping var */
+                       oldsize;        /* Current MaxLogSize */
+  struct tm            *date;          /* Date/time value */
+  cupsd_joblog_t       *message;       /* Current message */
+  char                 temp[2048],     /* Log message */
+                       *ptr,           /* Pointer into log message */
+                       start[256],     /* Start time */
+                       end[256];       /* End time */
+  cupsd_printer_t      *printer;       /* Printer for job */
+
+
+ /*
+  * See if we have anything to dump...
+  */
+
+  if (!job->history)
+    return;
+
+ /*
+  * Disable log rotation temporarily...
+  */
+
+  oldsize    = MaxLogSize;
+  MaxLogSize = 0;
+
+ /*
+  * Copy the debug messages to the log...
+  */
+
+  message = (cupsd_joblog_t *)cupsArrayFirst(job->history);
+  date = localtime(&(message->time));
+  strftime(start, sizeof(start), "%X", date);
+
+  message = (cupsd_joblog_t *)cupsArrayLast(job->history);
+  date = localtime(&(message->time));
+  strftime(end, sizeof(end), "%X", date);
+
+  snprintf(temp, sizeof(temp),
+           "[Job %d] The following messages were recorded from %s to %s",
+           job->id, start, end);
+  cupsdWriteErrorLog(CUPSD_LOG_DEBUG, temp);
+
+  for (message = (cupsd_joblog_t *)cupsArrayFirst(job->history);
+       message;
+       message = (cupsd_joblog_t *)cupsArrayNext(job->history))
+    cupsdWriteErrorLog(CUPSD_LOG_DEBUG, message->message);
+
+  snprintf(temp, sizeof(temp), "[Job %d] End of messages", job->id);
+  cupsdWriteErrorLog(CUPSD_LOG_DEBUG, temp);
+
+ /*
+  * Log the printer state values...
+  */
+
+  if ((printer = job->printer) == NULL)
+    printer = cupsdFindDest(job->dest);
+
+  if (printer)
+  {
+    snprintf(temp, sizeof(temp), "[Job %d] printer-state=%d(%s)", job->id,
+             printer->state,
+            printer->state == IPP_PRINTER_IDLE ? "idle" :
+                printer->state == IPP_PRINTER_PROCESSING ? "processing" :
+                "stopped");
+    cupsdWriteErrorLog(CUPSD_LOG_DEBUG, temp);
+
+    snprintf(temp, sizeof(temp), "[Job %d] printer-state-message=\"%s\"",
+             job->id, printer->state_message);
+    cupsdWriteErrorLog(CUPSD_LOG_DEBUG, temp);
+
+    snprintf(temp, sizeof(temp), "[Job %d] printer-state-reasons=", job->id);
+    ptr = temp + strlen(temp);
+    if (printer->num_reasons == 0)
+      strlcpy(ptr, "none", sizeof(temp) - (ptr - temp));
+    else
+    {
+      for (i = 0;
+           i < printer->num_reasons && ptr < (temp + sizeof(temp) - 2);
+           i ++)
+      {
+        if (i)
+         *ptr++ = ',';
+
+       strlcpy(ptr, printer->reasons[i], sizeof(temp) - (ptr - temp));
+       ptr += strlen(ptr);
+      }
+    }
+    cupsdWriteErrorLog(CUPSD_LOG_DEBUG, temp);
+  }
+
+ /*
+  * Restore log file rotation...
+  */
+
+  MaxLogSize = oldsize;
+
+ /*
+  * Free all messages...
+  */
+
+  free_job_history(job);
+}
+
+
+/*
+ * 'free_job_history()' - Free any log history.
+ */
+
+static void
+free_job_history(cupsd_job_t *job)     /* I - Job */
+{
+  char *message;                       /* Current message */
+
+
+  if (!job->history)
+    return;
+
+  for (message = (char *)cupsArrayFirst(job->history);
+       message;
+       message = (char *)cupsArrayNext(job->history))
+    free(message);
+
+  cupsArrayDelete(job->history);
+  job->history = NULL;
+}
+
+
 /*
  * 'finalize_job()' - Cleanup after job filter processes and support data.
  */
@@ -2493,8 +2652,8 @@ finalize_job(cupsd_job_t *job)            /* I - Job */
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "finalize_job(job=%p(%d))", job, job->id);
 
  /*
-  * Clear the "connecting-to-device" reason, which is only valid when a
-  * printer is processing...
+  * Clear the "connecting-to-device" reason, which is only valid when a printer
+  * is processing...
   */
 
   cupsdSetPrinterReasons(job->printer, "-connecting-to-device");
@@ -2549,8 +2708,8 @@ finalize_job(cupsd_job_t *job)            /* I - Job */
     default :
     case IPP_JOB_PROCESSING :
     case IPP_JOB_COMPLETED :
-       job_state     = IPP_JOB_COMPLETED;
-       message       = "Job completed.";
+       job_state = IPP_JOB_COMPLETED;
+       message   = "Job completed.";
         break;
 
     case IPP_JOB_STOPPED :
@@ -2684,14 +2843,12 @@ finalize_job(cupsd_job_t *job)          /* I - Job */
            message   = "Job aborted due to backend errors; please consult "
                        "the error_log file for details.";
          }
-         else
+         else if (job->state_value == IPP_JOB_PROCESSING)
           {
+            job_state     = IPP_JOB_PENDING;
            printer_state = IPP_PRINTER_STOPPED;
            message       = "Printer stopped due to backend errors; please "
                            "consult the error_log file for details.";
-
-            if (job_state == IPP_JOB_COMPLETED)
-             job_state = IPP_JOB_PENDING;
          }
           break;
 
@@ -2774,6 +2931,14 @@ finalize_job(cupsd_job_t *job)           /* I - Job */
                        printer_state == IPP_PRINTER_STOPPED);
   update_job_attrs(job, 0);
 
+  if (job->history)
+  {
+    if (job->status)
+      dump_job_history(job);
+    else
+      free_job_history(job);
+  }
+
   cupsArrayRemove(PrintingJobs, job);
 
  /*
@@ -2881,7 +3046,8 @@ get_options(cupsd_job_t *job,             /* I - Job */
          attr->value_tag == IPP_TAG_BEGIN_COLLECTION) /* Not yet supported */
        continue;
 
-      if (!strncmp(attr->name, "time-", 5))
+      if (!strncmp(attr->name, "time-", 5) ||
+          !strcmp(attr->name, "job-hold-until"))
        continue;
 
       if (!strncmp(attr->name, "job-", 4) &&
@@ -3228,11 +3394,8 @@ load_job_cache(const char *filename)     /* I - job.cache filename */
     {
       cupsArrayAdd(Jobs, job);
 
-      if (job->state_value <= IPP_JOB_STOPPED)
-      {
-        cupsArrayAdd(ActiveJobs, job);
-       cupsdLoadJob(job);
-      }
+      if (job->state_value <= IPP_JOB_STOPPED && cupsdLoadJob(job))
+       cupsArrayAdd(ActiveJobs, job);
 
       job = NULL;
     }
@@ -3484,18 +3647,19 @@ load_request_root(void)
       * Load the job...
       */
 
-      cupsdLoadJob(job);
-
-     /*
-      * Insert the job into the array, sorting by job priority and ID...
-      */
+      if (cupsdLoadJob(job))
+      {
+       /*
+        * Insert the job into the array, sorting by job priority and ID...
+        */
 
-      cupsArrayAdd(Jobs, job);
+       cupsArrayAdd(Jobs, job);
 
-      if (job->state_value <= IPP_JOB_STOPPED)
-        cupsArrayAdd(ActiveJobs, job);
-      else
-        unload_job(job);
+       if (job->state_value <= IPP_JOB_STOPPED)
+         cupsArrayAdd(ActiveJobs, job);
+       else
+         unload_job(job);
+      }
     }
 
   cupsDirClose(dir);
@@ -3698,6 +3862,11 @@ start_job(cupsd_job_t     *job,          /* I - Job ID */
   fcntl(job->side_pipes[1], F_SETFL,
        fcntl(job->side_pipes[1], F_GETFL) | O_NONBLOCK);
 
+  fcntl(job->side_pipes[0], F_SETFD,
+       fcntl(job->side_pipes[0], F_GETFD) | FD_CLOEXEC);
+  fcntl(job->side_pipes[1], F_SETFD,
+       fcntl(job->side_pipes[1], F_GETFD) | FD_CLOEXEC);
+
  /*
   * Now start the first file in the job...
   */
@@ -3769,7 +3938,8 @@ update_job(cupsd_job_t *job)              /* I - Job to check */
 {
   int          i;                      /* Looping var */
   int          copies;                 /* Number of copies printed */
-  char         message[1024],          /* Message text */
+  char         message[CUPSD_SB_BUFFER_SIZE],
+                                       /* Message text */
                *ptr;                   /* Pointer update... */
   int          loglevel,               /* Log level for message */
                event = 0;              /* Events? */
@@ -3866,9 +4036,8 @@ update_job(cupsd_job_t *job)              /* I - Job to check */
         cupsdStopPrinter(job->printer, 1);
        return;
       }
-      else
+      else if (cupsdSetPrinterReasons(job->printer, message))
       {
-       cupsdSetPrinterReasons(job->printer, message);
        cupsdAddPrinterHistory(job->printer);
        event |= CUPSD_EVENT_PRINTER_STATE;
       }
@@ -4009,43 +4178,32 @@ update_job(cupsd_job_t *job)            /* I - Job to check */
 
       cupsFreeOptions(num_keywords, keywords);
     }
-#ifdef __APPLE__
-    else if (!strncmp(message, "recoverable:", 12))
+    else
     {
-      ptr = message + 12;
-      while (isspace(*ptr & 255))
-        ptr ++;
+     /*
+      * Strip legacy message prefix...
+      */
 
-      if (*ptr)
+      if (!strncmp(message, "recoverable:", 12))
       {
-       cupsdSetPrinterReasons(job->printer,
-                              "+com.apple.print.recoverable-warning");
-       cupsdSetString(&(job->printer->recoverable), ptr);
-       cupsdAddPrinterHistory(job->printer);
-       event |= CUPSD_EVENT_PRINTER_STATE;
+        ptr = message + 12;
+       while (isspace(*ptr & 255))
+          ptr ++;
       }
-    }
-    else if (!strncmp(message, "recovered:", 10))
-    {
-      cupsdSetPrinterReasons(job->printer,
-                             "-com.apple.print.recoverable-warning");
-
-      ptr = message + 10;
-      while (isspace(*ptr & 255))
-        ptr ++;
+      else if (!strncmp(message, "recovered:", 10))
+      {
+        ptr = message + 10;
+       while (isspace(*ptr & 255))
+          ptr ++;
+      }
+      else
+        ptr = message;
 
-      cupsdSetString(&(job->printer->recoverable), ptr);
-      cupsdAddPrinterHistory(job->printer);
-      event |= CUPSD_EVENT_PRINTER_STATE;
-    }
-#endif /* __APPLE__ */
-    else
-    {
-      cupsdLogJob(job, loglevel, "%s", message);
+      cupsdLogJob(job, loglevel, "%s", ptr);
 
       if (loglevel < CUPSD_LOG_DEBUG)
       {
-       strlcpy(job->printer->state_message, message,
+       strlcpy(job->printer->state_message, ptr,
                sizeof(job->printer->state_message));
        cupsdAddPrinterHistory(job->printer);