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