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