Add calvaria. Tool to access Maemo CAL partition.
git-svn-id: svn://svn.openwrt.org/openwrt/packages@25235 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
parent
4749786c0d
commit
dbfc1f7584
39
utils/calvaria/Makefile
Normal file
39
utils/calvaria/Makefile
Normal file
@ -0,0 +1,39 @@
|
||||
#
|
||||
# Copyright (C) 2011 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=calvaria
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_INSTALL:=1
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/calvaria
|
||||
SECTION:=utils
|
||||
CATEGORY:=Utilities
|
||||
TITLE:=Maemo CAL partition access tool
|
||||
MAINTAINER:=Michael Buesch <mb@bu3sch.de>
|
||||
endef
|
||||
|
||||
define Package/calvaria/description
|
||||
Calvaria - Maemo CAL partition variable access tool
|
||||
The CAL partition (/dev/mtdblock1) is used to store configuration
|
||||
and calibration data.
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
$(CP) ./files/src/* $(PKG_BUILD_DIR)/
|
||||
endef
|
||||
|
||||
define Package/calvaria/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/calvaria $(1)/usr/bin/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,calvaria))
|
26
utils/calvaria/files/src/Makefile
Normal file
26
utils/calvaria/files/src/Makefile
Normal file
@ -0,0 +1,26 @@
|
||||
DESTDIR ?=
|
||||
PREFIX ?= /usr
|
||||
CFLAGS ?= -O2 -Wall
|
||||
LDFLAGS ?=
|
||||
LDLIBS ?=
|
||||
|
||||
STRIP ?= strip
|
||||
INSTALL ?= install
|
||||
|
||||
BIN := calvaria
|
||||
|
||||
all: $(BIN)
|
||||
|
||||
$(BIN): calvaria.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
$(STRIP) $@
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) $^ -o $@
|
||||
|
||||
install: $(BIN)
|
||||
$(INSTALL) -d $(DESTDIR)/$(PREFIX)/bin
|
||||
$(INSTALL) -m 0755 $(BIN) $(DESTDIR)/$(PREFIX)/bin/
|
||||
|
||||
clean:
|
||||
rm -f $(BIN) *.o
|
444
utils/calvaria/files/src/calvaria.c
Normal file
444
utils/calvaria/files/src/calvaria.c
Normal file
@ -0,0 +1,444 @@
|
||||
/*
|
||||
* Calvaria - Maemo CAL partition variable access tool.
|
||||
*
|
||||
* Copyright (c) 2011 Michael Buesch <mb@bu3sch.de>
|
||||
*
|
||||
* Licensed under the GNU General Public License
|
||||
* version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
|
||||
#define _packed __attribute__((__packed__))
|
||||
|
||||
typedef uint16_t le16_t;
|
||||
typedef uint32_t le32_t;
|
||||
|
||||
struct header {
|
||||
char magic[4]; /* Magic sequence */
|
||||
uint8_t type; /* Type number */
|
||||
uint8_t index; /* Index number */
|
||||
le16_t flags; /* Flags */
|
||||
char name[16]; /* Human readable section name */
|
||||
le32_t length; /* Payload length */
|
||||
le32_t datasum; /* Data CRC32 checksum */
|
||||
le32_t hdrsum; /* Header CRC32 checksum */
|
||||
} _packed;
|
||||
|
||||
#define HDR_MAGIC "ConF"
|
||||
|
||||
|
||||
static char toAscii(char c)
|
||||
{
|
||||
if (c >= 32 && c <= 126)
|
||||
return c;
|
||||
return '.';
|
||||
}
|
||||
|
||||
static void dump(FILE *outstream, const char *buf, size_t size)
|
||||
{
|
||||
size_t i, ascii_cnt = 0;
|
||||
char ascii[17] = { 0, };
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if (i % 16 == 0) {
|
||||
if (i != 0) {
|
||||
fprintf(outstream, " |%s|\n", ascii);
|
||||
ascii[0] = 0;
|
||||
ascii_cnt = 0;
|
||||
}
|
||||
fprintf(outstream, "[%04X]: ", (unsigned int)i);
|
||||
}
|
||||
fprintf(outstream, " %02X", buf[i]);
|
||||
ascii[ascii_cnt] = toAscii(buf[i]);
|
||||
ascii[ascii_cnt + 1] = 0;
|
||||
ascii_cnt++;
|
||||
}
|
||||
if (ascii[0]) {
|
||||
if (size % 16) {
|
||||
for (i = 0; i < 16 - (size % 16); i++)
|
||||
fprintf(outstream, " ");
|
||||
}
|
||||
fprintf(outstream, " |%s|\n", ascii);
|
||||
}
|
||||
fprintf(outstream, "\n");
|
||||
}
|
||||
|
||||
static uint32_t crc32(uint32_t crc, const void *_data, size_t size)
|
||||
{
|
||||
const uint8_t *data = _data;
|
||||
uint8_t value;
|
||||
unsigned int bit;
|
||||
size_t i;
|
||||
const uint32_t poly = 0xEDB88320;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
value = data[i];
|
||||
for (bit = 8; bit; bit--) {
|
||||
if ((crc & 1) != (value & 1))
|
||||
crc = (crc >> 1) ^ poly;
|
||||
else
|
||||
crc >>= 1;
|
||||
value >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
static inline uint16_t le16_to_cpu(le16_t x)
|
||||
{
|
||||
uint8_t *bytes = (uint8_t *)&x;
|
||||
uint16_t ret;
|
||||
|
||||
ret = bytes[0];
|
||||
ret |= (uint16_t)(bytes[1]) << 8;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint32_t le32_to_cpu(le32_t x)
|
||||
{
|
||||
uint8_t *bytes = (uint8_t *)&x;
|
||||
uint32_t ret;
|
||||
|
||||
ret = bytes[0];
|
||||
ret |= (uint32_t)(bytes[1]) << 8;
|
||||
ret |= (uint32_t)(bytes[2]) << 16;
|
||||
ret |= (uint32_t)(bytes[3]) << 24;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int is_header(void *data, size_t size)
|
||||
{
|
||||
struct header *hdr = data;
|
||||
|
||||
if (size < sizeof(struct header))
|
||||
return 0;
|
||||
if (memcmp(hdr->magic, HDR_MAGIC, sizeof(hdr->magic)) != 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dump_section(const struct header *hdr,
|
||||
const void *payload, size_t payload_len,
|
||||
int dump_payload,
|
||||
FILE *outstream)
|
||||
{
|
||||
char name[sizeof(hdr->name) + 1] = { 0, };
|
||||
int hdrsum_ok, datasum_ok;
|
||||
|
||||
memcpy(name, hdr->name, sizeof(hdr->name));
|
||||
hdrsum_ok = (crc32(0, hdr, sizeof(*hdr) - 4) == le32_to_cpu(hdr->hdrsum));
|
||||
datasum_ok = (crc32(0, payload, payload_len) == le32_to_cpu(hdr->datasum));
|
||||
|
||||
fprintf(outstream, "Section: %s\n", name);
|
||||
fprintf(outstream, "Type: %u (0x%X)\n", hdr->type, hdr->type);
|
||||
fprintf(outstream, "Index: %u (0x%X)\n", hdr->index, hdr->index);
|
||||
fprintf(outstream, "Flags: 0x%04X\n", le16_to_cpu(hdr->flags));
|
||||
fprintf(outstream, "Length: %u (0x%X)\n",
|
||||
le32_to_cpu(hdr->length), le32_to_cpu(hdr->length));
|
||||
fprintf(outstream, "Data CRC32: 0x%08X (%s)\n", le32_to_cpu(hdr->datasum),
|
||||
datasum_ok ? "Ok" : "MISMATCH");
|
||||
fprintf(outstream, "Header CRC32: 0x%08X (%s)\n", le32_to_cpu(hdr->hdrsum),
|
||||
hdrsum_ok ? "Ok" : "MISMATCH");
|
||||
if (dump_payload)
|
||||
dump(outstream, payload, payload_len);
|
||||
fprintf(outstream, "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void * map_file(const char *filepath, int readonly,
|
||||
uint64_t *filelen)
|
||||
{
|
||||
int fd;
|
||||
off_t len;
|
||||
void *data;
|
||||
|
||||
fd = open(filepath, readonly ? O_RDONLY : O_RDWR);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Failed to open file %s: %s\n",
|
||||
filepath, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
len = lseek(fd, 0, SEEK_END);
|
||||
if (len < 0 || lseek(fd, 0, SEEK_SET)) {
|
||||
fprintf(stderr, "Failed to calculate file length of %s: %s\n",
|
||||
filepath, strerror(errno));
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = mmap(NULL, len,
|
||||
readonly ? PROT_READ : (PROT_READ | PROT_WRITE),
|
||||
readonly ? MAP_PRIVATE : 0,
|
||||
fd, 0);
|
||||
close(fd);
|
||||
if (data == MAP_FAILED) {
|
||||
fprintf(stderr, "Failed to MMAP file %s: %s\n",
|
||||
filepath, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
madvise(data, len, MADV_SEQUENTIAL);
|
||||
|
||||
*filelen = len;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void unmap_file(void *mapping, uint64_t len)
|
||||
{
|
||||
munmap(mapping, len);
|
||||
}
|
||||
|
||||
static int64_t find_section(void *start, uint64_t count,
|
||||
int want_index, const char *want_name)
|
||||
{
|
||||
uint64_t offset = 0;
|
||||
uint8_t *data = start;
|
||||
struct header *hdr;
|
||||
char sectname[sizeof(hdr->name) + 1] = { 0, };
|
||||
uint32_t payload_len;
|
||||
|
||||
while (1) {
|
||||
/* Find header start */
|
||||
if (count < sizeof(struct header))
|
||||
break;
|
||||
if (!is_header(data + offset, count)) {
|
||||
count--;
|
||||
offset++;
|
||||
continue;
|
||||
}
|
||||
hdr = (struct header *)(data + offset);
|
||||
payload_len = le32_to_cpu(hdr->length);
|
||||
if (count - sizeof(struct header) < payload_len) {
|
||||
fprintf(stderr, "Premature EOF\n");
|
||||
return -1;
|
||||
}
|
||||
memcpy(sectname, hdr->name, sizeof(hdr->name));
|
||||
|
||||
if (want_index >= 0 && want_index != hdr->index)
|
||||
goto next;
|
||||
if (want_name && strcmp(sectname, want_name) != 0)
|
||||
goto next;
|
||||
|
||||
/* Found it */
|
||||
return offset;
|
||||
|
||||
next:
|
||||
count -= sizeof(struct header) + payload_len;
|
||||
offset += sizeof(struct header) + payload_len;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int dump_image(const char *filepath,
|
||||
int want_section_index, const char *want_section_name,
|
||||
int want_headers_only,
|
||||
FILE *outstream)
|
||||
{
|
||||
int err, ret = 0;
|
||||
uint64_t filelen;
|
||||
uint64_t count, offset;
|
||||
int64_t find_offset;
|
||||
uint8_t *data, *section;
|
||||
struct header *hdr;
|
||||
uint32_t payload_len;
|
||||
|
||||
data = map_file(filepath, 1, &filelen);
|
||||
if (!data)
|
||||
return -EIO;
|
||||
|
||||
count = filelen;
|
||||
offset = 0;
|
||||
while (1) {
|
||||
find_offset = find_section(data + offset, count,
|
||||
want_section_index, want_section_name);
|
||||
if (find_offset < 0)
|
||||
break;
|
||||
offset += find_offset;
|
||||
count -= find_offset;
|
||||
|
||||
section = data + offset;
|
||||
hdr = (struct header *)section;
|
||||
payload_len = le32_to_cpu(hdr->length);
|
||||
|
||||
err = dump_section(hdr, section + sizeof(struct header),
|
||||
payload_len,
|
||||
!want_headers_only,
|
||||
outstream);
|
||||
if (err) {
|
||||
ret = err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
count -= sizeof(struct header) + payload_len;
|
||||
offset += sizeof(struct header) + payload_len;
|
||||
}
|
||||
out:
|
||||
unmap_file(data, filelen);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int write_payload(const char *filepath,
|
||||
int want_section_index, const char *want_section_name,
|
||||
FILE *outstream)
|
||||
{
|
||||
int64_t find_offset;
|
||||
uint64_t filelen;
|
||||
uint8_t *data;
|
||||
struct header *hdr;
|
||||
|
||||
data = map_file(filepath, 1, &filelen);
|
||||
if (!data)
|
||||
return -EIO;
|
||||
|
||||
find_offset = find_section(data, filelen,
|
||||
want_section_index, want_section_name);
|
||||
if (find_offset < 0) {
|
||||
fprintf(stderr, "Section %s, index %d not found\n",
|
||||
want_section_name, want_section_index);
|
||||
unmap_file(data, filelen);
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
hdr = (struct header *)(data + find_offset);
|
||||
if (fwrite(data + find_offset + sizeof(struct header),
|
||||
le32_to_cpu(hdr->length), 1, outstream) != 1) {
|
||||
fprintf(stderr, "Could not write output data\n");
|
||||
unmap_file(data, filelen);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
unmap_file(data, filelen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usage(FILE *fd)
|
||||
{
|
||||
fprintf(fd, "Calvaria - Maemo CAL partition variable access tool\n");
|
||||
fprintf(fd, "\n");
|
||||
fprintf(fd, "Usage: calvaria [OPTIONS] FILE\n");
|
||||
fprintf(fd, "\n");
|
||||
fprintf(fd, "Actions:\n");
|
||||
fprintf(fd, " -d|--dump Dump the contents of the image\n");
|
||||
fprintf(fd, " -H|--headers Dump the headers of the image, only\n");
|
||||
fprintf(fd, " -p|--payload Write the binary payload to stdout.\n");
|
||||
fprintf(fd, " Requires -i and -n to be set, too\n");
|
||||
fprintf(fd, "\n");
|
||||
fprintf(fd, "Options:\n");
|
||||
fprintf(fd, " -i|--index NUMBER Use this section index number\n");
|
||||
fprintf(fd, " -n|--name STRING Use this section name\n");
|
||||
fprintf(fd, "\n");
|
||||
fprintf(fd, " -h|--help Print this help text\n");
|
||||
}
|
||||
|
||||
enum action {
|
||||
ACTION_NONE,
|
||||
ACTION_DUMP,
|
||||
ACTION_DUMPHDRS,
|
||||
ACTION_GETPAYLOAD,
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int err, c, idx = 0;
|
||||
const char *filepath;
|
||||
enum action action = ACTION_NONE;
|
||||
int opt_index = -1;
|
||||
const char *opt_name = NULL;
|
||||
|
||||
static struct option long_options[] = {
|
||||
{ "dump", no_argument, 0, 'd', },
|
||||
{ "headers", no_argument, 0, 'H', },
|
||||
{ "payload", no_argument, 0, 'p', },
|
||||
{ "index", required_argument, 0, 'i', },
|
||||
{ "name", required_argument, 0, 'n', },
|
||||
{ "help", no_argument, 0, 'h', },
|
||||
{ },
|
||||
};
|
||||
|
||||
while (1) {
|
||||
c = getopt_long(argc, argv, "dHphi:n:",
|
||||
long_options, &idx);
|
||||
if (c == -1)
|
||||
break;
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage(stdout);
|
||||
return 0;
|
||||
case 'd':
|
||||
action = ACTION_DUMP;
|
||||
break;
|
||||
case 'H':
|
||||
action = ACTION_DUMPHDRS;
|
||||
break;
|
||||
case 'p':
|
||||
action = ACTION_GETPAYLOAD;
|
||||
break;
|
||||
case 'i':
|
||||
if (sscanf(optarg, "%d", &opt_index) != 1 || opt_index < 0) {
|
||||
fprintf(stderr, "-i|--index is not a positive integer\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
opt_name = optarg;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if (action == ACTION_NONE) {
|
||||
fprintf(stderr, "No action specified.\n");
|
||||
return 1;
|
||||
}
|
||||
if (action == ACTION_GETPAYLOAD) {
|
||||
if (opt_index < 0 || !opt_name) {
|
||||
fprintf(stderr, "Required options -i|--index or -n|--name "
|
||||
"not specified for action -p|--payload\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (argc != 1) {
|
||||
usage(stderr);
|
||||
return 1;
|
||||
}
|
||||
filepath = argv[0];
|
||||
|
||||
switch (action) {
|
||||
case ACTION_NONE:
|
||||
break;
|
||||
case ACTION_DUMP:
|
||||
case ACTION_DUMPHDRS:
|
||||
err = dump_image(filepath, opt_index, opt_name,
|
||||
(action == ACTION_DUMPHDRS),
|
||||
stdout);
|
||||
if (err)
|
||||
return 1;
|
||||
break;
|
||||
case ACTION_GETPAYLOAD:
|
||||
err = write_payload(filepath, opt_index, opt_name, stdout);
|
||||
if (err)
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user