mtd: Changed mtd_fixtrx and related functions to be weak references. The weak referen...
[openwrt/svn-archive/archive.git] / package / mtd / src / trx.c
index 7094ef62b0c1c80ec163d45c5629bf5ba76c724d..b8d9e2bf05cc2ea49af722663f01880d7b38d002 100644 (file)
@@ -27,6 +27,7 @@
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <string.h>
+#include <errno.h>
 
 #include <sys/ioctl.h>
 #include "mtd-api.h"
 
 #define TRX_MAGIC       0x30524448      /* "HDR0" */
 struct trx_header {
-       unsigned magic;         /* "HDR0" */
-       unsigned len;           /* Length of file including header */
-       unsigned crc32;         /* 32-bit CRC from flag_version to end of file */
-       unsigned flag_version;  /* 0:15 flags, 16:31 version */
-       unsigned offsets[3];    /* Offsets of partitions from start of header */
+       uint32_t magic;         /* "HDR0" */
+       uint32_t len;           /* Length of file including header */
+       uint32_t crc32;         /* 32-bit CRC from flag_version to end of file */
+       uint32_t flag_version;  /* 0:15 flags, 16:31 version */
+       uint32_t offsets[3];    /* Offsets of partitions from start of header */
 };
 
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define STORE32_LE(X)           ((((X) & 0x000000FF) << 24) | (((X) & 0x0000FF00) << 8) | (((X) & 0x00FF0000) >> 8) | (((X) & 0xFF000000) >> 24))
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define STORE32_LE(X)           (X)
+#else
+#error unknown endianness!
+#endif
+
+ssize_t pread(int fd, void *buf, size_t count, off_t offset);
+ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
+
 int
 trx_fixup(int fd, const char *name)
 {
@@ -130,3 +142,79 @@ trx_check(int imagefd, const char *mtd, char *buf, int *len)
        return 1;
 }
 
+int
+mtd_fixtrx(const char *mtd, size_t offset)
+{
+       int fd;
+       struct trx_header *trx;
+       char *buf;
+       ssize_t res;
+       size_t block_offset;
+
+       if (quiet < 2)
+               fprintf(stderr, "Trying to fix trx header in %s at 0x%x...\n", mtd, offset);
+
+       block_offset = offset & ~(erasesize - 1);
+       offset -= block_offset;
+
+       fd = mtd_check_open(mtd);
+       if(fd < 0) {
+               fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+               exit(1);
+       }
+
+       if (block_offset + erasesize > mtdsize) {
+               fprintf(stderr, "Offset too large, device size 0x%x\n", mtdsize);
+               exit(1);
+       }
+
+       buf = malloc(erasesize);
+       if (!buf) {
+               perror("malloc");
+               exit(1);
+       }
+
+       res = pread(fd, buf, erasesize, block_offset);
+       if (res != erasesize) {
+               perror("pread");
+               exit(1);
+       }
+
+       trx = (struct trx_header *) (buf + offset);
+       if (trx->magic != STORE32_LE(0x30524448)) {
+               fprintf(stderr, "No trx magic found\n");
+               exit(1);
+       }
+
+       if (trx->len == STORE32_LE(erasesize - offset)) {
+               if (quiet < 2)
+                       fprintf(stderr, "Header already fixed, exiting\n");
+               close(fd);
+               return 0;
+       }
+
+       trx->len = STORE32_LE(erasesize - offset);
+
+       trx->crc32 = STORE32_LE(crc32buf((char*) &trx->flag_version, erasesize - offset - 3*4));
+       if (mtd_erase_block(fd, block_offset)) {
+               fprintf(stderr, "Can't erease block at 0x%x (%s)\n", block_offset, strerror(errno));
+               exit(1);
+       }
+
+       if (quiet < 2)
+               fprintf(stderr, "New crc32: 0x%x, rewriting block\n", trx->crc32);
+
+       if (pwrite(fd, buf, erasesize, block_offset) != erasesize) {
+               fprintf(stderr, "Error writing block (%s)\n", strerror(errno));
+               exit(1);
+       }
+
+       if (quiet < 2)
+               fprintf(stderr, "Done.\n");
+
+       close (fd);
+       sync();
+       return 0;
+
+}
+