• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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