| Class | Merb::Server |
| In: |
merb-core/lib/merb-core/server.rb
|
| Parent: | Object |
Change privileges of the process to the specified user and group.
| user<String>: | The user to change the process to. |
| group<String>: | The group to change the process to. |
If group is left out, the user will be used as the group.
:api: private
# File merb-core/lib/merb-core/server.rb, line 324
324: def _change_privilege(user, group=user)
325: Merb.logger.warn! "Changing privileges to #{user}:#{group}"
326:
327: uid, gid = Process.euid, Process.egid
328:
329: begin
330: target_uid = Etc.getpwnam(user).uid
331: rescue ArgumentError => e
332: Merb.fatal!("Failed to change to user #{user}, does the user exist?", e)
333: return false
334: end
335:
336: begin
337: target_gid = Etc.getgrnam(group).gid
338: rescue ArgumentError => e
339: Merb.fatal!("Failed to change to group #{group}, does the group exist?", e)
340: return false
341: end
342:
343: if (uid != target_uid) || (gid != target_gid)
344: # Change process ownership
345: Process.initgroups(user, target_gid)
346: Process::GID.change_privilege(target_gid)
347: Process::UID.change_privilege(target_uid)
348: end
349: true
350: rescue Errno::EPERM => e
351: Merb.fatal! "Permission denied for changing user:group to #{user}:#{group}.", e
352: false
353: end
Add trap to enter IRB on SIGINT. Process exit if second SIGINT is received.
:api: private
# File merb-core/lib/merb-core/server.rb, line 358
358: def add_irb_trap
359: Merb.trap("INT") do
360: if @interrupted
361: Merb.logger.warn! "Interrupt received a second time, exiting!\n"
362: exit
363: end
364:
365: @interrupted = true
366: Merb.logger.warn! "Interrupt a second time to quit."
367: Kernel.sleep 1.5
368: ARGV.clear # Avoid passing args to IRB
369:
370: if @irb.nil?
371: require "irb"
372: IRB.setup(nil)
373: @irb = IRB::Irb.new(nil)
374: IRB.conf[:MAIN_CONTEXT] = @irb.context
375: end
376:
377: Merb.trap(:INT) { @irb.signal_handle }
378: catch(:IRB_EXIT) { @irb.eval_input }
379:
380: Merb.logger.warn! "Exiting from IRB mode back into server mode."
381: @interrupted = false
382: add_irb_trap
383: end
384: end
| port<~to_s>: | The port to check for Merb instances on. |
| Boolean: | True if Merb is running on the specified port. |
:api: private
# File merb-core/lib/merb-core/server.rb, line 54
54: def alive?(port)
55: pidfile = pid_file(port)
56: pid = pid_in_file(pidfile)
57: Process.kill(0, pid)
58: true
59: rescue Errno::ESRCH, Errno::ENOENT
60: false
61: rescue Errno::EACCES => e
62: Merb.fatal!("You don't have access to the PID file at #{pidfile}: #{e.message}")
63: end
Starts up Merb by running the bootloader and starting the adapter.
:api: private
# File merb-core/lib/merb-core/server.rb, line 168
168: def bootup
169: Merb.trap("TERM") { shutdown }
170:
171: Merb.logger.warn! "Running bootloaders..." if Merb::Config[:verbose]
172: BootLoader.run
173: Merb.logger.warn! "Starting Rack adapter..." if Merb::Config[:verbose]
174: Merb.adapter.start(Merb::Config.to_hash)
175: end
Change process user/group to those specified in Merb::Config.
:api: private
# File merb-core/lib/merb-core/server.rb, line 190
190: def change_privilege
191: if Merb::Config[:user] && Merb::Config[:group]
192: Merb.logger.verbose! "About to change privilege to group " \
193: "#{Merb::Config[:group]} and user #{Merb::Config[:user]}"
194: _change_privilege(Merb::Config[:user], Merb::Config[:group])
195: elsif Merb::Config[:user]
196: Merb.logger.verbose! "About to change privilege to user " \
197: "#{Merb::Config[:user]}"
198: _change_privilege(Merb::Config[:user])
199: else
200: return true
201: end
202: end
| port<~to_s>: | The port of the Merb process to daemonize. |
:api: private
# File merb-core/lib/merb-core/server.rb, line 141
141: def daemonize(port)
142: Merb.logger.warn! "About to fork..." if Merb::Config[:verbose]
143: fork do
144: Process.setsid
145: exit if fork
146: Merb.logger.warn! "In #{Process.pid}" if Merb.logger
147: File.umask 0000
148: STDIN.reopen "/dev/null"
149: STDOUT.reopen "/dev/null", "a"
150: STDERR.reopen STDOUT
151: begin
152: Dir.chdir Merb::Config[:merb_root]
153: rescue Errno::EACCES => e
154: Merb.fatal! "You specified Merb root as #{Merb::Config[:merb_root]}, " \
155: "yet the current user does not have access to it. ", e
156: end
157: at_exit { remove_pid_file(port) }
158: Merb::Config[:port] = port
159: bootup
160: end
161: rescue NotImplementedError => e
162: Merb.fatal! "Daemonized mode is not supported on your platform. ", e
163: end
| port<~to_s>: | The port of the Merb process to kill. |
| sig<~to_s>: | The signal to send to the process, the default is 9 - SIGKILL. |
No Name Default Action Description 1 SIGHUP terminate process terminal line hangup 2 SIGINT terminate process interrupt program 3 SIGQUIT create core image quit program 4 SIGILL create core image illegal instruction 9 SIGKILL terminate process kill program 15 SIGTERM terminate process software termination signal 30 SIGUSR1 terminate process User defined signal 1 31 SIGUSR2 terminate process User defined signal 2
If you pass "all" as the port, the signal will be sent to all Merb processes.
:api: private
# File merb-core/lib/merb-core/server.rb, line 88
88: def kill(port, sig = "INT")
89: if sig.is_a?(Integer)
90: sig = Signal.list.invert[sig]
91: end
92:
93: Merb::BootLoader::BuildFramework.run
94:
95: # If we kill the master, then the workers should be reaped also.
96: if %w(main master all).include?(port)
97: # If a graceful exit is requested then send INT to the master process.
98: #
99: # Otherwise read pids from pid files and try to kill each process in turn.
100: kill_pid(sig, pid_file("main")) if sig == "INT"
101: else
102: kill_pid(sig, pid_file(port))
103: end
104: end
Sends the provided signal to the process pointed at by the provided pid file. :api: private
# File merb-core/lib/merb-core/server.rb, line 108
108: def kill_pid(sig, file)
109: begin
110: pid = pid_in_file(file)
111: Merb.logger.fatal! "Killing pid #{pid} with #{sig}"
112: Process.kill(sig, pid)
113: FileUtils.rm(file) if File.exist?(file)
114: rescue Errno::EINVAL
115: Merb.logger.fatal! "Failed to kill PID #{pid} with #{sig}: '#{sig}' is an invalid " \
116: "or unsupported signal number."
117: rescue Errno::EPERM
118: Merb.logger.fatal! "Failed to kill PID #{pid} with #{sig}: Insufficient permissions."
119: rescue Errno::ESRCH
120: FileUtils.rm file
121: Merb.logger.fatal! "Failed to kill PID #{pid} with #{sig}: Process is " \
122: "deceased or zombie."
123: rescue Errno::EACCES => e
124: Merb.logger.fatal! e.message
125: rescue Errno::ENOENT => e
126: # This should not cause abnormal exit, which is why
127: # we do not use Merb.fatal but instead just log with max level.
128: Merb.logger.fatal! "Could not find a PID file at #{file}. " \
129: "Most likely the process is no longer running and the pid file was not cleaned up."
130: rescue Exception => e
131: if !e.is_a?(SystemExit)
132: Merb.logger.fatal! "Failed to kill PID #{pid.inspect} with #{sig.inspect}: #{e.message}"
133: end
134: end
135: end
Gets the pid file for the specified port/socket.
| port<~to_s>: | The port/socket of the Merb process to whom the the PID file belongs to. |
| String: | Location of pid file for specified port. If clustered and pid_file option is specified, it adds the port/socket value to the path. |
:api: private
# File merb-core/lib/merb-core/server.rb, line 290
290: def pid_file(port)
291: pidfile = Merb::Config[:pid_file] || (Merb.log_path / "merb.%s.pid")
292: pidfile % port
293: end
Get a list of the pid files.
| Array: | List of pid file paths. If not running clustered, the array contains a single path. |
:api: private
# File merb-core/lib/merb-core/server.rb, line 302
302: def pid_files
303: if Merb::Config[:pid_file]
304: if Merb::Config[:cluster]
305: Dir[Merb::Config[:pid_file] % "*"]
306: else
307: [ Merb::Config[:pid_file] ]
308: end
309: else
310: Dir[Merb.log_path / "merb.*.pid"]
311: end
312: end
:api: private
# File merb-core/lib/merb-core/server.rb, line 66
66: def pid_in_file(pidfile)
67: File.read(pidfile).chomp.to_i
68: end
Delete the pidfile for the specified port/socket.
:api: private
# File merb-core/lib/merb-core/server.rb, line 245
245: def remove_pid(port)
246: FileUtils.rm(pid_file(port)) if File.file?(pid_file(port))
247: end
Removes a PID file used by the server from the filesystem. This uses :pid_file options from configuration when provided or merb.<port/socket>.pid in log directory by default.
| port<~to_s>: | The port of the Merb process to whom the the PID file belongs to. |
If Merb::Config[:pid_file] has been specified, that will be used instead of the port/socket based PID file.
:api: private
# File merb-core/lib/merb-core/server.rb, line 217
217: def remove_pid_file(port)
218: pidfile = pid_file(port)
219: if File.exist?(pidfile)
220: Merb.logger.warn! "Removing pid file #{pidfile} (port/socket: #{port})..."
221: FileUtils.rm(pidfile)
222: end
223: end
Shut down Merb, reap any workers if necessary.
:api: private
# File merb-core/lib/merb-core/server.rb, line 180
180: def shutdown(status = 0)
181: # reap_workers does exit but may not be called...
182: Merb::BootLoader::LoadClasses.reap_workers(status) if Merb::Config[:fork_for_class_load]
183: # which is why we exit explicitly here
184: exit(status)
185: end
Start a Merb server, in either foreground, daemonized or cluster mode.
| port<~to_i>: | The port to which the first server instance should bind to. Subsequent server instances bind to the immediately following ports. |
| cluster<~to_i>: | Number of servers to run in a cluster. |
If cluster is left out, then one process will be started. This process will be daemonized if Merb::Config[:daemonize] is true.
:api: private
# File merb-core/lib/merb-core/server.rb, line 23
23: def start(port, cluster=nil)
24:
25: @port = port
26: @cluster = cluster
27:
28: if Merb::Config[:daemonize]
29: pidfile = pid_file(port)
30: pid = File.read(pidfile).chomp.to_i if File.exist?(pidfile)
31:
32: unless alive?(@port)
33: remove_pid_file(@port)
34: Merb.logger.warn! "Daemonizing..." if Merb::Config[:verbose]
35: daemonize(@port)
36: else
37: Merb.fatal! "Merb is already running on port #{port}.\n" \
38: "\e[0m \e[1;31;47mpid file: \e[34;47m#{pidfile}" \
39: "\e[1;31;47m, process id is \e[34;47m#{pid}."
40: end
41: else
42: bootup
43: end
44: end
Stores a PID file on the filesystem. This uses :pid_file options from configuration when provided or merb.<port/socket>.pid in log directory by default.
| port<~to_s>: | The port of the Merb process to whom the the PID file belongs to. |
If Merb::Config[:pid_file] has been specified, that will be used instead of the port/socket based PID file.
:api: private
# File merb-core/lib/merb-core/server.rb, line 262
262: def store_details(port = nil)
263: file = pid_file(port)
264: begin
265: FileUtils.mkdir_p(File.dirname(file))
266: rescue Errno::EACCES => e
267: Merb.fatal! "Failed to store Merb logs in #{File.dirname(file)}, " \
268: "permission denied. ", e
269: end
270: Merb.logger.warn! "Storing pid #{Process.pid} file to #{file}..." if Merb::Config[:verbose]
271: begin
272: File.open(file, 'w'){ |f| f.write(Process.pid.to_s) }
273: rescue Errno::EACCES => e
274: Merb.fatal! "Failed to access #{file}, permission denied.", e
275: end
276: end
Stores a PID file on the filesystem. This uses :pid_file options from configuration when provided or merb.<port>.pid in log directory by default.
| port<~to_s>: | The port of the Merb process to whom the the PID file belongs to. |
If Merb::Config[:pid_file] has been specified, that will be used instead of the port/socket based PID file.
:api: private
# File merb-core/lib/merb-core/server.rb, line 238
238: def store_pid(port)
239: store_details(port)
240: end