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 "log/log.h"
32 #include "misc_info/misc_info.h"
33 #include "package/pkg_manager.h"
34 #include "securec.h"
35 #include "updater/updater_const.h"
36
37 namespace Updater {
38 using namespace Hpackage;
39
40 namespace Utils {
41 constexpr uint8_t SHIFT_RIGHT_FOUR_BITS = 4;
42 constexpr int USECONDS_PER_SECONDS = 1000000; // 1s = 1000000us
43 constexpr int NANOSECS_PER_USECONDS = 1000; // 1us = 1000ns
44 constexpr int MAX_TIME_SIZE = 20;
DeleteFile(const std::string & filename)45 int32_t DeleteFile(const std::string& filename)
46 {
47 if (filename.empty()) {
48 LOG(ERROR) << "Invalid filename";
49 return -1;
50 }
51 if (unlink(filename.c_str()) == -1 && errno != ENOENT) {
52 LOG(ERROR) << "unlink " << filename << " failed";
53 return -1;
54 }
55 return 0;
56 }
57
MkdirRecursive(const std::string & pathName,mode_t mode)58 int MkdirRecursive(const std::string &pathName, mode_t mode)
59 {
60 size_t slashPos = 0;
61 struct stat info {};
62 while (true) {
63 slashPos = pathName.find_first_of("/", slashPos);
64 if (slashPos == std::string::npos) {
65 break;
66 }
67 if (slashPos == 0) {
68 slashPos++;
69 continue;
70 }
71 if (slashPos > PATH_MAX) {
72 LOG(ERROR) << "path too long for mkdir";
73 return -1;
74 }
75 auto subDir = pathName.substr(0, slashPos);
76 std::cout << "subDir : " << subDir << std::endl;
77 if (stat(subDir.c_str(), &info) != 0) {
78 int ret = mkdir(subDir.c_str(), mode);
79 if (ret && errno != EEXIST) {
80 return ret;
81 }
82 }
83 slashPos++;
84 }
85 int ret = mkdir(pathName.c_str(), mode);
86 if (ret && errno != EEXIST) {
87 return ret;
88 }
89 return 0;
90 }
91
GetFilesFromDirectory(const std::string & path,std::vector<std::string> & files,bool isRecursive)92 int64_t GetFilesFromDirectory(const std::string &path, std::vector<std::string> &files,
93 bool isRecursive)
94 {
95 struct stat sb {};
96 if (stat(path.c_str(), &sb) == -1) {
97 LOG(ERROR) << "Failed to stat";
98 return -1;
99 }
100 DIR *dirp = opendir(path.c_str());
101 struct dirent *dp;
102 int64_t totalSize = 0;
103 while ((dp = readdir(dirp)) != nullptr) {
104 std::string fileName = path + "/" + dp->d_name;
105 struct stat st {};
106 if (stat(fileName.c_str(), &st) == 0) {
107 std::string tmpName = dp->d_name;
108 if (tmpName == "." || tmpName == "..") {
109 continue;
110 }
111 if (isRecursive && S_ISDIR(st.st_mode)) {
112 totalSize += GetFilesFromDirectory(fileName, files, isRecursive);
113 }
114 files.push_back(fileName);
115 totalSize += st.st_size;
116 }
117 }
118 closedir(dirp);
119 return totalSize;
120 }
121
SplitString(const std::string & str,const std::string del)122 std::vector<std::string> SplitString(const std::string &str, const std::string del)
123 {
124 std::vector<std::string> result;
125 size_t found = std::string::npos;
126 size_t start = 0;
127 while (true) {
128 found = str.find_first_of(del, start);
129 result.push_back(str.substr(start, found - start));
130 if (found == std::string::npos) {
131 break;
132 }
133 start = found + 1;
134 }
135 return result;
136 }
137
Trim(const std::string & str)138 std::string Trim(const std::string &str)
139 {
140 if (str.empty()) {
141 LOG(ERROR) << "str is empty";
142 return str;
143 }
144 size_t start = 0;
145 size_t end = str.size() - 1;
146 while (start < str.size()) {
147 if (!isspace(str[start])) {
148 break;
149 }
150 start++;
151 }
152 while (start < end) {
153 if (!isspace(str[end])) {
154 break;
155 }
156 end--;
157 }
158 if (end < start) {
159 return "";
160 }
161 return str.substr(start, end - start + 1);
162 }
163
ConvertSha256Hex(const uint8_t * shaDigest,size_t length)164 std::string ConvertSha256Hex(const uint8_t* shaDigest, size_t length)
165 {
166 const std::string hexChars = "0123456789abcdef";
167 std::string haxSha256 = "";
168 unsigned int c;
169 for (size_t i = 0; i < length; ++i) {
170 auto d = shaDigest[i];
171 c = (d >> SHIFT_RIGHT_FOUR_BITS) & 0xf; // last 4 bits
172 haxSha256.push_back(hexChars[c]);
173 haxSha256.push_back(hexChars[d & 0xf]);
174 }
175 return haxSha256;
176 }
177
DoReboot(const std::string & rebootTarget,const std::string & extData)178 void DoReboot(const std::string& rebootTarget, const std::string &extData)
179 {
180 LOG(INFO) << ", rebootTarget: " << rebootTarget;
181 static const int32_t maxCommandSize = 16;
182 LoadFstab();
183 struct UpdateMessage msg;
184 if (rebootTarget.empty()) {
185 UPDATER_ERROR_CHECK(!memset_s(msg.command, MAX_COMMAND_SIZE, 0, MAX_COMMAND_SIZE), "Memset_s failed", return);
186 if (WriteUpdaterMiscMsg(msg) != true) {
187 LOG(INFO) << "DoReboot: WriteUpdaterMessage empty error";
188 return;
189 }
190 sync();
191 } else {
192 int result = 0;
193 bool ret = ReadUpdaterMiscMsg(msg);
194 UPDATER_ERROR_CHECK(ret == true, "DoReboot read misc failed", return);
195 if (rebootTarget == "updater" && strcmp(msg.command, "boot_updater") != 0) {
196 result = strcpy_s(msg.command, maxCommandSize, "boot_updater");
197 msg.command[maxCommandSize] = 0;
198 } else if (rebootTarget == "flashd" && strcmp(msg.command, "flashd") != 0) {
199 result = strcpy_s(msg.command, maxCommandSize, "boot_flash");
200 msg.command[maxCommandSize] = 0;
201 } else if (rebootTarget == "bootloader" && strcmp(msg.command, "boot_loader") != 0) {
202 result = strcpy_s(msg.command, maxCommandSize, "boot_loader");
203 msg.command[maxCommandSize] = 0;
204 }
205 UPDATER_ERROR_CHECK(result == 0, "strcpy failed", return);
206 if (!extData.empty()) {
207 result = strcpy_s(msg.update, MAX_UPDATE_SIZE - 1, extData.c_str());
208 UPDATER_ERROR_CHECK(result == 0, "Failed to copy update", return);
209 msg.update[MAX_UPDATE_SIZE - 1] = 0;
210 } else {
211 UPDATER_ERROR_CHECK(!memset_s(msg.update, MAX_UPDATE_SIZE, 0, MAX_UPDATE_SIZE), "Memset_s failed", return);
212 }
213 if (!WriteUpdaterMiscMsg(msg)) {
214 LOG(INFO) << "DoReboot: WriteUpdaterMiscMsg empty error";
215 return;
216 }
217 sync();
218 }
219 #ifndef UPDATER_UT
220 syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());
221 while (true) {
222 pause();
223 }
224 #else
225 return;
226 #endif
227 }
228
DoShutdown()229 void DoShutdown()
230 {
231 UpdateMessage msg = {};
232 if (!WriteUpdaterMiscMsg(msg)) {
233 LOG(ERROR) << "DoShutdown: WriteUpdaterMessage empty error";
234 return;
235 }
236 sync();
237 reboot(RB_POWER_OFF);
238 }
239
GetCertName()240 std::string GetCertName()
241 {
242 #ifndef UPDATER_UT
243 static std::string signingCertName = "/etc/certificate/signing_cert.crt";
244 #else
245 static std::string signingCertName = "/data/updater/src/signing_cert.crt";
246 #endif
247 return signingCertName;
248 }
249
WriteFully(int fd,const uint8_t * data,size_t size)250 bool WriteFully(int fd, const uint8_t *data, size_t size)
251 {
252 ssize_t written = 0;
253 size_t rest = size;
254
255 while (rest > 0) {
256 do {
257 written = write(fd, data, rest);
258 } while (written < 0 && errno == EINTR);
259
260 if (written < 0) {
261 return false;
262 }
263 data += written;
264 rest -= static_cast<size_t>(written);
265 }
266 return true;
267 }
268
ReadFully(int fd,void * data,size_t size)269 bool ReadFully(int fd, void *data, size_t size)
270 {
271 auto p = reinterpret_cast<uint8_t *>(data);
272 size_t remaining = size;
273 while (remaining > 0) {
274 ssize_t sread = read(fd, p, remaining);
275 if (sread <= 0) {
276 LOG(ERROR) << "Utils::ReadFully run error";
277 return false;
278 }
279 p += sread;
280 remaining -= static_cast<size_t>(sread);
281 }
282 return true;
283 }
284
ReadFileToString(int fd,std::string & content)285 bool ReadFileToString(int fd, std::string &content)
286 {
287 struct stat sb {};
288 if (fstat(fd, &sb) != -1 && sb.st_size > 0) {
289 content.resize(static_cast<size_t>(sb.st_size));
290 }
291 ssize_t n;
292 auto remaining = static_cast<size_t>(sb.st_size);
293 auto p = reinterpret_cast<char *>(content.data());
294 while (remaining > 0) {
295 n = read(fd, p, remaining);
296 if (n <= 0) {
297 return false;
298 }
299 p += n;
300 remaining -= static_cast<size_t>(n);
301 }
302 return true;
303 }
304
WriteStringToFile(int fd,const std::string & content)305 bool WriteStringToFile(int fd, const std::string& content)
306 {
307 const char *p = content.data();
308 size_t remaining = content.size();
309 while (remaining > 0) {
310 ssize_t n = write(fd, p, remaining);
311 if (n == -1) {
312 return false;
313 }
314 p += n;
315 remaining -= static_cast<size_t>(n);
316 }
317 return true;
318 }
319
CopyFile(const std::string & src,const std::string & dest)320 bool CopyFile(const std::string &src, const std::string &dest)
321 {
322 char realPath[PATH_MAX + 1] = {0};
323 if (realpath(src.c_str(), realPath) == nullptr) {
324 LOG(ERROR) << src << " get realpath fail";
325 return false;
326 }
327
328 std::ifstream fin(realPath);
329 std::ofstream fout(dest);
330 if (!fin.is_open() || !fout.is_open()) {
331 return false;
332 }
333
334 fout << fin.rdbuf();
335 if (fout.fail()) {
336 fout.clear();
337 return false;
338 }
339 fout.flush();
340 return true;
341 }
342
GetLocalBoardId()343 std::string GetLocalBoardId()
344 {
345 return "HI3516";
346 }
347
CompressLogs(const std::string & name)348 void CompressLogs(const std::string &name)
349 {
350 PkgManager::PkgManagerPtr pkgManager = PkgManager::GetPackageInstance();
351 if (pkgManager == nullptr) {
352 LOG(ERROR) << "pkgManager is nullptr";
353 return;
354 }
355 std::vector<std::pair<std::string, ZipFileInfo>> files;
356 // Build the zip file to be packaged
357 std::vector<std::string> testFileNames;
358 std::string realName = name.substr(name.find_last_of("/") + 1);
359 testFileNames.push_back(realName);
360 for (auto name : testFileNames) {
361 ZipFileInfo file;
362 file.fileInfo.identity = name;
363 file.fileInfo.packMethod = PKG_COMPRESS_METHOD_ZIP;
364 file.fileInfo.digestMethod = PKG_DIGEST_TYPE_CRC;
365 std::string fileName = "/data/updater/log/" + name;
366 files.push_back(std::pair<std::string, ZipFileInfo>(fileName, file));
367 }
368
369 PkgInfo pkgInfo;
370 pkgInfo.signMethod = PKG_SIGN_METHOD_NONE;
371 pkgInfo.digestMethod = PKG_SIGN_METHOD_NONE;
372 pkgInfo.pkgType = PKG_PACK_TYPE_ZIP;
373
374 char realTime[MAX_TIME_SIZE] = {0};
375 auto sysTime = std::chrono::system_clock::now();
376 auto currentTime = std::chrono::system_clock::to_time_t(sysTime);
377 struct tm *localTime = std::localtime(¤tTime);
378 if (localTime != nullptr) {
379 std::strftime(realTime, sizeof(realTime), "%H_%M_%S", localTime);
380 }
381 char pkgName[MAX_LOG_NAME_SIZE];
382 if (snprintf_s(pkgName, MAX_LOG_NAME_SIZE, MAX_LOG_NAME_SIZE - 1,
383 "/data/updater/log/%s_%s.zip", realName.c_str(), realTime) == -1) {
384 return;
385 }
386 int32_t ret = pkgManager->CreatePackage(pkgName, GetCertName(), &pkgInfo, files);
387 if (ret != 0) {
388 LOG(WARNING) << "CompressLogs failed";
389 return;
390 }
391 (void)DeleteFile(name);
392 }
393
CopyUpdaterLogs(const std::string & sLog,const std::string & dLog)394 bool CopyUpdaterLogs(const std::string &sLog, const std::string &dLog)
395 {
396 UPDATER_WARING_CHECK(MountForPath(UPDATER_LOG_DIR) == 0, "MountForPath /data/log failed!", return false);
397 if (access(UPDATER_LOG_DIR, 0) != 0) {
398 if (MkdirRecursive(UPDATER_LOG_DIR, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
399 LOG(ERROR) << "MkdirRecursive error!";
400 return false;
401 }
402 if (chown(UPDATER_PATH, USER_ROOT_AUTHORITY, GROUP_SYS_AUTHORITY) != EOK &&
403 chmod(UPDATER_PATH, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != EOK) {
404 LOG(ERROR) << "Chmod failed!";
405 return false;
406 }
407 }
408
409 FILE* dFp = fopen(dLog.c_str(), "ab+");
410 if (dFp == nullptr) {
411 LOG(ERROR) << "open log failed";
412 return false;
413 }
414 FILE* sFp = fopen(sLog.c_str(), "r");
415 if (sFp == nullptr) {
416 LOG(ERROR) << "open log failed";
417 fclose(dFp);
418 return false;
419 }
420
421 char buf[MAX_LOG_BUF_SIZE];
422 size_t bytes;
423 while ((bytes = fread(buf, 1, sizeof(buf), sFp)) != 0) {
424 if (fwrite(buf, 1, bytes, dFp) <= 0) {
425 LOG(ERROR) << "fwrite failed";
426 fclose(sFp);
427 fclose(dFp);
428 return false;
429 }
430 }
431 if (fseek(dFp, 0, SEEK_END) != 0) {
432 LOG(ERROR) << "fseek failed";
433 fclose(sFp);
434 fclose(dFp);
435 return false;
436 }
437 UPDATER_INFO_CHECK(ftell(dFp) < MAX_LOG_SIZE, "log size greater than 5M!", CompressLogs(dLog));
438 sync();
439 fclose(sFp);
440 fclose(dFp);
441 return true;
442 }
443
CheckDumpResult()444 bool CheckDumpResult()
445 {
446 std::ifstream ifs;
447 const std::string resultPath = std::string(UPDATER_PATH) + "/" + std::string(UPDATER_RESULT_FILE);
448 ifs.open(resultPath, std::ios::in);
449 std::string buff;
450 if (ifs.is_open() && getline(ifs, buff) && buff.find("fail:") != std::string::npos) {
451 return true;
452 }
453 LOG(ERROR) << "open result file failed";
454 return false;
455 }
456
WriteDumpResult(const std::string & result)457 void WriteDumpResult(const std::string &result)
458 {
459 if (access(UPDATER_PATH, 0) != 0) {
460 if (MkdirRecursive(UPDATER_PATH, 0755) != 0) { // 0755: -rwxr-xr-x
461 LOG(ERROR) << "MkdirRecursive error!";
462 return;
463 }
464 }
465 LOG(INFO) << "WriteDumpResult: " << result;
466 const std::string resultPath = std::string(UPDATER_PATH) + "/" + std::string(UPDATER_RESULT_FILE);
467 FILE *fp = fopen(resultPath.c_str(), "w+");
468 if (fp == nullptr) {
469 LOG(ERROR) << "open result file failed";
470 return;
471 }
472 char buf[MAX_RESULT_BUFF_SIZE] = "Pass\n";
473 if (sprintf_s(buf, MAX_RESULT_BUFF_SIZE - 1, "%s\n", result.c_str()) < 0) {
474 LOG(WARNING) << "sprintf status fialed";
475 }
476 if (fwrite(buf, 1, strlen(buf) + 1, fp) <= 0) {
477 LOG(WARNING) << "write result file failed, err:" << errno;
478 }
479 if (fclose(fp) != 0) {
480 LOG(WARNING) << "close result file failed";
481 }
482
483 (void)chown(resultPath.c_str(), USER_ROOT_AUTHORITY, GROUP_UPDATE_AUTHORITY);
484 (void)chmod(resultPath.c_str(), 0660); // 0660: -rw-rw----
485 }
486
UsSleep(int usec)487 void UsSleep(int usec)
488 {
489 auto seconds = usec / USECONDS_PER_SECONDS;
490 long nanoSeconds = static_cast<long>(usec) % USECONDS_PER_SECONDS * NANOSECS_PER_USECONDS;
491 struct timespec ts = { static_cast<time_t>(seconds), nanoSeconds };
492 while (nanosleep(&ts, &ts) < 0 && errno == EINTR) {
493 }
494 }
495
PathToRealPath(const std::string & path,std::string & realPath)496 bool PathToRealPath(const std::string &path, std::string &realPath)
497 {
498 if (path.empty()) {
499 LOG(ERROR) << "path is empty!";
500 return false;
501 }
502
503 if ((path.length() >= PATH_MAX)) {
504 LOG(ERROR) << "path len is error, the len is: " << path.length();
505 return false;
506 }
507
508 char tmpPath[PATH_MAX] = {0};
509 if (realpath(path.c_str(), tmpPath) == nullptr) {
510 LOG(ERROR) << "path to realpath error " << path;
511 return false;
512 }
513
514 realPath = tmpPath;
515 return true;
516 }
517
IsUpdaterMode()518 bool IsUpdaterMode()
519 {
520 struct stat st {};
521 if (stat("/bin/updater", &st) == 0 && S_ISREG(st.st_mode)) {
522 LOG(INFO) << "updater mode";
523 return true;
524 }
525 LOG(INFO) << "normal mode";
526 return false;
527 }
528
RemoveDir(const std::string & path)529 bool RemoveDir(const std::string &path)
530 {
531 if (path.empty()) {
532 LOG(ERROR) << "input path is empty.";
533 return false;
534 }
535 std::string strPath = path;
536 if (strPath.at(strPath.length() - 1) != '/') {
537 strPath.append("/");
538 }
539 DIR *d = opendir(strPath.c_str());
540 if (d != nullptr) {
541 struct dirent *dt = nullptr;
542 dt = readdir(d);
543 while (dt != nullptr) {
544 if (strcmp(dt->d_name, "..") == 0 || strcmp(dt->d_name, ".") == 0) {
545 dt = readdir(d);
546 continue;
547 }
548 struct stat st {};
549 auto file_name = strPath + std::string(dt->d_name);
550 stat(file_name.c_str(), &st);
551 if (S_ISDIR(st.st_mode)) {
552 RemoveDir(file_name);
553 } else {
554 remove(file_name.c_str());
555 }
556 dt = readdir(d);
557 }
558 closedir(d);
559 }
560 return rmdir(strPath.c_str()) == 0 ? true : false;
561 }
562
IsFileExist(const std::string & path)563 bool IsFileExist(const std::string &path)
564 {
565 struct stat st {};
566 if (stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
567 return true;
568 }
569 return false;
570 }
571
IsDirExist(const std::string & path)572 bool IsDirExist(const std::string &path)
573 {
574 struct stat st {};
575 if (stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode)) {
576 return true;
577 }
578 return false;
579 }
580 } // Utils
581 } // namespace Updater
582