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 "updaterkits/updaterkits.h"
16
17#include <string>
18#include <sys/stat.h>
19#include <unistd.h>
20#include "init_reboot.h"
21#include "log.h"
22#include "misc_info/misc_info.h"
23#include "securec.h"
24#include "updater/updater_const.h"
25#include "utils.h"
26#include "utils_fs.h"
27
28using namespace Updater;
29using Updater::Utils::SplitString;
30
31static bool WriteToMiscAndRebootToUpdater(const struct UpdateMessage &updateMsg)
32{
33    // Write package name to misc, then trigger reboot.
34    const char *bootCmd = "boot_updater";
35    int ret = strncpy_s(const_cast<char*>(updateMsg.command), sizeof(updateMsg.command), bootCmd,
36        sizeof(updateMsg.command) - 1);
37    if (ret != 0) {
38        return false;
39    }
40#ifndef UPDATER_UT
41    WriteUpdaterMiscMsg(updateMsg);
42    DoReboot("updater:reboot to updater to trigger update");
43    while (true) {
44        pause();
45    }
46#else
47    return true;
48#endif
49}
50
51static void WriteUpdaterResultFile(const std::string &pkgPath, const std::string &result)
52{
53    if (access(UPDATER_PATH, 0) != 0) {
54        if (Utils::MkdirRecursive(UPDATER_PATH, 0755) != 0) { // 0755: -rwxr-xr-x
55            LOG(ERROR) << "Mkdir recursive error!";
56            return;
57        }
58    }
59    LOG(INFO) << "WriteUpdaterResultFile: " << result;
60    const std::string resultPath = std::string(UPDATER_PATH) + "/" + std::string(UPDATER_RESULT_FILE);
61    FILE *fp = fopen(resultPath.c_str(), "w+");
62    if (fp == nullptr) {
63        LOG(ERROR) << "open updater result file failed";
64        return;
65    }
66    std::string resultInfo = pkgPath + "|fail|" + result + "||\n";
67    if (fwrite(resultInfo.c_str(), resultInfo.size() + 1, 1, fp) <= 0) {
68        LOG(WARNING) << "write updater result file failed, err:" << errno;
69    }
70    if (fsync(fileno(fp)) != 0) {
71        LOG(WARNING) << "WriteUpdaterResultFile fsync failed" << strerror(errno);
72    }
73    if (fclose(fp) != 0) {
74        LOG(WARNING) << "close updater result file failed";
75    }
76
77    (void)chown(resultPath.c_str(), Utils::USER_ROOT_AUTHORITY, Utils::GROUP_UPDATE_AUTHORITY);
78    (void)chmod(resultPath.c_str(), 0660); // 0660: -rw-rw----
79}
80
81static std::string ParsePkgPath(const struct UpdateMessage &updateMsg)
82{
83    std::string pkgPath = "";
84    std::string pathInfo(updateMsg.update, sizeof(updateMsg.update));
85    std::string::size_type startPos = pathInfo.find("update_package=");
86    std::string::size_type endPos = pathInfo.find(".zip");
87    if (startPos != pathInfo.npos && endPos != pathInfo.npos) {
88        startPos += strlen("update_package=");
89        endPos += strlen(".zip");
90        if (endPos > startPos) {
91            pkgPath = pathInfo.substr(startPos, endPos - startPos);
92        } else {
93            LOG(ERROR) << "pkgPath invalid";
94        }
95    }
96    return pkgPath;
97}
98
99static bool WriteToMiscAndResultFileRebootToUpdater(const struct UpdateMessage &updateMsg)
100{
101    // Write package name to misc, then trigger reboot.
102    const char *bootCmd = "boot_updater";
103    int ret = strncpy_s(const_cast<char*>(updateMsg.command), sizeof(updateMsg.command), bootCmd,
104        sizeof(updateMsg.command) - 1);
105    if (ret != 0) {
106        return false;
107    }
108    std::string pkgPath = ParsePkgPath(updateMsg);
109    // Flag before the misc in written
110    std::string writeMiscBefore = "0x80000000";
111    WriteUpdaterResultFile(pkgPath, writeMiscBefore);
112#ifndef UPDATER_UT
113    WriteUpdaterMiscMsg(updateMsg);
114    // Flag after the misc in written
115    std::string writeMiscAfter = "0x80000008";
116    WriteUpdaterResultFile(pkgPath, writeMiscAfter);
117    DoReboot("updater:reboot to updater to trigger update");
118    while (true) {
119        pause();
120    }
121#else
122    return true;
123#endif
124}
125
126static bool IsPackagePath(const std::string &path)
127{
128    if (path.find("--force_update_action=") != std::string::npos ||
129        path.find("--night_update") != std::string::npos) {
130            return false;
131        }
132    return true;
133}
134
135static int AddPkgPath(struct UpdateMessage &msg, size_t updateOffset, const std::vector<std::string> &packageName)
136{
137    for (auto path : packageName) {
138        if (updateOffset > sizeof(msg.update)) {
139            LOG(ERROR) << "updaterkits: updateOffset > msg.update, return false";
140            return 4; // 4 : path is too long
141        }
142        int ret;
143        if (IsPackagePath(path)) {
144            ret = snprintf_s(msg.update + updateOffset, sizeof(msg.update) - updateOffset,
145                sizeof(msg.update) - 1 - updateOffset, "--update_package=%s\n", path.c_str());
146        } else {
147            ret = snprintf_s(msg.update + updateOffset, sizeof(msg.update) - updateOffset,
148                sizeof(msg.update) - 1 - updateOffset, "%s\n", path.c_str());
149        }
150        if (ret < 0) {
151            LOG(ERROR) << "updaterkits: copy updater message failed";
152            return 5; // 5 : The library function is incorrect
153        }
154        updateOffset += static_cast<size_t>(ret);
155    }
156    return 0;
157}
158
159bool RebootAndInstallSdcardPackage(const std::string &miscFile, const std::vector<std::string> &packageName)
160{
161    struct UpdateMessage msg {};
162    int ret = snprintf_s(msg.update, sizeof(msg.update), sizeof(msg.update) - 1, "--sdcard_update\n");
163    if (ret < 0) {
164        LOG(ERROR) << "updaterkits: copy updater message failed";
165        return false;
166    }
167
168    if (packageName.size() != 0 && AddPkgPath(msg, static_cast<size_t>(ret), packageName) != 0) {
169        LOG(ERROR) << "get sdcard pkg path fail";
170        return false;
171    }
172    WriteToMiscAndRebootToUpdater(msg);
173
174    // Never get here.
175    return true;
176}
177
178int RebootAndInstallUpgradePackage(const std::string &miscFile, const std::vector<std::string> &packageName,
179    const std::string &upgradeType)
180{
181    if (packageName.size() == 0 && upgradeType == UPGRADE_TYPE_OTA) {
182        LOG(ERROR) << "updaterkits: invalid argument. one of arugments is empty";
183        return 1; // 1 : Invalid input
184    }
185
186    for (auto path : packageName) {
187        if (IsPackagePath(path)) {
188            if (access(path.c_str(), R_OK) < 0) {
189            LOG(ERROR) << "updaterkits: " << path << " is not readable";
190            return 2; // 2 : pkg not exit
191            }
192        }
193    }
194    struct UpdateMessage updateMsg {};
195    int ret = 0;
196    if (upgradeType == UPGRADE_TYPE_SD) {
197        ret = snprintf_s(updateMsg.update, sizeof(updateMsg.update), sizeof(updateMsg.update) - 1,
198            "--sdcard_update\n");
199    } else if (upgradeType == UPGRADE_TYPE_SD_INTRAL) {
200        ret = snprintf_s(updateMsg.update, sizeof(updateMsg.update), sizeof(updateMsg.update) - 1,
201            "--sdcard_intral_update\n");
202    }
203    if (ret < 0) {
204        LOG(ERROR) << "updaterkits: copy updater message failed";
205        return 3; // 3 : The library function is incorrect
206    }
207    int addRet = AddPkgPath(updateMsg, static_cast<size_t>(ret), packageName);
208    if (addRet != 0) {
209        return addRet;
210    }
211    if (upgradeType == UPGRADE_TYPE_OTA) {
212        WriteToMiscAndResultFileRebootToUpdater(updateMsg);
213    } else {
214        WriteToMiscAndRebootToUpdater(updateMsg);
215    }
216
217    // Never get here.
218    return 0;
219}
220
221bool RebootAndCleanUserData(const std::string &miscFile, const std::string &cmd)
222{
223    if (miscFile.empty() || cmd.empty()) {
224        LOG(ERROR) << "updaterkits: invalid argument. one of arugments is empty";
225        return false;
226    }
227
228    // Write package name to misc, then trigger reboot.
229    struct UpdateMessage updateMsg {};
230    if (strncpy_s(updateMsg.update, sizeof(updateMsg.update), cmd.c_str(), cmd.size()) != EOK) {
231        LOG(ERROR) << "updaterkits: copy updater message failed";
232        return false;
233    }
234
235    WriteToMiscAndRebootToUpdater(updateMsg);
236
237    // Never get here.
238    return true;
239}
240