module RailsPwnerer::Util

Public Class Methods

kill_process_set(kill_script, pid_patterns, process_patterns, options = {}) click to toggle source

Complex procedure for killing a process or a bunch of process replicas kill_command is the script that’s supposed to kill the process / processes (tried first) pid_patters are globs identifying PID files (a file can match any of the patterns) process_patterns are strings that should show on a command line (a process must match all)

options:

:verbose - display what gets killed
:script_delay - the amount of seconds to sleep after launching the kill script
:force_script - the kill script is executed even if there are no PID files
   # File lib/rails_pwnerer/util/kill_process_set.rb
12 def self.kill_process_set(kill_script, pid_patterns, process_patterns, options = {})
13   # Phase 1: kill order (only if there's a PID file)
14   pid_patterns = [pid_patterns] unless pid_patterns.kind_of? Enumerable
15   unless options[:force_script]
16     pid_files = pid_patterns.map { |pattern| Dir.glob(pattern) }.flatten
17   end
18   if options[:force_script] or !(pid_files.empty? or kill_script.nil?)
19     print "Issuing kill order: #{kill_script}\n" if options[:verbose]
20     success = Kernel.system kill_script unless kill_script.nil?
21     if !success and options[:verbose]
22       print "Kill order failed with exit code #{$CHILD_STATUS.exitstatus}\n"
23     end
24     
25     deadline_time = Time.now + (options[:script_delay] || 0.5)
26     while Time.now < deadline_time
27       pid_files = pid_patterns.map { |pattern| Dir.glob(pattern) }.flatten
28       break if pid_files.empty?
29       sleep 0.05
30     end
31   end
32   
33   # Phase 2: look through PID files and issue kill orders
34   pinfo = process_info()
35   pid_files = pid_patterns.map { |pattern| Dir.glob(pattern) }.flatten 
36   pid_files.each do |fname|
37     begin
38       pid = File.open(fname, 'r') { |f| f.read.strip! }
39       process_cmdline = pinfo[pid][:cmdline]
40       # avoid killing innocent victims
41       if pinfo[pid].nil? or process_patterns.all? { |pattern| process_cmdline.index pattern } 
42         print "Killing #{pid}: #{process_cmdline}\n" if options[:verbose]
43         kill_tree pid.to_i
44       end
45     rescue
46       # just in case the file gets wiped before we see it
47     end
48     begin
49       print "Deleting #{fname}\n" if options[:verbose]
50       File.delete fname if File.exists? fname
51     rescue
52       # prevents crashing if the file is wiped after we call exists?
53     end
54   end
55   
56   # Phase 3: look through the process table and kill anything that looks good
57   pinfo = process_info()
58   pinfo.each do |pid, info|
59     next unless process_patterns.all? { |pattern| info[:cmdline].index pattern }
60     print "Killing #{pid}: #{pinfo[pid][:cmdline]}\n" if options[:verbose]
61     kill_tree pid.to_i
62   end
63 end