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 "cJSON.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 {
ParsePartitionInfo(const std::string & partitionInfo,PartitonList & newPartList) const32 int UpdatePartitions::ParsePartitionInfo(const std::string &partitionInfo, PartitonList &newPartList) const
33 {
34 cJSON* root = cJSON_Parse(partitionInfo.c_str());
35 UPDATER_ERROR_CHECK(root != nullptr, "Error get root", return -1);
36 cJSON* partitions = cJSON_GetObjectItem(root, "Partition");
37 UPDATER_ERROR_CHECK(partitions != nullptr, "Error get Partitions", cJSON_Delete(root); return -1);
38 int number = cJSON_GetArraySize(partitions);
39 UPDATER_ERROR_CHECK(number > MIN_PARTITIONS_NUM, "Error partitions number < 3", cJSON_Delete(root); return -1);
40 UPDATER_ERROR_CHECK(number < MAX_PARTITIONS_NUM, "Error partitions number > 20", cJSON_Delete(root); return -1);
41 LOG(INFO) << "Partitions numbers " << number;
42 int i = 0;
43 for (i = 0; i < number; i++) {
44 struct Partition* myPartition = static_cast<struct Partition*>(calloc(1, sizeof(struct Partition)));
45 if (!myPartition) {
46 LOG(ERROR) << "Allocate memory for partition failed: " << errno;
47 cJSON_Delete(root);
48 return 0;
49 }
50 cJSON* thisPartition = cJSON_GetArrayItem(partitions, i);
51 UPDATER_ERROR_CHECK(thisPartition != nullptr, "Error get thisPartion", free(myPartition);
52 myPartition = nullptr; break);
53
54 cJSON* item = cJSON_GetObjectItem(thisPartition, "start");
55 UPDATER_ERROR_CHECK(item != nullptr, "Error get start", free(myPartition); myPartition = nullptr; break);
56 myPartition->start = static_cast<size_t>(item->valueint);
57
58 item = cJSON_GetObjectItem(thisPartition, "length");
59 UPDATER_ERROR_CHECK(item != nullptr, "Error get length", free(myPartition); myPartition = nullptr; break);
60 myPartition->length = static_cast<size_t>(item->valueint);
61 myPartition->partNum = 0;
62 myPartition->devName = "mmcblk0px";
63
64 item = cJSON_GetObjectItem(thisPartition, "partName");
65 UPDATER_ERROR_CHECK(item != nullptr, "Error get partName", free(myPartition); myPartition = nullptr; break);
66 myPartition->partName = (item->valuestring);
67
68 item = cJSON_GetObjectItem(thisPartition, "fsType");
69 UPDATER_ERROR_CHECK(item != nullptr, "Error get fsType", free(myPartition); myPartition = nullptr; break);
70 myPartition->fsType = (item->valuestring);
71
72 LOG(INFO) << "<start> <length> <devname> <partname> <fstype>";
73 LOG(INFO) << myPartition->start << " " << myPartition->length << " " << myPartition->devName << " " <<
74 myPartition->partName << " " << myPartition->fsType;
75 newPartList.push_back(myPartition);
76 }
77 cJSON_Delete(root);
78 return 1;
79 }
80
DoNewPartitions(PartitonList & newPartList)81 int UpdatePartitions::DoNewPartitions(PartitonList &newPartList)
82 {
83 int ret = DoPartitions(newPartList);
84 newPartList.clear();
85 if (ret <= 0) {
86 LOG(INFO) << "do_partitions FAIL ";
87 } else if (ret == 1) {
88 LOG(INFO) << "partitions not changed,Skip.";
89 } else if (ret > 1) {
90 LOG(INFO) << "do_partitions success reboot";
91 #ifndef UPDATER_UT
92 Utils::DoReboot("updater");
93 #endif
94 }
95 return ret;
96 }
97
Execute(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)98 int32_t UpdatePartitions::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
99 {
100 LOG(INFO) << "enter UpdatePartitions::Execute ";
101 if (context.GetParamCount() != 1) {
102 LOG(ERROR) << "Invalid UpdatePartitions::Execute param";
103 return USCRIPT_INVALID_PARAM;
104 }
105 std::string filePath;
106 int32_t ret = context.GetParam(0, filePath);
107 if (ret != USCRIPT_SUCCESS) {
108 LOG(ERROR) << "Fail to get filePath";
109 return USCRIPT_INVALID_PARAM;
110 } else {
111 LOG(INFO) << "UpdatePartitions::Execute filePath " << filePath;
112 }
113 Hpackage::PkgManager::StreamPtr outStream = nullptr;
114 const FileInfo *info = env.GetPkgManager()->GetFileInfo(filePath);
115 UPDATER_ERROR_CHECK(info != nullptr, "Error to get file info", return USCRIPT_ERROR_EXECUTE);
116 std::string tmpPath = "/data/updater";
117 std::string tmpPath1 = tmpPath + filePath;
118 char realPath[PATH_MAX + 1] = {};
119 UPDATER_ERROR_CHECK(realpath(tmpPath1.c_str(), realPath) != nullptr,
120 "Error to create tmpPath1", return USCRIPT_ERROR_EXECUTE);
121 ret = env.GetPkgManager()->CreatePkgStream(outStream,
122 tmpPath1, info->unpackedSize, PkgStream::PkgStreamType_Write);
123 UPDATER_ERROR_CHECK(ret == USCRIPT_SUCCESS && outStream != nullptr, "Error to create output stream",
124 return USCRIPT_ERROR_EXECUTE);
125 ret = env.GetPkgManager()->ExtractFile(filePath, outStream);
126 UPDATER_ERROR_CHECK(ret == USCRIPT_SUCCESS, "Error to extract file",
127 env.GetPkgManager()->ClosePkgStream(outStream); return USCRIPT_ERROR_EXECUTE);
128 FILE *fp = fopen(realPath, "rb");
129 if (!fp) {
130 LOG(ERROR) << "Open " << tmpPath1 << " failed: " << errno;
131 env.GetPkgManager()->ClosePkgStream(outStream);
132 return USCRIPT_ERROR_EXECUTE;
133 }
134 char partitionInfo[MAX_LOG_BUF_SIZE];
135 size_t partitionCount = fread(partitionInfo, 1, MAX_LOG_BUF_SIZE, fp);
136 fclose(fp);
137 if (partitionCount <= LEAST_PARTITION_COUNT) {
138 env.GetPkgManager()->ClosePkgStream(outStream);
139 LOG(ERROR) << "Invalid partition size, too small";
140 return USCRIPT_ERROR_EXECUTE;
141 }
142 PartitonList newPartList {};
143 if (ParsePartitionInfo(std::string(partitionInfo), newPartList) == 0) {
144 env.GetPkgManager()->ClosePkgStream(outStream);
145 return USCRIPT_ABOART;
146 }
147 if (newPartList.empty()) {
148 LOG(ERROR) << "Partition is empty ";
149 env.GetPkgManager()->ClosePkgStream(outStream);
150 return USCRIPT_SUCCESS; // Partitions table is empty not require partition.
151 }
152 DoNewPartitions(newPartList);
153 env.GetPkgManager()->ClosePkgStream(outStream);
154 return USCRIPT_SUCCESS;
155 }
156 } // namespace Updater
157