diff --git a/examples/nsh/nsh_main.c b/examples/nsh/nsh_main.c index 2a81d5425..f55160c58 100644 --- a/examples/nsh/nsh_main.c +++ b/examples/nsh/nsh_main.c @@ -153,10 +153,13 @@ int nsh_main(int argc, char *argv[]) nsh_initialize(); /* If the Telnet console is selected as a front-end, then start the - * Telnet daemon. + * Telnet daemon UNLESS network initialization is deferred via + * CONFIG_NSH_NETLOCAL. In that case, the telnet daemon must be + * started manually with the telnetd command after the network has + * been initialized */ -#ifdef CONFIG_NSH_TELNET +#if defined(CONFIG_NSH_TELNET) && !defined(CONFIG_NSH_NETLOCAL) ret = nsh_telnetstart(); if (ret < 0) { diff --git a/nshlib/Kconfig b/nshlib/Kconfig index cabfd52b2..d5b37672b 100644 --- a/nshlib/Kconfig +++ b/nshlib/Kconfig @@ -483,6 +483,11 @@ config NSH_DISABLE_TEST bool "Disable test" default n +config NSH_DISABLE_TELNETD + bool "Disable telnetd" + default n if !NSH_NETLOCAL + default y if NSH_NETLOCAL + config NSH_DISABLE_UMOUNT bool "Disable umount" default n diff --git a/nshlib/README.txt b/nshlib/README.txt index 8edf053b7..0bf4a50f7 100644 --- a/nshlib/README.txt +++ b/nshlib/README.txt @@ -1080,6 +1080,21 @@ o sleep Pause execution (sleep) of seconds. +o telnetd + + The Telnet daemon may be started either programmatically by calling + nsh_telnetstart() or it may be started from the NSH command line using + this telnetd command. + + Normally this command would be suppressed with CONFIG_NSH_DISABLE_TELNETD + because the Telnet daemon is automatically started in nsh_main.c. The + exception is when CONFIG_NSH_NETLOCAL is selected. IN that case, the + network is not enabled at initialization but rather must be enabled from + the NSH command line or via other applications. + + In that case, calling nsh_telnetstart() before the the network is + initialized will fail. + o time "" Perform command timing. This command will execute the following @@ -1274,6 +1289,7 @@ Command Dependencies on Configuration Settings shutdown CONFIG_BOARDCTL_POWEROFF || CONFIG_BOARDCTL_RESET sleep !CONFIG_DISABLE_SIGNALS test !CONFIG_NSH_DISABLESCRIPT + telnetd CONFIG_NSH_TELNET && !CONFIG_NSH_DISABLE_TELNETD time --- umount !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_READABLE uname !CONFIG_NSH_DISABLE_UNAME diff --git a/nshlib/nsh.h b/nshlib/nsh.h index 73cfe9ec5..637a975cc 100644 --- a/nshlib/nsh.h +++ b/nshlib/nsh.h @@ -1187,6 +1187,11 @@ int cmd_lsmod(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); int cmd_wget(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); # endif # endif +# if defined(CONFIG_NSH_TELNET) +# ifndef CONFIG_NSH_DISABLE_TELNETD + int cmd_telnetd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# endif #endif /* CONFIG_NET */ #if defined(CONFIG_LIBC_NETDB) && defined(CONFIG_NETDB_DNSCLIENT) && \ diff --git a/nshlib/nsh_command.c b/nshlib/nsh_command.c index 2d8b731d2..9bd8d36f5 100644 --- a/nshlib/nsh_command.c +++ b/nshlib/nsh_command.c @@ -472,6 +472,10 @@ static const struct cmdmap_s g_cmdmap[] = { "test", cmd_test, 3, CONFIG_NSH_MAXARGUMENTS, "" }, #endif +#if defined(CONFIG_NSH_TELNET) && !defined(CONFIG_NSH_DISABLE_TELNETD) + {"telnetd", cmd_telnetd, 1, 1, NULL }, +#endif + #ifndef CONFIG_NSH_DISABLE_TIME { "time", cmd_time, 2, 2, "\"\"" }, #endif diff --git a/nshlib/nsh_telnetd.c b/nshlib/nsh_telnetd.c index 74a9ab82d..e8fec92c1 100644 --- a/nshlib/nsh_telnetd.c +++ b/nshlib/nsh_telnetd.c @@ -1,7 +1,7 @@ /**************************************************************************** * apps/nshlib/nsh_telnetd.c * - * Copyright (C) 2007-2013, 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2013, 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -39,7 +39,9 @@ #include +#include #include +#include #include #include @@ -51,6 +53,23 @@ #ifdef CONFIG_NSH_TELNET +/**************************************************************************** + * Private Types + ****************************************************************************/ + +enum telnetd_state_e +{ + TELNETD_NOTRUNNING = 0, + TELNETD_STARTED, + TELNETD_RUNNING +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static enum telnetd_state_e g_telnetd_state; + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -64,8 +83,9 @@ static int nsh_telnetmain(int argc, char *argv[]) FAR struct console_stdio_s *pstate = nsh_newconsole(); FAR struct nsh_vtbl_s *vtbl; - DEBUGASSERT(pstate != NULL); - vtbl = &pstate->cn_vtbl; + DEBUGASSERT(pstate != NULL && g_telnetd_state == TELNETD_STARTED); + vtbl = &pstate->cn_vtbl; + g_telnetd_state = TELNETD_RUNNING; _info("Session [%d] Started\n", getpid()); @@ -75,6 +95,7 @@ static int nsh_telnetmain(int argc, char *argv[]) if (nsh_telnetlogin(pstate) != OK) { nsh_exit(vtbl, 1); + g_telnetd_state = TELNETD_NOTRUNNING; return -1; /* nsh_exit does not return */ } #endif /* CONFIG_NSH_TELNET_LOGIN */ @@ -141,12 +162,14 @@ static int nsh_telnetmain(int argc, char *argv[]) { fprintf(pstate->cn_outstream, g_fmtcmdfailed, "nsh_telnetmain", "fgets", NSH_ERRNO); + g_telnetd_state = TELNETD_NOTRUNNING; nsh_exit(vtbl, 1); } } /* Clean up */ + g_telnetd_state = TELNETD_NOTRUNNING; nsh_exit(vtbl, 0); /* We do not get here, but this is necessary to keep some compilers happy */ @@ -178,37 +201,82 @@ static int nsh_telnetmain(int argc, char *argv[]) int nsh_telnetstart(void) { - struct telnetd_config_s config; - int ret; + int ret = OK; - /* 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 (g_telnetd_state == TELNETD_NOTRUNNING) + { + struct telnetd_config_s config; + + /* There is a tiny race condition here if two tasks were to try to + * start the Telnet daemon concurrently. + */ + + g_telnetd_state = TELNETD_STARTED; + + /* 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); + usbtrace_enable(TRACE_BITSET); #endif - /* Configure the telnet daemon */ + /* 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; + 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 */ + /* Start the telnet daemon */ - _info("Starting the Telnet daemon\n"); - ret = telnetd_start(&config); - if (ret < 0) - { - _err("ERROR: Failed to tart the Telnet daemon: %d\n", ret); + _info("Starting the Telnet daemon\n"); + + ret = telnetd_start(&config); + if (ret < 0) + { + _err("ERROR: Failed to tart the Telnet daemon: %d\n", ret); + g_telnetd_state = TELNETD_NOTRUNNING; + } } return ret; } +/**************************************************************************** + * Name: cmd_telnetd + * + * Description: + * The Telnet daemon may be started either programmatically by calling + * nsh_telnetstart() or it may be started from the NSH command line using + * this telnetd command. + * + * Normally this command would be suppressed with CONFIG_NSH_DISABLE_TELNETD + * because the Telnet daemon is automatically started in nsh_main.c. The + * exception is when CONFIG_NSH_NETLOCAL is selected. IN that case, the + * network is not enabled at initialization but rather must be enabled from + * the NSH command line or via other applications. + * + * In that case, calling nsh_telnetstart() before the the network is + * initialized will fail. + * + * Input Parameters: + * None. All of the properties of the Telnet daemon are controlled by + * NuttX configuration setting. + * + * Returned Values: + * OK is returned on success; ERROR is return on failure. + * + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_TELNETD +int cmd_telnetd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + return nsh_telnetstart() < 0 ? ERROR : OK; +} +#endif + #endif /* CONFIG_NSH_TELNET */