From 7f22c14077e8aa4edb0d35ca1c8a75f7a978c929 Mon Sep 17 00:00:00 2001 From: patacongo Date: Tue, 29 Jan 2013 22:11:04 +0000 Subject: Add support for a login script (in addition to the init script); Add logic so that a USB console session can connect and reconnect to the USB serial device git-svn-id: http://svn.code.sf.net/p/nuttx/code/trunk@5582 42af7a65-404d-4744-a932-0658087f49c3 --- apps/nshlib/Kconfig | 22 ++++ apps/nshlib/Makefile | 9 +- apps/nshlib/nsh.h | 47 ++++++-- apps/nshlib/nsh_consolemain.c | 88 +++++---------- apps/nshlib/nsh_fscmds.c | 67 +----------- apps/nshlib/nsh_script.c | 195 +++++++++++++++++++++++++++++++++ apps/nshlib/nsh_session.c | 163 ++++++++++++++++++++++++++++ apps/nshlib/nsh_telnetd.c | 33 +++++- apps/nshlib/nsh_usbdev.c | 245 +++++++++++++++++++++++++++++++++--------- 9 files changed, 668 insertions(+), 201 deletions(-) create mode 100644 apps/nshlib/nsh_script.c create mode 100644 apps/nshlib/nsh_session.c (limited to 'apps/nshlib') diff --git a/apps/nshlib/Kconfig b/apps/nshlib/Kconfig index 589476baf..92bc83cfd 100644 --- a/apps/nshlib/Kconfig +++ b/apps/nshlib/Kconfig @@ -292,6 +292,19 @@ config NSH_ROMFSETC endif if NSH_ROMFSETC + +config NSH_ROMFSRC + bool "Support ROMFS login script" + default n + ---help--- + The ROMFS start-up script will be executed excactly once. For + simple, persistence consoles (like a serial console). But with + other other kinds of consoles, there may be multiple, transient + sessions (such as Telnet and USB consoles). In these cases, you + may need another script that is executed at the beginning of each + session. Selecting this option enables support for such a login + script + config NSH_ROMFSMOUNTPT string "ROMFS mount point" default "/etc" @@ -308,6 +321,15 @@ config NSH_INITSCRIPT The default is init.d/rcS. This is a relative path and must not start with '/'. +config NSH_RCSCRIPT + string "Relative path to login script" + default ".nshrc" + depends on NSH_ROMFSRC + ---help--- + This is the relative path to the login script within the mountpoint. + The default is .nshrc. This is a relative path and must not + start with '/'. + config NSH_ROMFSDEVNO int "ROMFS block device minor number" default 0 diff --git a/apps/nshlib/Makefile b/apps/nshlib/Makefile index 948f43d52..76cdac40d 100644 --- a/apps/nshlib/Makefile +++ b/apps/nshlib/Makefile @@ -1,7 +1,7 @@ ############################################################################ # apps/nshlib/Makefile # -# Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. +# Copyright (C) 2011-2013 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without @@ -39,9 +39,10 @@ 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 +ASRCS = +CSRCS = nsh_init.c nsh_parse.c nsh_console.c nsh_script.c nsh_session.c +CSRCS += nsh_fscmds.c nsh_ddcmd.c nsh_proccmds.c nsh_mmcmds.c nsh_envcmds.c +CSRCS += nsh_dbgcmds.c ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) CSRCS += nsh_builtin.c diff --git a/apps/nshlib/nsh.h b/apps/nshlib/nsh.h index 168503580..23209dba5 100644 --- a/apps/nshlib/nsh.h +++ b/apps/nshlib/nsh.h @@ -93,8 +93,8 @@ # 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. +/* Check for a generic USB console. In this case, the USB console device + * must be provided in CONFIG_NSH_CONDEV. */ # elif defined(CONFIG_NSH_USBCONSOLE) @@ -244,40 +244,59 @@ # 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 + +# ifndef CONFIG_NSH_INITSCRIPT +# define CONFIG_NSH_INITSCRIPT "init.d/rcS" # endif + # undef NSH_INITPATH # define NSH_INITPATH CONFIG_NSH_ROMFSMOUNTPT "/" CONFIG_NSH_INITSCRIPT + +# ifdef CONFIG_NSH_ROMFSRC +# ifndef CONFIG_NSH_RCSCRIPT +# define CONFIG_NSH_RCSCRIPT ".nshrc" +# endif + +# undef NSH_RCPATH +# define NSH_RCPATH CONFIG_NSH_ROMFSMOUNTPT "/" CONFIG_NSH_RCSCRIPT +# endif + # 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_ROMFSRC # undef CONFIG_NSH_ROMFSMOUNTPT -# undef CONFIG_NSH_INIT # undef CONFIG_NSH_INITSCRIPT +# undef CONFIG_NSH_RCSCRIPT # undef CONFIG_NSH_ROMFSDEVNO # undef CONFIG_NSH_ROMFSSECTSIZE + #endif /* This is the maximum number of arguments that will be accepted for a @@ -486,6 +505,12 @@ int nsh_usbconsole(void); #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); +#ifdef CONFIG_NSH_ROMFSETC +int nsh_initscript(FAR struct nsh_vtbl_s *vtbl); +#ifdef CONFIG_NSH_ROMFSRC +int nsh_loginscript(FAR struct nsh_vtbl_s *vtbl); +#endif +#endif #endif /* Architecture-specific initialization */ @@ -496,8 +521,10 @@ int nsh_archinitialize(void); # define nsh_archinitialize() (-ENOSYS) #endif -/* Message handler */ +/* Basic session and message handling */ +struct console_stdio_s; +int nsh_session(FAR struct console_stdio_s *pstate); int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline); /* Application interface */ @@ -527,10 +554,8 @@ void nsh_dumpbuffer(FAR struct nsh_vtbl_s *vtbl, const char *msg, /* USB debug support */ -#if defined(CONFIG_NSH_USBDEV_TRACE) && defined(HAVE_USB_CONSOLE) +#ifdef CONFIG_NSH_USBDEV_TRACE void nsh_usbtrace(void); -#else -# define nsh_usbtrace() #endif /* Shell command handlers */ diff --git a/apps/nshlib/nsh_consolemain.c b/apps/nshlib/nsh_consolemain.c index f05447a64..8be44f7aa 100644 --- a/apps/nshlib/nsh_consolemain.c +++ b/apps/nshlib/nsh_consolemain.c @@ -1,7 +1,7 @@ /**************************************************************************** * apps/nshlib/nsh_consolemain.c * - * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011-2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -47,6 +47,8 @@ #include "nsh.h" #include "nsh_console.h" +#ifndef HAVE_USB_CONSOLE + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -76,21 +78,25 @@ ****************************************************************************/ /**************************************************************************** - * Name: nsh_consolemain + * Name: nsh_consolemain (Normal character device version) * * 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. + * single an NSH instance that operates on stdin and stdout. This + * function does not normally return (see below). * + * This version of nsh_consolmain handles generic /dev/console character + * devices (see nsh_usbdev.c for another version for special USB console + * devices). + * * Input Parameters: - * Standard task start-up arguements. These are not used. argc may be + * Standard task start-up arguments. 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). + * an error. In that case, a nonzero value is returned (EXIT_FAILURE=1). * ****************************************************************************/ @@ -101,70 +107,26 @@ int nsh_consolemain(int argc, char *argv[]) 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 */ + /* Execute the start-up script */ #ifdef CONFIG_NSH_ROMFSETC - (void)nsh_script(&pstate->cn_vtbl, "init", NSH_INITPATH); + (void)nsh_initscript(&pstate->cn_vtbl); #endif - /* Then enter the command line parsing loop */ - - for (;;) - { - /* For the case of debugging the USB console... dump collected USB trace data */ + /* Initialize any USB tracing options that were requested */ - 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); - } +#ifdef CONFIG_NSH_USBDEV_TRACE + usbtrace_enable(TRACE_BITSET); +#endif - /* 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. - */ + /* Execute the session */ - else - { - fprintf(pstate->cn_outstream, g_fmtcmdfailed, "nsh_consolemain", - "readline", NSH_ERRNO_OF(-ret)); - nsh_exit(&pstate->cn_vtbl, 1); - } - } + ret = nsh_session(pstate); - /* Clean up. We do not get here, but this is necessary to keep some - * compilers happy. But others will complain that this code is not - * reachable. - */ + /* Exit upon return */ - nsh_exit(&pstate->cn_vtbl, 0); - return OK; + nsh_exit(&pstate->cn_vtbl, ret); + return ret; } + +#endif /* !HAVE_USB_CONSOLE */ diff --git a/apps/nshlib/nsh_fscmds.c b/apps/nshlib/nsh_fscmds.c index 1a9f2eb57..f47dca896 100644 --- a/apps/nshlib/nsh_fscmds.c +++ b/apps/nshlib/nsh_fscmds.c @@ -1,7 +1,7 @@ /**************************************************************************** * apps/nshlib/nsh_fscmds.c * - * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011-2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -1220,71 +1220,6 @@ int cmd_rmdir(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) #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 ****************************************************************************/ diff --git a/apps/nshlib/nsh_script.c b/apps/nshlib/nsh_script.c new file mode 100644 index 000000000..3aa698b31 --- /dev/null +++ b/apps/nshlib/nsh_script.c @@ -0,0 +1,195 @@ +/**************************************************************************** + * apps/nshlib/nsh_script.c + * + * Copyright (C) 2007-2009, 2011-2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 + +#include "nsh.h" +#include "nsh_console.h" + +#if CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 && !defined(CONFIG_NSH_DISABLESCRIPT) + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_script + * + * Description: + * Execute the NSH script at path. + * + ****************************************************************************/ + +int nsh_script(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, + FAR 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; +} + +/**************************************************************************** + * Name: nsh_initscript + * + * Description: + * Attempt to execute the configured initialization script. This script + * should be executed once when NSH starts. nsh_initscript is idempotent + * and may, however, be called multiple times (the script will be executed + * once. + * + ****************************************************************************/ + +#ifdef CONFIG_NSH_ROMFSETC +int nsh_initscript(FAR struct nsh_vtbl_s *vtbl) +{ + static bool initialized; + bool already; + int ret = OK; + + /* Atomic test and set of the initialized flag */ + + sched_lock(); + already = initialized; + initialized = true; + sched_unlock(); + + /* If we have not already executed the init script, then do so now */ + + if (!already) + { + ret = nsh_script(vtbl, "init", NSH_INITPATH); + } + + return ret; +} + +/**************************************************************************** + * Name: nsh_loginscript + * + * Description: + * Attempt to execute the configured login script. This script + * should be executed when each NSH session starts. + * + ****************************************************************************/ + +#ifdef CONFIG_NSH_ROMFSRC +int nsh_loginscript(FAR struct nsh_vtbl_s *vtbl) +{ + return nsh_script(vtbl, "login", NSH_RCPATH); +} +#endif +#endif /* CONFIG_NSH_ROMFSETC */ + +#endif /* CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 && !CONFIG_NSH_DISABLESCRIPT */ diff --git a/apps/nshlib/nsh_session.c b/apps/nshlib/nsh_session.c new file mode 100644 index 000000000..8079b2de5 --- /dev/null +++ b/apps/nshlib/nsh_session.c @@ -0,0 +1,163 @@ +/**************************************************************************** + * apps/nshlib/nsh_session.c + * + * Copyright (C) 2007-2009, 2011-2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 + +#include +#include + +#include + +#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_session + * + * Description: + * This is the common session logic or any NSH session. This function + * return when an error reading from the input stream occurs, presumably + * signaling the end of the session. + * + * This function: + * - Executes the NSH logic script + * - Presents a greeting + * - Then provides a prompt then gets and processes the command line. + * - This continues until an error occurs, then the session returns. + * + * Input Parameters: + * pstate - Abstracts the underlying session. + * + * Returned Values: + * EXIT_SUCESS or EXIT_FAILURE is returned. + * + ****************************************************************************/ + +int nsh_session(FAR struct console_stdio_s *pstate) +{ + int ret; + + DEBUGASSERT(pstate); + + /* Present a greeting */ + + fputs(g_nshgreeting, pstate->cn_outstream); + fflush(pstate->cn_outstream); + + /* Execute the login script */ + +#ifdef CONFIG_NSH_ROMFSRC + (void)nsh_loginscript(&pstate->cn_vtbl); +#endif + + /* Then enter the command line parsing loop */ + + for (;;) + { + /* For the case of debugging the USB console... dump collected USB trace data */ + +#ifdef CONFIG_NSH_USBDEV_TRACE + nsh_usbtrace(); +#endif + + /* 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_session", + "readline", NSH_ERRNO_OF(-ret)); + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; + } + } + + /* We do not get here, but this is necessary to keep some compilers happy. + * But others will complain that this code is not reachable. + */ + + return EXIT_SUCCESS; +} diff --git a/apps/nshlib/nsh_telnetd.c b/apps/nshlib/nsh_telnetd.c index 478935d7f..76ed81086 100644 --- a/apps/nshlib/nsh_telnetd.c +++ b/apps/nshlib/nsh_telnetd.c @@ -1,7 +1,7 @@ /**************************************************************************** * apps/nshlib/nsh_telnetd.c * - * Copyright (C) 2007-2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -198,15 +198,29 @@ int nsh_telnetmain(int argc, char *argv[]) } #endif /* CONFIG_NSH_TELNET_LOGIN */ + /* The following logic mostly the same as the login in nsh_session.c. It + * differs only in that gets() is called to get the command instead of + * readline(). + */ + /* Present the NSH greeting */ fputs(g_nshgreeting, pstate->cn_outstream); fflush(pstate->cn_outstream); - /* Execute the startup script */ + /* Execute the startup script. If standard console is also defined, then + * we will not bother with the initscript here (although it is safe to + * call nshinitscript multiple times). + */ #if defined(CONFIG_NSH_ROMFSETC) && !defined(CONFIG_NSH_CONSOLE) - (void)nsh_script(&pstate->cn_vtbl, "init", NSH_INITPATH); + (void)nsh_initscript(&pstate->cn_vtbl); +#endif + + /* Execute the login script */ + +#ifdef CONFIG_NSH_ROMFSRC + (void)nsh_loginscript(&pstate->cn_vtbl); #endif /* Then enter the command line parsing loop */ @@ -261,8 +275,8 @@ int nsh_telnetmain(int argc, char *argv[]) * NuttX configuration setting. * * Returned Values: - * Zero if the Telnet daemon was successfully started. A negated errno - * value will be returned on failure. + * The task ID of the Telnet daemon was successfully started. A negated + * errno value will be returned on failure. * ****************************************************************************/ @@ -271,6 +285,15 @@ int nsh_telnetstart(void) struct telnetd_config_s config; int ret; + /* Initialize any USB tracing options that were requested. If standard + * console is also defined, then we will defer this step to the standard + * console. + */ + +#if defined(CONFIG_NSH_USBDEV_TRACE) && !defined(CONFIG_NSH_CONSOLE) + usbtrace_enable(TRACE_BITSET); +#endif + /* Configure the telnet daemon */ config.d_port = HTONS(CONFIG_NSH_TELNETD_PORT); diff --git a/apps/nshlib/nsh_usbdev.c b/apps/nshlib/nsh_usbdev.c index 2064cbd84..193fe0d79 100644 --- a/apps/nshlib/nsh_usbdev.c +++ b/apps/nshlib/nsh_usbdev.c @@ -1,7 +1,7 @@ /**************************************************************************** * apps/nshlib/nsh_usbdev.c * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2012-2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -55,11 +55,10 @@ #endif #include "nsh.h" - -#ifdef CONFIG_USBDEV +#include "nsh_console.h" /**************************************************************************** - * Definitions + * Pre-processor Definitions ****************************************************************************/ /* Output USB trace data to the console device using printf() unless (1) * debug is enabled, then we want to keep the trace output in sync with the @@ -98,6 +97,14 @@ * Name: nsh_tracecallback ****************************************************************************/ +/**************************************************************************** + * Name: nsh_tracecallback + * + * Description: + * This is part of the USB trace logic + * + ****************************************************************************/ + #ifdef CONFIG_NSH_USBDEV_TRACE static int nsh_tracecallback(struct usbtrace_s *trace, void *arg) { @@ -107,27 +114,96 @@ static int nsh_tracecallback(struct usbtrace_s *trace, void *arg) #endif /**************************************************************************** - * Public Functions + * Name: nsh_configstdio + * + * Description: + * Configure standard I/O + * + ****************************************************************************/ + +#ifdef HAVE_USB_CONSOLE +static void nsh_configstdio(int fd) +{ + /* 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); + + /* 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"); +} +#endif + +/**************************************************************************** + * Name: nsh_nullstdio + * + * Description: + * Use /dev/null for standard I/O + * ****************************************************************************/ +#ifdef HAVE_USB_CONSOLE +static int nsh_nullstdio(void) +{ + int fd; + + /* Open /dev/null for read/write access */ + + fd = open("/dev/null", O_RDWR); + if (fd >= 0) + { + /* Configure standard I/O to use /dev/null */ + + nsh_configstdio(fd); + + /* We can close the original file descriptor now (unless it was one of + * 0-2) + */ + + if (fd > 2) + { + close(fd); + } + + return OK; + } + + return fd; +} +#endif + /**************************************************************************** - * Name: nsh_usbconsole + * Name: nsh_waitusbready + * + * Description: + * Wait for the USB console device to be ready + * ****************************************************************************/ #ifdef HAVE_USB_CONSOLE -int nsh_usbconsole(void) +static int nsh_waitusbready(void) { char inch; ssize_t nbytes; int nlc; int fd; - int ret; - - /* Initialize any USB tracing options that were requested */ - -#ifdef CONFIG_NSH_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 @@ -135,17 +211,6 @@ int nsh_usbconsole(void) * 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_USBDEV_MINOR, NULL); -#else - ret = usbdev_serialinitialize(CONFIG_NSH_USBDEV_MINOR); -#endif - DEBUGASSERT(ret == OK); -#endif - /* Open the USB serial device for read/write access */ do @@ -199,17 +264,9 @@ int nsh_usbconsole(void) } 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 */ + /* Configure standard I/O */ - (void)dup2(fd, 0); - (void)dup2(fd, 1); - (void)dup2(fd, 2); + nsh_configstdio(fd); /* We can close the original file descriptor now (unless it was one of 0-2) */ @@ -218,33 +275,117 @@ int nsh_usbconsole(void) 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 + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_consolemain (USB console version) + * + * Description: + * This interfaces maybe to called or started with task_start to start a + * single an NSH instance that operates on stdin and stdout. This + * function does not return. + * + * This function handles generic /dev/console character devices, or + * special USB console devices. The USB console requires some special + * operations to handle the cases where the session is lost when the + * USB device is unplugged and restarted when the USB device is plugged + * in again. + * + * Input Parameters: + * Standard task start-up arguments. These are not used. argc may be + * zero and argv may be NULL. + * + * Returned Values: + * This function does not return nor does it ever exit (unless the user + * executes the NSH exit command). + * + ****************************************************************************/ + +#ifdef HAVE_USB_CONSOLE +int nsh_consolemain(int argc, char *argv[]) +{ + FAR struct console_stdio_s *pstate = nsh_newconsole(); + int ret; -#endif /* HAVE_USB_CONSOLE */ + DEBUGASSERT(pstate); + + /* Initialize any USB tracing options that were requested */ + +#ifdef CONFIG_NSH_USBDEV_TRACE + usbtrace_enable(TRACE_BITSET); +#endif + + /* Initialize the USB serial driver */ + +#if defined(CONFIG_PL2303) || defined(CONFIG_CDCACM) +#ifdef CONFIG_CDCACM + ret = cdcacm_initialize(CONFIG_NSH_USBDEV_MINOR, NULL); +#else + ret = usbdev_serialinitialize(CONFIG_NSH_USBDEV_MINOR); +#endif + DEBUGASSERT(ret == OK); +#endif + + /* Configure to use /dev/null if we do not have a valid console. */ + +#ifndef CONFIG_DEV_CONSOLE + (void)nsh_nullstdio(); +#endif + + /* Execute the one-time start-up script (output may go to /dev/null) */ + +#ifdef CONFIG_NSH_ROMFSETC + (void)nsh_initscript(&pstate->cn_vtbl); +#endif + + /* Now loop, executing creating a session for each USB connection */ + + for (;;) + { + /* Wait for the USB to be connected to the host and switch + * standard I/O to the USB serial device. + */ + + ret = nsh_waitusbready(); + DEBUGASSERT(ret == OK); + + /* Execute the session */ + + (void)nsh_session(pstate); + + /* Switch to /dev/null because we probably no longer have a + * valid console device. + */ + + (void)nsh_nullstdio(); + } +} +#endif /**************************************************************************** * Name: nsh_usbtrace + * + * Description: + * The function is called from the nsh_session() to dump USB data to the + * SYSLOG device. + * + * Input Parameters: + * None + * + * Returned Values: + * None + * ****************************************************************************/ -#if defined(CONFIG_NSH_USBDEV_TRACE) && defined(HAVE_USB_CONSOLE) +#ifdef CONFIG_NSH_USBDEV_TRACE void nsh_usbtrace(void) { (void)usbtrace_enumerate(nsh_tracecallback, NULL); } #endif - -#endif /* CONFIG_USBDEV */ -- cgit v1.2.3