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