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