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