initial commit

pull/1/head
cfig 9 years ago
parent e5ae389b48
commit 3fb9a9398a

@ -0,0 +1,93 @@
.DEFAULT_GOAL := flat
SHELL := /bin/bash
WORK_DIR := unzip_boot
help:
@echo "flat : boot.subimg -> unzip_boot/*"
@echo "boot.img : unsigned boot image"
@echo "boot.subimg : signed boot image"
@echo "addon : (recovery only) add additional tools"
.PHONY: flat
flat:
rm -fr $(WORK_DIR)
mkdir -p $(WORK_DIR)/root
abootimg -x boot.subimg $(WORK_DIR)/bootimg.cfg $(this_kernel) $(this_ramdisk).gz
gzip -c -d $(this_ramdisk).gz > $(this_ramdisk)
rm $(this_ramdisk).gz
cd $(WORK_DIR)/root && \
cpio -i -F ../ramdisk.img
@rm $(WORK_DIR)/ramdisk.img
@echo && echo "===================================" && file $(WORK_DIR)/* && echo "==================================="
kernel_cmdline := "$(shell grep -Po '(?<=cmdline = ).*' $(WORK_DIR)/bootimg.cfg)"
this_root := $(WORK_DIR)/root
this_kernel := $(WORK_DIR)/kernel
this_ramdisk := $(WORK_DIR)/ramdisk.img
ifeq '$(TARGET_PRODUCT)' ''
$(warning NON-android)
this_verity_key := tools/security/verity
else
$(warning android)
this_verity_key := build/target/product/security/verity
endif
.INTERMEDIATE: $(this_ramdisk).gz boot.img
$(this_ramdisk).gz: $(this_root)
mkbootfs $< | gzip > $@
boot.img: $(this_ramdisk).gz $(this_kernel)
mkbootimg \
--kernel $(this_kernel) \
--ramdisk $(this_ramdisk).gz \
--cmdline "$(shell echo $(kernel_cmdline))" \
--base 0x01000000 \
--output $@
boot.subimg: boot.img
$(call signer,/boot,$<,$@)
define signer
boot_signer $(1) $(2) $(this_verity_key).pk8 $(this_verity_key).x509.pem $(3)
endef
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
real_mkfile_path := $(shell readlink $(mkfile_path))
libs := libc.so libcrypto.so libcutils.so libm.so libselinux.so libstdc++.so libpcre.so liblog.so libnetutils.so libsysutils.so libutils.so libbacktrace.so libstlport.so libgccdemangle.so libunwind.so libunwind-ptrace.so
bins := toolbox sh linker netcfg logd logcat
addon: | unzip_boot/root/system/bin
addon: | unzip_boot/root/system/lib
addon: INITRC := unzip_boot/root/init.recovery.marvellberlin.rc
addon:
#initrc
echo "service console /system/bin/sh" > $(INITRC)
echo " console" >> $(INITRC)
echo " user root" >> $(INITRC)
echo " group root" >> $(INITRC)
echo >> $(INITRC)
echo "service logd /system/bin/logd" >> $(INITRC)
echo " socket logd stream 0666 logd logd" >> $(INITRC)
echo " socket logdr seqpacket 0666 logd logd" >> $(INITRC)
echo " socket logdw dgram 0222 logd logd" >> $(INITRC)
echo " seclabel u:r:logd:s0" >> $(INITRC)
#recovery
#cp out/target/product/$(TARGET_PRODUCT)/system/bin/recovery unzip_boot/root/sbin/
#@cp -v out/target/product/$(TARGET_PRODUCT)/obj/EXECUTABLES/recovery_intermediates/recovery unzip_boot/root/sbin/
#bin
@$(foreach item,$(bins), \
cp -v out/target/product/$(TARGET_PRODUCT)/system/bin/$(item) unzip_boot/root/system/bin/; $(newline))
#lib
@$(foreach item,$(libs), \
cp -v out/target/product/$(TARGET_PRODUCT)/system/lib/$(item) unzip_boot/root/system/lib/; $(newline))
#@cp -v out/target/product/$(TARGET_PRODUCT)/system/etc/sepolicy.recovery unzip_boot/root/sepolicy
@cp -v out/target/product/$(TARGET_PRODUCT)/obj/ETC/sepolicy.recovery_intermediates/sepolicy.recovery unzip_boot/root/sepolicy
unzip_boot/root/system/bin:
mkdir $@
unzip_boot/root/system/lib:
mkdir $@
#service console /system/bin/sh
# console
# user root
# group root

@ -0,0 +1,71 @@
apply plugin: 'c'
apply plugin: 'java'
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
model {
buildTypes {
release
}
components {
abootimg(NativeExecutableSpec) {
binaries.all {
cppCompiler.define 'HAS_BLKID'
linker.args '-lblkid'
}
}
}
components {
mkbootfs(NativeExecutableSpec) {
binaries.all {
}
}
}
}
def workdir='unzip_boot'
task unpack_bootimg(type: Exec, dependsOn: 'abootimgExecutable') {
new File(workdir + '/root').mkdirs()
workingDir '.'
executable 'build/exe/abootimg/abootimg'
args = ['-x', 'boot.img', workdir+'/bootimg.cfg', workdir+'/kernel', workdir+'/ramdisk.img.gz']
}
task unpack_ramdisk_gz << {
unGunzipFile(workdir+"/ramdisk.img.gz", workdir + "/ramdisk.img")
}
unpack_ramdisk_gz.dependsOn(unpack_bootimg)
task unpack_cpio(type: Exec, dependsOn: unpack_ramdisk_gz) {
workingDir workdir + "/root"
executable 'cpio'
args = ['-i', '-F', '../ramdisk.img']
}
public void unGunzipFile(String compressedFile, String decompressedFile) throws IOException {
byte[] buffer = new byte[1024];
try {
FileInputStream fileIn = new FileInputStream(compressedFile);
GZIPInputStream gZIPInputStream = new GZIPInputStream(fileIn);
FileOutputStream fileOutputStream = new FileOutputStream(decompressedFile);
int bytes_read;
while ((bytes_read = gZIPInputStream.read(buffer)) > 0) {
fileOutputStream.write(buffer, 0, bytes_read);
}
gZIPInputStream.close();
fileOutputStream.close();
System.out.println("The file was decompressed successfully!");
} catch (IOException ex) {
throw ex;
}
}
task unpack(type: Delete, dependsOn: unpack_cpio) {
delete workdir + "/ramdisk.img.gz"
}

@ -0,0 +1,952 @@
/* abootimg - Manipulate (read, modify, create) Android Boot Images
* Copyright (c) 2010-2011 Gilles Grandou <gilles@grandou.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef __linux__
#include <sys/ioctl.h>
#include <linux/fs.h> /* BLKGETSIZE64 */
#endif
#ifdef __CYGWIN__
#include <sys/ioctl.h>
#include <cygwin/fs.h> /* BLKGETSIZE64 */
#endif
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include <sys/disk.h> /* DIOCGMEDIASIZE */
#include <sys/sysctl.h>
#endif
#if defined(__APPLE__)
# include <sys/disk.h> /* DKIOCGETBLOCKCOUNT */
#endif
#ifdef HAS_BLKID
#include <blkid/blkid.h>
#endif
#include "version.h"
#include "bootimg.h"
enum command {
none,
help,
info,
extract,
update,
create
};
typedef struct
{
unsigned size;
int is_blkdev;
char* fname;
char* config_fname;
char* kernel_fname;
char* ramdisk_fname;
char* second_fname;
FILE* stream;
boot_img_hdr header;
char* kernel;
char* ramdisk;
char* second;
} t_abootimg;
#define MAX_CONF_LEN 4096
char config_args[MAX_CONF_LEN] = "";
void abort_perror(char* str)
{
perror(str);
exit(errno);
}
void abort_printf(char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "\n");
exit(1);
}
int blkgetsize(int fd, unsigned long long *pbsize)
{
# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
return ioctl(fd, DIOCGMEDIASIZE, pbsize);
# elif defined(__APPLE__)
return ioctl(fd, DKIOCGETBLOCKCOUNT, pbsize);
# elif defined(__NetBSD__)
// does a suitable ioctl exist?
// return (ioctl(fd, DIOCGDINFO, &label) == -1);
return 1;
# elif defined(__linux__) || defined(__CYGWIN__)
return ioctl(fd, BLKGETSIZE64, pbsize);
# elif defined(__GNU__)
// does a suitable ioctl for HURD exist?
return 1;
# else
return 1;
# endif
}
void print_usage(void)
{
printf (
" abootimg - manipulate Android Boot Images.\n"
" (c) 2010-2011 Gilles Grandou <gilles@grandou.net>\n"
" " VERSION_STR "\n"
"\n"
" abootimg [-h]\n"
"\n"
" print usage\n"
"\n"
" abootimg -i <bootimg>\n"
"\n"
" print boot image information\n"
"\n"
" abootimg -x <bootimg> [<bootimg.cfg> [<kernel> [<ramdisk> [<secondstage>]]]]\n"
"\n"
" extract objects from boot image:\n"
" - config file (default name bootimg.cfg)\n"
" - kernel image (default name zImage)\n"
" - ramdisk image (default name initrd.img)\n"
" - second stage image (default name stage2.img)\n"
"\n"
" abootimg -u <bootimg> [-c \"param=value\"] [-f <bootimg.cfg>] [-k <kernel>] [-r <ramdisk>] [-s <secondstage>]\n"
"\n"
" update a 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"
" bootimg has to be valid Android Boot Image, or the update will abort.\n"
"\n"
" abootimg --create <bootimg> [-c \"param=value\"] [-f <bootimg.cfg>] -k <kernel> -r <ramdisk> [-s <secondstage>]\n"
"\n"
" create a new image from scratch.\n"
" if the boot image file is a block device, sanity check will be performed to avoid overwriting a existing\n"
" filesystem.\n"
"\n"
" argurments are the same than for -u.\n"
" kernel and ramdisk are mandatory.\n"
"\n"
);
}
enum command parse_args(int argc, char** argv, t_abootimg* img)
{
enum command cmd = none;
int i;
if (argc<2)
return none;
if (!strcmp(argv[1], "-h")) {
return help;
}
else if (!strcmp(argv[1], "-i")) {
cmd=info;
}
else if (!strcmp(argv[1], "-x")) {
cmd=extract;
}
else if (!strcmp(argv[1], "-u")) {
cmd=update;
}
else if (!strcmp(argv[1], "--create")) {
cmd=create;
}
else
return none;
switch(cmd) {
case none:
case help:
break;
case info:
if (argc != 3)
return none;
img->fname = argv[2];
break;
case extract:
if ((argc < 3) || (argc > 7))
return none;
img->fname = argv[2];
if (argc >= 4)
img->config_fname = argv[3];
if (argc >= 5)
img->kernel_fname = argv[4];
if (argc >= 6)
img->ramdisk_fname = argv[5];
if (argc >= 7)
img->second_fname = argv[6];
break;
case update:
case create:
if (argc < 3)
return none;
img->fname = argv[2];
img->config_fname = NULL;
img->kernel_fname = NULL;
img->ramdisk_fname = NULL;
img->second_fname = NULL;
for(i=3; i<argc; i++) {
if (!strcmp(argv[i], "-c")) {
if (++i >= argc)
return none;
unsigned len = strlen(argv[i]);
if (strlen(config_args)+len+1 >= MAX_CONF_LEN)
abort_printf("too many config parameters.\n");
strcat(config_args, argv[i]);
strcat(config_args, "\n");
}
else if (!strcmp(argv[i], "-f")) {
if (++i >= argc)
return none;
img->config_fname = argv[i];
}
else if (!strcmp(argv[i], "-k")) {
if (++i >= argc)
return none;
img->kernel_fname = argv[i];
}
else if (!strcmp(argv[i], "-r")) {
if (++i >= argc)
return none;
img->ramdisk_fname = argv[i];
}
else if (!strcmp(argv[i], "-s")) {
if (++i >= argc)
return none;
img->second_fname = argv[i];
}
else
return none;
}
break;
}
return cmd;
}
int check_boot_img_header(t_abootimg* img)
{
if (strncmp((char*)(img->header.magic), BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
fprintf(stderr, "%s: no Android Magic Value\n", img->fname);
return 1;
}
if (!(img->header.kernel_size)) {
fprintf(stderr, "%s: kernel size is null\n", img->fname);
return 1;
}
if (!(img->header.ramdisk_size)) {
fprintf(stderr, "%s: ramdisk size is null\n", img->fname);
return 1;
}
unsigned page_size = img->header.page_size;
if (!page_size) {
fprintf(stderr, "%s: Image page size is null\n", img->fname);
return 1;
}
unsigned n = (img->header.kernel_size + page_size - 1) / page_size;
unsigned m = (img->header.ramdisk_size + page_size - 1) / page_size;
unsigned o = (img->header.second_size + page_size - 1) / page_size;
unsigned total_size = (1+n+m+o)*page_size;
if (total_size > img->size) {
fprintf(stderr, "%s: sizes mismatches in boot image\n", img->fname);
return 1;
}
return 0;
}
void check_if_block_device(t_abootimg* img)
{
struct stat st;
if (stat(img->fname, &st))
if (errno != ENOENT) {
printf("errno=%d\n", errno);
abort_perror(img->fname);
}
#ifdef HAS_BLKID
if (S_ISBLK(st.st_mode)) {
img->is_blkdev = 1;
char* type = blkid_get_tag_value(NULL, "TYPE", img->fname);
if (type)
abort_printf("%s: refuse to write on a valid partition type (%s)\n", img->fname, type);
int fd = open(img->fname, O_RDONLY);
if (fd == -1)
abort_perror(img->fname);
unsigned long long bsize = 0;
if (blkgetsize(fd, &bsize))
abort_perror(img->fname);
img->size = bsize;
close(fd);
}
#endif
}
void open_bootimg(t_abootimg* img, char* mode)
{
img->stream = fopen(img->fname, mode);
if (!img->stream)
abort_perror(img->fname);
}
void read_header(t_abootimg* img)
{
size_t rb = fread(&img->header, sizeof(boot_img_hdr), 1, img->stream);
if ((rb!=1) || ferror(img->stream))
abort_perror(img->fname);
else if (feof(img->stream))
abort_printf("%s: cannot read image header\n", img->fname);
struct stat s;
int fd = fileno(img->stream);
if (fstat(fd, &s))
abort_perror(img->fname);
if (S_ISBLK(s.st_mode)) {
unsigned long long bsize = 0;
if (blkgetsize(fd, &bsize))
abort_perror(img->fname);
img->size = bsize;
img->is_blkdev = 1;
}
else {
img->size = s.st_size;
img->is_blkdev = 0;
}
if (check_boot_img_header(img))
abort_printf("%s: not a valid Android Boot Image.\n", img->fname);
}
void update_header_entry(t_abootimg* img, char* cmd)
{
char *p;
char *token;
char *endtoken;
char *value;
p = strchr(cmd, '\n');
if (p)
*p = '\0';
p = cmd;
p += strspn(p, " \t");
token = p;
p += strcspn(p, " =\t");
endtoken = p;
p += strspn(p, " \t");
if (*p++ != '=')
goto err;
p += strspn(p, " \t");
value = p;
*endtoken = '\0';
unsigned valuenum = strtoul(value, NULL, 0);
if (!strcmp(token, "cmdline")) {
unsigned len = strlen(value);
if (len >= BOOT_ARGS_SIZE)
abort_printf("cmdline length (%d) is too long (max %d)", len, BOOT_ARGS_SIZE-1);
memset(img->header.cmdline, 0, BOOT_ARGS_SIZE);
strcpy((char*)(img->header.cmdline), value);
}
else if (!strncmp(token, "name", 4)) {
strncpy((char*)(img->header.name), value, BOOT_NAME_SIZE);
img->header.name[BOOT_NAME_SIZE-1] = '\0';
}
else if (!strncmp(token, "bootsize", 8)) {
if (img->is_blkdev && (img->size != valuenum))
abort_printf("%s: cannot change Boot Image size for a block device\n", img->fname);
img->size = valuenum;
}
else if (!strncmp(token, "pagesize", 8)) {
img->header.page_size = valuenum;
}
else if (!strncmp(token, "kerneladdr", 10)) {
img->header.kernel_addr = valuenum;
}
else if (!strncmp(token, "ramdiskaddr", 11)) {
img->header.ramdisk_addr = valuenum;
}
else if (!strncmp(token, "secondaddr", 10)) {
img->header.second_addr = valuenum;
}
else if (!strncmp(token, "tagsaddr", 8)) {
img->header.tags_addr = valuenum;
}
else
goto err;
return;
err:
abort_printf("%s: bad config entry\n", token);
}
void update_header(t_abootimg* img)
{
if (img->config_fname) {
FILE* config_file = fopen(img->config_fname, "r");
if (!config_file)
abort_perror(img->config_fname);
printf("reading config file %s\n", img->config_fname);
char* line = NULL;
size_t len = 0;
int read;
while ((read = getline(&line, &len, config_file)) != -1) {
update_header_entry(img, line);
free(line);
line = NULL;
}
if (ferror(config_file))
abort_perror(img->config_fname);
}
unsigned len = strlen(config_args);
if (len) {
FILE* config_file = fmemopen(config_args, len, "r");
if (!config_file)
abort_perror("-c args");
printf("reading config args\n");
char* line = NULL;
size_t len = 0;
int read;
while ((read = getline(&line, &len, config_file)) != -1) {
update_header_entry(img, line);
free(line);
line = NULL;
}
if (ferror(config_file))
abort_perror("-c args");
}
}
void update_images(t_abootimg *img)
{
unsigned page_size = img->header.page_size;
unsigned ksize = img->header.kernel_size;
unsigned rsize = img->header.ramdisk_size;
unsigned ssize = img->header.second_size;
if (!page_size)
abort_printf("%s: Image page size is null\n", img->fname);
unsigned n = (ksize + page_size - 1) / page_size;
unsigned m = (rsize + page_size - 1) / page_size;
unsigned o = (ssize + page_size - 1) / page_size;
unsigned roffset = (1+n)*page_size;
unsigned soffset = (1+n+m)*page_size;
if (img->kernel_fname) {
printf("reading kernel from %s\n", img->kernel_fname);
FILE* stream = fopen(img->kernel_fname, "r");
if (!stream)
abort_perror(img->kernel_fname);
struct stat st;
if (fstat(fileno(stream), &st))
abort_perror(img->kernel_fname);
ksize = st.st_size;
char* k = malloc(ksize);
if (!k)
abort_perror("");
size_t rb = fread(k, ksize, 1, stream);
if ((rb!=1) || ferror(stream))
abort_perror(img->kernel_fname);
else if (feof(stream))
abort_printf("%s: cannot read kernel\n", img->kernel_fname);
fclose(stream);
img->header.kernel_size = ksize;
img->kernel = k;
}
if (img->ramdisk_fname) {
printf("reading ramdisk from %s\n", img->ramdisk_fname);
FILE* stream = fopen(img->ramdisk_fname, "r");
if (!stream)
abort_perror(img->ramdisk_fname);
struct stat st;
if (fstat(fileno(stream), &st))
abort_perror(img->ramdisk_fname);
rsize = st.st_size;
char* r = malloc(rsize);
if (!r)
abort_perror("");
size_t rb = fread(r, rsize, 1, stream);
if ((rb!=1) || ferror(stream))
abort_perror(img->ramdisk_fname);
else if (feof(stream))
abort_printf("%s: cannot read ramdisk\n", img->ramdisk_fname);
fclose(stream);
img->header.ramdisk_size = rsize;
img->ramdisk = r;
}
else if (img->kernel) {
// if kernel is updated, copy the ramdisk from original image
char* r = malloc(rsize);
if (!r)
abort_perror("");
if (fseek(img->stream, roffset, SEEK_SET))
abort_perror(img->fname);
size_t rb = fread(r, rsize, 1, img->stream);
if ((rb!=1) || ferror(img->stream))
abort_perror(img->fname);
else if (feof(img->stream))
abort_printf("%s: cannot read ramdisk\n", img->fname);
img->ramdisk = r;
}
if (img->second_fname) {
printf("reading second stage from %s\n", img->second_fname);
FILE* stream = fopen(img->second_fname, "r");
if (!stream)
abort_perror(img->second_fname);
struct stat st;
if (fstat(fileno(stream), &st))
abort_perror(img->second_fname);
ssize = st.st_size;
char* s = malloc(ssize);
if (!s)
abort_perror("");
size_t rb = fread(s, ssize, 1, stream);
if ((rb!=1) || ferror(stream))
abort_perror(img->second_fname);
else if (feof(stream))
abort_printf("%s: cannot read second stage\n", img->second_fname);
fclose(stream);
img->header.second_size = ssize;
img->second = s;
}
else if (img->ramdisk && img->header.second_size) {
// if ramdisk is updated, copy the second stage from original image
char* s = malloc(ssize);
if (!s)
abort_perror("");
if (fseek(img->stream, soffset, SEEK_SET))
abort_perror(img->fname);
size_t rb = fread(s, ssize, 1, img->stream);
if ((rb!=1) || ferror(img->stream))
abort_perror(img->fname);
else if (feof(img->stream))
abort_printf("%s: cannot read second stage\n", img->fname);
img->second = s;
}
n = (img->header.kernel_size + page_size - 1) / page_size;
m = (img->header.ramdisk_size + page_size - 1) / page_size;
o = (img->header.second_size + page_size - 1) / page_size;
unsigned total_size = (1+n+m+o)*page_size;
if (!img->size)
img->size = total_size;
else if (total_size > img->size)
abort_printf("%s: updated is too big for the Boot Image (%u vs %u bytes)\n", img->fname, total_size, img->size);
}
void write_bootimg(t_abootimg* img)
{
unsigned psize;
char* padding;
printf ("Writing Boot Image %s\n", img->fname);
psize = img->header.page_size;
padding = calloc(psize, 1);
if (!padding)
abort_perror("");
unsigned n = (img->header.kernel_size + psize - 1) / psize;
unsigned m = (img->header.ramdisk_size + psize - 1) / psize;
//unsigned o = (img->header.second_size + psize - 1) / psize;
if (fseek(img->stream, 0, SEEK_SET))
abort_perror(img->fname);
fwrite(&img->header, sizeof(img->header), 1, img->stream);
if (ferror(img->stream))
abort_perror(img->fname);
fwrite(padding, psize - sizeof(img->header), 1, img->stream);
if (ferror(img->stream))
abort_perror(img->fname);
if (img->kernel) {
fwrite(img->kernel, img->header.kernel_size, 1, img->stream);
if (ferror(img->stream))
abort_perror(img->fname);
fwrite(padding, psize - (img->header.kernel_size % psize), 1, img->stream);
if (ferror(img->stream))
abort_perror(img->fname);
}
if (img->ramdisk) {
if (fseek(img->stream, (1+n)*psize, SEEK_SET))
abort_perror(img->fname);
fwrite(img->ramdisk, img->header.ramdisk_size, 1, img->stream);
if (ferror(img->stream))
abort_perror(img->fname);
fwrite(padding, psize - (img->header.ramdisk_size % psize), 1, img->stream);
if (ferror(img->stream))
abort_perror(img->fname);
}
if (img->header.second_size) {
if (fseek(img->stream, (1+n+m)*psize, SEEK_SET))
abort_perror(img->fname);
fwrite(img->second, img->header.second_size, 1, img->stream);
if (ferror(img->stream))
abort_perror(img->fname);
fwrite(padding, psize - (img->header.second_size % psize), 1, img->stream);
if (ferror(img->stream))
abort_perror(img->fname);
}
ftruncate (fileno(img->stream), img->size);
free(padding);
}
void print_bootimg_info(t_abootimg* img)
{
printf ("\nAndroid Boot Image Info:\n\n");
printf ("* file name = %s %s\n\n", img->fname, img->is_blkdev ? "[block device]":"");
printf ("* image size = %u bytes (%.2f MB)\n", img->size, (double)img->size/0x100000);
printf (" page size = %u bytes\n\n", img->header.page_size);
printf ("* Boot Name = \"%s\"\n\n", img->header.name);
unsigned kernel_size = img->header.kernel_size;
unsigned ramdisk_size = img->header.ramdisk_size;
unsigned second_size = img->header.second_size;
printf ("* kernel size = %u bytes (%.2f MB)\n", kernel_size, (double)kernel_size/0x100000);
printf (" ramdisk size = %u bytes (%.2f MB)\n", ramdisk_size, (double)ramdisk_size/0x100000);
if (second_size)
printf (" second stage size = %u bytes (%.2f MB)\n", ramdisk_size, (double)ramdisk_size/0x100000);
printf ("\n* load addresses:\n");
printf (" kernel: 0x%08x\n", img->header.kernel_addr);
printf (" ramdisk: 0x%08x\n", img->header.ramdisk_addr);
if (second_size)
printf (" second stage: 0x%08x\n", img->header.second_addr);
printf (" tags: 0x%08x\n\n", img->header.tags_addr);
if (img->header.cmdline[0])
printf ("* cmdline = %s\n\n", img->header.cmdline);
else
printf ("* empty cmdline\n");
printf ("* id = ");
int i;
for (i=0; i<8; i++)
printf ("0x%08x ", img->header.id[i]);
printf ("\n\n");
}
void write_bootimg_config(t_abootimg* img)
{
printf ("writing boot image config in %s\n", img->config_fname);
FILE* config_file = fopen(img->config_fname, "w");
if (!config_file)
abort_perror(img->config_fname);
fprintf(config_file, "bootsize = 0x%x\n", img->size);
fprintf(config_file, "pagesize = 0x%x\n", img->header.page_size);
fprintf(config_file, "kerneladdr = 0x%x\n", img->header.kernel_addr);
fprintf(config_file, "ramdiskaddr = 0x%x\n", img->header.ramdisk_addr);
fprintf(config_file, "secondaddr = 0x%x\n", img->header.second_addr);
fprintf(config_file, "tagsaddr = 0x%x\n", img->header.tags_addr);
fprintf(config_file, "name = %s\n", img->header.name);
fprintf(config_file, "cmdline = %s\n", img->header.cmdline);
fclose(config_file);
}
void extract_kernel(t_abootimg* img)
{
unsigned psize = img->header.page_size;
unsigned ksize = img->header.kernel_size;
printf ("extracting kernel in %s\n", img->kernel_fname);
void* k = malloc(ksize);
if (!k)
abort_perror(NULL);
if (fseek(img->stream, psize, SEEK_SET))
abort_perror(img->fname);
size_t rb = fread(k, ksize, 1, img->stream);
if ((rb!=1) || ferror(img->stream))
abort_perror(img->fname);
FILE* kernel_file = fopen(img->kernel_fname, "w");
if (!kernel_file)
abort_perror(img->kernel_fname);
fwrite(k, ksize, 1, kernel_file);
if (ferror(kernel_file))
abort_perror(img->kernel_fname);
fclose(kernel_file);
free(k);
}
void extract_ramdisk(t_abootimg* img)
{
unsigned psize = img->header.page_size;
unsigned ksize = img->header.kernel_size;
unsigned rsize = img->header.ramdisk_size;
unsigned n = (ksize + psize - 1) / psize;
unsigned roffset = (1+n)*psize;
printf ("extracting ramdisk in %s\n", img->ramdisk_fname);
void* r = malloc(rsize);
if (!r)
abort_perror(NULL);
if (fseek(img->stream, roffset, SEEK_SET))
abort_perror(img->fname);
size_t rb = fread(r, rsize, 1, img->stream);
if ((rb!=1) || ferror(img->stream))
abort_perror(img->fname);
FILE* ramdisk_file = fopen(img->ramdisk_fname, "w");
if (!ramdisk_file)
abort_perror(img->ramdisk_fname);
fwrite(r, rsize, 1, ramdisk_file);
if (ferror(ramdisk_file))
abort_perror(img->ramdisk_fname);
fclose(ramdisk_file);
free(r);
}
void extract_second(t_abootimg* img)
{
unsigned psize = img->header.page_size;
unsigned ksize = img->header.kernel_size;
unsigned rsize = img->header.ramdisk_size;
unsigned ssize = img->header.second_size;
if (!ssize) // Second Stage not present
return;
unsigned n = (rsize + ksize + psize - 1) / psize;
unsigned soffset = (1+n)*psize;
printf ("extracting second stage image in %s\n", img->second_fname);
void* s = malloc(ksize);
if (!s)
abort_perror(NULL);
if (fseek(img->stream, soffset, SEEK_SET))
abort_perror(img->fname);
size_t rb = fread(s, ssize, 1, img->stream);
if ((rb!=1) || ferror(img->stream))
abort_perror(img->fname);
FILE* second_file = fopen(img->second_fname, "w");
if (!second_file)
abort_perror(img->second_fname);
fwrite(s, ssize, 1, second_file);
if (ferror(second_file))
abort_perror(img->second_fname);
fclose(second_file);
free(s);
}
t_abootimg* new_bootimg()
{
t_abootimg* img;
img = calloc(sizeof(t_abootimg), 1);
if (!img)
abort_perror(NULL);
img->config_fname = "bootimg.cfg";
img->kernel_fname = "zImage";
img->ramdisk_fname = "initrd.img";
img->second_fname = "stage2.img";
memcpy(img->header.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
img->header.page_size = 2048; // a sensible default page size
return img;
}
int main(int argc, char** argv)
{
t_abootimg* bootimg = new_bootimg();
switch(parse_args(argc, argv, bootimg))
{
case none:
printf("error - bad arguments\n\n");
print_usage();
break;
case help:
print_usage();
break;
case info:
open_bootimg(bootimg, "r");
read_header(bootimg);
print_bootimg_info(bootimg);
break;
case extract:
open_bootimg(bootimg, "r");
read_header(bootimg);
write_bootimg_config(bootimg);
extract_kernel(bootimg);
extract_ramdisk(bootimg);
extract_second(bootimg);
break;
case update:
open_bootimg(bootimg, "r+");
read_header(bootimg);
update_header(bootimg);
update_images(bootimg);
write_bootimg(bootimg);
break;
case create:
if (!bootimg->kernel_fname || !bootimg->ramdisk_fname) {
print_usage();
break;
}
check_if_block_device(bootimg);
open_bootimg(bootimg, "w");
update_header(bootimg);
update_images(bootimg);
if (check_boot_img_header(bootimg))
abort_printf("%s: Sanity cheks failed", bootimg->fname);
write_bootimg(bootimg);
break;
}
return 0;
}

@ -0,0 +1,97 @@
/* tools/mkbootimg/bootimg.h
**
** Copyright 2007, 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_IMAGE_H_
#define _BOOT_IMAGE_H_
typedef struct boot_img_hdr boot_img_hdr;
#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 */
};
/*
** +-----------------+
** | 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
*/
#if 0
typedef struct ptentry ptentry;
struct ptentry {
char name[16]; /* asciiz partition name */
unsigned start; /* starting block number */
unsigned length; /* length in blocks */
unsigned flags; /* set to zero */
};
/* MSM Partition Table ATAG
**
** length: 2 + 7 * n
** atag: 0x4d534d70
** <ptentry> x n
*/
#endif
#endif

@ -0,0 +1,2 @@
//https://gitorious.org/ac100/abootimg
#define VERSION_STR "gitorious-7e127fee6a3981f6b0a50ce9910267cd501e09d4"

Binary file not shown.

Binary file not shown.

@ -0,0 +1,288 @@
/*
* Copyright (C) 2007 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.
*/
/* This file is used to define the properties of the filesystem
** images generated by build tools (mkbootfs and mkyaffs2image) and
** by the device side of adb.
*/
#define LOG_TAG "fs_config"
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <private/android_filesystem_config.h>
#ifndef O_BINARY
#define O_BINARY 0
#endif
#define ALOGE printf
/* Used to retry syscalls that can return EINTR. */
#define TEMP_FAILURE_RETRY(exp) ({ \
__typeof__(exp) _rc; \
do { \
_rc = (exp); \
} while (_rc == -1 && errno == EINTR); \
_rc; })
/* The following structure is stored little endian */
struct fs_path_config_from_file {
uint16_t len;
uint16_t mode;
uint16_t uid;
uint16_t gid;
uint64_t capabilities;
char prefix[];
} __attribute__((__aligned__(sizeof(uint64_t))));
/* My kingdom for <endian.h> */
static inline uint16_t get2LE(const uint8_t* src)
{
return src[0] | (src[1] << 8);
}
static inline uint64_t get8LE(const uint8_t* src)
{
uint32_t low, high;
low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
return ((uint64_t) high << 32) | (uint64_t) low;
}
#define ALIGN(x, alignment) ( ((x) + ((alignment) - 1)) & ~((alignment) - 1) )
/* Rules for directories.
** These rules are applied based on "first match", so they
** should start with the most specific path and work their
** way up to the root.
*/
static const struct fs_path_config android_dirs[] = {
{ 00770, AID_SYSTEM, AID_CACHE, 0, "cache" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" },
{ 00771, AID_ROOT, AID_ROOT, 0, "data/dalvik-cache" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" },
{ 00771, AID_SHELL, AID_SHELL, 0, "data/local/tmp" },
{ 00771, AID_SHELL, AID_SHELL, 0, "data/local" },
{ 01771, AID_SYSTEM, AID_MISC, 0, "data/misc" },
{ 00770, AID_DHCP, AID_DHCP, 0, "data/misc/dhcp" },
{ 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" },
{ 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" },
{ 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
{ 00750, AID_ROOT, AID_SHELL, 0, "sbin" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/vendor" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/xbin" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/etc/ppp" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor" },
{ 00777, AID_ROOT, AID_ROOT, 0, "sdcard" },
{ 00755, AID_ROOT, AID_ROOT, 0, 0 },
};
/* Rules for files.
** These rules are applied based on "first match", so they
** should start with the most specific path and work their
** way up to the root. Prefixes ending in * denotes wildcard
** and will allow partial matches.
*/
static const char conf_dir[] = "/system/etc/fs_config_dirs";
static const char conf_file[] = "/system/etc/fs_config_files";
static const struct fs_path_config android_files[] = {
{ 00440, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.rc" },
{ 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.sh" },
{ 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.ril" },
{ 00550, AID_DHCP, AID_SHELL, 0, "system/etc/dhcpcd/dhcpcd-run-hooks" },
{ 00555, AID_ROOT, AID_ROOT, 0, "system/etc/ppp/*" },
{ 00555, AID_ROOT, AID_ROOT, 0, "system/etc/rc.*" },
{ 00444, AID_ROOT, AID_ROOT, 0, conf_dir + 1 },
{ 00444, AID_ROOT, AID_ROOT, 0, conf_file + 1 },
{ 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app/*" },
{ 00644, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/*" },
{ 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private/*" },
{ 00644, AID_APP, AID_APP, 0, "data/data/*" },
/* the following five files are INTENTIONALLY set-uid, but they
* are NOT included on user builds. */
{ 04750, AID_ROOT, AID_SHELL, 0, "system/xbin/su" },
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/librank" },
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procrank" },
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" },
{ 04770, AID_ROOT, AID_RADIO, 0, "system/bin/pppd-ril" },
/* the following files have enhanced capabilities and ARE included in user builds. */
{ 00750, AID_ROOT, AID_SHELL, (1ULL << CAP_SETUID) | (1ULL << CAP_SETGID), "system/bin/run-as" },
{ 00700, AID_SYSTEM, AID_SHELL, (1ULL << CAP_BLOCK_SUSPEND), "system/bin/inputflinger" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/lib/valgrind/*" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/lib64/valgrind/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/xbin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/vendor/bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor/bin/*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "sbin/*" },
{ 00755, AID_ROOT, AID_ROOT, 0, "bin/*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "init*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "sbin/fs_mgr" },
{ 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" },
{ 00644, AID_ROOT, AID_ROOT, 0, 0 },
};
static int fs_config_open(int dir, const char *target_out_path)
{
int fd = -1;
if (target_out_path && *target_out_path) {
/* target_out_path is the path to the directory holding content of system partition
but as we cannot guaranty it ends with '/system' we need this below skip_len logic */
char *name = NULL;
int target_out_path_len = strlen(target_out_path);
int skip_len = strlen("/system");
if (target_out_path[target_out_path_len] == '/') {
skip_len++;
}
asprintf(&name, "%s%s", target_out_path, (dir ? conf_dir : conf_file) + skip_len);
if (name) {
fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_BINARY));
free(name);
}
}
if (fd < 0) {
fd = TEMP_FAILURE_RETRY(open(dir ? conf_dir : conf_file, O_RDONLY | O_BINARY));
}
return fd;
}
static bool fs_config_cmp(bool dir, const char *prefix, size_t len,
const char *path, size_t plen)
{
if (dir) {
if (plen < len) {
return false;
}
} else {
/* If name ends in * then allow partial matches. */
if (prefix[len - 1] == '*') {
return !strncmp(prefix, path, len - 1);
}
if (plen != len) {
return false;
}
}
return !strncmp(prefix, path, len);
}
void fs_config(const char *path, int dir, const char *target_out_path,
unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities)
{
const struct fs_path_config *pc;
int fd, plen;
if (path[0] == '/') {
path++;
}
plen = strlen(path);
fd = fs_config_open(dir, target_out_path);
if (fd >= 0) {
struct fs_path_config_from_file header;
while (TEMP_FAILURE_RETRY(read(fd, &header, sizeof(header))) == sizeof(header)) {
char *prefix;
uint16_t host_len = get2LE((const uint8_t *)&header.len);
ssize_t len, remainder = host_len - sizeof(header);
if (remainder <= 0) {
ALOGE("%s len is corrupted", dir ? conf_dir : conf_file);
break;
}
prefix = calloc(1, remainder);
if (!prefix) {
ALOGE("%s out of memory", dir ? conf_dir : conf_file);
break;
}
if (TEMP_FAILURE_RETRY(read(fd, prefix, remainder)) != remainder) {
free(prefix);
ALOGE("%s prefix is truncated", dir ? conf_dir : conf_file);
break;
}
len = strnlen(prefix, remainder);
if (len >= remainder) { /* missing a terminating null */
free(prefix);
ALOGE("%s is corrupted", dir ? conf_dir : conf_file);
break;
}
if (fs_config_cmp(dir, prefix, len, path, plen)) {
free(prefix);
close(fd);
*uid = get2LE((const uint8_t *)&(header.uid));
*gid = get2LE((const uint8_t *)&(header.gid));
*mode = (*mode & (~07777)) | get2LE((const uint8_t *)&(header.mode));
*capabilities = get8LE((const uint8_t *)&(header.capabilities));
return;
}
free(prefix);
}
close(fd);
}
pc = dir ? android_dirs : android_files;
for(; pc->prefix; pc++){
if (fs_config_cmp(dir, pc->prefix, strlen(pc->prefix), path, plen)) {
break;
}
}
*uid = pc->uid;
*gid = pc->gid;
*mode = (*mode & (~07777)) | pc->mode;
*capabilities = pc->capabilities;
}
ssize_t fs_config_generate(char *buffer, size_t length, const struct fs_path_config *pc)
{
struct fs_path_config_from_file *p = (struct fs_path_config_from_file *)buffer;
size_t len = ALIGN(sizeof(*p) + strlen(pc->prefix) + 1, sizeof(uint64_t));
if ((length < len) || (len > UINT16_MAX)) {
return -ENOSPC;
}
memset(p, 0, len);
uint16_t host_len = len;
p->len = get2LE((const uint8_t *)&host_len);
p->mode = get2LE((const uint8_t *)&(pc->mode));
p->uid = get2LE((const uint8_t *)&(pc->uid));
p->gid = get2LE((const uint8_t *)&(pc->gid));
p->capabilities = get8LE((const uint8_t *)&(pc->capabilities));
strcpy(p->prefix, pc->prefix);
return len;
}

@ -0,0 +1,363 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdarg.h>
#include <fcntl.h>
#include <private/android_filesystem_config.h>
/* NOTES
**
** - see buffer-format.txt from the linux kernel docs for
** an explanation of this file format
** - dotfiles are ignored
** - directories named 'root' are ignored
** - device notes, pipes, etc are not supported (error)
*/
void die(const char *why, ...)
{
va_list ap;
va_start(ap, why);
fprintf(stderr,"error: ");
vfprintf(stderr, why, ap);
fprintf(stderr,"\n");
va_end(ap);
exit(1);
}
struct fs_config_entry {
char* name;
int uid, gid, mode;
};
static struct fs_config_entry* canned_config = NULL;
static char *target_out_path = NULL;
/* Each line in the canned file should be a path plus three ints (uid,
* gid, mode). */
#ifdef PATH_MAX
#define CANNED_LINE_LENGTH (PATH_MAX+100)
#else
#define CANNED_LINE_LENGTH (1024)
#endif
static int verbose = 0;
static int total_size = 0;
static void fix_stat(const char *path, struct stat *s)
{
uint64_t capabilities;
if (canned_config) {
// Use the list of file uid/gid/modes loaded from the file
// given with -f.
struct fs_config_entry* empty_path_config = NULL;
struct fs_config_entry* p;
for (p = canned_config; p->name; ++p) {
if (!p->name[0]) {
empty_path_config = p;
}
if (strcmp(p->name, path) == 0) {
s->st_uid = p->uid;
s->st_gid = p->gid;
s->st_mode = p->mode | (s->st_mode & ~07777);
return;
}
}
s->st_uid = empty_path_config->uid;
s->st_gid = empty_path_config->gid;
s->st_mode = empty_path_config->mode | (s->st_mode & ~07777);
} else {
// Use the compiled-in fs_config() function.
unsigned st_mode = s->st_mode;
fs_config(path, S_ISDIR(s->st_mode), target_out_path,
&s->st_uid, &s->st_gid, &st_mode, &capabilities);
s->st_mode = (typeof(s->st_mode)) st_mode;
}
}
static void _eject(struct stat *s, char *out, int olen, char *data, unsigned datasize)
{
// Nothing is special about this value, just picked something in the
// approximate range that was being used already, and avoiding small
// values which may be special.
static unsigned next_inode = 300000;
while(total_size & 3) {
total_size++;
putchar(0);
}
fix_stat(out, s);
// fprintf(stderr, "_eject %s: mode=0%o\n", out, s->st_mode);
printf("%06x%08x%08x%08x%08x%08x%08x"
"%08x%08x%08x%08x%08x%08x%08x%s%c",
0x070701,
next_inode++, // s.st_ino,
s->st_mode,
0, // s.st_uid,
0, // s.st_gid,
1, // s.st_nlink,
0, // s.st_mtime,
datasize,
0, // volmajor
0, // volminor
0, // devmajor
0, // devminor,
olen + 1,
0,
out,
0
);
total_size += 6 + 8*13 + olen + 1;
if(strlen(out) != (unsigned int)olen) die("ACK!");
while(total_size & 3) {
total_size++;
putchar(0);
}
if(datasize) {
fwrite(data, datasize, 1, stdout);
total_size += datasize;
}
}
static void _eject_trailer()
{
struct stat s;
memset(&s, 0, sizeof(s));
_eject(&s, "TRAILER!!!", 10, 0, 0);
while(total_size & 0xff) {
total_size++;
putchar(0);
}
}
static void _archive(char *in, char *out, int ilen, int olen);
static int compare(const void* a, const void* b) {
return strcmp(*(const char**)a, *(const char**)b);
}
static void _archive_dir(char *in, char *out, int ilen, int olen)
{
int i, t;
DIR *d;
struct dirent *de;
if(verbose) {
fprintf(stderr,"_archive_dir('%s','%s',%d,%d)\n",
in, out, ilen, olen);
}
d = opendir(in);
if(d == 0) die("cannot open directory '%s'", in);
int size = 32;
int entries = 0;
char** names = malloc(size * sizeof(char*));
if (names == NULL) {
fprintf(stderr, "failed to allocate dir names array (size %d)\n", size);
exit(1);
}
while((de = readdir(d)) != 0){
/* xxx: feature? maybe some dotfiles are okay */
if(de->d_name[0] == '.') continue;
/* xxx: hack. use a real exclude list */
if(!strcmp(de->d_name, "root")) continue;
if (entries >= size) {
size *= 2;
names = realloc(names, size * sizeof(char*));
if (names == NULL) {
fprintf(stderr, "failed to reallocate dir names array (size %d)\n",
size);
exit(1);
}
}
names[entries] = strdup(de->d_name);
if (names[entries] == NULL) {
fprintf(stderr, "failed to strdup name \"%s\"\n",
de->d_name);
exit(1);
}
++entries;
}
qsort(names, entries, sizeof(char*), compare);
for (i = 0; i < entries; ++i) {
t = strlen(names[i]);
in[ilen] = '/';
memcpy(in + ilen + 1, names[i], t + 1);
if(olen > 0) {
out[olen] = '/';
memcpy(out + olen + 1, names[i], t + 1);
_archive(in, out, ilen + t + 1, olen + t + 1);
} else {
memcpy(out, names[i], t + 1);
_archive(in, out, ilen + t + 1, t);
}
in[ilen] = 0;
out[olen] = 0;
free(names[i]);
}
free(names);
closedir(d);
}
static void _archive(char *in, char *out, int ilen, int olen)
{
struct stat s;
if(verbose) {
fprintf(stderr,"_archive('%s','%s',%d,%d)\n",
in, out, ilen, olen);
}
if(lstat(in, &s)) die("could not stat '%s'\n", in);
if(S_ISREG(s.st_mode)){
char *tmp;
int fd;
fd = open(in, O_RDONLY);
if(fd < 0) die("cannot open '%s' for read", in);
tmp = (char*) malloc(s.st_size);
if(tmp == 0) die("cannot allocate %d bytes", s.st_size);
if(read(fd, tmp, s.st_size) != s.st_size) {
die("cannot read %d bytes", s.st_size);
}
_eject(&s, out, olen, tmp, s.st_size);
free(tmp);
close(fd);
} else if(S_ISDIR(s.st_mode)) {
_eject(&s, out, olen, 0, 0);
_archive_dir(in, out, ilen, olen);
} else if(S_ISLNK(s.st_mode)) {
char buf[1024];
int size;
size = readlink(in, buf, 1024);
if(size < 0) die("cannot read symlink '%s'", in);
_eject(&s, out, olen, buf, size);
} else {
die("Unknown '%s' (mode %d)?\n", in, s.st_mode);
}
}
void archive(const char *start, const char *prefix)
{
char in[8192];
char out[8192];
strcpy(in, start);
strcpy(out, prefix);
_archive_dir(in, out, strlen(in), strlen(out));
}
static void read_canned_config(char* filename)
{
int allocated = 8;
int used = 0;
canned_config =
(struct fs_config_entry*)malloc(allocated * sizeof(struct fs_config_entry));
char line[CANNED_LINE_LENGTH];
FILE* f = fopen(filename, "r");
if (f == NULL) die("failed to open canned file");
while (fgets(line, CANNED_LINE_LENGTH, f) != NULL) {
if (!line[0]) break;
if (used >= allocated) {
allocated *= 2;
canned_config = (struct fs_config_entry*)realloc(
canned_config, allocated * sizeof(struct fs_config_entry));
}
struct fs_config_entry* cc = canned_config + used;
if (isspace(line[0])) {
cc->name = strdup("");
cc->uid = atoi(strtok(line, " \n"));
} else {
cc->name = strdup(strtok(line, " \n"));
cc->uid = atoi(strtok(NULL, " \n"));
}
cc->gid = atoi(strtok(NULL, " \n"));
cc->mode = strtol(strtok(NULL, " \n"), NULL, 8);
++used;
}
if (used >= allocated) {
++allocated;
canned_config = (struct fs_config_entry*)realloc(
canned_config, allocated * sizeof(struct fs_config_entry));
}
canned_config[used].name = NULL;
fclose(f);
}
int main(int argc, char *argv[])
{
argc--;
argv++;
if (argc > 1 && strcmp(argv[0], "-d") == 0) {
target_out_path = argv[1];
argc -= 2;
argv += 2;
}
if (argc > 1 && strcmp(argv[0], "-f") == 0) {
read_canned_config(argv[1]);
argc -= 2;
argv += 2;
}
if(argc == 0) die("no directories to process?!");
while(argc-- > 0){
char *x = strchr(*argv, '=');
if(x != 0) {
*x++ = 0;
} else {
x = "";
}
archive(*argv, x);
argv++;
}
_eject_trailer();
return 0;
}

@ -0,0 +1,119 @@
/*
* Copyright (C) 2013 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.
*/
/*
* Taken from linux/capability.h, with minor modifications
*/
#ifndef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_FILESYSTEM_CAPABILITY_H
#define _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_FILESYSTEM_CAPABILITY_H
#include <stdint.h>
#define __user
#define __u32 uint32_t
#define __le32 uint32_t
#define _LINUX_CAPABILITY_VERSION_1 0x19980330
#define _LINUX_CAPABILITY_U32S_1 1
#define _LINUX_CAPABILITY_VERSION_2 0x20071026
#define _LINUX_CAPABILITY_U32S_2 2
#define _LINUX_CAPABILITY_VERSION_3 0x20080522
#define _LINUX_CAPABILITY_U32S_3 2
typedef struct __user_cap_header_struct {
__u32 version;
int pid;
} __user *cap_user_header_t;
typedef struct __user_cap_data_struct {
__u32 effective;
__u32 permitted;
__u32 inheritable;
} __user *cap_user_data_t;
#define VFS_CAP_REVISION_MASK 0xFF000000
#define VFS_CAP_REVISION_SHIFT 24
#define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK
#define VFS_CAP_FLAGS_EFFECTIVE 0x000001
#define VFS_CAP_REVISION_1 0x01000000
#define VFS_CAP_U32_1 1
#define XATTR_CAPS_SZ_1 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_1))
#define VFS_CAP_REVISION_2 0x02000000
#define VFS_CAP_U32_2 2
#define XATTR_CAPS_SZ_2 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_2))
#define XATTR_CAPS_SZ XATTR_CAPS_SZ_2
#define VFS_CAP_U32 VFS_CAP_U32_2
#define VFS_CAP_REVISION VFS_CAP_REVISION_2
struct vfs_cap_data {
__le32 magic_etc;
struct {
__le32 permitted;
__le32 inheritable;
} data[VFS_CAP_U32];
};
#define _LINUX_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_1
#define _LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_1
#define CAP_CHOWN 0
#define CAP_DAC_OVERRIDE 1
#define CAP_DAC_READ_SEARCH 2
#define CAP_FOWNER 3
#define CAP_FSETID 4
#define CAP_KILL 5
#define CAP_SETGID 6
#define CAP_SETUID 7
#define CAP_SETPCAP 8
#define CAP_LINUX_IMMUTABLE 9
#define CAP_NET_BIND_SERVICE 10
#define CAP_NET_BROADCAST 11
#define CAP_NET_ADMIN 12
#define CAP_NET_RAW 13
#define CAP_IPC_LOCK 14
#define CAP_IPC_OWNER 15
#define CAP_SYS_MODULE 16
#define CAP_SYS_RAWIO 17
#define CAP_SYS_CHROOT 18
#define CAP_SYS_PTRACE 19
#define CAP_SYS_PACCT 20
#define CAP_SYS_ADMIN 21
#define CAP_SYS_BOOT 22
#define CAP_SYS_NICE 23
#define CAP_SYS_RESOURCE 24
#define CAP_SYS_TIME 25
#define CAP_SYS_TTY_CONFIG 26
#define CAP_MKNOD 27
#define CAP_LEASE 28
#define CAP_AUDIT_WRITE 29
#define CAP_AUDIT_CONTROL 30
#define CAP_SETFCAP 31
#define CAP_MAC_OVERRIDE 32
#define CAP_MAC_ADMIN 33
#define CAP_SYSLOG 34
#define CAP_WAKE_ALARM 35
#define CAP_BLOCK_SUSPEND 36
#define CAP_AUDIT_READ 37
#define CAP_LAST_CAP CAP_AUDIT_READ
#define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
#define CAP_TO_INDEX(x) ((x) >> 5)
#define CAP_TO_MASK(x) (1 << ((x) & 31))
#undef __user
#undef __u32
#undef __le32
#endif

@ -0,0 +1,223 @@
/*
* Copyright (C) 2007 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.
*/
/* This file is used to define the properties of the filesystem
** images generated by build tools (mkbootfs and mkyaffs2image) and
** by the device side of adb.
*/
#ifndef _ANDROID_FILESYSTEM_CONFIG_H_
#define _ANDROID_FILESYSTEM_CONFIG_H_
#include <sys/cdefs.h>
#include <sys/types.h>
#include <stdint.h>
#ifdef HAVE_ANDROID_OS
#include <linux/capability.h>
#else
#include "android_filesystem_capability.h"
#endif
/* This is the master Users and Groups config for the platform.
* DO NOT EVER RENUMBER
*/
#define AID_ROOT 0 /* traditional unix root user */
#define AID_SYSTEM 1000 /* system server */
#define AID_RADIO 1001 /* telephony subsystem, RIL */
#define AID_BLUETOOTH 1002 /* bluetooth subsystem */
#define AID_GRAPHICS 1003 /* graphics devices */
#define AID_INPUT 1004 /* input devices */
#define AID_AUDIO 1005 /* audio devices */
#define AID_CAMERA 1006 /* camera devices */
#define AID_LOG 1007 /* log devices */
#define AID_COMPASS 1008 /* compass device */
#define AID_MOUNT 1009 /* mountd socket */
#define AID_WIFI 1010 /* wifi subsystem */
#define AID_ADB 1011 /* android debug bridge (adbd) */
#define AID_INSTALL 1012 /* group for installing packages */
#define AID_MEDIA 1013 /* mediaserver process */
#define AID_DHCP 1014 /* dhcp client */
#define AID_SDCARD_RW 1015 /* external storage write access */
#define AID_VPN 1016 /* vpn system */
#define AID_KEYSTORE 1017 /* keystore subsystem */
#define AID_USB 1018 /* USB devices */
#define AID_DRM 1019 /* DRM server */
#define AID_MDNSR 1020 /* MulticastDNSResponder (service discovery) */
#define AID_GPS 1021 /* GPS daemon */
#define AID_UNUSED1 1022 /* deprecated, DO NOT USE */
#define AID_MEDIA_RW 1023 /* internal media storage write access */
#define AID_MTP 1024 /* MTP USB driver access */
#define AID_UNUSED2 1025 /* deprecated, DO NOT USE */
#define AID_DRMRPC 1026 /* group for drm rpc */
#define AID_NFC 1027 /* nfc subsystem */
#define AID_SDCARD_R 1028 /* external storage read access */
#define AID_CLAT 1029 /* clat part of nat464 */
#define AID_LOOP_RADIO 1030 /* loop radio devices */
#define AID_MEDIA_DRM 1031 /* MediaDrm plugins */
#define AID_PACKAGE_INFO 1032 /* access to installed package details */
#define AID_SDCARD_PICS 1033 /* external storage photos access */
#define AID_SDCARD_AV 1034 /* external storage audio/video access */
#define AID_SDCARD_ALL 1035 /* access all users external storage */
#define AID_LOGD 1036 /* log daemon */
#define AID_SHARED_RELRO 1037 /* creator of shared GNU RELRO files */
#define AID_SHELL 2000 /* adb and debug shell user */
#define AID_CACHE 2001 /* cache access */
#define AID_DIAG 2002 /* access to diagnostic resources */
/* The range 2900-2999 is reserved for OEM, and must never be
* used here */
#define AID_OEM_RESERVED_START 2900
#define AID_OEM_RESERVED_END 2999
/* The 3000 series are intended for use as supplemental group id's only.
* They indicate special Android capabilities that the kernel is aware of. */
#define AID_NET_BT_ADMIN 3001 /* bluetooth: create any socket */
#define AID_NET_BT 3002 /* bluetooth: create sco, rfcomm or l2cap sockets */
#define AID_INET 3003 /* can create AF_INET and AF_INET6 sockets */
#define AID_NET_RAW 3004 /* can create raw INET sockets */
#define AID_NET_ADMIN 3005 /* can configure interfaces and routing tables. */
#define AID_NET_BW_STATS 3006 /* read bandwidth statistics */
#define AID_NET_BW_ACCT 3007 /* change bandwidth statistics accounting */
#define AID_NET_BT_STACK 3008 /* bluetooth: access config files */
#define AID_EVERYBODY 9997 /* shared between all apps in the same profile */
#define AID_MISC 9998 /* access to misc storage */
#define AID_NOBODY 9999
#define AID_APP 10000 /* first app user */
#define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */
#define AID_ISOLATED_END 99999 /* end of uids for fully isolated sandboxed processes */
#define AID_USER 100000 /* offset for uid ranges for each user */
#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
#define AID_SHARED_GID_END 59999 /* start of gids for apps in each user to share */
#if !defined(EXCLUDE_FS_CONFIG_STRUCTURES)
/*
* Used in:
* bionic/libc/bionic/stubs.cpp
* external/libselinux/src/android.c
* system/core/logd/LogStatistics.cpp
* system/core/init/ueventd.cpp
* system/core/init/util.cpp
*/
struct android_id_info {
const char *name;
unsigned aid;
};
static const struct android_id_info android_ids[] = {
{ "root", AID_ROOT, },
{ "system", AID_SYSTEM, },
{ "radio", AID_RADIO, },
{ "bluetooth", AID_BLUETOOTH, },
{ "graphics", AID_GRAPHICS, },
{ "input", AID_INPUT, },
{ "audio", AID_AUDIO, },
{ "camera", AID_CAMERA, },
{ "log", AID_LOG, },
{ "compass", AID_COMPASS, },
{ "mount", AID_MOUNT, },
{ "wifi", AID_WIFI, },
{ "adb", AID_ADB, },
{ "install", AID_INSTALL, },
{ "media", AID_MEDIA, },
{ "dhcp", AID_DHCP, },
{ "sdcard_rw", AID_SDCARD_RW, },
{ "vpn", AID_VPN, },
{ "keystore", AID_KEYSTORE, },
{ "usb", AID_USB, },
{ "drm", AID_DRM, },
{ "mdnsr", AID_MDNSR, },
{ "gps", AID_GPS, },
// AID_UNUSED1
{ "media_rw", AID_MEDIA_RW, },
{ "mtp", AID_MTP, },
// AID_UNUSED2
{ "drmrpc", AID_DRMRPC, },
{ "nfc", AID_NFC, },
{ "sdcard_r", AID_SDCARD_R, },
{ "clat", AID_CLAT, },
{ "loop_radio", AID_LOOP_RADIO, },
{ "mediadrm", AID_MEDIA_DRM, },
{ "package_info", AID_PACKAGE_INFO, },
{ "sdcard_pics", AID_SDCARD_PICS, },
{ "sdcard_av", AID_SDCARD_AV, },
{ "sdcard_all", AID_SDCARD_ALL, },
{ "logd", AID_LOGD, },
{ "shared_relro", AID_SHARED_RELRO, },
{ "shell", AID_SHELL, },
{ "cache", AID_CACHE, },
{ "diag", AID_DIAG, },
{ "net_bt_admin", AID_NET_BT_ADMIN, },
{ "net_bt", AID_NET_BT, },
{ "inet", AID_INET, },
{ "net_raw", AID_NET_RAW, },
{ "net_admin", AID_NET_ADMIN, },
{ "net_bw_stats", AID_NET_BW_STATS, },
{ "net_bw_acct", AID_NET_BW_ACCT, },
{ "net_bt_stack", AID_NET_BT_STACK, },
{ "everybody", AID_EVERYBODY, },
{ "misc", AID_MISC, },
{ "nobody", AID_NOBODY, },
};
#define android_id_count \
(sizeof(android_ids) / sizeof(android_ids[0]))
struct fs_path_config {
unsigned mode;
unsigned uid;
unsigned gid;
uint64_t capabilities;
const char *prefix;
};
/* Rules for directories and files has moved to system/code/libcutils/fs_config.c */
__BEGIN_DECLS
/*
* Used in:
* build/tools/fs_config/fs_config.c
* build/tools/fs_get_stats/fs_get_stats.c
* system/extras/ext4_utils/make_ext4fs_main.c
* external/squashfs-tools/squashfs-tools/android.c
* system/core/cpio/mkbootfs.c
* system/core/adb/file_sync_service.cpp
* system/extras/ext4_utils/canned_fs_config.c
*/
void fs_config(const char *path, int dir, const char *target_out_path,
unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities);
ssize_t fs_config_generate(char *buffer, size_t length, const struct fs_path_config *pc);
__END_DECLS
#endif
#endif
Loading…
Cancel
Save