1d9f0492fSopenharmony_ci/*
2d9f0492fSopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
3d9f0492fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4d9f0492fSopenharmony_ci * you may not use this file except in compliance with the License.
5d9f0492fSopenharmony_ci * You may obtain a copy of the License at
6d9f0492fSopenharmony_ci *
7d9f0492fSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8d9f0492fSopenharmony_ci *
9d9f0492fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10d9f0492fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11d9f0492fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12d9f0492fSopenharmony_ci * See the License for the specific language governing permissions and
13d9f0492fSopenharmony_ci * limitations under the License.
14d9f0492fSopenharmony_ci */
15d9f0492fSopenharmony_ci#include <errno.h>
16d9f0492fSopenharmony_ci
17d9f0492fSopenharmony_ci#include "bootstage.h"
18d9f0492fSopenharmony_ci#include "hookmgr.h"
19d9f0492fSopenharmony_ci#include "init_hook.h"
20d9f0492fSopenharmony_ci#include "init_module_engine.h"
21d9f0492fSopenharmony_ci#include "plugin_adapter.h"
22d9f0492fSopenharmony_ci#include "securec.h"
23d9f0492fSopenharmony_ci
24d9f0492fSopenharmony_ci#define REBOOT_NAME_PREFIX "reboot,"
25d9f0492fSopenharmony_ci#define REBOOT_CMD_PREFIX "reboot."
26d9f0492fSopenharmony_ci#define REBOOT_REPLACE_PREFIX "reboot."
27d9f0492fSopenharmony_ci#define PARAM_CMD_MAX 100
28d9f0492fSopenharmony_ci
29d9f0492fSopenharmony_cistatic int RebootHookWrapper(const HOOK_INFO *hookInfo, void *executionContext)
30d9f0492fSopenharmony_ci{
31d9f0492fSopenharmony_ci    RebootHookCtx *ctx = (RebootHookCtx *)executionContext;
32d9f0492fSopenharmony_ci    InitRebootHook realHook = (InitRebootHook)hookInfo->hookCookie;
33d9f0492fSopenharmony_ci    realHook(ctx);
34d9f0492fSopenharmony_ci    return 0;
35d9f0492fSopenharmony_ci};
36d9f0492fSopenharmony_ci
37d9f0492fSopenharmony_ciint InitAddRebootHook(InitRebootHook hook)
38d9f0492fSopenharmony_ci{
39d9f0492fSopenharmony_ci    HOOK_INFO info;
40d9f0492fSopenharmony_ci    info.stage = INIT_REBOOT;
41d9f0492fSopenharmony_ci    info.prio = 0;
42d9f0492fSopenharmony_ci    info.hook = RebootHookWrapper;
43d9f0492fSopenharmony_ci    info.hookCookie = (void *)hook;
44d9f0492fSopenharmony_ci    return HookMgrAddEx(GetBootStageHookMgr(), &info);
45d9f0492fSopenharmony_ci}
46d9f0492fSopenharmony_ci
47d9f0492fSopenharmony_cistatic ParamCmdInfo *g_rebootParamCmdInfos = NULL;
48d9f0492fSopenharmony_cistatic int g_rebootParamCmdMaxNumber = 0;
49d9f0492fSopenharmony_cistatic int g_rebootParamCmdValidNumber = 0;
50d9f0492fSopenharmony_cistatic char *Dup2String(const char *prefix, const char *str)
51d9f0492fSopenharmony_ci{
52d9f0492fSopenharmony_ci    if (str == NULL) {
53d9f0492fSopenharmony_ci        char *tmpstr = strdup("reboot");
54d9f0492fSopenharmony_ci        PLUGIN_CHECK(tmpstr != NULL, return NULL, "Failed to get str");
55d9f0492fSopenharmony_ci        return tmpstr;
56d9f0492fSopenharmony_ci    }
57d9f0492fSopenharmony_ci    size_t len = strlen(prefix) + strlen(str) + 1;
58d9f0492fSopenharmony_ci    char *tmp = calloc(1, len);
59d9f0492fSopenharmony_ci    PLUGIN_CHECK(tmp != NULL, return NULL, "Failed to alloc %s %s", prefix, str);
60d9f0492fSopenharmony_ci    int ret = sprintf_s(tmp, len, "%s%s", prefix, str);
61d9f0492fSopenharmony_ci    PLUGIN_CHECK(ret > 0, free(tmp);
62d9f0492fSopenharmony_ci        return NULL, "Failed to sprintf %s %s", prefix, str);
63d9f0492fSopenharmony_ci    return tmp;
64d9f0492fSopenharmony_ci}
65d9f0492fSopenharmony_ci
66d9f0492fSopenharmony_cistatic int CheckParamCmdExist(const char *cmd)
67d9f0492fSopenharmony_ci{
68d9f0492fSopenharmony_ci    if (g_rebootParamCmdInfos == NULL) {
69d9f0492fSopenharmony_ci        return 0;
70d9f0492fSopenharmony_ci    }
71d9f0492fSopenharmony_ci    char *cmdName = Dup2String(REBOOT_CMD_PREFIX, cmd);
72d9f0492fSopenharmony_ci    PLUGIN_CHECK(cmdName != NULL, return 0, "Failed to copy %s", cmd);
73d9f0492fSopenharmony_ci    for (int i = 0; i < g_rebootParamCmdValidNumber; i++) {
74d9f0492fSopenharmony_ci        if (strcmp(g_rebootParamCmdInfos[i].cmd, cmdName) == 0) {
75d9f0492fSopenharmony_ci            free(cmdName);
76d9f0492fSopenharmony_ci            return 1;
77d9f0492fSopenharmony_ci        }
78d9f0492fSopenharmony_ci    }
79d9f0492fSopenharmony_ci    free(cmdName);
80d9f0492fSopenharmony_ci    return 0;
81d9f0492fSopenharmony_ci}
82d9f0492fSopenharmony_ci
83d9f0492fSopenharmony_cistatic int SetParamCmdInfo(ParamCmdInfo *currInfo, CmdExecutor executor, const char *cmd)
84d9f0492fSopenharmony_ci{
85d9f0492fSopenharmony_ci    do {
86d9f0492fSopenharmony_ci        currInfo->name = Dup2String(REBOOT_NAME_PREFIX, cmd);
87d9f0492fSopenharmony_ci        PLUGIN_CHECK(currInfo->name != NULL, break, "Failed to copy %s", cmd);
88d9f0492fSopenharmony_ci        currInfo->replace = Dup2String(REBOOT_REPLACE_PREFIX, cmd);
89d9f0492fSopenharmony_ci        PLUGIN_CHECK(currInfo->replace != NULL, break, "Failed to copy %s", cmd);
90d9f0492fSopenharmony_ci        currInfo->cmd = Dup2String(REBOOT_CMD_PREFIX, cmd);
91d9f0492fSopenharmony_ci        PLUGIN_CHECK(currInfo->cmd != NULL, break, "Failed to copy %s", cmd);
92d9f0492fSopenharmony_ci        if (executor != NULL) {
93d9f0492fSopenharmony_ci            int cmdId = AddCmdExecutor(currInfo->cmd, executor);
94d9f0492fSopenharmony_ci            PLUGIN_CHECK(cmdId > 0, break, "Failed to add cmd %s", cmd);
95d9f0492fSopenharmony_ci        }
96d9f0492fSopenharmony_ci        PLUGIN_LOGV("SetParamCmdInfo '%s' '%s' '%s' ", currInfo->name, currInfo->cmd, currInfo->replace);
97d9f0492fSopenharmony_ci        currInfo = NULL;
98d9f0492fSopenharmony_ci        g_rebootParamCmdValidNumber++;
99d9f0492fSopenharmony_ci        return 0;
100d9f0492fSopenharmony_ci    } while (0);
101d9f0492fSopenharmony_ci    if (currInfo != NULL) {
102d9f0492fSopenharmony_ci        if (currInfo->name != NULL) {
103d9f0492fSopenharmony_ci            free(currInfo->name);
104d9f0492fSopenharmony_ci        }
105d9f0492fSopenharmony_ci        if (currInfo->cmd != NULL) {
106d9f0492fSopenharmony_ci            free(currInfo->cmd);
107d9f0492fSopenharmony_ci        }
108d9f0492fSopenharmony_ci        if (currInfo->replace != NULL) {
109d9f0492fSopenharmony_ci            free(currInfo->replace);
110d9f0492fSopenharmony_ci        }
111d9f0492fSopenharmony_ci    }
112d9f0492fSopenharmony_ci    return -1;
113d9f0492fSopenharmony_ci}
114d9f0492fSopenharmony_ci
115d9f0492fSopenharmony_cistatic int AddRebootCmdExecutor_(const char *cmd, CmdExecutor executor)
116d9f0492fSopenharmony_ci{
117d9f0492fSopenharmony_ci    PLUGIN_CHECK(g_rebootParamCmdMaxNumber <= PARAM_CMD_MAX, return -1, "Param cmd max number exceed limit");
118d9f0492fSopenharmony_ci    if (g_rebootParamCmdMaxNumber == 0 || g_rebootParamCmdMaxNumber <= g_rebootParamCmdValidNumber) {
119d9f0492fSopenharmony_ci        g_rebootParamCmdMaxNumber += 5; // inc 5 once time
120d9f0492fSopenharmony_ci        ParamCmdInfo *cmdInfos = calloc(1, sizeof(ParamCmdInfo) * g_rebootParamCmdMaxNumber);
121d9f0492fSopenharmony_ci        PLUGIN_CHECK(cmdInfos != NULL, return -1, "Failed to add reboot cmd %s", cmd);
122d9f0492fSopenharmony_ci        if (g_rebootParamCmdInfos != NULL) { // delete old
123d9f0492fSopenharmony_ci            // copy from old
124d9f0492fSopenharmony_ci            for (int i = 0; i < g_rebootParamCmdValidNumber; i++) {
125d9f0492fSopenharmony_ci                cmdInfos[i].name = g_rebootParamCmdInfos[i].name;
126d9f0492fSopenharmony_ci                cmdInfos[i].replace = g_rebootParamCmdInfos[i].replace;
127d9f0492fSopenharmony_ci                cmdInfos[i].cmd = g_rebootParamCmdInfos[i].cmd;
128d9f0492fSopenharmony_ci            }
129d9f0492fSopenharmony_ci            free(g_rebootParamCmdInfos);
130d9f0492fSopenharmony_ci        }
131d9f0492fSopenharmony_ci        g_rebootParamCmdInfos = cmdInfos;
132d9f0492fSopenharmony_ci    }
133d9f0492fSopenharmony_ci    PLUGIN_CHECK(g_rebootParamCmdValidNumber >= 0 && g_rebootParamCmdValidNumber < g_rebootParamCmdMaxNumber,
134d9f0492fSopenharmony_ci        return -1, "Param cmd number exceed limit");
135d9f0492fSopenharmony_ci    return SetParamCmdInfo(&g_rebootParamCmdInfos[g_rebootParamCmdValidNumber], executor, cmd);
136d9f0492fSopenharmony_ci}
137d9f0492fSopenharmony_ci
138d9f0492fSopenharmony_ciint AddRebootCmdExecutor(const char *cmd, CmdExecutor executor)
139d9f0492fSopenharmony_ci{
140d9f0492fSopenharmony_ci    PLUGIN_CHECK(cmd != NULL && executor != NULL, return EINVAL, "Invalid input parameter");
141d9f0492fSopenharmony_ci    int ret = CheckParamCmdExist(cmd);
142d9f0492fSopenharmony_ci    if (ret != 0) {
143d9f0492fSopenharmony_ci        PLUGIN_LOGI("Cmd %s exist", cmd);
144d9f0492fSopenharmony_ci        return EEXIST;
145d9f0492fSopenharmony_ci    }
146d9f0492fSopenharmony_ci    return AddRebootCmdExecutor_(cmd, executor);
147d9f0492fSopenharmony_ci}
148d9f0492fSopenharmony_ci
149d9f0492fSopenharmony_ciconst ParamCmdInfo *GetStartupPowerCtl(size_t *size)
150d9f0492fSopenharmony_ci{
151d9f0492fSopenharmony_ci    RebootHookCtx context;
152d9f0492fSopenharmony_ci    context.reason = "";
153d9f0492fSopenharmony_ci    (void)HookMgrExecute(GetBootStageHookMgr(), INIT_REBOOT, (void *)(&context), NULL);
154d9f0492fSopenharmony_ci    PLUGIN_LOGI("After install reboot module");
155d9f0492fSopenharmony_ci    *size = g_rebootParamCmdValidNumber;
156d9f0492fSopenharmony_ci    return g_rebootParamCmdInfos;
157d9f0492fSopenharmony_ci}
158d9f0492fSopenharmony_ci
159d9f0492fSopenharmony_cistatic void InitRebootHook_(RebootHookCtx *ctx)
160d9f0492fSopenharmony_ci{
161d9f0492fSopenharmony_ci#ifndef STARTUP_INIT_TEST // do not install
162d9f0492fSopenharmony_ci    ModuleMgrScan("init/reboot");
163d9f0492fSopenharmony_ci#endif
164d9f0492fSopenharmony_ci    PLUGIN_LOGI("Install rebootmodule.");
165d9f0492fSopenharmony_ci}
166d9f0492fSopenharmony_ci
167d9f0492fSopenharmony_ciMODULE_CONSTRUCTOR(void)
168d9f0492fSopenharmony_ci{
169d9f0492fSopenharmony_ci    // 执行reboot时调用,安装reboot模块
170d9f0492fSopenharmony_ci    InitAddRebootHook(InitRebootHook_);
171d9f0492fSopenharmony_ci}
172d9f0492fSopenharmony_ci
173d9f0492fSopenharmony_ciMODULE_DESTRUCTOR(void)
174d9f0492fSopenharmony_ci{
175d9f0492fSopenharmony_ci    for (int i = 0; i < g_rebootParamCmdValidNumber; i++) {
176d9f0492fSopenharmony_ci        if (g_rebootParamCmdInfos[i].name != NULL) {
177d9f0492fSopenharmony_ci            free(g_rebootParamCmdInfos[i].name);
178d9f0492fSopenharmony_ci        }
179d9f0492fSopenharmony_ci        if (g_rebootParamCmdInfos[i].replace != NULL) {
180d9f0492fSopenharmony_ci            free(g_rebootParamCmdInfos[i].replace);
181d9f0492fSopenharmony_ci        }
182d9f0492fSopenharmony_ci        if (g_rebootParamCmdInfos[i].cmd != NULL) {
183d9f0492fSopenharmony_ci            free(g_rebootParamCmdInfos[i].cmd);
184d9f0492fSopenharmony_ci        }
185d9f0492fSopenharmony_ci    }
186d9f0492fSopenharmony_ci    free(g_rebootParamCmdInfos);
187d9f0492fSopenharmony_ci    g_rebootParamCmdInfos = NULL;
188d9f0492fSopenharmony_ci}