• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "async_cmd.h"
16 
17 namespace Hdc {
18 // Do not add thread-specific init op in the following methods as it's running in child thread.
AsyncCmd()19 AsyncCmd::AsyncCmd()
20 {
21 }
22 
~AsyncCmd()23 AsyncCmd::~AsyncCmd()
24 {
25     if (childShell != nullptr) {
26         delete childShell;
27         childShell = nullptr;
28     }
29     WRITE_LOG(LOG_DEBUG, "~AsyncCmd");
30 };
31 
ReadyForRelease()32 bool AsyncCmd::ReadyForRelease()
33 {
34     if (childShell != nullptr && !childShell->ReadyForRelease()) {
35         return false;
36     }
37     if (refCount != 0) {
38         return false;
39     }
40     if (childShell != nullptr) {
41         delete childShell;
42         childShell = nullptr;
43     }
44     if (fd > 0) {
45         close(fd);
46     }
47     return true;
48 }
49 
DoRelease()50 void AsyncCmd::DoRelease()
51 {
52     WRITE_LOG(LOG_DEBUG, "AsyncCmd::DoRelease finish");
53     if (childShell != nullptr) {
54         childShell->StopWork(false, nullptr);
55     }
56     if (pid > 0) {
57         uv_kill(pid, SIGTERM);
58     }
59 }
60 
Initial(uv_loop_t * loopIn,const CmdResultCallback callback,uint32_t optionsIn)61 bool AsyncCmd::Initial(uv_loop_t *loopIn, const CmdResultCallback callback, uint32_t optionsIn)
62 {
63 #if defined _WIN32 || defined HDC_HOST
64     WRITE_LOG(LOG_FATAL, "Not support for win32 or host side");
65     return false;
66 #endif
67     loop = loopIn;
68     resultCallback = callback;
69     options = optionsIn;
70     return true;
71 }
72 
FinishShellProc(const void * context,const bool result,const string exitMsg)73 bool AsyncCmd::FinishShellProc(const void *context, const bool result, const string exitMsg)
74 {
75     WRITE_LOG(LOG_DEBUG, "FinishShellProc finish");
76     AsyncCmd *thisClass = (AsyncCmd *)context;
77     thisClass->resultCallback(true, result, thisClass->cmdResult + exitMsg);
78     --thisClass->refCount;
79     return true;
80 };
81 
ChildReadCallback(const void * context,uint8_t * buf,const int size)82 bool AsyncCmd::ChildReadCallback(const void *context, uint8_t *buf, const int size)
83 {
84     AsyncCmd *thisClass = (AsyncCmd *)context;
85     if (thisClass->options & OPTION_COMMAND_ONETIME) {
86         string s((char *)buf, size);
87         thisClass->cmdResult += s;
88         return true;
89     }
90     string s((char *)buf, size);
91     return thisClass->resultCallback(false, 0, s);
92 };
93 
Popen(string command,bool readWrite,int & pid)94 int AsyncCmd::Popen(string command, bool readWrite, int &pid)
95 {
96 #ifdef _WIN32
97     return ERR_NO_SUPPORT;
98 #else
99     constexpr uint8_t PIPE_READ = 0;
100     constexpr uint8_t PIPE_WRITE = 1;
101     pid_t childPid;
102     int fd[2];
103     pipe(fd);
104 
105     if ((childPid = fork()) == -1) {
106         return ERR_GENERIC;
107     }
108     if (childPid == 0) {
109         if (readWrite) {
110             dup2(fd[PIPE_WRITE], STDOUT_FILENO);
111             dup2(fd[PIPE_WRITE], STDERR_FILENO);
112         } else {
113             dup2(fd[PIPE_READ], STDIN_FILENO);
114         }
115         close(fd[PIPE_READ]);
116         close(fd[PIPE_WRITE]);
117 
118         setsid();
119         setpgid(childPid, childPid);
120         string shellPath = Base::GetShellPath();
121         execl(shellPath.c_str(), shellPath.c_str(), "-c", command.c_str(), NULL);
122         exit(0);
123     } else {
124         if (readWrite) {
125             close(fd[PIPE_WRITE]);
126             fcntl(fd[PIPE_READ], F_SETFD, FD_CLOEXEC);
127         } else {
128             close(fd[PIPE_READ]);
129             fcntl(fd[PIPE_WRITE], F_SETFD, FD_CLOEXEC);
130         }
131     }
132     pid = childPid;
133     if (readWrite) {
134         return fd[PIPE_READ];
135     } else {
136         return fd[PIPE_WRITE];
137     }
138 #endif
139 }
140 
ExecuteCommand(const string & command)141 bool AsyncCmd::ExecuteCommand(const string &command)
142 {
143     string cmd = command;
144     Base::Trim(cmd, "\"");
145     if ((fd = Popen(cmd, true, pid)) < 0) {
146         return false;
147     }
148     childShell = new(std::nothrow) HdcFileDescriptor(loop, fd, this, ChildReadCallback, FinishShellProc);
149     if (childShell == nullptr) {
150         WRITE_LOG(LOG_FATAL, "ExecuteCommand new childShell failed");
151         return false;
152     }
153     if (!childShell->StartWork()) {
154         return false;
155     }
156     ++refCount;
157     return true;
158 }
159 }  // namespace Hdc
160