[PATCH 6/6] [MTD-UTILS] nandwrite: Add Support for Reading from Standard Input
Grant Erickson
gerickson at nuovations.com
Mon Sep 8 00:29:19 EDT 2008
Added suppport for reading in band data from standard input based on a
patch originally generated by Richard Titmuss <titmuss at slimdevices.com>
at <http://lists.slimdevices.com/pipermail/jive-checkins/2008-May/001918.html>.
Signed-off-by: Grant Erickson <gerickson at nuovations.com>
---
In addition to the above patch, further discussion of this feature was
raised by Tommi Airikka <tommi.airikka at ericsson.com> at
<http://lists.infradead.org/pipermail/linux-mtd/2008-September/022913.html>.
While support a '-l,--length=length' option might be a good to-do
(noted in the patch comments) in the future, Richard's implementation
better suited my use case:
# flash_eraseall -q /dev/mtd10
# nandwrite -q -p /dev/mtd10 boot.itb
Some disjoint instance in the future when boot.itb is no longer
available in regular file form:
# flash_eraseall -q /dev/mtd8
# nanddump -o -b /dev/mtd10 | nandwrite -q -p /dev/mtd8
nandwrite.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 133 insertions(+), 28 deletions(-)
diff --git a/nandwrite.c b/nandwrite.c
index b7cd72e..fc23e85 100644
--- a/nandwrite.c
+++ b/nandwrite.c
@@ -24,6 +24,8 @@
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -74,7 +76,7 @@ static struct nand_oobinfo autoplace_oobinfo = {
static void display_help (void)
{
printf(
-"Usage: nandwrite [OPTION] MTD_DEVICE INPUTFILE\n"
+"Usage: nandwrite [OPTION] MTD_DEVICE [INPUTFILE|-]\n"
"Writes to the specified MTD device.\n"
"\n"
" -a, --autoplace Use auto oob layout\n"
@@ -110,6 +112,7 @@ static void display_version (void)
exit (EXIT_SUCCESS);
}
+static const char *standard_input = "-";
static const char *mtd_device, *img;
static int mtdoffset = 0;
static bool quiet = false;
@@ -198,16 +201,46 @@ static void process_options (int argc, char * const argv[])
blockalign = atoi (optarg);
break;
case '?':
- error = 1;
+ error++;
break;
}
}
- if ((argc - optind) != 2 || error)
+ if (mtdoffset < 0) {
+ fprintf(stderr, "Can't specify a negative device offset `%d'\n",
+ mtdoffset);
+ exit (EXIT_FAILURE);
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * There must be at least the MTD device node positional
+ * argument remaining and, optionally, the input file.
+ */
+
+ if (argc < 1 || argc > 2 || error)
display_help ();
- mtd_device = argv[optind++];
- img = argv[optind];
+ mtd_device = argv[0];
+
+ /*
+ * Standard input may be specified either explictly as "-" or
+ * implicity by simply omitting the second of the two
+ * positional arguments.
+ */
+
+ img = ((argc == 2) ? argv[1] : standard_input);
+}
+
+static void erase_buffer(void *buffer, size_t size)
+{
+ const uint8_t kEraseByte = 0xff;
+
+ if (buffer != NULL && size > 0) {
+ memset(buffer, kEraseByte, size);
+ }
}
/*
@@ -215,8 +248,12 @@ static void process_options (int argc, char * const argv[])
*/
int main(int argc, char * const argv[])
{
- int cnt, fd, ifd, imglen = 0, pagelen, blockstart = -1;
+ int cnt = 0;
+ int fd = -1;
+ int ifd = -1;
+ int imglen = 0, pagelen;
bool baderaseblock = false;
+ int blockstart = -1;
struct mtd_info_user meminfo;
struct mtd_oob_buf oob;
loff_t offs;
@@ -226,7 +263,7 @@ int main(int argc, char * const argv[])
process_options(argc, argv);
- memset(oobbuf, 0xff, sizeof(oobbuf));
+ erase_buffer(oobbuf, sizeof(oobbuf));
if (pad && writeoob) {
fprintf(stderr, "Can't pad when oob data is present.\n");
@@ -340,21 +377,48 @@ int main(int argc, char * const argv[])
oob.length = meminfo.oobsize;
oob.ptr = noecc ? oobreadbuf : oobbuf;
- /* Open the input file */
- if ((ifd = open(img, O_RDONLY)) == -1) {
+ /* Determine if we are reading from standard input or from a file. */
+ if (strcmp(img, standard_input) == 0) {
+ ifd = STDIN_FILENO;
+ } else {
+ ifd = open(img, O_RDONLY);
+ }
+
+ if (ifd == -1) {
perror(img);
goto restoreoob;
}
- // get image length
- imglen = lseek(ifd, 0, SEEK_END);
- lseek (ifd, 0, SEEK_SET);
+ /* For now, don't allow writing oob when reading from standard input. */
+ if (ifd == STDIN_FILENO && writeoob) {
+ fprintf(stderr, "Can't write oob when reading from standard input.\n");
+ goto closeall;
+ }
pagelen = meminfo.writesize + ((writeoob) ? meminfo.oobsize : 0);
- // Check, if file is pagealigned
+ /*
+ * For the standard input case, the input size is merely an
+ * invariant placeholder and is set to the write page
+ * size. Otherwise, just use the input file size.
+ *
+ * TODO: Add support for the -l,--length=length option (see
+ * previous discussion by Tommi Airikka <tommi.airikka at ericsson.com> at
+ * <http://lists.infradead.org/pipermail/linux-mtd/2008-September/
+ * 022913.html>
+ */
+
+ if (ifd == STDIN_FILENO) {
+ imglen = pagelen;
+ } else {
+ imglen = lseek(ifd, 0, SEEK_END);
+ lseek (ifd, 0, SEEK_SET);
+ }
+
+ // Check, if file is page-aligned
if ((!pad) && ((imglen % pagelen) != 0)) {
- fprintf (stderr, "Input file is not page aligned\n");
+ fprintf (stderr, "Input file is not page-aligned. Use the padding "
+ "option.\n");
goto closeall;
}
@@ -366,7 +430,13 @@ int main(int argc, char * const argv[])
goto closeall;
}
- /* Get data from input and write to the device */
+ /*
+ * Get data from input and write to the device while there is
+ * still input to read and we are still within the device
+ * bounds. Note that in the case of standard input, the input
+ * length is simply a quasi-boolean flag whose values are page
+ * length or zero.
+ */
while (imglen && (mtdoffset < meminfo.size)) {
// new eraseblock , check for bad block(s)
// Stay in the loop to be sure if the mtdoffset changes because
@@ -379,7 +449,8 @@ int main(int argc, char * const argv[])
offs = blockstart;
baderaseblock = false;
if (!quiet)
- fprintf (stdout, "Writing data to block %x\n", blockstart);
+ fprintf (stdout, "Writing data to block %d at offset 0x%x\n",
+ blockstart / meminfo.erasesize, blockstart);
/* Check all the blocks in an erase block for bad blocks */
do {
@@ -404,18 +475,50 @@ int main(int argc, char * const argv[])
}
readlen = meminfo.writesize;
- if (pad && (imglen < readlen))
- {
- readlen = imglen;
- memset(writebuf + readlen, 0xff, meminfo.writesize - readlen);
- }
- /* Read Page Data from input file */
- if ((cnt = read(ifd, writebuf, readlen)) != readlen) {
- if (cnt == 0) // EOF
+ if (ifd != STDIN_FILENO) {
+ if (pad && (imglen < readlen))
+ {
+ readlen = imglen;
+ erase_buffer(writebuf + readlen, meminfo.writesize - readlen);
+ }
+
+ /* Read Page Data from input file */
+ if ((cnt = read(ifd, writebuf, readlen)) != readlen) {
+ if (cnt == 0) // EOF
+ break;
+ perror ("File I/O error on input file");
+ goto closeall;
+ }
+ } else {
+ int tinycnt = 0;
+
+ while(tinycnt < readlen) {
+ cnt = read(ifd, writebuf + tinycnt, readlen - tinycnt);
+ if (cnt == 0) { // EOF
+ break;
+ } else if (cnt < 0) {
+ perror ("File I/O error on stdin");
+ goto closeall;
+ }
+ tinycnt += cnt;
+ }
+
+ /* No padding needed - we are done */
+ if (tinycnt == 0) {
+ imglen = 0;
break;
- perror ("File I/O error on input file");
- goto closeall;
+ }
+
+ /* No more bytes - we are done after writing the remaining bytes */
+ if (cnt == 0) {
+ imglen = 0;
+ }
+
+ /* Padding */
+ if (pad && (tinycnt < readlen)) {
+ erase_buffer(writebuf + tinycnt, meminfo.writesize - tinycnt);
+ }
}
if (writeoob) {
@@ -499,7 +602,9 @@ int main(int argc, char * const argv[])
continue;
}
- imglen -= readlen;
+ if (ifd != STDIN_FILENO) {
+ imglen -= readlen;
+ }
mtdoffset += meminfo.writesize;
}
@@ -517,7 +622,7 @@ restoreoob:
close(fd);
- if (imglen > 0) {
+ if ((ifd != STDIN_FILENO) && (imglen > 0)) {
perror ("Data was only partially written due to error\n");
exit (EXIT_FAILURE);
}
--
1.6.0.1
More information about the linux-mtd
mailing list