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