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