diff options
author | Ricky Zhou <ricky@fedoraproject.org> | 2009-12-31 12:07:24 -0500 |
---|---|---|
committer | James Turnbull <james@lovedthanlost.net> | 2010-01-01 11:42:01 +1100 |
commit | 5c6f07b404e946266b33f08855116f7bb1a1800c (patch) | |
tree | c3c4a1295bf18d28ddcbf1b31ef98eb61141c068 /lib/puppet/util.rb | |
parent | 7e64393dd10023d528d2fc21383ead30c9ee94dd (diff) | |
download | puppet-5c6f07b404e946266b33f08855116f7bb1a1800c.tar.gz puppet-5c6f07b404e946266b33f08855116f7bb1a1800c.tar.xz puppet-5c6f07b404e946266b33f08855116f7bb1a1800c.zip |
Use a pipe instead of a temp file for command output.
This solves some SELinux issues with programs such as mount being denied
from writing to temporary files and removes a race condition with
temporary file creation.
Diffstat (limited to 'lib/puppet/util.rb')
-rw-r--r-- | lib/puppet/util.rb | 90 |
1 files changed, 36 insertions, 54 deletions
diff --git a/lib/puppet/util.rb b/lib/puppet/util.rb index 21573d1da..cc2822f3b 100644 --- a/lib/puppet/util.rb +++ b/lib/puppet/util.rb @@ -259,39 +259,53 @@ module Util @@os ||= Facter.value(:operatingsystem) output = nil child_pid, child_status = nil - # 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 + output_read, output_write = IO.pipe 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 - child_status = (Process.waitpid2(child_pid)[1]).to_i >> 8 + Process.waitpid(child_pid) + child_status = $?.exitstatus else # Child process executes this Process.setsid begin + output_read.close + if arguments[:stdinfile] $stdin.reopen(arguments[:stdinfile]) else - $stdin.reopen("/dev/null") + $stdin.close + end + if arguments[:squelch] + $stdout.close + else + $stdout.reopen(output_write) + end + if arguments[:combine] + $stderr.reopen(output_write) + else + $stderr.close end - $stdout.reopen(output_file) - $stderr.reopen(error_file) 3.upto(256){|fd| IO::new(fd).close rescue nil} if arguments[:gid] @@ -303,42 +317,10 @@ module Util Process.uid = arguments[:uid] unless @@os == "Darwin" end ENV['LANG'] = ENV['LC_ALL'] = ENV['LC_MESSAGES'] = ENV['LANGUAGE'] = 'C' - if command.is_a?(Array) - Kernel.exec(*command) - else - Kernel.exec(command) - end + Kernel.exec(*command) rescue => detail - 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) + puts detail + exit(1) end end @@ -348,7 +330,7 @@ module Util end end - return output + output end module_function :execute |