Skip to content

Commit

Permalink
Merge branch 'OHAI-136'
Browse files Browse the repository at this point in the history
  • Loading branch information
danielsdeleo committed Apr 6, 2011
2 parents 1c0505c + 8cc64bd commit 622fbe4
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 52 deletions.
2 changes: 1 addition & 1 deletion bin/ohai
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ end
begin
# if we're in a source code checkout, we want to run the code from that.
# have to do this *after* rubygems is loaded.
$:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
$:.unshift File.expand_path('../../lib', __FILE__)
require 'ohai/application'
rescue LoadError
if missing_rubygems
Expand Down
205 changes: 157 additions & 48 deletions lib/ohai/mixin/command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand All @@ -27,44 +27,30 @@
module Ohai
module Mixin
module Command
def run_command(args={})

def run_command(args={})
if args.has_key?(:creates)
if File.exists?(args[:creates])
Ohai::Log.debug("Skipping #{args[:command]} - creates #{args[:creates]} exists.")
return false
end
end

stdout_string = nil
stderr_string = nil
args[:cwd] ||= Dir.tmpdir

args[:cwd] ||= Dir.tmpdir
unless File.directory?(args[:cwd])
raise Ohai::Exceptions::Exec, "#{args[:cwd]} does not exist or is not a directory"
end

status = nil
Dir.chdir(args[:cwd]) do
if args[:timeout]
begin
Timeout.timeout(args[:timeout]) do
status, stdout_string, stderr_string = systemu(args[:command])
end
rescue SystemExit => e
raise
rescue Exception => e
Ohai::Log.error("#{args[:command_string]} exceeded timeout #{args[:timeout]}")
raise(e)
end
else
status, stdout_string, stderr_string = systemu(args[:command])
end

status, stdout_string, stderr_string = run_command_backend(args[:command], args[:timeout])
# systemu returns 42 when it hits unexpected errors
if status.exitstatus == 42 and stderr_string == ""
stderr_string = "Failed to run: #{args[:command]}, assuming command not found"
Ohai::Log.debug(stderr_string)
Ohai::Log.debug(stderr_string)
end

if stdout_string
Expand All @@ -77,7 +63,7 @@ def run_command(args={})
Ohai::Log.debug(stderr_string.strip)
Ohai::Log.debug("---- End #{args[:command]} STDERR ----")
end

args[:returns] ||= 0
args[:no_status_check] ||= false
if status.exitstatus != args[:returns] and not args[:no_status_check]
Expand All @@ -90,16 +76,66 @@ def run_command(args={})
end

module_function :run_command

# This is taken directly from Ara T Howard's Open4 library, and then

def run_command_unix(command, timeout)
stderr_string, stdout_string, status = "", "", nil

exec_processing_block = lambda do |pid, stdin, stdout, stderr|
stdout_string, stderr_string = stdout.string.chomp, stderr.string.chomp
end

if timeout
begin
Timeout.timeout(timeout) do
status = popen4(command, {}, &exec_processing_block)
end
rescue Timeout::Error => e
Chef::Log.error("#{command} exceeded timeout #{timeout}")
raise(e)
end
else
status = popen4(command, {}, &exec_processing_block)
end
return status, stdout_string, stderr_string
end

def run_comand_windows(command, timeout)
if timeout
begin
systemu(command)
rescue SystemExit => e
raise
rescue Timeout::Error => e
Ohai::Log.error("#{command} exceeded timeout #{timeout}")
raise(e)
end
else
systemu(command)
end
end

if RUBY_PLATFORM =~ /mswin|mingw32|windows/
alias :run_command_backend :run_command_windows
else
alias :run_command_backend :run_command_unix
end
# This is taken directly from Ara T Howard's Open4 library, and then
# modified to suit the needs of Ohai. Any bugs here are most likely
# my own, and not Ara's.
#
# The original appears in external/open4.rb in its unmodified form.
# The original appears in external/open4.rb in its unmodified form.
#
# Thanks Ara!
def popen4(cmd, args={}, &b)


# Waitlast - this is magic.
#
# Do we wait for the child process to die before we yield
# to the block, or after? That is the magic of waitlast.
#
# By default, we are waiting before we yield the block.
args[:waitlast] ||= false

args[:user] ||= nil
unless args[:user].kind_of?(Integer)
args[:user] = Etc.getpwnam(args[:user]).uid if args[:user]
Expand All @@ -116,7 +152,7 @@ def popen4(cmd, args={}, &b)
unless args[:environment].has_key?("LC_ALL")
args[:environment]["LC_ALL"] = "C"
end

pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe

verbose = $VERBOSE
Expand All @@ -125,6 +161,8 @@ def popen4(cmd, args={}, &b)
ps.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)

cid = fork {
Process.setsid

pw.last.close
STDIN.reopen pw.first
pw.first.close
Expand All @@ -139,29 +177,32 @@ def popen4(cmd, args={}, &b)

STDOUT.sync = STDERR.sync = true

if args[:user]
Process.euid = args[:user]
Process.uid = args[:user]
end

if args[:group]
Process.egid = args[:group]
Process.gid = args[:group]
end


if args[:user]
Process.euid = args[:user]
Process.uid = args[:user]
end

args[:environment].each do |key,value|
ENV[key] = value
end


if args[:umask]
umask = ((args[:umask].respond_to?(:oct) ? args[:umask].oct : args[:umask].to_i) & 007777)
File.umask(umask)
end

begin
if cmd.kind_of?(Array)
exec(*cmd)
else
exec(cmd)
end
raise 'forty-two'
rescue SystemExit => e
raise
raise 'forty-two'
rescue Exception => e
Marshal.dump(e, ps.last)
ps.last.flush
Expand All @@ -177,9 +218,6 @@ def popen4(cmd, args={}, &b)

begin
e = Marshal.load ps.first
# If we get here, exec failed. Collect status of child to prevent
# zombies.
Process.waitpid(cid)
raise(Exception === e ? e : "unknown failure!")
rescue EOFError # If we get an EOF error, then the exec was successful
42
Expand All @@ -191,18 +229,89 @@ def popen4(cmd, args={}, &b)

pi = [pw.last, pr.first, pe.first]

if b
if b
begin
b[cid, *pi]
Process.waitpid2(cid).last
if args[:waitlast]
b[cid, *pi]
# send EOF so that if the child process is reading from STDIN
# it will actually finish up and exit
pi[0].close_write
Process.waitpid2(cid).last
else
# This took some doing.
# The trick here is to close STDIN
# Then set our end of the childs pipes to be O_NONBLOCK
# Then wait for the child to die, which means any IO it
# wants to do must be done - it's dead. If it isn't,
# it's because something totally skanky is happening,
# and we don't care.
o = StringIO.new
e = StringIO.new

#pi[0].close

stdout = pi[1]
stderr = pi[2]

stdout.sync = true
stderr.sync = true

stdout.fcntl(Fcntl::F_SETFL, pi[1].fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK)
stderr.fcntl(Fcntl::F_SETFL, pi[2].fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK)

stdout_finished = false
stderr_finished = false

results = nil

while !stdout_finished || !stderr_finished
begin
channels_to_watch = []
channels_to_watch << stdout if !stdout_finished
channels_to_watch << stderr if !stderr_finished
ready = IO.select(channels_to_watch, nil, nil, 1.0)
rescue Errno::EAGAIN
ensure
results = Process.waitpid2(cid, Process::WNOHANG)
if results
stdout_finished = true
stderr_finished = true
end
end

if ready && ready.first.include?(stdout)
line = results ? stdout.gets(nil) : stdout.gets
if line
o.write(line)
else
stdout_finished = true
end
end
if ready && ready.first.include?(stderr)
line = results ? stderr.gets(nil) : stderr.gets
if line
e.write(line)
else
stderr_finished = true
end
end
end
results = Process.waitpid2(cid) unless results
o.rewind
e.rewind
b[cid, pi[0], o, e]
results.last
end
ensure
pi.each{|fd| fd.close unless fd.closed?}
end
else
[cid, pw.last, pr.first, pe.first]
end
end

rescue Errno::ENOENT
raise Ohai::Exceptions::Exec, "command #{cmd} doesn't exist or is not in the PATH"
end

module_function :popen4
end
end
Expand Down
6 changes: 3 additions & 3 deletions lib/ohai/system.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def set(name, *value)
def from(cmd)
status, stdout, stderr = run_command(:command => cmd)
return "" if stdout.nil? || stdout.empty?
stdout.chomp!.strip
stdout.strip
end

def provides(*paths)
Expand Down Expand Up @@ -189,9 +189,9 @@ def require_plugin(plugin_name, force=false)
Ohai::Log.debug("Loading plugin #{plugin_name}")
from_file(check_path)
return true
rescue IOError => e
rescue Errno::ENOENT => e
Ohai::Log.debug("No #{plugin_name} at #{check_path}")
rescue SystemExit => e
rescue SystemExit, Interrupt
raise
rescue Exception,Errno::ENOENT => e
Ohai::Log.debug("Plugin #{plugin_name} threw exception #{e.inspect} #{e.backtrace.join("\n")}")
Expand Down

0 comments on commit 622fbe4

Please sign in to comment.