3 * Copyright (C) 2014 OpenWrt.org
4 * Copyright (C) 2014 Mikko Hissa <mikko.hissa@werzek.com>
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published
8 * by the Free Software Foundation.
17 #include <netinet/in.h>
24 #define IH_MAGIC 0x27051956
28 #define IH_TYPE_INVALID 0
29 #define IH_TYPE_STANDALONE 1
30 #define IH_TYPE_KERNEL 2
31 #define IH_TYPE_RAMDISK 3
32 #define IH_TYPE_MULTI 4
33 #define IH_TYPE_FIRMWARE 5
34 #define IH_TYPE_SCRIPT 6
35 #define IH_TYPE_FILESYSTEM 7
40 #define IH_COMP_NONE 0
41 #define IH_COMP_GZIP 1
42 #define IH_COMP_BZIP2 2
43 #define IH_COMP_LZMA 3
53 uint8_t productid
[IH_PRODLEN
];
58 typedef struct image_header
{
71 uint8_t ih_name
[IH_NMLEN
];
76 typedef struct squashfs_sb
{
83 NONE
, FACTORY
, SYSUPGRADE
,
87 calc_crc(image_header_t
*hdr
, void *data
, uint32_t len
)
90 * Calculate payload checksum
92 hdr
->ih_dcrc
= htonl(crc32(0, (Bytef
*)data
, len
));
93 hdr
->ih_size
= htonl(len
);
95 * Calculate header checksum
98 hdr
->ih_hcrc
= htonl(crc32(0, (Bytef
*)hdr
, sizeof(image_header_t
)));
103 usage(const char *progname
, int status
)
105 FILE *stream
= (status
!= EXIT_SUCCESS
) ? stderr
: stdout
;
108 fprintf(stream
, "Usage: %s [OPTIONS...]\n", progname
);
111 " -f <file> generate a factory flash image <file>\n"
112 " -s <file> generate a sysupgrade flash image <file>\n"
113 " -h show this screen\n");
118 process_image(char *progname
, char *filename
, op_mode_t opmode
)
122 char namebuf
[IH_NMLEN
];
124 uint32_t checksum
, offset_kernel
, offset_sqfs
, offset_end
,
125 offset_sec_header
, offset_eb
, offset_image_end
;
129 if ((fd
= open(filename
, O_RDWR
, 0666)) < 0) {
130 fprintf (stderr
, "%s: Can't open %s: %s\n",
131 progname
, filename
, strerror(errno
));
132 return (EXIT_FAILURE
);
135 if (fstat(fd
, &sbuf
) < 0) {
136 fprintf (stderr
, "%s: Can't stat %s: %s\n",
137 progname
, filename
, strerror(errno
));
138 return (EXIT_FAILURE
);
141 if ((unsigned)sbuf
.st_size
< sizeof(image_header_t
)) {
143 "%s: Bad size: \"%s\" is no valid image\n",
145 return (EXIT_FAILURE
);
148 ptr
= (void *)mmap(0, sbuf
.st_size
,
149 PROT_READ
| PROT_WRITE
,
153 if ((caddr_t
)ptr
== (caddr_t
)-1) {
154 fprintf (stderr
, "%s: Can't read %s: %s\n",
155 progname
, filename
, strerror(errno
));
156 return (EXIT_FAILURE
);
161 if (ntohl(hdr
->ih_magic
) != IH_MAGIC
) {
163 "%s: Bad Magic Number: \"%s\" is no valid image\n",
165 return (EXIT_FAILURE
);
168 if (opmode
== FACTORY
) {
169 strncpy(namebuf
, hdr
->tail
.ih_name
, IH_NMLEN
);
170 hdr
->tail
.asus
.kernel
.major
= 0;
171 hdr
->tail
.asus
.kernel
.minor
= 0;
172 hdr
->tail
.asus
.fs
.major
= 0;
173 hdr
->tail
.asus
.fs
.minor
= 0;
174 strncpy((char *)&hdr
->tail
.asus
.productid
, "RT-N56U", IH_PRODLEN
);
177 if (hdr
->tail
.asus
.ih_ksz
== 0)
178 hdr
->tail
.asus
.ih_ksz
= htonl(ntohl(hdr
->ih_size
) + sizeof(image_header_t
));
180 offset_kernel
= sizeof(image_header_t
);
181 offset_sqfs
= ntohl(hdr
->tail
.asus
.ih_ksz
);
182 sqs
= ptr
+ offset_sqfs
;
183 offset_sec_header
= offset_sqfs
+ sqs
->bytes_used
;
186 * Reserve space for the second header.
188 offset_end
= offset_sec_header
+ sizeof(image_header_t
);
189 offset_eb
= ((offset_end
>>16)+1)<<16;
191 if (opmode
== FACTORY
)
192 offset_image_end
= offset_eb
+ 4;
194 offset_image_end
= sbuf
.st_size
;
196 * Move the second header at the end of the image.
198 offset_end
= offset_sec_header
;
199 offset_sec_header
= offset_eb
- sizeof(image_header_t
);
202 * Remove jffs2 markers between squashfs and eb boundary.
204 if (opmode
== FACTORY
)
205 memset(ptr
+offset_end
, 0xff ,offset_eb
- offset_end
);
208 * Grow the image if needed.
210 if (offset_image_end
> sbuf
.st_size
) {
211 (void) munmap((void *)ptr
, sbuf
.st_size
);
212 ftruncate(fd
, offset_image_end
);
213 ptr
= (void *)mmap(0, offset_image_end
,
214 PROT_READ
| PROT_WRITE
,
220 if (opmode
== FACTORY
) {
221 *(uint8_t *)(ptr
+offset_image_end
-4) = 0xde;
222 *(uint8_t *)(ptr
+offset_image_end
-3) = 0xad;
223 *(uint8_t *)(ptr
+offset_image_end
-2) = 0xc0;
224 *(uint8_t *)(ptr
+offset_image_end
-1) = 0xde;
229 * Calculate checksums for the second header to be used after flashing.
231 if (opmode
== FACTORY
) {
232 hdr
= ptr
+offset_sec_header
;
233 memcpy(hdr
, ptr
, sizeof(image_header_t
));
234 strncpy(hdr
->tail
.ih_name
, namebuf
, IH_NMLEN
);
235 calc_crc(hdr
, ptr
+offset_kernel
, offset_sqfs
- offset_kernel
);
236 calc_crc((image_header_t
*)ptr
, ptr
+offset_kernel
, offset_image_end
- offset_kernel
);
238 calc_crc((image_header_t
*)ptr
, ptr
+offset_kernel
, offset_sqfs
- offset_kernel
);
241 if (sbuf
.st_size
> offset_image_end
)
242 (void) munmap((void *)ptr
, sbuf
.st_size
);
244 (void) munmap((void *)ptr
, offset_image_end
);
246 ftruncate(fd
, offset_image_end
);
253 main(int argc
, char **argv
)
256 char *filename
, *progname
;
257 op_mode_t opmode
= NONE
;
261 while ((opt
= getopt(argc
, argv
,":s:f:h?")) != -1) {
274 usage(progname
, EXIT_FAILURE
);
284 usage(progname
, EXIT_FAILURE
);
288 return process_image(progname
, filename
, opmode
);