1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
|
module ChildProcess
module Unix
class ForkExecProcess < Process
private
def launch_process
if @io
stdout = @io.stdout
stderr = @io.stderr
end
# pipe used to detect exec() failure
exec_r, exec_w = ::IO.pipe
ChildProcess.close_on_exec exec_w
if duplex?
reader, writer = ::IO.pipe
end
@pid = Kernel.fork {
# Children of the forked process will inherit its process group
# This is to make sure that all grandchildren dies when this Process instance is killed
::Process.setpgid 0, 0 if leader?
if @cwd
Dir.chdir(@cwd)
end
exec_r.close
set_env
if stdout
STDOUT.reopen(stdout)
else
STDOUT.reopen("/dev/null", "a+")
end
if stderr
STDERR.reopen(stderr)
else
STDERR.reopen("/dev/null", "a+")
end
if duplex?
STDIN.reopen(reader)
writer.close
end
executable, *args = @args
begin
Kernel.exec([executable, executable], *args)
rescue SystemCallError => ex
exec_w << ex.message
end
}
exec_w.close
if duplex?
io._stdin = writer
reader.close
end
# if we don't eventually get EOF, exec() failed
unless exec_r.eof?
raise LaunchError, exec_r.read || "executing command with #{@args.inspect} failed"
end
::Process.detach(@pid) if detach?
end
def set_env
@environment.each { |k, v| ENV[k.to_s] = v.nil? ? nil : v.to_s }
end
end # Process
end # Unix
end # ChildProcess
|