5 WRITES_PID = [:start, :restart]
7 attr_accessor :name, :uid, :gid, :log, :start, :stop, :restart
10 self.log = '/dev/null'
18 pid = File.read(self.pid_file).strip.to_i
19 System::Process.new(pid).exists?
25 def file_writable?(file)
27 ::Process::Sys.setgid(Etc.getgrnam(self.gid).gid) if self.gid
28 ::Process::Sys.setuid(Etc.getpwnam(self.uid).uid) if self.uid
30 File.writable?(file) ? exit(0) : exit(1)
33 wpid, status = ::Process.waitpid2(pid)
34 status.exitstatus == 0 ? true : false
38 # determine if we're tracking pid or not
43 # a start command must be specified
46 LOG.log(self, :error, "No start command was specified")
49 # self-daemonizing processes must specify a stop command
50 if !@tracking_pid && self.stop.nil?
52 LOG.log(self, :error, "No stop command was specified")
55 # uid must exist if specified
58 Etc.getpwnam(self.uid)
61 LOG.log(self, :error, "UID for '#{self.uid}' does not exist")
65 # gid must exist if specified
68 Etc.getgrnam(self.gid)
71 LOG.log(self, :error, "GID for '#{self.gid}' does not exist")
75 # pid dir must exist if specified
76 if !@tracking_pid && !File.exist?(File.dirname(self.pid_file))
78 LOG.log(self, :error, "PID file directory '#{File.dirname(self.pid_file)}' does not exist")
81 # pid dir must be writable if specified
82 if !@tracking_pid && !file_writable?(File.dirname(self.pid_file))
84 LOG.log(self, :error, "PID file directory '#{File.dirname(self.pid_file)}' is not writable by #{self.uid || Etc.getlogin}")
87 # log dir must exist if specified
88 if self.log && !File.exist?(File.dirname(self.log))
90 LOG.log(self, :error, "Log directory '#{File.dirname(self.log)}' does not exist")
93 # log dir must be writable if specified
94 if self.log && !file_writable?(File.dirname(self.log))
96 LOG.log(self, :error, "Log directory '#{File.dirname(self.log)}' is not writable by #{self.uid || Etc.getlogin}")
102 # DON'T USE THIS INTERNALLY. Use the instance variable. -- Kev
103 # No really, trust me. Use the instance variable.
105 # if value is nil, do the right thing
107 @tracking_pid = false
116 @pid_file ||= default_pid_file
128 call_action(:restart)
134 ::Process::Sys.setgid(Etc.getgrnam(self.gid).gid) if self.gid
135 ::Process::Sys.setuid(Etc.getpwnam(self.uid).uid) if self.uid
138 STDIN.reopen "/dev/null"
139 STDOUT.reopen self.log, "a"
142 exec command unless command.empty?
146 def call_action(action)
147 command = send(action)
149 if action == :stop && command.nil?
150 pid = File.read(self.pid_file).strip.to_i
153 LOG.log(self, :info, "#{self.name} stop: default lambda killer")
155 ::Process.kill('HUP', pid) rescue nil
157 # Poll to see if it's dead
160 ::Process.kill(0, pid)
169 ::Process.kill('KILL', pid) rescue nil
173 if command.kind_of?(String)
177 # double fork god-daemonized processes
178 # we don't want to wait for them to finish
183 pid = self.spawn(command)
187 ::Process.waitpid(opid, 0)
191 # single fork self-daemonizing processes
192 # we want to wait for them to finish
193 pid = self.spawn(command)
194 ::Process.waitpid(pid, 0)
197 if @tracking_pid or (@pid_file.nil? and WRITES_PID.include?(action))
198 File.open(default_pid_file, 'w') do |f|
203 @pid_file = default_pid_file
205 elsif command.kind_of?(Proc)
209 raise NotImplementedError
214 File.join(God.pid_file_directory, "#{self.name}.pid")