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