mirror of
https://gitee.com/openharmony/startup_init
synced 2024-12-02 16:06:31 +00:00
commit
295989d61b
@ -10,60 +10,109 @@
|
||||
# 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")
|
||||
if (defined(ohos_lite)) {
|
||||
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",
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
"include",
|
||||
"//third_party/cJSON",
|
||||
"//third_party/bounds_checking_function/include",
|
||||
"//base/startup/syspara_lite/interfaces/kits",
|
||||
]
|
||||
|
||||
cflags = [ "-Wall" ]
|
||||
|
||||
deps = [
|
||||
"//base/startup/syspara_lite/frameworks/parameter:parameter",
|
||||
"//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" ]
|
||||
lite_component("init_lite") {
|
||||
features = [ ":init" ]
|
||||
}
|
||||
|
||||
if (ohos_kernel_type == "linux") {
|
||||
defines += [ "NEED_EXEC_RCS_LINUX" ]
|
||||
ldflags += [
|
||||
"-lm",
|
||||
"-lpthread",
|
||||
# feature: init
|
||||
executable("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",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (ohos_build_type == "debug") {
|
||||
group("unittest") {
|
||||
deps = [ "//base/startup/init_lite/services/test/unittest/common:unittest" ]
|
||||
include_dirs = [
|
||||
"include",
|
||||
"//third_party/cJSON",
|
||||
"//third_party/bounds_checking_function/include",
|
||||
"//base/startup/syspara_lite/interfaces/kits",
|
||||
]
|
||||
|
||||
cflags = [ "-Wall" ]
|
||||
|
||||
deps = [
|
||||
"//base/startup/syspara_lite/frameworks/parameter:parameter",
|
||||
"//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" ]
|
||||
}
|
||||
if (ohos_kernel_type == "linux") {
|
||||
defines += [ "NEED_EXEC_RCS_LINUX" ]
|
||||
ldflags += [
|
||||
"-lm",
|
||||
"-lpthread",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (ohos_build_type == "debug") {
|
||||
group("unittest") {
|
||||
deps = [ "//base/startup/init_lite/services/test/unittest/common:unittest" ]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
import("//build/ohos.gni")
|
||||
|
||||
ohos_executable("updaterueventd") {
|
||||
sources = [
|
||||
"src/uevent.c",
|
||||
"src/list.c",
|
||||
]
|
||||
include_dirs = [
|
||||
"include",
|
||||
"//third_party/bounds_checking_function/include",
|
||||
]
|
||||
deps = [
|
||||
"//third_party/bounds_checking_function:libsec_static",
|
||||
]
|
||||
install_enable = true
|
||||
part_name = "updater"
|
||||
}
|
||||
|
||||
ohos_executable("updaterinit") {
|
||||
sources = [
|
||||
"src/main.c",
|
||||
"src/init_cmds.c",
|
||||
"src/init_jobs.c",
|
||||
"src/init_read_cfg.c",
|
||||
"src/init_adapter.c",
|
||||
"src/init_service.c",
|
||||
"src/init_service_manager.c",
|
||||
"src/init_signal_handler.c",
|
||||
"src/device.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"
|
||||
}
|
||||
|
||||
ohos_prebuilt_etc("init.cfg") {
|
||||
source = "//device/hisilicon/hi3516dv300/updater/init.cfg"
|
||||
relative_install_dir = "init"
|
||||
subsystem_name = "updater"
|
||||
}
|
||||
}
|
||||
|
33
services/include/device.h
Executable file
33
services/include/device.h
Executable file
@ -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
|
39
services/include/list.h
Executable file
39
services/include/list.h
Executable file
@ -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
|
58
services/src/device.c
Executable file
58
services/src/device.c
Executable file
@ -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 <sys/sysmacros.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mount.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#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));
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "init_adapter.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
@ -14,7 +14,6 @@
|
||||
*/
|
||||
|
||||
#include "init_cmds.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
@ -24,11 +23,14 @@
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef OHOS_LITE
|
||||
#include <sys/syscall.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/module.h>
|
||||
#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,6 +39,7 @@
|
||||
#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
|
||||
static const char *g_supportCfg[] = {
|
||||
"/patch/fstab.cfg",
|
||||
};
|
||||
@ -48,6 +51,7 @@ static const char* g_supportedCmds[] = {
|
||||
"chown ",
|
||||
"mount ",
|
||||
"loadcfg ",
|
||||
"insmod ",
|
||||
};
|
||||
|
||||
void ParseCmdLine(const char* cmdStr, CmdLine* resCmd)
|
||||
@ -115,7 +119,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 +176,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 +320,90 @@ 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)
|
||||
{
|
||||
int fd = -1;
|
||||
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) {
|
||||
goto out;
|
||||
}
|
||||
} else if (secondPtr != NULL) {
|
||||
if (strncpy_s(options, OPTIONS_SIZE - 1, secondPtr, strlen(secondPtr)) != 0) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
} else { // Only restPtr is option
|
||||
if (restPtr != NULL) {
|
||||
strncpy_s(options, OPTIONS_SIZE - 1, restPtr, strlen(restPtr));
|
||||
}
|
||||
}
|
||||
fd = open(fileName, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
printf("[Init] failed to open %s: %d\n", fileName, errno);
|
||||
goto out;
|
||||
}
|
||||
int rc = syscall(__NR_finit_module, fd, options, flags);
|
||||
if (rc == -1) {
|
||||
printf("[Init] finit_module for %s failed: %d\n", fileName, errno);
|
||||
}
|
||||
out:
|
||||
if (fd > 0) {
|
||||
close(fd);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// format insmod <ko name> [-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");
|
||||
return;
|
||||
}
|
||||
line[count] = '\0';
|
||||
do {
|
||||
if ((p = strtok_r(line, " ", &restPtr)) == NULL) {
|
||||
printf("[Init] debug, cannot get filename\n");
|
||||
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 +490,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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
36
services/src/list.c
Executable file
36
services/src/list.c
Executable file
@ -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;
|
||||
}
|
@ -27,12 +27,19 @@
|
||||
#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()
|
||||
{
|
||||
#ifdef OHOS_LITE
|
||||
char* sysInfo = GetVersionId();
|
||||
if (sysInfo != NULL) {
|
||||
printf("[Init] %s\n", sysInfo);
|
||||
@ -41,6 +48,7 @@ static void PrintSysInfo()
|
||||
return;
|
||||
}
|
||||
printf("[Init] main, GetVersionId failed!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef OHOS_DEBUG
|
||||
@ -72,7 +80,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 +96,7 @@ int main(int argc, char * const argv[])
|
||||
}
|
||||
#endif // OHOS_DEBUG
|
||||
|
||||
// 3. execute rcs
|
||||
// 4. execute rcs
|
||||
ExecuteRcs();
|
||||
|
||||
#ifdef OHOS_DEBUG
|
||||
@ -92,7 +106,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 +116,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));
|
||||
|
812
services/src/uevent.c
Executable file
812
services/src/uevent.c
Executable file
@ -0,0 +1,812 @@
|
||||
/*
|
||||
* 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 <sys/stat.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <poll.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
#include <dirent.h>
|
||||
#include <linux/netlink.h>
|
||||
#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)
|
||||
{
|
||||
struct dirent *de = NULL;
|
||||
int dfd = dirfd(dir);
|
||||
int fd = openat(dfd, "uevent", O_WRONLY);
|
||||
if (fd >= 0) {
|
||||
write(fd, "add\n", TRIGGER_ADDR_SIZE);
|
||||
close(fd);
|
||||
HandleUevent();
|
||||
}
|
||||
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
DIR *dir2 = NULL;
|
||||
if (de->d_type != DT_DIR || de->d_name[0] == '.') {
|
||||
continue;
|
||||
}
|
||||
fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
|
||||
if (fd < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dir2 = fdopendir(fd);
|
||||
if (dir2 == NULL) {
|
||||
close(fd);
|
||||
} else {
|
||||
DoTrigger(dir2);
|
||||
closedir(dir2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Trigger(const char *sysPath)
|
||||
{
|
||||
DIR *dir = opendir(sysPath);
|
||||
if (dir) {
|
||||
DoTrigger(dir);
|
||||
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))];
|
||||
uid_t uid = -1;
|
||||
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) {
|
||||
goto out;
|
||||
}
|
||||
struct ucred *cRed = (struct ucred *)CMSG_DATA(cMsg);
|
||||
uid = cRed->uid;
|
||||
if (uid != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (addr.nl_groups == 0 || addr.nl_pid != 0) {
|
||||
/* ignoring non-kernel or unicast netlink message */
|
||||
goto out;
|
||||
}
|
||||
|
||||
return n;
|
||||
out:
|
||||
bzero(buf, len);
|
||||
errno = -EIO;
|
||||
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 Sanitize(char *s)
|
||||
{
|
||||
const char* accept =
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789"
|
||||
"_-.";
|
||||
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (; *s; s++) {
|
||||
s += strspn(s, accept);
|
||||
if (*s) {
|
||||
*s = '_';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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), "/dev/block/%s/%s", type, device) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
if (uevent->partitionName) {
|
||||
p = strdup(uevent->partitionName);
|
||||
Sanitize(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), "%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));
|
||||
bus->path = strdup(path);
|
||||
bus->pathLen = pathLen;
|
||||
bus->name = bus->path + (name - path);
|
||||
ListAddTail(&g_platformNames, &bus->list);
|
||||
}
|
||||
|
||||
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 void FindCharEnd(const char *parent)
|
||||
{
|
||||
while (*++parent) {
|
||||
if (*parent == '/') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
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/<driver>" */
|
||||
const char *parent = strchr(uevent->path + pDev->pathLen, '/');
|
||||
if (!*parent) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!strncmp(parent, "/usb", DEV_USB)) {
|
||||
/* skip root hub name and device. use device interface */
|
||||
FindCharEnd(parent);
|
||||
if (*parent) {
|
||||
FindCharEnd(parent);
|
||||
}
|
||||
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);
|
||||
} else {
|
||||
goto err;
|
||||
}
|
||||
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, "/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, "/dev/bus/usb/%03d", busId) == -1) {
|
||||
return -1;
|
||||
}
|
||||
MakeDir(devpath, DEFAULT_DIR_MODE);
|
||||
if (snprintf_s(devpath, len, len, "/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, "%s%s", base, name) == -1) {
|
||||
printf("[Init] snprintf_s err \n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
HandleDevice(event, devpath, 0, 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;
|
||||
}
|
@ -21,9 +21,9 @@ unittest("init_test") {
|
||||
"-lpthread",
|
||||
"-lm",
|
||||
]
|
||||
|
||||
defines = ["OHOS_LITE"]
|
||||
if (storage_type == "emmc") {
|
||||
defines = [ "USE_EMMC_STORAGE" ]
|
||||
defines += [ "USE_EMMC_STORAGE" ]
|
||||
}
|
||||
|
||||
include_dirs = [ "//base/startup/init_lite/services/include" ]
|
||||
|
@ -135,7 +135,7 @@ public:
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F733F
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_001, TestSize.Level1)
|
||||
HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_001, TestSize.Level0)
|
||||
{
|
||||
// do not crash
|
||||
ParseCmdLine(nullptr, nullptr);
|
||||
@ -147,7 +147,7 @@ HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_001, TestSize.Level1)
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F733F
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_002, TestSize.Level1)
|
||||
HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_002, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
@ -175,7 +175,7 @@ HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_002, TestSize.Level1)
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F733F
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_003, TestSize.Level1)
|
||||
HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_003, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
@ -193,7 +193,7 @@ HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_003, TestSize.Level1)
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F733F
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_004, TestSize.Level1)
|
||||
HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_004, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
@ -234,7 +234,7 @@ HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_004, TestSize.Level1)
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F733E
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_005, TestSize.Level1)
|
||||
HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_005, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
@ -266,7 +266,7 @@ HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_005, TestSize.Level1)
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F733E
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_001, TestSize.Level1)
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_001, TestSize.Level0)
|
||||
{
|
||||
// do not crash here
|
||||
DoCmd(nullptr);
|
||||
@ -278,7 +278,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_001, TestSize.Level1)
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F733E
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_002, TestSize.Level1)
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_002, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
@ -297,7 +297,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_002, TestSize.Level1)
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F733E
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_003, TestSize.Level1)
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_003, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
@ -341,7 +341,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_003, TestSize.Level1)
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F732P
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_004, TestSize.Level1)
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_004, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
@ -393,7 +393,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_004, TestSize.Level1)
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F732P
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_005, TestSize.Level1)
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_005, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
@ -434,7 +434,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_005, TestSize.Level1)
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F732P
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_006, TestSize.Level1)
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_006, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
|
||||
@ -499,7 +499,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_006, TestSize.Level1)
|
||||
** @tc.type: FUNC
|
||||
** @tc.require: AR000F733F
|
||||
**/
|
||||
HWTEST_F(StartupInitUTest, cfgCheckStat_001, TestSize.Level1)
|
||||
HWTEST_F(StartupInitUTest, cfgCheckStat_001, TestSize.Level0)
|
||||
{
|
||||
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.Level1)
|
||||
HWTEST_F(StartupInitUTest, cfgCheckContent_001, TestSize.Level0)
|
||||
{
|
||||
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.Level1)
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_001, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine));
|
||||
@ -830,7 +830,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_001, TestSize.Level1)
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: AR000F861Q
|
||||
*/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_002, TestSize.Level1)
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_002, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
std::string cmdStr = "loadcfg ";
|
||||
@ -868,7 +868,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_002, TestSize.Level1)
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: AR000F861Q
|
||||
*/
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_003, TestSize.Level1)
|
||||
HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_003, TestSize.Level0)
|
||||
{
|
||||
CmdLine curCmdLine;
|
||||
std::string cmdStr = "loadcfg ";
|
||||
@ -916,7 +916,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_003, TestSize.Level1)
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: AR000F733F
|
||||
*/
|
||||
HWTEST_F(StartupInitUTest, cmdJobTest_001, TestSize.Level1)
|
||||
HWTEST_F(StartupInitUTest, cmdJobTest_001, TestSize.Level0)
|
||||
{
|
||||
// functions do not crash
|
||||
ParseAllJobs(nullptr);
|
||||
@ -938,7 +938,7 @@ HWTEST_F(StartupInitUTest, cmdJobTest_001, TestSize.Level1)
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: AR000F733F
|
||||
*/
|
||||
HWTEST_F(StartupInitUTest, cmdJobTest_002, TestSize.Level1)
|
||||
HWTEST_F(StartupInitUTest, cmdJobTest_002, TestSize.Level0)
|
||||
{
|
||||
std::string cfgJson = "{\"jobs\":[{\"name\":\"pre-init\",\"cmds\":[\"mkdir " +
|
||||
PRE_INIT_DIR + "\"]},{\"name\":\"init\",\"cmds\":[\"mkdir " + INIT_DIR +
|
||||
|
Loading…
Reference in New Issue
Block a user