#!/usr/bin/perl
# cpanel - munin/install                          Copyright(c) 2012 cPanel, Inc.
#                                                           All rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

BEGIN { unshift @INC, '/usr/local/cpanel'; }

use strict;

$| = 1;
my $system                = lc $^O;
my $ver                   = '1.4.7-cp2';
my $chrpath_ver           = '0.13';
my @REQUIRED_PERL_MODULES = ( 'Log::Log4perl', 'Module::Build', 'Time::HiRes', 'HTML::Template', 'Net::Server', 'Net::Server::Fork', 'Net::SNMP', 'HTML::Template', 'Cache::Cache' );
my @RRD_DIRS              = split( /\n/, `/usr/local/cpanel/bin/get_rrd_dirs` );

if ( !@RRD_DIRS ) {
    fail_install( "find_rrd_tool", "Could not use /usr/local/cpanel/bin/get_rrd_dirs to find the rrdtool \@INC" );
}

my $sitelib = findsitelib();

# sitelib() can be wrong as far as where a module will go see case 8494
my $version  = get_perl_version();
my $archname = get_perl_archname();

if ( !$sitelib || !$version || !$archname ) {
    fail_install( 'get_perl_data', "Could not find the perl sitelib ($sitelib), version ($version) or archname ($archname)" );
}

eval {
    require Cpanel::PwCache;
    require Cpanel::AccessIds::SetUids;
    require Cpanel::SafeFile;
    require Cpanel::SafeRun::Simple;
    require Cpanel::StringFunc;
    require Cpanel::LoadFile;
    require Cpanel::FindBin;
    require Cpanel::Hostname;
    require Cpanel::FileUtils::TouchFile;
    require Cpanel::cPCPAN;
    require Data::Dumper;
    require Cwd;
};
if ($@) {
    fail_install( 'load_perl_modules', "Could not load required cPanel Modules: $@" );
}

my $hostname = Cpanel::Hostname::gethostname();

if ( $hostname =~ m/[A-Z]/ ) {
    fail_install( 'hostname_uppercase_check', "Unexpected uppercase characters in hostname \"$hostname\". \nThe server hostname may not contain uppercase characters. \nPlease normalize the hostname to lowercase and try again." );
}

my $install_dir = Cwd::cwd();
my $make = Cpanel::FindBin::findbin('gmake') || Cpanel::FindBin::findbin('make') || 'make';

print "Checking for librrd version ...\n";
my $rrd_lib_dir = "/usr/local/cpanel/3rdparty/lib";
my $rrd_lib     = assign_rrdlib($rrd_lib_dir);
print "Done\n";

print "Adding munin user (if needed)...";
my ( $adduser_status, $adduser_message ) = add_munin_user_if_needed();
print "Done\n";
if ( !$adduser_status ) {
    fail_install( 'add_munin_user_if_needed', $adduser_message );
}
print "Installing perl modules....";
my ( $perl_install_status, $perl_install_messsage ) = install_required_perl_modules();
print "Done\n";
if ( !$perl_install_status ) {
    fail_install( 'install_required_perl_modules', $perl_install_messsage );
}

my $result = set_innodb_access();
if ( !$result ) {
    print "\nEncountered problem while setting MySQL InnoDB access. No further InnoDB access was performed.\n";
    print "Suggestion:\n";
    print "   Verify input data, enable InnoDB, check config file '/etc/my.cnf', restart MySQL and then reinstall Munin,\n";
    print "   or InnoDB chart may not function as expected.\n";
}

chdir($install_dir) || fail_install( 'return_to_install_dir', "Could not return to install dir: $install_dir" );

if ( $^O =~ /linux/i && -d '/usr/lib64' ) {

    if ( !-x '/usr/local/cpanel/3rdparty/bin/chrpath' ) {
        print "Extracting chrpath files...";
        fail_install( 'extract_files', "Could not find " . 'chrpath-' . $chrpath_ver . '.tar.gz' . " cwd: " . `pwd` ) if !-e 'chrpath-' . $chrpath_ver . '.tar.gz';
        safe_extract( 'chrpath-' . $chrpath_ver . '.tar.gz' );
        chdir 'chrpath-' . $chrpath_ver or fail_install( "extract", "Unable to chdir into chrpath-$chrpath_ver" );
        print "Done\n";

        print "Configuring chrpath\n";
        system './configure', '--prefix=/usr/local/cpanel/3rdparty';
        if ( $? >> 8 != 0 ) {
            warn_install( 'chrpath source: configure', "Failed to configure chrpath" );
        }
        print "Done\n";

        print "Making default target\n";
        system $make;
        if ( $? >> 8 != 0 ) {
            warn_install( 'chrpath source: make default target', "chrpath source: Failed to make default target" );
        }
        print "Done\n";

        print "Making install target\n";
        system $make, 'install';
        if ( $? >> 8 != 0 ) {
            warn_install( 'chrpath source: make install target', "chrpath source: Failed to make install target" );
        }
        print "Done\n";

        warn_install( 'chrpath executable test', 'chrpath could not be built' ) if !-x '/usr/local/cpanel/3rdparty/bin/chrpath';

        chdir($install_dir) || fail_install( 'return_to_install_dir', "Could not return to install dir: $install_dir" );
    }

    print "Fixing rpath (if needed)...";
    fix_rpath( $rrd_lib_dir, $rrd_lib );
    print "Done\n";

}

print "Extracting files...";
fail_install( 'extract_files', "Could not find " . 'munin-' . $ver . '.tar.gz' . " cwd: " . `pwd` ) if !-e 'munin-' . $ver . '.tar.gz';
my $src_dir = 'munin-' . $ver;
safe_extract( $src_dir . '.tar.gz' );
chdir $src_dir or fail_install( "extract", "Unable to chdir into $src_dir" );
print "Done\n";

print "Installing defaults file...";
append( '../osdata/defaults', 'Makefile.config' );
print "Done\n";

print "Setting up Makefile...";
setup_makefile();
print "Done\n";

print "Fixing problems with munin.conf (if needed)....";
fix_previous_conf();
print "Done\n";

print "Generating config....";
my $cf = buildconf();
print "Done\n";

if ( $cf->{'DBDIR'} !~ /munin/ || $cf->{'LOGDIR'} !~ /munin/ ) {
    fail_install( 'buildconf', "Failed to configure DBDIR and/or LOGDIR" );
}

print "Making clean target\n";
system $make, 'clean';
if ( $? >> 8 != 0 ) {
    fail_install( 'munin source: make clean target', "Failed to make clean target" );
}
print "Done\n";
print "Making default target\n";
system $make;
if ( $? >> 8 != 0 ) {
    fail_install( 'munin source: make default target', "Failed to make default target" );
}
print "Done\n";
print "Making install-common-prime target\n";
system $make, 'install-common-prime';
if ( $? >> 8 != 0 ) {
    fail_install( 'munin source: make install-common-prime target', "Failed to make install-common-prime target" );
}
print "Done\n";
print "Making install-master-prime target\n";
system $make, 'install-master-prime';
if ( $? >> 8 != 0 ) {
    fail_install( 'munin source: make install-master-prime target', "Failed to make install-master-prime target" );
}
print "Done\n";
print "Making install-node target\n";
system $make, 'install-node';
if ( $? >> 8 != 0 ) {
    fail_install( 'munin source: make install-node target', "Failed to make install-node target" );
}
print "Done\n";

print "Making install-node-prime target\n";
system $make, 'install-node-prime';
print "Done\n";
if ( $? >> 8 != 0 ) {
    fail_install( 'munin source: make install-node-prime target', "Failed to make install-node-prime target" );
}

print "Making install-node-plugins target\n";
system $make, 'install-node-plugins';
print "Done\n";
if ( $? >> 8 != 0 ) {
    fail_install( 'munin source: make install-node-plugins target', "Failed to make install-node-plugins target" );
}

print "Installing init scripts and crontab entries...";
install_init_script_and_crontab();
print "Done\n";

print "Applying cPanel modifications...";
modify_for_cpanel($cf);
print "Done\n";

print "Configuring munin plugins...\n";
configure_munin_plugins();
print "Done\n";

if ( -x '/usr/sbin/cagefsctl' ) {
    print "Updating CageFS\n";
    system '/usr/sbin/cagefsctl', '-u';
    print "Done\n";
}

print "Starting munin...";
start_munin();
print "Done\n";

print "Restarting apache (gracefully)....\n";
system '/usr/local/cpanel/bin/safeapacherestart';
print "Done\n";

print "Running munin cron...\n";
run_munin_cron();
print "Done\n";

print "Saving configuration...";
if ( open( my $conf_fh, ">", "../config.pl" ) ) {
    print {$conf_fh} Data::Dumper::Dumper($cf);
    close($conf_fh);
}
print "Done\n";

print "Removing extracted files...\n";
if ( chdir '..' && -e 'munin-' . $ver ) {
    system 'rm', '-rf', '--', 'munin-' . $ver;
    system 'rm', '-rf', '--', 'chrpath-' . $chrpath_ver;
}
print "Done\n";

print "Installing WHM Plugin...";
system 'install', '-m700', 'addon_munin.cgi', '/usr/local/cpanel/whostmgr/docroot/cgi/addon_munin.cgi';
print "Done\n";

print "Registering AppConfig...";
register_appconfig();
print "Done\n";

print 'Install Successfully Completed (munin ' . $ver . ")\n";

sub buildconf {
    my %CONFIG;
    if ( open my $mc, '<', 'Makefile.config' ) {
        while (<$mc>) {
            if (/^\s*(\S+)\s*=\s*(\S+)\s*$/) {
                $CONFIG{$1} = $2;
            }
        }
        close $mc;
    }
    foreach my $ele ( keys %CONFIG ) {
        while ( $CONFIG{$ele} =~ s/\$\((\S+)\)/$CONFIG{$1}/g ) {
            next;
        }
    }

    return \%CONFIG;
}

sub fix_previous_conf {
    if ( -e '/etc/munin/munin.conf' ) {
        my $munin_cf = Cpanel::LoadFile::loadfile('/etc/munin/munin.conf');
        if ( $munin_cf =~ s/^dbdir dbdir/dbdir/m ) {
            system 'cp', '-fv', '/etc/munin/munin.conf', '/etc/munin/munin.conf.bak';
            if ( open( my $munin_cf_fh, '>', '/etc/munin/munin.conf' ) ) {
                print {$munin_cf_fh} $munin_cf;
                close($munin_cf_fh);
            }
        }
    }
}

sub modify_for_cpanel {
    my $rcf = shift;

    #START CPANEL CUSTOM
    my $config_file      = $rcf->{'CONFDIR'} . '/munin.conf';
    my $node_config_file = $rcf->{'CONFDIR'} . '/munin-node.conf';

    if ( !-d '/usr/local/cpanel/whostmgr/docroot/munin' && !mkdir '/usr/local/cpanel/whostmgr/docroot/munin', 0700 ) {
        fail_install( 'modify_for_cpanel', 'create /usr/local/cpanel/whostmgr/docroot/munin' );
    }

    my ( $uid, $gid, $homedir ) = ( Cpanel::PwCache::getpwnam('munin') )[ 2, 3, 7 ];

    mkdir $homedir, 0711 if !-d $homedir;

    chown $uid, $gid, $homedir, '/usr/local/cpanel/whostmgr/docroot/munin', $rcf->{'DBDIR'}, $rcf->{'LOGDIR'};

    # Set directory permission for "plugin-state" dir to "775" (and not "755")
    # so that data/chart for mailman and exim can be generated.
    # (eg. "/var/lib/munin/plugin-state" dir on redhat)
    if ( -d $rcf->{'PLUGSTATE'} ) {
        system 'chmod', '0775', $rcf->{'PLUGSTATE'};
        print "Changed directory permission for \"$rcf->{'PLUGSTATE'}\" to '0775'. \n";
    }
    else {
        print "Warning: Unable to change \"$rcf->{'PLUGSTATE'}\" directory permission to '0775': $! \n";
    }

    my $plugindir  = $rcf->{'LIBDIR'} . '/plugins/';
    my $plugincdir = $rcf->{'CONFDIR'} . '/plugin-conf.d/';

    system 'install', '-m644', '../osdata/cpanel.conf', $plugincdir . '/cpanel.conf';

    if ( opendir( my $plugin_dir_dh, $plugindir ) ) {
        while ( my $file = readdir($plugin_dir_dh) ) {
            next if ( $file =~ /^\./ );
            print "Processing plugin $file.....";
            if ( $file =~ /(?:lpstat|sendmail|postfix)/ ) {
                print 'unlinked';
                unlink( $plugindir . '/' . $file );
            }
            elsif ( $file =~ /apache/i ) {
                print 'cpanel-compat';
                Cpanel::StringFunc::regsrep( $plugindir . '/' . $file, '/server-status', '/whm-server-status', 1 );
            }
            elsif ( $file =~ /mailman/i ) {
                print 'cpanel-compat';
                symlink( $plugindir . '/' . $file, $rcf->{'CONFDIR'} . '/plugins/' . $file );
                if ( !-e '/usr/local/cpanel/3rdparty/mailman/logs/post' ) {
                    if ( my $pid = fork() ) {

                    }
                    else {
                        Cpanel::AccessIds::SetUids::setuids( 'mailman', 'mailman' );
                        Cpanel::FileUtils::TouchFile::touchfile('/usr/local/cpanel/3rdparty/mailman/logs/post');
                        exit 0;
                    }
                }
                Cpanel::StringFunc::regsrep( $plugindir . '/' . $file, '^\$logfile\s+=', '$logfile = "/usr/local/cpanel/3rdparty/mailman/logs/post";' );
                Cpanel::StringFunc::regsrep( $plugindir . '/' . $file, '^\$libdir\s+=',  '$libdir  = "/usr/local/cpanel/3rdparty/mailman";' );
                Cpanel::StringFunc::regsrep( $plugindir . '/' . $file, '^\$lister\s+=',  '$lister  = "/usr/local/cpanel/3rdparty/mailman/bin/list_members";' );
            }

            print "....Done\n";
        }
        closedir($plugin_dir_dh);
    }

    Cpanel::StringFunc::regsrep( $node_config_file, '^\s*group', 'group wheel' );

    my $has_htmldir = 0;
    my $has_dbdir   = 0;
    my $has_tmpldir = 0;

    if ( open( my $config_file_fh, '+<', $config_file ) ) {
        local $/;
        my $munin_config_data = readline($config_file_fh);
        my $modified          = 0;

        if ( $munin_config_data =~ m/^\s*htmldir\s+/m ) { $has_htmldir = 1; }
        if ( $munin_config_data =~ m/^\s*dbdir\s+/m )   { $has_dbdir   = 1; }
        if ( $munin_config_data =~ m/^\s*tmpldir\s+/m ) { $has_tmpldir = 1; }

        if ( !$has_htmldir ) { $munin_config_data = 'htmldir /usr/local/cpanel/whostmgr/docroot/munin' . "\n" . $munin_config_data; $modified = 1; }
        if ( !$has_dbdir )   { $munin_config_data = 'dbdir ' . $rcf->{'DBDIR'} . "\n" . $munin_config_data;                         $modified = 1; }
        if ( !$has_tmpldir ) { $munin_config_data = 'tmpldir ' . $rcf->{'CONFDIR'} . '/templates' . "\n" . $munin_config_data;      $modified = 1; }

        if ($modified) {
            seek( $config_file_fh, 0, 0 );
            print {$config_file_fh} $munin_config_data;
        }

        close($config_file_fh);
    }
    Cpanel::StringFunc::regsrep( $config_file, '^\s*htmldir\s*', 'htmldir /usr/local/cpanel/whostmgr/docroot/munin' ) if $has_htmldir;
    Cpanel::StringFunc::regsrep( $config_file, '^\s*dbdir\s*',   'dbdir ' . $rcf->{'DBDIR'} )                         if $has_dbdir;
    Cpanel::StringFunc::regsrep( $config_file, '^\s*tmpldir\s*', 'tmpldir ' . $rcf->{'CONFDIR'} . '/templates' )      if $has_tmpldir;

    my $rrds_pm_path = "/usr/local/cpanel/3rdparty/lib/perl/$version/$archname";
    if ( !grep { $_ eq $rrds_pm_path } @RRD_DIRS ) {
        push @RRD_DIRS, $rrds_pm_path;
    }
    if ( !grep { $_ eq '/usr/local/cpanel/3rdparty/lib/perl' } @RRD_DIRS ) {
        push @RRD_DIRS, '/usr/local/cpanel/3rdparty/lib/perl';
    }
    my $pm_file_dir = $sitelib . '/' . 'Munin';
    if ( !-d $pm_file_dir . '/Master' ) {
        my $munin_common_config_pm;
        eval {
            local @INC = ( @INC, @RRD_DIRS );
            require Munin::Common::Config;
            print "Setting INC in actual -$INC{'Munin/Common/Config.pm'}-\n";
            $munin_common_config_pm = $INC{'Munin/Common/Config.pm'};
        };
        $pm_file_dir = $munin_common_config_pm;
        $pm_file_dir =~ s{/Common/Config\.pm$}{}g;
    }

    print "Found installed PM directory: $pm_file_dir\n";

    my @pm_files;
    if ( opendir( my $master_dir, $pm_file_dir . '/Master' ) ) {
        @pm_files = map { /\.pm$/ ? ( $pm_file_dir . '/Master/' . $_ ) : () } readdir($master_dir);
        closedir($master_dir);
    }
    else {
        fail_install( "modify_for_cpanel", "Failed to open PM directory: $pm_file_dir" );
    }

    my $inc_paths = join( ',', map { '"' . $_ . '"' } @RRD_DIRS );
    my @change = ( '^\s*use RRDs', 'BEGIN { unshift @INC, ' . $inc_paths . ' ; }; use RRDs;' );

    foreach my $file ( @pm_files, $rcf->{'LIBDIR'} . "/munin-graph", $rcf->{'LIBDIR'} . "/munin-update" ) {
        print "Patching $file....";
        Cpanel::StringFunc::regsrep( $file, @change );
        print "Done\n";
    }

    system '/bin/chown', '-h', '-R', 'munin:munin', $rcf->{'DBDIR'}, $rcf->{'LOGDIR'};

    # Make sure mysql is enable by setting links from '/usr/share/munin/plugins' to '/etc/munin/plugins'
    set_mysql_links( $rcf->{'LIBDIR'} . '/plugins', $rcf->{'CONFDIR'} . '/plugins' );

    #END CPANEL CUSTOM
}

sub set_mysql_links {
    my ( $source_dir, $link_dir ) = @_;
    return if ( $source_dir =~ m/^\.\.?$/ );
    return if ( $link_dir   =~ m/^\.\.?$/ );
    return if ( !( -d $source_dir && -d $link_dir ) );

    my $dh = undef;
    if ( !opendir( $dh, $source_dir ) ) {
        print "Warning: Unable to read \"$source_dir\" ($!)\n";
        print "         No mysql symlinks created from \"$source_dir\" to \"$link_dir\".\n";
        return;
    }
    my @filelist = grep { /^mysql_[\w]+/ } readdir($dh);
    closedir($dh);

    foreach my $file (@filelist) {
        my $link_file = "$link_dir/$file";

        # Clear out any potentially old broken link
        unlink $link_file if -l $link_file;

        # Assign valid link as needed
        if ( !-e $link_file ) {
            if ( !symlink( "$source_dir/$file", $link_file ) ) {
                print "Warning: Unable to create link \"$link_file\" ($!)\n";
            }
        }
    }

    # Exclude existing "mysql_isam_space"
    my $isam_link   = "$link_dir/mysql_isam_space_";
    my $isam_source = "$source_dir/mysql_isam_space_";
    if ( -e $isam_link && readlink($isam_link) =~ /^\Q$isam_source\E$/ ) {
        unlink $isam_link;
    }
}

sub set_innodb_access {

    my $user_name  = 'munin';
    my $db_name    = 'munin_innodb';
    my $table_name = 'sample_table';
    my $query_info = undef;

    eval { require Cpanel::MysqlUtils; };
    if ($@) {
        print "Warning: Unable to load required cPanel module \"Cpanel::MysqlUtils\": $@";
        return 0;
    }

    # Create "munin_innodb" database
    if ( !Cpanel::MysqlUtils::db_exists($db_name) ) {
        $query_info = Cpanel::MysqlUtils::sqlcmd("CREATE DATABASE $db_name;");
        $query_info = Cpanel::MysqlUtils::sqlcmd("SHOW DATABASES LIKE '$db_name';");
        chomp($query_info);
        $query_info =~ /\A\Q$db_name\E\z/;
        if ( !$query_info ) {
            print "Warning: Unable to create database \"$db_name\" for MySQL InnoDB plugin usage.\n";
            return 0;
        }
    }

    # Clear out old table
    $query_info = Cpanel::MysqlUtils::sqlcmd("USE $db_name; DROP TABLE '$table_name';");
    chomp($query_info);
    if ( !$query_info ) {
        print "Warning: Unable to remove existing table \"$table_name\".\n";
    }
    else {

        # Create new database table "munin_innodb.sample_table"
        $query_info = Cpanel::MysqlUtils::sqlcmd("CREATE TABLE $db_name.$table_name (field1 int) ENGINE=InnoDB;");
        $query_info = Cpanel::MysqlUtils::sqlcmd("USE $db_name; SHOW TABLES LIKE '$table_name';");
        if ( !$query_info ) {
            print "Warning: Unable to create table \"$table_name\".\n";
            return 0;
        }
    }

    # Verify if InnoDB engine was used for table creation
    $query_info = Cpanel::MysqlUtils::sqlcmd("USE $db_name; SHOW CREATE TABLE $table_name;");
    if ( $query_info !~ m/ENGINE=InnoDB/i ) {
        print "Warning: Unable to detect InnoDB engine; it might have been disabled. \n";
        return 0;
    }

    # Grant database table access
    $query_info = Cpanel::MysqlUtils::sqlcmd("GRANT SELECT ON $db_name.* to '$user_name'\@'localhost' IDENTIFIED BY '$user_name';");
    $query_info = Cpanel::MysqlUtils::sqlcmd("USE mysql; SELECT select_priv FROM db WHERE db='$db_name' AND user='$user_name' AND select_priv='Y';");
    chomp($query_info);
    if ( $query_info ne 'Y' ) {
        print "Warning: Unable to set access on database tables in \"$db_name\" for MySQL InnoDB plugin usage.\n";
        return 0;
    }
    else {
        print "\nFYI: InnoDB access granted ok.\n";
        return 1;
    }
}

sub findsitelib {
    my $sitelib = `perl -V:sitelib`;
    $sitelib =~ /\'([^\']+)/;
    return $1;
}

sub get_perl_version {
    my $string = `perl -V:version`;
    if ( $string =~ m{version\=\'(.*)\'\;} ) {
        return if $1 eq 'undef';
        return $1;
    }
    return;
}

sub get_perl_archname {
    my $string = `perl -V:archname`;
    if ( $string =~ m{archname\=\'(.*)\'\;} ) {
        return if $1 eq 'undef';
        return $1;
    }
    return;
}

sub append {
    my $src  = shift;
    my $dest = shift;

    open my $src_file,  '<',  $src;
    open my $dest_file, '>>', $dest;
    while (<$src_file>) {
        print {$dest_file} $_;
    }
    close $dest_file;
    close $src_file;
}

sub warn_install {
    my ( $fail_location, $fail_message ) = @_;
    warn "Failed @ $fail_location(): $fail_message, attempting to continue";
}

sub fail_install {
    my ( $fail_location, $fail_message ) = @_;
    if ( open( my $version_fh, '>', '/var/cpanel/addonmoduleversions/munin' ) ) {
        print {$version_fh} 'failed';
        close($version_fh);
    }

    $fail_location = $fail_location ? "in $0 at $fail_location ()" : "in $0";
    my $msg = "\nERROR: Failed to install Munin - $fail_location: \n$fail_message \nMunin install process cannot proceed further ... \nExiting ...";

    print $msg;    # Provide info to WHM
    die $msg;      # Info is included in error_log
}

sub install_required_perl_modules {
    my $cPCPAN = Cpanel::cPCPAN->new();
    my @MODULES_NEED_INSTALL;
    foreach my $module (@REQUIRED_PERL_MODULES) {
        if ( !$cPCPAN->check_installed($module) ) {
            push @MODULES_NEED_INSTALL, $module;
            print "$module..[needed]..";
        }
        else {
            print "$module..[ok]..";
        }
    }

    return ( 1, "No modules need to be installed" ) if !@MODULES_NEED_INSTALL;
    eval { $cPCPAN->install(@MODULES_NEED_INSTALL); };

    my @MODULES_NEED_FORCE_INSTALL;

    foreach my $module (@MODULES_NEED_INSTALL) {
        if ( !$cPCPAN->check_installed($module) ) {
            print "$module..[needed (forced)]..";
            push @MODULES_NEED_FORCE_INSTALL, $module;
        }
        else {
            print "$module..[ok]..";
        }
    }

    return ( 1, "Perl Module Installed OK after installing: " . join( ' , ', @MODULES_NEED_INSTALL ) ) if !@MODULES_NEED_FORCE_INSTALL;

    eval { $cPCPAN->install( '--force', @MODULES_NEED_FORCE_INSTALL ); };

    foreach my $module (@MODULES_NEED_FORCE_INSTALL) {
        if ( !$cPCPAN->check_installed($module) ) {
            return ( 0, "Could not install perl module $module" );
        }
    }

    return ( 1, "Perl Module Installed OK after force installing: " . join( ' , ', @MODULES_NEED_FORCE_INSTALL ) );
}

sub add_munin_user_if_needed {
    if ( $system =~ /freebsd/i ) {
        system '/usr/sbin/pw', 'groupadd', 'munin' if !getgrnam('munin');
        system '/usr/sbin/pw', 'useradd', 'munin', '-g', 'munin' if !Cpanel::PwCache::getpwnam('munin');
    }
    else {
        system '/usr/sbin/groupadd', 'munin' if !getgrnam('munin');
        system '/usr/sbin/useradd', '-g', 'munin', 'munin' if !Cpanel::PwCache::getpwnam('munin');
    }
    if ( !getgrnam('munin') || !Cpanel::PwCache::getpwnam('munin') ) {
        return ( 0, "Failed to add munin user" );
    }
    else {
        return ( 1, "Munin user added or existant" );
    }
}

sub install_init_script_and_crontab {
    if ( $system =~ /freebsd/i ) {
        my $hasrc = 0;
        my $sl = Cpanel::SafeFile::safeopen( \*RCC, '+<', '/etc/rc.conf' );
        while (<RCC>) {
            if (/munin/) { $hasrc = 1; }
        }

        if ( !$hasrc ) { print RCC 'munin_node_enable="YES"' . "\n"; }
        Cpanel::SafeFile::safeclose( \*RCC, $sl );

        system 'install', '-m755', '../osdata/freebsd/munin-node.sh', '/usr/local/etc/rc.d/munin-node.sh';
        system('crontab -u munin ../freebsd/munin.cron');
    }
    elsif ( -e '/etc/SuSE-release' ) {
        system('crontab -u munin ../osdata/linux/munin.cron');
        system( 'cp', '-a', 'dists/suse/munin-node.rc', '/etc/init.d/munin-node' );
        system( '/sbin/chkconfig', 'munin', '35' );
    }
    else {
        system('crontab -u munin ../osdata/linux/munin.cron');
        system( 'cp', '-a', 'dists/redhat/munin-node.rc', '/etc/init.d/munin-node' );
        system( '/sbin/chkconfig', '--add', 'munin-node' );
        system( '/sbin/chkconfig', '--level', '2345', 'munin-node', 'on' );
    }
}

sub setup_makefile {
    if ( $system =~ /freebsd/i ) {
        append( '../osdata/freebsd/Makefile.config.freebsd', 'Makefile.config' );
    }
    elsif ( -e '/etc/SuSE-release' ) {
        append( 'dists/suse/Makefile.config', 'Makefile.config' );
    }
    else {
        append( 'dists/redhat/Makefile.config', 'Makefile.config' );
    }
}

sub start_munin {
    if ( -e '/etc/init.d/munin-node' ) {
        system '/etc/init.d/munin-node', 'stop';
        system '/etc/init.d/munin-node', 'start';
    }
    elsif ( -e '/usr/local/etc/rc.d/munin-node.sh' ) {
        system '/usr/local/etc/rc.d/munin-node.sh', 'stop';
        system '/usr/local/etc/rc.d/munin-node.sh', 'start';
    }
}

sub configure_munin_plugins {
    system 'munin-node-configure --shell | sh';
}

sub run_munin_cron {
    if ( $system =~ /freebsd/i ) {
        system 'su munin -c /usr/local/bin/munin-cron';
    }
    else {
        system 'su munin -c /usr/bin/munin-cron';
    }
}

sub fix_rpath {
    my ( $rrd_lib_dir, $rrd_lib ) = @_;

    if ( !-e "$rrd_lib_dir/$rrd_lib" ) {
        fail_install( "fix_rpath", "\nUnable to adjust rpath --  \"$rrd_lib_dir/$rrd_lib\" does not exist.\n" );
    }

    my $rpath_line = Cpanel::SafeRun::Simple::saferun( '/usr/local/cpanel/3rdparty/bin/chrpath', '-l', "$rrd_lib_dir/$rrd_lib" );
    if ( $rpath_line =~ /RPATH=(\S+)/ ) {
        my $rpath = $1;
        if ( $rpath =~ m{^/usr/lib} ) {
            print "Fixing rpath for \"$rrd_lib\" ... Setting its rpath to \"$rrd_lib_dir\"\n";
            system( '/usr/local/cpanel/3rdparty/bin/chrpath', '-r', $rrd_lib_dir, "$rrd_lib_dir/$rrd_lib" );
            print "Done\n";
        }
    }
    return 1;
}

# Assign "librrd" version to use
sub assign_rrdlib {

    my ($rrd_lib_dir) = @_;
    if ( !-d $rrd_lib_dir ) {
        fail_install( "assigning_rrdlib", "\nDirectory for librrd does not exist \"$rrd_lib_dir\".\n" );
    }

    my $assigned_rrd_lib = undef;
    my $rrd_lib_prev     = "librrd.so.4";
    my $rrd_lib_curr     = "librrd.so.5";

    if ( -e "$rrd_lib_dir/$rrd_lib_curr" ) {
        $assigned_rrd_lib = $rrd_lib_curr;
    }
    elsif ( -e "$rrd_lib_dir/$rrd_lib_prev" ) {
        $assigned_rrd_lib = $rrd_lib_prev;
    }
    else {
        fail_install( "assigning_rrdlib", "\nUnable to locate librrd -- neither \"$rrd_lib_prev\" nor \"$rrd_lib_curr\" is available from dir \"$rrd_lib_dir\".\n" );
    }

    return $assigned_rrd_lib;
}

sub safe_extract {
    my $tarball = shift;
    return unless $tarball && -e $tarball;

    my $has_bsdtar = 1;
    system("tar --version | grep -i bsdtar 2>&1 >/dev/null") == 0 or $has_bsdtar = 0;

    if ($has_bsdtar) {
        system( 'tar', '-x', '-z', '-o', '-v', '-f', $tarball );
    }
    else {
        system( 'tar', '-x', '-z', '--no-same-owner', '--no-same-permissions', '-v', '-f', $tarball );
    }
}

sub register_appconfig {
    if ( -e "/usr/local/cpanel/bin/register_appconfig" ) {
        system '/usr/local/cpanel/bin/register_appconfig', 'appconfig/munin.conf';
    }
    else {
        if ( !-e "/var/cpanel/apps" ) {
            mkdir( '/var/cpanel/apps', 0755 );
        }
        my $CPARGS = ( $^O =~ /freebsd/i ? '-Rpf' : '-afv' );    # freebsd no longer supported but may have the module installed
        system( "cp", $CPARGS, "appconfig/munin.conf", "/var/cpanel/apps/munin.conf" );
    }
}
