1/* 2 * Copyright (C) 2022 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 16#include "host_updater.h" 17 18#include <algorithm> 19#include <unordered_map> 20 21#include "common.h" 22#include "define.h" 23#include "serial_struct.h" 24 25namespace Hdc { 26namespace { 27constexpr uint8_t PERCENT_FINISH = 100; 28constexpr uint8_t PERCENT_CLEAR = UINT8_MAX; 29constexpr int MAX_RETRY_COUNT = 3; 30constexpr size_t FLASH_PARAM_MIN_COUNT = 2; 31constexpr size_t FLASH_FILE_INDEX = 1; 32constexpr size_t UPDATE_PARAM_MIN_COUNT = 1; 33constexpr size_t UPDATE_FILE_INDEX = 0; 34constexpr size_t FORMAT_PARAM_MIN_COUNT = 2; 35constexpr size_t ERASE_PARAM_MIN_COUNT = 2; 36 37const std::string CMD_STR_UPDATE = "update "; 38const std::string CMD_STR_FLASH = "flash "; 39const std::string CMD_STR_ERASE = "erase "; 40const std::string CMD_STR_FORMAT = "format "; 41 42const std::unordered_map<std::string, uint16_t> FLASHD_CMD = { 43 {CMD_STR_UPDATE, CMD_FLASHD_UPDATE_INIT}, 44 {CMD_STR_FLASH, CMD_FLASHD_FLASH_INIT}, 45 {CMD_STR_ERASE, CMD_FLASHD_ERASE}, 46 {CMD_STR_FORMAT, CMD_FLASHD_FORMAT}, 47}; 48 49std::vector<std::string> Split(const std::string &src, const std::vector<std::string> &filter) 50{ 51 std::vector<std::string> result; 52 if (src.empty()) { 53 return result; 54 } 55 const auto len = src.size() + 1; 56 auto buffer = std::vector<char>(len, 0); 57 buffer.assign(src.begin(), src.end()); 58 const char delimit[] = "\t\r\n "; 59 char *nextToken = nullptr; 60 char *token = strtok_s(buffer.data(), delimit, &nextToken); 61 while (token != nullptr) { 62 if (std::find(filter.cbegin(), filter.cend(), token) == filter.cend()) { 63 result.push_back(token); 64 } 65 token = strtok_s(nullptr, delimit, &nextToken); 66 } 67 return result; 68} 69} 70 71HostUpdater::HostUpdater(HTaskInfo hTaskInfo) : HdcTransferBase(hTaskInfo) 72{ 73 commandBegin = CMD_FLASHD_BEGIN; 74 commandData = CMD_FLASHD_DATA; 75} 76 77HostUpdater::~HostUpdater() {} 78 79bool HostUpdater::RunQueue(CtxFile &context) 80{ 81 context.localPath = context.taskQueue.back(); 82 uv_fs_t *openReq = new uv_fs_t; 83 if (openReq == nullptr) { 84 WRITE_LOG(LOG_FATAL, "HostUpdater::RunQueue new uv_fs_t failed"); 85 OnFileOpenFailed(&context); 86 return false; 87 } 88 memset_s(openReq, sizeof(uv_fs_t), 0, sizeof(uv_fs_t)); 89 openReq->data = &context; 90 refCount++; 91 uv_fs_open(loopTask, openReq, context.localPath.c_str(), O_RDONLY, 0, OnFileOpen); 92 context.master = true; 93 return true; 94} 95 96bool HostUpdater::BeginTransfer(const std::string &function, const uint8_t *payload, int payloadSize, size_t minParam, 97 size_t fileIndex) 98{ 99 if (payload[payloadSize - 1] != '\0') { 100 WRITE_LOG(LOG_FATAL, "payload is invalid"); 101 return false; 102 } 103 std::string cmdParam(reinterpret_cast<const char *>(payload)); 104 auto params = Split(cmdParam, {}); 105 auto count = minParam; 106 auto index = fileIndex; 107 if (std::find(params.cbegin(), params.cend(), "-f") != params.cend()) { 108 count++; 109 index++; 110 } 111 if (params.size() != count || params.size() <= index) { 112 WRITE_LOG(LOG_FATAL, "param count is invalid"); 113 return false; 114 } 115 116 std::string localPath = params[index]; 117 if (!Base::CheckDirectoryOrPath(localPath.c_str(), true, true)) { 118 WRITE_LOG(LOG_FATAL, "localPath is invalid"); 119 return false; 120 } 121 122 if (MatchPackageExtendName(localPath, ".img") || MatchPackageExtendName(localPath, ".bin") || 123 MatchPackageExtendName(localPath, ".fd") || MatchPackageExtendName(localPath, ".cpio")) { 124 ctxNow.transferConfig.compressType = COMPRESS_NONE; 125 } else if (MatchPackageExtendName(localPath, ".zip")) { 126 WRITE_LOG(LOG_INFO, "file type is zip"); 127 } else { 128 WRITE_LOG(LOG_FATAL, "file type is invalid"); 129 return false; 130 } 131 ctxNow.transferConfig.functionName = function; 132 ctxNow.transferConfig.options = cmdParam; 133 ctxNow.localPath = localPath; 134 ctxNow.taskQueue.push_back(localPath); 135 return RunQueue(ctxNow); 136} 137 138void HostUpdater::CheckMaster(CtxFile *context) 139{ 140 uv_fs_t fs; 141 Base::ZeroStruct(fs.statbuf); 142 uv_fs_fstat(nullptr, &fs, context->openFd, nullptr); 143 context->transferConfig.fileSize = fs.statbuf.st_size; 144 uv_fs_req_cleanup(&fs); 145 context->transferConfig.optionalName = Base::GetFileNameAny(context->localPath); 146 std::string bufString = SerialStruct::SerializeToString(context->transferConfig); 147 148 WRITE_LOG(LOG_DEBUG, "functionName = %s, fileSize = %llu", context->transferConfig.functionName.c_str(), 149 context->transferConfig.fileSize); 150 151 std::vector<uint8_t> buffer(sizeof(uint64_t) / sizeof(uint8_t), 0); 152 buffer.insert(buffer.end(), bufString.begin(), bufString.end()); 153 SendToAnother(CMD_FLASHD_CHECK, (uint8_t *)buffer.data(), buffer.size()); 154} 155 156bool HostUpdater::CheckCmd(HdcCommand command, uint8_t *payload, int payloadSize, size_t paramCount) 157{ 158 if (payloadSize < 1 || payload[payloadSize - 1] != '\0') { 159 WRITE_LOG(LOG_FATAL, "payload is invalid"); 160 return false; 161 } 162 std::string cmdParam(reinterpret_cast<char *>(payload)); 163 WRITE_LOG(LOG_INFO, "cmdParam = %s, paramCount = %u", cmdParam.c_str(), paramCount); 164 165 auto result = Split(cmdParam, {}); 166 auto iter = std::find(result.cbegin(), result.cend(), "-f"); 167 bool ret = (iter != result.cend()) ? (result.size() == (paramCount + 1)) : (result.size() == paramCount); 168 if (!ret) { 169 WRITE_LOG(LOG_FATAL, "CheckCmd failed"); 170 return false; 171 } 172 173 SendToAnother(command, payload, payloadSize); 174 ctxNow.taskQueue.push_back(cmdParam); 175 return true; 176} 177 178bool HostUpdater::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize) 179{ 180 if (command == CMD_FLASHD_BEGIN) { 181 if (!HdcTransferBase::CommandDispatch(command, payload, payloadSize)) { 182 return false; 183 } 184 std::string tip("Processing: 0%"); 185 sendProgress_ = true; 186 SendRawData(tip); 187 return true; 188 } 189 190 if (payload == nullptr || payloadSize <= 0) { 191 WRITE_LOG(LOG_FATAL, "payload or payloadSize is invalid"); 192 return false; 193 } 194 if (!HdcTransferBase::CommandDispatch(command, payload, payloadSize)) { 195 return false; 196 } 197 bool ret = true; 198 switch (command) { 199 case CMD_FLASHD_UPDATE_INIT: 200 ret = BeginTransfer(CMDSTR_FLASHD_UPDATE, payload, payloadSize, UPDATE_PARAM_MIN_COUNT, UPDATE_FILE_INDEX); 201 break; 202 case CMD_FLASHD_FLASH_INIT: 203 ret = BeginTransfer(CMDSTR_FLASHD_FLASH, payload, payloadSize, FLASH_PARAM_MIN_COUNT, FLASH_FILE_INDEX); 204 break; 205 case CMD_FLASHD_FINISH: 206 ret = CheckUpdateContinue(command, payload, payloadSize); 207 break; 208 case CMD_FLASHD_ERASE: 209 ret = CheckCmd(CMD_FLASHD_ERASE, payload, payloadSize, ERASE_PARAM_MIN_COUNT); 210 break; 211 case CMD_FLASHD_FORMAT: 212 ret = CheckCmd(CMD_FLASHD_FORMAT, payload, payloadSize, FORMAT_PARAM_MIN_COUNT); 213 break; 214 case CMD_FLASHD_PROGRESS: 215 ProcessProgress(*payload); 216 break; 217 default: 218 break; 219 } 220 return ret; 221} 222 223void HostUpdater::ProcessProgress(uint8_t percentage) 224{ 225 if (!sendProgress_) { 226 return; 227 } 228 if (percentage == PERCENT_CLEAR) { 229 SendRawData("\n"); 230 sendProgress_ = false; 231 return; 232 } 233 std::string plrogress = "\rProcessing: " + std::to_string(percentage) + "%"; 234 SendRawData(plrogress); 235 if (percentage == PERCENT_FINISH) { 236 SendRawData("\n"); 237 sendProgress_ = false; 238 } 239} 240 241bool HostUpdater::CheckUpdateContinue(const uint16_t command, const uint8_t *payload, int payloadSize) 242{ 243 if (static_cast<size_t>(payloadSize) < sizeof(uint16_t)) { 244 return false; 245 } 246 247 MessageLevel level = static_cast<MessageLevel>(payload[1]); 248 if ((level == MSG_OK) && sendProgress_) { 249 ProcessProgress(PERCENT_FINISH); 250 } 251 std::string info(reinterpret_cast<char *>(const_cast<uint8_t *>(payload + sizeof(uint16_t))), 252 payloadSize - sizeof(uint16_t)); 253 if (!info.empty()) { 254 LogMsg(level, "%s", info.c_str()); 255 } 256 WRITE_LOG(LOG_DEBUG, "CheckUpdateContinue payloadSize %d %d %s", payloadSize, level, info.c_str()); 257 if (ctxNow.taskQueue.size() != 0) { 258 ctxNow.taskQueue.pop_back(); 259 } 260 if (singalStop || !ctxNow.taskQueue.size()) { 261 return false; 262 } 263 return RunQueue(ctxNow); 264} 265 266bool HostUpdater::CheckMatchUpdate(const std::string &input, TranslateCommand::FormatCommand &outCmd) 267{ 268 WRITE_LOG(LOG_DEBUG, "CheckMatchUpdate command:%s", input.c_str()); 269 for (const auto &iter : FLASHD_CMD) { 270 if ((input.find(iter.first) == 0) && (input.size() > iter.first.size())) { 271 outCmd.cmdFlag = iter.second; 272 return true; 273 } 274 } 275 return false; 276} 277 278bool HostUpdater::ConfirmCommand(const string &commandIn, bool &closeInput) 279{ 280 std::string tip = ""; 281 if (!strncmp(commandIn.c_str(), CMD_STR_UPDATE.c_str(), CMD_STR_UPDATE.size())) { 282 closeInput = true; 283 } else if (!strncmp(commandIn.c_str(), CMD_STR_FLASH.c_str(), CMD_STR_FLASH.size())) { 284 tip = "Confirm flash partition"; 285 closeInput = true; 286 } else if (!strncmp(commandIn.c_str(), CMD_STR_ERASE.c_str(), CMD_STR_ERASE.size())) { 287 tip = "Confirm erase partition"; 288 } else if (!strncmp(commandIn.c_str(), CMD_STR_FORMAT.c_str(), CMD_STR_FORMAT.size())) { 289 tip = "Confirm format partition"; 290 } 291 if (tip.empty() || strstr(commandIn.c_str(), " -f") != nullptr) { 292 return true; 293 } 294 const size_t minLen = strlen("yes"); 295 int retryCount = 0; 296 do { 297 printf("%s ? (Yes/No) ", tip.c_str()); 298 fflush(stdin); 299 std::string info = {}; 300 size_t i = 0; 301 while (1) { 302 char c = getchar(); 303 if (c == '\r' || c == '\n') { 304 break; 305 } 306 if (c == ' ') { 307 continue; 308 } 309 if (i < minLen && isprint(c)) { 310 info.append(1, std::tolower(c)); 311 i++; 312 } 313 } 314 if (info == "n" || info == "no") { 315 return false; 316 } 317 if (info == "y" || info == "yes") { 318 return true; 319 } 320 retryCount++; 321 } while (retryCount < MAX_RETRY_COUNT); 322 return (retryCount >= MAX_RETRY_COUNT) ? false : true; 323} 324 325void HostUpdater::SendRawData(std::string rawData) const 326{ 327 HdcSessionBase *sessionBase = (HdcSessionBase *)clsSession; 328 if (sessionBase == nullptr) { 329 WRITE_LOG(LOG_FATAL, "sessionBase is null"); 330 return; 331 } 332 sessionBase->ServerCommand(taskInfo->sessionId, taskInfo->channelId, CMD_KERNEL_ECHO_RAW, 333 reinterpret_cast<uint8_t *>(rawData.data()), rawData.size()); 334} 335} // namespace Hdc