diff options
-rw-r--r-- | lib/puppet/util.rb | 93 |
1 files changed, 54 insertions, 39 deletions
diff --git a/lib/puppet/util.rb b/lib/puppet/util.rb index e2df5c339..503c02b36 100644 --- a/lib/puppet/util.rb +++ b/lib/puppet/util.rb @@ -259,56 +259,39 @@ module Util @@os ||= Facter.value(:operatingsystem) output = nil child_pid, child_status = nil - output_read, output_write = IO.pipe + # There are problems with read blocking with badly behaved children + # read.partialread doesn't seem to capture either stdout or stderr + # We hack around this using a temporary file + + # The idea here is to avoid IO#read whenever possible. + output_file="/dev/null" + error_file="/dev/null" + if ! arguments[:squelch] + require "tempfile" + output_file = Tempfile.new("puppet") + if arguments[:combine] + error_file=output_file + end + end oldverb = $VERBOSE $VERBOSE = nil child_pid = Kernel.fork $VERBOSE = oldverb if child_pid - output_write.close - - # Read output in if required - if ! arguments[:squelch] - output = '' - begin - loop do - output << output_read.readpartial(4096) - end - rescue EOFError - # End of file - ensure - output_read.close - end - end - # Parent process executes this - Process.waitpid(child_pid) - child_status = $?.exitstatus + child_status = (Process.waitpid2(child_pid)[1]).to_i >> 8 else # Child process executes this Process.setsid begin - output_read.close - - if arguments[:squelch] - output_write.close - $stdout.reopen('/dev/null', 'w') - $stderr.reopen('/dev/null', 'w') - else - $stdout.reopen(output_write) - if arguments[:combine] - $stderr.reopen(output_write) - else - $stderr.reopen('/dev/null', 'w') - end - end - if arguments[:stdinfile] $stdin.reopen(arguments[:stdinfile]) else - $stdin.close + $stdin.reopen("/dev/null") end + $stdout.reopen(output_file) + $stderr.reopen(error_file) 3.upto(256){|fd| IO::new(fd).close rescue nil} if arguments[:gid] @@ -320,10 +303,42 @@ module Util Process.uid = arguments[:uid] unless @@os == "Darwin" end ENV['LANG'] = ENV['LC_ALL'] = ENV['LC_MESSAGES'] = ENV['LANGUAGE'] = 'C' - Kernel.exec(*command) + if command.is_a?(Array) + Kernel.exec(*command) + else + Kernel.exec(command) + end rescue => detail - puts detail - exit(1) + puts detail.to_s + exit!(1) + end # begin; rescue + end # if child_pid + + # read output in if required + if ! arguments[:squelch] + + # Make sure the file's actually there. This is + # basically a race condition, and is probably a horrible + # way to handle it, but, well, oh well. + unless FileTest.exists?(output_file.path) + Puppet.warning "sleeping" + sleep 0.5 + unless FileTest.exists?(output_file.path) + Puppet.warning "sleeping 2" + sleep 1 + unless FileTest.exists?(output_file.path) + Puppet.warning "Could not get output" + output = "" + end + end + end + unless output + # We have to explicitly open here, so that it reopens + # after the child writes. + output = output_file.open.read + + # The 'true' causes the file to get unlinked right away. + output_file.close(true) end end @@ -333,7 +348,7 @@ module Util end end - output + return output end module_function :execute |