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
{
67 /* Info about BCM4908 image */
68 struct bcm4908img_info
{
70 size_t vendor_header_size
; /* Vendor header size */
72 uint32_t crc32
; /* Calculated checksum */
73 struct bcm4908img_tail tail
;
78 static inline size_t bcm4908img_min(size_t x
, size_t y
) {
82 /**************************************************
84 **************************************************/
86 static const uint32_t crc32_tbl
[] = {
87 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
88 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
89 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
90 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
91 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
92 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
93 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
94 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
95 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
96 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
97 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
98 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
99 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
100 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
101 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
102 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
103 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
104 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
105 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
106 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
107 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
108 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
109 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
110 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
111 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
112 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
113 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
114 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
115 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
116 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
117 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
118 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
119 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
120 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
121 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
122 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
123 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
124 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
125 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
126 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
127 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
128 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
129 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
130 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
131 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
132 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
133 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
134 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
135 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
136 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
137 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
138 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
139 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
140 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
141 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
142 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
143 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
144 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
145 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
146 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
147 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
148 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
149 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
150 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
153 uint32_t bcm4908img_crc32(uint32_t crc
, const void *buf
, size_t len
) {
154 const uint8_t *in
= buf
;
157 crc
= crc32_tbl
[(crc
^ *in
) & 0xff] ^ (crc
>> 8);
165 /**************************************************
167 **************************************************/
169 static FILE *bcm4908img_open(const char *pathname
, const char *mode
) {
173 return fopen(pathname
, mode
);
175 if (isatty(fileno(stdin
))) {
176 fprintf(stderr
, "Reading from TTY stdin is unsupported\n");
180 if (fstat(fileno(stdin
), &st
)) {
181 fprintf(stderr
, "Failed to fstat stdin: %d\n", -errno
);
185 if (S_ISFIFO(st
.st_mode
)) {
186 fprintf(stderr
, "Reading from pipe stdin is unsupported\n");
193 static void bcm4908img_close(FILE *fp
) {
198 static int bcm4908img_calc_crc32(FILE *fp
, struct bcm4908img_info
*info
) {
203 fseek(fp
, info
->vendor_header_size
, SEEK_SET
);
205 info
->crc32
= 0xffffffff;
206 length
= info
->file_size
- info
->vendor_header_size
- sizeof(struct bcm4908img_tail
);
207 while (length
&& (bytes
= fread(buf
, 1, bcm4908img_min(sizeof(buf
), length
), fp
)) > 0) {
208 info
->crc32
= bcm4908img_crc32(info
->crc32
, buf
, bytes
);
212 fprintf(stderr
, "Failed to read last %zd B of data\n", length
);
219 /**************************************************
220 * Existing firmware parser
221 **************************************************/
227 uint32_t kernel_chksum
;
228 uint32_t rootfs_chksum
;
231 uint32_t image_chksum
;
232 uint32_t header_chksum
;
236 static int bcm4908img_parse(FILE *fp
, struct bcm4908img_info
*info
) {
237 struct bcm4908img_tail
*tail
= &info
->tail
;
238 struct chk_header
*chk
;
246 memset(info
, 0, sizeof(*info
));
250 if (fstat(fileno(fp
), &st
)) {
252 fprintf(stderr
, "Failed to fstat: %d\n", err
);
255 info
->file_size
= st
.st_size
;
260 if (fread(buf
, 1, sizeof(buf
), fp
) != sizeof(buf
)) {
261 fprintf(stderr
, "Failed to read file header\n");
265 if (be32_to_cpu(chk
->magic
) == 0x2a23245e)
266 info
->vendor_header_size
= be32_to_cpu(chk
->header_len
);
270 for (; info
->vendor_header_size
+ info
->cferom_size
<= info
->file_size
; info
->cferom_size
+= 0x20000) {
271 if (fseek(fp
, info
->vendor_header_size
+ info
->cferom_size
, SEEK_SET
)) {
273 fprintf(stderr
, "Failed to fseek to the 0x%zx\n", info
->cferom_size
);
276 if (fread(&tmp16
, 1, sizeof(tmp16
), fp
) != sizeof(tmp16
)) {
277 fprintf(stderr
, "Failed to read while looking for JFFS2\n");
280 if (be16_to_cpu(tmp16
) == 0x8519)
283 if (info
->vendor_header_size
+ info
->cferom_size
>= info
->file_size
) {
284 fprintf(stderr
, "Failed to find cferom size (no bootfs found)\n");
290 fseek(fp
, info
->vendor_header_size
, SEEK_SET
);
292 info
->crc32
= 0xffffffff;
293 length
= info
->file_size
- info
->vendor_header_size
- sizeof(*tail
);
294 while (length
&& (bytes
= fread(buf
, 1, bcm4908img_min(sizeof(buf
), length
), fp
)) > 0) {
295 info
->crc32
= bcm4908img_crc32(info
->crc32
, buf
, bytes
);
299 fprintf(stderr
, "Failed to read last %zd B of data\n", length
);
305 if (fread(tail
, 1, sizeof(*tail
), fp
) != sizeof(*tail
)) {
306 fprintf(stderr
, "Failed to read BCM4908 image tail\n");
310 /* Standard validation */
312 if (info
->crc32
!= le32_to_cpu(tail
->crc32
)) {
313 fprintf(stderr
, "Invalid data crc32: 0x%08x instead of 0x%08x\n", info
->crc32
, le32_to_cpu(tail
->crc32
));
320 /**************************************************
322 **************************************************/
324 static int bcm4908img_info(int argc
, char **argv
) {
325 struct bcm4908img_info info
;
326 const char *pathname
= NULL
;
331 while ((c
= getopt(argc
, argv
, "i:")) != -1) {
339 fp
= bcm4908img_open(pathname
, "r");
341 fprintf(stderr
, "Failed to open BCM4908 image\n");
346 err
= bcm4908img_parse(fp
, &info
);
348 fprintf(stderr
, "Failed to parse BCM4908 image\n");
352 printf("Vendor header length:\t%zu\n", info
.vendor_header_size
);
353 printf("cferom size:\t0x%zx\n", info
.cferom_size
);
354 printf("Checksum:\t0x%08x\n", info
.crc32
);
357 bcm4908img_close(fp
);
362 /**************************************************
364 **************************************************/
366 static ssize_t
bcm4908img_create_append_file(FILE *trx
, const char *in_path
, uint32_t *crc32
) {
372 in
= fopen(in_path
, "r");
374 fprintf(stderr
, "Failed to open %s\n", in_path
);
378 while ((bytes
= fread(buf
, 1, sizeof(buf
), in
)) > 0) {
379 if (fwrite(buf
, 1, bytes
, trx
) != bytes
) {
380 fprintf(stderr
, "Failed to write %zu B to %s\n", bytes
, pathname
);
384 *crc32
= bcm4908img_crc32(*crc32
, buf
, bytes
);
393 static ssize_t
bcm4908img_create_append_zeros(FILE *trx
, size_t length
) {
396 buf
= malloc(length
);
399 memset(buf
, 0, length
);
401 if (fwrite(buf
, 1, length
, trx
) != length
) {
402 fprintf(stderr
, "Failed to write %zu B to %s\n", length
, pathname
);
412 static ssize_t
bcm4908img_create_align(FILE *trx
, size_t cur_offset
, size_t alignment
) {
413 if (cur_offset
& (alignment
- 1)) {
414 size_t length
= alignment
- (cur_offset
% alignment
);
415 return bcm4908img_create_append_zeros(trx
, length
);
421 static int bcm4908img_create(int argc
, char **argv
) {
422 struct bcm4908img_tail tail
= {
423 .version
= cpu_to_le32(WFI_VERSION
),
424 .chip_id
= cpu_to_le32(0x4908),
425 .flash_type
= cpu_to_le32(WFI_NAND128_FLASH
),
426 .flags
= cpu_to_le32(WFI_FLAG_SUPPORTS_BTRM
),
428 uint32_t crc32
= 0xffffffff;
429 size_t cur_offset
= 0;
436 fprintf(stderr
, "No BCM4908 image pathname passed\n");
442 fp
= fopen(pathname
, "w+");
444 fprintf(stderr
, "Failed to open %s\n", pathname
);
450 while ((c
= getopt(argc
, argv
, "f:a:A:")) != -1) {
453 bytes
= bcm4908img_create_append_file(fp
, optarg
, &crc32
);
455 fprintf(stderr
, "Failed to append file %s\n", optarg
);
461 bytes
= bcm4908img_create_align(fp
, cur_offset
, strtol(optarg
, NULL
, 0));
463 fprintf(stderr
, "Failed to append zeros\n");
468 bytes
= strtol(optarg
, NULL
, 0) - cur_offset
;
470 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));
472 bytes
= bcm4908img_create_append_zeros(fp
, bytes
);
474 fprintf(stderr
, "Failed to append zeros\n");
484 tail
.crc32
= cpu_to_le32(crc32
);
486 bytes
= fwrite(&tail
, 1, sizeof(tail
), fp
);
487 if (bytes
!= sizeof(tail
)) {
488 fprintf(stderr
, "Failed to write BCM4908 image tail to %s\n", pathname
);
498 /**************************************************
500 **************************************************/
502 static int bcm4908img_extract(int argc
, char **argv
) {
503 struct bcm4908img_info info
;
504 const char *pathname
= NULL
;
514 while ((c
= getopt(argc
, argv
, "i:t:")) != -1) {
525 fp
= bcm4908img_open(pathname
, "r");
527 fprintf(stderr
, "Failed to open BCM4908 image\n");
532 err
= bcm4908img_parse(fp
, &info
);
534 fprintf(stderr
, "Failed to parse BCM4908 image\n");
538 if (!strcmp(type
, "cferom")) {
540 length
= info
.cferom_size
;
543 fprintf(stderr
, "This BCM4908 image doesn't contain cferom\n");
546 } else if (!strcmp(type
, "firmware")) {
547 offset
= info
.vendor_header_size
+ info
.cferom_size
;
548 length
= info
.file_size
- offset
- sizeof(struct bcm4908img_tail
);
551 fprintf(stderr
, "Unsupported extract type: %s\n", type
);
557 fprintf(stderr
, "No data to extract specified\n");
561 fseek(fp
, offset
, SEEK_SET
);
562 while (length
&& (bytes
= fread(buf
, 1, bcm4908img_min(sizeof(buf
), length
), fp
)) > 0) {
563 fwrite(buf
, bytes
, 1, stdout
);
568 fprintf(stderr
, "Failed to read last %zd B of data\n", length
);
573 bcm4908img_close(fp
);
578 /**************************************************
580 **************************************************/
582 #define JFFS2_MAGIC_BITMASK 0x1985
584 #define JFFS2_COMPR_NONE 0x00
585 #define JFFS2_COMPR_ZERO 0x01
586 #define JFFS2_COMPR_RTIME 0x02
587 #define JFFS2_COMPR_RUBINMIPS 0x03
588 #define JFFS2_COMPR_COPY 0x04
589 #define JFFS2_COMPR_DYNRUBIN 0x05
590 #define JFFS2_COMPR_ZLIB 0x06
591 #define JFFS2_COMPR_LZO 0x07
592 /* Compatibility flags. */
593 #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */
594 #define JFFS2_NODE_ACCURATE 0x2000
595 /* INCOMPAT: Fail to mount the filesystem */
596 #define JFFS2_FEATURE_INCOMPAT 0xc000
597 /* ROCOMPAT: Mount read-only */
598 #define JFFS2_FEATURE_ROCOMPAT 0x8000
599 /* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */
600 #define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000
601 /* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */
602 #define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000
604 #define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1)
608 } __attribute__((packed
)) jint32_t
;
612 } __attribute__((packed
)) jint16_t
;
614 struct jffs2_unknown_node
616 /* All start like this */
619 jint32_t totlen
; /* So we can skip over nodes we don't grok */
623 struct jffs2_raw_dirent
626 jint16_t nodetype
; /* == JFFS2_NODETYPE_DIRENT */
631 jint32_t ino
; /* == zero for unlink */
641 #define je16_to_cpu(x) ((x).v16)
642 #define je32_to_cpu(x) ((x).v32)
644 static int bcm4908img_bootfs_ls(FILE *fp
, struct bcm4908img_info
*info
) {
645 struct jffs2_unknown_node node
;
646 struct jffs2_raw_dirent dirent
;
651 for (offset
= info
->vendor_header_size
+ info
->cferom_size
; ; offset
+= (je32_to_cpu(node
.totlen
) + 0x03) & ~0x03) {
652 char name
[FILENAME_MAX
+ 1];
654 if (fseek(fp
, offset
, SEEK_SET
)) {
656 fprintf(stderr
, "Failed to fseek: %d\n", err
);
660 bytes
= fread(&node
, 1, sizeof(node
), fp
);
661 if (bytes
!= sizeof(node
)) {
662 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(node
));
666 if (je16_to_cpu(node
.magic
) != JFFS2_MAGIC_BITMASK
) {
670 if (je16_to_cpu(node
.nodetype
) != JFFS2_NODETYPE_DIRENT
) {
674 memcpy(&dirent
, &node
, sizeof(node
));
675 bytes
+= fread((uint8_t *)&dirent
+ sizeof(node
), 1, sizeof(dirent
) - sizeof(node
), fp
);
676 if (bytes
!= sizeof(dirent
)) {
677 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(node
));
681 if (dirent
.nsize
+ 1 > sizeof(name
)) {
682 /* Keep reading & printing BUT exit with error code */
683 fprintf(stderr
, "Too long filename\n");
688 bytes
= fread(name
, 1, dirent
.nsize
, fp
);
689 if (bytes
!= dirent
.nsize
) {
690 fprintf(stderr
, "Failed to read filename\n");
695 printf("%s\n", name
);
701 static int bcm4908img_bootfs_mv(FILE *fp
, struct bcm4908img_info
*info
, int argc
, char **argv
) {
702 struct jffs2_unknown_node node
;
703 struct jffs2_raw_dirent dirent
;
710 if (argc
- optind
< 2) {
711 fprintf(stderr
, "No enough arguments passed\n");
714 oldname
= argv
[optind
++];
715 newname
= argv
[optind
++];
717 if (strlen(newname
) != strlen(oldname
)) {
718 fprintf(stderr
, "New filename must have the same length as the old one\n");
722 for (offset
= info
->vendor_header_size
+ info
->cferom_size
; ; offset
+= (je32_to_cpu(node
.totlen
) + 0x03) & ~0x03) {
723 char name
[FILENAME_MAX
];
726 if (fseek(fp
, offset
, SEEK_SET
)) {
728 fprintf(stderr
, "Failed to fseek: %d\n", err
);
732 bytes
= fread(&node
, 1, sizeof(node
), fp
);
733 if (bytes
!= sizeof(node
)) {
734 fprintf(stderr
, "Failed to read %zu bytes\n", sizeof(node
));
738 if (je16_to_cpu(node
.magic
) != JFFS2_MAGIC_BITMASK
) {
742 if (je16_to_cpu(node
.nodetype
) != JFFS2_NODETYPE_DIRENT
) {
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 fprintf(stderr
, "Too long filename\n");
758 bytes
= fread(name
, 1, dirent
.nsize
, fp
);
759 if (bytes
!= dirent
.nsize
) {
760 fprintf(stderr
, "Failed to read filename\n");
766 printf("offset:%08zx name_crc:%04x filename:%s\n", offset
, je32_to_cpu(dirent
.name_crc
), name
);
768 if (strcmp(name
, oldname
)) {
772 if (fseek(fp
, offset
+ offsetof(struct jffs2_raw_dirent
, name_crc
), SEEK_SET
)) {
774 fprintf(stderr
, "Failed to fseek: %d\n", err
);
777 crc32
= bcm4908img_crc32(0, newname
, dirent
.nsize
);
778 bytes
= fwrite(&crc32
, 1, sizeof(crc32
), fp
);
779 if (bytes
!= sizeof(crc32
)) {
780 fprintf(stderr
, "Failed to write new CRC32\n");
784 if (fseek(fp
, offset
+ offsetof(struct jffs2_raw_dirent
, name
), SEEK_SET
)) {
786 fprintf(stderr
, "Failed to fseek: %d\n", err
);
789 bytes
= fwrite(newname
, 1, dirent
.nsize
, fp
);
790 if (bytes
!= dirent
.nsize
) {
791 fprintf(stderr
, "Failed to write new filename\n");
795 /* Calculate new BCM4908 image checksum */
797 err
= bcm4908img_calc_crc32(fp
, info
);
799 fprintf(stderr
, "Failed to write new filename\n");
803 info
->tail
.crc32
= cpu_to_le32(info
->crc32
);
804 if (fseek(fp
, -sizeof(struct bcm4908img_tail
), SEEK_END
)) {
806 fprintf(stderr
, "Failed to write new filename\n");
810 if (fwrite(&info
->tail
, 1, sizeof(struct bcm4908img_tail
), fp
) != sizeof(struct bcm4908img_tail
)) {
811 fprintf(stderr
, "Failed to write updated tail\n");
815 printf("Successfully renamed %s to the %s\n", oldname
, newname
);
820 fprintf(stderr
, "Failed to find %s\n", oldname
);
825 static int bcm4908img_bootfs(int argc
, char **argv
) {
826 struct bcm4908img_info info
;
827 const char *pathname
= NULL
;
834 while ((c
= getopt(argc
, argv
, "i:")) != -1) {
842 if (argc
- optind
< 1) {
843 fprintf(stderr
, "No bootfs command specified\n");
847 cmd
= argv
[optind
++];
849 mode
= strcmp(cmd
, "mv") ? "r" : "r+";
850 fp
= bcm4908img_open(pathname
, mode
);
852 fprintf(stderr
, "Failed to open BCM4908 image\n");
857 err
= bcm4908img_parse(fp
, &info
);
859 fprintf(stderr
, "Failed to parse BCM4908 image\n");
863 if (!strcmp(cmd
, "ls")) {
864 err
= bcm4908img_bootfs_ls(fp
, &info
);
865 } else if (!strcmp(cmd
, "mv")) {
866 err
= bcm4908img_bootfs_mv(fp
, &info
, argc
, argv
);
869 fprintf(stderr
, "Unsupported bootfs command: %s\n", cmd
);
873 bcm4908img_close(fp
);
878 /**************************************************
880 **************************************************/
882 static void usage() {
885 printf("Info about a BCM4908 image:\n");
886 printf("\tbcm4908img info <options>\n");
887 printf("\t-i <file>\t\t\t\tinput BCM490 image\n");
889 printf("Creating a new BCM4908 image:\n");
890 printf("\tbcm4908img create <file> [options]\n");
891 printf("\t-f file\t\t\t\tadd data from specified file\n");
892 printf("\t-a alignment\t\t\tpad image with zeros to specified alignment\n");
893 printf("\t-A offset\t\t\t\tappend zeros until reaching specified offset\n");
895 printf("Extracting from a BCM4908 image:\n");
896 printf("\tbcm4908img extract <options>\n");
897 printf("\t-i <file>\t\t\t\tinput BCM490 image\n");
898 printf("\t-t <type>\t\t\t\tone of: cferom, bootfs, rootfs, firmware\n");
900 printf("Access bootfs in a BCM4908 image:\n");
901 printf("\tbcm4908img bootfs <options> <command> <arguments>\n");
902 printf("\t-i <file>\t\t\t\tinput BCM490 image\n");
903 printf("\tls\t\t\t\t\tlist bootfs files\n");
904 printf("\tmv <source> <dest>\t\t\trename bootfs file\n");
907 int main(int argc
, char **argv
) {
910 if (!strcmp(argv
[1], "info"))
911 return bcm4908img_info(argc
, argv
);
912 else if (!strcmp(argv
[1], "create"))
913 return bcm4908img_create(argc
, argv
);
914 else if (!strcmp(argv
[1], "extract"))
915 return bcm4908img_extract(argc
, argv
);
916 else if (!strcmp(argv
[1], "bootfs"))
917 return bcm4908img_bootfs(argc
, argv
);