summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-03-18 19:46:25 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-03-18 19:46:25 +0000
commit058e81edfdee203f2143b3f0910aa957a7f8da48 (patch)
tree4842491d56251e5499f2838ee303bd752d518e12 /apps
parent529a1cf7339541eaee3d189a3b97d9c544ba7810 (diff)
downloadnuttx-058e81edfdee203f2143b3f0910aa957a7f8da48.tar.gz
nuttx-058e81edfdee203f2143b3f0910aa957a7f8da48.tar.bz2
nuttx-058e81edfdee203f2143b3f0910aa957a7f8da48.zip
Move NSH to apps/ as library
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3393 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'apps')
-rw-r--r--apps/nshlib/Makefile121
-rw-r--r--apps/nshlib/README.txt1016
-rw-r--r--apps/nshlib/nsh.h490
-rw-r--r--apps/nshlib/nsh_apps.c132
-rw-r--r--apps/nshlib/nsh_dbgcmds.c355
-rw-r--r--apps/nshlib/nsh_ddcmd.c641
-rw-r--r--apps/nshlib/nsh_envcmds.c335
-rw-r--r--apps/nshlib/nsh_fscmds.c1341
-rw-r--r--apps/nshlib/nsh_main.c1299
-rw-r--r--apps/nshlib/nsh_mmcmds.c95
-rw-r--r--apps/nshlib/nsh_netcmds.c815
-rw-r--r--apps/nshlib/nsh_netinit.c169
-rw-r--r--apps/nshlib/nsh_proccmds.c297
-rw-r--r--apps/nshlib/nsh_romfsetc.c124
-rw-r--r--apps/nshlib/nsh_romfsimg.h89
-rw-r--r--apps/nshlib/nsh_serial.c449
-rw-r--r--apps/nshlib/nsh_telnetd.c853
-rw-r--r--apps/nshlib/nsh_test.c437
-rw-r--r--apps/nshlib/rcS.template5
19 files changed, 9063 insertions, 0 deletions
diff --git a/apps/nshlib/Makefile b/apps/nshlib/Makefile
new file mode 100644
index 000000000..e4f5bf7b5
--- /dev/null
+++ b/apps/nshlib/Makefile
@@ -0,0 +1,121 @@
+############################################################################
+# apps/nshlib/Makefile
+#
+# Copyright (C) 2011 Gregory Nutt. All rights reserved.
+# Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# 3. Neither the name NuttX nor the names of its contributors may be
+# used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+############################################################################
+
+# TODO, this makefile should run make under the app dirs, instead of
+# sourcing the Make.defs!
+
+-include $(TOPDIR)/Make.defs
+include ../Make.defs
+
+ifeq ($(WINTOOL),y)
+INCDIROPT = -w
+endif
+
+# NSH Library
+
+ASRCS =
+CSRCS = nsh_main.c nsh_fscmds.c nsh_ddcmd.c nsh_proccmds.c nsh_mmcmds.c \
+ nsh_envcmds.c nsh_dbgcmds.c
+
+ifeq ($(CONFIG_EXAMPLES_NSH_BUILTIN_APPS),y)
+CSRCS += nsh_apps.c
+endif
+
+ifeq ($(CONFIG_EXAMPLES_NSH_ROMFSETC),y)
+CSRCS += nsh_romfsetc.c
+endif
+
+ifeq ($(CONFIG_NET),y)
+CSRCS += nsh_netinit.c nsh_netcmds.c
+endif
+
+ifeq ($(CONFIG_EXAMPLES_NSH_CONSOLE),y)
+CSRCS += nsh_serial.c
+endif
+
+ifeq ($(CONFIG_EXAMPLES_NSH_TELNET),y)
+CSRCS += nsh_telnetd.c
+endif
+
+ifneq ($(CONFIG_EXAMPLES_NSH_DISABLESCRIPT),y)
+CSRCS += nsh_test.c
+endif
+
+AOBJS = $(ASRCS:.S=$(OBJEXT))
+COBJS = $(CSRCS:.c=$(OBJEXT))
+
+SRCS = $(ASRCS) $(CSRCS)
+OBJS = $(AOBJS) $(COBJS)
+
+BIN = ../libapps$(LIBEXT)
+
+ROOTDEPPATH = --dep-path .
+
+# Common build
+
+VPATH =
+
+all: .built
+
+$(AOBJS): %$(OBJEXT): %.S
+ $(call ASSEMBLE, $<, $@)
+
+$(COBJS): %$(OBJEXT): %.c
+ $(call COMPILE, $<, $@)
+
+$(BIN): $(OBJS)
+ @( for obj in $(OBJS) ; do \
+ $(call ARCHIVE, $@, $${obj}); \
+ done ; )
+ @touch .built
+
+.built: $(BIN)
+
+.depend: Makefile $(SRCS)
+ @$(MKDEP) $(ROOTDEPPATH) \
+ $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep
+ @touch $@
+
+# Register application
+depend: .depend
+
+clean:
+ @rm -f $(BIN) *.o *~ .*.swp .built
+ $(call CLEAN)
+
+distclean: clean
+ @rm -f Make.dep .depend
+
+-include Make.dep
diff --git a/apps/nshlib/README.txt b/apps/nshlib/README.txt
new file mode 100644
index 000000000..10bb202df
--- /dev/null
+++ b/apps/nshlib/README.txt
@@ -0,0 +1,1016 @@
+apps/nshlib
+^^^^^^^^^^^
+
+ This directory contains the NuttShell (NSH) library. This library can be
+ linked with other logic to provide a simple shell application for NuttX.
+
+ - Console/NSH Front End
+ - Command Overview
+ - Conditional Command Execution
+ - Built-In Variables
+ - Current Working Directory
+ Environment Variables
+ - NSH Start-Up Script
+ - Simple Commands
+ - NSH Configuration Settings
+ Command Dependencies on Configuration Settings
+ NSH-Specific Configuration Settings
+ - Common Problems
+
+Console/NSH Front End
+^^^^^^^^^^^^^^^^^^^^^
+
+ Using settings in the configuration file, NSH may be configured to
+ use either the serial stdin/out or a telnet connection as the console
+ or BOTH. When NSH is started, you will see the following welcome on
+ either console:
+
+ NuttShell (NSH)
+ nsh>
+
+ 'nsh>' is the NSH prompt and indicates that you may enter a command
+ from the console.
+
+Command Overview
+^^^^^^^^^^^^^^^^
+
+ This directory contains the NuttShell (NSH). This is a simple
+ shell-like application. At present, NSH supports the following commands
+ forms:
+
+ Simple command: <cmd>
+ Command with re-directed output: <cmd> > <file>
+ <cmd> >> <file>
+ Background command: <cmd> &
+ Re-directed background command: <cmd> > <file> &
+ <cmd> >> <file> &
+
+ Where:
+
+ <cmd> is any one of the simple commands listed later.
+ <file> is the full or relative path to any writable object
+ in the filesystem name space (file or character driver).
+ Such objects will be referred to simply as files throughout
+ this README.
+
+ NSH executes at the mid-priority (128). Backgrounded commands can
+ be made to execute at higher or lower priorities using nice:
+
+ [nice [-d <niceness>>]] <cmd> [> <file>|>> <file>] [&]
+
+ Where <niceness> is any value between -20 and 19 where lower
+ (more negative values) correspond to higher priorities. The
+ default niceness is 10.
+
+Conditional Command Execution
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ An if-then[-else]-fi construct is also supported in order to
+ support conditional execution of commands. This works from the
+ command line but is primarily intended for use within NSH scripts
+ (see the sh commnd). The syntax is as follows:
+
+ if <cmd>
+ then
+ [sequence of <cmd>]
+ else
+ [sequence of <cmd>]
+ fi
+
+Built-In Variables
+^^^^^^^^^^^^^^^^^^
+
+ $? - The result of the last simple command execution
+
+Current Working Directory
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ All path arguments to commands may be either an absolute path or a
+ path relative to the current working directory. The current working
+ directory is set using the 'cd' command and can be queried either
+ by using the 'pwd' command or by using the 'echo $PWD' command.
+
+ Environment Variables:
+ ----------------------
+
+ PWD - The current working directory
+ OLDPWD - The previous working directory
+
+NSH Start-Up Script
+^^^^^^^^^^^^^^^^^^^
+
+NSH supports options to provide a start up script for NSH. In general
+this capability is enabled with CONFIG_EXAMPLES_NSH_ROMFSETC, but has
+several other related configuration options as described in the final
+section of this README. This capability also depends on:
+
+ - CONFIG_DISABLE_MOUNTPOINT not set
+ - CONFIG_NFILE_DESCRIPTORS < 4
+ - CONFIG_FS_ROMFS
+
+Default Start-Up Behavior
+-------------------------
+
+The implementation that is provided is intended to provide great flexibility
+for the use of Start-Up files. This paragraph will discuss the general
+behavior when all of the configuration options are set to the default
+values.
+
+In this default case, enabling CONFIG_EXAMPLES_NSH_ROMFSETC will cause
+NSH to behave as follows at NSH startup time:
+
+- NSH will create a read-only RAM disk (a ROM disk), containing a tiny
+ ROMFS filesystem containing the following:
+
+ |--init.d/
+ `-- rcS
+
+ Where rcS is the NSH start-up script
+
+- NSH will then mount the ROMFS filesystem at /etc, resulting in:
+
+ |--dev/
+ | `-- ram0
+ `--etc/
+ `--init.d/
+ `-- rcS
+
+- By default, the contents of rcS script are:
+
+ # Create a RAMDISK and mount it at XXXRDMOUNTPOUNTXXX
+
+ mkrd -m 1 -s 512 1024
+ mkfatfs /dev/ram1
+ mount -t vfat /dev/ram1 /tmp
+
+- NSH will execute the script at /etc/init.d/rcS at start-up (before the
+ first NSH prompt. After execution of the script, the root FS will look
+ like:
+
+ |--dev/
+ | |-- ram0
+ | `-- ram1
+ |--etc/
+ | `--init.d/
+ | `-- rcS
+ `--tmp/
+
+Modifying the ROMFS Image
+-------------------------
+
+The contents of the /etc directory are retained in the file
+apps/nshlib/nsh_romfsimg.h (OR, if CONFIG_EXAMPLES_NSH_ARCHROMFS
+is defined, include/arch/board/rcs.template). In order to modify
+the start-up behavior, there are three things to study:
+
+1. Configuration Options.
+ The additional CONFIG_EXAMPLES_NSH_ROMFSETC configuration options
+ discussed in the final section of this README.
+
+2. tools/mkromfsimg.sh Script.
+ The script tools/mkromfsimg.sh creates nsh_romfsimg.h.
+ It is not automatically executed. If you want to change the
+ configuration settings associated with creating and mounting
+ the /tmp directory, then it will be necessary to re-generate
+ this header file using the mkromfsimg.sh script.
+
+ The behavior of this script depends upon three things:
+
+ - The configuration settings of the installed NuttX configuration.
+ - The genromfs tool (available from http://romfs.sourceforge.net).
+ - The file apps/nshlib/rcS.template (OR, if
+ CONFIG_EXAMPLES_NSH_ARCHROMFS is defined, include/arch/board/rcs.template)
+
+3. rcS.template.
+ The file apps/nshlib/rcS.template contains the general form
+ of the rcS file; configured values are plugged into this
+ template file to produce the final rcS file.
+
+NOTE:
+
+ apps/nshlib/rcS.template generates the standard, default
+ nsh_romfsimg.h file. If CONFIG_EXAMPLES_NSH_ARCHROMFS is defined
+ in the NuttX configuration file, then a custom, board-specific
+ nsh_romfsimg.h file residing in configs/<board>/include will be
+ used. NOTE when the OS is configured, include/arch/board will
+ be linked to configs/<board>/include.
+
+All of the startup-behavior is contained in rcS.template. The
+role of mkromfsimg.sh is to (1) apply the specific configuration
+settings to rcS.template to create the final rcS, and (2) to
+generate the header file nsh_romfsimg.h containg the ROMFS
+file system image.
+
+Simple Commands
+^^^^^^^^^^^^^^^
+
+o [ <expression> ]
+o test <expression>
+
+ These are two alternative forms of the same command. They support
+ evaluation of a boolean expression which sets $?. This command
+ is used most frequently as the conditional command following the
+ 'if' in the if-then[-else]-fi construct.
+
+ Expression Syntax:
+ ------------------
+
+ expression = simple-expression | !expression |
+ expression -o expression | expression -a expression
+
+ simple-expression = unary-expression | binary-expression
+
+ unary-expression = string-unary | file-unary
+
+ string-unary = -n string | -z string
+
+ file-unary = -b file | -c file | -d file | -e file | -f file |
+ -r file | -s file | -w file
+
+ binary-expression = string-binary | numeric-binary
+
+ string-binary = string = string | string == string | string != string
+
+ numeric-binary = integer -eq integer | integer -ge integer |
+ integer -gt integer | integer -le integer |
+ integer -lt integer | integer -ne integer
+
+o cat <path> [<path> [<path> ...]]
+
+ This command copies and concatentates all of the files at <path>
+ to the console (or to another file if the output is redirected).
+
+o cd [<dir-path>|-|~|..]
+
+ Changes the current working directory (PWD). Also sets the
+ previous working directory environment variable (OLDPWD).
+
+ FORMS:
+ ------
+
+ 'cd <dir-path>' sets the current working directory to <dir-path>.
+ 'cd -' sets the current working directory to the previous
+ working directory ($OLDPWD). Equivalent to 'cd $OLDPWD'.
+ 'cd' or 'cd ~' set the current working directory to the 'home'
+ directory. The 'home' directory can be configured by setting
+ CONFIG_LIB_HOMEDIR in the configuration file. The default
+ 'home' directory is '/'.
+ 'cd ..' sets the current working directory to the parent directory.
+
+o cp <source-path> <dest-path>
+
+ Copy of the contents of the file at <source-path> to the location
+ in the filesystem indicated by <path-path>
+
+o dd if=<infile> of=<outfile> [bs=<sectsize>] [count=<sectors>] [skip=<sectors>]
+
+ Copy blocks from <infile> to <outfile>. <nfile> or <outfile> may
+ be the path to a standard file, a character device, or a block device.
+
+ 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 [<string|$name> [<string|$name>...]]
+
+ Copy the sequence of strings and expanded environment variables to
+ console out (or to a file if the output is re-directed).
+
+o exec <hex-address>
+
+ Execute the user logic at address <hex-address>. NSH will pause
+ until the execution unless the user logic is executed in background
+ via 'exec <hex-address> &'
+
+o exit
+
+ Exit NSH. Only useful if you have started some other tasks (perhaps
+ using the 'exec' command') and you would like to have NSH out of the
+ way.
+
+o free
+
+ Show the current state of the memory allocator. For example,
+
+ nsh> free
+ free
+ total used free largest
+ Mem: 4194288 1591552 2602736 2601584
+
+ Where:
+ total - This is the total size of memory allocated for use
+ by malloc in bytes.
+ used - This is the total size of memory occupied by
+ chunks handed out by malloc.
+ free - This is the total size of memory occupied by
+ free (not in use) chunks.
+ largest - Size of the largest free (not in use) chunk
+
+o get [-b|-n] [-f <local-path>] -h <ip-address> <remote-path>
+
+ Use TFTP to copy the file at <remote-address> from the host whose IP
+ address is identified by <ip-address>. Other options:
+
+ -f <local-path>
+ The file will be saved relative to the current working directory
+ unless <local-path> is provided.
+ -b|-n
+ Selects either binary ("octect") or test ("netascii") transfer
+ mode. Default: text.
+
+o help
+
+ Presents summary information about each command to console.
+
+o ifconfig
+
+ Show the current configuration of the network, for example:
+
+ nsh> ifconfig
+ eth0 HWaddr 00:18:11:80:10:06
+ IPaddr:10.0.0.2 DRaddr:10.0.0.1 Mask:255.255.255.0
+
+ if uIP statistics are enabled (CONFIG_NET_STATISTICS), then
+ this command will also show the detailed state of uIP.
+
+o kill -<signal> <pid>
+
+ Send the <signal> to the task identified by <pid>.
+
+o losetup [-d <dev-path>] | [[-o <offset>] [-r] <ldev-path> <file-path>]
+
+ Setup or teardown the loop device:
+
+ 1. Teardown the setup for the loop device at <dev-path>:
+
+ losetup d <dev-path>
+
+ 2. Setup the loop device at <dev-path> to access the file at <file-path>
+ as a block device:
+
+ losetup [-o <offset>] [-r] <dev-path> <file-path>
+
+ Example:
+
+ nsh> dd if=/dev/zero of=/tmp/image bs=512 count=512
+ nsh> ls -l /tmp
+ /tmp:
+ -rw-rw-rw- 262144 IMAGE
+ nsh> losetup /dev/loop0 /tmp/image
+ nsh> ls -l /dev
+ /dev:
+ brw-rw-rw- 0 loop0
+ nsh> mkfatfs /dev/loop0
+ nsh> mount -t vfat /dev/loop0 /mnt/example
+ nsh> ls -l /mnt
+ ls -l /mnt
+ /mnt:
+ drw-rw-rw- 0 example/
+ nsh> echo "This is a test" >/mnt/example/atest.txt
+ nsh> ls -l /mnt/example
+ /mnt/example:
+ -rw-rw-rw- 16 ATEST.TXT
+ nsh> cat /mnt/example/atest.txt
+ This is a test
+ nsh>
+
+o ls [-lRs] <dir-path>
+
+ Show the contents of the directory at <dir-path>. NOTE:
+ <dir-path> must refer to a directory and no other filesystem
+ object.
+
+ Options:
+ --------
+
+ -R Show the constents of specified directory and all of its
+ sub-directories.
+ -s Show the size of the files along with the filenames in the
+ listing
+ -l Show size and mode information along with the filenames
+ in the listing.
+
+o mb <hex-address>[=<hex-value>][ <hex-byte-count>]
+o mh <hex-address>[=<hex-value>][ <hex-byte-count>]
+o mw <hex-address>[=<hex-value>][ <hex-byte-count>]
+
+ Access memory using byte size access (mb), 16-bit accesses (mh),
+ or 32-bit access (mw). In each case,
+
+ <hex-address>. Specifies the address to be accessed. The current
+ value at that address will always be read and displayed.
+ <hex-address>=<hex-value>. Read the value, then write <hex-value>
+ to the location.
+ <hex-byte-count>. Perform the mb, mh, or mw operation on a total
+ of <hex-byte-count> bytes, increment the <hex-address> appropriately
+ after each access
+
+ Example
+
+ nsh> mh 0 16
+ 0 = 0x0c1e
+ 2 = 0x0100
+ 4 = 0x0c1e
+ 6 = 0x0110
+ 8 = 0x0c1e
+ a = 0x0120
+ c = 0x0c1e
+ e = 0x0130
+ 10 = 0x0c1e
+ 12 = 0x0140
+ 14 = 0x0c1e
+ nsh>
+
+o mkdir <path>
+
+ Create the directory at <path>. All components of of <path>
+ except the final directory name must exist on a mounted file
+ system; the final directory must not.
+
+ Recall that NuttX uses a pseudo filesystem for its root file system.
+ The mkdir command can only be used to create directories in volumes
+ set up with the mount command; it cannot be used to create directories
+ in the pseudo filesystem.
+
+ Example:
+ ^^^^^^^^
+
+ nsh> mkdir /mnt/fs/tmp
+ nsh> ls -l /mnt/fs
+ /mnt/fs:
+ drw-rw-rw- 0 TESTDIR/
+ drw-rw-rw- 0 TMP/
+ nsh>
+
+o mkfatfs <path>
+
+ Format a fat file system on the block device specified by path.
+ NSH provides this command to access the mkfatfs() NuttX API.
+ This block device must reside in the NuttX psuedo filesystem and
+ must have been created by some call to register_blockdriver() (see
+ include/nuttx/fs.h).
+
+o mkfifo <path>
+
+ Creates a FIFO character device anywhere in the pseudo file system,
+ creating whatever psuedo directories that may be needed to complete
+ the full path. By convention, however, device drivers are place in
+ the standard /dev directory. After it is created, the FIFO device
+ may be used as any other device driver. NSH provides this command
+ to access the mkfifo() NuttX API.
+
+ Example:
+ ^^^^^^^^
+
+ nsh> ls -l /dev
+ /dev:
+ crw-rw-rw- 0 console
+ crw-rw-rw- 0 null
+ brw-rw-rw- 0 ram0
+ nsh> mkfifo /dev/fifo
+ nsh> ls -l /dev
+ ls -l /dev
+ /dev:
+ crw-rw-rw- 0 console
+ crw-rw-rw- 0 fifo
+ crw-rw-rw- 0 null
+ brw-rw-rw- 0 ram0
+ nsh>
+
+o mkrd [-m <minor>] [-s <sector-size>] <nsectors>
+
+ Create a ramdisk consisting of <nsectors>, each of size
+ <sector-size> (or 512 bytes if <sector-size> is not specified.
+ The ramdisk will be registered as /dev/ram<n> (if <n> is not
+ specified, mkrd will attempt to register the ramdisk as
+ /dev/ram0.
+
+ Example:
+ ^^^^^^^^
+
+ nsh> ls /dev
+ /dev:
+ console
+ null
+ ttyS0
+ ttyS1
+ nsh> mkrd 1024
+ nsh> ls /dev
+ /dev:
+ console
+ null
+ ram0
+ ttyS0
+ ttyS1
+ nsh>
+
+ Once the ramdisk has been created, it may be formatted using
+ the mkfatfs command and mounted using the mount command.
+
+ Example:
+ ^^^^^^^^
+ nsh> mkrd 1024
+ nsh> mkfatfs /dev/ram0
+ nsh> mount -t vfat /dev/ram0 /tmp
+ nsh> ls /tmp
+ /tmp:
+ nsh>
+
+o mount -t <fstype> <block-device> <dir-path>
+
+ The 'mount' command mounts a file system in the NuttX psuedo
+ filesystem. 'mount' performs a three way associating, binding
+
+ File system. The '-t <fstype>' option identifies the type of
+ file system that has been formatted on the <block-device>. As
+ of this writing, vfat is the only supported value for <fstype>
+
+ Block Device. The <block-device> argument is the full or relative
+ path to a block driver inode in the psuedo filesystem. By convention,
+ this is a name under the /dev sub-directory. This <block-device>
+ must have been previously formatted with the same file system
+ type as specified by <fstype>
+
+ Mount Point. The mount point is the location in the psuedo file
+ system where the mounted volume will appear. This mount point
+ can only reside in the NuttX psuedo filesystem. By convention, this
+ mount point is a subdirectory under /mnt. The mount command will
+ create whatever psuedo directories that may be needed to complete
+ the full path but the full path must not already exist.
+
+ After the volume has been mounted in the NuttX psuedo file
+ system, it may be access in the same way as other objects in the
+ file system.
+
+ Example:
+ ^^^^^^^^
+
+ nsh> ls -l /dev
+ /dev:
+ crw-rw-rw- 0 console
+ crw-rw-rw- 0 null
+ brw-rw-rw- 0 ram0
+ nsh> ls /mnt
+ nsh: ls: no such directory: /mnt
+ nsh> mount -t vfat /dev/ram0 /mnt/fs
+ nsh> ls -l /mnt/fs/testdir
+ /mnt/fs/testdir:
+ -rw-rw-rw- 15 TESTFILE.TXT
+ nsh> echo "This is a test" >/mnt/fs/testdir/example.txt
+ nsh> ls -l /mnt/fs/testdir
+ /mnt/fs/testdir:
+ -rw-rw-rw- 15 TESTFILE.TXT
+ -rw-rw-rw- 16 EXAMPLE.TXT
+ nsh> cat /mnt/fs/testdir/example.txt
+ This is a test
+ nsh>
+
+o ps
+
+ Show the currently active threads and tasks. For example,
+
+ nsh> ps
+ PID PRI SCHD TYPE NP STATE NAME
+ 0 0 FIFO TASK READY Idle Task()
+ 1 128 RR TASK RUNNING init()
+ 2 128 FIFO TASK WAITSEM nsh_telnetmain()
+ 3 100 RR PTHREAD WAITSEM <pthread>(21)
+ nsh>
+
+o ping [-c <count>] [-i <interval>] <ip-address>
+
+ Test the network communication with a remote peer. Example,
+
+ nsh> 10.0.0.1
+ PING 10.0.0.1 56 bytes of data
+ 56 bytes from 10.0.0.1: icmp_seq=1 time=0 ms
+ 56 bytes from 10.0.0.1: icmp_seq=2 time=0 ms
+ 56 bytes from 10.0.0.1: icmp_seq=3 time=0 ms
+ 56 bytes from 10.0.0.1: icmp_seq=4 time=0 ms
+ 56 bytes from 10.0.0.1: icmp_seq=5 time=0 ms
+ 56 bytes from 10.0.0.1: icmp_seq=6 time=0 ms
+ 56 bytes from 10.0.0.1: icmp_seq=7 time=0 ms
+ 56 bytes from 10.0.0.1: icmp_seq=8 time=0 ms
+ 56 bytes from 10.0.0.1: icmp_seq=9 time=0 ms
+ 56 bytes from 10.0.0.1: icmp_seq=10 time=0 ms
+ 10 packets transmitted, 10 received, 0% packet loss, time 10190 ms
+ nsh>
+
+o put [-b|-n] [-f <remote-path>] -h <ip-address> <local-path>
+
+ Copy the file at <local-address> to the host whose IP address is
+ identified by <ip-address>. Other options:
+
+ -f <remote-path>
+ The file will be saved with the same name on the host unless
+ unless <local-path> is provided.
+ -b|-n
+ Selects either binary ("octect") or test ("netascii") transfer
+ mode. Default: text.
+
+o pwd
+
+ Show the current working directory.
+
+ nsh> cd /dev
+ nsh> pwd
+ /dev
+ nsh>
+
+ Same as 'echo $PWD'
+
+ nsh> echo $PWD
+ /dev
+ nsh>
+
+o rm <file-path>
+
+ Remove the specified <file-path> name from the mounted file system.
+ Recall that NuttX uses a pseudo filesystem for its root file system.
+ The rm command can only be used to remove (unlink) files in volumes
+ set up with the mount command; it cannot be used to remove names from
+ the pseudo filesystem.
+
+ Example:
+ ^^^^^^^^
+
+ nsh> ls /mnt/fs/testdir
+ /mnt/fs/testdir:
+ TESTFILE.TXT
+ EXAMPLE.TXT
+ nsh> rm /mnt/fs/testdir/example.txt
+ nsh> ls /mnt/fs/testdir
+ /mnt/fs/testdir:
+ TESTFILE.TXT
+ nsh>
+
+o rmdir <dir-path>
+
+ Remove the specified <dir-path> directory from the mounted file system.
+ Recall that NuttX uses a pseudo filesystem for its root file system. The
+ rmdir command can only be used to remove directories from volumes set up
+ with the mount command; it cannot be used to remove directories from the
+ pseudo filesystem.
+
+ Example:
+ ^^^^^^^^
+
+ nsh> mkdir /mnt/fs/tmp
+ nsh> ls -l /mnt/fs
+ /mnt/fs:
+ drw-rw-rw- 0 TESTDIR/
+ drw-rw-rw- 0 TMP/
+ nsh> rmdir /mnt/fs/tmp
+ nsh> ls -l /mnt/fs
+ ls -l /mnt/fs
+ /mnt/fs:
+ drw-rw-rw- 0 TESTDIR/
+ nsh>
+
+o set <name> <value>
+
+ Set the environment variable <name> to the sting <value>.
+ For example,
+
+ nsh> echo $foobar
+
+ nsh> set foobar foovalue
+ nsh> echo $foobar
+ foovalue
+ nsh>
+
+o sh <script-path>
+
+ Execute the sequence of NSH commands in the file referred
+ to by <script-path>.
+
+o sleep <sec>
+
+ Pause execution (sleep) of <sec> seconds.
+
+o unset <name>
+
+ Remove the value associated with the environment variable
+ <name>. Example:
+
+ nsh> echo $foobar
+ foovalue
+ nsh> unset foobar
+ nsh> echo $foobar
+
+ nsh>
+
+o usleep <usec>
+
+ Pause execution (sleep) of <usec> microseconds.
+
+o wget [-o <local-path>] <url>
+
+ Use HTTP to copy the file at <url> to the current directory.
+ Options:
+
+ -o <local-path>
+ The file will be saved relative to the current working directory
+ and with the same name as on the HTTP server unless <local-path>
+ is provided.
+
+o xd <hex-address> <byte-count>
+
+ Dump <byte-count> bytes of data from address <hex-address>
+
+ Example:
+ ^^^^^^^^
+
+ nsh> xd 410e0 512
+ Hex dump:
+ 0000: 00 00 00 00 9c 9d 03 00 00 00 00 01 11 01 10 06 ................
+ 0010: 12 01 11 01 25 08 13 0b 03 08 1b 08 00 00 02 24 ....%..........$
+ ...
+ 01f0: 08 3a 0b 3b 0b 49 13 00 00 04 13 01 01 13 03 08 .:.;.I..........
+ nsh>
+
+NSH Configuration Settings
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The availability of the above commands depends upon features that
+may or may not be enabled in the NuttX configuration file. The
+following table indicates the dependency of each command on NuttX
+configuration settings. General configuration settings are discussed
+in the NuttX Porting Guide. Configuration settings specific to NSH
+as discussed at the bottom of this README file.
+
+Command Dependencies on Configuration Settings
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Command Depends on Configuration
+ ---------- --------------------------
+ [ !CONFIG_EXAMPLES_NSH_DISABLESCRIPT
+ cat CONFIG_NFILE_DESCRIPTORS > 0
+ cd !CONFIG_DISABLE_ENVIRON && CONFIG_NFILE_DESCRIPTORS > 0
+ cp CONFIG_NFILE_DESCRIPTORS > 0
+ dd CONFIG_NFILE_DESCRIPTORS > 0
+ echo --
+ exec --
+ exit --
+ free --
+ get CONFIG_NET && CONFIG_NET_UDP && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NET_BUFSIZE >= 558 (see note 1)
+ help --
+ ifconfig CONFIG_NET
+ kill !CONFIG_DISABLE_SIGNALS
+ losetup !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0
+ ls CONFIG_NFILE_DESCRIPTORS > 0
+ mb,mh,mw ---
+ mkdir !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_WRITABLE (see note 4)
+ mkfatfs !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_FAT
+ mkfifo CONFIG_NFILE_DESCRIPTORS > 0
+ mkrd !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_WRITABLE (see note 4)
+ mount !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_READABLE (see note 3)
+ ping CONFIG_NET && CONFIG_NET_ICMP && CONFIG_NET_ICMP_PING && !CONFIG_DISABLE_CLOCK && !CONFIG_DISABLE_SIGNALS
+ ps --
+ put CONFIG_NET && CONFIG_NET_UDP && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NET_BUFSIZE >= 558 (see note 1,2)
+ pwd !CONFIG_DISABLE_ENVIRON && CONFIG_NFILE_DESCRIPTORS > 0
+ rm !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_WRITABLE (see note 4)
+ rmdir !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_WRITABLE (see note 4)
+ set !CONFIG_DISABLE_ENVIRON
+ sh CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 && !CONFIG_EXAMPLES_NSH_DISABLESCRIPT
+ sleep !CONFIG_DISABLE_SIGNALS
+ test !CONFIG_EXAMPLES_NSH_DISABLESCRIPT
+ umount !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_READABLE
+ unset !CONFIG_DISABLE_ENVIRON
+ usleep !CONFIG_DISABLE_SIGNALS
+ get CONFIG_NET && CONFIG_NET_TCP && CONFIG_NFILE_DESCRIPTORS > 0
+ xd ---
+
+* NOTES:
+ 1. Because of hardware padding, the actual buffersize required for put and get
+ operations size may be larger.
+ 2. Special TFTP server start-up optionss will probably be required to permit
+ creation of file for the correct operation of the put command.
+ 3. CONFIG_FS_READABLE is not a user configuration but is set automatically
+ if any readable filesystem is selected. At present, this is either CONFIG_FS_FAT
+ and CONFIG_FS_ROMFS.
+ 4. CONFIG_FS_WRITABLE is not a user configuration but is set automatically
+ if any writable filesystem is selected. At present, this is only CONFIG_FS_FAT.
+
+In addition, each NSH command can be individually disabled via one of the following
+settings. All of these settings make the configuration of NSH potentially complex but
+also allow it to squeeze into very small memory footprints.
+
+ CONFIG_EXAMPLES_NSH_DISABLE_CAT, CONFIG_EXAMPLES_NSH_DISABLE_CD, CONFIG_EXAMPLES_NSH_DISABLE_CP,
+ CONFIG_EXAMPLES_NSH_DISABLE_DD, CONFIG_EXAMPLES_NSH_DISABLE_ECHO, CONFIG_EXAMPLES_NSH_DISABLE_EXEC,
+ CONFIG_EXAMPLES_NSH_DISABLE_EXIT, CONFIG_EXAMPLES_NSH_DISABLE_FREE, CONFIG_EXAMPLES_NSH_DISABLE_GET,
+ CONFIG_EXAMPLES_NSH_DISABLE_HELP, CONFIG_EXAMPLES_NSH_DISABLE_IFCONFIG, CONFIG_EXAMPLES_NSH_DISABLE_KILL,
+ CONFIG_EXAMPLES_NSH_DISABLE_LOSETUP, CONFIG_EXAMPLES_NSH_DISABLE_LS, CONFIG_EXAMPLES_NSH_DISABLE_MB,
+ CONFIG_EXAMPLES_NSH_DISABLE_MKDIR, CONFIG_EXAMPLES_NSH_DISABLE_MKFATFS, CONFIG_EXAMPLES_NSH_DISABLE_MKFIFO,
+ CONFIG_EXAMPLES_NSH_DISABLE_MKRD, CONFIG_EXAMPLES_NSH_DISABLE_MH, CONFIG_EXAMPLES_NSH_DISABLE_MOUNT,
+ CONFIG_EXAMPLES_NSH_DISABLE_MW, CONFIG_EXAMPLES_NSH_DISABLE_PS, CONFIG_EXAMPLES_NSH_DISABLE_PING,
+ CONFIG_EXAMPLES_NSH_DISABLE_PUT, CONFIG_EXAMPLES_NSH_DISABLE_PWD, CONFIG_EXAMPLES_NSH_DISABLE_RM,
+ CONFIG_EXAMPLES_NSH_DISABLE_RMDIR, CONFIG_EXAMPLES_NSH_DISABLE_SET, CONFIG_EXAMPLES_NSH_DISABLE_SH,
+ CONFIG_EXAMPLES_NSH_DISABLE_SLEEP, CONFIG_EXAMPLES_NSH_DISABLE_TEST, CONFIG_EXAMPLES_NSH_DISABLE_UMOUNT,
+ CONFIG_EXAMPLES_NSH_DISABLE_UNSET, CONFIG_EXAMPLES_NSH_DISABLE_USLEEP, CONFIG_EXAMPLES_NSH_DISABLE_WGET,
+ CONFIG_EXAMPLES_NSH_DISABLE_XD
+
+NSH-Specific Configuration Settings
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ The behavior of NSH can be modified with the following settings in
+ the configs/<board-name>/defconfig file:
+
+ * CONFIG_EXAMPLES_NSH_FILEIOSIZE
+ Size of a static I/O buffer used for file access (ignored if
+ there is no filesystem). Default is 1024.
+
+ * CONFIG_EXAMPLES_NSH_STRERROR
+ strerror(errno) makes more readable output but strerror() is
+ very large and will not be used unless this setting is 'y'
+
+ * CONFIG_EXAMPLES_NSH_LINELEN
+ The maximum length of one command line and of one output line.
+ Default: 80
+
+ * CONFIG_EXAMPLES_NSH_STACKSIZE
+ The stack size to use when spawning new threads or tasks. Such
+ new threads are generated when a command is executed in background
+ or as new TELNET connections are established.
+
+ * CONFIG_EXAMPLES_NSH_NESTDEPTH
+ The maximum number of nested if-then[-else]-fi sequences that
+ are permissable. Default: 3
+
+ * CONFIG_EXAMPLES_NSH_DISABLESCRIPT
+ This can be set to 'y' to suppress support for scripting. This
+ setting disables the 'sh', 'test', and '[' commands and the
+ if-then[-else]-fi construct. This would only be set on systems
+ where a minimal footprint is a necessity and scripting is not.
+
+ * CONFIG_EXAMPLES_NSH_DISABLEBG
+ This can be set to 'y' to suppress support for background
+ commands. This setting disables the 'nice' command prefix and
+ the '&' command suffix. This would only be set on systems
+ where a minimal footprint is a necessity and background command
+ execution is not.
+
+ * CONFIG_EXAMPLES_NSH_MMCSDMINOR
+ If the architecture supports an MMC/SD slot and if the NSH
+ architecture specific logic is present, this option will provide
+ the MMC/SD minor number, i.e., the MMC/SD block driver will
+ be registered as /dev/mmcsdN where N is the minor number.
+ Default is zero.
+
+ * CONFIG_EXAMPLES_NSH_ROMFSETC
+ Mount a ROMFS filesystem at /etc and provide a startup script
+ at /etc/init.d/rcS. The default startup script will mount
+ a FAT FS RAMDISK at /tmp but the logic is easily extensible.
+
+ * CONFIG_EXAMPLES_NSH_CONSOLE
+ If CONFIG_EXAMPLES_NSH_CONSOLE is set to 'y', then a serial
+ console front-end is selected.
+
+ * CONFIG_EXAMPLES_NSH_TELNET
+ If CONFIG_EXAMPLES_NSH_TELNET is set to 'y', then a TELENET
+ server front-end is selected. When this option is provided,
+ you may log into NuttX remotely using telnet in order to
+ access NSH.
+
+ * CONFIG_EXAMPLES_NSH_ARCHINIT
+ Set if your board provides architecture specific initialization
+ via the board-specific function nsh_archinitialize(). This
+ function will be called early in NSH initialization to allow
+ board logic to do such things as configure MMC/SD slots.
+
+ One or both of CONFIG_EXAMPLES_NSH_CONSOLE and CONFIG_EXAMPLES_NSH_TELNET
+ must be defined. If CONFIG_EXAMPLES_NSH_TELNET is selected, then there some
+ other configuration settings that apply:
+
+ * CONFIG_NET=y
+ Of course, networking must be enabled
+
+ * CONFIG_NSOCKET_DESCRIPTORS
+ And, of course, you must allocate some socket descriptors.
+
+ * CONFIG_NET_TCP=y
+ TCP/IP support is required for telnet (as well as various other TCP-related
+ configuration settings).
+
+ * CONFIG_EXAMPLES_NSH_IOBUFFER_SIZE
+ Determines the size of the I/O buffer to use for sending/
+ receiving TELNET commands/reponses
+
+ * CONFIG_EXAMPLES_NSH_DHCPC
+ Obtain the IP address via DHCP.
+
+ * CONFIG_EXAMPLES_NSH_IPADDR
+ If CONFIG_EXAMPLES_NSH_DHCPC is NOT set, then the static IP
+ address must be provided.
+
+ * CONFIG_EXAMPLES_NSH_DRIPADDR
+ Default router IP address
+
+ * CONFIG_EXAMPLES_NSH_NETMASK
+ Network mask
+
+ * CONFIG_EXAMPLES_NSH_NOMAC
+ Set if your ethernet hardware has no built-in MAC address.
+ If set, a bogus MAC will be assigned.
+
+ If you use DHCPC, then some special configuration network options are
+ required. These include:
+
+ * CONFIG_NET=y
+ Of course, networking must be enabled
+
+ * CONFIG_NSOCKET_DESCRIPTORS
+ And, of course, you must allocate some socket descriptors.
+
+ * CONFIG_NET_UDP=y
+ UDP support is required for DHCP (as well as various other UDP-related
+ configuration settings)
+
+ * CONFIG_NET_BROADCAST=y
+ UDP broadcast support is needed.
+
+ * CONFIG_NET_BUFSIZE=650 (or larger)
+ Per RFC2131 (p. 9), the DHCP client must be prepared to receive DHCP
+ messages of up to 576 bytes (excluding Ethernet, IP, or UDP headers and FCS).
+
+ If CONFIG_EXAMPLES_NSH_ROMFSETC is selected, then the following additional
+ configuration setting apply:
+
+ * CONFIG_EXAMPLES_NSH_ROMFSMOUNTPT
+ The default mountpoint for the ROMFS volume is /etc, but that
+ can be changed with this setting. This must be a absolute path
+ beginning with '/'.
+
+ * CONFIG_EXAMPLES_NSH_INITSCRIPT
+ This is the relative path to the startup script within the mountpoint.
+ The default is init.d/rcS. This is a relative path and must not
+ start with '/'.
+
+ * CONFIG_EXAMPLES_NSH_ROMFSDEVNO
+ This is the minor number of the ROMFS block device. The default is
+ '0' corresponding to /dev/ram0.
+
+ * CONFIG_EXAMPLES_NSH_ROMFSSECTSIZE
+ This is the sector size to use with the ROMFS volume. Since the
+ default volume is very small, this defaults to 64 but should be
+ increased if the ROMFS volume were to be become large. Any value
+ selected must be a power of 2.
+
+ When the default rcS file used when CONFIG_EXAMPLES_NSH_ROMFSETC is
+ selected, it will mount a FAT FS under /tmp. The following selections
+ describe that FAT FS.
+
+ * CONFIG_EXAMPLES_NSH_FATDEVNO
+ This is the minor number of the FAT FS block device. The default is
+ '1' corresponding to /dev/ram1.
+
+ * CONFIG_EXAMPLES_NSH_FATSECTSIZE
+ This is the sector size use with the FAT FS. Default is 512.
+
+ * CONFIG_EXAMPLES_NSH_FATNSECTORS
+ This is the number of sectors to use with the FAT FS. Defalt is
+ 1024. The amount of memory used by the FAT FS will be
+ CONFIG_EXAMPLES_NSH_FATSECTSIZE * CONFIG_EXAMPLES_NSH_FATNSECTORS
+ bytes.
+
+ * CONFIG_EXAMPLES_NSH_FATMOUNTPT
+ This is the location where the FAT FS will be mounted. Default
+ is /tmp.
+
+Common Problems
+^^^^^^^^^^^^^^^
+
+ Problem:
+ Using NSH over serial, the "nsh>" prompt repeats over and over again
+ with no serial input.
+ Usual Cause:
+ NSH over serial needs to use the interrupt driven serial driver
+ (drivers/serial/serial.c) not the polled serial driver (drivers/serial/lowconsole.c).
+ Make sure that the polled console is disabled in the OS configuration
+ file, .config. That file should have CONFIG_DEV_LOWCONSOLE=n for
+ NSH over serial.
diff --git a/apps/nshlib/nsh.h b/apps/nshlib/nsh.h
new file mode 100644
index 000000000..c92bb6e80
--- /dev/null
+++ b/apps/nshlib/nsh.h
@@ -0,0 +1,490 @@
+/****************************************************************************
+ * apps/nshlib/nsh.h
+ *
+ * Copyright (C) 2007-2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __NSH_H
+#define __HSH_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef CONFIG_EXAMPLES_NSH_CONSOLE
+# include <stdio.h>
+#endif
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/* The telnetd interface and background commands require pthread support */
+
+#ifdef CONFIG_DISABLE_PTHREAD
+# undef CONFIG_EXAMPLES_NSH_TELNET
+# ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+# define CONFIG_EXAMPLES_NSH_DISABLEBG 1
+# endif
+#endif
+
+/* Telnetd requires networking support */
+
+#ifndef CONFIG_NET
+# undef CONFIG_EXAMPLES_NSH_TELNET
+#endif
+
+/* One front end must be defined */
+
+#if !defined(CONFIG_EXAMPLES_NSH_CONSOLE) && !defined(CONFIG_EXAMPLES_NSH_TELNET)
+# error "No NSH front end defined"
+#endif
+
+/* Verify support for ROMFS /etc directory support options */
+
+#ifdef CONFIG_EXAMPLES_NSH_ROMFSETC
+# ifdef CONFIG_DISABLE_MOUNTPOINT
+# error "Mountpoint support is disabled"
+# undef CONFIG_EXAMPLES_NSH_ROMFSETC
+# endif
+# if CONFIG_NFILE_DESCRIPTORS < 4
+# error "Not enough file descriptors"
+# undef CONFIG_EXAMPLES_NSH_ROMFSETC
+# endif
+# ifndef CONFIG_FS_ROMFS
+# error "ROMFS support not enabled"
+# undef CONFIG_EXAMPLES_NSH_ROMFSETC
+# endif
+# ifndef CONFIG_EXAMPLES_NSH_ROMFSMOUNTPT
+# define CONFIG_EXAMPLES_NSH_ROMFSMOUNTPT "/etc"
+# endif
+# ifdef CONFIG_EXAMPLES_NSH_INIT
+# ifndef CONFIG_EXAMPLES_NSH_INITSCRIPT
+# define CONFIG_EXAMPLES_NSH_INITSCRIPT "init.d/rcS"
+# endif
+# endif
+# undef NSH_INITPATH
+# define NSH_INITPATH CONFIG_EXAMPLES_NSH_ROMFSMOUNTPT "/" CONFIG_EXAMPLES_NSH_INITSCRIPT
+# ifndef CONFIG_EXAMPLES_NSH_ROMFSDEVNO
+# define CONFIG_EXAMPLES_NSH_ROMFSDEVNO 0
+# endif
+# ifndef CONFIG_EXAMPLES_NSH_ROMFSSECTSIZE
+# define CONFIG_EXAMPLES_NSH_ROMFSSECTSIZE 64
+# endif
+# define NSECTORS(b) (((b)+CONFIG_EXAMPLES_NSH_ROMFSSECTSIZE-1)/CONFIG_EXAMPLES_NSH_ROMFSSECTSIZE)
+# define STR_RAMDEVNO(m) #m
+# define MKMOUNT_DEVNAME(m) "/dev/ram" STR_RAMDEVNO(m)
+# define MOUNT_DEVNAME MKMOUNT_DEVNAME(CONFIG_EXAMPLES_NSH_ROMFSDEVNO)
+#else
+# undef CONFIG_EXAMPLES_NSH_ROMFSMOUNTPT
+# undef CONFIG_EXAMPLES_NSH_INIT
+# undef CONFIG_EXAMPLES_NSH_INITSCRIPT
+# undef CONFIG_EXAMPLES_NSH_ROMFSDEVNO
+# undef CONFIG_EXAMPLES_NSH_ROMFSSECTSIZE
+#endif
+
+/* This is the maximum number of arguments that will be accepted for a command */
+
+#define NSH_MAX_ARGUMENTS 6
+
+/* strerror() produces much nicer output but is, however, quite large and
+ * will only be used if CONFIG_EXAMPLES_NSH_STRERROR is defined.
+ */
+
+#ifdef CONFIG_EXAMPLES_NSH_STRERROR
+# define NSH_ERRNO strerror(errno)
+# define NSH_ERRNO_OF(err) strerror(err)
+#else
+# define NSH_ERRNO (errno)
+# define NSH_ERRNO_OF(err) (err)
+#endif
+
+/* Maximum size of one command line (telnet or serial) */
+
+#ifndef CONFIG_EXAMPLES_NSH_LINELEN
+# define CONFIG_EXAMPLES_NSH_LINELEN 80
+#endif
+
+/* The following two settings are used only in the telnetd interface */
+
+#ifndef CONFIG_EXAMPLES_NSH_IOBUFFER_SIZE
+# define CONFIG_EXAMPLES_NSH_IOBUFFER_SIZE 512
+#endif
+
+/* As threads are created to handle each request, a stack must be allocated
+ * for the thread. Use a default if the user provided no stacksize.
+ */
+
+#ifndef CONFIG_EXAMPLES_NSH_STACKSIZE
+# define CONFIG_EXAMPLES_NSH_STACKSIZE 4096
+#endif
+
+/* The maximum number of nested if-then[-else]-fi sequences that
+ * are permissable.
+ */
+
+#ifndef CONFIG_EXAMPLES_NSH_NESTDEPTH
+# define CONFIG_EXAMPLES_NSH_NESTDEPTH 3
+#endif
+
+/* Define to enable dumping of all input/output buffers */
+
+#undef CONFIG_EXAMPLES_NSH_TELNETD_DUMPBUFFER
+#undef CONFIG_EXAMPLES_NSH_FULLPATH
+
+/* Make sure that the home directory is defined */
+
+#ifndef CONFIG_LIB_HOMEDIR
+# define CONFIG_LIB_HOMEDIR "/"
+#endif
+
+/* Method access macros */
+
+#define nsh_clone(v) (v)->clone(v)
+#define nsh_release(v) (v)->release(v)
+#define nsh_write(v,b,n) (v)->write(v,b,n)
+#define nsh_linebuffer(v) (v)->linebuffer(v)
+#define nsh_redirect(v,f,s) (v)->redirect(v,f,s)
+#define nsh_undirect(v,s) (v)->undirect(v,s)
+#define nsh_exit(v) (v)->exit(v)
+
+#ifdef CONFIG_CPP_HAVE_VARARGS
+# define nsh_output(v, fmt...) (v)->output(v, ##fmt)
+#else
+# define nsh_output vtbl->output
+#endif
+
+/* Size of info to be saved in call to nsh_redirect */
+
+#define SAVE_SIZE (sizeof(int) + sizeof(FILE*) + sizeof(bool))
+
+/* Stubs used when working directory is not supported */
+
+#if CONFIG_NFILE_DESCRIPTORS <= 0 || defined(CONFIG_DISABLE_ENVIRON)
+# define nsh_getfullpath(v,p) ((char*)(p))
+# define nsh_freefullpath(p)
+#endif
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+enum nsh_parser_e
+{
+ NSH_PARSER_NORMAL = 0,
+ NSH_PARSER_IF,
+ NSH_PARSER_THEN,
+ NSH_PARSER_ELSE
+};
+
+struct nsh_state_s
+{
+ uint8_t ns_ifcond : 1; /* Value of command in 'if' statement */
+ uint8_t ns_disabled : 1; /* TRUE: Unconditionally disabled */
+ uint8_t ns_unused : 4;
+ uint8_t ns_state : 2; /* Parser state (see enum nsh_parser_e) */
+};
+
+struct nsh_parser_s
+{
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+ bool np_bg; /* true: The last command executed in background */
+#endif
+ bool np_redirect; /* true: Output from the last command was re-directed */
+ bool np_fail; /* true: The last command failed */
+#ifndef CONFIG_EXAMPLES_NSH_DISABLESCRIPT
+ uint8_t np_ndx; /* Current index into np_st[] */
+#endif
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+ int np_nice; /* "nice" value applied to last background cmd */
+#endif
+
+ /* This is a stack of parser state information. It supports nested
+ * execution of commands that span multiple lines (like if-then-else-fi)
+ */
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLESCRIPT
+ struct nsh_state_s np_st[CONFIG_EXAMPLES_NSH_NESTDEPTH];
+#endif
+};
+
+struct nsh_vtbl_s
+{
+ /* This function pointers are "hooks" into the front end logic to
+ * handle things like output of command results, redirection, etc.
+ * -- all of which must be done in a way that is unique to the nature
+ * of the front end.
+ */
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+ FAR struct nsh_vtbl_s *(*clone)(FAR struct nsh_vtbl_s *vtbl);
+ void (*addref)(FAR struct nsh_vtbl_s *vtbl);
+ void (*release)(FAR struct nsh_vtbl_s *vtbl);
+#endif
+ ssize_t (*write)(FAR struct nsh_vtbl_s *vtbl, FAR const void *buffer, size_t nbytes);
+ int (*output)(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...);
+ FAR char *(*linebuffer)(FAR struct nsh_vtbl_s *vtbl);
+ void (*redirect)(FAR struct nsh_vtbl_s *vtbl, int fd, FAR uint8_t *save);
+ void (*undirect)(FAR struct nsh_vtbl_s *vtbl, FAR uint8_t *save);
+ void (*exit)(FAR struct nsh_vtbl_s *vtbl);
+
+ /* Parser state data */
+
+ struct nsh_parser_s np;
+};
+
+typedef int (*cmd_t)(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+extern const char g_nshgreeting[];
+extern const char g_nshprompt[];
+extern const char g_nshsyntax[];
+extern const char g_fmtargrequired[];
+extern const char g_fmtarginvalid[];
+extern const char g_fmtargrange[];
+extern const char g_fmtcmdnotfound[];
+extern const char g_fmtnosuch[];
+extern const char g_fmttoomanyargs[];
+extern const char g_fmtdeepnesting[];
+extern const char g_fmtcontext[];
+extern const char g_fmtcmdfailed[];
+extern const char g_fmtcmdoutofmemory[];
+extern const char g_fmtinternalerror[];
+#ifndef CONFIG_DISABLE_SIGNALS
+extern const char g_fmtsignalrecvd[];
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/* Initialization */
+
+#ifdef CONFIG_EXAMPLES_NSH_ROMFSETC
+extern int nsh_romfsetc(void);
+#else
+# define nsh_romfsetc() (-ENOSYS)
+#endif
+
+#ifdef CONFIG_NET
+extern int nsh_netinit(void);
+#else
+# define nsh_netinit() (-ENOSYS)
+#endif
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 && !defined(CONFIG_EXAMPLES_NSH_DISABLESCRIPT)
+extern int nsh_script(FAR struct nsh_vtbl_s *vtbl, const char *cmd, const char *path);
+#endif
+
+/* Architecture-specific initialization */
+
+#ifdef CONFIG_EXAMPLES_NSH_ARCHINIT
+extern int nsh_archinitialize(void);
+#else
+# define nsh_archinitialize() (-ENOSYS)
+#endif
+
+/* Message handler */
+
+extern int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline);
+
+/* Application interface */
+
+#ifdef CONFIG_EXAMPLES_NSH_BUILTIN_APPS
+extern int nsh_execapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
+ FAR char *argv[]);
+#endif
+
+/* Working directory support */
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON)
+extern FAR const char *nsh_getcwd(void);
+extern char *nsh_getfullpath(FAR struct nsh_vtbl_s *vtbl, const char *relpath);
+extern void nsh_freefullpath(char *relpath);
+#endif
+
+/* Debug */
+
+extern void nsh_dumpbuffer(FAR struct nsh_vtbl_s *vtbl, const char *msg,
+ const uint8_t *buffer, ssize_t nbytes);
+
+/* Shell command handlers */
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_ECHO
+ extern int cmd_echo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_EXEC
+ extern int cmd_exec(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_MB
+ extern int cmd_mb(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_MH
+ extern int cmd_mh(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_MW
+ extern int cmd_mw(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_FREE
+ extern int cmd_free(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_PS
+ extern int cmd_ps(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_XD
+ extern int cmd_xd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
+
+#if !defined(CONFIG_EXAMPLES_NSH_DISABLESCRIPT) && !defined(CONFIG_EXAMPLES_NSH_DISABLE_TEST)
+extern int cmd_test(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+extern int cmd_lbracket(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
+
+#if CONFIG_NFILE_DESCRIPTORS > 0
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_CAT
+ extern int cmd_cat(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_CP
+ extern int cmd_cp(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_DD
+ extern int cmd_dd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_LS
+ extern int cmd_ls(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# if CONFIG_NFILE_STREAMS > 0 && !defined(CONFIG_EXAMPLES_NSH_DISABLESCRIPT)
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_SH
+ extern int cmd_sh(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# endif /* CONFIG_NFILE_STREAMS && !CONFIG_EXAMPLES_NSH_DISABLESCRIPT */
+# ifndef CONFIG_DISABLE_MOUNTPOINT
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_LOSETUP
+ extern int cmd_losetup(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_MKFIFO
+ extern int cmd_mkfifo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifdef CONFIG_FS_READABLE
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_MOUNT
+ extern int cmd_mount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_UMOUNT
+ extern int cmd_umount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifdef CONFIG_FS_WRITABLE
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_MKDIR
+ extern int cmd_mkdir(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_MKRD
+ extern int cmd_mkrd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_RM
+ extern int cmd_rm(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_RMDIR
+ extern int cmd_rmdir(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# endif /* CONFIG_FS_WRITABLE */
+# endif /* CONFIG_FS_READABLE */
+# ifdef CONFIG_FS_FAT
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_MKFATFS
+ extern int cmd_mkfatfs(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# endif /* CONFIG_FS_FAT */
+# endif /* !CONFIG_DISABLE_MOUNTPOINT */
+# if !defined(CONFIG_DISABLE_ENVIRON)
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_CD
+ extern int cmd_cd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_PWD
+ extern int cmd_pwd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# endif /* !CONFIG_DISABLE_MOUNTPOINT */
+#endif /* CONFIG_NFILE_DESCRIPTORS */
+
+#if defined(CONFIG_NET)
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_IFCONFIG
+ extern int cmd_ifconfig(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+#if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_GET
+ extern int cmd_get(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_PUT
+ extern int cmd_put(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+#endif
+#if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_WGET
+ extern int cmd_wget(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+#endif
+#if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \
+ !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_DISABLE_SIGNALS)
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_PING
+ extern int cmd_ping(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+#endif
+#endif
+
+#ifndef CONFIG_DISABLE_ENVIRON
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_SET
+ extern int cmd_set(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_UNSET
+ extern int cmd_unset(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+#endif /* CONFIG_DISABLE_ENVIRON */
+
+#ifndef CONFIG_DISABLE_SIGNALS
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_KILL
+ extern int cmd_kill(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_SLEEP
+ extern int cmd_sleep(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_USLEEP
+ extern int cmd_usleep(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+#endif /* CONFIG_DISABLE_SIGNALS */
+
+#endif /* __NSH_H */
diff --git a/apps/nshlib/nsh_apps.c b/apps/nshlib/nsh_apps.c
new file mode 100644
index 000000000..0c786dc12
--- /dev/null
+++ b/apps/nshlib/nsh_apps.c
@@ -0,0 +1,132 @@
+/****************************************************************************
+ * apps/nshlib/nsh_apps.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2011 Uros Platise. All rights reserved.
+ * Author: Uros Platise <uros.platise@isotel.eu>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#ifdef CONFIG_SCHED_WAITPID
+# include <sys/wait.h>
+#endif
+
+#include <stdbool.h>
+#include <errno.h>
+
+#include <apps/apps.h>
+
+#include "nsh.h"
+
+#ifdef CONFIG_EXAMPLES_NSH_BUILTIN_APPS
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_execute
+ ****************************************************************************/
+
+int nsh_execapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
+ FAR char *argv[])
+{
+ int ret = OK;
+ FAR const char * name;
+
+ /* Try to find command within pre-built application list. */
+
+ ret = exec_nuttapp(cmd, argv);
+ if (ret < 0)
+ {
+ int err = -errno;
+ int i;
+
+ /* On failure, list the set of available built-in commands */
+
+ nsh_output(vtbl, "Builtin Apps: ");
+ for (i = 0; (name = nuttapp_getname(i)) != NULL; i++)
+ {
+ nsh_output(vtbl, "%s ", name);
+ }
+ nsh_output(vtbl, "\nand type 'help' for more NSH commands.\n\n");
+
+ return err;
+ }
+
+#ifdef CONFIG_SCHED_WAITPID
+ if (vtbl->np.np_bg == false)
+ {
+ waitpid(ret, NULL, 0);
+ }
+ else
+#endif
+ {
+ struct sched_param param;
+ sched_getparam(0, &param);
+ nsh_output(vtbl, "%s [%d:%d]\n", cmd, ret, param.sched_priority);
+ }
+
+ return OK;
+}
+
+#endif /* CONFIG_EXAMPLES_NSH_BUILTIN_APPS */
+
+
diff --git a/apps/nshlib/nsh_dbgcmds.c b/apps/nshlib/nsh_dbgcmds.c
new file mode 100644
index 000000000..001f5dd49
--- /dev/null
+++ b/apps/nshlib/nsh_dbgcmds.c
@@ -0,0 +1,355 @@
+/****************************************************************************
+ * apps/nshlib/dbg_dbgcmds.c
+ *
+ * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "nsh.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct dbgmem_s
+{
+ bool dm_write; /* true: perfrom write operation */
+ void *dm_addr; /* Address to access */
+ uint32_t dm_value; /* Value to write */
+ unsigned int dm_count; /* The number of bytes to access */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mem_parse
+ ****************************************************************************/
+
+int mem_parse(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv,
+ struct dbgmem_s *mem)
+{
+ char *pcvalue = strchr(argv[1], '=');
+ unsigned long lvalue = 0;
+
+ /* Check if we are writing a value */
+
+ if (pcvalue)
+ {
+ *pcvalue = '\0';
+ pcvalue++;
+
+ lvalue = (unsigned long)strtol(pcvalue, NULL, 16);
+ if (lvalue > 0xffffffff)
+ {
+ return -EINVAL;
+ }
+
+ mem->dm_write = true;
+ mem->dm_value = (uint32_t)lvalue;
+ }
+ else
+ {
+ mem->dm_write = false;
+ mem->dm_value = 0;
+ }
+
+ /* Get the address to be accessed */
+
+ mem->dm_addr = (void*)strtol(argv[1], NULL, 16);
+
+ /* Get the number of bytes to access */
+
+ if (argc > 2)
+ {
+ mem->dm_count = (unsigned int)strtol(argv[2], NULL, 16);
+ }
+ else
+ {
+ mem->dm_count = 1;
+ }
+ return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: cmd_mb
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_MB
+int cmd_mb(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ struct dbgmem_s mem;
+ volatile uint8_t *ptr;
+ int ret;
+ int i;
+
+ ret = mem_parse(vtbl, argc, argv, &mem);
+ if (ret == 0)
+ {
+ /* Loop for the number of requested bytes */
+
+ for (i = 0, ptr = (volatile uint8_t*)mem.dm_addr; i < mem.dm_count; i++, ptr++)
+ {
+ /* Print the value at the address */
+
+ nsh_output(vtbl, " %p = 0x%02x", ptr, *ptr);
+
+ /* Are we supposed to write a value to this address? */
+
+ if (mem.dm_write)
+ {
+ /* Yes, was the supplied value within range? */
+
+ if (mem.dm_value > 0x000000ff)
+ {
+ nsh_output(vtbl, g_fmtargrange, argv[0]);
+ return ERROR;
+ }
+
+ /* Write the value and re-read the address so that we print its
+ * current value (if the address is a process address, then the
+ * value read might not necessarily be the value written).
+ */
+
+ *ptr = (uint8_t)mem.dm_value;
+ nsh_output(vtbl, " -> 0x%02x", *ptr);
+ }
+
+ /* Make sure we end it with a newline */
+
+ nsh_output(vtbl, "\n", *ptr);
+ }
+ }
+ return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: cmd_mh
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_MH
+int cmd_mh(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ struct dbgmem_s mem;
+ volatile uint16_t *ptr;
+ int ret;
+ int i;
+
+ ret = mem_parse(vtbl, argc, argv, &mem);
+ if (ret == 0)
+ {
+ /* Loop for the number of requested bytes */
+
+ for (i = 0, ptr = (volatile uint16_t*)mem.dm_addr; i < mem.dm_count; i += 2, ptr++)
+ {
+ /* Print the value at the address */
+
+ nsh_output(vtbl, " %p = 0x%04x", ptr, *ptr);
+
+ /* Are we supposed to write a value to this address? */
+
+ if (mem.dm_write)
+ {
+ /* Yes, was the supplied value within range? */
+
+ if (mem.dm_value > 0x0000ffff)
+ {
+ nsh_output(vtbl, g_fmtargrange, argv[0]);
+ return ERROR;
+ }
+
+ /* Write the value and re-read the address so that we print its
+ * current value (if the address is a process address, then the
+ * value read might not necessarily be the value written).
+ */
+
+ *ptr = (uint16_t)mem.dm_value;
+ nsh_output(vtbl, " -> 0x%04x", *ptr);
+ }
+
+ /* Make sure we end it with a newline */
+
+ nsh_output(vtbl, "\n", *ptr);
+ }
+ }
+ return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: cmd_mw
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_MW
+int cmd_mw(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ struct dbgmem_s mem;
+ volatile uint32_t *ptr;
+ int ret;
+ int i;
+
+ ret = mem_parse(vtbl, argc, argv, &mem);
+ if (ret == 0)
+ {
+ /* Loop for the number of requested bytes */
+
+ for (i = 0, ptr = (volatile uint32_t*)mem.dm_addr; i < mem.dm_count; i += 4, ptr++)
+ {
+ /* Print the value at the address */
+
+ nsh_output(vtbl, " %p = 0x%08x", ptr, *ptr);
+
+ /* Are we supposed to write a value to this address? */
+
+ if (mem.dm_write)
+ {
+ /* Write the value and re-read the address so that we print its
+ * current value (if the address is a process address, then the
+ * value read might not necessarily be the value written).
+ */
+
+ *ptr = mem.dm_value;
+ nsh_output(vtbl, " -> 0x%08x", *ptr);
+ }
+
+ /* Make sure we end it with a newline */
+
+ nsh_output(vtbl, "\n", *ptr);
+ }
+ }
+ return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: nsh_dumpbuffer
+ ****************************************************************************/
+
+void nsh_dumpbuffer(FAR struct nsh_vtbl_s *vtbl, const char *msg,
+ const uint8_t *buffer, ssize_t nbytes)
+{
+ char line[128];
+ int ch;
+ int i;
+ int j;
+
+ nsh_output(vtbl, "%s:\n", msg);
+ for (i = 0; i < nbytes; i += 16)
+ {
+ sprintf(line, "%04x: ", i);
+
+ for ( j = 0; j < 16; j++)
+ {
+ if (i + j < nbytes)
+ {
+ sprintf(&line[strlen(line)], "%02x ", buffer[i+j] );
+ }
+ else
+ {
+ strcpy(&line[strlen(line)], " ");
+ }
+ }
+
+ for ( j = 0; j < 16; j++)
+ {
+ if (i + j < nbytes)
+ {
+ ch = buffer[i+j];
+ sprintf(&line[strlen(line)], "%c", ch >= 0x20 && ch <= 0x7e ? ch : '.');
+ }
+ }
+ nsh_output(vtbl, "%s\n", line);
+ }
+}
+
+/****************************************************************************
+ * Name: cmd_xd
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_XD
+int cmd_xd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ char *addr;
+ char *endptr;
+ int nbytes;
+
+ addr = (char*)strtol(argv[1], &endptr, 16);
+ if (argv[0][0] == '\0' || *endptr != '\0')
+ {
+ return ERROR;
+ }
+
+ nbytes = (int)strtol(argv[2], &endptr, 0);
+ if (argv[0][0] == '\0' || *endptr != '\0' || nbytes < 0)
+ {
+ return ERROR;
+ }
+
+ nsh_dumpbuffer(vtbl, "Hex dump", (uint8_t*)addr, nbytes);
+ return OK;
+}
+#endif
+
diff --git a/apps/nshlib/nsh_ddcmd.c b/apps/nshlib/nsh_ddcmd.c
new file mode 100644
index 000000000..c33a80ec0
--- /dev/null
+++ b/apps/nshlib/nsh_ddcmd.c
@@ -0,0 +1,641 @@
+/****************************************************************************
+ * apps/nshlib/nsh_ddcmd.c
+ *
+ * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <nuttx/fs.h>
+#include "nsh.h"
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_EXAMPLES_NSH_DISABLE_DD)
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/* If no sector size is specified wity BS=, then the following default value
+ * is used.
+ */
+
+#define DEFAULT_SECTSIZE 512
+
+/* At present, piping of input and output are not support, i.e., both of=
+ * and if= arguments are required.
+ */
+
+#undef CAN_PIPE_FROM_STD
+
+/* Function pointer calls are only need if block drivers are supported
+ * (or, rather, if mount points are supported in the file system)
+ */
+
+#ifndef CONFIG_DISABLE_MOUNTPOINT
+# define DD_INFD ((dd)->inf.fd)
+# define DD_INHANDLE ((dd)->inf.handle)
+# define DD_OUTFD ((dd)->outf.fd)
+# define DD_OUTHANDLE ((dd)->outf.handle)
+# define DD_READ(dd) ((dd)->infread(dd))
+# define DD_WRITE(dd) ((dd)->outfwrite(dd))
+# define DD_INCLOSE(dd) ((dd)->infclose(dd))
+# define DD_OUTCLOSE(dd) ((dd)->outfclose(dd))
+#else
+# define DD_INFD ((dd)->infd)
+# undef DD_INHANDLE
+# define DD_OUTFD ((dd)->outfd)
+# undef DD_OUTHANDLE
+# define DD_READ(dd) dd_readch(dd)
+# define DD_WRITE(dd) dd_writech(dd)
+# define DD_INCLOSE(dd) dd_infclosech(dd)
+# define DD_OUTCLOSE(dd) dd_outfclosech(dd)
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct dd_s
+{
+ FAR struct nsh_vtbl_s *vtbl;
+
+#ifndef CONFIG_DISABLE_MOUNTPOINT
+ union
+ {
+ FAR void *handle; /* BCH lib handle for block device*/
+ int fd; /* File descriptor of the character device */
+ } inf;
+#else
+ int infd; /* File descriptor of the input device */
+#endif
+
+#ifndef CONFIG_DISABLE_MOUNTPOINT
+ union
+ {
+ FAR void *handle; /* BCH lib handle for block device*/
+ int fd; /* File descriptor of the character device */
+ } outf;
+#else
+ int outfd; /* File descriptor of the output device */
+#endif
+
+ uint32_t nsectors; /* Number of sectors to transfer */
+ uint32_t sector; /* The current sector number */
+ uint32_t skip; /* The number of sectors skipped on input */
+ bool eof; /* true: The of the input or output file has been hit */
+ uint16_t sectsize; /* Size of one sector */
+ uint16_t nbytes; /* Number of valid bytes in the buffer */
+ uint8_t *buffer; /* Buffer of data to write to the output file */
+
+ /* Function pointers to handle differences between block and character devices */
+
+#ifndef CONFIG_DISABLE_MOUNTPOINT
+ int (*infread)(struct dd_s *dd);
+ void (*infclose)(struct dd_s *dd);
+ int (*outfwrite)(struct dd_s *dd);
+ void (*outfclose)(struct dd_s *dd);
+#endif
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const char g_dd[] = "dd";
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: dd_outfcloseblk
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_MOUNTPOINT
+static void dd_outfcloseblk(struct dd_s *dd)
+{
+ (void)bchlib_teardown(DD_OUTHANDLE);
+}
+#endif
+
+
+/****************************************************************************
+ * Name: dd_outfclosech
+ ****************************************************************************/
+
+static void dd_outfclosech(struct dd_s *dd)
+{
+ (void)close(DD_OUTFD);
+}
+
+/****************************************************************************
+ * Name: dd_infcloseblk
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_MOUNTPOINT
+static void dd_infcloseblk(struct dd_s *dd)
+{
+ (void)bchlib_teardown(DD_INHANDLE);
+}
+#endif
+
+/****************************************************************************
+ * Name: dd_infclosech
+ ****************************************************************************/
+
+static void dd_infclosech(struct dd_s *dd)
+{
+ (void)close(DD_INFD);
+}
+
+/****************************************************************************
+ * Name: dd_writeblk
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_MOUNTPOINT
+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)
+ {
+ /* 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
+ {
+ FAR struct nsh_vtbl_s *vtbl = dd->vtbl;
+ nsh_output(vtbl, g_fmtcmdfailed, g_dd, "bshlib_write", NSH_ERRNO_OF(-nbytes));
+ return ERROR;
+ }
+ }
+
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: dd_writech
+ ****************************************************************************/
+
+static int dd_writech(struct dd_s *dd)
+{
+ uint8_t *buffer = dd->buffer;
+ uint16_t written ;
+ ssize_t nbytes;
+
+ /* Is the out buffer full (or is this the last one)? */
+
+ written = 0;
+ do
+ {
+ nbytes = write(DD_OUTFD, buffer, dd->sectsize - written);
+ if (nbytes < 0)
+ {
+ FAR struct nsh_vtbl_s *vtbl = dd->vtbl;
+ nsh_output(vtbl, g_fmtcmdfailed, g_dd, "write", NSH_ERRNO_OF(-nbytes));
+ return ERROR;
+ }
+
+ written += nbytes;
+ buffer += nbytes;
+ }
+ while (written < dd->sectsize);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: dd_readblk
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_MOUNTPOINT
+static int dd_readblk(struct dd_s *dd)
+{
+ ssize_t nbytes;
+ off_t offset = dd->sector * dd->sectsize;
+
+ nbytes = bchlib_read(DD_INHANDLE, (char*)dd->buffer, offset, dd->sectsize);
+ if (nbytes < 0)
+ {
+ FAR struct nsh_vtbl_s *vtbl = dd->vtbl;
+ nsh_output(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
+
+/****************************************************************************
+ * Name: dd_readch
+ ****************************************************************************/
+
+static int dd_readch(struct dd_s *dd)
+{
+ uint8_t *buffer = dd->buffer;
+ ssize_t nbytes;
+
+ dd->nbytes = 0;
+ do
+ {
+ nbytes = read(DD_INFD, buffer, dd->sectsize - dd->nbytes);
+ if (nbytes < 0)
+ {
+ FAR struct nsh_vtbl_s *vtbl = dd->vtbl;
+ nsh_output(vtbl, g_fmtcmdfailed, g_dd, "read", NSH_ERRNO_OF(-nbytes));
+ return ERROR;
+ }
+
+ dd->nbytes += nbytes;
+ buffer += nbytes;
+ }
+ while (dd->nbytes < dd->sectsize && nbytes > 0);
+
+ dd->eof |= (dd->nbytes == 0);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: dd_infopen
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_MOUNTPOINT
+static int dd_filetype(const char *filename)
+{
+ struct stat sb;
+ int ret;
+
+ /* Get the type of the file */
+
+ ret = stat(filename, &sb);
+ if (ret < 0)
+ {
+ return ERROR; /* Return -1 on failure */
+ }
+
+ return S_ISBLK(sb.st_mode); /* Return true(1) if block, false(0) if char */
+}
+#endif
+
+/****************************************************************************
+ * Name: dd_infopen
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_MOUNTPOINT
+static inline int dd_infopen(const char *name, struct dd_s *dd)
+{
+ FAR struct nsh_vtbl_s *vtbl = dd->vtbl;
+ int ret;
+ int type;
+
+ /* Get the type of the input file */
+
+ type = dd_filetype(name);
+ if (type < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, g_dd, "stat", NSH_ERRNO_OF(-type));
+ return type;
+ }
+
+ /* Open the input file */
+
+ if (!type)
+ {
+ DD_INFD = open(name, O_RDONLY);
+ if (DD_INFD < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, g_dd, "open", NSH_ERRNO);
+ return ERROR;
+ }
+
+ dd->infread = dd_readch; /* Character oriented read */
+ dd->infclose = dd_infclosech;
+ }
+ else
+ {
+ ret = bchlib_setup(name, true, &DD_INHANDLE);
+ if (ret < 0)
+ {
+ return ERROR;
+ }
+
+ dd->infread = dd_readblk;
+ dd->infclose = dd_infcloseblk;
+ }
+ return OK;
+}
+#else
+static inline int dd_infopen(const char *name, struct dd_s *dd)
+{
+ DD_INFD = open(name, O_RDONLY);
+ if (DD_INFD < 0)
+ {
+ FAR struct nsh_vtbl_s *vtbl = dd->vtbl;
+ nsh_output(vtbl, g_fmtcmdfailed, g_dd, "open", NSH_ERRNO);
+ return ERROR;
+ }
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: dd_outfopen
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_MOUNTPOINT
+static inline int dd_outfopen(const char *name, struct dd_s *dd)
+{
+ int type;
+ int ret = OK;
+
+ /* Get the type of the output file */
+
+ type = dd_filetype(name);
+
+ /* Open the block driver for input */
+
+ if (type == true)
+ {
+ ret = bchlib_setup(name, true, &DD_OUTHANDLE);
+ if (ret < 0)
+ {
+ return ERROR;
+ }
+
+ dd->outfwrite = dd_writeblk; /* Block oriented write */
+ dd->outfclose = dd_outfcloseblk;
+ }
+
+ /* Otherwise, the file is character oriented or does not exist */
+
+ else
+ {
+ DD_OUTFD = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (DD_OUTFD < 0)
+ {
+ FAR struct nsh_vtbl_s *vtbl = dd->vtbl;
+ nsh_output(vtbl, g_fmtcmdfailed, g_dd, "open", NSH_ERRNO);
+ return ERROR;
+ }
+
+ dd->outfwrite = dd_writech; /* Character oriented write */
+ dd->outfclose = dd_outfclosech;
+ }
+ return OK;
+}
+#else
+static inline int dd_outfopen(const char *name, struct dd_s *dd)
+{
+ DD_OUTFD = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (DD_OUTFD < 0)
+ {
+ FAR struct nsh_vtbl_s *vtbl = dd->vtbl;
+ nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "open", NSH_ERRNO);
+ return ERROR;
+ }
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: cmd_dd
+ ****************************************************************************/
+
+int cmd_dd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ struct dd_s dd;
+ char *infile = NULL;
+ char *outfile = NULL;
+ int ret = ERROR;
+ int i;
+
+ /* Initialize the dd structure */
+
+ memset(&dd, 0, sizeof(struct dd_s));
+ dd.vtbl = vtbl; /* For nsh_output */
+ dd.sectsize = DEFAULT_SECTSIZE; /* Sector size if 'bs=' not provided */
+ dd.nsectors = 0xffffffff; /* MAX_UINT32 */
+
+ /* If no IF= option is provided on the command line, then read
+ * from stdin.
+ */
+
+#ifdef CAN_PIPE_FROM_STD
+ DD_INFD = 0; /* stdin */
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_DD
+ dd.infread = readch; /* Character oriented read */
+ dd.infclose = noclose; /* Don't close stdin */
+#endif
+#endif
+ /* If no OF= option is provided on the command line, then write
+ * to stdout.
+ */
+
+#ifdef CAN_PIPE_FROM_STD
+ DD_OUTDF = 1; /* stdout */
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_DD
+ dd.outfwrite = writech; /* Character oriented write */
+ dd.outfclose = noclose; /* Don't close stdout */
+#endif
+#endif
+
+ /* Parse command line parameters */
+
+ for (i = 1; i < argc; i++)
+ {
+ if (strncmp(argv[i], "if=", 3) == 0)
+ {
+ infile = nsh_getfullpath(vtbl, &argv[i][3]);
+ }
+ else if (strncmp(argv[i], "of=", 3) == 0)
+ {
+ outfile = nsh_getfullpath(vtbl, &argv[i][3]);
+ }
+ else if (strncmp(argv[i], "bs=", 3) == 0)
+ {
+ dd.sectsize = atoi(&argv[i][3]);
+ }
+ else if (strncmp(argv[i], "count=", 6) == 0)
+ {
+ dd.nsectors = atoi(&argv[i][6]);
+ }
+ else if (strncmp(argv[i], "skip=", 5) == 0)
+ {
+ dd.skip = atoi(&argv[i][5]);
+ }
+ }
+
+#ifndef CAN_PIPE_FROM_STD
+ if (!infile || !outfile)
+ {
+ nsh_output(vtbl, g_fmtargrequired, g_dd);
+ goto errout_with_paths;
+ }
+#endif
+
+ if (dd.skip < 0 || dd.skip > dd.nsectors)
+ {
+ nsh_output(vtbl, g_fmtarginvalid, g_dd);
+ goto errout_with_paths;
+ }
+
+ /* Allocate the I/O buffer */
+
+ dd.buffer = malloc(dd.sectsize);
+ if (!dd.buffer)
+ {
+ nsh_output(vtbl, g_fmtcmdoutofmemory, g_dd);
+ goto errout_with_paths;
+ }
+
+ /* Open the input file */
+
+ ret = dd_infopen(infile, &dd);
+ if (ret < 0)
+ {
+ goto errout_with_paths;
+ }
+
+ /* Open the output file */
+
+ ret = dd_outfopen(outfile, &dd);
+ if (ret < 0)
+ {
+ goto errout_with_inf;
+ }
+
+ /* Then perform the data transfer */
+
+ dd.sector = 0;
+ while (!dd.eof && dd.nsectors > 0)
+ {
+ /* Read one sector from from the input */
+
+ ret = DD_READ(&dd);
+ if (ret < 0)
+ {
+ goto errout_with_outf;
+ }
+
+ /* Has the incoming data stream ended? */
+
+ if (!dd.eof)
+ {
+ /* Pad with zero if necessary (at the end of file only) */
+
+ for (i = dd.nbytes; i < dd.sectsize; i++)
+ {
+ dd.buffer[i] = 0;
+ }
+
+ /* Write one sector to the output file */
+
+ 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++;
+ }
+ }
+ 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;
+}
+
+#endif /* CONFIG_NFILE_DESCRIPTORS && !CONFIG_EXAMPLES_NSH_DISABLE_DD */
+
diff --git a/apps/nshlib/nsh_envcmds.c b/apps/nshlib/nsh_envcmds.c
new file mode 100644
index 000000000..edb2693c4
--- /dev/null
+++ b/apps/nshlib/nsh_envcmds.c
@@ -0,0 +1,335 @@
+/****************************************************************************
+ * apps/nshlib/nsh_envcmds.c
+ *
+ * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <libgen.h>
+#include <errno.h>
+
+#include "nsh.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON)
+static const char g_pwd[] = "PWD";
+static const char g_oldpwd[] = "OLDPWD";
+static const char g_home[] = CONFIG_LIB_HOMEDIR;
+#endif
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_getwd
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON)
+static inline FAR const char *nsh_getwd(const char *wd)
+{
+ const char *val;
+
+ /* If no working directory is defined, then default to the home directory */
+
+ val = getenv(wd);
+ if (!val)
+ {
+ val = g_home;
+ }
+ return val;
+}
+#endif
+
+/****************************************************************************
+ * Name: nsh_getdirpath
+ ****************************************************************************/
+
+static inline char *nsh_getdirpath(FAR struct nsh_vtbl_s *vtbl,
+ const char *dirpath, const char *relpath)
+{
+ char *alloc;
+ int len;
+
+ /* Handle the special case where the dirpath is simply */
+
+ if (strcmp(dirpath, "/") == 0)
+ {
+ len = strlen(relpath) + 2;
+ alloc = (char*)malloc(len);
+ if (alloc)
+ {
+ sprintf(alloc, "/%s", relpath);
+ }
+ }
+ else
+ {
+ len = strlen(dirpath) + strlen(relpath) + 2;
+ alloc = (char*)malloc(len);
+ if (alloc)
+ {
+ sprintf(alloc, "%s/%s", dirpath, relpath);
+ }
+ }
+
+ if (!alloc)
+ {
+ nsh_output(vtbl, g_fmtcmdoutofmemory, "nsh_getdirpath");
+ }
+ return alloc;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_getwd
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON)
+FAR const char *nsh_getcwd(void)
+{
+ return nsh_getwd(g_pwd);
+}
+#endif
+/****************************************************************************
+ * Name: nsh_getfullpath
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON)
+char *nsh_getfullpath(FAR struct nsh_vtbl_s *vtbl, const char *relpath)
+{
+ const char *wd;
+
+ /* Handle some special cases */
+
+ if (!relpath || relpath[0] == '\0')
+ {
+ /* No relative path provided */
+
+ return strdup(g_home);
+ }
+ else if (relpath[0] == '/')
+ {
+ return strdup(relpath);
+ }
+
+ /* Get the path to the current working directory */
+
+ wd = nsh_getcwd();
+
+ /* Fake the '.' directory */
+
+ if (strcmp(relpath, ".") == 0)
+ {
+ return strdup(wd);
+ }
+
+ /* Return the full path */
+
+ return nsh_getdirpath(vtbl, wd, relpath);
+}
+#endif
+
+/****************************************************************************
+ * Name: nsh_freefullpath
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON)
+void nsh_freefullpath(char *relpath)
+{
+ if (relpath)
+ {
+ free(relpath);
+ }
+}
+#endif
+
+/****************************************************************************
+ * Name: cmd_cd
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON)
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_CD
+int cmd_cd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ const char *path = argv[1];
+ char *alloc = NULL;
+ char *fullpath = NULL;
+ int ret = OK;
+
+ /* Check for special arguments */
+
+ if (argc < 2 || strcmp(path, "~") == 0)
+ {
+ path = g_home;
+ }
+ else if (strcmp(path, "-") == 0)
+ {
+ alloc = strdup(nsh_getwd(g_oldpwd));
+ path = alloc;
+ }
+ else if (strcmp(path, "..") == 0)
+ {
+ alloc = strdup(nsh_getcwd());
+ path = dirname(alloc);
+ }
+ else
+ {
+ fullpath = nsh_getfullpath(vtbl, path);
+ path = fullpath;
+ }
+
+ /* Set the new workding directory */
+
+ if (chdir(path) != 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "chdir", NSH_ERRNO);
+ ret = ERROR;
+ }
+
+ /* Free any memory that was allocated */
+
+ if (alloc)
+ {
+ free(alloc);
+ }
+
+ if (fullpath)
+ {
+ nsh_freefullpath(fullpath);
+ }
+ return ret;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: cmd_echo
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_ECHO
+int cmd_echo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ int i;
+
+ /* echo each argument, separated by a space as it must have been on the
+ * command line
+ */
+
+ for (i = 1; i < argc; i++)
+ {
+ nsh_output(vtbl, "%s ", argv[i]);
+ }
+ nsh_output(vtbl, "\n");
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: cmd_pwd
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON)
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_PWD
+int cmd_pwd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ nsh_output(vtbl, "%s\n", nsh_getcwd());
+ return OK;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: cmd_set
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_ENVIRON
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_SET
+int cmd_set(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ int ret = setenv(argv[1], argv[2], TRUE);
+ if (ret < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "setenv", NSH_ERRNO);
+ }
+ return ret;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: cmd_unset
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_ENVIRON
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_UNSET
+int cmd_unset(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ int ret = unsetenv(argv[1]);
+ if (ret < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "unsetenv", NSH_ERRNO);
+ }
+ return ret;
+}
+#endif
+#endif
diff --git a/apps/nshlib/nsh_fscmds.c b/apps/nshlib/nsh_fscmds.c
new file mode 100644
index 000000000..4a471e65f
--- /dev/null
+++ b/apps/nshlib/nsh_fscmds.c
@@ -0,0 +1,1341 @@
+/****************************************************************************
+ * apps/nshlib/nsh_fscmds.c
+ *
+ * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#if CONFIG_NFILE_DESCRIPTORS > 0
+# include <sys/stat.h>
+# include <fcntl.h>
+# if !defined(CONFIG_DISABLE_MOUNTPOINT)
+# ifdef CONFIG_FS_READABLE /* Need at least one filesytem in configuration */
+# include <sys/mount.h>
+# include <nuttx/ramdisk.h>
+# endif
+# ifdef CONFIG_FS_FAT
+# include <nuttx/mkfatfs.h>
+# endif
+#endif
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <limits.h>
+#include <libgen.h>
+#include <errno.h>
+#include <debug.h>
+
+#include "nsh.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+#define LSFLAGS_SIZE 1
+#define LSFLAGS_LONG 2
+#define LSFLAGS_RECURSIVE 4
+
+/* The size of the I/O buffer may be specified in the
+ * configs/<board-name>defconfig file -- provided that it is at least as
+ * large as PATH_MAX.
+ */
+
+#if CONFIG_NFILE_DESCRIPTORS > 0
+# ifdef CONFIG_EXAMPLES_NSH_FILEIOSIZE
+# if CONFIG_EXAMPLES_NSH_FILEIOSIZE > (PATH_MAX + 1)
+# define IOBUFFERSIZE CONFIG_EXAMPLES_NSH_FILEIOSIZE
+# else
+# define IOBUFFERSIZE (PATH_MAX + 1)
+# endif
+# else
+# define IOBUFFERSIZE 1024
+# endif
+# else
+# define IOBUFFERSIZE (PATH_MAX + 1)
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+typedef int (*direntry_handler_t)(FAR struct nsh_vtbl_s *, const char *, struct dirent *, void *);
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Common buffer for file I/O. Note the use of this common buffer precludes
+ * multiple copies of NSH running concurrently. It should be allocated per
+ * NSH instance and retained in the "vtbl" as is done for the telnet
+ * connection.
+ */
+
+static char g_iobuffer[IOBUFFERSIZE];
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: trim_dir
+ ****************************************************************************/
+
+static void trim_dir(char *arg)
+{
+ /* Skip any trailing '/' characters (unless it is also the leading '/') */
+
+ int len = strlen(arg) - 1;
+ while (len > 0 && arg[len] == '/')
+ {
+ arg[len] = '\0';
+ len--;
+ }
+}
+
+/****************************************************************************
+ * Name: nsh_getdirpath
+ ****************************************************************************/
+
+static char *nsh_getdirpath(const char *path, const char *file)
+{
+ /* Handle the case where all that is left is '/' */
+
+ if (strcmp(path, "/") == 0)
+ {
+ sprintf(g_iobuffer, "/%s", file);
+ }
+ else
+ {
+ sprintf(g_iobuffer, "%s/%s", path, file);
+ }
+
+ g_iobuffer[PATH_MAX] = '\0';
+ return strdup(g_iobuffer);
+}
+
+/****************************************************************************
+ * Name: foreach_direntry
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0
+static int foreach_direntry(FAR struct nsh_vtbl_s *vtbl, const char *cmd, const char *dirpath,
+ direntry_handler_t handler, void *pvarg)
+{
+ DIR *dirp;
+ int ret = OK;
+
+ /* Trim trailing '/' from directory names */
+
+#ifdef CONFIG_EXAMPLES_NSH_FULLPATH
+ trim_dir(arg);
+#endif
+
+ /* Open the directory */
+
+ dirp = opendir(dirpath);
+
+ if (!dirp)
+ {
+ /* Failed to open the directory */
+
+ nsh_output(vtbl, g_fmtnosuch, cmd, "directory", dirpath);
+ return ERROR;
+ }
+
+ /* Read each directory entry */
+
+ for (;;)
+ {
+ struct dirent *entryp = readdir(dirp);
+ if (!entryp)
+ {
+ /* Finished with this directory */
+
+ break;
+ }
+
+ /* Call the handler with this directory entry */
+
+ if (handler(vtbl, dirpath, entryp, pvarg) < 0)
+ {
+ /* The handler reported a problem */
+
+ ret = ERROR;
+ break;
+ }
+ }
+
+ closedir(dirp);
+ return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: ls_specialdir
+ ****************************************************************************/
+
+static inline int ls_specialdir(const char *dir)
+{
+ /* '.' and '..' directories are not listed like normal directories */
+
+ return (strcmp(dir, ".") == 0 || strcmp(dir, "..") == 0);
+}
+
+/****************************************************************************
+ * Name: ls_handler
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0
+static int ls_handler(FAR struct nsh_vtbl_s *vtbl, const char *dirpath, struct dirent *entryp, void *pvarg)
+{
+ unsigned int lsflags = (unsigned int)pvarg;
+ int ret;
+
+ /* Check if any options will require that we stat the file */
+
+ if ((lsflags & (LSFLAGS_SIZE|LSFLAGS_LONG)) != 0)
+ {
+ struct stat buf;
+ char *fullpath = nsh_getdirpath(dirpath, entryp->d_name);
+
+ /* Yes, stat the file */
+
+ ret = stat(fullpath, &buf);
+ free(fullpath);
+ if (ret != 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, "ls", "stat", NSH_ERRNO);
+ return ERROR;
+ }
+
+ if ((lsflags & LSFLAGS_LONG) != 0)
+ {
+ char details[] = "----------";
+ if (S_ISDIR(buf.st_mode))
+ {
+ details[0]='d';
+ }
+ else if (S_ISCHR(buf.st_mode))
+ {
+ details[0]='c';
+ }
+ else if (S_ISBLK(buf.st_mode))
+ {
+ details[0]='b';
+ }
+
+ if ((buf.st_mode & S_IRUSR) != 0)
+ {
+ details[1]='r';
+ }
+
+ if ((buf.st_mode & S_IWUSR) != 0)
+ {
+ details[2]='w';
+ }
+
+ if ((buf.st_mode & S_IXUSR) != 0)
+ {
+ details[3]='x';
+ }
+
+ if ((buf.st_mode & S_IRGRP) != 0)
+ {
+ details[4]='r';
+ }
+
+ if ((buf.st_mode & S_IWGRP) != 0)
+ {
+ details[5]='w';
+ }
+
+ if ((buf.st_mode & S_IXGRP) != 0)
+ {
+ details[6]='x';
+ }
+
+ if ((buf.st_mode & S_IROTH) != 0)
+ {
+ details[7]='r';
+ }
+
+ if ((buf.st_mode & S_IWOTH) != 0)
+ {
+ details[8]='w';
+ }
+
+ if ((buf.st_mode & S_IXOTH) != 0)
+ {
+ details[9]='x';
+ }
+
+ nsh_output(vtbl, " %s", details);
+ }
+
+ if ((lsflags & LSFLAGS_SIZE) != 0)
+ {
+ nsh_output(vtbl, "%8d", buf.st_size);
+ }
+ }
+
+ /* then provide the filename that is common to normal and verbose output */
+
+#ifdef CONFIG_EXAMPLES_NSH_FULLPATH
+ nsh_output(vtbl, " %s/%s", arg, entryp->d_name);
+#else
+ nsh_output(vtbl, " %s", entryp->d_name);
+#endif
+
+ if (DIRENT_ISDIRECTORY(entryp->d_type) && !ls_specialdir(entryp->d_name))
+ {
+ nsh_output(vtbl, "/\n");
+ }
+ else
+ {
+ nsh_output(vtbl, "\n");
+ }
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: ls_recursive
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0
+static int ls_recursive(FAR struct nsh_vtbl_s *vtbl, const char *dirpath,
+ struct dirent *entryp, void *pvarg)
+{
+ int ret = OK;
+
+ /* Is this entry a directory (and not one of the special directories, . and ..)? */
+
+ if (DIRENT_ISDIRECTORY(entryp->d_type) && !ls_specialdir(entryp->d_name))
+ {
+ /* Yes.. */
+
+ char *newpath;
+ newpath = nsh_getdirpath(dirpath, entryp->d_name);
+
+ /* List the directory contents */
+
+ nsh_output(vtbl, "%s:\n", newpath);
+
+ /* Traverse the directory */
+
+ ret = foreach_direntry(vtbl, "ls", newpath, ls_handler, pvarg);
+ if (ret == 0)
+ {
+ /* Then recurse to list each directory within the directory */
+
+ ret = foreach_direntry(vtbl, "ls", newpath, ls_recursive, pvarg);
+ free(newpath);
+ }
+ }
+ return ret;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: cmd_cat
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_CAT
+int cmd_cat(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ char buffer[IOBUFFERSIZE];
+ char *fullpath;
+ int fd;
+ int i;
+ int ret = OK;
+
+ /* Loop for each file name on the command line */
+
+ for (i = 1; i < argc && ret == OK; i++)
+ {
+ /* Get the fullpath to the file */
+
+ fullpath = nsh_getfullpath(vtbl, argv[i]);
+ if (fullpath)
+ {
+ /* Open the file for reading */
+
+ fd = open(fullpath, O_RDONLY);
+ if (fd < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO);
+ }
+ else
+ {
+ /* And just dump it byte for byte into stdout */
+
+ for (;;)
+ {
+ int nbytesread = read(fd, buffer, IOBUFFERSIZE);
+
+ /* Check for read errors */
+
+ if (nbytesread < 0)
+ {
+ /* EINTR is not an error (but will stop stop the cat) */
+
+#ifndef CONFIG_DISABLE_SIGNALS
+ if (errno == EINTR)
+ {
+ nsh_output(vtbl, g_fmtsignalrecvd, argv[0]);
+ }
+ else
+#endif
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "read", NSH_ERRNO);
+ }
+
+ ret = ERROR;
+ break;
+ }
+
+ /* Check for data successfully read */
+
+ else if (nbytesread > 0)
+ {
+ int nbyteswritten = 0;
+
+ while (nbyteswritten < nbytesread)
+ {
+ ssize_t n = nsh_write(vtbl, buffer, nbytesread);
+ if (n < 0)
+ {
+ /* EINTR is not an error (but will stop stop the cat) */
+
+ #ifndef CONFIG_DISABLE_SIGNALS
+ if (errno == EINTR)
+ {
+ nsh_output(vtbl, g_fmtsignalrecvd, argv[0]);
+ }
+ else
+#endif
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "write", NSH_ERRNO);
+ }
+ ret = ERROR;
+ break;
+ }
+ else
+ {
+ nbyteswritten += n;
+ }
+ }
+ }
+
+ /* Otherwise, it is the end of file */
+
+ else
+ {
+ break;
+ }
+ }
+
+ (void)close(fd);
+ }
+
+ /* Free the allocated full path */
+
+ nsh_freefullpath(fullpath);
+ }
+ }
+ return ret;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: cmd_cp
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_CP
+int cmd_cp(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ struct stat buf;
+ char *srcpath = NULL;
+ char *destpath = NULL;
+ char *allocpath = NULL;
+ int oflags = O_WRONLY|O_CREAT|O_TRUNC;
+ int rdfd;
+ int wrfd;
+ int ret = ERROR;
+
+ /* Get the full path to the source file */
+
+ srcpath = nsh_getfullpath(vtbl, argv[1]);
+ if (!srcpath)
+ {
+ goto errout;
+ }
+
+ /* Open the source file for reading */
+
+ rdfd = open(srcpath, O_RDONLY);
+ if (rdfd < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO);
+ goto errout_with_srcpath;
+ }
+
+ /* Get the full path to the destination file or directory */
+
+ destpath = nsh_getfullpath(vtbl, argv[2]);
+ if (!destpath)
+ {
+ goto errout_with_rdfd;
+ }
+
+ /* Check if the destination is a directory */
+
+ ret = stat(destpath, &buf);
+ if (ret == 0)
+ {
+ /* Something exists here... is it a directory? */
+
+ if (S_ISDIR(buf.st_mode))
+ {
+ /* Yes, it is a directory. Remove any trailing '/' characters from the path */
+
+ trim_dir(argv[2]);
+
+ /* Construct the full path to the new file */
+
+ allocpath = nsh_getdirpath(argv[2], basename(argv[1]) );
+ if (!allocpath)
+ {
+ nsh_output(vtbl, g_fmtcmdoutofmemory, argv[0]);
+ goto errout_with_destpath;
+ }
+
+ /* Open then dest for writing */
+
+ nsh_freefullpath(destpath);
+ destpath = allocpath;
+ }
+ else if (!S_ISREG(buf.st_mode))
+ {
+ /* Maybe it is a driver? */
+
+ oflags = O_WRONLY;
+ }
+ }
+
+ /* Now open the destination */
+
+ wrfd = open(destpath, oflags, 0666);
+ if (wrfd < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO);
+ goto errout_with_allocpath;
+ }
+
+ /* Now copy the file */
+
+ for (;;)
+ {
+ int nbytesread;
+ int nbyteswritten;
+
+ do
+ {
+ nbytesread = read(rdfd, g_iobuffer, IOBUFFERSIZE);
+ if (nbytesread == 0)
+ {
+ /* End of file */
+
+ ret = OK;
+ goto errout_with_wrfd;
+ }
+ else if (nbytesread < 0)
+ {
+ /* EINTR is not an error (but will still stop the copy) */
+
+#ifndef CONFIG_DISABLE_SIGNALS
+ if (errno == EINTR)
+ {
+ nsh_output(vtbl, g_fmtsignalrecvd, argv[0]);
+ }
+ else
+#endif
+ {
+ /* Read error */
+
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "read", NSH_ERRNO);
+ }
+ goto errout_with_wrfd;
+ }
+ }
+ while (nbytesread <= 0);
+
+ do
+ {
+ nbyteswritten = write(wrfd, g_iobuffer, nbytesread);
+ if (nbyteswritten >= 0)
+ {
+ nbytesread -= nbyteswritten;
+ }
+ else
+ {
+ /* EINTR is not an error (but will still stop the copy) */
+
+#ifndef CONFIG_DISABLE_SIGNALS
+ if (errno == EINTR)
+ {
+ nsh_output(vtbl, g_fmtsignalrecvd, argv[0]);
+ }
+ else
+#endif
+ {
+ /* Read error */
+
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "write", NSH_ERRNO);
+ }
+ goto errout_with_wrfd;
+ }
+ }
+ while (nbytesread > 0);
+ }
+
+errout_with_wrfd:
+ close(wrfd);
+
+errout_with_allocpath:
+ if (allocpath)
+ {
+ free(allocpath);
+ }
+
+errout_with_destpath:
+ if (destpath && !allocpath)
+ {
+ nsh_freefullpath(destpath);
+ }
+
+errout_with_rdfd:
+ close(rdfd);
+
+errout_with_srcpath:
+ if (srcpath)
+ {
+ nsh_freefullpath(srcpath);
+ }
+errout:
+ return ret;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: cmd_losetup
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT)
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_LOSETUP
+int cmd_losetup(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ char *loopdev = NULL;
+ char *filepath = NULL;
+ bool teardown = false;
+ bool readonly = false;
+ off_t offset = 0;
+ bool badarg = false;
+ int ret = ERROR;
+ int option;
+
+ /* Get the losetup options: Two forms are supported:
+ *
+ * losetup -d <loop-device>
+ * losetup [-o <offset>] [-r] <loop-device> <filename>
+ *
+ * NOTE that the -o and -r options are accepted with the -d option, but
+ * will be ignored.
+ */
+
+ while ((option = getopt(argc, argv, "d:o:r")) != ERROR)
+ {
+ switch (option)
+ {
+ case 'd':
+ loopdev = nsh_getfullpath(vtbl, optarg);
+ teardown = true;
+ break;
+
+ case 'o':
+ offset = atoi(optarg);
+ break;
+
+ case 'r':
+ readonly = true;
+ break;
+
+ case '?':
+ default:
+ nsh_output(vtbl, g_fmtarginvalid, argv[0]);
+ badarg = true;
+ break;
+ }
+ }
+
+ /* If a bad argument was encountered, then return without processing the command */
+
+ if (badarg)
+ {
+ goto errout_with_paths;
+ }
+
+ /* If this is not a tear down operation, then additional command line
+ * parameters are required.
+ */
+
+ if (!teardown)
+ {
+ /* There must be two arguments on the command line after the options */
+
+ if (optind + 1 < argc)
+ {
+ loopdev = nsh_getfullpath(vtbl, argv[optind]);
+ optind++;
+
+ filepath = nsh_getfullpath(vtbl, argv[optind]);
+ optind++;
+ }
+ else
+ {
+ nsh_output(vtbl, g_fmtargrequired, argv[0]);
+ goto errout_with_paths;
+ }
+ }
+
+ /* There should be nothing else on the command line */
+
+ if (optind < argc)
+ {
+ nsh_output(vtbl, g_fmttoomanyargs, argv[0]);
+ goto errout_with_paths;
+ }
+
+ /* Perform the teardown operation */
+
+ if (teardown)
+ {
+ /* Tear down the loop device. */
+
+ ret = loteardown(loopdev);
+ if (ret < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "loteardown", NSH_ERRNO_OF(-ret));
+ goto errout_with_paths;
+ }
+ }
+ else
+ {
+ /* Set up the loop device */
+
+ ret = losetup(loopdev, filepath, 512, offset, readonly);
+ if (ret < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "losetup", NSH_ERRNO_OF(-ret));
+ goto errout_with_paths;
+ }
+ }
+
+ /* Free memory */
+
+errout_with_paths:
+ if (loopdev)
+ {
+ free(loopdev);
+ }
+
+ if (filepath)
+ {
+ free(filepath);
+ }
+ return ret;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: cmd_ls
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_LS
+int cmd_ls(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ const char *relpath;
+ unsigned int lsflags = 0;
+ char *fullpath;
+ bool badarg = false;
+ int ret;
+
+ /* Get the ls options */
+
+ int option;
+ while ((option = getopt(argc, argv, "lRs")) != ERROR)
+ {
+ switch (option)
+ {
+ case 'l':
+ lsflags |= (LSFLAGS_SIZE|LSFLAGS_LONG);
+ break;
+
+ case 'R':
+ lsflags |= LSFLAGS_RECURSIVE;
+ break;
+
+ case 's':
+ lsflags |= LSFLAGS_SIZE;
+ break;
+
+ case '?':
+ default:
+ nsh_output(vtbl, g_fmtarginvalid, argv[0]);
+ badarg = true;
+ break;
+ }
+ }
+
+ /* If a bad argument was encountered, then return without processing the command */
+
+ if (badarg)
+ {
+ return ERROR;
+ }
+
+ /* There may be one argument after the options */
+
+ if (optind + 1 < argc)
+ {
+ nsh_output(vtbl, g_fmttoomanyargs, argv[0]);
+ return ERROR;
+ }
+ else if (optind >= argc)
+ {
+#ifndef CONFIG_DISABLE_ENVIRON
+ relpath = nsh_getcwd();
+#else
+ nsh_output(vtbl, g_fmtargrequired, argv[0]);
+ return ERROR;
+#endif
+ }
+ else
+ {
+ relpath = argv[optind];
+ }
+
+ /* Get the fullpath to the directory */
+
+ fullpath = nsh_getfullpath(vtbl, relpath);
+ if (!fullpath)
+ {
+ return ERROR;
+ }
+
+ /* List the directory contents */
+
+ nsh_output(vtbl, "%s:\n", fullpath);
+ ret = foreach_direntry(vtbl, "ls", fullpath, ls_handler, (void*)lsflags);
+ if (ret == OK && (lsflags & LSFLAGS_RECURSIVE) != 0)
+ {
+ /* Then recurse to list each directory within the directory */
+
+ ret = foreach_direntry(vtbl, "ls", fullpath, ls_recursive, (void*)lsflags);
+ }
+ nsh_freefullpath(fullpath);
+ return ret;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: cmd_mkdir
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE)
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_MKDIR
+int cmd_mkdir(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ char *fullpath = nsh_getfullpath(vtbl, argv[1]);
+ int ret = ERROR;
+
+ if (fullpath)
+ {
+ ret = mkdir(fullpath, 0777);
+ if (ret < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mkdir", NSH_ERRNO);
+ }
+ nsh_freefullpath(fullpath);
+ }
+ return ret;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: cmd_mkfatfs
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_FAT)
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_MKFATFS
+int cmd_mkfatfs(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ struct fat_format_s fmt = FAT_FORMAT_INITIALIZER;
+ char *fullpath = nsh_getfullpath(vtbl, argv[1]);
+ int ret = ERROR;
+
+ if (fullpath)
+ {
+ ret = mkfatfs(fullpath, &fmt);
+ if (ret < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mkfatfs", NSH_ERRNO);
+ }
+ nsh_freefullpath(fullpath);
+ }
+ return ret;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: cmd_mkfifo
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_MKFIFO
+int cmd_mkfifo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ char *fullpath = nsh_getfullpath(vtbl, argv[1]);
+ int ret = ERROR;
+
+ if (fullpath)
+ {
+ ret = mkfifo(fullpath, 0777);
+ if (ret < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mkfifo", NSH_ERRNO);
+ }
+ nsh_freefullpath(fullpath);
+ }
+ return ret;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: cmd_mkrd
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE)
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_MKRD
+int cmd_mkrd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ const char *fmt;
+ uint8_t *buffer;
+ uint32_t nsectors;
+ bool badarg = false;
+ int sectsize = 512;
+ int minor = 0;
+ int ret;
+
+ /* Get the mount options */
+
+ int option;
+ while ((option = getopt(argc, argv, ":m:s:")) != ERROR)
+ {
+ switch (option)
+ {
+ case 'm':
+ minor = atoi(optarg);
+ if (minor < 0 || minor > 255)
+ {
+ nsh_output(vtbl, g_fmtargrange, argv[0]);
+ badarg = true;
+ }
+ break;
+
+ case 's':
+ sectsize = atoi(optarg);
+ if (minor < 0 || minor > 16384)
+ {
+ nsh_output(vtbl, g_fmtargrange, argv[0]);
+ badarg = true;
+ }
+ break;
+
+ case ':':
+ nsh_output(vtbl, g_fmtargrequired, argv[0]);
+ badarg = true;
+ break;
+
+ case '?':
+ default:
+ nsh_output(vtbl, g_fmtarginvalid, argv[0]);
+ badarg = true;
+ break;
+ }
+ }
+
+ /* If a bad argument was encountered, then return without processing the command */
+
+ if (badarg)
+ {
+ return ERROR;
+ }
+
+ /* There should be exactly on parameter left on the command-line */
+
+ if (optind == argc-1)
+ {
+ nsectors = (uint32_t)atoi(argv[optind]);
+ }
+ else if (optind >= argc)
+ {
+ fmt = g_fmttoomanyargs;
+ goto errout_with_fmt;
+ }
+ else
+ {
+ fmt = g_fmtargrequired;
+ goto errout_with_fmt;
+ }
+
+ /* Allocate the memory backing up the ramdisk */
+
+ buffer = (uint8_t*)malloc(sectsize * nsectors);
+ if (!buffer)
+ {
+ fmt = g_fmtcmdoutofmemory;
+ goto errout_with_fmt;
+ }
+
+#ifdef CONFIG_DEBUG_VERBOSE
+ memset(buffer, 0, sectsize * nsectors);
+#endif
+ dbg("RAMDISK at %p\n", buffer);
+
+ /* Then register the ramdisk */
+
+ ret = ramdisk_register(minor, buffer, nsectors, sectsize, true);
+ if (ret < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "ramdisk_register", NSH_ERRNO_OF(-ret));
+ free(buffer);
+ return ERROR;
+ }
+ return ret;
+
+errout_with_fmt:
+ nsh_output(vtbl, fmt, argv[0]);
+ return ERROR;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: cmd_mount
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_READABLE)
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_MOUNT
+int cmd_mount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ char *source;
+ char *target;
+ char *filesystem = 0;
+ bool badarg = false;
+ int ret;
+
+ /* Get the mount options */
+
+ int option;
+ while ((option = getopt(argc, argv, ":t:")) != ERROR)
+ {
+ switch (option)
+ {
+ case 't':
+ filesystem = optarg;
+ break;
+
+ case ':':
+ nsh_output(vtbl, g_fmtargrequired, argv[0]);
+ badarg = true;
+ break;
+
+ case '?':
+ default:
+ nsh_output(vtbl, g_fmtarginvalid, argv[0]);
+ badarg = true;
+ break;
+ }
+ }
+
+ /* If a bad argument was encountered, then return without processing the command */
+
+ if (badarg)
+ {
+ return ERROR;
+ }
+
+ /* There are two required arguments after the options */
+
+ if (optind + 2 < argc)
+ {
+ nsh_output(vtbl, g_fmttoomanyargs, argv[0]);
+ return ERROR;
+ }
+ else if (optind + 2 > argc)
+ {
+ nsh_output(vtbl, g_fmtargrequired, argv[0]);
+ return ERROR;
+ }
+
+ /* The source and target pathes might be relative to the current
+ * working directory.
+ */
+
+ source = nsh_getfullpath(vtbl, argv[optind]);
+ if (!source)
+ {
+ return ERROR;
+ }
+
+ target = nsh_getfullpath(vtbl, argv[optind+1]);
+ if (!source)
+ {
+ nsh_freefullpath(source);
+ return ERROR;
+ }
+
+ /* Perform the mount */
+
+ ret = mount(source, target, filesystem, 0, NULL);
+ if (ret < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mount", NSH_ERRNO);
+ }
+
+ nsh_freefullpath(source);
+ nsh_freefullpath(target);
+ return ret;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: cmd_rm
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE)
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_RM
+int cmd_rm(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ char *fullpath = nsh_getfullpath(vtbl, argv[1]);
+ int ret = ERROR;
+
+ if (fullpath)
+ {
+ ret = unlink(fullpath);
+ if (ret < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "unlink", NSH_ERRNO);
+ }
+ nsh_freefullpath(fullpath);
+ }
+ return ret;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: cmd_rmdir
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE)
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_RMDIR
+int cmd_rmdir(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ char *fullpath = nsh_getfullpath(vtbl, argv[1]);
+ int ret = ERROR;
+
+ if (fullpath)
+ {
+ ret = rmdir(fullpath);
+ if (ret < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "rmdir", NSH_ERRNO);
+ }
+ nsh_freefullpath(fullpath);
+ }
+ return ret;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: nsh_script
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 && !defined(CONFIG_EXAMPLES_NSH_DISABLESCRIPT)
+int nsh_script(FAR struct nsh_vtbl_s *vtbl, const char *cmd, const char *path)
+{
+ char *fullpath;
+ FILE *stream;
+ char *buffer;
+ char *pret;
+ int ret = ERROR;
+
+ /* The path to the script may be relative to the current working directory */
+
+ fullpath = nsh_getfullpath(vtbl, path);
+ if (!fullpath)
+ {
+ return ERROR;
+ }
+
+ /* Get a reference to the common input buffer */
+
+ buffer = nsh_linebuffer(vtbl);
+ if (buffer)
+ {
+ /* Open the file containing the script */
+
+ stream = fopen(fullpath, "r");
+ if (!stream)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, cmd, "fopen", NSH_ERRNO);
+ nsh_freefullpath(fullpath);
+ return ERROR;
+ }
+
+ /* Loop, processing each command line in the script file (or
+ * until an error occurs)
+ */
+
+ do
+ {
+ /* Get the next line of input from the file*/
+
+ fflush(stdout);
+ pret = fgets(buffer, CONFIG_EXAMPLES_NSH_LINELEN, stream);
+ if (pret)
+ {
+ /* Parse process the command. NOTE: this is recursive...
+ * we got to cmd_sh via a call to nsh_parse. So some
+ * considerable amount of stack may be used.
+ */
+
+ ret = nsh_parse(vtbl, buffer);
+ }
+ }
+ while (pret && ret == OK);
+ fclose(stream);
+ }
+
+ nsh_freefullpath(fullpath);
+ return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: cmd_sh
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 && !defined(CONFIG_EXAMPLES_NSH_DISABLESCRIPT)
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_SH
+int cmd_sh(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ return nsh_script(vtbl, argv[0], argv[1]);
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: cmd_umount
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_READABLE)
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_UMOUNT
+int cmd_umount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ char *fullpath = nsh_getfullpath(vtbl, argv[1]);
+ int ret = ERROR;
+
+ if (fullpath)
+ {
+ /* Perform the umount */
+
+ ret = umount(fullpath);
+ if (ret < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "umount", NSH_ERRNO);
+ }
+ nsh_freefullpath(fullpath);
+ }
+ return ret;
+}
+#endif
+#endif
diff --git a/apps/nshlib/nsh_main.c b/apps/nshlib/nsh_main.c
new file mode 100644
index 000000000..3437707a3
--- /dev/null
+++ b/apps/nshlib/nsh_main.c
@@ -0,0 +1,1299 @@
+/****************************************************************************
+ * apps/nshlib/nsh_main.c
+ *
+ * Copyright (C) 2007-2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/stat.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sched.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <debug.h>
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+# include <pthread.h>
+#endif
+
+#ifdef CONFIG_EXAMPLES_NSH_BUILTIN_APPS
+# include <apps/apps.h>
+#endif
+#include <apps/nsh.h>
+
+#include "nsh.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/* Argument list size
+ *
+ * argv[0]: The command name.
+ * argv[1]: The beginning of argument (up to NSH_MAX_ARGUMENTS)
+ * argv[argc-3]: Possibly '>' or '>>'
+ * argv[argc-2]: Possibly <file>
+ * argv[argc-1]: Possibly '&' (if pthreads are enabled)
+ * argv[argc]: NULL terminating pointer
+ *
+ * Maximum size is NSH_MAX_ARGUMENTS+5
+ */
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+# define MAX_ARGV_ENTRIES (NSH_MAX_ARGUMENTS+5)
+#else
+# define MAX_ARGV_ENTRIES (NSH_MAX_ARGUMENTS+4)
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct cmdmap_s
+{
+ const char *cmd; /* Name of the command */
+ cmd_t handler; /* Function that handles the command */
+ uint8_t minargs; /* Minimum number of arguments (including command) */
+ uint8_t maxargs; /* Maximum number of arguments (including command) */
+ const char *usage; /* Usage instructions for 'help' command */
+};
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+struct cmdarg_s
+{
+ FAR struct nsh_vtbl_s *vtbl; /* For front-end interaction */
+ int fd; /* FD for output redirection */
+ int argc; /* Number of arguments in argv */
+ FAR char *argv[MAX_ARGV_ENTRIES]; /* Argument list */
+};
+#endif
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_HELP
+ static int cmd_help(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_EXIT
+ static int cmd_exit(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
+static int cmd_unrecognized(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const char g_delim[] = " \t\n";
+static const char g_redirect1[] = ">";
+static const char g_redirect2[] = ">>";
+static const char g_exitstatus[] = "$?";
+static const char g_success[] = "0";
+static const char g_failure[] = "1";
+
+static const struct cmdmap_s g_cmdmap[] =
+{
+#if !defined(CONFIG_EXAMPLES_NSH_DISABLESCRIPT) && !defined(CONFIG_EXAMPLES_NSH_DISABLE_TEST)
+ { "[", cmd_lbracket, 4, NSH_MAX_ARGUMENTS, "<expression> ]" },
+#endif
+
+#if CONFIG_NFILE_DESCRIPTORS > 0
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_CAT
+ { "cat", cmd_cat, 2, NSH_MAX_ARGUMENTS, "<path> [<path> [<path> ...]]" },
+# endif
+#ifndef CONFIG_DISABLE_ENVIRON
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_CD
+ { "cd", cmd_cd, 1, 2, "[<dir-path>|-|~|..]" },
+# endif
+#endif
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_CP
+ { "cp", cmd_cp, 3, 3, "<source-path> <dest-path>" },
+# endif
+#endif
+
+#if CONFIG_NFILE_DESCRIPTORS > 0
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_LS
+ { "dd", cmd_dd, 3, 6, "if=<infile> of=<outfile> [bs=<sectsize>] [count=<sectors>] [skip=<sectors>]" },
+# endif
+#endif
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_ECHO
+# ifndef CONFIG_DISABLE_ENVIRON
+ { "echo", cmd_echo, 0, NSH_MAX_ARGUMENTS, "[<string|$name> [<string|$name>...]]" },
+# else
+ { "echo", cmd_echo, 0, NSH_MAX_ARGUMENTS, "[<string> [<string>...]]" },
+# endif
+#endif
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_EXEC
+ { "exec", cmd_exec, 2, 3, "<hex-address>" },
+#endif
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_EXIT
+ { "exit", cmd_exit, 1, 1, NULL },
+#endif
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_FREE
+ { "free", cmd_free, 1, 1, NULL },
+#endif
+
+#if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_GET
+ { "get", cmd_get, 4, 7, "[-b|-n] [-f <local-path>] -h <ip-address> <remote-path>" },
+# endif
+#endif
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_HELP
+ { "help", cmd_help, 1, 1, NULL },
+#endif
+
+#ifdef CONFIG_NET
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_IFCONFIG
+ { "ifconfig", cmd_ifconfig, 1, 1, NULL },
+# endif
+#endif
+
+#ifndef CONFIG_DISABLE_SIGNALS
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_SLEEP
+ { "kill", cmd_kill, 3, 3, "-<signal> <pid>" },
+# endif
+#endif
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT)
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_LOSETUP
+ { "losetup", cmd_losetup, 3, 6, "[-d <dev-path>] | [[-o <offset>] [-r] <dev-path> <file-path>]" },
+# endif
+#endif
+
+#if CONFIG_NFILE_DESCRIPTORS > 0
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_LS
+ { "ls", cmd_ls, 1, 5, "[-lRs] <dir-path>" },
+# endif
+#endif
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_MB
+ { "mb", cmd_mb, 2, 3, "<hex-address>[=<hex-value>][ <hex-byte-count>]" },
+#endif
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE)
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_MKDIR
+ { "mkdir", cmd_mkdir, 2, 2, "<path>" },
+# endif
+#endif
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_FAT)
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_MKFATFS
+ { "mkfatfs", cmd_mkfatfs, 2, 2, "<path>" },
+# endif
+#endif
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_MKFIFO
+ { "mkfifo", cmd_mkfifo, 2, 2, "<path>" },
+# endif
+#endif
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE)
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_MKRD
+ { "mkrd", cmd_mkrd, 2, 6, "[-m <minor>] [-s <sector-size>] <nsectors>" },
+# endif
+#endif
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_MH
+ { "mh", cmd_mh, 2, 3, "<hex-address>[=<hex-value>][ <hex-byte-count>]" },
+#endif
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_READABLE)
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_MOUNT
+ { "mount", cmd_mount, 4, 5, "-t <fstype> <block-device> <dir-path>" },
+# endif
+#endif
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_MW
+ { "mw", cmd_mw, 2, 3, "<hex-address>[=<hex-value>][ <hex-byte-count>]" },
+#endif
+
+#if defined(CONFIG_NET) && defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \
+ !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_DISABLE_SIGNALS)
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_PING
+ { "ping", cmd_ping, 2, 6, "[-c <count>] [-i <interval>] <ip-address>" },
+# endif
+#endif
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_PS
+ { "ps", cmd_ps, 1, 1, NULL },
+#endif
+
+#if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_PUT
+ { "put", cmd_put, 4, 7, "[-b|-n] [-f <remote-path>] -h <ip-address> <local-path>" },
+# endif
+#endif
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON)
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_PWD
+ { "pwd", cmd_pwd, 1, 1, NULL },
+# endif
+#endif
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE)
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_RM
+ { "rm", cmd_rm, 2, 2, "<file-path>" },
+# endif
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_RMDIR
+ { "rmdir", cmd_rmdir, 2, 2, "<dir-path>" },
+# endif
+#endif
+
+#ifndef CONFIG_DISABLE_ENVIRON
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_SET
+ { "set", cmd_set, 3, 3, "<name> <value>" },
+# endif
+#endif
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 && !defined(CONFIG_EXAMPLES_NSH_DISABLESCRIPT)
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_SH
+ { "sh", cmd_sh, 2, 2, "<script-path>" },
+# endif
+#endif
+
+#ifndef CONFIG_DISABLE_SIGNALS
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_SLEEP
+ { "sleep", cmd_sleep, 2, 2, "<sec>" },
+# endif
+#endif
+
+#if !defined(CONFIG_EXAMPLES_NSH_DISABLESCRIPT) && !defined(CONFIG_EXAMPLES_NSH_DISABLE_TEST)
+ { "test", cmd_test, 3, NSH_MAX_ARGUMENTS, "<expression>" },
+#endif
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_READABLE)
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_UMOUNT
+ { "umount", cmd_umount, 2, 2, "<dir-path>" },
+# endif
+#endif
+
+#ifndef CONFIG_DISABLE_ENVIRON
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_UNSET
+ { "unset", cmd_unset, 2, 2, "<name>" },
+# endif
+#endif
+
+#ifndef CONFIG_DISABLE_SIGNALS
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_USLEEP
+ { "usleep", cmd_usleep, 2, 2, "<usec>" },
+# endif
+#endif
+
+#if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_GET
+ { "wget", cmd_wget, 2, 4, "[-o <local-path>] <url>" },
+# endif
+#endif
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_XD
+ { "xd", cmd_xd, 3, 3, "<hex-address> <byte-count>" },
+#endif
+ { NULL, NULL, 1, 1, NULL }
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+const char g_nshgreeting[] = "\nNuttShell (NSH)\n";
+const char g_nshprompt[] = "nsh> ";
+const char g_nshsyntax[] = "nsh: %s: syntax error\n";
+const char g_fmtargrequired[] = "nsh: %s: missing required argument(s)\n";
+const char g_fmtarginvalid[] = "nsh: %s: argument invalid\n";
+const char g_fmtargrange[] = "nsh: %s: value out of range\n";
+const char g_fmtcmdnotfound[] = "nsh: %s: command not found\n";
+const char g_fmtnosuch[] = "nsh: %s: no such %s: %s\n";
+const char g_fmttoomanyargs[] = "nsh: %s: too many arguments\n";
+const char g_fmtdeepnesting[] = "nsh: %s: nesting too deep\n";
+const char g_fmtcontext[] = "nsh: %s: not valid in this context\n";
+#ifdef CONFIG_EXAMPLES_NSH_STRERROR
+const char g_fmtcmdfailed[] = "nsh: %s: %s failed: %s\n";
+#else
+const char g_fmtcmdfailed[] = "nsh: %s: %s failed: %d\n";
+#endif
+const char g_fmtcmdoutofmemory[] = "nsh: %s: out of memory\n";
+const char g_fmtinternalerror[] = "nsh: %s: Internal error\n";
+#ifndef CONFIG_DISABLE_SIGNALS
+const char g_fmtsignalrecvd[] = "nsh: %s: Interrupted by signal\n";
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: cmd_help
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_HELP
+static int cmd_help(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ const struct cmdmap_s *ptr;
+
+ nsh_output(vtbl, "NSH command forms:\n");
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+ nsh_output(vtbl, " [nice [-d <niceness>>]] <cmd> [> <file>|>> <file>] [&]\n");
+#else
+ nsh_output(vtbl, " <cmd> [> <file>|>> <file>]\n");
+#endif
+#ifndef CONFIG_EXAMPLES_NSH_DISABLESCRIPT
+ nsh_output(vtbl, "OR\n");
+ nsh_output(vtbl, " if <cmd>\n");
+ nsh_output(vtbl, " then\n");
+ nsh_output(vtbl, " [sequence of <cmd>]\n");
+ nsh_output(vtbl, " else\n");
+ nsh_output(vtbl, " [sequence of <cmd>]\n");
+ nsh_output(vtbl, " fi\n");
+#endif
+ nsh_output(vtbl, "Where <cmd> is one of:\n");
+ for (ptr = g_cmdmap; ptr->cmd; ptr++)
+ {
+ if (ptr->usage)
+ {
+ nsh_output(vtbl, " %s %s\n", ptr->cmd, ptr->usage);
+ }
+ else
+ {
+ nsh_output(vtbl, " %s\n", ptr->cmd);
+ }
+ }
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: cmd_unrecognized
+ ****************************************************************************/
+
+static int cmd_unrecognized(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ nsh_output(vtbl, g_fmtcmdnotfound, argv[0]);
+ return ERROR;
+}
+
+/****************************************************************************
+ * Name: cmd_exit
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_EXIT
+static int cmd_exit(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ nsh_exit(vtbl);
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: nsh_execute
+ ****************************************************************************/
+
+static int nsh_execute(FAR struct nsh_vtbl_s *vtbl, int argc, char *argv[])
+{
+ const struct cmdmap_s *cmdmap;
+ const char *cmd;
+ cmd_t handler = cmd_unrecognized;
+ int ret;
+
+ /* The form of argv is:
+ *
+ * argv[0]: The command name. This is argv[0] when the arguments
+ * are, finally, received by the command vtblr
+ * argv[1]: The beginning of argument (up to NSH_MAX_ARGUMENTS)
+ * argv[argc]: NULL terminating pointer
+ */
+
+ cmd = argv[0];
+
+ /* See if the command is one that we understand */
+
+ for (cmdmap = g_cmdmap; cmdmap->cmd; cmdmap++)
+ {
+ if (strcmp(cmdmap->cmd, cmd) == 0)
+ {
+ /* Check if a valid number of arguments was provided. We
+ * do this simple, imperfect checking here so that it does
+ * not have to be performed in each command.
+ */
+
+ if (argc < cmdmap->minargs)
+ {
+ /* Fewer than the minimum number were provided */
+
+ nsh_output(vtbl, g_fmtargrequired, cmd);
+ return ERROR;
+ }
+ else if (argc > cmdmap->maxargs)
+ {
+ /* More than the maximum number were provided */
+
+ nsh_output(vtbl, g_fmttoomanyargs, cmd);
+ return ERROR;
+ }
+ else
+ {
+ /* A valid number of arguments were provided (this does
+ * not mean they are right).
+ */
+
+ handler = cmdmap->handler;
+ break;
+ }
+ }
+ }
+
+ /* If the command was not found, then try to execute the command from
+ * a list of pre-built applications.
+ */
+
+#ifdef CONFIG_EXAMPLES_NSH_BUILTIN_APPS
+ if (handler == cmd_unrecognized && nsh_execapp(vtbl, cmd, argv) == OK)
+ {
+ /* The pre-built application was successfully started -- return OK.
+ * If not, then fall through to execute the cmd_nrecognized handler.
+ */
+
+ return OK;
+ }
+#endif
+
+ ret = handler(vtbl, argc, argv);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: nsh_releaseargs
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+static void nsh_releaseargs(struct cmdarg_s *arg)
+{
+ FAR struct nsh_vtbl_s *vtbl = arg->vtbl;
+ int i;
+
+ /* If the output was redirected, then file descriptor should
+ * be closed. The created task has its one, independent copy of
+ * the file descriptor
+ */
+
+ if (vtbl->np.np_redirect)
+ {
+ (void)close(arg->fd);
+ }
+
+ /* Released the cloned vtbl instance */
+
+ nsh_release(vtbl);
+
+ /* Release the cloned args */
+
+ for (i = 0; i < arg->argc; i++)
+ {
+ free(arg->argv[i]);
+ }
+ free(arg);
+}
+#endif
+
+/****************************************************************************
+ * Name: nsh_child
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+static pthread_addr_t nsh_child(pthread_addr_t arg)
+{
+ struct cmdarg_s *carg = (struct cmdarg_s *)arg;
+ int ret;
+
+ dbg("BG %s\n", carg->argv[0]);
+
+ /* Execute the specified command on the child thread */
+
+ ret = nsh_execute(carg->vtbl, carg->argc, carg->argv);
+
+ /* Released the cloned arguments */
+
+ dbg("BG %s complete\n", carg->argv[0]);
+ nsh_releaseargs(carg);
+ return (void*)ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: nsh_cloneargs
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+static inline struct cmdarg_s *nsh_cloneargs(FAR struct nsh_vtbl_s *vtbl,
+ int fd, int argc, char *argv[])
+{
+ struct cmdarg_s *ret = (struct cmdarg_s *)zalloc(sizeof(struct cmdarg_s));
+ int i;
+
+ if (ret)
+ {
+ ret->vtbl = vtbl;
+ ret->fd = fd;
+ ret->argc = argc;
+
+ for (i = 0; i < argc; i++)
+ {
+ ret->argv[i] = strdup(argv[i]);
+ }
+ }
+ return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: nsh_argument
+ ****************************************************************************/
+
+char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, char **saveptr)
+{
+ char *pbegin = *saveptr;
+ char *pend = NULL;
+ const char *term;
+#ifndef CONFIG_DISABLE_ENVIRON
+ bool quoted = false;
+#endif
+
+ /* Find the beginning of the next token */
+
+ for (;
+ *pbegin && strchr(g_delim, *pbegin) != NULL;
+ pbegin++);
+
+ /* If we are at the end of the string with nothing
+ * but delimiters found, then return NULL.
+ */
+
+ if (!*pbegin)
+ {
+ return NULL;
+ }
+
+ /* Does the token begin with '>' -- redirection of output? */
+
+ if (*pbegin == '>')
+ {
+ /* Yes.. does it begin with ">>"? */
+
+ if (*(pbegin + 1) == '>')
+ {
+ *saveptr = pbegin + 2;
+ pbegin = (char*)g_redirect2;
+ }
+ else
+ {
+ *saveptr = pbegin + 1;
+ pbegin = (char*)g_redirect1;
+ }
+ }
+
+ /* Does the token begin with '#' -- comment */
+
+ else if (*pbegin == '#')
+ {
+ /* Return NULL meaning that we are at the end of the line */
+
+ *saveptr = pbegin;
+ pbegin = NULL;
+ }
+ else
+ {
+ /* Otherwise, we are going to have to parse to find the end of
+ * the token. Does the token begin with '"'?
+ */
+
+ if (*pbegin == '"')
+ {
+ /* Yes.. then only another '"' can terminate the string */
+
+ pbegin++;
+ term = "\"";
+#ifndef CONFIG_DISABLE_ENVIRON
+ quoted = true;
+#endif
+ }
+ else
+ {
+ /* No, then any of the usual terminators will terminate the argument */
+
+ term = g_delim;
+ }
+
+ /* Find the end of the string */
+
+ for (pend = pbegin + 1;
+ *pend && strchr(term, *pend) == NULL;
+ pend++);
+
+ /* pend either points to the end of the string or to
+ * the first delimiter after the string.
+ */
+
+ if (*pend)
+ {
+ /* Turn the delimiter into a null terminator */
+
+ *pend++ = '\0';
+ }
+
+ /* Save the pointer where we left off */
+
+ *saveptr = pend;
+
+#ifndef CONFIG_DISABLE_ENVIRON
+ /* Check for references to environment variables */
+
+ if (pbegin[0] == '$' && !quoted)
+ {
+ /* Check for built-in variables */
+
+ if (strcmp(pbegin, g_exitstatus) == 0)
+ {
+ if (vtbl->np.np_fail)
+ {
+ return (char*)g_failure;
+ }
+ else
+ {
+ return (char*)g_success;
+ }
+ }
+
+ /* Not a built-in? Return the value of the environment variable with this name */
+
+ else
+ {
+ char *value = getenv(pbegin+1);
+ if (value)
+ {
+ return value;
+ }
+ else
+ {
+ return (char*)"";
+ }
+ }
+ }
+#endif
+ }
+
+ /* Return the beginning of the token. */
+
+ return pbegin;
+}
+
+/****************************************************************************
+ * Name: nsh_cmdenabled
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLESCRIPT
+static inline bool nsh_cmdenabled(FAR struct nsh_vtbl_s *vtbl)
+{
+ struct nsh_parser_s *np = &vtbl->np;
+ bool ret = !np->np_st[np->np_ndx].ns_disabled;
+ if (ret)
+ {
+ switch (np->np_st[np->np_ndx].ns_state)
+ {
+ case NSH_PARSER_NORMAL :
+ case NSH_PARSER_IF:
+ default:
+ break;
+
+ case NSH_PARSER_THEN:
+ ret = !np->np_st[np->np_ndx].ns_ifcond;
+ break;
+
+ case NSH_PARSER_ELSE:
+ ret = np->np_st[np->np_ndx].ns_ifcond;
+ break;
+ }
+ }
+ return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: nsh_ifthenelse
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLESCRIPT
+static inline int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, FAR char **saveptr)
+{
+ struct nsh_parser_s *np = &vtbl->np;
+ FAR char *cmd = *ppcmd;
+ bool disabled;
+
+ if (cmd)
+ {
+ /* Check if the command is preceeded by "if" */
+
+ if (strcmp(cmd, "if") == 0)
+ {
+ /* Get the cmd following the if */
+
+ *ppcmd = nsh_argument(vtbl, saveptr);
+ if (!*ppcmd)
+ {
+ nsh_output(vtbl, g_fmtarginvalid, "if");
+ goto errout;
+ }
+
+ /* Verify that "if" is valid in this context */
+
+ if (np->np_st[np->np_ndx].ns_state != NSH_PARSER_NORMAL &&
+ np->np_st[np->np_ndx].ns_state != NSH_PARSER_THEN &&
+ np->np_st[np->np_ndx].ns_state != NSH_PARSER_ELSE)
+ {
+ nsh_output(vtbl, g_fmtcontext, "if");
+ goto errout;
+ }
+
+ /* Check if we have exceeded the maximum depth of nesting */
+
+ if (np->np_ndx >= CONFIG_EXAMPLES_NSH_NESTDEPTH-1)
+ {
+ nsh_output(vtbl, g_fmtdeepnesting, "if");
+ goto errout;
+ }
+
+ /* "Push" the old state and set the new state */
+
+ disabled = !nsh_cmdenabled(vtbl);
+ np->np_ndx++;
+ np->np_st[np->np_ndx].ns_state = NSH_PARSER_IF;
+ np->np_st[np->np_ndx].ns_disabled = disabled;
+ np->np_st[np->np_ndx].ns_ifcond = false;
+ }
+ else if (strcmp(cmd, "then") == 0)
+ {
+ /* Get the cmd following the then -- there shouldn't be one */
+
+ *ppcmd = nsh_argument(vtbl, saveptr);
+ if (*ppcmd)
+ {
+ nsh_output(vtbl, g_fmtarginvalid, "then");
+ goto errout;
+ }
+
+ /* Verify that "then" is valid in this context */
+
+ if (np->np_st[np->np_ndx].ns_state != NSH_PARSER_IF)
+ {
+ nsh_output(vtbl, g_fmtcontext, "then");
+ goto errout;
+ }
+ np->np_st[np->np_ndx].ns_state = NSH_PARSER_THEN;
+ }
+ else if (strcmp(cmd, "else") == 0)
+ {
+ /* Get the cmd following the else -- there shouldn't be one */
+
+ *ppcmd = nsh_argument(vtbl, saveptr);
+ if (*ppcmd)
+ {
+ nsh_output(vtbl, g_fmtarginvalid, "else");
+ goto errout;
+ }
+
+ /* Verify that "then" is valid in this context */
+
+ if (np->np_st[np->np_ndx].ns_state != NSH_PARSER_THEN)
+ {
+ nsh_output(vtbl, g_fmtcontext, "else");
+ goto errout;
+ }
+ np->np_st[np->np_ndx].ns_state = NSH_PARSER_ELSE;
+ }
+ else if (strcmp(cmd, "fi") == 0)
+ {
+ /* Get the cmd following the fi -- there should be one */
+
+ *ppcmd = nsh_argument(vtbl, saveptr);
+ if (*ppcmd)
+ {
+ nsh_output(vtbl, g_fmtarginvalid, "fi");
+ goto errout;
+ }
+
+ /* Verify that "fi" is valid in this context */
+
+ if (np->np_st[np->np_ndx].ns_state != NSH_PARSER_THEN &&
+ np->np_st[np->np_ndx].ns_state != NSH_PARSER_ELSE)
+ {
+ nsh_output(vtbl, g_fmtcontext, "fi");
+ goto errout;
+ }
+
+ if (np->np_ndx < 1) /* Shouldn't happen */
+ {
+ nsh_output(vtbl, g_fmtinternalerror, "if");
+ goto errout;
+ }
+
+ /* "Pop" the previous state */
+
+ np->np_ndx--;
+ }
+ else if (np->np_st[np->np_ndx].ns_state == NSH_PARSER_IF)
+ {
+ nsh_output(vtbl, g_fmtcontext, cmd);
+ goto errout;
+ }
+ }
+ return OK;
+
+errout:
+ np->np_ndx = 0;
+ np->np_st[0].ns_state = NSH_PARSER_NORMAL;
+ np->np_st[0].ns_disabled = false;
+ np->np_st[0].ns_ifcond = false;
+ return ERROR;
+}
+#endif
+
+/****************************************************************************
+ * Name: nsh_saveresult
+ ****************************************************************************/
+
+static inline int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, bool result)
+{
+ struct nsh_parser_s *np = &vtbl->np;
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLESCRIPT
+ if (np->np_st[np->np_ndx].ns_state == NSH_PARSER_IF)
+ {
+ np->np_fail = false;
+ np->np_st[np->np_ndx].ns_ifcond = result;
+ return OK;
+ }
+ else
+#endif
+ {
+ np->np_fail = result;
+ return result ? ERROR : OK;
+ }
+}
+
+/****************************************************************************
+ * Name: nsh_nice
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+static inline int nsh_nice(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, FAR char **saveptr)
+{
+ FAR char *cmd = *ppcmd;
+
+ vtbl->np.np_nice = 0;
+ if (cmd)
+ {
+ /* Check if the command is preceded by "nice" */
+
+ if (strcmp(cmd, "nice") == 0)
+ {
+ /* Nicenesses range from -20 (most favorable scheduling) to 19
+ * (least favorable). Default is 10.
+ */
+
+ vtbl->np.np_nice = 10;
+
+ /* Get the cmd (or -d option of nice command) */
+
+ cmd = nsh_argument(vtbl, saveptr);
+ if (cmd && strcmp(cmd, "-d") == 0)
+ {
+ FAR char *val = nsh_argument(vtbl, saveptr);
+ if (val)
+ {
+ char *endptr;
+ vtbl->np.np_nice = (int)strtol(val, &endptr, 0);
+ if (vtbl->np.np_nice > 19 || vtbl->np.np_nice < -20 ||
+ endptr == val || *endptr != '\0')
+ {
+ nsh_output(vtbl, g_fmtarginvalid, "nice");
+ return ERROR;
+ }
+ cmd = nsh_argument(vtbl, saveptr);
+ }
+ }
+
+ /* Return the real command name */
+
+ *ppcmd = cmd;
+ }
+ }
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_initialize
+ ****************************************************************************/
+
+void nsh_initialize(void)
+{
+ /* Mount the /etc filesystem */
+
+ (void)nsh_romfsetc();
+
+ /* Perform architecture-specific initialization (if available) */
+
+ (void)nsh_archinitialize();
+
+ /* Bring up the network */
+
+ (void)nsh_netinit();
+}
+
+/****************************************************************************
+ * Name: nsh_parse
+ ****************************************************************************/
+
+int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline)
+{
+ FAR char *argv[MAX_ARGV_ENTRIES];
+ FAR char *saveptr;
+ FAR char *cmd;
+ FAR char *redirfile = NULL;
+ int fd = -1;
+ int oflags = 0;
+ int argc;
+ int ret;
+
+ /* Initialize parser state */
+
+ memset(argv, 0, MAX_ARGV_ENTRIES*sizeof(FAR char *));
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+ vtbl->np.np_bg = false;
+#endif
+ vtbl->np.np_redirect = false;
+
+ /* Parse out the command at the beginning of the line */
+
+ saveptr = cmdline;
+ cmd = nsh_argument(vtbl, &saveptr);
+
+ /* Handler if-then-else-fi */
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLESCRIPT
+ if (nsh_ifthenelse(vtbl, &cmd, &saveptr) != 0)
+ {
+ goto errout;
+ }
+#endif
+
+ /* Handle nice */
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+ if (nsh_nice(vtbl, &cmd, &saveptr) != 0)
+ {
+ goto errout;
+ }
+#endif
+
+ /* Check if any command was provided -OR- if command processing is
+ * currently disabled.
+ */
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLESCRIPT
+ if (!cmd || !nsh_cmdenabled(vtbl))
+#else
+ if (!cmd)
+#endif
+ {
+ /* An empty line is not an error and an unprocessed command cannot
+ * generate an error, but neither should they change the last
+ * command status.
+ */
+
+ return OK;
+ }
+
+ /* Parse all of the arguments following the command name. The form
+ * of argv is:
+ *
+ * argv[0]: The command name.
+ * argv[1]: The beginning of argument (up to NSH_MAX_ARGUMENTS)
+ * argv[argc-3]: Possibly '>' or '>>'
+ * argv[argc-2]: Possibly <file>
+ * argv[argc-1]: Possibly '&'
+ * argv[argc]: NULL terminating pointer
+ *
+ * Maximum size is NSH_MAX_ARGUMENTS+5
+ */
+
+ argv[0] = cmd;
+ for (argc = 1; argc < MAX_ARGV_ENTRIES-1; argc++)
+ {
+ argv[argc] = nsh_argument(vtbl, &saveptr);
+ if (!argv[argc])
+ {
+ break;
+ }
+ }
+ argv[argc] = NULL;
+
+ /* Check if the command should run in background */
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+ if (argc > 1 && strcmp(argv[argc-1], "&") == 0)
+ {
+ vtbl->np.np_bg = true;
+ argv[argc-1] = NULL;
+ argc--;
+ }
+#endif
+
+
+ /* Check if the output was re-directed using > or >> */
+
+ if (argc > 2)
+ {
+ /* Check for redirection to a new file */
+
+ if (strcmp(argv[argc-2], g_redirect1) == 0)
+ {
+ vtbl->np.np_redirect = true;
+ oflags = O_WRONLY|O_CREAT|O_TRUNC;
+ redirfile = nsh_getfullpath(vtbl, argv[argc-1]);
+ argc -= 2;
+ }
+
+ /* Check for redirection by appending to an existing file */
+
+ else if (strcmp(argv[argc-2], g_redirect2) == 0)
+ {
+ vtbl->np.np_redirect = true;
+ oflags = O_WRONLY|O_CREAT|O_APPEND;
+ redirfile = nsh_getfullpath(vtbl, argv[argc-1]);
+ argc -= 2;
+ }
+ }
+
+ /* Redirected output? */
+
+ if (vtbl->np.np_redirect)
+ {
+ /* Open the redirection file. This file will eventually
+ * be closed by a call to either nsh_release (if the command
+ * is executed in the background) or by nsh_undirect if the
+ * command is executed in the foreground.
+ */
+
+ fd = open(redirfile, oflags, 0666);
+ nsh_freefullpath(redirfile);
+ redirfile = NULL;
+
+ if (fd < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, cmd, "open", NSH_ERRNO);
+ goto errout;
+ }
+ }
+
+ /* Check if the maximum number of arguments was exceeded */
+
+ if (argc > NSH_MAX_ARGUMENTS)
+ {
+ nsh_output(vtbl, g_fmttoomanyargs, cmd);
+ }
+
+ /* Handle the case where the command is executed in background.
+ * However is app is to be started as nuttapp new process will
+ * be created anyway, so skip this step. */
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+ if (vtbl->np.np_bg
+#ifdef CONFIG_EXAMPLES_NSH_BUILTIN_APPS
+ && nuttapp_isavail(argv[0]) < 0
+#endif
+ )
+ {
+ struct sched_param param;
+ struct nsh_vtbl_s *bkgvtbl;
+ struct cmdarg_s *args;
+ pthread_attr_t attr;
+ pthread_t thread;
+
+ /* Get a cloned copy of the vtbl with reference count=1.
+ * after the command has been processed, the nsh_release() call
+ * at the end of nsh_child() will destroy the clone.
+ */
+
+ bkgvtbl = nsh_clone(vtbl);
+ if (!bkgvtbl)
+ {
+ goto errout_with_redirect;
+ }
+
+ /* Create a container for the command arguments */
+
+ args = nsh_cloneargs(bkgvtbl, fd, argc, argv);
+ if (!args)
+ {
+ nsh_release(bkgvtbl);
+ goto errout_with_redirect;
+ }
+
+ /* Handle redirection of output via a file descriptor */
+
+ if (vtbl->np.np_redirect)
+ {
+ (void)nsh_redirect(bkgvtbl, fd, NULL);
+ }
+
+ /* Get the execution priority of this task */
+
+ ret = sched_getparam(0, &param);
+ if (ret != 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, cmd, "sched_getparm", NSH_ERRNO);
+ nsh_releaseargs(args);
+ nsh_release(bkgvtbl);
+ goto errout;
+ }
+
+ /* Determine the priority to execute the command */
+
+ if (vtbl->np.np_nice != 0)
+ {
+ int priority = param.sched_priority - vtbl->np.np_nice;
+ if (vtbl->np.np_nice < 0)
+ {
+ int max_priority = sched_get_priority_max(SCHED_NSH);
+ if (priority > max_priority)
+ {
+ priority = max_priority;
+ }
+ }
+ else
+ {
+ int min_priority = sched_get_priority_min(SCHED_NSH);
+ if (priority < min_priority)
+ {
+ priority = min_priority;
+ }
+ }
+ param.sched_priority = priority;
+ }
+
+ /* Set up the thread attributes */
+
+ (void)pthread_attr_init(&attr);
+ (void)pthread_attr_setschedpolicy(&attr, SCHED_NSH);
+ (void)pthread_attr_setschedparam(&attr, &param);
+
+ /* Execute the command as a separate thread at the appropriate priority */
+
+ ret = pthread_create(&thread, &attr, nsh_child, (pthread_addr_t)args);
+ if (ret != 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, cmd, "pthread_create", NSH_ERRNO_OF(ret));
+ nsh_releaseargs(args);
+ nsh_release(bkgvtbl);
+ goto errout;
+ }
+ nsh_output(vtbl, "%s [%d:%d]\n", cmd, thread, param.sched_priority);
+ }
+ else
+#endif
+ {
+ uint8_t save[SAVE_SIZE];
+
+ /* Handle redirection of output via a file descriptor */
+
+ if (vtbl->np.np_redirect)
+ {
+ nsh_redirect(vtbl, fd, save);
+ }
+
+ /* Then execute the command in "foreground" -- i.e., while the user waits
+ * for the next prompt.
+ */
+
+ ret = nsh_execute(vtbl, argc, argv);
+
+ /* Restore the original output. Undirect will close the redirection
+ * file descriptor.
+ */
+
+ if (vtbl->np.np_redirect)
+ {
+ nsh_undirect(vtbl, save);
+ }
+
+ if (ret < 0)
+ {
+ goto errout;
+ }
+ }
+
+ /* Return success if the command succeeded (or at least, starting of the
+ * command task succeeded).
+ */
+
+ return nsh_saveresult(vtbl, false);
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+errout_with_redirect:
+ if (vtbl->np.np_redirect)
+ {
+ close(fd);
+ }
+#endif
+errout:
+ return nsh_saveresult(vtbl, true);
+}
diff --git a/apps/nshlib/nsh_mmcmds.c b/apps/nshlib/nsh_mmcmds.c
new file mode 100644
index 000000000..f2e218786
--- /dev/null
+++ b/apps/nshlib/nsh_mmcmds.c
@@ -0,0 +1,95 @@
+/****************************************************************************
+ * apps/nshlib/dbg_mmcmds.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdlib.h>
+
+#include "nsh.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: cmd_free
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_FREE
+int cmd_free(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ struct mallinfo mem;
+
+#ifdef CONFIG_CAN_PASS_STRUCTS
+ mem = mallinfo();
+#else
+ (void)mallinfo(&mem);
+#endif
+
+ nsh_output(vtbl, " total used free largest\n");
+ nsh_output(vtbl, "Mem: %11d%11d%11d%11d\n",
+ mem.arena, mem.uordblks, mem.fordblks, mem.mxordblk);
+
+ return OK;
+}
+#endif
diff --git a/apps/nshlib/nsh_netcmds.c b/apps/nshlib/nsh_netcmds.c
new file mode 100644
index 000000000..44fea2e2a
--- /dev/null
+++ b/apps/nshlib/nsh_netcmds.c
@@ -0,0 +1,815 @@
+/****************************************************************************
+ * apps/nshlib/nsh_netcmds.c
+ *
+ * Copyright (C) 2007-2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#ifdef CONFIG_NET
+
+#include <sys/stat.h> /* Needed for open */
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sched.h>
+#include <fcntl.h> /* Needed for open */
+#include <libgen.h> /* Needed for basename */
+#include <errno.h>
+
+#include <nuttx/net.h>
+#include <nuttx/clock.h>
+#include <net/ethernet.h>
+#include <net/uip/uip.h>
+#include <net/uip/uip-arch.h>
+#include <netinet/ether.h>
+
+#ifdef CONFIG_NET_STATISTICS
+# include <net/uip/uip.h>
+#endif
+
+#if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \
+ !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_DISABLE_SIGNALS)
+# include <net/uip/uip-lib.h>
+#endif
+
+#if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0
+# include <net/uip/uip-lib.h>
+# include <net/uip/tftp.h>
+#endif
+
+#if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0
+# ifndef CONFIG_EXAMPLES_NSH_DISABLE_WGET
+# include <net/uip/uip-lib.h>
+# include <net/uip/webclient.h>
+# endif
+#endif
+
+#include "nsh.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+#define DEFAULT_PING_DATALEN 56
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+#if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0
+struct tftpc_args_s
+{
+ bool binary; /* true:binary ("octect") false:text ("netascii") */
+ bool allocated; /* true: destpath is allocated */
+ char *destpath; /* Path at destination */
+ const char *srcpath; /* Path at src */
+ in_addr_t ipaddr; /* Host IP address */
+};
+#endif
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \
+ !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_DISABLE_SIGNALS)
+static uint16_t g_pingid = 0;
+#endif
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ping_newid
+ ****************************************************************************/
+
+#if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \
+ !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_DISABLE_SIGNALS)
+static inline uint16_t ping_newid(void)
+{
+ irqstate_t save = irqsave();
+ uint16_t ret = ++g_pingid;
+ irqrestore(save);
+ return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: uip_statistics
+ ****************************************************************************/
+
+#if defined(CONFIG_NET_STATISTICS) && !defined(CONFIG_EXAMPLES_NSH_DISABLE_IFCONFIG)
+static inline void uip_statistics(FAR struct nsh_vtbl_s *vtbl)
+{
+ nsh_output(vtbl, "uIP IP ");
+#ifdef CONFIG_NET_TCP
+ nsh_output(vtbl, " TCP");
+#endif
+#ifdef CONFIG_NET_UDP
+ nsh_output(vtbl, " UDP");
+#endif
+#ifdef CONFIG_NET_ICMP
+ nsh_output(vtbl, " ICMP");
+#endif
+ nsh_output(vtbl, "\n");
+
+ /* Received packets */
+
+ nsh_output(vtbl, "Received %04x",uip_stat.ip.recv);
+#ifdef CONFIG_NET_TCP
+ nsh_output(vtbl, " %04x",uip_stat.tcp.recv);
+#endif
+#ifdef CONFIG_NET_UDP
+ nsh_output(vtbl, " %04x",uip_stat.udp.recv);
+#endif
+#ifdef CONFIG_NET_ICMP
+ nsh_output(vtbl, " %04x",uip_stat.icmp.recv);
+#endif
+ nsh_output(vtbl, "\n");
+
+ /* Dropped packets */
+
+ nsh_output(vtbl, "Dropped %04x",uip_stat.ip.drop);
+#ifdef CONFIG_NET_TCP
+ nsh_output(vtbl, " %04x",uip_stat.tcp.drop);
+#endif
+#ifdef CONFIG_NET_UDP
+ nsh_output(vtbl, " %04x",uip_stat.udp.drop);
+#endif
+#ifdef CONFIG_NET_ICMP
+ nsh_output(vtbl, " %04x",uip_stat.icmp.drop);
+#endif
+ nsh_output(vtbl, "\n");
+
+ nsh_output(vtbl, " IP VHL: %04x HBL: %04x\n",
+ uip_stat.ip.vhlerr, uip_stat.ip.hblenerr);
+ nsh_output(vtbl, " LBL: %04x Frg: %04x\n",
+ uip_stat.ip.lblenerr, uip_stat.ip.fragerr);
+
+ nsh_output(vtbl, " Checksum %04x",uip_stat.ip.chkerr);
+#ifdef CONFIG_NET_TCP
+ nsh_output(vtbl, " %04x",uip_stat.tcp.chkerr);
+#endif
+#ifdef CONFIG_NET_UDP
+ nsh_output(vtbl, " %04x",uip_stat.udp.chkerr);
+#endif
+#ifdef CONFIG_NET_ICMP
+ nsh_output(vtbl, " ----");
+#endif
+ nsh_output(vtbl, "\n");
+
+#ifdef CONFIG_NET_TCP
+ nsh_output(vtbl, " TCP ACK: %04x SYN: %04x\n",
+ uip_stat.tcp.ackerr, uip_stat.tcp.syndrop);
+ nsh_output(vtbl, " RST: %04x %04x\n",
+ uip_stat.tcp.rst, uip_stat.tcp.synrst);
+#endif
+
+ nsh_output(vtbl, " Type %04x",uip_stat.ip.protoerr);
+#ifdef CONFIG_NET_TCP
+ nsh_output(vtbl, " ----");
+#endif
+#ifdef CONFIG_NET_UDP
+ nsh_output(vtbl, " ----");
+#endif
+#ifdef CONFIG_NET_ICMP
+ nsh_output(vtbl, " %04x",uip_stat.icmp.typeerr);
+#endif
+ nsh_output(vtbl, "\n");
+
+ /* Sent packets */
+
+ nsh_output(vtbl, "Sent ----",uip_stat.ip.sent);
+#ifdef CONFIG_NET_TCP
+ nsh_output(vtbl, " %04x",uip_stat.tcp.sent);
+#endif
+#ifdef CONFIG_NET_UDP
+ nsh_output(vtbl, " %04x",uip_stat.udp.sent);
+#endif
+#ifdef CONFIG_NET_ICMP
+ nsh_output(vtbl, " %04x",uip_stat.icmp.sent);
+#endif
+ nsh_output(vtbl, "\n");
+
+#ifdef CONFIG_NET_TCP
+ nsh_output(vtbl, " Rexmit ---- %04x",uip_stat.tcp.rexmit);
+#ifdef CONFIG_NET_UDP
+ nsh_output(vtbl, " ----");
+#endif
+#ifdef CONFIG_NET_ICMP
+ nsh_output(vtbl, " ----");
+#endif
+ nsh_output(vtbl, "\n");
+#endif
+ nsh_output(vtbl, "\n");
+}
+#else
+# define uip_statistics(vtbl)
+#endif
+
+
+/****************************************************************************
+ * Name: ifconfig_callback
+ ****************************************************************************/
+
+int ifconfig_callback(FAR struct uip_driver_s *dev, void *arg)
+{
+ struct nsh_vtbl_s *vtbl = (struct nsh_vtbl_s*)arg;
+ struct in_addr addr;
+
+ nsh_output(vtbl, "%s\tHWaddr %s\n", dev->d_ifname, ether_ntoa(&dev->d_mac));
+ addr.s_addr = dev->d_ipaddr;
+ nsh_output(vtbl, "\tIPaddr:%s ", inet_ntoa(addr));
+ addr.s_addr = dev->d_draddr;
+ nsh_output(vtbl, "DRaddr:%s ", inet_ntoa(addr));
+ addr.s_addr = dev->d_netmask;
+ nsh_output(vtbl, "Mask:%s\n\n", inet_ntoa(addr));
+ return OK;
+}
+
+/****************************************************************************
+ * Name: tftpc_parseargs
+ ****************************************************************************/
+
+#if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0
+int tftpc_parseargs(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv,
+ struct tftpc_args_s *args)
+{
+ FAR const char *fmt = g_fmtarginvalid;
+ bool badarg = false;
+ int option;
+
+ /* Get the ping options */
+
+ memset(args, 0, sizeof(struct tftpc_args_s));
+ while ((option = getopt(argc, argv, ":bnf:h:")) != ERROR)
+ {
+ switch (option)
+ {
+ case 'b':
+ args->binary = true;
+ break;
+
+ case 'n':
+ args->binary = false;
+ break;
+
+ case 'f':
+ args->destpath = optarg;
+ break;
+
+ case 'h':
+ if (!uiplib_ipaddrconv(optarg, (FAR unsigned char*)&args->ipaddr))
+ {
+ nsh_output(vtbl, g_fmtarginvalid, argv[0]);
+ badarg = true;
+ }
+ break;
+
+ case ':':
+ nsh_output(vtbl, g_fmtargrequired, argv[0]);
+ badarg = true;
+ break;
+
+ case '?':
+ default:
+ nsh_output(vtbl, g_fmtarginvalid, argv[0]);
+ badarg = true;
+ break;
+ }
+ }
+
+ /* If a bad argument was encountered, then return without processing the command */
+
+ if (badarg)
+ {
+ return ERROR;
+ }
+
+ /* There should be exactly on parameter left on the command-line */
+
+ if (optind == argc-1)
+ {
+ args->srcpath = argv[optind];
+ }
+ else if (optind >= argc)
+ {
+ fmt = g_fmttoomanyargs;
+ goto errout;
+ }
+ else
+ {
+ fmt = g_fmtargrequired;
+ goto errout;
+ }
+
+ /* The HOST IP address is also required */
+
+ if (!args->ipaddr)
+ {
+ fmt = g_fmtargrequired;
+ goto errout;
+ }
+
+ /* If the destpath was not provided, then we have do a little work. */
+
+ if (!args->destpath)
+ {
+ char *tmp1;
+ char *tmp2;
+
+ /* Copy the srcpath... baseanme might modify it */
+
+ fmt = g_fmtcmdoutofmemory;
+ tmp1 = strdup(args->srcpath);
+ if (!tmp1)
+ {
+ goto errout;
+ }
+
+ /* Get the basename of the srcpath */
+
+ tmp2 = basename(tmp1);
+ if (!tmp2)
+ {
+ free(tmp1);
+ goto errout;
+ }
+
+ /* Use that basename as the destpath */
+
+ args->destpath = strdup(tmp2);
+ free(tmp1);
+ if (!args->destpath)
+ {
+ goto errout;
+ }
+ args->allocated = true;
+ }
+
+ return OK;
+
+errout:
+ nsh_output(vtbl, fmt, argv[0]);
+ return ERROR;
+}
+#endif
+
+/****************************************************************************
+ * Name: wget_callback
+ ****************************************************************************/
+
+#if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_WGET
+static void wget_callback(FAR char **buffer, int offset, int datend,
+ FAR int *buflen, FAR void *arg)
+{
+ (void)write((int)arg, &((*buffer)[offset]), datend - offset);
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: cmd_get
+ ****************************************************************************/
+
+#if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_GET
+int cmd_get(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ struct tftpc_args_s args;
+ char *fullpath;
+
+ /* Parse the input parameter list */
+
+ if (tftpc_parseargs(vtbl, argc, argv, &args) != OK)
+ {
+ return ERROR;
+ }
+
+ /* Get the full path to the local file */
+
+ fullpath = nsh_getfullpath(vtbl, args.srcpath);
+
+ /* Then perform the TFTP get operation */
+
+ if (tftpget(args.srcpath, fullpath, args.ipaddr, args.binary) != OK)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "tftpget", NSH_ERRNO);
+ }
+
+ /* Release any allocated memory */
+
+ if (args.allocated)
+ {
+ free(args.destpath);
+ }
+ free(fullpath);
+ return OK;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: cmd_ifconfig
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_IFCONFIG
+int cmd_ifconfig(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ netdev_foreach(ifconfig_callback, vtbl);
+ uip_statistics(vtbl);
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: cmd_ping
+ ****************************************************************************/
+
+#if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \
+ !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_DISABLE_SIGNALS)
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_PING
+int cmd_ping(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ FAR const char *fmt = g_fmtarginvalid;
+ const char *staddr;
+ uip_ipaddr_t ipaddr;
+ uint32_t start;
+ uint32_t next;
+ uint32_t dsec = 10;
+ uint16_t id;
+ bool badarg = false;
+ int count = 10;
+ int option;
+ int seqno;
+ int replies = 0;
+ int elapsed;
+ int tmp;
+ int i;
+
+ /* Get the ping options */
+
+ while ((option = getopt(argc, argv, ":c:i:")) != ERROR)
+ {
+ switch (option)
+ {
+ case 'c':
+ count = atoi(optarg);
+ if (count < 1 || count > 10000)
+ {
+ nsh_output(vtbl, g_fmtargrange, argv[0]);
+ badarg = true;
+ }
+ break;
+
+ case 'i':
+ tmp = atoi(optarg);
+ if (tmp < 1 || tmp >= 4294)
+ {
+ nsh_output(vtbl, g_fmtargrange, argv[0]);
+ badarg = true;
+ }
+ else
+ {
+ dsec = 10 * tmp;
+ }
+ break;
+
+ case ':':
+ nsh_output(vtbl, g_fmtargrequired, argv[0]);
+ badarg = true;
+ break;
+
+ case '?':
+ default:
+ nsh_output(vtbl, g_fmtarginvalid, argv[0]);
+ badarg = true;
+ break;
+ }
+ }
+
+ /* If a bad argument was encountered, then return without processing the command */
+
+ if (badarg)
+ {
+ return ERROR;
+ }
+
+ /* There should be exactly on parameter left on the command-line */
+
+ if (optind == argc-1)
+ {
+ staddr = argv[optind];
+ if (!uiplib_ipaddrconv(staddr, (FAR unsigned char*)&ipaddr))
+ {
+ goto errout;
+ }
+ }
+ else if (optind >= argc)
+ {
+ fmt = g_fmttoomanyargs;
+ goto errout;
+ }
+ else
+ {
+ fmt = g_fmtargrequired;
+ goto errout;
+ }
+
+ /* Get the ID to use */
+
+ id = ping_newid();
+
+ /* Loop for the specified count */
+
+ nsh_output(vtbl, "PING %s %d bytes of data\n", staddr, DEFAULT_PING_DATALEN);
+ start = g_system_timer;
+ for (i = 1; i <= count; i++)
+ {
+ /* Send the ECHO request and wait for the response */
+
+ next = g_system_timer;
+ seqno = uip_ping(ipaddr, id, i, DEFAULT_PING_DATALEN, dsec);
+
+ /* Was any response returned? We can tell if a non-negative sequence
+ * number was returned.
+ */
+
+ if (seqno >= 0 && seqno <= i)
+ {
+ /* Get the elpased time from the time that the request was
+ * sent until the response was received. If we got a response
+ * to an earlier request, then fudge the elpased time.
+ */
+
+ elapsed = TICK2MSEC(g_system_timer - next);
+ if (seqno < i)
+ {
+ elapsed += 100*dsec*(i - seqno);
+ }
+
+ /* Report the receipt of the reply */
+
+ nsh_output(vtbl, "%d bytes from %s: icmp_seq=%d time=%d ms\n",
+ DEFAULT_PING_DATALEN, staddr, seqno, elapsed);
+ replies++;
+ }
+
+ /* Wait for the remainder of the interval. If the last seqno<i,
+ * then this is a bad idea... we will probably lose the response
+ * to the current request!
+ */
+
+ elapsed = TICK2DSEC(g_system_timer - next);
+ if (elapsed < dsec)
+ {
+ usleep(100000*dsec);
+ }
+ }
+
+ /* Get the total elapsed time */
+
+ elapsed = TICK2MSEC(g_system_timer - start);
+
+ /* Calculate the percentage of lost packets */
+
+ tmp = (100*(count - replies) + (count >> 1)) / count;
+
+ nsh_output(vtbl, "%d packets transmitted, %d received, %d%% packet loss, time %d ms\n",
+ count, replies, tmp, elapsed);
+ return OK;
+
+errout:
+ nsh_output(vtbl, fmt, argv[0]);
+ return ERROR;
+}
+#endif
+#endif /* CONFIG_NET_ICMP && CONFIG_NET_ICMP_PING */
+
+/****************************************************************************
+ * Name: cmd_put
+ ****************************************************************************/
+
+#if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_PUT
+int cmd_put(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ struct tftpc_args_s args;
+ char *fullpath;
+
+ /* Parse the input parameter list */
+
+ if (tftpc_parseargs(vtbl, argc, argv, &args) != OK)
+ {
+ return ERROR;
+ }
+
+ /* Get the full path to the local file */
+
+ fullpath = nsh_getfullpath(vtbl, args.srcpath);
+
+ /* Then perform the TFTP put operation */
+
+ if (tftpput(fullpath, args.destpath, args.ipaddr, args.binary) != OK)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "tftpput", NSH_ERRNO);
+ }
+
+ /* Release any allocated memory */
+
+ if (args.allocated)
+ {
+ free(args.destpath);
+ }
+ free(fullpath);
+ return OK;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: cmd_wget
+ ****************************************************************************/
+
+#if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_WGET
+int cmd_wget(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ char *localfile = NULL;
+ char *allocfile = NULL;
+ char *buffer = NULL;
+ char *fullpath = NULL;
+ char *url;
+ const char *fmt;
+ bool badarg = false;
+ int option;
+ int fd = -1;
+ int ret;
+
+ /* Get the wget options */
+
+ while ((option = getopt(argc, argv, ":o:")) != ERROR)
+ {
+ switch (option)
+ {
+ case 'o':
+ localfile = optarg;
+ break;
+
+ case ':':
+ nsh_output(vtbl, g_fmtargrequired, argv[0]);
+ badarg = true;
+ break;
+
+ case '?':
+ default:
+ nsh_output(vtbl, g_fmtarginvalid, argv[0]);
+ badarg = true;
+ break;
+ }
+ }
+
+ /* If a bad argument was encountered, then return without processing the command */
+
+ if (badarg)
+ {
+ return ERROR;
+ }
+
+ /* There should be exactly on parameter left on the command-line */
+
+ if (optind == argc-1)
+ {
+ url = argv[optind];
+ }
+ else if (optind >= argc)
+ {
+ fmt = g_fmttoomanyargs;
+ goto errout;
+ }
+ else
+ {
+ fmt = g_fmtargrequired;
+ goto errout;
+ }
+
+ /* Get the local file name */
+
+ if (!localfile)
+ {
+ allocfile = strdup(url);
+ localfile = basename(allocfile);
+ }
+
+ /* Get the full path to the local file */
+
+ fullpath = nsh_getfullpath(vtbl, localfile);
+
+ /* Open the local file for writing */
+
+ fd = open(fullpath, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (fd < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO);
+ ret = ERROR;
+ goto exit;
+ }
+
+ /* Allocate an I/O buffer */
+
+ buffer = malloc(512);
+ if (!buffer)
+ {
+ fmt = g_fmtcmdoutofmemory;
+ goto errout;
+ }
+
+ /* And perform the wget */
+
+ ret = wget(url, buffer, 512, wget_callback, (FAR void *)fd);
+ if (ret < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "wget", NSH_ERRNO);
+ goto exit;
+ }
+
+ /* Free allocated resources */
+
+exit:
+ if (fd >= 0)
+ {
+ close(fd);
+ }
+ if (allocfile)
+ {
+ free(allocfile);
+ }
+ if (fullpath)
+ {
+ free(fullpath);
+ }
+ if (buffer)
+ {
+ free(buffer);
+ }
+ return ret;
+
+errout:
+ nsh_output(vtbl, fmt, argv[0]);
+ ret = ERROR;
+ goto exit;
+}
+#endif
+#endif
+
+#endif /* CONFIG_NET */
diff --git a/apps/nshlib/nsh_netinit.c b/apps/nshlib/nsh_netinit.c
new file mode 100644
index 000000000..eb0052cc7
--- /dev/null
+++ b/apps/nshlib/nsh_netinit.c
@@ -0,0 +1,169 @@
+/****************************************************************************
+ * apps/nshlib/nsh_netinit.c
+ *
+ * Copyright (C) 2010-2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * This is influenced by similar logic from uIP:
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ * Copyright (c) 2003, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <debug.h>
+
+#include <net/if.h>
+#include <net/uip/uip-lib.h>
+#if defined(CONFIG_EXAMPLES_NSH_DHCPC)
+# include <net/uip/resolv.h>
+# include <net/uip/dhcpc.h>
+#endif
+
+#include "nsh.h"
+
+#ifdef CONFIG_NET
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_netinit
+ *
+ * Description:
+ * Initialize the network per the selected NuttX configuration
+ *
+ ****************************************************************************/
+
+int nsh_netinit(void)
+{
+ struct in_addr addr;
+#if defined(CONFIG_EXAMPLES_NSH_DHCPC)
+ FAR void *handle;
+#endif
+#if defined(CONFIG_EXAMPLES_NSH_DHCPC) || defined(CONFIG_EXAMPLES_NSH_NOMAC)
+ uint8_t mac[IFHWADDRLEN];
+#endif
+
+/* Many embedded network interfaces must have a software assigned MAC */
+
+#ifdef CONFIG_EXAMPLES_NSH_NOMAC
+ mac[0] = 0x00;
+ mac[1] = 0xe0;
+ mac[2] = 0xb0;
+ mac[3] = 0x0b;
+ mac[4] = 0xba;
+ mac[5] = 0xbe;
+ uip_setmacaddr("eth0", mac);
+#endif
+
+ /* Set up our host address */
+
+#if !defined(CONFIG_EXAMPLES_NSH_DHCPC)
+ addr.s_addr = HTONL(CONFIG_EXAMPLES_NSH_IPADDR);
+#else
+ addr.s_addr = 0;
+#endif
+ uip_sethostaddr("eth0", &addr);
+
+ /* Set up the default router address */
+
+ addr.s_addr = HTONL(CONFIG_EXAMPLES_NSH_DRIPADDR);
+ uip_setdraddr("eth0", &addr);
+
+ /* Setup the subnet mask */
+
+ addr.s_addr = HTONL(CONFIG_EXAMPLES_NSH_NETMASK);
+ uip_setnetmask("eth0", &addr);
+
+#if defined(CONFIG_EXAMPLES_NSH_DHCPC)
+ /* Set up the resolver */
+
+ resolv_init();
+#endif
+
+#if defined(CONFIG_EXAMPLES_NSH_DHCPC)
+ /* Get the MAC address of the NIC */
+
+ uip_getmacaddr("eth0", mac);
+
+ /* Set up the DHCPC modules */
+
+ handle = dhcpc_open(&mac, IFHWADDRLEN);
+
+ /* Get an IP address. Note that there is no logic for renewing the IP address in this
+ * example. The address should be renewed in ds.lease_time/2 seconds.
+ */
+
+ if (handle)
+ {
+ struct dhcpc_state ds;
+ (void)dhcpc_request(handle, &ds);
+ uip_sethostaddr("eth1", &ds.ipaddr);
+ if (ds.netmask.s_addr != 0)
+ {
+ uip_setnetmask("eth0", &ds.netmask);
+ }
+ if (ds.default_router.s_addr != 0)
+ {
+ uip_setdraddr("eth0", &ds.default_router);
+ }
+ if (ds.dnsaddr.s_addr != 0)
+ {
+ resolv_conf(&ds.dnsaddr);
+ }
+ dhcpc_close(handle);
+ }
+#endif
+ return OK;
+}
+
+#endif /* CONFIG_NET */
diff --git a/apps/nshlib/nsh_proccmds.c b/apps/nshlib/nsh_proccmds.c
new file mode 100644
index 000000000..b49e114ae
--- /dev/null
+++ b/apps/nshlib/nsh_proccmds.c
@@ -0,0 +1,297 @@
+/****************************************************************************
+ * apps/nshlib/nsh_proccmds.c
+ *
+ * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sched.h>
+#include <errno.h>
+
+#include "nsh.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The returned value should be zero for sucess or TRUE or non zero for
+ * failure or FALSE.
+ */
+
+typedef int (*exec_t)(void);
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const char *g_statenames[] =
+{
+ "INVALID ",
+ "PENDING ",
+ "READY ",
+ "RUNNING ",
+ "INACTIVE",
+ "WAITSEM ",
+#ifndef CONFIG_DISABLE_MQUEUE
+ "WAITSIG ",
+#endif
+#ifndef CONFIG_DISABLE_MQUEUE
+ "MQNEMPTY",
+ "MQNFULL "
+#endif
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ps_task
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_PS
+static void ps_task(FAR _TCB *tcb, FAR void *arg)
+{
+ struct nsh_vtbl_s *vtbl = (struct nsh_vtbl_s*)arg;
+ int i;
+
+ /* Show task status */
+
+ nsh_output(vtbl, "%5d %3d %4s %7s%c%c %8s ",
+ tcb->pid, tcb->sched_priority,
+ tcb->flags & TCB_FLAG_ROUND_ROBIN ? "RR " : "FIFO",
+ tcb->flags & TCB_FLAG_PTHREAD ? "PTHREAD" : "TASK ",
+ tcb->flags & TCB_FLAG_NONCANCELABLE ? 'N' : ' ',
+ tcb->flags & TCB_FLAG_CANCEL_PENDING ? 'P' : ' ',
+ g_statenames[tcb->task_state]);
+
+ /* Show task name and arguments */
+
+ nsh_output(vtbl, "%s(", tcb->argv[0]);
+
+ /* Special case 1st argument (no comma) */
+
+ if (tcb->argv[1])
+ {
+ nsh_output(vtbl, "%p", tcb->argv[1]);
+ }
+
+ /* Then any additional arguments */
+
+#if CONFIG_MAX_TASK_ARGS > 2
+ for (i = 2; i <= CONFIG_MAX_TASK_ARGS && tcb->argv[i]; i++)
+ {
+ nsh_output(vtbl, ", %p", tcb->argv[i]);
+ }
+#endif
+ nsh_output(vtbl, ")\n");
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: cmd_exec
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_EXEC
+int cmd_exec(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ char *endptr;
+ long addr;
+
+ addr = strtol(argv[1], &endptr, 0);
+ if (!addr || endptr == argv[1] || *endptr != '\0')
+ {
+ nsh_output(vtbl, g_fmtarginvalid, argv[0]);
+ return ERROR;
+ }
+
+ nsh_output(vtbl, "Calling %p\n", (exec_t)addr);
+ return ((exec_t)addr)();
+}
+#endif
+
+/****************************************************************************
+ * Name: cmd_ps
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_PS
+int cmd_ps(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ nsh_output(vtbl, "PID PRI SCHD TYPE NP STATE NAME\n");
+ sched_foreach(ps_task, vtbl);
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: cmd_kill
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_SIGNALS
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_KILL
+int cmd_kill(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ char *ptr;
+ char *endptr;
+ long signal;
+ long pid;
+
+ /* Check incoming parameters. The first parameter should be "-<signal>" */
+
+ ptr = argv[1];
+ if (*ptr != '-' || ptr[1] < '0' || ptr[1] > '9')
+ {
+ goto invalid_arg;
+ }
+
+ /* Extract the signal number */
+
+ signal = strtol(&ptr[1], &endptr, 0);
+
+ /* The second parameter should be <pid> */
+
+ ptr = argv[2];
+ if (*ptr < '0' || *ptr > '9')
+ {
+ goto invalid_arg;
+ }
+
+ /* Extract athe pid */
+
+ pid = strtol(ptr, &endptr, 0);
+
+ /* Send the signal. Kill return values:
+ *
+ * EINVAL An invalid signal was specified.
+ * EPERM The process does not have permission to send the signal to any
+ * of the target processes.
+ * ESRCH The pid or process group does not exist.
+ * ENOSYS Do not support sending signals to process groups.
+ */
+
+ if (kill((pid_t)pid, (int)signal) == 0)
+ {
+ return OK;
+ }
+
+ switch (errno)
+ {
+ case EINVAL:
+ goto invalid_arg;
+
+ case ESRCH:
+ nsh_output(vtbl, g_fmtnosuch, argv[0], "task", argv[2]);
+ return ERROR;
+
+ case EPERM:
+ case ENOSYS:
+ default:
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "kill", NSH_ERRNO);
+ return ERROR;
+ }
+
+invalid_arg:
+ nsh_output(vtbl, g_fmtarginvalid, argv[0]);
+ return ERROR;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: cmd_sleep
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_SIGNALS
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_SLEEP
+int cmd_sleep(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ char *endptr;
+ long secs;
+
+ secs = strtol(argv[1], &endptr, 0);
+ if (!secs || endptr == argv[1] || *endptr != '\0')
+ {
+ nsh_output(vtbl, g_fmtarginvalid, argv[0]);
+ return ERROR;
+ }
+ sleep(secs);
+ return OK;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: cmd_usleep
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_SIGNALS
+#ifndef CONFIG_EXAMPLES_NSH_DISABLE_USLEEP
+int cmd_usleep(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ char *endptr;
+ long usecs;
+
+ usecs = strtol(argv[1], &endptr, 0);
+ if (!usecs || endptr == argv[1] || *endptr != '\0')
+ {
+ nsh_output(vtbl, g_fmtarginvalid, argv[0]);
+ return ERROR;
+ }
+ usleep(usecs);
+ return OK;
+}
+#endif
+#endif
diff --git a/apps/nshlib/nsh_romfsetc.c b/apps/nshlib/nsh_romfsetc.c
new file mode 100644
index 000000000..ec8300de4
--- /dev/null
+++ b/apps/nshlib/nsh_romfsetc.c
@@ -0,0 +1,124 @@
+/****************************************************************************
+ * apps/nshlib/nsh_romfsetc.c
+ *
+ * Copyright (C) 2008-2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/mount.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <nuttx/ramdisk.h>
+
+#include "nsh.h"
+
+#ifdef CONFIG_EXAMPLES_NSH_ROMFSETC
+
+/* Should we use the default ROMFS image? Or a custom, board-specific
+ * ROMFS image?
+ */
+
+#ifdef CONFIG_EXAMPLES_NSH_ARCHROMFS
+# include <arch/board/nsh_romfsimg.h>
+#else
+# include "nsh_romfsimg.h"
+#endif
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_romfsetc
+ ****************************************************************************/
+
+int nsh_romfsetc(void)
+{
+ int ret;
+
+ /* Create a ROM disk for the /etc filesystem */
+
+ ret = romdisk_register(CONFIG_EXAMPLES_NSH_ROMFSDEVNO, romfs_img,
+ NSECTORS(romfs_img_len), CONFIG_EXAMPLES_NSH_ROMFSSECTSIZE);
+ if (ret < 0)
+ {
+ dbg("nsh: romdisk_register failed: %d\n", -ret);
+ return ERROR;
+ }
+
+ /* Mount the file system */
+
+ vdbg("Mounting ROMFS filesystem at target=%s with source=%s\n",
+ CONFIG_EXAMPLES_NSH_ROMFSMOUNTPT, MOUNT_DEVNAME);
+
+ ret = mount(MOUNT_DEVNAME, CONFIG_EXAMPLES_NSH_ROMFSMOUNTPT, "romfs", MS_RDONLY, NULL);
+ if (ret < 0)
+ {
+ dbg("nsh: mount(%s,%s,romfs) failed: %s\n",
+ MOUNT_DEVNAME, CONFIG_EXAMPLES_NSH_ROMFSMOUNTPT, errno);
+ return ERROR;
+ }
+ return OK;
+}
+
+#endif /* CONFIG_EXAMPLES_NSH_ROMFSETC */
+
diff --git a/apps/nshlib/nsh_romfsimg.h b/apps/nshlib/nsh_romfsimg.h
new file mode 100644
index 000000000..49b0ad166
--- /dev/null
+++ b/apps/nshlib/nsh_romfsimg.h
@@ -0,0 +1,89 @@
+unsigned char romfs_img[] = {
+ 0x2d, 0x72, 0x6f, 0x6d, 0x31, 0x66, 0x73, 0x2d, 0x00, 0x00, 0x01, 0x50,
+ 0x9f, 0x13, 0x82, 0x87, 0x4e, 0x53, 0x48, 0x49, 0x6e, 0x69, 0x74, 0x56,
+ 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49,
+ 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xff, 0xff, 0x97,
+ 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0xd1, 0xd1, 0xff, 0x80, 0x2e, 0x2e, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x68, 0x2d, 0x96, 0x03, 0x69, 0x6e, 0x69, 0x74, 0x2e, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0,
+ 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xff, 0xff, 0x00,
+ 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6e, 0x8d, 0x9c, 0xab, 0x58, 0x72, 0x63, 0x53, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x23, 0x20, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x20, 0x61, 0x20, 0x52,
+ 0x41, 0x4d, 0x44, 0x49, 0x53, 0x4b, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6d,
+ 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x69, 0x74, 0x20, 0x61, 0x74, 0x20, 0x2f,
+ 0x74, 0x6d, 0x70, 0x0a, 0x0a, 0x6d, 0x6b, 0x72, 0x64, 0x20, 0x2d, 0x6d,
+ 0x20, 0x32, 0x20, 0x2d, 0x73, 0x20, 0x35, 0x31, 0x32, 0x20, 0x31, 0x30,
+ 0x32, 0x34, 0x0a, 0x6d, 0x6b, 0x66, 0x61, 0x74, 0x66, 0x73, 0x20, 0x2f,
+ 0x64, 0x65, 0x76, 0x2f, 0x72, 0x61, 0x6d, 0x32, 0x0a, 0x6d, 0x6f, 0x75,
+ 0x6e, 0x74, 0x20, 0x2d, 0x74, 0x20, 0x76, 0x66, 0x61, 0x74, 0x20, 0x2f,
+ 0x64, 0x65, 0x76, 0x2f, 0x72, 0x61, 0x6d, 0x32, 0x20, 0x2f, 0x74, 0x6d,
+ 0x70, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0xd1, 0xd1, 0xff, 0xe0, 0x2e, 0x2e, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+unsigned int romfs_img_len = 1024;
diff --git a/apps/nshlib/nsh_serial.c b/apps/nshlib/nsh_serial.c
new file mode 100644
index 000000000..54e6fff4c
--- /dev/null
+++ b/apps/nshlib/nsh_serial.c
@@ -0,0 +1,449 @@
+/****************************************************************************
+ * apps/nshlib/nsh_serial.c
+ *
+ * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name Gregory Nutt nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <debug.h>
+
+#include "nsh.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct serial_s
+{
+ struct nsh_vtbl_s ss_vtbl;
+ int ss_fd; /* Re-direct file descriptor */
+ FILE *ss_stream; /* Re-direct stream */
+ char ss_line[CONFIG_EXAMPLES_NSH_LINELEN];
+};
+
+struct serialsave_s
+{
+ int ss_fd; /* Re-direct file descriptor */
+ FILE *ss_stream; /* Re-direct stream */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+static FAR struct nsh_vtbl_s *nsh_consoleclone(FAR struct nsh_vtbl_s *vtbl);
+static void nsh_consolerelease(FAR struct nsh_vtbl_s *vtbl);
+#endif
+static ssize_t nsh_consolewrite(FAR struct nsh_vtbl_s *vtbl, FAR const void *buffer, size_t nbytes);
+static int nsh_consoleoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...);
+static FAR char *nsh_consolelinebuffer(FAR struct nsh_vtbl_s *vtbl);
+static void nsh_consoleredirect(FAR struct nsh_vtbl_s *vtbl, int fd, FAR uint8_t *save);
+static void nsh_consoleundirect(FAR struct nsh_vtbl_s *vtbl, FAR uint8_t *save);
+static void nsh_consoleexit(FAR struct nsh_vtbl_s *vtbl);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_allocstruct
+ ****************************************************************************/
+
+static inline FAR struct serial_s *nsh_allocstruct(void)
+{
+ struct serial_s *pstate = (struct serial_s *)zalloc(sizeof(struct serial_s));
+ if (pstate)
+ {
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+ pstate->ss_vtbl.clone = nsh_consoleclone;
+ pstate->ss_vtbl.release = nsh_consolerelease;
+#endif
+ pstate->ss_vtbl.write = nsh_consolewrite;
+ pstate->ss_vtbl.output = nsh_consoleoutput;
+ pstate->ss_vtbl.linebuffer = nsh_consolelinebuffer;
+ pstate->ss_vtbl.redirect = nsh_consoleredirect;
+ pstate->ss_vtbl.undirect = nsh_consoleundirect;
+ pstate->ss_vtbl.exit = nsh_consoleexit;
+
+ pstate->ss_fd = 1;
+ pstate->ss_stream = stdout;
+ }
+ return pstate;
+}
+
+/****************************************************************************
+ * Name: nsh_openifnotopen
+ ****************************************************************************/
+
+static int nsh_openifnotopen(struct serial_s *pstate)
+{
+ /* The stream is open in a lazy fashion. This is done because the file
+ * descriptor may be opened on a different task than the stream.
+ */
+
+ if (!pstate->ss_stream)
+ {
+ pstate->ss_stream = fdopen(pstate->ss_fd, "w");
+ if (!pstate->ss_stream)
+ {
+ return ERROR;
+ }
+ }
+ return 0;
+}
+
+/****************************************************************************
+ * Name: nsh_closeifnotclosed
+ ****************************************************************************/
+
+static void nsh_closeifnotclosed(struct serial_s *pstate)
+{
+ if (pstate->ss_stream == stdout)
+ {
+ fflush(stdout);
+ pstate->ss_fd = 1;
+ }
+ else
+ {
+ if (pstate->ss_stream)
+ {
+ fflush(pstate->ss_stream);
+ fclose(pstate->ss_stream);
+ }
+ else if (pstate->ss_fd >= 0 && pstate->ss_fd != 1)
+ {
+ close(pstate->ss_fd);
+ }
+
+ pstate->ss_fd = -1;
+ pstate->ss_stream = NULL;
+ }
+}
+
+/****************************************************************************
+ * Name: nsh_consolewrite
+ *
+ * Description:
+ * write a buffer to the remote shell window.
+ *
+ * Currently only used by cat.
+ *
+ ****************************************************************************/
+
+static ssize_t nsh_consolewrite(FAR struct nsh_vtbl_s *vtbl, FAR const void *buffer, size_t nbytes)
+{
+ FAR struct serial_s *pstate = (FAR struct serial_s *)vtbl;
+ ssize_t ret;
+
+ /* The stream is open in a lazy fashion. This is done because the file
+ * descriptor may be opened on a different task than the stream. The
+ * actual open will then occur with the first output from the new task.
+ */
+
+ if (nsh_openifnotopen(pstate) != 0)
+ {
+ return (ssize_t)ERROR;
+ }
+
+ /* Write the data to the output stream */
+
+ ret = fwrite(buffer, 1, nbytes, pstate->ss_stream);
+ if (ret < 0)
+ {
+ dbg("[%d] Failed to send buffer: %d\n", pstate->ss_fd, errno);
+ }
+ return ret;
+}
+
+/****************************************************************************
+ * Name: nsh_consoleoutput
+ *
+ * Description:
+ * Print a string to the currently selected stream.
+ *
+ ****************************************************************************/
+
+static int nsh_consoleoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...)
+{
+ FAR struct serial_s *pstate = (FAR struct serial_s *)vtbl;
+ va_list ap;
+ int ret;
+
+ /* The stream is open in a lazy fashion. This is done because the file
+ * descriptor may be opened on a different task than the stream. The
+ * actual open will then occur with the first output from the new task.
+ */
+
+ if (nsh_openifnotopen(pstate) != 0)
+ {
+ return ERROR;
+ }
+
+ va_start(ap, fmt);
+ ret = vfprintf(pstate->ss_stream, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: nsh_consolelinebuffer
+ *
+ * Description:
+ * Return a reference to the current line buffer
+ *
+ ****************************************************************************/
+
+static FAR char *nsh_consolelinebuffer(FAR struct nsh_vtbl_s *vtbl)
+{
+ FAR struct serial_s *pstate = (FAR struct serial_s *)vtbl;
+ return pstate->ss_line;
+}
+
+/****************************************************************************
+ * Name: nsh_consoleclone
+ *
+ * Description:
+ * Make an independent copy of the vtbl
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+static FAR struct nsh_vtbl_s *nsh_consoleclone(FAR struct nsh_vtbl_s *vtbl)
+{
+ FAR struct serial_s *pstate = (FAR struct serial_s *)vtbl;
+ FAR struct serial_s *pclone = nsh_allocstruct();
+
+ if (pclone->ss_fd == 1)
+ {
+ pclone->ss_fd = 1;
+ pclone->ss_stream = stdout;
+ }
+ else
+ {
+ pclone->ss_fd = pstate->ss_fd;
+ pclone->ss_stream = NULL;
+ }
+ return &pclone->ss_vtbl;
+}
+#endif
+
+/****************************************************************************
+ * Name: nsh_consolerelease
+ *
+ * Description:
+ * Release the cloned instance
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+static void nsh_consolerelease(FAR struct nsh_vtbl_s *vtbl)
+{
+ FAR struct serial_s *pstate = (FAR struct serial_s *)vtbl;
+
+ nsh_closeifnotclosed(pstate);
+ free(vtbl);
+}
+#endif
+
+/****************************************************************************
+ * Name: nsh_consoleredirect
+ *
+ * Description:
+ * Set up for redirected output. This function is called from nsh_parse()
+ * in two different contexts:
+ *
+ * 1) Redirected background commands of the form: command > xyz.text &
+ *
+ * In this case:
+ * - vtbl: A newly allocated and initialized instance created by
+ * nsh_consoleclone,
+ * - fd:- The file descriptor of the redirected output
+ * - save: NULL
+ *
+ * nsh_consolerelease() will perform the clean-up when the clone is
+ * destroyed.
+ *
+ * 2) Redirected foreground commands of the form: command > xyz.txt
+ *
+ * In this case:
+ * - vtbl: The current state structure,
+ * - fd: The file descriptor of the redirected output
+ * - save: Where to save the re-directed registers.
+ *
+ * nsh_consoleundirect() will perform the clean-up after the redirected
+ * command completes.
+ *
+ ****************************************************************************/
+
+static void nsh_consoleredirect(FAR struct nsh_vtbl_s *vtbl, int fd, FAR uint8_t *save)
+{
+ FAR struct serial_s *pstate = (FAR struct serial_s *)vtbl;
+ FAR struct serialsave_s *ssave = (FAR struct serialsave_s *)save;
+
+ /* Case 1: Redirected foreground commands */
+
+ if (ssave)
+ {
+ /* pstate->ss_stream and ss_fd refer refer to the
+ * currently opened output stream. If the console is open, flush
+ * any pending output.
+ */
+
+ if (pstate->ss_stream)
+ {
+ fflush(pstate->ss_stream);
+ }
+
+ /* Save the current fd and stream values. These will be restored
+ * when nsh_consoleundirect() is called.
+ */
+
+ ssave->ss_fd = pstate->ss_fd;
+ ssave->ss_stream = pstate->ss_stream;
+ }
+ else
+ {
+ /* nsh_consoleclone() set pstate->ss_fd and ss_stream to refer
+ * to standard out. We just want to leave these alone and overwrite
+ * them with the fd for the re-directed stream.
+ */
+ }
+
+ /* In either case, set the fd of the new, re-directed output and nullify
+ * the output stream (it will be fdopen'ed if it is used).
+ */
+
+ pstate->ss_fd = fd;
+ pstate->ss_stream = NULL;
+}
+
+/****************************************************************************
+ * Name: nsh_consoleundirect
+ *
+ * Description:
+ * Set up for redirected output
+ *
+ ****************************************************************************/
+
+static void nsh_consoleundirect(FAR struct nsh_vtbl_s *vtbl, FAR uint8_t *save)
+{
+ FAR struct serial_s *pstate = (FAR struct serial_s *)vtbl;
+ FAR struct serialsave_s *ssave = (FAR struct serialsave_s *)save;
+
+ nsh_closeifnotclosed(pstate);
+ pstate->ss_fd = ssave->ss_fd;
+ pstate->ss_stream = ssave->ss_stream;
+}
+
+/****************************************************************************
+ * Name: nsh_consoleexit
+ *
+ * Description:
+ * Exit the shell task
+ *
+ ****************************************************************************/
+
+static void nsh_consoleexit(FAR struct nsh_vtbl_s *vtbl)
+{
+ exit(0);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_main
+ ****************************************************************************/
+
+int nsh_consolemain(int argc, char *argv[])
+{
+ FAR struct serial_s *pstate = nsh_allocstruct();
+
+ /* Present a greeting */
+
+ printf(g_nshgreeting);
+ fflush(pstate->ss_stream);
+
+ /* Execute the startup script */
+
+#ifdef CONFIG_EXAMPLES_NSH_ROMFSETC
+ (void)nsh_script(&pstate->ss_vtbl, "init", NSH_INITPATH);
+#endif
+
+ /* Then enter the command line parsing loop */
+
+ for (;;)
+ {
+ /* Display the prompt string */
+
+ fputs(g_nshprompt, pstate->ss_stream);
+ fflush(pstate->ss_stream);
+
+ /* Get the next line of input */
+
+ if (fgets(pstate->ss_line, CONFIG_EXAMPLES_NSH_LINELEN, stdin))
+ {
+ /* Parse process the command */
+
+ (void)nsh_parse(&pstate->ss_vtbl, pstate->ss_line);
+ fflush(pstate->ss_stream);
+ }
+ }
+ return OK;
+}
diff --git a/apps/nshlib/nsh_telnetd.c b/apps/nshlib/nsh_telnetd.c
new file mode 100644
index 000000000..6cf9c188b
--- /dev/null
+++ b/apps/nshlib/nsh_telnetd.c
@@ -0,0 +1,853 @@
+/****************************************************************************
+ * apps/nshlib/nsh_telnetd.c
+ *
+ * Copyright (C) 2007-2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * This is a leverage of similar logic from uIP:
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ * Copyright (c) 2003, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <net/if.h>
+#include <net/uip/uip-lib.h>
+#if defined(CONFIG_EXAMPLES_NSH_DHCPC)
+# include <net/uip/resolv.h>
+# include <net/uip/dhcpc.h>
+#endif
+
+#include "nsh.h"
+
+#ifdef CONFIG_EXAMPLES_NSH_TELNET
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+#define ISO_nl 0x0a
+#define ISO_cr 0x0d
+
+#define STATE_NORMAL 0
+#define STATE_IAC 1
+#define STATE_WILL 2
+#define STATE_WONT 3
+#define STATE_DO 4
+#define STATE_DONT 5
+#define STATE_CLOSE 6
+
+#define TELNET_IAC 255
+#define TELNET_WILL 251
+#define TELNET_WONT 252
+#define TELNET_DO 253
+#define TELNET_DONT 254
+
+#ifdef CONFIG_EXAMPLES_NSH_TELNETD_DUMPBUFFER
+# define nsh_telnetdump(vtbl,msg,buf,nb) nsh_dumpbuffer(vtbl,msg,buf,nb)
+#else
+# define nsh_telnetdump(vtbl,msg,buf,nb)
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct telnetio_s
+{
+ sem_t tio_sem;
+ int tio_sockfd;
+ uint8_t tio_bufndx;
+ uint8_t tio_state;
+ char tio_inbuffer[CONFIG_EXAMPLES_NSH_IOBUFFER_SIZE];
+};
+
+struct redirect_s
+{
+ int rd_fd; /* Re-direct file descriptor */
+ FILE *rd_stream; /* Re-direct stream */
+};
+
+struct telnetsave_s
+{
+ bool ts_redirected;
+ union
+ {
+ struct telnetio_s *tn;
+ struct redirect_s rd;
+ } u;
+};
+
+struct telnetd_s
+{
+ struct nsh_vtbl_s tn_vtbl;
+ uint16_t tn_sndlen;
+ bool tn_redirected;
+ union
+ {
+ struct telnetio_s *tn;
+ struct redirect_s rd;
+ } u;
+ char tn_outbuffer[CONFIG_EXAMPLES_NSH_IOBUFFER_SIZE];
+ char tn_cmd[CONFIG_EXAMPLES_NSH_LINELEN];
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+static void tio_semtake(struct telnetio_s *tio);
+static FAR struct nsh_vtbl_s *nsh_telnetclone(FAR struct nsh_vtbl_s *vtbl);
+#endif
+static void nsh_telnetrelease(FAR struct nsh_vtbl_s *vtbl);
+static ssize_t nsh_telnetwrite(FAR struct nsh_vtbl_s *vtbl, FAR const void *buffer, size_t nbytes);
+static int nsh_telnetoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...);
+static int nsh_redirectoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...);
+static FAR char *nsh_telnetlinebuffer(FAR struct nsh_vtbl_s *vtbl);
+static void nsh_telnetredirect(FAR struct nsh_vtbl_s *vtbl, int fd, FAR uint8_t *save);
+static void nsh_telnetundirect(FAR struct nsh_vtbl_s *vtbl, FAR uint8_t *save);
+static void nsh_telnetexit(FAR struct nsh_vtbl_s *vtbl);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: tio_semtake
+ ****************************************************************************/
+
+static void tio_semtake(struct telnetio_s *tio)
+{
+ /* Take the semaphore (perhaps waiting) */
+
+ while (sem_wait(&tio->tio_sem) != 0)
+ {
+ /* The only case that an error should occur here is if the wait was
+ * awakened by a signal.
+ */
+
+ ASSERT(errno == EINTR);
+ }
+}
+
+/****************************************************************************
+ * Name: tio_semgive
+ ****************************************************************************/
+
+#define tio_semgive(tio) ASSERT(sem_post(&tio->tio_sem) == 0)
+
+/****************************************************************************
+ * Name: nsh_allocstruct
+ ****************************************************************************/
+
+static FAR struct telnetd_s *nsh_allocstruct(void)
+{
+ struct telnetd_s *pstate = (struct telnetd_s *)zalloc(sizeof(struct telnetd_s));
+ if (pstate)
+ {
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+ pstate->tn_vtbl.clone = nsh_telnetclone;
+ pstate->tn_vtbl.release = nsh_telnetrelease;
+#endif
+ pstate->tn_vtbl.write = nsh_telnetwrite;
+ pstate->tn_vtbl.output = nsh_telnetoutput;
+ pstate->tn_vtbl.linebuffer = nsh_telnetlinebuffer;
+ pstate->tn_vtbl.redirect = nsh_telnetredirect;
+ pstate->tn_vtbl.undirect = nsh_telnetundirect;
+ pstate->tn_vtbl.exit = nsh_telnetexit;
+ }
+ return pstate;
+}
+
+/****************************************************************************
+ * Name: nsh_openifnotopen
+ ****************************************************************************/
+
+static int nsh_openifnotopen(struct telnetd_s *pstate)
+{
+ struct redirect_s *rd = &pstate->u.rd;
+
+ /* The stream is open in a lazy fashion. This is done because the file
+ * descriptor may be opened on a different task than the stream.
+ */
+
+ if (!rd->rd_stream)
+ {
+ rd->rd_stream = fdopen(rd->rd_fd, "w");
+ if (!rd->rd_stream)
+ {
+ return ERROR;
+ }
+ }
+ return 0;
+}
+
+/****************************************************************************
+ * Name: nsh_closeifnotclosed
+ ****************************************************************************/
+
+static void nsh_closeifnotclosed(struct telnetd_s *pstate)
+{
+ struct redirect_s *rd = &pstate->u.rd;
+
+ if (rd->rd_stream == stdout)
+ {
+ fflush(stdout);
+ rd->rd_fd = 1;
+ }
+ else
+ {
+ if (rd->rd_stream)
+ {
+ fflush(rd->rd_stream);
+ fclose(rd->rd_stream);
+ }
+ else if (rd->rd_fd >= 0 && rd->rd_fd != 1)
+ {
+ close(rd->rd_fd);
+ }
+
+ rd->rd_fd = -1;
+ rd->rd_stream = NULL;
+ }
+}
+
+/****************************************************************************
+ * Name: nsh_putchar
+ *
+ * Description:
+ * Add another parsed character to the TELNET command string
+ *
+ * Assumption:
+ * Caller holds TIO semaphore
+ *
+ ****************************************************************************/
+
+static void nsh_putchar(struct telnetd_s *pstate, uint8_t ch)
+{
+ struct telnetio_s *tio = pstate->u.tn;
+
+ /* Ignore carriage returns */
+
+ if (ch == ISO_cr)
+ {
+ return;
+ }
+
+ /* Add all other characters to the cmd buffer */
+
+ pstate->tn_cmd[tio->tio_bufndx] = ch;
+
+ /* If a newline was added or if the buffer is full, then process it now */
+
+ if (ch == ISO_nl || tio->tio_bufndx == (CONFIG_EXAMPLES_NSH_LINELEN - 1))
+ {
+ pstate->tn_cmd[tio->tio_bufndx] = '\0';
+ nsh_telnetdump(&pstate->tn_vtbl, "TELNET CMD",
+ (uint8_t*)pstate->tn_cmd, strlen(pstate->tn_cmd));
+ nsh_parse(&pstate->tn_vtbl, pstate->tn_cmd);
+ tio->tio_bufndx = 0;
+ }
+ else
+ {
+ tio->tio_bufndx++;
+ vdbg("Add '%c', bufndx=%d\n", ch, tio->tio_bufndx);
+ }
+}
+
+/****************************************************************************
+ * Name: nsh_sendopt
+ *
+ * Description:
+ *
+ ****************************************************************************/
+
+static void nsh_sendopt(struct telnetd_s *pstate, uint8_t option, uint8_t value)
+{
+ struct telnetio_s *tio = pstate->u.tn;
+ uint8_t optbuf[4];
+ optbuf[0] = TELNET_IAC;
+ optbuf[1] = option;
+ optbuf[2] = value;
+ optbuf[3] = 0;
+
+ nsh_telnetdump(&pstate->tn_vtbl, "Send optbuf", optbuf, 4);
+ tio_semtake(tio); /* Only one call to send at a time */
+ if (send(tio->tio_sockfd, optbuf, 4, 0) < 0)
+ {
+ dbg("[%d] Failed to send TELNET_IAC: %d\n", tio->tio_sockfd, errno);
+ }
+ tio_semgive(tio);
+}
+
+/****************************************************************************
+ * Name: nsh_flush
+ *
+ * Description:
+ * Dump the buffered output info.
+ *
+ ****************************************************************************/
+
+static void nsh_flush(FAR struct telnetd_s *pstate)
+{
+ struct telnetio_s *tio = pstate->u.tn;
+
+ if (pstate->tn_sndlen > 0)
+ {
+ nsh_telnetdump(&pstate->tn_vtbl, "Shell output",
+ (uint8_t*)pstate->tn_outbuffer, pstate->tn_sndlen);
+ tio_semtake(tio); /* Only one call to send at a time */
+ if (send(tio->tio_sockfd, pstate->tn_outbuffer, pstate->tn_sndlen, 0) < 0)
+ {
+ dbg("[%d] Failed to send response: %d\n", tio->tio_sockfd, errno);
+ }
+ tio_semgive(tio);
+ }
+ pstate->tn_sndlen = 0;
+}
+
+/****************************************************************************
+ * Name: nsh_receive
+ *
+ * Description:
+ * Process a received TELENET buffer
+ *
+ ****************************************************************************/
+
+static int nsh_receive(struct telnetd_s *pstate, size_t len)
+{
+ struct telnetio_s *tio = pstate->u.tn;
+ char *ptr = tio->tio_inbuffer;
+ uint8_t ch;
+
+ while (len > 0)
+ {
+ ch = *ptr++;
+ len--;
+
+ vdbg("ch=%02x state=%d\n", ch, tio->tio_state);
+ switch (tio->tio_state)
+ {
+ case STATE_IAC:
+ if (ch == TELNET_IAC)
+ {
+ nsh_putchar(pstate, ch);
+ tio->tio_state = STATE_NORMAL;
+ }
+ else
+ {
+ switch (ch)
+ {
+ case TELNET_WILL:
+ tio->tio_state = STATE_WILL;
+ break;
+
+ case TELNET_WONT:
+ tio->tio_state = STATE_WONT;
+ break;
+
+ case TELNET_DO:
+ tio->tio_state = STATE_DO;
+ break;
+
+ case TELNET_DONT:
+ tio->tio_state = STATE_DONT;
+ break;
+
+ default:
+ tio->tio_state = STATE_NORMAL;
+ break;
+ }
+ }
+ break;
+
+ case STATE_WILL:
+ /* Reply with a DONT */
+
+ nsh_sendopt(pstate, TELNET_DONT, ch);
+ tio->tio_state = STATE_NORMAL;
+ break;
+
+ case STATE_WONT:
+ /* Reply with a DONT */
+
+ nsh_sendopt(pstate, TELNET_DONT, ch);
+ tio->tio_state = STATE_NORMAL;
+ break;
+
+ case STATE_DO:
+ /* Reply with a WONT */
+
+ nsh_sendopt(pstate, TELNET_WONT, ch);
+ tio->tio_state = STATE_NORMAL;
+ break;
+
+ case STATE_DONT:
+ /* Reply with a WONT */
+
+ nsh_sendopt(pstate, TELNET_WONT, ch);
+ tio->tio_state = STATE_NORMAL;
+ break;
+
+ case STATE_NORMAL:
+ if (ch == TELNET_IAC)
+ {
+ tio->tio_state = STATE_IAC;
+ }
+ else
+ {
+ nsh_putchar(pstate, ch);
+ }
+ break;
+ }
+ }
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nsh_connection
+ *
+ * Description:
+ * Each time a new connection to port 23 is made, a new thread is created
+ * that begins at this entry point. There should be exactly one argument
+ * and it should be the socket descriptor (+1).
+ *
+ ****************************************************************************/
+
+static void *nsh_connection(void *arg)
+{
+ struct telnetd_s *pstate = nsh_allocstruct();
+ struct telnetio_s *tio = (struct telnetio_s *)zalloc(sizeof(struct telnetio_s));
+ struct nsh_vtbl_s *vtbl = &pstate->tn_vtbl;
+ int sockfd = (int)arg;
+ int ret = ERROR;
+
+ dbg("[%d] Started\n", sockfd);
+
+ /* Verify that the state structure was successfully allocated */
+
+ if (pstate && tio)
+ {
+ /* Initialize the thread state structure */
+
+ sem_init(&tio->tio_sem, 0, 1);
+ tio->tio_sockfd = sockfd;
+ tio->tio_state = STATE_NORMAL;
+ pstate->u.tn = tio;
+
+ /* Output a greeting */
+
+ nsh_output(vtbl, g_nshgreeting);
+
+ /* Execute the startup script */
+
+#if defined(CONFIG_EXAMPLES_NSH_ROMFSETC) && !defined(CONFIG_EXAMPLES_NSH_CONSOLE)
+ (void)nsh_script(vtbl, "init", NSH_INITPATH);
+#endif
+
+ /* Loop processing each TELNET command */
+
+ do
+ {
+ /* Display the prompt string */
+
+ nsh_output(vtbl, g_nshprompt);
+ nsh_flush(pstate);
+
+ /* Read a buffer of data from the TELNET client */
+
+ ret = recv(tio->tio_sockfd, tio->tio_inbuffer,
+ CONFIG_EXAMPLES_NSH_IOBUFFER_SIZE, 0);
+ if (ret > 0)
+ {
+
+ /* Process the received TELNET data */
+
+ nsh_telnetdump(vtbl, "Received buffer",
+ (uint8_t*)tio->tio_inbuffer, ret);
+ ret = nsh_receive(pstate, ret);
+ }
+ }
+ while (ret >= 0 && tio->tio_state != STATE_CLOSE);
+ dbg("[%d] ret=%d tn.tio_state=%d\n", sockfd, ret, tio->tio_state);
+
+ /* End of command processing -- Clean up and exit */
+ }
+
+ /* Exit the task */
+
+ if (pstate)
+ {
+ free(pstate);
+ }
+
+ if (tio)
+ {
+ sem_destroy(&tio->tio_sem);
+ free(tio);
+ }
+
+ dbg("[%d] Exitting\n", sockfd);
+ close(sockfd);
+ return NULL;
+}
+
+/****************************************************************************
+ * Name: nsh_telnetwrite
+ *
+ * Description:
+ * write a buffer to the remote shell window.
+ *
+ * Currently only used by cat.
+ *
+ ****************************************************************************/
+
+static ssize_t nsh_telnetwrite(FAR struct nsh_vtbl_s *vtbl, FAR const void *buffer, size_t nbytes)
+{
+ struct telnetd_s *pstate = (struct telnetd_s *)vtbl;
+ struct telnetio_s *tio = pstate->u.tn;
+ ssize_t ret = nbytes;
+
+ /* Flush anything already in the output buffer */
+
+ nsh_flush(pstate);
+
+ /* Then write the user buffer */
+
+ nsh_telnetdump(&pstate->tn_vtbl, "Buffer output",(uint8_t*)buffer, nbytes);
+
+ tio_semtake(tio); /* Only one call to send at a time */
+ ret = send(tio->tio_sockfd, buffer, nbytes, 0);
+ if (ret < 0)
+ {
+ dbg("[%d] Failed to send buffer: %d\n", tio->tio_sockfd, errno);
+ }
+
+ tio_semgive(tio);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: nsh_telnetoutput
+ *
+ * Description:
+ * Print a string to the remote shell window.
+ *
+ * This function is implemented by the shell GUI / telnet server and
+ * can be called by the shell back-end to output a string in the
+ * shell window. The string is automatically appended with a linebreak.
+ *
+ ****************************************************************************/
+
+static int nsh_telnetoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...)
+{
+ struct telnetd_s *pstate = (struct telnetd_s *)vtbl;
+ int nbytes = pstate->tn_sndlen;
+ int len;
+ va_list ap;
+
+ /* Put the new info into the buffer. Here we are counting on the fact that
+ * no output strings will exceed CONFIG_EXAMPLES_NSH_LINELEN!
+ */
+
+ va_start(ap, fmt);
+ vsnprintf(&pstate->tn_outbuffer[nbytes],
+ (CONFIG_EXAMPLES_NSH_IOBUFFER_SIZE - 1) - nbytes, fmt, ap);
+ va_end(ap);
+
+ /* Get the size of the new string just added and the total size of
+ * buffered data
+ */
+
+ len = strlen(&pstate->tn_outbuffer[nbytes]);
+ nbytes += len;
+
+ /* Expand any terminating \n to \r\n */
+
+ if (nbytes < (CONFIG_EXAMPLES_NSH_IOBUFFER_SIZE - 2) &&
+ pstate->tn_outbuffer[nbytes-1] == '\n')
+ {
+ pstate->tn_outbuffer[nbytes-1] = ISO_cr;
+ pstate->tn_outbuffer[nbytes] = ISO_nl;
+ pstate->tn_outbuffer[nbytes+1] = '\0';
+ nbytes++;
+ }
+ pstate->tn_sndlen = nbytes;
+
+ /* Flush to the network if the buffer does not have room for one more
+ * maximum length string.
+ */
+
+ if (nbytes > CONFIG_EXAMPLES_NSH_IOBUFFER_SIZE - CONFIG_EXAMPLES_NSH_LINELEN)
+ {
+ nsh_flush(pstate);
+ }
+
+ return len;
+}
+
+/****************************************************************************
+ * Name: nsh_redirectoutput
+ *
+ * Description:
+ * Print a string to the currently selected stream.
+ *
+ ****************************************************************************/
+
+static int nsh_redirectoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...)
+{
+ FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl;
+ va_list ap;
+ int ret;
+
+ /* The stream is open in a lazy fashion. This is done because the file
+ * descriptor may be opened on a different task than the stream. The
+ * actual open will then occur with the first output from the new task.
+ */
+
+ if (nsh_openifnotopen(pstate) != 0)
+ {
+ return ERROR;
+ }
+
+ va_start(ap, fmt);
+ ret = vfprintf(pstate->u.rd.rd_stream, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: nsh_telnetlinebuffer
+ *
+ * Description:
+ * Return a reference to the current line buffer
+ *
+* ****************************************************************************/
+
+static FAR char *nsh_telnetlinebuffer(FAR struct nsh_vtbl_s *vtbl)
+{
+ struct telnetd_s *pstate = (struct telnetd_s *)vtbl;
+ return pstate->tn_cmd;
+}
+
+/****************************************************************************
+ * Name: nsh_telnetclone
+ *
+ * Description:
+ * Make an independent copy of the vtbl
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+static FAR struct nsh_vtbl_s *nsh_telnetclone(FAR struct nsh_vtbl_s *vtbl)
+{
+ FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl;
+ FAR struct telnetd_s *pclone = nsh_allocstruct();
+ FAR struct nsh_vtbl_s *ret = NULL;
+
+ if (pclone)
+ {
+ if (pstate->tn_redirected)
+ {
+ pclone->tn_redirected = true;
+ pclone->tn_vtbl.output = nsh_redirectoutput;
+ pclone->u.rd.rd_fd = pstate->u.rd.rd_fd;
+ pclone->u.rd.rd_stream = NULL;
+ }
+ else
+ {
+ pclone->u.tn = pstate->u.tn;
+ }
+ ret = &pclone->tn_vtbl;
+ }
+ return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: nsh_telnetrelease
+ *
+ * Description:
+ * Release the cloned instance
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_EXAMPLES_NSH_DISABLEBG
+static void nsh_telnetrelease(FAR struct nsh_vtbl_s *vtbl)
+{
+ FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl;
+
+ if (pstate->tn_redirected)
+ {
+ nsh_closeifnotclosed(pstate);
+ }
+ else
+ {
+ nsh_flush(pstate);
+ }
+ free(pstate);
+}
+#endif
+
+/****************************************************************************
+ * Name: nsh_telnetredirect
+ *
+ * Description:
+ * Set up for redirected output. This function is called from nsh_parse()
+ * in two different contexts:
+ *
+ * 1) Redirected background commands of the form: command > xyz.text &
+ *
+ * In this case:
+ * - vtbl: A newly allocated and initialized instance created by
+ * nsh_telnetclone,
+ * - fd:- The file descriptor of the redirected output
+ * - save: NULL
+ *
+ * nsh_telnetrelease() will perform the clean-up when the clone is
+ * destroyed.
+ *
+ * 2) Redirected foreground commands of the form: command > xyz.txt
+ *
+ * In this case:
+ * - vtbl: The current state structure,
+ * - fd: The file descriptor of the redirected output
+ * - save: Where to save the re-directed registers.
+ *
+ * nsh_telnetundirect() will perform the clean-up after the redirected
+ * command completes.
+ *
+ ****************************************************************************/
+
+static void nsh_telnetredirect(FAR struct nsh_vtbl_s *vtbl, int fd, FAR uint8_t *save)
+{
+ FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl;
+ FAR struct telnetsave_s *ssave = (FAR struct telnetsave_s *)save;
+
+ if (pstate->tn_redirected)
+ {
+ (void)nsh_openifnotopen(pstate);
+ fflush(pstate->u.rd.rd_stream);
+ if (!ssave)
+ {
+ fclose(pstate->u.rd.rd_stream);
+ }
+ }
+
+ if (ssave)
+ {
+ ssave->ts_redirected = pstate->tn_redirected;
+ memcpy(&ssave->u.rd, &pstate->u.rd, sizeof(struct redirect_s));
+ }
+
+ pstate->tn_redirected = true;
+ pstate->u.rd.rd_fd = fd;
+ pstate->u.rd.rd_stream = NULL;
+}
+
+/****************************************************************************
+ * Name: nsh_telnetundirect
+ *
+ * Description:
+ * Set up for redirected output
+ *
+ ****************************************************************************/
+
+static void nsh_telnetundirect(FAR struct nsh_vtbl_s *vtbl, FAR uint8_t *save)
+{
+ FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl;
+ FAR struct telnetsave_s *ssave = (FAR struct telnetsave_s *)save;
+
+ if (pstate->tn_redirected)
+ {
+ nsh_closeifnotclosed(pstate);
+ }
+
+ pstate->tn_redirected = ssave->ts_redirected;
+ memcpy(&pstate->u.rd, &ssave->u.rd, sizeof(struct redirect_s));
+}
+
+/****************************************************************************
+ * Name: nsh_telnetexit
+ *
+ * Description:
+ * Quit the shell instance
+ *
+ ****************************************************************************/
+
+static void nsh_telnetexit(FAR struct nsh_vtbl_s *vtbl)
+{
+ struct telnetd_s *pstate = (struct telnetd_s *)vtbl;
+ pstate->u.tn->tio_state = STATE_CLOSE;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_telnetmain
+ *
+ * Description:
+ * This is the main processing thread for telnetd. It never returns
+ * unless an error occurs
+ *
+ ****************************************************************************/
+
+int nsh_telnetmain(int argc, char *argv[])
+{
+ /* Execute nsh_connection() on each connection to port 23 */
+
+ uip_server(HTONS(23), nsh_connection, CONFIG_EXAMPLES_NSH_STACKSIZE);
+ return OK;
+}
+
+#endif /* CONFIG_EXAMPLES_NSH_TELNET */
diff --git a/apps/nshlib/nsh_test.c b/apps/nshlib/nsh_test.c
new file mode 100644
index 000000000..594887b18
--- /dev/null
+++ b/apps/nshlib/nsh_test.c
@@ -0,0 +1,437 @@
+/****************************************************************************
+ * apps/nshlib/nsh_test.c
+ *
+ * Copyright (C) 2008, 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/* Test syntax:
+ *
+ * expression = simple-expression | !expression |
+ * expression -o expression | expression -a expression
+ *
+ * simple-expression = unary-expression | binary-expression
+ *
+ * unary-expression = string-unary | file-unary
+ *
+ * string-unary = -n string | -z string
+ *
+ * file-unary = -b file | -c file | -d file | -e file | -f file |
+ * -r file | -s file | -w file
+ *
+ * binary-expression = string-binary | numeric-binary
+ *
+ * string-binary = string = string | string == string | string != string
+ *
+ * numeric-binary = integer -eq integer | integer -ge integer |
+ * integer -gt integer | integer -le integer |
+ * integer -lt integer | integer -ne integer
+ *
+ * Note that the smallest expression consists of two strings.
+ */
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "nsh.h"
+
+#if !defined(CONFIG_EXAMPLES_NSH_DISABLESCRIPT) && !defined(CONFIG_EXAMPLES_NSH_DISABLE_TEST)
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+#define TEST_TRUE OK
+#define TEST_FALSE ERROR
+#define TEST_ERROR 1
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: binaryexpression
+ ****************************************************************************/
+
+static inline int binaryexpression(FAR struct nsh_vtbl_s *vtbl, char **argv)
+{
+ char *endptr;
+ long integer1;
+ long integer2;
+
+ /* STRING2 = STRING2 */
+
+ if (strcmp(argv[1], "=") == 0 || strcmp(argv[1], "==") == 0)
+ {
+ /* Return true if the strings are identical */
+
+ return strcmp(argv[0], argv[2]) == 0 ? TEST_TRUE : TEST_FALSE;
+ }
+
+ /* STRING1 != STRING2 */
+
+ if (strcmp(argv[1], "!=") == 0)
+ {
+ /* Return true if the strings are different */
+
+ return strcmp(argv[0], argv[2]) != 0 ? TEST_TRUE : TEST_FALSE;
+ }
+
+ /* The remaining operators assuming that the two values are integers */
+
+ integer1 = strtol(argv[0], &endptr, 0);
+ if (argv[0][0] == '\0' || *endptr != '\0')
+ {
+ return TEST_ERROR;
+ }
+
+ integer2 = strtol(argv[2], &endptr, 0);
+ if (argv[2][0] == '\0' || *endptr != '\0')
+ {
+ return TEST_ERROR;
+ }
+
+ /* INTEGER1 -eq INTEGER2 */
+
+ if (strcmp(argv[1], "-eq") == 0)
+ {
+ /* Return true if the strings are different */
+
+ return integer1 == integer2 ? TEST_TRUE : TEST_FALSE;
+ }
+
+ /* INTEGER1 -ge INTEGER2 */
+
+ if (strcmp(argv[1], "-ge") == 0)
+ {
+ /* Return true if the strings are different */
+
+ return integer1 >= integer2 ? TEST_TRUE : TEST_FALSE;
+ }
+
+ /* INTEGER1 -gt INTEGER2 */
+
+ if (strcmp(argv[1], "-gt") == 0)
+ {
+ /* Return true if the strings are different */
+
+ return integer1 > integer2 ? TEST_TRUE : TEST_FALSE;
+ }
+
+ /* INTEGER1 -le INTEGER2 */
+
+ if (strcmp(argv[1], "-le") == 0)
+ {
+ /* Return true if the strings are different */
+
+ return integer1 <= integer2 ? TEST_TRUE : TEST_FALSE;
+ }
+
+ /* INTEGER1 -lt INTEGER2 */
+
+ if (strcmp(argv[1], "-lt") == 0)
+ {
+ /* Return true if the strings are different */
+
+ return integer1 < integer2 ? TEST_TRUE : TEST_FALSE;
+ }
+
+ /* INTEGER1 -ne INTEGER2 */
+
+ if (strcmp(argv[1], "-ne") == 0)
+ {
+ /* Return true if the strings are different */
+
+ return integer1 != integer2 ? TEST_TRUE : TEST_FALSE;
+ }
+
+ return TEST_ERROR;
+}
+
+/****************************************************************************
+ * Name: unaryexpression
+ ****************************************************************************/
+
+static inline int unaryexpression(FAR struct nsh_vtbl_s *vtbl, char **argv)
+{
+ struct stat buf;
+ char *fullpath;
+ int ret;
+
+ /* -n STRING */
+
+ if (strcmp(argv[0], "-n") == 0)
+ {
+ /* Return true if the length of the string is non-zero */
+
+ return strlen(argv[1]) != 0 ? TEST_TRUE : TEST_FALSE;
+ }
+
+ /* -z STRING */
+
+ if (strcmp(argv[0], "-z") == 0)
+ {
+ /* Return true if the length of the string is zero */
+
+ return strlen(argv[1]) == 0 ? TEST_TRUE : TEST_FALSE;
+ }
+
+ /* All of the remaining assume that the following argument is the
+ * path to a file.
+ */
+
+ fullpath = nsh_getfullpath(vtbl, argv[1]);
+ if (!fullpath)
+ {
+ return TEST_FALSE;
+ }
+
+ ret = stat(fullpath, &buf);
+ nsh_freefullpath(fullpath);
+
+ if (ret != 0)
+ {
+ /* The file does not exist (or another error occurred) -- return FALSE */
+
+ return TEST_FALSE;
+ }
+
+ /* -b FILE */
+
+ if (strcmp(argv[0], "-b") == 0)
+ {
+ /* Return true if the path is a block device */
+
+ return S_ISBLK(buf.st_mode) ? TEST_TRUE : TEST_FALSE;
+ }
+
+ /* -c FILE */
+
+ if (strcmp(argv[0], "-c") == 0)
+ {
+ /* Return true if the path is a character device */
+
+ return S_ISCHR(buf.st_mode) ? TEST_TRUE : TEST_FALSE;
+ }
+
+ /* -d FILE */
+
+ if (strcmp(argv[0], "-d") == 0)
+ {
+ /* Return true if the path is a directory */
+
+ return S_ISDIR(buf.st_mode) ? TEST_TRUE : TEST_FALSE;
+ }
+
+ /* -e FILE */
+
+ if (strcmp(argv[0], "-e") == 0)
+ {
+ /* Return true if the file exists */
+
+ return TEST_TRUE;
+ }
+
+ /* -f FILE */
+
+ if (strcmp(argv[0], "-f") == 0)
+ {
+ /* Return true if the path refers to a regular file */
+
+ return S_ISREG(buf.st_mode) ? TEST_TRUE : TEST_FALSE;
+ }
+
+ /* -r FILE */
+
+ if (strcmp(argv[0], "-r") == 0)
+ {
+ /* Return true if the file is readable */
+
+ return (buf.st_mode & (S_IRUSR|S_IRGRP|S_IROTH)) != 0 ? TEST_TRUE : TEST_FALSE;
+ }
+
+ /* -s FILE */
+
+ if (strcmp(argv[0], "-s") == 0)
+ {
+ /* Return true if the size of the file is greater than zero */
+
+ return buf.st_size > 0 ? TEST_TRUE : TEST_FALSE;
+ }
+
+ /* -w FILE */
+
+ if (strcmp(argv[0], "-w") == 0)
+ {
+ /* Return true if the file is write-able */
+
+ return (buf.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) != 0 ? TEST_TRUE : TEST_FALSE;
+ }
+
+ /* Unrecognized operator */
+
+ return TEST_ERROR;
+}
+
+/****************************************************************************
+ * Name: expression
+ ****************************************************************************/
+
+static int expression(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ int value;
+ int i = 0;
+
+ /* Check for unary operations on expressions */
+
+ if (strcmp(argv[0], "!") == 0)
+ {
+ if (argc < 2)
+ {
+ goto errout_syntax;
+ }
+ return expression(vtbl, argc-1, &argv[1]) == TEST_TRUE ? TEST_FALSE : TEST_TRUE;
+ }
+
+ /* Check for unary operations on simple, typed arguments */
+
+ else if (argv[0][0] == '-')
+ {
+ if (argc < 2)
+ {
+ goto errout_syntax;
+ }
+ i += 2;
+ value = unaryexpression(vtbl, argv);
+ }
+
+ /* Check for binary operations on simple, typed arguments */
+
+ else
+ {
+ if (argc < 3)
+ {
+ goto errout_syntax;
+ }
+ i += 3;
+ value = binaryexpression(vtbl, argv);
+ }
+
+ /* Test if there any failure */
+
+ if (value == TEST_ERROR)
+ {
+ goto errout_syntax;
+ }
+
+ /* Is there anything after the simple expression? */
+
+ if (i < argc)
+ {
+ /* EXPRESSION -a EXPRESSION */
+
+ if (strcmp(argv[i], "-a") == 0)
+ {
+ if (value != TEST_TRUE)
+ {
+ return TEST_FALSE;
+ }
+ else
+ {
+ i++;
+ return expression(vtbl, argc-i, &argv[i]);
+ }
+ }
+
+ /* EXPRESSION -o EXPRESSION */
+
+ else if (strcmp(argv[i], "-o") == 0)
+ {
+ if (value == TEST_TRUE)
+ {
+ return TEST_TRUE;
+ }
+ else
+ {
+ i++;
+ return expression(vtbl, argc-i, &argv[i]);
+ }
+ }
+ else
+ {
+ goto errout_syntax;
+ }
+ }
+ return value;
+
+errout_syntax:
+ nsh_output(vtbl, g_nshsyntax, "test");
+ return TEST_FALSE;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: cmd_test
+ ****************************************************************************/
+
+int cmd_test(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ return expression(vtbl, argc-1, &argv[1]);
+}
+
+/****************************************************************************
+ * Name: cmd_lbracket
+ ****************************************************************************/
+
+int cmd_lbracket(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ if (strcmp(argv[argc-1], "]") != 0)
+ {
+ nsh_output(vtbl, g_nshsyntax, argv[0]);
+ return ERROR;
+ }
+ else
+ {
+ return expression(vtbl, argc-2, &argv[1]);
+ }
+}
+
+#endif /* !CONFIG_EXAMPLES_NSH_DISABLESCRIPT && !CONFIG_EXAMPLES_NSH_DISABLE_TEST */
diff --git a/apps/nshlib/rcS.template b/apps/nshlib/rcS.template
new file mode 100644
index 000000000..996f37fb1
--- /dev/null
+++ b/apps/nshlib/rcS.template
@@ -0,0 +1,5 @@
+# Create a RAMDISK and mount it at XXXRDMOUNTPOUNTXXX
+
+mkrd -m XXXMKRDMINORXXX -s XXMKRDSECTORSIZEXXX XXMKRDBLOCKSXXX
+mkfatfs /dev/ramXXXMKRDMINORXXX
+mount -t vfat /dev/ramXXXMKRDMINORXXX XXXRDMOUNTPOUNTXXX