diff -uNr linux-2.2.8-virgin/Documentation/Configure.help linux-2.2.8-initrd_arch/Documentation/Configure.help
--- linux-2.2.8-virgin/Documentation/Configure.help	Tue May 11 12:57:14 1999
+++ linux-2.2.8-initrd_arch/Documentation/Configure.help	Wed May 12 21:23:17 1999
@@ -215,6 +215,32 @@
   "real" root file system, etc. See Documentation/initrd.txt for
   details.
 
+Initial RAM disk archive (untar) support
+CONFIG_BLK_DEV_INITRD_ARCHIVE
+  This allows you to use a tar.gz archive instead of those nasty
+  raw images. To use this feature first create a blank raw image
+  of the correct size and fs that you want. Compress it with gzip
+  then pad it up to an even kB. Next combine the rawfs.gz file with
+  your root tar.gz. Spec this resulting file as the initrd image
+  the boot loader should load. Now spec the offset in kB from the
+  first to the second file with the kernel option initrd_archive=[int].
+  Confused? Good! Just use auto fs below unless you need something
+  besides a minix or ext2 filesystem for the initrd.
+  
+Initial RAM disk minix auto filesystem support
+CONFIG_BLK_DEV_INITRD_ARCHIVE_AUTOFS_MINIX
+  Specing initrd_archive=minix will have the kernel dynamically create
+  a minix filesystem on /dev/ram0 at boot time. No raw image is needed
+  at all. Spec a normal tar.gz file for the boot loader to load as the
+  initrd root archive. 
+
+Initial RAM disk ext2 auto filesystem support
+CONFIG_BLK_DEV_INITRD_ARCHIVE_AUTOFS_EXT2
+  Specing initrd_archive=ext2 will have the kernel dynamically create
+  an ext2 filesystem on /dev/ram0 at boot time. No raw image is needed
+  at all. Spec a normal tar.gz file for the boot loader to load as the
+  initrd root archive. 
+
 Loop device support
 CONFIG_BLK_DEV_LOOP
   Saying Y here will allow you to use a regular file as a block
diff -uNr linux-2.2.8-virgin/drivers/block/Config.in linux-2.2.8-initrd_arch/drivers/block/Config.in
--- linux-2.2.8-virgin/drivers/block/Config.in	Thu Apr 29 15:53:48 1999
+++ linux-2.2.8-initrd_arch/drivers/block/Config.in	Wed May 12 21:23:17 1999
@@ -112,6 +112,16 @@
 tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
 if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
   bool '   Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
+  if [ "$CONFIG_BLK_DEV_INITRD" = "y" ]; then
+     bool '      Initial RAM disk archive (untar) support' CONFIG_BLK_DEV_INITRD_ARCHIVE
+     if [ "$CONFIG_BLK_DEV_INITRD_ARCHIVE" = "y" ]; then
+        bool '         Initial RAM disk minix auto fs support' CONFIG_BLK_DEV_INITRD_ARCHIVE_AUTOFS_MINIX
+	if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	   bool '         Initial RAM disk ext2 auto fs support (broken!)' CONFIG_BLK_DEV_INITRD_ARCHIVE_AUTOFS_EXT2
+	fi	
+     fi
+  fi
+
 fi
 tristate 'XT hard disk support' CONFIG_BLK_DEV_XD
 
diff -uNr linux-2.2.8-virgin/drivers/block/rd.c linux-2.2.8-initrd_arch/drivers/block/rd.c
--- linux-2.2.8-virgin/drivers/block/rd.c	Thu Apr 29 14:53:41 1999
+++ linux-2.2.8-initrd_arch/drivers/block/rd.c	Wed May 12 21:31:33 1999
@@ -1,7 +1,8 @@
 /*
- * ramdisk.c - Multiple RAM disk driver - gzip-loading version - v. 0.8 beta.
- * 
- * (C) Chad Page, Theodore Ts'o, et. al, 1995. 
+ * ramdisk.c - Multiple ramdisk driver v. 0.9
+ *             gzip and initrd-archive version
+ *
+ * (C) Chad Page, Theodore Ts'o, et. al, 1995, 1996, 1998. 
  *
  * This RAM disk is designed to have filesystems created on it and mounted
  * just like a regular floppy disk.  
@@ -36,6 +37,33 @@
  * 4/25/96 : Made RAM disk size a parameter (default is now 4 MB) 
  *		- Chad Page
  *
+ * 1998-01-10 :        Added initrd-archive (untar) feature.
+ *	       Added initrd_archive_autofs feature (minix)
+ *	       Made initrd a bit more verbose at boot.
+ *	       Fixed a comment.  : >
+ *	       Dave Cinege <dcinege@psychosis.com>
+ *
+ * 1998-01-17 : These -
+ *	       static struct inode out_inode;
+ *	       static struct file outfile;
+ *	       Needed to be before
+ *	       #ifdef CONFIG_BLK_DEV_INITRD
+ *	       not after. Opps  : >
+ *
+ * Format of initrd-archive
+ *
+ *0x0000      gziped blank rawfs image (empty aside from filesystem info)
+ *  |	      pad with zero's up to this an even K. Pass this amount to the
+ *0x????      kernel via the boot loader. IE initrd_archive=15  (15KB file)
+ *------------------------------
+ *0x????+1    root tar.gz
+ *end
+ *
+ *auto fs dynamically creates a filesystem on /dev/ram0 at boot.
+ *No image is needed, only a normal tar.gz.
+ *Spec it with the same option IE initrd_archive=minix
+ *Only minix support right now. 
+ *
  * Add support for fs images split across >1 disk, Paul Gortmaker, Mar '98
  *
  * Make block size and block size shift for RAM disks a global macro
@@ -93,6 +121,9 @@
 void rd_load(void);
 static int crd_load(struct file *fp, struct file *outfp);
 
+static struct inode out_inode;
+static struct file outfile;
+
 #ifdef CONFIG_BLK_DEV_INITRD
 static int initrd_users = 0;
 #endif
@@ -122,6 +153,16 @@
 unsigned long initrd_start,initrd_end;
 int mount_initrd = 1;		/* zero if initrd should not be mounted */
 int initrd_below_start_ok = 0;
+#ifdef CONFIG_BLK_DEV_INITRD_ARCHIVE
+int initrd_archive = 0;
+static int untar(void);
+#ifdef CONFIG_BLK_DEV_INITRD_ARCHIVE_AUTOFS_MINIX
+static int mkminixfs(void);
+#endif
+#ifdef CONFIG_BLK_DEV_INITRD_ARCHIVE_AUTOFS_EXT2
+static int mkext2fs(void);
+#endif
+#endif
 #endif
 #endif
 
@@ -465,8 +506,8 @@
  */
 __initfunc(static void rd_load_image(kdev_t device, int offset, int unit))
 {
- 	struct inode inode, out_inode;
-	struct file infile, outfile;
+ 	struct inode inode;
+	struct file infile;
 	struct dentry in_dentry, out_dentry;
 	mm_segment_t fs;
 	kdev_t ram_device;
@@ -506,8 +547,52 @@
 
 	if (nblocks == 0) {
 #ifdef BUILD_CRAMDISK
-		if (crd_load(&infile, &outfile) == 0)
+	#ifdef CONFIG_BLK_DEV_INITRD_ARCHIVE
+		if (initrd_archive) {
+		
+			if (initrd_archive > 0) {
+			
+				printk(KERN_NOTICE
+				       "RAMDISK: Uncompressing filesystem image: ");
+			
+				//dc: uncompress first part of file to ram0
+				if (crd_load(&infile, &outfile) == 0) {
+   					printk("done.\n");
+				} else {
+   					printk("failed!\n");
+					goto done;
+				}	
+			
+				//dc: offset infile to where the tar.gz root starts	
+		       		infile.f_pos = (initrd_archive * 1024);
+			}
+			
+			//dc: get ram1 ready as outfile
+		       	ram_device = MKDEV(MAJOR_NR,1);
+			
+			memset(&outfile, 0, sizeof(outfile));
+			memset(&out_inode, 0, sizeof(out_inode));
+			memset(&out_dentry, 0, sizeof(out_dentry));
+			out_inode.i_rdev = ram_device;
+			outfile.f_mode = 3; /* read/write */
+			outfile.f_dentry = &out_dentry;
+			out_dentry.d_inode = &out_inode;
+
+			if (blkdev_open(&out_inode, &outfile) != 0) return;
+
+			printk(KERN_NOTICE
+			       "RAMDISK: Uncompressing root archive: ");
+		} else 
+	#endif
+			printk(KERN_NOTICE
+			       "RAMDISK: Uncompressing root image: ");
+
+		if (crd_load(&infile, &outfile) == 0) {
+  			printk("done.\n");
 			goto successful_load;
+		} else {
+  			printk("failed!\n");
+		}
 #else
 		printk(KERN_NOTICE
 		       "RAMDISK: Kernel does not support compressed "
@@ -576,9 +661,58 @@
 	invalidate_buffers(device);
 	ROOT_DEV = MKDEV(MAJOR_NR, unit);
 
+#ifdef CONFIG_BLK_DEV_INITRD_ARCHIVE   
+       //yes this block is ugly, but it should save a big chunk of memory since
+       //the initrd image (device) is invalidated before we fill /dev/ram0
+       if (initrd_archive < 0) {
+       
+	       ram_device = MKDEV(MAJOR_NR,0);
+		       
+	       memset(&outfile, 0, sizeof(outfile));
+	       memset(&out_inode, 0, sizeof(out_inode));
+	       memset(&out_dentry, 0, sizeof(out_dentry));
+	       out_inode.i_rdev = ram_device;
+	       outfile.f_mode = 3; /* read/write */
+	       outfile.f_dentry = &out_dentry;
+	       out_dentry.d_inode = &out_inode;
+	       
+	       if (blkdev_open(&out_inode, &outfile) != 0) return;
+	       
+
+	       printk(KERN_NOTICE "RAMDISK: Auto Filesystem - ");
+		       
+	       switch (initrd_archive) {
+	       
+		       case -1:
+		       #ifndef CONFIG_BLK_DEV_INITRD_ARCHIVE_AUTOFS_MINIX
+			       printk("kernel does not support minix auto fs!\n");
+			       goto done;
+		       #else
+			       mkminixfs();
+		       #endif
+			       break;
+		       case -2:
+		       #ifndef CONFIG_BLK_DEV_INITRD_ARCHIVE_AUTOFS_EXT2
+			       printk("kernel does not support ext2 auto fs!\n");
+			       goto done;
+		       #else
+			       mkext2fs();
+		       #endif
+			       break;
+		       default:
+			       printk("unknown fs specified!\n");
+			       break;
+	       }
+	       
+       }
+#endif
+
 done:
 	if (infile.f_op->release)
 		infile.f_op->release(&inode, &infile);
+	if (outfile.f_op->release)
+		outfile.f_op->release(&out_inode, &outfile);
+				
 	set_fs(fs);
 }
 
@@ -627,6 +761,41 @@
 {
 	rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0,0);
 }
+
+#ifdef CONFIG_BLK_DEV_INITRD_ARCHIVE
+__initfunc(void initrd_untar(void))
+{
+extern int untar(void);
+        untar();
+}
+
+
+__initfunc(void initrd_archive_setup(char *line, int *ints))
+{
+	if (!strncmp(line,"minix",5)) {
+			initrd_archive = -1;
+			return;
+	}
+			
+	if (!strncmp(line,"ext2",4)) {
+			initrd_archive = -2;
+			return;
+	}
+	
+	initrd_archive = simple_strtoul(line,NULL,10);
+}
+
+#include "rd.untar.c"
+
+#ifdef CONFIG_BLK_DEV_INITRD_ARCHIVE_AUTOFS_MINIX
+	#include "rd.mkminix.c"
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD_ARCHIVE_AUTOFS_EXT2
+	#include "rd.mkext2.c"
+#endif
+
+#endif
 #endif
 
 #endif /* RD_LOADER */
diff -uNr linux-2.2.8-virgin/drivers/block/rd.mkext2.c linux-2.2.8-initrd_arch/drivers/block/rd.mkext2.c
--- linux-2.2.8-virgin/drivers/block/rd.mkext2.c	Wed Dec 31 19:00:00 1969
+++ linux-2.2.8-initrd_arch/drivers/block/rd.mkext2.c	Wed May 12 21:23:17 1999
@@ -0,0 +1,842 @@
+//extremely broken!!!!!  Not even near compilable.
+/*
+ * 
+ * rd.mkext2.c
+ * 
+ * 1998-02-22
+ * Chainsawed and converted by Dave Cinege
+ * 
+ * 
+ * mke2fs.c - Make a ext2fs filesystem.
+ * 
+ * Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o.
+ *  *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+
+#ifndef CONFIG_EXT2_FS
+	#error: "This won't do you much good without ext2 fs support!"
+#endif
+
+#include <linux/time.h>
+#include <linux/unistd.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+ 
+#include <linux/stddef.h>
+
+#include <linux/ext2_fs.h>
+#include <linux/ext2_fs_i.h>
+#include <linux/ext2_fs_sb.h>
+
+#include <linux/fs.h>
+#include <linux/major.h>
+
+#include <linux/vmalloc.h>
+
+
+#include <linux/module.h>
+
+#include <stdarg.h>
+
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+#include <linux/malloc.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+
+#define STRIDE_LENGTH 8
+
+
+#define super (*(struct ext2_super_block *)super_block_buffer)
+
+#define MAGIC (Super.s_magic)
+
+
+static int magic = EXT2_SUPER_MAGIC;
+
+/* Command line options */
+int	cflag = 0;
+int	verbose = 0;
+int	quiet = 0;
+int	super_only = 0;
+int	force = 0;
+char	*bad_blocks_filename = 0;
+__u32	fs_stride = 0;
+
+struct ext2_super_block param;
+char *creator_os = NULL;
+char *volume_label = NULL;
+char *mount_dir = NULL;
+
+static char super_block_buffer[sizeof(struct ext2_super_block)];
+
+static					
+int mkext2fs(void)
+{
+
+	//sanity check
+	outfile.f_pos = 0;
+
+	int	retval = 0;
+	ext2_filsys	fs;
+	badblocks_list	bb_list = 0;
+	struct ext2_super_block *s;
+	
+	/*
+	 * Initialize the superblock....
+	 */
+	ext2fs_initialize(device_name, 0, &param, unix_io_manager, &fs);
+-	
+	/*
+	 * Generate a UUID for it...
+	 */
+	s = (struct ext2_super_block *) fs->super;
+	uuid_generate(s->s_uuid);
+
+	handle_bad_blocks(fs, bb_list);
+	fs->stride = fs_stride;
+	ext2fs_allocate_tables(fs);
+	
+	write_inode_tables(fs);
+	create_root_dir(fs);
+	create_lost_and_found(fs);
+	reserve_inodes(fs);
+	create_bad_block_inode(fs, bb_list);
+		
+	
+	ext2fs_close(fs);
+	
+	return 0;
+}
+
+
+static int log2(int arg)
+{
+	int	l = 0;
+
+	arg >>= 1;
+	while (arg) {
+		l++;
+		arg >>= 1;
+	}
+	return l;
+}
+
+
+
+/*
+ * Helper function for read_bb_file and test_disk
+ */
+static void invalid_block(ext2_filsys fs, blk_t blk)
+{
+	printf("Bad block %u out of range; ignored.\n", blk);
+	return;
+}
+
+
+
+static void handle_bad_blocks(ext2_filsys fs, badblocks_list bb_list)
+{
+	int			i, j;
+	int			must_be_good;
+	blk_t			blk;
+	badblocks_iterate	bb_iter;
+	errcode_t		retval;
+	blk_t			group_block;
+	int			group;
+	int			group_bad;
+
+	if (!bb_list)
+		return;
+	
+	/*
+	 * The primary superblock and group descriptors *must* be
+	 * good; if not, abort.
+	 */
+	must_be_good = fs->super->s_first_data_block + 1 + fs->desc_blocks;
+	for (i = fs->super->s_first_data_block; i <= must_be_good; i++) {
+		if (badblocks_list_test(bb_list, i)) {
+			fprintf(stderr, "Block %d in primary superblock/group "
+				"descriptor area bad.\n", i);
+			fprintf(stderr, "Blocks %d through %d must be good "
+				"in order to build a filesystem.\n",
+				fs->super->s_first_data_block, must_be_good);
+			fprintf(stderr, "Aborting....\n");
+			exit(1);
+		}
+	}
+
+	/*
+	 * See if any of the bad blocks are showing up in the backup
+	 * superblocks and/or group descriptors.  If so, issue a
+	 * warning and adjust the block counts appropriately.
+	 */
+	group_block = fs->super->s_first_data_block +
+		fs->super->s_blocks_per_group;
+	group_bad = 0;
+	
+	for (i = 1; i < fs->group_desc_count; i++) {
+		for (j=0; j < fs->desc_blocks+1; j++) {
+			if (badblocks_list_test(bb_list, group_block +
+						j)) {
+				if (!group_bad) 
+					fprintf(stderr,
+"Warning: the backup superblock/group descriptors at block %d contain\n"
+"	bad blocks.\n\n",
+						group_block);
+				group_bad++;
+				group = ext2fs_group_of_blk(fs, group_block+j);
+				fs->group_desc[group].bg_free_blocks_count++;
+				fs->super->s_free_blocks_count++;
+			}
+		}
+		group_block += fs->super->s_blocks_per_group;
+	}
+	
+	/*
+	 * Mark all the bad blocks as used...
+	 */
+	retval = badblocks_list_iterate_begin(bb_list, &bb_iter);
+	if (retval) {
+		com_err("badblocks_list_iterate_begin", retval,
+			"while marking bad blocks as used");
+		exit(1);
+	}
+	while (badblocks_list_iterate(bb_iter, &blk)) 
+		ext2fs_mark_block_bitmap(fs->block_map, blk);
+	badblocks_list_iterate_end(bb_iter);
+}
+
+static void write_inode_tables(ext2_filsys fs)
+{
+	errcode_t	retval;
+	blk_t		blk;
+	int		i, j, num, count;
+	char		*buf;
+
+	buf = malloc(fs->blocksize * STRIDE_LENGTH);
+	if (!buf) {
+		com_err("malloc", ENOMEM, "while allocating zeroizing buffer");
+		exit(1);
+	}
+	memset(buf, 0, fs->blocksize * STRIDE_LENGTH);
+	
+	if (!quiet)
+		printf("Writing inode tables: ");
+	for (i = 0; i < fs->group_desc_count; i++) {
+		if (!quiet)
+			printf("%4d/%4ld", i, fs->group_desc_count);
+		
+		blk = fs->group_desc[i].bg_inode_table;
+		num = fs->inode_blocks_per_group;
+		
+		for (j=0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) {
+			if (num-j > STRIDE_LENGTH)
+				count = STRIDE_LENGTH;
+			else
+				count = num - j;
+			retval = io_channel_write_blk(fs->io, blk, count, buf);
+			if (retval)
+				printf("Warning: could not write %d blocks "
+				       "in inode table starting at %d: %s\n",
+				       count, blk, error_message(retval));
+		}
+		if (!quiet) 
+			printf("\b\b\b\b\b\b\b\b\b");
+	}
+	free(buf);
+	if (!quiet)
+		printf("done     \n");
+}
+
+static void create_root_dir(ext2_filsys fs)
+{
+	errcode_t	retval;
+	struct ext2_inode	inode;
+
+	retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0);
+	if (retval) {
+		com_err("ext2fs_mkdir", retval, "while creating root dir");
+		exit(1);
+	}
+	if (geteuid()) {
+		retval = ext2fs_read_inode(fs, EXT2_ROOT_INO, &inode);
+		if (retval) {
+			com_err("ext2fs_read_inode", retval,
+				"while reading root inode");
+			exit(1);
+		}
+		inode.i_uid = getuid();
+		if (inode.i_uid)
+			inode.i_gid = getgid();
+		retval = ext2fs_write_inode(fs, EXT2_ROOT_INO, &inode);
+		if (retval) {
+			com_err("ext2fs_write_inode", retval,
+				"while setting root inode ownership");
+			exit(1);
+		}
+	}
+}
+
+static void create_bad_block_inode(ext2_filsys fs, badblocks_list bb_list)
+{
+	errcode_t	retval;
+	
+	ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_BAD_INO);
+	fs->group_desc[0].bg_free_inodes_count--;
+	fs->super->s_free_inodes_count--;
+	retval = ext2fs_update_bb_inode(fs, bb_list);
+	if (retval) {
+		com_err("ext2fs_update_bb_inode", retval,
+			"while setting bad block inode");
+		exit(1);
+	}
+
+}
+
+static void reserve_inodes(ext2_filsys fs)
+{
+	ino_t	i;
+	int	group;
+
+	for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->super); i++) {
+		ext2fs_mark_inode_bitmap(fs->inode_map, i);
+		group = ext2fs_group_of_ino(fs, i);
+		fs->group_desc[group].bg_free_inodes_count--;
+		fs->super->s_free_inodes_count--;
+	}
+	ext2fs_mark_ib_dirty(fs);
+}
+	
+
+static void show_stats(ext2_filsys fs)
+{
+	struct ext2_super_block 	*s = (struct ext2_super_block *) fs->super;
+	char 			buf[80];
+	blk_t			group_block;
+	int			i, col_left;
+	
+	if (param.s_blocks_count != s->s_blocks_count)
+		printf("warning: %d blocks unused.\n\n",
+		       param.s_blocks_count - s->s_blocks_count);
+	
+	switch (fs->super->s_creator_os) {
+	    case EXT2_OS_LINUX: printf ("Linux"); break;
+	    case EXT2_OS_HURD:  printf ("GNU/hurd");   break;
+	    case EXT2_OS_MASIX: printf ("Masix"); break;
+	    default:		printf ("(unknown os)");
+        }
+	printf (" ext2 filesystem format\n");
+	memset(buf, 0, sizeof(buf));
+	strncpy(buf, s->s_volume_name, sizeof(s->s_volume_name));
+	printf("Filesystem label=%s\n", buf);
+	printf("%u inodes, %u blocks\n", s->s_inodes_count,
+	       s->s_blocks_count);
+	printf("%u blocks (%2.2f%%) reserved for the super user\n",
+		s->s_r_blocks_count,
+	       100.0 * s->s_r_blocks_count / s->s_blocks_count);
+	printf("First data block=%u\n", s->s_first_data_block);
+	printf("Block size=%u (log=%u)\n", fs->blocksize,
+		s->s_log_block_size);
+	printf("Fragment size=%u (log=%u)\n", fs->fragsize,
+		s->s_log_frag_size);
+	printf("%lu block group%s\n", fs->group_desc_count,
+		(fs->group_desc_count > 1) ? "s" : "");
+	printf("%u blocks per group, %u fragments per group\n",
+	       s->s_blocks_per_group, s->s_frags_per_group);
+	printf("%u inodes per group\n", s->s_inodes_per_group);
+
+	if (fs->group_desc_count == 1) {
+		printf("\n");
+		return;
+	}
+	
+	printf("Superblock backups stored on blocks: ");
+	group_block = s->s_first_data_block;
+	col_left = 0;
+	for (i = 1; i < fs->group_desc_count; i++) {
+		group_block += s->s_blocks_per_group;
+		if (!ext2fs_bg_has_super(fs, i))
+			continue;
+		if (!col_left--) {
+			printf("\n\t");
+			col_left = 8;
+		}
+		printf("%u", group_block);
+		if (i != fs->group_desc_count - 1)
+			printf(", ");
+	}
+	printf("\n\n");
+}
+
+#ifndef HAVE_STRCASECMP
+static int strcasecmp (char *s1, char *s2)
+{
+	while (*s1 && *s2) {
+		int ch1 = *s1++, ch2 = *s2++;
+		if (isupper (ch1))
+			ch1 = tolower (ch1);
+		if (isupper (ch2))
+			ch2 = tolower (ch2);
+		if (ch1 != ch2)
+			return ch1 - ch2;
+	}
+	return *s1 ? 1 : *s2 ? -1 : 0;
+}
+#endif
+
+/*
+ * Set the S_CREATOR_OS field.  Return true if OS is known,
+ * otherwise, 0.
+ */
+static int set_os(struct ext2_super_block *sb, char *os)
+{
+	sb->s_creator_os = EXT2_OS_LINUX;
+	
+	return 1;
+}
+
+
+
+static void PRS(int argc, char *argv[])
+{
+	char	c;
+	int	size;
+	char	* tmp;
+	blk_t	max = 8192;
+	int	inode_ratio = 4096;
+	int	reserved_ratio = 5;
+	errcode_t	retval;
+	int	sparse_option = -1;
+	char	*oldpath = getenv("PATH");
+	struct ext2_super_block *param_ext2 = (struct ext2_super_block *) &param;
+	char	*raid_opts = 0;
+	
+	/* Update our PATH to include /sbin  */
+	if (oldpath) {
+		char *newpath;
+		
+		newpath = malloc(sizeof (PATH_SET) + 1 + strlen (oldpath));
+		strcpy (newpath, PATH_SET);
+		strcat (newpath, ":");
+		strcat (newpath, oldpath);
+		putenv (newpath);
+	} else
+		putenv (PATH_SET);
+
+	setbuf(stdout, NULL);
+	setbuf(stderr, NULL);
+	initialize_ext2_error_table();
+	memset(&param, 0, sizeof(struct ext2_super_block));
+	
+	fprintf (stderr, "mke2fs %s, %s for EXT2 FS %s, %s\n",
+		 E2FSPROGS_VERSION, E2FSPROGS_DATE,
+		 EXT2FS_VERSION, EXT2FS_DATE);
+	if (argc && *argv)
+		program_name = *argv;
+	while ((c = getopt (argc, argv,
+			    "b:cf:g:i:l:m:o:qr:R:s:tvI:SFL:M:")) != EOF)
+		switch (c) {
+		case 'b':
+			size = strtoul(optarg, &tmp, 0);
+			if (size < 1024 || size > 4096 || *tmp) {
+				com_err(program_name, 0, "bad block size - %s",
+					optarg);
+				exit(1);
+			}
+			param.s_log_block_size =
+				log2(size >> EXT2_MIN_BLOCK_LOG_SIZE);
+			max = size * 8;
+			break;
+		case 'c':
+		case 't':	/* Check for bad blocks */
+			cflag = 1;
+			break;
+		case 'f':
+			size = strtoul(optarg, &tmp, 0);
+			if (size < 1024 || size > 4096 || *tmp) {
+				com_err(program_name, 0, "bad fragment size - %s",
+					optarg);
+				exit(1);
+			}
+			param.s_log_frag_size =
+				log2(size >> EXT2_MIN_BLOCK_LOG_SIZE);
+			printf("Warning: fragments not supported.  "
+			       "Ignoring -f option\n");
+			break;
+		case 'g':
+			param.s_blocks_per_group = strtoul(optarg, &tmp, 0);
+			if (*tmp) {
+				com_err(program_name, 0,
+					"Illegal number for blocks per group");
+				exit(1);
+			}
+			if ((param.s_blocks_per_group % 8) != 0) {
+				com_err(program_name, 0,
+				"blocks per group must be multiple of 8");
+				exit(1);
+			}
+			break;
+		case 'i':
+			inode_ratio = strtoul(optarg, &tmp, 0);
+			if (inode_ratio < 1024 || inode_ratio > 256 * 1024 ||
+			    *tmp) {
+				com_err(program_name, 0, "bad inode ratio - %s",
+					optarg);
+				exit(1);
+			}
+			break;
+		case 'l':
+			bad_blocks_filename = malloc(strlen(optarg)+1);
+			if (!bad_blocks_filename) {
+				com_err(program_name, ENOMEM,
+					"in malloc for bad_blocks_filename");
+				exit(1);
+			}
+			strcpy(bad_blocks_filename, optarg);
+			break;
+		case 'm':
+			reserved_ratio = strtoul(optarg, &tmp, 0);
+			if (reserved_ratio > 50 || *tmp) {
+				com_err(program_name, 0,
+					"bad reserved blocks percent - %s",
+					optarg);
+				exit(1);
+			}
+			break;
+		case 'o':
+			creator_os = optarg;
+			break;
+		case 'r':
+			param.s_rev_level = atoi(optarg);
+			break;
+		case 's':
+			sparse_option = atoi(optarg);
+			break;
+#ifdef EXT2_DYNAMIC_REV
+		case 'I':
+			param.s_inode_size = atoi(optarg);
+			break;
+#endif
+		case 'v':
+			verbose = 1;
+			break;
+		case 'q':
+			quiet = 1;
+			break;
+		case 'F':
+			force = 1;
+			break;
+		case 'L':
+			volume_label = optarg;
+			break;
+		case 'M':
+			mount_dir = optarg;
+			break;
+		case 'R':
+			raid_opts = optarg;
+			break;
+		case 'S':
+			super_only = 1;
+			break;
+		default:
+			usage();
+		}
+	if (optind == argc)
+		usage();
+	device_name = argv[optind];
+	optind++;
+	if (optind < argc) {
+		param.s_blocks_count = strtoul(argv[optind++], &tmp, 0);
+		if (*tmp) {
+			com_err(program_name, 0, "bad blocks count - %s",
+				argv[optind - 1]);
+			exit(1);
+		}
+	}
+	if (optind < argc)
+		usage();
+
+	if (raid_opts)
+		parse_raid_opts(raid_opts);
+
+	if (!force)
+		check_plausibility();
+	check_mount();
+
+	param.s_log_frag_size = param.s_log_block_size;
+
+	if (!param.s_blocks_count) {
+		retval = ext2fs_get_device_size(device_name,
+						EXT2_BLOCK_SIZE(&param),
+						&param.s_blocks_count);
+		if (retval) {
+			com_err(program_name, retval,
+				"while trying to determine filesystem size");
+			exit(1);
+		}
+	}
+
+	if (param.s_blocks_per_group) {
+		if (param.s_blocks_per_group < 256 ||
+		    param.s_blocks_per_group > max || *tmp) {
+			com_err(program_name, 0,
+				"blocks per group count out of range");
+			exit(1);
+		}
+	}
+
+	/*
+	 * Calculate number of inodes based on the inode ratio
+	 */
+	param.s_inodes_count =
+		((long long) param.s_blocks_count * EXT2_BLOCK_SIZE(&param))
+			/ inode_ratio;
+
+	/*
+	 * Calculate number of blocks to reserve
+	 */
+	param.s_r_blocks_count = (param.s_blocks_count * reserved_ratio) / 100;
+
+	/*
+	 * If we are using revision #1, use the sparse super feature
+	 * by default
+	 */
+#ifdef EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
+	if ((sparse_option == 1)
+#ifdef EXT2_DYNAMIC_REV
+	    || (param.s_rev_level >= EXT2_DYNAMIC_REV) && (!sparse_option)
+#endif
+	    ) 
+		param_ext2->s_feature_ro_compat |=
+			EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
+#endif
+}
+
+
+#define CREATOR_OS EXT2_OS_LINUX /* by default */
+
+
+int ext2fs_initialize(const char *name, int flags,
+			struct ext2_super_block *param,
+			io_manager manager, ext2_filsys *ret_fs)
+{
+	ext2_filsys	fs;
+	errcode_t	retval;
+	struct ext2_super_block *super;
+	int		frags_per_block;
+	int		rem;
+	int		overhead = 0;
+	blk_t		group_block;
+	int		i, j;
+	int		numblocks;
+	char		*buf;
+
+	
+	memset(super_block_buffer, 0, sizeof(struct ext2_super_block));
+
+	super.s_magic			= EXT2_SUPER_MAGIC;
+	super.s_state			= EXT2_VALID_FS;
+	super.s_log_block_size		= 0;
+	super.s_log_frag_size		= 0;
+	super.s_first_data_block	= 0;
+	super.s_max_mnt_count		= 4;
+	super.s_errors			= 0;
+	super.s_checkinterval		= 2;
+	super.s_lastcheck		= time(NULL);
+	super.s_creator_os		= EXT2_OS_LINUX;
+	super.s_blocks_per_group	= 
+	
+
+	fs->blocksize = EXT2_BLOCK_SIZE(super);
+	fs->fragsize = EXT2_FRAG_SIZE(super);
+	frags_per_block = fs->blocksize / fs->fragsize;
+	
+	/* default: (fs->blocksize*8) blocks/group */
+	set_field(s_blocks_per_group, fs->blocksize*8); 
+	
+		
+	super.s_frags_per_group		= super.s_blocks_per_group * frags_per_block;
+	
+	super.s_blocks_count		= param->s_blocks_count;
+	super.s_r_blocks_count		= param->s_r_blocks_count;
+
+	fs->group_desc_count = (super->s_blocks_count -
+				super->s_first_data_block +
+				EXT2_BLOCKS_PER_GROUP(super) - 1)
+		/ EXT2_BLOCKS_PER_GROUP(super);
+	if (fs->group_desc_count == 0)
+		return EXT2_ET_TOOSMALL;
+	fs->desc_blocks = (fs->group_desc_count +
+			   EXT2_DESC_PER_BLOCK(super) - 1)
+		/ EXT2_DESC_PER_BLOCK(super);
+
+	super.s_inodes_count		= (super.s_blocks_count * fs->blocksize)/4096;
+
+	/*
+	 * There should be at least as many inodes as the user
+	 * requested.  Figure out how many inodes per group that
+	 * should be.  But make sure that we don't allocate more than
+	 * one bitmap's worth of inodes
+	 */
+	super.s_inodes_per_group = (super->s_inodes_count +
+				     fs->group_desc_count - 1) /
+					     fs->group_desc_count;
+	if (super->s_inodes_per_group > fs->blocksize*8)
+		super->s_inodes_per_group = fs->blocksize*8;
+	
+	/*
+	 * Make sure the number of inodes per group completely fills
+	 * the inode table blocks in the descriptor.  If not, add some
+	 * additional inodes/group.  Waste not, want not...
+	 */
+	fs->inode_blocks_per_group = (((super->s_inodes_per_group *
+					EXT2_INODE_SIZE(super)) +
+				       EXT2_BLOCK_SIZE(super) - 1) /
+				      EXT2_BLOCK_SIZE(super));
+	super->s_inodes_per_group = ((fs->inode_blocks_per_group *
+				      EXT2_BLOCK_SIZE(super)) /
+				     EXT2_INODE_SIZE(super));
+	/*
+	 * Finally, make sure the number of inodes per group is a
+	 * multiple of 8.  This is needed to simplify the bitmap
+	 * splicing code.
+	 */
+	super->s_inodes_per_group &= ~7;
+	fs->inode_blocks_per_group = (((super->s_inodes_per_group *
+					EXT2_INODE_SIZE(super)) +
+				       EXT2_BLOCK_SIZE(super) - 1) /
+				      EXT2_BLOCK_SIZE(super));
+
+	/*
+	 * adjust inode count to reflect the adjusted inodes_per_group
+	 */
+	super->s_inodes_count = super->s_inodes_per_group *
+		fs->group_desc_count;
+	super->s_free_inodes_count = super->s_inodes_count;
+
+	/*
+	 * Overhead is the number of bookkeeping blocks per group.  It
+	 * includes the superblock backup, the group descriptor
+	 * backups, the inode bitmap, the block bitmap, and the inode
+	 * table.
+	 *
+	 * XXX Not all block groups need the descriptor blocks, but
+	 * being clever is tricky...
+	 */
+	overhead = 3 + fs->desc_blocks + fs->inode_blocks_per_group;
+	
+	/*
+	 * See if the last group is big enough to support the
+	 * necessary data structures.  If not, we need to get rid of
+	 * it.
+	 */
+	rem = (super->s_blocks_count - super->s_first_data_block) %
+		super->s_blocks_per_group;
+	if ((fs->group_desc_count == 1) && rem && (rem < overhead))
+		return EXT2_ET_TOOSMALL;
+	if (rem && (rem < overhead+50)) {
+		super->s_blocks_count -= rem;
+		goto retry;
+	}
+
+	/*
+	 * At this point we know how big the filesystem will be.  So
+	 * we can do any and all allocations that depend on the block
+	 * count.
+	 */
+
+	buf = malloc(strlen(fs->device_name) + 80);
+	if (!buf) {
+		retval = ENOMEM;
+		goto cleanup;
+	}
+	
+	sprintf(buf, "block bitmap for %s", fs->device_name);
+	retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
+	if (retval)
+		goto cleanup;
+	
+	sprintf(buf, "inode bitmap for %s", fs->device_name);
+	retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
+	if (retval)
+		goto cleanup;
+
+	free(buf);
+
+	fs->group_desc = malloc(fs->desc_blocks * fs->blocksize);
+	if (!fs->group_desc) {
+		retval = ENOMEM;
+		goto cleanup;
+	}
+	memset(fs->group_desc, 0, fs->desc_blocks * fs->blocksize);
+
+	/*
+	 * Reserve the superblock and group descriptors for each
+	 * group, and fill in the correct group statistics for group.
+	 * Note that although the block bitmap, inode bitmap, and
+	 * inode table have not been allocated (and in fact won't be
+	 * by this routine), they are accounted for nevertheless.
+	 */
+	group_block = super->s_first_data_block;
+	super->s_free_blocks_count = 0;
+	for (i = 0; i < fs->group_desc_count; i++) {
+		if (i == fs->group_desc_count-1) {
+			numblocks = (fs->super->s_blocks_count -
+				     fs->super->s_first_data_block) %
+					     fs->super->s_blocks_per_group;
+			if (!numblocks)
+				numblocks = fs->super->s_blocks_per_group;
+		} else
+			numblocks = fs->super->s_blocks_per_group;
+
+		if (ext2fs_bg_has_super(fs, i)) {
+			for (j=0; j < fs->desc_blocks+1; j++)
+				ext2fs_mark_block_bitmap(fs->block_map,
+							 group_block + j);
+			numblocks -= 1 + fs->desc_blocks;
+		}
+		
+		numblocks -= 2 + fs->inode_blocks_per_group;
+		
+		super->s_free_blocks_count += numblocks;
+		fs->group_desc[i].bg_free_blocks_count = numblocks;
+		fs->group_desc[i].bg_free_inodes_count =
+			fs->super->s_inodes_per_group;
+		fs->group_desc[i].bg_used_dirs_count = 0;
+		
+		group_block += super->s_blocks_per_group;
+	}
+	
+	ext2fs_mark_super_dirty(fs);
+	ext2fs_mark_bb_dirty(fs);
+	ext2fs_mark_ib_dirty(fs);
+	
+	io_channel_set_blksize(fs->io, fs->blocksize);
+
+	*ret_fs = fs;
+	return 0;
+cleanup:
+	ext2fs_free(fs);
+	return retval;
+}
+	
+
+
+
+
+
diff -uNr linux-2.2.8-virgin/drivers/block/rd.mkminix.c linux-2.2.8-initrd_arch/drivers/block/rd.mkminix.c
--- linux-2.2.8-virgin/drivers/block/rd.mkminix.c	Wed Dec 31 19:00:00 1969
+++ linux-2.2.8-initrd_arch/drivers/block/rd.mkminix.c	Wed May 12 21:23:17 1999
@@ -0,0 +1,290 @@
+
+/*
+ * rd.mkminix.c
+ *
+ * 1998-01-10
+ * Chainsawed and converted by Dave Cinege
+ *
+ * 1998-01-17
+ * Just some K&R styling 
+ *
+ * 1998-02-19
+ * Sanity check for 2.1 code
+ * Convert to 2.1 file ops
+ *
+ * 1998-10-17
+ * Change kmalloc to vmalloc, to allow >12MB FS. Minix FS make check.
+ *
+ * mkfs.c - make a linux (minix) file-system.
+ *
+ * (C) 1991 Linus Torvalds, et al...
+ *
+ */
+
+#ifndef CONFIG_MINIX_FS
+	#error: "This won't do you much good without minix fs support!"
+#endif
+
+#include <linux/time.h>
+#include <linux/unistd.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+ 
+#include <linux/stddef.h>
+#include <linux/minix_fs.h>
+#include <linux/vmalloc.h>
+
+#define MINIX_ROOT_INO 1
+#define MAX_GOOD_BLOCKS 512
+
+#define UPPER(size,n) ((size+((n)-1))/(n))
+#define INODE_SIZE (sizeof(struct minix_inode))
+#define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK))
+#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
+#define BITS_PER_BLOCK (BLOCK_SIZE<<3)
+#define Inode (((struct minix_inode *) inode_buffer)-1)
+#define Super (*(struct minix_super_block *)super_block_buffer)
+#define INODES ((unsigned long)Super.s_ninodes)
+#define ZONES ((unsigned long)(Super.s_nzones))
+#define IMAPS ((unsigned long)Super.s_imap_blocks)
+#define ZMAPS ((unsigned long)Super.s_zmap_blocks)
+#define FIRSTZONE ((unsigned long)Super.s_firstdatazone)
+#define ZONESIZE ((unsigned long)Super.s_log_zone_size)
+#define MAXSIZE ((unsigned long)Super.s_max_size)
+#define MAGIC (Super.s_magic)
+#define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS)
+
+#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1))
+#define mark_inode(x) (setbit(inode_map,(x)))
+#define unmark_inode(x) (clrbit(inode_map,(x)))
+#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1))
+#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1))
+
+static long BLOCKS = 0;
+
+static int dirsize = 32;
+static int magic = MINIX_SUPER_MAGIC2;
+
+static char root_block[BLOCK_SIZE] = "\0";
+
+static char * inode_buffer = NULL;
+
+static char super_block_buffer[BLOCK_SIZE];
+static char boot_block_buffer[512];
+static char inode_map[BLOCK_SIZE * MINIX_I_MAP_SLOTS];
+static char zone_map[BLOCK_SIZE * MINIX_Z_MAP_SLOTS];
+
+static unsigned short good_blocks_table[MAX_GOOD_BLOCKS];
+static int used_good_blocks = 0;
+static unsigned long req_nr_inodes = 0;
+
+static int mkminixfs(void);
+static void write_tables(void);
+static int get_free_block(void);
+static void make_root_inodes(void);
+static void setup_tables(void);
+
+static inline void write_block(int blk, char * buffer);
+static inline void mark_good_blocks(void);
+static inline int next(int zone);
+
+static inline int bit(char * addr,unsigned int nr); 
+static inline int setbit(char * addr,unsigned int nr);
+static inline int clrbit(char * addr,unsigned int nr);
+
+extern int sys_time(int * tloc);
+
+static
+int mkminixfs(void)
+{
+
+	char * tmp;
+
+	//sanity check
+	outfile.f_pos = 0;
+
+	magic = MINIX_SUPER_MAGIC2;
+
+	BLOCKS = rd_size;
+      
+	if (BLOCKS > 65535)
+		BLOCKS = 65535;
+
+	tmp = root_block;
+	*(short *)tmp = 1;
+	strcpy(tmp+2,".");
+	tmp += dirsize;
+	*(short *)tmp = 1;
+	strcpy(tmp+2,"..");
+	tmp += dirsize;
+	*(short *)tmp = 2;
+	strcpy(tmp+2,".badblocks");
+
+	setup_tables();
+
+	make_root_inodes();
+	mark_good_blocks();
+	write_tables();
+
+	return (0);
+}
+
+static
+void write_tables(void)
+{
+	/* Mark the super block valid. */
+	Super.s_state |= MINIX_VALID_FS;
+	Super.s_state &= ~MINIX_ERROR_FS;
+	
+	outfile.f_pos = 0;
+	outfile.f_op->write(&outfile, boot_block_buffer, 512, &outfile.f_pos);
+	outfile.f_pos = BLOCK_SIZE;
+	outfile.f_op->write(&outfile, super_block_buffer, BLOCK_SIZE, &outfile.f_pos);
+	outfile.f_op->write(&outfile, inode_map, IMAPS*BLOCK_SIZE, &outfile.f_pos);
+	outfile.f_op->write(&outfile, zone_map, ZMAPS*BLOCK_SIZE, &outfile.f_pos);
+	outfile.f_op->write(&outfile, inode_buffer, INODE_BUFFER_SIZE, &outfile.f_pos);
+}
+
+static
+int get_free_block(void)
+{
+	int blk;
+
+	if (used_good_blocks)
+		blk = good_blocks_table[used_good_blocks-1]+1;
+	else
+		blk = FIRSTZONE;
+	while (blk < ZONES && zone_in_use(blk))
+		blk++;
+	good_blocks_table[used_good_blocks] = blk;
+	used_good_blocks++;
+
+	return blk;
+}
+
+static
+void make_root_inodes(void)
+{
+	struct minix_inode * inode;
+
+	inode = vmalloc(INODE_BUFFER_SIZE);
+	memset(inode,0,INODE_BUFFER_SIZE);
+	inode = &Inode[MINIX_ROOT_INO];
+		
+	mark_inode(MINIX_ROOT_INO);
+
+	inode->i_zone[0] = get_free_block();	
+	inode->i_nlinks = 2;
+	inode->i_time = sys_time(NULL);
+		
+	root_block[2*dirsize] = '\0';
+	root_block[2*dirsize+1] = '\0';
+	inode->i_size = 2*dirsize;
+	
+	inode->i_mode = S_IFDIR + 0755;
+	write_block(inode->i_zone[0],root_block);
+}
+
+static
+void setup_tables(void)
+{
+	int i;
+	unsigned long inodes;
+
+	memset(inode_map,0xff,sizeof(inode_map));
+	memset(zone_map,0xff,sizeof(zone_map));
+	memset(super_block_buffer,0,BLOCK_SIZE);
+	memset(boot_block_buffer,0,512);
+	MAGIC = magic;
+	ZONESIZE = 0;
+	MAXSIZE = 0x7fffffff;
+	ZONES = BLOCKS;
+/* some magic nrs: 1 inode / 3 blocks */
+	if ( req_nr_inodes == 0 ) 
+		inodes = BLOCKS/3;
+	else
+		inodes = req_nr_inodes;
+	if (inodes > 65535)
+		inodes = 65535;
+	INODES = inodes;
+/* I don't want some off-by-one errors, so this hack... */
+	if ((INODES & 8191) > 8188)
+		INODES -= 5;
+	if ((INODES & 8191) < 10)
+		INODES -= 20;
+	IMAPS = UPPER(INODES,BITS_PER_BLOCK);
+	ZMAPS = 0;
+	while (ZMAPS != UPPER(BLOCKS - NORM_FIRSTZONE,BITS_PER_BLOCK))
+		ZMAPS = UPPER(BLOCKS - NORM_FIRSTZONE,BITS_PER_BLOCK);
+	if (ZMAPS > 64)
+		printk ("Filesystem too big for Linux to handle");
+	FIRSTZONE = NORM_FIRSTZONE;
+	for (i = FIRSTZONE ; i<ZONES ; i++)
+		unmark_zone(i);
+	for (i = MINIX_ROOT_INO ; i<INODES ; i++)
+		unmark_inode(i);
+	inode_buffer = vmalloc(INODE_BUFFER_SIZE);
+	if (!inode_buffer)
+		printk("unable to allocate buffer for inodes");
+	memset(inode_buffer,0,INODE_BUFFER_SIZE);
+	
+	printk("minix: %ldi %ldbk %ldfdz(%ld) %dzs %ldms\n",INODES,ZONES,FIRSTZONE,
+		NORM_FIRSTZONE,BLOCK_SIZE<<ZONESIZE,MAXSIZE);
+}
+
+
+static
+inline
+void write_block(int blk, char * buffer)
+{
+	outfile.f_pos=blk*BLOCK_SIZE;
+	outfile.f_op->write(&outfile, buffer, BLOCK_SIZE, &outfile.f_pos);
+}
+
+static
+inline
+void mark_good_blocks(void)
+{
+	int blk;
+
+	for (blk=0 ; blk < used_good_blocks ; blk++)
+		mark_zone(good_blocks_table[blk]);
+}
+
+static
+inline
+int next(int zone)
+{
+	if (!zone)
+		zone = FIRSTZONE-1;
+	while (++zone < ZONES)
+		if (zone_in_use(zone))
+			return zone;
+	return 0;
+}
+
+static
+inline
+int bit(char * addr,unsigned int nr) 
+{
+	return (addr[nr >> 3] & (1<<(nr & 7))) != 0;
+}
+
+static
+inline
+int setbit(char * addr,unsigned int nr)
+{
+	int __res = bit(addr, nr);
+	addr[nr >> 3] |= (1<<(nr & 7));
+	return __res != 0; \
+}
+
+static
+inline
+int clrbit(char * addr,unsigned int nr)
+{
+	int __res = bit(addr, nr);
+	addr[nr >> 3] &= ~(1<<(nr & 7));
+	return __res != 0;
+}
+
diff -uNr linux-2.2.8-virgin/drivers/block/rd.untar.c linux-2.2.8-initrd_arch/drivers/block/rd.untar.c
--- linux-2.2.8-virgin/drivers/block/rd.untar.c	Wed Dec 31 19:00:00 1969
+++ linux-2.2.8-initrd_arch/drivers/block/rd.untar.c	Wed May 12 21:23:17 1999
@@ -0,0 +1,359 @@
+/*
+ * 
+ * rd.untar.c
+ * 
+ * Dimitri Maziuk
+ * and
+ * Dave Cinege
+ * 
+ * Parts stolen from GNU 'Let's make the same archive 10 different ways' tar
+ * 
+ * 1998-01-10
+ * This version of untar is very limited. It expects a fairly good archive, 
+ * as well as expansion to a clean root.
+ * 
+ * It does not:
+ * 
+ * Look for a leading '/'
+ * Check before making links
+ * Look at the header checksum
+ * Check or create any leading directory structure
+ * 
+ * 1998-01-17
+ * Is GNUtar the biggest fuck-up in released software since MS-DOS? 
+ * It could be.
+ * 
+ * Tar decides it sometimes likes to make a dir entry that is blank or "./".
+ * We now check for this, and modified our exit pattern to deal with it.
+ * 
+ * Although both Dima and I thought it wasn't possible, tar can  
+ * stor files without first storing the dir they require.
+ * If your nice freshly made archive doesn't work don't be surprised.
+ * Try specing a different way to make it.
+ *
+ * Dima has a forthcoming mini tar archive creator (ctar) that should
+ * better deal with these problems. You may want to look for it if normal
+ * tar does not suite your needs when using this kernel feature.
+ * 
+ * 1998-02-22
+ * Convert to 2.1 file ops. Open /dev/ram1 locally. With 2.1 outfile in rd.c
+ * was not holding it's value when we entered this code. I think it has
+ * to do with the newer __initfunc(); thingy. Couldn't figure out how to
+ * make it work. Did this instead.
+ *
+ * 1998-10-17
+ * Move to wrapper function.
+ *
+ */
+
+#include <linux/unistd.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/stddef.h>  
+#include <linux/utime.h>
+
+//DEBUG_UNTAR only
+// #include <linux/delay.h>
+
+
+static unsigned long simple_strtoul_wrapper(const char *cp,char **endp,unsigned int base);
+
+static
+int untar(void)
+{
+
+//#define DEBUG_UNTAR
+
+#define E_NAMETOOLONG	1
+#define E_CANNOTSTAT	2
+#define E_READLINK	3
+#define E_SHORTWRITE	4
+#define E_FOPEN		5
+#define E_MALLOC	6
+#define E_OPENDIR	7
+#define E_WRONG_FTYPE	8
+
+#define	TARBLOCKSIZE	512
+
+#define NAME_FIELD_SIZE   100
+#define PREFIX_FIELD_SIZE 155
+#define UNAME_FIELD_SIZE   32
+#define GNAME_FIELD_SIZE   32
+
+#define TMAGIC   "ustar "	/* ustar and a null */
+#define TMAGLEN  6
+#define TVERSION " \0"		/* 00 and no null */
+#define TVERSLEN 2
+
+#define REGTYPE	 '0'		/* regular file */
+#define AREGTYPE '\0'		/* regular file */
+#define LNKTYPE  '1'		/* link */
+#define SYMTYPE  '2'		/* reserved */
+#define CHRTYPE  '3'		/* character special */
+#define BLKTYPE  '4'		/* block special */
+#define DIRTYPE  '5'		/* directory */
+#define FIFOTYPE '6'		/* FIFO special */
+#define CONTTYPE '7'		/* reserved */
+
+#define BUF_SIZE (1024*64)
+
+//#define strtoul simple_strtoul
+#define strtoul simple_strtoul_wrapper
+
+/* POSIX header  */
+struct fileHeader
+{					/* byte offset */
+  char name[NAME_FIELD_SIZE];		/*   0 */
+  char mode[8];				/* 100 */
+  char uid[8];				/* 108 */
+  char gid[8];				/* 116 */
+  char size[12];			/* 124 */
+  char mtime[12];			/* 136 */
+  char chksum[8];			/* 148 */
+  char typeflag;			/* 156 */
+  char linkname[NAME_FIELD_SIZE];	/* 157 */
+  char magic[TMAGLEN];			/* 257 */
+  char version[TVERSLEN];		/* 263 */
+  char uname[UNAME_FIELD_SIZE];		/* 265 */
+  char gname[GNAME_FIELD_SIZE];		/* 297 */
+  char devmajor[8];			/* 329 */
+  char devminor[8];			/* 337 */
+  char prefix[PREFIX_FIELD_SIZE];	/* 345 */
+					/* 500 */
+};
+
+union TarInfo 
+{
+  char buf[TARBLOCKSIZE];
+  struct fileHeader header;
+};
+
+typedef union TarInfo	TarInfo;
+
+extern int sys_write(unsigned int fd,char * buf,unsigned int count);
+extern int sys_chmod(const char * filename, mode_t mode);
+extern int sys_chown(const char * filename, uid_t user, gid_t group);
+extern int sys_mknod(const char * filename, int mode, dev_t dev);
+extern int sys_mkdir(const char * pathname, int mode);
+extern int sys_chdir(const char * filename);
+extern int sys_link(const char * oldname, const char * newname);
+extern int sys_symlink(const char * oldname, const char * newname);
+extern int sys_utime(char * filename, struct utimbuf * times);
+extern int sys_time(int * tloc);
+
+	char *buf = 0;
+	int err, fd;
+	unsigned long fsize, fsizebuf, rwsize;
+	mode_t fmode;
+	kdev_t fdev;
+	
+	struct inode inode;
+	struct file infile;
+	struct dentry in_dentry;
+	kdev_t ram_device;
+	struct utimbuf ut;
+	union TarInfo *tarInfo;	
+    	
+	ram_device = MKDEV(MAJOR_NR,1);
+	
+  	memset(&infile, 0, sizeof(infile));
+	memset(&inode, 0, sizeof(inode));
+	memset(&in_dentry, 0, sizeof(in_dentry));
+	inode.i_rdev = MKDEV(MAJOR_NR, 1);
+	infile.f_mode = 1; /* read only */
+	infile.f_dentry = &in_dentry;
+	in_dentry.d_inode = &inode;
+    	
+	if (blkdev_open(&inode, &infile) != 0) return -1;
+  
+  
+	//sanity check
+	infile.f_pos = 0;
+  
+	tarInfo = kmalloc(TARBLOCKSIZE,GFP_KERNEL);
+	if(tarInfo == 0) {
+		printk(KERN_ERR "RAMDISK: Can't allocate tar header buffer\n");
+		err=-1;
+		goto exit;
+	}
+	memset(tarInfo,0,TARBLOCKSIZE);  
+
+	buf = kmalloc(BUF_SIZE,GFP_KERNEL);
+  	if(buf == 0) {
+		printk(KERN_ERR "RAMDISK: Can't allocate tar dump buffer\n");
+		err=-1;
+		goto exit;
+	}
+	memset(buf,0,BUF_SIZE);  
+
+	printk(KERN_NOTICE "RAMDISK: Extracting root archive: ");
+
+/* main loop */  
+	while(1) {
+       
+		//read header or return short read
+		err=infile.f_op->read(&infile, (char *)tarInfo, TARBLOCKSIZE, &infile.f_pos);
+		if(err < TARBLOCKSIZE) {
+			if(err == 0) {
+				goto exit;
+			} else {
+				printk(KERN_ERR "RAMDISK: Corrupt tar archive\n");
+				err=-1;
+				goto exit;
+			}
+		}
+
+		fmode=strtoul(tarInfo->header.mode,NULL,8);
+		fsize=strtoul(tarInfo->header.size,NULL,8);
+	
+#ifdef DEBUG_UNTAR
+printk("\ntype: %c ",tarInfo->header.typeflag);   
+printk("name: %s ",tarInfo->header.name);
+printk("fsize: %ld ",fsize); 
+udelay(100000);
+#endif
+
+/*
+ * This should fix the problem with '\0' named dirs killing the archive
+ * extraction. A better way would be to look to see if fsize[0] contains 
+ * '\0' as a normal header would either have a number their or pad it with
+ * a ' '. Not sure if all tar's do this, so it may not be safe
+ */
+
+		if((tarInfo->header.name[0] == '\0') && (fmode == 0) && (fsize == 0)) {
+			err=0;
+			goto exit;
+		}
+
+		err=0;
+
+		//check the type
+		switch(tarInfo->header.typeflag) {
+		
+			case AREGTYPE : 
+			case REGTYPE  :
+			
+				fd=sys_open(tarInfo->header.name, O_CREAT|O_WRONLY|O_TRUNC, fmode);
+
+				if(fd == -1) {
+					err=1;
+					break;
+				}
+
+				//dump the file in big blocks
+				fsizebuf = fsize;
+
+				while (fsizebuf > 0) {
+	  
+					if (fsizebuf > BUF_SIZE)
+						rwsize = BUF_SIZE;
+					else
+						rwsize = fsizebuf;
+
+					if (infile.f_op->read(&infile , buf, rwsize, &infile.f_pos) < rwsize) 
+						err=1;
+		
+					if (sys_write(fd, buf, rwsize) < rwsize)
+						err=1;
+			
+					fsizebuf -= rwsize;
+				}
+
+				sys_close(fd);
+	
+				if(fsize%TARBLOCKSIZE != 0) 
+					infile.f_pos += (TARBLOCKSIZE*(fsize/TARBLOCKSIZE+1))-fsize;
+	
+				break;
+      
+			case LNKTYPE  :
+			
+				err=sys_link(tarInfo->header.linkname,tarInfo->header.name);
+				break;
+
+			case SYMTYPE  :
+			
+				err=sys_symlink(tarInfo->header.linkname,tarInfo->header.name);
+				break;
+	
+			case CHRTYPE  :	
+			case BLKTYPE  :	
+			case FIFOTYPE :	
+			
+				fdev=MKDEV(strtoul(tarInfo->header.devmajor,NULL,8),
+					   strtoul(tarInfo->header.devminor,NULL,8));
+				err=sys_mknod(tarInfo->header.name,fmode,fdev);
+       				break;
+	
+			case DIRTYPE  :
+	
+				//Skip if name is "" "./" "." ".."
+				if((tarInfo->header.name[0] != '.' && tarInfo->header.name[0] != '\0') &&
+				   (tarInfo->header.name[1] != '/' && tarInfo->header.name[1] != '\0') &&
+				   (tarInfo->header.name[1] != '\0')) {
+				err=sys_mkdir(tarInfo->header.name,fmode);
+				} else {
+					continue;
+				}	
+				break;
+	
+			default:
+				printk(KERN_ERR "RAMDISK: corrupt tar archive\n");
+				err=-1;
+				goto exit;
+		}
+
+
+		//Good idea to continue anyhow??
+		if(err)
+			printk("\nError making %s", tarInfo->header.name);
+    
+	
+		if(tarInfo->header.typeflag != LNKTYPE && tarInfo->header.typeflag != SYMTYPE) {
+			err=sys_chown(tarInfo->header.name,
+				      strtoul(tarInfo->header.uid,NULL,8),
+				      strtoul(tarInfo->header.gid,NULL,8));
+			err=sys_chmod(tarInfo->header.name,fmode);
+		}
+
+		if(err)
+			printk("\nError chown and/or chmod %s", tarInfo->header.name);
+		
+		ut.actime=sys_time(NULL);
+		ut.modtime=strtoul(tarInfo->header.mtime,NULL,8);
+		sys_utime(tarInfo->header.name,&ut);
+	
+	}
+/* end main loop */
+
+exit:
+
+	kfree(tarInfo);
+	kfree(buf);
+	invalidate_buffers(ram_device);
+
+	if (infile.f_op->release)
+		infile.f_op->release(&inode, &infile);
+
+	printk("done.\n");
+
+	return (err);
+	
+}
+
+/*
+ * simple_strtoul() does not strip leading spaces (0x20) from the input
+ * string. The 'real' strtoul does. This wrapper works around this.
+ * NOTE: This probably should be fixed in: lib/vsprintf.c 
+ *
+ */
+
+static
+unsigned long simple_strtoul_wrapper(const char *cp,char **endp,unsigned int base)
+{
+	while (*cp == ' ') {
+		cp++;
+	}
+
+	return ( simple_strtoul(cp,endp,base) );
+}
diff -uNr linux-2.2.8-virgin/init/main.c linux-2.2.8-initrd_arch/init/main.c
--- linux-2.2.8-virgin/init/main.c	Tue May 11 12:57:14 1999
+++ linux-2.2.8-initrd_arch/init/main.c	Wed May 12 21:23:17 1999
@@ -244,6 +244,10 @@
 #ifdef CONFIG_BLK_DEV_INITRD
 static void no_initrd(char *s,int *ints);
 #endif
+#ifdef CONFIG_BLK_DEV_INITRD_ARCHIVE
+extern void initrd_untar(void);
+extern int initrd_archive;
+#endif
 #endif CONFIG_BLK_DEV_RAM
 #ifdef CONFIG_ISDN_DRV_ICN
 extern void icn_setup(char *str, int *ints);
@@ -323,6 +327,9 @@
 #ifdef CONFIG_ROOT_NFS
 extern void nfs_root_setup(char *str, int *ints);
 #endif
+#ifdef CONFIG_BLK_DEV_INITRD_ARCHIVE
+extern void initrd_archive_setup(char *str, int *ints);
+#endif
 #ifdef CONFIG_FTAPE
 extern void ftape_setup(char *str, int *ints);
 #endif
@@ -562,6 +569,9 @@
 	{ "ramdisk_size=", ramdisk_size },
 #ifdef CONFIG_BLK_DEV_INITRD
 	{ "noinitrd", no_initrd },
+#ifdef CONFIG_BLK_DEV_INITRD_ARCHIVE
+	{ "initrd_archive=", initrd_archive_setup },
+#endif	
 #endif
 #endif
 #ifdef CONFIG_FB
@@ -1323,6 +1333,12 @@
 
 	/* Mount the root filesystem.. */
 	mount_root();
+
+#ifdef CONFIG_BLK_DEV_INITRD_ARCHIVE
+	if (initrd_archive)	
+		initrd_untar();
+#endif	
+
 
 #ifdef CONFIG_UMSDOS_FS
 	{
