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; }
void cupsdLoadAllSubscriptions(void) { int i; /* Looping var */ cups_file_t *fp; /* subscriptions.conf file */ int linenum; /* Current line number */ char line[1024], /* Line from file */ *value, /* Pointer to value */ *valueptr; /* Pointer into value */ cupsd_subscription_t *sub; /* Current subscription */ int hex; /* Non-zero if reading hex data */ int delete_sub; /* Delete subscription? */ /* * Open the subscriptions.conf file... */ snprintf(line, sizeof(line), "%s/subscriptions.conf", ServerRoot); if ((fp = cupsdOpenConfFile(line)) == NULL) return; /* * Read all of the lines from the file... */ linenum = 0; sub = NULL; delete_sub = 0; while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) { if (!_cups_strcasecmp(line, "NextSubscriptionId") && value) { /* * NextSubscriptionId NNN */ i = atoi(value); if (i >= NextSubscriptionId && i > 0) NextSubscriptionId = i; } else if (!_cups_strcasecmp(line, "<Subscription")) { /* * <Subscription #> */ if (!sub && value && isdigit(value[0] & 255)) { sub = cupsdAddSubscription(CUPSD_EVENT_NONE, NULL, NULL, NULL, atoi(value)); } else { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of subscriptions.conf.", linenum); break; } } else if (!_cups_strcasecmp(line, "</Subscription>")) { if (!sub) { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of subscriptions.conf.", linenum); break; } if (delete_sub) cupsdDeleteSubscription(sub, 0); sub = NULL; delete_sub = 0; } else if (!sub) { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of subscriptions.conf.", linenum); } else if (!_cups_strcasecmp(line, "Events")) { /* * Events name * Events name name name ... */ if (!value) { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of subscriptions.conf.", linenum); break; } while (*value) { /* * Separate event names... */ for (valueptr = value; !isspace(*valueptr) && *valueptr; valueptr ++); while (isspace(*valueptr & 255)) *valueptr++ = '\0'; /* * See if the name exists... */ if ((sub->mask |= cupsdEventValue(value)) == CUPSD_EVENT_NONE) { cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown event name \'%s\' on line %d of subscriptions.conf.", value, linenum); break; } value = valueptr; } } else if (!_cups_strcasecmp(line, "Owner")) { /* * Owner */ if (value) cupsdSetString(&sub->owner, value); else { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of subscriptions.conf.", linenum); break; } } else if (!_cups_strcasecmp(line, "Recipient")) { /* * Recipient uri */ if (value) cupsdSetString(&sub->recipient, value); else { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of subscriptions.conf.", linenum); break; } } else if (!_cups_strcasecmp(line, "JobId")) { /* * JobId # */ if (value && isdigit(*value & 255)) { if ((sub->job = cupsdFindJob(atoi(value))) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, "Job %s not found on line %d of subscriptions.conf.", value, linenum); delete_sub = 1; } } else { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of subscriptions.conf.", linenum); break; } } else if (!_cups_strcasecmp(line, "PrinterName")) { /* * PrinterName name */ if (value) { if ((sub->dest = cupsdFindDest(value)) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, "Printer \'%s\' not found on line %d of subscriptions.conf.", value, linenum); delete_sub = 1; } } else { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of subscriptions.conf.", linenum); break; } } else if (!_cups_strcasecmp(line, "UserData")) { /* * UserData encoded-string */ if (value) { for (i = 0, valueptr = value, hex = 0; i < 63 && *valueptr; i ++) { if (*valueptr == '<' && !hex) { hex = 1; valueptr ++; } if (hex) { if (isxdigit(valueptr[0]) && isxdigit(valueptr[1])) { if (isdigit(valueptr[0])) sub->user_data[i] = (unsigned char)((valueptr[0] - '0') << 4); else sub->user_data[i] = (unsigned char)((tolower(valueptr[0]) - 'a' + 10) << 4); if (isdigit(valueptr[1])) sub->user_data[i] |= valueptr[1] - '0'; else sub->user_data[i] |= tolower(valueptr[1]) - 'a' + 10; valueptr += 2; if (*valueptr == '>') { hex = 0; valueptr ++; } } else break; } else sub->user_data[i] = (unsigned char)*valueptr++; } if (*valueptr) { cupsdLogMessage(CUPSD_LOG_ERROR, "Bad UserData \'%s\' on line %d of subscriptions.conf.", value, linenum); } else sub->user_data_len = i; } else { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of subscriptions.conf.", linenum); break; } } else if (!_cups_strcasecmp(line, "LeaseDuration")) { /* * LeaseDuration # */ if (value && isdigit(*value & 255)) { sub->lease = atoi(value); sub->expire = sub->lease ? time(NULL) + sub->lease : 0; } else { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of subscriptions.conf.", linenum); break; } } else if (!_cups_strcasecmp(line, "Interval")) { /* * Interval # */ if (value && isdigit(*value & 255)) sub->interval = atoi(value); else { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of subscriptions.conf.", linenum); break; } } else if (!_cups_strcasecmp(line, "ExpirationTime")) { /* * ExpirationTime # */ if (value && isdigit(*value & 255)) sub->expire = atoi(value); else { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of subscriptions.conf.", linenum); break; } } else if (!_cups_strcasecmp(line, "NextEventId")) { /* * NextEventId # */ if (value && isdigit(*value & 255)) sub->next_event_id = sub->first_event_id = atoi(value); else { cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of subscriptions.conf.", linenum); break; } } else { /* * Something else we don't understand... */ cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown configuration directive %s on line %d of subscriptions.conf.", line, linenum); } } cupsFileClose(fp); }