feedupdater 0.1.0
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.
- data/CHANGELOG +2 -0
- data/README +34 -0
- data/bin/feed_updater +309 -0
- data/config/feed_updater.pid +1 -0
- data/config/feed_updater.yml +12 -0
- data/example/custom_updater.rb +14 -0
- data/lib/feed_updater/vendor/daemons/application.rb +298 -0
- data/lib/feed_updater/vendor/daemons/application_group.rb +150 -0
- data/lib/feed_updater/vendor/daemons/cmdline.rb +106 -0
- data/lib/feed_updater/vendor/daemons/controller.rb +134 -0
- data/lib/feed_updater/vendor/daemons/daemonize.rb +265 -0
- data/lib/feed_updater/vendor/daemons/exceptions.rb +28 -0
- data/lib/feed_updater/vendor/daemons/monitor.rb +126 -0
- data/lib/feed_updater/vendor/daemons/pid.rb +61 -0
- data/lib/feed_updater/vendor/daemons/pidfile.rb +99 -0
- data/lib/feed_updater/vendor/daemons/pidmem.rb +10 -0
- data/lib/feed_updater/vendor/daemons.rb +274 -0
- data/lib/feed_updater/version.rb +9 -0
- data/lib/feed_updater.rb +401 -0
- data/rakefile +121 -0
- metadata +80 -0
@@ -0,0 +1,150 @@
|
|
1
|
+
|
2
|
+
module Daemons
|
3
|
+
class ApplicationGroup
|
4
|
+
|
5
|
+
attr_reader :app_name
|
6
|
+
attr_reader :script
|
7
|
+
|
8
|
+
attr_reader :monitor
|
9
|
+
|
10
|
+
#attr_reader :controller
|
11
|
+
|
12
|
+
attr_reader :options
|
13
|
+
|
14
|
+
attr_reader :applications
|
15
|
+
|
16
|
+
attr_accessor :controller_argv
|
17
|
+
attr_accessor :app_argv
|
18
|
+
|
19
|
+
attr_accessor :dir_mode
|
20
|
+
attr_accessor :dir
|
21
|
+
|
22
|
+
# true if the application is supposed to run in multiple instances
|
23
|
+
attr_reader :multiple
|
24
|
+
|
25
|
+
|
26
|
+
def initialize(app_name, options = {})
|
27
|
+
@app_name = app_name
|
28
|
+
@options = options
|
29
|
+
|
30
|
+
if options[:script]
|
31
|
+
@script = File.expand_path(options[:script])
|
32
|
+
end
|
33
|
+
|
34
|
+
#@controller = controller
|
35
|
+
@monitor = nil
|
36
|
+
|
37
|
+
#options = controller.options
|
38
|
+
|
39
|
+
@multiple = options[:multiple] || false
|
40
|
+
|
41
|
+
@dir_mode = options[:dir_mode] || :script
|
42
|
+
@dir = options[:dir] || ''
|
43
|
+
|
44
|
+
#@applications = find_applications(pidfile_dir())
|
45
|
+
@applications = []
|
46
|
+
end
|
47
|
+
|
48
|
+
# Setup the application group.
|
49
|
+
# Currently this functions calls <tt>find_applications</tt> which finds
|
50
|
+
# all running instances of the application and populates the application array.
|
51
|
+
#
|
52
|
+
def setup
|
53
|
+
@applications = find_applications(pidfile_dir())
|
54
|
+
end
|
55
|
+
|
56
|
+
def pidfile_dir
|
57
|
+
PidFile.dir(@dir_mode, @dir, script)
|
58
|
+
end
|
59
|
+
|
60
|
+
def find_applications(dir)
|
61
|
+
pid_files = PidFile.find_files(dir, app_name)
|
62
|
+
|
63
|
+
#pp pid_files
|
64
|
+
|
65
|
+
@monitor = Monitor.find(dir, app_name + '_monitor')
|
66
|
+
|
67
|
+
pid_files.reject! {|f| f =~ /_monitor.pid$/}
|
68
|
+
|
69
|
+
return pid_files.map {|f|
|
70
|
+
app = Application.new(self, {}, PidFile.existing(f))
|
71
|
+
setup_app(app)
|
72
|
+
app
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
def new_application(add_options = {})
|
77
|
+
if @applications.size > 0 and not @multiple
|
78
|
+
if options[:force]
|
79
|
+
@applications.delete_if {|a|
|
80
|
+
unless a.running?
|
81
|
+
a.zap
|
82
|
+
true
|
83
|
+
end
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
raise RuntimeException.new('there is already one or more instance(s) of the program running') unless @applications.empty?
|
88
|
+
end
|
89
|
+
|
90
|
+
app = Application.new(self, add_options)
|
91
|
+
|
92
|
+
setup_app(app)
|
93
|
+
|
94
|
+
@applications << app
|
95
|
+
|
96
|
+
return app
|
97
|
+
end
|
98
|
+
|
99
|
+
def setup_app(app)
|
100
|
+
app.controller_argv = @controller_argv
|
101
|
+
app.app_argv = @app_argv
|
102
|
+
end
|
103
|
+
private :setup_app
|
104
|
+
|
105
|
+
def create_monitor(an_app)
|
106
|
+
return if @monitor
|
107
|
+
|
108
|
+
if options[:monitor]
|
109
|
+
@monitor = Monitor.new(an_app)
|
110
|
+
|
111
|
+
@monitor.start(@applications)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def start_all
|
116
|
+
@monitor.stop if @monitor
|
117
|
+
@monitor = nil
|
118
|
+
|
119
|
+
@applications.each {|a|
|
120
|
+
fork {
|
121
|
+
a.start
|
122
|
+
}
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
126
|
+
def stop_all(force = false)
|
127
|
+
@monitor.stop if @monitor
|
128
|
+
|
129
|
+
@applications.each {|a|
|
130
|
+
if force
|
131
|
+
a.stop rescue nil
|
132
|
+
else
|
133
|
+
a.stop
|
134
|
+
end
|
135
|
+
}
|
136
|
+
end
|
137
|
+
|
138
|
+
def zap_all
|
139
|
+
@monitor.stop if @monitor
|
140
|
+
|
141
|
+
@applications.each {|a| a.zap}
|
142
|
+
end
|
143
|
+
|
144
|
+
def show_status
|
145
|
+
@applications.each {|a| a.show_status}
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
|
2
|
+
module Daemons
|
3
|
+
|
4
|
+
class Optparse
|
5
|
+
|
6
|
+
attr_reader :usage
|
7
|
+
|
8
|
+
def initialize(controller)
|
9
|
+
@controller = controller
|
10
|
+
@options = {}
|
11
|
+
|
12
|
+
@opts = OptionParser.new do |opts|
|
13
|
+
#opts.banner = "Usage: example.rb [options]"
|
14
|
+
opts.banner = ""
|
15
|
+
|
16
|
+
# Boolean switch.
|
17
|
+
# opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
|
18
|
+
# @options[:verbose] = v
|
19
|
+
# end
|
20
|
+
|
21
|
+
opts.on("-t", "--ontop", "Stay on top (does not daemonize)") do |t|
|
22
|
+
@options[:ontop] = t
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on("-f", "--force", "Force operation") do |t|
|
26
|
+
@options[:force] = t
|
27
|
+
end
|
28
|
+
|
29
|
+
#opts.separator ""
|
30
|
+
#opts.separator "Specific options:"
|
31
|
+
|
32
|
+
|
33
|
+
opts.separator ""
|
34
|
+
opts.separator "Common options:"
|
35
|
+
|
36
|
+
# No argument, shows at tail. This will print an options summary.
|
37
|
+
# Try it and see!
|
38
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
39
|
+
#puts opts
|
40
|
+
#@usage =
|
41
|
+
controller.print_usage()
|
42
|
+
|
43
|
+
exit
|
44
|
+
end
|
45
|
+
|
46
|
+
# Another typical switch to print the version.
|
47
|
+
opts.on_tail("--version", "Show version") do
|
48
|
+
puts "daemons version #{Daemons::VERSION}"
|
49
|
+
exit
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
@usage = @opts.to_s
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
#
|
58
|
+
# Return a hash describing the options.
|
59
|
+
#
|
60
|
+
def parse(args)
|
61
|
+
# The options specified on the command line will be collected in *options*.
|
62
|
+
# We set default values here.
|
63
|
+
#options = {}
|
64
|
+
|
65
|
+
|
66
|
+
##pp args
|
67
|
+
@opts.parse(args)
|
68
|
+
|
69
|
+
return @options
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
class Controller
|
76
|
+
|
77
|
+
def print_usage
|
78
|
+
puts "Usage: #{@app_name} <command> <options> -- <application options>"
|
79
|
+
puts
|
80
|
+
puts "* where <command> is one of:"
|
81
|
+
puts " start start an instance of the application"
|
82
|
+
puts " stop stop all instances of the application"
|
83
|
+
puts " restart stop all instances and restart them afterwards"
|
84
|
+
puts " run start the application and stay on top"
|
85
|
+
puts " zap set the application to a stopped state"
|
86
|
+
puts
|
87
|
+
puts "* and where <options> may contain several of the following:"
|
88
|
+
|
89
|
+
puts @optparse.usage
|
90
|
+
end
|
91
|
+
|
92
|
+
def catch_exceptions(&block)
|
93
|
+
begin
|
94
|
+
block.call
|
95
|
+
rescue CmdException, OptionParser::ParseError => e
|
96
|
+
puts "ERROR: #{e.to_s}"
|
97
|
+
puts
|
98
|
+
print_usage()
|
99
|
+
rescue RuntimeException => e
|
100
|
+
puts "ERROR: #{e.to_s}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
|
2
|
+
module Daemons
|
3
|
+
class Controller
|
4
|
+
|
5
|
+
attr_reader :app_name
|
6
|
+
|
7
|
+
attr_reader :group
|
8
|
+
|
9
|
+
attr_reader :options
|
10
|
+
|
11
|
+
|
12
|
+
COMMANDS = [
|
13
|
+
'start',
|
14
|
+
'stop',
|
15
|
+
'restart',
|
16
|
+
'run',
|
17
|
+
'zap',
|
18
|
+
'status'
|
19
|
+
]
|
20
|
+
|
21
|
+
def initialize(options = {}, argv = [])
|
22
|
+
@options = options
|
23
|
+
@argv = argv
|
24
|
+
|
25
|
+
# Allow an app_name to be specified. If not specified use the
|
26
|
+
# basename of the script.
|
27
|
+
@app_name = options[:app_name]
|
28
|
+
|
29
|
+
if options[:script]
|
30
|
+
@script = File.expand_path(options[:script])
|
31
|
+
|
32
|
+
@app_name ||= File.split(@script)[1]
|
33
|
+
end
|
34
|
+
|
35
|
+
@app_name = options[:app_name] if options[:app_name]
|
36
|
+
|
37
|
+
@command, @controller_part, @app_part = Controller.split_argv(argv)
|
38
|
+
|
39
|
+
#@options[:dir_mode] ||= :script
|
40
|
+
|
41
|
+
@optparse = Optparse.new(self)
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
# This function is used to do a final update of the options passed to the application
|
46
|
+
# before they are really used.
|
47
|
+
#
|
48
|
+
# Note that this function should only update <tt>@options</tt> and no other variables.
|
49
|
+
#
|
50
|
+
def setup_options
|
51
|
+
#@options[:ontop] ||= true
|
52
|
+
end
|
53
|
+
|
54
|
+
def run
|
55
|
+
@options.update @optparse.parse(@controller_part).delete_if {|k,v| !v}
|
56
|
+
|
57
|
+
setup_options()
|
58
|
+
|
59
|
+
#pp @options
|
60
|
+
|
61
|
+
@group = ApplicationGroup.new(@app_name, @options)
|
62
|
+
@group.controller_argv = @controller_part
|
63
|
+
@group.app_argv = @app_part
|
64
|
+
|
65
|
+
@group.setup
|
66
|
+
|
67
|
+
case @command
|
68
|
+
when 'start'
|
69
|
+
@group.new_application.start
|
70
|
+
when 'run'
|
71
|
+
@options[:ontop] ||= true
|
72
|
+
@group.new_application.start
|
73
|
+
when 'stop'
|
74
|
+
@group.stop_all
|
75
|
+
when 'restart'
|
76
|
+
unless @group.applications.empty?
|
77
|
+
@group.stop_all
|
78
|
+
sleep 1
|
79
|
+
@group.start_all
|
80
|
+
end
|
81
|
+
when 'zap'
|
82
|
+
@group.zap_all
|
83
|
+
when 'status'
|
84
|
+
unless @group.applications.empty?
|
85
|
+
@group.show_status
|
86
|
+
else
|
87
|
+
puts "#{@group.app_name}: no instances running"
|
88
|
+
end
|
89
|
+
when nil
|
90
|
+
raise CmdException.new('no command given')
|
91
|
+
#puts "ERROR: No command given"; puts
|
92
|
+
|
93
|
+
#print_usage()
|
94
|
+
#raise('usage function not implemented')
|
95
|
+
else
|
96
|
+
raise Error.new("command '#{@command}' not implemented")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
# Split an _argv_ array.
|
102
|
+
# +argv+ is assumed to be in the following format:
|
103
|
+
# ['command', 'controller option 1', 'controller option 2', ..., '--', 'app option 1', ...]
|
104
|
+
#
|
105
|
+
# <tt>command</tt> must be one of the commands listed in <tt>COMMANDS</tt>
|
106
|
+
#
|
107
|
+
# *Returns*: the command as a string, the controller options as an array, the appliation options
|
108
|
+
# as an array
|
109
|
+
#
|
110
|
+
def Controller.split_argv(argv)
|
111
|
+
argv = argv.dup
|
112
|
+
|
113
|
+
command = nil
|
114
|
+
controller_part = []
|
115
|
+
app_part = []
|
116
|
+
|
117
|
+
if COMMANDS.include? argv[0]
|
118
|
+
command = argv.shift
|
119
|
+
end
|
120
|
+
|
121
|
+
if i = argv.index('--')
|
122
|
+
# Handle the case where no controller options are given, just
|
123
|
+
# options after "--" as well (i == 0)
|
124
|
+
controller_part = (i == 0 ? [] : argv[0..i-1])
|
125
|
+
app_part = argv[i+1..-1]
|
126
|
+
else
|
127
|
+
controller_part = argv[0..-1]
|
128
|
+
end
|
129
|
+
|
130
|
+
return command, controller_part, app_part
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
@@ -0,0 +1,265 @@
|
|
1
|
+
#--
|
2
|
+
###############################################################################
|
3
|
+
# daemonize.rb is a slightly modified version of daemonize.rb was #
|
4
|
+
# from the Daemonize Library written by Travis Whitton #
|
5
|
+
# for details, read the notice below #
|
6
|
+
###############################################################################
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
#
|
10
|
+
# =Daemonize Library
|
11
|
+
#
|
12
|
+
# February. 4, 2005 Travis Whitton <whitton@atlantic.net>
|
13
|
+
#
|
14
|
+
# Daemonize allows you to easily modify any existing Ruby program to run
|
15
|
+
# as a daemon. See README.rdoc for more details.
|
16
|
+
#
|
17
|
+
# == How to install
|
18
|
+
# 1. su to root
|
19
|
+
# 2. ruby install.rb
|
20
|
+
# build the docs if you want to
|
21
|
+
# 3. rdoc --main README.rdoc daemonize.rb README.rdoc
|
22
|
+
#
|
23
|
+
# == Copying
|
24
|
+
# The Daemonize extension module is copywrited free software by Travis Whitton
|
25
|
+
# <whitton@atlantic.net>. You can redistribute it under the terms specified in
|
26
|
+
# the COPYING file of the Ruby distribution.
|
27
|
+
#
|
28
|
+
# == WARRANTY
|
29
|
+
# THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
30
|
+
# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
31
|
+
# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
|
32
|
+
# PURPOSE.
|
33
|
+
#
|
34
|
+
#
|
35
|
+
# ----
|
36
|
+
#
|
37
|
+
# == Purpose
|
38
|
+
#
|
39
|
+
# Daemonize is a module derived from Perl's Proc::Daemon module. This module
|
40
|
+
# allows you to easily modify any existing Ruby program to run as a daemon.
|
41
|
+
# A daemon is a process that runs in the background with no controlling terminal.
|
42
|
+
# Generally servers (like FTP and HTTP servers) run as daemon processes.
|
43
|
+
# Note, do not make the mistake that a daemon == server. Converting a program
|
44
|
+
# to a daemon by hand is a relatively simple process; however, this module will
|
45
|
+
# save you the effort of repeatedly looking up the procedure, and it will also
|
46
|
+
# insure that your programs are daemonized in the safest and most corrects
|
47
|
+
# fashion possible.
|
48
|
+
#
|
49
|
+
# == Procedure
|
50
|
+
#
|
51
|
+
# The Daemonize module does the following:
|
52
|
+
#
|
53
|
+
# Forks a child and exits the parent process.
|
54
|
+
#
|
55
|
+
# Becomes a session leader (which detaches the program from
|
56
|
+
# the controlling terminal).
|
57
|
+
#
|
58
|
+
# Forks another child process and exits first child. This prevents
|
59
|
+
# the potential of acquiring a controlling terminal.
|
60
|
+
#
|
61
|
+
# Changes the current working directory to "/".
|
62
|
+
#
|
63
|
+
# Clears the file creation mask.
|
64
|
+
#
|
65
|
+
# Closes file descriptors.
|
66
|
+
#
|
67
|
+
# == Example usage
|
68
|
+
#
|
69
|
+
# Using the Daemonize module is extremely simple:
|
70
|
+
#
|
71
|
+
# require 'daemonize'
|
72
|
+
#
|
73
|
+
# class TestDaemon
|
74
|
+
# include Daemonize
|
75
|
+
#
|
76
|
+
# def initialize
|
77
|
+
# daemonize()
|
78
|
+
# loop do
|
79
|
+
# # do some work here
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# == Credits
|
85
|
+
#
|
86
|
+
# Daemonize was written by Travis Whitton and is based on Perl's
|
87
|
+
# Proc::Daemonize, which was written by Earl Hood. The above documentation
|
88
|
+
# is also partially borrowed from the Proc::Daemonize POD documentation.
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
module Daemonize
|
93
|
+
VERSION = "0.1.1m"
|
94
|
+
|
95
|
+
# Try to fork if at all possible retrying every 5 sec if the
|
96
|
+
# maximum process limit for the system has been reached
|
97
|
+
def safefork
|
98
|
+
tryagain = true
|
99
|
+
|
100
|
+
while tryagain
|
101
|
+
tryagain = false
|
102
|
+
begin
|
103
|
+
if pid = fork
|
104
|
+
return pid
|
105
|
+
end
|
106
|
+
rescue Errno::EWOULDBLOCK
|
107
|
+
sleep 5
|
108
|
+
tryagain = true
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
module_function :safefork
|
113
|
+
|
114
|
+
|
115
|
+
def simulate(logfile_name = nil)
|
116
|
+
# NOTE: STDOUT and STDERR will not be redirected to the logfile!
|
117
|
+
|
118
|
+
Dir.chdir "/" # Release old working directory
|
119
|
+
File.umask 0000 # Insure sensible umask
|
120
|
+
|
121
|
+
# Make sure all file descriptors are closed
|
122
|
+
ObjectSpace.each_object(IO) do |io|
|
123
|
+
unless [STDIN, STDOUT, STDERR].include?(io)
|
124
|
+
begin
|
125
|
+
unless io.closed?
|
126
|
+
io.close
|
127
|
+
end
|
128
|
+
rescue ::Exception
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Free file descriptors and
|
134
|
+
# point them somewhere sensible
|
135
|
+
# STDOUT/STDERR should go to a logfile
|
136
|
+
|
137
|
+
STDIN.reopen "/dev/null" rescue nil
|
138
|
+
end
|
139
|
+
module_function :simulate
|
140
|
+
|
141
|
+
|
142
|
+
def call_as_daemon(block, logfile_name = nil, oldmode = 0)
|
143
|
+
rd, wr = IO.pipe
|
144
|
+
|
145
|
+
if tmppid = safefork
|
146
|
+
# parent
|
147
|
+
wr.close
|
148
|
+
pid = rd.read.to_i
|
149
|
+
rd.close
|
150
|
+
|
151
|
+
Process.waitpid(tmppid)
|
152
|
+
|
153
|
+
return pid
|
154
|
+
else
|
155
|
+
rd.close
|
156
|
+
|
157
|
+
# Detach from the controlling terminal
|
158
|
+
unless sess_id = Process.setsid
|
159
|
+
raise Daemons.RuntimeException.new('cannot detach from controlling terminal')
|
160
|
+
end
|
161
|
+
|
162
|
+
# Prevent the possibility of acquiring a controlling terminal
|
163
|
+
if oldmode.zero?
|
164
|
+
trap 'SIGHUP', 'IGNORE'
|
165
|
+
exit if pid = safefork
|
166
|
+
end
|
167
|
+
|
168
|
+
wr.write Process.pid
|
169
|
+
wr.close
|
170
|
+
|
171
|
+
Dir.chdir "/" # Release old working directory
|
172
|
+
File.umask 0000 # Insure sensible umask
|
173
|
+
|
174
|
+
# Make sure all file descriptors are closed
|
175
|
+
ObjectSpace.each_object(IO) do |io|
|
176
|
+
unless [STDIN, STDOUT, STDERR].include?(io)
|
177
|
+
begin
|
178
|
+
unless io.closed?
|
179
|
+
io.close
|
180
|
+
end
|
181
|
+
rescue ::Exception
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# Free file descriptors and
|
187
|
+
# point them somewhere sensible
|
188
|
+
# STDOUT/STDERR should go to a logfile
|
189
|
+
|
190
|
+
STDIN.reopen "/dev/null" rescue nil
|
191
|
+
|
192
|
+
if logfile_name
|
193
|
+
begin
|
194
|
+
STDOUT.reopen logfile_name, "a"
|
195
|
+
rescue ::Exception
|
196
|
+
STDOUT.reopen "/dev/null" rescue nil
|
197
|
+
end
|
198
|
+
else
|
199
|
+
STDOUT.reopen "/dev/null" rescue nil
|
200
|
+
end
|
201
|
+
|
202
|
+
STDERR.reopen STDOUT rescue nil
|
203
|
+
|
204
|
+
block.call
|
205
|
+
|
206
|
+
exit
|
207
|
+
end
|
208
|
+
end
|
209
|
+
module_function :call_as_daemon
|
210
|
+
|
211
|
+
|
212
|
+
# This method causes the current running process to become a daemon
|
213
|
+
def daemonize(logfile_name = nil, oldmode=0)
|
214
|
+
srand # Split rand streams between spawning and daemonized process
|
215
|
+
safefork and exit # Fork and exit from the parent
|
216
|
+
|
217
|
+
# Detach from the controlling terminal
|
218
|
+
unless sess_id = Process.setsid
|
219
|
+
raise Daemons.RuntimeException.new('cannot detach from controlling terminal')
|
220
|
+
end
|
221
|
+
|
222
|
+
# Prevent the possibility of acquiring a controlling terminal
|
223
|
+
if oldmode.zero?
|
224
|
+
trap 'SIGHUP', 'IGNORE'
|
225
|
+
exit if pid = safefork
|
226
|
+
end
|
227
|
+
|
228
|
+
Dir.chdir "/" # Release old working directory
|
229
|
+
File.umask 0000 # Insure sensible umask
|
230
|
+
|
231
|
+
# Make sure all file descriptors are closed
|
232
|
+
ObjectSpace.each_object(IO) do |io|
|
233
|
+
unless [STDIN, STDOUT, STDERR].include?(io)
|
234
|
+
begin
|
235
|
+
unless io.closed?
|
236
|
+
io.close
|
237
|
+
end
|
238
|
+
rescue ::Exception
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
# Free file descriptors and
|
244
|
+
# point them somewhere sensible
|
245
|
+
# STDOUT/STDERR should go to a logfile
|
246
|
+
|
247
|
+
STDIN.reopen "/dev/null" rescue nil
|
248
|
+
|
249
|
+
if logfile_name
|
250
|
+
begin
|
251
|
+
STDOUT.reopen logfile_name, "a"
|
252
|
+
rescue ::Exception
|
253
|
+
STDOUT.reopen "/dev/null" rescue nil
|
254
|
+
end
|
255
|
+
else
|
256
|
+
STDOUT.reopen "/dev/null" rescue nil
|
257
|
+
end
|
258
|
+
|
259
|
+
STDERR.reopen STDOUT rescue nil
|
260
|
+
|
261
|
+
return oldmode ? sess_id : 0 # Return value is mostly irrelevant
|
262
|
+
end
|
263
|
+
module_function :daemonize
|
264
|
+
|
265
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
module Daemons
|
3
|
+
|
4
|
+
class Exception < ::RuntimeError
|
5
|
+
end
|
6
|
+
|
7
|
+
class RuntimeException < Exception
|
8
|
+
end
|
9
|
+
|
10
|
+
class CmdException < Exception
|
11
|
+
end
|
12
|
+
|
13
|
+
class Error < Exception
|
14
|
+
end
|
15
|
+
|
16
|
+
class SystemError < Error
|
17
|
+
|
18
|
+
attr_reader :system_error
|
19
|
+
|
20
|
+
def initialize(msg, system_error)
|
21
|
+
super(msg)
|
22
|
+
|
23
|
+
@system_error = system_error
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|