+ if ((size = _ppdCacheGetSize(pc, keyword)) != NULL)
+ {
+ /*
+ * Add a media-col value...
+ */
+
+ media_size = ippNew();
+ ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER,
+ "x-dimension", size->width);
+ ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER,
+ "y-dimension", size->length);
+
+ media_col = ippNew();
+ ippAddCollection(media_col, IPP_TAG_ZERO, "media-size", media_size);
+
+ media_source = _ppdCacheGetSource(pc, cupsGetOption("InputSlot",
+ num_options,
+ options));
+ media_type = _ppdCacheGetType(pc, cupsGetOption("MediaType",
+ num_options,
+ options));
+
+ for (i = 0; i < media_col_sup->num_values; i ++)
+ {
+ if (!strcmp(media_col_sup->values[i].string.text,
+ "media-left-margin"))
+ ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
+ "media-left-margin", size->left);
+ else if (!strcmp(media_col_sup->values[i].string.text,
+ "media-bottom-margin"))
+ ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
+ "media-bottom-margin", size->bottom);
+ else if (!strcmp(media_col_sup->values[i].string.text,
+ "media-right-margin"))
+ ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
+ "media-right-margin", size->right);
+ else if (!strcmp(media_col_sup->values[i].string.text,
+ "media-top-margin"))
+ ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
+ "media-top-margin", size->top);
+ else if (!strcmp(media_col_sup->values[i].string.text,
+ "media-source") && media_source)
+ ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD,
+ "media-source", NULL, media_source);
+ else if (!strcmp(media_col_sup->values[i].string.text,
+ "media-type") && media_type)
+ ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD,
+ "media-type", NULL, media_type);
+ }
+
+ ippAddCollection(request, IPP_TAG_JOB, "media-col", media_col);
+ }
+
+ if ((keyword = cupsGetOption("output-bin", num_options,
+ options)) == NULL)
+ {
+ if ((choice = ppdFindMarkedChoice(ppd, "OutputBin")) != NULL)
+ keyword = _ppdCacheGetBin(pc, choice->choice);
+ }
+
+ if (keyword)
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "output-bin",
+ NULL, keyword);
+
+ color_attr_name = print_color_mode ? "print-color-mode" : "output-mode";
+
+ if ((keyword = cupsGetOption("print-color-mode", num_options,
+ options)) != NULL)
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, color_attr_name,
+ NULL, keyword);
+ else if ((choice = ppdFindMarkedChoice(ppd, "ColorModel")) != NULL)
+ {
+ if (!_cups_strcasecmp(choice->choice, "Gray"))
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ color_attr_name, NULL, "monochrome");
+ else
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ color_attr_name, NULL, "color");
+ }
+
+ if ((keyword = cupsGetOption("print-quality", num_options,
+ options)) != NULL)
+ ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality",
+ atoi(keyword));
+ else if ((choice = ppdFindMarkedChoice(ppd, "cupsPrintQuality")) != NULL)
+ {
+ if (!_cups_strcasecmp(choice->choice, "draft"))
+ ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality",
+ IPP_QUALITY_DRAFT);
+ else if (!_cups_strcasecmp(choice->choice, "normal"))
+ ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality",
+ IPP_QUALITY_NORMAL);
+ else if (!_cups_strcasecmp(choice->choice, "high"))
+ ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality",
+ IPP_QUALITY_HIGH);
+ }
+
+ if ((keyword = cupsGetOption("sides", num_options, options)) != NULL)
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides",
+ NULL, keyword);
+ else if (pc->sides_option &&
+ (choice = ppdFindMarkedChoice(ppd, pc->sides_option)) != NULL)
+ {
+ if (!_cups_strcasecmp(choice->choice, pc->sides_1sided))
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides",
+ NULL, "one-sided");
+ else if (!_cups_strcasecmp(choice->choice, pc->sides_2sided_long))
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides",
+ NULL, "two-sided-long-edge");
+ if (!_cups_strcasecmp(choice->choice, pc->sides_2sided_short))
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides",
+ NULL, "two-sided-short-edge");
+ }
+
+ if ((keyword = cupsGetOption("multiple-document-handling",
+ num_options, options)) != NULL)
+ {
+ if (strstr(keyword, "uncollated"))
+ keyword = "false";
+ else
+ keyword = "true";
+ }
+ else if ((keyword = cupsGetOption("collate", num_options,
+ options)) == NULL)
+ keyword = "true";
+
+ if (format)
+ {
+ if (!_cups_strcasecmp(format, "image/gif") ||
+ !_cups_strcasecmp(format, "image/jp2") ||
+ !_cups_strcasecmp(format, "image/jpeg") ||
+ !_cups_strcasecmp(format, "image/png") ||
+ !_cups_strcasecmp(format, "image/tiff") ||
+ !_cups_strncasecmp(format, "image/x-", 8))
+ {
+ /*
+ * Collation makes no sense for single page image formats...
+ */
+
+ keyword = "false";
+ }
+ else if (!_cups_strncasecmp(format, "image/", 6) ||
+ !_cups_strcasecmp(format, "application/vnd.cups-raster"))
+ {
+ /*
+ * Multi-page image formats will have copies applied by the upstream
+ * filters...
+ */
+
+ copies = 1;
+ }
+ }
+
+ if (doc_handling_sup)
+ {
+ if (!_cups_strcasecmp(keyword, "true"))
+ collate_str = "separate-documents-collated-copies";
+ else
+ collate_str = "separate-documents-uncollated-copies";
+
+ for (i = 0; i < doc_handling_sup->num_values; i ++)
+ if (!strcmp(doc_handling_sup->values[i].string.text, collate_str))
+ {
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "multiple-document-handling", NULL, collate_str);
+ break;
+ }
+
+ if (i >= doc_handling_sup->num_values)
+ copies = 1;
+ }
+
+ /*
+ * Map finishing options...
+ */
+
+ num_finishings = _ppdCacheGetFinishingValues(pc, num_options, options,
+ (int)(sizeof(finishings) /
+ sizeof(finishings[0])),
+ finishings);
+ if (num_finishings > 0)
+ ippAddIntegers(request, IPP_TAG_JOB, IPP_TAG_ENUM, "finishings",
+ num_finishings, finishings);
+
+ /*
+ * Map FaxOut options...
+ */
+
+ if ((keyword = cupsGetOption("phone", num_options, options)) != NULL)
+ {
+ ipp_t *destination; /* destination collection */
+ char tel_uri[1024]; /* tel: URI */
+
+ destination = ippNew();
+
+ httpAssembleURI(HTTP_URI_CODING_ALL, tel_uri, sizeof(tel_uri), "tel",
+ NULL, NULL, 0, keyword);
+ ippAddString(destination, IPP_TAG_JOB, IPP_TAG_URI, "destination-uri",
+ NULL, tel_uri);
+
+ if ((keyword = cupsGetOption("faxPrefix", num_options,
+ options)) != NULL && *keyword)
+ ippAddString(destination, IPP_TAG_JOB, IPP_TAG_TEXT,
+ "pre-dial-string", NULL, keyword);
+
+ ippAddCollection(request, IPP_TAG_JOB, "destination-uris", destination);
+ ippDelete(destination);
+ }
+ }
+ else
+ {
+ /*
+ * When talking to another CUPS server, send all options...
+ */
+
+ fputs("DEBUG: Adding all operation/job attributes.\n", stderr);
+ cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION);
+ cupsEncodeOptions2(request, num_options, options, IPP_TAG_JOB);
+ }
+
+ if (copies > 1 && (!pc || copies <= pc->max_copies))
+ ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies", copies);
+ }
+
+ fprintf(stderr, "DEBUG: IPP/%d.%d %s #%d\n", version / 10, version % 10,
+ ippOpString(ippGetOperation(request)), ippGetRequestId(request));
+ for (group = IPP_TAG_ZERO, attr = ippFirstAttribute(request);
+ attr;
+ attr = ippNextAttribute(request))
+ {
+ const char *name = ippGetName(attr);
+
+ if (!name)
+ {
+ group = IPP_TAG_ZERO;
+ continue;
+ }
+
+ if (group != ippGetGroupTag(attr))
+ {
+ group = ippGetGroupTag(attr);
+ fprintf(stderr, "DEBUG: ---- %s ----\n", ippTagString(group));
+ }
+
+ ippAttributeString(attr, buffer, sizeof(buffer));
+ fprintf(stderr, "DEBUG: %s %s%s %s\n", name,
+ ippGetCount(attr) > 1 ? "1setOf " : "",
+ ippTagString(ippGetValueTag(attr)), buffer);
+ }
+
+ fprintf(stderr, "DEBUG: ---- %s ----\n", ippTagString(IPP_TAG_END));
+
+ return (request);
+}
+
+
+/*
+ * 'password_cb()' - Disable the password prompt for cupsDoFileRequest().
+ */
+
+static const char * /* O - Password */
+password_cb(const char *prompt, /* I - Prompt (not used) */
+ http_t *http, /* I - Connection */
+ const char *method, /* I - Request method (not used) */
+ const char *resource, /* I - Resource path (not used) */
+ void *user_data) /* I - User data (not used) */
+{
+ char def_username[HTTP_MAX_VALUE]; /* Default username */
+
+
+ fprintf(stderr, "DEBUG: password_cb(prompt=\"%s\"), password=%p, "
+ "password_tries=%d\n", prompt, password, password_tries);
+
+ (void)prompt;
+ (void)method;
+ (void)resource;
+ (void)user_data;
+
+ /*
+ * Remember that we need to authenticate...
+ */
+
+ auth_info_required = "username,password";
+
+ if (httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "username",
+ def_username))
+ {
+ char quoted[HTTP_MAX_VALUE * 2 + 4];
+ /* Quoted string */
+
+ fprintf(stderr, "ATTR: auth-info-default=%s,\n",
+ quote_string(def_username, quoted, sizeof(quoted)));
+ }
+
+ if (password && *password && password_tries < 3)
+ {
+ password_tries ++;
+
+ return (password);
+ }
+ else
+ {
+ /*
+ * Give up after 3 tries or if we don't have a password to begin with...
+ */
+
+ return (NULL);
+ }
+}
+
+
+/*
+ * 'quote_string()' - Quote a string value.
+ */
+
+static const char * /* O - Quoted string */
+quote_string(const char *s, /* I - String */
+ char *q, /* I - Quoted string buffer */
+ size_t qsize) /* I - Size of quoted string buffer */
+{
+ char *qptr, /* Pointer into string buffer */
+ *qend; /* End of string buffer */
+
+
+ qptr = q;
+ qend = q + qsize - 5;
+
+ if (qend < q)
+ {
+ *q = '\0';
+ return (q);
+ }
+
+ *qptr++ = '\'';
+ *qptr++ = '\"';
+
+ while (*s && qptr < qend)
+ {
+ if (*s == '\\' || *s == '\"' || *s == '\'')
+ {
+ if (q < (qend - 3))
+ {
+ *qptr++ = '\\';
+ *qptr++ = '\\';
+ *qptr++ = '\\';
+ }
+ else
+ break;
+ }
+
+ *qptr++ = *s++;
+ }
+
+ *qptr++ = '\"';
+ *qptr++ = '\'';
+ *qptr = '\0';
+
+ return (q);
+}
+
+
+/*
+ * 'report_attr()' - Report an IPP attribute value.
+ */
+
+static void
+report_attr(ipp_attribute_t *attr) /* I - Attribute */
+{
+ int i; /* Looping var */
+ char value[1024], /* Value string */
+ *valptr; /* Pointer into value string */
+ const char *cached; /* Cached attribute */
+
+
+ /*
+ * Convert the attribute values into quoted strings...
+ */
+
+ for (i = 0, valptr = value;
+ i < attr->num_values && valptr < (value + sizeof(value) - 10);
+ i ++)
+ {
+ if (i > 0)
+ *valptr++ = ',';
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ snprintf(valptr, sizeof(value) - (valptr - value), "%d",
+ attr->values[i].integer);
+ valptr += strlen(valptr);
+ break;
+
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ quote_string(attr->values[i].string.text, valptr,
+ value + sizeof(value) - valptr);
+ valptr += strlen(valptr);
+ break;
+
+ default :
+ /*
+ * Unsupported value type...
+ */
+
+ return;
+ }
+ }
+
+ *valptr = '\0';
+
+ _cupsMutexLock(&report_mutex);
+
+ if ((cached = cupsGetOption(attr->name, num_attr_cache,
+ attr_cache)) == NULL || strcmp(cached, value))
+ {
+ /*
+ * Tell the scheduler about the new values...
+ */
+
+ num_attr_cache = cupsAddOption(attr->name, value, num_attr_cache,
+ &attr_cache);
+ fprintf(stderr, "ATTR: %s=%s\n", attr->name, value);
+ }
+
+ _cupsMutexUnlock(&report_mutex);
+}
+
+
+/*
+ * 'report_printer_state()' - Report the printer state.
+ */
+
+static void
+report_printer_state(ipp_t *ipp) /* I - IPP response */
+{
+ ipp_attribute_t *pa, /* printer-alert */
+ *pam, /* printer-alert-message */
+ *psm, /* printer-state-message */
+ *reasons, /* printer-state-reasons */
+ *marker; /* marker-* attributes */
+ char value[1024], /* State/message string */
+ *valptr; /* Pointer into string */
+ static int ipp_supplies = -1;
+ /* Report supply levels? */
+
+
+ /*
+ * Report alerts and messages...
+ */
+
+ if ((pa = ippFindAttribute(ipp, "printer-alert", IPP_TAG_TEXT)) != NULL)
+ report_attr(pa);
+
+ if ((pam = ippFindAttribute(ipp, "printer-alert-message",
+ IPP_TAG_TEXT)) != NULL)
+ report_attr(pam);
+
+ if ((psm = ippFindAttribute(ipp, "printer-state-message",
+ IPP_TAG_TEXT)) != NULL)
+ {
+ char *ptr; /* Pointer into message */
+
+
+ strlcpy(value, "INFO: ", sizeof(value));
+ for (ptr = psm->values[0].string.text, valptr = value + 6;
+ *ptr && valptr < (value + sizeof(value) - 6);
+ ptr ++)
+ {
+ if (*ptr < ' ' && *ptr > 0 && *ptr != '\t')
+ {
+ /*
+ * Substitute "<XX>" for the control character; sprintf is safe because
+ * we always leave 6 chars free at the end...
+ */
+
+ sprintf(valptr, "<%02X>", *ptr);
+ valptr += 4;
+ }
+ else
+ *valptr++ = *ptr;
+ }
+
+ *valptr++ = '\n';
+ *valptr = '\0';
+
+ fputs(value, stderr);
+ }
+
+ /*
+ * Now report printer-state-reasons, filtering out some of the reasons we never
+ * want to set...
+ */
+
+ if ((reasons = ippFindAttribute(ipp, "printer-state-reasons",
+ IPP_TAG_KEYWORD)) == NULL)
+ return;
+
+ update_reasons(reasons, NULL);
+
+ /*
+ * Relay the current marker-* attribute values...
+ */
+
+ if (ipp_supplies < 0)
+ {
+ ppd_file_t *ppd; /* PPD file */
+ ppd_attr_t *ppdattr; /* Attribute in PPD file */
+
+ if ((ppd = ppdOpenFile(getenv("PPD"))) != NULL &&
+ (ppdattr = ppdFindAttr(ppd, "cupsIPPSupplies", NULL)) != NULL &&
+ ppdattr->value && _cups_strcasecmp(ppdattr->value, "true"))
+ ipp_supplies = 0;
+ else
+ ipp_supplies = 1;
+
+ ppdClose(ppd);
+ }
+
+ if (ipp_supplies > 0)
+ {
+ if ((marker = ippFindAttribute(ipp, "marker-colors", IPP_TAG_NAME)) != NULL)
+ report_attr(marker);
+ if ((marker = ippFindAttribute(ipp, "marker-high-levels",
+ IPP_TAG_INTEGER)) != NULL)
+ report_attr(marker);
+ if ((marker = ippFindAttribute(ipp, "marker-levels",
+ IPP_TAG_INTEGER)) != NULL)
+ report_attr(marker);
+ if ((marker = ippFindAttribute(ipp, "marker-low-levels",
+ IPP_TAG_INTEGER)) != NULL)
+ report_attr(marker);
+ if ((marker = ippFindAttribute(ipp, "marker-message",
+ IPP_TAG_TEXT)) != NULL)
+ report_attr(marker);
+ if ((marker = ippFindAttribute(ipp, "marker-names", IPP_TAG_NAME)) != NULL)
+ report_attr(marker);
+ if ((marker = ippFindAttribute(ipp, "marker-types",
+ IPP_TAG_KEYWORD)) != NULL)
+ report_attr(marker);
+ }
+}
+
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_XPC)
+/*
+ * 'run_as_user()' - Run the IPP backend as the printing user.
+ *
+ * This function uses an XPC-based user agent to run the backend as the printing
+ * user. We need to do this in order to have access to the user's Kerberos
+ * credentials.
+ */
+
+static int /* O - Exit status */
+run_as_user(char *argv[], /* I - Command-line arguments */
+ uid_t uid, /* I - User ID */
+ const char *device_uri, /* I - Device URI */
+ int fd) /* I - File to print */
+{
+ const char *auth_negotiate;/* AUTH_NEGOTIATE env var */
+ xpc_connection_t conn; /* Connection to XPC service */
+ xpc_object_t request; /* Request message dictionary */
+ __block xpc_object_t response; /* Response message dictionary */
+ dispatch_semaphore_t sem; /* Semaphore for waiting for response */
+ int status = CUPS_BACKEND_FAILED;
+ /* Status of request */
+
+
+ fprintf(stderr, "DEBUG: Running IPP backend as UID %d.\n", (int)uid);
+
+ /*
+ * Connect to the user agent for the specified UID...
+ */
+
+ conn = xpc_connection_create_mach_service(kPMPrintUIToolAgent,
+ dispatch_get_global_queue(0, 0), 0);
+ if (!conn)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to start backend process."));
+ fputs("DEBUG: Unable to create connection to agent.\n", stderr);
+ goto cleanup;
+ }
+
+ xpc_connection_set_event_handler(conn,
+ ^(xpc_object_t event)
+ {
+ xpc_type_t messageType = xpc_get_type(event);
+
+ if (messageType == XPC_TYPE_ERROR)
+ {
+ if (event == XPC_ERROR_CONNECTION_INTERRUPTED)
+ fprintf(stderr, "DEBUG: Interrupted connection to service %s.\n",
+ xpc_connection_get_name(conn));
+ else if (event == XPC_ERROR_CONNECTION_INVALID)
+ fprintf(stderr, "DEBUG: Connection invalid for service %s.\n",
+ xpc_connection_get_name(conn));
+ else
+ fprintf(stderr, "DEBUG: Unxpected error for service %s: %s\n",
+ xpc_connection_get_name(conn),
+ xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
+ }
+ });
+ xpc_connection_set_target_uid(conn, uid);
+ xpc_connection_resume(conn);
+
+ /*
+ * Try starting the backend...
+ */
+
+ request = xpc_dictionary_create(NULL, NULL, 0);
+ xpc_dictionary_set_int64(request, "command", kPMStartJob);
+ xpc_dictionary_set_string(request, "device-uri", device_uri);
+ xpc_dictionary_set_string(request, "job-id", argv[1]);
+ xpc_dictionary_set_string(request, "user", argv[2]);
+ xpc_dictionary_set_string(request, "title", argv[3]);
+ xpc_dictionary_set_string(request, "copies", argv[4]);
+ xpc_dictionary_set_string(request, "options", argv[5]);
+ xpc_dictionary_set_string(request, "auth-info-required",
+ getenv("AUTH_INFO_REQUIRED"));
+ if ((auth_negotiate = getenv("AUTH_NEGOTIATE")) != NULL)
+ xpc_dictionary_set_string(request, "auth-negotiate", auth_negotiate);
+ xpc_dictionary_set_fd(request, "stdin", fd);
+ xpc_dictionary_set_fd(request, "stderr", 2);
+ xpc_dictionary_set_fd(request, "side-channel", CUPS_SC_FD);
+
+ sem = dispatch_semaphore_create(0);
+ response = NULL;
+
+ xpc_connection_send_message_with_reply(conn, request,
+ dispatch_get_global_queue(0,0),
+ ^(xpc_object_t reply)
+ {
+ /* Save the response and wake up */
+ if (xpc_get_type(reply)
+ == XPC_TYPE_DICTIONARY)
+ response = xpc_retain(reply);
+
+ dispatch_semaphore_signal(sem);
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ xpc_release(request);
+ dispatch_release(sem);
+
+ if (response)
+ {
+ child_pid = xpc_dictionary_get_int64(response, "child-pid");
+
+ xpc_release(response);
+
+ if (child_pid)
+ fprintf(stderr, "DEBUG: Child PID=%d.\n", child_pid);
+ else
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to start backend process."));
+ fputs("DEBUG: No child PID.\n", stderr);
+ goto cleanup;
+ }
+ }
+ else
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to start backend process."));
+ fputs("DEBUG: No reply from agent.\n", stderr);
+ goto cleanup;
+ }
+
+ /*
+ * Then wait for the backend to finish...
+ */
+
+ request = xpc_dictionary_create(NULL, NULL, 0);
+ xpc_dictionary_set_int64(request, "command", kPMWaitForJob);
+ xpc_dictionary_set_fd(request, "stderr", 2);
+
+ sem = dispatch_semaphore_create(0);
+ response = NULL;
+
+ xpc_connection_send_message_with_reply(conn, request,
+ dispatch_get_global_queue(0,0),
+ ^(xpc_object_t reply)
+ {
+ /* Save the response and wake up */
+ if (xpc_get_type(reply)
+ == XPC_TYPE_DICTIONARY)
+ response = xpc_retain(reply);
+
+ dispatch_semaphore_signal(sem);
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ xpc_release(request);
+ dispatch_release(sem);
+
+ if (response)
+ {
+ status = xpc_dictionary_get_int64(response, "status");
+
+ if (status == SIGTERM || status == SIGKILL || status == SIGPIPE)
+ {
+ fprintf(stderr, "DEBUG: Child terminated on signal %d.\n", status);
+ status = CUPS_BACKEND_FAILED;
+ }
+ else if (WIFSIGNALED(status))
+ {
+ fprintf(stderr, "DEBUG: Child crashed on signal %d.\n", status);
+ status = CUPS_BACKEND_STOP;
+ }
+ else if (WIFEXITED(status))
+ {
+ status = WEXITSTATUS(status);
+ fprintf(stderr, "DEBUG: Child exited with status %d.\n", status);
+ }
+
+ xpc_release(response);
+ }
+ else
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to get backend exit status."));
+
+ cleanup:
+
+ if (conn)
+ {
+ xpc_connection_suspend(conn);
+ xpc_connection_cancel(conn);
+ xpc_release(conn);
+ }
+
+ return (status);
+}
+#endif /* HAVE_GSSAPI && HAVE_XPC */
+
+
+/*
+ * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
+ */