X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/e1487a7c65ad970087aada46171e31a56d6f9d33..ae039548a34a7dc84a20cac5b44b3a02eea6fb20:/openwrt/package/mtd/mtd.c

diff --git a/openwrt/package/mtd/mtd.c b/openwrt/package/mtd/mtd.c
index 69ef06496..06d765ce8 100644
--- a/openwrt/package/mtd/mtd.c
+++ b/openwrt/package/mtd/mtd.c
@@ -2,7 +2,7 @@
  * mtd - simple memory technology device manipulation tool
  *
  * Copyright (C) 2005 Waldemar Brodkorb <wbx@dass-it.de>,
- *		      Felix Fietkau <nbd@vd-s.ath.cx>
+ *	                  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
@@ -16,11 +16,11 @@
  *
  * 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.
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
  * $Id$
  *
- * code is based on linux-mtd example code
+ * The code is based on the linux-mtd examples.
  */
 
 #include <limits.h>
@@ -43,9 +43,11 @@
 #include <linux/mtd/mtd.h>
 
 #define TRX_MAGIC       0x30524448      /* "HDR0" */
-#define BUFSIZE (10 * 1024)
+#define BUFSIZE (16 * 1024)
 #define MAX_ARGS 8
 
+#define DEBUG
+
 struct trx_header {
 	uint32_t magic;		/* "HDR0" */
 	uint32_t len;		/* Length of file including header */
@@ -54,49 +56,33 @@ struct trx_header {
 	uint32_t offsets[3];    /* Offsets of partitions from start of header */
 };
 
+char buf[BUFSIZE];
+int buflen;
+
 int
-trx_check(const char *trxfile, const char *mtd, int force)
+trx_check(int imagefd, const char *mtd)
 {
 	struct mtd_info_user mtdInfo;
-	int trxfd, fd;
+	int fd;
 	size_t count;
-	struct trx_header trx;
+	struct trx_header *trx = (struct trx_header *) buf;
 	struct stat trxstat;
 
-	trxfd = open(trxfile,O_RDONLY);	
-	if(trxfd < 0) {
-		fprintf(stderr, "Could not open image: %s\n", trxfile);
-		exit(1);
-	}
-
-	if (fstat(trxfd,&trxstat) < 0) {
-		fprintf(stderr, "Could not get image file status: %s\n", trxfile);
-		close(trxfd);
-		exit(1);
+	buflen = read(imagefd, buf, sizeof(struct trx_header));
+	if (buflen < sizeof(struct trx_header)) {
+		fprintf(stderr, "Could not get trx header, file too small (%ld bytes)\n", buflen);
+		return 0;
 	}
 
-	if (force == 0) {
-		count = read(trxfd, &trx, sizeof(struct trx_header));
-		if (count < sizeof(struct trx_header)) {
-			fprintf(stderr, "Could not get trx header, file too small (%ld bytes)\n", count);
-			close(trxfd);
-			exit(1);
-		}
-
-		if (trx.magic != TRX_MAGIC || trx.len < sizeof(struct trx_header)) {
-			fprintf(stderr, "Bad trx header\n");
-			fprintf(stderr, "If this is a firmware in bin format, like some of the\n"
-					"original firmware files are, use following command to convert to trx:\n"
-					"dd if=firmware.bin of=firmware.trx bs=32 skip=1\n");
-			close(trxfd);
-			exit(1);
-		}
-	
-		lseek(trxfd, 0, SEEK_SET);
+	if (trx->magic != TRX_MAGIC || trx->len < sizeof(struct trx_header)) {
+		fprintf(stderr, "Bad trx header\n");
+		fprintf(stderr, "If this is a firmware in bin format, like some of the\n"
+				"original firmware files are, use following command to convert to trx:\n"
+				"dd if=firmware.bin of=firmware.trx bs=32 skip=1\n");
+		return 0;
 	}
 
 	/* check if image fits to mtd device */
-
 	fd = mtd_open(mtd, O_RDWR);
 	if(fd < 0) {
 		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
@@ -105,22 +91,37 @@ trx_check(const char *trxfile, const char *mtd, int force)
 
 	if(ioctl(fd, MEMGETINFO, &mtdInfo)) {
 		fprintf(stderr, "Could not get MTD device info from %s\n", mtd);
-		close(fd);
 		exit(1);
 	}
 		
-	if(mtdInfo.size < trxstat.st_size) {
+	if(mtdInfo.size < trx->len) {
 		fprintf(stderr, "Image too big for partition: %s\n", mtd);
-		close(trxfd);
 		close(fd);
-		exit(1);
+		return 0;
 	}	
 	
-	printf("Writing %s to %s ...\n", trxfile, mtd);
+	return 1;
+}
 
-	close(fd);
+int mtd_check(char *mtd)
+{
+	struct mtd_info_user mtdInfo;
+	int fd;
+
+	fd = mtd_open(mtd, O_RDWR);
+	if(fd < 0) {
+		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+		return 0;
+	}
+
+	if(ioctl(fd, MEMGETINFO, &mtdInfo)) {
+		fprintf(stderr, "Could not get MTD device info from %s\n", mtd);
+		close(fd);
+		return 0;
+	}
 
-	return(trxfd);
+	close(fd);
+	return 1;
 }
 
 int
@@ -142,7 +143,7 @@ mtd_unlock(const char *mtd)
 		exit(1);
 	}
 
-	printf("Unlocking %s ...\n", mtd);
+	fprintf(stderr, "Unlocking %s ...\n", mtd);
 	mtdLockInfo.start = 0;
 	mtdLockInfo.length = mtdInfo.size;
 	if(ioctl(fd, MEMUNLOCK, &mtdLockInfo)) {
@@ -194,7 +195,7 @@ mtd_erase(const char *mtd)
 		exit(1);
 	}
 
-	printf("Erasing %s ...\n", mtd);
+	fprintf(stderr, "Erasing %s ...\n", mtd);
 	mtdEraseInfo.length = mtdInfo.erasesize;
 
 	for (mtdEraseInfo.start = 0;
@@ -215,20 +216,12 @@ mtd_erase(const char *mtd)
 }
 
 int
-mtd_write(int trxfd, const char *mtd)
+mtd_write(int imagefd, const char *mtd)
 {
-	int fd,i;
-	size_t result,size,written;
+	int fd, i, result;
+	size_t r, w, e;
 	struct mtd_info_user mtdInfo;
 	struct erase_info_user mtdEraseInfo;
-	unsigned char src[BUFSIZE],dest[BUFSIZE];
-	struct stat trxstat;
-
-	if (fstat(trxfd,&trxstat) < 0) {
-		fprintf(stderr, "Could not get trx image file status\n");
-		close(trxfd);
-		exit(1);
-	}
 
 	fd = mtd_open(mtd, O_RDWR);
 	if(fd < 0) {
@@ -242,51 +235,63 @@ mtd_write(int trxfd, const char *mtd)
 		exit(1);
 	}
 		
-	mtdEraseInfo.start = 0;
-	mtdEraseInfo.length = trxstat.st_size & ~(mtdInfo.erasesize -1);
-	if(trxstat.st_size % mtdInfo.erasesize) mtdEraseInfo.length += mtdInfo.erasesize;
-
-	/* erase the chunk */
-	if (ioctl (fd,MEMERASE,&mtdEraseInfo) < 0) {
-		fprintf(stderr, "Erasing mtd failed: %s\n", mtd);
-		exit(1);
-	}
-	
-	size = trxstat.st_size;
-	i = BUFSIZE;
-	written = 0;
-
-	while (size) {
-		if (size < BUFSIZE) i = size;
-		read(trxfd,src,i);
-		result = write(fd,src,i);
-		if (i != result) {
+	r = w = e = 0;
+	fprintf(stderr, " [ ]");
+
+	for (;;) {
+		/* buffer may contain data already (from trx check) */
+		r = buflen;
+		r += read(imagefd, buf + buflen, BUFSIZE - buflen);
+		w += r;
+
+		/* EOF */
+		if (r <= 0) break;
+
+		/* need to erase the next block before writing data to it */
+		while (w > e) {
+			mtdEraseInfo.start = e;
+			mtdEraseInfo.length = mtdInfo.erasesize;
+
+			fprintf(stderr, "\b\b\b[e]");
+			/* erase the chunk */
+			if (ioctl (fd,MEMERASE,&mtdEraseInfo) < 0) {
+				fprintf(stderr, "Erasing mtd failed: %s\n", mtd);
+				exit(1);
+			}
+			e += mtdInfo.erasesize;
+		}
+		
+		fprintf(stderr, "\b\b\b[w]");
+		
+		if ((result = write(fd, buf, r)) < r) {
 			if (result < 0) {
-				fprintf(stderr,"Error while writing image");
+				fprintf(stderr, "Error writing image.\n");
+				exit(1);
+			} else {
+				fprintf(stderr, "Insufficient space.\n");
 				exit(1);
 			}
-			fprintf(stderr,"Error writing image");
-			exit(1);
 		}
-		written += i;
-		size -= i;
+		
+		buflen = 0;
 	}
+	fprintf(stderr, "\b\b\b\b");
 	
 	return 0;
 }
 
 void usage(void)
 {
-	printf("Usage: mtd [<options> ...] <command> [<arguments> ...] <device>\n\n"
+	fprintf(stderr, "Usage: mtd [<options> ...] <command> [<arguments> ...] <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"
-	"	erase			erase all data on device\n"
-	"	write <imagefile>	write imagefile to device\n"
+	"        unlock                  unlock the device\n"
+	"        erase                   erase all data on device\n"
+	"        write <imagefile>|-     write <imagefile> (use - for stdin) to device\n"
 	"Following options are available:\n"
-	"	-r			reboot after successful command\n"
-	"	-f			force write without trx checks\n"
-	"	-e <device>		erase <device> before executing the command\n\n"
+	"        -r                      reboot after successful command\n"
+	"        -f                      force write without trx checks\n"
+	"        -e <device>             erase <device> before executing the command\n\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);
@@ -294,8 +299,8 @@ void usage(void)
 
 int main (int argc, char **argv)
 {
-	int ch, i, boot, unlock, trxfd, force;
-	char *erase[MAX_ARGS], *device;
+	int ch, i, boot, unlock, imagefd, force;
+	char *erase[MAX_ARGS], *device, *imagefile;
 	enum {
 		CMD_ERASE,
 		CMD_WRITE,
@@ -305,6 +310,7 @@ int main (int argc, char **argv)
 	erase[0] = NULL;
 	boot = 0;
 	force = 0;
+	buflen = 0;
 
 	while ((ch = getopt(argc, argv, "fre:")) != -1)
 		switch (ch) {
@@ -342,14 +348,37 @@ int main (int argc, char **argv)
 	} else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) {
 		cmd = CMD_WRITE;
 		device = argv[2];
-		/* check trx file before erasing or writing anything */
-		trxfd = trx_check(argv[1], device, force);
+	
+		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 (system("grep Broadcom /proc/cpuinfo >&- >&-") == 0) {
+			/* check trx file before erasing or writing anything */
+			if (!trx_check(imagefd, device)) {
+				fprintf(stderr, "TRX check failed!\n");
+				if (!force)
+					exit(1);
+			}
+		} else {
+			if (!mtd_check(device)) {
+				fprintf(stderr, "Can't open device for writing!\n");
+				exit(1);
+			}
+		}
 	} else {
 		usage();
 	}
 
 	sync();
-
+	
 	i = 0;
 	while (erase[i] != NULL) {
 		mtd_unlock(erase[i]);
@@ -366,7 +395,9 @@ int main (int argc, char **argv)
 			mtd_erase(device);
 			break;
 		case CMD_WRITE:
-			mtd_write(trxfd, device);
+			fprintf(stderr, "Writing from %s to %s ... ", imagefile, device);
+			mtd_write(imagefd, device);
+			fprintf(stderr, "\n");
 			break;
 	}