ramdisk1of1 - RAM Disk Driver for UNIX on the PC

Berny Goodheart berny at tndsyd.oz.au
Thu Apr 11 20:41:16 AEST 1991


This is a ram disk for UNIX System V.2 or UNIX System V.3 systems
It has been specifically written for the 286/386 PC versions of UNIX
in particular it has been tested on the following versions (mainly
because I can't get to other versions):

Microport:		System V/AT 286 All Versions
			System V/386	All Versions
Bell Technology:	UNIX System V Release 3.0
Interactive Systems:	386/ix 3.2

However, the driver is pretty generic and should not take much
modification to work on other TRUE AT&T type UNIXes.

It has been used extensively by a number of users since 1987 with
few if any problems, but I will keep watch in comp.sources.bugs
for any feedback.

If anyone changes or modifies this code please send me the details so
that I can pass it on to everyone else. Also I should like to here
about other systems it has been ported to other than those mentioned above.

INSTALLING:
	Well I have to say that since there are so many 286/386/486
	versions of UNIX/XENIX etc on the market I cannot give
	installation details for each. So it's RTFM I am afraid. Read
	the section in your documentation on how to install device drivers.

------------------CUT HERE------------------------------------------------
# This is a shell archive.  Remove anything before this line
# then unpack it by saving it in a file and typing "sh file"
# (Files unpacked will be owned by you and have default permissions).
# This archive contains the following files:
#	./ram.7
#	./ram.c
#	./ram.h
#	./raminit
#	./raminit.1m
#	./ramstat.1m
#	./ramstat.c
#	./ramtab
#	./README
#
if `test ! -s ./ram.7`
then
echo "writing ./ram.7"
cat > ./ram.7 << '\gux-shar\'
.TH RAM 7 
.SH NAME
.B ram
\- memory resident disk interface
.SH DESCRIPTION
The memory resident disk (ram disk) uses a portion of the available
user memory as a pseudo device configured as far as the user is
concerned, the same as a normal file system. Files are accessed via
the system's normal buffering mechanism and may be read and written
to in the normal way. A raw interface is also provided for direct
serial transmission between the ram disk and the users buffer.
.PP
.PP
.SH RAW INTERFACE
Special filename          semantics.
.br
/dev/ctrlram              control interface
.br
/dev/rdsk/ram0            ram disk 0
.br
/dev/rdsk/ram1            ram disk 1
.br
/dev/rdsk/ram2            ram disk 2
.br
/dev/rdsk/ram3            ram disk 3
.br
.SH BLOCK INTERFACE
/dev/dsk/ram0             ram disk 0
.br
/dev/dsk/ram1             ram disk 1
.br
/dev/dsk/ram2             ram disk 2
.br
/dev/dsk/ram3             ram disk 3
.br
.PP
.SH AUTHOR
B.M.Goodheart 
\gux-shar\
else
  echo "will not over write ./ram.7"
fi
if `test ! -s ./ram.c`
then
echo "writing ./ram.c"
cat > ./ram.c << '\gux-shar\'

/*
 *
 *  @(#)ram.c	2.6 Copyright (C) B.M.Goodheart 1987, 1888, 1989, 1991 
 *
 *
 *
 *  		      DISCLAIMER OF WARRANTY. 
 *  This software is distributed "as is" and without warranties as to 
 *  performance of merchantability or any other warranties whether expressed 
 *  or implied. In no event shall the author (the copyright holder) be held 
 *  liable for any loss of profit or any other commercial damage resulting 
 *  from the use or misuse of this software, including but not limited to 
 *  special, incidental, consequential or other damages.  The user must 
 *  assume the entire risk of using this software.
 *
 *
 *			LISCENSE AGREEMENT
 *	This software is placed	into the public domain and 
 *	may be copied or distributed freely provided no profit or 
 *	gain is made and is used for personal use only and the code 
 *	as distributed retains all copyright notices in the code. 
 *	This includes any copyright statements in the target
 *	binary and executable code produced from the distributed source. 
 *
 *
 *	                DISTRIBUTION NOTE
 * 	This file contains the code for a RAM disk driver for UNIX System 5.2
 *	and System V.3.	It has been designed specifically for Microport's 
 *	System V/AT iAPX286 and Interactive Systems V/386 i386 systems
 * 	but should work with other PC based System V.? ports with only 
 *	minor modifications, specifically the BUFSEL selector on the 80286.
 *	This driver should work on any V.3 implementation on a PC. 
 *
 *
 *	               IMPORTANT NOTE !!!
 *	Any files or data stored within the ram disks will be 
 *	LOST FOR EVER if the system is brought down for ANY reason.
 *
 *	There are also two other programs distributed associated 
 *	with the driver, they are ramstat(1M) and raminit(1M). 
 *	These are used to control the ram disk driver in user mode 
 *	See also ram(7).
 *
 *	Berny Goodheart (berny at tndsyd.oz@munnari.oz.au)
 *
 * Modifications:
 *	20-10-87 (001)	The ramsize array would still hold the ram
 *			size even if could not get memory. This has
 *			now been fixed, variable is now zerod.
 *
 *	23-10-88 (002)	Reduced ambiguouse code, now drops through
 *			to the same statements. (reduces object size)
 *
 *	23-10-88 (003)	malloc() returns 0 not NULL (who cares)
 *
 *	12-11-88 (004)  fixed a really big bug, god knows how it
 *			worked in the first place. basically, almost
 *			all the routines that made reference to
 *			'dev' as passed to the sysentry call
 *			where using the raw data, now uses minor(dev)
 *			to extraxt the device index proper.
 *
 *	19-06-89 (005)  this mod is huge, basically I have added
 *			a switch to the compiler "i386" which will
 *			create the driver for System V.3. The difference
 *			to V.2 is quite large in that the two systems
 *			have different memory managment, V.3 uses Page Tables
 *			to map physical memory to kernel virtual memory.
 *
 *	20-06-89 (006)  fixed the character read overrun which used to
 *			to panic the system.
 *
 *      07-07-89 (007)  fixed the block count overrun check algorithm in
 *                      the strategy routine.
 *
 *	09-08-89 (008)  Added a few macros so that the code is
 *                      easier to read.
 *
 *	30-11-89 (009)  forgot to add the strategy print routine
 *                      Now the system tells you when you run out of
 *                      space in a ram disk.
 */

static char *bmgid = 
     "RAM disk 2.6-(%s) Copyright (C) Berny Goodheart 4/11/91\n";

#include <sys/errno.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/signal.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/file.h>
#include <sys/sysmacros.h>
#include <sys/map.h>
#include <sys/buf.h>
#include <sys/ram.h>			/* header file for this driver  */



#define DSK_PHYS_BLOCK	512		/* bytes in a physical disk block */

#define devnum(bp)	minor((bp)->b_dev) /* gets the minor device number */
#define blknum(bp)	((bp)->b_blkno)	   /* block offset for I/O */
#define RADDR(d)	(ramadd[minor(d)])
#define ROPEN(d)	(ram_opened[minor(d)])
#define RSTAT(d)	(ram_state[minor(d)])
#define RSIZE(d)	(ramsize[minor(d)])

#ifndef i386 				/* (008) */
#include <sys/mmu.h>			/* for BUFSEL selector */
caddr_t mapin();
#define  raddr_t	paddr_t
#define diskblk(x)	(ctob(x))
#define blktophys(bp)	(ctob(ramadd[devnum(bp)]) + diskblk(blknum(bp)));
static char *machtype = "iAPX286";
#else
#include <sys/immu.h>
#include <sys/cmn_err.h>
#define mapin(a,b)	(a)		/* emulate V.2 MMU stuff */
#define raddr_t		caddr_t
#define diskblk(x)	(x * DSK_PHYS_BLOCK)
#define blktophys(bp)	(ramadd[devnum(bp)] + diskblk(blknum(bp)));
static char *machtype = "iAPX386";
#endif

static raddr_t ramadd[NRDEVS];		/* base address of ram disk	*/
static int ram_opened[NRDEVS];		/* number of processes sleeping */
static int ram_state[NRDEVS];		/* current ram state		*/
static int ramDebug = 0;		/* debug static flag, 0 = off   */
static char busywait = 0;		/* sleeping processes           */

/*
 * ramsize[n] = holds the size of ram disk in physical memory blocks
 *
 * NOTE on i386 machines
 *      a physical block must be on a 4k boundry i.e 1 block = 4096 bytes
 * 	on iAPX286 machines a physical block is 512 bytes
 * 
 */
static int ramsize[NRDEVS];		




/* 
 * This routine is called whenever a process calls the system
 * call 'open' on this device
 *
 */
ramopen(dev)
{

	busywait++;
	(ROPEN(dev))++;

	if(ramDebug) 
		(void)printf("Ram-[%d] opened by uid-[%d]\n"
			,minor(dev)
			,u.u_ruid);

	/*
	 *
	 * Mask out any other opens while we are busy.
	 * The kernel does not experience any further CPU
	 * work while this happens, the process is simply
	 * put to sleep and added to the process que until 
	 * awoken later..
	 *
	 */
	while(busywait != 1)	/* mask out ram_opened opens */
		(void)sleep((caddr_t)&busywait, PRIBIO + 1);

	/* 
	 *
	 * Is it a valid device 
	 *
	 */
	if(minor(dev) < 0 || minor(dev) > (NRDEVS - 1)) 
		u.u_error = ENODEV; /* (002) */

	/*
	 * wakeup any pending I/O
	 *
	 */
	busywait--;
	(void)wakeup((caddr_t)&busywait);
}



ramclose(dev)
{
	ROPEN(dev) = 0; /* only called on last close */
}


/*
 * strategy routine is called by both character and block
 * drivers to do the I/O.
 */
ramstrategy(bp)
struct buf *bp;
{
	raddr_t physdr;

	/*
	 *
	 * If we slip up with deletion of the ram
	 * disk for some reason and we get here somehow,
	 * then this check will stop any reads 
	 * or writes to possibly now unassigned memory.
	 *
	 */
	if(ram_state[devnum(bp)] == RAM_CLOSED) {
		bp->b_error = EIO;
		bp->b_flags |= B_ERROR;
		bp->b_resid = bp->b_bcount;
		(void)iodone(bp);
		return;
	}


	/* 
	 *
	 * check its a legal block (007)
	 *
	 */
#if i386
	if((diskblk(blknum(bp))+bp->b_bcount)>=(ramsize[devnum(bp)] * PTSIZE)) {
#else
	if(diskblk(blknum(bp)) >= diskblk(ramsize[devnum(bp)])) {
#endif
		if(bp->b_flags & B_READ) 
			bp->b_error = EIO;
		else
			bp->b_error = ENOSPC;
		bp->b_flags |= B_ERROR;
		bp->b_resid = bp->b_bcount;
		(void)iodone(bp);
		return;
	}


	/* 
	 * work out which block number in the mapped in RAM array
	 * and convert to a physical address.
	 */
	physdr = blktophys(bp);



	/*
	 * If debug is set then send out to the console
	 *
	 */
	if(ramDebug) 
		(void)printf("Ram%d: blk-[%ld] addr-[0x%lx] bytes-[%d] %s\n"
			,devnum(bp)
			,blknum(bp)
			,physdr
			,bp->b_bcount
			,bp->b_flags & B_READ ? "Read" : "Write");
	

	/*
	 * Do the physical memory transfer I/O
	 */
	if(bp->b_flags & B_READ) 
		(void)bcopy(mapin(physdr,BUFSEL),bp->b_un.b_addr,bp->b_bcount);
	else 
		(void)bcopy(bp->b_un.b_addr,mapin(physdr,BUFSEL),bp->b_bcount);


	/*
	 * because bcopy() does not return anything
	 * we assume all bytes where copied and there is
	 * none left in the buffer to transmit
	 */
	bp->b_resid = 0;


	/*
	 * All finished, free the buffer
	 */
	(void)iodone(bp);

}




/*
 * ramread
 *
 * Uses ramstrategy for RAW I/O 
 *
 */
ramread(dev)
int dev;
{
	(void)physio(ramstrategy,NULL,dev,B_READ);
}




/*
 * ramwrite
 *
 * Uses ramstrategy for RAW I/O 
 *
 */
ramwrite(dev)
int dev;
{
	(void)physio(ramstrategy,NULL,dev,B_WRITE);
}



/*
 * user interface to I/O control
 *
 */
ramioctl(dev, cmd, arg)
int dev, cmd;
union r_ramst *arg;
{
	register x;
	int intlevel;
#if i386
	caddr_t ptalloc();	/* page table allocation routine */

	/*
	 * Only super user can set or unset the
	 * ram disks.
	 *
 	 * NOTE: TCMEMINFO is only available on 386
	 */
	if((!suser()) && ((cmd != TCGETRAM) || (cmd != TCMEMINFO)) ) {
#else
	if((!suser()) && cmd != TCGETRAM) {
#endif
		u.u_error = EACCES;
		return;
	}


	switch(cmd) {
		case  TCSETRAM :
			/*
	 		 * This will usually be done by 'ramstat' (hopefully)
			 *
			 * If already open then return with errno
			 */
			if(RSTAT(dev) == RAM_OPEN) {
				u.u_error = EBUSY;
				return;
			}

			/*
			 * arg is the ram size in physical blocks
			 * with which to create the RAM disk.
			 */
			if(arg->r_arg < MINRAMSIZ) {
				u.u_error = EINVAL;
				return;
			}
			RSIZE(dev) = arg->r_arg;



			/*
			 * turn interrupts off
			 */
			intlevel = spl6();


			/* 
			 * Try to get memory
			 * 
			 */
#if i386
			if((RADDR(dev) = ptalloc(RSIZE(dev),
					PHYSCONTIG|NOSLEEP)) == 0) {
#else
			if((RADDR(dev)=malloc(coremap,RSIZE(dev)))== 0){
#endif
				RSIZE(dev) = 0; /* (001) */
				u.u_error = ENOMEM;
				(void)splx(intlevel);
				return;
			}
#ifndef i386 
			/*
			 *
			 * Clear the Memory clicks to zero's
			 *
			 * not needed on i386
			 */
			for (x = 0; x < RSIZE(dev); x++)
				(void)clearseg(RADDR(dev) + x);
#endif


			/*
			 *
			 * Initialization is complete at this point
			 * so set the ram_state flag.
			 *
			 */
			RSTAT(dev) = RAM_OPEN;

			(void)splx(intlevel);

			break;


		case  TCDELRAM :
			/*
			 * No point in deleting if we don't exist
			 *
			 */
			if(RSTAT(dev) == RAM_CLOSED) {
				u.u_error = ENXIO;
				return;
			}

			/*
			 * Cant delete the RAM disk if busy
			 *
			 */
			if(ROPEN(dev) > 1) {
				u.u_error = EBUSY;
				return;
			} else
				ROPEN(dev) = 0;


			/*
			 * Try to free up the memory
			 * else GOD HELP THE WORLD
			 *
			 */
			intlevel = spl6();
#if i386
			/*
 			 * uptfree() does not return anything
			 */
			(void)uptfree(RADDR(dev),RSIZE(dev));
#else
			if(mfree(coremap,RSIZE(dev), RADDR(dev)) == -1) 
				/*
				 * We have to panic here because if we
				 * can't free up the memmory then anything
				 * can happen. (possible hardware fault).
				 *
				 * praise be the lord 
				 */
				(void)panic("ram%d: memory de-allocation error",
					minor(dev));
#endif


			/*
			 * PHEW ! THAT WAS CLOSE
			 *
			 * Reset the parameters to zilch
			 * so that next initialization is setup ok.
			 *
			 */
			RSTAT(dev) = RAM_CLOSED;
			RADDR(dev) = 0;
			RSIZE(dev) = 0;
			(void)splx(intlevel);
			break;

		case  TCGETRAM :
			/*
			 * Get statistics about the RAM disks
			 *
			 */
			for(x = 0; x < NRDEVS;x++) {
				arg->r_rstat.r_dev[x] = x;
				arg->r_rstat.r_blks[x] = ramsize[x];
				arg->r_rstat.r_stat[x] = 
					ram_state[x] == RAM_OPEN ? 1 : 0 ;
				arg->r_rstat.r_opns[x] = ram_opened[x];
				arg->r_rstat.r_addr[x] = (paddr_t)ramadd[x];
				arg->r_rstat.r_dbg = ramDebug == 0 ? 0 : 1 ;
			}
			break;

		case  TCRAMDBG :
			/*
			 *
			 * Toggle ramDebug mode 
			 *
			 */
			ramDebug = ramDebug == 0 ? 1 : 0;
			arg->r_arg = ramDebug;
			break;

#if i386
		case  TCMEMINFO:
			/*
		 	 * obtain system memory stats
			 *
			 */
			arg->r_meminfo.r_maxmem = maxmem;
			arg->r_meminfo.r_freemem = freemem;
			break;
#endif

		default:
			u.u_error = EINVAL;
	}
}


/*
 * Initialize start up logo.
 * Done at system boot only
 *
 */
raminit()
{
	(void)printf(bmgid,machtype);
}


/*
 * Generic kernel print routine 
 * called on internal error in strategy
 * routine (009)
 */
ramprint(dev,s)
int dev;
char *s;
{
	(void)printf("%s on ram disk device %d\n", s, minor(dev));
}
\gux-shar\
else
  echo "will not over write ./ram.c"
fi
if `test ! -s ./ram.h`
then
echo "writing ./ram.h"
cat > ./ram.h << '\gux-shar\'
/*
 *
 *  @(#)ram.h	2.5 Copyright (C) B.M.Goodheart 1987, 1888, 1989, 1991 
 *
 *
 *
 *  		      DISCLAIMER OF WARRANTY. 
 *  This software is distributed "as is" and without warranties as to 
 *  performance of merchantability or any other warranties whether expressed 
 *  or implied. In no event shall the author (the copyright holder) be held 
 *  liable for any loss of profit or any other commercial damage resulting 
 *  from the use or misuse of this software, including but not limited to 
 *  special, incidental, consequential or other damages.  The user must 
 *  assume the entire risk of using this software.
 *
 *
 *			LISCENSE AGREEMENT
 *	This software is placed	into the public domain and 
 *	may be copied or distributed freely provided no profit or 
 *	gain is made and is used for personal use only and the code 
 *	as distributed retains all copyright notices in the code. 
 *	This includes any copyright statements in the target
 *	binary and executable code produced from the distributed source. 
 *
 *
 *	                DISTRIBUTION NOTE
 * 	This file contains the code for a RAM disk driver for UNIX System 5.2
 *	and System V.3.	It has been designed specifically for Microport's 
 *	System V/AT iAPX286 and Interactive Systems V/386 i386 systems
 * 	but should work with other PC based System V.? ports with only 
 *	minor modifications, specifically the BUFSEL selector on the 80286.
 *	This driver should work on any V.3 implementation on a PC. 
 *
 *
 *	               IMPORTANT NOTE !!!
 *	Any files or data stored within the ram disks will be 
 *	LOST FOR EVER if the system is brought down for ANY reason.
 *
 *	There are also two other programs distributed associated 
 *	with the driver, they are ramstat(1M) and raminit(1M). 
 *	These are used to control the ram disk driver in user mode 
 *	See also ram(7).
 *
 *	Berny Goodheart (berny at tndsyd.oz@munnari.oz.au)
 *
 */

#define RAM_CLOSED	0
#define RAM_OPEN	1

#define RAMIO		('R'<<8)
#define TCSETRAM	(RAMIO|1)
#define TCDELRAM	(RAMIO|2)
#define TCGETRAM	(RAMIO|3)
#define TCRAMDBG	(RAMIO|4)
#if i386
#define TCMEMINFO	(RAMIO|5)
#endif


#define NRDEVS		4		/* max number of devs	      */

/*
 * NOTE on the i386 machine
 * a block is 4096 bytes
 * on the iAPX286 it is 512 bytes
 *
 * min number of blks/ram disk for a 32k ram disk
 *
 */
#if i386
#define MINRAMSIZ	8
#else
#define MINRAMSIZ	64
#endif

/* union for use by all ramdisk drive ioctl calls */
union r_ramst {
	int 	r_arg;

	/*
	 * Ram device status structure
	 */
	struct {
		int		r_dev[NRDEVS];	/* index to device	*/
		int		r_blks[NRDEVS];	/* physical block count */
		dev_t		r_stat[NRDEVS];	/* open or closed	*/
		int		r_opns[NRDEVS];	/* # of opens	  	*/
		int		r_addr[NRDEVS];	/* mapin memory addr	*/
		dev_t		r_dbg;		/* debug on or off	*/
	}r_rstat;
	
#if i386
	/*
	 * r_meminfo is used to request system wide 
	 * memory information using TCMEMINFO as the ioctl arg
	 * NOTE: not available on 80286
	 *
	 */
	struct {
		ulong		r_maxmem;	/* total system mem     */
		ulong		r_freemem;	/* available mem        */
	} r_meminfo;	
#endif
};


\gux-shar\
else
  echo "will not over write ./ram.h"
fi
if `test ! -s ./raminit`
then
echo "writing ./raminit"
cat > ./raminit << '\gux-shar\'
:
#
# 
# 
#   @(#)raminit	1.5 Copyright (C) B.M.Goodheart 1987, 1888, 1989, 1991 
# 
# 
# 
#   		      DISCLAIMER OF WARRANTY. 
#   This software is distributed "as is" and without warranties as to 
#   performance of merchantability or any other warranties whether expressed 
#   or implied. In no event shall the author (the copyright holder) be held 
#   liable for any loss of profit or any other commercial damage resulting 
#   from the use or misuse of this software, including but not limited to 
#   special, incidental, consequential or other damages.  The user must 
#   assume the entire risk of using this software.
# 
# 
# 			LISCENSE AGREEMENT
# 	This software is placed	into the public domain and 
# 	may be copied or distributed freely provided no profit or 
# 	gain is made and is used for personal use only and the code 
# 	as distributed retains all copyright notices in the code. 
# 	This includes any copyright statements in the target
# 	binary and executable code produced from the distributed source. 
# 
# 
# 	                DISTRIBUTION NOTE
#  	This file contains the code for a RAM disk driver for UNIX System 5.2
# 	and System V.3.	It has been designed specifically for Microport's 
# 	System V/AT iAPX286 and Interactive Systems V/386 i386 systems
#  	but should work with other PC based System V.? ports with only 
# 	minor modifications, specifically the BUFSEL selector on the 80286.
# 	This driver should work on any V.3 implementation on a PC. 
# 
# 
# 	               IMPORTANT NOTE !!!
# 	Any files or data stored within the ram disks will be 
# 	LOST FOR EVER if the system is brought down for ANY reason.
# 
# 	There are also two other programs distributed associated 
# 	with the driver, they are ramstat(1M) and raminit(1M). 
# 	These are used to control the ram disk driver in user mode 
# 	See also ram(7).
# 
# 	Berny Goodheart (berny at tndsyd.oz@munnari.oz.au)
# 
#
# initialise or remove ram disks ( reads /etc/ramtab )
#
#

trap "echo Interrupt ignored" 1 2 3 15

RAMRC=/etc/ramtab
view=0

if test $# -lt 1 
then
	echo "Usage: raminit -ir [ -v ]"
	exit
fi

if test $# -eq 2
then 
	if [ "$2" != "-v" ]
	then
		echo "Usage: raminit -ir [ -v ]"
		exit
	fi
	view=1
fi

case $1 in
	"-v")
		echo "Usage: raminit -ir [ -v ]"
		exit
		;;
	"-i")

		for x in `/bin/cat $RAMRC | /bin/grep "^\/"`
		do
			block=
			raw=
			size=
			inodes=
			label=
			mnt=
			rnum=

			block=`/bin/echo $x | /usr/bin/awk -F: '{print $1}'`
			raw=`/bin/echo $x | /usr/bin/awk -F: '{print $2}'`
			size=`/bin/echo $x | /usr/bin/awk -F: '{print $3}'`
			inodes=`/bin/echo $x | /usr/bin/awk -F: '{print $4}'`
			label=`/bin/echo $x | /usr/bin/awk -F: '{print $5}'`
			mnt=`/bin/echo $x | /usr/bin/awk -F: '{print $6}'`
			rnum=`/bin/echo $x | /usr/bin/awk -F: '{print $7}'`


			if [ "$rnum" = "" ]
			then
				echo "$0: error in /etc/ramtab, can't continue"
				exit 1
			fi

			# test if the driver is already open
			ramstat -n${rnum} | grep open > /dev/null
			if [ $? = 0 ]
			then
				continue
			fi

			if test -f $mnt/*
			then
				echo "$0: cannot mount on \"$mnt\", directory is not empty"
				continue
			elif test ! -d $mnt
			then
				echo "$0: Directory \"$mnt\" does not exist, entry ignored"
				continue
			else
				:
			fi

			if [ "$block" = "" ]
			then
				echo "$0: Block device not specified, entry ignored"
				continue
			fi

			if [ "$raw" = "" ]
			then
				echo "$0: Raw device not specified, entry ignored"
				continue
			fi

			if [ "$size" = "" ]
			then
				echo "$0: Device size not specified, entry ignored ***"
				continue
			fi

			if [ $view = 1 ]
			then
				echo "Trying for Space for $size * \c"
				if i386
				then
					echo "4k byte blocks"
				else
					echo "1k byte blocks"
				fi
			fi

			# test if we have enough space
			/bin/ramstat -i $size $raw
			if [ $? != 0 ]
			then
				exit
			fi

			echo "Please Wait ...."

			if i386
			then
				size=`expr ${size} \* 4096`
				size=`expr ${size} / 1024`
				inodes=`expr ${size} / 10`
			fi

			if [ $view = 1 ]
			then
				echo "Making file system on $block"
				echo "size = $size, inodes = $inodes\n"
			fi

			/etc/mkfs $block $size:$inodes > /dev/null
			if [ "$label" != "" ]
			then
				if [ "$mnt" != "" ]
				then
					j=`basename $mnt`
					if [ $view = 1 ]
					then
						echo "Labeling file system $label\n"
					fi
					/etc/labelit $block ${j} $label > /dev/null
				fi
			fi

			/etc/fsck $block
			if [ "$mnt" != "" ]
			then
				if [ $view = 1 ]
				then
					echo "\nMounting file system on $mnt\n"
				fi
				/etc/mount $block $mnt
			fi
		done
		;;
	"-r")
		ramstat | grep open > /dev/null
		if [ $? != 0 ]
		then
			exit
		fi

		for x in `/bin/cat $RAMRC | /bin/grep "^\/"`
		do
			block=
			raw=
			mnt=
			rnum=

			block=`/bin/echo $x | /usr/bin/awk -F: '{print $1}'`
			raw=`/bin/echo $x | /usr/bin/awk -F: '{print $2}'`
			mnt=`/bin/echo $x | /usr/bin/awk -F: '{print $6}'`
			rnum=`/bin/echo $x | /usr/bin/awk -F: '{print $7}'`

			if [ "$rnum" = "" ]
			then
				echo "$0: error in /etc/ramtab, can't continue"
				exit 1
			fi

			# test if the driver is open
			ramstat -n${rnum} | grep open > /dev/null
			if [ $? != 0 ]
			then
				continue
			fi

			if [ "$block" = "" ]
			then
				echo "$0: Block device not specified, entry ignored ***"
				continue
			fi

			if [ "$raw" = "" ]
			then
				echo "$0: Raw device not specified, entry ignored ***"
				continue
			fi

			if [ "$mnt" = "" ]
			then
				/bin/ramstat -r $block $raw
			else
				if /etc/umount $block 
				then
					/bin/ramstat -r $block $raw
				fi
			fi
		done
		;;
	*) /bin/echo "$0: illegal option $1" ;;
esac

\gux-shar\
else
  echo "will not over write ./raminit"
fi
if `test ! -s ./raminit.1m`
then
echo "writing ./raminit.1m"
cat > ./raminit.1m << '\gux-shar\'
.TH RAMINIT 1M
.SH NAME
.B raminit
\- memory resident disk interface control script
.SH SYNOPSIS
.B raminit -ri [ -v ]
.SH DESCRIPTION
.B Raminit
is the control script program used to configure the Ram disk device.
It reads the file
.B /etc/ramtab
to find out how to configure the ram disks.
.PP
The ram disk interface allows up to 4 ram disks to be resident in
memory at any one time. 
.PP
.B Raminit
sets up the ram disks via 
.B /bin/ramstat
and then runs 
.B mkfs(1M)
and
.B fsck(1M)
to create the file systems and check them before using
.B mount(1M)
to mount them accordingly.
.PP
The option 
.B -i 
is used to initiate the ram disks, while the
option 
.B -r 
is used to delete them, 
.B -v 
is an optional
parameter which turns verbose mode on (default is off).
.PP
Deleting the ram disks frees up memory allowing it to be used 
again by user programs.
.PP
The structure of the file
.B /etc/ramtab 
is as follows:
.P
.TP 16
.B field 1
The Block device path name.
.br
.TP 16
.B field 2
The Raw device path name.
.br
.TP 16
.B field 3
The size in blocks of the ram disk.
.br
.TP 16
.B field 4
The number of inodes for the new file system.
.br        
.TP 16
.B field 5
File system label.
.br
.TP 16
.B field 6
The name of the empty directory to mount the file system on to.
.br
.TP 16
.B field 7
The minor number of the ramdisk associated with the new file system.
.PP
Each field is separated by a ':' character.
.SH EXAMPLES
.PP
.ti+6
/dev/dsk/ram0:/dev/rdsk/ram0:750:200:tmp:/tmp:0:
.PP
This 
.B ramtab
entry is used by
.B raminit
to create a ram disk using the block special file
.B /dev/dsk/ram0
and the character special file 
.B /etc/rdsk/ram0,
of 750 physical blocks of memory, construct a file
sytem with 200 inodes and label it tmp, mount the new
file system onto /tmp, using minor device 0.
.SH FILES
/dev/ctrlram
.br
/dev/rdsk/ram?
.br
/dev/dsk/ram?
.br
/dev/console
.br
/etc/ramtab
.br
/bin/ramstat
.SH SEE ALSO
fs(4),mkfs(1M),fsck(1M),mount(1M),labelit(1M),ramstat(1M)
.SH AUTHOR
B.M.Goodheart 

\gux-shar\
else
  echo "will not over write ./raminit.1m"
fi
if `test ! -s ./ramstat.1m`
then
echo "writing ./ramstat.1m"
cat > ./ramstat.1m << '\gux-shar\'
.TH RAMSTAT 1M
.SH NAME
.B ramstat
\- memory resident disk interface control
.SH SYNOPSIS
.B ramstat 
.br
.B ramstat -n#
.br
.B ramstat -m
.br
.B ramstat -d
.br
.B ramstat -i blocks  char_special
.br
.B ramstat -r block_special char_special
.SH DESCRIPTION
.B Ramstat
is the control program used to configure or get information from
the kernel about the Ram disk devices.
.PP
The meaning of the options are:
.br
.PP
.TP 8
.B -n#
Display statistics on the standard output of a ramdisk,
where '#' represents the minor number associated with the driver,
.TP 8
.B -m
Display statistics on the standard output of current
available memory resources. This option is not available on
80286 processors.
.TP 8
.B -d
Toggles debug mode.
.TP 8
.B -i
This parameter takes a further two arguments; the
block number being the number of physical blocks
to configure the ram disk with and the ram disk 
raw interface path name.
.PP
.RS 8
This option is used to configure the ram disk 
before building a file system on it.
.RE
.TP 8
.B -r
This parameter also requires a further two 
arguments; the path names of the raw and block 
interface files. This option is used to delete 
the ram disk from existence freeing up memory. 
This option will cause ramstat to fail if 
the ram disk contains a currently mounted 
file system.
.PP
If invoked with no parameters then 
.I ramstat 
will display status
information about all of the ramdisks on the standard output.
.PP
The meaning of the column headings are as follows:
.PP
RAM       The ramdisk minor number.
.PP
BLOCKS    The number of physical blocks the ram disk 
          was configured with.
.PP
STATE     The current state of the ram disk open or closed.
.PP
OPENS     The number of processes currently holding the
          ramdisk open.
.PP
ADDR      The physical base address in Hex of the ram disk
          in memory.
.PP
The state of the debug mode is also displayed.
.PP
It is better to use the script 
.I raminit
to invoke the -i and -r options. Raminit invokes 
.I ramstat
in the long run any way. If 
.I ramstat
is invoked in this way
it is possible to enter a single line in the /etc/rc file
to configure the ram disks at system boot time.
.SH FILES
/dev/ctrlram
.br
/dev/rdsk/ram?
.br
/dev/dsk/ram?
.br
/dev/console
.SH SEE ALSO
fs(4),mkfs(1M),fsck(1M),volcopy(1M),raminit(1M)
.SH AUTHOR
B.M.Goodheart
\gux-shar\
else
  echo "will not over write ./ramstat.1m"
fi
if `test ! -s ./ramstat.c`
then
echo "writing ./ramstat.c"
cat > ./ramstat.c << '\gux-shar\'
/*
 *
 *  @(#)ramstat.c	1.5 Copyright (C) B.M.Goodheart 1987, 1888, 1989, 1991 
 *
 *
 *
 *  		      DISCLAIMER OF WARRANTY. 
 *  This software is distributed "as is" and without warranties as to 
 *  performance of merchantability or any other warranties whether expressed 
 *  or implied. In no event shall the author (the copyright holder) be held 
 *  liable for any loss of profit or any other commercial damage resulting 
 *  from the use or misuse of this software, including but not limited to 
 *  special, incidental, consequential or other damages.  The user must 
 *  assume the entire risk of using this software.
 *
 *
 *			LISCENSE AGREEMENT
 *	This software is placed	into the public domain and 
 *	may be copied or distributed freely provided no profit or 
 *	gain is made and is used for personal use only and the code 
 *	as distributed retains all copyright notices in the code. 
 *	This includes any copyright statements in the target
 *	binary and executable code produced from the distributed source. 
 *
 *
 *	                DISTRIBUTION NOTE
 * 	This file contains the code for a RAM disk driver for UNIX System 5.2
 *	and System V.3.	It has been designed specifically for Microport's 
 *	System V/AT iAPX286 and Interactive Systems V/386 i386 systems
 * 	but should work with other PC based System V.? ports with only 
 *	minor modifications, specifically the BUFSEL selector on the 80286.
 *	This driver should work on any V.3 implementation on a PC. 
 *
 *
 *	               IMPORTANT NOTE !!!
 *	Any files or data stored within the ram disks will be 
 *	LOST FOR EVER if the system is brought down for ANY reason.
 *
 *	There are also two other programs distributed associated 
 *	with the driver, they are ramstat(1M) and raminit(1M). 
 *	These are used to control the ram disk driver in user mode 
 *	See also ram(7).
 *
 *	Berny Goodheart (berny at tndsyd.oz@munnari.oz.au)
 *
 * The user program /etc/ramstat is used to initialise the RAM disk
 *
 *		-i	Initialise the RAM disk.
 *		-r	Delete and remove the RAM disk and all its contents
 *		-d	toggle debug mode on or off
 *		-n#	display stats of ram disk '#'
 *		-m	get system memory info (i386) only
 *
 *
 */


static char *bmgid = "@(#)ramstat.c	1.5 Copyright (C) Berny Goodheart 4/11/91";
#include <sys/types.h>
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ram.h>

static int size;
static int fd;
char devnam[128];
extern int errno;
static int ramnum;

union r_ramst state;

#if i386
#define pdetophys(x)	(x * 4096)
#endif

trap()
{
	signal(SIGINT,trap);
	if(fd > 0)
		close(fd);
	printf("Aborted\n");
	exit(0);
}

main(argc,argv)
int argc;
char *argv[];
{

	signal(SIGINT,trap);
	ramnum = -1;

	/*
 	 * Allow users to get stats
	 */
	if(argc != 1)
		setuid(getuid());

	if((fd = open("/dev/ctrlram",O_WRONLY)) == -1){
		perror("/dev/ctrlram");
		exit(1);
	} 

	if(argc == 1) {
		ramstat(fd,TCGETRAM);
		exit(0);
	}


	if(argv[1][0] != '-')
		usage();

	switch (argv[1][1]) {
#if i386
		case 'm':
			if(argc != 2)
				usage();
			ramstat(fd,TCMEMINFO);
			break;
#endif
		case 'n':
			if(isdigit(argv[1][2])) {
				ramnum = atoi(&argv[1][2]);
				ramstat(fd,TCGETRAM);
			} else usage();
			break;
		case 'd':
			if(argc != 2)
				usage();
			ramstat(fd,TCRAMDBG);
			break;
		case 'r':
			if(argc != 4)
				usage();
			close(fd);
			if((fd = open(argv[2],O_WRONLY)) == -1){
				perror(argv[2]);
				exit(1);
			} 
			close(fd);
			if((fd = open(argv[3],O_WRONLY)) == -1){
				perror(argv[3]);
				exit(1);
			}
			strcpy(devnam,argv[3]); 
			if(umount(argv[2]) == -1) {
				if(errno != EINVAL) {
					perror(argv[2]);
					exit(1);
				}
			}
			ramstat(fd,TCDELRAM);
			break;
		case 'i':
			if(argc != 4)
				usage();
			close(fd);
			if((fd = open(argv[3],O_WRONLY)) == -1){
				perror(argv[3]);
				exit(1);
			}
			strcpy(devnam,argv[3]); 
			if((size = atoi(argv[2])) < 20) {
				fprintf(stderr,"ramstat: illegal block size\n");
				exit(1);
			}
			ramstat(fd,TCSETRAM);
			break;
		default :
			usage();
	}
	close(fd);
	exit(0);
}

ramstat(fd,mode)
int fd, mode;
{
	int x,m;
	
	switch(mode) {
#if i386
		case TCMEMINFO:
			if((x = ioctl(fd,TCMEMINFO,&state)) != -1)
				printf("maxmem %ld\nfreemem %ld\n",
					pdetophys(state.r_meminfo.r_maxmem),
					pdetophys(state.r_meminfo.r_freemem));
			break;
#endif
		case TCDELRAM:
			if((x = ioctl(fd,TCDELRAM,0)) != -1)
				printf("Ram disk %s closed\n",devnam);
			break;
		case TCSETRAM:
			state.r_arg = size;
			if((x = ioctl(fd,TCSETRAM,&state)) != -1) 
				printf(
				"\nRam disk (%s) initialized (%d Physical Blocks)\n\n"
					,devnam,size);
			break;
		case TCRAMDBG:
			if((x = ioctl(fd,TCRAMDBG,&state)) != -1) 
				printf("Ram disk debug mode %s\n",
					state.r_arg == 0 ? "OFF" : "ON");
			break;
		case TCGETRAM:
			if((x = ioctl(fd,TCGETRAM,&state)) != -1) {
			if(ramnum == -1)
				printf("\n   RAM	BLOCKS	STATE	OPENS	ADDR\n");
			for(x = 0; x < NRDEVS;x++) {
				if(ramnum != -1 && ramnum != x)
					continue;
				printf(
				"   %d	%d	%s	%d	0x%x%c"
				,state.r_rstat.r_dev[x]
				,state.r_rstat.r_blks[x]
				,state.r_rstat.r_stat[x]
					== RAM_OPEN ? "open" : "closed"
				,(state.r_rstat.r_opns[x] 
					== 0 ? 0 : state.r_rstat.r_opns[x] -1)
				,state.r_rstat.r_addr[x]
				,(ramnum == -1 ? '\n' : ' '));
			}
			if(state.r_rstat.r_dbg != 0) {
				if(ramnum == -1)
					printf("\n  ");
				printf(" Debug ON");
			}
			putchar('\n');
			}/* if */

	}
	if(x < 0) {
		perror("ramstat");
		exit(1);
	}
	close(fd);
}


	
usage()
{
	fprintf(stderr,"Usage: ramstat\n"); 
	fprintf(stderr,"       ramstat -d\n");
	fprintf(stderr,"       ramstat -n#\n");
#if i386
	fprintf(stderr,"       ramstat -m\n");
#endif
	fprintf(stderr,"       ramstat -r  block_special  char_special\n");
	fprintf(stderr,"       ramstat -i  blocks  char_special\n");
	exit(1);
}

\gux-shar\
else
  echo "will not over write ./ramstat.c"
fi
if `test ! -s ./ramtab`
then
echo "writing ./ramtab"
cat > ./ramtab << '\gux-shar\'
#
# This file contains table information for the ram disk 
# configuration program called "raminit".
#
# See manual entries ramstat(1M), raminit(1M), ram(7)
#
# block_dev:char_dev:size:inodes:label:mount directory:driver minor
#
# NOTE: the 80386 uses 4096 bytes in a block so size
#	is n * 4096. The 80286 uses 512 byte blocks
#

# inodes and label are optional

/dev/dsk/ram0:/dev/rdsk/ram0:500:150:tmp:/tmp:0:
#/dev/dsk/ram1:/dev/rdsk/ram1:250:50:vbin:/vbin:1:
#/dev/dsk/ram0:/dev/rdsk/ram0:1500:100:tmp:/tmp:0:
#/dev/dsk/ram1:/dev/rdsk/ram1:500:100:ram1:/ram:1:
#/dev/dsk/ram2:/dev/rdsk/ram2:500::::2:
#/dev/dsk/ram3:/dev/rdsk/ram3:500::::3:
\gux-shar\
else
  echo "will not over write ./ramtab"
fi
if `test ! -s ./README`
then
echo "writing ./README"
cat > ./README << '\gux-shar\'


This is a ram disk for UNIX System V.2 or UNIX System V.3 systems
It has been specifically written for the 286/386 PC versions of UNIX
in particular it has been tested on the following versions (mainly
because I can't get to other versions):

Microport:		System V/AT 286 All Versions
			System V/386	All Versions
Bell Technology:	UNIX System V Release 3.0
Interactive Systems:	386/ix 3.2

However, the driver is pretty generic and should not take much
modification to work on other TRUE AT&T type UNIXes.

It has been used extensively by a number of users since 1987 with
few if any problems, but I will keep watch in comp.sources.bugs
for any feedback.

If anyone changes or modifies this code please send me the details so
that I can pass it on to everyone else. Also I should like to here
about other systems it has been ported to other than those mentioned above.

INSTALLING:
	Well I have to say that since there are so many 286/386/486
	versions of UNIX/XENIX etc on the market I cannot give
	installation details for each. So it's RTFM I am afraid. Read
	the section in your documentation on how to install device drivers.


\gux-shar\
else
  echo "will not over write ./README"
fi
echo "Finished archive 1 of 1"
# if you want to concatenate archives, remove anything after this line
exit



More information about the Comp.unix.sysv286 mailing list