1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * oseama 4 * 5 * Copyright (C) 2016 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 <unistd.h> 16 17 #include "md5.h" 18 19 #if !defined(__BYTE_ORDER) 20 #error "Unknown byte order" 21 #endif 22 23 #if __BYTE_ORDER == __BIG_ENDIAN 24 #define cpu_to_be32(x) (x) 25 #define be32_to_cpu(x) (x) 26 #define cpu_to_be16(x) (x) 27 #define be16_to_cpu(x) (x) 28 #elif __BYTE_ORDER == __LITTLE_ENDIAN 29 #define cpu_to_be32(x) bswap_32(x) 30 #define be32_to_cpu(x) bswap_32(x) 31 #define cpu_to_be16(x) bswap_16(x) 32 #define be16_to_cpu(x) bswap_16(x) 33 #else 34 #error "Unsupported endianness" 35 #endif 36 37 #define SEAMA_MAGIC 0x5ea3a417 38 39 struct seama_seal_header { 40 uint32_t magic; 41 uint16_t reserved; 42 uint16_t metasize; 43 uint32_t imagesize; 44 } __attribute__ ((packed)); 45 46 struct seama_entity_header { 47 uint32_t magic; 48 uint16_t reserved; 49 uint16_t metasize; 50 uint32_t imagesize; 51 uint8_t md5[16]; 52 } __attribute__ ((packed)); 53 54 char *seama_path; 55 int entity_idx = -1; 56 char *out_path; 57 58 static inline size_t oseama_min(size_t x, size_t y) { 59 return x < y ? x : y; 60 } 61 62 /************************************************** 63 * Helpers 64 **************************************************/ 65 66 static FILE *oseama_open(const char *pathname, const char *mode) { 67 if (strcmp(pathname, "-")) 68 return fopen(pathname, mode); 69 70 if (isatty(fileno(stdin))) { 71 fprintf(stderr, "Reading from TTY stdin is unsupported\n"); 72 return NULL; 73 } 74 75 return stdin; 76 } 77 78 static int oseama_skip(FILE *fp, size_t length) 79 { 80 if (fseek(fp, length, SEEK_CUR)) { 81 uint8_t buf[1024]; 82 size_t bytes; 83 84 do { 85 bytes = fread(buf, 1, oseama_min(sizeof(buf), length), fp); 86 if (bytes <= 0) 87 return -EIO; 88 length -= bytes; 89 } while (length); 90 } 91 92 return 0; 93 } 94 95 static void oseama_close(FILE *fp) { 96 if (fp != stdin) 97 fclose(fp); 98 } 99 100 /************************************************** 101 * Info 102 **************************************************/ 103 104 static void oseama_info_parse_options(int argc, char **argv) { 105 int c; 106 107 while ((c = getopt(argc, argv, "e:")) != -1) { 108 switch (c) { 109 case 'e': 110 entity_idx = atoi(optarg); 111 break; 112 } 113 } 114 } 115 116 static int oseama_info_entities(FILE *seama, size_t *pos) { 117 struct seama_entity_header hdr; 118 size_t bytes, metasize, imagesize; 119 uint8_t buf[1024]; 120 char *end, *tmp; 121 int i = 0; 122 int err = 0; 123 124 while ((bytes = fread(&hdr, 1, sizeof(hdr), seama)) == sizeof(hdr)) { 125 *pos += bytes; 126 127 if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) { 128 fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic)); 129 err = -EINVAL; 130 goto err_out; 131 } 132 metasize = be16_to_cpu(hdr.metasize); 133 imagesize = be32_to_cpu(hdr.imagesize); 134 135 if (entity_idx >= 0 && i != entity_idx) { 136 oseama_skip(seama, metasize + imagesize); 137 *pos += metasize + imagesize; 138 i++; 139 continue; 140 } 141 142 if (metasize >= sizeof(buf)) { 143 fprintf(stderr, "Too small buffer (%zu B) to read all meta info (%zd B)\n", sizeof(buf), metasize); 144 err = -EINVAL; 145 goto err_out; 146 } 147 148 if (entity_idx < 0) 149 printf("\n"); 150 printf("Entity offset:\t%ld\n", *pos - sizeof(hdr)); 151 printf("Entity size:\t%zd\n", sizeof(hdr) + metasize + imagesize); 152 printf("Meta size:\t%zd\n", metasize); 153 printf("Image size:\t%zd\n", imagesize); 154 155 bytes = fread(buf, 1, metasize, seama); 156 if (bytes != metasize) { 157 fprintf(stderr, "Couldn't read %zd B of meta\n", metasize); 158 err = -EIO; 159 goto err_out; 160 } 161 *pos += bytes; 162 163 end = (char *)&buf[metasize - 1]; 164 *end = '\0'; 165 for (tmp = (char *)buf; tmp < end && strlen(tmp); tmp += strlen(tmp) + 1) { 166 printf("Meta entry:\t%s\n", tmp); 167 } 168 169 oseama_skip(seama, imagesize); 170 *pos += imagesize; 171 i++; 172 } 173 174 err_out: 175 return err; 176 } 177 178 static int oseama_info(int argc, char **argv) { 179 FILE *seama; 180 struct seama_seal_header hdr; 181 size_t bytes; 182 uint16_t metasize; 183 uint32_t imagesize; 184 uint8_t buf[1024]; 185 size_t pos = 0; 186 int err = 0; 187 188 if (argc < 3) { 189 fprintf(stderr, "No Seama file passed\n"); 190 err = -EINVAL; 191 goto out; 192 } 193 seama_path = argv[2]; 194 195 optind = 3; 196 oseama_info_parse_options(argc, argv); 197 198 seama = oseama_open(seama_path, "r"); 199 if (!seama) { 200 fprintf(stderr, "Couldn't open %s\n", seama_path); 201 err = -EACCES; 202 goto out; 203 } 204 205 bytes = fread(&hdr, 1, sizeof(hdr), seama); 206 if (bytes != sizeof(hdr)) { 207 fprintf(stderr, "Couldn't read %s header\n", seama_path); 208 err = -EIO; 209 goto err_close; 210 } 211 pos += bytes; 212 213 metasize = be16_to_cpu(hdr.metasize); 214 imagesize = be32_to_cpu(hdr.imagesize); 215 216 if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) { 217 fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic)); 218 err = -EINVAL; 219 goto err_close; 220 } 221 222 if (metasize >= sizeof(buf)) { 223 fprintf(stderr, "Too small buffer (%zu B) to read all meta info (%d B)\n", sizeof(buf), metasize); 224 err = -EINVAL; 225 goto err_close; 226 } 227 228 if (imagesize) { 229 fprintf(stderr, "Invalid Seama image size: 0x%08x (should be 0)\n", imagesize); 230 err = -EINVAL; 231 goto err_close; 232 } 233 234 bytes = fread(buf, 1, metasize, seama); 235 if (bytes != metasize) { 236 fprintf(stderr, "Couldn't read %d B of meta\n", metasize); 237 err = -EIO; 238 goto err_close; 239 } 240 pos += bytes; 241 242 if (entity_idx < 0) { 243 char *end, *tmp; 244 245 printf("Meta size:\t%d\n", metasize); 246 printf("Image size:\t%d\n", imagesize); 247 248 end = (char *)&buf[metasize - 1]; 249 *end = '\0'; 250 for (tmp = (char *)buf; tmp < end && strlen(tmp); tmp += strlen(tmp) + 1) { 251 printf("Meta entry:\t%s\n", tmp); 252 } 253 } 254 255 oseama_info_entities(seama, &pos); 256 257 err_close: 258 oseama_close(seama); 259 out: 260 return err; 261 } 262 263 /************************************************** 264 * Create 265 **************************************************/ 266 267 static ssize_t oseama_entity_append_file(FILE *seama, const char *in_path) { 268 FILE *in; 269 size_t bytes; 270 ssize_t length = 0; 271 uint8_t buf[128]; 272 273 in = fopen(in_path, "r"); 274 if (!in) { 275 fprintf(stderr, "Couldn't open %s\n", in_path); 276 return -EACCES; 277 } 278 279 while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) { 280 if (fwrite(buf, 1, bytes, seama) != bytes) { 281 fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, seama_path); 282 length = -EIO; 283 break; 284 } 285 length += bytes; 286 } 287 288 fclose(in); 289 290 return length; 291 } 292 293 static ssize_t oseama_entity_append_zeros(FILE *seama, size_t length) { 294 uint8_t *buf; 295 296 buf = malloc(length); 297 if (!buf) 298 return -ENOMEM; 299 memset(buf, 0, length); 300 301 if (fwrite(buf, 1, length, seama) != length) { 302 fprintf(stderr, "Couldn't write %zu B to %s\n", length, seama_path); 303 return -EIO; 304 } 305 306 return length; 307 } 308 309 static ssize_t oseama_entity_align(FILE *seama, size_t curr_offset, size_t alignment) { 310 if (curr_offset & (alignment - 1)) { 311 size_t length = alignment - (curr_offset % alignment); 312 313 return oseama_entity_append_zeros(seama, length); 314 } 315 316 return 0; 317 } 318 319 static int oseama_entity_write_hdr(FILE *seama, size_t metasize, size_t imagesize) { 320 struct seama_entity_header hdr = {}; 321 uint8_t buf[128]; 322 size_t length = imagesize; 323 size_t bytes; 324 MD5_CTX ctx; 325 326 fseek(seama, sizeof(hdr) + metasize, SEEK_SET); 327 MD5_Init(&ctx); 328 while ((bytes = fread(buf, 1, oseama_min(sizeof(buf), length), seama)) > 0) { 329 MD5_Update(&ctx, buf, bytes); 330 length -= bytes; 331 } 332 MD5_Final(hdr.md5, &ctx); 333 334 hdr.magic = cpu_to_be32(SEAMA_MAGIC); 335 hdr.metasize = cpu_to_be16(metasize); 336 hdr.imagesize = cpu_to_be32(imagesize); 337 338 fseek(seama, 0, SEEK_SET); 339 bytes = fwrite(&hdr, 1, sizeof(hdr), seama); 340 if (bytes != sizeof(hdr)) { 341 fprintf(stderr, "Couldn't write Seama entity header to %s\n", seama_path); 342 return -EIO; 343 } 344 345 return 0; 346 } 347 348 static int oseama_entity(int argc, char **argv) { 349 FILE *seama; 350 ssize_t sbytes; 351 size_t curr_offset = sizeof(struct seama_entity_header); 352 size_t metasize = 0, imagesize = 0; 353 int c; 354 int err = 0; 355 356 if (argc < 3) { 357 fprintf(stderr, "No Seama file passed\n"); 358 err = -EINVAL; 359 goto out; 360 } 361 seama_path = argv[2]; 362 363 seama = fopen(seama_path, "w+"); 364 if (!seama) { 365 fprintf(stderr, "Couldn't open %s\n", seama_path); 366 err = -EACCES; 367 goto out; 368 } 369 fseek(seama, curr_offset, SEEK_SET); 370 371 optind = 3; 372 while ((c = getopt(argc, argv, "m:f:b:")) != -1) { 373 switch (c) { 374 case 'm': 375 sbytes = fwrite(optarg, 1, strlen(optarg) + 1, seama); 376 if (sbytes < 0) { 377 fprintf(stderr, "Failed to write meta %s\n", optarg); 378 } else { 379 curr_offset += sbytes; 380 metasize += sbytes; 381 } 382 383 sbytes = oseama_entity_align(seama, curr_offset, 4); 384 if (sbytes < 0) { 385 fprintf(stderr, "Failed to append zeros\n"); 386 } else { 387 curr_offset += sbytes; 388 metasize += sbytes; 389 } 390 391 break; 392 case 'f': 393 case 'b': 394 break; 395 } 396 } 397 398 optind = 3; 399 while ((c = getopt(argc, argv, "m:f:b:")) != -1) { 400 switch (c) { 401 case 'm': 402 break; 403 case 'f': 404 sbytes = oseama_entity_append_file(seama, optarg); 405 if (sbytes < 0) { 406 fprintf(stderr, "Failed to append file %s\n", optarg); 407 } else { 408 curr_offset += sbytes; 409 imagesize += sbytes; 410 } 411 break; 412 case 'b': 413 sbytes = strtol(optarg, NULL, 0) - curr_offset; 414 if (sbytes < 0) { 415 fprintf(stderr, "Current Seama entity length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset, strtol(optarg, NULL, 0)); 416 } else { 417 sbytes = oseama_entity_append_zeros(seama, sbytes); 418 if (sbytes < 0) { 419 fprintf(stderr, "Failed to append zeros\n"); 420 } else { 421 curr_offset += sbytes; 422 imagesize += sbytes; 423 } 424 } 425 break; 426 } 427 if (err) 428 break; 429 } 430 431 oseama_entity_write_hdr(seama, metasize, imagesize); 432 433 fclose(seama); 434 out: 435 return err; 436 } 437 438 /************************************************** 439 * Extract 440 **************************************************/ 441 442 static void oseama_extract_parse_options(int argc, char **argv) { 443 int c; 444 445 while ((c = getopt(argc, argv, "e:o:")) != -1) { 446 switch (c) { 447 case 'e': 448 entity_idx = atoi(optarg); 449 break; 450 case 'o': 451 out_path = optarg; 452 break; 453 } 454 } 455 } 456 457 static int oseama_extract_entity(FILE *seama, FILE *out) { 458 struct seama_entity_header hdr; 459 size_t bytes, metasize, imagesize, length; 460 uint8_t buf[1024]; 461 int i = 0; 462 int err = 0; 463 464 while ((bytes = fread(&hdr, 1, sizeof(hdr), seama)) == sizeof(hdr)) { 465 if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) { 466 fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic)); 467 err = -EINVAL; 468 break; 469 } 470 metasize = be16_to_cpu(hdr.metasize); 471 imagesize = be32_to_cpu(hdr.imagesize); 472 473 if (i != entity_idx) { 474 oseama_skip(seama, metasize + imagesize); 475 i++; 476 continue; 477 } 478 479 if (fwrite(&hdr, 1, sizeof(hdr), out) != sizeof(hdr)) { 480 fprintf(stderr, "Couldn't write %zu B to %s\n", sizeof(hdr), out_path); 481 err = -EIO; 482 break; 483 } 484 485 length = metasize + imagesize; 486 while ((bytes = fread(buf, 1, oseama_min(sizeof(buf), length), seama)) > 0) { 487 if (fwrite(buf, 1, bytes, out) != bytes) { 488 fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path); 489 err = -EIO; 490 break; 491 } 492 length -= bytes; 493 } 494 495 if (length) { 496 fprintf(stderr, "Couldn't extract whole entity %d from %s (%zu B left)\n", entity_idx, seama_path, length); 497 err = -EIO; 498 break; 499 } 500 501 break; 502 } 503 504 return err; 505 } 506 507 static int oseama_extract(int argc, char **argv) { 508 FILE *seama; 509 FILE *out; 510 struct seama_seal_header hdr; 511 size_t bytes; 512 uint16_t metasize; 513 int err = 0; 514 515 if (argc < 3) { 516 fprintf(stderr, "No Seama file passed\n"); 517 err = -EINVAL; 518 goto out; 519 } 520 seama_path = argv[2]; 521 522 optind = 3; 523 oseama_extract_parse_options(argc, argv); 524 if (entity_idx < 0) { 525 fprintf(stderr, "No entity specified\n"); 526 err = -EINVAL; 527 goto out; 528 } 529 530 seama = oseama_open(seama_path, "r"); 531 if (!seama) { 532 fprintf(stderr, "Couldn't open %s\n", seama_path); 533 err = -EACCES; 534 goto out; 535 } 536 537 if (out_path) { 538 out = fopen(out_path, "w"); 539 if (!out) { 540 fprintf(stderr, "Couldn't open %s\n", out_path); 541 err = -EACCES; 542 goto err_close_seama; 543 } 544 } else { 545 out = stdout; 546 } 547 548 bytes = fread(&hdr, 1, sizeof(hdr), seama); 549 if (bytes != sizeof(hdr)) { 550 fprintf(stderr, "Couldn't read %s header\n", seama_path); 551 err = -EIO; 552 goto err_close_out; 553 } 554 metasize = be16_to_cpu(hdr.metasize); 555 556 oseama_skip(seama, metasize); 557 558 oseama_extract_entity(seama, out); 559 560 err_close_out: 561 if (out != stdout) 562 fclose(out); 563 err_close_seama: 564 oseama_close(seama); 565 out: 566 return err; 567 } 568 569 /************************************************** 570 * Start 571 **************************************************/ 572 573 static void usage() { 574 printf("Usage:\n"); 575 printf("\n"); 576 printf("Info about Seama seal (container):\n"); 577 printf("\toseama info <file> [options]\n"); 578 printf("\t-e\t\t\t\tprint info about specified entity only\n"); 579 printf("\n"); 580 printf("Create Seama entity:\n"); 581 printf("\toseama entity <file> [options]\n"); 582 printf("\t-m meta\t\t\t\tmeta into to put in header\n"); 583 printf("\t-f file\t\t\t\tappend content from file\n"); 584 printf("\t-b offset\t\t\tappend zeros till reaching absolute offset\n"); 585 printf("\n"); 586 printf("Extract from Seama seal (container):\n"); 587 printf("\toseama extract <file> [options]\n"); 588 printf("\t-e\t\t\t\tindex of entity to extract\n"); 589 printf("\t-o file\t\t\t\toutput file\n"); 590 } 591 592 int main(int argc, char **argv) { 593 if (argc > 1) { 594 if (!strcmp(argv[1], "info")) 595 return oseama_info(argc, argv); 596 else if (!strcmp(argv[1], "entity")) 597 return oseama_entity(argc, argv); 598 else if (!strcmp(argv[1], "extract")) 599 return oseama_extract(argc, argv); 600 } 601 602 usage(); 603 return 0; 604 } 605
This page was automatically generated by LXR 0.3.1. • OpenWrt