diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2012-11-12 18:35:00 +0100 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2012-11-13 18:25:00 +0100 |
commit | 214f226ca63c8c5d6f446d69ffe95aec91779254 (patch) | |
tree | 79331e1f87552db1733ca4eb702e355a7c12ed10 /utils/nwztools | |
parent | 02f67224f9c424bf9c3a613741adfccaf4847d12 (diff) | |
download | rockbox-214f226ca63c8c5d6f446d69ffe95aec91779254.tar.gz rockbox-214f226ca63c8c5d6f446d69ffe95aec91779254.zip |
upgtools: allow creation of a UPG archive + improvements
Change-Id: I9c3e2eb95f7eb6d41591b006328fd720dfcf93a5
Diffstat (limited to 'utils/nwztools')
-rw-r--r-- | utils/nwztools/upgtools/fwp.c | 5 | ||||
-rw-r--r-- | utils/nwztools/upgtools/fwp.h | 1 | ||||
-rw-r--r-- | utils/nwztools/upgtools/mg.cpp | 4 | ||||
-rw-r--r-- | utils/nwztools/upgtools/upgtool.c | 353 |
4 files changed, 320 insertions, 43 deletions
diff --git a/utils/nwztools/upgtools/fwp.c b/utils/nwztools/upgtools/fwp.c index e739b8caef..c300f42f34 100644 --- a/utils/nwztools/upgtools/fwp.c +++ b/utils/nwztools/upgtools/fwp.c | |||
@@ -29,6 +29,11 @@ int fwp_read(void *in, int size, void *out, uint8_t *key) | |||
29 | return mg_decrypt_fw(in, size, out, key); | 29 | return mg_decrypt_fw(in, size, out, key); |
30 | } | 30 | } |
31 | 31 | ||
32 | int fwp_write(void *in, int size, void *out, uint8_t *key) | ||
33 | { | ||
34 | return mg_encrypt_fw(in, size, out, key); | ||
35 | } | ||
36 | |||
32 | static uint8_t g_key[NWZ_KEY_SIZE]; | 37 | static uint8_t g_key[NWZ_KEY_SIZE]; |
33 | 38 | ||
34 | void fwp_setkey(char key[NWZ_KEY_SIZE]) | 39 | void fwp_setkey(char key[NWZ_KEY_SIZE]) |
diff --git a/utils/nwztools/upgtools/fwp.h b/utils/nwztools/upgtools/fwp.h index dcfe80027e..7b527d47ba 100644 --- a/utils/nwztools/upgtools/fwp.h +++ b/utils/nwztools/upgtools/fwp.h | |||
@@ -34,6 +34,7 @@ extern "C" { | |||
34 | #define NWZ_DES_BLOCK 8 | 34 | #define NWZ_DES_BLOCK 8 |
35 | 35 | ||
36 | int fwp_read(void *in, int size, void *out, uint8_t *key); | 36 | int fwp_read(void *in, int size, void *out, uint8_t *key); |
37 | int fwp_write(void *in, int size, void *out, uint8_t *key); | ||
37 | void fwp_setkey(char key[8]); | 38 | void fwp_setkey(char key[8]); |
38 | int fwp_crypt(void *buf, int size, int mode); | 39 | int fwp_crypt(void *buf, int size, int mode); |
39 | 40 | ||
diff --git a/utils/nwztools/upgtools/mg.cpp b/utils/nwztools/upgtools/mg.cpp index 8816259755..21659ff3cf 100644 --- a/utils/nwztools/upgtools/mg.cpp +++ b/utils/nwztools/upgtools/mg.cpp | |||
@@ -33,6 +33,8 @@ namespace | |||
33 | 33 | ||
34 | inline int dec_des_ecb(void *in, int size, void *out, uint8_t *key) | 34 | inline int dec_des_ecb(void *in, int size, void *out, uint8_t *key) |
35 | { | 35 | { |
36 | if(size % 8) | ||
37 | return 42; | ||
36 | g_dec.SetKey(key, 8); | 38 | g_dec.SetKey(key, 8); |
37 | g_dec.ProcessData((byte*)out, (byte*)in, size); | 39 | g_dec.ProcessData((byte*)out, (byte*)in, size); |
38 | return 0; | 40 | return 0; |
@@ -40,6 +42,8 @@ namespace | |||
40 | 42 | ||
41 | inline int enc_des_ecb(void *in, int size, void *out, uint8_t *key) | 43 | inline int enc_des_ecb(void *in, int size, void *out, uint8_t *key) |
42 | { | 44 | { |
45 | if(size % 8) | ||
46 | return 42; | ||
43 | g_enc.SetKey(key, 8); | 47 | g_enc.SetKey(key, 8); |
44 | g_enc.ProcessData((byte*)out, (byte*)in, size); | 48 | g_enc.ProcessData((byte*)out, (byte*)in, size); |
45 | return 0; | 49 | return 0; |
diff --git a/utils/nwztools/upgtools/upgtool.c b/utils/nwztools/upgtools/upgtool.c index 73303e72d3..54bbbf3270 100644 --- a/utils/nwztools/upgtools/upgtool.c +++ b/utils/nwztools/upgtools/upgtool.c | |||
@@ -50,7 +50,6 @@ static char *g_sig = NULL; | |||
50 | 50 | ||
51 | enum keysig_search_method_t g_keysig_search = KEYSIG_SEARCH_NONE; | 51 | enum keysig_search_method_t g_keysig_search = KEYSIG_SEARCH_NONE; |
52 | 52 | ||
53 | |||
54 | #define let_the_force_flow(x) do { if(!g_force) return x; } while(0) | 53 | #define let_the_force_flow(x) do { if(!g_force) return x; } while(0) |
55 | #define continue_the_force(x) if(x) let_the_force_flow(x) | 54 | #define continue_the_force(x) if(x) let_the_force_flow(x) |
56 | 55 | ||
@@ -77,6 +76,8 @@ static void print_hex(void *p, int size, int unit) | |||
77 | } | 76 | } |
78 | } | 77 | } |
79 | 78 | ||
79 | static void usage(void); | ||
80 | |||
80 | /* key and signature */ | 81 | /* key and signature */ |
81 | struct nwz_kas_t | 82 | struct nwz_kas_t |
82 | { | 83 | { |
@@ -106,7 +107,7 @@ struct upg_header_t | |||
106 | { | 107 | { |
107 | char sig[8]; | 108 | char sig[8]; |
108 | uint32_t nr_files; | 109 | uint32_t nr_files; |
109 | uint32_t unk; | 110 | uint32_t pad; // make sure structure size is a multiple of 8 |
110 | } __attribute__((packed)); | 111 | } __attribute__((packed)); |
111 | 112 | ||
112 | struct upg_entry_t | 113 | struct upg_entry_t |
@@ -186,7 +187,7 @@ static int do_upg(void *buf, long size) | |||
186 | if(g_model_index == -1 && g_keysig_search == KEYSIG_SEARCH_NONE && g_key == NULL && g_kas == NULL) | 187 | if(g_model_index == -1 && g_keysig_search == KEYSIG_SEARCH_NONE && g_key == NULL && g_kas == NULL) |
187 | { | 188 | { |
188 | cprintf(GREY, "A KAS or a keysig is needed to decrypt the firmware\n"); | 189 | cprintf(GREY, "A KAS or a keysig is needed to decrypt the firmware\n"); |
189 | cprintf(GREY, "You have the following options(see hel for more details):\n"); | 190 | cprintf(GREY, "You have the following options(see help for more details):\n"); |
190 | cprintf(GREY, "- select a model with a known KAS\n"); | 191 | cprintf(GREY, "- select a model with a known KAS\n"); |
191 | cprintf(GREY, "- specify an explicit KAS or key(+optional sig)\n"); | 192 | cprintf(GREY, "- specify an explicit KAS or key(+optional sig)\n"); |
192 | cprintf(GREY, "- let me try to find the keysig(slow !)\n"); | 193 | cprintf(GREY, "- let me try to find the keysig(slow !)\n"); |
@@ -327,7 +328,7 @@ static int do_upg(void *buf, long size) | |||
327 | else | 328 | else |
328 | cprintf(RED, " Can't check\n"); | 329 | cprintf(RED, " Can't check\n"); |
329 | cprintf_field(" Files: ", "%d\n", hdr->nr_files); | 330 | cprintf_field(" Files: ", "%d\n", hdr->nr_files); |
330 | cprintf_field(" Unk: ", "0x%x\n", hdr->unk); | 331 | cprintf_field(" Pad: ", "0x%x\n", hdr->pad); |
331 | 332 | ||
332 | cprintf(BLUE, "Files\n"); | 333 | cprintf(BLUE, "Files\n"); |
333 | struct upg_entry_t *entry = (void *)(hdr + 1); | 334 | struct upg_entry_t *entry = (void *)(hdr + 1); |
@@ -344,14 +345,17 @@ static int do_upg(void *buf, long size) | |||
344 | if(g_out_prefix) | 345 | if(g_out_prefix) |
345 | { | 346 | { |
346 | char *str = malloc(strlen(g_out_prefix) + 32); | 347 | char *str = malloc(strlen(g_out_prefix) + 32); |
347 | sprintf(str, "%s/%d.bin", g_out_prefix, i); | 348 | sprintf(str, "%s%d.bin", g_out_prefix, i); |
348 | FILE *f = fopen(str, "wb"); | 349 | FILE *f = fopen(str, "wb"); |
349 | if(f) | 350 | if(f) |
350 | { | 351 | { |
351 | int ret = fwp_read(buf + entry->offset, entry->size, | 352 | // round up size, there is some padding done with random data |
353 | int crypt_size = ROUND_UP(entry->size, 8); | ||
354 | int ret = fwp_read(buf + entry->offset, crypt_size, | ||
352 | buf + entry->offset, (void *)g_key); | 355 | buf + entry->offset, (void *)g_key); |
353 | if(ret) | 356 | if(ret) |
354 | return ret; | 357 | return ret; |
358 | // but write the *good* amount of data | ||
355 | fwrite(buf + entry->offset, 1, entry->size, f); | 359 | fwrite(buf + entry->offset, 1, entry->size, f); |
356 | 360 | ||
357 | fclose(f); | 361 | fclose(f); |
@@ -364,10 +368,276 @@ static int do_upg(void *buf, long size) | |||
364 | return 0; | 368 | return 0; |
365 | } | 369 | } |
366 | 370 | ||
371 | static int extract_upg(int argc, char **argv) | ||
372 | { | ||
373 | if(argc == 0 || argc > 1) | ||
374 | { | ||
375 | if(argc == 0) | ||
376 | printf("You must specify a firmware file\n"); | ||
377 | else | ||
378 | printf("Extra arguments after firmware file\n"); | ||
379 | usage(); | ||
380 | } | ||
381 | |||
382 | g_in_file = argv[0]; | ||
383 | FILE *fin = fopen(g_in_file, "r"); | ||
384 | if(fin == NULL) | ||
385 | { | ||
386 | perror("Cannot open boot file"); | ||
387 | return 1; | ||
388 | } | ||
389 | fseek(fin, 0, SEEK_END); | ||
390 | long size = ftell(fin); | ||
391 | fseek(fin, 0, SEEK_SET); | ||
392 | |||
393 | void *buf = malloc(size); | ||
394 | if(buf == NULL) | ||
395 | { | ||
396 | perror("Cannot allocate memory"); | ||
397 | return 1; | ||
398 | } | ||
399 | |||
400 | if(fread(buf, size, 1, fin) != 1) | ||
401 | { | ||
402 | perror("Cannot read file"); | ||
403 | return 1; | ||
404 | } | ||
405 | |||
406 | fclose(fin); | ||
407 | |||
408 | int ret = do_upg(buf, size); | ||
409 | if(ret != 0) | ||
410 | { | ||
411 | cprintf(GREY, "Error: %d", ret); | ||
412 | if(!g_force) | ||
413 | cprintf(GREY, " (use --force to force processing)"); | ||
414 | printf("\n"); | ||
415 | ret = 2; | ||
416 | } | ||
417 | free(buf); | ||
418 | |||
419 | return ret; | ||
420 | } | ||
421 | |||
422 | static long filesize(FILE *f) | ||
423 | { | ||
424 | long pos = ftell(f); | ||
425 | fseek(f, 0, SEEK_END); | ||
426 | long size = ftell(f); | ||
427 | fseek(f, pos, SEEK_SET); | ||
428 | return size; | ||
429 | } | ||
430 | |||
431 | static int create_upg(int argc, char **argv) | ||
432 | { | ||
433 | if(argc == 0) | ||
434 | { | ||
435 | printf("You must specify a firmware filename\n"); | ||
436 | usage(); | ||
437 | } | ||
438 | |||
439 | if(g_model_index == -1 && (g_key == NULL || g_sig == NULL) && g_kas == NULL) | ||
440 | { | ||
441 | cprintf(GREY, "A KAS or a keysig is needed to encrypt the firmware\n"); | ||
442 | cprintf(GREY, "You have the following options(see help for more details):\n"); | ||
443 | cprintf(GREY, "- select a model with a known KAS\n"); | ||
444 | cprintf(GREY, "- specify an explicit KAS or key+sig\n"); | ||
445 | return 1; | ||
446 | } | ||
447 | |||
448 | struct nwz_kas_t kas; | ||
449 | char keysig[NWZ_KEYSIG_SIZE]; | ||
450 | |||
451 | memset(kas.kas, '?', NWZ_KAS_SIZE); | ||
452 | memset(keysig, '?', NWZ_KEYSIG_SIZE); | ||
453 | keysig[32] = keysig[41] = keysig[50] = 0; | ||
454 | |||
455 | if(g_kas) | ||
456 | { | ||
457 | if(strlen(g_kas) != NWZ_KAS_SIZE) | ||
458 | { | ||
459 | cprintf(GREY, "The specified KAS has wrong length (must be %d hex digits)\n", NWZ_KAS_SIZE); | ||
460 | return 4; | ||
461 | } | ||
462 | memcpy(keysig, g_kas, NWZ_KAS_SIZE); | ||
463 | decrypt_keysig(keysig); | ||
464 | g_kas = keysig; | ||
465 | g_key = keysig + 33; | ||
466 | g_sig = keysig + 42; | ||
467 | } | ||
468 | else if(g_key) | ||
469 | { | ||
470 | if(strlen(g_key) != 8) | ||
471 | { | ||
472 | cprintf(GREY, "The specified key has wrong length (must be 8 hex digits)\n"); | ||
473 | return 4; | ||
474 | } | ||
475 | if(strlen(g_sig) != 8) | ||
476 | { | ||
477 | cprintf(GREY, "The specified sig has wrong length (must be 8 hex digits)\n"); | ||
478 | return 5; | ||
479 | } | ||
480 | |||
481 | memcpy(keysig + 33, g_key, 8); | ||
482 | if(!g_sig) | ||
483 | cprintf(GREY, "Warning: you have specified a key but no sig, I won't be able to do any checks\n"); | ||
484 | else | ||
485 | memcpy(keysig + 42, g_sig, 8); | ||
486 | g_key = keysig + 33; | ||
487 | g_sig = keysig + 42; | ||
488 | } | ||
489 | else if(g_model_index != -1) | ||
490 | { | ||
491 | if(g_model_list[g_model_index].flags & HAS_KAS) | ||
492 | g_kas = g_model_list[g_model_index].kas.kas; | ||
493 | if(g_model_list[g_model_index].flags & HAS_KEY) | ||
494 | g_key = g_model_list[g_model_index].key; | ||
495 | if(g_model_list[g_model_index].flags & HAS_SIG) | ||
496 | g_sig = g_model_list[g_model_index].sig; | ||
497 | |||
498 | if(g_key && g_sig) | ||
499 | { | ||
500 | memcpy(keysig + 33, g_key, 8); | ||
501 | g_key = keysig + 33; | ||
502 | memcpy(keysig + 42, g_sig, 8); | ||
503 | g_sig = keysig + 42; | ||
504 | } | ||
505 | else if(g_kas) | ||
506 | { | ||
507 | memcpy(keysig, g_kas, NWZ_KAS_SIZE); | ||
508 | decrypt_keysig(keysig); | ||
509 | g_kas = keysig; | ||
510 | g_key = keysig + 33; | ||
511 | g_sig = keysig + 42; | ||
512 | } | ||
513 | else | ||
514 | { | ||
515 | printf("Target doesn't have enough information to get key and sig\n"); | ||
516 | return 1; | ||
517 | } | ||
518 | } | ||
519 | else | ||
520 | { | ||
521 | printf("Kill me\n"); | ||
522 | return 1; | ||
523 | } | ||
524 | |||
525 | if(!g_kas) | ||
526 | { | ||
527 | g_kas = keysig; | ||
528 | fwp_setkey("ed295076"); | ||
529 | memcpy(kas.kas, g_key, 8); | ||
530 | fwp_crypt(kas.kas, 8, 0); | ||
531 | for(int i = 0; i < 8; i++) | ||
532 | { | ||
533 | g_kas[2 * i] = hex_digit((kas.kas[i] >> 4) & 0xf); | ||
534 | g_kas[2 * i + 1] = hex_digit(kas.kas[i] & 0xf); | ||
535 | } | ||
536 | memcpy(kas.kas + 8, g_sig, 8); | ||
537 | fwp_crypt(kas.kas + 8, 8, 0); | ||
538 | for(int i = 8; i < 16; i++) | ||
539 | { | ||
540 | g_kas[2 * i] = hex_digit((kas.kas[i] >> 4) & 0xf); | ||
541 | g_kas[2 * i + 1] = hex_digit(kas.kas[i] & 0xf); | ||
542 | } | ||
543 | } | ||
544 | |||
545 | cprintf(BLUE, "Keys\n"); | ||
546 | cprintf_field(" KAS: ", "%."STR(NWZ_KAS_SIZE)"s\n", g_kas); | ||
547 | cprintf_field(" Key: ", "%s\n", g_key); | ||
548 | if(g_sig) | ||
549 | cprintf_field(" Sig: ", "%s\n", g_sig); | ||
550 | |||
551 | FILE *fout = fopen(argv[0], "wb"); | ||
552 | if(fout == NULL) | ||
553 | { | ||
554 | printf("Cannot open output firmware file: %m\n"); | ||
555 | return 1; | ||
556 | } | ||
557 | |||
558 | int nr_files = argc - 1; | ||
559 | FILE **files = malloc(nr_files * sizeof(FILE *)); | ||
560 | |||
561 | for(int i = 0; i < nr_files; i++) | ||
562 | { | ||
563 | files[i] = fopen(argv[1 + i], "rb"); | ||
564 | if(files[i] == NULL) | ||
565 | { | ||
566 | printf("Cannot open input file '%s': %m\n", argv[i + 1]); | ||
567 | return 1; | ||
568 | } | ||
569 | } | ||
570 | |||
571 | struct upg_md5_t md5; | ||
572 | memset(&md5, 0, sizeof(md5)); | ||
573 | MD5_CTX c; | ||
574 | MD5_Init(&c); | ||
575 | // output a dummy md5 sum | ||
576 | fwrite(&md5, 1, sizeof(md5), fout); | ||
577 | // output the encrypted signature | ||
578 | struct upg_header_t hdr; | ||
579 | memcpy(hdr.sig, g_sig, 8); | ||
580 | hdr.nr_files = nr_files; | ||
581 | hdr.pad = 0; | ||
582 | |||
583 | int ret = fwp_write(&hdr, sizeof(hdr), &hdr, (void *)g_key); | ||
584 | if(ret) | ||
585 | return ret; | ||
586 | MD5_Update(&c, &hdr, sizeof(hdr)); | ||
587 | fwrite(&hdr, 1, sizeof(hdr), fout); | ||
588 | |||
589 | // output file headers | ||
590 | long offset = sizeof(md5) + sizeof(hdr) + nr_files * sizeof(struct upg_entry_t); | ||
591 | for(int i = 0; i < nr_files; i++) | ||
592 | { | ||
593 | struct upg_entry_t entry; | ||
594 | entry.offset = offset; | ||
595 | entry.size = filesize(files[i]); | ||
596 | offset += ROUND_UP(entry.size, 8); // do it before encryption !! | ||
597 | |||
598 | ret = fwp_write(&entry, sizeof(entry), &entry, (void *)g_key); | ||
599 | if(ret) | ||
600 | return ret; | ||
601 | MD5_Update(&c, &entry, sizeof(entry)); | ||
602 | fwrite(&entry, 1, sizeof(entry), fout); | ||
603 | } | ||
604 | |||
605 | cprintf(BLUE, "Files\n"); | ||
606 | for(int i = 0; i < nr_files; i++) | ||
607 | { | ||
608 | long size = filesize(files[i]); | ||
609 | long r_size = ROUND_UP(size, 8); | ||
610 | cprintf(GREY, " File"); | ||
611 | cprintf(RED, " %d\n", i); | ||
612 | cprintf_field(" Offset: ", "0x%lx\n", ftell(fout)); | ||
613 | cprintf_field(" Size: ", "0x%lx\n", size); | ||
614 | |||
615 | void *buf = malloc(r_size); | ||
616 | memset(buf, 0, r_size); | ||
617 | fread(buf, 1, size, files[i]); | ||
618 | fclose(files[i]); | ||
619 | |||
620 | ret = fwp_write(buf, r_size, buf, (void *)g_key); | ||
621 | if(ret) | ||
622 | return ret; | ||
623 | MD5_Update(&c, buf, r_size); | ||
624 | fwrite(buf, 1, r_size, fout); | ||
625 | |||
626 | free(buf); | ||
627 | } | ||
628 | |||
629 | fseek(fout, 0, SEEK_SET); | ||
630 | MD5_Final(md5.md5, &c); | ||
631 | fwrite(&md5, 1, sizeof(md5), fout); | ||
632 | fclose(fout); | ||
633 | |||
634 | return 0; | ||
635 | } | ||
636 | |||
367 | static void usage(void) | 637 | static void usage(void) |
368 | { | 638 | { |
369 | color(OFF); | 639 | color(OFF); |
370 | printf("Usage: upgtool [options] firmware\n"); | 640 | printf("Usage: upgtool [options] firmware [files...]\n"); |
371 | printf("Options:\n"); | 641 | printf("Options:\n"); |
372 | printf(" -o <prefix>\t\tSet output prefix\n"); | 642 | printf(" -o <prefix>\t\tSet output prefix\n"); |
373 | printf(" -f/--force\t\tForce to continue on errors\n"); | 643 | printf(" -f/--force\t\tForce to continue on errors\n"); |
@@ -375,10 +645,12 @@ static void usage(void) | |||
375 | printf(" -d/--debug\t\tDisplay debug messages\n"); | 645 | printf(" -d/--debug\t\tDisplay debug messages\n"); |
376 | printf(" -c/--no-color\t\tDisable color output\n"); | 646 | printf(" -c/--no-color\t\tDisable color output\n"); |
377 | printf(" -m/--model <model>\tSelect model (or ? to list them)\n"); | 647 | printf(" -m/--model <model>\tSelect model (or ? to list them)\n"); |
378 | printf(" -l/--search <method>\tTry to find the keysig\n"); | 648 | printf(" -l/--search <method>\tTry to find the keysig (implies -e)\n"); |
379 | printf(" -a/--kas <kas>\tForce KAS\n"); | 649 | printf(" -a/--kas <kas>\tForce KAS\n"); |
380 | printf(" -k/--key <key>\tForce key\n"); | 650 | printf(" -k/--key <key>\tForce key\n"); |
381 | printf(" -s/--sig <sig>\tForce sig\n"); | 651 | printf(" -s/--sig <sig>\tForce sig\n"); |
652 | printf(" -e/--extract\t\tExtract a UPG archive\n"); | ||
653 | printf(" -c/--create\t\tCreate a UPG archive\n"); | ||
382 | printf("keysig search method:\n"); | 654 | printf("keysig search method:\n"); |
383 | for(int i = KEYSIG_SEARCH_FIRST; i < KEYSIG_SEARCH_LAST; i++) | 655 | for(int i = KEYSIG_SEARCH_FIRST; i < KEYSIG_SEARCH_LAST; i++) |
384 | printf(" %s\t%s\n", keysig_search_desc[i].name, keysig_search_desc[i].comment); | 656 | printf(" %s\t%s\n", keysig_search_desc[i].name, keysig_search_desc[i].comment); |
@@ -387,30 +659,38 @@ static void usage(void) | |||
387 | 659 | ||
388 | int main(int argc, char **argv) | 660 | int main(int argc, char **argv) |
389 | { | 661 | { |
662 | bool extract = false; | ||
663 | bool create = false; | ||
664 | |||
665 | if(argc <= 1) | ||
666 | usage(); | ||
667 | |||
390 | while(1) | 668 | while(1) |
391 | { | 669 | { |
392 | static struct option long_options[] = | 670 | static struct option long_options[] = |
393 | { | 671 | { |
394 | {"help", no_argument, 0, '?'}, | 672 | {"help", no_argument, 0, '?'}, |
395 | {"debug", no_argument, 0, 'd'}, | 673 | {"debug", no_argument, 0, 'd'}, |
396 | {"no-color", no_argument, 0, 'c'}, | 674 | {"no-color", no_argument, 0, 'n'}, |
397 | {"force", no_argument, 0, 'f'}, | 675 | {"force", no_argument, 0, 'f'}, |
398 | {"model", required_argument, 0, 'm'}, | 676 | {"model", required_argument, 0, 'm'}, |
399 | {"search", required_argument, 0, 'l'}, | 677 | {"search", required_argument, 0, 'l'}, |
400 | {"kas", required_argument, 0, 'a'}, | 678 | {"kas", required_argument, 0, 'a'}, |
401 | {"key", required_argument, 0, 'k'}, | 679 | {"key", required_argument, 0, 'k'}, |
402 | {"sig", required_argument, 0, 's'}, | 680 | {"sig", required_argument, 0, 's'}, |
681 | {"extract", no_argument, 0, 'e'}, | ||
682 | {"create", no_argument, 0 ,'c'}, | ||
403 | {0, 0, 0, 0} | 683 | {0, 0, 0, 0} |
404 | }; | 684 | }; |
405 | 685 | ||
406 | int c = getopt_long(argc, argv, "?dcfo:m:l:a:k:s:", long_options, NULL); | 686 | int c = getopt_long(argc, argv, "?dnfo:m:l:a:k:s:ec", long_options, NULL); |
407 | if(c == -1) | 687 | if(c == -1) |
408 | break; | 688 | break; |
409 | switch(c) | 689 | switch(c) |
410 | { | 690 | { |
411 | case -1: | 691 | case -1: |
412 | break; | 692 | break; |
413 | case 'c': | 693 | case 'n': |
414 | enable_color(false); | 694 | enable_color(false); |
415 | break; | 695 | break; |
416 | case 'd': | 696 | case 'd': |
@@ -438,6 +718,7 @@ int main(int argc, char **argv) | |||
438 | cprintf(GREY, "Unknown keysig search method '%s'\n", optarg); | 718 | cprintf(GREY, "Unknown keysig search method '%s'\n", optarg); |
439 | return 1; | 719 | return 1; |
440 | } | 720 | } |
721 | extract = true; | ||
441 | break; | 722 | break; |
442 | case 'a': | 723 | case 'a': |
443 | g_kas = optarg; | 724 | g_kas = optarg; |
@@ -448,6 +729,12 @@ int main(int argc, char **argv) | |||
448 | case 's': | 729 | case 's': |
449 | g_sig = optarg; | 730 | g_sig = optarg; |
450 | break; | 731 | break; |
732 | case 'e': | ||
733 | extract = true; | ||
734 | break; | ||
735 | case 'c': | ||
736 | create = true; | ||
737 | break; | ||
451 | default: | 738 | default: |
452 | abort(); | 739 | abort(); |
453 | } | 740 | } |
@@ -492,48 +779,28 @@ int main(int argc, char **argv) | |||
492 | cprintf(GREY, "Warning: unknown model %s\n", g_model); | 779 | cprintf(GREY, "Warning: unknown model %s\n", g_model); |
493 | } | 780 | } |
494 | 781 | ||
495 | if(argc - optind != 1) | 782 | if(!create && !extract) |
496 | { | ||
497 | usage(); | ||
498 | return 1; | ||
499 | } | ||
500 | |||
501 | g_in_file = argv[optind]; | ||
502 | FILE *fin = fopen(g_in_file, "r"); | ||
503 | if(fin == NULL) | ||
504 | { | 783 | { |
505 | perror("Cannot open boot file"); | 784 | printf("You must specify an action (extract or create)\n"); |
506 | return 1; | 785 | return 1; |
507 | } | 786 | } |
508 | fseek(fin, 0, SEEK_END); | ||
509 | long size = ftell(fin); | ||
510 | fseek(fin, 0, SEEK_SET); | ||
511 | 787 | ||
512 | void *buf = malloc(size); | 788 | if(create && extract) |
513 | if(buf == NULL) | ||
514 | { | 789 | { |
515 | perror("Cannot allocate memory"); | 790 | printf("You cannot specify both create and extract\n"); |
516 | return 1; | 791 | return 1; |
517 | } | 792 | } |
518 | 793 | ||
519 | if(fread(buf, size, 1, fin) != 1) | 794 | int ret = 0; |
520 | { | 795 | if(create) |
521 | perror("Cannot read file"); | 796 | ret = create_upg(argc - optind, argv + optind); |
522 | return 1; | 797 | else if(extract) |
523 | } | 798 | ret = extract_upg(argc - optind, argv + optind); |
524 | 799 | else | |
525 | fclose(fin); | ||
526 | |||
527 | int ret = do_upg(buf, size); | ||
528 | if(ret != 0) | ||
529 | { | 800 | { |
530 | cprintf(GREY, "Error: %d", ret); | 801 | printf("Die from lack of action\n"); |
531 | if(!g_force) | 802 | ret = 1; |
532 | cprintf(GREY, " (use --force to force processing)"); | ||
533 | printf("\n"); | ||
534 | ret = 2; | ||
535 | } | 803 | } |
536 | free(buf); | ||
537 | 804 | ||
538 | color(OFF); | 805 | color(OFF); |
539 | 806 | ||