CHips L MINI SHELL

CHips L pro

Current Path : /proc/3/root/scripts/
Upload File :
Current File : //proc/3/root/scripts/find_and_fix_rpm_issues

#!/usr/local/cpanel/3rdparty/bin/perl
# cpanel - find_and_fix_rpm_issues                   Copyright 2014 cPanel, Inc.
#                                                           All rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

use strict;
use warnings;

package scripts::find_and_fix_rpm_issues;

use parent qw( Cpanel::HelpfulScript );

use Cpanel::Usage;
use Cpanel::Update::Logger;
use Cpanel::Update::Blocker::RPM;
use Cpanel::SafeRun::Simple ();

our $RPM_DB_DIR = '/var/lib/rpm';

if ( !caller() ) {
    exit __PACKAGE__->new(@ARGV)->run();
}

=encoding utf-8

=head1 NAME

find_and_fix_rpm_issues

=head1 USAGE

scripts/find_and_fix_rpm_issues [--findonly] [--rebuildonly] [--help]

=head1 DESCRIPTION

Detects problems with the rpm database and will rebuild the database
if it detects problems. Exits 0 if RPM is working properly, or if
we were able to fix it by rebuilding its database.

This script also detects duplicate cPanel RPMs, removes, and then
re-installs them if necessary.

    --findonly - Detect and report problems. Do not make any changes.

    --rebuildonly - Unconditionally rebuild the RPM database.

=cut

sub _OPTIONS {
    return qw( findonly rebuildonly );
}

# NOTE: Return logic throughout the script is reversed so that $? is 0 for
# success or 1 for failure.
sub run {
    my ($self) = @_;

    my $findonly       = $self->getopt('findonly');
    my $rebuildonly    = $self->getopt('rebuildonly');
    my $rpm_db_is_good = 1;

    my $blocker_logger = Cpanel::Update::Logger->new(       { 'stdout' => 1, 'log_level' => 'debug', 'timestamp' => 0 } );
    my $rpm_db         = Cpanel::Update::Blocker::RPM->new( { 'logger' => $blocker_logger } );

    if ( !$rebuildonly ) {

        my $status;
        ( $rpm_db_is_good, $status ) = $rpm_db->check_package_system();

        if ($rpm_db_is_good) {
            my $rpm_db = _dump_rpm_db();

            fix_duplicate_cpanel_rpms( $blocker_logger, $rpm_db );

            $rpm_db_is_good = verify_no_duplicate_rpms( $blocker_logger, $rpm_db );
        }

        $blocker_logger->info("find_and_fix_rpm_issues: rpm issues have been found") if !$rpm_db_is_good;
    }

    $rpm_db_is_good = 0 if $rebuildonly;

    if ( !$findonly && !$rpm_db_is_good ) {
        $blocker_logger->info("find_and_fix_rpm_issues: Performing rpm rebuild");

        # A non-zero return from rebuild_rpm_database indicates failure. It just returns $?.
        rebuild_rpm_database($blocker_logger) && return 1;

    }

    return 0;
}

sub rebuild_rpm_database {
    my ($logger) = @_;

    if ( opendir my $dh, $RPM_DB_DIR ) {
        while ( my $file = readdir $dh ) {
            next unless $file =~ m{^__db\.[0-9]+$} && -f "$RPM_DB_DIR/$file";
            unlink "$RPM_DB_DIR/$file" or do {
                $logger->info("find_and_fix_rpm_issues: Could not unlink $RPM_DB_DIR/$file: $!");
                return 1;
            };
        }
        closedir $dh;
    }

    Cpanel::SafeRun::Simple::saferunallerrors( "/bin/rpm", '-vvv', '--rebuilddb' );

    if ( ( $? >> 8 ) > 0 ) {
        $logger->info("find_and_fix_rpm_issues: Rebuilding the rpm database failed with exit code $?.");
        return 1;
    }
    else {
        return 0;
    }
}

sub _dump_rpm_db {
    return [ split( m{\n}, Cpanel::SafeRun::Simple::saferunallerrors( qw { rpm -qa --nodigest --nosignature --queryformat }, '%{INSTALLTIME}\t%{NAME}\t%{VERSION}\t%{RELEASE}\t%{ARCH}\t\n' ) ) ];
}

sub fix_duplicate_cpanel_rpms {
    my ( $logger, $rpmdb_ar ) = @_;

    my %rpms;
    my %rpm_erase;
    foreach my $line (@$rpmdb_ar) {
        next if index( $line, '.cp' ) == -1;

        my ( $installtime, $name, $version, $release, $arch ) = split( m/\t/, $line );

        # Only fix cp11## rpms.
        next if ( $release !~ m/cp\d{4}$/ );

        if ( $rpms{$name} ) {
            $rpm_erase{ sprintf( "%s-%s-%s.%s", $name, $rpms{$name}[0], $rpms{$name}[1], $rpms{$name}[2] ) } = 1;
            $rpm_erase{ sprintf( "%s-%s-%s.%s", $name, $version, $release, $arch ) } = 1;
        }
        else {

            # No duplicate found.
            $rpms{$name} = [ $version, $release, $arch ];

        }
    }

    return 0 if !%rpm_erase;

    $logger->info("Duplicate RPMs found.");

    my @cmd = ( qw{/bin/rpm -e --nodeps --justdb}, sort { $a cmp $b } keys %rpm_erase );
    $logger->info( "\$> " . join( " ", @cmd ) . "\n" );
    $logger->info( Cpanel::SafeRun::Simple::saferunallerrors(@cmd) );

    $logger->info("\$> /usr/local/cpanel/scripts/check_cpanel_rpms --fix\n");
    $logger->info( Cpanel::SafeRun::Simple::saferunallerrors(qw{/usr/local/cpanel/scripts/check_cpanel_rpms --fix}) );

    return 0;
}

# NOTE: The logic here may not be obvious.
# If the system has duplicate RPMs, this function will return 0, indicating a problem.
# Otherwise, it will return 1, indicating that it did not detect a problem.
#
# (That doesn't mean there isn't a problem; it just means we didn't find one.)
sub verify_no_duplicate_rpms {
    my ( $logger, $rpmdb_ar ) = @_;
    my %rpm_hash;
    $rpm_hash{ substr( $_, index( $_, "\t" ) + 1 ) }++ for @$rpmdb_ar;

    # Multiple kernel packages are ok
    delete @rpm_hash{ grep { index( $_, "kernel" ) == 0 } keys %rpm_hash };

    if ( grep { $_ > 1 } values %rpm_hash ) {
        foreach my $line ( grep { $rpm_hash{$_} > 1 } keys %rpm_hash ) {
            my ( $name, $version, $release, $arch ) = split( m/\t/, $line );
            my $dupe_count = $rpm_hash{$line} - 1;
            $logger->info( "The “$name” package has “$dupe_count” duplicate package" . ( $dupe_count > 1 ? 's' : '' ) . " installed." );
        }
        return 0;
    }
    return 1;
}

1;

Copyright 2K16 - 2K18 Indonesian Hacker Rulez