bluepill 0.0.68 → 0.0.69

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -2
  3. data/bin/bluepill +19 -20
  4. data/bin/sample_forking_server +26 -13
  5. data/bluepill.gemspec +12 -18
  6. data/lib/bluepill.rb +12 -12
  7. data/lib/bluepill/application.rb +64 -71
  8. data/lib/bluepill/application/client.rb +0 -2
  9. data/lib/bluepill/application/server.rb +1 -3
  10. data/lib/bluepill/condition_watch.rb +12 -7
  11. data/lib/bluepill/controller.rb +37 -42
  12. data/lib/bluepill/dsl.rb +1 -2
  13. data/lib/bluepill/dsl/app_proxy.rb +3 -4
  14. data/lib/bluepill/dsl/process_factory.rb +40 -44
  15. data/lib/bluepill/dsl/process_proxy.rb +4 -5
  16. data/lib/bluepill/group.rb +15 -21
  17. data/lib/bluepill/logger.rb +4 -4
  18. data/lib/bluepill/process.rb +107 -109
  19. data/lib/bluepill/process_conditions.rb +1 -3
  20. data/lib/bluepill/process_conditions/always_true.rb +2 -3
  21. data/lib/bluepill/process_conditions/cpu_usage.rb +0 -1
  22. data/lib/bluepill/process_conditions/file_time.rb +5 -6
  23. data/lib/bluepill/process_conditions/http.rb +11 -9
  24. data/lib/bluepill/process_conditions/mem_usage.rb +6 -7
  25. data/lib/bluepill/process_conditions/process_condition.rb +4 -5
  26. data/lib/bluepill/process_conditions/running_time.rb +1 -2
  27. data/lib/bluepill/process_conditions/zombie_process.rb +1 -2
  28. data/lib/bluepill/process_journal.rb +18 -21
  29. data/lib/bluepill/process_statistics.rb +2 -4
  30. data/lib/bluepill/socket.rb +13 -16
  31. data/lib/bluepill/system.rb +57 -63
  32. data/lib/bluepill/trigger.rb +9 -11
  33. data/lib/bluepill/triggers/flapping.rb +12 -16
  34. data/lib/bluepill/util/rotational_array.rb +1 -2
  35. data/lib/bluepill/version.rb +1 -2
  36. metadata +4 -28
  37. data/.gitignore +0 -12
  38. data/.rspec +0 -1
  39. data/.travis.yml +0 -17
  40. data/Gemfile +0 -27
  41. data/Rakefile +0 -38
  42. data/examples/example.rb +0 -87
  43. data/examples/new_example.rb +0 -89
  44. data/examples/new_runit_example.rb +0 -29
  45. data/examples/runit_example.rb +0 -26
  46. data/local-bluepill +0 -130
  47. data/spec/lib/bluepill/application_spec.rb +0 -51
  48. data/spec/lib/bluepill/logger_spec.rb +0 -3
  49. data/spec/lib/bluepill/process_spec.rb +0 -135
  50. data/spec/lib/bluepill/process_statistics_spec.rb +0 -24
  51. data/spec/lib/bluepill/system_spec.rb +0 -45
  52. data/spec/spec_helper.rb +0 -26
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  module ProcessConditions
4
3
  def self.[](name)
@@ -7,8 +6,7 @@ module Bluepill
7
6
  end
8
7
  end
9
8
 
10
- require "bluepill/process_conditions/process_condition"
9
+ require 'bluepill/process_conditions/process_condition'
11
10
  Dir["#{File.dirname(__FILE__)}/process_conditions/*.rb"].each do |pc|
12
11
  require pc
13
12
  end
14
-
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  module ProcessConditions
4
3
  class AlwaysTrue < ProcessCondition
@@ -6,11 +5,11 @@ module Bluepill
6
5
  @below = options[:below]
7
6
  end
8
7
 
9
- def run(pid, include_children)
8
+ def run(_pid, _include_children)
10
9
  1
11
10
  end
12
11
 
13
- def check(value)
12
+ def check(_value)
14
13
  true
15
14
  end
16
15
  end
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  module ProcessConditions
4
3
  class CpuUsage < ProcessCondition
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  module ProcessConditions
4
3
  class FileTime < ProcessCondition
@@ -7,19 +6,19 @@ module Bluepill
7
6
  @filename = options[:filename]
8
7
  end
9
8
 
10
- def run(pid, include_children)
11
- if File.exists?(@filename)
12
- Time.now()-File::mtime(@filename)
9
+ def run(_pid, _include_children)
10
+ if File.exist?(@filename)
11
+ Time.now - File.mtime(@filename)
13
12
  else
14
13
  nil
15
14
  end
16
15
  rescue
17
- $!
16
+ $ERROR_INFO
18
17
  end
19
18
 
20
19
  def check(value)
21
20
  return false if value.nil?
22
- return value < @below
21
+ value < @below
23
22
  end
24
23
  end
25
24
  end
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require 'net/http'
3
2
  require 'uri'
4
3
 
@@ -8,8 +7,10 @@ module Bluepill
8
7
  def initialize(options = {})
9
8
  @uri = URI.parse(options[:url])
10
9
  @kind = case options[:kind]
11
- when Fixnum then Net::HTTPResponse::CODE_TO_OBJ[options[:kind].to_s]
12
- when String, Symbol then Net.const_get("HTTP#{options[:kind].to_s.camelize}")
10
+ when Fixnum
11
+ Net::HTTPResponse::CODE_TO_OBJ[options[:kind].to_s]
12
+ when String, Symbol
13
+ Net.const_get("HTTP#{options[:kind].to_s.camelize}")
13
14
  else
14
15
  Net::HTTPSuccess
15
16
  end
@@ -18,11 +19,11 @@ module Bluepill
18
19
  @read_timeout = (options[:read_timeout] || options[:timeout] || 5).to_i
19
20
  end
20
21
 
21
- def run(pid, include_children)
22
+ def run(_pid, _include_children)
22
23
  session = Net::HTTP.new(@uri.host, @uri.port)
23
24
  if @uri.scheme == 'https'
24
25
  require 'net/https'
25
- session.use_ssl=true
26
+ session.use_ssl = true
26
27
  session.verify_mode = OpenSSL::SSL::VERIFY_NONE
27
28
  end
28
29
  session.open_timeout = @open_timeout
@@ -33,22 +34,23 @@ module Bluepill
33
34
  end
34
35
  end
35
36
  rescue
36
- $!
37
+ $ERROR_INFO
37
38
  end
38
39
 
39
40
  def check(value)
40
- return false unless value.kind_of?(@kind)
41
+ return false unless value.is_a?(@kind)
41
42
  return true unless @pattern
42
43
  return false unless value.class.body_permitted?
43
44
  @pattern === value.body
44
45
  end
45
46
 
46
47
  private
48
+
47
49
  def hide_net_http_bug
48
50
  yield
49
51
  rescue NoMethodError => e
50
- if e.to_s =~ /#{Regexp.escape(%q|undefined method `closed?' for nil:NilClass|)}/
51
- raise Errno::ECONNREFUSED, "Connection refused attempting to contact #{@uri.scheme}://#{@uri.host}:#{@uri.port}"
52
+ if e.to_s =~ /#{Regexp.escape("undefined method `closed?' for nil:NilClass")}/
53
+ raise(Errno::ECONNREFUSED.new("Connection refused attempting to contact #{@uri.scheme}://#{@uri.host}:#{@uri.port}"))
52
54
  else
53
55
  raise
54
56
  end
@@ -1,11 +1,10 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  module ProcessConditions
4
3
  class MemUsage < ProcessCondition
5
- MB = 1024 ** 2
6
- FORMAT_STR = "%d%s"
7
- MB_LABEL = "MB"
8
- KB_LABEL = "KB"
4
+ MB = 1024**2
5
+ FORMAT_STR = '%d%s'
6
+ MB_LABEL = 'MB'
7
+ KB_LABEL = 'KB'
9
8
 
10
9
  def initialize(options = {})
11
10
  @below = options[:below]
@@ -22,9 +21,9 @@ module Bluepill
22
21
 
23
22
  def format_value(value)
24
23
  if value.kilobytes >= MB
25
- FORMAT_STR % [(value / 1024).round, MB_LABEL]
24
+ format(FORMAT_STR, (value / 1024).round, MB_LABEL)
26
25
  else
27
- FORMAT_STR % [value, KB_LABEL]
26
+ format(FORMAT_STR, value, KB_LABEL)
28
27
  end
29
28
  end
30
29
  end
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  module ProcessConditions
4
3
  class ProcessCondition
@@ -6,12 +5,12 @@ module Bluepill
6
5
  @options = options
7
6
  end
8
7
 
9
- def run(pid, include_children)
10
- raise "Implement in subclass!"
8
+ def run(_pid, _include_children)
9
+ fail 'Implement in subclass!'
11
10
  end
12
11
 
13
- def check(value)
14
- raise "Implement in subclass!"
12
+ def check(_value)
13
+ fail 'Implement in subclass!'
15
14
  end
16
15
 
17
16
  def format_value(value)
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  module ProcessConditions
4
3
  class RunningTime < ProcessCondition
@@ -6,7 +5,7 @@ module Bluepill
6
5
  @below = options[:below]
7
6
  end
8
7
 
9
- def run(pid, include_children)
8
+ def run(pid, _include_children)
10
9
  System.running_time(pid)
11
10
  end
12
11
 
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  module ProcessConditions
4
3
  # Process must have cache_actual_pid set to false to function correctly:
@@ -7,7 +6,7 @@ module Bluepill
7
6
  # process.cache_actual_pid = false
8
7
 
9
8
  class ZombieProcess < ProcessCondition
10
- def run(pid, include_children)
9
+ def run(pid, _include_children)
11
10
  System.command(pid)
12
11
  end
13
12
 
@@ -2,7 +2,7 @@ require 'bluepill/system'
2
2
 
3
3
  module Bluepill
4
4
  module ProcessJournal
5
- extend self
5
+ module_function
6
6
 
7
7
  class << self
8
8
  attr_reader :logger
@@ -13,8 +13,8 @@ module Bluepill
13
13
  end
14
14
 
15
15
  def base_dir=(base_dir)
16
- @journal_base_dir ||= File.join(base_dir, "journals")
17
- FileUtils.mkdir_p(@journal_base_dir) unless File.exists?(@journal_base_dir)
16
+ @journal_base_dir ||= File.join(base_dir, 'journals')
17
+ FileUtils.mkdir_p(@journal_base_dir) unless File.exist?(@journal_base_dir)
18
18
  FileUtils.chmod(0777, @journal_base_dir)
19
19
  end
20
20
  end
@@ -39,7 +39,7 @@ module Bluepill
39
39
  times += 1
40
40
  logger.debug("Waiting for lock #{name}")
41
41
  sleep 1
42
- unless times >= 10
42
+ if times < 10
43
43
  retry
44
44
  else
45
45
  logger.info("Timeout waiting for lock #{name}")
@@ -65,7 +65,7 @@ module Bluepill
65
65
 
66
66
  def pid_journal(filename)
67
67
  logger.debug("pid journal file: #{filename}")
68
- result = File.open(filename, 'r').readlines.map(&:to_i).reject {|pid| skip_pid?(pid)}
68
+ result = File.open(filename, 'r').readlines.map(&:to_i).reject { |pid| skip_pid?(pid) }
69
69
  logger.debug("pid journal = #{result.join(' ')}")
70
70
  result
71
71
  rescue Errno::ENOENT
@@ -74,7 +74,7 @@ module Bluepill
74
74
 
75
75
  def pgid_journal(filename)
76
76
  logger.debug("pgid journal file: #{filename}")
77
- result = File.open(filename, 'r').readlines.map(&:to_i).reject {|pgid| skip_pgid?(pgid)}
77
+ result = File.open(filename, 'r').readlines.map(&:to_i).reject { |pgid| skip_pgid?(pgid) }
78
78
  logger.debug("pgid journal = #{result.join(' ')}")
79
79
  result
80
80
  rescue Errno::ENOENT
@@ -82,18 +82,15 @@ module Bluepill
82
82
  end
83
83
 
84
84
  def clear_atomic_fs_lock(name)
85
- if File.directory?(name)
86
- Dir.rmdir(name)
87
- logger.debug("Cleared lock #{name}")
88
- end
85
+ return unless File.directory?(name)
86
+ Dir.rmdir(name)
87
+ logger.debug("Cleared lock #{name}")
89
88
  end
90
89
 
91
90
  def kill_all_from_all_journals
92
- Dir[".bluepill_pids_journal.*"].map { |x|
93
- x.sub(/^\.bluepill_pids_journal\./,"")
94
- }.reject { |y|
95
- y =~ /\.lock$/
96
- }.each do |journal_name|
91
+ pids = Dir['.bluepill_pids_journal.*'].map { |p| p.sub(/^\.bluepill_pids_journal\./, '') }
92
+ pids.reject! { |p| p =~ /\.lock$/ }
93
+ pids.each do |journal_name|
97
94
  kill_all_from_journal(journal_name)
98
95
  end
99
96
  end
@@ -177,13 +174,13 @@ module Bluepill
177
174
 
178
175
  filename = pgid_journal_filename(journal_name)
179
176
  acquire_atomic_fs_lock(filename) do
180
- unless pgid_journal(filename).include?(pgid)
177
+ if pgid_journal(filename).include?(pgid)
178
+ logger.debug("Skipping duplicate pgid #{pgid} already in journal #{journal_name}")
179
+ else
181
180
  logger.debug("Saving pgid #{pgid} to process journal #{journal_name}")
182
181
  File.open(filename, 'a+', 0600) { |f| f.puts(pgid) }
183
182
  logger.info("Saved pgid #{pgid} to journal #{journal_name}")
184
183
  logger.debug("Journal now = #{File.open(filename, 'r').read}")
185
- else
186
- logger.debug("Skipping duplicate pgid #{pgid} already in journal #{journal_name}")
187
184
  end
188
185
  end
189
186
  end
@@ -200,13 +197,13 @@ module Bluepill
200
197
 
201
198
  filename = pid_journal_filename(journal_name)
202
199
  acquire_atomic_fs_lock(filename) do
203
- unless pid_journal(filename).include?(pid)
200
+ if pid_journal(filename).include?(pid)
201
+ logger.debug("Skipping duplicate pid #{pid} already in journal #{journal_name}")
202
+ else
204
203
  logger.debug("Saving pid #{pid} to process journal #{journal_name}")
205
204
  File.open(filename, 'a+', 0600) { |f| f.puts(pid) }
206
205
  logger.info("Saved pid #{pid} to journal #{journal_name}")
207
206
  logger.debug("Journal now = #{File.open(filename, 'r').read}")
208
- else
209
- logger.debug("Skipping duplicate pid #{pid} already in journal #{journal_name}")
210
207
  end
211
208
  end
212
209
  end
@@ -1,7 +1,6 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  class ProcessStatistics
4
- STRFTIME = "%m/%d/%Y %H:%I:%S".freeze
3
+ STRFTIME = '%m/%d/%Y %H:%I:%S'.freeze
5
4
  EVENTS_TO_PERSIST = 10
6
5
 
7
6
  attr_reader :events
@@ -17,11 +16,10 @@ module Bluepill
17
16
 
18
17
  def to_s
19
18
  str = events.reverse.map do |(event, reason, time)|
20
- " #{event} at #{time.strftime(STRFTIME)} - #{reason || "unspecified"}"
19
+ " #{event} at #{time.strftime(STRFTIME)} - #{reason || 'unspecified'}"
21
20
  end.join("\n")
22
21
 
23
22
  "event history:\n#{str}"
24
23
  end
25
24
  end
26
25
  end
27
-
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require 'socket'
3
2
 
4
3
  module Bluepill
@@ -6,7 +5,7 @@ module Bluepill
6
5
  TIMEOUT = 60 # Used for client commands
7
6
  MAX_ATTEMPTS = 5
8
7
 
9
- extend self
8
+ module_function
10
9
 
11
10
  def client(base_dir, name, &block)
12
11
  UNIXSocket.open(socket_path(base_dir, name), &block)
@@ -25,7 +24,7 @@ module Bluepill
25
24
  break
26
25
  rescue EOFError, Timeout::Error
27
26
  if current_attempt == MAX_ATTEMPTS - 1
28
- abort("Socket Timeout: Server may not be responding")
27
+ abort('Socket Timeout: Server may not be responding')
29
28
  end
30
29
  puts "Retry #{current_attempt + 1} of #{MAX_ATTEMPTS}"
31
30
  end
@@ -35,24 +34,22 @@ module Bluepill
35
34
 
36
35
  def server(base_dir, name)
37
36
  socket_path = self.socket_path(base_dir, name)
37
+ UNIXServer.open(socket_path)
38
+ rescue Errno::EADDRINUSE
38
39
  begin
39
- UNIXServer.open(socket_path)
40
- rescue Errno::EADDRINUSE
41
- # if sock file has been created. test to see if there is a server
42
- begin
43
- UNIXSocket.open(socket_path)
44
- rescue Errno::ECONNREFUSED
45
- File.delete(socket_path)
46
- return UNIXServer.open(socket_path)
47
- else
48
- logger.err("Server is already running!")
49
- exit(7)
50
- end
40
+ # if sock file has been created, test to see if there is a server
41
+ UNIXSocket.open(socket_path)
42
+ rescue Errno::ECONNREFUSED
43
+ File.delete(socket_path)
44
+ return UNIXServer.open(socket_path)
45
+ else
46
+ logger.err('Server is already running!')
47
+ exit(7)
51
48
  end
52
49
  end
53
50
 
54
51
  def socket_path(base_dir, name)
55
- File.join(base_dir, 'socks', name + ".sock")
52
+ File.join(base_dir, 'socks', name + '.sock')
56
53
  end
57
54
  end
58
55
  end
@@ -1,13 +1,13 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require 'etc'
3
- require "shellwords"
2
+ require 'shellwords'
4
3
 
5
4
  module Bluepill
6
5
  # This class represents the system that bluepill is running on.. It's mainly used to memoize
7
6
  # results of running ps auxx etc so that every watch in the every process will not result in a fork
8
7
  module System
9
- APPEND_MODE = "a"
10
- extend self
8
+ APPEND_MODE = 'a'
9
+
10
+ module_function
11
11
 
12
12
  # The position of each field in ps output
13
13
  IDX_MAP = {
@@ -16,27 +16,25 @@ module Bluepill
16
16
  :pcpu => 2,
17
17
  :rss => 3,
18
18
  :etime => 4,
19
- :command => 5
19
+ :command => 5,
20
20
  }
21
21
 
22
22
  def pid_alive?(pid)
23
- begin
24
- ::Process.kill(0, pid)
25
- true
26
- rescue Errno::EPERM # no permission, but it is definitely alive
27
- true
28
- rescue Errno::ESRCH
29
- false
30
- end
23
+ ::Process.kill(0, pid)
24
+ true
25
+ rescue Errno::EPERM # no permission, but it is definitely alive
26
+ true
27
+ rescue Errno::ESRCH
28
+ false
31
29
  end
32
30
 
33
31
  def cpu_usage(pid, include_children)
34
32
  ps = ps_axu
35
33
  return unless ps[pid]
36
34
  cpu_used = ps[pid][IDX_MAP[:pcpu]].to_f
37
- get_children(pid).each { |child_pid|
35
+ get_children(pid).each do |child_pid|
38
36
  cpu_used += ps[child_pid][IDX_MAP[:pcpu]].to_f if ps[child_pid]
39
- } if include_children
37
+ end if include_children
40
38
  cpu_used
41
39
  end
42
40
 
@@ -44,9 +42,9 @@ module Bluepill
44
42
  ps = ps_axu
45
43
  return unless ps[pid]
46
44
  mem_used = ps[pid][IDX_MAP[:rss]].to_f
47
- get_children(pid).each { |child_pid|
45
+ get_children(pid).each do |child_pid|
48
46
  mem_used += ps[child_pid][IDX_MAP[:rss]].to_f if ps[child_pid]
49
- } if include_children
47
+ end if include_children
50
48
  mem_used
51
49
  end
52
50
 
@@ -63,11 +61,11 @@ module Bluepill
63
61
  end
64
62
 
65
63
  def get_children(parent_pid)
66
- child_pids = Array.new
67
- ps_axu.each_pair do |pid, chunks|
64
+ child_pids = []
65
+ ps_axu.each_pair do |_pid, chunks|
68
66
  child_pids << chunks[IDX_MAP[:pid]].to_i if chunks[IDX_MAP[:ppid]].to_i == parent_pid.to_i
69
67
  end
70
- grand_children = child_pids.map{|pid| get_children(pid)}.flatten
68
+ grand_children = child_pids.map { |pid| get_children(pid) }.flatten
71
69
  child_pids.concat grand_children
72
70
  end
73
71
 
@@ -75,8 +73,9 @@ module Bluepill
75
73
  def daemonize(cmd, options = {})
76
74
  rd, wr = IO.pipe
77
75
 
78
- if child = Daemonize.safefork
79
- # we do not wanna create zombies, so detach ourselves from the child exit status
76
+ child = Daemonize.safefork
77
+ if child
78
+ # we don't want to create zombies, so detach ourselves from the child exit status
80
79
  ::Process.detach(child)
81
80
 
82
81
  # parent
@@ -86,7 +85,6 @@ module Bluepill
86
85
  rd.close
87
86
 
88
87
  return daemon_id if daemon_id > 0
89
-
90
88
  else
91
89
  # child
92
90
  rd.close
@@ -98,7 +96,7 @@ module Bluepill
98
96
 
99
97
  to_daemonize = lambda do
100
98
  # Setting end PWD env emulates bash behavior when dealing with symlinks
101
- Dir.chdir(ENV["PWD"] = options[:working_dir].to_s) if options[:working_dir]
99
+ Dir.chdir(ENV['PWD'] = options[:working_dir].to_s) if options[:working_dir]
102
100
  options[:environment].each { |key, value| ENV[key.to_s] = value.to_s } if options[:environment]
103
101
 
104
102
  redirect_io(*options.values_at(:stdin, :stdout, :stderr))
@@ -109,12 +107,12 @@ module Bluepill
109
107
 
110
108
  daemon_id = Daemonize.call_as_daemon(to_daemonize, nil, cmd)
111
109
 
112
- File.open(options[:pid_file], "w") {|f| f.write(daemon_id)}
110
+ File.open(options[:pid_file], 'w') { |f| f.write(daemon_id) }
113
111
 
114
112
  wr.write daemon_id
115
113
  wr.close
116
114
 
117
- ::Process::exit!(true)
115
+ ::Process.exit!(true)
118
116
  end
119
117
  end
120
118
 
@@ -122,7 +120,7 @@ module Bluepill
122
120
  tries = 0
123
121
 
124
122
  begin
125
- File.unlink(filename) if filename && File.exists?(filename)
123
+ File.unlink(filename) if filename && File.exist?(filename)
126
124
  rescue IOError, Errno::ENOENT
127
125
  rescue Errno::EACCES
128
126
  retry if (tries += 1) < 3
@@ -134,7 +132,8 @@ module Bluepill
134
132
  def execute_blocking(cmd, options = {})
135
133
  rd, wr = IO.pipe
136
134
 
137
- if child = Daemonize.safefork
135
+ child = Daemonize.safefork
136
+ if child
138
137
  # parent
139
138
  wr.close
140
139
 
@@ -152,12 +151,12 @@ module Bluepill
152
151
  cmd_out_read, cmd_out_write = IO.pipe
153
152
  cmd_err_read, cmd_err_write = IO.pipe
154
153
 
155
- pid = fork {
154
+ pid = fork do
156
155
  begin
157
156
  # grandchild
158
157
  drop_privileges(options[:uid], options[:gid], options[:supplementary_groups])
159
158
 
160
- Dir.chdir(ENV["PWD"] = options[:working_dir].to_s) if options[:working_dir]
159
+ Dir.chdir(ENV['PWD'] = options[:working_dir].to_s) if options[:working_dir]
161
160
  options[:environment].each { |key, value| ENV[key.to_s] = value.to_s } if options[:environment]
162
161
 
163
162
  # close unused fds so ancestors wont hang. This line is the only reason we are not
@@ -166,7 +165,7 @@ module Bluepill
166
165
  wr.close
167
166
 
168
167
  # we do not care about stdin of cmd
169
- STDIN.reopen("/dev/null")
168
+ STDIN.reopen('/dev/null')
170
169
 
171
170
  # point stdout of cmd to somewhere we can read
172
171
  cmd_out_read.close
@@ -180,12 +179,12 @@ module Bluepill
180
179
 
181
180
  # finally, replace grandchild with cmd
182
181
  ::Kernel.exec(*Shellwords.shellwords(cmd))
183
- rescue Exception => e
184
- (cmd_err_write.closed? ? STDERR : cmd_err_write).puts "Exception in grandchild: #{e.to_s}."
182
+ rescue => e
183
+ (cmd_err_write.closed? ? STDERR : cmd_err_write).puts "Exception in grandchild: #{e}."
185
184
  (cmd_err_write.closed? ? STDERR : cmd_err_write).puts e.backtrace
186
185
  exit 1
187
186
  end
188
- }
187
+ end
189
188
 
190
189
  # we do not use these ends of the pipes in the child
191
190
  cmd_out_write.close
@@ -198,7 +197,7 @@ module Bluepill
198
197
  result = {
199
198
  :stdout => cmd_out_read.read,
200
199
  :stderr => cmd_err_read.read,
201
- :exit_code => $?.exitstatus
200
+ :exit_code => $CHILD_STATUS.exitstatus,
202
201
  }
203
202
 
204
203
  # We're done with these ends of the pipes as well
@@ -214,7 +213,7 @@ module Bluepill
214
213
  end
215
214
 
216
215
  def store
217
- @store ||= Hash.new
216
+ @store ||= {}
218
217
  end
219
218
 
220
219
  def reset_data
@@ -229,7 +228,7 @@ module Bluepill
229
228
 
230
229
  lines.inject(Hash.new) do |mem, line|
231
230
  chunks = line.split(/\s+/)
232
- chunks.delete_if {|c| c.strip.empty? }
231
+ chunks.delete_if { |c| c.strip.empty? }
233
232
  pid = chunks[IDX_MAP[:pid]].strip.to_i
234
233
  command = chunks.slice!(IDX_MAP[:command], chunks.length).join ' '
235
234
  chunks[IDX_MAP[:command]] = command
@@ -242,11 +241,11 @@ module Bluepill
242
241
  def parse_elapsed_time(str)
243
242
  # [[dd-]hh:]mm:ss
244
243
  if str =~ /(?:(?:(\d+)-)?(\d\d):)?(\d\d):(\d\d)/
245
- days = ($1 || 0).to_i
246
- hours = ($2 || 0).to_i
247
- mins = $3.to_i
248
- secs = $4.to_i
249
- ((days*24 + hours)*60 + mins)*60 + secs
244
+ days = (Regexp.last_match[1] || 0).to_i
245
+ hours = (Regexp.last_match[2] || 0).to_i
246
+ mins = Regexp.last_match[3].to_i
247
+ secs = Regexp.last_match[4].to_i
248
+ ((days * 24 + hours) * 60 + mins) * 60 + secs
250
249
  else
251
250
  0
252
251
  end
@@ -255,33 +254,28 @@ module Bluepill
255
254
  # be sure to call this from a fork otherwise it will modify the attributes
256
255
  # of the bluepill daemon
257
256
  def drop_privileges(uid, gid, supplementary_groups)
258
- if ::Process::Sys.geteuid == 0
259
- uid_num = Etc.getpwnam(uid).uid if uid
260
- gid_num = Etc.getgrnam(gid).gid if gid
261
-
262
- supplementary_groups ||= []
263
-
264
- group_nums = supplementary_groups.map do |group|
265
- Etc.getgrnam(group).gid
266
- end
267
-
268
- ::Process.groups = [gid_num] if gid
269
- ::Process.groups |= group_nums unless group_nums.empty?
270
- ::Process::Sys.setgid(gid_num) if gid
271
- ::Process::Sys.setuid(uid_num) if uid
272
- ENV['HOME'] = Etc.getpwuid(uid_num).try(:dir) || ENV['HOME'] if uid
257
+ return unless ::Process::Sys.geteuid.zero?
258
+ uid_num = Etc.getpwnam(uid).uid if uid
259
+ gid_num = Etc.getgrnam(gid).gid if gid
260
+ supplementary_groups ||= []
261
+ group_nums = supplementary_groups.map do |group|
262
+ Etc.getgrnam(group).gid
273
263
  end
264
+ ::Process.groups = [gid_num] if gid
265
+ ::Process.groups |= group_nums unless group_nums.empty?
266
+ ::Process::Sys.setgid(gid_num) if gid
267
+ ::Process::Sys.setuid(uid_num) if uid
268
+ ENV['HOME'] = Etc.getpwuid(uid_num).try(:dir) || ENV['HOME'] if uid
274
269
  end
275
270
 
276
271
  def can_write_pid_file(pid_file, logger)
277
272
  FileUtils.touch(pid_file)
278
273
  File.unlink(pid_file)
279
- return true
280
-
281
- rescue Exception => e
282
- logger.warning "%s - %s" % [e.class.name, e.message]
283
- e.backtrace.each {|l| logger.warning l}
284
- return false
274
+ true
275
+ rescue => e
276
+ logger.warning(format('%s - %s', e.class.name, e.message))
277
+ e.backtrace.each { |l| logger.warning l }
278
+ false
285
279
  end
286
280
 
287
281
  def redirect_io(io_in, io_out, io_err)