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