cmd_otcli.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. *
  3. * Copyright (c) 2020 Project CHIP Authors
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. #include <lib/core/CHIPCore.h>
  18. #include <ChipShellCollection.h>
  19. #if CONFIG_DEVICE_LAYER
  20. #include <platform/CHIPDeviceLayer.h>
  21. #endif
  22. #if CHIP_ENABLE_OPENTHREAD
  23. #include <stdio.h>
  24. #include <lib/shell/Engine.h>
  25. #include <lib/support/CHIPArgParser.hpp>
  26. #include <lib/support/CHIPMem.h>
  27. #include <lib/support/CodeUtils.h>
  28. #include <platform/ThreadStackManager.h>
  29. #if CHIP_TARGET_STYLE_EMBEDDED
  30. #include <openthread/cli.h>
  31. #include <openthread/instance.h>
  32. #include <openthread/ip6.h>
  33. #include <openthread/link.h>
  34. #include <openthread/thread.h>
  35. #if OPENTHREAD_API_VERSION >= 85
  36. #if !CHIP_DEVICE_CONFIG_THREAD_ENABLE_CLI
  37. #ifndef SHELL_OTCLI_TX_BUFFER_SIZE
  38. #define SHELL_OTCLI_TX_BUFFER_SIZE 1024
  39. #endif
  40. static char sTxBuffer[SHELL_OTCLI_TX_BUFFER_SIZE];
  41. static constexpr uint16_t sTxLength = SHELL_OTCLI_TX_BUFFER_SIZE;
  42. #endif // !CHIP_DEVICE_CONFIG_THREAD_ENABLE_CLI)
  43. #endif
  44. #else
  45. #include <sys/types.h>
  46. #include <sys/wait.h>
  47. #include <unistd.h>
  48. #endif
  49. using namespace chip;
  50. using namespace chip::Shell;
  51. using namespace chip::Platform;
  52. using namespace chip::DeviceLayer;
  53. using namespace chip::Logging;
  54. using namespace chip::ArgParser;
  55. static chip::Shell::Engine sShellOtcliSubcommands;
  56. CHIP_ERROR cmd_otcli_help_iterator(shell_command_t * command, void * arg)
  57. {
  58. streamer_printf(streamer_get(), " %-15s %s\n\r", command->cmd_name, command->cmd_help);
  59. return CHIP_NO_ERROR;
  60. }
  61. CHIP_ERROR cmd_otcli_help(int argc, char ** argv)
  62. {
  63. sShellOtcliSubcommands.ForEachCommand(cmd_otcli_help_iterator, nullptr);
  64. return CHIP_NO_ERROR;
  65. }
  66. #if CHIP_TARGET_STYLE_EMBEDDED
  67. CHIP_ERROR cmd_otcli_dispatch(int argc, char ** argv)
  68. {
  69. CHIP_ERROR error = CHIP_NO_ERROR;
  70. // From OT CLI internal lib, kMaxLineLength = 128
  71. #define kMaxLineLength 128
  72. char buff[kMaxLineLength] = { 0 };
  73. char * buff_ptr = buff;
  74. int i = 0;
  75. VerifyOrExit(argc > 0, error = CHIP_ERROR_INVALID_ARGUMENT);
  76. for (i = 0; i < argc; i++)
  77. {
  78. size_t arg_len = strlen(argv[i]);
  79. /* Make sure that the next argument won't overflow the buffer */
  80. VerifyOrExit(buff_ptr + arg_len < buff + kMaxLineLength, error = CHIP_ERROR_BUFFER_TOO_SMALL);
  81. strncpy(buff_ptr, argv[i], arg_len);
  82. buff_ptr += arg_len;
  83. /* Make sure that there is enough buffer for a space char */
  84. if (buff_ptr + sizeof(char) < buff + kMaxLineLength)
  85. {
  86. strncpy(buff_ptr, " ", sizeof(char));
  87. buff_ptr++;
  88. }
  89. }
  90. buff_ptr = 0;
  91. chip::DeviceLayer::ThreadStackMgr().LockThreadStack();
  92. #if OPENTHREAD_API_VERSION >= 85
  93. otCliInputLine(buff);
  94. #else
  95. otCliConsoleInputLine(buff, buff_ptr - buff);
  96. #endif
  97. chip::DeviceLayer::ThreadStackMgr().UnlockThreadStack();
  98. exit:
  99. return error;
  100. }
  101. #elif CHIP_TARGET_STYLE_UNIX
  102. CHIP_ERROR cmd_otcli_dispatch(int argc, char ** argv)
  103. {
  104. int pid;
  105. uid_t euid = geteuid();
  106. char ctl_command[] = "/usr/local/sbin/ot-ctl";
  107. // Must run as sudo.
  108. if (euid != 0)
  109. {
  110. streamer_printf(streamer_get(), "Error otcli: requires running chip-shell as sudo\n\r");
  111. return CHIP_ERROR_INCORRECT_STATE;
  112. }
  113. VerifyOrReturnError(argc > 0, CHIP_ERROR_INVALID_ARGUMENT);
  114. // Fork and execute the command.
  115. pid = fork();
  116. VerifyOrReturnError(pid != -1, CHIP_ERROR_INCORRECT_STATE);
  117. if (pid == 0)
  118. {
  119. // Child process to execute the command with provided arguments
  120. --argv; // Restore access to entry [0] containing the command;
  121. argv[0] = ctl_command;
  122. if (execvp(ctl_command, argv) < 0)
  123. {
  124. streamer_printf(streamer_get(), "Error exec %s: %s\n", ctl_command, strerror(errno));
  125. }
  126. exit(errno);
  127. }
  128. else
  129. {
  130. // Parent process to wait on child.
  131. int status;
  132. wait(&status);
  133. return (status) ? CHIP_ERROR_INCORRECT_STATE : CHIP_NO_ERROR;
  134. }
  135. }
  136. #endif // CHIP_TARGET_STYLE_UNIX
  137. static const shell_command_t cmds_otcli_root = { &cmd_otcli_dispatch, "otcli", "Dispatch OpenThread CLI command" };
  138. #if CHIP_TARGET_STYLE_EMBEDDED
  139. #if OPENTHREAD_API_VERSION >= 85
  140. #if !CHIP_DEVICE_CONFIG_THREAD_ENABLE_CLI
  141. static int OnOtCliOutput(void * aContext, const char * aFormat, va_list aArguments)
  142. {
  143. int rval = vsnprintf(sTxBuffer, sTxLength, aFormat, aArguments);
  144. VerifyOrExit(rval >= 0 && rval < sTxLength, rval = CHIP_ERROR_BUFFER_TOO_SMALL.AsInteger());
  145. return streamer_write(streamer_get(), (const char *) sTxBuffer, rval);
  146. exit:
  147. return rval;
  148. }
  149. #endif // !CHIP_DEVICE_CONFIG_THREAD_ENABLE_CLI
  150. #else
  151. static int OnOtCliOutput(const char * aBuf, uint16_t aBufLength, void * aContext)
  152. {
  153. return streamer_write(streamer_get(), aBuf, aBufLength);
  154. }
  155. #endif
  156. #endif
  157. #endif // CHIP_ENABLE_OPENTHREAD
  158. void cmd_otcli_init()
  159. {
  160. #if CHIP_ENABLE_OPENTHREAD
  161. #if CHIP_TARGET_STYLE_EMBEDDED
  162. #if !CHIP_DEVICE_CONFIG_THREAD_ENABLE_CLI
  163. #if OPENTHREAD_API_VERSION >= 85
  164. otCliInit(otInstanceInitSingle(), &OnOtCliOutput, NULL);
  165. #else
  166. otCliConsoleInit(otInstanceInitSingle(), &OnOtCliOutput, NULL);
  167. #endif // OPENTHREAD_API_VERSION >= 85
  168. #endif // !CHIP_DEVICE_CONFIG_THREAD_ENABLE_CLI
  169. #endif // CHIP_TARGET_STYLE_EMBEDDED
  170. // Register the root otcli command with the top-level shell.
  171. Engine::Root().RegisterCommands(&cmds_otcli_root, 1);
  172. #endif // CHIP_ENABLE_OPENTHREAD
  173. }