?? NEWTITLE := '  NOS/VE Set Management ' ??
MODULE stm$add_member;
?? RIGHT := 110 ??

{  PURPOSE:
{    This module provides the compilation unit for the stp$add_member_vol_to_set
{    request.
{
{  DESIGN:
{    Readers desiring understanding of the design should look at the entry point
{    procedure stp$add_member_vol_to_set.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc cle$ecc_lexical
*copyc ose$heap_full_exceptions
*copyc ste$error_condition_codes
*copyc dmt$active_volume_table_index
*copyc gft$system_file_identifier
*copyc ost$status
*copyc rmt$recorded_vsn
?? POP ??
*copyc clp$validate_name
*copyc osp$append_status_parameter
*copyc osp$set_status_abnormal
*copyc pmp$exit
*copyc pmp$get_user_identification
*copyc stp$attach_vst
*copyc stp$clear_exclusive_access
*copyc stp$detach_vst
*copyc stp$dm_mount_volume
*copyc stp$request_dm_volume_info
*copyc stp$ring2_add_member
*copyc stp$search_ast_by_set
*copyc stp$search_mel_for_vol
*copyc stp$set_exclusive_access
*copyc stp$validate_owner
*copyc stp$validate_recorded_vsn
*copyc stv$system_set_name
?? OLDTITLE ??
?? NEWTITLE := '  [XDCL, #GATE] stp$add_member_vol_to_set ', EJECT ??
*copyc sth$add_member_vol_to_set

  PROCEDURE [XDCL, #GATE] stp$add_member_vol_to_set
    (    c_set_name: stt$set_name;
         requested_member_vol: rmt$recorded_vsn;
     VAR status: ost$status);

    VAR
      add_member_status: ost$status,
      ast_entry: stt$active_set_entry,
      ast_index: stt$ast_index,
      converted_master_vol: rmt$recorded_vsn,
      converted_requested_member_vol: rmt$recorded_vsn,
      converted_set_name: stt$set_name,
      member_internal_vsn: dmt$internal_vsn,
      set_name: stt$set_name,
      master_vol: rmt$recorded_vsn,
      set_found_in_ast: boolean,
      members_avt_index: dmt$active_volume_table_index;

    add_member_status.normal := TRUE;
    set_name := c_set_name;

{Remain compatible with current system - default to current system set
    IF set_name = 'UNSPECIFIED' THEN
      set_name := stv$system_set_name;
    IFEND;

{Remain compatible - determine set master
    stp$search_ast_by_set (set_name, ast_entry, ast_index, set_found_in_ast);
    IF set_found_in_ast THEN
      IF ast_entry.master_ever_up THEN
        master_vol := ast_entry.master_vsn;
      ELSE
        osp$set_status_abnormal (stc$set_management_id, ste$master_not_active, master_vol, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, set_name, status);
        RETURN; {----->
      IFEND;
    ELSE
      osp$set_status_abnormal (stc$set_management_id, ste$set_not_active, set_name, status);
      osp$append_status_parameter (osc$status_parameter_delimiter, set_name, status);
      RETURN; {----->
    IFEND;

    validate_add_member_params (set_name, requested_member_vol, master_vol, converted_set_name,
          converted_requested_member_vol, converted_master_vol, add_member_status);
    IF add_member_status.normal THEN
      stp$set_exclusive_access;
      verify_add_vol_exec (converted_set_name, converted_requested_member_vol, converted_master_vol,
            member_internal_vsn, members_avt_index, ast_entry, ast_index, add_member_status);
      IF add_member_status.normal THEN
        stp$ring2_add_member (converted_set_name, converted_requested_member_vol, member_internal_vsn,
              converted_master_vol, members_avt_index, ast_entry, ast_index, add_member_status);
      IFEND;
      stp$clear_exclusive_access;
    IFEND;
    status := add_member_status;
    IF (NOT status.normal) AND (status.condition = ose$mainframe_pageable_full) THEN
      pmp$exit (status);
    IFEND;

  PROCEND stp$add_member_vol_to_set;
?? OLDTITLE ??
?? NEWTITLE := '  validate_add_member', EJECT ??

  PROCEDURE validate_add_member
    (    set_name: stt$set_name;
         requested_member_vol: rmt$recorded_vsn;
         master_vol: rmt$recorded_vsn;
     VAR ast_entry: stt$active_set_entry;
     VAR ast_index: stt$ast_index;
     VAR member_internal_vsn: dmt$internal_vsn;
     VAR members_avt_index: dmt$active_volume_table_index;
     VAR status: ost$status);

{  PURPOSE:
{    This procedure verifies that that the requested user, can perform the
{    add member request, and that there is no conflict (e.g. the member
{    is already on a set.) to prevent adding the member to the set.
{    First the condition of the member is verified via a call to
{    verify_member, then the active set table is looked at.
{    CONDITIONS:
{      ste$wrong_master
{      ste$set_not_master_owner
{      ste$master_not_active
{      ste$member_vol_in_set
{      ste$job_not_member_owner
{      ste$member_not_active

    VAR
      master_avt_index: dmt$active_volume_table_index,
      master_internal_vsn: dmt$internal_vsn,
      master_vol_found: boolean,
      master_vol_owner: ost$user_identification,
      mel_index: stt$mel_index,
      member_entry: stt$member_entry,
      member_found_in_ast: boolean,
      member_owner: ost$user_identification,
      set_found_in_ast: boolean;

    status.normal := TRUE;
    verify_member (requested_member_vol, member_internal_vsn, members_avt_index, member_owner, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    stp$search_ast_by_set (set_name, ast_entry, ast_index, set_found_in_ast);
    IF NOT set_found_in_ast THEN
      stp$request_dm_volume_info (master_vol, master_internal_vsn, master_vol_owner, master_avt_index,
            master_vol_found);
      IF master_vol_found THEN
        {
        { The set was not found active, but the master volume, as given by
        { the requestor, was found, thus the user specified the wrong master
        { for the given set, or the wrong set for the given master.
        {
        osp$set_status_abnormal (stc$set_management_id, ste$wrong_master, master_vol, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, set_name, status);
        RETURN; {----->
      ELSE
        {
        { Neither the set or the master volume was found active in the system.
        { This could have been caused by a bad set, and master volume parameter.
        {
        osp$set_status_abnormal (stc$set_management_id, ste$master_not_active, master_vol, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, set_name, status);
        RETURN; {----->
      IFEND;
    IFEND;

    IF requested_member_vol = master_vol THEN
      osp$set_status_abnormal (stc$set_management_id, ste$member_vol_in_set, requested_member_vol, status);
      osp$append_status_parameter (osc$status_parameter_delimiter, ast_entry.set_name, status);
      RETURN; {----->
    IFEND;

    IF NOT ast_entry.master_ever_up THEN
      osp$set_status_abnormal (stc$set_management_id, ste$master_not_active, master_vol, status);
      osp$append_status_parameter (osc$status_parameter_delimiter, set_name, status);
      RETURN; {----->
    IFEND;

    IF ast_entry.set_owner <> member_owner THEN
      {
      { The set owner must be the same as the member owner.
      {
      osp$set_status_abnormal (stc$set_management_id, ste$set_not_member_owner, member_owner.user, status);
      osp$append_status_parameter (osc$status_parameter_delimiter, member_owner.family, status);
      osp$append_status_parameter (osc$status_parameter_delimiter, set_name, status);
      RETURN; {----->
    IFEND;

    IF ast_entry.master_vsn <> master_vol THEN
      {
      { The master supplied by the user, differs from that in the ast.
      {
      osp$set_status_abnormal (stc$set_management_id, ste$wrong_master, master_vol, status);
      osp$append_status_parameter (osc$status_parameter_delimiter, set_name, status);
      RETURN; {----->
    IFEND;

    IF ast_entry.master_volume_activity.volume_activity_status = stc$inactive THEN
      {
      { The master is not currently active.
      {
      osp$set_status_abnormal (stc$set_management_id, ste$master_not_active, master_vol, status);
      osp$append_status_parameter (osc$status_parameter_delimiter, set_name, status);
      RETURN; {----->
    IFEND;

    stp$search_mel_for_vol (requested_member_vol, ast_index, member_entry, mel_index, member_found_in_ast);
    IF member_found_in_ast THEN
      osp$set_status_abnormal (stc$set_management_id, ste$member_vol_in_set, requested_member_vol, status);
      osp$append_status_parameter (osc$status_parameter_delimiter, ast_entry.set_name, status);
      RETURN; {----->
    IFEND;

  PROCEND validate_add_member;
?? OLDTITLE ??
?? NEWTITLE := '  validate_add_member_params ', EJECT ??

{  PURPOSE:
{    This procedure validates the user supplied parameters.

  PROCEDURE validate_add_member_params
    (    set_name: stt$set_name;
         requested_member_vol: rmt$recorded_vsn;
         master_vol: rmt$recorded_vsn;
     VAR cap_set_name: stt$set_name;
     VAR cap_requested_member_vol: rmt$recorded_vsn;
     VAR cap_master_vol: rmt$recorded_vsn;
     VAR parameter_status: ost$status);

    VAR
      local_name: ost$name,
      valid_name: boolean;

    clp$validate_name (set_name, local_name, valid_name);
    IF valid_name THEN
      cap_set_name := local_name;
      stp$validate_recorded_vsn (requested_member_vol, cap_requested_member_vol, parameter_status);
      IF parameter_status.normal THEN
        stp$validate_recorded_vsn (master_vol, cap_master_vol, parameter_status);
        IF NOT parameter_status.normal THEN
          osp$set_status_abnormal (stc$set_management_id, ste$bad_master_vol_desc, master_vol,
                parameter_status);
        IFEND;
      ELSE
        osp$set_status_abnormal (stc$set_management_id, ste$bad_member_vol_desc, requested_member_vol,
              parameter_status);
      IFEND;
    ELSE
      osp$set_status_abnormal (stc$set_management_id, ste$bad_set_name, set_name, parameter_status);
    IFEND;
  PROCEND validate_add_member_params;

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

{  PURPOSE:
{    This procedure manages the verification of adding a member to a set.
{    Basically this procedure verifies that both member and master are mounted
{    and does what is required to mount them, including demanding exclusive
{    access.

  PROCEDURE verify_add_vol_exec
    (    set_name: stt$set_name;
         member_volume: rmt$recorded_vsn;
         master_volume: rmt$recorded_vsn;
     VAR members_internal_vsn: dmt$internal_vsn;
     VAR members_avt_index: dmt$active_volume_table_index;
     VAR ast_entry: stt$active_set_entry;
     VAR ast_index: stt$ast_index;
     VAR status: ost$status);

    VAR
      local_status: ost$status;

    validate_add_member (set_name, member_volume, master_volume, ast_entry, ast_index, members_internal_vsn,
          members_avt_index, status);

    IF NOT status.normal THEN
      IF status.condition = ste$member_not_active THEN
        {
        {attempt to mount the member
        {
        stp$clear_exclusive_access;
        stp$dm_mount_volume (member_volume, local_status);
        stp$set_exclusive_access;
        IF local_status.normal THEN
          validate_add_member (set_name, member_volume, master_volume, ast_entry, ast_index,
                members_internal_vsn, members_avt_index, status);
        IFEND;
      IFEND;
      IF NOT status.normal THEN
        IF status.condition = ste$master_not_active THEN
          {
          {attempt to mount the master
          {
          stp$clear_exclusive_access;
          stp$dm_mount_volume (master_volume, local_status);
          stp$set_exclusive_access;
          IF local_status.normal THEN
            validate_add_member (set_name, member_volume, master_volume, ast_entry, ast_index,
                  members_internal_vsn, members_avt_index, status);
          IFEND;
        IFEND;
      IFEND;
    IFEND;
  PROCEND verify_add_vol_exec;

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

{  PURPOSE:
{    This procedure looks only at the member volume, and determines if there
{    is any reason to reject the request.  This includes determining if
{    the member is mounted, if the requestor owns the member (or is an
{    administrator).

  PROCEDURE verify_member
    (    member_vol: rmt$recorded_vsn;
     VAR member_internal_vsn: dmt$internal_vsn;
     VAR members_avt_index: dmt$active_volume_table_index;
     VAR member_owner: ost$user_identification;
     VAR member_valid_status: ost$status);

    VAR
      job_owner: ost$user_identification,
      job_owner_status: ost$status,
      member_vol_found: boolean,
      members_sfid: gft$system_file_identifier,
      valid_owner: boolean;

    member_valid_status.normal := TRUE;
    stp$request_dm_volume_info (member_vol, member_internal_vsn, member_owner, members_avt_index,
          member_vol_found);
    IF member_vol_found THEN
      stp$validate_owner (member_owner, valid_owner); {**?**}
      IF NOT valid_owner THEN {**?**}
        pmp$get_user_identification (job_owner, job_owner_status);
        osp$set_status_abnormal (stc$set_management_id, ste$job_not_member_owner, {**?**} job_owner.user,
              member_valid_status); {**?**}
        osp$append_status_parameter (osc$status_parameter_delimiter, job_owner.family, member_valid_status);
        osp$append_status_parameter (osc$status_parameter_delimiter, member_vol, member_valid_status);
      IFEND; {**?**}
    ELSE
      osp$set_status_abnormal (stc$set_management_id, ste$member_not_active, member_vol, member_valid_status);
    IFEND;

  PROCEND verify_member;
?? OLDTITLE ??
MODEND stm$add_member;
