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