?? RIGHT := 110 ??
?? NEWTITLE := 'INSTALL_SOFTWARE Utility: INSTALL_CORRECTION Subcommand.' ??
MODULE ram$install_correction_command;

{ PURPOSE:
{   This module contains the command interface that installs a correction.
{
{ DESIGN:
{   The compiled module resides in RAF$LIBRARY.
{
{ NOTES:
{

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc rac$control_job_identifier
*copyc rac$idb_directory_name
*copyc rae$install_software_cc
*copyc rat$installation_control_record
?? POP ??
*copyc amp$get_file_attributes
*copyc clp$evaluate_parameters
*copyc clp$include_line
*copyc clp$trimmed_string_size
*copyc clp$include_line
*copyc fsp$close_file
*copyc mmp$delete_scratch_segment
*copyc osp$append_status_file
*copyc osp$disestablish_cond_handler
*copyc osp$establish_block_exit_hndlr
*copyc osp$set_status_abnormal
*copyc rap$display_job_log_to_cmd_log
*copyc rap$establish_processing_cntrls
*copyc rap$init_processing_seq
*copyc rap$perform_installation_steps
*copyc rap$submit_batch_jobs
*copyc rap$validate_for_installation
*copyc rav$installation_defaults
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??

?? OLDTITLE ??
?? NEWTITLE := '[XDCL] rap$install_correction_command', EJECT ??

{ PURPOSE:
{   This command interface installs the specified product(s), subproduct(s)
{   or group(s).
{
{ DESIGN:
{   The installation process is divided into the following major steps:
{
{     1.  RECONCILING CYCLE CONFLICTS
{     2.  LOADING THE SUBPRODUCTS
{     3.  CORRECTING THE SUBPRODUCTS
{     4.  STAGING THE SUBPRODUCTS
{     5.  ACTIVATING THE SUBPRODUCTS
{     6.  EXECUTING THE INSTALLER PROCEDURES
{     7.  UPDATING THE IDB DIRECTORY
{     8.  DELETING PREVIOUS CYCLES
{
{   For the installation of corrections all steps are performed except the
{   deletion of previous cycles when previous cycles are to be saved.  In
{   addition, if the installation option is deferred, the steps to activate
{   the subproducts, execute installer procedures and delete previous cycles
{   are deferred.  The deferred steps are performed at a future deadstart.
{
{   The actual execution of the installation steps may cross job boundaries
{   depending on the circumstances.  By default processing is in batch.
{   This will free up the caller job (typically the console) for other
{   work.
{
{   Asynchronous processing is not available for installing corrections
{   as it is for installing products.  This is due to dependency concerns.
{
{   A hidden option is provided to force processing to remain in the job of
{   the caller.  This option is not advertised and solely for the maintenance
{   and checkout of this command interface.
{
{   The processing of any installation request is controlled by an
{   installation control record.  The installation control record contains
{   or has access to all pertainent information (including direct access to
{   information in the packing list).  The installation control record is
{   used to keep track of which TASKS are to be performed against which
{   subproducts.
{
{     NOTE:  The distinction between a step and a task is that steps
{     indicate processing at the global level, where as, tasks relate to
{     processing at the subproduct level.
{
{   The processing information is stored in segment accessed files (since
{   it must be accessable by other batch jobs).  Besides the packing list
{   (which defines the contents of the order and gives basic order
{   information), an installation control file is created to provide job
{   processing information, and a processing summary file is established to
{   provide job status feedback to the user.  The job logs from the batch
{   jobs (or current job) are (is) also written to permanent log files.
{
{   The installation control file is copied to memory by the batch job for
{   step/task processing.  The contents of the installation control file
{   were originally set up in memory and written to file only when batch
{   processing is performed.  While in memory it is referred to as the
{   processing sequence.
{
{   The installation control record contains pointers to the packing list,
{   the processing sequence and the job status record (in the processing
{   summary file).  It is only available to the job in which it was
{   created, and therefore must be recreated by the processing job.
{
{   The job log will be written to a permanent command log file under the
{   installation identifier catalog.  The job log is first displayed to
{   $null to set a LAST displayed mark.  After processing, the job log is
{   displayed starting from the last displayed mark.
{
{   The initial setup prior to performing the installation steps is:
{
{     1.  Flesh out the installation control record.  This includes the
{         creation of the processing sequence in memory (based on order
{         medium type and subproduct count).  The packing list is accessed
{         and a modifiable copy is placed into the processing sequence.
{         The major data pointers are established to the copy in the
{         processing sequence.
{
{     2.  Access the IDB directory and validate the product list.
{         Assign the tasks to be performed on the associated subproducts.
{
{     3.  Assign an installation identifier, job identifiers and log file
{         name.  Establish the processing summary file.
{
{     When batch processing is performed:
{
{     4.  Write the installation control file by copying the processing
{         sequence.  Submit the batch job.
{
{ NOTES:
{   The scratch segment is used for the processing sequence and is created
{   in RAP$INIT_PROCESSING_SEQ.
{

  PROCEDURE [XDCL] rap$install_correction_command
    (    parameter_list: clt$parameter_list;
     VAR status: ost$status);


{ PROCEDURE insc_pdt (
{   packing_list, pl: name 1..16 = $required
{   product, products, p: any of
{       key
{         all
{       keyend
{       list of name
{     anyend = $required
{   exclude_product, exclude_products, ep: list of name = $optional
{   force_reinstall, fr: boolean = false
{   installation_option, io: key
{       (immediate, i)
{       (deferred, d)
{     keyend = deferred
{   save_previous_cycles, spc: boolean = false
{   execute_in_job_of_caller, eijoc: (BY_NAME, HIDDEN) boolean = false
{   status)

?? PUSH (LISTEXT := ON) ??
?? FMT (FORMAT := OFF) ??

  VAR
    pdt: [STATIC, READ, cls$declaration_section] record
      header: clt$pdt_header,
      names: array [1 .. 17] of clt$pdt_parameter_name,
      parameters: array [1 .. 8] of clt$pdt_parameter,
      type1: record
        header: clt$type_specification_header,
        qualifier: clt$name_type_qualifier,
      recend,
      type2: record
        header: clt$type_specification_header,
        qualifier: clt$union_type_qualifier,
        type_size_1: clt$type_specification_size,
        element_type_spec_1: record
          header: clt$type_specification_header,
          qualifier: clt$keyword_type_qualifier,
          keyword_specs: array [1 .. 1] of clt$keyword_specification,
        recend,
        type_size_2: clt$type_specification_size,
        element_type_spec_2: record
          header: clt$type_specification_header,
          qualifier: clt$list_type_qualifier,
          element_type_spec: record
            header: clt$type_specification_header,
            qualifier: clt$name_type_qualifier,
          recend,
        recend,
      recend,
      type3: record
        header: clt$type_specification_header,
        qualifier: clt$list_type_qualifier,
        element_type_spec: record
          header: clt$type_specification_header,
          qualifier: clt$name_type_qualifier,
        recend,
      recend,
      type4: record
        header: clt$type_specification_header,
        default_value: string (5),
      recend,
      type5: record
        header: clt$type_specification_header,
        qualifier: clt$keyword_type_qualifier,
        keyword_specs: array [1 .. 4] of clt$keyword_specification,
        default_value: string (8),
      recend,
      type6: record
        header: clt$type_specification_header,
        default_value: string (5),
      recend,
      type7: record
        header: clt$type_specification_header,
        default_value: string (5),
      recend,
      type8: record
        header: clt$type_specification_header,
      recend,
    recend := [
    [1,
    [89, 8, 14, 11, 4, 45, 40],
    clc$command, 17, 8, 2, 0, 1, 0, 8, ''], [
    ['EIJOC                          ',clc$abbreviation_entry, 7],
    ['EP                             ',clc$abbreviation_entry, 3],
    ['EXCLUDE_PRODUCT                ',clc$nominal_entry, 3],
    ['EXCLUDE_PRODUCTS               ',clc$alias_entry, 3],
    ['EXECUTE_IN_JOB_OF_CALLER       ',clc$nominal_entry, 7],
    ['FORCE_REINSTALL                ',clc$nominal_entry, 4],
    ['FR                             ',clc$abbreviation_entry, 4],
    ['INSTALLATION_OPTION            ',clc$nominal_entry, 5],
    ['IO                             ',clc$abbreviation_entry, 5],
    ['P                              ',clc$abbreviation_entry, 2],
    ['PACKING_LIST                   ',clc$nominal_entry, 1],
    ['PL                             ',clc$abbreviation_entry, 1],
    ['PRODUCT                        ',clc$nominal_entry, 2],
    ['PRODUCTS                       ',clc$alias_entry, 2],
    ['SAVE_PREVIOUS_CYCLES           ',clc$nominal_entry, 6],
    ['SPC                            ',clc$abbreviation_entry, 6],
    ['STATUS                         ',clc$nominal_entry, 8]],
    [
{ PARAMETER 1
    [11, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name, clc$specify_positionally],
    clc$pass_by_value, clc$immediate_evaluation, clc$standard_parameter_checking, 5, clc$required_parameter, 0
  , 0],
{ PARAMETER 2
    [13, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name, clc$specify_positionally],
    clc$pass_by_value, clc$immediate_evaluation, clc$standard_parameter_checking, 85, clc$required_parameter,
  0, 0],
{ PARAMETER 3
    [3, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name, clc$specify_positionally],
    clc$pass_by_value, clc$immediate_evaluation, clc$standard_parameter_checking, 21, clc$optional_parameter,
  0, 0],
{ PARAMETER 4
    [6, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name, clc$specify_positionally],
    clc$pass_by_value, clc$immediate_evaluation, clc$standard_parameter_checking, 3,
  clc$optional_default_parameter, 0, 5],
{ PARAMETER 5
    [8, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name, clc$specify_positionally],
    clc$pass_by_value, clc$immediate_evaluation, clc$standard_parameter_checking, 155,
  clc$optional_default_parameter, 0, 8],
{ PARAMETER 6
    [15, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name, clc$specify_positionally],
    clc$pass_by_value, clc$immediate_evaluation, clc$standard_parameter_checking, 3,
  clc$optional_default_parameter, 0, 5],
{ PARAMETER 7
    [5, clc$hidden_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name],
    clc$pass_by_value, clc$immediate_evaluation, clc$standard_parameter_checking, 3,
  clc$optional_default_parameter, 0, 5],
{ PARAMETER 8
    [17, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name],
    clc$pass_by_reference, clc$immediate_evaluation, clc$standard_parameter_checking, 3,
  clc$optional_parameter, 0, 0]],
{ PARAMETER 1
    [[1, 0, clc$name_type], [1, 16]],
{ PARAMETER 2
    [[1, 0, clc$union_type], [[clc$keyword_type, clc$list_type],
    FALSE, 2],
    44, [[1, 0, clc$keyword_type], [1], [
      ['ALL                            ', clc$nominal_entry, clc$normal_usage_entry, 1]]
      ],
    21, [[1, 0, clc$list_type], [5, 1, clc$max_list_size, FALSE],
        [[1, 0, clc$name_type], [1, osc$max_name_size]]
      ]
    ],
{ PARAMETER 3
    [[1, 0, clc$list_type], [5, 1, clc$max_list_size, FALSE],
      [[1, 0, clc$name_type], [1, osc$max_name_size]]
    ],
{ PARAMETER 4
    [[1, 0, clc$boolean_type],
    'false'],
{ PARAMETER 5
    [[1, 0, clc$keyword_type], [4], [
    ['D                              ', clc$abbreviation_entry, clc$normal_usage_entry, 2],
    ['DEFERRED                       ', clc$nominal_entry, clc$normal_usage_entry, 2],
    ['I                              ', clc$abbreviation_entry, clc$normal_usage_entry, 1],
    ['IMMEDIATE                      ', clc$nominal_entry, clc$normal_usage_entry, 1]]
    ,
    'deferred'],
{ PARAMETER 6
    [[1, 0, clc$boolean_type],
    'false'],
{ PARAMETER 7
    [[1, 0, clc$boolean_type],
    'false'],
{ PARAMETER 8
    [[1, 0, clc$status_type]]];

?? FMT (FORMAT := ON) ??
?? POP ??

    CONST
      p$packing_list = 1,
      p$product = 2,
      p$exclude_product = 3,
      p$force_reinstall = 4,
      p$installation_option = 5,
      p$save_previous_cycles = 6,
      p$execute_in_job_of_caller = 7,
      p$status = 8;

    VAR
      pvt: array [1 .. 8] of clt$parameter_value;


    VAR
      ignore_status: ost$status,
      installation_control_record: rat$installation_control_record,
      installation_tasks: rat$task_selections,
      local_status: ost$status,
      packing_list_fid: amt$file_identifier,
      packing_list_opened: boolean,
      processing_segment_pointer: amt$segment_pointer;


?? NEWTITLE := 'abort_handler', EJECT ??

{ PURPOSE:
{   This procedure cleans up when an abort situation occurs within the
{   block structure.
{
{ DESIGN:
{   The function of this condition handler is to return the processing
{   segment and packing list file when an abort condition arises.
{
{   When the processing segment pointer is not NIL, attempt to display the
{   job log to the command log.
{
{ NOTES:
{

    PROCEDURE abort_handler
      (    condition: pmt$condition;
           condition_information: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        ignore_status: ost$status;


      IF processing_segment_pointer.sequence_pointer <> NIL THEN
        rap$display_job_log_to_cmd_log (installation_control_record.processing_header_p^.
              installation_defaults.installation_logs, installation_control_record.processing_header_p^.
              installation_identifier, ignore_status);
        mmp$delete_scratch_segment (processing_segment_pointer, ignore_status);
        processing_segment_pointer.sequence_pointer := NIL;
      IFEND;

      fsp$close_file (packing_list_fid, ignore_status);

    PROCEND abort_handler;

?? OLDTITLE, EJECT ??


    status.normal := TRUE;

    clp$evaluate_parameters (parameter_list, #SEQ (pdt), NIL, ^pvt, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    check_directory_presence (rav$installation_defaults.installation_database, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    clp$include_line ('$system.display_log do=last o=$null', TRUE, osc$null_name, ignore_status);

    installation_control_record.job_identifier := rac$control_job_identifier;
    installation_control_record.job_status_record_p := NIL;

    processing_segment_pointer.kind := amc$sequence_pointer;
    processing_segment_pointer.sequence_pointer := NIL;
    packing_list_opened := FALSE;

    osp$establish_block_exit_hndlr (^abort_handler);

  /main/
    BEGIN

      rap$init_processing_seq (pvt [p$packing_list].value^.name_value,
            pvt [p$save_previous_cycles].value^.boolean_value.value, rac$install_correction, rac$correction,
            rav$installation_defaults, installation_control_record, processing_segment_pointer,
            packing_list_fid, packing_list_opened, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      get_task_set (pvt [p$installation_option].value^.keyword_value, installation_control_record.
            processing_header_p, installation_tasks);

      rap$validate_for_installation (pvt [p$product].value, pvt [p$exclude_product].value,
            pvt [p$force_reinstall].value^.boolean_value.value, installation_tasks,
            installation_control_record, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      rap$establish_processing_cntrls (FALSE {multiple job processing} ,
            pvt [p$execute_in_job_of_caller].value^.boolean_value.value, installation_control_record, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      IF pvt [p$execute_in_job_of_caller].value^.boolean_value.value THEN

        rap$perform_installation_steps (installation_control_record, status);

      ELSE {execute in batch}

        rap$submit_batch_jobs (installation_control_record, status);

      IFEND;

    END /main/;

    IF packing_list_opened THEN
      fsp$close_file (packing_list_fid, local_status);
      IF status.normal AND (NOT local_status.normal) THEN
        status := local_status;
      IFEND;
    IFEND;

    IF processing_segment_pointer.sequence_pointer <> NIL THEN
      rap$display_job_log_to_cmd_log (installation_control_record.processing_header_p^.installation_defaults.
            installation_logs, installation_control_record.processing_header_p^.installation_identifier,
            ignore_status);
      mmp$delete_scratch_segment (processing_segment_pointer, local_status);
      processing_segment_pointer.sequence_pointer := NIL;
      IF status.normal AND (NOT local_status.normal) THEN
        status := local_status;
      IFEND;
    IFEND;

    osp$disestablish_cond_handler;

  PROCEND rap$install_correction_command;

?? OLDTITLE ??
?? NEWTITLE := 'check_directory_presence', EJECT ??

{ PURPOSE:
{   This procedure checks for the presence fo the IDB Directory as defined
{   by the installation database path.  Bad status is returned when not
{   found.
{
{ DESIGN:
{
{ NOTES:
{

  PROCEDURE check_directory_presence
    (    installation_database: rat$path;
     VAR status: ost$status);


    VAR
      directory: rat$path,
      existing_file: boolean,
      ignore_attributes: array [1 .. 1] of amt$get_item,
      ignore_contains_data: boolean,
      local_file: boolean;


    status.normal := TRUE;
    ignore_attributes [1].key := amc$file_length;

    STRINGREP (directory.path, directory.size, rav$installation_defaults.installation_database.
          path (1, rav$installation_defaults.installation_database.size), '.', rac$idb_directory_name);

    amp$get_file_attributes (directory.path (1, directory.size), ignore_attributes, local_file, existing_file,
          ignore_contains_data, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF (NOT local_file) AND (NOT existing_file) THEN
      osp$set_status_abnormal ('RA', rae$directory_required_for_corr, '', status);
      osp$append_status_file (osc$status_parameter_delimiter, directory.path (1, directory.size), status);
      RETURN;
    IFEND;

  PROCEND check_directory_presence;

?? OLDTITLE ??
?? NEWTITLE := 'get_task_set', EJECT ??

{ PURPOSE:
{   This procedure returns the set of tasks to be performed on the selected
{   products.  The step set and number of steps are registered in the
{   processing header record.
{
{ DESIGN:
{   For the installation of corrections all tasks are performed except the
{   deletion of previous cycles when save_previous_cycles is true.  In
{   addition, if the installation option is deferred, the tasks to
{   activate the files, execute installer procedures and delete previous
{   cycles are removed.
{
{   Currently the number of steps to be performed relates directly to the
{   number of tasks.  That is why the number of steps is computed by
{   subtracting the number of tasks removed from processing.
{
{ NOTES:
{

  PROCEDURE get_task_set
    (    installation_option: ost$name;
         processing_header_p {input, output} : ^rat$processing_header;
     VAR installation_tasks: rat$task_selections);


{ Determine the installation step and task sets.  The '-' means to take the complement.

    IF installation_option = 'DEFERRED' THEN
      processing_header_p^.step_set := -$rat$step_selections [rac$activate_subproducts_step,
            rac$execute_installer_proc_step, rac$delete_previous_cycles_step];
      processing_header_p^.number_of_steps := rac$max_number_of_steps - 3;
      installation_tasks := - $rat$task_selections [rac$activate_files_task,
            rac$execute_installer_proc_task, rac$delete_previous_cycles_task];
    ELSE  {installation option is immedidate}
      IF processing_header_p^.save_previous_cycles THEN
        processing_header_p^.step_set := -$rat$step_selections [rac$delete_previous_cycles_step];
        processing_header_p^.number_of_steps := rac$max_number_of_steps - 1;
        installation_tasks := -$rat$task_selections [rac$delete_previous_cycles_task];
      ELSE {delete previous cycles}
        processing_header_p^.step_set := -$rat$step_selections [];
        processing_header_p^.number_of_steps := rac$max_number_of_steps;
        installation_tasks := -$rat$task_selections [];
      IFEND;
    IFEND;

  PROCEND get_task_set;
MODEND ram$install_correction_command;
