Class: Arachni::Processes::Manager
- Includes:
- Singleton
- Defined in:
- lib/arachni/processes/manager.rb
Overview
Helper for managing processes.
Constant Summary collapse
- RUNNER =
"#{File.dirname( __FILE__ )}/executables/base.rb"
Instance Attribute Summary collapse
-
#pids ⇒ Array<Integer>
readonly
PIDs of all running processes.
Class Method Summary collapse
Instance Method Summary collapse
-
#<<(pid) ⇒ Integer
`pid`.
-
#alive?(pid) ⇒ Boolean
`true` if the process is alive, `false` otherwise.
- #discard_output ⇒ Object
- #discard_output? ⇒ Boolean
-
#initialize ⇒ Manager
constructor
A new instance of Manager.
- #kill(pid) ⇒ Object
- #kill_many(pids) ⇒ Object
-
#kill_reactor ⇒ Object
Stops the Reactor.
-
#killall ⇒ Object
Kills all processes.
-
#preserve_output ⇒ Object
Overrides the default setting of discarding process outputs.
- #preserve_output? ⇒ Boolean
-
#spawn(executable, options = {}) ⇒ Integer
PID of the process.
Constructor Details
#initialize ⇒ Manager
Returns a new instance of Manager.
26 27 28 29 |
# File 'lib/arachni/processes/manager.rb', line 26 def initialize @pids = [] @discard_output = true end |
Instance Attribute Details
#pids ⇒ Array<Integer> (readonly)
Returns PIDs of all running processes.
24 25 26 |
# File 'lib/arachni/processes/manager.rb', line 24 def pids @pids end |
Class Method Details
.method_missing(sym, *args, &block) ⇒ Object
224 225 226 227 228 229 230 |
# File 'lib/arachni/processes/manager.rb', line 224 def self.method_missing( sym, *args, &block ) if instance.respond_to?( sym ) instance.send( sym, *args, &block ) else super( sym, *args, &block ) end end |
.respond_to?(m) ⇒ Boolean
232 233 234 |
# File 'lib/arachni/processes/manager.rb', line 232 def self.respond_to?( m ) super( m ) || instance.respond_to?( m ) end |
Instance Method Details
#<<(pid) ⇒ Integer
Returns `pid`.
35 36 37 38 39 |
# File 'lib/arachni/processes/manager.rb', line 35 def <<( pid ) @pids << pid Process.detach pid pid end |
#alive?(pid) ⇒ Boolean
Returns `true` if the process is alive, `false` otherwise.
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/arachni/processes/manager.rb', line 67 def alive?( pid ) # Windows is not big on POSIX so try it its own way if possible. if Arachni.windows? begin alive = false wmi = WIN32OLE.connect( 'winmgmts://' ) processes = wmi.ExecQuery( "select ProcessId from win32_process where ProcessID='#{pid}'" ) processes.each do |proc| proc.ole_free alive = true end processes.ole_free wmi.ole_free return alive rescue WIN32OLERuntimeError end end !!(Process.kill( 0, pid ) rescue false) end |
#discard_output ⇒ Object
117 118 119 |
# File 'lib/arachni/processes/manager.rb', line 117 def discard_output @discard_output = true end |
#discard_output? ⇒ Boolean
121 122 123 |
# File 'lib/arachni/processes/manager.rb', line 121 def discard_output? @discard_output end |
#kill(pid) ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/arachni/processes/manager.rb', line 43 def kill( pid ) Timeout.timeout 10 do while sleep 0.1 do begin Process.kill( Arachni.windows? ? 'KILL' : 'TERM', pid ) # Either kill was successful or we don't have enough perms or # we hit a reused PID for someone else's process, either way, # consider the process gone. rescue Errno::ESRCH, Errno::EPERM, # Don't kill ourselves. SignalException @pids.delete pid return end end end rescue Timeout::Error end |
#kill_many(pids) ⇒ Object
91 92 93 |
# File 'lib/arachni/processes/manager.rb', line 91 def kill_many( pids ) pids.each { |pid| kill pid } end |
#kill_reactor ⇒ Object
Stops the Reactor.
102 103 104 105 106 |
# File 'lib/arachni/processes/manager.rb', line 102 def kill_reactor Reactor.stop rescue nil end |
#killall ⇒ Object
Kills all processes.
96 97 98 99 |
# File 'lib/arachni/processes/manager.rb', line 96 def killall kill_many @pids.dup @pids.clear end |
#preserve_output ⇒ Object
Overrides the default setting of discarding process outputs.
109 110 111 |
# File 'lib/arachni/processes/manager.rb', line 109 def preserve_output @discard_output = false end |
#preserve_output? ⇒ Boolean
113 114 115 |
# File 'lib/arachni/processes/manager.rb', line 113 def preserve_output? !discard_output? end |
#spawn(executable, options = {}) ⇒ Integer
Returns PID of the process.
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/arachni/processes/manager.rb', line 133 def spawn( executable, = {} ) fork = .delete(:fork) fork = false if fork.nil? stdin = .delete(:stdin) stdout = .delete(:stdout) stderr = .delete(:stderr) new_pgroup = .delete(:new_pgroup) = {} if new_pgroup if Arachni.windows? [:new_pgroup] = new_pgroup else [:pgroup] = new_pgroup end end [:in] = stdin if stdin [:out] = stdout if stdout [:err] = stderr if stderr [:ppid] = Process.pid = Options.to_h.merge( .delete(:options) || {} ) # Paths are not included in RPC nor Hash representations as they're # considered local, in this case though they're necessary to provide # the same environment the processes. [:paths] = Options.paths.to_h = Base64.strict_encode64( Marshal.dump( ) ) executable = "#{Options.paths.executables}/#{executable}.rb" = Base64.strict_encode64( Marshal.dump( ) ) argv = [executable, ] # Process.fork is faster, less stressful to the CPU and lets the parent # and child share the same RAM due to copy-on-write support on Ruby 2.0.0. # It is, however, not available when running on Windows nor JRuby so # have a fallback ready. if fork && Process.respond_to?( :fork ) pid = Process.fork do $stdin = [:in] if [:in] if [:out] $stdout = [:out] elsif discard_output? $stdout.reopen( Arachni.null_device, 'w' ) end if [:err] $stderr = [:err] elsif discard_output? $stderr.reopen( Arachni.null_device, 'w' ) end # Careful, Framework.reset will remove objects from Data # structures which off-load to disk, those files however belong # to our parent and should not be touched, thus, we remove # any references to them. Data.framework.page_queue.disk.clear Data.framework.url_queue.disk.clear Data.framework.rpc.distributed_page_queue.disk.clear # Provide a clean slate. Framework.reset Reactor.stop ENV['arachni_options'] = ARGV.replace( argv ) load RUNNER end else # It's very, **VERY** important that we use this argument format as # it bypasses the OS shell and we can thus count on a 1-to-1 process # creation and that the PID we get will be for the actual process. pid = Process.spawn( { 'arachni_options' => }, RbConfig.ruby, RUNNER, *(argv + []) ) end self << pid pid end |