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