[net.micro.amiga] How many locks have I left lying around?

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