/* * Copyright (c) 2021-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include "applypatch/partition_record.h" #include "flashd/flashd.h" #include "log/log.h" #include "misc_info/misc_info.h" #include "package/pkg_manager.h" #include "securec.h" #include "updater/updater.h" #include "updater/updater_const.h" #include "updater_main.h" #include "utils.h" namespace Updater { using namespace Hpackage; using namespace Updater::Utils; void DeleteInstallTimeFile() { const std::string installTimeFilePath = std::string(UPDATER_PATH) + "/" + std::string(INSTALL_TIME_FILE); if (access(installTimeFilePath.c_str(), F_OK) != -1) { (void)DeleteFile(installTimeFilePath); LOG(INFO) << "delete install time file"; } } bool IsDouble(const std::string& str) { std::regex pattern("^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$"); return std::regex_match(str, pattern); } void WriteInstallTime(UpdaterParams &upParams) { std::ofstream ofs; ofs.open(std::string(UPDATER_PATH) + "/" + std::string(INSTALL_TIME_FILE), std::ios::app | std::ios::out); if (!ofs.is_open()) { LOG(ERROR) << "open install time file fail"; return; } ofs << DurationToString(upParams.installTime, upParams.pkgLocation) << "\n"; } void ReadInstallTime(UpdaterParams &upParams) { std::ifstream ifs; std::string buf; ifs.open(std::string(UPDATER_PATH) + "/" + std::string(INSTALL_TIME_FILE), std::ios::in); if (!ifs.is_open()) { LOG(ERROR) << "read install time file fail"; return; } unsigned int index = 0; while (getline(ifs, buf)) { if (index >= upParams.pkgLocation) { break; } if (IsDouble(buf)) { upParams.installTime[index++] = std::chrono::duration(std::stod(buf)); } else { LOG(ERROR) << "read install time is invalid"; } } } bool DeleteUpdaterPath(const std::string &path) { auto pDir = std::unique_ptr(opendir(path.c_str()), closedir); if (pDir == nullptr) { LOG(INFO) << "Can not open dir"; return true; } bool sdcardTmp = false; if (path.find("sdcard") != std::string::npos) { sdcardTmp = true; } struct dirent *dp = nullptr; while ((dp = readdir(pDir.get())) != nullptr) { std::string currentName(dp->d_name); if (currentName[0] == '.' || (currentName.compare("log") == 0) || (currentName.compare(UPDATER_RESULT_FILE) == 0) || (currentName.compare(UPDATER_LOCALE_FILE) == 0) || (currentName.compare(MODULE_UPDATE_RESULT_FILE) == 0) || (currentName.compare(UPLOAD_LOG_TIME_FILE) == 0)) { continue; } if (sdcardTmp && currentName.find(SDCARD_PACKAGE_SUFFIX) != std::string::npos) { continue; } std::string tmpName(path); tmpName.append("/" + currentName); if (IsDirExist(tmpName)) { DeleteUpdaterPath(tmpName); } #ifndef UPDATER_UT remove(tmpName.c_str()); #endif } return true; } bool ClearMisc() { struct UpdateMessage cleanBoot {}; if (!WriteUpdaterMiscMsg(cleanBoot)) { LOG(ERROR) << "ClearMisc clear boot message to misc failed"; return false; } auto miscBlockDev = GetBlockDeviceByMountPoint(MISC_PATH); if (miscBlockDev.empty()) { LOG(INFO) << "cannot get block device of partition"; miscBlockDev = MISC_FILE; } LOG(INFO) << "ClearMisc::misc path : " << miscBlockDev; auto fp = std::unique_ptr(fopen(miscBlockDev.c_str(), "rb+"), fclose); if (fp == nullptr) { LOG(ERROR) << "WriteVersionCode fopen failed" << " : " << strerror(errno); return false; } if (fseek(fp.get(), PARTITION_RECORD_OFFSET, SEEK_SET) != 0) { LOG(ERROR) << "ClearMisc fseek failed"; return false; } off_t clearOffset = 0; if (fwrite(&clearOffset, sizeof(off_t), 1, fp.get()) != 1) { LOG(ERROR) << "ClearMisc write misc initOffset 0 failed" << " : " << strerror(errno); return false; } struct PartitionRecordInfo cleanPartition {}; for (size_t tmpOffset = 0; tmpOffset < PARTITION_UPDATER_RECORD_MSG_SIZE; tmpOffset += sizeof(PartitionRecordInfo)) { if (fseek(fp.get(), PARTITION_RECORD_START + tmpOffset, SEEK_SET) != 0) { LOG(ERROR) << "ClearMisc fseek failed"; return false; } if (fwrite(&cleanPartition, sizeof(PartitionRecordInfo), 1, fp.get()) != 1) { LOG(ERROR) << "ClearMisc write misc cleanPartition failed" << " : " << strerror(errno); return false; } } return true; } bool IsSDCardExist(const std::string &sdcardPath) { // Record system error codes. int save_errno = errno; struct stat st {}; if (stat(sdcardPath.c_str(), &st) < 0) { return false; } else { errno = save_errno; return true; } } void PostUpdater(bool clearMisc) { STAGE(UPDATE_STAGE_BEGIN) << "PostUpdater"; if (!CheckUpdateMode(SDCARD_MODE) && !CheckUpdateMode(USB_MODE)) { (void)SetupPartitions(); } else { (void)SetupPartitions(false); } UpdaterInit::GetInstance().InvokeEvent(UPDATER_POST_INIT_EVENT); // clear update misc partition. if (clearMisc && !ClearMisc()) { LOG(ERROR) << "PostUpdater clear misc failed"; } if (!access(COMMAND_FILE, 0) && unlink(COMMAND_FILE) != 0) { LOG(ERROR) << "Delete command failed"; } // delete updater tmp files if (access(UPDATER_PATH, 0) == 0 && access(SDCARD_CARD_PATH, 0) != 0 && !DeleteUpdaterPath(UPDATER_PATH)) { LOG(ERROR) << "DeleteUpdaterPath failed"; } if (access(SDCARD_CARD_PATH, 0) == 0 && !DeleteUpdaterPath(SDCARD_CARD_PATH)) { LOG(ERROR) << "Delete sdcard path failed"; } if (access(Flashd::FLASHD_FILE_PATH, 0) == 0 && !DeleteUpdaterPath(Flashd::FLASHD_FILE_PATH)) { LOG(ERROR) << "DeleteUpdaterPath failed"; } if (!CheckUpdateMode(SDCARD_MODE) && !CheckUpdateMode(USB_MODE)) { SaveLogs(); } } void BootMode::InitMode(void) const { InitLogger(modeName); #ifdef UPDATER_BUILD_VARIANT_USER SetLogLevel(INFO); #else SetLogLevel(DEBUG); #endif LoadFstab(); STAGE(UPDATE_STAGE_OUT) << "Start " << modeName; SetParameter(modePara.c_str(), "1"); } bool IsUpdater(const UpdateMessage &boot) { return !IsFlashd(boot) && strncmp(boot.command, "boot_updater", sizeof("boot_updater") - 1) == 0; } bool IsFlashd(const UpdateMessage &boot) { return strncmp(boot.update, "boot_flash", sizeof("boot_flash") - 1) == 0; } std::vector &GetBootModes(void) { static std::vector bootModes {}; return bootModes; } void RegisterMode(const BootMode &mode) { GetBootModes().push_back(mode); } std::optional SelectMode(const UpdateMessage &boot) { const auto &modes = GetBootModes(); // select modes by bootMode.cond which would check misc message auto it = std::find_if(modes.begin(), modes.end(), [&boot] (const auto &bootMode) { if (bootMode.cond != nullptr && bootMode.cond(boot)) { LOG(INFO) << "condition for mode " << bootMode.modeName << " is satisfied"; return true; } LOG(WARNING) << "condition for mode " << bootMode.modeName << " is not satisfied"; return false; }); // misc check failed for each mode, then enter updater mode if (it == modes.end() || it->entryFunc == nullptr) { LOG(WARNING) << "find valid mode failed, enter updater Mode"; return std::nullopt; } LOG(INFO) << "enter " << it->modeName << " mode"; return *it; } } // namespace Updater