зеркало из https://github.com/github/ruby.git
* 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:
Родитель
2bb4ca64f9
Коммит
a112ec787a
|
@ -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
|
||||
|
|
38
process.c
38
process.c
|
@ -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
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче