we have now a working foomatic-rip
author"Luc Saillard <luc@saillard.org>"
Wed Jun 04 17:51:24 2008 +0200 (3 months ago)
changeset 52755ae39670c0
parent 51096867bc19cd
child 53c53b7d56a0c8
we have now a working foomatic-rip
src/foomatic-rip.c
--- a/src/foomatic-rip.c Wed Jun 04 11:38:31 2008 +0200
+++ b/src/foomatic-rip.c Wed Jun 04 17:51:24 2008 +0200
@@ -30,6 +30,14 @@
#include <stdlib.h>
#include <string.h>
#include <locale.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+
#include "ppd.h"
@@ -40,7 +48,7 @@ static const char *cups_filters_path = "
static const char *cups_filters_path = "/usr/lib/cups/filter";
static const char *ghostscript_for_cups = "gs -dQUIET -dDEBUG -dPARANOIDSAFER -dNOPAUSE -dBATCH -dNOMEDIAATTRS -sDEVICE=cups -sOutputFile=-%W -";
-static int opt_debug;
+static int opt_debug = 1;
static int opt_print_version;
static int opt_verbose;
static int opt_spooler;
@@ -66,13 +74,15 @@ static char *string_replace_markers(cons
static char *string_replace_markers(const char *string,
const char *cups_options_string,
const char *cups_profile_string);
+static int string_read_from_pipe(GString *buffer, int fd);
+static int string_write_to_pipe(GString *buffer, int fd);
//static char *string_remove_unprintables(char *string);
static void cups_setup_font_path_for_ghostscript(void);
static void cups_get_parameters(int argc, char **argv);
static int cups_setup_with_ppd(struct ppd_t *ppd);
static char *cups_get_filter_from_mime_type(const char *mime_type, const char *program);
static char *cups_get_filter_command(struct ppd_t *ppd);
-static int send_job_to_ghostscript(const char *input_document, char **gs_argv);
+static int send_job_to_filter_command(const char *input_document, char **gs_argv);
void die(const char *fmt, ...);
void error(const char *fmt, ... );
@@ -146,9 +156,7 @@ main(int argc, char **argv)
ppd_set_options(ppd, job_options);
if (opt_debug)
- {
- ppd_print_options(ppd);
- }
+ ppd_print_options(ppd);
cups_setup_with_ppd(ppd);
@@ -158,8 +166,8 @@ main(int argc, char **argv)
trace("printer command line = %s\n", cups_filter_command);
- send_job_to_ghostscript(job_filename, gs_argv);
-
+ if (send_job_to_filter_command(job_filename, gs_argv) == FALSE)
+ exit(1);
return 0;
}
@@ -508,7 +516,48 @@ cups_get_filter_from_mime_type(const cha
-
+/*
+ * Foomatic provide a wrapper for calling ghostscript, but when it is not
+ * avaible (because perl is not installed) we need to change the command line.
+ */
+static char **
+rewrite_filter_command_if_using_ghostscript(char **gs_argv)
+{
+ int argv_len = g_strv_length(gs_argv);
+ char **new_argv;
+ unsigned int i, j;
+
+ /* The filter is not ghostscript ? don't try to parse the argument */
+ if (strcmp(gs_argv[0], "gs"))
+ return g_strdupv(gs_argv);
+
+ /* We don't have foomatic-wrapper, so we must do the job by hand */
+ j= 0;
+ new_argv = g_new0(char *, argv_len + 5);
+ new_argv[j++] = g_strdup("gs");
+ new_argv[j++] = g_strdup("-sstdout=%stderr");
+
+ for (i=1; gs_argv[i] ; i++)
+ {
+ if (strcmp(gs_argv[i], "-sOutputFile=-") == 0)
+ new_argv[j++] = g_strdup("-sOutputFile=%stdout");
+ else if ((strcmp(gs_argv[i], "-") == 0) || (strcmp(gs_argv[i], "/dev/fd/0") == 0))
+ new_argv[j++] = g_strdup("-_");
+ else if (strcmp(gs_argv[i], "-dQUIET") == 0)
+ {
+ }
+ else if (strcmp(gs_argv[i], "-q") == 0)
+ {
+ /* remove the -quiet option because we can report any error to the upper layout */
+ }
+ else
+ {
+ new_argv[j++] = g_strdup(gs_argv[i]);
+ }
+ }
+
+ return new_argv;
+}
@@ -517,104 +566,213 @@ cups_get_filter_from_mime_type(const cha
* Print the filename input_document, and output the result to filedescriptor
* output_printer_fd
*/
-static int
-send_job_to_ghostscript(const char *input_document, char **gs_argv)
-{
+static gboolean
+send_job_to_filter_command(const char *input_document, char **filter_command)
+{
+ fd_set rfds, wfds;
+ char **new_filter_command;
+ int document_fd;
+ int pipe_stdin, pipe_stdout, pipe_stderr, pid;
+ int exit_status;
+ GString *output_stdout, *output_stderr, *input_stdin;
GError *gerror;
- gboolean status;
- char *gs_stdout;
- char *gs_stderr;
- int gs_exit_status;
- unsigned int i;
+ gboolean status, failed;
+ int ret, nfds;
unsigned int flags;
-#if 0
/* If the filename is not defined, then read the stdin */
if (input_document == NULL)
- input_fd = STDIN_FILENO;
+ document_fd = STDIN_FILENO;
else
- {
- input_fd = open(input_document, O_RDONLY);
- if (input_fd < 0)
- {
- error("Can't open file %s\n", input_document);
- return -1;
- }
- }
-#endif
-
- /* Parse any argument, and rewrite if we need to modify it */
- if (strcmp(gs_argv[0], "gs") == 0)
- {
- /* replace it by the foomatic-wrapper */
- g_free(gs_argv[0]);
- gs_argv[0] = g_strdup("foomatic-gswrapper");
- }
- for (i=1; gs_argv[i]; i++)
- {
- if (strcmp(gs_argv[i], "-sOutputFile=-") == 0)
- {
- //g_free(gs_argv[i]);
- //gs_argv[i] = g_strdup("-sOutputFile=/tmp/a.ps");
- }
- }
-
- if (0)
- {
- trace("argv:\n");
- for (i=0; gs_argv[i]; i++)
- {
- if (strcmp(gs_argv[i], "-dQUIET") == 0)
- gs_argv[i] = g_strdup("-dSAFER");
- else if (strcmp(gs_argv[i], "-q") == 0)
- gs_argv[i] = g_strdup("-dSAFER");
- }
- }
+ {
+ document_fd = open(input_document, O_RDONLY);
+ if (document_fd < 0)
+ {
+ error("Can't open file %s\n", input_document);
+ return FALSE;
+ }
+ }
+
+ new_filter_command = rewrite_filter_command_if_using_ghostscript(filter_command);
if (opt_verbose)
{
unsigned int i;
- trace("argv:\n");
- for (i=0; gs_argv[i]; i++)
- {
- trace(" %s\n", gs_argv[i]);
- }
- }
-
-
- flags = G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_SEARCH_PATH | G_SPAWN_CHILD_INHERITS_STDIN;
- status = g_spawn_sync(NULL, /* working_directory */
- gs_argv, /* argv */
- NULL, /* envp */
- flags, /* flags */
- NULL, /* child_setup */
- NULL, /* user_data */
- &gs_stdout, /* standard_output */
- &gs_stderr, /* standard_error */
- &gs_exit_status, /* exit_status */
- &gerror);
+ trace("command filter argv:\n");
+ for (i=0; new_filter_command[i]; i++)
+ {
+ trace(" %s\n", new_filter_command[i]);
+ }
+ }
+
+
+ flags = G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH;
+ status = g_spawn_async_with_pipes(NULL, /* working_directory */
+ new_filter_command, /* argv */
+ NULL, /* envp */
+ flags, /* flags */
+ NULL, /* child_setup */
+ NULL, /* user_data */
+ &pid, /* child_pid */
+ &pipe_stdin, /* standard_output */
+ &pipe_stdout, /* standard_error */
+ &pipe_stderr, /* exit_status */
+ &gerror);
if (status == FALSE)
{
- trace("g_spawn_sync failed: %s\n", gerror->message);
- trace("standard_output:\n%s\n", gs_stdout);
- trace("standard_error:\n%s\n", gs_stderr);
+ trace("g_spawn_async_with_pipes failed: %s\n", gerror->message);
g_error_free(gerror);
- g_free(gs_stdout);
- g_free(gs_stderr);
- return -1;
- }
-
- trace("exit_status = %d\n", gs_exit_status);
-
- /* Job terminated */
- trace("gs_stdout (len=%z):\n%s\n", gs_stdout);
- trace("gs_stderr:\n%s\n", gs_stderr);
-
- g_free(gs_stdout);
- g_free(gs_stderr);
-
- return 0;
+ return FALSE;
+ }
+
+ output_stdout = g_string_new(NULL);
+ output_stderr = g_string_new(NULL);
+ input_stdin = g_string_new(NULL);
+
+ failed = FALSE;
+ while (!failed && (pipe_stdout>=0 || pipe_stderr>=0 || pipe_stdin>=0 || document_fd>=0))
+ {
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+
+ if (pipe_stdout >= 0)
+ FD_SET(pipe_stdout, &rfds);
+ if (pipe_stderr >= 0)
+ FD_SET(pipe_stderr, &rfds);
+ if (document_fd >= 0)
+ FD_SET(document_fd, &rfds);
+ if (pipe_stdin >= 0 && input_stdin->len > 0)
+ FD_SET(pipe_stdin, &wfds);
+
+ nfds = pipe_stderr;
+ if (pipe_stdout > pipe_stderr)
+ nfds = pipe_stdout;
+ if (pipe_stdin > nfds)
+ nfds = pipe_stdin;
+ if (document_fd > nfds)
+ nfds = document_fd;
+
+
+
+
+ ret = select(nfds+1, &rfds, &wfds, NULL, NULL);
+ if (ret < 0)
+ {
+ if (errno == EINTR)
+ {
+ sleep(1);
+ continue;
+ }
+
+ error("select() failed. %s\n", strerror(errno));
+ /* TODO: need to free memory */
+ return FALSE;
+ }
+
+
+
+
+
+ if (pipe_stdout >= 0 && FD_ISSET(pipe_stdout, &rfds))
+ {
+ ret = string_read_from_pipe(output_stdout, pipe_stdout);
+ if (ret < 0)
+ failed=TRUE;
+ else if (ret == 0)
+ {
+ trace("closing pipe stdout\n");
+ close(pipe_stdout);
+ pipe_stdout = -1;
+ }
+ }
+
+ if (pipe_stderr >= 0 && FD_ISSET(pipe_stderr, &rfds))
+ {
+ ret = string_read_from_pipe(output_stderr, pipe_stderr);
+ if (ret < 0)
+ failed=TRUE;
+ else if (ret == 0)
+ {
+ trace("closing pipe stderr\n");
+ close(pipe_stderr);
+ pipe_stderr = -1;
+ }
+ }
+
+ if (document_fd >= 0 && FD_ISSET(document_fd, &rfds))
+ {
+ ret = string_read_from_pipe(input_stdin, document_fd);
+ if (ret < 0)
+ failed=TRUE;
+ else if (ret == 0)
+ {
+ close(document_fd);
+ document_fd = -1;
+ }
+ }
+
+ if (pipe_stdin >= 0 && FD_ISSET(pipe_stdin, &wfds))
+ {
+ ret = string_write_to_pipe(input_stdin, pipe_stdin);
+ if (ret < 0)
+ failed=TRUE;
+ else if (ret == 0)
+ {
+ close(pipe_stdin);
+ pipe_stdin = -1;
+ }
+ else if (input_stdin->len == 0 && document_fd == -1)
+ {
+ /* our input is close, and we have an empty buffer so close also the stdin of the filter */
+ close(pipe_stdin);
+ pipe_stdin = -1;
+ }
+ }
+
+ if (output_stdout->len > 0)
+ string_write_to_pipe(output_stdout, STDOUT_FILENO);
+ if (output_stderr->len > 0)
+ string_write_to_pipe(output_stderr, STDERR_FILENO);
+ }
+
+ if (pipe_stdout >= 0)
+ close(pipe_stdout);
+ if (pipe_stdin >= 0)
+ close(pipe_stdin);
+ if (pipe_stderr >= 0)
+ close(pipe_stderr);
+ if (document_fd >= 0)
+ close(document_fd);
+
+ if (output_stdout->len > 0)
+ string_write_to_pipe(output_stdout, STDOUT_FILENO);
+ if (output_stderr->len > 0)
+ string_write_to_pipe(output_stderr, STDERR_FILENO);
+
+ g_string_free(output_stdout, TRUE);
+ g_string_free(output_stderr, TRUE);
+ g_string_free(input_stdin, TRUE);
+
+ do
+ {
+ ret = waitpid(pid, &exit_status, 0);
+ } while (ret == -1 && errno == EINTR);
+ if (ret == -1)
+ error("waitpid() failed. %s\n", strerror(errno));
+
+ if (WIFSIGNALED(exit_status))
+ trace("Print process terminated by signal %d.\n", WTERMSIG(exit_status));
+ else if (WIFEXITED(exit_status))
+ {
+ trace("Print process exited with status %d.\n", WEXITSTATUS(exit_status));
+ if (WEXITSTATUS(exit_status) == 0)
+ return TRUE;
+ }
+ else
+ trace("Print process returned unknown status 0x%x.\n", exit_status);
+
+ return FALSE;
}
@@ -744,6 +902,52 @@ string_replace_markers(const char *strin
}
+static int
+string_read_from_pipe(GString *buffer, int fd)
+{
+ gssize bytes;
+ char temp_buffer[4096];
+
+ do
+ {
+ bytes = read(fd, temp_buffer, sizeof(temp_buffer));
+ }
+ while (bytes < 0 && errno == EINTR);
+
+ if (bytes < 0)
+ {
+ error("read() failed: %s\n", strerror(errno));
+ return -1;
+ }
+ else if (bytes)
+ {
+ g_string_append_len(buffer, temp_buffer, bytes);
+ }
+ return bytes;
+}
+
+static int
+string_write_to_pipe(GString *buffer, int fd)
+{
+ gssize bytes;
+
+ while (1)
+ {
+ bytes = buffer->len > 4096 ? 4096 : buffer->len;
+ bytes = write(fd, buffer->str, bytes);
+ if (bytes == -1)
+ {
+ if (errno == EINTR)
+ continue;
+ error("write() failed: %s\n", strerror(errno));
+ return -1;
+ }
+ else if (bytes)
+ g_string_erase(buffer, 0, bytes);
+ return bytes;
+ }
+}
+