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