#!/usr/bin/perl # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # # # Licensed Materials - Property of IBM # # (C) COPYRIGHT International Business Machines Corp. 2000,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 = "@(#)09 1.58 src/rsct/rmc/cli/bin/mkrsrc.perl, rmccli, rsct_rady, rady2035a 11/12/15 16:30:06" ###################################################################### # # # Module: mkrsrc # # # # Purpose: # # mkrsrc - Makes (defines) a new resource. # # # # Syntax: # # To define a new resource using data entered on the command line: # # mkrsrc [-h] [-v] [ -N { node_file | "-" } ] [-T] [-V] # # Resource_class Attr=value... [Arg=value...] # # # # To define a new resource using data predefined in an input file: # # mkrsrc [-h] -f Resource_data_input_file [-v] # # [ -N { node_file | "-" } ][-T] [-V] Resource_class # # # # To see examples of the mkrsrc command for a resource class: # # mkrsrc [-h] -e [-T] [-V] Resource_class # # # # Flags: # # -h Help. Writes this command's usage statement to stdout. # # -f Resource_data_input_file File input. Specifies the name of # # the file which contains resource attribute information. # # PersistentResourceAttributes:: # # Resource 1: # # attr1 = value # # attr2 = value # # Resource 2: # # attr1 = value # # attr2 = value # # PersistentResourceArguments:: # # Resource 1: # # arg1 = value # # arg2 = value # # Resource 2: # # arg1 = value # # arg2 = value # # If arguments are specified there must be one set of # # resource arguments for each set of resource attributes. # # Multiple resource instances can be defined in this file. # # -e Example. Displays two examples of suitable command line # # input for this command. # # * Example of mkrsrc command line input for required # # attributes only. # # * Example of mkrsrc command line input for both required # # and optional attributes. # # In addition if any arguments are defined they are # # displayed right after the optional attributes. # # -v Verify. Verifies that all of the specified attributes # # are valid persistent attribute names that have either # # a "reqd_for_define" or "option_for_define" property. # # If any command argument is specified it verifies that # # it is a valid command argument name and that all command # # arguments have been entered. Does not actually define # # the resources. # # -N { node_file | "-" } Specifies that node names are read from # # a file or from standard input. Use -N node_file to # # indicate that the node names are in a file. # # o There is one node name per line in node_file # # o A number sign (#) in column 1 indicates that the line # # is a comment # # o Any blank characters to the left of a node name are # # ignored # # o Any characters to the right of a node name are ignored # # Use -N "-" to read the node names from standard input. # # -T Trace. Writes the command's trace messages to standard # # error. For your software-service organization use only. # # -V Verbose. Writes this command's verbose messages to # # standard output. # # # # Operands: # # Resource_class The resource class name of the resource to be # # defined. # # # # Attr=value Attributes of the resource being defined. When # # defining a new resource instance, there are # # specific required attributes for each resource # # that must be defined. These attributes can be # # specified on the command line or defined in an # # input file and specifying the -f flag. # # # # Attr The name of a persistent attribute for this # # resource. The attribute must have a property of # # "reqd_for_define" or "option_for_define". Use # # the lsrsrcdef command to check the property. # # # # value The value for this persistent attribute. The # # data type for this value must match the defined # # for the value of this attribute. Use the # # lsrsrcdef command to verify the data type for # # each attribute. # # # # Arg=value Enter the command arguments names and values. # # Command arguments are optional. # # If any Arg=value pairs are entered then there # # should be one Arg=value pair for each of the # # the command arguments defined for the define # # function for the specified resource class. # # Use mkrsrc -e to get the list of command # # arguments names and data types for the specific # # resource class. # # Use the lscmdargdef command to view the command # # arguments definition. # # Arg The argument name. # # value The value for this argument, the value data type # # must match the definition of arguments data type.# # Use the lscmdargdef command to verify the data # # type for each argument. # # # # Description: # # The mkrsrc command requests the RMC subsystem to define a new # # resource instance for the class specified by the Resource_class # # operand. At least one persistent attribute name and its value # # must be specified either as an operand or by a resource # # definition file using the -f flag. # # # # Prior to running mkrsrc, you should run the lsrsrcdef command # # to determine which attributes must be specified when defining # # the resource. Attributes that have a "reqd_for_define" property # # must be specified on the command line or in the input file. # # Attributes that have a "option_for_define" property are optional.# # The lsrsrcdef command also identifies the data type for each # # attribute. The value specified for each attribute must match # # this data type. # # # # Example of Resource Data Input File which can be used as input # # to mkrsrc when -f flag is specified. # # vi /tmp/IBM.Foo.rdef # # # Comment character is # # # # AttributeName = Value pairs, spaces or tabs are allowed before # # # or after the AttributeName, =, or Value. # # # All resources between PersistentResourceAttributes and the eof # # # or a :: will be processed by mkrsrc. # # # Next line is required exactly as written below. # # PersistentResourceAttributes:: # # resource 1: # # Name=c175n04 # # NodeList = {1} # # BinaryArray= {"0x01", "0x02", "0x0304"} # # SDArray = {[hello,1,{0,1,2,3}],[hello2,2,{2,4,6,8}]} # # String="hello" # # # # resource 2: # # Name = "c175n05" # # NodeList = {1} # # SDArray = {["hel lo1",1,{0,1,2}],[hello2,2,{3,4,5}]} # # # # Exit Values: # # 0 MC_CLI_SUCCESS Command completed successfully. # # 1 MC_CLI_RMC_ERROR Command terminated due to an underlying # # RMC error. # # 2 MC_CLI_ERROR Command terminated due to an underlying # # error in the command script. # # 3 MC_CLI_BAD_FLAG Command terminated due to user # # specifying an invalid flag. # # 4 MC_CLI_BAD_OPERAND Command terminated due to user # # specifying a bad operand. # # 5 MC_CLI_USER_ERROR Command terminated due to a user error. # # For example specifying an undefined # # Resource name as the Resource operand. # # # # Examples: # # mkrsrc IBM.Foo Name=c175n05 NodeNumber=1 # # mkrsrc -f /tmp/IBM.Foo.rdef IBM.Foo # # # # Man Page: # # For the most current detailed description of this command see # # the mkrsrc man page in /opt/rsct/man. # # # #--------------------------------------------------------------------# # Inputs: # # /opt/rsct/msgmaps/mccli.mkrsrc.map - message mapping # # /opt/rsct/msgmaps/mccli.mccli.map - message mapping # # # # Outputs: # # stdout - any verbose messages. # # stderr - any error message. # # # # External Ref: # # Commands: ctdspmsg # # Modules: MC_cli_utils.pm, MC_cli_rc.pm # # CT_cli_utils.pm, CT_cli_data_type_utils, # # CT_cli_input_utils, CT_cli_display_utils. # # Extensions: CT::MC, CT::MCerr, CT::CT # # Perl library routines: Getopt::Std # # # # Tab Settings: # # 4 and tabs should be expanded to spaces before saving this file. # # in vi: (:set ts=4 and :%!expand -4) # # # # Change Activity: # # 000315 SAB 60909: Initial design & write. # # 001106 GTM 67900: Change -e per review comments # # 010311 SAB 63852: Prepared for GA. # # 010813 SAB 75111: Added support for command arguments. # # 020114 JAC 78199: Add optional parm for cmd args call to process # # input and fix error message. # # 020925 JAC 87393: Change CT_cli_display_utils to .._displayext.. # # 021203 JAC 88085: Modify call to get_sd_defs_api. # # 030212 JAC 89941: Process SD differently for binaries and RHs. # # 030220 JAC 92003: Some commas incorrect in setup_mkrsrcapi. # # 040406 JAC 105863: Use new escape_chars function for escaping # # 040426 JAC 108105: Fix a typo. # # 050707 JAC 116172: Calculate CMD_LIMIT instead of using const. # # 051020 JAC 125712: Use mkrsrc-api -f option when cmd too long. # # 051116 JAC 131200: Check for multiple non-array attributes. # # 051213 JAC 131854: Bad 131200 change. Don't check SDs. # # 060614 JAC 135966: Fix quotes for file input strings. # # 070516 JAC 132926: Add -N and allow for >1 node in NodeNameList. # # 070607 JAC 144354: Only handle >1 node for subdivided classes. # # 070803 JAC 145853: check for -N used with NodeNameList. # # 080718 JAC 152239: -e not valid if class cannot define resources.# ###################################################################### #--------------------------------------------------------------------# # General Program Flow/Logic: # # # # A. Parse command line flags and operands, determine which flavor # # of this command we are actually invoking. # # This command allows a user to: # # * Define a resource using Attr=value pairs specified on the # # command line. # # * Define one or more resources using Attr=value pairs # # that were predefined in a resource data input file in # # stanza format with the PersistentResourceAttributes:: # # keyword to indicate start of the stanzas and Resource 1: # # keyword to separate each resource. # # * Request an example of suitable input for the specified # # Resource_class to the mkrsrc command. # # * Verify that the attributes they are specifying are valid # # persistent attributes for the specified resource class and # # have "reqd_for_define" or "option_for_define" property. # # B. Initialize a session with RMC. # # C. Query the definition of the specified resource class using RMC. # # Need to get the required and optional attribute data types. # # And the data types for any required SD elements. # # D. If requested, print out the example of input to mkrsrc. # # E. Parse the Attr=value pairs from either the command line or # # input file. # # F. If requested, verify that the attributes specified are valid # # and have the appropriate properties. # # G. Define the resource or resources. # # H. Cleanup. # #--------------------------------------------------------------------# #--------------------------------------------------------------------# # Included Libraries and Extensions # #--------------------------------------------------------------------# use lib "/opt/rsct/pm"; use locale; use Getopt::Std; use autouse CT_cli_utils => qw( printIMsg printEMsg calc_cmdarg_length ); use autouse CT_cli_input_utils => qw( process_input_file process_cmdline_input escape_chars check_input_file ); use autouse CT_cli_displayext_utils => qw( rsrc_handle_to_string ); use MC_cli_rc qw(:return_codes); use MC_cli_utils qw( get_p_attr_defs_api get_arg_defs_api get_sd_defs_api qdef_resource_class_api build_cmd_arg_sd_api error_exit printCEMsg convert_input_value_api process_exit_code process_api_error remove_api_error read_from_Stdin $RMC_RSRC_PATTR_REQD_FOR_DEFINE $RMC_RSRC_PATTR_OPTION_FOR_DEFINE $RMC_CLASS_MTYPE_SUBD $RMC_CLASS_CAN_DEF_UNDEF ); #--------------------------------------------------------------------# # Global Variables # #--------------------------------------------------------------------# $TRUE = 1; $FALSE = 0; $Verbose = $FALSE; # default - verbose turned off # By default output, attribute name value pairs should be entered # via the command line. Attr=value e.g. Name=c175n06 NodeNumber=1 $Opt_File_Input = $FALSE; # default - see -f (file form) $Opt_Example = $FALSE; # default - see -e (example) $Opt_Verify = $FALSE; # default - see -v (verify) $Opt_Node_File = $FALSE; # default - see -N (node file) $Opt_Stdin = $FALSE; # default - see -N (node file) $PROGNAME = "mkrsrc"; # Program Name for messages $MSGCAT = "mccli.cat"; # msg catalogue for this cmd $CTDIR = "/opt/rsct"; # RSCT root directory $CTBINDIR = "$CTDIR/bin"; # Cluster Bin directory path $LSMSG = "$CTBINDIR/ctdspmsg"; # list / display message rtn. $ENV{'MSGMAPPATH'} = "$CTDIR/msgmaps"; # msg maps used by $LSMSG #--------------------------------------------------------------------# # Variables # #--------------------------------------------------------------------# %HoPAttrDefs = (); # Hash of Persistent Attribute # definitions @LoPAttr = (); # Ordered list of Pers Attr %HoSDAttrDefs = (); my %HoSDArgDefs = (); # Hash of Command SD Arguments # element definitions my @LoSDArgs = (); # Array of SD Cmd Arg Elements # (type, value) ordered by # element id. my @LoSDArgNames = (); my @mkrsrcapi_parms = (); # parameters to send to mkrsrcapi my $node_file_name = ""; # file name for -N my $nodenamelist_found = $FALSE; # NodeNameList attr present my @attr_list = (); # list of attr names %HoNLSData = (); my $badrc = 0; my $opt_info = 0; my $rLoCInfo = ""; $DELIMITER = "tvrtvrtvr"; # delimiter for mkrsrc-api #--------------------------------------------------------------------# # Main Code # #--------------------------------------------------------------------# # parse the command line, exit if there are errors my ($rc, $resource, $filename, $node_file_name, $r_cmdline) = &parse_cmd_line; ($rc == 0) || error_exit($rc); # get the command line buffer length $CMD_LIMIT = calc_cmdarg_length; # Get the persistent attribute definitions for this resource class # and build a hash indexed using the persistent attribute program name # that will allow easy access to each attributes id, data type # and property definitions. # The resource must already have been defined for an instance to # be defined/created. my $req_properties = $RMC_RSRC_PATTR_REQD_FOR_DEFINE | $RMC_RSRC_PATTR_OPTION_FOR_DEFINE; my @req_attributes = (); $rc = get_p_attr_defs_api($resource, 0, $req_properties, \@req_attributes, \@LoPAttr, \%HoPAttrDefs); ($rc == 0) || error_exit($rc); # Check if any of the Attributes are SDs, if they are required or # optional for define (properties) then build HoSDAttrDefs $rc = get_sd_defs($resource, \%HoPAttrDefs, \%HoSDAttrDefs); ($rc == 0) || error_exit($rc); # Get the define command SD argument definitions for this resource # class. The returned hash level 1 key will be the SD element name. $rc = get_arg_defs_api($resource, "", "define", 1, \%HoSDArgDefs, \@LoSDArgNames); ($rc == 0) || error_exit($rc); if ($Opt_Ls_Cmd_Args) { ls_cmd_args($resource, \@LoSDArgNames, \%HoSDArgDefs); } elsif ($Opt_Example) { # Print out an example of how to run mkrsrc, required and optional # attributes and arguments, but don't actually define any resources # get the class information to see if this class supports define $opt_info = $FALSE; ($rc, $rLoCInfo) = qdef_resource_class_api($resource, $opt_info); ($rc == 0) || exit($rc); # look for can_define. If ok, then proceed to examples if ($$rLoCInfo[0] =~ /$RMC_CLASS_CAN_DEF_UNDEF/) { ls_mkrsrc_example($resource, \%HoPAttrDefs, \%HoSDArgDefs); } else { # return an error that mkrsrc can't be used for this class printEMsg("EMsgmkrsrcExamplesNotValid", $resource); exit(MC_CLI_USER_ERROR); } } else { # If reading resource data from an input file get the # NLSTranslation stanza data if it exists in this file if ($Opt_File_Input) { $rc = process_nls_input($filename, \%HoPAttrDefs, \%HoSDAttrDefs, \%HoNLSData); ($rc == 0) || error_exit($rc); } # Get the attr=value pairs and any arg=value pairs from either the # command line or the input file. ($rc, $rLoRsrcAttrData, $rLoRsrcArgData) = process_input( $Opt_File_Input, $filename, \%HoPAttrDefs, \%HoSDArgDefs, $r_cmdline); ($rc == 0) || error_exit($rc); # Merge the attr=value pairs you got from the user with the # resources actual attribute definitions to build a Hash of # Persistent Attributes which contains the equivalent data as # the mc_attribute_t structure ({at_name} {at_dtype} {at_value}) # The data you need to actually define the resource - also # check that the user supplied values for all the required # attributes foreach $new_resource (@$rLoRsrcAttrData) { ($rc, $rHoPAttr) = build_resource($resource, $new_resource, \%HoPAttrDefs, \%HoSDAttrDefs, \%HoNLSData); if ($rc != 0) { if (!$badrc) { $badrc = $rc; } next; } # Process the command arguments if any were specified. if (defined($rLoRsrcArgData) && scalar keys(%HoSDArgDefs) > 0) { $new_cmd_args = shift (@$rLoRsrcArgData); ($rc, @LoSDArgs) = build_cmd_arg_sd_api($resource, $new_cmd_args, \%HoSDArgDefs); if ($rc != 0) { if (!$badrc) { $badrc = $rc; } next; } } # If running in Verify mode, skip to next resource $Opt_Verify && next; # Build parameters for mkrsrc-api command @mkrsrcapi_parms = setup_mkrsrcapi(\@mkrsrcapi_parms, $resource, $rHoPAttr, \@LoSDArgs); # determine if NodeNameList specified (used for setting scope later) @attr_list = keys %$rHoPAttr; foreach $attr_spec (@attr_list) { if ( $attr_spec =~ /^NodeNameList/ ) { $nodenamelist_found = $TRUE; } } } # end foreach $new_resource ($badrc == 0) || error_exit($badrc); # 145853. If -N and NodeNameList used together, display error. if ( $Opt_Node_File && $nodenamelist_found ) { printCEMsg("EMsgMCcliImproperUsageCombination", "-N", "NodeNameList"); exit MC_CLI_BAD_FLAG; } # if -N used or NodeNameList specified, and the scope environment variable # is not set, see if this is a subdivided or globalized managed class. # if it's subdivided, set the scope to DM_SR. if ( ($Opt_Node_File || $nodenamelist_found) && (!defined $ENV{CT_MANAGEMENT_SCOPE}) ) { # get the class information $opt_info = $FALSE; ($rc, $rLoCInfo) = qdef_resource_class_api($resource, $opt_info); ($rc == 0) || exit($rc); # look for subdivided if ($$rLoCInfo[0] =~ /$RMC_CLASS_MTYPE_SUBD/) { $ENV{CT_MANAGEMENT_SCOPE} = 4; } } # Define the resource(s). $rc = define_resource(\@mkrsrcapi_parms, $node_file_name); if ($rc != 0) { $badrc = $rc; # more important rc } } # end if not example ($badrc == 0) || error_exit($badrc); exit($rc); #--------------------------------------------------------------------# # End Main Code # #--------------------------------------------------------------------# #--------------------------------------------------------------------# # parse_cmd_line - Parse the command line for options and operands. # # Set appropriate global variables as outlined below, make sure we # # have a valid combination of arguments / options. # # # # Return: # # $rc 0 Command line parsed fine, no problem. # # SR_CLI_BAD_FLAG Command line contained a bad flag. # # $resource Resource Class Name. # # $rsrc_file Name of file that contains rsrc data # # @cmdline_args Reference to an array of # # Command Argument = value pairs. mkrsrc # # command line arguments can be either # # attr=value or arg=value pairs. # # # # Global Variables Modified: # # $Opt_Example output True (-e) provide example of cmdline # # $Opt_File_Input output True (-f) read rsrc data from file. # # $Opt_Verify output True (-v) verify cmd line or file # # input is valid format. # # $Opt_Node_File output True (-N) using a node file # # $Opt_Stdin output True (-N) using stdin # # $Verbose output True (-V) turn Verbose mode on. # # $Trace output True (-T) turn Trace mode on. # #--------------------------------------------------------------------# sub parse_cmd_line { my $resource = ""; my $rsrc_file = ""; my $node_file_name = ""; my @cmdline_args = (); my %opts = (); # Process the command line... if (!&getopts('hef:F:lN:vVT', \%opts)) { # Gather options; if errors &print_usage; # display proper usage return MC_CLI_BAD_FLAG; # return bad rc - bad flag } # Always accept the -h flag regardless of other flags or operands if (defined $opts{h}) { # -h, help request &print_usage; # print usage statement exit(0); # all done with good return! } # mkrsrc requires at a minimum the resource class name as an # operand. # Get the arguments... if ($#ARGV >= 0) { $resource = shift @ARGV; # user specified resource } else { # Print Missing Resource Class Name Operand message printCEMsg("EMsgMCcliMissingRsrcClass"); &print_usage; # display proper usage return MC_CLI_BAD_OPERAND; # return bad rc - bad operand } # Grab all of the command arguments=value pairs (Attr=value or # Arg=value), that must come right after the resource class name or # resource handle. if ($#ARGV >= 0) { if (defined $opts{f} || defined $opts{F} || defined $opts{e} || defined $opts{l}) { printCEMsg("EMsgMCcliTooManyOperands"); &print_usage; return MC_CLI_BAD_OPERAND; } else { @cmdline_args= @ARGV; } } elsif (!defined $opts{f} && !defined $opts{F} && !defined $opts{e} && !defined $opts{l}) { printCEMsg("EMsgMCcliMissingAttrAndValue"); &print_usage; return MC_CLI_BAD_OPERAND; } # See which options/flags were used... if (defined $opts{e}) { # -e, ls examples of mkrsrc $Opt_Example = $TRUE; } if (defined $opts{F}) { # -f, filename for rsrc data $opts{f} = $opts{F}; # input rsrc file name } if (defined $opts{f}) { # -f, filename for rsrc data $Opt_File_Input = $TRUE; $rsrc_file = $opts{f}; # input rsrc file name } if (defined $opts{l}) { # List any required cmd_args=data_type pairs $Opt_Ls_Cmd_Args = $TRUE; } else { $Opt_Ls_Cmd_Args = $FALSE; } if (defined $opts{N}) # -N node file { if ($opts{N} eq "-") { $Opt_Stdin= $TRUE; } else { $node_file_name= $opts{N}; $node_file_name = escape_chars($node_file_name); $rc= check_input_file($node_file_name); if ($rc) { return MC_CLI_BAD_OPERAND; } } $Opt_Node_File= $TRUE; } if (defined $opts{v}) { # -v, verify rsrc data input $Opt_Verify = $TRUE; } if (defined $opts{T}) { # -T, turns tracing on $Trace = $TRUE; } if (defined $opts{V}) { # -V, turns verbose mode on $Verbose = $TRUE; } return(0, $resource, $rsrc_file, $node_file_name, \@cmdline_args); } # end parse_cmd_line #--------------------------------------------------------------------# # print_usage : print the usage statement (syntax) to stdout. # # See this command's prologue syntax section for current usage. # #--------------------------------------------------------------------# sub print_usage { printIMsg("IMsgmkrsrcUsage5"); } # end print_usage #--------------------------------------------------------------------# # ls_cmd_args - Lists the online arguments and data types if any # # are required for this resource class. # # # # Parameters: # # $resource in Name of the resource class. # # @$rLoArgNames in Reference to a list (array) of # # argument names in element order index # # for all arguments whose definitions # # are in %$rHoSDDef. # # %$rHoSDDef in Reference to the hash of command # # SD argument defintitions. # # # # Return: # # None. # # # # Global References: # # None. # #--------------------------------------------------------------------# sub ls_cmd_args { my ($resource, $rLoArgNames, $rHoSDDef) = @_; my ($arg_name, $data_type, $properties); print "mkrsrc $resource "; foreach $arg_name (@$rLoArgNames) { $data_type = lc $$rHoSDDef{$arg_name}{sd_dtype}; $data_type =~ s/^ct_//; print "$arg_name=$data_type "; } print "\n"; return; } # end ls_cmd_args #--------------------------------------------------------------------# # get_sd_defs - function to get this resource's persistent # # attribute SD definitions and build a hash indexible via the # # attribute program name with the attributes element names and # # types stored as data. # # # # Parameters: # # $resource input name of the resource that we wish to # # create an instance of. # # %$rHoPAttrDefs input Reference to the hash of Persistent # # attribute definitions. # # %$rHoSDAttrDefs in/out Reference to the hash of persistent # # SD attribute element definitions. # # Return # # $rc return code. # # # # Global References: # # None. # #--------------------------------------------------------------------# sub get_sd_defs { my ($resource, $rHoPAttrDefs, $rHoSDAttrDefs) = @_; my $rc = 0; my @sd_attr_names = (); my $properties = ""; # first scan through the Hash of Persistent Attributes checking # to see if any are SDs or SDArrays and their properties are # required or optional for define. my @pattr_names = keys %$rHoPAttrDefs; foreach $attr_name (@pattr_names) { $dtype = $$rHoPAttrDefs{$attr_name}{at_dtype}; $properties = $$rHoPAttrDefs{$attr_name}{at_properties}; if ( (($dtype =~ /^CT_SD_PTR$/) || ($dtype =~ /^CT_SD_PTR_ARRAY$/)) && (($properties =~ /reqd_for_define/) || ($properties =~ /option_for_define/)) ) { # Add these SD attributes to array of all SD attr names push @sd_attr_names, $attr_name; } } # Need to make sure each of the SDs are defined and get various info # associated with the each persistent resource SDs elements. # If we found any persistent attributes that are SD get their # definition from RMC if (scalar(@sd_attr_names) > 0) { # Get the SD data and # Format the Query Definition Structured Data attributes # and elements into a form suitable for quick look up by # attribute name the for the element data_types. get_sd_defs_api($resource, 0, \@sd_attr_names, $rHoSDAttrDefs); } return($rc); } # end get_sd_defs #--------------------------------------------------------------------# # get_sd_element_dtypes - for the specified attribute name return # # an array of this SDs element's data types in element index # # order. # # # # Parameters: # # %$rHoSDAttrDefs input Reference to a hash of persistent # # structured data attributes. # # key = attribute name # # data = array of hashes, each hash # # represents one of this SDs elements # # $attr_name input Attribute name. # # # # Return: # # @sd_element_dtypess Returns a reference to an array of # # the SD element data types in element # # index order for this attribute. # # # # Global References: # # None. # #--------------------------------------------------------------------# sub get_sd_element_dtypes { my ($rHoSDAttrDefs, $attr_name) = @_; my @sd_element_dtypes; my %index_to_dtype = (); my $element; my $element_cnt = 0; my @elements = keys %{ $rHoSDAttrDefs->{$attr_name} }; foreach $element (@elements) { $index = $rHoSDAttrDefs->{$attr_name}{$element}->{sd_index}; $index_to_dtype{$index} = $rHoSDAttrDefs->{$attr_name}{$element}->{sd_dtype}; $element_cnt++; } for ($i = 0; $i < $element_cnt; $i++) { push @sd_element_dtypes, $index_to_dtype{$i}; } return (@sd_element_dtypes); } # end get_sd_element_dtypes #--------------------------------------------------------------------# # process_input - process the attr=value pairs that are used to # # define this resource and were input by the user on the command # # line or via an input file. # # # # Parameters: # # $Opt_File_Input input True - input should come from file. # # False - input should come from command # # line. # # $filename input Name of file if $Opt_File_Input = TRUE # # %$rHoPAttrDefs input Reference to complex hash of # # persistent attribute definitions. # # %$rHoSDArgDefs input Reference to complex hash of command # # arguments definitions for define. # # @$r_cmdline input Reference to attr=value pairs via # # command line and ARGV. # # # # Return: # # $rc return code. # # $rLoRsrcAttrData reference to list/array of resources # # and each resources attr=value pairs. # # $rLoRsrcArgData reference to list/array of resources # # and each resources arg=value pairs. # # # # Global References: # # None. # #--------------------------------------------------------------------# sub process_input { my ($Opt_File_Input, $filename, $rHoPAttrDefs, $rHoSDArgDefs, $r_cmdline) = @_; my $req_attr_stanza = "PersistentResourceAttributes"; my $req_arg_stanza = "PersistentResourceArguments"; my $rc = 0; my $rLoRsrcAttrData; my $rLoRsrcArgData; if ($Opt_File_Input) { ($rc, $rLoRsrcAttrData) = process_input_file($filename, $req_attr_stanza); if ($rc != 0) { # Print Error processing input file msg # process_input_file will write a more detailed error message printEMsg("EMsgmkrsrcInputFileError", $filename); return(MC_CLI_USER_ERROR); } # If there are defined required command arguments get those too. # but args are optional so set optional parameter 78199 if (scalar keys(%$rHoSDArgDefs) > 0) { ($rc, $rLoRsrcArgData) = process_input_file($filename, $req_arg_stanza, 1); if ($rc != 0) { # process_input_file will write a more detailed error message 78199 printEMsg("EMsgmkrsrcInputFileError", $filename); return(MC_CLI_USER_ERROR); } } } else { # Divide the command line arguments into an array of attr=value # pairs and an array of arg=value pairs. In parse_cmd_line we # verified that all args are of form name=value or ^^. my $arg_cnt = scalar @$r_cmdline; my %dup_names = (); my @cmdline_attr = (); my @cmdline_args = (); my $name; for (my $i = 0; $i < $arg_cnt; $i++) { # Preserve any ^^, which are used as resource/record # separators in CT_cli_input_utils. if ($r_cmdline->[$i] eq "^^") { push @cmdline_attrs, $r_cmdline->[$i]; if (scalar @cmdline_args > 0) { push @cmdline_args, $r_cmdline->[$i]; } %dup_names = (); } else { # Get the keyword of the keyword=value pair ($name, my @garbage) = split /=/, $r_cmdline->[$i]; # If the command line argument is not defined as an # define command argument - then treat it as an attribute. if (!defined $$rHoSDArgDefs{$name}) { push @cmdline_attrs, $r_cmdline->[$i]; } # If the command line argument name is defined as both # a persistent attribute and as an SD, the first time you # find it treat it as an attr, the second time treat it # as an arg. elsif (defined $$rHoPAttrDefs{$name} && !defined $dup_names{$name}) { push @cmdline_attrs, $r_cmdline->[$i]; $dup_names{$name} = 1; # used it as an attr } else { push @cmdline_args, $r_cmdline->[$i]; } } } # end for ($rc, $rLoRsrcAttrData) = process_cmdline_input(\@cmdline_attrs); if ($rc != 0) { # Print Command Line Error Attr=value error msg printEMsg("EMsgmkrsrcCmdLineError", "\"@$r_cmdline\""); return(MC_CLI_BAD_OPERAND); } # If there are command arguments specified get those too. if (scalar @cmdline_args > 0 && scalar keys(%$rHoSDArgDefs) > 0) { ($rc, $rLoRsrcArgData) = process_cmdline_input(\@cmdline_args); if ($rc != 0) { # Print Command Line Error Arg=value error msg printCEMsg("EMsgMCcliCmdLineArgError", "\"$r_cmdline\""); return(MC_CLI_BAD_OPERAND); } } } if ($Verbose) { my ($attribute, $value, $entry, $row_header); foreach $entry (@$rLoRsrcAttrData) { $row_header = $entry->[0]; foreach $element (@{$entry->[1]}) { $attribute = $element->[0]; $value = $element->[1]; print "$attribute = \"$value\"\n"; } } foreach $entry (@$rLoRsrcArgData) { $row_header = $entry->[0]; foreach $element (@{$entry->[1]}) { $attribute = $element->[0]; $value = $element->[1]; print "$attribute = \"$value\"\n"; } } } # If there are command arguments specified, then there must be # one set of arguments for each set of attributes if ((defined $rLoRsrcArgData && scalar(@$rLoRsrcArgData) > 0) && (scalar(@$rLoRsrcAttrData) != scalar(@$rLoRsrcArgData))) { printEMsg("EMsgmkrsrcMismatchAttrArg"); return(MC_CLI_USER_ERROR); } return ($rc, $rLoRsrcAttrData, $rLoRsrcArgData); } # end process_input #--------------------------------------------------------------------# # process_nls_input - process the NLSTranslation stanza in the # # resource data input file if it exists. Right now only # # Predefined Conditions (not customers) should be using the # # NLSTranslation Stanza. Only persistent resource attributes # # that are defined and have a data type of ct_char_ptr, # # ct_char_ptr_array, ct_sd_ptr or ct_sd_ptr_array where element # # specified must have a ct_char_ptr or ct_char_ptr_array data type # # can be translated using msgmaps and $LSMSG at this time. # # Listed below is an example of an NLSTranslation stanza: # # NLSTranslation:: # # MessageMapPath = /opt/rsct/msgmaps # # MessageSet = mkrsrc # # MessageCat = mccli.cat # # PersistentResourceAttributes = {attr1,attr2,attr3.element2} # # where attr 3 is an SD or SD Array # # attr1, attr2, attr3.element2 are char or char Array. # # # # Parameters: # # $filename input Name of file if $Opt_File_Input = TRUE # # $rHoPAttrDefs input Reference to a hash of the persistent # # attribute definitions for this rsrc. # # $rHoSDAttrDefs input Reference to a hash of the SD element # # definitions for this rsrc. # # $rHoNLSData in/out input - empty hash. # # output - hash of NLS data. # # if the NLSTranslation stanza is used. # # Hash of NLS data and values. # # MessageMapPath => # # MessageSet => # # MessageCat => # # PersistentResourceAttributes => hash # # of attribute names. # # # # Return: # # $rc return code. # # # # Global References: # # None. # #--------------------------------------------------------------------# sub process_nls_input { my ($filename, $rHoPAttrDefs, $rHoSDAttrDefs, $rHoNLSData) = @_; my $rLoNLSInputData; my $rc = 0; # MessageMapPath, MessageSet, MessageCat and # PersistentResourceAttributes are all required keywords in the # NLSTranslation stanza my $nls_stanza = "NLSTranslation"; #my %RequiredNLSKeywords = ( # "MessageMapPath" => eval(CT_CHAR_PTR), # "MessageSet" => eval(CT_CHAR_PTR), # "MessageCat" => eval(CT_CHAR_PTR), # "PersistentResourceAttributes" => eval(CT_CHAR_PTR_ARRAY) #); my %RequiredNLSKeywords = (); $RequiredNLSKeywords{"MessageMapPath"} = "CT_CHAR_PTR"; $RequiredNLSKeywords{"MessageSet"} = "CT_CHAR_PTR"; $RequiredNLSKeywords{"MessageCat"} = "CT_CHAR_PTR"; $RequiredNLSKeywords{"PersistentResourceAttributes"} = "CT_CHAR_PTR_ARRAY"; ($rc, $rLoNLSInputData) = process_input_file($filename, $nls_stanza, 1); if ($rc != 0) { # Print Error processing input file msg # process_input_file will write a more detailed error message printEMsg("EMsgmkrsrcInputFileError", $filename); return(MC_CLI_USER_ERROR); } # NLSTranslation stanza is optional in the Resource Data Input # file for mkrsrc command. If it wasn't there nothing more to # do here - just return. if (!defined($rLoNLSInputData)) { return($rc); } # Read in the required keyword = value pairs from the NLSTranslation # Stanza building the Hash of NLS Data where the key to the hash # is the required keyword and value is the data for that keyword $entry = $rLoNLSInputData->[0]; foreach $new_keyword (@{$entry->[1]}) { $keyword = $new_keyword->[0]; if (!defined($RequiredNLSKeywords{$keyword})) { printEMsg("EMsgmkrsrcInvalidNLSKeyword", $keyword, $filename); $rc = MC_CLI_USER_ERROR; next; } if (!defined($rHoNLSData->{$keyword})) { $rHoNLSData->{$keyword} = $new_keyword->[1]; } } # Make sure that all of the required keywords were supplied in # the NLSTranslation stanza. @required_keywords = keys %RequiredNLSKeywords; foreach $required_keyword (@required_keywords) { if (!defined($rHoNLSData->{$required_keyword})) { printEMsg("EMsgmkrsrcMissingNLSKeyword", $required_keyword, $filename); $rc = MC_CLI_USER_ERROR; } } # PersistentResourceAttributes keyword should contain an array # of persistent attributes in the format {attr1, attr2, .., attrn} # Convert this to a perl hash so later on we can quickly see # if the persistent attributes we are processing in build_resource # in an attribute that needs to be translated. if ($rc == 0) { my ($rLoAttr, $attr); ($rc, $rLoAttr) = convert_input_value_api( $RequiredNLSKeywords{PersistentResourceAttributes}, $rHoNLSData->{PersistentResourceAttributes}); if ($rc == 0) { my %temp_hash = (); foreach $attr (@$rLoAttr) { # Make sure the persistent attribute is a valid defined # attribute name and it has a a valid data type # ct_char_ptr and ct_char_ptr_array are valid if (defined($rHoPAttrDefs->{$attr}) && ( $rHoPAttrDefs->{$attr}->{at_dtype} =~ /^CT_CHAR_PTR$/ || $rHoPAttrDefs->{$attr}->{at_dtype} =~ /^CT_CHAR_PTR_ARRAY$/ )) { $temp_hash{$attr} = ''; } else { ($attr, $element) = split /\./, $attr, 2; # ct_sd_ptr and ct_sd_ptr_array are valid if the # element specified is ct_char_ptr or ct_char_ptr_array if ( (defined($rHoPAttrDefs->{$attr}) && ( $rHoPAttrDefs->{$attr}->{at_dtype} =~ /^CT_SD_PTR$/ || $rHoPAttrDefs->{$attr}->{at_dtype} =~ /^CT_SD_PTR_ARRAY$/ )) && (defined($rHoSDAttrDefs->{$attr}->{$element}) && ( $rHoSDAttrDefs->{$attr}->{$element}->{sd_dtype} =~ /^CT_CHAR_PTR$/ || $rHoSDAttrDefs->{$attr}->{$element}->{sd_dtype} =~ /^CT_CHAR_PTR_ARRAY$/ )) ) { if (defined $temp_hash{$attr}) { push @{$temp_hash{$attr}}, $element; } else { $temp_hash{$attr} = [ ]; push @{$temp_hash{$attr}}, $element; } } else { printEMsg("EMsgmkrsrcNLSAttrNotValid", $attr, $filename); $rc = MC_CLI_USER_ERROR; } } } $rHoNLSData->{PersistentResourceAttributes} = { %temp_hash }; } } return ($rc); } # end process_nls_input #--------------------------------------------------------------------# # build_resource - function to build up the hash of persistent attr # # to be used in defining the resource. Merging the {at_name}, # # {at_value}, {at_dtype} all into one structure and validating # # the input data as its processed. # # # # Parameters: # # $resource input Resource name. # # $rRsrcData input Reference to array of attr,value pairs.# # $rHoPAttrDefs input Reference to hash of all the required # # and optional attribute definitions # # for this resource. # # $rHoSDAttrDefs input Reference to hash of all the required # # and optional SD attribute definitions # # for this resource. # # $rHoNLSData input Reference to hash of NLS Data. # # For example: # # MessageMapPath => # # MessageSet => mkrsrc # # MessageCat => mccli.cat # # PersistentResourceAttributes = %hash # # of attribute names that need to be # # translated. # # # # Return: # # $rc return code. # # $rHoPAttr Reference complex hash of persistent # # attributes including their values. # # # # Global References: # # None. # #--------------------------------------------------------------------# sub build_resource { my ($resource, $rRsrcData, $rHoPAttrDefs, $rHoSDAttrDefs, $rHoNLSData) = @_; my %HoPAttr = (); my @required_attributes = (); my ($new_attr, $dtype); my $badrc = 0; my $resource_def; # Process all of the attr value pairs for this resource. Attr # value pairs should come before Arg value pairs on the command line. foreach $new_attr (@{$rRsrcData->[1]}) { $attr_name = $new_attr->[0]; # first check to make sure this is either a valid attribute name # or a valid command argument name. if (!defined($$rHoPAttrDefs{$attr_name})) { if ($Opt_File_Input) { $resource_def= $rRsrcData->[0]; $resource_def=~ s/^\s+//; $resource_def=~ s/\s+$//; printEMsg("EMsgmkrsrcAttrNotDefForSet3", $attr_name, $resource, $resource_def); } else { printEMsg("EMsgmkrsrcAttrNotDefForSet2", $attr_name, $resource); } $badrc = MC_CLI_USER_ERROR; next; # continue validating rest of input } # next check to make sure the value is of the right type # SDs require some special handling... $dtype = $$rHoPAttrDefs{$attr_name}{at_dtype}; if ( ($dtype =~ /^CT_SD_PTR$/) || ($dtype =~ /^CT_SD_PTR_ARRAY$/) ) { @r_sd_element_dtypes = get_sd_element_dtypes($rHoSDAttrDefs, $attr_name); ($rc, $attr_value) = convert_input_value_api($dtype, $new_attr->[1], \@r_sd_element_dtypes); } else { ($rc, $attr_value) = convert_input_value_api($dtype, $new_attr->[1]); } if ($rc != 0) { printCEMsg("EMsgMCcliBadAttrValue", $attr_name, $new_attr->[1]); if ($badrc == 0) {$badrc = $rc; } next; } %elements = (); $elements{at_name} = $attr_name; $elements{at_dtype} = $$rHoPAttrDefs{$attr_name}{at_dtype}; $elements{at_value} = $attr_value; # for 2 non-array values specified in a row, save the last value 131200 131854 if (($#$attr_value >0) && ($dtype !~ /ARRAY/) && ($dtype !~ /SD/)) { $elements{at_value} = $$attr_value[$#$attr_value]; } # save original SD value if ( ($dtype =~ /^CT_SD_PTR$/) || ($dtype =~ /^CT_SD_PTR_ARRAY$/) ) { $elements{at_SD_value} = $new_attr->[1]; } $HoPAttr{$attr_name} = { %elements }; } # Build a list of the attributes that are required to define # this resource my @p_attr_names = keys %$rHoPAttrDefs; foreach $attr_name (@p_attr_names) { $properties = $$rHoPAttrDefs{$attr_name}{at_properties}; if ($properties =~ /reqd_for_define/ ) { push @required_attributes, $attr_name; } } # Make sure that all of the required attributes are being # defined. foreach $attr_name (@required_attributes) { if (!defined($HoPAttr{$attr_name})) { printEMsg("EMsgmkrsrcMissingReqAttr", $attr_name, $resource); $badrc = MC_CLI_USER_ERROR; } } # Translate any of the Persistent Attributes that were listed in # the NLSTranslation Stanza PersistentResourceAttributes keyword if (defined $rHoNLSData->{PersistentResourceAttributes}) { $rc = translate_attr_values(\%HoPAttr, $rHoSDAttrDefs, $rHoNLSData); } return($badrc, \%HoPAttr); } # end build_resource #--------------------------------------------------------------------# # translate_attr_values - function to translate persistent attribute # # values for persistent attributes that were listed in the # # NLSTranslationStanza PersistenResourceAttributes keyword. # # persistent attributes that have the following data types may be # # translated: ct_char_ptr, ct_char_ptr_array, ct_sd_ptr and # # ct_sd_ptr_array when the elements being translated are either # # ct_char_ptr or ct_char_ptr_array. # # # # Parameters: # # $rHoPAttr input Reference to hash of persistent # # attributes that we want to define. # # $rHoSDAttrDefs input Reference to hash of all the required # # and optional SD attribute definitions # # for this resource. # # $rHoNLSData input Reference to hash of NLS Data. # # For example: # # MessageMapPath => # # MessageSet => mkrsrc # # MessageCat => mccli.cat # # PersistentResourceAttributes = %hash # # of attribute names that need to be # # translated. # # # # Return: # # $rc return code. # # # # Global References: # # None. # #--------------------------------------------------------------------# sub translate_attr_values { my ($rHoPAttr, $rHoSDAttrDefs, $rHoNLSData) = @_; my $rc = 0; my $msg_mnemonic; # msg mnemonic to be translated # mnemonic & default msg are in # message map file my @attr_to_translate = keys %{ $rHoNLSData->{PersistentResourceAttributes} }; (scalar(@attr_to_translate) == 0) && return($rc); # temporarily change ENV MSGMAPPATH for LSMSG if need to my $restore_msgmappath_env = $ENV{MSGMAPPATH}; if ($ENV{MSGMAPPATH} ne $rHoNLSData->{MessageMapPath}) { $ENV{MSGMAPPATH} = $rHoNLSData->{MessageMapPath}; } foreach $attr_name (@attr_to_translate) { if (!defined($rHoPAttr->{$attr_name})) { next; } if ($rHoPAttr->{$attr_name}->{at_dtype} =~ /^CT_CHAR_PTR$/ ) { $msg_mnemonic = $rHoPAttr->{$attr_name}->{at_value}; $rHoPAttr->{$attr_name}->{at_value} = `$LSMSG $rHoNLSData->{MessageSet} $rHoNLSData->{MessageCat} $msg_mnemonic`; $rc = $?; if ($rc != 0) { $rc = translation_error($attr_name, $msg_mnemonic, $restore_msgmappath_env, $rHoNLSData); } } elsif ($rHoPAttr->{$attr_name}->{at_dtype} =~ /^CT_CHAR_PTR_ARRAY$/ ) { my $i = 0; my $element; foreach $element (@{$rHoPAttr->{$attr_name}->{at_value}}) { $msg_mnemonic = ($rHoPAttr->{$attr_name}->{at_value}[$i]); $rHoPAttr->{$attr_name}->{at_value}[$i] = `$LSMSG $rHoNLSData->{MessageSet} $rHoNLSData->{MessageCat} $msg_mnemonic`; $rc = $?; if ($rc != 0) { $rc = translation_error($attr_name, $msg_mnemonic, $restore_msgmappath_env, $rHoNLSData); } $i++; } } elsif ($rHoPAttr->{$attr_name}->{at_dtype} =~ /^CT_SD_PTR$/ ) { my $sd_element; foreach $sd_element (@{$rHoNLSData->{PersistentResourceAttributes}->{$attr_name}}) { my $sd_element_index = $rHoSDAttrDefs->{$attr_name}->{$sd_element}{sd_index}; $msg_mnemonic = $rHoPAttr->{$attr_name}{at_value}->[$sd_element_index]->{value}; $rHoPAttr->{$attr_name}{at_value}->[$sd_element_index]->{value} = `$LSMSG $rHoNLSData->{MessageSet} $rHoNLSData->{MessageCat} $msg_mnemonic`; $rc = $?; if ($rc != 0) { $rc = translation_error($attr_name, $msg_mnemonic, $restore_msgmappath_env, $rHoNLSData); } } } elsif ($rHoPAttr->{$attr_name}->{at_dtype} =~ /^CT_SD_PTR_ARRAY$/ ) { my $sd_element; foreach $sd_element (@{$rHoNLSData->{PersistentResourceAttributes}->{$attr_name}}) { my $sd_element_index = $rHoSDAttrDefs->{$attr_name}->{$sd_element}{sd_index}; my $num_array_elements = scalar(@{$rHoPAttr->{$attr_name}->{at_value}}); for (my $i = 0; $i < $num_array_elements; $i++) { $msg_mnemonic = $rHoPAttr->{$attr_name}{at_value}->[$i]->[$sd_element_index]->{value}; $rHoPAttr->{$attr_name}{at_value}->[$i]->[$sd_element_index]->{value} = `$LSMSG $rHoNLSData->{MessageSet} $rHoNLSData->{MessageCat} $msg_mnemonic`; $rc = $?; if ($rc != 0) { $rc = translation_error($attr_name, $msg_mnemonic, $restore_msgmappath_env, $rHoNLSData); } # change it in original value too $rHoPAttr->{$attr_name}{at_SD_value} =~ s/$msg_mnemonic/$rHoPAttr->{$attr_name}{at_value}->[$i]->[$sd_element_index]->{value}/; } } } else { # This should never happen - but print warning just in case. # NLS Translation only supported internal to IBM. print STDERR "mkrsrc - translation of data type: ", $rHoPAttr->{$attr_name}->{at_dtype}, " is not supported.\n"; } } # end foreach # restore the original messagemappath for normal error messages if ($ENV{MSGMAPPATH} ne $rHoNLSData->{MessageMapPath}) { $ENV{MSGMAPPATH} = $restore_msgmappath_env; } return $rc; } # end translate_attr_value #--------------------------------------------------------------------# # translation_error - convenience function to write the Translation # # Eror Message. Easier to have a function to do this since may # # to alter the MSGMAPPATH environment variable before writing the # # message and then resetting the environment variable. # # # # Parameters: # # $attr_name input Name of the persistent attribute whose # # value we are having problems # # translating. # # $msg_mnemonic input The message mnemonic that should be # # found in the specific message map. # # $restore_msgmappath input The message map path where mkrsrc # # msgmap file is located. # # %$rHoNLSData input Reference to complex hash associated # # with the data in the # # NLSTranslation stanza. # # # # Return: # # MC_CLI_USER_ERROR This function only gets called when # # there is translation problem. # # # # Global References: # # None. # #--------------------------------------------------------------------# sub translation_error { my ($attr_name, $msg_mnemonic, $restore_msgmappath, $rHoNLSData) = @_; if ($ENV{MSGMAPPATH} ne $restore_msgmappath) { $ENV{MSGMAPPATH} = $restore_msgmappath; } my ($msgcatprefix, $dummy) = split /\./, $rHoNLSData->{MessageCat}; my $msgmap = $rHoNLSData->{MessageMapPath} . "/" . $msgcatprefix . "." . $rHoNLSData->{MessageSet} . ".map"; printEMsg("EMsgmkrsrcTranslationError", $attr_name, "$msg_mnemonic", $msgmap, $rHoNLSData->{MessageCat}); if ($ENV{MSGMAPPATH} ne $restore_msgmappath) { $ENV{MSGMAPPATH} = $rHoNLSData->{MessageMapPath}; } return(MC_CLI_USER_ERROR); } # end translation_error #--------------------------------------------------------------------# # define_resource - function to call the mkrsrc-api command to # # create one or more resources. # # # # Parameters: # # @$parms input Reference to parameter strings to send # # to mkrsrc-api. # # $node_file input Name of the node list file, if used. # # # # Return: # # $rc return code. # # # # Global References: # # Trace input Trace call & return of extension. # # Verbose input Print newly defined rsrc handle. # #--------------------------------------------------------------------# sub define_resource { my ($parms, $node_file) = @_; my $rc = 0; my $i = 0; my @mk_out = (); my $parmlen = 0; # check if -f or -F was used for file input # -F means continue on error # get the total length for the command to see if the command buffer will be exceeded for ($i=0; $i<=$#$parms;$i++){ $parmlen += length($$parms[$i]); } # add in various other things to the length $parmlen += length($CTBINDIR) + length($DELIMITER)*2 + $#$parms + 50; # add in the length of the file name if ($Opt_Stdin) { $node_file = read_from_Stdin(); } if ($Opt_Node_File) { $parmlen += length($node_file); } # decide how to call mkrsrc-api based on the command length if ($parmlen > $CMD_LIMIT) { # use mkrsrc-api with file option $rc = mkrsrcapi_file($parms, $node_file); } else { # use mkrsrc-api using the command buffer $rc = mkrsrcapi_cmdline($parms, $node_file); } return $rc; } # end define_resource #--------------------------------------------------------------------# # setup_mkrsrcapi - function to add a parameter specification to be # # used later for mkrsrc-api. # # # # Parameters: # # $mkrsrcapi_parm in/out Name of the string variable that has # # any previous resource definition. # # $rsrc_class input Name of the resource class to which we # # want to define a new resource. # # %$rHoAttr input Reference to complex hash of attribute # # names and value pairs. # # @$rLoSDArgs input Reference to a list of of SD Command # # Arguments (if any). # # # # Return: # # $rc return code. # # # # Global References: # # Trace input Trace call & return of extension. # # Verbose input Print newly defined rsrc handle. # #--------------------------------------------------------------------# sub setup_mkrsrcapi { my ($mkrsrcapi_parm, $rsrc_class, $rHoAttr, $rLoSDArgs) = @_; my $newparms= ""; my $tmpparms= ""; my $i=0; my $j=0; my $k=0; my $m=0; my $comma = ""; my $incomma = ""; #$Verbose && printIMsg("IMsgmkrsrcDefiningRsrc", $rsrc_class); #$Trace && print STDERR "Calling mkrsrc-api\n"; # format being created: # ClassName[::::::]...] # start new parameter list with resource class $newparms = $rsrc_class; # add regular attributes and values my @attr_list = keys %$rHoAttr; foreach $attr (@attr_list) { if ( $$rHoAttr{$attr}{at_dtype} =~ /^CT_SD_PTR$/ ) { #$newparms .= $DELIMITER . $attr . $DELIMITER . $$rHoAttr{$attr}{at_SD_value}; $tmpparms = "["; $comma = ""; # build SD from converted elements in hashes for ($j=0; $j <= $#{$$rHoAttr{$attr}{at_value}}; $j++) { # see if the element is an array or not if (${${$$rHoAttr{$attr}{at_value}}[$j]}{type} =~ /ARRAY/) { # process array elemets $tmpparms .= $comma . "{"; $incomma = ""; for ($k=0; $k <= $#{${${$$rHoAttr{$attr}{at_value}}[$j]}{value}}; $k++) { $tmpparms .= $incomma . ${${${$$rHoAttr{$attr}{at_value}}[$j]}{value}}[$k]; $incomma = ","; } $tmpparms .= "}"; } # not an array, get elements else { $tmpparms .= $comma . ${${$$rHoAttr{$attr}{at_value}}[$j]}{value}; $comma = ","; } } $tmpparms .= "]"; $newparms .= $DELIMITER . $attr . $DELIMITER . $tmpparms; } elsif ( $$rHoAttr{$attr}{at_dtype} =~ /^CT_SD_PTR_ARRAY$/ ) { #$newparms .= $DELIMITER . $attr . $DELIMITER . $$rHoAttr{$attr}{at_SD_value}; $tmpparms = "{"; # build SD array from converted elements in arrays of hashes # first the array of hash arrays (1 for each SD in the array) for ($j=0; $j <= $#{$$rHoAttr{$attr}{at_value}}; $j++) { $tmpparms .= "["; $comma = ""; # get the values of each SD for ($k=0; $k <= $#{${$$rHoAttr{$attr}{at_value}}[$j]}; $k++) { # see if it's an array if (${${$$rHoAttr{$attr}{at_value}}[$j][$k]}{type} =~ /ARRAY/) { # process array elemets $tmpparms .= $comma . "{"; $incomma = ""; for ($m=0; $m <= $#{${${$$rHoAttr{$attr}{at_value}}[$j][$k]}{value}}; $m++) { $tmpparms .= $incomma . ${${${$$rHoAttr{$attr}{at_value}}[$j][$k]}{value}}[$m]; $incomma = ","; } # finish off the array $tmpparms .= "}"; } else { # not an array, get the value $tmpparms .= $comma . ${${$$rHoAttr{$attr}{at_value}}[$j][$k]}{value}; $comma = ","; } } # mark the end of an SD array element if ($j == $#{$$rHoAttr{$attr}{at_value}}) {$tmpparms .= "]";} else {$tmpparms .= "],";} } # mark the end of the SD array $tmpparms .= "}"; # assign the final value $newparms .= $DELIMITER . $attr . $DELIMITER . $tmpparms; } elsif ( $$rHoAttr{$attr}{at_dtype} =~ /ARRAY/ ) { $comma = ""; $tmpparms = "{"; $i = scalar(@{$rHoAttr->{$attr}->{at_value}}); for ($j=0; $j<$i; $j++){ $tmpparms .= $comma . $rHoAttr->{$attr}->{at_value}[$j]; $comma = ","; } $tmpparms .= "}"; $comma = ""; $newparms .= $DELIMITER . $attr . $DELIMITER . $tmpparms; } elsif ( $$rHoAttr{$attr}{at_dtype} =~ /^CT_CHAR_PTR$/ ) { # drop the outside double quotes, if any if ( ( $$rHoAttr{$attr}{at_value} =~ /^\"/ ) && ( $$rHoAttr{$attr}{at_value} =~ /\"$/ ) ) { $$rHoAttr{$attr}{at_value} =~ s/^\"//; $$rHoAttr{$attr}{at_value} =~ s/\"$//; } $newparms .= $DELIMITER . $attr . $DELIMITER . $$rHoAttr{$attr}{at_value}; } else { $newparms .= $DELIMITER . $attr . $DELIMITER . $$rHoAttr{$attr}{at_value}; } } # check for any null attribute values # should be ok but mkrsrc-api doesn't like it now $newparms =~ s/${DELIMITER}${DELIMITER}/${DELIMITER}''${DELIMITER}/g; $newparms =~ s/${DELIMITER}$/${DELIMITER}''/; $comma = ""; # process any command options (arguments) if ($#{$rLoSDArgs} >=0) { # use double delimiters to show args next $newparms .= $DELIMITER; for (my $j=0; $j<=$#$rLoSDArgs; $j++) { if ( ${$$rLoSDArgs[$j]}{type} =~ /ARRAY/ ) { $tmpparms = "{"; $i = scalar (@{$$rLoSDArgs[$j]->{value}}); for (my $k=0; $k<$i; $k++){ $tmpparms .= $comma . ${$$rLoSDArgs[$j]->{value}}[$k]; $comma = ","; } $tmpparms .= "}"; $comma = ""; $newparms .= $DELIMITER . $$rLoSDArgs[$j]->{name} . $DELIMITER . $tmpparms; } else { $newparms .= $DELIMITER . $$rLoSDArgs[$j]->{name} . $DELIMITER . $$rLoSDArgs[$j]->{value}; } } } # going to put double quotes around the whole thing so # escape any inner quotes ##$newparms =~ s/\\/\\\\/g; ##$newparms =~ s/\"/\\\"/g; #$newparms = escape_chars($newparms); #$newparms = "\"" . $newparms . "\""; # append the new parameters to the existing one $i = $#$mkrsrcapi_parm; #if ( ($i<0) || (length($$mkrsrcapi_parm[$i]) > $CMD_LIMIT) ) { # $$mkrsrcapi_parm[$i+1] .= " " . $newparms; #} #else { # $$mkrsrcapi_parm[$i] .= " " . $newparms; #} # create a new entry for this resource definition $$mkrsrcapi_parm[$i+1] .= $newparms; return (@$mkrsrcapi_parm); } # end setup_mkrsrcapi #--------------------------------------------------------------------# # mkrsrcapi_file - function to call the mkrsrc-api command after # # building an input file conataining the resource definition. # # This is called when the command line buffer is not big enough to # # handle all of the command input to be processed. # # # # Parameters: # # $@parms input Reference to parameter strings to send # # to mkrsrc-api. # # $node_file input Node list file, if used. # # # # Return: # # $rc return code. # # # # Global References: # # Trace input Trace calls & returns. # # Verbose input Print some extra details. # #--------------------------------------------------------------------# sub mkrsrcapi_file { my ($parms, $node_file) = @_; my $rc = 0; my $i = 0; my @mk_out = (); my @cmd_out = (); my $mytmpdir = ""; my $cttmpdir_exit = 0; my $mk_file = ""; my $mk_time = 0; my $mk_pid = $$; my $file_error = ""; my $node_file_opt = ""; # create the file name to be used $mk_time = time(); $mytmpdir = `/opt/rsct/bin/cttmpdir`; chomp $mytmpdir; $cttmpdir_exit = $?; if ($cttmpdir_exit != 0) { $mytmpdir = "/tmp"; } $mk_file = "$mytmpdir/mkrsrc_file_input.${mk_pid}.${mk_time}"; # add a new line character to each line to go into the file for ($i=0; $i<=$#$parms; $i++) { $$parms[$i] .= "\n"; } if ($main::Trace) { print STDERR "Creating $mk_file to store resource information.\n";} if (open (MKFILE, ">$mk_file") ) { if (!(print MKFILE @$parms)) { # get the error $file_error = $!; # print error message and exit &printEMsg("EMsgmkrsrcTempFileError",$file_error); # try to delete the temp file in case it was created @cmd_out = `/bin/rm $mk_file 2>&1`; exit(MC_CLI_USER_ERROR); } if (!(close(MKFILE))) { # get the error $file_error = $!; # print error message and exit &printEMsg("EMsgmkrsrcTempFileError",$file_error); # try to delete the temp file in case it was created @cmd_out = `/bin/rm $mk_file 2>&1`; exit(MC_CLI_USER_ERROR); } } # process error from open else { # get the error $file_error = $!; # print error message and exit &printEMsg("EMsgmkrsrcTempFileError",$file_error); # try to delete the temp file in case it was created @cmd_out = `/bin/rm $mk_file 2>&1`; exit(MC_CLI_USER_ERROR); } if ($main::Trace) { print STDERR "Calling mkrsrc-api:\n"; print STDERR "mkrsrc-api parameters:"; print STDERR "@$parms\n"; } # see if node file used if ($Opt_Node_File) { $node_file_opt = " -N ${node_file} "; } # call mkrsrc-api. -F causes the input file to be deleted @mk_out = `$CTBINDIR/mkrsrc-api $node_file_opt -I $DELIMITER -D $DELIMITER -F $mk_file 2>&1`; # capture the return code from mkrsrc-api $rc = $?; $rc = process_exit_code($rc); if ($main::Trace) { print STDERR "mkrsrc-api results:\n"; print STDERR "mkrsrc-api returned $rc \n"; print STDERR "@mk_out"; } # show any errors if there was a bad rc if ($rc != 0) { process_api_error($DELIMITER,$rc,@mk_out); } # delete the temp file, just in case @cmd_out = `/bin/rm $mk_file 2>&1`; # delete the temp Stdin file if used if ($Opt_Stdin) { unlink($node_file); } return $rc; } # end mkrsrcapi_file #--------------------------------------------------------------------# # mkrsrcapi_cmdline - function to call the mkrsrc-api command after # # building a command string to pass to the command. # # # # Parameters: # # $@parms input Reference to parameter strings to send # # to mkrsrc-api. # # $node_file input Node list file name, if used. # # # # Return: # # $rc return code. # # # # Global References: # # Trace input Trace calls & returns. # # Verbose input Print some extra details. # #--------------------------------------------------------------------# sub mkrsrcapi_cmdline { my ($parms, $node_file) = @_; my $parms_cmd = ""; my $args = ""; my $rc = 0; my @mk_out = (); my $node_file_opt = ""; # create the command string foreach $args (@$parms) { # need quotes around the whole thing so first escape an inner ones $args = escape_chars($args); $args = "\"" . $args . "\""; $parms_cmd .= " " . $args; } # see if node file used if ($Opt_Node_File) { $node_file_opt = " -N ${node_file} "; } if ($main::Trace) { print STDERR "Calling mkrsrc-api:\n"; print STDERR "mkrsrc-api parameters:"; print STDERR "$parms_cmd\n"; } @mk_out = `$CTBINDIR/mkrsrc-api $node_file_opt -I $DELIMITER -D $DELIMITER $parms_cmd 2>&1`; # capture the return code from mkrsrc-api $rc = $?; $rc = process_exit_code($rc); if ($main::Trace) { print STDERR "mkrsrc-api results:\n"; print STDERR "mkrsrc-api returned $rc \n"; print STDERR "@mk_out"; } # show any errors if there was a bad rc if ($rc != 0) { process_api_error($DELIMITER,$rc,@mk_out); } # delete the temp Stdin file if used if ($Opt_Stdin) { unlink($node_file); } return $rc; } # end mkrsrcapi_cmdline #--------------------------------------------------------------------# # ls_mkrsrc_example - Lists two examples of valid cmd line input # # for mkrsrc command for the specified resource. Required # # attributes are listed first, required and optional attributes # # are listed next. # # # # Parameters: # # $resource in Name of the resource class. # # %$rHoPAttrDefs in Reference to the hash of persistent # # attribute definitions. # # %$rHoSDArgDefs in Reference to the hash of argument # # definitions for define resource. # # # # Return: # # None. # # # # Global References: # # None. # #--------------------------------------------------------------------# sub ls_mkrsrc_example { my ($resource, $rHoPAttrDefs, $rHoSDArgDefs) = @_; my ($attribute, $argument, $data_type, $properties); # first list the attributes that are required for define printIMsg("IMsgmkrsrcExReqdAttrs"); print "mkrsrc $resource "; foreach $attribute (keys %$rHoPAttrDefs) { $properties = $$rHoPAttrDefs{$attribute}{at_properties}; if ( $properties =~ /reqd_for_define/ ) { $data_type = lc $$rHoPAttrDefs{$attribute}{at_dtype}; $data_type =~ s/^ct_//; print "$attribute=$data_type "; } } print "\n\n"; # next list required and optional attributes and arguments printIMsg("IMsgmkrsrcExReqdOptAttrsCmdArgs"); print "mkrsrc $resource "; # required for define... foreach $attribute (keys %$rHoPAttrDefs) { $properties = $$rHoPAttrDefs{$attribute}{at_properties}; if ( $properties =~ /reqd_for_define/ ) { $data_type = lc $$rHoPAttrDefs{$attribute}{at_dtype}; $data_type =~ s/^ct_//; print "$attribute=$data_type "; } } # ... and optional for define foreach $attribute (keys %$rHoPAttrDefs) { $properties = $$rHoPAttrDefs{$attribute}{at_properties}; if ( $properties =~ /option_for_define/ ) { $data_type = lc $$rHoPAttrDefs{$attribute}{at_dtype}; $data_type =~ s/^ct_//; print "$attribute=$data_type "; } } # ... and the optional argument=value pairs foreach $argument (keys %$rHoSDArgDefs) { $data_type = lc $$rHoSDArgDefs{$argument}{sd_dtype}; $data_type =~ s/^ct_//; print "$argument=$data_type "; } print "\n"; } # end ls_mkrsrc_example #--------------------------------------------------------------------# # error_check - checks the return code from the RMC function and # # the error response return code. If an error is detected # # appropriate error messages will be displayed. # # # # Parameters: # # $rmc_function in Name of the rmc function that was # # called and whose error code we are # # checking. # # $rmc_class in The rmc class name. # # $response in RMC response. # # $rmc_rc in The rmc function return code. # # $error in The error response. # # # # Return: # # $rc return code. # # # # Global References: # # None. # #--------------------------------------------------------------------# sub error_check { my ($rmc_function, $rmc_class, $response, $rmc_rc, $error) = @_; my $rc = 0; my $err_rc = $error->errnum(); if ($rmc_rc != 0) { printEMsg("EMsgmkrsrcMkRsrcError", $rmc_class); my $rmc_rc_hex = sprintf "0x%8.8lx", $rmc_rc; printCEMsg("EMsgMCcliMCFunctionFailure", $rmc_function, $rmc_rc, $rmc_rc_hex); $rc = MC_CLI_RMC_ERROR; return $rc; } # Check the errnum in each of the RMC responses for (my $r = 0; $r < $response->array_count; $r++) { # get the error that goes with the specific response if ($r > 0) { $response->error($error, $r); $err_rc = $error->errnum(); } if ($err_rc != 0) { if ($err_rc == RMC_ECLASSNOTDEFINED) { printCEMsg("EMsgMCcliClassNotDef", $rmc_class); $rc = MC_CLI_USER_ERROR; } elsif ($err_rc == RMC_EACCESS) { print STDERR $error->error_msg; $rc = MC_CLI_USER_ERROR; } else { printEMsg("EMsgmkrsrcMkRsrcError", $rmc_class); my $err_rc_hex = sprintf "0x%8.8lx", $err_rc; printCEMsg("EMsgMCcliMCFunctionFailure", $rmc_function, $err_rc, $err_rc_hex); print STDERR $error->error_msg; $rc = MC_CLI_RMC_ERROR; } } # end if } # end for return $rc; } # end error_check