Everhart, Glenn From: vandenheuvel@eps.enet.dec.c*m Sent: Monday, October 12, 1998 10:30 AM To: Info-VAX@Mvb.Saic.Com Subject: Re: Identifying processes locking rms files In article <uX3bhpV89GA.246@upnetnews02.moswest.msn.net>, "Donald Elliot" <d_elliot@msn.com> writes... >We are having a problem with a process (or processes) locking a file which >keeps hold of the lock. >What I would like is a method of identifying not only what processes >have the file open ... Is there any utility around or some other trick ? I have a crude tool that I hope to dust of for the next freeware submission: #define MAXDEVICE 200 #define MAXDEVNAMLEN 64 #define MAXDEVLOCKNAM 13 #define MAXFILNAMLEN 80 #define MAXPID 16 /* ** BLOCKING.C, Hein van den Heuvel, Digital, July 1995 ** ** List all locks not granted (converting, waiting) for a specified PID. ** For each, print blocking lock information, resource name and parent. ** Also, try to print out reverse fouind FILE NAME and RECORD CONTENTS. ** Have fun, ** Hein van den Heuvel, July 1995. */ #include <prvdef> #include <lkidef> #include <lckdef> #include <descrip> #include <string> #include <ctype> #include <stdio> #include <ssdef> #include <rms> #define terminator 0,0,0,0 #define EFN 1 static char devnam[MAXDEVICE][MAXDEVNAMLEN]; /* counted string */ static char devlocknames[MAXDEVICE][MAXDEVLOCKNAM+1]; static int device_count = 0; typedef struct { short len, cod; void *address; short *retlen; } item; typedef struct { unsigned int len; void *address; } desc; int sys$getlkiw(), sys$getjpi(), sys$setprv(), sys$cmexec(); void dump_data () ; int make_device_name_list(), print_filename_and_record() ; char *find_device_name(); char *mode[]={"NL", "CR", "CW", "PR", "PW", "EX", "??"}; main(int argc, char *argv[]) { int stat, s, i, l, parent, grand_parent, lock_id, lock_pid; int wildcard=0, retlen=0, parent_retlen=0, pid=0, locks=0; char *x; struct lkidef lkibuf[100], *lki; struct { unsigned all : 16, one : 15, too_small : 1 ;} lkilen; int privs[] = { PRV$M_WORLD | PRV$M_CMEXEC , 0}; int *search_devnam=0; desc search_devnam_desc; #pragma nostandard /* Using address of variable where constant is standard */ struct { char rqmode, grmode, queue, fill;} lki_state; struct { int rms; unsigned short fid_num, fid_seq, fid_rvn; char devlocknam[22] ;} parent_resnam; struct { unsigned int id, vbn, fill[6];} resnam; item getlki_items[] = { 4, LKI$_LOCKID, &lock_id, 0, 4, LKI$_PID, &lock_pid, 0, 3, LKI$_STATE, &lki_state, 0, terminator}; item block_items[] = { 31, LKI$_RESNAM, &resnam, &retlen, 4, LKI$_PARENT, &parent, 0, sizeof lkibuf, LKI$_BLOCKING,&lkibuf, &lkilen, terminator}; item parent_items[] = {31, LKI$_RESNAM, &parent_resnam, &parent_retlen, 4, LKI$_PARENT, &grand_parent, 0, terminator}; int getlki_args[] = {7, EFN, (int) &wildcard, (int) &getlki_items,0,0,0,0}, parent_args[] = {7, EFN, (int) &parent, (int) &parent_items,0,0,0,0}, block_args[] = {7, EFN, (int) &lock_id, (int) &block_items,0,0,0,0}; #pragma standard /* ** First get some temporary privs for the GETLKI in EXEC mode later on. */ stat = sys$setprv ( 1, privs, 0, 0); if (stat != SS$_NORMAL) return (stat & -2); if (argc > 1) { /* ** First argument, if present, specifies PID to look for. 0 = All. */ sscanf (argv[1], "%x", &pid); if (pid > MAXPID) { printf (" Looking for non-granted locks for PID %8X\n\n", pid); } else { x = ""; if (pid > 0) x = "RMS "; printf (" Looking for non-granted %slocks for all PIDs\n\n", x); }; }; if (argc > 2) { /* ** Second argument, if present, specifies wildcarded device name ** to look for. For lock on matching devices, the RMS files name ** and locked record is attempted to be displayed. */ search_devnam_desc.len = strlen(argv[2]); search_devnam_desc.address = (int) argv[2]; search_devnam = &search_devnam_desc; str$upcase (&search_devnam_desc, &search_devnam_desc); } (void) make_device_name_list(search_devnam); /* ** Main loop. Get a lock, any lock. ** Find out wether it is held by specified process, and waiting. */ stat = sys$cmexec (&sys$getlkiw, &getlki_args); while (stat & 1) { locks++; if ( (lki_state.queue != LKI$C_GRANTED) && ((pid < MAXPID) || (lock_pid == pid)) ) { int rms = 0; parent = 0; /* ** Have blocked lock for specified PID, request details. */ stat = sys$cmexec (&sys$getlkiw, &block_args); if (!(stat & 1)) break; /* ** Let's see if we stumbled into an rms record or bucket lock... */ if (parent!=0) { s = sys$cmexec (&sys$getlkiw, &parent_args); if ((s & 1) && (grand_parent==0) && (parent_resnam.rms == 'RMS$')) rms = 1; } /* ** Print out all locks, or just RMS ? */ if ((pid == 0) || (pid > MAXPID) || rms) { l = lkilen.all / lkilen.one; printf ("Pid %08X Lock %08X, Rq=%s, Parent %08X, blocked by %d.\n", lock_pid, lock_id, mode[lki_state.rqmode], parent, l); dump_data (&resnam, retlen, "Resource Name "); lki = &lkibuf; for ( i = 0; i < l; i++) { printf (" PID=%8X, Gr=%s, Rq=%s, LockId=%08X, System=%08\n", lki->lki$l_pid, mode[lki->lki$b_grmode], mode[lki->lki$b_rqmode], lki->lki$l_lkid, lki->lki$l_csid); lki++; } if (parent!=0) dump_data (&parent_resnam, parent_retlen, "Parent Resource Name"); printf ("\n"); } if (rms) { printf (" RMS lock! VBN/ID %X/%X, File (%d,%d,%d) on %s\n", resnam.vbn, resnam.id, parent_resnam.fid_num, parent_resnam.fid_seq, parent_resnam.fid_rvn, &parent_resnam.devlocknam[1]); print_filename_and_record ( &parent_resnam.devlocknam[0], &parent_resnam.fid_num, resnam.vbn, resnam.id); } } /* PID ? */ if (stat &1) stat = sys$cmexec (&sys$getlkiw, &getlki_args); } /* stat ? */ if (stat == SS$_NOMORELOCK) stat = SS$_NORMAL; printf (" Done. Scanned %d locks.\n", locks); return stat; } void dump_data (void *p, short len, char *t) { int i, j, k, l; unsigned char (*x)[72]; char out[80], *in, c; x = in = p; l = len; if (l > 72) l = 72; /* sizeof out */ for (i=0; i<l; i++){ c = *in++; if (!isalnum (c)) c = '.'; out[i]=c; } out[i]=0; printf (" %s (%d):\n <%s>\n", t, len, &out[0]); j = 0; for (i=0; i<l;) { j += sprintf (&out[j], "%02X ", (*x)[i++]); if (!(i%24)) { printf (" %s\n",&out[0]); j = 0; } } if (j) printf (" %s\n",&out[0]); return; } int print_filename_and_record ( char *devlocknam, unsigned short (*fid)[3], unsigned int vbn, unsigned int id) { struct FAB fab; struct NAM nam; struct RAB rab; int device_number, stat, i, l; char buf[512]; static char filnam[MAXFILNAMLEN+1]; desc devnam_desc, filnam_desc = {0, filnam}; for (device_number=0; strcmp ((char *) devlocknames[device_number], devlocknam); device_number++) if (device_number == device_count) return; devnam_desc.len = devnam[device_number][0]; devnam_desc.address = &devnam[device_number][1]; filnam_desc.len = MAXFILNAMLEN; stat = lib$fid_to_name(&devnam_desc, fid, &filnam_desc, &filnam_desc); filnam[filnam_desc.len] = 0; printf ( " %s %s\n", &devnam[device_number][1], filnam); /* ** Now that we've printed out the file name, and previously the record ** or bucket data, lets try get display the data being waited for. ** I suppose this could end up becoming blocked for the very same lock! ** (VBN lock code is not at all tested as RMS does not normally block there) */ fab = cc$rms_fab; rab = cc$rms_rab; nam = cc$rms_nam; rab.rab$l_fab = &fab; fab.fab$l_nam = &nam; fab.fab$l_fop = FAB$M_NAM; /* will use dev+id, not name */ if (!vbn) fab.fab$b_fac = FAB$M_BIO;/* block IO if not an RFA */ fab.fab$b_shr = FAB$M_SHRUPD; /* allow writers */ for (i=0; i<3; i++) nam.nam$w_fid[i] = (*fid)[i]; for (i=0; i<devnam[device_number][0]; i++) nam.nam$t_dvi[i] = devnam[device_number][i]; nam.nam$t_dvi[0]--; /* strip colon */ rab.rab$l_ubf = buf; rab.rab$w_usz = sizeof buf; stat = sys$open ( &fab ); if (!(stat&1)) return stat; stat = sys$connect ( &rab ); if (!(stat&1)) return stat; if (vbn) { rab.rab$b_rac = RAB$C_RFA; rab.rab$v_rrl = 1; rab.rab$l_rfa0 = vbn; rab.rab$w_rfa4 = id; stat = sys$get ( &rab ); l = rab.rab$w_rsz; if (stat == RMS$_RTB) { l = rab.rab$l_stv; stat = 1; } } else { rab.rab$l_bkt = id; stat = sys$read ( &rab ); } dump_data (rab.rab$l_rbf, l, " Record "); return stat; } int make_device_name_list(desc *search_devnam) { #include <dvidef> #include <dcdef> /* #include <dvsdef> does not exist, hand coded defines follow */ #define DVS$_DEVCLASS 1 #define DVS$_DEVTYPE 2 #define SS$_NOMOREDEV 2648 int i, stat, context[] = {0,0}, devclass = DC$_DISK; short int retlen; desc devnam_desc; item getdvi_items[] = { MAXDEVLOCKNAM, DVI$_DEVLOCKNAM,0, 0, terminator}; item device_items[] = { 4, DVS$_DEVCLASS, &devclass, 0, terminator}; /* ** Build two arrays with DISK device names and their lock names. */ for (i=0; i<MAXDEVICE; i++) { devnam_desc.len = MAXDEVNAMLEN-1; devnam_desc.address = &devnam[i][1]; stat = sys$device_scan (&devnam_desc, &devnam_desc, search_devnam, device_items, context); devnam[i][0]=devnam_desc.len; if (stat & 1) { devnam[i][devnam_desc.len+1]=0; /* Null terminate */ getdvi_items[0].address = devlocknames[i]; getdvi_items[0].retlen = &retlen; stat = sys$getdvi (0,0,&devnam_desc,getdvi_items,0,0,0,0); if (stat != SS$_NORMAL) return stat; devlocknames[i][retlen] = 0; } else { if (stat == SS$_NOMOREDEV) { device_count = i; i = MAXDEVICE; } break; } } return stat; }