�&ǐk�@'bJ�h�ۊL'}T� :��'2�Z#$��n�a��� �>a��`��_3d�Qpt�/�P -��#5�,�M��� �pA:©�q�����NW��ډ�A���� �9nʺج���� �TSM��{J6?7��r�@�\����D��� �׶���s�f�TJj?"��D��`?��̒� b�#�%�C*v�$�{�$����5Ծ�F�s��y�e/8��h-�f�̰&(����Gj�L:U� 2�� ����v�_k����Y��gp,�k�WF�R������_C�R��N@���R�@�ߔ?A�w9���F("iNa-S���Q�o�3tDMLh*�#4k�T/iQ��Y*�G��m����)��8�hBm/�I�,g�ﯖ���Z��}�Cz�q@´��d.����L�ŕ�,��1�Z�܌�: ̪���F+J-'��c�tvJ8��]Q-��b��y �6;*J`r_�d ��'�G ~p��)'�C,�%F��E(��2�k�����lР�z�!�=t ��_�0��f7��� ;�p�|�U �%{'backup'}->{'backup_type'} ) && $ref->{'backup'}->{'backup_type'} ne 'ERROR' ) { Cpanel::Backup::Metadata::create_meta_master_with_users_from_introspect( $dir, $ref ); } else { return 0; # ignore if the directory cannot be determined } } return 1; } # Set our "nice" level sub apply_nice_level_to_process { my ($logger) = @_; my $cpconf_ref; ( %{$cpconf_ref} ) = Cpanel::Config::LoadCpConf::loadcpconf(); Cpanel::OSSys::nice(18); # needs to be one higher for cpuwatch my $CAPABILITIES = Cpanel::OSSys::Capabilities->load; if ( $CAPABILITIES->capable_of('ionice') ) { if ( Cpanel::IONice::ionice( 'best-effort', exists $cpconf_ref->{'ionice_cpbackup'} ? $cpconf_ref->{'ionice_cpbackup'} : 6 ) ) { $logger->info( "Setting I/O priority to reduce system load: " . Cpanel::IONice::get_ionice() ); } } return; } sub _run_vacuum { require Cpanel::Daemonizer::Tiny; Cpanel::Daemonizer::Tiny::run_as_daemon( sub { require Cpanel::Logger; my $logger = Cpanel::Logger->new(); sleep 15; Cpanel::Backup::Metadata::vacuum_metadata($logger); }, "" ); return; } sub _get_raw_backup_dirs { my ($backup_master_dir) = @_; # get all backup dirs under the main backup my %backup_dirs_hash; foreach my $dir ( File::Glob::bsd_glob( $backup_master_dir . "/2*/accounts" ), File::Glob::bsd_glob( $backup_master_dir . "/monthly/2*/accounts" ), File::Glob::bsd_glob( $backup_master_dir . "/weekly/2*/accounts" ), File::Glob::bsd_glob( $backup_master_dir . "/incremental/accounts" ) ) { next if ( !-d $dir ); my ( $xdir, $accounts ) = Cpanel::FileUtils::Path::dir_and_file_from_path($dir); $backup_dirs_hash{$xdir} = 1; } return %backup_dirs_hash; } sub _get_all_backup_dirs { my ( $backup_master_dir, %backup_dirs_hash ) = @_; # sort this in a smart manner so it plays out like it would have had # bin/backup done it. my @order; foreach my $dir ( sort keys %backup_dirs_hash ) { my $introspect_ref; try { $introspect_ref = Cpanel::Backup::Metadata::introspect_old_backup($dir); }; next if !$introspect_ref; # if it dies this is not a valid backup dir, so just move on next if !exists $introspect_ref->{'backup'}->{'backup_id'}; next if $introspect_ref->{'backup'}->{'backup_id'} eq 'ERROR'; my @users = keys %{ $introspect_ref->{'users'} }; next if !@users; my $user = $users[0]; my $category_ref = Cpanel::Backup::StreamFileList::categorize_backup( $backup_master_dir, $dir, $user ); my $sort_path = $category_ref->{'backupID'}; if ( $sort_path =~ m{^(monthly|weekly)/(.*)$} ) { $sort_path = $2 . '/' . $1; } else { $sort_path .= '/a'; # for sorting consistency a is before (m)onthly } $category_ref->{'sort_path'} = $sort_path; push( @order, $category_ref ); } my @dirs = map { $_->{'path'} } sort { $a->{'sort_path'} cmp $b->{'sort_path'} } @order; return @dirs; } sub fix_corrupt_metadata { my ( $backup_master_dir, @users ) = @_; # delete the users db's foreach my $user (@users) { my $user_db_path = Cpanel::Backup::Metadata::get_metadata_filename( $user, 0 ); unlink $user_db_path if -f $user_db_path; } my @dirs = _get_all_backup_dirs( $backup_master_dir, _get_raw_backup_dirs($backup_master_dir) ); foreach my $user (@users) { print "Fixing corrupt backup metadata for $user\n"; foreach my $dir (@dirs) { Cpanel::Backup::Metadata::create_metadata_for_backup_user( $dir, $user, $logger ); } } return; } sub script { ##no critic qw(ProhibitExcessComplexity) my (@args) = @_; $ENV{'LANG'} = 'en_US.UTF-8'; local $| = 1; $logger //= Cpanel::Logger->new( { 'alternate_logfile' => '/dev/stdout' } ); apply_nice_level_to_process($logger); my $opts = Getopt::Long::GetOptionsFromArray( \@args, 'all' => \$all, 'backup=s' => \$backup, 'user=s' => \$user, 'vacuum' => \$vacuum, 'schedule_rebuild' => \$schedule_rebuild, 'fix_corrupt' => \$fix_corrupt, ) or _invalid_parms(); _help("You must provide at least one option to execute the script.") if ( !$all && !$backup && !$vacuum && !$schedule_rebuild && !$user && !$fix_corrupt ); _help("You cannot combine --all with other options.") if ( $all && ( $backup || $user || $vacuum || $schedule_rebuild || $fix_corrupt ) ); _help("You cannot combine --vacuum with other options.") if ( $vacuum && ( $all || $backup || $user || $schedule_rebuild || $fix_corrupt ) ); _help("You can only combine this option with the --user option.") if ( $backup && ( $all || $schedule_rebuild || $fix_corrupt || $vacuum ) ); _help("You can only combine this option with the --backup option.") if ( $user && ( $all || $schedule_rebuild || $fix_corrupt || $vacuum ) ); _help("You can only combine this option with the --fix_corrupt option.") if ( $schedule_rebuild && ( $all || $backup || $user || $vacuum ) ); _help("You can only combine this option with the --schedule_rebuild option.") if ( $fix_corrupt && ( $all || $backup || $user || $vacuum ) ); my $conf = Cpanel::Backup::Config::load(); my $backup_master_dir = $conf->{'BACKUPDIR'}; # if --user is on the command line by itself, leverage the --all code to # process all the backups but for this user only. if ( $user && !$backup ) { $all = $backup_master_dir; } # if disabled do not do anything, unless it is all then allow the # cleanup operation to happen, but then fail Cpanel::Backup::Metadata::metadata_disabled_check(1) if ( !$all ); #We use this two places, may as well just get it now my @users; if ($user) { push( @users, $user ); } else { @users = Cpanel::Backup::Metadata::get_all_users(); } if ($all) { $all = $backup_master_dir; foreach my $this_user (@users) { my $db = Cpanel::Backup::Metadata::get_metadata_filename($this_user); unlink $db if -f $db; } my %backup_dirs_hash = _get_raw_backup_dirs($backup_master_dir); # clean old metadata foreach my $dir ( sort keys %backup_dirs_hash ) { try { clean_old_metadata_files($dir); # delete existing master meta, as it may be of an older type my $meta_master = $dir . "/accounts/.master.meta"; unlink $meta_master if -e $meta_master; } catch { $logger->warn("Failed to clean old metadata for $dir :$_:"); }; } # allow the clean up to take place regardless of disabled or not # but then fail if metadata is disabled Cpanel::Backup::Metadata::metadata_disabled_check(1); my @dirs = _get_all_backup_dirs( $backup_master_dir, %backup_dirs_hash ); foreach my $dir (@dirs) { print "Processing directory “$dir”\n"; my $ret; try { $ret = create_master_meta($dir); } catch { $logger->warn("Failed to create metadata for $dir :$_:"); }; next if !$ret; # ignore if the directory cannot be determined try { if ($user) { Cpanel::Backup::Metadata::create_metadata_for_backup_user( $dir, $user, $logger ); } else { Cpanel::Backup::Metadata::create_metadata_for_backup( $dir, $logger ); } } catch { $logger->warn("Failed to create metadata for $dir : $! ($_)"); }; } _run_vacuum(); } elsif ($backup) { $backup = $backup_master_dir . "/$backup"; my $backup_ref = Cpanel::Backup::StreamFileList::categorize_backup( $backup_master_dir, $backup, "dontcare" ); if ( $backup_ref->{'backupID'} eq "ERROR" ) { _help("backup parameter is not a valid backup"); } if ($user) { $backup_ref = Cpanel::Backup::StreamFileList::categorize_backup( $backup_master_dir, $backup, $user ); if ( $backup_ref->{'type'} eq 'unknown' ) { _help("user parameter is not a valid backup"); } try { if ( !create_master_meta($backup) ) { die "Cannot create backup"; # is caught and warned } my $master_meta = Cpanel::Backup::Metadata::load_master_meta($backup); foreach my $user_ref ( values %{ $master_meta->{'users'} } ) { next if ( $user_ref->{'user'} ne $user ); $logger->info("Processing Backup $backup for User $user"); Cpanel::Backup::Metadata::create_metadata_for_backup_user( $backup, $user_ref->{'user'}, $logger ); last; } } catch { $logger->warn("Failed to create metadata for $backup"); } } else { try { if ( !create_master_meta($backup) ) { die "Cannot create backup"; # is caught and warned } $logger->info("Processing Backup $backup"); Cpanel::Backup::Metadata::create_metadata_for_backup( $backup, $logger ); } catch { $logger->warn("Failed to create metadata for $backup"); } } _run_vacuum(); $logger->info("Processing is complete."); } elsif ($vacuum) { _run_vacuum(); } elsif ($schedule_rebuild) { if ($fix_corrupt) { print "Fixing corrupted backup metadata in the background\n"; } else { print "Creating all backup metadata in the background\n"; } # remove old metadata, and regen with new schema require Cpanel::Daemonizer::Tiny; Cpanel::Daemonizer::Tiny::run_as_daemon( sub { # Don't lose output from the script when it detaches from here and goes off on it's own open( STDERR, '>>', $Cpanel::ConfigFiles::CPANEL_ROOT . '/logs/error_log' ) or warn "Could not open cPanel Error Log: $!"; open( STDOUT, '>>', $Cpanel::ConfigFiles::CPANEL_ROOT . '/logs/error_log' ) or warn "Could not open cPanel Error Log: $!"; if ($fix_corrupt) { Cpanel::SafeRun::Simple::saferun( '/usr/local/cpanel/scripts/backups_create_metadata', '--fix_corrupt' ); } else { Cpanel::SafeRun::Simple::saferun( '/usr/local/cpanel/scripts/backups_create_metadata', '--all' ); } }, "" ); } elsif ($fix_corrupt) { my ( $dbs_valid, $broken_users_ar ) = Cpanel::Backup::Metadata::is_database_valid( \@users ); if ($dbs_valid) { print "No user metadata is corrupt\n"; } else { try { fix_corrupt_metadata( $backup_master_dir, keys %{$broken_users_ar} ); } catch { print "Error fixing corrupt backup metadata: $_\n"; }; } } return 1; } exit( script(@ARGV) ? 0 : 1 ) unless caller();