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