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