packages: clean up the package folder

Signed-off-by: John Crispin <blogic@openwrt.org>

SVN-Revision: 37007
This commit is contained in:
John Crispin
2013-06-21 16:54:37 +00:00
parent 44b1688e6c
commit 4ebf19b48f
603 changed files with 28 additions and 28 deletions

View File

@@ -0,0 +1,18 @@
CC = gcc
CFLAGS += -Wall
obj = mtd.o jffs2.o crc32.o
obj.seama = seama.o md5.o
obj.ar71xx = trx.o
obj.brcm = trx.o
obj.brcm47xx = $(obj.brcm)
obj.brcm63xx = imagetag.o
obj.ramips = $(obj.seama)
ifdef FIS_SUPPORT
obj += fis.o
endif
mtd: $(obj) $(obj.$(TARGET))
clean:
rm -f *.o jffs2

View File

@@ -0,0 +1,95 @@
/*
* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
* code or tables extracted from it, as desired without restriction.
*
* First, the polynomial itself and its table of feedback terms. The
* polynomial is
* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
*
* Note that we take it "backwards" and put the highest-order term in
* the lowest-order bit. The X^32 term is "implied"; the LSB is the
* X^31 term, etc. The X^0 term (usually shown as "+1") results in
* the MSB being 1
*
* Note that the usual hardware shift register implementation, which
* is what we're using (we're merely optimizing it by doing eight-bit
* chunks at a time) shifts bits into the lowest-order term. In our
* implementation, that means shifting towards the right. Why do we
* do it this way? Because the calculated CRC must be transmitted in
* order from highest-order term to lowest-order term. UARTs transmit
* characters in order from LSB to MSB. By storing the CRC this way
* we hand it to the UART in the order low-byte to high-byte; the UART
* sends each low-bit to hight-bit; and the result is transmission bit
* by bit from highest- to lowest-order term without requiring any bit
* shuffling on our part. Reception works similarly
*
* The feedback terms table consists of 256, 32-bit entries. Notes
*
* The table can be generated at runtime if desired; code to do so
* is shown later. It might not be obvious, but the feedback
* terms simply represent the results of eight shift/xor opera
* tions for all combinations of data and CRC register values
*
* The values must be right-shifted by eight bits by the "updcrc
* logic; the shift must be unsigned (bring in zeroes). On some
* hardware you could probably optimize the shift in assembler by
* using byte-swap instructions
* polynomial $edb88320
*/
#include <stdint.h>
const uint32_t crc32_table[256] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
0x2d02ef8dL
};

View File

@@ -0,0 +1,26 @@
#ifndef CRC32_H
#define CRC32_H
#include <stdint.h>
extern const uint32_t crc32_table[256];
/* Return a 32-bit CRC of the contents of the buffer. */
static inline uint32_t
crc32(uint32_t val, const void *ss, int len)
{
const unsigned char *s = ss;
while (--len >= 0)
val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
return val;
}
static inline unsigned int crc32buf(char *buf, size_t len)
{
return crc32(0xFFFFFFFF, buf, len);
}
#endif

View File

@@ -0,0 +1,262 @@
/*
* FIS table updating code for mtd
*
* Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <sys/mman.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include "crc32.h"
#include "mtd.h"
#include "fis.h"
struct fis_image_hdr {
unsigned char name[16];
uint32_t flash_base;
uint32_t mem_base;
uint32_t size;
uint32_t entry_point;
uint32_t data_length;
} __attribute__((packed));
struct fis_image_crc {
uint32_t desc;
uint32_t file;
} __attribute__((packed));
struct fis_image_desc {
struct fis_image_hdr hdr;
char _pad[256 - sizeof(struct fis_image_hdr) - sizeof(struct fis_image_crc)];
struct fis_image_crc crc;
} __attribute__((packed));
static int fis_fd = -1;
static struct fis_image_desc *fis_desc;
static int fis_erasesize = 0;
static void
fis_close(void)
{
if (fis_desc)
munmap(fis_desc, fis_erasesize);
if (fis_fd >= 0)
close(fis_fd);
fis_fd = -1;
fis_desc = NULL;
}
static struct fis_image_desc *
fis_open(void)
{
struct fis_image_desc *desc;
if (fis_fd >= 0)
fis_close();
fis_fd = mtd_check_open("FIS directory");
if (fis_fd < 0)
goto error;
close(fis_fd);
fis_fd = mtd_open("FIS directory", true);
if (fis_fd < 0)
goto error;
fis_erasesize = erasesize;
desc = mmap(NULL, erasesize, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, fis_fd, 0);
if (desc == MAP_FAILED)
goto error;
fis_desc = desc;
return desc;
error:
fis_close();
return NULL;
}
int
fis_validate(struct fis_part *old, int n_old, struct fis_part *new, int n_new)
{
struct fis_image_desc *desc;
void *end;
int found = 0;
int i;
desc = fis_open();
if (!desc)
return -1;
for (i = 0; i < n_new - 1; i++) {
if (!new[i].size) {
fprintf(stderr, "FIS error: only the last partition can detect the size automatically\n");
i = -1;
goto done;
}
}
end = desc;
end = (char *) end + fis_erasesize;
while ((void *) desc < end) {
if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff))
break;
for (i = 0; i < n_old; i++) {
if (!strncmp((char *) desc->hdr.name, (char *) old[i].name, sizeof(desc->hdr.name))) {
found++;
goto next;
}
}
next:
desc++;
continue;
}
if (found == n_old)
i = 1;
else
i = -1;
done:
fis_close();
return i;
}
int
fis_remap(struct fis_part *old, int n_old, struct fis_part *new, int n_new)
{
struct fis_image_desc *fisdir = NULL;
struct fis_image_desc *redboot = NULL;
struct fis_image_desc *first = NULL;
struct fis_image_desc *last = NULL;
struct fis_image_desc *first_fb = NULL;
struct fis_image_desc *last_fb = NULL;
struct fis_image_desc *desc;
struct fis_part *part;
uint32_t offset = 0, size = 0;
char *start, *end, *tmp;
int i;
desc = fis_open();
if (!desc)
return -1;
if (!quiet)
fprintf(stderr, "Updating FIS table... \n");
start = (char *) desc;
end = (char *) desc + fis_erasesize;
while ((char *) desc < end) {
if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff))
break;
if (!strcmp((char *) desc->hdr.name, "FIS directory"))
fisdir = desc;
if (!strcmp((char *) desc->hdr.name, "RedBoot"))
redboot = desc;
/* update max offset */
if (offset < desc->hdr.flash_base)
offset = desc->hdr.flash_base;
for (i = 0; i < n_old; i++) {
if (!strncmp((char *) desc->hdr.name, (char *) old[i].name, sizeof(desc->hdr.name))) {
last = desc;
if (!first)
first = desc;
break;
}
}
desc++;
}
desc--;
first_fb = first;
last_fb = last;
if (first_fb->hdr.flash_base > last_fb->hdr.flash_base) {
first_fb = last;
last_fb = first;
}
/* determine size of available space */
desc = (struct fis_image_desc *) start;
while ((char *) desc < end) {
if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff))
break;
if (desc->hdr.flash_base > last_fb->hdr.flash_base &&
desc->hdr.flash_base < offset)
offset = desc->hdr.flash_base;
desc++;
}
desc--;
size = offset - first_fb->hdr.flash_base;
#ifdef notyet
desc = first - 1;
if (redboot && (desc >= redboot)) {
if (first->hdr.flash_base - desc->hdr.size > desc->hdr.flash_base) {
int delta = first->hdr.flash_base - desc->hdr.size - desc->hdr.flash_base;
offset -= delta;
size += delta;
}
}
#endif
last++;
desc = first + n_new;
offset = first_fb->hdr.flash_base;
if (desc != last) {
if (desc > last)
tmp = (char *) desc;
else
tmp = (char *) last;
memmove(desc, last, end - tmp);
if (desc < last) {
tmp = end - (last - desc) * sizeof(struct fis_image_desc);
memset(tmp, 0xff, tmp - end);
}
}
for (part = new, desc = first; desc < first + n_new; desc++, part++) {
memset(desc, 0, sizeof(struct fis_image_desc));
memcpy(desc->hdr.name, part->name, sizeof(desc->hdr.name));
desc->crc.desc = 0;
desc->crc.file = 0;
desc->hdr.flash_base = offset;
desc->hdr.mem_base = part->loadaddr;
desc->hdr.entry_point = part->loadaddr;
desc->hdr.size = (part->size > 0) ? part->size : size;
desc->hdr.data_length = desc->hdr.size;
offset += desc->hdr.size;
size -= desc->hdr.size;
}
msync(fis_desc, fis_erasesize, MS_SYNC|MS_INVALIDATE);
fis_close();
return 0;
}

View File

@@ -0,0 +1,14 @@
#ifndef __FIS_H
#define __FIS_H
struct fis_part {
unsigned char name[16];
uint32_t offset;
uint32_t loadaddr;
uint32_t size;
};
int fis_validate(struct fis_part *old, int n_old, struct fis_part *new, int n_new);
int fis_remap(struct fis_part *old, int n_old, struct fis_part *new, int n_new);
#endif

View File

@@ -0,0 +1,316 @@
/*
* imagetag.c
*
* Copyright (C) 2005 Mike Baker
* Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
* Copyrigth (C) 2010 Daniel Dickinson <openwrt@cshore.neomailbox.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <mtd/mtd-user.h>
#include <linux/bcm963xx_tag.h>
#include "mtd.h"
#include "crc32.h"
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);
#define CRC_START 0xFFFFFFFF
static uint32_t strntoul(char *str, char **endptr, int base, size_t len) {
char *newstr;
uint32_t res = 0;
newstr = calloc(len + 1, sizeof(char));
if (newstr) {
strncpy(newstr, str, len);
res = strtoul(newstr, endptr, base);
free(newstr);
}
return res;
}
uint32_t compute_crc32(uint32_t crc, off_t start, size_t compute_len, int fd)
{
uint8_t readbuf[1024];
ssize_t res;
off_t offset = start;
/* Read a buffer's worth of bytes */
while (fd && (compute_len >= sizeof(readbuf))) {
res = pread(fd, readbuf, sizeof(readbuf), offset);
crc = crc32(crc, readbuf, res);
compute_len = compute_len - res;
offset += res;
}
/* Less than buffer-size bytes remains, read compute_len bytes */
if (fd && (compute_len > 0)) {
res = pread(fd, readbuf, compute_len, offset);
crc = crc32(crc, readbuf, res);
}
return crc;
}
int
trx_fixup(int fd, const char *name)
{
struct mtd_info_user mtdInfo;
unsigned long len;
void *ptr, *scan;
int bfd;
struct bcm_tag *tag;
ssize_t res;
uint32_t cfelen, imagelen, imagestart, rootfslen;
uint32_t imagecrc, rootfscrc, headercrc;
uint32_t offset = 0;
cfelen = imagelen = imagestart = imagecrc = rootfscrc = headercrc = rootfslen = 0;
if (ioctl(fd, MEMGETINFO, &mtdInfo) < 0) {
fprintf(stderr, "Failed to get mtd info\n");
goto err;
}
len = mtdInfo.size;
if (mtdInfo.size <= 0) {
fprintf(stderr, "Invalid MTD device size\n");
goto err;
}
bfd = mtd_open(name, true);
ptr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, bfd, 0);
if (!ptr || (ptr == (void *) -1)) {
perror("mmap");
goto err1;
}
tag = (struct bcm_tag *) (ptr);
cfelen = strntoul(&tag->cfe_length[0], NULL, 10, IMAGE_LEN);
if (cfelen) {
fprintf(stderr, "Non-zero CFE length. This is currently unsupported.\n");
exit(1);
}
headercrc = compute_crc32(CRC_START, offset, offsetof(struct bcm_tag, header_crc), fd);
if (headercrc != *(uint32_t *)(&tag->header_crc)) {
fprintf(stderr, "Tag verify failed. This may not be a valid image.\n");
exit(1);
}
sprintf(&tag->root_length[0], "%u", 0);
strncpy(&tag->total_length[0], &tag->kernel_length[0], IMAGE_LEN);
imagestart = sizeof(tag);
memcpy(&tag->image_crc, &tag->kernel_crc, sizeof(uint32_t));
memcpy(&tag->fskernel_crc, &tag->kernel_crc, sizeof(uint32_t));
rootfscrc = CRC_START;
memcpy(&tag->rootfs_crc, &rootfscrc, sizeof(uint32_t));
headercrc = crc32(CRC_START, tag, offsetof(struct bcm_tag, header_crc));
memcpy(&tag->header_crc, &headercrc, sizeof(uint32_t));
msync(ptr, sizeof(struct bcm_tag), MS_SYNC|MS_INVALIDATE);
munmap(ptr, len);
close(bfd);
return 0;
err1:
close(bfd);
err:
fprintf(stderr, "Error fixing up imagetag header\n");
return -1;
}
int
trx_check(int imagefd, const char *mtd, char *buf, int *len)
{
struct bcm_tag *tag = (const struct bcm_tag *) buf;
int fd;
uint32_t headerCRC;
uint32_t imageLen;
if (strcmp(mtd, "linux") != 0)
return 1;
*len = read(imagefd, buf, sizeof(struct bcm_tag));
if (*len < sizeof(struct bcm_tag)) {
fprintf(stdout, "Could not get image header, file too small (%d bytes)\n", *len);
return 0;
}
headerCRC = crc32buf(buf, offsetof(struct bcm_tag, header_crc));
if (*(uint32_t *)(&tag->header_crc) != headerCRC) {
if (quiet < 2) {
fprintf(stderr, "Bad header CRC got %08x, calculated %08x\n",
*(uint32_t *)(&tag->header_crc), headerCRC);
fprintf(stderr, "This is not the correct file format; refusing to flash.\n"
"Please specify the correct file or use -f to force.\n");
}
return 0;
}
/* check if image fits to mtd device */
fd = mtd_check_open(mtd);
if(fd < 0) {
fprintf(stderr, "Could not open mtd device: %s\n", mtd);
exit(1);
}
imageLen = strntoul(&tag->total_length[0], NULL, 10, IMAGE_LEN);
if(mtdsize < imageLen) {
fprintf(stderr, "Image too big for partition: %s\n", mtd);
close(fd);
return 0;
}
close(fd);
return 1;
}
int
mtd_fixtrx(const char *mtd, size_t offset)
{
int fd;
struct bcm_tag *tag;
char *buf;
ssize_t res;
size_t block_offset;
uint32_t cfelen, imagelen, imagestart, rootfslen;
uint32_t imagecrc, rootfscrc, headercrc;
cfelen = imagelen = imagestart = imagecrc = rootfscrc = headercrc = rootfslen = 0;
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);
}
tag = (struct bcm_tag *) (buf + offset);
cfelen = strntoul(tag->cfe_length, NULL, 10, IMAGE_LEN);
if (cfelen) {
fprintf(stderr, "Non-zero CFE length. This is currently unsupported.\n");
exit(1);
}
if (quiet < 2) {
fprintf(stderr, "Verifying we actually have an imagetag.\n");
}
headercrc = compute_crc32(CRC_START, offset, offsetof(struct bcm_tag, header_crc), fd);
if (headercrc != *(uint32_t *)(&tag->header_crc)) {
fprintf(stderr, "Tag verify failed. This may not be a valid image.\n");
exit(1);
}
if (quiet < 2) {
fprintf(stderr, "Checking current fixed status.\n");
}
rootfslen = strntoul(&tag->root_length[0], NULL, 10, IMAGE_LEN);
if (rootfslen == 0) {
if (quiet < 2)
fprintf(stderr, "Header already fixed, exiting\n");
close(fd);
return 0;
}
if (quiet < 2) {
fprintf(stderr, "Setting root length to 0.\n");
}
sprintf(&tag->root_length[0], "%u", 0);
strncpy(&tag->total_length[0], &tag->kernel_length[0], IMAGE_LEN);
if (quiet < 2) {
fprintf(stderr, "Recalculating CRCs.\n");
}
imagestart = sizeof(tag);
memcpy(&tag->image_crc, &tag->kernel_crc, sizeof(uint32_t));
memcpy(&tag->fskernel_crc, &tag->kernel_crc, sizeof(uint32_t));
rootfscrc = CRC_START;
memcpy(&tag->rootfs_crc, &rootfscrc, sizeof(uint32_t));
headercrc = crc32(CRC_START, tag, offsetof(struct bcm_tag, header_crc));
memcpy(&tag->header_crc, &headercrc, sizeof(uint32_t));
if (quiet < 2) {
fprintf(stderr, "Erasing imagetag block\n");
}
if (mtd_erase_block(fd, block_offset)) {
fprintf(stderr, "Can't erase block at 0x%x (%s)\n", block_offset, strerror(errno));
exit(1);
}
if (quiet < 2) {
fprintf(stderr, "New image crc32: 0x%x, rewriting block\n",
*(uint32_t *)(&tag->image_crc));
fprintf(stderr, "New header crc32: 0x%x, rewriting block\n", headercrc);
}
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;
}

View File

@@ -0,0 +1,357 @@
/*
* jffs2 on-disk structure generator for mtd
*
* Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* Based on:
* JFFS2 -- Journalling Flash File System, Version 2.
* Copyright © 2001-2007 Red Hat, Inc.
* Created by David Woodhouse <dwmw2@infradead.org>
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <endian.h>
#include "jffs2.h"
#include "crc32.h"
#include "mtd.h"
#define PAD(x) (((x)+3)&~3)
#if BYTE_ORDER == BIG_ENDIAN
# define CLEANMARKER "\x19\x85\x20\x03\x00\x00\x00\x0c\xf0\x60\xdc\x98"
#else
# define CLEANMARKER "\x85\x19\x03\x20\x0c\x00\x00\x00\xb1\xb0\x1e\xe4"
#endif
static int last_ino = 0;
static int last_version = 0;
static char *buf = NULL;
static int ofs = 0;
static int outfd = -1;
static int mtdofs = 0;
static int target_ino = 0;
static void prep_eraseblock(void);
static void pad(int size)
{
if ((ofs % size == 0) && (ofs < erasesize))
return;
if (ofs < erasesize) {
memset(buf + ofs, 0xff, (size - (ofs % size)));
ofs += (size - (ofs % size));
}
ofs = ofs % erasesize;
if (ofs == 0) {
mtd_erase_block(outfd, mtdofs);
write(outfd, buf, erasesize);
mtdofs += erasesize;
}
}
static inline int rbytes(void)
{
return erasesize - (ofs % erasesize);
}
static inline void add_data(char *ptr, int len)
{
if (ofs + len > erasesize) {
pad(erasesize);
prep_eraseblock();
}
memcpy(buf + ofs, ptr, len);
ofs += len;
}
static void prep_eraseblock(void)
{
if (ofs > 0)
return;
add_data(CLEANMARKER, sizeof(CLEANMARKER) - 1);
}
static int add_dirent(const char *name, const char type, int parent)
{
struct jffs2_raw_dirent *de;
if (ofs - erasesize < sizeof(struct jffs2_raw_dirent) + strlen(name))
pad(erasesize);
prep_eraseblock();
last_ino++;
memset(buf + ofs, 0, sizeof(struct jffs2_raw_dirent));
de = (struct jffs2_raw_dirent *) (buf + ofs);
de->magic = JFFS2_MAGIC_BITMASK;
de->nodetype = JFFS2_NODETYPE_DIRENT;
de->type = type;
de->name_crc = crc32(0, name, strlen(name));
de->ino = last_ino++;
de->pino = parent;
de->totlen = sizeof(*de) + strlen(name);
de->hdr_crc = crc32(0, (void *) de, sizeof(struct jffs2_unknown_node) - 4);
de->version = last_version++;
de->mctime = 0;
de->nsize = strlen(name);
de->node_crc = crc32(0, (void *) de, sizeof(*de) - 8);
memcpy(de->name, name, strlen(name));
ofs += sizeof(struct jffs2_raw_dirent) + de->nsize;
pad(4);
return de->ino;
}
static int add_dir(const char *name, int parent)
{
struct jffs2_raw_inode ri;
int inode;
inode = add_dirent(name, IFTODT(S_IFDIR), parent);
if (rbytes() < sizeof(ri))
pad(erasesize);
prep_eraseblock();
memset(&ri, 0, sizeof(ri));
ri.magic = JFFS2_MAGIC_BITMASK;
ri.nodetype = JFFS2_NODETYPE_INODE;
ri.totlen = sizeof(ri);
ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node) - 4);
ri.ino = inode;
ri.mode = S_IFDIR | 0755;
ri.uid = ri.gid = 0;
ri.atime = ri.ctime = ri.mtime = 0;
ri.isize = ri.csize = ri.dsize = 0;
ri.version = 1;
ri.node_crc = crc32(0, &ri, sizeof(ri) - 8);
ri.data_crc = 0;
add_data((char *) &ri, sizeof(ri));
pad(4);
return inode;
}
static void add_file(const char *name, int parent)
{
int inode, f_offset = 0, fd;
struct jffs2_raw_inode ri;
struct stat st;
char wbuf[4096];
const char *fname;
if (stat(name, &st)) {
fprintf(stderr, "File %s does not exist\n", name);
return;
}
fname = strrchr(name, '/');
if (fname)
fname++;
else
fname = name;
inode = add_dirent(fname, IFTODT(S_IFREG), parent);
memset(&ri, 0, sizeof(ri));
ri.magic = JFFS2_MAGIC_BITMASK;
ri.nodetype = JFFS2_NODETYPE_INODE;
ri.ino = inode;
ri.mode = st.st_mode;
ri.uid = ri.gid = 0;
ri.atime = st.st_atime;
ri.ctime = st.st_ctime;
ri.mtime = st.st_mtime;
ri.isize = st.st_size;
ri.compr = 0;
ri.usercompr = 0;
fd = open(name, 0);
if (fd < 0) {
fprintf(stderr, "File %s does not exist\n", name);
return;
}
for (;;) {
int len = 0;
for (;;) {
len = rbytes() - sizeof(ri);
if (len > 128)
break;
pad(erasesize);
prep_eraseblock();
}
if (len > sizeof(wbuf))
len = sizeof(wbuf);
len = read(fd, wbuf, len);
if (len <= 0)
break;
ri.totlen = sizeof(ri) + len;
ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node) - 4);
ri.version = ++last_version;
ri.offset = f_offset;
ri.csize = ri.dsize = len;
ri.node_crc = crc32(0, &ri, sizeof(ri) - 8);
ri.data_crc = crc32(0, wbuf, len);
f_offset += len;
add_data((char *) &ri, sizeof(ri));
add_data(wbuf, len);
pad(4);
prep_eraseblock();
}
close(fd);
}
int mtd_replace_jffs2(const char *mtd, int fd, int ofs, const char *filename)
{
outfd = fd;
mtdofs = ofs;
buf = malloc(erasesize);
target_ino = 1;
if (!last_ino)
last_ino = 1;
add_file(filename, target_ino);
pad(erasesize);
/* add eof marker, pad to eraseblock size and write the data */
add_data(JFFS2_EOF, sizeof(JFFS2_EOF) - 1);
pad(erasesize);
free(buf);
return (mtdofs - ofs);
}
void mtd_parse_jffs2data(const char *buf, const char *dir)
{
struct jffs2_unknown_node *node = (struct jffs2_unknown_node *) buf;
unsigned int ofs = 0;
while (ofs < erasesize) {
node = (struct jffs2_unknown_node *) (buf + ofs);
if (node->magic != 0x1985)
break;
ofs += PAD(node->totlen);
if (node->nodetype == JFFS2_NODETYPE_DIRENT) {
struct jffs2_raw_dirent *de = (struct jffs2_raw_dirent *) node;
/* is this the right directory name and is it a subdirectory of / */
if (*dir && (de->pino == 1) && !strncmp((char *) de->name, dir, de->nsize))
target_ino = de->ino;
/* store the last inode and version numbers for adding extra files */
if (last_ino < de->ino)
last_ino = de->ino;
if (last_version < de->version)
last_version = de->version;
}
}
}
int mtd_write_jffs2(const char *mtd, const char *filename, const char *dir)
{
int err = -1, fdeof = 0;
outfd = mtd_check_open(mtd);
if (outfd < 0)
return -1;
if (quiet < 2)
fprintf(stderr, "Appending %s to jffs2 partition %s\n", filename, mtd);
buf = malloc(erasesize);
if (!buf) {
fprintf(stderr, "Out of memory!\n");
goto done;
}
if (!*dir)
target_ino = 1;
/* parse the structure of the jffs2 first
* locate the directory that the file is going to be placed in */
for(;;) {
struct jffs2_unknown_node *node = (struct jffs2_unknown_node *) buf;
if (read(outfd, buf, erasesize) != erasesize) {
fdeof = 1;
break;
}
mtdofs += erasesize;
if (node->magic == 0x8519) {
fprintf(stderr, "Error: wrong endianness filesystem\n");
goto done;
}
/* assume no magic == end of filesystem
* the filesystem will probably end with be32(0xdeadc0de) */
if (node->magic != 0x1985)
break;
mtd_parse_jffs2data(buf, dir);
}
if (fdeof) {
fprintf(stderr, "Error: No room for additional data\n");
goto done;
}
/* jump back one eraseblock */
mtdofs -= erasesize;
lseek(outfd, mtdofs, SEEK_SET);
ofs = 0;
if (!last_ino)
last_ino = 1;
if (!target_ino)
target_ino = add_dir(dir, 1);
add_file(filename, target_ino);
pad(erasesize);
/* add eof marker, pad to eraseblock size and write the data */
add_data(JFFS2_EOF, sizeof(JFFS2_EOF) - 1);
pad(erasesize);
err = 0;
if (trx_fixup) {
trx_fixup(outfd, mtd);
}
done:
close(outfd);
if (buf)
free(buf);
return err;
}

View File

@@ -0,0 +1,216 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in the
* jffs2 directory.
*
*
*/
#ifndef __LINUX_JFFS2_H__
#define __LINUX_JFFS2_H__
#define JFFS2_SUPER_MAGIC 0x72b6
/* You must include something which defines the C99 uintXX_t types.
We don't do it from here because this file is used in too many
different environments. */
/* Values we may expect to find in the 'magic' field */
#define JFFS2_OLD_MAGIC_BITMASK 0x1984
#define JFFS2_MAGIC_BITMASK 0x1985
#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */
#define JFFS2_EMPTY_BITMASK 0xffff
#define JFFS2_DIRTY_BITMASK 0x0000
/* Summary node MAGIC marker */
#define JFFS2_SUM_MAGIC 0x02851885
/* We only allow a single char for length, and 0xFF is empty flash so
we don't want it confused with a real length. Hence max 254.
*/
#define JFFS2_MAX_NAME_LEN 254
/* How small can we sensibly write nodes? */
#define JFFS2_MIN_DATA_LEN 128
#define JFFS2_COMPR_NONE 0x00
#define JFFS2_COMPR_ZERO 0x01
#define JFFS2_COMPR_RTIME 0x02
#define JFFS2_COMPR_RUBINMIPS 0x03
#define JFFS2_COMPR_COPY 0x04
#define JFFS2_COMPR_DYNRUBIN 0x05
#define JFFS2_COMPR_ZLIB 0x06
/* Compatibility flags. */
#define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */
#define JFFS2_NODE_ACCURATE 0x2000
/* INCOMPAT: Fail to mount the filesystem */
#define JFFS2_FEATURE_INCOMPAT 0xc000
/* ROCOMPAT: Mount read-only */
#define JFFS2_FEATURE_ROCOMPAT 0x8000
/* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */
#define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000
/* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */
#define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000
#define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1)
#define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2)
#define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4)
#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6)
#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8)
#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9)
/* XATTR Related */
#define JFFS2_XPREFIX_USER 1 /* for "user." */
#define JFFS2_XPREFIX_SECURITY 2 /* for "security." */
#define JFFS2_XPREFIX_ACL_ACCESS 3 /* for "system.posix_acl_access" */
#define JFFS2_XPREFIX_ACL_DEFAULT 4 /* for "system.posix_acl_default" */
#define JFFS2_XPREFIX_TRUSTED 5 /* for "trusted.*" */
#define JFFS2_ACL_VERSION 0x0001
// Maybe later...
//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
#define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at
mount time, don't wait for it to
happen later */
#define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific
compression type */
/* These can go once we've made sure we've caught all uses without
byteswapping */
typedef uint32_t jint32_t;
typedef uint32_t jmode_t;
typedef uint16_t jint16_t;
struct jffs2_unknown_node
{
/* All start like this */
jint16_t magic;
jint16_t nodetype;
jint32_t totlen; /* So we can skip over nodes we don't grok */
jint32_t hdr_crc;
};
struct jffs2_raw_dirent
{
jint16_t magic;
jint16_t nodetype; /* == JFFS2_NODETYPE_DIRENT */
jint32_t totlen;
jint32_t hdr_crc;
jint32_t pino;
jint32_t version;
jint32_t ino; /* == zero for unlink */
jint32_t mctime;
uint8_t nsize;
uint8_t type;
uint8_t unused[2];
jint32_t node_crc;
jint32_t name_crc;
uint8_t name[0];
};
/* The JFFS2 raw inode structure: Used for storage on physical media. */
/* The uid, gid, atime, mtime and ctime members could be longer, but
are left like this for space efficiency. If and when people decide
they really need them extended, it's simple enough to add support for
a new type of raw node.
*/
struct jffs2_raw_inode
{
jint16_t magic; /* A constant magic number. */
jint16_t nodetype; /* == JFFS2_NODETYPE_INODE */
jint32_t totlen; /* Total length of this node (inc data, etc.) */
jint32_t hdr_crc;
jint32_t ino; /* Inode number. */
jint32_t version; /* Version number. */
jmode_t mode; /* The file's type or mode. */
jint16_t uid; /* The file's owner. */
jint16_t gid; /* The file's group. */
jint32_t isize; /* Total resultant size of this inode (used for truncations) */
jint32_t atime; /* Last access time. */
jint32_t mtime; /* Last modification time. */
jint32_t ctime; /* Change time. */
jint32_t offset; /* Where to begin to write. */
jint32_t csize; /* (Compressed) data size */
jint32_t dsize; /* Size of the node's data. (after decompression) */
uint8_t compr; /* Compression algorithm used */
uint8_t usercompr; /* Compression algorithm requested by the user */
jint16_t flags; /* See JFFS2_INO_FLAG_* */
jint32_t data_crc; /* CRC for the (compressed) data. */
jint32_t node_crc; /* CRC for the raw inode (excluding data) */
uint8_t data[0];
};
struct jffs2_raw_xattr {
jint16_t magic;
jint16_t nodetype; /* = JFFS2_NODETYPE_XATTR */
jint32_t totlen;
jint32_t hdr_crc;
jint32_t xid; /* XATTR identifier number */
jint32_t version;
uint8_t xprefix;
uint8_t name_len;
jint16_t value_len;
jint32_t data_crc;
jint32_t node_crc;
uint8_t data[0];
} __attribute__((packed));
struct jffs2_raw_xref
{
jint16_t magic;
jint16_t nodetype; /* = JFFS2_NODETYPE_XREF */
jint32_t totlen;
jint32_t hdr_crc;
jint32_t ino; /* inode number */
jint32_t xid; /* XATTR identifier number */
jint32_t xseqno; /* xref sequencial number */
jint32_t node_crc;
} __attribute__((packed));
struct jffs2_raw_summary
{
jint16_t magic;
jint16_t nodetype; /* = JFFS2_NODETYPE_SUMMARY */
jint32_t totlen;
jint32_t hdr_crc;
jint32_t sum_num; /* number of sum entries*/
jint32_t cln_mkr; /* clean marker size, 0 = no cleanmarker */
jint32_t padded; /* sum of the size of padding nodes */
jint32_t sum_crc; /* summary information crc */
jint32_t node_crc; /* node crc */
jint32_t sum[0]; /* inode summary info */
};
union jffs2_node_union
{
struct jffs2_raw_inode i;
struct jffs2_raw_dirent d;
struct jffs2_raw_xattr x;
struct jffs2_raw_xref r;
struct jffs2_raw_summary s;
struct jffs2_unknown_node u;
};
/* Data payload for device nodes. */
union jffs2_device_node {
jint16_t old;
jint32_t new;
};
#endif /* __LINUX_JFFS2_H__ */

View File

@@ -0,0 +1,307 @@
/*
***********************************************************************
** md5.c -- the source code for MD5 routines **
** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
** Created: 2/17/90 RLR **
** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **
***********************************************************************
*/
/*
***********************************************************************
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
** **
** License to copy and use this software is granted provided that **
** it is identified as the "RSA Data Security, Inc. MD5 Message- **
** Digest Algorithm" in all material mentioning or referencing this **
** software or this function. **
** **
** License is also granted to make and use derivative works **
** provided that such works are identified as "derived from the RSA **
** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
** material mentioning or referencing the derived work. **
** **
** RSA Data Security, Inc. makes no representations concerning **
** either the merchantability of this software or the suitability **
** of this software for any particular purpose. It is provided "as **
** is" without express or implied warranty of any kind. **
** **
** These notices must be retained in any copies of any part of this **
** documentation and/or software. **
***********************************************************************
*/
#include <string.h>
#include "md5.h"
/*
***********************************************************************
** Message-digest routines: **
** To form the message digest for a message M **
** (1) Initialize a context buffer mdContext using MD5_Init **
** (2) Call MD5_Update on mdContext and M **
** (3) Call MD5_Final on mdContext **
** The message digest is now in mdContext->digest[0...15] **
***********************************************************************
*/
/* forward declaration */
static void Transform ();
static unsigned char PADDING[64] = {
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/* F, G, H and I are basic MD5 functions */
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
/* Rotation is separate from addition to prevent recomputation */
#define FF(a, b, c, d, x, s, ac) \
{(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) \
{(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) \
{(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) \
{(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#ifdef __STDC__
#define UL(x) x##U
#else
#define UL(x) x
#endif
/* The routine MD5_Init initializes the message-digest context
mdContext. All fields are set to zero.
*/
void MD5_Init (mdContext)
MD5_CTX *mdContext;
{
mdContext->i[0] = mdContext->i[1] = (UINT4)0;
/* Load magic initialization constants.
*/
mdContext->buf[0] = (UINT4)0x67452301;
mdContext->buf[1] = (UINT4)0xefcdab89;
mdContext->buf[2] = (UINT4)0x98badcfe;
mdContext->buf[3] = (UINT4)0x10325476;
}
/* The routine MD5Update updates the message-digest context to
account for the presence of each of the characters inBuf[0..inLen-1]
in the message whose digest is being computed.
*/
void MD5_Update (mdContext, inBuf, inLen)
MD5_CTX *mdContext;
unsigned char *inBuf;
unsigned int inLen;
{
UINT4 in[16];
int mdi;
unsigned int i, ii;
/* compute number of bytes mod 64 */
mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
/* update number of bits */
if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
mdContext->i[1]++;
mdContext->i[0] += ((UINT4)inLen << 3);
mdContext->i[1] += ((UINT4)inLen >> 29);
while (inLen--) {
/* add new character to buffer, increment mdi */
mdContext->in[mdi++] = *inBuf++;
/* transform if necessary */
if (mdi == 0x40) {
for (i = 0, ii = 0; i < 16; i++, ii += 4)
in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
(((UINT4)mdContext->in[ii+2]) << 16) |
(((UINT4)mdContext->in[ii+1]) << 8) |
((UINT4)mdContext->in[ii]);
Transform (mdContext->buf, in);
mdi = 0;
}
}
}
/* The routine MD5Final terminates the message-digest computation and
ends with the desired message digest in mdContext->digest[0...15].
*/
void MD5_Final (hash, mdContext)
unsigned char hash[];
MD5_CTX *mdContext;
{
UINT4 in[16];
int mdi;
unsigned int i, ii;
unsigned int padLen;
/* save number of bits */
in[14] = mdContext->i[0];
in[15] = mdContext->i[1];
/* compute number of bytes mod 64 */
mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
/* pad out to 56 mod 64 */
padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
MD5_Update (mdContext, PADDING, padLen);
/* append length in bits and transform */
for (i = 0, ii = 0; i < 14; i++, ii += 4)
in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
(((UINT4)mdContext->in[ii+2]) << 16) |
(((UINT4)mdContext->in[ii+1]) << 8) |
((UINT4)mdContext->in[ii]);
Transform (mdContext->buf, in);
/* store buffer in digest */
for (i = 0, ii = 0; i < 4; i++, ii += 4) {
mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
mdContext->digest[ii+1] =
(unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
mdContext->digest[ii+2] =
(unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
mdContext->digest[ii+3] =
(unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
}
memcpy(hash, mdContext->digest, 16);
}
/* Basic MD5 step. Transforms buf based on in.
*/
static void Transform (buf, in)
UINT4 *buf;
UINT4 *in;
{
UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
/* Round 1 */
#define S11 7
#define S12 12
#define S13 17
#define S14 22
FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */
FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */
FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */
FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */
FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */
FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */
FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */
FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */
FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */
FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */
FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */
FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */
FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */
FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */
FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */
FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */
/* Round 2 */
#define S21 5
#define S22 9
#define S23 14
#define S24 20
GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */
GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */
GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */
GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */
GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */
GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */
GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */
GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */
GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */
GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */
GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */
GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */
GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */
GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */
GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */
GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */
/* Round 3 */
#define S31 4
#define S32 11
#define S33 16
#define S34 23
HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */
HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */
HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */
HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */
HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */
HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */
HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */
HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */
HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */
HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */
HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */
HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */
HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */
HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */
HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */
HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */
/* Round 4 */
#define S41 6
#define S42 10
#define S43 15
#define S44 21
II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */
II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */
II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */
II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */
II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */
II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */
II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */
II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */
II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */
II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */
II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */
II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */
II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */
II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */
II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */
II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
/*
***********************************************************************
** End of md5.c **
******************************** (cut) ********************************
*/

View File

@@ -0,0 +1,65 @@
/*
***********************************************************************
** md5.h -- header file for implementation of MD5 **
** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
** Created: 2/17/90 RLR **
** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
** Revised (for MD5): RLR 4/27/91 **
** -- G modified to have y&~z instead of y&z **
** -- FF, GG, HH modified to add in last register done **
** -- Access pattern: round 2 works mod 5, round 3 works mod 3 **
** -- distinct additive constant for each step **
** -- round 4 added, working mod 7 **
***********************************************************************
*/
/*
***********************************************************************
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
** **
** License to copy and use this software is granted provided that **
** it is identified as the "RSA Data Security, Inc. MD5 Message- **
** Digest Algorithm" in all material mentioning or referencing this **
** software or this function. **
** **
** License is also granted to make and use derivative works **
** provided that such works are identified as "derived from the RSA **
** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
** material mentioning or referencing the derived work. **
** **
** RSA Data Security, Inc. makes no representations concerning **
** either the merchantability of this software or the suitability **
** of this software for any particular purpose. It is provided "as **
** is" without express or implied warranty of any kind. **
** **
** These notices must be retained in any copies of any part of this **
** documentation and/or software. **
***********************************************************************
*/
#ifndef __MD5_INCLUDE__
/* typedef a 32-bit type */
#ifdef _LP64
typedef unsigned int UINT4;
typedef int INT4;
#else
typedef unsigned long UINT4;
typedef long INT4;
#endif
#define _UINT4_T
/* Data structure for MD5 (Message-Digest) computation */
typedef struct {
UINT4 i[2]; /* number of _bits_ handled mod 2^64 */
UINT4 buf[4]; /* scratch buffer */
unsigned char in[64]; /* input buffer */
unsigned char digest[16]; /* actual digest after MD5Final call */
} MD5_CTX;
void MD5_Init ();
void MD5_Update ();
void MD5_Final ();
#define __MD5_INCLUDE__
#endif /* __MD5_INCLUDE__ */

View File

@@ -0,0 +1,761 @@
/*
* mtd - simple memory technology device manipulation tool
*
* Copyright (C) 2005 Waldemar Brodkorb <wbx@dass-it.de>,
* Copyright (C) 2005-2009 Felix Fietkau <nbd@openwrt.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
* The code is based on the linux-mtd examples.
*/
#include <limits.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/reboot.h>
#include <linux/reboot.h>
#include <mtd/mtd-user.h>
#include "fis.h"
#include "mtd.h"
#ifndef MTDREFRESH
#define MTDREFRESH _IO('M', 50)
#endif
#define MAX_ARGS 8
#define JFFS2_DEFAULT_DIR "" /* directory name without /, empty means root dir */
static char *buf = NULL;
static char *imagefile = NULL;
static char *jffs2file = NULL, *jffs2dir = JFFS2_DEFAULT_DIR;
static int buflen = 0;
int quiet;
int no_erase;
int mtdsize = 0;
int erasesize = 0;
int mtd_open(const char *mtd, bool block)
{
FILE *fp;
char dev[PATH_MAX];
int i;
int ret;
int flags = O_RDWR | O_SYNC;
if ((fp = fopen("/proc/mtd", "r"))) {
while (fgets(dev, sizeof(dev), fp)) {
if (sscanf(dev, "mtd%d:", &i) && strstr(dev, mtd)) {
snprintf(dev, sizeof(dev), "/dev/mtd%s/%d", (block ? "block" : ""), i);
if ((ret=open(dev, flags))<0) {
snprintf(dev, sizeof(dev), "/dev/mtd%s%d", (block ? "block" : ""), i);
ret=open(dev, flags);
}
fclose(fp);
return ret;
}
}
fclose(fp);
}
return open(mtd, flags);
}
int mtd_check_open(const char *mtd)
{
struct mtd_info_user mtdInfo;
int fd;
fd = mtd_open(mtd, false);
if(fd < 0) {
fprintf(stderr, "Could not open mtd device: %s\n", mtd);
return -1;
}
if(ioctl(fd, MEMGETINFO, &mtdInfo)) {
fprintf(stderr, "Could not get MTD device info from %s\n", mtd);
close(fd);
return -1;
}
mtdsize = mtdInfo.size;
erasesize = mtdInfo.erasesize;
return fd;
}
int mtd_erase_block(int fd, int offset)
{
struct erase_info_user mtdEraseInfo;
mtdEraseInfo.start = offset;
mtdEraseInfo.length = erasesize;
ioctl(fd, MEMUNLOCK, &mtdEraseInfo);
if (ioctl (fd, MEMERASE, &mtdEraseInfo) < 0)
return -1;
return 0;
}
int mtd_write_buffer(int fd, const char *buf, int offset, int length)
{
lseek(fd, offset, SEEK_SET);
write(fd, buf, length);
return 0;
}
static int
image_check(int imagefd, const char *mtd)
{
int ret = 1;
if (trx_check) {
ret = trx_check(imagefd, mtd, buf, &buflen);
}
return ret;
}
static int mtd_check(const char *mtd)
{
char *next = NULL;
char *str = NULL;
int fd;
if (strchr(mtd, ':')) {
str = strdup(mtd);
mtd = str;
}
do {
next = strchr(mtd, ':');
if (next) {
*next = 0;
next++;
}
fd = mtd_check_open(mtd);
if (fd < 0)
return 0;
if (!buf)
buf = malloc(erasesize);
close(fd);
mtd = next;
} while (next);
if (str)
free(str);
return 1;
}
static int
mtd_unlock(const char *mtd)
{
struct erase_info_user mtdLockInfo;
char *next = NULL;
char *str = NULL;
int fd;
if (strchr(mtd, ':')) {
str = strdup(mtd);
mtd = str;
}
do {
next = strchr(mtd, ':');
if (next) {
*next = 0;
next++;
}
fd = mtd_check_open(mtd);
if(fd < 0) {
fprintf(stderr, "Could not open mtd device: %s\n", mtd);
exit(1);
}
if (quiet < 2)
fprintf(stderr, "Unlocking %s ...\n", mtd);
mtdLockInfo.start = 0;
mtdLockInfo.length = mtdsize;
ioctl(fd, MEMUNLOCK, &mtdLockInfo);
close(fd);
mtd = next;
} while (next);
if (str)
free(str);
return 0;
}
static int
mtd_erase(const char *mtd)
{
int fd;
struct erase_info_user mtdEraseInfo;
if (quiet < 2)
fprintf(stderr, "Erasing %s ...\n", mtd);
fd = mtd_check_open(mtd);
if(fd < 0) {
fprintf(stderr, "Could not open mtd device: %s\n", mtd);
exit(1);
}
mtdEraseInfo.length = erasesize;
for (mtdEraseInfo.start = 0;
mtdEraseInfo.start < mtdsize;
mtdEraseInfo.start += erasesize) {
ioctl(fd, MEMUNLOCK, &mtdEraseInfo);
if(ioctl(fd, MEMERASE, &mtdEraseInfo))
fprintf(stderr, "Failed to erase block on %s at 0x%x\n", mtd, mtdEraseInfo.start);
}
close(fd);
return 0;
}
static int
mtd_refresh(const char *mtd)
{
int fd;
if (quiet < 2)
fprintf(stderr, "Refreshing mtd partition %s ... ", mtd);
fd = mtd_check_open(mtd);
if(fd < 0) {
fprintf(stderr, "Could not open mtd device: %s\n", mtd);
exit(1);
}
if (ioctl(fd, MTDREFRESH, NULL)) {
fprintf(stderr, "Failed to refresh the MTD device\n");
close(fd);
exit(1);
}
close(fd);
if (quiet < 2)
fprintf(stderr, "\n");
return 0;
}
static void
indicate_writing(const char *mtd)
{
if (quiet < 2)
fprintf(stderr, "\nWriting from %s to %s ... ", imagefile, mtd);
if (!quiet)
fprintf(stderr, " [ ]");
}
static int
mtd_write(int imagefd, const char *mtd, char *fis_layout, size_t part_offset)
{
char *next = NULL;
char *str = NULL;
int fd, result;
ssize_t r, w, e;
ssize_t skip = 0;
uint32_t offset = 0;
int jffs2_replaced = 0;
#ifdef FIS_SUPPORT
static struct fis_part new_parts[MAX_ARGS];
static struct fis_part old_parts[MAX_ARGS];
int n_new = 0, n_old = 0;
if (fis_layout) {
const char *tmp = mtd;
char *word, *brkt;
int ret;
memset(&old_parts, 0, sizeof(old_parts));
memset(&new_parts, 0, sizeof(new_parts));
do {
next = strchr(tmp, ':');
if (!next)
next = (char *) tmp + strlen(tmp);
memcpy(old_parts[n_old].name, tmp, next - tmp);
n_old++;
tmp = next + 1;
} while(*next);
for (word = strtok_r(fis_layout, ",", &brkt);
word;
word = strtok_r(NULL, ",", &brkt)) {
tmp = strtok(word, ":");
strncpy((char *) new_parts[n_new].name, tmp, sizeof(new_parts[n_new].name) - 1);
tmp = strtok(NULL, ":");
if (!tmp)
goto next;
new_parts[n_new].size = strtoul(tmp, NULL, 0);
tmp = strtok(NULL, ":");
if (!tmp)
goto next;
new_parts[n_new].loadaddr = strtoul(tmp, NULL, 16);
next:
n_new++;
}
ret = fis_validate(old_parts, n_old, new_parts, n_new);
if (ret < 0) {
fprintf(stderr, "Failed to validate the new FIS partition table\n");
exit(1);
}
if (ret == 0)
fis_layout = NULL;
}
#endif
if (strchr(mtd, ':')) {
str = strdup(mtd);
mtd = str;
}
r = 0;
resume:
next = strchr(mtd, ':');
if (next) {
*next = 0;
next++;
}
fd = mtd_check_open(mtd);
if(fd < 0) {
fprintf(stderr, "Could not open mtd device: %s\n", mtd);
exit(1);
}
if (part_offset > 0) {
fprintf(stderr, "Seeking on mtd device '%s' to: %u\n", mtd, part_offset);
lseek(fd, part_offset, SEEK_SET);
}
indicate_writing(mtd);
w = e = 0;
for (;;) {
/* buffer may contain data already (from trx check or last mtd partition write attempt) */
while (buflen < erasesize) {
r = read(imagefd, buf + buflen, erasesize - buflen);
if (r < 0) {
if ((errno == EINTR) || (errno == EAGAIN))
continue;
else {
perror("read");
break;
}
}
if (r == 0)
break;
buflen += r;
}
if (buflen == 0)
break;
if (skip > 0) {
skip -= buflen;
buflen = 0;
if (skip <= 0)
indicate_writing(mtd);
continue;
}
if (jffs2file) {
if (memcmp(buf, JFFS2_EOF, sizeof(JFFS2_EOF) - 1) == 0) {
if (!quiet)
fprintf(stderr, "\b\b\b ");
if (quiet < 2)
fprintf(stderr, "\nAppending jffs2 data from %s to %s...", jffs2file, mtd);
/* got an EOF marker - this is the place to add some jffs2 data */
skip = mtd_replace_jffs2(mtd, fd, e, jffs2file);
jffs2_replaced = 1;
/* don't add it again */
jffs2file = NULL;
w += skip;
e += skip;
skip -= buflen;
buflen = 0;
offset = 0;
continue;
}
/* no EOF marker, make sure we figure out the last inode number
* before appending some data */
mtd_parse_jffs2data(buf, jffs2dir);
}
/* need to erase the next block before writing data to it */
if(!no_erase)
{
while (w + buflen > e) {
if (!quiet)
fprintf(stderr, "\b\b\b[e]");
if (mtd_erase_block(fd, e) < 0) {
if (next) {
if (w < e) {
write(fd, buf + offset, e - w);
offset = e - w;
}
w = 0;
e = 0;
close(fd);
mtd = next;
fprintf(stderr, "\b\b\b \n");
goto resume;
} else {
fprintf(stderr, "Failed to erase block\n");
exit(1);
}
}
/* erase the chunk */
e += erasesize;
}
}
if (!quiet)
fprintf(stderr, "\b\b\b[w]");
if ((result = write(fd, buf + offset, buflen)) < buflen) {
if (result < 0) {
fprintf(stderr, "Error writing image.\n");
exit(1);
} else {
fprintf(stderr, "Insufficient space.\n");
exit(1);
}
}
w += buflen;
buflen = 0;
offset = 0;
}
if (jffs2_replaced && trx_fixup) {
trx_fixup(fd, mtd);
}
if (!quiet)
fprintf(stderr, "\b\b\b\b ");
done:
if (quiet < 2)
fprintf(stderr, "\n");
#ifdef FIS_SUPPORT
if (fis_layout) {
if (fis_remap(old_parts, n_old, new_parts, n_new) < 0)
fprintf(stderr, "Failed to update the FIS partition table\n");
}
#endif
close(fd);
return 0;
}
static void usage(void)
{
fprintf(stderr, "Usage: mtd [<options> ...] <command> [<arguments> ...] <device>[:<device>...]\n\n"
"The device is in the format of mtdX (eg: mtd4) or its label.\n"
"mtd recognizes these commands:\n"
" unlock unlock the device\n"
" refresh refresh mtd partition\n"
" erase erase all data on device\n"
" write <imagefile>|- write <imagefile> (use - for stdin) to device\n"
" jffs2write <file> append <file> to the jffs2 partition on the device\n");
if (mtd_fixtrx) {
fprintf(stderr,
" fixtrx fix the checksum in a trx header on first boot\n");
}
if (mtd_fixseama) {
fprintf(stderr,
" fixseama fix the checksum in a seama header on first boot\n");
}
fprintf(stderr,
"Following options are available:\n"
" -q quiet mode (once: no [w] on writing,\n"
" twice: no status messages)\n"
" -n write without first erasing the blocks\n"
" -r reboot after successful command\n"
" -f force write without trx checks\n"
" -e <device> erase <device> before executing the command\n"
" -d <name> directory for jffs2write, defaults to \"tmp\"\n"
" -j <name> integrate <file> into jffs2 data when writing an image\n"
" -p write beginning at partition offset\n");
if (mtd_fixtrx) {
fprintf(stderr,
" -o offset offset of the image header in the partition(for fixtrx)\n");
}
fprintf(stderr,
#ifdef FIS_SUPPORT
" -F <part>[:<size>[:<entrypoint>]][,<part>...]\n"
" alter the fis partition table to create new partitions replacing\n"
" the partitions provided as argument to the write command\n"
" (only valid together with the write command)\n"
#endif
"\n"
"Example: To write linux.trx to mtd4 labeled as linux and reboot afterwards\n"
" mtd -r write linux.trx linux\n\n");
exit(1);
}
static void do_reboot(void)
{
fprintf(stderr, "Rebooting ...\n");
fflush(stderr);
/* try regular reboot method first */
system("/sbin/reboot");
sleep(2);
/* if we're still alive at this point, force the kernel to reboot */
syscall(SYS_reboot,LINUX_REBOOT_MAGIC1,LINUX_REBOOT_MAGIC2,LINUX_REBOOT_CMD_RESTART,NULL);
}
int main (int argc, char **argv)
{
int ch, i, boot, imagefd = 0, force, unlocked;
char *erase[MAX_ARGS], *device = NULL;
char *fis_layout = NULL;
size_t offset = 0, part_offset = 0;
enum {
CMD_ERASE,
CMD_WRITE,
CMD_UNLOCK,
CMD_REFRESH,
CMD_JFFS2WRITE,
CMD_FIXTRX,
CMD_FIXSEAMA,
} cmd = -1;
erase[0] = NULL;
boot = 0;
force = 0;
buflen = 0;
quiet = 0;
no_erase = 0;
while ((ch = getopt(argc, argv,
#ifdef FIS_SUPPORT
"F:"
#endif
"frnqe:d:j:p:o:")) != -1)
switch (ch) {
case 'f':
force = 1;
break;
case 'r':
boot = 1;
break;
case 'n':
no_erase = 1;
break;
case 'j':
jffs2file = optarg;
break;
case 'q':
quiet++;
break;
case 'e':
i = 0;
while ((erase[i] != NULL) && ((i + 1) < MAX_ARGS))
i++;
erase[i++] = optarg;
erase[i] = NULL;
break;
case 'd':
jffs2dir = optarg;
break;
case 'p':
errno = 0;
part_offset = strtoul(optarg, 0, 0);
if (errno) {
fprintf(stderr, "-p: illegal numeric string\n");
usage();
}
break;
case 'o':
if (!mtd_fixtrx) {
fprintf(stderr, "-o: is not available on this platform\n");
usage();
}
errno = 0;
offset = strtoul(optarg, 0, 0);
if (errno) {
fprintf(stderr, "-o: illegal numeric string\n");
usage();
}
break;
#ifdef FIS_SUPPORT
case 'F':
fis_layout = optarg;
break;
#endif
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc < 2)
usage();
if ((strcmp(argv[0], "unlock") == 0) && (argc == 2)) {
cmd = CMD_UNLOCK;
device = argv[1];
} else if ((strcmp(argv[0], "refresh") == 0) && (argc == 2)) {
cmd = CMD_REFRESH;
device = argv[1];
} else if ((strcmp(argv[0], "erase") == 0) && (argc == 2)) {
cmd = CMD_ERASE;
device = argv[1];
} else if (((strcmp(argv[0], "fixtrx") == 0) && (argc == 2)) && mtd_fixtrx) {
cmd = CMD_FIXTRX;
device = argv[1];
} else if (((strcmp(argv[0], "fixseama") == 0) && (argc == 2)) && mtd_fixseama) {
cmd = CMD_FIXSEAMA;
device = argv[1];
} else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) {
cmd = CMD_WRITE;
device = argv[2];
if (strcmp(argv[1], "-") == 0) {
imagefile = "<stdin>";
imagefd = 0;
} else {
imagefile = argv[1];
if ((imagefd = open(argv[1], O_RDONLY)) < 0) {
fprintf(stderr, "Couldn't open image file: %s!\n", imagefile);
exit(1);
}
}
if (!mtd_check(device)) {
fprintf(stderr, "Can't open device for writing!\n");
exit(1);
}
/* check trx file before erasing or writing anything */
if (!image_check(imagefd, device) && !force) {
fprintf(stderr, "Image check failed.\n");
exit(1);
}
} else if ((strcmp(argv[0], "jffs2write") == 0) && (argc == 3)) {
cmd = CMD_JFFS2WRITE;
device = argv[2];
imagefile = argv[1];
if (!mtd_check(device)) {
fprintf(stderr, "Can't open device for writing!\n");
exit(1);
}
} else {
usage();
}
sync();
i = 0;
unlocked = 0;
while (erase[i] != NULL) {
mtd_unlock(erase[i]);
mtd_erase(erase[i]);
if (strcmp(erase[i], device) == 0)
unlocked = 1;
i++;
}
switch (cmd) {
case CMD_UNLOCK:
if (!unlocked)
mtd_unlock(device);
break;
case CMD_ERASE:
if (!unlocked)
mtd_unlock(device);
mtd_erase(device);
break;
case CMD_WRITE:
if (!unlocked)
mtd_unlock(device);
mtd_write(imagefd, device, fis_layout, part_offset);
break;
case CMD_JFFS2WRITE:
if (!unlocked)
mtd_unlock(device);
mtd_write_jffs2(device, imagefile, jffs2dir);
break;
case CMD_REFRESH:
mtd_refresh(device);
break;
case CMD_FIXTRX:
if (mtd_fixtrx) {
mtd_fixtrx(device, offset);
}
case CMD_FIXSEAMA:
if (mtd_fixseama)
mtd_fixseama(device, 0);
break;
}
sync();
if (boot)
do_reboot();
return 0;
}

View File

@@ -0,0 +1,29 @@
#ifndef __mtd_h
#define __mtd_h
#include <stdbool.h>
#ifdef target_brcm47xx
#define target_brcm 1
#endif
#define JFFS2_EOF "\xde\xad\xc0\xde"
extern int quiet;
extern int mtdsize;
extern int erasesize;
extern int mtd_open(const char *mtd, bool block);
extern int mtd_check_open(const char *mtd);
extern int mtd_erase_block(int fd, int offset);
extern int mtd_write_buffer(int fd, const char *buf, int offset, int length);
extern int mtd_write_jffs2(const char *mtd, const char *filename, const char *dir);
extern int mtd_replace_jffs2(const char *mtd, int fd, int ofs, const char *filename);
extern void mtd_parse_jffs2data(const char *buf, const char *dir);
/* target specific functions */
extern int trx_fixup(int fd, const char *name) __attribute__ ((weak));
extern int trx_check(int imagefd, const char *mtd, char *buf, int *len) __attribute__ ((weak));
extern int mtd_fixtrx(const char *mtd, size_t offset) __attribute__ ((weak));
extern int mtd_fixseama(const char *mtd, size_t offset) __attribute__ ((weak));
#endif /* __mtd_h */

View File

@@ -0,0 +1,179 @@
/*
* seama.c
*
* Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
*
* Based on the trx fixup code:
* Copyright (C) 2005 Mike Baker
* Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <mtd/mtd-user.h>
#include "mtd.h"
#include "seama.h"
#include "md5.h"
#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
seama_fix_md5(char *buf, size_t len)
{
struct seama_hdr *shdr;
char *data;
size_t msize;
size_t isize;
MD5_CTX ctx;
unsigned char digest[16];
int i;
if (len < sizeof(struct seama_hdr))
return -1;
shdr = (struct seama_hdr *) buf;
if (shdr->magic != htonl(SEAMA_MAGIC)) {
fprintf(stderr, "no SEAMA header found\n");
return -1;
}
isize = ntohl(shdr->size);
msize = ntohs(shdr->metasize);
if (isize == 0) {
/* the image contains no checksum */
return -1;
}
len -= sizeof(struct seama_hdr) + sizeof(digest) + msize;
if (isize > len)
isize = len;
data = buf + sizeof(struct seama_hdr) + sizeof(digest) + msize;
MD5_Init(&ctx);
MD5_Update(&ctx, data, isize);
MD5_Final(digest, &ctx);
if (!memcmp(digest, &buf[sizeof(struct seama_hdr)], sizeof(digest))) {
if (quiet < 2)
fprintf(stderr, "the header is fixed already\n");
return -1;
}
if (quiet < 2) {
fprintf(stderr, "new size:%u, new MD5: ", isize);
for (i = 0; i < sizeof(digest); i++)
fprintf(stderr, "%02x", digest[i]);
fprintf(stderr, "\n");
}
/* update the size in the image */
shdr->size = htonl(isize);
/* update the checksum in the image */
for (i = 0; i < sizeof(digest); i++)
buf[sizeof(struct seama_hdr) + i] = digest[i];
return 0;
}
int
mtd_fixseama(const char *mtd, size_t offset)
{
int fd;
char *buf;
ssize_t res;
size_t block_offset;
if (quiet < 2)
fprintf(stderr, "Trying to fix SEAMA 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(mtdsize);
if (!buf) {
perror("malloc");
exit(1);
}
res = pread(fd, buf, mtdsize, block_offset);
if (res != mtdsize) {
perror("pread");
exit(1);
}
if (seama_fix_md5(buf, mtdsize))
goto out;
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, "Rewriting block at 0x%x\n", block_offset);
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");
out:
close (fd);
sync();
return 0;
}

View File

@@ -0,0 +1,108 @@
/* vi: set sw=4 ts=4: */
/*
* (SEA)ttle i(MA)ge is the image which used in project seattle.
*
* Created by David Hsieh <david_hsieh@alphanetworks.com>
* Copyright (C) 2008-2009 Alpha Networks, Inc.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either'
* version 2.1 of the License, or (at your option) any later version.
*
* The GNU C Library is distributed in the hope that it will be useful,'
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the GNU C Library; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA.
*/
#ifndef __SEAMA_HEADER_FILE__
#define __SEAMA_HEADER_FILE__
#include <stdint.h>
#define SEAMA_MAGIC 0x5EA3A417
/*
* SEAMA looks like the following map.
* All the data of the header should be in network byte order.
*
* +-------------+-------------+------------
* | SEAMA magic | ^
* +-------------+-------------+ |
* | reserved | meta size | |
* +-------------+-------------+ header
* | image size (0 bytes) | |
* +-------------+-------------+ |
* ~ Meta data ~ v
* +-------------+-------------+------------
* | SEAMA magic | ^ ^
* +-------------+-------------+ | |
* | reserved | meta size | | |
* +-------------+-------------+ | |
* | image size | | |
* +-------------+-------------+ header |
* | | | |
* | 16 bytes of MD5 digest | | |
* | | | |
* | | | |
* +-------------+-------------+ | |
* ~ Meta data ~ v |
* +-------------+-------------+------- |
* | | |
* | Image of the 1st entity | |
* ~ ~ 1st entity
* | | |
* | | v
* +-------------+-------------+-------------
* | SEAMA magic | ^ ^
* +-------------+-------------+ | |
* | reserved | meta size | | |
* +-------------+-------------+ | |
* | image size | | |
* +-------------+-------------+ header |
* | | | |
* | 16 bytes of MD5 digest | | |
* | | | |
* | | | |
* +-------------+-------------+ | |
* ~ Meta data ~ v |
* +-------------+-------------+------- |
* | | |
* | Image of the 2nd entity | |
* ~ ~ 2nd entity
* | | |
* | | v
* +-------------+-------------+-------------
*/
/*
* SEAMA header
*
* |<-------- 32 bits -------->|
* +-------------+-------------+
* | SEAMA magic |
* +-------------+-------------+
* | reserved | meta size |
* +-------------+-------------+
* | image size |
* +-------------+-------------+
*/
/* seama header */
typedef struct seama_hdr seamahdr_t;
struct seama_hdr
{
uint32_t magic; /* should always be SEAMA_MAGIC. */
uint16_t reserved; /* reserved for */
uint16_t metasize; /* size of the META data */
uint32_t size; /* size of the image */
} __attribute__ ((packed));
#endif

View File

@@ -0,0 +1,220 @@
/*
* trx.c
*
* Copyright (C) 2005 Mike Baker
* Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <mtd/mtd-user.h>
#include "mtd.h"
#include "crc32.h"
#define TRX_MAGIC 0x30524448 /* "HDR0" */
struct trx_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)
{
struct mtd_info_user mtdInfo;
unsigned long len;
struct trx_header *trx;
void *ptr, *scan;
int bfd;
if (ioctl(fd, MEMGETINFO, &mtdInfo) < 0) {
fprintf(stderr, "Failed to get mtd info\n");
goto err;
}
len = mtdInfo.size;
if (mtdInfo.size <= 0) {
fprintf(stderr, "Invalid MTD device size\n");
goto err;
}
bfd = mtd_open(name, true);
ptr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, bfd, 0);
if (!ptr || (ptr == (void *) -1)) {
perror("mmap");
goto err1;
}
trx = ptr;
if (trx->magic != TRX_MAGIC) {
fprintf(stderr, "TRX header not found\n");
goto err;
}
scan = ptr + offsetof(struct trx_header, flag_version);
trx->crc32 = crc32buf(scan, trx->len - (scan - ptr));
msync(ptr, sizeof(struct trx_header), MS_SYNC|MS_INVALIDATE);
munmap(ptr, len);
close(bfd);
return 0;
err1:
close(bfd);
err:
fprintf(stderr, "Error fixing up TRX header\n");
return -1;
}
int
trx_check(int imagefd, const char *mtd, char *buf, int *len)
{
const struct trx_header *trx = (const struct trx_header *) buf;
int fd;
if (strcmp(mtd, "linux") != 0)
return 1;
*len = read(imagefd, buf, 32);
if (*len < 32) {
fprintf(stdout, "Could not get image header, file too small (%d bytes)\n", *len);
return 0;
}
if (trx->magic != TRX_MAGIC || trx->len < sizeof(struct trx_header)) {
if (quiet < 2) {
fprintf(stderr, "Bad trx header\n");
fprintf(stderr, "This is not the correct file format; refusing to flash.\n"
"Please specify the correct file or use -f to force.\n");
}
return 0;
}
/* check if image fits to mtd device */
fd = mtd_check_open(mtd);
if(fd < 0) {
fprintf(stderr, "Could not open mtd device: %s\n", mtd);
exit(1);
}
if(mtdsize < trx->len) {
fprintf(stderr, "Image too big for partition: %s\n", mtd);
close(fd);
return 0;
}
close(fd);
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);
fd = mtd_check_open(mtd);
if(fd < 0) {
fprintf(stderr, "Could not open mtd device: %s\n", mtd);
exit(1);
}
block_offset = offset & ~(erasesize - 1);
offset -= block_offset;
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;
}