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