NSH will now run files from the file system; Add logic to unload and clean-up after running a task from a file system; Extensions to builtin apps from Mike Smith

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5529 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2013-01-17 18:32:13 +00:00
parent cdc16263ee
commit 140d3e4374
9 changed files with 494 additions and 8 deletions

View File

@ -485,3 +485,6 @@
argument is now optional. Many files systems do not need
a source and it is really stupid to have to enter a bogus
source parameter.
* apps/nshlib/nsh_fileapp.c: Add the ability to execute a file
from a file system using posix_spawn().
* apps/builtin/: Extensions from Mike Smith.

79
builtin/builtin_list.c Normal file
View File

@ -0,0 +1,79 @@
/****************************************************************************
* apps/builtin/builtin_list.c
*
* Copyright (C) 2011 Uros Platise. All rights reserved.
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Authors: Uros Platise <uros.platise@isotel.eu>
* 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 <nuttx/binfmt/builtin.h>
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
#include "builtin_proto.h"
const struct builtin_s g_builtins[] =
{
# include "builtin_list.h"
{ NULL, 0, 0, 0 }
};
const int g_builtin_count = sizeof(g_builtins) / sizeof(g_builtins[0]);
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/

View File

@ -46,6 +46,12 @@
#include <errno.h>
#include <nuttx/arch.h>
#if defined(CONFIG_FS_BINFS) && (CONFIG_BUILTIN)
#include <nuttx/binfmt/builtin.h>
#endif
#if defined(CONFIG_LIBC_EXECFUNCS) && defined(CONFIG_EXECFUNCS_SYMTAB)
#include <nuttx/binfmt/symtab.h>
#endif
#include <apps/nsh.h>
@ -75,6 +81,21 @@
* Public Data
****************************************************************************/
/* If posix_spawn() is enabled as required for CONFIG_NSH_FILE_APPS, then
* a symbol table is needed by the internals of posix_spawn(). The symbol
* table is needed to support ELF and NXFLAT binaries to dynamically link to
* the base code. However, if only the BINFS file system is supported, then
* no Makefile is needed.
*
* This is a kludge to plug the missing file system in the case where BINFS
* is used. REVISIT: This will, of course, be in the way if you want to
* support ELF or NXFLAT binaries!
*/
#if defined(CONFIG_LIBC_EXECFUNCS) && defined(CONFIG_EXECFUNCS_SYMTAB)
const struct symtab_s CONFIG_EXECFUNCS_SYMTAB[1];
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
@ -98,6 +119,23 @@ int nsh_main(int argc, char *argv[])
up_cxxinitialize();
#endif
/* Make sure that we are using our symbol take */
#if defined(CONFIG_LIBC_EXECFUNCS) && defined(CONFIG_EXECFUNCS_SYMTAB)
exec_setsymtab(CONFIG_EXECFUNCS_SYMTAB, 0);
#endif
/* Register the BINFS file system */
#if defined(CONFIG_FS_BINFS) && (CONFIG_BUILTIN)
ret = builtin_initialize();
if (ret < 0)
{
fprintf(stderr, "ERROR: builtin_initialize failed: %d\n", ret);
exitval = 1;
}
#endif
/* Initialize the NSH library */
nsh_initialize();

View File

@ -14,7 +14,7 @@ config NSH_LIBRARY
if NSH_LIBRARY
config NSH_BUILTIN_APPS
bool "Enable built-in applications"
default y
default n
depends on BUILTIN
---help---
Support external registered, "built-in" applications that can be
@ -22,6 +22,15 @@ config NSH_BUILTIN_APPS
more information). This options requires support for builtin
applications (BUILTIN).
config NSH_FILE_APPS
bool "Enable execution of program files"
default n
depends on LIBC_EXECFUNCS
---help---
Support execution of program files residing within a file
system. This options requires support for the posix_spawn()
interface (LIBC_EXECFUNCS).
menu "Disable Individual commands"
config NSH_DISABLE_BASE64DEC

View File

@ -47,6 +47,10 @@ ifeq ($(CONFIG_NSH_BUILTIN_APPS),y)
CSRCS += nsh_builtin.c
endif
ifeq ($(CONFIG_NSH_FILE_APPS),y)
CSRCS += nsh_fileapps.c
endif
ifeq ($(CONFIG_NSH_ROMFSETC),y)
CSRCS += nsh_romfsetc.c
endif

View File

@ -495,6 +495,11 @@ int nsh_builtin(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
FAR char **argv, FAR const char *redirfile, int oflags);
#endif
#ifdef CONFIG_NSH_FILE_APPS
int nsh_fileapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
FAR char **argv, FAR const char *redirfile, int oflags);
#endif
/* Working directory support */
#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON)

View File

@ -51,6 +51,7 @@
#endif
#include <stdbool.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
@ -129,20 +130,34 @@ int nsh_builtin(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
ret = exec_builtin(cmd, (FAR const char **)argv, redirfile, oflags);
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. These really
* only works works with the following options:
/* The application was successfully started with pre-emption disabled.
* In the simplest cases, the application will not have run because the
* the scheduler is locked. but in the case were I/O redirected, a
* proxy task ran and, as result, so may have the application.
*
* If the application did not run and if the application was not
* backgrounded, then we need to wait here for the application to
* exit. This only works works with the following options:
*
* - CONFIG_NSH_DISABLEBG - Do not run commands in background
* - CONFIG_SCHED_WAITPID - Required to run external commands in
* foreground
*
* These concepts do not apply cleanly to the external applications.
*/
#ifdef CONFIG_SCHED_WAITPID
/* Check if the application is still running */
if (kill(ret, 0) < 0)
{
/* It is not running. In this case, we have no idea if the
* application ran successfully or not. Let's assume that is
* did.
*/
return 0;
}
/* CONFIG_SCHED_WAITPID is selected, so we may run the command in
* foreground unless we were specifically requested to run the command
* in background (and running commands in background is enabled).

298
nshlib/nsh_fileapps.c Normal file
View File

@ -0,0 +1,298 @@
/****************************************************************************
* apps/nshlib/nsh_fileapps.c
*
* Copyright (C) 2013 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_SCHED_WAITPID
# include <sys/wait.h>
#endif
#include <stdbool.h>
#include <signal.h>
#include <spawn.h>
#include <errno.h>
#include <string.h>
#include "nsh.h"
#include "nsh_console.h"
#ifdef CONFIG_NSH_FILE_APPS
/****************************************************************************
* Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: nsh_fileapp
*
* Description:
* Attempt to execute the application task whose name is 'cmd'
*
* Returned Value:
* <0 If exec_builtin() 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_fileapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
FAR char **argv, FAR const char *redirfile, int oflags)
{
posix_spawn_file_actions_t file_actions;
posix_spawnattr_t attr;
pid_t pid;
int ret;
/* Initialize the attributes file actions structure */
ret = posix_spawn_file_actions_init(&file_actions);
if (ret != 0)
{
/* posix_spawn_file_actions_init returns a positive errno value on
* failure.
*/
nsh_output(vtbl, g_fmtcmdfailed, cmd, "posix_spawn_file_actions_init",
NSH_ERRNO_OF(ret));
goto errout;
}
ret = posix_spawnattr_init(&attr);
if (ret != 0)
{
/* posix_spawnattr_init returns a positive errno value on failure. */
nsh_output(vtbl, g_fmtcmdfailed, cmd, "posix_spawnattr_init",
NSH_ERRNO);
goto errout_with_actions;
}
/* Handle re-direction of output */
if (redirfile)
{
ret = posix_spawn_file_actions_addopen(&file_actions, 1, redirfile,
oflags, 0644);
if (ret != 0)
{
/* posix_spawn_file_actions_addopen returns a positive errno
* value on failure.
*/
nsh_output(vtbl, g_fmtcmdfailed, cmd,
"posix_spawn_file_actions_addopen",
NSH_ERRNO);
goto errout_with_attrs;
}
}
/* Lock the scheduler to prevent the application from running until the
* waitpid() has been called.
*/
sched_lock();
/* Execute the program. posix_spawnp returns a positive errno value on
* failure.
*/
ret = posix_spawnp(&pid, cmd, &file_actions, &attr, &argv[1], NULL);
if (ret == OK)
{
/* The application was successfully started with pre-emption disabled.
* In the simplest cases, the application will not have run because the
* the scheduler is locked. but in the case were I/O redirected, a
* proxy task ran and, as result, so may have the application.
*
* If the application did not run and if the application was not
* backgrounded, then we need to wait here for the application to
* exit. This only works works with the following options:
*
* - CONFIG_NSH_DISABLEBG - Do not run commands in background
* - CONFIG_SCHED_WAITPID - Required to run external commands in
* foreground
*/
#ifdef CONFIG_SCHED_WAITPID
/* Check if the application is still running */
if (kill(ret, 0) < 0)
{
/* It is not running. In this case, we have no idea if the
* application ran successfully or not. Let's assume that is
* did.
*/
return 0;
}
/* CONFIG_SCHED_WAITPID is selected, so we may run the command in
* foreground unless we were specifically requested to run the command
* in background (and running commands in background is enabled).
*/
# ifndef CONFIG_NSH_DISABLEBG
if (vtbl->np.np_bg == false)
# endif /* CONFIG_NSH_DISABLEBG */
{
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(pid, &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.
*/
}
}
# ifndef CONFIG_NSH_DISABLEBG
else
# endif /* CONFIG_NSH_DISABLEBG */
#endif /* CONFIG_SCHED_WAITPID */
/* We get here if either:
*
* - CONFIG_SCHED_WAITPID is not selected meaning that all commands
* have to be run in background, or
* - CONFIG_SCHED_WAITPID and CONFIG_NSH_DISABLEBG are both selected, but the
* user requested to run the command in background.
*
* NOTE that the case of a) CONFIG_SCHED_WAITPID is not selected and
* b) CONFIG_NSH_DISABLEBG selected cannot be supported. In that event, all
* commands will have to run in background. The waitpid() API must be
* available to support running the command in foreground.
*/
#if !defined(CONFIG_SCHED_WAITPID) || !defined(CONFIG_NSH_DISABLEBG)
{
struct sched_param param;
sched_getparam(ret, &param);
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;
}
#endif /* !CONFIG_SCHED_WAITPID || !CONFIG_NSH_DISABLEBG */
}
sched_unlock();
/* Free attibutes and file actions. Ignoring return values in the case
* of an error.
*/
errout_with_actions:
(void)posix_spawn_file_actions_destroy(&file_actions);
errout_with_attrs:
(void)posix_spawnattr_destroy(&attr);
errout:
/* Most posix_spawn interfaces return a positive errno value on failure
* and do not set the errno variable.
*/
if (ret > 0)
{
/* Set the errno value and return -1 */
set_errno(ret);
ret = ERROR;
}
else if (ret < 0)
{
/* Return -1 on failure. errno should have been set. */
ret = ERROR;
}
return ret;
}
#endif /* CONFIG_NSH_FILE_APPS */

View File

@ -61,6 +61,7 @@
#ifdef CONFIG_NSH_BUILTIN_APPS
# include <nuttx/binfmt/builtin.h>
#endif
#include <apps/nsh.h>
#include "nsh.h"
@ -1398,6 +1399,40 @@ int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline)
nsh_output(vtbl, g_fmttoomanyargs, cmd);
}
/* Does this command correspond to an application filename?
* nsh_fileapp() returns:
*
* -1 (ERROR) if the application task corresponding to 'argv[0]' could not
* be started (possibly because it doesn not exist).
* 0 (OK) if the application task corresponding to 'argv[0]' 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.
*
* Note the priority if not effected by nice-ness.
*/
#ifdef CONFIG_NSH_FILE_APPS
ret = nsh_fileapp(vtbl, argv[0], argv, redirfile, oflags);
if (ret >= 0)
{
/* nsh_fileapp() returned 0 or 1. This means that the builtin
* command was successfully started (although it may not have ran
* successfully). So certainly it is not an NSH command.
*/
return nsh_saveresult(vtbl, ret != OK);
}
/* No, not a built in command (or, at least, we were unable to start a
* builtin command of that name). Treat it like an NSH command.
*/
#endif
/* Does this command correspond to a builtin command?
* nsh_builtin() returns:
*
@ -1414,7 +1449,7 @@ int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline)
* Note the priority if not effected by nice-ness.
*/
#ifdef CONFIG_NSH_BUILTIN_APPS
#if defined(CONFIG_NSH_BUILTIN_APPS) && (!defined(CONFIG_NSH_FILE_APPS) || !defined(CONFIG_FS_BINFS))
ret = nsh_builtin(vtbl, argv[0], argv, redirfile, oflags);
if (ret >= 0)
{