ileitch-hijack 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -6,10 +6,6 @@ Hijack allows you to connect to any ruby process and execute code as if it were
6
6
 
7
7
  Hijack uses DRb over a unix socket file, so you need to be on the same machine as the process you want to hijack. This is by design for security reasons. You also need to run the hijack client as the same user as the remote process.
8
8
 
9
- == WARNING
10
-
11
- Hijack is new code, I'd think twice about trying it out on your critical production systems. I'd love to get some feedback though so if you have any development or staging systems to try it out on then please do!
12
-
13
9
  == Using Hijack
14
10
 
15
11
  $ hijack 16451
@@ -104,12 +100,7 @@ Back in hijack you'll see your browsing activity:
104
100
  2009/08/22 14:24:53 - 127.0.0.1 - /login
105
101
  2009/08/22 14:24:54 - 127.0.0.1 - /signup
106
102
 
107
- Instead of pasting your code into hijack, you can pass hijack the -e option at startup to execute from a file:
108
-
109
- $ hijack -e examples/rails_dispatcher.rb 61565
110
- => Hijacked 61565 (/opt/local/bin/thin) (ruby 1.8.7 [i686-darwin9])
111
- => Executing examples/rails_dispatcher.rb... done!
112
- >> 2009/08/22 14:46:36 - 127.0.0.1 - /
103
+ Instead of pasting your code into hijack, you can pass hijack the -e option execute a local file on the target process.
113
104
 
114
105
  == Process Output
115
106
 
@@ -120,6 +111,8 @@ By default hijack will forward your process output to the hijack client. This ca
120
111
  >> hijack_unmute
121
112
  => true
122
113
 
114
+ For ease of use, hijack helper methods are discoverable with tab completion. hi<tab><tab> will give you a list of available helpers.
115
+
123
116
  == Process Mirroring
124
117
 
125
118
  DRb cannot dump objects to the hijack client for types that are not loaded in the client process. E.g if the remote process had required ActiveRecord and you tried to dump ActiveRecord::Base back to the client, DRb would instead return a DRb::Unknown object as ActiveRecord
data/TODO CHANGED
@@ -1,5 +1,5 @@
1
1
  * Use thread local stdout & stderr capture.
2
2
  * assigning a variable doesn't work
3
3
  * Improve startup experience
4
- * Check if attached process is in fact a ruby process
5
4
  * Require actual remote script if possible so that if it defines any classes we can dump those too.
5
+ * Add a hijack_exec helper to execute a local .rb on the target
data/bin/hijack CHANGED
@@ -11,8 +11,9 @@ new_argv.delete(pid)
11
11
 
12
12
  new_argv.options do |opts|
13
13
  opts.banner = usage
14
- opts.on("--gdb-debug", "Print gdb activity to the console.") { |v| options[:gdb_debug] = v }
15
- opts.on("-e", "--execute=FILE", String, "Execute the specified file in the remote process.") { |v| options[:execute] = v }
14
+ opts.on("--gdb-debug", "Print gdb activity to the console.") { |v| options[:gdb_debug] = true }
15
+ opts.on("--mute", "Ignore stdout/stderr writes from the remote process.") { |v| options[:mute] = true }
16
+ opts.on("-e", "--execute=FILE", String, "Execute the specified file in the remote process and then disconnect.") { |v| options[:execute] = v }
16
17
  opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
17
18
  opts.parse!
18
19
  end
@@ -15,7 +15,7 @@ module Hijack
15
15
  mirror_process
16
16
  banner
17
17
  execute_file
18
- start_output_receiver
18
+ OutputReceiver.start(@remote) unless Hijack.options[:mute]
19
19
  start_irb
20
20
  end
21
21
 
@@ -36,7 +36,7 @@ module Hijack
36
36
  Process.kill('USR2', @pid.to_i)
37
37
  loop do
38
38
  break if File.exists?(Hijack.socket_path_for(@pid))
39
- sleep 0.1
39
+ sleep 0.01
40
40
  end
41
41
  end
42
42
 
@@ -45,30 +45,32 @@ module Hijack
45
45
  end
46
46
 
47
47
  module OutputReceiver
48
- @@mute = false
48
+ class << self
49
+ def mute
50
+ @mute = true
51
+ end
49
52
 
50
- def self.mute
51
- @@mute = true
52
- end
53
+ def unmute(remote)
54
+ start(remote) unless @started
55
+ @mute = false
56
+ end
53
57
 
54
- def self.unmute
55
- @@mute = false
56
- end
58
+ def write(where, str)
59
+ Object.const_get(where.upcase).write(str) unless @mute
60
+ end
57
61
 
58
- def self.write(where, str)
59
- Object.const_get(where.upcase).write(str) unless @@mute
60
- end
62
+ def puts(where, str)
63
+ Object.const_get(where.upcase).puts(str) unless @mute
64
+ end
61
65
 
62
- def self.puts(where, str)
63
- Object.const_get(where.upcase).puts(str) unless @@mute
66
+ def start(remote)
67
+ DRb.start_service(Hijack.socket_for(Process.pid), self)
68
+ remote.evaluate("__hijack_output_receiver_ready_#{Process.pid}")
69
+ @started = true
70
+ end
64
71
  end
65
72
  end
66
73
 
67
- def start_output_receiver
68
- DRb.start_service(Hijack.socket_for(Process.pid), OutputReceiver)
69
- @remote.evaluate("__hijack_output_receiver_ready_#{Process.pid}")
70
- end
71
-
72
74
  def mirror_process
73
75
  # Attempt to require all files currently loaded by the remote process so DRb can dump as many objects as possible.
74
76
  #
@@ -130,6 +132,7 @@ module Hijack
130
132
  $stdout.flush
131
133
  @remote.evaluate(File.read(Hijack.options[:execute]))
132
134
  puts "done!"
135
+ exit
133
136
  else
134
137
  puts "=> Can't find #{Hijack.options[:execute]} to execute!"
135
138
  end
data/lib/hijack/gdb.rb CHANGED
@@ -10,8 +10,11 @@ module Hijack
10
10
  end
11
11
 
12
12
  def attached_to_ruby_process?
13
- # TODO: Implement me
14
- true
13
+ backtrace.any? {|line| line =~ /ruby_run/}
14
+ end
15
+
16
+ def main_thread_blocked_by_join?
17
+ backtrace.any? {|line| line =~ /rb_thread_join/}
15
18
  end
16
19
 
17
20
  def eval(cmd)
@@ -29,6 +32,10 @@ module Hijack
29
32
  end
30
33
 
31
34
  protected
35
+ def backtrace
36
+ @backtrace ||= exec('bt').reverse
37
+ end
38
+
32
39
  def set_trap_pending
33
40
  exec("set variable (int)rb_trap_pending=1")
34
41
  end
@@ -50,7 +57,7 @@ module Hijack
50
57
  end
51
58
 
52
59
  def exec(str)
53
- puts("(gdb) #{str}") if @verbose
60
+ puts("(gdb) #{str}") if @verbose
54
61
  @gdb.puts(str)
55
62
  wait
56
63
  end
@@ -70,6 +77,7 @@ module Hijack
70
77
  end
71
78
  end
72
79
  puts lines.map { |l| "> #{l}" } if @verbose
80
+ lines
73
81
  end
74
82
  end
75
83
  end
data/lib/hijack/helper.rb CHANGED
@@ -20,7 +20,7 @@ module Hijack
20
20
  end
21
21
 
22
22
  def hijack_unmute(remote)
23
- Hijack::Console::OutputReceiver.unmute
23
+ Hijack::Console::OutputReceiver.unmute(remote)
24
24
  true
25
25
  end
26
26
 
@@ -4,6 +4,13 @@ module Hijack
4
4
  gdb = GDB.new(pid)
5
5
  unless gdb.attached_to_ruby_process?
6
6
  puts "\n=> #{pid} doesn't appear to be a Ruby process!"
7
+ gdb.detach
8
+ exit 1
9
+ end
10
+ if gdb.main_thread_blocked_by_join?
11
+ puts "\n=> Unable to hijack #{pid} because the main thread is blocked waiting for another thread to join."
12
+ puts "=> Check that you are using the most recent version of hijack, a newer version may have solved this shortcoming."
13
+ gdb.detach
7
14
  exit 1
8
15
  end
9
16
  gdb.eval(payload(pid))
data/tasks/gem.rake CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'rake/gempackagetask'
2
2
  require 'yaml'
3
3
 
4
- HIJACK_VERSION = '0.1.7'
4
+ HIJACK_VERSION = '0.1.8'
5
5
 
6
6
  task :clean => :clobber_package
7
7
 
data/test/test.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
+ class SomeClass
4
+ end
5
+
3
6
  def do_shit(i)
4
7
  puts i
5
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ileitch-hijack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ian Leitch
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-09-13 21:00:00 -07:00
12
+ date: 2009-09-16 21:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -41,6 +41,8 @@ files:
41
41
  - examples/rails_dispatcher.rb
42
42
  has_rdoc: true
43
43
  homepage: http://github.com/ileitch/hijack
44
+ licenses: []
45
+
44
46
  post_install_message:
45
47
  rdoc_options: []
46
48
 
@@ -61,7 +63,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
61
63
  requirements: []
62
64
 
63
65
  rubyforge_project:
64
- rubygems_version: 1.2.0
66
+ rubygems_version: 1.3.5
65
67
  signing_key:
66
68
  specification_version: 3
67
69
  summary: Provides an irb session to an existing ruby process.