MINI MINI MANI MO

Path : /opt/oracle/product/18c/dbhomeXE/lib/
File Upload :
Current File : //opt/oracle/product/18c/dbhomeXE/lib/osds_okaroot.pm

# 
#
# osds_okaroot.pm
# 
# Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
#
#
#    NAME
#      osds_okaroot.pm - Linux OSD component of okaroot.
#
#    DESCRIPTION
#      Purpose
#          Install/uninstall OKA components.
#
#    NOTES
#      All user visible output should be done in the common code.
#      this will ensure a consistent look and feel across all platforms.
#
#

use strict;
package osds_okaroot;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(
                 osds_fix_oka_wrapper_scripts
                 osds_oka_initialize
                 osds_oka_install_from_distribution_files
                 osds_oka_search_for_distribution_files
                 osds_load_and_verify_oka_state
                 osds_oka_uninstall
                 $MEDIA_FOUND
                 $ORACLE_HOME
                 $OKA_DFLT_DRV_LOC
                 );

use acfslib;
use osds_okalib;
use osds_unix_linux_okalib;
use okalib;
use osds_acfslib;
use osds_acfsroot;

our ($ORACLE_HOME) = $ENV{ORACLE_HOME}; 
my  ($SHIPHOME_BASE_DIR) = "$ORACLE_HOME/usm/install";
our ($USM_DFLT_CMD_LOC)  = "$SHIPHOME_BASE_DIR/cmds/bin"; # cmds media loc
our ($OKA_DFLT_DRV_LOC);                        # location of the drivers media
my  ($MINUS_L_DRIVER_LOC);
our ($MEDIA_FOUND) = '';                        # path name to media
                                                # used for version_check
my ($ARCH)    = `uname -i`;                     # Machine architecture - i386
chomp($ARCH);
my ($UNAME_R) = `uname -r`;
chomp($UNAME_R);

my ($no_init) = "";
$no_init = `/sbin/weak-modules -h | grep ^'--no-init'` if machine_is_RH();
chomp($no_init);

# We do not install/uninstall the commands destined for ORACLE_HOME - that
# is now done by the mapfiles during Oracle install/uninstall. We use
# <XXX>_COMPONENTS only to verify that the commands exist in their
# installed location.
# The exception are the commands destined to live in /sbin. Since OUI
# won't have permissions to copy these commands directly, we do it here.
my ($SBIN_DIR)         = "/sbin";
my ($OH_BIN_DIR)       = "$ORACLE_HOME/bin"; 
my ($OH_LIB_DIR)       = "$ORACLE_HOME/lib"; 
my ($MESG_DST_DIR)     = "$ORACLE_HOME/usm/mesg";
my ($USM_PUB_DST_DIR)  = "$ORACLE_HOME/usm/public"; 
my ($CMDS_SRC_DIR)     = "$SHIPHOME_BASE_DIR/cmds/bin"; 
my ($MESG_SRC_DIR)     = "$SHIPHOME_BASE_DIR/../mesg"; 
my ($USM_LIB_SRC_DIR)  = "$SHIPHOME_BASE_DIR/../lib"; 
my ($USM_PUB_SRC_DIR)  = "$SHIPHOME_BASE_DIR/../public"; 

my (@OH_BIN_COMPONENTS) = (
     "$OH_BIN_DIR/okaroot",      "$OH_BIN_DIR/okaload",
     "$OH_BIN_DIR/okadriverstate",
);

my (@OH_LIB_COMPONENTS) = (
     "$OH_LIB_DIR/okatoolsdriver.sh", "$OH_LIB_DIR/okalib.pm",
     "$OH_LIB_DIR/okaroot.pl",        "$OH_LIB_DIR/osds_okaroot.pm",
     "$OH_LIB_DIR/okaload.pl",        "$OH_LIB_DIR/osds_okaload.pm",
     "$OH_LIB_DIR/okadriverstate.pl", "$OH_LIB_DIR/osds_okadriverstate.pm",
     "$OH_LIB_DIR/osds_okalib.pm",    "$OH_LIB_DIR/osds_unix_linux_okalib.pm",
);

my (@MESG_COMPONENTS) = (
     "$MESG_DST_DIR/okaus.msb",
);

my (@OH_COMPONENTS) = (@OH_BIN_COMPONENTS, @OH_LIB_COMPONENTS);

my ($DRIVER_DIR);              # installed driver location 
my ($minus_l_specified) = 0;   # Alternate install location specified by user.

# set by osds_oka_search_for_distribution_files() and
# consumed by osds_oka_install_from_distribution_files() 
my ($OIP_PATH, $GPL_PATH);

# make sure that /sbin is in the PATH - that's where modprobe lives
$ENV{PATH} .= ':/sbin';

my ($KVER);                              # kernel version being installed

# osds_oka_initialize
#
# Perform OSD initialization.
#   Set OKA_DFLT_DRV_LOC - the location of the OKA installation driver media.
#   We deduce the location of the other components from there.
#
sub osds_oka_initialize
{
  my ($install_kver, $sub_command) = @_;
  my ($vendor);
  my ($type);

  if (!defined($install_kver))
  {
    # use the current kernel version
    $KVER = $UNAME_R;
  }
  else
  {
    # use the specified kernel version
    # TODO we'll want to do some sanity checking here.
    $KVER = $install_kver;
  }

  # we have already verified that we have a valid Linix type
  $type = lib_osds_get_os_type();

  $vendor = lib_osds_get_linux_vendor();

  if (!((defined($ORACLE_HOME)) && (-e "$ORACLE_HOME/lib/okaroot.pl"))) 
  {
    lib_error_print_noalert(9389,
    "ORACLE_HOME is not set to the location of the Grid Infrastructure home.");
    return USM_TRANSIENT_FAIL;
  }

  # default media location - over-ride with the -l option
  my ($base) = $SHIPHOME_BASE_DIR;
  $OKA_DFLT_DRV_LOC = get_install_home_from_base($base, $type, $ARCH, $KVER);

  # /sbin/weak-modules depends on /boot being accessible and the 
  # symvers-<kernel_version> file being present.
  if (($sub_command eq "install") && machine_is_RH())
  {
    my ($symvers_file) = "symvers-" . $KVER . ".gz";
    if (! -e "/boot/$symvers_file")
    {
      lib_error_print_noalert(625,
        "OKA installation cannot proceed:");
      lib_error_print_noalert(9158,
        "Configuration file '%s' in the /boot directory does not exist.",
         $symvers_file);
      return USM_TRANSIENT_FAIL;
    }
  }

  return USM_SUCCESS;
}

# osds_oka_install_from_distribution_files
#
# Install the OKA components from the specified distribution files
# The files have already been validated by the time we get here
# by osds_oka_search_for_distribution_files(). Also, any previous USM installation
# will have been removed.
#
use File::Path;
sub osds_oka_install_from_distribution_files
{
  my ($component);                 # curent component being installed
  my ($command);                   # current command being executed by system()
  my ($ret);                       # return of individual copy commands
  my ($return_code) = USM_SUCCESS;

  # install drivers
  # the drivers have been verified to exist so the copy will not fail

  if (! -d $DRIVER_DIR)
  {
    mkpath($DRIVER_DIR, 0, 0755);
  }

  # Print the location of the driver files
  
  lib_verbose_print (626, "OKA driver media location is '%s'", 
                 $OIP_PATH);
 
  foreach my $component (@OKA_DRIVER_COMPONENTS)
  {
    my ($source) = "$OIP_PATH/$component";
    my ($target) = "$DRIVER_DIR/$component";

    lib_verbose_print (9504, "Copying file '%s' to the path '%s'", 
                       $source,
                       $target);

    $command = "cp $source $target";
    $ret = system ($command);
    $return_code = USM_FAIL if $ret;
  }

  if ($minus_l_specified)
  {
    # Normally, the ORACLE_HOME/{bin,lib} components are installed via the
    # mapfiles. But, when the user specifies an alternate location via the
    # '-l' option on the command line, we need to install the alternate 
    # OH/{bin,lib} files also. The OH commands are, conveniently located
    # with the sbin commands.
    #
    # If we are replacing existing files, we want to preserve the original
    # file attributes.

    foreach $component (@OH_COMPONENTS) 
    {
      my (@array) = split /\//, $component;
      my ($file) = $array[-1];
      my ($target) = "$component";
      my ($source);
      my ($have_orig);
      my ($uid, $gid);

      $source = "$CMDS_SRC_DIR/$file";
      
      $have_orig = 0;

      if (-e $target)
      {
        use constant UID  => 4;
        use constant GID  => 5;
 
        $have_orig = 1;

        # get the owner/group of the original file
        ($uid, $gid) = (stat($target))[UID,GID];
      }

      lib_verbose_print (9504, "Copying file '%s' to the path '%s'", 
                         $source,
                         $target);
     
      $ret = system ("cp $source $target");
      $return_code = USM_FAIL if $ret;
      if (($target =~ /\/bin\//) || ($component =~ /okatoolsdriver.sh/))
      {
        system("chmod 0755 $target");
      }
      else # lib
      {
        system("chmod 0644 $target");
      }

      if ($have_orig)
      {
        chown $uid, $gid, $target;
      }
    }

    foreach $component (@MESG_COMPONENTS) 
    {
      my (@array) = split /\//, $component;
      my ($file) = $array[-1];
      my ($target) = $component;
      my ($source) = "$MESG_SRC_DIR/$file";
      
      lib_verbose_print (9504, "Copying file '%s' to the path '%s'", 
                            $source,
                            $target);
    
      $ret = system ("cp $source $target");
      $return_code = USM_FAIL if $ret;
    }

    # Copy the drivers and system commands to the install area so that
    # subsequent "okaroot install"s will get the patched bits should
    # the user forget to use the -l option. It also allows us to compare
    # checksums on the drivers in the "install" area to the "installed"
    # area at load time. This will catch situations where users installed
    # new bits but did run "okaroot install".

    my ($cmd_install_area) = "$ORACLE_HOME/usm/install/cmds/bin";

    foreach $component (@OKA_DRIVER_COMPONENTS) 
    {
      my (@array) = split /\//, $component;
      my ($file) = $array[-1];
      my ($source) = "$MINUS_L_DRIVER_LOC/$component";
      my ($target) = "$OKA_DFLT_DRV_LOC/$file";
      
      lib_verbose_print (9504, "Copying file '%s' to the path '%s'", 
                        $source,
                        $target);

      $ret = system ("cp $source $target");
      $return_code = USM_FAIL if $ret;
    }
  }

  return $return_code;
} # end osds_oka_install_from_distribution_files

# osds_oka_search_for_distribution_files
#
# Search the media location(s) specified by the user for valid components
#
sub osds_oka_search_for_distribution_files
{
  my ($kernel_install_files_loc) = @_;
  my (@install_loc_array);
  my ($cur_loc);              # current location (directory) being examined
  my ($component);            # current component (cmd/driver) being examined
  my ($components_found) = "";# list of components detected
  my ($components_missing) = 0; # set if one or more components are AWOL
  my ($ret_code) = USM_SUCCESS;

  # $kernel_install_files_loc is where the drivers and drivers related files
  # live. - as of 11.2.0.3 and later, the commands are shipped in a separate
  # directory.

  if (!defined($kernel_install_files_loc))
  {
     return USM_FAIL;
  }

  # Look to see if an alternate location for the distribution was specified.
  if ($kernel_install_files_loc ne $OKA_DFLT_DRV_LOC)
  {
    # -l option specified (we know that the path is fully qualified).
    $minus_l_specified = 1;

    # $kernel_install_files_loc is a misnomer for -l within this 'if clause',
    # where it's really the the directory path up to and including "install" -
    # but, what the heck. Once out of this clause, it really will mean the
    # location of the kernel drivers.

    # We use "install" as our starting point for finding our bits
    # so it had better be there.
    if (!($kernel_install_files_loc =~ /install$/))
    {
      # Error message generated by caller
      return USM_TRANSIENT_FAIL;
    }

    # We have the "base" path, up to "install".
    # It's time to find where the drivers are relative to that base.

    my (@path_array) = split ("/", $OKA_DFLT_DRV_LOC);
    my ($last_element) = $#path_array;
    my ($driver_relative_path) = "";
    my ($i);
 
    for ($i = 1; $i <= $last_element; $i++)
    {
      # strip off all array elements of out default "base" location. What's 
      # left will be the parts of the driver relative path.
      my ($element) = shift(@path_array);
      if ($element eq "install")
      {
        last;
      }
    }
  
    # Now assemble the driver relative path.
    $last_element = $#path_array;
    for ($i = 0; $i <= $last_element; $i++)
    {
      $driver_relative_path .= "$path_array[$i]/";
    }
    # We now know where the drivers and commands live in the '-l' location.
    $CMDS_SRC_DIR = "$kernel_install_files_loc/cmds/bin";
    $MESG_SRC_DIR = "$kernel_install_files_loc/../mesg";
    $USM_LIB_SRC_DIR = "$kernel_install_files_loc/../lib";
    $USM_PUB_SRC_DIR = "$kernel_install_files_loc/../public";
    $MINUS_L_DRIVER_LOC = "$kernel_install_files_loc/$driver_relative_path";
    $kernel_install_files_loc = $MINUS_L_DRIVER_LOC;
  }

  @install_loc_array = split(/,/, $kernel_install_files_loc);

  # We need to uncompress driver files first
  lib_uncompress_all_driver_files($kernel_install_files_loc);

  foreach $cur_loc (@install_loc_array)
  {
    if (! -d $cur_loc)
    {
      # location (directory) does not exist
      next;
    }
    # test that all of our expected components exist in the distribution

    # search for OIP components
    foreach $component ($OKA_DRIVER_COMPONENTS[OKA_IDX],
                        $OKA_DRIVER_COMPONENTS[OKG_IDX],
                       )
    {
      my ($target) = $cur_loc . "/" . $component;
      if (-e $target)
      {
        $components_found .= " $component";
        $OIP_PATH = $cur_loc;
#       if (! ($MEDIA_FOUND =~ m/OIP/))
#       {
#         # $MEDIA_FOUND is used by the version_check sub-command
#         $MEDIA_FOUND .= "OIP components: $OIP_PATH\n";
#       }
      }
      else
      {
        lib_error_print_noalert(9320, "Missing file: '%s'.", $target);
        $components_missing = 1;
      }
    }
  }

  if (defined($OIP_PATH))
  {
    $MEDIA_FOUND = "$OIP_PATH\n";
  }
  else
  {
    $MEDIA_FOUND = "";
  }

  # verify that we have all that we need
  if ($components_missing)
  {
    return USM_FAIL;
  }

  foreach $component (@OKA_DRIVER_COMPONENTS)
  {
    if (!($components_found =~ m/$component/))
    {
      lib_error_print_noalert(9320, "Missing file: '%s'.", $component);
      $ret_code = USM_FAIL;
    }
  }

  if (!defined($OIP_PATH))
  {
    return USM_FAIL;
  }

  # We found drivers, now find where they will be installed.
  $DRIVER_DIR = get_oka_driver_dir($OIP_PATH);

  foreach $component (@OH_COMPONENTS, @MESG_COMPONENTS)
  {
    my ($source);

    if ($minus_l_specified)
    {
      my (@array) = split /\//, $component;
      my ($file) = $array[-1];
      $source = "$CMDS_SRC_DIR/$file";

      if ($component =~ /msb$/)
      {
        # Special case msg files as it lives apart from the other commands.
        $source = "$MESG_SRC_DIR/$file";
      }
    }
    else
    {
      $source = $component;
    }

    if (! -e $source) 
    {
      lib_error_print_noalert(9320, "Missing file: '%s'.", $source);
      $ret_code = USM_FAIL;
    }
  }

  return $ret_code;
} # end osds_oka_search_for_distribution_files

# osds_load_and_verify_oka_state
#
# We unconditionally create the OKA udev permissions file
# If the install was for the current kernel version, we load the drivers
# and test to see that the expected /dev entries get created.
#
use File::Copy;
sub osds_load_and_verify_oka_state
{
  my ($no_load) = @_;
  my ($driver);                            # currently loaded driver
  my ($return_val);
  my ($udev_perm_file);
  my ($okaadmin);

  # extract the admin name for use 
  $okaadmin = lib_get_oka_admin_name();

  lib_inform_print_noalert (9321, "Creating udev for OKA.");
  lib_osds_oka_create_udev($okaadmin);
  
  print ("creating oka node \n");
  lib_osds_oka_create_node($okaadmin);
  # Make sure that all drivers are in place and can be loaded
  my ($component);
  my ($fail) = USM_SUCCESS;
  my ($result);

  foreach $component (@OKA_DRIVER_COMPONENTS)
  {
    if (! -e "$DRIVER_DIR/$component")
    {
      lib_error_print_noalert(9320, "Missing file: '%s'.", "$DRIVER_DIR/$component");
      $fail = USM_FAIL;
    }
  }
 
  if ($fail != USM_SUCCESS)
  {
     return $fail;
  }

  # create the driver dependencies
  lib_inform_print_noalert(9323,
                   "Creating module dependencies - this may take some time.");

  if (machine_is_RH() || machine_is_SLES())
  {
    my ($moved_dep) = 0;
    my ($driver_list);
    foreach $component (@OKA_DRIVER_COMPONENTS)
    {
      $driver_list .= "$DRIVER_DIR/$component\n";
    }
    if (-e "/lib/modules/$KVER/modules.dep")
    {
      move("/lib/modules/$KVER/modules.dep", "/tmp/modules.dep");
      $moved_dep = 1;
    }
    $return_val = system("depmod -v $KVER > /dev/null");
    if (($return_val != 0) && $moved_dep)
    {
      # depmod failed - restore the original
      move("/tmp/modules.dep", "/lib/modules/$KVER/modules.dep");
    }

    if (machine_is_RH())
    {
      my ($print_header) = 1;
      my ($cmd) = "echo \"$driver_list\" | /sbin/weak-modules $no_init" . 
                  " --add-modules $KVER 2>&1 |";
      open (MOD, $cmd);
      while (<MOD>)
      {
        if ($_ =~ /^WARNING:/)
        {
          next;
        }
	if ($print_header)
	{
	  lib_print_cmd_header($cmd);
	  $print_header = 0;
        }
        lib_inform_print_noalert (9999, "$_");
      }
      close (MOD);
    }
  }

  if ($no_load)
  {
    # We're installing OKA for another kernel version - do not attempt to
    # load the drivers. The presumed scenario is that the user wants to
    # install OKA for an about to be upgraded kernel. This way, OKA can
    # be up and running upon reboot. Dunno if anyone will ever use this.
    lib_inform_print_noalert(9324, "Alternate drivers installed.");
    lib_inform_print_noalert(9325, "    OS kernel version = %s.", $UNAME_R);
    lib_inform_print_noalert(9326, "    installed driver version = %s.", $KVER);
  }
  else
  {
    # Load the OKA drivers
    $return_val = lib_load_oka_drivers();
    if ($return_val != USM_SUCCESS)
    {
      # lib_load_oka_drivers() will print the specific error(s), if any;
      return $return_val;
    }

    # Make sure that the proper /dev files get created by udevd
    lib_inform_print_noalert(649, "Verifying OKA devices.");
    $return_val = lib_verify_oka_devices();
    if ($return_val != USM_SUCCESS)
    {
      # osds_verify_oka_devices() will print the specific error(s), if any;
      return $return_val;
    }
  }

  # Fix wrapper scripts to have proper ORACLE_HOME
  osds_fix_oka_wrapper_scripts();

  return USM_SUCCESS;
} # end osds_load_and_verify_oka_state

# osds_oka_uninstall
#
# remove the OKA components.
#
# 
use File::Basename;
use File::Find;
sub osds_oka_uninstall
{
  my (undef, $preserve) = @_;
  my ($return_code) = USM_SUCCESS;       # Assume success
  my ($component);
  my ($oka_perm_file);

  if (!$preserve)
  {
    my $ret;

    # TODO-SOMA - do some KA specific action !!

    # Names MUST match the ASM_OSD_TUNABLE_FILE_NAME define in asmdefs.h
    # and OFS_OSD_TUNABLE_FILE_NAME in ofslintunables.h
    #my ($advm_tunables) = "/etc/sysconfig/advmtunables";
    #my ($acfs_tunables) = "/etc/sysconfig/acfstunables";

    #if (-e $advm_tunables)
    #{
    #  if (! unlink $advm_tunables)
    #  {
    #    lib_inform_print_noalert(9348, "Unable to remove '%s'.", $advm_tunables);
    #    $ret = USM_TRANSIENT_FAIL;
    #  }
    #}
    #if (-e $acfs_tunables)
    #{
    #  if (! unlink $acfs_tunables)
    #  {
    #    lib_inform_print_noalert(9348, "Unable to remove '%s'.", $acfs_tunables);
    #    $ret = USM_TRANSIENT_FAIL;
    #  }
    #}
  } 

  # SLES udev rules work the same as RH5
  if (machine_is_RH() || machine_is_SLES())
  {
    $oka_perm_file = lib_osds_get_oka_RH5_udev_rules_file();
    # remove the udev OKA premissions file
    if (! unlink $oka_perm_file)
    {
      # this is just a comment for the time being as we can still process
      # the rest of the work
      lib_inform_print_noalert(9348, "Unable to remove '%s'.", $oka_perm_file);
      #$return_code = USM_TRANSIENT_FAIL;
    }
  }

  # Guarantee that we're not in one of the usm directories about to be nuked.
  chdir "/";

  # Remove OKA drivers from and any *empty* sub-directories we would have 
  # created at install time (e.g., /lib/modules/2.6.18-8.el5/extra/oracle)
  open (CHECK, "find /lib/modules  2> /dev/null |");
  while (<CHECK>)
  {
    my ($driver) = split;

    if (($driver =~ m/\/oracle\/oracka.ko/) ||
        ($driver =~ m/\/oracle\/oracka_mod_kga.ko/))
    {
      # Remove the driver
      if (! unlink $driver)
      {
        lib_inform_print_noalert(9348, "Unable to remove '%s'.", $driver);
        $return_code = USM_TRANSIENT_FAIL;
      }

      # Remove the base directories but only if empty
      # even if it is not empty, it is removing, so comment it out for now
      #my (undef, $lib, $modules, $kver) = split (/\//, $driver);
      #my $subdir = "/$lib/$modules/$kver";
      #finddepth(sub{rmdir}, $subdir);
    }
  }
  close(CHECK);

  system("depmod  > /dev/null");
  system("rm -f /dev/oka");

  return $return_code;
} # end osds_oka_uninstall

###############################
# internal "static" functions #
###############################

# get_oka_driver_dir
#
# return the directory where the OKA drivers will be installed.
#
sub get_oka_driver_dir
{
  my ($path) = @_;

  if (machine_is_RH() || machine_is_SLES())
  {
    my ($driver_build_version); # version that the driver was linked for.
    my ($vermagic);
    my (@tmp_array);

    # pick the oka driver - any KA driver would do.
    open MODINFO , "modinfo $path/$OKA_DRIVER_COMPONENTS[OKA_IDX] |";

    while (<MODINFO>)
    {
      if ($_ =~ /^vermagic/)
      {
        $vermagic = $_;
      }
    }
    close (MODINFO);

    if (defined($vermagic))
    {
      # Get the version number from the modinfo vermagic line. It looks like:
      # vermagic:   2.6.18-8.el5PAE SMP mod_unload 686 REGPARM 4KSTACKS gcc-4.1
      $vermagic =~ s/vermagic://;
      $vermagic =~ s/^\s+//g;
      @tmp_array = split(/ /, $vermagic);
      $driver_build_version = $tmp_array[0];
    }
    else
    {
      # Use the current kernel version if we can't get vermagic
      lib_inform_print_noalert(9343, "Unable to retrieve OS kernel version from " .
                             "module %s.", "$path/$OKA_DRIVER_COMPONENTS[OKA_IDX]");
      $driver_build_version = $UNAME_R;
    }

    return "/lib/modules/$driver_build_version/extra/oracle";
  }
} #end get_oka_driver_dir

# osds_fix_oka_wrapper_scripts
#
# We need to resolve %ORA_CRS_HOME% in the command wrapper scripts.
#
sub osds_fix_oka_wrapper_scripts
{
  my (@progs) = (
                  "$OH_BIN_DIR/okaload",
                  "$OH_BIN_DIR/okadriverstate",
                  "$OH_BIN_DIR/okacmd"
                );
  my ($prog); 
  my ($line);
  my (@buffer);

  foreach $prog (@progs)
  {
    my ($read_index, $write_index);

    $read_index = 0;
    open READ, "<$prog" or next;
    while ($line = <READ>)
    {
      if ($line =~ m/^ORA_CRS_HOME/)
      {
         $line = "ORA_CRS_HOME=$ORACLE_HOME\n";
      }
      $buffer[$read_index++] = $line;
    }
    close (READ);
    
    $write_index = 0;
    open WRITE, ">$prog" or next;
    while($write_index < $read_index)
    {
      print WRITE "$buffer[$write_index++]";
    }
    close (WRITE);
  }
}
# end osds_fix_oka_wrapper_scripts

1;

OHA YOOOO