]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/cupsfilter.c
Merge changes from r6781 to r6792 (CUPS 1.3.0)
[thirdparty/cups.git] / scheduler / cupsfilter.c
CommitLineData
bc44d920 1/*
cc0d019f 2 * "$Id: cupsfilter.c 6695 2007-07-19 21:59:30Z mike $"
bc44d920 3 *
4 * CUPS filtering program for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
8 *
9 * These coded instructions, statements, and computer programs are the
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/".
14 *
15 * Contents:
16 *
17 * main() - Main entry for the test program.
18 * compare_pids() - Compare two filter PIDs...
19 * escape_options() - Convert an options array to a string.
20 * exec_filter() - Execute a single filter.
21 * exec_filters() - Execute filters for the given file and options.
22 * open_pipe() - Create a pipe which is closed on exec.
23 * read_cupsd_conf() - Read the cupsd.conf file to get the filter settings.
24 * set_string() - Copy and set a string.
25 * usage() - Show program usage...
26 */
27
28/*
29 * Include necessary headers...
30 */
31
32#include <cups/cups.h>
33#include <cups/i18n.h>
34#include <cups/string.h>
35#include <errno.h>
36#include "mime.h"
37#include <stdlib.h>
38#include <unistd.h>
39#include <fcntl.h>
40#include <sys/wait.h>
41#if defined(__APPLE__)
42# include <libgen.h>
43#endif /* __APPLE__ */
44
45
46/*
47 * Local globals...
48 */
49
50static char *DataDir = NULL;/* CUPS_DATADIR environment variable */
51static char *FontPath = NULL;
52 /* CUPS_FONTPATH environment variable */
53static mime_filter_t GZIPFilter = /* gziptoany filter */
54{
55 NULL, /* Source type */
56 NULL, /* Destination type */
57 0, /* Cost */
58 "gziptoany" /* Filter program to run */
59};
60static char *Path = NULL; /* PATH environment variable */
61static char *ServerBin = NULL;
62 /* CUPS_SERVERBIN environment variable */
63static char *ServerRoot = NULL;
64 /* CUPS_SERVERROOT environment variable */
65static char *RIPCache = NULL;
66 /* RIP_CACHE environment variable */
67
68
69/*
70 * Local functions...
71 */
72
73static int compare_pids(mime_filter_t *a, mime_filter_t *b);
74static char *escape_options(int num_options, cups_option_t *options);
75static int exec_filter(const char *filter, char **argv, char **envp,
76 int infd, int outfd);
cc0d019f
MS
77static int exec_filters(cups_array_t *filters, const char *infile,
78 const char *outfile, const char *ppdfile,
79 const char *user, const char *title,
bc44d920 80 int num_options, cups_option_t *options);
81static int open_pipe(int *fds);
82static int read_cupsd_conf(const char *filename);
83static void set_string(char **s, const char *val);
cc0d019f 84static void usage(const char *command, const char *opt);
bc44d920 85
86
87/*
88 * 'main()' - Main entry for the test program.
89 */
90
91int /* O - Exit status */
92main(int argc, /* I - Number of command-line args */
93 char *argv[]) /* I - Command-line arguments */
94{
95 int i; /* Looping vars */
cc0d019f
MS
96 const char *command, /* Command name */
97 *opt; /* Current option */
98 char *srctype, /* Source type */
99 *dsttype, /* Destination type */
100 super[MIME_MAX_SUPER], /* Super-type name */
bc44d920 101 type[MIME_MAX_TYPE]; /* Type name */
102 int compression; /* Compression of file */
103 int cost; /* Cost of filters */
104 mime_t *mime; /* MIME database */
cc0d019f
MS
105 char *infile, /* File to filter */
106 *outfile; /* File to create */
bc44d920 107 char cupsdconf[1024]; /* cupsd.conf file */
108 const char *server_root; /* CUPS_SERVERROOT environment variable */
109 mime_type_t *src, /* Source type */
110 *dst; /* Destination type */
111 cups_array_t *filters; /* Filters for the file */
112 int num_options; /* Number of options */
113 cups_option_t *options; /* Options */
114 const char *ppdfile; /* PPD file */
cc0d019f
MS
115 const char *title, /* Title string */
116 *user; /* Username */
117 int removeppd, /* Remove PPD file */
118 removeinfile; /* Remove input file */
119 int status; /* Execution status */
bc44d920 120
121
122 /*
123 * Setup defaults...
124 */
125
cc0d019f
MS
126 if ((command = strrchr(argv[0], '/')) != NULL)
127 command ++;
128 else
129 command = argv[0];
130
131 mime = NULL;
132 srctype = NULL;
133 dsttype = "application/pdf";
134 infile = NULL;
135 outfile = NULL;
136 num_options = 0;
137 options = NULL;
138 ppdfile = NULL;
139 title = NULL;
140 user = cupsUser();
141 removeppd = 0;
142 removeinfile = 0;
bc44d920 143
144 if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
145 server_root = CUPS_SERVERROOT;
146
147 snprintf(cupsdconf, sizeof(cupsdconf), "%s/cupsd.conf", server_root);
148
149 /*
150 * Process command-line arguments...
151 */
152
153 _cupsSetLocale(argv);
154
155 for (i = 1; i < argc; i ++)
156 if (argv[i][0] == '-')
157 {
158 for (opt = argv[i] + 1; *opt; opt ++)
159 switch (*opt)
160 {
161 case '-' : /* Next argument is a filename... */
162 i ++;
cc0d019f
MS
163 if (i < argc && !infile)
164 infile = argv[i];
bc44d920 165 else
cc0d019f
MS
166 usage(command, opt);
167 break;
168
169 case 'a' : /* Specify option... */
170 i ++;
171 if (i < argc)
172 num_options = cupsParseOptions(argv[i], num_options, &options);
173 else
174 usage(command, opt);
bc44d920 175 break;
176
177 case 'c' : /* Specify cupsd.conf file location... */
178 i ++;
179 if (i < argc)
cc0d019f
MS
180 {
181 if (!strcmp(command, "convert"))
182 num_options = cupsAddOption("copies", argv[i], num_options,
183 &options);
184 else
185 strlcpy(cupsdconf, argv[i], sizeof(cupsdconf));
186 }
187 else
188 usage(command, opt);
189 break;
190
191 case 'D' : /* Delete input file after conversion */
192 removeinfile = 1;
193 break;
194
195 case 'f' : /* Specify input file... */
196 i ++;
197 if (i < argc && !infile)
198 infile = argv[i];
199 else
200 usage(command, opt);
201 break;
202
203 case 'i' : /* Specify source MIME type... */
204 i ++;
205 if (i < argc)
206 {
207 if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2)
208 usage(command, opt);
209
210 srctype = argv[i];
211 }
bc44d920 212 else
cc0d019f 213 usage(command, opt);
bc44d920 214 break;
215
cc0d019f 216 case 'j' : /* Specify destination MIME type... */
bc44d920 217 case 'm' : /* Specify destination MIME type... */
218 i ++;
219 if (i < argc)
220 {
221 if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2)
cc0d019f
MS
222 usage(command, opt);
223
224 dsttype = argv[i];
bc44d920 225 }
226 else
cc0d019f 227 usage(command, opt);
bc44d920 228 break;
229
230 case 'n' : /* Specify number of copies... */
231 i ++;
232 if (i < argc)
233 num_options = cupsAddOption("copies", argv[i], num_options,
234 &options);
235 else
cc0d019f 236 usage(command, opt);
bc44d920 237 break;
238
cc0d019f 239 case 'o' : /* Specify option(s) or output filename */
bc44d920 240 i ++;
241 if (i < argc)
cc0d019f
MS
242 {
243 if (!strcmp(command, "convert"))
244 {
245 if (outfile)
246 usage(command, NULL);
247 else
248 outfile = argv[i];
249 }
250 else
251 num_options = cupsParseOptions(argv[i], num_options,
252 &options);
253 }
bc44d920 254 else
cc0d019f 255 usage(command, opt);
bc44d920 256 break;
257
258 case 'p' : /* Specify PPD file... */
cc0d019f 259 case 'P' : /* Specify PPD file... */
bc44d920 260 i ++;
261 if (i < argc)
262 ppdfile = argv[i];
263 else
cc0d019f 264 usage(command, opt);
bc44d920 265 break;
266
cc0d019f
MS
267 case 't' : /* Specify title... */
268 case 'J' : /* Specify title... */
bc44d920 269 i ++;
270 if (i < argc)
271 title = argv[i];
272 else
cc0d019f
MS
273 usage(command, opt);
274 break;
275
276 case 'u' : /* Delete PPD file after conversion */
277 removeinfile = 1;
278 break;
279
280 case 'U' : /* Specify username... */
281 i ++;
282 if (i < argc)
283 user = argv[i];
284 else
285 usage(command, opt);
bc44d920 286 break;
287
288 default : /* Something we don't understand... */
cc0d019f 289 usage(command, opt);
bc44d920 290 break;
291 }
292 }
cc0d019f
MS
293 else if (!infile)
294 {
295 if (strcmp(command, "convert"))
296 infile = argv[i];
297 else
298 {
299 _cupsLangPuts(stderr,
300 _("convert: Use the -f option to specify a file to "
301 "convert.\n"));
302 usage(command, NULL);
303 }
304 }
bc44d920 305 else
306 {
307 _cupsLangPuts(stderr,
308 _("cupsfilter: Only one filename can be specified!\n"));
cc0d019f 309 usage(command, NULL);
bc44d920 310 }
311
cc0d019f
MS
312 if (!infile && !srctype)
313 usage(command, NULL);
bc44d920 314
315 if (!title)
316 {
cc0d019f
MS
317 if (!infile)
318 title = "(stdin)";
319 else if ((title = strrchr(infile, '/')) != NULL)
bc44d920 320 title ++;
321 else
cc0d019f 322 title = infile;
bc44d920 323 }
324
325 /*
326 * Load the cupsd.conf file and create the MIME database...
327 */
328
329 if (read_cupsd_conf(cupsdconf))
330 return (1);
331
332 if ((mime = mimeLoad(ServerRoot, Path)) == NULL)
333 {
334 _cupsLangPrintf(stderr,
cc0d019f
MS
335 _("%s: Unable to read MIME database from \"%s\"!\n"),
336 command, ServerRoot);
bc44d920 337 return (1);
338 }
339
340 /*
341 * Get the source and destination types...
342 */
343
cc0d019f
MS
344 if (srctype)
345 {
346 sscanf(srctype, "%15[^/]/%255s", super, type);
347 if ((src = mimeType(mime, super, type)) == NULL)
348 {
349 _cupsLangPrintf(stderr,
350 _("%s: Unknown source MIME type %s/%s!\n"),
351 command, super, type);
352 return (1);
353 }
354 }
355 else if ((src = mimeFileType(mime, infile, infile, &compression)) == NULL)
bc44d920 356 {
357 _cupsLangPrintf(stderr,
cc0d019f
MS
358 _("%s: Unable to determine MIME type of \"%s\"!\n"),
359 command, infile);
bc44d920 360 return (1);
361 }
362
cc0d019f 363 sscanf(dsttype, "%15[^/]/%255s", super, type);
bc44d920 364 if ((dst = mimeType(mime, super, type)) == NULL)
365 {
366 _cupsLangPrintf(stderr,
cc0d019f
MS
367 _("%s: Unknown destination MIME type %s/%s!\n"),
368 command, super, type);
bc44d920 369 return (1);
370 }
371
372 /*
373 * Figure out how to filter the file...
374 */
375
376 if (src == dst)
377 {
378 /*
379 * Special case - no filtering needed...
380 */
381
382 filters = cupsArrayNew(NULL, NULL);
383 cupsArrayAdd(filters, &GZIPFilter);
384 }
385 else if ((filters = mimeFilter(mime, src, dst, &cost)) == NULL)
386 {
387 _cupsLangPrintf(stderr,
cc0d019f
MS
388 _("%s: No filter to convert from %s/%s to %s/%s!\n"),
389 command, src->super, src->type, dst->super, dst->type);
bc44d920 390 return (1);
391 }
392 else if (compression)
393 cupsArrayInsert(filters, &GZIPFilter);
394
395 /*
396 * Do it!
397 */
398
cc0d019f
MS
399 status = exec_filters(filters, infile, outfile, ppdfile, user, title,
400 num_options, options);
401
402 /*
403 * Remove files as needed, then exit...
404 */
405
406 if (removeppd && ppdfile)
407 unlink(ppdfile);
408
409 if (removeinfile && infile)
410 unlink(infile);
411
412 return (status);
bc44d920 413}
414
415
416/*
417 * 'compare_pids()' - Compare two filter PIDs...
418 */
419
420static int /* O - Result of comparison */
421compare_pids(mime_filter_t *a, /* I - First filter */
422 mime_filter_t *b) /* I - Second filter */
423{
424 /*
425 * Because we're particularly lazy, we store the process ID in the "cost"
426 * variable...
427 */
428
429 return (a->cost - b->cost);
430}
431
432
433/*
434 * 'escape_options()' - Convert an options array to a string.
435 */
436
437static char * /* O - Option string */
438escape_options(
439 int num_options, /* I - Number of options */
440 cups_option_t *options) /* I - Options */
441{
442 int i; /* Looping var */
443 cups_option_t *option; /* Current option */
444 int bytes; /* Number of bytes needed */
445 char *s, /* Option string */
446 *sptr, /* Pointer into string */
447 *vptr; /* Pointer into value */
448
449
450 /*
451 * Figure out the worst-case number of bytes we need for the option string.
452 */
453
454 for (i = num_options, option = options, bytes = 1; i > 0; i --, option ++)
455 bytes += 2 * (strlen(option->name) + strlen(option->value)) + 2;
456
457 s = malloc(bytes);
458
459 /*
460 * Copy the options to the string...
461 */
462
463 for (i = num_options, option = options, sptr = s; i > 0; i --, option ++)
464 {
465 if (!strcmp(option->name, "copies"))
466 continue;
467
468 if (sptr > s)
469 *sptr++ = ' ';
470
471 strcpy(sptr, option->name);
472 sptr += strlen(sptr);
473 *sptr++ = '=';
474
475 for (vptr = option->value; *vptr;)
476 {
477 if (strchr("\\ \t\n", *vptr))
478 *sptr++ = '\\';
479
480 *sptr++ = *vptr++;
481 }
482 }
483
484 *sptr = '\0';
485
bc44d920 486 return (s);
487}
488
489
490/*
491 * 'exec_filter()' - Execute a single filter.
492 */
493
494static int /* O - Process ID or -1 on error */
495exec_filter(const char *filter, /* I - Filter to execute */
496 char **argv, /* I - Argument list */
497 char **envp, /* I - Environment list */
498 int infd, /* I - Stdin file descriptor */
499 int outfd) /* I - Stdout file descriptor */
500{
501 int pid; /* Process ID */
502#if defined(__APPLE__)
503 char processPath[1024], /* CFProcessPath environment variable */
504 linkpath[1024]; /* Link path for symlinks... */
505 int linkbytes; /* Bytes for link path */
506
507
508 /*
509 * Add special voodoo magic for MacOS X - this allows MacOS X
510 * programs to access their bundle resources properly...
511 */
512
513 if ((linkbytes = readlink(filter, linkpath, sizeof(linkpath) - 1)) > 0)
514 {
515 /*
516 * Yes, this is a symlink to the actual program, nul-terminate and
517 * use it...
518 */
519
520 linkpath[linkbytes] = '\0';
521
522 if (linkpath[0] == '/')
523 snprintf(processPath, sizeof(processPath), "CFProcessPath=%s",
524 linkpath);
525 else
526 snprintf(processPath, sizeof(processPath), "CFProcessPath=%s/%s",
527 dirname((char *)filter), linkpath);
528 }
529 else
530 snprintf(processPath, sizeof(processPath), "CFProcessPath=%s", filter);
531
532 envp[0] = processPath; /* Replace <CFProcessPath> string */
533#endif /* __APPLE__ */
534
535 if ((pid = fork()) == 0)
536 {
537 /*
538 * Child process goes here...
539 *
540 * Update stdin/stdout/stderr as needed...
541 */
542
543 if (infd != 0)
544 {
545 close(0);
546 if (infd > 0)
547 dup(infd);
548 else
549 open("/dev/null", O_RDONLY);
550 }
551
552 if (outfd != 1)
553 {
554 close(1);
555 if (outfd > 0)
556 dup(outfd);
557 else
558 open("/dev/null", O_WRONLY);
559 }
560
561 close(3);
562 open("/dev/null", O_RDWR);
563 fcntl(3, F_SETFL, O_NDELAY);
564
565 close(4);
566 open("/dev/null", O_RDWR);
567 fcntl(4, F_SETFL, O_NDELAY);
568
569 /*
570 * Execute command...
571 */
572
573 execve(filter, argv, envp);
574
575 perror(filter);
576
577 exit(errno);
578 }
579
580 return (pid);
581}
582
583
584/*
585 * 'exec_filters()' - Execute filters for the given file and options.
586 */
587
588static int /* O - 0 on success, 1 on error */
589exec_filters(cups_array_t *filters, /* I - Array of filters to run */
cc0d019f
MS
590 const char *infile, /* I - File to filter */
591 const char *outfile, /* I - File to create */
bc44d920 592 const char *ppdfile, /* I - PPD file, if any */
cc0d019f 593 const char *user, /* I - Username */
bc44d920 594 const char *title, /* I - Job title */
595 int num_options, /* I - Number of filter options */
596 cups_option_t *options) /* I - Filter options */
597{
cc0d019f 598 int i; /* Looping var */
bc44d920 599 const char *argv[8], /* Command-line arguments */
600 *envp[11], /* Environment variables */
601 *temp; /* Temporary string */
602 char *optstr, /* Filter options */
603 cups_datadir[1024], /* CUPS_DATADIR */
604 cups_fontpath[1024], /* CUPS_FONTPATH */
605 cups_serverbin[1024], /* CUPS_SERVERBIN */
606 cups_serverroot[1024], /* CUPS_SERVERROOT */
607 lang[1024], /* LANG */
608 path[1024], /* PATH */
609 ppd[1024], /* PPD */
610 rip_cache[1024], /* RIP_CACHE */
cc0d019f 611 userenv[1024], /* USER */
bc44d920 612 program[1024]; /* Program to run */
613 mime_filter_t *filter, /* Current filter */
614 *next; /* Next filter */
615 int current, /* Current filter */
616 filterfds[2][2], /* Pipes for filters */
617 pid, /* Process ID of filter */
618 status, /* Exit status */
619 retval; /* Return value */
620 cups_array_t *pids; /* Executed filters array */
621 mime_filter_t key; /* Search key for filters */
cc0d019f 622 cups_lang_t *language; /* Current language */
bc44d920 623
624
625 /*
626 * Setup the filter environment and command-line...
627 */
628
629 optstr = escape_options(num_options, options);
630
631 snprintf(cups_datadir, sizeof(cups_datadir), "CUPS_DATADIR=%s", DataDir);
632 snprintf(cups_fontpath, sizeof(cups_fontpath), "CUPS_FONTPATH=%s", FontPath);
633 snprintf(cups_serverbin, sizeof(cups_serverbin), "CUPS_SERVERBIN=%s",
634 ServerBin);
635 snprintf(cups_serverroot, sizeof(cups_serverroot), "CUPS_SERVERROOT=%s",
636 ServerRoot);
cc0d019f
MS
637 language = cupsLangDefault();
638 snprintf(lang, sizeof(lang), "LANG=%s.UTF8", language->language);
bc44d920 639 snprintf(path, sizeof(path), "PATH=%s", Path);
640 if (ppdfile)
641 snprintf(ppd, sizeof(ppd), "PPD=%s", ppdfile);
642 else if ((temp = getenv("PPD")) != NULL)
643 snprintf(ppd, sizeof(ppd), "PPD=%s", temp);
644 else
cc0d019f
MS
645#ifdef __APPLE__
646 strlcpy(ppd, "PPD=/System/Library/Frameworks/ApplicationServices.framework/"
647 "Versions/A/Frameworks/PrintCore.framework/Versions/A/"
648 "Resources/English.lproj/Generic.ppd", sizeof(ppd));
649#else
bc44d920 650 snprintf(ppd, sizeof(ppd), "PPD=%s/model/laserjet.ppd", DataDir);
cc0d019f 651#endif /* __APPLE__ */
bc44d920 652 snprintf(rip_cache, sizeof(rip_cache), "RIP_CACHE=%s", RIPCache);
cc0d019f 653 snprintf(userenv, sizeof(userenv), "USER=%s", user);
bc44d920 654
655 argv[0] = "cupsfilter";
656 argv[1] = "0";
cc0d019f 657 argv[2] = user;
bc44d920 658 argv[3] = title;
659 argv[4] = cupsGetOption("copies", num_options, options);
660 argv[5] = optstr;
cc0d019f 661 argv[6] = infile;
bc44d920 662 argv[7] = NULL;
663
664 if (!argv[4])
665 argv[4] = "1";
666
667 envp[0] = "<CFProcessPath>";
668 envp[1] = cups_datadir;
669 envp[2] = cups_fontpath;
670 envp[3] = cups_serverbin;
671 envp[4] = cups_serverroot;
672 envp[5] = lang;
673 envp[6] = path;
674 envp[7] = ppd;
675 envp[8] = rip_cache;
cc0d019f 676 envp[9] = userenv;
bc44d920 677 envp[10] = NULL;
678
cc0d019f
MS
679 for (i = 0; argv[i]; i ++)
680 fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]);
681
682 for (i = 0; envp[i]; i ++)
683 fprintf(stderr, "DEBUG: envp[%d]=\"%s\"\n", i, envp[i]);
684
bc44d920 685 /*
686 * Execute all of the filters...
687 */
688
689 pids = cupsArrayNew((cups_array_func_t)compare_pids, NULL);
690 current = 0;
691 filterfds[0][0] = -1;
692 filterfds[0][1] = -1;
693 filterfds[1][0] = -1;
694 filterfds[1][1] = -1;
695
cc0d019f
MS
696 if (!infile)
697 filterfds[0][0] = 0;
698
bc44d920 699 for (filter = (mime_filter_t *)cupsArrayFirst(filters);
700 filter;
701 filter = next, current = 1 - current)
702 {
703 next = (mime_filter_t *)cupsArrayNext(filters);
704
705 if (filter->filter[0] == '/')
706 strlcpy(program, filter->filter, sizeof(program));
707 else
708 snprintf(program, sizeof(program), "%s/filter/%s", ServerBin,
709 filter->filter);
710
711 if (filterfds[!current][1] > 1)
712 {
713 close(filterfds[1 - current][0]);
714 close(filterfds[1 - current][1]);
715
716 filterfds[1 - current][0] = -1;
717 filterfds[1 - current][0] = -1;
718 }
719
720 if (next)
721 open_pipe(filterfds[1 - current]);
cc0d019f
MS
722 else if (outfile)
723 {
724 filterfds[1 - current][1] = open(outfile, O_CREAT | O_TRUNC | O_WRONLY,
725 0666);
726
727 if (filterfds[1 - current][1] < 0)
728 fprintf(stderr, "ERROR: Unable to create \"%s\" - %s\n", outfile,
729 strerror(errno));
730 }
bc44d920 731 else
732 filterfds[1 - current][1] = 1;
733
734 pid = exec_filter(program, (char **)argv, (char **)envp,
735 filterfds[current][0], filterfds[1 - current][1]);
736
737 if (pid > 0)
738 {
739 fprintf(stderr, "INFO: %s (PID %d) started.\n", filter->filter, pid);
740
741 filter->cost = pid;
742 cupsArrayAdd(pids, filter);
743 }
744 else
745 break;
746
747 argv[6] = NULL;
748 }
749
750 /*
751 * Close remaining pipes...
752 */
753
754 if (filterfds[0][1] > 1)
755 {
756 close(filterfds[0][0]);
757 close(filterfds[0][1]);
758 }
759
760 if (filterfds[1][1] > 1)
761 {
762 close(filterfds[1][0]);
763 close(filterfds[1][1]);
764 }
765
766 /*
767 * Wait for the children to exit...
768 */
769
770 retval = 0;
771
772 while (cupsArrayCount(pids) > 0)
773 {
774 if ((pid = wait(&status)) < 0)
775 continue;
776
777 key.cost = pid;
778 if ((filter = (mime_filter_t *)cupsArrayFind(pids, &key)) != NULL)
779 {
780 cupsArrayRemove(pids, filter);
781
782 if (status)
783 {
784 if (WIFEXITED(status))
785 fprintf(stderr, "ERROR: %s (PID %d) stopped with status %d!\n",
786 filter->filter, pid, WEXITSTATUS(status));
787 else
788 fprintf(stderr, "ERROR: %s (PID %d) crashed on signal %d!\n",
789 filter->filter, pid, WTERMSIG(status));
790
791 retval = 1;
792 }
793 else
794 fprintf(stderr, "INFO: %s (PID %d) exited with no errors.\n",
795 filter->filter, pid);
796 }
797 }
798
799 return (retval);
800}
801
802
803/*
804 * 'open_pipe()' - Create a pipe which is closed on exec.
805 */
806
807int /* O - 0 on success, -1 on error */
808open_pipe(int *fds) /* O - Pipe file descriptors (2) */
809{
810 /*
811 * Create the pipe...
812 */
813
814 if (pipe(fds))
815 {
816 fds[0] = -1;
817 fds[1] = -1;
818
819 return (-1);
820 }
821
822 /*
823 * Set the "close on exec" flag on each end of the pipe...
824 */
825
826 if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC))
827 {
828 close(fds[0]);
829 close(fds[1]);
830
831 fds[0] = -1;
832 fds[1] = -1;
833
834 return (-1);
835 }
836
837 if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC))
838 {
839 close(fds[0]);
840 close(fds[1]);
841
842 fds[0] = -1;
843 fds[1] = -1;
844
845 return (-1);
846 }
847
848 /*
849 * Return 0 indicating success...
850 */
851
852 return (0);
853}
854
855
856/*
857 * 'read_cupsd_conf()' - Read the cupsd.conf file to get the filter settings.
858 */
859
860static int /* O - 0 on success, 1 on error */
861read_cupsd_conf(const char *filename) /* I - File to read */
862{
cc0d019f 863 cups_file_t *fp; /* cupsd.conf file */
bc44d920 864 const char *temp; /* Temporary string */
865 char line[1024], /* Line from file */
866 *ptr; /* Pointer into line */
cc0d019f 867 int linenum; /* Current line number */
bc44d920 868
869
870 if ((temp = getenv("CUPS_DATADIR")) != NULL)
871 set_string(&DataDir, temp);
872 else
873 set_string(&DataDir, CUPS_DATADIR);
874
875 if ((temp = getenv("CUPS_FONTPATH")) != NULL)
876 set_string(&FontPath, temp);
877 else
878 set_string(&FontPath, CUPS_FONTPATH);
879
cc0d019f
MS
880 set_string(&RIPCache, "8m");
881
bc44d920 882 if ((temp = getenv("CUPS_SERVERBIN")) != NULL)
883 set_string(&ServerBin, temp);
884 else
885 set_string(&ServerBin, CUPS_SERVERBIN);
886
887 strlcpy(line, filename, sizeof(line));
888 if ((ptr = strrchr(line, '/')) != NULL)
889 *ptr = '\0';
890 else
891 getcwd(line, sizeof(line));
892
893 set_string(&ServerRoot, line);
894
cc0d019f
MS
895 if ((fp = cupsFileOpen(filename, "r")) != NULL)
896 {
897 linenum = 0;
898
899 while (cupsFileGetConf(fp, line, sizeof(line), &ptr, &linenum))
900 {
901 if (!strcasecmp(line, "DataDir"))
902 set_string(&DataDir, ptr);
903 else if (!strcasecmp(line, "FontPath"))
904 set_string(&FontPath, ptr);
905 else if (!strcasecmp(line, "RIPCache"))
906 set_string(&RIPCache, ptr);
907 else if (!strcasecmp(line, "ServerBin"))
908 set_string(&ServerBin, ptr);
909 else if (!strcasecmp(line, "ServerRoot"))
910 set_string(&ServerRoot, ptr);
911 }
912
913 cupsFileClose(fp);
914 }
915
bc44d920 916 snprintf(line, sizeof(line),
917 "%s/filter:" CUPS_BINDIR ":" CUPS_SBINDIR ":/bin/usr/bin",
918 ServerBin);
919 set_string(&Path, line);
920
921 return (0);
922}
923
924
925/*
926 * 'set_string()' - Copy and set a string.
927 */
928
929static void
930set_string(char **s, /* O - Copy of string */
931 const char *val) /* I - String to copy */
932{
933 if (*s)
934 free(*s);
935
936 *s = strdup(val);
937}
938
939
940/*
941 * 'usage()' - Show program usage...
942 */
943
944static void
cc0d019f
MS
945usage(const char *command, /* I - Command name */
946 const char *opt) /* I - Incorrect option, if any */
bc44d920 947{
948 if (opt)
cc0d019f
MS
949 _cupsLangPrintf(stderr, _("%s: Unknown option '%c'!\n"), command, *opt);
950
951 if (!strcmp(command, "cupsfilter"))
952 _cupsLangPuts(stdout,
953 _("Usage: cupsfilter -m mime/type [ options ] filename\n"
954 "\n"
955 "Options:\n"
956 "\n"
957 " -c cupsd.conf Set cupsd.conf file to use\n"
958 " -n copies Set number of copies\n"
959 " -o name=value Set option(s)\n"
960 " -p filename.ppd Set PPD file\n"
961 " -t title Set title\n"));
962 else
963 _cupsLangPuts(stdout,
964 _("Usage: convert [ options ]\n"
965 "\n"
966 "Options:\n"
967 "\n"
968 " -f filename Set file to be converted (otherwise stdin)\n"
969 " -o filename Set file to be generated (otherwise stdout)\n"
970 " -i mime/type Set input MIME type (otherwise auto-typed)\n"
971 " -j mime/type Set output MIME type (otherwise application/pdf)\n"
972 " -P filename.ppd Set PPD file\n"
973 " -a 'name=value ...' Set option(s)\n"
974 " -U username Set username for job\n"
975 " -J title Set title\n"
976 " -c copies Set number of copies\n"
977 " -u Remove the PPD file when finished\n"
978 " -D Remove the input file when finished\n"));
bc44d920 979
980 exit(1);
981}
982
983
984/*
cc0d019f 985 * End of "$Id: cupsfilter.c 6695 2007-07-19 21:59:30Z mike $".
bc44d920 986 */