# Phusion Passenger - https://www.phusionpassenger.com/ # Copyright (c) 2013-2015 Phusion # # "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. PhusionPassenger.require_passenger_lib 'constants' PhusionPassenger.require_passenger_lib 'platform_info' PhusionPassenger.require_passenger_lib 'platform_info/ruby' PhusionPassenger.require_passenger_lib 'platform_info/apache' PhusionPassenger.require_passenger_lib 'utils/ansi_colors' require 'pathname' module PhusionPassenger module PlatformInfo # Detects all possible Apache installations on the system, and presents the # autodetection information to the user in a friendly way. It turns out too # many people have multiple Apache installations on their system, but they # don't know about that, or they don't know how to compile against the # correct Apache installation. This tool helps them. # # If you use this class to log things to the terminal, then be sure to set # the terminal color to Utils::AnsiColors::DEFAULT_TERMINAL_COLOR. class ApacheDetector class Result # These are required and are never nil. attr_accessor :apxs2, :httpd, :ctl, :version # These are optional and may be nil. attr_accessor :a2enmod, :a2dismod # Ttis may be nil. It depends on whether 'apache2ctl -V' succeeds. attr_accessor :config_file # This may be nil. It depends on how well we can infer information from the config file. attr_accessor :error_log attr_writer :config_file_broken def initialize(detector) @detector = detector end def config_file_broken? @config_file_broken end def report log " * Found Apache #{version}!" log " Information:" log " apxs2 : #{apxs2}" log " Main executable: #{httpd}" log " Control command: #{ctl}" log " Config file : #{config_file || 'unknown'}" log " Error log file : #{error_log || 'unknown'}" if config_file_broken? log "" log " WARNING:" log " The configuration file seems to be broken! Please double-check it by running:" log " #{ctl} -t" end log "" log " To install #{PROGRAM_NAME} against this specific Apache version:" log " #{PlatformInfo.ruby_command} #{PhusionPassenger.bin_dir}/passenger-install-apache2-module --apxs2-path='#{apxs2}'" log "" log " To start, stop or restart this specific Apache version:" log " #{ctl} start" log " #{ctl} stop" log " #{ctl} restart" log "" if error_log log " To troubleshoot, please read the logs in this file:" log " #{error_log}" log "" end end private def log(message) @detector.send(:log, message) end end attr_reader :results def initialize(output) @output = output @results = [] @failures = 0 PlatformInfo.verbose = true PlatformInfo.log_implementation = lambda do |message| if message =~ /: found$/ log(" --> #{message}") else log(" --> #{message}") end end end def finish PlatformInfo.verbose = false PlatformInfo.log_implementation = nil end def detect_all log "Looking for possible Apache installations..." apxses = PlatformInfo.find_all_commands("apxs2") + PlatformInfo.find_all_commands("apxs") if !apxses.include?(PlatformInfo.apxs2) PlatformInfo.send(:log, "Looking for #{PlatformInfo.apxs2}: found") apxses << PlatformInfo.apxs2 end apxses = remove_symlink_duplications(apxses) log "" apxses.each do |apxs2| detect_one(apxs2) end end def detect_one(apxs2) log "Analyzing #{apxs2}..." add_result do |result| result.apxs2 = apxs2 log "Detecting main Apache executable..." result.httpd = PlatformInfo.httpd(:apxs2 => apxs2) if result.httpd log "Detecting version..." if result.version = PlatformInfo.httpd_version(:httpd => result.httpd) log " --> #{result.version}" else log " --> Cannot detect version!" result.httpd = nil end end if result.httpd log "Detecting control command..." result.ctl = PlatformInfo.apache2ctl(:apxs2 => apxs2) result.httpd = nil if !result.ctl end if result.httpd log "Detecting configuration file location..." result.config_file = PlatformInfo.httpd_default_config_file(:httpd => result.httpd) if result.config_file log " --> #{result.config_file}" else log " --> Cannot detect default config file location!" end end if result.httpd log "Detecting error log file..." result.error_log = PlatformInfo.httpd_actual_error_log(:httpd => result.httpd) if result.error_log log " --> #{result.error_log}" else log " --> Cannot detect error log file!" end end if result.httpd log "Detecting a2enmod and a2dismod..." result.a2enmod = PlatformInfo.a2enmod(:apxs2 => apxs2) result.a2dismod = PlatformInfo.a2dismod(:apxs2 => apxs2) end if result.httpd result.config_file_broken = PlatformInfo.apache2ctl_V(:apxs2 => apxs2).nil? end if result.httpd log "Found a usable Apache installation using #{apxs2}." true else log "Cannot find a usable Apache installation using #{apxs2}." false end end log "" end def report if @failures > 0 && Process.uid != 0 user = `whoami`.strip sudo_s_e = PhusionPassenger::PlatformInfo.ruby_sudo_shell_command("-E") ruby = PhusionPassenger::PlatformInfo.ruby_command log "" log "----------------------------" log "" log "Permission problems" log "" log "Sorry, this program doesn't have enough permissions to autodetect all your" log "Apache installations, because it's running as the #{`whoami`.strip} user." log "Please re-run this program with root privileges:" log "" log " export ORIG_PATH=\"$PATH\"" log " #{sudo_s_e}" log " export PATH=\"$ORIG_PATH\"" log " #{ruby} #{PhusionPassenger.bin_dir}/passenger-config --detect-apache2" return end log "Final autodetection results" @results.each do |result| result.report end if @results.empty? PhusionPassenger.require_passenger_lib 'platform_info/depcheck' PlatformInfo::Depcheck.load("depcheck_specs/apache2") apache2 = PlatformInfo::Depcheck.find("apache2") apache2_install_instructions = apache2.install_instructions.split("\n").join("\n ") # apxs2 is part of the development headers. apache2_dev = PlatformInfo::Depcheck.find("apache2-dev") apache2_dev_install_instructions = apache2_dev.install_instructions.split("\n").join("\n ") log "Sorry, this program cannot find an Apache installation." log "" log "Please install Apache and its development headers." log "" log " * To install Apache:" log " #{apache2_install_instructions}" log "" log " * To install Apache development headers:" log " #{apache2_dev_install_instructions}" log "" log "If you are sure that you have Apache installed, please read the documentation:" log "https://www.phusionpassenger.com/library/install/apache/customizing_compilation_process.html#forcing-location-of-command-line-tools-and-dependencies" elsif @results.size > 1 log "WARNING: You have multiple Apache installations on your system!" log "You are strongly recommended to read this section of the documentation:" log "https://www.phusionpassenger.com/install/apache/multiple_apache_installs.html" end end def result_for(apxs2) # All the results use realpaths, so the input must too. apxs2 = try_realpath(apxs2) return @results.find { |r| r.apxs2 == apxs2 } end private def log(message) if @output.tty? @output.puts(Utils::AnsiColors.ansi_colorize(message)) else @output.puts(Utils::AnsiColors.strip_color_tags(message)) end end # On Ubuntu, /usr/bin/apxs2 is a symlink to /usr/bin/apxs. # On recent Arch Linux releases, /bin, /sbin etc are symlinks to # /usr/bin and /usr/sbin. # We're only supposed to detect one Apache in that case so we need to # resolve symlinks. def remove_symlink_duplications(filenames) old_size = filenames.size filenames = filenames.map do |filename| try_realpath(filename) end filenames.uniq! if old_size != filenames.size log "#{old_size - filenames.size} symlink duplicate(s) detected; ignoring them." end return filenames end def add_result result = Result.new(self) if yield(result) @results << result else @failures += 1 end end def try_realpath(path) if path begin Pathname.new(path).realpath.to_s rescue Errno::ENOENT, Errno::EACCES path end else nil end end end end end # module Phusion Passenger