diff -uNr linux-2.4.16-virgin/Documentation/Configure.help linux-2.4.16-initrd_dyn/Documentation/Configure.help --- linux-2.4.16-virgin/Documentation/Configure.help Thu Nov 22 13:52:44 2001 +++ linux-2.4.16-initrd_dyn/Documentation/Configure.help Sun Dec 9 04:04:48 2001 @@ -438,6 +438,52 @@ "real" root file system, etc. See for details. +Initial RAM disk dynamic creation support + CONFIG_BLK_DEV_INITRD_DYN + Initrd Dynamic allows you to use tar.gz archive(s) instead of those + nasty raw images. It works by dynamically creating a filesystem at + boot, mounting it as '/', then extracting the archive(s) loaded into + the initrd memory space. If your bootloader can load multiple archives + sequentially (IE a patched GRUB) all archives will be extracted in the + order they where loaded. + + Optionally Initrd Dynamic can create the /dev directory and some + failsafe console files. + + You must select at least one of the available filesystems below. + You probably want to use tmpfs if it's available in your kernel. + + The kernel parameter to specify options is: + initrd_dyn=fstype[,fssize[k|m]][,mkdev] + + fstype == One of the supported dynamic mkfs filesystems. + + fssize == Limits the size of the filesystem created. + tmpfs: If not speced it's equal to the real memory space. + minix: If not speced it's equal to ramdisk_size. + + mkdev == /dev is created after archive untar. Useful even if devfs=mount. + + Examples: + initrd_dyn=tmpfs load_ramdisk=1 + initrd_dyn=tmpfs,4096k load_ramdisk=1 + initrd_dyn=tmpfs,16m,mkdev load_ramdisk=1 + + initrd_dyn=minix,8m ramdisk_size=20480 root=/dev/ram0 load_ramdisk=1 + initrd_dyn=minix,,mkdev root=/dev/rd/0 load_ramdisk=1 + + Initial RAM disk tmpfs auto filesystem support + CONFIG_BLK_DEV_INITRD_DYN_TMPFS + Specing initrd_tar=tmpfs[,fssize] will have the kernel dynamically + mount a tmpfs filesystem as the root. Spec a normal tar.gz file for + the boot loader to load as the initrd root archive. + + Initial RAM disk minix auto filesystem support + CONFIG_BLK_DEV_INITRD_DYN_MINIX + Specing initrd_tar=minix[,fssize] will have the kernel dynamically + create a minix filesystem on /dev/ram0 at boot time. Spec a normal + tar.gz file for the boot loader to load as the initrd root archive. + Loopback device support CONFIG_BLK_DEV_LOOP Saying Y here will allow you to use a regular file as a block diff -uNr linux-2.4.16-virgin/drivers/block/Config.in linux-2.4.16-initrd_dyn/drivers/block/Config.in --- linux-2.4.16-virgin/drivers/block/Config.in Fri Sep 14 17:04:06 2001 +++ linux-2.4.16-initrd_dyn/drivers/block/Config.in Sun Dec 9 04:03:37 2001 @@ -45,5 +45,8 @@ int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096 fi dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM +dep_bool ' Initial RAM disk dynamic creation support' CONFIG_BLK_DEV_INITRD_DYN $CONFIG_BLK_DEV_INITRD +dep_bool ' Initial RAM disk tmpfs mkfs support' CONFIG_BLK_DEV_INITRD_DYN_TMPFS $CONFIG_BLK_DEV_INITRD_DYN +dep_bool ' Initial RAM disk minix mkfs support' CONFIG_BLK_DEV_INITRD_DYN_MINIX $CONFIG_BLK_DEV_INITRD_DYN endmenu diff -uNr linux-2.4.16-virgin/drivers/block/rd.c linux-2.4.16-initrd_dyn/drivers/block/rd.c --- linux-2.4.16-virgin/drivers/block/rd.c Fri Nov 9 17:15:00 2001 +++ linux-2.4.16-initrd_dyn/drivers/block/rd.c Sun Dec 9 04:03:37 2001 @@ -87,6 +87,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; #endif @@ -131,6 +134,9 @@ unsigned long initrd_start, initrd_end; int mount_initrd = 1; /* zero if initrd should not be mounted */ int initrd_below_start_ok; +#ifdef CONFIG_BLK_DEV_INITRD_DYN +extern int initrd_dyn_mkfs(void); +#endif static int __init no_initrd(char *str) { @@ -659,8 +665,8 @@ */ static void __init 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; @@ -709,8 +715,21 @@ if (nblocks == 0) { #ifdef BUILD_CRAMDISK - if (crd_load(&infile, &outfile) == 0) - goto successful_load; +# ifdef CONFIG_BLK_DEV_INITRD_DYN + switch (initrd_dyn_mkfs()) { //dc: Prepare filesystem on ram0 + case 0: return; + case -1: goto done; + } +# 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 " @@ -854,6 +873,10 @@ { rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),rd_image_start,0); } + +#ifdef CONFIG_BLK_DEV_INITRD_DYN + #include "rd.dyn.c" +#endif #endif #endif /* RD_LOADER */ diff -uNr linux-2.4.16-virgin/drivers/block/rd.dyn.c linux-2.4.16-initrd_dyn/drivers/block/rd.dyn.c --- linux-2.4.16-virgin/drivers/block/rd.dyn.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.16-initrd_dyn/drivers/block/rd.dyn.c Mon Dec 10 14:04:08 2001 @@ -0,0 +1,565 @@ +/* + * rd.dyn.c + * + * Copyright 1998-2001 Dave Cinege + * with portions by Dimitri Maziuk (untar) and Robert Kaiser (gunzip buffer) + * + * Some parts might have been stolen from GNU 'Let's make the same archive + * 10 different ways' tar. (However I doubt much is left.) + * + * 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 + * + * NOTE: Tar can store 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. + * + * 1998-01-10 + * First version + * + * 1998-01-17 + * DC: 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. + * + * 1998-02-22 + * DC: 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 + * DC: Move to simple_strtoul function. No hope of bug being fixed in kernel. + * + * 2000-04-14 + * Partly re-written by Robert Kaiser (rkaiser@sysgo.de) to support + * uncompressing/extracting through a buffer in one pass. /dev/ram1 + * no longer used. + * + * 2000-05-22 + * DC: Merged and standardized buffer patch. Upgraded to Linux 2.3.99 series. + * Code now creates /dev dir and several /dev files reguardless of archive + * contents. I'm getting sick of seeing "Could not open an initial console." + * Why didn't I do this 2 years ago? + * + * 2000-05-27 + * Major code reorganization. Most all code now resides in rd.untar.c. + * rd.dyn.c (formally rd.untar.c.) and is unified for 2.0/2.2/2.4 versions + * of the Linux kernel. + * The version specific defining is a bit ugly, but maintaining and porting + * this feature is now GREATLY simplified. + * + * 2001-01-27 + * Support extracting mutiple tgz's loaded inline as an initrd. + * Requires bootloader to load them that way. GRUB patches available. + * + * 2001-08-18 + * Added support for using tmpfs. Requires >= 2.4.7(?) Ext2 and ramfs framework + * purged. fssize argument now understands the k and m suffix. + * Properly doesn't run if load_ramdisk == 0 + * + */ + +#include +#include +#include +#include +#include + +//#define DEBUG_UNTAR + +#include "rd.dyn.h" + +extern int rd_size; + +static unsigned long simple_strtoul_wrapper(const char *cp,char **endp,unsigned int base); +static int untar(void); +static int mkfs_minix(int fssize); +static int mkfs_tmpfs(int fssize); + +static int initrd_dyn_fstype = 0; +static int initrd_dyn_dev = 0; + +unsigned long initrd_dyn_fssize = 0; + +#if defined(L20) + #define INITRD_DYN_SETUP int initrd_dyn_setup(char *line, int *ints) + #define INITRD_DYN_MKFS int initrd_dyn_mkfs(void) + #define INITRD_DYN_MKDEV int initrd_dyn_mkdev(void) + #define INITRD_DYN_MKROOT int initrd_dyn_mkroot(void) + #define UNTAR_WRITE static int untar_write( struct inode *ip, struct file *fp, const char *buf, int count) + #define UNTAR static int untar(void) +#else + #if defined(L22) + #define INITRD_DYN_SETUP int __init initrd_dyn_setup(char *line, int *ints) + #else + #define INITRD_DYN_SETUP int __init initrd_dyn_setup(char *line) + #endif + #define INITRD_DYN_MKFS int __init initrd_dyn_mkfs(void) + #define INITRD_DYN_MKDEV int __init initrd_dyn_mkdev(void) + #define INITRD_DYN_MKROOT int __init initrd_dyn_mkroot(void) + #define UNTAR_WRITE static ssize_t __init untar_write( struct file *fp, const char *buf, size_t count, loff_t *fpos) + #define UNTAR static int __init untar(void) +#endif + +#if !defined(L24) + #define STRUCT_INODE struct inode inode + #define INODE &inode +#else + #define STRUCT_INODE struct inode *inode + #define INODE inode +#endif + +INITRD_DYN_SETUP +{ + char *fssize; + + if (strncmp(line,"minix",5) == 0) + initrd_dyn_fstype = MKMINIX; + if (strncmp(line,"tmpfs",5) == 0) + initrd_dyn_fstype = MKTMPFS; + + fssize = strchr(line, ','); // Parse options. Jesus, this is scary. + if (fssize != NULL) { + char * mkdev = strchr(++fssize, ','); + if (mkdev != NULL) { + + *mkdev = 0; // Probably blasphamy... + if (*++mkdev != 0) + initrd_dyn_dev = 1; + } + if(*fssize != 0 && *fssize != ',') { // Recognize k and m suffix to size + char * fssize_byte; + int mutiple = 1; + if ((fssize_byte = strrchr(fssize, 'k'))) + fssize_byte = 0; + + if ((fssize_byte = strrchr(fssize, 'm'))) { + fssize_byte = 0; + mutiple = 1024; + } + + initrd_dyn_fssize = simple_strtoul(fssize,NULL,10); + initrd_dyn_fssize *= mutiple; + } + } + + return 0; +} +#if defined(L24) +__setup("initrd_dyn=", initrd_dyn_setup); +#endif + +INITRD_DYN_MKFS +{ + if (initrd_dyn_fstype == 0 || rd_doload == 0) + return 0; + + printk(KERN_NOTICE "RAMDISK: Auto Filesystem - "); + + switch (initrd_dyn_fstype) { + case MKMINIX: if (initrd_dyn_fssize > rd_size || initrd_dyn_fssize <= 0) initrd_dyn_fssize = rd_size; + if (mkfs_minix(initrd_dyn_fssize) == 0) return 0; else goto fserror; + + case MKTMPFS: if (mkfs_tmpfs(initrd_dyn_fssize) == 0) return 0; else goto fserror; + default: +fserror: printk("unknown fs specified or mkfs error!\n"); + } + + return -1; +} + +INITRD_DYN_MKDEV +{ + // Create /dev and possible consoles. I think it's a good idea to include this + // even if DEVFS is compiled in. Default permissions are STRONG. + // Will not change pemissions if file existed in the previous archive. + // Set remaining permissions in userland. + printk(KERN_NOTICE "RAMDISK: Creating failsafe /dev/ hiearchy: "); + + sys_mkdir("/dev", 0700); + sys_mknod("/dev/tty", S_IFCHR + 0600, MKDEV(TTYAUX_MAJOR, 0)); + sys_mknod("/dev/console", S_IFCHR + 0600, MKDEV(TTYAUX_MAJOR, 1)); + sys_mknod("/dev/tty0", S_IFCHR + 0600, MKDEV(TTY_MAJOR, 0)); + sys_mknod("/dev/tty1", S_IFCHR + 0600, MKDEV(TTY_MAJOR, 1)); + sys_mknod("/dev/null", S_IFCHR + 0600, MKDEV(MEM_MAJOR, 3)); // Everybody loves /dev/null... + sys_mknod("/dev/ttyS0", S_IFCHR + 0600, MKDEV(TTY_MAJOR, 64)); + sys_mknod("/dev/ttyS1", S_IFCHR + 0600, MKDEV(TTY_MAJOR, 65)); + sys_mknod("/dev/lp0", S_IFCHR + 0600, MKDEV(LP_MAJOR, 0)); + sys_mknod("/dev/lp1", S_IFCHR + 0600, MKDEV(LP_MAJOR, 1)); + + printk("done.\n"); + return 0; +} + +INITRD_DYN_MKROOT +{ + if (initrd_dyn_fstype != 0 && rd_doload != 0) { + untar(); + if (initrd_dyn_dev != 0) + initrd_dyn_mkdev(); + } + + return 0; +} + +// This is called by flush_window to flush the gzip output +// buffer (containing part of a tar image). +UNTAR_WRITE +{ + int i, scoop, err, file_written = 0; + char *to; + kdev_t fdev; + struct utimbuf ut; + struct untar_context *Untar; +#ifndef DEBUG_UNTAR +#ifndef CONFIG_ARCH_S390 + char rotator[4] = { '|' , '/' , '-' , '\\' }; + + // pointer to our context structure is passed thru ioctl fop + Untar = (struct untar_context*)fp->f_op->ioctl; + + printk("%c\b", rotator[Untar->rotate & 0x3]); + Untar->rotate++; +#endif +#endif + // Note: the gunzip routines call this only when + // a) the gunzip buffer is full -> count = WSIZE = 64 * TARBLOCKSIZE + // or b) to flush the last bytes out + while(count) { // What is our current state ? + err = 0; + switch(Untar->state) { + case READING_HEADER: + // Get the tar header + if(count < TARBLOCKSIZE) { + count = 0; + break; + } + to = (char*)&Untar->tarInfo; + for(i = 0; i < TARBLOCKSIZE; i++) { + *to++ = *buf++; + --count; + } + + // Tar usually pads the output byte to a multiple of it's block size usually + // 10 KB, appending zeroes if necessary. Here we skip those zeroes: + if(Untar->tarInfo.header.name[0] == '\0' && + Untar->tarInfo.header.mode[0] == '\0' && + Untar->tarInfo.header.mode[0] == '\0') { + if(count < TARBLOCKSIZE) + count = 0; + break; + } + // determine mode, size, uid, gid + Untar->fmode = strtoul(Untar->tarInfo.header.mode,NULL,8); + Untar->fsize = strtoul(Untar->tarInfo.header.size,NULL,8); + Untar->uid = strtoul(Untar->tarInfo.header.uid,NULL,8); + Untar->gid = strtoul(Untar->tarInfo.header.gid,NULL,8); +#ifdef DEBUG_UNTAR + printk("\ntype: %c ",Untar->tarInfo.header.typeflag); + printk("name: %s ",Untar->tarInfo.header.name); + printk("Untar->fsize: %ld ",Untar->fsize); + udelay(100000); +#endif + // check the type + switch(Untar->tarInfo.header.typeflag) { + case AREGTYPE : + case REGTYPE : + Untar->out = sys_open(Untar->tarInfo.header.name, + O_CREAT|O_WRONLY|O_TRUNC, Untar->fmode); + + if(Untar->out == -1) { + err = 1; + break; + } + Untar->state = READING_DATA; + break; + case LNKTYPE : + err = sys_link(Untar->tarInfo.header.linkname, + Untar->tarInfo.header.name); + break; + + case SYMTYPE : + err = sys_symlink(Untar->tarInfo.header.linkname, + Untar->tarInfo.header.name); + break; + + case CHRTYPE : + case BLKTYPE : + case FIFOTYPE : + fdev = MKDEV(strtoul(Untar->tarInfo.header.devmajor,NULL,8), + strtoul(Untar->tarInfo.header.devminor,NULL,8)); + err = sys_mknod(Untar->tarInfo.header.name,Untar->fmode,fdev); + break; + + case DIRTYPE : + if((Untar->tarInfo.header.name[0] != '.' && // Skip if name is "" "./" "." ".." */ + Untar->tarInfo.header.name[0] != '\0') && + (Untar->tarInfo.header.name[1] != '/' && + Untar->tarInfo.header.name[1] != '\0') && + (Untar->tarInfo.header.name[1] != '\0')) { + err = sys_mkdir(Untar->tarInfo.header.name,Untar->fmode); + } + break; + default: + printk(KERN_ERR "RAMDISK: corrupt tar archive\n"); + Untar->state = SKIPPING_REST; + return(-1); + } + break; + case READING_DATA: + scoop = 0; + while(count > 0 && Untar->fsize > 0) { + scoop = Untar->fsize > TARBLOCKSIZE ? TARBLOCKSIZE : Untar->fsize; + if(sys_write(Untar->out, buf, scoop) < scoop) + err = 1; + count -= scoop; + buf += scoop; + Untar->fsize -= scoop; + } + if(Untar->fsize == 0) { //skip to the next tar block + sys_close(Untar->out); + scoop = count % TARBLOCKSIZE; + buf += scoop; + count -= scoop; + Untar->state = READING_HEADER; + file_written = 1; + } + break; + + case SKIPPING_REST: + count = 0; + break; + } + if(err) + printk("!"); + //printk("\nError making %s", Untar->tarInfo.header.name); + + if(file_written) { + + err = sys_chown(Untar->tarInfo.header.name, Untar->uid, Untar->gid); + + if(Untar->tarInfo.header.typeflag != LNKTYPE && + Untar->tarInfo.header.typeflag != SYMTYPE) { + err += sys_chmod(Untar->tarInfo.header.name, Untar->fmode); + } + + if(err) + printk("\nError chown and/or chmod %s", Untar->tarInfo.header.name); + ut.actime=sys_time(NULL); + ut.modtime=strtoul(Untar->tarInfo.header.mtime,NULL,8); + sys_utime(Untar->tarInfo.header.name,&ut); + file_written = 0; + } + } + return(0); +} + +typedef int (*ioctl_fop_t)(struct inode *, struct file *, unsigned int, unsigned long); + +UNTAR +{ + STRUCT_INODE; + +#if !defined(L20) + struct dentry in_dentry, out_dentry; +#endif + struct file infile, outfile; + struct file_operations out_fops; + kdev_t device; + int err; + struct untar_context *Untar; + int i; + + // Get buffers for tar extractor + if(!(Untar = kmalloc(sizeof(*Untar), GFP_KERNEL))) { + printk(KERN_ERR "RAMDISK: Couldn't allocate untar buffer\n"); + return(-1); + } + Untar->state = READING_HEADER; // Begin reading header + Untar->rotate = 0; + + // Load from initrd: initrd has already been left open by rd_load_image(). + // We don't open again to ensure proper deallocation + device = MKDEV(MAJOR_NR, INITRD_MINOR); + +#if defined(L20) + memset(&infile, 0, sizeof(infile)); + memset(&inode, 0, sizeof(inode)); + inode.i_rdev = device; + infile.f_mode = 1; // read only + infile.f_op = &initrd_fops; + infile.f_inode = &inode; + +#elif defined(L22) + memset(&infile, 0, sizeof(infile)); + memset(&inode, 0, sizeof(inode)); + memset(&in_dentry, 0, sizeof(in_dentry)); + inode.i_rdev = device; + infile.f_mode = 1; // read only + infile.f_dentry = &in_dentry; + infile.f_op = &initrd_fops; + in_dentry.d_inode = &inode; + +#elif defined(L24) + if ((inode = get_empty_inode()) == NULL) { + iput(inode); + return -1; + } + memset(&infile, 0, sizeof(infile)); + memset(&in_dentry, 0, sizeof(in_dentry)); + infile.f_mode = 1; // read only + infile.f_dentry = &in_dentry; + in_dentry.d_inode = inode; + infile.f_op = &initrd_fops; + init_special_inode(inode, S_IFBLK | S_IRUSR, kdev_t_to_nr(device)); + #if LINUX_VERSION_CODE > UNTAR_LINUX_VERSION(2,4,10) + inode->i_bdev = bdget(kdev_t_to_nr(inode->i_rdev)); + #endif +#endif + + // Build a fake outfile descriptor for use with gunzip(). All gunzip will + // ever do with it is to call the write function. We misuse the fops.iocl + // entry here to pass a pointer to Untar down to untar_write() + +#if defined(L20) + memset(&outfile, 0, sizeof(outfile)); + memset(&out_inode, 0, sizeof(out_inode)); + memset(&out_fops, 0, sizeof(out_fops)); + out_inode.i_rdev = 0; // don't care + outfile.f_mode = 3; // don't care + out_fops.write = untar_write; + out_fops.ioctl = (ioctl_fop_t)Untar; + outfile.f_op = &out_fops; + outfile.f_inode = &out_inode; + +#elif defined(L22) + memset(&outfile, 0, sizeof(outfile)); + memset(&out_inode, 0, sizeof(out_inode)); + memset(&out_dentry, 0, sizeof(out_dentry)); + memset(&out_fops, 0, sizeof(out_fops)); + out_inode.i_rdev = 0; // don't care + outfile.f_mode = 3; // don't care + out_fops.write = untar_write; + out_fops.ioctl = (ioctl_fop_t)Untar; + outfile.f_dentry = &out_dentry; + outfile.f_op = &out_fops; + out_dentry.d_inode = &out_inode; + +#elif defined(L24) + // dc: FIX ME This might not be 100% correct + memset(&outfile, 0, sizeof(outfile)); + memset(&out_inode, 0, sizeof(out_inode)); + memset(&out_dentry, 0, sizeof(out_dentry)); + memset(&out_fops, 0, sizeof(out_fops)); + outfile.f_mode = 3; //don't care + out_fops.write = untar_write; + out_fops.ioctl = (ioctl_fop_t)Untar; + outfile.f_dentry = &out_dentry; + outfile.f_op = &out_fops; + out_dentry.d_inode = out_inode; +#endif + + // Now uncompress & untar the initrd.tgz image(s) + // Continue for as long as we find gzip magic, for multiple tgz's. + for(i = 0;;i++) { + unsigned char buf[3]; + extern unsigned insize; // dc: FIX ME These raise a warning but seem to work ok. + extern unsigned inptr; // They keep us from having to change rd.c + + printk(KERN_NOTICE "RAMDISK: Extracting root archive[%d]: ",i); + + err = crd_load(&infile, &outfile); + if(err == 0) + printk("done.\n"); + + memset(buf, 0xe5, sizeof(buf)); + infile.f_pos = (infile.f_pos - insize) + inptr; // Place fp where gunzip ended, not buffer. + infile.f_op->read(&infile, buf, sizeof(buf), &infile.f_pos); // Read magic + infile.f_pos -= sizeof(buf); + + if (buf[0] != 037 || ((buf[1] != 0213) && (buf[1] != 0236))) // Test gzip magic + break; + } + + // Free buffer + kfree(Untar); + + // Free the initrd image + invalidate_buffers(device); + +#ifdef DEBUG_UNTAR + printk("\ninitrd_users = %d ",initrd_users); +#endif + + // Close the initrd device, freeing it's space + if(infile.f_op->release) + infile.f_op->release(INODE, &infile); + +#ifdef DEBUG_UNTAR + printk("-> %d\n",initrd_users); +#endif + + 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) ); +} + + +#ifdef CONFIG_BLK_DEV_INITRD_DYN_MINIX + #ifndef CONFIG_MINIX_FS + #error: "This won't do you much good without minix fs support!" + #endif + #include "rd.dyn.mkfs_minix.c" +#else + static int mkfs_minix(int fssize) { + printk("kernel does not support minix auto fs!\n"); return -1; + } +#endif + +#ifdef CONFIG_BLK_DEV_INITRD_DYN_TMPFS + #ifndef CONFIG_TMPFS + #error: "This won't do you much good without tmpfs support!" + #endif + //This is probably moot since tmpfs is quite new... + #if defined(L20) + #define MKFS_TMPFS static int mkfs_tmpfs(int fssize) + #else + #define MKFS_TMPFS static int __init mkfs_tmpfs(int fssize) + #endif + MKFS_TMPFS + { + // dc: FIX ME this minor may not be correct. I grabbed it from + // what someone was using for ramfs + ROOT_DEV = MKDEV(UNNAMED_MAJOR, 0xfe); // Tag ROOTDEV as tmpfs + + printk("Virtual Memory Filesystem."); + if (fssize > 0) + printk(" [%dk ceiling]", fssize); + + printk("\n"); + + return 0; + } +#else + static int mkfs_tmpfs(int fssize) { + printk("kernel does not support tmpfs auto fs!\n"); return -1; + } +#endif diff -uNr linux-2.4.16-virgin/drivers/block/rd.dyn.h linux-2.4.16-initrd_dyn/drivers/block/rd.dyn.h --- linux-2.4.16-virgin/drivers/block/rd.dyn.h Wed Dec 31 19:00:00 1969 +++ linux-2.4.16-initrd_dyn/drivers/block/rd.dyn.h Mon Dec 10 17:10:04 2001 @@ -0,0 +1,116 @@ +#ifdef DEBUG_UNTAR + #include +#endif + + +#define BUF_SIZE (1024*64) + +#define strtoul simple_strtoul_wrapper + + +#define UNTAR_LINUX_VERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch)) + +#ifndef LINUX_VERSION_CODE + #include +#endif + +#if LINUX_VERSION_CODE > UNTAR_LINUX_VERSION(2,3,99) + #define L24 +#elif LINUX_VERSION_CODE > UNTAR_LINUX_VERSION(2,1,0) + #define L22 +#elif LINUX_VERSION_CODE > UNTAR_LINUX_VERSION(2,0,0) + #define L20 +#endif + +#define MKMINIX 1 +#define MKTMPFS 4 + +#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 + +// 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 +}; + +typedef union TarInfo +{ + char buf[TARBLOCKSIZE]; + struct fileHeader header; +} TarInfo; + +enum untar_status +{ + READING_HEADER, + READING_DATA, + SKIPPING_REST +}; + +struct untar_context +{ + TarInfo tarInfo; + enum untar_status state; + mode_t fmode; + unsigned long fsize; + uid_t uid; + gid_t gid; + int out; + int rotate; +} *Untar; + + +extern int sys_write(unsigned int fd, const 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); diff -uNr linux-2.4.16-virgin/drivers/block/rd.dyn.mkfs_minix.c linux-2.4.16-initrd_dyn/drivers/block/rd.dyn.mkfs_minix.c --- linux-2.4.16-virgin/drivers/block/rd.dyn.mkfs_minix.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.16-initrd_dyn/drivers/block/rd.dyn.mkfs_minix.c Sun Dec 9 04:03:38 2001 @@ -0,0 +1,298 @@ +/* + * 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. + * + * 2000-05-27 + * Unified into 2.0/2.2/2.4 Linux kernel version. + * + * mkfs.c - make a linux (minix) file-system. + * + * (C) 1991 Linus Torvalds, et al... + * + */ + +#include +#include +#include +#include + +#include +#include +#if !defined(L20) +#include +#endif + +#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 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(char * buffer, int block_size); +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); + +#if defined(L20) + #define MKFS_MINIX static int mkfs_minix(int fssize) +#else + #define MKFS_MINIX static int __init mkfs_minix(int fssize) +#endif + + +MKFS_MINIX +{ + + char * tmp; + + //sanity check + outfile.f_pos = 0; + + magic = MINIX_SUPER_MAGIC2; + + BLOCKS = fssize; + + 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; + write_block(boot_block_buffer, 512); + outfile.f_pos = BLOCK_SIZE; + write_block(super_block_buffer, BLOCK_SIZE); + write_block(inode_map, IMAPS*BLOCK_SIZE); + write_block(zone_map, ZMAPS*BLOCK_SIZE); + write_block(inode_buffer, INODE_BUFFER_SIZE); +} + +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; + outfile.f_pos=inode->i_zone[0]*BLOCK_SIZE; + write_block(root_block,BLOCK_SIZE); +} + +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; + + if ( req_nr_inodes == 0 ) // some magic nrs: 1 inode / 3 blocks + inodes = BLOCKS/3; + else + inodes = req_nr_inodes; + if (inodes > 65535) + inodes = 65535; + INODES = inodes; + + if ((INODES & 8191) > 8188) // I don't want some off-by-one errors, so this hack... + 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.f_inode,&outfile,buffer,block_size); +#else + outfile.f_op->write(&outfile, buffer, block_size, &outfile.f_pos); +#endif +} + +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.4.16-virgin/fs/super.c linux-2.4.16-initrd_dyn/fs/super.c --- linux-2.4.16-virgin/fs/super.c Mon Nov 26 08:29:17 2001 +++ linux-2.4.16-initrd_dyn/fs/super.c Mon Dec 10 18:35:37 2001 @@ -933,6 +933,23 @@ #endif root_mountflags |= MS_VERBOSE; +#if defined CONFIG_TMPFS && defined CONFIG_BLK_DEV_INITRD_DYN_TMPFS + if (ROOT_DEV == MKDEV(UNNAMED_MAJOR, 0xfe)) { + extern unsigned long initrd_dyn_fssize; + char fs_data[80] = {0}; + + if (initrd_dyn_fssize > 0) + snprintf(fs_data, sizeof(fs_data), "size=%luk", initrd_dyn_fssize); + + vfsmnt = do_kern_mount("tmpfs", root_mountflags, "/dev/root", fs_data); + if (!IS_ERR(vfsmnt)) { + printk ("VFS: Mounted root (%s filesystem).\n","tmpfs"); + ROOT_DEV = vfsmnt->mnt_sb->s_dev; + goto attach_it; + } + } +#endif + #ifdef CONFIG_ROOT_NFS if (MAJOR(ROOT_DEV) != UNNAMED_MAJOR) goto skip_nfs; @@ -1066,9 +1083,7 @@ bdput(bdev); /* sb holds a reference */ -#ifdef CONFIG_ROOT_NFS attach_it: -#endif root_nd.mnt = root_vfsmnt; root_nd.dentry = root_vfsmnt->mnt_sb->s_root; graft_tree(vfsmnt, &root_nd); diff -uNr linux-2.4.16-virgin/init/main.c linux-2.4.16-initrd_dyn/init/main.c --- linux-2.4.16-virgin/init/main.c Fri Nov 9 17:15:00 2001 +++ linux-2.4.16-initrd_dyn/init/main.c Sun Dec 9 04:03:38 2001 @@ -107,6 +107,10 @@ extern void ipc_init(void); #endif +#ifdef CONFIG_BLK_DEV_INITRD_DYN +extern void initrd_dyn_mkroot(void); +#endif + /* * Boot command-line arguments */ @@ -766,13 +770,16 @@ /* Mount the root filesystem.. */ mount_root(); + +#ifdef CONFIG_BLK_DEV_INITRD_DYN + initrd_dyn_mkroot(); +#endif mount_devfs_fs (); #ifdef CONFIG_BLK_DEV_INITRD root_mountflags = real_root_mountflags; - if (mount_initrd && ROOT_DEV != real_root_dev - && MAJOR(ROOT_DEV) == RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) { + if (mount_initrd && MAJOR(ROOT_DEV) == RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) { int error; int i, pid;