tools/firmware-utils: mktplinkfw* fix rootfs offset
[openwrt/openwrt.git] / tools / firmware-utils / src / fix-u-media-header.c
1 /*
2 * Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published
6 * by the Free Software Foundation.
7 *
8 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stdint.h>
12 #include <string.h>
13 #include <unistd.h> /* for unlink() */
14 #include <libgen.h>
15 #include <getopt.h> /* for getopt() */
16 #include <stdarg.h>
17 #include <errno.h>
18 #include <sys/stat.h>
19
20 #include "cyg_crc.h"
21
22 #include <arpa/inet.h>
23 #include <netinet/in.h>
24
25 #define IH_MAGIC 0x27051956 /* Image Magic Number */
26 #define IH_NMLEN 32 /* Image Name Length */
27
28 #define UM_MAGIC 0x55525F46
29 #define UM_HEADER_LEN 12
30
31 /*
32 * all data in network byte order (aka natural aka bigendian)
33 */
34 struct u_media_header {
35 uint32_t ih_magic; /* Image Header Magic Number */
36 uint32_t ih_hcrc; /* Image Header CRC Checksum */
37 uint32_t ih_time; /* Image Creation Timestamp */
38 uint32_t ih_size; /* Image Data Size */
39 uint32_t ih_load; /* Data Load Address */
40 uint32_t ih_ep; /* Entry Point Address */
41 uint32_t ih_dcrc; /* Image Data CRC Checksum */
42 uint8_t ih_os; /* Operating System */
43 uint8_t ih_arch; /* CPU architecture */
44 uint8_t ih_type; /* Image Type */
45 uint8_t ih_comp; /* Compression Type */
46 uint8_t ih_name[IH_NMLEN - UM_HEADER_LEN]; /* Image Name */
47
48 uint32_t ih_UMedia_magic; /* U-Media magic number */
49 uint32_t ih_UMedia_boardID; /* U-Media board ID */
50 uint8_t ih_UMedia_imageType; /* U-Media image type */
51 uint8_t ih_UMedia_LoadDefault; /* U-Media load to factory default setting */
52 uint8_t ih_UMedia_temp1; /* U-Media didn't use this tag */
53 uint8_t ih_UMedia_temp2; /* U-Media didn't use this tag */
54 } __attribute__ ((packed));
55
56 struct if_info {
57 char *file_name; /* name of the file */
58 uint32_t file_size; /* length of the file */
59 };
60
61 static char *progname;
62 static char *ofname;
63 static struct if_info if_info;
64 static int factory_defaults;
65 static uint32_t board_id;
66 static uint8_t image_type;
67
68 /*
69 * Message macros
70 */
71 #define ERR(fmt, ...) do { \
72 fflush(0); \
73 fprintf(stderr, "[%s] *** error: " fmt "\n", \
74 progname, ## __VA_ARGS__ ); \
75 } while (0)
76
77 #define ERRS(fmt, ...) do { \
78 int save = errno; \
79 fflush(0); \
80 fprintf(stderr, "[%s] *** error: " fmt " (%s)\n", \
81 progname, ## __VA_ARGS__, strerror(save)); \
82 } while (0)
83
84 #define DBG(fmt, ...) do { \
85 fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
86 } while (0)
87
88 static void usage(int status)
89 {
90 FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
91
92 fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
93 fprintf(stream,
94 "\n"
95 "Options:\n"
96 " -B <board_id> set board ID to <board_id>\n"
97 " -i <file> read input from the file <file>\n"
98 " -F load factory defaults\n"
99 " -o <file> write output to the file <file>\n"
100 " -T <type> set image type to <type>\n"
101 " -h show this screen\n"
102 );
103
104 exit(status);
105 }
106
107 static int str2u32(char *arg, uint32_t *val)
108 {
109 char *err = NULL;
110 uint32_t t;
111
112 errno=0;
113 t = strtoul(arg, &err, 0);
114 if (errno || (err==arg) || ((err != NULL) && *err)) {
115 return -1;
116 }
117
118 *val = t;
119 return 0;
120 }
121
122 static int str2u8(char *arg, uint8_t *val)
123 {
124 char *err = NULL;
125 uint32_t t;
126
127 errno=0;
128 t = strtoul(arg, &err, 0);
129 if (errno || (err==arg) || ((err != NULL) && *err)) {
130 return -1;
131 }
132
133 if (t > 255)
134 return -1;
135
136 *val = t;
137 return 0;
138 }
139
140 static int get_file_stat(struct if_info *fdata)
141 {
142 struct stat st;
143 int res;
144
145 if (fdata->file_name == NULL)
146 return 0;
147
148 res = stat(fdata->file_name, &st);
149 if (res){
150 ERRS("stat failed on %s", fdata->file_name);
151 return res;
152 }
153
154 fdata->file_size = st.st_size;
155 return 0;
156 }
157
158 static int read_to_buf(struct if_info *fdata, char *buf)
159 {
160 FILE *f;
161 int ret = EXIT_FAILURE;
162
163 f = fopen(fdata->file_name, "r");
164 if (f == NULL) {
165 ERRS("could not open \"%s\" for reading", fdata->file_name);
166 goto out;
167 }
168
169 errno = 0;
170 fread(buf, fdata->file_size, 1, f);
171 if (errno != 0) {
172 ERRS("unable to read from file \"%s\"", fdata->file_name);
173 goto out_close;
174 }
175
176 ret = EXIT_SUCCESS;
177
178 out_close:
179 fclose(f);
180 out:
181 return ret;
182 }
183
184 static int check_options(void)
185 {
186 int ret;
187
188 if (ofname == NULL) {
189 ERR("no %s specified", "output file");
190 return -1;
191 }
192
193 if (if_info.file_name == NULL) {
194 ERR("no %s specified", "input file");
195 return -1;
196 }
197
198 ret = get_file_stat(&if_info);
199 if (ret)
200 return ret;
201
202 return 0;
203 }
204
205 static int write_fw(char *data, int len)
206 {
207 FILE *f;
208 int ret = EXIT_FAILURE;
209
210 f = fopen(ofname, "w");
211 if (f == NULL) {
212 ERRS("could not open \"%s\" for writing", ofname);
213 goto out;
214 }
215
216 errno = 0;
217 fwrite(data, len, 1, f);
218 if (errno) {
219 ERRS("unable to write output file");
220 goto out_flush;
221 }
222
223 ret = EXIT_SUCCESS;
224
225 out_flush:
226 fflush(f);
227 fclose(f);
228 if (ret != EXIT_SUCCESS) {
229 unlink(ofname);
230 }
231 out:
232 return ret;
233 }
234
235 static int fix_header(void)
236 {
237 int buflen;
238 char *buf;
239 uint32_t crc, crc_orig;
240 struct u_media_header *hdr;
241 int ret = EXIT_FAILURE;
242
243 buflen = if_info.file_size;
244 if (buflen < sizeof(*hdr)) {
245 ERR("invalid input file\n");
246 return ret;
247 }
248
249 buf = malloc(buflen);
250 if (!buf) {
251 ERR("no memory for buffer\n");
252 goto out;
253 }
254
255 ret = read_to_buf(&if_info, buf);
256 if (ret)
257 goto out_free_buf;
258
259 hdr = (struct u_media_header *) buf;
260 if (ntohl(hdr->ih_magic) != IH_MAGIC) {
261 ERR("invalid input file, bad magic\n");
262 goto out_free_buf;
263 }
264
265 /* verify header CRC */
266 crc_orig = ntohl(hdr->ih_hcrc);
267 hdr->ih_hcrc = 0;
268 crc = cyg_ether_crc32((unsigned char *)hdr, sizeof(*hdr));
269 if (crc != crc_orig) {
270 ERR("invalid input file, bad header CRC\n");
271 goto out_free_buf;
272 }
273
274 hdr->ih_name[IH_NMLEN - UM_HEADER_LEN - 1] = '\0';
275
276 /* set U-Media specific fields */
277 hdr->ih_UMedia_magic = htonl(UM_MAGIC);
278 hdr->ih_UMedia_boardID = htonl(board_id);
279 hdr->ih_UMedia_imageType = image_type;
280 hdr->ih_UMedia_LoadDefault = (factory_defaults) ? 1 : 0;
281
282 /* update header CRC */
283 crc = cyg_ether_crc32((unsigned char *)hdr, sizeof(*hdr));
284 hdr->ih_hcrc = htonl(crc);
285
286 ret = write_fw(buf, buflen);
287 if (ret)
288 goto out_free_buf;
289
290 DBG("U-Media header fixed in \"%s\"", ofname);
291
292 ret = EXIT_SUCCESS;
293
294 out_free_buf:
295 free(buf);
296 out:
297 return ret;
298 }
299
300 int main(int argc, char *argv[])
301 {
302 int ret = EXIT_FAILURE;
303
304 progname = basename(argv[0]);
305
306 while (1) {
307 int c;
308
309 c = getopt(argc, argv, "B:Fi:o:T:h");
310 if (c == -1)
311 break;
312
313 switch (c) {
314 case 'B':
315 if (str2u32(optarg, &board_id)) {
316 ERR("%s is invalid '%s'",
317 "board ID", optarg);
318 goto out;
319 }
320 break;
321 case 'T':
322 if (str2u8(optarg, &image_type)) {
323 ERR("%s is invalid '%s'",
324 "image type", optarg);
325 goto out;
326 }
327 break;
328 case 'F':
329 factory_defaults = 1;
330 break;
331 case 'i':
332 if_info.file_name = optarg;
333 break;
334 case 'o':
335 ofname = optarg;
336 break;
337 case 'h':
338 usage(EXIT_SUCCESS);
339 break;
340 default:
341 usage(EXIT_FAILURE);
342 break;
343 }
344 }
345
346 ret = check_options();
347 if (ret)
348 goto out;
349
350 ret = fix_header();
351
352 out:
353 return ret;
354 }