initial commit
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…
Reference in New Issue