add abstraction to adb "walking" - a sax like API to enumerate whole db
This converts 'adbdump' applet to generate adb_walk api callbacks, and implement gentext backend to generate the yaml-like text output.cute-signatures
parent
7167bc9e7b
commit
209201bc5d
|
@ -503,10 +503,12 @@ adb_val_t adb_w_blob(struct adb *db, apk_blob_t b)
|
||||||
val.u16 = htole16(n);
|
val.u16 = htole16(n);
|
||||||
vec[0].iov_len = sizeof val.u16;
|
vec[0].iov_len = sizeof val.u16;
|
||||||
o = ADB_TYPE_BLOB_16;
|
o = ADB_TYPE_BLOB_16;
|
||||||
} else {
|
} else if (n > 0) {
|
||||||
val.u8 = n;
|
val.u8 = n;
|
||||||
vec[0].iov_len = sizeof val.u8;
|
vec[0].iov_len = sizeof val.u8;
|
||||||
o = ADB_TYPE_BLOB_8;
|
o = ADB_TYPE_BLOB_8;
|
||||||
|
} else {
|
||||||
|
return ADB_VAL_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ADB_VAL(o, adb_w_data(db, vec, ARRAY_SIZE(vec), vec[0].iov_len));
|
return ADB_VAL(o, adb_w_data(db, vec, ARRAY_SIZE(vec), vec[0].iov_len));
|
||||||
|
@ -712,7 +714,7 @@ adb_val_t adb_wa_append(struct adb_obj *o, adb_val_t v)
|
||||||
assert(o->schema->kind == ADB_KIND_ARRAY);
|
assert(o->schema->kind == ADB_KIND_ARRAY);
|
||||||
if (o->num >= o->obj[ADBI_NUM_ENTRIES]) return adb_w_error(o->db, E2BIG);
|
if (o->num >= o->obj[ADBI_NUM_ENTRIES]) return adb_w_error(o->db, E2BIG);
|
||||||
if (ADB_IS_ERROR(v)) return adb_w_error(o->db, ADB_VAL_VALUE(v));
|
if (ADB_IS_ERROR(v)) return adb_w_error(o->db, ADB_VAL_VALUE(v));
|
||||||
o->obj[o->num++] = v;
|
if (v != ADB_VAL_NULL) o->obj[o->num++] = v;
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
35
src/adb.h
35
src/adb.h
|
@ -236,4 +236,39 @@ struct adb_xfrm {
|
||||||
};
|
};
|
||||||
int adb_c_xfrm(struct adb_xfrm *, int (*cb)(struct adb_xfrm *, struct adb_block *, struct apk_istream *));
|
int adb_c_xfrm(struct adb_xfrm *, int (*cb)(struct adb_xfrm *, struct adb_block *, struct apk_istream *));
|
||||||
|
|
||||||
|
/* SAX style event based handling of ADB */
|
||||||
|
|
||||||
|
struct adb_db_schema {
|
||||||
|
unsigned long magic;
|
||||||
|
const struct adb_object_schema *root;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct adb_walk;
|
||||||
|
struct adb_walk_ops {
|
||||||
|
int (*schema)(struct adb_walk *, uint32_t schema_id);
|
||||||
|
int (*comment)(struct adb_walk *, apk_blob_t comment);
|
||||||
|
int (*start_array)(struct adb_walk *, unsigned int num_items);
|
||||||
|
int (*start_object)(struct adb_walk *);
|
||||||
|
int (*end)(struct adb_walk *);
|
||||||
|
int (*key)(struct adb_walk *, apk_blob_t key_name);
|
||||||
|
int (*scalar)(struct adb_walk *, apk_blob_t scalar, int multiline);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct adb_walk_ops adb_walk_gentext_ops;
|
||||||
|
|
||||||
|
struct adb_walk {
|
||||||
|
const struct adb_walk_ops *ops;
|
||||||
|
const struct adb_db_schema *schemas;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct adb_walk_gentext {
|
||||||
|
struct adb_walk d;
|
||||||
|
FILE *out;
|
||||||
|
int nest;
|
||||||
|
int line_started : 1;
|
||||||
|
int key_printed : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
int adb_walk_adb(struct adb_walk *d, struct adb *db, struct apk_trust *trust);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
#include "adb.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "apk_adb.h"
|
||||||
|
#include "apk_applet.h"
|
||||||
|
#include "apk_print.h"
|
||||||
|
|
||||||
|
struct adb_walk_ctx {
|
||||||
|
struct adb_walk *d;
|
||||||
|
struct adb *db;
|
||||||
|
struct apk_trust *trust;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int dump_object(struct adb_walk_ctx *ctx, const struct adb_object_schema *schema, adb_val_t v);
|
||||||
|
static int dump_adb(struct adb_walk_ctx *ctx);
|
||||||
|
|
||||||
|
static int dump_item(struct adb_walk_ctx *ctx, const char *name, const uint8_t *kind, adb_val_t v)
|
||||||
|
{
|
||||||
|
struct adb_walk *d = ctx->d;
|
||||||
|
struct adb db, *origdb;
|
||||||
|
struct adb_obj o;
|
||||||
|
struct adb_object_schema *obj_schema;
|
||||||
|
char tmp[256];
|
||||||
|
apk_blob_t b;
|
||||||
|
|
||||||
|
if (v == ADB_VAL_NULL) return 0;
|
||||||
|
|
||||||
|
d->ops->key(d, name ? APK_BLOB_STR(name) : APK_BLOB_NULL);
|
||||||
|
|
||||||
|
switch (*kind) {
|
||||||
|
case ADB_KIND_ARRAY:
|
||||||
|
obj_schema = container_of(kind, struct adb_object_schema, kind);
|
||||||
|
adb_r_obj(ctx->db, v, &o, obj_schema);
|
||||||
|
//if (!adb_ra_num(&o)) return 0;
|
||||||
|
|
||||||
|
d->ops->start_array(d, adb_ra_num(&o));
|
||||||
|
for (size_t i = ADBI_FIRST; i <= adb_ra_num(&o); i++) {
|
||||||
|
dump_item(ctx, NULL, obj_schema->fields[0].kind, adb_ro_val(&o, i));
|
||||||
|
}
|
||||||
|
d->ops->end(d);
|
||||||
|
break;
|
||||||
|
case ADB_KIND_ADB:
|
||||||
|
db.hdr.schema = container_of(kind, struct adb_adb_schema, kind)->schema_id;
|
||||||
|
db.data = adb_r_blob(ctx->db, v);
|
||||||
|
origdb = ctx->db;
|
||||||
|
ctx->db = &db;
|
||||||
|
d->ops->start_object(d);
|
||||||
|
dump_adb(ctx);
|
||||||
|
d->ops->end(d);
|
||||||
|
ctx->db = origdb;
|
||||||
|
break;
|
||||||
|
case ADB_KIND_OBJECT:
|
||||||
|
d->ops->start_object(d);
|
||||||
|
dump_object(ctx, container_of(kind, struct adb_object_schema, kind), v);
|
||||||
|
d->ops->end(d);
|
||||||
|
break;
|
||||||
|
case ADB_KIND_BLOB:
|
||||||
|
case ADB_KIND_INT:;
|
||||||
|
struct adb_scalar_schema *scalar = container_of(kind, struct adb_scalar_schema, kind);
|
||||||
|
if (scalar->tostring) {
|
||||||
|
b = scalar->tostring(ctx->db, v, tmp, sizeof tmp);
|
||||||
|
} else {
|
||||||
|
b = APK_BLOB_STR("(unknown)");
|
||||||
|
}
|
||||||
|
if (!APK_BLOB_IS_NULL(b))
|
||||||
|
d->ops->scalar(d, b, scalar->multiline);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dump_object(struct adb_walk_ctx *ctx, const struct adb_object_schema *schema, adb_val_t v)
|
||||||
|
{
|
||||||
|
size_t schema_len = 0;
|
||||||
|
struct adb_obj o;
|
||||||
|
char tmp[256];
|
||||||
|
apk_blob_t b;
|
||||||
|
struct adb_walk *d = ctx->d;
|
||||||
|
|
||||||
|
adb_r_obj(ctx->db, v, &o, schema);
|
||||||
|
if (schema) {
|
||||||
|
if (schema->tostring) {
|
||||||
|
b = schema->tostring(&o, tmp, sizeof tmp);
|
||||||
|
if (!APK_BLOB_IS_NULL(b))
|
||||||
|
d->ops->scalar(d, b, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
schema_len = schema->num_fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = ADBI_FIRST; i < adb_ro_num(&o); i++) {
|
||||||
|
adb_val_t val = adb_ro_val(&o, i);
|
||||||
|
if (val == ADB_NULL) continue;
|
||||||
|
if (i < schema_len && schema->fields[i-1].kind != 0) {
|
||||||
|
dump_item(ctx, schema->fields[i-1].name, schema->fields[i-1].kind, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dump_adb(struct adb_walk_ctx *ctx)
|
||||||
|
{
|
||||||
|
char tmp[256];
|
||||||
|
struct adb_block *blk;
|
||||||
|
struct adb_sign_hdr *s;
|
||||||
|
struct adb_verify_ctx vfy = {};
|
||||||
|
unsigned char *id;
|
||||||
|
uint32_t schema_magic = ctx->db->hdr.schema;
|
||||||
|
const struct adb_db_schema *ds;
|
||||||
|
struct adb_walk *d = ctx->d;
|
||||||
|
int r, len;
|
||||||
|
|
||||||
|
for (ds = d->schemas; ds->magic; ds++)
|
||||||
|
if (ds->magic == schema_magic) break;
|
||||||
|
|
||||||
|
adb_foreach_block(blk, ctx->db->data) {
|
||||||
|
apk_blob_t b = APK_BLOB_PTR_LEN((char*)(blk+1), ADB_BLOCK_SIZE(blk));
|
||||||
|
switch (ADB_BLOCK_TYPE(blk)) {
|
||||||
|
case ADB_BLOCK_ADB:
|
||||||
|
len = snprintf(tmp, sizeof tmp, "ADB block, size: %u", ADB_BLOCK_SIZE(blk));
|
||||||
|
d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
|
||||||
|
if (ds->root) {
|
||||||
|
ctx->db->adb = b;
|
||||||
|
dump_object(ctx, ds->root, adb_r_root(ctx->db));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ADB_BLOCK_SIG:
|
||||||
|
s = (struct adb_sign_hdr*) b.ptr;
|
||||||
|
r = adb_trust_verify_signature(ctx->trust, ctx->db, &vfy, b);
|
||||||
|
|
||||||
|
len = snprintf(tmp, sizeof tmp, "signature: v%d ", s->sign_ver);
|
||||||
|
switch (s->sign_ver) {
|
||||||
|
case 0:
|
||||||
|
id = (unsigned char*)(s + 1);
|
||||||
|
for (size_t j = 0; j < 16; j++)
|
||||||
|
len += snprintf(&tmp[len], sizeof tmp - len, "%02x", id[j]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len += snprintf(&tmp[len], sizeof tmp - len, ": %s", r ? apk_error_str(r) : "OK");
|
||||||
|
d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
len = snprintf(tmp, sizeof tmp, "unknown block %d, size: %d",
|
||||||
|
ADB_BLOCK_TYPE(blk), ADB_BLOCK_SIZE(blk));
|
||||||
|
d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (IS_ERR(blk)) {
|
||||||
|
d->ops->comment(d, APK_BLOB_STRLIT("block enumeration error: corrupt data area"));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int adb_walk_adb(struct adb_walk *d, struct adb *db, struct apk_trust *trust)
|
||||||
|
{
|
||||||
|
struct adb_walk_ctx ctx = {
|
||||||
|
.d = d,
|
||||||
|
.db = db,
|
||||||
|
.trust = trust,
|
||||||
|
};
|
||||||
|
return dump_adb(&ctx);
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
#include "adb.h"
|
||||||
|
#include "apk_print.h"
|
||||||
|
|
||||||
|
static void adb_walk_gentext_indent(struct adb_walk_gentext *dt)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!dt->line_started) {
|
||||||
|
for (i = 0; i < dt->nest; i++) {
|
||||||
|
fprintf(dt->out, " ");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(dt->out, " ");
|
||||||
|
}
|
||||||
|
dt->line_started = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void adb_walk_gentext_newline(struct adb_walk_gentext *dt)
|
||||||
|
{
|
||||||
|
dt->line_started = 0;
|
||||||
|
dt->key_printed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int adb_walk_gentext_schema(struct adb_walk *d, uint32_t schema_id)
|
||||||
|
{
|
||||||
|
struct adb_walk_gentext *dt = container_of(d, struct adb_walk_gentext, d);
|
||||||
|
FILE *out = dt->out;
|
||||||
|
|
||||||
|
adb_walk_gentext_indent(dt);
|
||||||
|
fprintf(out, "#%%SCHEMA: %08X\n", schema_id);
|
||||||
|
adb_walk_gentext_newline(dt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int adb_walk_gentext_comment(struct adb_walk *d, apk_blob_t comment)
|
||||||
|
{
|
||||||
|
struct adb_walk_gentext *dt = container_of(d, struct adb_walk_gentext, d);
|
||||||
|
FILE *out = dt->out;
|
||||||
|
|
||||||
|
adb_walk_gentext_indent(dt);
|
||||||
|
fprintf(out, "# "BLOB_FMT"\n", BLOB_PRINTF(comment));
|
||||||
|
adb_walk_gentext_newline(dt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int adb_walk_gentext_start_array(struct adb_walk *d, unsigned int num)
|
||||||
|
{
|
||||||
|
struct adb_walk_gentext *dt = container_of(d, struct adb_walk_gentext, d);
|
||||||
|
FILE *out = dt->out;
|
||||||
|
|
||||||
|
adb_walk_gentext_indent(dt);
|
||||||
|
fprintf(out, "# %d items\n", num);
|
||||||
|
adb_walk_gentext_newline(dt);
|
||||||
|
dt->nest++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int adb_walk_gentext_start_object(struct adb_walk *d)
|
||||||
|
{
|
||||||
|
struct adb_walk_gentext *dt = container_of(d, struct adb_walk_gentext, d);
|
||||||
|
|
||||||
|
dt->nest++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int adb_walk_gentext_end(struct adb_walk *d)
|
||||||
|
{
|
||||||
|
struct adb_walk_gentext *dt = container_of(d, struct adb_walk_gentext, d);
|
||||||
|
FILE *out = dt->out;
|
||||||
|
|
||||||
|
if (dt->line_started) {
|
||||||
|
adb_walk_gentext_indent(dt);
|
||||||
|
fprintf(out, "# empty object\n");
|
||||||
|
adb_walk_gentext_newline(dt);
|
||||||
|
}
|
||||||
|
dt->nest--;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int adb_walk_gentext_key(struct adb_walk *d, apk_blob_t key)
|
||||||
|
{
|
||||||
|
struct adb_walk_gentext *dt = container_of(d, struct adb_walk_gentext, d);
|
||||||
|
FILE *out = dt->out;
|
||||||
|
|
||||||
|
if (!APK_BLOB_IS_NULL(key)) {
|
||||||
|
if (dt->key_printed) {
|
||||||
|
fprintf(out, "\n");
|
||||||
|
adb_walk_gentext_newline(dt);
|
||||||
|
}
|
||||||
|
adb_walk_gentext_indent(dt);
|
||||||
|
fprintf(out, BLOB_FMT":", BLOB_PRINTF(key));
|
||||||
|
dt->key_printed = 1;
|
||||||
|
} else {
|
||||||
|
adb_walk_gentext_indent(dt);
|
||||||
|
fprintf(out, "-");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int adb_walk_gentext_scalar(struct adb_walk *d, apk_blob_t scalar, int multiline)
|
||||||
|
{
|
||||||
|
struct adb_walk_gentext *dt = container_of(d, struct adb_walk_gentext, d);
|
||||||
|
FILE *out = dt->out;
|
||||||
|
apk_blob_t nl = APK_BLOB_STR("\n");
|
||||||
|
|
||||||
|
adb_walk_gentext_indent(dt);
|
||||||
|
|
||||||
|
if (scalar.len >= 60 || multiline) {
|
||||||
|
/* long or multiline */
|
||||||
|
apk_blob_t l;
|
||||||
|
|
||||||
|
fprintf(out, "|\n");
|
||||||
|
adb_walk_gentext_newline(dt);
|
||||||
|
dt->nest++;
|
||||||
|
while (apk_blob_split(scalar, nl, &l, &scalar)) {
|
||||||
|
adb_walk_gentext_indent(dt);
|
||||||
|
fprintf(out, BLOB_FMT"\n", BLOB_PRINTF(l));
|
||||||
|
adb_walk_gentext_newline(dt);
|
||||||
|
}
|
||||||
|
if (scalar.len) {
|
||||||
|
adb_walk_gentext_indent(dt);
|
||||||
|
fprintf(out, BLOB_FMT"\n", BLOB_PRINTF(scalar));
|
||||||
|
adb_walk_gentext_newline(dt);
|
||||||
|
}
|
||||||
|
dt->nest--;
|
||||||
|
} else {
|
||||||
|
fprintf(out, BLOB_FMT"\n", BLOB_PRINTF(scalar));
|
||||||
|
adb_walk_gentext_newline(dt);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct adb_walk_ops adb_walk_gentext_ops = {
|
||||||
|
.schema = adb_walk_gentext_schema,
|
||||||
|
.comment = adb_walk_gentext_comment,
|
||||||
|
.start_array = adb_walk_gentext_start_array,
|
||||||
|
.start_object = adb_walk_gentext_start_object,
|
||||||
|
.end = adb_walk_gentext_end,
|
||||||
|
.key = adb_walk_gentext_key,
|
||||||
|
.scalar = adb_walk_gentext_scalar,
|
||||||
|
};
|
|
@ -160,7 +160,7 @@ static adb_val_t int_fromstring(struct adb *db, apk_blob_t val)
|
||||||
{
|
{
|
||||||
uint32_t n = apk_blob_pull_uint(&val, 10);
|
uint32_t n = apk_blob_pull_uint(&val, 10);
|
||||||
if (val.len) return ADB_ERROR(EINVAL);
|
if (val.len) return ADB_ERROR(EINVAL);
|
||||||
return adb_w_int(db, n);
|
return adb_w_int(db, n) ?: ADB_VAL_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int int_compare(struct adb *db1, adb_val_t v1, struct adb *db2, adb_val_t v2)
|
static int int_compare(struct adb *db1, adb_val_t v1, struct adb *db2, adb_val_t v2)
|
||||||
|
|
|
@ -5,218 +5,27 @@
|
||||||
#include "apk_applet.h"
|
#include "apk_applet.h"
|
||||||
#include "apk_print.h"
|
#include "apk_print.h"
|
||||||
|
|
||||||
struct adb_dump_ctx {
|
|
||||||
struct adb *db;
|
|
||||||
struct apk_trust *trust;
|
|
||||||
char prefix[128], *pfx;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct adb_db_schema {
|
|
||||||
unsigned long magic;
|
|
||||||
const struct adb_object_schema *root;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void ctx_nest(struct adb_dump_ctx *ctx, unsigned depth)
|
|
||||||
{
|
|
||||||
while (depth--) *ctx->pfx++ = ' ';
|
|
||||||
assert(ctx->pfx < &ctx->prefix[ARRAY_SIZE(ctx->prefix)]);
|
|
||||||
*ctx->pfx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ctx_unnest(struct adb_dump_ctx *ctx, unsigned depth)
|
|
||||||
{
|
|
||||||
ctx->pfx -= depth;
|
|
||||||
assert(ctx->pfx >= ctx->prefix);
|
|
||||||
*ctx->pfx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ctx_itemstart(struct adb_dump_ctx *ctx)
|
|
||||||
{
|
|
||||||
ctx->pfx[-2] = '-';
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ctx_itemdone(struct adb_dump_ctx *ctx)
|
|
||||||
{
|
|
||||||
memset(ctx->prefix, ' ', ctx->pfx - ctx->prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dump_object(struct adb_dump_ctx *ctx, const struct adb_object_schema *schema, adb_val_t v);
|
|
||||||
static void dump_adb(struct adb_dump_ctx *ctx);
|
|
||||||
|
|
||||||
static void dump_item(struct adb_dump_ctx *ctx, const char *name, const uint8_t *kind, adb_val_t v)
|
|
||||||
{
|
|
||||||
struct adb db, *origdb;
|
|
||||||
struct adb_obj o;
|
|
||||||
struct adb_object_schema *obj_schema;
|
|
||||||
char tmp[256];
|
|
||||||
apk_blob_t b, nl = APK_BLOB_STR("\n");
|
|
||||||
|
|
||||||
switch (*kind) {
|
|
||||||
case ADB_KIND_ARRAY:
|
|
||||||
obj_schema = container_of(kind, struct adb_object_schema, kind);
|
|
||||||
adb_r_obj(ctx->db, v, &o, obj_schema);
|
|
||||||
if (!adb_ra_num(&o)) return;
|
|
||||||
|
|
||||||
fprintf(stdout, "%s%s: # %u items\n", ctx->prefix, name, adb_ra_num(&o));
|
|
||||||
ctx_nest(ctx, 4);
|
|
||||||
for (size_t i = ADBI_FIRST; i <= adb_ra_num(&o); i++) {
|
|
||||||
ctx_itemstart(ctx);
|
|
||||||
dump_item(ctx, NULL, obj_schema->fields[0].kind, adb_ro_val(&o, i));
|
|
||||||
ctx_itemdone(ctx);
|
|
||||||
}
|
|
||||||
ctx_unnest(ctx, 4);
|
|
||||||
break;
|
|
||||||
case ADB_KIND_ADB:
|
|
||||||
db.hdr.schema = container_of(kind, struct adb_adb_schema, kind)->schema_id;
|
|
||||||
db.data = adb_r_blob(ctx->db, v);
|
|
||||||
origdb = ctx->db;
|
|
||||||
ctx->db = &db;
|
|
||||||
dump_adb(ctx);
|
|
||||||
ctx->db = origdb;
|
|
||||||
break;
|
|
||||||
case ADB_KIND_OBJECT:
|
|
||||||
if (name) {
|
|
||||||
fprintf(stdout, "%s%s:\n", ctx->prefix, name);
|
|
||||||
ctx_nest(ctx, 4);
|
|
||||||
}
|
|
||||||
dump_object(ctx, container_of(kind, struct adb_object_schema, kind), v);
|
|
||||||
if (name) ctx_unnest(ctx, 4);
|
|
||||||
break;
|
|
||||||
case ADB_KIND_BLOB:
|
|
||||||
case ADB_KIND_INT:;
|
|
||||||
struct adb_scalar_schema *scalar = container_of(kind, struct adb_scalar_schema, kind);
|
|
||||||
if (scalar->tostring) {
|
|
||||||
b = scalar->tostring(ctx->db, v, tmp, sizeof tmp);
|
|
||||||
} else {
|
|
||||||
b = APK_BLOB_STR("(unknown)");
|
|
||||||
}
|
|
||||||
if (!APK_BLOB_IS_NULL(b)) {
|
|
||||||
fputs(ctx->prefix, stdout);
|
|
||||||
if (name) fprintf(stdout, "%s: ", name);
|
|
||||||
if (b.len >= 60 || scalar->multiline) {
|
|
||||||
/* long or multiline */
|
|
||||||
apk_blob_t l;
|
|
||||||
fprintf(stdout, "|\n");
|
|
||||||
ctx_itemdone(ctx);
|
|
||||||
ctx_nest(ctx, 4);
|
|
||||||
while (apk_blob_split(b, nl, &l, &b)) {
|
|
||||||
fprintf(stdout, "%s"BLOB_FMT"\n",
|
|
||||||
ctx->prefix, BLOB_PRINTF(l));
|
|
||||||
}
|
|
||||||
if (b.len) {
|
|
||||||
fprintf(stdout, "%s"BLOB_FMT"\n",
|
|
||||||
ctx->prefix, BLOB_PRINTF(b));
|
|
||||||
}
|
|
||||||
ctx_unnest(ctx, 4);
|
|
||||||
} else {
|
|
||||||
fwrite(b.ptr, 1, b.len, stdout);
|
|
||||||
fputc('\n', stdout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dump_object(struct adb_dump_ctx *ctx, const struct adb_object_schema *schema, adb_val_t v)
|
|
||||||
{
|
|
||||||
size_t schema_len = 0;
|
|
||||||
struct adb_obj o;
|
|
||||||
char tmp[256];
|
|
||||||
apk_blob_t b;
|
|
||||||
|
|
||||||
adb_r_obj(ctx->db, v, &o, schema);
|
|
||||||
if (schema) {
|
|
||||||
if (schema->tostring) {
|
|
||||||
b = schema->tostring(&o, tmp, sizeof tmp);
|
|
||||||
if (!APK_BLOB_IS_NULL(b))
|
|
||||||
fprintf(stdout, "%s"BLOB_FMT"\n", ctx->prefix, BLOB_PRINTF(b));
|
|
||||||
ctx_itemdone(ctx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
schema_len = schema->num_fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = ADBI_FIRST; i < adb_ro_num(&o); i++) {
|
|
||||||
adb_val_t val = adb_ro_val(&o, i);
|
|
||||||
if (val == ADB_NULL) continue;
|
|
||||||
if (i < schema_len && schema->fields[i-1].kind != 0) {
|
|
||||||
dump_item(ctx, schema->fields[i-1].name, schema->fields[i-1].kind, val);
|
|
||||||
ctx_itemdone(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct adb_db_schema dbschemas[] = {
|
static const struct adb_db_schema dbschemas[] = {
|
||||||
{ .magic = ADB_SCHEMA_INDEX, .root = &schema_index, },
|
{ .magic = ADB_SCHEMA_INDEX, .root = &schema_index, },
|
||||||
{ .magic = ADB_SCHEMA_INSTALLED_DB, .root = &schema_idb, },
|
{ .magic = ADB_SCHEMA_INSTALLED_DB, .root = &schema_idb, },
|
||||||
{ .magic = ADB_SCHEMA_PACKAGE, .root = &schema_package },
|
{ .magic = ADB_SCHEMA_PACKAGE, .root = &schema_package },
|
||||||
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
static void dump_adb(struct adb_dump_ctx *ctx)
|
static int mmap_and_dump_adb(struct apk_trust *trust, int fd, struct apk_out *out)
|
||||||
{
|
|
||||||
struct adb_block *blk;
|
|
||||||
struct adb_sign_hdr *s;
|
|
||||||
struct adb_verify_ctx vfy = {};
|
|
||||||
const struct adb_db_schema *ds;
|
|
||||||
unsigned char *id;
|
|
||||||
uint32_t schema_magic = ctx->db->hdr.schema;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
for (ds = dbschemas; ds < &dbschemas[ARRAY_SIZE(dbschemas)]; ds++)
|
|
||||||
if (ds->magic == schema_magic) break;
|
|
||||||
if (ds >= &dbschemas[ARRAY_SIZE(dbschemas)]) ds = NULL;
|
|
||||||
|
|
||||||
adb_foreach_block(blk, ctx->db->data) {
|
|
||||||
apk_blob_t b = APK_BLOB_PTR_LEN((char*)(blk+1), ADB_BLOCK_SIZE(blk));
|
|
||||||
switch (ADB_BLOCK_TYPE(blk)) {
|
|
||||||
case ADB_BLOCK_ADB:
|
|
||||||
fprintf(stdout, "%s# ADB block, size: %d\n", ctx->prefix, ADB_BLOCK_SIZE(blk));
|
|
||||||
ctx_itemdone(ctx);
|
|
||||||
ctx->db->adb = b;
|
|
||||||
if (ds)
|
|
||||||
dump_object(ctx, ds->root, adb_r_root(ctx->db));
|
|
||||||
else
|
|
||||||
fprintf(stdout, "%s# Unrecognized schema: 0x%08x\n", ctx->prefix, schema_magic);
|
|
||||||
break;
|
|
||||||
case ADB_BLOCK_SIG:
|
|
||||||
s = (struct adb_sign_hdr*) b.ptr;
|
|
||||||
fprintf(stdout, "%s# signature: v%d ", ctx->prefix, s->sign_ver);
|
|
||||||
ctx_itemdone(ctx);
|
|
||||||
r = adb_trust_verify_signature(ctx->trust, ctx->db, &vfy, b);
|
|
||||||
switch (s->sign_ver) {
|
|
||||||
case 0:
|
|
||||||
id = (unsigned char*)(s + 1);
|
|
||||||
for (size_t j = 0; j < 16; j++)
|
|
||||||
fprintf(stdout, "%02x", id[j]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fprintf(stdout, ": %s\n", r ? apk_error_str(r) : "OK");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stdout, "%s# unknown block %d, size: %d\n",
|
|
||||||
ctx->prefix, ADB_BLOCK_TYPE(blk), ADB_BLOCK_SIZE(blk));
|
|
||||||
ctx_itemdone(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (IS_ERR(blk)) fprintf(stdout, "%s# block enumeration error: corrupt data area\n", ctx->prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mmap_and_dump_adb(struct apk_trust *trust, int fd)
|
|
||||||
{
|
{
|
||||||
struct adb db;
|
struct adb db;
|
||||||
struct adb_dump_ctx ctx = {
|
struct adb_walk_gentext td = {
|
||||||
.db = &db,
|
.d.ops = &adb_walk_gentext_ops,
|
||||||
.pfx = ctx.prefix,
|
.d.schemas = dbschemas,
|
||||||
.trust = trust,
|
.out = out->out,
|
||||||
};
|
};
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = adb_m_map(&db, fd, 0, NULL);
|
r = adb_m_map(&db, fd, 0, NULL);
|
||||||
if (r) return r;
|
if (r) return r;
|
||||||
|
|
||||||
dump_adb(&ctx);
|
adb_walk_adb(&td.d, &db, trust);
|
||||||
adb_free(&db);
|
adb_free(&db);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -228,7 +37,7 @@ static int adbdump_main(void *pctx, struct apk_ctx *ac, struct apk_string_array
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
foreach_array_item(arg, args) {
|
foreach_array_item(arg, args) {
|
||||||
r = mmap_and_dump_adb(apk_ctx_get_trust(ac), open(*arg, O_RDONLY));
|
r = mmap_and_dump_adb(apk_ctx_get_trust(ac), open(*arg, O_RDONLY), out);
|
||||||
if (r) {
|
if (r) {
|
||||||
apk_err(out, "%s: %s", *arg, apk_error_str(r));
|
apk_err(out, "%s: %s", *arg, apk_error_str(r));
|
||||||
return r;
|
return r;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
libapk_so_version = '2.99.0'
|
libapk_so_version = '2.99.0'
|
||||||
libapk_src = [
|
libapk_src = [
|
||||||
'adb.c',
|
'adb.c',
|
||||||
|
'adb_walk_adb.c',
|
||||||
|
'adb_walk_gentext.c',
|
||||||
'apk_adb.c',
|
'apk_adb.c',
|
||||||
'atom.c',
|
'atom.c',
|
||||||
'blob.c',
|
'blob.c',
|
||||||
|
|
Loading…
Reference in New Issue