dewi@druca.UUCP (WilliamsD) (03/25/86)
The following piece of code is something I cooked up in order to check if I was unlocking all my filesystem locks in my current project. I use it with AvailMem (Avail?, I forget at the moment...) and Frags to ensure that my code isn't slowly dribbling away pieces of the system. It's a rather offbeat way of doing it, but I thought I'd post it to the net for 2 reasons: 1. Somebody might find it useful. 2. Somebody might suggest a better way of doing it! I'm not overly happy with this approach. It works most OK of the time, but once in a blue moon the system will request that my boot volume get re-mounted before I get around to analyzing its DeviceList entries. No harm done, LockMon will just report it as mounted. Yours in Amiga-ing, Dewi Williams -------------------------------- cut here --------------------------------- /* * LockMon: determine the number of locks associated with a filesystem * task. I haven't figured out how to do this directly, so I * cheat -- if a volume is offlined, then a linked list of locks * is transferred to the volume's DeviceList entry. Note that * this isn't a permanent solution -- it won't work with hard * disks or RAM:, for instance. * * Warnings: Uses Aztec C library internal DOSBase, which holds the * DOS library base pointer. Lattice does the same. * And ... this implementation is guesswork. Caveat emptor! * * Request: Anybody know a better way? * * Perpetrator: Dewi Williams ..!ihnp4!druca!dewi. * Extremely public domain. * * Version: 1.0 */ #include <stdio.h> #include <libraries/dos.h> #include <libraries/dosextens.h> #include <exec/memory.h> /* Defines */ /* Change typeless BCPL BPTR to typed C (for struct pointers). Don't * use this define on an APTR, that's only a badly disguised void *. */ #define BPTR_TO_C(strtag, var) ((struct strtag *)(BADDR( (ULONG) var))) /* And do the reverse */ #define C_TO_BPTR(var) (((ULONG)var)>>2) /* Externs */ extern struct DosLibrary *DOSBase; /* dos library base pointer */ extern short Enable_Abort; /* controls ^C processing */ /* ARGSUSED */ main(argc, argv) int argc; char **argv; { struct RootNode *rn; struct DosInfo *di; struct DeviceList *dl; struct FileLock *myFileLock; struct Process *myprocess; char buf[80]; struct FileInfoBlock *fi; char *name; char *btocstr(); void *malloc(); void CountLocks(); struct Task *FindTask(); Enable_Abort = 0; /* Disable ^C processing */ printf("Eject any volumes you wish to profile.\n"); printf("You will be requested to re-insert them as needed.\n"); printf("When ready, press RETURN to continue or 'q' to abort.\n"); (void)gets(buf); /* Well, q and RETURN really... */ if (buf[0] == 'q') { /* Last chance to change your mind! */ printf("Aborted...\n"); exit(0); } /* Wait for things to settle down (just in case) */ (void)Delay(5 * TICKS_PER_SECOND); /* The FileInfoBlock with guaranteed alignment. */ if ((fi = (struct FileInfoBlock *)malloc(sizeof(*fi) )) == NULL) { printf("Memory allocation failure"); exit(1); } /* Note that since lockmon itself has a lock on the current * directory, this has to be filtered out as an artefact. * We can get its value out of the CLI stuff. Our task control * block is the first element of the process control block, * hence the following casting. This code fragment courtesy of * the kind person at C-A who answered my query about finding * the current directory on RAM: */ myprocess = (struct Process *)FindTask(NULL); myFileLock = BPTR_TO_C(FileLock, myprocess->pr_CurrentDir); /* Any system manipulation of AmigaDOS linked lists while we're * traversing could quite easily crash us, and the system. So * we righteously forbid it. */ Forbid(); /* but is this really necessary? */ /* Take the DOS library base pointer, deduce the DOS Root Node * address from that. Follow this to the Info substructure, which * gives us the start address of the DeviceList chain. Volumes are * DeviceList entries with a type of DLT_VOLUME. Note that these are * AmigaDOS linked lists *NOT* Exec ones, so all the stuff about List, * Node etc. doesn't apply. One box, 2 operating systems! */ rn = (struct RootNode *)DOSBase->dl_Root; di = BPTR_TO_C(DosInfo, rn->rn_Info); dl = BPTR_TO_C(DeviceList, di->di_DevInfo); while (dl != NULL) { if (dl->dl_Type == DLT_VOLUME) { if ((name = btocstr(dl->dl_Name)) == NULL) { printf("Memory allocation failure\n"); break; } printf("Volume '%s': ", name); if (dl->dl_LockList != NULL) { CountLocks(BPTR_TO_C(FileLock,dl->dl_LockList), fi, myFileLock); } else { /* Either mounted or no locks... */ if (dl->dl_Task == NULL) printf(": no locks\n"); else printf(": mounted\n"); } free(name); } dl = BPTR_TO_C(DeviceList, dl->dl_Next); } Permit(); /* Multi-tasking now back on */ free(fi); exit(0); } /* * Traverse the linked lists of locks, counting them and printing out their * corresponding filesystem names. */ void CountLocks(list, fi, mylock) struct FileLock *list; /* the linked list to run through */ struct FileInfoBlock *fi; /* area for Examine */ struct FileLock *mylock; /* this one's ours */ { register struct FileLock *lptr; register int count = 0; short Examine(); for(lptr=list;lptr != NULL; lptr= BPTR_TO_C(FileLock,lptr->fl_Link)){ if (lptr == mylock) continue; if (Examine(C_TO_BPTR(lptr), fi) == FALSE) { /* Clicked Cancel on system requester ? */ printf("\n\tCannot deduce filename for lock"); } else { printf("\n\t%s", fi->fib_FileName); } count++; } if (count > 0) printf("\nTotal: %d lock(s)\n", count); else printf(": no locks\n"); } /* * Convert a BCPL string to a C string. To avoid scrogging in-memory * stuff, it malloc's off a copy first. */ char * btocstr(b) ULONG b; { register char *p, *s; void *malloc(); s = (char *)BADDR(b); /* Shift & get length-prefixed str */ if ((p = malloc(s[0])) != NULL) { (void)movmem(s +1, p, s[0]); /* Aztec memcpy */ p[s[0]] = '\0'; } return p; } ---- -- ---------------------------------------------------------------------- Dewi Williams. uucp: ..!ihnp4!druca!dewi phone: (303) 538 4884