Simplified config file (removing meddle construct)
[god.git] / lib / god / process.rb
blobd2d845beca7e1a05a1219ba19dcbe193571270cb
1 require 'fileutils'
3 module God
4   class Process
5     WRITES_PID = [:start, :restart]
6     
7     attr_accessor :name, :uid, :gid, :start, :stop, :restart
8     
9     def initialize(options={})
10       options.each do |k,v|
11         send("#{k}=", v)
12       end
13       
14       @tracking_pid = false
15     end
16     
17     # DON'T USE THIS INTERNALLY. Use the instance variable. -- Kev
18     # No really, trust me. Use the instance variable.
19     def pid_file=(value)
20       @tracking_pid = false
21       @pid_file = value
22     end
23     
24     def pid_file
25       if @pid_file.nil?
26         @tracking_pid = true
27         @pid_file = default_pid_file
28       end
29       @pid_file
30     end
31     
32     def start!
33       call_action(:start)
34     end
35     
36     def stop!
37       call_action(:stop)
38     end
39     
40     def restart!
41       call_action(:restart)
42     end
43     
44     def call_action(action)
45       command = send(action)
46       if command.kind_of?(String)
47         # Make pid directory
48         unless test(?d, God.pid_file_directory)
49           begin
50             FileUtils.mkdir_p(God.pid_file_directory)
51           rescue Errno::EACCES => e
52             abort"Failed to create pid file directory: #{e.message}"
53           end
54         end
55         
56         unless test(?w, God.pid_file_directory)
57           abort "The pid file directory (#{God.pid_file_directory}) is not writable by #{Etc.getlogin}"
58         end
59         
60         # string command
61         # fork/exec to setuid/gid
62         pid = fork {
63           ::Process.setsid
64           ::Process::Sys.setgid(Etc.getgrnam(self.gid).gid) if self.gid
65           ::Process::Sys.setuid(Etc.getpwnam(self.uid).uid) if self.uid
66           Dir.chdir "/"
67           $0 = command
68           STDIN.reopen "/dev/null"
69           STDOUT.reopen "/dev/null", "a"
70           STDERR.reopen STDOUT
71           exec command
72         }
73         
74         ::Process.detach pid
75         
76         if @tracking_pid or (@pid_file.nil? and WRITES_PID.include?(action))
77           File.open(default_pid_file, 'w') do |f|
78             f.write pid
79           end
80           
81           @tracking_pid = true
82           @pid_file = default_pid_file
83         end
84         
85       elsif command.kind_of?(Proc)
86         # lambda command
87         command.call
88       else
89         raise NotImplementedError
90       end
91     end
92     
93     def default_pid_file
94       File.join(God.pid_file_directory, "#{self.name}.pid")
95     end
96   end
97 end