firmware-utils: replace GPL 2.0 boilerplate/reference with SPDX
[openwrt/staging/ldir.git] / tools / firmware-utils / src / mkplanexfw.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2009 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> /* for unlink() */
11 #include <libgen.h>
12 #include <getopt.h> /* for getopt() */
13 #include <stdarg.h>
14 #include <errno.h>
15 #include <sys/stat.h>
16
17 #include "sha1.h"
18
19 #if (__BYTE_ORDER == __BIG_ENDIAN)
20 # define HOST_TO_BE32(x) (x)
21 # define BE32_TO_HOST(x) (x)
22 #else
23 # define HOST_TO_BE32(x) bswap_32(x)
24 # define BE32_TO_HOST(x) bswap_32(x)
25 #endif
26
27
28 struct planex_hdr {
29 uint8_t sha1sum[20];
30 char version[8];
31 uint8_t unk1[2];
32 uint32_t datalen;
33 } __attribute__ ((packed));
34
35 struct board_info {
36 char *id;
37 uint32_t seed;
38 uint8_t unk[2];
39 uint32_t datalen;
40 };
41
42 /*
43 * Globals
44 */
45 static char *ifname;
46 static char *progname;
47 static char *ofname;
48 static char *version = "1.00.00";
49
50 static char *board_id;
51 static struct board_info *board;
52
53 static struct board_info boards[] = {
54 {
55 .id = "MZK-W04NU",
56 .seed = 2,
57 .unk = {0x04, 0x08},
58 .datalen = 0x770000,
59 }, {
60 .id = "MZK-W300NH",
61 .seed = 4,
62 .unk = {0x00, 0x00},
63 .datalen = 0x770000,
64 }, {
65 /* terminating entry */
66 }
67 };
68
69 /*
70 * Message macros
71 */
72 #define ERR(fmt, ...) do { \
73 fflush(0); \
74 fprintf(stderr, "[%s] *** error: " fmt "\n", \
75 progname, ## __VA_ARGS__ ); \
76 } while (0)
77
78 #define ERRS(fmt, ...) do { \
79 int save = errno; \
80 fflush(0); \
81 fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
82 progname, ## __VA_ARGS__, strerror(save)); \
83 } while (0)
84
85 static struct board_info *find_board(char *id)
86 {
87 struct board_info *ret;
88 struct board_info *board;
89
90 ret = NULL;
91 for (board = boards; board->id != NULL; board++){
92 if (strcasecmp(id, board->id) == 0) {
93 ret = board;
94 break;
95 }
96 };
97
98 return ret;
99 }
100
101 void usage(int status)
102 {
103 FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
104
105 fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
106 fprintf(stream,
107 "\n"
108 "Options:\n"
109 " -B <board> create image for the board specified with <board>\n"
110 " -i <file> read input from the file <file>\n"
111 " -o <file> write output to the file <file>\n"
112 " -v <version> set image version to <version>\n"
113 " -h show this screen\n"
114 );
115
116 exit(status);
117 }
118
119 int main(int argc, char *argv[])
120 {
121 int res = EXIT_FAILURE;
122 int buflen;
123 int err;
124 struct stat st;
125 char *buf;
126 struct planex_hdr *hdr;
127 sha1_context ctx;
128 uint32_t seed;
129
130 FILE *outfile, *infile;
131
132 progname = basename(argv[0]);
133
134 while ( 1 ) {
135 int c;
136
137 c = getopt(argc, argv, "B:i:o:v:h");
138 if (c == -1)
139 break;
140
141 switch (c) {
142 case 'B':
143 board_id = optarg;
144 break;
145 case 'i':
146 ifname = optarg;
147 break;
148 case 'o':
149 ofname = optarg;
150 break;
151 case 'v':
152 version = optarg;
153 break;
154 case 'h':
155 usage(EXIT_SUCCESS);
156 break;
157 default:
158 usage(EXIT_FAILURE);
159 break;
160 }
161 }
162
163 if (board_id == NULL) {
164 ERR("no board specified");
165 goto err;
166 }
167
168 board = find_board(board_id);
169 if (board == NULL) {
170 ERR("unknown board '%s'", board_id);
171 goto err;
172 };
173
174 if (ifname == NULL) {
175 ERR("no input file specified");
176 goto err;
177 }
178
179 if (ofname == NULL) {
180 ERR("no output file specified");
181 goto err;
182 }
183
184 err = stat(ifname, &st);
185 if (err){
186 ERRS("stat failed on %s", ifname);
187 goto err;
188 }
189
190 if (st.st_size > board->datalen) {
191 ERR("file '%s' is too big - max size: 0x%08X (exceeds %lu bytes)\n",
192 ifname, board->datalen, st.st_size - board->datalen);
193 goto err;
194 }
195
196 buflen = board->datalen + 0x10000;
197 buf = malloc(buflen);
198 if (!buf) {
199 ERR("no memory for buffer\n");
200 goto err;
201 }
202
203 memset(buf, 0xff, buflen);
204 hdr = (struct planex_hdr *)buf;
205
206 hdr->datalen = HOST_TO_BE32(board->datalen);
207 hdr->unk1[0] = board->unk[0];
208 hdr->unk1[1] = board->unk[1];
209
210 snprintf(hdr->version, sizeof(hdr->version), "%s", version);
211
212 infile = fopen(ifname, "r");
213 if (infile == NULL) {
214 ERRS("could not open \"%s\" for reading", ifname);
215 goto err_free;
216 }
217
218 errno = 0;
219 fread(buf + sizeof(*hdr), st.st_size, 1, infile);
220 if (errno != 0) {
221 ERRS("unable to read from file %s", ifname);
222 goto err_close_in;
223 }
224
225 seed = HOST_TO_BE32(board->seed);
226 sha1_starts(&ctx);
227 sha1_update(&ctx, (uchar *) &seed, sizeof(seed));
228 sha1_update(&ctx, buf + sizeof(*hdr), board->datalen);
229 sha1_finish(&ctx, hdr->sha1sum);
230
231 outfile = fopen(ofname, "w");
232 if (outfile == NULL) {
233 ERRS("could not open \"%s\" for writing", ofname);
234 goto err_close_in;
235 }
236
237 errno = 0;
238 fwrite(buf, buflen, 1, outfile);
239 if (errno) {
240 ERRS("unable to write to file %s", ofname);
241 goto err_close_out;
242 }
243
244 res = EXIT_SUCCESS;
245
246 fflush(outfile);
247
248 err_close_out:
249 fclose(outfile);
250 if (res != EXIT_SUCCESS) {
251 unlink(ofname);
252 }
253
254 err_close_in:
255 fclose(infile);
256
257 err_free:
258 free(buf);
259
260 err:
261 return res;
262 }
263