#!/usr/bin/perl
$| = 1;

use Getopt::Std;

# Parse our command line options
our ($opt_f);
getopts('f');

use strict;
my $AT     = 0;
my $tree   = $ARGV[0];
my $unlink = $ARGV[1];
use Sys::Hostname ();
my $hostname = Sys::Hostname::hostname();

my $hastar = 0;
eval {
    require Archive::Tar;
    import Archive::Tar;
    $hastar = 1;
};
if ( !$hastar ) {
    if ( $> != 0 ) { die 'Unable install Archive::Tar on ' . $hostname; }
    if ( !-e '/scripts/perlinstaller' ) {
        system( 'rsync', '-av', 'rsync://rsync.cpanel.net/scripts', '/scripts' );
        system( '/scripts/updatenow', '--fromupcp' );
    }
    system( '/scripts/perlinstaller', '--force', 'Archive::Tar' );
}

eval {
    require Archive::Tar;
    import Archive::Tar;
    $hastar = 1;
};
if ( !$hastar ) { die 'Archive::Tar Missing on ' . $hostname; }

use POSIX;

mkdir( '/home/cpanel/pids', 0700 );
my $xpid;
if ( -e "/home/cpanel/pids/cpanelsync2bzip.${tree}.pid"
    && ( ( stat("/var/log/cpanelsync2bzip.${tree}.pid") )[9] + 1000 ) > time() ) {
    open( CP, "<", "/home/cpanel/pids/cpanelsync2bzip.${tree}.pid" );
    $xpid = <CP>;
    chomp($xpid);
    close(CP);
}
if ( $xpid ne '' ) {
    kill( 9, $xpid );
}

my $pid;
if ( !$opt_f && ( $pid = fork() ) ) {
    open( CP, '>', "/home/cpanel/pids/cpanelsync2bzip.${tree}.pid" )
      || warn "Could not write pid file on $hostname: $!";
    print CP $pid;
    close(CP);
    print "[$hostname] Background archive build for $tree started in background with pid ${pid}\n";

}
else {
    open( STDOUT, ">", "/home/cpanel/cpanelsync/util/logs/cpanelsync_build_bzip2_$tree" )
      || die "Could not open /home/cpanel/cpanelsync/util/logs/cpanelsync_build_bzip2_$tree\n";
    open( STDERR, ">&STDOUT" );
    open( STDIN, "<", "/dev/null" );
    POSIX::setsid();

    opendir( CPD, '/home/cpanel/cpanelsync/' . $tree );
    while ( my $path = readdir(CPD) ) {
        cps( '/home/cpanel/cpanelsync/' . $tree . '/' . $path );

    }
    closedir(CPS);
    cps( '/home/cpanel/cpanelsync/' . $tree . '/base/3rdparty' );

    sub cps {
        my $path = shift;
        return if ( $path eq '.' );
        my @rp   = split( /\//, $path );
        my $dir  = pop(@rp);
        my $rdir = join( '/', @rp );
        chdir($rdir);

        if ( -e $path . '/.cpanelsync' ) {
            print "[$hostname] building ${dir}\n";

            my $tarball = $rdir . '/' . $dir . '.tar';
            if ( $dir eq '.' || $unlink eq "--unlink" ) {
                unlink($tarball);
                unlink( $tarball . '.bz2' );
                unlink "/home/cpanel/pids/cpanelsync2bzip.${tree}.pid";
                return;
            }
            my @f;
            my @symlinks;
            my $tar;

            open( CPS, '<', $path . '/.cpanelsync' );
            if ($AT) { $tar = new Archive::Tar; }
            while (<CPS>) {
                chomp();
                my ( $ftype, $rfile, $perm, $extra ) = split( /===/, $_ );
                my $tfile = $rfile;
                $tfile =~ s/^\./$dir/g;
                $tfile =~ s/\s/\\ /g;
                next if ( $tfile eq '' );
                if ( $ftype eq 'f' ) {
                    if ($AT) {
                        $tar->add_files($tfile);
                    }
                    else {
                        push @f, $tfile;
                    }
                }
                elsif ( $ftype eq 'l' ) {
                    if ($AT) {
                        my $obj = Archive::Tar::File->new( file => $tfile );
                        if ( !$obj ) {
                            print STDERR " Error while adding $tfile on $hostname \n";
                        }
                        else {
                            push @{ $tar->{_data} }, $obj;
                        }
                    }
                    else {
                        push @f, $tfile;
                    }

                    #push(@symlinks,$tfile);
                }
            }
            if ($AT) {
                $tar->write($tarball);
                $tar->clear;
            }
            else {

                # Tar can break when large file lists are passed on the command line
                if ( scalar(@f) > 1000 ) {

                    # Tar up files in 1000 file chunks
                    system( 'nice', '-n', '19', 'tar', 'cf', $tarball, shift @f );

                    # Append the rest of the files to the archive using xargs
                    open TAR, "| xargs -n1000 nice -n 19 tar rf $tarball";
                    foreach my $file (@f) {
                        print TAR "$file\n";
                    }
                    close TAR;
                    print "Zipping up: $tarball\n";
                    system( 'nice', '-n', '19', '/usr/bin/bzip2', '-f', $tarball );
                }
                else {
                    system( 'nice', '-n', '19', 'tar', 'cjf', $tarball . '.bz2', @f );
                }

            }

            #if ($#symlinks > -1) {
            #   system 'tar','-rf',$tarball,@symlinks;
            #}
            if ($AT) {
                if ( $tree eq 'RELEASE' ) {
                    system( "pbzip2", "-9", "-f", $tarball );
                }
                else {
                    system( "pbzip2", "-1", "-f", $tarball );
                }
            }
            unlink "/home/cpanel/pids/cpanelsync2bzip.${tree}.pid";
            print "[$hostname] built ${tarball}.bz2\n";
            close(CPS);
        }
    }
}
