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
;
68 #define ERR(fmt, ...) do { \
70 fprintf(stderr, "[%s] *** error: " fmt "\n", \
71 progname, ## __VA_ARGS__ ); \
74 #define ERRS(fmt, ...) do { \
77 fprintf(stderr, "[%s] *** error: " fmt " (%s)\n", \
78 progname, ## __VA_ARGS__, strerror(save)); \
81 #define DBG(fmt, ...) do { \
82 fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
85 static void usage(int status
)
87 FILE *stream
= (status
!= EXIT_SUCCESS
) ? stderr
: stdout
;
89 fprintf(stream
, "Usage: %s [OPTIONS...]\n", progname
);
93 " -k <file> read kernel image from the file <file>\n"
94 " -M <model> set model to <model>\n"
95 " -o <file> write output to the file <file>\n"
96 " -r <file> read rootfs image from the file <file>\n"
97 " -S <signature> set image signature to <signature>\n"
98 " -R <region> set image region to <region>\n"
99 " -V <version> set image version to <version>\n"
100 " -I <size> set image size to <size>\n"
101 " -K <size> set kernel size to <size>\n"
102 " -h show this screen\n"
109 str2u32(char *arg
, uint32_t *val
)
115 t
= strtoul(arg
, &err
, 0);
116 if (errno
|| (err
==arg
) || ((err
!= NULL
) && *err
)) {
124 static int get_file_stat(struct file_info
*fdata
)
129 if (fdata
->file_name
== NULL
)
132 res
= stat(fdata
->file_name
, &st
);
134 ERRS("stat failed on %s", fdata
->file_name
);
138 fdata
->file_size
= st
.st_size
;
139 fdata
->write_size
= fdata
->file_size
;
143 static int read_to_buf(struct file_info
*fdata
, char *buf
)
146 int ret
= EXIT_FAILURE
;
148 f
= fopen(fdata
->file_name
, "r");
150 ERRS("could not open \"%s\" for reading", fdata
->file_name
);
155 fread(buf
, fdata
->file_size
, 1, f
);
157 ERRS("unable to read from file \"%s\"", fdata
->file_name
);
169 static int check_options(void)
173 #define CHKSTR(_name, _msg) \
175 if (_name == NULL) { \
176 ERR("no %s specified", _msg); \
181 #define CHKSTRLEN(_name, _msg) \
184 CHKSTR(_name, _msg); \
185 field_len = FIELD_SIZEOF(struct img_header, _name) - 1; \
186 if (strlen(_name) > field_len) { \
187 ERR("%s is too long, max length is %d", \
193 CHKSTRLEN(model
, "model");
194 CHKSTRLEN(signature
, "signature");
195 CHKSTRLEN(region
, "region");
196 CHKSTRLEN(version
, "version");
197 CHKSTR(ofname
, "output file");
198 CHKSTR(kernel_info
.file_name
, "kernel image");
199 CHKSTR(rootfs_info
.file_name
, "rootfs image");
201 ret
= get_file_stat(&kernel_info
);
205 ret
= get_file_stat(&rootfs_info
);
210 /* override kernel size */
211 kernel_info
.write_size
= kernel_size
;
215 if (image_size
< kernel_info
.write_size
)
216 kernel_info
.write_size
= image_size
;
218 /* override rootfs size */
219 rootfs_info
.write_size
= image_size
- kernel_info
.write_size
;
222 if (kernel_info
.file_size
> kernel_info
.write_size
) {
223 ERR("kernel image is too big");
227 if (rootfs_info
.file_size
> rootfs_info
.write_size
) {
228 ERR("rootfs image is too big");
235 static int write_fw(char *data
, int len
)
238 int ret
= EXIT_FAILURE
;
240 f
= fopen(ofname
, "w");
242 ERRS("could not open \"%s\" for writing", ofname
);
247 fwrite(data
, len
, 1, f
);
249 ERRS("unable to write output file");
253 DBG("firmware file \"%s\" completed", ofname
);
260 if (ret
!= EXIT_SUCCESS
) {
267 static uint32_t get_csum(unsigned char *p
, uint32_t len
)
277 static int build_fw(void)
283 struct img_header
*hdr
;
284 int ret
= EXIT_FAILURE
;
286 buflen
= sizeof(struct img_header
) +
287 kernel_info
.write_size
+ rootfs_info
.write_size
;
289 buf
= malloc(buflen
);
291 ERR("no memory for buffer\n");
295 memset(buf
, 0, buflen
);
297 p
= buf
+ sizeof(struct img_header
);
299 /* read kernel data */
300 ret
= read_to_buf(&kernel_info
, p
);
304 p
+= kernel_info
.write_size
;
306 /* read rootfs data */
307 ret
= read_to_buf(&rootfs_info
, p
);
311 csum
= get_csum((unsigned char *)(buf
+ sizeof(struct img_header
)),
312 buflen
- sizeof(struct img_header
));
314 /* fill firmware header */
315 hdr
= (struct img_header
*) buf
;
317 hdr
->checksum
= htonl(csum
);
318 hdr
->image_size
= htonl(buflen
- sizeof(struct img_header
));
319 hdr
->kernel_size
= htonl(kernel_info
.write_size
);
320 hdr
->header_len
= sizeof(struct img_header
);
321 strncpy(hdr
->model
, model
, sizeof(hdr
->model
));
322 strncpy(hdr
->signature
, signature
, sizeof(hdr
->signature
));
323 strncpy(hdr
->version
, version
, sizeof(hdr
->version
));
324 strncpy(hdr
->region
, region
, sizeof(hdr
->region
));
326 ret
= write_fw(buf
, buflen
);
338 int main(int argc
, char *argv
[])
340 int ret
= EXIT_FAILURE
;
342 progname
= basename(argv
[0]);
347 c
= getopt(argc
, argv
, "M:S:V:R:k:K:I:r:o:h");
365 kernel_info
.file_name
= optarg
;
368 if (str2u32(optarg
, &kernel_size
)) {
369 ERR("%s is invalid '%s'",
370 "kernel size", optarg
);
375 if (str2u32(optarg
, &image_size
)) {
376 ERR("%s is invalid '%s'",
377 "image size", optarg
);
382 rootfs_info
.file_name
= optarg
;
396 ret
= check_options();