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
59 struct bcm4908img_tail
{
68 * struct bcm4908img_info - info about BCM4908 image
70 * Standard BCM4908 image consists of:
71 * 1. (Optional) vedor header
72 * 2. (Optional) cferom
74 * 4. padding ├─ firmware
78 struct bcm4908img_info
{
82 uint32_t crc32
; /* Calculated checksum */
83 struct bcm4908img_tail tail
;
88 static inline size_t bcm4908img_min(size_t x
, size_t y
) {
92 /**************************************************
94 **************************************************/
96 static const uint32_t crc32_tbl
[] = {
97 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
98 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
99 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
100 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
101 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
102 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
103 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
104 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
105 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
106 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
107 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
108 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
109 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
110 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
111 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
112 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
113 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
114 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
115 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
116 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
117 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
118 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
119 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
120 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
121 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
122 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
123 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
124 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
125 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
126 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
127 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
128 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
129 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
130 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
131 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
132 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
133 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
134 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
135 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
136 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
137 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
138 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
139 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
140 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
141 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
142 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
143 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
144 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
145 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
146 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
147 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
148 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
149 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
150 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
151 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
152 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
153 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
154 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
155 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
156 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
157 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
158 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
159 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
160 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
163 uint32_t bcm4908img_crc32(uint32_t crc
, const void *buf
, size_t len
) {
164 const uint8_t *in
= buf
;
167 crc
= crc32_tbl
[(crc
^ *in
) & 0xff] ^ (crc
>> 8);
175 /**************************************************
177 **************************************************/
179 static FILE *bcm4908img_open(const char *pathname
, const char *mode
) {
183 return fopen(pathname
, mode
);
185 if (isatty(fileno(stdin
))) {
186 fprintf(stderr
, "Reading from TTY stdin is unsupported\n");
190 if (fstat(fileno(stdin
), &st
)) {
191 fprintf(stderr
, "Failed to fstat stdin: %d\n", -errno
);
195 if (S_ISFIFO(st
.st_mode
)) {
196 fprintf(stderr
, "Reading from pipe stdin is unsupported\n");
203 static void bcm4908img_close(FILE *fp
) {
208 static int bcm4908img_calc_crc32(FILE *fp
, struct bcm4908img_info
*info
) {
213 /* Start with cferom (or bootfs) - skip vendor header */
214 fseek(fp
, info
->cferom_offset
, SEEK_SET
);
216 info
->crc32
= 0xffffffff;
217 length
= info
->file_size
- info
->cferom_offset
- sizeof(struct bcm4908img_tail
);
218 while (length
&& (bytes
= fread(buf
, 1, bcm4908img_min(sizeof(buf
), length
), fp
)) > 0) {
219 info
->crc32
= bcm4908img_crc32(info
->crc32
, buf
, bytes
);
223 fprintf(stderr
, "Failed to read last %zd B of data\n", length
);
230 /**************************************************
231 * Existing firmware parser
232 **************************************************/
238 uint32_t kernel_chksum
;
239 uint32_t rootfs_chksum
;
242 uint32_t image_chksum
;
243 uint32_t header_chksum
;
247 static int bcm4908img_parse(FILE *fp
, struct bcm4908img_info
*info
) {
248 struct bcm4908img_tail
*tail
= &info
->tail
;
249 struct chk_header
*chk
;
257 memset(info
, 0, sizeof(*info
));
261 if (fstat(fileno(fp
), &st
)) {
263 fprintf(stderr
, "Failed to fstat: %d\n", err
);
266 info
->file_size
= st
.st_size
;
271 if (fread(buf
, 1, sizeof(buf
), fp
) != sizeof(buf
)) {
272 fprintf(stderr
, "Failed to read file header\n");
276 if (be32_to_cpu(chk
->magic
) == 0x2a23245e)
277 info
->cferom_offset
= be32_to_cpu(chk
->header_len
);
281 for (info
->bootfs_offset
= info
->cferom_offset
;
282 info
->bootfs_offset
< info
->file_size
;
283 info
->bootfs_offset
+= 0x20000) {
284 if (fseek(fp
, info
->bootfs_offset
, SEEK_SET
)) {
286 fprintf(stderr
, "Failed to fseek to the 0x%zx\n", info
->bootfs_offset
);
289 if (fread(&tmp16
, 1, sizeof(tmp16
), fp
) != sizeof(tmp16
)) {
290 fprintf(stderr
, "Failed to read while looking for JFFS2\n");
293 if (be16_to_cpu(tmp16
) == 0x8519)
296 if (info
->bootfs_offset
>= info
->file_size
) {
297 fprintf(stderr
, "Failed to find bootfs offset\n");
303 /* Start with cferom (or bootfs) - skip vendor header */
304 fseek(fp
, info
->cferom_offset
, SEEK_SET
);
306 info
->crc32
= 0xffffffff;
307 length
= info
->file_size
- info
->cferom_offset
- sizeof(*tail
);
308 while (length
&& (bytes
= fread(buf
, 1, bcm4908img_min(sizeof(buf
), length
), fp
)) > 0) {
309 info
->crc32
= bcm4908img_crc32(info
->crc32
, buf
, bytes
);
313 fprintf(stderr
, "Failed to read last %zd B of data\n", length
);
319 if (fread(tail
, 1, sizeof(*tail
), fp
) != sizeof(*tail
)) {
320 fprintf(stderr
, "Failed to read BCM4908 image tail\n");
324 /* Standard validation */
326 if (info
->crc32
!= le32_to_cpu(tail
->crc32
)) {
327 fprintf(stderr
, "Invalid data crc32: 0x%08x instead of 0x%08x\n", info
->crc32
, le32_to_cpu(tail
->crc32
));
334 /**************************************************
336 **************************************************/
338 static int bcm4908img_info(int argc
, char **argv
) {
339 struct bcm4908img_info info
;
340 const char *pathname
= NULL
;
345 while ((c
= getopt(argc
, argv
, "i:")) != -1) {
353 fp
= bcm4908img_open(pathname
, "r");
355 fprintf(stderr
, "Failed to open BCM4908 image\n");
360 err
= bcm4908img_parse(fp
, &info
);
362 fprintf(stderr
, "Failed to parse BCM4908 image\n");
366 if (info
.bootfs_offset
!= info
.cferom_offset
)
367 printf("cferom offset:\t%zu\n", info
.cferom_offset
);
368 printf("bootfs offset:\t0x%zx\n", info
.bootfs_offset
);
369 printf("Checksum:\t0x%08x\n", info
.crc32
);
372 bcm4908img_close(fp
);
377 /**************************************************
379 **************************************************/
381 static ssize_t
bcm4908img_create_append_file(FILE *trx
, const char *in_path
, uint32_t *crc32
) {
387 in
= fopen(in_path
, "r");
389 fprintf(stderr
, "Failed to open %s\n", in_path
);
393 while ((bytes
= fread(buf
, 1, sizeof(buf
), in
)) > 0) {
394 if (fwrite(buf
, 1, bytes
, trx
) != bytes
) {
395 fprintf(stderr
, "Failed to write %zu B to %s\n", bytes
, pathname
);
399 *crc32
= bcm4908img_crc32(*crc32
, buf
, bytes
);
408 static ssize_t
bcm4908img_create_append_zeros(FILE *trx
, size_t length
) {
411 buf
= malloc(length
);
414 memset(buf
, 0, length
);
416 if (fwrite(buf
, 1, length
, trx
) != length
) {
417 fprintf(stderr
, "Failed to write %zu B to %s\n", length
, pathname
);
427 static ssize_t
bcm4908img_create_align(FILE *trx
, size_t cur_offset
, size_t alignment
) {
428 if (cur_offset
& (alignment
- 1)) {
429 size_t length
= alignment
- (cur_offset
% alignment
);
430 return bcm4908img_create_append_zeros(trx
, length
);
436 static int bcm4908img_create(int argc
, char **argv
) {
437 struct bcm4908img_tail tail
= {
438 .version
= cpu_to_le32(WFI_VERSION
),
439 .chip_id
= cpu_to_le32(0x4908),
440 .flash_type
= cpu_to_le32(WFI_NAND128_FLASH
),
441 .flags
= cpu_to_le32(WFI_FLAG_SUPPORTS_BTRM
),
443 uint32_t crc32
= 0xffffffff;
444 size_t cur_offset
= 0;
451 fprintf(stderr
, "No BCM4908 image pathname passed\n");
457 fp
= fopen(pathname
, "w+");
459 fprintf(stderr
, "Failed to open %s\n", pathname
);
465 while ((c
= getopt(argc
, argv
, "f:a:A:")) != -1) {
468 bytes
= bcm4908img_create_append_file(fp
, optarg
, &crc32
);
470 fprintf(stderr
, "Failed to append file %s\n", optarg
);
476 bytes
= bcm4908img_create_align(fp
, cur_offset
, strtol(optarg
, NULL
, 0));
478 fprintf(stderr
, "Failed to append zeros\n");
483 bytes
= strtol(optarg
, NULL
, 0) - cur_offset
;
485 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));
487 bytes
= bcm4908img_create_append_zeros(fp
, bytes
);
489 fprintf(stderr
, "Failed to append zeros\n");
499 tail
.crc32
= cpu_to_le32(crc32
);
501 bytes
= fwrite(&tail
, 1, sizeof(tail
), fp
);
502 if (bytes
!= sizeof(tail
)) {
503 fprintf(stderr
, "Failed to write BCM4908 image tail to %s\n", pathname
);
513 /**************************************************
515 **************************************************/
517 static int bcm4908img_extract(int argc
, char **argv
) {
518 struct bcm4908img_info info
;
519 const char *pathname
= NULL
;
529 while ((c
= getopt(argc
, argv
, "i:t:")) != -1) {
540 fp
= bcm4908img_open(pathname
, "r");
542 fprintf(stderr
, "Failed to open BCM4908 image\n");
547 err
= bcm4908img_parse(fp
, &info
);
549 fprintf(stderr
, "Failed to parse BCM4908 image\n");
553 if (!strcmp(type
, "cferom")) {
555 length
= info
.bootfs_offset
- offset
;
558 fprintf(stderr
, "This BCM4908 image doesn't contain cferom\n");
561 } else if (!strcmp(type
, "firmware")) {
562 offset
= info
.bootfs_offset
;
563 length
= info
.file_size
- offset
- sizeof(struct bcm4908img_tail
);
566 fprintf(stderr
, "Unsupported extract type: %s\n", type
);
572 fprintf(stderr
, "No data to extract specified\n");
576 fseek(fp
, offset
, SEEK_SET
);
577 while (length
&& (bytes
= fread(buf
, 1, bcm4908img_min(sizeof(buf
), length
), fp
)) > 0) {
578 fwrite(buf
, bytes
, 1, stdout
);
583 fprintf(stderr
, "Failed to read last %zd B of data\n", length
);
588 bcm4908img_close(fp
);
593 /**************************************************
595 **************************************************/
597 #define JFFS2_MAGIC_BITMASK 0x1985
599 #define JFFS2_COMPR_NONE 0x00
600 #define JFFS2_COMPR_ZERO 0x01
601 #define JFFS2_COMPR_RTIME 0x02
602 #define JFFS2_COMPR_RUBINMIPS 0x03
603 #define JFFS2_COMPR_COPY 0x04
604 #define JFFS2_COMPR_DYNRUBIN 0x05
605 #define JFFS2_COMPR_ZLIB 0x06
606 #define JFFS2_COMPR_LZO 0x07
607 /* Compatibility flags. */
608 #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */
609 #define JFFS2_NODE_ACCURATE 0x2000
610 /* INCOMPAT: Fail to mount the filesystem */
611 #define JFFS2_FEATURE_INCOMPAT 0xc000
612 /* ROCOMPAT: Mount read-only */
613 #define JFFS2_FEATURE_ROCOMPAT 0x8000
614 /* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */
615 #define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000
616 /* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */
617 #define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000
619 #define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1)
623 } __attribute__((packed
)) jint32_t
;
627 } __attribute__((packed
)) jint16_t
;
629 struct jffs2_unknown_node
631 /* All start like this */
634 jint32_t totlen
; /* So we can skip over nodes we don't grok */
638 struct jffs2_raw_dirent
641 jint16_t nodetype
; /* == JFFS2_NODETYPE_DIRENT */
646 jint32_t ino
; /* == zero for unlink */
656 #define je16_to_cpu(x) ((x).v16)
657 #define je32_to_cpu(x) ((x).v32)
659 static int bcm4908img_bootfs_ls(FILE *fp
, struct bcm4908img_info
*info
) {
660 struct jffs2_unknown_node node
;
661 struct jffs2_raw_dirent dirent
;
666 for (offset
= info
->bootfs_offset
; ; offset
+= (je32_to_cpu(node
.totlen
) + 0x03) & ~0x03) {
667 char name
[FILENAME_MAX
+ 1];
669 if (fseek(fp
, offset
, SEEK_SET
)) {
671 fprintf(stderr
, "Failed to fseek: %d\n", err
);
675 bytes
= fread(&node
, 1, sizeof(node
), fp
);
676 if (bytes
!= sizeof(node
)) {
677 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(node
));
681 if (je16_to_cpu(node
.magic
) != JFFS2_MAGIC_BITMASK
) {
685 if (je16_to_cpu(node
.nodetype
) != JFFS2_NODETYPE_DIRENT
) {
689 memcpy(&dirent
, &node
, sizeof(node
));
690 bytes
+= fread((uint8_t *)&dirent
+ sizeof(node
), 1, sizeof(dirent
) - sizeof(node
), fp
);
691 if (bytes
!= sizeof(dirent
)) {
692 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(node
));
696 if (dirent
.nsize
+ 1 > sizeof(name
)) {
697 /* Keep reading & printing BUT exit with error code */
698 fprintf(stderr
, "Too long filename\n");
703 bytes
= fread(name
, 1, dirent
.nsize
, fp
);
704 if (bytes
!= dirent
.nsize
) {
705 fprintf(stderr
, "Failed to read filename\n");
710 printf("%s\n", name
);
716 static int bcm4908img_bootfs_mv(FILE *fp
, struct bcm4908img_info
*info
, int argc
, char **argv
) {
717 struct jffs2_unknown_node node
;
718 struct jffs2_raw_dirent dirent
;
725 if (argc
- optind
< 2) {
726 fprintf(stderr
, "No enough arguments passed\n");
729 oldname
= argv
[optind
++];
730 newname
= argv
[optind
++];
732 if (strlen(newname
) != strlen(oldname
)) {
733 fprintf(stderr
, "New filename must have the same length as the old one\n");
737 for (offset
= info
->bootfs_offset
; ; offset
+= (je32_to_cpu(node
.totlen
) + 0x03) & ~0x03) {
738 char name
[FILENAME_MAX
];
741 if (fseek(fp
, offset
, SEEK_SET
)) {
743 fprintf(stderr
, "Failed to fseek: %d\n", err
);
747 bytes
= fread(&node
, 1, sizeof(node
), fp
);
748 if (bytes
!= sizeof(node
)) {
749 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(node
));
753 if (je16_to_cpu(node
.magic
) != JFFS2_MAGIC_BITMASK
) {
757 if (je16_to_cpu(node
.nodetype
) != JFFS2_NODETYPE_DIRENT
) {
761 bytes
+= fread((uint8_t *)&dirent
+ sizeof(node
), 1, sizeof(dirent
) - sizeof(node
), fp
);
762 if (bytes
!= sizeof(dirent
)) {
763 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(node
));
767 if (dirent
.nsize
+ 1 > sizeof(name
)) {
768 fprintf(stderr
, "Too long filename\n");
773 bytes
= fread(name
, 1, dirent
.nsize
, fp
);
774 if (bytes
!= dirent
.nsize
) {
775 fprintf(stderr
, "Failed to read filename\n");
781 printf("offset:%08zx name_crc:%04x filename:%s\n", offset
, je32_to_cpu(dirent
.name_crc
), name
);
783 if (strcmp(name
, oldname
)) {
787 if (fseek(fp
, offset
+ offsetof(struct jffs2_raw_dirent
, name_crc
), SEEK_SET
)) {
789 fprintf(stderr
, "Failed to fseek: %d\n", err
);
792 crc32
= bcm4908img_crc32(0, newname
, dirent
.nsize
);
793 bytes
= fwrite(&crc32
, 1, sizeof(crc32
), fp
);
794 if (bytes
!= sizeof(crc32
)) {
795 fprintf(stderr
, "Failed to write new CRC32\n");
799 if (fseek(fp
, offset
+ offsetof(struct jffs2_raw_dirent
, name
), SEEK_SET
)) {
801 fprintf(stderr
, "Failed to fseek: %d\n", err
);
804 bytes
= fwrite(newname
, 1, dirent
.nsize
, fp
);
805 if (bytes
!= dirent
.nsize
) {
806 fprintf(stderr
, "Failed to write new filename\n");
810 /* Calculate new BCM4908 image checksum */
812 err
= bcm4908img_calc_crc32(fp
, info
);
814 fprintf(stderr
, "Failed to write new filename\n");
818 info
->tail
.crc32
= cpu_to_le32(info
->crc32
);
819 if (fseek(fp
, -sizeof(struct bcm4908img_tail
), SEEK_END
)) {
821 fprintf(stderr
, "Failed to write new filename\n");
825 if (fwrite(&info
->tail
, 1, sizeof(struct bcm4908img_tail
), fp
) != sizeof(struct bcm4908img_tail
)) {
826 fprintf(stderr
, "Failed to write updated tail\n");
830 printf("Successfully renamed %s to the %s\n", oldname
, newname
);
835 fprintf(stderr
, "Failed to find %s\n", oldname
);
840 static int bcm4908img_bootfs(int argc
, char **argv
) {
841 struct bcm4908img_info info
;
842 const char *pathname
= NULL
;
849 while ((c
= getopt(argc
, argv
, "i:")) != -1) {
857 if (argc
- optind
< 1) {
858 fprintf(stderr
, "No bootfs command specified\n");
862 cmd
= argv
[optind
++];
864 mode
= strcmp(cmd
, "mv") ? "r" : "r+";
865 fp
= bcm4908img_open(pathname
, mode
);
867 fprintf(stderr
, "Failed to open BCM4908 image\n");
872 err
= bcm4908img_parse(fp
, &info
);
874 fprintf(stderr
, "Failed to parse BCM4908 image\n");
878 if (!strcmp(cmd
, "ls")) {
879 err
= bcm4908img_bootfs_ls(fp
, &info
);
880 } else if (!strcmp(cmd
, "mv")) {
881 err
= bcm4908img_bootfs_mv(fp
, &info
, argc
, argv
);
884 fprintf(stderr
, "Unsupported bootfs command: %s\n", cmd
);
888 bcm4908img_close(fp
);
893 /**************************************************
895 **************************************************/
897 static void usage() {
900 printf("Info about a BCM4908 image:\n");
901 printf("\tbcm4908img info <options>\n");
902 printf("\t-i <file>\t\t\t\tinput BCM490 image\n");
904 printf("Creating a new BCM4908 image:\n");
905 printf("\tbcm4908img create <file> [options]\n");
906 printf("\t-f file\t\t\t\tadd data from specified file\n");
907 printf("\t-a alignment\t\t\tpad image with zeros to specified alignment\n");
908 printf("\t-A offset\t\t\t\tappend zeros until reaching specified offset\n");
910 printf("Extracting from a BCM4908 image:\n");
911 printf("\tbcm4908img extract <options>\n");
912 printf("\t-i <file>\t\t\t\tinput BCM490 image\n");
913 printf("\t-t <type>\t\t\t\tone of: cferom, bootfs, rootfs, firmware\n");
915 printf("Access bootfs in a BCM4908 image:\n");
916 printf("\tbcm4908img bootfs <options> <command> <arguments>\n");
917 printf("\t-i <file>\t\t\t\tinput BCM490 image\n");
918 printf("\tls\t\t\t\t\tlist bootfs files\n");
919 printf("\tmv <source> <dest>\t\t\trename bootfs file\n");
922 int main(int argc
, char **argv
) {
925 if (!strcmp(argv
[1], "info"))
926 return bcm4908img_info(argc
, argv
);
927 else if (!strcmp(argv
[1], "create"))
928 return bcm4908img_create(argc
, argv
);
929 else if (!strcmp(argv
[1], "extract"))
930 return bcm4908img_extract(argc
, argv
);
931 else if (!strcmp(argv
[1], "bootfs"))
932 return bcm4908img_bootfs(argc
, argv
);