PROCEDURE (HIDDEN) pfp$recover_system_set (
  set_name, sn: name = $required
  status)

" PURPOSE: To automate the recovery of existing system set members when the
"          $SYSTEM master catalog has been lost.
"
" CONSTRAINTS: This procedure cannot submit batch jobs or print files to
"              accomplish the recovery of the system set due to the fact
"              the subcatalogs for queued files are lost.
"
" This procedure is automatically executed by the NOS/VE deadstart process
" as a result of:
"
"   1) INITIALIZE_SYSTEM_DEVICE ,,RECOVER_SYSTEM_SET
"      In this case the $SYSTEM master catalog may be on a surviving class J
"      catalog volume.  Deadstart re-creates the $SYSTEM root catalog, family
"      catalog and master catalog.  All are marked as PARENT_RECREATED to
"      authorize the restoration of unreconciled catalogs; this recovers all
"      of the $SYSTEM files and catalogs not actually contained on the system
"      device.  To recover the original $SYSTEM master catalog that is
"      presumed to exist on the class J volume, it is necessary to delete the
"      master catalog $SYSTEM and all of its contents.  This also has the
"      effect of deleting the $SYSTEM family catalog.  Recovering the $SYSTEM
"      master catalog allows us to recover all files and catalogs created in
"      that catalog since the last catalog backup was taken.
"
"   2) A continuation deadstart that is missing the $SYSTEM master catalog.
"      This case differs from the preceding one in that the class J volume
"      containing the $SYSTEM master catalog has been DOWNed at a continuation
"      deadstart.  Deadstart will detect that the $SYSTEM master catalog is
"      missing and re-create it.  It will also set the PARENT_RECREATED
"      boolean in the $SYSTEM catalog to authorize the restoration of its
"      contents.  Unlike (1) above, there is no advantage to deleting the
"      $SYSTEM catalog because it exists on no other volume that is
"      accessible.
"
"      Further, we cannot deadstart without the $SYSTEM master catalog; thus
"      we are unable to wait for the class J volume to be reinstated.
"
" This procedure should not be manually executed because the two circumstances
" identified above have caused the family and master catalog $SYSTEM to be
" marked as re-created for the purposes of recovering catalogs and files on
" volumes other than the system device.  Executing this procedure at other
" times would cause the contents of the master catalog $SYSTEM to be deleted
" without hope of recovering its contents on other volumes.

  "$FORMAT=OFF
  VAR
      catalog_info: file = $fname($unique())
      echo_file: file = $fname($unique())
      extended_access_privilege: integer 0 .. 15
      ignore_status: status
      lost_cycles: file = $fname($unique())
      missing_catalogs:integer
      menu_items: list 1..5 of name
      missing_files: integer
      missing_count: integer = 9999 "Assume missing files"
      osv$deadstart_phase: (XREF) string 0 .. $max_name
      osv$reinitialize_system_device: (XREF) boolean
      restore_listing: file = $fname($unique())
      rss_report_file:file
      rss_status: status
      system_job: boolean
      system_master_catalog: file
  VAREND
  "$FORMAT=ON"

" Save current command and object lists in case this proc abends"
" Reduce the command and object lists to allow the corresponding permanent
" files to be deleted.

  PUSH command_list
  PUSH file_connections
  PUSH program_attributes
  PUSH working_catalog

  IF $variable(cmv$deadstart_simulation, defined) THEN
    extended_access_privilege=11
    system_master_catalog=cmv$rss_working_catalog
    system_job=true
  ELSE
    extended_access_privilege=3
    system_master_catalog=:$system.$system
    system_job=$job(system)
  IFEND

  set_program_attributes delete_library=all

  " The display of unreconciled files requires the use of BACPF which is
  " packaged on $system.osf$builtin_library.  A copy of this library to a
  " temporary file is required to allow access to BACPF while allowing the
  " $SYSTEM master catalog to be deleted.
  copy_file $system.osf$builtin_library $local.$builtin_library
  change_file_attributes $local.$builtin_library ring_attributes=(..
        extended_access_privilege, 13, 13)

  "The procedures that get involved in the reinitialization of the system device
  "use commands that are packaged in the SOU library.  So a copy of this library
  "to a temporary file is required before the $system master catalog is deleted.
  copy_file $system.osf$sou_library $local.$sou_library
  change_file_attributes $local.$sou_library ring_attributes=(..
        extended_access_privilege, 13, 13)

  delete_command_list_entry entry=all "allow all of $SYSTEM to be deleted"

  $system.create_command_list_entry entry=($local.osf$ds_library ..
        $local.$builtin_library $local.$sou_library $system)

  set_working_catalog system_master_catalog status=ignore_status

  rss_report_file=$fname('recover_system_set_report_'//$date('y2j3'))

  IF system_job AND ($ring = extended_access_privilege) THEN

" Task to ring 11 to allow pause-break (STOP) from System Console.  This proc
" starts running in ring 3 and execution in this ring does not permit
" interactive interruption.  This command cannot be executed until the command
" list has been adjusted to allow deletion of permanent files that may have
" been in the command list.

    TASK ring=11

      create_file_connection $errors $job_log status=ignore_status
      create_file_connection $output $job_log status=ignore_status
      create_file_connection $response $job_log status=ignore_status
      create_file_connection $echo echo_file status=ignore_status

      IF osv$deadstart_phase = 'INSTALL' AND osv$reinitialize_system_device ..
            THEN
        rap$display_message message_module=recover_system_set ..
              message_name=initialize_system_device to=$output
      ELSE
        rap$display_message message_module=recover_system_set ..
              message_name=initialize_system_catalog to=$output
      IFEND

      rap$display_message message_module=recover_system_set ..
            message_name=rss_consequences to=$output
      rap$press_next "wait for operator to read text and respond"

" Delete the contents of the master catalog $SYSTEM to allow files created in
" the $SYSTEM catalog since the catalog backup to be recovered by the catalog
" restoration process. Optionally delete the master catalog itself.

      TASK ring=extended_access_privilege
        BACKUP_PERMANENT_FILES backup_file=$null
          include_empty_catalogs delete_catalog=true
          IF osv$reinitialize_system_device THEN
            IF NOT $variable(cmv$deadstart_simulation, defined) THEN
              include_master_catalogs delete_master_catalogs=true
            IFEND
          IFEND
          IF NOT $variable(cmv$deadstart_simulation, defined) THEN
            delete_catalog_contents catalog=$working_catalog ..
                  status=ignore_status
          IFEND

        QUIT
      TASKEND

    menu_items=$list_of(display_active_volumes, ..
          display_command_information restore_only_catalogs, ..
          restore_catalogs_and_files)

    " Turn off the flushing of catalogs to improve the performance of catalog restoration"
    " This is safe because modified pages are flushed by the TERMINATE_SYSTEM at the end"
    change_catalog_access flush_catalogs=off
    resmc_loop: ..
      LOOP
        choice=''
        rap$prompt_via_menu menu_module=rss_resuc_menu ..
              menu_selections=menu_items selection_chosen=choice
        cmp$display_menu_selection menu_selection=choice ..
              menu_items=menu_items output=$job_log

        IF choice = 'RESTORE_ONLY_CATALOGS' THEN
          refc='none'
          chacc_text='recovered'
        ELSEIF choice = 'RESTORE_CATALOGS_AND_FILES' THEN
          refc='(media_missing no_data_defined)'
          chacc_text='recovered and restored'
        ELSEIF choice = 'DISPLAY_ACTIVE_VOLUMES' THEN
          display_active_volumes output=$output ..
                relevant_classes=system_defined_classes sets=all
          number_of_active_volumes=0
          LOGICAL_CONFIGURATION_UTILITY
            FOR each set in $active_sets() DO
              number_of_active_volumes=number_of_active_volumes + ..
                   $size($active_set_members(set))
            FOREND
          QUIT
          rap$display_message message_module=recover_system_set ..
                message_name=active_volume_summary ..
                message_parameters=$string(number_of_active_volumes) ..
                to=$output
          rap$press_next "wait for operator to read text and respond"
          CYCLE resmc_loop
        ELSEIF choice = 'DISPLAY_COMMAND_INFORMATION' THEN
          display_command_information command=pfp$recover_system_catalogs ..
                output=$output
          rap$press_next "wait for operator to read text and respond"
          CYCLE resmc_loop
        ELSEIF choice = 'QUIT' THEN
          EXIT resmc_loop
        ELSE
          CYCLE resmc_loop
        IFEND

        rap$display_message message_module=recover_system_set ..
              message_name=catalog_restoration to=$output

        rap$display_message message_module=recover_system_set ..
              message_name=parameter_prompting to=$output

        rap$press_next "wait for operator to read text and respond"
        include_line statement_list= ..
'?pfp$recover_system_catalogs restore_excluded_file_cycles='//refc//..
' output=restore_listing.$eoi' status=rss_status

        EXIT resmc_loop WHEN rss_status.normal

        rap$display_message message_module=recover_system_set ..
              message_name=abnormal_status to=$output
        display_value value=rss_status output=$output
        rap$press_next "wait for operator to read text and respond"

" Add quit to the menu items to allow the process to continue without
" restoring more catalogs.

        menu_items=$list_of(display_active_volumes, ..
              display_command_information restore_only_catalogs, ..
              restore_catalogs_and_files, quit)
      LOOPEND resmc_loop

" Terminate the window for restoration of missing catalogs"

      IF NOT $variable(cmv$deadstart_simulation, defined) THEN
        IF $job(system) THEN
          RESTORE_PERMANENT_FILES
            set_restore_missing_catalogs operation=end status=ignore_status
          QUIT
        IFEND
      IFEND

" Delete the damage conditions that were set for the recovered/restored files
" in the $SYSTEM master catalog to allow the products and files to be
" attachable - in particular EDIT_FILE which is used in the next step.

      rap$display_message message_module=recover_system_set ..
            message_name=deleting_$system_damage ..
            message_parameters=chacc_text to=$output

      TASK ring=extended_access_privilege
        change_catalog_contents catalog=$working_catalog ..
              delete_damage_conditions=(parent_catalog_restored ..
              respf_modification_mismatch) output=catalog_info.$eoi status=ignore_status
        change_file_attributes catalog_info ring_attributes=(11, 11, 11) status=ignore_status
      TASKEND

" Optionally restore missing files, if there are any"

    file_restore_loop: ..
      LOOP
        IF rss_status.normal AND (missing_count = 0) THEN
          rap$display_message message_module=recover_system_set ..
                message_name=all_is_well to=$output
          EXIT file_restore_loop
        ELSE
          choice=''
          menu_items=$list_of(display_unreconciled_files, ..
                restore_unreconciled_files, display_active_volumes, ..
                display_command_information, quit)
          rap$prompt_via_menu menu_module=rss_resuf_menu ..
                menu_selections=menu_items selection_chosen=choice
          cmp$display_menu_selection menu_selection=choice ..
                menu_items=menu_items output=$job_log

          IF choice = 'DISPLAY_UNRECONCILED_FILES' THEN
            IF NOT $file(lost_cycles, opened) THEN
              rap$display_message message_module=recover_system_set ..
                    message_name=determine_unreconciled_files to=$output
              pup$generate_backup_listing set_name=set_name ..
                    backup_listing= lost_cycles status=rss_status
            IFEND
            IF NOT rss_status.normal THEN
              display_value value=rss_status output=$output
              rap$press_next "wait for operator to read text and respond"
              CYCLE file_restore_loop
            IFEND
            pfp$count_unreconciled_files backup_listing=lost_cycles ..
                  missing_catalogs=missing_catalogs ..
                  missing_files=missing_files status=rss_status
            IF NOT rss_status.normal THEN
              display_value value=rss_status output=$output
              rap$press_next "wait for operator to read text and respond"
              CYCLE file_restore_loop
            IFEND
            missing_count=missing_catalogs + missing_files
            IF missing_count > 0 THEN
              rap$display_message message_module=recover_system_set ..
                    message_name=unreconciled_files, message_parameters= (''..
//missing_files, ''//missing_catalogs) to=$output
              rap$press_next "wait for operator to read text and respond"

              choice=''
              menu_items=$list_of(display_missing_system_set, ..
                    continue_with_restoration)
              rap$prompt_via_menu menu_module=display_missing_menu ..
                    menu_selections=menu_items selection_chosen=choice
              cmp$display_menu_selection menu_selection=choice ..
                    menu_items=menu_items output=$job_log
              IF choice='DISPLAY_MISSING_SYSTEM_SET' THEN
                pfp$display_unreconciled_files backup_listing=lost_cycles ..
                      output=$output status=rss_status
                IF rss_status.normal THEN
                  rap$press_next "wait for operator to read text and respond"
                ELSE
                  display_value value=rss_status output=$output
                  rap$press_next "wait for operator to read text and respond"
                IFEND
              IFEND
            IFEND
          ELSEIF choice = 'RESTORE_UNRECONCILED_FILES' THEN
            rap$display_message message_module=recover_system_set ..
                  message_name=file_restoration to=$output
            rap$display_message message_module=recover_system_set ..
                  message_name=parameter_prompting to=$output
            rap$press_next "wait for operator to read text and respond"
            include_line statement_list= ..
'?pfp$restore_system_device restore_options=(no_data_defi..
ned media_missing) output=restore_listing.$eoi' status=rss_status

            IF rss_status.normal THEN
              " Force regeneration of the unreconciled file/catalog report"

              delete_file file=lost_cycles status=ignore_status

              " Delete the damage conditions that were set for the restored
              " files in the $SYSTEM master catalog to allow the products and
              " files to be attachable.

              rap$display_message message_module=recover_system_set ..
                    message_name=deleting_$system_damage ..
                    message_parameters='restored' to=$output

              TASK ring=extended_access_privilege
                change_catalog_contents catalog=$working_catalog ..
                      delete_damage_conditions=(parent_catalog_restored ..
                      respf_modification_mismatch) output=catalog_info.$eoi status=ignore_status
                change_file_attributes catalog_info ring_attributes=(11, 11, 11) status=ignore_status
              TASKEND
            ELSE
              display_value value=rss_status output=$output
              rap$press_next "wait for operator to read text and respond"
            IFEND
          ELSEIF choice = 'DISPLAY_ACTIVE_VOLUMES' THEN
            display_active_volumes output=$output ..
                  relevant_classes=system_defined_classes sets=all
            number_of_active_volumes=0
            LOGICAL_CONFIGURATION_UTILITY
              FOR each set in $active_sets() DO
                number_of_active_volumes=number_of_active_volumes + ..
                     $size($active_set_members(set))
              FOREND
            QUIT
            rap$display_message message_module=recover_system_set ..
                  message_name=active_volume_summary ..
                  message_parameters=$string(number_of_active_volumes) ..
                  to=$output
            rap$press_next "wait for operator to read text and respond"

          ELSEIF choice = 'DISPLAY_COMMAND_INFORMATION' THEN
            display_command_information command=pfp$restore_system_device ..
                  output=$output
            rap$press_next "wait for operator to read text and respond"
          ELSEIF choice = 'QUIT' THEN
            EXIT file_restore_loop
          IFEND
        IFEND
      LOOPEND file_restore_loop

" Delete the $job_input_queue, $sf_job_input_queue, and $job_swap_files
" subcatalogs of $SYSTEM just in case they were restored during this process.

      TASK ring=extended_access_privilege
        delete_catalog catalog=$job_input_queue do=contents_only ..
              status=ignore_status
        delete_catalog catalog=$job_swap_files do=contents_only ..
              status=ignore_status
        delete_catalog catalog=$sf_job_input_queue do=contents_only ..
              status=ignore_status
      TASKEND
" Delete damage conditions from all known validation files
      LOGICAL_CONFIGURATION_UTILITY
        FOR EACH set IN $active_sets DO
          FOR EACH family IN $active_set_families(set) DO
            validation_file = $fname(':'//family//'.$system.$validations')
            display_value ' Clearing damage conditions from '//validation_file output=$output
            change_catalog_entry validation_file delete_damage_condition=(respf_modification_mismatch, ..
                  parent_catalog_restored) status=ignore_status
          FOREND
        FOREND
      QUIT

      display_catalog catalog=$working_catalog display_options=contents ..
            depth=all include_exception_conditions=all ..
            output=catalog_info.$eoi status=ignore_status

      POP file_connections

      display_log o=rss_report_file.$next status=ignore_status
      copy_file lost_cycles rss_report_file.$eoi status=ignore_status
      copy_file restore_listing rss_report_file.$eoi status=ignore_status
      copy_file catalog_info rss_report_file.$eoi status=ignore_status
      copy_file echo_file rss_report_file.$eoi status=ignore_status

      IF NOT $variable(cmv$deadstart_simulation, defined) THEN
        print_file rss_report_file status=ignore_status
      IFEND

      rap$display_message message_module=recover_system_set ..
            message_name=results_on_file message_parameters= ..
'$system.$system.recover_system_set_report_'//$date('y2j3') to=$output
      rap$press_next "wait for operator to read text and respond"

      rap$display_message message_module=recover_system_set ..
            message_name=system_termination to=$output

      IF (missing_count > 0) THEN
        rap$display_message message_module=recover_system_set ..
              message_name=termination_with_files_missing to=$output
        rap$press_next "wait for operator to read text and respond"
      IFEND

" A TERMINATE_SYSTEM is mandated to address the following deficiencies:
"
"  1. Job management cannot recover the queued output catalog except at
"     deadstart.
"  2. Job management depends upon an image file for information about which
"     jobs have started execution.  The image file is lost when the system
"     device is reinitialized.  Therefore, this proc has deleted the job
"     input queue to prevent any job from being rerun (since we cannot
"     determine which jobs had started and we have an obligation to prevent
"     jobs from being rerun that requested not to be rerun).
"  3. It is necessary to delete the PARENT_RECREATED condition in each catalog
"     that was re-created automatically by NOS/VE or by catalog restoration.
"     This prevents a deleted catalog from being restored by subsequent
"     RESPF operations.

      IF NOT $variable(cmv$deadstart_simulation, defined) THEN
        terminate_system
      IFEND

    TASKEND
  ELSE
    rap$display_message message_module=recover_system_set ..
          message_name=not_system_origin to=$output
  IFEND

PROCEND pfp$recover_system_set
