source: trunk/tools/firmware-utils/src/mktplinkfw.c

Last change on this file was 49215, checked in by blogic, 5 months ago

tools: firmware-utils: add region code support to mktplinkfw

Signed-off-by: Matthias Schiffer <mschiffer@…>

  • Property svn:eol-style set to native
File size: 19.7 KB
Line 
1/*
2 * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
3 *
4 * This tool was based on:
5 *   TP-Link WR941 V2 firmware checksum fixing tool.
6 *   Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published
10 * by the Free Software Foundation.
11 *
12 */
13
14#include <stdio.h>
15#include <stdlib.h>
16#include <stdint.h>
17#include <string.h>
18#include <unistd.h>     /* for unlink() */
19#include <libgen.h>
20#include <getopt.h>     /* for getopt() */
21#include <stdarg.h>
22#include <errno.h>
23#include <sys/stat.h>
24
25#include <arpa/inet.h>
26#include <netinet/in.h>
27
28#include "md5.h"
29
30#define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
31#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
32
33#define HEADER_VERSION_V1       0x01000000
34#define HEADER_VERSION_V2       0x02000000
35
36#define MD5SUM_LEN      16
37
38struct file_info {
39        char            *file_name;     /* name of the file */
40        uint32_t        file_size;      /* length of the file */
41};
42
43struct fw_header {
44        uint32_t        version;        /* header version */
45        char            vendor_name[24];
46        char            fw_version[36];
47        uint32_t        hw_id;          /* hardware id */
48        uint32_t        hw_rev;         /* hardware revision */
49        uint32_t        region;         /* region code */
50        uint8_t         md5sum1[MD5SUM_LEN];
51        uint32_t        unk2;
52        uint8_t         md5sum2[MD5SUM_LEN];
53        uint32_t        unk3;
54        uint32_t        kernel_la;      /* kernel load address */
55        uint32_t        kernel_ep;      /* kernel entry point */
56        uint32_t        fw_length;      /* total length of the firmware */
57        uint32_t        kernel_ofs;     /* kernel data offset */
58        uint32_t        kernel_len;     /* kernel data length */
59        uint32_t        rootfs_ofs;     /* rootfs data offset */
60        uint32_t        rootfs_len;     /* rootfs data length */
61        uint32_t        boot_ofs;       /* bootloader data offset */
62        uint32_t        boot_len;       /* bootloader data length */
63        uint16_t        ver_hi;
64        uint16_t        ver_mid;
65        uint16_t        ver_lo;
66        uint8_t         pad[354];
67} __attribute__ ((packed));
68
69struct flash_layout {
70        char            *id;
71        uint32_t        fw_max_len;
72        uint32_t        kernel_la;
73        uint32_t        kernel_ep;
74        uint32_t        rootfs_ofs;
75};
76
77/*
78 * Globals
79 */
80static char *ofname;
81static char *progname;
82static char *vendor = "TP-LINK Technologies";
83static char *version = "ver. 1.0";
84static char *fw_ver = "0.0.0";
85static uint32_t hdr_ver = HEADER_VERSION_V1;
86
87static char *layout_id;
88static struct flash_layout *layout;
89static char *opt_hw_id;
90static uint32_t hw_id;
91static char *opt_hw_rev;
92static uint32_t hw_rev;
93static uint32_t opt_hdr_ver = 1;
94static char *country;
95static uint32_t region;
96static int fw_ver_lo;
97static int fw_ver_mid;
98static int fw_ver_hi;
99static struct file_info kernel_info;
100static uint32_t kernel_la = 0;
101static uint32_t kernel_ep = 0;
102static uint32_t kernel_len = 0;
103static struct file_info rootfs_info;
104static uint32_t rootfs_ofs = 0;
105static uint32_t rootfs_align;
106static struct file_info boot_info;
107static int combined;
108static int strip_padding;
109static int ignore_size;
110static int add_jffs2_eof;
111static unsigned char jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde};
112static uint32_t fw_max_len;
113static uint32_t reserved_space;
114
115static struct file_info inspect_info;
116static int extract = 0;
117
118static const char md5salt_normal[MD5SUM_LEN] = {
119        0xdc, 0xd7, 0x3a, 0xa5, 0xc3, 0x95, 0x98, 0xfb,
120        0xdd, 0xf9, 0xe7, 0xf4, 0x0e, 0xae, 0x47, 0x38,
121};
122
123static const char md5salt_boot[MD5SUM_LEN] = {
124        0x8c, 0xef, 0x33, 0x5b, 0xd5, 0xc5, 0xce, 0xfa,
125        0xa7, 0x9c, 0x28, 0xda, 0xb2, 0xe9, 0x0f, 0x42,
126};
127
128static struct flash_layout layouts[] = {
129        {
130                .id             = "4M",
131                .fw_max_len     = 0x3c0000,
132                .kernel_la      = 0x80060000,
133                .kernel_ep      = 0x80060000,
134                .rootfs_ofs     = 0x140000,
135        }, {
136                .id             = "4Mlzma",
137                .fw_max_len     = 0x3c0000,
138                .kernel_la      = 0x80060000,
139                .kernel_ep      = 0x80060000,
140                .rootfs_ofs     = 0x100000,
141        }, {
142                .id             = "8M",
143                .fw_max_len     = 0x7c0000,
144                .kernel_la      = 0x80060000,
145                .kernel_ep      = 0x80060000,
146                .rootfs_ofs     = 0x140000,
147        }, {
148                .id             = "8Mlzma",
149                .fw_max_len     = 0x7c0000,
150                .kernel_la      = 0x80060000,
151                .kernel_ep      = 0x80060000,
152                .rootfs_ofs     = 0x100000,
153        }, {
154                .id             = "16M",
155                .fw_max_len     = 0xf80000,
156                .kernel_la      = 0x80060000,
157                .kernel_ep      = 0x80060000,
158                .rootfs_ofs     = 0x140000,
159        }, {
160                .id             = "16Mlzma",
161                .fw_max_len     = 0xf80000,
162                .kernel_la      = 0x80060000,
163                .kernel_ep      = 0x80060000,
164                .rootfs_ofs     = 0x100000,
165        }, {
166                .id             = "16Mppc",
167                .fw_max_len     = 0xf80000,
168                .kernel_la      = 0x00000000 ,
169                .kernel_ep      = 0xc0000000,
170                .rootfs_ofs     = 0x2a0000,
171        }, {
172                /* terminating entry */
173        }
174};
175
176static const char *const regions[] = {
177        "UN", /* universal */
178        "US",
179};
180
181/*
182 * Message macros
183 */
184#define ERR(fmt, ...) do { \
185        fflush(0); \
186        fprintf(stderr, "[%s] *** error: " fmt "\n", \
187                        progname, ## __VA_ARGS__ ); \
188} while (0)
189
190#define ERRS(fmt, ...) do { \
191        int save = errno; \
192        fflush(0); \
193        fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
194                        progname, ## __VA_ARGS__, strerror(save)); \
195} while (0)
196
197#define DBG(fmt, ...) do { \
198        fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
199} while (0)
200
201static struct flash_layout *find_layout(const char *id)
202{
203        struct flash_layout *ret;
204        struct flash_layout *l;
205
206        ret = NULL;
207        for (l = layouts; l->id != NULL; l++){
208                if (strcasecmp(id, l->id) == 0) {
209                        ret = l;
210                        break;
211                }
212        };
213
214        return ret;
215}
216
217static uint32_t find_region(const char *country) {
218        uint32_t i;
219
220        for (i = 0; i < ARRAY_SIZE(regions); i++) {
221                if (strcasecmp(regions[i], country) == 0)
222                        return i;
223        }
224
225        return -1;
226}
227
228static const char * get_region_country(uint32_t region) {
229        if (region < ARRAY_SIZE(regions))
230                return regions[region];
231        else
232                return "unknown";
233}
234
235static void usage(int status)
236{
237        fprintf(stderr, "Usage: %s [OPTIONS...]\n", progname);
238        fprintf(stderr,
239"\n"
240"Options:\n"
241"  -c              use combined kernel image\n"
242"  -E <ep>         overwrite kernel entry point with <ep> (hexval prefixed with 0x)\n"
243"  -L <la>         overwrite kernel load address with <la> (hexval prefixed with 0x)\n"
244"  -H <hwid>       use hardware id specified with <hwid>\n"
245"  -W <hwrev>      use hardware revision specified with <hwrev>\n"
246"  -C <country>    set region code to <country>\n"
247"  -F <id>         use flash layout specified with <id>\n"
248"  -k <file>       read kernel image from the file <file>\n"
249"  -r <file>       read rootfs image from the file <file>\n"
250"  -a <align>      align the rootfs start on an <align> bytes boundary\n"
251"  -R <offset>     overwrite rootfs offset with <offset> (hexval prefixed with 0x)\n"
252"  -o <file>       write output to the file <file>\n"
253"  -s              strip padding from the end of the image\n"
254"  -S              ignore firmware size limit (only for combined images)\n"
255"  -j              add jffs2 end-of-filesystem markers\n"
256"  -N <vendor>     set image vendor to <vendor>\n"
257"  -V <version>    set image version to <version>\n"
258"  -v <version>    set firmware version to <version>\n"
259"  -m <version>    set header version to <version>\n"
260"  -i <file>       inspect given firmware file <file>\n"
261"  -x              extract kernel and rootfs while inspecting (requires -i)\n"
262"  -X <size>       reserve <size> bytes in the firmware image (hexval prefixed with 0x)\n"
263"  -h              show this screen\n"
264        );
265
266        exit(status);
267}
268
269static void get_md5(const char *data, int size, uint8_t *md5)
270{
271        MD5_CTX ctx;
272
273        MD5_Init(&ctx);
274        MD5_Update(&ctx, data, size);
275        MD5_Final(md5, &ctx);
276}
277
278static int get_file_stat(struct file_info *fdata)
279{
280        struct stat st;
281        int res;
282
283        if (fdata->file_name == NULL)
284                return 0;
285
286        res = stat(fdata->file_name, &st);
287        if (res){
288                ERRS("stat failed on %s", fdata->file_name);
289                return res;
290        }
291
292        fdata->file_size = st.st_size;
293        return 0;
294}
295
296static int read_to_buf(const struct file_info *fdata, char *buf)
297{
298        FILE *f;
299        int ret = EXIT_FAILURE;
300
301        f = fopen(fdata->file_name, "r");
302        if (f == NULL) {
303                ERRS("could not open \"%s\" for reading", fdata->file_name);
304                goto out;
305        }
306
307        errno = 0;
308        fread(buf, fdata->file_size, 1, f);
309        if (errno != 0) {
310                ERRS("unable to read from file \"%s\"", fdata->file_name);
311                goto out_close;
312        }
313
314        ret = EXIT_SUCCESS;
315
316 out_close:
317        fclose(f);
318 out:
319        return ret;
320}
321
322static int check_options(void)
323{
324        int ret;
325        int exceed_bytes;
326
327        if (inspect_info.file_name) {
328                ret = get_file_stat(&inspect_info);
329                if (ret)
330                        return ret;
331
332                return 0;
333        } else if (extract) {
334                ERR("no firmware for inspection specified");
335                return -1;
336        }
337
338        if (opt_hw_id == NULL) {
339                ERR("hardware id not specified");
340                return -1;
341        }
342        hw_id = strtoul(opt_hw_id, NULL, 0);
343
344        if (layout_id == NULL) {
345                ERR("flash layout is not specified");
346                return -1;
347        }
348
349        if (opt_hw_rev)
350                hw_rev = strtoul(opt_hw_rev, NULL, 0);
351        else
352                hw_rev = 1;
353
354        if (country) {
355                region = find_region(country);
356                if (region == (uint32_t)-1) {
357                        char *end;
358                        region = strtoul(country, &end, 0);
359                        if (*end) {
360                                ERR("unknown region code \"%s\"", country);
361                                return -1;
362                        }
363                }
364        }
365
366        layout = find_layout(layout_id);
367        if (layout == NULL) {
368                ERR("unknown flash layout \"%s\"", layout_id);
369                return -1;
370        }
371
372        if (!kernel_la)
373                kernel_la = layout->kernel_la;
374        if (!kernel_ep)
375                kernel_ep = layout->kernel_ep;
376        if (!rootfs_ofs)
377                rootfs_ofs = layout->rootfs_ofs;
378
379        if (reserved_space > layout->fw_max_len) {
380                ERR("reserved space is not valid");
381                return -1;
382        }
383
384        fw_max_len = layout->fw_max_len - reserved_space;
385
386        if (kernel_info.file_name == NULL) {
387                ERR("no kernel image specified");
388                return -1;
389        }
390
391        ret = get_file_stat(&kernel_info);
392        if (ret)
393                return ret;
394
395        kernel_len = kernel_info.file_size;
396
397        if (combined) {
398                exceed_bytes = kernel_info.file_size - (fw_max_len - sizeof(struct fw_header));
399                if (exceed_bytes > 0) {
400                        if (!ignore_size) {
401                                ERR("kernel image is too big by %i bytes", exceed_bytes);
402                                return -1;
403                        }
404                        layout->fw_max_len = sizeof(struct fw_header) +
405                                             kernel_info.file_size +
406                                             reserved_space;
407                }
408        } else {
409                if (rootfs_info.file_name == NULL) {
410                        ERR("no rootfs image specified");
411                        return -1;
412                }
413
414                ret = get_file_stat(&rootfs_info);
415                if (ret)
416                        return ret;
417
418                if (rootfs_align) {
419                        kernel_len += sizeof(struct fw_header);
420                        kernel_len = ALIGN(kernel_len, rootfs_align);
421                        kernel_len -= sizeof(struct fw_header);
422
423                        DBG("kernel length aligned to %u", kernel_len);
424
425                        exceed_bytes = kernel_len + rootfs_info.file_size - (fw_max_len - sizeof(struct fw_header));
426                        if (exceed_bytes > 0) {
427                                ERR("images are too big by %i bytes", exceed_bytes);
428                                return -1;
429                        }
430                } else {
431                        exceed_bytes = kernel_info.file_size - (rootfs_ofs - sizeof(struct fw_header));
432                        if (exceed_bytes > 0) {
433                                ERR("kernel image is too big by %i bytes", exceed_bytes);
434                                return -1;
435                        }
436
437                        exceed_bytes = rootfs_info.file_size - (fw_max_len - rootfs_ofs);
438                        if (exceed_bytes > 0) {
439                                ERR("rootfs image is too big by %i bytes", exceed_bytes);
440                                return -1;
441                        }
442                }
443        }
444
445        if (ofname == NULL) {
446                ERR("no output file specified");
447                return -1;
448        }
449
450        ret = sscanf(fw_ver, "%d.%d.%d", &fw_ver_hi, &fw_ver_mid, &fw_ver_lo);
451        if (ret != 3) {
452                ERR("invalid firmware version '%s'", fw_ver);
453                return -1;
454        }
455
456        if (opt_hdr_ver == 1) {
457                hdr_ver = HEADER_VERSION_V1;
458        } else if (opt_hdr_ver == 2) {
459                hdr_ver = HEADER_VERSION_V2;
460        } else {
461                ERR("invalid header version '%u'", opt_hdr_ver);
462                return -1;
463        }
464
465        return 0;
466}
467
468static void fill_header(char *buf, int len)
469{
470        struct fw_header *hdr = (struct fw_header *)buf;
471
472        memset(hdr, 0, sizeof(struct fw_header));
473
474        hdr->version = htonl(hdr_ver);
475        strncpy(hdr->vendor_name, vendor, sizeof(hdr->vendor_name));
476        strncpy(hdr->fw_version, version, sizeof(hdr->fw_version));
477        hdr->hw_id = htonl(hw_id);
478        hdr->hw_rev = htonl(hw_rev);
479        hdr->region = htonl(region);
480
481        if (boot_info.file_size == 0)
482                memcpy(hdr->md5sum1, md5salt_normal, sizeof(hdr->md5sum1));
483        else
484                memcpy(hdr->md5sum1, md5salt_boot, sizeof(hdr->md5sum1));
485
486        hdr->kernel_la = htonl(kernel_la);
487        hdr->kernel_ep = htonl(kernel_ep);
488        hdr->fw_length = htonl(layout->fw_max_len);
489        hdr->kernel_ofs = htonl(sizeof(struct fw_header));
490        hdr->kernel_len = htonl(kernel_len);
491        if (!combined) {
492                hdr->rootfs_ofs = htonl(rootfs_ofs);
493                hdr->rootfs_len = htonl(rootfs_info.file_size);
494        }
495
496        hdr->ver_hi = htons(fw_ver_hi);
497        hdr->ver_mid = htons(fw_ver_mid);
498        hdr->ver_lo = htons(fw_ver_lo);
499
500        get_md5(buf, len, hdr->md5sum1);
501}
502
503static int pad_jffs2(char *buf, int currlen)
504{
505        int len;
506        uint32_t pad_mask;
507
508        len = currlen;
509        pad_mask = (64 * 1024);
510        while ((len < layout->fw_max_len) && (pad_mask != 0)) {
511                uint32_t mask;
512                int i;
513
514                for (i = 10; i < 32; i++) {
515                        mask = 1 << i;
516                        if (pad_mask & mask)
517                                break;
518                }
519
520                len = ALIGN(len, mask);
521
522                for (i = 10; i < 32; i++) {
523                        mask = 1 << i;
524                        if ((len & (mask - 1)) == 0)
525                                pad_mask &= ~mask;
526                }
527
528                for (i = 0; i < sizeof(jffs2_eof_mark); i++)
529                        buf[len + i] = jffs2_eof_mark[i];
530
531                len += sizeof(jffs2_eof_mark);
532        }
533
534        return len;
535}
536
537static int write_fw(const char *data, int len)
538{
539        FILE *f;
540        int ret = EXIT_FAILURE;
541
542        f = fopen(ofname, "w");
543        if (f == NULL) {
544                ERRS("could not open \"%s\" for writing", ofname);
545                goto out;
546        }
547
548        errno = 0;
549        fwrite(data, len, 1, f);
550        if (errno) {
551                ERRS("unable to write output file");
552                goto out_flush;
553        }
554
555        DBG("firmware file \"%s\" completed", ofname);
556
557        ret = EXIT_SUCCESS;
558
559 out_flush:
560        fflush(f);
561        fclose(f);
562        if (ret != EXIT_SUCCESS) {
563                unlink(ofname);
564        }
565 out:
566        return ret;
567}
568
569static int build_fw(void)
570{
571        int buflen;
572        char *buf;
573        char *p;
574        int ret = EXIT_FAILURE;
575        int writelen = 0;
576
577        buflen = layout->fw_max_len;
578
579        buf = malloc(buflen);
580        if (!buf) {
581                ERR("no memory for buffer\n");
582                goto out;
583        }
584
585        memset(buf, 0xff, buflen);
586        p = buf + sizeof(struct fw_header);
587        ret = read_to_buf(&kernel_info, p);
588        if (ret)
589                goto out_free_buf;
590
591        writelen = sizeof(struct fw_header) + kernel_len;
592
593        if (!combined) {
594                if (rootfs_align)
595                        p = buf + writelen;
596                else
597                        p = buf + rootfs_ofs;
598
599                ret = read_to_buf(&rootfs_info, p);
600                if (ret)
601                        goto out_free_buf;
602
603                if (rootfs_align)
604                        writelen += rootfs_info.file_size;
605                else
606                        writelen = rootfs_ofs + rootfs_info.file_size;
607
608                if (add_jffs2_eof)
609                        writelen = pad_jffs2(buf, writelen);
610        }
611
612        if (!strip_padding)
613                writelen = buflen;
614
615        fill_header(buf, writelen);
616        ret = write_fw(buf, writelen);
617        if (ret)
618                goto out_free_buf;
619
620        ret = EXIT_SUCCESS;
621
622 out_free_buf:
623        free(buf);
624 out:
625        return ret;
626}
627
628/* Helper functions to inspect_fw() representing different output formats */
629static inline void inspect_fw_pstr(const char *label, const char *str)
630{
631        printf("%-23s: %s\n", label, str);
632}
633
634static inline void inspect_fw_phex(const char *label, uint32_t val)
635{
636        printf("%-23s: 0x%08x\n", label, val);
637}
638
639static inline void inspect_fw_phexpost(const char *label, uint32_t val, const char *post)
640{
641        printf("%-23s: 0x%08x (%s)\n", label, val, post);
642}
643
644static inline void inspect_fw_phexdec(const char *label, uint32_t val)
645{
646        printf("%-23s: 0x%08x / %8u bytes\n", label, val, val);
647}
648
649static inline void inspect_fw_pmd5sum(const char *label, const uint8_t *val, const char *text)
650{
651        int i;
652
653        printf("%-23s:", label);
654        for (i=0; i<MD5SUM_LEN; i++)
655                printf(" %02x", val[i]);
656        printf(" %s\n", text);
657}
658
659static int inspect_fw(void)
660{
661        char *buf;
662        struct fw_header *hdr;
663        uint8_t md5sum[MD5SUM_LEN];
664        int ret = EXIT_FAILURE;
665
666        buf = malloc(inspect_info.file_size);
667        if (!buf) {
668                ERR("no memory for buffer!\n");
669                goto out;
670        }
671
672        ret = read_to_buf(&inspect_info, buf);
673        if (ret)
674                goto out_free_buf;
675        hdr = (struct fw_header *)buf;
676
677        inspect_fw_pstr("File name", inspect_info.file_name);
678        inspect_fw_phexdec("File size", inspect_info.file_size);
679
680        if ((ntohl(hdr->version) != HEADER_VERSION_V1) &&
681            (ntohl(hdr->version) != HEADER_VERSION_V2)) {
682                ERR("file does not seem to have V1/V2 header!\n");
683                goto out_free_buf;
684        }
685
686        inspect_fw_phexdec("Version 1 Header size", sizeof(struct fw_header));
687
688        memcpy(md5sum, hdr->md5sum1, sizeof(md5sum));
689        if (ntohl(hdr->boot_len) == 0)
690                memcpy(hdr->md5sum1, md5salt_normal, sizeof(md5sum));
691        else
692                memcpy(hdr->md5sum1, md5salt_boot, sizeof(md5sum));
693        get_md5(buf, inspect_info.file_size, hdr->md5sum1);
694
695        if (memcmp(md5sum, hdr->md5sum1, sizeof(md5sum))) {
696                inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(*ERROR*)");
697                inspect_fw_pmd5sum("          --> expected", hdr->md5sum1, "");
698        } else {
699                inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(ok)");
700        }
701        if (ntohl(hdr->unk2) != 0)
702                inspect_fw_phexdec("Unknown value 2", hdr->unk2);
703        inspect_fw_pmd5sum("Header MD5Sum2", hdr->md5sum2,
704                           "(purpose yet unknown, unchecked here)");
705        if (ntohl(hdr->unk3) != 0)
706                inspect_fw_phexdec("Unknown value 3", hdr->unk3);
707
708        printf("\n");
709
710        inspect_fw_pstr("Vendor name", hdr->vendor_name);
711        inspect_fw_pstr("Firmware version", hdr->fw_version);
712        inspect_fw_phex("Hardware ID", ntohl(hdr->hw_id));
713        inspect_fw_phex("Hardware Revision", ntohl(hdr->hw_rev));
714        inspect_fw_phexpost("Region code", ntohl(hdr->region), get_region_country(ntohl(hdr->region)));
715
716        printf("\n");
717
718        inspect_fw_phexdec("Kernel data offset",
719                           ntohl(hdr->kernel_ofs));
720        inspect_fw_phexdec("Kernel data length",
721                           ntohl(hdr->kernel_len));
722        inspect_fw_phex("Kernel load address",
723                        ntohl(hdr->kernel_la));
724        inspect_fw_phex("Kernel entry point",
725                        ntohl(hdr->kernel_ep));
726        inspect_fw_phexdec("Rootfs data offset",
727                           ntohl(hdr->rootfs_ofs));
728        inspect_fw_phexdec("Rootfs data length",
729                           ntohl(hdr->rootfs_len));
730        inspect_fw_phexdec("Boot loader data offset",
731                           ntohl(hdr->boot_ofs));
732        inspect_fw_phexdec("Boot loader data length",
733                           ntohl(hdr->boot_len));
734        inspect_fw_phexdec("Total firmware length",
735                           ntohl(hdr->fw_length));
736
737        if (extract) {
738                FILE *fp;
739                char *filename;
740
741                printf("\n");
742
743                filename = malloc(strlen(inspect_info.file_name) + 8);
744                sprintf(filename, "%s-kernel", inspect_info.file_name);
745                printf("Extracting kernel to \"%s\"...\n", filename);
746                fp = fopen(filename, "w");
747                if (fp) {
748                        if (!fwrite(buf + ntohl(hdr->kernel_ofs),
749                                    ntohl(hdr->kernel_len), 1, fp)) {
750                                ERR("error in fwrite(): %s", strerror(errno));
751                        }
752                        fclose(fp);
753                } else {
754                        ERR("error in fopen(): %s", strerror(errno));
755                }
756                free(filename);
757
758                filename = malloc(strlen(inspect_info.file_name) + 8);
759                sprintf(filename, "%s-rootfs", inspect_info.file_name);
760                printf("Extracting rootfs to \"%s\"...\n", filename);
761                fp = fopen(filename, "w");
762                if (fp) {
763                        if (!fwrite(buf + ntohl(hdr->rootfs_ofs),
764                                    ntohl(hdr->rootfs_len), 1, fp)) {
765                                ERR("error in fwrite(): %s", strerror(errno));
766                        }
767                        fclose(fp);
768                } else {
769                        ERR("error in fopen(): %s", strerror(errno));
770                }
771                free(filename);
772        }
773
774 out_free_buf:
775        free(buf);
776 out:
777        return ret;
778}
779
780int main(int argc, char *argv[])
781{
782        int ret = EXIT_FAILURE;
783
784        progname = basename(argv[0]);
785
786        while ( 1 ) {
787                int c;
788
789                c = getopt(argc, argv, "a:H:E:F:L:m:V:N:W:C:ci:k:r:R:o:xX:hsSjv:");
790                if (c == -1)
791                        break;
792
793                switch (c) {
794                case 'a':
795                        sscanf(optarg, "0x%x", &rootfs_align);
796                        break;
797                case 'H':
798                        opt_hw_id = optarg;
799                        break;
800                case 'E':
801                        sscanf(optarg, "0x%x", &kernel_ep);
802                        break;
803                case 'F':
804                        layout_id = optarg;
805                        break;
806                case 'W':
807                        opt_hw_rev = optarg;
808                        break;
809                case 'C':
810                        country = optarg;
811                        break;
812                case 'L':
813                        sscanf(optarg, "0x%x", &kernel_la);
814                        break;
815                case 'm':
816                        sscanf(optarg, "%u", &opt_hdr_ver);
817                        break;
818                case 'V':
819                        version = optarg;
820                        break;
821                case 'v':
822                        fw_ver = optarg;
823                        break;
824                case 'N':
825                        vendor = optarg;
826                        break;
827                case 'c':
828                        combined++;
829                        break;
830                case 'k':
831                        kernel_info.file_name = optarg;
832                        break;
833                case 'r':
834                        rootfs_info.file_name = optarg;
835                        break;
836                case 'R':
837                        sscanf(optarg, "0x%x", &rootfs_ofs);
838                        break;
839                case 'o':
840                        ofname = optarg;
841                        break;
842                case 's':
843                        strip_padding = 1;
844                        break;
845                case 'S':
846                        ignore_size = 1;
847                        break;
848                case 'i':
849                        inspect_info.file_name = optarg;
850                        break;
851                case 'j':
852                        add_jffs2_eof = 1;
853                        break;
854                case 'x':
855                        extract = 1;
856                        break;
857                case 'h':
858                        usage(EXIT_SUCCESS);
859                        break;
860                case 'X':
861                        sscanf(optarg, "0x%x", &reserved_space);
862                        break;
863                default:
864                        usage(EXIT_FAILURE);
865                        break;
866                }
867        }
868
869        ret = check_options();
870        if (ret)
871                goto out;
872
873        if (!inspect_info.file_name)
874                ret = build_fw();
875        else
876                ret = inspect_fw();
877
878 out:
879        return ret;
880}
Note: See TracBrowser for help on using the repository browser.