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