nexmon – Rev 1

Subversion Repositories:
Rev:
/* tools/mkbootimg/unmkbootimg.c
**
** Copyright 2013, Pete Batard <pete@akeo.ie>
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

#include "bootimg.h"

static void *load_file(const char *fn, unsigned *_sz)
{
    char *data;
    int sz;
    FILE *fd;

    data = 0;
    fd = fopen(fn, "rb");
    if(fd == 0) return 0;

    if(fseek(fd, 0, SEEK_END) != 0) goto oops;
    sz = ftell(fd);
    if(sz < 0) goto oops;

    if(fseek(fd, 0, SEEK_SET) != 0) goto oops;

    data = (char*) malloc(sz);
    if(data == 0) goto oops;

    if(fread(data, 1, sz, fd) != (size_t) sz) goto oops;
    fclose(fd);

    if(_sz) *_sz = sz;
    return data;

oops:
    fclose(fd);
    if(data != 0) free(data);
    return 0;
}

static unsigned save_file(const char *fn, const void* data, const unsigned sz)
{
    FILE *fd;
    unsigned _sz = 0;

    fd = fopen(fn, "wb");
    if(fd == 0) return 0;

    _sz = fwrite(data, 1, sz, fd);
    fclose(fd);

    return _sz;
}

int usage(void)
{
    fprintf(stderr,"usage: unmkbootimg\n"
            "       [ --kernel <filename> ]\n"
            "       [ --ramdisk <filename> ]\n"
            "       [ --second <2ndbootloader-filename> ]\n"
            "       -i|--input <filename>\n"
            );
    return 1;
}

int main(int argc, char **argv)
{
    void *file_data = 0;
    unsigned file_size = 0;
    boot_img_hdr *hdr = 0;

    char *kernel_fn = "kernel";
    char *ramdisk_fn = "ramdisk.cpio.gz";
    char *second_fn = "second_bootloader";
    char *bootimg = 0;
    unsigned offset;

    argc--;
    argv++;

    while(argc > 0){
        char *arg = argv[0];
        char *val = argv[1];
        if(argc < 2) {
            return usage();
        }
        argc -= 2;
        argv += 2;
        if(!strcmp(arg, "--input") || !strcmp(arg, "-i")) {
            bootimg = val;
        } else if(!strcmp(arg, "--kernel")) {
            kernel_fn = val;
        } else if(!strcmp(arg, "--ramdisk")) {
            ramdisk_fn = val;
        } else if(!strcmp(arg, "--second")) {
           second_fn = val;
        } else {
            return usage();
        }
    }

    if(bootimg == 0) {
        fprintf(stderr,"error: no input filename specified\n");
        return usage();
    }

    file_data = load_file(bootimg, &file_size);
    if(file_data == 0) {
        fprintf(stderr,"error: could not load image '%s'\n", bootimg);
        return 1;
    }
    if(file_size < sizeof(boot_img_hdr)) {
        fprintf(stderr,"error: file too small for a boot image\n");
        goto fail;
    }
    hdr = (boot_img_hdr *)file_data;
    if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE) != 0) {
        fprintf(stderr,"error: not an Android boot image\n");
        goto fail;
    }

    if(hdr->kernel_size != 0) {
        offset = hdr->page_size;
        if (save_file(kernel_fn, &((char *)file_data)[offset],
            hdr->kernel_size) != hdr->kernel_size) {
            fprintf(stderr,"error: could not save kernel '%s'\n", kernel_fn);
            return 1;
        }
        printf("kernel written to '%s' (%d bytes)\n", kernel_fn, 
            hdr->kernel_size);
    }

    if(hdr->ramdisk_size != 0) {
        offset = ((hdr->kernel_size + 2*hdr->page_size - 1) /
            hdr->page_size) * hdr->page_size;
        if (save_file(ramdisk_fn, &((char *)file_data)[offset],
            hdr->ramdisk_size) != hdr->ramdisk_size) {
            fprintf(stderr,"error: could not save ramdisk '%s'\n",
                ramdisk_fn);
            return 1;
        }
        printf("ramdisk written to '%s' (%d bytes)\n", ramdisk_fn,
            hdr->ramdisk_size);
    }

    if(hdr->second_size != 0) {
        offset = ((hdr->kernel_size + hdr->ramdisk_size
            + 2*hdr->page_size - 1) / hdr->page_size) * hdr->page_size;
        if (save_file(second_fn, &((char *)file_data)[offset],
            hdr->second_size) != hdr->second_size) {
            fprintf(stderr,"error: could not save second bootloader '%s'\n",
                second_fn);
            return 1;
        }
        printf("second bootloader written to '%s' (%d bytes)\n",
            second_fn, hdr->second_size);
    }

    /* Ideally, we'd also check the SHA sums here */

    printf("\nTo rebuild this boot image, you can use the command:\n");
    printf("  mkbootimg --base 0 --pagesize %d ", hdr->page_size);
    if(hdr->name[0] != 0) {
        printf("--board %s ", hdr->name);
    }
    printf("--kernel_offset 0x%08x --ramdisk_offset 0x%08x ",
        hdr->kernel_addr, hdr->ramdisk_addr);
    printf("--second_offset 0x%08x --tags_offset 0x%08x ",
         hdr->second_addr, hdr->tags_addr);
    if(hdr->cmdline[0] != 0) {
        printf("--cmdline '%s%s' ", hdr->cmdline, hdr->extra_cmdline);
    }
    if(hdr->kernel_size != 0) {
        printf("--kernel %s ", kernel_fn);
    }
    if(hdr->ramdisk_size != 0) {
        printf("--ramdisk %s ", ramdisk_fn);
    }
    if(hdr->second_size != 0) {
        printf("--second %s ", second_fn);
    }
    printf("-o %s\n", bootimg);

    free(file_data);
    return 0;

fail:
    free(file_data);
    return 1;
}