3 WRT350Nv2-Builder 2.4 (previously called buildimg)
4 Copyright (C) 2008-2009 Dirk Teurlings <info@upexia.nl>
5 Copyright (C) 2009-2011 Matthias Buecher (http://www.maddes.net/)
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 A lot of thanks to Kaloz and juhosg from OpenWRT and Lennert Buytenhek from
22 marvell for helping me figure this one out. This code is based on bash
23 scripts wrote by Peter van Valderen so the real credit should go to him.
25 This program reads the provided parameter file and creates an image which can
26 be used to flash a Linksys WRT350N v2 from stock firmware.
27 The trick is to fill unused space in the bin file with random, so that the
28 resulting zip file passes the size check of the stock firmware.
30 The parameter file layout for an original Linksys firmware:
31 :kernel 0x001A0000 /path/to/uImage
32 :rootfs 0 /path/to/root.squashfs
33 :u-boot 0 /path/to/u-boot.bin
36 Additionally since v2.4 an already complete image can be used:
37 :image 0 /path/to/openwrt-wrt350nv2-[squashfs|jffs2-64k].img
40 1 wrt350nv2.par parameter file describing the image layout
41 2 wrt350nv2.img output file for linksys style image
43 A u-boot image inside the bin file is not necessary.
44 The version is not important.
45 The name of the bin file is not important, but still "wrt350n.bin" is used to
46 keep as close as possible to the stock firmware.
48 Linksys assumes that no mtd will be used to its maximum, so the last 16 bytes
49 of the mtd are abused to define the length of the next mtd content (4 bytes for
52 At the end of "rootfs" additional 16 bytes are abused for some data and a
53 highly important eRcOmM identifier, so the last 32 bytes of "rootfs" are abused.
55 At the end of "u-boot" 128 bytes are abused for some data, a checksum and a
56 highly important sErCoMm identifier.
59 This program uses a special GNU scanf modifier to allocate
60 sufficient memory for a strings with unknown length.
61 See http://www.kernel.org/doc/man-pages/online/pages/man3/scanf.3.html#NOTES
64 To extract everything from a Linksys style firmware image see
65 https://forum.openwrt.org/viewtopic.php?pid=92928#p92928
68 v2.4 - added ":image" definition for parameter file, this allows
69 to use a complete sysupgrade image without any kernel size check
70 v2.3 - allow jffs by adding its magic number (0x8519)
71 added parameter option -i to ignore unknown magic numbers
72 v2.2 - fixed checksum byte calculation for other versions than 0x2019
73 fixed rare problem with padsize
74 updated info to stock firmware 2.00.20
76 v2.1 - used "wrt350n.bin" for the created image (closer to stock)
77 added option to create the image in two separate steps (-b / -z)
78 v2.0 - complete re-write
83 #define _GNU_SOURCE // for GNU's basename()
85 #include <errno.h> // errno
87 #include <stdio.h> // fopen(), fread(), fclose(), etc.
88 #include <stdlib.h> // system(), etc.
89 #include <string.h> // basename(), strerror(), strdup(), etc.
90 #include <unistd.h> // optopt(), access(), etc.
92 #include <sys/wait.h> // WEXITSTATUS, etc.
95 #include "md5.h" // MD5 routines
96 #include "upgrade.h" // Linksys definitions from firmware 2.0.19 (unchanged up to 2.0.20)
100 #define VERSION "2.4"
101 char program_info
[] = "WRT350Nv2-Builder v%s by Dirk Teurlings <info@upexia.nl> and Matthias Buecher (http://www.maddes.net/)\n";
115 unsigned char magic
[2];
118 mtd_info mtd_kernel
= { "kernel", 0, 0, NULL
, 0L, { 0, 0 } };
119 mtd_info mtd_rootfs
= { "rootfs", 0, 0, NULL
, 0L, { 0, 0 } };
120 mtd_info mtd_image
= { "image", 0, 0, NULL
, 0L, { 0, 0 } };
121 mtd_info mtd_uboot
= { "u-boot", 0, 0, NULL
, 0L, { 0, 0 } };
123 #define ROOTFS_END_OFFSET 0x00760000
124 #define ROOTFS_MIN_OFFSET 0x00640000 // should be filled up to here, to make sure that the zip file is big enough to pass the size check of the stock firmware
125 // 2.0.17: filled up to 0x00640000
126 // 2.0.19: filled up to 0x00670000
127 // 2.0.20: filled up to 0x00670000
129 // rootfs statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0x0075FFE0 -n 16 "wrt350n.bin" ; echo -en "\n"
130 unsigned char product_id
[] = { 0x00, 0x03 }; // seems to be a fixed value
131 unsigned char protocol_id
[] = { 0x00, 0x00 }; // seems to be a fixed value
132 unsigned char fw_version
[] = { 0x20, 0x20 };
133 unsigned char rootfs_unknown
[] = { 0x90, 0xF7 }; // seems to be a fixed value
134 unsigned char sign
[] = { 0x65, 0x52, 0x63, 0x4F, 0x6D, 0x4D, 0x00, 0x00 }; // eRcOmM
136 // u-boot statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0x007FFF80 -n 128 "wrt350n.bin" ; echo -en "\n"
137 //unsigned char sn[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // (12) seems to be an unused value
138 //unsigned char pin[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // (8) seems to be an unused value
139 //unsigned char node[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // (25) seems to be an unused value
140 // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
141 //unsigned char checksum[] = { 0xE9 }; // (1) is calculated, does it belong to node?
142 unsigned char pid
[] = { 0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D, 0x00, 0x01, 0x00, 0x00, 0x59, 0x42, 0x50, 0x00, 0x01, // (70) seems to be a fixed value, except for fw version
143 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, // protocol id?
145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, // protocol id?
146 0x12, 0x34, // firmware version, same as in rootfs
147 0x00, 0x00, 0x00, 0x04,
148 0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D }; // sErCoMm
150 // img statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0 -n 512 "WRT350N-EU-ETSI-2.00.19.img" ; echo -en "\n" (unchanged up to 2.0.20)
151 unsigned char img_hdr
[] = { 0x00, 0x01, 0x00, 0x00, 0x59, 0x42, 0x50, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
155 0x12, 0x34, // firmware version, same as in rootfs
156 0x00, 0x00, 0x00, 0x04, 0x61, 0x44, 0x6D, 0x42, 0x6C, 0x4B, 0x3D, 0x00,
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
163 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
166 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
167 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
180 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
181 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
182 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
183 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, // md5 checksum
184 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
186 unsigned char img_eof
[] = { 0xFF };
189 void lprintf(int outputlevel
, char *fmt
, ...) {
191 if (outputlevel
<= verbosity
) {
199 int parse_par_file(FILE *f_par
) {
221 while (!feof(f_par
)) {
222 // read next line into memory
224 // allocate memory for input line
226 buffer
= malloc(buffer_size
);
230 printf("parse_par_file: can not allocate %i bytes\n", (int) buffer_size
);
234 line
= fgets(buffer
, buffer_size
, f_par
);
236 exitcode
= ferror(f_par
);
238 printf("parse_par_file: %s\n", strerror(exitcode
));
243 // if buffer was not completely filled, then assume that line is complete
244 count
= strlen(buffer
) + 1;
245 if (count
-- < buffer_size
) {
251 // reset file position to line start
252 value
= fseek(f_par
, -count
, SEEK_CUR
);
255 printf("parse_par_file: %s\n", strerror(exitcode
));
259 // double buffer size
263 lprintf(DEBUG_LVL2
, " extending buffer to %i bytes\n", buffer_size
);
265 if ((!line
) || (exitcode
)) {
269 lineno
++; // increase line number
271 lprintf(DEBUG_LVL2
, " line %i (%i) %s", lineno
, count
, line
);
276 // split line if starting with a colon
279 count
= sscanf(line
, ":%255s %i %255s", string1
, &value
, string2
);
281 printf("line %i does not meet defined format (:<mtdname> <mtdsize> <file>)\n", lineno
);
283 // populate mtd_info if supported mtd names
284 if (!strcmp(string1
, mtd_kernel
.name
)) {
286 } else if (!strcmp(string1
, mtd_rootfs
.name
)) {
288 } else if (!strcmp(string1
, mtd_uboot
.name
)) {
290 } else if (!strcmp(string1
, mtd_image
.name
)) {
295 printf("unknown mtd %s in line %i\n", string1
, lineno
);
296 } else if (mtd
->filename
) {
298 printf("mtd %s in line %i multiple definitions\n", string1
, lineno
);
301 mtd
->filename
= strdup(string2
);
304 f_in
= fopen(mtd
->filename
, "rb");
307 printf("input file %s: %s\n", mtd
->filename
, strerror(f_exitcode
));
309 value
= fread(&mtd
->magic
, 1, 2, f_in
);
312 f_exitcode
= ferror(f_in
);
313 printf("input file %s: %s\n", mtd
->filename
, strerror(f_exitcode
));
316 printf("input file %s: smaller than two bytes, no magic code\n", mtd
->filename
);
320 value
= fseek(f_in
, 0, SEEK_END
);
323 printf("input file %s: %s\n", mtd
->filename
, strerror(f_exitcode
));
325 mtd
->filesize
= ftell(f_in
);
326 if (mtd
->filesize
== -1) {
328 printf("input file %s: %s\n", mtd
->filename
, strerror(f_exitcode
));
335 lprintf(DEBUG
, "mtd %s in line %i: size=0x%08X, filesize=0x%08lX, magic=0x%02X%02X, file=%s\n", mtd
->name
, lineno
, mtd
->size
, mtd
->filesize
, mtd
->magic
[0], mtd
->magic
[1], mtd
->filename
);
339 case '#': // integer values
340 count
= sscanf(line
, "#%255s %i", string1
, &value
);
342 printf("line %i does not meet defined format (#<variable name> <integer>\n", lineno
);
344 if (!strcmp(string1
, "version")) {
346 fw_version
[0] = 0x000000FF & ( value
>> 8 );
347 fw_version
[1] = 0x000000FF & value
;
349 printf("unknown integer variable %s in line %i\n", string1
, lineno
);
352 lprintf(DEBUG
, "integer variable %s in line %i: 0x%08X\n", string1
, lineno
, value
);
356 count
= sscanf(line
, "$%255s %255s", string1
, string2
);
358 printf("line %i does not meet defined format (:<mtdname> <mtdsize> <file>)\n", lineno
);
361 if (!strcmp(string1, "something")) {
362 something = strdup(string2);
365 printf("unknown string variable %s in line %i\n", string1
, lineno
);
367 lprintf(DEBUG
, "string variable %s in line %i: %s\n", string1
, lineno
, string2
);
377 exitcode
= f_exitcode
;
384 int create_bin_file(char *bin_filename
) {
387 unsigned char *buffer
;
394 char *rand_filename
= "/dev/urandom";
398 unsigned long int csum
;
399 unsigned char checksum
;
403 // allocate memory for bin file
404 buffer
= malloc(KERNEL_CODE_OFFSET
+ FLASH_SIZE
);
407 printf("create_bin_file: can not allocate %i bytes\n", FLASH_SIZE
);
409 // initialize with zero
410 memset(buffer
, 0, KERNEL_CODE_OFFSET
+ FLASH_SIZE
);
415 for (i
= 1; i
<= 4; i
++) {
422 padsize
= ROOTFS_MIN_OFFSET
- mtd
->filesize
;
429 addsize
= mtd
->filesize
;
430 padsize
= ROOTFS_MIN_OFFSET
- mtd_kernel
.size
- mtd
->filesize
;
434 addsize
= mtd
->filesize
;
439 printf("create_bin_file: unknown mtd %i\n", i
);
445 if (!mtd
->filename
) {
449 lprintf(DEBUG
, "adding mtd %s file %s\n", mtd
->name
, mtd
->filename
);
453 buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
- 16] = 0x000000FFL
& ( addsize
>> 24 );
454 buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
- 15] = 0x000000FFL
& ( addsize
>> 16 );
455 buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
- 14] = 0x000000FFL
& ( addsize
>> 8 );
456 buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
- 13] = 0x000000FFL
& addsize
;
459 // adding file content
460 f_in
= fopen(mtd
->filename
, "rb");
463 printf("input file %s: %s\n", mtd
->filename
, strerror(exitcode
));
465 size
= fread(&buffer
[KERNEL_CODE_OFFSET
+ mtd
->offset
], mtd
->filesize
, 1, f_in
);
468 exitcode
= ferror(f_in
);
469 printf("input file %s: %s\n", mtd
->filename
, strerror(exitcode
));
472 printf("input file %s: smaller than before *doh*\n", mtd
->filename
);
480 addsize
= padsize
& 0x0000FFFF; // start on next 64KB border
484 printf("mtd %s input file %s is too small (0x%08lX), adding 0x%08X random bytes\n", mtd
->name
, mtd
->filename
, mtd
->filesize
, padsize
);
486 addsize
+= KERNEL_CODE_OFFSET
+ mtd
->offset
+ mtd
->filesize
; // get offset
487 lprintf(DEBUG
, " padding offset 0x%08X length 0x%08X\n", addsize
, padsize
);
489 f_in
= fopen(rand_filename
, "rb");
492 printf("input file %s: %s\n", rand_filename
, strerror(exitcode
));
494 size
= fread(&buffer
[addsize
], padsize
, 1, f_in
);
497 exitcode
= ferror(f_in
);
498 printf("input file %s: %s\n", rand_filename
, strerror(exitcode
));
501 printf("input file %s: smaller than before *doh*\n", rand_filename
);
510 // add special contents
512 lprintf(DEBUG
, "adding rootfs special data\n");
513 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ PRODUCT_ID_OFFSET
], product_id
, 2);
514 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ PROTOCOL_ID_OFFSET
], protocol_id
, 2);
515 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ FW_VERSION_OFFSET
], fw_version
, 2);
516 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ FW_VERSION_OFFSET
+ 2], rootfs_unknown
, 2);
517 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ SIGN_OFFSET
], sign
, 8); // eRcOmM
519 lprintf(DEBUG
, "adding u-boot special data\n");
520 // memcpy(&buffer[KERNEL_CODE_OFFSET + SN_OFF], sn, 12); // ToDo: currently zero, find out what's this for?
521 // memcpy(&buffer[KERNEL_CODE_OFFSET + PIN_OFF], pin, 8); // ToDo: currently zero, find out what's this for?
522 // memcpy(&buffer[KERNEL_CODE_OFFSET + NODE_BASE_OFF], node, 25); // ToDo: currently zero, find out what's this for?
523 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ BOOT_ADDR_BASE_OFF
+ PID_OFFSET
], pid
, 70); // sErCoMm
524 memcpy(&buffer
[KERNEL_CODE_OFFSET
+ BOOT_ADDR_BASE_OFF
+ PID_OFFSET
+ 57], fw_version
, 2);
526 lprintf(DEBUG
, "adding checksum byte\n");
528 for (i
= 0; i
< KERNEL_CODE_OFFSET
+ FLASH_SIZE
; i
++) {
531 lprintf(DEBUG_LVL2
, " checksum 0x%016lX (%li)\n", csum
, csum
);
533 buffer
[KERNEL_CODE_OFFSET
+ NODE_BASE_OFF
+ 25] = ~csum
+ 1;
534 lprintf(DEBUG
, " byte 0x%02X\n", buffer
[KERNEL_CODE_OFFSET
+ NODE_BASE_OFF
+ 25]);
539 lprintf(DEBUG
, "writing file %s\n", bin_filename
);
540 f_out
= fopen(bin_filename
, "wb");
543 printf("output file %s: %s\n", bin_filename
, strerror(exitcode
));
545 size
= fwrite(buffer
, KERNEL_CODE_OFFSET
+ FLASH_SIZE
, 1, f_out
);
548 exitcode
= ferror(f_out
);
549 printf("output file %s: %s\n", bin_filename
, strerror(exitcode
));
552 printf("output file %s: unspecified write error\n", bin_filename
);
564 int create_zip_file(char *zip_filename
, char *bin_filename
) {
574 // allocate memory for command line
576 buffer
= malloc(buffer_size
);
580 printf("create_zip_file: can not allocate %i bytes\n", (int) buffer_size
);
584 // if buffer was not completely filled, then line fit in completely
585 count
= snprintf(buffer
, buffer_size
, "zip \"%s\" \"%s\"", zip_filename
, bin_filename
);
586 if ((count
> -1) && (count
< buffer_size
)) {
590 // otherwise try again with more space
591 if (count
> -1) { // glibc 2.1
592 buffer_size
= count
+ 1; // precisely what is needed
593 } else { // glibc 2.0
594 buffer_size
*= 2; // twice the old size
598 lprintf(DEBUG_LVL2
, " extending buffer to %i bytes\n", buffer_size
);
603 lprintf(DEBUG
, "%s\n", buffer
);
604 count
= system(buffer
);
605 if ((count
< 0) || (WEXITSTATUS(count
))) {
607 printf("create_zip_file: can not execute %s bytes\n", buffer
);
615 int create_img_file(FILE *f_out
, char *out_filename
, char *zip_filename
) {
619 md5_byte_t digest
[16];
625 unsigned char buffer
[1];
627 // copy firmware version
628 memcpy(&img_hdr
[50], fw_version
, 2);
630 // clear md5 checksum
631 memset(&img_hdr
[480], 0, 16);
633 // prepare md5 checksum calculation
637 lprintf(DEBUG_LVL2
, " adding img header\n");
638 for (i
= 0; i
< 512; i
++) {
639 size
= fputc(img_hdr
[i
], f_out
);
641 exitcode
= ferror(f_out
);
642 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
645 md5_append(&state
, (const md5_byte_t
*)&img_hdr
[i
], 1);
650 lprintf(DEBUG_LVL2
, " adding zip file\n");
651 f_in
= fopen(zip_filename
, "rb");
654 printf("input file %s: %s\n", zip_filename
, strerror(exitcode
));
656 while ((size
= fgetc(f_in
)) != EOF
) {
659 size
= fputc(buffer
[0], f_out
);
661 exitcode
= ferror(f_out
);
662 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
665 md5_append(&state
, (const md5_byte_t
*)buffer
, 1);
668 exitcode
= ferror(f_in
);
669 printf("input file %s: %s\n", zip_filename
, strerror(exitcode
));
677 lprintf(DEBUG_LVL2
, " adding img eof byte\n");
678 size
= fputc(img_eof
[0], f_out
);
680 exitcode
= ferror(f_out
);
681 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
683 md5_append(&state
, (const md5_byte_t
*)img_eof
, 1);
686 // append salt to md5 checksum
687 md5_append(&state
, (const md5_byte_t
*)"A^gU*<>?RFY@#DR&Z", 17);
689 // finish md5 checksum calculation
690 md5_finish(&state
, digest
);
692 // write md5 checksum into img header
694 lprintf(DEBUG_LVL2
, " writing md5 checksum into img header of file\n");
696 size
= fseek(f_out
, 480, SEEK_SET
);
699 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
701 size
= fwrite(digest
, 16, 1, f_out
);
704 exitcode
= ferror(f_out
);
705 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
708 printf("output file %s: unspecified write error\n", out_filename
);
720 int main(int argc
, char *argv
[]) {
728 char *par_filename
= NULL
;
729 char *img_filename
= NULL
;
730 char *base_filename
= NULL
;
731 char *bin_filename
= NULL
;
732 char *zip_filename
= NULL
;
745 // display program header
746 printf(program_info
, VERSION
);
749 // command line processing
755 while ((option
= getopt(argc
, argv
, "hbzif:v")) != -1) {
770 sizecheck
= sscanf(optarg
, "%i", &i
);
771 if (sizecheck
!= 1) {
772 printf("Firmware version of -f option not a valid integer\n");
775 fw_version
[0] = 0x000000FF & ( i
>> 8 );
776 fw_version
[1] = 0x000000FF & i
;
782 case ':': // option with missing operand
783 printf("Option -%c requires an operand\n", optopt
);
787 printf("Unrecognized option: -%c\n", optopt
);
794 for ( ; optind
< argc
; optind
++) {
796 par_filename
= argv
[optind
];
798 if (access(par_filename
, R_OK
)) {
800 printf("No read access to zip file %s\n", par_filename
);
802 printf("No read access to parameter or zip file %s\n", par_filename
);
810 if ((!onlybin
) && (!img_filename
)) {
811 img_filename
= argv
[optind
];
813 if (!access(img_filename
, F_OK
)) { // if file already exists then check write access
814 if (access(img_filename
, W_OK
)) {
815 printf("No write access to image file %s\n", img_filename
);
823 printf("Too many files stated\n");
831 printf("Zip file not stated\n");
833 printf("Parameter file not stated\n");
837 base_filename
= basename(par_filename
);
838 if (!base_filename
) {
840 printf("Zip file is a directory\n");
842 printf("Parameter file is a directory\n");
850 printf("Image file not stated\n");
853 base_filename
= basename(img_filename
);
854 if (!base_filename
) {
855 printf("Image file is a directory\n");
861 // check for mutually exclusive options
862 if ((onlybin
) && (havezip
)) {
863 printf("Option -b and -z are mutually exclusive\n");
867 // react on option problems or help request, then exit
868 if ((exitcode
) || (help
)) {
870 printf("This program creates Linksys style images for the WRT350Nv2 router.\n");
873 %s [-h] [-b] [-z] [-i] [-f <version>] [-v] <parameter or zip file> [<image file>]\n\n\
875 -h - Show this help\n\
876 -b - Create only bin file, no img or zip file is created\n\
877 -z - Have zip file, the img file will be directly created from it\n\
878 -i - Ignore unknown magic numbers\n\
879 -f <version> - Wanted firmware version to use with -z\n\
880 Default firmware version is 0x2020 = 2.00.20.\n\
881 Note: version from parameter file will supersede this\n\
882 -v - Increase debug verbosity level\n\n\
884 %s wrt350nv2.par wrt350nv2.img\n\n", argv
[0], argv
[0]);
888 // handle special case when zipfile is stated
890 zip_filename
= par_filename
;
894 lprintf(DEBUG_LVL2
, " Verbosity: %i\n", verbosity
);
895 lprintf(DEBUG_LVL2
, " Program: %s\n", argv
[0]);
898 lprintf(DEBUG
, "Parameter file: %s\n", par_filename
);
901 lprintf(DEBUG
, "Zip file: %s\n", zip_filename
);
904 lprintf(DEBUG
, "Image file: %s\n", img_filename
);
908 // open files from command line
909 // parameter/zip file
911 f_par
= fopen(par_filename
, "rt");
914 printf("Input file %s: %s\n", par_filename
, strerror(exitcode
));
920 f_img
= fopen(img_filename
, "wb");
923 printf("Output file %s: %s\n", img_filename
, strerror(exitcode
));
932 // parameter file processing
933 if ((!exitcode
) && (f_par
)) {
934 lprintf(DEBUG
, "parsing parameter file...\n");
936 exitcode
= parse_par_file(f_par
);
938 lprintf(DEBUG
, "...done parsing file\n");
945 // check all input data
946 if ((!exitcode
) && (par_filename
)) {
947 lprintf(DEBUG
, "checking mtd data...\n");
949 for (i
= 1; i
<= 4; i
++) {
957 sizecheck
= ROOTFS_END_OFFSET
;
962 sizecheck
= mtd_kernel
.size
- 16;
967 mtd
->offset
= mtd_kernel
.size
;
968 mtd
->size
= ROOTFS_END_OFFSET
- mtd_kernel
.size
;
969 sizecheck
= PRODUCT_ID_OFFSET
- mtd_kernel
.size
;
974 mtd
->offset
= BOOT_ADDR_BASE_OFF
;
976 sizecheck
= SN_OFF
- BOOT_ADDR_BASE_OFF
;
981 printf("unknown mtd check %i\n", i
);
988 lprintf(DEBUG_LVL2
, " checking mtd %s\n", mtd
->name
);
992 // no further checks if no file data present
993 if (!mtd
->filename
) {
997 // not updated by stock firmware
999 printf("mtd %s is specified, but will not be updated as of Linksys firmware 2.0.19\n", mtd
->name
);
1002 // general magic number check
1009 ((mtd
->magic
[0] == 0x27) && (mtd
->magic
[1] == 0x05)) // uImage
1016 ((mtd
->magic
[0] == 0x68) && (mtd
->magic
[1] == 0x73)) // squashfs
1017 || ((mtd
->magic
[0] == 0x85) && (mtd
->magic
[1] == 0x19)) // jffs
1027 printf("mtd %s input file %s has unknown magic number (0x%02X%02X)", mtd
->name
, mtd
->filename
, mtd
->magic
[0], mtd
->magic
[1]);
1029 printf("...ignoring");
1037 // mtd specific size check
1038 if (mtd
== &mtd_image
) {
1039 if (mtd
->filesize
< 0x00200000) {
1041 printf("mtd %s input file %s too unrealistic small (0x%08lX)\n", mtd
->name
, mtd
->filename
, mtd
->filesize
);
1045 if (mtd
== &mtd_kernel
) {
1046 if (mtd
->filesize
< 0x00080000) {
1048 printf("mtd %s input file %s too unrealistic small (0x%08lX)\n", mtd
->name
, mtd
->filename
, mtd
->filesize
);
1052 // general size check
1054 if (sizecheck
<= 0) {
1056 printf("mtd %s bad file size check (%i) due to input data\n", mtd
->name
, sizecheck
);
1058 if (mtd
->filesize
> sizecheck
) {
1060 printf("mtd %s input file %s too big (0x%08lX)\n", mtd
->name
, mtd
->filename
, mtd
->filesize
);
1066 // Check for mandatory parts
1067 if ((!mtd_image
.filename
) && (!mtd_kernel
.filename
|| !mtd_rootfs
.filename
)) {
1069 if (mtd_kernel
.filename
&& !mtd_rootfs
.filename
) {
1070 printf("Kernel without rootfs, either incorrectly specified or not at all in parameter file\n");
1071 } else if (!mtd_kernel
.filename
&& mtd_rootfs
.filename
) {
1072 printf("Rootfs without kernel, either incorrectly specified or not at all in parameter file\n");
1074 printf("Neither an image nor kernel with rootfs was/were correctly specified or at all in parameter file\n");
1078 // Check for duplicate parts
1079 if ((mtd_image
.filename
) && (mtd_kernel
.filename
|| mtd_rootfs
.filename
)) {
1081 printf("Image and kernel/rootfs specified in parameter file\n");
1084 lprintf(DEBUG
, "...done checking mtd data\n");
1088 // bin creation in memory
1089 if ((!exitcode
) && (par_filename
)) {
1090 bin_filename
= "wrt350n.bin";
1092 lprintf(DEBUG
, "creating bin file %s...\n", bin_filename
);
1094 exitcode
= create_bin_file(bin_filename
);
1096 lprintf(DEBUG
, "...done creating bin file\n");
1099 // zip file creation
1100 if ((!exitcode
) && (!onlybin
) && (!zip_filename
)) {
1101 zip_filename
= "wrt350n.zip";
1103 lprintf(DEBUG
, "creating zip file %s...\n", zip_filename
);
1105 exitcode
= create_zip_file(zip_filename
, bin_filename
);
1107 lprintf(DEBUG
, "...done creating zip file\n");
1111 // img file creation
1112 if ((!exitcode
) && (f_img
)) {
1113 lprintf(DEBUG
, "creating img file...\n");
1115 exitcode
= create_img_file(f_img
, img_filename
, zip_filename
);
1117 lprintf(DEBUG
, "...done creating img file\n");