%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /scripts/
Upload File :
Create Path :
Current File : //scripts/rdate

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

# cpanel - scripts/rdate                           Copyright 2022 cPanel, L.L.C.
#                                                           All rights reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

package rdate;

use cPstrict;

use Cpanel::Unix::PID::Tiny ();
use Cpanel::SafeRun::Simple ();
use Getopt::Long            ();
use Cpanel::OS              ();
use Cpanel::OSSys::Env      ();
use Cpanel::Binaries        ();

use Socket;

my $timeout = 10;

exit( _run_alarmed( $timeout, @ARGV ) // 0 ) unless caller;

sub run (@args) {

    my $print_time;    # used to map usage to rdate's -p option
    my $help;

    Getopt::Long::GetOptionsFromArray(
        \@args,
        '-p|print' => \$print_time,
        '-h|help'  => \$help,
    ) or return usage(1);

    return usage(0) if $help;

    my $envtype = Cpanel::OSSys::Env::get_envtype();

    # Case 48348 -- Virtual environments cannot set the system time so do nothing.
    if ( $envtype =~ qr{^(?:virtuozzo|cpanel-vserver|vzcontainer)$} ) {
        say "Container environment detected - rdate skipped";
        return;
    }

    my $pid = 0;

    my $check_ntpd_pid_method = Cpanel::OS::check_ntpd_pid_method();

    if ( $check_ntpd_pid_method eq 'systemd_ntpd' ) {
        $pid = _detect_systemd_managed_ntpd();
    }
    elsif ( $check_ntpd_pid_method eq 'pid_check_var_run_ntpd' ) {
        my $upid = Cpanel::Unix::PID::Tiny->new();
        $pid = $upid->is_pidfile_running('/var/run/ntpd.pid');
    }
    else {
        die qq[Unknown check_ntpd_pid_method method: $check_ntpd_pid_method];
    }

    if ($pid) {
        say "The 'ntpd' daemon is running on PID '$pid'. Exiting.";
    }
    else {
        my %rdate_opts = ( 'set_time' => 1 );
        $rdate_opts{'print_time'} = 1 if $print_time;
        $rdate_opts{'server'}     = 'rdate.cpanel.net';
        exec_rdate(%rdate_opts);
    }

    return;
}

sub exec_rdate (%opts) {

    my $server     = $opts{'server'} || 'rdate.cpanel.net';
    my $port       = $opts{'port'} // 37;
    my $rdate_mode = $opts{'mode'} // 1;    # act like the binary unless otherwise requested

    my $socket = _create_socket( $server, $port );

    my $time_data;
    recv( $socket, $time_data, 4, 0 );
    close($socket);

    # Make sure we actually got some data back
    if ( !$time_data ) {
        print "Server returned empty data, please try a different server.\n";
        return;
    }

    # Take the binary data we get from the time server, convert to hex, sprintf to decimal then
    # subtract the number of seconds from Jan 1st 1900 to 1970 ( 2208988800 ) to get our epoch, es defined in RFC868

    my $epoch = unpack( "N*", $time_data ) - 2208988800;

    if ( $opts{'print_time'} || ( !$opts{'set_time'} ) ) {
        print "rdate: [$server]\t" . scalar localtime($epoch) . "\n" if $rdate_mode == 1;
    }

    if ( $opts{'set_time'} ) {
        set_system_time( $epoch, $rdate_mode );
    }
    return $epoch;
}

# split out for mocking purposes
sub _create_socket ( $server, $port ) {
    my $socket;
    socket( $socket, PF_INET, SOCK_STREAM, ( getprotobyname('tcp') )[2] ) or die "Can't open socket $!\n";
    binmode($socket);
    connect( $socket, pack_sockaddr_in( $port, inet_aton($server) ) ) or die "Can't connect to $server:$port $! \n";

    return $socket;
}

sub set_system_time {
    my ( $epoch, $rdate_mode ) = @_;

    # We only want to allow for a 10 digit number, anything else is nonsensical here
    if ( $epoch !~ m/^\d{10}$/ ) {
        die "Invalid epoch given to set_system_time.\n";
    }

    # Find date binary on CentOS 6 and 7+
    my $date_bin_path = Cpanel::Binaries::path('date');
    my $output        = Cpanel::SafeRun::Simple::saferunnoerror( $date_bin_path, '-s', "\@$epoch" );
    chomp $output;

    # mimic binary rdate behavior
    print "Set system time to “$output”\n" if !$rdate_mode;
    return;
}

sub _detect_systemd_managed_ntpd() {

    my $output = Cpanel::SafeRun::Simple::saferunallerrors( '/usr/bin/systemctl', 'status', 'ntpd' );
    if ( $output =~ m/Active:\sactive\s+\(running\)/a && $output =~ m/Main\s+PID:\s+(\d+)\s+\(/a ) {
        return $1;
    }

    return;
}

sub _run_alarmed {

    my ( $timeout, @args ) = @_;
    {
        require Cpanel::Alarm;
        my $alrm = Cpanel::Alarm->new( $timeout, sub { die "Failed to run due to the $timeout second timeout being exceeded.\n" } );
        run(@args);
    }
    return;
}

sub usage ($status) {
    $status //= 0;

    print <<EOS;
scripts/rdate

On servers without ntp daemon, use 'rdate' to adjust the system clock.

Options:
    --help  [-h] display this help
    --print [-p] Print the time returned by the remote machine.

Usage:
    scripts/rdate
    scripts/rdate -p

EOS

    return $status;
}

Zerion Mini Shell 1.0