* 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;
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, "Fail to create instruction", instrName);
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, "Fail to add instruction for ", instrName);
delete instr;
instr = nullptr;
}
return ret;
}
int32_t ScriptInstructionHelper::RegisterUserInstruction(const std::string& libName,
const std::string &instrName)
{
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("realPath is NUL", libName);
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("Lib name must be equal", realLibName);
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, "Fail to dlopen " + libName, dlerror());
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("Fail to get sym", libName);
return USCRIPT_INVALID_PARAM;
}
factory = pGetInstructionFactory();
if (factory == nullptr) {
USCRIPT_LOGE("Fail to create instruction factory for %s", instrName.c_str());
UPDATER_LAST_WORD("Fail to create instruction factory for", instrName);
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;
}
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());
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;
}
}