1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
17 #if !defined(__BYTE_ORDER)
18 #error "Unknown byte order"
21 #if __BYTE_ORDER == __BIG_ENDIAN
22 #define cpu_to_le32(x) bswap_32(x)
23 #define le32_to_cpu(x) bswap_32(x)
24 #define cpu_to_be32(x) (x)
25 #define be32_to_cpu(x) (x)
26 #define cpu_to_le16(x) bswap_16(x)
27 #define le16_to_cpu(x) bswap_16(x)
28 #define cpu_to_be16(x) (x)
29 #define be16_to_cpu(x) (x)
30 #elif __BYTE_ORDER == __LITTLE_ENDIAN
31 #define cpu_to_le32(x) (x)
32 #define le32_to_cpu(x) (x)
33 #define cpu_to_be32(x) bswap_32(x)
34 #define be32_to_cpu(x) bswap_32(x)
35 #define cpu_to_le16(x) (x)
36 #define le16_to_cpu(x) (x)
37 #define cpu_to_be16(x) bswap_16(x)
38 #define be16_to_cpu(x) bswap_16(x)
40 #error "Unsupported endianness"
43 #define WFI_VERSION 0x00005732
44 #define WFI_VERSION_NAND_1MB_DATA 0x00005731
46 #define WFI_NOR_FLASH 1
47 #define WFI_NAND16_FLASH 2
48 #define WFI_NAND128_FLASH 3
49 #define WFI_NAND256_FLASH 4
50 #define WFI_NAND512_FLASH 5
51 #define WFI_NAND1024_FLASH 6
52 #define WFI_NAND2048_FLASH 7
54 #define WFI_FLAG_HAS_PMC 0x1
55 #define WFI_FLAG_SUPPORTS_BTRM 0x2
57 #define UBI_EC_HDR_MAGIC 0x55424923
61 struct bcm4908img_tail
{
70 * struct bcm4908img_info - info about BCM4908 image
72 * Standard BCM4908 image consists of:
73 * 1. (Optional) vedor header
74 * 2. (Optional) cferom
76 * 4. padding ├─ firmware
80 struct bcm4908img_info
{
85 uint32_t crc32
; /* Calculated checksum */
86 struct bcm4908img_tail tail
;
91 static inline size_t bcm4908img_min(size_t x
, size_t y
) {
95 /**************************************************
97 **************************************************/
99 static const uint32_t crc32_tbl
[] = {
100 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
101 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
102 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
103 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
104 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
105 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
106 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
107 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
108 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
109 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
110 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
111 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
112 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
113 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
114 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
115 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
116 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
117 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
118 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
119 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
120 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
121 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
122 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
123 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
124 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
125 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
126 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
127 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
128 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
129 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
130 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
131 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
132 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
133 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
134 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
135 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
136 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
137 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
138 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
139 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
140 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
141 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
142 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
143 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
144 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
145 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
146 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
147 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
148 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
149 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
150 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
151 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
152 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
153 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
154 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
155 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
156 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
157 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
158 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
159 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
160 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
161 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
162 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
163 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
166 uint32_t bcm4908img_crc32(uint32_t crc
, const void *buf
, size_t len
) {
167 const uint8_t *in
= buf
;
170 crc
= crc32_tbl
[(crc
^ *in
) & 0xff] ^ (crc
>> 8);
178 /**************************************************
180 **************************************************/
182 static FILE *bcm4908img_open(const char *pathname
, const char *mode
) {
186 return fopen(pathname
, mode
);
188 if (isatty(fileno(stdin
))) {
189 fprintf(stderr
, "Reading from TTY stdin is unsupported\n");
193 if (fstat(fileno(stdin
), &st
)) {
194 fprintf(stderr
, "Failed to fstat stdin: %d\n", -errno
);
198 if (S_ISFIFO(st
.st_mode
)) {
199 fprintf(stderr
, "Reading from pipe stdin is unsupported\n");
206 static void bcm4908img_close(FILE *fp
) {
211 static int bcm4908img_calc_crc32(FILE *fp
, struct bcm4908img_info
*info
) {
216 /* Start with cferom (or bootfs) - skip vendor header */
217 fseek(fp
, info
->cferom_offset
, SEEK_SET
);
219 info
->crc32
= 0xffffffff;
220 length
= info
->file_size
- info
->cferom_offset
- sizeof(struct bcm4908img_tail
);
221 while (length
&& (bytes
= fread(buf
, 1, bcm4908img_min(sizeof(buf
), length
), fp
)) > 0) {
222 info
->crc32
= bcm4908img_crc32(info
->crc32
, buf
, bytes
);
226 fprintf(stderr
, "Failed to read last %zd B of data\n", length
);
233 /**************************************************
234 * Existing firmware parser
235 **************************************************/
241 uint32_t kernel_chksum
;
242 uint32_t rootfs_chksum
;
245 uint32_t image_chksum
;
246 uint32_t header_chksum
;
250 static int bcm4908img_parse(FILE *fp
, struct bcm4908img_info
*info
) {
251 struct bcm4908img_tail
*tail
= &info
->tail
;
252 struct chk_header
*chk
;
260 memset(info
, 0, sizeof(*info
));
264 if (fstat(fileno(fp
), &st
)) {
266 fprintf(stderr
, "Failed to fstat: %d\n", err
);
269 info
->file_size
= st
.st_size
;
274 if (fread(buf
, 1, sizeof(buf
), fp
) != sizeof(buf
)) {
275 fprintf(stderr
, "Failed to read file header\n");
279 if (be32_to_cpu(chk
->magic
) == 0x2a23245e)
280 info
->cferom_offset
= be32_to_cpu(chk
->header_len
);
284 for (info
->bootfs_offset
= info
->cferom_offset
;
285 info
->bootfs_offset
< info
->file_size
;
286 info
->bootfs_offset
+= 0x20000) {
287 if (fseek(fp
, info
->bootfs_offset
, SEEK_SET
)) {
289 fprintf(stderr
, "Failed to fseek to the 0x%zx\n", info
->bootfs_offset
);
292 if (fread(&tmp16
, 1, sizeof(tmp16
), fp
) != sizeof(tmp16
)) {
293 fprintf(stderr
, "Failed to read while looking for JFFS2\n");
296 if (be16_to_cpu(tmp16
) == 0x8519)
299 if (info
->bootfs_offset
>= info
->file_size
) {
300 fprintf(stderr
, "Failed to find bootfs offset\n");
304 for (info
->rootfs_offset
= info
->bootfs_offset
;
305 info
->rootfs_offset
< info
->file_size
;
306 info
->rootfs_offset
+= 0x20000) {
309 if (fseek(fp
, info
->rootfs_offset
, SEEK_SET
)) {
311 fprintf(stderr
, "Failed to fseek: %d\n", err
);
315 bytes
= fread(&magic
, 1, sizeof(magic
), fp
);
316 if (bytes
!= sizeof(magic
)) {
317 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(magic
));
321 if (be32_to_cpu(magic
) == UBI_EC_HDR_MAGIC
)
324 if (info
->rootfs_offset
>= info
->file_size
) {
325 fprintf(stderr
, "Failed to find rootfs offset\n");
331 /* Start with cferom (or bootfs) - skip vendor header */
332 fseek(fp
, info
->cferom_offset
, SEEK_SET
);
334 info
->crc32
= 0xffffffff;
335 length
= info
->file_size
- info
->cferom_offset
- sizeof(*tail
);
336 while (length
&& (bytes
= fread(buf
, 1, bcm4908img_min(sizeof(buf
), length
), fp
)) > 0) {
337 info
->crc32
= bcm4908img_crc32(info
->crc32
, buf
, bytes
);
341 fprintf(stderr
, "Failed to read last %zd B of data\n", length
);
347 if (fread(tail
, 1, sizeof(*tail
), fp
) != sizeof(*tail
)) {
348 fprintf(stderr
, "Failed to read BCM4908 image tail\n");
352 /* Standard validation */
354 if (info
->crc32
!= le32_to_cpu(tail
->crc32
)) {
355 fprintf(stderr
, "Invalid data crc32: 0x%08x instead of 0x%08x\n", info
->crc32
, le32_to_cpu(tail
->crc32
));
362 /**************************************************
364 **************************************************/
366 static int bcm4908img_info(int argc
, char **argv
) {
367 struct bcm4908img_info info
;
368 const char *pathname
= NULL
;
373 while ((c
= getopt(argc
, argv
, "i:")) != -1) {
381 fp
= bcm4908img_open(pathname
, "r");
383 fprintf(stderr
, "Failed to open BCM4908 image\n");
388 err
= bcm4908img_parse(fp
, &info
);
390 fprintf(stderr
, "Failed to parse BCM4908 image\n");
394 if (info
.bootfs_offset
!= info
.cferom_offset
)
395 printf("cferom offset:\t%zu\n", info
.cferom_offset
);
396 printf("bootfs offset:\t0x%zx\n", info
.bootfs_offset
);
397 printf("rootfs offset:\t0x%zx\n", info
.rootfs_offset
);
398 printf("Checksum:\t0x%08x\n", info
.crc32
);
401 bcm4908img_close(fp
);
406 /**************************************************
408 **************************************************/
410 static ssize_t
bcm4908img_create_append_file(FILE *trx
, const char *in_path
, uint32_t *crc32
) {
416 in
= fopen(in_path
, "r");
418 fprintf(stderr
, "Failed to open %s\n", in_path
);
422 while ((bytes
= fread(buf
, 1, sizeof(buf
), in
)) > 0) {
423 if (fwrite(buf
, 1, bytes
, trx
) != bytes
) {
424 fprintf(stderr
, "Failed to write %zu B to %s\n", bytes
, pathname
);
428 *crc32
= bcm4908img_crc32(*crc32
, buf
, bytes
);
437 static ssize_t
bcm4908img_create_append_zeros(FILE *trx
, size_t length
) {
440 buf
= malloc(length
);
443 memset(buf
, 0, length
);
445 if (fwrite(buf
, 1, length
, trx
) != length
) {
446 fprintf(stderr
, "Failed to write %zu B to %s\n", length
, pathname
);
456 static ssize_t
bcm4908img_create_align(FILE *trx
, size_t cur_offset
, size_t alignment
) {
457 if (cur_offset
& (alignment
- 1)) {
458 size_t length
= alignment
- (cur_offset
% alignment
);
459 return bcm4908img_create_append_zeros(trx
, length
);
465 static int bcm4908img_create(int argc
, char **argv
) {
466 struct bcm4908img_tail tail
= {
467 .version
= cpu_to_le32(WFI_VERSION
),
468 .chip_id
= cpu_to_le32(0x4908),
469 .flash_type
= cpu_to_le32(WFI_NAND128_FLASH
),
470 .flags
= cpu_to_le32(WFI_FLAG_SUPPORTS_BTRM
),
472 uint32_t crc32
= 0xffffffff;
473 size_t cur_offset
= 0;
480 fprintf(stderr
, "No BCM4908 image pathname passed\n");
486 fp
= fopen(pathname
, "w+");
488 fprintf(stderr
, "Failed to open %s\n", pathname
);
494 while ((c
= getopt(argc
, argv
, "f:a:A:")) != -1) {
497 bytes
= bcm4908img_create_append_file(fp
, optarg
, &crc32
);
499 fprintf(stderr
, "Failed to append file %s\n", optarg
);
505 bytes
= bcm4908img_create_align(fp
, cur_offset
, strtol(optarg
, NULL
, 0));
507 fprintf(stderr
, "Failed to append zeros\n");
512 bytes
= strtol(optarg
, NULL
, 0) - cur_offset
;
514 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));
516 bytes
= bcm4908img_create_append_zeros(fp
, bytes
);
518 fprintf(stderr
, "Failed to append zeros\n");
528 tail
.crc32
= cpu_to_le32(crc32
);
530 bytes
= fwrite(&tail
, 1, sizeof(tail
), fp
);
531 if (bytes
!= sizeof(tail
)) {
532 fprintf(stderr
, "Failed to write BCM4908 image tail to %s\n", pathname
);
542 /**************************************************
544 **************************************************/
546 static int bcm4908img_extract(int argc
, char **argv
) {
547 struct bcm4908img_info info
;
548 const char *pathname
= NULL
;
558 while ((c
= getopt(argc
, argv
, "i:t:")) != -1) {
569 fp
= bcm4908img_open(pathname
, "r");
571 fprintf(stderr
, "Failed to open BCM4908 image\n");
576 err
= bcm4908img_parse(fp
, &info
);
578 fprintf(stderr
, "Failed to parse BCM4908 image\n");
582 if (!strcmp(type
, "cferom")) {
583 offset
= info
.cferom_offset
;
584 length
= info
.bootfs_offset
- offset
;
587 fprintf(stderr
, "This BCM4908 image doesn't contain cferom\n");
590 } else if (!strcmp(type
, "bootfs")) {
591 offset
= info
.bootfs_offset
;
592 length
= info
.rootfs_offset
- offset
;
593 } else if (!strcmp(type
, "rootfs")) {
594 offset
= info
.rootfs_offset
;
595 length
= info
.file_size
- offset
- sizeof(struct bcm4908img_tail
);
596 } else if (!strcmp(type
, "firmware")) {
597 offset
= info
.bootfs_offset
;
598 length
= info
.file_size
- offset
- sizeof(struct bcm4908img_tail
);
601 fprintf(stderr
, "Unsupported extract type: %s\n", type
);
607 fprintf(stderr
, "No data to extract specified\n");
611 fseek(fp
, offset
, SEEK_SET
);
612 while (length
&& (bytes
= fread(buf
, 1, bcm4908img_min(sizeof(buf
), length
), fp
)) > 0) {
613 fwrite(buf
, bytes
, 1, stdout
);
618 fprintf(stderr
, "Failed to read last %zd B of data\n", length
);
623 bcm4908img_close(fp
);
628 /**************************************************
630 **************************************************/
632 #define JFFS2_MAGIC_BITMASK 0x1985
634 #define JFFS2_COMPR_NONE 0x00
635 #define JFFS2_COMPR_ZERO 0x01
636 #define JFFS2_COMPR_RTIME 0x02
637 #define JFFS2_COMPR_RUBINMIPS 0x03
638 #define JFFS2_COMPR_COPY 0x04
639 #define JFFS2_COMPR_DYNRUBIN 0x05
640 #define JFFS2_COMPR_ZLIB 0x06
641 #define JFFS2_COMPR_LZO 0x07
642 /* Compatibility flags. */
643 #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */
644 #define JFFS2_NODE_ACCURATE 0x2000
645 /* INCOMPAT: Fail to mount the filesystem */
646 #define JFFS2_FEATURE_INCOMPAT 0xc000
647 /* ROCOMPAT: Mount read-only */
648 #define JFFS2_FEATURE_ROCOMPAT 0x8000
649 /* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */
650 #define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000
651 /* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */
652 #define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000
654 #define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1)
658 } __attribute__((packed
)) jint32_t
;
662 } __attribute__((packed
)) jint16_t
;
664 struct jffs2_unknown_node
666 /* All start like this */
669 jint32_t totlen
; /* So we can skip over nodes we don't grok */
673 struct jffs2_raw_dirent
676 jint16_t nodetype
; /* == JFFS2_NODETYPE_DIRENT */
681 jint32_t ino
; /* == zero for unlink */
691 #define je16_to_cpu(x) ((x).v16)
692 #define je32_to_cpu(x) ((x).v32)
694 static int bcm4908img_bootfs_ls(FILE *fp
, struct bcm4908img_info
*info
) {
695 struct jffs2_unknown_node node
;
696 struct jffs2_raw_dirent dirent
;
701 for (offset
= info
->bootfs_offset
; ; offset
+= (je32_to_cpu(node
.totlen
) + 0x03) & ~0x03) {
702 char name
[FILENAME_MAX
+ 1];
704 if (fseek(fp
, offset
, SEEK_SET
)) {
706 fprintf(stderr
, "Failed to fseek: %d\n", err
);
710 bytes
= fread(&node
, 1, sizeof(node
), fp
);
711 if (bytes
!= sizeof(node
)) {
712 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(node
));
716 if (je16_to_cpu(node
.magic
) != JFFS2_MAGIC_BITMASK
) {
720 if (je16_to_cpu(node
.nodetype
) != JFFS2_NODETYPE_DIRENT
) {
724 memcpy(&dirent
, &node
, sizeof(node
));
725 bytes
+= fread((uint8_t *)&dirent
+ sizeof(node
), 1, sizeof(dirent
) - sizeof(node
), fp
);
726 if (bytes
!= sizeof(dirent
)) {
727 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(node
));
731 if (dirent
.nsize
+ 1 > sizeof(name
)) {
732 /* Keep reading & printing BUT exit with error code */
733 fprintf(stderr
, "Too long filename\n");
738 bytes
= fread(name
, 1, dirent
.nsize
, fp
);
739 if (bytes
!= dirent
.nsize
) {
740 fprintf(stderr
, "Failed to read filename\n");
745 printf("%s\n", name
);
751 static int bcm4908img_bootfs_mv(FILE *fp
, struct bcm4908img_info
*info
, int argc
, char **argv
) {
752 struct jffs2_unknown_node node
;
753 struct jffs2_raw_dirent dirent
;
760 if (argc
- optind
< 2) {
761 fprintf(stderr
, "No enough arguments passed\n");
764 oldname
= argv
[optind
++];
765 newname
= argv
[optind
++];
767 if (strlen(newname
) != strlen(oldname
)) {
768 fprintf(stderr
, "New filename must have the same length as the old one\n");
772 for (offset
= info
->bootfs_offset
; ; offset
+= (je32_to_cpu(node
.totlen
) + 0x03) & ~0x03) {
773 char name
[FILENAME_MAX
];
776 if (fseek(fp
, offset
, SEEK_SET
)) {
778 fprintf(stderr
, "Failed to fseek: %d\n", err
);
782 bytes
= fread(&node
, 1, sizeof(node
), fp
);
783 if (bytes
!= sizeof(node
)) {
784 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(node
));
788 if (je16_to_cpu(node
.magic
) != JFFS2_MAGIC_BITMASK
) {
792 if (je16_to_cpu(node
.nodetype
) != JFFS2_NODETYPE_DIRENT
) {
796 bytes
+= fread((uint8_t *)&dirent
+ sizeof(node
), 1, sizeof(dirent
) - sizeof(node
), fp
);
797 if (bytes
!= sizeof(dirent
)) {
798 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(node
));
802 if (dirent
.nsize
+ 1 > sizeof(name
)) {
803 fprintf(stderr
, "Too long filename\n");
808 bytes
= fread(name
, 1, dirent
.nsize
, fp
);
809 if (bytes
!= dirent
.nsize
) {
810 fprintf(stderr
, "Failed to read filename\n");
816 printf("offset:%08zx name_crc:%04x filename:%s\n", offset
, je32_to_cpu(dirent
.name_crc
), name
);
818 if (strcmp(name
, oldname
)) {
822 if (fseek(fp
, offset
+ offsetof(struct jffs2_raw_dirent
, name_crc
), SEEK_SET
)) {
824 fprintf(stderr
, "Failed to fseek: %d\n", err
);
827 crc32
= bcm4908img_crc32(0, newname
, dirent
.nsize
);
828 bytes
= fwrite(&crc32
, 1, sizeof(crc32
), fp
);
829 if (bytes
!= sizeof(crc32
)) {
830 fprintf(stderr
, "Failed to write new CRC32\n");
834 if (fseek(fp
, offset
+ offsetof(struct jffs2_raw_dirent
, name
), SEEK_SET
)) {
836 fprintf(stderr
, "Failed to fseek: %d\n", err
);
839 bytes
= fwrite(newname
, 1, dirent
.nsize
, fp
);
840 if (bytes
!= dirent
.nsize
) {
841 fprintf(stderr
, "Failed to write new filename\n");
845 /* Calculate new BCM4908 image checksum */
847 err
= bcm4908img_calc_crc32(fp
, info
);
849 fprintf(stderr
, "Failed to write new filename\n");
853 info
->tail
.crc32
= cpu_to_le32(info
->crc32
);
854 if (fseek(fp
, -sizeof(struct bcm4908img_tail
), SEEK_END
)) {
856 fprintf(stderr
, "Failed to write new filename\n");
860 if (fwrite(&info
->tail
, 1, sizeof(struct bcm4908img_tail
), fp
) != sizeof(struct bcm4908img_tail
)) {
861 fprintf(stderr
, "Failed to write updated tail\n");
865 printf("Successfully renamed %s to the %s\n", oldname
, newname
);
870 fprintf(stderr
, "Failed to find %s\n", oldname
);
875 static int bcm4908img_bootfs(int argc
, char **argv
) {
876 struct bcm4908img_info info
;
877 const char *pathname
= NULL
;
884 while ((c
= getopt(argc
, argv
, "i:")) != -1) {
892 if (argc
- optind
< 1) {
893 fprintf(stderr
, "No bootfs command specified\n");
897 cmd
= argv
[optind
++];
899 mode
= strcmp(cmd
, "mv") ? "r" : "r+";
900 fp
= bcm4908img_open(pathname
, mode
);
902 fprintf(stderr
, "Failed to open BCM4908 image\n");
907 err
= bcm4908img_parse(fp
, &info
);
909 fprintf(stderr
, "Failed to parse BCM4908 image\n");
913 if (!strcmp(cmd
, "ls")) {
914 err
= bcm4908img_bootfs_ls(fp
, &info
);
915 } else if (!strcmp(cmd
, "mv")) {
916 err
= bcm4908img_bootfs_mv(fp
, &info
, argc
, argv
);
919 fprintf(stderr
, "Unsupported bootfs command: %s\n", cmd
);
923 bcm4908img_close(fp
);
928 /**************************************************
930 **************************************************/
932 static void usage() {
935 printf("Info about a BCM4908 image:\n");
936 printf("\tbcm4908img info <options>\n");
937 printf("\t-i <file>\t\t\t\tinput BCM490 image\n");
939 printf("Creating a new BCM4908 image:\n");
940 printf("\tbcm4908img create <file> [options]\n");
941 printf("\t-f file\t\t\t\tadd data from specified file\n");
942 printf("\t-a alignment\t\t\tpad image with zeros to specified alignment\n");
943 printf("\t-A offset\t\t\t\tappend zeros until reaching specified offset\n");
945 printf("Extracting from a BCM4908 image:\n");
946 printf("\tbcm4908img extract <options>\n");
947 printf("\t-i <file>\t\t\t\tinput BCM490 image\n");
948 printf("\t-t <type>\t\t\t\tone of: cferom, bootfs, rootfs, firmware\n");
950 printf("Access bootfs in a BCM4908 image:\n");
951 printf("\tbcm4908img bootfs <options> <command> <arguments>\n");
952 printf("\t-i <file>\t\t\t\tinput BCM490 image\n");
953 printf("\tls\t\t\t\t\tlist bootfs files\n");
954 printf("\tmv <source> <dest>\t\t\trename bootfs file\n");
957 int main(int argc
, char **argv
) {
960 if (!strcmp(argv
[1], "info"))
961 return bcm4908img_info(argc
, argv
);
962 else if (!strcmp(argv
[1], "create"))
963 return bcm4908img_create(argc
, argv
);
964 else if (!strcmp(argv
[1], "extract"))
965 return bcm4908img_extract(argc
, argv
);
966 else if (!strcmp(argv
[1], "bootfs"))
967 return bcm4908img_bootfs(argc
, argv
);