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 uint8_t 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;
107 fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
110 " -f <file> generate a factory flash image <file>\n"
111 " -s <file> generate a sysupgrade flash image <file>\n"
112 " -h show this screen\n");
117 process_image(char *progname, char *filename, op_mode_t opmode)
121 char namebuf[IH_NMLEN];
123 uint32_t checksum, offset_kernel, offset_sqfs, offset_end,
124 offset_sec_header, offset_eb, offset_image_end;
128 if ((fd = open(filename, O_RDWR, 0666)) < 0) {
129 fprintf (stderr, "%s: Can't open %s: %s\n",
130 progname, filename, strerror(errno));
131 return (EXIT_FAILURE);
134 if (fstat(fd, &sbuf) < 0) {
135 fprintf (stderr, "%s: Can't stat %s: %s\n",
136 progname, filename, strerror(errno));
137 return (EXIT_FAILURE);
140 if ((unsigned)sbuf.st_size < sizeof(image_header_t)) {
142 "%s: Bad size: \"%s\" is no valid image\n",
144 return (EXIT_FAILURE);
147 ptr = (void *)mmap(0, sbuf.st_size,
148 PROT_READ | PROT_WRITE,
152 if ((caddr_t)ptr == (caddr_t)-1) {
153 fprintf (stderr, "%s: Can't read %s: %s\n",
154 progname, filename, strerror(errno));
155 return (EXIT_FAILURE);
160 if (ntohl(hdr->ih_magic) != IH_MAGIC) {
162 "%s: Bad Magic Number: \"%s\" is no valid image\n",
164 return (EXIT_FAILURE);
167 if (opmode == FACTORY) {
168 strncpy(namebuf, hdr->tail.ih_name, IH_NMLEN);
169 hdr->tail.asus.kernel.major = 0;
170 hdr->tail.asus.kernel.minor = 0;
171 hdr->tail.asus.fs.major = 0;
172 hdr->tail.asus.fs.minor = 0;
173 strncpy((char *)&hdr->tail.asus.productid, "RT-N56U", IH_PRODLEN);
176 if (hdr->tail.asus.ih_ksz == 0)
177 hdr->tail.asus.ih_ksz = htonl(ntohl(hdr->ih_size) + sizeof(image_header_t));
179 offset_kernel = sizeof(image_header_t);
180 offset_sqfs = ntohl(hdr->tail.asus.ih_ksz);
181 sqs = ptr + offset_sqfs;
182 offset_sec_header = offset_sqfs + sqs->bytes_used;
185 * Reserve space for the second header.
187 offset_end = offset_sec_header + sizeof(image_header_t);
188 offset_eb = ((offset_end>>16)+1)<<16;
190 if (opmode == FACTORY)
191 offset_image_end = offset_eb + 4;
193 offset_image_end = sbuf.st_size;
195 * Move the second header at the end of the image.
197 offset_end = offset_sec_header;
198 offset_sec_header = offset_eb - sizeof(image_header_t);
201 * Remove jffs2 markers between squashfs and eb boundary.
203 if (opmode == FACTORY)
204 memset(ptr+offset_end, 0xff ,offset_eb - offset_end);
207 * Grow the image if needed.
209 if (offset_image_end > sbuf.st_size) {
210 (void) munmap((void *)ptr, sbuf.st_size);
211 ftruncate(fd, offset_image_end);
212 ptr = (void *)mmap(0, offset_image_end,
213 PROT_READ | PROT_WRITE,
219 if (opmode == FACTORY) {
220 *(uint8_t *)(ptr+offset_image_end-4) = 0xde;
221 *(uint8_t *)(ptr+offset_image_end-3) = 0xad;
222 *(uint8_t *)(ptr+offset_image_end-2) = 0xc0;
223 *(uint8_t *)(ptr+offset_image_end-1) = 0xde;
228 * Calculate checksums for the second header to be used after flashing.
230 if (opmode == FACTORY) {
231 hdr = ptr+offset_sec_header;
232 memcpy(hdr, ptr, sizeof(image_header_t));
233 strncpy(hdr->tail.ih_name, namebuf, IH_NMLEN);
234 calc_crc(hdr, ptr+offset_kernel, offset_sqfs - offset_kernel);
235 calc_crc((image_header_t *)ptr, ptr+offset_kernel, offset_image_end - offset_kernel);
237 calc_crc((image_header_t *)ptr, ptr+offset_kernel, offset_sqfs - offset_kernel);
240 if (sbuf.st_size > offset_image_end)
241 (void) munmap((void *)ptr, sbuf.st_size);
243 (void) munmap((void *)ptr, offset_image_end);
245 ftruncate(fd, offset_image_end);
252 main(int argc, char **argv)
255 char *filename, *progname;
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);