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/