module PhusionPassenger::Utils
def self.included(klass)
def self.included(klass) # When included into another class, make sure that Utils # methods are made private. public_instance_methods(false).each do |method_name| klass.send(:private, method_name) end end
def self.mktmpdir(prefix_suffix=nil, tmpdir=nil)
def self.mktmpdir(prefix_suffix=nil, tmpdir=nil) case prefix_suffix when nil prefix = "d" suffix = "" when String prefix = prefix_suffix suffix = "" when Array prefix = prefix_suffix[0] suffix = prefix_suffix[1] else raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}" end tmpdir ||= Dir.tmpdir begin path = "#{tmpdir}/#{prefix}#{rand(0x100000000).to_s(36)}" path << suffix Dir.mkdir(path, 0700) rescue Errno::EEXIST retry end if block_given? begin yield path ensure FileUtils.remove_entry_secure path end else path end end
def self.new(filenames, termination_pipe = nil)
def self.new(filenames, termination_pipe = nil) # Default parameter values, type conversion and exception # handling in C is too much of a pain. filenames = filenames.map do |filename| filename.to_s end return _new(filenames, termination_pipe) end
def self.opens_files?
def self.opens_files? return true end
def self.passenger_tmpdir(create = true)
temporary files. If +create+ is true, then this method creates the
Returns the directory in which to store Phusion Passenger-specific
def self.passenger_tmpdir(create = true) dir = @@passenger_tmpdir if dir.nil? || dir.empty? tmpdir = "/tmp" ["PASSENGER_TEMP_DIR", "PASSENGER_TMPDIR"].each do |name| if ENV.has_key?(name) && !ENV[name].empty? tmpdir = ENV[name] break end end dir = "#{tmpdir}/passenger.1.0.#{Process.pid}" dir.gsub!(%r{//+}, '/') @@passenger_tmpdir = dir end if create && !File.exist?(dir) # This is a very minimal implementation of the subdirectory # creation logic in ServerInstanceDir.h. This implementation # is only meant to make the unit tests pass. For production # systems one should pre-create the temp directory with # ServerInstanceDir.h. system("mkdir", "-p", "-m", "u=rwxs,g=rwx,o=rwx", dir) system("mkdir", "-p", "-m", "u=rwxs,g=rwx,o=rwx", "#{dir}/generation-0") system("mkdir", "-p", "-m", "u=rwxs,g=rwx,o=rwx", "#{dir}/backends") system("mkdir", "-p", "-m", "u=rwxs,g=rwx,o=rwx", "#{dir}/spawn-server") end return dir end
def self.passenger_tmpdir=(dir)
def self.passenger_tmpdir=(dir) @@passenger_tmpdir = dir end
def connect_to_server(address)
def connect_to_server(address) case get_socket_address_type(address) when :unix return UNIXSocket.new(address.sub(/^unix:/, '')) when :tcp host, port = address.sub(%r{^tcp://}, '').split(':', 2) port = port.to_i return TCPSocket.new(host, port) else raise ArgumentError, "Unknown socket address type for '#{address}'." end end
def generate_random_id(method)
Generate a long, cryptographically secure random ID string, which
def generate_random_id(method) data = File.open("/dev/urandom", "rb") do |f| f.read(64) end case method when :base64 data = [data].pack('m') data.gsub!("\n", '') data.gsub!("+", '') data.gsub!("/", '') data.gsub!(/==$/, '') return data when :hex return data.unpack('H*')[0] else raise ArgumentError, "Invalid method #{method.inspect}" end end
def get_socket_address_type(address)
def get_socket_address_type(address) if address =~ %r{^unix:.} return :unix elsif address =~ %r{^tcp://.} return :tcp else return :unknown end end
def global_backtrace_report
Returns a string which reports the backtraces for all threads,
def global_backtrace_report if Kernel.respond_to?(:caller_for_all_threads) all_thread_stacks = caller_for_all_threads elsif Thread.respond_to?(:list) && Thread.public_method_defined?(:backtrace) all_thread_stacks = {} Thread.list.each do |thread| all_thread_stacks[thread] = thread.backtrace end end output = "========== Process #{Process.pid}: backtrace dump ==========\n" if all_thread_stacks all_thread_stacks.each_pair do |thread, stack| if thread_name = thread[:name] thread_name = "(#{thread_name})" end output << ("-" * 60) << "\n" output << "# Thread: #{thread.inspect}#{thread_name}, " if thread == Thread.main output << "[main thread], " end if thread == Thread.current output << "[current thread], " end output << "alive = #{thread.alive?}\n" output << ("-" * 60) << "\n" output << " " << stack.join("\n ") output << "\n\n" end else output << ("-" * 60) << "\n" output << "# Current thread: #{Thread.current.inspect}\n" output << ("-" * 60) << "\n" output << " " << caller.join("\n ") end return output end
def install_options_as_ivars(object, options, *keys)
def install_options_as_ivars(object, options, *keys) keys.each do |key| object.instance_variable_set("@#{key}", options[key]) end end
def local_socket_address?(address)
def local_socket_address?(address) case get_socket_address_type(address) when :unix return true when :tcp host, port = address.sub(%r{^tcp://}, '').split(':', 2) return host == "127.0.0.1" || host == "::1" || host == "localhost" else raise ArgumentError, "Unknown socket address type for '#{address}'." end end
def passenger_tmpdir(create = true)
def passenger_tmpdir(create = true) PhusionPassenger::Utils.passenger_tmpdir(create) end
def print_exception(current_location, exception, destination = nil)
+current_location+ is a string which describes where the code is
Print the given exception, including the stack trace, to STDERR.
def print_exception(current_location, exception, destination = nil) if !exception.is_a?(SystemExit) data = exception.backtrace_string(current_location) if defined?(DebugLogging) && self.is_a?(DebugLogging) error(data) else destination ||= STDERR destination.puts(data) destination.flush if destination.respond_to?(:flush) end end end
def process_is_alive?(pid)
def process_is_alive?(pid) begin Process.kill(0, pid) return true rescue Errno::ESRCH return false rescue SystemCallError => e return true end end
def require_option(hash, key)
def require_option(hash, key) if hash.has_key?(key) return hash[key] else raise ArgumentError, "Option #{key.inspect} required" end end
def split_by_null_into_hash(data)
Split the given string into an hash. Keys and values are obtained by splitting the
def split_by_null_into_hash(data) return PhusionPassenger::NativeSupport.split_by_null_into_hash(data) end
def split_by_null_into_hash(data)
def split_by_null_into_hash(data) args = data.split(NULL, -1) args.pop return Hash[*args] end