cmd_otcli.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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. #ifndef SHELL_OTCLI_TX_BUFFER_SIZE
  37. #define SHELL_OTCLI_TX_BUFFER_SIZE 1024
  38. #endif
  39. static char sTxBuffer[SHELL_OTCLI_TX_BUFFER_SIZE];
  40. static constexpr uint16_t sTxLength = SHELL_OTCLI_TX_BUFFER_SIZE;
  41. #endif
  42. #else
  43. #include <sys/types.h>
  44. #include <sys/wait.h>
  45. #include <unistd.h>
  46. #endif
  47. using namespace chip;
  48. using namespace chip::Shell;
  49. using namespace chip::Platform;
  50. using namespace chip::DeviceLayer;
  51. using namespace chip::Logging;
  52. using namespace chip::ArgParser;
  53. static chip::Shell::Engine sShellOtcliSubcommands;
  54. CHIP_ERROR cmd_otcli_help_iterator(shell_command_t * command, void * arg)
  55. {
  56. streamer_printf(streamer_get(), " %-15s %s\n\r", command->cmd_name, command->cmd_help);
  57. return CHIP_NO_ERROR;
  58. }
  59. CHIP_ERROR cmd_otcli_help(int argc, char ** argv)
  60. {
  61. sShellOtcliSubcommands.ForEachCommand(cmd_otcli_help_iterator, nullptr);
  62. return CHIP_NO_ERROR;
  63. }
  64. #if CHIP_TARGET_STYLE_EMBEDDED
  65. CHIP_ERROR cmd_otcli_dispatch(int argc, char ** argv)
  66. {
  67. CHIP_ERROR error = CHIP_NO_ERROR;
  68. // From OT CLI internal lib, kMaxLineLength = 128
  69. #define kMaxLineLength 128
  70. char buff[kMaxLineLength] = { 0 };
  71. char * buff_ptr = buff;
  72. int i = 0;
  73. VerifyOrExit(argc > 0, error = CHIP_ERROR_INVALID_ARGUMENT);
  74. for (i = 0; i < argc; i++)
  75. {
  76. size_t arg_len = strlen(argv[i]);
  77. /* Make sure that the next argument won't overflow the buffer */
  78. VerifyOrExit(buff_ptr + arg_len < buff + kMaxLineLength, error = CHIP_ERROR_BUFFER_TOO_SMALL);
  79. strncpy(buff_ptr, argv[i], arg_len);
  80. buff_ptr += arg_len;
  81. /* Make sure that there is enough buffer for a space char */
  82. if (buff_ptr + sizeof(char) < buff + kMaxLineLength)
  83. {
  84. strncpy(buff_ptr, " ", sizeof(char));
  85. buff_ptr++;
  86. }
  87. }
  88. buff_ptr = 0;
  89. chip::DeviceLayer::ThreadStackMgr().LockThreadStack();
  90. #if OPENTHREAD_API_VERSION >= 85
  91. otCliInputLine(buff);
  92. #else
  93. otCliConsoleInputLine(buff, buff_ptr - buff);
  94. #endif
  95. chip::DeviceLayer::ThreadStackMgr().UnlockThreadStack();
  96. exit:
  97. return error;
  98. }
  99. #elif CHIP_TARGET_STYLE_UNIX
  100. CHIP_ERROR cmd_otcli_dispatch(int argc, char ** argv)
  101. {
  102. int pid;
  103. uid_t euid = geteuid();
  104. char ctl_command[] = "/usr/local/sbin/ot-ctl";
  105. // Must run as sudo.
  106. if (euid != 0)
  107. {
  108. streamer_printf(streamer_get(), "Error otcli: requires running chip-shell as sudo\n\r");
  109. return CHIP_ERROR_INCORRECT_STATE;
  110. }
  111. VerifyOrReturnError(argc > 0, CHIP_ERROR_INVALID_ARGUMENT);
  112. // Fork and execute the command.
  113. pid = fork();
  114. VerifyOrReturnError(pid != -1, CHIP_ERROR_INCORRECT_STATE);
  115. if (pid == 0)
  116. {
  117. // Child process to execute the command with provided arguments
  118. --argv; // Restore access to entry [0] containing the command;
  119. argv[0] = ctl_command;
  120. if (execvp(ctl_command, argv) < 0)
  121. {
  122. streamer_printf(streamer_get(), "Error exec %s: %s\n", ctl_command, strerror(errno));
  123. }
  124. exit(errno);
  125. }
  126. else
  127. {
  128. // Parent process to wait on child.
  129. int status;
  130. wait(&status);
  131. return (status) ? CHIP_ERROR_INCORRECT_STATE : CHIP_NO_ERROR;
  132. }
  133. }
  134. #endif // CHIP_TARGET_STYLE_UNIX
  135. static const shell_command_t cmds_otcli_root = { &cmd_otcli_dispatch, "otcli", "Dispatch OpenThread CLI command" };
  136. #if CHIP_TARGET_STYLE_EMBEDDED
  137. #if OPENTHREAD_API_VERSION >= 85
  138. static int OnOtCliOutput(void * aContext, const char * aFormat, va_list aArguments)
  139. {
  140. int rval = vsnprintf(sTxBuffer, sTxLength, aFormat, aArguments);
  141. VerifyOrExit(rval >= 0 && rval < sTxLength, rval = CHIP_ERROR_BUFFER_TOO_SMALL.AsInteger());
  142. return streamer_write(streamer_get(), (const char *) sTxBuffer, rval);
  143. exit:
  144. return rval;
  145. }
  146. #else
  147. static int OnOtCliOutput(const char * aBuf, uint16_t aBufLength, void * aContext)
  148. {
  149. return streamer_write(streamer_get(), aBuf, aBufLength);
  150. }
  151. #endif
  152. #endif
  153. #endif // CHIP_ENABLE_OPENTHREAD
  154. void cmd_otcli_init()
  155. {
  156. #if CHIP_ENABLE_OPENTHREAD
  157. #if CHIP_TARGET_STYLE_EMBEDDED
  158. #if OPENTHREAD_API_VERSION >= 85
  159. otCliInit(otInstanceInitSingle(), &OnOtCliOutput, NULL);
  160. #else
  161. otCliConsoleInit(otInstanceInitSingle(), &OnOtCliOutput, NULL);
  162. #endif
  163. #endif
  164. // Register the root otcli command with the top-level shell.
  165. Engine::Root().RegisterCommands(&cmds_otcli_root, 1);
  166. #endif // CHIP_ENABLE_OPENTHREAD
  167. }