689dc8b37553841664b38d179674c636dd13613d
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>
23 #define IH_MAGIC 0x27051956
27 #define IH_TYPE_INVALID 0
28 #define IH_TYPE_STANDALONE 1
29 #define IH_TYPE_KERNEL 2
30 #define IH_TYPE_RAMDISK 3
31 #define IH_TYPE_MULTI 4
32 #define IH_TYPE_FIRMWARE 5
33 #define IH_TYPE_SCRIPT 6
34 #define IH_TYPE_FILESYSTEM 7
39 #define IH_COMP_NONE 0
40 #define IH_COMP_GZIP 1
41 #define IH_COMP_BZIP2 2
42 #define IH_COMP_LZMA 3
52 uint8_t productid
[IH_PRODLEN
];
57 typedef struct image_header
{
70 char ih_name
[IH_NMLEN
];
75 typedef struct squashfs_sb
{
82 NONE
, FACTORY
, SYSUPGRADE
,
86 calc_crc(image_header_t
*hdr
, void *data
, uint32_t len
)
89 * Calculate payload checksum
91 hdr
->ih_dcrc
= htonl(crc32(0, (Bytef
*)data
, len
));
92 hdr
->ih_size
= htonl(len
);
94 * Calculate header checksum
97 hdr
->ih_hcrc
= htonl(crc32(0, (Bytef
*)hdr
, sizeof(image_header_t
)));
102 usage(const char *progname
, int status
)
104 FILE *stream
= (status
!= EXIT_SUCCESS
) ? stderr
: stdout
;
106 fprintf(stream
, "Usage: %s [OPTIONS...]\n", progname
);
109 " -f <file> generate a factory flash image <file>\n"
110 " -s <file> generate a sysupgrade flash image <file>\n"
111 " -h show this screen\n");
116 process_image(char *progname
, char *filename
, op_mode_t opmode
)
120 char namebuf
[IH_NMLEN
];
122 uint32_t offset_kernel
, offset_sqfs
, offset_end
,
123 offset_sec_header
, offset_eb
, offset_image_end
;
127 if ((fd
= open(filename
, O_RDWR
, 0666)) < 0) {
128 fprintf (stderr
, "%s: Can't open %s: %s\n",
129 progname
, filename
, strerror(errno
));
130 return (EXIT_FAILURE
);
133 if (fstat(fd
, &sbuf
) < 0) {
134 fprintf (stderr
, "%s: Can't stat %s: %s\n",
135 progname
, filename
, strerror(errno
));
136 return (EXIT_FAILURE
);
139 if ((unsigned)sbuf
.st_size
< sizeof(image_header_t
)) {
141 "%s: Bad size: \"%s\" is no valid image\n",
143 return (EXIT_FAILURE
);
146 ptr
= (void *)mmap(0, sbuf
.st_size
,
147 PROT_READ
| PROT_WRITE
,
151 if ((caddr_t
)ptr
== (caddr_t
)-1) {
152 fprintf (stderr
, "%s: Can't read %s: %s\n",
153 progname
, filename
, strerror(errno
));
154 return (EXIT_FAILURE
);
159 if (ntohl(hdr
->ih_magic
) != IH_MAGIC
) {
161 "%s: Bad Magic Number: \"%s\" is no valid image\n",
163 return (EXIT_FAILURE
);
166 if (opmode
== FACTORY
) {
167 strncpy(namebuf
, hdr
->tail
.ih_name
, IH_NMLEN
);
168 hdr
->tail
.asus
.kernel
.major
= 0;
169 hdr
->tail
.asus
.kernel
.minor
= 0;
170 hdr
->tail
.asus
.fs
.major
= 0;
171 hdr
->tail
.asus
.fs
.minor
= 0;
172 strncpy((char *)&hdr
->tail
.asus
.productid
, "RT-N56U", IH_PRODLEN
);
175 if (hdr
->tail
.asus
.ih_ksz
== 0)
176 hdr
->tail
.asus
.ih_ksz
= htonl(ntohl(hdr
->ih_size
) + sizeof(image_header_t
));
178 offset_kernel
= sizeof(image_header_t
);
179 offset_sqfs
= ntohl(hdr
->tail
.asus
.ih_ksz
);
180 sqs
= ptr
+ offset_sqfs
;
181 offset_sec_header
= offset_sqfs
+ sqs
->bytes_used
;
184 * Reserve space for the second header.
186 offset_end
= offset_sec_header
+ sizeof(image_header_t
);
187 offset_eb
= ((offset_end
>>16)+1)<<16;
189 if (opmode
== FACTORY
)
190 offset_image_end
= offset_eb
+ 4;
192 offset_image_end
= sbuf
.st_size
;
194 * Move the second header at the end of the image.
196 offset_end
= offset_sec_header
;
197 offset_sec_header
= offset_eb
- sizeof(image_header_t
);
200 * Remove jffs2 markers between squashfs and eb boundary.
202 if (opmode
== FACTORY
)
203 memset(ptr
+offset_end
, 0xff ,offset_eb
- offset_end
);
206 * Grow the image if needed.
208 if (offset_image_end
> sbuf
.st_size
) {
209 (void) munmap((void *)ptr
, sbuf
.st_size
);
210 ftruncate(fd
, offset_image_end
);
211 ptr
= (void *)mmap(0, offset_image_end
,
212 PROT_READ
| PROT_WRITE
,
218 if (opmode
== FACTORY
) {
219 *(uint8_t *)(ptr
+offset_image_end
-4) = 0xde;
220 *(uint8_t *)(ptr
+offset_image_end
-3) = 0xad;
221 *(uint8_t *)(ptr
+offset_image_end
-2) = 0xc0;
222 *(uint8_t *)(ptr
+offset_image_end
-1) = 0xde;
227 * Calculate checksums for the second header to be used after flashing.
229 if (opmode
== FACTORY
) {
230 hdr
= ptr
+offset_sec_header
;
231 memcpy(hdr
, ptr
, sizeof(image_header_t
));
232 strncpy(hdr
->tail
.ih_name
, namebuf
, IH_NMLEN
);
233 calc_crc(hdr
, ptr
+offset_kernel
, offset_sqfs
- offset_kernel
);
234 calc_crc((image_header_t
*)ptr
, ptr
+offset_kernel
, offset_image_end
- offset_kernel
);
236 calc_crc((image_header_t
*)ptr
, ptr
+offset_kernel
, offset_sqfs
- offset_kernel
);
239 if (sbuf
.st_size
> offset_image_end
)
240 (void) munmap((void *)ptr
, sbuf
.st_size
);
242 (void) munmap((void *)ptr
, offset_image_end
);
244 ftruncate(fd
, offset_image_end
);
251 main(int argc
, char **argv
)
254 char *filename
= NULL
;
256 op_mode_t opmode
= NONE
;
260 while ((opt
= getopt(argc
, argv
,":s:f:h?")) != -1) {
273 usage(progname
, EXIT_FAILURE
);
283 usage(progname
, EXIT_FAILURE
);
287 return process_image(progname
, filename
, opmode
);