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