?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Deadstart : Manage RDF and Image File' ??
MODULE dsm$manage_rdf_and_image_file;

{ PURPOSE:
{   This module contains procedures used to manage the RDF areas and the image file.  The RDF (recover
{   deadstart file) areas exist before the image file on the device file.  The RDF area consists of four
{   areas.  These areas contain values that must be saved across deadstarts.  These areas are created during
{   an installation deadstart and used during continuation deadstarts.  This is a very delicate area that
{   cannot be changed without worring about back level support of the operating system.  Each RDF area
{   contains a directory and a storage area.  The directory contains entries which define the values that
{   are stored in the storage area.  Each entry contains a four character name and a relative pointer to the
{   data stored in the storage area.  Each of the four RDF areas has a special meaning to the deadstart
{   process.  The first RDF area contains data used during a production deadstart.  The second RDF area
{   contains data for the system message buffer, data from the existing buffer is stored in this area during
{   a recovery.  The third RDF contains data used during a recovery deadstart.  The fourth RDF area is unused.
{   New entries can be added to these areas.  Several things must be done for each new entry:
{     1)  An ordinal describing the entry must be added to the type declaration dst$rdf_entries.
{     2)  The v$rdf_entries array in this module, containing the four character name of the entry and the size
{         of the entry data, must be updated.
{     3)  A call to create_an_rdf_entry must be added to the procedure establish_the_rdf_areas.  That
{         procedure is divided into four areas for each RDF area so the call to create_an_rdf_entry must be
{         added in the correct place.  This will create the entry during an installation deadstart.  If the
{         entry does not exist during a continuation deadstart then the entry will be created.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc dmc$deadstart_file_alloc_size
*copyc dsc$rdf_constants
*copyc dst$image_file
*copyc dst$image_status
*copyc dst$list_block
*copyc dst$rdf_entries
*copyc dst$rdf_pointers
*copyc dst$rdf_type
*copyc dst$recover_deadstart_files
*copyc jmt$system_supplied_name
*copyc mmt$rcv_memory_mgr
*copyc pft$retained_restore_status
?? POP ??
*copyc dmp$attach_device_file
*copyc dmp$close_file
*copyc dmp$detach_device_file
*copyc dmp$open_file
*copyc dsp$create_image_file
*copyc dsp$update_image_values_in_ssr
*copyc i#current_sequence_position
*copyc mmp$write_modified_pages
*copyc osp$system_error
*copyc pmp$zero_out_table
?? EJECT ??
*copyc dmv$system_device_information
*copyc dsv$rdf_size
*copyc jmv$system_core_id
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??
  TYPE
    t$rdf_entry = RECORD
      name: t$rdf_entry_name,
      data_p: REL (SEQ ( * )) ^SEQ ( * ),
    RECEND,

    t$rdf_entry_name = string (4);
?? EJECT ??
  VAR

    { This variable contains the four character name of the RDF entry and the size, in bytes, of the RDF
    { entry data.  When a new RDF entry is added, an ordinal should be added to dst$rdf_entries and the
    { name and the size should be added to this array in the correct spot.

    v$rdf_entries: [READ] ARRAY [dst$rdf_entries] OF RECORD
      name: t$rdf_entry_name,
      size: 0 .. dsc$rdf_size,
    RECEND := [['CNDF', 8],                                              {dsc$rdf_commit_new_dsfile_flag
               ['SDST', 8],                                              {dsc$rdf_deadstart_state
               ['SDIR', dsc$rdf_directory_size],                         {dsc$rdf_directory
               ['GIMG', 8],                                              {dsc$rdf_good_image_flag
               ['SIZE', 8],                                              {dsc$rdf_image_size
               ['SKIP', 8],                                              {dsc$rdf_image_table_size
               ['JOBR', 8],                                              {dsc$rdf_job_recovery
               ['JROP', 8],                     {no longer used at 1.4.1  dsc$rdf_job_recovery_command
               ['LIST', #SIZE (dst$list_block)],                         {dsc$rdf_list_block
               ['LOAD', 8],                                              {dsc$rdf_lower_memory_limit
               ['MEMM', #SIZE (mmt$rcv_memory_mgr)],                     {dsc$rdf_page_table_modified_bit
               ['PIMW', 8],                                              {dsc$rdf_password_interval_data
               ['PREC', 8],                                              {dsc$rdf_previous_recovery_type
               ['RNAM', 32],                                             {dsc$rdf_recovery_image_status
               ['REGV', 4*8],                                            {dsc$rdf_register_values
               ['REST', #SIZE (pft$retained_restore_status)],            {dsc$rdf_restore_status
               ['NAMO', 8],                                              {dsc$rdf_ssr_name_bo_in_image
               ['STOR', dsc$rdf_size - dsc$rdf_directory_size],          {dsc$rdf_storage_area
               ['SSIZ', 8],                                              {dsc$rdf_sys_msg_buffer_size
               ['SCID', #SIZE (jmv$system_core_id)],                     {dsc$rdf_system_core_id
               ['IDLE', 32],                                             {dsc$rdf_system_idled_status
               ['SBUF', dsc$rdf_size - (dsc$rdf_directory_size + 200)],  {dsc$rdf_system_messages_buffer
               ['LSSN', jmc$system_supplied_name_size]],                 {dsc$rdf_system_supplied_name

    v$rdf_file_sfid_during_idle: gft$system_file_identifier,
    v$rdf_sfid_during_idle_exists: boolean := FALSE;
?? OLDTITLE ??
?? NEWTITLE := 'create_an_rdf_entry', EJECT ??

{ PURPOSE:
{   This procedure creates an entry in the specified RDF area.  An entry consists of a name which identifies
{   the entry and a relative pointer which points to the entry's data which is stored in the RDF storage area.

  PROCEDURE create_an_rdf_entry
    (    rdf_name: dst$rdf_entries;
     VAR rdf_seq_p: ^SEQ ( * ));

    VAR
      new_rdf_entry_p: ^t$rdf_entry,
      rdf_data_seq_p: ^SEQ ( * ),
      rdf_directory_entry_p: ^t$rdf_entry,
      rdf_directory_seq_p: ^SEQ ( * ),
      rdf_storage_entry_p: ^t$rdf_entry,
      rdf_storage_seq_p: ^SEQ ( * ),
      temp_rdf_seq_p: ^SEQ ( * );

    { Strip off the directory entry and the storage entry of the RDF area.

    temp_rdf_seq_p := rdf_seq_p;
    RESET temp_rdf_seq_p;
    NEXT rdf_directory_entry_p IN temp_rdf_seq_p;
    NEXT rdf_storage_entry_p IN temp_rdf_seq_p;

    { Retrieve the sequence pointer to the next available spot in the directory.

    rdf_directory_seq_p := #PTR (rdf_directory_entry_p^.data_p, rdf_seq_p^);

    { Add the new entry and update the directory pointer to point to the next available spot in the directory.

    IF (i#current_sequence_position (rdf_directory_seq_p) + #SIZE (t$rdf_entry)) > dsc$rdf_directory_size THEN
      osp$system_error ('The RDF directory has overflowed, cannot add anymore entries', NIL);
    IFEND;
    NEXT new_rdf_entry_p IN rdf_directory_seq_p;
    new_rdf_entry_p^.name := v$rdf_entries [rdf_name].name;
    rdf_directory_entry_p^.data_p := #REL (rdf_directory_seq_p, rdf_seq_p^);

    { Retrieve the sequence pointer to the next available spot in the storage area.

    rdf_storage_seq_p := #PTR (rdf_storage_entry_p^.data_p, rdf_seq_p^);

    { Create space for the new data in the next available spot in the storage area.

    IF (i#current_sequence_position (rdf_storage_seq_p) + v$rdf_entries [rdf_name].size) > dsc$rdf_size THEN
      osp$system_error ('The RDF area has overflowed, cannot add anymore data entries', NIL);
    IFEND;
    NEXT rdf_data_seq_p: [[REP v$rdf_entries [rdf_name].size OF cell]] IN rdf_storage_seq_p;
    pmp$zero_out_table (#LOC (rdf_data_seq_p^), #SIZE (rdf_data_seq_p^));
    new_rdf_entry_p^.data_p := #REL (rdf_data_seq_p, rdf_seq_p^);

    { Update the storage pointer to point to the next available spot in the storage area.

    rdf_storage_entry_p^.data_p := #REL (rdf_storage_seq_p, rdf_seq_p^);

  PROCEND create_an_rdf_entry;
?? OLDTITLE ??
?? NEWTITLE := 'establish_the_rdf_areas', EJECT ??

{ PURPOSE:
{   This procedure establishes the RDF areas so that they are ready to be used.  This procedure should only
{   be called during an installation deadstart.

  PROCEDURE establish_the_rdf_areas;

    VAR
      local_status: ost$status,
      rdf_file_segment: mmt$segment_pointer,
      rdf_file_sfid: gft$system_file_identifier,
      rdf_pointers: dst$rdf_pointers;

    dsp$open_rdf (rdf_file_sfid, rdf_file_segment, rdf_pointers);

    { Zero out the RDF area.

    pmp$zero_out_table (#LOC (rdf_file_segment.seq_pointer^), dsv$rdf_size);

    { Establish the production area of the RDF.

    format_the_rdf_area (rdf_pointers.production_seq_p);

    create_an_rdf_entry (dsc$rdf_commit_new_dsfile_flag, rdf_pointers.production_seq_p);
    create_an_rdf_entry (dsc$rdf_image_size, rdf_pointers.production_seq_p);
    create_an_rdf_entry (dsc$rdf_image_table_size, rdf_pointers.production_seq_p);
    create_an_rdf_entry (dsc$rdf_job_recovery, rdf_pointers.production_seq_p);
    create_an_rdf_entry (dsc$rdf_job_recovery_command, rdf_pointers.production_seq_p);
    create_an_rdf_entry (dsc$rdf_list_block, rdf_pointers.production_seq_p);
    create_an_rdf_entry (dsc$rdf_lower_memory_limit, rdf_pointers.production_seq_p);
    create_an_rdf_entry (dsc$rdf_page_table_modified_bit, rdf_pointers.production_seq_p);
    create_an_rdf_entry (dsc$rdf_previous_recovery_type, rdf_pointers.production_seq_p);
    create_an_rdf_entry (dsc$rdf_recovery_image_status, rdf_pointers.production_seq_p);
    create_an_rdf_entry (dsc$rdf_register_values, rdf_pointers.production_seq_p);
    create_an_rdf_entry (dsc$rdf_restore_status, rdf_pointers.production_seq_p);
    create_an_rdf_entry (dsc$rdf_ssr_name_bo_in_image, rdf_pointers.production_seq_p);
    create_an_rdf_entry (dsc$rdf_system_core_id, rdf_pointers.production_seq_p);
    create_an_rdf_entry (dsc$rdf_system_supplied_name, rdf_pointers.production_seq_p);
    create_an_rdf_entry (dsc$rdf_password_interval_data, rdf_pointers.production_seq_p);

    RESET rdf_pointers.production_seq_p;
    mmp$write_modified_pages (rdf_pointers.production_seq_p, #SIZE (rdf_pointers.production_seq_p^),
          osc$wait, local_status);
    IF NOT local_status.normal THEN
      osp$system_error ('Cannot write modified pages (establish production rdf).', ^local_status);
    IFEND;

    { Establish the system message buffer area of the RDF.

    format_the_rdf_area (rdf_pointers.system_message_buffer_seq_p);

    create_an_rdf_entry (dsc$rdf_system_messages_buffer, rdf_pointers.system_message_buffer_seq_p);
    create_an_rdf_entry (dsc$rdf_sys_msg_buffer_size, rdf_pointers.system_message_buffer_seq_p);

    RESET rdf_pointers.system_message_buffer_seq_p;
    mmp$write_modified_pages (rdf_pointers.system_message_buffer_seq_p,
          #SIZE (rdf_pointers.system_message_buffer_seq_p^), osc$wait, local_status);
    IF NOT local_status.normal THEN
      osp$system_error ('Cannot write modified pages (establish system message buffer rdf).', ^local_status);
    IFEND;

    { Establish the recovery area of the RDF.

    format_the_rdf_area (rdf_pointers.recovery_seq_p);

    create_an_rdf_entry (dsc$rdf_deadstart_state, rdf_pointers.recovery_seq_p);
    create_an_rdf_entry (dsc$rdf_good_image_flag, rdf_pointers.recovery_seq_p);
    create_an_rdf_entry (dsc$rdf_list_block, rdf_pointers.recovery_seq_p);
    create_an_rdf_entry (dsc$rdf_lower_memory_limit, rdf_pointers.recovery_seq_p);
    create_an_rdf_entry (dsc$rdf_page_table_modified_bit, rdf_pointers.recovery_seq_p);
    create_an_rdf_entry (dsc$rdf_recovery_image_status, rdf_pointers.recovery_seq_p);
    create_an_rdf_entry (dsc$rdf_register_values, rdf_pointers.recovery_seq_p);
    create_an_rdf_entry (dsc$rdf_ssr_name_bo_in_image, rdf_pointers.recovery_seq_p);
    create_an_rdf_entry (dsc$rdf_system_idled_status, rdf_pointers.recovery_seq_p);

    RESET rdf_pointers.recovery_seq_p;
    mmp$write_modified_pages (rdf_pointers.recovery_seq_p, #SIZE (rdf_pointers.recovery_seq_p^),
          osc$wait, local_status);
    IF NOT local_status.normal THEN
      osp$system_error ('Cannot write modified pages (establish recovery rdf).', ^local_status);
    IFEND;

    { Establish the unused area of the RDF.

    format_the_rdf_area (rdf_pointers.unused_seq_p);

    RESET rdf_pointers.unused_seq_p;
    mmp$write_modified_pages (rdf_pointers.unused_seq_p, #SIZE (rdf_pointers.unused_seq_p^),
          osc$wait, local_status);
    IF NOT local_status.normal THEN
      osp$system_error ('Cannot write modified pages (establish unused rdf).', ^local_status);
    IFEND;

    dsp$close_rdf (rdf_file_sfid, rdf_file_segment);

  PROCEND establish_the_rdf_areas;
?? OLDTITLE ??
?? NEWTITLE := 'format_the_rdf_area', EJECT ??

{ PURPOSE:
{   This procedure formats the specified RDF area.  Each area contains a directory area and a storage area.

  PROCEDURE format_the_rdf_area
    (VAR rdf_seq_p: ^SEQ ( * ));

    VAR
      rdf_directory_entry_p: ^t$rdf_entry,
      rdf_directory_seq_p: ^SEQ ( * ),
      rdf_storage_entry_p: ^t$rdf_entry,
      temp_rdf_seq_p: ^SEQ ( * );

    { Set a temporary pointer to the beginning of the RDF area.

    temp_rdf_seq_p := rdf_seq_p;
    RESET temp_rdf_seq_p;

    { Create the directory for the RDF area.

    NEXT rdf_directory_seq_p: [[REP dsc$rdf_directory_size OF cell]] IN temp_rdf_seq_p;
    RESET rdf_directory_seq_p;

    { Create the directory entry and the storage entry for the RDF area.  The directory entry contains a
    { pointer which points to the next available spot in the directory and the storage entry contains a
    { pointer which points to the next available spot in the storage area.

    NEXT rdf_directory_entry_p IN rdf_directory_seq_p;
    NEXT rdf_storage_entry_p IN rdf_directory_seq_p;
    rdf_directory_entry_p^.name := v$rdf_entries [dsc$rdf_directory].name;
    rdf_directory_entry_p^.data_p := #REL (rdf_directory_seq_p, rdf_seq_p^);
    rdf_storage_entry_p^.name := v$rdf_entries [dsc$rdf_storage_area].name;
    rdf_storage_entry_p^.data_p := #REL (temp_rdf_seq_p, rdf_seq_p^);

  PROCEND format_the_rdf_area;
?? OLDTITLE ??
?? NEWTITLE := 'get_pointer_to_rdf_type', EJECT ??

{ PURPOSE:
{   This procedure returns a pointer to the correct RDF area based on the RDF type.  It also checks to see if
{   the recovery segment, which contains the RDFs, is damaged.  The production RDF and the recovery RDF must
{   be defined.  It is possible, because of back level support, that the other two RDFs are not defined.

  PROCEDURE get_pointer_to_rdf_type
    (    rdf_type: dst$rdf_type;
     VAR rdf_pointers: dst$rdf_pointers;
     VAR rdf_seq_p: ^SEQ ( * ));

    VAR
      rdf_directory_entry_p: ^t$rdf_entry,
      rdf_storage_entry_p: ^t$rdf_entry,
      temp_rdf_seq_p: ^SEQ ( * );

    { Find the pointer to the correct RDF area.

    CASE rdf_type OF
    = dsc$rdf_production =
      rdf_seq_p := rdf_pointers.production_seq_p;
    = dsc$rdf_system_message_buffer =
      rdf_seq_p := rdf_pointers.system_message_buffer_seq_p;
    = dsc$rdf_recovery =
      rdf_seq_p := rdf_pointers.recovery_seq_p;
    ELSE { = dsc$rdf_unused =
      rdf_seq_p := rdf_pointers.unused_seq_p;
    CASEND;

    { Check if the recovery segment is destroyed.  If the RDF area does not have a directory entry and a
    { storage entry then the RDF area is not setup.  At this point, both the production and the recovery
    { areas should be set up.  If they are not set up then the recovery segment is considered destroyed.

    temp_rdf_seq_p := rdf_seq_p;
    RESET temp_rdf_seq_p;
    NEXT rdf_directory_entry_p IN temp_rdf_seq_p;
    NEXT rdf_storage_entry_p IN temp_rdf_seq_p;
    IF (rdf_directory_entry_p^.name <> v$rdf_entries [dsc$rdf_directory].name) OR
          (rdf_storage_entry_p^.name <> v$rdf_entries [dsc$rdf_storage_area].name) THEN
      CASE rdf_type OF
      = dsc$rdf_production =
        osp$system_error ('The production RDF in the recovery segment is destroyed', NIL);
      = dsc$rdf_system_message_buffer =

        { This is an upgrade to 1.2.1.

        format_the_rdf_area (rdf_pointers.system_message_buffer_seq_p);
        create_an_rdf_entry (dsc$rdf_system_messages_buffer, rdf_pointers.system_message_buffer_seq_p);
        create_an_rdf_entry (dsc$rdf_sys_msg_buffer_size, rdf_pointers.system_message_buffer_seq_p);
      = dsc$rdf_recovery =
        osp$system_error ('The recovery RDF in the recovery segment is destroyed', NIL);
      ELSE { = dsc$rdf_unused =

        { This is an upgrade to 1.2.1

        format_the_rdf_area (rdf_pointers.unused_seq_p);
      CASEND;
    IFEND;

  PROCEND get_pointer_to_rdf_type;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$attach_rdf_for_idle', EJECT ??

{ PURPOSE:
{   This procedure attaches the RDF device file so that it can be opened during idle_system when the attach
{   would not be allowed.

  PROCEDURE [XDCL, #GATE] dsp$attach_rdf_for_idle;

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

    { Attach the RDF device file.

    name := dsc$image_file_name;
    dmp$attach_device_file (dmv$system_device_recorded_vsn, name, v$rdf_file_sfid_during_idle, local_status);
    IF NOT local_status.normal THEN
      osp$system_error ('Cannot attach the device file for the RDF area for idle.', ^local_status);
    IFEND;
    v$rdf_sfid_during_idle_exists := TRUE;

  PROCEND dsp$attach_rdf_for_idle;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$build_recovery_segment', EJECT ??

{ PURPOSE:
{   This procedure creates a device file which contains the recovery deadstart file (RDF) area followed by
{   the image file.  The image will consist of a block of memory.  The image is written before the system is
{   loaded into this block, this plus memory outside of this block provides all needed memory from the
{   previously running system needed for system recovery.  The size of the image is determined from an entry
{   in the RDF.  The entire device file is referred to as the image file in most cases. The part of this
{   device file that contains the RDF is referred to as the image table or the RDF.
{
{ NOTE:
{   The creation of the recovery device file is only done on an installation deadstart.

  PROCEDURE [XDCL] dsp$build_recovery_segment;

    VAR
      local_status: ost$status,
      name_stored: ost$name;

    { Set size of the RDF to a multiple of the allocation size.

    dsv$rdf_size := #SIZE (dst$recover_deadstart_files);
    IF (#SIZE (dst$recover_deadstart_files) MOD dmc$deadstart_file_alloc_size) > 0 THEN
      dsv$rdf_size := dsv$rdf_size + dmc$deadstart_file_alloc_size -
            (#SIZE (dst$recover_deadstart_files) MOD dmc$deadstart_file_alloc_size);
    IFEND;

    dsp$create_image_file ((dsv$rdf_size + dsc$image_size), local_status);
    IF NOT local_status.normal THEN
      osp$system_error ('Cannot create image file.', ^local_status);
    IFEND;

    { Create the RDF areas.

    establish_the_rdf_areas;

    dsp$store_integer_in_rdf (dsc$rdf_image_size, dsc$rdf_production, dsc$image_size);
    dsp$store_integer_in_rdf (dsc$rdf_image_table_size, dsc$rdf_production, dsv$rdf_size);
    dsp$store_integer_in_rdf (dsc$rdf_good_image_flag, dsc$rdf_recovery, $INTEGER (FALSE));

    { Set the recovery condition names to 'initialized'.

    name_stored := dsc$image_initialized;
    dsp$store_data_in_rdf (dsc$rdf_recovery_image_status, dsc$rdf_recovery, #SEQ (name_stored));
    dsp$store_data_in_rdf (dsc$rdf_system_idled_status, dsc$rdf_recovery, #SEQ (name_stored));

    dsp$update_image_values_in_ssr;

  PROCEND dsp$build_recovery_segment;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$close_image_file', EJECT ??

{ PURPOSE:
{   This procedure closes the image device file.  All modified pages of the device file are written to mass
{   storage as a result of this procedure.
{
{ NOTE:
{   All errors are considered fatal to system operation.

  PROCEDURE [XDCL] dsp$close_image_file
    (    image_file_sfid: gft$system_file_identifier;
         image_file_segment: mmt$segment_pointer);

    VAR
      file_modified: boolean,
      fmd_modified: boolean,
      status: ost$status;

    { Close and detach the image file.

    dmp$close_file (image_file_segment.seq_pointer, status);
    IF NOT status.normal THEN
      osp$system_error ('Cannot close the image device file.', ^status);
    IFEND;

    dmp$detach_device_file (image_file_sfid, file_modified, fmd_modified, status);
    IF NOT status.normal THEN
      osp$system_error ('Cannot detach the image device file.', ^status);
    IFEND;

  PROCEND dsp$close_image_file;
?? OLDTITLE ??
?? TITLE := 'dsp$close_rdf', EJECT ??

{ PURPOSE:
{   This procedure closes the RDF device file.  All modified pages of the device file are written to mass
{   storage as a result of this procedure.  The RDF cannot be accessed until it is opened again.
{
{ NOTE:
{   All errors are considered fatal to system operation.

  PROCEDURE [XDCL, #GATE] dsp$close_rdf
    (    rdf_file_sfid: gft$system_file_identifier;
         rdf_file_segment: mmt$segment_pointer);

    VAR
      file_modified: boolean,
      fmd_modified: boolean,
      local_status: ost$status;

    { Close and detach the RDF file.

    dmp$close_file (rdf_file_segment.seq_pointer, local_status);
    IF NOT local_status.normal THEN
      osp$system_error ('Cannot close the device file for the RDF area.', ^local_status);
    IFEND;

    IF NOT v$rdf_sfid_during_idle_exists THEN
      dmp$detach_device_file (rdf_file_sfid, file_modified, fmd_modified, local_status);
      IF NOT local_status.normal THEN
        osp$system_error ('Cannot detach the device file for the RDF area.', ^local_status);
      IFEND;
    IFEND;

  PROCEND dsp$close_rdf;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$detach_rdf_after_resume', EJECT ??

{ PURPOSE:
{   This procedure detaches the RDF device file that was attached for the idle_system now that the system
{   is resumed.

  PROCEDURE [XDCL, #GATE] dsp$detach_rdf_after_resume;

    VAR
      file_modified: boolean,
      fmd_modified: boolean,
      local_status: ost$status;

    { Detach the RDF device file.

    dmp$detach_device_file (v$rdf_file_sfid_during_idle, file_modified, fmd_modified, local_status);
    IF NOT local_status.normal THEN
      osp$system_error ('Cannot detach the device file for the RDF area after resume.', ^local_status);
    IFEND;
    v$rdf_sfid_during_idle_exists := FALSE;

  PROCEND dsp$detach_rdf_after_resume;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$determine_if_entry_in_rdf', EJECT ??

{ PURPOSE:
{   This procedure determines if the given RDF entry is in the specified RDF area.

  PROCEDURE [XDCL] dsp$determine_if_entry_in_rdf
    (    rdf_name: dst$rdf_entries;
         rdf_type: dst$rdf_type;
     VAR rdf_entry_exists: boolean);

    VAR
      next_avail_directory_entry_p: ^t$rdf_entry,
      rdf_directory_entry_p: ^t$rdf_entry,
      rdf_directory_seq_p: ^SEQ ( * ),
      rdf_entry_p: ^t$rdf_entry,
      rdf_file_segment: mmt$segment_pointer,
      rdf_file_sfid: gft$system_file_identifier,
      rdf_seq_p: ^SEQ ( * ),
      rdf_pointers: dst$rdf_pointers,
      temp_rdf_seq_p: ^SEQ ( * );

    dsp$open_rdf (rdf_file_sfid, rdf_file_segment, rdf_pointers);

    { Retrieve the pointer to the correct RDF area.

    get_pointer_to_rdf_type (rdf_type, rdf_pointers, rdf_seq_p);

    { Retrieve the directory entry to the RDF area.

    temp_rdf_seq_p := rdf_seq_p;
    RESET temp_rdf_seq_p;
    NEXT rdf_directory_entry_p IN temp_rdf_seq_p;

    { Search the RDF directory to determine whether the specified entry exists.

    rdf_directory_seq_p := #PTR (rdf_directory_entry_p^.data_p, rdf_seq_p^);
    NEXT next_avail_directory_entry_p IN rdf_directory_seq_p;
    RESET temp_rdf_seq_p;
    NEXT rdf_entry_p IN temp_rdf_seq_p;
    rdf_entry_exists := FALSE;
    WHILE (rdf_entry_p <> next_avail_directory_entry_p) AND (NOT rdf_entry_exists) DO
      rdf_entry_exists := (rdf_entry_p^.name = v$rdf_entries [rdf_name].name);
      NEXT rdf_entry_p IN temp_rdf_seq_p;
    WHILEND;

    dsp$close_rdf (rdf_file_sfid, rdf_file_segment);

  PROCEND dsp$determine_if_entry_in_rdf;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$get_data_from_rdf', EJECT ??

{ PURPOSE:
{   This procedure retrieves data from the specified RDF area.  The caller to this procedure should set up a
{   sequence pointer to their data variable, call this procedure with the sequence pointer and then access
{   their data variable directly.
{     EXAMPLE:  data_variable_seq_p := #SEQ (data_variable);
{               dsp$get_data_from_rdf (rdf_name, rdf_type, data_variable_seq_p);
{               IF data_variable = 'xxx' THEN
{                   etc.

  PROCEDURE [XDCL, #GATE] dsp$get_data_from_rdf
    (    rdf_name: dst$rdf_entries;
         rdf_type: dst$rdf_type;
     VAR rdf_value_p: ^SEQ ( * ));

    VAR
      data_seq_p: ^SEQ ( * ),
      rdf_entry_seq_p: ^SEQ ( * ),
      rdf_file_segment: mmt$segment_pointer,
      rdf_file_sfid: gft$system_file_identifier,
      rdf_pointers: dst$rdf_pointers;

    dsp$open_rdf (rdf_file_sfid, rdf_file_segment, rdf_pointers);

    { Retrieve the sequence pointer to the requested data.

    dsp$get_rdf_entry_seq_pointer (rdf_name, rdf_type, rdf_pointers, rdf_entry_seq_p);
    RESET rdf_entry_seq_p;

    { Move the data from the RDF area to the parameter sequence pointer.

    IF #SIZE (rdf_value_p^) > #SIZE (rdf_entry_seq_p^) THEN
      NEXT data_seq_p: [[REP #SIZE (rdf_entry_seq_p^) OF cell]] IN rdf_entry_seq_p;
    ELSE
      NEXT data_seq_p: [[REP #SIZE (rdf_value_p^) OF cell]] IN rdf_entry_seq_p;
    IFEND;
    rdf_value_p^ := data_seq_p^;

    dsp$close_rdf (rdf_file_sfid, rdf_file_segment);

  PROCEND dsp$get_data_from_rdf;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$get_integer_from_rdf', EJECT ??

{ PURPOSE:
{   This procedure retrieves an integer value from the specified RDF area.

  PROCEDURE [XDCL, #GATE] dsp$get_integer_from_rdf
    (    rdf_name: dst$rdf_entries;
         rdf_type: dst$rdf_type;
     VAR rdf_value: integer);

    VAR
      rdf_value_seq_p: ^SEQ ( * );

    rdf_value_seq_p := #SEQ (rdf_value);
    dsp$get_data_from_rdf (rdf_name, rdf_type, rdf_value_seq_p);

  PROCEND dsp$get_integer_from_rdf;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$get_rdf_entry_seq_pointer', EJECT ??

{ PURPOSE:
{   This procedure retrieves a pointer to the entry in the specified RDF area.  If the entry does not exists,
{   this procedure will create the entry.  This procedure expects the caller to open and close the RDF.

  PROCEDURE [XDCL, #GATE] dsp$get_rdf_entry_seq_pointer
    (    rdf_name: dst$rdf_entries;
         rdf_type: dst$rdf_type;
     VAR rdf_pointers: dst$rdf_pointers;
     VAR rdf_entry_seq_p: ^SEQ ( * ));

    VAR
      local_status: ost$status,
      next_avail_directory_entry_p: ^t$rdf_entry,
      rdf_entry_exists: boolean,
      rdf_directory_entry_p: ^t$rdf_entry,
      rdf_directory_seq_p: ^SEQ ( * ),
      rdf_entry_p: ^t$rdf_entry,
      rdf_seq_p: ^SEQ ( * ),
      temp_rdf_seq_p: ^SEQ ( * );

    { Retrieve the pointer to the correct RDF area.

    get_pointer_to_rdf_type (rdf_type, rdf_pointers, rdf_seq_p);

    { Retrieve the directory entry of the RDF area.

    temp_rdf_seq_p := rdf_seq_p;
    RESET temp_rdf_seq_p;
    NEXT rdf_directory_entry_p IN temp_rdf_seq_p;

    { Search the RDF directory to determine whether the specified entry exists.

    rdf_directory_seq_p := #PTR (rdf_directory_entry_p^.data_p, rdf_seq_p^);
    NEXT next_avail_directory_entry_p IN rdf_directory_seq_p;
    RESET temp_rdf_seq_p;
    NEXT rdf_entry_p IN temp_rdf_seq_p;
    rdf_entry_exists := FALSE;
    WHILE (rdf_entry_p <> next_avail_directory_entry_p) AND (NOT rdf_entry_exists) DO
      rdf_entry_exists := (rdf_entry_p^.name = v$rdf_entries [rdf_name].name);
      NEXT rdf_entry_p IN temp_rdf_seq_p;
    WHILEND;
    IF NOT rdf_entry_exists THEN
      create_an_rdf_entry (rdf_name, rdf_seq_p);
      RESET rdf_seq_p;
      mmp$write_modified_pages (rdf_seq_p, #SIZE (rdf_seq_p^), osc$wait, local_status);
      IF NOT local_status.normal THEN
        osp$system_error ('Cannot write modified pages (dsp$get_rdf_entry_seq_pointer)', ^local_status);
      IFEND;
    IFEND;

    { Retrieve the sequence pointer to the directory.

    rdf_directory_seq_p := #PTR (rdf_directory_entry_p^.data_p, rdf_seq_p^);

    { Find the correct entry in the directory.

    RESET rdf_directory_seq_p;
    REPEAT
      NEXT rdf_entry_p IN rdf_directory_seq_p;
    UNTIL rdf_entry_p^.name = v$rdf_entries [rdf_name].name;

    { Retrieve the sequence pointer to the storage area for the entry.

    rdf_entry_seq_p := #PTR (rdf_entry_p^.data_p, rdf_seq_p^);

  PROCEND dsp$get_rdf_entry_seq_pointer;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$open_image_file', EJECT ??

{ PURPOSE:
{   This procedure opens the image device file and allows access to the file.
{
{ NOTE:
{   All errors are considered fatal to system operation.

  PROCEDURE [XDCL] dsp$open_image_file
    (VAR image_file_sfid: gft$system_file_identifier;
     VAR image_file_segment: mmt$segment_pointer;
     VAR image_file_p: ^SEQ ( * ));

    VAR
      ignore_rdf_part_p: ^SEQ ( * ),
      local_status: ost$status,
      name: ost$name,
      rdf_size: integer;

    { Attach the image file.

    name := dsc$image_file_name;
    dmp$attach_device_file (dmv$system_device_recorded_vsn, name, image_file_sfid, local_status);
    IF NOT local_status.normal THEN
      osp$system_error ('Cannot attach image device file.', ^local_status);
    IFEND;

    { Make a segment for the image file.

    image_file_segment.kind := mmc$sequence_pointer;
    dmp$open_file (image_file_sfid, osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend, mmc$as_random,
          image_file_segment, local_status);
    IF NOT local_status.normal THEN
      osp$system_error ('Cannot open the image device file.', ^local_status);
    IFEND;

    RESET image_file_segment.seq_pointer;

    { Get size of the RDF and save in global variable if not already done.

    IF dsv$rdf_size = 0 THEN
      dsp$get_integer_from_rdf (dsc$rdf_image_table_size, dsc$rdf_production, rdf_size);
      dsv$rdf_size := rdf_size;
    IFEND;

    { Skip over the RDF at the beginning of the device file.

    NEXT ignore_rdf_part_p: [[REP dsv$rdf_size OF cell]] IN image_file_segment.seq_pointer;

    { Retrieve a pointer to the image file.

    NEXT image_file_p: [[REP 7fffffff(16) - dsv$rdf_size OF cell]] IN image_file_segment.seq_pointer;
    RESET image_file_p;

  PROCEND dsp$open_image_file;
?? OLDTITLE ??
?? TITLE := 'dsp$open_rdf', EJECT ??

{ PURPOSE:
{   This procedure opens the RDF device file and initializes pointers to the separate RDF areas.
{
{ NOTE:
{   All errors are considered fatal to system operation.

  PROCEDURE [XDCL, #GATE] dsp$open_rdf
    (VAR rdf_file_sfid: gft$system_file_identifier;
     VAR rdf_file_segment: mmt$segment_pointer;
     VAR rdf_pointers: dst$rdf_pointers);

    VAR
      local_status: ost$status,
      name: ost$name,
      rdf_p: ^dst$recover_deadstart_files;

    { Attach the RDF device file.

    IF v$rdf_sfid_during_idle_exists THEN
      rdf_file_sfid := v$rdf_file_sfid_during_idle;
    ELSE
      name := dsc$image_file_name;
      dmp$attach_device_file (dmv$system_device_recorded_vsn, name, rdf_file_sfid, local_status);
      IF NOT local_status.normal THEN
        osp$system_error ('Cannot attach the device file for the RDF area.', ^local_status);
      IFEND;
    IFEND;

    { Make a segment for the image file.

    rdf_file_segment.kind := mmc$sequence_pointer;
    dmp$open_file (rdf_file_sfid, osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend, mmc$as_random,
          rdf_file_segment, local_status);
    IF NOT local_status.normal THEN
      osp$system_error ('Cannot open the device file for the RDF area.', ^local_status);
    IFEND;

    { Setup the rdf pointers.

    RESET rdf_file_segment.seq_pointer;
    NEXT rdf_p IN rdf_file_segment.seq_pointer;
    rdf_pointers.production_seq_p := ^rdf_p^.production;
    rdf_pointers.system_message_buffer_seq_p := ^rdf_p^.system_message_buffer;
    rdf_pointers.recovery_seq_p := ^rdf_p^.recovery;
    rdf_pointers.unused_seq_p := ^rdf_p^.unused;

  PROCEND dsp$open_rdf;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$store_data_in_rdf', EJECT ??

{ PURPOSE:
{   This procedure stores data in the specified RDF area.  The caller of this procedure should use the #SEQ
{   function so that they do not have to set up a sequence.
{     EXAMPLE:  dsp$store_data_in_rdf (rdf_name, rdf_type, #SEQ (data_variable));
{   After the procedure call the data_variable can be access directly.

  PROCEDURE [XDCL, #GATE] dsp$store_data_in_rdf
    (    rdf_name: dst$rdf_entries;
         rdf_type: dst$rdf_type;
         rdf_value_p: ^SEQ ( * ));

    VAR
      data_seq_p: ^SEQ ( * ),
      local_status: ost$status,
      rdf_entry_seq_p: ^SEQ ( * ),
      rdf_file_segment: mmt$segment_pointer,
      rdf_file_sfid: gft$system_file_identifier,
      rdf_pointers: dst$rdf_pointers;

    dsp$open_rdf (rdf_file_sfid, rdf_file_segment, rdf_pointers);

    { Retrieve the sequence pointer to the data area.

    dsp$get_rdf_entry_seq_pointer (rdf_name, rdf_type, rdf_pointers, rdf_entry_seq_p);

    { Move the data from the parameter sequence pointer to the rdf area.

    RESET rdf_entry_seq_p;
    IF #SIZE (rdf_value_p^) > #SIZE (rdf_entry_seq_p^) THEN
      osp$system_error ('Trying to store too large a data item in the rdf area', NIL);
    IFEND;
    NEXT data_seq_p: [[REP #SIZE (rdf_value_p^) OF cell]] IN rdf_entry_seq_p;
    data_seq_p^ := rdf_value_p^;

    RESET rdf_entry_seq_p;
    mmp$write_modified_pages (rdf_entry_seq_p, #SIZE (rdf_entry_seq_p^), osc$wait, local_status);
    IF NOT local_status.normal THEN
      osp$system_error ('Cannot write modified pages (dsp$store_data_in_rdf).', ^local_status);
    IFEND;

    dsp$close_rdf (rdf_file_sfid, rdf_file_segment);

  PROCEND dsp$store_data_in_rdf;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$store_integer_in_rdf', EJECT ??

{ PURPOSE:
{   This procedure stores an integer value in the specified RDF area.

  PROCEDURE [XDCL, #GATE] dsp$store_integer_in_rdf
    (    rdf_name: dst$rdf_entries;
         rdf_type: dst$rdf_type;
         rdf_value: integer);

    dsp$store_data_in_rdf (rdf_name, rdf_type, #SEQ (rdf_value));

  PROCEND dsp$store_integer_in_rdf;
MODEND dsm$manage_rdf_and_image_file;
