mirror of
https://github.com/openwrt/openwrt.git
synced 2025-01-01 19:46:51 +00:00
26a016731d
Move the zip compression into a build recipe. Pad the image using the existing build recipes as well to remove duplicate functionality Change the code to append header and footer in two steps. Allow to use a fixed filename as the netgear update image does. Use a fixed timestamp within the zip archive to make the images reproducible. Due to the changes we are now compatible to the gnu89 c standard used by default on the buildbots and we don't need to force a more recent standard anymore. Beside all changes, the footer still looks wrong in compare to the netgear update image. Signed-off-by: Mathias Kresin <dev@kresin.me>
262 lines
5.5 KiB
C
262 lines
5.5 KiB
C
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <byteswap.h>
|
|
#include <endian.h>
|
|
#include <getopt.h>
|
|
|
|
#if !defined(__BYTE_ORDER)
|
|
#error "Unknown byte order"
|
|
#endif
|
|
|
|
#if __BYTE_ORDER == __BIG_ENDIAN
|
|
#define cpu_to_be32(x) (x)
|
|
#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
|
#define cpu_to_be32(x) bswap_32(x)
|
|
#else
|
|
#error "Unsupported endianness"
|
|
#endif
|
|
|
|
/* #define DEBUG 1 */
|
|
|
|
#ifdef DEBUG
|
|
#define DBG(...) {printf(__VA_ARGS__); }
|
|
#else
|
|
#define DBG(...) {}
|
|
#endif
|
|
|
|
#define ERR(...) {printf(__VA_ARGS__); }
|
|
|
|
/*
|
|
* Fw Header Layout for Netgear / Sercomm devices (bytes)
|
|
*
|
|
* Size : 512 bytes + zipped image size
|
|
*
|
|
* Locations:
|
|
* magic : 0-6 ASCII
|
|
* version: 7-11 fixed
|
|
* hwID : 11-44 ASCII
|
|
* hwVer : 45-54 ASCII
|
|
* swVer : 55-62 uint32_t in BE
|
|
* magic : 63-69 ASCII
|
|
* ChkSum : 511 Inverse value of the full image checksum while this location is 0x00
|
|
*/
|
|
static const char* magic = "sErCoMm"; /* 7 */
|
|
static const unsigned char version[4] = { 0x00, 0x01, 0x00, 0x00 };
|
|
static const int header_sz = 512;
|
|
static const int footer_sz = 71;
|
|
|
|
static int is_header = 1;
|
|
|
|
struct file_info {
|
|
char* file_name; /* name of the file */
|
|
char* file_data; /* data of the file in memory */
|
|
u_int32_t file_size; /* length of the file */
|
|
};
|
|
|
|
static u_int8_t getCheckSum(char* data, int len) {
|
|
u_int8_t new = 0;
|
|
int i;
|
|
|
|
if (!data) {
|
|
ERR("Invalid pointer provided!\n");
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < len; i++) {
|
|
new += data[i];
|
|
}
|
|
|
|
return new;
|
|
}
|
|
|
|
/*
|
|
* read file into buffer
|
|
* add space for header/footer
|
|
*/
|
|
static int copyToOutputBuf(struct file_info* finfo) {
|
|
FILE* fp = NULL;
|
|
|
|
int file_sz = 0;
|
|
int extra_sz;
|
|
int hdr_pos;
|
|
int img_pos;
|
|
|
|
if (!finfo || !finfo->file_name) {
|
|
ERR("Invalid pointer provided!\n");
|
|
return -1;
|
|
}
|
|
|
|
DBG("Opening file: %s\n", finfo->file_name);
|
|
|
|
if (!(fp = fopen(finfo->file_name, "rb"))) {
|
|
ERR("Error opening file: %s\n", finfo->file_name);
|
|
return -1;
|
|
}
|
|
|
|
/* Get filesize */
|
|
rewind(fp);
|
|
fseek(fp, 0L, SEEK_END);
|
|
file_sz = ftell(fp);
|
|
rewind(fp);
|
|
|
|
if (file_sz < 1) {
|
|
ERR("Error getting filesize: %s\n", finfo->file_name);
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
|
|
if (is_header) {
|
|
extra_sz = header_sz;
|
|
hdr_pos = 0;
|
|
img_pos = header_sz;
|
|
} else {
|
|
extra_sz = footer_sz;
|
|
hdr_pos = file_sz;
|
|
img_pos = 0;
|
|
}
|
|
|
|
DBG("Filesize: %i\n", file_sz);
|
|
finfo->file_size = file_sz + extra_sz;
|
|
|
|
if (!(finfo->file_data = malloc(finfo->file_size))) {
|
|
ERR("Out of memory!\n");
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
|
|
/* init header/footer bytes */
|
|
memset(finfo->file_data + hdr_pos, 0, extra_sz);
|
|
|
|
/* read file and take care of leading header if exists */
|
|
if (fread(finfo->file_data + img_pos, 1, file_sz, fp) != file_sz) {
|
|
ERR("Error reading file %s\n", finfo->file_name);
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
|
|
DBG("File: read successful\n");
|
|
fclose(fp);
|
|
|
|
return hdr_pos;
|
|
}
|
|
|
|
static int writeFile(struct file_info* finfo) {
|
|
FILE* fp;
|
|
|
|
if (!finfo || !finfo->file_name) {
|
|
ERR("Invalid pointer provided!\n");
|
|
return -1;
|
|
}
|
|
|
|
DBG("Opening file: %s\n", finfo->file_name);
|
|
|
|
if (!(fp = fopen(finfo->file_name, "w"))) {
|
|
ERR("Error opening file: %s\n", finfo->file_name);
|
|
return -1;
|
|
}
|
|
|
|
DBG("Writing file: %s\n", finfo->file_name);
|
|
|
|
if (fwrite(finfo->file_data, 1, finfo->file_size, fp) != finfo->file_size) {
|
|
ERR("Wanted to write, but something went wrong!\n");
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
|
|
fclose(fp);
|
|
return 0;
|
|
}
|
|
|
|
static void usage(char* argv[]) {
|
|
printf("Usage: %s [OPTIONS...]\n"
|
|
"\n"
|
|
"Options:\n"
|
|
" -f add sercom footer (if absent, header)\n"
|
|
" -b <hwid> use hardware id specified with <hwid> (ASCII)\n"
|
|
" -r <hwrev> use hardware revision specified with <hwrev> (ASCII)\n"
|
|
" -v <version> set image version to <version> (decimal, hex or octal notation)\n"
|
|
" -i <file> input file\n"
|
|
, argv[0]);
|
|
}
|
|
|
|
int main(int argc, char* argv[]) {
|
|
struct file_info image = { 0 };
|
|
|
|
char* hwID = NULL;
|
|
char* hwVer = NULL;
|
|
u_int32_t swVer = 0;
|
|
u_int8_t chkSum;
|
|
int hdr_offset;
|
|
|
|
while ( 1 ) {
|
|
int c;
|
|
|
|
c = getopt(argc, argv, "b:i:r:v:f");
|
|
if (c == -1)
|
|
break;
|
|
|
|
switch (c) {
|
|
case 'b':
|
|
hwID = optarg;
|
|
break;
|
|
case 'f':
|
|
is_header = 0;
|
|
break;
|
|
case 'i':
|
|
image.file_name = optarg;
|
|
break;
|
|
case 'r':
|
|
hwVer = optarg;
|
|
break;
|
|
case 'v':
|
|
swVer = (u_int32_t) strtol(optarg, NULL, 0);
|
|
swVer = cpu_to_be32(swVer);
|
|
break;
|
|
default:
|
|
usage(argv);
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
if (!hwID || !hwVer || !image.file_name) {
|
|
usage(argv);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* copy input to buffer, add extra space for header/footer and return
|
|
* header position
|
|
*/
|
|
hdr_offset = copyToOutputBuf(&image);
|
|
if (hdr_offset < 0)
|
|
return EXIT_FAILURE;
|
|
|
|
DBG("Filling header: %s %s %2X %s\n", hwID, hwVer, swVer, magic);
|
|
|
|
strncpy(image.file_data + hdr_offset + 0, magic, 7);
|
|
memcpy(image.file_data + hdr_offset + 7, version, sizeof(version));
|
|
strncpy(image.file_data + hdr_offset + 11, hwID, 34);
|
|
strncpy(image.file_data + hdr_offset + 45, hwVer, 10);
|
|
memcpy(image.file_data + hdr_offset + 55, &swVer, sizeof(swVer));
|
|
strncpy(image.file_data + hdr_offset + 63, magic, 7);
|
|
|
|
/* calculate checksum and invert checksum */
|
|
if (is_header) {
|
|
chkSum = getCheckSum(image.file_data, image.file_size);
|
|
chkSum = (chkSum ^ 0xFF) + 1;
|
|
DBG("Checksum for Image: %hhX\n", chkSum);
|
|
|
|
/* write checksum to header */
|
|
image.file_data[511] = (char) chkSum;
|
|
}
|
|
|
|
/* overwrite input file */
|
|
if (writeFile(&image))
|
|
return EXIT_FAILURE;
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|