diff --git a/initsync/BUILD.gn b/initsync/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..86b0ad0703058e33e629ee37434573bf07ead162 --- /dev/null +++ b/initsync/BUILD.gn @@ -0,0 +1,38 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/lite/config/component/lite_component.gni") + +lite_component("initsync") { + features = [ "//base/startup/init_lite/initsync:libinitsync_shared" ] +} + +shared_library("libinitsync_shared") { + sources = [ "src/init_sync.c" ] + cflags = [ "-Wall" ] + include_dirs = [ + "//base/startup/init_lite/initsync/include", + "//base/startup/init_lite/interfaces/kits", + ] + public_deps = [ "//third_party/bounds_checking_function:libsec_shared" ] +} + +static_library("libinitsync_static") { + sources = [ "src/init_sync.c" ] + cflags = [ "-Wall" ] + include_dirs = [ + "//base/startup/init_lite/initsync/include", + "//base/startup/init_lite/interfaces/kits", + ] + public_deps = [ "//third_party/bounds_checking_function:libsec_static" ] +} diff --git a/initsync/include/init_stage.h b/initsync/include/init_stage.h new file mode 100644 index 0000000000000000000000000000000000000000..7d5b7848b38e6f62cf6c707df5b8d38911d18800 --- /dev/null +++ b/initsync/include/init_stage.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BASE_STARTUP_INITLITE_STAGE_H +#define BASE_STARTUP_INITLITE_STAGE_H + +#include "init_sync.h" +#include +#include + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +typedef enum { + QS_STAGE1 = 1, /* 1: start from stage1, 0 is already called in kernel process */ + QS_STAGE2, /* system init stage No 2 */ + QS_STAGE3, /* system init stage No 3 */ + QS_STAGE_LIMIT +} QuickstartStage; + +typedef enum { + QS_NOTIFY = QS_STAGE_LIMIT, /* quickstart notify */ + QS_LISTEN, /* quickstart listen */ + QS_CTL_LIMIT +} QuickstartConctrl; + +typedef struct { + unsigned int events; + unsigned int wait; +} QuickstartListenArgs; + +#define QUICKSTART_IOC_MAGIC 'T' +#define QUICKSTART_NOTIFY _IO(QUICKSTART_IOC_MAGIC, QS_NOTIFY) +#define QUICKSTART_LISTEN _IOR(QUICKSTART_IOC_MAGIC, QS_LISTEN, QuickstartListenArgs) +#define QUICKSTART_STAGE(x) _IO(QUICKSTART_IOC_MAGIC, (x)) + +#define QUICKSTART_NODE "/dev/quickstart" + +/* Simple sample Useage: + * INIT PROCESS + * SystemInitStage(QS_STAGE1)----(1)fork----> key APP + * |(2) |(3) + * InitListen<-------------------(4)---------- NotifyInit + * |(5) + * SystemInitStage(QS_STAGE2)----(6)fork---------------------> other APP + * |... + * InitStageFinished + */ + +/* + * Listen the events of a specific pid process by Init process. + * Only be called by Init process. + * eventMask: There needs to be a consensus between the listener and the notifier. + */ +extern int InitListen(unsigned long eventMask, unsigned int wait); + +/* + * Trigger the SystemInit stage. + * Only be called by Init process. + */ +extern int SystemInitStage(QuickstartStage stage); + +/* + * InitStage finished. + * Only be called by Init process. + */ +extern int InitStageFinished(void); + +/* + * Listen event and trigger the SystemInit stage. + * Only be called by Init process. + */ +extern void TriggerStage(unsigned int event, unsigned int wait, QuickstartStage stagelevel); +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif + +#endif // BASE_STARTUP_INITLITE_STAGE_H diff --git a/initsync/src/init_sync.c b/initsync/src/init_sync.c new file mode 100644 index 0000000000000000000000000000000000000000..24aa1cdd951b83e2fa1087bd086a4d79978c71ca --- /dev/null +++ b/initsync/src/init_sync.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "init_stage.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int SendCmd(int cmd, unsigned long arg) +{ + int fd = open(QUICKSTART_NODE, O_RDONLY); + if (fd != -1) { + int ret = ioctl(fd, cmd, arg); + if (ret == -1) { + printf("[ERR][%s,%d] %s!\n", __FUNCTION__, __LINE__, strerror(errno)); + } + close(fd); + return ret; + } + printf("[ERR][%s,%d] %s!\n", __FUNCTION__, __LINE__, strerror(errno)); + return fd; +} + +int InitListen(unsigned long eventMask, unsigned int wait) +{ + QuickstartListenArgs args; + args.wait = wait; + args.events = eventMask; + return SendCmd(QUICKSTART_LISTEN, (unsigned long)&args); +} + +int NotifyInit(unsigned long event) +{ + return SendCmd(QUICKSTART_NOTIFY, event); +} + +int SystemInitStage(QuickstartStage stage) +{ + if (stage >= QS_STAGE_LIMIT || stage < QS_STAGE1) { + printf("[ERR][%s,%d] the stage(%d) is not expected!\n", __FUNCTION__, __LINE__, stage); + return -1; + } + return SendCmd(QUICKSTART_STAGE(stage), 0); +} + +void TriggerStage(unsigned int event, unsigned int wait, QuickstartStage stagelevel) +{ + int ret = InitListen(event, wait); + if (ret != 0) { + SystemInitStage(stagelevel); + } +} + +int InitStageFinished(void) +{ + return unlink(QUICKSTART_NODE); +} diff --git a/interfaces/kits/init_sync.h b/interfaces/kits/init_sync.h new file mode 100644 index 0000000000000000000000000000000000000000..ceeefbce390a32bf12cb49334c52fc475fced04c --- /dev/null +++ b/interfaces/kits/init_sync.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BASE_STARTUP_INITLITE_NOTIFY_H +#define BASE_STARTUP_INITLITE_NOTIFY_H + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +#define EVENT1 0xf +#define EVENT1_WAITTIME 10000 // 10s = 10*1000 * 1 tick(1ms) + +#define EVENT2 0xf0 +/* Define EVENT2_WAITTIME 0 means QS_STAGE2 is no used */ +#define EVENT2_WAITTIME 0 + +#define EVENT3 0xf00 +/* Define EVENT3_WAITTIME 0 means QS_STAGE3 is no used */ +#define EVENT3_WAITTIME 0 + +/* + * Notify the event to Init process. + * All processes can call. Usually called by the listened process. + * event: There needs to be a consensus between the listener(init process) and the notifier. + */ +extern int NotifyInit(unsigned long event); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif + +#endif // BASE_STARTUP_INITLITE_NOTIFY_H diff --git a/services/BUILD.gn b/services/BUILD.gn index a161e6e22e2b105e34c5a07a9d30516cbf423c2d..286dadf956a3d7eea7fccce55f271a6564aad512 100644 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -10,60 +10,113 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -import("//build/lite/config/component/lite_component.gni") - -lite_component("init_lite") { - features = [ ":init" ] -} - -# feature: init -executable("init") { - defines = [ - "_GNU_SOURCE", #syscall function need this macro definition - ] - sources = [ - "src/init_adapter.c", - "src/init_cmds.c", - "src/init_jobs.c", - "src/init_read_cfg.c", - "src/init_service.c", - "src/init_service_manager.c", - "src/init_signal_handler.c", - "src/main.c", - ] +if (defined(ohos_lite)) { + # feature: init + executable("init_lite") { + output_name = "init" + defines = [ + "_GNU_SOURCE", #syscall function need this macro definition + "OHOS_LITE", + ] + sources = [ + "src/init_adapter.c", + "src/init_cmds.c", + "src/init_jobs.c", + "src/init_read_cfg.c", + "src/init_service.c", + "src/init_service_manager.c", + "src/init_signal_handler.c", + "src/main.c", + ] - include_dirs = [ - "include", - "//third_party/cJSON", - "//third_party/bounds_checking_function/include", - "//base/startup/syspara_lite/interfaces/kits", - ] + include_dirs = [ + "include", + "//third_party/cJSON", + "//third_party/bounds_checking_function/include", + "//base/startup/syspara_lite/interfaces/kits", + ] - cflags = [ "-Wall" ] + cflags = [ "-Wall" ] - deps = [ - "//base/startup/syspara_lite/frameworks/parameter:parameter", - "//build/lite/config/component/cJSON:cjson_shared", - "//third_party/bounds_checking_function:libsec_shared", - ] + deps = [ + "//base/startup/syspara_lite/frameworks/parameter:parameter", + "//base/startup/init_lite/initsync:initsync", + "//build/lite/config/component/cJSON:cjson_shared", + "//third_party/bounds_checking_function:libsec_shared", + ] + ldflags = [] + if (ohos_kernel_type == "liteos_a") { + include_dirs += [ + "//kernel/liteos_a/syscall", + "//base/startup/init_lite/interfaces/kits", + "//base/startup/init_lite/initsync/include", + ] + deps += [ "//base/startup/init_lite/initsync:initsync" ] + } + if (ohos_kernel_type == "linux") { + defines += [ "NEED_EXEC_RCS_LINUX" ] + ldflags += [ + "-lm", + "-lpthread", + ] + deps += [ + "//third_party/mksh", + "//third_party/toybox", + ] + } + } - ldflags = [] + if (ohos_build_type == "debug") { + group("unittest") { + deps = + [ "//base/startup/init_lite/services/test/unittest/common:unittest" ] + } + } +} else { + import("//build/ohos.gni") - if (ohos_kernel_type == "liteos_a") { - include_dirs += [ "//kernel/liteos_a/syscall" ] + ohos_executable("updaterueventd") { + sources = [ + "src/list.c", + "src/uevent.c", + ] + include_dirs = [ + "include", + "//third_party/bounds_checking_function/include", + ] + deps = [ "//third_party/bounds_checking_function:libsec_static" ] + install_enable = true + part_name = "updater" } - if (ohos_kernel_type == "linux") { - defines += [ "NEED_EXEC_RCS_LINUX" ] - ldflags += [ - "-lm", - "-lpthread", + ohos_executable("updaterinit") { + sources = [ + "src/device.c", + "src/init_adapter.c", + "src/init_cmds.c", + "src/init_jobs.c", + "src/init_read_cfg.c", + "src/init_service.c", + "src/init_service_manager.c", + "src/init_signal_handler.c", + "src/main.c", ] + include_dirs = [ + "include", + "//third_party/cJSON", + "//third_party/bounds_checking_function/include", + ] + deps = [ + "//third_party/bounds_checking_function:libsec_static", + "//third_party/cJSON:cjson_static", + ] + install_enable = true + part_name = "updater" } -} -if (ohos_build_type == "debug") { - group("unittest") { - deps = [ "//base/startup/init_lite/services/test/unittest/common:unittest" ] + ohos_prebuilt_etc("init.cfg") { + source = "//device/hisilicon/hi3516dv300/updater/init.cfg" + relative_install_dir = "init" + subsystem_name = "updater" } } diff --git a/services/include/device.h b/services/include/device.h new file mode 100755 index 0000000000000000000000000000000000000000..6739b2bc78280535403a06546405950ba2656f38 --- /dev/null +++ b/services/include/device.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BASE_STARTUP_INITLITE_DEVICE_H +#define BASE_STARTUP_INITLITE_DEVICE_H + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +void MountBasicFs(); +void CreateDeviceNode(); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif +#endif // BASE_STARTUP_INITLITE_DEVICE_H diff --git a/services/include/list.h b/services/include/list.h new file mode 100755 index 0000000000000000000000000000000000000000..ee2220cc078053150768ea0735f1b57a40c1b646 --- /dev/null +++ b/services/include/list.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BASE_STARTUP_INITLITE_LIST_H +#define BASE_STARTUP_INITLITE_LIST_H + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +struct ListNode { + struct ListNode *next; + struct ListNode *prev; +}; + +void ListInit(struct ListNode *list); +void ListAddTail(struct ListNode *list, struct ListNode *item); +void ListRemove(struct ListNode *item); +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif + +#endif // BASE_STARTUP_INITLITE_LIST_H diff --git a/services/src/device.c b/services/src/device.c new file mode 100755 index 0000000000000000000000000000000000000000..84013a2cbf376ed2ab91a7b59036ff5ec844edf2 --- /dev/null +++ b/services/src/device.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#define DEFAULT_RW_MODE 0666 +#define DEFAULT_NO_AUTHORITY_MODE 0600 +#define DEVICE_ID_THIRD 3 +#define DEVICE_ID_EIGHTH 8 +#define DEVICE_ID_NINTH 9 +#define DEVICE_ID_ELEVNTH 11 + +void MountBasicFs() +{ + if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755") != 0) { + printf("Mount tmpfs failed. %s\n", strerror(errno)); + } + if (mount("proc", "/proc", "proc", 0, "hidepid=2") != 0) { + printf("Mount procfs failed. %s\n", strerror(errno)); + } + if (mount("sysfs", "/sys", "sysfs", 0, NULL) != 0) { + printf("Mount sysfs failed. %s\n", strerror(errno)); + } +} + +void CreateDeviceNode() +{ + if (mknod("/dev/kmsg", S_IFCHR | DEFAULT_NO_AUTHORITY_MODE, makedev(1, DEVICE_ID_ELEVNTH)) != 0) { + printf("Create /dev/kmsg device node failed. %s\n", strerror(errno)); + } + if (mknod("/dev/null", S_IFCHR | DEFAULT_RW_MODE, makedev(1, DEVICE_ID_THIRD)) != 0) { + printf("Create /dev/null device node failed. %s\n", strerror(errno)); + } + if (mknod("/dev/random", S_IFCHR | DEFAULT_RW_MODE, makedev(1, DEVICE_ID_EIGHTH)) != 0) { + printf("Create /dev/random device node failed. %s\n", strerror(errno)); + } + + if (mknod("/dev/urandom", S_IFCHR | DEFAULT_RW_MODE, makedev(1, DEVICE_ID_NINTH)) != 0) { + printf("Create /dev/urandom device node failed. %s\n", strerror(errno)); + } +} diff --git a/services/src/init_adapter.c b/services/src/init_adapter.c index e82cec5aac292c0a872e149c938d3a09b7f67587..34c46408b42119df54b41760bb7c8d0ccc9de1e6 100644 --- a/services/src/init_adapter.c +++ b/services/src/init_adapter.c @@ -14,6 +14,7 @@ */ #include "init_adapter.h" + #include #include #include diff --git a/services/src/init_cmds.c b/services/src/init_cmds.c index f1083374977030530821bda51850f42d31133f75..b79c561823120e208274e35f2106afaaa9dc4eff 100644 --- a/services/src/init_cmds.c +++ b/services/src/init_cmds.c @@ -24,11 +24,15 @@ #include #include #include +#ifndef OHOS_LITE +#include +#include +#include +#endif #include "init_service_manager.h" #include "securec.h" - #define MODE_LEN 4 // for chmod mode, format 0xxx #define DEFAULT_DIR_MODE 0755 // mkdir, default mode #define SPACES_CNT_IN_CMD_MAX 10 // mount, max number of spaces in cmdline @@ -37,7 +41,10 @@ #define LOADCFG_BUF_SIZE 128 // loadcfg, max buffer for one cmdline #define LOADCFG_MAX_FILE_LEN 51200 // loadcfg, max file size is 50K #define LOADCFG_MAX_LOOP 20 // loadcfg, to prevent to be trapped in infite loop +#define OCTAL_TYPE 8 // 8 means octal to decimal +#define MAX_BUFFER 256 static const char *g_supportCfg[] = { + "/etc/patch.cfg", "/patch/fstab.cfg", }; @@ -48,6 +55,7 @@ static const char* g_supportedCmds[] = { "chown ", "mount ", "loadcfg ", + "insmod ", }; void ParseCmdLine(const char* cmdStr, CmdLine* resCmd) @@ -115,7 +123,7 @@ static void DoChmod(const char* cmdContent) } const char* pathBeginStr = cmdContent + MODE_LEN + 1; // after space - mode_t mode = strtoul(cmdContent, NULL, 8); // 8 means octal to decimal + mode_t mode = strtoul(cmdContent, NULL, OCTAL_TYPE); if (mode == 0) { printf("[Init] DoChmod, strtoul failed for %s, er %d.\n", cmdContent, errno); return; @@ -172,14 +180,14 @@ static void DoChown(const char* cmdContent) static char* CopySubStr(const char* srcStr, size_t startPos, size_t endPos) { if (endPos <= startPos) { - printf("[Init] DoMount, invalid params<%lu, %lu> for %s.\n", endPos, startPos, srcStr); + printf("[Init] DoMount, invalid params<%zu, %zu> for %s.\n", endPos, startPos, srcStr); return NULL; } size_t mallocLen = endPos - startPos + 1; char* retStr = (char*)malloc(mallocLen); if (retStr == NULL) { - printf("[Init] DoMount, malloc failed! malloc size %lu, for %s.\n", mallocLen, srcStr); + printf("[Init] DoMount, malloc failed! malloc size %zu, for %s.\n", mallocLen, srcStr); return NULL; } @@ -316,6 +324,101 @@ static void DoMount(const char* cmdContent) free(target); } +#ifndef OHOS_LITE +#define OPTIONS_SIZE 128u +static void DoInsmodInternal(const char *fileName, char *secondPtr, char *restPtr, int flags) +{ + char options[OPTIONS_SIZE] = {0}; + if (flags == 0) { // '-f' option + if (restPtr != NULL && secondPtr != NULL) { // Reset arugments, combine then all. + if (snprintf_s(options, sizeof(options), OPTIONS_SIZE -1, "%s %s", secondPtr, restPtr) == -1) { + return; + } + } else if (secondPtr != NULL) { + if (strncpy_s(options, OPTIONS_SIZE - 1, secondPtr, strlen(secondPtr)) != 0) { + return; + } + } + } else { // Only restPtr is option + if (restPtr != NULL) { + if (strncpy_s(options, OPTIONS_SIZE - 1, restPtr, strlen(restPtr)) != 0) { + return; + } + } + } + if (!fileName) { + return; + } + char *realPath = (char *)calloc(MAX_BUFFER, sizeof(char)); + if (realPath == NULL) { + return; + } + realPath = realpath(fileName, realPath); + int fd = open(realPath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); + if (fd < 0) { + printf("[Init] failed to open %s: %d\n", realPath, errno); + free(realPath); + return; + } + int rc = syscall(__NR_finit_module, fd, options, flags); + if (rc == -1) { + printf("[Init] finit_module for %s failed: %d\n", realPath, errno); + } + if (fd >= 0) { + close(fd); + } + free(realPath); + return; +} + +// format insmod [-f] [options] +static void DoInsmod(const char *cmdContent) +{ + char *p = NULL; + char *restPtr = NULL; + char *fileName = NULL; + char *line = NULL; + int flags = 0; + + size_t count = strlen(cmdContent); + if (count > OPTIONS_SIZE) { + printf("[Init], options too long, maybe lost some of options\n"); + } + line = (char *)malloc(count + 1); + if (line == NULL) { + printf("[Init] Allocate memory failed.\n"); + return; + } + + if (memcpy_s(line, count, cmdContent, count) != EOK) { + printf("[Init] memcpy failed\n"); + free(line); + return; + } + line[count] = '\0'; + do { + if ((p = strtok_r(line, " ", &restPtr)) == NULL) { + printf("[Init] debug, cannot get filename\n"); + free(line); + return; + } + fileName = p; + printf("[Init] debug, fileName is [%s]\n", fileName); + if ((p = strtok_r(NULL, " ", &restPtr)) == NULL) { + break; + } + if (!strcmp(p, "-f")) { + flags = MODULE_INIT_IGNORE_VERMAGIC | MODULE_INIT_IGNORE_MODVERSIONS; + } + } while (0); + DoInsmodInternal(fileName, p, restPtr, flags); + if (line != NULL) { + free(line); + } + return; +} +#endif // OHOS_LITE + static bool CheckValidCfg(const char *path) { size_t cfgCnt = sizeof(g_supportCfg) / sizeof(g_supportCfg[0]); @@ -402,6 +505,10 @@ void DoCmd(const CmdLine* curCmd) DoMount(curCmd->cmdContent); } else if (strncmp(curCmd->name, "loadcfg ", strlen("loadcfg ")) == 0) { DoLoadCfg(curCmd->cmdContent); +#ifndef OHOS_LITE + } else if (strncmp(curCmd->name, "insmod ", strlen("insmod ")) == 0) { + DoInsmod(curCmd->cmdContent); +#endif } else { printf("[Init] DoCmd, unknown cmd name %s.\n", curCmd->name); } diff --git a/services/src/init_read_cfg.c b/services/src/init_read_cfg.c index 11d122a1ac6f399896f88ced2378882281dcbb55..0d2108f3c20fcde487be941a29a1ce805aa0dd33 100644 --- a/services/src/init_read_cfg.c +++ b/services/src/init_read_cfg.c @@ -27,7 +27,11 @@ #include "init_perms.h" #include "init_service_manager.h" #include "securec.h" - +#ifndef __LINUX__ +#ifdef OHOS_LITE +#include "init_stage.h" +#endif +#endif static const long MAX_JSON_FILE_LEN = 102400; // max init.cfg size 100KB static const int MAX_PATH_ARGS_CNT = 20; // max path and args count @@ -350,8 +354,27 @@ void InitReadCfg() // do jobs DoJob("pre-init"); +#ifndef __LINUX__ +#ifdef OHOS_LITE + TriggerStage(EVENT1, EVENT1_WAITTIME, QS_STAGE1); +#endif +#endif + DoJob("init"); +#ifndef __LINUX__ +#ifdef OHOS_LITE + TriggerStage(EVENT2, EVENT2_WAITTIME, QS_STAGE2); +#endif +#endif + DoJob("post-init"); +#ifndef __LINUX__ +#ifdef OHOS_LITE + TriggerStage(EVENT3, EVENT3_WAITTIME, QS_STAGE3); + + InitStageFinished(); +#endif +#endif ReleaseAllJobs(); } diff --git a/services/src/init_service.c b/services/src/init_service.c index fd85045542885df34e56dba4d696f4f7e88ab5e7..1e6e577abf7d0cee79ab404282057ad06cbbe177 100644 --- a/services/src/init_service.c +++ b/services/src/init_service.c @@ -64,7 +64,7 @@ static int SetPerms(const Service *service) capHeader.version = _LINUX_CAPABILITY_VERSION_3; capHeader.pid = 0; - struct __user_cap_data_struct capData[CAP_NUM] = {0}; + struct __user_cap_data_struct capData[CAP_NUM] = {}; for (unsigned int i = 0; i < service->servPerm.capsCnt; ++i) { if (service->servPerm.caps[i] == FULL_CAP) { for (int i = 0; i < CAP_NUM; ++i) { diff --git a/services/src/init_service_manager.c b/services/src/init_service_manager.c index d06fec7f1a7c2de9fd6934cf7e21b24ffcb0cd1a..2a7cbcbbe4cc13e82cac5accd1d0639b1e907bbf 100755 --- a/services/src/init_service_manager.c +++ b/services/src/init_service_manager.c @@ -66,7 +66,7 @@ void StartServiceByName(const char* servName) void StopAllServices() { - for (size_t i = 0; i < g_servicesCnt; i++) { + for (int i = 0; i < g_servicesCnt; i++) { if (ServiceStop(&g_services[i]) != SERVICE_SUCCESS) { printf("[Init] StopAllServices, service %s stop failed!\n", g_services[i].name); } @@ -75,7 +75,7 @@ void StopAllServices() void ReapServiceByPID(int pid) { - for (size_t i = 0; i < g_servicesCnt; i++) { + for (int i = 0; i < g_servicesCnt; i++) { if (g_services[i].pid == pid) { if (g_services[i].attribute & SERVICE_ATTR_IMPORTANT) { // important process exit, need to reboot system diff --git a/services/src/list.c b/services/src/list.c new file mode 100755 index 0000000000000000000000000000000000000000..17e6f468fc9087fa8ef81ac29fd9a18d103f01fa --- /dev/null +++ b/services/src/list.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "list.h" + +void ListInit(struct ListNode *node) +{ + node->next = node; + node->prev = node; +} + +void ListAddTail(struct ListNode *head, struct ListNode *item) +{ + item->next = head; + item->prev = head->prev; + head->prev->next = item; + head->prev = item; +} + +void ListRemove(struct ListNode *item) +{ + item->next->prev = item->prev; + item->prev->next = item->next; +} diff --git a/services/src/main.c b/services/src/main.c index 7f1436512d81f587ab5d7e47059a8de529ee9e87..40ab4241076b031b2acdd33311375bb6250eb3ac 100755 --- a/services/src/main.c +++ b/services/src/main.c @@ -27,20 +27,26 @@ #include "init_adapter.h" #include "init_read_cfg.h" #include "init_signal_handler.h" +#ifdef OHOS_LITE #include "parameter.h" +#endif + +#ifndef OHOS_LITE +#include "device.h" +#endif static const pid_t INIT_PROCESS_PID = 1; static void PrintSysInfo() { - char* sysInfo = GetVersionId(); +#ifdef OHOS_LITE + const char* sysInfo = GetVersionId(); if (sysInfo != NULL) { printf("[Init] %s\n", sysInfo); - free(sysInfo); - sysInfo = NULL; return; } printf("[Init] main, GetVersionId failed!\n"); +#endif } #ifdef OHOS_DEBUG @@ -72,7 +78,13 @@ int main(int argc, char * const argv[]) // 1. print system info PrintSysInfo(); - // 2. signal register +#ifndef OHOS_LITE + // 2. Mount basic filesystem and create common device node. + MountBasicFs(); + CreateDeviceNode(); +#endif + + // 3. signal register SignalInitModule(); #ifdef OHOS_DEBUG @@ -82,7 +94,7 @@ int main(int argc, char * const argv[]) } #endif // OHOS_DEBUG - // 3. execute rcs + // 4. execute rcs ExecuteRcs(); #ifdef OHOS_DEBUG @@ -92,7 +104,7 @@ int main(int argc, char * const argv[]) } #endif // OHOS_DEBUG - // 4. read configuration file and do jobs + // 5. read configuration file and do jobs InitReadCfg(); #ifdef OHOS_DEBUG @@ -102,7 +114,7 @@ int main(int argc, char * const argv[]) } #endif // OHOS_DEBUG - // 5. keep process alive + // 6. keep process alive #ifdef OHOS_DEBUG printf("[Init] main, time used: sigInfo %ld ms, rcs %ld ms, cfg %ld ms.\n", \ TimeDiffMs(&tmEnter, &tmSysInfo), TimeDiffMs(&tmSysInfo, &tmRcs), TimeDiffMs(&tmRcs, &tmCfg)); diff --git a/services/src/uevent.c b/services/src/uevent.c new file mode 100755 index 0000000000000000000000000000000000000000..08cf8afe18befc60dd41a35a7ae6f2fff5874fc2 --- /dev/null +++ b/services/src/uevent.c @@ -0,0 +1,810 @@ +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "list.h" +#include "securec.h" + +#define LINK_NUMBER 4 +#define DEFAULT_DIR_MODE 0755 +#define DEV_DRM 3 +#define DEV_ONCRPC 6 +#define DEV_ADSP 4 +#define DEV_INPUT 5 +#define DEV_MTD 3 +#define DEV_SOUND 5 +#define DEV_MISC 4 +#define DEV_DEFAULT 4 +#define DEV_PLAT_FORM 9 +#define DEV_USB 4 +#define DEV_GRAPHICS 8 +#define EVENT_ACTION 7 +#define EVENT_DEVPATH 8 +#define EVENT_SYSTEM 10 +#define EVENT_FIRMWARE 9 +#define EVENT_MAJOR 6 +#define EVENT_MINOR 6 +#define EVENT_PARTN 6 +#define EVENT_PART_NAME 9 +#define EVENT_DEV_NAME 8 +#define EVENT_BLOCK 5 +#define EVENT_PLAT_FORM 8 +#define TRIGGER_ADDR_SIZE 4 +#define BASE_BUFFER_SIZE 1024 +#define MAX_BUFFER 256 +#define EVENT_MAX_BUFFER 1026 +#define MAX_DEV_PATH 96 +#define MINORS_GROUPS 128 +#define SYS_LINK_NUMBER 2 +#define MAX_DEVICE_LEN 64 +#define DEFAULT_MODE 0000 +#define DEVICE_SKIP 5 +#define HANDLE_DEVICE_USB 3 +#define DEFAULT_NO_AUTHORITY_MODE 0600 + +int g_ueventFD = -1; + +struct Uevent { + const char *action; + const char *path; + const char *subsystem; + const char *firmware; + const char *partitionName; + const char *deviceName; + int partitionNum; + int major; + int minor; +}; + +struct PlatformNode { + char *name; + char *path; + size_t pathLen; + struct ListNode list; +}; + +static struct ListNode g_platformNames = { + .next = &g_platformNames, + .prev = &g_platformNames, +}; + +const char *g_trigger = "/dev/.trigger_uevent"; +static void HandleUevent(); + +static int UeventFD() +{ + return g_ueventFD; +} + +static void DoTrigger(DIR *dir, const char *path, int32_t pathLen) +{ + if (pathLen < 0) { + return; + } + struct dirent *dirent = NULL; + char ueventPath[MAX_BUFFER]; + if (snprintf_s(ueventPath, sizeof(ueventPath), sizeof(ueventPath) - 1, "%s/uevent", path) == -1) { + return; + } + int fd = open(ueventPath, O_WRONLY); + if (fd >= 0) { + write(fd, "add\n", TRIGGER_ADDR_SIZE); + close(fd); + HandleUevent(); + } + + while ((dirent = readdir(dir)) != NULL) { + if (dirent->d_name[0] == '.' || dirent->d_type != DT_DIR) { + continue; + } + char tmpPath[MAX_BUFFER]; + if (snprintf_s(tmpPath, sizeof(tmpPath), sizeof(tmpPath) - 1, "%s/%s", path, dirent->d_name) == -1) { + continue; + } + + DIR *dir2 = opendir(tmpPath); + if (dir2) { + DoTrigger(dir2, tmpPath, strlen(tmpPath)); + closedir(dir2); + } + } +} + +void Trigger(const char *sysPath) +{ + DIR *dir = opendir(sysPath); + if (dir) { + DoTrigger(dir, sysPath, strlen(sysPath)); + closedir(dir); + } +} + +static void RetriggerUevent() +{ + if (access(g_trigger, F_OK) == 0) { + printf("Skip trigger uevent, alread done\n"); + return; + } + Trigger("/sys/class"); + Trigger("/sys/block"); + Trigger("/sys/devices"); + int fd = open(g_trigger, O_WRONLY | O_CREAT | O_CLOEXEC, DEFAULT_MODE); + if (fd >= 0) { + close(fd); + } + printf("Re-trigger uevent done\n"); +} + +static void UeventSockInit() +{ + struct sockaddr_nl addr; + int buffSize = MAX_BUFFER * BASE_BUFFER_SIZE; + int on = 1; + + if (memset_s(&addr, sizeof(addr), 0, sizeof(addr)) != 0) { + return; + } + addr.nl_family = AF_NETLINK; + addr.nl_pid = getpid(); + addr.nl_groups = 0xffffffff; + + int sockfd = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT); + if (sockfd < 0) { + printf("Create socket failed. %d\n", errno); + return; + } + + setsockopt(sockfd, SOL_SOCKET, SO_RCVBUFFORCE, &buffSize, sizeof(buffSize)); + setsockopt(sockfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); + + if (bind(sockfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + printf("Bind socket failed. %d\n", errno); + close(sockfd); + return; + } + g_ueventFD = sockfd; + fcntl(g_ueventFD, F_SETFD, FD_CLOEXEC); + fcntl(g_ueventFD, F_SETFL, O_NONBLOCK); + RetriggerUevent(); + return; +} + +ssize_t ReadUevent(int fd, void *buf, size_t len) +{ + struct iovec iov = { buf, len }; + struct sockaddr_nl addr; + char control[CMSG_SPACE(sizeof(struct ucred))]; + struct msghdr hdr = { + &addr, + sizeof(addr), + &iov, + 1, + control, + sizeof(control), + 0, + }; + ssize_t n = recvmsg(fd, &hdr, 0); + if (n <= 0) { + return n; + } + struct cmsghdr *cMsg = CMSG_FIRSTHDR(&hdr); + if (cMsg == NULL || cMsg->cmsg_type != SCM_CREDENTIALS) { + bzero(buf, len); + errno = -EIO; + return n; + } + struct ucred *cRed = (struct ucred *)CMSG_DATA(cMsg); + if (cRed->uid != 0) { + bzero(buf, len); + errno = -EIO; + return n; + } + + if (addr.nl_groups == 0 || addr.nl_pid != 0) { + /* ignoring non-kernel or unicast netlink message */ + bzero(buf, len); + errno = -EIO; + return n; + } + + return n; +} + +static void InitUevent(struct Uevent *event) +{ + event->action = ""; + event->path = ""; + event->subsystem = ""; + event->firmware = ""; + event->partitionName = ""; + event->deviceName = ""; + event->partitionNum = -1; +} + +static void ParseUevent(const char *buf, struct Uevent *event) +{ + InitUevent(event); + while (*buf) { + if (strncmp(buf, "ACTION=", EVENT_ACTION) == 0) { + buf += EVENT_ACTION; + event->action = buf; + } else if (strncmp(buf, "DEVPATH=", EVENT_DEVPATH) == 0) { + buf += EVENT_DEVPATH; + event->path = buf; + } else if (strncmp(buf, "SUBSYSTEM=", EVENT_SYSTEM) == 0) { + buf += EVENT_SYSTEM; + event->subsystem = buf; + } else if (strncmp(buf, "FIRMWARE=", EVENT_FIRMWARE) == 0) { + buf += EVENT_FIRMWARE; + event->firmware = buf; + } else if (strncmp(buf, "MAJOR=", EVENT_MAJOR) == 0) { + buf += EVENT_MAJOR; + event->major = atoi(buf); + } else if (strncmp(buf, "MINOR=", EVENT_MINOR) == 0) { + buf += EVENT_MINOR; + event->minor = atoi(buf); + } else if (strncmp(buf, "PARTN=", EVENT_PARTN) == 0) { + buf += EVENT_PARTN; + event->partitionNum = atoi(buf); + } else if (strncmp(buf, "PARTNAME=", EVENT_PART_NAME) == 0) { + buf += EVENT_PART_NAME; + event->partitionName = buf; + } else if (strncmp(buf, "DEVNAME=", EVENT_DEV_NAME) == 0) { + buf += EVENT_DEV_NAME; + event->deviceName = buf; + } + // Drop reset. + while (*buf++) {} + } +} + +static int MakeDir(const char *path, mode_t mode) +{ + int rc = mkdir(path, mode); + if (rc < 0 && errno != EEXIST) { + printf("Create %s failed. %d\n", path, errno); + } + return rc; +} + +static struct PlatformNode *FindPlatformDevice(const char *path) +{ + size_t pathLen = strlen(path); + struct ListNode *node = NULL; + struct PlatformNode *bus = NULL; + + for (node = (&g_platformNames)->prev; node != &g_platformNames; node = node->prev) { + bus = (struct PlatformNode *)(((char*)(node)) - offsetof(struct PlatformNode, list)); + if ((bus->pathLen < pathLen) && (path[bus->pathLen] == '/') && !strncmp(path, bus->path, bus->pathLen)) { + return bus; + } + } + return NULL; +} + +static void CheckValidPartitionName(char *partitionName) +{ + const char* supportPartition = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-"; + if (!partitionName) { + return; + } + + for (size_t i = 0; i < strlen(partitionName); i++) { + int len = strspn(partitionName, supportPartition); + partitionName += len; + i = len; + if (*partitionName) { + *partitionName = '_'; + } + } +} + +static char **ParsePlatformBlockDevice(const struct Uevent *uevent) +{ + const char *device; + char *slash = NULL; + const char *type; + char linkPath[MAX_BUFFER]; + int linkNum = 0; + char *p = NULL; + + struct PlatformNode *pDev = FindPlatformDevice(uevent->path); + if (!pDev) { + return NULL; + } + device = pDev->name; + type = "platform"; + char **links = calloc(sizeof(char *), LINK_NUMBER); + if (!links) { + return NULL; + } + if (snprintf_s(linkPath, sizeof(linkPath), sizeof(linkPath) - 1, "/dev/block/%s/%s", type, device) == -1) { + free(links); + return NULL; + } + if (uevent->partitionName) { + p = strdup(uevent->partitionName); + CheckValidPartitionName(p); + if (strcmp(uevent->partitionName, p)) { + printf("Linking partition '%s' as '%s'\n", uevent->partitionName, p); + } + if (asprintf(&links[linkNum], "%s/by-name/%s", linkPath, p) > 0) { + linkNum++; + } else { + links[linkNum] = NULL; + } + free(p); + } + if (uevent->partitionNum >= 0) { + if (asprintf(&links[linkNum], "%s/by-num/p%d", linkPath, uevent->partitionNum) > 0) { + linkNum++; + } else { + links[linkNum] = NULL; + } + } + slash = strrchr(uevent->path, '/'); + if (asprintf(&links[linkNum], "%s/%s", linkPath, slash + 1) > 0) { + linkNum++; + } else { + links[linkNum] = NULL; + } + return links; +} + +static void MakeDevice(const char *devpath, const char *path, int block, int major, int minor) +{ + /* Only for super user */ + gid_t gid = 0; + dev_t dev; + mode_t mode = DEFAULT_NO_AUTHORITY_MODE; + mode |= (block ? S_IFBLK : S_IFCHR); + dev = makedev(major, minor); + setegid(gid); + if (mknod(devpath, mode, dev) != 0) { + if (errno != EEXIST) { + printf("Make device node[%d, %d] failed. %d\n", major, minor, errno); + } + } +} + +int MkdirRecursive(const char *pathName, mode_t mode) +{ + char buf[128]; + const char *slash; + const char *p = pathName; + struct stat info; + + while ((slash = strchr(p, '/')) != NULL) { + int width = slash - pathName; + p = slash + 1; + if (width < 0) { + break; + } + if (width == 0) { + continue; + } + if ((unsigned int)width > sizeof(buf) - 1) { + printf("path too long for MkdirRecursive\n"); + return -1; + } + if (memcpy_s(buf, width, pathName, width) != 0) { + return -1; + } + buf[width] = 0; + if (stat(buf, &info) != 0) { + int ret = MakeDir(buf, mode); + if (ret && errno != EEXIST) { + return ret; + } + } + } + int ret = MakeDir(pathName, mode); + if (ret && errno != EEXIST) { + return ret; + } + return 0; +} + +void RemoveLink(const char *oldpath, const char *newpath) +{ + char path[MAX_BUFFER]; + ssize_t ret = readlink(newpath, path, sizeof(path) - 1); + if (ret <= 0) { + return; + } + path[ret] = 0; + if (!strcmp(path, oldpath)) { + unlink(newpath); + } +} + +static void MakeLink(const char *oldPath, const char *newPath) +{ + char buf[MAX_BUFFER]; + char *slash = strrchr(newPath, '/'); + if (!slash) { + return; + } + int width = slash - newPath; + if (width <= 0 || width > (int)sizeof(buf) - 1) { + return; + } + if (memcpy_s(buf, sizeof(buf), newPath, width) != 0) { + return; + } + buf[width] = 0; + int ret = MkdirRecursive(buf, DEFAULT_DIR_MODE); + if (ret) { + printf("Failed to create directory %s: %s (%d)\n", buf, strerror(errno), errno); + } + ret = symlink(oldPath, newPath); + if (ret && errno != EEXIST) { + printf("Failed to symlink %s to %s: %s (%d)\n", oldPath, newPath, strerror(errno), errno); + } +} + +static void HandleDevice(struct Uevent *event, const char *devpath, int block, char **links) +{ + int i; + if (!strcmp(event->action, "add")) { + MakeDevice(devpath, event->path, block, event->major, event->minor); + if (links) { + for (i = 0; links[i]; i++) { + MakeLink(devpath, links[i]); + } + } + } + + if (!strcmp(event->action, "remove")) { + if (links) { + for (i = 0; links[i]; i++) { + RemoveLink(devpath, links[i]); + } + } + unlink(devpath); + } + + if (links) { + for (i = 0; links[i]; i++) { + free(links[i]); + } + free(links); + } +} + +static void HandleBlockDevice(struct Uevent *event) +{ + const char *base = "/dev/block"; + char devpath[MAX_DEV_PATH]; + char **links = NULL; + + if (event->major < 0 || event->minor < 0) { + return; + } + const char *name = strrchr(event->path, '/'); + if (name == NULL) { + return; + } + name++; + if (strlen(name) > MAX_DEVICE_LEN) { // too long + return; + } + if (snprintf_s(devpath, sizeof(devpath), sizeof(devpath) - 1, "%s/%s", base, name) == -1) { + return; + } + MakeDir(base, DEFAULT_DIR_MODE); + if (!strncmp(event->path, "/devices/", DEV_PLAT_FORM)) { + links = ParsePlatformBlockDevice(event); + } + HandleDevice(event, devpath, 1, links); +} + +static void AddPlatformDevice(const char *path) +{ + size_t pathLen = strlen(path); + const char *name = path; + + if (!strncmp(path, "/devices/", DEV_PLAT_FORM)) { + name += DEV_PLAT_FORM; + if (!strncmp(name, "platform/", DEV_PLAT_FORM)) { + name += DEV_PLAT_FORM; + } + } + printf("adding platform device %s (%s)\n", name, path); + struct PlatformNode *bus = calloc(1, sizeof(struct PlatformNode)); + if (!bus) { + return; + } + bus->path = strdup(path); + bus->pathLen = pathLen; + bus->name = bus->path + (name - path); + ListAddTail(&g_platformNames, &bus->list); + return; +} + +static void RemovePlatformDevice(const char *path) +{ + struct ListNode *node = NULL; + struct PlatformNode *bus = NULL; + + for (node = (&g_platformNames)->prev; node != &g_platformNames; node = node->prev) { + bus = (struct PlatformNode *)(((char*)(node)) - offsetof(struct PlatformNode, list)); + if (!strcmp(path, bus->path)) { + printf("removing platform device %s\n", bus->name); + free(bus->path); + ListRemove(node); + free(bus); + return; + } + } +} + +static void HandlePlatformDevice(const struct Uevent *event) +{ + const char *path = event->path; + if (strcmp(event->action, "add") == 0) { + AddPlatformDevice(path); + } else if (strcmp(event->action, "remove") == 0) { + RemovePlatformDevice(path); + } +} + +static const char *ParseDeviceName(const struct Uevent *uevent, unsigned int len) +{ + /* if it's not a /dev device, nothing else to do */ + if ((uevent->major < 0) || (uevent->minor < 0)) { + return NULL; + } + /* do we have a name? */ + const char *name = strrchr(uevent->path, '/'); + if (!name) { + return NULL; + } + name++; + /* too-long names would overrun our buffer */ + if (strlen(name) > len) { + return NULL; + } + return name; +} + +static char **GetCharacterDeviceSymlinks(const struct Uevent *uevent) +{ + char *slash = NULL; + int linkNum = 0; + int width; + + struct PlatformNode *pDev = FindPlatformDevice(uevent->path); + if (!pDev) { + return NULL; + } + char **links = calloc(sizeof(char *), SYS_LINK_NUMBER); + if (!links) { + return NULL; + } + + /* skip "/devices/platform/" */ + const char *parent = strchr(uevent->path + pDev->pathLen, '/'); + if (!*parent) { + goto err; + } + + if (strncmp(parent, "/usb", DEV_USB)) { + goto err; + } + /* skip root hub name and device. use device interface */ + if (!*parent) { + goto err; + } + slash = strchr(++parent, '/'); + if (!slash) { + goto err; + } + width = slash - parent; + if (width <= 0) { + goto err; + } + + if (asprintf(&links[linkNum], "/dev/usb/%s%.*s", uevent->subsystem, width, parent) > 0) { + linkNum++; + } else { + links[linkNum] = NULL; + } + mkdir("/dev/usb", DEFAULT_DIR_MODE); + return links; +err: + free(links); + return NULL; +} + +static int HandleUsbDevice(const struct Uevent *event, char *devpath, int len) +{ + if (event->deviceName) { + /* + * create device node provided by kernel if present + * see drivers/base/core.c + */ + char *p = devpath; + if (snprintf_s(devpath, len, len - 1, "/dev/%s", event->deviceName) == -1) { + return -1; + } + /* skip leading /dev/ */ + p += DEVICE_SKIP; + /* build directories */ + while (*p) { + if (*p == '/') { + *p = 0; + MakeDir(devpath, DEFAULT_DIR_MODE); + *p = '/'; + } + p++; + } + } else { + /* This imitates the file system that would be created + * if we were using devfs instead. + * Minors are broken up into groups of 128, starting at "001" + */ + int busId = event->minor / MINORS_GROUPS + 1; + int deviceId = event->minor % MINORS_GROUPS + 1; + /* build directories */ + MakeDir("/dev/bus", DEFAULT_DIR_MODE); + MakeDir("/dev/bus/usb", DEFAULT_DIR_MODE); + if (snprintf_s(devpath, len, len - 1, "/dev/bus/usb/%03d", busId) == -1) { + return -1; + } + MakeDir(devpath, DEFAULT_DIR_MODE); + if (snprintf_s(devpath, len, len - 1, "/dev/bus/usb/%03d/%03d", busId, + deviceId) == -1) { + return -1; + } + } + return 0; +} + +static void HandleDeviceEvent(struct Uevent *event, char *devpath, int len, const char *base, const char *name) +{ + char **links = NULL; + links = GetCharacterDeviceSymlinks(event); + if (!devpath[0]) { + if (snprintf_s(devpath, len, len - 1, "%s%s", base, name) == -1) { + printf("[Init] snprintf_s err \n"); + goto err; + } + } + HandleDevice(event, devpath, 0, links); + return; +err: + if (links) { + for (int i = 0; links[i]; i++) { + free(links[i]); + } + free(links); + } + return; +} +static void HandleGenericDevice(struct Uevent *event) +{ + char *base = NULL; + char devpath[MAX_DEV_PATH] = {0}; + const char *name = ParseDeviceName(event, MAX_DEVICE_LEN); + if (!name) { + return; + } + if (!strncmp(event->subsystem, "usb", HANDLE_DEVICE_USB)) { + if (!strcmp(event->subsystem, "usb")) { + if (HandleUsbDevice(event, devpath, MAX_DEV_PATH) == -1) { + return; + } + } else { + /* ignore other USB events */ + return; + } + } else if (!strncmp(event->subsystem, "graphics", DEV_GRAPHICS)) { + base = "/dev/graphics/"; + MakeDir(base, DEFAULT_DIR_MODE); + } else if (!strncmp(event->subsystem, "drm", DEV_DRM)) { + base = "/dev/dri/"; + MakeDir(base, DEFAULT_DIR_MODE); + } else if (!strncmp(event->subsystem, "oncrpc", DEV_ONCRPC)) { + base = "/dev/oncrpc/"; + MakeDir(base, DEFAULT_DIR_MODE); + } else if (!strncmp(event->subsystem, "adsp", DEV_ADSP)) { + base = "/dev/adsp/"; + MakeDir(base, DEFAULT_DIR_MODE); + } else if (!strncmp(event->subsystem, "input", DEV_INPUT)) { + base = "/dev/input/"; + MakeDir(base, DEFAULT_DIR_MODE); + } else if (!strncmp(event->subsystem, "mtd", DEV_MTD)) { + base = "/dev/mtd/"; + MakeDir(base, DEFAULT_DIR_MODE); + } else if (!strncmp(event->subsystem, "sound", DEV_SOUND)) { + base = "/dev/snd/"; + MakeDir(base, DEFAULT_DIR_MODE); + } else { + base = "/dev/"; + } + HandleDeviceEvent(event, devpath, MAX_DEV_PATH, base, name); + return; +} + +static void HandleDeviceUevent(struct Uevent *event) +{ + if (strcmp(event->action, "add") == 0 || strcmp(event->action, "change") == 0) { + /* Do nothing for now */ + } + if (strncmp(event->subsystem, "block", EVENT_BLOCK) == 0) { + HandleBlockDevice(event); + } else if (strncmp(event->subsystem, "platform", EVENT_PLAT_FORM) == 0) { + HandlePlatformDevice(event); + } else { + HandleGenericDevice(event); + } +} + +static void HandleUevent() +{ + char buf[EVENT_MAX_BUFFER]; + int ret; + struct Uevent event; + while ((ret = ReadUevent(g_ueventFD, buf, BASE_BUFFER_SIZE)) > 0) { + if (ret >= BASE_BUFFER_SIZE) { + continue; + } + buf[ret] = '\0'; + buf[ret + 1] = '\0'; + ParseUevent(buf, &event); + HandleDeviceUevent(&event); + } +} + +void UeventInit() +{ + struct pollfd ufd; + UeventSockInit(); + ufd.events = POLLIN; + ufd.fd = UeventFD(); + while (1) { + ufd.revents = 0; + int ret = poll(&ufd, 1, -1); + if (ret <= 0) { + continue; + } + if (ufd.revents & POLLIN) { + HandleUevent(); + } + } + return; +} + +int main(const int argc, const char **argv) +{ + printf("Uevent demo starting...\n"); + UeventInit(); + return 0; +} diff --git a/services/test/unittest/common/BUILD.gn b/services/test/unittest/common/BUILD.gn index 8214e3a4eddf69685c4b39d17d4f382b93a40e41..a692ab44a0803cf9c4abed127124bd93d64d7f53 100644 --- a/services/test/unittest/common/BUILD.gn +++ b/services/test/unittest/common/BUILD.gn @@ -10,41 +10,49 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -import("//build/lite/config/component/lite_component.gni") -import("//build/lite/config/test.gni") +if (defined(ohos_lite)) { + import("//build/lite/config/component/lite_component.gni") + import("//build/lite/config/test.gni") -unittest("init_test") { - output_extension = "bin" - output_dir = "$root_out_dir/test/unittest/startup" - ldflags = [ - "-lstdc++", - "-lpthread", - "-lm", - ] + unittest("init_test") { + output_extension = "bin" + output_dir = "$root_out_dir/test/unittest/startup" + ldflags = [ + "-lstdc++", + "-lpthread", + "-lm", + ] + defines = ["OHOS_LITE"] + if (storage_type == "emmc") { + defines += [ "USE_EMMC_STORAGE" ] + } - if (storage_type == "emmc") { - defines = [ "USE_EMMC_STORAGE" ] - } - - include_dirs = [ "//base/startup/init_lite/services/include" ] + include_dirs = [ "//base/startup/init_lite/services/include" ] - sources = [ - "//base/startup/init_lite/services/src/init_adapter.c", - "//base/startup/init_lite/services/src/init_cmds.c", - "//base/startup/init_lite/services/src/init_jobs.c", - "//base/startup/init_lite/services/src/init_service.c", - "//base/startup/init_lite/services/src/init_service_manager.c", - "//base/startup/init_lite/services/src/init_signal_handler.c", - "cmd_func_test.cpp", - ] + sources = [ + "//base/startup/init_lite/services/src/init_adapter.c", + "//base/startup/init_lite/services/src/init_cmds.c", + "//base/startup/init_lite/services/src/init_jobs.c", + "//base/startup/init_lite/services/src/init_service.c", + "//base/startup/init_lite/services/src/init_service_manager.c", + "//base/startup/init_lite/services/src/init_signal_handler.c", + "cmd_func_test.cpp", + ] - deps = [ - "//base/startup/syspara_lite/frameworks/parameter:parameter", - "//build/lite/config/component/cJSON:cjson_shared", - "//third_party/bounds_checking_function:libsec_shared", - ] -} + deps = [ + "//base/startup/syspara_lite/frameworks/parameter:parameter", + "//build/lite/config/component/cJSON:cjson_shared", + "//third_party/bounds_checking_function:libsec_shared", + ] + } -group("unittest") { - deps = [ ":init_test" ] + group("unittest") { + deps = [ ":init_test" ] + } +} else { + import("//build/ohos.gni") + sources = [] + group("unittest") { + deps = [] + } } diff --git a/services/test/unittest/common/cmd_func_test.cpp b/services/test/unittest/common/cmd_func_test.cpp index 41eb980e83e778047ed0a6777aca622f0f3f3802..676403b7e43f6c15fa6be53364fabab29840db5d 100644 --- a/services/test/unittest/common/cmd_func_test.cpp +++ b/services/test/unittest/common/cmd_func_test.cpp @@ -135,7 +135,7 @@ public: ** @tc.type: FUNC ** @tc.require: AR000F733F **/ -HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_001, TestSize.Level0) +HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_001, TestSize.Level1) { // do not crash ParseCmdLine(nullptr, nullptr); @@ -147,7 +147,7 @@ HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_001, TestSize.Level0) ** @tc.type: FUNC ** @tc.require: AR000F733F **/ -HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_002, TestSize.Level0) +HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_002, TestSize.Level1) { CmdLine curCmdLine; memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); @@ -175,7 +175,7 @@ HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_002, TestSize.Level0) ** @tc.type: FUNC ** @tc.require: AR000F733F **/ -HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_003, TestSize.Level0) +HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_003, TestSize.Level1) { CmdLine curCmdLine; memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); @@ -193,7 +193,7 @@ HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_003, TestSize.Level0) ** @tc.type: FUNC ** @tc.require: AR000F733F **/ -HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_004, TestSize.Level0) +HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_004, TestSize.Level1) { CmdLine curCmdLine; memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); @@ -234,7 +234,7 @@ HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_004, TestSize.Level0) ** @tc.type: FUNC ** @tc.require: AR000F733E **/ -HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_005, TestSize.Level0) +HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_005, TestSize.Level1) { CmdLine curCmdLine; memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); @@ -266,7 +266,7 @@ HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_005, TestSize.Level0) ** @tc.type: FUNC ** @tc.require: AR000F733E **/ -HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_001, TestSize.Level0) +HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_001, TestSize.Level1) { // do not crash here DoCmd(nullptr); @@ -278,7 +278,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_001, TestSize.Level0) ** @tc.type: FUNC ** @tc.require: AR000F733E **/ -HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_002, TestSize.Level0) +HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_002, TestSize.Level1) { CmdLine curCmdLine; memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); @@ -297,7 +297,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_002, TestSize.Level0) ** @tc.type: FUNC ** @tc.require: AR000F733E **/ -HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_003, TestSize.Level0) +HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_003, TestSize.Level1) { CmdLine curCmdLine; memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); @@ -341,7 +341,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_003, TestSize.Level0) ** @tc.type: FUNC ** @tc.require: AR000F732P **/ -HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_004, TestSize.Level0) +HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_004, TestSize.Level1) { CmdLine curCmdLine; memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); @@ -393,7 +393,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_004, TestSize.Level0) ** @tc.type: FUNC ** @tc.require: AR000F732P **/ -HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_005, TestSize.Level0) +HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_005, TestSize.Level1) { CmdLine curCmdLine; memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); @@ -434,7 +434,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_005, TestSize.Level0) ** @tc.type: FUNC ** @tc.require: AR000F732P **/ -HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_006, TestSize.Level0) +HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_006, TestSize.Level1) { CmdLine curCmdLine; @@ -499,7 +499,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_006, TestSize.Level0) ** @tc.type: FUNC ** @tc.require: AR000F733F **/ -HWTEST_F(StartupInitUTest, cfgCheckStat_001, TestSize.Level0) +HWTEST_F(StartupInitUTest, cfgCheckStat_001, TestSize.Level1) { struct stat fileStat = {0}; EXPECT_EQ(0, stat(CFG_FILE.c_str(), &fileStat)); @@ -764,7 +764,7 @@ static void CheckJobs(const cJSON* fileRoot) ** @tc.type: FUNC ** @tc.require: AR000F733F **/ -HWTEST_F(StartupInitUTest, cfgCheckContent_001, TestSize.Level0) +HWTEST_F(StartupInitUTest, cfgCheckContent_001, TestSize.Level1) { char* fileBuf = ReadFileToBuf(); if (fileBuf == nullptr) { @@ -814,7 +814,7 @@ static void CreateIllegalCfg() * @tc.type: FUNC * @tc.require: AR000F861Q */ -HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_001, TestSize.Level0) +HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_001, TestSize.Level1) { CmdLine curCmdLine; memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); @@ -830,7 +830,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_001, TestSize.Level0) * @tc.type: FUNC * @tc.require: AR000F861Q */ -HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_002, TestSize.Level0) +HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_002, TestSize.Level1) { CmdLine curCmdLine; std::string cmdStr = "loadcfg "; @@ -868,7 +868,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_002, TestSize.Level0) * @tc.type: FUNC * @tc.require: AR000F861Q */ -HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_003, TestSize.Level0) +HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_003, TestSize.Level1) { CmdLine curCmdLine; std::string cmdStr = "loadcfg "; @@ -916,7 +916,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_003, TestSize.Level0) * @tc.type: FUNC * @tc.require: AR000F733F */ -HWTEST_F(StartupInitUTest, cmdJobTest_001, TestSize.Level0) +HWTEST_F(StartupInitUTest, cmdJobTest_001, TestSize.Level1) { // functions do not crash ParseAllJobs(nullptr); @@ -938,7 +938,7 @@ HWTEST_F(StartupInitUTest, cmdJobTest_001, TestSize.Level0) * @tc.type: FUNC * @tc.require: AR000F733F */ -HWTEST_F(StartupInitUTest, cmdJobTest_002, TestSize.Level0) +HWTEST_F(StartupInitUTest, cmdJobTest_002, TestSize.Level1) { std::string cfgJson = "{\"jobs\":[{\"name\":\"pre-init\",\"cmds\":[\"mkdir " + PRE_INIT_DIR + "\"]},{\"name\":\"init\",\"cmds\":[\"mkdir " + INIT_DIR +