We have a 3.9 release, update builds.pm
[maemo-rb.git] / utils / sbtools / sbtoelf.c
blob7e6b77055bcb0f6a4c4831eef6682243d518b527
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 if(hdr->opcode == SB_INST_MODE)
312 struct sb_instruction_mode_t *mode = (struct sb_instruction_mode_t *)hdr;
313 color(RED);
314 printf("MODE");
315 color(OFF);printf(" | ");
316 color(BLUE);
317 printf("mod=0x%08x\n", mode->mode);
318 color(OFF);
319 pos += sizeof(struct sb_instruction_mode_t);
321 else
323 color(RED);
324 printf("Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos);
325 break;
329 if(!elf_is_empty(&elf))
330 extract_elf_section(&elf, elf_count++, filename, indent);
331 elf_release(&elf);
334 void fill_section_name(char name[5], uint32_t identifier)
336 name[0] = (identifier >> 24) & 0xff;
337 name[1] = (identifier >> 16) & 0xff;
338 name[2] = (identifier >> 8) & 0xff;
339 name[3] = identifier & 0xff;
340 for(int i = 0; i < 4; i++)
341 if(!isprint(name[i]))
342 name[i] = '_';
343 name[4] = 0;
346 static void extract(unsigned long filesize)
348 struct sha_1_params_t sha_1_params;
349 /* Basic header info */
350 struct sb_header_t *sb_header = (struct sb_header_t *)g_buf;
352 if(memcmp(sb_header->signature, "STMP", 4) != 0)
353 bugp("Bad signature");
354 if(sb_header->image_size * BLOCK_SIZE != filesize)
355 bugp("File size mismatch");
356 if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t))
357 bugp("Bad header size");
358 if((sb_header->major_ver != IMAGE_MAJOR_VERSION ||
359 sb_header->minor_ver != IMAGE_MINOR_VERSION) && strcasecmp(s_getenv("SB_IGNORE_VER"), "YES"))
360 bugp("Bad file format version");
361 if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t))
362 bugp("Bad section header size");
364 color(BLUE);
365 printf("Basic info:\n");
366 color(GREEN);
367 printf(" Header SHA-1: ");
368 byte *hdr_sha1 = sb_header->sha1_header;
369 color(YELLOW);
370 print_hex(hdr_sha1, 20, false);
371 /* Check SHA1 sum */
372 byte computed_sha1[20];
373 sha_1_init(&sha_1_params);
374 sha_1_update(&sha_1_params, &sb_header->signature[0],
375 sizeof(struct sb_header_t) - sizeof(sb_header->sha1_header));
376 sha_1_finish(&sha_1_params);
377 sha_1_output(&sha_1_params, computed_sha1);
378 color(RED);
379 if(memcmp(hdr_sha1, computed_sha1, 20) == 0)
380 printf(" Ok\n");
381 else
382 printf(" Failed\n");
383 color(GREEN);
384 printf(" Flags: ");
385 color(YELLOW);
386 printf("%x\n", sb_header->flags);
387 color(GREEN);
388 printf(" Total file size : ");
389 color(YELLOW);
390 printf("%ld\n", filesize);
392 /* Sizes and offsets */
393 color(BLUE);
394 printf("Sizes and offsets:\n");
395 color(GREEN);
396 printf(" # of encryption keys = ");
397 color(YELLOW);
398 printf("%d\n", sb_header->nr_keys);
399 color(GREEN);
400 printf(" # of sections = ");
401 color(YELLOW);
402 printf("%d\n", sb_header->nr_sections);
404 /* Versions */
405 color(BLUE);
406 printf("Versions\n");
407 color(GREEN);
409 printf(" Random 1: ");
410 color(YELLOW);
411 print_hex(sb_header->rand_pad0, sizeof(sb_header->rand_pad0), true);
412 color(GREEN);
413 printf(" Random 2: ");
414 color(YELLOW);
415 print_hex(sb_header->rand_pad1, sizeof(sb_header->rand_pad1), true);
417 uint64_t micros = sb_header->timestamp;
418 time_t seconds = (micros / (uint64_t)1000000L);
419 struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */
420 seconds += mktime(&tm_base);
421 struct tm *time = gmtime(&seconds);
422 color(GREEN);
423 printf(" Creation date/time = ");
424 color(YELLOW);
425 printf("%s", asctime(time));
427 color(GREEN);
428 printf(" Product version = ");
429 color(YELLOW);
430 printf("%X.%X.%X\n", sb_header->product_ver.major,
431 sb_header->product_ver.minor, sb_header->product_ver.revision);
432 color(GREEN);
433 printf(" Component version = ");
434 color(YELLOW);
435 printf("%X.%X.%X\n", sb_header->component_ver.major,
436 sb_header->component_ver.minor, sb_header->component_ver.revision);
438 color(GREEN);
439 printf(" Drive tag = ");
440 color(YELLOW);
441 printf("%x\n", sb_header->drive_tag);
442 color(GREEN);
443 printf(" First boot tag offset = ");
444 color(YELLOW);
445 printf("%x\n", sb_header->first_boot_tag_off);
446 color(GREEN);
447 printf(" First boot section ID = ");
448 color(YELLOW);
449 printf("0x%08x\n", sb_header->first_boot_sec_id);
451 /* encryption cbc-mac */
452 key_array_t keys = NULL; /* array of 16-bytes keys */
453 byte real_key[16];
454 if(sb_header->nr_keys > 0)
456 keys = read_keys(sb_header->nr_keys);
457 color(BLUE);
458 printf("Encryption data\n");
459 for(int i = 0; i < sb_header->nr_keys; i++)
461 color(RED);
462 printf(" Key %d: ", i);
463 print_hex(keys[i], 16, true);
464 color(GREEN);
465 printf(" CBC-MAC of headers: ");
467 uint32_t ofs = sizeof(struct sb_header_t)
468 + sizeof(struct sb_section_header_t) * sb_header->nr_sections
469 + sizeof(struct sb_key_dictionary_entry_t) * i;
470 struct sb_key_dictionary_entry_t *dict_entry =
471 (struct sb_key_dictionary_entry_t *)&g_buf[ofs];
472 /* cbc mac */
473 color(YELLOW);
474 print_hex(dict_entry->hdr_cbc_mac, 16, false);
475 /* check it */
476 byte computed_cbc_mac[16];
477 byte zero[16];
478 memset(zero, 0, 16);
479 cbc_mac(g_buf, NULL, sb_header->header_size + sb_header->nr_sections,
480 keys[i], zero, &computed_cbc_mac, 1);
481 color(RED);
482 if(memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0)
483 printf(" Ok\n");
484 else
485 printf(" Failed\n");
486 color(GREEN);
488 printf(" Encrypted key : ");
489 color(YELLOW);
490 print_hex(dict_entry->key, 16, true);
491 color(GREEN);
492 /* decrypt */
493 byte decrypted_key[16];
494 byte iv[16];
495 memcpy(iv, g_buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
496 cbc_mac(dict_entry->key, decrypted_key, 1, keys[i], iv, NULL, 0);
497 printf(" Decrypted key : ");
498 color(YELLOW);
499 print_hex(decrypted_key, 16, false);
500 /* cross-check or copy */
501 if(i == 0)
502 memcpy(real_key, decrypted_key, 16);
503 else if(memcmp(real_key, decrypted_key, 16) == 0)
505 color(RED);
506 printf(" Cross-Check Ok");
508 else
510 color(RED);
511 printf(" Cross-Check Failed");
513 printf("\n");
517 /* sections */
518 if(strcasecmp(s_getenv("SB_RAW_CMD"), "YES") != 0)
520 color(BLUE);
521 printf("Sections\n");
522 for(int i = 0; i < sb_header->nr_sections; i++)
524 uint32_t ofs = sb_header->header_size * BLOCK_SIZE + i * sizeof(struct sb_section_header_t);
525 struct sb_section_header_t *sec_hdr = (struct sb_section_header_t *)&g_buf[ofs];
527 char name[5];
528 fill_section_name(name, sec_hdr->identifier);
529 int pos = sec_hdr->offset * BLOCK_SIZE;
530 int size = sec_hdr->size * BLOCK_SIZE;
531 int data_sec = !(sec_hdr->flags & SECTION_BOOTABLE);
532 int encrypted = !(sec_hdr->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0;
534 color(GREEN);
535 printf(" Section ");
536 color(YELLOW);
537 printf("'%s'\n", name);
538 color(GREEN);
539 printf(" pos = ");
540 color(YELLOW);
541 printf("%8x - %8x\n", pos, pos+size);
542 color(GREEN);
543 printf(" len = ");
544 color(YELLOW);
545 printf("%8x\n", size);
546 color(GREEN);
547 printf(" flags = ");
548 color(YELLOW);
549 printf("%8x", sec_hdr->flags);
550 color(RED);
551 if(data_sec)
552 printf(" Data Section");
553 else
554 printf(" Boot Section");
555 if(encrypted)
556 printf(" (Encrypted)");
557 printf("\n");
559 /* save it */
560 byte *sec = xmalloc(size);
561 if(encrypted)
562 cbc_mac(g_buf + pos, sec, size / BLOCK_SIZE, real_key, g_buf, NULL, 0);
563 else
564 memcpy(sec, g_buf + pos, size);
566 extract_section(data_sec, name, sec, size, " ");
567 free(sec);
570 else
572 /* advanced raw mode */
573 color(BLUE);
574 printf("Commands\n");
575 uint32_t offset = sb_header->first_boot_tag_off * BLOCK_SIZE;
576 byte iv[16];
577 memcpy(iv, g_buf, 16);
578 const char *indent = " ";
579 while(true)
581 byte cmd[16];
582 if(sb_header->nr_keys > 0)
583 cbc_mac(g_buf + offset, cmd, 1, real_key, iv, &iv, 0);
584 else
585 memcpy(cmd, g_buf + offset, BLOCK_SIZE);
586 struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)cmd;
587 printf("%s", indent);
588 uint8_t checksum = instruction_checksum(hdr);
589 if(checksum != hdr->checksum)
591 color(GREY);
592 printf("[Bad checksum]");
595 if(hdr->opcode == SB_INST_NOP)
597 color(RED);
598 printf("NOOP\n");
599 offset += BLOCK_SIZE;
601 else if(hdr->opcode == SB_INST_TAG)
603 struct sb_instruction_tag_t *tag = (struct sb_instruction_tag_t *)hdr;
604 color(RED);
605 printf("BTAG");
606 color(OFF);printf(" | ");
607 color(BLUE);
608 printf("sec=0x%08x", tag->identifier);
609 color(OFF);printf(" | ");
610 color(GREEN);
611 printf("cnt=0x%08x", tag->len);
612 color(OFF);printf(" | ");
613 color(YELLOW);
614 printf("flg=0x%08x\n", tag->flags);
615 color(OFF);
616 offset += sizeof(struct sb_instruction_tag_t);
618 char name[5];
619 fill_section_name(name, tag->identifier);
620 int pos = offset;
621 int size = tag->len * BLOCK_SIZE;
622 int data_sec = !(tag->flags & SECTION_BOOTABLE);
623 int encrypted = !(tag->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0;
625 color(GREEN);
626 printf("%sSection ", indent);
627 color(YELLOW);
628 printf("'%s'\n", name);
629 color(GREEN);
630 printf("%s pos = ", indent);
631 color(YELLOW);
632 printf("%8x - %8x\n", pos, pos+size);
633 color(GREEN);
634 printf("%s len = ", indent);
635 color(YELLOW);
636 printf("%8x\n", size);
637 color(GREEN);
638 printf("%s flags = ", indent);
639 color(YELLOW);
640 printf("%8x", tag->flags);
641 color(RED);
642 if(data_sec)
643 printf(" Data Section");
644 else
645 printf(" Boot Section");
646 if(encrypted)
647 printf(" (Encrypted)");
648 printf("\n");
650 /* save it */
651 byte *sec = xmalloc(size);
652 if(encrypted)
653 cbc_mac(g_buf + pos, sec, size / BLOCK_SIZE, real_key, g_buf, NULL, 0);
654 else
655 memcpy(sec, g_buf + pos, size);
657 extract_section(data_sec, name, sec, size, " ");
658 free(sec);
660 /* last one ? */
661 if(tag->hdr.flags & SB_INST_LAST_TAG)
662 break;
663 offset += size;
664 /* restart with IV */
665 memcpy(iv, g_buf, 16);
667 else
669 color(RED);
670 printf("Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset);
671 break;
676 /* final signature */
677 color(BLUE);
678 printf("Final signature:\n");
679 byte decrypted_block[32];
680 if(sb_header->nr_keys > 0)
682 color(GREEN);
683 printf(" Encrypted SHA-1:\n");
684 color(YELLOW);
685 byte *encrypted_block = &g_buf[filesize - 32];
686 printf(" ");
687 print_hex(encrypted_block, 16, true);
688 printf(" ");
689 print_hex(encrypted_block + 16, 16, true);
690 /* decrypt it */
691 cbc_mac(encrypted_block, decrypted_block, 2, real_key, g_buf, NULL, 0);
693 else
694 memcpy(decrypted_block, &g_buf[filesize - 32], 32);
695 color(GREEN);
696 printf(" File SHA-1:\n ");
697 color(YELLOW);
698 print_hex(decrypted_block, 20, false);
699 /* check it */
700 sha_1_init(&sha_1_params);
701 sha_1_update(&sha_1_params, g_buf, filesize - 32);
702 sha_1_finish(&sha_1_params);
703 sha_1_output(&sha_1_params, computed_sha1);
704 color(RED);
705 if(memcmp(decrypted_block, computed_sha1, 20) == 0)
706 printf(" Ok\n");
707 else
708 printf(" Failed\n");
711 int main(int argc, const char **argv)
713 int fd;
714 struct stat st;
715 if(argc != 3 && argc != 4)
717 printf("Usage: %s <firmware> <key file> [<out prefix>]\n",*argv);
718 printf("To use raw command mode, set environment variable SB_RAW_CMD to YES\n");
719 printf("To ignore the file version check, set environment variable SB_IGNORE_VER to YES\n");
720 return 1;
723 if(argc == 4)
724 snprintf(out_prefix, PREFIX_SIZE, "%s", argv[3]);
725 else
726 strcpy(out_prefix, "");
728 if( (fd = open(argv[1], O_RDONLY)) == -1 )
729 bugp("opening firmware failed");
731 key_file = argv[2];
733 if(fstat(fd, &st) == -1)
734 bugp("firmware stat() failed");
735 g_sz = st.st_size;
737 g_buf = xmalloc(g_sz);
738 if(read(fd, g_buf, g_sz) != (ssize_t)g_sz) /* load the whole file into memory */
739 bugp("reading firmware");
741 close(fd);
743 extract(st.st_size);
745 color(OFF);
747 free(g_buf);
748 return 0;