#!/usr/bin/perl
#
# (C) Copyright IBM Corp. 2004
#
# This program is free software;  you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY;  without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
# the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program;  if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Script to collect EVMS information

use strict;
use warnings;

# run_evms_command
# Use the EVMS CLI to run a command. Optionally return the screen output.
#
# Arguments:
#    command: String containing a single command to run.
#    output:  Reference of array to pass back command output (optional).
sub run_evms_command
{
	my $command = $_[0];
	my $rc_output = $_[1];  # Optional.
	my @output;
	my $rc;

	@output = `echo "$command" | evms -s 2>&1`;
	$rc = $? >> 8;

	if (ref($rc_output)) {
		@{$rc_output} = @output;
	}

	return $rc;
}


# run_evms_commands
# Use the EVMS CLI to run an array of commands. Optionally return the screen output.
# Since the input can be potentially lengthy, use a file rather than passing the
# commands on the command line.  The CLI's buffer is 4KB.  If the string of commands
# goes beyond 4KB, commands will get lost.
#
# Arguments:
#    commands: Reference to an array of single command strings.
#    output:   Reference of array to pass back command output (optional).
sub run_evms_commands
{
	my @commands = @{$_[0]};
	my $rc_output = $_[1];  # Optional.
	my $input_file = "gather_info.qry";
	my @output;
	my $rc;
	my $i;

        open(OUTFILE, ">$input_file") or die "Can't open $input_file: $!";

	for ($i = 0; $i < @commands; $i++) {
		print OUTFILE $commands[$i] . ":\n";
	}
	
	close(OUTFILE);

	@output = `evms -f $input_file 2>&1`;
	$rc = $? >> 8;

	if (ref($rc_output)) {
		@{$rc_output} = @output;
	}

	return $rc;
}


# compress_parents_and_children
# Find the lines that begin with "--- Begin [parents|children" and replace
# them with ["Parents:"|"Children:"].  Process the lines that follow until
# a line with "--- End" is encountered.
# A line that has "Name: <name>" gets compressed to just the name.
# All other lines get removed from the array.
#
# Arguments:
#    output: An array of output lines.
sub compress_parents_and_children(@) {

	my @output = @_;

	my $i = 0;

	while ($i < @output) {
		my $line = $output[$i];

		if ($line =~ /--- Begin/) {

			if ($output[$i] =~ /parents/) {
				$output[$i] = "Parents:\n";
			} else {
				$output[$i] = "Children:\n";
			}
			$i++;

			for ($line = $output[$i]; !($line =~ /--- End/); $line = $output[$i]) {
				# Replace object name lines with just the object name.
				# Remove non-objet-name lines.
				if ($output[$i] =~ /Name:\s+(\S+)/) {
					$output[$i] = "  " . $1 . "\n";
					$i++;
				} else {
					# Remove the line.
					splice(@output, $i, 1);
				}
			}
			
			# $output[$i] is the line that had the "--- End" marker.
			# Replace it with an empty line.
			$output[$i] = "\n";
		}

		$i++;
	}

	return @output;
}


MAIN:
{
	my $rc;
	my $evms_cli = "";
	my @output;
	my @disks;
	my @segments;
	my @regions;
	my @evms_objects;
	my @containers;
	my @volumes;
	my @plugins;
	my $i;
	my @commands;

	# Make sure the CLI is accessible.
	@output = `which evms`;
	if (@output > 0) {
		($evms_cli) = grep(/^\/.*/, @output)
	}
	if ($evms_cli eq "") {
		print "The EVMS Command Line Interface (evms) is not in the current path.\n";
		print "Unable to get EVMS data.\n";
		goto the_end;
	}

	# Get a list of the objects, and volumes (things that can have parents and children) in the system.
	$rc = run_evms_command("query:objects:query:volumes", \@output);
	if ($rc) {
		# Spit out whatever error messages the CLI said.
		print @output;
		goto the_end;
	}

	# Extract the disks
	@disks = grep(/Logical Disk Name:/, @output);
	for ($i = 0; $i <= $#disks; $i++) {
		# Remove the "Logical Disk Name:" from the line leaving only the disk name.
		if ($disks[$i] =~ /Name:\s+(\S+)/) {
			$disks[$i] = $1;
		}
	}

	# Extract the segments
	@segments = grep(/Segment Name:/, @output);
	for ($i = 0; $i <= $#segments; $i++) {
		# Remove the "Segment Name" from the line leaving only the segment name.
		if ($segments[$i] =~ /Name:\s+(\S+)/) {
			$segments[$i] = $1;
		}
	}

	# Extract the regions
	@regions = grep(/Region Name:/, @output);
	for ($i = 0; $i <= $#regions; $i++) {
		# Remove the "Region Name:" from the line leaving only the region name.
		if ($regions[$i] =~ /Name:\s+(\S+)/) {
			$regions[$i] = $1;
		}
	}

	# Extract the EVMS objects
	@evms_objects = grep(/Object Name:/, @output);
	for ($i = 0; $i <= $#evms_objects; $i++) {
		# Remove the "Object Name:" from the line leaving only the EVMS object name.
		if ($evms_objects[$i] =~ /Name:\s+(\S+)/) {
			$evms_objects[$i] = $1;
		}
	}

	# Extract the Volumes
	@volumes = grep(/Volume Name:/, @output);
	for ($i = 0; $i <= $#volumes; $i++) {
		# Remove the "Object Name:" from the line leaving only the volume name.
		if ($volumes[$i] =~ /Name:\s+(\S+)/) {
			$volumes[$i] = $1;
		}
	}

	# Build the list of query commands to send to the CLI.

	push(@commands, "query:plugins,lo");

	foreach my $disk (@disks) {
		push(@commands, "query:disks,lo,disk=$disk");
		push(@commands, "echo:\"--- Begin parents of $disk ---\"");
		push(@commands, "query:parent,$disk");
		push(@commands, "echo:\"--- End parents of $disk ---\"");
		push(@commands, "echo:\"--- Begin children of $disk ---\"");
		push(@commands, "query:children,$disk");
		push(@commands, "echo:\"--- End children of $disk ---\"");
	}

	foreach my $segment (@segments) {
		push(@commands, "query:segments,lo,segment=$segment");
		push(@commands, "echo:\"--- Begin parents of $segment ---\"");
		push(@commands, "query:parent,$segment");
		push(@commands, "echo:\"--- End parents of $segment ---\"");
		push(@commands, "echo:\"--- Begin children of $segment ---\"");
		push(@commands, "query:children,$segment");
		push(@commands, "echo:\"--- End children of $segment ---\"");
	}

	foreach my $region (@regions) {
		push(@commands, "query:regions,lo,region=$region");
		push(@commands, "echo:\"--- Begin parents of $region ---\"");
		push(@commands, "query:parent,$region");
		push(@commands, "echo:\"--- End parents of $region ---\"");
		push(@commands, "echo:\"--- Begin children of $region ---\"");
	        push(@commands, "query:children,$region");
		push(@commands, "echo:\"--- End children of $region ---\"");
	}

	foreach my $evms_object (@evms_objects) {
	        push(@commands, "query:objects,lo,object=$evms_object");
		push(@commands, "echo:\"--- Begin parents of $evms_object ---\"");
		push(@commands, "query:parent,$evms_object");
		push(@commands, "echo:\"--- End parents of $evms_object ---\"");
		push(@commands, "echo:\"--- Begin children of $evms_object ---\"");
		push(@commands, "query:children,$evms_object");
		push(@commands, "echo:\"--- End children of $evms_object ---\"");
	}
	
	push(@commands, "query:c,lo");
	
	foreach my $volume (@volumes) {
		push(@commands, "query:volumes,lo,volume=$volume");
		push(@commands, "echo:\"--- Begin children of $volume ---\"");
		push(@commands, "query:children,$volume");
		push(@commands, "echo:\"--- End children of $volume ---\"");
	}

	$rc = run_evms_commands(\@commands, \@output);
	if ($rc) {
		print "Command set failed with error code $rc\n";
		goto the_end;
	}

	@output = compress_parents_and_children(@output);

	print @output;

the_end:
}

