1fb299fa2Sopenharmony_ci/*
2fb299fa2Sopenharmony_ci * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3fb299fa2Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4fb299fa2Sopenharmony_ci * you may not use this file except in compliance with the License.
5fb299fa2Sopenharmony_ci * You may obtain a copy of the License at
6fb299fa2Sopenharmony_ci *
7fb299fa2Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8fb299fa2Sopenharmony_ci *
9fb299fa2Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10fb299fa2Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11fb299fa2Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fb299fa2Sopenharmony_ci * See the License for the specific language governing permissions and
13fb299fa2Sopenharmony_ci * limitations under the License.
14fb299fa2Sopenharmony_ci */
15fb299fa2Sopenharmony_ci#include <chrono>
16fb299fa2Sopenharmony_ci#include <dirent.h>
17fb299fa2Sopenharmony_ci#include <fcntl.h>
18fb299fa2Sopenharmony_ci#include <sys/mount.h>
19fb299fa2Sopenharmony_ci#include <sys/stat.h>
20fb299fa2Sopenharmony_ci#include <sys/statvfs.h>
21fb299fa2Sopenharmony_ci#include <regex>
22fb299fa2Sopenharmony_ci
23fb299fa2Sopenharmony_ci#include "applypatch/partition_record.h"
24fb299fa2Sopenharmony_ci#include "flashd/flashd.h"
25fb299fa2Sopenharmony_ci#include "log/log.h"
26fb299fa2Sopenharmony_ci#include "misc_info/misc_info.h"
27fb299fa2Sopenharmony_ci#include "package/pkg_manager.h"
28fb299fa2Sopenharmony_ci#include "securec.h"
29fb299fa2Sopenharmony_ci#include "updater/updater.h"
30fb299fa2Sopenharmony_ci#include "updater/updater_const.h"
31fb299fa2Sopenharmony_ci#include "updater_main.h"
32fb299fa2Sopenharmony_ci#include "utils.h"
33fb299fa2Sopenharmony_ci
34fb299fa2Sopenharmony_cinamespace Updater {
35fb299fa2Sopenharmony_ciusing namespace Hpackage;
36fb299fa2Sopenharmony_ciusing namespace Updater::Utils;
37fb299fa2Sopenharmony_ci
38fb299fa2Sopenharmony_civoid DeleteInstallTimeFile()
39fb299fa2Sopenharmony_ci{
40fb299fa2Sopenharmony_ci    const std::string installTimeFilePath = std::string(UPDATER_PATH) + "/" + std::string(INSTALL_TIME_FILE);
41fb299fa2Sopenharmony_ci    if (access(installTimeFilePath.c_str(), F_OK) != -1) {
42fb299fa2Sopenharmony_ci        (void)DeleteFile(installTimeFilePath);
43fb299fa2Sopenharmony_ci        LOG(INFO) << "delete install time file";
44fb299fa2Sopenharmony_ci    }
45fb299fa2Sopenharmony_ci}
46fb299fa2Sopenharmony_ci
47fb299fa2Sopenharmony_cibool IsDouble(const std::string& str)
48fb299fa2Sopenharmony_ci{
49fb299fa2Sopenharmony_ci    std::regex pattern("^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$");
50fb299fa2Sopenharmony_ci    return std::regex_match(str, pattern);
51fb299fa2Sopenharmony_ci}
52fb299fa2Sopenharmony_ci
53fb299fa2Sopenharmony_civoid WriteInstallTime(UpdaterParams &upParams)
54fb299fa2Sopenharmony_ci{
55fb299fa2Sopenharmony_ci    std::ofstream ofs;
56fb299fa2Sopenharmony_ci    ofs.open(std::string(UPDATER_PATH) + "/" + std::string(INSTALL_TIME_FILE), std::ios::app | std::ios::out);
57fb299fa2Sopenharmony_ci    if (!ofs.is_open()) {
58fb299fa2Sopenharmony_ci        LOG(ERROR) << "open install time file fail";
59fb299fa2Sopenharmony_ci        return;
60fb299fa2Sopenharmony_ci    }
61fb299fa2Sopenharmony_ci    ofs << DurationToString(upParams.installTime, upParams.pkgLocation) << "\n";
62fb299fa2Sopenharmony_ci}
63fb299fa2Sopenharmony_ci
64fb299fa2Sopenharmony_civoid ReadInstallTime(UpdaterParams &upParams)
65fb299fa2Sopenharmony_ci{
66fb299fa2Sopenharmony_ci    std::ifstream ifs;
67fb299fa2Sopenharmony_ci    std::string buf;
68fb299fa2Sopenharmony_ci    ifs.open(std::string(UPDATER_PATH) + "/" + std::string(INSTALL_TIME_FILE), std::ios::in);
69fb299fa2Sopenharmony_ci    if (!ifs.is_open()) {
70fb299fa2Sopenharmony_ci        LOG(ERROR) << "read install time file fail";
71fb299fa2Sopenharmony_ci        return;
72fb299fa2Sopenharmony_ci    }
73fb299fa2Sopenharmony_ci    unsigned int index = 0;
74fb299fa2Sopenharmony_ci    while (getline(ifs, buf)) {
75fb299fa2Sopenharmony_ci        if (index >= upParams.pkgLocation) {
76fb299fa2Sopenharmony_ci            break;
77fb299fa2Sopenharmony_ci        }
78fb299fa2Sopenharmony_ci        if (IsDouble(buf)) {
79fb299fa2Sopenharmony_ci            upParams.installTime[index++] = std::chrono::duration<double>(std::stod(buf));
80fb299fa2Sopenharmony_ci        } else {
81fb299fa2Sopenharmony_ci            LOG(ERROR) << "read install time is invalid";
82fb299fa2Sopenharmony_ci        }
83fb299fa2Sopenharmony_ci    }
84fb299fa2Sopenharmony_ci}
85fb299fa2Sopenharmony_ci
86fb299fa2Sopenharmony_cibool DeleteUpdaterPath(const std::string &path)
87fb299fa2Sopenharmony_ci{
88fb299fa2Sopenharmony_ci    auto pDir = std::unique_ptr<DIR, decltype(&closedir)>(opendir(path.c_str()), closedir);
89fb299fa2Sopenharmony_ci    if (pDir == nullptr) {
90fb299fa2Sopenharmony_ci        LOG(INFO) << "Can not open dir";
91fb299fa2Sopenharmony_ci        return true;
92fb299fa2Sopenharmony_ci    }
93fb299fa2Sopenharmony_ci    bool sdcardTmp = false;
94fb299fa2Sopenharmony_ci    if (path.find("sdcard") != std::string::npos) {
95fb299fa2Sopenharmony_ci        sdcardTmp = true;
96fb299fa2Sopenharmony_ci    }
97fb299fa2Sopenharmony_ci    struct dirent *dp = nullptr;
98fb299fa2Sopenharmony_ci    while ((dp = readdir(pDir.get())) != nullptr) {
99fb299fa2Sopenharmony_ci        std::string currentName(dp->d_name);
100fb299fa2Sopenharmony_ci        if (currentName[0] == '.' || (currentName.compare("log") == 0) ||
101fb299fa2Sopenharmony_ci            (currentName.compare(UPDATER_RESULT_FILE) == 0) ||
102fb299fa2Sopenharmony_ci            (currentName.compare(UPDATER_LOCALE_FILE) == 0) ||
103fb299fa2Sopenharmony_ci            (currentName.compare(MODULE_UPDATE_RESULT_FILE) == 0) ||
104fb299fa2Sopenharmony_ci            (currentName.compare(UPLOAD_LOG_TIME_FILE) == 0)) {
105fb299fa2Sopenharmony_ci            continue;
106fb299fa2Sopenharmony_ci        }
107fb299fa2Sopenharmony_ci        if (sdcardTmp && currentName.find(SDCARD_PACKAGE_SUFFIX) != std::string::npos) {
108fb299fa2Sopenharmony_ci            continue;
109fb299fa2Sopenharmony_ci        }
110fb299fa2Sopenharmony_ci        std::string tmpName(path);
111fb299fa2Sopenharmony_ci        tmpName.append("/" + currentName);
112fb299fa2Sopenharmony_ci        if (IsDirExist(tmpName)) {
113fb299fa2Sopenharmony_ci            DeleteUpdaterPath(tmpName);
114fb299fa2Sopenharmony_ci        }
115fb299fa2Sopenharmony_ci#ifndef UPDATER_UT
116fb299fa2Sopenharmony_ci        remove(tmpName.c_str());
117fb299fa2Sopenharmony_ci#endif
118fb299fa2Sopenharmony_ci    }
119fb299fa2Sopenharmony_ci    return true;
120fb299fa2Sopenharmony_ci}
121fb299fa2Sopenharmony_ci
122fb299fa2Sopenharmony_cibool ClearMisc()
123fb299fa2Sopenharmony_ci{
124fb299fa2Sopenharmony_ci    struct UpdateMessage cleanBoot {};
125fb299fa2Sopenharmony_ci    if (!WriteUpdaterMiscMsg(cleanBoot)) {
126fb299fa2Sopenharmony_ci        LOG(ERROR) << "ClearMisc clear boot message to misc failed";
127fb299fa2Sopenharmony_ci        return false;
128fb299fa2Sopenharmony_ci    }
129fb299fa2Sopenharmony_ci    auto miscBlockDev = GetBlockDeviceByMountPoint(MISC_PATH);
130fb299fa2Sopenharmony_ci    if (miscBlockDev.empty()) {
131fb299fa2Sopenharmony_ci        LOG(INFO) << "cannot get block device of partition";
132fb299fa2Sopenharmony_ci        miscBlockDev = MISC_FILE;
133fb299fa2Sopenharmony_ci    }
134fb299fa2Sopenharmony_ci    LOG(INFO) << "ClearMisc::misc path : " << miscBlockDev;
135fb299fa2Sopenharmony_ci    auto fp = std::unique_ptr<FILE, decltype(&fclose)>(fopen(miscBlockDev.c_str(), "rb+"), fclose);
136fb299fa2Sopenharmony_ci    if (fp == nullptr) {
137fb299fa2Sopenharmony_ci        LOG(ERROR) << "WriteVersionCode fopen failed" << " : " << strerror(errno);
138fb299fa2Sopenharmony_ci        return false;
139fb299fa2Sopenharmony_ci    }
140fb299fa2Sopenharmony_ci    if (fseek(fp.get(), PARTITION_RECORD_OFFSET, SEEK_SET) != 0) {
141fb299fa2Sopenharmony_ci        LOG(ERROR) << "ClearMisc fseek failed";
142fb299fa2Sopenharmony_ci        return false;
143fb299fa2Sopenharmony_ci    }
144fb299fa2Sopenharmony_ci    off_t clearOffset = 0;
145fb299fa2Sopenharmony_ci    if (fwrite(&clearOffset, sizeof(off_t), 1, fp.get()) != 1) {
146fb299fa2Sopenharmony_ci        LOG(ERROR) << "ClearMisc write misc initOffset 0 failed" << " : " << strerror(errno);
147fb299fa2Sopenharmony_ci        return false;
148fb299fa2Sopenharmony_ci    }
149fb299fa2Sopenharmony_ci
150fb299fa2Sopenharmony_ci    struct PartitionRecordInfo cleanPartition {};
151fb299fa2Sopenharmony_ci    for (size_t tmpOffset = 0; tmpOffset < PARTITION_UPDATER_RECORD_MSG_SIZE; tmpOffset +=
152fb299fa2Sopenharmony_ci        sizeof(PartitionRecordInfo)) {
153fb299fa2Sopenharmony_ci        if (fseek(fp.get(), PARTITION_RECORD_START + tmpOffset, SEEK_SET) != 0) {
154fb299fa2Sopenharmony_ci            LOG(ERROR) << "ClearMisc fseek failed";
155fb299fa2Sopenharmony_ci            return false;
156fb299fa2Sopenharmony_ci        }
157fb299fa2Sopenharmony_ci        if (fwrite(&cleanPartition, sizeof(PartitionRecordInfo), 1, fp.get()) != 1) {
158fb299fa2Sopenharmony_ci            LOG(ERROR) << "ClearMisc write misc cleanPartition failed" << " : " << strerror(errno);
159fb299fa2Sopenharmony_ci            return false;
160fb299fa2Sopenharmony_ci        }
161fb299fa2Sopenharmony_ci    }
162fb299fa2Sopenharmony_ci    return true;
163fb299fa2Sopenharmony_ci}
164fb299fa2Sopenharmony_ci
165fb299fa2Sopenharmony_cibool IsSDCardExist(const std::string &sdcardPath)
166fb299fa2Sopenharmony_ci{
167fb299fa2Sopenharmony_ci    // Record system error codes.
168fb299fa2Sopenharmony_ci    int save_errno = errno;
169fb299fa2Sopenharmony_ci    struct stat st {};
170fb299fa2Sopenharmony_ci    if (stat(sdcardPath.c_str(), &st) < 0) {
171fb299fa2Sopenharmony_ci        return false;
172fb299fa2Sopenharmony_ci    } else {
173fb299fa2Sopenharmony_ci        errno = save_errno;
174fb299fa2Sopenharmony_ci        return true;
175fb299fa2Sopenharmony_ci    }
176fb299fa2Sopenharmony_ci}
177fb299fa2Sopenharmony_ci
178fb299fa2Sopenharmony_civoid PostUpdater(bool clearMisc)
179fb299fa2Sopenharmony_ci{
180fb299fa2Sopenharmony_ci    STAGE(UPDATE_STAGE_BEGIN) << "PostUpdater";
181fb299fa2Sopenharmony_ci
182fb299fa2Sopenharmony_ci    if (!CheckUpdateMode(SDCARD_MODE) && !CheckUpdateMode(USB_MODE) && (CheckUpdateMode(OTA_MODE) ||
183fb299fa2Sopenharmony_ci        GetMountStatusForMountPoint("/log") != MountStatus::MOUNT_MOUNTED)) {
184fb299fa2Sopenharmony_ci        (void)SetupPartitions();
185fb299fa2Sopenharmony_ci    } else {
186fb299fa2Sopenharmony_ci        (void)SetupPartitions(false);
187fb299fa2Sopenharmony_ci    }
188fb299fa2Sopenharmony_ci    UpdaterInit::GetInstance().InvokeEvent(UPDATER_POST_INIT_EVENT);
189fb299fa2Sopenharmony_ci    // clear update misc partition.
190fb299fa2Sopenharmony_ci    if (clearMisc && !ClearMisc()) {
191fb299fa2Sopenharmony_ci        LOG(ERROR) << "PostUpdater clear misc failed";
192fb299fa2Sopenharmony_ci    }
193fb299fa2Sopenharmony_ci    if (!access(COMMAND_FILE, 0) && unlink(COMMAND_FILE) != 0) {
194fb299fa2Sopenharmony_ci        LOG(ERROR) << "Delete command failed";
195fb299fa2Sopenharmony_ci    }
196fb299fa2Sopenharmony_ci
197fb299fa2Sopenharmony_ci    // delete updater tmp files
198fb299fa2Sopenharmony_ci    if (access(UPDATER_PATH, 0) == 0 && access(SDCARD_CARD_PATH, 0) != 0 && !DeleteUpdaterPath(UPDATER_PATH)) {
199fb299fa2Sopenharmony_ci        LOG(ERROR) << "DeleteUpdaterPath failed";
200fb299fa2Sopenharmony_ci    }
201fb299fa2Sopenharmony_ci    if (access(SDCARD_CARD_PATH, 0) == 0 && !DeleteUpdaterPath(SDCARD_CARD_PATH)) {
202fb299fa2Sopenharmony_ci        LOG(ERROR) << "Delete sdcard path failed";
203fb299fa2Sopenharmony_ci    }
204fb299fa2Sopenharmony_ci    if (access(Flashd::FLASHD_FILE_PATH, 0) == 0 && !DeleteUpdaterPath(Flashd::FLASHD_FILE_PATH)) {
205fb299fa2Sopenharmony_ci        LOG(ERROR) << "DeleteUpdaterPath failed";
206fb299fa2Sopenharmony_ci    }
207fb299fa2Sopenharmony_ci    if (!CheckUpdateMode(SDCARD_MODE) && !CheckUpdateMode(USB_MODE) &&
208fb299fa2Sopenharmony_ci        GetMountStatusForMountPoint("/log") != MountStatus::MOUNT_MOUNTED) {
209fb299fa2Sopenharmony_ci        SaveLogs();
210fb299fa2Sopenharmony_ci    }
211fb299fa2Sopenharmony_ci}
212fb299fa2Sopenharmony_ci
213fb299fa2Sopenharmony_civoid BootMode::InitMode(void) const
214fb299fa2Sopenharmony_ci{
215fb299fa2Sopenharmony_ci    InitLogger(modeName);
216fb299fa2Sopenharmony_ci#ifdef UPDATER_BUILD_VARIANT_USER
217fb299fa2Sopenharmony_ci    SetLogLevel(INFO);
218fb299fa2Sopenharmony_ci#else
219fb299fa2Sopenharmony_ci    SetLogLevel(DEBUG);
220fb299fa2Sopenharmony_ci#endif
221fb299fa2Sopenharmony_ci    LoadFstab();
222fb299fa2Sopenharmony_ci    STAGE(UPDATE_STAGE_OUT) << "Start " << modeName;
223fb299fa2Sopenharmony_ci    SetParameter(modePara.c_str(), "1");
224fb299fa2Sopenharmony_ci}
225fb299fa2Sopenharmony_ci
226fb299fa2Sopenharmony_cibool IsUpdater(const UpdateMessage &boot)
227fb299fa2Sopenharmony_ci{
228fb299fa2Sopenharmony_ci    return !IsFlashd(boot) && strncmp(boot.command, "boot_updater", sizeof("boot_updater") - 1) == 0;
229fb299fa2Sopenharmony_ci}
230fb299fa2Sopenharmony_ci
231fb299fa2Sopenharmony_cibool IsFlashd(const UpdateMessage &boot)
232fb299fa2Sopenharmony_ci{
233fb299fa2Sopenharmony_ci    return strncmp(boot.update, "boot_flash", sizeof("boot_flash") - 1) == 0;
234fb299fa2Sopenharmony_ci}
235fb299fa2Sopenharmony_ci
236fb299fa2Sopenharmony_cistd::vector<BootMode> &GetBootModes(void)
237fb299fa2Sopenharmony_ci{
238fb299fa2Sopenharmony_ci    static std::vector<BootMode> bootModes {};
239fb299fa2Sopenharmony_ci    return bootModes;
240fb299fa2Sopenharmony_ci}
241fb299fa2Sopenharmony_ci
242fb299fa2Sopenharmony_civoid RegisterMode(const BootMode &mode)
243fb299fa2Sopenharmony_ci{
244fb299fa2Sopenharmony_ci    GetBootModes().push_back(mode);
245fb299fa2Sopenharmony_ci}
246fb299fa2Sopenharmony_ci
247fb299fa2Sopenharmony_cistd::optional<BootMode> SelectMode(const UpdateMessage &boot)
248fb299fa2Sopenharmony_ci{
249fb299fa2Sopenharmony_ci    const auto &modes = GetBootModes();
250fb299fa2Sopenharmony_ci
251fb299fa2Sopenharmony_ci    // select modes by bootMode.cond which would check misc message
252fb299fa2Sopenharmony_ci    auto it = std::find_if(modes.begin(), modes.end(), [&boot] (const auto &bootMode) {
253fb299fa2Sopenharmony_ci        if (bootMode.cond != nullptr && bootMode.cond(boot)) {
254fb299fa2Sopenharmony_ci            LOG(INFO) << "condition for mode " << bootMode.modeName << " is satisfied";
255fb299fa2Sopenharmony_ci            return true;
256fb299fa2Sopenharmony_ci        }
257fb299fa2Sopenharmony_ci        LOG(WARNING) << "condition for mode " << bootMode.modeName << " is not satisfied";
258fb299fa2Sopenharmony_ci        return false;
259fb299fa2Sopenharmony_ci    });
260fb299fa2Sopenharmony_ci    // misc check failed for each mode, then enter updater mode
261fb299fa2Sopenharmony_ci    if (it == modes.end() || it->entryFunc == nullptr) {
262fb299fa2Sopenharmony_ci        LOG(WARNING) << "find valid mode failed, enter updater Mode";
263fb299fa2Sopenharmony_ci        return std::nullopt;
264fb299fa2Sopenharmony_ci    }
265fb299fa2Sopenharmony_ci
266fb299fa2Sopenharmony_ci    LOG(INFO) << "enter " << it->modeName << " mode";
267fb299fa2Sopenharmony_ci    return *it;
268fb299fa2Sopenharmony_ci}
269fb299fa2Sopenharmony_ci} // namespace Updater
270