firmware-utils: replace GPL 2.0 boilerplate/reference with SPDX
[openwrt/staging/ldir.git] / tools / firmware-utils / src / mkwrgimg.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
4 */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <stdint.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <libgen.h>
12 #include <getopt.h>
13 #include <stdarg.h>
14 #include <errno.h>
15 #include <sys/stat.h>
16
17 #include "md5.h"
18
19 #define ERR(fmt, ...) do { \
20 fflush(0); \
21 fprintf(stderr, "[%s] *** error: " fmt "\n", \
22 progname, ## __VA_ARGS__ ); \
23 } while (0)
24
25 #define ERRS(fmt, ...) do { \
26 int save = errno; \
27 fflush(0); \
28 fprintf(stderr, "[%s] *** error: " fmt ", %s\n", \
29 progname, ## __VA_ARGS__, strerror(save)); \
30 } while (0)
31
32 #define WRG_MAGIC 0x20040220
33
34 struct wrg_header {
35 char signature[32];
36 uint32_t magic1;
37 uint32_t magic2;
38 uint32_t size;
39 uint32_t offset;
40 char devname[32];
41 char digest[16];
42 } __attribute__ ((packed));
43
44 static char *progname;
45 static char *ifname;
46 static char *ofname;
47 static char *signature;
48 static char *dev_name;
49 static uint32_t offset;
50 static int big_endian;
51
52 void usage(int status)
53 {
54 FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
55
56 fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
57 fprintf(stream,
58 "\n"
59 "Options:\n"
60 " -b create image in big endian format\n"
61 " -i <file> read input from the file <file>\n"
62 " -d <name> set device name to <name>\n"
63 " -o <file> write output to the file <file>\n"
64 " -O <offset> set offset to <offset>\n"
65 " -s <sig> set image signature to <sig>\n"
66 " -h show this screen\n"
67 );
68
69 exit(status);
70 }
71
72 static void put_u32(void *data, uint32_t val)
73 {
74 unsigned char *p = data;
75
76 if (big_endian) {
77 p[0] = (val >> 24) & 0xff;
78 p[1] = (val >> 16) & 0xff;
79 p[2] = (val >> 8) & 0xff;
80 p[3] = val & 0xff;
81 } else {
82 p[3] = (val >> 24) & 0xff;
83 p[2] = (val >> 16) & 0xff;
84 p[1] = (val >> 8) & 0xff;
85 p[0] = val & 0xff;
86 }
87 }
88
89 static void get_digest(struct wrg_header *header, char *data, int size)
90 {
91 MD5_CTX ctx;
92
93 MD5_Init(&ctx);
94
95 MD5_Update(&ctx, (char *)&header->offset, sizeof(header->offset));
96 MD5_Update(&ctx, (char *)&header->devname, sizeof(header->devname));
97 MD5_Update(&ctx, data, size);
98
99 MD5_Final((unsigned char *)header->digest, &ctx);
100 }
101
102 int main(int argc, char *argv[])
103 {
104 struct wrg_header *header;
105 char *buf;
106 struct stat st;
107 int buflen;
108 int err;
109 int res = EXIT_FAILURE;
110
111 FILE *outfile, *infile;
112
113 progname = basename(argv[0]);
114
115 while ( 1 ) {
116 int c;
117
118 c = getopt(argc, argv, "bd:i:o:s:O:h");
119 if (c == -1)
120 break;
121
122 switch (c) {
123 case 'b':
124 big_endian = 1;
125 break;
126 case 'd':
127 dev_name = optarg;
128 break;
129 case 'i':
130 ifname = optarg;
131 break;
132 case 'o':
133 ofname = optarg;
134 break;
135 case 's':
136 signature = optarg;
137 break;
138 case 'O':
139 offset = strtoul(optarg, NULL, 0);
140 break;
141 case 'h':
142 usage(EXIT_SUCCESS);
143 break;
144
145 default:
146 usage(EXIT_FAILURE);
147 break;
148 }
149 }
150
151 if (signature == NULL) {
152 ERR("no signature specified");
153 goto err;
154 }
155
156 if (ifname == NULL) {
157 ERR("no input file specified");
158 goto err;
159 }
160
161 if (ofname == NULL) {
162 ERR("no output file specified");
163 goto err;
164 }
165
166 if (dev_name == NULL) {
167 ERR("no device name specified");
168 goto err;
169 }
170
171 err = stat(ifname, &st);
172 if (err){
173 ERRS("stat failed on %s", ifname);
174 goto err;
175 }
176
177 buflen = st.st_size + sizeof(struct wrg_header);
178 buf = malloc(buflen);
179 if (!buf) {
180 ERR("no memory for buffer\n");
181 goto err;
182 }
183
184 infile = fopen(ifname, "r");
185 if (infile == NULL) {
186 ERRS("could not open \"%s\" for reading", ifname);
187 goto err_free;
188 }
189
190 errno = 0;
191 fread(buf + sizeof(struct wrg_header), st.st_size, 1, infile);
192 if (errno != 0) {
193 ERRS("unable to read from file %s", ifname);
194 goto close_in;
195 }
196
197 header = (struct wrg_header *) buf;
198 memset(header, '\0', sizeof(struct wrg_header));
199
200 strncpy(header->signature, signature, sizeof(header->signature));
201 strncpy(header->devname, dev_name, sizeof(header->signature));
202 put_u32(&header->magic1, WRG_MAGIC);
203 put_u32(&header->magic2, WRG_MAGIC);
204 put_u32(&header->size, st.st_size);
205 put_u32(&header->offset, offset);
206
207 get_digest(header, buf + sizeof(struct wrg_header), st.st_size);
208
209 outfile = fopen(ofname, "w");
210 if (outfile == NULL) {
211 ERRS("could not open \"%s\" for writing", ofname);
212 goto close_in;
213 }
214
215 errno = 0;
216 fwrite(buf, buflen, 1, outfile);
217 if (errno) {
218 ERRS("unable to write to file %s", ofname);
219 goto close_out;
220 }
221
222 fflush(outfile);
223
224 res = EXIT_SUCCESS;
225
226 close_out:
227 fclose(outfile);
228 if (res != EXIT_SUCCESS)
229 unlink(ofname);
230 close_in:
231 fclose(infile);
232 err_free:
233 free(buf);
234 err:
235 return res;
236 }