• 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 "update_image_block.h"
16 #include <cerrno>
17 #include <fcntl.h>
18 #include <pthread.h>
19 #include <sstream>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 #include "applypatch/block_set.h"
24 #include "applypatch/store.h"
25 #include "applypatch/transfer_manager.h"
26 #include "applypatch/partition_record.h"
27 #include "fs_manager/mount.h"
28 #include "log/dump.h"
29 #include "log/log.h"
30 #include "utils.h"
31 
32 using namespace Uscript;
33 using namespace Hpackage;
34 using namespace Updater;
35 
36 namespace Updater {
37 constexpr int32_t SHA_CHECK_SECOND = 2;
38 constexpr int32_t SHA_CHECK_PARAMS = 3;
ExtractNewData(const PkgBuffer & buffer,size_t size,size_t start,bool isFinish,const void * context)39 static int ExtractNewData(const PkgBuffer &buffer, size_t size, size_t start, bool isFinish, const void* context)
40 {
41     void *p = const_cast<void *>(context);
42     WriterThreadInfo *info = static_cast<WriterThreadInfo *>(p);
43     uint8_t *addr = buffer.buffer;
44     while (size > 0) {
45         pthread_mutex_lock(&info->mutex);
46         while (info->writer == nullptr) {
47             if (!info->readyToWrite) {
48                 LOG(WARNING) << "writer is not ready to write.";
49                 pthread_mutex_unlock(&info->mutex);
50                 return Hpackage::PKG_INVALID_STREAM;
51             }
52             pthread_cond_wait(&info->cond, &info->mutex);
53         }
54         pthread_mutex_unlock(&info->mutex);
55         size_t toWrite = std::min(size, info->writer->GetBlocksSize() - info->writer->GetTotalWritten());
56         // No more data to write.
57         if (toWrite == 0) {
58             break;
59         }
60         bool ret = info->writer->Write(addr, toWrite, nullptr);
61         std::ostringstream logMessage;
62         logMessage << "Write " << toWrite << " byte(s) failed";
63         if (!ret) {
64             LOG(ERROR) << logMessage.str();
65             return Hpackage::PKG_INVALID_STREAM;
66         }
67         size -= toWrite;
68         addr += toWrite;
69 
70         if (info->writer->IsWriteDone()) {
71             pthread_mutex_lock(&info->mutex);
72             info->writer.reset();
73             pthread_cond_broadcast(&info->cond);
74             pthread_mutex_unlock(&info->mutex);
75         }
76     }
77     return Hpackage::PKG_SUCCESS;
78 }
79 
CondBroadcast(WriterThreadInfo * info)80 static inline void CondBroadcast(WriterThreadInfo *info)
81 {
82     pthread_mutex_lock(&info->mutex);
83     info->readyToWrite = false;
84     if (info->writer != nullptr) {
85         pthread_cond_broadcast(&info->cond);
86     }
87     pthread_mutex_unlock(&info->mutex);
88 }
89 
UnpackNewData(void * arg)90 void* UnpackNewData(void *arg)
91 {
92     WriterThreadInfo *info = static_cast<WriterThreadInfo *>(arg);
93     Hpackage::PkgManager::StreamPtr stream = nullptr;
94     TransferManagerPtr tm = TransferManager::GetTransferManagerInstance();
95     if (info->newPatch.empty()) {
96         LOG(ERROR) << "new patch file name is empty. thread quit.";
97         CondBroadcast(info);
98         return nullptr;
99     }
100     LOG(DEBUG) << "new patch file name: " << info->newPatch;
101     auto env = tm->GetGlobalParams()->env;
102     const FileInfo *file = env->GetPkgManager()->GetFileInfo(info->newPatch);
103     if (file == nullptr) {
104         LOG(ERROR) << "Cannot get file info of :" << info->newPatch;
105         CondBroadcast(info);
106         return nullptr;
107     }
108     LOG(DEBUG) << info->newPatch << " info: size " << file->packedSize << " unpacked size " <<
109         file->unpackedSize << " name " << file->identity;
110     int32_t ret = env->GetPkgManager()->CreatePkgStream(stream, info->newPatch, ExtractNewData, info);
111     if (ret != Hpackage::PKG_SUCCESS || stream == nullptr) {
112         LOG(ERROR) << "Cannot extract " << info->newPatch << " from package.";
113         CondBroadcast(info);
114         return nullptr;
115     }
116     ret = env->GetPkgManager()->ExtractFile(info->newPatch, stream);
117     env->GetPkgManager()->ClosePkgStream(stream);
118     LOG(DEBUG) << "new data writer ending...";
119     // extract new data done.
120     // tell command.
121     CondBroadcast(info);
122     return nullptr;
123 }
124 
ReturnAndPushParam(int32_t returnValue,Uscript::UScriptContext & context)125 static int32_t ReturnAndPushParam(int32_t returnValue, Uscript::UScriptContext &context)
126 {
127     context.PushParam(returnValue);
128     return returnValue;
129 }
130 
131 struct UpdateBlockInfo {
132     std::string partitionName;
133     std::string transferName;
134     std::string newDataName;
135     std::string patchDataName;
136     std::string devPath;
137 };
138 
GetUpdateBlockInfo(struct UpdateBlockInfo & infos,Uscript::UScriptEnv & env,Uscript::UScriptContext & context)139 static int32_t GetUpdateBlockInfo(struct UpdateBlockInfo &infos, Uscript::UScriptEnv &env,
140     Uscript::UScriptContext &context)
141 {
142     if (context.GetParamCount() != 4) { // 4:Determine the number of parameters
143         LOG(ERROR) << "Invalid param";
144         return ReturnAndPushParam(USCRIPT_INVALID_PARAM, context);
145     }
146 
147     // Get partition Name first.
148     // Use partition name as zip file name. ${partition name}.zip
149     // load ${partition name}.zip from updater package.
150     // Try to unzip ${partition name}.zip, extract transfer.list, net.dat, patch.dat
151     size_t pos = 0;
152     int32_t ret = context.GetParam(pos++, infos.partitionName);
153     if (ret != USCRIPT_SUCCESS) {
154         LOG(ERROR) << "Error to get param 1";
155         return ret;
156     }
157     ret = context.GetParam(pos++, infos.transferName);
158     if (ret != USCRIPT_SUCCESS) {
159         LOG(ERROR) << "Error to get param 2";
160         return ret;
161     }
162     ret = context.GetParam(pos++, infos.newDataName);
163     if (ret != USCRIPT_SUCCESS) {
164         LOG(ERROR) << "Error to get param 3";
165         return ret;
166     }
167     ret = context.GetParam(pos++, infos.patchDataName);
168     if (ret != USCRIPT_SUCCESS) {
169         LOG(ERROR) << "Error to get param 4";
170         return ret;
171     }
172 
173     LOG(INFO) << "ExecuteUpdateBlock::updating  " << infos.partitionName << " ...";
174     infos.devPath = GetBlockDeviceByMountPoint(infos.partitionName);
175     LOG(INFO) << "ExecuteUpdateBlock::updating  dev path : " << infos.devPath;
176     if (infos.devPath.empty()) {
177         LOG(ERROR) << "cannot get block device of partition";
178         return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context);
179     }
180     return USCRIPT_SUCCESS;
181 }
182 
ExecuteTransferCommand(int fd,const std::vector<std::string> & lines,Uscript::UScriptEnv & env,Uscript::UScriptContext & context,const std::string & partitionName)183 static int32_t ExecuteTransferCommand(int fd, const std::vector<std::string> &lines, Uscript::UScriptEnv &env,
184     Uscript::UScriptContext &context, const std::string &partitionName)
185 {
186     TransferManagerPtr tm = TransferManager::GetTransferManagerInstance();
187     auto globalParams = tm->GetGlobalParams();
188     auto writerThreadInfo = globalParams->writerThreadInfo.get();
189 
190     globalParams->storeBase = "/data/updater/update_tmp";
191     globalParams->retryFile = std::string("/data/updater") + partitionName + "_retry";
192     LOG(INFO) << "Store base path is " << globalParams->storeBase;
193     int32_t ret = Store::CreateNewSpace(globalParams->storeBase, !globalParams->env->IsRetry());
194     if (ret == -1) {
195         LOG(ERROR) << "Error to create new store space";
196         return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context);
197     }
198     globalParams->storeCreated = ret;
199 
200     if (!tm->CommandsParser(fd, lines)) {
201         return USCRIPT_ERROR_EXECUTE;
202     }
203     pthread_mutex_lock(&writerThreadInfo->mutex);
204     if (writerThreadInfo->readyToWrite) {
205         LOG(WARNING) << "New data writer thread is still available...";
206     }
207 
208     writerThreadInfo->readyToWrite = false;
209     pthread_cond_broadcast(&writerThreadInfo->cond);
210     pthread_mutex_unlock(&writerThreadInfo->mutex);
211     ret = pthread_join(globalParams->thread, nullptr);
212     std::ostringstream logMessage;
213     logMessage << "pthread join returned with " << ret;
214     if (ret != 0) {
215         LOG(WARNING) << logMessage.str();
216     }
217     if (globalParams->storeCreated != -1) {
218         Store::DoFreeSpace(globalParams->storeBase);
219     }
220     return USCRIPT_SUCCESS;
221 }
222 
InitThread(const struct UpdateBlockInfo & infos,Uscript::UScriptEnv & env,Uscript::UScriptContext & context)223 static int InitThread(const struct UpdateBlockInfo &infos, Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
224 {
225     TransferManagerPtr tm = TransferManager::GetTransferManagerInstance();
226     auto globalParams = tm->GetGlobalParams();
227     auto writerThreadInfo = globalParams->writerThreadInfo.get();
228     writerThreadInfo->readyToWrite = true;
229     pthread_mutex_init(&writerThreadInfo->mutex, nullptr);
230     pthread_cond_init(&writerThreadInfo->cond, nullptr);
231     pthread_attr_t attr;
232     pthread_attr_init(&attr);
233     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
234     writerThreadInfo->newPatch = infos.newDataName;
235     int error = pthread_create(&globalParams->thread, &attr, UnpackNewData, writerThreadInfo);
236     return error;
237 }
238 
ExtractDiffPackageAndLoad(const UpdateBlockInfo & infos,Uscript::UScriptEnv & env,Uscript::UScriptContext & context)239 static int32_t ExtractDiffPackageAndLoad(const UpdateBlockInfo &infos, Uscript::UScriptEnv &env,
240     Uscript::UScriptContext &context)
241 {
242     Hpackage::PkgManager::StreamPtr outStream = nullptr;
243     LOG(DEBUG) << "partitionName is " << infos.partitionName;
244     const FileInfo *info = env.GetPkgManager()->GetFileInfo(infos.partitionName);
245     if (info == nullptr) {
246         LOG(WARNING) << "Error to get file info";
247         return USCRIPT_SUCCESS;
248     }
249     std::string diffPackage = std::string("/data/updater") + infos.partitionName;
250     int32_t ret = env.GetPkgManager()->CreatePkgStream(outStream,
251         diffPackage, info->unpackedSize, PkgStream::PkgStreamType_Write);
252     if (outStream == nullptr) {
253         LOG(ERROR) << "Error to create output stream";
254         return USCRIPT_ERROR_EXECUTE;
255     }
256 
257     ret = env.GetPkgManager()->ExtractFile(infos.partitionName, outStream);
258     if (ret != USCRIPT_SUCCESS) {
259         LOG(ERROR) << "Error to extract file";
260         env.GetPkgManager()->ClosePkgStream(outStream);
261         return USCRIPT_ERROR_EXECUTE;
262     }
263     env.GetPkgManager()->ClosePkgStream(outStream);
264     std::string diffPackageZip = diffPackage + ".zip";
265     if (rename(diffPackage.c_str(), diffPackageZip.c_str()) != 0) {
266         LOG(ERROR) << "rename failed";
267         return USCRIPT_ERROR_EXECUTE;
268     }
269     LOG(DEBUG) << "Rename " << diffPackage << " to zip\nExtract " << diffPackage << " done\nReload " << diffPackageZip;
270     std::vector<std::string> diffPackageComponents;
271     ret = env.GetPkgManager()->LoadPackage(diffPackageZip, Updater::Utils::GetCertName(), diffPackageComponents);
272     if (diffPackageComponents.size() < 1) {
273         LOG(ERROR) << "Diff package is empty";
274         return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context);
275     }
276     return USCRIPT_SUCCESS;
277 }
278 
DoExecuteUpdateBlock(const UpdateBlockInfo & infos,Uscript::UScriptEnv & env,Hpackage::PkgManager::StreamPtr & outStream,const std::vector<std::string> & lines,Uscript::UScriptContext & context)279 static int32_t DoExecuteUpdateBlock(const UpdateBlockInfo &infos, Uscript::UScriptEnv &env,
280     Hpackage::PkgManager::StreamPtr &outStream, const std::vector<std::string> &lines, Uscript::UScriptContext &context)
281 {
282     int fd = open(infos.devPath.c_str(), O_RDWR | O_LARGEFILE);
283     if (fd == -1) {
284         LOG(ERROR) << "Failed to open block";
285         env.GetPkgManager()->ClosePkgStream(outStream);
286         return USCRIPT_ERROR_EXECUTE;
287     }
288     int32_t ret = ExecuteTransferCommand(fd, lines, env, context, infos.partitionName);
289     fsync(fd);
290     close(fd);
291     fd = -1;
292     env.GetPkgManager()->ClosePkgStream(outStream);
293     if (ret == USCRIPT_SUCCESS) {
294         PartitionRecord::GetInstance().RecordPartitionUpdateStatus(infos.partitionName, true);
295     }
296     return ret;
297 }
298 
ExtractFileByName(Uscript::UScriptEnv & env,const std::string & fileName,Hpackage::PkgManager::StreamPtr & outStream,uint8_t * & outBuf,size_t & buffSize)299 static int32_t ExtractFileByName(Uscript::UScriptEnv &env, const std::string &fileName,
300                                      Hpackage::PkgManager::StreamPtr &outStream, uint8_t *&outBuf, size_t &buffSize)
301 {
302     if (env.GetPkgManager() == nullptr) {
303         LOG(ERROR) << "Error to get pkg manager";
304         return USCRIPT_ERROR_EXECUTE;
305     }
306 
307     const FileInfo *info = env.GetPkgManager()->GetFileInfo(fileName);
308     if (info == nullptr) {
309         LOG(ERROR) << "GetFileInfo fail";
310         return USCRIPT_ERROR_EXECUTE;
311     }
312     auto ret = env.GetPkgManager()->CreatePkgStream(outStream,
313         fileName, info->unpackedSize, PkgStream::PkgStreamType_MemoryMap);
314     if (ret != USCRIPT_SUCCESS || outStream == nullptr) {
315         LOG(ERROR) << "Error to create output stream";
316         return USCRIPT_ERROR_EXECUTE;
317     }
318     ret = env.GetPkgManager()->ExtractFile(fileName, outStream);
319     if (ret != USCRIPT_SUCCESS) {
320         LOG(ERROR) << "Error to extract file";
321         env.GetPkgManager()->ClosePkgStream(outStream);
322         return USCRIPT_ERROR_EXECUTE;
323     }
324     ret = outStream->GetBuffer(outBuf, buffSize);
325     LOG(DEBUG) << "outBuf data size is: " << buffSize;
326 
327     return USCRIPT_SUCCESS;
328 }
329 
ExecuteUpdateBlock(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)330 static int32_t ExecuteUpdateBlock(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
331 {
332     UpdateBlockInfo infos {};
333     if (GetUpdateBlockInfo(infos, env, context) != USCRIPT_SUCCESS) {
334         return USCRIPT_ERROR_EXECUTE;
335     }
336 
337     if (env.IsRetry()) {
338         LOG(DEBUG) << "Retry updater, check if current partition updatered already during last time";
339         if (PartitionRecord::GetInstance().IsPartitionUpdated(infos.partitionName)) {
340             LOG(INFO) << infos.partitionName << " already updated, skip";
341             return USCRIPT_SUCCESS;
342         }
343     }
344 
345     if (ExtractDiffPackageAndLoad(infos, env, context) != USCRIPT_SUCCESS) {
346         return USCRIPT_ERROR_EXECUTE;
347     }
348 
349     uint8_t *transferListBuffer = nullptr;
350     size_t transferListSize = 0;
351     Hpackage::PkgManager::StreamPtr outStream = nullptr;
352     if (ExtractFileByName(env, infos.transferName, outStream, transferListBuffer, transferListSize) != USCRIPT_SUCCESS) {
353         return USCRIPT_ERROR_EXECUTE;
354     }
355 
356     TransferManagerPtr tm = TransferManager::GetTransferManagerInstance();
357     auto globalParams = tm->GetGlobalParams();
358     /* Save Script Env to transfer manager */
359     globalParams->env = &env;
360 
361     std::vector<std::string> lines =
362         Updater::Utils::SplitString(std::string(reinterpret_cast<const char*>(transferListBuffer)), "\n");
363     // Close stream opened before.
364     env.GetPkgManager()->ClosePkgStream(outStream);
365 
366     LOG(INFO) << "Start unpack new data thread done. Get patch data: " << infos.patchDataName;
367     if (ExtractFileByName(env, infos.patchDataName, outStream,
368         globalParams->patchDataBuffer, globalParams->patchDataSize) != USCRIPT_SUCCESS) {
369         return USCRIPT_ERROR_EXECUTE;
370     }
371 
372     LOG(INFO) << "Ready to start a thread to handle new data processing";
373     if (InitThread(infos, env, context) != 0) {
374         LOG(ERROR) << "Failed to create pthread";
375         env.GetPkgManager()->ClosePkgStream(outStream);
376         return USCRIPT_ERROR_EXECUTE;
377     }
378 
379     int32_t ret = DoExecuteUpdateBlock(infos, env, outStream, lines, context);
380     TransferManager::ReleaseTransferManagerInstance(tm);
381     return ret;
382 }
383 
Execute(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)384 int32_t UScriptInstructionBlockUpdate::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
385 {
386     int32_t result = ExecuteUpdateBlock(env, context);
387     context.PushParam(result);
388     return result;
389 }
390 
ExecReadBlockInfo(const std::string & devPath,Uscript::UScriptContext & context,time_t & mountTime,uint16_t & mountCount)391 bool UScriptInstructionBlockCheck::ExecReadBlockInfo(const std::string &devPath, Uscript::UScriptContext &context,
392     time_t &mountTime, uint16_t &mountCount)
393 {
394     UPDATER_INIT_RECORD;
395     int fd = open(devPath.c_str(), O_RDWR | O_LARGEFILE);
396     if (fd == -1) {
397         LOG(ERROR) << "Failed to open file";
398         UPDATER_LAST_WORD(false);
399         return false;
400     }
401     std::vector<uint8_t> block_buff(H_BLOCK_SIZE);
402     BlockSet blk0(std::vector<BlockPair> {BlockPair{0, 1}});
403 
404     size_t pos = 0;
405     std::vector<BlockPair>::iterator it = blk0.Begin();
406     for (; it != blk0.End(); ++it) {
407         LOG(INFO) << "BlockSet::ReadDataFromBlock lseek64";
408         if (lseek64(fd, static_cast<off64_t>(it->first * H_BLOCK_SIZE), SEEK_SET) == -1) {
409             LOG(ERROR) << "Failed to seek";
410             close(fd);
411             UPDATER_LAST_WORD(false);
412             return false;
413         }
414         size_t size = (it->second - it->first) * H_BLOCK_SIZE;
415         LOG(INFO) << "BlockSet::ReadDataFromBlock Read " << size << " from block";
416         if (!Utils::ReadFully(fd, block_buff.data() + pos, size)) {
417             LOG(ERROR) << "Failed to read";
418             close(fd);
419             UPDATER_LAST_WORD(false);
420             return false;
421         }
422         pos += size;
423     }
424     close(fd);
425     mountTime = *reinterpret_cast<uint32_t *>(&block_buff[0x400 + 0x2C]);
426     mountCount = *reinterpret_cast<uint16_t *>(&block_buff[0x400 + 0x34]);
427     return true;
428 }
429 
Execute(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)430 int32_t UScriptInstructionBlockCheck::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
431 {
432     if (context.GetParamCount() != 1) {
433         LOG(ERROR) << "Invalid param";
434         UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM);
435         return ReturnAndPushParam(USCRIPT_INVALID_PARAM, context);
436     }
437     if (env.IsRetry()) {
438         return ReturnAndPushParam(USCRIPT_SUCCESS, context);
439     }
440     std::string partitionName;
441     int32_t ret = context.GetParam(0, partitionName);
442     if (ret != USCRIPT_SUCCESS) {
443         LOG(ERROR) << "Failed to get param";
444         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
445         return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context);
446     }
447     auto devPath = GetBlockDeviceByMountPoint(partitionName);
448     LOG(INFO) << "UScriptInstructionBlockCheck::dev path : " << devPath;
449     time_t mountTime = 0;
450     uint16_t mountCount = 0;
451     if (devPath.empty() || (!ExecReadBlockInfo(devPath, context, mountTime, mountCount))) {
452         LOG(ERROR) << "cannot get block device of partition";
453         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
454         return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context);
455     }
456 
457     if (mountCount > 0) {
458         std::ostringstream ostr;
459         ostr << "Device was remounted R/W " << mountCount << "times\nLast remount happened on " <<
460             ctime(&mountTime) << std::endl;
461         std::string message = ostr.str();
462         env.PostMessage("ui_log", message);
463     }
464     LOG(INFO) << "UScriptInstructionBlockCheck::Execute Success";
465     context.PushParam(USCRIPT_SUCCESS);
466     return USCRIPT_SUCCESS;
467 }
468 
ExecReadShaInfo(const std::string & devPath,const std::string & blockPairs,const std::string & contrastSha,Uscript::UScriptContext & context)469 int UScriptInstructionShaCheck::ExecReadShaInfo(const std::string &devPath, const std::string &blockPairs,
470     const std::string &contrastSha, Uscript::UScriptContext &context)
471 {
472     UPDATER_INIT_RECORD;
473     int fd = open(devPath.c_str(), O_RDWR | O_LARGEFILE);
474     if (fd == -1) {
475         LOG(ERROR) << "Failed to open file";
476         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
477         return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context);
478     }
479 
480     BlockSet blk;
481     blk.ParserAndInsert(blockPairs);
482     std::vector<uint8_t> block_buff(H_BLOCK_SIZE);
483     SHA256_CTX ctx;
484     SHA256_Init(&ctx);
485     std::vector<BlockPair>::iterator it = blk.Begin();
486     for (; it != blk.End(); ++it) {
487         if (lseek64(fd, static_cast<off64_t>(it->first * H_BLOCK_SIZE), SEEK_SET) == -1) {
488             LOG(ERROR) << "Failed to seek";
489             close(fd);
490             UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
491             return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context);
492         }
493         for (size_t i = it->first; i < it->second; ++i) {
494             if (!Utils::ReadFully(fd, block_buff.data(), H_BLOCK_SIZE)) {
495                 LOG(ERROR) << "Failed to read";
496                 close(fd);
497                 UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
498                 return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context);
499             }
500             SHA256_Update(&ctx, block_buff.data(), H_BLOCK_SIZE);
501         }
502     }
503     close(fd);
504 
505     uint8_t digest[SHA256_DIGEST_LENGTH];
506     SHA256_Final(digest, &ctx);
507     std::string resultSha = Utils::ConvertSha256Hex(digest, SHA256_DIGEST_LENGTH);
508     if (resultSha != contrastSha) {
509         LOG(ERROR) << "Different sha256, cannot continue";
510         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
511         return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context);
512     }
513     LOG(INFO) << "UScriptInstructionShaCheck::Execute Success";
514     context.PushParam(USCRIPT_SUCCESS);
515     return USCRIPT_SUCCESS;
516 }
517 
Execute(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)518 int32_t UScriptInstructionShaCheck::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
519 {
520     if (context.GetParamCount() != SHA_CHECK_PARAMS) {
521         LOG(ERROR) << "Invalid param";
522         UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM);
523         return ReturnAndPushParam(USCRIPT_INVALID_PARAM, context);
524     }
525     if (env.IsRetry()) {
526         return ReturnAndPushParam(USCRIPT_SUCCESS, context);
527     }
528 
529     std::string partitionName;
530     int32_t ret = context.GetParam(0, partitionName);
531     if (ret != USCRIPT_SUCCESS) {
532         LOG(ERROR) << "Failed to get param";
533         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
534         return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context);
535     }
536     std::string blockPairs;
537     ret = context.GetParam(1, blockPairs);
538     if (ret != USCRIPT_SUCCESS) {
539         LOG(ERROR) << "Failed to get param";
540         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
541         return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context);
542     }
543     std::string contrastSha;
544     ret = context.GetParam(SHA_CHECK_SECOND, contrastSha);
545     if (ret != USCRIPT_SUCCESS) {
546         LOG(ERROR) << "Failed to get param";
547         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
548         return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context);
549     }
550     auto devPath = GetBlockDeviceByMountPoint(partitionName);
551     LOG(INFO) << "UScriptInstructionShaCheck::dev path : " << devPath;
552     if (devPath.empty()) {
553         LOG(ERROR) << "cannot get block device of partition";
554         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
555         return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context);
556     }
557     return ExecReadShaInfo(devPath, blockPairs, contrastSha, context);
558 }
559 }
560