#!/usr/perl5/bin/perl
#
# Copyright (c) 2001 by Sun Microsystems, Inc.
# All rights reserved.
#
#ident  "@(#)SUNW_cluster_publicnet.pl 1.2     01/08/15 SMI"
#
#
# This RCM script prevents the removal of Sun Cluster public network
# adapters if no alternate path exists.
#

require 5.005;

use English;
use strict;
use POSIX qw(locale_h EEXIST ENOENT);
use Sun::Solaris::Utils qw(textdomain gettext);
use Fcntl ':flock';		# needed for LOCK_EX and LOCK_UN constants
use File::stat;

my ($resource, $resource_short, $ispublicnet, $publicnetlist, 
    $retval, @nets, $adapter, $pipe_exitstatus, $cachefile, $cacheres,
    $command, $scpublicnet, $publicnetrestore, $publicnetremove, 
    $isclustered, $loc);

#
# Specify location of Sun Cluster public network helper script
#
$scpublicnet = "/usr/cluster/lib/sc/publicnet";

$ispublicnet = "$scpublicnet check";
$publicnetlist = "$scpublicnet list";
$publicnetrestore = "$scpublicnet restore";
$publicnetremove = "$scpublicnet remove";
$isclustered = "/usr/sbin/clinfo";
$cachefile = "/tmp/suncluster_publicnet.cache";

$command = shift(@ARGV);
$resource = shift(@ARGV); 

main();

# fails with an internal error if the cache file is not owned by root

sub assert_cachefile_root {
    if(stat($cachefile)->uid != 0) {
	print "rcm_failure_reason=", 
		gettext("Public Network Cache File Corrupted."), "\n";
	exit(1);
    }
}

# parse the SUNW_network/ portion off the resource

sub get_resource_short {
    if(($resource =~ /SUNW_network\/(.+)/)) {
	$resource_short = $1;
    } else {
	print "rcm_log_error=",
		"Could not process public network adapter list.\n";
	exit(2);
    }
}

# removes an entry from the cache file and returns the resource
# sets $cacheres to the removed resource

sub remove_from_cachefile {
    # find the entry in the cache

    get_resource_short;

    assert_cachefile_root;
    
    if(!rename("$cachefile","$cachefile".".tmp")) {
	print "rcm_failure_reason=",
		gettext("Unable to read from cache file."), "\n";
	exit(1);
    }
    
    if(!open(CACHEFILE, "<$cachefile".".tmp")) {
	print "rcm_failure_reason=",
		gettext("Cannot open cache file"), "\n";
	exit(1);
    }
    
    if(!open(CACHEFILEOUT, ">$cachefile")) {
	print "rcm_failure_reason=",
		gettext("Cannot open cache file"), "\n";
	exit(1);
    }

    if(!flock(CACHEFILEOUT, LOCK_EX)) {
	print "rcm_failure_reason=",
		gettext("Cannot lock cache file"), "\n";
	exit(1);
    }
    
    $cacheres = "";
    while(<CACHEFILE>) {
	chop;
	if(/$resource_short/) {
	    $cacheres = $ARG;			# remove from cache
	} else {
	    print CACHEFILEOUT "$ARG\n";	# put back in cache
	}
    }
    
    if(!flock(CACHEFILEOUT, LOCK_UN)) {
	print "rcm_failure_reason=",
		gettext("Cannot unlock cache file"), "\n";
	exit(1);
    }

    close(CACHEFILE);
    close(CACHEFILEOUT);
    
    unlink("$cachefile".".tmp");
}

# MAIN

sub main {

    $ARG = $command;

  SWITCH: {
      /scriptinfo/   && do {
	  print "rcm_script_version=1\n";
	  print "rcm_script_func_info=",
		gettext("Sun Cluster Public Network"), "\n";
	  print "rcm_cmd_timeout=86400\n";
	  exit (0);
      };
      
      /register/ && do {
	  if((system($isclustered)/256) != 0) {
	      exit(0);
	  }

	  $loc = setlocale(LC_ALL, "C");
	  if(!open(PUBLICNET, "$publicnetlist|")) {
	      setlocale(LC_ALL, $loc);
	      print "rcm_failure_reason=",
		gettext("Cannot obtain list of public network adapters."),
	        "\n";
	      exit(1);
	  }
	  setlocale(LC_ALL, $loc);
 
	  while(<PUBLICNET>) {
	      chop;
	      if(@nets = split(/ /)) {
		  while($adapter = shift(@nets)) {
		      print "rcm_resource_name=SUNW_network/$adapter\n";
		  }
	      }
	  }
	  
	  if(!close(PUBLICNET)) {
	      print "rcm_failure_reason=",
		gettext("Cannot read list of public network adapters."),"\n";
	      exit(1);
	  }
	  exit (0);
      };
      
      /resourceinfo/ && do {
	  print "rcm_resource_usage_info=",
		gettext("Sun Cluster Public Network Adapter"), "\n";
	  exit (0);
      };
      
      /queryremove/ && do {
	  
	  get_resource_short();
	  
	  $loc = setlocale(LC_ALL, "C");
	  if(!open(CHECK, "$ispublicnet $resource_short |")) {
	      setlocale(LC_ALL, $loc);
	      print "rcm_failure_reason=",
		gettext("Cannot determine status of network adapters"), "\n";
	      exit(1);
	  }
	  setlocale(LC_ALL, $loc);

 
	  $retval = <CHECK>;
	  chop($retval);
	  
	  if(!close(CHECK) && ($OS_ERROR)) {
	      print "rcm_failure_reason=",
		gettext("Cannot determine status of network adapters"), "\n";
	      exit(1);
	  }
	  
	  $pipe_exitstatus = $CHILD_ERROR;
	  
	  if($pipe_exitstatus == 0) {
	      exit(0);			# success
	  } else {
	      print "rcm_failure_reason=$resource_short",
		gettext("is part of a NAFO group.\n");
	      print "rcm_log_info=$retval\n";
	      exit(3);
	  }
	  
      };
      
      /preremove/ && do {
	  
	  get_resource_short();
	  
	  # actually remove the resource
	  
	  $loc = setlocale(LC_ALL, "C");
	  if(!open(CHECK, "$publicnetremove $resource_short |")) {
	      setlocale(LC_ALL, $loc);
	      print "rcm_failure_reason=",
		gettext("Cannot remove network adapter from NAFO group"),
		"\n";
	      exit(1);
	  }
	  setlocale(LC_ALL, $loc);
	  
	  $retval = <CHECK>;
	  chop($retval);
	  
	  if(!close(CHECK) && ($OS_ERROR)) {
	      print "rcm_failure_reason=",
		gettext("Cannot remove network adapter from NAFO group"),
		"\n";
	      exit(1);
	  }
	  
	  $pipe_exitstatus = $CHILD_ERROR;
	  
	  if($pipe_exitstatus != 0) {
	      print "rcm_failure_reason=",
		gettext("Cannot alterm PNM configuration"),"\n";
	      print "rcm_log_info=$retval\n";
	      exit(3);
	  }

	  # place what is to be removed in the cache
	  if(!open(CACHEFILE, ">>$cachefile")) {
	      print "rcm_failure_reason=",
		gettext("Cannot access cache file"), "\n";
	      exit(1);
	  }
	  
	  assert_cachefile_root();
	  
	  if(!flock(CACHEFILE, LOCK_EX)) {
	      print "rcm_log_error=Cannot lock cache file.\n";
	      exit(1);
	  }
	  
	  print CACHEFILE "$retval\n";
	  
	  if(!flock(CACHEFILE, LOCK_UN)) {
	      print "rcm_log_error=Cannot unlock cache file.\n";
	  }
	  
	  close(CACHEFILE);

	  exit (0);
      };
      
      /cancelremove/ && do {
	  
	  remove_from_cachefile();
	  
	  if($cacheres eq "") {
	      print "rcm_failure_reason=",
		gettext("Cannot restore network adapter to NAFO group."),
		"\n";
	      exit(1);
	  }

	 $loc = setlocale(LC_ALL, "C");
	 if(($retval = system("$publicnetrestore $cacheres")) != 0) {
	     setlocale(LC_ALL, $loc);
	     print "rcm_failure_reason=",
	       gettext("Cannot restore network adapter to NAFO group."),
	       "\n";
	     exit (3);
	 }
	 setlocale(LC_ALL, $loc);
	  
	  exit (0);
      };
      
      /postresume/ && do {
	  
	  remove_from_cachefile();
	  
	  exit (0);
      };
  }
    
    exit (2);
}
