a224b25b608c5dc95054b150dfe5f26aaacfb773
[openwrt/staging/stintel.git] / tools / firmware-utils / src / mkwrggimg.c
1 /*
2 * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
3 * Copyright (C) 2016 Stijn Tintel <stijn@linux-ipv6.be>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published
7 * by the Free Software Foundation.
8 *
9 */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <stdint.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <libgen.h>
17 #include <getopt.h>
18 #include <stdarg.h>
19 #include <errno.h>
20 #include <sys/stat.h>
21
22 #include "md5.h"
23
24 #define ERR(fmt, ...) do { \
25 fflush(0); \
26 fprintf(stderr, "[%s] *** error: " fmt "\n", \
27 progname, ## __VA_ARGS__ ); \
28 } while (0)
29
30 #define ERRS(fmt, ...) do { \
31 int save = errno; \
32 fflush(0); \
33 fprintf(stderr, "[%s] *** error: " fmt ", %s\n", \
34 progname, ## __VA_ARGS__, strerror(save)); \
35 } while (0)
36
37 #define WRGG03_MAGIC 0x20080321
38
39 struct wrgg03_header {
40 char signature[32];
41 uint32_t magic1;
42 uint32_t magic2;
43 char version[16];
44 char model[16];
45 uint32_t flag[2];
46 uint32_t reserve[2];
47 char buildno[16];
48 uint32_t size;
49 uint32_t offset;
50 char devname[32];
51 char digest[16];
52 } __attribute__ ((packed));
53
54 static char *progname;
55 static char *ifname;
56 static char *ofname;
57 static char *signature;
58 static char *version;
59 static char *model;
60 static uint32_t flag = 0;
61 static uint32_t reserve = 0;
62 static char *buildno;
63 static uint32_t offset;
64 static char *devname;
65 static int big_endian;
66
67 void usage(int status)
68 {
69 FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
70
71 fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
72 fprintf(stream,
73 "\n"
74 "Options:\n"
75 " -b create image in big endian format\n"
76 " -B <buildno> build number\n"
77 " -i <file> read input from the file <file>\n"
78 " -d <name> set device name to <name>\n"
79 " -m <model> model name\n"
80 " -o <file> write output to the file <file>\n"
81 " -O <offset> set offset to <offset>\n"
82 " -s <sig> set image signature to <sig>\n"
83 " -h show this screen\n"
84 );
85
86 exit(status);
87 }
88
89 static void put_u32(void *data, uint32_t val, int swap)
90 {
91 unsigned char *p = data;
92
93 if (swap) {
94 p[0] = (val >> 24) & 0xff;
95 p[1] = (val >> 16) & 0xff;
96 p[2] = (val >> 8) & 0xff;
97 p[3] = val & 0xff;
98 } else {
99 p[3] = (val >> 24) & 0xff;
100 p[2] = (val >> 16) & 0xff;
101 p[1] = (val >> 8) & 0xff;
102 p[0] = val & 0xff;
103 }
104 }
105
106 static void get_digest(struct wrgg03_header *header, char *data, int size)
107 {
108 MD5_CTX ctx;
109
110 MD5_Init(&ctx);
111
112 MD5_Update(&ctx, (char *)&header->offset, sizeof(header->offset));
113 MD5_Update(&ctx, (char *)&header->devname, sizeof(header->devname));
114 MD5_Update(&ctx, data, size);
115
116 MD5_Final(header->digest, &ctx);
117 }
118
119 int main(int argc, char *argv[])
120 {
121 struct wrgg03_header *header;
122 char *buf;
123 struct stat st;
124 int buflen;
125 int err;
126 int res = EXIT_FAILURE;
127
128 FILE *outfile, *infile;
129
130 progname = basename(argv[0]);
131
132 while ( 1 ) {
133 int c;
134
135 c = getopt(argc, argv, "bd:i:m:o:s:v:B:O:h");
136 if (c == -1)
137 break;
138
139 switch (c) {
140 case 'b':
141 big_endian = 1;
142 break;
143 case 'B':
144 buildno = optarg;
145 break;
146 case 'd':
147 devname = optarg;
148 break;
149 case 'i':
150 ifname = optarg;
151 break;
152 case 'm':
153 model = optarg;
154 break;
155 case 'o':
156 ofname = optarg;
157 break;
158 case 's':
159 signature = optarg;
160 break;
161 case 'v':
162 version = optarg;
163 break;
164 case 'O':
165 offset = strtoul(optarg, NULL, 0);
166 break;
167 case 'h':
168 usage(EXIT_SUCCESS);
169 break;
170
171 default:
172 usage(EXIT_FAILURE);
173 break;
174 }
175 }
176
177 if (signature == NULL) {
178 ERR("no signature specified");
179 goto err;
180 }
181
182 if (ifname == NULL) {
183 ERR("no input file specified");
184 goto err;
185 }
186
187 if (ofname == NULL) {
188 ERR("no output file specified");
189 goto err;
190 }
191
192 if (devname == NULL) {
193 ERR("no device name specified");
194 goto err;
195 }
196
197 if (model == NULL) {
198 ERR("no model name specified");
199 goto err;
200 }
201
202 if (buildno == NULL) {
203 ERR("no build number specified");
204 goto err;
205 }
206
207 if (version == NULL) {
208 ERR("no version specified");
209 goto err;
210 }
211
212 err = stat(ifname, &st);
213 if (err){
214 ERRS("stat failed on %s", ifname);
215 goto err;
216 }
217
218 buflen = st.st_size + sizeof(struct wrgg03_header);
219 buf = malloc(buflen);
220 if (!buf) {
221 ERR("no memory for buffer\n");
222 goto err;
223 }
224
225 infile = fopen(ifname, "r");
226 if (infile == NULL) {
227 ERRS("could not open \"%s\" for reading", ifname);
228 goto err_free;
229 }
230
231 errno = 0;
232 fread(buf + sizeof(struct wrgg03_header), st.st_size, 1, infile);
233 if (errno != 0) {
234 ERRS("unable to read from file %s", ifname);
235 goto close_in;
236 }
237
238 header = (struct wrgg03_header *) buf;
239 memset(header, '\0', sizeof(struct wrgg03_header));
240
241 strncpy(header->signature, signature, sizeof(header->signature));
242 put_u32(&header->magic1, WRGG03_MAGIC, 0);
243 put_u32(&header->magic2, WRGG03_MAGIC, 0);
244 strncpy(header->version, version, sizeof(header->version));
245 strncpy(header->model, model, sizeof(header->model));
246 put_u32(&header->flag, flag, 0);
247 put_u32(&header->reserve, reserve, 0);
248 strncpy(header->buildno, buildno, sizeof(header->buildno));
249 put_u32(&header->size, st.st_size, big_endian);
250 put_u32(&header->offset, offset, big_endian);
251 strncpy(header->devname, devname, sizeof(header->devname));
252
253 get_digest(header, buf + sizeof(struct wrgg03_header), st.st_size);
254
255 outfile = fopen(ofname, "w");
256 if (outfile == NULL) {
257 ERRS("could not open \"%s\" for writing", ofname);
258 goto close_in;
259 }
260
261 errno = 0;
262 fwrite(buf, buflen, 1, outfile);
263 if (errno) {
264 ERRS("unable to write to file %s", ofname);
265 goto close_out;
266 }
267
268 fflush(outfile);
269
270 res = EXIT_SUCCESS;
271
272 close_out:
273 fclose(outfile);
274 if (res != EXIT_SUCCESS)
275 unlink(ofname);
276 close_in:
277 fclose(infile);
278 err_free:
279 free(buf);
280 err:
281 return res;
282 }