#!/usr/local/bin/perl
# 
# $Header: ob.pl 07-oct-2004.13:06:22 pfgavin Exp $
#
# ob.pl
# 
# Copyright (c) 2002, 2004, Oracle. All rights reserved.  
#
#    NAME
#      ob.pl - Perl script for Oracle Backup remote operations.
#
#    DESCRIPTION
#      Remote execution routines for Oracle Backup.
#
#    NOTES
#      <other useful comments, qualifications, etc.>
#
#    MODIFIED   (MM/DD/YY)
#    pfgavin     10/07/04 - rb->ob
#    pfgavin     05/28/04 - pfgavin_oracle-backup-init
#    pfgavin     03/17/04 - Creation
# 

use FileHandle;
use IPC::Open2;
use vars qw/ $OS $NT $S $TEMP $CP $MV $PS $DF $DELIMITER/;

require "emd_common.pl";

$ERROR_CODE = 8;

#
# set_ob_env()
#
# If the perl script is run in an ade environment then
# look for the env script in the temp dir. This script fille
# will set the nessessary environment variables to access
# the ob administrative domain running in a view.
#
sub set_ob_env
{
  EMD_PERL_DEBUG("ob.set_ob_env(): start");
  $rbtmpfile = "/tmp/rbmapvars.sh";
  open rbtmpfile or die "Can't find /tmp/rbmapvars.sh\n";
  while (<rbtmpfile>)
  {
    ($xtra, $varname, $varvalue) = split / /;
    substr($varvalue, 0, 1) = ""; 
    substr($varvalue, -2)   = ""; 
    $ENV{$varname} = $varvalue;
  }
  EMD_PERL_DEBUG("ob.set_ob_env(): end");
}

#
# runOb
#
# Run Oracle Backup CLI and pass output backup up to the OMS.
# 
sub runOb()
{
  EMD_PERL_DEBUG("ob.runOb(): start");
  $? = 0;
  local $SIG{PIPE};
  local $SIG{CHLD};
  if (!$NT)
  {
      # Ignore PIPE signal which might be invoked by "print OB_WRITER .. "
      # If we don't catch it the signal will terminate the script
      $SIG{PIPE} = sub { 
      };
      
      $obExit = 0;
        
      # Reaper to collect ob exit status
      $SIG{CHLD} = sub { 
        if (waitpid($pid, WNOHANG))
        {
           $ob_result = $?;
           $obExit = 1;
        }
      };  
  }

  # Check for obtool in the ob_command string.
  ($rbpath, $other) = split / /, $ob_command;
  EMD_PERL_DEBUG("ob.runOb(): obpath: $rbpath");
  if (!-e $rbpath)
  {
    print "No obtool found: $rbpath\n";
    return -1;
  }

  # Look for ADE env file.
  if (!$NT)
  {
    if (-e "/tmp/rbmapvars.sh")
    {
      set_ob_env();
    }
  }
  else
  {
    #TODO on Windows
  }

  EMD_PERL_DEBUG("ob.runOb(): open2: command: $ob_command");
    
  $pid = open2(\*RDRFH, \*WRITER, "$ob_command 2>&1")
      || ((print "Unable to open the obtool process in run_ob().\n") && (return -1));
  
  # Turn on autoflush for pipe output
  $old_fh = select(RDRFH);
  $| = 1;
  select($old_fh);

  if (!$NT)
  {  
      # set RDRFH non-blocking
      my $flags = '';
      fcntl(RDRFH, F_GETFL(), $flags)
          or die "Couldn't get flags for RDRFH : $!\n";
      $flags |= O_NONBLOCK();
      fcntl(RDRFH, F_SETFL(), $flags)
          or die "Couldn't set flags for RDRFH: $!\n";
  }  

  # Turn on autoflush for standard output
  $old_fh = select(STDOUT);
  $| = 1;
  select($old_fh);

  # Write the password to obtool
  print WRITER $ob_password;

  close WRITER;
  
  $MAX_OUT_SIZE = 7168; #7K
  $cur_out_size = 0;
  $timeout = 0;
  
  if (!$NT)
  {
      # Construct the data structure for select call
      vec($rin, fileno(RDRFH), 1) = 1;
    
      my $bufSize = 100;
      $fullBuf ="";
      
      while (1)
      {
          # wait for reading event on RDRFH, or timeout after 5 seconds
          $a = select($rout=$rin, undef, undef, 5);
        
          if ($a > 0 && vec($rout,fileno(RDRFH),1))
          {
              # There are something in RDRFH for read
            
              $sysret = sysread RDRFH, $buf, $bufSize;
            
              if (defined($sysret))
              {
                  if ($sysret == 0)
                  {
                      # RDRFH is closed by ob
                      last;
                  }
                  else
                  {
                      $fullBuf .= $buf;
                      
                      $cur_out_size += length($buf);
                      print "$buf";
                  }
              }
          }
          else
          {
             # select() times out or detects an error
             if ($timeout > 15)
             {
                # ob has exited as detected by the reaper
              
                # we do a final non-blocking reading in case there are something 
                # in the pipe left by obtool
                while ($sysret = sysread RDRFH, $buf, $bufSize)
                {
                    $fullBuf .= $buf;

                    $cur_out_size += length($buf);
                    print "$buf";
                }    
    
                last;
             } 
             $timeout = $timeout + 5;
          } 
      }
  }
  else
  {
    # NT case
    $fullBuf ="";
    do {
        $sysret = sysread RDRFH, $buf, 100;

        if (defined($sysret))
        {
            $cur_out_size += length($buf);
            print "$buf";
    
            $fullBuf=$fullBuf.$buf;
        }    
        else
        {
            print "An error ocurred when reading from ob: $? $!\n";
            $ob_result = -1;
        }
    } while (defined($sysret) && $sysret != 0);
  
  }  
  
  # xun: close RDRFH after reading is done
  close RDRFH;

  
  if ($NT)
  {
     # On NT, there is no reaper to collect the exit status of obtool.
     # We'll do it here.
     my $wpid = waitpid $pid, 0;
     
     if ($wpid != -1)
     {
        $ob_result = $?;
     }   

     # if waitpid returns -1 (in which case it's a bug for perl), 
     # we'll have to parse the obtool output to determine whether 
     # the operation is successful or not

  }
      
  if ($ob_result != 0)
  {
    $ob_result = -1;
  }

  EMD_PERL_DEBUG("ob.runOb(): end");

  return("0");
}

#runOb();
