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 + * + * 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 +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include + + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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, ¶m, 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 *) ¶m; + 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(¶m, 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(¶m), + ¶m.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(¶m)) + / 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 +#include +#include +#include + +#include +#include +#include + +#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 ; iwrite(&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 +#include +#include +#include +#include + +//DEBUG_UNTAR only +// #include + + +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 {