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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
# File 'lib/funkysystem.rb', line 63
def self.run(cmd, stdin=nil)
fps = {
:stdout => IO.pipe,
:stderr => IO.pipe
}
fps[:stdin] = IO.pipe if stdin
fps.each do |key,fpa|
class << fpa
alias :reader :first
alias :writer :last
end
end
pid = fork do
keep = [STDERR, STDOUT, STDIN] + fps.values.flatten
ObjectSpace.each_object(IO) { |io|
begin
io.close() unless keep.include?(io)
rescue Exception
end
}
if fps[:stdin]
fps[:stdin].writer.close
STDIN.reopen(fps[:stdin].reader)
fps[:stdin].reader.close
else
STDIN.close()
end
fps[:stdout].reader.close
STDOUT.reopen(fps[:stdout].writer)
fps[:stdout].writer.close
fps[:stderr].reader.close
STDERR.reopen(fps[:stderr].writer)
fps[:stderr].writer.close
exec(* ( cmd.is_a?(Array) ? cmd : [cmd] ) )
end
fps[:stderr].writer.close
fps[:stdout].writer.close
if fps[:stdin]
fps[:stdin].reader.close
out_fds = [fps[:stdin].writer]
else
out_fds = []
end
in_fds = [fps[:stderr].reader, fps[:stdout].reader]
all_fds = in_fds + out_fds
all_fds.each { |fd| fd.nonblock = true }
stdout = ''
stderr = ''
exited = nil
exit_time = nil
until exited && (in_fds.all? { |fd| fd.closed? or fd.eof? } || exit_time < (Time.now.to_i - 3) )
exited ||= Process.waitpid2(pid, Process::WNOHANG)
exit_time ||= Time.now.to_i if exited
begin
rd, wr, er = select(in_fds, out_fds, all_fds, 0.05)
rescue IOError
[in_fds, out_fds, all_fds].each { |grp|
grp.reject!{ |fd| fd.closed? }
}
rd = wr = er = nil
end
wr.each do |fd|
begin
case fd
when fps[:stdin].writer
size = fd.syswrite(stdin)
stdin = stdin[size..-1]
if stdin.empty?
fd.close
out_fds = []
stdin = nil
end
end
rescue Errno::EPIPE, IOError
end
end if wr.respond_to?(:each)
rd.each do |fd|
begin
case fd
when fps[:stderr].reader
stderr << fd.sysread(4096 * 4)
when fps[:stdout].reader
stdout << fd.sysread(4096 * 4)
end
rescue Errno::EPIPE, IOError
end
end if rd.respond_to?(:each)
end
ProgramOutput.new(pid, exited.last, stdout, stderr, stdin)
end
|