Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / examples / shell / shell_common / cmd_otcli.cpp
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
18 #include <core/CHIPCore.h>
19
20 #include <ChipShellCollection.h>
21
22 #if CONFIG_DEVICE_LAYER
23 #include <platform/CHIPDeviceLayer.h>
24 #endif
25
26 #if CHIP_ENABLE_OPENTHREAD
27
28 #include <stdio.h>
29
30 #include <lib/shell/shell.h>
31 #include <lib/support/CHIPArgParser.hpp>
32 #include <lib/support/CHIPMem.h>
33 #include <lib/support/CodeUtils.h>
34 #include <platform/ThreadStackManager.h>
35
36 #if CHIP_TARGET_STYLE_EMBEDDED
37 #include <openthread/cli.h>
38 #include <openthread/instance.h>
39 #include <openthread/ip6.h>
40 #include <openthread/link.h>
41 #include <openthread/thread.h>
42 #else
43 #include <sys/types.h>
44 #include <sys/wait.h>
45 #include <unistd.h>
46 #endif
47
48 using namespace chip;
49 using namespace chip::Shell;
50 using namespace chip::Platform;
51 using namespace chip::DeviceLayer;
52 using namespace chip::Logging;
53 using namespace chip::ArgParser;
54
55 static chip::Shell::Shell sShellOtcliSubcommands;
56
57 int cmd_otcli_help_iterator(shell_command_t * command, void * arg)
58 {
59     streamer_printf(streamer_get(), "  %-15s %s\n\r", command->cmd_name, command->cmd_help);
60     return 0;
61 }
62
63 int cmd_otcli_help(int argc, char ** argv)
64 {
65     sShellOtcliSubcommands.ForEachCommand(cmd_otcli_help_iterator, nullptr);
66     return 0;
67 }
68
69 #if CHIP_TARGET_STYLE_EMBEDDED
70
71 int cmd_otcli_dispatch(int argc, char ** argv)
72 {
73     CHIP_ERROR error = CHIP_NO_ERROR;
74
75 // From OT CLI internal lib, kMaxLineLength = 128
76 #define kMaxLineLength 128
77     char buff[kMaxLineLength] = { 0 };
78     char * buff_ptr           = buff;
79     int i                     = 0;
80
81     VerifyOrExit(argc > 0, error = CHIP_ERROR_INVALID_ARGUMENT);
82
83     for (i = 0; i < argc; i++)
84     {
85         size_t arg_len = strlen(argv[i]);
86
87         /* Make sure that the next argument won't overflow the buffer */
88         VerifyOrExit(buff_ptr + arg_len < buff + kMaxLineLength, error = CHIP_ERROR_BUFFER_TOO_SMALL);
89
90         strncpy(buff_ptr, argv[i], arg_len);
91         buff_ptr += arg_len;
92
93         /* Make sure that there is enough buffer for a space char */
94         if (buff_ptr + sizeof(char) < buff + kMaxLineLength)
95         {
96             strncpy(buff_ptr, " ", sizeof(char));
97             buff_ptr++;
98         }
99     }
100     buff_ptr = 0;
101
102     otCliConsoleInputLine(buff, buff_ptr - buff);
103 exit:
104     return error;
105 }
106
107 #elif CHIP_TARGET_STYLE_UNIX
108
109 int cmd_otcli_dispatch(int argc, char ** argv)
110 {
111     CHIP_ERROR error = CHIP_NO_ERROR;
112
113     int pid;
114     uid_t euid         = geteuid();
115     char ctl_command[] = "/usr/local/sbin/ot-ctl";
116
117     // Must run as sudo.
118     if (euid != 0)
119     {
120         streamer_printf(streamer_get(), "Error otcli: requires running chip-shell as sudo\n\r");
121         error = CHIP_ERROR_INCORRECT_STATE;
122         ExitNow();
123     }
124
125     VerifyOrExit(argc > 0, error = CHIP_ERROR_INVALID_ARGUMENT);
126
127     // Fork and execute the command.
128     pid = fork();
129     VerifyOrExit(pid != -1, error = CHIP_ERROR_INCORRECT_STATE);
130
131     if (pid == 0)
132     {
133         // Child process to execute the command with provided arguments
134         --argv; // Restore access to entry [0] containing the command;
135         argv[0] = ctl_command;
136         if (execvp(ctl_command, argv) < 0)
137         {
138             streamer_printf(streamer_get(), "Error exec %s: %s\n", ctl_command, strerror(errno));
139         }
140         exit(errno);
141     }
142     else
143     {
144         // Parent process to wait on child.
145         int status;
146         wait(&status);
147         error = (status) ? CHIP_ERROR_INCORRECT_STATE : CHIP_NO_ERROR;
148     }
149
150 exit:
151     return error;
152 }
153
154 #endif // CHIP_TARGET_STYLE_UNIX
155
156 static const shell_command_t cmds_otcli_root = { &cmd_otcli_dispatch, "otcli", "Dispatch OpenThread CLI command" };
157
158 #if CHIP_TARGET_STYLE_EMBEDDED
159 static int OnOtCliOutput(const char * aBuf, uint16_t aBufLength, void * aContext)
160 {
161     return streamer_write(streamer_get(), aBuf, aBufLength);
162 }
163 #endif
164
165 #endif // CHIP_ENABLE_OPENTHREAD
166
167 void cmd_otcli_init()
168 {
169 #if CHIP_ENABLE_OPENTHREAD
170 #if CHIP_TARGET_STYLE_EMBEDDED
171     otCliConsoleInit(otInstanceInitSingle(), &OnOtCliOutput, NULL);
172 #endif
173
174     // Register the root otcli command with the top-level shell.
175     shell_register(&cmds_otcli_root, 1);
176 #endif // CHIP_ENABLE_OPENTHREAD
177 }