[前][次][番号順一覧][スレッド一覧]

ruby-changes:8975

From: akr <ko1@a...>
Date: Thu, 4 Dec 2008 19:19:01 +0900 (JST)
Subject: [ruby-changes:8975] Ruby:r20511 (trunk): * process.c (check_exec_fds): resolve cascaded child fd reference.

akr	2008-12-04 19:17:34 +0900 (Thu, 04 Dec 2008)

  New Revision: 20511

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=20511

  Log:
    * process.c (check_exec_fds): resolve cascaded child fd reference.

  Modified files:
    trunk/ChangeLog
    trunk/process.c
    trunk/test/ruby/test_process.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 20510)
+++ ChangeLog	(revision 20511)
@@ -1,3 +1,7 @@
+Thu Dec  4 19:16:28 2008  Tanaka Akira  <akr@f...>
+
+	* process.c (check_exec_fds): resolve cascaded child fd reference.
+
 Thu Dec  4 16:58:12 2008  Yukihiro Matsumoto  <matz@r...>
 
 	* lib/rubygems/validator.rb (Gem#remove_leading_dot_dir): make
Index: process.c
===================================================================
--- process.c	(revision 20510)
+++ process.c	(revision 20511)
@@ -1516,7 +1516,12 @@
             if (RTEST(rb_hash_lookup(h, INT2FIX(fd)))) {
                 rb_raise(rb_eArgError, "fd %d specified twice", fd);
             }
-            rb_hash_aset(h, INT2FIX(fd), INT2FIX(index));
+            if (index == EXEC_OPTION_OPEN || index == EXEC_OPTION_DUP2)
+                rb_hash_aset(h, INT2FIX(fd), Qtrue);
+            else if (index == EXEC_OPTION_DUP2_CHILD)
+                rb_hash_aset(h, INT2FIX(fd), RARRAY_PTR(elt)[1]);
+            else /* index == EXEC_OPTION_CLOSE */
+                rb_hash_aset(h, INT2FIX(fd), INT2FIX(-1));
             if (maxhint < fd)
                 maxhint = fd;
             if (index == EXEC_OPTION_DUP2 || index == EXEC_OPTION_DUP2_CHILD) {
@@ -1527,20 +1532,33 @@
         }
     }
 
-    /* support cascaded mapping in future?
-     * fd1 => [:child, fd2],
-     * fd2 => [:child, fd3],
-     * fd3 => "/dev/null"
-     */
     ary = rb_ary_entry(options, EXEC_OPTION_DUP2_CHILD);
     if (!NIL_P(ary)) {
         for (i = 0; i < RARRAY_LEN(ary); i++) {
             VALUE elt = RARRAY_PTR(ary)[i];
+            int newfd = FIX2INT(RARRAY_PTR(elt)[0]);
             int oldfd = FIX2INT(RARRAY_PTR(elt)[1]);
-            VALUE vindex = rb_hash_lookup(h, INT2FIX(oldfd));
-            if (vindex != INT2FIX(EXEC_OPTION_DUP2) &&
-                vindex != INT2FIX(EXEC_OPTION_OPEN)) {
+            int lastfd = oldfd;
+            VALUE val = rb_hash_lookup(h, INT2FIX(lastfd));
+            long depth = 0;
+            while (FIXNUM_P(val) && 0 <= FIX2INT(val)) {
+                lastfd = FIX2INT(val);
+                val = rb_hash_lookup(h, val);
+                if (RARRAY_LEN(ary) < depth)
+                    rb_raise(rb_eArgError, "cyclic child fd redirection from %d", oldfd);
+                depth++;
+            }
+            if (val != Qtrue)
                 rb_raise(rb_eArgError, "child fd %d is not redirected", oldfd);
+            if (oldfd != lastfd) {
+                VALUE val2;
+                rb_ary_store(elt, 1, INT2FIX(lastfd));
+                rb_hash_aset(h, INT2FIX(newfd), INT2FIX(lastfd));
+                val = INT2FIX(oldfd);
+                while (FIXNUM_P(val2 = rb_hash_lookup(h, val))) {
+                    rb_hash_aset(h, val, INT2FIX(lastfd));
+                    val = val2;
+                }
             }
         }
     }
@@ -2941,6 +2959,8 @@
  *    pid = spawn(command, STDOUT=>["log", "w"], STDERR=>[:child, STDOUT])
  *
  *  [:child, STDOUT] can be used to merge STDERR into STDOUT in IO.popen.
+ *  In this case, IO.popen redirects STDOUT to a pipe in the child process
+ *  and [:child, STDOUT] refers the redirected STDOUT.
  *
  *    io = IO.popen(["sh", "-c", "echo out; echo err >&2", STDERR=>[:child, STDOUT]])
  *    p io.read #=> "out\nerr\n"
Index: test/ruby/test_process.rb
===================================================================
--- test/ruby/test_process.rb	(revision 20510)
+++ test/ruby/test_process.rb	(revision 20511)
@@ -417,21 +417,30 @@
 
   def test_execopts_redirect_dup2_child
     with_tmpchdir {|d|
-      Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'", STDOUT=>"out", STDERR=>[:child, STDOUT])
+      Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'",
+                         STDOUT=>"out", STDERR=>[:child, STDOUT])
       assert_equal("errout", File.read("out"))
-      Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'", STDERR=>"out", STDOUT=>[:child, STDERR])
+
+      Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'",
+                         STDERR=>"out", STDOUT=>[:child, STDERR])
       assert_equal("errout", File.read("out"))
 
+      Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'",
+                         STDOUT=>"out", 
+                         STDERR=>[:child, 3],
+                         3=>[:child, 4], 
+                         4=>[:child, STDOUT]
+                        )
+      assert_equal("errout", File.read("out"))
+
       IO.popen([RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'", STDERR=>[:child, STDOUT]]) {|io|
         assert_equal("errout", io.read)
       }
 
-      assert_raise(ArgumentError) {
-        Process.wait spawn(*TRUECOMMAND, STDOUT=>[:child, STDOUT])
-      }
-      assert_raise(ArgumentError) {
-        Process.wait spawn(*TRUECOMMAND, STDOUT=>[:child, 3])
-      }
+      assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, STDOUT=>[:child, STDOUT]) }
+      assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, 3=>[:child, 4], 4=>[:child, 3]) }
+      assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, 3=>[:child, 4], 4=>[:child, 5], 5=>[:child, 3]) }
+      assert_raise(ArgumentError) { Process.wait spawn(*TRUECOMMAND, STDOUT=>[:child, 3]) }
     }
   end
 

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]