open4 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +52 -17
- data/{open4-0.2.0.gem → build} +0 -0
- data/lib/open4-0.3.0.rb +133 -0
- data/lib/open4.rb +87 -85
- data/open4-0.3.0.gem +0 -0
- data/sample/spawn.rb +16 -0
- metadata +10 -8
- data/lib/open4-0.2.0.rb +0 -131
data/README
CHANGED
@@ -3,14 +3,15 @@ URIS
|
|
3
3
|
http://rubyforge.org/frs/?group_id=1024
|
4
4
|
http://www.codeforpeople.com/lib/ruby/
|
5
5
|
|
6
|
-
|
7
6
|
SYNOPSIS
|
8
7
|
|
9
8
|
open child process with handles on pid, stdin, stdout, and stderr
|
10
9
|
|
11
|
-
|
12
10
|
HISTORY
|
13
11
|
|
12
|
+
0.3.0 :
|
13
|
+
- bug fix from jordan breeding. general clean up. added spawn method.
|
14
|
+
|
14
15
|
0.2.0 :
|
15
16
|
- added exception marshaled from child -> parent when exec fails. thanks
|
16
17
|
to jordan breeding for a patch (yay!) and paul brannan for this most
|
@@ -22,17 +23,17 @@ HISTORY
|
|
22
23
|
0.0.0 :
|
23
24
|
- initial version
|
24
25
|
|
25
|
-
|
26
26
|
INSTALL
|
27
27
|
|
28
28
|
~> gem install open4
|
29
29
|
|
30
|
-
|
31
30
|
SAMPLES
|
32
31
|
|
33
|
-
|
32
|
+
----------------------------------------------------------------------------
|
33
|
+
simple usage
|
34
|
+
----------------------------------------------------------------------------
|
34
35
|
|
35
|
-
|
36
|
+
harp: > cat sample/simple.rb
|
36
37
|
require "open4"
|
37
38
|
|
38
39
|
pid, stdin, stdout, stderr = Open4::popen4 "sh"
|
@@ -50,7 +51,7 @@ SAMPLES
|
|
50
51
|
puts "exitstatus : #{ status.exitstatus }"
|
51
52
|
|
52
53
|
|
53
|
-
|
54
|
+
harp: > ruby sample/simple.rb
|
54
55
|
pid : 17273
|
55
56
|
stdout : 42.out
|
56
57
|
stderr : 42.err
|
@@ -58,10 +59,11 @@ SAMPLES
|
|
58
59
|
exitstatus : 0
|
59
60
|
|
60
61
|
|
61
|
-
|
62
|
-
|
62
|
+
----------------------------------------------------------------------------
|
63
|
+
in block form - the child process is automatically waited for
|
64
|
+
----------------------------------------------------------------------------
|
63
65
|
|
64
|
-
|
66
|
+
harp: > cat sample/block.rb
|
65
67
|
require 'open4'
|
66
68
|
|
67
69
|
status =
|
@@ -79,32 +81,65 @@ SAMPLES
|
|
79
81
|
puts "exitstatus : #{ status.exitstatus }"
|
80
82
|
|
81
83
|
|
82
|
-
|
84
|
+
harp: > ruby sample/block.rb
|
83
85
|
pid : 17295
|
84
86
|
stdout : 42.out
|
85
87
|
stderr : 42.err
|
86
88
|
status : #<Process::Status: pid=17295,exited(0)>
|
87
89
|
exitstatus : 0
|
88
90
|
|
91
|
+
----------------------------------------------------------------------------
|
92
|
+
exceptions are marshaled from child to parent if fork/exec fails
|
93
|
+
----------------------------------------------------------------------------
|
89
94
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
jib:~/eg/ruby/open4/open4-0.2.0 > cat sample/exception.rb
|
95
|
+
harp: > cat sample/exception.rb
|
94
96
|
require "open4"
|
95
97
|
Open4::popen4 "noexist"
|
96
98
|
|
97
99
|
|
98
|
-
|
100
|
+
harp: > ruby sample/exception.rb
|
99
101
|
/dmsp/reference/ruby-1.8.1//lib/ruby/site_ruby/open4.rb:100:in `popen4': No such file or directory - noexist (Errno::ENOENT)
|
100
102
|
from sample/exception.rb:3
|
101
103
|
|
104
|
+
----------------------------------------------------------------------------
|
105
|
+
the spawn method provides and even more convenient method of running a
|
106
|
+
process, allowing any object that supports 'each', 'read', or 'to_s' to be
|
107
|
+
given as stdin and any objects that support '<<' to be given as
|
108
|
+
stdout/stderr. an exception is thrown if the exec'd cmd fails (nonzero
|
109
|
+
exitstatus) unless the option 'raise'=>false is given
|
110
|
+
----------------------------------------------------------------------------
|
111
|
+
|
112
|
+
harp: > cat sample/spawn.rb
|
113
|
+
require 'open4'
|
114
|
+
include Open4
|
115
|
+
|
116
|
+
cat = ' ruby -e" ARGF.each{|line| STDOUT << line} " '
|
117
|
+
|
118
|
+
stdout, stderr = '', ''
|
119
|
+
status = spawn cat, 'stdin' => '42', 'stdout' => stdout, 'stderr' => stderr
|
120
|
+
p status
|
121
|
+
p stdout
|
122
|
+
p stderr
|
123
|
+
|
124
|
+
stdout, stderr = '', ''
|
125
|
+
status = spawn cat, 0=>'42', 1=>stdout, 2=>stderr
|
126
|
+
p status
|
127
|
+
p stdout
|
128
|
+
p stderr
|
129
|
+
|
130
|
+
|
131
|
+
harp: > RUBYLIB=lib ruby sample/spawn.rb
|
132
|
+
0
|
133
|
+
"42"
|
134
|
+
""
|
135
|
+
0
|
136
|
+
"42"
|
137
|
+
""
|
102
138
|
|
103
139
|
AUTHOR
|
104
140
|
|
105
141
|
ara.t.howard@noaa.gov
|
106
142
|
|
107
|
-
|
108
143
|
LICENSE
|
109
144
|
|
110
145
|
ruby's
|
data/{open4-0.2.0.gem → build}
RENAMED
File without changes
|
data/lib/open4-0.3.0.rb
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'fcntl'
|
2
|
+
|
3
|
+
module Open4
|
4
|
+
#--{{{
|
5
|
+
def self.version() '0.3.0' end
|
6
|
+
|
7
|
+
def popen4(*cmd)
|
8
|
+
#--{{{
|
9
|
+
pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe
|
10
|
+
|
11
|
+
verbose = $VERBOSE
|
12
|
+
begin
|
13
|
+
$VERBOSE = nil
|
14
|
+
ps.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
15
|
+
|
16
|
+
cid = fork {
|
17
|
+
pw.last.close
|
18
|
+
STDIN.reopen pw.first
|
19
|
+
pw.first.close
|
20
|
+
|
21
|
+
pr.first.close
|
22
|
+
STDOUT.reopen pr.last
|
23
|
+
pr.last.close
|
24
|
+
|
25
|
+
pe.first.close
|
26
|
+
STDERR.reopen pe.last
|
27
|
+
pe.last.close
|
28
|
+
|
29
|
+
STDOUT.sync = STDERR.sync = true
|
30
|
+
|
31
|
+
begin
|
32
|
+
exec(*cmd)
|
33
|
+
raise "exec failed!"
|
34
|
+
rescue Exception => e
|
35
|
+
Marshal.dump(e, ps.last)
|
36
|
+
ps.last.flush
|
37
|
+
end
|
38
|
+
ps.last.close unless (ps.last.closed?)
|
39
|
+
exit!
|
40
|
+
}
|
41
|
+
ensure
|
42
|
+
$VERBOSE = verbose
|
43
|
+
end
|
44
|
+
|
45
|
+
[pw.first, pr.last, pe.last, ps.last].each{|fd| fd.close}
|
46
|
+
|
47
|
+
begin
|
48
|
+
e = Marshal.load ps.first
|
49
|
+
if Exception === e
|
50
|
+
raise e
|
51
|
+
else
|
52
|
+
raise "unknown failure"
|
53
|
+
end
|
54
|
+
rescue EOFError # If we get an EOF error, then the exec was successful
|
55
|
+
42
|
56
|
+
end
|
57
|
+
|
58
|
+
pw.last.sync = true
|
59
|
+
|
60
|
+
pi = [pw.last, pr.first, pe.first]
|
61
|
+
|
62
|
+
if defined? yield
|
63
|
+
begin
|
64
|
+
yield(cid, *pi)
|
65
|
+
Process.waitpid2(cid).last
|
66
|
+
ensure
|
67
|
+
pi.each{|fd| fd.close unless fd.closed?}
|
68
|
+
end
|
69
|
+
else
|
70
|
+
[cid, pw.last, pr.first, pe.first]
|
71
|
+
end
|
72
|
+
#--}}}
|
73
|
+
end
|
74
|
+
alias open4 popen4
|
75
|
+
module_function :popen4
|
76
|
+
module_function :open4
|
77
|
+
|
78
|
+
def spawn cmd, opts = {}
|
79
|
+
#--{{{
|
80
|
+
getopt = lambda do |*args|
|
81
|
+
keys, default, ignored = args
|
82
|
+
catch('opt') do
|
83
|
+
[keys].flatten.each do |key|
|
84
|
+
[key, key.to_s, key.to_s.intern].each do |key|
|
85
|
+
throw 'opt', opts[key] if opts.has_key?(key)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
default
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
dont_raise = getopt[ 'quiet', !getopt['raise', true] ]
|
93
|
+
exitstatus = getopt[ %w( exitstatus exit_status status ), 0 ]
|
94
|
+
stdin = getopt[ ['stdin', 'in', '0', 0] ]
|
95
|
+
stdout = getopt[ ['stdout', 'out', '1', 1] ]
|
96
|
+
stderr = getopt[ ['stderr', 'err', '2', 2] ]
|
97
|
+
|
98
|
+
started = false
|
99
|
+
|
100
|
+
status =
|
101
|
+
begin
|
102
|
+
popen4(cmd) do |c, i, o, e|
|
103
|
+
started = true
|
104
|
+
|
105
|
+
if stdin.respond_to? :each
|
106
|
+
stdin.each{|buf| i << buf}
|
107
|
+
elsif stdin.respond_to? :read
|
108
|
+
i << stdin.read
|
109
|
+
else
|
110
|
+
i << stdin.to_s
|
111
|
+
end
|
112
|
+
|
113
|
+
i.close
|
114
|
+
|
115
|
+
ot = Thread.new(o){ o.each{|buf| stdout << buf if stdout} }
|
116
|
+
et = Thread.new(e){ e.each{|buf| stderr << buf if stderr} }
|
117
|
+
|
118
|
+
ot.join
|
119
|
+
et.join
|
120
|
+
end
|
121
|
+
rescue
|
122
|
+
raise unless(not started and dont_raise)
|
123
|
+
end
|
124
|
+
|
125
|
+
raise "cmd <#{ cmd }> failed with <#{ status }>" unless
|
126
|
+
((status == exitstatus) or dont_raise)
|
127
|
+
|
128
|
+
status
|
129
|
+
#--}}}
|
130
|
+
end
|
131
|
+
module_function :spawn
|
132
|
+
#--}}}
|
133
|
+
end
|
data/lib/open4.rb
CHANGED
@@ -1,131 +1,133 @@
|
|
1
|
-
# vim: ts=2 sts=2 et
|
2
|
-
# stolen directly from Open3::open3.rb!
|
3
|
-
#
|
4
|
-
# open4.rb: Spawn a program like popen, but with stderr, and pid, too. You might
|
5
|
-
# also want to use this if you want to bypass the shell. (By passing multiple
|
6
|
-
# args, which IO#popen does not allow)
|
7
|
-
#
|
8
|
-
# Usage:
|
9
|
-
# require "open4"
|
10
|
-
#
|
11
|
-
# pid, stdin, stdout, stderr = Open4.popen4('nroff -man')
|
12
|
-
# or
|
13
|
-
# include Open4
|
14
|
-
# pid, stdin, stdout, stderr = popen4('nroff -man')
|
15
|
-
|
16
1
|
require 'fcntl'
|
17
2
|
|
18
3
|
module Open4
|
19
4
|
#--{{{
|
20
|
-
|
21
|
-
if false
|
22
|
-
PROCESSES = Hash.new
|
23
|
-
|
24
|
-
orig_sigchld_handler = trap("CLD") do |*args|
|
25
|
-
begin
|
26
|
-
PROCESSES.each do |pid, foo|
|
27
|
-
if (Process.waitpid2(pid, Process::WNOHANG) == pid)
|
28
|
-
PROCESSES.delete(pid)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
rescue Errno::ECHILD
|
32
|
-
nil
|
33
|
-
end
|
34
|
-
orig_sigchld_handler.call(*args) if (not (orig_sigchld_handler.nil?))
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
#
|
39
|
-
# [ pid, stdin, stdout, stderr ] = popen4 command
|
40
|
-
#
|
5
|
+
def self.version() '0.3.0' end
|
41
6
|
|
42
7
|
def popen4(*cmd)
|
43
8
|
#--{{{
|
44
|
-
|
45
|
-
pw = IO::pipe # pipe[1] for read, pipe[0] for write
|
46
|
-
pr = IO::pipe # pipe[0] for read, pipe[1] for write
|
47
|
-
pe = IO::pipe # pipe[0] for read, pipe[1] for write
|
48
|
-
ps = IO::pipe # pipe[0] for read, pipe[1] for write
|
9
|
+
pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe
|
49
10
|
|
50
11
|
verbose = $VERBOSE
|
51
12
|
begin
|
52
|
-
$VERBOSE = nil
|
53
|
-
|
54
|
-
|
55
|
-
ps[1].fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
13
|
+
$VERBOSE = nil
|
14
|
+
ps.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
56
15
|
|
57
16
|
cid = fork {
|
58
|
-
|
59
|
-
pw
|
60
|
-
|
61
|
-
pw[0].close
|
17
|
+
pw.last.close
|
18
|
+
STDIN.reopen pw.first
|
19
|
+
pw.first.close
|
62
20
|
|
63
|
-
pr
|
64
|
-
STDOUT.reopen
|
65
|
-
pr
|
21
|
+
pr.first.close
|
22
|
+
STDOUT.reopen pr.last
|
23
|
+
pr.last.close
|
66
24
|
|
67
|
-
pe
|
68
|
-
STDERR.reopen
|
69
|
-
pe
|
25
|
+
pe.first.close
|
26
|
+
STDERR.reopen pe.last
|
27
|
+
pe.last.close
|
70
28
|
|
71
|
-
STDOUT.sync = true
|
72
|
-
STDERR.sync = true
|
29
|
+
STDOUT.sync = STDERR.sync = true
|
73
30
|
|
74
31
|
begin
|
75
32
|
exec(*cmd)
|
76
|
-
raise "exec
|
77
|
-
rescue Exception
|
78
|
-
Marshal.dump(
|
79
|
-
ps
|
33
|
+
raise "exec failed!"
|
34
|
+
rescue Exception => e
|
35
|
+
Marshal.dump(e, ps.last)
|
36
|
+
ps.last.flush
|
80
37
|
end
|
81
|
-
ps
|
38
|
+
ps.last.close unless (ps.last.closed?)
|
82
39
|
exit!
|
83
40
|
}
|
84
41
|
ensure
|
85
42
|
$VERBOSE = verbose
|
86
43
|
end
|
87
44
|
|
88
|
-
pw
|
89
|
-
pr[1].close
|
90
|
-
pe[1].close
|
91
|
-
ps[1].close
|
45
|
+
[pw.first, pr.last, pe.last, ps.last].each{|fd| fd.close}
|
92
46
|
|
93
|
-
exc = nil
|
94
47
|
begin
|
95
|
-
|
48
|
+
e = Marshal.load ps.first
|
49
|
+
if Exception === e
|
50
|
+
raise e
|
51
|
+
else
|
52
|
+
raise "unknown failure"
|
53
|
+
end
|
96
54
|
rescue EOFError # If we get an EOF error, then the exec was successful
|
55
|
+
42
|
97
56
|
end
|
98
57
|
|
99
|
-
|
100
|
-
raise exc
|
101
|
-
end
|
58
|
+
pw.last.sync = true
|
102
59
|
|
103
|
-
|
60
|
+
pi = [pw.last, pr.first, pe.first]
|
104
61
|
|
105
|
-
pi = [pw[1], pr[0], pe[0]]
|
106
|
-
pw[1].sync = true
|
107
62
|
if defined? yield
|
108
63
|
begin
|
109
64
|
yield(cid, *pi)
|
110
|
-
|
65
|
+
Process.waitpid2(cid).last
|
111
66
|
ensure
|
112
|
-
pi.each{|
|
67
|
+
pi.each{|fd| fd.close unless fd.closed?}
|
113
68
|
end
|
69
|
+
else
|
70
|
+
[cid, pw.last, pr.first, pe.first]
|
114
71
|
end
|
115
|
-
[cid, pw[1], pr[0], pe[0]]
|
116
72
|
#--}}}
|
117
73
|
end
|
118
|
-
|
119
74
|
alias open4 popen4
|
120
75
|
module_function :popen4
|
121
76
|
module_function :open4
|
122
77
|
|
123
|
-
|
124
|
-
|
78
|
+
def spawn cmd, opts = {}
|
79
|
+
#--{{{
|
80
|
+
getopt = lambda do |*args|
|
81
|
+
keys, default, ignored = args
|
82
|
+
catch('opt') do
|
83
|
+
[keys].flatten.each do |key|
|
84
|
+
[key, key.to_s, key.to_s.intern].each do |key|
|
85
|
+
throw 'opt', opts[key] if opts.has_key?(key)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
default
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
dont_raise = getopt[ 'quiet', !getopt['raise', true] ]
|
93
|
+
exitstatus = getopt[ %w( exitstatus exit_status status ), 0 ]
|
94
|
+
stdin = getopt[ ['stdin', 'in', '0', 0] ]
|
95
|
+
stdout = getopt[ ['stdout', 'out', '1', 1] ]
|
96
|
+
stderr = getopt[ ['stderr', 'err', '2', 2] ]
|
97
|
+
|
98
|
+
started = false
|
99
|
+
|
100
|
+
status =
|
101
|
+
begin
|
102
|
+
popen4(cmd) do |c, i, o, e|
|
103
|
+
started = true
|
104
|
+
|
105
|
+
if stdin.respond_to? :each
|
106
|
+
stdin.each{|buf| i << buf}
|
107
|
+
elsif stdin.respond_to? :read
|
108
|
+
i << stdin.read
|
109
|
+
else
|
110
|
+
i << stdin.to_s
|
111
|
+
end
|
112
|
+
|
113
|
+
i.close
|
125
114
|
|
126
|
-
if
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
115
|
+
ot = Thread.new(o){ o.each{|buf| stdout << buf if stdout} }
|
116
|
+
et = Thread.new(e){ e.each{|buf| stderr << buf if stderr} }
|
117
|
+
|
118
|
+
ot.join
|
119
|
+
et.join
|
120
|
+
end
|
121
|
+
rescue
|
122
|
+
raise unless(not started and dont_raise)
|
123
|
+
end
|
124
|
+
|
125
|
+
raise "cmd <#{ cmd }> failed with <#{ status }>" unless
|
126
|
+
((status == exitstatus) or dont_raise)
|
127
|
+
|
128
|
+
status
|
129
|
+
#--}}}
|
130
|
+
end
|
131
|
+
module_function :spawn
|
132
|
+
#--}}}
|
131
133
|
end
|
data/open4-0.3.0.gem
ADDED
File without changes
|
data/sample/spawn.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'open4'
|
2
|
+
include Open4
|
3
|
+
|
4
|
+
cat = 'ruby -e" ARGF.each{|line| STDOUT << line} "'
|
5
|
+
|
6
|
+
stdout, stderr = '', ''
|
7
|
+
status = spawn cat, 'stdin' => '42', 'stdout' => stdout, 'stderr' => stderr
|
8
|
+
p status
|
9
|
+
p stdout
|
10
|
+
p stderr
|
11
|
+
|
12
|
+
stdout, stderr = '', ''
|
13
|
+
status = spawn cat, 0=>'42', 1=>stdout, 2=>stderr
|
14
|
+
p status
|
15
|
+
p stdout
|
16
|
+
p stderr
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: open4
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2006-
|
6
|
+
version: 0.3.0
|
7
|
+
date: 2006-04-19 00:00:00.000000 -06:00
|
8
8
|
summary: open4
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -29,18 +29,20 @@ cert_chain:
|
|
29
29
|
authors:
|
30
30
|
- Ara T. Howard
|
31
31
|
files:
|
32
|
-
-
|
33
|
-
- install
|
32
|
+
- open4-0.3.0.gem
|
34
33
|
- install.rb
|
35
|
-
- README
|
36
34
|
- sample
|
35
|
+
- lib
|
36
|
+
- README
|
37
|
+
- build
|
38
|
+
- install
|
37
39
|
- gemspec.rb
|
38
|
-
- open4-0.2.0.gem
|
39
|
-
- lib/open4.rb
|
40
|
-
- lib/open4-0.2.0.rb
|
41
40
|
- sample/block.rb
|
42
41
|
- sample/simple.rb
|
43
42
|
- sample/exception.rb
|
43
|
+
- sample/spawn.rb
|
44
|
+
- lib/open4-0.3.0.rb
|
45
|
+
- lib/open4.rb
|
44
46
|
test_files: []
|
45
47
|
rdoc_options: []
|
46
48
|
extra_rdoc_files: []
|
data/lib/open4-0.2.0.rb
DELETED
@@ -1,131 +0,0 @@
|
|
1
|
-
# vim: ts=2 sts=2 et
|
2
|
-
# stolen directly from Open3::open3.rb!
|
3
|
-
#
|
4
|
-
# open4.rb: Spawn a program like popen, but with stderr, and pid, too. You might
|
5
|
-
# also want to use this if you want to bypass the shell. (By passing multiple
|
6
|
-
# args, which IO#popen does not allow)
|
7
|
-
#
|
8
|
-
# Usage:
|
9
|
-
# require "open4"
|
10
|
-
#
|
11
|
-
# pid, stdin, stdout, stderr = Open4.popen4('nroff -man')
|
12
|
-
# or
|
13
|
-
# include Open4
|
14
|
-
# pid, stdin, stdout, stderr = popen4('nroff -man')
|
15
|
-
|
16
|
-
require 'fcntl'
|
17
|
-
|
18
|
-
module Open4
|
19
|
-
#--{{{
|
20
|
-
|
21
|
-
if false
|
22
|
-
PROCESSES = Hash.new
|
23
|
-
|
24
|
-
orig_sigchld_handler = trap("CLD") do |*args|
|
25
|
-
begin
|
26
|
-
PROCESSES.each do |pid, foo|
|
27
|
-
if (Process.waitpid2(pid, Process::WNOHANG) == pid)
|
28
|
-
PROCESSES.delete(pid)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
rescue Errno::ECHILD
|
32
|
-
nil
|
33
|
-
end
|
34
|
-
orig_sigchld_handler.call(*args) if (not (orig_sigchld_handler.nil?))
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
#
|
39
|
-
# [ pid, stdin, stdout, stderr ] = popen4 command
|
40
|
-
#
|
41
|
-
|
42
|
-
def popen4(*cmd)
|
43
|
-
#--{{{
|
44
|
-
|
45
|
-
pw = IO::pipe # pipe[1] for read, pipe[0] for write
|
46
|
-
pr = IO::pipe # pipe[0] for read, pipe[1] for write
|
47
|
-
pe = IO::pipe # pipe[0] for read, pipe[1] for write
|
48
|
-
ps = IO::pipe # pipe[0] for read, pipe[1] for write
|
49
|
-
|
50
|
-
verbose = $VERBOSE
|
51
|
-
begin
|
52
|
-
$VERBOSE = nil # shut up warning about forking in threads, world writable
|
53
|
-
# dirs, etc
|
54
|
-
|
55
|
-
ps[1].fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
56
|
-
|
57
|
-
cid = fork {
|
58
|
-
# child
|
59
|
-
pw[1].close
|
60
|
-
STDIN.reopen(pw[0])
|
61
|
-
pw[0].close
|
62
|
-
|
63
|
-
pr[0].close
|
64
|
-
STDOUT.reopen(pr[1])
|
65
|
-
pr[1].close
|
66
|
-
|
67
|
-
pe[0].close
|
68
|
-
STDERR.reopen(pe[1])
|
69
|
-
pe[1].close
|
70
|
-
|
71
|
-
STDOUT.sync = true
|
72
|
-
STDERR.sync = true
|
73
|
-
|
74
|
-
begin
|
75
|
-
exec(*cmd)
|
76
|
-
raise "exec returned!"
|
77
|
-
rescue Exception
|
78
|
-
Marshal.dump($!, ps[1])
|
79
|
-
ps[1].flush
|
80
|
-
end
|
81
|
-
ps[1].close unless (ps[1].closed?)
|
82
|
-
exit!
|
83
|
-
}
|
84
|
-
ensure
|
85
|
-
$VERBOSE = verbose
|
86
|
-
end
|
87
|
-
|
88
|
-
pw[0].close
|
89
|
-
pr[1].close
|
90
|
-
pe[1].close
|
91
|
-
ps[1].close
|
92
|
-
|
93
|
-
exc = nil
|
94
|
-
begin
|
95
|
-
exc = Marshal.load(ps[0])
|
96
|
-
rescue EOFError # If we get an EOF error, then the exec was successful
|
97
|
-
end
|
98
|
-
|
99
|
-
if (not (exc.nil?)) then
|
100
|
-
raise exc
|
101
|
-
end
|
102
|
-
|
103
|
-
# PROCESSES[cid] = true
|
104
|
-
|
105
|
-
pi = [pw[1], pr[0], pe[0]]
|
106
|
-
pw[1].sync = true
|
107
|
-
if defined? yield
|
108
|
-
begin
|
109
|
-
yield(cid, *pi)
|
110
|
-
return((Process.waitpid2(cid, 1)).last)
|
111
|
-
ensure
|
112
|
-
pi.each{|p| p.close unless p.closed?}
|
113
|
-
end
|
114
|
-
end
|
115
|
-
[cid, pw[1], pr[0], pe[0]]
|
116
|
-
#--}}}
|
117
|
-
end
|
118
|
-
|
119
|
-
alias open4 popen4
|
120
|
-
module_function :popen4
|
121
|
-
module_function :open4
|
122
|
-
|
123
|
-
#--}}}
|
124
|
-
end
|
125
|
-
|
126
|
-
if $0 == __FILE__
|
127
|
-
status = Open4::popen4('sh'){|cid,i,o,e|i.puts 'echo 42';i.close; puts o.read;}
|
128
|
-
p [status]
|
129
|
-
p status.exitstatus
|
130
|
-
p status == 0
|
131
|
-
end
|