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 
16 #include <unistd.h>
17 #include <linux/reboot.h>
18 #include <sys/reboot.h>
19 #include <sys/syscall.h>
20 
21 #include "reboot_adp.h"
22 #include "init_cmdexecutor.h"
23 #include "init_module_engine.h"
24 #include "init_utils.h"
25 #include "plugin_adapter.h"
26 #include "securec.h"
27 
28 #define BUFF_SIZE 256
29 
DoRoot_(const char * jobName,int type)30 PLUGIN_STATIC int DoRoot_(const char *jobName, int type)
31 {
32     // by job to stop service and unmount
33     if (jobName != NULL) {
34         DoJobNow(jobName);
35     }
36 #ifndef STARTUP_INIT_TEST
37     return reboot(type);
38 #else
39     return 0;
40 #endif
41 }
42 
DoReboot(int id,const char * name,int argc,const char ** argv)43 static int DoReboot(int id, const char *name, int argc, const char **argv)
44 {
45     UNUSED(id);
46     UNUSED(name);
47     UNUSED(argc);
48     UNUSED(argv);
49     // clear misc
50     (void)UpdateMiscMessage(NULL, "reboot", NULL, NULL);
51     return DoRoot_("reboot", RB_AUTOBOOT);
52 }
53 
DoRebootPanic(int id,const char * name,int argc,const char ** argv)54 static int DoRebootPanic(int id, const char *name, int argc, const char **argv)
55 {
56     UNUSED(id);
57     char str[BUFF_SIZE] = {0};
58     int ret = sprintf_s(str, sizeof(str) - 1, "panic caused by %s:", name);
59     if (ret <= 0) {
60         PLUGIN_LOGW("DoRebootPanic sprintf_s name %s failed!", name);
61     }
62 
63     int len = ret > 0 ? (sizeof(str) - ret) : sizeof(str);
64     char *tmp = str + (sizeof(str) - len);
65     for (int i = 0; i < argc; ++i) {
66         ret = sprintf_s(tmp, len - 1, " %s", argv[i]);
67         if (ret <= 0) {
68             PLUGIN_LOGW("DoRebootPanic sprintf_s arg %s failed!", argv[i]);
69             break;
70         } else {
71             len -= ret;
72             tmp += ret;
73         }
74     }
75     PLUGIN_LOGI("DoRebootPanic %s", str);
76     if (InRescueMode() == 0) {
77         PLUGIN_LOGI("Don't panic in resuce mode!");
78         return 0;
79     }
80     // clear misc
81     (void)UpdateMiscMessage(NULL, "reboot", NULL, NULL);
82     DoJobNow("reboot");
83 #ifndef STARTUP_INIT_TEST
84     FILE *panic = fopen("/proc/sysrq-trigger", "wb");
85     if (panic == NULL) {
86         return reboot(RB_AUTOBOOT);
87     }
88     if (fwrite((void *)"c", 1, 1, panic) != 1) {
89         (void)fclose(panic);
90         PLUGIN_LOGI("fwrite to panic failed");
91         return -1;
92     }
93     (void)fclose(panic);
94 #endif
95     return 0;
96 }
97 
DoRebootShutdown(int id,const char * name,int argc,const char ** argv)98 PLUGIN_STATIC int DoRebootShutdown(int id, const char *name, int argc, const char **argv)
99 {
100     UNUSED(id);
101     UNUSED(name);
102     UNUSED(argc);
103     UNUSED(argv);
104     PLUGIN_CHECK(argc >= 1, return -1, "Invalid parameter");
105     // clear misc
106     (void)UpdateMiscMessage(NULL, "reboot", NULL, NULL);
107     const size_t len = strlen("reboot,");
108     const char *cmd = strstr(argv[0], "reboot,");
109     if (cmd != NULL && strlen(cmd) > len) {
110         PLUGIN_LOGI("DoRebootShutdown argv %s", cmd + len);
111         // by job to stop service and unmount
112         DoJobNow("reboot");
113 #ifndef STARTUP_INIT_TEST
114         return syscall(__NR_reboot,
115             LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, cmd + len);
116 #else
117         return 0;
118 #endif
119     }
120     return DoRoot_("reboot", RB_POWER_OFF);
121 }
122 
DoRebootUpdater(int id,const char * name,int argc,const char ** argv)123 static int DoRebootUpdater(int id, const char *name, int argc, const char **argv)
124 {
125     UNUSED(id);
126     PLUGIN_LOGI("DoRebootUpdater argc %d %s", argc, name);
127     PLUGIN_CHECK(argc >= 1, return -1, "Invalid parameter");
128     PLUGIN_LOGI("DoRebootUpdater argv %s", argv[0]);
129     int ret = UpdateMiscMessage(argv[0], "updater", "updater:", "boot_updater");
130     if (ret == 0) {
131         return DoRoot_("reboot", RB_AUTOBOOT);
132     }
133     return ret;
134 }
135 
DoRebootFlashed(int id,const char * name,int argc,const char ** argv)136 PLUGIN_STATIC int DoRebootFlashed(int id, const char *name, int argc, const char **argv)
137 {
138     UNUSED(id);
139     PLUGIN_LOGI("DoRebootFlashed argc %d %s", argc, name);
140     PLUGIN_CHECK(argc >= 1, return -1, "Invalid parameter");
141     PLUGIN_LOGI("DoRebootFlashd argv %s", argv[0]);
142     int ret = UpdateMiscMessage(argv[0], "flash", "flash:", "boot_flash");
143     if (ret == 0) {
144         return DoRoot_("reboot", RB_AUTOBOOT);
145     }
146     return ret;
147 }
148 
DoRebootCharge(int id,const char * name,int argc,const char ** argv)149 PLUGIN_STATIC int DoRebootCharge(int id, const char *name, int argc, const char **argv)
150 {
151     UNUSED(id);
152     UNUSED(name);
153     UNUSED(argc);
154     UNUSED(argv);
155     int ret = UpdateMiscMessage(NULL, "charge", "charge:", "boot_charge");
156     if (ret == 0) {
157         return DoRoot_("reboot", RB_AUTOBOOT);
158     }
159     return ret;
160 }
161 
DoRebootSuspend(int id,const char * name,int argc,const char ** argv)162 static int DoRebootSuspend(int id, const char *name, int argc, const char **argv)
163 {
164     UNUSED(id);
165     UNUSED(name);
166     UNUSED(argc);
167     UNUSED(argv);
168     return DoRoot_("suspend", RB_AUTOBOOT);
169 }
170 
DoRebootOther(int id,const char * name,int argc,const char ** argv)171 PLUGIN_STATIC int DoRebootOther(int id, const char *name, int argc, const char **argv)
172 {
173     UNUSED(id);
174     UNUSED(name);
175     PLUGIN_CHECK(argc >= 1, return -1, "Invalid parameter argc %d", argc);
176     const char *cmd = strstr(argv[0], "reboot,");
177     PLUGIN_CHECK(cmd != NULL, return -1, "Invalid parameter argc %s", argv[0]);
178     PLUGIN_LOGI("DoRebootOther argv %s", argv[0]);
179     DoJobNow("reboot");
180 #ifndef STARTUP_INIT_TEST
181     return syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
182         LINUX_REBOOT_CMD_RESTART2, cmd + strlen("reboot,"));
183 #else
184     return 0;
185 #endif
186 }
187 
RebootAdpInit(void)188 static void RebootAdpInit(void)
189 {
190     // add default reboot cmd
191     (void)AddCmdExecutor("reboot", DoReboot);
192     (void)AddCmdExecutor("reboot.other", DoRebootOther);
193     AddRebootCmdExecutor("shutdown", DoRebootShutdown);
194     AddRebootCmdExecutor("flashd", DoRebootFlashed);
195     AddRebootCmdExecutor("updater", DoRebootUpdater);
196     AddRebootCmdExecutor("charge", DoRebootCharge);
197     AddRebootCmdExecutor("suspend", DoRebootSuspend);
198     AddRebootCmdExecutor("panic", DoRebootPanic);
199     (void)AddCmdExecutor("panic", DoRebootPanic);
200 }
201 
MODULE_CONSTRUCTOR(void)202 MODULE_CONSTRUCTOR(void)
203 {
204     PLUGIN_LOGI("Reboot adapter plug-in init now ...");
205     RebootAdpInit();
206 }
207 
MODULE_DESTRUCTOR(void)208 MODULE_DESTRUCTOR(void)
209 {
210     PLUGIN_LOGI("Reboot adapter plug-in exit now ...");
211 }
212