1#include <linux/unistd.h> 2#include <linux/kernel.h> 3#include <linux/fs.h> 4#include <linux/minix_fs.h> 5#include <linux/ext2_fs.h> 6#include <linux/romfs_fs.h> 7#include <linux/initrd.h> 8#include <linux/sched.h> 9#include <linux/freezer.h> 10 11#include "do_mounts.h" 12 13unsigned long initrd_start, initrd_end; 14int initrd_below_start_ok; 15unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */ 16static int __initdata old_fd, root_fd; 17static int __initdata mount_initrd = 1; 18 19static int __init no_initrd(char *str) 20{ 21 mount_initrd = 0; 22 return 1; 23} 24 25__setup("noinitrd", no_initrd); 26 27static int __init do_linuxrc(void * shell) 28{ 29 static char *argv[] = { "linuxrc", NULL, }; 30 extern char * envp_init[]; 31 32 sys_close(old_fd);sys_close(root_fd); 33 sys_close(0);sys_close(1);sys_close(2); 34 sys_setsid(); 35 (void) sys_open("/dev/console",O_RDWR,0); 36 (void) sys_dup(0); 37 (void) sys_dup(0); 38 return kernel_execve(shell, argv, envp_init); 39} 40 41static void __init handle_initrd(void) 42{ 43 int error; 44 int pid; 45 46 real_root_dev = new_encode_dev(ROOT_DEV); 47 create_dev("/dev/root.old", Root_RAM0); 48 /* mount initrd on rootfs' /root */ 49 mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY); 50 sys_mkdir("/old", 0700); 51 root_fd = sys_open("/", 0, 0); 52 old_fd = sys_open("/old", 0, 0); 53 /* move initrd over / and chdir/chroot in initrd root */ 54 sys_chdir("/root"); 55 sys_mount(".", "/", NULL, MS_MOVE, NULL); 56 sys_chroot("."); 57 58 pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); 59 if (pid > 0) { 60 while (pid != sys_wait4(-1, NULL, 0, NULL)) { 61 try_to_freeze(); 62 yield(); 63 } 64 } 65 66 /* move initrd to rootfs' /old */ 67 sys_fchdir(old_fd); 68 sys_mount("/", ".", NULL, MS_MOVE, NULL); 69 /* switch root and cwd back to / of rootfs */ 70 sys_fchdir(root_fd); 71 sys_chroot("."); 72 sys_close(old_fd); 73 sys_close(root_fd); 74 75 if (new_decode_dev(real_root_dev) == Root_RAM0) { 76 sys_chdir("/old"); 77 return; 78 } 79 80 ROOT_DEV = new_decode_dev(real_root_dev); 81 mount_root(); 82 83 printk(KERN_NOTICE "Trying to move old root to /initrd ... "); 84 error = sys_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL); 85 if (!error) 86 printk("okay\n"); 87 else { 88 int fd = sys_open("/dev/root.old", O_RDWR, 0); 89 if (error == -ENOENT) 90 printk("/initrd does not exist. Ignored.\n"); 91 else 92 printk("failed\n"); 93 printk(KERN_NOTICE "Unmounting old root\n"); 94 sys_umount("/old", MNT_DETACH); 95 printk(KERN_NOTICE "Trying to free ramdisk memory ... "); 96 if (fd < 0) { 97 error = fd; 98 } else { 99 error = sys_ioctl(fd, BLKFLSBUF, 0); 100 sys_close(fd); 101 } 102 printk(!error ? "okay\n" : "failed\n"); 103 } 104} 105 106int __init initrd_load(void) 107{ 108 if (mount_initrd) { 109 create_dev("/dev/ram", Root_RAM0); 110 /* 111 * Load the initrd data into /dev/ram0. Execute it as initrd 112 * unless /dev/ram0 is supposed to be our actual root device, 113 * in that case the ram disk is just set up here, and gets 114 * mounted in the normal path. 115 */ 116 if (rd_load_image("/initrd.image") && ROOT_DEV != Root_RAM0) { 117 sys_unlink("/initrd.image"); 118 handle_initrd(); 119 return 1; 120 } 121 } 122 sys_unlink("/initrd.image"); 123 return 0; 124} 125