#!/usr/bin/perl # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # # # Licensed Materials - Property of IBM # # (C) COPYRIGHT International Business Machines Corp. 2006,2019 # All Rights Reserved # # US Government Users Restricted Rights - Use, duplication or # disclosure restricted by GSA ADP Schedule Contract with IBM Corp. # # IBM_PROLOG_END_TAG # sccsid = "@(#)16 1.7 src/rsct/rm/StorageRM/tools/srmdiag.perl, StorageRM, rsct_rady, rady2035a 6/16/15 08:10:29" #------------------------------------------------------------------------------------------# # Syntax: # # srmdiag [-h] [-r|-s|-d] -q query_string # # # # -h - Display the usage information of this command # # -r - Display only LVM attribute information or the relationship # # of the LVM attributes collected by RSCT StoragRM. # # -s - Display only LVM attribute information or the relationship # # of the LVM attributes collected by system commands. # # -d - Display the diffrence of attribute information collected # # from StorageRM and system commands. # # -q - The query string determines what kind of relationship will # # be displayed. # # The following keywords can be used in the string with colon # # as delimiter. # # pt Partitiion # # dk Disk # # pod Partiition or Disk # # vg Volume Group # # lv Logical Volume # # fs File System # # # # Common Query String and explanation: # # fs - all file systems; # # lv - all logical volumes; # # pt - all partitions; # # dk - all disks; # # pod - all partitions or disks; # # fs:lv - the relationship of file system and logical volume; # # fs:pt - the relationship of file system and logical volume; # # fs:dk - the relationship of file system and disk; # # fs:pod - the relationship of file system and partition or disk; # # fs:pod:dk - the relationship of file system, partition or disk and disk; # # pt:dk/dk:pt - the relationship of partition and disk; # # fs:lv:vg - the relationship of file system, logical volume and volume group.# # File system is the key word to get the relationship; # # fs:lv:vg:pod - the relationship of file system, logical volume. # # Volume Group is the key word. # # # # # # Examples: # # 1. To display the file systems' information collected by rsct. # # srmdiag -r -q fs # # # # 2. Display the relationship among the file system, logical volume # # and volume group information collected by system command line. # # srmdiag -s -q fs:lv:vg # # # # 3. Display the differences information of filesystem,logical volume, # # volume group and disk respectively which is collected from RSCT # # StorageRM and system commands. # # srmdiag -d -q fs:lv:vg:dk # # # # # # Return code: # # # # 0 - success, no difference found # # 1 - success, difference between system and StorageRM was found # # 2 - input error. detail will be outputed to stderr # # 3 - other errors. detail will be outputed to stderr # # # #------------------------------------------------------------------------------------------# #--------------------------------------------------------------------# # # # External commands used: # # # # fdisk # # pvdisplay # # vgdisplay # # lvdisplay # # bldid # # cat # # lspv # # getlvodm # # lsfs # # lsrsrc-api # # # #--------------------------------------------------------------------# BEGIN { $ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/sbin:' . $ENV{'PATH'}; } ##require 5.8.0; use strict; use warnings; use locale; use Getopt::Std; package common; #--------------------------------------------------------------------# # # # common.pm : include some common functions # # # #--------------------------------------------------------------------# # @EXPORT = qw( # # errlog # # trim # # is_blank_line # # is_comment # # exit_with_msg # # reverse_hash # # reverse_hashlist # # format_list # # repeat_list # # strlist_cmp # # differ # # ); # #--------------------------------------------------------------------# #--------------------------------------------------------------------# # # # errlog : record the error messages # # # # Parameters : # # [Variation Parameters] String or Integer # # # # Return : # # NULL # # # #--------------------------------------------------------------------# sub errlog { # my @err = @_; # print $::log_handle ("@err\n"); } #--------------------------------------------------------------------# # # # trim : remove the blank symbols at begin or end # # # # Parameters : # # [String] the string # # # # Return : # # [String] the trimed string # #--------------------------------------------------------------------# sub trim { my $line = shift; if ( $line =~ /^\s*(\S.*\S)\s*$/ ) { $line = $1; } elsif ( $line =~ /^\s*\S\s*$/ ) { $line = $1; } return $line; } #--------------------------------------------------------------------# # # # is_blank_line : check if the input line is a blank line; # # # # Parameters : # # [string] # # # # Return : # # [int] 1:SUCCESS; 0:FAIL; # # # #--------------------------------------------------------------------# sub is_blank_line { my ($line) = shift; if ( $line =~ /^\s*$/ ) { return 1; } return 0; } #--------------------------------------------------------------------# # is_comment : check if the input line is a blank line or a comment # # line ( start with '#' ) # # # # Parameters : # # [string] the input line # # # # Return : # # [int] 1:SUCCESS 0:FAIL; # # # #--------------------------------------------------------------------# sub is_comment { my $line = shift; if ( $line =~ /^[\s]*$/ || $line =~ /^\s*#/) { return 1; } else { return 0; } } #--------------------------------------------------------------------# # # # exit_with_msg : print some msg into stderr device and return the # # specified value # # # # Parameters : # # [string] the error msg # # [int] the return code # # # # Return : # # NULL # # # #--------------------------------------------------------------------# sub exit_with_msg { my ($msg, $rc) = @_; print STDERR ($msg."\n"); # errlog($msg); # close($::log_handle); exit($rc); } #--------------------------------------------------------------------# # # # reverse_hash : reverse a hash's key and value and save the result # # into a new hash; # # # # Parameters : # # [hash_handle] the original hash handle; # # [hash_handle] the target hash handle; # # [list_handle] the whole values list handle; # # [unkown] padding # # # # Return: # # NULL # # # # Used Global Variables # # $::nonexistent : the symbol for nonexistent relationship # # # #--------------------------------------------------------------------# sub reverse_hash { my ($hash1, $hash2, $list2) = @_; my $itr; # build keys # use $::nonexistent to fill all value position firstly. foreach $itr ( @$list2 ) { $$hash2{ $itr } = $::nonexistent; } foreach $itr ( keys(%$hash1) ) { $$hash2{ $$hash1{$itr} } = $itr; } } #--------------------------------------------------------------------# # # # reverse_hashlist : reverse a hash's key and value, and save # # the result into a new hash_list; # # # # WHAT IS HASH_LIST ? # # normal hash struct: # # ( key1 => value1, key2 => value2, ... ) # # hash_list struct: # # ( key1 => (value1, value2 .. ),key2 => (..) .. keyn=>() ) # # # # Parameters : # # [hash_handle] the original hash handle; # # [hash_list_handle] the target hash_list handle; # # [list_handle] the whole value list handle; # # # # Return : # # NULL # # # # Used Global Variables # # $::nonexistent : the symbol for nonexistent relationship # # # #--------------------------------------------------------------------# sub reverse_hashlist { my ($_n1_hash, $_1n_hash, $_1_list) = @_; my $itr; my $value; my $list_handle; # Build keys foreach $itr ( @$_1_list ) { # I have no idea is there any way to move the @null_list # definition out of here. :-( my @null_list = (); $$_1n_hash{$itr} = \@null_list; } foreach $itr ( keys(%$_n1_hash) ) { $value = $$_n1_hash{$itr}; $list_handle = $$_1n_hash{$value}; push( @$list_handle, $itr ); } # se ($::nonexistent) to indicate a nonexistent relationship; foreach $itr ( keys(%$_1n_hash) ) { $list_handle = $$_1n_hash{$itr}; if ( scalar(@$list_handle) == 0 ) { push (@$list_handle, $::nonexistent); } } } #--------------------------------------------------------------------# # format_list : using a format list to format a input str list, and # # return the result string line # # # # Parameters : # # [strlist_handle] the input string data list; # # [intlist_handle] the field width list; # # [char] the padding character; # # [int] indicate if truncate the overflow part of a string; # # # # Return : # # [string] the final formatted string; # # # #--------------------------------------------------------------------# sub format_list { my ($input_lst, $fw_lst, $padding, $truncate_flg) = @_; my $fw = 0; # field width my $diff = 0; my $offset = 0; my $data_len = 0; my $length = 0; my $data = ''; my $output = ''; $length = scalar(@$input_lst); while( $offset < $length ) { $data = $$input_lst[$offset]; $fw = $$fw_lst[$offset]; $data_len = length($data); $diff = $fw - $data_len; if ( $diff > 0 ) { $output .= $data; $output .= $padding x $diff; } else { # truncate the overflow part of a string if ( $truncate_flg == 1 ) { $output .= substr($data, 0, $fw - 4 ); $output .= "...$padding"; } else { $output .= $data; $output .= $padding; } # if ( $truncat_flg == 1 ) } # if ( $diff > 0 ) $offset++; } # while( $offset < $length ) return $output; } #--------------------------------------------------------------------# # # # repeat_list : repeatly fill some info into a list # # # # Parameters : # # [list_handle] the target list handle # # [any] the padding # # [int] length, how many push time # # # # Return : # # NULL # # # #--------------------------------------------------------------------# sub repeat_list { my ( $list_handle, $padding, $length ) = @_; my $offset = 0; while ( $offset < $length ) { push ( @$list_handle, $padding ); $offset++; } } #--------------------------------------------------------------------# # # # strlist_cmp : cmpare 2 string list # # # # Parameters : # # [strlist_handle] 1st strlist handle # # [strlist_handle] 2nd strlist handle # # # # Return : # # [int] 0: equal 1: non-equal # # # #--------------------------------------------------------------------# sub strlist_cmp($$) { my ( $l_strlist, $r_strlist ) = @_; my $ofst = 0; my $l_str = ''; my $r_str = ''; my $l_len = scalar(@$l_strlist); my $r_len = scalar(@$r_strlist); if ( $l_len != $r_len ) { return 1; } while ( $ofst < $l_len ) { $l_str = $$l_strlist[$ofst]; $r_str = $$r_strlist[$ofst]; if ( $l_str ne $r_str ) { return 1; } $ofst++; } return 0; } #--------------------------------------------------------------------# # diff : diff 2 lists and get the common and different data. # # # # Parameters : # # [anylist_handle] the 1st list; # # [anylist_handle] the 2st list; # # [anylist_handle] the handle to refer the common data from # # 1st list; # # [anylist_handle] the handle to refer the common data from # # 2nd list; # # [anylist_handle] the handle to refer the special data from # # 1st list; # # [anylist_handle] the handle to refer the special data from # # 2nd list; # # [func_ptr] the function pointer, which refer the call back # # function to compare two elements # # 0 : specify equal # # 1 : special not equal # # # # Return : # # [int] 0: equal; non-0: different; # #--------------------------------------------------------------------# sub differ { my ( $lh_1, $lh_2, $lh_com1, $lh_com2, $lh_spe1, $lh_spe2, $cb_func ) = @_; my $ret = 0; my $loop_2 = 0; my $offset_1 = 0; my $offset_2 = 0; my @spe_1 = @$lh_1; my @spe_2 = @$lh_2; my $len_1 = scalar( @spe_1 ); my $len_2 = scalar( @spe_2 ); my $itor_1; my $itor_2; @$lh_com1 = (); @$lh_com2 = (); @$lh_spe1 = (); @$lh_spe2 = (); while ( $offset_1 < $len_1 ) { $itor_1 = $spe_1[$offset_1]; $loop_2 = 1; $offset_2 = 0; while ( $loop_2 == 1 && $offset_2 < $len_2 ) { if ( defined( $spe_2[$offset_2] ) ) { $itor_2 = $spe_2[$offset_2]; # Insert the comman elements into correspoing list; if ( $cb_func->($itor_1, $itor_2 ) == 0 ) { push( @$lh_com1, $itor_1 ); push( @$lh_com2, $itor_2 ); delete $spe_1[$offset_1]; delete $spe_2[$offset_2]; # exit the inner loop $loop_2 = 0; } } $offset_2++; } # Insert list1 special elements; if ( $loop_2 == 1 ) { push ( @$lh_spe1, $itor_1 ); $ret++; } $offset_1++; } # Insert list2 special elements; $offset_2 = 0; while( $offset_2 < $len_2 ) { if ( defined( $spe_2[$offset_2] ) ) { push ( @$lh_spe2, $spe_2[$offset_2] ); $ret++; } $offset_2++; } return $ret; } package wrapper; #--------------------------------------------------------------------# # # # wrapper.pm : wrapper class # # wrapper::type |indicate the data type which is transparent # # to client programmer. # # wrapper::handle |indicate the handle which refer to the real # # date # # # # In other words, this class will provide a transparent data type # # information to client programmer. # # # #--------------------------------------------------------------------# # @EXPORT = qw( # # get_type # # get_handle # #--------------------------------------------------------------------# #--------------------------------------------------------------------# # new : constructor # # # # Parameters : # # [String] %_{'type'} the data type # # [handle] %_{'handle'} the handle # # # # Return : # # [handle] object reference # # # #--------------------------------------------------------------------# sub new { my $this = []; my %params= @_; $this->[0] = $params{'type'}; $this->[1] = $params{'handle'}; bless $this; return $this; } sub get_type { my $this = shift; return $this->[0]; } sub get_handle { my $this = shift; my $type = shift; # # Error Occured!!! # if ( common::is_blank_line( $this->[0] ) ) { # print 'This->[0] is null',"\m"; # } if ( $this->[0] eq $type ) { return $this->[1]; } return 0; } package reaper; #--------------------------------------------------------------------# # # # reaper.pm : reaper class # # # # This class is a proxy to aix_reaper, lix_reaper, and srm_reaper# # the function 'checkup' and 'checkout' will be associated with # # corresponding aix_reaper::checkup, aix_reaper::checkout, # # lix_reaper::checkup, lix_reaper::checkout, srm_reaper::checkup # # srm_reaper::checkout. # # # # This class help me to do sample dynamic-binding # #--------------------------------------------------------------------# $reaper::rel_one2more = 0; $reaper::rel_one2one = 1; $reaper::rel_unsupt = -1; #--------------------------------------------------------------------# # new : constructor # # # # Parameters : # # [String] %_{'type'} the data type # # [handle] %_{'handle'} the handle # # # # Return : # # [handle] object reference # # # #--------------------------------------------------------------------# sub new { my $this = []; my @params = (); shift; @params = @_; $this->[0] = $params[0]; # this $this->[1] = $params[1]; # checkup func $this->[2] = $params[2]; # checkout func bless $this; return $this; } sub checkup { my $this = shift; my $inst = $this->[0]; my $func = $this->[1]; my @params = @_; return $func->($inst, @params); } sub checkout { my $this = shift; my $inst = $this->[0]; my $func = $this->[2]; my @params = @_; return $func->($inst, @params); } package lix_reaper; #--------------------------------------------------------------------# # # # lix_reaper.pm : lix_reaper class # # # # This class will harvest LVM attributes and information from Linux # # platform. # # This class isn't transparent to client programer. # #--------------------------------------------------------------------# # @EXPORT = qw( # # checkup # # checkout # # ); # #--------------------------------------------------------------------# #--------------------------------------------------------------------# # new : constructor # # # # Parameters : # # NULL # # # # Return : # # [handle] object reference # # # #--------------------------------------------------------------------# sub new { my $this = {}; my $proxy; bless $this; $this->harvest_harddisk(); $this->harvest_volumegroup(); $this->harvest_logicalvolume(); $this->harvest_filessystem(); $proxy = reaper->new( $this, \&lix_reaper::checkup, \&lix_reaper::checkout ); return $proxy; } sub checkup { my ( $this, $query ) = @_; my $hdl; my $type=''; if ( defined($this->{$query} ) ) { $hdl = $this->{$query}; $type = wrapper::get_type($hdl); if ( $type eq 'Hash_List' ) { return $reaper::rel_one2more; } else { return $reaper::rel_one2one; } } return $reaper::rel_unsupt; } sub checkout { my ($this, $query) = @_; my $relationship = $this->{$query}; return $relationship; } # ------------------------------------------------------------------ # PRIVATE FUNCTIONS # ------------------------------------------------------------------ sub support_dev($) { my $device = shift; my $itor = ''; my $dev_name = ''; my $dev_type = ''; if ( $device =~ /\/([^\/]+)$/ ) { $dev_name = $1; } else { $dev_name = $device; } if ( $dev_name =~ /s[gd]\S+$/ ) { $dev_type = 'SCSI'; } if ( $dev_type eq '' ) { return 0; } foreach $itor ( @::Supported_DEV_Type_Linux_List ) { if ( $dev_type eq $itor ) { return 1; } } return 0; } sub support_fs_type($) { my $fs_type = shift; my $itor = ''; foreach $itor ( @::Supported_FS_Type_Linux_List ) { if ( $fs_type eq $itor ) { return 1; } } return 0; } sub harvest_harddisk { my $this = shift; my $disk_name = ''; my $part_name = ''; my $cmd = ''; my $rc = 0; my %part_disk =(); my %part_part =(); my %disk_part =(); my %disk_disk =(); my %pod_dk =(); my %dk_pod =(); my %pod_pt =(); my %pt_pod =(); my %pod_pod =(); my @parts =(); my @disks =(); my @pods =(); my %tmp =(); my %mded = (); my @output = (); my $itor; # harvest MD devices my $md_name = ''; my @mds = (); my %md_md = (); $cmd = "/sbin/mdadm --version 2>&1"; @output = `$cmd`; $cmd = ""; foreach (@output) { if ($_ =~ /^mdadm\s+-\s+v(\d+\.\d+)\.?.*/) { my $version = $1; if ($version < 2.0 ) { $cmd = "/sbin/mdadm --examine --brief --scan --config=partitions"; } else { $cmd = "/sbin/mdadm --examine --brief --scan --config=partitions --verbose"; } last; } } if (length($cmd) == 0) { common::exit_with_msg("System Error: can't detect the mdadm program version.\n", 3); } @output = `$cmd`; foreach $itor (@output) { next if ( 1 == common::is_blank_line($itor) ); if ( $itor =~ /^ARRAY\s*(\S+)\s*/ ) { $md_name = $1; push(@mds, $md_name); push(@disks, $md_name); $md_md{$md_name} = $md_name; $disk_disk{$md_name} = $md_name; } if ( $itor =~ /^\s+devices=(.*)\s*$/) { my @devs = split(/,/, $1); $mded{$_} = $md_name foreach (@devs); # push(@mded, @devs); } } # harvest regular devices $cmd = 'fdisk -l 2>/dev/null'; @output = `$cmd`; $rc = $? >> 8; if ( $rc != 0 ) { common::exit_with_msg("System Error: Invoke '$cmd' failed with RC=$rc\n", 3); } foreach $itor ( @output ) { next if ( 1 == common::is_blank_line($itor) ); # if disk is supported but Disk identifier is 0x00000000 # that means that its actually a logical volume. if ( $itor =~ /^\s*Disk\s*identifier\s*:\s*(0x[0]{8})/){ if (scalar(@disks)){ if ( support_dev($disk_name) == 1 ) { pop (@disks); } } }elsif ( $itor =~ /^\s*Disk\s*(\S+)\s*:/ ) { $disk_name = $1; if ( support_dev($disk_name) == 1 ) { $disk_disk{$disk_name} = $disk_name; push ( @disks, $disk_name ); } else { $disk_name = ''; } } elsif ( $itor =~ /^\s*(\/dev\S+).*/) { $part_name = $1; push ( @parts, $part_name ); $part_part{$part_name} = $part_name; # Get the disk name printed in output just before the partition. $disk_name = $disks[-1]; $part_disk{$part_name} = $disk_name; } } @pods = (@disks, @parts); %dk_pod = %disk_disk; %pt_pod = %part_part; %pod_pod = (%disk_disk, %part_part); %pod_dk = (%disk_disk, %part_disk); common::reverse_hashlist( \%part_part, \%tmp, \@parts ); common::reverse_hashlist( \%part_disk, \%disk_part, \@disks ); %pod_pt = (%disk_part, %tmp); #print "size of \%md_md is " . scalar(keys(%md_md)) . "\n"; $this->{' | mded | '} = wrapper::new( 'type' => 'Hash', 'handle' => \%mded ); $this->{'md:md'} = wrapper::new( 'type' => 'Hash', 'handle' => \%md_md ); $this->{'pt:dk'} = wrapper::new( 'type' => 'Hash', 'handle' => \%part_disk ); $this->{'dk:dk'} = wrapper::new( 'type' => 'Hash', 'handle' => \%disk_disk ); $this->{'pt:pt'} = wrapper::new( 'type' => 'Hash', 'handle' => \%part_part ); $this->{'dk:pt'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%disk_part ); $this->{'dk:pod'} = wrapper::new( 'type' => 'Hash', 'handle' => \%dk_pod ); $this->{'pod:dk'} = wrapper::new( 'type' => 'Hash', 'handle' => \%pod_dk ); $this->{'pt:pod'} = wrapper::new( 'type' => 'Hash', 'handle' => \%pt_pod ); $this->{'pod:pt'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%pod_pt ); $this->{'pod:pod'} = wrapper::new( 'type' => 'Hash', 'handle' => \%pod_pod ); $this->{'md'} = wrapper::new( 'type' => 'List', 'handle' => \@mds ); $this->{'pt'} = wrapper::new( 'type' => 'List', 'handle' => \@parts ); $this->{'dk'} = wrapper::new( 'type' => 'List', 'handle' => \@disks ); $this->{'pod'} = wrapper::new( 'type' => 'List', 'handle' => \@pods ); return 0; } sub harvest_volumegroup { my $this = shift; my $rc = 0; my $pv_name_valid = 0; my $lonely_vg = 0; my $pv_name = ''; my $vg_name = ''; my $itor = ''; my $cmd = ''; my %pv_vg = (); # ParTition or Disk to VG my %vg_pv = (); # VG to POD my %vg_vg = (); # VG to VG my %pt_vg = (); # ParTition to VG my %vg_pt = (); # VG to ParTition my %dk_vg = (); # DisK to VG my %vg_dk = (); # VG to DisK my %pt_dk = (); # ParTition to DisK my %vg_md = (); # VG to MD my %md_vg = (); # MD to VG my @vgs = (); # VG List my %pod_pod = (); # PoD to PoD my %md_md = (); # MD to MD my @output = (); my $hash_handle; $hash_handle = wrapper::get_handle( $this->{'pod:pod'}, 'Hash'); %pod_pod = %$hash_handle; $cmd = 'pvdisplay 2>/dev/null'; @output = `$cmd`; $rc = $? >> 8; if ( $rc != 0 ) { common::exit_with_msg("System Error: Invoke '$cmd' failed with RC=$rc\n", 3); } $hash_handle = wrapper::get_handle( $this->{'pt:dk'}, 'Hash' ); %pt_dk = %$hash_handle; $hash_handle = wrapper::get_handle( $this->{'md:md'}, 'Hash' ); %md_md = %$hash_handle; foreach $itor ( @output ) { next if ( common::is_blank_line($itor) == 1 ); if ( $pv_name_valid == 0 && $itor =~ /^\s*PV\s*Name\s*(\S+)\s*$/ ) { $pv_name = $1; $pv_name_valid++; if ( !defined($pod_pod{$pv_name}) ) { $lonely_vg++; } } elsif ( $pv_name_valid != 0 && $itor =~ /^\s*VG\s*Name\s*(\S*)\s*$/ ) { $vg_name = $1; if ( $lonely_vg == 0 ) { if ( 1 != common::is_blank_line($vg_name) ) { $pv_vg{$pv_name}=$vg_name; if ( defined($vg_pv{$vg_name}) ) { my $tmp_pv_list_handle = $vg_pv{$vg_name}; push ( @$tmp_pv_list_handle, $pv_name ); } else { my @tmp_pv_list = ( $pv_name ); push (@vgs, $vg_name); $vg_pv{$vg_name} = \@tmp_pv_list; $vg_vg{$vg_name}=$vg_name; } # if ( defined($vg_pv{$vg_name}) ) } # if ( 1 != common::is_blank_line($vg_name) ) } else { $lonely_vg = 0; if ( 1 != common::is_blank_line($vg_name)) { if($vg_name ~~ @vgs) {print "Already exists... \n"; } else { push (@vgs, $vg_name);} } # if ( 1 != common::is_blank_line($vg_name) ) } # if ( $pv_name_valid > 0 ) $pv_name_valid = 0; } # if ( $pv_name_valid == 0 && $itor =~ /^\s*PV\s*Name\s*(\S+)\s*$/ ) } # foreach $itor ( @output ) #@vgs = keys(%vg_pv); foreach $itor ( keys(%pv_vg) ) { if ( defined($pt_dk{$itor}) ) { $pt_vg{$itor} = $pv_vg{$itor}; } else { if ( defined($md_md{$itor}) ) { $md_vg{$itor} = $pv_vg{$itor}; } $dk_vg{$itor} = $pv_vg{$itor}; } # if ( defined($pt_dk{$itor}) ) } # foreach $itor ( keys(%pv_vg) ) common::reverse_hashlist( \%pt_vg, \%vg_pt, \@vgs); common::reverse_hashlist( \%dk_vg, \%vg_dk, \@vgs); common::reverse_hashlist( \%md_vg, \%vg_md, \@vgs); $this->{'pod:vg'} = wrapper::new( 'type' => 'Hash', 'handle' => \%pv_vg ); $this->{'vg:pod'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%vg_pv ); $this->{'pt:vg'} = wrapper::new( 'type' => 'Hash', 'handle' => \%pt_vg ); $this->{'vg:pt'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%vg_pt ); $this->{'dk:vg'} = wrapper::new( 'type' => 'Hash', 'handle' => \%dk_vg ); $this->{'vg:dk'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%vg_dk ); $this->{'md:vg'} = wrapper::new( 'type' => 'Hash', 'handle' => \%md_vg ); $this->{'vg:md'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%vg_md); $this->{'vg:vg'} = wrapper::new( 'type' => 'Hash', 'handle' => \%vg_vg ); $this->{'vg'} = wrapper::new( 'type' => 'List', 'handle' => \@vgs ); return 0; } sub harvest_logicalvolume { my $this = shift; my $rc = 0; my $cmd = ''; my $itor = ''; my $lv_name = ''; my $vg_name = ''; my $short_lvname = ''; my %lv_vg =(); # LV to VG my %vg_lv =(); # VG to LV my %lv_lv =(); # LV to LV my @lvs = (); # LV List my @vgs = (); # VG List my %lvname_long2short = (); # LV : long name to short name my @output = (); my $list_handle; $cmd = 'lvdisplay 2>/dev/null'; @output = `$cmd`; $rc = $? >> 8; if ( $rc != 0 ) { common::exit_with_msg("System Error: Invoke '$cmd' failed with RC=$rc\n", 3); } $list_handle = wrapper::get_handle( $this->{'vg'}, 'List'); @vgs = @$list_handle; foreach $itor ( @output ) { next if ( 1 == common::is_blank_line($itor) ); if ( length($lv_name) == 0 && $itor =~ /^\s*LV\s*Path\s*(\S+)\s*$/ ) { $lv_name = $1; } if ( length($lv_name) == 0 && $itor =~ /^\s*LV\s*Name\s*(\S+)\s*$/ ) { $lv_name = $1; } elsif ( length($lv_name) > 0 && $itor =~ /^\s*VG\s*Name\s*(\S*)\s*$/ ) { $vg_name = $1; push( @lvs, $lv_name ); if ( $lv_name =~ /\/([^\/]+)$/ ) { $short_lvname = $1; $lvname_long2short{$lv_name} = $short_lvname; } # if ( $lv_name =~ /\/([^\/]+)$/ ) if ( 1 != common::is_blank_line($vg_name) ) { $lv_lv{$lv_name}=$lv_name; $lv_vg{$lv_name}=$vg_name; $vg_name = ''; } # if ( 1 != common::is_blank_line($vg_name) ) $lv_name = ''; } # if ( length($lv_name) == 0 && $itor =~ /^\s*LV\s*Name\s*(\S+)\s*$/ ) } # foreach $itor ( @output ) common::reverse_hashlist( \%lv_vg, \%vg_lv, \@vgs ); $this->{'lv:vg'} = wrapper::new( 'type' => 'Hash', 'handle' => \%lv_vg ); $this->{'lv:lv'} = wrapper::new( 'type' => 'Hash', 'handle' => \%lv_lv ); $this->{'vg:lv'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%vg_lv ); $this->{'lv'} = wrapper::new( 'type' => 'List', 'handle' => \@lvs ); $this->{'lv:short_lv'} = wrapper::new( 'type' => 'Hash', 'handle' => \%lvname_long2short ); return 0; } sub harvest_filessystem { my $this = shift; my $rc = 0; my $cmd = ''; my $line = ''; my $itor = ''; my @out = (); my @lvs = (); # LV List my @pts = (); # ParTition List my @dks = (); # DisK List my %mds = (); # MD Hash my %fs_fs = (); # FS to FS my %fs_lv = (); # FS to LV my %lv_fs = (); # LV to FS my %fs_pt = (); # FS to ParTition my %pt_fs = (); # ParTition to FS my %fs_dk = (); # FS to DisK my %dk_fs = (); # DisK to FS my %md_fs = (); # MD to FS my %fs_md = (); # FS to MD my %fs_pod = (); # FS to ParTition or Disk my %pod_fs = (); # ParTition or Disk to FS my @fs = (); # FS List my %fs_mp = (); # FS : device name to mount point my %fs_mnt = (); # FS : device name to real mount point my %fs_sysmnt = (); # FS : device naem to system mount point information my %mded = (); # FS : MD-ed deviced to MD deviced my $list_handle; $list_handle = wrapper::get_handle( $this->{'lv'}, 'List' ); @lvs = @$list_handle; $list_handle = wrapper::get_handle( $this->{'pt'}, 'List' ); @pts = @$list_handle; $list_handle = wrapper::get_handle( $this->{'dk'}, 'List' ); @dks = @$list_handle; $list_handle = wrapper::get_handle( $this->{'md:md'}, 'Hash' ); %mds = %$list_handle; $list_handle = wrapper::get_handle( $this->{' | mded | '}, 'Hash' ); %mded = %$list_handle; # By using /bin/df to collection the MountPoint information #Filesystem Type 1024-blocks Used Available Capacity Mounted on #/dev/sda2 reiserfs 34506524 3552400 30954124 11% / #proc proc 0 0 0 - /proc #sysfs sysfs 0 0 0 - /sys #tmpfs tmpfs 257044 12 257032 1% /dev/shm #devpts devpts 0 0 0 - /dev/pts #/dev/hda subfs 0 0 0 - /media/cdrom #/dev/fd0 subfs 0 0 0 - /media/floppy #usbfs usbfs 0 0 0 - /proc/bus/usb # $cmd = '/bin/df -alTP'; # common::errlog(" RUN '$cmd'"); # @out = `$cmd`; # $rc = $? >> 8; # if ( $rc != 0 ) { # common::errlog(": failed with RC=$rc\n"); # next; # } else { # common::errlog(": successfully.\n"); # } # # # foreach my $line ( @out ) { # next if ( common::is_blank_line($line) == 1 ); # # if ( $line =~ /^(\S+)\s+(\S+)\s+\d+\s+.*\s+(\S+)\s*$/ ) { # my ($dev_name, $fs_type, $mnt) = ($1, $2, $3); # # if ( support_fs_type($fs_type) == 1 ) { # if ( $dev_name =~ /^\/dev\/mapper\/(\S+)\-(\S+)$/ ) { # $dev_name = "/dev/$1/$2"; # } # # $fs_mnt{ $dev_name } = $mnt; # } # } # } # # # # By read /etc/fstab to collection the MountPoint information # my @save_ARGV = @ARGV; @ARGV = ('/etc/fstab'); #/dev/sda6 / reiserfs acl,user_xattr 1 1 ##/dev/sda7 /data1 auto noauto,user 0 0 #/dev/sda8 /data2 auto noauto,user 0 0 ##/dev/sda9 /data3 auto noauto,user 0 0 #/dev/sda10 /data4 auto noauto,user 0 0 #/dev/sda11 /data5 auto noauto,user 0 0 #/dev/sda12 /data6 auto noauto,user 0 0 #/dev/sda1 /windows/C ntfs ro,users,gid=users,umask=0002,nls=utf8 0 0 #/dev/sda2 /windows/D vfat users,gid=users,umask=0002,iocharset=utf8 0 0 #/dev/sda5 swap swap pri=42 0 0 #devpts /dev/pts devpts mode=0620,gid=5 0 0 #proc /proc proc defaults 0 0 #usbfs /proc/bus/usb usbfs noauto 0 0 #sysfs /sys sysfs noauto 0 0 #/dev/dvd /media/dvd subfs fs=cdfss,ro,procuid,nosuid,nodev,exec,iocharset=utf8 0 0 #/dev/fd0 /media/floppy subfs fs=floppyfss,procuid,nodev,nosuid,sync 0 0 # #LABEL=bbb /data1 auto noauto,user 0 0 #UUID=87b95f27-82a4-4abb-a2a3-1dc4a8e11eeb /data3 auto noauto,user 0 0 foreach $line ( <> ) { next if ( common::is_comment($line) == 1 ); my ($dev_name, $sys_mnt, $fs_type, $option, $p1, $p2) = split(/\s+/, $line); next if ( length($p2) == 0 ); if ( $dev_name =~ /^\s*LABEL=\"?(\S+)\"?\s*$/ ) { $dev_name = "L:$1"; } elsif ( $dev_name =~ /^\s*UUID=\"?(\S+)\"?\s*$/ ) { $dev_name = "U:$1"; } # if ( $dev_name =~ /^\s*LABEL=\"?(\S+)\"?\s*$/ ) # Comment the following line to support build # hash relationship for swap or orther filesytems # the name of which just used to describe the fucntion #if ( support_fs_type($fs_type) == 1 ) { if ( $dev_name =~ /^\/dev\/mapper\/(\S+)\-(\S+)$/ ) { $dev_name = "/dev/$1/$2"; } $fs_sysmnt{ $dev_name } = $sys_mnt; #} } @ARGV = @save_ARGV; %fs_mp = (%fs_sysmnt, %fs_mnt); # build the relationship for fs:lv foreach $itor ( @lvs ) { # skip the MD-ed devices next if(defined($mded{$itor})); $cmd = "blkid $itor"; @out = `$cmd`; $rc = $? >> 8; if ( $rc != 0 ) { common::errlog("Invoke '$cmd' failed with RC=$rc\n"); next; } foreach $line ( @out ) { next if ( common::is_blank_line($line) == 1 ); my @fields = split( /\s+/, $line ); my $dev_name = $itor; my $label_name = ''; my $uuid_name = ''; my $fs_type = ''; foreach my $field (@fields) { if ( $field =~ /LABEL=\"(\S+)\"/ ) { $label_name = "L:$1"; } elsif ( $field =~ /UUID=\"(\S+)\"/ ) { $uuid_name = "U:$1"; } elsif ( $field =~ /\s*TYPE=\"(\S+)\"/) { $fs_type = $1; } } if ( support_fs_type($fs_type) == 1 ) { my $fs_name = $dev_name; if ( defined($fs_mp{$dev_name}) ) { $fs_name = $fs_mp{$dev_name}; } elsif ( defined($fs_mp{$label_name}) ){ $fs_name = $fs_mp{$label_name}; } elsif ( defined($fs_mp{$uuid_name}) ){ $fs_name = $fs_mp{$uuid_name}; } $fs_fs{$fs_name} = $fs_name; $fs_lv{$fs_name} = $dev_name; push ( @fs, $fs_name ); } } } # build relationships for fs:dk foreach my $itor ( @dks ) { # skip the MD-ed devices next if(defined($mded{$itor})); $cmd = "blkid $itor"; @out = `$cmd`; $rc = $? >> 8; if ( $rc != 0 ) { common::errlog("Invoke '$cmd' failed with RC=$rc\n"); next; } foreach $line ( @out ) { next if ( common::is_blank_line($line) == 1 ); my @fields = split( /\s+/, $line ); my $dev_name = $itor; my $label_name = ''; my $uuid_name = ''; my $fs_type = ''; foreach my $field (@fields) { if ( $field =~ /LABEL=\"(\S+)\"/ ) { $label_name = "L:$1"; } elsif ( $field =~ /UUID=\"(\S+)\"/ ) { $uuid_name = "U:$1"; } elsif ( $field =~ /\s*TYPE=\"(\S+)\"/) { $fs_type = $1; } } if ( support_fs_type($fs_type) == 1 ) { my $fs_name = $dev_name; if ( defined($fs_mp{$dev_name}) ) { $fs_name = $fs_mp{$dev_name}; } elsif ( defined($fs_mp{$label_name}) ){ $fs_name = $fs_mp{$label_name}; } elsif ( defined($fs_mp{$uuid_name}) ){ $fs_name = $fs_mp{$uuid_name}; } $fs_fs{$fs_name} = $fs_name; $fs_dk{$fs_name} = $dev_name; if ( defined($mds{$itor}) ) { $fs_md{$fs_name} = $fs_dk{$fs_name}; } push ( @fs, $fs_name ); } } } # build relationships for fs:pt foreach my $itor ( @pts ) { # skip the MD-ed devices next if(defined($mded{$itor})); $cmd = "blkid $itor"; @out = `$cmd`; $rc = $? >> 8; if ( $rc != 0 ) { common::errlog("Invoke '$cmd' failed with RC=$rc\n"); next; } foreach my $line ( @out ) { next if ( common::is_blank_line($line) == 1 ); my @fields = split( /\s+/, $line ); my $dev_name = $itor; my $label_name = ''; my $uuid_name = ''; my $fs_type = ''; foreach my $field (@fields) { if ( $field =~ /LABEL=\"(\S+)\"/ ) { $label_name = "L:$1"; } elsif ( $field =~ /UUID=\"(\S+)\"/ ) { $uuid_name = "U:$1"; } elsif ( $field =~ /\s*TYPE=\"(\S+)\"/) { $fs_type = $1; } } if ( support_fs_type($fs_type) == 1 ) { my $fs_name = $dev_name; if ( defined($fs_mp{$dev_name}) ) { $fs_name = $fs_mp{$dev_name}; } elsif ( defined($fs_mp{$label_name}) ){ $fs_name = $fs_mp{$label_name}; } elsif ( defined($fs_mp{$uuid_name}) ){ $fs_name = $fs_mp{$uuid_name}; } $fs_fs{$fs_name} = $fs_name; $fs_pt{$fs_name} = $dev_name; push ( @fs, $fs_name ); } } } #Harvest GPFS data #File system attributes for /dev/crfs33on33Node: #=============================================== #flag value description #---- ---------------- ----------------------------------------------------- # -o none Additional mount options # -T /gpfs/crfs33on33Node Default mount point # #File system attributes for /dev/f32f33Co: #========================================= #flag value description #---- ---------------- ----------------------------------------------------- # -o none Additional mount options # -T /gpfs/f32f33Co Default mount point # $cmd = '/usr/lpp/mmfs/bin/mmlsfs all -o -T 2>/dev/null'; @out = `$cmd`; my ($mmdev, $mmname) = ('', ''); foreach my $line ( @out ) { next if ( common::is_comment( $line ) == 1 ); if ( $line =~ /^File system attributes for\s*(\S+):\s*$/ ) { $mmdev = $1; } if ( $line =~ /\s*-T\s+(\S+)\s+/ ) { $mmname = $1; if (length($mmdev) != 0) { # $fs_lv{$mmname} = $mmdev; $fs_fs{$mmname} = $mmname; push ( @fs, $mmname ); } } } %fs_pod = ( %fs_pt, %fs_dk ); common::reverse_hash( \%fs_lv, \%lv_fs, \@lvs); common::reverse_hash( \%fs_pt, \%pt_fs, \@pts); common::reverse_hash( \%fs_dk, \%dk_fs, \@dks); my @tmplist = keys(%mds); common::reverse_hash( \%fs_md, \%md_fs, \@tmplist); %pod_fs = ( %pt_fs, %dk_fs ); $this->{'fs:lv'} = wrapper::new( 'type' => 'Hash', 'handle' => \%fs_lv ); $this->{'lv:fs'} = wrapper::new( 'type' => 'Hash', 'handle' => \%lv_fs ); $this->{'fs:pt'} = wrapper::new( 'type' => 'Hash', 'handle' => \%fs_pt ); $this->{'pt:fs'} = wrapper::new( 'type' => 'Hash', 'handle' => \%pt_fs ); $this->{'fs:dk'} = wrapper::new( 'type' => 'Hash', 'handle' => \%fs_dk ); $this->{'dk:fs'} = wrapper::new( 'type' => 'Hash', 'handle' => \%dk_fs ); $this->{'md:fs'} = wrapper::new( 'type' => 'Hash', 'handle' => \%md_fs ); $this->{'fs:md'} = wrapper::new( 'type' => 'Hash', 'handle' => \%fs_md ); $this->{'fs:pod'}= wrapper::new( 'type' => 'Hash', 'handle' => \%fs_pod ); $this->{'pod:fs'}= wrapper::new( 'type' => 'Hash', 'handle' => \%pod_fs ); $this->{'fs'} = wrapper::new( 'type' => 'List', 'handle' => \@fs ); $this->{'fs:fs'} = wrapper::new( 'type' => 'Hash', 'handle' => \%fs_fs ); $this->{'fs:mnt'} = wrapper::new( 'type' => 'Hash', 'handle' => \%fs_mnt ); $this->{'fs:sysmnt'}= wrapper::new( 'type' => 'Hash', 'handle' => \%fs_sysmnt ); return 0; } package srm_reaper; # ------------------------------------------------------------------ # PUBLIC FUNCTIONS # ------------------------------------------------------------------ sub new { my $this = {}; my $proxy; bless $this; $this->harvest_dk_pt_vg($this); $this->harvest_lv_fs($this); $proxy = reaper->new( $this, \&srm_reaper::checkup, \&srm_reaper::checkout ); return $proxy; } sub checkup { my ( $this, $query ) = @_; my $hdl; my $type=''; if ( defined($this->{$query} ) ) { $hdl = $this->{$query}; $type = wrapper::get_type($hdl); if ( $type eq 'Hash_List' ) { return $reaper::rel_one2more; } else { return $reaper::rel_one2one; } } return $reaper::rel_unsupt; } sub checkout { my ($this, $query) = @_; my $relationship = $this->{$query}; return $relationship; } # ------------------------------------------------------------------ # PRIVATE FUNCTIONS # ------------------------------------------------------------------ sub harvest_dk_pt_vg { my $this = shift; my %pod_pt =(); my %pod_dk =(); my %pt_pod =(); my %dk_pod =(); my %dk_dk =(); my %pt_pt =(); my %md_md =(); my %vg_vg =(); my %pod_pod =(); my %pod_vg =(); my %vg_pod =(); my %pt_dk =(); my %dk_pt =(); my %dk_vg =(); my %vg_dk =(); my %md_vg =(); my %vg_md =(); my %pt_vg =(); my %vg_pt =(); my %vgid_vg =(); my %dkid_dk =(); my %ptid_pt =(); my %pt_vgid =(); my %dk_vgid =(); my %tmp =(); my @dks =(); my @mds =(); my @pts =(); my @pods =(); my @vgs =(); my $cmd = ''; my @out = (); my $rc = 0; my $mdflag = 0; ########################################################################### ## DISK COLLECTION ########################################################################### $cmd = 'lsrsrc-api -D"::" -I"::" -s IBM.Disk::ResourceType==0::ResourceHandle::DeviceName::DependentResource::GhostDevice 2>/dev/null'; @out = `$cmd`; $rc = $? >> 8; if ( $rc != 0 ) { # Run double check $cmd = 'lsrsrc IBM.Disk 2>&1 >/dev/null'; $rc = system($cmd) >> 8; if ( $rc != 0 ) { common::exit_with_msg("RSCT Error:RUN '$cmd' failed with RC=$rc\n", 3); } else { @out = (); } } foreach my $line ( @out ) { next if ( 1 == common::is_blank_line($line) ); my ($dkid, $dk, $vgid, $ghost) = split('::', $line); next if ( length($ghost) == 0 ); $mdflag = 0; $mdflag = 1 if ($dk =~ /^\/dev\/md/); $dk = "$::ghost_mark$dk" if ( $ghost != 0 ); push( @dks, $dk ); $dk_vgid{$dk} = $vgid; $dkid_dk{$dkid} = $dk; $dk_dk{$dk} = $dk; if ($mdflag == 1) { $md_md{$dk} = $dk; push(@mds, $dk); } } ########################################################################### ## PARTITION COLLECTION ########################################################################### $cmd = 'lsrsrc-api -D"::" -I"::" -s IBM.Partition::ResourceType==0::ResourceHandle::DeviceName::ContainerResource::DependentResource::GhostDevice 2>/dev/null'; @out = `$cmd`; $rc = $? >> 8; if ( $rc != 0 ) { # Run double check $cmd = 'lsrsrc IBM.Partition 2>&1 >/dev/null'; $rc = system($cmd) >> 8; if ( $rc != 0 ) { common::exit_with_msg("RSCT Error:RUN '$cmd' failed with RC=$rc\n", 3); } else { @out = (); } } foreach my $itor ( @out ) { next if ( 1 == common::is_blank_line($itor) ); my ($ptid, $pt, $dkid, $vgid, $ghost) = split('::', $itor); next if ( length($ghost) == 0 ); my $dk = $dkid_dk{$dkid}; $pt = "$::ghost_mark$pt" if ( $ghost != 0 ); push ( @pts, $pt ); $ptid_pt{$ptid} = $pt; $pt_dk{$pt} = $dk; $pt_vgid{$pt} = $vgid; $pt_pt{$pt} = $pt; } ########################################################################### ## VOLUME GROUP COLLECTION ########################################################################### $cmd = 'lsrsrc-api -D"::" -I"::" -s IBM.VolumeGroup::ResourceType==0::ResourceHandle::VGName::GhostDevice 2>/dev/null'; @out = `$cmd`; $rc = $? >> 8; if ( $rc != 0 ) { # Run double check $cmd = 'lsrsrc IBM.VolumeGroup 2>&1 >/dev/null'; $rc = system($cmd) >> 8; if ( $rc != 0 ) { common::exit_with_msg("RSCT Error:RUN '$cmd' failed with RC=$rc\n", 3); } else { @out = (); } } foreach my $itor ( @out ) { next if ( 1 == common::is_blank_line($itor) ); my ($vgid, $vg, $ghost) = split('::', $itor); next if ( length($ghost) == 0 ); $vg = "$::ghost_mark$vg" if ( $ghost != 0 ); push ( @vgs, $vg ); $vgid_vg{$vgid} = $vg; $vg_vg{$vg} = $vg; } foreach my $itor ( keys(%dk_vgid) ) { my $value = $dk_vgid{$itor}; if ( defined( $vgid_vg{$value} ) ) { my $vg = $vgid_vg{$value}; $dk_vg{$itor} = $vg; if (defined( $md_md{$itor} )) { $md_vg{$itor} = $vg; } } } foreach my $itor ( keys(%pt_vgid) ) { my $value = $pt_vgid{$itor}; if ( defined($vgid_vg{$value}) ) { my $vg = $vgid_vg{$value}; $pt_vg{$itor} = $vg; } } @pods = (@dks, @pts); %pod_vg = (%dk_vg, %pt_vg); %pt_pod = %pt_pt; %dk_pod = %dk_dk; %pod_pod = (%pt_pt, %dk_dk); %pod_dk = (%pt_dk, %dk_dk); common::reverse_hashlist( \%pt_vg, \%vg_pt, \@vgs ); common::reverse_hashlist( \%dk_vg, \%vg_dk, \@vgs ); common::reverse_hashlist( \%md_vg, \%vg_md, \@vgs ); common::reverse_hashlist( \%pt_dk, \%dk_pt, \@dks ); common::reverse_hashlist( \%pod_vg, \%vg_pod, \@vgs ); common::reverse_hashlist( \%pt_pt, \%tmp, \@pods ); %pod_pt = (%tmp, %dk_pt); $this->{' | vg_handle2vg_name | '} = wrapper::new( 'type' => 'Hash', 'handle' => \%vgid_vg ); $this->{' | dk_handle2dk_name | '} = wrapper::new( 'type' => 'Hash', 'handle' => \%dkid_dk ); $this->{' | pt_handle2pt_name | '} = wrapper::new( 'type' => 'Hash', 'handle' => \%ptid_pt ); $this->{'pt:dk'} = wrapper::new( 'type' => 'Hash', 'handle' => \%pt_dk ); $this->{'dk:pt'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%dk_pt ); $this->{'vg:vg'} = wrapper::new( 'type' => 'Hash', 'handle' => \%vg_vg ); $this->{'pt:pt'} = wrapper::new( 'type' => 'Hash', 'handle' => \%pt_pt ); $this->{'dk:dk'} = wrapper::new( 'type' => 'Hash', 'handle' => \%dk_dk ); $this->{'md:md'} = wrapper::new( 'type' => 'Hash', 'handle' => \%md_md ); $this->{'pt:pod'} = wrapper::new( 'type' => 'Hash', 'handle' => \%pt_pod ); $this->{'pod:pt'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%pod_pt ); $this->{'dk:pod'} = wrapper::new( 'type' => 'Hash', 'handle' => \%dk_pod ); $this->{'pod:dk'} = wrapper::new( 'type' => 'Hash', 'handle' => \%pod_dk ); $this->{'pod:pod'} = wrapper::new( 'type' => 'Hash', 'handle' => \%pod_pod ); $this->{'pt:vg'} = wrapper::new( 'type' => 'Hash', 'handle' => \%pt_vg ); $this->{'vg:pt'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%vg_pt ); $this->{'dk:vg'} = wrapper::new( 'type' => 'Hash', 'handle' => \%dk_vg ); $this->{'vg:dk'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%vg_dk ); $this->{'md:vg'} = wrapper::new( 'type' => 'Hash', 'handle' => \%md_vg ); $this->{'vg:md'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%vg_md ); $this->{'pod:vg'} = wrapper::new( 'type' => 'Hash', 'handle' => \%pod_vg ); $this->{'vg:pod'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%vg_pod ); $this->{'pt'} = wrapper::new( 'type' => 'List', 'handle' => \@pts ); $this->{'dk'} = wrapper::new( 'type' => 'List', 'handle' => \@dks ); $this->{'pod'} = wrapper::new( 'type' => 'List', 'handle' => \@pods ); $this->{'vg'} = wrapper::new( 'type' => 'List', 'handle' => \@vgs ); $this->{'md'} = wrapper::new( 'type' => 'List', 'handle' => \@mds ); return 0; } sub harvest_lv_fs { my $this = shift; my %lv_lv =(); my %fs_fs =(); my %lv_vg =(); my %vg_lv =(); my %fs_lv =(); my %lv_fs =(); my %fs_pt =(); my %pt_fs =(); my %fs_dk =(); my %dk_fs =(); my %fs_md =(); my %md_fs =(); my %fs_pod =(); my %pod_fs =(); my @lvs =(); my @fss =(); my %lvid_lv =(); my %lvname_long2short = (); my $hash_handle = wrapper::get_handle( $this->{' | vg_handle2vg_name | '}, 'Hash' ); my %vgid_vg = %$hash_handle; $hash_handle = wrapper::get_handle( $this->{' | pt_handle2pt_name | '}, 'Hash' ); my %ptid_pt = %$hash_handle; $hash_handle = wrapper::get_handle( $this->{' | dk_handle2dk_name | '}, 'Hash' ); my %dkid_dk = %$hash_handle; my $list_handle = wrapper::get_handle ($this->{'dk'}, 'List'); my @dks = @$list_handle; $list_handle = wrapper::get_handle ($this->{'pt'}, 'List'); my @pts = @$list_handle; $list_handle = wrapper::get_handle ($this->{'vg'}, 'List'); my @vgs = @$list_handle; $list_handle = wrapper::get_handle ($this->{'md:md'}, 'Hash'); my %mds = %$list_handle; my $cmd = ''; my @out = (); my $rc = 0; ########################################################################### ## LOGICAL VOLUME COLLECTION ########################################################################### $cmd = 'lsrsrc-api -D"::" -I"::" -s IBM.LogicalVolume::ResourceType==0::ResourceHandle::DeviceName::ContainerResource::GhostDevice 2>/dev/null'; @out = `$cmd`; $rc = $? >> 8; if ( $rc != 0 ) { # Run double check $cmd = 'lsrsrc IBM.LogicalVolume 2>&1 >/dev/null'; $rc = system($cmd) >> 8; if ( $rc != 0 ) { common::exit_with_msg("RSCT Error:RUN '$cmd' failed with RC=$rc\n", 3); } else { @out = (); } } foreach my $itor ( @out ) { next if ( common::is_blank_line($itor) == 1 ); my ($lvid, $lv, $vgid, $ghost) = split('::', $itor); next if ( length($ghost) == 0 ); $lv="$::ghost_mark$lv" if ($ghost != 0); if ( $lv =~ /\/([^\/]+)$/ ) { my $short_lvname = $1; $short_lvname="$::ghost_mark$short_lvname" if ($ghost != 0); $lvname_long2short{"$lv"}= $short_lvname; } push( @lvs, $lv ); $lv_vg{$lv}= $vgid_vg{$vgid}; $lvid_lv{$lvid} = $lv; $lv_lv{$lv} = $lv; } ########################################################################### ## FILE SYSTEM COLLECTION ########################################################################### $cmd = 'lsrsrc-api -D"::" -I"::" -s IBM.AgFileSystem::ResourceType==0::DeviceName::SysMountPoint::MountPoint::ContainerResource::GhostDevice::UserControl::OpState 2>/dev/null'; @out= `$cmd`; $rc = $? >> 8; if ( $rc != 0 ) { # Run double check $cmd = 'lsrsrc IBM.AgFileSystem 2>&1 >/dev/null'; $rc = system($cmd) >> 8; if ( $rc != 0 ) { common::exit_with_msg("RSCT Error:RUN '$cmd' failed with RC=$rc\n", 3); } else { @out = (); } } foreach my $itor ( @out ) { next if ( common::is_blank_line($itor) == 1 ); my ( $fs, $sys_mnt, $mnt, $cont_id, $ghost, $usr_def, $state ) = split('::', $itor); next if ( length($usr_def) == 0 ); if ( common::is_blank_line( $mnt ) == 1 ) { if ( common::is_blank_line( $sys_mnt ) != 1 ) { $fs = $sys_mnt; } } else { if ( $state == 1 ) { $fs = $mnt; } elsif ( common::is_blank_line( $sys_mnt ) != 1 ) { $fs = $sys_mnt; } } if ( $ghost != 0 ) { if ( $usr_def != 0 ) { $fs = "$::ghost_usr_def_mark$fs"; } else { $fs = "$::ghost_mark$fs"; } } else { if ( $usr_def != 0 ) { $fs = "$::usr_def_mark$fs"; } } push ( @fss, $fs ); $fs_fs{$fs} = $fs; if ( defined( $lvid_lv{$cont_id} ) ) { $fs_lv{$fs} = $lvid_lv{$cont_id}; } elsif ( defined( $ptid_pt{$cont_id} ) ) { $fs_pt{$fs} = $ptid_pt{$cont_id}; } elsif ( defined( $dkid_dk{$cont_id} ) ) { $fs_dk{$fs} = $dkid_dk{$cont_id}; if ( defined( $mds{$fs_dk{$fs}} )) { $fs_md{$fs} = $fs_dk{$fs}; } } } %fs_pod=(%fs_pt, %fs_dk); ########################################################################### ## SUMMARY ########################################################################### common::reverse_hashlist( \%lv_vg, \%vg_lv, \@vgs ); common::reverse_hash( \%fs_lv, \%lv_fs, \@lvs); common::reverse_hash( \%fs_pt, \%pt_fs, \@pts ); common::reverse_hash( \%fs_dk, \%dk_fs, \@dks ); my @tmplist = keys(%mds); common::reverse_hash( \%fs_md, \%md_fs, \@tmplist ); %pod_fs = ( %dk_fs, %pt_fs ); $this->{'lv:vg'} = wrapper::new( 'type' => 'Hash', 'handle' => \%lv_vg ); $this->{'vg:lv'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%vg_lv ); $this->{'fs:lv'} = wrapper::new( 'type' => 'Hash', 'handle' => \%fs_lv ); $this->{'lv:fs'} = wrapper::new( 'type' => 'Hash', 'handle' => \%lv_fs ); $this->{'fs:pt'} = wrapper::new( 'type' => 'Hash', 'handle' => \%fs_pt ); $this->{'pt:fs'} = wrapper::new( 'type' => 'Hash', 'handle' => \%pt_fs ); $this->{'fs:dk'} = wrapper::new( 'type' => 'Hash', 'handle' => \%fs_dk ); $this->{'dk:fs'} = wrapper::new( 'type' => 'Hash', 'handle' => \%dk_fs ); $this->{'fs:md'} = wrapper::new( 'type' => 'Hash', 'handle' => \%fs_md ); $this->{'md:fs'} = wrapper::new( 'type' => 'Hash', 'handle' => \%md_fs ); $this->{'fs:fs'}= wrapper::new( 'type' => 'Hash', 'handle' => \%fs_fs ); $this->{'lv:lv'}= wrapper::new( 'type' => 'Hash', 'handle' => \%lv_lv ); $this->{'fs:pod'}= wrapper::new( 'type' => 'Hash', 'handle' => \%fs_pod ); $this->{'pod:fs'}= wrapper::new( 'type' => 'Hash', 'handle' => \%pod_fs ); $this->{'lv'} = wrapper::new( 'type' => 'List', 'handle' => \@lvs ); $this->{'fs'} = wrapper::new( 'type' => 'List', 'handle' => \@fss ); $this->{'lv:short_lv'} = wrapper::new( 'type' => 'Hash', 'handle' => \%lvname_long2short); return 0; } package aix_reaper; #--------------------------------------------------------------------# # aix_reaper : harvest LVM relationships on AIX platformso # # and supply the query function using uniform # # query interface # #--------------------------------------------------------------------# #require Exporter; #require reaper; #@ISA = qw(Exporter reaper); #@EXPORT = qw(checkout checkup); #--------------------------------------------------------------------# # Public functions # #--------------------------------------------------------------------# sub new { # make an instance, and setup the virtual function pointer; my $this = {}; my $proxy; bless $this; $this->harvest_physicalvolume($this); $this->harvest_logicalvolume($this); $this->harvest_filesystem($this); $proxy = reaper->new( $this, \&aix_reaper::checkup, \&aix_reaper::checkout ); return $proxy; } sub checkup { my ( $this, $query ) = @_; my $hdl; my $type=''; if ( defined($this->{$query} ) ) { $hdl = $this->{$query}; $type = wrapper::get_type($hdl); if ( $type eq 'Hash_List' ) { return $reaper::rel_one2more; } else { return $reaper::rel_one2one; } } return $reaper::rel_unsupt; } sub checkout { my ($this, $query) = @_; my $relationship = $this->{$query}; return $relationship; } #--------------------------------------------------------------------# # Private functions # #--------------------------------------------------------------------# sub support_fs_type($) { my $fs_type = shift; my $itor = ''; foreach $itor ( @::Supported_FS_Type_AIX_List ) { if ( $fs_type eq $itor ) { return 1; } } return 0; } #--------------------------------------------------------------------# # # # harvest_physicalvolume : Harvest all valid relaitonships among # # PV, VG, PV to VG on AIX platform # # # # Parameters : # # [aix_reaper_handle] this pointer # # # # Return : # # NULL # # # #--------------------------------------------------------------------# sub harvest_physicalvolume { my $this = shift; my $cmd = ''; my $rc = 0; my @output = (); my %part_disk = (); # Partition to Disk my %disk_disk = (); # Disk to Disk my %part_part = (); # ParTition to ParTition my %pod_dk = (); # ParTition or DisK to DisK my %dk_pod = (); # Disk to ParTition or DisK my %pod_pt = (); # ParTition or DisK to ParTition my %pt_pod = (); # ParTition to ParTition or DisK my %pod_pod = (); # ParTition or DisK to ParTition or DisK my %pod_vg = (); # ParTition or DisK to VG my %vg_pod = (); # VG to ParTition or DisK my %vg_vg = (); # VG to VG my %disk_part = (); # Disk to Partition my %disk_vg = (); # Disk to VG my %vg_disk = (); # VG to Disk my %part_vg = (); # Partition to VG my %vg_part = (); # VG to Partition my @parts = (); # Partition List my @vgs = (); # VG List my @disks = (); # Disk List my @pods = (); # Partition and Disk List my @mds = (); my %md_md = (); my $disk_name = ''; my $part_name = ''; my $vg_name = ''; my $tmp_cmd =''; my $line = ''; my $tmp_rc=0; my $tmp_handle; my $itor; my $vg_valid_flag = 0; my @tmp_out = (); $cmd = '/usr/sbin/lspv -L 2>/dev/null'; #hdisk0 0024a09a1b6f2012 rootvg active #hdisk1 0024a09a543cb76f None #hdisk2 0024a09a50cc0c7d baevg1 #hdisk3 0024a09ad82a0789 yuj_test_vg01 active #hdisk4 0024a09ad82a3a3b yuj_test_vg02 #hdisk5 0024a09ad82a5e81 yuj_test_vg03 #hdisk6 none None #hdisk7 none None #hdisk8 0024a15a54078137 None #hdisk9 0024a15a540785ec None #hdisk10 0024a15a54078735 None active #hdisk11 0024a15a540787f5 None #hdisk12 0024a15a540788bf None #hdisk13 0024a15a5407897f None #hdisk14 0024a15a54078a4a None @output = `$cmd`; $rc = $? >> 8; if ( $rc != 0 ) { common::exit_with_msg("System Error: Invoke '$cmd' failed with RC=$rc\n", 3); } foreach $itor ( @output ) { next if ( 1 == common::is_blank_line($itor) ); # From the src of IBM.StorageRM # A valid Disk resource should belong to a valid VG. if ( $itor =~ /^\s*(\S+)\s*\S+\s*(\S+)\s*\S*\s*$/ ) { $disk_name = $1; $vg_name = $2; $vg_valid_flag = 0; if ( $vg_name =~ /^none$/i ) { # The vg_name matchs /^none$/i, Then use command line # lspv -L disk_name # To do check work. If there is no VG definition on this disk, # It will return a non-zero value, or 0 will be returned. $tmp_cmd = "/usr/sbin/lspv -L $disk_name 2>/dev/null"; @tmp_out = `$tmp_cmd`; $tmp_rc = $? >> 8; if( $tmp_rc != 0 ) { common::errlog("Invoke '$tmp_cmd' failed with RC=[$tmp_rc]\n"); }# if( $tmp_rc != 0 ) foreach $line ( @tmp_out ) { if ( $line =~ /^\s*VG IDENTIFIER\s*\S+\s*$/ ) { $vg_valid_flag++; last; } # if ( $line =~ /^\s*VG IDENTIFIER\s*\S+\s*$/ ) } # foreach $line ( @tmp_out ) } else { # if ( $vg_name =~ /^none$/i ) # Just collect the disks belongs to some valid VG. Command Line: # getlvodm -v vg_name # Is used to do the check work. # $tmp_cmd = "/usr/sbin/getlvodm -v $vg_name 2>/dev/null"; @tmp_out = `$tmp_cmd`; $tmp_rc = $? >> 8; if ( $tmp_rc != 0 ) { common::errlog("Invoke '$tmp_cmd' failed with RC=[$tmp_rc]\n"); }else { $vg_valid_flag++; } # if ( $tmp_rc != 0 ) if ( $vg_valid_flag == 0 ) { foreach my $tmp_line ( @tmp_out ) { if ( $tmp_line =~ /^\s*\S+\s*$/ ) { $vg_valid_flag++; last; } # if ( $tmp_line =~ /^\s*\S+\s*$/ ) } # foreach my $tmp_line ( @tmp_out ) } # if ( $vg_valid_flag == 0 ) } # if ( $vg_name =~ /^none$/i ) if ( $vg_valid_flag != 0 ) { $disk_name = '/dev/'.$disk_name; push ( @disks, $disk_name ); $vg_vg{$vg_name} = $vg_name; $disk_vg{$disk_name} = $vg_name; $disk_disk{$disk_name} = $disk_name; if ( !defined($vg_disk{$vg_name}) ){ my @new_list = ($disk_name); $vg_disk{$vg_name} = \@new_list; } else { #if ( !defined($vg_disk{$vg_name}) ) $tmp_handle = $vg_disk{$vg_name}; push( @$tmp_handle, $disk_name ); } # if ( !defined($vg_disk{$vg_name}) ) } else { # if ( $vg_valid_flag != 0 ) ; } # if ( $vg_valid_flag != 0 ) } # if ( $itor =~ /^\s*(\S+)\s*\S+\s*(\S+)\s*\S*\s*$/ ) } # foreach $itor ( @output ) common::reverse_hashlist( \%part_disk, \%disk_part, \@disks ); @vgs = keys(%vg_vg); @pods = (@disks, @parts); common::reverse_hashlist( \%part_vg, \%vg_part, \@vgs ); %pod_vg = (%disk_vg, %part_vg); %vg_pod = %vg_disk; %pod_pod = %disk_disk; %pod_pt = %disk_part; %dk_pod = %disk_disk; %pod_dk = %disk_disk; # Setup the query entry; $this->{'md:md'} = wrapper::new( 'type' => 'Hash', 'handle' => {} ); $this->{'pt:dk'} = wrapper::new( 'type' => 'Hash', 'handle' => \%part_disk ); $this->{'dk:pt'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%disk_part ); $this->{'pt:vg'} = wrapper::new( 'type' => 'Hash', 'handle' => \%part_vg ); $this->{'vg:pt'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%vg_part ); $this->{'dk:vg'} = wrapper::new( 'type' => 'Hash', 'handle' => \%disk_vg ); $this->{'vg:dk'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%vg_disk ); $this->{'vg:pod'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%vg_pod ); $this->{'pt'} = wrapper::new( 'type' => 'List', 'handle' => \@parts ); $this->{'dk'} = wrapper::new( 'type' => 'List', 'handle' => \@disks ); $this->{'vg'} = wrapper::new( 'type' => 'List', 'handle' => \@vgs ); $this->{'md'} = wrapper::new( 'type' => 'List', 'handle' => [] ); $this->{'pod'} = wrapper::new( 'type' => 'List', 'handle' => \@pods ); $this->{'pod:vg'} = wrapper::new( 'type' => 'Hash', 'handle' => \%pod_vg ); $this->{'pod:dk'} = wrapper::new( 'type' => 'Hash', 'handle' => \%pod_dk ); $this->{'dk:pod'} = wrapper::new( 'type' => 'Hash', 'handle' => \%dk_pod ); $this->{'pod:pt'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%pod_pt ); $this->{'pt:pod'} = wrapper::new( 'type' => 'Hash', 'handle' => \%pt_pod ); $this->{'pt:pt'} =wrapper::new( 'type' => 'Hash', 'handle' => \%part_part ); $this->{'dk:dk'} =wrapper::new( 'type' => 'Hash', 'handle' => \%disk_disk ); $this->{'vg:vg'} =wrapper::new( 'type' => 'Hash', 'handle' => \%vg_vg ); $this->{'pod:pod'} =wrapper::new( 'type' => 'Hash', 'handle' => \%pod_pod ); $this->{'md:vg'} = wrapper::new( 'type' => 'Hash', 'handle' => {}); $this->{'vg:md'} = wrapper::new( 'type' => 'Hash_List', 'handle' => {}); return 0; } #--------------------------------------------------------------------# # # # harvest_logicalvolume : Harvest all valid relaitonships among # # LV, VG, LV to VG on AIX platform # # # # Parameters : # # [aix_reaper_handle] this pointer # # # # Return : # # NULL # # # #--------------------------------------------------------------------# sub harvest_logicalvolume { my $this = shift; my $list_handle; my @vgs = (); # VG list my @lvs = (); # LV list my %vg_lv = (); # VG to LV my %lv_vg = (); # LV to VG my %lv_lv = (); # LV to LV my %lvname_long2short = (); # LV : long name to short name my $itor; my $cmd = ''; my $line= ''; my $rc = 0; my @out = (); my $lv_name = ''; my $short_lvname = ''; $list_handle = wrapper::get_handle($this->{'vg'}, 'List'); @vgs = @$list_handle; foreach $itor ( @vgs ) { $cmd = "/usr/sbin/getlvodm -L $itor 2>/dev/null"; #[c48f1rp16][/]> /usr/sbin/getlvodm -L baevg1 #loglv03 0024a09a00004c000000010d958c50d6.1 #lv00 0024a09a00004c000000010d958c50d6.2 #[c48f1rp16][/]> echo $? #0 #[c48f1rp16][/]> /usr/sbin/getlvodm -L None #[c48f1rp16][/]> echo $? #0 #[c48f1rp16][/]> /usr/sbin/getlvodm -L ABC #[c48f1rp16][/]> echo $? #0 @out = `$cmd`; $rc = $? >> 8; if ( $rc != 0 ) { common::errlog("Invoke '$cmd' failed with RC=$rc.\n"); } foreach $line ( @out ) { if ( $line =~ /\s*(\S+)\s*\S+\s*$/ ) { $short_lvname = $1; $lv_name = "/dev/$short_lvname"; push ( @lvs, $lv_name ); $lv_lv{$lv_name} = $lv_name; $lv_vg{$lv_name} = $itor; $lvname_long2short{$lv_name} = $short_lvname; } } } common::reverse_hashlist( \%lv_vg, \%vg_lv, \@vgs ); # Setup the query entry; $this->{'lv:vg'} = wrapper::new( 'type' => 'Hash', 'handle' => \%lv_vg ); $this->{'lv:lv'} = wrapper::new( 'type' => 'Hash', 'handle' => \%lv_lv ); $this->{'vg:lv'} = wrapper::new( 'type' => 'Hash_List', 'handle' => \%vg_lv ); $this->{'lv'} = wrapper::new( 'type' => 'List', 'handle' => \@lvs ); $this->{'lv:short_lv'} = wrapper::new( 'type' => 'Hash', 'handle' => \%lvname_long2short); return 0; } #--------------------------------------------------------------------# # # # harvest_filesystem : Harvest all valid relaitonships among FS, # # FS to LV, FS to PV on AIX platform # # # # Parameters : # # [aix_reaper_handle] this pointer # # # # Return : # # NULL # # # #--------------------------------------------------------------------# sub harvest_filesystem { my $this = shift; my $list_handle; my @lvs = (); # LV list my @dks = (); # DisK list my @pts = (); # ParTition List my %lsfs = (); # FS list from instruction 'lsfs' my %fs_lv = (); # FS to LV my %fs_fs = (); # FS to FS my %lv_fs = (); # LV to FS my %fs_pt = (); # FS to ParTition my %pt_fs = (); # ParTition to FS my %fs_dk = (); # FS to Disk my %dk_fs = (); # DisK to FS my %fs_pod = (); # FS to Partition Or Disk my %pod_fs = (); # Partition Or Disk to FS my %md_fs = (); # MD to FS my @fs = (); # FS List my $cmd = ''; my $line = ''; my $fs_name = ''; my $mount_dir = ''; my $lv_name = ''; my $fs_type = ''; my $rc = 0; my @out = (); # Read harvested LV, DK, PT List $list_handle = wrapper::get_handle( $this->{'lv'}, 'List' ); @lvs = @$list_handle; $list_handle = wrapper::get_handle( $this->{'dk'}, 'List' ); @dks = @$list_handle; $list_handle = wrapper::get_handle( $this->{'pt'}, 'List' ); @pts = @$list_handle; $cmd = '/usr/sbin/lsfs -ca 2>/dev/null'; #[c48f1rp16][/]> lsfs #Name Nodename Mount Pt VFS Size Options Auto Accounting #/dev/hd4 -- / jfs 262144 -- yes no #/dev/hd1 -- /home jfs 131072 -- yes no #/dev/hd2 -- /usr jfs 5111808 -- yes no #/dev/hd9var -- /var jfs 393216 -- yes no #/dev/hd3 -- /tmp jfs 393216 -- yes no #/proc -- /proc procfs -- -- yes no #/dev/hd10opt -- /opt jfs 131072 -- yes no #/dev/lv00 -- /baelv0 jfs -- rw no no #/dev/yuj_test_lv31 -- /yuj_test_fs31 jfs -- rw no no #/dev/yuj_test_lv21 -- /yuj_test_fs21 jfs -- rw no no #/dev/yuj_test_lv11 -- /yuj_test_fs11 jfs 131072 rw no no #/dev/yuj_test_lv12 -- /yuj_test_fs12 jfs 131072 rw no no #/dev/yuj_test_lv13 -- /yuj_test_fs528 jfs 131072 rw no no #/dev/yuj_test_lv13 -- /yuj_test_fs13 jfs 131072 rw no no #[c48f1rp16][/]> echo $? #0 @out = `$cmd`; $rc = $? >> 8; if ( $rc != 0 ) { common::exit_with_msg("System Error: Invoke '$cmd' failed with RC=$rc\n", 3); } foreach my $line ( @out ) { next if ( common::is_comment( $line ) == 1 ); if ( $line =~ /^([^:]*):([^:]+):([^:]+)/ ) { $mount_dir = $1; $lv_name = $2; $fs_type = $3; if ( support_fs_type($fs_type) == 1 ) { # fs will use mount point directory as name, if the mount point # dir doesn't exist, the lv name will be used. $fs_name = $mount_dir; if ( 1 == common::is_blank_line( $mount_dir ) ) { $fs_name = $lv_name; } $fs_lv{$fs_name} = $lv_name; $fs_fs{$fs_name} = $fs_name; push ( @fs, $fs_name ); } } } #Harvest GPFS data #File system attributes for /dev/crfs33on33Node: #=============================================== #flag value description #---- ---------------- ----------------------------------------------------- # -o none Additional mount options # -T /gpfs/crfs33on33Node Default mount point # #File system attributes for /dev/f32f33Co: #========================================= #flag value description #---- ---------------- ----------------------------------------------------- # -o none Additional mount options # -T /gpfs/f32f33Co Default mount point # $cmd = '/usr/lpp/mmfs/bin/mmlsfs all -o -T 2>/dev/null'; @out = `$cmd`; foreach my $line ( @out ) { next if ( common::is_comment( $line ) == 1 ); if ( $line =~ /^File system attributes for\s*(\S+):\s*$/ ) { $lv_name = $1; } if ( $line =~ /\s*-T\s+(\S+)\s+/ ) { $fs_name = $1; if (length($lv_name) != 0) { # $fs_lv{$fs_name} = $lv_name; $fs_fs{$fs_name} = $fs_name; push ( @fs, $fs_name ); } } } %fs_pod = ( %fs_pt, %fs_dk ); common::reverse_hash( \%fs_lv, \%lv_fs, \@lvs ); common::reverse_hash( \%fs_dk, \%dk_fs, \@dks ); common::reverse_hash( \%fs_pt, \%pt_fs, \@pts ); common::reverse_hash( {}, \%md_fs, [] ); %pod_fs = ( %dk_fs, %pt_fs ); # Setup the query entry; $this->{'fs:lv'} = wrapper::new( 'type' => 'Hash', 'handle' => \%fs_lv ); $this->{'fs:fs'} = wrapper::new( 'type' => 'Hash', 'handle' => \%fs_fs ); $this->{'lv:fs'} = wrapper::new( 'type' => 'Hash', 'handle' => \%lv_fs ); $this->{'fs:pt'} = wrapper::new( 'type' => 'Hash', 'handle' => \%fs_pt ); $this->{'pt:fs'} = wrapper::new( 'type' => 'Hash', 'handle' => \%pt_fs ); $this->{'fs:dk'} = wrapper::new( 'type' => 'Hash', 'handle' => \%fs_dk ); $this->{'dk:fs'} = wrapper::new( 'type' => 'Hash', 'handle' => \%dk_fs ); $this->{'fs:md'} = wrapper::new( 'type' => 'Hash', 'handle' => {} ); $this->{'md:fs'} = wrapper::new( 'type' => 'Hash', 'handle' => \%md_fs ); $this->{'fs:pod'}= wrapper::new( 'type' => 'Hash', 'handle' => \%fs_pod ); $this->{'pod:fs'}= wrapper::new( 'type' => 'Hash', 'handle' => \%pod_fs ); $this->{'fs'} = wrapper::new( 'type' => 'List', 'handle' => \@fs ); return 0; } package config; #--------------------------------------------------------------------# # # # config.pm : config class # # # # This class is uesed to read some system configure information. # # Currently just check unix type is supported. # # # #--------------------------------------------------------------------# # Exporter = qw ( # # get_utype # # ); # #--------------------------------------------------------------------# use constant CFG_MEM_UNAME => 0; sub new { my $this = []; my @uname = (); $this->[CFG_MEM_UNAME] = \@uname; bless $this; return $this; } sub get_utype { my $this = shift; my $uname_handle = $this->[CFG_MEM_UNAME]; if ( scalar( @$uname_handle ) == 0 ) { &__check_uname($this); return $$uname_handle[0]; } else { return $$uname_handle[0]; } } sub __check_uname { my $this = shift; my $rc = 0; my $line = ''; my $utype = ''; my @out = (); my @uname_list = (); my $uname_handle; $uname_handle = $this->[CFG_MEM_UNAME]; @out = `uname 2>/dev/null`; $rc = $? >> 8; if ( $rc != 0 ) { common::exit_with_msg("System Error: Invoked 'uname' command failed with RC=$rc.\n", 3); } foreach $line ( @out ) { next if ( common::is_blank_line ( $line ) == 1 ); if ( $line =~ /^\s*(\S+)\s*$/ ) { $utype = $1; } } push ( @uname_list, $utype ); push ( @$uname_handle, @uname_list ); } package dnode; #--------------------------------------------------------------------# # # # dnode.pm : dnode class # # # # dnode is a double link node, the query result will be dnode-tree # # list. each dnode will describe one field. # # # #--------------------------------------------------------------------# # Exporter = qw ( # # [dnode list] get_children() # # [void] add_child([dnode]) # # [dnode handle] get_parent() # # [void] set_parent([dnode]) # # [any] get_value() # # [void] set_value() # # [integer] children() # # [dnode handle] parent() # # [dnode list] vertical() # # ); # #--------------------------------------------------------------------# use constant DND_MEM_VALUE => 0; use constant DND_MEM_CHILDREN => 1; use constant DND_MEM_PARENT => 2; sub new { my $this = []; my $value = shift; my @children = (); $this->[DND_MEM_VALUE] = $value; # value; $this->[DND_MEM_CHILDREN] = \@children; # children node list; $this->[DND_MEM_PARENT] = 0; # parent node; bless $this; return $this; } sub get_children { my $this = shift; return $this->[DND_MEM_CHILDREN]; } sub get_parent { my $this = shift; return $this->[DND_MEM_PARENT]; } sub get_value { my $this = shift; return $this->[DND_MEM_VALUE]; } sub set_value { my $this = shift; my $value = shift; $this->[DND_MEM_VALUE] = $value; } sub children { my $this = shift; my $ary_handle = $this->[DND_MEM_CHILDREN]; if ( scalar(@$ary_handle) == 0 ) { return 0; } else { return 1; } } sub parent { my $this = shift; return $this->[DND_MEM_PARENT]; } sub add_child { my $this = shift; my $next = shift; my $ary_handle = $this->[DND_MEM_CHILDREN]; $next->[DND_MEM_PARENT] = $this; push ( @$ary_handle, $next ); } sub set_parent { my $this = shift; my $parent = shift; $this->[DND_MEM_PARENT] = $parent; } sub vertical { my $this = shift; my @matrix = (); do { unshift ( @matrix, $this->[DND_MEM_VALUE] ); } while ( ($this = $this->[DND_MEM_PARENT] ) != 0 ); return @matrix; } package ssession; #--------------------------------------------------------------------# # # # ssession.pm : ssession class # # # # ssession will hold an group of query list, can execute it or diff # # its result. # # # #--------------------------------------------------------------------# # @EXPORT = qw( # # get_query # # get_tail # # get_spec # # get_head # # execute # # differ # # vertical # # ); # #--------------------------------------------------------------------# use constant SSES_MEM_QUERY_LIST => 0; use constant SSES_MEM_REAPER => 1; use constant SSES_MEM_HEAD => 2; use constant SSES_MEM_TAIL => 3; use constant SSES_MEM_SPEC => 4; sub new { my $this = []; my $spec = 0; my $qlist_len = 0; my $rel_type = ''; my %params = @_; my $query_list; my $rel_hdl; $this->[SSES_MEM_QUERY_LIST] = $params{'Query'}; $this->[SSES_MEM_REAPER] = $params{'Reaper'}; $this->[SSES_MEM_HEAD] = $params{'Head'}; # Head string $this->[SSES_MEM_TAIL] = 0; # Redundancy structure, tail nodes list; $query_list = $params{'Query'}; $qlist_len = scalar(@$query_list); $spec = $qlist_len; if ( $qlist_len > 0 ) { $rel_hdl = $params{'Reaper'}->reaper::checkout($$query_list[0]); $rel_type = $rel_hdl->get_type(); if ( $rel_type ne 'List' ) { $spec++; } # if ( $rel_type ne 'List' ) } # if ( $qlist_len > 0 ) $this->[SSES_MEM_SPEC] = $spec; bless $this; return $this; } sub get_query { my $this = shift; return $this->[SSES_MEM_QUERY_LIST]; } sub get_spec { my $this = shift; return $this->[SSES_MEM_SPEC]; } sub get_head { my $this = shift; return $this->[SSES_MEM_HEAD]; } sub get_tail { my $this = shift; return $this->[SSES_MEM_TAIL]; } #--------------------------------------------------------------------# # # # execute : query the query list on reaper, and collect the # # result about head string; # # # # Parameters : # # NULL # # # # Return : # # NULL # # # # Used Global Varibale : # # $::nonexistent # describe the non-existent relationship # # # #--------------------------------------------------------------------# sub execute { my $this = shift; my $ret = 0; my $dnode_value = ''; my $relation_type = ''; my $query_list_itor = ''; my @curr_dnode_list = (); my @tail_dnode_list = (); my $reaper = $this->[SSES_MEM_REAPER]; my $head_dnode = $this->[SSES_MEM_HEAD]; my $query_list = $this->[SSES_MEM_QUERY_LIST]; my $relation; my $dnode_itor; my $relation_handle; @curr_dnode_list = ( $head_dnode ); foreach $query_list_itor ( @$query_list ) { $relation = $reaper->reaper::checkout($query_list_itor); $relation_type = wrapper::get_type($relation); @tail_dnode_list = (); if ( $relation_type eq 'Hash_List' ) { $relation_handle = wrapper::get_handle($relation, 'Hash_List'); foreach $dnode_itor ( @curr_dnode_list ) { $dnode_value = $dnode_itor->get_value(); if ( defined( $$relation_handle{ $dnode_value } ) ) { my $target_value_list_handle = $$relation_handle{ $dnode_value }; foreach my $target_value ( @$target_value_list_handle ) { my $target_dnode = dnode::new ( $target_value ); $dnode_itor->add_child( $target_dnode ); push( @tail_dnode_list, $target_dnode ); } # foreach my $target_value ( @$target_value_list_handle ) } else { my $target_dnode = dnode::new ( $::nonexistent ); $dnode_itor->add_child( $target_dnode ); push( @tail_dnode_list, $target_dnode ); } # if ( defined( $$relation_handle{ $dnode_value } ) ) } # foreach my $dnode_itor ( @curr_dnode_list ) } # if ( $relation_type eq 'Hash_List' ) elsif ( $relation_type eq 'Hash' ) { $relation_handle = wrapper::get_handle($relation, 'Hash'); foreach $dnode_itor ( @curr_dnode_list ) { $dnode_value = $dnode_itor->get_value(); if ( defined( $$relation_handle{ $dnode_value } ) ) { my $target_value = $$relation_handle{ $dnode_value }; my $target_dnode = dnode::new ( $target_value ); $dnode_itor->add_child( $target_dnode ); push( @tail_dnode_list, $target_dnode ); } else { my $target_dnode = dnode::new ( $::nonexistent ); $dnode_itor->add_child( $target_dnode ); push( @tail_dnode_list, $target_dnode ); } # if ( defined( $$relation_handle{ $dnode_value } ) ) } # foreach $dnode_itor ( @curr_dnode_list ) } # if ( $relation_type eq 'Hash_List' ) elsif ( $relation_type eq 'List' ) { foreach $dnode_itor ( @curr_dnode_list ) { push ( @tail_dnode_list, $dnode_itor ); } # foreach $dnode_itor ( @curr_dnode_list ) } # elsif ( $relation_type eq 'List' ) @curr_dnode_list = @tail_dnode_list; } # foreach $query_list_itor ( @$query_list ) $this->[SSES_MEM_TAIL] = \@tail_dnode_list; return $ret; } #--------------------------------------------------------------------# # # # differ : diff tow session, and return back the common and different# # data; # # # # Parameters : # # [ssession handle] other # # [list_handle] the common data from this ssession # # [list_handle] the common data from the other ssession # # [list_handle] the special data from this ssession # # [list_handle] the special data from the other ssession # # # # Return : # # [Integer] 0 : no difference, >0 : different # # # #--------------------------------------------------------------------# sub differ { my ( $this, $other, $this_com_list, $other_com_list, $this_spe_list, $other_spe_list ) = @_; my $ret = 0; my $itor = ''; my @this_nd_vtor = (); my @other_nd_vtor = (); my $this_tail = $this->[SSES_MEM_TAIL]; my $other_tail = $other->[SSES_MEM_TAIL]; foreach $itor ( @$this_tail ) { my @temp_list = dnode::vertical($itor); push ( @this_nd_vtor, \@temp_list ); } foreach $itor ( @$other_tail ) { my @temp_list = dnode::vertical($itor); push ( @other_nd_vtor, \@temp_list ); } $ret = common::differ(\@this_nd_vtor, \@other_nd_vtor, $this_com_list, $other_com_list, $this_spe_list, $other_spe_list, \&common::strlist_cmp ); return $ret; } #--------------------------------------------------------------------# # # # vertical : vertical the result # # # # Parameters : # # [list_handle] result matrix handle # # [Integer] Begin Pos [Option] # # [Integer] End Pos [Opition] # # # # Return : # # NULL # # # #--------------------------------------------------------------------# sub vertical { my $this = shift; my $matrix = shift; my $begin = shift || 0; my $end = shift || -1; my $offset = 0; my $length = 0; my @last_unrepeat_row = (); my $tail_list; @$matrix = (); $tail_list = $this->[SSES_MEM_TAIL]; $length = scalar ( @$tail_list ); $offset = $begin; if ( $end < 0 || $end > $length ) { $end = $length; } while ( $offset < $end ) { my $start_dnode = $$tail_list[$offset]; my @curr_list = (); my $curr_list_offset = 0; my $insert_flag = 1; my $loop_flag = 1; while( $loop_flag == 1 ) { if ( $insert_flag == 1 && !defined($last_unrepeat_row[$curr_list_offset]) ) { $insert_flag = 1; } elsif ( $insert_flag == 1 && $start_dnode != $last_unrepeat_row[$curr_list_offset] ) { $insert_flag = 1; } else { $insert_flag = 0; } if ( $insert_flag == 0 ) { push ( @curr_list, dnode::new( $::padding ) ); } else { push ( @curr_list, $start_dnode ); $last_unrepeat_row[ $curr_list_offset ] = $start_dnode; } if ( $start_dnode->parent() != 0 ) { $start_dnode = $start_dnode->get_parent(); } else { $loop_flag = 0; } $curr_list_offset++; } push(@$matrix, \@curr_list); $offset++; } } package sgroup; #--------------------------------------------------------------------# # # # sgroup.pm : sgroup class # # # # sgroup manage 2 ssession: left ssession and right ssession. # # A query list will be divided into 2 parts: left query list and # # right query list. # # # #--------------------------------------------------------------------# # @EXPORT = qw( # # get_lquery # # get_rquery # # get_lsession # # get_rsession # # vertical # # execute # # superficially_differ # # differ # # get_result # # ); # #--------------------------------------------------------------------# use constant SGRP_MEM_HEAD => 0; use constant SGRP_MEM_REAPER => 1; use constant SGRP_MEM_LEFTQ_LIST => 2; use constant SGRP_MEM_RIGHTQ_LIST => 3; use constant SGRP_MEM_SESSIONS => 4; use constant SGRP_MEM_RESULT => 5; sub new { my $this = []; my %params = @_; my @result = (); my @seses = (); $this->[SGRP_MEM_HEAD] = $params{'Head'}; $this->[SGRP_MEM_REAPER] = $params{'Reaper'}; $this->[SGRP_MEM_LEFTQ_LIST] = $params{'LeftQuery'}; $this->[SGRP_MEM_RIGHTQ_LIST] = $params{'RightQuery'}; $this->[SGRP_MEM_SESSIONS] = \@seses; # session list; $this->[SGRP_MEM_RESULT] = \@result; # session list; bless $this; return $this; } sub get_lquery { my $this = shift; return $this->[SGRP_MEM_LEFTQ_LIST]; } sub get_rquery { my $this = shift; return $this->[SGRP_MEM_RIGHTQ_LIST]; } sub get_lsession { my $this = shift; my $session_list_hdl = $this->[SGRP_MEM_SESSIONS]; return $$session_list_hdl[0]; } sub get_rsession { my $this = shift; my $session_list_hdl = $this->[SGRP_MEM_SESSIONS]; return $$session_list_hdl[1]; } sub vertical { my $this = shift; my $l_len = 0; my $r_len = 0; my $offset = 0; my $length = 0; my $spec_len = 0; my $session_list_hdl = $this->[SGRP_MEM_SESSIONS]; # Session list handle my $matrix = $this->[SGRP_MEM_RESULT]; # result list my $l_session = $$session_list_hdl[0]; # Left query session my $r_session = $$session_list_hdl[1]; # Right query session my @l_matrix = (); my @r_matrix = (); my @blank_line = (); @$matrix = (); $l_session->ssession::vertical(\@l_matrix); $r_session->ssession::vertical(\@r_matrix); # The follow code will format the result $l_len = scalar( @l_matrix ); $r_len = scalar( @r_matrix ); if ( $l_len > $r_len ) { $spec_len = $r_session->get_spec(); $length = $l_len; common::repeat_list ( \@blank_line, dnode::new($::padding), $spec_len ); common::repeat_list ( \@r_matrix, \@blank_line, $length - $r_len ); } else { $spec_len = $l_session->get_spec(); $length = $r_len; common::repeat_list ( \@blank_line, dnode::new($::padding), $spec_len ); common::repeat_list ( \@l_matrix, \@blank_line, $length - $l_len ); } while ( $offset < $length ) { my @temp_line = (); my $l_part = $l_matrix[$offset]; my $r_part = $r_matrix[$offset]; @temp_line = @$l_part; pop( @temp_line ); push ( @temp_line, reverse( @$r_part ) ); push ( @$matrix, \@temp_line ); $offset++; } return @$matrix; } sub execute { my $this = shift; my $ret_code = 0; my $ret_msg = 0; my @session_group = (); my $left_session; my $right_session; my $str_head = $this->[SGRP_MEM_HEAD]; my $reaper = $this->[SGRP_MEM_REAPER]; my $left_qlist = $this->[SGRP_MEM_LEFTQ_LIST]; my $right_qlist = $this->[SGRP_MEM_RIGHTQ_LIST]; my $left_head_dnode = dnode::new($str_head); my $right_head_dnode = dnode::new($str_head); # Setup the left session $left_session = ssession::new( 'Reaper' => $reaper, 'Query' => $left_qlist, 'Head' => $left_head_dnode ); ($ret_code, $ret_msg) = ssession::execute($left_session); if ( $ret_code != 0 ) { return ( $ret_code, $ret_msg ); } push ( @session_group, $left_session ); # Setup the right session $right_session = ssession::new( 'Reaper' => $reaper, 'Query' => $right_qlist, 'Head' => $right_head_dnode ); ($ret_code, $ret_msg) = ssession::execute($right_session); if ( $ret_code != 0 ) { return ( $ret_code, $ret_msg ); } # Setup session group push ( @session_group, $right_session ); $this->[SGRP_MEM_SESSIONS] = \@session_group; return ( $ret_code, $ret_msg ); } sub superficially_differ { my ( $this, $other ) = @_; if ( $this->[SGRP_MEM_HEAD] eq $other->[SGRP_MEM_HEAD] ) { return 0; } else { return 1; } } sub differ { my ( $this, $other, $com_list, $tspe_list, $ospe_list ) = @_; my $tmp_ret = 0; my $ret = 0; my $left_spec_len = 0; my @spec_blank = (); my @tl_com = (); # This::left COMmon data list my @tr_com = (); # This::Right ... my @ol_com = (); # Other::Left ... my @or_com = (); # Other::Right... my @tl_spe = (); # This::left SPEcial data list my @tr_spe = (); # This::Right ... my @ol_spe = (); # Other::Left ... my @or_spe = (); # Other::Right... my $this_sessions = $this->[SGRP_MEM_SESSIONS]; my $other_sessions = $other->[SGRP_MEM_SESSIONS]; my $itor; my $this_left = $$this_sessions[0]; my $this_right = $$this_sessions[1]; my $other_left = $$other_sessions[0]; my $other_right = $$other_sessions[1]; $tmp_ret = ssession::differ($this_left, $other_left, \@tl_com, \@ol_com, \@tl_spe, \@ol_spe); $ret += $tmp_ret; $tmp_ret = ssession::differ($this_right, $other_right, \@tr_com, \@or_com, \@tr_spe, \@or_spe); $ret += $tmp_ret; @$com_list = (); @$tspe_list = (); @$ospe_list = (); foreach $itor ( @tl_com ) { my @temp = reverse ( @$itor ); push ( @$com_list, \@temp ); } foreach $itor ( @tl_spe ) { my @temp = reverse ( @$itor ); push ( @$tspe_list, \@temp ); } foreach $itor ( @ol_spe ) { my @temp = reverse ( @$itor ); push ( @$ospe_list, \@temp ); } $left_spec_len = $this_left->get_spec() ; common::repeat_list(\@spec_blank, $::padding, $left_spec_len-1 ); foreach $itor ( @tr_com ) { my @temp = ( @spec_blank, @$itor ); push ( @$com_list, \@temp ); } foreach $itor ( @tr_spe ) { my @temp = ( @spec_blank, @$itor ); push ( @$tspe_list, \@temp ); } foreach $itor ( @or_spe ) { my @temp = ( @spec_blank, @$itor ); push ( @$ospe_list, \@temp ); } return $ret; } sub eval_dnode_list { my ($dnode_list, $value_list) = @_; my $nd; foreach $nd ( @$dnode_list ) { if ( $nd !~ /^\s*$/ ) { push ( @$value_list, dnode::get_value($nd) ); } else { push ( @$value_list, $nd ); } } } sub get_result { my $this = shift; my @result = (); my $matrix = $this->[SGRP_MEM_RESULT]; my $row; foreach $row ( @$matrix ) { my @temp = (); &eval_dnode_list( $row, \@temp ); push ( @result, \@temp ); } return @result; } package smanager; # @EXPORT = qw( # get_key # has_one2more # query # get_result # diff_result # apply # check # ); use constant SMGR_MEM_REAPER => 0; use constant SMGR_MEM_QUERY => 1; use constant SMGR_MEM_SGROUP => 2; use constant SMGR_MEM_KEY => 3; use constant SMGR_MEM_ONE2MORE => 4; use constant SMGR_MEM_LEFTQ_LIST => 5; use constant SMGR_MEM_RIGHTQ_LIST => 6; use constant SMGR_MEM_RESULT => 7; use constant SMGR_MEM_KEY_STR => 8; # new sub new { my $this = []; my %params = @_; my @s_grps = (); $this->[SMGR_MEM_REAPER] = $params{'Reaper'}; # reaper handle $this->[SMGR_MEM_QUERY] = $params{'Query List'}; # query list $this->[SMGR_MEM_SGROUP] = \@s_grps; # session group list; $this->[SMGR_MEM_KEY] = 0; # Key position $this->[SMGR_MEM_KEY_STR] = ''; # Key value $this->[SMGR_MEM_ONE2MORE] = 0; # if has 1-to-more rels; $this->[SMGR_MEM_LEFTQ_LIST] = 0; # Left part of query list; $this->[SMGR_MEM_RIGHTQ_LIST] = 0; # Right part of query list; $this->[SMGR_MEM_RESULT] = 0; # Result bless $this; return $this; } sub get_key { my $this = shift; return $this->[SMGR_MEM_KEY]; } sub has_one2more { my $this = shift; return $this->[SMGR_MEM_ONE2MORE]; } sub query { my $this = shift; my $ret_code = 0; my $ret_msg = ''; my $reaper = $this->[SMGR_MEM_REAPER]; # reaper handle my $s_grp_hdl = $this->[SMGR_MEM_SGROUP]; # sgroup list handle my $left_query_list_hdl = $this->[SMGR_MEM_LEFTQ_LIST]; # left request list handle my $right_query_list_hdl = $this->[SMGR_MEM_RIGHTQ_LIST]; # right request list handle my $rel_hdl = $reaper->reaper::checkout( $$right_query_list_hdl[0] ); # key's relationship handle my $rel_type = $rel_hdl->wrapper::get_type(); # key's relationship type; my @tmp = (); my @keys = (); # key's value list; my @result = (); my $list_hdl; my $hash_hdl; my $itor; if ( $rel_type eq 'List' ) { $list_hdl = wrapper::get_handle($rel_hdl, 'List'); @keys = sort @$list_hdl; } elsif ( $rel_type eq 'Hash' or $rel_type eq 'Hash_List' ) { $hash_hdl = wrapper::get_handle($rel_hdl, $rel_type); @keys = sort (keys(%$hash_hdl)); if ( scalar( @keys ) == 0 ) { $rel_hdl = $reaper->reaper::checkout( $this->[SMGR_MEM_KEY_STR] ); # key's relationship handle $list_hdl = wrapper::get_handle($rel_hdl, 'List'); @keys = sort @$list_hdl; } } foreach $itor ( @keys ) { my @tmp_matrix = (); # make a sgroup to finish the query work; my $tmp_sgrp = sgroup::new('Head'=>$itor, 'Reaper'=>$reaper, 'LeftQuery'=>$left_query_list_hdl, 'RightQuery'=>$right_query_list_hdl); ($ret_code, $ret_msg) = $tmp_sgrp->sgroup::execute(); if ( $ret_code != 0 ) { return ($ret_code, $ret_msg); } @tmp_matrix = $tmp_sgrp->sgroup::vertical(); push ( @result, \@tmp_matrix ); push ( @$s_grp_hdl, $tmp_sgrp ); } $this->[SMGR_MEM_RESULT] = \@result; } # result_hdl will hold a matrix list; # each matrix for one scope; sub get_result { my $this = shift; my $sgrps = $this->[SMGR_MEM_SGROUP]; my @results = (); my $itor; foreach $itor (@$sgrps ) { my @tmp_result = sgroup::get_result($itor); push ( @results, \@tmp_result); } return @results; } # The head data will from a list or a hash whch is collected from system or Storage RM # This must be ensured. sub diff_result { my ( $left, $right, $com_list, $l_spe_list, $r_spe_list ) = @_; my $ret = 0; my $len = 0; my $itr = 0; my $tmp_ret = 0; my $l_sgrps = $left->[SMGR_MEM_SGROUP]; my $r_sgrps = $right->[SMGR_MEM_SGROUP]; my @l_com = (); my @r_com = (); my @l_spe = (); my @r_spe = (); my $itor; # The head data will from a list or a hash whch is collected from system or Storage RM # This must be ensured. $tmp_ret = common::differ( $l_sgrps, $r_sgrps, \@l_com, \@r_com, \@l_spe, \@r_spe, \&sgroup::superficially_differ ); $ret += $tmp_ret; foreach $itor ( @l_spe ) { my @tmp_result = sgroup::get_result( $itor ); push ( @$l_spe_list, \@tmp_result ); } foreach $itor ( @r_spe ) { my @tmp_result = sgroup::get_result( $itor ); push ( @$r_spe_list, \@tmp_result ); } $len = scalar(@l_com); $itr = 0; while ( $itr < $len ) { my @tmp_com = (); my @tmp_lspe = (); my @tmp_rspe = (); my $tmp_lgrp = $l_com[$itr]; my $tmp_rgrp = $r_com[$itr]; $tmp_ret = sgroup::differ($tmp_lgrp, $tmp_rgrp, \@tmp_com, \@tmp_lspe, \@tmp_rspe); $ret += $tmp_ret; push ( @$com_list , \@tmp_com); push ( @$l_spe_list , \@tmp_lspe); push ( @$r_spe_list , \@tmp_rspe); $itr++; } return $ret; } # apply additional query rule on result sub apply { my ( $this, $rule ) = @_; my $matrixs = $this->[SMGR_MEM_RESULT]; my $reaper = $this->[SMGR_MEM_REAPER]; my $query = $this->[SMGR_MEM_QUERY]; my $query_pair = ''; my $rel_type = ''; my $offset = 0; my $seg_itor; my $row_itor; my $rel_hdl; my $hash_hdl; my $node; my $value; my $length = scalar( @$rule ); while ( $offset < $length ) { if ( defined($$rule[$offset]) ) { $query_pair = $$rule[$offset]; # check if reaper support this relationship; if ( $reaper->reaper::checkup( $query_pair ) == -1 ) { return (1, "$query_pair: No such direct relation exists." ); } # if ( $reaper->reaper::checkup( $query_pair ) # check if reaper support this relationship; $rel_hdl = $reaper->reaper::checkout($query_pair); $rel_type = wrapper::get_type( $rel_hdl ); if ( $rel_type ne 'Hash' ) { return (2, "Invalid query string. $query_pair should be a hash table."); } # if ( $rel_type ne 'Hash' ) $hash_hdl = wrapper::get_handle( $rel_hdl, 'Hash' ); foreach $seg_itor ( @$matrixs ) { foreach $row_itor ( @$seg_itor ) { $node = $$row_itor[$offset]; $value = dnode::get_value( $node ); if ( defined( $$hash_hdl{$value} ) ) { dnode::set_value($node, $$hash_hdl{$value} ); } # if ( defined( $$hash_hdl{$value} ) ) } # foreach $row_itor ( @$seg_itor ) } # foreach $seg_itor ( @$matrixs ) } # if ( defined($$rule[$offset]) ) $offset++; } # while ( $offset < $length ) return 0; } sub check { my $this = shift; my $reaper = $this->[SMGR_MEM_REAPER]; my $query_list = $this->[SMGR_MEM_QUERY]; my $offset = 0; my $itor = ''; my @left_query_list = (); my @right_query_list = (); my $length = scalar( @$query_list ); if ( $length == 0 ) { return (2, "Invalid query string."); } # Default : The 1st query string is the query key; # Left query list is null; # Right query list is query list; # This just happened in case the all query list is 1-to-1 or more-to-1 rels # combination; $itor = $$query_list[0]; @right_query_list = @$query_list; if ( $itor =~ /\:/ ) { while ( $offset < $length ) { $itor = $$query_list[$offset]; if ( $reaper->reaper::checkup($itor) == -1 ) { return (1, "Invalid query string. $itor:No such direct relation exists.") } # if ( $reaper->reaper::checkup($itor) == -1 ) { # if 1-to-more realtionships are detected. if ( $reaper->reaper::checkup($itor) == 0 ) { if ( $itor =~ /(\S+)\:\S+/ ) { $this->[SMGR_MEM_KEY] = $offset; $this->[SMGR_MEM_ONE2MORE] = 1; if ( $offset > 0 ) { @left_query_list = reverse (@$query_list[ 0 .. $offset - 1 ]); @right_query_list= @$query_list[ $offset .. $length - 1 ]; } # if ( $offset > 0 ) } # if ( $itor =~ /\:/ ) else { return (1, "Invalid query string."); } # if ( $itor =~ /\:/ ) last; } # if ( $reaper->reaper::checkup($itor) == 0 $offset++; } # while ( $offset < $length ) } # else if ( $itor =~ /\:/ ) $offset = $this->[SMGR_MEM_KEY]; $itor = $$query_list[$offset]; if ( $itor =~ /(\S+)\:/ ) { $this->[SMGR_MEM_KEY_STR] = $1; } else { $this->[SMGR_MEM_KEY_STR] = $itor; } # reverse the left query string; $offset = 0; $length = scalar( @left_query_list ); while ( $offset < $length ) { if ( $left_query_list[$offset] =~ /^(\S+)\:(\S+)$/ ) { $left_query_list[$offset] = "$2:$1"; } # if ( $left_query_list[$left_qlist_ofst] =~ /^(\S+)\:(\S+)$/ ) $offset++; } # while ( $left_qlist_ofst < $left_qlist_len ) # Setup the left query list and right query list; $this->[SMGR_MEM_LEFTQ_LIST] = \@left_query_list; $this->[SMGR_MEM_RIGHTQ_LIST]= \@right_query_list; return 0; } package main; #--------------------------------------------------------------------# # Included Libraries and Extensions # #--------------------------------------------------------------------# # Default FiledWidth Hash table %::FW = ( 'fs' => 25, # File System 'lv' => 25, # Logical Volume 'vg' => 25, # Volume Group 'pt' => 25, # ParTition 'dk' => 25, # DisK 'pod' => 25, # ParTition Or DisK 'md' => 25, # MD ); # Default filed header list %::Header = ( 'fs' => 'File System', 'lv' => 'Logical Volume', 'vg' => 'Volume Group', 'pt' => 'Partition', 'dk' => 'Disk', 'pod' => 'Partition and Disk', 'md' => 'MD' ); #Supported File System typs on Linux @::Supported_FS_Type_Linux_List = ( 'ext2', 'ext3', 'reiserfs', 'ext4', 'xfs', ); # Supported Device typs on Linux @::Supported_DEV_Type_Linux_List = ( 'SCSI', ); # Supported File System typs on AIX @::Supported_FS_Type_AIX_List = ( 'jfs', 'jfs2', ); @::RequestList = (); # User specified request list @::AdditionalRequestList = (); # Additional request list @::HeaderList = (); # Output header list @::FiledWidthFmtList = (); # Output filed width list @::SeparatorList = (); # Output separator line list $::ghost_mark = '~'; # prefix for GhostDevice rsrc $::usr_def_mark = '*'; # prefix for UserControl rsrc $::ghost_usr_def_mark = '*~'; # prefix for Ghost UserControl rsrc $::separator = '-'; # Separator symbol $::nonexistent = '-'; # Mark for nonexistent rsrc $::padding = ' '; # Padding symbol $ENV{'CT_MANAGEMENT_SCOPE'} = 0; # Just collect local rsrc info. #$::log_handle; # Global log file handle; $::usage=" Usage: srmdiag [-h] [-r|-s|-d] -q query_string ----------------------- -h - Display the usage information of this command -r - Display only LVM attribute information or the relationship of the LVM attributes collected by RSCT StoragRM. -s - Display only LVM attribute information or the relationship of the LVM attributes collected by system commands. -d - Display the diffrence of attribute information collected from StorageRM and system commands. -q - The query string determines what kind of relationship will be displayed. The following keywords can be used in the string with colon as delimiter. pt Partitiion dk Disk pod Partiition or Disk vg Volume Group lv Logical Volume fs File System Common Query String and explanation: fs - all file systems; lv - all logical volumes; pt - all partitions; dk - all disks; pod - all partitions or disks; fs:lv - the relationship of file system and logical volume; fs:pt - the relationship of file system and logical volume; fs:dk - the relationship of file system and disk; fs:pod - the relationship of file system and partition or disk; fs:pod:dk - the relationship of file system, partition or disk and disk; pt:dk/dk:pt - the relationship of partition and disk; fs:lv:vg - the relationship of file system, logical volume and volume group. File system is the key word to get the relationship; fs:lv:vg:pod - the relationship of file system, logical volume. Volume Group is the key word. Examples: 1. To display the file systems' information collected by rsct. srmdiag -r -q fs 2. Display the relationship among the file system, logical volume and volume group information collected by system command line. srmdiag -s -q fs:lv:vg 3. Display the differences information of filesystem,logical volume, volume group and disk respectively which is collected from RSCT StorageRM and system commands. srmdiag -d -q fs:lv:vg:dk "; #--------------------------------------------------------------------# # Variable # #--------------------------------------------------------------------# my $flag_mark = 1; # refer to '-m' my $flag_truncation = 0; # refer to '-t' my $flag_out_srm = 0; # refer to '-r' my $flag_out_sys = 0; # refer to '-s' my $flag_out_diff = 0; # refer to '-d' my $opt_query_string; # refer to '-q' my $rconfig; my $srm_reaper; # rel-reaper for StorageRM my $sys_reaper; # rel-repaer for System cmd line my @sys_rels=(); # relationships from system cmd line my @srm_rels=(); # relationships from RSCT StorageRM my @diff_rels=(); # differenct relationships my @both_com=(); # carry the common part rels my @sys_spe =(); # carry the system special parts rels my @srm_spe =(); # carry the srm special parts rels my $header_hdl; # output header list handle my $separator_hdl; # separator list handle my $fws_hdl; # output field width list handle my $request_hdl; # request list handle my $add_hdl; # additional relus list handle my $separator_line = ''; # separator line my $header_line = ''; # header line my $sys_rel_mgr; # rels manager for system command line my $srm_rel_mgr; # rels manager for SRM # - my $key_pos = 0; # indicate the key position my $one2more = 0; # indicate if there is one_to_more relationships # existing in user specified query string my $ret_code = 0; my $ret_msg = ''; my $offset = 0; my $line = ''; my $length = 0; my @result = (); my @temp = (); my $u_type; my $segment; my $row; my $flag = 0; my $flag_srm = 0; my $flag_sys = 0; #--------------------------------------------------------------------# # Main Code # #--------------------------------------------------------------------# # Parse the input parameters, exit if there is errors ($flag_mark, $flag_truncation, $flag_out_srm, $flag_out_sys, $flag_out_diff, $opt_query_string ) = &parse_cmd_line; if ( $flag_out_sys ) { $flag_sys++; } if ( $flag_out_srm ) { $flag_srm++; } if ( $flag_out_diff ) { $flag_sys++; $flag_srm++; } # Parse the query string ($ret_code, $ret_msg) = &parse_request_string($opt_query_string, ';', ':'); if ( $ret_code != 0 ) { common::exit_with_msg($ret_msg, 2); } # Create sys::reaper and srm::reaper instances if ( $flag_sys ) { $rconfig = config::new(); # check the system type $u_type = $rconfig->config::get_utype(); if ( $u_type eq 'Linux' ) { # sys_reaper is used to reap information form # Storage related System Command Lines on Linux # LVM should be supprted. $sys_reaper = lix_reaper::new(); } elsif ( $u_type eq 'AIX' ) { # sys_reaper is used to reap information form # Storage related System Command Lines on AIX # LVM should be supprted. $sys_reaper = aix_reaper::new(); } } if ( $flag_srm ) { # srm_reaper is used to reap information form RSCT StorageRM $srm_reaper = srm_reaper::new(); } $offset = 0; $length = scalar(@::RequestList); while ( $offset < $length ) { # Get request list handle and additional rules list handle $request_hdl = $::RequestList[$offset]; $add_hdl = $::AdditionalRequestList[$offset]; # Get header,separator line,field width format,list handle $header_hdl = $::HeaderList[$offset]; $separator_hdl = $::SeparatorList[$offset]; $fws_hdl = $::FiledWidthFmtList[$offset]; # check the query elements and find out the key if ( $flag_sys ) { $sys_rel_mgr = smanager::new('Reaper'=>$sys_reaper, 'Query List'=>$request_hdl ); ($ret_code, $ret_msg) = $sys_rel_mgr->smanager::check(); if ( $ret_code != 0 ) { common::exit_with_msg( $ret_msg, 3 ); } $one2more = $sys_rel_mgr->has_one2more(); $key_pos = $sys_rel_mgr->get_key(); } # check the query elements and find out the key if ( $flag_srm ) { $srm_rel_mgr = smanager::new('Reaper'=>$srm_reaper, 'Query List'=>$request_hdl ); ($ret_code, $ret_msg) = $srm_rel_mgr->smanager::check(); if ( $ret_code != 0 ) { common::exit_with_msg( $ret_msg, 3 ); } $one2more = $srm_rel_mgr->has_one2more(); $key_pos = $srm_rel_mgr->get_key(); } # Mark the key header with '['']' $$header_hdl[$key_pos] = '[' . $$header_hdl[$key_pos] . ']'; # execute query if ( $flag_sys ) { $sys_rel_mgr->smanager::query(); # apply the additional relus; $sys_rel_mgr->smanager::apply($add_hdl); } if ( $flag_srm ) { $srm_rel_mgr->smanager::query(); # apply the additional relus; $srm_rel_mgr->smanager::apply($add_hdl); } $header_line = common::format_list($header_hdl, $fws_hdl, $::padding, $flag_truncation); push(@srm_rels, $header_line); push(@sys_rels, $header_line); $separator_line = common::format_list($separator_hdl, $fws_hdl, $::separator, $flag_truncation); push(@sys_rels, $separator_line ); push(@srm_rels, $separator_line ); # SYSTEM COMMAND LINE if ( $flag_sys ) { @result = $sys_rel_mgr->get_result(); foreach $segment ( @result ) { foreach $row ( @$segment ) { $line = common::format_list($row, $fws_hdl, $::padding, $flag_truncation); push ( @sys_rels, $line); } push ( @sys_rels, $separator_line ) if ( $one2more == 1 ); } } # RSCT STORAGERM if ( $flag_srm ) { @result = $srm_rel_mgr->get_result(); foreach my $segment ( @result ) { foreach $row ( @$segment ) { $line = common::format_list($row, $fws_hdl, $::padding, $flag_truncation); push ( @srm_rels, $line); } push ( @srm_rels, $separator_line ) if ( $one2more == 1 ); } } # Diff them $ret_code = 0; if ( $flag_out_diff ) { $flag = &smanager::diff_result($sys_rel_mgr, $srm_rel_mgr, \@both_com, \@sys_spe, \@srm_spe); if ( $flag != 0 ) { $ret_code = 1; # Get system special information push ( @diff_rels, '>>> The resource or relation only found with system commands:' ); push ( @diff_rels, $header_line); push ( @diff_rels, $separator_line ); foreach $segment ( @sys_spe ) { $flag = 0; foreach $row ( @$segment ) { $flag++; $line = common::format_list($row, $fws_hdl, $::padding, $flag_truncation); push ( @diff_rels, $line); } push ( @diff_rels, $separator_line ) if ( $flag != 0 && $one2more == 1 ); } # foreach $segment ( @sys_spe ) push ( @diff_rels, '' ); # Get RSCT SRM special information push ( @diff_rels, '>>> The resource or relation only found from RSCT StorageRM:' ); push ( @diff_rels, $header_line); push ( @diff_rels, $separator_line ); foreach $segment ( @srm_spe ) { $flag = 0; foreach $row ( @$segment ) { $flag++; $line = common::format_list($row, $fws_hdl, $::padding, $flag_truncation); push ( @diff_rels, $line); } push ( @diff_rels, $separator_line ) if ( $flag != 0 && $one2more == 1 ); } #foreach $segment ( @srm_spe ) push ( @diff_rels, '' ); # Get common informaton push ( @diff_rels, '>>> Existing in both:'); push ( @diff_rels, $header_line); push ( @diff_rels, $separator_line ); foreach $segment ( @both_com ) { foreach $row ( @$segment ) { $line = common::format_list($row, $fws_hdl, $::padding, $flag_truncation); push ( @diff_rels, $line); } push ( @diff_rels, $separator_line ) if ( $one2more == 1 ); } # foreach my $segment ( @com ) } else { push ( @diff_rels, '>>> No differences found.' ); push ( @diff_rels, $header_line); push ( @diff_rels, $separator_line ); # SYSTEM COMMAND LINE @result = $sys_rel_mgr->get_result(); foreach $segment ( @result ) { foreach $row ( @$segment ) { $line = common::format_list($row, $fws_hdl, $::padding, $flag_truncation); push ( @diff_rels, $line); } push ( @diff_rels, $separator_line ) if ( $one2more == 1 ); } } # if ( $flag != 0 ) } push(@sys_rels, "\n\n"); push(@srm_rels, "\n\n"); push(@diff_rels, "\n\n"); $offset++; } if ( $flag_out_sys ) { $line = join( "\n", @sys_rels ); print STDOUT ( "\nThe resource or relation found with system commands:\n" ); print STDOUT ( $line ); } if ( $flag_out_srm ) { $line = join( "\n", @srm_rels ); print STDOUT ( "\nThe resource or relation found from RSCT StorageRM:\n" ); print STDOUT ( $line ); } if ( $flag_out_diff ) { $line = join( "\n", @diff_rels ); print STDOUT ( "\n" ); print STDOUT ( $line ); } #close $::log_handle; exit $ret_code; #--------------------------------------------------------------------# # End Main Code # #--------------------------------------------------------------------# #--------------------------------------------------------------------# # # #- parse_cmd_line : parse cmd line, and return all parameters values # # # # # #- Paremeters : # #- NULL # # # # # #- Return : # #- flg_m # #- flg_t # #- flg_o # #- flg_s # #- flg_d # #- opt_q # # # #--------------------------------------------------------------------# sub parse_cmd_line() { my %opts; my $flag = 0; my $flg_m = 1; my $flg_t = 0; my $flg_s = 0; my $flg_r = 0; my $flg_d = 0; my $opt_q = ''; my $tmp = 0; if( !getopts ("hmtrsdq:", \%opts) ) { print $::usage; common::exit_with_msg("Invalid option.\n", 2); } if( !defined( $opts{"q"} ) ) { print $::usage; exit 0; } if ( defined($opts{"h"}) ) { print $::usage; exit 2; } if ( defined( $opts{"m"} ) ) { $flag++; $flg_m=0; } if ( defined( $opts{"t"} ) ) { $flag++; $flg_t=1; } if( defined( $opts{"r"} ) ) { $flag++; $flg_r++; } if( defined( $opts{"s"} ) ) { $flag++; $flg_s++; } if( defined( $opts{"d"} ) ) { $flag++; $flg_d++; } # 3 options r|s|d are be exclusive $tmp = $flg_r+$flg_s+$flg_d; if ( $tmp > 1 ) { print $::usage; common::exit_with_msg("Invalid option.\n", 2); } elsif ( $tmp == 0 ) { # $flg_r = $flg_s = $flg_d = 1; $flg_r = 1; } if( defined( $opts{"q"} ) ) { $flag++; $opt_q = $opts{"q"}; } if ( $flag == 0 ) { print $::usage; exit 0; } return ( $flg_m, $flg_t, $flg_r, $flg_s, $flg_d, $opt_q ); } #--------------------------------------------------------------------# # # # parse_request_string : Parse user input query string; # # Save the result into global variable $::RequestList; # # And set up the output format at the same time; # # # # # #- Parameters : # # [string] The user input query string; # # [char] The delimiter symbol used to separate fileds; # # [char] The delimiter symbol used to separate format strings; # # # # # #- Return : # # [int] 0 indicate SUCC; # # 1 indicate the input string is NULL or a blank line # # 2 indicate the input format is not correct # # [string] tell the error information; # # # # # #- Global Variables Modified : # # @::RequestList - Carry user requests # # @::AdditionalRequestList - Carry additional requests # # # # # #--------------------------------------------------------------------# sub parse_request_string($$$) { my ($query_string, $de1, $de2) = @_; my $ret_code = 0; my $itor = ''; my $ret_msg = ''; if ( common::is_blank_line($query_string) == 1 ) { return (1, 'Invalid query string.' ); } foreach $itor ( split($de1, $query_string) ) { if ( common::is_blank_line( $itor ) == 1 ) { return (2, 'Invalid query string.' ); } # Parse each query string ($ret_code, $ret_msg) = parse_request_entry($itor, $de2); if ( $ret_code != 0 ) { return (2, $ret_msg); } # Set ornament attributes ($ret_code, $ret_msg) = set_ornament($itor, $de2); if ( $ret_code != 0 ) { return (2, $ret_msg); } } return 0; } #--------------------------------------------------------------------# # parse_request_entry : Parse user input query entry; # # Save the result into global variable @::RequestList; # # Also add some additional rules into @::AdditionalRequestList. # # # # # #- Parameters : # # [string] The user input query entry; # # [char] The delimiter symbol used to separate fileds; # # # # # #- Return : # # [int] 0 indicate SUCC; # # 1 indicate the input string is NULL or blank line # # # # # #- Global Variables Modified : # # @::RequestList - Carry user requests # # @::AdditionalRequestList - Carry additional requests # # # # # #--------------------------------------------------------------------# sub parse_request_entry($$) { my ($request_entry_string, $delimiter) = @_; my @request_entry_list = (); my @additional = (); my $flg_lv = 0; my $flg_vg = 0; my $length = 0; my $offset = 0; my $offset2 = 0; my $prev = ""; my $curr = ""; my @temp = (); my @field_list = (); foreach $prev ( split( /$delimiter/, $request_entry_string ) ) { $curr = common::trim($prev); if ( common::is_blank_line($curr) != 1 ) { push ( @field_list, $curr ); } } $length = scalar(@field_list); if ( $length == 0 ) { return (1, 'Invalid query string.' ); } $offset = 0; while ( $offset < $length ) { $prev = $field_list[$offset]; $offset2 = $offset+1; while ( $offset2 < $length ) { $curr = $field_list[$offset2]; if ( $curr eq $prev ) { return (2, 'Invalid query string.' ); } $offset2++; } $offset++; } @temp = @field_list[1 .. $length-1]; $prev = $field_list[0]; if ( length($prev) == 0 ) { return (2, 'Invalid query string.'); } foreach $curr ( @temp ) { if ( length($curr) == 0 ) { return (2, 'Invalid query string.'); } push ( @request_entry_list, "$prev:$curr"); $prev = $curr; } # foreach $curr ( @temp ) if ( $length == 1 ) { push ( @request_entry_list, $prev ); } # if ( $length == 1 ) # Add default additional rule # If LV exists with VG field, lv display short name will be added. foreach $curr ( @field_list ) { if ( $curr eq 'vg' ) { $flg_vg++; } # if ( $curr eq 'vg' ) elsif ( $curr eq 'lv' ) { $flg_lv++; } # if ( $curr eq 'vg' ) } # foreach $curr ( @field_list ) if ( $flg_lv && $flg_vg ) { $offset = 0; foreach $curr ( @field_list ) { if ( $curr eq 'lv' ) { $additional[$offset]='lv:short_lv'; } # if ( $curr eq 'lv' ) $offset++; } # foreach $curr ( @field_list ) } # if ( $flg_lv && $flg_vg ) push(@::RequestList, \@request_entry_list ); push(@::AdditionalRequestList, \@additional ); return 0; } #--------------------------------------------------------------------# #- set_ornament : Set output field width, header and separator # # line style, and save the result into appropriate # # global variables. # # # # # #- Parameters : # # [string] The user input query string; # # [char] The delimiter symbol used to separate fileds; # # # # # #- Return : # # [int] 0 indicate SUCC; # # 1 indicate FAIL; ( User input error ) # # # # # #- Global Variables Modified : # # @::FiledWidthFmtList -Filed Width format list; # # @::HeaderList -Header line list; # # @::SeparatorList -Separator line list; # # # # # #--------------------------------------------------------------------# sub set_ornament($$) { my ( $query_str, $delimiter ) = @_; my $itor = ''; my @fws = (); # Filed Width my @headers = (); my @separators = (); my @list = split($delimiter, $query_str); foreach $itor (@list) { if ( defined( $::Header{$itor} ) ) { push( @headers, $::Header{$itor} ); } else { return ( 1, "'$itor' : No such resource or relation exists!" ); } # if ( defined( $::CONF{"$itor::Header"}) ) if ( defined( $::FW{$itor} ) ) { push( @fws, $::FW{$itor} ); } else { return ( 1, "'$itor' : No such resource or relation exists!" ); } # if ( defined( $::CONF{"$itor::FW"} ) ) push( @separators, $::separator ); } # foreach $itor (@list) push ( @::FiledWidthFmtList, \@fws ); push ( @::HeaderList, \@headers ); push ( @::SeparatorList, \@separators ); return 0; }