cmd_otcli.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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 <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. #if OPENTHREAD_API_VERSION >= 85
  90. otCliInputLine(buff);
  91. #else
  92. otCliConsoleInputLine(buff, buff_ptr - buff);
  93. #endif
  94. exit:
  95. return error;
  96. }
  97. #elif CHIP_TARGET_STYLE_UNIX
  98. CHIP_ERROR cmd_otcli_dispatch(int argc, char ** argv)
  99. {
  100. int pid;
  101. uid_t euid = geteuid();
  102. char ctl_command[] = "/usr/local/sbin/ot-ctl";
  103. // Must run as sudo.
  104. if (euid != 0)
  105. {
  106. streamer_printf(streamer_get(), "Error otcli: requires running chip-shell as sudo\n\r");
  107. return CHIP_ERROR_INCORRECT_STATE;
  108. }
  109. VerifyOrReturnError(argc > 0, CHIP_ERROR_INVALID_ARGUMENT);
  110. // Fork and execute the command.
  111. pid = fork();
  112. VerifyOrReturnError(pid != -1, CHIP_ERROR_INCORRECT_STATE);
  113. if (pid == 0)
  114. {
  115. // Child process to execute the command with provided arguments
  116. --argv; // Restore access to entry [0] containing the command;
  117. argv[0] = ctl_command;
  118. if (execvp(ctl_command, argv) < 0)
  119. {
  120. streamer_printf(streamer_get(), "Error exec %s: %s\n", ctl_command, strerror(errno));
  121. }
  122. exit(errno);
  123. }
  124. else
  125. {
  126. // Parent process to wait on child.
  127. int status;
  128. wait(&status);
  129. return (status) ? CHIP_ERROR_INCORRECT_STATE : CHIP_NO_ERROR;
  130. }
  131. }
  132. #endif // CHIP_TARGET_STYLE_UNIX
  133. static const shell_command_t cmds_otcli_root = { &cmd_otcli_dispatch, "otcli", "Dispatch OpenThread CLI command" };
  134. #if CHIP_TARGET_STYLE_EMBEDDED
  135. #if OPENTHREAD_API_VERSION >= 85
  136. static int OnOtCliOutput(void * aContext, const char * aFormat, va_list aArguments)
  137. {
  138. int rval = vsnprintf(sTxBuffer, sTxLength, aFormat, aArguments);
  139. VerifyOrExit(rval >= 0 && rval < sTxLength, rval = CHIP_ERROR_BUFFER_TOO_SMALL);
  140. return streamer_write(streamer_get(), (const char *) sTxBuffer, rval);
  141. exit:
  142. return rval;
  143. }
  144. #else
  145. static int OnOtCliOutput(const char * aBuf, uint16_t aBufLength, void * aContext)
  146. {
  147. return streamer_write(streamer_get(), aBuf, aBufLength);
  148. }
  149. #endif
  150. #endif
  151. #endif // CHIP_ENABLE_OPENTHREAD
  152. void cmd_otcli_init()
  153. {
  154. #if CHIP_ENABLE_OPENTHREAD
  155. #if CHIP_TARGET_STYLE_EMBEDDED
  156. #if OPENTHREAD_API_VERSION >= 85
  157. otCliInit(otInstanceInitSingle(), &OnOtCliOutput, NULL);
  158. #else
  159. otCliConsoleInit(otInstanceInitSingle(), &OnOtCliOutput, NULL);
  160. #endif
  161. #endif
  162. // Register the root otcli command with the top-level shell.
  163. Engine::Root().RegisterCommands(&cmds_otcli_root, 1);
  164. #endif // CHIP_ENABLE_OPENTHREAD
  165. }