1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
18 #if !defined(__BYTE_ORDER)
19 #error "Unknown byte order"
22 #if __BYTE_ORDER == __BIG_ENDIAN
23 #define cpu_to_le32(x) bswap_32(x)
24 #define le32_to_cpu(x) bswap_32(x)
25 #define cpu_to_be32(x) (x)
26 #define be32_to_cpu(x) (x)
27 #define cpu_to_le16(x) bswap_16(x)
28 #define le16_to_cpu(x) bswap_16(x)
29 #define cpu_to_be16(x) (x)
30 #define be16_to_cpu(x) (x)
31 #elif __BYTE_ORDER == __LITTLE_ENDIAN
32 #define cpu_to_le32(x) (x)
33 #define le32_to_cpu(x) (x)
34 #define cpu_to_be32(x) bswap_32(x)
35 #define be32_to_cpu(x) bswap_32(x)
36 #define cpu_to_le16(x) (x)
37 #define le16_to_cpu(x) (x)
38 #define cpu_to_be16(x) bswap_16(x)
39 #define be16_to_cpu(x) bswap_16(x)
41 #error "Unsupported endianness"
44 #define WFI_VERSION 0x00005732
45 #define WFI_VERSION_NAND_1MB_DATA 0x00005731
47 #define WFI_NOR_FLASH 1
48 #define WFI_NAND16_FLASH 2
49 #define WFI_NAND128_FLASH 3
50 #define WFI_NAND256_FLASH 4
51 #define WFI_NAND512_FLASH 5
52 #define WFI_NAND1024_FLASH 6
53 #define WFI_NAND2048_FLASH 7
55 #define WFI_FLAG_HAS_PMC 0x1
56 #define WFI_FLAG_SUPPORTS_BTRM 0x2
58 #define UBI_EC_HDR_MAGIC 0x55424923
62 struct bcm4908img_tail
{
71 * struct bcm4908img_info - info about BCM4908 image
73 * Standard BCM4908 image consists of:
74 * 1. (Optional) vedor header
75 * 2. (Optional) cferom
77 * 4. padding ├─ firmware
81 struct bcm4908img_info
{
85 size_t padding_offset
;
87 uint32_t crc32
; /* Calculated checksum */
88 struct bcm4908img_tail tail
;
93 static inline size_t bcm4908img_min(size_t x
, size_t y
) {
97 /**************************************************
99 **************************************************/
101 static const uint32_t crc32_tbl
[] = {
102 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
103 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
104 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
105 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
106 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
107 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
108 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
109 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
110 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
111 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
112 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
113 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
114 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
115 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
116 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
117 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
118 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
119 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
120 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
121 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
122 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
123 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
124 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
125 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
126 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
127 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
128 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
129 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
130 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
131 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
132 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
133 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
134 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
135 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
136 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
137 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
138 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
139 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
140 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
141 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
142 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
143 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
144 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
145 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
146 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
147 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
148 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
149 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
150 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
151 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
152 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
153 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
154 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
155 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
156 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
157 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
158 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
159 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
160 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
161 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
162 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
163 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
164 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
165 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
168 uint32_t bcm4908img_crc32(uint32_t crc
, const void *buf
, size_t len
) {
169 const uint8_t *in
= buf
;
172 crc
= crc32_tbl
[(crc
^ *in
) & 0xff] ^ (crc
>> 8);
180 /**************************************************
182 **************************************************/
184 static FILE *bcm4908img_open(const char *pathname
, const char *mode
) {
188 return fopen(pathname
, mode
);
190 if (isatty(fileno(stdin
))) {
191 fprintf(stderr
, "Reading from TTY stdin is unsupported\n");
195 if (fstat(fileno(stdin
), &st
)) {
196 fprintf(stderr
, "Failed to fstat stdin: %d\n", -errno
);
200 if (S_ISFIFO(st
.st_mode
)) {
201 fprintf(stderr
, "Reading from pipe stdin is unsupported\n");
208 static void bcm4908img_close(FILE *fp
) {
213 static int bcm4908img_calc_crc32(FILE *fp
, struct bcm4908img_info
*info
) {
218 /* Start with cferom (or bootfs) - skip vendor header */
219 fseek(fp
, info
->cferom_offset
, SEEK_SET
);
221 info
->crc32
= 0xffffffff;
222 length
= info
->file_size
- info
->cferom_offset
- sizeof(struct bcm4908img_tail
);
223 while (length
&& (bytes
= fread(buf
, 1, bcm4908img_min(sizeof(buf
), length
), fp
)) > 0) {
224 info
->crc32
= bcm4908img_crc32(info
->crc32
, buf
, bytes
);
228 fprintf(stderr
, "Failed to read last %zd B of data\n", length
);
235 /**************************************************
236 * Existing firmware parser
237 **************************************************/
243 uint32_t kernel_chksum
;
244 uint32_t rootfs_chksum
;
247 uint32_t image_chksum
;
248 uint32_t header_chksum
;
252 static bool bcm4908img_is_all_ff(const void *buf
, size_t length
)
254 const uint8_t *in
= buf
;
257 for (i
= 0; i
< length
; i
++) {
265 static int bcm4908img_parse(FILE *fp
, struct bcm4908img_info
*info
) {
266 struct bcm4908img_tail
*tail
= &info
->tail
;
267 struct chk_header
*chk
;
275 memset(info
, 0, sizeof(*info
));
279 if (fstat(fileno(fp
), &st
)) {
281 fprintf(stderr
, "Failed to fstat: %d\n", err
);
284 info
->file_size
= st
.st_size
;
289 if (fread(buf
, 1, sizeof(buf
), fp
) != sizeof(buf
)) {
290 fprintf(stderr
, "Failed to read file header\n");
294 if (be32_to_cpu(chk
->magic
) == 0x2a23245e)
295 info
->cferom_offset
= be32_to_cpu(chk
->header_len
);
299 for (info
->bootfs_offset
= info
->cferom_offset
;
300 info
->bootfs_offset
< info
->file_size
;
301 info
->bootfs_offset
+= 0x20000) {
302 if (fseek(fp
, info
->bootfs_offset
, SEEK_SET
)) {
304 fprintf(stderr
, "Failed to fseek to the 0x%zx\n", info
->bootfs_offset
);
307 if (fread(&tmp16
, 1, sizeof(tmp16
), fp
) != sizeof(tmp16
)) {
308 fprintf(stderr
, "Failed to read while looking for JFFS2\n");
311 if (be16_to_cpu(tmp16
) == 0x8519)
314 if (info
->bootfs_offset
>= info
->file_size
) {
315 fprintf(stderr
, "Failed to find bootfs offset\n");
319 for (info
->rootfs_offset
= info
->bootfs_offset
;
320 info
->rootfs_offset
< info
->file_size
;
321 info
->rootfs_offset
+= 0x20000) {
322 uint32_t *magic
= (uint32_t *)&buf
[0];
324 if (fseek(fp
, info
->rootfs_offset
, SEEK_SET
)) {
326 fprintf(stderr
, "Failed to fseek: %d\n", err
);
330 length
= info
->padding_offset
? sizeof(*magic
) : 256;
331 bytes
= fread(buf
, 1, length
, fp
);
332 if (bytes
!= length
) {
333 fprintf(stderr
, "Failed to read %zu bytes\n", length
);
337 if (!info
->padding_offset
&& bcm4908img_is_all_ff(buf
, length
))
338 info
->padding_offset
= info
->rootfs_offset
;
340 if (be32_to_cpu(*magic
) == UBI_EC_HDR_MAGIC
)
343 if (info
->rootfs_offset
>= info
->file_size
) {
344 fprintf(stderr
, "Failed to find rootfs offset\n");
350 /* Start with cferom (or bootfs) - skip vendor header */
351 fseek(fp
, info
->cferom_offset
, SEEK_SET
);
353 info
->crc32
= 0xffffffff;
354 length
= info
->file_size
- info
->cferom_offset
- sizeof(*tail
);
355 while (length
&& (bytes
= fread(buf
, 1, bcm4908img_min(sizeof(buf
), length
), fp
)) > 0) {
356 info
->crc32
= bcm4908img_crc32(info
->crc32
, buf
, bytes
);
360 fprintf(stderr
, "Failed to read last %zd B of data\n", length
);
366 if (fread(tail
, 1, sizeof(*tail
), fp
) != sizeof(*tail
)) {
367 fprintf(stderr
, "Failed to read BCM4908 image tail\n");
371 /* Standard validation */
373 if (info
->crc32
!= le32_to_cpu(tail
->crc32
)) {
374 fprintf(stderr
, "Invalid data crc32: 0x%08x instead of 0x%08x\n", info
->crc32
, le32_to_cpu(tail
->crc32
));
381 /**************************************************
383 **************************************************/
385 static int bcm4908img_info(int argc
, char **argv
) {
386 struct bcm4908img_info info
;
387 const char *pathname
= NULL
;
392 while ((c
= getopt(argc
, argv
, "i:")) != -1) {
400 fp
= bcm4908img_open(pathname
, "r");
402 fprintf(stderr
, "Failed to open BCM4908 image\n");
407 err
= bcm4908img_parse(fp
, &info
);
409 fprintf(stderr
, "Failed to parse BCM4908 image\n");
413 if (info
.bootfs_offset
!= info
.cferom_offset
)
414 printf("cferom offset:\t%zu\n", info
.cferom_offset
);
415 printf("bootfs offset:\t0x%zx\n", info
.bootfs_offset
);
416 if (info
.padding_offset
)
417 printf("padding offset:\t0x%zx\n", info
.padding_offset
);
418 printf("rootfs offset:\t0x%zx\n", info
.rootfs_offset
);
419 printf("Checksum:\t0x%08x\n", info
.crc32
);
422 bcm4908img_close(fp
);
427 /**************************************************
429 **************************************************/
431 static ssize_t
bcm4908img_create_append_file(FILE *trx
, const char *in_path
, uint32_t *crc32
) {
437 in
= fopen(in_path
, "r");
439 fprintf(stderr
, "Failed to open %s\n", in_path
);
443 while ((bytes
= fread(buf
, 1, sizeof(buf
), in
)) > 0) {
444 if (fwrite(buf
, 1, bytes
, trx
) != bytes
) {
445 fprintf(stderr
, "Failed to write %zu B to %s\n", bytes
, pathname
);
449 *crc32
= bcm4908img_crc32(*crc32
, buf
, bytes
);
458 static ssize_t
bcm4908img_create_append_zeros(FILE *trx
, size_t length
) {
461 buf
= malloc(length
);
464 memset(buf
, 0, length
);
466 if (fwrite(buf
, 1, length
, trx
) != length
) {
467 fprintf(stderr
, "Failed to write %zu B to %s\n", length
, pathname
);
477 static ssize_t
bcm4908img_create_align(FILE *trx
, size_t cur_offset
, size_t alignment
) {
478 if (cur_offset
& (alignment
- 1)) {
479 size_t length
= alignment
- (cur_offset
% alignment
);
480 return bcm4908img_create_append_zeros(trx
, length
);
486 static int bcm4908img_create(int argc
, char **argv
) {
487 struct bcm4908img_tail tail
= {
488 .version
= cpu_to_le32(WFI_VERSION
),
489 .chip_id
= cpu_to_le32(0x4908),
490 .flash_type
= cpu_to_le32(WFI_NAND128_FLASH
),
491 .flags
= cpu_to_le32(WFI_FLAG_SUPPORTS_BTRM
),
493 uint32_t crc32
= 0xffffffff;
494 size_t cur_offset
= 0;
501 fprintf(stderr
, "No BCM4908 image pathname passed\n");
507 fp
= fopen(pathname
, "w+");
509 fprintf(stderr
, "Failed to open %s\n", pathname
);
515 while ((c
= getopt(argc
, argv
, "f:a:A:")) != -1) {
518 bytes
= bcm4908img_create_append_file(fp
, optarg
, &crc32
);
520 fprintf(stderr
, "Failed to append file %s\n", optarg
);
526 bytes
= bcm4908img_create_align(fp
, cur_offset
, strtol(optarg
, NULL
, 0));
528 fprintf(stderr
, "Failed to append zeros\n");
533 bytes
= strtol(optarg
, NULL
, 0) - cur_offset
;
535 fprintf(stderr
, "Current BCM4908 image length is 0x%zx, can't pad it with zeros to 0x%lx\n", cur_offset
, strtol(optarg
, NULL
, 0));
537 bytes
= bcm4908img_create_append_zeros(fp
, bytes
);
539 fprintf(stderr
, "Failed to append zeros\n");
549 tail
.crc32
= cpu_to_le32(crc32
);
551 bytes
= fwrite(&tail
, 1, sizeof(tail
), fp
);
552 if (bytes
!= sizeof(tail
)) {
553 fprintf(stderr
, "Failed to write BCM4908 image tail to %s\n", pathname
);
563 /**************************************************
565 **************************************************/
567 static int bcm4908img_extract(int argc
, char **argv
) {
568 struct bcm4908img_info info
;
569 const char *pathname
= NULL
;
579 while ((c
= getopt(argc
, argv
, "i:t:")) != -1) {
590 fp
= bcm4908img_open(pathname
, "r");
592 fprintf(stderr
, "Failed to open BCM4908 image\n");
597 err
= bcm4908img_parse(fp
, &info
);
599 fprintf(stderr
, "Failed to parse BCM4908 image\n");
603 if (!strcmp(type
, "cferom")) {
604 offset
= info
.cferom_offset
;
605 length
= info
.bootfs_offset
- offset
;
608 fprintf(stderr
, "This BCM4908 image doesn't contain cferom\n");
611 } else if (!strcmp(type
, "bootfs")) {
612 offset
= info
.bootfs_offset
;
613 length
= (info
.padding_offset
? info
.padding_offset
: info
.rootfs_offset
) - offset
;
614 } else if (!strcmp(type
, "rootfs")) {
615 offset
= info
.rootfs_offset
;
616 length
= info
.file_size
- offset
- sizeof(struct bcm4908img_tail
);
617 } else if (!strcmp(type
, "firmware")) {
618 offset
= info
.bootfs_offset
;
619 length
= info
.file_size
- offset
- sizeof(struct bcm4908img_tail
);
622 fprintf(stderr
, "Unsupported extract type: %s\n", type
);
628 fprintf(stderr
, "No data to extract specified\n");
632 fseek(fp
, offset
, SEEK_SET
);
633 while (length
&& (bytes
= fread(buf
, 1, bcm4908img_min(sizeof(buf
), length
), fp
)) > 0) {
634 fwrite(buf
, bytes
, 1, stdout
);
639 fprintf(stderr
, "Failed to read last %zd B of data\n", length
);
644 bcm4908img_close(fp
);
649 /**************************************************
651 **************************************************/
653 #define JFFS2_MAGIC_BITMASK 0x1985
655 #define JFFS2_COMPR_NONE 0x00
656 #define JFFS2_COMPR_ZERO 0x01
657 #define JFFS2_COMPR_RTIME 0x02
658 #define JFFS2_COMPR_RUBINMIPS 0x03
659 #define JFFS2_COMPR_COPY 0x04
660 #define JFFS2_COMPR_DYNRUBIN 0x05
661 #define JFFS2_COMPR_ZLIB 0x06
662 #define JFFS2_COMPR_LZO 0x07
663 /* Compatibility flags. */
664 #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */
665 #define JFFS2_NODE_ACCURATE 0x2000
666 /* INCOMPAT: Fail to mount the filesystem */
667 #define JFFS2_FEATURE_INCOMPAT 0xc000
668 /* ROCOMPAT: Mount read-only */
669 #define JFFS2_FEATURE_ROCOMPAT 0x8000
670 /* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */
671 #define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000
672 /* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */
673 #define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000
675 #define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1)
679 } __attribute__((packed
)) jint32_t
;
683 } __attribute__((packed
)) jint16_t
;
685 struct jffs2_unknown_node
687 /* All start like this */
690 jint32_t totlen
; /* So we can skip over nodes we don't grok */
694 struct jffs2_raw_dirent
697 jint16_t nodetype
; /* == JFFS2_NODETYPE_DIRENT */
702 jint32_t ino
; /* == zero for unlink */
712 #define je16_to_cpu(x) ((x).v16)
713 #define je32_to_cpu(x) ((x).v32)
715 static int bcm4908img_bootfs_ls(FILE *fp
, struct bcm4908img_info
*info
) {
716 struct jffs2_unknown_node node
;
717 struct jffs2_raw_dirent dirent
;
722 for (offset
= info
->bootfs_offset
; ; offset
+= (je32_to_cpu(node
.totlen
) + 0x03) & ~0x03) {
723 char name
[FILENAME_MAX
+ 1];
725 if (fseek(fp
, offset
, SEEK_SET
)) {
727 fprintf(stderr
, "Failed to fseek: %d\n", err
);
731 bytes
= fread(&node
, 1, sizeof(node
), fp
);
732 if (bytes
!= sizeof(node
)) {
733 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(node
));
737 if (je16_to_cpu(node
.magic
) != JFFS2_MAGIC_BITMASK
) {
741 if (je16_to_cpu(node
.nodetype
) != JFFS2_NODETYPE_DIRENT
) {
745 memcpy(&dirent
, &node
, sizeof(node
));
746 bytes
+= fread((uint8_t *)&dirent
+ sizeof(node
), 1, sizeof(dirent
) - sizeof(node
), fp
);
747 if (bytes
!= sizeof(dirent
)) {
748 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(node
));
752 if (dirent
.nsize
+ 1 > sizeof(name
)) {
753 /* Keep reading & printing BUT exit with error code */
754 fprintf(stderr
, "Too long filename\n");
759 bytes
= fread(name
, 1, dirent
.nsize
, fp
);
760 if (bytes
!= dirent
.nsize
) {
761 fprintf(stderr
, "Failed to read filename\n");
766 printf("%s\n", name
);
772 static int bcm4908img_bootfs_mv(FILE *fp
, struct bcm4908img_info
*info
, int argc
, char **argv
) {
773 struct jffs2_unknown_node node
;
774 struct jffs2_raw_dirent dirent
;
781 if (argc
- optind
< 2) {
782 fprintf(stderr
, "No enough arguments passed\n");
785 oldname
= argv
[optind
++];
786 newname
= argv
[optind
++];
788 if (strlen(newname
) != strlen(oldname
)) {
789 fprintf(stderr
, "New filename must have the same length as the old one\n");
793 for (offset
= info
->bootfs_offset
; ; offset
+= (je32_to_cpu(node
.totlen
) + 0x03) & ~0x03) {
794 char name
[FILENAME_MAX
];
797 if (fseek(fp
, offset
, SEEK_SET
)) {
799 fprintf(stderr
, "Failed to fseek: %d\n", err
);
803 bytes
= fread(&node
, 1, sizeof(node
), fp
);
804 if (bytes
!= sizeof(node
)) {
805 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(node
));
809 if (je16_to_cpu(node
.magic
) != JFFS2_MAGIC_BITMASK
) {
813 if (je16_to_cpu(node
.nodetype
) != JFFS2_NODETYPE_DIRENT
) {
817 bytes
+= fread((uint8_t *)&dirent
+ sizeof(node
), 1, sizeof(dirent
) - sizeof(node
), fp
);
818 if (bytes
!= sizeof(dirent
)) {
819 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(node
));
823 if (dirent
.nsize
+ 1 > sizeof(name
)) {
824 fprintf(stderr
, "Too long filename\n");
829 bytes
= fread(name
, 1, dirent
.nsize
, fp
);
830 if (bytes
!= dirent
.nsize
) {
831 fprintf(stderr
, "Failed to read filename\n");
837 printf("offset:%08zx name_crc:%04x filename:%s\n", offset
, je32_to_cpu(dirent
.name_crc
), name
);
839 if (strcmp(name
, oldname
)) {
843 if (fseek(fp
, offset
+ offsetof(struct jffs2_raw_dirent
, name_crc
), SEEK_SET
)) {
845 fprintf(stderr
, "Failed to fseek: %d\n", err
);
848 crc32
= bcm4908img_crc32(0, newname
, dirent
.nsize
);
849 bytes
= fwrite(&crc32
, 1, sizeof(crc32
), fp
);
850 if (bytes
!= sizeof(crc32
)) {
851 fprintf(stderr
, "Failed to write new CRC32\n");
855 if (fseek(fp
, offset
+ offsetof(struct jffs2_raw_dirent
, name
), SEEK_SET
)) {
857 fprintf(stderr
, "Failed to fseek: %d\n", err
);
860 bytes
= fwrite(newname
, 1, dirent
.nsize
, fp
);
861 if (bytes
!= dirent
.nsize
) {
862 fprintf(stderr
, "Failed to write new filename\n");
866 /* Calculate new BCM4908 image checksum */
868 err
= bcm4908img_calc_crc32(fp
, info
);
870 fprintf(stderr
, "Failed to write new filename\n");
874 info
->tail
.crc32
= cpu_to_le32(info
->crc32
);
875 if (fseek(fp
, -sizeof(struct bcm4908img_tail
), SEEK_END
)) {
877 fprintf(stderr
, "Failed to write new filename\n");
881 if (fwrite(&info
->tail
, 1, sizeof(struct bcm4908img_tail
), fp
) != sizeof(struct bcm4908img_tail
)) {
882 fprintf(stderr
, "Failed to write updated tail\n");
886 printf("Successfully renamed %s to the %s\n", oldname
, newname
);
891 fprintf(stderr
, "Failed to find %s\n", oldname
);
896 static int bcm4908img_bootfs(int argc
, char **argv
) {
897 struct bcm4908img_info info
;
898 const char *pathname
= NULL
;
905 while ((c
= getopt(argc
, argv
, "i:")) != -1) {
913 if (argc
- optind
< 1) {
914 fprintf(stderr
, "No bootfs command specified\n");
918 cmd
= argv
[optind
++];
920 mode
= strcmp(cmd
, "mv") ? "r" : "r+";
921 fp
= bcm4908img_open(pathname
, mode
);
923 fprintf(stderr
, "Failed to open BCM4908 image\n");
928 err
= bcm4908img_parse(fp
, &info
);
930 fprintf(stderr
, "Failed to parse BCM4908 image\n");
934 if (!strcmp(cmd
, "ls")) {
935 err
= bcm4908img_bootfs_ls(fp
, &info
);
936 } else if (!strcmp(cmd
, "mv")) {
937 err
= bcm4908img_bootfs_mv(fp
, &info
, argc
, argv
);
940 fprintf(stderr
, "Unsupported bootfs command: %s\n", cmd
);
944 bcm4908img_close(fp
);
949 /**************************************************
951 **************************************************/
953 static void usage() {
956 printf("Info about a BCM4908 image:\n");
957 printf("\tbcm4908img info <options>\n");
958 printf("\t-i <file>\t\t\t\tinput BCM490 image\n");
960 printf("Creating a new BCM4908 image:\n");
961 printf("\tbcm4908img create <file> [options]\n");
962 printf("\t-f file\t\t\t\tadd data from specified file\n");
963 printf("\t-a alignment\t\t\tpad image with zeros to specified alignment\n");
964 printf("\t-A offset\t\t\t\tappend zeros until reaching specified offset\n");
966 printf("Extracting from a BCM4908 image:\n");
967 printf("\tbcm4908img extract <options>\n");
968 printf("\t-i <file>\t\t\t\tinput BCM490 image\n");
969 printf("\t-t <type>\t\t\t\tone of: cferom, bootfs, rootfs, firmware\n");
971 printf("Access bootfs in a BCM4908 image:\n");
972 printf("\tbcm4908img bootfs <options> <command> <arguments>\n");
973 printf("\t-i <file>\t\t\t\tinput BCM490 image\n");
974 printf("\tls\t\t\t\t\tlist bootfs files\n");
975 printf("\tmv <source> <dest>\t\t\trename bootfs file\n");
978 int main(int argc
, char **argv
) {
981 if (!strcmp(argv
[1], "info"))
982 return bcm4908img_info(argc
, argv
);
983 else if (!strcmp(argv
[1], "create"))
984 return bcm4908img_create(argc
, argv
);
985 else if (!strcmp(argv
[1], "extract"))
986 return bcm4908img_extract(argc
, argv
);
987 else if (!strcmp(argv
[1], "bootfs"))
988 return bcm4908img_bootfs(argc
, argv
);