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
);
563 int create_zip_file(char *zip_filename
, char *bin_filename
) {
573 // allocate memory for command line
575 buffer
= malloc(buffer_size
);
579 printf("create_zip_file: can not allocate %i bytes\n", (int) buffer_size
);
583 // if buffer was not completely filled, then line fit in completely
584 count
= snprintf(buffer
, buffer_size
, "zip \"%s\" \"%s\"", zip_filename
, bin_filename
);
585 if ((count
> -1) && (count
< buffer_size
)) {
589 // otherwise try again with more space
590 if (count
> -1) { // glibc 2.1
591 buffer_size
= count
+ 1; // precisely what is needed
592 } else { // glibc 2.0
593 buffer_size
*= 2; // twice the old size
597 lprintf(DEBUG_LVL2
, " extending buffer to %i bytes\n", buffer_size
);
602 lprintf(DEBUG
, "%s\n", buffer
);
603 count
= system(buffer
);
604 if ((count
< 0) || (WEXITSTATUS(count
))) {
606 printf("create_zip_file: can not execute %s bytes\n", buffer
);
614 int create_img_file(FILE *f_out
, char *out_filename
, char *zip_filename
) {
618 md5_byte_t digest
[16];
624 unsigned char buffer
[1];
626 // copy firmware version
627 memcpy(&img_hdr
[50], fw_version
, 2);
629 // clear md5 checksum
630 memset(&img_hdr
[480], 0, 16);
632 // prepare md5 checksum calculation
636 lprintf(DEBUG_LVL2
, " adding img header\n");
637 for (i
= 0; i
< 512; i
++) {
638 size
= fputc(img_hdr
[i
], f_out
);
640 exitcode
= ferror(f_out
);
641 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
644 md5_append(&state
, (const md5_byte_t
*)&img_hdr
[i
], 1);
649 lprintf(DEBUG_LVL2
, " adding zip file\n");
650 f_in
= fopen(zip_filename
, "rb");
653 printf("input file %s: %s\n", zip_filename
, strerror(exitcode
));
655 while ((size
= fgetc(f_in
)) != EOF
) {
658 size
= fputc(buffer
[0], f_out
);
660 exitcode
= ferror(f_out
);
661 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
664 md5_append(&state
, (const md5_byte_t
*)buffer
, 1);
667 exitcode
= ferror(f_in
);
668 printf("input file %s: %s\n", zip_filename
, strerror(exitcode
));
676 lprintf(DEBUG_LVL2
, " adding img eof byte\n");
677 size
= fputc(img_eof
[0], f_out
);
679 exitcode
= ferror(f_out
);
680 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
682 md5_append(&state
, (const md5_byte_t
*)img_eof
, 1);
685 // append salt to md5 checksum
686 md5_append(&state
, (const md5_byte_t
*)"A^gU*<>?RFY@#DR&Z", 17);
688 // finish md5 checksum calculation
689 md5_finish(&state
, digest
);
691 // write md5 checksum into img header
693 lprintf(DEBUG_LVL2
, " writing md5 checksum into img header of file\n");
695 size
= fseek(f_out
, 480, SEEK_SET
);
698 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
700 size
= fwrite(digest
, 16, 1, f_out
);
703 exitcode
= ferror(f_out
);
704 printf("output file %s: %s\n", out_filename
, strerror(exitcode
));
707 printf("output file %s: unspecified write error\n", out_filename
);
719 int main(int argc
, char *argv
[]) {
727 char *par_filename
= NULL
;
728 char *img_filename
= NULL
;
729 char *base_filename
= NULL
;
730 char *bin_filename
= NULL
;
731 char *zip_filename
= NULL
;
744 // display program header
745 printf(program_info
, VERSION
);
748 // command line processing
754 while ((option
= getopt(argc
, argv
, "hbzif:v")) != -1) {
769 sizecheck
= sscanf(optarg
, "%i", &i
);
770 if (sizecheck
!= 1) {
771 printf("Firmware version of -f option not a valid integer\n");
774 fw_version
[0] = 0x000000FF & ( i
>> 8 );
775 fw_version
[1] = 0x000000FF & i
;
781 case ':': // option with missing operand
782 printf("Option -%c requires an operand\n", optopt
);
786 printf("Unrecognized option: -%c\n", optopt
);
793 for ( ; optind
< argc
; optind
++) {
795 par_filename
= argv
[optind
];
797 if (access(par_filename
, R_OK
)) {
799 printf("No read access to zip file %s\n", par_filename
);
801 printf("No read access to parameter or zip file %s\n", par_filename
);
809 if ((!onlybin
) && (!img_filename
)) {
810 img_filename
= argv
[optind
];
812 if (!access(img_filename
, F_OK
)) { // if file already exists then check write access
813 if (access(img_filename
, W_OK
)) {
814 printf("No write access to image file %s\n", img_filename
);
822 printf("Too many files stated\n");
830 printf("Zip file not stated\n");
832 printf("Parameter file not stated\n");
836 base_filename
= basename(par_filename
);
837 if (!base_filename
) {
839 printf("Zip file is a directory\n");
841 printf("Parameter file is a directory\n");
849 printf("Image file not stated\n");
852 base_filename
= basename(img_filename
);
853 if (!base_filename
) {
854 printf("Image file is a directory\n");
860 // check for mutually exclusive options
861 if ((onlybin
) && (havezip
)) {
862 printf("Option -b and -z are mutually exclusive\n");
866 // react on option problems or help request, then exit
867 if ((exitcode
) || (help
)) {
869 printf("This program creates Linksys style images for the WRT350Nv2 router.\n");
872 %s [-h] [-b] [-z] [-i] [-f <version>] [-v] <parameter or zip file> [<image file>]\n\n\
874 -h - Show this help\n\
875 -b - Create only bin file, no img or zip file is created\n\
876 -z - Have zip file, the img file will be directly created from it\n\
877 -i - Ignore unknown magic numbers\n\
878 -f <version> - Wanted firmware version to use with -z\n\
879 Default firmware version is 0x2020 = 2.00.20.\n\
880 Note: version from parameter file will supersede this\n\
881 -v - Increase debug verbosity level\n\n\
883 %s wrt350nv2.par wrt350nv2.img\n\n", argv
[0], argv
[0]);
887 // handle special case when zipfile is stated
889 zip_filename
= par_filename
;
893 lprintf(DEBUG_LVL2
, " Verbosity: %i\n", verbosity
);
894 lprintf(DEBUG_LVL2
, " Program: %s\n", argv
[0]);
897 lprintf(DEBUG
, "Parameter file: %s\n", par_filename
);
900 lprintf(DEBUG
, "Zip file: %s\n", zip_filename
);
903 lprintf(DEBUG
, "Image file: %s\n", img_filename
);
907 // open files from command line
908 // parameter/zip file
910 f_par
= fopen(par_filename
, "rt");
913 printf("Input file %s: %s\n", par_filename
, strerror(exitcode
));
919 f_img
= fopen(img_filename
, "wb");
922 printf("Output file %s: %s\n", img_filename
, strerror(exitcode
));
931 // parameter file processing
932 if ((!exitcode
) && (f_par
)) {
933 lprintf(DEBUG
, "parsing parameter file...\n");
935 exitcode
= parse_par_file(f_par
);
937 lprintf(DEBUG
, "...done parsing file\n");
944 // check all input data
945 if ((!exitcode
) && (par_filename
)) {
946 lprintf(DEBUG
, "checking mtd data...\n");
948 for (i
= 1; i
<= 4; i
++) {
956 sizecheck
= ROOTFS_END_OFFSET
;
961 sizecheck
= mtd_kernel
.size
- 16;
966 mtd
->offset
= mtd_kernel
.size
;
967 mtd
->size
= ROOTFS_END_OFFSET
- mtd_kernel
.size
;
968 sizecheck
= PRODUCT_ID_OFFSET
- mtd_kernel
.size
;
973 mtd
->offset
= BOOT_ADDR_BASE_OFF
;
975 sizecheck
= SN_OFF
- BOOT_ADDR_BASE_OFF
;
980 printf("unknown mtd check %i\n", i
);
987 lprintf(DEBUG_LVL2
, " checking mtd %s\n", mtd
->name
);
991 // no further checks if no file data present
992 if (!mtd
->filename
) {
996 // not updated by stock firmware
998 printf("mtd %s is specified, but will not be updated as of Linksys firmware 2.0.19\n", mtd
->name
);
1001 // general magic number check
1008 ((mtd
->magic
[0] == 0x27) && (mtd
->magic
[1] == 0x05)) // uImage
1015 ((mtd
->magic
[0] == 0x68) && (mtd
->magic
[1] == 0x73)) // squashfs
1016 || ((mtd
->magic
[0] == 0x85) && (mtd
->magic
[1] == 0x19)) // jffs
1026 printf("mtd %s input file %s has unknown magic number (0x%02X%02X)", mtd
->name
, mtd
->filename
, mtd
->magic
[0], mtd
->magic
[1]);
1028 printf("...ignoring");
1036 // mtd specific size check
1037 if (mtd
== &mtd_image
) {
1038 if (mtd
->filesize
< 0x00200000) {
1040 printf("mtd %s input file %s too unrealistic small (0x%08lX)\n", mtd
->name
, mtd
->filename
, mtd
->filesize
);
1044 if (mtd
== &mtd_kernel
) {
1045 if (mtd
->filesize
< 0x00080000) {
1047 printf("mtd %s input file %s too unrealistic small (0x%08lX)\n", mtd
->name
, mtd
->filename
, mtd
->filesize
);
1051 // general size check
1053 if (sizecheck
<= 0) {
1055 printf("mtd %s bad file size check (%i) due to input data\n", mtd
->name
, sizecheck
);
1057 if (mtd
->filesize
> sizecheck
) {
1059 printf("mtd %s input file %s too big (0x%08lX)\n", mtd
->name
, mtd
->filename
, mtd
->filesize
);
1065 // Check for mandatory parts
1066 if ((!mtd_image
.filename
) && (!mtd_kernel
.filename
|| !mtd_rootfs
.filename
)) {
1068 if (mtd_kernel
.filename
&& !mtd_rootfs
.filename
) {
1069 printf("Kernel without rootfs, either incorrectly specified or not at all in parameter file\n");
1070 } else if (!mtd_kernel
.filename
&& mtd_rootfs
.filename
) {
1071 printf("Rootfs without kernel, either incorrectly specified or not at all in parameter file\n");
1073 printf("Neither an image nor kernel with rootfs was/were correctly specified or at all in parameter file\n");
1077 // Check for duplicate parts
1078 if ((mtd_image
.filename
) && (mtd_kernel
.filename
|| mtd_rootfs
.filename
)) {
1080 printf("Image and kernel/rootfs specified in parameter file\n");
1083 lprintf(DEBUG
, "...done checking mtd data\n");
1087 // bin creation in memory
1088 if ((!exitcode
) && (par_filename
)) {
1089 bin_filename
= "wrt350n.bin";
1091 lprintf(DEBUG
, "creating bin file %s...\n", bin_filename
);
1093 exitcode
= create_bin_file(bin_filename
);
1095 lprintf(DEBUG
, "...done creating bin file\n");
1098 // zip file creation
1099 if ((!exitcode
) && (!onlybin
) && (!zip_filename
)) {
1100 zip_filename
= "wrt350n.zip";
1102 lprintf(DEBUG
, "creating zip file %s...\n", zip_filename
);
1104 exitcode
= create_zip_file(zip_filename
, bin_filename
);
1106 lprintf(DEBUG
, "...done creating zip file\n");
1110 // img file creation
1111 if ((!exitcode
) && (f_img
)) {
1112 lprintf(DEBUG
, "creating img file...\n");
1114 exitcode
= create_img_file(f_img
, img_filename
, zip_filename
);
1116 lprintf(DEBUG
, "...done creating img file\n");
This page took 0.133607 seconds and 5 git commands to generate.