Thanks for Mike Westerhof <mwester@dls.net>
[oweals/opkg-lede.git] / libbb / gz_open.c
index dbaf3bb023bceebd90694a4b7282fea0241a9692..ba4d6a5099b12e917331a52475fcd5be0495b057 100644 (file)
@@ -56,3 +56,78 @@ extern FILE *gz_open(FILE *compressed_file, int *pid)
        }
        return(fdopen(unzip_pipe[0], "r"));
 }
+
+/* gz_open implementation using gunzip and a vfork/exec -- dodges OOM killer */
+extern FILE *gzvopen(FILE *compressed_file, int *pid)
+{
+       int unzip_pipe[2];
+       off_t floc;
+       int cfile;
+
+       /* create a new file descriptor for the input stream
+        * (it *must* be associated with a file)
+        * and seek to the same position in that fd as the stream.
+        */
+       cfile = dup(fileno(compressed_file));
+       floc = ftello(compressed_file);
+       lseek(cfile, floc, SEEK_SET);
+
+       /* create the pipe */
+       if (pipe(unzip_pipe)!=0) {
+               error_msg("gzvopen(): pipe error");
+               return(NULL);
+       }
+
+       *pid = vfork();
+
+       if (*pid < 0) {
+               error_msg("gzvopen(): fork failed");
+               return(NULL);
+       }
+
+       if (*pid==0) {
+               /* child process - reads STDIN, writes to pipe */
+
+               /* close unused read end of pipe */
+               close(unzip_pipe[0]);
+
+               /* connect child's stdout to the pipe write end */
+               dup2(unzip_pipe[1], 1);
+
+               /* connect child's stdin to the fd passed in to us */
+               dup2(cfile, 0);
+
+               /* execute the gunzip utility */
+               execlp("gunzip","gunzip",NULL);
+
+               /* if we get here, we had a failure - since we are
+                * using vfork(), we cannot call exit(), must call _exit().
+                */
+               _exit(-1);
+       }
+
+       /* Parent process is executing here */
+
+       /* we have no more need of the duplicate fd */
+       close(cfile);
+
+       /* close the write end of the pipe */
+       close(unzip_pipe[1]);
+
+       /* return the read end of the pipe as a FILE */
+       return(fdopen(unzip_pipe[0], "r"));
+}
+
+extern void gzvclose(int gunzip_pid)
+{
+        if (kill(gunzip_pid, SIGTERM) == -1) {
+               perror("gzvclose()");
+                fprintf(stderr,"%s: unable to kill gunzip pid.\n",
+                       __FUNCTION__);
+        }
+
+        if (waitpid(gunzip_pid, NULL, 0) == -1) {
+                fprintf(stderr,"%s: unable to wait on gunzip pid.\n",
+                       __FUNCTION__);
+        }
+}