Here's a new version with lots of help and input from semarie, thanks!
Besides lots of small tweaks, the main improvements are:

* fork one pledged child per fs which reads the data.
* pipe the data to the unpledged parent that dumps it to stdout.
* parent waits for current child, then calls opendev(2) for next child.
* make sure parent reports properly on child failure (e.g. pledge abort)

Index: sbin/dumpfs/dumpfs.c
===================================================================
RCS file: /var/cvs/src/sbin/dumpfs/dumpfs.c,v
retrieving revision 1.33
diff -u -p -r1.33 dumpfs.c
--- sbin/dumpfs/dumpfs.c        23 Nov 2015 19:19:29 -0000      1.33
+++ sbin/dumpfs/dumpfs.c        14 May 2016 15:02:24 -0000
@@ -40,6 +40,7 @@
 
 #include <sys/param.h> /* DEV_BSIZE MAXBSIZE isset */
 #include <sys/time.h>
+#include <sys/wait.h>
 
 #include <ufs/ufs/dinode.h>
 #include <ufs/ffs/fs.h>
@@ -51,6 +52,7 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <util.h>
 
@@ -73,6 +75,7 @@ int   dumpcg(const char *, int, int);
 int    marshal(const char *);
 int    open_disk(const char *);
 void   pbits(void *, int);
+void   writedata(int, int);
 __dead void    usage(void);
 
 int
@@ -80,7 +83,9 @@ main(int argc, char *argv[])
 {
        struct fstab *fs;
        const char *name;
-       int ch, domarshal, eval, fd;
+       pid_t pid, wpid;
+       int p[2];
+       int ch, domarshal, eval, fd, pstat;
 
        domarshal = eval = 0;
 
@@ -100,25 +105,69 @@ main(int argc, char *argv[])
        if (argc < 1)
                usage();
 
-       if (pledge("stdio rpath disklabel", NULL) == -1)
-               err(1, "pledge");
-
        for (; *argv != NULL; argv++) {
                if ((fs = getfsfile(*argv)) != NULL)
                        name = fs->fs_spec;
                else
                        name = *argv;
+
                if ((fd = open_disk(name)) == -1) {
                        eval |= 1;
                        continue;
                }
-               if (domarshal)
-                       eval |= marshal(name);
-               else
-                       eval |= dumpfs(fd, name);
-               close(fd);
+
+               if (pipe(p) < 0)
+                       err(1, "pipe");
+
+               switch(pid = fork()) {
+               case -1:
+                       err(1, "fork");
+
+               case 0:
+                       if (pledge("stdio", NULL) == -1)
+                               err(1, "pledge");
+
+                       close(p[0]);
+                       dup2(p[1], STDOUT_FILENO);
+                       close(p[1]);
+
+                       if (domarshal)
+                               eval |= marshal(name);
+                       else
+                               eval |= dumpfs(fd, name);
+
+                       close(fd);
+
+                       if (fflush(stdout))
+                               err(1, "fflush");
+
+                       _exit(eval);
+
+               default:
+                       close(p[1]);
+                       writedata(p[0], STDOUT_FILENO);
+                       close(p[0]);
+                       close(fd);
+
+                       do {
+                               wpid = waitpid(pid, &pstat, 0);
+                       } while (wpid == -1 && errno == EINTR);
+
+                       if (wpid == -1) {
+                               warn("waitpid");
+                               eval |= 1;
+                       } else if (WIFEXITED(pstat))
+                               eval |= WEXITSTATUS(pstat);
+                       else if (WIFSIGNALED(pstat)) {
+                               warnx("child processing %s terminated: %s%s",
+                                   name, strsignal(WTERMSIG(pstat)),
+                                   WCOREDUMP(pstat) ? " (core dumped)" : "");
+                               eval |= 1;
+                       }
+               }
        }
-       exit(eval);
+
+       return (eval);
 }
 
 int
@@ -458,6 +507,23 @@ pbits(void *vp, int max)
                                printf("-%d", i);
                }
        printf("\n");
+}
+
+void
+writedata(int ifd, int ofd)
+{
+       int nr, nw, off;
+       char buf[1024];
+       
+       while ((nr = read(ifd, buf, sizeof(buf))) != -1 && nr != 0) {
+               for (off = 0; nr; nr -= nw, off += nw) {
+                       if ((nw = write(ofd, buf + off, nr)) == 0 || nw == -1)
+                               err(1, "write");
+               }
+       }
+
+       if (nr < 0)
+               warn("read");
 }
 
 __dead void

Reply via email to