diff options
| author | Xu Cheng | 2015-04-13 18:02:46 +0800 | 
|---|---|---|
| committer | Xu Cheng | 2015-04-15 19:51:54 +0800 | 
| commit | 436951609d97229fbefc416a7f7796e3519d12f4 (patch) | |
| tree | 31c07912cc1a2241e11e12a463d386c289699ffe | |
| parent | 9f0ac075c21f31206a81fcf90b915ea41f69d61a (diff) | |
| download | homebrew-436951609d97229fbefc416a7f7796e3519d12f4.tar.bz2 | |
move safe_fork into a standalone method
| -rw-r--r-- | Library/Homebrew/formula_installer.rb | 47 | ||||
| -rw-r--r-- | Library/Homebrew/utils.rb | 1 | ||||
| -rw-r--r-- | Library/Homebrew/utils/fork.rb | 44 | 
3 files changed, 50 insertions, 42 deletions
| diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index c87972d2e..32b61072d 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -11,8 +11,6 @@ require 'install_renamed'  require 'cmd/tap'  require 'hooks/bottles'  require 'debrew' -require 'fcntl' -require 'socket'  require 'sandbox'  class FormulaInstaller @@ -458,9 +456,6 @@ class FormulaInstaller    end    def build -    socket_path = "#{Dir.mktmpdir("homebrew", HOMEBREW_TEMP)}/socket" -    server = UNIXServer.new(socket_path) -      FileUtils.rm Dir["#{HOMEBREW_LOGS}/#{formula.name}/*"]      @start_time = Time.now @@ -468,9 +463,6 @@ class FormulaInstaller      # 1. formulae can modify ENV, so we must ensure that each      #    installation has a pristine ENV when it starts, forking now is      #    the easiest way to do this -    read, write = IO.pipe -    ENV["HOMEBREW_ERROR_PIPE"] = socket_path -      args = %W[        nice #{RUBY_PATH}        -W0 @@ -480,39 +472,13 @@ class FormulaInstaller        #{formula.path}      ].concat(build_argv) -    pid = fork do -      begin -        server.close -        read.close -        write.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) -        if Sandbox.available? && ARGV.sandbox? -          sandbox = Sandbox.new(formula) -          sandbox.exec(*args) -        else -          exec(*args) -        end -      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) +    Utils.safe_fork do +      if Sandbox.available? && ARGV.sandbox? +        sandbox = Sandbox.new(formula) +        sandbox.exec(*args)        else -        socket.send_io(write) +        exec(*args)        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 installation failure" unless $?.success?      end      raise "Empty installation" if Dir["#{formula.prefix}/*"].empty? @@ -524,9 +490,6 @@ class FormulaInstaller        formula.rack.rmdir_if_possible      end      raise -  ensure -    server.close -    FileUtils.rm_r File.dirname(socket_path)    end    def link(keg) diff --git a/Library/Homebrew/utils.rb b/Library/Homebrew/utils.rb index 2cdd920c9..ad358581e 100644 --- a/Library/Homebrew/utils.rb +++ b/Library/Homebrew/utils.rb @@ -4,6 +4,7 @@ require 'os/mac'  require 'utils/json'  require 'utils/inreplace'  require 'utils/popen' +require 'utils/fork'  require 'open-uri'  class Tty 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 | 
