#!/usr/bin/perl -T
# $Id: rsync_fedora_core.pl,v 1.35 2009/07/24 18:16:03 root Exp $
#
# This script rsyncs the Fedora (addon packages for RedHat) mirror
# See www.fedora.us and the mirror-list-d@fedora.us mailing list
#
# This script *should* be safe to run setuid if needed.
#

use Fcntl qw(:DEFAULT :flock);
use FileHandle;
use LWP::Simple;
use File::Temp qw/ tempfile tempdir /;

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

#
# Select umask and log file
#
$umask = 002;
$log_file = '/var/log/mirror/fedora';

#
# Exclude list
#
#@excludes = ('/extras/', '/development/', '/core/development/',
#	     'index.html', '.htaccess');
@excludes = ('/lastsync');

#
# Real location
#
$real_path    = '/home/mirrors/fedora-enchilada/';
$temp_path    = '/home/temp-rsync-dump/fedora/';

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

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

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

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

    $from_host   = 'sync.fedoraproject.org';
    $from_fedora = "rsync://$from_host/fedora-enchilada0/";

    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-dir='. $temp_dir, 
		 '--partial', @exclude_list, @ARGV,
		 $from_fedora, $real_path);

    print "Return Value: ". $rv ."\n";

    my ($sec, $min, $hour, $month_day, $month, $year, $week_day, $year_day, $isdst) = localtime(time());
    open FH, ">$real_path/lastsync";
    if ( $week_day != 1 || ( $week_day == 1 && $hour > 12 ) ){
	print FH "$currentsynctime";
    }
    close FH;

    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;