2f305cf4844ed0985d681fe43fba4ad4821fa7a0
[openwrt/openwrt.git] / package / utils / otrx / src / otrx.c
1 /*
2 * otrx
3 *
4 * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 */
11
12 #include <errno.h>
13 #include <stdint.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17
18 #if __BYTE_ORDER == __BIG_ENDIAN
19 #define cpu_to_le32(x) bswap_32(x)
20 #define le32_to_cpu(x) bswap_32(x)
21 #elif __BYTE_ORDER == __LITTLE_ENDIAN
22 #define cpu_to_le32(x) (x)
23 #define le32_to_cpu(x) (x)
24 #else
25 #error "Unsupported endianness"
26 #endif
27
28 #define TRX_MAGIC 0x30524448
29 #define TRX_FLAGS_OFFSET 12
30 #define TRX_MAX_PARTS 3
31
32 struct trx_header {
33 uint32_t magic;
34 uint32_t length;
35 uint32_t crc32;
36 uint16_t flags;
37 uint16_t version;
38 uint32_t offset[3];
39 };
40
41 enum mode {
42 MODE_UNKNOWN,
43 MODE_CHECK,
44 MODE_EXTRACT,
45 };
46
47 enum mode mode = MODE_UNKNOWN;
48
49 char *trx_path;
50 size_t trx_offset = 0;
51 char *partition[TRX_MAX_PARTS] = {};
52
53 /**************************************************
54 * CRC32
55 **************************************************/
56
57 uint32_t otrx_crc32(uint8_t *buf, size_t len) {
58 static const uint32_t t[] = {
59 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
60 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
61 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
62 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
63 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
64 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
65 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
66 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
67 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
68 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
69 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
70 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
71 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
72 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
73 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
74 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
75 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
76 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
77 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
78 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
79 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
80 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
81 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
82 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
83 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
84 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
85 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
86 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
87 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
88 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
89 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
90 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
91 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
92 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
93 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
94 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
95 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
96 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
97 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
98 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
99 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
100 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
101 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
102 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
103 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
104 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
105 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
106 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
107 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
108 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
109 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
110 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
111 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
112 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
113 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
114 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
115 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
116 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
117 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
118 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
119 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
120 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
121 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
122 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
123 };
124 uint32_t crc = 0xffffffff;
125
126 while (len) {
127 crc = t[(crc ^ *buf) & 0xff] ^ (crc >> 8);
128 buf++;
129 len--;
130 }
131
132 return crc;
133 }
134
135 /**************************************************
136 * Check
137 **************************************************/
138
139 static int otrx_check() {
140 FILE *trx;
141 struct trx_header hdr;
142 size_t bytes, length;
143 uint8_t *buf;
144 uint32_t crc32;
145 int err = 0;
146
147 trx = fopen(trx_path, "r");
148 if (!trx) {
149 fprintf(stderr, "Couldn't open %s\n", trx_path);
150 err = -EACCES;
151 goto out;
152 }
153
154 fseek(trx, trx_offset, SEEK_SET);
155 bytes = fread(&hdr, 1, sizeof(hdr), trx);
156 if (bytes != sizeof(hdr)) {
157 fprintf(stderr, "Couldn't read %s header\n", trx_path);
158 err = -EIO;
159 goto err_close;
160 }
161
162 if (le32_to_cpu(hdr.magic) != TRX_MAGIC) {
163 fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr.magic));
164 err = -EINVAL;
165 goto err_close;
166 }
167
168 length = le32_to_cpu(hdr.length);
169 buf = malloc(length);
170 if (!buf) {
171 fprintf(stderr, "Couldn't alloc %d B buffer\n", length);
172 err = -ENOMEM;
173 goto err_close;
174 }
175
176 fseek(trx, trx_offset, SEEK_SET);
177 bytes = fread(buf, 1, length, trx);
178 if (bytes != length) {
179 fprintf(stderr, "Couldn't read %d B of data from %s\n", length, trx_path);
180 err = -ENOMEM;
181 goto err_free_buf;
182 }
183
184 crc32 = otrx_crc32(buf + TRX_FLAGS_OFFSET, length - TRX_FLAGS_OFFSET);
185 if (crc32 != le32_to_cpu(hdr.crc32)) {
186 fprintf(stderr, "Invalid data crc32: 0x%08x instead of 0x%08x\n", crc32, le32_to_cpu(hdr.crc32));
187 err = -EINVAL;
188 goto err_free_buf;
189 }
190
191 printf("Found a valid TRX version %d\n", le32_to_cpu(hdr.version));
192
193 err_free_buf:
194 free(buf);
195 err_close:
196 fclose(trx);
197 out:
198 return err;
199 }
200
201 /**************************************************
202 * Extract
203 **************************************************/
204
205 static int otrx_extract_copy(FILE *trx, size_t offset, size_t length, char *out_path) {
206 FILE *out;
207 size_t bytes;
208 uint8_t *buf;
209 int err = 0;
210
211 out = fopen(out_path, "w");
212 if (!out) {
213 fprintf(stderr, "Couldn't open %s\n", out_path);
214 err = -EACCES;
215 goto out;
216 }
217
218 buf = malloc(length);
219 if (!buf) {
220 fprintf(stderr, "Couldn't alloc %zu B buffer\n", length);
221 err = -ENOMEM;
222 goto err_close;
223 }
224
225 fseek(trx, offset, SEEK_SET);
226 bytes = fread(buf, 1, length, trx);
227 if (bytes != length) {
228 fprintf(stderr, "Couldn't read %zu B of data from %s\n", length, trx_path);
229 err = -ENOMEM;
230 goto err_free_buf;
231 };
232
233 bytes = fwrite(buf, 1, length, out);
234 if (bytes != length) {
235 fprintf(stderr, "Couldn't write %zu B to %s\n", length, out_path);
236 err = -ENOMEM;
237 goto err_free_buf;
238 }
239
240 printf("Extracted 0x%zx bytes into %s\n", length, out_path);
241
242 err_free_buf:
243 free(buf);
244 err_close:
245 fclose(out);
246 out:
247 return err;
248 }
249
250 static int otrx_extract() {
251 FILE *trx;
252 struct trx_header hdr;
253 size_t bytes;
254 int i;
255 int err = 0;
256
257 trx = fopen(trx_path, "r");
258 if (!trx) {
259 fprintf(stderr, "Couldn't open %s\n", trx_path);
260 err = -EACCES;
261 goto out;
262 }
263
264 fseek(trx, trx_offset, SEEK_SET);
265 bytes = fread(&hdr, 1, sizeof(hdr), trx);
266 if (bytes != sizeof(hdr)) {
267 fprintf(stderr, "Couldn't read %s header\n", trx_path);
268 err = -EIO;
269 goto err_close;
270 }
271
272 if (le32_to_cpu(hdr.magic) != TRX_MAGIC) {
273 fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr.magic));
274 err = -EINVAL;
275 goto err_close;
276 }
277
278 for (i = 0; i < TRX_MAX_PARTS; i++) {
279 size_t length;
280
281 if (!partition[i])
282 continue;
283 if (!hdr.offset[i]) {
284 printf("TRX doesn't contain partition %d, can't extract %s\n", i + 1, partition[i]);
285 continue;
286 }
287
288 if (i + 1 >= TRX_MAX_PARTS || !hdr.offset[i + 1])
289 length = le32_to_cpu(hdr.length) - le32_to_cpu(hdr.offset[i]);
290 else
291 length = le32_to_cpu(hdr.offset[i + 1]) - le32_to_cpu(hdr.offset[i]);
292
293 otrx_extract_copy(trx, trx_offset + le32_to_cpu(hdr.offset[i]), length, partition[i]);
294 }
295
296 err_close:
297 fclose(trx);
298 out:
299 return err;
300 }
301
302 /**************************************************
303 * Start
304 **************************************************/
305
306 static void parse_options(int argc, char **argv) {
307 int c;
308
309 while ((c = getopt(argc, argv, "c:e:o:1:2:3:")) != -1) {
310 switch (c) {
311 case 'c':
312 mode = MODE_CHECK;
313 trx_path = optarg;
314 break;
315 case 'e':
316 mode = MODE_EXTRACT;
317 trx_path = optarg;
318 break;
319 case 'o':
320 trx_offset = atoi(optarg);
321 break;
322 case '1':
323 partition[0] = optarg;
324 break;
325 case '2':
326 partition[1] = optarg;
327 break;
328 case '3':
329 partition[2] = optarg;
330 break;
331 }
332 }
333 }
334
335 static void usage() {
336 printf("Usage:\n");
337 printf("\n");
338 printf("Checking TRX file:\n");
339 printf("\t-c file\t\tcheck if file is a valid TRX\n");
340 printf("\t-o offset\toffset of TRX data in file (default: 0)\n");
341 printf("\n");
342 printf("Extracting from TRX file:\n");
343 printf("\t-e file\t\tfile with TRX to extract from\n");
344 printf("\t-o offset\toffset of TRX data in file (default: 0)\n");
345 printf("\t-1 file\t\tfile to extract 1st partition to (optional)\n");
346 printf("\t-2 file\t\tfile to extract 2nd partition to (optional)\n");
347 printf("\t-3 file\t\tfile to extract 3rd partition to (optional)\n");
348 }
349
350 int main(int argc, char **argv) {
351 parse_options(argc, argv);
352
353 switch (mode) {
354 case MODE_CHECK:
355 return otrx_check();
356 case MODE_EXTRACT:
357 return otrx_extract();
358 default:
359 usage();
360 }
361
362 return 0;
363 }