@@ -1170,52 +1167,6 @@ printer-state-reasons, and printer-type attributes as options.
Use the cupsFreeDests function to free the destination list and
the cupsGetDest function to find a particular destination.
-
Comma-separated URI schemes to exclude or CUPS_EXCLUDE_NONE
+
callback
+
Callback function
+
user_data
+
User data pointer
+
+
Return Value
+
Request status - IPP_OK on success.
+
Discussion
+
This function sends a CUPS-Get-Devices request and streams the discovered
+devices to the specified callback function. The "timeout" parameter controls
+how long the request lasts, while the "exclude_schemes" parameter provides
+a comma-delimited list of backends to omit from the request.
+
+
@@ -976,6 +1059,54 @@ to add the standard groups.
cupsSendDocument() or cupsSendRequest(). For requests that return
additional data, use httpRead() after getting a successful response.
+
+
The client OPTIONALLY supplies a device class keyword to select
which devices are returned.
+
"exclude-schemes" (1setOf name) :CUPS 1.4
+
+
The client OPTIONALLY supplies a set of scheme names that the
+ requestor does not want to discover. If the client omits this attribute,
+ the server responds with devices of all schemes.
+
"limit" (integer (1:MAX)):
The client OPTIONALLY supplies this attribute limiting the number of
@@ -1583,6 +1589,11 @@ CUPS-Get-Devices request:
the client omits this attribute, the server responds as if this
attribute had been supplied with a value of 'all'.
+
"timeout" (integer (1:MAX)) :CUPS 1.4
+
+
The client OPTIONALLY supplies this attribute limiting the number of
+ devices that are returned.
+
CUPS-Get-Devices Response
diff --git a/filter/error.c b/filter/error.c
index f4e8c3983..44c2eabfb 100644
--- a/filter/error.c
+++ b/filter/error.c
@@ -3,7 +3,7 @@
*
* Raster error handling for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007 by Apple Inc.
+ * Copyright 2007-2008 by Apple Inc.
* Copyright 2007 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
@@ -196,8 +196,7 @@ get_error_buffer(void)
* Initialize the global data exactly once...
*/
- DEBUG_printf(("get_error_buffer(): raster_key_once=%d\n",
- raster_key_once));
+ DEBUG_puts("get_error_buffer()");
pthread_once(&raster_key_once, raster_init);
@@ -237,8 +236,8 @@ raster_init(void)
{
pthread_key_create(&raster_key, raster_destructor);
- DEBUG_printf(("raster_init(): raster_key=%x(%u)\n", raster_key,
- raster_key));
+ DEBUG_printf(("raster_init(): raster_key=%x(%u)\n", (unsigned)raster_key,
+ (unsigned)raster_key));
}
diff --git a/filter/interpret.c b/filter/interpret.c
index 0cc782f9c..945c8f40a 100644
--- a/filter/interpret.c
+++ b/filter/interpret.c
@@ -468,9 +468,8 @@ _cupsRasterExecPS(
while ((obj = scan_ps(st, &codeptr)) != NULL)
{
#ifdef DEBUG
- printf(" (%d): ", st->num_objs);
+ DEBUG_printf(("_cupsRasterExecPS: Stack (%d objects)\n", st->num_objs));
DEBUG_object(obj);
- putchar('\n');
#endif /* DEBUG */
switch (obj->type)
@@ -486,7 +485,7 @@ _cupsRasterExecPS(
_cupsRasterAddError("cleartomark: Stack underflow!\n");
#ifdef DEBUG
- fputs(" dup: ", stdout);
+ DEBUG_puts(" dup: ");
DEBUG_stack(st);
#endif /* DEBUG */
break;
@@ -498,7 +497,7 @@ _cupsRasterExecPS(
copy_stack(st, (int)obj->value.number);
#ifdef DEBUG
- fputs(" copy: ", stdout);
+ DEBUG_puts("_cupsRasterExecPS: copy");
DEBUG_stack(st);
#endif /* DEBUG */
}
@@ -509,7 +508,7 @@ _cupsRasterExecPS(
copy_stack(st, 1);
#ifdef DEBUG
- fputs(" dup: ", stdout);
+ DEBUG_puts("_cupsRasterExecPS: dup");
DEBUG_stack(st);
#endif /* DEBUG */
break;
@@ -521,7 +520,7 @@ _cupsRasterExecPS(
index_stack(st, (int)obj->value.number);
#ifdef DEBUG
- fputs(" index: ", stdout);
+ DEBUG_puts("_cupsRasterExecPS: index");
DEBUG_stack(st);
#endif /* DEBUG */
}
@@ -532,7 +531,7 @@ _cupsRasterExecPS(
pop_stack(st);
#ifdef DEBUG
- fputs(" pop: ", stdout);
+ DEBUG_puts("_cupsRasterExecPS: pop");
DEBUG_stack(st);
#endif /* DEBUG */
break;
@@ -551,7 +550,7 @@ _cupsRasterExecPS(
roll_stack(st, (int)obj->value.number, c);
#ifdef DEBUG
- fputs(" roll:", stdout);
+ DEBUG_puts("_cupsRasterExecPS: roll");
DEBUG_stack(st);
#endif /* DEBUG */
}
@@ -563,7 +562,7 @@ _cupsRasterExecPS(
setpagedevice(st, h, preferred_bits);
#ifdef DEBUG
- fputs(" setpagedevice: ", stdout);
+ DEBUG_puts("_cupsRasterExecPS: setpagedevice");
DEBUG_stack(st);
#endif /* DEBUG */
break;
@@ -576,7 +575,8 @@ _cupsRasterExecPS(
case CUPS_PS_OTHER :
_cupsRasterAddError("Unknown operator \"%s\"!\n", obj->value.other);
- DEBUG_printf((" Unknown operator \"%s\"!\n", obj->value.other));
+ DEBUG_printf(("_cupsRasterExecPS: Unknown operator \"%s\"!\n",
+ obj->value.other));
break;
}
@@ -595,7 +595,7 @@ _cupsRasterExecPS(
error_stack(st, "Stack not empty:");
#ifdef DEBUG
- fputs(" Stack not empty:", stdout);
+ DEBUG_puts("_cupsRasterExecPS: Stack not empty:");
DEBUG_stack(st);
#endif /* DEBUG */
@@ -1353,7 +1353,7 @@ setpagedevice(
* Now pull /name and value pairs from the dictionary...
*/
- DEBUG_puts(" Dictionary:");
+ DEBUG_puts("setpagedevice: Dictionary:");
for (obj ++; obj < end; obj ++)
{
@@ -1368,9 +1368,8 @@ setpagedevice(
obj ++;
#ifdef DEBUG
- printf(" /%s ", name);
+ DEBUG_printf(("setpagedevice: /%s ", name));
DEBUG_object(obj);
- putchar('\n');
#endif /* DEBUG */
/*
@@ -1542,86 +1541,86 @@ DEBUG_object(_cups_ps_obj_t *obj) /* I - Object to print */
switch (obj->type)
{
case CUPS_PS_NAME :
- printf("/%s", obj->value.name);
+ DEBUG_printf(("/%s\n", obj->value.name));
break;
case CUPS_PS_NUMBER :
- printf("%g", obj->value.number);
+ DEBUG_printf(("%g\n", obj->value.number));
break;
case CUPS_PS_STRING :
- printf("(%s)", obj->value.string);
+ DEBUG_printf(("(%s)\n", obj->value.string));
break;
case CUPS_PS_BOOLEAN :
if (obj->value.boolean)
- fputs("true", stdout);
+ DEBUG_puts("true");
else
- fputs("false", stdout);
+ DEBUG_puts("false");
break;
case CUPS_PS_NULL :
- fputs("null", stdout);
+ DEBUG_puts("null");
break;
case CUPS_PS_START_ARRAY :
- fputs("[", stdout);
+ DEBUG_puts("[");
break;
case CUPS_PS_END_ARRAY :
- fputs("]", stdout);
+ DEBUG_puts("]");
break;
case CUPS_PS_START_DICT :
- fputs("<<", stdout);
+ DEBUG_puts("<<");
break;
case CUPS_PS_END_DICT :
- fputs(">>", stdout);
+ DEBUG_puts(">>");
break;
case CUPS_PS_START_PROC :
- fputs("{", stdout);
+ DEBUG_puts("{");
break;
case CUPS_PS_END_PROC :
- fputs("}", stdout);
+ DEBUG_puts("}");
break;
case CUPS_PS_CLEARTOMARK :
- fputs("--cleartomark--", stdout);
+ DEBUG_puts("--cleartomark--");
break;
case CUPS_PS_COPY :
- fputs("--copy--", stdout);
+ DEBUG_puts("--copy--");
break;
case CUPS_PS_DUP :
- fputs("--dup--", stdout);
+ DEBUG_puts("--dup--");
break;
case CUPS_PS_INDEX :
- fputs("--index--", stdout);
+ DEBUG_puts("--index--");
break;
case CUPS_PS_POP :
- fputs("--pop--", stdout);
+ DEBUG_puts("--pop--");
break;
case CUPS_PS_ROLL :
- fputs("--roll--", stdout);
+ DEBUG_puts("--roll--");
break;
case CUPS_PS_SETPAGEDEVICE :
- fputs("--setpagedevice--", stdout);
+ DEBUG_puts("--setpagedevice--");
break;
case CUPS_PS_STOPPED :
- fputs("--stopped--", stdout);
+ DEBUG_puts("--stopped--");
break;
case CUPS_PS_OTHER :
- printf("--%s--", obj->value.other);
+ DEBUG_printf(("--%s--\n", obj->value.other));
break;
}
}
@@ -1639,12 +1638,7 @@ DEBUG_stack(_cups_ps_stack_t *st) /* I - Stack */
for (obj = st->objs, c = st->num_objs; c > 0; c --, obj ++)
- {
- putchar(' ');
DEBUG_object(obj);
- }
-
- putchar('\n');
}
#endif /* DEBUG */
diff --git a/filter/pdftops.c b/filter/pdftops.c
index f1abb52bf..0529dd144 100644
--- a/filter/pdftops.c
+++ b/filter/pdftops.c
@@ -68,9 +68,13 @@ main(int argc, /* I - Number of command-line args */
pdfwaitpid, /* Process ID from wait() */
pdfstatus, /* Status from pdftops */
pdfargc; /* Number of args for pdftops */
- char *pdfargv[100], /* Arguments for pdftops */
+ char *pdfargv[100], /* Arguments for pdftops/gs */
+#ifdef HAVE_PDFTOPS
pdfwidth[255], /* Paper width */
pdfheight[255]; /* Paper height */
+#else
+ pdfgeometry[255]; /* Paper width and height */
+#endif /* HAVE_PDFTOPS */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
struct sigaction action; /* Actions for POSIX signals */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
@@ -157,11 +161,22 @@ main(int argc, /* I - Number of command-line args */
cupsMarkOptions(ppd, num_options, options);
/*
- * Build the command-line for the pdftops filter...
+ * Build the command-line for the pdftops or gs filter...
*/
+#ifdef HAVE_PDFTOPS
pdfargv[0] = (char *)"pdftops";
pdfargc = 1;
+#else
+ pdfargv[0] = (char *)"gs";
+ pdfargv[1] = (char *)"-q";
+ pdfargv[2] = (char *)"-dNOPAUSE";
+ pdfargv[3] = (char *)"-dBATCH";
+ pdfargv[4] = (char *)"-dSAFER";
+ pdfargv[5] = (char *)"-sDEVICE=pswrite";
+ pdfargv[6] = (char *)"-sOUTPUTFILE=%stdout";
+ pdfargc = 7;
+#endif /* HAVE_PDFTOPS */
if (ppd)
{
@@ -171,17 +186,29 @@ main(int argc, /* I - Number of command-line args */
if (ppd->language_level == 1)
{
+#ifdef HAVE_PDFTOPS
pdfargv[pdfargc++] = (char *)"-level1";
pdfargv[pdfargc++] = (char *)"-noembtt";
+#else
+ pdfargv[pdfargc++] = (char *)"-dLanguageLevel=1";
+#endif /* HAVE_PDFTOPS */
}
else if (ppd->language_level == 2)
{
+#ifdef HAVE_PDFTOPS
pdfargv[pdfargc++] = (char *)"-level2";
if (!ppd->ttrasterizer)
pdfargv[pdfargc++] = (char *)"-noembtt";
+#else
+ pdfargv[pdfargc++] = (char *)"-dLanguageLevel=2";
+#endif /* HAVE_PDFTOPS */
}
else
+#ifdef HAVE_PDFTOPS
pdfargv[pdfargc++] = (char *)"-level3";
+#else
+ pdfargv[pdfargc++] = (char *)"-dLanguageLevel=3";
+#endif /* HAVE_PDFTOPS */
/*
* Set output page size...
@@ -218,6 +245,7 @@ main(int argc, /* I - Number of command-line args */
orientation ^= 1;
}
+#ifdef HAVE_PDFTOPS
if (orientation & 1)
{
snprintf(pdfwidth, sizeof(pdfwidth), "%.0f", size->length);
@@ -233,9 +261,20 @@ main(int argc, /* I - Number of command-line args */
pdfargv[pdfargc++] = pdfwidth;
pdfargv[pdfargc++] = (char *)"-paperh";
pdfargv[pdfargc++] = pdfheight;
+#else
+ if (orientation & 1)
+ snprintf(pdfgeometry, sizeof(pdfgeometry), "-g%.0fx%.0f", size->length,
+ size->width);
+ else
+ snprintf(pdfgeometry, sizeof(pdfgeometry), "-g%.0fx%.0f", size->width,
+ size->length);
+
+ pdfargv[pdfargc++] = pdfgeometry;
+#endif /* HAVE_PDFTOPS */
}
}
+#ifdef HAVE_PDFTOPS
if ((val = cupsGetOption("fitplot", num_options, options)) != NULL &&
strcasecmp(val, "no") && strcasecmp(val, "off") &&
strcasecmp(val, "false"))
@@ -243,7 +282,14 @@ main(int argc, /* I - Number of command-line args */
pdfargv[pdfargc++] = filename;
pdfargv[pdfargc++] = (char *)"-";
- pdfargv[pdfargc] = NULL;
+#else
+ pdfargv[pdfargc++] = (char *)"-c";
+ pdfargv[pdfargc++] = (char *)"save pop";
+ pdfargv[pdfargc++] = (char *)"-f";
+ pdfargv[pdfargc++] = filename;
+#endif /* HAVE_PDFTOPS */
+
+ pdfargv[pdfargc] = NULL;
if ((pdfpid = fork()) == 0)
{
@@ -251,8 +297,14 @@ main(int argc, /* I - Number of command-line args */
* Child comes here...
*/
+#ifdef HAVE_PDFTOPS
execv(CUPS_PDFTOPS, pdfargv);
- _cupsLangPrintError(_("ERROR: Unable to execute pdftops filter"));
+ _cupsLangPrintError(_("ERROR: Unable to execute pdftops program"));
+#else
+ execv(CUPS_GHOSTSCRIPT, pdfargv);
+ _cupsLangPrintError(_("ERROR: Unable to execute gs program"));
+#endif /* HAVE_PDFTOPS */
+
exit(1);
}
else if (pdfpid < 0)
@@ -261,7 +313,12 @@ main(int argc, /* I - Number of command-line args */
* Unable to fork!
*/
- _cupsLangPrintError(_("ERROR: Unable to execute pdftops filter"));
+#ifdef HAVE_PDFTOPS
+ _cupsLangPrintError(_("ERROR: Unable to execute pdftops program"));
+#else
+ _cupsLangPrintError(_("ERROR: Unable to execute gs program"));
+#endif /* HAVE_PDFTOPS */
+
pdfstatus = 1;
}
else
diff --git a/filter/rastertoepson.c b/filter/rastertoepson.c
index 62ecb347b..b528bc06b 100644
--- a/filter/rastertoepson.c
+++ b/filter/rastertoepson.c
@@ -322,11 +322,6 @@ StartPage(const ppd_file_t *ppd, /* I - PPD file */
void
EndPage(const cups_page_header2_t *header) /* I - Page header */
{
-#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
- struct sigaction action; /* Actions for POSIX signals */
-#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
-
-
if (DotBytes && header)
{
/*
diff --git a/filter/rastertolabel.c b/filter/rastertolabel.c
index cb62278fd..956ae88ab 100644
--- a/filter/rastertolabel.c
+++ b/filter/rastertolabel.c
@@ -482,9 +482,6 @@ EndPage(ppd_file_t *ppd, /* I - PPD file */
{
int val; /* Option value */
ppd_choice_t *choice; /* Marked choice */
-#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
- struct sigaction action; /* Actions for POSIX signals */
-#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
switch (ModelNumber)
diff --git a/notifier/mailto.c b/notifier/mailto.c
index a83409e95..3376065fe 100644
--- a/notifier/mailto.c
+++ b/notifier/mailto.c
@@ -3,7 +3,7 @@
*
* "mailto" notifier for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007 by Apple Inc.
+ * Copyright 2007-2008 by Apple Inc.
* Copyright 1997-2005 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
@@ -315,7 +315,7 @@ email_message(const char *to, /* I - Recipient of message */
cupsFilePrintf(fp, "Content-Type: text/plain%s", nl);
cupsFilePuts(fp, nl);
cupsFilePrintf(fp, "%s%s", text, nl);
- cupsFilePrintf(fp, ".\n", nl);
+ cupsFilePrintf(fp, ".%s", nl);
/*
* Close the connection to the mail server...
diff --git a/notifier/rss.c b/notifier/rss.c
index c5767a6b1..03f1199bb 100644
--- a/notifier/rss.c
+++ b/notifier/rss.c
@@ -579,6 +579,7 @@ save_rss(cups_array_t *rss, /* I - RSS messages */
FILE *fp; /* File pointer */
_cups_rss_t *msg; /* Current message */
char date[1024]; /* Current date */
+ char *href; /* Escaped base URL */
if ((fp = fopen(filename, "w")) == NULL)
@@ -592,7 +593,11 @@ save_rss(cups_array_t *rss, /* I - RSS messages */
fputs("\n", fp);
fputs(" \n", fp);
fputs(" CUPS RSS Feed\n", fp);
- fprintf(fp, " %s\n", baseurl);
+
+ href = xml_escape(baseurl);
+ fprintf(fp, " %s\n", href);
+ free(href);
+
fputs(" CUPS RSS Feed\n", fp);
fputs(" " CUPS_SVERSION "\n", fp);
fputs(" 1\n", fp);
diff --git a/ppdc/ppdc-catalog.cxx b/ppdc/ppdc-catalog.cxx
index 29de91f67..db9528e6d 100644
--- a/ppdc/ppdc-catalog.cxx
+++ b/ppdc/ppdc-catalog.cxx
@@ -178,7 +178,7 @@ ppdcCatalog::load_messages(
if ((fp = cupsFileOpen(f, "r")) == NULL)
return (-1);
- if ((ptr = strrchr(f, '.')) == NULL)
+ if ((ptr = (char *)strrchr(f, '.')) == NULL)
goto unknown_load_format;
else if (!strcmp(ptr, ".strings"))
{
@@ -305,7 +305,7 @@ ppdcCatalog::load_messages(
continue;
// Strip the trailing quote...
- if ((ptr = strrchr(line, '\"')) == NULL)
+ if ((ptr = (char *)strrchr(line, '\"')) == NULL)
{
fprintf(stderr, "ERROR: Expected quoted string on line %d of %s!\n",
linenum, f);
@@ -451,7 +451,7 @@ ppdcCatalog::save_messages(
// Open the file...
- if ((ptr = strrchr(f, '.')) == NULL)
+ if ((ptr = (char *)strrchr(f, '.')) == NULL)
return (-1);
if (!strcmp(ptr, ".gz"))
diff --git a/scheduler/client.c b/scheduler/client.c
index 94ddc900a..ba016434a 100644
--- a/scheduler/client.c
+++ b/scheduler/client.c
@@ -2606,7 +2606,8 @@ cupsdWriteClient(cupsd_client_t *con) /* I - Client connection */
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdWriteClient(con=%p) %d response=%p(%d), file=%d "
"pipe_pid=%d state=%d",
- con, con->http.fd, con->response, con->response->state,
+ con, con->http.fd, con->response,
+ con->response ? con->response->state : -1,
con->file, con->pipe_pid, con->http.state);
#endif /* DEBUG */
@@ -2768,6 +2769,8 @@ cupsdWriteClient(cupsd_client_t *con) /* I - Client connection */
return;
}
+ httpFlushWrite(HTTP(con));
+
con->bytes += bytes;
if (con->http.state == HTTP_WAITING)
diff --git a/scheduler/conf.c b/scheduler/conf.c
index 254755648..c8e814886 100644
--- a/scheduler/conf.c
+++ b/scheduler/conf.c
@@ -416,7 +416,7 @@ cupsdReadConfiguration(void)
cupsdSetString(&PrintcapGUI, "/usr/bin/glpoptions");
cupsdSetString(&FontPath, CUPS_FONTPATH);
cupsdSetString(&RemoteRoot, "remroot");
- cupsdSetString(&ServerHeader, "CUPS/1.2");
+ cupsdSetString(&ServerHeader, "CUPS/1.4");
cupsdSetString(&StateDir, CUPS_STATEDIR);
#ifdef HAVE_GSSAPI
cupsdSetString(&GSSServiceName, CUPS_DEFAULT_GSSSERVICENAME);
@@ -783,10 +783,14 @@ cupsdReadConfiguration(void)
* writable by the user and group in the cupsd.conf file...
*/
+ snprintf(temp, sizeof(temp), "%s/rss", CacheDir);
+
if (cupsdCheckPermissions(RequestRoot, NULL, 0710, RunUser,
Group, 1, 1) < 0 ||
cupsdCheckPermissions(CacheDir, NULL, 0775, RunUser,
Group, 1, 1) < 0 ||
+ cupsdCheckPermissions(temp, NULL, 0775, RunUser,
+ Group, 1, 1) < 0 ||
cupsdCheckPermissions(StateDir, NULL, 0755, RunUser,
Group, 1, 1) < 0 ||
cupsdCheckPermissions(StateDir, "certs", RunUser ? 0711 : 0511, User,
@@ -2965,7 +2969,7 @@ read_configuration(cups_file_t *fp) /* I - File to read from */
else if (!strcasecmp(value, "Major"))
cupsdSetString(&ServerHeader, "CUPS/1");
else if (!strcasecmp(value, "Minor"))
- cupsdSetString(&ServerHeader, "CUPS/1.2");
+ cupsdSetString(&ServerHeader, "CUPS/1.4");
else if (!strcasecmp(value, "Minimal"))
cupsdSetString(&ServerHeader, CUPS_MINIMAL);
else if (!strcasecmp(value, "OS"))
diff --git a/scheduler/cups-deviced.c b/scheduler/cups-deviced.c
index 385037ea2..9c5b6991f 100644
--- a/scheduler/cups-deviced.c
+++ b/scheduler/cups-deviced.c
@@ -14,11 +14,15 @@
*
* Contents:
*
- * main() - Scan for devices and return an IPP response.
- * add_dev() - Add a new device to the list.
- * compare_devs() - Compare device names for sorting.
- * run_backend() - Run a backend to gather the available devices.
- * sigalrm_handler() - Handle alarm signals for backends that get hung
+ * main() - Scan for devices and return an IPP response.
+ * add_device() - Add a new device to the list.
+ * compare_devices() - Compare device names to eliminate duplicates.
+ * create_strings_array() - Create a CUPS array of strings.
+ * get_current_time() - Get the current time as a double value in seconds.
+ * get_device() - Get a device from a backend.
+ * process_children() - Process all dead children...
+ * sigchld_handler() - Handle 'child' signals from old processes.
+ * start_backend() - Run a backend to gather the available devices.
*/
/*
@@ -29,6 +33,29 @@
#include
#include
#include
+#include
+#include
+
+
+/*
+ * Constants...
+ */
+
+#define MAX_BACKENDS 200 /* Maximum number of backends we'll run */
+
+
+/*
+ * Backend information...
+ */
+
+typedef struct
+{
+ char *name; /* Name of backend */
+ int pid, /* Process ID */
+ status; /* Exit status */
+ cups_file_t *pipe; /* Pipe from backend stdout */
+ int count; /* Number of devices found */
+} cupsd_backend_t;
/*
@@ -42,30 +69,51 @@ typedef struct
device_info[128], /* Device info/description */
device_uri[1024], /* Device URI */
device_id[1024]; /* 1284 Device ID */
-} dev_info_t;
+} cupsd_device_t;
/*
* Local globals...
*/
-static int alarm_tripped; /* Non-zero if alarm was tripped */
-static cups_array_t *devs; /* Device info */
+static int num_backends = 0,
+ /* Total backends */
+ active_backends = 0;
+ /* Active backends */
+static cupsd_backend_t backends[MAX_BACKENDS];
+ /* Array of backends */
+static struct pollfd backend_fds[MAX_BACKENDS];
+ /* Array for poll() */
+static cups_array_t *devices; /* Array of devices */
static int normal_user; /* Normal user ID */
+static int device_limit; /* Maximum number of devices */
+static int send_class, /* Send device-class attribute? */
+ send_info, /* Send device-info attribute? */
+ send_make_and_model,
+ /* Send device-make-and-model attribute? */
+ send_uri, /* Send device-uri attribute? */
+ send_id; /* Send device-id attribute? */
+static int dead_children = 0;
+ /* Dead children? */
/*
* Local functions...
*/
-static dev_info_t *add_dev(const char *device_class,
- const char *device_make_and_model,
- const char *device_info,
- const char *device_uri,
- const char *device_id);
-static int compare_devs(dev_info_t *p0, dev_info_t *p1);
-static FILE *run_backend(const char *backend, int uid, int *pid);
-static void sigalrm_handler(int sig);
+static int add_device(const char *device_class,
+ const char *device_make_and_model,
+ const char *device_info,
+ const char *device_uri,
+ const char *device_id);
+static int compare_devices(cupsd_device_t *p0,
+ cupsd_device_t *p1);
+static cups_array_t *create_strings_array(const char *s);
+static double get_current_time(void);
+static int get_device(cupsd_backend_t *backend);
+static void process_children(void);
+static void sigchld_handler(int sig);
+static int start_backend(const char *backend, int root);
/*
@@ -80,31 +128,19 @@ int /* O - Exit code */
main(int argc, /* I - Number of command-line args */
char *argv[]) /* I - Command-line arguments */
{
- const char *server_bin; /* CUPS_SERVERBIN environment variable */
- char backends[1024]; /* Location of backends */
+ int i; /* Looping var */
int request_id; /* Request ID */
- int count; /* Number of devices from backend */
- int compat; /* Compatibility device? */
- FILE *fp; /* Pipe to device backend */
- int pid; /* Process ID of backend */
+ int timeout; /* Timeout in seconds */
+ const char *server_bin; /* CUPS_SERVERBIN environment variable */
+ char filename[1024]; /* Backend directory filename */
cups_dir_t *dir; /* Directory pointer */
cups_dentry_t *dent; /* Directory entry */
- char filename[1024], /* Name of backend */
- line[2048], /* Line from backend */
- dclass[64], /* Device class */
- uri[1024], /* Device URI */
- info[128], /* Device info */
- make_model[256], /* Make and model */
- device_id[1024]; /* 1284 device ID */
+ double current_time, /* Current time */
+ end_time; /* Ending time */
int num_options; /* Number of options */
cups_option_t *options; /* Options */
- const char *requested; /* requested-attributes option */
- int send_class, /* Send device-class attribute? */
- send_info, /* Send device-info attribute? */
- send_make_and_model, /* Send device-make-and-model attribute? */
- send_uri, /* Send device-uri attribute? */
- send_id; /* Send device-id attribute? */
- dev_info_t *dev; /* Current device */
+ cups_array_t *requested, /* requested-attributes values */
+ *exclude; /* exclude-schemes values */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
struct sigaction action; /* Actions for POSIX signals */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
@@ -116,53 +152,79 @@ main(int argc, /* I - Number of command-line args */
* Check the command-line...
*/
- if (argc > 1)
- request_id = atoi(argv[1]);
- else
- request_id = 1;
-
- if (argc != 5)
+ if (argc != 6)
{
- fputs("Usage: cups-deviced request-id limit user-id options\n", stderr);
+ fputs("Usage: cups-deviced request-id limit timeout user-id options\n", stderr);
return (1);
}
+ request_id = atoi(argv[1]);
if (request_id < 1)
{
- fprintf(stderr, "cups-deviced: Bad request ID %d!\n", request_id);
+ fprintf(stderr, "ERROR: [cups-deviced] Bad request ID %d!\n", request_id);
return (1);
}
- normal_user = atoi(argv[3]);
- if (normal_user <= 0)
+ device_limit = atoi(argv[2]);
+ if (device_limit < 0)
{
- fprintf(stderr, "cups-deviced: Bad user %d!\n", normal_user);
+ fprintf(stderr, "ERROR: [cups-deviced] Bad limit %d!\n", device_limit);
return (1);
}
- num_options = cupsParseOptions(argv[4], 0, &options);
- requested = cupsGetOption("requested-attributes", num_options, options);
+ timeout = atoi(argv[3]);
+ if (timeout < 1)
+ {
+ fprintf(stderr, "ERROR: [cups-deviced] Bad timeout %d!\n", timeout);
+
+ return (1);
+ }
- if (!requested || strstr(requested, "all"))
+ normal_user = atoi(argv[4]);
+ if (normal_user <= 0)
{
- send_class = 1;
- send_info = 1;
- send_make_and_model = 1;
- send_uri = 1;
- send_id = 1;
+ fprintf(stderr, "ERROR: [cups-deviced] Bad user %d!\n", normal_user);
+
+ return (1);
}
+
+ num_options = cupsParseOptions(argv[5], 0, &options);
+ requested = create_strings_array(cupsGetOption("requested-attributes",
+ num_options, options));
+ exclude = create_strings_array(cupsGetOption("exclude-schemes",
+ num_options, options));
+
+ if (!requested || cupsArrayFind(requested, "all") != NULL)
+ send_class = send_info = send_make_and_model = send_uri = send_id = 1;
else
{
- send_class = strstr(requested, "device-class") != NULL;
- send_info = strstr(requested, "device-info") != NULL;
- send_make_and_model = strstr(requested, "device-make-and-model") != NULL;
- send_uri = strstr(requested, "device-uri") != NULL;
- send_id = strstr(requested, "device-id") != NULL;
+ send_class = cupsArrayFind(requested, "device-class") != NULL;
+ send_info = cupsArrayFind(requested, "device-info") != NULL;
+ send_make_and_model = cupsArrayFind(requested, "device-make-and-model") != NULL;
+ send_uri = cupsArrayFind(requested, "device-uri") != NULL;
+ send_id = cupsArrayFind(requested, "device-id") != NULL;
}
+ /*
+ * Listen to child signals...
+ */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGCHLD, sigchld_handler);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGCHLD);
+ action.sa_handler = sigchld_handler;
+ sigaction(SIGCHLD, &action, NULL);
+#else
+ signal(SIGCLD, sigchld_handler); /* No, SIGCLD isn't a typo... */
+#endif /* HAVE_SIGSET */
+
/*
* Try opening the backend directory...
*/
@@ -170,12 +232,12 @@ main(int argc, /* I - Number of command-line args */
if ((server_bin = getenv("CUPS_SERVERBIN")) == NULL)
server_bin = CUPS_SERVERBIN;
- snprintf(backends, sizeof(backends), "%s/backend", server_bin);
+ snprintf(filename, sizeof(filename), "%s/backend", server_bin);
- if ((dir = cupsDirOpen(backends)) == NULL)
+ if ((dir = cupsDirOpen(filename)) == NULL)
{
fprintf(stderr, "ERROR: [cups-deviced] Unable to open backend directory "
- "\"%s\": %s", backends, strerror(errno));
+ "\"%s\": %s", filename, strerror(errno));
return (1);
}
@@ -184,7 +246,7 @@ main(int argc, /* I - Number of command-line args */
* Setup the devices array...
*/
- devs = cupsArrayNew((cups_array_func_t)compare_devs, NULL);
+ devices = cupsArrayNew((cups_array_func_t)compare_devices, NULL);
/*
* Loop through all of the device backends...
@@ -197,273 +259,172 @@ main(int argc, /* I - Number of command-line args */
*/
if (!S_ISREG(dent->fileinfo.st_mode) ||
+ !isalnum(dent->filename[0] & 255) ||
(dent->fileinfo.st_mode & (S_IRUSR | S_IXUSR)) != (S_IRUSR | S_IXUSR))
continue;
- /*
- * Change effective users depending on the backend permissions...
- */
-
- snprintf(filename, sizeof(filename), "%s/%s", backends, dent->filename);
+ if (cupsArrayFind(exclude, dent->filename))
+ continue;
/*
* Backends without permissions for normal users run as root,
* all others run as the unprivileged user...
*/
- fp = run_backend(filename,
- (dent->fileinfo.st_mode & (S_IRWXG | S_IRWXO))
- ? normal_user : 0,
- &pid);
-
- /*
- * Collect the output from the backend...
- */
-
- if (fp)
- {
- /*
- * Set an alarm for the first read from the backend; this avoids
- * problems when a backend is hung getting device information.
- */
-
-#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
- sigset(SIGALRM, sigalrm_handler);
-#elif defined(HAVE_SIGACTION)
- memset(&action, 0, sizeof(action));
-
- sigemptyset(&action.sa_mask);
- sigaddset(&action.sa_mask, SIGALRM);
- action.sa_handler = sigalrm_handler;
- sigaction(SIGALRM, &action, NULL);
-#else
- signal(SIGALRM, sigalrm_handler);
-#endif /* HAVE_SIGSET */
-
- alarm_tripped = 0;
- count = 0;
- compat = !strcmp(dent->filename, "smb");
-
- alarm(30);
-
- while (fgets(line, sizeof(line), fp) != NULL)
- {
- /*
- * Reset the alarm clock...
- */
-
- alarm(30);
-
- /*
- * Each line is of the form:
- *
- * class URI "make model" "name" ["1284 device ID"]
- */
-
- device_id[0] = '\0';
-
- if (!strncasecmp(line, "Usage", 5))
- compat = 1;
- else if (sscanf(line,
- "%63s%1023s%*[ \t]\"%255[^\"]\"%*[ \t]\"%127[^\"]\""
- "%*[ \t]\"%1023[^\"]",
- dclass, uri, make_model, info, device_id) < 4)
- {
- /*
- * Bad format; strip trailing newline and write an error message.
- */
-
- if (line[strlen(line) - 1] == '\n')
- line[strlen(line) - 1] = '\0';
-
- fprintf(stderr, "ERROR: [cups-deviced] Bad line from \"%s\": %s\n",
- dent->filename, line);
- compat = 1;
- break;
- }
- else
- {
- /*
- * Add the device to the array of available devices...
- */
-
- dev = add_dev(dclass, make_model, info, uri, device_id);
- if (!dev)
- {
- cupsDirClose(dir);
- fclose(fp);
- kill(pid, SIGTERM);
- return (1);
- }
-
- fprintf(stderr, "DEBUG: [cups-deviced] Added device \"%s\"...\n",
- uri);
- count ++;
- }
- }
-
- /*
- * Turn the alarm clock off and close the pipe to the command...
- */
-
- alarm(0);
-
- if (alarm_tripped)
- fprintf(stderr, "WARNING: [cups-deviced] Backend \"%s\" did not "
- "respond within 30 seconds!\n", dent->filename);
-
- fclose(fp);
- kill(pid, SIGTERM);
-
- /*
- * Hack for backends that don't support the CUPS 1.1 calling convention:
- * add a network device with the method == backend name.
- */
-
- if (count == 0 && compat)
- {
- snprintf(line, sizeof(line), "Unknown Network Device (%s)",
- dent->filename);
-
- dev = add_dev("network", line, "Unknown", dent->filename, "");
- if (!dev)
- {
- cupsDirClose(dir);
- return (1);
- }
-
- fprintf(stderr, "DEBUG: [cups-deviced] Compatibility device "
- "\"%s\"...\n", dent->filename);
- }
- }
- else
- fprintf(stderr, "WARNING: [cups-deviced] Unable to execute \"%s\" "
- "backend: %s\n", dent->filename, strerror(errno));
+ start_backend(dent->filename,
+ !(dent->fileinfo.st_mode & (S_IRWXG | S_IRWXO)));
}
cupsDirClose(dir);
/*
- * Output the list of devices...
+ * Collect devices...
*/
- puts("Content-Type: application/ipp\n");
+ if (getenv("SOFTWARE"))
+ puts("Content-Type: application/ipp\n");
cupsdSendIPPHeader(IPP_OK, request_id);
cupsdSendIPPGroup(IPP_TAG_OPERATION);
cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", "en-US");
- if ((count = atoi(argv[2])) <= 0)
- count = cupsArrayCount(devs);
-
- if (count > cupsArrayCount(devs))
- count = cupsArrayCount(devs);
+ end_time = get_current_time() + timeout;
- for (dev = (dev_info_t *)cupsArrayFirst(devs);
- count > 0;
- count --, dev = (dev_info_t *)cupsArrayNext(devs))
+ while (active_backends > 0 && (current_time = get_current_time()) < end_time)
{
/*
- * Add strings to attributes...
+ * Collect the output from the backends...
+ */
+
+ timeout = (int)(1000 * (end_time - current_time));
+
+ if (poll(backend_fds, num_backends, timeout) > 0)
+ {
+ for (i = 0; i < num_backends; i ++)
+ if (backend_fds[i].revents && backends[i].pipe)
+ if (get_device(backends + i))
+ {
+ backend_fds[i].fd = 0;
+ backend_fds[i].events = 0;
+ }
+ }
+
+ /*
+ * Get exit status from children...
*/
- cupsdSendIPPGroup(IPP_TAG_PRINTER);
- if (send_class)
- cupsdSendIPPString(IPP_TAG_KEYWORD, "device-class", dev->device_class);
- if (send_info)
- cupsdSendIPPString(IPP_TAG_TEXT, "device-info", dev->device_info);
- if (send_make_and_model)
- cupsdSendIPPString(IPP_TAG_TEXT, "device-make-and-model",
- dev->device_make_and_model);
- if (send_uri)
- cupsdSendIPPString(IPP_TAG_URI, "device-uri", dev->device_uri);
- if (send_id)
- cupsdSendIPPString(IPP_TAG_TEXT, "device-id", dev->device_id);
+ if (dead_children)
+ process_children();
}
cupsdSendIPPTrailer();
/*
- * Free the devices array and return...
+ * Terminate any remaining backends and exit...
*/
- for (dev = (dev_info_t *)cupsArrayFirst(devs);
- dev;
- dev = (dev_info_t *)cupsArrayNext(devs))
- free(dev);
-
- cupsArrayDelete(devs);
+ if (active_backends > 0)
+ {
+ for (i = 0; i < num_backends; i ++)
+ if (backends[i].pid)
+ kill(backends[i].pid, SIGTERM);
+ }
return (0);
}
/*
- * 'add_dev()' - Add a new device to the list.
+ * 'add_device()' - Add a new device to the list.
*/
-static dev_info_t * /* O - New device or NULL on error */
-add_dev(
+static int /* O - 0 on success, -1 on error */
+add_device(
const char *device_class, /* I - Device class */
const char *device_make_and_model, /* I - Device make and model */
const char *device_info, /* I - Device information */
const char *device_uri, /* I - Device URI */
const char *device_id) /* I - 1284 device ID */
{
- dev_info_t *dev, /* New device */
- *temp; /* Found device */
+ cupsd_device_t *device, /* New device */
+ *temp; /* Found device */
/*
* Allocate memory for the device record...
*/
- if ((dev = calloc(1, sizeof(dev_info_t))) == NULL)
+ if ((device = calloc(1, sizeof(cupsd_device_t))) == NULL)
{
fputs("ERROR: [cups-deviced] Ran out of memory allocating a device!\n",
stderr);
- return (NULL);
+ return (-1);
}
/*
* Copy the strings over...
*/
- strlcpy(dev->device_class, device_class, sizeof(dev->device_class));
- strlcpy(dev->device_make_and_model, device_make_and_model,
- sizeof(dev->device_make_and_model));
- strlcpy(dev->device_info, device_info, sizeof(dev->device_info));
- strlcpy(dev->device_uri, device_uri, sizeof(dev->device_uri));
- strlcpy(dev->device_id, device_id, sizeof(dev->device_id));
+ strlcpy(device->device_class, device_class, sizeof(device->device_class));
+ strlcpy(device->device_make_and_model, device_make_and_model,
+ sizeof(device->device_make_and_model));
+ strlcpy(device->device_info, device_info, sizeof(device->device_info));
+ strlcpy(device->device_uri, device_uri, sizeof(device->device_uri));
+ strlcpy(device->device_id, device_id, sizeof(device->device_id));
/*
* Add the device to the array and return...
*/
- if ((temp = cupsArrayFind(devs, dev)) != NULL)
+ if ((temp = cupsArrayFind(devices, device)) != NULL)
{
/*
* Avoid duplicates!
*/
- free(dev);
- dev = temp;
+ free(device);
}
else
- cupsArrayAdd(devs, dev);
-
- return (dev);
+ {
+ cupsArrayAdd(devices, device);
+
+ if (device_limit <= 0 || cupsArrayCount(devices) < device_limit)
+ {
+ /*
+ * Send device info...
+ */
+
+ cupsdSendIPPGroup(IPP_TAG_PRINTER);
+ if (send_class)
+ cupsdSendIPPString(IPP_TAG_KEYWORD, "device-class",
+ device->device_class);
+ if (send_info)
+ cupsdSendIPPString(IPP_TAG_TEXT, "device-info", device->device_info);
+ if (send_make_and_model)
+ cupsdSendIPPString(IPP_TAG_TEXT, "device-make-and-model",
+ device->device_make_and_model);
+ if (send_uri)
+ cupsdSendIPPString(IPP_TAG_URI, "device-uri", device->device_uri);
+ if (send_id)
+ cupsdSendIPPString(IPP_TAG_TEXT, "device-id", device->device_id);
+
+ fflush(stdout);
+ fputs("DEBUG: Flushed attributes...\n", stderr);
+ }
+ }
+
+ return (0);
}
/*
- * 'compare_devs()' - Compare device names for sorting.
+ * 'compare_devices()' - Compare device names to eliminate duplicates.
*/
static int /* O - Result of comparison */
-compare_devs(dev_info_t *d0, /* I - First device */
- dev_info_t *d1) /* I - Second device */
+compare_devices(cupsd_device_t *d0, /* I - First device */
+ cupsd_device_t *d1) /* I - Second device */
{
int diff; /* Difference between strings */
@@ -482,44 +443,276 @@ compare_devs(dev_info_t *d0, /* I - First device */
/*
- * 'run_backend()' - Run a backend to gather the available devices.
+ * 'create_strings_array()' - Create a CUPS array of strings.
*/
-static FILE * /* O - stdout of backend */
-run_backend(const char *backend, /* I - Backend to run */
- int uid, /* I - User ID to run as */
- int *pid) /* O - Process ID of backend */
+static cups_array_t * /* O - CUPS array */
+create_strings_array(const char *s) /* I - Comma-delimited strings */
{
- int fds[2]; /* Pipe file descriptors */
+ cups_array_t *a; /* CUPS array */
+ const char *start, /* Start of string */
+ *end; /* End of string */
+ char *ptr; /* New string */
+
+
+ if (!s)
+ return (NULL);
+
+ if ((a = cupsArrayNew((cups_array_func_t)strcmp, NULL)) != NULL)
+ {
+ for (start = end = s; *end; start = end + 1)
+ {
+ /*
+ * Find the end of the current delimited string...
+ */
+
+ if ((end = strchr(start, ',')) == NULL)
+ end = start + strlen(start);
+
+ /*
+ * Duplicate the string and add it to the array...
+ */
+
+ if ((ptr = calloc(1, end - start + 1)) == NULL)
+ break;
+ memcpy(ptr, start, end - start);
+ cupsArrayAdd(a, ptr);
+ }
+ }
+
+ return (a);
+}
+
+
+/*
+ * 'get_current_time()' - Get the current time as a double value in seconds.
+ */
+
+static double /* O - Time in seconds */
+get_current_time(void)
+{
+ struct timeval curtime; /* Current time */
+
+
+ gettimeofday(&curtime, NULL);
+
+ return (curtime.tv_sec + 0.000001 * curtime.tv_usec);
+}
+
+
+/*
+ * 'get_device()' - Get a device from a backend.
+ */
+
+static int /* O - 0 on success, -1 on error */
+get_device(cupsd_backend_t *backend) /* I - Backend to read from */
+{
+ char line[2048], /* Line from backend */
+ dclass[64], /* Device class */
+ uri[1024], /* Device URI */
+ info[128], /* Device info */
+ make_model[256], /* Make and model */
+ device_id[1024]; /* 1284 device ID */
+
+
+ if (cupsFileGets(backend->pipe, line, sizeof(line)))
+ {
+ /*
+ * Each line is of the form:
+ *
+ * class URI "make model" "name" ["1284 device ID"]
+ */
+
+ device_id[0] = '\0';
+
+ if (sscanf(line,
+ "%63s%1023s%*[ \t]\"%255[^\"]\"%*[ \t]\"%127[^\"]\""
+ "%*[ \t]\"%1023[^\"]",
+ dclass, uri, make_model, info, device_id) < 4)
+ {
+ /*
+ * Bad format; strip trailing newline and write an error message.
+ */
+
+ if (line[strlen(line) - 1] == '\n')
+ line[strlen(line) - 1] = '\0';
+
+ fprintf(stderr, "ERROR: [cups-deviced] Bad line from \"%s\": %s\n",
+ backend->name, line);
+ }
+ else
+ {
+ /*
+ * Add the device to the array of available devices...
+ */
+
+ if (!add_device(dclass, make_model, info, uri, device_id))
+ fprintf(stderr, "DEBUG: [cups-deviced] Found device \"%s\"...\n", uri);
+ }
+
+ return (0);
+ }
+
+ /*
+ * End of file...
+ */
+
+ cupsFileClose(backend->pipe);
+ backend->pipe = NULL;
+
+ return (-1);
+}
+
+
+/*
+ * 'process_children()' - Process all dead children...
+ */
+
+static void
+process_children(void)
+{
+ int i; /* Looping var */
+ int status; /* Exit status of child */
+ int pid; /* Process ID of child */
+ cupsd_backend_t *backend; /* Current backend */
+ const char *name; /* Name of process */
+
+
+ /*
+ * 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 */
+ {
+ if (status == SIGTERM)
+ status = 0;
+
+ for (i = num_backends, backend = backends; i > 0; i --, backend ++)
+ if (backend->pid == pid)
+ break;
+
+ if (i > 0)
+ {
+ name = backend->name;
+ backend->pid = 0;
+ backend->status = status;
+
+ active_backends --;
+ }
+ else
+ name = "Unknown";
+
+ if (status)
+ {
+ if (WIFEXITED(status))
+ fprintf(stderr,
+ "ERROR: [cups-deviced] PID %d (%s) stopped with status %d!\n",
+ pid, name, WEXITSTATUS(status));
+ else
+ fprintf(stderr,
+ "ERROR: [cups-deviced] PID %d (%s) crashed on signal %d!\n",
+ pid, name, WTERMSIG(status));
+ }
+ else
+ fprintf(stderr,
+ "DEBUG: [cups-deviced] PID %d (%s) exited with no errors.\n",
+ pid, name);
+ }
+}
+
+
+/*
+ * 'sigchld_handler()' - Handle 'child' signals from old processes.
+ */
+
+static void
+sigchld_handler(int sig) /* I - Signal number */
+{
+ (void)sig;
+
+ /*
+ * Flag that we have dead children...
+ */
+
+ dead_children = 1;
+
+ /*
+ * Reset the signal handler as needed...
+ */
+
+#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
+ signal(SIGCLD, sigchld_handler);
+#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
+}
+
+
+/*
+ * 'start_backend()' - Run a backend to gather the available devices.
+ */
+
+static int /* O - 0 on success, -1 on error */
+start_backend(const char *name, /* I - Backend to run */
+ int root) /* I - Run as root? */
+{
+ const char *server_bin; /* CUPS_SERVERBIN environment variable */
+ char program[1024]; /* Full path to backend */
+ int fds[2]; /* Pipe file descriptors */
+ cupsd_backend_t *backend; /* Current backend */
+
+
+ if (num_backends >= MAX_BACKENDS)
+ {
+ fprintf(stderr, "ERROR: Too many backends (%d)!\n", num_backends);
+ return (-1);
+ }
if (pipe(fds))
{
fprintf(stderr, "ERROR: Unable to create a pipe for \"%s\" - %s\n",
- backend, strerror(errno));
- return (NULL);
+ name, strerror(errno));
+ return (-1);
}
- if ((*pid = fork()) < 0)
+ if ((server_bin = getenv("CUPS_SERVERBIN")) == NULL)
+ server_bin = CUPS_SERVERBIN;
+
+ snprintf(program, sizeof(program), "%s/backend/%s", server_bin, name);
+
+ backend = backends + num_backends;
+
+ if ((backend->pid = fork()) < 0)
{
/*
* Error!
*/
- fprintf(stderr, "ERROR: Unable to fork for \"%s\" - %s\n", backend,
- strerror(errno));
+ fprintf(stderr, "ERROR: [cups-deviced] Unable to fork for \"%s\" - %s\n",
+ program, strerror(errno));
close(fds[0]);
close(fds[1]);
- return (NULL);
+ return (-1);
}
- else if (!*pid)
+ else if (!backend->pid)
{
/*
* Child comes here...
*/
- if (!getuid() && uid)
- setuid(uid); /* Run as restricted user */
+ if (!getuid() && !root)
+ setuid(normal_user); /* Run as restricted user */
close(0); /* pid);
- return (fdopen(fds[0], "r"));
-}
+ close(fds[1]);
+ backend_fds[num_backends].fd = fds[0];
+ backend_fds[num_backends].events = POLLIN;
-/*
- * 'sigalrm_handler()' - Handle alarm signals for backends that get hung
- * trying to list the available devices...
- */
+ backend->name = strdup(name);
+ backend->status = 0;
+ backend->pipe = cupsFileOpenFd(fds[0], "r");
+ backend->count = 0;
-static void
-sigalrm_handler(int sig) /* I - Signal number */
-{
- (void)sig; /* remove compiler warnings... */
+ active_backends ++;
+ num_backends ++;
- alarm_tripped = 1;
+ return (0);
}
diff --git a/scheduler/filter.c b/scheduler/filter.c
index 30231306d..73344b6ae 100644
--- a/scheduler/filter.c
+++ b/scheduler/filter.c
@@ -275,7 +275,7 @@ find_filters(mime_t *mime, /* I - MIME database */
* Got a direct filter!
*/
- DEBUG_puts("Direct filter found!");
+ DEBUG_puts("find_filters: Direct filter found!");
if ((mintemp = cupsArrayNew(NULL, NULL)) == NULL)
return (NULL);
@@ -287,8 +287,8 @@ find_filters(mime_t *mime, /* I - MIME database */
if (!cost)
return (mintemp);
- DEBUG_puts(" Found direct filter:");
- DEBUG_printf((" %s (cost=%d)\n", current->filter, mincost));
+ DEBUG_puts("find_filters: Found direct filter:");
+ DEBUG_printf(("find_filters: %s (cost=%d)\n", current->filter, mincost));
}
else
{
@@ -381,11 +381,13 @@ find_filters(mime_t *mime, /* I - MIME database */
*/
#ifdef DEBUG
- printf(" Returning %d filters:\n", cupsArrayCount(mintemp));
+ DEBUG_printf(("find_filters: Returning %d filters:\n",
+ cupsArrayCount(mintemp)));
+
for (current = (mime_filter_t *)cupsArrayFirst(mintemp);
current;
current = (mime_filter_t *)cupsArrayNext(mintemp))
- printf(" %s\n", current->filter);
+ DEBUG_printf(("find_filters: %s\n", current->filter));
#endif /* DEBUG */
if (cost)
@@ -394,7 +396,7 @@ find_filters(mime_t *mime, /* I - MIME database */
return (mintemp);
}
- DEBUG_puts(" Returning zippo...");
+ DEBUG_puts("find_filters: Returning zippo...");
return (NULL);
}
diff --git a/scheduler/ipp.c b/scheduler/ipp.c
index 9ecca1cde..f29006b86 100644
--- a/scheduler/ipp.c
+++ b/scheduler/ipp.c
@@ -6158,12 +6158,16 @@ static void
get_devices(cupsd_client_t *con) /* I - Client connection */
{
http_status_t status; /* Policy status */
- ipp_attribute_t *limit, /* Limit attribute */
- *requested; /* requested-attributes attribute */
+ ipp_attribute_t *limit, /* limit attribute */
+ *timeout, /* timeout attribute */
+ *requested, /* requested-attributes attribute */
+ *exclude; /* exclude-schemes attribute */
char command[1024], /* cups-deviced command */
options[1024], /* Options to pass to command */
- requested_str[256];
+ requested_str[256],
/* String for requested attributes */
+ exclude_str[512];
+ /* String for excluded attributes */
cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_devices(%p[%d])", con, con->http.fd);
@@ -6182,21 +6186,31 @@ get_devices(cupsd_client_t *con) /* I - Client connection */
* Run cups-deviced command with the given options...
*/
- limit = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER);
+ limit = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER);
+ timeout = ippFindAttribute(con->request, "timeout", IPP_TAG_INTEGER);
requested = ippFindAttribute(con->request, "requested-attributes",
IPP_TAG_KEYWORD);
+ exclude = ippFindAttribute(con->request, "exclude-schemes", IPP_TAG_NAME);
if (requested)
url_encode_attr(requested, requested_str, sizeof(requested_str));
else
strlcpy(requested_str, "requested-attributes=all", sizeof(requested_str));
+ if (exclude)
+ url_encode_attr(exclude, exclude_str, sizeof(exclude_str));
+ else
+ exclude_str[0] = '\0';
+
snprintf(command, sizeof(command), "%s/daemon/cups-deviced", ServerBin);
snprintf(options, sizeof(options),
- "%d+%d+%d+%s",
+ "%d+%d+%d+%d+%s%s%s",
con->request->request.op.request_id,
- limit ? limit->values[0].integer : 0, (int)User,
- requested_str);
+ limit ? limit->values[0].integer : 0,
+ timeout ? timeout->values[0].integer : 10,
+ (int)User,
+ requested_str,
+ exclude_str[0] ? "%20" : "", exclude_str);
if (cupsdSendCommand(con, command, options, 1))
{
diff --git a/scheduler/main.c b/scheduler/main.c
index 8ecd4309e..e831920a0 100644
--- a/scheduler/main.c
+++ b/scheduler/main.c
@@ -1730,7 +1730,7 @@ process_children(void)
*/
static void
-sigchld_handler(int sig) /* I - Signal number */
+sigchld_handler(int sig) /* I - Signal number */
{
(void)sig;
@@ -1755,7 +1755,7 @@ sigchld_handler(int sig) /* I - Signal number */
*/
static void
-sighup_handler(int sig) /* I - Signal number */
+sighup_handler(int sig) /* I - Signal number */
{
(void)sig;
@@ -1773,7 +1773,7 @@ sighup_handler(int sig) /* I - Signal number */
*/
static void
-sigterm_handler(int sig) /* I - Signal */
+sigterm_handler(int sig) /* I - Signal number */
{
(void)sig; /* remove compiler warnings... */
diff --git a/systemv/lpinfo.c b/systemv/lpinfo.c
index b8697c2c8..137304994 100644
--- a/systemv/lpinfo.c
+++ b/systemv/lpinfo.c
@@ -15,6 +15,7 @@
* Contents:
*
* main() - Parse options and show information.
+ * device_cb - Device callback.
* show_devices() - Show available devices.
* show_models() - Show available PPDs.
*/
@@ -36,6 +37,10 @@
* Local functions...
*/
+static void device_cb(const char *device_clas, const char *device_id,
+ const char *device_info,
+ const char *device_make_and_model,
+ const char *device_uri, void *user_data);
static int show_devices(http_t *, int);
static int show_models(http_t *, int);
@@ -158,134 +163,53 @@ main(int argc, /* I - Number of command-line arguments */
/*
- * 'show_devices()' - Show available devices.
+ * 'device_cb()' - Device callback.
*/
-static int /* O - 0 on success, 1 on failure */
-show_devices(http_t *http, /* I - HTTP connection to server */
- int long_status) /* I - Long status report? */
+static void
+device_cb(
+ const char *device_class, /* I - device-class string */
+ const char *device_id, /* I - device-id string */
+ const char *device_info, /* I - device-info string */
+ const char *device_make_and_model, /* I - device-make-and-model string */
+ const char *device_uri, /* I - device-uri string */
+ void *user_data) /* I - User data */
{
- ipp_t *request, /* IPP Request */
- *response; /* IPP Response */
- ipp_attribute_t *attr; /* Current attribute */
- const char *device_class, /* Pointer to device-class */
- *device_id, /* Pointer to device-id */
- *device_info, /* Pointer to device-info */
- *device_make, /* Pointer to device-make-and-model */
- *device_uri; /* Pointer to device-uri */
-
+ int *long_status; /* Show verbose info? */
- if (http == NULL)
- return (1);
/*
- * Build a CUPS_GET_DEVICES request, which requires the following
- * attributes:
- *
- * attributes-charset
- * attributes-natural-language
+ * Display the device...
*/
- request = ippNewRequest(CUPS_GET_DEVICES);
-
- /*
- * Do the request and get back a response...
- */
+ long_status = (int *)user_data;
- if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ if (*long_status)
{
- /*
- * Loop through the device list and display them...
- */
-
- if (response->request.status.status_code > IPP_OK_CONFLICT)
- {
- _cupsLangPrintf(stderr, "lpinfo: %s\n", cupsLastErrorString());
- ippDelete(response);
- return (1);
- }
-
- for (attr = response->attrs; attr != NULL; attr = attr->next)
- {
- /*
- * Skip leading attributes until we hit a device...
- */
-
- while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
- attr = attr->next;
-
- if (attr == NULL)
- break;
-
- /*
- * Pull the needed attributes from this device...
- */
-
- device_class = NULL;
- device_info = NULL;
- device_make = NULL;
- device_uri = NULL;
- device_id = "NONE";
-
- while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
- {
- if (!strcmp(attr->name, "device-class") &&
- attr->value_tag == IPP_TAG_KEYWORD)
- device_class = attr->values[0].string.text;
- else if (!strcmp(attr->name, "device-info") &&
- attr->value_tag == IPP_TAG_TEXT)
- device_info = attr->values[0].string.text;
- else if (!strcmp(attr->name, "device-make-and-model") &&
- attr->value_tag == IPP_TAG_TEXT)
- device_make = attr->values[0].string.text;
- else if (!strcmp(attr->name, "device-uri") &&
- attr->value_tag == IPP_TAG_URI)
- device_uri = attr->values[0].string.text;
- else if (!strcmp(attr->name, "device-id") &&
- attr->value_tag == IPP_TAG_TEXT)
- device_id = attr->values[0].string.text;
-
- attr = attr->next;
- }
-
- /*
- * See if we have everything needed...
- */
-
- if (device_class == NULL || device_info == NULL ||
- device_make == NULL || device_uri == NULL)
- {
- if (attr == NULL)
- break;
- else
- continue;
- }
-
- /*
- * Display the device...
- */
+ _cupsLangPrintf(stdout,
+ _("Device: uri = %s\n"
+ " class = %s\n"
+ " info = %s\n"
+ " make-and-model = %s\n"
+ " device-id = %s\n"),
+ device_uri, device_class, device_info,
+ device_make_and_model, device_id);
+ }
+ else
+ _cupsLangPrintf(stdout, "%s %s\n", device_class, device_uri);
+}
- if (long_status)
- {
- _cupsLangPrintf(stdout,
- _("Device: uri = %s\n"
- " class = %s\n"
- " info = %s\n"
- " make-and-model = %s\n"
- " device-id = %s\n"),
- device_uri, device_class, device_info, device_make,
- device_id);
- }
- else
- _cupsLangPrintf(stdout, "%s %s\n", device_class, device_uri);
- if (attr == NULL)
- break;
- }
+/*
+ * 'show_devices()' - Show available devices.
+ */
- ippDelete(response);
- }
- else
+static int /* O - 0 on success, 1 on failure */
+show_devices(http_t *http, /* I - HTTP connection to server */
+ int long_status) /* I - Long status report? */
+{
+ if (cupsGetDevices(http, CUPS_TIMEOUT_DEFAULT, CUPS_EXCLUDE_NONE, device_cb,
+ &long_status) != IPP_OK)
{
_cupsLangPrintf(stderr, "lpinfo: %s\n", cupsLastErrorString());
return (1);
--
2.39.5