1fb299fa2Sopenharmony_ci/*
2fb299fa2Sopenharmony_ci * Copyright (c) 2021 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 "update_partitions.h"
16fb299fa2Sopenharmony_ci#include <cerrno>
17fb299fa2Sopenharmony_ci#include <cstdio>
18fb299fa2Sopenharmony_ci#include <sstream>
19fb299fa2Sopenharmony_ci#include <string>
20fb299fa2Sopenharmony_ci#include "log/dump.h"
21fb299fa2Sopenharmony_ci#include "log/log.h"
22fb299fa2Sopenharmony_ci#include "updater/updater_const.h"
23fb299fa2Sopenharmony_ci#include "utils.h"
24fb299fa2Sopenharmony_ci
25fb299fa2Sopenharmony_ciusing namespace std;
26fb299fa2Sopenharmony_ciusing namespace Uscript;
27fb299fa2Sopenharmony_ciusing namespace Hpackage;
28fb299fa2Sopenharmony_ciusing namespace Updater;
29fb299fa2Sopenharmony_ciconstexpr int MIN_PARTITIONS_NUM = 2;
30fb299fa2Sopenharmony_ciconstexpr int MAX_PARTITIONS_NUM = 20;
31fb299fa2Sopenharmony_cinamespace Updater {
32fb299fa2Sopenharmony_cistatic bool CheckValueInt(const cJSON *item)
33fb299fa2Sopenharmony_ci{
34fb299fa2Sopenharmony_ci    if (item == nullptr || !cJSON_IsNumber(item)) {
35fb299fa2Sopenharmony_ci        LOG(ERROR) << "Error get valueint";
36fb299fa2Sopenharmony_ci        return false;
37fb299fa2Sopenharmony_ci    }
38fb299fa2Sopenharmony_ci    return true;
39fb299fa2Sopenharmony_ci}
40fb299fa2Sopenharmony_ci
41fb299fa2Sopenharmony_cistatic bool CheckValueString(const cJSON *item)
42fb299fa2Sopenharmony_ci{
43fb299fa2Sopenharmony_ci    if (item == nullptr || !cJSON_IsString(item) || strlen(item->valuestring) == 0) {
44fb299fa2Sopenharmony_ci        LOG(ERROR) << "Error get valuestring";
45fb299fa2Sopenharmony_ci        return false;
46fb299fa2Sopenharmony_ci    }
47fb299fa2Sopenharmony_ci    return true;
48fb299fa2Sopenharmony_ci}
49fb299fa2Sopenharmony_ci
50fb299fa2Sopenharmony_cibool UpdatePartitions::SetPartitionInfo(const cJSON *partitions, int idx, struct Partition *myPartition) const
51fb299fa2Sopenharmony_ci{
52fb299fa2Sopenharmony_ci    cJSON *thisPartition = cJSON_GetArrayItem(partitions, idx);
53fb299fa2Sopenharmony_ci    if (thisPartition == nullptr) {
54fb299fa2Sopenharmony_ci        LOG(ERROR) << "Error get thisPartion: " << idx;
55fb299fa2Sopenharmony_ci        return false;
56fb299fa2Sopenharmony_ci    }
57fb299fa2Sopenharmony_ci    cJSON *item = cJSON_GetObjectItem(thisPartition, "start");
58fb299fa2Sopenharmony_ci    if (!CheckValueInt(item)) {
59fb299fa2Sopenharmony_ci        LOG(ERROR) << "Error get start";
60fb299fa2Sopenharmony_ci        return false;
61fb299fa2Sopenharmony_ci    }
62fb299fa2Sopenharmony_ci    myPartition->start = static_cast<size_t>(item->valueint);
63fb299fa2Sopenharmony_ci
64fb299fa2Sopenharmony_ci    item = cJSON_GetObjectItem(thisPartition, "length");
65fb299fa2Sopenharmony_ci    if (!CheckValueInt(item)) {
66fb299fa2Sopenharmony_ci        LOG(ERROR) << "Error get length";
67fb299fa2Sopenharmony_ci        return false;
68fb299fa2Sopenharmony_ci    }
69fb299fa2Sopenharmony_ci    myPartition->length = static_cast<size_t>(item->valueint);
70fb299fa2Sopenharmony_ci    myPartition->partNum = 0;
71fb299fa2Sopenharmony_ci    myPartition->devName = "mmcblk0px";
72fb299fa2Sopenharmony_ci
73fb299fa2Sopenharmony_ci    item = cJSON_GetObjectItem(thisPartition, "partName");
74fb299fa2Sopenharmony_ci    if (!CheckValueString(item)) {
75fb299fa2Sopenharmony_ci        LOG(ERROR) << "Error get partName";
76fb299fa2Sopenharmony_ci        return false;
77fb299fa2Sopenharmony_ci    }
78fb299fa2Sopenharmony_ci    myPartition->partName = (item->valuestring);
79fb299fa2Sopenharmony_ci
80fb299fa2Sopenharmony_ci    item = cJSON_GetObjectItem(thisPartition, "fsType");
81fb299fa2Sopenharmony_ci    if (!CheckValueString(item)) {
82fb299fa2Sopenharmony_ci        LOG(ERROR) << "Error get fsType";
83fb299fa2Sopenharmony_ci        return false;
84fb299fa2Sopenharmony_ci    }
85fb299fa2Sopenharmony_ci    myPartition->fsType = (item->valuestring);
86fb299fa2Sopenharmony_ci
87fb299fa2Sopenharmony_ci    LOG(INFO) << "<start> <length> <devname> <partname> <fstype>";
88fb299fa2Sopenharmony_ci    LOG(INFO) << myPartition->start << " " << myPartition->length << " " << myPartition->devName << " " <<
89fb299fa2Sopenharmony_ci        myPartition->partName << " " << myPartition->fsType;
90fb299fa2Sopenharmony_ci    return true;
91fb299fa2Sopenharmony_ci}
92fb299fa2Sopenharmony_ci
93fb299fa2Sopenharmony_ciint UpdatePartitions::ParsePartitionInfo(const std::string &partitionInfo, PartitonList &newPartList) const
94fb299fa2Sopenharmony_ci{
95fb299fa2Sopenharmony_ci    cJSON* root = cJSON_Parse(partitionInfo.c_str());
96fb299fa2Sopenharmony_ci    if (root == nullptr) {
97fb299fa2Sopenharmony_ci        LOG(ERROR) << "Error get root";
98fb299fa2Sopenharmony_ci        return -1;
99fb299fa2Sopenharmony_ci    }
100fb299fa2Sopenharmony_ci    cJSON* partitions = cJSON_GetObjectItem(root, "Partition");
101fb299fa2Sopenharmony_ci    if (partitions == nullptr) {
102fb299fa2Sopenharmony_ci        LOG(ERROR) << "Error get Partitions";
103fb299fa2Sopenharmony_ci        cJSON_Delete(root);
104fb299fa2Sopenharmony_ci        return -1;
105fb299fa2Sopenharmony_ci    }
106fb299fa2Sopenharmony_ci    int number = cJSON_GetArraySize(partitions);
107fb299fa2Sopenharmony_ci    if (number <= MIN_PARTITIONS_NUM || number >= MAX_PARTITIONS_NUM) {
108fb299fa2Sopenharmony_ci        LOG(ERROR) << "Error partitions number: " << number;
109fb299fa2Sopenharmony_ci        cJSON_Delete(root);
110fb299fa2Sopenharmony_ci        return -1;
111fb299fa2Sopenharmony_ci    }
112fb299fa2Sopenharmony_ci    LOG(INFO) << "Partitions numbers " << number;
113fb299fa2Sopenharmony_ci
114fb299fa2Sopenharmony_ci    for (int i = 0; i < number; i++) {
115fb299fa2Sopenharmony_ci        struct Partition* myPartition = static_cast<struct Partition*>(calloc(1, sizeof(struct Partition)));
116fb299fa2Sopenharmony_ci        if (!myPartition) {
117fb299fa2Sopenharmony_ci            LOG(ERROR) << "Allocate memory for partition failed: " << errno;
118fb299fa2Sopenharmony_ci            cJSON_Delete(root);
119fb299fa2Sopenharmony_ci            return 0;
120fb299fa2Sopenharmony_ci        }
121fb299fa2Sopenharmony_ci        if (!SetPartitionInfo(partitions, i, myPartition)) {
122fb299fa2Sopenharmony_ci            free(myPartition);
123fb299fa2Sopenharmony_ci            myPartition = nullptr;
124fb299fa2Sopenharmony_ci            break;
125fb299fa2Sopenharmony_ci        }
126fb299fa2Sopenharmony_ci        newPartList.push_back(myPartition);
127fb299fa2Sopenharmony_ci    }
128fb299fa2Sopenharmony_ci    cJSON_Delete(root);
129fb299fa2Sopenharmony_ci    return 1;
130fb299fa2Sopenharmony_ci}
131fb299fa2Sopenharmony_ci
132fb299fa2Sopenharmony_ciint UpdatePartitions::DoNewPartitions(PartitonList &newPartList)
133fb299fa2Sopenharmony_ci{
134fb299fa2Sopenharmony_ci    int ret = DoPartitions(newPartList);
135fb299fa2Sopenharmony_ci    newPartList.clear();
136fb299fa2Sopenharmony_ci    if (ret <= 0) {
137fb299fa2Sopenharmony_ci        LOG(INFO) << "do_partitions FAIL ";
138fb299fa2Sopenharmony_ci    } else if (ret == 1) {
139fb299fa2Sopenharmony_ci        LOG(INFO) << "partitions not changed,Skip.";
140fb299fa2Sopenharmony_ci    } else if (ret > 1) {
141fb299fa2Sopenharmony_ci        LOG(INFO) << "do_partitions success reboot";
142fb299fa2Sopenharmony_ci#ifndef UPDATER_UT
143fb299fa2Sopenharmony_ci        Utils::UpdaterDoReboot("updater", "Updater finish do new partitions");
144fb299fa2Sopenharmony_ci#endif
145fb299fa2Sopenharmony_ci    }
146fb299fa2Sopenharmony_ci    return ret;
147fb299fa2Sopenharmony_ci}
148fb299fa2Sopenharmony_ci
149fb299fa2Sopenharmony_ciint UpdatePartitions::SetNewPartition(const std::string &filePath, const FileInfo *info, Uscript::UScriptEnv &env)
150fb299fa2Sopenharmony_ci{
151fb299fa2Sopenharmony_ci    std::string tmpPath = "/data/updater" + filePath;
152fb299fa2Sopenharmony_ci    char realPath[PATH_MAX + 1] = {};
153fb299fa2Sopenharmony_ci    if (realpath(tmpPath.c_str(), realPath) == nullptr) {
154fb299fa2Sopenharmony_ci        LOG(ERROR) << "Error to create: " << tmpPath;
155fb299fa2Sopenharmony_ci        return USCRIPT_ERROR_EXECUTE;
156fb299fa2Sopenharmony_ci    }
157fb299fa2Sopenharmony_ci    Hpackage::PkgManager::StreamPtr outStream = nullptr;
158fb299fa2Sopenharmony_ci    int ret = env.GetPkgManager()->CreatePkgStream(outStream,
159fb299fa2Sopenharmony_ci        std::string(realPath), info->unpackedSize, PkgStream::PkgStreamType_Write);
160fb299fa2Sopenharmony_ci    if (ret != USCRIPT_SUCCESS || outStream == nullptr) {
161fb299fa2Sopenharmony_ci        LOG(ERROR) << "Error to create output stream";
162fb299fa2Sopenharmony_ci        return USCRIPT_ERROR_EXECUTE;
163fb299fa2Sopenharmony_ci    }
164fb299fa2Sopenharmony_ci    ret = env.GetPkgManager()->ExtractFile(filePath, outStream);
165fb299fa2Sopenharmony_ci    if (ret != USCRIPT_SUCCESS) {
166fb299fa2Sopenharmony_ci        LOG(ERROR) << "Error to extract file";
167fb299fa2Sopenharmony_ci        env.GetPkgManager()->ClosePkgStream(outStream);
168fb299fa2Sopenharmony_ci        return USCRIPT_ERROR_EXECUTE;
169fb299fa2Sopenharmony_ci    }
170fb299fa2Sopenharmony_ci    FILE *fp = fopen(realPath, "rb");
171fb299fa2Sopenharmony_ci    if (!fp) {
172fb299fa2Sopenharmony_ci        LOG(ERROR) << "Open " << tmpPath << " failed: " << errno;
173fb299fa2Sopenharmony_ci        env.GetPkgManager()->ClosePkgStream(outStream);
174fb299fa2Sopenharmony_ci        return USCRIPT_ERROR_EXECUTE;
175fb299fa2Sopenharmony_ci    }
176fb299fa2Sopenharmony_ci    char partitionInfo[MAX_LOG_BUF_SIZE];
177fb299fa2Sopenharmony_ci    size_t partitionCount = fread(partitionInfo, 1, MAX_LOG_BUF_SIZE, fp);
178fb299fa2Sopenharmony_ci    fclose(fp);
179fb299fa2Sopenharmony_ci    if (partitionCount <= LEAST_PARTITION_COUNT) {
180fb299fa2Sopenharmony_ci        env.GetPkgManager()->ClosePkgStream(outStream);
181fb299fa2Sopenharmony_ci        LOG(ERROR) << "Invalid partition size, too small";
182fb299fa2Sopenharmony_ci        return USCRIPT_ERROR_EXECUTE;
183fb299fa2Sopenharmony_ci    }
184fb299fa2Sopenharmony_ci    PartitonList newPartList {};
185fb299fa2Sopenharmony_ci    if (ParsePartitionInfo(std::string(partitionInfo), newPartList) == 0) {
186fb299fa2Sopenharmony_ci        env.GetPkgManager()->ClosePkgStream(outStream);
187fb299fa2Sopenharmony_ci        return USCRIPT_ABOART;
188fb299fa2Sopenharmony_ci    }
189fb299fa2Sopenharmony_ci    if (newPartList.empty()) {
190fb299fa2Sopenharmony_ci        LOG(ERROR) << "Partition is empty ";
191fb299fa2Sopenharmony_ci        env.GetPkgManager()->ClosePkgStream(outStream);
192fb299fa2Sopenharmony_ci        return USCRIPT_SUCCESS; // Partitions table is empty not require partition.
193fb299fa2Sopenharmony_ci    }
194fb299fa2Sopenharmony_ci    DoNewPartitions(newPartList);
195fb299fa2Sopenharmony_ci    env.GetPkgManager()->ClosePkgStream(outStream);
196fb299fa2Sopenharmony_ci    return USCRIPT_SUCCESS;
197fb299fa2Sopenharmony_ci}
198fb299fa2Sopenharmony_ci
199fb299fa2Sopenharmony_ciint32_t UpdatePartitions::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
200fb299fa2Sopenharmony_ci{
201fb299fa2Sopenharmony_ci    LOG(INFO) << "enter UpdatePartitions::Execute ";
202fb299fa2Sopenharmony_ci    if (context.GetParamCount() != 1) {
203fb299fa2Sopenharmony_ci        LOG(ERROR) << "Invalid UpdatePartitions::Execute param";
204fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM);
205fb299fa2Sopenharmony_ci        return USCRIPT_INVALID_PARAM;
206fb299fa2Sopenharmony_ci    }
207fb299fa2Sopenharmony_ci    std::string filePath;
208fb299fa2Sopenharmony_ci    int32_t ret = context.GetParam(0, filePath);
209fb299fa2Sopenharmony_ci    if (ret != USCRIPT_SUCCESS) {
210fb299fa2Sopenharmony_ci        LOG(ERROR) << "Fail to get filePath";
211fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM);
212fb299fa2Sopenharmony_ci        return USCRIPT_INVALID_PARAM;
213fb299fa2Sopenharmony_ci    } else {
214fb299fa2Sopenharmony_ci        LOG(INFO) << "UpdatePartitions::Execute filePath " << filePath;
215fb299fa2Sopenharmony_ci    }
216fb299fa2Sopenharmony_ci    const FileInfo *info = env.GetPkgManager()->GetFileInfo(filePath);
217fb299fa2Sopenharmony_ci    if (info == nullptr) {
218fb299fa2Sopenharmony_ci        LOG(ERROR) << "Error to get file info";
219fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM);
220fb299fa2Sopenharmony_ci        return USCRIPT_ERROR_EXECUTE;
221fb299fa2Sopenharmony_ci    }
222fb299fa2Sopenharmony_ci    return SetNewPartition(filePath, info, env);
223fb299fa2Sopenharmony_ci}
224fb299fa2Sopenharmony_ci} // namespace Updater
225