#!/usr/local/cpanel/3rdparty/bin/perl

#                                      Copyright 2026 WebPros International, LLC
#                                                            All rights reserved.
# copyright@cpanel.net                                          http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited.

package scripts::comet_account_capture_refresh;

use cPstrict;

use Getopt::Long qw(GetOptions);
use Pod::Usage   qw(pod2usage);
use Cpanel::Logger;
use Cpanel::Debug ();

use Fcntl qw( :flock O_CREAT O_RDWR );

use Whostmgr::CometBackup::AccountCapture ();

my $LOCK_FILE = '/var/run/comet_account_capture_refresh.lock';

my $logger = Cpanel::Logger->new();

=encoding utf-8

=head1 NAME

comet_account_capture_refresh - Nightly full refresh of per-account Comet
capture artifacts (the account manifest).

=head1 SYNOPSIS

    comet_account_capture_refresh [options]

    Options:
      --help, -h       Show this help
      --verbose, -v    Verbose logging
      --debug, -d      Enable debug logging

=head1 DESCRIPTION

Iterates every account this plugin backs up (the union of accounts across all
active backup jobs) and refreshes each account's manifest and secret artifact
by driving L<Whostmgr::CometBackup::AccountCapture/refresh_all_backed_up_accounts>.
Designed to be run once nightly from cron alongside the account-lifecycle hooks
(L<Whostmgr::CometBackup::Hooks::AccountCapture>), which keep artifacts current
between sweeps.

The sweep is failure-isolated per account: one account's failure is logged and
the sweep continues. An C<flock> prevents overlapping runs.

=cut

sub main {

    # Plugin policy: nothing in this process should be world-readable. The
    # secret artifact is written 0600 by the exporter, but keep the whole
    # process defensive.
    umask 0027;

    my ( $help, $verbose, $debug );

    GetOptions(
        'help|h'    => \$help,
        'verbose|v' => \$verbose,
        'debug|d'   => \$debug,
    ) or pod2usage(2);

    pod2usage(1) if $help;

    if ($debug) {
        $Cpanel::Debug::level = 1;
    }

    # Single-instance guard, held for the life of this process.
    #
    # An flock rather than an existence check (review suggestion, PR #2556): the
    # previous exists() / unlink / create() sequence was a TOCTOU. Two invocations
    # could both decide the same lock file was stale, and the second would unlink
    # the lock the first had just created and take its own -- so both sweeps ran,
    # which is exactly what the guard exists to prevent. There is also no stale lock
    # to reclaim with an flock: the kernel drops it when the holder exits, however
    # it exits, so the "previous process died without cleaning up" branch that made
    # the race necessary is gone rather than fixed.
    #
    # The lock FILE is deliberately never unlinked -- unlinking is what reintroduces
    # the race. A 0-byte file under /var/run is the normal cost of an flock guard.
    my $lock_fh;
    unless ( sysopen( $lock_fh, $LOCK_FILE, O_CREAT | O_RDWR, 0600 ) ) {
        $logger->error("Failed to open lock file $LOCK_FILE: $!; cannot proceed.");
        exit 1;    ## no critic (Cpanel::NoExitsFromSubroutines)
    }

    unless ( flock( $lock_fh, LOCK_EX | LOCK_NB ) ) {
        $logger->info('Another comet_account_capture_refresh is already running; exiting.');
        exit 0;
    }

    $logger->info("Starting nightly Comet account capture refresh") if $verbose;

    my $summary = eval { Whostmgr::CometBackup::AccountCapture::refresh_all_backed_up_accounts() };
    my $run_err = $@;

    if ($run_err) {
        chomp $run_err;
        $logger->error("Error in comet_account_capture_refresh: $run_err");
        exit 1;
    }

    if ( $verbose && ref $summary eq 'HASH' ) {
        $logger->info( "Comet account capture refresh complete: " . "total=$summary->{total} refreshed=$summary->{refreshed} failed=$summary->{failed}" );
    }

    return;
}

# Run the main function if this script is executed directly.
main() if !caller;

1;

__END__

=head1 SEE ALSO

L<Whostmgr::CometBackup::AccountCapture>,
L<Whostmgr::CometBackup::Hooks::AccountCapture>,
L<Whostmgr::CometBackup::AccountManifestExporter>

=head1 AUTHOR

WebPros International, LLC

=head1 COPYRIGHT

Copyright 2026 WebPros International, LLC. All rights reserved.

=cut
