• 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     SignalInit();
97     // umask call always succeeds and return the previous mask value which is not needed here
98     (void)umask(DEFAULT_UMASK_INIT);
99     MakeDirRecursive("/dev/unix/socket", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
100     int sock = FdHolderSockInit();
101     if (sock >= 0) {
102         RegisterFdHoldWatcher(sock);
103     }
104     InitControlFd();
105 }
106 
EnableDevKmsg(void)107 static void EnableDevKmsg(void)
108 {
109     /* printk_devkmsg default value is ratelimit, We need to set "on" and remove the restrictions */
110     int fd = open("/proc/sys/kernel/printk_devkmsg", O_WRONLY | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
111     if (fd < 0) {
112         return;
113     }
114     char *kmsgStatus = "on";
115     write(fd, kmsgStatus, strlen(kmsgStatus) + 1);
116     close(fd);
117     fd = -1;
118     return;
119 }
120 
LogInit(void)121 void LogInit(void)
122 {
123     int ret = mknod("/dev/kmsg", S_IFCHR | S_IWUSR | S_IRUSR,
124         makedev(MEM_MAJOR, DEV_KMSG_MINOR));
125     if (ret == 0) {
126         OpenLogDevice();
127     }
128 }
129 
GetRequiredDevices(Fstab fstab,int * requiredNum)130 static char **GetRequiredDevices(Fstab fstab, int *requiredNum)
131 {
132     int num = 0;
133     FstabItem *item = fstab.head;
134     while (item != NULL) {
135         if (FM_MANAGER_REQUIRED_ENABLED(item->fsManagerFlags)) {
136             num++;
137         }
138         item = item->next;
139     }
140     char **devices = (char **)calloc(num, sizeof(char *));
141     INIT_ERROR_CHECK(devices != NULL, return NULL, "Failed calloc err=%d", errno);
142 
143     int i = 0;
144     item = fstab.head;
145     while (item != NULL) {
146         if (FM_MANAGER_REQUIRED_ENABLED(item->fsManagerFlags)) {
147             devices[i] = strdup(item->deviceName);
148             INIT_ERROR_CHECK(devices[i] != NULL, FreeStringVector(devices, num); return NULL,
149                 "Failed strdup err=%d", errno);
150             i++;
151         }
152         item = item->next;
153     }
154     *requiredNum = num;
155     return devices;
156 }
157 
StartUeventd(char ** requiredDevices,int num)158 static int StartUeventd(char **requiredDevices, int num)
159 {
160     INIT_ERROR_CHECK(requiredDevices != NULL && num > 0, return -1, "Failed parameters");
161     int ueventSockFd = UeventdSocketInit();
162     if (ueventSockFd < 0) {
163         INIT_LOGE("Failed to create uevent socket");
164         return -1;
165     }
166     RetriggerUevent(ueventSockFd, requiredDevices, num);
167     close(ueventSockFd);
168     return 0;
169 }
170 
StartInitSecondStage(void)171 static void StartInitSecondStage(void)
172 {
173     int requiredNum = 0;
174     Fstab* fstab = LoadRequiredFstab();
175     INIT_ERROR_CHECK(fstab != NULL, abort(), "Failed to load required fstab");
176     char **devices = GetRequiredDevices(*fstab, &requiredNum);
177     if (devices != NULL && requiredNum > 0) {
178         int ret = StartUeventd(devices, requiredNum);
179         if (ret == 0) {
180             ret = MountRequriedPartitions(fstab);
181         }
182         FreeStringVector(devices, requiredNum);
183         devices = NULL;
184         ReleaseFstab(fstab);
185         fstab = NULL;
186         if (ret < 0) {
187             // If mount required partitions failure.
188             // There is no necessary to continue.
189             // Just abort
190             INIT_LOGE("Mount required partitions failed; please check fstab file");
191             // Execute sh for debugging
192             execv("/bin/sh", NULL);
193             abort();
194         }
195     }
196 
197     // It will panic if close stdio before execv("/bin/sh", NULL)
198     CloseStdio();
199 
200     // Set up a session keyring that all processes will have access to.
201     KeyCtrlGetKeyringId(KEY_SPEC_SESSION_KEYRING, 1);
202 
203 #ifndef DISABLE_INIT_TWO_STAGES
204     INIT_LOGI("Start init second stage.");
205     SwitchRoot("/usr");
206     // Execute init second stage
207     char * const args[] = {
208         "/bin/init",
209         "--second-stage",
210         NULL,
211     };
212     if (execv("/bin/init", args) != 0) {
213         INIT_LOGE("Failed to exec \"/bin/init\", err = %d", errno);
214         exit(-1);
215     }
216 #endif
217 }
218 
SystemPrepare(void)219 void SystemPrepare(void)
220 {
221     MountBasicFs();
222     CreateDeviceNode();
223     LogInit();
224     // Make sure init log always output to /dev/kmsg.
225     EnableDevKmsg();
226     INIT_LOGI("Start init first stage.");
227     // Only ohos normal system support
228     // two stages of init.
229     // If we are in updater mode, only one stage of init.
230     if (InUpdaterMode() == 0) {
231         StartInitSecondStage();
232     }
233 }
234 
235 #define INIT_BOOTSTAGE_HOOK_NAME "bootstage"
236 static HOOK_MGR *bootStageHookMgr = NULL;
237 
GetBootStageHookMgr()238 HOOK_MGR *GetBootStageHookMgr()
239 {
240     if (bootStageHookMgr != NULL) {
241         return bootStageHookMgr;
242     }
243 
244     /*
245      * Create bootstage hook manager for booting only.
246      * When boot completed, this manager will be destroyed.
247      */
248     bootStageHookMgr = HookMgrCreate(INIT_BOOTSTAGE_HOOK_NAME);
249     return bootStageHookMgr;
250 }
251 
252 INIT_TIMING_STAT g_bootJob = {{0}, {0}};
253 
RecordInitBootEvent(const char * initBootEvent)254 static void RecordInitBootEvent(const char *initBootEvent)
255 {
256     const char *bootEventArgv[] = {"init", initBootEvent};
257     PluginExecCmd("bootevent", ARRAY_LENGTH(bootEventArgv), bootEventArgv);
258     return;
259 }
260 
BootStateChange(int start,const char * content)261 static void BootStateChange(int start, const char *content)
262 {
263     if (start == 0) {
264         clock_gettime(CLOCK_MONOTONIC, &(g_bootJob.startTime));
265         RecordInitBootEvent(content);
266         INIT_LOGI("boot job %s start.", content);
267     } else {
268         clock_gettime(CLOCK_MONOTONIC, &(g_bootJob.endTime));
269         RecordInitBootEvent(content);
270         long long diff = InitDiffTime(&g_bootJob);
271         INIT_LOGI("boot job %s finish diff %lld us.", content, diff);
272     }
273 }
274 
InitLoadParamFiles(void)275 static void InitLoadParamFiles(void)
276 {
277     if (InUpdaterMode() != 0) {
278         LoadDefaultParams("/etc/param/ohos_const", LOAD_PARAM_NORMAL);
279         LoadDefaultParams("/etc/param", LOAD_PARAM_ONLY_ADD);
280         return;
281     }
282 
283     // Load const params, these can't be override!
284     LoadDefaultParams("/system/etc/param/ohos_const", LOAD_PARAM_NORMAL);
285     CfgFiles *files = GetCfgFiles("etc/param");
286     for (int i = MAX_CFG_POLICY_DIRS_CNT - 1; files && i >= 0; i--) {
287         if (files->paths[i]) {
288             LoadDefaultParams(files->paths[i], LOAD_PARAM_ONLY_ADD);
289         }
290     }
291     FreeCfgFiles(files);
292 }
293 
InitPreHook(const HOOK_INFO * hookInfo,void * executionContext)294 static void InitPreHook(const HOOK_INFO *hookInfo, void *executionContext)
295 {
296     INIT_TIMING_STAT *stat = (INIT_TIMING_STAT *)executionContext;
297     clock_gettime(CLOCK_MONOTONIC, &(stat->startTime));
298 }
299 
InitPostHook(const HOOK_INFO * hookInfo,void * executionContext,int executionRetVal)300 static void InitPostHook(const HOOK_INFO *hookInfo, void *executionContext, int executionRetVal)
301 {
302     INIT_TIMING_STAT *stat = (INIT_TIMING_STAT *)executionContext;
303     clock_gettime(CLOCK_MONOTONIC, &(stat->endTime));
304     long long diff = InitDiffTime(stat);
305     INIT_LOGI("Executing hook [%d:%d] cost [%lld]us, return %d.",
306         hookInfo->stage, hookInfo->prio, diff, executionRetVal);
307 }
308 
InitSysAdj(void)309 static void InitSysAdj(void)
310 {
311     const char* path = "/proc/self/oom_score_adj";
312     const char* content = "-1000";
313     int fd = open(path, O_RDWR);
314     if (fd == -1) {
315         return;
316     }
317     if (write(fd, content, strlen(content)) < 0) {
318         close(fd);
319         return;
320     }
321     close(fd);
322     return;
323 }
324 
TriggerServices(int startMode)325 static void TriggerServices(int startMode)
326 {
327     int index = 0;
328     int jobNum = 0;
329     char jobName[64] = {0}; // 64 job name
330     char cmd[64] = {0};  // 64 job name
331     const int maxServiceInJob = 4; // 4 service in job
332     InitGroupNode *node = GetNextGroupNode(NODE_TYPE_SERVICES, NULL);
333     while (node != NULL) {
334         Service *service = node->data.service;
335         if (service == NULL || service->startMode != startMode) {
336             node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
337             continue;
338         }
339         if (IsOnDemandService(service)) {
340             if (CreateServiceSocket(service) != 0) {
341                 INIT_LOGE("service %s exit! create socket failed!", service->name);
342             }
343             node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
344             continue;
345         }
346         if (sprintf_s(cmd, sizeof(cmd), "start %s", service->name) <= 0) {
347             node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
348             continue;
349         }
350         if (index == 0) {
351             if (sprintf_s(jobName, sizeof(jobName), "boot-service:service-%d-%03d", startMode, jobNum) <= 0) {
352                 node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
353                 continue;
354             }
355             jobNum++;
356         }
357         index++;
358         AddCompleteJob(jobName, NULL, cmd);
359         INIT_LOGV("Add %s to job %s", service->name, jobName);
360         if (index == maxServiceInJob) {
361             PostTrigger(EVENT_TRIGGER_BOOT, jobName, strlen(jobName));
362             index = 0;
363         }
364         node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
365     }
366     if (index > 0) {
367         PostTrigger(EVENT_TRIGGER_BOOT, jobName, strlen(jobName));
368     }
369 }
370 
ParseInitCfgByPriority(void)371 void ParseInitCfgByPriority(void)
372 {
373     CfgFiles *files = GetCfgFiles("etc/init");
374     for (int i = 0; files && i < MAX_CFG_POLICY_DIRS_CNT; i++) {
375         if (files->paths[i]) {
376             if (ReadFileInDir(files->paths[i], ".cfg", ParseInitCfg, NULL) < 0) {
377                 break;
378             }
379         }
380     }
381     FreeCfgFiles(files);
382 }
383 
SystemConfig(void)384 void SystemConfig(void)
385 {
386     INIT_TIMING_STAT timingStat;
387 
388     InitSysAdj();
389     HOOK_EXEC_OPTIONS options;
390 
391     options.flags = 0;
392     options.preHook = InitPreHook;
393     options.postHook = InitPostHook;
394     InitServiceSpace();
395     HookMgrExecute(GetBootStageHookMgr(), INIT_GLOBAL_INIT, (void *)&timingStat, (void *)&options);
396     RecordInitBootEvent("init.prepare");
397 
398     HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_SERVICE, (void *)&timingStat, (void *)&options);
399     InitParamService();
400     InitParseGroupCfg();
401     RegisterBootStateChange(BootStateChange);
402 
403     INIT_LOGI("boot init finish.");
404     // load SELinux context and policy
405     // Do not move position!
406     PluginExecCmdByName("loadSelinuxPolicy", "");
407     RecordInitBootEvent("init.prepare");
408 
409     RecordInitBootEvent("init.ParseCfg");
410     LoadSpecialParam();
411 
412     // parse parameters
413     HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_LOAD, (void *)&timingStat, (void *)&options);
414     InitLoadParamFiles();
415     // read config
416     HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_CFG_LOAD, (void *)&timingStat, (void *)&options);
417     ReadConfig();
418     RecordInitBootEvent("init.ParseCfg");
419     INIT_LOGI("boot parse config file done.");
420     HookMgrExecute(GetBootStageHookMgr(), INIT_POST_CFG_LOAD, (void *)&timingStat, (void *)&options);
421 
422     IsEnableSandbox();
423     // execute init
424     PostTrigger(EVENT_TRIGGER_BOOT, "pre-init", strlen("pre-init"));
425     PostTrigger(EVENT_TRIGGER_BOOT, "init", strlen("init"));
426     TriggerServices(START_MODE_BOOT);
427     PostTrigger(EVENT_TRIGGER_BOOT, "post-init", strlen("post-init"));
428     TriggerServices(START_MODE_NORMAL);
429     clock_gettime(CLOCK_MONOTONIC, &(g_bootJob.startTime));
430 }
431 
SystemRun(void)432 void SystemRun(void)
433 {
434     StartParamService();
435 }
436