perf cgroup: Fix a typo in kernel config
[linux-2.6.git] / init / initramfs.c
index 76f4a01..2531811 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/fcntl.h>
 #include <linux/delay.h>
 #include <linux/string.h>
+#include <linux/dirent.h>
 #include <linux/syscalls.h>
 #include <linux/utime.h>
 
@@ -166,8 +167,6 @@ static __initdata char *victim;
 static __initdata unsigned count;
 static __initdata loff_t this_header, next_header;
 
-static __initdata int dry_run;
-
 static inline void __init eat(unsigned n)
 {
        victim += n;
@@ -229,10 +228,6 @@ static int __init do_header(void)
        parse_header(collected);
        next_header = this_header + N_ALIGN(name_len) + body_len;
        next_header = (next_header + 3) & ~3;
-       if (dry_run) {
-               read_into(name_buf, N_ALIGN(name_len), GotName);
-               return 0;
-       }
        state = SkipIt;
        if (name_len <= 0 || name_len > PATH_MAX)
                return 0;
@@ -303,8 +298,6 @@ static int __init do_name(void)
                free_hash();
                return 0;
        }
-       if (dry_run)
-               return 0;
        clean_path(collected, mode);
        if (S_ISREG(mode)) {
                int ml = maybe_link();
@@ -317,7 +310,8 @@ static int __init do_name(void)
                        if (wfd >= 0) {
                                sys_fchown(wfd, uid, gid);
                                sys_fchmod(wfd, mode);
-                               sys_ftruncate(wfd, body_len);
+                               if (body_len)
+                                       sys_ftruncate(wfd, body_len);
                                vcollected = kstrdup(collected, GFP_KERNEL);
                                state = CopyFile;
                        }
@@ -417,12 +411,13 @@ static unsigned my_inptr;   /* index of next byte to be processed in inbuf */
 
 #include <linux/decompress/generic.h>
 
-static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
+static char * __init unpack_to_rootfs(char *buf, unsigned len)
 {
-       int written;
+       int written, res;
        decompress_fn decompress;
+       const char *compress_name;
+       static __initdata char msg_buf[64];
 
-       dry_run = check_only;
        header_buf = kmalloc(110, GFP_KERNEL);
        symlink_buf = kmalloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1, GFP_KERNEL);
        name_buf = kmalloc(N_ALIGN(PATH_MAX), GFP_KERNEL);
@@ -449,10 +444,21 @@ static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
                        continue;
                }
                this_header = 0;
-               decompress = decompress_method(buf, len, NULL);
-               if (decompress)
-                       decompress(buf, len, NULL, flush_buffer, NULL,
+               decompress = decompress_method(buf, len, &compress_name);
+               if (decompress) {
+                       res = decompress(buf, len, NULL, flush_buffer, NULL,
                                   &my_inptr, error);
+                       if (res)
+                               error("decompressor failed");
+               } else if (compress_name) {
+                       if (!message) {
+                               snprintf(msg_buf, sizeof msg_buf,
+                                        "compression method %s not configured",
+                                        compress_name);
+                               message = msg_buf;
+                       }
+               } else
+                       error("junk in compressed archive");
                if (state != Reset)
                        error("junk in compressed archive");
                this_header = saved_offset + my_inptr;
@@ -477,7 +483,8 @@ static int __init retain_initrd_param(char *str)
 }
 __setup("retain_initrd", retain_initrd_param);
 
-extern char __initramfs_start[], __initramfs_end[];
+extern char __initramfs_start[];
+extern unsigned long __initramfs_size;
 #include <linux/initrd.h>
 #include <linux/kexec.h>
 
@@ -513,27 +520,77 @@ skip:
        initrd_end = 0;
 }
 
+#ifdef CONFIG_BLK_DEV_RAM
+#define BUF_SIZE 1024
+static void __init clean_rootfs(void)
+{
+       int fd;
+       void *buf;
+       struct linux_dirent64 *dirp;
+       int num;
+
+       fd = sys_open((const char __user __force *) "/", O_RDONLY, 0);
+       WARN_ON(fd < 0);
+       if (fd < 0)
+               return;
+       buf = kzalloc(BUF_SIZE, GFP_KERNEL);
+       WARN_ON(!buf);
+       if (!buf) {
+               sys_close(fd);
+               return;
+       }
+
+       dirp = buf;
+       num = sys_getdents64(fd, dirp, BUF_SIZE);
+       while (num > 0) {
+               while (num > 0) {
+                       struct stat st;
+                       int ret;
+
+                       ret = sys_newlstat(dirp->d_name, &st);
+                       WARN_ON_ONCE(ret);
+                       if (!ret) {
+                               if (S_ISDIR(st.st_mode))
+                                       sys_rmdir(dirp->d_name);
+                               else
+                                       sys_unlink(dirp->d_name);
+                       }
+
+                       num -= dirp->d_reclen;
+                       dirp = (void *)dirp + dirp->d_reclen;
+               }
+               dirp = buf;
+               memset(buf, 0, BUF_SIZE);
+               num = sys_getdents64(fd, dirp, BUF_SIZE);
+       }
+
+       sys_close(fd);
+       kfree(buf);
+}
+#endif
+
 static int __init populate_rootfs(void)
 {
-       char *err = unpack_to_rootfs(__initramfs_start,
-                        __initramfs_end - __initramfs_start, 0);
+       char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
        if (err)
-               panic(err);
+               panic(err);     /* Failed to decompress INTERNAL initramfs */
        if (initrd_start) {
 #ifdef CONFIG_BLK_DEV_RAM
                int fd;
-               printk(KERN_INFO "checking if image is initramfs...");
+               printk(KERN_INFO "Trying to unpack rootfs image as initramfs...\n");
                err = unpack_to_rootfs((char *)initrd_start,
-                       initrd_end - initrd_start, 1);
+                       initrd_end - initrd_start);
                if (!err) {
-                       printk(" it is\n");
-                       unpack_to_rootfs((char *)initrd_start,
-                               initrd_end - initrd_start, 0);
                        free_initrd();
                        return 0;
+               } else {
+                       clean_rootfs();
+                       unpack_to_rootfs(__initramfs_start, __initramfs_size);
                }
-               printk("it isn't (%s); looks like an initrd\n", err);
-               fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700);
+               printk(KERN_INFO "rootfs image is not initramfs (%s)"
+                               "; looks like an initrd\n", err);
+               fd = sys_open((const char __user __force *) "/initrd.image",
+                             O_WRONLY|O_CREAT, 0700);
                if (fd >= 0) {
                        sys_write(fd, (char *)initrd_start,
                                        initrd_end - initrd_start);
@@ -541,12 +598,11 @@ static int __init populate_rootfs(void)
                        free_initrd();
                }
 #else
-               printk(KERN_INFO "Unpacking initramfs...");
+               printk(KERN_INFO "Unpacking initramfs...\n");
                err = unpack_to_rootfs((char *)initrd_start,
-                       initrd_end - initrd_start, 0);
+                       initrd_end - initrd_start);
                if (err)
-                       panic(err);
-               printk(" done\n");
+                       printk(KERN_EMERG "Initramfs unpacking failed: %s\n", err);
                free_initrd();
 #endif
        }