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 "sdcard_update.h"
16#include <chrono>
17#include <dirent.h>
18#include <fcntl.h>
19#include <string>
20#include <sys/mount.h>
21#include <sys/stat.h>
22#include <thread>
23#include <unistd.h>
24#include <vector>
25#include "language/language_ui.h"
26#include "log/dump.h"
27#include "log/log.h"
28#include "fs_manager/mount.h"
29#include "securec.h"
30#include "ui/updater_ui_stub.h"
31#include "updater/updater_const.h"
32#include "utils.h"
33
34namespace Updater {
35__attribute__((weak)) UpdaterStatus GetSdcardPkgsPath(UpdaterParams &upParams)
36{
37    if (upParams.updatePackage.size() != 0) {
38        LOG(INFO) << "get sdcard packages from misc";
39        return UPDATE_SUCCESS;
40    }
41    LOG(INFO) << "get sdcard packages from sdcard path";
42    std::vector<std::string> sdcardPkgs = Utils::SplitString(SDCARD_CARD_PKG_PATH, ", ");
43    for (auto pkgPath : sdcardPkgs) {
44        if (access(pkgPath.c_str(), 0) == 0) {
45            LOG(INFO) << "find sdcard package : " << pkgPath;
46            upParams.updatePackage.push_back(pkgPath);
47        }
48    }
49    if (upParams.updatePackage.size() == 0) {
50        return UPDATE_ERROR;
51    }
52    return UPDATE_SUCCESS;
53}
54
55__attribute__((weak)) UpdaterStatus GetSdcardPkgsFromDev(UpdaterParams &upParams)
56{
57    LOG(INFO) << "not implemented get sdcard pkgs from dev";
58    return UPDATE_ERROR;
59}
60
61bool CheckPathNeedMountSD(UpdaterParams &upParams)
62{
63    for (auto pkgPath : upParams.updatePackage) {
64        if (pkgPath.find("/sdcard") != 0) {
65            return false;
66        }
67    }
68    return true;
69}
70
71bool DoMountSdCard(std::vector<std::string> &sdCardStr, std::string &mountPoint, UpdaterParams &upParams)
72{
73    bool mountSuccess = false;
74    unsigned int retryTimes = 20; // Wait 20s
75    if (upParams.sdExtMode == SDCARD_MAINIMG || upParams.sdExtMode == SDCARD_NORMAL_UPDATE) {
76        retryTimes = 60; // Wait 60s
77    }
78    for (unsigned int retryCount = 1; retryCount <= retryTimes; retryCount++) {
79        LOG(INFO) << "the retry time is: " << retryCount;
80        for (auto item : sdCardStr) {
81            if (MountSdcard(item, mountPoint) == 0) {
82                mountSuccess = true;
83                LOG(INFO) << "mount " << item << " sdcard success!";
84                break;
85            }
86        }
87        if (mountSuccess) {
88            break;
89        }
90        sleep(1); // sleep 1 second to wait for sd card recognition
91    }
92    return mountSuccess;
93}
94
95UpdaterStatus CheckSdcardPkgs(UpdaterParams &upParams)
96{
97#ifndef UPDATER_UT
98    auto sdParam = "updater.data.configs";
99    Utils::SetParameter(sdParam, "1");
100    if (upParams.sdExtMode == SDCARD_UPDATE_FROM_DEV && GetSdcardPkgsFromDev(upParams) == UPDATE_SUCCESS) {
101        LOG(INFO) << "get sd card from dev succeed, skip get package from sd card";
102        return UPDATE_SUCCESS;
103    }
104
105    if (GetSdcardInternalPkgs(upParams) == UPDATE_SUCCESS) {
106        LOG(INFO) << "get sdcard internal pkgs succeed";
107        return UPDATE_SUCCESS;
108    }
109
110    std::string mountPoint = std::string(SDCARD_PATH);
111    std::vector<std::string> sdcardStr = GetBlockDevicesByMountPoint(mountPoint);
112    if (sdcardStr.empty()) {
113        UPDATER_UI_INSTANCE.ShowLog(
114            (errno == ENOENT) ? TR(LOG_SDCARD_NOTFIND) : TR(LOG_SDCARD_ABNORMAL), true);
115        return UPDATE_ERROR;
116    }
117    if (Utils::CheckUpdateMode(Updater::SDCARD_INTRAL_MODE)) {
118        if (MountForPath("/data") != 0) {
119            LOG(ERROR) << "data partition mount fail";
120            return UPDATE_ERROR;
121        }
122    }
123    if ((Utils::CheckUpdateMode(Updater::SDCARD_MODE) && !Utils::CheckUpdateMode(Updater::SDCARD_INTRAL_MODE)) ||
124        (Utils::CheckUpdateMode(Updater::SDCARD_INTRAL_MODE) && CheckPathNeedMountSD(upParams))) {
125            if (!DoMountSdCard(sdcardStr, mountPoint, upParams)) {
126                LOG(ERROR) << "mount sdcard fail!";
127                return UPDATE_ERROR;
128            }
129        }
130#endif
131    if (GetSdcardPkgsPath(upParams) != UPDATE_SUCCESS) {
132        LOG(ERROR) << "there is no package in sdcard/updater, please check";
133        return UPDATE_ERROR;
134    }
135    return UPDATE_SUCCESS;
136}
137
138__attribute__((weak)) UpdaterStatus GetSdcardInternalPkgs(UpdaterParams &upParams)
139{
140    LOG(INFO) << "not implemented get normal update sdcard pkgs";
141    return UPDATE_ERROR;
142}
143} // Updater
144