summaryrefslogtreecommitdiff
path: root/src/app_adbsign.c
blob: d903c60ad5111e675a8d23f76d9eea051cd1651c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "adb.h"
#include "apk_applet.h"
#include "apk_print.h"

struct sign_ctx {
	struct apk_ctx *ac;

	struct adb db;
	struct apk_istream *is;
	struct apk_ostream *os;
	struct adb_verify_ctx vfy;

	int reset_signatures : 1;
	int signatures_written : 1;
};

#define ADBSIGN_OPTIONS(OPT) \
	OPT(OPT_ADBSIGN_reset_signatures,	"reset-signatures")

APK_OPT_APPLET(option_desc, ADBSIGN_OPTIONS);

static int option_parse_applet(void *pctx, struct apk_ctx *ac, int optch, const char *optarg)
{
	struct sign_ctx *ctx = (struct sign_ctx *) pctx;

	switch (optch) {
	case OPT_ADBSIGN_reset_signatures:
		ctx->reset_signatures = 1;
		break;
	default:
		return -ENOTSUP;
	}
	return 0;
}

static const struct apk_option_group optgroup_applet = {
	.desc = option_desc,
	.parse = option_parse_applet,
};

static int process_signatures(struct sign_ctx *ctx)
{
	int r;

	if (ctx->signatures_written) return 0;
	ctx->signatures_written = 1;
	r = adb_trust_write_signatures(apk_ctx_get_trust(ctx->ac), &ctx->db, &ctx->vfy, ctx->os);
	if (r < 0) apk_ostream_cancel(ctx->os, r);
	return r;
}

static int process_block(struct adb *db, struct adb_block *blk, struct apk_istream *is)
{
	struct sign_ctx *ctx = container_of(db, struct sign_ctx, db);
	int r;

	switch (adb_block_type(blk)) {
	case ADB_BLOCK_ADB:
		adb_c_header(ctx->os, db);
		return adb_c_block_copy(ctx->os, blk, is, &ctx->vfy);
	case ADB_BLOCK_SIG:
		if (ctx->reset_signatures)
			break;
		return adb_c_block_copy(ctx->os, blk, is, NULL);
	default:
		r = process_signatures(ctx);
		if (r < 0) return r;
		return adb_c_block_copy(ctx->os, blk, is, NULL);
	}
	return 0;
}

static int adbsign_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *args)
{
	struct apk_out *out = &ac->out;
	struct sign_ctx *ctx = pctx;
	adb_comp_t comp;
	char **arg;
	int r;

	ctx->ac = ac;
	foreach_array_item(arg, args) {
		memset(&ctx->vfy, 0, sizeof ctx->vfy);
		struct apk_istream *is = adb_decompress(apk_istream_from_file_mmap(AT_FDCWD, *arg), &comp);
		ctx->os = adb_compress(apk_ostream_to_file(AT_FDCWD, *arg, 0644), comp);
		apk_ostream_cancel(ctx->os, adb_m_process(&ctx->db, is, 0, 0, process_block));
		apk_ostream_cancel(ctx->os, process_signatures(ctx));
		adb_free(&ctx->db);
		r = apk_ostream_close(ctx->os);
		if (r) apk_err(out, "%s: %s", *arg, apk_error_str(r));
	}

	return 0;
}

static struct apk_applet apk_adbsign = {
	.name = "adbsign",
	.context_size = sizeof(struct sign_ctx),
	.optgroups = { &optgroup_global, &optgroup_signing, &optgroup_applet },
	.main = adbsign_main,
};

APK_DEFINE_APPLET(apk_adbsign);