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 
16 #include "component_processor.h"
17 #include <fcntl.h>
18 #include "applypatch/data_writer.h"
19 #include "applypatch/partition_record.h"
20 #include "log.h"
21 #include "parameter.h"
22 #ifdef UPDATER_USE_PTABLE
23 #include "ptable_parse/ptable_manager.h"
24 #endif
25 #include "slot_info/slot_info.h"
26 #include "updater/updater_const.h"
27 
28 using namespace std;
29 using namespace std::placeholders;
30 using namespace Hpackage;
31 using namespace Uscript;
32 
33 namespace Updater {
34 REGISTER_PROCESSOR(VersionCheckProcessor, "version_list")
35 REGISTER_PROCESSOR(BoardIdCheckProcessor, "board_list")
36 REGISTER_PROCESSOR(RawImgProcessor, "uboot", "boot_linux", "ramdisk",
37                    "system", "vendor", "resource", "updater", "userdata")
38 
39 ComponentProcessorFactory &ComponentProcessorFactory::GetInstance()
40 {
41     static ComponentProcessorFactory instance;
42     return instance;
43 }
44 
RegisterProcessor(Constructor constructor,std::vector<std::string> & nameList)45 void ComponentProcessorFactory::RegisterProcessor(Constructor constructor, std::vector<std::string> &nameList)
46 {
47     for (auto &iter : nameList) {
48         if (!m_constructorMap.emplace(iter, constructor).second) {
49             LOG(ERROR) << "emplace: " << iter.c_str() << " fail";
50         }
51     }
52 }
53 
GetProcessor(const std::string & name,const uint8_t len) const54 std::unique_ptr<ComponentProcessor> ComponentProcessorFactory::GetProcessor(const std::string &name,
55     const uint8_t len) const
56 {
57     std::string partitionName = name;
58     std::transform(partitionName.begin(), partitionName.end(), partitionName.begin(), ::tolower);
59     partitionName.erase(std::remove(partitionName.begin(), partitionName.end(), '/'), partitionName.end());
60     std::string::size_type position = partitionName.find("_es");
61     if (position != partitionName.npos) {
62         partitionName = partitionName.substr(0, position);
63     }
64     auto it = m_constructorMap.find(partitionName);
65     if (it == m_constructorMap.end() || it->second == nullptr) {
66         LOG(WARNING) << "GetProcessor for: " << name.c_str() << " fail, use default raw write";
67         return std::make_unique<RawImgProcessor>(name, len);
68     }
69     return (*(it->second))(name, len);
70 }
71 
DoProcess(Uscript::UScriptEnv & env)72 int32_t VersionCheckProcessor::DoProcess(Uscript::UScriptEnv &env)
73 {
74     PackagesInfoPtr pkginfomanager = PackagesInfo::GetPackagesInfoInstance();
75     if (pkginfomanager == nullptr) {
76         LOG(ERROR) << "Fail to pkginfomanager";
77         return PKG_INVALID_VERSION;
78     }
79 
80     if (env.GetPkgManager() == nullptr || pkginfomanager == nullptr) {
81         return PKG_INVALID_VERSION;
82     }
83     const char *verPtr = GetDisplayVersion();
84     if (verPtr == nullptr) {
85         LOG(ERROR) << "Fail to GetDisplayVersion";
86         return PKG_INVALID_VERSION;
87     }
88     std::string verStr(verPtr);
89     LOG(INFO) << "current version:" << verStr;
90     int ret = -1;
91     std::vector<std::string> targetVersions = pkginfomanager->GetOTAVersion(env.GetPkgManager(), "/version_list", "");
92     for (size_t i = 0; i < targetVersions.size(); i++) {
93         LOG(INFO) << "Check version " << targetVersions[i];
94         ret = verStr.compare(targetVersions[i]);
95         if (ret == 0) {
96             LOG(INFO) << "Check version success";
97             break;
98         }
99     }
100 #ifndef UPDATER_UT
101     return ret;
102 #else
103     return USCRIPT_SUCCESS;
104 #endif
105 }
106 
DoProcess(Uscript::UScriptEnv & env)107 int32_t BoardIdCheckProcessor::DoProcess(Uscript::UScriptEnv &env)
108 {
109     PackagesInfoPtr pkginfomanager = PackagesInfo::GetPackagesInfoInstance();
110     if (pkginfomanager == nullptr) {
111         LOG(ERROR) << "Fail to get pkginfomanager";
112         return PKG_INVALID_VERSION;
113     }
114 
115     if (env.GetPkgManager() == nullptr) {
116         LOG(ERROR) << "Fail to GetPkgManager";
117         return PKG_INVALID_VERSION;
118     }
119 
120     std::string localBoardId = Utils::GetLocalBoardId();
121     if (localBoardId.empty()) {
122         return 0;
123     }
124 
125     int ret = -1;
126     std::vector<std::string> boardIdList = pkginfomanager->GetBoardID(env.GetPkgManager(), "/board_list", "");
127     for (size_t i = 0; i < boardIdList.size(); i++) {
128         LOG(INFO) << "Check BoardId " << boardIdList[i];
129         ret = localBoardId.compare(boardIdList[i]);
130         if (ret == 0) {
131             LOG(INFO) << "Check board list success ";
132             break;
133         }
134     }
135 #ifndef UPDATER_UT
136     return ret;
137 #else
138     return USCRIPT_SUCCESS;
139 #endif
140 }
141 
PreProcess(Uscript::UScriptEnv & env)142 int32_t RawImgProcessor::PreProcess(Uscript::UScriptEnv &env)
143 {
144     std::string partitionName = name_;
145     LOG(INFO) << "RawImgProcessor::PreProcess " << partitionName;
146     if (env.GetPkgManager() == nullptr) {
147         LOG(ERROR) << "Error to get pkg manager";
148         return USCRIPT_ERROR_EXECUTE;
149     }
150 
151     std::string writePath;
152     uint64_t offset = 0;
153     uint64_t partitionSize = 0;
154     if (GetWritePathAndOffset(partitionName, writePath, offset, partitionSize) != USCRIPT_SUCCESS) {
155         LOG(ERROR) << "Get partition:%s WritePathAndOffset fail \'" <<
156             partitionName.substr(1, partitionName.size()) << "\'.";
157         return USCRIPT_ERROR_EXECUTE;
158     }
159     const FileInfo *info = env.GetPkgManager()->GetFileInfo(partitionName);
160     if (info == nullptr) {
161         LOG(ERROR) << "Error to get file info";
162         return USCRIPT_ERROR_EXECUTE;
163     }
164 #ifdef UPDATER_USE_PTABLE
165     if (partitionSize < info->unpackedSize) {
166         LOG(ERROR) << "partition size: " << partitionSize << " is short than image size: " << totalSize_;
167         return USCRIPT_ERROR_EXECUTE;
168     }
169 #endif
170 
171     writer_ = DataWriter::CreateDataWriter(WRITE_RAW, writePath,
172         static_cast<UpdaterEnv *>(&env), offset);
173     if (writer_ == nullptr) {
174         LOG(ERROR) << "Error to create writer";
175         return USCRIPT_ERROR_EXECUTE;
176     }
177 #ifdef UPDATER_UT
178     int fd = open(writePath.c_str(), O_RDWR | O_CREAT);
179     if (fd >= 0) {
180         close(fd);
181     }
182 #endif
183     return USCRIPT_SUCCESS;
184 }
185 
DoProcess(Uscript::UScriptEnv & env)186 int32_t RawImgProcessor::DoProcess(Uscript::UScriptEnv &env)
187 {
188     std::string partitionName = name_;
189     // Extract partition information
190     const FileInfo *info = env.GetPkgManager()->GetFileInfo(partitionName);
191     if (info == nullptr) {
192         LOG(ERROR) << "Error to get file info";
193         return USCRIPT_ERROR_EXECUTE;
194     }
195 
196     PkgStream::ExtractFileProcessor processor =
197         [this](const PkgBuffer &buffer, size_t size, size_t start, bool isFinish, const void *context) {
198             return this->RawImageWriteProcessor(buffer, size, start, isFinish, context);
199         };
200 
201     Hpackage::PkgManager::StreamPtr outStream = nullptr;
202     int ret = env.GetPkgManager()->CreatePkgStream(outStream, partitionName, processor, writer_.get());
203     if (ret != USCRIPT_SUCCESS || outStream == nullptr) {
204         LOG(ERROR) << "Error to create output stream";
205         return USCRIPT_ERROR_EXECUTE;
206     }
207 
208     ret = env.GetPkgManager()->ExtractFile(partitionName, outStream);
209     if (ret != USCRIPT_SUCCESS) {
210         LOG(ERROR) << "Error to extract file";
211         env.GetPkgManager()->ClosePkgStream(outStream);
212         return USCRIPT_ERROR_EXECUTE;
213     }
214     env.GetPkgManager()->ClosePkgStream(outStream);
215     return USCRIPT_SUCCESS;
216 }
217 
PostProcess(Uscript::UScriptEnv & env)218 int32_t RawImgProcessor::PostProcess(Uscript::UScriptEnv &env)
219 {
220     PartitionRecord::GetInstance().RecordPartitionUpdateStatus(name_, true);
221     DataWriter::ReleaseDataWriter(writer_);
222     totalSize_ = 0;
223     LOG(INFO) << "UScriptInstructionRawImageWrite finish";
224     return USCRIPT_SUCCESS;
225 }
226 
GetWritePathAndOffset(const std::string & partitionName,std::string & writePath,uint64_t & offset,uint64_t & partitionSize)227 int RawImgProcessor::GetWritePathAndOffset(const std::string &partitionName, std::string &writePath,
228                                            uint64_t &offset, uint64_t &partitionSize)
229 {
230 #ifdef UPDATER_USE_PTABLE
231     DevicePtable &devicePtb = DevicePtable::GetInstance();
232     Ptable::PtnInfo ptnInfo;
233     if (!devicePtb.GetPartionInfoByName(partitionName, ptnInfo)) {
234         LOG(ERROR) << "Datawriter: cannot find device path for partition \'" <<
235             partitionName.substr(1, partitionName.size()) << "\'.";
236         return USCRIPT_ERROR_EXECUTE;
237     }
238     writePath = ptnInfo.writePath;
239     offset = ptnInfo.startAddr;
240     partitionSize = ptnInfo.partitionSize;
241 #else
242     writePath = GetBlockDeviceByMountPoint(partitionName);
243     if (writePath.empty()) {
244         LOG(ERROR) << "Datawriter: cannot find device path for partition \'" <<
245             partitionName.substr(1, partitionName.size()) << "\'.";
246         return USCRIPT_ERROR_EXECUTE;
247     }
248 
249 #ifndef UPDATER_UT
250     if (partitionName != "/userdata") {
251         std::string suffix = "";
252         GetPartitionSuffix(suffix);
253         writePath += suffix;
254     }
255     LOG(INFO) << "write partition path: " << writePath;
256 #else
257     writePath = "/data/updater" + partitionName;
258 #endif
259 #endif
260     return USCRIPT_SUCCESS;
261 }
262 
RawImageWriteProcessor(const PkgBuffer & buffer,size_t size,size_t start,bool isFinish,const void * context)263 int RawImgProcessor::RawImageWriteProcessor(const PkgBuffer &buffer, size_t size, size_t start,
264                                             bool isFinish, const void* context)
265 {
266     void *p = const_cast<void *>(context);
267     DataWriter *writer = static_cast<DataWriter *>(p);
268     if (writer == nullptr) {
269         LOG(ERROR) << "Data writer is null";
270         return PKG_INVALID_STREAM;
271     }
272 
273     // maybe extract from package is finished. just return.
274     if (buffer.buffer == nullptr || size == 0) {
275         return PKG_SUCCESS;
276     }
277 
278     bool ret = writer->Write(const_cast<uint8_t*>(buffer.buffer), size, nullptr);
279     if (!ret) {
280         LOG(ERROR) << "Write " << size << " byte(s) failed";
281         if (errno == EIO) {
282             writer->GetUpdaterEnv()->PostMessage(UPDATER_RETRY_TAG, IO_FAILED_REBOOT);
283         }
284         return PKG_INVALID_STREAM;
285     }
286 
287     UpdateProgress(size);
288     return PKG_SUCCESS;
289 }
290 
PreProcess(Uscript::UScriptEnv & env)291 int32_t SkipImgProcessor::PreProcess(Uscript::UScriptEnv &env)
292 {
293     std::string partitionName = name_;
294     LOG(INFO) << "SkipImgProcessor::PreProcess " << partitionName;
295     if (env.GetPkgManager() == nullptr) {
296         LOG(ERROR) << "Error to get pkg manager";
297         return USCRIPT_ERROR_EXECUTE;
298     }
299 
300     std::string writePath;
301     writer_ = DataWriter::CreateDataWriter(WRITE_RAW, writePath,
302         static_cast<UpdaterEnv *>(&env), 0);
303     if (writer_ == nullptr) {
304         LOG(ERROR) << "Error to create writer";
305         return USCRIPT_ERROR_EXECUTE;
306     }
307 #ifdef UPDATER_UT
308     int fd = open(writePath.c_str(), O_RDWR | O_CREAT);
309     if (fd >= 0) {
310         close(fd);
311     }
312 #endif
313     return USCRIPT_SUCCESS;
314 }
315 
DoProcess(Uscript::UScriptEnv & env)316 int32_t SkipImgProcessor::DoProcess(Uscript::UScriptEnv &env)
317 {
318     std::string partitionName = name_;
319     // Extract partition information
320     const FileInfo *info = env.GetPkgManager()->GetFileInfo(partitionName);
321     if (info == nullptr) {
322         LOG(ERROR) << "Error to get file info";
323         return USCRIPT_ERROR_EXECUTE;
324     }
325 
326     PkgStream::ExtractFileProcessor processor =
327         [this](const PkgBuffer &buffer, size_t size, size_t start, bool isFinish, const void *context) {
328             return this->SkipImageWriteProcessor(buffer, size, start, isFinish, context);
329         };
330 
331     Hpackage::PkgManager::StreamPtr outStream = nullptr;
332     int ret = env.GetPkgManager()->CreatePkgStream(outStream, partitionName, processor, writer_.get());
333     if (ret != USCRIPT_SUCCESS || outStream == nullptr) {
334         LOG(ERROR) << "Error to create output stream";
335         return USCRIPT_ERROR_EXECUTE;
336     }
337 
338     ret = env.GetPkgManager()->ExtractFile(partitionName, outStream);
339     if (ret != USCRIPT_SUCCESS) {
340         LOG(ERROR) << "Error to extract file";
341         env.GetPkgManager()->ClosePkgStream(outStream);
342         return USCRIPT_ERROR_EXECUTE;
343     }
344     env.GetPkgManager()->ClosePkgStream(outStream);
345     return USCRIPT_SUCCESS;
346 }
347 
348 int SkipImgProcessor::SkipImageWriteProcessor(const PkgBuffer &buffer, size_t size, [[maybe_unused]]size_t start,
349                                               [[maybe_unused]]bool isFinish, [[maybe_unused]]const void* context)
350 {
351     void *p = const_cast<void *>(context);
352     DataWriter *writer = static_cast<DataWriter *>(p);
353     if (writer == nullptr) {
354         LOG(ERROR) << "Data writer is null";
355         return PKG_INVALID_STREAM;
356     }
357 
358     // maybe extract from package is finished. just return.
359     if (buffer.buffer == nullptr || size == 0) {
360         return PKG_SUCCESS;
361     }
362 
363     UpdateProgress(size);
364     return PKG_SUCCESS;
365 }
366 
PostProcess(Uscript::UScriptEnv & env)367 int32_t SkipImgProcessor::PostProcess(Uscript::UScriptEnv &env)
368 {
369     PartitionRecord::GetInstance().RecordPartitionUpdateStatus(name_, true);
370     DataWriter::ReleaseDataWriter(writer_);
371     totalSize_ = 0;
372     LOG(INFO) << name_ << " SkipImgProcess finish";
373     return USCRIPT_SUCCESS;
374 }
375 }