File: //proc/3/root/proc/self/root/proc/2/root/installd/install
#!/usr/bin/perl
# installd - install Copyright(c) 2011 cPanel, Inc.
# All rights Reserved.
# copyright@cpanel.net http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited
# Helper routines for the log.
our $message_caller_depth = 1;
sub DEBUG($) { _MSG( 'DEBUG', " " . shift ) } # space pad debug messages.
sub ERROR($) { _MSG( 'ERROR', shift ) }
sub WARN($) { _MSG( 'WARN', shift ) }
sub INFO($) { _MSG( 'INFO', shift ) }
sub FATAL($) { _MSG( 'FATAL', shift ); exit 1; }
use strict;
use warnings;
use POSIX;
use Sys::Hostname ();
use IO::Handle ();
use IO::Select ();
use IPC::Open3 ();
use Cwd ();
$ENV{'CPANEL_BASE_INSTALL'} = 1;
$ENV{'LANG'} = 'C';
my $yumcheck = 0;
my $lock_file = '/root/installer.lock';
$| = 1;
umask 022;
if ( open my $fh, '<', $lock_file ) {
print "Detected an installer lock file ($lock_file).\n";
print "Please be sure that an installer is not already running.\n\n";
print "You can remove this file and re-run the cpanel install once you're certain another installation isn't in progress\n\n";
my $pid = <$fh>;
chomp $pid;
print `ps -auxwww |grep $pid`;
exit 1;
}
else {
# Create the lock file.
touch( $lock_file, $$ );
}
# Cleanup the lock file on exit.
END {
if ( open my $fh, '<', $lock_file ) {
my $pid = <$fh>;
chomp $pid;
close $fh;
if ( $pid == $$ ) {
print "Removing $lock_file\n";
unlink $lock_file;
}
}
}
# Open the install logs for append.
my $installstart = open_logs();
# Determine local distro and version. Fail if unsupported.
my ( $distro, $distro_version ) = check_system_support();
# Validate hostname is FQDN.
check_hostname();
# Which wget?
my ( $wget_bin, $wget_args ) = get_download_tool_binary( $distro, $distro_version );
# Assure minimum setup.
bootstrap( $distro, $distro_version );
# Setup cpanel.config. This has to be done early for blocker checking.
setup_cpanel_config();
# Look for conditions that require tier manipulation or require us to block the install.
check_for_install_version_blockers( $distro, $distro_version );
DEBUG "Parsing command line arguments";
get_install_type(@ARGV); # Set DNSONLY if need be.
my $skip_apache = ( grep( /^--skipapache/, @ARGV ) or -e '/root/skipapache' ) ? 1 : 0;
# Bootstrap checks.
INFO "Running health checks prior to start";
check_resolv_conf();
if ( $distro !~ m/bsd/i ) {
check_update_system();
}
check_if_we_can_get_to_httpupdate();
my $installer_dir = Cwd::getcwd();
# Make sure the OS is relativley clean.
clean_install_check();
# TODO: Get rid of these files and replace them with /var/cpanel/dnsonly
# Disable services by touching files.
touch('/etc/entropychatdisable');
if ( is_dnsonly() ) {
my @dnsonlydisable = qw( cppop cpdavd melange interchange );
foreach my $dis_service (@dnsonlydisable) {
ssystem( 'touch', '/etc/' . $dis_service . 'disable' );
}
}
# Set selinux to permissive mode for installation.
if ( -e '/usr/sbin/setenforce' ) {
ssystem( '/usr/sbin/setenforce', '0' );
}
# Install cpanel files and directories
install_cpanel_files();
# Stop and possibly remove some services
disable_and_remove_init_services();
# Init the package management system, update installed, then run sysup
ensure_rpms_installed( $distro, $distro_version );
# Remove rpms and stop unneeded services
disable_software($distro);
# Now software is installed, call rdate in case it couldn't be called earlier.
update_system_clock();
# Setup default cPanel users;
setup_cpanel_system_users();
# Re-compile and install perl if /usr/bin/perl is not > 5.8.8 at this point
ensure_perl_588($distro);
# Update/Install CPAN modules required by cPanel.
check_perl_modules();
# Update license information ASAP so code can get at it.
INFO "Updating license information";
ssystem(qw{/usr/local/cpanel/cpkeyclt});
# Upgrade to cloud linux if licensed via cpanel. Change distro if it updates.
( $distro, $distro_version ) = upgrade_to_cloud_linux( $distro, $distro_version );
################################################################
#
# At this point, cpanel code and perl are stable #
#
################################################################
if ( -e '/usr/sbin/pwconv' ) {
INFO "making sure we are shadowed";
ssystem('/usr/sbin/pwconv');
}
INFO "Making sure cPanel processes are not running";
foreach my $app (qw(cpsrvd cpdavd cphulkd)) {
ssystem( '/usr/local/cpanel/etc/init/stop' . $app );
}
INFO("Setting up sysinfo.conf");
ssystem('/usr/local/cpanel/scripts/gensysinfo');
INFO("Setting up locale databases");
ssystem('/usr/local/cpanel/bin/build_locale_databases');
INFO("Making sure the firewall (if present) is setup for cPanel.");
ssystem('/usr/local/cpanel/scripts/configure_rh_firewall_for_cpanel');
INFO("Setting up secure /tmp if possible");
install_secure_tmp();
INFO("Making sure the 3rd party services setup in cpanel.conf are properly enabled");
setup_third_party_services();
INFO("Attending to Easy apache");
install_apache();
setup_misc_cpanel_config_files($distro);
# TODO: Move into rpm update sub and hunt down FB case about yum upgrade breaking the service.
os_service_start('syslog');
INFO("Setting the PHP binary used by /usr/local/cpanel/cpanel to the php shipped with cPanel & WHM");
touch('/var/cpanel/usecpphp');
INFO "Base Install Complete";
INFO "Starting final installation phase";
# Run upcp for the first time.
INFO " ";
INFO " ";
INFO "Running upcp for the first time.";
INFO " ";
INFO " ";
ssystem(qw{/usr/local/cpanel/scripts/upcp --force});
# Enable services for startup.
# TODO: Add chkconfig to RPM spec entries and remove this code.
if ( $distro !~ m/bsd/i ) {
my @services = qw/cpanel mysql sshd/;
INFO 'Adding services to chkconfig.';
foreach my $service (@services) {
INFO " - Enabling $service";
ssystem( '/sbin/chkconfig', '--level', '35', $service, 'on' );
}
}
schdir($installer_dir);
# Restore any staged cpanel accounts
cpanel_account_restore();
# enable cphulkd by default
enable_cphulkd();
my $finishtime = time();
my $installtime = $finishtime - $installstart;
my $installfinishtime = localtime($finishtime);
INFO sprintf( "cPanel install finished in %d minutes and %d seconds!", int( $installtime / 60 ), $installtime % 60 );
# Check if the kernel set for boot matches what's currently running (uname -r)
notify_if_boot_kernel_changed($distro);
close LOG;
# TODO: MARKER FOR END OF PROGRAM EXIT HERE
exit;
sub yum_nohang_ssystem {
if ( !-e '/var/cpanel/useyum' ) {
goto &ssystem;
}
my @cmd = @_;
$yumcheck = 1;
my $failcount = 0;
my $result = 1;
while ($result) { # While yum is failing.
$result = ssystem(@cmd);
last if ( !$result ); # yum came back clean. Stop re-trying
$failcount++;
if ( $failcount > 5 ) {
FATAL "yum failed $failcount times. Cannot continue!";
}
}
$yumcheck = 0;
}
sub ssystem {
my @cmd = @_;
my $conf_hr = ref( $cmd[-1] ) eq 'HASH' ? pop(@cmd) : {};
local $message_caller_depth = $message_caller_depth + 1; # Set caller depth deeper during this sub so debugging it clearer.
DEBUG '- ssystem [BEGIN]: ' . join( ' ', @cmd );
open( RNULL, '<', '/dev/null' );
my $io = new IO::Handle;
my $pid = IPC::Open3::open3( "<&RNULL", $io, $io, @cmd );
$io->blocking(0);
my $select = IO::Select->new($io);
my $exit_status;
my $buffer = '';
my $buffered_waiting_count = 0;
while ( !defined $exit_status ) {
while ( my $line = readline($io) ) {
# Push the buffer lacking a newline onto the front of this.
if ($buffer) {
$line = $buffer . $line;
$buffer = '';
}
$line =~ s/\r//msg; # Strip ^M from output for better log output.
if ( $yumcheck && $line =~ /yum might be hung/ ) {
kill 15, $pid;
sleep 2;
WARN "....yum is hung, trying to restart it....";
ssystem(qw/killall -TERM yum/);
sleep(20);
ssystem(qw/killall -TERM yum/);
}
# Internally buffer on newlines.
if ( $line =~ m/\n$/ms ) {
DEBUG( " " . $line );
$buffered_waiting_count = 0;
}
else {
print "." if ( $buffered_waiting_count++ > 1 );
$buffer = $line;
}
}
# Parse exit status or yield time to the CPU.
if ( waitpid( $pid, 1 ) == $pid ) {
$exit_status = $? >> 8;
}
else {
# Watch the file handle for output.
$select->can_read(0.1);
}
}
ERROR " - ssystem [EXIT_CODE] '$cmd[0]' exited with $exit_status (ignored)" if ($exit_status);
close(RNULL);
$io->close();
DEBUG '- ssystem [END]';
return $exit_status;
}
sub schdir {
my $dir = shift;
my $cwd = Cwd::getcwd();
chdir($dir) || die "Cannot chdir to ${dir}, cwd was: $cwd";
}
# TODO: This sub is no longer used. We believe it was an issue
# pre- Centos 4 and so no longer an issue for the installer
sub check_for_rpm_race_condition {
DEBUG 'Verifying we do not have a RPM race condition';
if ( -e '/var/lib/rpm/__db.001' ) {
my $runrpm = 0;
my $isfping = `ps uxawwwwwww`;
my @ISFPING = split( /\n/, $isfping );
foreach (@ISFPING) {
if (/rpm/) {
$runrpm = 1;
}
}
if ( !$runrpm ) {
WARN "detected running rpm process";
ssystem('rm -f /var/lib/rpm/__db.*');
}
}
}
sub is_dnsonly {
return -e '/var/cpanel/dnsonly' ? 1 : 0;
}
sub get_install_type {
my @args = @_;
# TYPE could be DNSONLY
my $type = 'standard';
if (@args) {
foreach my $val (@args) {
next if $val =~ m/^--/;
$type = $val;
last;
}
}
if ( $type =~ m/dnsonly/i ) {
INFO "DNSONLY install requested";
touch('/var/cpanel/dnsonly');
}
INFO "Install type: $type\n";
}
sub touch {
my $file = shift;
open( my $fh, ">>", $file ) or return;
foreach my $line (@_) { # concat anything found.
print {$fh} $line;
}
close $fh;
}
sub check_system_support {
my $system = ( POSIX::uname() )[0];
if ( $system =~ m/freebsd/i ) {
my $machine = ( POSIX::uname() )[3];
my ($version) = $machine =~ m/freebsd\s+(\d+\.\d+)/i or invalid_system("Cannot determine the distro number for FreeBSD");
invalid_system() if ( $version < 7.29999 ); # Safety for floating point check.
INFO "FreeBSD version $version detected!";
return ( $system, $version );
}
elsif ( $system =~ m/linux/i ) {
# /etc/redhat-release must be present.
my $rhel_release = '/etc/redhat-release';
( -e $rhel_release ) or invalid_system("I could not detect '$rhel_release'.");
# rpm must manage it.
my $release_rpm = `rpm -qf $rhel_release`;
chomp $release_rpm;
$release_rpm or invalid_system("'$rhel_release' is not managed by RPM.");
# an rpm we recognize must manage it.
my ( $distro, $distro_version ) = $release_rpm =~ m{^(\D+)-(\d+).*$}ms;
$distro_version = $distro_version + 0;
$distro_version or invalid_system("Unexpected RPM '$release_rpm' found managing the file $rhel_release.");
# That RPM must have redhat or centos in the name.
$distro =~ m/centos|redhat|enterprise-release|cloud/i or invalid_system("Unexpected rpm '$distro' found managing the file '$rhel_release'");
$distro =~ s/-release//imsg;
if ( $distro eq 'enterprise' ) {
$distro = 'redhat';
}
INFO "$distro $distro_version (Linux) detected!";
# The version number must be 4-6
( $distro_version <= 6 && $distro_version >= 4 ) or invalid_system("$distro version $distro_version is unsupported by cPanel for new installs.");
# Supported distros for installer: redhat/red hat enterprise/cloud/centos
$distro = ( $distro =~ m/redhat|hat enterprise/i ) ? 'redhat' : ( $distro =~ m/cloud/i ) ? 'cloud' : 'centos';
return ( $distro, $distro_version );
}
invalid_system("Unknown or unsupport operating system. ($system)");
exit(2);
}
sub invalid_system {
my $message = shift || '';
chomp $message;
ERROR "$message";
ERROR "Unsupported distro detected. cPanel only supports CentOS or RedHat Enterprise 4-6 and upstream supported Free BSD systems >= 7.3";
FATAL "Please re-install cPanel from a valid distro";
}
sub check_hostname {
my $hostname = Sys::Hostname::hostname();
if ( $hostname !~ m/\./ ) {
$hostname = `hostname -f`;
chomp $hostname;
}
INFO "Validating that '$hostname' is a FQDN";
if ( $hostname =~ /^www\./ ) {
FATAL "Hostname $hostname detected. Hostnames cannot start with www! Please change it.";
}
if ( $hostname !~ /\./ ) {
ERROR "";
ERROR "********************* ERROR *********************";
ERROR "";
ERROR "Your hostname ($hostname) is not set properly. Please";
ERROR "change your hostname to a fully qualified domain name,";
ERROR "and re-run this installer.";
ERROR "";
ERROR "********************* ERROR *********************";
FATAL "exiting...";
}
}
sub clean_install_check {
INFO "cPanel Layer 1 Installer Starting.....";
INFO "Warning !!! Warning !!! WARNING !!! Warning !!! Warning";
INFO "-------------------------------------------------------";
INFO "cPanel requires a fresh/clean server!";
INFO "If you are serving websites off this server (and are";
INFO "not already running cPanel) this installer will";
INFO "overwrite all of your config files. You should hit";
INFO "Ctrl+C NOW!!!";
INFO "If this is a new server please ignore this messages";
INFO "-------------------------------------------------------";
INFO "Warning !!! Warning !!! WARNING !!! Warning !!! Warning";
INFO "Waiting 5 seconds.....";
INFO "";
INFO "";
sleep(5);
# TODO: We should die if we see evidence of any control panel.
INFO 'Checking for another control panel...';
my @server_detected;
push @server_detected, 'DirectAdmin' if ( -e '/usr/local/directadmin' );
push @server_detected, 'Plesk' if ( -e '/etc/psa' );
push @server_detected, 'Ensim' if ( -e '/etc/appliance' || -d '/etc/virtualhosting' );
#push @server_detected, 'Alabanza' if ( -e '/etc/mail/mailertable' );
push @server_detected, 'Zervex' if ( -e '/var/db/dsm' );
push @server_detected, 'Web Server Director' if ( -e '/bin/rpm' && `/bin/rpm -q ServerDirector` =~ /^ServerDirector/ms );
return if ( !@server_detected );
ERROR "Evidence that the following servers have been installed on this system was detected";
ERROR $_ foreach (@server_detected);
FATAL 'cPanel needs to be installed on a clean server';
}
sub open_logs {
my $installstart = time();
my $log_file = '/var/log/cpanel-install.log';
if ( my $mtime = ( stat($log_file) )[9] ) {
my $bu_file = $log_file . '.' . $mtime;
ssystem( 'cp', $log_file, $bu_file ) unless -e $bu_file;
}
open( LOG, '>>', $log_file );
select(LOG);
$| = 1;
select(STDOUT);
my $installstarttime = localtime($installstart);
INFO "cPanel install started at: ${installstarttime}!";
INFO "This install will take 10-70 minutes depending on your hardware.";
INFO "Now is the time to go get another cup of coffee/jolt.";
INFO "The install will log to /var/log/cpanel-install.log.";
INFO "";
INFO "Beginning Installation";
return $installstart;
}
sub disable_and_remove_init_services {
INFO "Disabling unneeded services...";
ssystem('/usr/local/cpanel/scripts/disable_unused_xinetd');
my @service_shutdown = qw(named);
push @service_shutdown, qw(exim smail sendmail postfix master mysql mysqld httpd apache wu-ftpd inetd ncsd)
if ( !is_dnsonly() );
# Disable and remove the ncsd service.
if ( -e '/etc/init.d/nscd' ) {
push @service_shutdown, 'ncsd';
ssystem( '/sbin/chkconfig', '--del', 'nscd' );
}
INFO "Stopping services:";
foreach my $service (@service_shutdown) {
os_service_stop($service);
}
}
sub ensure_rpms_installed {
my ( $distro, $distro_version ) = @_;
if ( $distro =~ m/bsd/i ) {
install_bsd_software();
return;
}
# Disable rpmforge repos
if ( glob '/etc/yum.repos.d/*rpmforge*' ) {
WARN 'DISABLING rpmforge yum repos';
mkdir( '/etc/yum.repos.d.disabled', 0755 );
ssystem('mv -fv -- /etc/yum.repos.d/*rpmforge* /etc/yum.repos.d.disabled/ 2>/dev/null');
}
# Install fastest mirror plugin for CentOS
if ( $distro =~ m/centos/ ) {
my $valid = `$wget_bin $wget_args - http://www.cpanel.net/apps/proxytest/proxytest.cgi`;
if ( $valid =~ m/^0/ ) {
INFO "No proxy found, installing fastest mirror plugin.";
ssystem 'yum', 'clean', 'all';
ssystem 'yum', '-y', 'install', ( $distro_version =~ /^4/ ? 'yum-plugin-fastestmirror' : 'yum-fastestmirror' );
ssystem 'yum', 'clean', 'all';
}
else {
WARN "http proxy found. Skipping fastest mirror plugin for CentOS";
}
# Lower the number of threads for the fastestmirror plugin on CentOS 6
if ( $distro_version == 6 && open( my $fh, '<', '/etc/yum/pluginconf.d/fastestmirror.conf' ) ) {
my @conf = <$fh>;
close $fh;
if ( open( my $ofh, '>', '/etc/yum/pluginconf.d/fastestmirror.conf' ) ) {
foreach my $line (@conf) {
$line =~ s/^(\s*maxthreads\s*=\s*)\d+/${1}1/;
print {$ofh} $line;
}
}
else {
WARN("Could not update fastest mirror plugin for yum to lower it's threads");
}
}
}
# This if/else loop to make sure yum/up2date are setup. Do a little boostrapping with yum if possible.
if ( -e '/etc/yum.conf' || -e '/var/cpanel/useyum' ) { # YUM
# Minimal packages needed to use yum.
# Install perl-devel on centhat 6
if ( $distro_version == 6 ) {
INFO("Installing perl development packages so that system perl can install from CPAN");
yum_nohang_ssystem( '/usr/bin/yum', '-y', 'install', qw{ perl-devel perl-CPAN perl-Module-Build perl-core perl-libwww-perl crontabs sysstat} );
}
# Remove all excludes from /etc/yum.conf
ssystem( '/usr/local/cpanel/scripts/checkyum', '--nokernel', '--noperl' );
ssystem( 'touch', '/etc/checkyumdisable' ); # Disable checkyum
yum_nohang_ssystem( '/usr/bin/yum', '-y', 'install', 'kernel-headers' ); # Needed because Cpanel::SysPkgs excludes kernel_version
# Make sure all rpms are up to date.
yum_nohang_ssystem( '/usr/bin/yum', '-y', 'update' );
# Reinstate yum exclusions
unlink '/etc/checkyumdisable';
ssystem('/usr/local/cpanel/scripts/checkyum');
}
elsif ( -e '/var/cpanel/use2update' || -e '/usr/sbin/up2date' ) { # RHEL 4
ssystem('/usr/local/cpanel/scripts/checkup2date');
}
else {
invalid_system("Could not determine the correct rpm update system. It should be yum or up2date");
}
# Check to make sure all installed rpms are up to date
# TODO parse this output and determine if our mirror access is broken. Die on failure.
ssystem('/usr/local/cpanel/scripts/rpmup');
# Make sure all of the rpms cPanel needs are installed
ssystem('/usr/local/cpanel/scripts/sysup');
# TODO: Remove this if RHEL 4-6 don't have this version after yum -y update
# Remove fontconfig-2.2.3-7 if present. It breaks stuff when we try to build.
ssystem('/usr/local/cpanel/scripts/fontconfigfix');
if ( !-e '/usr/bin/gcc' ) {
ERROR "Could not automatically install gcc. The GNU C compiler is required for a successful cPanel installation.";
ERROR "gcc often fails to install due to missing dependencies such as a required update of the kernel-headers.";
ERROR "cPanel specifically excludes kernel updates and this may have prevented the gcc installation.";
ERROR "The installer will attempt once more to install gcc by allowing updates of the system kernel.";
FATAL "exiting..."; # Terminal Bell
}
}
sub disable_software {
my $distro = shift or die;
return if ( is_dnsonly() or $distro =~ m/bsd/i );
my @remove_rpms = qw(
mysql
MySQL
mysql-max
MySQL-Max
mysql-devel
MySQL-devel
mysql-client
MySQL-client
mysql-ndb-storage
MySQL-ndb-storage
mysql-ndb-management
MySQL-ndb-management
mysql-ndb-tools
MySQL-ndb-tools
mysql-ndb-extra
MySQL-ndb-extra
mysql-shared
MySQL-shared
mysql-libs
MySQL-libs
mysql-bench
MySQL-bench
mysql-server
MySQL-server
wu-ftpd
postfix
sendmail
smail
spamassassin
apache-conf
mod_perl
);
INFO 'Ensuring conflicting services are uninstalled.';
foreach my $rpm (@remove_rpms) {
my $installed = `rpm -q $rpm`;
next if ( $installed =~ m/is not installed/ms );
DEBUG " Removing $rpm";
ssystem( 'rpm', '-e', '--nodeps', $rpm );
}
INFO 'Ensuring conflicting service references are removed from rpm database (but leaving service installed).';
my @all_pkgs = `rpm -qa --queryformat '%{name}\n'`;
return if ($skip_apache);
# TODO: Why are we doing --justdb??? Fix this after at least 11.30
foreach my $rpm ( grep m/http|php|apache|mod_perl/, @all_pkgs ) {
chomp $rpm;
DEBUG " Removing $rpm\n";
ssystem( 'rpm', '-e', '--justdb', '--nodeps', $rpm );
}
}
sub setup_cpanel_system_users {
INFO 'Creating default cPanel users.';
my @cpanel_users = qw( cpanel );
if ( !is_dnsonly() ) {
push @cpanel_users, qw( cpanelhorde cpanelphpmyadmin cpanelphppgadmin cpanelroundcube );
}
foreach my $cpanel_user (@cpanel_users) {
next if ( getpwnam($cpanel_user) );
DEBUG " adding $cpanel_user ...";
ssystem( '/usr/local/cpanel/scripts/adduser', '--nochecks', '--noshell', $cpanel_user, '/var/cpanel/userhomes' );
}
if ( !is_dnsonly() && !getpwnam('mailman') ) { # Fix for broken mailman installer. TODO: Still needed?
DEBUG " adding mailman ...";
ssystem( '/usr/local/cpanel/scripts/adduser', '--nochecks', '--noshell', 'mailman', '/usr/local/cpanel/3rdparty/mailman' );
}
}
sub setup_misc_cpanel_config_files {
my $distro = shift or die;
INFO 'Setting up misc cPanel config files.';
# FB Case about running this out of maintenance and into the install script
DEBUG ' Running scripts/secureit';
ssystem( '/usr/local/cpanel/scripts/secureit', '--fast' );
# TODO: Should/Can we remove these installations? Open FB over it.
DEBUG ' Installing issue and bashrc';
ssystem( 'cp', '-f', $installer_dir . '/issue', '/etc' );
ssystem( 'cp', '-f', $installer_dir . '/issue.net', '/etc' );
ssystem( 'cp', '-f', $installer_dir . '/bashrc', '/etc' );
chmod( 0755, '/etc/bashrc' );
# sync time on reboot.
my $rc_local = ( $distro =~ m/bsd/i ) ? '/etc/rc.local' : '/etc/rc.d/rc.local';
DEBUG ' Configuring rdate to run on reboot';
if ( open my $rc_fh, '>>', $rc_local ) {
print {$rc_fh} "/scripts/rdate &\n";
close $rc_fh;
}
DEBUG ' Setting whemtheme to x';
open( THEME, '>', '/var/cpanel/whmtheme' );
print THEME 'x';
close(THEME);
}
sub install_apache {
return if ( is_dnsonly() );
if ($skip_apache) {
WARN "Skipping Apache installation due to command line request";
return;
}
INFO "Installing Apache...";
DEBUG "Moving /etc/httpd out of the way and pointing /etc/httpd to /usr/local/apache";
if ( -e '/etc/httpd' && !-e '/usr/local/apache' ) {
if ( !-l '/etc/httpd' && !-e '/etc/httpd.old' ) {
ssystem( 'mv', '/etc/httpd', '/etc/httpd.old' );
}
else {
unlink '/etc/httpd';
}
}
ssystem(qw{ln -sf /usr/local/apache /etc/httpd});
DEBUG "Determining if a custom profile needs to be used";
my $local_profile = '/etc/cp_easyapache_profile.yaml';
my $ea_profile = ( -s $local_profile ) ? $local_profile : 'cpanel_default';
# install EA
DEBUG "Running apache install scripts";
ssystem( '/usr/local/cpanel/scripts/cpanel_easy_sanity_check', '--quiet' );
ssystem( '/usr/local/cpanel/scripts/easyapache', "--profile=$ea_profile", '--build' );
DEBUG "Symlink etc -> conf as long as conf isn't a symlink";
if ( -d '/usr/local/apache/conf' && !-l '/usr/local/apache/conf' ) {
symlink(qw{conf /usr/local/apache/etc});
}
}
sub install_cpanel_files {
# Install cPanel files.
INFO 'Installing /usr/local/cpanel files.';
unlink 'updatenow.static';
my $update_source = get_update_source();
DEBUG "HTTPUPDATE is set to $update_source";
if ( -e '/scripts' && !-l '/scripts' ) {
if ( !-d '/scripts' ) {
WARN "/scripts detected as a file. Moving it out of the way";
ssystem( qw{/bin/mv /scripts}, "/scripts.o.$$" );
}
else {
WARN "/scripts detected. moving contents to /usr/local/cpanel/scripts";
ssystem(qw{mkdir -p /usr/local/cpanel/scripts});
ssystem('cd / && tar -cf - scripts | (cd /usr/local/cpanel && tar -xvf -)');
ssystem(qw{/bin/rm -rf /scripts});
}
}
unlink '/scripts';
symlink(qw{/usr/local/cpanel/scripts /scripts}) if ( !-e '/scripts' );
WARN("/scripts should be a symlink to /usr/local/cpanel/scripts. cPanel doesn't use /scripts any more but you might")
if ( !-l '/scripts' );
# Download the tar.gz files and extract them instead.
my $source = "http://$update_source/cpanelsync/installer/cpanel/scripts/updatenow.static.bz2";
DEBUG "Retrieving updatenow.static from $source";
cpfetch($source);
ssystem( "/usr/bin/bunzip2", "updatenow.static.bz2" );
chmod 0755, 'updatenow.static';
my $exit;
for ( 1 .. 5 ) { # Re-try updatenow if it fails.
$exit = ssystem( './updatenow.static', '--upcp', '--no-check-perl', '--force' );
last if ( $exit == 0 );
DEBUG("Detected a failed sync. Re-trying updatenow.static to correct");
}
if ($exit) {
FATAL("Unable to sync cpanel. Please verify your network connectivity to httpupdate.cpanel.net and re-run the installer");
}
}
sub ensure_perl_588 {
my $distro = shift or die;
INFO "Ensuring /usr/bin/perl is at least 5.8.8";
my $has_perlver = `/usr/bin/perl -e'print \$]'`;
chomp $has_perlver;
if ( $distro =~ m/bsd/i ) {
INFO "Perl ($has_perlver) will not be updated on BSD";
return;
}
DEBUG "/usr/bin/perl = $has_perlver";
INFO "Determining system VPS type";
my $envtype = `/usr/local/cpanel/bin/envtype` || '';
chomp $envtype;
open( my $envtype_fh, '>', '/var/cpanel/envtype' );
print $envtype_fh $envtype;
close($envtype_fh);
my $isvps = ( $envtype ne 'standard' ) ? 1 : 0;
INFO "Detected a '$envtype' VPS" if ($isvps);
# These 2 vars need to stay in sync.
my $needed_perl = '5.008008';
my $perl_installer = 'perl588installer';
# Custom compile perl if /usr/bin/perl < $needed_perl (5.8.8)
unless ( $isvps or $has_perlver < $needed_perl ) {
INFO "Perl does not need to be updated";
return;
}
INFO 'Updating Perl.';
#child
local $0 = 'cPanel install - compiling perl';
mkdir '/root/.gnupg', 0700 unless -e '/root/.gnupg';
schdir($installer_dir);
if ( -e "/root/$perl_installer.tar.gz" ) {
require File::Copy;
WARN "Using local copy of $perl_installer.tar.gz";
File::Copy::copy( "/root/$perl_installer.tar.gz", "$perl_installer.tar.gz" );
}
else {
cpfetch("$perl_installer.tar.gz");
}
if ( !-e "$perl_installer.tar.gz" ) {
ERROR "Unable to download $perl_installer.tar.gz!";
return;
}
INFO "extracting perl";
ssystem( 'tar', '-xzv', '--no-same-owner', '--no-same-permissions', '-f', "$perl_installer.tar.gz" );
INFO "Compiling perl";
schdir($perl_installer);
chmod 0644, '/usr/local/cpanel/scripts/checkperlmodules', '/usr/local/cpanel/bin/rrdtoolcheck'; # Disable rrdtool/chkperl in the perl installer
ssystem( './install', '-optimize-memory', '--nomodules' );
chmod 0755, '/usr/local/cpanel/scripts/checkperlmodules', '/usr/local/cpanel/bin/rrdtoolcheck'; # Re-enable rrdtool/chkperl
schdir($installer_dir);
INFO "Perl install complete";
return;
}
sub check_perl_modules {
# Cleanup .cpan dir
INFO 'Cleaning up CPAN cache.';
ssystem( 'rm', '-rf', '/root/.cpan' );
# Make sure cpan downloads a new list of modules
unlink('/home/.cpcpan/modulecheck');
# Assure spamd is shut down.
ssystem( 'killall', '-TERM', 'spamd' );
INFO "Bootstrapping CPAN. (CPAN, IO::Tty, Expect, YAML::Syck, Bundle::LWP)";
ssystem( '/usr/local/cpanel/scripts/perlinstaller', 'CPAN' );
ssystem( '/usr/local/cpanel/scripts/perlinstaller', 'IO::Tty', 'Expect', 'YAML::Syck', 'Bundle::LWP' );
# checkperlmodules tries to do these one at a time. This approach is a little cheaper when in installing many modules at once.
INFO "Attempting a quick install of most of the needed CPAN modules prior to calling checkperlmodules";
my @check_perl_modules = qw {
Locales version CDB_File Module::Build BSD::Resource Class::Std Digest::MD5::File Expect Encode::Guess Encode::MIME::Name Encode::Detect::Detector
Data::Dump File::Copy::Recursive File::ReadBackwards File::Find::Rule IO::Tty Sys::Hostname::Long local::lib AppConfig Template YAML::Syck JSON::Syck
cPanel::MemTest List::MoreUtils DateTime::Locale DateTime DB_File HTTP::Date Scalar::Util MIME::Base64 URI Net::FTP HTML::Tagset HTML::Parser
HTML::HeadParser LWP Bundle::LWP DBI Crypt::SSLeay CPAN::SQLite Data::Dumper Digest::MD5 Digest::SHA1 Encode
ExtUtils::Constant ExtUtils::Install ExtUtils::ParseXS File::Touch Filesys::Df Filesys::Virtual Filter::Util::Call Getopt::Long Getopt::Param::Tiny
Compress::Raw::Zlib Authen::Libwrap Net::FTPSSL Net::SSL Net::SSLeay IO::Compress::Gzip IO::Scalar IO::Socket::SSL IO::Stty IO::Uncompress::Gunzip
Lchown List::Util MD5 Net::DNS Net::OSCAR Pod::Perldoc Storable Sys::Syslog Term::ReadKey Term::ReadLine::Perl Time::HiRes Tree::MultiNode Unix::PID
Unix::PID::Tiny XML::LibXML::Common XML::LibXML XML::Parser XML::SAX XML::Simple lib::restrict Crypt::Passwd::XS Filesys::Statvfs Crypt::GPG
Class::Accessor Class::Accessor::Fast File::MMagic::XS Email::Valid ExtUtils::MakeMaker Mail::SRS Acme::Spork Archive::Tar Archive::Tar::Streamed
Archive::Zip MIME::Lite Business::OnlinePayment::AuthorizeNet Business::UPS CGI Class::Std::Utils Compress::Bzip2 Compress::Zlib DBIx::MyParsePP
DBD::SQLite2 Date::Parse File::Tail GD::Graph GD::Text::Align Memoize Geo::IPfree HTTP::Daemon::App IO::Socket::ByteCounter Image::Size
Mail::DomainKeys Error NetAddr::IP Net::DNS::Resolver::Programmable Mail::SPF Mail::SPF::Query Mail::DKIM IP::Country Graph::Easy Graph::Flowchart
Mail::SpamAssassin URI::Escape File::Find::Rule::Filesys::Virtual File::Slurp Net::DAV::Server Net::Daemon Net::Daemon::SSL Net::LDAP
Net::LDAP::Schema Net::LDAP::Server Net::IP::Match::Regexp OLE::Storage_Lite Parse::RecDescent Quota SVG::TT::Graph Safe::Hole Text::CSV
Spreadsheet::ParseExcel Spreadsheet::WriteExcel String::CRC32 SQL::Statement Set::Crontab Tie::IxHash Tie::ShadowHash Tie::DBI URI::URL
Bundle::Interchange Devel::PPPort Linux::Inotify2 };
ssystem( '/usr/local/cpanel/scripts/perlinstaller', @check_perl_modules );
# Make sure spamd is stopped during perl module installs.
INFO "Updating all cpanel required CPAN modules.";
for ( 1 .. 2 ) {
INFO("Running checkperlmodules for time $_");
ssystem( '/usr/local/cpanel/scripts/checkperlmodules', '--full', '--nowarn' );
}
# Make sure spamd is stopped during perl module installs.
INFO "Making sure any library dependencies are met for perl modules.";
ssystem('/usr/local/cpanel/install/perlmods');
INFO "Making sure rrdtool is setup correctly";
ssystem('/usr/local/cpanel/bin/rrdtoolcheck');
}
sub cpanel_account_restore {
my $acct_restore_file = '/etc/cpanelacctrestore';
return if ( !-e $acct_restore_file );
INFO "Restoring Accounts.";
sleep(2);
open( my $fh, $acct_restore_file );
while (<$fh>) {
s/\n//g;
DEBUG "Restoring $_";
ssystem( "/usr/local/cpanel/scripts/restorepkg", "$_" );
}
close($fh);
unlink($acct_restore_file);
}
sub install_secure_tmp {
return if ( is_dnsonly() );
INFO 'Securing the /tmp and /var/tmp directories.';
ssystem( '/usr/local/cpanel/scripts/securetmp', '--auto', '--install' );
# TODO: #################### Work around securetmp problem with no loopback ####################
my $failed_securetmp = 0;
if ( !-e '/tmp' ) {
mkdir '/tmp';
}
my $mode = ( stat('/tmp') )[2] & 07777;
if ( sprintf( '%o', $mode ) ne '1777' ) {
$failed_securetmp = 1;
chmod oct('1777'), '/tmp';
}
if ($failed_securetmp) {
ERROR "Unable to secure /tmp directory";
if ( open my $excl_fh, '>>', '/etc/cpanelsync.exclude' ) {
print {$excl_fh} "\n/usr/local/cpanel/scripts/securetmp\n";
close $excl_fh;
}
if ( open my $securetmp_fh, '>', '/usr/local/cpanel/scripts/securetmp' ) {
print {$securetmp_fh} "#!/bin/sh\necho \"/usr/local/cpanel/scripts/securetmp is disabled\"\necho \"It is not compatible with this system. Check the kernel for loopback support.\"\n";
close $securetmp_fh;
}
ssystem( 'mkdir', '-p', '/var/cpanel/version/' );
ssystem( 'touch', '/var/cpanel/version/securetmp_disabled' );
WARN "---- DISABLING securetmp on your system!!! ----";
}
}
sub check_resolv_conf {
use Socket;
INFO "Validating that we can lookup domains";
my @domains = qw(
cpanel.net
www.cpanel.net
updates.cpanel.net
httpupdate.cpanel.net
layer2.cpanel.net
layer1.cpanel.net
www.google.com
);
foreach my $domain (@domains) {
DEBUG "Testing $domain";
next if ( gethostbyname($domain) );
ERROR '!' x 105 . "\n";
ERROR "Cannot resolve $domain. Please check /etc/resolv.conf. Installation terminated.\n";
FATAL '!' x 105 . "\n";
}
}
sub read_config {
my $file = shift or die;
my $config = {};
open( my $fh, "<", $file ) or return $config;
while ( my $line = readline $fh ) {
chomp $line;
if ( $line =~ m/^\s*(.*?)\s*=\s*(.*?)\s*$/ ) {
my $key = $1 or next; # Skip loading the key if it's undef or 0
my $value = $2;
$config->{$key} = defined $value ? $value : '';
}
}
return $config;
}
sub save_config {
my $file = shift or die;
my $settings = shift or die;
INFO "Writing out $file";
if ( open my $fh, '>', $file ) {
foreach my $key ( sort keys %$settings ) {
my $value = $settings->{$key};
print {$fh} "$key=$value\n";
}
close $fh;
}
else {
ERROR "Unable to write to $file: $!";
}
}
sub setup_cpanel_config {
my $cp_etc_path = '/usr/local/cpanel/etc';
my $config_target = '/var/cpanel/cpanel.config';
my $config_default = $cp_etc_path . '/cpanel.config';
my $custom_config = '/root/cpanel_profile/cpanel.config';
# Setup the the etc dir for downloading the default cpanel.config
ssystem( 'mkdir', '-p', $cp_etc_path );
chmod 0755, $cp_etc_path;
# Assure /var/cpanel is there.
mkdir '/var/cpanel';
chmod 0755, '/var/cpanel';
# Download the default cpanel.config if not already present.
if ( !-e $config_default ) {
INFO("Downloading default cpanel config");
cpfetch( 'cpanelsync/installer/cpanel/etc/cpanel.config.bz2', "$config_default.bz2" );
ssystem( "/usr/bin/bunzip2", "$config_default.bz2" );
( -e $config_default ) or die("Failed to download default cpanel.config file.");
chmod 0644, $config_default;
}
# If no customization, just put the file in place and return.
if ( !-e $config_target ) {
INFO "Installing the default cPanel configuration file from $config_default";
ERROR "$config_default could not be found!" if ( !-e $config_default );
ssystem( qw{cp -fv}, $config_default, $config_target );
# No further action if the file was just put in place and no custom config is found.
return if ( !-e $custom_config );
}
# Load in whatever is in the current config file
my $current_settings = read_config($config_target);
# Merge in $custom_config, overwriting whatever is there.
if ( -e $custom_config ) {
INFO "Merging in custom settings from $custom_config";
my $custom_settings = read_config($custom_config);
foreach my $key ( sort keys %$custom_settings ) {
my $value = $custom_settings->{$key};
INFO " - Customizing $key=$value";
$current_settings->{$key} = $value;
}
}
# Pull any missing keys in the current config from $config_default
my $default_settings = read_config($config_default);
foreach my $key ( sort keys %$default_settings ) {
next if ( exists $current_settings->{$key} );
my $value = $default_settings->{$key};
INFO "Injecting missing setting '$key=$value' into $config_target";
$current_settings->{$key} = $value;
}
# Write out $config_target with our changes.
save_config( $config_target, $current_settings );
}
sub setup_third_party_services {
# Read in cpanel.config manually so we don't have to load modules.
my $config = read_config('/var/cpanel/cpanel.config');
# Setup the FTP server. Default to proftpd
{
my $target = $config->{'ftpserver'} || 'proftpd';
$target = 'disabled' if ( is_dnsonly() ); # DNSONLY installs cannot set a custom ftp server.
INFO "Setting up FTP server to '$target'";
if ( $target !~ m/^(disabled|proftpd|pure-ftpd)$/ ) {
WARN "$target is an unsupported ftpserver. Will default to 'proftpd' instead";
$target = 'proftpd';
}
ssystem( '/usr/local/cpanel/scripts/setupftpserver', '--force', $target );
}
# Setup the name server. Default to bind
{
my $target = $config->{'local_nameserver_type'} || 'bind';
INFO "Setting up name server to '$target'";
if ( $target !~ m/^(disabled|bind|nsd)$/ ) {
WARN "$target is an unsupported name server. Will default to 'bind' instead";
$target = 'bind';
}
if ( $target eq 'bind' && $distro =~ m/centos|redhat/i && $distro_version >= 6 ) {
if ( -e '/etc/named.conf' ) {
INFO "Saving /etc/named.conf, and rebuild with cPanel defaults";
if ( rename '/etc/named.conf', '/etc/named.conf.precpanelinstall' ) {
ssystem('/usr/local/cpanel/scripts/rebuilddnsconfig');
}
else {
WARN "Unable to rebuild /etc/named.conf file";
}
}
}
ssystem( '/usr/local/cpanel/scripts/setupnameserver', '--force', $target );
}
# Make sure exim is installed so setupmailserver doesn't freak out.
INFO("Setting up exim");
ssystem( '/usr/local/cpanel/scripts/eximup', '--force' );
# Setup the mail server. Default to courier
{
my $target = $config->{'mailserver'} || 'courier';
$target = 'disabled' if ( is_dnsonly() ); # DNSONLY installs cannot set a custom mail server.
INFO "Setting up mail server to '$target'";
if ( $target !~ m/^(disabled|courier|dovecot)$/ ) {
WARN "$target is an unsupported mail server. Will default to 'courier' instead";
$target = 'courier';
}
ssystem( '/usr/local/cpanel/scripts/setupmailserver', '--force', $target );
}
# Force update mysql just to be sure.
ensure_mysql_enabled();
INFO("Setting up mysql");
ssystem( '/usr/local/cpanel/scripts/mysqlup', '--force' );
}
sub ensure_mysql_enabled {
# stop gap measure until case 51994 is resolved.
# mysql cannot be bootstrapped on BSD without it first
# being enabled in /etc/rc.conf
return unless ( $distro =~ m/bsd/i );
if ( open( my $rc_conf_fh, '+<', '/etc/rc.conf' ) ) {
while ( my $line = readline($rc_conf_fh) ) {
if ( $line =~ m{^mysql_enable\s*=} ) {
close $rc_conf_fh;
return;
}
}
INFO("Enabling mysql in rc.conf");
print {$rc_conf_fh} qq{\nmysql_enable="YES"\n};
close $rc_conf_fh;
}
}
sub check_if_we_can_get_to_httpupdate {
return if ( $wget_bin !~ m/wget/ ); # Just skip this check on BSD if no wget is avail.
foreach my $src ( 'index.html', 'modules/index.html' ) {
my $page = `$wget_bin $wget_args - http://httpupdate.cpanel.net/pub/CPAN/$src`;
if ( $page =~ m/perl/i && $page =~ m/CPAN/ ) {
INFO "we can connect to httpupdate.cpanel.net";
return;
}
}
FATAL "Cannot download from httpupdate.cpanel.net at the moment.";
}
# A tiny version of Cpanel::RpmUtils::checkupdatesystem();
sub check_update_system {
my $method = '';
if ( -e '/var/cpanel/useyum' ) {
$method = 'yum';
my $out = `yum info glibc 2>&1`;
return if ( $out =~ m{ (?: Installed | Available) \s+ Packages }xmsi );
}
elsif ( -e '/var/cpanel/useup2date' ) {
$method = 'up2date';
my $out = `up2date --showall`;
return if ( $out =~ /^glibc-/mi );
}
else {
invalid_system('yum or up2date not detected.');
}
ERROR chr(27) . '[1;31m';
ERROR q{Your operating system's rpm update method } . qq{($method) was not able to locate the glibc package. } . q{This is an indication of an improper setup. } . q{You must correct this error before you can proceed. };
ERROR chr(27) . '[0;39m';
FATAL "\n\n";
exit 2;
}
sub cpfetch {
my $url = shift or FATAL("cpfetch called without a URL?");
my $target_file = shift;
if ( $url !~ /^http/ ) {
$url = 'http://' . get_update_source() . '/' . $url;
}
my $file;
if ( !$target_file ) {
my @FILE = split( /\//, $url );
$file = pop(@FILE);
}
else {
$file = $target_file;
}
if ( -e $file ) {
WARN("Warning: Overwriting $file");
unlink $file;
FATAL("Cannot remove $file") if ( -e $file );
}
DEBUG "Retrieving $url to $file";
`$wget_bin $wget_args '$file' $url`;
if ( !-e $file || -z $file ) {
unlink $file;
FATAL "Unable to fetch file $file.";
}
}
sub get_update_source {
my $update_source = 'httpupdate.cpanel.net';
my $source_file = '/etc/cpsources.conf';
if ( -r $source_file && -s $source_file ) { # pull in from cpsources.conf if it's set.
open( my $fh, "<", $source_file );
while (<$fh>) {
next if ( $_ !~ m/^\s*HTTPUPDATE\s*=\s*(\S+)/ );
$update_source = "$1";
FATAL("HTTPUPDATE is set to '$update_source' in $source_file") if ( !$update_source );
last;
}
}
return $update_source;
}
sub _MSG {
my $level = shift;
my $msg = shift || '';
chomp $msg;
my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime;
my ( $package, $filename, $line ) = caller($message_caller_depth);
my $stamp_msg = sprintf( "%04d-%02d-%02d %02d:%02d:%02d %4s (%5s): %s\n", $year + 1900, $mon + 1, $mday, $hour, $min, $sec, $line, $level, $msg );
print LOG $stamp_msg;
print $stamp_msg;
}
sub os_service_stop {
my $service = shift or die;
if ( $distro =~ m/bsd/i ) {
if ( $service =~ m/syslog/i ) {
ssystem( '/etc/rc.d/syslogd', 'stop' );
}
else {
DEBUG "Skipping stop of service '$service' on bsd";
}
return;
}
if ( !-e "/etc/init.d/$service" ) {
DEBUG("Skipping shutdown of non-existent service: $service");
return;
}
my $service_bin = '/sbin/service';
DEBUG "Ensuring service $service is not running";
ssystem( $service_bin, $service, 'stop' );
ssystem( 'killall', $service );
sleep 1;
ssystem( 'killall', '-9', $service );
}
sub os_service_start {
my $service = shift or die;
if ( $distro =~ m/bsd/i ) {
if ( $service =~ m/syslog/i ) {
ssystem( '/etc/rc.d/syslogd', 'start' );
}
else {
DEBUG "Skipping start of service '$service' on bsd";
}
return;
}
my $service_bin = '/sbin/service';
DEBUG " Starting service $service";
ssystem( $service_bin, $service, 'start' );
}
sub os_service_restart {
my $service = shift or die;
if ( $distro =~ m/bsd/i ) {
if ( $service =~ m/syslog/i ) {
ssystem( '/etc/rc.d/syslogd', 'restart' );
}
else {
DEBUG "Skipping restart of service '$service' on bsd";
}
return;
}
my $service_bin = '/sbin/service';
DEBUG "Restarting service $service";
ssystem( $service_bin, $service, 'restart' );
}
# Code previously located in the bootstrap script.
sub bootstrap {
my ( $distro, $distro_version ) = @_;
# Confirm perl version.
if ( $] < 5.008 ) {
print "Sorry, Perl 5.8.0 or better is required to run this installer.\n";
exit 5;
}
validate_rhn_registration( $distro, $distro_version );
# Assure wget/bzip2/gpg are installed for centhat. These packages are needed prior to sysup
install_critical_packages( $distro, $distro_version );
# Sync the clock.
if ( !update_system_clock() ) {
WARN( "Current system time is set to: " . `date` );
WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
WARN("Unable to verify system time. The utility to set time from a remote host, rdate, is not installed yet.");
WARN("If your system time is skewed greater than a few hours, then source compilations will subtly fail.");
WARN("This may result in an overall installation failure.");
WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
setup_empty_directories($distro);
# Setup yum/up2date touch files.
setup_update_config( $distro, $distro_version );
# BSD Sanity
bsd_sanity_checks($distro);
}
sub setup_empty_directories {
my $distro = shift or die;
# mkdir some directories.
INFO 'Setting up needed empty cpanel directories.';
foreach my $dir (qw{/usr/local/cpanel /usr/local/cpanel/logs /var/cpanel /var/cpanel/tmp /var/cpanel/version}) {
unlink $dir if ( -f $dir || -l $dir );
if ( !-d $dir ) {
DEBUG "mkdir $dir";
mkdir( $dir, 0755 );
}
}
}
sub setup_update_config {
my ( $distro, $distro_version ) = @_;
# No touchfiles for BSD.
return if ( $distro =~ m/bsd/i );
# IF RHEL 4
INFO("Setting up update flag files");
if ( $distro eq 'redhat' && $distro_version < 5 ) {
touch('/var/cpanel/useup2date');
}
else {
touch('/var/cpanel/useyum');
unlink('/var/cpanel/useup2date');
touch('/var/cpanel/yum_rhn') if ( $distro eq 'redhat' );
}
INFO("Making sure GPG is setup before importing keys");
system(qw{gpg --list-keys});
INFO("Importing gpg keys for yum");
if ( -e '/usr/share/rhn/RPM-GPG-KEY' ) {
system( 'gpg', '--import', '/usr/share/rhn/RPM-GPG-KEY' );
system( 'rpm', '--import', '/usr/share/rhn/RPM-GPG-KEY' );
}
# import CentOS 4 keys if that's what we are.
if ( $distro eq 'centos' && $distro_version == 4 && open( my $fh, '<', '/etc/redhat-release' ) ) {
my $ver = <$fh>;
if ( $ver =~ m/4\.([012])/ ) {
system( 'rpm', '--import', "http://mirror.centos.org/centos/4.$1/os/i386/RPM-GPG-KEY" );
}
}
if ( -e '/usr/share/doc/centos-release-4/RPM-GPG-KEY-centos4' ) {
system( 'rpm', '--import', '/usr/share/doc/centos-release-4/RPM-GPG-KEY-centos4' );
}
if ( !-e '/etc/yum.conf' && -e '/etc/centos-yum.conf' ) {
INFO("Setting up yum from '/etc/centos-yum.conf'");
system(qw{cp -f /etc/centos-yum.conf /etc/yum.conf});
}
}
sub validate_rhn_registration {
my ( $distro, $distro_version ) = @_;
# Short here if not redhat
return if ( $distro ne 'redhat' );
INFO("Checking RedHat registration for updates");
local $ENV{'TERM'} = 'dumb';
my $registered = '';
if ( $distro_version > 4 ) {
$registered = `yum list < blank 2>&1`;
}
elsif ( $distro_version eq 4 ) {
$registered = `up2date --show-channels --nox < blank 2>&1`;
}
else {
FATAL("Unknown update system. Cannot register.");
}
if ( $registered =~ m/not register|Please run rhn_register/ms ) {
ERROR("You must register with the Red Hat Network");
ERROR("when using Red Hat Enterprise before you can install cPanel.");
ERROR("Please run the following to register your server: /usr/sbin/rhn_register ");
FATAL("Installer Terminating....");
}
return if ( $distro_version < 6 );
my @channels = `/usr/sbin/spacewalk-channel --list`;
INFO("Validating you are subscribed to the optional RHN channel");
# optional channel validated.
return if ( grep { m/-optional-\d/ } @channels );
my $optional_channel;
foreach my $channel (@channels) {
chomp $channel;
next if ( $channel !~ /^rhel-([\dxi_]+)-server-\d+$/i );
$optional_channel = $channel;
$optional_channel =~ s/-server-6/-server-optional-6/;
}
if ( !$optional_channel ) {
ERROR("You do not appear to be registered with a known base channel for redhat");
ERROR('$> /usr/sbin/spacewalk-channel --list');
ERROR(`/usr/sbin/spacewalk-channel --list`);
exit 8;
}
ERROR("cPanel requires you be subscribed to the RHEL 6 optional channel to get all of the needed packages.");
ERROR("cPanel will not function without this channel. Please correct the situation and re-run the installer.");
ERROR('$> /usr/sbin/spacewalk-channel --list');
ERROR(`/usr/sbin/spacewalk-channel --list`);
ERROR(" ");
ERROR("Please run this command: /usr/sbin/spacewalk-channel --add --channel=$optional_channel");
ERROR(" ");
ERROR("Or you can register to the optional channel at http://rhn.redhat.com");
FATAL("Terminating...");
}
sub upgrade_to_cloud_linux {
DEBUG "Detecting if Cloud Linux is licensed through cpanel";
# /ULC/cpanel can't run until nativedf is run.
ssystem('/usr/local/cpanel/install/nativedf');
my $license_options = `/usr/local/cpanel/cpanel -F`;
return @_ if ( $license_options !~ m/cloudlinux/ms );
my $cloud_installer = '/usr/local/cpanel/bin/cloudlinux_update';
INFO("Upgrading your distro to Cloud Linux");
if ( !-x $cloud_installer ) {
WARN("Cannot convert your system to Cloud Linux without $cloud_installer");
}
else {
ssystem($cloud_installer);
}
# Re-check system to make sure we haven't moved to cloud linux
return check_system_support();
}
sub notify_if_boot_kernel_changed {
my $distro = shift || '';
return if ( $^O =~ m/bsd/i ); # Not a BSD check.
open( my $fh, '<', '/boot/grub/grub.conf' ) or return;
my $default;
while ( my $line = <$fh> ) {
next if ( $line !~ m/^\s*default\s*=\s*(\d+)/ );
$default = "$1";
last;
}
if ( !defined $default ) {
WARN("Cannot determine default boot from /boot/grub/grub.conf. You may need to reboot");
return;
}
# Walk the file to find the $default boot's title
my $title;
for ( 0 .. $default ) {
while ( my $line = <$fh> ) {
if ( $line =~ m/^title\s/ ) {
$title = $line;
chomp $title;
last;
}
}
}
# Look for the kernel.
my $boot_kernel;
while ( my $line = <$fh> ) {
return WARN("Cannot determine default boot from /boot/grub/grub.conf. for boot entry '$title' You may need to reboot -- $line")
if ( $line =~ m/^title\s/ );
next if ( $line !~ m{^\s*kernel\s+\S*/vmlinuz-(\S+)\s}i );
$boot_kernel = "$1";
last;
}
return WARN("Cannot determine default boot from /boot/grub/grub.conf. You may need to reboot")
if ( !$boot_kernel );
my $current_kernel = `uname -r`;
chomp $current_kernel;
return if ( $current_kernel eq $boot_kernel );
WARN "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
WARN "Your system kernel may have been updated.";
WARN "Current kernel ($current_kernel) has been changed to: $boot_kernel";
WARN "Before rebooting the system, please ensure that the installed kernel version is compatible with your deployment.";
if ( $distro =~ m/cloud/i ) {
WARN " ";
WARN " ************************************************************************************************************";
WARN " ";
WARN " NOTE: Because this is a Cloud Linux install, cPanel WILL NOT BE FULLY FUNCTIONAL until you reboot. ";
WARN " ";
WARN " ************************************************************************************************************";
WARN " ";
}
WARN "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
}
sub install_critical_packages {
my ( $distro, $distro_version ) = @_;
return if ( $distro =~ m/bsd/i ); # We can't do bsd this early in the installer.
# This is a hail mary to try to get these in and prevent updatenow/yum from failing in wierd ways.
# If the install fails and these did too, it's probably the cause.
foreach (qw/wget bzip2 gnupg rdate/) {
my $critical_pkg = $_; # Permit modification on this variable.
$critical_pkg .= '2' if ( $critical_pkg eq 'gnupg' && $distro_version >= 6 ); # C6 decided to rename their gnupg package to gnupg2
`rpm -q $critical_pkg`;
next if ( !$? );
WARN "Attempting to install critical package '$critical_pkg' for the installer";
unless ( $distro eq 'redhat' && $distro_version == 4 ) {
ssystem( qw/yum -y install/, $critical_pkg );
}
elsif ( $distro eq 'redhat' ) {
ssystem( qw{/usr/sbin/up2date -i}, $critical_pkg );
}
}
}
sub get_download_tool_binary {
my ( $distro, $distro_version ) = @_;
for my $bin (qw(/bin/wget /usr/bin/wget /usr/local/bin/wget)) {
next if ( !-e $bin );
next if ( !-x _ );
next if ( -z _ );
return ( $bin, '-q --tries=3 --timeout=60 --dns-timeout=60 -O' ) if ( `$bin --version` =~ m/GNU\s+Wget\s+\d+\.\d+/ims );
}
if ( $distro =~ m/bsd/i ) {
for my $bin (qw(/usr/bin/fetch /usr/local/bin/fetch /bin/fetch)) {
next if ( !-e $bin );
next if ( !-x _ );
next if ( -z _ );
return ( $bin, '-q -T 60 -o' );
}
FATAL "Neither wget nor fetch found, please install one to a standard location";
}
FATAL "The wget binary could not be found. Please install it to a standard location";
}
sub bsd_sanity_checks {
my $distro = shift;
return if ( $distro !~ m/bsd/i );
if ( !-e '/proc/1' ) {
INFO "Mounting procfs on /proc";
ssystem( 'mount', '-t', 'procfs', '/proc', '/proc' );
}
if ( !-e '/usr/local/bin/rsync' && !-e '/usr/bin/rsync' ) {
if ( -e '/usr/sbin/pkg_add' ) {
INFO "Installing rsync";
ssystem( '/usr/sbin/pkg_add', '-r', 'rsync' );
}
if ( !-e '/usr/local/bin/rsync' && !-e '/usr/bin/rsync' ) {
FATAL "The rsync binary could not be installed";
}
}
setup_bsd_symlinks();
}
sub setup_bsd_symlinks {
my %symlinks = qw{
/usr/bin/gzip /bin/gzip
/usr/bin/false /bin/false
/sbin/md5 /bin/md5
/usr/bin/tar /bin/tar
/etc/namedb /var/named
/usr/sbin/rndc /usr/sbin/ndc
/usr/local/bin/ncftpget /usr/bin/ncftpget
/usr/local/bin/lynx /usr/bin/lynx
/usr/local/bin/bash /bin/bash
/usr/local/bin/expect /usr/bin/expect
/usr/local/sbin/exim /usr/sbin/exim
/var/db/mysql /var/lib/mysql
/usr/home /home
/usr/local/bin/gmake /usr/bin/gmake
};
mkdir('/var/lib'); # For /var/lib/mysql
mkdir('/usr/home'); # default home directory isn't necessarily setup on bsd systems.
touch('/etc/make.conf') if ( !-e '/etc/make.conf' );
# Setup a forced symlink for each of these.
while ( my ( $bsd_location, $linux_location ) = each %symlinks ) {
next if ( -e $linux_location );
ssystem( qw{ln -sf}, $bsd_location, $linux_location );
}
}
sub install_bsd_software {
touch('/var/cpanel/usebsdpkgs');
ssystem('/usr/local/cpanel/scripts/setupmakeconf');
ssystem('/usr/local/cpanel/scripts/fixbinpath');
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'rsync' );
ssystem('/usr/local/cpanel/scripts/portsup');
# Case #51804
INFO "Building openssl in with STDOUT not redirected to work around bug in openssl";
system( '/usr/local/cpanel/scripts/ensurepkg', 'openssl' );
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'expect-devel' );
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'libltdl' );
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'expat' );
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'gd' );
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'p5-XML-Parser' ); # handles installing perl modules better
if ( -e '/usr/local/bin/use.perl' ) {
ssystem( '/usr/local/bin/use.perl', 'port' );
if ( !-e '/usr/bin/perl5' and !-l '/usr/bin/perl5' ) {
ssystem( 'ln', '-sf', '/usr/local/bin/perl', '/usr/bin/perl5' );
}
}
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'compat3x' );
if ( $distro_version < 7.99999 ) {
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'compat4x' );
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'compat5x' );
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'compat6x' );
}
elsif ( $distro_version > 7.9999 ) {
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'compat4x' );
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'compat5x' );
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'compat6x' );
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'compat7x' );
}
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'rdate' );
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'bind9' );
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'python' );
# needed due to bad pth on freebsd default install which breaks gnupg
my $installer_dir = Cwd::getcwd() || `pwd`;
schdir('/usr/ports/devel/pth');
ssystem('make deinstall');
ssystem('make clean');
ssystem('make install clean');
schdir($installer_dir);
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'gnupg' );
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'wget' );
ssystem( '/usr/local/cpanel/scripts/ensurepkg', 'libiconv' );
ssystem('/usr/local/cpanel/scripts/installfpfreebsd');
ssystem('/usr/local/cpanel/scripts/sysup');
}
sub enable_cphulkd {
my $conf_dir = '/var/cpanel/hulkd';
my $enabled_file = "$conf_dir/enabled";
INFO "Enabling cphulkd ...";
mkdir '/var/cpanel', 0755 unless -e '/var/cpanel';
mkdir "$conf_dir", 0755 unless -e "$conf_dir";
if ( open my $enabled_fh, '>', $enabled_file ) {
print {$enabled_fh} time();
close $enabled_fh;
INFO "Done";
}
else {
WARN "Unable to enable cphulkd";
}
}
# This code is somewhat of a duplication of the code for updatenow that blocks updates based on configuration
# settings. It needs to be here also because of the bootstrap level nature for when this needs to run.
sub check_for_install_version_blockers {
my ( $distro, $distro_version ) = @_;
# pull in cpanel.config settings.
my $cpanel_config = read_config('/var/cpanel/cpanel.config');
# Pull in cpupdate.conf settings.
my $cpupdate_conf = read_config('/etc/cpupdate.conf');
# Determine tier or assume defaults.
my $tier = $cpupdate_conf->{'CPANEL'} || ( -e '/var/cpanel/dnsonly' ? 'stable' : 'release' );
$tier =~ s/^(\d+\.\d+)[\d.]+?$/$1/; # Strip special versioned tiers down to 2 numbered.
if ( $distro =~ m/bsd/i && $tier ne '11.30' ) {
WARN('Setting installation tier to "11.30" since this is the only version supported for FreeBSD (see http://www.cpanel.net/products/cpanelwhm/system-requirements.html)');
$tier = $cpupdate_conf->{'CPANEL'} = '11.30';
save_config( '/etc/cpupdate.conf', $cpupdate_conf );
}
if ( $cpanel_config->{'mysql-version'} =~ m/5\.5/ && $tier eq '11.30' ) {
FATAL "Sorry, you have set MySQL to 5.5 in '/var/cpanel/cpanel.config' and your tier to 11.30 in '/etc/cpupdate.conf'. These are incompatible custom settings.";
}
if ( !$cpanel_config->{'maildir'} && $tier ne '11.30' ) {
FATAL "Sorry, you are trying to install exim with mbox '/var/cpanel/cpanel.config' on a cPanel version after 11.30. These are incompatible custom settings.";
}
}
sub update_system_clock {
my @rdate_bin =
-x '/scripts/rdate' ? ('/scripts/rdate')
: -x '/usr/bin/rdate' ? ( '/usr/bin/rdate', '-s', 'rdate.cpanel.net' )
: -x '/usr/local/bin/rdate' ? ( '/usr/local/bin/rdate', '-s', 'rdate.cpanel.net' )
: -x '/usr/local/sbin/rdate' ? ( '/usr/local/sbin/rdate', '-s', 'rdate.cpanel.net' )
: -x '/bin/rdate' ? ( '/bin/rdate', '-s', 'rdate.cpanel.net' )
: ();
# Complain if we don't have an rdate binary.
if ( !@rdate_bin ) {
ERROR("Could not set system clock. Missing an rdate binary");
return;
}
# Set the clock
my $was = time();
ssystem(@rdate_bin);
my $now = time();
INFO( "Clock set to: " . localtime($now) );
my $change = $now - $was;
# Adjust the start time if it shifted more than 10 seconds.
if ( abs($change) > 10 ) {
WARN("Clock changed by $change seconds.");
$installstart += $change;
WARN( "Starting time adjusted to " . localtime($installstart) );
}
else {
INFO("Clock changed by $change seconds");
}
return 1;
}