aboutsummaryrefslogtreecommitdiffstats
path: root/Library/Homebrew/utils
diff options
context:
space:
mode:
authorXu Cheng2015-04-13 18:02:46 +0800
committerXu Cheng2015-04-15 19:51:54 +0800
commit06f72ab38f7330eaef9a4cc05dd31b35e8bf26f5 (patch)
tree1beb8858448723e7eba52bcc5ec04b3dde7c784a /Library/Homebrew/utils
parentc952fda20230db91aae369423475757a0fc8db71 (diff)
downloadbrew-06f72ab38f7330eaef9a4cc05dd31b35e8bf26f5.tar.bz2
move safe_fork into a standalone method
Diffstat (limited to 'Library/Homebrew/utils')
-rw-r--r--Library/Homebrew/utils/fork.rb44
1 files changed, 44 insertions, 0 deletions
diff --git a/Library/Homebrew/utils/fork.rb b/Library/Homebrew/utils/fork.rb
new file mode 100644
index 000000000..defe1fa79
--- /dev/null
+++ b/Library/Homebrew/utils/fork.rb
@@ -0,0 +1,44 @@
+require "fcntl"
+require "socket"
+
+module Utils
+ def self.safe_fork(&block)
+ socket_path = "#{Dir.mktmpdir("homebrew", HOMEBREW_TEMP)}/socket"
+ server = UNIXServer.new(socket_path)
+ ENV["HOMEBREW_ERROR_PIPE"] = socket_path
+ read, write = IO.pipe
+
+ pid = fork do
+ begin
+ server.close
+ read.close
+ write.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
+ yield
+ rescue Exception => e
+ Marshal.dump(e, write)
+ write.close
+ exit! 1
+ end
+ end
+
+ ignore_interrupts(:quietly) do # the child will receive the interrupt and marshal it back
+ begin
+ socket = server.accept_nonblock
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
+ retry unless Process.waitpid(pid, Process::WNOHANG)
+ else
+ socket.send_io(write)
+ end
+ write.close
+ data = read.read
+ read.close
+ Process.wait(pid) unless socket.nil?
+ raise Marshal.load(data) unless data.nil? or data.empty?
+ raise Interrupt if $?.exitstatus == 130
+ raise "Suspicious failure" unless $?.success?
+ end
+ ensure
+ server.close
+ FileUtils.rm_r File.dirname(socket_path)
+ end
+end