1 // SPDX-License-Identifier: GPL-2.0-only
4 * Copyright (C) 2014 OpenWrt.org
5 * Copyright (C) 2014 Mikko Hissa <mikko.hissa@werzek.com>
13 #include <netinet/in.h>
19 #define IH_MAGIC 0x27051956
23 #define IH_TYPE_INVALID 0
24 #define IH_TYPE_STANDALONE 1
25 #define IH_TYPE_KERNEL 2
26 #define IH_TYPE_RAMDISK 3
27 #define IH_TYPE_MULTI 4
28 #define IH_TYPE_FIRMWARE 5
29 #define IH_TYPE_SCRIPT 6
30 #define IH_TYPE_FILESYSTEM 7
35 #define IH_COMP_NONE 0
36 #define IH_COMP_GZIP 1
37 #define IH_COMP_BZIP2 2
38 #define IH_COMP_LZMA 3
48 uint8_t productid
[IH_PRODLEN
];
53 typedef struct image_header
{
66 char ih_name
[IH_NMLEN
];
71 typedef struct squashfs_sb
{
78 NONE
, FACTORY
, SYSUPGRADE
,
82 calc_crc(image_header_t
*hdr
, void *data
, uint32_t len
)
85 * Calculate payload checksum
87 hdr
->ih_dcrc
= htonl(crc32(0, (Bytef
*)data
, len
));
88 hdr
->ih_size
= htonl(len
);
90 * Calculate header checksum
93 hdr
->ih_hcrc
= htonl(crc32(0, (Bytef
*)hdr
, sizeof(image_header_t
)));
98 usage(const char *progname
, int status
)
100 FILE *stream
= (status
!= EXIT_SUCCESS
) ? stderr
: stdout
;
102 fprintf(stream
, "Usage: %s [OPTIONS...]\n", progname
);
105 " -f <file> generate a factory flash image <file>\n"
106 " -s <file> generate a sysupgrade flash image <file>\n"
107 " -h show this screen\n");
112 process_image(char *progname
, char *filename
, op_mode_t opmode
)
116 char namebuf
[IH_NMLEN
];
118 uint32_t offset_kernel
, offset_sqfs
, offset_end
,
119 offset_sec_header
, offset_eb
, offset_image_end
;
123 if ((fd
= open(filename
, O_RDWR
, 0666)) < 0) {
124 fprintf (stderr
, "%s: Can't open %s: %s\n",
125 progname
, filename
, strerror(errno
));
126 return (EXIT_FAILURE
);
129 if (fstat(fd
, &sbuf
) < 0) {
130 fprintf (stderr
, "%s: Can't stat %s: %s\n",
131 progname
, filename
, strerror(errno
));
132 return (EXIT_FAILURE
);
135 if ((unsigned)sbuf
.st_size
< sizeof(image_header_t
)) {
137 "%s: Bad size: \"%s\" is no valid image\n",
139 return (EXIT_FAILURE
);
142 ptr
= (void *)mmap(0, sbuf
.st_size
,
143 PROT_READ
| PROT_WRITE
,
147 if ((caddr_t
)ptr
== (caddr_t
)-1) {
148 fprintf (stderr
, "%s: Can't read %s: %s\n",
149 progname
, filename
, strerror(errno
));
150 return (EXIT_FAILURE
);
155 if (ntohl(hdr
->ih_magic
) != IH_MAGIC
) {
157 "%s: Bad Magic Number: \"%s\" is no valid image\n",
159 return (EXIT_FAILURE
);
162 if (opmode
== FACTORY
) {
163 strncpy(namebuf
, hdr
->tail
.ih_name
, IH_NMLEN
);
164 hdr
->tail
.asus
.kernel
.major
= 0;
165 hdr
->tail
.asus
.kernel
.minor
= 0;
166 hdr
->tail
.asus
.fs
.major
= 0;
167 hdr
->tail
.asus
.fs
.minor
= 0;
168 strncpy((char *)&hdr
->tail
.asus
.productid
, "RT-N56U", IH_PRODLEN
);
171 if (hdr
->tail
.asus
.ih_ksz
== 0)
172 hdr
->tail
.asus
.ih_ksz
= htonl(ntohl(hdr
->ih_size
) + sizeof(image_header_t
));
174 offset_kernel
= sizeof(image_header_t
);
175 offset_sqfs
= ntohl(hdr
->tail
.asus
.ih_ksz
);
176 sqs
= ptr
+ offset_sqfs
;
177 offset_sec_header
= offset_sqfs
+ sqs
->bytes_used
;
180 * Reserve space for the second header.
182 offset_end
= offset_sec_header
+ sizeof(image_header_t
);
183 offset_eb
= ((offset_end
>>16)+1)<<16;
185 if (opmode
== FACTORY
)
186 offset_image_end
= offset_eb
+ 4;
188 offset_image_end
= sbuf
.st_size
;
190 * Move the second header at the end of the image.
192 offset_end
= offset_sec_header
;
193 offset_sec_header
= offset_eb
- sizeof(image_header_t
);
196 * Remove jffs2 markers between squashfs and eb boundary.
198 if (opmode
== FACTORY
)
199 memset(ptr
+offset_end
, 0xff ,offset_eb
- offset_end
);
202 * Grow the image if needed.
204 if (offset_image_end
> sbuf
.st_size
) {
205 (void) munmap((void *)ptr
, sbuf
.st_size
);
206 ftruncate(fd
, offset_image_end
);
207 ptr
= (void *)mmap(0, offset_image_end
,
208 PROT_READ
| PROT_WRITE
,
214 if (opmode
== FACTORY
) {
215 *(uint8_t *)(ptr
+offset_image_end
-4) = 0xde;
216 *(uint8_t *)(ptr
+offset_image_end
-3) = 0xad;
217 *(uint8_t *)(ptr
+offset_image_end
-2) = 0xc0;
218 *(uint8_t *)(ptr
+offset_image_end
-1) = 0xde;
223 * Calculate checksums for the second header to be used after flashing.
225 if (opmode
== FACTORY
) {
226 hdr
= ptr
+offset_sec_header
;
227 memcpy(hdr
, ptr
, sizeof(image_header_t
));
228 strncpy(hdr
->tail
.ih_name
, namebuf
, IH_NMLEN
);
229 calc_crc(hdr
, ptr
+offset_kernel
, offset_sqfs
- offset_kernel
);
230 calc_crc((image_header_t
*)ptr
, ptr
+offset_kernel
, offset_image_end
- offset_kernel
);
232 calc_crc((image_header_t
*)ptr
, ptr
+offset_kernel
, offset_sqfs
- offset_kernel
);
235 if (sbuf
.st_size
> offset_image_end
)
236 (void) munmap((void *)ptr
, sbuf
.st_size
);
238 (void) munmap((void *)ptr
, offset_image_end
);
240 ftruncate(fd
, offset_image_end
);
247 main(int argc
, char **argv
)
250 char *filename
= NULL
;
252 op_mode_t opmode
= NONE
;
256 while ((opt
= getopt(argc
, argv
,":s:f:h?")) != -1) {
269 usage(progname
, EXIT_FAILURE
);
279 usage(progname
, EXIT_FAILURE
);
283 return process_image(progname
, filename
, opmode
);