/*
- * "$Id: cups-deviced.c 5194 2006-02-27 20:57:07Z mike $"
+ * "$Id$"
*
- * Device scanning mini-daemon for the Common UNIX Printing System (CUPS).
+ * Device scanning mini-daemon for CUPS.
*
+ * Copyright 2007-2011 by Apple Inc.
* Copyright 1997-2006 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
- * property of Easy Software Products and are protected by Federal
- * copyright law. Distribution and use rights are outlined in the file
- * "LICENSE.txt" which should have been included with this file. If this
- * file is missing or damaged please contact Easy Software Products
- * at:
- *
- * Attn: CUPS Licensing Information
- * Easy Software Products
- * 44141 Airport View Drive, Suite 204
- * Hollywood, Maryland 20636 USA
- *
- * Voice: (301) 373-9600
- * EMail: cups-info@cups.org
- * WWW: http://www.cups.org
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file. If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
*
* 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.
- * 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.
+ * 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.
*/
/*
#include "util.h"
#include <cups/array.h>
#include <cups/dir.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <poll.h>
+
+
+/*
+ * Constants...
+ */
+
+#define MAX_BACKENDS 200 /* Maximum number of backends we'll run */
+
+
+/*
+ * Backend information...
+ */
-#ifdef __hpux
-# define seteuid(uid) setresuid(-1, (uid), -1)
-#endif /* __hpux */
+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;
/*
typedef struct
{
char device_class[128], /* Device class */
- device_make_and_model[128], /* Make and model, if known */
device_info[128], /* Device info/description */
- device_uri[1024], /* Device URI */
- device_id[1024]; /* 1284 Device ID */
-} dev_info_t;
+ device_uri[1024]; /* Device URI */
+} 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? */
+ send_location; /* Send device-location 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 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,
+ const char *device_location);
+static int compare_devices(cupsd_device_t *p0,
+ cupsd_device_t *p1);
+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);
/*
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 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 */
+ *include; /* include-schemes values */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
struct sigaction action; /* Actions for POSIX signals */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
* 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]);
+ device_limit = atoi(argv[2]);
+ if (device_limit < 0)
+ {
+ fprintf(stderr, "ERROR: [cups-deviced] Bad limit %d!\n", device_limit);
+
+ return (1);
+ }
+
+ timeout = atoi(argv[3]);
+ if (timeout < 1)
+ {
+ fprintf(stderr, "ERROR: [cups-deviced] Bad timeout %d!\n", timeout);
+
+ return (1);
+ }
+
+ normal_user = atoi(argv[4]);
if (normal_user <= 0)
{
- fprintf(stderr, "cups-deviced: Bad user %d!\n", normal_user);
+ fprintf(stderr, "ERROR: [cups-deviced] Bad user %d!\n", normal_user);
return (1);
}
- num_options = cupsParseOptions(argv[4], 0, &options);
- requested = cupsGetOption("requested-attributes", num_options, options);
+ num_options = cupsParseOptions(argv[5], 0, &options);
+ requested = cupsdCreateStringsArray(cupsGetOption("requested-attributes",
+ num_options, options));
+ exclude = cupsdCreateStringsArray(cupsGetOption("exclude-schemes",
+ num_options, options));
+ include = cupsdCreateStringsArray(cupsGetOption("include-schemes",
+ num_options, options));
- if (!requested || strstr(requested, "all"))
+ if (!requested || cupsArrayFind(requested, "all") != NULL)
{
- send_class = 1;
- send_info = 1;
- send_make_and_model = 1;
- send_uri = 1;
- send_id = 1;
+ send_class = send_info = send_make_and_model = send_uri = send_id =
+ send_location = 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;
+ send_location = cupsArrayFind(requested, "device-location") != 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...
*/
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);
}
* 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...
*/
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...
+ * Skip excluded or not included backends...
*/
- if (!getuid())
- {
- /*
- * Backends without permissions for normal users run as root,
- * all others run as the unprivileged user...
- */
-
- if (!(dent->fileinfo.st_mode & (S_IRWXG | S_IRWXO)))
- seteuid(0);
- else
- seteuid(normal_user);
- }
+ if (cupsArrayFind(exclude, dent->filename) ||
+ (include && !cupsArrayFind(include, dent->filename)))
+ continue;
/*
- * Run the backend with no arguments and collect the output...
+ * Backends without permissions for normal users run as root,
+ * all others run as the unprivileged user...
*/
- snprintf(filename, sizeof(filename), "%s/%s", backends, dent->filename);
- if ((fp = popen(filename, "r")) != NULL)
- {
- /*
- * 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);
- 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);
-
- pclose(fp);
-
- /*
- * 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);
/*
- * Switch back to root as needed...
+ * Collect devices...
*/
- if (!getuid() && geteuid())
- seteuid(0);
-
- /*
- * Output the list of 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);
+ end_time = get_current_time() + timeout;
- if (count > cupsArrayCount(devs))
- count = cupsArrayCount(devs);
-
- 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...
*/
- 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);
+ 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)
+ {
+ cups_file_t *bpipe = backends[i].pipe;
+ /* Copy of pipe for backend... */
+
+ do
+ {
+ if (get_device(backends + i))
+ {
+ backend_fds[i].fd = 0;
+ backend_fds[i].events = 0;
+ break;
+ }
+ }
+ while (bpipe->ptr &&
+ memchr(bpipe->ptr, '\n', bpipe->end - bpipe->ptr));
+ }
+ }
+
+ /*
+ * Get exit status from children...
+ */
+
+ 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 */
+ const char *device_id, /* I - 1284 device ID */
+ const char *device_location) /* I - Physical location */
{
- dev_info_t *dev; /* New device */
+ cupsd_device_t *device; /* New 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_info, device_info, sizeof(device->device_info));
+ strlcpy(device->device_uri, device_uri, sizeof(device->device_uri));
/*
* Add the device to the array and return...
*/
- cupsArrayAdd(devs, dev);
+ if (cupsArrayFind(devices, device))
+ {
+ /*
+ * Avoid duplicates!
+ */
- return (dev);
+ free(device);
+ }
+ else
+ {
+ 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_class);
+ if (send_info)
+ cupsdSendIPPString(IPP_TAG_TEXT, "device-info", device_info);
+ if (send_make_and_model)
+ cupsdSendIPPString(IPP_TAG_TEXT, "device-make-and-model",
+ device_make_and_model);
+ if (send_uri)
+ cupsdSendIPPString(IPP_TAG_URI, "device-uri", device_uri);
+ if (send_id)
+ cupsdSendIPPString(IPP_TAG_TEXT, "device-id",
+ device_id ? device_id : "");
+ if (send_location)
+ cupsdSendIPPString(IPP_TAG_TEXT, "device-location",
+ device_location ? device_location : "");
+
+ 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 */
if ((diff = cupsdCompareNames(d0->device_info, d1->device_info)) != 0)
return (diff);
- else if ((diff = strcasecmp(d0->device_class, d1->device_class)) != 0)
+ else if ((diff = _cups_strcasecmp(d0->device_class, d1->device_class)) != 0)
return (diff);
else
- return (strcasecmp(d0->device_uri, d1->device_uri));
+ return (_cups_strcasecmp(d0->device_uri, d1->device_uri));
+}
+
+
+/*
+ * '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 */
+ temp[2048], /* Copy of line */
+ *ptr, /* Pointer into line */
+ *dclass, /* Device class */
+ *uri, /* Device URI */
+ *make_model, /* Make and model */
+ *info, /* Device info */
+ *device_id, /* 1284 device ID */
+ *location; /* Physical location */
+
+
+ if (cupsFileGets(backend->pipe, line, sizeof(line)))
+ {
+ /*
+ * Each line is of the form:
+ *
+ * class URI "make model" "name" ["1284 device ID"] ["location"]
+ */
+
+ strlcpy(temp, line, sizeof(temp));
+
+ /*
+ * device-class
+ */
+
+ dclass = temp;
+
+ for (ptr = temp; *ptr; ptr ++)
+ if (isspace(*ptr & 255))
+ break;
+
+ while (isspace(*ptr & 255))
+ *ptr++ = '\0';
+
+ /*
+ * device-uri
+ */
+
+ if (!*ptr)
+ goto error;
+
+ for (uri = ptr; *ptr; ptr ++)
+ if (isspace(*ptr & 255))
+ break;
+
+ while (isspace(*ptr & 255))
+ *ptr++ = '\0';
+
+ /*
+ * device-make-and-model
+ */
+
+ if (*ptr != '\"')
+ goto error;
+
+ for (ptr ++, make_model = ptr; *ptr && *ptr != '\"'; ptr ++)
+ {
+ if (*ptr == '\\' && ptr[1])
+ _cups_strcpy(ptr, ptr + 1);
+ }
+
+ if (*ptr != '\"')
+ goto error;
+
+ for (*ptr++ = '\0'; isspace(*ptr & 255); *ptr++ = '\0');
+
+ /*
+ * device-info
+ */
+
+ if (*ptr != '\"')
+ goto error;
+
+ for (ptr ++, info = ptr; *ptr && *ptr != '\"'; ptr ++)
+ {
+ if (*ptr == '\\' && ptr[1])
+ _cups_strcpy(ptr, ptr + 1);
+ }
+
+ if (*ptr != '\"')
+ goto error;
+
+ for (*ptr++ = '\0'; isspace(*ptr & 255); *ptr++ = '\0');
+
+ /*
+ * device-id
+ */
+
+ if (*ptr == '\"')
+ {
+ for (ptr ++, device_id = ptr; *ptr && *ptr != '\"'; ptr ++)
+ {
+ if (*ptr == '\\' && ptr[1])
+ _cups_strcpy(ptr, ptr + 1);
+ }
+
+ if (*ptr != '\"')
+ goto error;
+
+ for (*ptr++ = '\0'; isspace(*ptr & 255); *ptr++ = '\0');
+
+ /*
+ * device-location
+ */
+
+ if (*ptr == '\"')
+ {
+ for (ptr ++, location = ptr; *ptr && *ptr != '\"'; ptr ++)
+ {
+ if (*ptr == '\\' && ptr[1])
+ _cups_strcpy(ptr, ptr + 1);
+ }
+
+ if (*ptr != '\"')
+ goto error;
+
+ *ptr = '\0';
+ }
+ else
+ location = NULL;
+ }
+ else
+ {
+ device_id = NULL;
+ location = NULL;
+ }
+
+ /*
+ * Add the device to the array of available devices...
+ */
+
+ if (!add_device(dclass, make_model, info, uri, device_id, location))
+ fprintf(stderr, "DEBUG: [cups-deviced] Found device \"%s\"...\n", uri);
+
+ return (0);
+ }
+
+ /*
+ * End of file...
+ */
+
+ cupsFileClose(backend->pipe);
+ backend->pipe = NULL;
+
+ return (-1);
+
+ /*
+ * Bad format; strip trailing newline and write an error message.
+ */
+
+ error:
+
+ 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);
+ return (0);
}
/*
- * 'sigalrm_handler()' - Handle alarm signals for backends that get hung
- * trying to list the available devices...
+ * 'process_children()' - Process all dead children...
*/
static void
-sigalrm_handler(int sig) /* I - Signal number */
+process_children(void)
{
- (void)sig; /* remove compiler warnings... */
+ 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...
+ */
- alarm_tripped = 1;
+ 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 */
+ cupsd_backend_t *backend; /* Current backend */
+ char *argv[2]; /* Command-line arguments */
+
+
+ if (num_backends >= MAX_BACKENDS)
+ {
+ fprintf(stderr, "ERROR: Too many backends (%d)!\n", num_backends);
+ return (-1);
+ }
+
+ if ((server_bin = getenv("CUPS_SERVERBIN")) == NULL)
+ server_bin = CUPS_SERVERBIN;
+
+ snprintf(program, sizeof(program), "%s/backend/%s", server_bin, name);
+
+ if (_cupsFileCheck(program, _CUPS_FILE_CHECK_PROGRAM, !geteuid(),
+ _cupsFileCheckFilter, NULL))
+ return (-1);
+
+ backend = backends + num_backends;
+
+ argv[0] = (char *)name;
+ argv[1] = NULL;
+
+ if ((backend->pipe = cupsdPipeCommand(&(backend->pid), program, argv,
+ root ? 0 : normal_user)) == NULL)
+ {
+ fprintf(stderr, "ERROR: [cups-deviced] Unable to execute \"%s\" - %s\n",
+ program, strerror(errno));
+ return (-1);
+ }
+
+ /*
+ * Fill in the rest of the backend information...
+ */
+
+ fprintf(stderr, "DEBUG: [cups-deviced] Started backend %s (PID %d)\n",
+ program, backend->pid);
+
+ backend_fds[num_backends].fd = cupsFileNumber(backend->pipe);
+ backend_fds[num_backends].events = POLLIN;
+
+ backend->name = strdup(name);
+ backend->status = 0;
+ backend->count = 0;
+
+ active_backends ++;
+ num_backends ++;
+
+ return (0);
}
/*
- * End of "$Id: cups-deviced.c 5194 2006-02-27 20:57:07Z mike $".
+ * End of "$Id$".
*/