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