1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
10 #include <unistd.h> /* for unlink() */
12 #include <getopt.h> /* for getopt() */
17 #include <arpa/inet.h>
18 #include <netinet/in.h>
20 #define MAX_MODEL_LEN 20
21 #define MAX_SIGNATURE_LEN 30
22 #define MAX_REGION_LEN 4
23 #define MAX_VERSION_LEN 12
25 #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
28 char *file_name
; /* name of the file */
29 uint32_t file_size
; /* length of the file */
37 char model
[MAX_MODEL_LEN
];
38 char signature
[MAX_SIGNATURE_LEN
];
39 char region
[MAX_REGION_LEN
];
40 char version
[MAX_VERSION_LEN
];
41 unsigned char header_len
;
44 } __attribute__ ((packed
));
50 static char *progname
;
53 static char *signature
;
54 static char *region
= "DEF";
56 static struct file_info kernel_info
;
57 static struct file_info rootfs_info
;
58 static uint32_t kernel_size
;
59 static uint32_t image_size
;
65 #define ERR(fmt, ...) do { \
67 fprintf(stderr, "[%s] *** error: " fmt "\n", \
68 progname, ## __VA_ARGS__ ); \
71 #define ERRS(fmt, ...) do { \
74 fprintf(stderr, "[%s] *** error: " fmt " (%s)\n", \
75 progname, ## __VA_ARGS__, strerror(save)); \
78 #define DBG(fmt, ...) do { \
79 fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
82 static void usage(int status
)
84 FILE *stream
= (status
!= EXIT_SUCCESS
) ? stderr
: stdout
;
86 fprintf(stream
, "Usage: %s [OPTIONS...]\n", progname
);
90 " -k <file> read kernel image from the file <file>\n"
91 " -c use the kernel image as a combined image\n"
92 " -M <model> set model to <model>\n"
93 " -o <file> write output to the file <file>\n"
94 " -r <file> read rootfs image from the file <file>\n"
95 " -S <signature> set image signature to <signature>\n"
96 " -R <region> set image region to <region>\n"
97 " -V <version> set image version to <version>\n"
98 " -I <size> set image size to <size>\n"
99 " -K <size> set kernel size to <size>\n"
100 " -h show this screen\n"
107 str2u32(char *arg
, uint32_t *val
)
113 t
= strtoul(arg
, &err
, 0);
114 if (errno
|| (err
==arg
) || ((err
!= NULL
) && *err
)) {
122 static int get_file_stat(struct file_info
*fdata
)
127 if (fdata
->file_name
== NULL
)
130 res
= stat(fdata
->file_name
, &st
);
132 ERRS("stat failed on %s", fdata
->file_name
);
136 fdata
->file_size
= st
.st_size
;
137 fdata
->write_size
= fdata
->file_size
;
141 static int read_to_buf(struct file_info
*fdata
, char *buf
)
144 int ret
= EXIT_FAILURE
;
146 f
= fopen(fdata
->file_name
, "r");
148 ERRS("could not open \"%s\" for reading", fdata
->file_name
);
153 fread(buf
, fdata
->file_size
, 1, f
);
155 ERRS("unable to read from file \"%s\"", fdata
->file_name
);
167 static int check_options(void)
171 #define CHKSTR(_name, _msg) \
173 if (_name == NULL) { \
174 ERR("no %s specified", _msg); \
179 #define CHKSTRLEN(_name, _msg) \
182 CHKSTR(_name, _msg); \
183 field_len = FIELD_SIZEOF(struct img_header, _name) - 1; \
184 if (strlen(_name) > field_len) { \
185 ERR("%s is too long, max length is %d", \
191 CHKSTRLEN(model
, "model");
192 CHKSTRLEN(signature
, "signature");
193 CHKSTRLEN(region
, "region");
194 CHKSTRLEN(version
, "version");
195 CHKSTR(ofname
, "output file");
196 CHKSTR(kernel_info
.file_name
, "kernel image");
198 ret
= get_file_stat(&kernel_info
);
204 ERR("kernel size must be specified for combined images");
209 image_size
= kernel_info
.file_size
;
211 if (kernel_info
.file_size
> image_size
) {
212 ERR("kernel image is too big");
216 kernel_info
.write_size
= image_size
;
218 CHKSTR(rootfs_info
.file_name
, "rootfs image");
220 ret
= get_file_stat(&rootfs_info
);
225 /* override kernel size */
226 kernel_info
.write_size
= kernel_size
;
230 if (image_size
< kernel_info
.write_size
)
231 kernel_info
.write_size
= image_size
;
233 /* override rootfs size */
234 rootfs_info
.write_size
= image_size
- kernel_info
.write_size
;
237 if (kernel_info
.file_size
> kernel_info
.write_size
) {
238 ERR("kernel image is too big");
242 if (rootfs_info
.file_size
> rootfs_info
.write_size
) {
243 ERR("rootfs image is too big");
251 static int write_fw(char *data
, int len
)
254 int ret
= EXIT_FAILURE
;
256 f
= fopen(ofname
, "w");
258 ERRS("could not open \"%s\" for writing", ofname
);
263 fwrite(data
, len
, 1, f
);
265 ERRS("unable to write output file");
269 DBG("firmware file \"%s\" completed", ofname
);
276 if (ret
!= EXIT_SUCCESS
) {
283 static uint32_t get_csum(unsigned char *p
, uint32_t len
)
293 static int build_fw(void)
299 struct img_header
*hdr
;
300 int ret
= EXIT_FAILURE
;
302 buflen
= sizeof(struct img_header
) +
303 kernel_info
.write_size
+ rootfs_info
.write_size
;
305 buf
= malloc(buflen
);
307 ERR("no memory for buffer\n");
311 memset(buf
, 0, buflen
);
313 p
= buf
+ sizeof(struct img_header
);
315 /* read kernel data */
316 ret
= read_to_buf(&kernel_info
, p
);
321 p
+= kernel_info
.write_size
;
323 /* read rootfs data */
324 ret
= read_to_buf(&rootfs_info
, p
);
329 csum
= get_csum((unsigned char *)(buf
+ sizeof(struct img_header
)),
330 buflen
- sizeof(struct img_header
));
332 /* fill firmware header */
333 hdr
= (struct img_header
*) buf
;
335 hdr
->checksum
= htonl(csum
);
336 hdr
->image_size
= htonl(buflen
- sizeof(struct img_header
));
338 hdr
->kernel_size
= htonl(kernel_info
.write_size
);
340 hdr
->kernel_size
= htonl(kernel_size
);
341 hdr
->header_len
= sizeof(struct img_header
);
342 strncpy(hdr
->model
, model
, sizeof(hdr
->model
));
343 strncpy(hdr
->signature
, signature
, sizeof(hdr
->signature
));
344 strncpy(hdr
->version
, version
, sizeof(hdr
->version
));
345 strncpy(hdr
->region
, region
, sizeof(hdr
->region
));
347 ret
= write_fw(buf
, buflen
);
359 int main(int argc
, char *argv
[])
361 int ret
= EXIT_FAILURE
;
363 progname
= basename(argv
[0]);
368 c
= getopt(argc
, argv
, "M:S:V:R:k:K:I:r:o:hc");
386 kernel_info
.file_name
= optarg
;
389 if (str2u32(optarg
, &kernel_size
)) {
390 ERR("%s is invalid '%s'",
391 "kernel size", optarg
);
396 if (str2u32(optarg
, &image_size
)) {
397 ERR("%s is invalid '%s'",
398 "image size", optarg
);
403 rootfs_info
.file_name
= optarg
;
420 ret
= check_options();