/usr/lib/ruby/vendor_ruby/childprocess/unix/posix_spawn_process.rb is in ruby-childprocess 0.5.9-1ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | require 'ffi'
require 'thread'
module ChildProcess
module Unix
class PosixSpawnProcess < Process
private
@@cwd_lock = Mutex.new
def launch_process
pid_ptr = FFI::MemoryPointer.new(:pid_t)
actions = Lib::FileActions.new
attrs = Lib::Attrs.new
if io.stdout
actions.add_dup fileno_for(io.stdout), fileno_for(STDOUT)
else
actions.add_open fileno_for(STDOUT), "/dev/null", File::WRONLY, 0644
end
if io.stderr
actions.add_dup fileno_for(io.stderr), fileno_for(STDERR)
else
actions.add_open fileno_for(STDERR), "/dev/null", File::WRONLY, 0644
end
if duplex?
reader, writer = ::IO.pipe
actions.add_dup fileno_for(reader), fileno_for(STDIN)
actions.add_close fileno_for(writer)
end
attrs.pgroup = 0 if leader?
attrs.flags |= Platform::POSIX_SPAWN_USEVFORK if defined? Platform::POSIX_SPAWN_USEVFORK
# wrap in helper classes in order to avoid GC'ed pointers
argv = Argv.new(@args)
envp = Envp.new(ENV.to_hash.merge(@environment))
ret = 0
@@cwd_lock.synchronize do
Dir.chdir(@cwd || Dir.pwd) do
if ChildProcess.jruby?
# on JRuby, the current working directory is for some reason not inherited.
# We'll work around it by making a chdir call through FFI.
# TODO: report this to JRuby
Lib.chdir Dir.pwd
end
ret = Lib.posix_spawnp(
pid_ptr,
@args.first, # TODO: not sure this matches exec() behaviour
actions,
attrs,
argv,
envp
)
end
end
if duplex?
io._stdin = writer
reader.close
end
actions.free
attrs.free
if ret != 0
raise LaunchError, "#{Lib.strerror(ret)} (#{ret})"
end
@pid = pid_ptr.read_int
::Process.detach(@pid) if detach?
end
if ChildProcess.jruby?
def fileno_for(obj)
ChildProcess::JRuby.posix_fileno_for(obj)
end
else
def fileno_for(obj)
obj.fileno
end
end
class Argv
def initialize(args)
@ptrs = args.map do |e|
if e.include?("\0")
raise ArgumentError, "argument cannot contain null bytes: #{e.inspect}"
end
FFI::MemoryPointer.from_string(e.to_s)
end
@ptrs << FFI::Pointer.new(0)
end
def to_ptr
argv = FFI::MemoryPointer.new(:pointer, @ptrs.size)
argv.put_array_of_pointer(0, @ptrs)
argv
end
end # Argv
class Envp
def initialize(env)
@ptrs = env.map do |key, val|
next if val.nil?
if key =~ /=|\0/ || val.include?("\0")
raise InvalidEnvironmentVariable, "#{key.inspect} => #{val.inspect}"
end
FFI::MemoryPointer.from_string("#{key}=#{val}")
end.compact
@ptrs << FFI::Pointer.new(0)
end
def to_ptr
env = FFI::MemoryPointer.new(:pointer, @ptrs.size)
env.put_array_of_pointer(0, @ptrs)
env
end
end # Envp
end
end
end
|