• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "utils.h"
17 #include <algorithm>
18 #include <cerrno>
19 #include <cstdint>
20 #include <cstdlib>
21 #include <dirent.h>
22 #include <limits>
23 #include <linux/reboot.h>
24 #include <string>
25 #include <sys/reboot.h>
26 #include <sys/stat.h>
27 #include <sys/syscall.h>
28 #include <unistd.h>
29 #include <vector>
30 #include "fs_manager/mount.h"
31 #include "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(&currentTime);
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