1 /*
2 * Copyright (c) 2021 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 #include <limits.h>
17 #include <stdlib.h>
18 #include <sys/mount.h>
19 #include <sys/reboot.h>
20
21 #include "fs_manager/fs_manager.h"
22 #include "init_log.h"
23 #include "init_jobs_internal.h"
24 #include "init_group_manager.h"
25 #include "init_service.h"
26 #include "init_service_manager.h"
27 #include "init_utils.h"
28 #include "securec.h"
29
30 #ifdef PRODUCT_RK
31 #include <sys/syscall.h>
32
33 #define REBOOT_MAGIC1 0xfee1dead
34 #define REBOOT_MAGIC2 672274793
35 #define REBOOT_CMD_RESTART2 0xA1B2C3D4
36 #endif
37
38 #define MAX_VALUE_LENGTH 500
39 #define MAX_COMMAND_SIZE 20
40 #define MAX_UPDATE_SIZE 100
41
42 struct RBMiscUpdateMessage {
43 char command[MAX_COMMAND_SIZE];
44 char update[MAX_UPDATE_SIZE];
45 };
46
RBMiscWriteUpdaterMessage(const char * path,const struct RBMiscUpdateMessage * boot)47 static int RBMiscWriteUpdaterMessage(const char *path, const struct RBMiscUpdateMessage *boot)
48 {
49 char *realPath = GetRealPath(path);
50 INIT_CHECK_RETURN_VALUE(realPath != NULL, -1);
51 int ret = 0;
52 FILE *fp = fopen(realPath, "rb+");
53 free(realPath);
54 realPath = NULL;
55 if (fp != NULL) {
56 size_t writeLen = fwrite(boot, sizeof(struct RBMiscUpdateMessage), 1, fp);
57 INIT_ERROR_CHECK(writeLen == 1, ret = -1, "Failed to write misc for reboot");
58 (void)fclose(fp);
59 } else {
60 ret = -1;
61 INIT_LOGE("Failed to open %s", path);
62 }
63 return ret;
64 }
65
RBMiscReadUpdaterMessage(const char * path,struct RBMiscUpdateMessage * boot)66 static int RBMiscReadUpdaterMessage(const char *path, struct RBMiscUpdateMessage *boot)
67 {
68 int ret = 0;
69 FILE *fp = NULL;
70 char *realPath = GetRealPath(path);
71 if (realPath != NULL) {
72 fp = fopen(realPath, "rb");
73 free(realPath);
74 realPath = NULL;
75 } else {
76 fp = fopen(path, "rb");
77 }
78 if (fp != NULL) {
79 size_t readLen = fread(boot, 1, sizeof(struct RBMiscUpdateMessage), fp);
80 (void)fclose(fp);
81 INIT_ERROR_CHECK(readLen > 0, ret = -1, "Failed to read misc for reboot");
82 } else {
83 ret = -1;
84 INIT_LOGE("Failed to open %s errno %d", path, errno);
85 }
86 return ret;
87 }
88
GetBootModeFromMisc(void)89 int GetBootModeFromMisc(void)
90 {
91 char miscFile[PATH_MAX] = {0};
92 int ret = GetBlockDevicePath("/misc", miscFile, PATH_MAX);
93 INIT_ERROR_CHECK(ret == 0, return -1, "Failed to get misc path");
94 struct RBMiscUpdateMessage msg;
95 ret = RBMiscReadUpdaterMessage(miscFile, &msg);
96 INIT_ERROR_CHECK(ret == 0, return -1, "Failed to get misc info");
97 if (memcmp(msg.command, "boot_charing", strlen("boot_charing")) == 0) {
98 return GROUP_CHARING;
99 }
100 return 0;
101 }
102
CheckAndRebootToUpdater(const char * valueData,const char * cmd,const char * cmdExt,const char * boot)103 static int CheckAndRebootToUpdater(const char *valueData, const char *cmd,
104 const char *cmdExt, const char *boot)
105 {
106 char miscFile[PATH_MAX] = {0};
107 int ret = GetBlockDevicePath("/misc", miscFile, PATH_MAX);
108 INIT_ERROR_CHECK(ret == 0, return -1, "Failed to get misc path for %s.", valueData);
109
110 // "updater" or "updater:"
111 struct RBMiscUpdateMessage msg;
112 ret = RBMiscReadUpdaterMessage(miscFile, &msg);
113 INIT_ERROR_CHECK(ret == 0, return -1, "Failed to get misc info for %s.", cmd);
114
115 if (boot != NULL) {
116 ret = snprintf_s(msg.command, MAX_COMMAND_SIZE, MAX_COMMAND_SIZE - 1, "%s", boot);
117 INIT_ERROR_CHECK(ret > 0, return -1, "Failed to format cmd for %s.", cmd);
118 msg.command[MAX_COMMAND_SIZE - 1] = 0;
119 } else {
120 ret = memset_s(msg.command, MAX_COMMAND_SIZE, 0, MAX_COMMAND_SIZE);
121 INIT_ERROR_CHECK(ret == 0, return -1, "Failed to format cmd for %s.", cmd);
122 }
123
124 if ((cmdExt != NULL) && (valueData != NULL) && (strncmp(valueData, cmdExt, strlen(cmdExt)) == 0)) {
125 const char *p = valueData + strlen(cmdExt);
126 ret = snprintf_s(msg.update, MAX_UPDATE_SIZE, MAX_UPDATE_SIZE - 1, "%s", p);
127 INIT_ERROR_CHECK(ret > 0, return -1, "Failed to format param for %s.", cmd);
128 msg.update[MAX_UPDATE_SIZE - 1] = 0;
129 } else {
130 ret = memset_s(msg.update, MAX_UPDATE_SIZE, 0, MAX_UPDATE_SIZE);
131 INIT_ERROR_CHECK(ret == 0, return -1, "Failed to format update for %s.", cmd);
132 }
133
134 if (RBMiscWriteUpdaterMessage(miscFile, &msg) == 0) {
135 return 0;
136 }
137 return -1;
138 }
139
DoRebootCmd(const char * cmd,const char * opt)140 static int DoRebootCmd(const char *cmd, const char *opt)
141 {
142 // by job to stop service and unmount
143 DoJobNow("reboot");
144 int ret = CheckAndRebootToUpdater(NULL, "reboot", NULL, NULL);
145 if (ret == 0) {
146 #ifndef STARTUP_INIT_TEST
147 return reboot(RB_AUTOBOOT);
148 #endif
149 }
150 return 0;
151 }
152
DoShutdownCmd(const char * cmd,const char * opt)153 static int DoShutdownCmd(const char *cmd, const char *opt)
154 {
155 // by job to stop service and unmount
156 DoJobNow("reboot");
157 int ret = CheckAndRebootToUpdater(NULL, "reboot", NULL, NULL);
158 if (ret == 0) {
159 #ifndef STARTUP_INIT_TEST
160 return reboot(RB_POWER_OFF);
161 #endif
162 }
163 return 0;
164 }
165
DoUpdaterCmd(const char * cmd,const char * opt)166 static int DoUpdaterCmd(const char *cmd, const char *opt)
167 {
168 // by job to stop service and unmount
169 DoJobNow("reboot");
170 int ret = CheckAndRebootToUpdater(opt, "updater", "updater:", "boot_updater");
171 if (ret == 0) {
172 #ifndef STARTUP_INIT_TEST
173 return reboot(RB_AUTOBOOT);
174 #endif
175 }
176 return 0;
177 }
178
DoFlashdCmd(const char * cmd,const char * opt)179 static int DoFlashdCmd(const char *cmd, const char *opt)
180 {
181 // by job to stop service and unmount
182 DoJobNow("reboot");
183 int ret = CheckAndRebootToUpdater(opt, "flash", "flash:", "boot_flash");
184 if (ret == 0) {
185 #ifndef STARTUP_INIT_TEST
186 return reboot(RB_AUTOBOOT);
187 #endif
188 }
189 return 0;
190 }
191
192 #ifdef PRODUCT_RK
DoLoaderCmd(const char * cmd,const char * opt)193 static int DoLoaderCmd(const char *cmd, const char *opt)
194 {
195 syscall(__NR_reboot, REBOOT_MAGIC1, REBOOT_MAGIC2, REBOOT_CMD_RESTART2, "loader");
196 return 0;
197 }
198 #endif
199
DoSuspendCmd(const char * cmd,const char * opt)200 static int DoSuspendCmd(const char *cmd, const char *opt)
201 {
202 // by job to stop service and unmount
203 DoJobNow("suspend");
204 int ret = CheckAndRebootToUpdater(NULL, "reboot", NULL, NULL);
205 if (ret == 0) {
206 #ifndef STARTUP_INIT_TEST
207 INIT_LOGE("DoSuspendCmd %s RB_SW_SUSPEND.", cmd);
208 return reboot(RB_AUTOBOOT);
209 #endif
210 }
211 return 0;
212 }
213
214 #ifdef INIT_TEST
DoCharingCmd()215 static int DoCharingCmd()
216 {
217 // by job to stop service and unmount
218 DoJobNow("reboot");
219 int ret = CheckAndRebootToUpdater(NULL, "charing", "charing:", "boot_charing");
220 if (ret == 0) {
221 #ifndef STARTUP_INIT_TEST
222 return reboot(RB_AUTOBOOT);
223 #endif
224 }
225 return 0;
226 }
227 #endif
228
229 struct {
230 char *cmdName;
231 int (*doCmd)(const char *cmd, const char *opt);
232 } g_rebootCmd[] = {
233 { "reboot", DoRebootCmd },
234 { "shutdown", DoShutdownCmd },
235 { "bootloader", DoShutdownCmd },
236 { "updater", DoUpdaterCmd },
237 { "flashd", DoFlashdCmd },
238 #ifdef PRODUCT_RK
239 { "loader", DoLoaderCmd },
240 #endif
241 { "suspend", DoSuspendCmd },
242 #ifdef INIT_TEST
243 { "charing", DoCharingCmd }
244 #endif
245 };
246
ExecReboot(const char * value)247 void ExecReboot(const char *value)
248 {
249 INIT_ERROR_CHECK(value != NULL && strlen(value) <= MAX_VALUE_LENGTH, return, "Invalid arg");
250 char *cmd = NULL;
251 if (strcmp(value, "reboot") == 0) {
252 cmd = "reboot";
253 } else if (strncmp(value, "reboot,", strlen("reboot,")) == 0) {
254 cmd = (char *)(value + strlen("reboot,"));
255 } else {
256 INIT_LOGE("Invalid rebot cmd %s.", value);
257 return;
258 }
259
260 INIT_LOGI("ExecReboot %s param %s.", cmd, value);
261 for (int i = 0; i < (int)ARRAY_LENGTH(g_rebootCmd); i++) {
262 if (strncmp(cmd, g_rebootCmd[i].cmdName, strlen(g_rebootCmd[i].cmdName)) == 0) {
263 int ret = g_rebootCmd[i].doCmd(cmd, cmd);
264 INIT_LOGI("Reboot %s %s errno %d .", cmd, (ret == 0) ? "success" : "fail", errno);
265 return;
266 }
267 }
268 INIT_LOGE("Invalid reboot cmd %s.", value);
269 return;
270 }
271