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