diff -uNr linux-2.5.45-virgin/drivers/block/Kconfig linux-2.5.45-initrd_dyn/drivers/block/Kconfig --- linux-2.5.45-virgin/drivers/block/Kconfig 2002-11-01 05:24:59.000000000 -0500 +++ linux-2.5.45-initrd_dyn/drivers/block/Kconfig 2002-11-01 01:55:37.000000000 -0500 @@ -331,6 +331,18 @@ "real" root file system, etc. See for details. +config BLK_DEV_INITRD_UNTAR + bool "Initial RAM disk untar support (requires TMPFS)" + depends on BLK_DEV_INITRD && TMPFS + help + Untar support to a tmpfs root. Say Y. + +config BLK_DEV_INITRD_GUNZIP + bool "Initial RAM disk gunzip support" + depends on BLK_DEV_INITRD + help + Use gzip compressed images/archives with initrd. Say Y. + config LBD bool "Support for Large Block Devices" depends on X86 diff -uNr linux-2.5.45-virgin/include/linux/root_dev.h linux-2.5.45-initrd_dyn/include/linux/root_dev.h --- linux-2.5.45-virgin/include/linux/root_dev.h 2002-10-19 00:01:18.000000000 -0400 +++ linux-2.5.45-initrd_dyn/include/linux/root_dev.h 2002-11-01 03:11:42.000000000 -0500 @@ -3,6 +3,7 @@ enum { Root_NFS = MKDEV(UNNAMED_MAJOR, 255), + Root_TMPFS = MKDEV(UNNAMED_MAJOR, 12), Root_RAM0 = MKDEV(RAMDISK_MAJOR, 0), Root_RAM1 = MKDEV(RAMDISK_MAJOR, 1), Root_FD0 = MKDEV(FLOPPY_MAJOR, 0), diff -uNr linux-2.5.45-virgin/init/do_mounts.c linux-2.5.45-initrd_dyn/init/do_mounts.c --- linux-2.5.45-virgin/init/do_mounts.c 2002-11-01 05:25:08.000000000 -0500 +++ linux-2.5.45-initrd_dyn/init/do_mounts.c 2002-11-01 01:56:50.000000000 -0500 @@ -20,8 +20,6 @@ #include #include -#define BUILD_CRAMDISK - extern int get_filesystem_list(char * buf); extern asmlinkage long sys_mount(char *dev_name, char *dir_name, char *type, @@ -37,24 +35,16 @@ extern asmlinkage long sys_umount(char *name, int flags); extern asmlinkage long sys_ioctl(int fd, int cmd, unsigned long arg); -#ifdef CONFIG_BLK_DEV_INITRD -unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */ -static int __initdata mount_initrd = 1; +int root_mountflags = MS_RDONLY | MS_VERBOSE; -static int __init no_initrd(char *str) -{ - mount_initrd = 0; - return 1; -} +int __initdata rd_doload; /* 1 = load initrd, 0 = don't load */ +int __initdata rd_prompt = 1; /* 1 = prompt for initrd floppy, 0 = don't prompt */ +int __initdata rd_image_start; /* starting block # of image */ -__setup("noinitrd", no_initrd); -#else -static int __initdata mount_initrd = 0; +#ifdef CONFIG_BLK_DEV_INITRD_UNTAR +static unsigned long __initdata tmpfs_root_fssize = 0; #endif -int __initdata rd_doload; /* 1 = load RAM disk, 0 = don't load */ - -int root_mountflags = MS_RDONLY | MS_VERBOSE; static char root_device_name[64]; static char saved_root_name[64]; @@ -63,13 +53,6 @@ static int do_devfs = 0; -static int __init load_ramdisk(char *str) -{ - rd_doload = simple_strtol(str,NULL,0) & 3; - return 1; -} -__setup("load_ramdisk=", load_ramdisk); - static int __init readonly(char *str) { if (*str) @@ -85,7 +68,6 @@ root_mountflags &= ~MS_RDONLY; return 1; } - __setup("ro", readonly); __setup("rw", readwrite); @@ -220,7 +202,6 @@ saved_root_name[63] = '\0'; return 1; } - __setup("root=", root_dev_setup); static char * __initdata root_mount_data; @@ -236,7 +217,6 @@ root_fs_names = str; return 1; } - __setup("rootflags=", root_data_setup); __setup("rootfstype=", fs_names_setup); @@ -266,6 +246,20 @@ } *s = '\0'; } + +static void __init bad_root_panic(void) +{ + /* + * Allow the user to distinguish between failed open + * and bad superblock on root device. + */ + printk ("VFS: Cannot open root device \"%s\" or %s\n", + root_device_name, kdevname (to_kdev_t(ROOT_DEV))); + printk ("Please append a correct \"root=\" boot option\n"); + panic("VFS: Unable to mount root fs on %s", + kdevname(to_kdev_t(ROOT_DEV))); +} + static void __init mount_block_root(char *name, int flags) { char *fs_names = __getname(); @@ -284,15 +278,7 @@ case -EINVAL: continue; } - /* - * Allow the user to distinguish between failed open - * and bad superblock on root device. - */ - printk ("VFS: Cannot open root device \"%s\" or %s\n", - root_device_name, kdevname (to_kdev_t(ROOT_DEV))); - printk ("Please append a correct \"root=\" boot option\n"); - panic("VFS: Unable to mount root fs on %s", - kdevname(to_kdev_t(ROOT_DEV))); + bad_root_panic(); } panic("VFS: Unable to mount root fs on %s", kdevname(to_kdev_t(ROOT_DEV))); out: @@ -304,16 +290,63 @@ (current->fs->pwdmnt->mnt_sb->s_flags & MS_RDONLY) ? " readonly" : ""); } -#ifdef CONFIG_ROOT_NFS +static int __init mount_tmpfs_root(char *name) +{ +#ifndef CONFIG_BLK_DEV_INITRD_UNTAR + if (ROOT_DEV != Root_TMPFS) + return 0; + + printk(KERN_ERR "VFS: Kernel does not support root fs on tmpfs.\n"); + bad_root_panic(); + return 0; +#else + char data[16] = {0}; + + if (ROOT_DEV != Root_TMPFS) + return 0; + + if (tmpfs_root_fssize > 0) + snprintf(data, sizeof(data), "size=%luk", tmpfs_root_fssize); + + if (sys_mount(name,"/root","tmpfs",root_mountflags & ~MS_RDONLY,data) == 0) { + sys_chdir("/root"); + ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev; + printk("VFS: Mounted root (tmpfs filesystem). ["); + if (tmpfs_root_fssize) printk("%luKB",tmpfs_root_fssize); else printk("No"); + printk(" Ceiling]\n"); + return 1; + } + printk(KERN_ERR "VFS: Unable to mount root fs on tmpfs.\n"); + return 0; +#endif +} + static int __init mount_nfs_root(void) { +#ifndef CONFIG_ROOT_NFS + if (ROOT_DEV != Root_NFS) + return 0; + + printk(KERN_ERR "VFS: Kernel does not support root fs via NFS.\n"); + bad_root_panic(); + return 0; +#else void *data = nfs_root_data(); - if (data && sys_mount("/dev/root","/root","nfs",root_mountflags,data) == 0) + if (ROOT_DEV != Root_NFS) + return 0; + + if (data && sys_mount("/dev/root","/root","nfs",root_mountflags,data) == 0) { + sys_chdir("/root"); + ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev; + printk("VFS: Mounted root (nfs filesystem).\n"); return 1; + } + printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying initrd.\n"); + root_dev_setup("/dev/ram0"); return 0; -} #endif +} static int __init create_dev(char *name, dev_t dev, char *devfs_name) { @@ -336,398 +369,21 @@ return sys_symlink(path + n + 5, name); } -#if defined(CONFIG_BLK_DEV_RAM) || defined(CONFIG_BLK_DEV_FD) -static void __init change_floppy(char *fmt, ...) -{ - struct termios termios; - char buf[80]; - char c; - int fd; - va_list args; - va_start(args, fmt); - vsprintf(buf, fmt, args); - va_end(args); - fd = open("/dev/root", O_RDWR | O_NDELAY, 0); - if (fd >= 0) { - sys_ioctl(fd, FDEJECT, 0); - close(fd); - } - printk(KERN_NOTICE "VFS: Insert %s and press ENTER\n", buf); - fd = open("/dev/console", O_RDWR, 0); - if (fd >= 0) { - sys_ioctl(fd, TCGETS, (long)&termios); - termios.c_lflag &= ~ICANON; - sys_ioctl(fd, TCSETSF, (long)&termios); - read(fd, &c, 1); - termios.c_lflag |= ICANON; - sys_ioctl(fd, TCSETSF, (long)&termios); - close(fd); - } -} -#endif - -#ifdef CONFIG_BLK_DEV_RAM - -int __initdata rd_prompt = 1; /* 1 = prompt for RAM disk, 0 = don't prompt */ - -static int __init prompt_ramdisk(char *str) -{ - rd_prompt = simple_strtol(str,NULL,0) & 1; - return 1; -} -__setup("prompt_ramdisk=", prompt_ramdisk); - -int __initdata rd_image_start; /* starting block # of image */ - -static int __init ramdisk_start_setup(char *str) -{ - rd_image_start = simple_strtol(str,NULL,0); - return 1; -} -__setup("ramdisk_start=", ramdisk_start_setup); - -static int __init crd_load(int in_fd, int out_fd); - -/* - * This routine tries to find a RAM disk image to load, and returns the - * number of blocks to read for a non-compressed image, 0 if the image - * is a compressed image, and -1 if an image with the right magic - * numbers could not be found. - * - * We currently check for the following magic numbers: - * minix - * ext2 - * romfs - * gzip - */ -static int __init -identify_ramdisk_image(int fd, int start_block) -{ - const int size = 512; - struct minix_super_block *minixsb; - struct ext2_super_block *ext2sb; - struct romfs_super_block *romfsb; - int nblocks = -1; - unsigned char *buf; - - buf = kmalloc(size, GFP_KERNEL); - if (buf == 0) - return -1; - - minixsb = (struct minix_super_block *) buf; - ext2sb = (struct ext2_super_block *) buf; - romfsb = (struct romfs_super_block *) buf; - memset(buf, 0xe5, size); - - /* - * Read block 0 to test for gzipped kernel - */ - lseek(fd, start_block * BLOCK_SIZE, 0); - read(fd, buf, size); - - /* - * If it matches the gzip magic numbers, return -1 - */ - if (buf[0] == 037 && ((buf[1] == 0213) || (buf[1] == 0236))) { - printk(KERN_NOTICE - "RAMDISK: Compressed image found at block %d\n", - start_block); - nblocks = 0; - goto done; - } - - /* romfs is at block zero too */ - if (romfsb->word0 == ROMSB_WORD0 && - romfsb->word1 == ROMSB_WORD1) { - printk(KERN_NOTICE - "RAMDISK: romfs filesystem found at block %d\n", - start_block); - nblocks = (ntohl(romfsb->size)+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; - goto done; - } - - /* - * Read block 1 to test for minix and ext2 superblock - */ - lseek(fd, (start_block+1) * BLOCK_SIZE, 0); - read(fd, buf, size); - - /* Try minix */ - if (minixsb->s_magic == MINIX_SUPER_MAGIC || - minixsb->s_magic == MINIX_SUPER_MAGIC2) { - printk(KERN_NOTICE - "RAMDISK: Minix filesystem found at block %d\n", - start_block); - nblocks = minixsb->s_nzones << minixsb->s_log_zone_size; - goto done; - } - - /* Try ext2 */ - if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) { - printk(KERN_NOTICE - "RAMDISK: ext2 filesystem found at block %d\n", - start_block); - nblocks = le32_to_cpu(ext2sb->s_blocks_count); - goto done; - } - - printk(KERN_NOTICE - "RAMDISK: Couldn't find valid RAM disk image starting at %d.\n", - start_block); - -done: - lseek(fd, start_block * BLOCK_SIZE, 0); - kfree(buf); - return nblocks; -} -#endif - -static int __init rd_load_image(char *from) -{ - int res = 0; - -#ifdef CONFIG_BLK_DEV_RAM - int in_fd, out_fd; - int nblocks, rd_blocks, devblocks, i; - char *buf; - unsigned short rotate = 0; -#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES) - char rotator[4] = { '|' , '/' , '-' , '\\' }; -#endif - - out_fd = open("/dev/ram", O_RDWR, 0); - if (out_fd < 0) - goto out; - - in_fd = open(from, O_RDONLY, 0); - if (in_fd < 0) - goto noclose_input; - - nblocks = identify_ramdisk_image(in_fd, rd_image_start); - if (nblocks < 0) - goto done; - - if (nblocks == 0) { -#ifdef BUILD_CRAMDISK - if (crd_load(in_fd, out_fd) == 0) - goto successful_load; +#ifdef CONFIG_BLK_DEV_INITRD +static int __init initrd_mount(void); // in initrd.c #else - printk(KERN_NOTICE - "RAMDISK: Kernel does not support compressed " - "RAM disk images\n"); +static int __init initrd_mount(void) { return 0;} #endif - goto done; - } - - /* - * NOTE NOTE: nblocks suppose that the blocksize is BLOCK_SIZE, so - * rd_load_image will work only with filesystem BLOCK_SIZE wide! - * So make sure to use 1k blocksize while generating ext2fs - * ramdisk-images. - */ - if (sys_ioctl(out_fd, BLKGETSIZE, (unsigned long)&rd_blocks) < 0) - rd_blocks = 0; - else - rd_blocks >>= 1; - - if (nblocks > rd_blocks) { - printk("RAMDISK: image too big! (%d/%d blocks)\n", - nblocks, rd_blocks); - goto done; - } - - /* - * OK, time to copy in the data - */ - buf = kmalloc(BLOCK_SIZE, GFP_KERNEL); - if (buf == 0) { - printk(KERN_ERR "RAMDISK: could not allocate buffer\n"); - goto done; - } - - if (sys_ioctl(in_fd, BLKGETSIZE, (unsigned long)&devblocks) < 0) - devblocks = 0; - else - devblocks >>= 1; - - if (strcmp(from, "/dev/initrd") == 0) - devblocks = nblocks; - - if (devblocks == 0) { - printk(KERN_ERR "RAMDISK: could not determine device size\n"); - goto done; - } - - printk(KERN_NOTICE "RAMDISK: Loading %d blocks [%d disk%s] into ram disk... ", - nblocks, ((nblocks-1)/devblocks)+1, nblocks>devblocks ? "s" : ""); - for (i=0; i < nblocks; i++) { - if (i && (i % devblocks == 0)) { - printk("done disk #%d.\n", i/devblocks); - rotate = 0; - if (close(in_fd)) { - printk("Error closing the disk.\n"); - goto noclose_input; - } - change_floppy("disk #%d", i/devblocks+1); - in_fd = open(from, O_RDONLY, 0); - if (in_fd < 0) { - printk("Error opening disk.\n"); - goto noclose_input; - } - printk("Loading disk #%d... ", i/devblocks+1); - } - read(in_fd, buf, BLOCK_SIZE); - write(out_fd, buf, BLOCK_SIZE); -#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES) - if (!(i % 16)) { - printk("%c\b", rotator[rotate & 0x3]); - rotate++; - } -#endif - } - printk("done.\n"); - kfree(buf); - -successful_load: - res = 1; -done: - close(in_fd); -noclose_input: - close(out_fd); -out: - sys_unlink("/dev/ram"); -#endif - return res; -} - -static int __init rd_load_disk(int n) -{ -#ifdef CONFIG_BLK_DEV_RAM - if (rd_prompt) - change_floppy("root floppy disk to be loaded into RAM disk"); - create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, n), NULL); -#endif - return rd_load_image("/dev/root"); -} static void __init mount_root(void) { -#ifdef CONFIG_ROOT_NFS - if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) { - if (mount_nfs_root()) { - sys_chdir("/root"); - ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev; - printk("VFS: Mounted root (nfs filesystem).\n"); - return; - } - printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n"); - ROOT_DEV = Root_FD0; - } -#endif create_dev("/dev/root", ROOT_DEV, root_device_name); -#ifdef CONFIG_BLK_DEV_FD - if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { - /* rd_doload is 2 for a dual initrd/ramload setup */ - if (rd_doload==2) { - if (rd_load_disk(1)) { - ROOT_DEV = Root_RAM1; - create_dev("/dev/root", ROOT_DEV, NULL); - } - } else - change_floppy("root floppy"); - } -#endif - mount_block_root("/dev/root", root_mountflags); -} - -#ifdef CONFIG_BLK_DEV_INITRD -static int old_fd, root_fd; -static int do_linuxrc(void * shell) -{ - static char *argv[] = { "linuxrc", NULL, }; - extern char * envp_init[]; - - close(old_fd);close(root_fd); - close(0);close(1);close(2); - setsid(); - (void) open("/dev/console",O_RDWR,0); - (void) dup(0); - (void) dup(0); - return execve(shell, argv, envp_init); -} - -#endif - -static void __init handle_initrd(void) -{ -#ifdef CONFIG_BLK_DEV_INITRD - int error; - int i, pid; - - create_dev("/dev/root.old", Root_RAM0, NULL); - /* mount initrd on rootfs' /root */ - mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY); - sys_mkdir("/old", 0700); - root_fd = open("/", 0, 0); - old_fd = open("/old", 0, 0); - /* move initrd over / and chdir/chroot in initrd root */ - sys_chdir("/root"); - sys_mount(".", "/", NULL, MS_MOVE, NULL); - sys_chroot("."); - mount_devfs_fs (); - pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); - if (pid > 0) { - while (pid != waitpid(-1, &i, 0)) - yield(); - } - - /* move initrd to rootfs' /old */ - sys_fchdir(old_fd); - sys_mount("/", ".", NULL, MS_MOVE, NULL); - /* switch root and cwd back to / of rootfs */ - sys_fchdir(root_fd); - sys_chroot("."); - close(old_fd); - close(root_fd); - sys_umount("/old/dev", 0); - - if (real_root_dev == Root_RAM0) { - sys_chdir("/old"); - return; - } - - ROOT_DEV = real_root_dev; - mount_root(); - - printk(KERN_NOTICE "Trying to move old root to /initrd ... "); - error = sys_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL); - if (!error) - printk("okay\n"); - else { - int fd = open("/dev/root.old", O_RDWR, 0); - printk("failed\n"); - printk(KERN_NOTICE "Unmounting old root\n"); - sys_umount("/old", MNT_DETACH); - printk(KERN_NOTICE "Trying to free ramdisk memory ... "); - if (fd < 0) { - error = fd; - } else { - error = sys_ioctl(fd, BLKFLSBUF, 0); - close(fd); - } - printk(!error ? "okay\n" : "failed\n"); - } -#endif -} - -static int __init initrd_load(void) -{ -#ifdef CONFIG_BLK_DEV_INITRD - create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, 0), NULL); - create_dev("/dev/initrd", MKDEV(RAMDISK_MAJOR, INITRD_MINOR), NULL); -#endif - return rd_load_image("/dev/initrd"); + if (mount_nfs_root()) return; + + if (initrd_mount()) return; + + mount_block_root("/dev/root", root_mountflags); } /* @@ -735,7 +391,6 @@ */ void prepare_namespace(void) { - int is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR; if (saved_root_name[0]) { char *p = saved_root_name; ROOT_DEV = name_to_dev_t(p); @@ -743,11 +398,6 @@ p += 5; strcpy(root_device_name, p); } -#ifdef CONFIG_BLK_DEV_INITRD - if (!initrd_start) - mount_initrd = 0; - real_root_dev = ROOT_DEV; -#endif sys_mkdir("/dev", 0700); sys_mkdir("/root", 0700); sys_mknod("/dev/console", S_IFCHR|0600, MKDEV(TTYAUX_MAJOR, 1)); @@ -755,22 +405,14 @@ sys_mount("devfs", "/dev", "devfs", 0, NULL); do_devfs = 1; #endif - create_dev("/dev/root", ROOT_DEV, NULL); /* This has to be before mounting root, because even readonly mount of reiserfs would replay log corrupting stuff */ software_resume(); - if (mount_initrd) { - if (initrd_load() && ROOT_DEV != Root_RAM0) { - handle_initrd(); - goto out; - } - } else if (is_floppy && rd_doload && rd_load_disk(0)) - ROOT_DEV = Root_RAM0; mount_root(); -out: + sys_umount("/dev", 0); sys_mount(".", "/", NULL, MS_MOVE, NULL); sys_chroot("."); @@ -778,149 +420,6 @@ mount_devfs_fs (); } -#if defined(BUILD_CRAMDISK) && defined(CONFIG_BLK_DEV_RAM) - -/* - * gzip declarations - */ - -#define OF(args) args - -#ifndef memzero -#define memzero(s, n) memset ((s), 0, (n)) +#ifdef CONFIG_BLK_DEV_INITRD +#include "initrd.c" #endif - -typedef unsigned char uch; -typedef unsigned short ush; -typedef unsigned long ulg; - -#define INBUFSIZ 4096 -#define WSIZE 0x8000 /* window size--must be a power of two, and */ - /* at least 32K for zip's deflate method */ - -static uch *inbuf; -static uch *window; - -static unsigned insize; /* valid bytes in inbuf */ -static unsigned inptr; /* index of next byte to be processed in inbuf */ -static unsigned outcnt; /* bytes in output buffer */ -static int exit_code; -static long bytes_out; -static int crd_infd, crd_outfd; - -#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) - -/* Diagnostic functions (stubbed out) */ -#define Assert(cond,msg) -#define Trace(x) -#define Tracev(x) -#define Tracevv(x) -#define Tracec(c,x) -#define Tracecv(c,x) - -#define STATIC static - -static int fill_inbuf(void); -static void flush_window(void); -static void *malloc(int size); -static void free(void *where); -static void error(char *m); -static void gzip_mark(void **); -static void gzip_release(void **); - -#include "../lib/inflate.c" - -static void __init *malloc(int size) -{ - return kmalloc(size, GFP_KERNEL); -} - -static void __init free(void *where) -{ - kfree(where); -} - -static void __init gzip_mark(void **ptr) -{ -} - -static void __init gzip_release(void **ptr) -{ -} - - -/* =========================================================================== - * Fill the input buffer. This is called only when the buffer is empty - * and at least one byte is really needed. - */ -static int __init fill_inbuf(void) -{ - if (exit_code) return -1; - - insize = read(crd_infd, inbuf, INBUFSIZ); - if (insize == 0) return -1; - - inptr = 1; - - return inbuf[0]; -} - -/* =========================================================================== - * Write the output window window[0..outcnt-1] and update crc and bytes_out. - * (Used for the decompressed data only.) - */ -static void __init flush_window(void) -{ - ulg c = crc; /* temporary variable */ - unsigned n; - uch *in, ch; - - write(crd_outfd, window, outcnt); - in = window; - for (n = 0; n < outcnt; n++) { - ch = *in++; - c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); - } - crc = c; - bytes_out += (ulg)outcnt; - outcnt = 0; -} - -static void __init error(char *x) -{ - printk(KERN_ERR "%s", x); - exit_code = 1; -} - -static int __init crd_load(int in_fd, int out_fd) -{ - int result; - - insize = 0; /* valid bytes in inbuf */ - inptr = 0; /* index of next byte to be processed in inbuf */ - outcnt = 0; /* bytes in output buffer */ - exit_code = 0; - bytes_out = 0; - crc = (ulg)0xffffffffL; /* shift register contents */ - - crd_infd = in_fd; - crd_outfd = out_fd; - inbuf = kmalloc(INBUFSIZ, GFP_KERNEL); - if (inbuf == 0) { - printk(KERN_ERR "RAMDISK: Couldn't allocate gzip buffer\n"); - return -1; - } - window = kmalloc(WSIZE, GFP_KERNEL); - if (window == 0) { - printk(KERN_ERR "RAMDISK: Couldn't allocate gzip window\n"); - kfree(inbuf); - return -1; - } - makecrc(); - result = gunzip(); - kfree(inbuf); - kfree(window); - return result; -} - -#endif /* BUILD_CRAMDISK && CONFIG_BLK_DEV_RAM */ diff -uNr linux-2.5.45-virgin/init/initrd.c linux-2.5.45-initrd_dyn/init/initrd.c --- linux-2.5.45-virgin/init/initrd.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.5.45-initrd_dyn/init/initrd.c 2002-11-01 04:17:08.000000000 -0500 @@ -0,0 +1,890 @@ +/* + * Copyright 2002 Dave Cinege + * GPL2 - Copyright notice may not be altered. + * initrd rewrite and untar to tmpfs additions + * + */ + +/* +DOCS: +bootloader initrd=root.img +cmdline root=/dev/ram0 + +Load raw image to /dev/ram0. Mount /dev/ram0 as primary root. +Try to execute /linuxrc. If /linuxrc changes the root device +pivot to that device and remount /dev/ram0 to /initrd. +(DOING THIS HAS DEPRECIATED! Set root= to the final root, +that is unless you want /dev/ram0 as you final root device.) + +bootloader initrd=root.img +cmdline root=/dev/hda1 +Load raw image to /dev/ram0. Mount /dev/ram0 as primary root. +Try to execute /linuxrc. After excuting /linuxrc pivot to root= device +and remount initrd to /initrd. + +cmdline root=/dev/hda1 initrd_from_floppy=1 +Attempt to load raw image to /dev/ram0, from /dev/fd0. +Mount /dev/ram0 as primary root. Try to execute /linuxrc. +After excuting /linuxrc pivot to root= device and remount /dev/ram0 +to /initrd. If the bootloader has already loaded an initrd image +it is deallocated. + + +bootloader initrd=root.tgz,etc.tgz,myhostconifg.tgz +cmdline root=/dev/tmpfs initrd_tmpfs_fssize=10MB +Mount /dev/tmpfs as the primary root. If initrd_tmpfs_fssize= is +specificed, the root will have a ceiling of that size. +If initrd_tmpfs_fssize=0, their will be no ceiling limit. +If initrd_tmpfs_fssize= is not specified, the root will have a +ceiling equal to ramdisk_size. +Extract tar.gz archives sequencially.to the root. +Try to execute /linuxrc. If /linuxrc changes the root device +pivot to that device and remount /dev/tmpfs to /initrd. +(DOING THIS HAS DEPRECIATED! Set root= to the final root, +that is unless you want /dev/tmpfs as your final root device.) + +NOTE: Your bootloader must support loading multiple files +sequencially into the initrd memory space. If your boot loader +is outdated you can create a multi-archive file like this: + cat root.tgz etc.tgz myhostconifg.tgz > root_tgzs.img +And load this single file. + + +bootloader initrd=root.tar +cmdline root=/dev/hda1 +Mount /dev/tmpfs as the primary root. +Since initrd_tmpfs_fssize= is not specified, the root will have a +ceiling equal to ramdisk_size. +Extract tar archive to the root. +Try to execute /linuxrc. After excuting /linuxrc pivot to root= device +and remount initrd to /initrd. + +*/ +#include + + +#ifdef CONFIG_BLK_DEV_INITRD_GUNZIP +static int __init gunzip_load(int in_fd, int out_fd, int size); +#endif +#ifdef CONFIG_BLK_DEV_INITRD_UNTAR +static int __init initrd_untar(int in_fd); +#endif + +extern asmlinkage long sys_access(const char * filename, int mode); + +unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */ + +static int __initdata mount_initrd = 1; +static int __initdata initrd_from_floppy = 0; +static unsigned long __initdata initrd_fssize = 0; +#ifdef CONFIG_BLK_DEV_INITRD_UNTAR +static int __initdata initrd_tmpfs_fssize_speced = 0; +#endif + + +enum image_type { + UNKNOWN = 0, + GZIPPED = 2<<0, + TAR = 2<<1, + IMAGE = 2<<2, + ROMFS = 2<<3, + EXT2 = 2<<4, + MINIX = 2<<5 +}; + +static int __init no_initrd(char *str) +{ + mount_initrd = 0; + return 1; +} +__setup("noinitrd", no_initrd); + + +#ifdef CONFIG_BLK_DEV_FD +static int __init prompt_ramdisk(char *str) +{ + rd_prompt = simple_strtol(str,NULL,0) & 1; + return 1; +} +__setup("prompt_ramdisk=", prompt_ramdisk); + +static int __init load_floppy(char *str) +{ + initrd_from_floppy = 1; + return 1; +} +__setup("initrd_from_floppy",load_floppy); + +static int __init ramdisk_start_setup(char *str) +{ + rd_image_start = simple_strtol(str,NULL,0); + return 1; +} +__setup("ramdisk_start=", ramdisk_start_setup); + +static void __init change_floppy(char *fmt, ...) +{ + struct termios termios; + char buf[80]; + char c; + int fd; + va_list args; + va_start(args, fmt); + vsprintf(buf, fmt, args); + va_end(args); + fd = open("/dev/fd0", O_RDWR | O_NDELAY, 0); + if (fd >= 0) { + sys_ioctl(fd, FDEJECT, 0); + close(fd); + } + printk(KERN_NOTICE "VFS: Insert %s and press ENTER\n", buf); + fd = open("/dev/console", O_RDWR, 0); + if (fd >= 0) { + sys_ioctl(fd, TCGETS, (long)&termios); + termios.c_lflag &= ~ICANON; + sys_ioctl(fd, TCSETSF, (long)&termios); + read(fd, &c, 1); + termios.c_lflag |= ICANON; + sys_ioctl(fd, TCSETSF, (long)&termios); + close(fd); + } +} +#endif + +// dc: FIX ME updates these comments +/* + * This routine tries to find a RAM disk image to load, and returns the + * number of blocks to read for a non-compressed image, 0 if the image + * is a compressed image, and -1 if an image with the right magic + * numbers could not be found. + * + * We currently check for the following magic numbers: + * tar + * minix + * ext2 + * romfs + * gzip + */ +static int __init initrd_identify(int in_fd, int start_block, int *nblocks) +{ + const int size = 512; + struct minix_super_block *minixsb; + struct ext2_super_block *ext2sb; + struct romfs_super_block *romfsb; + + unsigned char *buf; + int fd, buf_fd = -1; + int initrd_type = 0; + + *nblocks = -1; + + buf = kmalloc(size, GFP_KERNEL); + if (buf == 0) + return -1; + memset(buf, 0xe5, size); + + /* + * Read block 0 to test for gzipped kernel + */ + fd = in_fd; + lseek(fd, start_block * BLOCK_SIZE, 0); + read(fd, buf, size); + + /* + * If it matches the gzip magic, gunzip some bytes to compare + */ + if (buf[0] == 037 && ((buf[1] == 0213) || (buf[1] == 0236))) { + *nblocks = 0; + initrd_type = GZIPPED; +#ifndef CONFIG_BLK_DEV_INITRD_GUNZIP + goto done; +#else + memset(buf, 0xe5, size); + lseek(in_fd, start_block * BLOCK_SIZE, 0); + + create_dev("/dev/ram1", MKDEV(RAMDISK_MAJOR, 1), NULL); + buf_fd = open("/dev/ram1", O_RDWR, 0); + if (buf_fd < 0) + goto done; + gunzip_load(in_fd, buf_fd, ((start_block+1) * BLOCK_SIZE) + size); + lseek(buf_fd, 0, 0); + read(buf_fd, buf, size); + fd = buf_fd; +#endif + } + + /* tar archive */ + if (strncmp(&buf[257],"ustar",5) == 0) { + *nblocks = 0; + initrd_type |= TAR; + goto done; + } + + romfsb = (struct romfs_super_block *) buf; + minixsb = (struct minix_super_block *) buf; + ext2sb = (struct ext2_super_block *) buf; + + /* romfs is at block zero too */ + if (romfsb->word0 == ROMSB_WORD0 && + romfsb->word1 == ROMSB_WORD1) { + *nblocks = (ntohl(romfsb->size)+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; + initrd_type |= IMAGE | ROMFS; + goto done; + } + + /* + * Read block 1 to test for minix and ext2 superblock + */ + lseek(fd, (start_block+1) * BLOCK_SIZE, 0); + read(fd, buf, size); + + /* Try minix */ + if (minixsb->s_magic == MINIX_SUPER_MAGIC || + minixsb->s_magic == MINIX_SUPER_MAGIC2) { + *nblocks = minixsb->s_nzones << minixsb->s_log_zone_size; + initrd_type |= IMAGE | MINIX; + goto done; + } + + /* Try ext2 */ + if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) { + *nblocks = le32_to_cpu(ext2sb->s_blocks_count); + initrd_type |= IMAGE | EXT2; + goto done; + } + + /* It's.....Unknown! */ + initrd_type = UNKNOWN; + +done: + lseek(fd, start_block * BLOCK_SIZE, 0); + kfree(buf); + +#ifdef CONFIG_BLK_DEV_INITRD_GUNZIP + if (buf_fd > -1) { + close(buf_fd); + sys_unlink("/dev/ram1"); + } +#endif + + return initrd_type; +} + + +static int __init rd_load_image(int fd, int nblocks) +{ + int res = 0; + + int in_fd, out_fd; + int rd_blocks, devblocks, i; + char *buf; + unsigned short rotate = 0; +#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES) + char rotator[4] = { '|' , '/' , '-' , '\\' }; +#endif + in_fd = fd; + + out_fd = open("/dev/ram0", O_RDWR, 0); + if (out_fd < 0) + goto out; + + if (nblocks < 0) + goto done; + + if (nblocks == 0) { +#ifdef CONFIG_BLK_DEV_INITRD_GUNZIP + if (gunzip_load(in_fd, out_fd, 0) == 0) + goto successful_load; +#endif + goto done; + } + + /* + * NOTE NOTE: nblocks suppose that the blocksize is BLOCK_SIZE, so + * rd_load_image will work only with filesystem BLOCK_SIZE wide! + * So make sure to use 1k blocksize while generating ext2fs + * ramdisk-images. + */ + if (sys_ioctl(out_fd, BLKGETSIZE, (unsigned long)&rd_blocks) < 0) + rd_blocks = 0; + else + rd_blocks >>= 1; + + if (nblocks > rd_blocks) { + printk("INITRD: image too big! (%d/%d blocks)\n", + nblocks, rd_blocks); + goto done; + } + + /* + * OK, time to copy in the data + */ + buf = kmalloc(BLOCK_SIZE, GFP_KERNEL); + if (buf == 0) { + printk(KERN_ERR "INITRD: could not allocate buffer\n"); + goto done; + } + + if (sys_ioctl(in_fd, BLKGETSIZE, (unsigned long)&devblocks) < 0) + devblocks = 0; + else + devblocks >>= 1; + + // dc: FIX ME + if (initrd_start) //if (strcmp(from, "/dev/initrd") == 0) + devblocks = nblocks; + + if (devblocks == 0) { + printk(KERN_ERR "INITRD: could not determine device size\n"); + goto done; + } + + printk(KERN_NOTICE "INITRD: Loading %d blocks [%d disk%s] into ram disk... ", + nblocks, ((nblocks-1)/devblocks)+1, nblocks>devblocks ? "s" : ""); + for (i=0; i < nblocks; i++) { + if (i && (i % devblocks == 0)) { + printk("done disk #%d.\n", i/devblocks); + rotate = 0; + if (close(in_fd)) { + printk("Error closing the disk.\n"); + goto noclose_input; + } + change_floppy("disk #%d", i/devblocks+1); + in_fd = open("/dev/fd0", O_RDONLY, 0); + if (in_fd < 0) { + printk("Error opening disk.\n"); + goto noclose_input; + } + printk("Loading disk #%d... ", i/devblocks+1); + } + read(in_fd, buf, BLOCK_SIZE); + write(out_fd, buf, BLOCK_SIZE); +#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES) + if (!(i % 16)) { + printk("%c\b", rotator[rotate & 0x3]); + rotate++; + } +#endif + } + printk("done.\n"); + kfree(buf); + +successful_load: + res = 1; +done: + close(in_fd); +noclose_input: + close(out_fd); +out: + return res; +} + + +static void __init initrd_free_memory(char *dev) +{ + int fd = open(dev, O_RDWR, 0); + if (fd >= 0) { + sys_ioctl(fd, BLKFLSBUF, 0); + close(fd); + } +} + +#ifdef CONFIG_BLK_DEV_INITRD_UNTAR +static int __init initrd_tmpfs_setup(char *str) +{ + initrd_fssize = simple_strtoul(str,NULL,10); + initrd_tmpfs_fssize_speced = 1; + tmpfs_root_fssize = initrd_fssize; + return 1; +} +__setup("initrd_tmpfs_size=", initrd_tmpfs_setup); +#endif + +static int initrd_fd, root_fd; +static int do_linuxrc(void * shell) +{ + static char *argv[] = { "linuxrc", NULL, }; + extern char * envp_init[]; + + close(initrd_fd);close(root_fd); + close(0);close(1);close(2); + setsid(); + (void) open("/dev/console",O_RDWR,0); + (void) dup(0); + (void) dup(0); + return execve(shell, argv, envp_init); +} + +/* Depreciated. Purge at will.*/ +static void __init initrd_pivot(void) +{ + int error; + int i, pid; + + /* If there's no executable /linuxrc to change the ROOT_DEV, it can't pivot. */ + if (ROOT_DEV == real_root_dev && !sys_access("./linuxrc",1)) + return; + + create_dev("/dev/root_initrd", ROOT_DEV, NULL); + + /* make location to pivot to. */ + sys_mkdir("/initrd", 0700); + root_fd = open("/", 0, 0); + initrd_fd = open("/initrd", 0, 0); + + /* move initrd over / and chdir/chroot in initrd root */ + sys_chdir("/root"); + sys_mount(".", "/", NULL, MS_MOVE, NULL); + sys_chroot("."); + mount_devfs_fs (); + + printk(KERN_NOTICE "INITRD: Executing /linuxrc.\n"); + pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); + if (pid > 0) { + while (pid != waitpid(-1, &i, 0)) + yield(); + } + printk(KERN_NOTICE "INITRD: Exiting /linuxrc.\n"); + + /* linuxrc changed the root. move initrd to rootfs' /initrd */ + if (ROOT_DEV != real_root_dev) { + sys_fchdir(initrd_fd); + sys_mount("/", ".", NULL, MS_MOVE, NULL); + } + + /* switch root and cwd back to / of rootfs */ + sys_fchdir(root_fd); + sys_chroot("."); + close(initrd_fd); + close(root_fd); + + /* linuxrc did not change the root. Move it back. Can't pivot */ + if (ROOT_DEV == real_root_dev) { + sys_umount("/root/dev", 0); + create_dev("/dev/root", ROOT_DEV, NULL); + sys_chdir("/root"); + return; + } + + sys_umount("/initrd/dev", 0); + + ROOT_DEV = real_root_dev; + create_dev("/dev/root", ROOT_DEV, NULL); + // dc: FIX ME do this or make it safe to reenter mount_root()? + // linuxrc pivoting *IS* depreciated after all... + mount_block_root("/dev/root", root_mountflags); + + printk(KERN_NOTICE "INITRD: Moving initrd root to /initrd..."); + error = sys_mount("/initrd", "/root/initrd", NULL, MS_MOVE, NULL); + if (!error) { + printk("done.\n"); + } else { + printk("failed!\n"); + sys_umount("/initrd", MNT_DETACH); + initrd_free_memory("/dev/initrd"); + } +} + +static int __init initrd_open(void) +{ + create_dev("/dev/ram0", MKDEV(RAMDISK_MAJOR, 0), NULL); + create_dev("/dev/initrd", MKDEV(RAMDISK_MAJOR, INITRD_MINOR), NULL); + +#ifdef CONFIG_BLK_DEV_FD + /* Try loading initrd from floppy. Wipe initrd image if present in memory. */ + if (initrd_from_floppy) { + initrd_free_memory("/dev/initrd"); + create_dev("/dev/fd0", MKDEV(FLOPPY_MAJOR, 0), NULL); + if (rd_prompt) + change_floppy("root floppy disk to be loaded into RAM disk"); + return open("/dev/fd0", O_RDONLY, 0); + } +#endif + return open("/dev/initrd", O_RDONLY, 0); +} + + +static void __init initrd_print_type(int initrd_type, int nblocks) +{ + printk(KERN_NOTICE "INITRD: "); + if (initrd_type & GZIPPED) printk("Compressed "); + + if (initrd_type & TAR) printk("Tar archive found at block %d.\n",rd_image_start); + + if (initrd_type & ROMFS) printk("RomFS"); + if (initrd_type & EXT2) printk("EXT2"); + if (initrd_type & MINIX) printk("Minix"); + + if (initrd_type & IMAGE) printk(" filesystem found at block %d. %d blocks.\n",rd_image_start, nblocks); +} + +static int __init initrd_mount(void) +{ + extern int rd_size; + int initrd_type, nblocks; + int in_fd; + + /* There is no image in memory AND we shouldn't try to load one from floppy. */ + if (initrd_start == 0 && initrd_from_floppy == 0) + return 0; + + /* Don't mount_initrd (noinitrd option)*/ + if (mount_initrd == 0) + return 0; + + real_root_dev = ROOT_DEV; + + /* Open initrd */ + in_fd = initrd_open(); + if (in_fd < 0) { + printk(KERN_NOTICE "INITRD: Could not open initrd. (This is an error if you loaded one...)\n"); + return 0; + } + + initrd_type = initrd_identify(in_fd, rd_image_start, &nblocks); + + if (initrd_type & UNKNOWN) { + printk(KERN_ERR "INITRD: Could not find a valid image or archive starting at %d!\n",rd_image_start); + return 0; + } +#ifndef CONFIG_BLK_DEV_INITRD_GUNZIP + if (initrd_type & GZIPPED) { + printk(KERN_ERR "INITRD: Kernel does not support compressed images!\n"); + return 0; + } +#endif +#ifndef CONFIG_BLK_DEV_INITRD_UNTAR + if (initrd_type & TAR) { + printk(KERN_ERR "INITRD: Kernel does not support Tar archives!\n"); + return 0; + } +#endif + if ((initrd_type & IMAGE) && (nblocks > rd_size)) { + printk(KERN_ERR "INITRD: Image will not fit on ramdisk! (%d vs. %d)\n",nblocks,rd_size); + return 0; + } + + initrd_print_type(initrd_type, nblocks); + + /* Mount initrd on rootfs' /root, chdir there, and extract archive if it's tmpfs */ + if (initrd_type & TAR) { +#ifndef CONFIG_BLK_DEV_INITRD_UNTAR + mount_tmpfs_root("/dev/root"); + } +#else + if (initrd_tmpfs_fssize_speced == 0) + initrd_fssize = rd_size; + ROOT_DEV = Root_TMPFS; + create_dev("/dev/root", ROOT_DEV, NULL); + mount_tmpfs_root("/dev/root"); + initrd_untar(in_fd); // dc: FIX ME chroot first. Get rid of mount_tmpfs_root(). + close(in_fd); + } +#endif + if (initrd_type & IMAGE) { + initrd_fssize = rd_size; + if(rd_load_image(in_fd, nblocks) == 0) + return 0; + ROOT_DEV = Root_RAM0; + create_dev("/dev/root", ROOT_DEV, NULL); + mount_block_root("/dev/root", root_mountflags & ~MS_RDONLY); + } + + /* Make failsafe /dev and /dev/console on initrd.*/ + sys_mkdir("./dev", 0700); + sys_mknod("./dev/console", S_IFCHR|0600, MKDEV(TTYAUX_MAJOR, 1)); + + /* Depreciated. Purge at will.*/ + initrd_pivot(); + + return -1; +} + + +#if defined(CONFIG_BLK_DEV_INITRD_GUNZIP) || defined(CONFIG_BLK_DEV_INITRD_UNTAR) + +/* + * gzip and untar declarations + */ +#define OF(args) args + +#ifndef memzero +#define memzero(s, n) memset ((s), 0, (n)) +#endif + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +#define INBUFSIZ 4096 +#define WSIZE 0x8000 /* window size--must be a power of two, and */ + /* at least 32K for zip's deflate method */ + +static uch *inbuf; +static unsigned insizeT; /* valid bytes in inbuf */ +static unsigned insize; /* valid bytes in inbuf */ +static unsigned inptr; /* index of next byte to be processed in inbuf */ +static int exit_code; +static long bytes_out; +static long bytes_limit; /* if > 0, write no more then X bytes to out_fd*/ +static int crd_infd; + + +/* =========================================================================== + * Fill the input buffer. This is called only when the buffer is empty + * and at least one byte is really needed. + */ +static int __init fill_inbuf(void) +{ + if ((bytes_out >= bytes_limit) && (bytes_limit > 0)) + exit_code = 1; + + insize = read(crd_infd, inbuf, INBUFSIZ); + if (insize == 0) return -1; + + insizeT += insize; + + inptr = 1; + + return inbuf[0]; +} +#endif //CONFIG_BLK_DEV_INITRD_GUNZIP || CONFIG_BLK_DEV_INITRD_UNTAR + + +#ifdef CONFIG_BLK_DEV_INITRD_GUNZIP + +static uch *window; +static unsigned outcnt; /* bytes in output buffer */ +static int crd_outfd; + +#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) +#define EXIT_CODE exit_code + +/* Diagnostic functions (stubbed out) */ +#define Assert(cond,msg) +#define Trace(x) +#define Tracev(x) +#define Tracevv(x) +#define Tracec(c,x) +#define Tracecv(c,x) + +#define STATIC static + +//static int fill_inbuf(void); +static void flush_window(void); +static void *malloc(int size); +static void free(void *where); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +#include "../lib/inflate.c" + +static void __init *malloc(int size) +{ + return kmalloc(size, GFP_KERNEL); +} + +static void __init free(void *where) +{ + kfree(where); +} + +static void __init gzip_mark(void **ptr) +{ +} + +static void __init gzip_release(void **ptr) +{ +} + + +/* =========================================================================== + * Write the output window window[0..outcnt-1] and update crc and bytes_out. + * (Used for the decompressed data only.) + */ +static void __init flush_window(void) +{ + ulg c = crc; /* temporary variable */ + unsigned n; + uch *in, ch; + + if ((((bytes_out + (ulg)outcnt) > bytes_limit) && (bytes_limit > 0))) + outcnt = bytes_limit - bytes_out; // dc: FIX ME? We get lazy here and ignore the crc + + // dc: FIX ME? Check for return -1, IE out of space + write(crd_outfd, window, outcnt); + + in = window; + for (n = 0; n < outcnt; n++) { + ch = *in++; + c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + outcnt = 0; +} + +static void __init error(char *x) +{ + printk(KERN_ERR "%s", x); + exit_code = 1; +} + +static int __init gunzip_load(int in_fd, int out_fd, int size) +{ + int result; + + insize = 0; /* valid bytes in inbuf */ + inptr = 0; /* index of next byte to be processed in inbuf */ + outcnt = 0; /* bytes in output buffer */ + exit_code = 0; + bytes_out = 0; + bytes_limit = size; /* limit of bytes to write out. 0 == unlimited */ + + crd_infd = in_fd; + crd_outfd = out_fd; + inbuf = kmalloc(INBUFSIZ, GFP_KERNEL); + if (inbuf == 0) { + printk(KERN_ERR "INITRD: Couldn't allocate gzip buffer\n"); + return -1; + } + window = kmalloc(WSIZE, GFP_KERNEL); + if (window == 0) { + printk(KERN_ERR "INITRD: Couldn't allocate gzip window\n"); + kfree(inbuf); + return -1; + } + makecrc(); + result = gunzip(); + lseek(in_fd, -1 * (insize - inptr), 1); // Place in_fd.fpos where gunzip ended, not window. + + kfree(inbuf); + kfree(window); + return result; +} +#endif //CONFIG_BLK_DEV_INITRD_GUNZIP + + +#ifdef CONFIG_BLK_DEV_INITRD_UNTAR + +#include "../lib/untar.c" + +static struct untar_context *untarPtr; + +static int __init untar_load(int in_fd, int size) +{ + int result = 0; + + insize = 0; /* valid bytes in inbuf */ + exit_code = 0; + bytes_out = 0; + bytes_limit = size; /* limit of bytes to write out. 0 == unlimited */ + + crd_infd = in_fd; + inbuf = kmalloc(INBUFSIZ, GFP_KERNEL); + if (inbuf == 0) { + printk(KERN_ERR "INITRD: Couldn't allocate untar buffer\n"); + return -1; + } + while (fill_inbuf() >= 0) { + int count; + count = untar_write(untarPtr, inbuf, insize); + bytes_out += insize; + if (count > 0) { // End of archive + count -= TARBLOCKSIZE; + lseek(in_fd, -1 * count, 1); + bytes_out -= count; + break; + } else if (count < 0) { + printk(KERN_ERR "INITRD: corrupt tar archive!\n"); + result = -1; + } + } + kfree(inbuf); + return result; +} + +#ifdef CONFIG_BLK_DEV_INITRD_GUNZIP +// 'wrapper' so we can access untar_write() like a file descriptor +static ssize_t __init untar_write_fd(struct file *fp, const char *buf, size_t count, loff_t *fpos) +{ + return untar_write(untarPtr, (char*)buf, count); +} +#endif + +static int __init initrd_untar(int in_fd) +{ + int err, i; + int type; // 0 unknown, 1 gzip(tar), 2 tar + const int size = 512; + unsigned char *buf; +#ifdef CONFIG_BLK_DEV_INITRD_GUNZIP + int untar_fd; + struct file *untar_filp; +#endif + untarPtr = kmalloc(sizeof(struct untar_context), GFP_KERNEL); + if (untarPtr == 0) { + printk(KERN_ERR "INITRD: Couldn't allocate untar buffer\n"); + return -1; + } + + untar_init(untarPtr); + + buf = kmalloc(size, GFP_KERNEL); + if (buf == 0) + return -1; + + lseek(in_fd, rd_image_start * BLOCK_SIZE, 0); // Sanity + +#ifdef CONFIG_BLK_DEV_INITRD_GUNZIP + // Open a 'dummy' fd and filp. Replace f_op.write with untar_write_fd() + // It's a bit tidier then deficating in flush_window() with a global var + untar_fd = open("/dev/null", O_RDWR, 0); // Opening against '/dev/null' should be safe, no? + untar_filp = fget(untar_fd); + untar_filp->f_op->write = untar_write_fd; + fput(untar_filp); +#endif + // Now uncompress and/or untar the initrd.tgz/tar archives(s) + // Continue for as long as we find magic, for multiple archives. + for(i = 0;;i++) { + memset(buf, 0xe5, size); + read(in_fd, buf, size); + lseek(in_fd, -1 * size, 1); + + // dc: FIX ME? Call initrd_identify() here in the loop? Overkill? + + type = 0; + if (buf[0] == 037 && ((buf[1] == 0213) || (buf[1] == 0236))) + type = 1; // gzip + if (strncmp(&buf[257],"ustar",5) == 0) + type = 2; // tar + if (type == 0) + break; // unknown/EOF + + if (type == 1) { +#ifdef CONFIG_BLK_DEV_INITRD_GUNZIP + printk(KERN_NOTICE "INITRD: Extracting TGZ archive[%d]: ",i); + err = gunzip_load(in_fd,untar_fd,0); + if(err == 0) + printk("done. [%lu bytes]\n", bytes_out); +#else + printk(KERN_ERR "INITRD: Kernel does not support compressed Tar archives.\n"); + return 0; +#endif + } else { + printk(KERN_NOTICE "INITRD: Extracting Tar archive[%d]: ",i); + err = untar_load(in_fd,0); + if(err == 0) + printk("done. [%lu bytes]\n", bytes_out); + + } + } +#ifdef CONFIG_BLK_DEV_INITRD_GUNZIP + close(untar_fd); +#endif + kfree(untarPtr); + kfree(buf); + return 0; +} +#endif //CONFIG_BLK_DEV_INITRD_UNTAR diff -uNr linux-2.5.45-virgin/lib/inflate.c linux-2.5.45-initrd_dyn/lib/inflate.c --- linux-2.5.45-virgin/lib/inflate.c 2002-10-19 00:01:53.000000000 -0400 +++ linux-2.5.45-initrd_dyn/lib/inflate.c 2002-11-01 02:48:50.000000000 -0500 @@ -161,6 +161,10 @@ #define wp outcnt #define flush_output(w) (wp=(w),flush_window()) +#ifndef EXIT_CODE +#define EXIT_CODE 0 +#endif + /* Tables for deflate from PKZIP's appnote.txt. */ static const unsigned border[] = { /* Order of the bit length code lengths */ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; @@ -980,7 +984,7 @@ gzip_release(&ptr); if (hufts > h) h = hufts; - } while (!e); + } while (!e && !EXIT_CODE); /* Undo too much lookahead. The next read will be byte aligned so we * can discard unused bits in the last meaningful byte. @@ -1146,7 +1150,10 @@ } return -1; } - + + if (EXIT_CODE) + return 0; + /* Get the crc and original length */ /* crc32 (see algorithm.doc) * uncompressed input size modulo 2^32 diff -uNr linux-2.5.45-virgin/lib/untar.c linux-2.5.45-initrd_dyn/lib/untar.c --- linux-2.5.45-virgin/lib/untar.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.5.45-initrd_dyn/lib/untar.c 2002-11-01 04:21:34.000000000 -0500 @@ -0,0 +1,306 @@ +/* + * untar.c + * + * Copyright 1998-2002 Dave Cinege + * GPL2 - Copyright notice may not be altered. + * + * This is the untar portition of the original Initird Dynamic feature + * Some original portions by Dimitri Maziuk (very first untar.c) + * and Robert Kaiser (gunzip buffer) + * + * 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-10 + * First version of Initrd Archive. Extract tar.gz's to a dynamically + * created minix FS on /dev/ram0. + * + * 2000-05-27 + * Major code reorganization and rename to Initrd Dynamic. + * Unified for 2.0/2.2/2.4 kernels versions up to 2.4.18 + * + * 2001-01-27 + * Support extracting mutiple tgz's. + * + * 2001-08-18 + * Added support for using tmpfs on 2.4 kernels. + * + * 2002-10-27 + * Final kernel merge for adoption into 2.4.20/2.5.45. + * Initrd routines rewritten. Support for both un/compressed tar archives. + * Seemless operation with archive magic testing. Purged minix support. + * Many untar enhancments. + * + */ + +#include +#include +#include +#include +#include + +//#define DEBUG_UNTAR + +// These must be already present: + +//extern sys_mknod(); +//extern sys_mkdir(); +//extern sys_chdir(); +//extern sys_symlink(); +//extern sys_access(); + +extern asmlinkage long sys_write(unsigned int fd, const char * buf,unsigned int count); +extern asmlinkage long sys_chmod(const char * filename, mode_t mode); +extern asmlinkage long sys_chown(const char * filename, uid_t user, gid_t group); +extern asmlinkage long sys_lchown(const char * filename, uid_t user, gid_t group); +extern asmlinkage long sys_link(const char * oldname, const char * newname); +extern asmlinkage long sys_utime(char * filename, struct utimbuf * times); +extern asmlinkage long sys_time(int * tloc); + +#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" // 6 chars and a null +#define TMAGLEN 6 +#define TVERSION " \0" // 00 and no null +#define TVERSLEN 2 + + /* POSIX Tar header */ +struct TarFileHeader { // 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 +}; + +enum untar_type { + AREGTYPE = 0, // regular file + REGTYPE = '0', // regular file + LNKTYPE = '1', // link + SYMTYPE = '2', // reserved + CHRTYPE = '3', // character special + BLKTYPE = '4', // block special + DIRTYPE = '5', // directory + FIFOTYPE = '6', // FIFO special + CONTTYPE = '7' // reserved +}; + +enum untar_status { + READING_HEADER, + READING_DATA, + SKIPPING_REST +}; + +typedef union TarInfo { + char buf[TARBLOCKSIZE]; + struct TarFileHeader header; +} TarInfo; + +struct untar_context { + enum untar_status state; + unsigned long fsize_remaining; + int out_fd; + int rotate; + TarInfo tarInfo; +} *Untar; + + +/* + * simple_strtoul() does not strip leading spaces (0x20) from the input + * string. The 'real' strtoul does. This wrapper works around this. + * NOTE: This really should be fixed in: lib/vsprintf.c + * + */ +#define strtoul simple_strtoul_wrapper +static unsigned long __init simple_strtoul_wrapper( const char *cp, char **endp, unsigned int base) +{ + while (*cp == ' ') + cp++; + return ( simple_strtoul(cp,endp,base) ); +} + +/* + * Initialize/Reset the context structure. + * The external parent is responcible for definition and kmalloc of *Untar + * + */ +static void __init untar_init(struct untar_context *Untar) +{ + memset(Untar,0,sizeof(struct untar_context)); + Untar->state = READING_HEADER; + Untar->rotate = 0; +} + +#define Type Untar->tarInfo.header.typeflag +#define Name Untar->tarInfo.header.name +#define LName Untar->tarInfo.header.linkname +#define Mode strtoul(Untar->tarInfo.header.mode,NULL,8) +#define Uid strtoul(Untar->tarInfo.header.uid,NULL,8) +#define Gid strtoul(Untar->tarInfo.header.gid,NULL,8) +#define Size strtoul(Untar->tarInfo.header.size,NULL,8) +#define Dev MKDEV(strtoul(Untar->tarInfo.header.devmajor,NULL,8),strtoul(Untar->tarInfo.header.devminor,NULL,8)) +#define Magic Untar->tarInfo.header.magic + +static int __init untar_setmodes(struct untar_context *Untar) +{ + int err; + struct utimbuf ut; + + if(Type == LNKTYPE || Type == SYMTYPE) + return sys_lchown(Name, Uid, Gid); + + err = sys_chown(Name, Uid, Gid); + err |= sys_chmod(Name, Mode); + + ut.actime=sys_time(NULL); + ut.modtime=strtoul(Untar->tarInfo.header.mtime,NULL,8); + err |= sys_utime(Untar->tarInfo.header.name,&ut); + + return err; +} + +static int __init untar_create(struct untar_context *Untar) +{ + int err = 0; + switch(Type) { + case AREGTYPE : case REGTYPE : + Untar->out_fd = sys_open(Name,O_CREAT|O_WRONLY|O_TRUNC,Mode); + if(Untar->out_fd == -1) { + err = 1; + break; + } + Untar->state = READING_DATA; + Untar->fsize_remaining = Size; + break; + case LNKTYPE : + err = sys_link(LName, Name); + break; + case SYMTYPE : + err = sys_symlink(LName, Name); + break; + case CHRTYPE : case BLKTYPE : case FIFOTYPE : + err = sys_mknod(Name,Mode,Dev); + break; + case DIRTYPE : + if((Name[0] != '.' && Name[0] != 0) && // Skip if dirname is "" "./" "." ".." + (Name[1] != '/' && Name[1] != 0) && // Yes, Gnu tar can do stupid shit like this. + (Name[1] != 0)) { + err = sys_mkdir(Name,Mode); + } + break; + default: // corrupt tar archive + Untar->state = SKIPPING_REST; + return -1; + } + if (err == 0) + return untar_setmodes(Untar); + + return err; +} + +/* + * untar_write() can be re-entered as needed by the external parent function. + * We keep status of the current state and Tar header in our context + * structure, and return when we need more data to continue with extraction + * The parent is responcible for preparing root, chdir(), and chroot(). + * + */ +static ssize_t __init untar_write(struct untar_context *Untar, char *buf, size_t count) +{ + int i, scoop, err; + char *to; +#ifndef DEBUG_UNTAR +#ifndef CONFIG_ARCH_S390 + char rotator[4] = { '|' , '/' , '-' , '\\' }; + + printk("%c\b", rotator[Untar->rotate & 0x3]); + Untar->rotate++; +#endif +#endif + while (count) { + err = 0; + switch (Untar->state) { + case READING_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, + // appending zeroes if necessary. Here we skip those zeroes: + if (Name[0] == 0 && Magic[0] == 0) { + if(count < TARBLOCKSIZE) + count = 0; + break; + } + // Check magic to see if it's a valid header. + // If not assume overrun of EOF, and return 'count' that was valid. + // Parent can reset buf position with this offset. + if (strncmp(Magic,TMAGIC,sizeof(TMAGIC) != 0)) { + return count; + } + + err = untar_create(Untar); + + break; + case READING_DATA: + scoop = 0; + while (count > 0 && Untar->fsize_remaining > 0) { + scoop = Untar->fsize_remaining > TARBLOCKSIZE ? TARBLOCKSIZE : Untar->fsize_remaining; + if(sys_write(Untar->out_fd, buf, scoop) < scoop) + err = 1; + count -= scoop; + buf += scoop; + Untar->fsize_remaining -= scoop; + } + if (Untar->fsize_remaining == 0) { //skip to the next tar block + sys_close(Untar->out_fd); + scoop = count % TARBLOCKSIZE; + buf += scoop; + count -= scoop; + Untar->state = READING_HEADER; + } + break; + + case SKIPPING_REST: + count = 0; + break; + } + if (err) { +#ifndef DEBUG_UNTAR + printk("!"); +#else + printk("\nerr=%d, Error making %s", err, Name); +#endif + } + + + } + return 0; +}