]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/cups-deviced.c
Merge changes from CUPS 1.4svn-r8148.
[thirdparty/cups.git] / scheduler / cups-deviced.c
CommitLineData
ef416fc2 1/*
b19ccc9e 2 * "$Id: cups-deviced.c 7816 2008-07-30 20:53:31Z mike $"
ef416fc2 3 *
4 * Device scanning mini-daemon for the Common UNIX Printing System (CUPS).
5 *
91c84a35 6 * Copyright 2007-2008 by Apple Inc.
bd7854cb 7 * Copyright 1997-2006 by Easy Software Products.
ef416fc2 8 *
9 * These coded instructions, statements, and computer programs are the
bc44d920 10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 14 *
15 * Contents:
16 *
ae71f5de
MS
17 * main() - Scan for devices and return an IPP response.
18 * add_device() - Add a new device to the list.
19 * compare_devices() - Compare device names to eliminate duplicates.
20 * create_strings_array() - Create a CUPS array of strings.
21 * get_current_time() - Get the current time as a double value in seconds.
22 * get_device() - Get a device from a backend.
23 * process_children() - Process all dead children...
24 * sigchld_handler() - Handle 'child' signals from old processes.
25 * start_backend() - Run a backend to gather the available devices.
ef416fc2 26 */
27
28/*
29 * Include necessary headers...
30 */
31
32#include "util.h"
33#include <cups/array.h>
34#include <cups/dir.h>
cc0d019f 35#include <fcntl.h>
ae71f5de
MS
36#include <sys/wait.h>
37#include <poll.h>
38
39
40/*
41 * Constants...
42 */
43
44#define MAX_BACKENDS 200 /* Maximum number of backends we'll run */
45
46
47/*
48 * Backend information...
49 */
50
51typedef struct
52{
53 char *name; /* Name of backend */
54 int pid, /* Process ID */
55 status; /* Exit status */
56 cups_file_t *pipe; /* Pipe from backend stdout */
57 int count; /* Number of devices found */
58} cupsd_backend_t;
b423cd4c 59
ef416fc2 60
61/*
62 * Device information structure...
63 */
64
65typedef struct
66{
67 char device_class[128], /* Device class */
ef416fc2 68 device_info[128], /* Device info/description */
749b1e90 69 device_uri[1024]; /* Device URI */
ae71f5de 70} cupsd_device_t;
ef416fc2 71
72
73/*
74 * Local globals...
75 */
76
ae71f5de
MS
77static int num_backends = 0,
78 /* Total backends */
79 active_backends = 0;
80 /* Active backends */
81static cupsd_backend_t backends[MAX_BACKENDS];
82 /* Array of backends */
83static struct pollfd backend_fds[MAX_BACKENDS];
84 /* Array for poll() */
85static cups_array_t *devices; /* Array of devices */
e00b005a 86static int normal_user; /* Normal user ID */
ae71f5de
MS
87static int device_limit; /* Maximum number of devices */
88static int send_class, /* Send device-class attribute? */
89 send_info, /* Send device-info attribute? */
90 send_make_and_model,
91 /* Send device-make-and-model attribute? */
92 send_uri, /* Send device-uri attribute? */
749b1e90
MS
93 send_id, /* Send device-id attribute? */
94 send_location; /* Send device-location attribute? */
ae71f5de
MS
95static int dead_children = 0;
96 /* Dead children? */
ef416fc2 97
98
99/*
100 * Local functions...
101 */
102
ae71f5de
MS
103static int add_device(const char *device_class,
104 const char *device_make_and_model,
105 const char *device_info,
106 const char *device_uri,
749b1e90
MS
107 const char *device_id,
108 const char *device_location);
ae71f5de
MS
109static int compare_devices(cupsd_device_t *p0,
110 cupsd_device_t *p1);
111static cups_array_t *create_strings_array(const char *s);
112static double get_current_time(void);
113static int get_device(cupsd_backend_t *backend);
114static void process_children(void);
115static void sigchld_handler(int sig);
116static int start_backend(const char *backend, int root);
ef416fc2 117
118
119/*
120 * 'main()' - Scan for devices and return an IPP response.
121 *
122 * Usage:
123 *
124 * cups-deviced request_id limit options
125 */
126
127int /* O - Exit code */
128main(int argc, /* I - Number of command-line args */
129 char *argv[]) /* I - Command-line arguments */
130{
ae71f5de 131 int i; /* Looping var */
e00b005a 132 int request_id; /* Request ID */
ae71f5de
MS
133 int timeout; /* Timeout in seconds */
134 const char *server_bin; /* CUPS_SERVERBIN environment variable */
135 char filename[1024]; /* Backend directory filename */
ef416fc2 136 cups_dir_t *dir; /* Directory pointer */
137 cups_dentry_t *dent; /* Directory entry */
ae71f5de
MS
138 double current_time, /* Current time */
139 end_time; /* Ending time */
ef416fc2 140 int num_options; /* Number of options */
141 cups_option_t *options; /* Options */
ae71f5de
MS
142 cups_array_t *requested, /* requested-attributes values */
143 *exclude; /* exclude-schemes values */
ef416fc2 144#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
145 struct sigaction action; /* Actions for POSIX signals */
146#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
147
148
e00b005a 149 setbuf(stderr, NULL);
150
ef416fc2 151 /*
152 * Check the command-line...
153 */
154
ae71f5de 155 if (argc != 6)
e00b005a 156 {
ae71f5de 157 fputs("Usage: cups-deviced request-id limit timeout user-id options\n", stderr);
e00b005a 158
e00b005a 159 return (1);
160 }
161
ae71f5de 162 request_id = atoi(argv[1]);
e00b005a 163 if (request_id < 1)
ef416fc2 164 {
ae71f5de 165 fprintf(stderr, "ERROR: [cups-deviced] Bad request ID %d!\n", request_id);
e00b005a 166
ef416fc2 167 return (1);
168 }
169
ae71f5de
MS
170 device_limit = atoi(argv[2]);
171 if (device_limit < 0)
e00b005a 172 {
ae71f5de 173 fprintf(stderr, "ERROR: [cups-deviced] Bad limit %d!\n", device_limit);
e00b005a 174
e00b005a 175 return (1);
176 }
177
ae71f5de
MS
178 timeout = atoi(argv[3]);
179 if (timeout < 1)
180 {
181 fprintf(stderr, "ERROR: [cups-deviced] Bad timeout %d!\n", timeout);
182
183 return (1);
184 }
ef416fc2 185
ae71f5de
MS
186 normal_user = atoi(argv[4]);
187 if (normal_user <= 0)
ef416fc2 188 {
ae71f5de
MS
189 fprintf(stderr, "ERROR: [cups-deviced] Bad user %d!\n", normal_user);
190
191 return (1);
ef416fc2 192 }
ae71f5de
MS
193
194 num_options = cupsParseOptions(argv[5], 0, &options);
195 requested = create_strings_array(cupsGetOption("requested-attributes",
196 num_options, options));
197 exclude = create_strings_array(cupsGetOption("exclude-schemes",
198 num_options, options));
199
200 if (!requested || cupsArrayFind(requested, "all") != NULL)
749b1e90
MS
201 {
202 send_class = send_info = send_make_and_model = send_uri = send_id =
203 send_location = 1;
204 }
ef416fc2 205 else
206 {
ae71f5de
MS
207 send_class = cupsArrayFind(requested, "device-class") != NULL;
208 send_info = cupsArrayFind(requested, "device-info") != NULL;
209 send_make_and_model = cupsArrayFind(requested, "device-make-and-model") != NULL;
210 send_uri = cupsArrayFind(requested, "device-uri") != NULL;
211 send_id = cupsArrayFind(requested, "device-id") != NULL;
749b1e90 212 send_location = cupsArrayFind(requested, "device-location") != NULL;
ef416fc2 213 }
214
ae71f5de
MS
215 /*
216 * Listen to child signals...
217 */
218
219#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
220 sigset(SIGCHLD, sigchld_handler);
221#elif defined(HAVE_SIGACTION)
222 memset(&action, 0, sizeof(action));
223
224 sigemptyset(&action.sa_mask);
225 sigaddset(&action.sa_mask, SIGCHLD);
226 action.sa_handler = sigchld_handler;
227 sigaction(SIGCHLD, &action, NULL);
228#else
229 signal(SIGCLD, sigchld_handler); /* No, SIGCLD isn't a typo... */
230#endif /* HAVE_SIGSET */
231
ef416fc2 232 /*
233 * Try opening the backend directory...
234 */
235
236 if ((server_bin = getenv("CUPS_SERVERBIN")) == NULL)
237 server_bin = CUPS_SERVERBIN;
238
ae71f5de 239 snprintf(filename, sizeof(filename), "%s/backend", server_bin);
ef416fc2 240
ae71f5de 241 if ((dir = cupsDirOpen(filename)) == NULL)
ef416fc2 242 {
e00b005a 243 fprintf(stderr, "ERROR: [cups-deviced] Unable to open backend directory "
ae71f5de 244 "\"%s\": %s", filename, strerror(errno));
e00b005a 245
ef416fc2 246 return (1);
247 }
248
249 /*
250 * Setup the devices array...
251 */
252
ae71f5de 253 devices = cupsArrayNew((cups_array_func_t)compare_devices, NULL);
ef416fc2 254
255 /*
256 * Loop through all of the device backends...
257 */
258
259 while ((dent = cupsDirRead(dir)) != NULL)
260 {
e00b005a 261 /*
262 * Skip entries that are not executable files...
263 */
264
265 if (!S_ISREG(dent->fileinfo.st_mode) ||
ae71f5de 266 !isalnum(dent->filename[0] & 255) ||
e00b005a 267 (dent->fileinfo.st_mode & (S_IRUSR | S_IXUSR)) != (S_IRUSR | S_IXUSR))
268 continue;
269
ae71f5de
MS
270 if (cupsArrayFind(exclude, dent->filename))
271 continue;
e00b005a 272
cc0d019f
MS
273 /*
274 * Backends without permissions for normal users run as root,
275 * all others run as the unprivileged user...
276 */
277
ae71f5de
MS
278 start_backend(dent->filename,
279 !(dent->fileinfo.st_mode & (S_IRWXG | S_IRWXO)));
ef416fc2 280 }
281
282 cupsDirClose(dir);
283
284 /*
ae71f5de 285 * Collect devices...
ef416fc2 286 */
287
ae71f5de
MS
288 if (getenv("SOFTWARE"))
289 puts("Content-Type: application/ipp\n");
ef416fc2 290
e00b005a 291 cupsdSendIPPHeader(IPP_OK, request_id);
ef416fc2 292 cupsdSendIPPGroup(IPP_TAG_OPERATION);
293 cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
294 cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", "en-US");
295
ae71f5de 296 end_time = get_current_time() + timeout;
ef416fc2 297
ae71f5de 298 while (active_backends > 0 && (current_time = get_current_time()) < end_time)
ef416fc2 299 {
300 /*
ae71f5de
MS
301 * Collect the output from the backends...
302 */
303
304 timeout = (int)(1000 * (end_time - current_time));
305
306 if (poll(backend_fds, num_backends, timeout) > 0)
307 {
308 for (i = 0; i < num_backends; i ++)
309 if (backend_fds[i].revents && backends[i].pipe)
310 if (get_device(backends + i))
311 {
312 backend_fds[i].fd = 0;
313 backend_fds[i].events = 0;
314 }
315 }
316
317 /*
318 * Get exit status from children...
ef416fc2 319 */
320
ae71f5de
MS
321 if (dead_children)
322 process_children();
ef416fc2 323 }
324
325 cupsdSendIPPTrailer();
326
327 /*
ae71f5de 328 * Terminate any remaining backends and exit...
ef416fc2 329 */
330
ae71f5de
MS
331 if (active_backends > 0)
332 {
333 for (i = 0; i < num_backends; i ++)
334 if (backends[i].pid)
335 kill(backends[i].pid, SIGTERM);
336 }
ef416fc2 337
338 return (0);
339}
340
341
342/*
ae71f5de 343 * 'add_device()' - Add a new device to the list.
ef416fc2 344 */
345
ae71f5de
MS
346static int /* O - 0 on success, -1 on error */
347add_device(
ef416fc2 348 const char *device_class, /* I - Device class */
349 const char *device_make_and_model, /* I - Device make and model */
350 const char *device_info, /* I - Device information */
351 const char *device_uri, /* I - Device URI */
749b1e90
MS
352 const char *device_id, /* I - 1284 device ID */
353 const char *device_location) /* I - Physical location */
ef416fc2 354{
1f0275e3 355 cupsd_device_t *device; /* New device */
ef416fc2 356
357
358 /*
359 * Allocate memory for the device record...
360 */
361
ae71f5de 362 if ((device = calloc(1, sizeof(cupsd_device_t))) == NULL)
ef416fc2 363 {
364 fputs("ERROR: [cups-deviced] Ran out of memory allocating a device!\n",
365 stderr);
ae71f5de 366 return (-1);
ef416fc2 367 }
368
369 /*
370 * Copy the strings over...
371 */
372
ae71f5de 373 strlcpy(device->device_class, device_class, sizeof(device->device_class));
ae71f5de
MS
374 strlcpy(device->device_info, device_info, sizeof(device->device_info));
375 strlcpy(device->device_uri, device_uri, sizeof(device->device_uri));
ef416fc2 376
377 /*
378 * Add the device to the array and return...
379 */
380
1f0275e3 381 if (cupsArrayFind(devices, device))
2e4ff8af
MS
382 {
383 /*
384 * Avoid duplicates!
385 */
ef416fc2 386
ae71f5de 387 free(device);
2e4ff8af
MS
388 }
389 else
ae71f5de
MS
390 {
391 cupsArrayAdd(devices, device);
392
393 if (device_limit <= 0 || cupsArrayCount(devices) < device_limit)
394 {
395 /*
396 * Send device info...
397 */
398
399 cupsdSendIPPGroup(IPP_TAG_PRINTER);
400 if (send_class)
401 cupsdSendIPPString(IPP_TAG_KEYWORD, "device-class",
749b1e90 402 device_class);
ae71f5de 403 if (send_info)
749b1e90 404 cupsdSendIPPString(IPP_TAG_TEXT, "device-info", device_info);
ae71f5de
MS
405 if (send_make_and_model)
406 cupsdSendIPPString(IPP_TAG_TEXT, "device-make-and-model",
749b1e90 407 device_make_and_model);
ae71f5de 408 if (send_uri)
749b1e90 409 cupsdSendIPPString(IPP_TAG_URI, "device-uri", device_uri);
ae71f5de 410 if (send_id)
749b1e90
MS
411 cupsdSendIPPString(IPP_TAG_TEXT, "device-id",
412 device_id ? device_id : "");
413 if (send_location)
414 cupsdSendIPPString(IPP_TAG_TEXT, "device-location",
415 device_location ? device_location : "");
ae71f5de
MS
416
417 fflush(stdout);
418 fputs("DEBUG: Flushed attributes...\n", stderr);
419 }
420 }
421
422 return (0);
ef416fc2 423}
424
425
426/*
ae71f5de 427 * 'compare_devices()' - Compare device names to eliminate duplicates.
ef416fc2 428 */
429
430static int /* O - Result of comparison */
ae71f5de
MS
431compare_devices(cupsd_device_t *d0, /* I - First device */
432 cupsd_device_t *d1) /* I - Second device */
ef416fc2 433{
434 int diff; /* Difference between strings */
435
436
437 /*
438 * Sort devices by device-info, device-class, and device-uri...
439 */
440
441 if ((diff = cupsdCompareNames(d0->device_info, d1->device_info)) != 0)
442 return (diff);
443 else if ((diff = strcasecmp(d0->device_class, d1->device_class)) != 0)
444 return (diff);
445 else
446 return (strcasecmp(d0->device_uri, d1->device_uri));
447}
448
449
cc0d019f 450/*
ae71f5de 451 * 'create_strings_array()' - Create a CUPS array of strings.
cc0d019f
MS
452 */
453
ae71f5de
MS
454static cups_array_t * /* O - CUPS array */
455create_strings_array(const char *s) /* I - Comma-delimited strings */
cc0d019f 456{
ae71f5de
MS
457 cups_array_t *a; /* CUPS array */
458 const char *start, /* Start of string */
459 *end; /* End of string */
460 char *ptr; /* New string */
461
462
463 if (!s)
464 return (NULL);
465
466 if ((a = cupsArrayNew((cups_array_func_t)strcmp, NULL)) != NULL)
467 {
468 for (start = end = s; *end; start = end + 1)
469 {
470 /*
471 * Find the end of the current delimited string...
472 */
473
474 if ((end = strchr(start, ',')) == NULL)
475 end = start + strlen(start);
476
477 /*
478 * Duplicate the string and add it to the array...
479 */
480
481 if ((ptr = calloc(1, end - start + 1)) == NULL)
482 break;
cc0d019f 483
ae71f5de
MS
484 memcpy(ptr, start, end - start);
485 cupsArrayAdd(a, ptr);
486 }
487 }
488
489 return (a);
490}
491
492
493/*
494 * 'get_current_time()' - Get the current time as a double value in seconds.
495 */
496
497static double /* O - Time in seconds */
498get_current_time(void)
499{
500 struct timeval curtime; /* Current time */
501
502
503 gettimeofday(&curtime, NULL);
504
505 return (curtime.tv_sec + 0.000001 * curtime.tv_usec);
506}
507
508
509/*
510 * 'get_device()' - Get a device from a backend.
511 */
512
513static int /* O - 0 on success, -1 on error */
514get_device(cupsd_backend_t *backend) /* I - Backend to read from */
515{
516 char line[2048], /* Line from backend */
749b1e90
MS
517 temp[2048], /* Copy of line */
518 *ptr, /* Pointer into line */
519 *dclass, /* Device class */
520 *uri, /* Device URI */
521 *make_model, /* Make and model */
522 *info, /* Device info */
523 *device_id, /* 1284 device ID */
524 *location; /* Physical location */
ae71f5de
MS
525
526
527 if (cupsFileGets(backend->pipe, line, sizeof(line)))
528 {
529 /*
530 * Each line is of the form:
531 *
749b1e90
MS
532 * class URI "make model" "name" ["1284 device ID"] ["location"]
533 */
534
535 strlcpy(temp, line, sizeof(temp));
536
537 /*
538 * device-class
539 */
540
541 dclass = temp;
542
543 for (ptr = temp; *ptr; ptr ++)
544 if (isspace(*ptr & 255))
545 break;
546
547 while (isspace(*ptr & 255))
548 *ptr++ = '\0';
549
550 /*
551 * device-uri
ae71f5de
MS
552 */
553
749b1e90
MS
554 if (!*ptr)
555 goto error;
ae71f5de 556
749b1e90
MS
557 for (uri = ptr; *ptr; ptr ++)
558 if (isspace(*ptr & 255))
559 break;
560
561 while (isspace(*ptr & 255))
562 *ptr++ = '\0';
563
564 /*
565 * device-make-and-model
566 */
567
568 if (*ptr != '\"')
569 goto error;
570
571 for (ptr ++, make_model = ptr; *ptr && *ptr != '\"'; ptr ++)
ae71f5de 572 {
749b1e90
MS
573 if (*ptr == '\\' && ptr[1])
574 _cups_strcpy(ptr, ptr + 1);
575 }
576
577 if (*ptr != '\"')
578 goto error;
ae71f5de 579
749b1e90
MS
580 for (*ptr++ = '\0'; isspace(*ptr & 255); *ptr++ = '\0');
581
582 /*
583 * device-info
584 */
ae71f5de 585
749b1e90
MS
586 if (*ptr != '\"')
587 goto error;
588
589 for (ptr ++, info = ptr; *ptr && *ptr != '\"'; ptr ++)
590 {
591 if (*ptr == '\\' && ptr[1])
592 _cups_strcpy(ptr, ptr + 1);
ae71f5de 593 }
749b1e90
MS
594
595 if (*ptr != '\"')
596 goto error;
597
598 for (*ptr++ = '\0'; isspace(*ptr & 255); *ptr++ = '\0');
599
600 /*
601 * device-id
602 */
603
604 if (*ptr == '\"')
ae71f5de 605 {
749b1e90
MS
606 for (ptr ++, device_id = ptr; *ptr && *ptr != '\"'; ptr ++)
607 {
608 if (*ptr == '\\' && ptr[1])
609 _cups_strcpy(ptr, ptr + 1);
610 }
611
612 if (*ptr != '\"')
613 goto error;
614
615 for (*ptr++ = '\0'; isspace(*ptr & 255); *ptr++ = '\0');
616
ae71f5de 617 /*
749b1e90 618 * device-location
ae71f5de
MS
619 */
620
749b1e90
MS
621 if (*ptr == '\"')
622 {
623 for (ptr ++, location = ptr; *ptr && *ptr != '\"'; ptr ++)
624 {
625 if (*ptr == '\\' && ptr[1])
626 _cups_strcpy(ptr, ptr + 1);
627 }
628
629 if (*ptr != '\"')
630 goto error;
631
632 *ptr = '\0';
633 }
634 else
635 location = NULL;
636 }
637 else
638 {
639 device_id = NULL;
640 location = NULL;
ae71f5de
MS
641 }
642
749b1e90
MS
643 /*
644 * Add the device to the array of available devices...
645 */
646
647 if (!add_device(dclass, make_model, info, uri, device_id, location))
648 fprintf(stderr, "DEBUG: [cups-deviced] Found device \"%s\"...\n", uri);
649
ae71f5de
MS
650 return (0);
651 }
652
653 /*
654 * End of file...
655 */
656
657 cupsFileClose(backend->pipe);
658 backend->pipe = NULL;
659
660 return (-1);
749b1e90
MS
661
662 /*
663 * Bad format; strip trailing newline and write an error message.
664 */
665
666 error:
667
668 if (line[strlen(line) - 1] == '\n')
669 line[strlen(line) - 1] = '\0';
670
671 fprintf(stderr, "ERROR: [cups-deviced] Bad line from \"%s\": %s\n",
672 backend->name, line);
673 return (0);
ae71f5de
MS
674}
675
676
677/*
678 * 'process_children()' - Process all dead children...
679 */
680
681static void
682process_children(void)
683{
684 int i; /* Looping var */
685 int status; /* Exit status of child */
686 int pid; /* Process ID of child */
687 cupsd_backend_t *backend; /* Current backend */
688 const char *name; /* Name of process */
689
690
691 /*
692 * Reset the dead_children flag...
693 */
694
695 dead_children = 0;
696
697 /*
698 * Collect the exit status of some children...
699 */
700
701#ifdef HAVE_WAITPID
702 while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
703#elif defined(HAVE_WAIT3)
704 while ((pid = wait3(&status, WNOHANG, NULL)) > 0)
705#else
706 if ((pid = wait(&status)) > 0)
707#endif /* HAVE_WAITPID */
708 {
709 if (status == SIGTERM)
710 status = 0;
711
712 for (i = num_backends, backend = backends; i > 0; i --, backend ++)
713 if (backend->pid == pid)
714 break;
715
716 if (i > 0)
717 {
718 name = backend->name;
719 backend->pid = 0;
720 backend->status = status;
721
722 active_backends --;
723 }
724 else
725 name = "Unknown";
726
727 if (status)
728 {
729 if (WIFEXITED(status))
730 fprintf(stderr,
731 "ERROR: [cups-deviced] PID %d (%s) stopped with status %d!\n",
732 pid, name, WEXITSTATUS(status));
733 else
734 fprintf(stderr,
735 "ERROR: [cups-deviced] PID %d (%s) crashed on signal %d!\n",
736 pid, name, WTERMSIG(status));
737 }
738 else
739 fprintf(stderr,
740 "DEBUG: [cups-deviced] PID %d (%s) exited with no errors.\n",
741 pid, name);
742 }
743}
744
745
746/*
747 * 'sigchld_handler()' - Handle 'child' signals from old processes.
748 */
749
750static void
751sigchld_handler(int sig) /* I - Signal number */
752{
753 (void)sig;
754
755 /*
756 * Flag that we have dead children...
757 */
758
759 dead_children = 1;
760
761 /*
762 * Reset the signal handler as needed...
763 */
764
765#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
766 signal(SIGCLD, sigchld_handler);
767#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
768}
769
770
771/*
772 * 'start_backend()' - Run a backend to gather the available devices.
773 */
774
775static int /* O - 0 on success, -1 on error */
776start_backend(const char *name, /* I - Backend to run */
777 int root) /* I - Run as root? */
778{
779 const char *server_bin; /* CUPS_SERVERBIN environment variable */
780 char program[1024]; /* Full path to backend */
ae71f5de 781 cupsd_backend_t *backend; /* Current backend */
c934a06c 782 char *argv[2]; /* Command-line arguments */
ae71f5de
MS
783
784
785 if (num_backends >= MAX_BACKENDS)
786 {
787 fprintf(stderr, "ERROR: Too many backends (%d)!\n", num_backends);
788 return (-1);
789 }
cc0d019f 790
ae71f5de
MS
791 if ((server_bin = getenv("CUPS_SERVERBIN")) == NULL)
792 server_bin = CUPS_SERVERBIN;
793
794 snprintf(program, sizeof(program), "%s/backend/%s", server_bin, name);
795
796 backend = backends + num_backends;
797
c934a06c
MS
798 argv[0] = (char *)name;
799 argv[1] = NULL;
cc0d019f 800
c934a06c
MS
801 if ((backend->pipe = cupsdPipeCommand(&(backend->pid), program, argv,
802 root ? 0 : normal_user)) == NULL)
cc0d019f 803 {
ae71f5de
MS
804 fprintf(stderr, "ERROR: [cups-deviced] Unable to execute \"%s\" - %s\n",
805 program, strerror(errno));
c934a06c 806 return (-1);
cc0d019f
MS
807 }
808
809 /*
c934a06c 810 * Fill in the rest of the backend information...
cc0d019f
MS
811 */
812
ae71f5de
MS
813 fprintf(stderr, "DEBUG: [cups-deviced] Started backend %s (PID %d)\n",
814 program, backend->pid);
cc0d019f 815
c934a06c 816 backend_fds[num_backends].fd = cupsFileNumber(backend->pipe);
ae71f5de 817 backend_fds[num_backends].events = POLLIN;
cc0d019f 818
ae71f5de
MS
819 backend->name = strdup(name);
820 backend->status = 0;
ae71f5de 821 backend->count = 0;
ef416fc2 822
ae71f5de
MS
823 active_backends ++;
824 num_backends ++;
ef416fc2 825
ae71f5de 826 return (0);
ef416fc2 827}
828
829
830/*
b19ccc9e 831 * End of "$Id: cups-deviced.c 7816 2008-07-30 20:53:31Z mike $".
ef416fc2 832 */