1 /*
2 * Copyright © 2008 Chris Wilson
3 *
4 * Permission to use, copy, modify, distribute, and sell this software
5 * and its documentation for any purpose is hereby granted without
6 * fee, provided that the above copyright notice appear in all copies
7 * and that both that copyright notice and this permission notice
8 * appear in supporting documentation, and that the name of
9 * Chris Wilson not be used in advertising or publicity pertaining to
10 * distribution of the software without specific, written prior
11 * permission. Chris Wilson makes no representations about the
12 * suitability of this software for any purpose. It is provided "as
13 * is" without express or implied warranty.
14 *
15 * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL,
18 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
21 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 * Author: Chris Wilson <chris@chris-wilson.co.uk>
24 *
25 * Contributor(s):
26 * Carlos Garcia Campos <carlosgc@gnome.org>
27 *
28 * Adapted from pdf2png.c:
29 * Copyright © 2005 Red Hat, Inc.
30 *
31 * Permission to use, copy, modify, distribute, and sell this software
32 * and its documentation for any purpose is hereby granted without
33 * fee, provided that the above copyright notice appear in all copies
34 * and that both that copyright notice and this permission notice
35 * appear in supporting documentation, and that the name of
36 * Red Hat, Inc. not be used in advertising or publicity pertaining to
37 * distribution of the software without specific, written prior
38 * permission. Red Hat, Inc. makes no representations about the
39 * suitability of this software for any purpose. It is provided "as
40 * is" without express or implied warranty.
41 *
42 * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
43 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
44 * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
45 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
46 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
47 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
48 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
49 *
50 * Author: Kristian Høgsberg <krh@redhat.com>
51 */
52
53 #if HAVE_CONFIG_H
54 #include "config.h"
55 #endif
56
57 #if HAVE_UNISTD_H
58 #include <unistd.h>
59 #endif
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63
64 #include <cairo.h>
65 #include <cairo-script-interpreter.h>
66
67 #if CAIRO_CAN_TEST_PDF_SURFACE
68 #include <poppler.h>
69 #endif
70
71 #if CAIRO_CAN_TEST_SVG_SURFACE
72 #include <librsvg/rsvg.h>
73 #ifndef RSVG_CAIRO_H
74 #include <librsvg/rsvg-cairo.h>
75 #endif
76 #endif
77
78 #if CAIRO_HAS_SPECTRE
79 #include <libspectre/spectre.h>
80 #endif
81
82 #include <errno.h>
83
84 #if HAVE_FCNTL_H
85 #include <fcntl.h>
86 #endif
87
88 #if HAVE_UNISTD_H && HAVE_SIGNAL_H && HAVE_SYS_STAT_H && HAVE_SYS_SOCKET_H && (HAVE_POLL_H || HAVE_SYS_POLL_H) && HAVE_SYS_UN_H
89 #include <signal.h>
90 #include <sys/stat.h>
91 #include <sys/socket.h>
92 #include <sys/un.h>
93
94 #if defined(HAVE_POLL_H)
95 #include <poll.h>
96 #elif defined(HAVE_SYS_POLL_H)
97 #include <sys/poll.h>
98 #endif
99
100 #define SOCKET_PATH "./.any2ppm"
101 #define TIMEOUT 60000 /* 60 seconds */
102
103 #if HAVE_FORK
104 #define CAN_RUN_AS_DAEMON 1
105 #endif
106 #endif
107
108 #define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0])))
109
110 static int
_cairo_writen(int fd,char * buf,int len)111 _cairo_writen (int fd, char *buf, int len)
112 {
113 while (len) {
114 int ret;
115
116 ret = write (fd, buf, len);
117 if (ret == -1) {
118 int err = errno;
119 switch (err) {
120 case EINTR:
121 case EAGAIN:
122 continue;
123 default:
124 return 0;
125 }
126 }
127 len -= ret;
128 buf += ret;
129 }
130
131 return 1;
132 }
133
134 static int
_cairo_write(int fd,char * buf,int maxlen,int buflen,const unsigned char * src,int srclen)135 _cairo_write (int fd,
136 char *buf, int maxlen, int buflen,
137 const unsigned char *src, int srclen)
138 {
139 if (buflen < 0)
140 return buflen;
141
142 while (srclen) {
143 int len;
144
145 len = buflen + srclen;
146 if (len > maxlen)
147 len = maxlen;
148 len -= buflen;
149
150 memcpy (buf + buflen, src, len);
151 buflen += len;
152 srclen -= len;
153 src += len;
154
155 if (buflen == maxlen) {
156 if (! _cairo_writen (fd, buf, buflen))
157 return -1;
158
159 buflen = 0;
160 }
161 }
162
163 return buflen;
164 }
165
166 static const char *
write_ppm(cairo_surface_t * surface,int fd)167 write_ppm (cairo_surface_t *surface, int fd)
168 {
169 char buf[4096];
170 cairo_format_t format;
171 const char *format_str;
172 const unsigned char *data;
173 int len;
174 int width, height, stride;
175 int i, j;
176
177 data = cairo_image_surface_get_data (surface);
178 height = cairo_image_surface_get_height (surface);
179 width = cairo_image_surface_get_width (surface);
180 stride = cairo_image_surface_get_stride (surface);
181 format = cairo_image_surface_get_format (surface);
182 if (format == CAIRO_FORMAT_ARGB32) {
183 /* see if we can convert to a standard ppm type and trim a few bytes */
184 const unsigned char *alpha = data;
185 for (j = height; j--; alpha += stride) {
186 for (i = 0; i < width; i++) {
187 if ((*(unsigned int *) (alpha+4*i) & 0xff000000) != 0xff000000)
188 goto done;
189 }
190 }
191 format = CAIRO_FORMAT_RGB24;
192 done: ;
193 }
194
195 switch (format) {
196 case CAIRO_FORMAT_ARGB32:
197 /* XXX need true alpha for svg */
198 format_str = "P7";
199 break;
200 case CAIRO_FORMAT_RGB24:
201 format_str = "P6";
202 break;
203 case CAIRO_FORMAT_A8:
204 format_str = "P5";
205 break;
206 case CAIRO_FORMAT_A1:
207 case CAIRO_FORMAT_RGB16_565:
208 case CAIRO_FORMAT_RGB30:
209 case CAIRO_FORMAT_RGB96F:
210 case CAIRO_FORMAT_RGBA128F:
211 case CAIRO_FORMAT_INVALID:
212 default:
213 return "unhandled image format";
214 }
215
216 len = sprintf (buf, "%s %d %d 255\n", format_str, width, height);
217 for (j = 0; j < height; j++) {
218 const unsigned int *row = (unsigned int *) (data + stride * j);
219
220 switch ((int) format) {
221 case CAIRO_FORMAT_ARGB32:
222 len = _cairo_write (fd,
223 buf, sizeof (buf), len,
224 (unsigned char *) row, 4 * width);
225 break;
226 case CAIRO_FORMAT_RGB24:
227 for (i = 0; i < width; i++) {
228 unsigned char rgb[3];
229 unsigned int p = *row++;
230 rgb[0] = (p & 0xff0000) >> 16;
231 rgb[1] = (p & 0x00ff00) >> 8;
232 rgb[2] = (p & 0x0000ff) >> 0;
233 len = _cairo_write (fd,
234 buf, sizeof (buf), len,
235 rgb, 3);
236 }
237 break;
238 case CAIRO_FORMAT_A8:
239 len = _cairo_write (fd,
240 buf, sizeof (buf), len,
241 (unsigned char *) row, width);
242 break;
243 }
244 if (len < 0)
245 return "write failed";
246 }
247
248 if (len && ! _cairo_writen (fd, buf, len))
249 return "write failed";
250
251 return NULL;
252 }
253
254 #if CAIRO_HAS_INTERPRETER
255 static cairo_surface_t *
_create_image(void * closure,cairo_content_t content,double width,double height,long uid)256 _create_image (void *closure,
257 cairo_content_t content,
258 double width, double height,
259 long uid)
260 {
261 cairo_surface_t **out = closure;
262 cairo_format_t format;
263 switch (content) {
264 case CAIRO_CONTENT_ALPHA:
265 format = CAIRO_FORMAT_A8;
266 break;
267 case CAIRO_CONTENT_COLOR:
268 format = CAIRO_FORMAT_RGB24;
269 break;
270 default:
271 case CAIRO_CONTENT_COLOR_ALPHA:
272 format = CAIRO_FORMAT_ARGB32;
273 break;
274 }
275 *out = cairo_image_surface_create (format, width, height);
276 return cairo_surface_reference (*out);
277 }
278
279 static const char *
_cairo_script_render_page(const char * filename,cairo_surface_t ** surface_out)280 _cairo_script_render_page (const char *filename,
281 cairo_surface_t **surface_out)
282 {
283 cairo_script_interpreter_t *csi;
284 cairo_surface_t *surface = NULL;
285 cairo_status_t status;
286 const cairo_script_interpreter_hooks_t hooks = {
287 &surface,
288 _create_image,
289 NULL, /* surface_destroy */
290 NULL, /* context_create */
291 NULL, /* context_destroy */
292 NULL, /* show_page */
293 NULL /* copy_page */
294 };
295
296 csi = cairo_script_interpreter_create ();
297 cairo_script_interpreter_install_hooks (csi, &hooks);
298 status = cairo_script_interpreter_run (csi, filename);
299 if (status) {
300 cairo_surface_destroy (surface);
301 surface = NULL;
302 }
303 status = cairo_script_interpreter_destroy (csi);
304 if (surface == NULL)
305 return "cairo-script interpreter failed";
306
307 if (status == CAIRO_STATUS_SUCCESS)
308 status = cairo_surface_status (surface);
309 if (status) {
310 cairo_surface_destroy (surface);
311 return cairo_status_to_string (status);
312 }
313
314 *surface_out = surface;
315 return NULL;
316 }
317
318 static const char *
cs_convert(char ** argv,int fd)319 cs_convert (char **argv, int fd)
320 {
321 const char *err;
322 cairo_surface_t *surface = NULL; /* silence compiler warning */
323
324 err = _cairo_script_render_page (argv[0], &surface);
325 if (err != NULL)
326 return err;
327
328 err = write_ppm (surface, fd);
329 cairo_surface_destroy (surface);
330
331 return err;
332 }
333 #else
334 static const char *
cs_convert(char ** argv,int fd)335 cs_convert (char **argv, int fd)
336 {
337 return "compiled without CairoScript support.";
338 }
339 #endif
340
341 #if CAIRO_CAN_TEST_PDF_SURFACE
342 /* adapted from pdf2png.c */
343 static const char *
_poppler_render_page(const char * filename,const char * page_label,cairo_surface_t ** surface_out)344 _poppler_render_page (const char *filename,
345 const char *page_label,
346 cairo_surface_t **surface_out)
347 {
348 PopplerDocument *document;
349 PopplerPage *page;
350 double width, height;
351 GError *error = NULL;
352 gchar *absolute, *uri;
353 cairo_surface_t *surface;
354 cairo_t *cr;
355 cairo_status_t status;
356
357 if (g_path_is_absolute (filename)) {
358 absolute = g_strdup (filename);
359 } else {
360 gchar *dir = g_get_current_dir ();
361 absolute = g_build_filename (dir, filename, (gchar *) 0);
362 g_free (dir);
363 }
364
365 uri = g_filename_to_uri (absolute, NULL, &error);
366 g_free (absolute);
367 if (uri == NULL)
368 return error->message; /* XXX g_error_free (error) */
369
370 document = poppler_document_new_from_file (uri, NULL, &error);
371 g_free (uri);
372 if (document == NULL)
373 return error->message; /* XXX g_error_free (error) */
374
375 page = poppler_document_get_page_by_label (document, page_label);
376 g_object_unref (document);
377 if (page == NULL)
378 return "page not found";
379
380 poppler_page_get_size (page, &width, &height);
381
382 surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
383 cr = cairo_create (surface);
384
385 cairo_set_source_rgb (cr, 1., 1., 1.);
386 cairo_paint (cr);
387 cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA);
388
389 poppler_page_render (page, cr);
390 g_object_unref (page);
391
392 cairo_pop_group_to_source (cr);
393 cairo_paint (cr);
394
395 status = cairo_status (cr);
396 cairo_destroy (cr);
397
398 if (status) {
399 cairo_surface_destroy (surface);
400 return cairo_status_to_string (status);
401 }
402
403 *surface_out = surface;
404 return NULL;
405 }
406
407 static const char *
pdf_convert(char ** argv,int fd)408 pdf_convert (char **argv, int fd)
409 {
410 const char *err;
411 cairo_surface_t *surface = NULL; /* silence compiler warning */
412
413 err = _poppler_render_page (argv[0], argv[1], &surface);
414 if (err != NULL)
415 return err;
416
417 err = write_ppm (surface, fd);
418 cairo_surface_destroy (surface);
419
420 return err;
421 }
422 #else
423 static const char *
pdf_convert(char ** argv,int fd)424 pdf_convert (char **argv, int fd)
425 {
426 return "compiled without PDF support.";
427 }
428 #endif
429
430 #if CAIRO_CAN_TEST_SVG_SURFACE
431 static const char *
_rsvg_render_page(const char * filename,cairo_surface_t ** surface_out)432 _rsvg_render_page (const char *filename,
433 cairo_surface_t **surface_out)
434 {
435 RsvgHandle *handle;
436 RsvgDimensionData dimensions;
437 GError *error = NULL;
438 cairo_surface_t *surface;
439 cairo_t *cr;
440 cairo_status_t status;
441
442 handle = rsvg_handle_new_from_file (filename, &error);
443 if (handle == NULL)
444 return error->message; /* XXX g_error_free */
445
446 rsvg_handle_set_dpi (handle, 72.0);
447 rsvg_handle_get_dimensions (handle, &dimensions);
448 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
449 dimensions.width,
450 dimensions.height);
451 cr = cairo_create (surface);
452
453 rsvg_handle_render_cairo (handle, cr);
454 g_object_unref (handle);
455
456 status = cairo_status (cr);
457 cairo_destroy (cr);
458
459 if (status) {
460 cairo_surface_destroy (surface);
461 return cairo_status_to_string (status);
462 }
463
464 *surface_out = surface;
465 return NULL;
466 }
467
468 static const char *
svg_convert(char ** argv,int fd)469 svg_convert (char **argv, int fd)
470 {
471 const char *err;
472 cairo_surface_t *surface = NULL; /* silence compiler warning */
473
474 err = _rsvg_render_page (argv[0], &surface);
475 if (err != NULL)
476 return err;
477
478 err = write_ppm (surface, fd);
479 cairo_surface_destroy (surface);
480
481 return err;
482 }
483 #else
484 static const char *
svg_convert(char ** argv,int fd)485 svg_convert (char **argv, int fd)
486 {
487 return "compiled without SVG support.";
488 }
489 #endif
490
491 #if CAIRO_HAS_SPECTRE
492 static const char *
_spectre_render_page(const char * filename,const char * page_label,cairo_surface_t ** surface_out)493 _spectre_render_page (const char *filename,
494 const char *page_label,
495 cairo_surface_t **surface_out)
496 {
497 static const cairo_user_data_key_t key;
498
499 SpectreDocument *document;
500 SpectreStatus status;
501 int width, height, stride;
502 unsigned char *pixels;
503 cairo_surface_t *surface;
504
505 document = spectre_document_new ();
506 spectre_document_load (document, filename);
507 status = spectre_document_status (document);
508 if (status) {
509 spectre_document_free (document);
510 return spectre_status_to_string (status);
511 }
512
513 if (page_label) {
514 SpectrePage *page;
515 SpectreRenderContext *rc;
516
517 page = spectre_document_get_page_by_label (document, page_label);
518 spectre_document_free (document);
519 if (page == NULL)
520 return "page not found";
521
522 spectre_page_get_size (page, &width, &height);
523 rc = spectre_render_context_new ();
524 spectre_render_context_set_page_size (rc, width, height);
525 spectre_page_render (page, rc, &pixels, &stride);
526 spectre_render_context_free (rc);
527 status = spectre_page_status (page);
528 spectre_page_free (page);
529 if (status) {
530 free (pixels);
531 return spectre_status_to_string (status);
532 }
533 } else {
534 spectre_document_get_page_size (document, &width, &height);
535 spectre_document_render (document, &pixels, &stride);
536 spectre_document_free (document);
537 }
538
539 surface = cairo_image_surface_create_for_data (pixels,
540 CAIRO_FORMAT_RGB24,
541 width, height,
542 stride);
543 cairo_surface_set_user_data (surface, &key,
544 pixels, (cairo_destroy_func_t) free);
545 *surface_out = surface;
546 return NULL;
547 }
548
549 static const char *
ps_convert(char ** argv,int fd)550 ps_convert (char **argv, int fd)
551 {
552 const char *err;
553 cairo_surface_t *surface = NULL; /* silence compiler warning */
554
555 err = _spectre_render_page (argv[0], argv[1], &surface);
556 if (err != NULL)
557 return err;
558
559 err = write_ppm (surface, fd);
560 cairo_surface_destroy (surface);
561
562 return err;
563 }
564 #else
565 static const char *
ps_convert(char ** argv,int fd)566 ps_convert (char **argv, int fd)
567 {
568 return "compiled without PostScript support.";
569 }
570 #endif
571
572 static const char *
convert(char ** argv,int fd)573 convert (char **argv, int fd)
574 {
575 static const struct converter {
576 const char *type;
577 const char *(*func) (char **, int);
578 } converters[] = {
579 { "cs", cs_convert },
580 { "pdf", pdf_convert },
581 { "ps", ps_convert },
582 { "svg", svg_convert },
583 { NULL, NULL }
584 };
585 const struct converter *converter = converters;
586 char *type;
587
588 type = strrchr (argv[0], '.');
589 if (type == NULL)
590 return "no file extension";
591 type++;
592
593 while (converter->type) {
594 if (strcmp (type, converter->type) == 0)
595 return converter->func (argv, fd);
596 converter++;
597 }
598 return "no converter";
599 }
600
601 #if CAN_RUN_AS_DAEMON
602 static int
_getline(int fd,char ** linep,size_t * lenp)603 _getline (int fd, char **linep, size_t *lenp)
604 {
605 char *line;
606 size_t len, i;
607 ssize_t ret;
608
609 line = *linep;
610 if (line == NULL) {
611 line = malloc (1024);
612 if (line == NULL)
613 return -1;
614 line[0] = '\0';
615 len = 1024;
616 } else
617 len = *lenp;
618
619 /* XXX simple, but ugly! */
620 i = 0;
621 do {
622 if (i == len - 1) {
623 char *nline;
624
625 nline = realloc (line, len + 1024);
626 if (nline == NULL)
627 goto out;
628
629 line = nline;
630 len += 1024;
631 }
632
633 ret = read (fd, line + i, 1);
634 if (ret == -1 || ret == 0)
635 goto out;
636 } while (line[i++] != '\n');
637
638 out:
639 line[i] = '\0';
640 *linep = line;
641 *lenp = len;
642 return i-1;
643 }
644
645 static int
split_line(char * line,char * argv[],int max_argc)646 split_line (char *line, char *argv[], int max_argc)
647 {
648 int i = 0;
649
650 max_argc--; /* leave one spare for the trailing NULL */
651
652 argv[i++] = line;
653 while (i < max_argc && (line = strchr (line, ' ')) != NULL) {
654 *line++ = '\0';
655 argv[i++] = line;
656 }
657
658 /* chomp the newline */
659 line = strchr (argv[i-1], '\n');
660 if (line != NULL)
661 *line = '\0';
662
663 argv[i] = NULL;
664
665 return i;
666 }
667
668 static int
any2ppm_daemon_exists(void)669 any2ppm_daemon_exists (void)
670 {
671 struct stat st;
672 int fd;
673 char buf[80];
674 int pid;
675 int ret;
676
677 if (stat (SOCKET_PATH, &st) < 0)
678 return 0;
679
680 fd = open (SOCKET_PATH ".pid", O_RDONLY);
681 if (fd < 0)
682 return 0;
683
684 pid = 0;
685 ret = read (fd, buf, sizeof (buf) - 1);
686 if (ret > 0) {
687 buf[ret] = '\0';
688 pid = atoi (buf);
689 }
690 close (fd);
691
692 return pid > 0 && kill (pid, 0) == 0;
693 }
694
695 static int
write_pid_file(void)696 write_pid_file (void)
697 {
698 int fd;
699 char buf[80];
700 int ret;
701
702 fd = open (SOCKET_PATH ".pid", O_CREAT | O_TRUNC | O_WRONLY, 0666);
703 if (fd < 0)
704 return 0;
705
706 ret = sprintf (buf, "%d\n", getpid ());
707 ret = write (fd, buf, ret) == ret;
708 close (fd);
709
710 return ret;
711 }
712
713 static int
open_devnull_to_fd(int want_fd,int flags)714 open_devnull_to_fd (int want_fd, int flags)
715 {
716 int error;
717 int got_fd;
718
719 close (want_fd);
720
721 got_fd = open("/dev/null", flags | O_CREAT, 0700);
722 if (got_fd == -1)
723 return -1;
724
725 error = dup2 (got_fd, want_fd);
726 close (got_fd);
727
728 return error;
729 }
730
731 static int
daemonize(void)732 daemonize (void)
733 {
734 void (*oldhup) (int);
735
736 /* Let the parent go. */
737 switch (fork ()) {
738 case -1: return -1;
739 case 0: break;
740 default: _exit (0);
741 }
742
743 /* Become session leader. */
744 if (setsid () == -1)
745 return -1;
746
747 /* Refork to yield session leadership. */
748 oldhup = signal (SIGHUP, SIG_IGN);
749
750 switch (fork ()) { /* refork to yield session leadership. */
751 case -1: return -1;
752 case 0: break;
753 default: _exit (0);
754 }
755
756 signal (SIGHUP, oldhup);
757
758 /* Establish stdio. */
759 if (open_devnull_to_fd (0, O_RDONLY) == -1)
760 return -1;
761 if (open_devnull_to_fd (1, O_WRONLY | O_APPEND) == -1)
762 return -1;
763 if (dup2 (1, 2) == -1)
764 return -1;
765
766 return 0;
767 }
768
769 static const char *
any2ppm_daemon(void)770 any2ppm_daemon (void)
771 {
772 int timeout = TIMEOUT;
773 struct pollfd pfd;
774 int sk, fd;
775 long flags;
776 struct sockaddr_un addr;
777 char *line = NULL;
778 size_t len = 0;
779
780 #ifdef SIGPIPE
781 signal (SIGPIPE, SIG_IGN);
782 #endif
783
784 /* XXX racy! */
785 if (getenv ("ANY2PPM_FORCE") == NULL && any2ppm_daemon_exists ())
786 return "any2ppm daemon already running";
787
788 unlink (SOCKET_PATH);
789
790 sk = socket (PF_UNIX, SOCK_STREAM, 0);
791 if (sk == -1)
792 return "unable to create socket";
793
794 memset (&addr, 0, sizeof (addr));
795 addr.sun_family = AF_UNIX;
796 strcpy (addr.sun_path, SOCKET_PATH);
797 if (bind (sk, (struct sockaddr *) &addr, sizeof (addr)) == -1) {
798 close (sk);
799 return "unable to bind socket";
800 }
801
802 flags = fcntl (sk, F_GETFL);
803 if (flags == -1 || fcntl (sk, F_SETFL, flags | O_NONBLOCK) == -1) {
804 close (sk);
805 return "unable to set socket to non-blocking";
806 }
807
808 if (listen (sk, 5) == -1) {
809 close (sk);
810 return "unable to listen on socket";
811 }
812
813 /* ready for client connection - detach from parent/terminal */
814 if (getenv ("ANY2PPM_NODAEMON") == NULL && daemonize () == -1) {
815 close (sk);
816 return "unable to detach from parent";
817 }
818
819 if (! write_pid_file ()) {
820 close (sk);
821 return "unable to write pid file";
822 }
823
824 if (getenv ("ANY2PPM_TIMEOUT") != NULL) {
825 timeout = atoi (getenv ("ANY2PPM_TIMEOUT"));
826 if (timeout == 0)
827 timeout = -1;
828 if (timeout > 0)
829 timeout *= 1000; /* convert env (in seconds) to milliseconds */
830 }
831
832 pfd.fd = sk;
833 pfd.events = POLLIN;
834 pfd.revents = 0; /* valgrind */
835 while (poll (&pfd, 1, timeout) > 0) {
836 while ((fd = accept (sk, NULL, NULL)) != -1) {
837 if (_getline (fd, &line, &len) != -1) {
838 char *argv[10];
839
840 if (split_line (line, argv, ARRAY_LENGTH (argv)) > 0) {
841 const char *err;
842
843 err = convert (argv, fd);
844 if (err != NULL) {
845 FILE *file = fopen (".any2ppm.errors", "a");
846 if (file != NULL) {
847 fprintf (file,
848 "Failed to convert '%s': %s\n",
849 argv[0], err);
850 fclose (file);
851 }
852 }
853 }
854 }
855 close (fd);
856 }
857 }
858 close (sk);
859 unlink (SOCKET_PATH);
860 unlink (SOCKET_PATH ".pid");
861
862 free (line);
863 return NULL;
864 }
865 #else
866 static const char *
any2ppm_daemon(void)867 any2ppm_daemon (void)
868 {
869 return "daemon not compiled in.";
870 }
871 #endif
872
873 int
main(int argc,char ** argv)874 main (int argc, char **argv)
875 {
876 const char *err;
877
878 #if CAIRO_CAN_TEST_PDF_SURFACE || CAIRO_CAN_TEST_SVG_SURFACE
879 #if GLIB_MAJOR_VERSION <= 2 && GLIB_MINOR_VERSION <= 34
880 g_type_init ();
881 #endif
882 #endif
883
884 #if defined(_WIN32) && !defined (__CYGWIN__)
885 _setmode (1, _O_BINARY);
886 #endif
887
888 if (argc == 1)
889 err = any2ppm_daemon ();
890 else
891 err = convert (argv + 1, 1);
892 if (err != NULL) {
893 fprintf (stderr, "Failed to run converter: %s\n", err);
894 return EXIT_FAILURE;
895 }
896
897 return EXIT_SUCCESS;
898 }
899