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