OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * |
||
3 | * Copyright (C) 2014 OpenWrt.org |
||
4 | * Copyright (C) 2014 Mikko Hissa <mikko.hissa@werzek.com> |
||
5 | * |
||
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. |
||
9 | * |
||
10 | */ |
||
11 | |||
12 | #include <errno.h> |
||
13 | #include <fcntl.h> |
||
14 | #include <stdio.h> |
||
15 | #include <stdlib.h> |
||
16 | #include <string.h> |
||
17 | #include <netinet/in.h> |
||
18 | #include <sys/mman.h> |
||
19 | #include <sys/stat.h> |
||
20 | #include <unistd.h> |
||
21 | #include <zlib.h> |
||
22 | |||
23 | #define IH_MAGIC 0x27051956 |
||
24 | #define IH_NMLEN 32 |
||
25 | #define IH_PRODLEN 23 |
||
26 | |||
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 |
||
35 | |||
36 | /* |
||
37 | * Compression Types |
||
38 | */ |
||
39 | #define IH_COMP_NONE 0 |
||
40 | #define IH_COMP_GZIP 1 |
||
41 | #define IH_COMP_BZIP2 2 |
||
42 | #define IH_COMP_LZMA 3 |
||
43 | |||
44 | typedef struct { |
||
45 | uint8_t major; |
||
46 | uint8_t minor; |
||
47 | } version_t; |
||
48 | |||
49 | typedef struct { |
||
50 | version_t kernel; |
||
51 | version_t fs; |
||
52 | uint8_t productid[IH_PRODLEN]; |
||
53 | uint8_t sub_fs; |
||
54 | uint32_t ih_ksz; |
||
55 | } asus_t; |
||
56 | |||
57 | typedef struct image_header { |
||
58 | uint32_t ih_magic; |
||
59 | uint32_t ih_hcrc; |
||
60 | uint32_t ih_time; |
||
61 | uint32_t ih_size; |
||
62 | uint32_t ih_load; |
||
63 | uint32_t ih_ep; |
||
64 | uint32_t ih_dcrc; |
||
65 | uint8_t ih_os; |
||
66 | uint8_t ih_arch; |
||
67 | uint8_t ih_type; |
||
68 | uint8_t ih_comp; |
||
69 | union { |
||
70 | uint8_t ih_name[IH_NMLEN]; |
||
71 | asus_t asus; |
||
72 | } tail; |
||
73 | } image_header_t; |
||
74 | |||
75 | typedef struct squashfs_sb { |
||
76 | uint32_t s_magic; |
||
77 | uint32_t pad0[9]; |
||
78 | uint64_t bytes_used; |
||
79 | } squashfs_sb_t; |
||
80 | |||
81 | typedef enum { |
||
82 | NONE, FACTORY, SYSUPGRADE, |
||
83 | } op_mode_t; |
||
84 | |||
85 | void |
||
86 | calc_crc(image_header_t *hdr, void *data, uint32_t len) |
||
87 | { |
||
88 | /* |
||
89 | * Calculate payload checksum |
||
90 | */ |
||
91 | hdr->ih_dcrc = htonl(crc32(0, (Bytef *)data, len)); |
||
92 | hdr->ih_size = htonl(len); |
||
93 | /* |
||
94 | * Calculate header checksum |
||
95 | */ |
||
96 | hdr->ih_hcrc = 0; |
||
97 | hdr->ih_hcrc = htonl(crc32(0, (Bytef *)hdr, sizeof(image_header_t))); |
||
98 | } |
||
99 | |||
100 | |||
101 | static void |
||
102 | usage(const char *progname, int status) |
||
103 | { |
||
104 | FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; |
||
105 | int i; |
||
106 | |||
107 | fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); |
||
108 | fprintf(stream, "\n" |
||
109 | "Options:\n" |
||
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"); |
||
113 | exit(status); |
||
114 | } |
||
115 | |||
116 | int |
||
117 | process_image(char *progname, char *filename, op_mode_t opmode) |
||
118 | { |
||
119 | int fd, len; |
||
120 | void *data, *ptr; |
||
121 | char namebuf[IH_NMLEN]; |
||
122 | struct stat sbuf; |
||
123 | uint32_t checksum, offset_kernel, offset_sqfs, offset_end, |
||
124 | offset_sec_header, offset_eb, offset_image_end; |
||
125 | squashfs_sb_t *sqs; |
||
126 | image_header_t *hdr; |
||
127 | |||
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); |
||
132 | } |
||
133 | |||
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); |
||
138 | } |
||
139 | |||
140 | if ((unsigned)sbuf.st_size < sizeof(image_header_t)) { |
||
141 | fprintf (stderr, |
||
142 | "%s: Bad size: \"%s\" is no valid image\n", |
||
143 | progname, filename); |
||
144 | return (EXIT_FAILURE); |
||
145 | } |
||
146 | |||
147 | ptr = (void *)mmap(0, sbuf.st_size, |
||
148 | PROT_READ | PROT_WRITE, |
||
149 | MAP_SHARED, |
||
150 | fd, 0); |
||
151 | |||
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); |
||
156 | } |
||
157 | |||
158 | hdr = ptr; |
||
159 | |||
160 | if (ntohl(hdr->ih_magic) != IH_MAGIC) { |
||
161 | fprintf (stderr, |
||
162 | "%s: Bad Magic Number: \"%s\" is no valid image\n", |
||
163 | progname, filename); |
||
164 | return (EXIT_FAILURE); |
||
165 | } |
||
166 | |||
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); |
||
174 | } |
||
175 | |||
176 | if (hdr->tail.asus.ih_ksz == 0) |
||
177 | hdr->tail.asus.ih_ksz = htonl(ntohl(hdr->ih_size) + sizeof(image_header_t)); |
||
178 | |||
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; |
||
183 | |||
184 | /* |
||
185 | * Reserve space for the second header. |
||
186 | */ |
||
187 | offset_end = offset_sec_header + sizeof(image_header_t); |
||
188 | offset_eb = ((offset_end>>16)+1)<<16; |
||
189 | |||
190 | if (opmode == FACTORY) |
||
191 | offset_image_end = offset_eb + 4; |
||
192 | else |
||
193 | offset_image_end = sbuf.st_size; |
||
194 | /* |
||
195 | * Move the second header at the end of the image. |
||
196 | */ |
||
197 | offset_end = offset_sec_header; |
||
198 | offset_sec_header = offset_eb - sizeof(image_header_t); |
||
199 | |||
200 | /* |
||
201 | * Remove jffs2 markers between squashfs and eb boundary. |
||
202 | */ |
||
203 | if (opmode == FACTORY) |
||
204 | memset(ptr+offset_end, 0xff ,offset_eb - offset_end); |
||
205 | |||
206 | /* |
||
207 | * Grow the image if needed. |
||
208 | */ |
||
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, |
||
214 | MAP_SHARED, |
||
215 | fd, 0); |
||
216 | /* |
||
217 | * jffs2 marker |
||
218 | */ |
||
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; |
||
224 | } |
||
225 | } |
||
226 | |||
227 | /* |
||
228 | * Calculate checksums for the second header to be used after flashing. |
||
229 | */ |
||
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); |
||
236 | } else { |
||
237 | calc_crc((image_header_t *)ptr, ptr+offset_kernel, offset_sqfs - offset_kernel); |
||
238 | } |
||
239 | |||
240 | if (sbuf.st_size > offset_image_end) |
||
241 | (void) munmap((void *)ptr, sbuf.st_size); |
||
242 | else |
||
243 | (void) munmap((void *)ptr, offset_image_end); |
||
244 | |||
245 | ftruncate(fd, offset_image_end); |
||
246 | (void) close (fd); |
||
247 | |||
248 | return EXIT_SUCCESS; |
||
249 | } |
||
250 | |||
251 | int |
||
252 | main(int argc, char **argv) |
||
253 | { |
||
254 | int opt; |
||
255 | char *filename, *progname; |
||
256 | op_mode_t opmode = NONE; |
||
257 | |||
258 | progname = argv[0]; |
||
259 | |||
260 | while ((opt = getopt(argc, argv,":s:f:h?")) != -1) { |
||
261 | switch (opt) { |
||
262 | case 's': |
||
263 | opmode = SYSUPGRADE; |
||
264 | filename = optarg; |
||
265 | break; |
||
266 | case 'f': |
||
267 | opmode = FACTORY; |
||
268 | filename = optarg; |
||
269 | break; |
||
270 | case 'h': |
||
271 | opmode = NONE; |
||
272 | default: |
||
273 | usage(progname, EXIT_FAILURE); |
||
274 | opmode = NONE; |
||
275 | } |
||
276 | } |
||
277 | |||
278 | if(filename == NULL) |
||
279 | opmode = NONE; |
||
280 | |||
281 | switch (opmode) { |
||
282 | case NONE: |
||
283 | usage(progname, EXIT_FAILURE); |
||
284 | break; |
||
285 | case FACTORY: |
||
286 | case SYSUPGRADE: |
||
287 | return process_image(progname, filename, opmode); |
||
288 | break; |
||
289 | } |
||
290 | |||
291 | return EXIT_SUCCESS; |
||
292 | } |
||
293 |