2 * Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published
6 * by the Free Software Foundation.
14 #include <unistd.h> /* for unlink() */
16 #include <getopt.h> /* for getopt() */
21 #include <arpa/inet.h>
22 #include <netinet/in.h>
24 #define MAX_MODEL_LEN 20
25 #define MAX_SIGNATURE_LEN 30
26 #define MAX_REGION_LEN 4
27 #define MAX_VERSION_LEN 12
29 #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
32 char *file_name
; /* name of the file */
33 uint32_t file_size
; /* length of the file */
41 char model
[MAX_MODEL_LEN
];
42 char signature
[MAX_SIGNATURE_LEN
];
43 char region
[MAX_REGION_LEN
];
44 char version
[MAX_VERSION_LEN
];
45 unsigned char header_len
;
48 } __attribute__ ((packed
));
54 static char *progname
;
57 static char *signature
;
58 static char *region
= "DEF";
60 static struct file_info kernel_info
;
61 static struct file_info rootfs_info
;
62 static uint32_t kernel_size
;
63 static uint32_t image_size
;
69 #define ERR(fmt, ...) do { \
71 fprintf(stderr, "[%s] *** error: " fmt "\n", \
72 progname, ## __VA_ARGS__ ); \
75 #define ERRS(fmt, ...) do { \
78 fprintf(stderr, "[%s] *** error: " fmt " (%s)\n", \
79 progname, ## __VA_ARGS__, strerror(save)); \
82 #define DBG(fmt, ...) do { \
83 fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
86 static void usage(int status
)
88 FILE *stream
= (status
!= EXIT_SUCCESS
) ? stderr
: stdout
;
90 fprintf(stream
, "Usage: %s [OPTIONS...]\n", progname
);
94 " -k <file> read kernel image from the file <file>\n"
95 " -c use the kernel image as a combined image\n"
96 " -M <model> set model to <model>\n"
97 " -o <file> write output to the file <file>\n"
98 " -r <file> read rootfs image from the file <file>\n"
99 " -S <signature> set image signature to <signature>\n"
100 " -R <region> set image region to <region>\n"
101 " -V <version> set image version to <version>\n"
102 " -I <size> set image size to <size>\n"
103 " -K <size> set kernel size to <size>\n"
104 " -h show this screen\n"
111 str2u32(char *arg
, uint32_t *val
)
117 t
= strtoul(arg
, &err
, 0);
118 if (errno
|| (err
==arg
) || ((err
!= NULL
) && *err
)) {
126 static int get_file_stat(struct file_info
*fdata
)
131 if (fdata
->file_name
== NULL
)
134 res
= stat(fdata
->file_name
, &st
);
136 ERRS("stat failed on %s", fdata
->file_name
);
140 fdata
->file_size
= st
.st_size
;
141 fdata
->write_size
= fdata
->file_size
;
145 static int read_to_buf(struct file_info
*fdata
, char *buf
)
148 int ret
= EXIT_FAILURE
;
150 f
= fopen(fdata
->file_name
, "r");
152 ERRS("could not open \"%s\" for reading", fdata
->file_name
);
157 fread(buf
, fdata
->file_size
, 1, f
);
159 ERRS("unable to read from file \"%s\"", fdata
->file_name
);
171 static int check_options(void)
175 #define CHKSTR(_name, _msg) \
177 if (_name == NULL) { \
178 ERR("no %s specified", _msg); \
183 #define CHKSTRLEN(_name, _msg) \
186 CHKSTR(_name, _msg); \
187 field_len = FIELD_SIZEOF(struct img_header, _name) - 1; \
188 if (strlen(_name) > field_len) { \
189 ERR("%s is too long, max length is %d", \
195 CHKSTRLEN(model
, "model");
196 CHKSTRLEN(signature
, "signature");
197 CHKSTRLEN(region
, "region");
198 CHKSTRLEN(version
, "version");
199 CHKSTR(ofname
, "output file");
200 CHKSTR(kernel_info
.file_name
, "kernel image");
202 ret
= get_file_stat(&kernel_info
);
208 ERR("kernel size must be specified for combined images");
213 image_size
= kernel_info
.file_size
;
215 if (kernel_info
.file_size
> image_size
) {
216 ERR("kernel image is too big");
220 kernel_info
.write_size
= image_size
;
222 CHKSTR(rootfs_info
.file_name
, "rootfs image");
224 ret
= get_file_stat(&rootfs_info
);
229 /* override kernel size */
230 kernel_info
.write_size
= kernel_size
;
234 if (image_size
< kernel_info
.write_size
)
235 kernel_info
.write_size
= image_size
;
237 /* override rootfs size */
238 rootfs_info
.write_size
= image_size
- kernel_info
.write_size
;
241 if (kernel_info
.file_size
> kernel_info
.write_size
) {
242 ERR("kernel image is too big");
246 if (rootfs_info
.file_size
> rootfs_info
.write_size
) {
247 ERR("rootfs image is too big");
255 static int write_fw(char *data
, int len
)
258 int ret
= EXIT_FAILURE
;
260 f
= fopen(ofname
, "w");
262 ERRS("could not open \"%s\" for writing", ofname
);
267 fwrite(data
, len
, 1, f
);
269 ERRS("unable to write output file");
273 DBG("firmware file \"%s\" completed", ofname
);
280 if (ret
!= EXIT_SUCCESS
) {
287 static uint32_t get_csum(unsigned char *p
, uint32_t len
)
297 static int build_fw(void)
303 struct img_header
*hdr
;
304 int ret
= EXIT_FAILURE
;
306 buflen
= sizeof(struct img_header
) +
307 kernel_info
.write_size
+ rootfs_info
.write_size
;
309 buf
= malloc(buflen
);
311 ERR("no memory for buffer\n");
315 memset(buf
, 0, buflen
);
317 p
= buf
+ sizeof(struct img_header
);
319 /* read kernel data */
320 ret
= read_to_buf(&kernel_info
, p
);
325 p
+= kernel_info
.write_size
;
327 /* read rootfs data */
328 ret
= read_to_buf(&rootfs_info
, p
);
333 csum
= get_csum((unsigned char *)(buf
+ sizeof(struct img_header
)),
334 buflen
- sizeof(struct img_header
));
336 /* fill firmware header */
337 hdr
= (struct img_header
*) buf
;
339 hdr
->checksum
= htonl(csum
);
340 hdr
->image_size
= htonl(buflen
- sizeof(struct img_header
));
342 hdr
->kernel_size
= htonl(kernel_info
.write_size
);
344 hdr
->kernel_size
= htonl(kernel_size
);
345 hdr
->header_len
= sizeof(struct img_header
);
346 strncpy(hdr
->model
, model
, sizeof(hdr
->model
));
347 strncpy(hdr
->signature
, signature
, sizeof(hdr
->signature
));
348 strncpy(hdr
->version
, version
, sizeof(hdr
->version
));
349 strncpy(hdr
->region
, region
, sizeof(hdr
->region
));
351 ret
= write_fw(buf
, buflen
);
363 int main(int argc
, char *argv
[])
365 int ret
= EXIT_FAILURE
;
367 progname
= basename(argv
[0]);
372 c
= getopt(argc
, argv
, "M:S:V:R:k:K:I:r:o:hc");
390 kernel_info
.file_name
= optarg
;
393 if (str2u32(optarg
, &kernel_size
)) {
394 ERR("%s is invalid '%s'",
395 "kernel size", optarg
);
400 if (str2u32(optarg
, &image_size
)) {
401 ERR("%s is invalid '%s'",
402 "image size", optarg
);
407 rootfs_info
.file_name
= optarg
;
424 ret
= check_options();