Created
May 1, 2012 18:03
fdkiller in Ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.*.swp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Execute a code block while silencing chosen file descriptors. This can be | |
# used to silence stdout or stderr even in subprocesses, which inherit the | |
# parent process's stdout and stderr file descriptors. | |
# | |
# Author:: Ori Peleg (http://orip.org) | |
# License:: MIT, http://www.opensource.org/licenses/MIT | |
require 'fcntl' | |
# The file descriptors will be changed to write to /dev/null for the duration | |
# of the code block. | |
# | |
# fdkiller(STDOUT.fileno) do | |
# system "echo foo bar" # this won't print anything | |
# end | |
def fdkiller(*target_fds) | |
# simulate close(2) | |
def fd_close(fd) | |
IO.open(fd).close | |
end | |
# simulate dup(2) | |
def fd_dup(fd) | |
return IO.open(fd).fcntl(Fcntl::F_DUPFD) | |
end | |
# simulate dup2(2) | |
def fd_dup2(fd, fd2) | |
fd_close(fd2) | |
# dup fd into fd2 | |
IO.open(fd).fcntl(Fcntl::F_DUPFD, fd2) | |
end | |
# duplicate each of the target fds | |
duplicated_fds = target_fds.collect { |fd| fd_dup(fd) } | |
null_fd = IO.sysopen("/dev/null", "w") | |
# change target fds to write to /dev/null, by dup'ing the null fd into them | |
target_fds.each { |fd| fd_dup2(null_fd, fd) } | |
begin | |
yield | |
ensure | |
target_fds.zip(duplicated_fds).each do |(original_fd, duplicated_fd)| | |
# restore the original fd | |
fd_dup2(duplicated_fd, original_fd) | |
# clean up the duplicated fd | |
fd_close(duplicated_fd) | |
end | |
fd_close(null_fd) | |
end | |
end | |
def selftest | |
def test_prints | |
STDOUT.puts "same process stdout" | |
STDERR.puts "same process stderr" | |
system "echo child process stdout" | |
system "echo child process stderr 1>&2" | |
end | |
def test_with_fds(name, *fds) | |
puts "-- blocking #{name}" | |
fdkiller(*fds) { test_prints } | |
puts "-- finished blocking #{name}" | |
end | |
test_with_fds("stdout", STDOUT.fileno) | |
puts | |
test_with_fds("stderr", STDERR.fileno) | |
puts | |
test_with_fds("stdout + stderr", STDOUT.fileno, STDERR.fileno) | |
end | |
selftest if __FILE__ == $0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment