• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <errno.h>
16 #include <fcntl.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <termios.h>
20 #include <unistd.h>
21 
22 #include "beget_ext.h"
23 #include "control_fd.h"
24 #include "securec.h"
25 
ProcessPtyWrite(const WatcherHandle taskHandle,int fd,uint32_t * events,const void * context)26 CONTROL_FD_STATIC void ProcessPtyWrite(const WatcherHandle taskHandle, int fd, uint32_t *events, const void *context)
27 {
28     if ((fd < 0) || (events == NULL) || (context == NULL)) {
29         BEGET_LOGE("[control_fd] Invalid fifo write parameter");
30         return;
31     }
32     CmdAgent *agent = (CmdAgent *)context;
33     char rbuf[PTY_BUF_SIZE] = {0};
34     ssize_t rlen = read(fd, rbuf, PTY_BUF_SIZE - 1);
35     int ret = fflush(stdin);
36     BEGET_ERROR_CHECK(ret == 0, return, "[control_fd] Failed fflush err=%d", errno);
37     if (rlen > 0) {
38         ssize_t wlen = write(agent->ptyFd, rbuf, rlen);
39         BEGET_ERROR_CHECK(wlen == rlen, return, "[control_fd] Failed write fifo err=%d", errno);
40     }
41     ret = fflush(stdout);
42     BEGET_ERROR_CHECK(ret == 0, return, "[control_fd] Failed fflush err=%d", errno);
43     *events = Event_Read;
44 }
45 
ProcessPtyRead(const WatcherHandle taskHandle,int fd,uint32_t * events,const void * context)46 CONTROL_FD_STATIC void ProcessPtyRead(const WatcherHandle taskHandle, int fd, uint32_t *events, const void *context)
47 {
48     if ((fd < 0) || (events == NULL) || (context == NULL)) {
49         BEGET_LOGE("[control_fd] Invalid fifo read parameter");
50         return;
51     }
52     CmdAgent *agent = (CmdAgent *)context;
53     char buf[PTY_BUF_SIZE] = {0};
54     long readlen = read(fd, buf, PTY_BUF_SIZE - 1);
55     if (readlen > 0) {
56         fprintf(stdout, "%s", buf);
57     } else {
58         (void)close(agent->ptyFd);
59         return;
60     }
61     int ret = fflush(stdout);
62     BEGET_ERROR_CHECK(ret == 0, return, "[control_fd] Failed fflush err=%d", errno);
63     *events = Event_Read;
64 }
65 
CmdClientOnRecvMessage(const TaskHandle task,const uint8_t * buffer,uint32_t buffLen)66 CONTROL_FD_STATIC void CmdClientOnRecvMessage(const TaskHandle task, const uint8_t *buffer, uint32_t buffLen)
67 {
68     BEGET_LOGI("[control_fd] CmdOnRecvMessage %s len %d.", (char *)buffer, buffLen);
69 }
70 
CmdOnConnectComplete(const TaskHandle client)71 CONTROL_FD_STATIC void CmdOnConnectComplete(const TaskHandle client)
72 {
73     BEGET_LOGI("[control_fd] CmdOnConnectComplete");
74 }
75 
CmdOnClose(const TaskHandle task)76 CONTROL_FD_STATIC void CmdOnClose(const TaskHandle task)
77 {
78     BEGET_LOGI("[control_fd] CmdOnClose");
79     CmdAgent *agent = (CmdAgent *)LE_GetUserData(task);
80     BEGET_ERROR_CHECK(agent != NULL, return, "[control_fd] Invalid agent");
81     (void)close(agent->ptyFd);
82     agent->ptyFd = -1;
83     LE_StopLoop(LE_GetDefaultLoop());
84 }
85 
CmdDisConnectComplete(const TaskHandle client)86 CONTROL_FD_STATIC void CmdDisConnectComplete(const TaskHandle client)
87 {
88     BEGET_LOGI("[control_fd] CmdDisConnectComplete");
89 }
90 
CmdOnSendMessageComplete(const TaskHandle task,const BufferHandle handle)91 CONTROL_FD_STATIC void CmdOnSendMessageComplete(const TaskHandle task, const BufferHandle handle)
92 {
93     BEGET_LOGI("[control_fd] CmdOnSendMessageComplete");
94 }
95 
CmdAgentCreate(const char * server)96 CONTROL_FD_STATIC CmdAgent *CmdAgentCreate(const char *server)
97 {
98     if (server == NULL) {
99         BEGET_LOGE("[control_fd] Invalid parameter");
100         return NULL;
101     }
102     TaskHandle task = NULL;
103     LE_StreamInfo info = {};
104     info.baseInfo.flags = TASK_STREAM | TASK_PIPE | TASK_CONNECT;
105     info.server = (char *)server;
106     info.baseInfo.userDataSize = sizeof(CmdAgent);
107     info.baseInfo.close = CmdOnClose;
108     info.disConnectComplete = CmdDisConnectComplete;
109     info.connectComplete = CmdOnConnectComplete;
110     info.sendMessageComplete = CmdOnSendMessageComplete;
111     info.recvMessage = CmdClientOnRecvMessage;
112     LE_STATUS status = LE_CreateStreamClient(LE_GetDefaultLoop(), &task, &info);
113     BEGET_ERROR_CHECK(status == 0, return NULL, "[control_fd] Failed create client");
114     CmdAgent *agent = (CmdAgent *)LE_GetUserData(task);
115     BEGET_ERROR_CHECK(agent != NULL, return NULL, "[control_fd] Invalid agent");
116     agent->task = task;
117     return agent;
118 }
119 
SendCmdMessage(const CmdAgent * agent,uint16_t type,const char * cmd,const char * ptyName)120 CONTROL_FD_STATIC int SendCmdMessage(const CmdAgent *agent, uint16_t type, const char *cmd, const char *ptyName)
121 {
122     if ((agent == NULL) || (cmd == NULL) || (ptyName == NULL)) {
123         BEGET_LOGE("[control_fd] Invalid parameter");
124         return -1;
125     }
126     BufferHandle handle = NULL;
127     uint32_t bufferSize = sizeof(CmdMessage) + strlen(cmd) + PTY_PATH_SIZE + 1;
128     handle = LE_CreateBuffer(LE_GetDefaultLoop(), bufferSize);
129     char *buff = (char *)LE_GetBufferInfo(handle, NULL, NULL);
130     BEGET_ERROR_CHECK(buff != NULL, return -1, "[control_fd] Failed get buffer info");
131     CmdMessage *message = (CmdMessage *)buff;
132     message->msgSize = bufferSize;
133     message->type = type;
134     int ret = strcpy_s(message->ptyName, PTY_PATH_SIZE - 1, ptyName);
135     BEGET_ERROR_CHECK(ret == 0, LE_FreeBuffer(LE_GetDefaultLoop(), agent->task, handle);
136         return -1, "[control_fd] Failed to copy pty name %s", ptyName);
137     ret = strcpy_s(message->cmd, bufferSize - sizeof(CmdMessage) - PTY_PATH_SIZE, cmd);
138     BEGET_ERROR_CHECK(ret == 0, LE_FreeBuffer(LE_GetDefaultLoop(), agent->task, handle);
139         return -1, "[control_fd] Failed to copy cmd %s", cmd);
140     ret = LE_Send(LE_GetDefaultLoop(), agent->task, handle, bufferSize);
141     BEGET_ERROR_CHECK(ret == 0, return -1, "[control_fd] Failed LE_Send msg type %d, cmd %s",
142         message->type, message->cmd);
143     return 0;
144 }
145 
InitPtyInterface(CmdAgent * agent,uint16_t type,const char * cmd)146 CONTROL_FD_STATIC int InitPtyInterface(CmdAgent *agent, uint16_t type, const char *cmd)
147 {
148     if ((cmd == NULL) || (agent == NULL)) {
149         return -1;
150     }
151 #ifndef STARTUP_INIT_TEST
152     // initialize terminal
153     struct termios term;
154     int ret = tcgetattr(STDIN_FILENO, &term);
155     BEGET_ERROR_CHECK(ret == 0, return -1, "Failed tcgetattr stdin, err=%d", errno);
156     cfmakeraw(&term);
157     term.c_cc[VTIME] = 0;
158     term.c_cc[VMIN] = 1;
159     ret = tcsetattr(STDIN_FILENO, TCSANOW, &term);
160     BEGET_ERROR_CHECK(ret == 0, return -1, "Failed tcsetattr term, err=%d", errno);
161     // open master pty and get slave pty
162     int pfd = open("/dev/ptmx", O_RDWR | O_CLOEXEC);
163     BEGET_ERROR_CHECK(pfd >= 0, return -1, "Failed open pty err=%d", errno);
164     BEGET_ERROR_CHECK(grantpt(pfd) >= 0, close(pfd); return -1, "Failed to call grantpt");
165     BEGET_ERROR_CHECK(unlockpt(pfd) >= 0, close(pfd); return -1, "Failed to call unlockpt");
166     char ptsbuffer[PTY_PATH_SIZE] = {0};
167     ret = ptsname_r(pfd, ptsbuffer, sizeof(ptsbuffer));
168     BEGET_ERROR_CHECK(ret >= 0, close(pfd); return -1, "Failed to get pts name err=%d", errno);
169     BEGET_LOGI("ptsbuffer is %s", ptsbuffer);
170     agent->ptyFd = pfd;
171 
172     LE_WatchInfo info = {};
173     info.flags = 0;
174     info.events = Event_Read;
175     info.processEvent = ProcessPtyRead;
176     info.fd = pfd; // read ptmx
177     BEGET_ERROR_CHECK(LE_StartWatcher(LE_GetDefaultLoop(), &agent->reader, &info, agent) == LE_SUCCESS,
178         close(pfd); return -1, "[control_fd] Failed le_loop start watcher ptmx read");
179     info.processEvent = ProcessPtyWrite;
180     info.fd = STDIN_FILENO; // read stdin and write ptmx
181     BEGET_ERROR_CHECK(LE_StartWatcher(LE_GetDefaultLoop(), &agent->input, &info, agent) == LE_SUCCESS,
182         close(pfd); return -1, "[control_fd] Failed le_loop start watcher stdin read and write ptmx");
183     ret = SendCmdMessage(agent, type, cmd, ptsbuffer);
184     BEGET_ERROR_CHECK(ret == 0, close(pfd); return -1, "[control_fd] Failed send message");
185 #endif
186     return 0;
187 }
188 
CmdClientInit(const char * socketPath,uint16_t type,const char * cmd)189 void CmdClientInit(const char *socketPath, uint16_t type, const char *cmd)
190 {
191     if ((socketPath == NULL) || (cmd == NULL)) {
192         BEGET_LOGE("[control_fd] Invalid parameter");
193     }
194     BEGET_LOGI("[control_fd] CmdAgentInit");
195     CmdAgent *agent = CmdAgentCreate(socketPath);
196     BEGET_ERROR_CHECK(agent != NULL, return, "[control_fd] Failed to create agent");
197 #ifndef STARTUP_INIT_TEST
198     int ret = InitPtyInterface(agent, type, cmd);
199     if (ret != 0) {
200         return;
201     }
202     LE_RunLoop(LE_GetDefaultLoop());
203     LE_CloseLoop(LE_GetDefaultLoop());
204 #endif
205     BEGET_LOGI("Cmd Client exit ");
206 }
207