Module: Mixlib::ShellOut::Windows::Utils

Defined in:
lib/mixlib/shellout/windows.rb

Class Method Summary collapse

Class Method Details

.executable?(path) ⇒ Boolean

Returns:

  • (Boolean)


320
321
322
# File 'lib/mixlib/shellout/windows.rb', line 320

def self.executable?(path)
  File.executable?(path) && !File.directory?(path)
end

.find_executable(path) ⇒ Object

Windows has a different notion of what “executable” means The OS will search through valid the extensions and look for a binary there.



310
311
312
313
314
315
316
317
318
# File 'lib/mixlib/shellout/windows.rb', line 310

def self.find_executable(path)
  return path if executable? path

  pathext.each do |ext|
    exe = "#{path}#{ext}"
    return exe if executable? exe
  end
  return nil
end

.format_process(process, app_name, command_line, timeout) ⇒ Object



371
372
373
374
375
376
377
378
# File 'lib/mixlib/shellout/windows.rb', line 371

def self.format_process(process, app_name, command_line, timeout)
  msg = []
  msg << "ProcessId: #{process.process_id}"
  msg << "app_name: #{app_name}"
  msg << "command_line: #{command_line}"
  msg << "timeout: #{timeout}"
  msg.join("\n")
end

.kill_process(instance, logger) ⇒ Object



357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'lib/mixlib/shellout/windows.rb', line 357

def self.kill_process(instance, logger)
  child_pid = instance.wmi_ole_object.processid
  logger.debug([
    "killing child process #{child_pid}::",
    "#{instance.wmi_ole_object.Name} of parent #{pid}"
    ].join) if logger
  Process.kill(:KILL, instance.wmi_ole_object.processid)
rescue Errno::EIO, SystemCallError
  logger.debug([
    "Failed to kill child process #{child_pid}::",
    "#{instance.wmi_ole_object.Name} of parent #{pid}"
  ].join) if logger
end

.kill_process_tree(pid, wmi, logger) ⇒ Object

recursively kills all child processes of given pid calls itself querying for children child procs until none remain. Important that a single WmiLite instance is passed in since each creates its own WMI rpc process



348
349
350
351
352
353
354
355
# File 'lib/mixlib/shellout/windows.rb', line 348

def self.kill_process_tree(pid, wmi, logger)
  wmi.query("select * from Win32_Process where ParentProcessID=#{pid}").each do |instance|
    next if unsafe_process?(instance.wmi_ole_object.name, logger)
    child_pid = instance.wmi_ole_object.processid
    kill_process_tree(child_pid, wmi, logger)
    kill_process(instance, logger)
  end
end

.pathextObject



293
294
295
# File 'lib/mixlib/shellout/windows.rb', line 293

def self.pathext
  @pathext ||= ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') + [''] : ['']
end

.should_run_under_cmd?(command) ⇒ Boolean

api: semi-private If there are special characters parsable by cmd.exe (such as file redirection), then this method should return true.

This parser is based on github.com/ruby/ruby/blob/9073db5cb1d3173aff62be5b48d00f0fb2890991/win32/win32.c#L1437

Returns:

  • (Boolean)


259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/mixlib/shellout/windows.rb', line 259

def self.should_run_under_cmd?(command)
  return true if command =~ /^@/

  quote = nil
  env = false
  env_first_char = false

  command.dup.each_char do |c|
    case c
    when "'", '"'
      if (!quote)
        quote = c
      elsif quote == c
        quote = nil
      end
      next
    when '>', '<', '|', '&', "\n"
      return true unless quote
    when '%'
      return true if env
      env = env_first_char = true
      next
    else
      next unless env
      if env_first_char
        env_first_char = false
        env = false and next if c !~ /[A-Za-z_]/
      end
      env = false if c !~ /[A-Za-z1-9_]/
    end
  end
  return false
end

.system_required_processesObject



324
325
326
327
328
329
330
331
332
333
334
# File 'lib/mixlib/shellout/windows.rb', line 324

def self.system_required_processes
  [
    'System Idle Process',
    'System',
    'spoolsv.exe',
    'lsass.exe',
    'csrss.exe',
    'smss.exe',
    'svchost.exe'
  ]
end

.unsafe_process?(name, logger) ⇒ Boolean

Returns:

  • (Boolean)


336
337
338
339
340
341
342
# File 'lib/mixlib/shellout/windows.rb', line 336

def self.unsafe_process?(name, logger)
  return false unless system_required_processes.include? name
  logger.debug(
    "A request to kill a critical system process - #{name} - was received and skipped."
  )
  true
end

.which(cmd) ⇒ Object

which() mimicks the Unix which command FIXME: it is not working



299
300
301
302
303
304
305
# File 'lib/mixlib/shellout/windows.rb', line 299

def self.which(cmd)
  ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
    exe = find_executable("#{path}/#{cmd}")
    return exe if exe
  end
  return nil
end