5 WorkingDirectory = File.expand_path(File.dirname(__FILE__))
8 def self.task_identifier
16 def self.pid_fn(timestamp)
17 "/tmp/#{name}.#{timestamp}.pid"
20 def self.daemonize(task_identifier, uid=nil)
21 @@uid = uid || 1000 # The default uid of the daemon process is 10000
22 @@task_identifier = task_identifier
23 Controller.daemonize(self)
28 def self.run_and_record(command)
36 @child_pid, stdin, stdout, stderr =
37 Open4::popen4(command)
40 Process::waitpid2 @child_pid
44 all_files = Dir.glob(pid_fn('*'))
45 all_files.each do |pid_file|
46 pid, command_id = `cat #{pid_file}`.split("\n")
48 if pid.to_i == Process.pid
49 file = File.open(pid_file, "a")
50 file << command.center(80, "-")
53 file << "STDERR".center(80, "=")
57 @@std_errors_txt << err
63 file << "STDOUT".center(80, "=")
71 if !@@ruby_errors.empty?
73 file << "RUBYERR".center(80, "=")
93 def self.daemonize(daemon)
95 if ARGV.include?('--kill-daemon')
102 def self.stop(daemon)
103 all_files = Dir.glob(daemon.pid_fn('*')[0..-5])
106 all_files.each do |pid_file|
107 pid, command_id = `cat #{pid_file}`.split("\n")[0..1] # first 2 lines
108 if command_id == daemon.task_identifier
117 STDERR.puts "No PID files found for:\n #{daemon.task_identifier}"
119 STDERR.puts "Is the daemon started?"
127 # Daemonizer by Travis Whitton
129 # Try to fork if at all possible retrying every 5 sec if the
130 # maximum process limit for the system has been reached
140 rescue Errno::EWOULDBLOCK
147 # This method causes the current running process to become a daemon
148 # If closefd is true, all existing file descriptors are closed
149 def self.start(daemon, oldmode=0, closefd=false)
151 srand # Split rand streams between spawning and daemonized process
152 safefork and exit # Fork and exit from the parent
155 daemon.pid_fn(Time.now.to_i.to_s + '.' +
156 Process.pid.to_s.rjust(5,'0') + '.' +
157 daemon.task_identifier.rjust(26).gsub(' ', '_')
160 raise 'daemon.uid is not set' if daemon.uid == nil
162 if Process.uid != daemon.uid
163 Process.gid = Process.egid =
164 `grep -E ^.*?:.*?:#{Process.uid} /etc/passwd`.split(':')[3].to_i
165 Process.uid = Process.euid = daemon.uid
168 # Detach from the controlling terminal
169 unless sess_id = Process.setsid
170 raise "Cannot detach from controlled terminal"
173 # Prevent the possibility of acquiring a controlling terminal
175 trap 'SIGHUP', 'IGNORE'
176 exit if pid = safefork
180 `echo #{Process.pid} >> #{pid_file}`
181 `echo #{daemon.task_identifier} >> #{pid_file}`
184 Dir.chdir "/" # Release old working directory
185 File.umask 0000 # Insure sensible umask
188 # Make sure all file descriptors are closed
189 ObjectSpace.each_object(IO) do |io|
190 unless [STDIN, STDOUT, STDERR].include?(io)
196 STDIN.reopen "/dev/null" # Free file descriptors and
197 STDOUT.reopen "/dev/null", "a" # point them somewhere sensible
198 STDERR.reopen STDOUT # STDOUT/STDERR should go to a logfile
201 # The user defined tasks
203 daemon.stop # Clean up after daemon terminates self
204 # if the user defined any cleanup procedures
206 return # Return value is mostly irrelevant