Initial commit

This commit is contained in:
Vojtech Bocek
2013-09-23 16:56:40 +02:00
commit a4477364ac
10 changed files with 1004 additions and 0 deletions

20
.travis.yml Normal file
View File

@@ -0,0 +1,20 @@
# Travis-CI Build for libbootimg
# see travis-ci.org for details
language: c
compiler:
- gcc
- clang
matrix:
include:
- compiler: i586-mingw32msvc-gcc
script:
- make
# Only watch the master
branches:
only:
- master

22
Android.mk Normal file
View File

@@ -0,0 +1,22 @@
# bbootimg
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= bbootimg.c libbootimg.c
LOCAL_MODULE:= bbootimg
LOCAL_MODULE_TAGS := eng
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_UNSTRIPPED_PATH := $(TARGET_OUT_EXECUTABLES_UNSTRIPPED)
LOCAL_STATIC_LIBRARIES := libc
include $(BUILD_EXECUTABLE)
# libbootimg
include $(CLEAR_VARS)
LOCAL_SRC_FILES := libbootimg.c
LOCAL_MODULE := libbootimg
LOCAL_MODULE_TAGS := eng
include $(BUILD_STATIC_LIBRARY)

18
COPYING Normal file
View File

@@ -0,0 +1,18 @@
The MIT License (MIT)
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

29
Makefile Normal file
View File

@@ -0,0 +1,29 @@
program=bbootimg
CC?=gcc
OPT=-O2 ${CFLAGS}
OBJ=bbootimg.o libbootimg.o
.PHONY: build
.PHONY: install
.PHONY: uninstall
.PHONY: clean
build: ${program}
clean:
rm -f *.o ${program}
${program}: ${OBJ}
$(CC) ${OBJ} -o ${program} ${OPT}
bbootimg.o: bbootimg.c
$(CC) -c ${OPT} $<
libbootimg.o: libbootimg.c
$(CC) -c ${OPT} $<
install: build
install -D ${program} /usr/local/bin/${program}
uninstall:
rm /usr/local/bin/${program}

5
README.md Normal file
View File

@@ -0,0 +1,5 @@
# libbootimg
libbootimg is small library which can create, extract or update Android boot images.
## bbootimg
This is cli frontend for libbootimg, compatible with abootimg's arguments.

338
bbootimg.c Normal file
View File

@@ -0,0 +1,338 @@
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include "libbootimg.h"
#define ACT_EXTRACT 1
#define ACT_UPDATE 2
#define ACT_CREATE 3
struct bbootimg_info
{
struct bootimg img;
int act;
char *fname_img;
char *fname_kernel;
char *fname_ramdisk;
char *fname_second;
char *fname_cfg;
};
static void print_help(const char *prog_name)
{
printf(
"bbootimg %s\n"
"Manipulate Android Boot Images.\n"
"This is abootimg-compatible implementation using libbootimg.\n"
"\n"
"%s [-h,--help] - print usage\n"
"\n"
"%s -i <bootimg> - print image information\n"
"\n"
"%s -x <bootimg> [<bootimg.cfg> [<kernel> [<ramdisk> [<secondstage>]]]]\n"
" extract objects from boot image:\n"
" - config file (bootimg.cfg)\n"
" - kernel image (zImage)\n"
" - ramdisk image (initrd.img)\n"
" - second stage image (stage2.img)\n"
"\n"
"%s -u <bootimg> [-c \"param=value\"] [-f <bootimg.cfg>] [-k <kernel>] [-r <ramdisk>] [-s <secondstage>]\n"
" update current boot image with objects given in command line\n"
" - header informations given in arguments (several can be provided)\n"
" - header informations given in config file\n"
" - kernel image\n"
" - ramdisk image\n"
" - second stage image\n"
"\n"
"%s --create <bootimg> [-c \"param=value\"] [-f <bootimg.cfg>] -k <kernel> -r <ramdisk> [-s <secondstage>]\n"
" create a new image from scratch.\n"
" arguments are the same as for -u.\n"
" kernel and ramdisk are mandatory.\n"
,libbootimg_version_str(), prog_name, prog_name, prog_name, prog_name, prog_name);
}
static int print_info(const char *path)
{
struct bootimg img;
if(libbootimg_init_load(&img, path) < 0)
{
fprintf(stderr, "Failed to load bootimg \"%s\"!\n", path);
return 1;
}
printf ("\nAndroid Boot Image Info:\n\n");
printf ("* file name = %s\n\n", path);
printf ("* image size = %u bytes (%.2f MB)\n", img.size, (double)img.size/0x100000);
printf (" page size = %u bytes\n\n", img.hdr.page_size);
printf ("* Boot Name = \"%s\"\n\n", img.hdr.name);
printf ("* kernel size = %u bytes (%.2f MB)\n", img.hdr.kernel_size, (double)img.hdr.kernel_size/0x100000);
printf (" ramdisk size = %u bytes (%.2f MB)\n", img.hdr.ramdisk_size, (double)img.hdr.ramdisk_size/0x100000);
if (img.hdr.second_size)
printf (" second stage size = %u bytes (%.2f MB)\n", img.hdr.second_size, (double)img.hdr.second_size/0x100000);
printf ("\n* load addresses:\n");
printf (" kernel: 0x%08x\n", img.hdr.kernel_addr);
printf (" ramdisk: 0x%08x\n", img.hdr.ramdisk_addr);
if (img.hdr.second_size)
printf (" second stage: 0x%08x\n", img.hdr.second_addr);
printf (" tags: 0x%08x\n\n", img.hdr.tags_addr);
if (img.hdr.cmdline[0])
printf ("* cmdline = %s\n\n", img.hdr.cmdline);
else
printf ("* empty cmdline\n");
printf ("* id = ");
int i;
for (i=0; i<8; i++)
printf ("0x%08x ", img.hdr.id[i]);
printf ("\n\n");
libbootimg_destroy(&img);
return 0;
}
static int extract_bootimg(struct bbootimg_info *i)
{
int res = libbootimg_init_load(&i->img, i->fname_img);
if(res < 0)
{
fprintf(stderr, "Failed to load boot image (%s)!\n", strerror(-res));
return -res;
}
const char *cfg = i->fname_cfg ? i->fname_cfg : "bootimg.cfg";
printf("writing boot image config in %s\n", cfg);
res = libbootimg_write_config(&i->img, cfg);
if(res < 0)
{
fprintf(stderr, "Failed to write bootimg cfg (%s)!\n", strerror(-res));
return -res;
}
const char *kernel = i->fname_kernel ? i->fname_kernel : "zImage";
printf("extracting kernel in %s\n", kernel);
res = libbootimg_dump_kernel(&i->img, kernel);
if(res < 0)
{
fprintf(stderr, "Failed to extract kernel (%s)!\n", strerror(-res));
return -res;
}
const char *ramdisk = i->fname_ramdisk ? i->fname_ramdisk : "initrd.img";
printf("extracting kernel in %s\n", ramdisk);
res = libbootimg_dump_ramdisk(&i->img, ramdisk);
if(res < 0)
{
fprintf(stderr, "Failed to extract ramdisk (%s)!\n", strerror(-res));
return -res;
}
if(i->img.hdr.second_size > 0)
{
const char *second = i->fname_second ? i->fname_second : "stage2.img";
printf("extracting second stage in %s\n", second);
res = libbootimg_dump_second(&i->img, second);
if(res < 0)
{
fprintf(stderr, "Failed to extract second stage (%s)!\n", strerror(-res));
return -res;
}
}
libbootimg_destroy(&i->img);
return 0;
}
static int update_bootimg(struct bbootimg_info *i)
{
int res = -1;
char *tmpname = malloc(strlen(i->fname_img)+sizeof(".new"));
strcpy(tmpname, i->fname_img);
strcat(tmpname, ".new");
if(i->fname_cfg)
{
int line = -1;
printf("reading config file %s\n", i->fname_cfg);
res = libbootimg_load_config(&i->img, i->fname_cfg, &line);
if(res < 0)
{
res = -res;
fprintf(stderr, "Failed to load config (%s), error on line %d!\n", strerror(res), line);
goto exit;
}
}
if(i->fname_kernel)
{
printf("reading kernel from %s\n", i->fname_kernel);
res = libbootimg_load_kernel(&i->img, i->fname_kernel);
if(res < 0)
{
res = -res;
fprintf(stderr, "Failed to load kernel (%s)!\n", strerror(res));
goto exit;
}
}
if(i->fname_ramdisk)
{
printf("reading ramdisk from %s\n", i->fname_ramdisk);
res = libbootimg_load_ramdisk(&i->img, i->fname_ramdisk);
if(res < 0)
{
res = -res;
fprintf(stderr, "Failed to load ramdisk (%s)!\n", strerror(res));
goto exit;
}
}
if(i->fname_second)
{
printf("reading second stage from %s\n", i->fname_second);
res = libbootimg_load_second(&i->img, i->fname_second);
if(res < 0)
{
res = -res;
fprintf(stderr, "Failed to load second stage (%s)!\n", strerror(res));
goto exit;
}
}
printf("Writing Boot Image %s\n", i->fname_img);
res = libbootimg_write_img(&i->img, tmpname);
if(res < 0)
{
res = -res;
fprintf(stderr, "Failed to create boot image (%s)!\n", strerror(res));
remove(tmpname);
goto exit;
}
rename(tmpname, i->fname_img);
remove(tmpname);
exit:
free(tmpname);
libbootimg_destroy(&i->img);
return res;
}
static int execute_action(struct bbootimg_info *i)
{
switch(i->act)
{
case ACT_EXTRACT:
return extract_bootimg(i);
case ACT_UPDATE:
return update_bootimg(i);
case ACT_CREATE:
{
if(!i->fname_kernel || !i->fname_ramdisk)
{
fprintf(stderr, "You have to specify both ramdisk and kernel to create boot image!\n");
return EINVAL;
}
return update_bootimg(i);
}
}
return EINVAL;
}
static int load_bootimg(struct bootimg *b, const char *path)
{
int res = libbootimg_init_load(b, path);
if(res < 0)
{
fprintf(stderr, "Failed to load boot image (%s)!", strerror(-res));
return -res;
}
return 0;
}
int main(int argc, char *argv[])
{
int i;
struct bbootimg_info info;
memset(&info, 0, sizeof(info));
libbootimg_init_new(&info.img);
for(i = 1; i < argc; ++i)
{
if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0)
{
print_help(argv[0]);
return 0;
}
if(i+1 >= argc)
continue;
if(strcmp("-i", argv[i]) == 0)
return print_info(argv[i+1]);
// actions
if(strcmp("-x", argv[i]) == 0)
{
info.act = ACT_EXTRACT;
info.fname_img = argv[++i];
if(++i < argc)
info.fname_cfg = argv[i];
if(++i < argc)
info.fname_kernel = argv[i];
if(++i < argc)
info.fname_ramdisk = argv[i];
if(++i < argc)
info.fname_second = argv[i];
break;
}
else if(strcmp("-u", argv[i]) == 0)
{
info.act = ACT_UPDATE;
info.fname_img = argv[++i];
if(load_bootimg(&info.img, info.fname_img) != 0)
return -1;
}
else if(strcmp("--create", argv[i]) == 0)
{
info.act = ACT_CREATE;
info.fname_img = argv[++i];
}
// params
else if(strcmp("-c", argv[i]) == 0)
{
if(libbootimg_load_config_line(&info.img, argv[++i]) < 0)
{
fprintf(stderr, "Invalid config option \"%s\"\n\n", argv[i]);
goto exit_help;
}
}
else if(strcmp("-f", argv[i]) == 0)
info.fname_cfg = argv[++i];
else if(strcmp("-k", argv[i]) == 0)
info.fname_kernel = argv[++i];
else if(strcmp("-r", argv[i]) == 0)
info.fname_ramdisk = argv[++i];
else if(strcmp("-s", argv[i]) == 0)
info.fname_second = argv[++i];
else
{
fprintf(stderr, "Unknown argument: %s\n\n", argv[i]);
goto exit_help;
}
}
return execute_action(&info);
exit_help:
libbootimg_destroy(&info.img);
print_help(argv[0]);
return EINVAL;
}

78
boot_img_hdr.h Normal file
View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* 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.
*/
#ifndef BOOT_IMG_HDR_H
#define BOOT_IMG_HDR_H
/*
** +-----------------+
** | boot header | 1 page
** +-----------------+
** | kernel | n pages
** +-----------------+
** | ramdisk | m pages
** +-----------------+
** | second stage | o pages
** +-----------------+
**
** n = (kernel_size + page_size - 1) / page_size
** m = (ramdisk_size + page_size - 1) / page_size
** o = (second_size + page_size - 1) / page_size
**
** 0. all entities are page_size aligned in flash
** 1. kernel and ramdisk are required (size != 0)
** 2. second is optional (second_size == 0 -> no second)
** 3. load each element (kernel, ramdisk, second) at
** the specified physical address (kernel_addr, etc)
** 4. prepare tags at tag_addr. kernel_args[] is
** appended to the kernel commandline in the tags.
** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
** 6. if second_size != 0: jump to second_addr
** else: jump to kernel_addr
*/
#define BOOT_MAGIC "ANDROID!"
#define BOOT_MAGIC_SIZE 8
#define BOOT_NAME_SIZE 16
#define BOOT_ARGS_SIZE 512
struct boot_img_hdr
{
unsigned char magic[BOOT_MAGIC_SIZE];
unsigned kernel_size; /* size in bytes */
unsigned kernel_addr; /* physical load addr */
unsigned ramdisk_size; /* size in bytes */
unsigned ramdisk_addr; /* physical load addr */
unsigned second_size; /* size in bytes */
unsigned second_addr; /* physical load addr */
unsigned tags_addr; /* physical addr for kernel tags */
unsigned page_size; /* flash page size we assume */
unsigned unused[2]; /* future expansion: should be 0 */
unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
unsigned char cmdline[BOOT_ARGS_SIZE];
unsigned id[8]; /* timestamp / checksum / sha1 / etc */
};
typedef struct boot_img_hdr boot_img_hdr;
#endif

449
libbootimg.c Normal file
View File

@@ -0,0 +1,449 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#include <ctype.h>
#include "libbootimg.h"
#include "version.h"
#define DEFAULT_PAGE_SIZE 2048
#define MAX_PATH_LEN 4096
static inline unsigned align_size(unsigned size, unsigned page_size)
{
return ((size + page_size - 1)/page_size)*page_size;
}
void libbootimg_init_new(struct bootimg *img)
{
memset(img, 0, sizeof(struct bootimg));
strcpy((char*)img->hdr.magic, BOOT_MAGIC);
img->hdr.page_size = DEFAULT_PAGE_SIZE;
}
int libbootimg_init_load(struct bootimg *img, const char *path)
{
int res = 0;
long addr;
libbootimg_init_new(img);
res = libbootimg_load_header(&img->hdr, path);
if(res < 0)
{
libbootimg_destroy(img);
return res;
}
FILE *f = fopen(path, "r");
if(!f)
return -errno;
img->kernel = malloc(img->hdr.kernel_size);
img->ramdisk = malloc(img->hdr.ramdisk_size);
img->second = malloc(img->hdr.second_size);
// Read kernel
addr = img->hdr.page_size;
if(fseek(f, addr, SEEK_SET) < 0)
goto fail;
if(fread(img->kernel, img->hdr.kernel_size, 1, f) != 1)
goto fail;
// Read ramdisk
addr += align_size(img->hdr.kernel_size, img->hdr.page_size);
if(fseek(f, addr, SEEK_SET) < 0)
goto fail;
if(fread(img->ramdisk, img->hdr.ramdisk_size, 1, f) != 1)
goto fail;
// Read second
if(img->hdr.second_size > 0)
{
addr += align_size(img->hdr.ramdisk_size, img->hdr.page_size);
if(fseek(f, addr, SEEK_SET) < 0)
goto fail;
if(fread(img->second, img->hdr.second_size, 1, f) != 1)
goto fail;
}
fseek(f, 0, SEEK_END);
img->size = ftell(f);
fclose(f);
return 0;
fail:
res = -errno;
libbootimg_destroy(img);
fclose(f);
return res;
}
void libbootimg_destroy(struct bootimg *b)
{
free(b->kernel);
free(b->ramdisk);
free(b->second);
b->kernel = b->ramdisk = b->second = NULL;
}
int libbootimg_load_header(struct boot_img_hdr *hdr, const char *path)
{
FILE *f = fopen(path, "r");
if(!f)
return -errno;
int res = fread(hdr, sizeof(struct boot_img_hdr), 1, f);
res = res == 1 ? 0 : -errno;
fclose(f);
return res;
}
static int dump_part(uint8_t *data, unsigned len, const char *dest)
{
int res = 0;
FILE *f = fopen(dest, "w");
if(!f)
return -errno;
if(fwrite(data, len, 1, f) != 1)
res = -errno;
fclose(f);
return res;
}
int libbootimg_dump_kernel(struct bootimg *b, const char *dest)
{
return dump_part(b->kernel, b->hdr.kernel_size, dest);
}
int libbootimg_dump_ramdisk(struct bootimg *b, const char *dest)
{
return dump_part(b->ramdisk, b->hdr.ramdisk_size, dest);
}
int libbootimg_dump_second(struct bootimg *b, const char *dest)
{
if(b->hdr.second_size == 0)
return -ENOENT;
return dump_part(b->second, b->hdr.second_size, dest);
}
int libbootimg_dump(struct bootimg *b, const char *dest_dir)
{
char dest[MAX_PATH_LEN];
int res = 0;
snprintf(dest, sizeof(dest), "%s/zImage", dest_dir);
res = libbootimg_dump_kernel(b, dest);
if(res == 0)
{
snprintf(dest, sizeof(dest), "%s/initrd.img", dest_dir);
res = libbootimg_dump_ramdisk(b, dest);
}
if(res == 0 && b->hdr.second_size)
{
snprintf(dest, sizeof(dest), "%s/second.img", dest_dir);
res = libbootimg_dump_second(b, dest);
}
return res;
}
static int load_part(uint8_t **data, const char *src)
{
struct stat info;
if(stat(src, &info) < 0)
return -errno;
if(info.st_size > INT_MAX)
return -EFBIG;
FILE *f = fopen(src, "r");
if(!f)
return -errno;
int res = info.st_size;
*data = realloc(*data, info.st_size);
if(fread(*data, info.st_size, 1, f) != 1)
{
res = -errno;
free(*data);
*data = NULL;
}
fclose(f);
return res;
}
int libbootimg_load_kernel(struct bootimg *b, const char *src)
{
int res = load_part(&b->kernel, src);
if(res >= 0)
b->hdr.kernel_size = res;
return res;
}
int libbootimg_load_ramdisk(struct bootimg *b, const char *src)
{
int res = load_part(&b->ramdisk, src);
if(res >= 0)
b->hdr.ramdisk_size = res;
return res;
}
int libbootimg_load_second(struct bootimg *b, const char *src)
{
int res = load_part(&b->second, src);
if(res >= 0)
b->hdr.second_size = res;
return res;
}
// 32bit FNV-1a hash algorithm
// http://isthe.com/chongo/tech/comp/fnv/#FNV-1a
static uint32_t calc_fnv_hash(void *data, unsigned len)
{
static const uint32_t FNV_prime = 16777619U;
static const uint32_t offset_basis = 2166136261U;
uint32_t *d = (uint32_t*)data;
uint32_t i, max;
uint32_t hash = offset_basis;
max = len/4;
// 32 bit data
for(i = 0; i < max; ++i)
{
hash ^= d[i];
hash *= FNV_prime;
}
// last bits
for(i *= 4; i < len; ++i)
{
hash ^= (uint32_t) ((uint8_t*)data)[i];
hash *= FNV_prime;
}
return hash;
}
static void fill_id_hashes(struct bootimg *b)
{
b->hdr.id[0] = calc_fnv_hash(b->kernel, b->hdr.kernel_size);
b->hdr.id[1] = calc_fnv_hash(b->ramdisk, b->hdr.ramdisk_size);
b->hdr.id[2] = calc_fnv_hash(b->ramdisk, b->hdr.second_size);
b->hdr.id[3] = calc_fnv_hash(&b->hdr.kernel_addr, sizeof(b->hdr.kernel_addr));
b->hdr.id[4] = calc_fnv_hash(&b->hdr.ramdisk_addr, sizeof(b->hdr.ramdisk_addr));
b->hdr.id[5] = calc_fnv_hash(&b->hdr.second_addr, sizeof(b->hdr.second_addr));
b->hdr.id[6] = calc_fnv_hash(&b->hdr.tags_addr, sizeof(b->hdr.tags_addr));
b->hdr.id[7] = calc_fnv_hash(b->hdr.cmdline, strlen((char*)b->hdr.cmdline));
}
int libbootimg_write_img(struct bootimg *b, const char *dest)
{
if(b->hdr.kernel_size == 0 || b->hdr.ramdisk_size == 0 || b->hdr.page_size < sizeof(b->hdr))
return -EINVAL;
uint32_t i;
int res = 0;
FILE *f = fopen(dest, "w");
if(!f)
return -errno;
// make sure it ends with 0
b->hdr.cmdline[BOOT_ARGS_SIZE-1] = 0;
fill_id_hashes(b);
size_t to_write;
char *blank = malloc(b->hdr.page_size);
memset(blank, 0, b->hdr.page_size);
// write header
if(fwrite(&b->hdr, sizeof(b->hdr), 1, f) != 1)
goto fail;
to_write = align_size(sizeof(b->hdr), b->hdr.page_size) - sizeof(b->hdr);
if(fwrite(blank, sizeof(char), to_write, f) != to_write)
goto fail;
// write kernel
if(fwrite(b->kernel, b->hdr.kernel_size, 1, f) != 1)
goto fail;
to_write = align_size(b->hdr.kernel_size, b->hdr.page_size) - b->hdr.kernel_size;
if(fwrite(blank, sizeof(char), to_write, f) != to_write)
goto fail;
// write ramdisk
if(fwrite(b->ramdisk, b->hdr.ramdisk_size, 1, f) != 1)
goto fail;
to_write = align_size(b->hdr.ramdisk_size, b->hdr.page_size) - b->hdr.ramdisk_size;
if(fwrite(blank, sizeof(char), to_write, f) != to_write)
goto fail;
// write second
if(b->hdr.second_size != 0)
{
if(fwrite(b->second, b->hdr.second_size, 1, f) != 1)
goto fail;
to_write = align_size(b->hdr.second_size, b->hdr.page_size) - b->hdr.second_size;
if(fwrite(blank, sizeof(char), to_write, f) != to_write)
goto fail;
}
// bootimg size (abootimg compatibility)
if(b->size != 0)
{
if((int)b->size < ftell(f))
{
res = -EFBIG;
remove(dest);
goto exit;
}
to_write = (b->size - ftell(f))/b->hdr.page_size;
for(i = 0; i < to_write; ++i)
if(fwrite(blank, sizeof(char), b->hdr.page_size, f) != b->hdr.page_size)
goto fail;
to_write = (b->size - ftell(f))%b->hdr.page_size;
if(fwrite(blank, sizeof(char), to_write, f) != to_write)
goto fail;
}
goto exit;
fail:
res = -errno;
remove(dest);
exit:
fclose(f);
free(blank);
return res;
}
int libbootimg_write_img_and_destroy(struct bootimg *b, const char *dest)
{
int res = libbootimg_write_img(b, dest);
libbootimg_destroy(b);
return res;
}
int libbootimg_load_config(struct bootimg *b, const char *src, int *error_line)
{
FILE *f = fopen(src, "r");
if(!f)
return -errno;
int res = 0;
int line_num = 0;
char line[1024];
while(fgets(line, sizeof(line), f))
{
if(libbootimg_load_config_line(b, line) < 0)
{
res = -1;
if(error_line)
*error_line = line_num;
goto exit;
}
++line_num;
}
exit:
fclose(f);
return res;
}
int libbootimg_load_config_line(struct bootimg *b, char *line)
{
char *s, *e;
char *name_e;
char *arg_s;
size_t n_to_cmp;
for(s = line; isspace(*s); ++s);
for(e = s+strlen(s)-1; isspace(*e); --e)
*e = 0;
if(*s == 0 || (name_e = strchr(s, '=')) == NULL)
return 0;
arg_s = name_e+1;
for(--name_e; isspace(*name_e); --name_e);
for(++arg_s; isspace(*arg_s); ++arg_s);
n_to_cmp = name_e-s;
if(strncmp("bootsize", s, n_to_cmp) == 0)
b->size = strtol(arg_s, NULL, 16);
else if(strncmp("pagesize", s, n_to_cmp) == 0)
b->hdr.page_size = strtol(arg_s, NULL, 16);
else if(strncmp("kerneladdr", s, n_to_cmp) == 0)
b->hdr.kernel_addr = strtol(arg_s, NULL, 16);
else if(strncmp("ramdiskaddr", s, n_to_cmp) == 0)
b->hdr.ramdisk_addr = strtol(arg_s, NULL, 16);
else if(strncmp("secondaddr", s, n_to_cmp) == 0)
b->hdr.second_addr = strtol(arg_s, NULL, 16);
else if(strncmp("tagsaddr", s, n_to_cmp) == 0)
b->hdr.tags_addr = strtol(arg_s, NULL, 16);
else if(strncmp("name", s, n_to_cmp) == 0)
strncpy((char*)b->hdr.name, arg_s, BOOT_NAME_SIZE);
else if(strncmp("cmdline", s, n_to_cmp) == 0)
strncpy((char*)b->hdr.cmdline, arg_s, BOOT_ARGS_SIZE);
else
return -1;
return 0;
}
int libbootimg_write_config(struct bootimg *b, const char *dst)
{
FILE *f = fopen(dst, "w");
if(!f)
return -errno;
int res = fprintf(f,
"bootsize = 0x%X\n"
"pagesize = 0x%X\n"
"kerneladdr = 0x%X\n"
"ramdiskaddr = 0x%X\n"
"secondaddr = 0x%X\n"
"tagsaddr = 0x%X\n"
"name = %s\n"
"cmdline = %s\n",
b->size, b->hdr.page_size, b->hdr.kernel_addr, b->hdr.ramdisk_addr,
b->hdr.second_addr, b->hdr.tags_addr, b->hdr.name, b->hdr.cmdline);
fclose(f);
return res;
}
uint32_t libbootimg_version(void)
{
return VERSION;
}
const char *libbootimg_version_str(void)
{
return VERSION_STR;
}

40
libbootimg.h Normal file
View File

@@ -0,0 +1,40 @@
#ifndef LIBBOOTIMG_H
#define LIBBOOTIMG_h
#include <stdint.h>
#include "boot_img_hdr.h"
struct bootimg
{
struct boot_img_hdr hdr;
uint8_t *kernel;
uint8_t *ramdisk;
uint8_t *second;
uint32_t size;
};
void libbootimg_init_new(struct bootimg *img);
int libbootimg_init_load(struct bootimg *img, const char *path);
void libbootimg_destroy(struct bootimg *b);
int libbootimg_load_header(struct boot_img_hdr *hdr, const char *path);
int libbootimg_dump_kernel(struct bootimg *b, const char *dest);
int libbootimg_dump_ramdisk(struct bootimg *b, const char *dest);
int libbootimg_dump_second(struct bootimg *b, const char *dest);
int libbootimg_dump(struct bootimg *b, const char *dest_dir);
int libbootimg_load_kernel(struct bootimg *b, const char *src);
int libbootimg_load_ramdisk(struct bootimg *b, const char *src);
int libbootimg_load_second(struct bootimg *b, const char *src);
int libbootimg_write_img(struct bootimg *b, const char *dest);
int libbootimg_write_img_and_destroy(struct bootimg *b, const char *dest);
int libbootimg_load_config(struct bootimg *b, const char *src, int *error_line);
int libbootimg_load_config_line(struct bootimg *b, char *line);
int libbootimg_write_config(struct bootimg *b, const char *dst);
uint32_t libbootimg_version(void);
const char *libbootimg_version_str(void);
#endif

5
version.h Normal file
View File

@@ -0,0 +1,5 @@
#ifndef VERSION_H
#define VERSION_H
#define VERSION 0x000100 // 0xMMNNPP
#define VERSION_STR "0.1.0"
#endif