• 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     Base::CloseFd(fd);
45     return true;
46 }
47 
DoRelease()48 void AsyncCmd::DoRelease()
49 {
50     WRITE_LOG(LOG_DEBUG, "AsyncCmd::DoRelease finish");
51     if (childShell != nullptr) {
52         childShell->StopWork(false, nullptr);
53     }
54     if (pid > 0) {
55         uv_kill(pid, SIGTERM);
56     }
57 }
58 
Initial(uv_loop_t * loopIn,const CmdResultCallback callback,uint32_t optionsIn)59 bool AsyncCmd::Initial(uv_loop_t *loopIn, const CmdResultCallback callback, uint32_t optionsIn)
60 {
61 #if defined _WIN32 || defined HDC_HOST
62     WRITE_LOG(LOG_FATAL, "Not support for win32 or host side");
63     return false;
64 #endif
65     loop = loopIn;
66     resultCallback = callback;
67     options = optionsIn;
68     return true;
69 }
70 
FinishShellProc(const void * context,const bool result,const string exitMsg)71 bool AsyncCmd::FinishShellProc(const void *context, const bool result, const string exitMsg)
72 {
73     WRITE_LOG(LOG_DEBUG, "FinishShellProc finish");
74     AsyncCmd *thisClass = static_cast<AsyncCmd *>(const_cast<void *>(context));
75     thisClass->resultCallback(true, result, thisClass->cmdResult + exitMsg);
76     --thisClass->refCount;
77     return true;
78 };
79 
ChildReadCallback(const void * context,uint8_t * buf,const int size)80 bool AsyncCmd::ChildReadCallback(const void *context, uint8_t *buf, const int size)
81 {
82     AsyncCmd *thisClass = static_cast<AsyncCmd *>(const_cast<void *>(context));
83     if (thisClass->options & OPTION_COMMAND_ONETIME) {
84         string s(reinterpret_cast<char *>(buf), size);
85         thisClass->cmdResult += s;
86         return true;
87     }
88     string s(reinterpret_cast<char *>(buf), size);
89     return thisClass->resultCallback(false, 0, s);
90 };
91 
Popen(string command,bool readWrite,int & cpid)92 int AsyncCmd::Popen(string command, bool readWrite, int &cpid)
93 {
94 #ifdef _WIN32
95     return ERR_NO_SUPPORT;
96 #else
97     constexpr uint8_t pipeRead = 0;
98     constexpr uint8_t pipeWrite = 1;
99     pid_t childPid;
100     int fds[2];
101     pipe(fds);
102 
103     if ((childPid = fork()) == -1) {
104         return ERR_GENERIC;
105     }
106     if (childPid == 0) {
107         Base::DeInitProcess();
108         if (readWrite) {
109             dup2(fds[pipeWrite], STDOUT_FILENO);
110             dup2(fds[pipeWrite], STDERR_FILENO);
111         } else {
112             dup2(fds[pipeRead], STDIN_FILENO);
113         }
114         Base::CloseFd(fds[pipeRead]);
115         Base::CloseFd(fds[pipeWrite]);
116 
117         setsid();
118         setpgid(childPid, childPid);
119         string shellPath = Base::GetShellPath();
120         execl(shellPath.c_str(), shellPath.c_str(), "-c", command.c_str(), NULL);
121         exit(0);
122     } else {
123         if (readWrite) {
124             Base::CloseFd(fds[pipeWrite]);
125             fcntl(fds[pipeRead], F_SETFD, FD_CLOEXEC);
126         } else {
127             Base::CloseFd(fds[pipeRead]);
128             fcntl(fds[pipeWrite], F_SETFD, FD_CLOEXEC);
129         }
130     }
131     cpid = childPid;
132     if (readWrite) {
133         return fds[pipeRead];
134     } else {
135         return fds[pipeWrite];
136     }
137 #endif
138 }
139 
ExecuteCommand(const string & command)140 bool AsyncCmd::ExecuteCommand(const string &command)
141 {
142     string cmd = command;
143     Base::Trim(cmd, "\"");
144     if ((fd = Popen(cmd, true, pid)) < 0) {
145         return false;
146     }
147     childShell = new(std::nothrow) HdcFileDescriptor(loop, fd, this, ChildReadCallback, FinishShellProc);
148     if (childShell == nullptr) {
149         WRITE_LOG(LOG_FATAL, "ExecuteCommand new childShell failed");
150         return false;
151     }
152     if (!childShell->StartWork()) {
153         return false;
154     }
155     ++refCount;
156     return true;
157 }
158 }  // namespace Hdc
159