1 /*
2 * Copyright (c) 2021-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 "init.h"
16
17 #include <errno.h>
18 #include <poll.h>
19 #include <stdarg.h>
20 #include <stdlib.h>
21 #include <signal.h>
22 #include <time.h>
23 #include <sys/sysmacros.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <linux/major.h>
28
29 #include "config_policy_utils.h"
30 #include "device.h"
31 #include "fd_holder_service.h"
32 #include "fs_manager/fs_manager.h"
33 #include "key_control.h"
34 #include "init_control_fd_service.h"
35 #include "init_log.h"
36 #include "init_mount.h"
37 #include "init_group_manager.h"
38 #include "init_param.h"
39 #include "init_service.h"
40 #include "init_service_manager.h"
41 #include "init_utils.h"
42 #include "securec.h"
43 #include "switch_root.h"
44 #include "ueventd.h"
45 #include "ueventd_socket.h"
46 #include "fd_holder_internal.h"
47 #include "bootstage.h"
48
FdHolderSockInit(void)49 static int FdHolderSockInit(void)
50 {
51 int sock = -1;
52 int on = 1;
53 int fdHolderBufferSize = FD_HOLDER_BUFFER_SIZE; // 4KiB
54 sock = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
55 if (sock < 0) {
56 INIT_LOGE("Failed to create fd holder socket, err = %d", errno);
57 return -1;
58 }
59
60 setsockopt(sock, SOL_SOCKET, SO_RCVBUFFORCE, &fdHolderBufferSize, sizeof(fdHolderBufferSize));
61 setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
62
63 if (access(INIT_HOLDER_SOCKET_PATH, F_OK) == 0) {
64 INIT_LOGI("%s exist, remove it", INIT_HOLDER_SOCKET_PATH);
65 unlink(INIT_HOLDER_SOCKET_PATH);
66 }
67 struct sockaddr_un addr;
68 addr.sun_family = AF_UNIX;
69 if (strncpy_s(addr.sun_path, sizeof(addr.sun_path),
70 INIT_HOLDER_SOCKET_PATH, strlen(INIT_HOLDER_SOCKET_PATH)) != 0) {
71 INIT_LOGE("Failed to copy fd hoder socket path");
72 close(sock);
73 return -1;
74 }
75 socklen_t len = (socklen_t)(offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path) + 1);
76 if (bind(sock, (struct sockaddr *)&addr, len) < 0) {
77 INIT_LOGE("Failed to binder fd folder socket %d", errno);
78 close(sock);
79 return -1;
80 }
81
82 // Owned by root
83 if (lchown(addr.sun_path, 0, 0)) {
84 INIT_LOGW("Failed to change owner of fd holder socket, err = %d", errno);
85 }
86 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
87 if (fchmodat(AT_FDCWD, addr.sun_path, mode, AT_SYMLINK_NOFOLLOW)) {
88 INIT_LOGW("Failed to change mode of fd holder socket, err = %d", errno);
89 }
90 INIT_LOGI("Init fd holder socket done");
91 return sock;
92 }
93
SystemInit(void)94 void SystemInit(void)
95 {
96 CloseStdio();
97 #ifndef STARTUP_INIT_TEST
98 // Set up a session keyring that all processes will have access to.
99 KeyCtrlGetKeyringId(KEY_SPEC_SESSION_KEYRING, 1);
100 #endif
101 // umask call always succeeds and return the previous mask value which is not needed here
102 (void)umask(DEFAULT_UMASK_INIT);
103 MakeDirRecursive("/dev/unix/socket", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
104 int sock = FdHolderSockInit();
105 if (sock >= 0) {
106 RegisterFdHoldWatcher(sock);
107 }
108 InitControlFd();
109 }
110
EnableDevKmsg(void)111 static void EnableDevKmsg(void)
112 {
113 /* printk_devkmsg default value is ratelimit, We need to set "on" and remove the restrictions */
114 int fd = open("/proc/sys/kernel/printk_devkmsg", O_WRONLY | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
115 if (fd < 0) {
116 return;
117 }
118 char *kmsgStatus = "on";
119 write(fd, kmsgStatus, strlen(kmsgStatus) + 1);
120 close(fd);
121 return;
122 }
123
LogInit(void)124 void LogInit(void)
125 {
126 int ret = mknod("/dev/kmsg", S_IFCHR | S_IWUSR | S_IRUSR,
127 makedev(MEM_MAJOR, DEV_KMSG_MINOR));
128 if (ret == 0) {
129 OpenLogDevice();
130 }
131 }
132
GetRequiredDevices(Fstab fstab,int * requiredNum)133 static char **GetRequiredDevices(Fstab fstab, int *requiredNum)
134 {
135 int num = 0;
136 FstabItem *item = fstab.head;
137 while (item != NULL) {
138 if (FM_MANAGER_REQUIRED_ENABLED(item->fsManagerFlags)) {
139 num++;
140 }
141 item = item->next;
142 }
143 if (num == 0) {
144 return NULL;
145 }
146 char **devices = (char **)calloc(num, sizeof(char *));
147 INIT_ERROR_CHECK(devices != NULL, return NULL, "Failed calloc err=%d", errno);
148
149 int i = 0;
150 item = fstab.head;
151 while (item != NULL) {
152 if (FM_MANAGER_REQUIRED_ENABLED(item->fsManagerFlags)) {
153 devices[i] = strdup(item->deviceName);
154 INIT_ERROR_CHECK(devices[i] != NULL, FreeStringVector(devices, num); return NULL,
155 "Failed strdup err=%d", errno);
156 i++;
157 }
158 item = item->next;
159 }
160 *requiredNum = num;
161 return devices;
162 }
163
StartUeventd(char ** requiredDevices,int num)164 static int StartUeventd(char **requiredDevices, int num)
165 {
166 INIT_ERROR_CHECK(requiredDevices != NULL && num > 0, return -1, "Failed parameters");
167 int ueventSockFd = UeventdSocketInit();
168 if (ueventSockFd < 0) {
169 INIT_LOGE("Failed to create uevent socket");
170 return -1;
171 }
172 RetriggerUevent(ueventSockFd, requiredDevices, num);
173 close(ueventSockFd);
174 return 0;
175 }
176
StartInitSecondStage(void)177 static void StartInitSecondStage(void)
178 {
179 int requiredNum = 0;
180 Fstab *fstab = LoadRequiredFstab();
181 char **devices = (fstab != NULL) ? GetRequiredDevices(*fstab, &requiredNum) : NULL;
182 if (devices != NULL && requiredNum > 0) {
183 int ret = StartUeventd(devices, requiredNum);
184 if (ret == 0) {
185 ret = MountRequriedPartitions(fstab);
186 }
187 FreeStringVector(devices, requiredNum);
188 devices = NULL;
189 ReleaseFstab(fstab);
190 fstab = NULL;
191 if (ret < 0) {
192 // If mount required partitions failure.
193 // There is no necessary to continue.
194 // Just abort
195 INIT_LOGE("Mount required partitions failed; please check fstab file");
196 // Execute sh for debugging
197 #ifndef STARTUP_INIT_TEST
198 execv("/bin/sh", NULL);
199 abort();
200 #endif
201 }
202 }
203
204 if (fstab != NULL) {
205 ReleaseFstab(fstab);
206 fstab = NULL;
207 }
208 // It will panic if close stdio before execv("/bin/sh", NULL)
209 CloseStdio();
210
211 INIT_LOGI("Start init second stage.");
212 SwitchRoot("/usr");
213 // Execute init second stage
214 char * const args[] = {
215 "/bin/init",
216 "--second-stage",
217 NULL,
218 };
219 if (execv("/bin/init", args) != 0) {
220 INIT_LOGE("Failed to exec \"/bin/init\", err = %d", errno);
221 exit(-1);
222 }
223 }
224
SystemPrepare(void)225 void SystemPrepare(void)
226 {
227 MountBasicFs();
228 CreateDeviceNode();
229 LogInit();
230 // Make sure init log always output to /dev/kmsg.
231 EnableDevKmsg();
232 INIT_LOGI("Start init first stage.");
233 HookMgrExecute(GetBootStageHookMgr(), INIT_FIRST_STAGE, NULL, NULL);
234 // Only ohos normal system support
235 // two stages of init.
236 // If we are in updater mode, only one stage of init.
237 if (InUpdaterMode() == 0) {
238 StartInitSecondStage();
239 }
240 }
241
242 #define INIT_BOOTSTAGE_HOOK_NAME "bootstage"
243 static HOOK_MGR *bootStageHookMgr = NULL;
244
GetBootStageHookMgr()245 HOOK_MGR *GetBootStageHookMgr()
246 {
247 if (bootStageHookMgr != NULL) {
248 return bootStageHookMgr;
249 }
250
251 /*
252 * Create bootstage hook manager for booting only.
253 * When boot completed, this manager will be destroyed.
254 */
255 bootStageHookMgr = HookMgrCreate(INIT_BOOTSTAGE_HOOK_NAME);
256 return bootStageHookMgr;
257 }
258
259 INIT_TIMING_STAT g_bootJob = {{0}, {0}};
260
RecordInitBootEvent(const char * initBootEvent)261 static void RecordInitBootEvent(const char *initBootEvent)
262 {
263 const char *bootEventArgv[] = {"init", initBootEvent};
264 PluginExecCmd("bootevent", ARRAY_LENGTH(bootEventArgv), bootEventArgv);
265 return;
266 }
267
BootStateChange(int start,const char * content)268 INIT_STATIC void BootStateChange(int start, const char *content)
269 {
270 if (start == 0) {
271 clock_gettime(CLOCK_MONOTONIC, &(g_bootJob.startTime));
272 RecordInitBootEvent(content);
273 INIT_LOGI("boot job %s start.", content);
274 } else {
275 clock_gettime(CLOCK_MONOTONIC, &(g_bootJob.endTime));
276 RecordInitBootEvent(content);
277 long long diff = InitDiffTime(&g_bootJob);
278 INIT_LOGI("boot job %s finish diff %lld us.", content, diff);
279 }
280 }
281
InitLoadParamFiles(void)282 static void InitLoadParamFiles(void)
283 {
284 if (InUpdaterMode() != 0) {
285 LoadDefaultParams("/etc/param/ohos_const", LOAD_PARAM_NORMAL);
286 LoadDefaultParams("/etc/param", LOAD_PARAM_ONLY_ADD);
287 return;
288 }
289
290 // Load const params, these can't be override!
291 LoadDefaultParams("/system/etc/param/ohos_const", LOAD_PARAM_NORMAL);
292 CfgFiles *files = GetCfgFiles("etc/param");
293 for (int i = MAX_CFG_POLICY_DIRS_CNT - 1; files && i >= 0; i--) {
294 if (files->paths[i]) {
295 LoadDefaultParams(files->paths[i], LOAD_PARAM_ONLY_ADD);
296 }
297 }
298 FreeCfgFiles(files);
299 }
300
InitPreHook(const HOOK_INFO * hookInfo,void * executionContext)301 INIT_STATIC void InitPreHook(const HOOK_INFO *hookInfo, void *executionContext)
302 {
303 INIT_TIMING_STAT *stat = (INIT_TIMING_STAT *)executionContext;
304 clock_gettime(CLOCK_MONOTONIC, &(stat->startTime));
305 }
306
InitPostHook(const HOOK_INFO * hookInfo,void * executionContext,int executionRetVal)307 INIT_STATIC void InitPostHook(const HOOK_INFO *hookInfo, void *executionContext, int executionRetVal)
308 {
309 INIT_TIMING_STAT *stat = (INIT_TIMING_STAT *)executionContext;
310 clock_gettime(CLOCK_MONOTONIC, &(stat->endTime));
311 long long diff = InitDiffTime(stat);
312 INIT_LOGI("Executing hook [%d:%d] cost [%lld]us, return %d.",
313 hookInfo->stage, hookInfo->prio, diff, executionRetVal);
314 }
315
InitSysAdj(void)316 static void InitSysAdj(void)
317 {
318 const char* path = "/proc/self/oom_score_adj";
319 const char* content = "-1000";
320 int fd = open(path, O_RDWR);
321 if (fd == -1) {
322 return;
323 }
324 if (write(fd, content, strlen(content)) < 0) {
325 close(fd);
326 return;
327 }
328 close(fd);
329 return;
330 }
331
TriggerServices(int startMode)332 INIT_STATIC void TriggerServices(int startMode)
333 {
334 int index = 0;
335 int jobNum = 0;
336 char jobName[64] = {0}; // 64 job name
337 char cmd[64] = {0}; // 64 job name
338 const int maxServiceInJob = 4; // 4 service in job
339 InitGroupNode *node = GetNextGroupNode(NODE_TYPE_SERVICES, NULL);
340 while (node != NULL) {
341 Service *service = node->data.service;
342 if (service == NULL || service->startMode != startMode) {
343 node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
344 continue;
345 }
346 if (IsOnDemandService(service)) {
347 if (CreateServiceSocket(service) != 0) {
348 INIT_LOGE("service %s exit! create socket failed!", service->name);
349 }
350 node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
351 continue;
352 }
353 if (sprintf_s(cmd, sizeof(cmd), "start %s", service->name) <= 0) {
354 node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
355 continue;
356 }
357 if (index == 0) {
358 if (sprintf_s(jobName, sizeof(jobName), "boot-service:service-%d-%03d", startMode, jobNum) <= 0) {
359 node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
360 continue;
361 }
362 jobNum++;
363 }
364 index++;
365 AddCompleteJob(jobName, NULL, cmd);
366 INIT_LOGV("Add %s to job %s", service->name, jobName);
367 if (index == maxServiceInJob) {
368 PostTrigger(EVENT_TRIGGER_BOOT, jobName, strlen(jobName));
369 index = 0;
370 }
371 node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
372 }
373 if (index > 0) {
374 PostTrigger(EVENT_TRIGGER_BOOT, jobName, strlen(jobName));
375 }
376 }
377
ParseInitCfgByPriority(void)378 void ParseInitCfgByPriority(void)
379 {
380 CfgFiles *files = GetCfgFiles("etc/init");
381 for (int i = 0; files && i < MAX_CFG_POLICY_DIRS_CNT; i++) {
382 if (files->paths[i]) {
383 if (ReadFileInDir(files->paths[i], ".cfg", ParseInitCfg, NULL) < 0) {
384 break;
385 }
386 }
387 }
388 FreeCfgFiles(files);
389 }
390
SystemConfig(void)391 void SystemConfig(void)
392 {
393 INIT_TIMING_STAT timingStat;
394
395 InitSysAdj();
396 HOOK_EXEC_OPTIONS options;
397
398 options.flags = 0;
399 options.preHook = InitPreHook;
400 options.postHook = InitPostHook;
401 InitServiceSpace();
402 HookMgrExecute(GetBootStageHookMgr(), INIT_GLOBAL_INIT, (void *)&timingStat, (void *)&options);
403 RecordInitBootEvent("init.prepare");
404
405 HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_SERVICE, (void *)&timingStat, (void *)&options);
406 InitParamService();
407 InitParseGroupCfg();
408 RegisterBootStateChange(BootStateChange);
409
410 INIT_LOGI("boot init finish.");
411 // load SELinux context and policy
412 // Do not move position!
413 PluginExecCmdByName("loadSelinuxPolicy", "");
414 RecordInitBootEvent("init.prepare");
415
416 // after selinux loaded
417 SignalInit();
418
419 RecordInitBootEvent("init.ParseCfg");
420 LoadSpecialParam();
421
422 // parse parameters
423 HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_LOAD, (void *)&timingStat, (void *)&options);
424 InitLoadParamFiles();
425 // read config
426 HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_CFG_LOAD, (void *)&timingStat, (void *)&options);
427 ReadConfig();
428 RecordInitBootEvent("init.ParseCfg");
429 INIT_LOGI("boot parse config file done.");
430 HookMgrExecute(GetBootStageHookMgr(), INIT_POST_CFG_LOAD, (void *)&timingStat, (void *)&options);
431
432 IsEnableSandbox();
433 // execute init
434 PostTrigger(EVENT_TRIGGER_BOOT, "pre-init", strlen("pre-init"));
435 PostTrigger(EVENT_TRIGGER_BOOT, "init", strlen("init"));
436 TriggerServices(START_MODE_BOOT);
437 PostTrigger(EVENT_TRIGGER_BOOT, "post-init", strlen("post-init"));
438 TriggerServices(START_MODE_NORMAL);
439 clock_gettime(CLOCK_MONOTONIC, &(g_bootJob.startTime));
440 }
441
SystemRun(void)442 void SystemRun(void)
443 {
444 StartParamService();
445 }
446