47 lines
		
	
	
		
			1.3 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			47 lines
		
	
	
		
			1.3 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| require "fcntl"
 | |
| require "socket"
 | |
| 
 | |
| module Utils
 | |
|   def self.safe_fork(&_block)
 | |
|     Dir.mktmpdir("homebrew", HOMEBREW_TEMP) do |tmpdir|
 | |
|       UNIXServer.open("#{tmpdir}/socket") do |server|
 | |
|         read, write = IO.pipe
 | |
| 
 | |
|         pid = fork do
 | |
|           begin
 | |
|             ENV["HOMEBREW_ERROR_PIPE"] = server.path
 | |
|             server.close
 | |
|             read.close
 | |
|             write.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
 | |
|             yield
 | |
|           rescue Exception => e
 | |
|             Marshal.dump(e, write)
 | |
|             write.close
 | |
|             exit!
 | |
|           else
 | |
|             exit!(true)
 | |
|           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)
 | |
|             socket.close
 | |
|           end
 | |
|           write.close
 | |
|           data = read.read
 | |
|           read.close
 | |
|           Process.wait(pid) unless socket.nil?
 | |
|           raise Marshal.load(data) unless data.nil? || data.empty?
 | |
|           raise Interrupt if $CHILD_STATUS.exitstatus == 130
 | |
|           raise "Suspicious failure" unless $CHILD_STATUS.success?
 | |
|         end
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| end
 | 
