Blame SOURCES/netpbm-pnmtops-hangs.patch

a996cb
diff --git a/converter/other/pnmtops.c b/converter/other/pnmtops.c
a996cb
index e393931..e1f2d18 100644
a996cb
--- a/converter/other/pnmtops.c
a996cb
+++ b/converter/other/pnmtops.c
a996cb
@@ -42,6 +42,8 @@
a996cb
 #include <unistd.h>
a996cb
 #include <assert.h>
a996cb
 #include <string.h>
a996cb
+#include <errno.h>
a996cb
+#include <signal.h>
a996cb
 #ifndef NOFLATE
a996cb
 #include <zlib.h>
a996cb
 #endif
a996cb
@@ -52,6 +54,37 @@
a996cb
 #include "shhopt.h"
a996cb
 #include "nstring.h"
a996cb
 
a996cb
+
a996cb
+
a996cb
+static void
a996cb
+setSignals() {
a996cb
+/*----------------------------------------------------------------------------
a996cb
+   Set up the process-global signal-related state.
a996cb
+
a996cb
+   Note that we can't rely on defaults, because much of this is inherited
a996cb
+   from the process that forked and exec'ed this program.
a996cb
+-----------------------------------------------------------------------------*/
a996cb
+    /* See waitForChildren() for why we do this to SIGCHLD */
a996cb
+
a996cb
+    struct sigaction sigchldAction;
a996cb
+    int rc;
a996cb
+    sigset_t emptySet;
a996cb
+
a996cb
+    sigemptyset(&emptySet);
a996cb
+
a996cb
+    sigchldAction.sa_handler = SIG_DFL;
a996cb
+    sigchldAction.sa_mask = emptySet;
a996cb
+    sigchldAction.sa_flags = SA_NOCLDSTOP;
a996cb
+
a996cb
+    rc = sigaction(SIGCHLD, &sigchldAction, NULL);
a996cb
+
a996cb
+    if (rc != 0)
a996cb
+        pm_error("sigaction() to set up signal environment failed, "
a996cb
+                 "errno = %d (%s)", errno, strerror(errno));
a996cb
+}
a996cb
+
a996cb
+
a996cb
+
a996cb
 struct cmdlineInfo {
a996cb
     /* All the information the user supplied in the command line,
a996cb
        in a form easy for the program to use.
a996cb
@@ -256,21 +289,17 @@ parseCommandLine(int argc, const char ** argv,
a996cb
     validateCompDimension(width, 72, "-width value");
a996cb
     validateCompDimension(height, 72, "-height value");
a996cb
     
a996cb
-    overflow2(width, 72);
a996cb
     cmdlineP->width  = width * 72;
a996cb
-    overflow2(height, 72);
a996cb
     cmdlineP->height = height * 72;
a996cb
 
a996cb
     if (imagewidthSpec) {
a996cb
         validateCompDimension(imagewidth, 72, "-imagewidth value");
a996cb
-        overflow2(imagewidth, 72);
a996cb
         cmdlineP->imagewidth = imagewidth * 72;
a996cb
     }
a996cb
     else
a996cb
         cmdlineP->imagewidth = 0;
a996cb
     if (imageheightSpec) {
a996cb
-        validateCompDimension(imageheight, 72, "-imageheight value");
a996cb
-        overflow2(imageheight, 72);
a996cb
+        validateCompDimension(imagewidth, 72, "-imageheight value");
a996cb
         cmdlineP->imageheight = imageheight * 72;
a996cb
     }
a996cb
     else
a996cb
@@ -339,6 +368,33 @@ basebasename(const char * const filespec) {
a996cb
 
a996cb
 
a996cb
 
a996cb
+static void
a996cb
+writeFile(const unsigned char * const buffer,
a996cb
+          size_t                const writeCt,
a996cb
+          const char *          const name,
a996cb
+          FILE *                const ofP) {
a996cb
+
a996cb
+    size_t writtenCt;
a996cb
+
a996cb
+    writtenCt = fwrite(buffer, 1, writeCt, ofP);
a996cb
+
a996cb
+    if (writtenCt != writeCt)
a996cb
+        pm_error("Error writing to %s output file", name);
a996cb
+}
a996cb
+
a996cb
+
a996cb
+
a996cb
+static void
a996cb
+writeFileChar(const char * const buffer,
a996cb
+              size_t       const writeCt,
a996cb
+              const char * const name,
a996cb
+              FILE *       const ofP) {
a996cb
+
a996cb
+    writeFile((const unsigned char *)buffer, writeCt, name, ofP);
a996cb
+}
a996cb
+
a996cb
+
a996cb
+
a996cb
 #define MAX_FILTER_CT 10
a996cb
     /* The maximum number of filters this code is capable of applying */
a996cb
 
a996cb
@@ -498,18 +554,12 @@ flateFilter(FILE *          const ifP,
a996cb
         */
a996cb
         do {
a996cb
             unsigned int have;
a996cb
-            size_t bytesWritten;
a996cb
 
a996cb
             strm.avail_out = chunkSz;
a996cb
             strm.next_out = out;
a996cb
             deflate(&strm, flush);
a996cb
             have = chunkSz - strm.avail_out;
a996cb
-            bytesWritten = fwrite(out, 1, have, ofP);
a996cb
-            if (ferror(ofP) || bytesWritten != have) {
a996cb
-                deflateEnd(&strm;;
a996cb
-                pm_error("Error writing to internal pipe during "
a996cb
-                         "flate compression.");
a996cb
-            }
a996cb
+            writeFile(out, have, "flate filter", ofP);
a996cb
         } while (strm.avail_out == 0);
a996cb
         assert(strm.avail_in == 0);     /* all input is used */
a996cb
 
a996cb
@@ -554,7 +604,7 @@ rlePutBuffer (unsigned int    const repeat,
a996cb
         fputc(repeatitem, fP);
a996cb
     } else {
a996cb
         fputc(count - 1, fP);
a996cb
-        fwrite(itembuf, 1, count, fP);
a996cb
+        writeFile(itembuf, count, "rlePutBuffer", fP);
a996cb
     }
a996cb
 }
a996cb
 
a996cb
@@ -677,23 +727,24 @@ asciiHexFilter(FILE *          const ifP,
a996cb
     unsigned char inbuff[40], outbuff[81];
a996cb
 
a996cb
     for (eof = false; !eof; ) {
a996cb
-        size_t bytesRead;
a996cb
+        size_t readCt;
a996cb
 
a996cb
-        bytesRead = fread(inbuff, 1, 40, ifP);
a996cb
+        readCt = fread(inbuff, 1, 40, ifP);
a996cb
 
a996cb
-        if (bytesRead == 0)
a996cb
+        if (readCt == 0)
a996cb
             eof = true;
a996cb
         else {
a996cb
             unsigned int i;
a996cb
 
a996cb
-            for (i = 0; i < bytesRead; ++i) {
a996cb
+            for (i = 0; i < readCt; ++i) {
a996cb
                 int const item = inbuff[i]; 
a996cb
                 outbuff[i*2]   = hexits[item >> 4];
a996cb
                 outbuff[i*2+1] = hexits[item & 15];
a996cb
             }
a996cb
         }
a996cb
-        outbuff[bytesRead * 2] = '\n';
a996cb
-        fwrite(outbuff, 1, bytesRead*2 + 1, ofP);
a996cb
+        outbuff[readCt * 2] = '\n';
a996cb
+
a996cb
+        writeFile(outbuff, readCt * 2 + 1, "asciiHex filter", ofP);
a996cb
     }
a996cb
 
a996cb
     fclose(ifP);
a996cb
@@ -731,7 +782,8 @@ ascii85Filter(FILE *          const ifP,
a996cb
             ++count;
a996cb
 
a996cb
             if (value == 0 && count == 4) {
a996cb
-                putchar('z');  /* Ascii85 encoding z exception */
a996cb
+                writeFileChar("z", 1, "ASCII 85 filter", ofP);
a996cb
+                    /* Ascii85 encoding z exception */
a996cb
                 ++outcount;
a996cb
                 count = 0;
a996cb
             } else if (count == 4) {
a996cb
@@ -741,13 +793,14 @@ ascii85Filter(FILE *          const ifP,
a996cb
                 outbuff[1] = value % 85 + 33;
a996cb
                 outbuff[0] = value / 85 + 33;
a996cb
 
a996cb
-                fwrite(outbuff, 1, count + 1, ofP);
a996cb
+                writeFileChar(outbuff, count + 1, "ASCII 85 filter", ofP);
a996cb
+
a996cb
                 count = value = 0;
a996cb
                 outcount += 5; 
a996cb
             }
a996cb
 
a996cb
             if (outcount > 75) {
a996cb
-                putchar('\n');
a996cb
+                writeFileChar("\n", 1, "ASCII 85 filter", ofP);
a996cb
                 outcount = 0;
a996cb
             }
a996cb
         }
a996cb
@@ -763,7 +816,7 @@ ascii85Filter(FILE *          const ifP,
a996cb
         outbuff[0] = value / 85 + 33;
a996cb
         outbuff[count + 1] = '\n';
a996cb
 
a996cb
-        fwrite(outbuff, 1, count + 2, ofP);
a996cb
+        writeFileChar(outbuff, count + 2, "ASCII 85 filter", ofP);
a996cb
     }
a996cb
 
a996cb
     fclose(ifP);
a996cb
@@ -873,13 +926,22 @@ addFilter(const char *    const description,
a996cb
           OutputEncoder * const oeP,
a996cb
           FILE **         const feedFilePP,
a996cb
           pid_t *         const pidList) {
a996cb
+/*----------------------------------------------------------------------------
a996cb
+   Add a filter to the front of the chain.
a996cb
 
a996cb
-    pid_t pid;
a996cb
+   Spawn a process to do the filtering, by running function 'filter'.
a996cb
+
a996cb
+   *feedFilePP is the present head of the chain.  We make the new filter
a996cb
+   process write its output to that and get its input from a new pipe.
a996cb
+   We update *feedFilePP to the sending end of the new pipe.
a996cb
 
a996cb
+   Add to the list pidList[] the PID of the process we spawn.
a996cb
+-----------------------------------------------------------------------------*/
a996cb
     FILE * const oldFeedFileP = *feedFilePP;
a996cb
 
a996cb
     FILE * newFeedFileP;
a996cb
-        
a996cb
+    pid_t pid;
a996cb
+
a996cb
     spawnFilter(oldFeedFileP, filter, oeP, &newFeedFileP, &pid;;
a996cb
             
a996cb
     if (verbose)
a996cb
@@ -887,7 +949,7 @@ addFilter(const char *    const description,
a996cb
                    description, (unsigned)pid);
a996cb
     
a996cb
     fclose(oldFeedFileP);  /* Child keeps this open now */
a996cb
-    
a996cb
+
a996cb
     addToPidList(pidList, pid);
a996cb
 
a996cb
     *feedFilePP = newFeedFileP;
a996cb
@@ -949,6 +1011,15 @@ waitForChildren(const pid_t * const pidList) {
a996cb
    Wait for all child processes with PIDs in pidList[] to exit.
a996cb
    In pidList[], end-of-list is marked with a special zero value.
a996cb
 -----------------------------------------------------------------------------*/
a996cb
+    /* There's an odd behavior in Unix such that if you have set the
a996cb
+       action for SIGCHLD to ignore the signal (even though ignoring the
a996cb
+       signal is the default), the process' children do not become
a996cb
+       zombies.  Consequently, waitpid() always fails with ECHILD - but
a996cb
+       nonetheless waits for the child to exit.
a996cb
+    
a996cb
+       We expect the process not to have the action for SIGCHLD set that
a996cb
+       way.
a996cb
+    */
a996cb
     unsigned int i;
a996cb
 
a996cb
     for (i = 0; pidList[i]; ++i) {
a996cb
@@ -960,7 +1031,8 @@ waitForChildren(const pid_t * const pidList) {
a996cb
 
a996cb
         rc = waitpid(pidList[i], &status, 0);
a996cb
         if (rc == -1)
a996cb
-            pm_error ("waitpid() for child %u failed", i);
a996cb
+            pm_error ("waitpid() for child %u failed, errno=%d (%s)",
a996cb
+                      i, errno, strerror(errno));
a996cb
         else if (status != EXIT_SUCCESS)
a996cb
             pm_error ("Child process %u terminated abnormally", i);
a996cb
     }
a996cb
@@ -1724,7 +1796,7 @@ convertRowPbm(struct pam *     const pamP,
a996cb
         bitrow[colChars-1] <<= padRight;  /* right edge */
a996cb
     }
a996cb
 
a996cb
-    fwrite(bitrow, 1, colChars, fP); 
a996cb
+    writeFile(bitrow, colChars, "PBM reader", fP);
a996cb
 }
a996cb
 
a996cb
 
a996cb
@@ -1867,6 +1939,21 @@ convertRaster(struct pam * const inpamP,
a996cb
 
a996cb
 
a996cb
 
a996cb
+/* FILE MANAGEMENT: File management is pretty hairy here.  A filter, which
a996cb
+   runs in its own process, needs to be able to cause its output file to
a996cb
+   close because it might be an internal pipe and the next stage needs to
a996cb
+   know output is done.  So the forking process must close its copy of the
a996cb
+   file descriptor.  BUT: if the output of the filter is not an internal
a996cb
+   pipe but this program's output, then we don't want it closed when the
a996cb
+   filter terminates because we'll need it to be open for the next image
a996cb
+   the program converts (with a whole new chain of filters).
a996cb
+   
a996cb
+   To prevent the progam output file from getting closed, we pass a
a996cb
+   duplicate of it to spawnFilters() and keep the original open.
a996cb
+*/
a996cb
+
a996cb
+
a996cb
+
a996cb
 static void
a996cb
 convertPage(FILE *       const ifP, 
a996cb
             int          const turnflag, 
a996cb
@@ -1954,7 +2041,7 @@ convertPage(FILE *       const ifP,
a996cb
 
a996cb
     fflush(stdout);
a996cb
     filterChainOfP = fdopen(dup(fileno(stdout)), "w");
a996cb
-        /* spawnFilters() closes this. See FILE MANAGEMENT above */
a996cb
+        /* spawnFilters() closes this.  See FILE MANAGEMENT above */
a996cb
 
a996cb
     spawnFilters(filterChainOfP, &oe, &feedFileP, filterPidList);
a996cb
  
a996cb
@@ -1979,6 +2066,8 @@ main(int argc, const char * argv[]) {
a996cb
 
a996cb
     pm_proginit(&argc, argv);
a996cb
 
a996cb
+    setSignals();
a996cb
+
a996cb
     parseCommandLine(argc, argv, &cmdline);
a996cb
 
a996cb
     verbose = cmdline.verbose;
a996cb
@@ -1994,6 +2083,13 @@ main(int argc, const char * argv[]) {
a996cb
         name = strdup("noname");
a996cb
     else
a996cb
         name = basebasename(cmdline.inputFileName);
a996cb
+
a996cb
+    /* This program manages file descriptors in a way that assumes
a996cb
+       that new files will get file descriptor numbers less than 10,
a996cb
+       so we close superfluous files now to make sure that's true.
a996cb
+    */
a996cb
+    closeAllBut(fileno(ifP), fileno(stdout), fileno(stderr));
a996cb
+
a996cb
     {
a996cb
         int eof;  /* There are no more images in the input file */
a996cb
         unsigned int imageSeq;