$! BUILD.COM $! $! Builds DECW_ITM.EXE. $! $! Once built, you should place DECW_ITM.EXE, DECW_ITM_START.COM, and $! DECW_STARTLOGIN.COM in a directory and define a system-wide logical $! name DECW_ITM_DIR to point to that directory. $! $ BLISS/LIBRARY DECW_ITM.R32 $ BLISS DECW_ITM $ BLISS COLLECT $ BLISS FORCE $ BLISS DECW_DISPLAY $ LINK DECW_ITM,COLLECT,FORCE,DECW_DISPLAY,SYS$SYSTEM:SYS.STB/SELECTIVE $ EXIT #ifndef __DALDEF_LOADED #define __DALDEF_LOADED 1 /*+-+ * DAL - Device Allocation Lock (value block contents) * * This structure defines the contents of the lock value block for a * device allocation lock as defined in SYS$LIBRARY:LIB.REQ *-+- */ #define DAL$M_NOTFIRST_MNT 1 #define DAL$M_FOREIGN 2 #define DAL$M_GROUP 4 #define DAL$M_SYSTEM 8 #define DAL$M_WRITE 16 #define DAL$M_NOQUOTA 32 #define DAL$M_OVR_PROT 64 #define DAL$M_OVR_OWNUIC 128 #define DAL$M_NOINTERLOCK 256 #define DAL$M_SHADOW_MBR 512 #pragma nostandard struct daldef { variant_union { unsigned short int dal$w_flags; /* Device usage flags: */ variant_struct { unsigned dal$v_notfirst_mnt : 1; /* not first time mounted. */ unsigned dal$v_foreign : 1; /* device mounted /FOREIGN */ unsigned dal$v_group : 1; /* device mounted /GROUP */ unsigned dal$v_system : 1; /* device mounted /SYSTEM */ unsigned dal$v_write : 1; /* write access allowed */ unsigned dal$v_noquota : 1; /* quota checking disabled */ unsigned dal$v_ovr_prot : 1; /* override protection */ unsigned dal$v_ovr_ownuic : 1; /* override volume ownership*/ unsigned dal$v_nointerlock : 1; /* NOT VAXcluster interlocked */ unsigned dal$v_shadow_mbr : 1; /* shadow set member */ unsigned dal$v_fill_2 : 6; } dal$r_fill_1; } dal$r_fill_0; unsigned short int dal$w_protection; /* Volume protection */ unsigned long int dal$l_owner_uic; /* Volume owner UIC */ unsigned long int dal$l_reserved[2]; /* reserved */ }; #pragma standard #endif /* __DALDEF_LOADED */ /* *+-+ * * MODULE: DEVLCK.C * * ABSTRACT: * This program displays local and remote device information obtained * by accessing the Device Allocation Lock. Information is obtained * by calling the kernel mode subroutine DEVLCKINFO. * * AUTHOR: Eric M. LaFranchi, CREATION DATE: 31-JUL-1991 * *-*- */ #include /* VMS descriptor macros */ #include /* $GETDVI item code definitions */ #include /* lock mode definitions */ #include /* VMS RTL status code definitions */ #include /* $GETLKI item codes and definitions */ #include /* VMS system service definitions */ #include /* standard C-RTL I/O definitions */ #include /* system service failure and status */ #include /* C RTL string function definitions */ #include /* $GETSYI item codes and definitions */ #include "daldef.h" /* device allocation lock definitions */ /* item list descriptor structure */ typedef struct item_descriptor { unsigned short int buflen; unsigned short int itmcod; void *bufadr; unsigned short int *retlen; } ITEM_LIST; /* node name structure */ typedef struct { char name[16]; } NODE; /* Flags for device access type */ #define FLG_M_LOCAL 1 #define FLG_M_ALLOCATED 2 #define FLG_M_REMOTE 4 /* Index constants for the following string table. */ #define FILES11 0 #define FOREIGN 1 #define ALLOCATED 2 #define SYSTEM 3 #define GROUP 4 #define PROCESS 5 #define ODS1 6 #define ODS2 7 #define NONE 8 #define YES 9 #define NO 10 extern unsigned long int devlckinfo( ); /* * FUNCTION: display_dal * * ABSTRACT: * This function displays device information obtained from a device's * Device Allocation Lock (DAL) resource. * * INPUTS: * device -- pointer to device name * local_csid -- csid of current local node * lckcnt -- number of lki buffers to process * lkibuf -- pointer to array of lki buffers * valblk -- pointer to lock value block */ static unsigned long int display_dal( const char *const device, const unsigned long int local_csid, const unsigned short int lckcnt, const struct lkidef *const lkibuf, const struct daldef *const valblk ) { static ITEM_LIST syiitmlst[] = { { sizeof( NODE ), SYI$_NODENAME, NULL, NULL }, { 0, 0, NULL, NULL } }; static const char *devcxt[] = { "Mounted Files-11", "Mounted Foreign", "Allocated", "System", "Group", "Process", "ODS-1", "ODS-2", "N/A", "Yes", "No" }; static const char *ownership[] = { "S:", " O:", " G:", " W:" }; static const char prot[] = "rwed"; char devprt[28]; char owneruic[12]; unsigned long int csid, status; unsigned long access, structure, write, shadow, mntsts; unsigned short int retlen, iosb[4], nodecnt; register char *cp; register NODE *node; register i, tmp, tmp1, flags; /* allocate buffer for node names and set node count to zero */ node = (NODE *)malloc( (lckcnt - 1) * sizeof ( NODE ) ); if ( node == NULL ) return ( LIB$_INSVIRMEM ); /* Scan the Lock Information buffers and compute remote activity */ flags = 0; nodecnt = 0; syiitmlst[0].retlen = &retlen; for ( i = 0; i < lckcnt; i++ ) { if ( lkibuf[i].lki$b_grmode != LCK$K_NLMODE ) { csid = lkibuf[i].lki$l_csid; /* Determine if local or remote access */ if ( local_csid == csid ) flags |= FLG_M_LOCAL; else flags |= FLG_M_REMOTE; /* The device is allocated if an exclusive mode lock * is granted on the DAL resource */ if ( lkibuf[i].lki$b_grmode == LCK$K_EXMODE ) flags |= FLG_M_ALLOCATED; /* Store the node name accessing the device and increment * the access (node) count */ syiitmlst[0].bufadr = &node[nodecnt]; status = SYS$GETSYIW( 1, &csid, NULL, syiitmlst, iosb, NULL, NULL ); if ( status & 1 ) status = iosb[0]; if ( !(status & 1) ) { nodecnt = 0; break; } node[nodecnt].name[retlen] = '\0'; nodecnt++; } } /* If the device is accessed, print the device name, the access * mechanism, the node names accessing the device, and whether or * not the device is accessed with the F11B-XQP */ if ( nodecnt > 0 ) { access = ALLOCATED; structure = mntsts = write = shadow = NONE; /* determine access type of device */ if ( valblk->dal$v_notfirst_mnt ) { if ( !valblk->dal$v_foreign ) { /* file structure level */ if ( valblk->dal$v_nointerlock ) structure = ODS1; else structure = ODS2; access = FILES11; } else access = FOREIGN; /* The device is mounted, determine mount status */ if ( valblk->dal$v_system ) mntsts = SYSTEM; else if ( valblk->dal$v_group ) mntsts = GROUP; else mntsts = PROCESS; if ( valblk->dal$v_write ) write = YES; else write = NO; } /* Is device a shadow set. */ if ( valblk->dal$v_shadow_mbr ) shadow = YES; else shadow = NO; printf( "\n Device %s is %s %son node%s\n", device, flags & FLG_M_ALLOCATED ? "allocated" : "accessed", (flags & FLG_M_REMOTE) && !(flags & FLG_M_LOCAL) ? "remotely " : "", nodecnt > 1 ? "s" : "" ); for ( i = (nodecnt - 1); i >= 0; i-- ) printf( " %s\n", node[i].name ); printf( "\n%s%s\n%s%s\n%s%s\n", " Access Mount File ", "Write Shadow Owner Device", " Type Status Structure ", "Enable Member UIC Protection", " ---------------- -------- ---------- ", "------- ------- ---------- -------------" ); sprintf( owneruic, "[%o,%o]", valblk->dal$l_owner_uic >> 16, valblk->dal$l_owner_uic & 0xffff ); /* build device protection string */ memset( devprt, '\0', sizeof( devprt ) ); tmp = valblk->dal$w_protection; for ( i = 0; i < 16; i++ ) { tmp1 = i & 3; if ( !tmp1 ) strcat( devprt, ownership[i >> 2] ); if ( !((1 << i) & tmp) ) sprintf( devprt, "%s%c", devprt, prot[tmp1] ); } cp = (char *)strchr( devprt, 'G' ); *--cp = '\0'; printf( " %- 17s%- 9s%- 11s%- 8s%- 8s%- 11s%s\n", devcxt[access], devcxt[mntsts], devcxt[structure], devcxt[write], devcxt[shadow], owneruic, devprt ); printf( "%65s%s\n", "", ++cp ); } /* Release memory associated with node name buffer */ free( node ); return ( status ); } /* * FUNCTION: main * * ABSTRACT: * This function allocates a buffer for lock information based on the * number of nodes in the VAXcluster (plus four in case a new node joins * the cluster or a show device command has been issued concurrently.) * The devlockinfo kernel mode routine is called to gather lock * the information to be processed by the display_dal function. * */ main( unsigned argc, char **argv ) { static ITEM_LIST syiitmlst[ ] = { { sizeof(unsigned long int), SYI$_NODE_CSID, NULL, NULL }, { sizeof(unsigned short int), SYI$_CLUSTER_NODES, NULL, NULL }, { 0, 0, NULL, NULL } }; static ITEM_LIST lkiitmlst[ ] = { { 0, LKI$_LOCKS, NULL, NULL }, { 0, 0, NULL, NULL } }; void *arglst[4]; char devbuf[132]; struct daldef valblk; struct lkidef *lkibuf; struct dsc$descriptor_s devnam; unsigned short int iosb[4], nodecnt; unsigned long int lckcnt, local_csid, status; char devlst[80], *argvec[3]; register tmp; register char *device; /* if no devices on command line, then we're done. */ if ( argc == 1 ) { argv = argvec; argvec[2] = NULL; fputs( "Enter device: ", stdout ); argvec[1] = gets( devlst ); } /* Build item list and call $GETSYI system service */ syiitmlst[0].bufadr = &local_csid; syiitmlst[1].bufadr = &nodecnt; status = SYS$GETSYIW( 1, NULL, NULL, syiitmlst, iosb, NULL, NULL ); if ( status & 1 ) status = iosb[0]; if ( !(status & 1) ) return ( status ); /* Allocate and intialize $GETLKI system service item list. */ tmp = (nodecnt + 4) * LKI$K_LENGTH; lkibuf = (struct lkidef *)malloc( tmp ); if ( lkibuf == NULL ) return ( LIB$_INSVIRMEM ); lkiitmlst[0].buflen = tmp; lkiitmlst[0].bufadr = (void *)lkibuf; lkiitmlst[0].retlen = (unsigned short int *)&lckcnt; /* Initialize argument list for kernel mode subroutine */ arglst[0] = (void *)3; arglst[1] = (void *)&devnam; arglst[2] = (void *)&valblk; arglst[3] = (void *)lkiitmlst; /* process command line into contigous string, then parse off each * device name and process one at a time. */ for ( strcpy( devbuf, *++argv ); *++argv; strcat( devbuf, *argv ) ); for ( device = strtok( devbuf, "," ); device; device = strtok( NULL, "," ) ) { devnam.dsc$a_pointer = device; devnam.dsc$w_length = strlen( device ); status = SYS$CMKRNL( devlckinfo, arglst ); if ( !(status & 1) ) break; /* Test for buffer overflow. */ if ( (tmp = lckcnt) < 0 ) { status = (SS$_BUFFEROVF & ~STS$M_SEVERITY) | STS$K_WARNING; break; } lckcnt = (tmp & 0xFFFF) / ((tmp >> 16) & 0x7FFF); status = display_dal( device, local_csid, lckcnt, lkibuf, &valblk ); } free( lkibuf ); return ( status ); } .title devlckinfo -- get device allocation lock information .ident 'V01.0' ;++ ; FACILITY: ; devlckinfo -- get device allocation lock information ; ; ABSTRACT: ; This module provides a routine to access the Device Allocation Lock ; (DAL) for a device. The lock value block and any other information ; specified in the item list argument to the $GETLKI system service. ; ; AUTHOR: Eric M. LaFranchi, CREATION DATE: 31-JUL-1991 ; ;-- .default displacement, byte .library 'sys$share:lib.mlb' .link 'sys$system:sys.stb' /selective_search $chfdef ; condition handling fac definitions $devdef ; device characteristic definitions $ipldef ; IPL definitions $lckdef ; lock manager definitions $lkidef ; lock information definitions $pcbdef ; process control block definitions $prdef ; processor register definitions $psldef ; access mode definitions $ssdef ; system service status definitions $stsdef ; system service failure definitions $ucbdef ; device unit control block definitions .page .sbttl devlckinfo -- request device allocation lock information .psect code nowrt, exe, shr, pic, novec, quad ;++ ; Environment: ; VAX/VMS kernel mode routine ; ; Abstract: ; This routine probes user arguments, builds the Device Allocation ; Lock (DAL) resource name, and enqueues a NULL mode lock on the ; Device Allocation resource. The lock value block is returned if a ; buffer is specified, and $GETLKI system service is requested with ; the user specified item list. ; ; Calling Sequence: ; $cmkrnl_s - ; routin = devlckinfo, ; arglst = arglst ; ; Inputs: ; devnam -- address of device name descriptor ; valblk -- user value block address ; itmlst -- item list argument to $GETLKI system service ; ; Outputs: ; value block -- returned to caller if specified ; itmlst -- process by the $GETLKI system service ; ; Return Value: ; r0 -- VMS status code ; ;-- flags = LCK$M_EXPEDITE!LCK$M_SYSTEM!LCK$M_VALBLK!LCK$M_NOQUEUE devnam = 4 valblk = 8 itmlst = 12 $offset 0, NEGATIVE, <- ; frame pointer (fp) offsets , - ; for local storage , - , - , - , - , - stksiz> .entry devlckinfo, ^m ; save registers movab w^handler, (fp) ; establish condition handler movab stksiz(sp), sp ; reserve work space movzwl #ss$_accvio, r0 ; assume access violation status ifnord s^#16, (ap), 20$ ; check accessibility of arglst movl devnam(ap), r1 ; load device name descriptor ifnord s^#8, (r1), 20$ ; check descriptor readability movq (r1), r2 ; load descriptor contents ifnord r2, (r3), 20$ ; branch if string not readable jsb g^sch$iolockr ; grab I/O database mutex jsb g^ioc$searchdev ; search I/O DB for device blbc r0, 10$ ; branch if device not found movl r1, r5 ; place ucb address in r5 movzwl #ss$_ivdevnam, r0 ; assume invalid device status assume dev$v_clu eq 0 ; check DEV$V_CLU is bit zero blbc ucb$l_devchar2(r5), 10$ ; branch not available movl #^a'SYS$', prefix(fp) ; store system lock prefix movl r4, r3 ; save pcb address movab alldevnam(fp), r1 ; load address for device name movl s^#16, r0 ; load device name buffer length movl s^#1, r4 ; load flags for name type jsb g^ioc$cvt_devnam ; get device name movl r3, r4 ; restore pcb addl3 s^#4, r1, resnam(fp) ; store DAL resource name length 10$: movl r0, r5 ; save status jsb g^sch$iounlock ; release I/O database mutex setipl s^#0 ; return IPL to zero blbs r5, 25$ ; check status -- branch if O.K. movl r5, r0 ; restore bad status 20$: ret ; return error status 25$: pushal efn(fp) ; push event flag address calls s^#1, g^lib$get_ef ; allocate event flag blbc r0, 20$ ; branch is no event flag movab prefix(fp), (fp) ; initalize resource descriptor $enqw_s - ; Enqueue a NULL mode lock on efn = efn(fp), - ; device allocation lock resourc lkmode = #LCK$K_NLMODE, - lksb = lksb(fp), - flags = #flags, - resnam = resnam(fp), - acmode = #PSL$C_KERNEL blbc r0, 30$ ; branch if error return status movzwl lksb(fp), r0 ; load status from lksb 30$: cmpw r0, #ss$_valnotvalid ; invalid value block? beql 40$ ; branch invalid value blk O.K. blbc r0, 70$ ; branch error enqueueing lock 40$: movl valblk(ap), r1 ; load user value block address beql 50$ ; branch no value block address movzwl #ss$_accvio, r2 ; assume access violation status ifnowrt s^#16, (r1), 60$ ; branch buffer not writeable movc3 s^#16, (fp), (r1) ; copy value block to user buffe movl (fp), lkid(fp) ; save/store lock id movzwl #ss$_normal, r2 ; load success if no item list movl itmlst(ap), r3 ; load item list address beql 60$ ; branch no item list address 50$: $getlkiw_s - ; get information for all locks efn = efn(fp), - ; on the device allocation lock lkidadr = lkid(fp), - ; resource itmlst = (r3), - iosb = lksb(fp) movl r0, r2 ; load return status into r2 blbc r0, 60$ ; branch if an error occurred movzwl lksb(fp), r2 ; load completion status 60$: $deq_s - ; dequeue the lock lkid = lkid(fp), - acmode = #PSL$C_KERNEL blbc r2, 80$ ; branch if previous bad status 70$: movl r0, r2 ; save status 80$: pushal efn(fp) ; push event flag address calls s^#1, g^lib$free_ef ; give back event flag blbc r0, 90$ ; branch, bad event flag movl r2, r0 ; restore real status ret ; return status to caller 90$: blbs r2, 99$ ; return bad event flag status movl r2, r0 ; load previous bad status to r0 99$: ret ; return status to caller .page .sbttl handler -- handler for kernel mode exceptions ;++ ; ; abstract: ; This handler releases the I/O database mutex if it has been aquired ; by this process, then returns the exception status. ; ; establish sequence: ; movab handler, (fp) ; ;-- .align long handler: .word ^m<> movl chf$l_sigarglst(ap), r1 ; load signal array address movl chf$l_sig_name(r1), r0 ; load signal name cmpl r0, #ss$_unwind ; are we unwinding? beql 20$ ; branch if yes and resignal pushr #^m ; save registers movl g^ctl$gl_pcb, r4 ; load pcb address tstw pcb$w_mtxcnt(r4) ; holding I/O database mutex? beql 10$ ; branch if not holding mutex jsb g^sch$iounlock ; release I/O database mutex setipl s^#0 ; return IPL to zero 10$: popr #^m ; restore registers movl chf$l_mcharglst(ap), r1 ; load mechanism array address movl r0, chf$l_mch_savr0(r1) ; set return status into r0 $unwind_s ; return condition to caller 20$: movl #ss$_resignal, r0 ; continue unwinding ret .end