sbtools: always check the result of getenv against NULL, use strcasecmp instead of...
[kugel-rb.git] / utils / sbtools / sbtoelf.c
blob854af2851e65e788312e165eeb1b56ca610a39f8
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2010 Bertrik Sikken
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 * .sb file parser and chunk extractor
25 * Based on amsinfo, which is
26 * Copyright © 2008 Rafaël Carré <rafael.carre@gmail.com>
29 #define _ISOC99_SOURCE /* snprintf() */
30 #include <stdio.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <inttypes.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <time.h>
41 #include <strings.h>
43 #include "crypto.h"
44 #include "elf.h"
45 #include "sb.h"
47 #if 1 /* ANSI colors */
49 # define color(a) printf("%s",a)
50 char OFF[] = { 0x1b, 0x5b, 0x31, 0x3b, '0', '0', 0x6d, '\0' };
52 char GREY[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '0', 0x6d, '\0' };
53 char RED[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '1', 0x6d, '\0' };
54 char GREEN[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' };
55 char YELLOW[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' };
56 char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' };
58 #else
59 /* disable colors */
60 # define color(a)
61 #endif
63 #define bug(...) do { fprintf(stderr,"ERROR: "__VA_ARGS__); exit(1); } while(0)
64 #define bugp(a) do { perror("ERROR: "a); exit(1); } while(0)
66 /* all blocks are sized as a multiple of 0x1ff */
67 #define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff)
69 /* If you find a firmware that breaks the known format ^^ */
70 #define assert(a) do { if(!(a)) { fprintf(stderr,"Assertion \"%s\" failed in %s() line %d!\n\nPlease send us your firmware!\n",#a,__func__,__LINE__); exit(1); } } while(0)
72 /* globals */
74 size_t g_sz; /* file size */
75 uint8_t *g_buf; /* file content */
76 #define PREFIX_SIZE 128
77 char out_prefix[PREFIX_SIZE];
78 const char *key_file;
80 char *s_getenv(const char *name)
82 char *s = getenv(name);
83 return s ? s : "";
86 void *xmalloc(size_t s) /* malloc helper, used in elf.c */
88 void * r = malloc(s);
89 if(!r) bugp("malloc");
90 return r;
93 static void print_hex(byte *data, int len, bool newline)
95 for(int i = 0; i < len; i++)
96 printf("%02X ", data[i]);
97 if(newline)
98 printf("\n");
101 static int convxdigit(char digit, byte *val)
103 if(digit >= '0' && digit <= '9')
105 *val = digit - '0';
106 return 0;
108 else if(digit >= 'A' && digit <= 'F')
110 *val = digit - 'A' + 10;
111 return 0;
113 else if(digit >= 'a' && digit <= 'f')
115 *val = digit - 'a' + 10;
116 return 0;
118 else
119 return 1;
122 typedef byte (*key_array_t)[16];
124 static key_array_t read_keys(int num_keys)
126 int size;
127 struct stat st;
128 int fd = open(key_file,O_RDONLY);
129 if(fd == -1)
130 bugp("opening key file failed");
131 if(fstat(fd,&st) == -1)
132 bugp("key file stat() failed");
133 size = st.st_size;
134 char *buf = xmalloc(size);
135 if(read(fd, buf, size) != (ssize_t)size)
136 bugp("reading key file");
137 close(fd);
139 key_array_t keys = xmalloc(sizeof(byte[16]) * num_keys);
140 int pos = 0;
141 for(int i = 0; i < num_keys; i++)
143 /* skip ws */
144 while(pos < size && isspace(buf[pos]))
145 pos++;
146 /* enough space ? */
147 if((pos + 32) > size)
148 bugp("invalid key file (not enough keys)");
149 for(int j = 0; j < 16; j++)
151 byte a, b;
152 if(convxdigit(buf[pos + 2 * j], &a) || convxdigit(buf[pos + 2 * j + 1], &b))
153 bugp(" invalid key, it should be a 128-bit key written in hexadecimal\n");
154 keys[i][j] = (a << 4) | b;
156 pos += 32;
158 free(buf);
160 return keys;
163 #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
165 static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr)
167 uint8_t sum = 90;
168 byte *ptr = (byte *)hdr;
169 for(int i = 1; i < 16; i++)
170 sum += ptr[i];
171 return sum;
174 static void elf_write(void *user, uint32_t addr, const void *buf, size_t count)
176 FILE *f = user;
177 fseek(f, addr, SEEK_SET);
178 fwrite(buf, count, 1, f);
181 static void extract_elf_section(struct elf_params_t *elf, int count, const char *prefix,
182 const char *indent)
184 char *filename = xmalloc(strlen(prefix) + 32);
185 sprintf(filename, "%s.%d.elf", prefix, count);
186 printf("%swrite %s\n", indent, filename);
188 FILE *fd = fopen(filename, "wb");
189 free(filename);
191 if(fd == NULL)
192 return ;
193 elf_write_file(elf, elf_write, fd);
194 fclose(fd);
197 static void extract_section(int data_sec, char name[5], byte *buf, int size, const char *indent)
199 char filename[PREFIX_SIZE + 32];
200 snprintf(filename, sizeof filename, "%s%s.bin", out_prefix, name);
201 FILE *fd = fopen(filename, "wb");
202 if (fd != NULL) {
203 fwrite(buf, size, 1, fd);
204 fclose(fd);
206 if(data_sec)
207 return;
209 snprintf(filename, sizeof filename, "%s%s", out_prefix, name);
211 /* elf construction */
212 struct elf_params_t elf;
213 elf_init(&elf);
214 int elf_count = 0;
215 /* Pretty print the content */
216 int pos = 0;
217 while(pos < size)
219 struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)&buf[pos];
220 printf("%s", indent);
221 uint8_t checksum = instruction_checksum(hdr);
222 if(checksum != hdr->checksum)
224 color(GREY);
225 printf("[Bad checksum]");
228 if(hdr->opcode == SB_INST_LOAD)
230 struct sb_instruction_load_t *load = (struct sb_instruction_load_t *)&buf[pos];
231 color(RED);
232 printf("LOAD");
233 color(OFF);printf(" | ");
234 color(BLUE);
235 printf("addr=0x%08x", load->addr);
236 color(OFF);printf(" | ");
237 color(GREEN);
238 printf("len=0x%08x", load->len);
239 color(OFF);printf(" | ");
240 color(YELLOW);
241 printf("crc=0x%08x", load->crc);
242 /* data is padded to 16-byte boundary with random data and crc'ed with it */
243 uint32_t computed_crc = crc(&buf[pos + sizeof(struct sb_instruction_load_t)],
244 ROUND_UP(load->len, 16));
245 color(RED);
246 if(load->crc == computed_crc)
247 printf(" Ok\n");
248 else
249 printf(" Failed (crc=0x%08x)\n", computed_crc);
251 /* elf construction */
252 elf_add_load_section(&elf, load->addr, load->len,
253 &buf[pos + sizeof(struct sb_instruction_load_t)]);
255 pos += load->len + sizeof(struct sb_instruction_load_t);
256 // unsure about rounding
257 pos = ROUND_UP(pos, 16);
259 else if(hdr->opcode == SB_INST_FILL)
261 struct sb_instruction_fill_t *fill = (struct sb_instruction_fill_t *)&buf[pos];
262 color(RED);
263 printf("FILL");
264 color(OFF);printf(" | ");
265 color(BLUE);
266 printf("addr=0x%08x", fill->addr);
267 color(OFF);printf(" | ");
268 color(GREEN);
269 printf("len=0x%08x", fill->len);
270 color(OFF);printf(" | ");
271 color(YELLOW);
272 printf("pattern=0x%08x\n", fill->pattern);
273 color(OFF);
275 /* elf construction */
276 elf_add_fill_section(&elf, fill->addr, fill->len, fill->pattern);
278 pos += sizeof(struct sb_instruction_fill_t);
279 // fixme: useless as pos is a multiple of 16 and fill struct is 4-bytes wide ?
280 pos = ROUND_UP(pos, 16);
282 else if(hdr->opcode == SB_INST_CALL ||
283 hdr->opcode == SB_INST_JUMP)
285 int is_call = (hdr->opcode == SB_INST_CALL);
286 struct sb_instruction_call_t *call = (struct sb_instruction_call_t *)&buf[pos];
287 color(RED);
288 if(is_call)
289 printf("CALL");
290 else
291 printf("JUMP");
292 color(OFF);printf(" | ");
293 color(BLUE);
294 printf("addr=0x%08x", call->addr);
295 color(OFF);printf(" | ");
296 color(GREEN);
297 printf("arg=0x%08x\n", call->arg);
298 color(OFF);
300 /* elf construction */
301 elf_set_start_addr(&elf, call->addr);
302 extract_elf_section(&elf, elf_count++, filename, indent);
303 elf_release(&elf);
304 elf_init(&elf);
306 pos += sizeof(struct sb_instruction_call_t);
307 // fixme: useless as pos is a multiple of 16 and call struct is 4-bytes wide ?
308 pos = ROUND_UP(pos, 16);
310 else
312 color(RED);
313 printf("Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos);
314 break;
318 if(!elf_is_empty(&elf))
319 extract_elf_section(&elf, elf_count++, filename, indent);
320 elf_release(&elf);
323 void fill_section_name(char name[5], uint32_t identifier)
325 name[0] = (identifier >> 24) & 0xff;
326 name[1] = (identifier >> 16) & 0xff;
327 name[2] = (identifier >> 8) & 0xff;
328 name[3] = identifier & 0xff;
329 for(int i = 0; i < 4; i++)
330 if(!isprint(name[i]))
331 name[i] = '_';
332 name[4] = 0;
335 static void extract(unsigned long filesize)
337 struct sha_1_params_t sha_1_params;
338 /* Basic header info */
339 struct sb_header_t *sb_header = (struct sb_header_t *)g_buf;
341 if(memcmp(sb_header->signature, "STMP", 4) != 0)
342 bugp("Bad signature");
343 if(sb_header->image_size * BLOCK_SIZE != filesize)
344 bugp("File size mismatch");
345 if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t))
346 bugp("Bad header size");
347 if((sb_header->major_ver != IMAGE_MAJOR_VERSION ||
348 sb_header->minor_ver != IMAGE_MINOR_VERSION) && strcasecmp(s_getenv("SB_IGNORE_VER"), "YES"))
349 bugp("Bad file format version");
350 if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t))
351 bugp("Bad section header size");
353 color(BLUE);
354 printf("Basic info:\n");
355 color(GREEN);
356 printf(" Header SHA-1: ");
357 byte *hdr_sha1 = sb_header->sha1_header;
358 color(YELLOW);
359 print_hex(hdr_sha1, 20, false);
360 /* Check SHA1 sum */
361 byte computed_sha1[20];
362 sha_1_init(&sha_1_params);
363 sha_1_update(&sha_1_params, &sb_header->signature[0],
364 sizeof(struct sb_header_t) - sizeof(sb_header->sha1_header));
365 sha_1_finish(&sha_1_params);
366 sha_1_output(&sha_1_params, computed_sha1);
367 color(RED);
368 if(memcmp(hdr_sha1, computed_sha1, 20) == 0)
369 printf(" Ok\n");
370 else
371 printf(" Failed\n");
372 color(GREEN);
373 printf(" Flags: ");
374 color(YELLOW);
375 printf("%x\n", sb_header->flags);
376 color(GREEN);
377 printf(" Total file size : ");
378 color(YELLOW);
379 printf("%ld\n", filesize);
381 /* Sizes and offsets */
382 color(BLUE);
383 printf("Sizes and offsets:\n");
384 color(GREEN);
385 printf(" # of encryption keys = ");
386 color(YELLOW);
387 printf("%d\n", sb_header->nr_keys);
388 color(GREEN);
389 printf(" # of sections = ");
390 color(YELLOW);
391 printf("%d\n", sb_header->nr_sections);
393 /* Versions */
394 color(BLUE);
395 printf("Versions\n");
396 color(GREEN);
398 printf(" Random 1: ");
399 color(YELLOW);
400 print_hex(sb_header->rand_pad0, sizeof(sb_header->rand_pad0), true);
401 color(GREEN);
402 printf(" Random 2: ");
403 color(YELLOW);
404 print_hex(sb_header->rand_pad1, sizeof(sb_header->rand_pad1), true);
406 uint64_t micros = sb_header->timestamp;
407 time_t seconds = (micros / (uint64_t)1000000L);
408 struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */
409 seconds += mktime(&tm_base);
410 struct tm *time = gmtime(&seconds);
411 color(GREEN);
412 printf(" Creation date/time = ");
413 color(YELLOW);
414 printf("%s", asctime(time));
416 color(GREEN);
417 printf(" Product version = ");
418 color(YELLOW);
419 printf("%X.%X.%X\n", sb_header->product_ver.major,
420 sb_header->product_ver.minor, sb_header->product_ver.revision);
421 color(GREEN);
422 printf(" Component version = ");
423 color(YELLOW);
424 printf("%X.%X.%X\n", sb_header->component_ver.major,
425 sb_header->component_ver.minor, sb_header->component_ver.revision);
427 color(GREEN);
428 printf(" Drive tag = ");
429 color(YELLOW);
430 printf("%x\n", sb_header->drive_tag);
431 color(GREEN);
432 printf(" First boot tag offset = ");
433 color(YELLOW);
434 printf("%x\n", sb_header->first_boot_tag_off);
435 color(GREEN);
436 printf(" First boot section ID = ");
437 color(YELLOW);
438 printf("0x%08x\n", sb_header->first_boot_sec_id);
440 /* encryption cbc-mac */
441 key_array_t keys = NULL; /* array of 16-bytes keys */
442 byte real_key[16];
443 if(sb_header->nr_keys > 0)
445 keys = read_keys(sb_header->nr_keys);
446 color(BLUE);
447 printf("Encryption data\n");
448 for(int i = 0; i < sb_header->nr_keys; i++)
450 color(RED);
451 printf(" Key %d: ", i);
452 print_hex(keys[i], 16, true);
453 color(GREEN);
454 printf(" CBC-MAC of headers: ");
456 uint32_t ofs = sizeof(struct sb_header_t)
457 + sizeof(struct sb_section_header_t) * sb_header->nr_sections
458 + sizeof(struct sb_key_dictionary_entry_t) * i;
459 struct sb_key_dictionary_entry_t *dict_entry =
460 (struct sb_key_dictionary_entry_t *)&g_buf[ofs];
461 /* cbc mac */
462 color(YELLOW);
463 print_hex(dict_entry->hdr_cbc_mac, 16, false);
464 /* check it */
465 byte computed_cbc_mac[16];
466 byte zero[16];
467 memset(zero, 0, 16);
468 cbc_mac(g_buf, NULL, sb_header->header_size + sb_header->nr_sections,
469 keys[i], zero, &computed_cbc_mac, 1);
470 color(RED);
471 if(memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0)
472 printf(" Ok\n");
473 else
474 printf(" Failed\n");
475 color(GREEN);
477 printf(" Encrypted key : ");
478 color(YELLOW);
479 print_hex(dict_entry->key, 16, true);
480 color(GREEN);
481 /* decrypt */
482 byte decrypted_key[16];
483 byte iv[16];
484 memcpy(iv, g_buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
485 cbc_mac(dict_entry->key, decrypted_key, 1, keys[i], iv, NULL, 0);
486 printf(" Decrypted key : ");
487 color(YELLOW);
488 print_hex(decrypted_key, 16, false);
489 /* cross-check or copy */
490 if(i == 0)
491 memcpy(real_key, decrypted_key, 16);
492 else if(memcmp(real_key, decrypted_key, 16) == 0)
494 color(RED);
495 printf(" Cross-Check Ok");
497 else
499 color(RED);
500 printf(" Cross-Check Failed");
502 printf("\n");
506 /* sections */
507 if(strcasecmp(s_getenv("SB_RAW_CMD"), "YES") != 0)
509 color(BLUE);
510 printf("Sections\n");
511 for(int i = 0; i < sb_header->nr_sections; i++)
513 uint32_t ofs = sb_header->header_size * BLOCK_SIZE + i * sizeof(struct sb_section_header_t);
514 struct sb_section_header_t *sec_hdr = (struct sb_section_header_t *)&g_buf[ofs];
516 char name[5];
517 fill_section_name(name, sec_hdr->identifier);
518 int pos = sec_hdr->offset * BLOCK_SIZE;
519 int size = sec_hdr->size * BLOCK_SIZE;
520 int data_sec = !(sec_hdr->flags & SECTION_BOOTABLE);
521 int encrypted = !(sec_hdr->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0;
523 color(GREEN);
524 printf(" Section ");
525 color(YELLOW);
526 printf("'%s'\n", name);
527 color(GREEN);
528 printf(" pos = ");
529 color(YELLOW);
530 printf("%8x - %8x\n", pos, pos+size);
531 color(GREEN);
532 printf(" len = ");
533 color(YELLOW);
534 printf("%8x\n", size);
535 color(GREEN);
536 printf(" flags = ");
537 color(YELLOW);
538 printf("%8x", sec_hdr->flags);
539 color(RED);
540 if(data_sec)
541 printf(" Data Section");
542 else
543 printf(" Boot Section");
544 if(encrypted)
545 printf(" (Encrypted)");
546 printf("\n");
548 /* save it */
549 byte *sec = xmalloc(size);
550 if(encrypted)
551 cbc_mac(g_buf + pos, sec, size / BLOCK_SIZE, real_key, g_buf, NULL, 0);
552 else
553 memcpy(sec, g_buf + pos, size);
555 extract_section(data_sec, name, sec, size, " ");
556 free(sec);
559 else
561 /* advanced raw mode */
562 color(BLUE);
563 printf("Commands\n");
564 uint32_t offset = sb_header->first_boot_tag_off * BLOCK_SIZE;
565 byte iv[16];
566 memcpy(iv, g_buf, 16);
567 const char *indent = " ";
568 while(true)
570 byte cmd[16];
571 if(sb_header->nr_keys > 0)
572 cbc_mac(g_buf + offset, cmd, 1, real_key, iv, &iv, 0);
573 else
574 memcpy(cmd, g_buf + offset, BLOCK_SIZE);
575 struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)cmd;
576 printf("%s", indent);
577 uint8_t checksum = instruction_checksum(hdr);
578 if(checksum != hdr->checksum)
580 color(GREY);
581 printf("[Bad checksum]");
584 if(hdr->opcode == SB_INST_NOP)
586 color(RED);
587 printf("NOOP\n");
588 offset += BLOCK_SIZE;
590 else if(hdr->opcode == SB_INST_TAG)
592 struct sb_instruction_tag_t *tag = (struct sb_instruction_tag_t *)hdr;
593 color(RED);
594 printf("BTAG");
595 color(OFF);printf(" | ");
596 color(BLUE);
597 printf("sec=0x%08x", tag->identifier);
598 color(OFF);printf(" | ");
599 color(GREEN);
600 printf("cnt=0x%08x", tag->len);
601 color(OFF);printf(" | ");
602 color(YELLOW);
603 printf("flg=0x%08x\n", tag->flags);
604 color(OFF);
605 offset += sizeof(struct sb_instruction_tag_t);
607 char name[5];
608 fill_section_name(name, tag->identifier);
609 int pos = offset;
610 int size = tag->len * BLOCK_SIZE;
611 int data_sec = !(tag->flags & SECTION_BOOTABLE);
612 int encrypted = !(tag->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0;
614 color(GREEN);
615 printf("%sSection ", indent);
616 color(YELLOW);
617 printf("'%s'\n", name);
618 color(GREEN);
619 printf("%s pos = ", indent);
620 color(YELLOW);
621 printf("%8x - %8x\n", pos, pos+size);
622 color(GREEN);
623 printf("%s len = ", indent);
624 color(YELLOW);
625 printf("%8x\n", size);
626 color(GREEN);
627 printf("%s flags = ", indent);
628 color(YELLOW);
629 printf("%8x", tag->flags);
630 color(RED);
631 if(data_sec)
632 printf(" Data Section");
633 else
634 printf(" Boot Section");
635 if(encrypted)
636 printf(" (Encrypted)");
637 printf("\n");
639 /* save it */
640 byte *sec = xmalloc(size);
641 if(encrypted)
642 cbc_mac(g_buf + pos, sec, size / BLOCK_SIZE, real_key, g_buf, NULL, 0);
643 else
644 memcpy(sec, g_buf + pos, size);
646 extract_section(data_sec, name, sec, size, " ");
647 free(sec);
649 /* last one ? */
650 if(tag->hdr.flags & SB_INST_LAST_TAG)
651 break;
652 offset += size;
653 /* restart with IV */
654 memcpy(iv, g_buf, 16);
656 else
658 color(RED);
659 printf("Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset);
660 break;
665 /* final signature */
666 color(BLUE);
667 printf("Final signature:\n");
668 byte decrypted_block[32];
669 if(sb_header->nr_keys > 0)
671 color(GREEN);
672 printf(" Encrypted SHA-1:\n");
673 color(YELLOW);
674 byte *encrypted_block = &g_buf[filesize - 32];
675 printf(" ");
676 print_hex(encrypted_block, 16, true);
677 printf(" ");
678 print_hex(encrypted_block + 16, 16, true);
679 /* decrypt it */
680 cbc_mac(encrypted_block, decrypted_block, 2, real_key, g_buf, NULL, 0);
682 else
683 memcpy(decrypted_block, &g_buf[filesize - 32], 32);
684 color(GREEN);
685 printf(" File SHA-1:\n ");
686 color(YELLOW);
687 print_hex(decrypted_block, 20, false);
688 /* check it */
689 sha_1_init(&sha_1_params);
690 sha_1_update(&sha_1_params, g_buf, filesize - 32);
691 sha_1_finish(&sha_1_params);
692 sha_1_output(&sha_1_params, computed_sha1);
693 color(RED);
694 if(memcmp(decrypted_block, computed_sha1, 20) == 0)
695 printf(" Ok\n");
696 else
697 printf(" Failed\n");
700 int main(int argc, const char **argv)
702 int fd;
703 struct stat st;
704 if(argc != 3 && argc != 4)
706 printf("Usage: %s <firmware> <key file> [<out prefix>]\n",*argv);
707 printf("To use raw command mode, set environment variable SB_RAW_CMD to YES\n");
708 return 1;
711 if(argc == 4)
712 snprintf(out_prefix, PREFIX_SIZE, "%s", argv[3]);
713 else
714 strcpy(out_prefix, "");
716 if( (fd = open(argv[1], O_RDONLY)) == -1 )
717 bugp("opening firmware failed");
719 key_file = argv[2];
721 if(fstat(fd, &st) == -1)
722 bugp("firmware stat() failed");
723 g_sz = st.st_size;
725 g_buf = xmalloc(g_sz);
726 if(read(fd, g_buf, g_sz) != (ssize_t)g_sz) /* load the whole file into memory */
727 bugp("reading firmware");
729 close(fd);
731 extract(st.st_size);
733 color(OFF);
735 free(g_buf);
736 return 0;