#!/usr/bin/perl -T
# $Id: rsync_centos.pl,v 1.2 2006/05/04 00:40:43 hpa Exp $
#
# This script rsyncs the Centos mirror
# See http://www.centos.org/modules/tinycontent/index.php?id=22
# and the http://lists.centos.org/mailman/listinfo/CentOS-mirror
# mailing list
#
# This script *should* be safe to run setuid if needed.
#

use Fcntl qw(:DEFAULT :flock);
use FileHandle;

#
# Environment variables.  The PATH should include rsync.
#
$ENV{'PATH'}           = '/bin:/usr/bin';
#$ENV{'RSYNC_PASSWORD'} = 'xxx';

#
# Select umask and log file
#
$umask = 002;
$name = 'centos';
$log_file = "/var/log/mirror/$name";

#
# Exclude list
#
@excludes = ('index.html', '.htaccess');

#
# Real location
#
$real_path    = '/mirrors/centos';

# 
# This program requires write access to two lock files.
#
$lock_file_1 = "/var/lock/mirror/LOCK-rsync-$name";
$lock_file_2 = "/var/lock/mirror/LOCK-rsync-$name:crit";

sub drain_input() {
    my($drain);
    while( read(STDIN,$drain,65536) ) { }
}

sub do_rsync() {
    my(@exclude_list, $ex, $rv);

    @exclude_list = ();
    foreach $ex (@excludes) {
	push(@exclude_list, '--exclude', $ex);
    }

    $from_host = 'msync-dvd.centos.org';
    $from_url  = "rsync://$from_host/CentOS-incdvd/";

    print "\n--- BEGIN RSYNC ---\n";
    print `date`, "\n";

    # 12 hour IO timeout (for building the file list)
    $rv = system('rsync', '-avH', '--stats', '--delete',
		 '--delete-after',
                 '--timeout=43200',
		 '--numeric-ids',
		 '--partial', @exclude_list, @ARGV,
		 $from_url, $real_path);

    print "\n--- END RSYNC ---\n";
    print `date`, "\n";
}

#
# Avoid sender getting SIGPIPE
#
if ( -p STDIN ) {
    drain_input();
}

#
# Set umask, and redirect output to a log file
#
umask($umask);
open(LOGFILE, ">> $log_file") or open(LOGFILE, ">> /dev/null");
select LOGFILE;  $| = 1;	# Make unbuffered
close(STDOUT);
close(STDERR);
open(STDERR, ">>&LOGFILE");
select STDERR;  $| = 1;
open(STDOUT, ">>&LOGFILE");
select STDOUT;  $| = 1;

#
# Enter critical section
#
open(CRITICAL, "> $lock_file_2") || die "$0: Cannot open lock file $lock_file_2\n";
if ( flock(CRITICAL, LOCK_EX) == -1 ) {
    die "$0: Cannot lock $lock_file_2\n";
}

#
# Check to see if someone else is already doing this
#
open(ROCK, "+> $lock_file_1") || die "$0: Cannot open lock file $lock_file_1\n";
autoflush ROCK 1;
if ( !flock(ROCK, LOCK_EX|LOCK_NB) ) {
    #
    # rsync process already active.  Mark that they have
    # to start over.
    #
    seek ROCK, 0, 0;
    print ROCK "1\n";
    flock(ROCK, LOCK_UN);
    close(ROCK);
    flock(CRITICAL, LOCK_UN);
    close(CRITICAL);
    exit 0;
}
    
#
# No other rsync process.  We're "it".  Note check at end if another
# poll request came in.
#
do
{
    seek ROCK, 0, 0;
    print ROCK "0\n";
    flock(CRITICAL, LOCK_UN); # Drop critical section lock

    do_rsync();

    flock(CRITICAL, LOCK_EX); # Get critical section lock
    seek ROCK, 0, 0;
    $flag = scalar <ROCK>;
    chomp $flag;
} while ( $flag );
    
close(ROCK);
flock(CRITICAL, LOCK_UN);
close(CRITICAL);

exit 0;
