#!/usr/local/bin/perl
# 
# $Header: emdb/sysman/admin/scripts/db/sgastart.pl /st_emdbsa_11.2/3 2010/03/17 12:05:30 pbhogara Exp $
#
# sgastart.pl
# 
# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 
#
#    NAME
#      sgastart.pl - Script to start SGA collector
#
#    DESCRIPTION
#      This script is called by the Collections Manager to start the
#      SGA Collector
#
#    NOTES
#      -
#
#    MODIFIED   (MM/DD/YY)
#    pbhogara    03/05/10 - Use native make for HPUX platforms
#    pbhogara    05/14/09 - Change permissions on advert_dir
#    pbhogara    01/30/09 - Check if rdbms group owner is set
#    jsoule      05/23/07 - use EMSTATE for ADVERTDIR, at times
#    jsoule      05/10/07 - use version 11 libraries
#    jsoule      11/30/06 - link nmccollector using target db binaries
#    jsoule      10/10/06 - version-specific linking
#    hopark      09/01/06 - relink nmccollector everytime, use libclntsh from
#                           the target db
#    ysun        07/05/06 - move c code to emagent
#    hopark      03/06/06 - add libgeneric 
#    hopark      02/27/06 - turn off SGA by default 
#    hopark      06/27/05 - fix advert_dir permission 
#    hopark      06/21/05 - put nmc.status under the same advert_dir as other files.
#    jsoule      06/06/05 - do not start collector in resume on NT. 
#    jsoule      05/24/05 - use correct libserver10 
#    hopark      05/14/05 - Fix ownership and mode of the collection directory 
#    hopark      05/09/05 - grabtrans 'hopark_bug-4258298' 
#                           add enable/disable collector 
#    zsyed       04/17/05 - Changing to work in GRID_AGENT_VIEW 
#    zsyed       02/07/05 - Removing inverted commas for NT 
#    zsyed       11/22/04 - Removing references to emdw 
#    zsyed       09/28/04 - Fixing Solaris collector startup problem 
#    zsyed       08/23/04 - Creation
# 

#########################
# Declare packages to use
#########################

require "emd_common.pl";
require "semd_common.pl";
require "$ENV{EMDROOT}/sysman/admin/scripts/db/db_common.pl";
require "$ENV{EMDROOT}/sysman/admin/scripts/db/sgapid.pl";
use POSIX;
use vars qw($NT);

########################
# Declare variables
########################
$debug = EMAGENT_isPerlDebugEnabled();

$collmode = trim($ARGV[0]);
$connstr = trim($ARGV[1]);
$machname = trim($ARGV[2]);
$portname = trim($ARGV[3]);
$sidname = trim($ARGV[4]);

my %stdinArgs = get_stdinvars();
$username = $stdinArgs{"EM_TARGET_USERNAME"};
$password = $stdinArgs{"EM_TARGET_PASSWORD"};

$targetorahome = trim($ARGV[5]);
$ENV{TARGETORACLE_HOME}=$targetorahome;
$myorahome = trim($ENV{'ORACLE_HOME'});
$myversion = trim($ENV{'EM_TARGET_VERSION'});
$emdhome = trim($ENV{'EMDROOT'});

$cmd = "";
$resume = 0;
$numArgs = $#ARGV + 1;
if ($numArgs > 7) {
   $cmd = trim($ARGV[7]) ;
   $resume = ($cmd eq "resume");
}


if($emdhome eq "")
{
  $emdhome = $myorahome;
}

$msg_dir = $emdhome."/mesg/";

if (defined($ENV{EMSTATE}))
{
  $nmcstate = $ENV{EMSTATE};
}
else
{
  $nmcstate = $emdhome;
}

if ($nmcstate ne $myorahome && $nmcstate =~ /_$sidname/)
{
  ################################
  # use EMSTATE if it is different from the agent's oracle home, but specific
  #  to the instance sid of the target...
  ################################
  chdir($nmcstate) || die "Cannot chdir $nmcstate: $!";

  $advert_dir = $nmcstate."/";
}
else
{
  ################################
  # otherwise create advert_dir under myorahome
  ################################
  $firstdir = $machname."_".$sidname;

  chdir($myorahome) || die "Cannot chdir $myorahome: $!";

  if(!(-d $firstdir))
  {
    mkdir($firstdir, 0750) || die "Cannot mkdir $firstdir: $!";
  }

  chdir($firstdir) || die "Cannot chdir $firstdir: $!";

  $advert_dir = $myorahome."/".$firstdir."/";
}

$seconddir = "sysman";
$thirddir = "log";

if(!(-d $seconddir))
{
  mkdir($seconddir, 0750) || die "Cannot mkdir $seconddir: $!";
}

chdir($seconddir) || die "Cannot chdir $seconddir: $!";

if(!(-d $thirddir))
{
  mkdir($thirddir, 0750) || die "Cannot mkdir $thirddir: $!";
}
chdir($thirddir) || die "Cannot chdir $thirddir: $!";

$advert_dir .= $seconddir."/".$thirddir."/";

# Check to see if nmccollector exists
# If it doesn't, create it

if($NT)
{
   $groupname = 'ORA_DBA';
} else {
    $groupname = trim($ENV{'RDBMS_GROUP_OWNER'});
    if($groupname eq '')
    {
      # If RDBMS_GROUP_OWNER is not set by the user then
      # set the group name to 'dba' by default.
      $groupname = 'dba';
    }
    $uid = POSIX::getuid();
    $gid = getgrnam($groupname);
    if (!chown ($uid, $gid, $advert_dir))
    {
      EMAGENT_PERL_WARN("couldn't chown $advert_dir.");
    }
    # Originally, the permissions on the advert_dir were set with
    # write permissions for the group.  This should not be
    # necessary: an agent --installed as another user in the same
    # group-- which shares a running nmccollector should not be
    # writing to the advert_dir.
    # Note: in testing this fix, it was discovered that this sharing
    # is not happening (GC 10.2.0.5 agent trying to share the
    # nmccollector of a DBC 11.2 agent) due to insufficient access
    # privileges on the shared memory segment when the agent is a
    # different user (in the same group) from the one of the
    # nmccollector.  This needs to be investigated further.

    if (!chmod (0750, $advert_dir))
    {
      EMAGENT_PERL_WARN("couldn't chmod $advert_dir.");
    }
}  

$tracefile = $advert_dir . "sgastart.trc";

$ttfile = $advert_dir . "nmc.debug";
if (-e $ttfile){
   $debug = 1;
}

TRACE("------ sgastart ".$cmd);
TRACE("ARG0 : ".$ARGV[0]);
TRACE("ARG1 : ".$ARGV[1]);
TRACE("ARG2 : ".$ARGV[2]);
TRACE("ARG3 : ".$ARGV[3]);
TRACE("ARG4 : ".$ARGV[4]);
TRACE("ARG5 : ".$ARGV[5]);
TRACE("ARG6 : ".$ARGV[6]);
TRACE("ORACLE_HOME : ".$ENV{'ORACLE_HOME'});
TRACE("EMDROOT : ".$ENV{'EMDROOT'});
TRACE("advert_dir : $advert_dir");

####################################################
# Check to see if the collector is disabled
####################################################
$statusfile = $advert_dir . "nmc.status";
TRACE("statusfile : $statusfile");

################################
## This status setting is ignored.
################################
$status = "disable";

if ($resume == 0) {
  EMAGENT_PERL_DEBUG("using status from $statusfile");
  open(SFP, $statusfile);
  $status = <SFP>;
  close(SFP);
} else {

  ################################
  ## resume: (== enable:)
  ################################
  EMAGENT_PERL_DEBUG("resuming SGA metric collection");
  $status = "enable";
}

if ($status eq "stopped") {
  # The collector has been stopped by other process, 
  # but failed to kill the process.
  EMAGENT_PERL_DEBUG("Collector was stopped, killing running process...");
  $rpidval = getsgapid($emdhome, $connstr);
  $result = killCollector($rpidval, $statusfile);
  $status = "disable";
}

if($status =~ m/ERROR/ || $status eq "") {
  # This is the default behavior
  $status = "disable";
  EMAGENT_PERL_DEBUG("falling back to default status: $status");
}
TRACE("status = ". $status);
EMAGENT_PERL_INFO("status = $status");

if ($cmd eq "status") {
  ################################
  ## status:
  ################################
  TRACE("em_result =  ". $status);
  print "em_result=";
  print $status;
  EMAGENT_PERL_DEBUG("requesting status only; exiting.");
  exit;
}

####################################################
# Check to see if someone is monitoring DB already
# If so, exit
####################################################
$rpidval = getsgapid($emdhome, $connstr);

if ($cmd eq "stop") {
  ################################
  ## stop:
  ################################
  EMAGENT_PERL_DEBUG("stopping nmccollector...");
  $res = killCollector($rpidval, $statusfile);
  if ($res == -1) {
    EMAGENT_PERL_DEBUG("no nmccollector process");
    $result = "no nmccollector process"; 
  } elsif ($res == 0) {
    EMAGENT_PERL_DEBUG("failed to kill nmccollector [pid=$rpid]");
    $result = "failed to kill nmccollector pid=" . $rpid; 
  } elsif ($res == 1){
    EMAGENT_PERL_DEBUG("killed nmccollector [pid=$rpid]");
    $result = "killed nmccollector pid=" . $rpid; 
  }
  TRACE("em_result=".$result);
  print "em_result=";
  print $result;
  EMAGENT_PERL_DEBUG("nmccollector stopped; exiting.");
  exit;
}

if ($status eq "disable") {
  ################################
  ## disable:
  ################################
  $result = "collector is disabled.";
  TRACE("em_result=".$result);
  print "em_result=";
  print $result;
  EMAGENT_PERL_DEBUG("nmccollector disabled; exiting.");
  exit;
}

################################
## enable:
################################
writeStatus($statusfile, "enable");

if (!($rpidval eq "")) {
  ################################
  ## nmccollector process found; don't restart it.
  ################################
  $result = "collector has already started. pid=".$rpidval;
  TRACE("em_result=".$result);
  print "em_result=";
  print $result;
  EMAGENT_PERL_DEBUG("nmccollector is alread running [pid=$rpidval]; exiting.");
  exit;
}

if($NT) {
   if ($resume) {
      TRACE("collector will start in next sga_start.");
      $result = "enabled.";
      TRACE("em_result=".$result);
      print "em_result=";
      print $result;
      exit;
   }
}

###############################################################
# If process not found, then collector ought to be (re)started
###############################################################
TRACE("collector not found. restarting it.");
EMAGENT_PERL_INFO("nmccollector not found; restarting it...");

chdir($advert_dir) || die "Cannot chdir $advert_dir: $!";
EMAGENT_PERL_DEBUG("current working directory: $advert_dir");

if($NT)
{
  $binhome = $emdhome."/bin/nmccollector ".$collmode." ".$connstr." ".$advert_dir." ".$advert_dir." ".$msg_dir;
}
else
{
  # In order to support database upgrade, relink it everytime this script 
  # is invoked.  
  my $makefilename;
  my $libserverloc = $targetorahome;
  my $makedestloc  = $myorahome;
  my $makebinary;
  my $uname = `uname`;
  chomp ($uname);
  if($uname =~ m/HP-UX/)
  {
    $makebinary = '/usr/ccs/bin/make';
  }
  else
  {
    $makebinary = 'make';
  } 

  EMAGENT_PERL_INFO("nmccollector does not exist; relinking...");
  TRACE("nmccollector does not exist. building...");
    
  $makefilename1 = $myorahome."/sysman/lib/ins_emagent.mk";
  $makefilename2 = $myorahome."/emagent/lib/ins_emagent2.mk";
    
  TRACE("looking for $makefilename1");
  TRACE("looking for $makefilename2");
  if(-e $makefilename1)
  {
    TRACE("makefile $makefilename1");
    $makefilename  = $makefilename1;
    $libserverloc .= "/lib/";
    $makedestloc  .= "/bin/";
  }
  elsif(-e $makefilename2)
  {
    TRACE("makefile $makefilename2");
    $makefilename  = $makefilename2;
    $libserverloc .= "/rdbms/lib/";
    $makedestloc  .= "/emagent/bin/";
  }
  else
  {
    EMAGENT_PERL_ERROR("cannot find emagent install makefiles in $makefilename1 or $makefilename2; exiting.");
    die "Cannot find ins_emagentx makefiles in $makefilename1 or $makefilename2";
  }

  my $libclientline;
  my $libversion;
  if ($myversion ne "10gR203")
  {
    ################################
    ## For 11g and later, we need to link with the 11g client library
    ##  and with LD_LIBRARY_PATH set specially.
    ################################
    my $oldlibpath = trim($ENV{'LD_LIBRARY_PATH'});
    $ENV{'LD_LIBRARY_PATH'} = $targetorahome."/lib:".$oldlibpath;
    $libclientline =
      " \"LIBCLNTSH=".$targetorahome."/lib/libclntsh.so\" ";

    $libversion = "11";
  }
  else
  {
    $libclientline = "";
    $libversion = "10";
  }

  $dsgaline =
    " \"DSGALIB=".$targetorahome."/rdbms/lib/libdsga$libversion.a\" ";
  $libserverline =
    " \"LIBSERVER=".$libserverloc."libserver$libversion.a\" ";
  $linkline = " \"RDBMSLIBHOME=".$targetorahome."/lib/\" ".
              " \"RDBMSORACLELIB=-L".$targetorahome."/lib/\" ";
  $makecommand = "$makebinary -f ".$makefilename." collector ".$libclientline.$dsgaline.$libserverline.$linkline;
  EMAGENT_PERL_DEBUG("issuing make command [$makecommand]");
  EMAGENT_PERL_DEBUG('$ORACLE_HOME: '.$ENV{'ORACLE_HOME'});
  EMAGENT_PERL_DEBUG('$ORA_SID: '.$ENV{'ORA_SID'});
  EMAGENT_PERL_DEBUG('$ORACLE_SID: '.$ENV{'ORACLE_SID'});
  EMAGENT_PERL_DEBUG('$LD_LIBRARY_PATH: '.$ENV{'LD_LIBRARY_PATH'});
  if (system($makecommand))
  {
    EMAGENT_PERL_ERROR("nmccollector relinking failed!");
  }
  else
  {
    $movecommand = "mv ".$makedestloc."nmccollector nmccollector";
    EMAGENT_PERL_DEBUG("issuing mv command [$movecommand]");
    system($movecommand);
  }

  my $nmcbinary = "./nmccollector";
  if (!(-e $nmcbinary))
  {
    ################################
    ##  There is no nmccollector binary to run.  Might as well exit.
    ################################
    EMAGENT_PERL_ERROR("nmccollector does not exist");
    exit;
  }
  
  $binhome = $nmcbinary." ".$collmode." \'".$connstr."\' ".$advert_dir." ".$advert_dir." ".$msg_dir;
  
  $ENV{'ORACLE_HOME'} = $targetorahome;
  $ENV{'ORA_SID'} = $sidname;
  $ENV{'ORACLE_SID'} = $sidname;

  $oldlibpath = trim($ENV{'LD_LIBRARY_PATH'});
  $newlibpath = $targetorahome."/lib:".$oldlibpath;

  $ENV{'LD_LIBRARY_PATH'} = $newlibpath;
}

################################
## We haven't aborted or exited normally so far.  That must mean that the
##  nmccollector should be started up.
################################
TRACE($binhome);
if(!$NT)
{
  EMAGENT_PERL_DEBUG("spawning nmccollector");
  if (!defined($child_pid = fork()))
  {
    die "cannot fork: $!";
  } 
  elsif ($child_pid) 
  {
    ################################
    ##  Note: This is not the nmccollector process.  Rather, it's the process
    ##        that spawns the nmccollector process below.
    ################################
    EMAGENT_PERL_DEBUG("nmccollector spawner process [pid=$child_pid] spawned; parent process exiting.");
    TRACE("em_result=$child_pid");
    print "em_result=";
    exit;
  }
  else 
  {
    ################################
    ## This is the spawned child.
    ################################
    sleep 10;
    
    POSIX::setsid() or die "Can't start a new session: $!";
    umask(027);
    
    close STDIN or die "Can't close STDIN";
    close STDOUT or die "Can't close STDOUT";
    close STDERR or die "Can't close STDERR";
    
    $ENV{'ORACLE_HOME'} = $targetorahome;
    $ENV{'ORA_SID'} = $sidname;
    $ENV{'ORACLE_SID'} = $sidname;

    EMAGENT_PERL_DEBUG("execing nmccollector [$binhome]...");
    EMAGENT_PERL_DEBUG('$ORACLE_HOME: '.$ENV{'ORACLE_HOME'});
    EMAGENT_PERL_DEBUG('$ORA_SID: '.$ENV{'ORA_SID'});
    EMAGENT_PERL_DEBUG('$ORACLE_SID: '.$ENV{'ORACLE_SID'});
    EMAGENT_PERL_DEBUG('$LD_LIBRARY_PATH: '.$ENV{'LD_LIBRARY_PATH'});

    my $nmcpid = open(PROCWRITE, "| ".$binhome);
    if (!defined($nmcpid))
    {
      EMAGENT_PERL_ERROR("could not exec nmccollector; exiting.");
      die "Could not start collector";
    }
    elsif ($nmcpid)
    {
      ################################
      ## Note: Just because we got here doesn't mean necessarily that the
      ##       exec-ed process will run properly.
      ##       But if it does, this trace line tells us the pid.
      ################################
      EMAGENT_PERL_DEBUG("nmccollector exec-ed [pid=$nmcpid]");
      print PROCWRITE $username." ".$password." ";
    }
    close(PROCWRITE);
  }
}
else
{
  require Win32::Process;

  close STDIN or die "Can't close STDIN";
  close STDERR or die "Can't close STDERR";
  
  pipe(READ, WRITE);  
  
  select(WRITE); 
  $| = 1; 
  select(READ);
  $| = 1;
  
  open(STDIN, "<&READ") or die "Can't redirect STDIN: $!"; 
  
  open(BLAH, ">BLAH.TXT");
  print BLAH $binhome;
  print BLAH $emdhome;
  close(BLAH);
  
  Win32::Process::Create($Process, 
			 $emdhome."/bin/nmccollector.exe",
			 $binhome, 
			 1, 
			 NORMAL_PRIORITY_CLASS,
			 "."); 
  print WRITE "$username $password ";
  print WRITE "\n";
  
  close READ or die "Can't close pipe READ: $!"; 
  close WRITE or die "Can't close pipe WRITE: $!"; 
  close STDOUT or die "Can't close STDOUT";
}

sub killCollector {
  my $rpid = $_[0];
  my $sfile = $_[1];
  EMAGENT_PERL_DEBUG("killing collector $rpid");
  $res = -1;
  if ($rpid != "") {
    $res = kill 9, $rpid;
  }
  if ($res) {
    EMAGENT_PERL_DEBUG("nmccollector stopped and killed");
    writeStatus($sfile, "disable");
  } else {
    EMAGENT_PERL_DEBUG("nmccollector stopped but not killed");
    writeStatus($sfile, "stopped");
  }
  return $res;
}
   
sub writeStatus {
   my $sfile = $_[0];
   my $s = $_[1];
   TRACE("writing ". $s ." in statusfile $sfile");
   open(SFP, ">$sfile");
   print SFP $s;
   close(SFP);
}
   

