#!/usr/local/bin/perl
# 
#
# olfsroot.pl
# 
# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
#
#    NAME
#      olfsroot.pl - <one-line expansion of the name>
#
#    DESCRIPTION
#      <short description of component this file declares/defines>
#
#    NOTES
#      <other useful comments, qualifications, etc.>
#
# 

my ($KVER);
my ($ARCH) = `uname -i`;                        # Machine architecture - i386
chomp($ARCH);
my ($UNAME_R) = `uname -r`;
chomp($UNAME_R);

our ($ORACLE_HOME) = $ENV{ORACLE_HOME};

my  ($SHIPHOME_BASE_DIR) = "$ORACLE_HOME/usm/install";
our ($OLFS_DFLT_CMD_LOC)  = "$SHIPHOME_BASE_DIR/cmds/bin";
our ($OLFS_DFLT_DRV_LOC);
my ($SBIN_DIR)         = "/sbin";
my ($DRIVER_DIR);
my ($COMMAND) = "No Command Specified";

use constant USM_SUCCESS            => 0;
use constant USM_FAIL               => 1;

use strict;
use Getopt::Std;
use Cwd 'abs_path';
use File::Basename;
use English;
use Config;
use File::Path;

main();

sub get_olfs_driver_dir
{
    my ($driver_build_version); # version that the driver was linked for.

    $driver_build_version = $UNAME_R;

    return "/lib/modules/$driver_build_version/extra/oracle";
}

sub olfsroot_exit
{
  my ($ret) = @_;

  exit $ret;
}

sub main
{
  my ($sub_command);         # start or stop
  my ($return_code);         # as the name implies 
  # user options
  my (%opt);                 # user options hash - used by getopts()
                             # -h : help

  # user flags. See description above or usage message output
  my (%flags) = ( load      => 'h',
                  unload    => 'h',
                  repltree  => 'h',
                );

  # process the command line for acfsutil cmdlog
  # We could just use "acfsutil cmdlog -s @ARGV"
  # but that wouldn't give us the absolute command path name;
  my ($opt, $opts);

  $opts = "";
  foreach $opt (@ARGV)
  {
    $opts = abs_path($0) if $opts eq "";  # command name
    $opts .= " $opt";
  }

  # supplied by the front end driver and 'guaranteed' to be there.
  # command is what the user actually typed in (sans directories).
  $COMMAND = shift(@ARGV);

  # supplied by user
  $sub_command = shift(@ARGV);

  print "sub command is $sub_command\n";

  # must be supplied by the user.
  if (defined($sub_command))
  {
    if (!(($sub_command eq 'load') ||
          ($sub_command eq 'unload') ||
          ($sub_command eq 'repltree')))
    {
      # illegal sub-command
      print "invalid command\n";
      usage("invalid", 0);
      olfsroot_exit(USM_FAIL);
    }
  }
  else
  {
    # no sub-command
    print "No sub command found\n";
    usage("invalid", 0);
    olfsroot_exit(USM_FAIL);
  }

  # parse user options
  %opt=();
  getopts($flags{$sub_command}, \%opt) or usage($sub_command, 1);
  if ($opt{'h'})
  {
    # print help information
    usage($sub_command, 0);
    olfsroot_exit(USM_SUCCESS);
  }

  ##### command parsing complete #####

  if ($sub_command eq 'load')
  {
      $return_code = load();
  }
  else
  {
    if ($sub_command eq 'unload')
    {
        $return_code = unload();
    }
    else
    {
        if ($sub_command eq 'repltree')
        {
            my ($src, $dest);
            $src = shift(@ARGV);
            $dest = shift(@ARGV);

            repltree($src, $dest);
            $return_code = USM_SUCCESS;
        }
    }
  }

  olfsroot_exit($return_code);
} # end main

sub load()
{
    my $command;
    my $ret;
    my $return_code = USM_SUCCESS;

    $DRIVER_DIR = get_olfs_driver_dir();

    $command = "/sbin/insmod $DRIVER_DIR/oracleolfs.ko";
    $ret = system ($command);
    $return_code = USM_FAIL if $ret;

    return ($return_code);

}

sub unload()
{
    my $command;
    my $ret;
    my $return_code = USM_SUCCESS;

    $command = "/sbin/rmmod oracleolfs.ko";
    $ret = system ($command);
    $return_code = USM_FAIL if $ret;

    return ($return_code);
}

sub repltree {
    my $mysrc = $_[0];
    die "Incorrect source directory path ($mysrc) provided" 
        unless -d $mysrc;
    
    my $mydest = $_[1];    
    if (-d $mydest)
    {
        create_dir($mysrc, $mydest, 1);
    }
    else
    {
        if (-f $mydest)
        {
            die "Destination ($mydest) not a directory\n"
        }
        else
        {
            create_dir($mysrc, $mydest, 0);
        }
    }
}

sub create_dir {
    my $src = $_[0];
    my $dest = $_[1];
    my $call_num = $_[2];
    if ($call_num == 0)
    {
        mkdir $dest;
        #print "Creating new directory $dest\n";
    }

    opendir(my $DIR, $src);
    while (my $dirent = readdir $DIR) {
        next if $dirent eq '.' or $dirent eq '..';
        my $new_src = $src . '/' . $dirent;
        my $new_dest = $dest . '/' . $dirent;
        next unless -d $new_src;
        if (-l $new_src)
        {
            #print "Symlink found $new_src and dest is $new_dest\n";
            my $new_link = readlink($new_src);
            #print "Symlink path $new_link\n";
            symlink($new_link, $new_dest);
        }
        elsif (-d $new_dest)
        {
            create_dir($new_src, $new_dest, 1);
        }
        else
        {
            if (-f $new_dest)
            {
                die "Destination ($new_dest) not a directory\n"
            }
            create_dir($new_src, $new_dest, 0);
        }
    }
    closedir $DIR;
}


sub usage
{
    my ($sub_command, $abort) = @_;

    if ($sub_command eq "load")
    {
        print "olfscmd load: Load OLFS kernel driver.\n";
        print "Usage: olfscmd load\n";
    }

    if ($sub_command eq "unload")
    {
        print "olfscmd load: Unload OLFS kernel driver.\n";
        print "Usage: olfscmd unload\n";
    }

    if ($sub_command eq "repltree")
    {
        print "olfscmd repltree: replicate directory structure from src to dest\n";
        print "Usage: olfscmd repltree <srcdir> <destdir>\n";
    }

    if ($sub_command eq "invalid")
    {
        print "olfscmd: Invalid command.\n";
        print "Usage: olfscmd {load | unload | repltree <srcdir> <destdir>} [-h]\n";
    }

    if ($abort)
    {
        olfsroot_exit(USM_FAIL);
    }
}
