]> git.ipfire.org Git - thirdparty/cups-filters.git/commitdiff
libppd: When running dynamic PPD generators wait for the process to finish
authorTill Kamppeter <till.kamppeter@gmail.com>
Fri, 26 Nov 2021 12:53:43 +0000 (13:53 +0100)
committerTill Kamppeter <till.kamppeter@gmail.com>
Fri, 26 Nov 2021 12:53:43 +0000 (13:53 +0100)
The PPD collection functions come from the cups-driverd daemon helper.
As cups-driverd did not run permanently (like cupsd or a Printer
Application) but was started for each request no sophisticated
clean-up was performed after responding to the request.

This fact was overlooked at some points when the functions were
transferred to libppd and supposed to be directly called by
permanently running Printer Applications. Here especially forked
processes for running dynamic PPD generator executables (the ones CUPS
uses in /usr/lib/cups/driver) were not waited for in the end. This
made them often dandling around as zombie processes and these could
accumulate during the life of a Printer Application process. See
https://github.com/OpenPrinting/cups-filters/issues/430.

This is fixed now by adding an appropriate function.

To avoid zombie processes dangling around during the life of a Printer
Application

ppd/ppd-collection.cxx

index 3892509475f14387739f58eeb9b631b327177653..64a4056a340c026f4a6401aac137273d6ac2315d 100644 (file)
@@ -23,6 +23,7 @@
 #include "file-private.h"
 #include "array-private.h"
 #include <regex.h>
+#include <sys/wait.h>
 
 
 /*
@@ -169,6 +170,7 @@ static cups_array_t *CreateStringsArray(const char *s);
 static int             ExecCommand(const char *command, char **argv);
 static cups_file_t     *PipeCommand(int *pid, const char *command,
                                     char **argv, uid_t user);
+static int             ClosePipeCommand(cups_file_t *fp, int pid);
 
 
 /*
@@ -776,7 +778,7 @@ ppdCollectionGetPPD(
       }
       while ((bytes = cupsFileRead(fp, buffer, sizeof(buffer))) > 0)
        bytes = write(fd, buffer, bytes);
-      cupsFileClose(fp);
+      ClosePipeCommand(fp, pid);
       close(fd);
       fp = cupsFileOpen(tempname, "r");
       unlink(tempname);
@@ -1419,7 +1421,7 @@ load_driver(const char *filename, /* I - Driver excutable file name */
       }
     }
 
-    cupsFileClose(fp);
+    ClosePipeCommand(fp, pid);
   }
   else
     if (log) log(ld, FILTER_LOGLEVEL_WARN,
@@ -2874,3 +2876,50 @@ PipeCommand(int        *pid,             /* O - Process ID or 0 on error */
 
   return (cupsFileOpenFd(fds[0], "r"));
 }
+
+
+/*
+ * 'ClosePipeCommand()' - Wait for the command called with PipeCommand() to
+ *                        finish and return the status.
+ */
+
+static int
+ClosePipeCommand(cups_file_t *fp,
+                int pid)
+{
+  int          status,          /* Exit status */
+                retval;                 /* Return value */
+
+
+ /*
+  * close the stream...
+  */
+
+  cupsFileClose(fp);
+
+ /*
+  * Wait for the child process to exit...
+  */
+
+  retval = 0;
+
+ retry_wait:
+  if (waitpid (pid, &status, 0) == -1)
+  {
+    if (errno == EINTR)
+      goto retry_wait;
+    else
+      goto out;
+  }
+
+  /* How did the filter function terminate */
+  if (WIFEXITED(status))
+    /* Via exit() anywhere or return() in the main() function */
+    retval = WEXITSTATUS(status);
+  else if (WIFSIGNALED(status))
+    /* Via signal */
+    retval = 256 * WTERMSIG(status);
+
+ out:
+  return(retval);
+}