*copyc osd$default_pragmats
?? TITLE := '  NOS/VE : Resource Manager' ??
MODULE rmm$resource_manager;
{
{        PURPOSE:  The purpose of this module is to be the 2dd/user ring
{                  screen for those resource manager routines which
{                  accept a file reference as input.  This screen is needed
{                  in order to call clp$evaluate_file_reference in the user
{                  ring so that a file reference containing a user defined
{                  function can be evaluated.
{
?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*IF NOT $true(osv$unix)
*copyc fsc$local
*IFEND
*copyc fst$file_reference
*copyc rme$class_validation_errors
*IF NOT $true(osv$unix)
*copyc fst$goi_object_information
*copyc rme$request_mass_storage
*copyc rme$request_tape
*copyc rmt$tape_class
*copyc rmt$write_ring
*IFEND
*copyc rmt$device_classes
?? POP ??
*IF NOT $true(osv$unix)
*copyc bap$create_file
*copyc bap$get_device_class
*copyc bap$process_pt_request
*copyc bap$set_evaluated_file_abnormal
*copyc bap$set_evaluated_file_abnormal
*copyc clp$evaluate_file_reference
*copyc clp$get_variable_value
*copyc fsp$create_file
*copyc fsp$evaluate_file_for_creation
*copyc fsp$evaluate_file_reference
*copyc fsp$path_element
*copyc osp$enforce_exception_policies
*copyc osp$file_access_condition
*copyc osp$set_status_abnormal
*copyc osv$initial_exception_context
*copyc pfp$r3_get_object_information
*copyc rmp$r3_request_null_device
*copyc rmp$r3_request_terminal
*IFEND
*copyc osp$set_status_abnormal
*IF NOT $true(osv$unix)
*copyc oss$job_paged_literal
*ELSE
*copyc clp$convert_str_to_path_handle
*copyc fsp$close_file
*copyc fsp_open
*copyc osp$set_status_from_errno
*copyc rmp_isatty
*IFEND
*IF NOT $true(osv$unix)
?? TITLE := 'Global Declarations Declared by This Module', EJECT ??

  CONST
    command_file_reference_allowed = TRUE;

  VAR
    default_information_request: [oss$job_paged_literal, READ] fst$goi_information_request :=
          [[fsc$specific_depth, 1], [fsc$goi_cycle_identity]],
    rmv$null_device_set: [XDCL, READ, oss$job_paged_literal] rmt$device_classes :=
          $rmt$device_classes [rmc$connected_file_device, rmc$log_device,
          rmc$interstate_link_device, rmc$local_queue_device, rmc$pipeline_device],
    rmv$valid_vsn_characters: [XDCL, READ, oss$job_paged_literal] set of char :=
          ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
           'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
           'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1',
           '2', '3', '4', '5', '6', '7', '8', '9', ' ', '!', '"', '%', '&', '''', '(', ')', '*', '+',
           ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '_', '$', '#', '@'];
*IFEND

?? TITLE := '  [XDCL, #GATE] rmp$get_device_class', EJECT ??
*copyc RMH$GET_DEVICE_CLASS
?? EJECT ??

  PROCEDURE [XDCL, #GATE] rmp$get_device_class
    (    file: fst$file_reference;
*IF NOT $true(osv$unix)
     VAR device_assigned: boolean;
*IFEND
     VAR device_class: rmt$device_class;
     VAR status: ost$status);

    VAR
      evaluated_file_reference: fst$evaluated_file_reference,
*IF NOT $true(osv$unix)
      context: ^ost$ecp_exception_context,
      information_request: fst$goi_information_request,
      local_status: ost$status,
      object_information_p: ^fst$goi_object_information,
      work_area_p: ^SEQ ( * );
*ELSE
      access_mode: amt_access_mode,
      errno: ost_c_integer,
      file_identifier: amt$file_identifier,
      file_reference: fst$path,
      ignore_path_handle_name: fst$path,
      open_mode: amt_open_mode,
      stat: integer,
      syserrlist_message: string (256),
      terminal_device: ost_c_boolean;
*IFEND

    status.normal := TRUE;
*IF NOT $true(osv$unix)
    context := NIL;
    device_assigned := FALSE;
    device_class := rmc$mass_storage_device;

    fsp$evaluate_file_reference (file, command_file_reference_allowed, evaluated_file_reference, status);
    IF status.normal AND ((evaluated_file_reference.number_of_path_elements < 3) AND
          ((fsp$path_element (^evaluated_file_reference, 1)^ <> fsc$local) OR
          (evaluated_file_reference.number_of_path_elements < 2))) THEN
      bap$set_evaluated_file_abnormal (evaluated_file_reference, pfe$name_not_permanent_file,
            'RMP$GET_DEVICE_CLASS', '', status);
    IFEND;
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF fsp$path_element (^evaluated_file_reference, 1)^ = fsc$local THEN
      bap$get_device_class (evaluated_file_reference.path_handle_info.path_handle, device_assigned,
            device_class, local_status);
      IF device_class IN rmv$null_device_set THEN
        device_class := rmc$null_device;
      IFEND;
    ELSE
      PUSH work_area_p: [[REP #SIZE (fst$goi_object_information) + fsc$max_path_size +
            #SIZE (fst$goi_object) OF cell]];
      information_request := default_information_request;

    /get_device_class/
      REPEAT
        RESET work_area_p;
        pfp$r3_get_object_information (evaluated_file_reference, information_request, NIL,
              work_area_p, local_status);
        IF local_status.normal THEN
          RESET work_area_p;
          NEXT object_information_p IN work_area_p;
          IF object_information_p <> NIL THEN
            IF object_information_p^.object <> NIL THEN
              IF object_information_p^.object^.object_type = fsc$goi_cycle_object THEN
                device_assigned := TRUE;
                IF object_information_p^.object^.cycle_device_class IN rmv$null_device_set THEN
                  device_class := rmc$null_device;
                ELSE
                  device_class := object_information_p^.object^.cycle_device_class;
                IFEND;
              ELSE
                EXIT /get_device_class/;
              IFEND;
            ELSE
              bap$set_evaluated_file_abnormal (evaluated_file_reference, pfe$name_not_permanent_file,
                    'RMP$GET_DEVICE_CLASS', '', status);
            IFEND;
          IFEND;
        ELSEIF osp$file_access_condition (local_status) THEN
          IF context = NIL THEN
            PUSH context;
            context^ := osv$initial_exception_context;
            context^.file.selector := osc$ecp_evaluated_file_ref;
            context^.file.evaluated_file_reference := evaluated_file_reference;
          IFEND;
          context^.condition_status := local_status;
          osp$enforce_exception_policies (context^);
          local_status := context^.condition_status;
        IFEND;
      UNTIL local_status.normal OR (NOT osp$file_access_condition (local_status)) OR (NOT context^.wait);
    IFEND;

*ELSE
    file_reference := file;
    open_mode := amc_o_rdonly;
    access_mode.delay := 0;
    access_mode.append := 0;
    access_mode.sync := 0;
    access_mode.creat := 0;
    access_mode.trunc := 0;
    access_mode.excl := 0;
    errno := 0;
    syserrlist_message := ' ';
    stat := 0;

    clp$convert_str_to_path_handle (file_reference, {delete_allowed} TRUE, {resolve_path} TRUE,
          {open_position} FALSE, ignore_path_handle_name, evaluated_file_reference, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF evaluated_file_reference.command_file_path.found THEN
      device_class := rmc$terminal_device;
    ELSE
      fsp_open (file_reference, open_mode, access_mode, file_identifier, errno,
            syserrlist_message, stat);
      IF stat = 0 THEN
        rmp_isatty (file_identifier, terminal_device);
        CASE terminal_device OF
        = 0 =
          device_class := rmc$mass_storage_device;
        ELSE
          device_class := rmc$terminal_device;
        CASEND;
        fsp$close_file (file_identifier, status);
      ELSE
        osp$set_status_from_errno ('rmp$get_device_class', errno, syserrlist_message, status);
      IFEND;
    IFEND;
*IFEND

  PROCEND rmp$get_device_class;

*IF NOT $true(osv$unix)
?? TITLE := '  [XDCL, #GATE] rmp$request_mass_storage', EJECT ??
*copy rmh$request_mass_storage
?? EJECT ??

  PROCEDURE [XDCL, #GATE] rmp$request_mass_storage
    (    file: fst$file_reference;
         allocation_size: rmt$allocation_size;
         estimated_file_size: amt$file_byte_address;
         file_class: rmt$mass_storage_class;
         initial_volume: rmt$recorded_vsn;
         volume_overflow_allowed: boolean;
     VAR status: ost$status);

    VAR
      device_attributes: array [1 .. 5] of fst$device_attribute,
      ignore_status: ost$status,
      resolved_path: fst$path;

    status.normal := TRUE;

    device_attributes [1].selector := fsc$allocation_size;
    device_attributes [1].allocation_size := allocation_size;
    device_attributes [2].selector := fsc$estimated_file_size;
    device_attributes [2].estimated_file_size := estimated_file_size;
    device_attributes [3].selector := fsc$mass_storage_class;
    device_attributes [3].mass_storage_class := file_class;
    device_attributes [4].selector := fsc$initial_volume;
    device_attributes [4].initial_volume := initial_volume;
    device_attributes [5].selector := fsc$volume_overflow_allowed;
    device_attributes [5].volume_overflow_allowed := volume_overflow_allowed;

    fsp$create_file (file, {attachment_options} NIL, {cycle_attributes} NIL, ^device_attributes,
          {file_attributes} NIL, resolved_path, status);

  PROCEND rmp$request_mass_storage;

?? TITLE := '  [XDCL, #GATE] rmp$request_null_device', EJECT ??

  PROCEDURE [XDCL, #GATE] rmp$request_null_device
    (    file: fst$file_reference;
     VAR status: ost$status);

    VAR
      evaluated_file_reference: fst$evaluated_file_reference;

    status.normal := TRUE;
    fsp$evaluate_file_for_creation (file, NOT command_file_reference_allowed,
          evaluated_file_reference, status);

    IF status.normal THEN
      rmp$r3_request_null_device (evaluated_file_reference, status);
    IFEND;

  PROCEND rmp$request_null_device;

?? TITLE := '  [XDCL, #GATE] rmp$request_tape', EJECT ??
*copyc RMH$REQUEST_TAPE

  PROCEDURE [XDCL, #GATE] rmp$request_tape
    (    file: fst$file_reference;
         class: rmt$tape_class;
         density: rmt$density;
         write_ring: rmt$write_ring;
         volume_list: rmt$volume_list;
     VAR status: ost$status);

    VAR
      attachment_options: ^fst$attachment_options,
      attribute_count: integer,
      device_attributes: ^fst$device_attributes,
      evaluated_file_reference: fst$evaluated_file_reference,
      family_name: ost$name,
      ignore_process_pt_results: bat$process_pt_results,
      p_data_value: ^clt$data_value,
      resolved_path: fst$path;

    CONST
      max_attachment_options = 1,
      max_device_attributes = 5;

    fsp$evaluate_file_for_creation (file, NOT command_file_reference_allowed,
          evaluated_file_reference, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF (class < rmc$mt9) OR (class > rmc$mt18) THEN
      bap$set_evaluated_file_abnormal (evaluated_file_reference, rme$improper_class_value,
            'RMP$REQUEST_TAPE', '', status);
      RETURN;
    IFEND;

    IF (density < rmc$800) OR (density > rmc$38000) THEN
      osp$set_status_abnormal (rmc$resource_management_id, rme$improper_density_value, '', status);
      RETURN;
    IFEND;

    IF (write_ring < LOWERVALUE (rmt$write_ring)) OR (write_ring > UPPERVALUE (rmt$write_ring)) THEN
      bap$set_evaluated_file_abnormal (evaluated_file_reference, rme$improper_write_ring_value,
            'RMP$REQUEST_TAPE', '', status);
      RETURN;
    IFEND;

    PUSH attachment_options: [1 .. max_attachment_options];
    attribute_count := 0;

    attribute_count := attribute_count + 1;
    attachment_options^ [attribute_count].selector := fsc$access_and_share_modes;
    attachment_options^ [attribute_count].access_modes.selector := fsc$specific_access_modes;
    IF write_ring = rmc$write_ring THEN
      attachment_options^ [attribute_count].access_modes.value :=
            $fst$file_access_options [fsc$read, fsc$shorten, fsc$append, fsc$modify];
    ELSE
      attachment_options^ [attribute_count].access_modes.value :=
            $fst$file_access_options [fsc$read];
    IFEND;
    attachment_options^ [attribute_count].share_modes.selector := fsc$specific_share_modes;
    attachment_options^ [attribute_count].share_modes.value := $fst$file_access_options [];

    PUSH device_attributes: [1 .. max_device_attributes];
    attribute_count := 0;

    attribute_count := attribute_count + 1;
    device_attributes^ [attribute_count].selector := fsc$device_class;
    device_attributes^ [attribute_count].device_class := fsc$magnetic_tape_device;

    attribute_count := attribute_count + 1;
    device_attributes^ [attribute_count].selector := fsc$removable_media_group;

    PUSH p_data_value;
    clp$get_variable_value ('OSD$REQMT_REMOVABLE_MEDIA_GROUP', p_data_value, status);
    IF status.normal AND (p_data_value^.kind = clc$name) THEN
      device_attributes^ [attribute_count].removable_media_group := p_data_value^.name_value;
    ELSE
      device_attributes^ [attribute_count].removable_media_group := osc$null_name;
    IFEND;

    attribute_count := attribute_count + 1;
    device_attributes^ [attribute_count].selector := fsc$density;
    device_attributes^ [attribute_count].density := density;

    attribute_count := attribute_count + 1;
    device_attributes^ [attribute_count].selector := fsc$volume_overflow_allowed;
    device_attributes^ [attribute_count].volume_overflow_allowed := TRUE;

    attribute_count := attribute_count + 1;
    device_attributes^ [attribute_count].selector := fsc$volume_list;
    device_attributes^ [attribute_count].volume_list := ^volume_list;

    bap$create_file (attachment_options, {cycle_attributes} NIL, {file_attributes} NIL,
          device_attributes, evaluated_file_reference, resolved_path, status);

  PROCEND rmp$request_tape;

?? TITLE := '  [XDCL, #GATE] rmp$request_terminal', EJECT ??

  PROCEDURE [XDCL, #GATE] rmp$request_terminal
    (    file: fst$file_reference;
         terminal_file_name: ^fst$file_reference;
         term_conn_attributes: ift$connection_attributes;
     VAR status: ost$status);

    VAR
      cycle_number_specified: boolean,
      evaluated_file_reference: fst$evaluated_file_reference,
      ignore_process_pt_results: bat$process_pt_results;

    status.normal := TRUE;

{
{ Request Terminal calls clp$evaluate_file_reference & bap$process_pt_request
{ rather than fsp$evaluate_file_reference because it is necessary to
{ record the path so that rmp$r3_request_terminal can compare the
{ requested file with the prompt file (if specified) to see if they are the
{ same.
{
    clp$evaluate_file_reference (file, $clt$file_ref_parsing_options
            [clc$use_$local_as_working_cat], {resolve_cycle_number=} FALSE,
            evaluated_file_reference, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    cycle_number_specified := evaluated_file_reference.cycle_reference.specification = fsc$cycle_number;

{ Return permanent file path if alias and resolve if registered.
    IF (fsp$path_element (^evaluated_file_reference, 1) ^ = fsc$local) THEN
      bap$process_pt_request ($bat$process_pt_work_list [bac$record_path,
            bac$resolve_path], osc$null_name, evaluated_file_reference,
            ignore_process_pt_results, status);
    IFEND;

    IF status.normal THEN

{ The following IF statement is necessary to prevent a currently attached file from being resolved to the next
{ cycle (in fmp$request_terminal), if a specific cycle was requested.

      IF cycle_number_specified THEN
        evaluated_file_reference.path_handle_info.path_handle_present := FALSE;
      IFEND;
      rmp$r3_request_terminal (terminal_file_name, term_conn_attributes,
            evaluated_file_reference, status);
    IFEND;

  PROCEND rmp$request_terminal;
*IFEND

MODEND rmm$resource_manager;
