| 11 | rodolico | 1 | #! /usr/bin/env perl
 | 
        
           |  |  | 2 |   | 
        
           | 13 | rodolico | 3 | # archiveDirectories.pl
 | 
        
           | 11 | rodolico | 4 | # Author: R. W. Rodolico
 | 
        
           |  |  | 5 | # Date: 20180603
 | 
        
           |  |  | 6 |   | 
        
           | 18 | rodolico | 7 | # Copyright (c) 2018, Daily Data, Inc
 | 
        
           |  |  | 8 | # All rights reserved.
 | 
        
           |  |  | 9 | # 
 | 
        
           |  |  | 10 | # Redistribution and use in source and binary forms, with or without
 | 
        
           |  |  | 11 | # modification, are permitted provided that the following conditions are met:
 | 
        
           |  |  | 12 | # 
 | 
        
           |  |  | 13 | # 1. Redistributions of source code must retain the above copyright notice, this
 | 
        
           |  |  | 14 | #    list of conditions and the following disclaimer.
 | 
        
           |  |  | 15 | # 2. Redistributions in binary form must reproduce the above copyright notice,
 | 
        
           |  |  | 16 | #    this list of conditions and the following disclaimer in the documentation
 | 
        
           |  |  | 17 | #    and/or other materials provided with the distribution.
 | 
        
           |  |  | 18 | # 
 | 
        
           |  |  | 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 | 
        
           |  |  | 20 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
        
           |  |  | 21 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
        
           |  |  | 22 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 | 
        
           |  |  | 23 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 | 
        
           |  |  | 24 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | 
        
           |  |  | 25 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 | 
        
           |  |  | 26 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
        
           |  |  | 27 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
        
           |  |  | 28 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
        
           |  |  | 29 | # 
 | 
        
           |  |  | 30 | # The views and conclusions contained in the software and documentation are those
 | 
        
           |  |  | 31 | # of the authors and should not be interpreted as representing official policies,
 | 
        
           |  |  | 32 | # either expressed or implied, of the <project name> project.
 | 
        
           |  |  | 33 |   | 
        
           | 13 | rodolico | 34 | # Script designed to be run from a cron job, which checks if any directories
 | 
        
           | 12 | rodolico | 35 | # are ready to be archived. A directory is defined as a directory under
 | 
        
           | 13 | rodolico | 36 | # the root of $config{'local root dir'}.
 | 
        
           | 11 | rodolico | 37 |   | 
        
           |  |  | 38 | # If found, all directories are moved into the staging area and 
 | 
        
           |  |  | 39 | # an md5 checksum is calculated for the entire tree.
 | 
        
           | 13 | rodolico | 40 | # After all directories are moved, a second process looks in the staging
 | 
        
           | 11 | rodolico | 41 | # area and copies the files (using rsync for reliability) into the staging
 | 
        
           | 13 | rodolico | 42 | # area of $config{'target server'}. When a directory has been copied, a checksum is
 | 
        
           | 11 | rodolico | 43 | # calculated on the remote copy and compared to the checksum calculated
 | 
        
           | 12 | rodolico | 44 | # in the first stage and, if it passes, the directory is then moved to the 
 | 
        
           | 13 | rodolico | 45 | # $config{'target final directory'}.
 | 
        
           | 12 | rodolico | 46 | # After the copy and move, the directory and its MD5 sum file are moved
 | 
        
           | 13 | rodolico | 47 | # to the $config{'local trash dir'} (which is cleaned on the next invocation of
 | 
        
           | 11 | rodolico | 48 | # the script).
 | 
        
           |  |  | 49 |   | 
        
           |  |  | 50 | #
 | 
        
           |  |  | 51 | # Version: 1.0
 | 
        
           |  |  | 52 |   | 
        
           |  |  | 53 | use warnings;
 | 
        
           |  |  | 54 | use strict;
 | 
        
           |  |  | 55 | use Cwd qw();
 | 
        
           |  |  | 56 | use File::Copy qw(move);
 | 
        
           |  |  | 57 | use File::Basename;
 | 
        
           | 13 | rodolico | 58 | use File::stat;
 | 
        
           | 11 | rodolico | 59 |   | 
        
           | 22 | rodolico | 60 | # http://computer-programming-forum.com/53-perl/843e6090fe295ffc.htm
 | 
        
           |  |  | 61 | # how to verify this script is not already running
 | 
        
           |  |  | 62 | # creates a lock file which only lasts the length of the script
 | 
        
           |  |  | 63 | # if we die before removing it, the lock is released.
 | 
        
           |  |  | 64 | use Fcntl qw(:flock);  #  imports some constants
 | 
        
           |  |  | 65 | my $LOCKFILE = '/tmp/archiveDirectories.lock';
 | 
        
           |  |  | 66 | open LOCK, ">>$LOCKFILE" or die ("Can't open lockfile $LOCKFILE: $!");
 | 
        
           |  |  | 67 | flock(LOCK, LOCK_EX) or die ("I'm already running"); 
 | 
        
           |  |  | 68 |   | 
        
           | 18 | rodolico | 69 | our $VERSION = '1.0';
 | 
        
           | 11 | rodolico | 70 |   | 
        
           | 22 | rodolico | 71 | my $DEBUG = 0;
 | 
        
           | 18 | rodolico | 72 |   | 
        
           | 16 | rodolico | 73 | my %config;
 | 
        
           | 11 | rodolico | 74 |   | 
        
           | 16 | rodolico | 75 | my @DirectoriesToMove;
 | 
        
           | 13 | rodolico | 76 |   | 
        
           | 16 | rodolico | 77 | sub loadConfig {
 | 
        
           |  |  | 78 |    use FindBin;
 | 
        
           |  |  | 79 |    my $configFileName = "$FindBin::Bin/$FindBin::Script";
 | 
        
           |  |  | 80 |    unless ( $configFileName =~ s/\.pl$/\.conf/ ) {
 | 
        
           |  |  | 81 |       $configFileName .= '.conf';
 | 
        
           |  |  | 82 |    }
 | 
        
           |  |  | 83 |   | 
        
           |  |  | 84 |    if ( -e $configFileName ) {
 | 
        
           |  |  | 85 |       my $configFileContents = &slurpFile( $configFileName );
 | 
        
           |  |  | 86 |       eval( $configFileContents );
 | 
        
           |  |  | 87 |       die "Error interpreting $configFileName: $@\n" if $@;
 | 
        
           |  |  | 88 |    } else {
 | 
        
           |  |  | 89 |       die "Could not locate config file $configFileName\n";
 | 
        
           |  |  | 90 |    } # if..else
 | 
        
           |  |  | 91 | } #loadConfig
 | 
        
           | 13 | rodolico | 92 |   | 
        
           | 18 | rodolico | 93 | # simply read the entire file into a string
 | 
        
           | 13 | rodolico | 94 | sub slurpFile {
 | 
        
           |  |  | 95 |    my $filename = shift;
 | 
        
           |  |  | 96 |    return '' unless -e $filename;
 | 
        
           | 20 | rodolico | 97 |    open TEMP, "<$filename" or die "could not read $filename: $!\n";
 | 
        
           | 13 | rodolico | 98 |    my @contents = <TEMP>;
 | 
        
           |  |  | 99 |    close TEMP;
 | 
        
           |  |  | 100 |    return join( '', @contents );
 | 
        
           |  |  | 101 | }
 | 
        
           |  |  | 102 |   | 
        
           |  |  | 103 | # print a value to a file
 | 
        
           |  |  | 104 | sub writeData {
 | 
        
           |  |  | 105 |    my $filename = shift;
 | 
        
           |  |  | 106 |    open TEMP, ">$filename" or die "could not write to $filename: $!\n";
 | 
        
           |  |  | 107 |    print TEMP join( '', @_ );
 | 
        
           |  |  | 108 |    close TEMP;
 | 
        
           |  |  | 109 | }
 | 
        
           |  |  | 110 |   | 
        
           | 18 | rodolico | 111 | # returns how many seconds ago a file was created
 | 
        
           |  |  | 112 | sub fileAge {
 | 
        
           |  |  | 113 |    my $filename = shift;
 | 
        
           |  |  | 114 |    my $age = stat( $filename );
 | 
        
           |  |  | 115 |    $age = $$age[9];
 | 
        
           |  |  | 116 |    print "$age\t$filename" if $DEBUG > 3;
 | 
        
           |  |  | 117 |    return time - $age;
 | 
        
           |  |  | 118 | }
 | 
        
           |  |  | 119 |   | 
        
           |  |  | 120 |   | 
        
           | 13 | rodolico | 121 | # look in the directories to move directory and see if there is anything 
 | 
        
           |  |  | 122 | # new in there. If so, check MD5 Sum file (create if necessary) and ensure
 | 
        
           |  |  | 123 | # we have waited long enough and the sums match
 | 
        
           |  |  | 124 | sub getDirectories {
 | 
        
           | 11 | rodolico | 125 |    my $rootDir = shift;
 | 
        
           | 13 | rodolico | 126 |    print "In getDirectories with dir of $rootDir\n" if $DEBUG;
 | 
        
           | 11 | rodolico | 127 |    opendir( my $dh, $rootDir ) or die "Could not open directory $rootDir: $!\n";
 | 
        
           |  |  | 128 |    my @dirs = grep { ! /^\./ && -d "$rootDir/$_" } readdir( $dh );
 | 
        
           | 13 | rodolico | 129 |    closedir ( $dh );
 | 
        
           |  |  | 130 |    print "Directories Found\n" . join( "\n", @dirs ) . "\n" if $DEBUG > 1;
 | 
        
           |  |  | 131 |    my @dirsToMove;
 | 
        
           |  |  | 132 |    foreach my $thisDir ( @dirs ) {
 | 
        
           |  |  | 133 |       my $fullyQualified = "$rootDir/$thisDir";
 | 
        
           |  |  | 134 |       my $md5 = calcMD5( $fullyQualified );
 | 
        
           |  |  | 135 |       print "\tFound Dir $fullyQualified with MD5 of $md5\n" if $DEBUG > 2;
 | 
        
           |  |  | 136 |       # let's look for the md5 checksum file and compare if it exist
 | 
        
           |  |  | 137 |       my $md5Name = "$fullyQualified.$config{'md5 suffix'}";
 | 
        
           |  |  | 138 |       if ( -e $md5Name ) {
 | 
        
           |  |  | 139 |          # find out when it was last written to
 | 
        
           | 18 | rodolico | 140 |          print "\tFound existing MD5 file $md5Name\n" if $DEBUG > 3;
 | 
        
           | 13 | rodolico | 141 |          # and blow it off if it is too recent
 | 
        
           | 18 | rodolico | 142 |          if ( &fileAge( $md5Name) < $config{'quiesent seconds'} ) {
 | 
        
           |  |  | 143 |             print "\t\tBlowing it off because it is less than $config{'quiesent seconds'} seconds old\n" if $DEBUG > 4;
 | 
        
           | 13 | rodolico | 144 |             next;
 | 
        
           |  |  | 145 |          }
 | 
        
           |  |  | 146 |          my $oldMD5 = &slurpFile( $md5Name );
 | 
        
           |  |  | 147 |          if ( $md5 eq $oldMD5 ) {
 | 
        
           |  |  | 148 |             print "\t\tAdding, md5 not changed, $md5 same as $oldMD5\n" if $DEBUG > 4;
 | 
        
           |  |  | 149 |             push @dirsToMove, $thisDir;
 | 
        
           |  |  | 150 |          } else {
 | 
        
           |  |  | 151 |             print "\t\tWaiting, md5 changed, $md5 and $oldMD5\n" if $DEBUG > 4;
 | 
        
           |  |  | 152 |             # overwrite if the checksum has changed
 | 
        
           |  |  | 153 |             &writeData( $md5Name, $md5 ) if $md5 ne &slurpFile( $md5Name );
 | 
        
           |  |  | 154 |          }
 | 
        
           |  |  | 155 |       } else { # doesn't exist, so create it
 | 
        
           |  |  | 156 |          print "\t\tCreating MD5 File $md5Name with value $md5\n" if $DEBUG > 4;
 | 
        
           |  |  | 157 |          &writeData( $md5Name, $md5 );
 | 
        
           |  |  | 158 |       }
 | 
        
           |  |  | 159 |    } # foreach
 | 
        
           |  |  | 160 |    return @dirsToMove;
 | 
        
           | 11 | rodolico | 161 | }
 | 
        
           |  |  | 162 |   | 
        
           |  |  | 163 | # calculate the checksum of a directory by
 | 
        
           |  |  | 164 | # 1. calculate checksum of each individual file in the entire tree
 | 
        
           |  |  | 165 | # 2. Grab the first column, which is the checksum
 | 
        
           |  |  | 166 | # 3. sort the result since Linux will not always return them in the same order
 | 
        
           |  |  | 167 | # 4. do a checksum of the checksums
 | 
        
           |  |  | 168 | #
 | 
        
           |  |  | 169 | # This is highly unlikely to give the same answer if any file changes
 | 
        
           |  |  | 170 | # in the process of the copy
 | 
        
           |  |  | 171 | sub calcMD5 {
 | 
        
           |  |  | 172 |    my $directory = shift;
 | 
        
           |  |  | 173 |    return -1 unless -d $directory;
 | 
        
           |  |  | 174 |    my $md5 = `find '$directory' -type f -exec md5sum \\{\\} \\; | cut -d' ' -f1 | sort | md5sum | cut -d' ' -f1`;
 | 
        
           |  |  | 175 |    chomp $md5;
 | 
        
           |  |  | 176 |    return $md5;
 | 
        
           |  |  | 177 | }
 | 
        
           |  |  | 178 |   | 
        
           | 12 | rodolico | 179 | # moves directory to staging area and puts the md5 sum into a file
 | 
        
           | 11 | rodolico | 180 | # with the same name, but a .md5sum suffix
 | 
        
           |  |  | 181 | sub moveToStaging {
 | 
        
           | 13 | rodolico | 182 |    my ( $directory, $fullPath, $staging ) = @_;
 | 
        
           |  |  | 183 |    # and let's get the md5 file name also
 | 
        
           |  |  | 184 |    my $md5File = $fullPath . ".$config{'md5 suffix'}";
 | 
        
           | 20 | rodolico | 185 |    mkdir( $staging ) unless -d $staging;
 | 
        
           | 13 | rodolico | 186 |    return 'Directory already exists in staging' if -e "$staging/$directory";
 | 
        
           |  |  | 187 |    move( $fullPath, "$staging/$directory" ) or die "Error moving $fullPath to $staging/$directory: $!\n";
 | 
        
           |  |  | 188 |    move( $md5File, $staging ) or die "Error moving $md5File to $staging: $!\n";
 | 
        
           |  |  | 189 |    return '';
 | 
        
           | 11 | rodolico | 190 | }
 | 
        
           | 16 | rodolico | 191 |   | 
        
           |  |  | 192 | sub getCheckSum {
 | 
        
           |  |  | 193 |    my $project = shift;
 | 
        
           |  |  | 194 |    my $checkSumFile = $config{'local staging area'} . '/' . $project . '.' . $config{'md5 suffix'};
 | 
        
           |  |  | 195 |    if ( -e $checkSumFile ) {
 | 
        
           |  |  | 196 |       return &slurpFile( $checkSumFile );
 | 
        
           |  |  | 197 |    }
 | 
        
           |  |  | 198 |    return '';
 | 
        
           |  |  | 199 | }
 | 
        
           |  |  | 200 |   | 
        
           | 12 | rodolico | 201 | # verifies the directory is correct on the server by comparing the checksums
 | 
        
           | 11 | rodolico | 202 | # calculated locally and remote server. If valid, moves it into the final
 | 
        
           |  |  | 203 | # location on the remote server
 | 
        
           |  |  | 204 | sub validateTarget {
 | 
        
           | 12 | rodolico | 205 |    my ( $remoteServer, $remoteStaging, $remoteTarget, $directory, $checksum ) = @_;
 | 
        
           |  |  | 206 |    my $md5sum = `ssh $remoteServer "find '$remoteStaging/$directory' -type f -exec md5sum \\{\\} \\; | cut -d' ' -f1 | sort | md5sum | cut -d' ' -f1"`;
 | 
        
           | 11 | rodolico | 207 |    chomp $md5sum;
 | 
        
           |  |  | 208 |    if ( $checksum eq $md5sum ) {
 | 
        
           | 30 | rodolico | 209 |       &logit( $directory, $config{'log suffix'}, "checksums match" );
 | 
        
           | 29 | rodolico | 210 |       return 1;
 | 
        
           | 11 | rodolico | 211 |    } else {
 | 
        
           | 30 | rodolico | 212 |       &logit( $directory, $config{'error suffix'}, "Invalid checksum moving directory $directory" );
 | 
        
           | 11 | rodolico | 213 |       return 0;
 | 
        
           |  |  | 214 |    }
 | 
        
           |  |  | 215 | }
 | 
        
           |  |  | 216 |   | 
        
           |  |  | 217 | # simple little logger that records some information   
 | 
        
           |  |  | 218 | sub logit {
 | 
        
           | 15 | rodolico | 219 |    my $projectName = shift;
 | 
        
           |  |  | 220 |    my $suffix = shift;
 | 
        
           | 29 | rodolico | 221 |    $suffix = $config{'log suffix'} unless $suffix;
 | 
        
           | 16 | rodolico | 222 |    my $logfile = $config{'local root dir'} . "/$projectName.$suffix";
 | 
        
           | 11 | rodolico | 223 |    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
 | 
        
           |  |  | 224 |    my $now = sprintf( "%04d-%02d-%02d %02d:%-2d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec );
 | 
        
           | 22 | rodolico | 225 |    # create the logfile if it doesn't exist and set it to rw by everyone
 | 
        
           |  |  | 226 |    unless ( -e $logfile ) {
 | 
        
           |  |  | 227 |       qx(touch '$logfile');
 | 
        
           |  |  | 228 |       qx(chmod 666 '$logfile');
 | 
        
           |  |  | 229 |    }
 | 
        
           | 13 | rodolico | 230 |    open LOG, ">>$logfile" or die "could not write to $logfile: $!\n";
 | 
        
           |  |  | 231 |    while ( my $message = shift ) {
 | 
        
           |  |  | 232 |       print LOG "$now\t$message\n";
 | 
        
           |  |  | 233 |    }
 | 
        
           | 11 | rodolico | 234 |    close LOG;
 | 
        
           |  |  | 235 | }
 | 
        
           | 15 | rodolico | 236 |   | 
        
           |  |  | 237 | sub runRemoteCommand {
 | 
        
           |  |  | 238 |    my $server = shift;
 | 
        
           |  |  | 239 |    while ( my $command = shift ) {
 | 
        
           |  |  | 240 |       my $output = qx/ssh $server '$command'/;
 | 
        
           |  |  | 241 |       if ( my $error = $? & 127 ) {
 | 
        
           |  |  | 242 |          return ( $output, $error );
 | 
        
           |  |  | 243 |       }
 | 
        
           |  |  | 244 |    }
 | 
        
           |  |  | 245 |    return ('', 0);
 | 
        
           |  |  | 246 | }
 | 
        
           |  |  | 247 |   | 
        
           | 11 | rodolico | 248 |   | 
        
           | 15 | rodolico | 249 | sub copyToRemote {
 | 
        
           |  |  | 250 |    my ( $path, $dirname, $remoteServer, $remotePath ) = @_;
 | 
        
           |  |  | 251 |    # first, copy the file
 | 
        
           | 16 | rodolico | 252 |    #print "rsync -a $path/$dirname $remoteServer:$remotePath > /tmp/lastrsync.log";
 | 
        
           |  |  | 253 |    #die;
 | 
        
           | 21 | rodolico | 254 |    qx"rsync -a '$path/$dirname' $remoteServer:$remotePath > /tmp/lastrsync.log";
 | 
        
           | 15 | rodolico | 255 |    return 'rsync failed with error :' . $? & 127 if $? & 127;
 | 
        
           |  |  | 256 |    return '';
 | 
        
           |  |  | 257 | }
 | 
        
           |  |  | 258 |   | 
        
           | 18 | rodolico | 259 | # simply remove everything from the trash directory over $age seconds old
 | 
        
           |  |  | 260 | sub cleanTrash {
 | 
        
           |  |  | 261 |    my ( $trashDir, $age ) = @_;
 | 
        
           |  |  | 262 |    my $md5Suffix = $config{'md5 suffix'};
 | 
        
           |  |  | 263 |    my @toRemove = ();
 | 
        
           |  |  | 264 |    if ( opendir( my $dh, $trashDir ) ) {
 | 
        
           |  |  | 265 |       # get all the md5sum files which are older than $age seconds old
 | 
        
           |  |  | 266 |       @toRemove = grep { &fileAge( "$_" ) > $age  } map{ "$trashDir/$_" }  grep{ /$md5Suffix$/ } readdir( $dh);
 | 
        
           |  |  | 267 |       closedir( $dh );
 | 
        
           |  |  | 268 |    }
 | 
        
           |  |  | 269 |    print "You should remove the following files\n" if $DEBUG > 1;
 | 
        
           |  |  | 270 |    foreach my $thisDir ( @toRemove ) {
 | 
        
           |  |  | 271 |       $thisDir =~ m/(.*)\.$md5Suffix/;
 | 
        
           |  |  | 272 |       $thisDir = $1;
 | 
        
           | 19 | rodolico | 273 |       qx/rm -fR '$thisDir' '$thisDir.$md5Suffix'/;
 | 
        
           | 18 | rodolico | 274 |    }
 | 
        
           |  |  | 275 | }
 | 
        
           |  |  | 276 |   | 
        
           | 20 | rodolico | 277 | sub makeDirectories {
 | 
        
           |  |  | 278 |    my $directory = shift;
 | 
        
           |  |  | 279 |    my $permissions = shift;
 | 
        
           |  |  | 280 |    $permissions = '777' unless $permissions;
 | 
        
           |  |  | 281 |    unless ( -d $directory ) {
 | 
        
           |  |  | 282 |       print "Making directory $directory\n" if $DEBUG > 1;
 | 
        
           |  |  | 283 |       `mkdir -p $directory`; 
 | 
        
           |  |  | 284 |       `chmod $permissions $directory`;
 | 
        
           |  |  | 285 |    }
 | 
        
           |  |  | 286 | }
 | 
        
           |  |  | 287 |   | 
        
           | 18 | rodolico | 288 |   | 
        
           |  |  | 289 |   | 
        
           | 16 | rodolico | 290 | ###############################################################################
 | 
        
           |  |  | 291 | # Main
 | 
        
           |  |  | 292 | ###############################################################################
 | 
        
           | 15 | rodolico | 293 |   | 
        
           | 16 | rodolico | 294 | &loadConfig();
 | 
        
           |  |  | 295 | #use Data::Dumper;
 | 
        
           |  |  | 296 | #print Dumper( \%config );
 | 
        
           |  |  | 297 | #die;
 | 
        
           |  |  | 298 |   | 
        
           | 20 | rodolico | 299 | foreach my $dirsToMake ( 'local root dir', 'local trash dir', 'local staging area' ) {
 | 
        
           |  |  | 300 |    &makeDirectories( $config{$dirsToMake} );
 | 
        
           | 13 | rodolico | 301 | }
 | 
        
           | 20 | rodolico | 302 |   | 
        
           | 13 | rodolico | 303 | # clean the trash if $config{ 'trash cleanup' } is non-zero
 | 
        
           |  |  | 304 | &cleanTrash( $config{'local trash dir'}, $config{ 'trash cleanup' } ) if $config{ 'trash cleanup' };
 | 
        
           | 18 | rodolico | 305 |   | 
        
           | 13 | rodolico | 306 | # Check if we have any directories which are ready to be moved.
 | 
        
           |  |  | 307 | @DirectoriesToMove = &getDirectories( $config{'local root dir'} );
 | 
        
           | 11 | rodolico | 308 |   | 
        
           | 18 | rodolico | 309 | print "Processing\n\t" . join( "\n\t", @DirectoriesToMove ) . "\n" if $DEBUG > 1;
 | 
        
           | 13 | rodolico | 310 |   | 
        
           |  |  | 311 | foreach my $directory ( @DirectoriesToMove ) {
 | 
        
           |  |  | 312 |    my $fullPath = $config{'local root dir'} . "/$directory";
 | 
        
           |  |  | 313 |    my $logFile = "$fullPath.$config{'log suffix'}";
 | 
        
           |  |  | 314 |    my $errorFile = "$fullPath.$config{'error suffix'}";
 | 
        
           |  |  | 315 |    print "Path for $directory is $fullPath\n\tLog File is $logFile\n\tError file is $errorFile\n" if $DEBUG > 3;
 | 
        
           |  |  | 316 |    if ( -e $errorFile ) {
 | 
        
           | 15 | rodolico | 317 |       &logit( $directory, $config{'log suffix'}, "Aborting because we have a pre-existing error" );
 | 
        
           | 13 | rodolico | 318 |       print "\tAborting because we have a pre-existing error\n" if $DEBUG > 3;
 | 
        
           |  |  | 319 |       next;
 | 
        
           |  |  | 320 |    }
 | 
        
           | 15 | rodolico | 321 |    &logit( $directory, $config{'log suffix'}, "Processing $directory" );
 | 
        
           | 13 | rodolico | 322 |    my $error = &moveToStaging( $directory, $fullPath, $config{'local staging area'} );
 | 
        
           |  |  | 323 |    if ( ! $error ) {
 | 
        
           |  |  | 324 |       print "\tMoved to $config{'local staging area'}\n" if $DEBUG > 3;
 | 
        
           | 15 | rodolico | 325 |       &logit( $directory, $config{'log suffix'},  "Successfully moved to $config{'local staging area'}" );
 | 
        
           | 13 | rodolico | 326 |    } else {
 | 
        
           | 15 | rodolico | 327 |       &logit( $directory, $config{'log suffix'},  "Error, move aborted" );
 | 
        
           |  |  | 328 |       &logit( $directory, $config{'error suffix'},  $error );
 | 
        
           | 13 | rodolico | 329 |    }
 | 
        
           | 11 | rodolico | 330 | }
 | 
        
           |  |  | 331 |   | 
        
           | 29 | rodolico | 332 |   | 
        
           | 11 | rodolico | 333 | # done with that, now we need to see if there is anything in the staging area
 | 
        
           |  |  | 334 | # that needs to be sent to the remote server
 | 
        
           | 15 | rodolico | 335 | `mkdir -p $config{'local staging area'}` unless -d $config{'local staging area'};
 | 
        
           | 13 | rodolico | 336 | opendir( my $dh, $config{'local staging area'} ) or die "Could not read $config{'local staging area'}: $!\n";
 | 
        
           | 11 | rodolico | 337 | my @directories;
 | 
        
           | 15 | rodolico | 338 | # get all the .md5 files
 | 
        
           | 13 | rodolico | 339 | my @toMove = grep { /$config{'md5 suffix'}$/ } readdir( $dh );
 | 
        
           |  |  | 340 | my $targetPath = "$config{'target server'}:$config{'target staging area'}/";
 | 
        
           | 18 | rodolico | 341 | print "Copying the following to $targetPath\n\t" . join ("\n\t", @toMove ) . "\n" if $DEBUG > 1;
 | 
        
           | 15 | rodolico | 342 | # create the target directory on the server if it doesn't exist
 | 
        
           |  |  | 343 | &runRemoteCommand( $config{'target server'},
 | 
        
           |  |  | 344 |    "[ ! -d $config{'target staging area'} ] && mkdir -p $config{'target staging area'}",
 | 
        
           |  |  | 345 |    "[ ! -d $config{'target final directory'} ] && mkdir -p $config{'target final directory'}"
 | 
        
           |  |  | 346 |    );
 | 
        
           | 16 | rodolico | 347 |   | 
        
           |  |  | 348 |   | 
        
           | 15 | rodolico | 349 | # now, process each directory in turn
 | 
        
           | 16 | rodolico | 350 | foreach my $dirname ( @toMove ) {
 | 
        
           |  |  | 351 |    print "Processing $dirname\n";
 | 
        
           | 15 | rodolico | 352 |    my $error;
 | 
        
           | 16 | rodolico | 353 |    $dirname =~ m/^(.*)\.$config{'md5 suffix'}$/;
 | 
        
           | 15 | rodolico | 354 |    $dirname = $1;
 | 
        
           |  |  | 355 |    $error = ©ToRemote( $config{'local staging area'}, $dirname, $config{'target server'}, $config{'target staging area'} );
 | 
        
           |  |  | 356 |    if ( $error ) {
 | 
        
           | 16 | rodolico | 357 |       &logit( $dirname, $config{'error suffix'}, $error );
 | 
        
           | 15 | rodolico | 358 |       next;
 | 
        
           |  |  | 359 |    } else {
 | 
        
           | 16 | rodolico | 360 |       &logit( $dirname, $config{'log suffix'}, "Copied to $config{'target server'}:$config{'target staging area'}" );
 | 
        
           |  |  | 361 |    }
 | 
        
           | 15 | rodolico | 362 |   | 
        
           | 16 | rodolico | 363 |    my $md5sum = &getCheckSum( $dirname );
 | 
        
           | 11 | rodolico | 364 |    next unless $md5sum;
 | 
        
           | 21 | rodolico | 365 |    if ( &validateTarget( $config{'target server'}, $config{'target staging area'}, $config{'target final directory'}, $dirname, $md5sum ) ) {
 | 
        
           |  |  | 366 |       `mkdir -p $config{'local trash dir'}` unless -d $config{'local trash dir'};
 | 
        
           |  |  | 367 |       move( "$config{'local staging area'}/$dirname", "$config{'local trash dir'}/$dirname" );
 | 
        
           |  |  | 368 |       my $md5File = $dirname . '.' . $config{'md5 suffix'};
 | 
        
           |  |  | 369 |       move( "$config{'local staging area'}/$md5File", "$config{'local trash dir'}/$md5File" );
 | 
        
           |  |  | 370 |       &logit( $dirname, $config{'log suffix'}, "Successfully moved directory $dirname to $config{'target server'}" );
 | 
        
           | 11 | rodolico | 371 |    } else {
 | 
        
           | 21 | rodolico | 372 |       &logit( $dirname, $config{'error suffix'}, "Unable to validate target for $dirname" );
 | 
        
           | 11 | rodolico | 373 |    }
 | 
        
           |  |  | 374 | }
 | 
        
           |  |  | 375 |   | 
        
           | 29 | rodolico | 376 | if ( defined ( $config{ 'final procedure' } ) ) {
 | 
        
           | 30 | rodolico | 377 |    my $command = 'ssh ' . $config{'target server'};
 | 
        
           |  |  | 378 |    $command .= " 'ls -p $config{'target staging area'} | grep /'";
 | 
        
           |  |  | 379 |    #print "$command\n";
 | 
        
           |  |  | 380 |    my $dirs  = qx/$command/;
 | 
        
           | 29 | rodolico | 381 |    my @dirs = split( "\n", $dirs );
 | 
        
           |  |  | 382 |    foreach my $thisDir ( @dirs ) {
 | 
        
           | 30 | rodolico | 383 |       $thisDir =~ s'/$'';
 | 
        
           |  |  | 384 |       my $result = $config{ 'final procedure' }->( $config{'target server'}, $config{'target staging area'}, $config{'target final directory'}, $thisDir );
 | 
        
           |  |  | 385 |       &logit( $thisDir, $config{'log suffix'}, $result ) if ( $result );
 | 
        
           | 29 | rodolico | 386 |    }
 | 
        
           |  |  | 387 | } # do the final procedure, if it exist
 | 
        
           | 11 | rodolico | 388 |   | 
        
           | 29 | rodolico | 389 |   | 
        
           |  |  | 390 |   | 
        
           | 11 | rodolico | 391 | 1;
 |