#!/usr/bin/perl -wT use strict; use File::Temp qw/ tempfile tempdir /; use Time::Local 'timelocal_nocheck'; use File::Basename; use Getopt::Std; $ENV{PATH} = '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin'; my @servers = (); my %timestamp; my $tmp_dir = tempdir( CLEANUP => 1 ); my $verbose = 0; my $allowed_time_span = 0; sub get_timestamp($) { my $server = shift; if ( $server =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/ ) { $server = $1; } else { warn "$server is not valid IP addr.\n"; return -1; } system "rsync", "-q", "rsync://$server/gentoo-portage/metadata/timestamp.chk", $tmp_dir; if ( $? == -1 ) { warn "failed to execute: $!\n"; return -1; } elsif ( $? & 127 ) { printf STDERR "rsync died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without'; return -1; } elsif ( $? != 0 ) { printf STDERR "rsync exited with value %d\n", $? >> 8; return -1; } open my $timestamp_fd, "<", "$tmp_dir/timestamp.chk" or die "cannot open tmp file: $tmp_dir/timestamp.chk"; # Wed, 29 Mar 2006 20:20:01 +0000 my $line; while ( <$timestamp_fd> ) { chomp; if ( $. > 1 ) { warn "malformed timestamp.chk on $server: more than one line read\n"; return -1; } $line = $_; } close $timestamp_fd; warn "\$line = $line\n" if $verbose; my (undef, $mday, $mon, $year, $hhmmss, undef) = split /\s+/, $line; my ($hour, $min, $sec) = split /:/, $hhmmss; my $unixtime = timelocal_nocheck( $sec, $min, $hour, $mday, month2num($mon), $year ); warn "unix time = $unixtime\n" if $verbose; warn "localtime = ", scalar localtime $unixtime, "\n" if $verbose; return scalar $unixtime; } sub month2num($) { my $month = shift; my %m = ( Jan => 1, Feb => 2, Mar => 3, Apr => 4, May => 5, Jun => 6, Jul => 7, Aug => 8, Sep => 9, Oct => 10, Nov => 11, Dec => 12 ); return $m{$month} - 1; } sub usage() { my $myname = basename $0; print STDERR "$myname [ -v ] [ -t sec ] server1 [ server2 ... ]\n"; print STDERR "$myname -h show this help\n"; print STDERR "-t num\n"; print STDERR " a server is allowed to be num sec late. (86400)\n"; print STDERR "-v\n"; print STDERR " be verbose"; return } sub HELP_MESSAGE() { usage(); exit -1; } our ($opt_v, $opt_h, $opt_t); getopts('vht:'); if ( $opt_h ) { usage(); exit -1 } $verbose = $opt_v || 0; $allowed_time_span = $opt_t || 86400; warn "\$allowed_time_span = $allowed_time_span sec\n" if $verbose; warn "\$tmp_dir = $tmp_dir\n" if $verbose; @servers = @ARGV; if ( $#servers < 0 ) { warn "no server to check\n"; usage(); exit -1; } for my $server ( @servers ) { my (undef, undef, undef, undef, @ips ) = gethostbyname $server; foreach my $ip ( @ips ) { $ip = join '.', unpack 'C4', $ip; warn "checking $ip ...\n" if $verbose; $timestamp{$ip} = get_timestamp($ip); warn "$ip ==> ", $timestamp{$ip}, "\n" if $verbose; } } my @ips_sort_by_time = sort { $timestamp{$b} <=> $timestamp{$a} } keys %timestamp; my $latest_timestamp = $timestamp{$ips_sort_by_time[0]}; warn "\$latest_timestamp = $latest_timestamp\n" if $verbose; my $oldest_timestamp = $timestamp{$ips_sort_by_time[$#ips_sort_by_time]}; warn "\$oldest_timestamp = $oldest_timestamp\n" if $verbose; if ( $verbose ) { foreach my $ip ( @ips_sort_by_time ) { my $diff; if ( $timestamp{$ip} > 0 ) { $diff = $latest_timestamp - $timestamp{$ip}; printf "%-15s ==> %s\n", $ip, $diff ? "$diff sec late" : "the latest"; } else { printf "%-15s ==> %s\n", $ip, "*failed*"; } } } if ( $oldest_timestamp < 0 ) { print STDERR "failed server found:"; foreach my $ip ( keys %timestamp ) { print STDERR " $ip" if $timestamp{$ip} < 0; } print STDERR "\n"; exit 1; } elsif ( $latest_timestamp - $oldest_timestamp > $allowed_time_span ) { warn "too old server found: ", $ips_sort_by_time[$#ips_sort_by_time], " is ", $latest_timestamp - $oldest_timestamp, " sec late.\n"; exit 1; } exit 0;