#! /usr/bin/perl -w

# $Id: fwsm-backup,v 1.8 2011/01/06 15:09:13 root Exp $

# fwsm-backup 0.2 - Laurent FACQ 3/12/2010 - laurent.facq@univ-bordeaux.fr - 

# Quick and Dirty Tool to backup all FWSM configuration (all contexts)

# 0.2 : take "snapshot" of running configs (even if not wrote to mem) in case...

use Expect; # aptitude install libexpect-perl

$usr= 	'backup-account';      # backup account on FWSM
$pswd= 	'backup-password-account';   # password of backup account on FWSM

$ena = 'anable-password';    # enable password of FWSM  TODO faire un compte local super user juste pour les commandes necessaire a la savegarde
$fwsm= "fwsm-ip-or-hostname"; # FWSM IP or Hostname
$destdir= "destination-directory"; # where to keep backups

# command to run before backup (ex: versioning with RCS)
$precmd= "rcs -q -l $destdir/* ";
# command to run after all (ex: versioning with RCS)
$postcmd= "rcs -i -mauto $destdir/* ; ci -q -u -mauto -t-auto $destdir/* ";

$ssh_cmd= "/usr/bin/ssh";
$scp_cmd= "/usr/bin/scp";
@params= ("$usr\@$fwsm");
$timeout= 5;

# name of the system context backup file
$system_backup_filename= "backup-system-config";

$debug= 0;
#########################################################################

mkdir($destdir); mkdir("$destdir/RCS");

# create an Expect object by spawning another process
my $exp = Expect->spawn($ssh_cmd,@params)
    or die "Cannot spawn $ssh_cmd: $!\n";

#$exp->slave->stty(qw(raw -echo));

#### ssh password
# then do some pattern matching with either the simple interface
@patterns= ('password:','yes/no');
$patidx = $exp->expect($timeout, ('password:','yes/no'));

if ($patidx==1)
{		
# send some string there:
    $exp->send("$pswd\n");
}
else
{
    erreure("pb pattern non souhaite - $patidx $patterns[$patidx-1]\n");
    exit 1;
}

expect_prompt_or_die($exp, $timeout);

$exp->send("enable\n"); $patidx = $exp->expect($timeout, ('assword:'));

$exp->send("$ena\n"); expect_prompt_or_die($exp, $timeout);

$exp->send("change system\n"); expect_prompt_or_die($exp, $timeout);

$exp->send("copy /noconfirm running-config disk:/$system_backup_filename\n"); expect_prompt_or_die($exp, $timeout);

$exp->send("show context\n"); expect_prompt_or_die($exp, $timeout);

$result= $exp->exp_before(); $ok= 0;
@lines= split('\r\n', $result);
foreach $line (@lines)
{
    if ($line =~ m/Context\s+Name\s+Class\s+Interfaces\s+Mode\s+URL/)
    {
	$ok= 1;
	next;
    }
    
    if ($ok && ($line =~ m/Routed|Transparent/))
    {
	chomp($line);
	# remove first char (space or star)
	$line = substr($line,1);
	($name,$class,$interfaces,$mode,$url)= split('\s+',$line);
	
	if ($debug) { print "\n--$name--$line\n"; }
	
	$contexts{$name}{CLASS}= $class;
	$contexts{$name}{INTERFACES}= $interfaces;
	$contexts{$name}{MODE}= $mode;
	$contexts{$name}{CLASS}= $class;
	$contexts{$name}{URL}= $url;
    }
}


@filestoget= ( $system_backup_filename );

foreach $name ( keys %contexts )
{
    if ($debug) { print "** $name :"; }
    foreach $a ( keys %{$contexts{$name}} )
    {
	if ($debug) { print " $a=$contexts{$name}{$a}"; }
	
    }
    
    $url= $contexts{$name}{URL};

    if ($url =~ m/^disk:/) 
    { 
	($file= $url) =~ s|disk:/||;

	push @filestoget, $file;
	push @filestoget, "snapshot-$file";

	$exp->send("changeto context $name\n"); expect_prompt_or_die($exp, $timeout);
	$exp->send("copy /noconfirm running-config snapshot-$file\n"); expect_prompt_or_die($exp, $timeout);
    }

    if ($debug) { print "\n"; }
}

if (!$ok) { erreure ("erreure dans la recuperation du show context\n"); }

$exp->send("exit\n"); $exp->hard_close();

$contexts{"system"}{URL}= "disk:/$system_backup_filename";


###### SCP pour recuperer

system("$precmd");

foreach $file ( @filestoget )
{
    if ($debug) { print "DEBUG : $scp_cmd $usr\@$fwsm:$file $destdir\n"; }
    my $exp = Expect->spawn($scp_cmd,"$usr\@$fwsm:$file",$destdir) or die "Cannot spawn $scp_cmd: $!\n";
    @patterns= ('password:','yes/no');
    $patidx = $exp->expect($timeout, ('password:','yes/no'));
    
    if ($patidx==1)
    {		
	# send some string there:
	$exp->send("$pswd\n");
    }
    else
    {
	erreure("pb pattern non souhaite - backup $name ($file) $patidx $patterns[$patidx-1]\n");
	exit 1;
    }
    $exp->soft_close();
}

system("$postcmd");

################## THE END !

sub expect_prompt_or_die   # $exp $timeout 
{
    my ($exp,$timeout)= @_;
    
    if ($exp->expect($timeout, ('> ','# ')))
    {
	return 1;
    }
    else 
    {
	erreure("pb prompt non rendu - $e - $timeout\n");
	exit 1;
    }
	
}

sub expect_questionmark_confirm_or_die   # $exp $timeout 
{
    my ($exp,$timeout)= @_;
    
    if ($exp->expect($timeout, ('? ','confirm')))
    {
	return 1;
    }
    else 
    {
	erreure("pb prompt non rendu - $e - $timeout\n");
	exit 1;
    }
	
}
    

sub erreure
{
    print STDERR $_[0];
}

