• 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 
16 #include "utils.h"
17 #include <algorithm>
18 #include <cerrno>
19 #include <cstdint>
20 #include <cstdlib>
21 #include <dirent.h>
22 #include <fcntl.h>
23 #include <limits>
24 #include <linux/reboot.h>
25 #include <string>
26 #include <sys/reboot.h>
27 #include <sys/stat.h>
28 #include <sys/syscall.h>
29 #include <unistd.h>
30 #include <vector>
31 #include "fs_manager/mount.h"
32 #include "init_reboot.h"
33 #include "log/log.h"
34 #include "misc_info/misc_info.h"
35 #ifdef WITH_SELINUX
36 #include <policycoreutils.h>
37 #include "selinux/selinux.h"
38 #endif
39 #include "package/pkg_manager.h"
40 #include "parameter.h"
41 #include "securec.h"
42 #include "updater/updater_const.h"
43 #include "scope_guard.h"
44 
45 namespace Updater {
46 using namespace Hpackage;
47 
48 namespace Utils {
49 constexpr uint8_t SHIFT_RIGHT_FOUR_BITS = 4;
50 constexpr int MAX_TIME_SIZE = 20;
51 constexpr size_t PARAM_SIZE = 32;
52 constexpr const char *PREFIX_PARTITION_NODE = "/dev/block/by-name/";
53 constexpr mode_t DEFAULT_DIR_MODE = 0775;
54 
55 namespace {
UpdateInfoInMisc(const std::string headInfo,const std::optional<int> message,bool isRemove)56 void UpdateInfoInMisc(const std::string headInfo, const std::optional<int> message, bool isRemove)
57 {
58     if (headInfo.empty()) {
59         return;
60     }
61     std::vector<std::string> args = Utils::ParseParams(0, nullptr);
62     struct UpdateMessage msg {};
63     if (!ReadUpdaterMiscMsg(msg)) {
64         LOG(ERROR) << "SetMessageToMisc read misc failed";
65         return;
66     }
67 
68     (void)memset_s(msg.update, sizeof(msg.update), 0, sizeof(msg.update));
69     for (const auto& arg : args) {
70         if (arg.find(headInfo) == std::string::npos) {
71             if (strncat_s(msg.update, sizeof(msg.update), arg.c_str(), strlen(arg.c_str()) + 1) != EOK) {
72                 LOG(ERROR) << "SetMessageToMisc strncat_s failed";
73                 return;
74             }
75             if (strncat_s(msg.update, sizeof(msg.update), "\n", strlen("\n") + 1) != EOK) {
76                 LOG(ERROR) << "SetMessageToMisc strncat_s failed";
77                 return;
78             }
79         }
80     }
81     char buffer[128] {}; // 128 : set headInfo size
82     if (isRemove) {
83         LOG(INFO) << "remove --" << headInfo << " from misc";
84     } else if (!message.has_value()) {
85         if (snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "--%s", headInfo.c_str()) == -1) {
86             LOG(ERROR) << "SetMessageToMisc snprintf_s failed";
87             return;
88         }
89     } else {
90         if (snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "--%s=%d",
91             headInfo.c_str(), message.value()) == -1) {
92             LOG(ERROR) << "SetMessageToMisc snprintf_s failed";
93             return;
94         }
95     }
96     if (strncat_s(msg.update, sizeof(msg.update), buffer, strlen(buffer) + 1) != EOK) {
97         LOG(ERROR) << "SetMessageToMisc strncat_s failed";
98         return;
99     }
100     if (WriteUpdaterMiscMsg(msg) != true) {
101         LOG(ERROR) << "Write command to misc failed.";
102     }
103 }
104 } // namespace
105 
SaveLogs()106 void SaveLogs()
107 {
108     std::string updaterLogPath = std::string(UPDATER_LOG);
109     std::string stageLogPath = std::string(UPDATER_STAGE_LOG);
110 
111     // save logs
112     bool ret = CopyUpdaterLogs(TMP_LOG, updaterLogPath);
113     if (!ret) {
114         LOG(ERROR) << "Copy updater log failed!";
115     }
116 
117     mode_t mode = 0660;
118 #ifndef __WIN32
119     SetFileAttributes(updaterLogPath, USER_UPDATE_AUTHORITY, GROUP_UPDATE_AUTHORITY, mode);
120 #endif
121 
122     STAGE(UPDATE_STAGE_SUCCESS) << "PostUpdater";
123     ret = CopyUpdaterLogs(TMP_STAGE_LOG, stageLogPath);
124     chmod(stageLogPath.c_str(), mode);
125     if (!ret) {
126         LOG(ERROR) << "Copy stage log failed!";
127     }
128 }
129 
DeleteFile(const std::string & filename)130 int32_t DeleteFile(const std::string& filename)
131 {
132     if (filename.empty()) {
133         LOG(ERROR) << "Invalid filename";
134         return -1;
135     }
136     if (unlink(filename.c_str()) == -1 && errno != ENOENT) {
137         LOG(ERROR) << "unlink " << filename << " failed";
138         return -1;
139     }
140     return 0;
141 }
142 
SplitString(const std::string & str,const std::string del)143 std::vector<std::string> SplitString(const std::string &str, const std::string del)
144 {
145     std::vector<std::string> result;
146     size_t found = std::string::npos;
147     size_t start = 0;
148     while (true) {
149         found = str.find_first_of(del, start);
150         result.push_back(str.substr(start, found - start));
151         if (found == std::string::npos) {
152             break;
153         }
154         start = found + 1;
155     }
156     return result;
157 }
158 
Trim(const std::string & str)159 std::string Trim(const std::string &str)
160 {
161     if (str.empty()) {
162         LOG(ERROR) << "str is empty";
163         return str;
164     }
165     size_t start = 0;
166     size_t end = str.size() - 1;
167     while (start < str.size()) {
168         if (!isspace(str[start])) {
169             break;
170         }
171         start++;
172     }
173     while (start < end) {
174         if (!isspace(str[end])) {
175             break;
176         }
177         end--;
178     }
179     if (end < start) {
180         return "";
181     }
182     return str.substr(start, end - start + 1);
183 }
184 
ConvertSha256Hex(const uint8_t * shaDigest,size_t length)185 std::string ConvertSha256Hex(const uint8_t* shaDigest, size_t length)
186 {
187     const std::string hexChars = "0123456789abcdef";
188     std::string haxSha256 = "";
189     unsigned int c;
190     for (size_t i = 0; i < length; ++i) {
191         auto d = shaDigest[i];
192         c = (d >> SHIFT_RIGHT_FOUR_BITS) & 0xf;     // last 4 bits
193         haxSha256.push_back(hexChars[c]);
194         haxSha256.push_back(hexChars[d & 0xf]);
195     }
196     return haxSha256;
197 }
198 
SetRebootMisc(const std::string & rebootTarget,const std::string & extData,struct UpdateMessage & msg)199 bool SetRebootMisc(const std::string& rebootTarget, const std::string &extData, struct UpdateMessage &msg)
200 {
201     static const int32_t maxCommandSize = 16;
202     int result = 0;
203     if (rebootTarget == "updater" && strcmp(msg.command, "boot_updater") != 0) {
204         result = strcpy_s(msg.command, maxCommandSize, "boot_updater");
205     } else if (rebootTarget == "flashd" && strcmp(msg.command, "flashd") != 0) {
206         result = strcpy_s(msg.command, maxCommandSize, "boot_flash");
207     } else if (rebootTarget == "bootloader" && strcmp(msg.command, "boot_loader") != 0) {
208         result = strcpy_s(msg.command, maxCommandSize, "boot_loader");
209     }
210     if (result != EOK) {
211         LOG(ERROR) << "reboot set misc strcpy failed";
212         return false;
213     }
214     msg.command[maxCommandSize] = 0;
215     if (extData.empty()) {
216         (void)memset_s(msg.update, sizeof(msg.update), 0, sizeof(msg.update));
217         return true;
218     }
219     if (strcpy_s(msg.update, sizeof(msg.update) - 1, extData.c_str()) != EOK) {
220         LOG(ERROR) << "failed to copy update";
221         return false;
222     }
223     msg.update[sizeof(msg.update) - 1] = 0;
224     return true;
225 }
226 
UpdaterDoReboot(const std::string & rebootTarget,const std::string & rebootReason,const std::string & extData)227 void UpdaterDoReboot(const std::string& rebootTarget, const std::string &rebootReason, const std::string &extData)
228 {
229     LOG(INFO) << ", rebootTarget: " << rebootTarget;
230     LOG(INFO) << ", rebootReason: " << rebootReason;
231     LoadFstab();
232     struct UpdateMessage msg = {};
233     if (rebootTarget.empty()) {
234         if (WriteUpdaterMiscMsg(msg) != true) {
235             LOG(INFO) << "UpdaterDoReboot: WriteUpdaterMessage empty error";
236         }
237     } else {
238         if (!ReadUpdaterMiscMsg(msg)) {
239             LOG(ERROR) << "UpdaterDoReboot read misc failed";
240         }
241         if (!SetRebootMisc(rebootTarget, extData, msg)) {
242             LOG(ERROR) << "UpdaterDoReboot set misc failed";
243         }
244         if (!WriteUpdaterMiscMsg(msg)) {
245             LOG(INFO) << "UpdaterDoReboot: WriteUpdaterMiscMsg error";
246         }
247     }
248     sync();
249 #ifndef UPDATER_UT
250     DoRebootExt(rebootTarget.c_str(), rebootReason.c_str());
251     while (true) {
252         pause();
253     }
254 #else
255     return;
256 #endif
257 }
258 
DoShutdown(const std::string & shutdownReason)259 void DoShutdown(const std::string &shutdownReason)
260 {
261     UpdateMessage msg = {};
262     if (!WriteUpdaterMiscMsg(msg)) {
263         LOG(ERROR) << "DoShutdown: WriteUpdaterMessage empty error";
264         return;
265     }
266     sync();
267     DoRebootExt("shutdown", shutdownReason.c_str());
268 }
269 
GetCertName()270 std::string GetCertName()
271 {
272 #ifndef UPDATER_UT
273     static std::string signingCertName = "/etc/certificate/signing_cert.crt";
274 #ifdef SIGN_ON_SERVER
275     signingCertName = Updater::Utils::ON_SERVER;
276 #endif
277 #else
278     static std::string signingCertName = "/data/updater/src/signing_cert.crt";
279 #endif
280     return signingCertName;
281 }
282 
WriteFully(int fd,const uint8_t * data,size_t size)283 bool WriteFully(int fd, const uint8_t *data, size_t size)
284 {
285     ssize_t written = 0;
286     size_t rest = size;
287 
288     while (rest > 0) {
289         do {
290             written = write(fd, data, rest);
291         } while (written < 0 && errno == EINTR);
292         if (written < 0) {
293             return false;
294         }
295         data += written;
296         rest -= static_cast<size_t>(written);
297         if (rest != 0) {
298             LOG(INFO) << "totalSize =  " << size << ", rest =  " << rest;
299         }
300     }
301     return true;
302 }
303 
ReadFully(int fd,void * data,size_t size)304 bool ReadFully(int fd, void *data, size_t size)
305 {
306     auto p = reinterpret_cast<uint8_t *>(data);
307     size_t remaining = size;
308     while (remaining > 0) {
309         ssize_t sread = read(fd, p, remaining);
310         if (sread == -1) {
311             LOG(ERROR) << "read failed: " << strerror(errno);
312             return false;
313         }
314         if (sread == 0) {
315             LOG(ERROR) << "read reached unexpected EOF";
316             return false;
317         }
318         p += sread;
319         remaining -= static_cast<size_t>(sread);
320     }
321     return true;
322 }
323 
ReadFileToString(int fd,std::string & content)324 bool ReadFileToString(int fd, std::string &content)
325 {
326     struct stat sb {};
327     if (fstat(fd, &sb) != -1 && sb.st_size > 0) {
328         content.resize(static_cast<size_t>(sb.st_size));
329     }
330     ssize_t n;
331     auto remaining = static_cast<size_t>(sb.st_size);
332     auto p = reinterpret_cast<char *>(content.data());
333     while (remaining > 0) {
334         n = read(fd, p, remaining);
335         if (n <= 0) {
336             return false;
337         }
338         p += n;
339         remaining -= static_cast<size_t>(n);
340     }
341     return true;
342 }
343 
WriteStringToFile(int fd,const std::string & content)344 bool WriteStringToFile(int fd, const std::string& content)
345 {
346     const char *p = content.data();
347     size_t remaining = content.size();
348     while (remaining > 0) {
349         ssize_t n = write(fd, p, remaining);
350         if (n == -1) {
351             return false;
352         }
353         p += n;
354         remaining -= static_cast<size_t>(n);
355     }
356     return true;
357 }
358 
SyncFile(const std::string & dst)359 void SyncFile(const std::string &dst)
360 {
361     int fd = open(dst.c_str(), O_RDWR);
362     if (fd < 0) {
363         LOG(ERROR) << "open " << dst << " failed! err " << strerror(errno);
364         return;
365     }
366     fsync(fd);
367     close(fd);
368 }
369 
CopyFile(const std::string & src,const std::string & dest,bool isAppend)370 bool CopyFile(const std::string &src, const std::string &dest, bool isAppend)
371 {
372     char realPath[PATH_MAX + 1] = {0};
373     if (realpath(src.c_str(), realPath) == nullptr) {
374         LOG(ERROR) << src << " get realpath fail";
375         return false;
376     }
377 
378     std::ios_base::openmode mode = isAppend ? std::ios::app | std::ios::out : std::ios_base::out;
379     std::ifstream fin(realPath);
380     std::ofstream fout(dest, mode);
381     if (!fin.is_open() || !fout.is_open()) {
382         return false;
383     }
384 
385     fout << fin.rdbuf();
386     if (fout.fail()) {
387         fout.clear();
388         return false;
389     }
390     fout.flush();
391     fout.close();
392     SyncFile(dest); // no way to get fd from ofstream, so reopen to sync this file
393     return true;
394 }
395 
CopyDir(const std::string & srcPath,const std::string & dstPath)396 bool CopyDir(const std::string &srcPath, const std::string &dstPath)
397 {
398     DIR *dir = opendir(srcPath.c_str());
399     if (dir == nullptr) {
400         LOG(ERROR) << "opendir failed, path: " << srcPath.c_str() << ", err: " << strerror(errno);
401         return false;
402     }
403     ON_SCOPE_EXIT(closedir) {
404         closedir(dir);
405     };
406     bool existFlag = (access(dstPath.c_str(), 0) == 0);
407     if ((!existFlag) && (mkdir(dstPath.c_str(), DEFAULT_DIR_MODE) != 0)) {
408         LOG(ERROR) << "mkdir failed, path: " << dstPath.c_str() << ", err: " << strerror(errno);
409         return false;
410     }
411     ON_SCOPE_EXIT(rmdir) {
412         if (!existFlag) {
413             remove(dstPath.c_str());
414         }
415     };
416     dirent *dirent = nullptr;
417     while ((dirent = readdir(dir)) != nullptr) {
418         if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) {
419             continue;
420         }
421         if (dirent->d_type == DT_DIR) {
422             std::string fullSourcePath = srcPath + dirent->d_name + "/";
423             std::string fullDestPath = dstPath + dirent->d_name + "/";
424             if (!CopyDir(fullSourcePath, fullDestPath)) {
425                 LOG(ERROR) << "copydir failed, fullSourcePath: " << fullSourcePath.c_str()
426                           << ", fullDestPath: " << fullDestPath.c_str();
427                 return false;
428             }
429         } else {
430             std::string fullSourcePath = srcPath + dirent->d_name;
431             std::string fullDestPath = dstPath + dirent->d_name;
432             if (!CopyFile(fullSourcePath, fullDestPath)) {
433                 LOG(ERROR) << "copyfile failed, fullSourcePath: " << fullSourcePath.c_str()
434                           << ", fullDestPath: " << fullDestPath.c_str();
435                 return false;
436             }
437         }
438     }
439     CANCEL_SCOPE_EXIT_GUARD(rmdir);
440     return true;
441 }
442 
GetLocalBoardId()443 std::string GetLocalBoardId()
444 {
445     return "HI3516";
446 }
447 
CreateCompressLogFile(const std::string & pkgName,std::vector<std::pair<std::string,ZipFileInfo>> & files)448 int32_t CreateCompressLogFile(const std::string &pkgName, std::vector<std::pair<std::string, ZipFileInfo>> &files)
449 {
450     PkgInfo pkgInfo;
451     pkgInfo.signMethod = PKG_SIGN_METHOD_NONE;
452     pkgInfo.digestMethod = PKG_SIGN_METHOD_NONE;
453     pkgInfo.pkgType = PKG_PACK_TYPE_ZIP;
454     PkgManager::PkgManagerPtr pkgManager = PkgManager::CreatePackageInstance();
455     if (pkgManager == nullptr) {
456         LOG(ERROR) << "pkgManager is nullptr";
457         return -1;
458     }
459     int32_t ret = pkgManager->CreatePackage(pkgName, GetCertName(), &pkgInfo, files);
460     PkgManager::ReleasePackageInstance(pkgManager);
461     return ret;
462 }
463 
CompressFiles(std::vector<std::string> & files,const std::string & zipFile)464 void CompressFiles(std::vector<std::string> &files, const std::string &zipFile)
465 {
466     (void)DeleteFile(zipFile);
467     std::vector<std::pair<std::string, ZipFileInfo>> zipFiles {};
468     for (auto path : files) {
469         ZipFileInfo file {};
470         file.fileInfo.identity = path.substr(path.find_last_of("/") + 1);
471         file.fileInfo.packMethod = PKG_COMPRESS_METHOD_ZIP;
472         file.fileInfo.digestMethod = PKG_DIGEST_TYPE_CRC;
473         zipFiles.push_back(std::pair<std::string, ZipFileInfo>(path, file));
474     }
475 
476     int32_t ret = CreateCompressLogFile(zipFile, zipFiles);
477     if (ret != 0) {
478         LOG(WARNING) << "CompressFiles failed: " << zipFile;
479         return;
480     }
481     mode_t mode = 0660;
482 #ifndef __WIN32
483     SetFileAttributes(zipFile, USER_UPDATE_AUTHORITY, GROUP_SYS_AUTHORITY, mode);
484 #endif
485 }
486 
CompressLogs(const std::string & logName)487 void CompressLogs(const std::string &logName)
488 {
489     std::vector<std::pair<std::string, ZipFileInfo>> files;
490     // Build the zip file to be packaged
491     std::vector<std::string> testFileNames;
492     std::string realName = logName.substr(logName.find_last_of("/") + 1);
493     std::string logPath = logName.substr(0, logName.find_last_of("/"));
494     testFileNames.push_back(realName);
495     for (auto name : testFileNames) {
496         ZipFileInfo file;
497         file.fileInfo.identity = name;
498         file.fileInfo.packMethod = PKG_COMPRESS_METHOD_ZIP;
499         file.fileInfo.digestMethod = PKG_DIGEST_TYPE_CRC;
500         std::string fileName = logName;
501         files.push_back(std::pair<std::string, ZipFileInfo>(fileName, file));
502     }
503 
504     char realTime[MAX_TIME_SIZE] = {0};
505     auto sysTime = std::chrono::system_clock::now();
506     auto currentTime = std::chrono::system_clock::to_time_t(sysTime);
507     struct tm *localTime = std::localtime(&currentTime);
508     if (localTime != nullptr) {
509         std::strftime(realTime, sizeof(realTime), "%Y%m%d%H%M%S", localTime);
510     }
511     char pkgName[MAX_LOG_NAME_SIZE];
512     if (snprintf_s(pkgName, MAX_LOG_NAME_SIZE, MAX_LOG_NAME_SIZE - 1,
513         "%s/%s_%s.zip", logPath.c_str(), realName.c_str(), realTime) == -1) {
514         return;
515     }
516     int32_t ret = CreateCompressLogFile(pkgName, files);
517     if (ret != 0) {
518         LOG(WARNING) << "CompressLogs failed";
519         return;
520     }
521     mode_t mode = 0660;
522 #ifndef __WIN32
523     SetFileAttributes(pkgName, USER_UPDATE_AUTHORITY, GROUP_SYS_AUTHORITY, mode);
524 #endif
525     sync();
526     if (access(pkgName, 0) != 0) {
527         LOG(ERROR) << "Failed to create zipfile: " << pkgName;
528     } else {
529         (void)DeleteFile(logName);
530     }
531 }
532 
GetFileSize(const std::string & filePath)533 size_t GetFileSize(const std::string &filePath)
534 {
535     size_t ret = 0;
536     std::ifstream ifs(filePath, std::ios::binary | std::ios::in);
537     if (ifs.is_open()) {
538         ifs.seekg(0, std::ios::end);
539         ret = static_cast<size_t>(ifs.tellg());
540     }
541     return ret;
542 }
543 
RestoreconPath(const std::string & path)544 bool RestoreconPath(const std::string &path)
545 {
546     if (MountForPath(path) != 0) {
547         LOG(ERROR) << "MountForPath " << path << " failed!";
548         return false;
549     }
550 #ifdef WITH_SELINUX
551     if (RestoreconRecurse(path.c_str()) == -1) {
552         LOG(WARNING) << "restore " << path << " failed";
553     }
554 #endif // WITH_SELINUX
555     if (UmountForPath(path) != 0) {
556         LOG(WARNING) << "UmountForPath " << path << " failed!";
557     }
558     return true;
559 }
560 
CopyUpdaterLogs(const std::string & sLog,const std::string & dLog)561 bool CopyUpdaterLogs(const std::string &sLog, const std::string &dLog)
562 {
563     std::size_t found = dLog.find_last_of("/");
564     if (found == std::string::npos) {
565         LOG(ERROR) << "Dest filePath error";
566         return false;
567     }
568     std::string destPath = dLog.substr(0, found);
569     if (MountForPath(destPath) != 0) {
570         LOG(WARNING) << "MountForPath /data/log failed!";
571     }
572 
573     if (access(destPath.c_str(), 0) != 0) {
574         if (MkdirRecursive(destPath.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
575             LOG(ERROR) << "MkdirRecursive error!";
576             return false;
577         }
578         #ifdef WITH_SELINUX
579             RestoreconRecurse(UPDATER_PATH);
580         #endif // WITH_SELINUX
581     }
582 
583     if (Utils::GetFileSize(sLog) > MAX_LOG_SIZE) {
584         LOG(ERROR) << "Size bigger for" << sLog;
585         STAGE(UPDATE_STAGE_FAIL) << "Log file error, unable to copy";
586         return false;
587     }
588 
589     while (Utils::GetFileSize(sLog) + GetDirSizeForFile(dLog) > MAX_LOG_DIR_SIZE) {
590         if (DeleteOldFile(destPath) != true) {
591             break;
592         }
593     }
594 
595     if (!CopyFile(sLog, dLog, true)) {
596         LOG(ERROR) << "copy log file failed.";
597         return false;
598     }
599     if (GetFileSize(dLog) >= MAX_LOG_SIZE) {
600         LOG(INFO) << "log size greater than 5M!";
601         CompressLogs(dLog);
602     }
603     sync();
604     return true;
605 }
606 
CheckResultFail()607 bool CheckResultFail()
608 {
609     std::ifstream ifs;
610     const std::string resultPath = std::string(UPDATER_PATH) + "/" + std::string(UPDATER_RESULT_FILE);
611     ifs.open(resultPath, std::ios::in);
612     std::string buff;
613     while (ifs.is_open() && getline(ifs, buff)) {
614         if (buff.find("fail|") != std::string::npos) {
615             ifs.close();
616             return true;
617         }
618     }
619     LOG(ERROR) << "open result file failed";
620     return false;
621 }
622 
WriteDumpResult(const std::string & result,const std::string & fileName)623 void WriteDumpResult(const std::string &result, const std::string &fileName)
624 {
625     if (access(UPDATER_PATH, 0) != 0) {
626         if (MkdirRecursive(UPDATER_PATH, 0755) != 0) { // 0755: -rwxr-xr-x
627             LOG(ERROR) << "MkdirRecursive error!";
628             return;
629         }
630     }
631     const std::string resultPath = std::string(UPDATER_PATH) + "/" + fileName;
632     FILE *fp = fopen(resultPath.c_str(), "w+");
633     if (fp == nullptr) {
634         LOG(ERROR) << "open result file failed";
635         return;
636     }
637     char buf[MAX_RESULT_BUFF_SIZE] = "Pass\n";
638     if (sprintf_s(buf, MAX_RESULT_BUFF_SIZE - 1, "%s\n", result.c_str()) < 0) {
639         LOG(WARNING) << "sprintf status fialed";
640     }
641     if (fwrite(buf, 1, strlen(buf) + 1, fp) <= 0) {
642         LOG(WARNING) << "write result file failed, err:" << errno;
643     }
644     if (fclose(fp) != 0) {
645         LOG(WARNING) << "close result file failed";
646     }
647 
648     (void)chown(resultPath.c_str(), USER_ROOT_AUTHORITY, GROUP_UPDATE_AUTHORITY);
649     (void)chmod(resultPath.c_str(), 0660); // 0660: -rw-rw----
650 }
651 
GetDirSize(const std::string & folderPath)652 long long int GetDirSize(const std::string &folderPath)
653 {
654     DIR* dir = opendir(folderPath.c_str());
655     if (dir == nullptr) {
656         LOG(ERROR) << "Failed to open folder: " << folderPath << std::endl;
657         return 0;
658     }
659 
660     struct dirent* entry;
661     long long int totalSize = 0;
662     while ((entry = readdir(dir)) != nullptr) {
663         std::string fileName = entry->d_name;
664         std::string filePath = folderPath + "/" + fileName;
665         struct stat fileStat;
666         if (stat(filePath.c_str(), &fileStat) != 0) {
667             LOG(ERROR) << "Failed to get file status: " << filePath << std::endl;
668             continue;
669         }
670         if (S_ISDIR(fileStat.st_mode)) {
671             if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
672                 continue;
673             }
674             std::string subFolderPath = filePath;
675             totalSize += GetDirSize(subFolderPath);
676         } else {
677             totalSize += fileStat.st_size;
678         }
679     }
680     closedir(dir);
681     return totalSize;
682 }
683 
GetDirSizeForFile(const std::string & filePath)684 long long int GetDirSizeForFile(const std::string &filePath)
685 {
686     std::size_t found = filePath.find_last_of("/");
687     if (found == std::string::npos) {
688         LOG(ERROR) << "filePath error";
689         return -1;
690     }
691     return GetDirSize(filePath.substr(0, found));
692 }
693 
DeleteOldFile(const std::string folderPath)694 bool DeleteOldFile(const std::string folderPath)
695 {
696     DIR* dir = opendir(folderPath.c_str());
697     if (dir == nullptr) {
698         LOG(ERROR) << "Failed to open folder: " << folderPath << std::endl;
699         return false;
700     }
701 
702     struct dirent* entry;
703     std::string oldestFilePath = "";
704     time_t oldestFileTime = std::numeric_limits<time_t>::max();
705     while ((entry = readdir(dir)) != nullptr) {
706         std::string fileName = entry->d_name;
707         std::string filePath = folderPath + "/" + fileName;
708         struct stat fileStat;
709         if (stat(filePath.c_str(), &fileStat) != 0) {
710             LOG(ERROR) << "Failed to get file status: " << filePath;
711             continue;
712         }
713         if (fileName == "." || fileName == "..") {
714             continue;
715         }
716         if (fileStat.st_mtime < oldestFileTime) {
717             oldestFileTime = fileStat.st_mtime;
718             oldestFilePath = filePath;
719         }
720     }
721     closedir(dir);
722     if (oldestFilePath.empty()) {
723         LOG(ERROR) << "Unable to delete file";
724         return false;
725     }
726     size_t size = GetFileSize(oldestFilePath);
727     if (remove(oldestFilePath.c_str()) != 0) {
728         LOG(ERROR) << "Failed to delete file: " << oldestFilePath;
729         return false;
730     }
731     LOG(INFO) << "Delete old file: " << oldestFilePath << " size: " << size;
732     return true;
733 }
734 
ParseParams(int argc,char ** argv)735 std::vector<std::string> ParseParams(int argc, char **argv)
736 {
737     struct UpdateMessage boot {};
738     // read from misc
739     if (!ReadUpdaterMiscMsg(boot)) {
740         LOG(ERROR) << "ReadUpdaterMessage MISC_FILE failed!";
741     }
742     // if boot.update is empty, read from command.The Misc partition may have dirty data,
743     // so strlen(boot.update) is not used, which can cause system exceptions.
744     if (boot.update[0] == '\0' && !access(COMMAND_FILE, 0)) {
745         if (!ReadUpdaterMessage(COMMAND_FILE, boot)) {
746             LOG(ERROR) << "ReadUpdaterMessage COMMAND_FILE failed!";
747         }
748     }
749 
750     boot.update[sizeof(boot.update) - 1] = '\0';
751     std::vector<std::string> parseParams = Utils::SplitString(boot.update, "\n");
752     if (argc != 0 && argv != nullptr) {
753         parseParams.insert(parseParams.begin(), argv, argv + argc);
754     }
755     return parseParams;
756 }
757 
TrimUpdateMode(const std::string & mode)758 std::string TrimUpdateMode(const std::string &mode)
759 {
760     std::string optEqual = "=";
761     std::string modePrefix = "--"; // misc = --update_package=xxxx / --sdcard_update
762     size_t optPos = mode.size();
763     size_t prefixPos = 0;
764     if (mode.empty() || mode == "") {
765         return "";
766     }
767     if (mode.find(optEqual) != std::string::npos) {
768         optPos = mode.find(optEqual);
769     }
770     if (mode.find(modePrefix) != std::string::npos) {
771         prefixPos = mode.find(modePrefix) + modePrefix.size();
772     }
773     if (optPos < prefixPos) {
774         return mode;
775     }
776     return mode.substr(prefixPos, optPos - prefixPos);
777 }
778 
CheckUpdateMode(const std::string & mode)779 bool CheckUpdateMode(const std::string &mode)
780 {
781     std::vector<std::string> args = ParseParams(0, nullptr);
782     for (const auto &arg : args) {
783         if (TrimUpdateMode(arg) == mode) {
784             return true;
785         }
786     }
787     return false;
788 }
789 
DurationToString(std::vector<std::chrono::duration<double>> & durations,std::size_t pkgPosition,int precision)790 std::string DurationToString(std::vector<std::chrono::duration<double>> &durations, std::size_t pkgPosition,
791     int precision)
792 {
793     if (pkgPosition >= durations.size()) {
794         LOG(ERROR) << "pkg position is " << pkgPosition << ", duration's size is " << durations.size();
795         return "0";
796     }
797     std::ostringstream oss;
798     oss << std::fixed << std::setprecision(precision) << durations[pkgPosition].count();
799     return oss.str();
800 }
801 
GetRealPath(const std::string & path)802 std::string GetRealPath(const std::string &path)
803 {
804     char realPath[PATH_MAX + 1] = {0};
805     auto ret = realpath(path.c_str(), realPath);
806     return (ret == nullptr) ? "" : ret;
807 }
808 
GetPartitionRealPath(const std::string & name)809 std::string GetPartitionRealPath(const std::string &name)
810 {
811     return GetRealPath(PREFIX_PARTITION_NODE + name);
812 }
813 
SetMessageToMisc(const std::string & miscCmd,const int message,const std::string headInfo)814 void SetMessageToMisc(const std::string &miscCmd, const int message, const std::string headInfo)
815 {
816     if (headInfo.empty()) {
817         return;
818     }
819     std::vector<std::string> args = ParseParams(0, nullptr);
820     struct UpdateMessage msg {};
821     if (!ReadUpdaterMiscMsg(msg)) {
822         LOG(ERROR) << "SetMessageToMisc read misc failed";
823         return;
824     }
825     (void)memset_s(msg.command, sizeof(msg.command), 0, sizeof(msg.command));
826     if (strncpy_s(msg.command, sizeof(msg.command), miscCmd.c_str(), miscCmd.size() + 1) != EOK) {
827         LOG(ERROR) << "SetMessageToMisc strncpy_s failed";
828         return;
829     }
830     (void)memset_s(msg.update, sizeof(msg.update), 0, sizeof(msg.update));
831     for (const auto& arg : args) {
832         if (arg.find(headInfo) == std::string::npos) {
833             if (strncat_s(msg.update, sizeof(msg.update), arg.c_str(), strlen(arg.c_str()) + 1) != EOK) {
834                 LOG(ERROR) << "SetMessageToMisc strncat_s failed";
835                 return;
836             }
837             if (strncat_s(msg.update, sizeof(msg.update), "\n", strlen("\n") + 1) != EOK) {
838                 LOG(ERROR) << "SetMessageToMisc strncat_s failed";
839                 return;
840             }
841         }
842     }
843     char buffer[128] {}; // 128 : set headInfo size
844     if (headInfo == "sdcard_update") {
845         if (snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "--%s", headInfo.c_str()) == -1) {
846             LOG(ERROR) << "SetMessageToMisc snprintf_s failed";
847             return;
848         }
849     } else {
850         if (snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "--%s=%d", headInfo.c_str(), message) == -1) {
851             LOG(ERROR) << "SetMessageToMisc snprintf_s failed";
852             return;
853         }
854     }
855     if (strncat_s(msg.update, sizeof(msg.update), buffer, strlen(buffer) + 1) != EOK) {
856         LOG(ERROR) << "SetMessageToMisc strncat_s failed";
857         return;
858     }
859     if (WriteUpdaterMiscMsg(msg) != true) {
860         LOG(ERROR) << "Write command to misc failed.";
861     }
862 }
863 
SetCmdToMisc(const std::string & miscCmd)864 void SetCmdToMisc(const std::string &miscCmd)
865 {
866     struct UpdateMessage msg {};
867     if (!ReadUpdaterMiscMsg(msg)) {
868         LOG(ERROR) << "SetMessageToMisc read misc failed";
869         return;
870     }
871 
872     (void)memset_s(msg.command, sizeof(msg.command), 0, sizeof(msg.command));
873     if (strncpy_s(msg.command, sizeof(msg.command), miscCmd.c_str(), miscCmd.size() + 1) != EOK) {
874         LOG(ERROR) << "SetMessageToMisc strncpy_s failed";
875         return;
876     }
877 
878     if (WriteUpdaterMiscMsg(msg) != true) {
879         LOG(ERROR) << "Write command to misc failed.";
880     }
881 }
882 
AddUpdateInfoToMisc(const std::string headInfo,const std::optional<int> message)883 void AddUpdateInfoToMisc(const std::string headInfo, const std::optional<int> message)
884 {
885     UpdateInfoInMisc(headInfo, message, false);
886 }
887 
RemoveUpdateInfoFromMisc(const std::string & headInfo)888 void RemoveUpdateInfoFromMisc(const std::string &headInfo)
889 {
890     UpdateInfoInMisc(headInfo, std::nullopt, true);
891 }
892 
SetFaultInfoToMisc(const std::string & faultInfo)893 void SetFaultInfoToMisc(const std::string &faultInfo)
894 {
895     struct UpdateMessage msg {};
896     if (!ReadUpdaterMiscMsg(msg)) {
897         LOG(ERROR) << "SetMessageToMisc read misc failed";
898         return;
899     }
900 
901     (void)memset_s(msg.faultinfo, sizeof(msg.faultinfo), 0, sizeof(msg.faultinfo));
902     if (strncpy_s(msg.faultinfo, sizeof(msg.faultinfo), faultInfo.c_str(), faultInfo.size() + 1) != EOK) {
903         LOG(ERROR) << "SetMessageToMisc strncpy_s failed";
904         return;
905     }
906 
907     if (WriteUpdaterMiscMsg(msg) != true) {
908         LOG(ERROR) << "Write fault info to misc failed.";
909     }
910 }
911 
CheckFaultInfo(const std::string & faultInfo)912 bool CheckFaultInfo(const std::string &faultInfo)
913 {
914     struct UpdateMessage msg = {};
915     if (!ReadUpdaterMiscMsg(msg)) {
916         LOG(ERROR) << "read misc data failed";
917         return false;
918     }
919 
920     if (strcmp(msg.faultinfo, faultInfo.c_str()) == 0) {
921         return true;
922     }
923     return false;
924 }
925 
GetTagValInStr(const std::string & str,const std::string & tag,std::string & val)926 void GetTagValInStr(const std::string &str, const std::string &tag, std::string &val)
927 {
928     if (str.find(tag + "=") != std::string::npos) {
929         val = str.substr(str.find("=") + 1, str.size() - str.find("="));
930     }
931 }
932 
IsValidHexStr(const std::string & str)933 bool IsValidHexStr(const std::string &str)
934 {
935     for (const auto &ch : str) {
936         if (isxdigit(ch) == 0) {
937             return false;
938         }
939     }
940     return true;
941 }
942 
TrimString(std::string & str)943 void TrimString(std::string &str)
944 {
945     auto pos = str.find_last_not_of("\r\n");
946     if (pos != std::string::npos) {
947         str.erase(pos + 1, str.size() - pos);
948     }
949 }
950 
IsEsDevice()951 bool IsEsDevice()
952 {
953     char deviceType[PARAM_SIZE + 1] = {0};
954     if (GetParameter("ohos.boot.chiptype", "", deviceType, sizeof(deviceType) - 1) <= 0) {
955         LOG(ERROR) << "get device type failed";
956         return false;
957     }
958     LOG(INFO) << "device type is " << deviceType;
959     if (strstr(deviceType, "_es") == nullptr) {
960         return false;
961     }
962     return true;
963 }
964 
ConvertToUnsignedLongLong(const std::string & str,uint64_t & value)965 bool ConvertToUnsignedLongLong(const std::string &str, uint64_t &value)
966 {
967     char *endPtr = nullptr;
968     errno = 0;
969 
970     value = std::strtoull(str.c_str(), &endPtr, 0);
971 #ifndef UPDATER_UT
972     if (endPtr == str.c_str() || *endPtr != '\0' || errno == ERANGE) {
973         LOG(ERROR) << "Convert string to uint64_t failed, str " << str << " converted to value " << value;
974         return false;
975     }
976 #endif
977     return true;
978 }
979 
ConvertToLongLong(const std::string & str,int64_t & value)980 bool ConvertToLongLong(const std::string &str, int64_t &value)
981 {
982     char *endPtr = nullptr;
983     errno = 0;
984 
985     value = std::strtoll(str.c_str(), &endPtr, 10); // 10 : decimal scale
986 #ifndef UPDATER_UT
987     if (endPtr == str.c_str() || *endPtr != '\0' || errno == ERANGE) {
988         LOG(ERROR) << "Convert string to int64_t failed, str " << str << " converted to value " << value;
989         return false;
990     }
991 #endif
992     return true;
993 }
994 
ConvertToLong(const std::string & str,int32_t & value)995 bool ConvertToLong(const std::string &str, int32_t &value)
996 {
997     char *endPtr = nullptr;
998     errno = 0;
999 
1000     value = std::strtol(str.c_str(), &endPtr, 10); // 10 : decimal scale
1001 #ifndef UPDATER_UT
1002     if (endPtr == str.c_str() || *endPtr != '\0' || errno == ERANGE) {
1003         LOG(ERROR) << "Convert string to int32_t failed, str " << str << " converted to value " << value;
1004         return false;
1005     }
1006 #endif
1007     return true;
1008 }
1009 
ConvertToUnsignedLong(const std::string & str,uint32_t & value,int base)1010 bool ConvertToUnsignedLong(const std::string &str, uint32_t &value, int base)
1011 {
1012     char *endPtr = nullptr;
1013     errno = 0;
1014 
1015     value = std::strtoul(str.c_str(), &endPtr, base);
1016 #ifndef UPDATER_UT
1017     if (endPtr == str.c_str() || *endPtr != '\0' || errno == ERANGE) {
1018         LOG(ERROR) << "Convert string to uint32_t failed, str " << str << " converted to value " << value;
1019         return false;
1020     }
1021 #endif
1022     return true;
1023 }
1024 
ConvertToDouble(const std::string & str,double & value)1025 bool ConvertToDouble(const std::string &str, double &value)
1026 {
1027     char *endPtr = nullptr;
1028     errno = 0;
1029 
1030     value = std::strtod(str.c_str(), &endPtr);
1031 #ifndef UPDATER_UT
1032     if (endPtr == str.c_str() || *endPtr != '\0' || errno == ERANGE) {
1033         LOG(ERROR) << "Convert string to double failed, str " << str << " converted to value " << value;
1034         return false;
1035     }
1036 #endif
1037     return true;
1038 }
1039 
ConvertToFloat(const std::string & str,float & value)1040 bool ConvertToFloat(const std::string &str, float &value)
1041 {
1042     char *endPtr = nullptr;
1043     errno = 0;
1044 
1045     value = std::strtof(str.c_str(), &endPtr);
1046 #ifndef UPDATER_UT
1047     if (endPtr == str.c_str() || *endPtr != '\0' || errno == ERANGE) {
1048         LOG(ERROR) << "Convert string to float failed, str " << str << " converted to value " << value;
1049         return false;
1050     }
1051 #endif
1052     return true;
1053 }
1054 
1055 #ifndef __WIN32
SetFileAttributes(const std::string & file,uid_t owner,gid_t group,mode_t mode)1056 void SetFileAttributes(const std::string& file, uid_t owner, gid_t group, mode_t mode)
1057 {
1058 #ifdef WITH_SELINUX
1059     RestoreconRecurse(file.c_str());
1060 #endif // WITH_SELINUX
1061     if (chown(file.c_str(), USER_ROOT_AUTHORITY, GROUP_ROOT_AUTHORITY) != 0) {
1062         LOG(ERROR) << "Chown failed: " << file << " " << USER_ROOT_AUTHORITY << "," << GROUP_ROOT_AUTHORITY;
1063     }
1064     if (chmod(file.c_str(), mode) != EOK) {
1065         LOG(ERROR) << "chmod failed: " << file << " " << mode;
1066     }
1067     if (chown(file.c_str(), owner, group) != 0) {
1068         LOG(ERROR) << "Chown failed: " << file << " " << owner << "," << group;
1069     }
1070 }
1071 #endif
1072 } // Utils
InitLogger(const std::string & tag)1073 void __attribute__((weak)) InitLogger(const std::string &tag)
1074 {
1075     if (Utils::IsUpdaterMode()) {
1076         InitUpdaterLogger(tag, TMP_LOG, TMP_STAGE_LOG, TMP_ERROR_CODE_PATH);
1077     } else {
1078         InitUpdaterLogger(tag, SYS_INSTALLER_LOG, UPDATER_STAGE_LOG, ERROR_CODE_PATH);
1079     }
1080 }
1081 } // namespace Updater
1082