1 /*
2 * Copyright (c) 2022-2024 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
16 #include "shell_command_executor.h"
17
18 #include <chrono>
19 #include <cinttypes>
20 #include <iostream>
21 #include <sstream>
22
23 #include "hilog_tag_wrapper.h"
24 #include "shell_command_config_loader.h"
25
26 using namespace std::chrono_literals;
27 namespace OHOS {
28 namespace AAFwk {
ShellCommandExecutor(const std::string & cmd,const int64_t timeoutSec)29 ShellCommandExecutor::ShellCommandExecutor(const std::string& cmd, const int64_t timeoutSec)
30 : cmd_(cmd), timeoutSec_(timeoutSec)
31 {
32 handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::Create());
33 }
34
WaitWorkDone()35 ShellCommandResult ShellCommandExecutor::WaitWorkDone()
36 {
37 TAG_LOGD(AAFwkTag::AA_TOOL, "enter");
38
39 if (!DoWork()) {
40 TAG_LOGI(AAFwkTag::AA_TOOL, "Failed cmd: \"%{public}s\"", cmd_.data());
41 return cmdResult_;
42 }
43
44 std::unique_lock<std::mutex> workLock(mtxWork_);
45
46 auto condition = [this]() { return isDone_; };
47 if (timeoutSec_ <= 0) {
48 cvWork_.wait(workLock, condition);
49 } else if (!cvWork_.wait_for(workLock, timeoutSec_ * 1s, condition)) {
50 TAG_LOGW(AAFwkTag::AA_TOOL, "cmd timed out! cmd : \"%{public}s\", timeoutSec : %{public}" PRId64,
51 cmd_.data(), timeoutSec_);
52 std::cout << "Warning! Command execution timed out! cmd : " << cmd_ << ", timeoutSec : " << timeoutSec_
53 << std::endl;
54
55 ShellCommandResult realResult;
56 realResult.exitCode = -1;
57 {
58 std::lock_guard<std::mutex> copyLock(mtxCopy_);
59 realResult.stdResult = cmdResult_.stdResult;
60 }
61 return realResult;
62 }
63
64 TAG_LOGI(AAFwkTag::AA_TOOL, "cmd complete, cmd : \"%{public}s\", exitCode : %{public}d",
65 cmd_.data(), cmdResult_.exitCode);
66 return cmdResult_;
67 }
68
DoWork()69 bool ShellCommandExecutor::DoWork()
70 {
71 TAG_LOGD(AAFwkTag::AA_TOOL, "enter");
72
73 if (cmd_.empty()) {
74 TAG_LOGE(AAFwkTag::AA_TOOL, "Invalid cmd_");
75 return false;
76 }
77
78 if (!handler_) {
79 TAG_LOGE(AAFwkTag::AA_TOOL, "Invalid handler_");
80 return false;
81 }
82
83 if (!CheckCommand()) {
84 TAG_LOGE(AAFwkTag::AA_TOOL, "Invalid command");
85 return false;
86 }
87
88 auto self(shared_from_this());
89 handler_->PostTask([this, self]() {
90 TAG_LOGI(AAFwkTag::AA_TOOL, "DoWork task begin, cmd: \"%{public}s\"", cmd_.data());
91
92 FILE* file = popen(cmd_.c_str(), "r");
93 if (!file) {
94 TAG_LOGE(AAFwkTag::AA_TOOL, "popen failed, cmd: \"%{public}s\"", cmd_.data());
95
96 {
97 std::unique_lock<std::mutex> workLock(mtxWork_);
98 isDone_ = true;
99 }
100 cvWork_.notify_one();
101 TAG_LOGI(AAFwkTag::AA_TOOL, "DoWork task end, cmd: \"%{public}s\"", cmd_.data());
102 return;
103 }
104
105 char commandResult[1024] = { '\0' };
106 while ((fgets(commandResult, sizeof(commandResult), file)) != nullptr) {
107 {
108 std::lock_guard<std::mutex> copyLock(mtxCopy_);
109 cmdResult_.stdResult.append(commandResult);
110 }
111 std::cout << commandResult;
112 }
113
114 cmdResult_.exitCode = pclose(file);
115 file = nullptr;
116
117 {
118 std::unique_lock<std::mutex> workLock(mtxWork_);
119 isDone_ = true;
120 }
121 cvWork_.notify_one();
122 TAG_LOGI(AAFwkTag::AA_TOOL, "DoWork task end, cmd: \"%{public}s\"", cmd_.data());
123 });
124
125 return true;
126 }
127
CheckCommand()128 bool ShellCommandExecutor::CheckCommand()
129 {
130 std::istringstream iss(cmd_);
131 std::string firstCommand = "";
132 iss >> firstCommand;
133 if (ShellCommandConfigLoader::commands_.find(firstCommand) != ShellCommandConfigLoader::commands_.end()) {
134 return true;
135 }
136 return false;
137 }
138 } // namespace AAFwk
139 } // namespace OHOS
140