summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordanielsdeleo <dan@getchef.com>2014-03-31 10:24:50 -0700
committerdanielsdeleo <dan@getchef.com>2014-03-31 10:24:50 -0700
commit6faa04e8c173e5c1f029a0d378c991a9a908dc36 (patch)
treee291ec19b3cab03688274122452b068df5fdf516
parenta6b9916767825b0902059e72025b7e649c61d7fd (diff)
downloadmixlib-shellout-6faa04e8c173e5c1f029a0d378c991a9a908dc36.tar.gz
Handle ESRCH when getting pgid of a zombie on OS X
-rw-r--r--CHANGELOG.md1
-rw-r--r--lib/mixlib/shellout/unix.rb18
-rw-r--r--spec/mixlib/shellout_spec.rb19
3 files changed, 37 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0bfb831..e1495ca 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,5 +6,6 @@
* Enabled travis.
* Added error? to check if the command ran successfully. MIXLIB-18.
* Remove GC.disable hack for non-ruby 1.8.8
+* Handle ESRCH from getpgid of a zombie on OS X
## Last Release: 1.3.0 (12/03/2013)
diff --git a/lib/mixlib/shellout/unix.rb b/lib/mixlib/shellout/unix.rb
index e8aa26e..03f619b 100644
--- a/lib/mixlib/shellout/unix.rb
+++ b/lib/mixlib/shellout/unix.rb
@@ -63,7 +63,7 @@ module Mixlib
# CHEF-3390: Marshall.load on Ruby < 1.8.7p369 also has a GC bug related
# to Marshall.load, so try disabling GC first.
propagate_pre_exec_failure
- @child_pgid = -Process.getpgid(@child_pid)
+ get_child_pgid
@result = nil
@execution_time = 0
@@ -107,6 +107,18 @@ module Mixlib
private
+ def get_child_pgid
+ # The behavior of Process.getpgid (see also getpgid(2) ) when the
+ # argument is the pid of a zombie isn't well specified. On Linux it
+ # works, on OS X it returns ESRCH (which ruby turns into Errno::ESRCH).
+ #
+ # If the child dies very quickly, @child_pid may be a zombie, so handle
+ # ESRCH here.
+ @child_pgid = -Process.getpgid(@child_pid)
+ rescue Errno::ESRCH
+ @child_pgid = nil
+ end
+
def set_user
if user
Process.euid = uid
@@ -137,6 +149,10 @@ module Mixlib
# Process group id of the child. Returned as a negative value so you can
# put it directly in arguments to kill, wait, etc.
+ #
+ # This may be nil if the child dies before the parent can query the
+ # system for its pgid (on some systems it is an error to get the pgid of
+ # a zombie).
def child_pgid
@child_pgid
end
diff --git a/spec/mixlib/shellout_spec.rb b/spec/mixlib/shellout_spec.rb
index 42f2714..03bb47b 100644
--- a/spec/mixlib/shellout_spec.rb
+++ b/spec/mixlib/shellout_spec.rb
@@ -843,6 +843,25 @@ describe Mixlib::ShellOut do
end
end
+ context "when the child process dies immediately" do
+ let(:cmd) { [ 'exit' ] }
+
+ it "handles ESRCH from getpgid of a zombie" do
+ Process.stub(:setsid) { exit!(4) }
+
+ # there is a small race condition here if the child doesn't get
+ # scheduled and call exit! before the parent can call getpgid, so run
+ # this a few times to make sure we've created the reproduction case
+ # correctly.
+ 5.times do
+ s = Mixlib::ShellOut.new(cmd)
+ s.run_command # should not raise Errno::ESRCH
+ end
+
+ end
+
+ end
+
context 'with subprocess that takes longer than timeout' do
def ruby_wo_shell(code)
parts = %w[ruby]