/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "script_instructionhelper.h" #include <dlfcn.h> #include <set> #include "dump.h" #include "scope_guard.h" #include "script_basicinstruction.h" #include "script_loadscript.h" #include "script_manager_impl.h" #include "script_registercmd.h" #include "script_updateprocesser.h" #include "script_utils.h" using namespace BasicInstruction; using namespace Updater; namespace Uscript { static std::set<std::string> g_reservedInstructions = { "LoadScript", "RegisterCmd", "abort", "assert", "concat", "is_substring", "stdout", "sleep", "set_progress", "ui_print", "show_progress", "set_proportion" }; static ScriptInstructionHelper* g_instructionHelper = nullptr; ScriptInstructionHelper* ScriptInstructionHelper::GetBasicInstructionHelper(ScriptManagerImpl *impl) { if (g_instructionHelper == nullptr) { if (impl == nullptr) { return nullptr; } g_instructionHelper = new ScriptInstructionHelper(impl); } return g_instructionHelper; } void ScriptInstructionHelper::ReleaseBasicInstructionHelper() { if (g_instructionHelper != nullptr) { delete g_instructionHelper; } g_instructionHelper = nullptr; } ScriptInstructionHelper::~ScriptInstructionHelper() { if (instrLib_ != nullptr) { dlclose(instrLib_); } instrLib_ = nullptr; } int32_t ScriptInstructionHelper::RegisterInstructions() const { scriptManager_->AddInstruction("RegisterCmder", new ScriptRegisterCmd()); scriptManager_->AddInstruction("LoadScript", new ScriptLoadScript()); scriptManager_->AddInstruction("Stdout", new UScriptInstructionStdout()); scriptManager_->AddInstruction("Abort", new UScriptInstructionAbort()); scriptManager_->AddInstruction("Assert", new UScriptInstructionAssert()); scriptManager_->AddInstruction("Sleep", new UScriptInstructionSleep()); scriptManager_->AddInstruction("Concat", new UScriptInstructionConcat()); scriptManager_->AddInstruction("IsSubString", new UScriptInstructionIsSubString()); scriptManager_->AddInstruction("set_progress", new UScriptInstructionSetProcess()); scriptManager_->AddInstruction("show_progress", new UScriptInstructionShowProcess()); scriptManager_->AddInstruction("ui_print", new UScriptInstructionUiPrint()); scriptManager_->AddInstruction("DeleteFile", new UScriptInstructionDeleteFile()); scriptManager_->AddInstruction("DeleteDir", new UScriptInstructionDeleteDir()); scriptManager_->AddInstruction("set_proportion", new UScriptInstructionSetProportion()); return USCRIPT_SUCCESS; } bool ScriptInstructionHelper::IsReservedInstruction(const std::string &scriptName) const { if (g_reservedInstructions.find(scriptName) != g_reservedInstructions.end()) { return true; } return false; } int32_t ScriptInstructionHelper::AddScript(const std::string &scriptName, int32_t priority) const { return scriptManager_->AddScript(scriptName, priority); } int32_t ScriptInstructionHelper::AddInstruction(const std::string &instrName, const UScriptInstructionPtr instr) { if (IsReservedInstruction(instrName)) { USCRIPT_LOGE(" %s reserved", instrName.c_str()); return USCRIPT_ERROR_REVERED; } return scriptManager_->AddInstruction(instrName, instr); } int32_t ScriptInstructionHelper::RegisterAddInstruction(const Uscript::UScriptInstructionFactoryPtr factory, const std::string &instrName) { UPDATER_INIT_RECORD; // Create instruction and register it UScriptInstructionPtr instr = nullptr; int32_t ret = factory->CreateInstructionInstance(instr, instrName); if (ret != USCRIPT_SUCCESS || instr == nullptr) { USCRIPT_LOGE("Fail to create instruction for %s", instrName.c_str()); UPDATER_LAST_WORD(ret); return ret == USCRIPT_SUCCESS ? USCRIPT_ERROR_CREATE_OBJ : USCRIPT_NOTEXIST_INSTRUCTION; } ret = AddInstruction(instrName, instr); if (ret != USCRIPT_SUCCESS) { USCRIPT_LOGE("Fail to add instruction for %s", instrName.c_str()); UPDATER_LAST_WORD(ret); // ret is USCRIPT_ERROR_REVERED, instr register failed, can be deleted delete instr; instr = nullptr; } // ScriptManagerImpl::AddInstruction has saved instr, don't delete it here!!! return ret; } int32_t ScriptInstructionHelper::RegisterUserInstruction(const std::string& libName, const std::string &instrName) { // first get realpath of libName, then compare with realLibName UPDATER_INIT_RECORD; char *realPath = realpath(libName.c_str(), nullptr); if (realPath == nullptr) { USCRIPT_LOGE("realPath is NULL %s", libName.c_str()); UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM); return USCRIPT_INVALID_PARAM; } std::string realLibName = realPath; free(realPath); if (!userInstrLibName_.empty() && userInstrLibName_.compare(realLibName) != 0) { USCRIPT_LOGE("Lib name must be equal %s ", realLibName.c_str()); UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM); return USCRIPT_INVALID_PARAM; } userInstrLibName_.assign(realLibName); Uscript::UScriptInstructionFactoryPtr factory = nullptr; if (instrLib_ == nullptr) { instrLib_ = dlopen(realLibName.c_str(), RTLD_LAZY | RTLD_LOCAL); } if (instrLib_ == nullptr) { USCRIPT_LOGE("Fail to dlopen %s , dlerror: %s", libName.c_str(), dlerror()); UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM); return USCRIPT_INVALID_PARAM; } auto pGetInstructionFactory = (Uscript::UScriptInstructionFactoryPtr(*)())dlsym(instrLib_, "GetInstructionFactory"); auto pReleaseInstructionFactory = (void(*)(Uscript::UScriptInstructionFactoryPtr))dlsym(instrLib_, "ReleaseInstructionFactory"); if (pReleaseInstructionFactory == nullptr || pGetInstructionFactory == nullptr) { USCRIPT_LOGE("Fail to get sym %s", libName.c_str()); UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM); return USCRIPT_INVALID_PARAM; } factory = pGetInstructionFactory(); if (factory == nullptr) { USCRIPT_LOGE("Fail to create instruction factory for %s", instrName.c_str()); UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM); return USCRIPT_INVALID_PARAM; } ON_SCOPE_EXIT(freeFactory) { pReleaseInstructionFactory(factory); }; return RegisterAddInstruction(factory, instrName); } int32_t ScriptInstructionHelper::RegisterUserInstruction(const std::string &instrName, Uscript::UScriptInstructionFactory *factory) { if (factory == nullptr) { USCRIPT_LOGE("%s factory is null", instrName.c_str()); return USCRIPT_INVALID_PARAM; } // Create instruction and register it UScriptInstructionPtr instr = nullptr; int32_t ret = factory->CreateInstructionInstance(instr, instrName); if (ret != USCRIPT_SUCCESS || instr == nullptr) { USCRIPT_LOGE("Fail to create instruction for %s", instrName.c_str()); // when instr == nullptr && ret == USCRIPT_SUCCESS, shouldn't return USCRIPT_SUCCESS return ret == USCRIPT_SUCCESS ? USCRIPT_ERROR_CREATE_OBJ : USCRIPT_NOTEXIST_INSTRUCTION; } ret = AddInstruction(instrName, instr); if (ret != USCRIPT_SUCCESS) { USCRIPT_LOGE("Fail to add instruction for %s", instrName.c_str()); delete instr; instr = nullptr; return ret; } USCRIPT_LOGD("RegisterUserInstruction %s successfull", instrName.c_str()); return ret; } } // namespace Uscript