#
# Copyright 2001-2003 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
#ident	"@(#)scrgcommon.pm	1.24	03/02/25 SMI"
#
# common methods

package Cluster::scrgcommon;
use strict;
use Socket;
use Exporter;
use FileHandle;
use Cluster::Cgi;
use Cluster::common;
use Sun::Solaris::Utils qw(gettext);
use vars qw(@ISA $VERSION @EXPORT %extdesc @rtprops %rttable %rtdesc
	    %rgprops %rsprops %rtvar @rs @rst @rsh);
$VERSION = '1.00';
@ISA = qw(Exporter);
@EXPORT = qw(cmd_rt_info cmd_rg_info cmd_rs_info cmd_rt_create
	     cmd_rt_create_1 cmd_rt_delete cmd_rg_modify cmd_rg_create
	     cmd_rg_create_1 cmd_rgsf_create cmd_rgsf_create_1
	     cmd_rg_delete analyzerg info getrgprops getrtprops
	     getrsprops &proptable %rtdesc %rgprops
	     %rsprops @rtprops %rttable %rtvar @rs @rst @rsh);

# The following strings are from the RTR files.  They need to be modified
# to track changes to the RTR files.  When a general RTR internationalization
# scheme is implemented, these strings can be removed.

;#gettext("NONE")
;#gettext("SOFT")
;#gettext("HARD")
;#gettext("True")
;#gettext("False")
;#gettext("Apache Web Server on Sun Cluster")
;#gettext("Boolean specify whether this resource needs to do affinity switchover")
;#gettext("Boolean to indicate if we should reboot system when null rpc call on rpcbind fails")
;#gettext("Boolean to indicate if we should restart mountd when null rpc call fails")
;#gettext("Boolean to indicate if we should restart nfsd when null rpc call fails")
;#gettext("Child monitoring level for PMF")
;#gettext("Command to invoke application being made HA")
;#gettext("Command to stop application being made HA")
;#gettext("Configuration file (named.conf or named.boot) to use")
;#gettext("Domain Name Service on Sun Cluster")
;#gettext("HA Shared Address Resource Type")
;#gettext("HA Storage Resource Type")
;#gettext("HA-NFS for Sun Cluster")
;#gettext("Levels of child processes monitored")
;#gettext("List of IPMP groups on each node")
;#gettext("List of hostnames this resource manages")
;#gettext("List of nodes on which this resource is available")
;#gettext("Logical Hostname Resource Type")
;#gettext("Netscape Directory Server on Sun Cluster")
;#gettext("Number of PMF restarts allowed for the fault monitor")
;#gettext("The Binary Directory Path")
;#gettext("The Configuration Directory Path")
;#gettext("The Configuration Directory Path(s)")
;#gettext("The Paramtable Version for this Resource")
;#gettext("The list of HA service paths to be checked")
;#gettext("Time out value for the probe (seconds)")
;#gettext("Time window (minutes) for fault monitor restarts")
;#gettext("Timeout(seconds) to use when probing lockd")
;#gettext("Timeout(seconds) to use when probing mountd")
;#gettext("Timeout(seconds) to use when probing nfsd")
;#gettext("Timeout(seconds) to use when probing rpcbind")
;#gettext("Timeout(seconds) to use when probing statd")
;#gettext("Unix Daemon on Sun Cluster")
;#gettext("X Font Server on Sun Cluster")
;#gettext("Sun ONE Web Server on Sun Cluster")

#Extension property descriptions:
;#gettext("Timeout for start method (sec)");
$extdesc{"START_TIMEOUT"} = "Timeout for start method (sec)";
;#gettext("Timeout for stop method (sec)");
$extdesc{"STOP_TIMEOUT"} = "Timeout for stop method (sec)";
;#gettext("Timeout for validate method (sec)");
$extdesc{"VALIDATE_TIMEOUT"} = "Timeout for validate method (sec)";
;#gettext("Timeout for update method (sec)");
$extdesc{"UPDATE_TIMEOUT"} = "Timeout for update method (sec)";
;#gettext("Timeout for init method (sec)");
$extdesc{"INIT_TIMEOUT"} = "Timeout for init method (sec)";
;#gettext("Timeout for fini method (sec)");
$extdesc{"FINI_TIMEOUT"} = "Timeout for fini method (sec)";
;#gettext("Timeout for boot method (sec)");
$extdesc{"BOOT_TIMEOUT"} = "Timeout for boot method (sec)";
;#gettext("Timeout for monitor start method (sec)");
$extdesc{"MONITOR_START_TIMEOUT"} = "Timeout for monitor start method (sec)";
;#gettext("Timeout for monitor stop method (sec)");
$extdesc{"MONITOR_STOP_TIMEOUT"} = "Timeout for monitor stop method (sec)";
;#gettext("Timeout for monitor check method (sec))";
$extdesc{"MONITOR_CHECK_TIMEOUT"} = "Timeout for monitor check method (sec)";
;#gettext("Soft/hard failover");
$extdesc{"Failover_mode"} = "Soft/hard failover";
;#gettext("Network resources");
$extdesc{"Network_resources_used"} = "Network resources";
;#gettext("Ports and protocols");
$extdesc{"Port_list"} = "Ports and protocols";
;#gettext("Interval between cheap probes (sec)");
$extdesc{"Cheap_probe_interval"} = "Interval between cheap probes (sec)";
;#gettext("Interval between thorough probes (sec)");
$extdesc{"Thorough_probe_interval"} = "Interval between thorough probes (sec)";
;#gettext("Number of retries to do");
$extdesc{"Retry_count"} = "Number of retries to do";
;#gettext("Interval between retries (sec)");
$extdesc{"Retry_interval"} = "Interval between retries (sec)";
;#gettext("Timeout for prenet start method (sec)");
$extdesc{"PRENET_START_TIMEOUT"} = "Timeout for prenet start method (sec)";
;#gettext("Timeout for postnet stop method (sec)");
$extdesc{"POSTNET_STOP_TIMEOUT"} = "Timeout for postnet stop method (sec)";
;#gettext("Timeout for client affinity (sec)");
$extdesc{"Affinity_timeout"} = "Timeout for client affinity (sec)";
;#gettext("Affinity applies to UDP packets");
$extdesc{"UDP_Affinity"} = "Affinity applies to UDP packets";
;#gettext("Use weaker affinity guarantees");
$extdesc{"Weak_Affinity"} = "Use weaker affinity guarantees";
;#gettext("The packet distribution policy");
$extdesc{"Load_balancing_policy"} = "The packet distribution policy";
;#gettext("The relative weights per node");
$extdesc{"Load_balancing_weights"} = "The relative weights per node";

sub cmd_rt_info {
    print "<h2>".sprintf(gettext("Type %s"), $FORM{"rt"})."</h2>\n";
    &info($FORM{"rt"}, "", "rt");
}

sub cmd_rg_info {
    print "<h2>".sprintf(gettext("Resource group %s"), $FORM{"rg"})."</h2>\n";
    &info($FORM{"rg"}, "", "rg");
}

sub cmd_rs_info {
    print "<h2>".sprintf(gettext("Resource %s"), $FORM{"rs"})."</h2>\n";
    &info($FORM{"rg"}, $FORM{"rs"}, "rs");
}

sub cmd_rt_create {
    my ($found, $rtdir, $dir, $desc);
    &getscrgconfig();
    $rtdir = "/usr/cluster/lib/rgm/rtreg";
    opendir(RTDIR, $rtdir) || &bailout("Couldn't open $rtdir");
    &wizard_start;
    $found = 0;
    while ($dir = readdir(RTDIR)) {
	if ($dir eq "." || $dir eq "..") {
	    next;
	}
	if ($rtdesc{$dir} eq "") {
	    if ($found == 0) {
		print gettext("Select a resource type and click \"Add\" to add it.\n");
		print "<br><select name=\"rt\">\n";
		$found = 1;
	    }
	    $desc = "";
	    if (open(IN, "<$rtdir/$dir")) {
		while (<IN>) {
		    if (/^RT_DESCRIPTION\s*=\s*"(.*)"/) {
			$desc = $1;
			last;
		    }
		}
		close(IN);
	    }
	    if ($desc) {
		$desc = "$desc ($dir)";
	    } else {
		$desc = $dir;
	    }
	    &option("rt", $dir, $desc);
	}

    }
    if ($found == 0) {
	print "<p>".gettext("All available resource types have been added already.")."<p>";
    } else {
	print "</select><br>\n";
    }
    closedir(RTDIR);
    #print "<br><input name=\"cmd_mainpage\" type=\"submit\" value=\"Back\">\n";
    &wizard_end();

}

sub cmd_rt_create_1 {
    my ($cmd, $status);
    &wizard_start(gettext("Add Type"), "scrgadm.pl");
    $cmd = "scrgadm -a -t ".$FORM{"rt"};
    $status = &runsuid($cmd);
    if ($status == 0) {
	&okmsg(gettext("Type added successfully"));
    } else {
	if ($result =~ /already exists/) {
	    &errmsg(gettext("That type already exists in the cluster"));
	} else {
	    &errmsg(gettext("Failure"), $result);
	}
    }
    #print "<br><input name=\"cmd_mainpage\" type=\"submit\" value=\"Back\">\n";
    &wizard_end();
}

sub cmd_rt_delete {
    my ($cmd, $status);
    &wizard_start(gettext("Remove Resource Type"), "scrgadm.pl");
    $cmd = "scrgadm -r -t ".$FORM{"rt"};
    $status = &runsuid($cmd);
    if ($status == 0) {
	&okmsg(gettext("Type removed successfully"));
    } else {
	if ($result =~ /invalid/) {
	    &errmsg(gettext("That type does not exist in the cluster."));
	} else {
	    &errmsg(gettext("Failure"), $result);
	}
    }
    #print "<br><input name=\"cmd_mainpage\" type=\"submit\" value=\"Back\">\n";
    &wizard_end();
}

# ----------- rg create/modify ----------------

#Modify a resource group
sub cmd_rg_modify {
    my ($i, $j);
    $FORM{"rgnew"} = $FORM{"rg"};
    &getrgprops($FORM{"rg"});
    foreach $i (keys %rgprops) {
	($j = $i) =~ s/ /_/g;
	$FORM{"prop_$j"} = $rgprops{$i};
    }
    ($FORM{"nodelist"} = $FORM{"prop_Nodelist"} ) =~ s/ /,/g;

    # Get current info on the resource group

    &cmd_rg_create("modify");
}

#Create a new resource group
#Or modify, if $modify is set
sub cmd_rg_create {
    my ($modify) = @_;
    my ($item);
    &getscrgconfig();
    $item = 1;
    if ($modify) {
	&wizard_start(gettext("Modify Resource Group"), "scrgadm.pl");
	print gettext("Resource group name: ").$FORM{"rgnew"}."<p>\n";
	&hidden("rgnew");
    } else {
	&wizard_start(gettext("Add Resource Group"), "scrgadm.pl");
	if ($errpos == 1) {
	    &errmsg();
	}
	print "<p>$item. ".gettext("Enter a name for the new resource group:")."<br>\n";
	$item++;
	&input("rgnew");
    }

    if ($errpos == 2) {
	&errmsg();
    }
    print "<p>$item. ".gettext("(Optional) Modify node list:");
    $item++;
    print "<br>".gettext("Nodes: ");
    if ($FORM{"nodelist"} eq "" || $common::errpos == 2) {
	# Get new list of nodes
	&getnodes();
	$FORM{"nodelist"} = join(",", @nodes);
    }
    &input("nodelist");
    print "<p>$item. ".gettext("(Optional) Modify properties:");
    $item++;
    print "<table border=2 cellpadding=2 cellspacing=2><tr>\n";
	print "<th>".gettext("Parameter")."</th><th>".gettext("Value")."</th></tr>\n";

    print "<tr><td>".gettext("Description")."</td><td>\n";
    &input("prop_RG_description");
    print "</td></tr>\n";

    if ($FORM{"prop_management_state"}) {
	print "<tr><td>".gettext("Management state")."</td><td>\n";
	print $FORM{"prop_management_state"}."</td></tr>\n";
    }

    print "<tr><td>".gettext("Failback")."</td><td>\n";
    print "<select name=\"prop_Failback\">\n";
    &option("prop_Failback", "False", gettext("False"));
    &option("prop_Failback", "True", gettext("True"));
    print "</select></td></tr>\n";

    if ($FORM{"prop_mode"} eq "Failover") {
    } else {
	print "<tr><td>".gettext("Maximum primaries")."</td><td>\n";
	&input("prop_Maximum_primaries");
	print "</td></tr>\n";
	print "<tr><td>".gettext("Desired primaries")."</td><td>\n";
	&input("prop_Desired_primaries");
	print "</td></tr>\n";
    }

    print "<tr><td>".gettext("RG dependencies")."</td><td>\n";
    &input("prop_RG_dependencies");
    print "</td></tr>\n";

    print "<tr><td>".gettext("Mode")."</td><td>\n";
    print $FORM{"prop_mode"}."</td></tr>\n";

    print "<tr><td>".gettext("Network dependencies")."</td><td>\n";
    &input("prop_network_dependencies");
    print "</td></tr>\n";

    print "<tr><td>".gettext("Path prefix")."</td><td>\n";
    &input("prop_Pathprefix");
    print "</td></tr>\n";


    print "</table>\n";
    my $i;
    foreach $i (keys %FORM) {

    }
    if ($modify) {
	print "<p>$item.".gettext("Click to modify:");
    } else {
	print "<p>$item.".gettext("Click to create:");
    }
    $item++;
	print "<input name=\"cmd_rg_create_1\" type=\"submit\" value=\"".gettext("Create")."\">\n";
    #print "<br><input name=\"cmd_rg_create_1\" type=\"submit\" value=\"Create\">\n";
    if ($modify) {
	&hidden("modify", 1);
    }
    &wizard_end();

}

# Next step of creating a new resource group
sub cmd_rg_create_1 {
    my ($cmd, $status);
    if ($FORM{"rgnew"} eq "") {
	$errpos = 1;
	$errmsg = gettext("You must specify a name for the new resource group");
	&cmd_rg_create;
	return;
    }
    if ($FORM{"nodelist"} eq "") {
	$errpos = 2;
	$errmsg = gettext("You must specify at least one node");
	&cmd_rg_create;
	return;
    }

    if ($FORM{"modify"}) {
	&getrgprops($FORM{"rg"});
	$cmd = "scrgadm -a -g ".$FORM{"rgnew"};
    } else {
	$cmd = "scrgadm -c -g ".$FORM{"rgnew"};
    }
    $cmd .= " -h ".$FORM{"nodelist"};

    if ($FORM{"prop_RG_description"} ne $rgprops{"RG_description"}) {
	$cmd .= " -y RG_description=\"".$FORM{"prop_RG_description"}."\"";
    }

    if ($FORM{"prop_Failback"} ne $rgprops{"Failback"}) {
	$cmd .= " -y Failback=\"".$FORM{"prop_Failback"}."\"";
    }

    if ($FORM{"prop_Maximum_primaries"} ne $rgprops{"Maximum_primaries"} &&
	$FORM{"prop_mode"} ne "Failover") {
	$cmd .= " -y Maximum_primaries=\"".$FORM{"prop_Maximum_primaries"}."\"";
    }

    if ($FORM{"prop_Desired_primaries"} ne $rgprops{"Desired_primaries"} &&
	$FORM{"prop_mode"} ne "Failover") {
	$cmd .= " -y Desired_primaries=\"".$FORM{"prop_Desired_primaries"}."\"";
    }

    if ($FORM{"prop_Global_resources_used"} ne
	$rgprops{"Global_resources_used"}) {
	$cmd .= " -y Global_resources_used=\"".$FORM{"prop_Global_resources_used"}."\"";
    }

    if ($FORM{"prop_Pathprefix"} ne $rgprops{"Pathprefix"}) {
	$cmd .= " -y Pathprefix=\"".$FORM{"prop_Pathprefix"}."\"";
    }


    $status = &runsuid($cmd);
    if ($status == 0) {
	&wizard_start(gettext("Create Resource Group"), "scrgadm.pl");
	&okmsg(gettext("Resource group added successfully"));
    } elsif ($result =~ /already exists/ || $common::result =~ /resource group exists/) {
	$errmsg = $common::result;
	$errpos = 1;
	&cmd_rg_create;
	return;
    } elsif ($result =~ /node/) {
	$errmsg = $result;
	$errpos = 2;
	&cmd_rg_create;
	return;
    } else {
	&wizard_start(gettext("Create Resource Group"), "scrgadm.pl");
	&errmsg(gettext("Failure"), $result);
    }

    #print "<br><input name=\"cmd_mainpage\" type=\"submit\" value=\"Back\">\n";
    &wizard_end();
}


#Create a new resource group, scalable or failover
sub cmd_rgsf_create {
    my ($item);
    &getscrgconfig();
    $item = 1;
    &wizard_start;

    if ($errpos == 1) {
	&errmsg();
    }
    print "<p>$item. ".gettext("Enter a name for the new resource group:")."<br>\n";
    $item++;
    &input("rgnew");

    &hidden("prop_RG_mode");
    if ($FORM{"prop_RG_mode"} eq "Switchover") {
	if ($errpos == 3) {
	    &errmsg();
	}
	print "<p>$item. ".gettext("Specify the maximum number of primaries on which the service can run, and the desired number of primaries:\n");
	$item++;
	print "<br>".gettext("Maximum primaries: ");
	&input("prop_Maximum_primaries");
	print "<br>".gettext("Desired primaries: ");
	&input("prop_Desired_primaries");

	print "<p>$item. ".gettext("Select the resource group on which this group depends.\n");
	print gettext("This will normally be the resource group containing " .
	    the Shared Address resource associated with this scalable " .
	    resource group.\n");
	$item++;
	&input("prop_RG_dependencies");
    }


    if ($errpos == 2) {
	&errmsg();
    }
    print "<p>$item. ".gettext("(Optional) Modify node list:");
    $item++;
    print "<br>".gettext("Nodes: ");
    &input("nodelist");
    print "<p>$item. ".gettext("(Optional) Enter a description:");
    $item++;
    &input("prop_RG_description");

    print "<p>$item. ".gettext("(If necessary) Enter a path prefix:");
    $item++;
    &input("prop_Pathprefix");


    print "<p>$item. ".gettext("Click to create:");
    $item++;
	print "<input name=\"cmd_rgsf_create_1\" type=\"submit\" value=\"".gettext("Create")."\">\n";
    &wizard_end();

}

# Final step of creating a new resource group
sub cmd_rgsf_create_1 {
    my ($cmd, $modeflag, $status);
    if ($FORM{"rgnew"} eq "") {
	$errpos = 1;
	$errmsg = gettext("You must specify a name for the new resource group");
	&cmd_rg_create;
	return;
    }

    $cmd = "scrgadm -c -g ".$FORM{"rgnew"};

    $modeflag = "";

    if ($FORM{"nodelist"}) {
	$cmd .= " -h ".$FORM{"nodelist"};
    }

    if ($FORM{"prop_RG_description"}) {
	$cmd .= " -y RG_description=\"".$FORM{"prop_RG_description"}."\"";
    }

    if ($FORM{"prop_RG_mode"} eq "Scalable") {
	$cmd .= " -y Maximum_primaries=\"".$FORM{"prop_Maximum_primaries"}."\"";
	$cmd .= " -y Desired_primaries=\"".$FORM{"prop_Desired_primaries"}."\"";
	# Mode will be scalable automatically if primaries > 1
	if ($FORM{"prop_Maximum_primaries"} <= 1) {
	    $modeflag += "-y RG_mode=\"Scalable\"";
	}
    }

    if ($FORM{"prop_RG_dependencies"}) {
	$cmd .= " -y Pathprefix=\"".$FORM{"prop_RG_dependencies"}."\"";
    }

    if ($FORM{"prop_Pathprefix"}) {
	$cmd .= " -y Pathprefix=\"".$FORM{"prop_Pathprefix"}."\"";
    }

    $status = &runsuid($cmd);
    if ($status == 0) {
	&wizard_start(gettext("Create Resource Group"), "scrgadm.pl");
	&okmsg(gettext("Resource group added successfully"));
    } elsif ($result =~ /already exists/ || $result =~ /resource group exists/) {
	$errmsg = $result;
	$errpos = 1;
	&cmd_rgsf_create;
	return;
    } elsif ($result =~ /primaires/) {
	$errmsg = $result;
	$errpos = 3;
	&cmd_rgsf_create;
	return;
    } elsif ($result =~ /node/) {
	$errmsg = $result;
	$errpos = 2;
	&cmd_rgsf_create;
	return;
    } else {
	&wizard_start(gettext("Create Resource Group"), "scrgadm.pl");
	&errmsg(gettext("Failure"), $result);
    }

    #print "<br><input name=\"cmd_mainpage\" type=\"submit\" value=\"Back\">\n";
    &wizard_end();
}

sub cmd_rg_delete {
    my ($cmd, $status);
    &wizard_start(gettext("Remove Resource Group"), "scrgadm.pl");
    $cmd = "scrgadm -r -g ".$FORM{"rg"};
    $status = &runsuid($cmd);
    if ($status == 0) {
	&okmsg(gettext("Resource group deleted successfully"));
	&reloadmenu();
    } else {
	if ($result =~ /invalid/) {
	    &errmsg(gettext("That resource group does not exist in the cluster"));
	} else {
	    &errmsg(gettext("Failure"), $result);
	}
    }
    #print "<br><input name=\"cmd_mainpage\" type=\"submit\" value=\"Back\">\n";
    &wizard_end();
}

# ----------- rs create/modify ----------------

# Analyze the rg and find out what resources are in it
# Return:	@rs - list of resources
# 		@rst - type of resources
#		@rsh - hostname (if appropriate)
sub analyzerg {
    my ($cnt);
    my($rg) = @_;
    opencmdIN("scrgadm -pvv -g $rg");
    $cnt = -1;
    while (<IN>) {
	if (/Res name:\s+(.+)/) {
	    $cnt++;
	    $rs[$cnt] = $1;
	} elsif (/Res resource type:\s+(.+)/) {
	    $rst[$cnt] = $1;
	} elsif (/Res hostname/) {
	    $rsh[$cnt] = $1;
	}
    }
}

# ------- end of create/modify


# The info page
sub info {
    my ($arg, $subarg, $type) = @_;
    my ($label, $value, $name, $param, $nproptable, %proptable,
	$i, $ntable, %table, $def);
    opencmdIN("scrgadm -pvv");

    while (<IN>) {
	chop;
	$_ =~ s/\s+$//;
	if (/^[A-Z].*:\s+$arg$/) {
	    print "<pre>\n";
	    print $_."\n";
	    if ($subarg) {
		while (<IN>) {
		    chop;
		    if (/\s+[A-Z].*:\s+$subarg$/) {
			print $_."\n";
			last;
		    }
		    if (/^$/) {
			last;
		    }
		}
	    }
	    while (<IN>) {
		chop;
		if (/^$/) {
		    last;
		}
		if ($subarg && /RS Name/) {
		    last;
		}
		s/\(\S+\)//;
		if (/^\s*([^:]*):\s*(.*)\s*/) {
		    ($label, $value) = ($1, $2);
		} else {
		    print "$_\n";
		    next;
		}

		# For group properties, don't print RS stuff
		if ($type eq "rg" && $label =~ /^RS /) {
		    if ($label eq "RS Name") {
			print $_;
		    }
		    next;
		}

		# Handle rs properties
		if ($type eq "rs" && /Res property\s+([^:]+):\s+(.*)$/) {
		    ($name,$param) = ($1, $2);
		    if ($name eq "name") {
			$nproptable++;
		    }
		    $proptable{$nproptable,$name} = $param;
		    next;
		}
		if ($type eq "rs" && /Properties:\s+([^:]+):\s+(.*)$/) {
		    ($name,$param) = ($1, $2);
		    if ($name eq "name") {
			$nproptable++;
		    }
		    if (/value, [^:]*:\s*(.*)/) {
			$name = "value";
			$param = $1;
		    }
		    $proptable{$nproptable,$name} = $param;
		    next;
		}

		# Handle rt properties
		if ($type eq "rt" &&
    (/Paramtable entry:\s+([^:]+):\s+(.*)$/ || /Res Type param ([^:]+):\s+(.*)$/)) {
		    ($name,$param) = ($1, $2);
		    if ($name eq "name") {
			$ntable++;
		    }
		    $param =~ s/\s+$//;
		    $param =~ s/\s*;//;
		    $param =~ s/^none registered$//;
		    if ($name eq "type") {
			$table{$ntable,"default"} = "&nbsp;";
			$param =~ s/\.$//;
			if ($param =~ /(.*),\s*default:\s*(.*)$/) {
			    ($param,$def) = ($1,$2);
			    if ($def ne "") {
				$table{$ntable,"default"} = $def;
			    }
			}
		    }
		    if ($param ne "") {
			$table{$ntable,$name} = $param;
		    } else {
			$table{$ntable,$name} = "&nbsp;";
		    }
		} else {
		    print $_."\n";
		}
	    }
	    print "</pre>\n";
	}
    }
    if ($nproptable) {
	print "<table border=2 cellpadding=2 cellspacing=2><tr>\n";
	print "<th>".gettext("Parameter")."</th><th>".gettext("Value")."</th></tr>\n";
	for ($i = 1; $i <= $nproptable; $i++) {
	    print "<tr>\n";
	    print "<td>".gettext($proptable{$i,"name"})."</td>\n";
	    print "<td>".$proptable{$i,"value"}."</td>\n";
	}
	print "</table><br>\n";
    }
    if ($ntable) {
	print "<table border=2 cellpadding=2 cellspacing=2><tr>\n";
	print "<th>".gettext("Parameter")."</th><th>".gettext("Extension")."</th>".
	    "<th>".gettext("Description")."</th><th>".gettext("Tunability")."</th><th>".gettext("type")."</th>".
	    "<th>".gettext("Default")."</th><tr>\n";

	for ($i = 1; $i <= $ntable; $i++) {
	    print "<tr>\n";
	    print "<td>".$table{$i,"name"}."&nbsp;</td>\n";
	    print "<td>".gettext($table{$i,"extension"})."&nbsp;</td>\n";
	    if ($table{$i, "extension"} eq "False") {
		print "<td>".gettext($extdesc{$table{$i,"name"}}).
		    "&nbsp;</td>\n";
	    } else {
		print "<td>".gettext($table{$i,"description"}).
		    "&nbsp;</td>\n";
	    }
	    print "<td>".gettext($table{$i,"tunability"})."&nbsp;</td>\n";
	    print "<td>".gettext($table{$i,"type"})."&nbsp;</td>\n";
	    print "<td>".gettext($table{$i,"default"})."&nbsp;</td>\n";
	    print "</tr>\n";
	}
	print "</table>\n";
    }
    print "<form action=\"scrgadm.pl\" method=\"post\">\n";
    #print "<br><input name=\"cmd_mainpage\" type=\"submit\" value=\"Back\">\n";
    print "</form>\n";
}

# Get Res properties from scrgadm -pv
# Return rsprops{name} = value
sub getrsprops {
    my($resource) = @_;
    my $scrgadm = "scrgadm";

    undef %rsprops;

    opencmdIN("$scrgadm -pvv -j $resource");
    my ($name);
    while (<IN>) {
	chop;
	if (/^\s+\((.+):([^:]+):([^:]+)\)\s+Res property value:\s+(.*)/) {
	    $rsprops{$3} = $4;
	    $rsrg{$2} = $1;
	} elsif (/^\s+\((.+):([^:]+):([^:]+)\)\s+Res property type:\s+(.*)/) {
	    $rsprops{$3,"type"} = $4;
	} elsif (/^\s+\((.+):([^:]+)\)\s+Res (.*):\s+(.*)/) {
	    $rsprops{$3} = $4;
	}
    }
    # Convert stringarray delimiter from space to comma
    my ($i);
    foreach $i (keys %rsprops) {
	if (lc($rsprops{$i,"type"}) eq "stringarray") {
	    $rsprops{$i} =~ s/ /,/g;
	}
    }
}

# Get Res Group properties from scrgadm -pv
# Return rgprops{name} = value
sub getrgprops {
    my($group) = @_;
    my $scrgadm = "scrgadm";

    undef %rgprops;

    opencmdIN("$scrgadm -pv -g $group");
    while (<IN>) {
	chop;
	$_ =~ s/\s+$//;
	if (/^Res Group name:\s*(.*)/i) {
	} elsif (/\S+\s+Res Group\s+([^:]+):\s+(.+)/i) {
	    $rgprops{$1} = $2;
	    $rgprops{$1} =~ s/<NULL>//;
	} elsif (/^$/) {
	} else {
	    #print "Couldn't parse $_\n";
	}
    }
}

# getrtprops("rt");
# Fill in @rtprops with propname
# $rttable{"propname","field"} = field value
# $rtvar{"var"} = var value (e.g. description, base directory, failover)

sub getrtprops {
    my($rt) = @_;
    my($curr) = "";

    undef @rtprops;
    undef %rttable;
    undef %rtvar;
    opencmdIN("scrgadm -pvv -t $rt");
    while (<IN>) {
	chop;
	if (/not registered/) {
	    &errmsg(sprintf(gettext("Type %s is not registered"), $rt));
	}
	if (/Res Type param name:\s*(\S+)/) {
	    $curr = $1;
	    $rtprops[$#rtprops+1] = $curr;
	} elsif (/Res Type param\s+([^:]+): (.*)/) {
	    my($field, $value) = ($1, $2);
	    $field =~ s/<NULL>//;
	    $rttable{$curr, $field} = $value;
	} elsif (/^  / && /Res Type ([^:]+):\s*(.*)/) {
	    $rtvar{$1} = $2;
	}
    }
    close(IN);
}

# Print editable table of properties
# proptable($modify, $lhmode) : $modify indicates we are modifying existing.
# $lhmode is "sa", "rg", or "".
# If $errpos == 200, an error will be printed for each unspecified property.
# Uses FORM{"rt"}, FORM{"rg"}, and FORM{"allparams"}
# Sets FORM{"prop_...}
sub proptable {
    my ($modify, $lhmode) = @_;
    #print "<table border=2 cellpadding=2 cellspacing=2><tr>\n";
    #print "<th>Parameter</th><th>Value</th></tr>\n";

    &getrtprops($FORM{"rt"});

    if ($modify) {
	&getrsprops($FORM{"rs"});
	my ($i, $j);
	foreach $i (keys %rsprops) {
	    ($j = $i) =~ s/ /_/g;
	    $FORM{"prop_$j"} = $rsprops{$i};
	}
    }

    my $i;
    my $errorhandled = 0;
    my $lastpass = 2;
    if ($FORM{"allparams"}) {
	$lastpass = 3;
    }

    if ($FORM{"allparams"}) {
	# Special properties
	if (`uname -r` !~ /5.8/) {
	    if ($modify) {
		$FORM{"prop_Resource_project_name"} = $rsprops{"resource project name"};
	    } else {
		$FORM{"prop_Resource_project_name"} = "default";
	    }
	}
	if ($modify) {
	    $FORM{"prop_Resource_dependencies"} = $rsprops{"strong dependencies"};
	    $FORM{"prop_Resource_dependencies_weak"} = $rsprops{"weak dependencies"};
	    $FORM{"prop_Type_version"} = $rsprops{"type version"};
	}
	&action_table_row_start("R_description</div><br><div>".gettext("A brief description of the resource"));
	&input("prop_R_description");
	&action_table_row_end();

	if (`uname -r` !~ /5.8/) {
	    # Solaris 8 doesn't support project name
	    &action_table_row_start("Resource_project_name</div><br><div>".gettext("The project name"));
	    print "<select name=\"prop_Resource_project_name\">\n";
	    my $projects = `/usr/bin/projects root`;
	    chomp $projects;
	    my (@projects) = split(/ /, $projects);
	    foreach my $i (@projects) {
		my $selected = "";
		if ($i eq $FORM{"prop_Resource_project_name"}) {
		    $selected = "selected";
		}
		print "<option value=$i $selected>$i\n";
	    }
	    print "</select>";
	    &action_table_row_end();
	}

	&action_table_row_start("Resource_dependencies</div><br><div>".gettext("List of strong resource dependencies"));
	&input("prop_Resource_dependencies");
	&action_table_row_end();
	&action_table_row_start("Resource_dependencies_weak</div><br><div>".gettext("List of weak resource dependencies"));
	&input("prop_Resource_dependencies_weak");
	&action_table_row_end();
	&action_table_row_start("Type_version</div><br><div>".gettext("Version of the Resource Type"));
	&input("prop_Type_version");
	&action_table_row_end();
    }

    for (my $pass = 0; $pass <= $lastpass; $pass++) {
	foreach $i (@rtprops) {
	    my $tun = $rttable{$i, "tunability"};
	    my $default = defined $rttable{$i, "default"};
	    my $ext = ($rttable{$i, "extension"} eq "True");

	    if ($i eq "Load_balancing_weights" || $i eq "NetIfList" ||
		    $i eq "AuxNodeList") {
		if ($lastpass < 3) {
		    # Don't display the item
		    next;
		}
	    }
	    if ($i eq "Port_list") {
		# Pretend there is no default
		$default = 0;
	    }

	    if ($ext && ! $default) {
		# Extension, needs value
		$pass == 0 || next;
	    } elsif (! $ext && ! $default) {
		# Regular, needs value
		$pass == 1 || next;
	    } elsif ($ext && $default) {
		# Extension, has default
		$pass == 2 || next;
	    } elsif (! $ext && $default) {
		# Regular, has default
		$pass == 3 || next;
	    } else {
		&errmsg(sprintf(gettext("Unexpected property %s"), $i));
	    }
	    if ($tun eq "At creation" && $modify) {
		# Can't modify it
		next;
	    }
	    if ($i eq "Scalable" || $i eq "Network_resources_used") {
		# Skip the property
		next;
	    }
	    if ($i eq "Port_list" && $lhmode ne "sa" &&
		    $FORM{"rt"} ne "SUNW.gds") {
		# Port_list is only applicable for scalable service or
		# generic data service.
		next;
	    }
	    if ($i eq "Load_balancing_policy" ||
		    $i eq "Load_balancing_weights" ||
		    $i eq "Affinity_timeout" ||
		    $i eq "UDP_Affinity" ||
		    $i eq "Weak_Affinity") {
		if ($lhmode ne "sa") {
		    # Properties only relevant for scalable
		    next;
		}
	    }

	    if ($errpos == 200 && $FORM{"prop_$i"} eq "" && !$default && $ext) {
		&errmsg(sprintf(gettext("Property %s must be specified"), $i));
		$errorhandled = 1;
		$errpos = 200; # Keep checking for multiple missing args
	    }

	    if (!$modify && $FORM{"prop_$i"} eq "") {
		$FORM{"prop_$i"} = $rttable{$i, "default"};
	    }

	    if ($FORM{"prop_$i"} eq "<NULL>" && $i eq "HostnameList") {
		    $FORM{"prop_$i"} = "";
	    }

	    my ($desc);
	    if ($rttable{$i, "description"} ne "" &&
		    $rttable{$i, "description"} ne "<NULL>") {
		$desc = gettext($rttable{$i, "description"});
		$desc = &printable($desc);
		&action_table_row_start("$i</div><br><div>$desc");
	    } elsif ($extdesc{$i} ne "") {
		$desc = gettext($extdesc{$i});
		$desc = &printable($desc);
		&action_table_row_start("$i</div><br><div>$desc");
	    } else {
		&action_table_row_start("$i");
	    }

	    if ($rttable{$i, "type"} eq "Boolean") {
	      my @bool_vals = ("True", "False");
	      print "<select name=\"prop_$i\">";
	      if ($FORM{"prop_$i"} eq "<unset>") {
		&option("prop_$i", "<unset>", gettext("unset"));
	      } else {
		$FORM{"prop_$i"} = ucfirst(lc($FORM{"prop_$i"}));
	      }
	      foreach my $bool_val (@bool_vals) {
		&option("prop_$i", $bool_val, gettext($bool_val));
	      }
	      print "</select>";
	    } elsif ($rttable{$i, "type"} eq "Enum") {
	      my @enum_vals = split(/ /, $rttable{$i, "enum list"});
	      print "<select name=\"prop_$i\">";
	      if ($FORM{"prop_$i"} eq "<unset>") {
		&option("prop_$i", "<unset>", gettext("unset"));
	      }
	      foreach my $enum_val (@enum_vals) {
		&option("prop_$i", $enum_val, gettext($enum_val));
	      }
	      print "</select>";
	    } else { # do textfields
	      &input("prop_$i");
	    }
	    &action_table_row_end();
	}
    }

    if ($errpos == 200 && $errorhandled) {
	$errpos = 0;
    }

    #print "</table>\n";
}

# Module load success
1;
