changeset 1472:2f9bc9495144 draft

Split xpopen() into xpopen_both(), xpopen(), and xrun() depending on whether we want to redirect both, one, or neither of stdin/stdout.
author Rob Landley <rob@landley.net>
date Sun, 14 Sep 2014 12:29:44 -0500
parents b748127e092e
children bff076394df5
files lib/lib.h lib/xwrap.c toys/lsb/mount.c toys/other/inotifyd.c toys/posix/cp.c toys/posix/find.c
diffstat 6 files changed, 78 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/lib/lib.h	Sat Sep 13 14:48:37 2014 -0500
+++ b/lib/lib.h	Sun Sep 14 12:29:44 2014 -0500
@@ -95,8 +95,12 @@
 pid_t xfork(void);
 void xexec_optargs(int skip);
 void xexec(char **argv);
-pid_t xpopen(char **argv, int *pipes);
-int xpclose(pid_t pid, int *pipes);
+pid_t xpopen_both(char **argv, int *pipes);
+int xpclose_both(pid_t pid, int *pipes);
+pid_t xpopen(char **argv, int *pipe, int stdout);
+pid_t xpclose(pid_t pid, int pipe);
+int xrun(char **argv);
+int xpspawn(char **argv, int*pipes);
 void xaccess(char *path, int flags);
 void xunlink(char *path);
 int xcreate(char *path, int flags, int mode);
--- a/lib/xwrap.c	Sat Sep 13 14:48:37 2014 -0500
+++ b/lib/xwrap.c	Sun Sep 14 12:29:44 2014 -0500
@@ -145,33 +145,41 @@
 
 // Spawn child process, capturing stdin/stdout.
 // argv[]: command to exec. If null, child returns to original program.
-// pipes[]: stdin, stdout of new process. If null, block and wait for child.
+// pipes[2]: stdin, stdout of new process. If -1 will not have pipe allocated.
 // return: pid of child process
-pid_t xpopen(char **argv, int *pipes)
+pid_t xpopen_both(char **argv, int *pipes)
 {
   int cestnepasun[4], pid;
 
-  // Make the pipes?
+  // Make the pipes? Not this won't set either pipe to 0 because if fds are
+  // allocated in order and if fd0 was free it would go to cestnepasun[0]
   if (pipes) {
-    if (pipe(cestnepasun) || pipe(cestnepasun+2)) perror_exit("pipe");
-    pipes[0] = cestnepasun[1];
-    pipes[1] = cestnepasun[2];
+    for (pid = 0; pid < 2; pid++) {
+      if (pipes[pid] == -1) continue;
+      if (pipe(cestnepasun+(2*pid))) perror_exit("pipe");
+      pipes[pid] = cestnepasun[pid+1];
+    }
   }
 
   // Child process
   if (!(pid = xfork())) {
     // Dance of the stdin/stdout redirection.
     if (pipes) {
-      close(cestnepasun[1]);
-      close(cestnepasun[2]);
-      // if we had no stdin/out, pipe handles could overlap, so test for that
-      if (cestnepasun[0]) {
-        dup2(cestnepasun[0], 0);
-        close(cestnepasun[0]);
+      // if we had no stdin/out, pipe handles could overlap, so test for it
+      // and free up potentially overlapping pipe handles before reuse
+      if (pipes[1] != -1) close(cestnepasun[2]);
+      if (pipes[0] != -1) {
+        close(cestnepasun[1]);
+        if (cestnepasun[0]) {
+          dup2(cestnepasun[0], 0);
+          close(cestnepasun[0]);
+        }
       }
-      dup2(cestnepasun[3], 1);
-      dup2(cestnepasun[3], 2);
-      if (cestnepasun[3] > 2) close(cestnepasun[3]);
+      if (pipes[1] != -1) {
+        dup2(cestnepasun[3], 1);
+        dup2(cestnepasun[3], 2);
+        if (cestnepasun[3] > 2 || !cestnepasun[3]) close(cestnepasun[3]);
+      }
     }
     if (argv) {
       if (CFG_TOYBOX) toy_exec(argv);
@@ -180,18 +188,18 @@
     }
     return 0;
 
+  }
+
   // Parent process
-  } else {
-    if (pipes) {
-      close(cestnepasun[0]);
-      close(cestnepasun[3]);
-    }
+  if (pipes) {
+    if (pipes[0] != -1) close(cestnepasun[0]);
+    if (pipes[1] != -1) close(cestnepasun[3]);
+  }
 
-    return pid;
-  }
+  return pid;
 }
 
-int xpclose(pid_t pid, int *pipes)
+int xpclose_both(pid_t pid, int *pipes)
 {
   int rc = 127;
 
@@ -204,6 +212,30 @@
   return WIFEXITED(rc) ? WEXITSTATUS(rc) : WTERMSIG(rc) + 127;
 }
 
+// Wrapper to xpopen with a pipe for just one of stdin/stdout
+pid_t xpopen(char **argv, int *pipe, int stdout)
+{
+  int pipes[2];
+
+  pipe[!stdout] = -1;
+  pipe[!!stdout] = 0;
+
+  return xpopen_both(argv, pipes);
+}
+
+int xpclose(pid_t pid, int pipe)
+{
+  close(pipe);
+
+  return xpclose_both(pid, 0);
+}
+
+// Call xpopen and wait for it to finish, keeping existing stdin/stdout.
+int xrun(char **argv)
+{
+  return xpclose_both(xpopen_both(argv, 0), 0);
+}
+
 void xaccess(char *path, int flags)
 {
   if (access(path, flags)) perror_exit("Can't access '%s'", path);
--- a/toys/lsb/mount.c	Sat Sep 13 14:48:37 2014 -0500
+++ b/toys/lsb/mount.c	Sun Sep 14 12:29:44 2014 -0500
@@ -7,6 +7,7 @@
  * no mtab (/proc/mounts does it) so -n is NOP.
 
 USE_MOUNT(NEWTOY(mount, "?O:afnrvwt:o*[-rw]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
+USE_NFSMOUNT(NEWTOY(nfsmount, "?<2>2", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
 
 config MOUNT
   bool "mount"
@@ -32,6 +33,14 @@
     bind mounts (file on file, directory on directory), so you don't need
     to say --bind or --loop. You can also "mount -a /path" to mount everything
     in /etc/fstab under /path, even if it's noauto.
+
+config NFSMOUNT
+  bool "nfsmount"
+  default n
+  help
+    usage: nfsmount SHARE DIR
+
+    Invoke an eldrich horror from the dawn of time.
 */
 
 #define FOR_mount
@@ -155,7 +164,7 @@
     } else fp = xfopen("/proc/filesystems", "r");
   } else if (!strcmp(type, "ignore")) return;
   else if (!strcmp(type, "swap"))
-    toys.exitval |= xpclose(xpopen((char *[]){"swapon", "--", dev, 0}, 0), 0);
+    toys.exitval |= xrun((char *[]){"swapon", "--", dev, 0});
 
   for (;;) {
     char *buf = 0;
@@ -204,13 +213,13 @@
 
     if (errno == ENOTBLK) {
       char *losetup[] = {"losetup", "-fs", dev, 0};
-      int pipes[2], len;
+      int pipe, len;
       pid_t pid;
 
       if (flags & MS_RDONLY) losetup[1] = "-fsr";
-      pid = xpopen(losetup, pipes);
-      len = readall(pipes[1], toybuf, sizeof(toybuf)-1);
-      rc = xpclose(pid, pipes);
+      pid = xpopen(losetup, &pipe, 1);
+      len = readall(pipe, toybuf, sizeof(toybuf)-1);
+      rc = xpclose(pid, pipe);
       if (!rc && len > 1) {
         if (toybuf[len-1] == '\n') --len;
         toybuf[len] = 0;
--- a/toys/other/inotifyd.c	Sat Sep 13 14:48:37 2014 -0500
+++ b/toys/other/inotifyd.c	Sun Sep 14 12:29:44 2014 -0500
@@ -104,7 +104,7 @@
           prog_args[1] = toybuf;
           prog_args[2] = toys.optargs[event->wd];
           prog_args[3] = event->len ? event->name : 0;
-          xpclose(xpopen(prog_args, 0), 0);
+          xrun(prog_args);
         }
 
         if (event->mask & IN_IGNORED) {
--- a/toys/posix/cp.c	Sat Sep 13 14:48:37 2014 -0500
+++ b/toys/posix/cp.c	Sun Sep 14 12:29:44 2014 -0500
@@ -341,8 +341,7 @@
 
   // No -r so always one level deep, so destname as set by cp_node() is correct
   if (toys.optflags & FLAG_s)
-    if (xpclose(xpopen((char *[]){"strip", "-p", TT.destname, 0}, 0), 0))
-      toys.exitval = 1;
+    if (xrun((char *[]){"strip", "-p", TT.destname, 0})) toys.exitval = 1;
 
   return 0;
 }
--- a/toys/posix/find.c	Sat Sep 13 14:48:37 2014 -0500
+++ b/toys/posix/find.c	Sun Sep 14 12:29:44 2014 -0500
@@ -102,7 +102,7 @@
     newargs[pos+rest] = 0;
   }
 
-  rc = xpclose(xpopen(newargs, 0), 0);
+  rc = xrun(newargs);
 
   llist_traverse(*dl, llist_free_double);
   *dl = 0;