1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * otrx 4 * 5 * Copyright (C) 2015-2017 Rafał Miłecki <zajec5@gmail.com> 6 */ 7 8 #include <byteswap.h> 9 #include <endian.h> 10 #include <errno.h> 11 #include <stdint.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <sys/stat.h> 16 #include <unistd.h> 17 18 #if !defined(__BYTE_ORDER) 19 #error "Unknown byte order" 20 #endif 21 22 #if __BYTE_ORDER == __BIG_ENDIAN 23 #define cpu_to_le32(x) bswap_32(x) 24 #define le32_to_cpu(x) bswap_32(x) 25 #elif __BYTE_ORDER == __LITTLE_ENDIAN 26 #define cpu_to_le32(x) (x) 27 #define le32_to_cpu(x) (x) 28 #else 29 #error "Unsupported endianness" 30 #endif 31 32 #define TRX_MAGIC 0x30524448 33 #define TRX_FLAGS_OFFSET 12 34 #define TRX_MAX_PARTS 3 35 36 struct trx_header { 37 uint32_t magic; 38 uint32_t length; 39 uint32_t crc32; 40 uint16_t flags; 41 uint16_t version; 42 uint32_t offset[3]; 43 }; 44 45 struct otrx_part { 46 int idx; 47 size_t offset; 48 size_t length; 49 }; 50 51 struct otrx_ctx { 52 FILE *fp; 53 struct trx_header hdr; 54 struct otrx_part parts[TRX_MAX_PARTS]; /* Sorted partitions */ 55 }; 56 57 char *trx_path; 58 size_t trx_offset = 0; 59 char *partition[TRX_MAX_PARTS] = {}; 60 61 static inline size_t otrx_min(size_t x, size_t y) { 62 return x < y ? x : y; 63 } 64 65 /************************************************** 66 * CRC32 67 **************************************************/ 68 69 static const uint32_t crc32_tbl[] = { 70 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 71 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 72 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 73 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 74 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 75 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 76 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 77 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 78 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 79 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 80 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 81 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 82 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 83 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 84 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 85 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 86 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 87 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 88 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 89 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 90 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 91 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 92 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 93 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 94 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 95 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 96 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 97 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 98 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 99 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 100 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 101 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 102 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 103 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 104 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 105 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 106 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 107 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 108 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 109 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 110 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 111 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 112 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 113 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 114 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 115 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 116 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 117 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 118 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 119 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 120 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 121 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 122 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 123 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 124 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 125 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 126 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 127 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 128 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 129 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 130 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 131 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 132 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 133 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, 134 }; 135 136 uint32_t otrx_crc32(uint32_t crc, uint8_t *buf, size_t len) { 137 while (len) { 138 crc = crc32_tbl[(crc ^ *buf) & 0xff] ^ (crc >> 8); 139 buf++; 140 len--; 141 } 142 143 return crc; 144 } 145 146 /************************************************** 147 * Helpers 148 **************************************************/ 149 150 static FILE *otrx_open(const char *pathname, const char *mode) { 151 if (strcmp(pathname, "-")) 152 return fopen(pathname, mode); 153 154 if (isatty(fileno(stdin))) { 155 fprintf(stderr, "Reading from TTY stdin is unsupported\n"); 156 return NULL; 157 } 158 159 return stdin; 160 } 161 162 static int otrx_skip(FILE *fp, size_t length) 163 { 164 if (fseek(fp, length, SEEK_CUR)) { 165 uint8_t buf[1024]; 166 size_t bytes; 167 168 do { 169 bytes = fread(buf, 1, otrx_min(sizeof(buf), length), fp); 170 if (bytes <= 0) 171 return -EIO; 172 length -= bytes; 173 } while (length); 174 } 175 176 return 0; 177 } 178 179 static void otrx_close(FILE *fp) { 180 if (fp != stdin) 181 fclose(fp); 182 } 183 184 static int otrx_part_compar(const void *a, const void *b) 185 { 186 const struct otrx_part *partA = a; 187 const struct otrx_part *partB = b; 188 189 if (!partA->offset) 190 return 1; 191 if (!partB->offset) 192 return -1; 193 194 return partA->offset - partB->offset; 195 } 196 197 static int otrx_open_parse(const char *pathname, const char *mode, 198 struct otrx_ctx *otrx) 199 { 200 size_t length; 201 size_t bytes; 202 int err; 203 int i; 204 205 otrx->fp = otrx_open(pathname, mode); 206 if (!otrx->fp) { 207 fprintf(stderr, "Couldn't open %s\n", pathname); 208 err = -EACCES; 209 goto err_out; 210 } 211 212 if (trx_offset && otrx_skip(otrx->fp, trx_offset)) { 213 fprintf(stderr, "Couldn't skip first %zd B\n", trx_offset); 214 err = -EIO; 215 goto err_close; 216 } 217 218 bytes = fread(&otrx->hdr, 1, sizeof(otrx->hdr), otrx->fp); 219 if (bytes != sizeof(otrx->hdr)) { 220 fprintf(stderr, "Couldn't read %s header\n", pathname); 221 err = -EIO; 222 goto err_close; 223 } 224 225 if (le32_to_cpu(otrx->hdr.magic) != TRX_MAGIC) { 226 fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(otrx->hdr.magic)); 227 err = -EINVAL; 228 goto err_close; 229 } 230 231 length = le32_to_cpu(otrx->hdr.length); 232 if (length < sizeof(otrx->hdr)) { 233 fprintf(stderr, "Length read from TRX too low (%zu B)\n", length); 234 err = -EINVAL; 235 goto err_close; 236 } 237 238 for (i = 0; i < TRX_MAX_PARTS; i++) { 239 otrx->parts[i].idx = i; 240 otrx->parts[i].offset = le32_to_cpu(otrx->hdr.offset[i]); 241 } 242 qsort(otrx->parts, TRX_MAX_PARTS, sizeof(otrx->parts[0]), otrx_part_compar); 243 244 /* Calculate length of every partition */ 245 for (i = 0; i < TRX_MAX_PARTS; i++) { 246 if (otrx->parts[i].offset) { 247 if (i + 1 >= TRX_MAX_PARTS || !otrx->parts[i + 1].offset) 248 otrx->parts[i].length = le32_to_cpu(otrx->hdr.length) - otrx->parts[i].offset; 249 else 250 otrx->parts[i].length = otrx->parts[i + 1].offset - otrx->parts[i].offset; 251 } 252 } 253 254 return 0; 255 256 err_close: 257 otrx_close(otrx->fp); 258 err_out: 259 return err; 260 } 261 262 /************************************************** 263 * Check 264 **************************************************/ 265 266 static void otrx_check_parse_options(int argc, char **argv) { 267 int c; 268 269 while ((c = getopt(argc, argv, "o:")) != -1) { 270 switch (c) { 271 case 'o': 272 trx_offset = atoi(optarg); 273 break; 274 } 275 } 276 } 277 278 static int otrx_check(int argc, char **argv) { 279 struct otrx_ctx otrx = { }; 280 size_t bytes, length; 281 uint8_t buf[1024]; 282 uint32_t crc32; 283 int err = 0; 284 285 if (argc < 3) { 286 fprintf(stderr, "No TRX file passed\n"); 287 err = -EINVAL; 288 goto out; 289 } 290 trx_path = argv[2]; 291 292 optind = 3; 293 otrx_check_parse_options(argc, argv); 294 295 err = otrx_open_parse(trx_path, "r", &otrx); 296 if (err) { 297 fprintf(stderr, "Couldn't open & parse %s: %d\n", trx_path, err); 298 err = -EACCES; 299 goto out; 300 } 301 302 crc32 = 0xffffffff; 303 crc32 = otrx_crc32(crc32, (uint8_t *)&otrx.hdr + TRX_FLAGS_OFFSET, sizeof(otrx.hdr) - TRX_FLAGS_OFFSET); 304 length = le32_to_cpu(otrx.hdr.length) - sizeof(otrx.hdr); 305 while ((bytes = fread(buf, 1, otrx_min(sizeof(buf), length), otrx.fp)) > 0) { 306 crc32 = otrx_crc32(crc32, buf, bytes); 307 length -= bytes; 308 } 309 310 if (length) { 311 fprintf(stderr, "Couldn't read last %zd B of data from %s\n", length, trx_path); 312 err = -EIO; 313 goto err_close; 314 } 315 316 if (crc32 != le32_to_cpu(otrx.hdr.crc32)) { 317 fprintf(stderr, "Invalid data crc32: 0x%08x instead of 0x%08x\n", crc32, le32_to_cpu(otrx.hdr.crc32)); 318 err = -EINVAL; 319 goto err_close; 320 } 321 322 printf("Found a valid TRX version %d\n", le32_to_cpu(otrx.hdr.version)); 323 324 err_close: 325 otrx_close(otrx.fp); 326 out: 327 return err; 328 } 329 330 /************************************************** 331 * Create 332 **************************************************/ 333 334 static ssize_t otrx_create_append_file(FILE *trx, const char *in_path) { 335 FILE *in; 336 size_t bytes; 337 ssize_t length = 0; 338 uint8_t buf[1024]; 339 340 in = fopen(in_path, "r"); 341 if (!in) { 342 fprintf(stderr, "Couldn't open %s\n", in_path); 343 return -EACCES; 344 } 345 346 while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) { 347 if (fwrite(buf, 1, bytes, trx) != bytes) { 348 fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, trx_path); 349 length = -EIO; 350 break; 351 } 352 length += bytes; 353 } 354 355 fclose(in); 356 357 return length; 358 } 359 360 static ssize_t otrx_create_append_zeros(FILE *trx, size_t length) { 361 uint8_t *buf; 362 363 buf = malloc(length); 364 if (!buf) 365 return -ENOMEM; 366 memset(buf, 0, length); 367 368 if (fwrite(buf, 1, length, trx) != length) { 369 fprintf(stderr, "Couldn't write %zu B to %s\n", length, trx_path); 370 free(buf); 371 return -EIO; 372 } 373 374 free(buf); 375 376 return length; 377 } 378 379 static ssize_t otrx_create_align(FILE *trx, size_t curr_offset, size_t alignment) { 380 if (curr_offset & (alignment - 1)) { 381 size_t length = alignment - (curr_offset % alignment); 382 return otrx_create_append_zeros(trx, length); 383 } 384 385 return 0; 386 } 387 388 static int otrx_create_write_hdr(FILE *trx, struct trx_header *hdr) { 389 size_t bytes, length; 390 uint8_t buf[1024]; 391 uint32_t crc32; 392 393 hdr->version = 1; 394 395 fseek(trx, 0, SEEK_SET); 396 bytes = fwrite(hdr, 1, sizeof(struct trx_header), trx); 397 if (bytes != sizeof(struct trx_header)) { 398 fprintf(stderr, "Couldn't write TRX header to %s\n", trx_path); 399 return -EIO; 400 } 401 402 length = le32_to_cpu(hdr->length); 403 404 crc32 = 0xffffffff; 405 fseek(trx, TRX_FLAGS_OFFSET, SEEK_SET); 406 length -= TRX_FLAGS_OFFSET; 407 while ((bytes = fread(buf, 1, otrx_min(sizeof(buf), length), trx)) > 0) { 408 crc32 = otrx_crc32(crc32, buf, bytes); 409 length -= bytes; 410 } 411 hdr->crc32 = cpu_to_le32(crc32); 412 413 fseek(trx, 0, SEEK_SET); 414 bytes = fwrite(hdr, 1, sizeof(struct trx_header), trx); 415 if (bytes != sizeof(struct trx_header)) { 416 fprintf(stderr, "Couldn't write TRX header to %s\n", trx_path); 417 return -EIO; 418 } 419 420 return 0; 421 } 422 423 static int otrx_create(int argc, char **argv) { 424 FILE *trx; 425 struct trx_header hdr = {}; 426 ssize_t sbytes; 427 size_t curr_idx = 0; 428 size_t curr_offset = sizeof(hdr); 429 char *e; 430 uint32_t magic; 431 int c; 432 int err = 0; 433 434 hdr.magic = cpu_to_le32(TRX_MAGIC); 435 436 if (argc < 3) { 437 fprintf(stderr, "No TRX file passed\n"); 438 err = -EINVAL; 439 goto out; 440 } 441 trx_path = argv[2]; 442 443 trx = fopen(trx_path, "w+"); 444 if (!trx) { 445 fprintf(stderr, "Couldn't open %s\n", trx_path); 446 err = -EACCES; 447 goto out; 448 } 449 fseek(trx, curr_offset, SEEK_SET); 450 451 optind = 3; 452 while ((c = getopt(argc, argv, "f:A:a:b:M:")) != -1) { 453 switch (c) { 454 case 'f': 455 if (curr_idx >= TRX_MAX_PARTS) { 456 err = -ENOSPC; 457 fprintf(stderr, "Reached TRX partitions limit, no place for %s\n", optarg); 458 goto err_close; 459 } 460 461 sbytes = otrx_create_append_file(trx, optarg); 462 if (sbytes < 0) { 463 fprintf(stderr, "Failed to append file %s\n", optarg); 464 } else { 465 hdr.offset[curr_idx++] = curr_offset; 466 curr_offset += sbytes; 467 } 468 469 sbytes = otrx_create_align(trx, curr_offset, 4); 470 if (sbytes < 0) 471 fprintf(stderr, "Failed to append zeros\n"); 472 else 473 curr_offset += sbytes; 474 475 break; 476 case 'A': 477 sbytes = otrx_create_append_file(trx, optarg); 478 if (sbytes < 0) { 479 fprintf(stderr, "Failed to append file %s\n", optarg); 480 } else { 481 curr_offset += sbytes; 482 } 483 484 sbytes = otrx_create_align(trx, curr_offset, 4); 485 if (sbytes < 0) 486 fprintf(stderr, "Failed to append zeros\n"); 487 else 488 curr_offset += sbytes; 489 break; 490 case 'a': 491 sbytes = otrx_create_align(trx, curr_offset, strtol(optarg, NULL, 0)); 492 if (sbytes < 0) 493 fprintf(stderr, "Failed to append zeros\n"); 494 else 495 curr_offset += sbytes; 496 break; 497 case 'b': 498 sbytes = strtol(optarg, NULL, 0) - curr_offset; 499 if (sbytes < 0) { 500 fprintf(stderr, "Current TRX length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset, strtol(optarg, NULL, 0)); 501 } else { 502 sbytes = otrx_create_append_zeros(trx, sbytes); 503 if (sbytes < 0) 504 fprintf(stderr, "Failed to append zeros\n"); 505 else 506 curr_offset += sbytes; 507 } 508 break; 509 case 'M': 510 errno = 0; 511 magic = strtoul(optarg, &e, 0); 512 if (errno || (e == optarg) || *e) 513 fprintf(stderr, "illegal magic string %s\n", optarg); 514 else 515 hdr.magic = cpu_to_le32(magic); 516 break; 517 } 518 if (err) 519 break; 520 } 521 522 sbytes = otrx_create_align(trx, curr_offset, 0x1000); 523 if (sbytes < 0) 524 fprintf(stderr, "Failed to append zeros\n"); 525 else 526 curr_offset += sbytes; 527 528 hdr.length = curr_offset; 529 otrx_create_write_hdr(trx, &hdr); 530 err_close: 531 fclose(trx); 532 out: 533 return err; 534 } 535 536 /************************************************** 537 * Extract 538 **************************************************/ 539 540 static void otrx_extract_parse_options(int argc, char **argv) { 541 int c; 542 543 while ((c = getopt(argc, argv, "c:e:o:1:2:3:")) != -1) { 544 switch (c) { 545 case 'o': 546 trx_offset = atoi(optarg); 547 break; 548 case '1': 549 partition[0] = optarg; 550 break; 551 case '2': 552 partition[1] = optarg; 553 break; 554 case '3': 555 partition[2] = optarg; 556 break; 557 } 558 } 559 } 560 561 static int otrx_extract_copy(struct otrx_ctx *otrx, size_t length, char *out_path) { 562 FILE *out; 563 size_t bytes; 564 uint8_t *buf; 565 int err = 0; 566 567 out = fopen(out_path, "w"); 568 if (!out) { 569 fprintf(stderr, "Couldn't open %s\n", out_path); 570 err = -EACCES; 571 goto out; 572 } 573 574 buf = malloc(length); 575 if (!buf) { 576 fprintf(stderr, "Couldn't alloc %zu B buffer\n", length); 577 err = -ENOMEM; 578 goto err_close; 579 } 580 581 bytes = fread(buf, 1, length, otrx->fp); 582 if (bytes != length) { 583 fprintf(stderr, "Couldn't read %zu B of data from %s\n", length, trx_path); 584 err = -ENOMEM; 585 goto err_free_buf; 586 }; 587 588 bytes = fwrite(buf, 1, length, out); 589 if (bytes != length) { 590 fprintf(stderr, "Couldn't write %zu B to %s\n", length, out_path); 591 err = -ENOMEM; 592 goto err_free_buf; 593 } 594 595 printf("Extracted 0x%zx bytes into %s\n", length, out_path); 596 597 err_free_buf: 598 free(buf); 599 err_close: 600 fclose(out); 601 out: 602 return err; 603 } 604 605 static int otrx_extract(int argc, char **argv) { 606 struct otrx_ctx otrx = { }; 607 int i; 608 int err = 0; 609 610 if (argc < 3) { 611 fprintf(stderr, "No TRX file passed\n"); 612 err = -EINVAL; 613 goto err_out; 614 } 615 trx_path = argv[2]; 616 617 optind = 3; 618 otrx_extract_parse_options(argc, argv); 619 620 err = otrx_open_parse(trx_path, "r", &otrx); 621 if (err) { 622 fprintf(stderr, "Couldn't open & parse %s: %d\n", trx_path, err); 623 err = -EACCES; 624 goto err_out; 625 } 626 627 for (i = 0; i < TRX_MAX_PARTS; i++) { 628 struct otrx_part *part = &otrx.parts[i]; 629 630 if (!part->offset && partition[part->idx]) 631 printf("TRX doesn't contain partition %d, can't extract %s\n", part->idx + 1, partition[part->idx]); 632 if (!part->offset || !partition[part->idx]) 633 otrx_skip(otrx.fp, part->length); 634 else 635 otrx_extract_copy(&otrx, part->length, partition[part->idx]); 636 } 637 638 otrx_close(otrx.fp); 639 err_out: 640 return err; 641 } 642 643 /************************************************** 644 * Start 645 **************************************************/ 646 647 static void usage() { 648 printf("Usage:\n"); 649 printf("\n"); 650 printf("Checking TRX file:\n"); 651 printf("\totrx check <file> [options]\tcheck if file is a valid TRX\n"); 652 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n"); 653 printf("\n"); 654 printf("Creating new TRX file:\n"); 655 printf("\totrx create <file> [options] [partitions]\n"); 656 printf("\t-f file\t\t\t\t[partition] start new partition with content copied from file\n"); 657 printf("\t-A file\t\t\t\t[partition] append current partition with content copied from file\n"); 658 printf("\t-a alignment\t\t\t[partition] align current partition\n"); 659 printf("\t-b offset\t\t\t[partition] append zeros to partition till reaching absolute offset\n"); 660 printf("\n"); 661 printf("Extracting from TRX file:\n"); 662 printf("\totrx extract <file> [options]\textract partitions from TRX file\n"); 663 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n"); 664 printf("\t-1 file\t\t\t\tfile to extract 1st partition to (optional)\n"); 665 printf("\t-2 file\t\t\t\tfile to extract 2nd partition to (optional)\n"); 666 printf("\t-3 file\t\t\t\tfile to extract 3rd partition to (optional)\n"); 667 } 668 669 int main(int argc, char **argv) { 670 if (argc > 1) { 671 if (!strcmp(argv[1], "check")) 672 return otrx_check(argc, argv); 673 else if (!strcmp(argv[1], "create")) 674 return otrx_create(argc, argv); 675 else if (!strcmp(argv[1], "extract")) 676 return otrx_extract(argc, argv); 677 } 678 679 usage(); 680 return 0; 681 } 682
This page was automatically generated by LXR 0.3.1. • OpenWrt