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