1 /*
2  * Copyright (c) 2022 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 <errno.h>
16 
17 #include "bootstage.h"
18 #include "hookmgr.h"
19 #include "init_hook.h"
20 #include "init_module_engine.h"
21 #include "plugin_adapter.h"
22 #include "securec.h"
23 
24 #define REBOOT_NAME_PREFIX "reboot,"
25 #define REBOOT_CMD_PREFIX "reboot."
26 #define REBOOT_REPLACE_PREFIX "reboot."
27 #define PARAM_CMD_MAX 100
28 
RebootHookWrapper(const HOOK_INFO * hookInfo,void * executionContext)29 static int RebootHookWrapper(const HOOK_INFO *hookInfo, void *executionContext)
30 {
31     RebootHookCtx *ctx = (RebootHookCtx *)executionContext;
32     InitRebootHook realHook = (InitRebootHook)hookInfo->hookCookie;
33     realHook(ctx);
34     return 0;
35 };
36 
InitAddRebootHook(InitRebootHook hook)37 int InitAddRebootHook(InitRebootHook hook)
38 {
39     HOOK_INFO info;
40     info.stage = INIT_REBOOT;
41     info.prio = 0;
42     info.hook = RebootHookWrapper;
43     info.hookCookie = (void *)hook;
44     return HookMgrAddEx(GetBootStageHookMgr(), &info);
45 }
46 
47 static ParamCmdInfo *g_rebootParamCmdInfos = NULL;
48 static int g_rebootParamCmdMaxNumber = 0;
49 static int g_rebootParamCmdValidNumber = 0;
Dup2String(const char * prefix,const char * str)50 static char *Dup2String(const char *prefix, const char *str)
51 {
52     if (str == NULL) {
53         char *tmpstr = strdup("reboot");
54         PLUGIN_CHECK(tmpstr != NULL, return NULL, "Failed to get str");
55         return tmpstr;
56     }
57     size_t len = strlen(prefix) + strlen(str) + 1;
58     char *tmp = calloc(1, len);
59     PLUGIN_CHECK(tmp != NULL, return NULL, "Failed to alloc %s %s", prefix, str);
60     int ret = sprintf_s(tmp, len, "%s%s", prefix, str);
61     PLUGIN_CHECK(ret > 0, free(tmp);
62         return NULL, "Failed to sprintf %s %s", prefix, str);
63     return tmp;
64 }
65 
CheckParamCmdExist(const char * cmd)66 static int CheckParamCmdExist(const char *cmd)
67 {
68     if (g_rebootParamCmdInfos == NULL) {
69         return 0;
70     }
71     char *cmdName = Dup2String(REBOOT_CMD_PREFIX, cmd);
72     PLUGIN_CHECK(cmdName != NULL, return 0, "Failed to copy %s", cmd);
73     for (int i = 0; i < g_rebootParamCmdValidNumber; i++) {
74         if (strcmp(g_rebootParamCmdInfos[i].cmd, cmdName) == 0) {
75             free(cmdName);
76             return 1;
77         }
78     }
79     free(cmdName);
80     return 0;
81 }
82 
SetParamCmdInfo(ParamCmdInfo * currInfo,CmdExecutor executor,const char * cmd)83 static int SetParamCmdInfo(ParamCmdInfo *currInfo, CmdExecutor executor, const char *cmd)
84 {
85     do {
86         currInfo->name = Dup2String(REBOOT_NAME_PREFIX, cmd);
87         PLUGIN_CHECK(currInfo->name != NULL, break, "Failed to copy %s", cmd);
88         currInfo->replace = Dup2String(REBOOT_REPLACE_PREFIX, cmd);
89         PLUGIN_CHECK(currInfo->replace != NULL, break, "Failed to copy %s", cmd);
90         currInfo->cmd = Dup2String(REBOOT_CMD_PREFIX, cmd);
91         PLUGIN_CHECK(currInfo->cmd != NULL, break, "Failed to copy %s", cmd);
92         if (executor != NULL) {
93             int cmdId = AddCmdExecutor(currInfo->cmd, executor);
94             PLUGIN_CHECK(cmdId > 0, break, "Failed to add cmd %s", cmd);
95         }
96         PLUGIN_LOGV("SetParamCmdInfo '%s' '%s' '%s' ", currInfo->name, currInfo->cmd, currInfo->replace);
97         currInfo = NULL;
98         g_rebootParamCmdValidNumber++;
99         return 0;
100     } while (0);
101     if (currInfo != NULL) {
102         if (currInfo->name != NULL) {
103             free(currInfo->name);
104         }
105         if (currInfo->cmd != NULL) {
106             free(currInfo->cmd);
107         }
108         if (currInfo->replace != NULL) {
109             free(currInfo->replace);
110         }
111     }
112     return -1;
113 }
114 
AddRebootCmdExecutor_(const char * cmd,CmdExecutor executor)115 static int AddRebootCmdExecutor_(const char *cmd, CmdExecutor executor)
116 {
117     PLUGIN_CHECK(g_rebootParamCmdMaxNumber <= PARAM_CMD_MAX, return -1, "Param cmd max number exceed limit");
118     if (g_rebootParamCmdMaxNumber == 0 || g_rebootParamCmdMaxNumber <= g_rebootParamCmdValidNumber) {
119         g_rebootParamCmdMaxNumber += 5; // inc 5 once time
120         ParamCmdInfo *cmdInfos = calloc(1, sizeof(ParamCmdInfo) * g_rebootParamCmdMaxNumber);
121         PLUGIN_CHECK(cmdInfos != NULL, return -1, "Failed to add reboot cmd %s", cmd);
122         if (g_rebootParamCmdInfos != NULL) { // delete old
123             // copy from old
124             for (int i = 0; i < g_rebootParamCmdValidNumber; i++) {
125                 cmdInfos[i].name = g_rebootParamCmdInfos[i].name;
126                 cmdInfos[i].replace = g_rebootParamCmdInfos[i].replace;
127                 cmdInfos[i].cmd = g_rebootParamCmdInfos[i].cmd;
128             }
129             free(g_rebootParamCmdInfos);
130         }
131         g_rebootParamCmdInfos = cmdInfos;
132     }
133     PLUGIN_CHECK(g_rebootParamCmdValidNumber >= 0 && g_rebootParamCmdValidNumber < g_rebootParamCmdMaxNumber,
134         return -1, "Param cmd number exceed limit");
135     return SetParamCmdInfo(&g_rebootParamCmdInfos[g_rebootParamCmdValidNumber], executor, cmd);
136 }
137 
AddRebootCmdExecutor(const char * cmd,CmdExecutor executor)138 int AddRebootCmdExecutor(const char *cmd, CmdExecutor executor)
139 {
140     PLUGIN_CHECK(cmd != NULL && executor != NULL, return EINVAL, "Invalid input parameter");
141     int ret = CheckParamCmdExist(cmd);
142     if (ret != 0) {
143         PLUGIN_LOGI("Cmd %s exist", cmd);
144         return EEXIST;
145     }
146     return AddRebootCmdExecutor_(cmd, executor);
147 }
148 
GetStartupPowerCtl(size_t * size)149 const ParamCmdInfo *GetStartupPowerCtl(size_t *size)
150 {
151     RebootHookCtx context;
152     context.reason = "";
153     (void)HookMgrExecute(GetBootStageHookMgr(), INIT_REBOOT, (void *)(&context), NULL);
154     PLUGIN_LOGI("After install reboot module");
155     *size = g_rebootParamCmdValidNumber;
156     return g_rebootParamCmdInfos;
157 }
158 
InitRebootHook_(RebootHookCtx * ctx)159 static void InitRebootHook_(RebootHookCtx *ctx)
160 {
161 #ifndef STARTUP_INIT_TEST // do not install
162     ModuleMgrScan("init/reboot");
163 #endif
164     PLUGIN_LOGI("Install rebootmodule.");
165 }
166 
MODULE_CONSTRUCTOR(void)167 MODULE_CONSTRUCTOR(void)
168 {
169     // 执行reboot时调用,安装reboot模块
170     InitAddRebootHook(InitRebootHook_);
171 }
172 
MODULE_DESTRUCTOR(void)173 MODULE_DESTRUCTOR(void)
174 {
175     for (int i = 0; i < g_rebootParamCmdValidNumber; i++) {
176         if (g_rebootParamCmdInfos[i].name != NULL) {
177             free(g_rebootParamCmdInfos[i].name);
178         }
179         if (g_rebootParamCmdInfos[i].replace != NULL) {
180             free(g_rebootParamCmdInfos[i].replace);
181         }
182         if (g_rebootParamCmdInfos[i].cmd != NULL) {
183             free(g_rebootParamCmdInfos[i].cmd);
184         }
185     }
186     free(g_rebootParamCmdInfos);
187     g_rebootParamCmdInfos = NULL;
188 }