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

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@20511 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
akr 2008-12-04 10:17:34 +00:00
Родитель 2bb4ca64f9
Коммит a112ec787a
3 изменённых файлов: 50 добавлений и 17 удалений

Просмотреть файл

@ -1,3 +1,7 @@
Thu Dec 4 19:16:28 2008 Tanaka Akira <akr@fsij.org>
* process.c (check_exec_fds): resolve cascaded child fd reference.
Thu Dec 4 16:58:12 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
* lib/rubygems/validator.rb (Gem#remove_leading_dot_dir): make

Просмотреть файл

@ -1516,7 +1516,12 @@ check_exec_fds(VALUE options)
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 @@ check_exec_fds(VALUE options)
}
}
/* 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 @@ rb_f_system(int argc, VALUE *argv)
* 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"

Просмотреть файл

@ -417,21 +417,30 @@ class TestProcess < Test::Unit::TestCase
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