UBUNTU: Ubuntu-2.6.38-12.51
[linux-flexiantxendom0-natty.git] / init / initramfs.c
1 #include <linux/init.h>
2 #include <linux/fs.h>
3 #include <linux/slab.h>
4 #include <linux/types.h>
5 #include <linux/fcntl.h>
6 #include <linux/delay.h>
7 #include <linux/string.h>
8 #include <linux/dirent.h>
9 #include <linux/syscalls.h>
10 #include <linux/utime.h>
11 #include <linux/async.h>
12
13 static __initdata char *message;
14 static void __init error(char *x)
15 {
16         if (!message)
17                 message = x;
18 }
19
20 /* link hash */
21
22 #define N_ALIGN(len) ((((len) + 1) & ~3) + 2)
23
24 static __initdata struct hash {
25         int ino, minor, major;
26         mode_t mode;
27         struct hash *next;
28         char name[N_ALIGN(PATH_MAX)];
29 } *head[32];
30
31 static inline int hash(int major, int minor, int ino)
32 {
33         unsigned long tmp = ino + minor + (major << 3);
34         tmp += tmp >> 5;
35         return tmp & 31;
36 }
37
38 static char __init *find_link(int major, int minor, int ino,
39                               mode_t mode, char *name)
40 {
41         struct hash **p, *q;
42         for (p = head + hash(major, minor, ino); *p; p = &(*p)->next) {
43                 if ((*p)->ino != ino)
44                         continue;
45                 if ((*p)->minor != minor)
46                         continue;
47                 if ((*p)->major != major)
48                         continue;
49                 if (((*p)->mode ^ mode) & S_IFMT)
50                         continue;
51                 return (*p)->name;
52         }
53         q = kmalloc(sizeof(struct hash), GFP_KERNEL);
54         if (!q)
55                 panic("can't allocate link hash entry");
56         q->major = major;
57         q->minor = minor;
58         q->ino = ino;
59         q->mode = mode;
60         strcpy(q->name, name);
61         q->next = NULL;
62         *p = q;
63         return NULL;
64 }
65
66 static void __init free_hash(void)
67 {
68         struct hash **p, *q;
69         for (p = head; p < head + 32; p++) {
70                 while (*p) {
71                         q = *p;
72                         *p = q->next;
73                         kfree(q);
74                 }
75         }
76 }
77
78 static long __init do_utime(char __user *filename, time_t mtime)
79 {
80         struct timespec t[2];
81
82         t[0].tv_sec = mtime;
83         t[0].tv_nsec = 0;
84         t[1].tv_sec = mtime;
85         t[1].tv_nsec = 0;
86
87         return do_utimes(AT_FDCWD, filename, t, AT_SYMLINK_NOFOLLOW);
88 }
89
90 static __initdata LIST_HEAD(dir_list);
91 struct dir_entry {
92         struct list_head list;
93         char *name;
94         time_t mtime;
95 };
96
97 static void __init dir_add(const char *name, time_t mtime)
98 {
99         struct dir_entry *de = kmalloc(sizeof(struct dir_entry), GFP_KERNEL);
100         if (!de)
101                 panic("can't allocate dir_entry buffer");
102         INIT_LIST_HEAD(&de->list);
103         de->name = kstrdup(name, GFP_KERNEL);
104         de->mtime = mtime;
105         list_add(&de->list, &dir_list);
106 }
107
108 static void __init dir_utime(void)
109 {
110         struct dir_entry *de, *tmp;
111         list_for_each_entry_safe(de, tmp, &dir_list, list) {
112                 list_del(&de->list);
113                 do_utime(de->name, de->mtime);
114                 kfree(de->name);
115                 kfree(de);
116         }
117 }
118
119 static __initdata time_t mtime;
120
121 /* cpio header parsing */
122
123 static __initdata unsigned long ino, major, minor, nlink;
124 static __initdata mode_t mode;
125 static __initdata unsigned long body_len, name_len;
126 static __initdata uid_t uid;
127 static __initdata gid_t gid;
128 static __initdata unsigned rdev;
129
130 static void __init parse_header(char *s)
131 {
132         unsigned long parsed[12];
133         char buf[9];
134         int i;
135
136         buf[8] = '\0';
137         for (i = 0, s += 6; i < 12; i++, s += 8) {
138                 memcpy(buf, s, 8);
139                 parsed[i] = simple_strtoul(buf, NULL, 16);
140         }
141         ino = parsed[0];
142         mode = parsed[1];
143         uid = parsed[2];
144         gid = parsed[3];
145         nlink = parsed[4];
146         mtime = parsed[5];
147         body_len = parsed[6];
148         major = parsed[7];
149         minor = parsed[8];
150         rdev = new_encode_dev(MKDEV(parsed[9], parsed[10]));
151         name_len = parsed[11];
152 }
153
154 /* FSM */
155
156 static __initdata enum state {
157         Start,
158         Collect,
159         GotHeader,
160         SkipIt,
161         GotName,
162         CopyFile,
163         GotSymlink,
164         Reset
165 } state, next_state;
166
167 static __initdata char *victim;
168 static __initdata unsigned count;
169 static __initdata loff_t this_header, next_header;
170
171 static inline void __init eat(unsigned n)
172 {
173         victim += n;
174         this_header += n;
175         count -= n;
176 }
177
178 static __initdata char *vcollected;
179 static __initdata char *collected;
180 static __initdata int remains;
181 static __initdata char *collect;
182
183 static void __init read_into(char *buf, unsigned size, enum state next)
184 {
185         if (count >= size) {
186                 collected = victim;
187                 eat(size);
188                 state = next;
189         } else {
190                 collect = collected = buf;
191                 remains = size;
192                 next_state = next;
193                 state = Collect;
194         }
195 }
196
197 static __initdata char *header_buf, *symlink_buf, *name_buf;
198
199 static int __init do_start(void)
200 {
201         read_into(header_buf, 110, GotHeader);
202         return 0;
203 }
204
205 static int __init do_collect(void)
206 {
207         unsigned n = remains;
208         if (count < n)
209                 n = count;
210         memcpy(collect, victim, n);
211         eat(n);
212         collect += n;
213         if ((remains -= n) != 0)
214                 return 1;
215         state = next_state;
216         return 0;
217 }
218
219 static int __init do_header(void)
220 {
221         if (memcmp(collected, "070707", 6)==0) {
222                 error("incorrect cpio method used: use -H newc option");
223                 return 1;
224         }
225         if (memcmp(collected, "070701", 6)) {
226                 error("no cpio magic");
227                 return 1;
228         }
229         parse_header(collected);
230         next_header = this_header + N_ALIGN(name_len) + body_len;
231         next_header = (next_header + 3) & ~3;
232         state = SkipIt;
233         if (name_len <= 0 || name_len > PATH_MAX)
234                 return 0;
235         if (S_ISLNK(mode)) {
236                 if (body_len > PATH_MAX)
237                         return 0;
238                 collect = collected = symlink_buf;
239                 remains = N_ALIGN(name_len) + body_len;
240                 next_state = GotSymlink;
241                 state = Collect;
242                 return 0;
243         }
244         if (S_ISREG(mode) || !body_len)
245                 read_into(name_buf, N_ALIGN(name_len), GotName);
246         return 0;
247 }
248
249 static int __init do_skip(void)
250 {
251         if (this_header + count < next_header) {
252                 eat(count);
253                 return 1;
254         } else {
255                 eat(next_header - this_header);
256                 state = next_state;
257                 return 0;
258         }
259 }
260
261 static int __init do_reset(void)
262 {
263         while(count && *victim == '\0')
264                 eat(1);
265         if (count && (this_header & 3))
266                 error("broken padding");
267         return 1;
268 }
269
270 static int __init maybe_link(void)
271 {
272         if (nlink >= 2) {
273                 char *old = find_link(major, minor, ino, mode, collected);
274                 if (old)
275                         return (sys_link(old, collected) < 0) ? -1 : 1;
276         }
277         return 0;
278 }
279
280 static void __init clean_path(char *path, mode_t mode)
281 {
282         struct stat st;
283
284         if (!sys_newlstat(path, &st) && (st.st_mode^mode) & S_IFMT) {
285                 if (S_ISDIR(st.st_mode))
286                         sys_rmdir(path);
287                 else
288                         sys_unlink(path);
289         }
290 }
291
292 static __initdata int wfd;
293
294 static int __init do_name(void)
295 {
296         state = SkipIt;
297         next_state = Reset;
298         if (strcmp(collected, "TRAILER!!!") == 0) {
299                 free_hash();
300                 return 0;
301         }
302         clean_path(collected, mode);
303         if (S_ISREG(mode)) {
304                 int ml = maybe_link();
305                 if (ml >= 0) {
306                         int openflags = O_WRONLY|O_CREAT;
307                         if (ml != 1)
308                                 openflags |= O_TRUNC;
309                         wfd = sys_open(collected, openflags, mode);
310
311                         if (wfd >= 0) {
312                                 sys_fchown(wfd, uid, gid);
313                                 sys_fchmod(wfd, mode);
314                                 if (body_len)
315                                         sys_ftruncate(wfd, body_len);
316                                 vcollected = kstrdup(collected, GFP_KERNEL);
317                                 state = CopyFile;
318                         }
319                 }
320         } else if (S_ISDIR(mode)) {
321                 sys_mkdir(collected, mode);
322                 sys_chown(collected, uid, gid);
323                 sys_chmod(collected, mode);
324                 dir_add(collected, mtime);
325         } else if (S_ISBLK(mode) || S_ISCHR(mode) ||
326                    S_ISFIFO(mode) || S_ISSOCK(mode)) {
327                 if (maybe_link() == 0) {
328                         sys_mknod(collected, mode, rdev);
329                         sys_chown(collected, uid, gid);
330                         sys_chmod(collected, mode);
331                         do_utime(collected, mtime);
332                 }
333         }
334         return 0;
335 }
336
337 static int __init do_copy(void)
338 {
339         if (count >= body_len) {
340                 sys_write(wfd, victim, body_len);
341                 sys_close(wfd);
342                 do_utime(vcollected, mtime);
343                 kfree(vcollected);
344                 eat(body_len);
345                 state = SkipIt;
346                 return 0;
347         } else {
348                 sys_write(wfd, victim, count);
349                 body_len -= count;
350                 eat(count);
351                 return 1;
352         }
353 }
354
355 static int __init do_symlink(void)
356 {
357         collected[N_ALIGN(name_len) + body_len] = '\0';
358         clean_path(collected, 0);
359         sys_symlink(collected + N_ALIGN(name_len), collected);
360         sys_lchown(collected, uid, gid);
361         do_utime(collected, mtime);
362         state = SkipIt;
363         next_state = Reset;
364         return 0;
365 }
366
367 static __initdata int (*actions[])(void) = {
368         [Start]         = do_start,
369         [Collect]       = do_collect,
370         [GotHeader]     = do_header,
371         [SkipIt]        = do_skip,
372         [GotName]       = do_name,
373         [CopyFile]      = do_copy,
374         [GotSymlink]    = do_symlink,
375         [Reset]         = do_reset,
376 };
377
378 static int __init write_buffer(char *buf, unsigned len)
379 {
380         count = len;
381         victim = buf;
382
383         while (!actions[state]())
384                 ;
385         return len - count;
386 }
387
388 static int __init flush_buffer(void *bufv, unsigned len)
389 {
390         char *buf = (char *) bufv;
391         int written;
392         int origLen = len;
393         if (message)
394                 return -1;
395         while ((written = write_buffer(buf, len)) < len && !message) {
396                 char c = buf[written];
397                 if (c == '0') {
398                         buf += written;
399                         len -= written;
400                         state = Start;
401                 } else if (c == 0) {
402                         buf += written;
403                         len -= written;
404                         state = Reset;
405                 } else
406                         error("junk in compressed archive");
407         }
408         return origLen;
409 }
410
411 static unsigned my_inptr;   /* index of next byte to be processed in inbuf */
412
413 #include <linux/decompress/generic.h>
414
415 static char * __init unpack_to_rootfs(char *buf, unsigned len)
416 {
417         int written, res;
418         decompress_fn decompress;
419         const char *compress_name;
420         static __initdata char msg_buf[64];
421
422         header_buf = kmalloc(110, GFP_KERNEL);
423         symlink_buf = kmalloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1, GFP_KERNEL);
424         name_buf = kmalloc(N_ALIGN(PATH_MAX), GFP_KERNEL);
425
426         if (!header_buf || !symlink_buf || !name_buf)
427                 panic("can't allocate buffers");
428
429         state = Start;
430         this_header = 0;
431         message = NULL;
432         while (!message && len) {
433                 loff_t saved_offset = this_header;
434                 if (*buf == '0' && !(this_header & 3)) {
435                         state = Start;
436                         written = write_buffer(buf, len);
437                         buf += written;
438                         len -= written;
439                         continue;
440                 }
441                 if (!*buf) {
442                         buf++;
443                         len--;
444                         this_header++;
445                         continue;
446                 }
447                 this_header = 0;
448                 decompress = decompress_method(buf, len, &compress_name);
449                 if (decompress) {
450                         res = decompress(buf, len, NULL, flush_buffer, NULL,
451                                    &my_inptr, error);
452                         if (res)
453                                 error("decompressor failed");
454                 } else if (compress_name) {
455                         if (!message) {
456                                 snprintf(msg_buf, sizeof msg_buf,
457                                          "compression method %s not configured",
458                                          compress_name);
459                                 message = msg_buf;
460                         }
461                 } else
462                         error("junk in compressed archive");
463                 if (state != Reset)
464                         error("junk in compressed archive");
465                 this_header = saved_offset + my_inptr;
466                 buf += my_inptr;
467                 len -= my_inptr;
468         }
469         dir_utime();
470         kfree(name_buf);
471         kfree(symlink_buf);
472         kfree(header_buf);
473         return message;
474 }
475
476 static int __initdata do_retain_initrd;
477
478 static int __init retain_initrd_param(char *str)
479 {
480         if (*str)
481                 return 0;
482         do_retain_initrd = 1;
483         return 1;
484 }
485 __setup("retain_initrd", retain_initrd_param);
486
487 extern char __initramfs_start[];
488 extern unsigned long __initramfs_size;
489 #include <linux/initrd.h>
490 #include <linux/kexec.h>
491
492 static void __init free_initrd(void)
493 {
494 #ifdef CONFIG_KEXEC
495         unsigned long crashk_start = (unsigned long)__va(crashk_res.start);
496         unsigned long crashk_end   = (unsigned long)__va(crashk_res.end);
497 #endif
498         if (do_retain_initrd)
499                 goto skip;
500
501 #ifdef CONFIG_KEXEC
502         /*
503          * If the initrd region is overlapped with crashkernel reserved region,
504          * free only memory that is not part of crashkernel region.
505          */
506         if (initrd_start < crashk_end && initrd_end > crashk_start) {
507                 /*
508                  * Initialize initrd memory region since the kexec boot does
509                  * not do.
510                  */
511                 memset((void *)initrd_start, 0, initrd_end - initrd_start);
512                 if (initrd_start < crashk_start)
513                         free_initrd_mem(initrd_start, crashk_start);
514                 if (initrd_end > crashk_end)
515                         free_initrd_mem(crashk_end, initrd_end);
516         } else
517 #endif
518                 free_initrd_mem(initrd_start, initrd_end);
519 skip:
520         initrd_start = 0;
521         initrd_end = 0;
522 }
523
524 #ifdef CONFIG_BLK_DEV_RAM
525 #define BUF_SIZE 1024
526 static void __init clean_rootfs(void)
527 {
528         int fd;
529         void *buf;
530         struct linux_dirent64 *dirp;
531         int num;
532
533         fd = sys_open((const char __user __force *) "/", O_RDONLY, 0);
534         WARN_ON(fd < 0);
535         if (fd < 0)
536                 return;
537         buf = kzalloc(BUF_SIZE, GFP_KERNEL);
538         WARN_ON(!buf);
539         if (!buf) {
540                 sys_close(fd);
541                 return;
542         }
543
544         dirp = buf;
545         num = sys_getdents64(fd, dirp, BUF_SIZE);
546         while (num > 0) {
547                 while (num > 0) {
548                         struct stat st;
549                         int ret;
550
551                         ret = sys_newlstat(dirp->d_name, &st);
552                         WARN_ON_ONCE(ret);
553                         if (!ret) {
554                                 if (S_ISDIR(st.st_mode))
555                                         sys_rmdir(dirp->d_name);
556                                 else
557                                         sys_unlink(dirp->d_name);
558                         }
559
560                         num -= dirp->d_reclen;
561                         dirp = (void *)dirp + dirp->d_reclen;
562                 }
563                 dirp = buf;
564                 memset(buf, 0, BUF_SIZE);
565                 num = sys_getdents64(fd, dirp, BUF_SIZE);
566         }
567
568         sys_close(fd);
569         kfree(buf);
570 }
571 #endif
572
573 LIST_HEAD(populate_rootfs_domain);
574
575 void populate_rootfs_wait(void)
576 {
577         async_synchronize_full_domain(&populate_rootfs_domain);
578 }
579 EXPORT_SYMBOL(populate_rootfs_wait);
580
581 static void __init async_populate_rootfs(void)
582 {
583         char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
584         if (err)
585                 panic(err);     /* Failed to decompress INTERNAL initramfs */
586         if (initrd_start) {
587 #ifdef CONFIG_BLK_DEV_RAM
588                 int fd;
589                 printk(KERN_INFO "Trying to unpack rootfs image as initramfs...\n");
590                 err = unpack_to_rootfs((char *)initrd_start,
591                         initrd_end - initrd_start);
592                 if (!err) {
593                         free_initrd();
594                         return;
595                 } else {
596                         clean_rootfs();
597                         unpack_to_rootfs(__initramfs_start, __initramfs_size);
598                 }
599                 printk(KERN_INFO "rootfs image is not initramfs (%s)"
600                                 "; looks like an initrd\n", err);
601                 fd = sys_open((const char __user __force *) "/initrd.image",
602                               O_WRONLY|O_CREAT, 0700);
603                 if (fd >= 0) {
604                         sys_write(fd, (char *)initrd_start,
605                                         initrd_end - initrd_start);
606                         sys_close(fd);
607                         free_initrd();
608                 }
609 #else
610                 printk(KERN_INFO "Unpacking initramfs...\n");
611                 err = unpack_to_rootfs((char *)initrd_start,
612                         initrd_end - initrd_start);
613                 if (err)
614                         printk(KERN_EMERG "Initramfs unpacking failed: %s\n", err);
615                 free_initrd();
616 #endif
617         }
618         return;
619 }
620
621 static int __initdata rootfs_populated;
622
623 static int __init populate_rootfs_early(void)
624 {
625         if (num_online_cpus() > 1) {
626                 rootfs_populated = 1;
627                 async_schedule_domain(async_populate_rootfs, NULL,
628                                                 &populate_rootfs_domain);
629         }
630 }
631 static int __init populate_rootfs(void)
632 {
633         if (!rootfs_populated)
634                 async_schedule_domain(async_populate_rootfs, NULL,
635                                                 &populate_rootfs_domain);
636 }
637
638 earlyrootfs_initcall(populate_rootfs_early);
639 rootfs_initcall(populate_rootfs);