ramips: fix netgear r6120 factory image generation
[openwrt/openwrt.git] / tools / firmware-utils / src / mksercommfw.c
index ccd5d67a87dc85c5accb80e96c440f5a01fc4be0..e3b499a097d97343c60fde880ca63619feb4b6d7 100644 (file)
 #include <string.h>
 #include <stdlib.h>
 #include <sys/types.h>
+#include <unistd.h>
+#include <asm/byteorder.h>
 
 /* #define DEBUG 1 */
 
-/*
- * Fw Header Layout for Netgear / Sercomm devices
- * */
-static const char *magic = "sErCoMm"; /* 7 */
-/* 7-11: version control/download control ? */
-unsigned char version[4] = {0x00, 0x01, 0x00, 0x00};
-char *hwID = ""; /* 11-43 , ASCII/HEX */
-char *hwVer = ""; /* 44-57 , ASCII/HEX */
-char *swVer = ""; /* 58-62 , ASCII/HEX */
-/* magic again. */
+#ifdef DEBUG
+#define DBG(...) {printf(__VA_ARGS__); }
+#else
+#define DBG(...) {}
+#endif
 
+#define ERR(...) {printf(__VA_ARGS__); }
+#define ALIGN(a,b) ((a) + ((b) - ((a) % (b))))
+#define ROOTFS_ALIGN 128
 #define HEADER_SIZE 71
 
-/* null bytes until 511 */
-u_int32_t checksum = 0xFF; /* checksum */
-/* 512 onwards -> ZIP containing rootfs with the same Header */
+/*
+ * 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 */
 
+/* 7-11: version control/download control ? */
+static const unsigned char version[4] = { 0x00, 0x01, 0x00, 0x00 };
 
-/* appended on rootfs for the Header. */
-const int footer_size = 128;
+
+/* 512 onwards -> ZIP containing rootfs with the same Header */
 
 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 */
+       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 */
 };
 
-u_int8_t getCheckSum(char *data, int len)
-{
+static u_int8_t getCheckSum(char* data, int len) {
+       u_int8_t new = 0;
 
-       int32_t previous = 0;
-       u_int32_t new = 0;
+       if (!data) {
+               ERR("Invalid pointer provided!\n");
+               return 0;
+       }
 
-       for (u_int32_t i = 0; i < len; i++) {
-               new = (data[i] + previous) % 256;
-               previous = new | previous & -256;
+       for (int i = 0; i < len; i++) {
+               new += data[i];
        }
-       return (u_int8_t) new;
+
+       return new;
 }
 
-void *bufferFile(struct file_info *finfo, int dontload)
-{
+static int bufferFile(struct file_info* finfo) {
        int fs = 0;
-       FILE *f = NULL;
+       FILE* fp = NULL;
 
-#ifdef DEBUG
-       printf("Opening file: %s\n", finfo->file_name);
-#endif
-       f = fopen(finfo->file_name, "rb");
-       if (f == NULL) {
-               perror("Error");
-               exit(1);
+       if (!finfo || !finfo->file_name) {
+               ERR("Invalid pointer provided!\n");
+               return -1;
        }
 
-       fseek(f, 0L, SEEK_END);
-       fs = ftell(f);
-       rewind(f);
+       DBG("Opening file: %s\n", finfo->file_name);
 
-#ifdef DEBUG
-       printf("Filesize: %i .\n", fs);
-#endif
+       if (!(fp = fopen(finfo->file_name, "rb"))) {
+               ERR("Error opening file: %s\n", finfo->file_name);
+               return -1;
+       }
 
-       finfo->file_size = fs;
+       /* Get filesize */
+       rewind(fp);
+       fseek(fp, 0L, SEEK_END);
+       fs = ftell(fp);
+       rewind(fp);
 
-       if (dontload) {
-               return 0;
+       if (fs < 0) {
+               ERR("Error getting filesize: %s\n", finfo->file_name);
+               fclose(fp);
+               return -1;
        }
 
-       char *data = malloc(fs);
-       finfo->file_data = data;
+       DBG("Filesize: %i\n", fs);
+       finfo->file_size = fs;
 
-       int read = fread(data, fs, 1, f);
+       if (!(finfo->file_data = malloc(fs))) {
+               ERR("Out of memory!\n");
+               fclose(fp);
+               return -1;
+       }
 
-       if (read != 1) {
-               printf("Error reading file %s.", finfo->file_name);
-               exit(1);
+       if (fread(finfo->file_data, 1, fs, fp) != fs) {
+               ERR("Error reading file %s\n", finfo->file_name);
+               fclose(fp);
+               return -1;
        }
 
-#ifdef DEBUG
-       printf("File: read successfully %i bytes.\n", read*fs);
-#endif
-       fclose(f);
+       DBG("File: read successful\n");
+       fclose(fp);
+
+       return 0;
 }
 
-void *writeFile(struct file_info *finfo)
-{
+static int writeFile(struct file_info* finfo) {
+       FILE* fp;
 
-#ifdef DEBUG
-       printf("Writing file: %s.\n", finfo->file_name);
-#endif
+       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;
+       }
 
-       FILE *fout = fopen(finfo->file_name, "w");
+       DBG("Writing file: %s\n", finfo->file_name);
 
-       if (!fwrite(finfo->file_data, finfo->file_size, 1, fout)) {
-               printf("Wanted to write, but something went wrong.\n");
-               fclose(fout);
-               exit(1);
+       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(fout);
+
+       fclose(fp);
+       return 0;
 }
 
-void *rmFile(struct file_info *finfo)
-{
-       remove(finfo->file_name);
-       free(finfo->file_data);
+static void fi_clean(struct file_info* finfo) {
+       if (!finfo)
+               return;
+
+       if (finfo->file_name) {
+               finfo->file_name = NULL;
+       }
+
+       if (finfo->file_data) {
+               free(finfo->file_data);
+               finfo->file_data = NULL;
+       }
+
        finfo->file_size = 0;
 }
 
-void *usage(char *argv[])
-{
-       printf("Usage: %s <sysupgradefile> <kernel_offset> <HWID> <HWVER> <SWID>\n"
-               "All are positional arguments ...       \n"
-               "       sysupgradefile:         File with the kernel uimage at 0\n"
-               "       kernel_offset:          Offset in Hex where the kernel is located\n"
-               "       HWID:                   Hardware ID, ASCII\n"
-               "       HWVER:                  Hardware Version, ASCII\n"
-               "       SWID:                   Software Version, Hex\n"
-               "       \n"
-               "       ", argv[0]);
+static void usage(char* argv[]) {
+    printf("Usage: %s <sysupgradefile> <kernel_offset> <HWID> <HWVER> <SWID>\n"
+           "All are positional arguments ...   \n"
+           "   sysupgradefile:     File with the kernel uimage at 0\n"
+           "   kernel_offset:      Offset where the kernel is located (decimal, hex or octal notation)\n"
+           "   HWID:               Hardware ID, ASCII\n"
+           "   HWVER:              Hardware Version, ASCII\n"
+           "   SWID:               Software Version (decimal, hex or octal notation)\n"
+           "   \n"
+           , argv[0]);
 }
 
-int main(int argc, char *argv[])
-{
-       printf("Building fw image for sercomm devices.\n");
+int main(int argc, char* argv[]) {
+       int ret = 1;
+       int rootfsname_sz;
+       int zipfsname_sz;
+       int zipcmd_sz;
+       u_int32_t kernel_offset = 0x90000; /* offset for the kernel inside the rootfs, default val */
+       u_int32_t swVer = 0;
+       struct file_info sysupgrade = { 0 };
+       struct file_info header = { 0 };
+       struct file_info rootfs = { 0 };
+       struct file_info zippedfs = { 0 };
+       struct file_info image = { 0 };
+       char* hwID = NULL;
+       char* hwVer = NULL;
+       char* rootfsname = NULL;
+       char* zipfsname = NULL;
+       char* zipcmd = NULL;
+       u_int8_t chkSum;
 
        if (argc == 2) {
-               struct file_info myfile = {argv[1], 0, 0};
-               bufferFile(&myfile, 0);
-               char chksum = getCheckSum(myfile.file_data, myfile.file_size);
-               printf("Checksum for File: %X.\n", chksum);
+               struct file_info myfile = { argv[1], 0, 0 };
+
+               if (bufferFile(&myfile))
+                       return 1;
+
+               chkSum = getCheckSum(myfile.file_data, myfile.file_size);
+               printf("Checksum for File: 0x%hhX\n", chkSum);
+
                return 0;
        }
 
@@ -143,113 +202,202 @@ int main(int argc, char *argv[])
                return 1;
        }
 
-       /* Args */
+       printf("Building fw image for sercomm devices ..\n");
 
-       struct file_info sysupgrade = {argv[1], 0, 0};
-       bufferFile(&sysupgrade, 0);
+       /* process args */
+       hwID = argv[3];
+       hwVer = argv[4];
 
-       int kernel_offset = 0x90000; /* offset for the kernel inside the rootfs, default val */
-       sscanf(argv[2], "%X", &kernel_offset);
-#ifdef DEBUG
-       printf("Kernel_offset: at %X/%i bytes.\n", kernel_offset, kernel_offset);
-#endif
-       char *hwID = argv[3];
-       char *hwVer = argv[4];
-       u_int32_t swVer = 0;
-       sscanf(argv[5],"%4X",&swVer);
-       swVer = bswap_32(swVer);
+       sysupgrade.file_name = argv[1];
+       image.file_name = argv[1];
+       kernel_offset = (u_int32_t) strtol(argv[2], NULL, 0);
+       swVer = (u_int32_t) strtol(argv[5], NULL, 0);
+       swVer = __cpu_to_be32(swVer);
 
-       char *rootfsname = malloc(2*strlen(sysupgrade.file_name) + 8);
-       sprintf(rootfsname, "%s.rootfs", sysupgrade.file_name);
+       /* Check if files actually exist */
+       if (access(sysupgrade.file_name, (F_OK | R_OK))) {
+               /* Error */
+               ERR("File not found: %s\n", sysupgrade.file_name);
+               goto cleanup;
+       }
 
-       char *zipfsname = malloc(2*strlen(rootfsname) + 5);
-       sprintf(zipfsname, "%s.zip", rootfsname);
-       /* / Args */
+       /* Calculate amount of required memory (incl. 0-term) */
+       rootfsname_sz = strlen(sysupgrade.file_name) + 7 + 1;
+       zipfsname_sz = strlen(sysupgrade.file_name) + 7 + 4 + 1;
+
+       /* Allocate required memory */
+       if (!(rootfsname = (char*) malloc(rootfsname_sz)) || !(zipfsname =
+                       (char*) malloc(zipfsname_sz))) {
+               /* Error */
+               ERR("Out of memory!\n");
+               goto cleanup;
+       }
+
+       /* Create filenames */
+       if (snprintf(rootfsname, rootfsname_sz, "%s.rootfs", sysupgrade.file_name)
+                       >= rootfsname_sz
+                       || snprintf(zipfsname, zipfsname_sz, "%s.rootfs.zip",
+                                       sysupgrade.file_name) >= zipfsname_sz) {
+               /* Error */
+               ERR("Buffer too small!\n");
+               goto cleanup;
+       }
+
+       /* Buffer all files */
+       if (bufferFile(&sysupgrade)) {
+               /* Error */
+               goto cleanup;
+       }
+
+       DBG("Building header: %s %s %2X %s\n", hwID, hwVer, swVer, magic);
 
-#ifdef DEBUG
-       printf("Building header: %s %s %2X %s.\n", hwID , hwVer, swVer, magic);
-#endif
        /* Construct the firmware header/magic */
-       struct file_info header = {0, 0, 0};
+       header.file_name = NULL;
        header.file_size = HEADER_SIZE;
-       header.file_data = malloc(HEADER_SIZE);
-       bzero(header.file_data, header.file_size);
 
-       char *tg = header.file_data;
-       strcpy(tg, magic);
-       memcpy(tg+7, version, 4*sizeof(char));
-       strcpy(tg+11, hwID);
-       strcpy(tg+45, hwVer);
-       memcpy(tg+55, &swVer,sizeof(u_int32_t));
-       strcpy(tg+63, magic);
+       if (!(header.file_data = (char*) calloc(1, HEADER_SIZE))) {
+               /* Error */
+               ERR("Out of memory!\n");
+               goto cleanup;
+       }
+
+       strncpy(header.file_data + 0, magic, 7);
+       memcpy(header.file_data + 7, version, sizeof(version));
+       strncpy(header.file_data + 11, hwID, 34);
+       strncpy(header.file_data + 45, hwVer, 10);
+       memcpy(header.file_data + 55, &swVer, sizeof(swVer));
+       strncpy(header.file_data + 63, magic, 7);
+
+       DBG("Creating rootfs ..\n");
 
-#ifdef DEBUG
-       printf("Header done, now creating rootfs.");
-#endif
        /* Construct a rootfs */
-       struct file_info rootfs = {0, 0, 0};
-       rootfs.file_size = sysupgrade.file_size + kernel_offset + footer_size;
-       rootfs.file_data =  malloc(rootfs.file_size);
-       bzero(rootfs.file_data, rootfs.file_size);
        rootfs.file_name = rootfsname;
+       rootfs.file_size = ALIGN(
+                       sysupgrade.file_size + kernel_offset + header.file_size,
+                       ROOTFS_ALIGN);
+
+       if (!(rootfs.file_data = calloc(1, rootfs.file_size))) {
+               /* Error */
+               ERR("Out of memory!\n");
+               goto cleanup;
+       }
 
-       /* copy Owrt image to Kernel location */
-       memcpy(rootfs.file_data+kernel_offset, sysupgrade.file_data, sysupgrade.file_size);
+       /* copy Owrt image to kernel location */
+       memcpy(rootfs.file_data + kernel_offset, sysupgrade.file_data,
+                       sysupgrade.file_size);
 
-       /* 22 added to get away from sysup image, no other reason.
-        *  updater searches for magic anyway */
-       tg = rootfs.file_data + kernel_offset + sysupgrade.file_size+22;
+       /* Append header after the owrt image.  The updater searches for it */
+       memcpy(rootfs.file_data + kernel_offset + sysupgrade.file_size,
+                       header.file_data, header.file_size);
 
-       memcpy(tg, header.file_data, header.file_size);
-       writeFile(&rootfs);
+       /* Write to file */
+       if (writeFile(&rootfs)) {
+               /* Error */
+               goto cleanup;
+       }
+
+       /* Construct a zip */
+       DBG("Preparing to zip ..\n");
 
-#ifdef DEBUG
-       printf("Preparing to zip.\n");
-#endif
        /* now that we got the rootfs, repeat the whole thing again(sorta):
         * 1. zip the rootfs */
-       char *zipper = malloc(5 + 2*strlen(rootfs.file_name) + 6);
-       sprintf(zipper, "%s %s %s", "zip ", zipfsname, rootfs.file_name);
-       int ret = system(zipper);
+       zipcmd_sz = 3 + 1 + strlen(zipfsname) + 1 + strlen(rootfs.file_name) + 1;
+
+       if (!(zipcmd = malloc(zipcmd_sz))) {
+               /* Error */
+               ERR("Out of memory!\n");
+               goto cleanup;
+       }
 
-       /* clear rootfs file */
-       rmFile(&rootfs);
+       if (snprintf(zipcmd, zipcmd_sz, "%s %s %s", "zip", zipfsname,
+                       rootfs.file_name) >= zipcmd_sz) {
+               /* Error */
+               ERR("Buffer too small!\n");
+               goto cleanup;
+       }
+
+       if (system(zipcmd)) {
+               /* Error */
+               ERR("Error creating a zip file!\n");
+               goto cleanup;
+       }
 
        /* and load zipped fs */
-       struct file_info zippedfs = {zipfsname, 0, 0};
-       bufferFile(&zippedfs, 0);
+       zippedfs.file_name = zipfsname;
 
-#ifdef DEBUG
-       printf("Creating Image.\n");
-#endif
+       if (bufferFile(&zippedfs)) {
+               /* Error */
+               goto cleanup;
+       }
 
-       /* 2. create new file 512+rootfs size */
-       struct file_info image = {argv[1], 0, 0};
-       image.file_data = malloc(zippedfs.file_size + 512);
-       image.file_size = zippedfs.file_size + 512;
+       DBG("Creating Image.\n");
 
-       /* 3. copy zipfile at loc 512 */
-       memcpy(image.file_data+512, zippedfs.file_data, zippedfs.file_size);
-       rmFile(&zippedfs);
+       /* 2. create new file 512 + rootfs size */
+       image.file_size = zippedfs.file_size + 512;
+       if (!(image.file_data = malloc(zippedfs.file_size + 512))) {
+               /* Error */
+               ERR("Out of memory!\n");
+               goto cleanup;
+       }
 
-       /* 4. add header to file */
+       /* 3. add header to file */
        memcpy(image.file_data, header.file_data, header.file_size);
 
-       /* 5. do a checksum run, and compute checksum */
-       char chksum = getCheckSum(image.file_data, image.file_size);
-#ifdef DEBUG
-       printf("Checksum for Image: %X.\n", chksum);
-#endif
+       /* 4. clear remaining space */
+       if (header.file_size < 512)
+               memset(image.file_data + header.file_size, 0, 512 - header.file_size);
 
-       /* 6. write the checksum invert into byte 511 to bring it to 0 */
-       chksum = (chksum ^ 0xFF) + 1;
-       memcpy(image.file_data+511, &chksum, 1);
+       /* 5. copy zipfile at loc 512 */
+       memcpy(image.file_data + 512, zippedfs.file_data, zippedfs.file_size);
 
-       chksum = getCheckSum(image.file_data, image.file_size);
-#ifdef DEBUG
-       printf("Checksum for after fix: %X.\n", chksum);
-#endif
-       /* 7. pray that the updater will accept the file */
-       writeFile(&image);
-       return 0;
+       /* 6. do a checksum run, and compute checksum */
+       chkSum = getCheckSum(image.file_data, image.file_size);
+
+       DBG("Checksum for Image: %hhX\n", chkSum);
+
+       /* 7. write the checksum inverted into byte 511 to bring it to 0 on verification */
+       chkSum = (chkSum ^ 0xFF) + 1;
+       image.file_data[511] = (char) chkSum;
+
+       chkSum = getCheckSum(image.file_data, image.file_size);
+       DBG("Checksum for after fix: %hhX\n", chkSum);
+
+       if (chkSum != 0) {
+               ERR("Invalid checksum!\n")
+               goto cleanup;
+       }
+
+       /* 8. pray that the updater will accept the file */
+       if (writeFile(&image)) {
+               /* Error */
+               goto cleanup;
+       }
+
+       /* All seems OK */
+       ret = 0;
+
+       cleanup:
+
+       if (rootfs.file_name && !access(rootfs.file_name, F_OK | W_OK))
+               remove(rootfs.file_name);
+
+       if (zippedfs.file_name && !access(zippedfs.file_name, F_OK | W_OK))
+               remove(zippedfs.file_name);
+
+       fi_clean(&sysupgrade);
+       fi_clean(&header);
+       fi_clean(&rootfs);
+       fi_clean(&zippedfs);
+       fi_clean(&image);
+
+       if (rootfsname)
+               free(rootfsname);
+
+       if (zipfsname)
+               free(zipfsname);
+
+       if (zipcmd)
+               free(zipcmd);
+
+       return ret;
 }