示例#1
0
static void
process_children(void)
{
  int		status;			/* Exit status of child */
  int		pid,			/* Process ID of child */
		job_id;			/* Job ID of child */
  cupsd_job_t	*job;			/* Current job */
  int		i;			/* Looping var */
  char		name[1024];		/* Process name */
  const char	*type;			/* Type of program */


  cupsdLogMessage(CUPSD_LOG_DEBUG2, "process_children()");

 /*
  * Reset the dead_children flag...
  */

  dead_children = 0;

 /*
  * Collect the exit status of some children...
  */

#ifdef HAVE_WAITPID
  while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
#elif defined(HAVE_WAIT3)
  while ((pid = wait3(&status, WNOHANG, NULL)) > 0)
#else
  if ((pid = wait(&status)) > 0)
#endif /* HAVE_WAITPID */
  {
   /*
    * Collect the name of the process that finished...
    */

    cupsdFinishProcess(pid, name, sizeof(name), &job_id);

   /*
    * Delete certificates for CGI processes...
    */

    if (pid)
      cupsdDeleteCert(pid);

   /*
    * Handle completed job filters...
    */

    if (job_id > 0)
      job = cupsdFindJob(job_id);
    else
      job  = NULL;

    if (job)
    {
      for (i = 0; job->filters[i]; i ++)
	if (job->filters[i] == pid)
	  break;

      if (job->filters[i] || job->backend == pid)
      {
       /*
	* OK, this process has gone away; what's left?
	*/

	if (job->filters[i])
	{
	  job->filters[i] = -pid;
	  type            = "Filter";
	}
	else
	{
	  job->backend = -pid;
	  type         = "Backend";
	}

	if (status && status != SIGTERM && status != SIGKILL &&
	    status != SIGPIPE)
	{
	 /*
	  * An error occurred; save the exit status so we know to stop
	  * the printer or cancel the job when all of the filters finish...
	  *
	  * A negative status indicates that the backend failed and the
	  * printer needs to be stopped.
	  *
	  * In order to preserve the most serious status, we always log
	  * when a process dies due to a signal (e.g. SIGABRT, SIGSEGV,
	  * and SIGBUS) and prefer to log the backend exit status over a
	  * filter's.
	  */

	  int old_status = abs(job->status);

          if (WIFSIGNALED(status) ||	/* This process crashed, or */
              !job->status ||		/* No process had a status, or */
              (!job->filters[i] && WIFEXITED(old_status)))
          {				/* Backend and filter didn't crash */
	    if (job->filters[i])
	      job->status = status;	/* Filter failed */
	    else
	      job->status = -status;	/* Backend failed */
          }

	  if (job->state_value == IPP_JOB_PROCESSING &&
	      job->status_level > CUPSD_LOG_ERROR &&
	      (job->filters[i] || !WIFEXITED(status)))
	  {
	    char	message[1024];	/* New printer-state-message */


	    job->status_level = CUPSD_LOG_ERROR;

	    snprintf(message, sizeof(message), "%s failed", type);

            if (job->printer)
	    {
	      strlcpy(job->printer->state_message, message,
		       sizeof(job->printer->state_message));
	    }

	    if (!job->attrs)
	      cupsdLoadJob(job);

	    if (!job->printer_message && job->attrs)
	    {
	      if ((job->printer_message =
	               ippFindAttribute(job->attrs, "job-printer-state-message",
					IPP_TAG_TEXT)) == NULL)
		job->printer_message = ippAddString(job->attrs, IPP_TAG_JOB,
		                                    IPP_TAG_TEXT,
						    "job-printer-state-message",
						    NULL, NULL);
	    }

	    if (job->printer_message)
	      cupsdSetString(&(job->printer_message->values[0].string.text),
			     message);
	  }
	}

       /*
	* If this is not the last file in a job, see if all of the
	* filters are done, and if so move to the next file.
	*/

	if (job->current_file < job->num_files && job->printer)
	{
	  for (i = 0; job->filters[i] < 0; i ++);

	  if (!job->filters[i] &&
	      (!job->printer->pc || !job->printer->pc->single_file ||
	       job->backend <= 0))
	  {
	   /*
	    * Process the next file...
	    */

	    cupsdContinueJob(job);
	  }
	}
	else if (job->state_value >= IPP_JOB_CANCELED)
	{
	 /*
	  * Remove the job from the active list if there are no processes still
	  * running for it...
	  */

	  for (i = 0; job->filters[i] < 0; i++);

	  if (!job->filters[i] && job->backend <= 0)
	    cupsArrayRemove(ActiveJobs, job);
	}
      }
    }

   /*
    * Show the exit status as needed, ignoring SIGTERM and SIGKILL errors
    * since they come when we kill/end a process...
    */

    if (status == SIGTERM || status == SIGKILL)
    {
      cupsdLogJob(job, CUPSD_LOG_DEBUG,
		  "PID %d (%s) was terminated normally with signal %d.", pid,
		  name, status);
    }
    else if (status == SIGPIPE)
    {
      cupsdLogJob(job, CUPSD_LOG_DEBUG,
		  "PID %d (%s) did not catch or ignore signal %d.", pid, name,
		  status);
    }
    else if (status)
    {
      if (WIFEXITED(status))
      {
        int code = WEXITSTATUS(status);	/* Exit code */

        if (code > 100)
	  cupsdLogJob(job, CUPSD_LOG_DEBUG,
		      "PID %d (%s) stopped with status %d (%s)", pid, name,
		      code, strerror(code - 100));
	else
	  cupsdLogJob(job, CUPSD_LOG_DEBUG,
		      "PID %d (%s) stopped with status %d.", pid, name, code);
      }
      else
	cupsdLogJob(job, CUPSD_LOG_DEBUG, "PID %d (%s) crashed on signal %d.",
		    pid, name, WTERMSIG(status));

      if (LogLevel < CUPSD_LOG_DEBUG)
        cupsdLogJob(job, CUPSD_LOG_INFO,
		    "Hint: Try setting the LogLevel to \"debug\" to find out "
		    "more.");
    }
    else
      cupsdLogJob(job, CUPSD_LOG_DEBUG, "PID %d (%s) exited with no errors.",
		  pid, name);
  }

 /*
  * If wait*() is interrupted by a signal, tell main() to call us again...
  */

  if (pid < 0 && errno == EINTR)
    dead_children = 1;
}
示例#2
0
文件: quotas.c 项目: ystk/debian-cups
cupsd_quota_t *				/* O - Quota data */
cupsdUpdateQuota(
    cupsd_printer_t *p,			/* I - Printer */
    const char      *username,		/* I - User */
    int             pages,		/* I - Number of pages */
    int             k)			/* I - Number of kilobytes */
{
  cupsd_quota_t		*q;		/* Quota data */
  cupsd_job_t		*job;		/* Current job */
  time_t		curtime;	/* Current time */
  ipp_attribute_t	*attr;		/* Job attribute */


  if (!p || !username)
    return (NULL);

  if (!p->k_limit && !p->page_limit)
    return (NULL);

  if ((q = cupsdFindQuota(p, username)) == NULL)
    return (NULL);

  cupsdLogMessage(CUPSD_LOG_DEBUG,
                  "cupsdUpdateQuota: p=%s username=%s pages=%d k=%d",
                  p->name, username, pages, k);

#if defined(__APPLE__) && defined(HAVE_DLFCN_H)
 /*
  * Use Apple PrintService quota enforcement if installed (X Server only)
  */

  if (AppleQuotas && PSQUpdateQuotaProc)
  { 
    q->page_count = (*PSQUpdateQuotaProc)(p->name, p->info, username, pages, 0);

    return (q);
  }
#endif /* __APPLE__ && HAVE_DLFCN_H */

  curtime = time(NULL);

  if (curtime < q->next_update)
  {
    q->page_count += pages;
    q->k_count    += k;

    return (q);
  }

  if (p->quota_period)
    curtime -= p->quota_period;
  else
    curtime = 0;

  q->next_update = 0;
  q->page_count  = 0;
  q->k_count     = 0;

  for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
       job;
       job = (cupsd_job_t *)cupsArrayNext(Jobs))
  {
   /*
    * We only care about the current printer/class and user...
    */

    if (strcasecmp(job->dest, p->name) != 0 ||
        strcasecmp(job->username, q->username) != 0)
      continue;

   /*
    * Make sure attributes are loaded; we always call cupsdLoadJob() to ensure
    * the access_time member is updated so the job isn't unloaded right away...
    */

    if (!cupsdLoadJob(job))
      continue;

    if ((attr = ippFindAttribute(job->attrs, "time-at-completion",
                                 IPP_TAG_INTEGER)) == NULL)
      if ((attr = ippFindAttribute(job->attrs, "time-at-processing",
                                   IPP_TAG_INTEGER)) == NULL)
        attr = ippFindAttribute(job->attrs, "time-at-creation",
                                IPP_TAG_INTEGER);

    if (attr->values[0].integer < curtime)
    {
     /*
      * This job is too old to count towards the quota, ignore it...
      */

      if (JobAutoPurge && !job->printer && job->state_value > IPP_JOB_STOPPED)
        cupsdDeleteJob(job, CUPSD_JOB_PURGE);

      continue;
    }

    if (q->next_update == 0)
      q->next_update = attr->values[0].integer + p->quota_period;

    if ((attr = ippFindAttribute(job->attrs, "job-media-sheets-completed",
                                 IPP_TAG_INTEGER)) != NULL)
      q->page_count += attr->values[0].integer;

    if ((attr = ippFindAttribute(job->attrs, "job-k-octets",
                                 IPP_TAG_INTEGER)) != NULL)
      q->k_count += attr->values[0].integer;
  }

  return (q);
}