cmd_otcli.cpp 4.6 KB

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