Skip to content

Instantly share code, notes, and snippets.

@orip
Created May 1, 2012 18:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save orip/2570101 to your computer and use it in GitHub Desktop.
Save orip/2570101 to your computer and use it in GitHub Desktop.
fdkiller in Ruby
# 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