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(¤tTime);
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