Backups Blow - BackupsBlow/Transport/Ftp.pm
#!/usr/bin/perl -w
# Backups Blow by Brandon Low 
#
# Copyright 2007 Brandon Low 
# Released under the terms of the GPL v2
#
# http://lostlogicx.com/backupsblow/

package BackupsBlow::Transport::Ftp;

use strict;
use Exporter;
our (@EXPORT_OK, %EXPORT_TAGS, @ISA);
@ISA = qw(Exporter);
@EXPORT_OK = qw(&performBackup &removeBackups &listBackups &fixBackupPath);
%EXPORT_TAGS = ("all" => [@EXPORT_OK]);

use BackupsBlow::Config qw(:read);
use BackupsBlow::Programs qw(:all);
use BackupsBlow::Util qw(:transport);

use Log::Log4perl;
my $logger=Log::Log4perl->get_logger();

sub fixBackupPath ($) {
    my ($backupPath)=@_;
    $backupPath=~s/\/*$/\//;
    return $backupPath;
}

sub buildFtpCommand () {
    # Create a general ftp command
    my @ftpCommand;
    push @ftpCommand,needProgram("ncftp");
    push @ftpCommand,buildFtpBase();
    return join(" ",@ftpCommand);
}

# Package up an echo command to echo pre and post lines
# surrounding the output of a given ftp command
sub buildEchoCommand ($$$) {
    my @startCommand;
    push @startCommand,"echo";
    push @startCommand,$_[1];
    my @endCommand;
    push @endCommand,"echo";
    push @endCommand,$_[2];
    my @commands;
    push @commands,join(" ",@startCommand);
    push @commands,$_[0];
    push @commands,join(" ",@endCommand);
    my @echoCommand;
    push @echoCommand,"echo";
    push @echoCommand,"\"" . join(";", @commands) . "\"";
    return join(" ", @echoCommand);
}

# Build a base for the FTP commands
sub buildFtpBase () {
    my @ftpBase;

    push @ftpBase, "-u ".needConfig("USERNAME");
    push @ftpBase, "-p ".needConfig("PASSWORD");
    push @ftpBase, needConfig("HOSTNAME");

    return @ftpBase
}

sub performBackup ($$$$) {
    my ($backupDir,$backupFile,$incFile,$errFile)=@_;

    my @command;
    push @command,buildTarCommand($incFile, $errFile);

    # Build a ftp put commandline
    my @ftpCommand;
    push @ftpCommand,needProgram("ncftpput"); # Pipeable ftp command
    push @ftpCommand,"-c";                    # Read from stdin
    push @ftpCommand,buildFtpBase();          # The basic username/site/pwd
    push @ftpCommand,"$backupDir$backupFile"; # Destination file
    # Build a command to delay ftp start until there is data to transfer
    my @delayCommand;
    push @delayCommand,"while [ ! -s $errFile ]";
    push @delayCommand,"do sleep 1";
    push @delayCommand,"done";
    push @delayCommand,join(" ",@ftpCommand);
    push @command,"(" . join(";",@delayCommand) . ")";
    my $command=join("|",@command);
    system($command);
    unless ($? == 0) {
        die("Failed to perform backup: $command: $?");
        capture("rm $backupDir$backupFile");
    }
}

sub removeBackups ($$) {
    my ($backupDir,$fileNames)=@_;
    unshift @$fileNames,"rm";
    my $rmCommand=join(" $backupDir",@$fileNames);
    my @rm=capture($rmCommand);
    my $errStr;
    foreach my $line(@rm) {
        $errStr.="$line " if ($line =~ m/failed/i);
    }
    die("Failed to remove old backups: $rmCommand: $errStr") if ($errStr);
}

# Takes an ftp command to read the FTP server and a command to run there
# returns an array of the lines resulting from the command
sub capture ($) {
    my @commands;
    push @commands,buildEchoCommand($_[0],"B#B#S","B#B#E");
    push @commands,buildFtpCommand();
    my $command=join("|",@commands);
    # Capture the output from the ls comand
    my @lsOutput=`$command`;

    #TODO: This should report the error to the caller, not die itself
    die("Unable to capture $_[0]") unless ($? == 0);
    my @retVal;
    # Search the listing for the actual output of our command
    my $active=0;
    foreach my $line(@lsOutput) {
        chomp($line);
        unless ($active) {
            $active=1 if ($line =~ m/^B#B#S$/);
            next;
        }
        last if ($active == 1 && $line =~ m/^B#B#E$/);
        $line=~s/^[[:space:]]*(.*)[[:space:]]*$/$1/;
        push @retVal,$line unless ($line =~ m/^$/);
    }
    return @retVal;
}

# Takes a directory to list
# returns an array of files in that directory
sub listBackups ($) {
    # Create a command to list the backups already on the server
    my @lsCommand;
    push @lsCommand,"ls";
    push @lsCommand,"-1";
    push @lsCommand,$_[0];
    return capture(join(" ",@lsCommand));
}

1;
"Remember, brick walls let us show our dedication. They are there to separate us from the people who don't really want to achieve their dreams. Don't bail. The best of the gold's at the bottom of barrels of crap." --Randy Pausch
Google
 
© 2002-2008 Brandon Low 6 hits since September 11, 2008