any2ppm.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  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. #if HAVE_CONFIG_H
  53. #include "config.h"
  54. #endif
  55. #if HAVE_UNISTD_H
  56. #include <unistd.h>
  57. #endif
  58. #include <stdio.h>
  59. #include <stdlib.h>
  60. #include <string.h>
  61. #include <cairo.h>
  62. #include <cairo-script-interpreter.h>
  63. #if CAIRO_CAN_TEST_PDF_SURFACE
  64. #include <poppler.h>
  65. #endif
  66. #if CAIRO_CAN_TEST_SVG_SURFACE
  67. #include <librsvg/rsvg.h>
  68. #ifndef RSVG_CAIRO_H
  69. #include <librsvg/rsvg-cairo.h>
  70. #endif
  71. #endif
  72. #if CAIRO_HAS_SPECTRE
  73. #include <libspectre/spectre.h>
  74. #endif
  75. #include <errno.h>
  76. #if HAVE_FCNTL_H
  77. #include <fcntl.h>
  78. #endif
  79. #if HAVE_UNISTD_H && HAVE_SIGNAL_H && HAVE_SYS_STAT_H && HAVE_SYS_SOCKET_H && HAVE_SYS_POLL_H && HAVE_SYS_UN_H
  80. #include <signal.h>
  81. #include <sys/stat.h>
  82. #include <sys/socket.h>
  83. #include <sys/poll.h>
  84. #include <sys/un.h>
  85. #define SOCKET_PATH "./.any2ppm"
  86. #define TIMEOUT 60000 /* 60 seconds */
  87. #if HAVE_FORK
  88. #define CAN_RUN_AS_DAEMON 1
  89. #endif
  90. #endif
  91. #define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0])))
  92. static int
  93. _cairo_writen (int fd, char *buf, int len)
  94. {
  95. while (len) {
  96. int ret;
  97. ret = write (fd, buf, len);
  98. if (ret == -1) {
  99. int err = errno;
  100. switch (err) {
  101. case EINTR:
  102. case EAGAIN:
  103. continue;
  104. default:
  105. return 0;
  106. }
  107. }
  108. len -= ret;
  109. buf += ret;
  110. }
  111. return 1;
  112. }
  113. static int
  114. _cairo_write (int fd,
  115. char *buf, int maxlen, int buflen,
  116. const unsigned char *src, int srclen)
  117. {
  118. if (buflen < 0)
  119. return buflen;
  120. while (srclen) {
  121. int len;
  122. len = buflen + srclen;
  123. if (len > maxlen)
  124. len = maxlen;
  125. len -= buflen;
  126. memcpy (buf + buflen, src, len);
  127. buflen += len;
  128. srclen -= len;
  129. src += len;
  130. if (buflen == maxlen) {
  131. if (! _cairo_writen (fd, buf, buflen))
  132. return -1;
  133. buflen = 0;
  134. }
  135. }
  136. return buflen;
  137. }
  138. static const char *
  139. write_ppm (cairo_surface_t *surface, int fd)
  140. {
  141. char buf[4096];
  142. cairo_format_t format;
  143. const char *format_str;
  144. const unsigned char *data;
  145. int len;
  146. int width, height, stride;
  147. int i, j;
  148. data = cairo_image_surface_get_data (surface);
  149. height = cairo_image_surface_get_height (surface);
  150. width = cairo_image_surface_get_width (surface);
  151. stride = cairo_image_surface_get_stride (surface);
  152. format = cairo_image_surface_get_format (surface);
  153. if (format == CAIRO_FORMAT_ARGB32) {
  154. /* see if we can convert to a standard ppm type and trim a few bytes */
  155. const unsigned char *alpha = data;
  156. for (j = height; j--; alpha += stride) {
  157. for (i = 0; i < width; i++) {
  158. if ((*(unsigned int *) (alpha+4*i) & 0xff000000) != 0xff000000)
  159. goto done;
  160. }
  161. }
  162. format = CAIRO_FORMAT_RGB24;
  163. done: ;
  164. }
  165. switch (format) {
  166. case CAIRO_FORMAT_ARGB32:
  167. /* XXX need true alpha for svg */
  168. format_str = "P7";
  169. break;
  170. case CAIRO_FORMAT_RGB24:
  171. format_str = "P6";
  172. break;
  173. case CAIRO_FORMAT_A8:
  174. format_str = "P5";
  175. break;
  176. case CAIRO_FORMAT_A1:
  177. case CAIRO_FORMAT_RGB16_565:
  178. case CAIRO_FORMAT_RGB30:
  179. case CAIRO_FORMAT_INVALID:
  180. default:
  181. return "unhandled image format";
  182. }
  183. len = sprintf (buf, "%s %d %d 255\n", format_str, width, height);
  184. for (j = 0; j < height; j++) {
  185. const unsigned int *row = (unsigned int *) (data + stride * j);
  186. switch ((int) format) {
  187. case CAIRO_FORMAT_ARGB32:
  188. len = _cairo_write (fd,
  189. buf, sizeof (buf), len,
  190. (unsigned char *) row, 4 * width);
  191. break;
  192. case CAIRO_FORMAT_RGB24:
  193. for (i = 0; i < width; i++) {
  194. unsigned char rgb[3];
  195. unsigned int p = *row++;
  196. rgb[0] = (p & 0xff0000) >> 16;
  197. rgb[1] = (p & 0x00ff00) >> 8;
  198. rgb[2] = (p & 0x0000ff) >> 0;
  199. len = _cairo_write (fd,
  200. buf, sizeof (buf), len,
  201. rgb, 3);
  202. }
  203. break;
  204. case CAIRO_FORMAT_A8:
  205. len = _cairo_write (fd,
  206. buf, sizeof (buf), len,
  207. (unsigned char *) row, width);
  208. break;
  209. }
  210. if (len < 0)
  211. return "write failed";
  212. }
  213. if (len && ! _cairo_writen (fd, buf, len))
  214. return "write failed";
  215. return NULL;
  216. }
  217. static cairo_surface_t *
  218. _create_image (void *closure,
  219. cairo_content_t content,
  220. double width, double height,
  221. long uid)
  222. {
  223. cairo_surface_t **out = closure;
  224. cairo_format_t format;
  225. switch (content) {
  226. case CAIRO_CONTENT_ALPHA:
  227. format = CAIRO_FORMAT_A8;
  228. break;
  229. case CAIRO_CONTENT_COLOR:
  230. format = CAIRO_FORMAT_RGB24;
  231. break;
  232. default:
  233. case CAIRO_CONTENT_COLOR_ALPHA:
  234. format = CAIRO_FORMAT_ARGB32;
  235. break;
  236. }
  237. *out = cairo_image_surface_create (format, width, height);
  238. return cairo_surface_reference (*out);
  239. }
  240. #if CAIRO_HAS_INTERPRETER
  241. static const char *
  242. _cairo_script_render_page (const char *filename,
  243. cairo_surface_t **surface_out)
  244. {
  245. cairo_script_interpreter_t *csi;
  246. cairo_surface_t *surface = NULL;
  247. cairo_status_t status;
  248. const cairo_script_interpreter_hooks_t hooks = {
  249. &surface,
  250. _create_image,
  251. NULL, /* surface_destroy */
  252. NULL, /* context_create */
  253. NULL, /* context_destroy */
  254. NULL, /* show_page */
  255. NULL /* copy_page */
  256. };
  257. csi = cairo_script_interpreter_create ();
  258. cairo_script_interpreter_install_hooks (csi, &hooks);
  259. status = cairo_script_interpreter_run (csi, filename);
  260. if (status) {
  261. cairo_surface_destroy (surface);
  262. surface = NULL;
  263. }
  264. status = cairo_script_interpreter_destroy (csi);
  265. if (surface == NULL)
  266. return "cairo-script interpreter failed";
  267. if (status == CAIRO_STATUS_SUCCESS)
  268. status = cairo_surface_status (surface);
  269. if (status) {
  270. cairo_surface_destroy (surface);
  271. return cairo_status_to_string (status);
  272. }
  273. *surface_out = surface;
  274. return NULL;
  275. }
  276. static const char *
  277. cs_convert (char **argv, int fd)
  278. {
  279. const char *err;
  280. cairo_surface_t *surface = NULL; /* silence compiler warning */
  281. err = _cairo_script_render_page (argv[0], &surface);
  282. if (err != NULL)
  283. return err;
  284. err = write_ppm (surface, fd);
  285. cairo_surface_destroy (surface);
  286. return err;
  287. }
  288. #else
  289. static const char *
  290. cs_convert (char **argv, int fd)
  291. {
  292. return "compiled without CairoScript support.";
  293. }
  294. #endif
  295. #if CAIRO_CAN_TEST_PDF_SURFACE
  296. /* adapted from pdf2png.c */
  297. static const char *
  298. _poppler_render_page (const char *filename,
  299. const char *page_label,
  300. cairo_surface_t **surface_out)
  301. {
  302. PopplerDocument *document;
  303. PopplerPage *page;
  304. double width, height;
  305. GError *error = NULL;
  306. gchar *absolute, *uri;
  307. cairo_surface_t *surface;
  308. cairo_t *cr;
  309. cairo_status_t status;
  310. if (g_path_is_absolute (filename)) {
  311. absolute = g_strdup (filename);
  312. } else {
  313. gchar *dir = g_get_current_dir ();
  314. absolute = g_build_filename (dir, filename, (gchar *) 0);
  315. g_free (dir);
  316. }
  317. uri = g_filename_to_uri (absolute, NULL, &error);
  318. g_free (absolute);
  319. if (uri == NULL)
  320. return error->message; /* XXX g_error_free (error) */
  321. document = poppler_document_new_from_file (uri, NULL, &error);
  322. g_free (uri);
  323. if (document == NULL)
  324. return error->message; /* XXX g_error_free (error) */
  325. page = poppler_document_get_page_by_label (document, page_label);
  326. g_object_unref (document);
  327. if (page == NULL)
  328. return "page not found";
  329. poppler_page_get_size (page, &width, &height);
  330. surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
  331. cr = cairo_create (surface);
  332. cairo_set_source_rgb (cr, 1., 1., 1.);
  333. cairo_paint (cr);
  334. cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA);
  335. poppler_page_render (page, cr);
  336. g_object_unref (page);
  337. cairo_pop_group_to_source (cr);
  338. cairo_paint (cr);
  339. status = cairo_status (cr);
  340. cairo_destroy (cr);
  341. if (status) {
  342. cairo_surface_destroy (surface);
  343. return cairo_status_to_string (status);
  344. }
  345. *surface_out = surface;
  346. return NULL;
  347. }
  348. static const char *
  349. pdf_convert (char **argv, int fd)
  350. {
  351. const char *err;
  352. cairo_surface_t *surface = NULL; /* silence compiler warning */
  353. err = _poppler_render_page (argv[0], argv[1], &surface);
  354. if (err != NULL)
  355. return err;
  356. err = write_ppm (surface, fd);
  357. cairo_surface_destroy (surface);
  358. return err;
  359. }
  360. #else
  361. static const char *
  362. pdf_convert (char **argv, int fd)
  363. {
  364. return "compiled without PDF support.";
  365. }
  366. #endif
  367. #if CAIRO_CAN_TEST_SVG_SURFACE
  368. static const char *
  369. _rsvg_render_page (const char *filename,
  370. cairo_surface_t **surface_out)
  371. {
  372. RsvgHandle *handle;
  373. RsvgDimensionData dimensions;
  374. GError *error = NULL;
  375. cairo_surface_t *surface;
  376. cairo_t *cr;
  377. cairo_status_t status;
  378. handle = rsvg_handle_new_from_file (filename, &error);
  379. if (handle == NULL)
  380. return error->message; /* XXX g_error_free */
  381. rsvg_handle_get_dimensions (handle, &dimensions);
  382. surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
  383. dimensions.width,
  384. dimensions.height);
  385. cr = cairo_create (surface);
  386. rsvg_handle_render_cairo (handle, cr);
  387. g_object_unref (handle);
  388. status = cairo_status (cr);
  389. cairo_destroy (cr);
  390. if (status) {
  391. cairo_surface_destroy (surface);
  392. return cairo_status_to_string (status);
  393. }
  394. *surface_out = surface;
  395. return NULL;
  396. }
  397. static const char *
  398. svg_convert (char **argv, int fd)
  399. {
  400. const char *err;
  401. cairo_surface_t *surface = NULL; /* silence compiler warning */
  402. err = _rsvg_render_page (argv[0], &surface);
  403. if (err != NULL)
  404. return err;
  405. err = write_ppm (surface, fd);
  406. cairo_surface_destroy (surface);
  407. return err;
  408. }
  409. #else
  410. static const char *
  411. svg_convert (char **argv, int fd)
  412. {
  413. return "compiled without SVG support.";
  414. }
  415. #endif
  416. #if CAIRO_HAS_SPECTRE
  417. static const char *
  418. _spectre_render_page (const char *filename,
  419. const char *page_label,
  420. cairo_surface_t **surface_out)
  421. {
  422. static const cairo_user_data_key_t key;
  423. SpectreDocument *document;
  424. SpectreStatus status;
  425. int width, height, stride;
  426. unsigned char *pixels;
  427. cairo_surface_t *surface;
  428. document = spectre_document_new ();
  429. spectre_document_load (document, filename);
  430. status = spectre_document_status (document);
  431. if (status) {
  432. spectre_document_free (document);
  433. return spectre_status_to_string (status);
  434. }
  435. if (page_label) {
  436. SpectrePage *page;
  437. SpectreRenderContext *rc;
  438. page = spectre_document_get_page_by_label (document, page_label);
  439. spectre_document_free (document);
  440. if (page == NULL)
  441. return "page not found";
  442. spectre_page_get_size (page, &width, &height);
  443. rc = spectre_render_context_new ();
  444. spectre_render_context_set_page_size (rc, width, height);
  445. spectre_page_render (page, rc, &pixels, &stride);
  446. spectre_render_context_free (rc);
  447. status = spectre_page_status (page);
  448. spectre_page_free (page);
  449. if (status) {
  450. free (pixels);
  451. return spectre_status_to_string (status);
  452. }
  453. } else {
  454. spectre_document_get_page_size (document, &width, &height);
  455. spectre_document_render (document, &pixels, &stride);
  456. spectre_document_free (document);
  457. }
  458. surface = cairo_image_surface_create_for_data (pixels,
  459. CAIRO_FORMAT_RGB24,
  460. width, height,
  461. stride);
  462. cairo_surface_set_user_data (surface, &key,
  463. pixels, (cairo_destroy_func_t) free);
  464. *surface_out = surface;
  465. return NULL;
  466. }
  467. static const char *
  468. ps_convert (char **argv, int fd)
  469. {
  470. const char *err;
  471. cairo_surface_t *surface = NULL; /* silence compiler warning */
  472. err = _spectre_render_page (argv[0], argv[1], &surface);
  473. if (err != NULL)
  474. return err;
  475. err = write_ppm (surface, fd);
  476. cairo_surface_destroy (surface);
  477. return err;
  478. }
  479. #else
  480. static const char *
  481. ps_convert (char **argv, int fd)
  482. {
  483. return "compiled without PostScript support.";
  484. }
  485. #endif
  486. static const char *
  487. convert (char **argv, int fd)
  488. {
  489. static const struct converter {
  490. const char *type;
  491. const char *(*func) (char **, int);
  492. } converters[] = {
  493. { "cs", cs_convert },
  494. { "pdf", pdf_convert },
  495. { "ps", ps_convert },
  496. { "svg", svg_convert },
  497. { NULL, NULL }
  498. };
  499. const struct converter *converter = converters;
  500. char *type;
  501. type = strrchr (argv[0], '.');
  502. if (type == NULL)
  503. return "no file extension";
  504. type++;
  505. while (converter->type) {
  506. if (strcmp (type, converter->type) == 0)
  507. return converter->func (argv, fd);
  508. converter++;
  509. }
  510. return "no converter";
  511. }
  512. #if CAN_RUN_AS_DAEMON
  513. static int
  514. _getline (int fd, char **linep, size_t *lenp)
  515. {
  516. char *line;
  517. size_t len, i;
  518. ssize_t ret;
  519. line = *linep;
  520. if (line == NULL) {
  521. line = malloc (1024);
  522. if (line == NULL)
  523. return -1;
  524. line[0] = '\0';
  525. len = 1024;
  526. } else
  527. len = *lenp;
  528. /* XXX simple, but ugly! */
  529. i = 0;
  530. do {
  531. if (i == len - 1) {
  532. char *nline;
  533. nline = realloc (line, len + 1024);
  534. if (nline == NULL)
  535. goto out;
  536. line = nline;
  537. len += 1024;
  538. }
  539. ret = read (fd, line + i, 1);
  540. if (ret == -1 || ret == 0)
  541. goto out;
  542. } while (line[i++] != '\n');
  543. out:
  544. line[i] = '\0';
  545. *linep = line;
  546. *lenp = len;
  547. return i-1;
  548. }
  549. static int
  550. split_line (char *line, char *argv[], int max_argc)
  551. {
  552. int i = 0;
  553. max_argc--; /* leave one spare for the trailing NULL */
  554. argv[i++] = line;
  555. while (i < max_argc && (line = strchr (line, ' ')) != NULL) {
  556. *line++ = '\0';
  557. argv[i++] = line;
  558. }
  559. /* chomp the newline */
  560. line = strchr (argv[i-1], '\n');
  561. if (line != NULL)
  562. *line = '\0';
  563. argv[i] = NULL;
  564. return i;
  565. }
  566. static int
  567. any2ppm_daemon_exists (void)
  568. {
  569. struct stat st;
  570. int fd;
  571. char buf[80];
  572. int pid;
  573. int ret;
  574. if (stat (SOCKET_PATH, &st) < 0)
  575. return 0;
  576. fd = open (SOCKET_PATH ".pid", O_RDONLY);
  577. if (fd < 0)
  578. return 0;
  579. pid = 0;
  580. ret = read (fd, buf, sizeof (buf) - 1);
  581. if (ret > 0) {
  582. buf[ret] = '\0';
  583. pid = atoi (buf);
  584. }
  585. close (fd);
  586. return pid > 0 && kill (pid, 0) == 0;
  587. }
  588. static int
  589. write_pid_file (void)
  590. {
  591. int fd;
  592. char buf[80];
  593. int ret;
  594. fd = open (SOCKET_PATH ".pid", O_CREAT | O_TRUNC | O_WRONLY, 0666);
  595. if (fd < 0)
  596. return 0;
  597. ret = sprintf (buf, "%d\n", getpid ());
  598. ret = write (fd, buf, ret) == ret;
  599. close (fd);
  600. return ret;
  601. }
  602. static int
  603. open_devnull_to_fd (int want_fd, int flags)
  604. {
  605. int error;
  606. int got_fd;
  607. close (want_fd);
  608. got_fd = open("/dev/null", flags | O_CREAT, 0700);
  609. if (got_fd == -1)
  610. return -1;
  611. error = dup2 (got_fd, want_fd);
  612. close (got_fd);
  613. return error;
  614. }
  615. static int
  616. daemonize (void)
  617. {
  618. void (*oldhup) (int);
  619. /* Let the parent go. */
  620. switch (fork ()) {
  621. case -1: return -1;
  622. case 0: break;
  623. default: _exit (0);
  624. }
  625. /* Become session leader. */
  626. if (setsid () == -1)
  627. return -1;
  628. /* Refork to yield session leadership. */
  629. oldhup = signal (SIGHUP, SIG_IGN);
  630. switch (fork ()) { /* refork to yield session leadership. */
  631. case -1: return -1;
  632. case 0: break;
  633. default: _exit (0);
  634. }
  635. signal (SIGHUP, oldhup);
  636. /* Establish stdio. */
  637. if (open_devnull_to_fd (0, O_RDONLY) == -1)
  638. return -1;
  639. if (open_devnull_to_fd (1, O_WRONLY | O_APPEND) == -1)
  640. return -1;
  641. if (dup2 (1, 2) == -1)
  642. return -1;
  643. return 0;
  644. }
  645. static const char *
  646. any2ppm_daemon (void)
  647. {
  648. int timeout = TIMEOUT;
  649. struct pollfd pfd;
  650. int sk, fd;
  651. long flags;
  652. struct sockaddr_un addr;
  653. char *line = NULL;
  654. size_t len = 0;
  655. #ifdef SIGPIPE
  656. signal (SIGPIPE, SIG_IGN);
  657. #endif
  658. /* XXX racy! */
  659. if (getenv ("ANY2PPM_FORCE") == NULL && any2ppm_daemon_exists ())
  660. return "any2ppm daemon already running";
  661. unlink (SOCKET_PATH);
  662. sk = socket (PF_UNIX, SOCK_STREAM, 0);
  663. if (sk == -1)
  664. return "unable to create socket";
  665. memset (&addr, 0, sizeof (addr));
  666. addr.sun_family = AF_UNIX;
  667. strcpy (addr.sun_path, SOCKET_PATH);
  668. if (bind (sk, (struct sockaddr *) &addr, sizeof (addr)) == -1) {
  669. close (sk);
  670. return "unable to bind socket";
  671. }
  672. flags = fcntl (sk, F_GETFL);
  673. if (flags == -1 || fcntl (sk, F_SETFL, flags | O_NONBLOCK) == -1) {
  674. close (sk);
  675. return "unable to set socket to non-blocking";
  676. }
  677. if (listen (sk, 5) == -1) {
  678. close (sk);
  679. return "unable to listen on socket";
  680. }
  681. /* ready for client connection - detach from parent/terminal */
  682. if (getenv ("ANY2PPM_NODAEMON") == NULL && daemonize () == -1) {
  683. close (sk);
  684. return "unable to detach from parent";
  685. }
  686. if (! write_pid_file ()) {
  687. close (sk);
  688. return "unable to write pid file";
  689. }
  690. if (getenv ("ANY2PPM_TIMEOUT") != NULL) {
  691. timeout = atoi (getenv ("ANY2PPM_TIMEOUT"));
  692. if (timeout == 0)
  693. timeout = -1;
  694. if (timeout > 0)
  695. timeout *= 1000; /* convert env (in seconds) to milliseconds */
  696. }
  697. pfd.fd = sk;
  698. pfd.events = POLLIN;
  699. pfd.revents = 0; /* valgrind */
  700. while (poll (&pfd, 1, timeout) > 0) {
  701. while ((fd = accept (sk, NULL, NULL)) != -1) {
  702. if (_getline (fd, &line, &len) != -1) {
  703. char *argv[10];
  704. if (split_line (line, argv, ARRAY_LENGTH (argv)) > 0) {
  705. const char *err;
  706. err = convert (argv, fd);
  707. if (err != NULL) {
  708. FILE *file = fopen (".any2ppm.errors", "a");
  709. if (file != NULL) {
  710. fprintf (file,
  711. "Failed to convert '%s': %s\n",
  712. argv[0], err);
  713. fclose (file);
  714. }
  715. }
  716. }
  717. }
  718. close (fd);
  719. }
  720. }
  721. close (sk);
  722. unlink (SOCKET_PATH);
  723. unlink (SOCKET_PATH ".pid");
  724. free (line);
  725. return NULL;
  726. }
  727. #else
  728. static const char *
  729. any2ppm_daemon (void)
  730. {
  731. return "daemon not compiled in.";
  732. }
  733. #endif
  734. int
  735. main (int argc, char **argv)
  736. {
  737. const char *err;
  738. #if CAIRO_CAN_TEST_PDF_SURFACE || CAIRO_CAN_TEST_SVG_SURFACE
  739. #if GLIB_MAJOR_VERSION <= 2 && GLIB_MINOR_VERSION <= 34
  740. g_type_init ();
  741. #endif
  742. #endif
  743. #if CAIRO_CAN_TEST_SVG_SURFACE
  744. rsvg_set_default_dpi (72.0);
  745. #endif
  746. #if defined(_WIN32) && !defined (__CYGWIN__)
  747. _setmode (1, _O_BINARY);
  748. #endif
  749. if (argc == 1)
  750. err = any2ppm_daemon ();
  751. else
  752. err = convert (argv + 1, 1);
  753. if (err != NULL) {
  754. fprintf (stderr, "Failed to run converter: %s\n", err);
  755. return EXIT_FAILURE;
  756. }
  757. return EXIT_SUCCESS;
  758. }