#!/usr/bin/perl
#   This is a perl script to initiate cleanup activity at the MEGHA server side
#   This script will look out at the following places for cleanup
#   i.~meghadata/backup/<yyyymmdd>/<hh> <<- Raw files coming from clients
#   ii.~meghadata/<uuid>/<yyyymmdd> <- Raw zip files
#   iii./usr/local/megha/db/backup (Backup Zip files)
#   iv./usr/local/megha/db/perf (Processed performance data)
#   v.Old logs /usr/local/megha/logs/sysstat
#   @Author     : Cumulus Systems
#   @Date       : 04 - mar - 2012
#   @Copyright  : (C) Copyright 2012 Cumulus Systems, All rights reserved.
#   Update: FTP mechanism should happen through the server FTP tool
###########################################################################################
use strict;
use warnings;

use File::stat;
use File::Basename;
use File::Copy;
use File::Path;
#use Net::FTP;
use Cwd;
#use Expect;

my $CONFIGFILE          = $ARGV[0];
my $DEFAULTBACKUPDIR    = "/data/megha/ftp";
my $DEFAULTFTPDIR       = "/data/megha/ftp";
my $yes                 = "YES";
my $no                  = "NO";

select(STDERR); $| = 1;
select(STDOUT); $| = 1;

my @listOfProps;
eval {
    &mainRoutine;
};
if ($@) {
    logMessage($@);
}
# This script will not run once... as it is from two different users now
# also if running it twice is not going to harm any thing
###########################################################################################
#sub INIT {
#    #set the log file name for logging
#    print("In begin\n");
#    if (-e "/tmp/." . $0 . $user . ".lck") {
#        print ("Another instance already running\n");
#        exit;
#    }
#    else {
#        system("touch /tmp/." . $0 . $user . ".lck" . "\n");
#    }
#}

###########################################################################################
#END {
#  print("In end");
#  unlink("/tmp/." . $0 . $user. ".lck");
#}

###########################################################################################
# this is the main routine which does the following
# Parses the config file and then looks at the parameters set per directory
# Initiates logging
# Initiates cleaning after which a disc status check is done, if the disk is
# still not ok re-inintate cleaning by changing cleanup properties on the fly

sub mainRoutine {
    #first get the configuration parameters from config file
    if( $CONFIGFILE ne "" && -e $CONFIGFILE) {
        my $prefHash = &parseConfigFile;

        #Dump what values are set
        dumpCleanupPrefs($prefHash);

        #check if the partition on the disk is in good status?
        my $dataToBeFreed =0;
        do {
            # do normal cleanup activity
            my %cleanupRef      = %$prefHash;

            for(my $i=0 ; $i <= $#listOfProps; $i++) {
                if( uc($cleanupRef{(uc($listOfProps[$i]) .".ENABLE")}) eq $yes) {
                    executeProcess($prefHash,$listOfProps[$i],$i);
                } else {
                    logMessage("Skipping property section $listOfProps[$i]");
                }
            }
            $dataToBeFreed = checkDiskStatus("/data",$prefHash);

            # we still have not reached safe limit.
            if($dataToBeFreed > 0) {
                modifyPrefHash($prefHash,\@listOfProps);
            }
        } while ($dataToBeFreed > 0);
    } else {
        logMessage("Script triggered with invalid input... config file missing");
        exit;
    }
}

###########################################################################################

# this function is used to modify the has property values on the fly
# this is done when we are still low on disc space even after cleaning
# up is performed. Ideally we should never be under this situation if
# in case of a healthy and apropriately configured system

sub modifyPrefHash {
    my($cleanupPrefRef,$propArrayRef) = @_;
    my %cleanupPref = %$cleanupPrefRef;
    my @proparray    = @$propArrayRef;

    #ProcessClientFiles
    foreach my $prop (@proparray) {
        my $basePropCF          = uc($prop);
        my $propCountCF         = uc($basePropCF . ".count");
        my $propRetentiontimeCF = uc($basePropCF . ".retentiontime");
        
        if($cleanupPref{$propCountCF} > 0) {
            # REDUCE by 75%
            my $countVal = $cleanupPref{$propCountCF} /4;
            if($countVal <= 0) {
                $countVal = 1;
            }
            $cleanupPref{$propCountCF} = $countVal;
        } else {
            my $timeVal = $cleanupPref{$propRetentiontimeCF} /4;
            if($timeVal <=0) {
                $timeVal = 1;
            }
            $cleanupPref{$propRetentiontimeCF}  = $timeVal;
        }
    }
}

###########################################################################################
# this function is used only for debug purposes and it will dump what all properties are set.
# this is required where we have to know if something was changed somewhere
sub dumpCleanupPrefs {
    my($cleanupPrefRef) = @_;
    my %cleanupPref = %$cleanupPrefRef;
    for my $pref (keys(%cleanupPref)) {
        logMessage($pref . " has value " .$cleanupPref{$pref});
    }
}

###########################################################################################
# this function will return the shell date time.

sub getDateString {
  my $date = `date -u +"%Y%m%d"`;
  $date =~ s/[\r\n]//g;
  return $date;
}

# this will process the client raw files cleanup
# this should ensure that we are properly deleteing the client files
# since we sort based on last modified time everywhere we are safe
# and we know we don't delete the current client files which are being
# processed.
# here we know that the directory structure is ~meghadata/backup/<yyyymmdd>/<hh>
# so we can optimize the logic to only look at directory name for deletion
# from the name we extract the day part in date and then delete

###########################################################################################
sub executeProcess {
    my($cleanupPrefRef,$propArrayStr,$arrayIndex) = @_;
    my %cleanupPref = %$cleanupPrefRef;
    my $retCode = 1;

    # list of properties
    my $baseProp            = uc($propArrayStr);
    my $propEnable          = uc($baseProp . ".enable");
    my $propRoot            = uc($baseProp . ".root");
    my $propCount           = uc($baseProp . ".count");
    my $propBackupMode      = uc($baseProp . ".mode");
    my $propBackupDir       = uc($baseProp . ".backupdir");
    my $propRetentiontime   = uc($baseProp . ".retentiontime");
    my $propDirOrFile       = uc($baseProp . ".type");
    my $propExtension       = uc($baseProp . ".extension");


    #if we have care for this property
    my $rootDir             = $cleanupPref{$propRoot};
    my $count               = $cleanupPref{$propCount};
    my $backUpdir           = $cleanupPref{$propBackupDir};
    my $retentTime          = $cleanupPref{$propRetentiontime};
    my $backupMode          = $cleanupPref{$propBackupMode};
    my $bDoDirCleanup       = $cleanupPref{$propDirOrFile};
    my $extension           = $cleanupPref{$propExtension};

    if(uc($backupMode) eq "LOCAL") {
        if( uc($backUpdir) eq "NONE") {
            logMessage("Error : for local mode backup dir should not be none and should be set");
            $retCode = 0;
        }
    }

    $retCode = $retCode && ProcessRequest($baseProp,$rootDir, $count, $backUpdir, $retentTime, $backupMode, $bDoDirCleanup, $extension, \%cleanupPref);
    return $retCode;
}

###########################################################################################
# this funtion gives the sorted list of file based on the last modified time
# of the files in a particular path. We sort them so that we can remove them
# instantly
sub getSortedFileList {
  #Schwartzian transform hack
  # ref : http://www.sysarch.com/Perl/sort_paper.html
    my ($inputDirLowest,$extension) = @_;
    if(uc($extension) eq "ALL") {
        $extension = "*";
    }
    my $cwd = cwd();
    chdir($inputDirLowest);
    my @fileList =
        map { $_->[1] }
            sort {$a->[0] <=> $b->[0]}
                map { [ stat($_)->mtime, $_ ] }
                    glob $extension;
    chdir($cwd);
    foreach my $file (@fileList) {
        $file = $inputDirLowest . "/". $file;
    }
    return \@fileList;
}

###########################################################################################
# this funtion gives the sorted list of directories based on the last created time
# of the files in a particular path. We sort them so that we can remove them
# instantly
sub getSortedDirList {
    #Schwartzian transform hack
    # ref: http://www.sysarch.com/Perl/sort_paper.html
    my ($baseDir,$extension) = @_;
    if(uc($extension) eq "ALL") {
        $extension = "*";
    }
    my $cwd = cwd();
    chdir($baseDir);
    my @dirList =
        map { $_->[0] }
            sort{ $a->[1] <=> $b->[1] }
                map { [ $_, (-M $_) ] }
                    grep -d, glob $extension;
    chdir($cwd);
    foreach my $dir (@dirList) {
        $dir = $baseDir . "/". $dir;
    }
    my @reverseArr = reverse(@dirList);
    return \@reverseArr;
}

###########################################################################################
# checks if we are ok for deletion based on the time??
sub checkIfCanBeDeleted {
    my($fileName,$diffAllowed) = @_;

    my $statTime = stat($fileName)->mtime; #this will give last modified time since epoch
#    use Date::Calc qw/Delta_Days/;

    my ($statd,$statm,$staty) = (localtime($statTime))[3,4,5];
    $statm++;
    $staty = $staty + 1900;

    my ($nowd,$nowm,$nowy) = (localtime)[3,4,5];
    $nowm++;
    $nowy = $nowy + 1900;
    
    # no need to do complex date checking then
    if($staty eq $nowy) {
        if($statm eq $nowm) {
            if($statd eq $nowd) {
               return 0; #do not delete
            }
        }
    }
    my $dateDiff = Delta_Days( $staty, $statm, $statd, $nowy, $nowm, $nowd);
    if($dateDiff >= $diffAllowed) {
        return 1; #delete
    } else {
        return 0; #do not delete
    }
}

# Alternate implementation in case the Date::Calc is not to be used
sub Delta_Days {
    my ($staty, $statm, $statd, $nowy, $nowm, $nowd) = @_;
    use Time::Local qw /timelocal/;
    my $epochStat = timelocal(0, 0, 0, $statd+0, $statm-1, $staty-1900);
    my $epochnow = timelocal(0, 0, 0, $nowd+0, $nowm-1, $nowy-1900);
    my $diffTime = abs($epochnow - $epochStat);
    $diffTime = $diffTime / (24 * 60 * 60); # we don't consider leap seconds here
    return $diffTime;
}

###########################################################################################
# this function is the main processing function for the count based deletion logic
sub doCountBasedProcess {
    # we ignore potential race conditions here.. !
    my ($baseProp,$count,$dirListRef,$backupDir,$backupMode,$bDirProcessing,$cleanupPrefRef) = @_;
       my %cleanupPref = %$cleanupPrefRef;
    my $ftpFolder = $cleanupPref{"CLEANUPAPP.FTP.ROOT"};
    if(!$ftpFolder) {
        $ftpFolder = $DEFAULTFTPDIR;
    }

    my @sortedDirList = @$dirListRef;
    my $totalElems = $#sortedDirList + 1 - $count;

    if(uc($bDirProcessing) eq "FILES") {
        my $backupDest = "";
        if( uc($backupMode) ne "NONE") {
            if( uc($backupMode) eq "REMOTE") {
                $backupDest = $ftpFolder ."/" . $baseProp . getDateString();
                mkpath($backupDest);
            } else {
                $backupDest = $backupDir ."/" . $baseProp . getDateString();
                mkpath($backupDest);
            }
        }
        my $bDoRemote = 0;
        my $bDoArchive = 0;
        for (my $i=0;$i<=$#sortedDirList;$i++) {
            if($i eq $totalElems) {
                last;
            }
            if( uc($backupMode)eq "NONE") {
                unlink($sortedDirList[$i]) or logMessage($! . " can't unlink ". $sortedDirList[$i]);
                next;
            } else {
                my $fileName = basename($sortedDirList[$i]);
                if(!Move($sortedDirList[$i],$backupDest . "/" .$fileName)) { #get it out of main stream first
                    logMessage("Error moving $sortedDirList[$i] ... $!");
                }

                if(uc($backupMode) eq "REMOTE") {
                    $bDoRemote = 1;
                    $bDoArchive = 1;
                    logMessage("removing $sortedDirList[$i]");
                } elsif(uc($backupMode) eq "LOCAL") {
                    $bDoArchive = 1; 
                    logMessage("removing $sortedDirList[$i]");
                } else {
                    unlink($backupDest . "/" .$fileName);
                    logMessage("removing $sortedDirList[$i]");
                }
            }
        }

        if($bDoArchive eq 1) {
            my $archiveName = "";
            if($bDoRemote eq 1) {
                $archiveName = createArchive($ftpFolder,$backupDest);
                if(!Move($archiveName,$ftpFolder)){
                    logMessage("Error moving $archiveName ... $!");
                }
           } else {
               $archiveName = createArchive($backupDir,$backupDest);
               if (!Move($archiveName,$backupDir)) {
                  logMessage("Error moving $archiveName ... $!");
               }
            }
            rmtree($backupDest);
        }
        #else {
        #    rmtree($backupDest);
        #}
        #if($DoRemote eq 1) {
        #doFTP($ftpFolder,\%cleanupPref);
        #}

    } else {
        my $backupDest = "";
        if( uc($backupMode) ne "NONE") {
            if( uc($backupMode) eq "REMOTE") {
               $backupDest = $ftpFolder ."/" . $baseProp;
               mkpath($backupDest);
            } else {
                $backupDest = $backupDir . "/" . $baseProp;
                mkpath($backupDest);
            }
        }

        my $bDoRemote = 0;
        my $bDoArchive = 0;
        
        for (my $i=0;$i<=@sortedDirList;$i++) {
            if($i eq $totalElems) {
                last;
            }
            if( uc($backupMode)eq "NONE") {
                rmtree($sortedDirList[$i]) or logMessage($! . " can't delete ". $sortedDirList[$i]);
                next;
            } else {
                mkpath($backupDest . "/". basename($sortedDirList[$i]));
                if(!Move($sortedDirList[$i],$backupDest . "/" . basename($sortedDirList[$i])) ) {
                    logMessage("Error moving directory $sortedDirList[$i] ... $!");
                }

                if(uc($backupMode) eq "REMOTE") {
                    $bDoRemote = 1;
                    $bDoArchive = 1;
                    logMessage("removing $sortedDirList[$i]");
                } elsif(uc($backupMode) eq "LOCAL") {
                    $bDoArchive = 1;
                    logMessage("removing $sortedDirList[$i]");
                } else {
                    rmtree($backupDest . "/" . basename($sortedDirList[$i])); # remove the entire directory
                    logMessage("removing $sortedDirList[$i]");
                }
            }
        }

        if($bDoArchive eq 1) {
            my $archiveName = "";
            if($bDoRemote eq 1) {
               $archiveName = createArchive($ftpFolder,$backupDest);
               if(! Move($archiveName,$ftpFolder)) {
                   logMessage("Error removing $archiveName ... $1");
               }
            } else {
                $archiveName = createArchive($backupDir,$backupDest);
                if(!Move($archiveName,$backupDir)) {
                    logMessage("Error removing $archiveName ... $!");
                }
            }
            rmtree($backupDest);
        }
        # else {
        #    rmtree($backupDest);
        #}
        #if($DoRemote eq 1) {
        #doFTP($ftpFolder,\%cleanupPref);
        #}
    }
}

###########################################################################################
# this function is the main processing function for the period based deletion logic
sub doTimeBasedProcess {
    # we ignore potential race conditions here.. !
    my $retCode = 1;
    my ($baseProp,$numdays, $dirListRef,$backupDir,$backupMode,$bDirProcessing,$cleanupPrefRef) = @_ ;
    my @sortedDirList = @$dirListRef;
    my %cleanupPref = %$cleanupPrefRef;

    my $ftpFolder = $cleanupPref{"CLEANUPAPP.FTP.ROOT"};
    if(!$ftpFolder) {
        $ftpFolder = $DEFAULTFTPDIR;
    }
    
    if( uc($bDirProcessing) eq "FILES") {
        my $backupDest = "";
        if( uc($backupMode) ne "NONE") {
            if( uc($backupMode) eq "REMOTE") {
                $backupDest = $ftpFolder ."/" . $baseProp . getDateString();
                mkpath($backupDest);
            } else {
                $backupDest = $backupDir . "/" . $baseProp . getDateString();
                mkpath($backupDest);
            }
        }

        my $bDoRemote = 0;
        my $bDoArchive = 0;
        for (my $i=0;$i<=$#sortedDirList;$i++) {
            if( uc($backupMode)eq "NONE") {
                if(checkIfCanBeDeleted($sortedDirList[$i],$numdays)) {
                    logMessage("deleting $sortedDirList[$i]");
                    unlink($sortedDirList[$i]) or logMessage($! . " can't delete ". $sortedDirList[$i]);
                }
                next;
            } else {
                    if(checkIfCanBeDeleted($sortedDirList[$i],$numdays)) {
                        mkpath($backupDest);
                        my $fileName = basename($sortedDirList[$i]);
                        if(!Move($sortedDirList[$i],$backupDest . "/" .$fileName)) {
                            logMessage("Error moving $sortedDirList[$i] ... $1");
                        }

                        if(uc($backupMode) eq "REMOTE") {
                            $bDoRemote = 1;
                            $bDoArchive = 1;
                            logMessage("removing $sortedDirList[$i]");
                        } elsif(uc($backupMode) eq "LOCAL") {
                            $bDoArchive = 1;
                            logMessage("removing $sortedDirList[$i]");
                        } else {
                            unlink($backupDest . "/" .$fileName);
                            logMessage("removing $sortedDirList[$i]");
                        }
                    } else {
                        last;
                    }
            }
        }

        if($bDoArchive eq 1) {
            my $archiveName = "";
            if($bDoRemote eq 1) {
               $archiveName = createArchive($ftpFolder,$backupDest);
               if(! Move($archiveName,$ftpFolder)) {
                   logMessage("Error moving $archiveName ... $!");
               }
            } else {
                $archiveName = createArchive($backupDir,$backupDest);
                if(! Move($archiveName,$backupDir)) {
                   logMessage("Error moving $archiveName ... $!");
                }
            }
            rmtree($backupDest);
        } 
        #else {
            #rmtree($backupDest);
        #}

        #if($DoRemote eq 1) {
        #$retCode = doFTP($ftpFolder,\%cleanupPref);
        #}
    } else {
        my $backupDest = "";
        if( uc($backupMode) ne "NONE") {
            if( uc($backupMode) eq "REMOTE") {
                $backupDest = $ftpFolder ."/" . $baseProp;
                mkpath($backupDest);
            } else {
                $backupDest = $backupDir . "/" . $baseProp;
                mkpath($backupDest);
            }
        }
        
        my $bDoRemote = 0;
        my $bDoArchive = 0;

        foreach my $directory (@sortedDirList) {
            if( uc($backupMode)eq "NONE") {
                if(checkIfCanBeDeleted($directory,$numdays)) {
                    rmtree($directory) or logMessage($! . " can't delete ". $directory);
                }
                next;
            } else {
                if(checkIfCanBeDeleted($directory,$numdays)) {
                    mkpath($backupDest ."/" . basename($directory));

                    if(!Move($directory,$backupDest ."/".  basename($directory)) ) {
                        logMessage("Error moving $directory ... $!");
                    }

                    if(uc($backupMode) eq "REMOTE") {
                        $bDoRemote = 1;
                        $bDoArchive = 1;
                        logMessage("removing $directory");
                    } elsif(uc($backupMode) eq "LOCAL") {
                        $bDoArchive = 1;
                        logMessage("removing $directory");
                    } else {
                        rmtree($backupDest . "/" .  basename($directory)); # remove the entire directory
                        logMessage("removing $directory");
                    }
                } else {
                    last;
                }
            }
       }

    if($bDoArchive eq 1) {
        my $archiveName = "";
        if($bDoRemote eq 1) {
            $archiveName = createArchive($ftpFolder,$backupDest);
            if(!Move($archiveName,$ftpFolder)) {
                logMessage("Error moving $archiveName ... $!");
            }
        } else {
            $archiveName = createArchive($backupDir,$backupDest);
            if(! Move($archiveName,$backupDir)) {
                logMessage("Error moving $archiveName ... $!");
            }
        }
        rmtree($backupDest);
    } 
    #else {
        #rmtree($backupDest);
    #}

    #if($DoRemote eq 1) {
    #$retCode  = doFTP($ftpFolder,\%cleanupPref);
    #}
    }
    return $retCode;
}

###########################################################################################
# this function does all the processing
# here we set the necessary parameters to do the sort of processing we want
# Check for appropriate rights
# get the sorted list of either files or directories based on the flag
# Do respective processing

sub doProcessing {
    my$ retCode =0;
    my($baseProp,$dir,$fileCount,$backupDir,$retentionTime,$backupMode,$bDoDirCleanup,$extension,$cleanupPrefRef) = @_;
    my %cleanupPref = %$cleanupPrefRef;

    if( -d $dir) {
        #directory exists
        #check if we have appropriate permissions to do our work in there!
        my $isPermissionOk = isPermOk($dir);

        if($isPermissionOk eq 1 ) {
            #Get the file list sorted by mtime(last modified time)
            my $sortedDirList;
            if(uc($bDoDirCleanup) eq "FILES") {
                $sortedDirList = getSortedFileList($dir,$extension);
            } else {
                $sortedDirList = getSortedDirList($dir,$extension);
            }

            #check if we need to be count based?
            if($fileCount > 0){
                # we have the count of the number of files to be retained
                $retCode = doCountBasedProcess($baseProp,$fileCount,$sortedDirList,$backupDir,$backupMode,$bDoDirCleanup,\%cleanupPref);
            } else {
                if($retentionTime > 0) {
                    $retCode = doTimeBasedProcess($baseProp,$retentionTime,$sortedDirList,$backupDir,$backupMode,$bDoDirCleanup,\%cleanupPref);
                } else {
                    logMessage("Both count and retention time cannot be 0 or either one of them has to be defined");
                }
            }

        } else {
            #we don't have correct permissions
            logMessage("The directory specified $dir does not carry appropriate permissions");            
        }
    } else {
        logMessage("The directory specified $dir does not exist");
    }
    return $retCode;
}

###########################################################################################
# this function will do processing based on the preocess request type
# whether we are count based or retention time based in days
# The flow is split in this main processing function

sub ProcessRequest {
    my $retCode = 0;
    my($baseProp,$dir,$fileCount,$backupDir,$retentionTime,$backupMode,$bDoDirCleanup,$extension,$cleanupPrefRef) = @_;
    my %cleanupPref = %$cleanupPrefRef;
    my @dirs = <${dir}>; # Do for all directories matching the pattern

    foreach my $matchingDir (@dirs) {
        my $temp = doProcessing($baseProp,$matchingDir,$fileCount,$backupDir,$retentionTime,$backupMode,$bDoDirCleanup,$extension,$cleanupPrefRef);
        $retCode = $temp if ($temp != 0); # See error code if any time processing returns error
    }
    return $retCode;
}

###########################################################################################
# this function checks if we are authentic ones to perform the action of cleanup
# if we are not the ones we would quit silently
# the user should refer to execution log.
sub isPermOk {
    my $path = shift;
    my $info = stat($path);
    return 0 unless $info;
    my $statMode = $info->mode & 0777;


    #first case if I am the owner of the file
    if($info->uid == $<) {
        return 1; # I can delete it
    } else {
        #if i am not the owner and I am the group
        if($info->gid == $() {
            # I am in the group
            # check if group has write or execute permission
            if(($statMode & 020) || ($statMode & 010)) {
                # write or execute permission
                return 1;
            } else {
                return 0;
            }
        } else {
            #we are neither owner nor group
            #check if other has write or execute
            if(($statMode & 002) || ($statMode & 001)) {
                return 1;
            } else {
                return 0;
            }
        }
    }
  return 0;
}


###########################################################################################
# the main configuration file parser

sub parseConfigFile {
    open(FH, $CONFIGFILE) or die "could not open $CONFIGFILE for reason $!";
    my %cleanupPrefs = ();
    while (<FH>) {
        chomp;                  # no newline
        s/#.*//;                # no comments
        s/^\s+//;               # no leading white spaces
        s/\s+$//;               # no trailing white spaces
        next unless length;     # anything left?

        if ($_ =~ /^cleanupapp/) {
            
            # read multi line cc
            if ($_ =~ s/\\$//) {
                $_ .= <FH>;
                redo unless eof(FH);
            }

            my ($var, $value) = split(/\s*=\s*/, $_, 2);

            if( uc($var) eq "CLEANUPAPP.PROPLIST") {
                @listOfProps = split(/,/,$value);
            }
            $cleanupPrefs{uc($var)} = $value; #fill the hash
        }
    }
    return \%cleanupPrefs;
}

###########################################################################################
#will return 1 if we need to cleanup
sub checkDiskStatus {

    my($partitionName,$cleanupPrefRef) = @_;
    my %cleanupPref = %$cleanupPrefRef;
    my $retCode = 0;

    my $baseProp = "cleanupapp.disc.";
    my $propalertWarning = $baseProp . "warning";
    my $propalertCritical = $baseProp. "Critical";

    my $alert1 = $cleanupPref{uc($propalertWarning)} ;        #Warning level free space below 30%
    my $alert2 = $cleanupPref{uc($propalertCritical)};        #Critical level free space below 10%

    my ($size,$used,$avail,$use,$mounted);
    my $message;
    my @list;
    my $sysname = `/bin/uname -n`;
    chomp $sysname;
    my @df = `/bin/df $partitionName`;
    my $df;

    foreach $df (@df) {
        if ($df =~ /^\//s) {
            @list = split(/\s+/, $df);
        } else {
            next;
        }
    }

    # Check the usage
    my $diskfree = (($list[3]) / ($list[2]+$list[3])) * 100.00;

    # Round the number off to 2 decimals
    $diskfree = sprintf("%.2f", $diskfree);

    # See if free disk space is below any of our levels
    if ( ($diskfree < $alert1) && ($diskfree > $alert2) ) {
        $message = "Warning Diskspace threshold reached...free space below $alert1% at $diskfree%\n";
    } elsif ( ($diskfree < $alert1) && ($diskfree < $alert2) ) {

            $message = "Critical Diskspace threshold reached...free space below $alert2% at $diskfree%\n";
            # here we are at critical phase and we need to be going to warning phase less critical phase

            my $totalPercentToFree = $alert1 + $alert2;
            my $totalSizeFreeReqd = sprintf "%.0f", ($list[2]+$list[3]) * $totalPercentToFree / 100.00;

            $retCode = $totalSizeFreeReqd - $list[3];
    } else {
        $message = "Free diskspace is good at $diskfree%\n";
    }

    logMessage($message);
    logMessage("~" x 75, "\n@df","~" x 75,"\n","From system: $sysname");
    return $retCode;
}

###########################################################################################
#logging functionality

sub timeString {
    my ($tm) = @_;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($tm);
    return sprintf("%04d-%02d-%02d_%02d:%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);
}

###########################################################################################
#basic logging functionality

sub logMessage {
    my ($text) = @_;
    my $time = timeString time;
    # log to logfile.
    print "[$time] $text\n";
}

###########################################################################################
# this function will create the archive folder
# this is required to store data before we delete it basically for ftp purposes

sub createArchive {
    my ($backupdir,$dirName) = @_; # this is the directory whose contents need to be zipped
    my $time = timeString time;
    my $zipName = $backupdir. "/" . basename($dirName) . "." . $time . ".zip";
    logMessage("Creating zip file $zipName");
    my $cwd = cwd();
    chdir($dirName);
    system("zip -q -r $zipName *");
    rmtree($dirName);
    chdir($cwd);
    return $zipName;
}

###########################################################################################
# this function will move a folder or files
sub Move {
    my($source,$dest) = @_;
    system("mv -f $source $dest");
    if (($? == -1) || ($? & 127) > 0) {
        logMessage(" failed to move $source to $dest: " . ($? & 127));
        return 0;
    }
    return 1;
} 

###########################################################################################
#ftp capability
#sub doFTP {
#   my($localDir,$cleanupPrefRef) = @_;
#   my %cleanupPref = %$cleanupPrefRef;
#
#   # list of preperties
#   my $baseProp        = "cleanupapp.ftp.";
#   my $propdirectory   = uc($baseProp . "directory");
#   my $propServer      = uc($baseProp . "server");
#   my $proplogin       = uc($baseProp . "login");
#   my $proppassword    = uc($baseProp . "password");
#   my $propputdir      = uc($baseProp . "DestDir");
#
#
#   my $ftp;
#   my $newerr;
#   my @files;
#   my $file;
#   my $filecount;
#   my $line;
#   my $date;
#   my $directory = "";
##  if($localDir ne "") {
#       $directory = $localDir;
#   } else {
#       $directory = $cleanupPref{$propdirectory};
#   }
#
#   chdir($directory) or die("$! Can't cd to $directory");
#   @files=();
#   $newerr=0;
#   logMessage("Starting to FTP");
#   foreach(<*.zip>) {
#       push @files,$_;
#   }
#
#   $filecount=@files;
#   logMessage($filecount . "files to transfer");
#   if  (not $filecount) {
#       logMessage("Nothing to do");
#       return 1;
#   }
#
#   my $destination = $cleanupPref{$propServer};
#   $ftp = Net::FTP->new($destination,Timeout=>240) or $newerr=1;
#   if ($newerr) {
#       logMessage("Can't connect to ". $destination);
#       return 0;
#   }
#
#   my $login = $cleanupPref{$proplogin};
#   my $password = $cleanupPref{$proppassword}; #TODO this needs to be encrypted
#   $ftp->login($login,$password) or $newerr=1;
#   if ($newerr) {
#       logMessage("Can't login ". $destination . "with ". $login,$password);
#       $ftp->quit;
#       return 0;
#   }
#   $ftp->binary(); # set binary mode
#
#   my $putdir = $cleanupPref{$propputdir};
#   $ftp->mkdir($putdir,1); #make recusrisve directory
#   $ftp->cwd($putdir) or $newerr=1; 
#   if ($newerr) {
#       logMessage("Can't cd to ". $putdir . "on ".  $destination);
#       $ftp->quit;
#       return 0;
#   }
#
#   foreach(@files) {
#       $file=$_;
#       $newerr=0;
#       $ftp->put($file,$file) or $newerr=1;
#       if ($newerr) {
#           logMessage("Error transferring ". $file);
#           $ftp->quit;
#           return 0;    
#       }
#       unlink($file) or logMessage($! . " can't unlink ". $file);
#   }
#   return 1;
#}

###########################################################################################
# this function executes the SFPT protocol
# We use this implementation as other perl implementation under NET::SFTP::*
# have not give reliable transfers, so we better rely on the local unix
# sftp implementation

#sub doSFTP {
#   # set your username/password here
#
#   my($localDir,$cleanupPrefRef) = @_;
#   my %cleanupPref = %$cleanupPrefRef;
#
#   # list of preperties
#   my $baseProp        = "cleanupapp.ftp.";
#   my $propdirectory   = uc($baseProp . "directory");
#   my $propServer      = uc($baseProp . "server");
#   my $proplogin       = uc($baseProp . "login");
#   my $proppassword    = uc($baseProp . "password");
#   my $propputdir      = uc($baseProp . "DestDir");
#   my $proptimeOut     = uc($baseProp . "TimeOut");
#
#   my $sftpUsername = $cleanupPref{$proplogin} ;
#   my $sftpPassword = $cleanupPref{$proppassword}; 
#   my $sftpServer   = $cleanupPref{$propServer};
#   my $timeout      = $cleanupPref{$proptimeOut};
#   my $remoteDir    = $cleanupPref{$propputdir};
#
#   my $directory = "";
#   if($localDir ne "") {
#       $directory = $localDir;
#   } else {
#       $directory = $cleanupPref{$propdirectory};
#   }
#
#   chdir($directory) or die("$! Can't cd to $directory");
#   my @files=();
#   logMessage("Starting to SFTP");
#   foreach(<*.zip>) {
#       push @files,$_;
#   }
#
#   # If sftp is not in your path replace with absolute path of sftp program
#   my $command = 'sftp';
#   my $params = ("$sftpUsername\@$sftpServer");
#
#   # Create the Expect object
##  my $exp = Expect->spawn($command, $params) or die "Cannot spawn sftp command \n";
#
#   # If this is the first time you are running this , expect will send "yes" to add the key
#   # for the sftp server to the ~/.ssh/known_hosts file else
#   # wait for "Password Authentication" string to show up
#   $exp->expect($timeout,
#       ["Password Authentication"],
#       ["Are you sure you want to continue connecting", sub {my $self = shift; $self->send("yes\n");}]
#       );
#
#   # Wait for Password prompt to show up 
#   $exp->expect($timeout, ["Password:"]);
#
#   # Sent the sftp password 
#   $exp->send("$sftpPassword\n");
#
#   # Wait for sftp prompt
#   $exp->expect($timeout, ["sftp>"]);
#
#   #create the remote directory
#   $exp->send("mkdir $remoteDir\n");
#   foreach(@files) {
#       my $file=$_;
#       $exp->send("put -p -r $directory . "/" .$file $remoteDir ."/" . $file \n");
#       $exp->expect($timeout, ["sftp>"]);
#       unlink($file) or logMessage($! . " can't unlink ". $file);
#   }
#
#   # Wait for sftp prompt
#   $exp->expect($timeout, ["sftp>"]);
#
#   # Close ftp session
#   $exp->send("bye\n");
#
#   # Destroy the expect object
#   $exp->soft_close();
#}
