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