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 "script_instructionhelper.h" 16#include <dlfcn.h> 17#include <set> 18#include "dump.h" 19#include "scope_guard.h" 20#include "script_basicinstruction.h" 21#include "script_loadscript.h" 22#include "script_manager_impl.h" 23#include "script_registercmd.h" 24#include "script_updateprocesser.h" 25#include "script_utils.h" 26 27using namespace BasicInstruction; 28using namespace Updater; 29 30namespace Uscript { 31static std::set<std::string> g_reservedInstructions = { 32 "LoadScript", "RegisterCmd", "abort", "assert", "concat", 33 "is_substring", "stdout", "sleep", "set_progress", "ui_print", 34 "show_progress", "set_proportion" 35 }; 36 37static ScriptInstructionHelper* g_instructionHelper = nullptr; 38 39ScriptInstructionHelper* ScriptInstructionHelper::GetBasicInstructionHelper(ScriptManagerImpl *impl) 40{ 41 if (g_instructionHelper == nullptr) { 42 if (impl == nullptr) { 43 return nullptr; 44 } 45 g_instructionHelper = new ScriptInstructionHelper(impl); 46 } 47 return g_instructionHelper; 48} 49 50void ScriptInstructionHelper::ReleaseBasicInstructionHelper() 51{ 52 if (g_instructionHelper != nullptr) { 53 delete g_instructionHelper; 54 } 55 g_instructionHelper = nullptr; 56} 57 58ScriptInstructionHelper::~ScriptInstructionHelper() 59{ 60 if (instrLib_ != nullptr) { 61 dlclose(instrLib_); 62 } 63 instrLib_ = nullptr; 64} 65 66int32_t ScriptInstructionHelper::RegisterInstructions() const 67{ 68 scriptManager_->AddInstruction("RegisterCmder", new ScriptRegisterCmd()); 69 scriptManager_->AddInstruction("LoadScript", new ScriptLoadScript()); 70 scriptManager_->AddInstruction("Stdout", new UScriptInstructionStdout()); 71 scriptManager_->AddInstruction("Abort", new UScriptInstructionAbort()); 72 scriptManager_->AddInstruction("Assert", new UScriptInstructionAssert()); 73 scriptManager_->AddInstruction("Sleep", new UScriptInstructionSleep()); 74 scriptManager_->AddInstruction("Concat", new UScriptInstructionConcat()); 75 scriptManager_->AddInstruction("IsSubString", new UScriptInstructionIsSubString()); 76 scriptManager_->AddInstruction("set_progress", new UScriptInstructionSetProcess()); 77 scriptManager_->AddInstruction("show_progress", new UScriptInstructionShowProcess()); 78 scriptManager_->AddInstruction("ui_print", new UScriptInstructionUiPrint()); 79 scriptManager_->AddInstruction("DeleteFile", new UScriptInstructionDeleteFile()); 80 scriptManager_->AddInstruction("DeleteDir", new UScriptInstructionDeleteDir()); 81 scriptManager_->AddInstruction("set_proportion", new UScriptInstructionSetProportion()); 82 return USCRIPT_SUCCESS; 83} 84 85bool ScriptInstructionHelper::IsReservedInstruction(const std::string &scriptName) const 86{ 87 if (g_reservedInstructions.find(scriptName) != g_reservedInstructions.end()) { 88 return true; 89 } 90 return false; 91} 92 93int32_t ScriptInstructionHelper::AddScript(const std::string &scriptName, int32_t priority) const 94{ 95 return scriptManager_->AddScript(scriptName, priority); 96} 97 98int32_t ScriptInstructionHelper::AddInstruction(const std::string &instrName, const UScriptInstructionPtr instr) 99{ 100 if (IsReservedInstruction(instrName)) { 101 USCRIPT_LOGE(" %s reserved", instrName.c_str()); 102 return USCRIPT_ERROR_REVERED; 103 } 104 return scriptManager_->AddInstruction(instrName, instr); 105} 106 107int32_t ScriptInstructionHelper::RegisterAddInstruction(const Uscript::UScriptInstructionFactoryPtr factory, 108 const std::string &instrName) 109{ 110 UPDATER_INIT_RECORD; 111 // Create instruction and register it 112 UScriptInstructionPtr instr = nullptr; 113 int32_t ret = factory->CreateInstructionInstance(instr, instrName); 114 if (ret != USCRIPT_SUCCESS || instr == nullptr) { 115 USCRIPT_LOGE("Fail to create instruction for %s", instrName.c_str()); 116 UPDATER_LAST_WORD(ret); 117 return ret == USCRIPT_SUCCESS ? USCRIPT_ERROR_CREATE_OBJ : USCRIPT_NOTEXIST_INSTRUCTION; 118 } 119 120 ret = AddInstruction(instrName, instr); 121 if (ret != USCRIPT_SUCCESS) { 122 USCRIPT_LOGE("Fail to add instruction for %s", instrName.c_str()); 123 UPDATER_LAST_WORD(ret); 124 // ret is USCRIPT_ERROR_REVERED, instr register failed, can be deleted 125 delete instr; 126 instr = nullptr; 127 } 128 // ScriptManagerImpl::AddInstruction has saved instr, don't delete it here!!! 129 return ret; 130} 131 132int32_t ScriptInstructionHelper::RegisterUserInstruction(const std::string& libName, 133 const std::string &instrName) 134{ 135 // first get realpath of libName, then compare with realLibName 136 UPDATER_INIT_RECORD; 137 char *realPath = realpath(libName.c_str(), nullptr); 138 if (realPath == nullptr) { 139 USCRIPT_LOGE("realPath is NULL %s", libName.c_str()); 140 UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM); 141 return USCRIPT_INVALID_PARAM; 142 } 143 std::string realLibName = realPath; 144 free(realPath); 145 if (!userInstrLibName_.empty() && userInstrLibName_.compare(realLibName) != 0) { 146 USCRIPT_LOGE("Lib name must be equal %s ", realLibName.c_str()); 147 UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM); 148 return USCRIPT_INVALID_PARAM; 149 } 150 151 userInstrLibName_.assign(realLibName); 152 Uscript::UScriptInstructionFactoryPtr factory = nullptr; 153 if (instrLib_ == nullptr) { 154 instrLib_ = dlopen(realLibName.c_str(), RTLD_LAZY | RTLD_LOCAL); 155 } 156 if (instrLib_ == nullptr) { 157 USCRIPT_LOGE("Fail to dlopen %s , dlerror: %s", libName.c_str(), dlerror()); 158 UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM); 159 return USCRIPT_INVALID_PARAM; 160 } 161 auto pGetInstructionFactory = 162 (Uscript::UScriptInstructionFactoryPtr(*)())dlsym(instrLib_, "GetInstructionFactory"); 163 auto pReleaseInstructionFactory = 164 (void(*)(Uscript::UScriptInstructionFactoryPtr))dlsym(instrLib_, "ReleaseInstructionFactory"); 165 if (pReleaseInstructionFactory == nullptr || pGetInstructionFactory == nullptr) { 166 USCRIPT_LOGE("Fail to get sym %s", libName.c_str()); 167 UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM); 168 return USCRIPT_INVALID_PARAM; 169 } 170 factory = pGetInstructionFactory(); 171 if (factory == nullptr) { 172 USCRIPT_LOGE("Fail to create instruction factory for %s", instrName.c_str()); 173 UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM); 174 return USCRIPT_INVALID_PARAM; 175 } 176 ON_SCOPE_EXIT(freeFactory) { 177 pReleaseInstructionFactory(factory); 178 }; 179 180 return RegisterAddInstruction(factory, instrName); 181} 182 183int32_t ScriptInstructionHelper::RegisterUserInstruction(const std::string &instrName, 184 Uscript::UScriptInstructionFactory *factory) 185{ 186 if (factory == nullptr) { 187 USCRIPT_LOGE("%s factory is null", instrName.c_str()); 188 return USCRIPT_INVALID_PARAM; 189 } 190 191 // Create instruction and register it 192 UScriptInstructionPtr instr = nullptr; 193 int32_t ret = factory->CreateInstructionInstance(instr, instrName); 194 if (ret != USCRIPT_SUCCESS || instr == nullptr) { 195 USCRIPT_LOGE("Fail to create instruction for %s", instrName.c_str()); 196 // when instr == nullptr && ret == USCRIPT_SUCCESS, shouldn't return USCRIPT_SUCCESS 197 return ret == USCRIPT_SUCCESS ? USCRIPT_ERROR_CREATE_OBJ : USCRIPT_NOTEXIST_INSTRUCTION; 198 } 199 200 ret = AddInstruction(instrName, instr); 201 if (ret != USCRIPT_SUCCESS) { 202 USCRIPT_LOGE("Fail to add instruction for %s", instrName.c_str()); 203 delete instr; 204 instr = nullptr; 205 return ret; 206 } 207 208 USCRIPT_LOGD("RegisterUserInstruction %s successfull", instrName.c_str()); 209 return ret; 210} 211} // namespace Uscript 212