diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2012-09-17 18:18:44 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2012-09-17 18:18:44 +0000 |
commit | 57623d42ebb04f0a0b9e6eb7c0847a3ece2aa0ff (patch) | |
tree | 25d07d14e920d31c0b1947c9ca586f2a01fc32d8 /apps/nshlib | |
download | px4-firmware-57623d42ebb04f0a0b9e6eb7c0847a3ece2aa0ff.tar.gz px4-firmware-57623d42ebb04f0a0b9e6eb7c0847a3ece2aa0ff.tar.bz2 px4-firmware-57623d42ebb04f0a0b9e6eb7c0847a3ece2aa0ff.zip |
Resync new repository with old repo r5166
git-svn-id: http://svn.code.sf.net/p/nuttx/code/trunk@5153 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'apps/nshlib')
27 files changed, 10973 insertions, 0 deletions
diff --git a/apps/nshlib/Kconfig b/apps/nshlib/Kconfig new file mode 100644 index 000000000..c0f7d6a92 --- /dev/null +++ b/apps/nshlib/Kconfig @@ -0,0 +1,494 @@ +# +# For a description of the syntax of this configuration file, +# see misc/tools/kconfig-language.txt. +# + +config NSH_LIBRARY + bool "NSH Library" + default n + select SYSTEM_READLINE + ---help--- + Build the NSH support library. This is used, for example, by examples/nsh + in order to implement the full NuttShell (NSH). + +if NSH_LIBRARY +config NSH_BUILTIN_APPS + bool "Enable built-in applications" + default y + depends on NAMEDAPP + ---help--- + Support external registered, "named" applications that can be + executed from the NSH command line (see apps/README.txt for + more information). This options requires support for named applications + (NAMEDAPP). + +menu "Disable Individual commands" +config NSH_DISABLE_CAT + bool "Disable cat" + default n +config NSH_DISABLE_CD + bool "Disable cd" + default n +config NSH_DISABLE_CP + bool "Disable cp" + default n +config NSH_DISABLE_DD + bool "Disable dd" + default n +config NSH_DISABLE_ECHO + bool "Disable echo" + default n +config NSH_DISABLE_EXEC + bool "Disable exec" + default n +config NSH_DISABLE_EXIT + bool "Disable exit" + default n +config NSH_DISABLE_FREE + bool "Disable free" + default n +config NSH_DISABLE_GET + bool "Disable get" + default n +config NSH_DISABLE_HELP + bool "Disable help" + default n +config NSH_DISABLE_IFCONFIG + bool "Disable ifconfig" + default n +config NSH_DISABLE_KILL + bool "Disable kill" + default n +config NSH_DISABLE_LOSETUP + bool "Disable losetup" + default n +config NSH_DISABLE_LS + bool "Disable ls" + default n +config NSH_DISABLE_MB + bool "Disable mb" + default n +config NSH_DISABLE_MKDIR + bool "Disable mkdir" + default n +config NSH_DISABLE_MKFATFS + bool "Disable mkfatfs" + default n +config NSH_DISABLE_MKFIFO + bool "Disable mkfifo" + default n +config NSH_DISABLE_MKRD + bool "Disable mkrd" + default n +config NSH_DISABLE_MH + bool "Disable mh" + default n +config NSH_DISABLE_MOUNT + bool "Disable mount" + default n +config NSH_DISABLE_MW + bool "Disable mw" + default n +config NSH_DISABLE_NSFMOUNT + bool "Disable nfsmount" + default n +config NSH_DISABLE_PS + bool "Disable ps" + default n +config NSH_DISABLE_PING + bool "Disable ping" + default n +config NSH_DISABLE_PUT + bool "Disable put" + default n +config NSH_DISABLE_PWD + bool "Disable pwd" + default n +config NSH_DISABLE_RM + bool "Disable rm" + default n +config NSH_DISABLE_RMDIR + bool "Disable rmdir" + default n +config NSH_DISABLE_SET + bool "Disable set" + default n +config NSH_DISABLE_SH + bool "Disable sh" + default n +config NSH_DISABLE_SLEEP + bool "Disable sleep" + default n +config NSH_DISABLE_TEST + bool "Disable test" + default n +config NSH_DISABLE_UMOUNT + bool "Disable umount" + default n +config NSH_DISABLE_UNSET + bool "Disable unset" + default n +config NSH_DISABLE_USLEEP + bool "Disable usleep" + default n +config NSH_DISABLE_WGET + bool "Disable wget" + default n +config NSH_DISABLE_XD + bool "Disable xd" + default n +endmenu + +config NSH_FILEIOSIZE + int "NSH I/O buffer size" + default 1024 + ---help--- + Size of a static I/O buffer used for file access (ignored if + there is no filesystem). Default is 1024. + +config NSH_STRERROR + bool "Use strerror()" + default n + depends on LIBC_STRERROR + ---help--- + strerror(errno) makes more readable output but strerror() is + very large and will not be used unless this setting is 'y' + This setting depends upon the strerror() having been enabled + with LIBC_STRERROR. + +config NSH_LINELEN + int "Max command line length" + default 80 + ---help--- + The maximum length of one command line and of one output line. + Default: 80 + +config NSH_NESTDEPTH + int "Maximum command nesting" + default 3 + ---help--- + The maximum number of nested if-then[-else]-fi sequences that + are permissable. Default: 3 + +config NSH_DISABLESCRIPT + bool "Disable script support" + default n + ---help--- + 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 NSH_DISABLEBG + bool "Disable background commands" + default n + ---help--- + 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 NSH_MMCSDMINOR + int "MMC/SD minor device number" + default 0 + ---help--- + 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 NSH_ROMFSETC + bool "Support ROMFS start-up script" + default n + depends on FS_ROMFS + ---help--- + 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. + +endif + +if NSH_ROMFSETC +config NSH_ROMFSMOUNTPT + string "ROMFS mount point" + default "/etc" + ---help--- + 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 NSH_INITSCRIPT + string "Relative path to startup script" + default "init.d/rcS" + ---help--- + 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 NSH_ROMFSDEVNO + int "ROMFS block device minor number" + default 0 + ---help--- + This is the minor number of the ROMFS block device. The default is + '0' corresponding to /dev/ram0. + +config NSH_ROMFSSECTSIZE + int "ROMFS sector size" + default 64 + ---help--- + 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. + +config NSH_FATDEVNO + int "FAT block device minor number" + default 0 + depends on FS_FAT + ---help--- + When the default rcS file used when NSH_ROMFSETC is selected, it + will mount a FAT FS under /tmp. This is the minor number of the FAT + FS block device. The default is '1' corresponding to /dev/ram1. + +config NSH_FATSECTSIZE + int "FAT sector size" + default 512 + depends on FS_FAT + ---help--- + When the default rcS file used when NSH_ROMFSETC is selected, it + will mount a FAT FS under /tmp. This is the sector size use with the + FAT FS. Default is 512. + +config NSH_FATNSECTORS + int "FAT number of sectors" + default 1024 + depends on FS_FAT + ---help--- + When the default rcS file used when NSH_ROMFSETC is selected, it + will mount a FAT FS under /tmp. This is the number of sectors to use + with the FAT FS. Defualt is 1024. The amount of memory used by the + FAT FS will be NSH_FATSECTSIZE * NSH_FATNSECTORS bytes. + +config NSH_FATMOUNTPT + string "FAT mount point" + default "/tmp" + depends on FS_FAT + ---help--- + When the default rcS file used when NSH_ROMFSETC is selected, it + will mount a FAT FS under /tmp. This is the location where the FAT + FS will be mounted. Default is "/tmp". + +endif + +if NSH_LIBRARY +config NSH_CONSOLE + bool "Use console" + default y + ---help--- + If NSH_CONSOLE is set to 'y', then a character driver + console front-end is selected (/dev/console). + + Normally, the serial console device is a UART and RS-232 + interface. However, if CONFIG_USBDEV is defined, then a USB + serial device may, instead, be used if the one of + the following are defined: + + CONFIG_PL2303 and CONFIG_PL2303_CONSOLE - Sets up the + Prolifics PL2303 emulation as a console device at /dev/console. + + CONFIG_CDCACM and CONFIG_CDCACM_CONSOLE - Sets up the + CDC/ACM serial device as a console device at dev/console. + + CONFIG_NSH_USBCONSOLE and CONFIG_NSH_USBCONDEV - Sets up the + some other USB serial device as the NSH console (not necessarily + dev/console). + +config NSH_USBCONSOLE + bool "Use a USB console" + default n + depends on NSH_CONSOLE && USBDEV + ---help--- + If defined, then the an arbitrary USB device may be used + to as the NSH console. In this case, CONFIG_NSH_USBCONDEV + must be defined to indicate which USB device to use as + the console. + +config NSH_USBCONDEV + string "USB console device" + default "/dev/ttyACM0" + depends on NSH_USBCONSOLE + ---help--- + If CONFIG_NSH_USBCONSOLE is set to 'y', then CONFIG_NSH_USBCONDEV + must also be set to select the USB device used to support + the NSH console. This should be set to the quoted name of a + readable/write-able USB driver such as: + CONFIG_NSH_USBCONDEV="/dev/ttyACM0". + +config UBSDEV_MINOR + int "USB console device minor number" + default 0 + depends on NSH_USBCONSOLE + ---help--- + If there are more than one USB devices, then a USB device + minor number may also need to be provided. Default: 0 + +menu "USB Trace Support" + depends on USBDEV && (DEBUG || USBDEV_TRACE) + +config NSH_USBDEV_TRACEINIT + bool "Show initialization events" + default n + ---help--- + Show initialization events + +config NSH_USBDEV_TRACECLASS + bool "Show class driver events" + default n + ---help--- + Show class driver events + +config NSH_USBDEV_TRACETRANSFERS + bool "Show data transfer events" + default n + ---help--- + Show data transfer events + +config NSH_USBDEV_TRACECONTROLLER + bool "Show controller events" + default n + ---help--- + Show controller events + +config NSH_USBDEV_TRACEINTERRUPTS + bool "Show interrupt-related events" + default n + ---help--- + Show interrupt-related events + +endmenu + +config NSH_CONDEV + bool "Default console device" + default "/dev/console" + depends on NSH_CONSOLE && !NSH_USBCONSOLE + ---help--- + If NSH_CONSOLE is set to 'y', then NSH_CONDEV + may also be set to select the serial device used to support + the NSH console. This should be set to the quoted name of a + readable/write-able character driver such as: + NSH_CONDEV="/dev/ttyS1". This is useful, for example, + to separate the NSH command line from the system console when + the system console is used to provide debug output. Default: + stdin and stdout (probably "/dev/console") + + NOTE: When any other device other than /dev/console is used + for a user interface, (1) linefeeds (\n) will not be expanded to + carriage return / linefeeds (\r\n). You will need to set + your terminal program to account for this. And (2) input is + not automatically echoed so you will have to turn local echo on. + +config NSH_ARCHINIT + bool "Have architecture-specific initialization" + default n + ---help--- + 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. + +config NSH_TELNET + bool "Use Telnet console" + default n + depends on NET && NET_TCP + ---help--- + If 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. + +endif + +if NSH_TELNET +config NSH_TELNETD_PORT + int "Telnet port number" + default 23 + ---help--- + The telnet daemon will listen on this TCP port number for connections. + Default: 23 + +config NSH_TELNETD_DAEMONPRIO + int "Telnet daemon priority" + default 100 + ---help--- + Priority of the Telnet daemon. Default: 100 + +config NSH_TELNETD_DAEMONSTACKSIZE + int "Telnet daemon stack size" + default 2048 + ---help--- + Stack size allocated for the Telnet daemon. Default: 2048 + +config NSH_TELNETD_CLIENTPRIO + int "Telnet client priority" + default 100 + ---help--- + Priority of the Telnet client. Default: 100 + +config NSH_TELNETD_CLIENTSTACKSIZE + int "Telnet client stack size" + default 2048 + ---help--- + Stack size allocated for the Telnet client. Default: 2048 + +config NSH_IOBUFFER_SIZE + int "Telnet I/O buffer size" + default 512 + ---help--- + Determines the size of the I/O buffer to use for sending/ + receiving TELNET commands/reponses. Default: 512 +endif + +config NSH_DHCPC + bool "Use DHCP to get IP address" + default n + depends on NSH_LIBRARY && NET && NET_UDP && NET_BROADCAST + ---help--- + Obtain the IP address via DHCP. + + 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). + +config NSH_IPADDR + hex "Target IP address" + default 0x10000002 + depends on NSH_LIBRARY && NET && !NSH_DHCPC + ---help--- + If NSH_DHCPC is NOT set, then the static IP address must be provided. + This is a 32-bit integer value in host order. So, as an example, + 0x10000002 would be 10.0.0.2. + +config NSH_DRIPADDR + hex "Router IP address" + default 0x10000001 + depends on NSH_LIBRARY && NET && !NSH_DHCPC + ---help--- + Default router IP address (aka, Gateway). This is a 32-bit integer + value in host order. So, as an example, 0x10000001 would be 10.0.0.1. + +config NSH_NETMASK + hex "Network mask" + default 0xffffff00 + depends on NSH_LIBRARY && NET && !NSH_DHCPC + ---help--- + Network mask. This is a 32-bit integer value in host order. So, as + an example, 0xffffff00 would be 255.255.255.0. + +config NSH_NOMAC + bool "Hardware has no MAC address" + default n + depends on NSH_LIBRARY && NET + ---help--- + Set if your ethernet hardware has no built-in MAC address. + If set, a bogus MAC will be assigned. diff --git a/apps/nshlib/Make.defs b/apps/nshlib/Make.defs new file mode 100644 index 000000000..2bacb5b79 --- /dev/null +++ b/apps/nshlib/Make.defs @@ -0,0 +1,40 @@ +############################################################################ +# apps/nshlib/Make.defs +# Adds selected applications to apps/ build +# +# Copyright (C) 2012 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <gnutt@nuttx.org> +# +# 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. +# +############################################################################ + +ifeq ($(CONFIG_NSH_LIBRARY),y) +CONFIGURED_APPS += nshlib +endif + diff --git a/apps/nshlib/Makefile b/apps/nshlib/Makefile new file mode 100644 index 000000000..f616374bf --- /dev/null +++ b/apps/nshlib/Makefile @@ -0,0 +1,131 @@ +############################################################################ +# apps/nshlib/Makefile +# +# Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <gnutt@nuttx.org> +# +# 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. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# NSH Library + +ASRCS = +CSRCS = nsh_init.c nsh_parse.c nsh_console.c nsh_fscmds.c nsh_ddcmd.c \ + nsh_proccmds.c nsh_mmcmds.c nsh_envcmds.c nsh_dbgcmds.c + +ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) +CSRCS += nsh_apps.c +endif + +ifeq ($(CONFIG_NSH_ROMFSETC),y) +CSRCS += nsh_romfsetc.c +endif + +ifeq ($(CONFIG_NET),y) +CSRCS += nsh_netinit.c nsh_netcmds.c +endif + +ifeq ($(CONFIG_RTC),y) +CSRCS += nsh_timcmds.c +endif + +ifneq ($(CONFIG_DISABLE_MOUNTPOINT),y) +CSRCS += nsh_mntcmds.c +endif + +ifeq ($(CONFIG_NSH_CONSOLE),y) +CSRCS += nsh_consolemain.c +endif + +ifeq ($(CONFIG_NSH_TELNET),y) +CSRCS += nsh_telnetd.c +endif + +ifneq ($(CONFIG_NSH_DISABLESCRIPT),y) +CSRCS += nsh_test.c +endif + +ifeq ($(CONFIG_USBDEV),y) +CSRCS += nsh_usbdev.c +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . +VPATH = + +# Build targets + +all: .built +.PHONY: context .depend depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) \ + $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.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..0f6aee759 --- /dev/null +++ b/apps/nshlib/README.txt @@ -0,0 +1,1170 @@ +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_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_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_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_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_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_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 date [-s "MMM DD HH:MM:SS YYYY"] + + Show or set the current date and time. This command is only supported + if the platform supported RTC hardware (CONFIG_RTC=y). + + Only one format is used both on display and when setting the date/time: + MMM DD HH:MM:SS YYYY. For example, + + data -s "Sep 1 11:30:00 2011" + + 24-hour time format is assumed. + +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 df + + Show the state of each mounted volume. + + Example: + + nsh> mount + /etc type romfs + /tmp type vfat + nsh> df + Block Number + Size Blocks Used Available Mounted on + 64 6 6 0 /etc + 512 985 2 983 /tmp + nsh> + +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 [-v] [<cmd>] + + Presents summary information about NSH commands to console. Options: + + -v + Show verbose output will full command usage + + <cmd> + Show full command usage only for this command + +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 pseudo filesystem and + must have been created by some call to register_blockdriver() (see + include/nuttx/fs/fs.h). + +o mkfifo <path> + + Creates a FIFO character device anywhere in the pseudo file system, + creating whatever pseudo 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 performs one of two different operations. If no + paramters are provided on the command line after the mount command, + then the 'mount' command will enumerate all of the current + mountpoints on the console. + + If the mount parameters are provied on the command after the 'mount' + command, then the 'mount' command will mount a file system in the + NuttX pseudo-file system. 'mount' performs a three way association, + 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 pseudo 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 pseudo file + system where the mounted volume will appear. This mount point + can only reside in the NuttX pseudo filesystem. By convention, this + mount point is a subdirectory under /mnt. The mount command will + create whatever pseudo 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 pseudo file + system, it may be access in the same way as other objects in the + file system. + + Examples: + ^^^^^^^^^ + + 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> + + nsh> mount + /etc type romfs + /tmp type vfat + /mnt/fs type vfat + +o mv <old-path> <new-path> + + Rename the file object at <old-path> to <new-path>. Both paths must + reside in the same mounted filesystem. + +o nfsmount <server-address> <mount-point> <remote-path> + + Mount the remote NFS server directory <remote-path> at <mount-point> on the target machine. + <server-address> is the IP address of the remote server. + +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_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 + df !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_READABLE (see note 3) + 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) + mv !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_WRITABLE (see note 4) + nfsmount !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NET && CONFIG_NFS + 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_NSH_DISABLESCRIPT + sleep !CONFIG_DISABLE_SIGNALS + test !CONFIG_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_NSH_DISABLE_CAT, CONFIG_NSH_DISABLE_CD, CONFIG_NSH_DISABLE_CP, + CONFIG_NSH_DISABLE_DD, CONFIG_NSH_DISABLE_DF, CONFIG_NSH_DISABLE_ECHO, + CONFIG_NSH_DISABLE_EXEC, CONFIG_NSH_DISABLE_EXIT, CONFIG_NSH_DISABLE_FREE, + CONFIG_NSH_DISABLE_GET, CONFIG_NSH_DISABLE_HELP, CONFIG_NSH_DISABLE_IFCONFIG, + CONFIG_NSH_DISABLE_KILL, CONFIG_NSH_DISABLE_LOSETUP, CONFIG_NSH_DISABLE_LS, + CONFIG_NSH_DISABLE_MB, CONFIG_NSH_DISABLE_MKDIR, CONFIG_NSH_DISABLE_MKFATFS, + CONFIG_NSH_DISABLE_MKFIFO, CONFIG_NSH_DISABLE_MKRD, CONFIG_NSH_DISABLE_MH, + CONFIG_NSH_DISABLE_MOUNT, CONFIG_NSH_DISABLE_MW, CONFIG_NSH_DISABLE_MV, + CONFIG_NSH_DISABLE_NFSMOUNT, CONFIG_NSH_DISABLE_PS, CONFIG_NSH_DISABLE_PING, + CONFIG_NSH_DISABLE_PUT, CONFIG_NSH_DISABLE_PWD, CONFIG_NSH_DISABLE_RM, + CONFIG_NSH_DISABLE_RMDIR, CONFIG_NSH_DISABLE_SET, CONFIG_NSH_DISABLE_SH, + CONFIG_NSH_DISABLE_SLEEP, CONFIG_NSH_DISABLE_TEST, CONFIG_NSH_DISABLE_UMOUNT, + CONFIG_NSH_DISABLE_UNSET, CONFIG_NSH_DISABLE_USLEEP, CONFIG_NSH_DISABLE_WGET, + CONFIG_NSH_DISABLE_XD + +Verbose help output can be suppressed by defining CONFIG_NSH_HELP_TERSE. In that +case, the help command is still available but will be slightly smaller. + +NSH-Specific Configuration Settings +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + The behavior of NSH can be modified with the following settings in + the configs/<board-name>/defconfig file: + + * CONFIG_NSH_BUILTIN_APPS + Support external registered, "named" applications that can be + executed from the NSH command line (see apps/README.txt for + more information). + + * CONFIG_NSH_FILEIOSIZE + Size of a static I/O buffer used for file access (ignored if + there is no filesystem). Default is 1024. + + * CONFIG_NSH_STRERROR + strerror(errno) makes more readable output but strerror() is + very large and will not be used unless this setting is 'y'. + This setting depends upon the strerror() having been enabled + with CONFIG_LIBC_STRERROR. + + * CONFIG_NSH_LINELEN + The maximum length of one command line and of one output line. + Default: 80 + + * CONFIG_NSH_NESTDEPTH + The maximum number of nested if-then[-else]-fi sequences that + are permissable. Default: 3 + + * CONFIG_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_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_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_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_NSH_CONSOLE + If CONFIG_NSH_CONSOLE is set to 'y', then a serial + console front-end is selected. + + Normally, the serial console device is a UART and RS-232 + interface. However, if CONFIG_USBDEV is defined, then a USB + serial device may, instead, be used if the one of + the following are defined: + + CONFIG_PL2303 and CONFIG_PL2303_CONSOLE - Sets up the + Prolifics PL2303 emulation as a console device + at /dev/console. + + CONFIG_CDCACM and CONFIG_CDCACM_CONSOLE - Sets up the + CDC/ACM serial device as a console device at + dev/console. + + CONFIG_NSH_USBCONSOLE + If defined, then the an arbitrary USB device may be used + to as the NSH console. In this case, CONFIG_NSH_USBCONDEV + must be defined to indicate which USB device to use as + the console. + + CONFIG_NSH_USBCONDEV + If CONFIG_NSH_USBCONSOLE is set to 'y', then CONFIG_NSH_USBCONDEV + must also be set to select the USB device used to support + the NSH console. This should be set to the quoted name of a + readable/write-able USB driver such as: + CONFIG_NSH_USBCONDEV="/dev/ttyACM0". + + If there are more than one USB devices, then a USB device + minor number may also need to be provided: + + CONFIG_NSH_UBSDEV_MINOR + The minor device number of the USB device. Default: 0 + + If USB tracing is enabled (CONFIG_USBDEV_TRACE), then NSH will + initialize USB tracing as requested by the following. Default: + Only USB errors are traced. + + CONFIG_NSH_USBDEV_TRACEINIT + Show initialization events + CONFIG_NSH_USBDEV_TRACECLASS + Show class driver events + CONFIG_NSH_USBDEV_TRACETRANSFERS + Show data transfer events + CONFIG_NSH_USBDEV_TRACECONTROLLER + Show controller events + CONFIG_NSH_USBDEV_TRACEINTERRUPTS + Show interrupt-related events. + + * CONFIG_NSH_CONDEV + If CONFIG_NSH_CONSOLE is set to 'y', then CONFIG_NSH_CONDEV + may also be set to select the serial device used to support + the NSH console. This should be set to the quoted name of a + readable/write-able character driver such as: + CONFIG_NSH_CONDEV="/dev/ttyS1". This is useful, for example, + to separate the NSH command line from the system console when + the system console is used to provide debug output. Default: + stdin and stdout (probably "/dev/console") + + NOTE: When any other device other than /dev/console is used + for a user interface, (1) linefeeds (\n) will not be expanded to + carriage return / linefeeds (\r\n). You will need to set + your terminal program to account for this. And (2) input is + not automatically echoed so you will have to turn local echo on. + + * CONFIG_NSH_TELNET + If CONFIG_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_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. + + If Telnet is selected for the NSH console, then we must configure + the resources used by the Telnet daemon and by the Telnet clients. + + * CONFIG_NSH_TELNETD_PORT - The telnet daemon will listen on this + TCP port number for connections. Default: 23 + + * CONFIG_NSH_TELNETD_DAEMONPRIO - Priority of the Telnet daemon. + Default: SCHED_PRIORITY_DEFAULT + + * CONFIG_NSH_TELNETD_DAEMONSTACKSIZE - Stack size allocated for the + Telnet daemon. Default: 2048 + + * CONFIG_NSH_TELNETD_CLIENTPRIO- Priority of the Telnet client. + Default: SCHED_PRIORITY_DEFAULT + + * CONFIG_NSH_TELNETD_CLIENTSTACKSIZE - Stack size allocated for the + Telnet client. Default: 2048 + + One or both of CONFIG_NSH_CONSOLE and CONFIG_NSH_TELNET + must be defined. If CONFIG_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_NSH_IOBUFFER_SIZE + Determines the size of the I/O buffer to use for sending/ + receiving TELNET commands/reponses + + * CONFIG_NSH_DHCPC + Obtain the IP address via DHCP. + + * CONFIG_NSH_IPADDR + If CONFIG_NSH_DHCPC is NOT set, then the static IP + address must be provided. + + * CONFIG_NSH_DRIPADDR + Default router IP address + + * CONFIG_NSH_NETMASK + Network mask + + * CONFIG_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_NSH_ROMFSETC is selected, then the following additional + configuration setting apply: + + * CONFIG_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_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_NSH_ROMFSDEVNO + This is the minor number of the ROMFS block device. The default is + '0' corresponding to /dev/ram0. + + * CONFIG_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_NSH_ROMFSETC is + selected, it will mount a FAT FS under /tmp. The following selections + describe that FAT FS. + + * CONFIG_NSH_FATDEVNO + This is the minor number of the FAT FS block device. The default is + '1' corresponding to /dev/ram1. + + * CONFIG_NSH_FATSECTSIZE + This is the sector size use with the FAT FS. Default is 512. + + * CONFIG_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_NSH_FATSECTSIZE * CONFIG_NSH_FATNSECTORS + bytes. + + * CONFIG_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. + + Problem: + The function 'readline' is undefined. + Usual Cause: + The following is missing from your appconfig file: + + CONFIGURED_APPS += system/readline + diff --git a/apps/nshlib/nsh.h b/apps/nshlib/nsh.h new file mode 100644 index 000000000..dac91ba05 --- /dev/null +++ b/apps/nshlib/nsh.h @@ -0,0 +1,611 @@ +/**************************************************************************** + * apps/nshlib/nsh.h + * + * Copyright (C) 2007-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 __APPS_NSHLIB_NSH_H +#define __APPS_NSHLIB_NSH_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> + +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <errno.h> + +#include <nuttx/usb/usbdev_trace.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ +/* The background commands require pthread support */ + +#ifdef CONFIG_DISABLE_PTHREAD +# ifndef CONFIG_NSH_DISABLEBG +# define CONFIG_NSH_DISABLEBG 1 +# endif +#endif + +/* Telnetd requires networking support */ + +#ifndef CONFIG_NET +# undef CONFIG_NSH_TELNET +#endif + +/* One front end must be defined */ + +#if !defined(CONFIG_NSH_CONSOLE) && !defined(CONFIG_NSH_TELNET) +# error "No NSH front end defined" +#endif + +/* If a USB device is selected for the NSH console then we need to handle some + * special start-up conditions. + */ + +#undef HAVE_USB_CONSOLE +#if defined(CONFIG_USBDEV) + +/* Check for a PL2303 serial console. Use console device "/dev/console". */ + +# if defined(CONFIG_PL2303) && defined(CONFIG_PL2303_CONSOLE) +# define HAVE_USB_CONSOLE 1 + +/* Check for a CDC/ACM serial console. Use console device "/dev/console". */ + +# elif defined(CONFIG_CDCACM) && defined(CONFIG_CDCACM_CONSOLE) +# define HAVE_USB_CONSOLE 1 + +/* Check for other USB console. USB console device must be provided in CONFIG_NSH_CONDEV */ + +# elif defined(CONFIG_NSH_USBCONSOLE) +# define HAVE_USB_CONSOLE 1 +# endif +#endif + +/* Defaults for the USB console */ + +#ifdef HAVE_USB_CONSOLE + +/* The default USB console device minor number is 0*/ + +# ifndef CONFIG_NSH_UBSDEV_MINOR +# define CONFIG_NSH_UBSDEV_MINOR 0 +# endif + +/* The default console device is always /dev/console */ + +# ifndef CONFIG_NSH_USBCONDEV +# define CONFIG_NSH_USBCONDEV "/dev/console" +# endif + +/* USB trace settings */ + +#ifdef CONFIG_NSH_USBDEV_TRACEINIT +# define TRACE_INIT_BITS (TRACE_INIT_BIT) +#else +# define TRACE_INIT_BITS (0) +#endif + +#define TRACE_ERROR_BITS (TRACE_DEVERROR_BIT|TRACE_CLSERROR_BIT) + +#ifdef CONFIG_NSH_USBDEV_TRACECLASS +# define TRACE_CLASS_BITS (TRACE_CLASS_BIT|TRACE_CLASSAPI_BIT|TRACE_CLASSSTATE_BIT) +#else +# define TRACE_CLASS_BITS (0) +#endif + +#ifdef CONFIG_NSH_USBDEV_TRACETRANSFERS +# define TRACE_TRANSFER_BITS (TRACE_OUTREQQUEUED_BIT|TRACE_INREQQUEUED_BIT|TRACE_READ_BIT|\ + TRACE_WRITE_BIT|TRACE_COMPLETE_BIT) +#else +# define TRACE_TRANSFER_BITS (0) +#endif + +#ifdef CONFIG_NSH_USBDEV_TRACECONTROLLER +# define TRACE_CONTROLLER_BITS (TRACE_EP_BIT|TRACE_DEV_BIT) +#else +# define TRACE_CONTROLLER_BITS (0) +#endif + +#ifdef CONFIG_NSH_USBDEV_TRACEINTERRUPTS +# define TRACE_INTERRUPT_BITS (TRACE_INTENTRY_BIT|TRACE_INTDECODE_BIT|TRACE_INTEXIT_BIT) +#else +# define TRACE_INTERRUPT_BITS (0) +#endif + +#define TRACE_BITSET (TRACE_INIT_BITS|TRACE_ERROR_BITS|TRACE_CLASS_BITS|\ + TRACE_TRANSFER_BITS|TRACE_CONTROLLER_BITS|TRACE_INTERRUPT_BITS) + +#endif + +/* If Telnet is selected for the NSH console, then we must configure + * the resources used by the Telnet daemon and by the Telnet clients. + * + * CONFIG_NSH_TELNETD_PORT - The telnet daemon will listen on this. + * port. Default: 23 + * CONFIG_NSH_TELNETD_DAEMONPRIO - Priority of the Telnet daemon. + * Default: SCHED_PRIORITY_DEFAULT + * CONFIG_NSH_TELNETD_DAEMONSTACKSIZE - Stack size allocated for the + * Telnet daemon. Default: 2048 + * CONFIG_NSH_TELNETD_CLIENTPRIO- Priority of the Telnet client. + * Default: SCHED_PRIORITY_DEFAULT + * CONFIG_NSH_TELNETD_CLIENTSTACKSIZE - Stack size allocated for the + * Telnet client. Default: 2048 + */ + +#ifndef CONFIG_NSH_TELNETD_PORT +# define CONFIG_NSH_TELNETD_PORT 23 +#endif + +#ifndef CONFIG_NSH_TELNETD_DAEMONPRIO +# define CONFIG_NSH_TELNETD_DAEMONPRIO SCHED_PRIORITY_DEFAULT +#endif + +#ifndef CONFIG_NSH_TELNETD_DAEMONSTACKSIZE +# define CONFIG_NSH_TELNETD_DAEMONSTACKSIZE 2048 +#endif + +#ifndef CONFIG_NSH_TELNETD_CLIENTPRIO +# define CONFIG_NSH_TELNETD_CLIENTPRIO SCHED_PRIORITY_DEFAULT +#endif + +#ifndef CONFIG_NSH_TELNETD_CLIENTSTACKSIZE +# define CONFIG_NSH_TELNETD_CLIENTSTACKSIZE 2048 +#endif + +/* Verify support for ROMFS /etc directory support options */ + +#ifdef CONFIG_NSH_ROMFSETC +# ifdef CONFIG_DISABLE_MOUNTPOINT +# error "Mountpoint support is disabled" +# undef CONFIG_NSH_ROMFSETC +# endif +# if CONFIG_NFILE_DESCRIPTORS < 4 +# error "Not enough file descriptors" +# undef CONFIG_NSH_ROMFSETC +# endif +# ifndef CONFIG_FS_ROMFS +# error "ROMFS support not enabled" +# undef CONFIG_NSH_ROMFSETC +# endif +# ifndef CONFIG_NSH_ROMFSMOUNTPT +# define CONFIG_NSH_ROMFSMOUNTPT "/etc" +# endif +# ifdef CONFIG_NSH_INIT +# ifndef CONFIG_NSH_INITSCRIPT +# define CONFIG_NSH_INITSCRIPT "init.d/rcS" +# endif +# endif +# undef NSH_INITPATH +# define NSH_INITPATH CONFIG_NSH_ROMFSMOUNTPT "/" CONFIG_NSH_INITSCRIPT +# ifndef CONFIG_NSH_ROMFSDEVNO +# define CONFIG_NSH_ROMFSDEVNO 0 +# endif +# ifndef CONFIG_NSH_ROMFSSECTSIZE +# define CONFIG_NSH_ROMFSSECTSIZE 64 +# endif +# define NSECTORS(b) (((b)+CONFIG_NSH_ROMFSSECTSIZE-1)/CONFIG_NSH_ROMFSSECTSIZE) +# define STR_RAMDEVNO(m) #m +# define MKMOUNT_DEVNAME(m) "/dev/ram" STR_RAMDEVNO(m) +# define MOUNT_DEVNAME MKMOUNT_DEVNAME(CONFIG_NSH_ROMFSDEVNO) +#else +# undef CONFIG_NSH_ROMFSMOUNTPT +# undef CONFIG_NSH_INIT +# undef CONFIG_NSH_INITSCRIPT +# undef CONFIG_NSH_ROMFSDEVNO +# undef CONFIG_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_NSH_STRERROR is defined. Note that the strerror + * interface must also have been enabled with CONFIG_LIBC_STRERROR. + */ + +#ifndef CONFIG_LIBC_STRERROR +# undef CONFIG_NSH_STRERROR +#endif + +#ifdef CONFIG_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_NSH_LINELEN +# define CONFIG_NSH_LINELEN 80 +#endif + +/* The following two settings are used only in the telnetd interface */ + +#ifndef CONFIG_NSH_IOBUFFER_SIZE +# define CONFIG_NSH_IOBUFFER_SIZE 512 +#endif + +/* The maximum number of nested if-then[-else]-fi sequences that + * are permissable. + */ + +#ifndef CONFIG_NSH_NESTDEPTH +# define CONFIG_NSH_NESTDEPTH 3 +#endif + +/* Define to enable dumping of all input/output buffers */ + +#undef CONFIG_NSH_TELNETD_DUMPBUFFER +#undef CONFIG_NSH_FULLPATH + +/* Make sure that the home directory is defined */ + +#ifndef CONFIG_LIB_HOMEDIR +# define CONFIG_LIB_HOMEDIR "/" +#endif + +/* 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 + +/* 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_NSH_FILEIOSIZE +# if CONFIG_NSH_FILEIOSIZE > (PATH_MAX + 1) +# define IOBUFFERSIZE CONFIG_NSH_FILEIOSIZE +# else +# define IOBUFFERSIZE (PATH_MAX + 1) +# endif +# else +# define IOBUFFERSIZE 1024 +# endif +# else +# define IOBUFFERSIZE (PATH_MAX + 1) +#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_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_NSH_DISABLESCRIPT + uint8_t np_ndx; /* Current index into np_st[] */ +#endif +#ifndef CONFIG_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_NSH_DISABLESCRIPT + struct nsh_state_s np_st[CONFIG_NSH_NESTDEPTH]; +#endif +}; + +struct nsh_vtbl_s; /* Defined in nsh_console.h */ +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_NSH_ROMFSETC +int nsh_romfsetc(void); +#else +# define nsh_romfsetc() (-ENOSYS) +#endif + +#ifdef CONFIG_NET +int nsh_netinit(void); +#else +# define nsh_netinit() (-ENOSYS) +#endif + +#ifdef HAVE_USB_CONSOLE +int nsh_usbconsole(void); +#else +# define nsh_usbconsole() (-ENOSYS) +#endif + +#if CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 && !defined(CONFIG_NSH_DISABLESCRIPT) +int nsh_script(FAR struct nsh_vtbl_s *vtbl, const char *cmd, const char *path); +#endif + +/* Architecture-specific initialization */ + +#ifdef CONFIG_NSH_ARCHINIT +int nsh_archinitialize(void); +#else +# define nsh_archinitialize() (-ENOSYS) +#endif + +/* Message handler */ + +int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline); + +/* Application interface */ + +#ifdef CONFIG_NSH_BUILTIN_APPS +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) +FAR const char *nsh_getcwd(void); +char *nsh_getfullpath(FAR struct nsh_vtbl_s *vtbl, const char *relpath); +void nsh_freefullpath(char *relpath); +#endif + +/* Debug */ + +void nsh_dumpbuffer(FAR struct nsh_vtbl_s *vtbl, const char *msg, + const uint8_t *buffer, ssize_t nbytes); + +/* USB debug support */ + +#if defined(CONFIG_USBDEV_TRACE) && defined(HAVE_USB_CONSOLE) +void nsh_usbtrace(void); +#else +# define nsh_usbtrace() +#endif + +/* Shell command handlers */ + +#ifndef CONFIG_NSH_DISABLE_ECHO + int cmd_echo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif +#ifndef CONFIG_NSH_DISABLE_EXEC + int cmd_exec(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif +#ifndef CONFIG_NSH_DISABLE_MB + int cmd_mb(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif +#ifndef CONFIG_NSH_DISABLE_MH + int cmd_mh(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif +#ifndef CONFIG_NSH_DISABLE_MW + int cmd_mw(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif +#ifndef CONFIG_NSH_DISABLE_FREE + int cmd_free(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif +#ifndef CONFIG_NSH_DISABLE_PS + int cmd_ps(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif +#ifndef CONFIG_NSH_DISABLE_XD + int cmd_xd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif + +#if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_NSH_DISABLE_TEST) + int cmd_test(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); + int cmd_lbracket(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif + +#ifndef CONFIG_DISABLE_CLOCK +# if defined (CONFIG_RTC) && !defined(CONFIG_NSH_DISABLE_DATE) + int cmd_date(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +#endif + +#if CONFIG_NFILE_DESCRIPTORS > 0 +# ifndef CONFIG_NSH_DISABLE_CAT + int cmd_cat(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_CP + int cmd_cp(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_DD + int cmd_dd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_LS + int cmd_ls(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# if defined(CONFIG_SYSLOG) && defined(CONFIG_RAMLOG_SYSLOG) && !defined(CONFIG_NSH_DISABLE_DMESG) + int cmd_dmesg(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# if CONFIG_NFILE_STREAMS > 0 && !defined(CONFIG_NSH_DISABLESCRIPT) +# ifndef CONFIG_NSH_DISABLE_SH + int cmd_sh(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# endif /* CONFIG_NFILE_STREAMS && !CONFIG_NSH_DISABLESCRIPT */ +# ifndef CONFIG_DISABLE_MOUNTPOINT +# ifndef CONFIG_NSH_DISABLE_LOSETUP + int cmd_losetup(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_MKFIFO + int cmd_mkfifo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifdef CONFIG_FS_READABLE +# ifndef CONFIG_NSH_DISABLE_DF + int cmd_df(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_MOUNT + int cmd_mount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_UMOUNT + int cmd_umount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifdef CONFIG_FS_WRITABLE +# ifndef CONFIG_NSH_DISABLE_MKDIR + int cmd_mkdir(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_MKRD + int cmd_mkrd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_MV + int cmd_mv(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_RM + int cmd_rm(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_RMDIR + 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_NSH_DISABLE_MKFATFS + 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_NSH_DISABLE_CD + int cmd_cd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_PWD + 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_NSH_DISABLE_IFCONFIG + 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_NSH_DISABLE_GET + int cmd_get(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_PUT + 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_NSH_DISABLE_WGET + 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_NSH_DISABLE_PING + int cmd_ping(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +#endif +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && \ + defined(CONFIG_FS_READABLE) && defined(CONFIG_NFS) +# ifndef CONFIG_NSH_DISABLE_NFSMOUNT + int cmd_nfsmount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +#endif +#endif + +#ifndef CONFIG_DISABLE_ENVIRON +# ifndef CONFIG_NSH_DISABLE_SET + int cmd_set(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_UNSET + int cmd_unset(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +#endif /* CONFIG_DISABLE_ENVIRON */ + +#ifndef CONFIG_DISABLE_SIGNALS +# ifndef CONFIG_NSH_DISABLE_KILL + int cmd_kill(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_SLEEP + int cmd_sleep(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_USLEEP + int cmd_usleep(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +#endif /* CONFIG_DISABLE_SIGNALS */ + +#endif /* __APPS_NSHLIB_NSH_H */ diff --git a/apps/nshlib/nsh_apps.c b/apps/nshlib/nsh_apps.c new file mode 100644 index 000000000..e335c2e2c --- /dev/null +++ b/apps/nshlib/nsh_apps.c @@ -0,0 +1,187 @@ +/**************************************************************************** + * apps/nshlib/nsh_apps.c + * + * Copyright (C) 2011-2012 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 <string.h> + +#include <apps/apps.h> + +#include "nsh.h" +#include "nsh_console.h" + +#ifdef CONFIG_NSH_BUILTIN_APPS + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_execapp + * + * Description: + * Attempt to execute the application task whose name is 'cmd' + * + * Returned Value: + * <0 If exec_namedapp() fails, then the negated errno value + * is returned. + * -1 (ERROR) if the application task corresponding to 'cmd' could not + * be started (possibly because it doesn not exist). + * 0 (OK) if the application task corresponding to 'cmd' was + * and successfully started. If CONFIG_SCHED_WAITPID is + * defined, this return value also indicates that the + * application returned successful status (EXIT_SUCCESS) + * 1 If CONFIG_SCHED_WAITPID is defined, then this return value + * indicates that the application task was spawned successfully + * but returned failure exit status. + * + ****************************************************************************/ + +int nsh_execapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, + FAR char **argv) +{ + int ret = OK; + + /* Lock the scheduler to prevent the application from running until the + * waitpid() has been called. + */ + + sched_lock(); + + /* Try to find and execute the command within the list of builtin + * applications. + */ + + ret = exec_namedapp(cmd, (FAR const char **)argv); + if (ret >= 0) + { + /* The application was successfully started (but still blocked because the + * scheduler is locked). If the application was not backgrounded, then we + * need to wait here for the application to exit. + */ + +#ifdef CONFIG_SCHED_WAITPID + if (vtbl->np.np_bg == false) + { + int rc = 0; + + /* Wait for the application to exit. Since we have locked the + * scheduler above, we know that the application has not yet + * started and there is no possibility that it has already exited. + * The scheduler will be unlocked while waitpid is waiting and the + * application will be able to run. + */ + + ret = waitpid(ret, &rc, 0); + if (ret >= 0) + { + /* We can't return the exact status (nsh has nowhere to put it) + * so just pass back zero/nonzero in a fashion that doesn't look + * like an error. + */ + + ret = (rc == 0) ? OK : 1; + + /* TODO: Set the environment variable '?' to a string corresponding + * to WEXITSTATUS(rc) so that $? will expand to the exit status of + * the most recently executed task. + */ + } + } + else +#endif + { + struct sched_param param; + sched_getparam(0, ¶m); + nsh_output(vtbl, "%s [%d:%d]\n", cmd, ret, param.sched_priority); + + /* Backgrounded commands always 'succeed' as long as we can start + * them. + */ + + ret = OK; + } + } + + sched_unlock(); + + /* If exec_namedapp() or waitpid() failed, then return the negated errno + * value. + */ + + if (ret < 0) + { + return -errno; + } + + return ret; +} + +#endif /* CONFIG_NSH_BUILTIN_APPS */ diff --git a/apps/nshlib/nsh_console.c b/apps/nshlib/nsh_console.c new file mode 100644 index 000000000..b066e71f5 --- /dev/null +++ b/apps/nshlib/nsh_console.c @@ -0,0 +1,432 @@ +/**************************************************************************** + * apps/nshlib/nsh_serial.c + * + * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <fcntl.h> +#include <string.h> +#include <stdarg.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include "nsh.h" +#include "nsh_console.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct serialsave_s +{ + int cn_outfd; /* Re-directed output file descriptor */ + FILE *cn_outstream; /* Re-directed output stream */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLEBG +static FAR struct nsh_vtbl_s *nsh_consoleclone(FAR struct nsh_vtbl_s *vtbl); +#endif +static void nsh_consolerelease(FAR struct nsh_vtbl_s *vtbl); +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, int exitstatus); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_openifnotopen + ****************************************************************************/ + +static int nsh_openifnotopen(struct console_stdio_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->cn_outstream) + { + pstate->cn_outstream = fdopen(pstate->cn_outfd, "w"); + if (!pstate->cn_outstream) + { + return ERROR; + } + } + return 0; +} + +/**************************************************************************** + * Name: nsh_closeifnotclosed + * + * Description: + * Close the output stream if it is not the standard output stream. + * + ****************************************************************************/ + +static void nsh_closeifnotclosed(struct console_stdio_s *pstate) +{ + if (pstate->cn_outstream == OUTSTREAM(pstate)) + { + fflush(OUTSTREAM(pstate)); + pstate->cn_outfd = OUTFD(pstate); + } + else + { + if (pstate->cn_outstream) + { + fflush(pstate->cn_outstream); + fclose(pstate->cn_outstream); + } + else if (pstate->cn_outfd >= 0 && pstate->cn_outfd != OUTFD(pstate)) + { + close(pstate->cn_outfd); + } + + pstate->cn_outfd = -1; + pstate->cn_outstream = 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 console_stdio_s *pstate = (FAR struct console_stdio_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->cn_outstream); + if (ret < 0) + { + dbg("[%d] Failed to send buffer: %d\n", pstate->cn_outfd, 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 console_stdio_s *pstate = (FAR struct console_stdio_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->cn_outstream, 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 console_stdio_s *pstate = (FAR struct console_stdio_s *)vtbl; + return pstate->cn_line; +} + +/**************************************************************************** + * Name: nsh_consoleclone + * + * Description: + * Make an independent copy of the vtbl + * + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLEBG +static FAR struct nsh_vtbl_s *nsh_consoleclone(FAR struct nsh_vtbl_s *vtbl) +{ + FAR struct console_stdio_s *pclone = nsh_newconsole(); + return &pclone->cn_vtbl; +} +#endif + +/**************************************************************************** + * Name: nsh_consolerelease + * + * Description: + * Release the cloned instance + * + ****************************************************************************/ + +static void nsh_consolerelease(FAR struct nsh_vtbl_s *vtbl) +{ + FAR struct console_stdio_s *pstate = (FAR struct console_stdio_s *)vtbl; + + /* Close the output stream */ + + nsh_closeifnotclosed(pstate); + + /* Close the console stream */ + +#ifdef CONFIG_NSH_CONDEV + (void)fclose(pstate->cn_constream); +#endif + + /* Then release the vtable container */ + + free(pstate); +} + +/**************************************************************************** + * 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 console_stdio_s *pstate = (FAR struct console_stdio_s *)vtbl; + FAR struct serialsave_s *ssave = (FAR struct serialsave_s *)save; + + /* Case 1: Redirected foreground commands */ + + if (ssave) + { + /* pstate->cn_outstream and cn_outfd refer refer to the + * currently opened output stream. If the output stream is open, flush + * any pending output. + */ + + if (pstate->cn_outstream) + { + fflush(pstate->cn_outstream); + } + + /* Save the current fd and stream values. These will be restored + * when nsh_consoleundirect() is called. + */ + + ssave->cn_outfd = pstate->cn_outfd; + ssave->cn_outstream = pstate->cn_outstream; + } + else + { + /* nsh_consoleclone() set pstate->cn_outfd and cn_outstream 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->cn_outfd = fd; + pstate->cn_outstream = 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 console_stdio_s *pstate = (FAR struct console_stdio_s *)vtbl; + FAR struct serialsave_s *ssave = (FAR struct serialsave_s *)save; + + nsh_closeifnotclosed(pstate); + pstate->cn_outfd = ssave->cn_outfd; + pstate->cn_outstream = ssave->cn_outstream; +} + +/**************************************************************************** + * Name: nsh_consoleexit + * + * Description: + * Exit the shell task + * + ****************************************************************************/ + +static void nsh_consoleexit(FAR struct nsh_vtbl_s *vtbl, int exitstatus) +{ + /* Destroy ourself then exit with the provided status */ + + nsh_consolerelease(vtbl); + exit(exitstatus); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_newconsole + ****************************************************************************/ + +FAR struct console_stdio_s *nsh_newconsole(void) +{ + struct console_stdio_s *pstate = (struct console_stdio_s *)zalloc(sizeof(struct console_stdio_s)); + if (pstate) + { + /* Initialize the call table */ + +#ifndef CONFIG_NSH_DISABLEBG + pstate->cn_vtbl.clone = nsh_consoleclone; + pstate->cn_vtbl.release = nsh_consolerelease; +#endif + pstate->cn_vtbl.write = nsh_consolewrite; + pstate->cn_vtbl.output = nsh_consoleoutput; + pstate->cn_vtbl.linebuffer = nsh_consolelinebuffer; + pstate->cn_vtbl.redirect = nsh_consoleredirect; + pstate->cn_vtbl.undirect = nsh_consoleundirect; + pstate->cn_vtbl.exit = nsh_consoleexit; + + /* (Re-) open the console input device */ + +#ifdef CONFIG_NSH_CONDEV + pstate->cn_confd = open(CONFIG_NSH_CONDEV, O_RDWR); + if (pstate->cn_confd < 0) + { + free(pstate); + return NULL; + } + + /* Create a standard C stream on the console device */ + + pstate->cn_constream = fdopen(pstate->cn_confd, "r+"); + if (!pstate->cn_constream) + { + close(pstate->cn_confd); + free(pstate); + return NULL; + } +#endif + + /* Initialize the output stream */ + + pstate->cn_outfd = OUTFD(pstate); + pstate->cn_outstream = OUTSTREAM(pstate); + } + return pstate; +} diff --git a/apps/nshlib/nsh_console.h b/apps/nshlib/nsh_console.h new file mode 100644 index 000000000..53e8c7897 --- /dev/null +++ b/apps/nshlib/nsh_console.h @@ -0,0 +1,159 @@ +/**************************************************************************** + * apps/nshlib/nsh_console.h + * + * Copyright (C) 2007-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 __APPS_NSHLIB_NSH_CONSOLE_H +#define __APPS_NSHLIB_NSH_CONSOLE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> + +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <errno.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ +/* 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,s) (v)->exit(v,s) + +#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)) + +/* Are we using the NuttX console for I/O? Or some other character device? */ + +#ifdef CONFIG_NSH_CONDEV +# define INFD(p) ((p)->cn_confd) +# define INSTREAM(p) ((p)->cn_constream) +# define OUTFD(p) ((p)->cn_confd) +# define OUTSTREAM(p) ((p)->cn_constream) +#else +# define INFD(p) 0 +# define INSTREAM(p) stdin +# define OUTFD(p) 1 +# define OUTSTREAM(p) stdout +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ +/* This describes a generic console front-end */ + +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_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, int exitstatus); + + /* Parser state data */ + + struct nsh_parser_s np; +}; + +/* This structure describes a console front-end that is based on stdin and + * stdout (which is all of the supported console types at the time being). + */ + +struct console_stdio_s +{ + /* NSH front-end call table */ + + struct nsh_vtbl_s cn_vtbl; + + /* NSH input/output streams */ + +#ifdef CONFIG_NSH_CONDEV + int cn_confd; /* Console I/O file descriptor */ +#endif + int cn_outfd; /* Output file descriptor (possibly redirected) */ +#ifdef CONFIG_NSH_CONDEV + FILE *cn_constream; /* Console I/O stream (possibly redirected) */ +#endif + FILE *cn_outstream; /* Output stream */ + + /* Line input buffer */ + + char cn_line[CONFIG_NSH_LINELEN]; +}; + + + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* Defined in nsh_console.c *************************************************/ + +FAR struct console_stdio_s *nsh_newconsole(void); + +#endif /* __APPS_NSHLIB_NSH_CONSOLE_H */ diff --git a/apps/nshlib/nsh_consolemain.c b/apps/nshlib/nsh_consolemain.c new file mode 100644 index 000000000..6b51be470 --- /dev/null +++ b/apps/nshlib/nsh_consolemain.c @@ -0,0 +1,170 @@ +/**************************************************************************** + * apps/nshlib/nsh_consolemain.c + * + * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <stdio.h> +#include <assert.h> + +#include <apps/readline.h> + +#include "nsh.h" +#include "nsh_console.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_consolemain + * + * Description: + * This interfaces maybe to called or started with task_start to start a + * single an NSH instance that operates on stdin and stdout (/dev/console). + * This function does not return. + * + * Input Parameters: + * Standard task start-up arguements. These are not used. argc may be + * zero and argv may be NULL. + * + * Returned Values: + * This function does not normally return. exit() is usually called to + * terminate the NSH session. This function will return in the event of + * an error. In that case, a nonzero value is returned (1). + * + ****************************************************************************/ + +int nsh_consolemain(int argc, char *argv[]) +{ + FAR struct console_stdio_s *pstate = nsh_newconsole(); + int ret; + + DEBUGASSERT(pstate); + + /* If we are using a USB serial console, then we will have to wait for the + * USB to be connected to the host. + */ + +#ifdef HAVE_USB_CONSOLE + ret = nsh_usbconsole(); + DEBUGASSERT(ret == OK); +#endif + + /* Present a greeting */ + + fputs(g_nshgreeting, pstate->cn_outstream); + fflush(pstate->cn_outstream); + + /* Execute the startup script */ + +#ifdef CONFIG_NSH_ROMFSETC + (void)nsh_script(&pstate->cn_vtbl, "init", NSH_INITPATH); +#endif + + /* Then enter the command line parsing loop */ + + for (;;) + { + /* For the case of debugging the USB console... dump collected USB trace data */ + + nsh_usbtrace(); + + /* Display the prompt string */ + + fputs(g_nshprompt, pstate->cn_outstream); + fflush(pstate->cn_outstream); + + /* Get the next line of input */ + + ret = readline(pstate->cn_line, CONFIG_NSH_LINELEN, + INSTREAM(pstate), OUTSTREAM(pstate)); + if (ret > 0) + { + /* Parse process the command */ + + (void)nsh_parse(&pstate->cn_vtbl, pstate->cn_line); + fflush(pstate->cn_outstream); + } + + /* Readline normally returns the number of characters read, + * but will return 0 on end of file or a negative value + * if an error occurs. Either will cause the session to + * terminate. + */ + + else + { + fprintf(pstate->cn_outstream, g_fmtcmdfailed, "nsh_consolemain", + "readline", NSH_ERRNO_OF(-ret)); + nsh_exit(&pstate->cn_vtbl, 1); + } + } + + /* Clean up */ + + nsh_exit(&pstate->cn_vtbl, 0); + + /* We do not get here, but this is necessary to keep some compilers happy */ + + return OK; +} diff --git a/apps/nshlib/nsh_dbgcmds.c b/apps/nshlib/nsh_dbgcmds.c new file mode 100644 index 000000000..384b377f3 --- /dev/null +++ b/apps/nshlib/nsh_dbgcmds.c @@ -0,0 +1,355 @@ +/**************************************************************************** + * apps/nshlib/dbg_dbgcmds.c + * + * Copyright (C) 2008-2009, 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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" +#include "nsh_console.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*)((uintptr_t)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_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_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_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_NSH_DISABLE_XD +int cmd_xd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + FAR char *addr; + FAR char *endptr; + int nbytes; + + addr = (char*)((uintptr_t)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..40a3710b1 --- /dev/null +++ b/apps/nshlib/nsh_ddcmd.c @@ -0,0 +1,643 @@ +/**************************************************************************** + * apps/nshlib/nsh_ddcmd.c + * + * Copyright (C) 2008-2009, 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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/fs.h> + +#include "nsh.h" +#include "nsh_console.h" + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_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) + { + 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_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_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_NSH_DISABLE_DD */ + diff --git a/apps/nshlib/nsh_envcmds.c b/apps/nshlib/nsh_envcmds.c new file mode 100644 index 000000000..07b775517 --- /dev/null +++ b/apps/nshlib/nsh_envcmds.c @@ -0,0 +1,338 @@ +/**************************************************************************** + * apps/nshlib/nsh_envcmds.c + * + * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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" +#include "nsh_console.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_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 */ + + ret = chdir(path); + if (ret != 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_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_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_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_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..1a9f2eb57 --- /dev/null +++ b/apps/nshlib/nsh_fscmds.c @@ -0,0 +1,1299 @@ +/**************************************************************************** + * apps/nshlib/nsh_fscmds.c + * + * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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/fs/mkfatfs.h> +# endif +# ifdef CONFIG_NFS +# include <sys/socket.h> +# include <netinet/in.h> +# include <nuttx/fs/nfs.h> +# endif +# ifdef CONFIG_RAMLOG_SYSLOG +# include <nuttx/ramlog.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" +#include "nsh_console.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define LSFLAGS_SIZE 1 +#define LSFLAGS_LONG 2 +#define LSFLAGS_RECURSIVE 4 + +/**************************************************************************** + * 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_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_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 + +/**************************************************************************** + * Name: cat_common + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 +#ifndef CONFIG_NSH_DISABLE_CAT +static int cat_common(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, + FAR const char *filename) +{ + char buffer[IOBUFFERSIZE]; + int fd; + int ret = OK; + + /* Open the file for reading */ + + fd = open(filename, O_RDONLY); + if (fd < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, cmd, "open", NSH_ERRNO); + return ERROR; + } + + /* And just dump it byte for byte into stdout */ + + for (;;) + { + int nbytesread = read(fd, buffer, IOBUFFERSIZE); + + /* Check for read errors */ + + if (nbytesread < 0) + { + int errval = errno; + + /* EINTR is not an error (but will stop stop the cat) */ + +#ifndef CONFIG_DISABLE_SIGNALS + if (errval == EINTR) + { + nsh_output(vtbl, g_fmtsignalrecvd, cmd); + } + else +#endif + { + nsh_output(vtbl, g_fmtcmdfailed, cmd, "read", NSH_ERRNO_OF(errval)); + } + + 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) + { + int errval = errno; + + /* EINTR is not an error (but will stop stop the cat) */ + + #ifndef CONFIG_DISABLE_SIGNALS + if (errval == EINTR) + { + nsh_output(vtbl, g_fmtsignalrecvd, cmd); + } + else +#endif + { + nsh_output(vtbl, g_fmtcmdfailed, cmd, "write", NSH_ERRNO); + } + + ret = ERROR; + break; + } + else + { + nbyteswritten += n; + } + } + } + + /* Otherwise, it is the end of file */ + + else + { + break; + } + } + + (void)close(fd); + return ret; +} +#endif +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cmd_cat + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 +#ifndef CONFIG_NSH_DISABLE_CAT +int cmd_cat(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *fullpath; + 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) + { + ret = ERROR; + } + else + { + /* Dump the file to the console */ + + ret = cat_common(vtbl, argv[0], fullpath); + + /* Free the allocated full path */ + + nsh_freefullpath(fullpath); + } + } + + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_dmesg + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_SYSLOG) && \ + defined(CONFIG_RAMLOG_SYSLOG) && !defined(CONFIG_NSH_DISABLE_DMESG) +int cmd_dmesg(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + return cat_common(vtbl, argv[0], CONFIG_SYSLOG_DEVPATH); +} +#endif + +/**************************************************************************** + * Name: cmd_cp + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 +#ifndef CONFIG_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_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_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_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_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_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_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 mkrd 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_mv + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE) +#ifndef CONFIG_NSH_DISABLE_MV +int cmd_mv(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *oldpath; + char *newpath; + int ret; + + /* Get the full path to the old and new file paths */ + + oldpath = nsh_getfullpath(vtbl, argv[1]); + if (!oldpath) + { + return ERROR; + } + + newpath = nsh_getfullpath(vtbl, argv[2]); + if (!newpath) + { + nsh_freefullpath(newpath); + return ERROR; + } + + /* Perform the mount */ + + ret = rename(oldpath, newpath); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "rename", NSH_ERRNO); + } + + /* Free the file paths */ + + nsh_freefullpath(oldpath); + nsh_freefullpath(newpath); + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_rm + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE) +#ifndef CONFIG_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_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_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_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_NSH_DISABLESCRIPT) +#ifndef CONFIG_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 diff --git a/apps/nshlib/nsh_init.c b/apps/nshlib/nsh_init.c new file mode 100644 index 000000000..7c7e78ea1 --- /dev/null +++ b/apps/nshlib/nsh_init.c @@ -0,0 +1,102 @@ +/**************************************************************************** + * apps/nshlib/nsh_init.c + * + * Copyright (C) 2007-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 "nsh.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_initialize + * + * Description: + * This nterfaces is used to initialize the NuttShell (NSH). + * nsh_initialize() should be called one during application start-up prior + * to executing either nsh_consolemain() or nsh_telnetstart(). + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +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(); +} + diff --git a/apps/nshlib/nsh_mmcmds.c b/apps/nshlib/nsh_mmcmds.c new file mode 100644 index 000000000..545ae60ad --- /dev/null +++ b/apps/nshlib/nsh_mmcmds.c @@ -0,0 +1,96 @@ +/**************************************************************************** + * apps/nshlib/nsh_mmcmds.c + * + * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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" +#include "nsh_console.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cmd_free + ****************************************************************************/ + +#ifndef CONFIG_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 /* !CONFIG_NSH_DISABLE_FREE */ diff --git a/apps/nshlib/nsh_mntcmds.c b/apps/nshlib/nsh_mntcmds.c new file mode 100644 index 000000000..690d027ca --- /dev/null +++ b/apps/nshlib/nsh_mntcmds.c @@ -0,0 +1,434 @@ +/**************************************************************************** + * apps/nshlib/nsh_mntcmds.c + * + * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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/mount.h> +#include <sys/statfs.h> + +#include <stdint.h> +#include <stdbool.h> +#include <unistd.h> +#include <errno.h> +#include <debug.h> + +#include "nsh.h" +#include "nsh_console.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: df_handler + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) && \ + defined(CONFIG_FS_READABLE) && !defined(CONFIG_NSH_DISABLE_MOUNT) +static int df_handler(FAR const char *mountpoint, + FAR struct statfs *statbuf, FAR void *arg) +{ + FAR struct nsh_vtbl_s *vtbl = (FAR struct nsh_vtbl_s *)arg; + + DEBUGASSERT(mountpoint && statbuf && vtbl); + + nsh_output(vtbl, "%6ld %8ld %8ld %8ld %s\n", + statbuf->f_bsize, statbuf->f_blocks, + statbuf->f_blocks - statbuf->f_bavail, statbuf->f_bavail, + mountpoint); + + return OK; +} +#endif + +/**************************************************************************** + * Name: mount_handler + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) && \ + defined(CONFIG_FS_READABLE) && !defined(CONFIG_NSH_DISABLE_MOUNT) +static int mount_handler(FAR const char *mountpoint, + FAR struct statfs *statbuf, FAR void *arg) +{ + FAR struct nsh_vtbl_s *vtbl = (FAR struct nsh_vtbl_s *)arg; + FAR const char *fstype; + + DEBUGASSERT(mountpoint && statbuf && vtbl); + + /* Get the file system type */ + + switch (statbuf->f_type) + { +#ifdef CONFIG_FS_FAT + case MSDOS_SUPER_MAGIC: + fstype = "vfat"; + break; +#endif + +#ifdef CONFIG_FS_ROMFS + case ROMFS_MAGIC: + fstype = "romfs"; + break; +#endif + +#ifdef CONFIG_APPS_BINDIR + case BINFS_MAGIC: + fstype = "bindir"; + break; +#endif + +#ifdef CONFIG_FS_NXFFS + case NXFFS_MAGIC: + fstype = "nxffs"; + break; +#endif + +#ifdef CONFIG_NFS + case NFS_SUPER_MAGIC: + fstype = "nfs"; + break; +#endif + + default: + fstype = "Unrecognized"; + break; + } + + nsh_output(vtbl, " %s type %s\n", mountpoint, fstype); + return OK; +} +#endif + +/**************************************************************************** + * Name: mount_show + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) && \ + defined(CONFIG_FS_READABLE) && !defined(CONFIG_NSH_DISABLE_MOUNT) +static inline int mount_show(FAR struct nsh_vtbl_s *vtbl, FAR const char *progname) +{ + return foreach_mountpoint(mount_handler, (FAR void *)vtbl); +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cmd_df + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) && \ + defined(CONFIG_FS_READABLE) && !defined(CONFIG_NSH_DISABLE_DF) +int cmd_df(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + nsh_output(vtbl, " Block Number\n"); + nsh_output(vtbl, " Size Blocks Used Available Mounted on\n"); + + return foreach_mountpoint(df_handler, (FAR void *)vtbl); +} +#endif + +/**************************************************************************** + * Name: cmd_mount + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) && \ + defined(CONFIG_FS_READABLE) && !defined(CONFIG_NSH_DISABLE_MOUNT) +int cmd_mount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + FAR char *source; + FAR char *target; + FAR char *filesystem = NULL; + bool badarg = false; + int option; + int ret; + + /* The mount command behaves differently if no parameters are provided */ + + if (argc < 2) + { + return mount_show(vtbl, argv[0]); + } + + /* Get the mount options. NOTE: getopt() is not thread safe nor re-entrant. + * To keep its state proper for the next usage, it is necessary to parse to + * the end of the line even if an error occurs. If an error occurs, this + * logic just sets 'badarg' and continues. + */ + + 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: the source and target + * paths. + */ + + 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; + } + + /* While the above parsing for the -t argument looks nice, the -t argument + * not really optional. + */ + + if (!filesystem) + { + nsh_output(vtbl, g_fmtargrequired, argv[0]); + return ERROR; + } + + /* The source and target paths 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 (!target) + { + 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 + +/**************************************************************************** + * Name: cmd_nfsmount + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) && \ + defined(CONFIG_NET) && defined(CONFIG_NFS) && !defined(CONFIG_NSH_DISABLE_NFSMOUNT) +int cmd_nfsmount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + struct nfs_args data; + FAR char *address; + FAR char *lpath; + FAR char *rpath; + bool badarg = false; +#ifdef CONFIG_NET_IPv6 + FAR struct sockaddr_in6 *sin; + struct in6_addr inaddr; +#else + FAR struct sockaddr_in *sin; + struct in_addr inaddr; +#endif + int ret; + + /* If a bad argument was encountered, then return without processing the + * command. + */ + + if (badarg) + { + return ERROR; + } + + /* The fist argument on the command line should be the NFS server IP address + * in standard IPv4 (or IPv6) dot format. + */ + + address = argv[1]; + if (!address) + { + return ERROR; + } + + /* The local mount point path (lpath) might be relative to the current working + * directory. + */ + + lpath = nsh_getfullpath(vtbl, argv[2]); + if (!lpath) + { + return ERROR; + } + + /* Get the remote mount point path */ + + rpath = argv[3]; + + /* Convert the IP address string into its binary form */ + +#ifdef CONFIG_NET_IPv6 + ret = inet_pton(AF_INET6, address, &inaddr); +#else + ret = inet_pton(AF_INET, address, &inaddr); +#endif + if (ret != 1) + { + nsh_freefullpath(lpath); + return ERROR; + } + + /* Place all of the NFS arguements into the nfs_args structure */ + + memset(&data, 0, sizeof(data)); + +#ifdef CONFIG_NET_IPv6 + sin = (FAR struct sockaddr_in6 *)&data.addr; + sin->sin_family = AF_INET6; + sin->sin_port = htons(NFS_PMAPPORT); + memcpy(&sin->sin6_addr, &inaddr, sizeof(struct in6_addr)); + data.addrlen = sizeof(struct sockaddr_in6); +#else + sin = (FAR struct sockaddr_in *)&data.addr; + sin->sin_family = AF_INET; + sin->sin_port = htons(NFS_PMAPPORT); + sin->sin_addr = inaddr; + data.addrlen = sizeof(struct sockaddr_in); +#endif + + data.sotype = SOCK_DGRAM; + data.path = rpath; + data.flags = 0; /* 0=Use all defaults */ + + /* Perform the mount */ + + ret = mount(NULL, lpath, "nfs", 0, (FAR void *)&data); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mount", NSH_ERRNO); + } + + /* We no longer need the allocated mount point path */ + + nsh_freefullpath(lpath); + return ret; +} +#endif + +/**************************************************************************** + * Name: cmd_umount + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) && \ + defined(CONFIG_FS_READABLE) && !defined(CONFIG_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 diff --git a/apps/nshlib/nsh_netcmds.c b/apps/nshlib/nsh_netcmds.c new file mode 100644 index 000000000..cfea5a08a --- /dev/null +++ b/apps/nshlib/nsh_netcmds.c @@ -0,0 +1,864 @@ +/**************************************************************************** + * apps/nshlib/nsh_netcmds.c + * + * Copyright (C) 2007-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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/net.h> +#include <nuttx/clock.h> +#include <net/ethernet.h> +#include <nuttx/net/uip/uip.h> +#include <nuttx/net/uip/uip-arch.h> +#include <netinet/ether.h> + +#ifdef CONFIG_NET_STATISTICS +# include <nuttx/net/uip/uip.h> +#endif + +#if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \ + !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_DISABLE_SIGNALS) +# include <apps/netutils/uiplib.h> +#endif + +#if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 +# include <apps/netutils/uiplib.h> +# include <apps/netutils/tftp.h> +#endif + +#if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0 +# ifndef CONFIG_NSH_DISABLE_WGET +# include <apps/netutils/uiplib.h> +# include <apps/netutils/webclient.h> +# endif +#endif + +#include "nsh.h" +#include "nsh_console.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_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 one parameter left on the command-line */ + + if (optind == argc-1) + { + args->srcpath = argv[optind]; + } + + /* optind == argc means that there is nothing left on the command-line */ + + else if (optind >= argc) + { + fmt = g_fmtargrequired; + goto errout; + } + + /* optind < argc-1 means that there are too many arguments on the + * command-line + */ + + else + { + fmt = g_fmttoomanyargs; + 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_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_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_NSH_DISABLE_IFCONFIG +int cmd_ifconfig(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + struct in_addr addr; + in_addr_t ip; + + /* With one or no arguments, ifconfig simply shows the status of ethernet + * device: + * + * ifconfig + * ifconfig [nic_name] + */ + + if (argc <= 2) + { + netdev_foreach(ifconfig_callback, vtbl); + uip_statistics(vtbl); + return OK; + } + + /* If both the network interface name and an IP address are supplied as + * arguments, then ifconfig will set the address of the ethernet device: + * + * ifconfig nic_name ip_address + */ + + /* Set host ip address */ + + ip = addr.s_addr = inet_addr(argv[2]); + uip_sethostaddr(argv[1], &addr); + + /* Set gateway */ + + ip = NTOHL(ip); + ip &= ~0x000000ff; + ip |= 0x00000001; + + addr.s_addr = HTONL(ip); + uip_setdraddr(argv[1], &addr); + + /* Set netmask */ + + addr.s_addr = inet_addr("255.255.255.0"); + uip_setnetmask(argv[1], &addr); + + 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_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_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_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..bc845c4ed --- /dev/null +++ b/apps/nshlib/nsh_netinit.c @@ -0,0 +1,171 @@ +/**************************************************************************** + * apps/nshlib/nsh_netinit.c + * + * Copyright (C) 2010-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <apps/netutils/uiplib.h> +#if defined(CONFIG_NSH_DHCPC) +# include <apps/netutils/resolv.h> +# include <apps/netutils/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_NSH_DHCPC) + FAR void *handle; +#endif +#if defined(CONFIG_NSH_DHCPC) || defined(CONFIG_NSH_NOMAC) + uint8_t mac[IFHWADDRLEN]; +#endif + +/* Many embedded network interfaces must have a software assigned MAC */ + +#ifdef CONFIG_NSH_NOMAC + mac[0] = 0x00; + mac[1] = 0xe0; + mac[2] = 0xde; + mac[3] = 0xad; + mac[4] = 0xbe; + mac[5] = 0xef; + uip_setmacaddr("eth0", mac); +#endif + + /* Set up our host address */ + +#if !defined(CONFIG_NSH_DHCPC) + addr.s_addr = HTONL(CONFIG_NSH_IPADDR); +#else + addr.s_addr = 0; +#endif + uip_sethostaddr("eth0", &addr); + + /* Set up the default router address */ + + addr.s_addr = HTONL(CONFIG_NSH_DRIPADDR); + uip_setdraddr("eth0", &addr); + + /* Setup the subnet mask */ + + addr.s_addr = HTONL(CONFIG_NSH_NETMASK); + uip_setnetmask("eth0", &addr); + +#if defined(CONFIG_NSH_DHCPC) + /* Set up the resolver */ + + resolv_init(); +#endif + +#if defined(CONFIG_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_parse.c b/apps/nshlib/nsh_parse.c new file mode 100644 index 000000000..ba597a062 --- /dev/null +++ b/apps/nshlib/nsh_parse.c @@ -0,0 +1,1550 @@ +/**************************************************************************** + * apps/nshlib/nsh_parse.c + * + * Copyright (C) 2007-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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> + +#include <nuttx/version.h> + +#ifndef CONFIG_NSH_DISABLEBG +# include <pthread.h> +#endif + +#ifdef CONFIG_NSH_BUILTIN_APPS +# include <apps/apps.h> +#endif +#include <apps/nsh.h> + +#include "nsh.h" +#include "nsh_console.h" + +/**************************************************************************** + * Pre-processor 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_NSH_DISABLEBG +# define MAX_ARGV_ENTRIES (NSH_MAX_ARGUMENTS+5) +#else +# define MAX_ARGV_ENTRIES (NSH_MAX_ARGUMENTS+4) +#endif + +/* Help command summary layout */ + +#define MAX_CMDLEN 12 +#define CMDS_PER_LINE 6 + +#define NUM_CMDS ((sizeof(g_cmdmap)/sizeof(struct cmdmap_s)) - 1) +#define NUM_CMD_ROWS ((NUM_CMDS + (CMDS_PER_LINE-1)) / CMDS_PER_LINE) + +/**************************************************************************** + * 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_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_NSH_DISABLE_HELP +static int cmd_help(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif + +#ifndef CONFIG_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_NSH_DISABLESCRIPT) && !defined(CONFIG_NSH_DISABLE_TEST) + { "[", cmd_lbracket, 4, NSH_MAX_ARGUMENTS, "<expression> ]" }, +#endif + +#ifndef CONFIG_NSH_DISABLE_HELP + { "?", cmd_help, 1, 1, NULL }, +#endif + +#if CONFIG_NFILE_DESCRIPTORS > 0 +# ifndef CONFIG_NSH_DISABLE_CAT + { "cat", cmd_cat, 2, NSH_MAX_ARGUMENTS, "<path> [<path> [<path> ...]]" }, +# endif +#ifndef CONFIG_DISABLE_ENVIRON +# ifndef CONFIG_NSH_DISABLE_CD + { "cd", cmd_cd, 1, 2, "[<dir-path>|-|~|..]" }, +# endif +#endif +# ifndef CONFIG_NSH_DISABLE_CP + { "cp", cmd_cp, 3, 3, "<source-path> <dest-path>" }, +# endif +#endif + +#if defined (CONFIG_RTC) && !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_NSH_DISABLE_DATE) + { "date", cmd_date, 1, 3, "[-s \"MMM DD HH:MM:SS YYYY\"]" }, +#endif + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_NSH_DISABLE_DD) + { "dd", cmd_dd, 3, 6, "if=<infile> of=<outfile> [bs=<sectsize>] [count=<sectors>] [skip=<sectors>]" }, +# endif + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) && \ + defined(CONFIG_FS_READABLE) && !defined(CONFIG_NSH_DISABLE_DF) + { "df", cmd_df, 1, 1, NULL }, +#endif + +#if CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_SYSLOG) && \ + defined(CONFIG_RAMLOG_SYSLOG) && !defined(CONFIG_NSH_DISABLE_DMESG) + { "dmesg", cmd_dmesg, 1, 1, NULL }, +#endif + +#ifndef CONFIG_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_NSH_DISABLE_EXEC + { "exec", cmd_exec, 2, 3, "<hex-address>" }, +#endif +#ifndef CONFIG_NSH_DISABLE_EXIT + { "exit", cmd_exit, 1, 1, NULL }, +#endif + +#ifndef CONFIG_NSH_DISABLE_FREE + { "free", cmd_free, 1, 1, NULL }, +#endif + +#if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 +# ifndef CONFIG_NSH_DISABLE_GET + { "get", cmd_get, 4, 7, "[-b|-n] [-f <local-path>] -h <ip-address> <remote-path>" }, +# endif +#endif + +#ifndef CONFIG_NSH_DISABLE_HELP +# ifdef CONFIG_NSH_HELP_TERSE + { "help", cmd_help, 1, 2, "[<cmd>]" }, +#else + { "help", cmd_help, 1, 3, "[-v] [<cmd>]" }, +# endif +#endif + +#ifdef CONFIG_NET +# ifndef CONFIG_NSH_DISABLE_IFCONFIG + { "ifconfig", cmd_ifconfig, 1, 3, "[nic_name [ip]]" }, +# endif +#endif + +#ifndef CONFIG_DISABLE_SIGNALS +# ifndef CONFIG_NSH_DISABLE_KILL + { "kill", cmd_kill, 3, 3, "-<signal> <pid>" }, +# endif +#endif + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) +# ifndef CONFIG_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_NSH_DISABLE_LS + { "ls", cmd_ls, 1, 5, "[-lRs] <dir-path>" }, +# endif +#endif + +#ifndef CONFIG_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_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_NSH_DISABLE_MKFATFS + { "mkfatfs", cmd_mkfatfs, 2, 2, "<path>" }, +# endif +#endif + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 +# ifndef CONFIG_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_NSH_DISABLE_MKRD + { "mkrd", cmd_mkrd, 2, 6, "[-m <minor>] [-s <sector-size>] <nsectors>" }, +# endif +#endif + +#ifndef CONFIG_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_NSH_DISABLE_MOUNT + { "mount", cmd_mount, 1, 5, "[-t <fstype> <block-device> <mount-point>]" }, +# endif +#endif + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE) +# ifndef CONFIG_NSH_DISABLE_MV + { "mv", cmd_mv, 3, 3, "<old-path> <new-path>" }, +# endif +#endif + +#ifndef CONFIG_NSH_DISABLE_MW + { "mw", cmd_mw, 2, 3, "<hex-address>[=<hex-value>][ <hex-byte-count>]" }, +#endif + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && \ + defined(CONFIG_NET) && defined(CONFIG_NFS) +# ifndef CONFIG_NSH_DISABLE_NFSMOUNT + { "nfsmount", cmd_nfsmount, 4, 4, "<server-address> <mount-point> <remote-path>" }, +# endif +#endif + +#if defined(CONFIG_NET) && defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \ + !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_DISABLE_SIGNALS) +# ifndef CONFIG_NSH_DISABLE_PING + { "ping", cmd_ping, 2, 6, "[-c <count>] [-i <interval>] <ip-address>" }, +# endif +#endif + +#ifndef CONFIG_NSH_DISABLE_PS + { "ps", cmd_ps, 1, 1, NULL }, +#endif + +#if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 +# ifndef CONFIG_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_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_NSH_DISABLE_RM + { "rm", cmd_rm, 2, 2, "<file-path>" }, +# endif +# ifndef CONFIG_NSH_DISABLE_RMDIR + { "rmdir", cmd_rmdir, 2, 2, "<dir-path>" }, +# endif +#endif + +#ifndef CONFIG_DISABLE_ENVIRON +# ifndef CONFIG_NSH_DISABLE_SET + { "set", cmd_set, 3, 3, "<name> <value>" }, +# endif +#endif + +#if CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 && !defined(CONFIG_NSH_DISABLESCRIPT) +# ifndef CONFIG_NSH_DISABLE_SH + { "sh", cmd_sh, 2, 2, "<script-path>" }, +# endif +#endif + +#ifndef CONFIG_DISABLE_SIGNALS +# ifndef CONFIG_NSH_DISABLE_SLEEP + { "sleep", cmd_sleep, 2, 2, "<sec>" }, +# endif +#endif + +#if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_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_NSH_DISABLE_UMOUNT + { "umount", cmd_umount, 2, 2, "<dir-path>" }, +# endif +#endif + +#ifndef CONFIG_DISABLE_ENVIRON +# ifndef CONFIG_NSH_DISABLE_UNSET + { "unset", cmd_unset, 2, 2, "<name>" }, +# endif +#endif + +#ifndef CONFIG_DISABLE_SIGNALS +# ifndef CONFIG_NSH_DISABLE_USLEEP + { "usleep", cmd_usleep, 2, 2, "<usec>" }, +# endif +#endif + +#if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0 +# ifndef CONFIG_NSH_DISABLE_WGET + { "wget", cmd_wget, 2, 4, "[-o <local-path>] <url>" }, +# endif +#endif + +#ifndef CONFIG_NSH_DISABLE_XD + { "xd", cmd_xd, 3, 3, "<hex-address> <byte-count>" }, +#endif + { NULL, NULL, 1, 1, NULL } +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* If NuttX versioning information is available, Include that information + * in the NSH greeting. + */ + +#if CONFIG_VERSION_MAJOR != 0 || CONFIG_VERSION_MINOR != 0 +const char g_nshgreeting[] = "\nNuttShell (NSH) NuttX-" CONFIG_VERSION_STRING "\n"; +#else +const char g_nshgreeting[] = "\nNuttShell (NSH)\n"; +#endif + +/* The NSH prompt */ + +const char g_nshprompt[] = "nsh> "; + +/* Common, message formats */ + +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_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: help_cmdlist + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_HELP +static inline void help_cmdlist(FAR struct nsh_vtbl_s *vtbl) +{ + int i; + int j; + int k; + + /* Print the command name in NUM_CMD_ROWS rows with CMDS_PER_LINE commands + * on each line. + */ + + for (i = 0; i < NUM_CMD_ROWS; i++) + { + nsh_output(vtbl, " "); + for (j = 0, k = i; j < CMDS_PER_LINE && k < NUM_CMDS; j++, k += NUM_CMD_ROWS) + { + nsh_output(vtbl, "%-12s", g_cmdmap[k].cmd); + } + + nsh_output(vtbl, "\n"); + } +} +#endif + +/**************************************************************************** + * Name: help_usage + ****************************************************************************/ + +#if !defined(CONFIG_NSH_DISABLE_HELP) && !defined(CONFIG_NSH_HELP_TERSE) +static inline void help_usage(FAR struct nsh_vtbl_s *vtbl) +{ + nsh_output(vtbl, "NSH command forms:\n"); +#ifndef CONFIG_NSH_DISABLEBG + nsh_output(vtbl, " [nice [-d <niceness>>]] <cmd> [> <file>|>> <file>] [&]\n"); +#else + nsh_output(vtbl, " <cmd> [> <file>|>> <file>]\n"); +#endif +#ifndef CONFIG_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\n"); +#endif +} +#endif + +/**************************************************************************** + * Name: help_showcmd + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_HELP +static void help_showcmd(FAR struct nsh_vtbl_s *vtbl, + FAR const struct cmdmap_s *cmdmap) +{ + if (cmdmap->usage) + { + nsh_output(vtbl, " %s %s\n", cmdmap->cmd, cmdmap->usage); + } + else + { + nsh_output(vtbl, " %s\n", cmdmap->cmd); + } +} +#endif + +/**************************************************************************** + * Name: help_cmd + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_HELP +static int help_cmd(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd) +{ + FAR const struct cmdmap_s *cmdmap; + + /* Find the command in the command table */ + + for (cmdmap = g_cmdmap; cmdmap->cmd; cmdmap++) + { + /* Is this the one we are looking for? */ + + if (strcmp(cmdmap->cmd, cmd) == 0) + { + /* Yes... show it */ + + nsh_output(vtbl, "%s usage:", cmd); + help_showcmd(vtbl, cmdmap); + return OK; + } + } + + nsh_output(vtbl, g_fmtcmdnotfound, cmd); + return ERROR; +} +#endif + +/**************************************************************************** + * Name: help_allcmds + ****************************************************************************/ + +#if !defined(CONFIG_NSH_DISABLE_HELP) && !defined(CONFIG_NSH_HELP_TERSE) +static inline void help_allcmds(FAR struct nsh_vtbl_s *vtbl) +{ + FAR const struct cmdmap_s *cmdmap; + + /* Show all of the commands in the command table */ + + for (cmdmap = g_cmdmap; cmdmap->cmd; cmdmap++) + { + help_showcmd(vtbl, cmdmap); + } +} +#endif + +/**************************************************************************** + * Name: help_builtins + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_HELP +static inline void help_builtins(FAR struct nsh_vtbl_s *vtbl) +{ +#ifdef CONFIG_NSH_BUILTIN_APPS + FAR const char *name; + int i; + + /* List the set of available built-in commands */ + + nsh_output(vtbl, "\nBuiltin Apps:\n"); + for (i = 0; (name = namedapp_getname(i)) != NULL; i++) + { + nsh_output(vtbl, " %s\n", name); + } +#endif +} +#endif + +/**************************************************************************** + * Name: cmd_help + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_HELP +static int cmd_help(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + FAR const char *cmd = NULL; +#ifndef CONFIG_NSH_HELP_TERSE + bool verbose = false; + int i; +#endif + + /* The command may be followed by a verbose option */ + +#ifndef CONFIG_NSH_HELP_TERSE + i = 1; + if (argc > i) + { + if (strcmp(argv[i], "-v") == 0) + { + verbose = true; + i++; + } + } + + /* The command line may end with a command name */ + + if (argc > i) + { + cmd = argv[i]; + } + + /* Show the generic usage if verbose is requested */ + + if (verbose) + { + help_usage(vtbl); + } +#else + if (argc > 1) + { + cmd = argv[1]; + } +#endif + + /* Are we showing help on a single command? */ + + if (cmd) + { + /* Yes.. show the single command */ + + help_cmd(vtbl, cmd); + } + else + { + /* In verbose mode, show detailed help for all commands */ + +#ifndef CONFIG_NSH_HELP_TERSE + if (verbose) + { + nsh_output(vtbl, "Where <cmd> is one of:\n"); + help_allcmds(vtbl); + } + + /* Otherwise, just show the list of command names */ + + else +#endif + { + help_cmd(vtbl, "help"); + nsh_output(vtbl, "\n"); + help_cmdlist(vtbl); + } + + /* And show the list of built-in applications */ + + help_builtins(vtbl); + } + + 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_NSH_DISABLE_EXIT +static int cmd_exit(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + nsh_exit(vtbl, 0); + return OK; +} +#endif + +/**************************************************************************** + * Name: nsh_execute + * + * Description: + * Exectue the command in argv[0] + * + * Returned Value: + * <0 If exec_namedapp() fails, then the negated errno value + * is returned. + * -1 (ERRROR) if the command was unsuccessful + * 0 (OK) if the command was successful + * 1 if an application task was spawned successfully, but + * returned failure exit status. + * + ****************************************************************************/ + +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]; + + /* Try to find a command in the application library. */ + +#ifdef CONFIG_NSH_BUILTIN_APPS + ret = nsh_execapp(vtbl, cmd, argv); + + /* If the built-in application was successfully started, return OK + * or 1 (if the application returned a non-zero exit status). + */ + + if (ret >= 0) + { + return ret; + } +#endif + + /* 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; + } + } + } + + ret = handler(vtbl, argc, argv); + return ret; +} + +/**************************************************************************** + * Name: nsh_releaseargs + ****************************************************************************/ + +#ifndef CONFIG_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_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_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_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_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_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_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_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_parse + * + * Description: + * This function parses and executes one NSH command. + * + ****************************************************************************/ + +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_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_NSH_DISABLESCRIPT + if (nsh_ifthenelse(vtbl, &cmd, &saveptr) != 0) + { + goto errout; + } +#endif + + /* Handle nice */ + +#ifndef CONFIG_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_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_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 namedapp new process will + * be created anyway, so skip this step. */ + +#ifndef CONFIG_NSH_DISABLEBG + if (vtbl->np.np_bg +#ifdef CONFIG_NSH_BUILTIN_APPS + && namedapp_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, ¶m); + 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, ¶m); + + /* 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. nsh_execute will return: + * + * -1 (ERRROR) if the command was unsuccessful + * 0 (OK) if the command was successful + * 1 if an application task was spawned successfully, but + * returned failure exit status. + */ + + 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); + } + + /* Treat both errors and non-zero return codes as "errors" so that + * it is possible to test for non-zero returns in nsh scripts. + */ + + if (ret != OK) + { + goto errout; + } + } + + /* Return success if the command succeeded (or at least, starting of the + * command task succeeded). + */ + + return nsh_saveresult(vtbl, false); + +#ifndef CONFIG_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_proccmds.c b/apps/nshlib/nsh_proccmds.c new file mode 100644 index 000000000..487214501 --- /dev/null +++ b/apps/nshlib/nsh_proccmds.c @@ -0,0 +1,310 @@ +/**************************************************************************** + * apps/nshlib/nsh_proccmds.c + * + * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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" +#include "nsh_console.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 + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_PS +static const char *g_statenames[] = +{ + "INVALID ", + "PENDING ", + "READY ", + "RUNNING ", + "INACTIVE", + "WAITSEM ", +#ifndef CONFIG_DISABLE_MQUEUE + "WAITSIG ", +#endif +#ifndef CONFIG_DISABLE_MQUEUE + "MQNEMPTY", + "MQNFULL " +#endif +}; + +static const char *g_ttypenames[4] = +{ + "TASK ", + "PTHREAD", + "KTHREAD", + "--?-- " +}; +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ps_task + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_PS +static void ps_task(FAR _TCB *tcb, FAR void *arg) +{ + struct nsh_vtbl_s *vtbl = (struct nsh_vtbl_s*)arg; +#if CONFIG_MAX_TASK_ARGS > 2 + int i; +#endif + + /* 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", + g_ttypenames[(tcb->flags & TCB_FLAG_TTYPE_MASK) >> TCB_FLAG_TTYPE_SHIFT], + 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_NSH_DISABLE_EXEC +int cmd_exec(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *endptr; + uintptr_t addr; + + addr = (uintptr_t)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_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_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_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_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..4134b45a3 --- /dev/null +++ b/apps/nshlib/nsh_romfsetc.c @@ -0,0 +1,124 @@ +/**************************************************************************** + * apps/nshlib/nsh_romfsetc.c + * + * Copyright (C) 2008-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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_NSH_ROMFSETC + +/* Should we use the default ROMFS image? Or a custom, board-specific + * ROMFS image? + */ + +#ifdef CONFIG_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_NSH_ROMFSDEVNO, romfs_img, + NSECTORS(romfs_img_len), CONFIG_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_NSH_ROMFSMOUNTPT, MOUNT_DEVNAME); + + ret = mount(MOUNT_DEVNAME, CONFIG_NSH_ROMFSMOUNTPT, "romfs", MS_RDONLY, NULL); + if (ret < 0) + { + dbg("nsh: mount(%s,%s,romfs) failed: %d\n", + MOUNT_DEVNAME, CONFIG_NSH_ROMFSMOUNTPT, errno); + return ERROR; + } + return OK; +} + +#endif /* CONFIG_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_telnetd.c b/apps/nshlib/nsh_telnetd.c new file mode 100644 index 000000000..0117aad04 --- /dev/null +++ b/apps/nshlib/nsh_telnetd.c @@ -0,0 +1,187 @@ +/**************************************************************************** + * apps/nshlib/nsh_telnetd.c + * + * Copyright (C) 2007-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <stdio.h> +#include <unistd.h> +#include <assert.h> +#include <debug.h> + +#include <apps/netutils/telnetd.h> + +#include "nsh.h" +#include "nsh_console.h" + +#ifdef CONFIG_NSH_TELNET + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_telnetmain + ****************************************************************************/ + +int nsh_telnetmain(int argc, char *argv[]) +{ + FAR struct console_stdio_s *pstate = nsh_newconsole(); + DEBUGASSERT(pstate != NULL); + + dbg("Session [%d] Started\n", getpid()); + + /* Present a greeting */ + + fputs(g_nshgreeting, pstate->cn_outstream); + fflush(pstate->cn_outstream); + + /* Execute the startup script */ + +#if defined(CONFIG_NSH_ROMFSETC) && !defined(CONFIG_NSH_CONSOLE) + (void)nsh_script(&pstate->cn_vtbl, "init", NSH_INITPATH); +#endif + + /* Then enter the command line parsing loop */ + + for (;;) + { + /* Display the prompt string */ + + fputs(g_nshprompt, pstate->cn_outstream); + fflush(pstate->cn_outstream); + + /* Get the next line of input from the Telnet client */ + + if (fgets(pstate->cn_line, CONFIG_NSH_LINELEN, INSTREAM(pstate)) != NULL) + { + /* Parse process the received Telnet command */ + + (void)nsh_parse(&pstate->cn_vtbl, pstate->cn_line); + fflush(pstate->cn_outstream); + } + else + { + fprintf(pstate->cn_outstream, g_fmtcmdfailed, "nsh_telnetmain", + "fgets", NSH_ERRNO); + nsh_exit(&pstate->cn_vtbl, 1); + } + } + + /* Clean up */ + + nsh_exit(&pstate->cn_vtbl, 0); + + /* We do not get here, but this is necessary to keep some compilers happy */ + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_telnetstart + * + * Description: + * nsh_telnetstart() starts the Telnet daemon that will allow multiple + * NSH connections via Telnet. This function returns immediately after + * the daemon has been started. + * + * Input Parameters: + * None. All of the properties of the Telnet daemon are controlled by + * NuttX configuration setting. + * + * Returned Values: + * Zero if the Telnet daemon was successfully started. A negated errno + * value will be returned on failure. + * + ****************************************************************************/ + +int nsh_telnetstart(void) +{ + struct telnetd_config_s config; + int ret; + + /* Configure the telnet daemon */ + + config.d_port = HTONS(CONFIG_NSH_TELNETD_PORT); + config.d_priority = CONFIG_NSH_TELNETD_DAEMONPRIO; + config.d_stacksize = CONFIG_NSH_TELNETD_DAEMONSTACKSIZE; + config.t_priority = CONFIG_NSH_TELNETD_CLIENTPRIO; + config.t_stacksize = CONFIG_NSH_TELNETD_CLIENTSTACKSIZE; + config.t_entry = nsh_telnetmain; + + /* Start the telnet daemon */ + + vdbg("Starting the Telnet daemon\n"); + ret = telnetd_start(&config); + if (ret < 0) + { + dbg("Failed to tart the Telnet daemon: %d\n", ret); + } + + return ret; +} + +#endif /* CONFIG_NSH_TELNET */ diff --git a/apps/nshlib/nsh_test.c b/apps/nshlib/nsh_test.c new file mode 100644 index 000000000..6e1b65e5f --- /dev/null +++ b/apps/nshlib/nsh_test.c @@ -0,0 +1,438 @@ +/**************************************************************************** + * apps/nshlib/nsh_test.c + * + * Copyright (C) 2008, 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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" +#include "nsh_console.h" + +#if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_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_NSH_DISABLESCRIPT && !CONFIG_NSH_DISABLE_TEST */ diff --git a/apps/nshlib/nsh_timcmds.c b/apps/nshlib/nsh_timcmds.c new file mode 100644 index 000000000..bc2bda6f4 --- /dev/null +++ b/apps/nshlib/nsh_timcmds.c @@ -0,0 +1,331 @@ +/**************************************************************************** + * apps/nshlib/dbg_timcmds.c + * + * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <string.h> +#include <unistd.h> +#include <time.h> + +#include "nsh.h" +#include "nsh_console.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define MAX_TIME_STRING 80 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#if defined (CONFIG_RTC) && !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_NSH_DISABLE_DATE) +static FAR const char * const g_datemontab[] = +{ + "jan", "feb", "mar", "apr", "may", "jun", + "jul", "aug", "sep", "oct", "nov", "dec" +}; +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: date_month + ****************************************************************************/ + +#if defined (CONFIG_RTC) && !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_NSH_DISABLE_DATE) +static inline int date_month(FAR const char *abbrev) +{ + int i; + + for (i = 0; i < 12; i++) + { + if (strncasecmp(g_datemontab[i], abbrev, 3) == 0) + { + return i; + } + } + return ERROR; +} +#endif + +/**************************************************************************** + * Name: date_gettime + ****************************************************************************/ + +#if defined (CONFIG_RTC) && !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_NSH_DISABLE_DATE) +static inline int date_showtime(FAR struct nsh_vtbl_s *vtbl, FAR const char *name) +{ + static const char format[] = "%b %d %H:%M:%S %Y"; + struct timespec ts; + struct tm tm; + char timbuf[MAX_TIME_STRING]; + int ret; + + /* Get the current time */ + + ret = clock_gettime(CLOCK_REALTIME, &ts); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, name, "clock_gettime", NSH_ERRNO); + return ERROR; + } + + /* Break the current time up into the format needed by strftime */ + + (void)gmtime_r((FAR const time_t*)&ts.tv_sec, &tm); + + /* Show the current time in the requested format */ + + (void)strftime(timbuf, MAX_TIME_STRING, format, &tm); + nsh_output(vtbl, "%s\n", timbuf); + return OK; +} +#endif + +/**************************************************************************** + * Name: date_settime + ****************************************************************************/ + +#if defined (CONFIG_RTC) && !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_NSH_DISABLE_DATE) +static inline int date_settime(FAR struct nsh_vtbl_s *vtbl, FAR const char *name, + FAR char *newtime) +{ + struct timespec ts; + struct tm tm; + FAR char *token; + FAR char *saveptr; + long result; + int ret; + + /* Only this date format is supported: MMM DD HH:MM:SS YYYY */ + /* Get the month abbreviation */ + + token = strtok_r(newtime, " \t",&saveptr); + if (token == NULL) + { + goto errout_bad_parm; + } + + tm.tm_mon = date_month(token); + if (tm.tm_mon < 0) + { + goto errout_bad_parm; + } + + /* Get the day of the month. NOTE: Accepts day-of-month up to 31 for all months */ + + token = strtok_r(NULL, " \t",&saveptr); + if (token == NULL) + { + goto errout_bad_parm; + } + + result = strtol(token, NULL, 10); + if (result < 1 || result > 31) + { + goto errout_bad_parm; + } + tm.tm_mday = (int)result; + + /* Get the hours */ + + token = strtok_r(NULL, " \t:", &saveptr); + if (token == NULL) + { + goto errout_bad_parm; + } + + result = strtol(token, NULL, 10); + if (result < 0 || result > 23) + { + goto errout_bad_parm; + } + tm.tm_hour = (int)result; + + /* Get the minutes */ + + token = strtok_r(NULL, " \t:", &saveptr); + if (token == NULL) + { + goto errout_bad_parm; + } + + result = strtol(token, NULL, 10); + if (result < 0 || result > 59) + { + goto errout_bad_parm; + } + tm.tm_min = (int)result; + + /* Get the seconds */ + + token = strtok_r(NULL, " \t:", &saveptr); + if (token == NULL) + { + goto errout_bad_parm; + } + + result = strtol(token, NULL, 10); + if (result < 0 || result > 61) + { + goto errout_bad_parm; + } + tm.tm_sec = (int)result; + + /* And finally the year */ + + token = strtok_r(NULL, " \t", &saveptr); + if (token == NULL) + { + goto errout_bad_parm; + } + + result = strtol(token, NULL, 10); + if (result < 1900 || result > 2100) + { + goto errout_bad_parm; + } + tm.tm_year = (int)result - 1900; + + /* Convert this to the right form, then set the timer */ + + ts.tv_sec = mktime(&tm); + ts.tv_nsec = 0; + + ret = clock_settime(CLOCK_REALTIME, &ts); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, name, "clock_settime", NSH_ERRNO); + return ERROR; + } + return OK; + +errout_bad_parm: + nsh_output(vtbl, g_fmtarginvalid, name); + return ERROR; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cmd_date + ****************************************************************************/ + +#if defined (CONFIG_RTC) && !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_NSH_DISABLE_DATE) +int cmd_date(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + FAR char *newtime = NULL; + FAR const char *errfmt; + bool badarg = false; + int option; + int ret; + + /* Get the date options: date [-s time] [+FORMAT] */ + + while ((option = getopt(argc, argv, "s:")) != ERROR) + { + if (option == 's') + { + /* We will be setting the time */ + + newtime = optarg; + } + else /* option = '?' */ + { + /* We need to parse to the end anyway so that getopt stays healthy */ + + badarg = true; + } + } + + /* If a bad argument was encountered then exit with an error */ + + if (badarg) + { + errfmt = g_fmtarginvalid; + goto errout; + } + + /* optind < argc-1 means that there are additional, unexpected arguments on + * th command-line + */ + + if (optind < argc) + { + errfmt = g_fmttoomanyargs; + goto errout; + } + + /* Display or set the time */ + + if (newtime) + { + ret = date_settime(vtbl, argv[0], newtime); + } + else + { + ret = date_showtime(vtbl, argv[0]); + } + return ret; + +errout: + nsh_output(vtbl, errfmt, argv[0]); + return ERROR; +} +#endif diff --git a/apps/nshlib/nsh_usbdev.c b/apps/nshlib/nsh_usbdev.c new file mode 100644 index 000000000..3d123532a --- /dev/null +++ b/apps/nshlib/nsh_usbdev.c @@ -0,0 +1,243 @@ +/**************************************************************************** + * apps/nshlib/nsh_usbdev.c + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <fcntl.h> +#include <assert.h> +#include <debug.h> + +#ifdef CONFIG_CDCACM +# include <nuttx/usb/cdcacm.h> +#endif + +#ifdef CONFIG_CDCACM +# include <nuttx/usb/pl2303.h> +#endif + +#include "nsh.h" + +#ifdef CONFIG_USBDEV + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#if defined(CONFIG_DEBUG) || defined(CONFIG_NSH_USBCONSOLE) +# define trmessage lib_lowprintf +#else +# define trmessage printf +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_tracecallback + ****************************************************************************/ + +#ifdef CONFIG_USBDEV_TRACE +static int nsh_tracecallback(struct usbtrace_s *trace, void *arg) +{ + usbtrace_trprintf((trprintf_t)trmessage, trace->event, trace->value); + return 0; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_usbconsole + ****************************************************************************/ + +#ifdef HAVE_USB_CONSOLE +int nsh_usbconsole(void) +{ + char inch; + ssize_t nbytes; + int nlc; + int fd; + int ret; + + /* Initialize any USB tracing options that were requested */ + +#ifdef CONFIG_USBDEV_TRACE + usbtrace_enable(TRACE_BITSET); +#endif + + /* Don't start the NSH console until the console device is ready. Chances + * are, we get here with no functional console. The USB console will not + * be available until the device is connected to the host and until the + * host-side application opens the connection. + */ + + /* Initialize the USB serial driver */ + +#if defined(CONFIG_PL2303) || defined(CONFIG_CDCACM) +#ifdef CONFIG_CDCACM + ret = cdcacm_initialize(CONFIG_NSH_UBSDEV_MINOR, NULL); +#else + ret = usbdev_serialinitialize(CONFIG_NSH_UBSDEV_MINOR); +#endif + DEBUGASSERT(ret == OK); +#endif + + /* Open the USB serial device for read/write access */ + + do + { + /* Try to open the console */ + + fd = open(CONFIG_NSH_USBCONDEV, O_RDWR); + if (fd < 0) + { + /* ENOTCONN means that the USB device is not yet connected. Anything + * else is bad. + */ + + DEBUGASSERT(errno == ENOTCONN); + + /* Sleep a bit and try again */ + + sleep(2); + } + } + while (fd < 0); + + /* Now waiting until we successfully read a carriage return a few times. + * That is a sure way of know that there is something at the other end of + * the USB serial connection that is ready to talk with us. The user needs + * to hit ENTER a few times to get things started. + */ + + nlc = 0; + do + { + /* Read one byte */ + + inch = 0; + nbytes = read(fd, &inch, 1); + + /* Is it a carriage return (or maybe a newline)? */ + + if (nbytes == 1 && (inch == '\n' || inch == '\r')) + { + /* Yes.. increment the count */ + + nlc++; + } + else + { + /* No.. Reset the count. We need to see 3 in a row to continue. */ + + nlc = 0; + } + } + while (nlc < 3); + + /* Make sure the stdin, stdout, and stderr are closed */ + + (void)fclose(stdin); + (void)fclose(stdout); + (void)fclose(stderr); + + /* Dup the fd to create standard fd 0-2 */ + + (void)dup2(fd, 0); + (void)dup2(fd, 1); + (void)dup2(fd, 2); + + /* We can close the original file descriptor now (unless it was one of 0-2) */ + + if (fd > 2) + { + close(fd); + } + + /* fdopen to get the stdin, stdout and stderr streams. The following logic depends + * on the fact that the library layer will allocate FILEs in order. And since + * we closed stdin, stdout, and stderr above, that is what we should get. + * + * fd = 0 is stdin (read-only) + * fd = 1 is stdout (write-only, append) + * fd = 2 is stderr (write-only, append) + */ + + (void)fdopen(0, "r"); + (void)fdopen(1, "a"); + (void)fdopen(2, "a"); + return OK; +} + +#endif /* HAVE_USB_CONSOLE */ + +/**************************************************************************** + * Name: nsh_usbtrace + ****************************************************************************/ + +#if defined(CONFIG_USBDEV_TRACE) && defined(HAVE_USB_CONSOLE) +void nsh_usbtrace(void) +{ + (void)usbtrace_enumerate(nsh_tracecallback, NULL); +} +#endif + +#endif /* CONFIG_USBDEV */ 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 |