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 "applypatch/transfer_manager.h"
16 #include <fcntl.h>
17 #include <sstream>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include "applypatch/command_function.h"
21 #include "log/log.h"
22 #include "utils.h"
23
24 namespace updater {
25 using namespace updater::utils;
26 static TransferManagerPtr g_transferManagerInstance = nullptr;
GetTransferManagerInstance()27 TransferManagerPtr TransferManager::GetTransferManagerInstance()
28 {
29 if (g_transferManagerInstance == nullptr) {
30 g_transferManagerInstance = new TransferManager();
31 g_transferManagerInstance->Init();
32 }
33 return g_transferManagerInstance;
34 }
35
ReleaseTransferManagerInstance(TransferManagerPtr transferManager)36 void TransferManager::ReleaseTransferManagerInstance(TransferManagerPtr transferManager)
37 {
38 delete transferManager;
39 g_transferManagerInstance = nullptr;
40 transferManager = nullptr;
41 }
42
~TransferManager()43 TransferManager::~TransferManager()
44 {
45 if (globalParams != nullptr) {
46 if (globalParams->writerThreadInfo != nullptr) {
47 globalParams->writerThreadInfo.reset();
48 }
49 globalParams.reset();
50 }
51 }
52
CommandsParser(int fd,const std::vector<std::string> & context)53 bool TransferManager::CommandsParser(int fd, const std::vector<std::string> &context)
54 {
55 UPDATER_ERROR_CHECK(context.size() >= 1, "too small context in transfer file", return false);
56 std::vector<std::string>::const_iterator ct = context.begin();
57 globalParams->version = utils::String2Int<size_t>(*ct++, utils::N_DEC);
58 globalParams->blockCount = utils::String2Int<size_t>(*ct++, utils::N_DEC);
59 globalParams->maxEntries = utils::String2Int<size_t>(*ct++, utils::N_DEC);
60 globalParams->maxBlocks = utils::String2Int<size_t>(*ct++, utils::N_DEC);
61 size_t totalSize = globalParams->blockCount;
62 std::string retryCmd = "";
63 if (globalParams != nullptr && globalParams->env != nullptr && globalParams->env->IsRetry()) {
64 retryCmd = ReloadForRetry();
65 }
66 std::unique_ptr<Command> cmd;
67 int initBlock = 0;
68 while (ct != context.end()) {
69 cmd = std::make_unique<Command>();
70 UPDATER_ERROR_CHECK(cmd != nullptr, "Failed to parse command line.", return false);
71 if (cmd->Init(*ct) && cmd->GetCommandType() != CommandType::LAST) {
72 if (!retryCmd.empty() && globalParams->env->IsRetry()) {
73 if (*ct == retryCmd) {
74 retryCmd.clear();
75 }
76 if (cmd->GetCommandType() != CommandType::NEW) {
77 LOG(INFO) << "Retry: Command " << *ct << " passed";
78 cmd.reset();
79 ct++;
80 continue;
81 }
82 }
83 cmd->SetFileDescriptor(fd);
84 std::unique_ptr<CommandFunction> cf = CommandFunctionFactory::GetCommandFunction(cmd->GetCommandType());
85 UPDATER_ERROR_CHECK(cf != nullptr, "Failed to get cmd exec", return false);
86 CommandResult ret = cf->Execute(const_cast<Command &>(*cmd.get()));
87 CommandFunctionFactory::ReleaseCommandFunction(cf);
88 if (CheckResult(ret, cmd->GetCommandLine(), cmd->GetCommandType()) == false) {
89 return false;
90 }
91 if (initBlock == 0) {
92 initBlock = globalParams->written;
93 }
94 if (totalSize != 0 && globalParams->env != nullptr && NeedSetProgress(cmd->GetCommandType())) {
95 globalParams->env->PostMessage("set_progress",
96 std::to_string((float)(globalParams->written - initBlock) / totalSize));
97 }
98 LOG(INFO) << "Running command : " << cmd->GetArgumentByPos(0) << " success";
99 }
100 cmd.reset();
101 ct++;
102 }
103 return true;
104 }
105
Init()106 void TransferManager::Init()
107 {
108 globalParams = std::make_unique<GlobalParams>();
109 globalParams->writerThreadInfo = std::make_unique<WriterThreadInfo>();
110 blocksetMap.clear();
111 }
112
RegisterForRetry(const std::string & cmd)113 bool TransferManager::RegisterForRetry(const std::string &cmd)
114 {
115 std::string path = globalParams->retryFile;
116 int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
117 UPDATER_ERROR_CHECK(fd != -1, "Failed to create", return false);
118 UPDATER_ERROR_CHECK(fchown(fd, O_USER_GROUP_ID, O_USER_GROUP_ID) == 0,
119 "Failed to chown", close(fd); return -1);
120 bool ret = utils::WriteStringToFile(fd, cmd);
121 UPDATER_ERROR_CHECK_NOT_RETURN(ret, "Write retry flag error");
122 fsync(fd);
123 close(fd);
124 return ret;
125 }
126
ReloadForRetry() const127 std::string TransferManager::ReloadForRetry() const
128 {
129 std::string path = globalParams->retryFile;
130 int fd = open(path.c_str(), O_RDONLY);
131 UPDATER_ERROR_CHECK(fd >= 0, "Failed to open", return "");
132 (void)lseek(fd, 0, SEEK_SET);
133 std::string cmd = "";
134 UPDATER_ERROR_CHECK_NOT_RETURN(utils::ReadFileToString(fd, cmd), "Error to read retry flag");
135 close(fd);
136 return cmd;
137 }
138
NeedSetProgress(const CommandType & type)139 bool TransferManager::NeedSetProgress(const CommandType &type)
140 {
141 return type == CommandType::NEW ||
142 type == CommandType::IMGDIFF ||
143 type == CommandType::BSDIFF ||
144 type == CommandType::ZERO;
145 }
146
CheckResult(const CommandResult result,const std::string & cmd,const CommandType & type)147 bool TransferManager::CheckResult(const CommandResult result, const std::string &cmd, const CommandType &type)
148 {
149 switch (result) {
150 case SUCCESS:
151 if (type != CommandType::NEW) {
152 RegisterForRetry(cmd);
153 }
154 break;
155 case NEED_RETRY:
156 LOG(INFO) << "Running command need retry!";
157 UPDATER_CHECK_ONLY_RETURN(!globalParams->env, globalParams->env->PostMessage("retry_update", cmd));
158 return false;
159 break;
160 case FAILED:
161 default:
162 LOG(ERROR) << "Running command failed";
163 return false;
164 break;
165 }
166 return true;
167 }
168 } // namespace updater
169