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 #include <chrono>
16 #include <dirent.h>
17 #include <fcntl.h>
18 #include <sys/mount.h>
19 #include <sys/stat.h>
20 #include <sys/statvfs.h>
21
22 #include "applypatch/partition_record.h"
23 #include "flashd/flashd.h"
24 #include "log/log.h"
25 #include "misc_info/misc_info.h"
26 #include "package/pkg_manager.h"
27 #include "securec.h"
28 #include "updater/updater.h"
29 #include "updater/updater_const.h"
30 #include "updater_ui.h"
31 #include "utils.h"
32
33 namespace {
34 static constexpr int USER_ROOT_AUTHORITY = 0;
35 static constexpr int GROUP_SYS_AUTHORITY = 1000;
36 }
37 namespace updater {
38 using namespace hpackage;
39 using namespace updater::utils;
CompressLogs(const std::string & name)40 void CompressLogs(const std::string &name)
41 {
42 PkgManager::PkgManagerPtr pkgManager = PkgManager::GetPackageInstance();
43 UPDATER_ERROR_CHECK(pkgManager != nullptr, "pkgManager is nullptr", return);
44 std::vector<std::pair<std::string, ZipFileInfo>> files;
45 // Build the zip file to be packaged
46 std::vector<std::string> testFileNames;
47 std::string realName = name.substr(name.find_last_of("/") + 1);
48 testFileNames.push_back(realName);
49 for (auto name : testFileNames) {
50 ZipFileInfo file;
51 file.fileInfo.identity = name;
52 file.fileInfo.packMethod = PKG_COMPRESS_METHOD_ZIP;
53 file.fileInfo.digestMethod = PKG_DIGEST_TYPE_CRC;
54 std::string fileName = "/data/updater/log/" + name;
55 files.push_back(std::pair<std::string, ZipFileInfo>(fileName, file));
56 }
57
58 PkgInfo pkgInfo;
59 pkgInfo.signMethod = PKG_SIGN_METHOD_RSA;
60 pkgInfo.digestMethod = PKG_DIGEST_TYPE_SHA256;
61 pkgInfo.pkgType = PKG_PACK_TYPE_ZIP;
62
63 char realTime[MAX_TIME_SIZE] = { 0 };
64 auto sysTime = std::chrono::system_clock::now();
65 auto currentTime = std::chrono::system_clock::to_time_t(sysTime);
66 struct tm *localTime = std::localtime(¤tTime);
67 if (localTime != nullptr) {
68 std::strftime(realTime, sizeof(realTime), "%H_%M_%S", localTime);
69 }
70 char pkgName[MAX_LOG_NAME_SIZE];
71 UPDATER_CHECK_ONLY_RETURN(snprintf_s(pkgName, MAX_LOG_NAME_SIZE, MAX_LOG_NAME_SIZE - 1,
72 "/data/updater/log/%s_%s.zip", realName.c_str(), realTime) != -1, return);
73 int32_t ret = pkgManager->CreatePackage(pkgName, GetCertName(), &pkgInfo, files);
74 UPDATER_CHECK_ONLY_RETURN(ret != 0, return);
75 UPDATER_CHECK_ONLY_RETURN(DeleteFile(name) == 0, return);
76 }
77
CopyUpdaterLogs(const std::string & sLog,const std::string & dLog)78 bool CopyUpdaterLogs(const std::string &sLog, const std::string &dLog)
79 {
80 UPDATER_WARING_CHECK(MountForPath(UPDATER_LOG_DIR) == 0, "MountForPath /data/log failed!", return false);
81 if (access(UPDATER_LOG_DIR.c_str(), 0) != 0) {
82 UPDATER_ERROR_CHECK(!MkdirRecursive(UPDATER_LOG_DIR, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH),
83 "MkdirRecursive error!", return false);
84 UPDATER_ERROR_CHECK(chown(UPDATER_PATH.c_str(), USER_ROOT_AUTHORITY, GROUP_SYS_AUTHORITY) == 0,
85 "Chown failed!", return false);
86 UPDATER_ERROR_CHECK(chmod(UPDATER_PATH.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0,
87 "Chmod failed!", return false);
88 }
89
90 FILE *dFp = fopen(dLog.c_str(), "ab+");
91 UPDATER_ERROR_CHECK(dFp != nullptr, "open log failed", return false);
92
93 FILE *sFp = fopen(sLog.c_str(), "r");
94 UPDATER_ERROR_CHECK(sFp != nullptr, "open log failed", fclose(dFp);
95 return false);
96
97 char buf[MAX_LOG_BUF_SIZE];
98 size_t bytes;
99 while ((bytes = fread(buf, 1, sizeof(buf), sFp)) != 0) {
100 int ret = fwrite(buf, 1, bytes, dFp);
101 if (ret < 0) {
102 break;
103 }
104 }
105 (void)fseek(dFp, 0, SEEK_END);
106 UPDATER_INFO_CHECK(ftell(dFp) < MAX_LOG_SIZE, "log size greater than 5M!", CompressLogs(dLog));
107 sync();
108 (void)fclose(sFp);
109 (void)fclose(dFp);
110 return true;
111 }
112
IsDir(const std::string & path)113 static bool IsDir(const std::string &path)
114 {
115 struct stat st {};
116 if (stat(path.c_str(), &st) < 0) {
117 return false;
118 }
119 return S_ISDIR(st.st_mode);
120 }
121
DeleteUpdaterPath(const std::string & path)122 static bool DeleteUpdaterPath(const std::string &path)
123 {
124 auto pDir = std::unique_ptr<DIR, decltype(&closedir)>(opendir(path.c_str()), closedir);
125 UPDATER_INFO_CHECK_NOT_RETURN(pDir != nullptr, "Can not open dir");
126 if (pDir == nullptr) {
127 return true;
128 }
129 struct dirent *dp = nullptr;
130 while ((dp = readdir(pDir.get())) != nullptr) {
131 std::string currentName(dp->d_name);
132 if (currentName[0] != '.' && (currentName.compare("log") != 0)) {
133 std::string tmpName(path);
134 tmpName.append("/" + currentName);
135 if (IsDir(tmpName)) {
136 DeleteUpdaterPath(tmpName);
137 }
138 #ifndef UPDATER_UT
139 remove(tmpName.c_str());
140 #endif
141 }
142 }
143 return true;
144 }
145
ClearMisc()146 static bool ClearMisc()
147 {
148 struct UpdateMessage cleanBoot {};
149 UPDATER_ERROR_CHECK(WriteUpdaterMessage(MISC_FILE, cleanBoot) == true,
150 "ClearMisc clear boot message to misc failed", return false);
151 auto fp = std::unique_ptr<FILE, decltype(&fclose)>(fopen(MISC_FILE.c_str(), "rb+"), fclose);
152 UPDATER_FILE_CHECK(fp != nullptr, "WriteVersionCode fopen failed", return false);
153 (void)fseek(fp.get(), PARTITION_RECORD_OFFSET, SEEK_SET);
154 off_t clearOffset = 0;
155 UPDATER_FILE_CHECK(fwrite(&clearOffset, sizeof(off_t), 1, fp.get()) == 1,
156 "ClearMisc write misc initOffset 0 failed", return false);
157
158 struct PartitionRecordInfo cleanPartition {};
159 for (size_t tmpOffset = 0; tmpOffset < PARTITION_UPDATER_RECORD_MSG_SIZE; tmpOffset +=
160 sizeof(PartitionRecordInfo)) {
161 (void)fseek(fp.get(), PARTITION_RECORD_START + tmpOffset, SEEK_SET);
162 UPDATER_FILE_CHECK(fwrite(&cleanPartition, sizeof(PartitionRecordInfo), 1, fp.get()) == 1,
163 "ClearMisc write misc cleanPartition failed", return false);
164 }
165 return true;
166 }
167
IsSDCardExist(const std::string & sdcardPath)168 bool IsSDCardExist(const std::string &sdcardPath)
169 {
170 // Record system error codes.
171 int save_errno = errno;
172 struct stat st {};
173 if (stat(sdcardPath.c_str(), &st) < 0) {
174 return false;
175 } else {
176 errno = save_errno;
177 return true;
178 }
179 }
180
PostUpdaterForSdcard(std::string & updaterLogPath,std::string & stageLogPath,std::string & errorCodePath)181 void PostUpdaterForSdcard(std::string &updaterLogPath, std::string &stageLogPath, std::string &errorCodePath)
182 {
183 if (SetupPartitions() != 0) {
184 ShowText(GetUpdateInfoLabel(), "Mount data failed.");
185 LOG(ERROR) << "Mount for /data failed.";
186 std::string sdcardPath = GetBlockDeviceByMountPoint(SDCARD_PATH);
187 if (IsSDCardExist(sdcardPath)) {
188 if (MountForPath(SDCARD_PATH) != 0) {
189 int ret = mount(sdcardPath.c_str(), SDCARD_PATH.c_str(), "vfat", 0, NULL);
190 UPDATER_WARING_CHECK(ret == 0, "Mount for /sdcard failed!", return);
191 }
192 updaterLogPath = "/sdcard/updater/log/updater_log";
193 stageLogPath = "/sdcard/updater/log/updater_stage_log";
194 errorCodePath = "/sdcard/updater/log/error_code.log";
195 }
196 }
197 return;
198 }
199
PostUpdater(bool clearMisc)200 void PostUpdater(bool clearMisc)
201 {
202 STAGE(UPDATE_STAGE_BEGIN) << "PostUpdater";
203 std::string updaterLogPath = "/data/updater/log/updater_log";
204 std::string stageLogPath = "/data/updater/log/updater_stage_log";
205 std::string errorCodePath = "/data/updater/log/error_code.log";
206 PostUpdaterForSdcard(updaterLogPath, stageLogPath, errorCodePath);
207 // clear update misc partition.
208 if (clearMisc) {
209 UPDATER_ERROR_CHECK_NOT_RETURN(ClearMisc() == true, "PostUpdater clear misc failed");
210 }
211 if (!access(COMMAND_FILE.c_str(), 0)) {
212 UPDATER_ERROR_CHECK_NOT_RETURN(unlink(COMMAND_FILE.c_str()) == 0, "Delete command failed");
213 }
214
215 // delete updater tmp files
216 if (access(UPDATER_PATH.c_str(), 0) == 0 && access(SDCARD_CARD_PATH.c_str(), 0) != 0) {
217 UPDATER_ERROR_CHECK_NOT_RETURN(DeleteUpdaterPath(UPDATER_PATH), "DeleteUpdaterPath failed");
218 }
219 if (!access(SDCARD_CARD_PATH.c_str(), 0)) {
220 UPDATER_ERROR_CHECK_NOT_RETURN(DeleteUpdaterPath(SDCARD_CARD_PATH), "Delete sdcard path failed");
221 }
222 if (access(flashd::FLASHD_FILE_PATH.c_str(), 0) == 0) {
223 UPDATER_ERROR_CHECK_NOT_RETURN(DeleteUpdaterPath(flashd::FLASHD_FILE_PATH), "DeleteUpdaterPath failed");
224 }
225
226 // save logs
227 bool ret = CopyUpdaterLogs(TMP_LOG, updaterLogPath);
228 UPDATER_ERROR_CHECK_NOT_RETURN(ret, "Copy updater log failed!");
229 ret = CopyUpdaterLogs(TMP_ERROR_CODE_PATH, errorCodePath);
230 UPDATER_ERROR_CHECK_NOT_RETURN(ret, "Copy error code log failed!");
231 ret = CopyUpdaterLogs(flashd::FLASHD_HDC_LOG_PATH, UPDATER_HDC_LOG);
232 UPDATER_ERROR_CHECK_NOT_RETURN(ret, "Copy error hdc log failed!");
233
234 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
235 chmod(updaterLogPath.c_str(), mode);
236 chmod(stageLogPath.c_str(), mode);
237 chmod(errorCodePath.c_str(), mode);
238 STAGE(UPDATE_STAGE_SUCCESS) << "PostUpdater";
239 ret = CopyUpdaterLogs(TMP_STAGE_LOG, stageLogPath);
240 UPDATER_ERROR_CHECK_NOT_RETURN(ret, "Copy stage log failed!");
241 }
242
IsSpaceCapacitySufficient(const std::string & packagePath)243 int IsSpaceCapacitySufficient(const std::string &packagePath)
244 {
245 hpackage::PkgManager::PkgManagerPtr pkgManager = PkgManager::CreatePackageInstance();
246 UPDATER_ERROR_CHECK(pkgManager != nullptr, "pkgManager is nullptr", return UPDATE_CORRUPT);
247 std::vector<std::string> fileIds;
248 int ret = pkgManager->LoadPackageWithoutUnPack(packagePath, fileIds);
249 UPDATER_ERROR_CHECK(ret == PKG_SUCCESS, "LoadPackageWithoutUnPack failed",
250 PkgManager::ReleasePackageInstance(pkgManager); return UPDATE_CORRUPT);
251 const FileInfo *info = pkgManager->GetFileInfo("update.bin");
252 UPDATER_ERROR_CHECK(info != nullptr, "update.bin is not exist",
253 PkgManager::ReleasePackageInstance(pkgManager); return UPDATE_CORRUPT);
254 uint64_t needSpace = static_cast<uint64_t>(info->unpackedSize);
255 PkgManager::ReleasePackageInstance(pkgManager);
256
257 struct statvfs64 updaterVfs {};
258 if (strncmp(packagePath.c_str(), SDCARD_CARD_PATH.c_str(), SDCARD_CARD_PATH.size()) == 0) { // for sdcard
259 ret = statvfs64(SDCARD_PATH.c_str(), &updaterVfs);
260 UPDATER_ERROR_CHECK(ret >= 0, "Statvfs read /sdcard error!", return UPDATE_ERROR);
261 } else {
262 needSpace += MAX_LOG_SPACE;
263 ret = statvfs64(UPDATER_PATH.c_str(), &updaterVfs);
264 UPDATER_ERROR_CHECK(ret >= 0, "Statvfs read /data error!", return UPDATE_ERROR);
265 }
266 auto freeSpaceSize = static_cast<uint64_t>(updaterVfs.f_bfree);
267 auto blockSize = static_cast<uint64_t>(updaterVfs.f_bsize);
268 uint64_t totalFreeSize = freeSpaceSize * blockSize;
269 UPDATER_ERROR_CHECK(totalFreeSize > needSpace,
270 "Can not update, free space is not enough", return UPDATE_SPACE_NOTENOUGH);
271 return UPDATE_SUCCESS;
272 }
273
ParseParams(int argc,char ** argv)274 std::vector<std::string> ParseParams(int argc, char **argv)
275 {
276 struct UpdateMessage boot {};
277 // read from misc
278 UPDATER_ERROR_CHECK_NOT_RETURN(ReadUpdaterMessage(MISC_FILE, boot) == true,
279 "ReadUpdaterMessage MISC_FILE failed!");
280 // if boot.update is empty, read from command.The Misc partition may have dirty data,
281 // so strlen(boot.update) is not used, which can cause system exceptions.
282 if (boot.update[0] == '\0' && !access(COMMAND_FILE.c_str(), 0)) {
283 UPDATER_ERROR_CHECK_NOT_RETURN(ReadUpdaterMessage(COMMAND_FILE, boot) == true,
284 "ReadUpdaterMessage COMMAND_FILE failed!");
285 }
286 STAGE(UPDATE_STAGE_OUT) << "Init Params: " << boot.update;
287 std::vector<std::string> parseParams(argv, argv + argc);
288 boot.update[sizeof(boot.update) - 1] = '\0';
289 std::vector<std::string> parseParams1 = utils::SplitString(boot.update, "\n");
290 parseParams.insert(parseParams.end(), parseParams1.begin(), parseParams1.end());
291 return parseParams;
292 }
293
GetBootMode(int & mode)294 int GetBootMode(int &mode)
295 {
296 #ifndef UPDATER_UT
297 mode = BOOT_UPDATER;
298 #else
299 mode = BOOT_FLASHD;
300 #endif
301 struct UpdateMessage boot {};
302 // read from misc
303 bool ret = ReadUpdaterMessage(MISC_FILE, boot);
304 if (!ret) {
305 return -1;
306 }
307 // if boot.update is empty, read from command.The Misc partition may have dirty data,
308 // so strlen(boot.update) is not used, which can cause system exceptions.
309 if (boot.update[0] == '\0' && !access(COMMAND_FILE.c_str(), 0)) {
310 ret = ReadUpdaterMessage(COMMAND_FILE, boot);
311 if (!ret) {
312 return -1;
313 }
314 }
315 if (memcmp(boot.command, "boot_flash", strlen("boot_flash")) == 0) {
316 mode = BOOT_FLASHD;
317 }
318 return 0;
319 }
320 } // namespace updater
321