              <<< VAXAXP::NOTES$:[NOTES$LIBRARY]VMSNOTES.NOTE;1 >>>
               -< VAX and Alpha VMS - Digital Internal Use Only >-
================================================================================
Note 58.2             Disk status "remote shadow member" ?                2 of 2
VIVIAN::RANCE "http://vivian.hhl.dec.com/rance/bus" 201 lines   9-JAN-1995 05:03
                               -< Example code >-
--------------------------------------------------------------------------------
/* SHADOW_MEMBER.C */

/*      This program defines symbol FULL_MEMBER to be the name   */
/*      of a disk that is guaranteed to be a current full member */
/*      of an OpenVMS Phase II shadow set.                       */
/*                                                               */
/*      Usage                                                    */
/*      $ SET PROCESS /PRIVILEGE=CMKRNL                          */
/*      $ SHADOW_MEMBER = "$dev:[dir]SHADOW_MEMBER"              */
/*      $ SHADOW_MEMBER nnn      ! Unit number of shadow set     */
/*      $ Symbol FULL_MEMBER is now defined                      */
/*                                                               */
/*      This program will define the FULL_MEMBER symbol so       */
/*      long as at least one node in the VMSCluster has the      */
/*      shadow set mounted.  It can be used to locate a valid    */
/*      shadow set member to enable a MOUNT/INCLUDE command to   */
/*      be issued without any fear of adding a drive to the      */
/*      shadow set.                                              */
/*                                                               */
/*  Stuart Rance, London MCS, May 1994   VIVIAN::RANCE           */


#include <stdio.h>
#include <lkidef.h>
#include <lckdef.h>
#include <psldef.h>
#include <ssdef.h>
#include <descrip.h>
#include <ctype.h>

#ifndef LCK$M_QUECVT
#define LCK$M_QUECVT 4096
#endif

#ifndef SS$_VALNOTVALID
$define SS$_VALNOTVALID 2544
#endif

struct lksb
           {
            short status;
            short reserved;
            int lockid;
            struct
                 { long alloclass;
                   short unit;
                   union
                      { short pad;
                        struct
                             { unsigned let3 : 5;   /* 3 letter controller  */
                               unsigned let2 : 5;   /* name in RAD-HUSTVEDT */
                               unsigned let1 : 5;   /* format (1=A, 26=Z)   */
                               unsigned let0 : 1;
                             } letters;
                      } controller;
                 } valblk;
           };

struct lksb lksb;
int queue_lock(void),requeue_lock(void),dequeue_lock(void);
char resnam[32];
struct dsc$descriptor_s resdsc;

main(int argc,char *argv[])
{
    int stat;            /* Return status from VMS system services        */
    int i;               /* loop counter                                  */
    int unit_num;        /* Unit number of shadow set                     */
    int physunit;        /* Unit number of Physical Disk in shadow set    */
    int alloclass;       /* Allocation class of "    "    "    "    "     */
    char controller[4];  /* Controller letter of "   "    "    "    "     */
    char physdisk[33];   /* Full name of physical disk in shadow set      */
    $DESCRIPTOR(disk_desc,physdisk);   /* Descriptor for "" "" ""         */
    const $DESCRIPTOR(full_member,"FULL_MEMBER"); /* DCL Symbol to define */

    if (argc != 2)
    {
        printf("Usage: %s nnn (nnn=shadow set unit number)\n",argv[0]);
        exit(1);
    }

    if (strlen(argv[1])>4)
    {
        printf("Usage: %s nnn (nnn=shadow set unit number)\n",argv[0]);
        exit(1);
    }

    for(i=0;i<strlen(argv[1]);i++)
    {
       if (!(isdigit(argv[1][i])))
       {
        printf("Usage: %s nnn (nnn=shadow set unit number)\n",argv[0]);
        exit(1);
       }
    }

    resdsc.dsc$b_class   = DSC$K_CLASS_S;
    resdsc.dsc$b_dtype   = DSC$K_DTYPE_T;
    resdsc.dsc$w_length  = 16;
    resdsc.dsc$a_pointer = resnam;

    unit_num = atoi(argv[1]);
    if ( (unit_num > 4096) || (unit_num < 0) )
    {
       printf("Shadow set unit number should be <4096 and >0");
       exit(1);
    }

    /* Resource name is $DSAnnnn_$IN_SET with the unit number 0 filled */
    strcpy(resnam,"$DSA0000_$IN_SET");
    /* Copy unit number from argv[1] to bits 8-5 of resource name */
    memcpy(&resnam[8-strlen(argv[1])],argv[1],strlen(argv[1]));

    stat =  sys$cmkrnl(queue_lock,0);	/* Queue lock in kernel mode */
    if (!(stat & 1))
	lib$stop(stat);

    if (lksb.status == SS$_VALNOTVALID)
    {
        stat = sys$cmkrnl(requeue_lock,0);  /* Queue CR lock to force update */
    }

    stat =  sys$cmkrnl(dequeue_lock,0);	/* DEQueue lock in kernel mode */
    if (!(stat & 1))
	lib$stop(stat);
    if (!(lksb.status & 1))
	lib$stop(stat);

    /*
    The lock value block now contains the name of a disk which is a full
    member of the shadow set.  This data is held in the following format

	31..................0	Allocation Class
	             15.....0   Unit Number
	         20..16         Controller Name (3rd character rad-Hustvedt)
	     25..21             Controller Name (2nd character rad-Hustvedt)
	 30..26                 Controller Name (1st character rad-Hustvedt)
    */

    physunit      = lksb.valblk.unit;            /* Unit Number      */
    alloclass     = lksb.valblk.alloclass;       /* Allocation class */
    controller[0] = lksb.valblk.controller.letters.let1 + 'A' - 1;
    controller[1] = lksb.valblk.controller.letters.let2 + 'A' - 1;
    controller[2] = lksb.valblk.controller.letters.let3 + 'A' - 1;
    controller[3] = '\0';

    if ( controller[0] == 'A'-1 || 
         controller[1] == 'A'-1 ||
         controller[0] == 'A'-1
       )  
    {
       physdisk[0]='\0';   /* No valid disk name so define null string */
    }   
    else      
    {
       sprintf(physdisk,"$%d$%s%d",alloclass,controller,physunit);
    }
    disk_desc.dsc$w_length = strlen(physdisk);
    return lib$set_symbol(&full_member,&disk_desc);
}

/* End of MAIN routine. */


queue_lock()
/* Queue lock on in_set resource. This is called from kernel mode */
{
    return sys$enqw(0, LCK$K_NLMODE,&lksb,LCK$M_SYSTEM|LCK$M_VALBLK,
                    &resdsc,0,0,0,0,0,0);
}

dequeue_lock()
/* Dequeue lock on in_set resource. This is called from kernel mode */
{
    return sys$deq(lksb.lockid, 0, 0, 0);
}


requeue_lock()
/* Routine REQUEUE lock is called if QUEUE_LOCK has returned SS$_VALNOTVALID */
/* it converts the lock to CR mode and back to NL so that the disk watcher   */
/* will be asked to update the Lock Value Block                              */
{
   int stat;

   /* Queue a CR mode lock */
   stat=sys$enqw(0,LCK$K_CRMODE,&lksb,LCK$M_CONVERT|LCK$M_SYSTEM|LCK$M_VALBLK,
                 &resdsc,0,0,0,0,0,0);

   /* If the CR mode lock request succeeded then convert to NL mode */
   if ( (stat&1) && ( (lksb.status&1) || (lksb.status==SS$_VALNOTVALID) ) )
   stat=sys$enqw(0,LCK$K_NLMODE,&lksb,LCK$M_CONVERT|LCK$M_SYSTEM|LCK$M_VALBLK,
                 &resdsc,0,0,0,0,0,0);

   if (!(stat&1))
      return stat;
   else 
      return lksb.status;
}


