#!/usr/bin/perl

use strict;
use warnings;

our $VERSION = 3.1;

=head1 NAME

restore_config - 

=head1 DESCRIPTION

TBD

=cut

use Data::Dumper;
use Config::General;
use File::Find;
use File::Compare;
use Params::Validate qw(:all);
use Archive::Tar;
use File::Temp qw(tempfile);
use File::Path qw(mkpath);

use FindBin qw($RealBin);

use lib "$RealBin/../lib";

use perfSONAR_PS::NPToolkit::BackingStore::Config qw(parse_config);
use perfSONAR_PS::NPToolkit::BackingStore::Utils  qw(load_original_cd mount_data_store);

my $CONF_FILE = "$RealBin/../etc/backingstore.conf";
my $CONF_DIRECTORY = "$RealBin/../etc/backingstore.conf.d";

my $data_store_location;
my $data_store_device;
my $data_store_version;
my $original_cd_location;

my ($status, $res);

($status, $res) = parse_config({ base_config_file => $CONF_FILE, config_directory => $CONF_DIRECTORY });
if ($status != 0) {
    print "Problem parsing configuration: $res";
    exit -1;
}

my $conf = $res;

($status, $res) = load_original_cd();
if ($status != 0) {
    print "Problem loading original CD: $res";
    exit -1;
}

$original_cd_location = $res->{directory};

($status, $res) = mount_data_store();
if ($status != 0) {
    print "Couldn't find data store: $res";
    exit -1;
}

$data_store_location = $res->{directory};
$data_store_device   = $res->{device};
$data_store_version  = $res->{version};
$data_store_version  = "" unless ($data_store_version);

# Run any pre-restore scripts 
if ($conf->{restore_pre_run}) {
    $conf->{restore_pre_run} = [ $conf->{restore_pre_run} ] unless (ref $conf->{restore_pre_run});

    foreach my $script (@{ $conf->{restore_pre_run} }) {
        my @cmd = ();

        push @cmd, $script;
        push @cmd, ("-v", $data_store_version);
        push @cmd, ("-s", $data_store_location);
        push @cmd, ("-c", $original_cd_location);

        my $status = system(@cmd);
        if ($status != 0) {
            my $exit_value  = $? >> 8;
            my $signal_num  = $? & 127;
            my $dumped_core = $? & 128;

            print "Problem executing: ".join(",", @cmd).": ".$exit_value."\n";
        }
    }
}

# bind mount the given directories on the backing store over the original. If
# the directory already exists on the ISO, copy its contents over. If not, just
# make the directory.
if ($conf->{store}) {
    $conf->{store} = [ $conf->{store} ] unless (ref $conf->{store});

    foreach my $directory (@{ $conf->{store} }) {
        if (-d $data_store_location."/NPTools/".$directory) {
            # do nothing since the directory already exists
        }
        elsif (-d $original_cd_location."/".$directory) {
            my ($fh, $filename) = tempfile;

            close(*$fh);

            $Archive::Tar::DEBUG = 1;

            # Tar up the directory from the original location
            chdir($original_cd_location);
            my @file_list = ();
            find({ wanted => sub { push @file_list, $File::Find::name }, no_chdir => 1 }, ".".$directory);
            Archive::Tar->create_archive($filename, "", @file_list);

            # Untar is under the new location
            #chdir($data_store_location."/NPTools");

            # XXX: Archive::Tar isn't preserving ownership of directories when
            # it untars so we have to use the tar command manually.
            #Archive::Tar->extract_archive($filename);
            `/bin/tar -x -C $data_store_location/NPTools -f $filename`;

            unlink($filename);
        }
        else {
            # make an empty directory if it doesn't already exist on the CD
            my $error;

            mkpath($data_store_location."/NPTools/".$directory, { error => \$error });
            if ($error) {
                # XXX: complain
            }
        }

        unless (-d "/".$directory) {
            my $error;

            mkpath("/".$directory, { error => \$error });
        }

        my @cmd = ();
        push @cmd, "mount";
        push @cmd, "--bind";
        push @cmd, $data_store_location."/NPTools/".$directory;
        push @cmd, "/".$directory;

        my $status = system(@cmd);
        if ($status != 0) {
            my $exit_value  = $? >> 8;
            my $signal_num  = $? & 127;
            my $dumped_core = $? & 128;

            print "Problem executing: ".join(",", @cmd).": ".$exit_value."\n";
        }
    }
}

if (-e $data_store_location."/NPTools/".$conf->{configuration_tarball}) {
    # Untar is under the new location
    chdir("/");
    Archive::Tar->extract_archive($data_store_location."/NPTools/".$conf->{configuration_tarball});
}

# Run any post-restore scripts 
if ($conf->{restore_post_run}) {
    $conf->{restore_post_run} = [ $conf->{restore_post_run} ] unless (ref $conf->{restore_post_run});

    foreach my $script (@{ $conf->{restore_post_run} }) {
        my @cmd = ();

        push @cmd, $script;
        push @cmd, ("-v", $data_store_version);
        push @cmd, ("-s", $data_store_location);
        push @cmd, ("-c", $original_cd_location);

        my $status = system(@cmd);
        if ($status != 0) {
            my $exit_value  = $? >> 8;
            my $signal_num  = $? & 127;
            my $dumped_core = $? & 128;

            print "Problem executing: ".join(",", @cmd).": ".$exit_value."\n";
        }
    }
}

exit 0;

__END__

=head1 SEE ALSO

L<Config::General>, L<FindBin>

To join the 'perfSONAR Users' mailing list, please visit:

  https://mail.internet2.edu/wws/info/perfsonar-user

The perfSONAR-PS subversion repository is located at:

  http://anonsvn.internet2.edu/svn/perfSONAR-PS/trunk

Questions and comments can be directed to the author, or the mailing list.
Bugs, feature requests, and improvements can be directed here:

  http://code.google.com/p/perfsonar-ps/issues/list

=head1 VERSION

$Id$

=head1 AUTHOR

Aaron Brown, aaron@internet2.edu

=head1 LICENSE

You should have received a copy of the Internet2 Intellectual Property Framework
along with this software.  If not, see
<http://www.internet2.edu/membership/ip.html>

=head1 COPYRIGHT

Copyright (c) 2004-2010, Internet2 and the University of Delaware

All rights reserved.

=cut
