?? RIGHT := 110 ??
?? NEWTITLE := 'INSTALL_SOFTWARE Utility: RAP$LOAD_PRODUCTS Interface.' ??
MODULE ram$load_products;

{ PURPOSE:
{   This module contains the interface and procedures to load
{   the products from the order medium into their destinations.
{
{ DESIGN:
{   The compiled module resides in RAF$LIBRARY.
{
{ NOTES:
{

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc rac$local_primary_tape
*copyc rae$install_software_cc
*copyc rme$request_command_exceptions
*copyc rat$installation_control_record
?? POP ??
*copyc amp$return
*copyc clp$delete_variable
*copyc clp$convert_integer_to_string
*copyc clp$get_variable
*copyc clp$include_line
*copyc clp$trimmed_string_size
*copyc osp$generate_error_message
*copyc osp$generate_log_message
*copyc osp$set_status_abnormal
*copyc pfp$convert_fs_path_to_pf_path
*copyc pfp$convert_string_to_fs_path
*copyc pfp$define_catalog
*copyc pmp$get_unique_name
*copyc rap$clear_installation
*copyc rap$convert_path_to_str
*copyc rap$create_scl_status_variable
*copyc rap$get_majority_file_class
*copyc rap$record_step_status
*copyc rap$record_subproduct_status
*copyc rmp$request_tape


?? TITLE := 'Global Declarations Declared by This Module', EJECT ??

  CONST
    restore_status_variable = 'RAV$RESTORE_STATUS';

?? TITLE := '[XDCL] rap$load_products', EJECT ??

{ PURPOSE:
{   This interface peforms the load products step.
{
{ DESIGN:
{
{ NOTES:
{   If a step start is recorded then a step completion should also be
{   recorded.  The same thing applies to subproduct task information.
{
{   Status handling:
{
{   Generally, all bad status is recorded to the job log and not returned.
{   The idea is that as long as the installation process remains in control
{   it will continue to install everything it possibly can (on a subproduct
{   basis).  This puts a great deal of importance on being able to record
{   to the job log.  Therefore bad status is returned when recording the
{   step status information (which is the first indication of not being
{   able to record to the job log).
{
{   Status is ignored when recording task status.  This should never fail
{   as long as we can write to $job_log and other routines have already
{   verified this.
{
{   Currently the only bad status being returned to this interface are
{   requesting tape errors or restoring disk backup catalog.  This causes
{   the rest of the processing steps to be skipped.  It is believed that
{   there is no reason to continue with the other steps since nothing was
{   loaded.
{
{   The SUBPRODUCTS_FAILED_PROCESSING boolean has been initialized outside
{   of this interface and should never be re-initialized here.
{

  PROCEDURE [XDCL] rap$load_products
    (VAR called_from_package_software: boolean;
     VAR installation_control_record {input, output} : rat$installation_control_record;
     VAR subproducts_failed_processing: boolean;
     VAR status: ost$status);


    VAR
      ignore_status: ost$status,
      local_status: ost$status;


    status.normal := TRUE;

    IF NOT (rac$load_subproducts_step IN installation_control_record.processing_header_p^.step_set) THEN
      RETURN;
    IFEND;

    rap$record_step_status (rac$load_subproducts_step, rac$step_started, installation_control_record, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

  /main/
    BEGIN

      { Create an SCL status variable to be used by the loading procedures.

      rap$create_scl_status_variable (restore_status_variable, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      IF installation_control_record.packing_list_pointers.order_medium = rac$tape THEN

        load_products_from_tape (called_from_package_software, installation_control_record,
              subproducts_failed_processing, status);

      ELSE {order medium = rac$disk}

        load_products_from_disk (called_from_package_software, installation_control_record,
              subproducts_failed_processing, status);

      IFEND;

      rap$clear_installation (installation_control_record, ignore_status);

      clp$delete_variable (restore_status_variable, ignore_status);

    END /main/;

    rap$record_step_status (rac$load_subproducts_step, rac$step_completed, installation_control_record,
          local_status);
    IF status.normal AND (NOT local_status.normal) THEN
      status := local_status;
    IFEND;

  PROCEND rap$load_products;

?? TITLE := 'delete_disk_file_catalog', EJECT ??

{ PURPOSE:
{   This procedure deletes the disk file catalog and contents.
{
{ DESIGN:
{
{ NOTES:
{

  PROCEDURE delete_disk_file_catalog
    (    disk_file_catalog: rat$path;
     VAR status: ost$status);


    VAR
      command_line: string (1000),
      command_line_length: integer;


    status.normal := TRUE;

    { Collect the SCL command required to delete disk backup catalog from the disk file.

?? FMT (FORMAT := OFF) ??
    STRINGREP (command_line, command_line_length,
          '$system.delete_catalog c=', disk_file_catalog.path (1, disk_file_catalog.size),
                 ' do=catalog_and_contents');
?? FMT (FORMAT := ON) ??

    { Execute the SCL command to delete catalog and contents.

    clp$include_line (command_line (1, command_line_length), TRUE, osc$null_name, status);

  PROCEND delete_disk_file_catalog;

?? TITLE := 'get_restore_status', EJECT ??

{ PURPOSE:
{   This interface returns the SCL status variable used in restoring the
{   products.
{
{ DESIGN:
{   The restore status variable's name is passed in along with a scratch
{   sequence to hold the status variable.  The retrieval of the SCL status
{   variable follows standard cybil procedure.
{
{ NOTES:
{   The scratch sequence is defined to be for temporary storage and can
{   therefore be reset at anytime.
{

  PROCEDURE get_restore_status
    (    restore_status_var_name: clt$variable_ref_expression;
     VAR scratch_seq_p {output} : ^SEQ ( * );
     VAR restore_status: ost$status);


    VAR
      access_mode: clt$data_access_mode,
      class: clt$variable_class,
      evaluation_method: clt$expression_eval_method,
      restore_status_p: ^clt$data_value,
      type_specification_p: ^clt$type_specification;


    restore_status.normal := TRUE;

    RESET scratch_seq_p;

    clp$get_variable (restore_status_var_name, scratch_seq_p, class, access_mode, evaluation_method,
          type_specification_p, restore_status_p, restore_status);
    IF NOT restore_status.normal THEN
      RETURN;
    IFEND;

    restore_status := restore_status_p^.status_value^;

  PROCEND get_restore_status;

?? TITLE := 'load_products_from_disk', EJECT ??

{ PURPOSE:
{   This procedure loads the products from disk.
{
{ DESIGN:
{   It is assumed only one job is processing the entire disk order.
{
{ NOTES:
{

  PROCEDURE load_products_from_disk
    (VAR called_from_package_software: boolean;
     VAR installation_control_record {input, output} : rat$installation_control_record;
     VAR subproducts_failed_processing: boolean;
     VAR status: ost$status);


    VAR
      disk_file_catalog: rat$path,
      ignore_status: ost$status,
      local_status: ost$status,
      subproduct_index: rat$subproduct_count,
      task_status: ost$status;


    status.normal := TRUE;

    restore_disk_file_catalog (called_from_package_software, installation_control_record,
           disk_file_catalog, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    FOR subproduct_index := 1 TO UPPERBOUND (installation_control_record.subproduct_processing_records_p^) DO

      IF (installation_control_record.job_identifier = installation_control_record.
            subproduct_processing_records_p^ [subproduct_index].job_identifier) AND
            (rac$load_files_task IN installation_control_record.
            subproduct_processing_records_p^ [subproduct_index].task_set) AND
            (installation_control_record.subproduct_processing_records_p^ [subproduct_index].task_status <>
            rac$task_failed) THEN

        rap$record_subproduct_status (rac$load_files_task, rac$task_started, subproduct_index,
              installation_control_record, ignore_status);

        load_subproduct_from_disk (called_from_package_software, disk_file_catalog, subproduct_index,
              installation_control_record, task_status);

        IF task_status.normal THEN
          rap$record_subproduct_status (rac$load_files_task, rac$task_completed, subproduct_index,
                installation_control_record, ignore_status);
        ELSE
          osp$generate_log_message ($pmt$ascii_logset [pmc$job_log], task_status, ignore_status);
          rap$record_subproduct_status (rac$load_files_task, rac$task_failed, subproduct_index,
                installation_control_record, ignore_status);
          subproducts_failed_processing := TRUE;
        IFEND;

      IFEND;
    FOREND;

    delete_disk_file_catalog (disk_file_catalog, local_status);
    IF NOT local_status.normal THEN
      osp$generate_log_message ($pmt$ascii_logset [pmc$job_log], ignore_status, ignore_status);
    IFEND;

  PROCEND load_products_from_disk;

?? TITLE := 'load_products_from_tape', EJECT ??

{ PURPOSE:
{   This procedure loads the products from tape.
{
{ DESIGN:
{   Processing loops through the medium processing record.  Each tape
{   assigned to this job is handled separately.
{
{   If a tape has been previously mounted, it will be left attached unless
{   more than one tape will be requested.  This allows for a tape to be left
{   mounted through a series of command calls, which is important during the
{   deadstart process.
{
{ NOTES:
{

  PROCEDURE load_products_from_tape
    (VAR called_from_package_software: boolean;
     VAR installation_control_record {input, output} : rat$installation_control_record;
     VAR subproducts_failed_processing: boolean;
     VAR status: ost$status);


    VAR
      ignore_status: ost$status,
      local_status: ost$status,
      number_of_tapes_to_assign: rat$tape_count,
      subproduct_index: rat$subproduct_count,
      tape_already_assigned: boolean,
      tape_file: rat$path,
      tape_index: rat$tape_count,
      task_status: ost$status;


    status.normal := TRUE;

    { Determine the number of tapes to be assigned by this job.

    number_of_tapes_to_assign := 0;
    FOR tape_index := 1 TO UPPERBOUND (installation_control_record.medium_processing_records_p^) DO
      IF installation_control_record.job_identifier = installation_control_record.
            medium_processing_records_p^ [tape_index].job_identifier THEN
        number_of_tapes_to_assign := number_of_tapes_to_assign + 1;
      IFEND;
    FOREND;

    { Load the subproducts from each tape assigned to this job.

    FOR tape_index := 1 TO UPPERBOUND (installation_control_record.medium_processing_records_p^) DO

      IF installation_control_record.job_identifier = installation_control_record.
            medium_processing_records_p^ [tape_index].job_identifier THEN

        request_tape (installation_control_record.packing_list_pointers, tape_index, tape_file,
              tape_already_assigned, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

        FOR subproduct_index := 1 TO UPPERBOUND (installation_control_record.subproduct_processing_records_p^)
              DO

          IF (installation_control_record.job_identifier = installation_control_record.
                subproduct_processing_records_p^ [subproduct_index].job_identifier) AND
                (tape_index = installation_control_record.packing_list_pointers.
                tape_subproduct_indexer_p^ [subproduct_index].primary_tape_vsn) AND
                (rac$load_files_task IN installation_control_record.
                subproduct_processing_records_p^ [subproduct_index].task_set) AND
                (installation_control_record.subproduct_processing_records_p^ [subproduct_index].
                task_status <> rac$task_failed) THEN

            rap$record_subproduct_status (rac$load_files_task, rac$task_started, subproduct_index,
                  installation_control_record, ignore_status);

            load_subproduct_from_tape (called_from_package_software, tape_file, subproduct_index,
                  installation_control_record, task_status);

            IF task_status.normal THEN
              rap$record_subproduct_status (rac$load_files_task, rac$task_completed, subproduct_index,
                    installation_control_record, ignore_status);
            ELSE
              osp$generate_log_message ($pmt$ascii_logset [pmc$job_log], task_status, ignore_status);
              rap$record_subproduct_status (rac$load_files_task, rac$task_failed, subproduct_index,
                    installation_control_record, ignore_status);
              subproducts_failed_processing := TRUE;
            IFEND;

          IFEND;
        FOREND;

        { If a tape has been previously mounted, it will be left attached unless
        { more than one tape will be requested.  This allows for a tape to be left

        IF (number_of_tapes_to_assign > 1) OR (NOT tape_already_assigned) THEN
          amp$return (tape_file.path (1, tape_file.size), local_status);
          IF NOT local_status.normal THEN
            osp$generate_log_message ($pmt$ascii_logset [pmc$job_log], local_status, ignore_status);
          IFEND;
        IFEND;

      IFEND;
    FOREND;

  PROCEND load_products_from_tape;

?? TITLE := 'load_subproduct_from_disk', EJECT ??

{ PURPOSE:
{   This procedure loads the packing list from tailored disk file to the
{   loading destination.
{
{ DESIGN:
{   Loading is performed using RESTORE_PERMANENT_FILES utility which is only
{   callable through command language.  To accomplish this, the SCL commands
{   must be collected and executed by including the lines.
{
{   Information about the load will show up in the job log.
{
{ NOTES:
{   The RESTORE_EXISTING_CATALOG subcommand uses a warning status
{   to return status with.  This is not picked up by the CLP$INCLUDE_LINE
{   (unless it happens to be the last command).  Because of this, a status
{   must be placed directly on the restore command.
{
{   The RESTORE_STATUS_VARIABLE is a global string constant that is used
{   as the name of the restore status variable.
{
{   The SCL commands that are assembled by STRINGREP into the command
{   line have been arranged for readability.  Formating has been turned
{   off to protect these lines from formatting.
{

  PROCEDURE load_subproduct_from_disk
    (    called_from_package_software: boolean;
         disk_file_catalog: rat$path;
         subproduct_index: rat$subproduct_count;
     VAR installation_control_record {input, output} : rat$installation_control_record;
     VAR status: ost$status);


    VAR
      command_line: string (1000),
      command_line_length: integer,
      file_class: ost$name,
      ignore_file_class_char: rmt$mass_storage_class,
      ignore_status: ost$status,
      loading_destination: rat$path,
      pacs_catalog: rat$path,
      restore_status: ost$status,
      subproduct_backup_file: rat$path;


    status.normal := TRUE;

    prepare_loading_destination (installation_control_record.
          subproduct_processing_records_p^ [subproduct_index], loading_destination, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pacs_catalog := installation_control_record.subproduct_processing_records_p^ [subproduct_index].
          subproduct_info_pointers.attributes_p^.pacs_catalog_path;

    rap$get_majority_file_class (subproduct_index, installation_control_record, file_class,
          ignore_file_class_char, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    STRINGREP (subproduct_backup_file.path, subproduct_backup_file.size, disk_file_catalog.
          path (1, disk_file_catalog.size), '.', installation_control_record.packing_list_pointers.
          disk_subproduct_indexer_p^ [subproduct_index].backup_file
          (1, clp$trimmed_string_size (installation_control_record.packing_list_pointers.
          disk_subproduct_indexer_p^ [subproduct_index].backup_file)));

    { Collect the SCL commands required to load the subproduct from disk.

?? FMT (FORMAT := OFF) ??
    IF called_from_package_software THEN
      STRINGREP (command_line, command_line_length,
          restore_status_variable, '.normal = TRUE; ',
          '$system.osf$builtin_library.restore_permanent_files l=$job_log; ',
          '  restore_existing_catalog c=', pacs_catalog.path (1, pacs_catalog.size),
                   ' bf=', subproduct_backup_file.path (1, subproduct_backup_file.size),
                   ' ncn=', loading_destination.path (1, loading_destination.size),
                   ' status=', restore_status_variable, '; ',
          'quit');
    ELSE
      STRINGREP (command_line, command_line_length,
          restore_status_variable, '.normal = TRUE; ',
          '$system.osf$builtin_library.restore_permanent_files l=$job_log; ',
          '  set_restore_options fc=', file_class (1, clp$trimmed_string_size (file_class)), '; ',
          '  restore_existing_catalog c=', pacs_catalog.path (1, pacs_catalog.size),
                   ' bf=', subproduct_backup_file.path (1, subproduct_backup_file.size),
                   ' ncn=', loading_destination.path (1, loading_destination.size),
                   ' status=', restore_status_variable, '; ',
          'quit');
    IFEND;
?? FMT (FORMAT := ON) ??

    { Execute the SCL loading commands and verify that the loaded file is a packing list.

    clp$include_line (command_line (1, command_line_length), TRUE, osc$null_name, status);

    get_restore_status (restore_status_variable, installation_control_record.scratch_seq_p, restore_status);
    IF NOT restore_status.normal THEN
      IF status.normal THEN
        status := restore_status;
      ELSE
        osp$generate_log_message ($pmt$ascii_logset [pmc$job_log], restore_status, ignore_status);
      IFEND;
    IFEND;

    { Delete the subproduct backup file to keep disk space usage to a minimum.

    STRINGREP (command_line, command_line_length, '$system.delete_file f=', subproduct_backup_file.path
          (1, subproduct_backup_file.size));

    clp$include_line (command_line (1, command_line_length), TRUE, osc$null_name, ignore_status);

  PROCEND load_subproduct_from_disk;

?? TITLE := 'load_subproduct_from_tape', EJECT ??

{ PURPOSE:
{   This interface loads the subproduct from a tailored product tape to the
{   loading destination.
{
{ DESIGN:
{   Loading is performed using RESTORE_PERMANENT_FILES utility which is only
{   callable through command language.  To accomplish this, the SCL commands
{   must be collected and executed by including the lines.
{
{   Information about the load will show up in the job log.
{
{ NOTES:
{   The RESTORE_EXISTING_CATALOG subcommand uses a warning status
{   to return status with.  This is not picked up by the CLP$INCLUDE_LINE
{   (unless it happens to be the last command).  Because of this, a status
{   must be placed directly on the restore command.
{
{   The RESTORE_STATUS_VARIABLE is a global string constant that is used
{   as the name of the restore status variable.
{
{   The SCL commands that are assembled by STRINGREP into the command
{   line have been arranged for readability.  Formating has been turned
{   off to protect these lines from the formater.
{
{   The tape file identifier could be checked first before attempting
{   to load packing list.
{

  PROCEDURE load_subproduct_from_tape
    (    called_from_package_software: boolean;
         tape_file: rat$path;
         subproduct_index: rat$subproduct_count;
     VAR installation_control_record {input, output} : rat$installation_control_record;
     VAR status: ost$status);


    VAR
      command_line: string (1000),
      command_line_length: integer,
      file_class: ost$name,
      file_sequence_number: ost$string,
      ignore_file_class_char: rmt$mass_storage_class,
      ignore_status: ost$status,
      loading_destination: rat$path,
      pacs_catalog: rat$path,
      restore_status: ost$status;


    status.normal := TRUE;

    prepare_loading_destination (installation_control_record.
          subproduct_processing_records_p^ [subproduct_index], loading_destination, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pacs_catalog := installation_control_record.subproduct_processing_records_p^ [subproduct_index].
          subproduct_info_pointers.attributes_p^.pacs_catalog_path;

    rap$get_majority_file_class (subproduct_index, installation_control_record, file_class,
          ignore_file_class_char, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    clp$convert_integer_to_string (installation_control_record.packing_list_pointers.
          tape_subproduct_indexer_p^ [subproduct_index].tape_file_sequence_number, 10, FALSE,
          file_sequence_number, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;


    { Collect the SCL commands required to load the subproduct from tape.

?? FMT (FORMAT := OFF) ??
    IF called_from_package_software THEN
      STRINGREP (command_line, command_line_length,
          restore_status_variable, '.normal = TRUE; ',
          '$system.osf$builtin_library.restore_permanent_files l=$job_log; ',
          '  change_tape_label_attributes f=', tape_file.path (1, tape_file.size),
                   ' fsp=fsp fsn=', file_sequence_number.value (1, file_sequence_number.size), '; ',
          '  restore_existing_catalog c=', pacs_catalog.path (1, pacs_catalog.size),
                   ' bf=', tape_file.path (1, tape_file.size),
                   ' ncn=', loading_destination.path (1, loading_destination.size),
                   ' status=', restore_status_variable, '; ',
          'quit');
    ELSE
      STRINGREP (command_line, command_line_length,
          restore_status_variable, '.normal = TRUE; ',
          '$system.osf$builtin_library.restore_permanent_files l=$job_log; ',
          '  set_restore_options fc=', file_class (1, clp$trimmed_string_size (file_class)), '; ',
          '  change_tape_label_attributes f=', tape_file.path (1, tape_file.size),
                   ' fsp=fsp fsn=', file_sequence_number.value (1, file_sequence_number.size), '; ',
          '  restore_existing_catalog c=', pacs_catalog.path (1, pacs_catalog.size),
                   ' bf=', tape_file.path (1, tape_file.size),
                   ' ncn=', loading_destination.path (1, loading_destination.size),
                   ' status=', restore_status_variable, '; ',
          'quit');
    IFEND;
?? FMT (FORMAT := ON) ??

    { Execute the SCL loading commands and verify that the loaded file is a packing list.

    clp$include_line (command_line (1, command_line_length), TRUE, osc$null_name, status);

    get_restore_status (restore_status_variable, installation_control_record.scratch_seq_p, restore_status);
    IF NOT restore_status.normal THEN
      IF status.normal THEN
        status := restore_status;
      ELSE
        osp$generate_log_message ($pmt$ascii_logset [pmc$job_log], restore_status, ignore_status);
      IFEND;
    IFEND;

  PROCEND load_subproduct_from_tape;

?? TITLE := 'prepare_loading_destination', EJECT ??

{ PURPOSE:
{   This procedure prepares the loading destination for a subproduct.  That
{   is, after determining loading destination path, it makes sure that all
{   subcatalogs in the path are created.  The loading destination path is
{   returned in string format for use by the loading procedures.
{
{ DESIGN:
{   The loading destination for a subproduct is refered to as the
{   installation catalog.  The path value for the installation catalog was
{   assigned during the initiation setup and stored in the processing record
{   of the subproduct
{
{   All the subcatalogs along the loading destination path are created if
{   they don't already exist.  The loading destination path must be in PF
{   format for the interface that attempts to create the subcatalogs, but
{   must be convert to FS path format to be used by the loading procedures.
{
{ NOTES:
{   The conversion back and forth between PF and FS path formats is a mess,
{   but it is neccessary until the PF interfaces are converted to accept FS
{   path formats.  The conversion code could be consolidated into common
{   interfaces when the SIF path container is converted to FS format.
{

  PROCEDURE prepare_loading_destination
    (    processing_record: rat$subp_processing_record;
     VAR loading_destination: rat$path;
     VAR status: ost$status);


    CONST
      first_subcatalog = 1,
      family_user_catalogs = 2; { The number of elements that makeup the family and user catalogs. }

    VAR
      destination_path_p: ^pft$path,
      ignore_status: ost$status,
      number_of_subcatalogs: fst$number_of_path_elements,
      path_sequence_p: ^SEQ ( * ),
      subcatalogs: integer;


    status.normal := TRUE;

    PUSH path_sequence_p: [[REP #SIZE (processing_record.installation_catalog_p^) OF cell]];
    RESET path_sequence_p;
    NEXT destination_path_p: [1 .. UPPERBOUND (processing_record.installation_catalog_p^)] IN path_sequence_p;
    destination_path_p^ := processing_record.installation_catalog_p^;

    rap$convert_path_to_str (destination_path_p^, loading_destination);

    number_of_subcatalogs := UPPERBOUND (destination_path_p^) - family_user_catalogs;

    FOR subcatalogs := first_subcatalog TO number_of_subcatalogs DO

      RESET path_sequence_p;
      NEXT destination_path_p: [1 .. family_user_catalogs + subcatalogs] IN path_sequence_p;

      pfp$define_catalog (destination_path_p^, ignore_status);

    FOREND;

  PROCEND prepare_loading_destination;

?? TITLE := 'restore_disk_file_catalog', EJECT ??

{ PURPOSE:
{   This procedure restores the catalog on the disk file that contains the
{   backups of all the subproducts shipped with the order.
{
{ DESIGN:
{   Loading is performed using RESTORE_PERMANENT_FILES utility which is only
{   callable through command language.  To accomplish this, the SCL commands
{   must be collected and executed by including the lines.
{
{   Information about the load will show up in the job log.
{
{ NOTES:
{   The RESTORE_CATALOG subcommand uses a warning status to return status
{   with.  This is not picked up by the CLP$INCLUDE_LINE (unless it happens
{   to be the last command).  Because of this, a status must be placed
{   directly on the restore command.
{
{   The RESTORE_STATUS_VARIABLE is a global string constant that is used
{   as the name of the restore status variable.
{
{   The SCL commands that are assembled by STRINGREP into the command
{   line have been arranged for readability.  Formating has been turned
{   off to protect these lines from formatting.
{

  PROCEDURE restore_disk_file_catalog
    (    called_from_package_software: boolean;
     VAR installation_control_record {input, output} : rat$installation_control_record;
     VAR disk_file_catalog: rat$path;
     VAR status: ost$status);


    VAR
      command_line: string (1000),
      command_line_length: integer,
      disk_backup_catalog: rat$path,
      disk_file: rat$path,
      ignore_status: ost$status,
      restore_status: ost$status,
      unique_catalog_name: ost$name;


    status.normal := TRUE;

    disk_file.path := installation_control_record.packing_list_pointers.header_p^.disk_path;
    disk_file.size := clp$trimmed_string_size (disk_file.path);

    disk_backup_catalog.path := installation_control_record.packing_list_pointers.header_p^.
          disk_backup_catalog;
    disk_backup_catalog.size := clp$trimmed_string_size (disk_backup_catalog.path);

    pmp$get_unique_name (unique_catalog_name, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    STRINGREP (disk_file_catalog.path, disk_file_catalog.size, ':$USER.',
          unique_catalog_name (1, clp$trimmed_string_size (unique_catalog_name)));


    { Collect the SCL commands required to restore disk backup catalog from the disk file.

?? FMT (FORMAT := OFF) ??
    IF called_from_package_software THEN
      STRINGREP (command_line, command_line_length,
          restore_status_variable, '.normal = TRUE; ',
          '$system.osf$builtin_library.restore_permanent_files l=$job_log; ',
          '  restore_catalog c=', disk_backup_catalog.path (1, disk_backup_catalog.size),
                   ' bf=', disk_file.path (1, disk_file.size),
                   ' ncn=', disk_file_catalog.path (1, disk_file_catalog.size),
                   ' status=', restore_status_variable, '; ',
          'quit');
    ELSE
      STRINGREP (command_line, command_line_length,
          restore_status_variable, '.normal = TRUE; ',
          '$system.osf$builtin_library.restore_permanent_files l=$job_log; ',
          '  set_restore_options fc=product; ',
          '  restore_catalog c=', disk_backup_catalog.path (1, disk_backup_catalog.size),
                   ' bf=', disk_file.path (1, disk_file.size),
                   ' ncn=', disk_file_catalog.path (1, disk_file_catalog.size),
                   ' status=', restore_status_variable, '; ',
          'quit');
    IFEND;
?? FMT (FORMAT := ON) ??

    { Execute the SCL loading commands and verify that the loaded file is a packing list.

    clp$include_line (command_line (1, command_line_length), TRUE, osc$null_name, status);

    get_restore_status (restore_status_variable, installation_control_record.scratch_seq_p, restore_status);
    IF NOT restore_status.normal THEN
      IF status.normal THEN
        status := restore_status;
      ELSE
        osp$generate_log_message ($pmt$ascii_logset [pmc$job_log], restore_status, ignore_status);
      IFEND;
    IFEND;

  PROCEND restore_disk_file_catalog;

?? TITLE := 'request_tape', EJECT ??

{ PURPOSE:
{   This procedure makes the tape request after determining the tape file
{   usage.
{
{ DESIGN:
{   The naming the of the local file associated with the tape is rigidly
{   controlled to allow for tapes to be left mounted through a series of
{   command calls.  The local file path is created by taking constant path
{   value and appending the primary tape vsn for the tape.  When the tape
{   is detected as being assigned a boolean to that effect is returned.
{
{ NOTES:
{   With the support of cartridge tape, tape class and density had to be
{   added to the packing list.  For compatibility, the processor version
{   field of the packing list's sequence descriptor is used to indicate
{   which packing lists contain tape class and density and which do not.  If
{   the packing list was generated with an earlier processor the default
{   values are used.
{
{   Prior to processor version 'PACS V1.01 1989166' the tape class and
{   density were not on the packing list.  Since the utilities only read
{   tapes, and the density could be determined from the tape itself, this was
{   acceptable.  A default density of 1600 was chosen since all tape drives
{   at that time could support this density.  Selection of 6250, for
{   example, would make it impossible for sites with non-6250 drives to read
{   tailored release tapes.  Tape class was assumed to be 9 track.
{
{   In the overall process scheme, the SETIT command and the associated
{   menus use a default of 6250.  That is density the majority of the orders
{   should be written at.  This should not be confused with the default used
{   here, which was done for the reason stated above.
{
{   Also, tape class and density taken together define tape type.  In most
{   of the other TRP interfaces tape type is referenced.
{
{   *** If the packing list's tape vsns were stored in rmt$volume_list
{   records there would not have to be any reformating.
{

  PROCEDURE request_tape
    (    packing_list_pointers: rat$packing_list_pointers;
         tape_index: rat$tape_count;
     VAR tape_file: rat$path;
     VAR tape_already_assigned: boolean;
     VAR status: ost$status);


    VAR
      i: rat$tape_count,
      ignore_status: ost$status,
      local_status: ost$status,
      next_vol_p: ^rat$tape_vsn,
      number_of_volumes: rat$tape_count,
      tape_class: rmt$tape_class,
      tape_density: rmt$density,
      vsn_list_p: ^rmt$volume_list;


    status.normal := TRUE;
    tape_already_assigned := FALSE;

    STRINGREP (tape_file.path, tape_file.size, rac$local_primary_tape, packing_list_pointers.
          tape_vsns_p^ [tape_index].recorded_vsn (1, clp$trimmed_string_size
          (packing_list_pointers.tape_vsns_p^ [tape_index].recorded_vsn)), '.1');

    { Get the values for the tape class and density.  Starting at processor version
    { 'PACS V1.01 1989166' the tape class and density are added to the packing list.

    IF packing_list_pointers.sequence_descriptor_p^.processor_version < 'PACS V1.01 1989166' THEN
      { Use defaults, tape class and density not on packing list. }
      tape_class := rmc$mt9;
      tape_density := rmc$1600;
    ELSE { packing list contains tape class and density }
      tape_class := packing_list_pointers.header_p^.tape_class;
      tape_density := packing_list_pointers.header_p^.tape_density;
    IFEND;

    { Create the vsn list by taking the linked list of additional volumes associated with
    { the current tape and converting it into an array.

    next_vol_p := #PTR (packing_list_pointers.tape_vsns_p^ [tape_index].additional_volume_p,
          packing_list_pointers.sequence_p^);
    number_of_volumes := 1;
    WHILE next_vol_p <> NIL DO
      number_of_volumes := number_of_volumes + 1;
      next_vol_p := #PTR (next_vol_p^.additional_volume_p, packing_list_pointers.sequence_p^);
    WHILEND;

    PUSH vsn_list_p: [1 .. number_of_volumes];
    next_vol_p := ^packing_list_pointers.tape_vsns_p^ [tape_index];
    FOR i := 1 TO number_of_volumes DO
      vsn_list_p^ [i].external_vsn := next_vol_p^.external_vsn;
      vsn_list_p^ [i].recorded_vsn := next_vol_p^.recorded_vsn;
      next_vol_p := #PTR (next_vol_p^.additional_volume_p, packing_list_pointers.sequence_p^);
    FOREND;

{  Make the tape request.

    rmp$request_tape (tape_file.path (1, tape_file.size), tape_class, tape_density,
          rmc$no_write_ring, vsn_list_p^, status);
    IF (NOT status.normal) AND (status.condition = rme$redundant_device_assignment) THEN
      status.normal := TRUE;
      tape_already_assigned := TRUE;
    IFEND;

  PROCEND request_tape;

MODEND ram$load_products;
