| foomatic-rip failure status fix |
| |
| Changes execution of renderer thread in the foomatic-rip package to fail |
| whenever any of its individual sub-comands fails. |
| |
| Parent process now ignores SIGPIPE calls from upstream/downstream CUPS filters, |
| per https://www.cups.org/doc/api-filter.html, while correctly noting child |
| process failures and exiting accordingly. |
| |
| NOTE: Child processes still abort on SIGPIPE. It is now the responsibility |
| of the parent to note this crash and exit gracefully. |
| |
| Reported here: |
| |
| https://bugs.linuxfoundation.org/show_bug.cgi?id=1412 |
| |
| diff -u filter/foomatic-rip/foomaticrip.c filter-new/foomatic-rip/foomaticrip.c |
| --- filter/foomatic-rip/foomaticrip.c 2015-10-20 07:59:20.000000000 -0700 |
| +++ filter-new/foomatic-rip/foomaticrip.c 2017-09-26 10:37:23.747220621 -0700 |
| @@ -517,7 +517,7 @@ |
| while (isspace(*p++) && left-- > 0) |
| ; |
| |
| - fwrite((void *)p, left, 1, postpipe); |
| + fwrite_or_die((void *)p, left, 1, postpipe); |
| fflush(postpipe); |
| } |
| |
| @@ -572,7 +572,7 @@ |
| } |
| } |
| |
| - n = fread(buf, 1, sizeof(buf) - 1, file); |
| + n = fread_or_die(buf, 1, sizeof(buf) - 1, file); |
| buf[n] = '\0'; |
| type = guess_file_type(buf, n, &startpos); |
| /* We do not use any JCL preceeded to the inputr data, as it is simply |
| @@ -745,6 +745,7 @@ |
| |
| signal(SIGTERM, signal_terminate); |
| signal(SIGINT, signal_terminate); |
| + signal(SIGPIPE, SIG_IGN); |
| |
| |
| config_from_file(CONFIG_PATH "/filter.conf"); |
| diff -u filter/foomatic-rip/pdf.c filter-new/foomatic-rip/pdf.c |
| --- filter/foomatic-rip/pdf.c 2015-10-09 18:32:52.000000000 -0700 |
| +++ filter-new/foomatic-rip/pdf.c 2017-09-26 10:37:23.751220608 -0700 |
| @@ -56,7 +56,7 @@ |
| if (!pd) |
| rip_die(EXIT_STARVED, "Failed to execute ghostscript to determine number of input pages!\n"); |
| |
| - bytes = fread(output, 1, 31, pd); |
| + bytes = fread_or_die(output, 1, 31, pd); |
| pclose(pd); |
| |
| if (bytes <= 0 || sscanf(output, "PageCount: %d", &pagecount) < 1) |
| diff -u filter/foomatic-rip/postscript.c filter-new/foomatic-rip/postscript.c |
| --- filter/foomatic-rip/postscript.c 2015-07-04 04:21:47.000000000 -0700 |
| +++ filter-new/foomatic-rip/postscript.c 2017-09-26 10:36:29.279398863 -0700 |
| @@ -1032,14 +1032,14 @@ |
| |
| if (!isempty(psfifo->data)) { |
| /* Send psfifo to renderer */ |
| - fwrite(psfifo->data, psfifo->len, 1, rendererhandle); |
| + fwrite_or_die(psfifo->data, psfifo->len, 1, rendererhandle); |
| /* flush psfifo */ |
| dstrclear(psfifo); |
| } |
| |
| /* Send line to renderer */ |
| if (!printprevpage) { |
| - fwrite(line->data, line->len, 1, rendererhandle); |
| + fwrite_or_die(line->data, line->len, 1, rendererhandle); |
| |
| while (stream_next_line(line, stream) > 0) { |
| if (startswith(line->data, "%%")) { |
| @@ -1049,7 +1049,7 @@ |
| break; |
| } |
| else { |
| - fwrite(line->data, line->len, 1, rendererhandle); |
| + fwrite_or_die(line->data, line->len, 1, rendererhandle); |
| linect++; |
| } |
| } |
| @@ -1141,14 +1141,14 @@ |
| |
| if (psfifo->len) { |
| /* Send psfifo to the renderer */ |
| - fwrite(psfifo->data, psfifo->len, 1, rendererhandle); |
| + fwrite_or_die(psfifo->data, psfifo->len, 1, rendererhandle); |
| dstrclear(psfifo); |
| } |
| |
| /* Print the rest of the input data */ |
| if (more_stuff) { |
| while (stream_next_line(tmp, stream)) |
| - fwrite(tmp->data, tmp->len, 1, rendererhandle); |
| + fwrite_or_die(tmp->data, tmp->len, 1, rendererhandle); |
| } |
| } |
| |
| @@ -1197,7 +1197,7 @@ |
| |
| /* Feed the PostScript header and the FIFO contents */ |
| if (prepend) |
| - fwrite(prepend->data, prepend->len, 1, kid3in); |
| + fwrite_or_die(prepend->data, prepend->len, 1, kid3in); |
| |
| /* We are the parent, return glob to the file handle */ |
| *fd = kid3in; |
| diff -u filter/foomatic-rip/process.c filter-new/foomatic-rip/process.c |
| --- filter/foomatic-rip/process.c 2015-07-04 04:21:47.000000000 -0700 |
| +++ filter-new/foomatic-rip/process.c 2017-09-25 12:54:46.279584580 -0700 |
| @@ -125,6 +125,10 @@ |
| } |
| |
| if (pid == 0) { /* Child */ |
| + |
| + // Reset sigpipe behavior to default for all children |
| + signal(SIGPIPE, SIG_DFL); |
| + |
| if (pipe_in) { |
| close(pfdin[1]); |
| in = fdopen(pfdin[0], "r"); |
| @@ -179,7 +183,7 @@ |
| if (out && dup2(fileno(out), fileno(stdout)) < 0) |
| rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "%s: Could not dup stdout\n", (const char *)cmd); |
| |
| - execl(get_modern_shell(), get_modern_shell(), "-c", (const char *)cmd, (char *)NULL); |
| + execl(get_modern_shell(), get_modern_shell(), "-e", "-c", (const char *)cmd, (char *)NULL); |
| |
| _log("Error: Executing \"%s -c %s\" failed (%s).\n", get_modern_shell(), (const char *)cmd, strerror(errno)); |
| return EXIT_PRNERR_NORETRY_BAD_SETTINGS; |
| diff -u filter/foomatic-rip/renderer.c filter-new/foomatic-rip/renderer.c |
| --- filter/foomatic-rip/renderer.c 2015-07-04 04:21:47.000000000 -0700 |
| +++ filter-new/foomatic-rip/renderer.c 2017-09-26 10:37:23.751220608 -0700 |
| @@ -52,7 +52,7 @@ |
| return 0; |
| } |
| |
| - bytes = fread(output, 1, 10, pd); |
| + bytes = fread_or_die(output, 1, 10, pd); |
| pclose(pd); |
| |
| if (bytes > 0 && startswith(output, "hello")) |
| @@ -288,7 +288,7 @@ |
| * also contains the "<esc>%-12345X" which has to be in the beginning |
| * of the job */ |
| if (p) |
| - fwrite(original_opts[0], 1, p - original_opts[0], stream); |
| + fwrite_or_die(original_opts[0], 1, p - original_opts[0], stream); |
| else |
| fprintf(stream, "%s\n", original_opts[0]); |
| |
| @@ -392,7 +392,7 @@ |
| |
| /* A JCL trailer */ |
| if (argv_count(jclprepend) > 0 && !driverjcl) |
| - fwrite(jclappend->data, jclappend->len, 1, fileh); |
| + fwrite_or_die(jclappend->data, jclappend->len, 1, fileh); |
| |
| fclose(in); |
| if (fclose(fileh) != 0) |
| diff -u filter/foomatic-rip/util.c filter-new/foomatic-rip/util.c |
| --- filter/foomatic-rip/util.c 2015-12-12 15:21:05.000000000 -0800 |
| +++ filter-new/foomatic-rip/util.c 2017-09-26 10:37:23.759220582 -0700 |
| @@ -29,6 +29,7 @@ |
| #include <unistd.h> |
| #include <stdarg.h> |
| #include <assert.h> |
| +#include <errno.h> |
| |
| |
| const char* shellescapes = "|;<>&!$\'\"`#*?()[]{}"; |
| @@ -291,6 +292,22 @@ |
| return psrc +1; |
| } |
| |
| +size_t fwrite_or_die(const void* ptr, size_t size, size_t count, FILE* stream) { |
| + size_t res = fwrite(ptr, size, count, stream); |
| + if (ferror(stream)) |
| + rip_die(EXIT_PRNERR, "Encountered error %s during fwrite", strerror(errno)); |
| + |
| + return res; |
| +} |
| + |
| +size_t fread_or_die(void* ptr, size_t size, size_t count, FILE* stream) { |
| + size_t res = fread(ptr, size, count, stream); |
| + if (ferror(stream)) |
| + rip_die(EXIT_PRNERR, "Encountered error %s during fread", strerror(errno)); |
| + |
| + return res; |
| +} |
| + |
| int find_in_path(const char *progname, const char *paths, char *found_in) |
| { |
| char *pathscopy; |
| @@ -1111,15 +1128,15 @@ |
| |
| if (alreadyread && alreadyread_len) |
| { |
| - if (fwrite(alreadyread, 1, alreadyread_len, dest) < alreadyread_len) |
| + if (fwrite_or_die(alreadyread, 1, alreadyread_len, dest) < alreadyread_len) |
| { |
| _log("Could not write to temp file\n"); |
| return 0; |
| } |
| } |
| |
| - while ((bytes = fread(buf, 1, 8192, src))) |
| - fwrite(buf, 1, bytes, dest); |
| + while ((bytes = fread_or_die(buf, 1, 8192, src))) |
| + fwrite_or_die(buf, 1, bytes, dest); |
| |
| return !ferror(src) && !ferror(dest); |
| } |
| diff -u filter/foomatic-rip/util.h filter-new/foomatic-rip/util.h |
| --- filter/foomatic-rip/util.h 2015-06-26 08:45:26.000000000 -0700 |
| +++ filter-new/foomatic-rip/util.h 2017-09-26 10:38:16.443048131 -0700 |
| @@ -98,6 +98,11 @@ |
| */ |
| const char * strncpy_tochar(char *dest, const char *src, size_t max, const char *stopchars); |
| |
| +/* "safe" versions of standard <cstdio> fwrite and fread that will cause the |
| + * program to exit gracefully when a write/read fails */ |
| +size_t fwrite_or_die(const void* ptr, size_t size, size_t count, FILE* stream); |
| +size_t fread_or_die(void* ptr, size_t size, size_t count, FILE* stream); |
| + |
| /* 'paths' is a colon seperated list of paths (like $PATH) |
| * 'found_in' may be NULL if it is not needed */ |
| int find_in_path(const char *progname, const char *paths, char *found_in); |