From d6aa80bbd02d970b7d2c179c153e195d42cf51cc Mon Sep 17 00:00:00 2001
From: patacongo
Date: Sat, 15 Nov 2008 16:36:32 +0000
Subject: [PATCH] NSH dd command test with block devices
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1242 42af7a65-404d-4744-a932-0658087f49c3
---
Documentation/NuttShell.html | 40 ++++++++++-
drivers/bch/bchlib_read.c | 134 +----------------------------------
drivers/bch/bchlib_write.c | 2 +-
examples/nsh/README.txt | 27 ++++++-
examples/nsh/nsh_ddcmd.c | 95 ++++++++++++++++---------
include/nuttx/fs.h | 12 +++-
6 files changed, 137 insertions(+), 173 deletions(-)
diff --git a/Documentation/NuttShell.html b/Documentation/NuttShell.html
index a2a4a7c5b3..9418056eb9 100644
--- a/Documentation/NuttShell.html
+++ b/Documentation/NuttShell.html
@@ -754,14 +754,50 @@ dd if=<infile> of=<outfile> [bs=<sectsize>] [count=<sectors
Synopsis.
- Copy blocks from <infile> to <outfile>. As an example:
+ Copy blocks from <infile> to <outfile>.
+ <infile> or <outfile> may be the path to a standard file, a character device, or a block device.
+ Examples follow:
+
+
+ -
+ Read from character device, write to regular file.
+ This will create a new file of the specified size filled with zero.
+nsh> ls -l /dev
+/dev:
+ crw-rw-rw- 0 zero
nsh> dd if=/dev/zero of=/tmp/zeros bs=64 count=16
nsh> ls -l /tmp
/tmp:
-rw-rw-rw- 1024 ZEROS
-
+
+
+ Read from character device, write to block device.
+ This will fill the entire block device with zeros.
+
+
+nsh> ls -l /dev
+/dev:
+ brw-rw-rw- 0 ram0
+ crw-rw-rw- 0 zero
+nsh> dd if=/dev/zero of=/dev/ram0
+
+
+
+ Read from a block devic, write to a character device. This
+ will read the entire block device and dump the contents in
+ the bit bucket.
+
+
+nsh> ls -l /dev
+/dev:
+ crw-rw-rw- 0 null
+ brw-rw-rw- 0 ram0
+nsh> dd if=/dev/ram0 of=/dev/null
+
+
+
diff --git a/drivers/bch/bchlib_read.c b/drivers/bch/bchlib_read.c
index 7af72ce8ad..d2301d4392 100644
--- a/drivers/bch/bchlib_read.c
+++ b/drivers/bch/bchlib_read.c
@@ -85,7 +85,7 @@
ssize_t bchlib_read(FAR void *handle, FAR char *buffer, size_t offset, size_t len)
{
- FAR struct bchlib_s *bch;
+ FAR struct bchlib_s *bch = (FAR struct bchlib_s *)handle;
size_t nsectors;
size_t sector;
uint16 sectoffset;
@@ -202,135 +202,3 @@ ssize_t bchlib_read(FAR void *handle, FAR char *buffer, size_t offset, size_t le
return bytesread;
}
-
-/****************************************************************************
- * Name: bchlib_write
- *
- * Description:
- * Write to the block device set-up by bchlib_setup as if it were a character
- * device.
- *
- ****************************************************************************/
-
-ssize_t bchlib_write(FAR void *handle, FAR const char *buffer, size_t offset, size_t len)
-{
- FAR struct bchlib_s *bch;
- size_t nsectors;
- size_t sector;
- uint16 sectoffset;
- size_t nbytes;
- size_t byteswritten;
- int ret;
-
- /* Get rid of this special case right away */
-
- if (len < 1)
- {
- return 0;
- }
-
- /* Convert the file position into a sector number an offset. */
-
- sector = offset / bch->sectsize;
- sectoffset = offset - sector * bch->sectsize;
-
- if (sector >= bch->nsectors)
- {
- return -EFBIG;
- }
-
- /* Write the initial partial sector */
-
- byteswritten = 0;
- if (sectoffset > 0)
- {
- /* Read the full sector into the sector buffer */
-
- bchlib_readsector(bch, sector);
-
- /* Copy the tail end of the sector from the user buffer */
-
- if (sectoffset + len > bch->sectsize)
- {
- nbytes = bch->sectsize - sectoffset;
- }
- else
- {
- nbytes = len;
- }
-
- memcpy(&bch->buffer[sectoffset], buffer, nbytes);
- bch->dirty = TRUE;
-
- /* Adjust pointers and counts */
-
- sectoffset = 0;
- sector++;
-
- if (sector >= bch->nsectors)
- {
- return nbytes;
- }
-
- byteswritten = nbytes;
- buffer += nbytes;
- len -= nbytes;
- }
-
- /* Then write all of the full sectors following the partial sector */
-
- if (len >= bch->sectsize )
- {
- nsectors = len / bch->sectsize;
- if (sector + nsectors > bch->nsectors)
- {
- nsectors = bch->nsectors - sector;
- }
-
- /* Write the contiguous sectors */
-
- ret = bch->inode->u.i_bops->write(bch->inode, bch->buffer, sector, nsectors);
- if (ret < 0)
- {
- fdbg("Write failed: %d\n");
- return ret;
- }
-
- /* Adjust pointers and counts */
-
- sectoffset = 0;
- sector += nsectors;
-
- nbytes = nsectors * bch->sectsize;
- byteswritten += nbytes;
-
- if (sector >= bch->nsectors)
- {
- return byteswritten;
- }
-
- buffer += nbytes;
- len -= nbytes;
- }
-
- /* Then write any partial final sector */
-
- if (len > 0)
- {
- /* Read the sector into the sector buffer */
-
- bchlib_readsector(bch, sector);
-
- /* Copy the head end of the sector from the user buffer */
-
- memcpy(bch->buffer, buffer, len);
- bch->dirty = TRUE;
-
- /* Adjust counts */
-
- byteswritten += len;
- }
-
- return byteswritten;
-}
-
diff --git a/drivers/bch/bchlib_write.c b/drivers/bch/bchlib_write.c
index a897215ea4..ad0737faf3 100644
--- a/drivers/bch/bchlib_write.c
+++ b/drivers/bch/bchlib_write.c
@@ -85,7 +85,7 @@
ssize_t bchlib_write(FAR void *handle, FAR const char *buffer, size_t offset, size_t len)
{
- FAR struct bchlib_s *bch;
+ FAR struct bchlib_s *bch = (FAR struct bchlib_s *)handle;
size_t nsectors;
size_t sector;
uint16 sectoffset;
diff --git a/examples/nsh/README.txt b/examples/nsh/README.txt
index 4b822e02e9..9ea0464099 100644
--- a/examples/nsh/README.txt
+++ b/examples/nsh/README.txt
@@ -252,15 +252,38 @@ o cp
o dd if= of= [bs=] [count=] [skip=]
- Copy blocks from to .
+ Copy blocks from to . or may
+ be the path to a standard file, a character device, or a block device.
- Example:
+ Examples:
+
+ 1. Read from character device, write to regular file. This will
+ create a new file of the specified size filled with zero.
nsh> dd if=/dev/zero of=/tmp/zeros bs=64 count=16
nsh> ls -l /tmp
/tmp:
-rw-rw-rw- 1024 ZEROS
+ 2. Read from character device, write to block device. This will
+ fill the entire block device with zeros.
+
+ nsh> ls -l /dev
+ /dev:
+ brw-rw-rw- 0 ram0
+ crw-rw-rw- 0 zero
+ nsh> dd if=/dev/zero of=/dev/ram0
+
+ 3. Read from a block devic, write to a character device. This
+ will read the entire block device and dump the contents in
+ the bit bucket.
+
+ nsh> ls -l /dev
+ /dev:
+ crw-rw-rw- 0 null
+ brw-rw-rw- 0 ram0
+ nsh> dd if=/dev/ram0 of=/dev/null
+
o echo [ [...]]
Copy the sequence of strings and expanded environment variables to
diff --git a/examples/nsh/nsh_ddcmd.c b/examples/nsh/nsh_ddcmd.c
index 86f829f2be..48cc822f10 100644
--- a/examples/nsh/nsh_ddcmd.c
+++ b/examples/nsh/nsh_ddcmd.c
@@ -209,11 +209,24 @@ static int dd_writeblk(struct dd_s *dd)
ssize_t nbytes;
off_t offset = (dd->sector - dd->skip) * dd->sectsize;
+ /* Write the sector at the specified offset */
+
nbytes = bchlib_write(DD_OUTHANDLE, (char*)dd->buffer, offset, dd->sectsize);
if (nbytes < 0)
{
- nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "bshlib_write", NSH_ERRNO);
- return ERROR;
+ /* bchlib_write return -EFBIG on attempts to write past the end of
+ * the device.
+ */
+
+ if (nbytes == -EFBIG)
+ {
+ dd->eof = TRUE; /* Set end-of-file */
+ }
+ else
+ {
+ nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "bshlib_write", NSH_ERRNO_OF(-nbytes));
+ return ERROR;
+ }
}
return OK;
@@ -238,7 +251,7 @@ static int dd_writech(struct dd_s *dd)
nbytes = write(DD_OUTFD, buffer, dd->sectsize - written);
if (nbytes < 0)
{
- nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "write", NSH_ERRNO);
+ nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "write", NSH_ERRNO_OF(-nbytes));
return ERROR;
}
@@ -263,11 +276,14 @@ static int dd_readblk(struct dd_s *dd)
nbytes = bchlib_read(DD_INHANDLE, (char*)dd->buffer, offset, dd->sectsize);
if (nbytes < 0)
{
- nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "bshlib_read", NSH_ERRNO);
+ nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "bshlib_read", NSH_ERRNO_OF(-nbytes));
return ERROR;
}
+ /* bchlib_read return 0 on attempts to write past the end of the device. */
+
dd->nbytes = nbytes;
+ dd->eof = (nbytes == 0);
return OK;
}
#endif
@@ -287,7 +303,7 @@ static int dd_readch(struct dd_s *dd)
nbytes = read(DD_INFD, buffer, dd->sectsize - dd->nbytes);
if (nbytes < 0)
{
- nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "read", NSH_ERRNO);
+ nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "read", NSH_ERRNO_OF(-nbytes));
return ERROR;
}
@@ -337,7 +353,7 @@ static inline int dd_infopen(const char *name, struct dd_s *dd)
type = dd_filetype(name);
if (type < 0)
{
- nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "stat", NSH_ERRNO);
+ nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "stat", NSH_ERRNO_OF(-type));
return type;
}
@@ -449,9 +465,9 @@ static inline int dd_outfopen(const char *name, struct dd_s *dd)
int cmd_dd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
{
struct dd_s dd;
- const char *infile = NULL;
- const char *outfile = NULL;
- int ret;
+ char *infile = NULL;
+ char *outfile = NULL;
+ int ret = ERROR;
int i;
/* Initialize the dd structure */
@@ -490,11 +506,11 @@ int cmd_dd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
{
if (strncmp(argv[i], "if=", 3) == 0)
{
- infile = &argv[i][3];
+ infile = nsh_getfullpath(vtbl, &argv[i][3]);
}
else if (strncmp(argv[i], "of=", 3) == 0)
{
- outfile = &argv[i][3];
+ outfile = nsh_getfullpath(vtbl, &argv[i][3]);
}
else if (strncmp(argv[i], "bs=", 3) == 0)
{
@@ -514,14 +530,14 @@ int cmd_dd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
if (!infile || !outfile)
{
nsh_output(vtbl, g_fmtargrequired, g_dd);
- return ERROR;
+ goto errout_with_paths;
}
#endif
if (dd.skip < 0 || dd.skip > dd.nsectors)
{
nsh_output(vtbl, g_fmtarginvalid, g_dd);
- return ERROR;
+ goto errout_with_paths;
}
/* Allocate the I/O buffer */
@@ -530,7 +546,7 @@ int cmd_dd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
if (!dd.buffer)
{
nsh_output(vtbl, g_fmtcmdoutofmemory, g_dd);
- return ERROR;
+ goto errout_with_paths;
}
/* Open the input file */
@@ -538,7 +554,7 @@ int cmd_dd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
ret = dd_infopen(infile, &dd);
if (ret < 0)
{
- return ret;
+ goto errout_with_paths;
}
/* Open the output file */
@@ -562,38 +578,53 @@ int cmd_dd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
goto errout_with_outf;
}
- /* Pad with zero if necessary (at the end of file only) */
+ /* Has the incoming data stream ended? */
- for (i = dd.nbytes; i < dd.sectsize; i++)
+ if (!dd.eof)
{
- dd.buffer[i] = 0;
- }
+ /* Pad with zero if necessary (at the end of file only) */
- /* Write one sector to the output file */
-
- if (dd.sector >= dd.skip)
- {
- ret = DD_WRITE(&dd);
- if (ret < 0)
+ for (i = dd.nbytes; i < dd.sectsize; i++)
{
- goto errout_with_outf;
+ dd.buffer[i] = 0;
}
- /* Decrement to show that a sector was written */
+ /* Write one sector to the output file */
- dd.nsectors--;
+ if (dd.sector >= dd.skip)
+ {
+ ret = DD_WRITE(&dd);
+ if (ret < 0)
+ {
+ goto errout_with_outf;
+ }
+
+ /* Decrement to show that a sector was written */
+
+ dd.nsectors--;
+ }
+
+ /* Increment the sector number */
+
+ dd.sector++;
}
-
- /* Increment the sector number */
-
- dd.sector++;
}
+ ret = OK;
errout_with_outf:
DD_INCLOSE(&dd);
errout_with_inf:
DD_OUTCLOSE(&dd);
free(dd.buffer);
+errout_with_paths:
+ if (infile)
+ {
+ free(infile);
+ }
+ if (outfile)
+ {
+ free(outfile);
+ }
return ret;
}
diff --git a/include/nuttx/fs.h b/include/nuttx/fs.h
index 8a174b0117..ad979c5849 100644
--- a/include/nuttx/fs.h
+++ b/include/nuttx/fs.h
@@ -370,9 +370,10 @@ EXTERN int lib_flushall(FAR struct streamlist *list);
* subdirectory
*/
-/* Register /dev/null */
+/* Register /dev/null and /dev/zero */
EXTERN void devnull_register(void);
+EXTERN void devzero_register(void);
/* Setup the loop device so that it exports the file referenced by 'filename'
* as a block device.
@@ -382,12 +383,17 @@ EXTERN int losetup(const char *devname, const char *filename, uint16 sectsize,
off_t offset, boolean readonly);
EXTERN int loteardown(const char *devname);
-/* Setup so that the block driver referenced by 'blkdev' can be accessed
- * similar to a character device.
+/* Setup so that the block driver referenced by 'blkdev' can be accessed
+ * similar to a character device.
+ *
+ * Access via a character device:
*/
EXTERN int bchdev_register(const char *blkdev, const char *chardev, boolean readonly);
EXTERN int bchdev_unregister(const char *chardev);
+
+/* Low level, direct access: */
+
EXTERN int bchlib_setup(const char *blkdev, boolean readonly, FAR void **handle);
EXTERN int bchlib_teardown(FAR void *handle);
EXTERN ssize_t bchlib_read(FAR void *handle, FAR char *buffer, size_t offset, size_t len);