<reponame>hyche/openbmc-test-automation
#!/usr/bin/env python

import sys
import __builtin__
import subprocess
import os
import argparse

# python puts the program's directory path in sys.path[0].  In other words,
# the user ordinarily has no way to override python's choice of a module from
# its own dir.  We want to have that ability in our environment.  However, we
# don't want to break any established python modules that depend on this
# behavior.  So, we'll save the value from sys.path[0], delete it, import our
# modules and then restore sys.path to its original value.

save_path_0 = sys.path[0]
del sys.path[0]

from gen_print import *
from gen_valid import *
from gen_arg import *
from gen_plug_in import *
from gen_cmd import *

# Restore sys.path[0].
sys.path.insert(0, save_path_0)
# I use this variable in calls to print_var.
hex = 1

# Create parser object to process command line parameters and args.

# Create parser object.
parser = argparse.ArgumentParser(
    usage='%(prog)s [OPTIONS]',
    description="%(prog)s will process the plug-in packages passed to it."
                + "  A plug-in package is essentially a directory containing"
                + " one or more call point programs.  Each of these call point"
                + " programs must have a prefix of \"cp_\".  When calling"
                + " %(prog)s, a user must provide a call_point parameter"
                + " (described below).  For each plug-in package passed,"
                + " %(prog)s will check for the presence of the specified call"
                + " point program in the plug-in directory.  If it is found,"
                + " %(prog)s will run it.  It is the responsibility of the"
                + " caller to set any environment variables needed by the call"
                + " point programs.\n\nAfter each call point program"
                + " has been run, %(prog)s will print the following values in"
                + " the following formats for use by the calling program:\n"
                + "  failed_plug_in_name:               <failed plug-in value,"
                + " if any>\n  shell_rc:                          "
                + "<shell return code value of last call point program - this"
                + " will be printed in hexadecimal format.  Also, be aware"
                + " that if a call point program returns a value it will be"
                + " shifted left 2 bytes (e.g. rc of 2 will be printed as"
                + " 0x00000200).  That is because the rightmost byte is"
                + " reserved for errors in calling the call point program"
                + " rather than errors generated by the call point program.>",
    formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    prefix_chars='-+')

# Create arguments.
parser.add_argument(
    'plug_in_dir_paths',
    nargs='?',
    default="",
    help=plug_in_dir_paths_help_text + default_string)

parser.add_argument(
    '--call_point',
    default="setup",
    required=True,
    help='The call point program name.  This value must not include the'
         + ' "cp_" prefix.  For each plug-in package passed to this program,'
         + ' the specified call_point program will be called if it exists in'
         + ' the plug-in directory.' + default_string)

parser.add_argument(
    '--allow_shell_rc',
    default="0x00000000",
    help='The user may supply a value other than zero to indicate an'
         + ' acceptable non-zero return code.  For example, if this value'
         + ' equals 0x00000200, it means that for each plug-in call point that'
         + ' runs, a 0x00000200 will not be counted as a failure.  See note'
         + ' above regarding left-shifting of return codes.' + default_string)

parser.add_argument(
    '--stop_on_plug_in_failure',
    default=1,
    type=int,
    choices=[1, 0],
    help='If this parameter is set to 1, this program will stop and return '
         + 'non-zero if the call point program from any plug-in directory '
         + 'fails.  Conversely, if it is set to false, this program will run '
         + 'the call point program from each and every plug-in directory '
         + 'regardless of their return values.  Typical example cases where '
         + 'you\'d want to run all plug-in call points regardless of success '
         + 'or failure would be "cleanup" or "ffdc" call points.')

parser.add_argument(
    '--stop_on_non_zero_rc',
    default=0,
    type=int,
    choices=[1, 0],
    help='If this parm is set to 1 and a plug-in call point program returns '
         + 'a valid non-zero return code (see "allow_shell_rc" parm above),'
         + ' this program will stop processing and return 0 (success).  Since'
         + ' this constitutes a successful exit, this would normally be used'
         + ' where the caller wishes to stop processing if one of the plug-in'
         + ' directory call point programs returns a special value indicating'
         + ' that some special case has been found.  An example might be in'
         + ' calling some kind of "check_errl" call point program.  Such a'
         + ' call point program might return a 2 (i.e. 0x00000200) to indicate'
         + ' that a given error log entry was found in an "ignore" list and is'
         + ' therefore to be ignored.  That being the case, no other'
         + ' "check_errl" call point program would need to be called.'
         + default_string)

parser.add_argument(
    '--mch_class',
    default="obmc",
    help=mch_class_help_text + default_string)

# The stock_list will be passed to gen_get_options.  We populate it with the
# names of stock parm options we want.  These stock parms are pre-defined by
# gen_get_options.
stock_list = [("test_mode", 0), ("quiet", 1), ("debug", 0)]


def exit_function(signal_number=0,
                  frame=None):
    r"""
    Execute whenever the program ends normally or with the signals that we
    catch (i.e. TERM, INT).
    """

    dprint_executing()
    dprint_var(signal_number)

    qprint_pgm_footer()


def signal_handler(signal_number, frame):
    r"""
    Handle signals.  Without a function to catch a SIGTERM or SIGINT, our
    program would terminate immediately with return code 143 and without
    calling our exit_function.
    """

    # Our convention is to set up exit_function with atexit.registr() so
    # there is no need to explicitly call exit_function from here.

    dprint_executing()

    # Calling exit prevents us from returning to the code that was running
    # when we received the signal.
    exit(0)


def validate_parms():
    r"""
    Validate program parameters, etc.  Return True or False accordingly.
    """

    if not valid_value(call_point):
        return False

    global allow_shell_rc
    if not valid_integer(allow_shell_rc):
        return False

    # Convert to hex string for consistency in printout.
    allow_shell_rc = "0x%08x" % int(allow_shell_rc, 0)
    set_pgm_arg(allow_shell_rc)

    gen_post_validation(exit_function, signal_handler)

    return True


def run_pgm(plug_in_dir_path,
            call_point,
            allow_shell_rc):
    r"""
    Run the call point program in the given plug_in_dir_path.  Return the
    following:
    rc                              The return code - 0 = PASS, 1 = FAIL.
    shell_rc                        The shell return code returned by
                                    process_plug_in_packages.py.
    failed_plug_in_name             The failed plug in name (if any).

    Description of arguments:
    plug_in_dir_path                The directory path where the call_point
                                    program may be located.
    call_point                      The call point (e.g. "setup").  This
                                    program will look for a program named
                                    "cp_" + call_point in the
                                    plug_in_dir_path.  If no such call point
                                    program is found, this function returns an
                                    rc of 0 (i.e. success).
    allow_shell_rc                  The user may supply a value other than
                                    zero to indicate an acceptable non-zero
                                    return code.  For example, if this value
                                    equals 0x00000200, it means that for each
                                    plug-in call point that runs, a 0x00000200
                                    will not be counted as a failure.  See
                                    note above regarding left-shifting of
                                    return codes.
    """

    global autoscript

    rc = 0
    failed_plug_in_name = ""
    shell_rc = 0x00000000

    plug_in_name = os.path.basename(os.path.normpath(plug_in_dir_path))
    cp_prefix = "cp_"
    plug_in_pgm_path = plug_in_dir_path + cp_prefix + call_point
    if not os.path.exists(plug_in_pgm_path):
        # No such call point in this plug in dir path.  This is legal so we
        # return 0, etc.
        return rc, shell_rc, failed_plug_in_name

    # Get some stats on the file.
    cmd_buf = "stat -c '%n %s %z' " + plug_in_pgm_path
    dpissuing(cmd_buf)
    sub_proc = subprocess.Popen(cmd_buf, shell=True, stdout=subprocess.PIPE,
                                stderr=subprocess.STDOUT)
    out_buf, err_buf = sub_proc.communicate()
    shell_rc = sub_proc.returncode
    if shell_rc != 0:
        rc = 1
        print_var(shell_rc, hex)
        failed_plug_in_name = plug_in_name
        print(out_buf)
        print_var(failed_plug_in_name)
        print_var(shell_rc, hex)
        return rc, shell_rc, failed_plug_in_name

    print("------------------------------------------------- Starting plug-"
          + "in -----------------------------------------------")
    print(out_buf)
    if autoscript:
        stdout = 1 - quiet
        if AUTOBOOT_OPENBMC_NICKNAME != "":
            autoscript_prefix = AUTOBOOT_OPENBMC_NICKNAME + "."
        else:
            autoscript_prefix = ""
        autoscript_prefix += plug_in_name + ".cp_" + call_point
        autoscript_subcmd = "autoscript --quiet=1 --show_url=y --prefix=" +\
            autoscript_prefix + " --stdout=" + str(stdout) + " -- "
    else:
        autoscript_subcmd = ""

    cmd_buf = "PATH=" + plug_in_dir_path.rstrip("/") + ":${PATH} ; " +\
        autoscript_subcmd + cp_prefix + call_point
    pissuing(cmd_buf)

    sub_proc = subprocess.Popen(cmd_buf, shell=True)
    sub_proc.communicate()
    shell_rc = sub_proc.returncode
    # Shift to left.
    shell_rc *= 0x100
    if shell_rc != 0 and shell_rc != allow_shell_rc:
        rc = 1
        failed_plug_in_name = plug_in_name
    if shell_rc != 0:
        failed_plug_in_name = plug_in_name

    print("------------------------------------------------- Ending plug-in"
          + " -------------------------------------------------")
    if failed_plug_in_name != "":
        print_var(failed_plug_in_name)
    print_var(shell_rc, hex)

    return rc, shell_rc, failed_plug_in_name


def main():
    r"""
    This is the "main" function.  The advantage of having this function vs
    just doing this in the true mainline is that you can:
    - Declare local variables
    - Use "return" instead of "exit".
    - Indent 4 chars like you would in any function.
    This makes coding more consistent, i.e. it's easy to move code from here
    into a function and vice versa.
    """

    if not gen_get_options(parser, stock_list):
        return False

    if not validate_parms():
        return False

    qprint_pgm_header()

    # Access program parameter globals.
    global plug_in_dir_paths
    global mch_class
    global allow_shell_rc
    global stop_on_plug_in_failure
    global stop_on_non_zero_rc

    plug_in_packages_list = return_plug_in_packages_list(plug_in_dir_paths,
                                                         mch_class)

    qpvar(plug_in_packages_list)
    qprint("\n")

    allow_shell_rc = int(allow_shell_rc, 0)
    shell_rc = 0
    failed_plug_in_name = ""

    # If the autoscript program is present, we will use it to direct call point
    # program output to a separate status file.  This keeps the output of the
    # main program (i.e. OBMC Boot Test) cleaner and yet preserves call point
    # output if it is needed for debug.
    global autoscript
    global AUTOBOOT_OPENBMC_NICKNAME
    autoscript = 0
    AUTOBOOT_OPENBMC_NICKNAME = ""
    rc, out_buf = cmd_fnc("which autoscript", quiet=1, print_output=0,
                          show_err=0)
    if rc == 0:
        autoscript = 1
        AUTOBOOT_OPENBMC_NICKNAME = os.environ.get("AUTOBOOT_OPENBMC_NICKNAME",
                                                   "")
    ret_code = 0
    for plug_in_dir_path in plug_in_packages_list:
        rc, shell_rc, failed_plug_in_name = \
            run_pgm(plug_in_dir_path, call_point, allow_shell_rc)
        if rc != 0:
            ret_code = 1
            if stop_on_plug_in_failure:
                break
        if shell_rc != 0 and stop_on_non_zero_rc:
            qprint_time("Stopping on non-zero shell return code as requested"
                        + " by caller.\n")
            break

    if ret_code == 0:
        return True
    else:
        if not stop_on_plug_in_failure:
            # We print a summary error message to make the failure more
            # obvious.
            print_error("At least one plug-in failed.\n")
        return False


# Main

if not main():
    exit(1)

#!/usr/bin/env python

import sys
import __builtin__
import subprocess
import os
import argparse

# python puts the program's directory path in sys.path[0].  In other words,
# the user ordinarily has no way to override python's choice of a module from
# its own dir.  We want to have that ability in our environment.  However, we
# don't want to break any established python modules that depend on this
# behavior.  So, we'll save the value from sys.path[0], delete it, import our
# modules and then restore sys.path to its original value.

save_path_0 = sys.path[0]
del sys.path[0]

from gen_print import *
from gen_valid import *
from gen_arg import *
from gen_plug_in import *
from gen_cmd import *

# Restore sys.path[0].
sys.path.insert(0, save_path_0)
# I use this variable in calls to print_var.
hex = 1

# Create parser object to process command line parameters and args.

# Create parser object.
parser = argparse.ArgumentParser(
    usage='%(prog)s [OPTIONS]',
    description="%(prog)s will process the plug-in packages passed to it."
                + "  A plug-in package is essentially a directory containing"
                + " one or more call point programs.  Each of these call point"
                + " programs must have a prefix of \"cp_\".  When calling"
                + " %(prog)s, a user must provide a call_point parameter"
                + " (described below).  For each plug-in package passed,"
                + " %(prog)s will check for the presence of the specified call"
                + " point program in the plug-in directory.  If it is found,"
                + " %(prog)s will run it.  It is the responsibility of the"
                + " caller to set any environment variables needed by the call"
                + " point programs.\n\nAfter each call point program"
                + " has been run, %(prog)s will print the following values in"
                + " the following formats for use by the calling program:\n"
                + "  failed_plug_in_name:               <failed plug-in value,"
                + " if any>\n  shell_rc:                          "
                + "<shell return code value of last call point program - this"
                + " will be printed in hexadecimal format.  Also, be aware"
                + " that if a call point program returns a value it will be"
                + " shifted left 2 bytes (e.g. rc of 2 will be printed as"
                + " 0x00000200).  That is because the rightmost byte is"
                + " reserved for errors in calling the call point program"
                + " rather than errors generated by the call point program.>",
    formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    prefix_chars='-+')

# Create arguments.
parser.add_argument(
    'plug_in_dir_paths',
    nargs='?',
    default="",
    help=plug_in_dir_paths_help_text + default_string)

parser.add_argument(
    '--call_point',
    default="setup",
    required=True,
    help='The call point program name.  This value must not include the'
         + ' "cp_" prefix.  For each plug-in package passed to this program,'
         + ' the specified call_point program will be called if it exists in'
         + ' the plug-in directory.' + default_string)

parser.add_argument(
    '--allow_shell_rc',
    default="0x00000000",
    help='The user may supply a value other than zero to indicate an'
         + ' acceptable non-zero return code.  For example, if this value'
         + ' equals 0x00000200, it means that for each plug-in call point that'
         + ' runs, a 0x00000200 will not be counted as a failure.  See note'
         + ' above regarding left-shifting of return codes.' + default_string)

parser.add_argument(
    '--stop_on_plug_in_failure',
    default=1,
    type=int,
    choices=[1, 0],
    help='If this parameter is set to 1, this program will stop and return '
         + 'non-zero if the call point program from any plug-in directory '
         + 'fails.  Conversely, if it is set to false, this program will run '
         + 'the call point program from each and every plug-in directory '
         + 'regardless of their return values.  Typical example cases where '
         + 'you\'d want to run all plug-in call points regardless of success '
         + 'or failure would be "cleanup" or "ffdc" call points.')

parser.add_argument(
    '--stop_on_non_zero_rc',
    default=0,
    type=int,
    choices=[1, 0],
    help='If this parm is set to 1 and a plug-in call point program returns '
         + 'a valid non-zero return code (see "allow_shell_rc" parm above),'
         + ' this program will stop processing and return 0 (success).  Since'
         + ' this constitutes a successful exit, this would normally be used'
         + ' where the caller wishes to stop processing if one of the plug-in'
         + ' directory call point programs returns a special value indicating'
         + ' that some special case has been found.  An example might be in'
         + ' calling some kind of "check_errl" call point program.  Such a'
         + ' call point program might return a 2 (i.e. 0x00000200) to indicate'
         + ' that a given error log entry was found in an "ignore" list and is'
         + ' therefore to be ignored.  That being the case, no other'
         + ' "check_errl" call point program would need to be called.'
         + default_string)

parser.add_argument(
    '--mch_class',
    default="obmc",
    help=mch_class_help_text + default_string)

# The stock_list will be passed to gen_get_options.  We populate it with the
# names of stock parm options we want.  These stock parms are pre-defined by
# gen_get_options.
stock_list = [("test_mode", 0), ("quiet", 1), ("debug", 0)]


def exit_function(signal_number=0,
                  frame=None):
    r"""
    Execute whenever the program ends normally or with the signals that we
    catch (i.e. TERM, INT).
    """

    dprint_executing()
    dprint_var(signal_number)

    qprint_pgm_footer()


def signal_handler(signal_number, frame):
    r"""
    Handle signals.  Without a function to catch a SIGTERM or SIGINT, our
    program would terminate immediately with return code 143 and without
    calling our exit_function.
    """

    # Our convention is to set up exit_function with atexit.registr() so
    # there is no need to explicitly call exit_function from here.

    dprint_executing()

    # Calling exit prevents us from returning to the code that was running
    # when we received the signal.
    exit(0)


def validate_parms():
    r"""
    Validate program parameters, etc.  Return True or False accordingly.
    """

    if not valid_value(call_point):
        return False

    global allow_shell_rc
    if not valid_integer(allow_shell_rc):
        return False

    # Convert to hex string for consistency in printout.
    allow_shell_rc = "0x%08x" % int(allow_shell_rc, 0)
    set_pgm_arg(allow_shell_rc)

    gen_post_validation(exit_function, signal_handler)

    return True


def run_pgm(plug_in_dir_path,
            call_point,
            allow_shell_rc):
    r"""
    Run the call point program in the given plug_in_dir_path.  Return the
    following:
    rc                              The return code - 0 = PASS, 1 = FAIL.
    shell_rc                        The shell return code returned by
                                    process_plug_in_packages.py.
    failed_plug_in_name             The failed plug in name (if any).

    Description of arguments:
    plug_in_dir_path                The directory path where the call_point
                                    program may be located.
    call_point                      The call point (e.g. "setup").  This
                                    program will look for a program named
                                    "cp_" + call_point in the
                                    plug_in_dir_path.  If no such call point
                                    program is found, this function returns an
                                    rc of 0 (i.e. success).
    allow_shell_rc                  The user may supply a value other than
                                    zero to indicate an acceptable non-zero
                                    return code.  For example, if this value
                                    equals 0x00000200, it means that for each
                                    plug-in call point that runs, a 0x00000200
                                    will not be counted as a failure.  See
                                    note above regarding left-shifting of
                                    return codes.
    """

    global autoscript

    rc = 0
    failed_plug_in_name = ""
    shell_rc = 0x00000000

    plug_in_name = os.path.basename(os.path.normpath(plug_in_dir_path))
    cp_prefix = "cp_"
    plug_in_pgm_path = plug_in_dir_path + cp_prefix + call_point
    if not os.path.exists(plug_in_pgm_path):
        # No such call point in this plug in dir path.  This is legal so we
        # return 0, etc.
        return rc, shell_rc, failed_plug_in_name

    # Get some stats on the file.
    cmd_buf = "stat -c '%n %s %z' " + plug_in_pgm_path
    dpissuing(cmd_buf)
    sub_proc = subprocess.Popen(cmd_buf, shell=True, stdout=subprocess.PIPE,
                                stderr=subprocess.STDOUT)
    out_buf, err_buf = sub_proc.communicate()
    shell_rc = sub_proc.returncode
    if shell_rc != 0:
        rc = 1
        print_var(shell_rc, hex)
        failed_plug_in_name = plug_in_name
        print(out_buf)
        print_var(failed_plug_in_name)
        print_var(shell_rc, hex)
        return rc, shell_rc, failed_plug_in_name

    print("------------------------------------------------- Starting plug-"
          + "in -----------------------------------------------")
    print(out_buf)
    if autoscript:
        stdout = 1 - quiet
        if AUTOBOOT_OPENBMC_NICKNAME != "":
            autoscript_prefix = AUTOBOOT_OPENBMC_NICKNAME + "."
        else:
            autoscript_prefix = ""
        autoscript_prefix += plug_in_name + ".cp_" + call_point
        autoscript_subcmd = "autoscript --quiet=1 --show_url=y --prefix=" +\
            autoscript_prefix + " --stdout=" + str(stdout) + " -- "
    else:
        autoscript_subcmd = ""

    cmd_buf = "PATH=" + plug_in_dir_path.rstrip("/") + ":${PATH} ; " +\
        autoscript_subcmd + cp_prefix + call_point
    pissuing(cmd_buf)

    sub_proc = subprocess.Popen(cmd_buf, shell=True)
    sub_proc.communicate()
    shell_rc = sub_proc.returncode
    # Shift to left.
    shell_rc *= 0x100
    if shell_rc != 0 and shell_rc != allow_shell_rc:
        rc = 1
        failed_plug_in_name = plug_in_name
    if shell_rc != 0:
        failed_plug_in_name = plug_in_name

    print("------------------------------------------------- Ending plug-in"
          + " -------------------------------------------------")
    if failed_plug_in_name != "":
        print_var(failed_plug_in_name)
    print_var(shell_rc, hex)

    return rc, shell_rc, failed_plug_in_name


def main():
    r"""
    This is the "main" function.  The advantage of having this function vs
    just doing this in the true mainline is that you can:
    - Declare local variables
    - Use "return" instead of "exit".
    - Indent 4 chars like you would in any function.
    This makes coding more consistent, i.e. it's easy to move code from here
    into a function and vice versa.
    """

    if not gen_get_options(parser, stock_list):
        return False

    if not validate_parms():
        return False

    qprint_pgm_header()

    # Access program parameter globals.
    global plug_in_dir_paths
    global mch_class
    global allow_shell_rc
    global stop_on_plug_in_failure
    global stop_on_non_zero_rc

    plug_in_packages_list = return_plug_in_packages_list(plug_in_dir_paths,
                                                         mch_class)

    qpvar(plug_in_packages_list)
    qprint("\n")

    allow_shell_rc = int(allow_shell_rc, 0)
    shell_rc = 0
    failed_plug_in_name = ""

    # If the autoscript program is present, we will use it to direct call point
    # program output to a separate status file.  This keeps the output of the
    # main program (i.e. OBMC Boot Test) cleaner and yet preserves call point
    # output if it is needed for debug.
    global autoscript
    global AUTOBOOT_OPENBMC_NICKNAME
    autoscript = 0
    AUTOBOOT_OPENBMC_NICKNAME = ""
    rc, out_buf = cmd_fnc("which autoscript", quiet=1, print_output=0,
                          show_err=0)
    if rc == 0:
        autoscript = 1
        AUTOBOOT_OPENBMC_NICKNAME = os.environ.get("AUTOBOOT_OPENBMC_NICKNAME",
                                                   "")
    ret_code = 0
    for plug_in_dir_path in plug_in_packages_list:
        rc, shell_rc, failed_plug_in_name = \
            run_pgm(plug_in_dir_path, call_point, allow_shell_rc)
        if rc != 0:
            ret_code = 1
            if stop_on_plug_in_failure:
                break
        if shell_rc != 0 and stop_on_non_zero_rc:
            qprint_time("Stopping on non-zero shell return code as requested"
                        + " by caller.\n")
            break

    if ret_code == 0:
        return True
    else:
        if not stop_on_plug_in_failure:
            # We print a summary error message to make the failure more
            # obvious.
            print_error("At least one plug-in failed.\n")
        return False


# Main

if not main():
    exit(1)
#!/usr/bin/env python # python puts the program's directory path in sys.path[0].  In other words, # the user ordinarily has no way to override python's choice of a module from # its own dir.  We want to have that ability in our environment.  However, we # don't want to break any established python modules that depend on this # behavior.  So, we'll save the value from sys.path[0], delete it, import our # modules and then restore sys.path to its original value. # Restore sys.path[0]. # I use this variable in calls to print_var. # Create parser object to process command line parameters and args. # Create parser object. # Create arguments. # The stock_list will be passed to gen_get_options.  We populate it with the # names of stock parm options we want.  These stock parms are pre-defined by # gen_get_options. Execute whenever the program ends normally or with the signals that we     catch (i.e. TERM, INT). Handle signals.  Without a function to catch a SIGTERM or SIGINT, our     program would terminate immediately with return code 143 and without     calling our exit_function. # Our convention is to set up exit_function with atexit.registr() so # there is no need to explicitly call exit_function from here. # Calling exit prevents us from returning to the code that was running # when we received the signal. Validate program parameters, etc.  Return True or False accordingly. # Convert to hex string for consistency in printout. Run the call point program in the given plug_in_dir_path.  Return the     following:     rc                              The return code - 0 = PASS, 1 = FAIL.     shell_rc                        The shell return code returned by                                     process_plug_in_packages.py.     failed_plug_in_name             The failed plug in name (if any).      Description of arguments:     plug_in_dir_path                The directory path where the call_point                                     program may be located.     call_point                      The call point (e.g. "setup").  This                                     program will look for a program named                                     "cp_" + call_point in the                                     plug_in_dir_path.  If no such call point                                     program is found, this function returns an                                     rc of 0 (i.e. success).     allow_shell_rc                  The user may supply a value other than                                     zero to indicate an acceptable non-zero                                     return code.  For example, if this value                                     equals 0x00000200, it means that for each                                     plug-in call point that runs, a 0x00000200                                     will not be counted as a failure.  See                                     note above regarding left-shifting of                                     return codes. # No such call point in this plug in dir path.  This is legal so we # return 0, etc. # Get some stats on the file. # Shift to left. This is the "main" function.  The advantage of having this function vs     just doing this in the true mainline is that you can:     - Declare local variables     - Use "return" instead of "exit".     - Indent 4 chars like you would in any function.     This makes coding more consistent, i.e. it's easy to move code from here     into a function and vice versa. # Access program parameter globals. # If the autoscript program is present, we will use it to direct call point # program output to a separate status file.  This keeps the output of the # main program (i.e. OBMC Boot Test) cleaner and yet preserves call point # output if it is needed for debug. # We print a summary error message to make the failure more # obvious. # Main