#!/usr/bin/perl
#
#
# Notes:
#  should be run by root only
#  fixed location $APL/cache/bin/cachectl
#


use strict;
use warnings;
use File::Basename qw(dirname);


# Load configuration (env may be emtpy on the start)
my $dirname = dirname(__FILE__);
open (ECF,"$dirname/../../base/etc/env.conf")     || die("Cannot read env.conf\n");
map {$ENV{$1}=$2 if /^(\w+)=(\S+)/} grep {/^\w+=\S+/} <ECF>;
close ECF;

# ------------------ VARS -----------------------
my $APL = $ENV{APL} || '/opt/sarch';
my $CMD = $ARGV[0];
my $RETVAL = 1;
my $USAGE = "Usage: cachectl <start|stop|status>\n";
my $CONFFILE = "$APL/cache/etc/cache.cfg";
my $OWNER ="$ENV{APL_USR}:$ENV{APL_HTTPD_GRP}"; # ex: apl:apache
my %CFG;

# ------------------ ROUTINES -------------------
sub announce {
    print "$_[0]...\n";
}

sub complete {
    print $RETVAL?"Failed\n" : "Success\n";
}

sub read_conf {
    open CONF, $CONFFILE or return 0;
    %CFG = map {/^(\w+)=(\S+)/} grep {/^\w+=\S+/} <CONF>;
    close CONF;
    return 1;
}

sub get_memsize() {
    my $physmem = 0;
    open(FREE, "/usr/bin/free -m |") or return 0;
    while(<FREE>) {
	$physmem = $1, last if /^Mem:\s+(\d+)/;
    }
    close FREE;
    return $physmem;
}

sub get_status {
    my ($status, $total, $free) = ('off', 0, 0);
    open(DF, "/bin/df -Pm $CFG{MOUNT_POINT} |");
    while(<DF>) {
	if (/^\S+\s+(\d+)\s+\d+\s+(\d+)\s+\d+%\s+$CFG{MOUNT_POINT}/) {
	    ($status, $total, $free) = ('on', $1, $2, $3);
	    last;
	}
    }
    close DF;
    return wantarray ? ($status, $total, $free) : $status;
}

sub attach {
    return 1 if get_status eq 'on';
    my $physmem = get_memsize;
    my $size = $CFG{MIN_SIZE};
    my $max_size = int(($physmem * (100 - $CFG{OS_RESERVE})) / 100);
    if($CFG{MINSIZE} >= $physmem) {
	warn "Not enough ram!\n";
	return 0;
    }
    $size = $max_size > $CFG{MAXSIZE} ? $CFG{MAXSIZE} : $max_size;
    system("/bin/mount -o noexec,nosuid -t tmpfs tmpfs $CFG{MOUNT_POINT} -o size=${size}M 1>/dev/null 2>&1");
    return 0 if $?;
    #-------- following few operations without error checking
    mkdir("$CFG{MOUNT_POINT}/sm",0755) if not -d "$CFG{MOUNT_POINT}/sm";
    system("/bin/chown $OWNER $CFG{MOUNT_POINT}/sm");
    symlink($CFG{MOUNT_POINT},"/vasm/store/cache") if -d "$CFG{MOUNT_POINT}/sm";
    return 1;
}

sub detach {
    my $status = get_status;
    return 1 unless $status eq 'on';
    unlink("/vasm/store/cache") if -e "/vasm/store/cache";
    system("/bin/umount -t tmpfs $CFG{MOUNT_POINT} 1>/dev/null 2>&1");
    if($?) {	# Try 'lazy' umount if previous operation failed
	system("/bin/umount -t tmpfs -l $CFG{MOUNT_POINT} 1>/dev/null 2>&1");
    }
    return $? ? 0 : 1;
}

sub status {
    print "@{[get_status]}\n";
    $RETVAL = 0;
}

sub start {
    announce "Attaching RAM cache";
    $RETVAL = 1 - attach;
    complete;
}

sub stop {
    announce "Detaching RAM cache";
    $RETVAL = 1 - detach;
    complete;
}

# ------------------ MAIN -----------------------
die $USAGE unless defined $CMD;
die "Unable to read configuration\n" unless read_conf;
die "Mount point doesn't exist\n" unless -d $CFG{MOUNT_POINT};
for($CMD) {
    /^start$/  && do { start ; last };
    /^stop$/   && do { stop  ; last };
    /^status$/ && do { status; last };
    die $USAGE;
}
exit $RETVAL;
