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/syscalls.h> 9 10 static __initdata char *message; 11 static void __init error(char *x) 12 { 13 if (!message) 14 message = x; 15 } 16 17 static void __init *malloc(size_t size) 18 { 19 return kmalloc(size, GFP_KERNEL); 20 } 21 22 static void __init free(void *where) 23 { 24 kfree(where); 25 } 26 27 /* link hash */ 28 29 #define N_ALIGN(len) ((((len) + 1) & ~3) + 2) 30 31 static __initdata struct hash { 32 int ino, minor, major; 33 mode_t mode; 34 struct hash *next; 35 char name[N_ALIGN(PATH_MAX)]; 36 } *head[32]; 37 38 static inline int hash(int major, int minor, int ino) 39 { 40 unsigned long tmp = ino + minor + (major << 3); 41 tmp += tmp >> 5; 42 return tmp & 31; 43 } 44 45 static char __init *find_link(int major, int minor, int ino, 46 mode_t mode, char *name) 47 { 48 struct hash **p, *q; 49 for (p = head + hash(major, minor, ino); *p; p = &(*p)->next) { 50 if ((*p)->ino != ino) 51 continue; 52 if ((*p)->minor != minor) 53 continue; 54 if ((*p)->major != major) 55 continue; 56 if (((*p)->mode ^ mode) & S_IFMT) 57 continue; 58 return (*p)->name; 59 } 60 q = (struct hash *)malloc(sizeof(struct hash)); 61 if (!q) 62 panic("can't allocate link hash entry"); 63 q->major = major; 64 q->minor = minor; 65 q->ino = ino; 66 q->mode = mode; 67 strcpy(q->name, name); 68 q->next = NULL; 69 *p = q; 70 return NULL; 71 } 72 73 static void __init free_hash(void) 74 { 75 struct hash **p, *q; 76 for (p = head; p < head + 32; p++) { 77 while (*p) { 78 q = *p; 79 *p = q->next; 80 free(q); 81 } 82 } 83 } 84 85 /* cpio header parsing */ 86 87 static __initdata unsigned long ino, major, minor, nlink; 88 static __initdata mode_t mode; 89 static __initdata unsigned long body_len, name_len; 90 static __initdata uid_t uid; 91 static __initdata gid_t gid; 92 static __initdata unsigned rdev; 93 94 static void __init parse_header(char *s) 95 { 96 unsigned long parsed[12]; 97 char buf[9]; 98 int i; 99 100 buf[8] = '\0'; 101 for (i = 0, s += 6; i < 12; i++, s += 8) { 102 memcpy(buf, s, 8); 103 parsed[i] = simple_strtoul(buf, NULL, 16); 104 } 105 ino = parsed[0]; 106 mode = parsed[1]; 107 uid = parsed[2]; 108 gid = parsed[3]; 109 nlink = parsed[4]; 110 body_len = parsed[6]; 111 major = parsed[7]; 112 minor = parsed[8]; 113 rdev = new_encode_dev(MKDEV(parsed[9], parsed[10])); 114 name_len = parsed[11]; 115 } 116 117 /* FSM */ 118 119 static __initdata enum state { 120 Start, 121 Collect, 122 GotHeader, 123 SkipIt, 124 GotName, 125 CopyFile, 126 GotSymlink, 127 Reset 128 } state, next_state; 129 130 static __initdata char *victim; 131 static __initdata unsigned count; 132 static __initdata loff_t this_header, next_header; 133 134 static __initdata int dry_run; 135 136 static inline void __init eat(unsigned n) 137 { 138 victim += n; 139 this_header += n; 140 count -= n; 141 } 142 143 static __initdata char *collected; 144 static __initdata int remains; 145 static __initdata char *collect; 146 147 static void __init read_into(char *buf, unsigned size, enum state next) 148 { 149 if (count >= size) { 150 collected = victim; 151 eat(size); 152 state = next; 153 } else { 154 collect = collected = buf; 155 remains = size; 156 next_state = next; 157 state = Collect; 158 } 159 } 160 161 static __initdata char *header_buf, *symlink_buf, *name_buf; 162 163 static int __init do_start(void) 164 { 165 read_into(header_buf, 110, GotHeader); 166 return 0; 167 } 168 169 static int __init do_collect(void) 170 { 171 unsigned n = remains; 172 if (count < n) 173 n = count; 174 memcpy(collect, victim, n); 175 eat(n); 176 collect += n; 177 if ((remains -= n) != 0) 178 return 1; 179 state = next_state; 180 return 0; 181 } 182 183 static int __init do_header(void) 184 { 185 if (memcmp(collected, "070707", 6)==0) { 186 error("incorrect cpio method used: use -H newc option"); 187 return 1; 188 } 189 if (memcmp(collected, "070701", 6)) { 190 error("no cpio magic"); 191 return 1; 192 } 193 parse_header(collected); 194 next_header = this_header + N_ALIGN(name_len) + body_len; 195 next_header = (next_header + 3) & ~3; 196 if (dry_run) { 197 read_into(name_buf, N_ALIGN(name_len), GotName); 198 return 0; 199 } 200 state = SkipIt; 201 if (name_len <= 0 || name_len > PATH_MAX) 202 return 0; 203 if (S_ISLNK(mode)) { 204 if (body_len > PATH_MAX) 205 return 0; 206 collect = collected = symlink_buf; 207 remains = N_ALIGN(name_len) + body_len; 208 next_state = GotSymlink; 209 state = Collect; 210 return 0; 211 } 212 if (S_ISREG(mode) || !body_len) 213 read_into(name_buf, N_ALIGN(name_len), GotName); 214 return 0; 215 } 216 217 static int __init do_skip(void) 218 { 219 if (this_header + count < next_header) { 220 eat(count); 221 return 1; 222 } else { 223 eat(next_header - this_header); 224 state = next_state; 225 return 0; 226 } 227 } 228 229 static int __init do_reset(void) 230 { 231 while(count && *victim == '\0') 232 eat(1); 233 if (count && (this_header & 3)) 234 error("broken padding"); 235 return 1; 236 } 237 238 static int __init maybe_link(void) 239 { 240 if (nlink >= 2) { 241 char *old = find_link(major, minor, ino, mode, collected); 242 if (old) 243 return (sys_link(old, collected) < 0) ? -1 : 1; 244 } 245 return 0; 246 } 247 248 static void __init clean_path(char *path, mode_t mode) 249 { 250 struct stat st; 251 252 if (!sys_newlstat(path, &st) && (st.st_mode^mode) & S_IFMT) { 253 if (S_ISDIR(st.st_mode)) 254 sys_rmdir(path); 255 else 256 sys_unlink(path); 257 } 258 } 259 260 static __initdata int wfd; 261 262 static int __init do_name(void) 263 { 264 state = SkipIt; 265 next_state = Reset; 266 if (strcmp(collected, "TRAILER!!!") == 0) { 267 free_hash(); 268 return 0; 269 } 270 if (dry_run) 271 return 0; 272 clean_path(collected, mode); 273 if (S_ISREG(mode)) { 274 int ml = maybe_link(); 275 if (ml >= 0) { 276 int openflags = O_WRONLY|O_CREAT; 277 if (ml != 1) 278 openflags |= O_TRUNC; 279 wfd = sys_open(collected, openflags, mode); 280 281 if (wfd >= 0) { 282 sys_fchown(wfd, uid, gid); 283 sys_fchmod(wfd, mode); 284 state = CopyFile; 285 } 286 } 287 } else if (S_ISDIR(mode)) { 288 sys_mkdir(collected, mode); 289 sys_chown(collected, uid, gid); 290 sys_chmod(collected, mode); 291 } else if (S_ISBLK(mode) || S_ISCHR(mode) || 292 S_ISFIFO(mode) || S_ISSOCK(mode)) { 293 if (maybe_link() == 0) { 294 sys_mknod(collected, mode, rdev); 295 sys_chown(collected, uid, gid); 296 sys_chmod(collected, mode); 297 } 298 } 299 return 0; 300 } 301 302 static int __init do_copy(void) 303 { 304 if (count >= body_len) { 305 sys_write(wfd, victim, body_len); 306 sys_close(wfd); 307 eat(body_len); 308 state = SkipIt; 309 return 0; 310 } else { 311 sys_write(wfd, victim, count); 312 body_len -= count; 313 eat(count); 314 return 1; 315 } 316 } 317 318 static int __init do_symlink(void) 319 { 320 collected[N_ALIGN(name_len) + body_len] = '\0'; 321 clean_path(collected, 0); 322 sys_symlink(collected + N_ALIGN(name_len), collected); 323 sys_lchown(collected, uid, gid); 324 state = SkipIt; 325 next_state = Reset; 326 return 0; 327 } 328 329 static __initdata int (*actions[])(void) = { 330 [Start] = do_start, 331 [Collect] = do_collect, 332 [GotHeader] = do_header, 333 [SkipIt] = do_skip, 334 [GotName] = do_name, 335 [CopyFile] = do_copy, 336 [GotSymlink] = do_symlink, 337 [Reset] = do_reset, 338 }; 339 340 static int __init write_buffer(char *buf, unsigned len) 341 { 342 count = len; 343 victim = buf; 344 345 while (!actions[state]()) 346 ; 347 return len - count; 348 } 349 350 static void __init flush_buffer(char *buf, unsigned len) 351 { 352 int written; 353 if (message) 354 return; 355 while ((written = write_buffer(buf, len)) < len && !message) { 356 char c = buf[written]; 357 if (c == '0') { 358 buf += written; 359 len -= written; 360 state = Start; 361 } else if (c == 0) { 362 buf += written; 363 len -= written; 364 state = Reset; 365 } else 366 error("junk in compressed archive"); 367 } 368 } 369 370 /* 371 * gzip declarations 372 */ 373 374 #define OF(args) args 375 376 #ifndef memzero 377 #define memzero(s, n) memset ((s), 0, (n)) 378 #endif 379 380 typedef unsigned char uch; 381 typedef unsigned short ush; 382 typedef unsigned long ulg; 383 384 #define WSIZE 0x8000 /* window size--must be a power of two, and */ 385 /* at least 32K for zip's deflate method */ 386 387 static uch *inbuf; 388 static uch *window; 389 390 static unsigned insize; /* valid bytes in inbuf */ 391 static unsigned inptr; /* index of next byte to be processed in inbuf */ 392 static unsigned outcnt; /* bytes in output buffer */ 393 static long bytes_out; 394 395 #define get_byte() (inptr < insize ? inbuf[inptr++] : -1) 396 397 /* Diagnostic functions (stubbed out) */ 398 #define Assert(cond,msg) 399 #define Trace(x) 400 #define Tracev(x) 401 #define Tracevv(x) 402 #define Tracec(c,x) 403 #define Tracecv(c,x) 404 405 #define STATIC static 406 #define INIT __init 407 408 static void __init flush_window(void); 409 static void __init error(char *m); 410 static void __init gzip_mark(void **); 411 static void __init gzip_release(void **); 412 413 #include "../lib/inflate.c" 414 415 static void __init gzip_mark(void **ptr) 416 { 417 } 418 419 static void __init gzip_release(void **ptr) 420 { 421 } 422 423 /* =========================================================================== 424 * Write the output window window[0..outcnt-1] and update crc and bytes_out. 425 * (Used for the decompressed data only.) 426 */ 427 static void __init flush_window(void) 428 { 429 ulg c = crc; /* temporary variable */ 430 unsigned n; 431 uch *in, ch; 432 433 flush_buffer(window, outcnt); 434 in = window; 435 for (n = 0; n < outcnt; n++) { 436 ch = *in++; 437 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); 438 } 439 crc = c; 440 bytes_out += (ulg)outcnt; 441 outcnt = 0; 442 } 443 444 static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only) 445 { 446 int written; 447 dry_run = check_only; 448 header_buf = malloc(110); 449 symlink_buf = malloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1); 450 name_buf = malloc(N_ALIGN(PATH_MAX)); 451 window = malloc(WSIZE); 452 if (!window || !header_buf || !symlink_buf || !name_buf) 453 panic("can't allocate buffers"); 454 state = Start; 455 this_header = 0; 456 message = NULL; 457 while (!message && len) { 458 loff_t saved_offset = this_header; 459 if (*buf == '0' && !(this_header & 3)) { 460 state = Start; 461 written = write_buffer(buf, len); 462 buf += written; 463 len -= written; 464 continue; 465 } 466 if (!*buf) { 467 buf++; 468 len--; 469 this_header++; 470 continue; 471 } 472 this_header = 0; 473 insize = len; 474 inbuf = buf; 475 inptr = 0; 476 outcnt = 0; /* bytes in output buffer */ 477 bytes_out = 0; 478 crc = (ulg)0xffffffffL; /* shift register contents */ 479 makecrc(); 480 gunzip(); 481 if (state != Reset) 482 error("junk in gzipped archive"); 483 this_header = saved_offset + inptr; 484 buf += inptr; 485 len -= inptr; 486 } 487 free(window); 488 free(name_buf); 489 free(symlink_buf); 490 free(header_buf); 491 return message; 492 } 493 494 static int __initdata do_retain_initrd; 495 496 static int __init retain_initrd_param(char *str) 497 { 498 if (*str) 499 return 0; 500 do_retain_initrd = 1; 501 return 1; 502 } 503 __setup("retain_initrd", retain_initrd_param); 504 505 extern char __initramfs_start[], __initramfs_end[]; 506 #ifdef CONFIG_BLK_DEV_INITRD 507 #include <linux/initrd.h> 508 #include <linux/kexec.h> 509 510 static void __init free_initrd(void) 511 { 512 #ifdef CONFIG_KEXEC 513 unsigned long crashk_start = (unsigned long)__va(crashk_res.start); 514 unsigned long crashk_end = (unsigned long)__va(crashk_res.end); 515 #endif 516 if (do_retain_initrd) 517 goto skip; 518 519 #ifdef CONFIG_KEXEC 520 /* 521 * If the initrd region is overlapped with crashkernel reserved region, 522 * free only memory that is not part of crashkernel region. 523 */ 524 if (initrd_start < crashk_end && initrd_end > crashk_start) { 525 /* 526 * Initialize initrd memory region since the kexec boot does 527 * not do. 528 */ 529 memset((void *)initrd_start, 0, initrd_end - initrd_start); 530 if (initrd_start < crashk_start) 531 free_initrd_mem(initrd_start, crashk_start); 532 if (initrd_end > crashk_end) 533 free_initrd_mem(crashk_end, initrd_end); 534 } else 535 #endif 536 free_initrd_mem(initrd_start, initrd_end); 537 skip: 538 initrd_start = 0; 539 initrd_end = 0; 540 } 541 542 #endif 543 544 static int __init populate_rootfs(void) 545 { 546 char *err = unpack_to_rootfs(__initramfs_start, 547 __initramfs_end - __initramfs_start, 0); 548 if (err) 549 panic(err); 550 #ifdef CONFIG_BLK_DEV_INITRD 551 if (initrd_start) { 552 #ifdef CONFIG_BLK_DEV_RAM 553 int fd; 554 printk(KERN_INFO "checking if image is initramfs..."); 555 err = unpack_to_rootfs((char *)initrd_start, 556 initrd_end - initrd_start, 1); 557 if (!err) { 558 printk(" it is\n"); 559 unpack_to_rootfs((char *)initrd_start, 560 initrd_end - initrd_start, 0); 561 free_initrd(); 562 return 0; 563 } 564 printk("it isn't (%s); looks like an initrd\n", err); 565 fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700); 566 if (fd >= 0) { 567 sys_write(fd, (char *)initrd_start, 568 initrd_end - initrd_start); 569 sys_close(fd); 570 free_initrd(); 571 } 572 #else 573 printk(KERN_INFO "Unpacking initramfs..."); 574 err = unpack_to_rootfs((char *)initrd_start, 575 initrd_end - initrd_start, 0); 576 if (err) 577 panic(err); 578 printk(" done\n"); 579 free_initrd(); 580 #endif 581 } 582 #endif 583 return 0; 584 } 585 rootfs_initcall(populate_rootfs); 586