• 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 <limits>
23 #include <linux/reboot.h>
24 #include <string>
25 #include <sys/reboot.h>
26 #include <sys/stat.h>
27 #include <sys/syscall.h>
28 #include <unistd.h>
29 #include <vector>
30 #include "fs_manager/mount.h"
31 #include "init_reboot.h"
32 #include "log/log.h"
33 #include "misc_info/misc_info.h"
34 #ifdef WITH_SELINUX
35 #include <policycoreutils.h>
36 #include "selinux/selinux.h"
37 #endif
38 #include "package/pkg_manager.h"
39 #include "securec.h"
40 #include "updater/updater_const.h"
41 
42 namespace Updater {
43 using namespace Hpackage;
44 
45 namespace Utils {
46 constexpr uint8_t SHIFT_RIGHT_FOUR_BITS = 4;
47 constexpr int USECONDS_PER_SECONDS = 1000000; // 1s = 1000000us
48 constexpr int NANOSECS_PER_USECONDS = 1000; // 1us = 1000ns
49 constexpr int MAX_TIME_SIZE = 20;
50 
SaveLogs()51 void SaveLogs()
52 {
53     std::string updaterLogPath = std::string(UPDATER_LOG);
54     std::string stageLogPath = std::string(UPDATER_STAGE_LOG);
55 
56     // save logs
57     bool ret = CopyUpdaterLogs(TMP_LOG, updaterLogPath);
58     if (!ret) {
59         LOG(ERROR) << "Copy updater log failed!";
60     }
61 
62     mode_t mode = 0640;
63     chmod(updaterLogPath.c_str(), mode);
64 
65     STAGE(UPDATE_STAGE_SUCCESS) << "PostUpdater";
66     ret = CopyUpdaterLogs(TMP_STAGE_LOG, stageLogPath);
67     chmod(stageLogPath.c_str(), mode);
68     if (!ret) {
69         LOG(ERROR) << "Copy stage log failed!";
70     }
71 }
72 
DeleteFile(const std::string & filename)73 int32_t DeleteFile(const std::string& filename)
74 {
75     if (filename.empty()) {
76         LOG(ERROR) << "Invalid filename";
77         return -1;
78     }
79     if (unlink(filename.c_str()) == -1 && errno != ENOENT) {
80         LOG(ERROR) << "unlink " << filename << " failed";
81         return -1;
82     }
83     return 0;
84 }
85 
MkdirRecursive(const std::string & pathName,mode_t mode)86 int MkdirRecursive(const std::string &pathName, mode_t mode)
87 {
88     size_t slashPos = 0;
89     struct stat info {};
90     while (true) {
91         slashPos = pathName.find_first_of("/", slashPos);
92         if (slashPos == std::string::npos) {
93             break;
94         }
95         if (slashPos == 0) {
96             slashPos++;
97             continue;
98         }
99         if (slashPos > PATH_MAX) {
100             LOG(ERROR) << "path too long for mkdir";
101             return -1;
102         }
103         auto subDir = pathName.substr(0, slashPos);
104         LOG(INFO) << "subDir : " << subDir;
105         if (stat(subDir.c_str(), &info) != 0) {
106             int ret = mkdir(subDir.c_str(), mode);
107             if (ret && errno != EEXIST) {
108                 return ret;
109             }
110         }
111         slashPos++;
112     }
113     int ret = mkdir(pathName.c_str(), mode);
114     if (ret && errno != EEXIST) {
115         return ret;
116     }
117     return 0;
118 }
119 
GetFilesFromDirectory(const std::string & path,std::vector<std::string> & files,bool isRecursive)120 int64_t GetFilesFromDirectory(const std::string &path, std::vector<std::string> &files,
121     bool isRecursive)
122 {
123     struct stat sb {};
124     if (stat(path.c_str(), &sb) == -1) {
125         LOG(ERROR) << "Failed to stat";
126         return -1;
127     }
128     DIR *dirp = opendir(path.c_str());
129     struct dirent *dp;
130     int64_t totalSize = 0;
131     while ((dp = readdir(dirp)) != nullptr) {
132         std::string fileName = path + "/" + dp->d_name;
133         struct stat st {};
134         if (stat(fileName.c_str(), &st) == 0) {
135             std::string tmpName = dp->d_name;
136             if (tmpName == "." || tmpName == "..") {
137                 continue;
138             }
139             if (isRecursive && S_ISDIR(st.st_mode)) {
140                 totalSize += GetFilesFromDirectory(fileName, files, isRecursive);
141             }
142             files.push_back(fileName);
143             totalSize += st.st_size;
144         }
145     }
146     closedir(dirp);
147     return totalSize;
148 }
149 
SplitString(const std::string & str,const std::string del)150 std::vector<std::string> SplitString(const std::string &str, const std::string del)
151 {
152     std::vector<std::string> result;
153     size_t found = std::string::npos;
154     size_t start = 0;
155     while (true) {
156         found = str.find_first_of(del, start);
157         result.push_back(str.substr(start, found - start));
158         if (found == std::string::npos) {
159             break;
160         }
161         start = found + 1;
162     }
163     return result;
164 }
165 
Trim(const std::string & str)166 std::string Trim(const std::string &str)
167 {
168     if (str.empty()) {
169         LOG(ERROR) << "str is empty";
170         return str;
171     }
172     size_t start = 0;
173     size_t end = str.size() - 1;
174     while (start < str.size()) {
175         if (!isspace(str[start])) {
176             break;
177         }
178         start++;
179     }
180     while (start < end) {
181         if (!isspace(str[end])) {
182             break;
183         }
184         end--;
185     }
186     if (end < start) {
187         return "";
188     }
189     return str.substr(start, end - start + 1);
190 }
191 
ConvertSha256Hex(const uint8_t * shaDigest,size_t length)192 std::string ConvertSha256Hex(const uint8_t* shaDigest, size_t length)
193 {
194     const std::string hexChars = "0123456789abcdef";
195     std::string haxSha256 = "";
196     unsigned int c;
197     for (size_t i = 0; i < length; ++i) {
198         auto d = shaDigest[i];
199         c = (d >> SHIFT_RIGHT_FOUR_BITS) & 0xf;     // last 4 bits
200         haxSha256.push_back(hexChars[c]);
201         haxSha256.push_back(hexChars[d & 0xf]);
202     }
203     return haxSha256;
204 }
205 
SetRebootMisc(const std::string & rebootTarget,const std::string & extData,struct UpdateMessage & msg)206 bool SetRebootMisc(const std::string& rebootTarget, const std::string &extData, struct UpdateMessage &msg)
207 {
208     static const int32_t maxCommandSize = 16;
209     int result = 0;
210     if (rebootTarget == "updater" && strcmp(msg.command, "boot_updater") != 0) {
211         result = strcpy_s(msg.command, maxCommandSize, "boot_updater");
212     } else if (rebootTarget == "flashd" && strcmp(msg.command, "flashd") != 0) {
213         result = strcpy_s(msg.command, maxCommandSize, "boot_flash");
214     } else if (rebootTarget == "bootloader" && strcmp(msg.command, "boot_loader") != 0) {
215         result = strcpy_s(msg.command, maxCommandSize, "boot_loader");
216     }
217     if (result != EOK) {
218         LOG(ERROR) << "reboot set misc strcpy failed";
219         return false;
220     }
221     msg.command[maxCommandSize] = 0;
222     if (extData.empty()) {
223         (void)memset_s(msg.update, sizeof(msg.update), 0, sizeof(msg.update));
224         return true;
225     }
226     if (strcpy_s(msg.update, sizeof(msg.update) - 1, extData.c_str()) != EOK) {
227         LOG(ERROR) << "failed to copy update";
228         return false;
229     }
230     msg.update[sizeof(msg.update) - 1] = 0;
231     return true;
232 }
233 
UpdaterDoReboot(const std::string & rebootTarget,const std::string & extData)234 void UpdaterDoReboot(const std::string& rebootTarget, const std::string &extData)
235 {
236     LOG(INFO) << ", rebootTarget: " << rebootTarget;
237     LoadFstab();
238     struct UpdateMessage msg = {};
239     if (rebootTarget.empty()) {
240         if (WriteUpdaterMiscMsg(msg) != true) {
241             LOG(INFO) << "UpdaterDoReboot: WriteUpdaterMessage empty error";
242             return;
243         }
244     } else {
245         if (!ReadUpdaterMiscMsg(msg)) {
246             LOG(ERROR) << "UpdaterDoReboot read misc failed";
247             return;
248         }
249         if (!SetRebootMisc(rebootTarget, extData, msg)) {
250             LOG(ERROR) << "UpdaterDoReboot set misc failed";
251             return;
252         }
253         if (!WriteUpdaterMiscMsg(msg)) {
254             LOG(INFO) << "UpdaterDoReboot: WriteUpdaterMiscMsg error";
255             return;
256         }
257     }
258     sync();
259 #ifndef UPDATER_UT
260     DoReboot(rebootTarget.c_str());
261     while (true) {
262         pause();
263     }
264 #else
265     return;
266 #endif
267 }
268 
DoShutdown()269 void DoShutdown()
270 {
271     UpdateMessage msg = {};
272     if (!WriteUpdaterMiscMsg(msg)) {
273         LOG(ERROR) << "DoShutdown: WriteUpdaterMessage empty error";
274         return;
275     }
276     sync();
277     DoReboot("shutdown");
278 }
279 
GetCertName()280 std::string GetCertName()
281 {
282 #ifndef UPDATER_UT
283     static std::string signingCertName = "/etc/certificate/signing_cert.crt";
284 #else
285     static std::string signingCertName = "/data/updater/src/signing_cert.crt";
286 #endif
287     return signingCertName;
288 }
289 
WriteFully(int fd,const uint8_t * data,size_t size)290 bool WriteFully(int fd, const uint8_t *data, size_t size)
291 {
292     ssize_t written = 0;
293     size_t rest = size;
294 
295     while (rest > 0) {
296         do {
297             written = write(fd, data, rest);
298         } while (written < 0 && errno == EINTR);
299 
300         if (written < 0) {
301             return false;
302         }
303         data += written;
304         rest -= static_cast<size_t>(written);
305     }
306     return true;
307 }
308 
ReadFully(int fd,void * data,size_t size)309 bool ReadFully(int fd, void *data, size_t size)
310 {
311     auto p = reinterpret_cast<uint8_t *>(data);
312     size_t remaining = size;
313     while (remaining > 0) {
314         ssize_t sread = read(fd, p, remaining);
315         if (sread <= 0) {
316             LOG(ERROR) << "Utils::ReadFully run error";
317             return false;
318         }
319         p += sread;
320         remaining -= static_cast<size_t>(sread);
321     }
322     return true;
323 }
324 
ReadFileToString(int fd,std::string & content)325 bool ReadFileToString(int fd, std::string &content)
326 {
327     struct stat sb {};
328     if (fstat(fd, &sb) != -1 && sb.st_size > 0) {
329         content.resize(static_cast<size_t>(sb.st_size));
330     }
331     ssize_t n;
332     auto remaining = static_cast<size_t>(sb.st_size);
333     auto p = reinterpret_cast<char *>(content.data());
334     while (remaining > 0) {
335         n = read(fd, p, remaining);
336         if (n <= 0) {
337             return false;
338         }
339         p += n;
340         remaining -= static_cast<size_t>(n);
341     }
342     return true;
343 }
344 
WriteStringToFile(int fd,const std::string & content)345 bool WriteStringToFile(int fd, const std::string& content)
346 {
347     const char *p = content.data();
348     size_t remaining = content.size();
349     while (remaining > 0) {
350         ssize_t n = write(fd, p, remaining);
351         if (n == -1) {
352             return false;
353         }
354         p += n;
355         remaining -= static_cast<size_t>(n);
356     }
357     return true;
358 }
359 
CopyFile(const std::string & src,const std::string & dest,bool isAppend)360 bool CopyFile(const std::string &src, const std::string &dest, bool isAppend)
361 {
362     char realPath[PATH_MAX + 1] = {0};
363     if (realpath(src.c_str(), realPath) == nullptr) {
364         LOG(ERROR) << src << " get realpath fail";
365         return false;
366     }
367 
368     std::ios_base::openmode mode = isAppend ? std::ios::app | std::ios::out : std::ios_base::out;
369     std::ifstream fin(realPath);
370     std::ofstream fout(dest, mode);
371     if (!fin.is_open() || !fout.is_open()) {
372         return false;
373     }
374 
375     fout << fin.rdbuf();
376     if (fout.fail()) {
377         fout.clear();
378         return false;
379     }
380     fout.flush();
381     return true;
382 }
383 
GetLocalBoardId()384 std::string GetLocalBoardId()
385 {
386     return "HI3516";
387 }
388 
CompressLogs(const std::string & logName)389 void CompressLogs(const std::string &logName)
390 {
391     PkgManager::PkgManagerPtr pkgManager = PkgManager::CreatePackageInstance();
392     if (pkgManager == nullptr) {
393         LOG(ERROR) << "pkgManager is nullptr";
394         return;
395     }
396     std::vector<std::pair<std::string, ZipFileInfo>> files;
397     // Build the zip file to be packaged
398     std::vector<std::string> testFileNames;
399     std::string realName = logName.substr(logName.find_last_of("/") + 1);
400     std::string logPath = logName.substr(0, logName.find_last_of("/"));
401     testFileNames.push_back(realName);
402     for (auto name : testFileNames) {
403         ZipFileInfo file;
404         file.fileInfo.identity = name;
405         file.fileInfo.packMethod = PKG_COMPRESS_METHOD_ZIP;
406         file.fileInfo.digestMethod = PKG_DIGEST_TYPE_CRC;
407         std::string fileName = logName;
408         files.push_back(std::pair<std::string, ZipFileInfo>(fileName, file));
409     }
410 
411     PkgInfo pkgInfo;
412     pkgInfo.signMethod = PKG_SIGN_METHOD_NONE;
413     pkgInfo.digestMethod = PKG_SIGN_METHOD_NONE;
414     pkgInfo.pkgType = PKG_PACK_TYPE_ZIP;
415 
416     char realTime[MAX_TIME_SIZE] = {0};
417     auto sysTime = std::chrono::system_clock::now();
418     auto currentTime = std::chrono::system_clock::to_time_t(sysTime);
419     struct tm *localTime = std::localtime(&currentTime);
420     if (localTime != nullptr) {
421         std::strftime(realTime, sizeof(realTime), "%Y%m%d%H%M%S", localTime);
422     }
423     char pkgName[MAX_LOG_NAME_SIZE];
424     if (snprintf_s(pkgName, MAX_LOG_NAME_SIZE, MAX_LOG_NAME_SIZE - 1,
425         "%s/%s_%s.zip", logPath.c_str(), realName.c_str(), realTime) == -1) {
426         PkgManager::ReleasePackageInstance(pkgManager);
427         return;
428     }
429     int32_t ret = pkgManager->CreatePackage(pkgName, GetCertName(), &pkgInfo, files);
430     if (ret != 0) {
431         LOG(WARNING) << "CompressLogs failed";
432         PkgManager::ReleasePackageInstance(pkgManager);
433         return;
434     }
435     (void)DeleteFile(logName);
436     PkgManager::ReleasePackageInstance(pkgManager);
437 }
438 
GetFileSize(const std::string & dLog)439 int GetFileSize(const std::string &dLog)
440 {
441     int ret = 0;
442     std::ifstream ifs(dLog, std::ios::binary | std::ios::in);
443     if (ifs.is_open()) {
444         ifs.seekg(0, std::ios::end);
445         ret = ifs.tellg();
446     }
447     return ret;
448 }
449 
CopyUpdaterLogs(const std::string & sLog,const std::string & dLog)450 bool CopyUpdaterLogs(const std::string &sLog, const std::string &dLog)
451 {
452     std::size_t found = dLog.find_last_of("/");
453     if (found == std::string::npos) {
454         LOG(ERROR) << "Dest filePath error";
455         return false;
456     }
457     std::string destPath = dLog.substr(0, found);
458     if (MountForPath(destPath) != 0) {
459         LOG(WARNING) << "MountForPath /data/log failed!";
460         return false;
461     }
462 #ifdef WITH_SELINUX
463     RestoreconRecurse(destPath.c_str());
464 #endif // WITH_SELINUX
465     if (access(destPath.c_str(), 0) != 0) {
466         if (MkdirRecursive(destPath.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
467             LOG(ERROR) << "MkdirRecursive error!";
468             return false;
469         }
470         if (chown(destPath.c_str(), USER_UPDATE_AUTHORITY, USER_UPDATE_AUTHORITY) != EOK &&
471             chmod(destPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != EOK) {
472                 LOG(ERROR) << "Chmod failed!";
473                 return false;
474         }
475     }
476 
477     if (Utils::GetFileSize(sLog) > MAX_LOG_SIZE) {
478         LOG(ERROR) << "Size bigger for" << sLog;
479         STAGE(UPDATE_STAGE_FAIL) << "Log file error, unable to copy";
480         return false;
481     }
482 
483     while (Utils::GetFileSize(sLog) + GetDirSizeForFile(dLog) > MAX_LOG_DIR_SIZE) {
484         if (DeleteOldFile(destPath) != true) {
485             break;
486         }
487     }
488 
489     if (!CopyFile(sLog, dLog, true)) {
490         LOG(ERROR) << "copy log file failed.";
491         return false;
492     }
493     if (GetFileSize(dLog) >= MAX_LOG_SIZE) {
494         LOG(INFO) << "log size greater than 5M!";
495         CompressLogs(dLog);
496     }
497     sync();
498     return true;
499 }
500 
CheckDumpResult()501 bool CheckDumpResult()
502 {
503     std::ifstream ifs;
504     const std::string resultPath = std::string(UPDATER_PATH) + "/" + std::string(UPDATER_RESULT_FILE);
505     ifs.open(resultPath, std::ios::in);
506     std::string buff;
507     if (ifs.is_open() && getline(ifs, buff) && buff.find("fail:") != std::string::npos) {
508         return true;
509     }
510     LOG(ERROR) << "open result file failed";
511     return false;
512 }
513 
WriteDumpResult(const std::string & result)514 void WriteDumpResult(const std::string &result)
515 {
516     if (access(UPDATER_PATH, 0) != 0) {
517         if (MkdirRecursive(UPDATER_PATH, 0755) != 0) { // 0755: -rwxr-xr-x
518             LOG(ERROR) << "MkdirRecursive error!";
519             return;
520         }
521     }
522     LOG(INFO) << "WriteDumpResult: " << result;
523     const std::string resultPath = std::string(UPDATER_PATH) + "/" + std::string(UPDATER_RESULT_FILE);
524     FILE *fp = fopen(resultPath.c_str(), "w+");
525     if (fp == nullptr) {
526         LOG(ERROR) << "open result file failed";
527         return;
528     }
529     char buf[MAX_RESULT_BUFF_SIZE] = "Pass\n";
530     if (sprintf_s(buf, MAX_RESULT_BUFF_SIZE - 1, "%s\n", result.c_str()) < 0) {
531         LOG(WARNING) << "sprintf status fialed";
532     }
533     if (fwrite(buf, 1, strlen(buf) + 1, fp) <= 0) {
534         LOG(WARNING) << "write result file failed, err:" << errno;
535     }
536     if (fclose(fp) != 0) {
537         LOG(WARNING) << "close result file failed";
538     }
539 
540     (void)chown(resultPath.c_str(), USER_ROOT_AUTHORITY, GROUP_UPDATE_AUTHORITY);
541     (void)chmod(resultPath.c_str(), 0660); // 0660: -rw-rw----
542 }
543 
UsSleep(int usec)544 void UsSleep(int usec)
545 {
546     auto seconds = usec / USECONDS_PER_SECONDS;
547     long nanoSeconds = static_cast<long>(usec) % USECONDS_PER_SECONDS * NANOSECS_PER_USECONDS;
548     struct timespec ts = { static_cast<time_t>(seconds), nanoSeconds };
549     while (nanosleep(&ts, &ts) < 0 && errno == EINTR) {
550     }
551 }
552 
PathToRealPath(const std::string & path,std::string & realPath)553 bool PathToRealPath(const std::string &path, std::string &realPath)
554 {
555     if (path.empty()) {
556         LOG(ERROR) << "path is empty!";
557         return false;
558     }
559 
560     if ((path.length() >= PATH_MAX)) {
561         LOG(ERROR) << "path len is error, the len is: " << path.length();
562         return false;
563     }
564 
565     char tmpPath[PATH_MAX] = {0};
566     if (realpath(path.c_str(), tmpPath) == nullptr) {
567         LOG(ERROR) << "path to realpath error " << path;
568         return false;
569     }
570 
571     realPath = tmpPath;
572     return true;
573 }
574 
IsUpdaterMode()575 bool IsUpdaterMode()
576 {
577     struct stat st {};
578     if (stat("/bin/updater", &st) == 0 && S_ISREG(st.st_mode)) {
579         LOG(INFO) << "updater mode";
580         return true;
581     }
582     LOG(INFO) << "normal mode";
583     return false;
584 }
585 
RemoveDir(const std::string & path)586 bool RemoveDir(const std::string &path)
587 {
588     if (path.empty()) {
589         LOG(ERROR) << "input path is empty.";
590         return false;
591     }
592     std::string strPath = path;
593     if (strPath.at(strPath.length() - 1) != '/') {
594         strPath.append("/");
595     }
596     DIR *d = opendir(strPath.c_str());
597     if (d != nullptr) {
598         struct dirent *dt = nullptr;
599         dt = readdir(d);
600         while (dt != nullptr) {
601             if (strcmp(dt->d_name, "..") == 0 || strcmp(dt->d_name, ".") == 0) {
602                 dt = readdir(d);
603                 continue;
604             }
605             struct stat st {};
606             auto file_name = strPath + std::string(dt->d_name);
607             stat(file_name.c_str(), &st);
608             if (S_ISDIR(st.st_mode)) {
609                 RemoveDir(file_name);
610             } else {
611                 remove(file_name.c_str());
612             }
613             dt = readdir(d);
614         }
615         closedir(d);
616     }
617     return rmdir(strPath.c_str()) == 0 ? true : false;
618 }
619 
IsFileExist(const std::string & path)620 bool IsFileExist(const std::string &path)
621 {
622     struct stat st {};
623     if (stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
624         return true;
625     }
626     return false;
627 }
628 
IsDirExist(const std::string & path)629 bool IsDirExist(const std::string &path)
630 {
631     struct stat st {};
632     if (stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode)) {
633         return true;
634     }
635     return false;
636 }
637 
GetDirSize(const std::string & folderPath)638 long long int GetDirSize(const std::string &folderPath)
639 {
640     DIR* dir = opendir(folderPath.c_str());
641     if (dir == nullptr) {
642         LOG(ERROR) << "Failed to open folder: " << folderPath << std::endl;
643         return 0;
644     }
645 
646     struct dirent* entry;
647     long long int totalSize = 0;
648     while ((entry = readdir(dir)) != nullptr) {
649         std::string fileName = entry->d_name;
650         std::string filePath = folderPath + "/" + fileName;
651         struct stat fileStat;
652         if (stat(filePath.c_str(), &fileStat) != 0) {
653             LOG(ERROR) << "Failed to get file status: " << filePath << std::endl;
654             continue;
655         }
656         if (S_ISDIR(fileStat.st_mode)) {
657             if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
658                 continue;
659             }
660             std::string subFolderPath = filePath;
661             totalSize += GetDirSize(subFolderPath);
662         } else {
663             totalSize += fileStat.st_size;
664         }
665     }
666     closedir(dir);
667     return totalSize;
668 }
669 
GetDirSizeForFile(const std::string & filePath)670 long long int GetDirSizeForFile(const std::string &filePath)
671 {
672     std::size_t found = filePath.find_last_of("/");
673     if (found == std::string::npos) {
674         LOG(ERROR) << "filePath error";
675         return -1;
676     }
677     return GetDirSize(filePath.substr(0, found));
678 }
679 
DeleteOldFile(const std::string folderPath)680 bool DeleteOldFile(const std::string folderPath)
681 {
682     DIR* dir = opendir(folderPath.c_str());
683     if (dir == nullptr) {
684         LOG(ERROR) << "Failed to open folder: " << folderPath << std::endl;
685         return false;
686     }
687 
688     struct dirent* entry;
689     std::string oldestFilePath = "";
690     time_t oldestFileTime = std::numeric_limits<time_t>::max();
691     while ((entry = readdir(dir)) != nullptr) {
692         std::string fileName = entry->d_name;
693         std::string filePath = folderPath + "/" + fileName;
694         struct stat fileStat;
695         if (stat(filePath.c_str(), &fileStat) != 0) {
696             LOG(ERROR) << "Failed to get file status: " << filePath;
697             continue;
698         }
699         if (fileName == "." || fileName == "..") {
700             continue;
701         }
702         if (fileStat.st_mtime < oldestFileTime) {
703             oldestFileTime = fileStat.st_mtime;
704             oldestFilePath = filePath;
705         }
706     }
707     closedir(dir);
708     if (oldestFilePath.empty()) {
709         LOG(ERROR) << "Unable to delete file";
710         return false;
711     }
712     if (remove(oldestFilePath.c_str()) != 0) {
713         LOG(ERROR) << "Failed to delete file: " << oldestFilePath;
714         return false;
715     }
716     return true;
717 }
718 
ParseParams(int argc,char ** argv)719 std::vector<std::string> ParseParams(int argc, char **argv)
720 {
721     struct UpdateMessage boot {};
722     // read from misc
723     if (!ReadUpdaterMiscMsg(boot)) {
724         LOG(ERROR) << "ReadUpdaterMessage MISC_FILE failed!";
725     }
726     // if boot.update is empty, read from command.The Misc partition may have dirty data,
727     // so strlen(boot.update) is not used, which can cause system exceptions.
728     if (boot.update[0] == '\0' && !access(COMMAND_FILE, 0)) {
729         if (!ReadUpdaterMessage(COMMAND_FILE, boot)) {
730             LOG(ERROR) << "ReadUpdaterMessage COMMAND_FILE failed!";
731         }
732     }
733     STAGE(UPDATE_STAGE_OUT) << "Init Params: " << boot.update;
734     boot.update[sizeof(boot.update) - 1] = '\0';
735     std::vector<std::string> parseParams = Utils::SplitString(boot.update, "\n");
736     if (argc != 0 && argv != nullptr) {
737         parseParams.insert(parseParams.begin(), argv, argv + argc);
738     }
739     return parseParams;
740 }
741 
CheckUpdateMode(const std::string & mode)742 bool CheckUpdateMode(const std::string &mode)
743 {
744     std::vector<std::string> args = ParseParams(0, nullptr);
745     for(const auto &arg : args) {
746         if (arg.find(mode) != std::string::npos) {
747             return true;
748         }
749     }
750     return false;
751 }
752 
DurationToString(std::chrono::duration<double> duration,int precision)753 std::string DurationToString(std::chrono::duration<double> duration, int precision)
754 {
755     std::ostringstream oss;
756     oss << std::fixed << std::setprecision(precision) << duration.count();
757     return oss.str();
758 }
759 } // Utils
760 } // namespace Updater
761