mirror of
https://gitee.com/openharmony/startup_init
synced 2024-10-07 22:24:31 +00:00
modify for l2 init
This commit is contained in:
parent
2a43725c10
commit
2b19a1cf0b
24
interfaces/innerkits/include/init_socket_api.h
Executable file
24
interfaces/innerkits/include/init_socket_api.h
Executable file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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 INIT_SOCKET_API_H
|
||||
#define INIT_SOCKET_API_H
|
||||
|
||||
#define OHOS_SOCKET_DIR "/dev/unix/socket"
|
||||
#define OHOS_SOCKET_ENV_PREFIX "OHOS_SOCKET_"
|
||||
// parameter is service name
|
||||
int GetControlSocket(const char *name);
|
||||
|
||||
#endif
|
27
interfaces/innerkits/socket/BUILD.gn
Executable file
27
interfaces/innerkits/socket/BUILD.gn
Executable file
@ -0,0 +1,27 @@
|
||||
# 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/ohos.gni")
|
||||
ohos_static_library("libsocket") {
|
||||
sources = [
|
||||
"//base/startup/init_lite/interfaces/innerkits/socket/init_socket_api.c",
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
"//base/startup/init_lite/interfaces/innerkits/include",
|
||||
]
|
||||
|
||||
deps = [
|
||||
]
|
||||
}
|
||||
|
87
interfaces/innerkits/socket/init_socket_api.c
Executable file
87
interfaces/innerkits/socket/init_socket_api.c
Executable file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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_socket_api.h"
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#define N_DEC 10
|
||||
#define MAX_SOCKET_ENV_PREFIX_LEN 64
|
||||
#define MAX_SOCKET_DIR_LEN 128
|
||||
|
||||
static int GetControlFromEnv(char *path)
|
||||
{
|
||||
if (path == NULL) {
|
||||
return -1;
|
||||
}
|
||||
printf("GetControlFromEnv path is %s \n", path);
|
||||
const char *val = getenv(path);
|
||||
if (val == NULL) {
|
||||
printf("test GetControlFromEnv val is null %d\n", errno);
|
||||
return -1;
|
||||
}
|
||||
errno = 0;
|
||||
int fd = strtol(val, NULL, N_DEC);
|
||||
if (errno) {
|
||||
return -1;
|
||||
}
|
||||
printf("test GetControlFromEnv fd is %d \n", fd);
|
||||
if (fcntl(fd, F_GETFD) < 0) {
|
||||
printf("test GetControlFromEnv errno %d \n", errno);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int GetControlSocket(const char *name)
|
||||
{
|
||||
if (name == NULL) {
|
||||
return -1;
|
||||
}
|
||||
char path[MAX_SOCKET_ENV_PREFIX_LEN] = {0};
|
||||
snprintf(path, sizeof(path), OHOS_SOCKET_ENV_PREFIX"%s", name);
|
||||
printf("test GetControlSocket path is %s \n", path);
|
||||
int fd = GetControlFromEnv(path);
|
||||
if (fd < 0) {
|
||||
printf("GetControlFromEnv fail \n");
|
||||
return -1;
|
||||
}
|
||||
struct sockaddr_un addr;
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
int ret = getsockname(fd, (struct sockaddr*)&addr, &addrlen);
|
||||
if (ret < 0) {
|
||||
printf("test GetControlSocket errno %d \n", errno);
|
||||
return -1;
|
||||
}
|
||||
char sockDir[MAX_SOCKET_DIR_LEN] = {0};
|
||||
snprintf(sockDir, sizeof(sockDir), OHOS_SOCKET_DIR"/%s", name);
|
||||
printf("test sockDir %s \n", sockDir);
|
||||
printf("addr.sun_path %s \n", addr.sun_path);
|
||||
if (strncmp(sockDir, addr.sun_path, strlen(sockDir)) == 0) {
|
||||
return fd;
|
||||
}
|
||||
return -1;
|
||||
}
|
10
ohos.build
Executable file
10
ohos.build
Executable file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"subsystem": "startup",
|
||||
"parts": {
|
||||
"init": {
|
||||
"module_list": [
|
||||
"//base/startup/init_lite/services:startup_init"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -25,12 +25,17 @@ if (defined(ohos_lite)) {
|
||||
"src/init_read_cfg.c",
|
||||
"src/init_service.c",
|
||||
"src/init_service_manager.c",
|
||||
"src/init_import.c",
|
||||
"src/init_signal_handler.c",
|
||||
"src/init_utils.c",
|
||||
"src/init_service_socket.c",
|
||||
"src/main.c",
|
||||
"src/init_capability.c",
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
"include",
|
||||
"//base/startup/init_lite/services/include",
|
||||
"//base/startup/init_lite/services/property/include",
|
||||
"//third_party/cJSON",
|
||||
"//third_party/bounds_checking_function/include",
|
||||
"//base/startup/syspara_lite/interfaces/kits",
|
||||
@ -74,7 +79,6 @@ if (defined(ohos_lite)) {
|
||||
}
|
||||
} else {
|
||||
import("//build/ohos.gni")
|
||||
|
||||
ohos_executable("updaterueventd") {
|
||||
sources = [
|
||||
"src/list.c",
|
||||
@ -86,37 +90,66 @@ if (defined(ohos_lite)) {
|
||||
]
|
||||
deps = [ "//third_party/bounds_checking_function:libsec_static" ]
|
||||
install_enable = true
|
||||
part_name = "updater"
|
||||
part_name = "init"
|
||||
}
|
||||
|
||||
ohos_executable("updaterinit") {
|
||||
ohos_executable("init") {
|
||||
sources = [
|
||||
"src/device.c",
|
||||
"src/init_adapter.c",
|
||||
"src/init_cmds.c",
|
||||
"src/init_jobs.c",
|
||||
"src/init_log.c",
|
||||
"src/init_read_cfg.c",
|
||||
"src/init_service.c",
|
||||
"src/init_service_manager.c",
|
||||
"src/init_import.c",
|
||||
"src/init_signal_handler.c",
|
||||
"src/init_utils.c",
|
||||
"src/init_service_socket.c",
|
||||
"src/main.c",
|
||||
"src/init_capability.c",
|
||||
]
|
||||
include_dirs = [
|
||||
"include",
|
||||
"//base/startup/init_lite/services/include/property",
|
||||
"//base/startup/init_lite/services/include/trigger",
|
||||
"//base/startup/init_lite/services/include",
|
||||
"//base/startup/init_lite/services/property/include",
|
||||
"//third_party/cJSON",
|
||||
"//third_party/bounds_checking_function/include",
|
||||
]
|
||||
deps = [
|
||||
"//base/startup/init_lite/services/property:propertyserver",
|
||||
"//base/startup/init_lite/services/property:propertyclient",
|
||||
"//base/startup/init_lite/services/trigger:triggerservice",
|
||||
"//third_party/bounds_checking_function:libsec_static",
|
||||
"//third_party/cJSON:cjson_static",
|
||||
]
|
||||
if (use_musl) {
|
||||
deps += [
|
||||
"//third_party/mksh:sh",
|
||||
"//third_party/toybox:toybox"
|
||||
]
|
||||
}
|
||||
install_enable = true
|
||||
part_name = "updater"
|
||||
part_name = "init"
|
||||
}
|
||||
|
||||
ohos_prebuilt_etc("init.cfg") {
|
||||
source = "//device/hisilicon/hi3516dv300/updater/init.cfg"
|
||||
relative_install_dir = "init"
|
||||
subsystem_name = "updater"
|
||||
part_name = "init"
|
||||
}
|
||||
|
||||
group("startup_init") {
|
||||
deps = [
|
||||
":init.cfg",
|
||||
":init",
|
||||
":updaterueventd",
|
||||
"//base/startup/init_lite/services/trigger:triggerservice",
|
||||
"//base/startup/init_lite/services/property:propertyserver",
|
||||
"//base/startup/init_lite/services/property:propertyclient",
|
||||
"//base/startup/init_lite/services/property:setparam",
|
||||
"//base/startup/init_lite/services/property:getparam"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -21,9 +21,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
|
||||
void MountBasicFs();
|
||||
void CreateDeviceNode();
|
||||
int MakeSocketDir(const char *path, mode_t mode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
|
@ -16,10 +16,10 @@
|
||||
#ifndef BASE_STARTUP_INITLITE_ADAPTER_H
|
||||
#define BASE_STARTUP_INITLITE_ADAPTER_H
|
||||
|
||||
#ifdef __LINUX__
|
||||
#include <linux/capability.h>
|
||||
#else
|
||||
#ifdef OHOS_LITE
|
||||
#include <sys/capability.h>
|
||||
#else
|
||||
#include <linux/capability.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -28,7 +28,7 @@ extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __LINUX__
|
||||
#ifndef OHOS_LITE
|
||||
/* Control the ambient capability set */
|
||||
#ifndef PR_CAP_AMBIENT
|
||||
#define PR_CAP_AMBIENT 47
|
||||
|
25
services/include/init_capability.h
Executable file
25
services/include/init_capability.h
Executable file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 INIT_CAPABILITY_H
|
||||
#define INIT_CAPABILITY_H
|
||||
|
||||
#include "cJSON.h"
|
||||
#include "init_service.h"
|
||||
|
||||
int GetServiceCaps(const cJSON* curArrItem, Service* curServ);
|
||||
|
||||
#endif
|
||||
|
@ -23,9 +23,10 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_CMD_NAME_LEN 10
|
||||
#define MAX_CMD_CONTENT_LEN 128
|
||||
#define MAX_CMD_CNT_IN_ONE_JOB 30
|
||||
|
||||
#define MAX_CMD_CONTENT_LEN 256
|
||||
#define MAX_CMD_CNT_IN_ONE_JOB 200
|
||||
#define MAX_COPY_BUF_SIZE 256
|
||||
#define DEFAULT_COPY_ARGS_CNT 2
|
||||
// one cmd line
|
||||
typedef struct {
|
||||
char name[MAX_CMD_NAME_LEN + 1];
|
||||
@ -35,6 +36,8 @@ typedef struct {
|
||||
void ParseCmdLine(const char* cmdStr, CmdLine* resCmd);
|
||||
void DoCmd(const CmdLine* curCmd);
|
||||
|
||||
void DoCmdByName(const char *name, const char *cmdContent);
|
||||
const char *GetMatchCmd(const char *cmdStr);
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
|
19
services/include/init_import.h
Executable file
19
services/include/init_import.h
Executable file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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_IMPORT_H
|
||||
#define BASE_STARTUP_INITLITE_IMPORT_H
|
||||
#include "cJSON.h"
|
||||
void ParseAllImports(cJSON *root);
|
||||
#endif
|
@ -25,7 +25,7 @@ extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define MAX_JOB_NAME_LEN 32
|
||||
#define MAX_JOB_NAME_LEN 64
|
||||
|
||||
// one job, could have many cmd lines
|
||||
typedef struct {
|
||||
@ -37,7 +37,7 @@ typedef struct {
|
||||
void ParseAllJobs(const cJSON* fileRoot);
|
||||
void DoJob(const char* jobName);
|
||||
void ReleaseAllJobs();
|
||||
|
||||
void DumpAllJobs();
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
|
91
services/include/init_log.h
Executable file
91
services/include/init_log.h
Executable file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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 INIT_LOG_H
|
||||
#define INIT_LOG_H
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef enum StatupLogLevel {
|
||||
STARTUP_DEBUG = 0,
|
||||
STARTUP_INFO,
|
||||
STARTUP_WARN,
|
||||
STARTUP_ERROR,
|
||||
STARTUP_FATAL
|
||||
} StatupLogLevel;
|
||||
|
||||
#define __FILE_NAME__ (strrchr((__FILE__), '/') ? strrchr((__FILE__), '/') + 1 : (__FILE__))
|
||||
|
||||
#ifdef OHOS_LITE
|
||||
#define INIT_LOGE(format, ...) printf("%s %d: "format, __FILE_NAME__, __LINE__, ##__VA_ARGS__)
|
||||
#define INIT_LOGW(format, ...) printf("%s %d: "format, __FILE_NAME__, __LINE__, ##__VA_ARGS__)
|
||||
#define INIT_LOGI(format, ...) printf("%s %d: "format, __FILE_NAME__, __LINE__, ##__VA_ARGS__)
|
||||
#define INIT_LOGD(format, ...) printf("%s %d: "format, __FILE_NAME__, __LINE__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define INIT_LOGE(format, ...) printf("%s %d: "format, __FILE_NAME__, __LINE__, ##__VA_ARGS__)
|
||||
#define INIT_LOGW(format, ...) printf("%s %d: "format, __FILE_NAME__, __LINE__, ##__VA_ARGS__)
|
||||
#define INIT_LOGI(format, ...) printf("%s %d: "format, __FILE_NAME__, __LINE__, ##__VA_ARGS__)
|
||||
#define INIT_LOGD(format, ...) printf("%s %d: "format, __FILE_NAME__, __LINE__, ##__VA_ARGS__)
|
||||
void InitLog(int logLevel, const char *fileName, int line, const char *fmt, ...);
|
||||
void Logger(StatupLogLevel level, const char *format, ...);
|
||||
#endif
|
||||
|
||||
|
||||
#define INIT_ERROR_CHECK(ret, statement, format, ...) \
|
||||
if (!(ret)) { \
|
||||
INIT_LOGE(format, ##__VA_ARGS__); \
|
||||
statement; \
|
||||
}
|
||||
|
||||
#define INIT_CHECK_ONLY_RETURN(ret, statement) \
|
||||
if (!(ret)) { \
|
||||
statement; \
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_HILOG
|
||||
#include "hilog/log.h"
|
||||
|
||||
static constexpr OHOS::HiviewDFX::HiLogLabel STARTUP_LABEL = {LOG_CORE, 0, "STARTUP"};
|
||||
|
||||
StatupLogLevel level_;
|
||||
int JudgeLevel(const StatupLogLevel level) { return return; }
|
||||
|
||||
#define STARTUP_LOG(LEVEL, LABEL, Level, fmt, ...) \
|
||||
Logger(__FILE_NAME__, (__LINE__), fmt, ##__VA_ARGS__); \
|
||||
if (JudgeLevel(StatupLogLevel::LEVEL)) \
|
||||
OHOS::HiviewDFX::HiLog::Level(STARTUP_LABEL, "[%{public}s(%{public}d)] " fmt, \
|
||||
__FILE_NAME__, __LINE__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define STARTUP_LOG(LEVEL, LABEL, Level, fmt, ...) \
|
||||
printf("[%s][%s:%d] " fmt "\n", LABEL, __FILE_NAME__, __LINE__, ##__VA_ARGS__);
|
||||
#endif
|
||||
|
||||
#define STARTUP_LOGI(LABEL, fmt, ...) STARTUP_LOG(STARTUP_INFO, LABEL, Info, fmt, ##__VA_ARGS__)
|
||||
#define STARTUP_LOGE(LABEL, fmt, ...) STARTUP_LOG(STARTUP_ERROR, LABEL, Error, fmt, ##__VA_ARGS__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // INIT_LOG_H
|
@ -22,9 +22,12 @@ extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define INIT_CONFIGURATION_FILE "/etc/init.cfg"
|
||||
#define INIT_CONFIGURATION_FILE "/init.cfg"
|
||||
#define MAX_PATH_ARGS_CNT 20
|
||||
#define MAX_ONE_ARG_LEN 200 // max length of one param/path
|
||||
|
||||
void InitReadCfg();
|
||||
void ParseInitCfg(const char *configFile);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
|
@ -17,6 +17,8 @@
|
||||
#define BASE_STARTUP_INITLITE_SERVICE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "init_cmds.h"
|
||||
#include "init_service_socket.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
@ -34,8 +36,11 @@ extern "C" {
|
||||
#define SERVICE_ATTR_NEED_RESTART 0x004 // will restart in the near future
|
||||
#define SERVICE_ATTR_NEED_STOP 0x008 // will stop in reap
|
||||
#define SERVICE_ATTR_IMPORTANT 0x010 // will reboot if it crash
|
||||
#define SERVICE_ATTR_CRITICAL 0x020 // critical, will reboot if it crash 4 times in 4 minutes
|
||||
#define SERVICE_ATTR_DISABLED 0x040 // disabled
|
||||
|
||||
#define MAX_SERVICE_NAME 32
|
||||
#define MAX_WRITEPID_FILES 100
|
||||
|
||||
#define CAP_NUM 2
|
||||
|
||||
@ -43,12 +48,17 @@ extern "C" {
|
||||
|
||||
typedef struct {
|
||||
uid_t uID;
|
||||
gid_t *gIDs;
|
||||
unsigned int gidsCnt;
|
||||
gid_t *gIDArray;
|
||||
int gIDCnt;
|
||||
unsigned int *caps;
|
||||
unsigned int capsCnt;
|
||||
} Perms;
|
||||
|
||||
struct OnRestartCmd {
|
||||
CmdLine *cmdLine;
|
||||
int cmdNum;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
char name[MAX_SERVICE_NAME + 1];
|
||||
char** pathArgs;
|
||||
@ -56,8 +66,13 @@ typedef struct {
|
||||
int pid;
|
||||
int crashCnt;
|
||||
time_t firstCrashTime;
|
||||
int criticalCrashCnt; // count for critical
|
||||
time_t firstCriticalCrashTime; // record for critical
|
||||
char *writepidFiles[MAX_WRITEPID_FILES];
|
||||
unsigned int attribute;
|
||||
Perms servPerm;
|
||||
struct OnRestartCmd *onRestart;
|
||||
struct ServiceSocket *socketCfg;
|
||||
} Service;
|
||||
|
||||
int ServiceStart(Service *service);
|
||||
|
@ -17,6 +17,7 @@
|
||||
#define BASE_STARTUP_INITLITE_SERVICEMANAGER_H
|
||||
|
||||
#include "init_service.h"
|
||||
#include "cJSON.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
@ -24,10 +25,23 @@ extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define UID_STR_IN_CFG "uid"
|
||||
#define GID_STR_IN_CFG "gid"
|
||||
#define ONCE_STR_IN_CFG "once"
|
||||
#define IMPORTANT_STR_IN_CFG "importance"
|
||||
#define BIN_SH_NOT_ALLOWED "/bin/sh"
|
||||
#define CRITICAL_STR_IN_CFG "critical"
|
||||
#define DISABLED_STR_IN_CFG "disabled"
|
||||
|
||||
#define MAX_SERVICES_CNT_IN_FILE 100
|
||||
|
||||
void RegisterServices(Service* services, int servicesCnt);
|
||||
void StartServiceByName(const char* serviceName);
|
||||
void StopServiceByName(const char* serviceName);
|
||||
void StopAllServices();
|
||||
void ReapServiceByPID(int pid);
|
||||
void ParseAllServices(const cJSON* fileRoot);
|
||||
void DumpAllServices();
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
|
38
services/include/init_service_socket.h
Executable file
38
services/include/init_service_socket.h
Executable file
@ -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.
|
||||
*/
|
||||
|
||||
#ifndef INIT_SERVICE_SOCKET_
|
||||
#define INIT_SERVICE_SOCKET_
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct ServiceSocket;
|
||||
struct ServiceSocket
|
||||
{
|
||||
char *name; // service name
|
||||
int type; // socket type
|
||||
uid_t uid; // uid
|
||||
gid_t gid; // gid
|
||||
bool passcred; // setsocketopt
|
||||
mode_t perm; // Setting permissions
|
||||
struct ServiceSocket *next;
|
||||
};
|
||||
|
||||
int DoCreateSocket(struct ServiceSocket *sockopt);
|
||||
|
||||
#endif
|
41
services/include/init_utils.h
Executable file
41
services/include/init_utils.h
Executable file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 INIT_UTILS_H
|
||||
#define INIT_UTILS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct CmdArgs {
|
||||
int argc;
|
||||
char **argv;
|
||||
};
|
||||
|
||||
struct CmdArgs* GetCmd(const char *cmdContent, const char *delim);
|
||||
void FreeCmd(struct CmdArgs **cmd);
|
||||
int DecodeUid(const char *name);
|
||||
void CheckAndCreateDir(const char *fileName);
|
||||
char* ReadFileToBuf(const char *configFile);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif // INIT_UTILS_H
|
@ -1,10 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Huawei Device Co., Ltd.
|
||||
* 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
|
||||
* 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,
|
||||
@ -22,10 +22,13 @@ extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct ListNode {
|
||||
typedef struct ListNode {
|
||||
struct ListNode *next;
|
||||
struct ListNode *prev;
|
||||
};
|
||||
} ListNode;
|
||||
|
||||
#define ListEmpty(node) ((node).next == &(node) && (node).prev == &(node))
|
||||
#define ListEntry(ptr, type, member) (type *)((char *)(ptr) - offsetof(type, member))
|
||||
|
||||
void ListInit(struct ListNode *list);
|
||||
void ListAddTail(struct ListNode *list, struct ListNode *item);
|
||||
|
91
services/include/property/property.h
Executable file
91
services/include/property/property.h
Executable file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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_PROPERTY_H
|
||||
#define BASE_STARTUP_PROPERTY_H
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define PROPERTY_VALUE_LEN_MAX 96
|
||||
typedef u_int32_t PropertyHandle;
|
||||
|
||||
typedef struct {
|
||||
u_int32_t serial;
|
||||
PropertyHandle handle;
|
||||
char value[PROPERTY_VALUE_LEN_MAX];
|
||||
} PropertyCacheNode;
|
||||
|
||||
typedef const char *(*PropertyEvaluatePtr)(u_int32_t cacheCount, PropertyCacheNode *node);
|
||||
|
||||
typedef struct {
|
||||
pthread_mutex_t lock;
|
||||
u_int32_t serial;
|
||||
u_int32_t cacheCount;
|
||||
PropertyEvaluatePtr evaluate;
|
||||
PropertyCacheNode *cacheNode;
|
||||
} PropertyCache;
|
||||
|
||||
/**
|
||||
* 对外接口
|
||||
* 设置属性,主要用于其他进程使用,通过管道修改属性。
|
||||
*
|
||||
*/
|
||||
int SystemSetParameter(const char *name, const char *value);
|
||||
|
||||
/**
|
||||
* 对外接口
|
||||
* 查询属性,主要用于其他进程使用,需要给定足够的内存保存属性。
|
||||
* 如果 value == null,获取value的长度
|
||||
* 否则value的大小认为是len
|
||||
*
|
||||
*/
|
||||
int SystemGetParameter(const char *name, char *value, unsigned int *len);
|
||||
|
||||
/**
|
||||
* 对外接口
|
||||
* 查询属性,主要用于其他进程使用,需要给定足够的内存保存属性。
|
||||
* 如果 value == null,获取value的长度
|
||||
* 否则value的大小认为是len
|
||||
*
|
||||
*/
|
||||
int SystemGetParameterName(PropertyHandle handle, char *name, unsigned int len);
|
||||
|
||||
/**
|
||||
* 对外接口
|
||||
* 遍历所有属性。
|
||||
*
|
||||
*/
|
||||
int SystemTraversalParameter(void (*traversalParameter)(PropertyHandle handle, void* cookie), void* cookie);
|
||||
|
||||
/**
|
||||
* 对外接口
|
||||
* 获取属性值。
|
||||
*
|
||||
*/
|
||||
int SystemGetParameterValue(PropertyHandle handle, char *value, unsigned int *len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
47
services/include/trigger/trigger.h
Executable file
47
services/include/trigger/trigger.h
Executable file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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_TRIGER_H
|
||||
#define BASE_STARTUP_TRIGER_H
|
||||
#include <stdio.h>
|
||||
#include "cJSON.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
EVENT_PROPERTY, // 属性修改事件
|
||||
EVENT_BOOT
|
||||
} EventType;
|
||||
|
||||
void PostTrigger(EventType type, void *content, u_int32_t contentLen);
|
||||
|
||||
void PostPropertyTrigger(const char *name, const char *value);
|
||||
|
||||
void StartTriggerService();
|
||||
|
||||
int ParseTriggerConfig(cJSON *fileRoot);
|
||||
|
||||
void DoTriggerExec(const char *content);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
106
services/property/BUILD.gn
Executable file
106
services/property/BUILD.gn
Executable file
@ -0,0 +1,106 @@
|
||||
# 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.
|
||||
|
||||
import("//build/ohos.gni")
|
||||
|
||||
ohos_static_library("propertyserver") {
|
||||
sources = [
|
||||
"manager/property_manager.c",
|
||||
"manager/property_trie.c",
|
||||
"manager/property_cache.c",
|
||||
"service/property_service.c",
|
||||
"service/property_persist.c",
|
||||
"//base/startup/init_lite/services/src/init_utils.c",
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
"include",
|
||||
"//base/startup/init_lite/services/include/property",
|
||||
"//base/startup/init_lite/services/include/trigger",
|
||||
"//base/startup/init_lite/services/include",
|
||||
"//third_party/libuv/include",
|
||||
"//third_party/cJSON",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"//third_party/libuv:uv_static",
|
||||
"//base/startup/init_lite/services/trigger:triggerservice",
|
||||
"//third_party/bounds_checking_function:libsec_static",
|
||||
]
|
||||
part_name = "init"
|
||||
subsystem_name = "startup"
|
||||
}
|
||||
|
||||
ohos_static_library("propertyclient") {
|
||||
sources = [
|
||||
"manager/property_manager.c",
|
||||
"client/property_request.c",
|
||||
"manager/property_trie.c",
|
||||
"manager/property_cache.c",
|
||||
"//base/startup/init_lite/services/src/init_utils.c",
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
"include",
|
||||
"//base/startup/init_lite/services/include/property",
|
||||
"//base/startup/init_lite/services/include/trigger",
|
||||
"//base/startup/init_lite/services/include",
|
||||
"//third_party/libuv/include",
|
||||
"//third_party/cJSON",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"//third_party/libuv:uv_static",
|
||||
"//third_party/bounds_checking_function:libsec_static",
|
||||
]
|
||||
part_name = "init"
|
||||
subsystem_name = "startup"
|
||||
}
|
||||
|
||||
ohos_executable("getparam") {
|
||||
sources = [
|
||||
"cmd/property_get.c",
|
||||
]
|
||||
include_dirs = [
|
||||
"include",
|
||||
"//base/startup/init_lite/services/include/property",
|
||||
"//base/startup/init_lite/services/include/trigger",
|
||||
"//base/startup/init_lite/services/include",
|
||||
]
|
||||
deps = [
|
||||
"//base/startup/init_lite/services/property:propertyclient",
|
||||
"//third_party/bounds_checking_function:libsec_static",
|
||||
"//third_party/cJSON:cjson_static",
|
||||
]
|
||||
install_enable = true
|
||||
part_name = "init"
|
||||
}
|
||||
|
||||
ohos_executable("setparam") {
|
||||
sources = [
|
||||
"cmd/property_set.c",
|
||||
]
|
||||
include_dirs = [
|
||||
"include",
|
||||
"//base/startup/init_lite/services/include/property",
|
||||
"//base/startup/init_lite/services/include/trigger",
|
||||
"//base/startup/init_lite/services/include",
|
||||
]
|
||||
deps = [
|
||||
"//base/startup/init_lite/services/property:propertyclient",
|
||||
"//third_party/bounds_checking_function:libsec_static",
|
||||
"//third_party/cJSON:cjson_static",
|
||||
]
|
||||
install_enable = true
|
||||
part_name = "init"
|
||||
}
|
156
services/property/client/property_request.c
Executable file
156
services/property/client/property_request.c
Executable file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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 "property_request.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "property_manager.h"
|
||||
#include "uv.h"
|
||||
|
||||
#define LABEL "Client"
|
||||
#define BUFFER_SIZE 200
|
||||
#define PropertyEntry(ptr, type, member) (type *)((char *)(ptr) - offsetof(type, member))
|
||||
|
||||
static PropertyWorkSpace g_propertyWorkSpaceReadOnly = {ATOMIC_VAR_INIT(0), {}, {}, {}};
|
||||
|
||||
static void OnWrite(uv_write_t* req, int status)
|
||||
{
|
||||
PROPERTY_LOGI("OnWrite status %d", status);
|
||||
}
|
||||
|
||||
static void OnReceiveAlloc(uv_handle_t* handle, size_t suggestedSize, uv_buf_t* buf)
|
||||
{
|
||||
// 这里需要按实际回复大小申请内存,不需要大内存
|
||||
buf->base = (char *)malloc(sizeof(ResponseMsg));
|
||||
buf->len = suggestedSize;
|
||||
PROPERTY_LOGI("OnReceiveAlloc handle %p %zu", handle, suggestedSize);
|
||||
}
|
||||
|
||||
static void OnReceiveResponse(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf)
|
||||
{
|
||||
RequestNode *req = PropertyEntry(handle, RequestNode, handle);
|
||||
PROPERTY_LOGI("OnReceiveResponse %p", handle);
|
||||
if (nread <= 0 || buf == NULL || buf->base == NULL) {
|
||||
free(buf->base);
|
||||
uv_close((uv_handle_t*)handle, NULL);
|
||||
uv_stop(req->loop);
|
||||
return;
|
||||
}
|
||||
ResponseMsg *response = (ResponseMsg *)(buf->base);
|
||||
PROPERTY_CHECK(response != NULL, return, "The response is null");
|
||||
PROPERTY_LOGI("OnReceiveResponse %p cmd %d result: %d", handle, response->type, response->result);
|
||||
switch (response->type) {
|
||||
case SET_PROPERTY:
|
||||
req->result = response->result;
|
||||
break;
|
||||
default:
|
||||
PROPERTY_LOGE("not supported the command: %d", response->type);
|
||||
break;
|
||||
}
|
||||
|
||||
PROPERTY_LOGE("Close handle %p", handle);
|
||||
free(buf->base);
|
||||
uv_close((uv_handle_t*)handle, NULL);
|
||||
uv_stop(req->loop);
|
||||
}
|
||||
|
||||
static void OnConnection(uv_connect_t *connect, int status)
|
||||
{
|
||||
PROPERTY_CHECK(status >= 0, return, "Failed to conntect status %s", uv_strerror(status));
|
||||
uv_write_t wr;
|
||||
RequestNode *request = PropertyEntry(connect, RequestNode, connect);
|
||||
PROPERTY_LOGI("Connect to server handle %p", &(request->handle));
|
||||
uv_buf_t buf = uv_buf_init((char*)&request->msg, request->msg.contentSize + sizeof(request->msg));
|
||||
int ret = uv_write2(&wr, (uv_stream_t*)&(request->handle), &buf, 1, (uv_stream_t*)&(request->handle), OnWrite);
|
||||
PROPERTY_CHECK(ret >= 0, return, "Failed to uv_write2 porperty");
|
||||
|
||||
// read result
|
||||
ret = uv_read_start((uv_stream_t*)&(request->handle), OnReceiveAlloc, OnReceiveResponse);
|
||||
PROPERTY_CHECK(ret >= 0, return, "Failed to uv_read_start response");
|
||||
}
|
||||
|
||||
static int StartRequest(int cmd, RequestNode *request)
|
||||
{
|
||||
PROPERTY_CHECK(request != NULL, return -1, "Invalid request");
|
||||
request->result = -1;
|
||||
request->msg.type = cmd;
|
||||
request->loop = uv_loop_new();
|
||||
uv_pipe_init(request->loop, &request->handle, 1);
|
||||
uv_pipe_connect(&request->connect, &request->handle, PIPE_NAME, OnConnection);
|
||||
uv_run(request->loop, UV_RUN_DEFAULT);
|
||||
int result = request->result;
|
||||
free(request);
|
||||
return result;
|
||||
}
|
||||
|
||||
int SystemSetParameter(const char *name, const char *value)
|
||||
{
|
||||
PROPERTY_CHECK(name != NULL && value != NULL, return -1, "Invalid param");
|
||||
int ret = CheckPropertyName(name, 0);
|
||||
PROPERTY_CHECK(ret == 0, return ret, "Illegal property name");
|
||||
|
||||
PROPERTY_LOGI("StartRequest %s", name);
|
||||
u_int32_t msgSize = sizeof(RequestMsg) + strlen(name) + strlen(value) + 2;
|
||||
RequestNode *request = (RequestNode *)malloc(sizeof(RequestNode) + msgSize);
|
||||
PROPERTY_CHECK(request != NULL, return -1, "Failed to malloc for connect");
|
||||
|
||||
// 带字符串结束符
|
||||
int contentSize = BuildPropertyContent(request->msg.content, msgSize - sizeof(RequestMsg), name, value);
|
||||
PROPERTY_CHECK(contentSize > 0, return -1, "Failed to copy porperty");
|
||||
request->msg.contentSize = contentSize;
|
||||
return StartRequest(SET_PROPERTY, request);
|
||||
}
|
||||
|
||||
int SystemGetParameter(const char *name, char *value, unsigned int *len)
|
||||
{
|
||||
PROPERTY_CHECK(name != NULL && len != NULL, return -1, "The name or value is null");
|
||||
InitPropertyWorkSpace(&g_propertyWorkSpaceReadOnly, 1, NULL);
|
||||
|
||||
PropertyHandle handle = 0;
|
||||
int ret = ReadPropertyWithCheck(&g_propertyWorkSpaceReadOnly, name, &handle);
|
||||
PROPERTY_CHECK(ret == 0, return ret, "Can not get param for %s", name);
|
||||
return ReadPropertyValue(&g_propertyWorkSpaceReadOnly, handle, value, len);
|
||||
}
|
||||
|
||||
int SystemGetParameterName(PropertyHandle handle, char *name, unsigned int len)
|
||||
{
|
||||
PROPERTY_CHECK(name != NULL && handle != 0, return -1, "The name is null");
|
||||
InitPropertyWorkSpace(&g_propertyWorkSpaceReadOnly, 1, NULL);
|
||||
return ReadPropertyName(&g_propertyWorkSpaceReadOnly, handle, name, len);
|
||||
}
|
||||
|
||||
int SystemGetParameterValue(PropertyHandle handle, char *value, unsigned int *len)
|
||||
{
|
||||
PROPERTY_CHECK(len != NULL && handle != 0, return -1, "The value is null");
|
||||
InitPropertyWorkSpace(&g_propertyWorkSpaceReadOnly, 1, NULL);
|
||||
return ReadPropertyValue(&g_propertyWorkSpaceReadOnly, handle, value, len);
|
||||
}
|
||||
|
||||
int SystemTraversalParameter(void (*traversalParameter)(PropertyHandle handle, void* cookie), void* cookie)
|
||||
{
|
||||
PROPERTY_CHECK(traversalParameter != NULL, return -1, "The param is null");
|
||||
InitPropertyWorkSpace(&g_propertyWorkSpaceReadOnly, 1, NULL);
|
||||
return TraversalProperty(&g_propertyWorkSpaceReadOnly, traversalParameter, cookie);
|
||||
}
|
||||
|
||||
const char *SystemDetectPropertyChange(PropertyCache *cache,
|
||||
PropertyEvaluatePtr evaluate, u_int32_t count, const char *properties[][2])
|
||||
{
|
||||
PROPERTY_CHECK(cache != NULL && evaluate != NULL && properties != NULL, return NULL, "The param is null");
|
||||
return DetectPropertyChange(&g_propertyWorkSpaceReadOnly, cache, evaluate, count, properties);
|
||||
}
|
54
services/property/cmd/property_get.c
Executable file
54
services/property/cmd/property_get.c
Executable file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include "property.h"
|
||||
|
||||
#define HELP_PARAM "--help"
|
||||
#define BUFFER_SIZE 256
|
||||
|
||||
static void ProcessParam(PropertyHandle handle, void* cookie)
|
||||
{
|
||||
SystemGetParameterName(handle, (char*)cookie, BUFFER_SIZE);
|
||||
u_int32_t size = BUFFER_SIZE;
|
||||
SystemGetParameterValue(handle, ((char*)cookie) + BUFFER_SIZE, &size);
|
||||
printf("\t%s=%s \n", (char*)cookie, ((char*)cookie) + BUFFER_SIZE);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc == 1) { // 显示所有的记录
|
||||
char value[BUFFER_SIZE + BUFFER_SIZE] = {0};
|
||||
SystemTraversalParameter(ProcessParam, (void*)value);
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && strncmp(argv[1], HELP_PARAM, strlen(HELP_PARAM)) == 0) { // 显示帮助
|
||||
printf("usage: getprop NAME VALUE\n");
|
||||
return 0;
|
||||
}
|
||||
if (argc != 2) {
|
||||
printf("usage: getprop NAME VALUE\n");
|
||||
return 0;
|
||||
}
|
||||
char value[BUFFER_SIZE] = {0};
|
||||
u_int32_t size = BUFFER_SIZE;
|
||||
int ret = SystemGetParameter(argv[1], value, &size);
|
||||
if (ret == 0) {
|
||||
printf("getparm %s %s \n", argv[1], value);
|
||||
} else {
|
||||
printf("getparm %s %s fail\n", argv[1], value);
|
||||
}
|
||||
}
|
39
services/property/cmd/property_set.c
Executable file
39
services/property/cmd/property_set.c
Executable file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "property.h"
|
||||
|
||||
#define HELP_PARAM "--help"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc == 1 || argc > 3) {
|
||||
printf("setparm: Need 2 arguments (see \"setparm --help\")\n");
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && strncmp(argv[1], HELP_PARAM, strlen(HELP_PARAM)) == 0) {
|
||||
printf("usage: setprop NAME VALUE\n");
|
||||
return 0;
|
||||
}
|
||||
int ret = SystemSetParameter(argv[1], argv[2]);
|
||||
if (ret == 0) {
|
||||
printf("setparm %s %s success\n", argv[1], argv[2]);
|
||||
} else {
|
||||
printf("setparm %s %s fail\n", argv[1], argv[2]);
|
||||
}
|
||||
}
|
165
services/property/include/property_manager.h
Executable file
165
services/property/include/property_manager.h
Executable file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* 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_PROPERTY_MANAGER_H
|
||||
#define BASE_STARTUP_PROPERTY_MANAGER_H
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "init_log.h"
|
||||
#include "property.h"
|
||||
#include "property_trie.h"
|
||||
#include "securec.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
PROPERTY_CODE_INVALID_PARAM = 100,
|
||||
PROPERTY_CODE_INVALID_NAME,
|
||||
PROPERTY_CODE_INVALID_VALUE,
|
||||
PROPERTY_CODE_REACHED_MAX,
|
||||
PROPERTY_CODE_PERMISSION_DENIED,
|
||||
PROPERTY_CODE_READ_ONLY_PROPERTY,
|
||||
PROPERTY_CODE_NOT_SUPPORT,
|
||||
PROPERTY_CODE_ERROR_MAP_FILE,
|
||||
PROPERTY_CODE_NOT_FOUND_PROP,
|
||||
PROPERTY_CODE_NOT_INIT
|
||||
} PROPERTY_CODE;
|
||||
|
||||
#define IS_READY_ONLY(name) strncmp((name), "ro.", strlen("ro.")) == 0
|
||||
#define LABEL_STRING_LEN 128
|
||||
|
||||
#ifdef STARTUP_LOCAL
|
||||
#define PIPE_NAME "/tmp/propertyservice.sock"
|
||||
#define PROPERTY_STORAGE_PATH "/media/sf_ubuntu/test/__properties__/property_storage"
|
||||
#define PROPERTY_PERSIST_PATH "/media/sf_ubuntu/test/property/persist_properties.property"
|
||||
#define PROPERTY_INFO_PATH "/media/sf_ubuntu/test/__properties__/property_info"
|
||||
#else
|
||||
#define PIPE_NAME "/dev/unix/socket/PropertyService"
|
||||
#define PROPERTY_STORAGE_PATH "/dev/__properties__/property_storage"
|
||||
#define PROPERTY_PERSIST_PATH "/data/property/persist_properties.property"
|
||||
#define PROPERTY_INFO_PATH "/dev/__properties__/property_info"
|
||||
#endif
|
||||
|
||||
#define SUBSTR_INFO_NAME 0
|
||||
#define SUBSTR_INFO_LABEL 1
|
||||
#define SUBSTR_INFO_TYPE 2
|
||||
#define SUBSTR_INFO_MAX 4
|
||||
|
||||
#define WORKSPACE_FLAGS_INIT 0x01
|
||||
#define WORKSPACE_FLAGS_LOADED 0x02
|
||||
|
||||
#define PROPERTY_LOGI(fmt, ...) STARTUP_LOGI(LABEL, fmt, ##__VA_ARGS__)
|
||||
#define PROPERTY_LOGE(fmt, ...) STARTUP_LOGE(LABEL, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define PROPERTY_CHECK(retCode, exper, ...) \
|
||||
if (!(retCode)) { \
|
||||
PROPERTY_LOGE(__VA_ARGS__); \
|
||||
exper; \
|
||||
}
|
||||
|
||||
#define futex(addr1, op, val, rel, addr2, val3) \
|
||||
syscall(SYS_futex, addr1, op, val, rel, addr2, val3)
|
||||
#define futex_wait_always(addr1) \
|
||||
syscall(SYS_futex, addr1, FUTEX_WAIT, *(int*)(addr1), 0, 0, 0)
|
||||
#define futex_wake_single(addr1) \
|
||||
syscall(SYS_futex, addr1, FUTEX_WAKE, 1, 0, 0, 0)
|
||||
|
||||
typedef struct UserCred {
|
||||
pid_t pid;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
} UserCred;
|
||||
|
||||
typedef struct {
|
||||
char label[LABEL_STRING_LEN];
|
||||
UserCred cred;
|
||||
} PropertySecurityLabel;
|
||||
|
||||
typedef struct PropertyAuditData {
|
||||
const UserCred *cr;
|
||||
const char *name;
|
||||
} PropertyAuditData;
|
||||
|
||||
typedef struct {
|
||||
atomic_uint_least32_t flags;
|
||||
WorkSpace propertyLabelSpace;
|
||||
WorkSpace propertySpace;
|
||||
PropertySecurityLabel label;
|
||||
} PropertyWorkSpace;
|
||||
|
||||
typedef struct {
|
||||
atomic_uint_least32_t flags;
|
||||
WorkSpace persistWorkSpace;
|
||||
} PropertyPersistWorkSpace;
|
||||
|
||||
typedef struct {
|
||||
char value[128];
|
||||
} SubStringInfo;
|
||||
|
||||
int InitPropertyWorkSpace(PropertyWorkSpace *workSpace, int onlyRead, const char *context);
|
||||
void ClosePropertyWorkSpace(PropertyWorkSpace *workSpace);
|
||||
|
||||
int ReadPropertyWithCheck(PropertyWorkSpace *workSpace, const char *name, PropertyHandle *handle);
|
||||
int ReadPropertyValue(PropertyWorkSpace *workSpace, PropertyHandle handle, char *value, u_int32_t *len);
|
||||
int ReadPropertyName(PropertyWorkSpace *workSpace, PropertyHandle handle, char *name, u_int32_t len);
|
||||
u_int32_t ReadPropertySerial(PropertyWorkSpace *workSpace, PropertyHandle handle);
|
||||
|
||||
int AddProperty(WorkSpace *workSpace, const char *name, const char *value);
|
||||
int WriteProperty(WorkSpace *workSpace, const char *name, const char *value);
|
||||
int WritePropertyWithCheck(PropertyWorkSpace *workSpace,
|
||||
const PropertySecurityLabel *srcLabel, const char *name, const char *value);
|
||||
int WritePropertyInfo(PropertyWorkSpace *workSpace, SubStringInfo *info, int subStrNumber);
|
||||
|
||||
int CheckPropertyValue(WorkSpace *workSpace, const TrieDataNode *node, const char *name, const char *value);
|
||||
int CheckPropertyName(const char *name, int propInfo);
|
||||
int CanReadProperty(PropertyWorkSpace *workSpace, u_int32_t labelIndex, const char *name);
|
||||
int CanWriteProperty(PropertyWorkSpace *workSpace,
|
||||
const PropertySecurityLabel *srcLabel, const TrieDataNode *node, const char *name, const char *value);
|
||||
|
||||
int CheckMacPerms(PropertyWorkSpace *workSpace,
|
||||
const PropertySecurityLabel *srcLabel, const char *name, u_int32_t labelIndex);
|
||||
int CheckControlPropertyPerms(PropertyWorkSpace *workSpace,
|
||||
const PropertySecurityLabel *srcLabel, const char *name, const char *value);
|
||||
|
||||
int GetSubStringInfo(const char *buff, u_int32_t buffLen, char delimiter, SubStringInfo *info, int subStrNumber);
|
||||
int BuildPropertyContent(char *content, u_int32_t contentSize, const char *name, const char *value);
|
||||
PropertyWorkSpace *GetPropertyWorkSpace();
|
||||
|
||||
typedef void (*TraversalParamPtr)(PropertyHandle handle, void* context);
|
||||
typedef struct {
|
||||
TraversalParamPtr traversalParamPtr;
|
||||
void *context;
|
||||
} PropertyTraversalContext;
|
||||
int TraversalProperty(PropertyWorkSpace *workSpace, TraversalParamPtr walkFunc, void *cookie);
|
||||
|
||||
int InitPersistPropertyWorkSpace(const char *context);
|
||||
int RefreshPersistProperties(PropertyWorkSpace *workSpace, const char *context);
|
||||
void ClosePersistPropertyWorkSpace();
|
||||
int WritePersistProperty(const char *name, const char *value);
|
||||
|
||||
const char *DetectPropertyChange(PropertyWorkSpace *workSpace, PropertyCache *cache,
|
||||
PropertyEvaluatePtr evaluate, u_int32_t count, const char *properties[][2]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
67
services/property/include/property_request.h
Executable file
67
services/property/include/property_request.h
Executable file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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_PROPERTY_REQUEST_H
|
||||
#define BASE_STARTUP_PROPERTY_REQUEST_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "property.h"
|
||||
#include "property_manager.h"
|
||||
|
||||
#include "uv.h"
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef enum RequestType {
|
||||
SET_PROPERTY,
|
||||
GET_PROPERTY,
|
||||
} RequestType;
|
||||
|
||||
typedef struct {
|
||||
PropertySecurityLabel securitylabel;
|
||||
RequestType type;
|
||||
int contentSize;
|
||||
char content[0];
|
||||
} RequestMsg;
|
||||
|
||||
typedef struct {
|
||||
RequestType type;
|
||||
int result;
|
||||
int contentSize;
|
||||
char content[0];
|
||||
} ResponseMsg;
|
||||
|
||||
typedef struct {
|
||||
uv_loop_t *loop;
|
||||
uv_connect_t connect;
|
||||
uv_pipe_t handle;
|
||||
int result;
|
||||
RequestMsg msg;
|
||||
} RequestNode;
|
||||
|
||||
typedef struct {
|
||||
uv_write_t writer;
|
||||
ResponseMsg msg;
|
||||
} ResponseNode;
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
87
services/property/include/property_service.h
Executable file
87
services/property/include/property_service.h
Executable file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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_PROPERTY_SERVICE_H
|
||||
#define BASE_STARTUP_PROPERTY_SERVICE_H
|
||||
#include <stdio.h>
|
||||
#include "property.h"
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Init 接口
|
||||
* 初始化属性服务
|
||||
*
|
||||
*/
|
||||
void InitPropertyService();
|
||||
|
||||
/**
|
||||
* Init 接口
|
||||
* 加载默认的属性值
|
||||
*
|
||||
*/
|
||||
int LoadDefaultProperty(const char *fileName);
|
||||
|
||||
/**
|
||||
* Init 接口
|
||||
* 安全使用,加载属性的信息,包括selinux label 等
|
||||
*
|
||||
*/
|
||||
int LoadPropertyInfo(const char *fileName);
|
||||
|
||||
/**
|
||||
* Init 接口
|
||||
* 启动属性服务,在main启动的最后调用,阻赛当前线程
|
||||
*
|
||||
*/
|
||||
int StartPropertyService();
|
||||
|
||||
/**
|
||||
* Init 接口
|
||||
* 设置属性,主要用于其他进程使用,通过管道修改属性
|
||||
*
|
||||
*/
|
||||
int SystemWriteParameter(const char *name, const char *value);
|
||||
|
||||
/**
|
||||
* Init 接口
|
||||
* 查询属性。
|
||||
*
|
||||
*/
|
||||
int SystemReadParameter(const char *name, char *value, unsigned int *len);
|
||||
|
||||
/**
|
||||
* Init 接口
|
||||
* 遍历属性。
|
||||
*
|
||||
*/
|
||||
int SystemTraversalParameters(void (*traversalParameter)(PropertyHandle handle, void* cookie), void* cookie);
|
||||
|
||||
/**
|
||||
* Init 接口
|
||||
* 加载默认属性。
|
||||
*
|
||||
*/
|
||||
int LoadPersistProperties();
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
139
services/property/include/property_trie.h
Executable file
139
services/property/include/property_trie.h
Executable file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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_PROPERTY_TRIE_H
|
||||
#define BASE_STARTUP_PROPERTY_TRIE_H
|
||||
#include <linux/futex.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include "init_log.h"
|
||||
#include "property.h"
|
||||
#include "securec.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define PROPERTY_WORKSPACE_MAX 64*1024
|
||||
|
||||
#define TRIE_SERIAL_DIRTY_OFFSET 1
|
||||
#define TRIE_SERIAL_KEY_LEN_OFFSET 24
|
||||
#define TRIE_SERIAL_DATA_LEN_OFFSET 16
|
||||
|
||||
#define FILENAME_LEN_MAX 255
|
||||
#define TRIE_DATA_LEN_MAX 128
|
||||
|
||||
#define NODE_INDEX unsigned int
|
||||
|
||||
#define TRIE_NODE_HEADER \
|
||||
atomic_uint_least32_t serial; \
|
||||
NODE_INDEX left; \
|
||||
NODE_INDEX right;
|
||||
|
||||
#define DATA_ENTRY_KEY_LEN(entry) (entry)->dataLength >> TRIE_SERIAL_KEY_LEN_OFFSET
|
||||
#define DATA_ENTRY_DATA_LEN(entry) (((entry)->dataLength >> TRIE_SERIAL_DATA_LEN_OFFSET) & 0x00FF)
|
||||
#define DATA_ENTRY_DIRTY(serial) ((serial) & 1)
|
||||
|
||||
#define FUTEX_WAIT 0
|
||||
#define FUTEX_WAKE 1
|
||||
#define __futex(ftx, op, value, timeout, bitset) \
|
||||
syscall(__NR_futex, ftx, op, value, timeout, NULL, bitset)
|
||||
#define futex_wake(ftx, count) __futex(ftx, FUTEX_WAKE, count, NULL, 0)
|
||||
#define futex_wait(ftx, value, timeout) __futex(ftx, FUTEX_WAIT, value, timeout, 0)
|
||||
|
||||
typedef struct {
|
||||
TRIE_NODE_HEADER;
|
||||
char key[0];
|
||||
} TrieNode;
|
||||
|
||||
typedef struct {
|
||||
TRIE_NODE_HEADER;
|
||||
NODE_INDEX child;
|
||||
NODE_INDEX labelIndex;
|
||||
NODE_INDEX dataIndex;
|
||||
char key[0];
|
||||
} TrieDataNode;
|
||||
|
||||
typedef struct {
|
||||
atomic_uint_least32_t serial;
|
||||
atomic_uint_least32_t dataLength;
|
||||
char data[0];
|
||||
} DataEntry;
|
||||
|
||||
typedef struct {
|
||||
atomic_uint_least32_t serial;
|
||||
u_int32_t currOffset;
|
||||
u_int32_t firstNode;
|
||||
u_int32_t dataSize;
|
||||
u_int32_t reserved_[28];
|
||||
char data[0];
|
||||
} WorkArea;
|
||||
|
||||
struct WorkSpace_;
|
||||
typedef u_int32_t (*AllocTrieNodePtr)(struct WorkSpace_ *workSpace, const char *key, u_int32_t keyLen);
|
||||
typedef int (*CompareTrieNodePtr)(TrieNode *node, const char *key2, u_int32_t key2Len);
|
||||
|
||||
typedef struct WorkSpace_ {
|
||||
char fileName[FILENAME_LEN_MAX + 1];
|
||||
WorkArea *area;
|
||||
TrieNode *rootNode;
|
||||
AllocTrieNodePtr allocTrieNode;
|
||||
CompareTrieNodePtr compareTrieNode;
|
||||
} WorkSpace;
|
||||
|
||||
u_int32_t GetWorkSpaceSerial(WorkSpace *workSpace);
|
||||
int CompareTrieNode(TrieNode *node, const char *key, u_int32_t keyLen);
|
||||
u_int32_t AllocateTrieNode(WorkSpace *workSpace, const char *key, u_int32_t keyLen);
|
||||
int CompareTrieDataNode(TrieNode *node, const char *key, u_int32_t keyLen);
|
||||
u_int32_t AllocateTrieDataNode(WorkSpace *workSpace, const char *key, u_int32_t keyLen);
|
||||
|
||||
u_int32_t GetTrieNodeOffset(WorkSpace *workSpace, const TrieNode *current);
|
||||
TrieNode *GetTrieNode(WorkSpace *workSpace, NODE_INDEX *index);
|
||||
u_int32_t GetTrieKeyLen(TrieNode *current);
|
||||
void SaveIndex(NODE_INDEX *index, u_int32_t offset);
|
||||
TrieDataNode *AddTrieDataNode(WorkSpace *workSpace, const char *key, u_int32_t keyLen);
|
||||
TrieDataNode *AddToSubTrie(WorkSpace *workSpace, TrieDataNode *dataNode, const char *key, u_int32_t keyLen);
|
||||
TrieDataNode *FindSubTrie(WorkSpace *workSpace, TrieDataNode *dataNode, const char *key, u_int32_t keyLen);
|
||||
TrieDataNode *FindTrieDataNode(WorkSpace *workSpace, const char *key, u_int32_t keyLen, int matchPrefix);
|
||||
|
||||
TrieNode *AddTrieNode(WorkSpace *workSpace, TrieNode *root, const char *key, u_int32_t keyLen);
|
||||
TrieNode *FindTrieNode(WorkSpace *workSpace, TrieNode *tree, const char *key, u_int32_t keyLen);
|
||||
|
||||
int InitWorkSpace_(WorkSpace *workSpace, int mode, int prot, u_int32_t spaceSize, int readOnly);
|
||||
int InitPersistWorkSpace(const char *fileName, WorkSpace *workSpace);
|
||||
int InitWorkSpace(const char *fileName, WorkSpace *workSpace, int onlyRead);
|
||||
void CloseWorkSpace(WorkSpace *workSpace);
|
||||
|
||||
typedef int (*TraversalTrieNodePtr)(WorkSpace *workSpace, TrieNode *node, void *cookie);
|
||||
int TraversalTrieNode(WorkSpace *workSpace, TrieNode *root, TraversalTrieNodePtr walkFunc, void *cookie);
|
||||
int TraversalTrieDataNode(WorkSpace *workSpace, TrieDataNode *current, TraversalTrieNodePtr walkFunc, void *cookie);
|
||||
|
||||
u_int32_t AddData(WorkSpace *workSpace, const char *key, u_int32_t keyLen, const char *value, u_int32_t valueLen);
|
||||
int UpdateDataValue(DataEntry *entry, const char *value);
|
||||
int GetDataName(const DataEntry *entry, char *name, u_int32_t len);
|
||||
int GetDataValue(const DataEntry *entry, char *value, u_int32_t len);
|
||||
u_int32_t GetDataSerial(const DataEntry *entry);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif // BASE_STARTUP_PROPERTY_TRIE_H
|
148
services/property/manager/property_cache.c
Executable file
148
services/property/manager/property_cache.c
Executable file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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 "property.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "property_manager.h"
|
||||
|
||||
#define LABEL "Manager"
|
||||
#define MAX_PROPERT_IN_WATCH 5
|
||||
#define NORMAL_MEMORY_FOR_PROPERTY_CACHE 4 * 1024
|
||||
static WorkSpace g_workSpace;
|
||||
static pthread_mutex_t cacheLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static int InitNormalMemory(WorkSpace *workSpace, u_int32_t spaceSize)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace != NULL, return -1, "Invalid param");
|
||||
if (workSpace->area != NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *areaAddr = (void *)mmap(NULL, spaceSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_POPULATE | MAP_ANON, -1, 0);
|
||||
PROPERTY_CHECK(areaAddr != MAP_FAILED, return -1, "Failed to map memory error %s", strerror(errno));
|
||||
workSpace->area = (WorkArea*)areaAddr;
|
||||
atomic_init(&workSpace->area->serial, 0);
|
||||
workSpace->area->dataSize = spaceSize;
|
||||
workSpace->area->currOffset = sizeof(WorkArea);
|
||||
PROPERTY_LOGI("InitNormalMemory success, currOffset %u firstNode %u dataSize %u",
|
||||
workSpace->area->currOffset, workSpace->area->firstNode, workSpace->area->dataSize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PropertyCacheNode *AllocPropertyCacheNode(WorkSpace *workSpace, u_int32_t size)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace != NULL, return 0, "Invalid param");
|
||||
PROPERTY_CHECK((workSpace->area->currOffset + size) < workSpace->area->dataSize, return 0,
|
||||
"Failed to allocate currOffset %d, dataSize %d", workSpace->area->currOffset, workSpace->area->dataSize);
|
||||
PropertyCacheNode *cache = (PropertyCacheNode *)(workSpace->area->data + workSpace->area->currOffset);
|
||||
workSpace->area->currOffset += size;
|
||||
return cache;
|
||||
}
|
||||
|
||||
static int CreatePropertyCache(PropertyCache *cache, PropertyWorkSpace *workSpace, PropertyEvaluatePtr evaluate)
|
||||
{
|
||||
PROPERTY_CHECK(cache != NULL && evaluate != NULL, return -1, "Invalid param");
|
||||
if (cache->cacheNode != NULL) {
|
||||
return 0;
|
||||
}
|
||||
int ret = InitNormalMemory(&g_workSpace, NORMAL_MEMORY_FOR_PROPERTY_CACHE);
|
||||
PROPERTY_CHECK(ret == 0, return -1, "Failed to init normal memory");
|
||||
pthread_mutex_init(&cache->lock, NULL);
|
||||
cache->serial = GetWorkSpaceSerial(&workSpace->propertySpace);
|
||||
cache->cacheCount = 0;
|
||||
cache->evaluate = evaluate;
|
||||
cache->cacheNode = (PropertyCacheNode *)AllocPropertyCacheNode(&g_workSpace,
|
||||
sizeof(PropertyCache) * MAX_PROPERT_IN_WATCH);
|
||||
PROPERTY_CHECK(cache->cacheNode != NULL, return -1, "Failed to malloc memory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int AddPropertyNode(PropertyCache *cache, PropertyWorkSpace *workSpace, const char *name, const char *defValue)
|
||||
{
|
||||
PROPERTY_CHECK(cache != NULL && name != NULL, return -1, "Invalid param");
|
||||
PROPERTY_CHECK(cache->cacheCount < MAX_PROPERT_IN_WATCH, return -1, "Full property in cache");
|
||||
|
||||
PropertyCacheNode *cacheNode = &cache->cacheNode[cache->cacheCount++];
|
||||
int ret = memcpy_s(cacheNode->value, sizeof(cacheNode->value), defValue, strlen(defValue));
|
||||
PROPERTY_CHECK(ret == 0, return -1, "Failed to copy default value");
|
||||
|
||||
ret = ReadPropertyWithCheck(workSpace, name, &cacheNode->handle);
|
||||
PROPERTY_CHECK(ret == 0, return -1, "Failed to read property");
|
||||
cacheNode->serial = ReadPropertySerial(workSpace, cacheNode->handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int CheckCacheNode(PropertyWorkSpace *workSpace, PropertyCacheNode *cacheNode)
|
||||
{
|
||||
return cacheNode && ReadPropertySerial(workSpace, cacheNode->handle) != cacheNode->serial;
|
||||
}
|
||||
|
||||
static void RefreshCacheNode(PropertyWorkSpace *workSpace, PropertyCacheNode *cacheNode)
|
||||
{
|
||||
cacheNode->serial = ReadPropertySerial(workSpace, cacheNode->handle);
|
||||
u_int32_t len = sizeof(cacheNode->value);
|
||||
ReadPropertyValue(workSpace, cacheNode->handle, cacheNode->value, &len);
|
||||
}
|
||||
|
||||
static const char *TestPropertyCache(PropertyCache *cache, PropertyWorkSpace *workSpace)
|
||||
{
|
||||
int changeDetected;
|
||||
if (pthread_mutex_trylock(&cache->lock)) {
|
||||
return cache->evaluate(cache->cacheCount, cache->cacheNode);
|
||||
}
|
||||
if (GetWorkSpaceSerial(&workSpace->propertySpace) != cache->serial) {
|
||||
changeDetected = 1;
|
||||
}
|
||||
for (u_int32_t i = 0; (i < cache->cacheCount) && changeDetected == 0; i++) {
|
||||
changeDetected = CheckCacheNode(workSpace, &cache->cacheNode[i]);
|
||||
}
|
||||
if (changeDetected) {
|
||||
for (u_int32_t i = 0; i < cache->cacheCount; i++) {
|
||||
RefreshCacheNode(workSpace, &cache->cacheNode[i]);
|
||||
}
|
||||
cache->serial = GetWorkSpaceSerial(&workSpace->propertySpace);
|
||||
}
|
||||
pthread_mutex_unlock(&cache->lock);
|
||||
|
||||
return cache->evaluate(cache->cacheCount, cache->cacheNode);
|
||||
}
|
||||
|
||||
const char *DetectPropertyChange(PropertyWorkSpace *workSpace, PropertyCache *cache,
|
||||
PropertyEvaluatePtr evaluate, u_int32_t count, const char *properties[][2])
|
||||
{
|
||||
pthread_mutex_lock(&cacheLock);
|
||||
while (cache->cacheCount == 0) {
|
||||
int ret = CreatePropertyCache(cache, workSpace, evaluate);
|
||||
PROPERTY_CHECK(ret == 0, break, "Failed to create cache");
|
||||
for (u_int32_t i = 0; i < count; i++) {
|
||||
ret = AddPropertyNode(cache, workSpace, properties[i][0], properties[i][1]);
|
||||
PROPERTY_CHECK(ret == 0, break, "Failed to add property cache");
|
||||
}
|
||||
PROPERTY_CHECK(ret == 0, break, "Failed to add property cache");
|
||||
}
|
||||
pthread_mutex_unlock(&cacheLock);
|
||||
return TestPropertyCache(cache, workSpace);
|
||||
}
|
532
services/property/manager/property_manager.c
Executable file
532
services/property/manager/property_manager.c
Executable file
@ -0,0 +1,532 @@
|
||||
/*
|
||||
* 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 "property_manager.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define LABEL "Manager"
|
||||
|
||||
#ifdef PROPERTY_SUPPORT_SELINUX
|
||||
static int SelinuxAuditCallback(void *data,
|
||||
__attribute__((unused))security_class_t class, char *msgBuf, size_t msgSize)
|
||||
{
|
||||
PropertyAuditData *auditData = (PropertyAuditData*)(data);
|
||||
PROPERTY_CHECK(auditData != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
PROPERTY_CHECK(auditData->name != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
PROPERTY_CHECK(auditData->cr != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
snprintf(msgBuf, msgSize, "property=%s pid=%d uid=%d gid=%d",
|
||||
auditData->name, auditData->cr->pid, auditData->cr->uid, auditData->cr->gid);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int InitPropertyWorkSpace(PropertyWorkSpace *workSpace, int onlyRead, const char *context)
|
||||
{
|
||||
u_int32_t flags = atomic_load_explicit(&workSpace->flags, memory_order_relaxed);
|
||||
PROPERTY_LOGI("InitPropertyWorkSpace flags %x", flags);
|
||||
if ((flags & WORKSPACE_FLAGS_INIT) == WORKSPACE_FLAGS_INIT) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef PROPERTY_SUPPORT_SELINUX
|
||||
union selinux_callback cb;
|
||||
cb.func_audit = SelinuxAuditCallback;
|
||||
selinux_set_callback(SELINUX_CB_AUDIT, cb);
|
||||
#endif
|
||||
|
||||
#ifdef PROPERTY_SUPPORT_SELINUX
|
||||
if (context && fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0) != 0) {
|
||||
PROPERTY_LOGI("fsetxattr context %s fail", context);
|
||||
}
|
||||
#endif
|
||||
PROPERTY_CHECK(workSpace != NULL, return PROPERTY_CODE_INVALID_NAME, "Invalid param");
|
||||
workSpace->propertySpace.compareTrieNode = CompareTrieDataNode;
|
||||
workSpace->propertySpace.allocTrieNode = AllocateTrieDataNode;
|
||||
int ret = InitWorkSpace(PROPERTY_STORAGE_PATH, &workSpace->propertySpace, onlyRead);
|
||||
|
||||
// 保存selinux 使用的属性标签值
|
||||
workSpace->propertyLabelSpace.compareTrieNode = CompareTrieNode; // 必须先设置
|
||||
workSpace->propertyLabelSpace.allocTrieNode = AllocateTrieNode;
|
||||
ret |= InitWorkSpace(PROPERTY_INFO_PATH, &workSpace->propertyLabelSpace, onlyRead);
|
||||
atomic_store_explicit(&workSpace->flags, WORKSPACE_FLAGS_INIT, memory_order_release);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ClosePropertyWorkSpace(PropertyWorkSpace *workSpace)
|
||||
{
|
||||
CloseWorkSpace(&workSpace->propertySpace);
|
||||
CloseWorkSpace(&workSpace->propertyLabelSpace);
|
||||
atomic_store_explicit(&workSpace->flags, 0, memory_order_release);
|
||||
}
|
||||
|
||||
int WritePropertyInfo(PropertyWorkSpace *workSpace, SubStringInfo *info, int subStrNumber)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace != NULL && info != NULL && subStrNumber > SUBSTR_INFO_NAME,
|
||||
return PROPERTY_CODE_INVALID_PARAM, "Failed to check param");
|
||||
const char *name = info[SUBSTR_INFO_NAME].value;
|
||||
char *label = NULL;
|
||||
char *type = NULL;
|
||||
if (subStrNumber >= SUBSTR_INFO_LABEL) {
|
||||
label = info[SUBSTR_INFO_LABEL].value;
|
||||
} else {
|
||||
label = "u:object_r:default_prop:s0";
|
||||
}
|
||||
if (subStrNumber >= SUBSTR_INFO_TYPE) {
|
||||
type = info[SUBSTR_INFO_TYPE].value;
|
||||
} else {
|
||||
type = "string";
|
||||
}
|
||||
|
||||
int ret = CheckPropertyName(name, 1);
|
||||
PROPERTY_CHECK(ret == 0, return ret, "Illegal property name %s", name);
|
||||
|
||||
// 先保存标签值
|
||||
TrieNode *node = AddTrieNode(&workSpace->propertyLabelSpace,
|
||||
workSpace->propertyLabelSpace.rootNode, label, strlen(label));
|
||||
PROPERTY_CHECK(node != NULL, return PROPERTY_CODE_REACHED_MAX, "Failed to add label");
|
||||
u_int32_t offset = GetTrieNodeOffset(&workSpace->propertyLabelSpace, node);
|
||||
|
||||
TrieDataNode *dataNode = AddTrieDataNode(&workSpace->propertySpace, name, strlen(name));
|
||||
PROPERTY_CHECK(dataNode != NULL, return PROPERTY_CODE_REACHED_MAX, "Failed to add node %s", name);
|
||||
TrieNode *entry = (TrieNode *)GetTrieNode(&workSpace->propertyLabelSpace, &dataNode->labelIndex);
|
||||
if (entry != 0) { // 已经存在label
|
||||
PROPERTY_LOGE("Has been set label %s old label %s new label: %s", name, entry->key, label);
|
||||
}
|
||||
SaveIndex(&dataNode->labelIndex, offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AddProperty(WorkSpace *workSpace, const char *name, const char *value)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace != NULL && name != NULL && value != NULL,
|
||||
return PROPERTY_CODE_INVALID_PARAM, "Failed to check param");
|
||||
|
||||
TrieDataNode *node = AddTrieDataNode(workSpace, name, strlen(name));
|
||||
PROPERTY_CHECK(node != NULL, return PROPERTY_CODE_REACHED_MAX, "Failed to add node");
|
||||
DataEntry *entry = (DataEntry *)GetTrieNode(workSpace, &node->dataIndex);
|
||||
if (entry == NULL) {
|
||||
u_int32_t offset = AddData(workSpace, name, strlen(name), value, strlen(value));
|
||||
PROPERTY_CHECK(offset != 0, return PROPERTY_CODE_REACHED_MAX, "Failed to allocate name %s", name);
|
||||
SaveIndex(&node->dataIndex, offset);
|
||||
}
|
||||
PROPERTY_LOGI("AddProperty trie %p dataIndex %u name %s", node, node->dataIndex, name);
|
||||
atomic_store_explicit(&workSpace->area->serial,
|
||||
atomic_load_explicit(&workSpace->area->serial, memory_order_relaxed) + 1,
|
||||
memory_order_release);
|
||||
futex_wake(&workSpace->area->serial, INT_MAX);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UpdateProperty(WorkSpace *workSpace, u_int32_t *dataIndex, const char *name, const char *value)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace != NULL && name != NULL && value != NULL,
|
||||
return PROPERTY_CODE_INVALID_PARAM, "Failed to check param");
|
||||
|
||||
DataEntry *entry = (DataEntry *)GetTrieNode(workSpace, dataIndex);
|
||||
if (entry == NULL) {
|
||||
PROPERTY_LOGE("Failed to update property value %s %u", name, *dataIndex);
|
||||
return -1;
|
||||
}
|
||||
u_int32_t keyLen = DATA_ENTRY_KEY_LEN(entry);
|
||||
PROPERTY_CHECK(keyLen == strlen(name), return PROPERTY_CODE_INVALID_NAME, "Failed to check name len %s", name);
|
||||
|
||||
u_int32_t serial = atomic_load_explicit(&entry->serial, memory_order_relaxed);
|
||||
serial |= 1;
|
||||
atomic_store_explicit(&entry->serial, serial | 1, memory_order_release);
|
||||
atomic_thread_fence(memory_order_release);
|
||||
|
||||
int ret = UpdateDataValue(entry, value);
|
||||
if (ret != 0) {
|
||||
PROPERTY_LOGE("Failed to update property value %s %s", name, value);
|
||||
}
|
||||
atomic_store_explicit(&entry->serial, serial + 1, memory_order_release);
|
||||
futex_wake(&entry->serial, INT_MAX);
|
||||
|
||||
atomic_store_explicit(&workSpace->area->serial,
|
||||
atomic_load_explicit(&workSpace->area->serial, memory_order_relaxed) + 1, memory_order_release);
|
||||
futex_wake(&workSpace->area->serial, INT_MAX);
|
||||
return ret;
|
||||
}
|
||||
|
||||
DataEntry *FindProperty(WorkSpace *workSpace, const char *name)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace != NULL, return NULL, "Failed to check param");
|
||||
PROPERTY_CHECK(name != NULL, return NULL, "Invalid param size");
|
||||
|
||||
TrieDataNode *node = FindTrieDataNode(workSpace, name, strlen(name), 0);
|
||||
if (node != NULL) {
|
||||
return (DataEntry *)GetTrieNode(workSpace, &node->dataIndex);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int WritePropertyWithCheck(PropertyWorkSpace *workSpace,
|
||||
const PropertySecurityLabel *srcLabel, const char *name, const char *value)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace != NULL && srcLabel != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
PROPERTY_CHECK(value != NULL && name != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
|
||||
u_int32_t flags = atomic_load_explicit(&workSpace->flags, memory_order_relaxed);
|
||||
if ((flags & WORKSPACE_FLAGS_INIT) != WORKSPACE_FLAGS_INIT) {
|
||||
return PROPERTY_CODE_NOT_INIT;
|
||||
}
|
||||
|
||||
int ret = CheckPropertyName(name, 0);
|
||||
PROPERTY_CHECK(ret == 0, return ret, "Illegal property name %s", name);
|
||||
|
||||
// 取最长匹配的属性的label
|
||||
TrieDataNode *propertInfo = FindTrieDataNode(&workSpace->propertySpace, name, strlen(name), 1);
|
||||
ret = CanWriteProperty(workSpace, srcLabel, propertInfo, name, value);
|
||||
PROPERTY_CHECK(ret == 0, return ret, "Permission to write property %s", name);
|
||||
|
||||
return WriteProperty(&workSpace->propertySpace, name, value);
|
||||
}
|
||||
|
||||
int WriteProperty(WorkSpace *workSpace, const char *name, const char *value)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
PROPERTY_CHECK(value != NULL && name != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
|
||||
TrieDataNode *node = FindTrieDataNode(workSpace, name, strlen(name), 0);
|
||||
int ret = CheckPropertyValue(workSpace, node, name, value);
|
||||
PROPERTY_CHECK(ret == 0, return ret, "Invalid value %s %s", name, value);
|
||||
|
||||
if (node != NULL) {
|
||||
return UpdateProperty(workSpace, &node->dataIndex, name, value);
|
||||
}
|
||||
return AddProperty(workSpace, name, value);
|
||||
}
|
||||
|
||||
int ReadPropertyWithCheck(PropertyWorkSpace *workSpace, const char *name, PropertyHandle *handle)
|
||||
{
|
||||
PROPERTY_CHECK(handle != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
PROPERTY_CHECK(workSpace != NULL && name != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
u_int32_t flags = atomic_load_explicit(&workSpace->flags, memory_order_relaxed);
|
||||
if ((flags & WORKSPACE_FLAGS_INIT) != WORKSPACE_FLAGS_INIT) {
|
||||
return PROPERTY_CODE_NOT_INIT;
|
||||
}
|
||||
|
||||
*handle = 0;
|
||||
// 取最长匹配
|
||||
TrieDataNode *propertyInfo = FindTrieDataNode(&workSpace->propertySpace, name, strlen(name), 1);
|
||||
int ret = CanReadProperty(workSpace, propertyInfo == NULL ? 0 : propertyInfo->labelIndex, name);
|
||||
PROPERTY_CHECK(ret == 0, return ret, "Permission to read property %s", name);
|
||||
|
||||
// 查找结点
|
||||
TrieDataNode *node = FindTrieDataNode(&workSpace->propertySpace, name, strlen(name), 0);
|
||||
if (node != NULL && node->dataIndex != 0) {
|
||||
PROPERTY_LOGI("ReadPropertyWithCheck trie %p dataIndex %u name %s", node, node->dataIndex, name);
|
||||
*handle = node->dataIndex;
|
||||
return 0;
|
||||
}
|
||||
return PROPERTY_CODE_NOT_FOUND_PROP;
|
||||
}
|
||||
|
||||
int ReadPropertyValue(PropertyWorkSpace *workSpace, PropertyHandle handle, char *value, u_int32_t *len)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
u_int32_t flags = atomic_load_explicit(&workSpace->flags, memory_order_relaxed);
|
||||
if ((flags & WORKSPACE_FLAGS_INIT) != WORKSPACE_FLAGS_INIT) {
|
||||
return PROPERTY_CODE_NOT_INIT;
|
||||
}
|
||||
DataEntry *entry = (DataEntry *)GetTrieNode(&workSpace->propertySpace, &handle);
|
||||
if (entry == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (value == NULL) {
|
||||
*len = DATA_ENTRY_DATA_LEN(entry);;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
u_int32_t serial = GetDataSerial(entry);
|
||||
int ret = GetDataValue(entry, value, *len);
|
||||
PROPERTY_CHECK(ret == 0, return ret, "Failed to get value");
|
||||
atomic_thread_fence(memory_order_acquire);
|
||||
if (serial == atomic_load_explicit(&(entry->serial), memory_order_relaxed)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ReadPropertyName(PropertyWorkSpace *workSpace, PropertyHandle handle, char *name, u_int32_t len)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace != NULL && name != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
DataEntry *entry = (DataEntry *)GetTrieNode(&workSpace->propertySpace, &handle);
|
||||
if (entry == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return GetDataValue(entry, name, len);
|
||||
}
|
||||
|
||||
u_int32_t ReadPropertySerial(PropertyWorkSpace *workSpace, PropertyHandle handle)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace != NULL, return 0, "Invalid param");
|
||||
DataEntry *entry = (DataEntry *)GetTrieNode(&workSpace->propertySpace, &handle);
|
||||
if (entry == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return GetDataSerial(entry);
|
||||
}
|
||||
|
||||
int CheckControlPropertyPerms(PropertyWorkSpace *workSpace,
|
||||
const PropertySecurityLabel *srcLabel, const char *name, const char *value)
|
||||
{
|
||||
PROPERTY_CHECK(srcLabel != NULL && name != NULL && value != NULL,
|
||||
return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
|
||||
char * ctrlName[] = {
|
||||
"ctl.start", "ctl.stop", "ctl.restart"
|
||||
};
|
||||
size_t size1 = strlen("ctl.") + strlen(value);
|
||||
size_t size2 = strlen(name) + strlen(value) + 1;
|
||||
size_t size = ((size1 > size2) ? size1 : size2) + 1;
|
||||
char *legacyName = (char*)malloc(size);
|
||||
PROPERTY_CHECK(legacyName != NULL, return PROPERTY_CODE_INVALID_PARAM, "Failed to alloc memory");
|
||||
|
||||
// We check the legacy method first but these properties are dontaudit, so we only log an audit
|
||||
// if the newer method fails as well. We only do this with the legacy ctl. properties.
|
||||
for (size_t i = 0; i < sizeof(ctrlName) / sizeof(char*); i++) {
|
||||
if (strcmp(name, ctrlName[i]) == 0) {
|
||||
// The legacy permissions model is that ctl. properties have their name ctl.<action> and
|
||||
// their value is the name of the service to apply that action to. Permissions for these
|
||||
// actions are based on the service, so we must create a fake name of ctl.<service> to
|
||||
// check permissions.
|
||||
int n = snprintf_s(legacyName, size, size, "ctl.%s", value);
|
||||
PROPERTY_CHECK(n > 0, free(legacyName); return PROPERTY_CODE_INVALID_PARAM, "Failed to snprintf value");
|
||||
legacyName[n] = '\0';
|
||||
|
||||
TrieDataNode *node = FindTrieDataNode(&workSpace->propertySpace, legacyName, strlen(legacyName), 1);
|
||||
int ret = CheckMacPerms(workSpace, srcLabel, legacyName, node == NULL ? 0 : node->labelIndex);
|
||||
if (ret == 0) {
|
||||
free(legacyName);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
int n = snprintf_s(legacyName, size, size, "%s$%s", name, value);
|
||||
PROPERTY_CHECK(n > 0, free(legacyName); return PROPERTY_CODE_INVALID_PARAM, "Failed to snprintf value");
|
||||
|
||||
TrieDataNode *node = FindTrieDataNode(&workSpace->propertySpace, name, strlen(name), 1);
|
||||
int ret = CheckMacPerms(workSpace, srcLabel, name, node == NULL ? 0 : node->labelIndex);
|
||||
free(legacyName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CheckPropertyName(const char *name, int propInfo)
|
||||
{
|
||||
size_t nameLen = strlen(name);
|
||||
if (nameLen >= PROPERTY_VALUE_LEN_MAX) {
|
||||
return PROPERTY_CODE_INVALID_NAME;
|
||||
}
|
||||
|
||||
if (nameLen < 1 || name[0] == '.' || (!propInfo && name[nameLen - 1] == '.')) {
|
||||
PROPERTY_LOGE("CheckPropertyName %s %d", name, propInfo);
|
||||
return PROPERTY_CODE_INVALID_NAME;
|
||||
}
|
||||
|
||||
/* Only allow alphanumeric, plus '.', '-', '@', ':', or '_' */
|
||||
/* Don't allow ".." to appear in a property name */
|
||||
for (size_t i = 0; i < nameLen; i++) {
|
||||
if (name[i] == '.') {
|
||||
if (name[i - 1] == '.') {
|
||||
return PROPERTY_CODE_INVALID_NAME;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (name[i] == '_' || name[i] == '-' || name[i] == '@' || name[i] == ':') {
|
||||
continue;
|
||||
}
|
||||
if (isalnum(name[i])) {
|
||||
continue;
|
||||
}
|
||||
return PROPERTY_CODE_INVALID_NAME;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CheckPropertyValue(WorkSpace *workSpace, const TrieDataNode *node, const char *name, const char *value)
|
||||
{
|
||||
if (IS_READY_ONLY(name)) {
|
||||
if (node != NULL && node->dataIndex != 0) {
|
||||
PROPERTY_LOGE("Read-only property was already set %s", name);
|
||||
return PROPERTY_CODE_READ_ONLY_PROPERTY;
|
||||
}
|
||||
} else {
|
||||
// 限制非read only的属性,防止属性值修改后,原空间不能保存
|
||||
PROPERTY_CHECK(strlen(value) < PROPERTY_VALUE_LEN_MAX,
|
||||
return PROPERTY_CODE_INVALID_VALUE, "Illegal property value");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CheckMacPerms(PropertyWorkSpace *workSpace,
|
||||
const PropertySecurityLabel *srcLabel, const char *name, u_int32_t labelIndex)
|
||||
{
|
||||
#ifdef PROPERTY_SUPPORT_SELINUX
|
||||
PropertyAuditData auditData;
|
||||
auditData.name = name;
|
||||
auditData.cr = &srcLabel->cred;
|
||||
|
||||
int ret = 0;
|
||||
TrieNode *node = (TrieNode *)GetTrieNode(&workSpace->propertyLabelSpace, &labelIndex);
|
||||
if (node != 0) { // 已经存在label
|
||||
ret = selinux_check_access(srcLabel, node->key, "property_service", "set", &auditData);
|
||||
} else {
|
||||
ret = selinux_check_access(srcLabel, "u:object_r:default_prop:s0", "property_service", "set", &auditData);
|
||||
}
|
||||
return ret == 0 ? 0 : PROPERTY_CODE_PERMISSION_DENIED;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int CanWriteProperty(PropertyWorkSpace *workSpace,
|
||||
const PropertySecurityLabel *srcLabel, const TrieDataNode *node, const char *name, const char *value)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace != NULL && name != NULL && value != NULL && srcLabel != NULL,
|
||||
return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
|
||||
if (strncmp(name, "ctl.", strlen("ctl.")) == 0) { // 处理ctrl TODO
|
||||
return CheckControlPropertyPerms(workSpace, srcLabel, name, value);
|
||||
}
|
||||
|
||||
int ret = CheckMacPerms(workSpace, srcLabel, name, node == NULL ? 0 : node->labelIndex);
|
||||
PROPERTY_CHECK(ret == 0, return ret, "SELinux permission check failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CanReadProperty(PropertyWorkSpace *workSpace, u_int32_t labelIndex, const char *name)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
PROPERTY_CHECK(name != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
#ifdef PROPERTY_SUPPORT_SELINUX
|
||||
PropertyAuditData auditData;
|
||||
auditData.name = name;
|
||||
UserCred cr = {.pid = 0, .uid = 0, .gid = 0};
|
||||
auditData.cr = &cr;
|
||||
|
||||
int ret = 0;
|
||||
TrieNode *node = (TrieNode *)GetTrieNode(&workSpace->propertyLabelSpace, &labelIndex);
|
||||
if (node != 0) { // 已经存在label
|
||||
ret = selinux_check_access(&workSpace->context, node->key, "property_service", "read", &auditData);
|
||||
} else {
|
||||
ret = selinux_check_access(&workSpace->context, "selinux_check_access", "file", "read", &auditData);
|
||||
}
|
||||
return ret == 0 ? 0 : PROPERTY_CODE_PERMISSION_DENIED;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int GetSubStringInfo(const char *buff, u_int32_t buffLen, char delimiter, SubStringInfo *info, int subStrNumber)
|
||||
{
|
||||
size_t i = 0;
|
||||
// 去掉开始的空格
|
||||
for (; i < strlen(buff); i++) {
|
||||
if (!isspace(buff[i])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 过滤掉注释
|
||||
if (buff[i] == '#') {
|
||||
return -1;
|
||||
}
|
||||
// 分割字符串
|
||||
int curr = 0;
|
||||
int valueCurr = 0;
|
||||
for (; i < buffLen; i++) {
|
||||
if (buff[i] == '\n' || buff[i] == '\r') {
|
||||
break;
|
||||
}
|
||||
if (buff[i] == delimiter && valueCurr != 0) {
|
||||
info[curr].value[valueCurr] = '\0';
|
||||
valueCurr = 0;
|
||||
curr++;
|
||||
} else if (isspace(buff[i])) { // 无效字符,进行过滤
|
||||
continue;
|
||||
} else {
|
||||
if ((valueCurr + 1) >= (int)sizeof(info[curr].value)) {
|
||||
continue;
|
||||
}
|
||||
info[curr].value[valueCurr++] = buff[i];
|
||||
}
|
||||
if (curr >= subStrNumber) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (valueCurr > 0) {
|
||||
info[curr].value[valueCurr] = '\0';
|
||||
valueCurr = 0;
|
||||
curr++;
|
||||
}
|
||||
return curr;
|
||||
}
|
||||
|
||||
int BuildPropertyContent(char *content, u_int32_t contentSize, const char *name, const char *value)
|
||||
{
|
||||
PROPERTY_CHECK(name != NULL && value != NULL && content != NULL, return -1, "Invalid param");
|
||||
u_int32_t nameLen = (u_int32_t)strlen(name);
|
||||
u_int32_t valueLen = (u_int32_t)strlen(value);
|
||||
PROPERTY_CHECK(contentSize >= (nameLen + valueLen + 2), return -1, "Invalid content size %u", contentSize);
|
||||
|
||||
int offset = 0;
|
||||
int ret = memcpy_s(content + offset, contentSize - offset, name, nameLen);
|
||||
offset += nameLen;
|
||||
ret |= memcpy_s(content + offset, contentSize - offset, "=", 1);
|
||||
offset += 1;
|
||||
ret |= memcpy_s(content + offset, contentSize - offset, value, valueLen);
|
||||
offset += valueLen;
|
||||
content[offset] = '\0';
|
||||
PROPERTY_CHECK(ret == 0, return -1, "Failed to copy porperty");
|
||||
offset += 1;
|
||||
return offset;
|
||||
}
|
||||
|
||||
int ProcessPropertTraversal(WorkSpace *workSpace, TrieNode *node, void *cookie)
|
||||
{
|
||||
PropertyTraversalContext *context = (PropertyTraversalContext *)cookie;
|
||||
TrieDataNode *current = (TrieDataNode *)node;
|
||||
if (current == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (current->dataIndex == 0) {
|
||||
return 0;
|
||||
}
|
||||
context->traversalParamPtr(current->dataIndex, context->context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TraversalProperty(PropertyWorkSpace *workSpace, TraversalParamPtr walkFunc, void *cookie)
|
||||
{
|
||||
PropertyTraversalContext context = {
|
||||
walkFunc, cookie
|
||||
};
|
||||
return TraversalTrieDataNode(&workSpace->propertySpace,
|
||||
(TrieDataNode *)workSpace->propertySpace.rootNode, ProcessPropertTraversal, &context);
|
||||
}
|
536
services/property/manager/property_trie.c
Executable file
536
services/property/manager/property_trie.c
Executable file
@ -0,0 +1,536 @@
|
||||
/*
|
||||
* 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 "property_trie.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "init_utils.h"
|
||||
#include "property.h"
|
||||
#include "property_manager.h"
|
||||
|
||||
#define LABEL "Manager"
|
||||
|
||||
int InitWorkSpace(const char *fileName, WorkSpace *workSpace, int onlyRead)
|
||||
{
|
||||
PROPERTY_CHECK(fileName != NULL, return PROPERTY_CODE_INVALID_NAME, "Invalid param");
|
||||
PROPERTY_CHECK(workSpace != NULL, return PROPERTY_CODE_INVALID_NAME, "Invalid param");
|
||||
if (workSpace->area != NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = memcpy_s(workSpace->fileName, FILENAME_LEN_MAX, fileName, strlen(fileName));
|
||||
PROPERTY_CHECK(ret == 0, return PROPERTY_CODE_INVALID_NAME, "Copy file %s fail ", fileName);
|
||||
int openMode = 0;
|
||||
int prot = PROT_READ;
|
||||
if (onlyRead) {
|
||||
openMode = O_RDONLY;
|
||||
} else {
|
||||
openMode = O_CREAT | O_RDWR | O_TRUNC;
|
||||
prot = PROT_READ | PROT_WRITE;
|
||||
}
|
||||
ret = InitWorkSpace_(workSpace, openMode, prot, PROPERTY_WORKSPACE_MAX, onlyRead);
|
||||
PROPERTY_CHECK(ret == 0, return ret, "Failed to init workspace %s", workSpace->fileName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int InitPersistWorkSpace(const char *fileName, WorkSpace *workSpace)
|
||||
{
|
||||
PROPERTY_CHECK(fileName != NULL, return PROPERTY_CODE_INVALID_NAME, "Invalid param");
|
||||
PROPERTY_CHECK(workSpace != NULL, return PROPERTY_CODE_INVALID_NAME, "Invalid param");
|
||||
if (workSpace->area != NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = memcpy_s(workSpace->fileName, FILENAME_LEN_MAX, fileName, strlen(fileName));
|
||||
PROPERTY_CHECK(ret == 0, return PROPERTY_CODE_INVALID_NAME, "Copy file %s fail ", fileName);
|
||||
|
||||
int flag = (access(fileName, F_OK) == 0) ? 1 : 0;
|
||||
int openMode = (flag == 0) ? (O_CREAT | O_RDWR | O_TRUNC) : O_RDWR;
|
||||
int prot = PROT_READ | PROT_WRITE;
|
||||
ret = InitWorkSpace_(workSpace, openMode, prot, PROPERTY_WORKSPACE_MAX, flag);
|
||||
PROPERTY_CHECK(ret == 0, return ret, "Failed to init workspace %s", workSpace->fileName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int InitWorkSpace_(WorkSpace *workSpace, int mode, int prot, u_int32_t spaceSize, int readOnly)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid fileName");
|
||||
PROPERTY_CHECK(workSpace->allocTrieNode != NULL,
|
||||
return PROPERTY_CODE_INVALID_PARAM, "Invalid param %s", workSpace->fileName);
|
||||
PROPERTY_CHECK(workSpace->compareTrieNode != NULL,
|
||||
return PROPERTY_CODE_INVALID_PARAM, "Invalid param %s", workSpace->fileName);
|
||||
PROPERTY_LOGI("InitWorkSpace %s ", workSpace->fileName);
|
||||
CheckAndCreateDir(workSpace->fileName);
|
||||
|
||||
int fd = open(workSpace->fileName, mode, 00777); //0444);
|
||||
PROPERTY_CHECK(fd >= 0, return PROPERTY_CODE_INVALID_NAME,
|
||||
"Open file %s fail error %s", workSpace->fileName, strerror(errno));
|
||||
|
||||
if (!readOnly) {
|
||||
lseek(fd, spaceSize, SEEK_SET);
|
||||
write(fd, "", 1);
|
||||
}
|
||||
void *areaAddr = (void *)mmap(NULL, spaceSize, prot, MAP_SHARED, fd, 0);
|
||||
PROPERTY_CHECK(areaAddr != MAP_FAILED, close(fd); return PROPERTY_CODE_ERROR_MAP_FILE,
|
||||
"Failed to map memory error %s", strerror(errno));
|
||||
close(fd);
|
||||
|
||||
if (!readOnly) {
|
||||
workSpace->area = (WorkArea*)areaAddr;
|
||||
atomic_init(&workSpace->area->serial, 0);
|
||||
workSpace->area->dataSize = spaceSize;
|
||||
workSpace->area->currOffset = sizeof(WorkArea);
|
||||
// 创建一个key为#的节点
|
||||
u_int32_t offset = workSpace->allocTrieNode(workSpace, "#", 1);
|
||||
workSpace->area->firstNode = offset;
|
||||
workSpace->rootNode = GetTrieNode(workSpace, &offset);
|
||||
} else {
|
||||
workSpace->area = (WorkArea*)areaAddr;
|
||||
workSpace->rootNode = GetTrieNode(workSpace, &workSpace->area->firstNode);
|
||||
}
|
||||
PROPERTY_LOGI("InitWorkSpace success, currOffset %u firstNode %u dataSize %u",
|
||||
workSpace->area->currOffset, workSpace->area->firstNode, workSpace->area->dataSize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CloseWorkSpace(WorkSpace *workSpace)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace != NULL && workSpace->area != NULL, return, "The workspace is null");
|
||||
munmap((char *)workSpace->area, workSpace->area->dataSize);
|
||||
workSpace->area = NULL;
|
||||
}
|
||||
|
||||
u_int32_t GetWorkSpaceSerial(WorkSpace *workSpace)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace != NULL && workSpace->area != NULL, return 0, "The workspace is null");
|
||||
return (u_int32_t)workSpace->area->serial;
|
||||
}
|
||||
|
||||
u_int32_t AllocateTrieNode(WorkSpace *workSpace, const char *key, u_int32_t keyLen)
|
||||
{
|
||||
u_int32_t len = keyLen + sizeof(TrieNode) + 1;
|
||||
PROPERTY_CHECK((workSpace->area->currOffset + len) < workSpace->area->dataSize, return 0,
|
||||
"Failed to allocate currOffset %d, dataSize %d", workSpace->area->currOffset, workSpace->area->dataSize);
|
||||
TrieNode *node = (TrieNode*)(workSpace->area->data + workSpace->area->currOffset + len);
|
||||
|
||||
atomic_init(&node->serial, ATOMIC_VAR_INIT(keyLen << TRIE_SERIAL_KEY_LEN_OFFSET));
|
||||
int ret = memcpy_s(node->key, keyLen, key, keyLen);
|
||||
PROPERTY_CHECK(ret == 0, return 0, "Failed to copy key");
|
||||
node->key[keyLen] = '\0';
|
||||
node->left = 0;
|
||||
node->right = 0;
|
||||
u_int32_t offset = workSpace->area->currOffset;
|
||||
workSpace->area->currOffset += len;
|
||||
return offset;
|
||||
}
|
||||
|
||||
u_int32_t AllocateTrieDataNode(WorkSpace *workSpace, const char *key, u_int32_t keyLen)
|
||||
{
|
||||
u_int32_t len = keyLen + sizeof(TrieDataNode) + 1;
|
||||
PROPERTY_CHECK((workSpace->area->currOffset + len) < workSpace->area->dataSize, return 0,
|
||||
"Failed to allocate currOffset %d, dataSize %d", workSpace->area->currOffset, workSpace->area->dataSize);
|
||||
TrieDataNode *node = (TrieDataNode*)(workSpace->area->data + workSpace->area->currOffset);
|
||||
|
||||
atomic_init(&node->serial, ATOMIC_VAR_INIT(keyLen << TRIE_SERIAL_KEY_LEN_OFFSET));
|
||||
int ret = memcpy_s(node->key, keyLen, key, keyLen);
|
||||
PROPERTY_CHECK(ret == 0, return 0, "Failed to copy key");
|
||||
node->key[keyLen] = '\0';
|
||||
node->left = 0;
|
||||
node->right = 0;
|
||||
node->child = 0;
|
||||
node->dataIndex = 0;
|
||||
node->labelIndex = 0;
|
||||
u_int32_t offset = workSpace->area->currOffset;
|
||||
workSpace->area->currOffset += len;
|
||||
return offset;
|
||||
}
|
||||
|
||||
TrieNode *GetTrieNode(WorkSpace *workSpace, NODE_INDEX *index)
|
||||
{
|
||||
if (index == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
u_int32_t offset = *index; // atomic_load_explicit(¤t->children, memory_order_relaxed);
|
||||
if (offset == 0 || offset > workSpace->area->dataSize) {
|
||||
return NULL;
|
||||
}
|
||||
return (TrieNode*)(workSpace->area->data + offset);
|
||||
}
|
||||
|
||||
u_int32_t GetTrieKeyLen(TrieNode *current)
|
||||
{
|
||||
return (current)->serial >> TRIE_SERIAL_KEY_LEN_OFFSET;
|
||||
}
|
||||
|
||||
u_int32_t GetTrieNodeOffset(WorkSpace *workSpace, const TrieNode *current)
|
||||
{
|
||||
return (((char *)current) - workSpace->area->data);
|
||||
}
|
||||
|
||||
void SaveIndex(NODE_INDEX *index, u_int32_t offset)
|
||||
{
|
||||
// atomic_store_explicit(¤t->children, new_offset, memory_order_release);
|
||||
*index = offset;
|
||||
}
|
||||
|
||||
int CompareTrieDataNode(TrieNode *node, const char *key, u_int32_t keyLen)
|
||||
{
|
||||
TrieDataNode *data = (TrieDataNode *)node;
|
||||
u_int32_t len = GetTrieKeyLen((TrieNode *)data);
|
||||
if (len > keyLen) {
|
||||
return -1;
|
||||
} else if (len < keyLen) {
|
||||
return 1;
|
||||
}
|
||||
return strncmp(data->key, key, keyLen);
|
||||
}
|
||||
|
||||
int CompareTrieNode(TrieNode *node, const char *key, u_int32_t keyLen)
|
||||
{
|
||||
u_int32_t len = GetTrieKeyLen(node);
|
||||
if (len > keyLen) {
|
||||
return -1;
|
||||
} else if (len < keyLen) {
|
||||
return 1;
|
||||
}
|
||||
return strncmp(node->key, key, keyLen);
|
||||
}
|
||||
|
||||
static void GetNextKey(const char **remainingKey, int *hasDot, char **subKey, u_int32_t *subKeyLen)
|
||||
{
|
||||
*subKey = strchr(*remainingKey, '.');
|
||||
if (*subKey != NULL) {
|
||||
if ((*subKey)[0] == '.') {
|
||||
*hasDot = 1;
|
||||
}
|
||||
*subKeyLen = *subKey - *remainingKey;
|
||||
} else {
|
||||
*subKeyLen = strlen(*remainingKey);
|
||||
}
|
||||
}
|
||||
|
||||
TrieDataNode *AddTrieDataNode(WorkSpace *workSpace, const char *key, u_int32_t keyLen)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace->allocTrieNode != NULL, return NULL, "Invalid param %s", key);
|
||||
PROPERTY_CHECK(workSpace->compareTrieNode != NULL, return NULL, "Invalid param %s", key);
|
||||
|
||||
const char *remainingKey = key;
|
||||
TrieDataNode *current = (TrieDataNode *)workSpace->rootNode;
|
||||
while (1) {
|
||||
int hasDot = 0;
|
||||
u_int32_t subKeyLen = 0;
|
||||
char *subKey = NULL;
|
||||
GetNextKey(&remainingKey, &hasDot, &subKey, &subKeyLen);
|
||||
if (!subKeyLen) {
|
||||
return NULL;
|
||||
}
|
||||
u_int32_t offset = subKey == NULL ? strlen(key) : subKey - key;
|
||||
|
||||
if (current->child != 0) { // 如果child存在,则检查是否匹配
|
||||
TrieDataNode *next = (TrieDataNode*)GetTrieNode(workSpace, ¤t->child);
|
||||
if (next != NULL && workSpace->compareTrieNode((TrieNode*)next, remainingKey, subKeyLen) == 0) {
|
||||
current = next;
|
||||
} else { // 不匹配,需要建立子树
|
||||
current = (TrieDataNode*)AddToSubTrie(workSpace, current, key, offset);
|
||||
}
|
||||
} else if (hasDot) {
|
||||
u_int32_t offset = workSpace->allocTrieNode(workSpace, remainingKey, subKeyLen);
|
||||
PROPERTY_CHECK(offset != 0, return NULL, "Failed to allocate key %s", key);
|
||||
SaveIndex(¤t->child, offset);
|
||||
current = (TrieDataNode*)GetTrieNode(workSpace, ¤t->child);
|
||||
} else {
|
||||
current = (TrieDataNode*)AddToSubTrie(workSpace, current, key, offset);
|
||||
}
|
||||
if (current == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (subKey == NULL || strcmp(subKey, ".") == 0) {
|
||||
break;
|
||||
}
|
||||
remainingKey = subKey + 1;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
TrieDataNode *AddToSubTrie(WorkSpace *workSpace, TrieDataNode *dataNode, const char *key, u_int32_t keyLen)
|
||||
{
|
||||
TrieDataNode *root = NULL;
|
||||
int ret = workSpace->compareTrieNode((TrieNode *)dataNode, key, keyLen);
|
||||
if (ret <= 0) {
|
||||
root = (TrieDataNode *)GetTrieNode(workSpace, &dataNode->left);
|
||||
if (root == NULL) {
|
||||
u_int32_t offset = workSpace->allocTrieNode(workSpace, key, keyLen);
|
||||
PROPERTY_CHECK(offset != 0, return NULL, "Failed to allocate key %s", key);
|
||||
SaveIndex(&dataNode->left, offset);
|
||||
return (TrieDataNode *)GetTrieNode(workSpace, &dataNode->left);
|
||||
}
|
||||
} else {
|
||||
root = (TrieDataNode *)GetTrieNode(workSpace, &dataNode->right);
|
||||
if (root == NULL) {
|
||||
u_int32_t offset = workSpace->allocTrieNode(workSpace, key, keyLen);
|
||||
PROPERTY_CHECK(offset != 0, return NULL, "Failed to allocate key %s", key);
|
||||
SaveIndex(&dataNode->right, offset);
|
||||
return (TrieDataNode *)GetTrieNode(workSpace, &dataNode->right);
|
||||
}
|
||||
}
|
||||
return (TrieDataNode*)AddTrieNode(workSpace, (TrieNode*)root, key, keyLen);
|
||||
}
|
||||
|
||||
TrieNode *AddTrieNode(WorkSpace *workSpace, TrieNode *root, const char *key, u_int32_t keyLen)
|
||||
{
|
||||
PROPERTY_CHECK(root != NULL, return NULL, "Invalid param %s", key);
|
||||
TrieNode *current = root;
|
||||
TrieNode *next = NULL;
|
||||
while (1) {
|
||||
if (current == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
int ret = workSpace->compareTrieNode(current, key, keyLen);
|
||||
if (ret == 0) {
|
||||
return current;
|
||||
}
|
||||
if (ret < 0) {
|
||||
next = GetTrieNode(workSpace, ¤t->left);
|
||||
if (next == NULL) {
|
||||
u_int32_t offset = workSpace->allocTrieNode(workSpace, key, keyLen);
|
||||
PROPERTY_CHECK(offset != 0, return NULL, "Failed to allocate key %s", key);
|
||||
SaveIndex(¤t->left, offset);
|
||||
return GetTrieNode(workSpace, ¤t->left);
|
||||
}
|
||||
} else {
|
||||
next = GetTrieNode(workSpace, ¤t->right);
|
||||
if (next == NULL) {
|
||||
u_int32_t offset = workSpace->allocTrieNode(workSpace, key, keyLen);
|
||||
PROPERTY_CHECK(offset != 0, return NULL, "Failed to allocate key %s", key);
|
||||
SaveIndex(¤t->right, offset);
|
||||
return GetTrieNode(workSpace, ¤t->right);
|
||||
}
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
TrieDataNode *FindTrieDataNode(WorkSpace *workSpace, const char *key, u_int32_t keyLen, int matchPrefix)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace->allocTrieNode != NULL, return NULL, "Invalid param %s", key);
|
||||
PROPERTY_CHECK(workSpace->compareTrieNode != NULL, return NULL, "Invalid param %s", key);
|
||||
|
||||
const char *remainingKey = key;
|
||||
TrieDataNode *matchNode = (TrieDataNode *)workSpace->rootNode;
|
||||
TrieDataNode *current = (TrieDataNode *)workSpace->rootNode;
|
||||
while (1) {
|
||||
int hasDot = 0;
|
||||
u_int32_t subKeyLen = 0;
|
||||
char *subKey = NULL;
|
||||
GetNextKey(&remainingKey, &hasDot, &subKey, &subKeyLen);
|
||||
if (!subKeyLen) {
|
||||
return matchPrefix ? matchNode : NULL;
|
||||
}
|
||||
u_int32_t offset = subKey == NULL ? strlen(key) : subKey - key;
|
||||
|
||||
if (current->child != 0) { // 如果child存在,则检查是否匹配
|
||||
TrieDataNode *next = (TrieDataNode*)GetTrieNode(workSpace, ¤t->child);
|
||||
if (next != NULL && workSpace->compareTrieNode((TrieNode*)next, remainingKey, subKeyLen) == 0) {
|
||||
current = next;
|
||||
} else { // 不匹配,搜索子树
|
||||
current = (TrieDataNode*)FindSubTrie(workSpace, current, key, offset);
|
||||
}
|
||||
} else {
|
||||
current = (TrieDataNode*)FindSubTrie(workSpace, current, key, offset);
|
||||
}
|
||||
if (current == NULL) {
|
||||
return matchPrefix ? matchNode : NULL;
|
||||
}
|
||||
matchNode = current;
|
||||
if (subKey == NULL || strcmp(subKey, ".") == 0) {
|
||||
break;
|
||||
}
|
||||
remainingKey = subKey + 1;
|
||||
}
|
||||
return matchPrefix ? matchNode : current;
|
||||
}
|
||||
|
||||
TrieDataNode *FindSubTrie(WorkSpace *workSpace, TrieDataNode *dataNode, const char *key, u_int32_t keyLen)
|
||||
{
|
||||
TrieDataNode *root = NULL;
|
||||
int ret = workSpace->compareTrieNode((TrieNode*)dataNode, key, keyLen);
|
||||
if (ret <= 0) {
|
||||
root = (TrieDataNode *)GetTrieNode(workSpace, &dataNode->left);
|
||||
if (root == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
root = (TrieDataNode *)GetTrieNode(workSpace, &dataNode->right);
|
||||
if (root == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return (TrieDataNode*)FindTrieNode(workSpace, (TrieNode*)root, key, keyLen);
|
||||
}
|
||||
|
||||
TrieNode *FindTrieNode(WorkSpace *workSpace, TrieNode *root, const char *key, u_int32_t keyLen)
|
||||
{
|
||||
PROPERTY_CHECK(root != NULL, return NULL, "Invalid param %s", key);
|
||||
TrieNode *current = root;
|
||||
TrieNode *next = NULL;
|
||||
while (1) {
|
||||
if (current == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
int ret = workSpace->compareTrieNode(current, key, keyLen);
|
||||
if (ret == 0) {
|
||||
return current;
|
||||
}
|
||||
if (ret < 0) {
|
||||
next = GetTrieNode(workSpace, ¤t->left);
|
||||
} else {
|
||||
next = GetTrieNode(workSpace, ¤t->right);
|
||||
}
|
||||
if (next == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
int TraversalTrieDataNode(WorkSpace *workSpace, TrieDataNode *current, TraversalTrieNodePtr walkFunc, void* cookie)
|
||||
{
|
||||
PROPERTY_CHECK(walkFunc != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
PROPERTY_CHECK(workSpace != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
if (current == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
TrieDataNode *child = NULL;
|
||||
// 显示子树
|
||||
TraversalTrieDataNode(workSpace, (TrieDataNode*)GetTrieNode(workSpace, ¤t->left), walkFunc, cookie);
|
||||
TraversalTrieDataNode(workSpace, (TrieDataNode*)GetTrieNode(workSpace, ¤t->right), walkFunc, cookie);
|
||||
walkFunc(workSpace, (TrieNode *)current, cookie);
|
||||
|
||||
if (current->child != 0) { // 如果child存在,则检查是否匹配
|
||||
child = (TrieDataNode*)GetTrieNode(workSpace, ¤t->child);
|
||||
}
|
||||
if (child == NULL) {
|
||||
return 0;
|
||||
}
|
||||
current = child;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TraversalTrieNode(WorkSpace *workSpace, TrieNode *root, TraversalTrieNodePtr walkFunc, void* cookie)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
PROPERTY_CHECK(walkFunc != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
if (root == NULL) {
|
||||
return 0;
|
||||
}
|
||||
TraversalTrieNode(workSpace, GetTrieNode(workSpace, &root->left), walkFunc, cookie);
|
||||
TraversalTrieNode(workSpace, GetTrieNode(workSpace, &root->right), walkFunc, cookie);
|
||||
walkFunc(workSpace, (TrieNode *)root, cookie);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u_int32_t AddData(WorkSpace *workSpace, const char *key, u_int32_t keyLen, const char *value, u_int32_t valueLen)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace != NULL, return 0, "Invalid param");
|
||||
PROPERTY_CHECK(key != NULL && value != NULL, return 0, "Invalid param");
|
||||
u_int32_t realLen = sizeof(DataEntry) + 1 + 1;
|
||||
if (valueLen > PROPERTY_VALUE_LEN_MAX) { // value超过最大时,只能是只读属性,保存最大字符串
|
||||
realLen = keyLen + valueLen;
|
||||
} else {
|
||||
realLen = keyLen + PROPERTY_VALUE_LEN_MAX; // 属性保存,预留最大属性值长度
|
||||
}
|
||||
PROPERTY_CHECK((workSpace->area->currOffset + realLen) < workSpace->area->dataSize, return 0,
|
||||
"Failed to allocate currOffset %d, dataSize %d", workSpace->area->currOffset, workSpace->area->dataSize);
|
||||
|
||||
DataEntry *node = (DataEntry*)(workSpace->area->data + workSpace->area->currOffset);
|
||||
u_int32_t dataLength = keyLen << TRIE_SERIAL_KEY_LEN_OFFSET | valueLen << TRIE_SERIAL_DATA_LEN_OFFSET;
|
||||
atomic_init(&node->serial, ATOMIC_VAR_INIT(0));
|
||||
atomic_init(&node->dataLength, ATOMIC_VAR_INIT(dataLength));
|
||||
|
||||
int ret = memcpy_s(node->data, keyLen, key, keyLen);
|
||||
ret |= memcpy_s(node->data + keyLen + 1, valueLen, value, valueLen);
|
||||
PROPERTY_CHECK(ret == 0, return 0, "Failed to copy key");
|
||||
node->data[keyLen] = '=';
|
||||
node->data[keyLen + 1 + valueLen] = '\0';
|
||||
u_int32_t offset = workSpace->area->currOffset;
|
||||
workSpace->area->currOffset += realLen;
|
||||
return offset;
|
||||
}
|
||||
|
||||
int UpdateDataValue(DataEntry *entry, const char *value)
|
||||
{
|
||||
PROPERTY_CHECK(entry != NULL && value != NULL, return PROPERTY_CODE_INVALID_PARAM, "Failed to check param");
|
||||
int ret = PROPERTY_CODE_INVALID_VALUE;
|
||||
u_int32_t keyLen = DATA_ENTRY_KEY_LEN(entry);
|
||||
u_int32_t valueLen = strlen(value);
|
||||
u_int32_t oldLen = DATA_ENTRY_DATA_LEN(entry);
|
||||
if (oldLen < PROPERTY_VALUE_LEN_MAX && valueLen < PROPERTY_VALUE_LEN_MAX) {
|
||||
PROPERTY_LOGE("Old value %s new value %s", entry->data + keyLen + 1, value);
|
||||
ret = memcpy_s(entry->data + keyLen + 1, PROPERTY_VALUE_LEN_MAX, value, valueLen + 1);
|
||||
PROPERTY_CHECK(ret == 0, return PROPERTY_CODE_INVALID_VALUE, "Failed to copy value");
|
||||
u_int32_t dataLength = keyLen << TRIE_SERIAL_KEY_LEN_OFFSET | valueLen << TRIE_SERIAL_DATA_LEN_OFFSET;
|
||||
atomic_store_explicit(&entry->dataLength, dataLength, memory_order_release);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
u_int32_t GetDataSerial(const DataEntry *entry)
|
||||
{
|
||||
u_int32_t serial = atomic_load_explicit(&entry->serial, memory_order_acquire);
|
||||
while (DATA_ENTRY_DIRTY(serial)) {
|
||||
futex_wait(&entry->serial, serial, NULL);
|
||||
serial = atomic_load_explicit(&entry->serial, memory_order_acquire);
|
||||
}
|
||||
return serial;
|
||||
}
|
||||
|
||||
int GetDataName(const DataEntry *entry, char *name, u_int32_t len)
|
||||
{
|
||||
PROPERTY_CHECK(entry != NULL && name != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
u_int32_t keyLen = DATA_ENTRY_KEY_LEN(entry);
|
||||
PROPERTY_CHECK(len > keyLen, return -1, "Invalid param size");
|
||||
int ret = memcpy_s(name, len, entry->data, keyLen);
|
||||
PROPERTY_CHECK(ret == 0, return PROPERTY_CODE_INVALID_PARAM, "Failed to copy name");
|
||||
name[keyLen] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
int GetDataValue(const DataEntry *entry, char *value, u_int32_t len)
|
||||
{
|
||||
PROPERTY_CHECK(entry != NULL && value != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
u_int32_t keyLen = DATA_ENTRY_KEY_LEN(entry);
|
||||
u_int32_t valueLen = DATA_ENTRY_DATA_LEN(entry);
|
||||
PROPERTY_CHECK(len > valueLen, return PROPERTY_CODE_INVALID_PARAM, "Invalid value len %u %u", len, valueLen);
|
||||
int ret = memcpy_s(value, len, entry->data + keyLen + 1, valueLen);
|
||||
PROPERTY_CHECK(ret == 0, return PROPERTY_CODE_INVALID_PARAM, "Failed to copy value");
|
||||
value[valueLen] = '\0';
|
||||
return ret;
|
||||
}
|
156
services/property/service/property_persist.c
Executable file
156
services/property/service/property_persist.c
Executable file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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 "property.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "property_manager.h"
|
||||
#include "property_trie.h"
|
||||
|
||||
#define LABEL "Manager"
|
||||
#define MAX_BUFF 256
|
||||
|
||||
typedef struct {
|
||||
WorkSpace *workSpace;
|
||||
WorkSpace *persistWorkSpace;
|
||||
char *buffer;
|
||||
} PersistContext;
|
||||
|
||||
static PropertyPersistWorkSpace g_persistWorkSpace = {ATOMIC_VAR_INIT(0), };
|
||||
|
||||
static int ProcessPropertTraversal(WorkSpace *workSpace, TrieNode *node, void *cookie)
|
||||
{
|
||||
PROPERTY_CHECK(workSpace != 0 && node != NULL && cookie != NULL, return -1, "Invalid param");
|
||||
TrieDataNode *current = (TrieDataNode *)node;
|
||||
if (current == NULL || current->dataIndex == 0) {
|
||||
return 0;
|
||||
}
|
||||
DataEntry *entry = (DataEntry *)GetTrieNode(workSpace, ¤t->dataIndex);
|
||||
if (entry == NULL) {
|
||||
return -1;
|
||||
}
|
||||
PersistContext *persistContext = (PersistContext *)cookie;
|
||||
int ret = GetDataName(entry, persistContext->buffer, MAX_BUFF);
|
||||
if (strncmp(persistContext->buffer, "persist.", strlen("persist.")) != 0) {
|
||||
return 0;
|
||||
}
|
||||
ret |= GetDataValue(entry, persistContext->buffer + MAX_BUFF, MAX_BUFF);
|
||||
if (ret == 0) { // 只支持新建
|
||||
PROPERTY_LOGI("Insert new persist property from normal property %s", persistContext->buffer);
|
||||
ret = AddProperty(persistContext->persistWorkSpace, persistContext->buffer, persistContext->buffer + MAX_BUFF);
|
||||
}
|
||||
PROPERTY_CHECK(ret == 0, return ret, "Failed to add persist property");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ProcessPersistPropertTraversal(WorkSpace *workSpace, TrieNode *node, void *cookie)
|
||||
{
|
||||
TrieDataNode *current = (TrieDataNode *)node;
|
||||
if (current == NULL || current->dataIndex == 0) {
|
||||
return 0;
|
||||
}
|
||||
DataEntry *entry = (DataEntry *)GetTrieNode(workSpace, ¤t->dataIndex);
|
||||
if (entry == NULL) {
|
||||
return -1;
|
||||
}
|
||||
PersistContext *persistContext = (PersistContext *)cookie;
|
||||
int ret = GetDataName(entry, persistContext->buffer, MAX_BUFF);
|
||||
ret |= GetDataValue(entry, persistContext->buffer + MAX_BUFF, MAX_BUFF);
|
||||
if (ret == 0) {
|
||||
PROPERTY_LOGI("update normal property %s %s from persist property ",
|
||||
persistContext->buffer, persistContext->buffer + MAX_BUFF);
|
||||
ret = WriteProperty(persistContext->workSpace, persistContext->buffer, persistContext->buffer + MAX_BUFF);
|
||||
}
|
||||
PROPERTY_CHECK(ret == 0, return ret, "Failed to add persist property");
|
||||
return ret;
|
||||
}
|
||||
|
||||
int InitPersistPropertyWorkSpace(const char *context)
|
||||
{
|
||||
u_int32_t flags = atomic_load_explicit(&g_persistWorkSpace.flags, memory_order_relaxed);
|
||||
PROPERTY_LOGI("InitPersistPropertyWorkSpace flags %x", flags);
|
||||
if ((flags & WORKSPACE_FLAGS_INIT) == WORKSPACE_FLAGS_INIT) {
|
||||
return 0;
|
||||
}
|
||||
g_persistWorkSpace.persistWorkSpace.compareTrieNode = CompareTrieDataNode;
|
||||
g_persistWorkSpace.persistWorkSpace.allocTrieNode = AllocateTrieDataNode;
|
||||
int ret = InitPersistWorkSpace(PROPERTY_PERSIST_PATH, &g_persistWorkSpace.persistWorkSpace);
|
||||
atomic_store_explicit(&g_persistWorkSpace.flags, WORKSPACE_FLAGS_INIT, memory_order_release);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int RefreshPersistProperties(PropertyWorkSpace *workSpace, const char *context)
|
||||
{
|
||||
u_int32_t flags = atomic_load_explicit(&g_persistWorkSpace.flags, memory_order_relaxed);
|
||||
if ((flags & WORKSPACE_FLAGS_INIT) != WORKSPACE_FLAGS_INIT) {
|
||||
int ret = InitPersistPropertyWorkSpace(context);
|
||||
PROPERTY_CHECK(ret == 0, return ret, "Failed to init persist property");
|
||||
flags = atomic_load_explicit(&g_persistWorkSpace.flags, memory_order_relaxed);
|
||||
}
|
||||
|
||||
if ((flags & WORKSPACE_FLAGS_LOADED) == WORKSPACE_FLAGS_LOADED) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 申请临时的缓存,用于数据读取
|
||||
char *buffer = (char *)malloc(MAX_BUFF + MAX_BUFF);
|
||||
PROPERTY_CHECK(buffer != NULL, return -1, "Failed to malloc memory for property");
|
||||
PersistContext persistContext = {
|
||||
&workSpace->propertySpace, &g_persistWorkSpace.persistWorkSpace, buffer
|
||||
};
|
||||
|
||||
// 遍历当前的属性,并把persist的写入
|
||||
int ret = TraversalTrieDataNode(&workSpace->propertySpace,
|
||||
(TrieDataNode *)workSpace->propertySpace.rootNode, ProcessPropertTraversal, &persistContext);
|
||||
|
||||
// 修改默认属性值
|
||||
ret = TraversalTrieDataNode(&g_persistWorkSpace.persistWorkSpace,
|
||||
(TrieDataNode *)g_persistWorkSpace.persistWorkSpace.rootNode, ProcessPersistPropertTraversal, &persistContext);
|
||||
|
||||
atomic_store_explicit(&g_persistWorkSpace.flags, flags | WORKSPACE_FLAGS_LOADED, memory_order_release);
|
||||
free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ClosePersistPropertyWorkSpace()
|
||||
{
|
||||
CloseWorkSpace(&g_persistWorkSpace.persistWorkSpace);
|
||||
atomic_store_explicit(&g_persistWorkSpace.flags, 0, memory_order_release);
|
||||
}
|
||||
|
||||
int WritePersistProperty(const char *name, const char *value)
|
||||
{
|
||||
PROPERTY_CHECK(value != NULL && name != NULL, return PROPERTY_CODE_INVALID_PARAM, "Invalid param");
|
||||
|
||||
u_int32_t flags = atomic_load_explicit(&g_persistWorkSpace.flags, memory_order_relaxed);
|
||||
if ((flags & WORKSPACE_FLAGS_LOADED) != WORKSPACE_FLAGS_LOADED) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strncmp(name, "persist.", strlen("persist.")) != 0) {
|
||||
return 0;
|
||||
}
|
||||
return WriteProperty(&g_persistWorkSpace.persistWorkSpace, name, value);
|
||||
}
|
282
services/property/service/property_service.c
Executable file
282
services/property/service/property_service.c
Executable file
@ -0,0 +1,282 @@
|
||||
/*
|
||||
* 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 "property_service.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "property.h"
|
||||
#include "property_manager.h"
|
||||
#include "property_request.h"
|
||||
#include "trigger.h"
|
||||
|
||||
#include "uv.h"
|
||||
|
||||
#define BUFFER_SIZE 256
|
||||
#define LABEL "Server"
|
||||
|
||||
static char *g_initContext = "";
|
||||
static PropertyWorkSpace g_propertyWorkSpace = {ATOMIC_VAR_INIT(0), {}, {}, {}};
|
||||
|
||||
void InitPropertyService()
|
||||
{
|
||||
int ret = InitPropertyWorkSpace(&g_propertyWorkSpace, 0, g_initContext);
|
||||
PROPERTY_CHECK(ret == 0, return, "Init propert workspace fail");
|
||||
}
|
||||
|
||||
int LoadDefaultProperty(const char *fileName)
|
||||
{
|
||||
u_int32_t flags = atomic_load_explicit(&g_propertyWorkSpace.flags, memory_order_relaxed);
|
||||
if ((flags & WORKSPACE_FLAGS_INIT) != WORKSPACE_FLAGS_INIT) {
|
||||
return PROPERTY_CODE_NOT_INIT;
|
||||
}
|
||||
|
||||
FILE *fp = fopen(fileName, "r");
|
||||
PROPERTY_CHECK(fp != NULL, return -1, "Open file %s fail", fileName);
|
||||
char buff[BUFFER_SIZE];
|
||||
SubStringInfo *info = malloc(sizeof(SubStringInfo) * (SUBSTR_INFO_LABEL + 1));
|
||||
while(fgets(buff, BUFFER_SIZE, fp) != NULL) {
|
||||
int subStrNumber = GetSubStringInfo(buff, strlen(buff), '\n', info, SUBSTR_INFO_LABEL + 1);
|
||||
if (subStrNumber <= SUBSTR_INFO_LABEL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(info[0].value, "ctl.", strlen("ctl.")) == 0) {
|
||||
PROPERTY_LOGE("Do not set ctl. properties from init %s", info[0].value);
|
||||
continue;
|
||||
}
|
||||
if (strcmp(info[0].value, "selinux.restorecon_recursive") == 0) {
|
||||
PROPERTY_LOGE("Do not set selinux.restorecon_recursive from init %s", info[0].value);
|
||||
continue;
|
||||
}
|
||||
int ret = CheckPropertyName(info[0].value, 0);
|
||||
PROPERTY_CHECK(ret == 0, continue, "Illegal property name %s", info[0].value);
|
||||
|
||||
ret = WriteProperty(&g_propertyWorkSpace.propertySpace, info[0].value, info[1].value);
|
||||
PROPERTY_CHECK(ret == 0, continue, "Failed to set property %d %s", ret, buff);
|
||||
|
||||
ret = WritePersistProperty(info[0].value, info[1].value);
|
||||
PROPERTY_CHECK(ret == 0, continue, "Failed to set persist property %d %s", ret, buff);
|
||||
}
|
||||
fclose(fp);
|
||||
free(info);
|
||||
PROPERTY_LOGI("LoadDefaultProperty proterty success %s", fileName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LoadPropertyInfo(const char *fileName)
|
||||
{
|
||||
u_int32_t flags = atomic_load_explicit(&g_propertyWorkSpace.flags, memory_order_relaxed);
|
||||
if ((flags & WORKSPACE_FLAGS_INIT) != WORKSPACE_FLAGS_INIT) {
|
||||
return PROPERTY_CODE_NOT_INIT;
|
||||
}
|
||||
FILE *fp = fopen(fileName, "r");
|
||||
PROPERTY_CHECK(fp != NULL, return -1, "Open file %s fail", fileName);
|
||||
SubStringInfo *info = malloc(sizeof(SubStringInfo) * SUBSTR_INFO_MAX);
|
||||
char buff[BUFFER_SIZE];
|
||||
int propInfoCount = 0;
|
||||
while(fgets(buff, BUFFER_SIZE, fp) != NULL) {
|
||||
int subStrNumber = GetSubStringInfo(buff, strlen(buff), ' ', info, SUBSTR_INFO_MAX);
|
||||
if (subStrNumber <= 0) {
|
||||
continue;
|
||||
}
|
||||
int ret = WritePropertyInfo(&g_propertyWorkSpace, info, subStrNumber);
|
||||
PROPERTY_CHECK(ret == 0, continue, "Failed to write property info %d %s", ret, buff);
|
||||
propInfoCount++;
|
||||
}
|
||||
fclose(fp);
|
||||
free(info);
|
||||
PROPERTY_LOGI("Load proterty info %d success %s", propInfoCount, fileName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ProcessPropertySet(RequestMsg *msg)
|
||||
{
|
||||
PROPERTY_CHECK(msg != NULL, return PROPERTY_CODE_INVALID_PARAM, "Failed to check param");
|
||||
|
||||
SubStringInfo info[3];
|
||||
int ret = GetSubStringInfo(msg->content, msg->contentSize, '=', info, sizeof(info)/sizeof(info[0]));
|
||||
PROPERTY_CHECK(ret >= 2, return ret, "Failed to get name from content %s", msg->content);
|
||||
|
||||
PROPERTY_LOGI("ProcessPropertySet name %s value: %s", info[0].value, info[1].value);
|
||||
ret = WritePropertyWithCheck(&g_propertyWorkSpace, &msg->securitylabel, info[0].value, info[1].value);
|
||||
PROPERTY_CHECK(ret == 0, return ret, "Failed to set property %d name %s %s", ret, info[0].value, info[1].value);
|
||||
|
||||
ret = WritePersistProperty(info[0].value, info[1].value);
|
||||
PROPERTY_CHECK(ret == 0, return ret, "Failed to set property");
|
||||
|
||||
// notify event to process trigger
|
||||
PostTrigger(EVENT_PROPERTY, msg->content, msg->contentSize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void OnClose(uv_handle_t *handle)
|
||||
{
|
||||
free(handle);
|
||||
}
|
||||
|
||||
static void OnReceiveAlloc(uv_handle_t *handle, size_t suggestedSize, uv_buf_t* buf)
|
||||
{
|
||||
// 这里需要按实际消息的大小申请内存,取最大消息的长度
|
||||
buf->base = (char *)malloc(sizeof(RequestMsg) + BUFFER_SIZE * 2);
|
||||
buf->len = suggestedSize;
|
||||
}
|
||||
|
||||
static void OnWriteResponse(uv_write_t *req, int status)
|
||||
{
|
||||
// 发送成功,释放请求内存
|
||||
PROPERTY_LOGI("OnWriteResponse status %d", status);
|
||||
ResponseNode *node = (ResponseNode*)req;
|
||||
free(node);
|
||||
}
|
||||
|
||||
static void SendResponse(uv_stream_t *handle, RequestType type, int result, void *content, int size)
|
||||
{
|
||||
int ret = 0;
|
||||
// 申请整块内存,用于回复数据和写请求
|
||||
ResponseNode *response = (ResponseNode *)malloc(sizeof(ResponseNode) + size);
|
||||
PROPERTY_CHECK(response != NULL, return, "Failed to alloc memory for response");
|
||||
response->msg.type = type;
|
||||
response->msg.contentSize = size;
|
||||
response->msg.result = result;
|
||||
if (content != NULL && size != 0) {
|
||||
ret = memcpy_s(response->msg.content, size, content, size);
|
||||
PROPERTY_CHECK(ret == 0, return, "Failed to copy content");
|
||||
}
|
||||
uv_buf_t buf = uv_buf_init((char *)&response->msg, sizeof(response->msg) + size);
|
||||
ret = uv_write2(&response->writer, handle, &buf, 1, handle, OnWriteResponse);
|
||||
PROPERTY_CHECK(ret >= 0, return, "Failed to uv_write2 ret %s", uv_strerror(ret));
|
||||
}
|
||||
|
||||
static void OnReceiveRequest(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf)
|
||||
{
|
||||
if (nread <= 0 || buf == NULL || buf->base == NULL) {
|
||||
uv_close((uv_handle_t*)handle, OnClose);
|
||||
free(buf->base);
|
||||
return;
|
||||
}
|
||||
int freeHandle = 1;
|
||||
RequestMsg *msg = (RequestMsg *)buf->base;
|
||||
switch (msg->type) {
|
||||
case SET_PROPERTY: {
|
||||
freeHandle = 0;
|
||||
int ret = ProcessPropertySet(msg);
|
||||
SendResponse(handle, SET_PROPERTY, ret, NULL, 0);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PROPERTY_LOGE("not supported the command: %d", msg->type);
|
||||
break;
|
||||
}
|
||||
free(buf->base);
|
||||
uv_close((uv_handle_t*)handle, OnClose);
|
||||
}
|
||||
|
||||
static void RemoveSocket(int sig)
|
||||
{
|
||||
uv_fs_t req;
|
||||
uv_fs_unlink(uv_default_loop(), &req, PIPE_NAME, NULL);
|
||||
ClosePropertyWorkSpace(&g_propertyWorkSpace);
|
||||
ClosePersistPropertyWorkSpace();
|
||||
uv_stop(uv_default_loop());
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void OnConnection(uv_stream_t *server, int status)
|
||||
{
|
||||
PROPERTY_CHECK(status >= 0, return, "Error status %d", status);
|
||||
PROPERTY_CHECK(server != NULL, return, "Error server");
|
||||
uv_pipe_t *stream = (uv_pipe_t*)malloc(sizeof(uv_pipe_t));
|
||||
PROPERTY_CHECK(stream != NULL, return, "Failed to alloc stream");
|
||||
|
||||
int ret = uv_pipe_init(uv_default_loop(), (uv_pipe_t*)stream, 1);
|
||||
PROPERTY_CHECK(ret == 0, free(stream); return, "Failed to uv_pipe_init %d", ret);
|
||||
|
||||
stream->data = server;
|
||||
ret = uv_accept(server, (uv_stream_t *)stream);
|
||||
PROPERTY_CHECK(ret == 0, uv_close((uv_handle_t*)stream, NULL); free(stream);
|
||||
return, "Failed to uv_accept %d", ret);
|
||||
|
||||
ret = uv_read_start((uv_stream_t *)stream, OnReceiveAlloc, OnReceiveRequest);
|
||||
PROPERTY_CHECK(ret == 0, uv_close((uv_handle_t*)stream, NULL); free(stream);
|
||||
return, "Failed to uv_read_start %d", ret);
|
||||
}
|
||||
|
||||
int StartPropertyService()
|
||||
{
|
||||
PROPERTY_LOGI("StartPropertyService.");
|
||||
uv_fs_t req;
|
||||
uv_fs_unlink(uv_default_loop(), &req, PIPE_NAME, NULL);
|
||||
|
||||
signal(SIGINT, RemoveSocket);
|
||||
|
||||
uv_pipe_t pipeServer;
|
||||
int ret = uv_pipe_init(uv_default_loop(), &pipeServer, 0);
|
||||
PROPERTY_CHECK(ret == 0, return ret, "Failed to uv_pipe_init %d", ret);
|
||||
ret = uv_pipe_bind(&pipeServer, PIPE_NAME);
|
||||
PROPERTY_CHECK(ret == 0, return ret, "Failed to uv_pipe_bind %d %s", ret, uv_err_name(ret));
|
||||
ret = uv_listen((uv_stream_t*)&pipeServer, SOMAXCONN, OnConnection);
|
||||
PROPERTY_CHECK(ret == 0, return ret, "Failed to uv_listen %d %s", ret, uv_err_name(ret));
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
PROPERTY_LOGI("Start service exit.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SystemWriteParameter(const char *name, const char *value)
|
||||
{
|
||||
PROPERTY_CHECK(name != NULL && value != NULL, return -1, "The name is null");
|
||||
PROPERTY_LOGI("SystemWriteParameter name %s value: %s", name, value);
|
||||
int ret = WritePropertyWithCheck(&g_propertyWorkSpace, &g_propertyWorkSpace.label, name, value);
|
||||
if (ret == 0) {
|
||||
ret = WritePersistProperty(name, value);
|
||||
PROPERTY_CHECK(ret == 0, return ret, "Failed to set property");
|
||||
} else {
|
||||
PROPERTY_LOGE("Failed to set property %d name %s %s", ret, name, value);
|
||||
}
|
||||
// notify event to process trigger
|
||||
PostPropertyTrigger(name, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SystemReadParameter(const char *name, char *value, unsigned int *len)
|
||||
{
|
||||
PROPERTY_CHECK(name != NULL && len != NULL, return -1, "The name is null");
|
||||
PropertyHandle handle = 0;
|
||||
int ret = ReadPropertyWithCheck(&g_propertyWorkSpace, name, &handle);
|
||||
if (ret == 0) {
|
||||
ret = ReadPropertyValue(&g_propertyWorkSpace, handle, value, len);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SystemTraversalParameters(void (*traversalParameter)(PropertyHandle handle, void* cookie), void* cookie)
|
||||
{
|
||||
PROPERTY_CHECK(traversalParameter != NULL, return -1, "The param is null");
|
||||
return TraversalProperty(&g_propertyWorkSpace, traversalParameter, cookie);
|
||||
}
|
||||
|
||||
PropertyWorkSpace *GetPropertyWorkSpace()
|
||||
{
|
||||
return &g_propertyWorkSpace;
|
||||
}
|
||||
|
||||
int LoadPersistProperties()
|
||||
{
|
||||
return RefreshPersistProperties(&g_propertyWorkSpace, g_initContext);
|
||||
}
|
@ -38,6 +38,11 @@ void MountBasicFs()
|
||||
if (mount("sysfs", "/sys", "sysfs", 0, NULL) != 0) {
|
||||
printf("Mount sysfs failed. %s\n", strerror(errno));
|
||||
}
|
||||
#ifndef __LITEOS__
|
||||
if (mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL) != 0) {
|
||||
printf("Mount selinuxfs failed. %s\n", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CreateDeviceNode()
|
||||
@ -56,3 +61,19 @@ void CreateDeviceNode()
|
||||
printf("Create /dev/urandom device node failed. %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
int MakeSocketDir(const char *path, mode_t mode)
|
||||
{
|
||||
int rc = mkdir("/dev/unix/", mode);
|
||||
if (rc < 0 && errno != EEXIST) {
|
||||
printf("Create %s failed. %d\n", path, errno);
|
||||
return -1;
|
||||
}
|
||||
rc = mkdir("/dev/unix/socket/", mode);
|
||||
if (rc < 0 && errno != EEXIST) {
|
||||
printf("Create %s failed. %d\n", path, errno);
|
||||
return -1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -20,8 +20,10 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/reboot.h>
|
||||
#ifdef __LINUX__
|
||||
#if ((defined __LINUX__) || (!defined OHOS_LITE))
|
||||
#include <linux/securebits.h>
|
||||
#endif
|
||||
#ifdef __LINUX__
|
||||
#include "init_signal_handler.h"
|
||||
#endif
|
||||
|
||||
@ -35,9 +37,9 @@ void RebootSystem()
|
||||
|
||||
int KeepCapability()
|
||||
{
|
||||
#ifdef __LINUX__
|
||||
#if ((defined __LINUX__) || (!defined OHOS_LITE))
|
||||
if (prctl(PR_SET_SECUREBITS, SECBIT_NO_SETUID_FIXUP | SECBIT_NO_SETUID_FIXUP_LOCKED)) {
|
||||
printf("[Init] prctl failed\n");
|
||||
printf("[Init] prctl PR_SET_SECUREBITS failed: %d\n", errno);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
@ -46,9 +48,9 @@ int KeepCapability()
|
||||
|
||||
int SetAmbientCapability(int cap)
|
||||
{
|
||||
#ifdef __LINUX__
|
||||
#if ((defined __LINUX__) || (!defined OHOS_LITE))
|
||||
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0)) {
|
||||
printf("[Init] prctl PR_CAP_AMBIENT failed\n");
|
||||
printf("[Init] prctl PR_CAP_AMBIENT failed: %d\n", errno);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
165
services/src/init_capability.c
Executable file
165
services/src/init_capability.c
Executable file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* 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 "init_capability.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef OHOS_LITE
|
||||
#include <sys/capability.h>
|
||||
#else
|
||||
#include <linux/capability.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "init_log.h"
|
||||
#include "init_perms.h"
|
||||
|
||||
#define MAX_CAPS_CNT_FOR_ONE_SERVICE 100
|
||||
|
||||
struct CapStrCapNum {
|
||||
char *capStr;
|
||||
int CapNum;
|
||||
};
|
||||
|
||||
static struct CapStrCapNum g_capStrCapNum[] = {
|
||||
{"CHOWN", CAP_CHOWN},
|
||||
{"DAC_OVERRIDE", CAP_DAC_OVERRIDE},
|
||||
{"DAC_READ_SEARCH", CAP_DAC_READ_SEARCH},
|
||||
{"FOWNER", CAP_FOWNER},
|
||||
{"FSETID", CAP_FSETID},
|
||||
{"KILL", CAP_KILL},
|
||||
{"SETGID", CAP_SETGID},
|
||||
{"SETUID", CAP_SETUID},
|
||||
{"SETPCAP", CAP_SETPCAP},
|
||||
{"LINUX_IMMUTABLE", CAP_LINUX_IMMUTABLE},
|
||||
{"NET_BIND_SERVICE", CAP_NET_BIND_SERVICE},
|
||||
{"NET_BROADCAST", CAP_NET_BROADCAST},
|
||||
{"NET_ADMIN", CAP_NET_ADMIN},
|
||||
{"NET_RAW", CAP_NET_RAW},
|
||||
{"IPC_LOCK", CAP_IPC_LOCK},
|
||||
{"IPC_OWNER", CAP_IPC_OWNER},
|
||||
{"SYS_MODULE", CAP_SYS_MODULE},
|
||||
{"SYS_RAWIO", CAP_SYS_RAWIO},
|
||||
{"SYS_CHROOT", CAP_SYS_CHROOT},
|
||||
{"SYS_PTRACE", CAP_SYS_PTRACE},
|
||||
{"SYS_PACCT", CAP_SYS_PACCT},
|
||||
{"SYS_ADMIN", CAP_SYS_ADMIN},
|
||||
{"SYS_BOOT", CAP_SYS_BOOT},
|
||||
{"SYS_NICE", CAP_SYS_NICE},
|
||||
{"SYS_RESOURCE", CAP_SYS_RESOURCE},
|
||||
{"SYS_TIME", CAP_SYS_TIME},
|
||||
{"SYS_TTY_CONFIG", CAP_SYS_TTY_CONFIG},
|
||||
{"MKNOD", CAP_MKNOD},
|
||||
{"LEASE", CAP_LEASE},
|
||||
{"AUDIT_WRITE", CAP_AUDIT_WRITE},
|
||||
{"AUDIT_CONTROL", CAP_AUDIT_CONTROL},
|
||||
{"SETFCAP", CAP_SETFCAP},
|
||||
{"MAC_OVERRIDE", CAP_MAC_OVERRIDE},
|
||||
{"MAC_ADMIN", CAP_MAC_ADMIN},
|
||||
{"SYSLOG", CAP_SYSLOG},
|
||||
{"WAKE_ALARM", CAP_WAKE_ALARM},
|
||||
{"BLOCK_SUSPEND", CAP_BLOCK_SUSPEND},
|
||||
{"AUDIT_READ", CAP_AUDIT_READ},
|
||||
};
|
||||
|
||||
static int GetServiceStringCaps(const cJSON* filedJ, Service* curServ) // string form
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for (; i < curServ->servPerm.capsCnt; ++i) {
|
||||
if (cJSON_GetArrayItem(filedJ, i) == NULL || !cJSON_GetStringValue(cJSON_GetArrayItem(filedJ, i))
|
||||
|| strlen(cJSON_GetStringValue(cJSON_GetArrayItem(filedJ, i))) <= 0) { // check all errors
|
||||
INIT_LOGE("[Init] GetServiceStringCaps, parse item[%d] as string, error.\n", i);
|
||||
break;
|
||||
}
|
||||
char* fieldStr = cJSON_GetStringValue(cJSON_GetArrayItem(filedJ, i));
|
||||
int mapSize = sizeof(g_capStrCapNum) / sizeof(struct CapStrCapNum); // search
|
||||
int j = 0;
|
||||
for (; j < mapSize; j++) {
|
||||
if (!strcmp(fieldStr, g_capStrCapNum[j].capStr)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j < mapSize) {
|
||||
curServ->servPerm.caps[i] = g_capStrCapNum[j].CapNum;
|
||||
} else {
|
||||
INIT_LOGE("[Init] GetServiceStringCaps, fieldStr = %s, error.\n", fieldStr);
|
||||
break;
|
||||
}
|
||||
if (curServ->servPerm.caps[i] > CAP_LAST_CAP && curServ->servPerm.caps[i] != FULL_CAP) {
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
INIT_LOGE("[Init] GetServiceStringCaps, cap = %d, error.\n", curServ->servPerm.caps[i]);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
}
|
||||
int ret = i == curServ->servPerm.capsCnt ? SERVICE_SUCCESS : SERVICE_FAILURE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int GetServiceCaps(const cJSON* curArrItem, Service* curServ)
|
||||
{
|
||||
curServ->servPerm.capsCnt = 0;
|
||||
curServ->servPerm.caps = NULL;
|
||||
cJSON* filedJ = cJSON_GetObjectItem(curArrItem, "caps");
|
||||
if (filedJ == NULL) {
|
||||
INIT_LOGE("[Init] GetServiceCaps, caps is not found. but maybe ok.\n");
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
if (!cJSON_IsArray(filedJ)) {
|
||||
INIT_LOGE("[Init] GetServiceCaps, caps is not a list, error.\n");
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
// caps array does not exist, means do not need any capability
|
||||
int capsCnt = cJSON_GetArraySize(filedJ);
|
||||
if (capsCnt <= 0) {
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
if (capsCnt > MAX_CAPS_CNT_FOR_ONE_SERVICE) {
|
||||
INIT_LOGE("[Init] GetServiceCaps, too many caps[cnt %d] for one service, should not exceed %d.\n",
|
||||
capsCnt, MAX_CAPS_CNT_FOR_ONE_SERVICE);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->servPerm.caps = (unsigned int*)malloc(sizeof(unsigned int) * capsCnt);
|
||||
if (curServ->servPerm.caps == NULL) {
|
||||
INIT_LOGE("[Init] GetServiceCaps, malloc error.\n");
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->servPerm.capsCnt = capsCnt;
|
||||
int i = 0;
|
||||
for (; i < capsCnt; ++i) { // number form
|
||||
cJSON* capJ = cJSON_GetArrayItem(filedJ, i);
|
||||
if (!cJSON_IsNumber(capJ) || cJSON_GetNumberValue(capJ) < 0) {
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
INIT_LOGE("[Init] GetServiceCaps, capJ is not a number or capJ < 0, error.\n");
|
||||
break;
|
||||
}
|
||||
curServ->servPerm.caps[i] = (unsigned int)cJSON_GetNumberValue(capJ);
|
||||
if (curServ->servPerm.caps[i] > CAP_LAST_CAP && curServ->servPerm.caps[i] != FULL_CAP) { // CAP_LAST_CAP = 37
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
INIT_LOGE("[Init] GetServiceCaps, caps = %d, error.\n", curServ->servPerm.caps[i]);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
}
|
||||
if (i == capsCnt) {
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
int ret = GetServiceStringCaps(filedJ, curServ);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Huawei Device Co., Ltd.
|
||||
* Copyright (c) 2020-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
|
||||
@ -23,17 +23,24 @@
|
||||
#include <string.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#ifndef OHOS_LITE
|
||||
#include <fcntl.h>
|
||||
#ifndef OHOS_LITE
|
||||
#include <linux/module.h>
|
||||
#endif
|
||||
#include <sys/syscall.h>
|
||||
#include "init_jobs.h"
|
||||
#include "init_log.h"
|
||||
#include "init_service_manager.h"
|
||||
#include "init_utils.h"
|
||||
#include "securec.h"
|
||||
#ifndef OHOS_LITE
|
||||
#include "property_service.h"
|
||||
#include "trigger.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
|
||||
#define SPACES_CNT_IN_CMD_MIN 2 // mount, min number of spaces in cmdline
|
||||
@ -43,6 +50,9 @@
|
||||
#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
|
||||
#define AUTHORITY_MAX_SIZE 128
|
||||
#define CONVERT_MICROSEC_TO_SEC(x) ((x) / 1000 / 1000)
|
||||
|
||||
static const char *g_supportCfg[] = {
|
||||
"/etc/patch.cfg",
|
||||
"/patch/fstab.cfg",
|
||||
@ -54,8 +64,21 @@ static const char* g_supportedCmds[] = {
|
||||
"chmod ",
|
||||
"chown ",
|
||||
"mount ",
|
||||
"export ",
|
||||
"loadcfg ",
|
||||
"insmod ",
|
||||
"rm ",
|
||||
"rmdir ",
|
||||
"write ",
|
||||
"exec ",
|
||||
"mknode ",
|
||||
"makedev ",
|
||||
"symlink ",
|
||||
"stop ",
|
||||
"trigger ",
|
||||
"reset ",
|
||||
"copy ",
|
||||
"load_persist_props "
|
||||
};
|
||||
|
||||
void ParseCmdLine(const char* cmdStr, CmdLine* resCmd)
|
||||
@ -88,93 +111,165 @@ void ParseCmdLine(const char* cmdStr, CmdLine* resCmd)
|
||||
}
|
||||
|
||||
if (!foundAndSucceed) {
|
||||
printf("[Init][Debug], Cannot parse command: %s\n", cmdStr);
|
||||
(void)memset_s(resCmd, sizeof(*resCmd), 0, sizeof(*resCmd));
|
||||
}
|
||||
}
|
||||
|
||||
static void DoStart(const char* cmdContent)
|
||||
{
|
||||
printf("[init][Debug] DoStart %s \n", cmdContent);
|
||||
StartServiceByName(cmdContent);
|
||||
}
|
||||
|
||||
static void DoMkDir(const char* cmdContent)
|
||||
static void DoStop(const char* cmdContent)
|
||||
{
|
||||
mode_t mode = DEFAULT_DIR_MODE;
|
||||
if (mkdir(cmdContent, mode) != 0) {
|
||||
if (errno != EEXIST) {
|
||||
printf("[Init] DoMkDir, failed for %s, err %d.\n", cmdContent, errno);
|
||||
}
|
||||
}
|
||||
StopServiceByName(cmdContent);
|
||||
}
|
||||
|
||||
static void DoChmod(const char* cmdContent)
|
||||
static void DoReset(const char* cmdContent)
|
||||
{
|
||||
// format: 0xxx /xxx/xxx/xxx
|
||||
if (cmdContent[0] != '0' || cmdContent[MODE_LEN] != ' ' || strlen(cmdContent) <= MODE_LEN + 1) {
|
||||
printf("[Init] DoChmod, bad format for %s.\n", cmdContent);
|
||||
return;
|
||||
}
|
||||
INIT_LOGE("[init][Debug] DoReset %s \n", cmdContent);
|
||||
DoStop(cmdContent);
|
||||
DoStart(cmdContent);
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < MODE_LEN; ++i) {
|
||||
if (cmdContent[i] > '7' || cmdContent[i] < '0') {
|
||||
printf("[Init] DoChmod, bad mode format for %s.\n", cmdContent);
|
||||
return;
|
||||
}
|
||||
static void DoCopy(const char* cmdContent)
|
||||
{
|
||||
int srcFd = -1;
|
||||
int dstFd = -1;
|
||||
int rdLen = 0;
|
||||
int rtLen = 0;
|
||||
char buf[MAX_COPY_BUF_SIZE] = {0};
|
||||
mode_t mode = 0;
|
||||
struct stat fileStat = {0};
|
||||
struct CmdArgs *ctx = GetCmd(cmdContent, " ");
|
||||
if (ctx == NULL || ctx->argv == NULL || ctx->argc != DEFAULT_COPY_ARGS_CNT) {
|
||||
INIT_LOGE("[Init] DoCopy failed.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
const char* pathBeginStr = cmdContent + MODE_LEN + 1; // after space
|
||||
mode_t mode = strtoul(cmdContent, NULL, OCTAL_TYPE);
|
||||
if (mode == 0) {
|
||||
printf("[Init] DoChmod, strtoul failed for %s, er %d.\n", cmdContent, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
if (chmod(pathBeginStr, mode) != 0) {
|
||||
printf("[Init] DoChmod, failed for %s, err %d.\n", cmdContent, errno);
|
||||
srcFd = open(ctx->argv[0], O_RDONLY);
|
||||
INIT_ERROR_CHECK(srcFd >= 0, goto out, "[Init] copy open %s fail %d! \n", ctx->argv[0], errno);
|
||||
INIT_ERROR_CHECK(stat(ctx->argv[0], &fileStat) == 0, goto out, "[Init] stat fail \n");
|
||||
mode = fileStat.st_mode;
|
||||
dstFd = open(ctx->argv[1], O_WRONLY | O_TRUNC | O_CREAT, mode);
|
||||
INIT_ERROR_CHECK(dstFd >= 0, goto out, "[Init] copy open %s fail %d! \n", ctx->argv[1], errno);
|
||||
while ((rdLen = read(srcFd, buf, sizeof(buf) - 1)) > 0) {
|
||||
rtLen = write(dstFd, buf, rdLen);
|
||||
INIT_ERROR_CHECK(rtLen == rdLen, goto out, "[Init] write %s file fail %d! \n", ctx->argv[1], errno);
|
||||
}
|
||||
fsync(dstFd);
|
||||
out:
|
||||
FreeCmd(&ctx);
|
||||
ctx = NULL;
|
||||
close(srcFd);
|
||||
srcFd = -1;
|
||||
close(dstFd);
|
||||
dstFd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
static void DoChown(const char* cmdContent)
|
||||
{
|
||||
// format: owner group /xxx/xxx/xxx
|
||||
size_t firstSpace = 0;
|
||||
size_t secondSpace = 0;
|
||||
size_t strLen = strlen(cmdContent);
|
||||
for (size_t i = 0; i < strLen; ++i) {
|
||||
if (cmdContent[i] == ' ') {
|
||||
if (i == 0) {
|
||||
printf("[Init] DoChown, bad format for %s.\n", cmdContent);
|
||||
return;
|
||||
}
|
||||
if (firstSpace == 0) {
|
||||
firstSpace = i;
|
||||
} else {
|
||||
secondSpace = i;
|
||||
break;
|
||||
// format: chown owner group /xxx/xxx/xxx
|
||||
struct CmdArgs *ctx = GetCmd(cmdContent, " ");
|
||||
if (ctx == NULL || ctx->argv == NULL || ctx->argc != 3) {
|
||||
INIT_LOGE("[Init] DoChown failed.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
uid_t owner = (uid_t)-1;
|
||||
gid_t group = (gid_t)-1;
|
||||
if (isalpha(ctx->argv[0][0])) {
|
||||
owner = DecodeUid(ctx->argv[0]);
|
||||
INIT_ERROR_CHECK(owner != (uid_t)-1, goto out, "[Init] DoChown decode owner failed.\n");
|
||||
} else {
|
||||
owner = strtoul(ctx->argv[0], NULL, 0);
|
||||
}
|
||||
|
||||
if (isalpha(ctx->argv[1][0])) {
|
||||
group = DecodeUid(ctx->argv[1]);
|
||||
INIT_ERROR_CHECK(group != (gid_t)-1, goto out, "[Init] DoChown decode group failed.\n");
|
||||
} else {
|
||||
group = strtoul(ctx->argv[1], NULL, 0);
|
||||
}
|
||||
|
||||
int pathPos = 2;
|
||||
if (chown(ctx->argv[pathPos], owner, group) != 0) {
|
||||
INIT_LOGE("[Init] DoChown, failed for %s, err %d.\n", cmdContent, errno);
|
||||
}
|
||||
out:
|
||||
FreeCmd(&ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
static void DoMkDir(const char* cmdContent)
|
||||
{
|
||||
// format: mkdir /xxx/xxx/xxx or mkdir /xxx/xxx/xxx mode owner group
|
||||
struct CmdArgs *ctx = GetCmd(cmdContent, " ");
|
||||
if (ctx == NULL || ctx->argv == NULL || ctx->argc < 1) {
|
||||
INIT_LOGE("[Init] DoMkDir failed.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
mode_t mode = DEFAULT_DIR_MODE;
|
||||
for (size_t i = 0; i < strlen(ctx->argv[0]); ++i) {
|
||||
if (ctx->argv[0][i] == '/') {
|
||||
ctx->argv[0][i] = '\0';
|
||||
if (access(ctx->argv[0], 0) != 0 ) {
|
||||
mkdir(ctx->argv[0], mode);
|
||||
}
|
||||
ctx->argv[0][i]='/';
|
||||
}
|
||||
}
|
||||
if (access(ctx->argv[0], 0) != 0) {
|
||||
if (mkdir(ctx->argv[0], mode) != 0 && errno != EEXIST) {
|
||||
INIT_LOGE("[Init] DoMkDir %s failed, err %d.\n", ctx->argv[0], errno);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (secondSpace <= firstSpace || firstSpace + 1 == secondSpace || secondSpace == strLen - 1) {
|
||||
printf("[Init] DoChown, bad format for %s.\n", cmdContent);
|
||||
return;
|
||||
}
|
||||
|
||||
// only numbers valid
|
||||
for (size_t i = 0; i < secondSpace; ++i) {
|
||||
if (i != firstSpace && !isdigit(cmdContent[i])) {
|
||||
printf("[Init] DoChown, bad format for %s.\n", cmdContent);
|
||||
return;
|
||||
if (ctx->argc > 1) {
|
||||
mode = strtoul(ctx->argv[1], NULL, OCTAL_TYPE);
|
||||
if (chmod(ctx->argv[0], mode) != 0) {
|
||||
printf("[Init] DoMkDir failed for %s, err %d.\n", cmdContent, errno);
|
||||
}
|
||||
int ownerPos = 2;
|
||||
int groupPos = 3;
|
||||
char chownCmdContent[AUTHORITY_MAX_SIZE] = { 0 };
|
||||
if (snprintf_s(chownCmdContent, AUTHORITY_MAX_SIZE, AUTHORITY_MAX_SIZE - 1, "%s %s %s",
|
||||
ctx->argv[ownerPos], ctx->argv[groupPos], ctx->argv[0]) == -1) {
|
||||
INIT_LOGE("[Init] DoMkDir snprintf failed.\n");
|
||||
goto out;
|
||||
}
|
||||
DoChown(chownCmdContent);
|
||||
}
|
||||
out:
|
||||
FreeCmd(&ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
static void DoChmod(const char* cmdContent)
|
||||
{
|
||||
// format: chmod xxxx /xxx/xxx/xxx
|
||||
struct CmdArgs *ctx = GetCmd(cmdContent, " ");
|
||||
if (ctx == NULL || ctx->argv == NULL || ctx->argc != 2) {
|
||||
INIT_LOGE("[Init] DoChmod failed.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
uid_t owner = strtoul(cmdContent, NULL, 0);
|
||||
const char* groupBegin = cmdContent + firstSpace + 1;
|
||||
gid_t group = strtoul(groupBegin, NULL, 0);
|
||||
const char *path = cmdContent + secondSpace + 1;
|
||||
if (chown(path, owner, group) != 0) {
|
||||
printf("[Init] DoChown, failed for %s, err %d.\n", cmdContent, errno);
|
||||
mode_t mode = strtoul(ctx->argv[0], NULL, OCTAL_TYPE);
|
||||
if (mode == 0) {
|
||||
INIT_LOGE("[Init] DoChmod, strtoul failed for %s, er %d.\n", cmdContent, errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (chmod(ctx->argv[1], mode) != 0) {
|
||||
printf("[Init] DoChmod, failed for %s, err %d.\n", cmdContent, errno);
|
||||
}
|
||||
out:
|
||||
FreeCmd(&ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
static char* CopySubStr(const char* srcStr, size_t startPos, size_t endPos)
|
||||
@ -206,7 +301,23 @@ static char* CopySubStr(const char* srcStr, size_t startPos, size_t endPos)
|
||||
return retStr;
|
||||
}
|
||||
|
||||
static int GetMountFlag(unsigned long* mountflags, const char* targetStr)
|
||||
static void WaitForFile(const char *source)
|
||||
{
|
||||
struct stat sourceInfo;
|
||||
unsigned int waitTime = 500000;
|
||||
int maxCount = 10; // 10 means that sleep 10 times, 500ms at a time
|
||||
int count = 0;
|
||||
do {
|
||||
usleep(waitTime);
|
||||
count++;
|
||||
} while ((stat(source, &sourceInfo) < 0) && (errno == ENOENT) && (count < maxCount));
|
||||
if (count == maxCount) {
|
||||
INIT_LOGE("[Init] wait for file:%s failed after %d.\n", source, maxCount * CONVERT_MICROSEC_TO_SEC(waitTime));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static int GetMountFlag(unsigned long* mountflags, const char* targetStr, const char *source)
|
||||
{
|
||||
if (targetStr == NULL) {
|
||||
return 0;
|
||||
@ -220,6 +331,10 @@ static int GetMountFlag(unsigned long* mountflags, const char* targetStr)
|
||||
(*mountflags) |= MS_NOSUID;
|
||||
} else if (strncmp(targetStr, "rdonly", strlen("rdonly")) == 0) {
|
||||
(*mountflags) |= MS_RDONLY;
|
||||
} else if (strncmp(targetStr, "noatime", strlen("noatime")) == 0) {
|
||||
(*mountflags) |= MS_NOATIME;
|
||||
} else if (strncmp(targetStr, "wait", strlen("wait")) == 0) {
|
||||
WaitForFile(source);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@ -296,7 +411,7 @@ static void DoMount(const char* cmdContent)
|
||||
while (indexOffset < spaceCnt) {
|
||||
size_t tmpStrEndPos = (indexOffset == spaceCnt - 1) ? strLen : spacePosArr[indexOffset + 1];
|
||||
char* tmpStr = CopySubStr(cmdContent, spacePosArr[indexOffset] + 1, tmpStrEndPos);
|
||||
int ret = GetMountFlag(&mountflags, tmpStr);
|
||||
int ret = GetMountFlag(&mountflags, tmpStr, source);
|
||||
free(tmpStr);
|
||||
tmpStr = NULL;
|
||||
|
||||
@ -487,30 +602,291 @@ static void DoLoadCfg(const char *path)
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void DoCmd(const CmdLine* curCmd)
|
||||
static void DoWrite(const char *cmdContent)
|
||||
{
|
||||
if (curCmd == NULL) {
|
||||
return;
|
||||
// format: write path content
|
||||
struct CmdArgs *ctx = GetCmd(cmdContent, " ");
|
||||
int writeCmdNumber = 2;
|
||||
if (ctx == NULL || ctx->argv == NULL || ctx->argc != writeCmdNumber) {
|
||||
printf("[Init] DoWrite: invalid arguments\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strncmp(curCmd->name, "start ", strlen("start ")) == 0) {
|
||||
DoStart(curCmd->cmdContent);
|
||||
} else if (strncmp(curCmd->name, "mkdir ", strlen("mkdir ")) == 0) {
|
||||
DoMkDir(curCmd->cmdContent);
|
||||
} else if (strncmp(curCmd->name, "chmod ", strlen("chmod ")) == 0) {
|
||||
DoChmod(curCmd->cmdContent);
|
||||
} else if (strncmp(curCmd->name, "chown ", strlen("chown ")) == 0) {
|
||||
DoChown(curCmd->cmdContent);
|
||||
} else if (strncmp(curCmd->name, "mount ", strlen("mount ")) == 0) {
|
||||
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);
|
||||
int fd = open(ctx->argv[0], O_WRONLY | O_CREAT | O_NOFOLLOW | O_CLOEXEC, S_IRWXU |
|
||||
S_IRGRP | S_IROTH);
|
||||
if (fd == -1) {
|
||||
printf("[Init] DoWrite: open %s failed: %d\n", ctx->argv[0], errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
size_t ret = write(fd, ctx->argv[1], strlen(ctx->argv[1]));
|
||||
if (ret < 0) {
|
||||
printf("[Init] DoWrite: write to file %s failed: %d\n", ctx->argv[0], errno);
|
||||
close(fd);
|
||||
goto out;
|
||||
}
|
||||
close(fd);
|
||||
out:
|
||||
FreeCmd(&ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
static void DoRmdir(const char *cmdContent)
|
||||
{
|
||||
// format: rmdir path
|
||||
struct CmdArgs *ctx = GetCmd(cmdContent, " ");
|
||||
if (ctx == NULL || ctx->argv == NULL || ctx->argc != 1) {
|
||||
INIT_LOGE("[Init] DoRmdir: invalid arguments\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
int ret = rmdir(ctx->argv[0]);
|
||||
if (ret == -1) {
|
||||
INIT_LOGE("[Init] DoRmdir: remove %s failed: %d.\n", ctx->argv[0], errno);
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
FreeCmd(&ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
static void DoRm(const char *cmdContent)
|
||||
{
|
||||
// format: rm /xxx/xxx/xxx
|
||||
struct CmdArgs *ctx = GetCmd(cmdContent, " ");
|
||||
if (ctx == NULL || ctx->argv == NULL || ctx->argc != 1) {
|
||||
printf("[Init] DoRm: invalid arguments\n");
|
||||
goto out;
|
||||
}
|
||||
int ret = unlink(ctx->argv[0]);
|
||||
if (ret == -1) {
|
||||
INIT_LOGE("[Init] DoRm: unlink %s failed: %d.\n", ctx->argv[0], errno);
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
FreeCmd(&ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
static void DoExport(const char *cmdContent)
|
||||
{
|
||||
// format: export xxx /xxx/xxx/xxx
|
||||
struct CmdArgs *ctx = GetCmd(cmdContent, " ");
|
||||
if (ctx == NULL || ctx->argv == NULL || ctx->argc != 2) {
|
||||
printf("[Init] DoExport: invalid arguments\n");
|
||||
goto out;
|
||||
}
|
||||
int ret = setenv(ctx->argv[0], ctx->argv[1], 1);
|
||||
if (ret != 0) {
|
||||
INIT_LOGE("[Init] DoExport: set %s with %s failed: %d\n", ctx->argv[0], ctx->argv[1], errno);
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
FreeCmd(&ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
static void DoExec(const char *cmdContent)
|
||||
{
|
||||
// format: exec /xxx/xxx/xxx xxx
|
||||
struct CmdArgs *ctx = GetCmd(cmdContent, " ");
|
||||
if (ctx == NULL || ctx->argv == NULL) {
|
||||
INIT_LOGE("[Init] DoExec: invalid arguments\n");
|
||||
goto out;
|
||||
}
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
#ifdef OHOS_LITE
|
||||
int ret = execve(ctx->argv[0], ctx->argv, NULL);
|
||||
#else
|
||||
int ret = execv(ctx->argv[0], ctx->argv);
|
||||
#endif
|
||||
if (ret == -1) {
|
||||
INIT_LOGE("[Init] DoExec: execute \"%s\" failed: %d.\n", cmdContent, errno);
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
printf("[Init] DoCmd, unknown cmd name %s.\n", curCmd->name);
|
||||
int status = 0;
|
||||
waitpid(pid, &status, 0);
|
||||
INIT_LOGI("[Init] DoExec done.\n");
|
||||
}
|
||||
out:
|
||||
FreeCmd(&ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef __LITEOS__
|
||||
static void DoSymlink(const char *cmdContent)
|
||||
{
|
||||
// format: symlink /xxx/xxx/xxx /xxx/xxx/xxx
|
||||
struct CmdArgs *ctx = GetCmd(cmdContent, " ");
|
||||
int symlinkCmdNumber = 2;
|
||||
if (ctx == NULL || ctx->argv == NULL || ctx->argc != symlinkCmdNumber) {
|
||||
INIT_LOGE("[Init] DoSymlink: invalid arguments.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
int ret = symlink(ctx->argv[0], ctx->argv[1]);
|
||||
if (ret != 0) {
|
||||
INIT_LOGE("[Init] DoSymlink: link %s to %s failed: %d\n", ctx->argv[0], ctx->argv[1], errno);
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
FreeCmd(&ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
static mode_t GetDeviceMode(const char *deviceStr)
|
||||
{
|
||||
switch (*deviceStr) {
|
||||
case 'b':
|
||||
case 'B':
|
||||
return S_IFBLK;
|
||||
case 'c':
|
||||
case 'C':
|
||||
return S_IFCHR;
|
||||
case 'f':
|
||||
case 'F':
|
||||
return S_IFIFO;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void DoMakeNode(const char *cmdContent)
|
||||
{
|
||||
// format: mknod path b 0644 1 9
|
||||
struct CmdArgs *ctx = GetCmd(cmdContent, " ");
|
||||
int mkNodeCmdNumber = 5;
|
||||
int deviceTypePos = 1;
|
||||
int authorityPos = 2;
|
||||
int majorDevicePos = 3;
|
||||
int minorDevicePos = 4;
|
||||
int decimal = 10;
|
||||
int octal = 8;
|
||||
if (ctx == NULL || ctx->argv == NULL || ctx->argc != mkNodeCmdNumber) {
|
||||
INIT_LOGE("[Init] DoMakeNode: invalid arguments\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!access(ctx->argv[1], F_OK)) {
|
||||
INIT_LOGE("[Init] DoMakeNode failed, path has not sexisted\n");
|
||||
goto out;
|
||||
}
|
||||
mode_t deviceMode = GetDeviceMode(ctx->argv[deviceTypePos]);
|
||||
unsigned int major = strtoul(ctx->argv[majorDevicePos], NULL, decimal);
|
||||
unsigned int minor = strtoul(ctx->argv[minorDevicePos], NULL, decimal);
|
||||
mode_t authority = strtoul(ctx->argv[authorityPos], NULL, octal);
|
||||
|
||||
int ret = mknod(ctx->argv[0], deviceMode | authority, makedev(major, minor));
|
||||
if (ret != 0) {
|
||||
INIT_LOGE("[Init] DoMakeNode: path: %s failed: %d\n", ctx->argv[0], errno);
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
FreeCmd(&ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
static void DoMakeDevice(const char *cmdContent)
|
||||
{
|
||||
// format: makedev major minor
|
||||
struct CmdArgs *ctx = GetCmd(cmdContent, " ");
|
||||
int makeDevCmdNumber = 2;
|
||||
int decimal = 10;
|
||||
if (ctx == NULL || ctx->argv == NULL || ctx->argc != makeDevCmdNumber) {
|
||||
INIT_LOGE("[Init] DoMakedevice: invalid arugments\n");
|
||||
goto out;
|
||||
}
|
||||
unsigned int major = strtoul(ctx->argv[0], NULL, decimal);
|
||||
unsigned int minor = strtoul(ctx->argv[1], NULL, decimal);
|
||||
dev_t deviceId = makedev(major, minor);
|
||||
if (deviceId < 0) {
|
||||
INIT_LOGE("[Init] DoMakedevice \" %s \" failed :%d \n", cmdContent, errno);
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
FreeCmd(&ctx);
|
||||
return;
|
||||
}
|
||||
#endif // __LITEOS__
|
||||
|
||||
void DoCmd(const CmdLine* curCmd)
|
||||
{
|
||||
// null curCmd or empty command, just quit.
|
||||
if (curCmd == NULL || curCmd->name[0] == '\0') {
|
||||
return;
|
||||
}
|
||||
// INIT_LOGE("curCmd->name:%s, curCmd->cmdContent:%s\n", curCmd->name, curCmd->cmdContent);
|
||||
DoCmdByName(curCmd->name, curCmd->cmdContent);
|
||||
}
|
||||
|
||||
void DoCmdByName(const char *name, const char *cmdContent)
|
||||
{
|
||||
if (name == NULL || cmdContent == NULL) {
|
||||
return;
|
||||
}
|
||||
if (strncmp(name, "start ", strlen("start ")) == 0) {
|
||||
DoStart(cmdContent);
|
||||
} else if (strncmp(name, "mkdir ", strlen("mkdir ")) == 0) {
|
||||
DoMkDir(cmdContent);
|
||||
} else if (strncmp(name, "stop ", strlen("stop ")) == 0) {
|
||||
DoStop(cmdContent);
|
||||
} else if (strncmp(name, "reset ", strlen("reset ")) == 0) {
|
||||
DoReset(cmdContent);
|
||||
} else if (strncmp(name, "copy ", strlen("copy ")) == 0) {
|
||||
DoCopy(cmdContent);
|
||||
} else if (strncmp(name, "chmod ", strlen("chmod ")) == 0) {
|
||||
DoChmod(cmdContent);
|
||||
} else if (strncmp(name, "chown ", strlen("chown ")) == 0) {
|
||||
DoChown(cmdContent);
|
||||
} else if (strncmp(name, "mount ", strlen("mount ")) == 0) {
|
||||
DoMount(cmdContent);
|
||||
} else if (strncmp(name, "write ", strlen("write ")) == 0) {
|
||||
DoWrite(cmdContent);
|
||||
} else if (strncmp(name, "rmdir ", strlen("rmdir ")) == 0) {
|
||||
DoRmdir(cmdContent);
|
||||
} else if (strncmp(name, "rm ", strlen("rm ")) == 0) {
|
||||
DoRm(cmdContent);
|
||||
} else if (strncmp(name, "export ", strlen("export ")) == 0) {
|
||||
DoExport(cmdContent);
|
||||
} else if (strncmp(name, "exec ", strlen("exec ")) == 0) {
|
||||
DoExec(cmdContent);
|
||||
#ifndef __LITEOS__
|
||||
} else if (strncmp(name, "symlink ", strlen("symlink ")) == 0) {
|
||||
DoSymlink(cmdContent);
|
||||
} else if (strncmp(name, "makedev ", strlen("makedev ")) == 0) {
|
||||
DoMakeDevice(cmdContent);
|
||||
} else if (strncmp(name, "mknode ", strlen("mknode ")) == 0) {
|
||||
DoMakeNode(cmdContent);
|
||||
#endif
|
||||
} else if (strncmp(name, "loadcfg ", strlen("loadcfg ")) == 0) {
|
||||
DoLoadCfg(cmdContent);
|
||||
#ifndef OHOS_LITE
|
||||
} else if (strncmp(name, "insmod ", strlen("insmod ")) == 0) {
|
||||
DoInsmod(cmdContent);
|
||||
} else if (strncmp(name, "trigger ", strlen("trigger ")) == 0) {
|
||||
printf("[Init][Debug], ready to trigger job: %s\n", name);
|
||||
DoTriggerExec(cmdContent);
|
||||
} else if (strncmp(name, "load_persist_props ", strlen("load_persist_props ")) == 0) {
|
||||
LoadPersistProperties();
|
||||
#endif
|
||||
} else {
|
||||
printf("[Init] DoCmd, unknown cmd name %s.\n", name);
|
||||
}
|
||||
}
|
||||
|
||||
const char *GetMatchCmd(const char *cmdStr)
|
||||
{
|
||||
if (cmdStr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
size_t supportCmdCnt = sizeof(g_supportedCmds) / sizeof(g_supportedCmds[0]);
|
||||
for (size_t i = 0; i < supportCmdCnt; ++i) {
|
||||
size_t curCmdNameLen = strlen(g_supportedCmds[i]);
|
||||
if (strncmp(g_supportedCmds[i], cmdStr, curCmdNameLen) == 0) {
|
||||
return g_supportedCmds[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
49
services/src/init_import.c
Executable file
49
services/src/init_import.c
Executable file
@ -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.
|
||||
*/
|
||||
|
||||
#include "init_import.h"
|
||||
#include <stdio.h>
|
||||
#include "cJSON.h"
|
||||
#include "init_read_cfg.h"
|
||||
|
||||
#define IMPORT_ARR_NAME_IN_JSON "import"
|
||||
|
||||
void ParseAllImports(cJSON *root)
|
||||
{
|
||||
cJSON *importAttr = cJSON_GetObjectItemCaseSensitive(root, IMPORT_ARR_NAME_IN_JSON);
|
||||
|
||||
if (!cJSON_IsArray(importAttr)) {
|
||||
printf("[Init] ParseAllImports, import item is not array!\n");
|
||||
return;
|
||||
}
|
||||
int importAttrSize = cJSON_GetArraySize(importAttr);
|
||||
|
||||
for (int i = 0; i < importAttrSize; i++) {
|
||||
cJSON *importItem = cJSON_GetArrayItem(importAttr, i);
|
||||
if (!cJSON_IsString(importItem)) {
|
||||
printf("[Init] Invalid type of import item. should be string\n");
|
||||
return;
|
||||
}
|
||||
char *importFile = cJSON_GetStringValue(importItem);
|
||||
if (importFile == NULL) {
|
||||
printf("[Init] cannot get import config file\n");
|
||||
return;
|
||||
}
|
||||
printf("[Init] [Debug], ready to import %s...\n", importFile);
|
||||
ParseInitCfg(importFile);
|
||||
}
|
||||
printf("[Init] [Debug], parse import file done\n");
|
||||
return;
|
||||
}
|
@ -24,17 +24,31 @@
|
||||
|
||||
#define JOBS_ARR_NAME_IN_JSON "jobs"
|
||||
#define CMDS_ARR_NAME_IN_JSON "cmds"
|
||||
#define MAX_JOBS_COUNT 10
|
||||
#define MAX_JOBS_COUNT 100
|
||||
|
||||
static const char* g_supportedJobs[] = {
|
||||
"pre-init",
|
||||
"init",
|
||||
"post-init",
|
||||
};
|
||||
// static const char* g_supportedJobs[] = {
|
||||
// "pre-init",
|
||||
// "init",
|
||||
// "post-init",
|
||||
// };
|
||||
|
||||
static Job* g_jobs = NULL;
|
||||
static int g_jobCnt = 0;
|
||||
|
||||
void DumpAllJobs()
|
||||
{
|
||||
printf("[Init][Debug], Ready to dump all jobs:\n");
|
||||
for (int i = 0; i < g_jobCnt; i++) {
|
||||
printf("\t[Init], job name: %s\n", g_jobs[i].name);
|
||||
printf("\t[Init], list all commands:\n");
|
||||
for (int j = 0; j < g_jobs[i].cmdLinesCnt; j++) {
|
||||
printf("\t\t[Init], command name : %s, command options: %s\n",
|
||||
g_jobs[i].cmdLines[j].name, g_jobs[i].cmdLines[j].cmdContent);
|
||||
}
|
||||
}
|
||||
printf("[Init][Debug], To dump all jobs finished\n");
|
||||
}
|
||||
|
||||
static int GetJobName(const cJSON* jobItem, Job* resJob)
|
||||
{
|
||||
char* jobNameStr = cJSON_GetStringValue(cJSON_GetObjectItem(jobItem, "name"));
|
||||
@ -42,37 +56,46 @@ static int GetJobName(const cJSON* jobItem, Job* resJob)
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t supportJobCnt = sizeof(g_supportedJobs) / sizeof(g_supportedJobs[0]);
|
||||
for (size_t i = 0; i < supportJobCnt; ++i) {
|
||||
if (strlen(g_supportedJobs[i]) == strlen(jobNameStr) &&
|
||||
strncmp(g_supportedJobs[i], jobNameStr, strlen(g_supportedJobs[i])) == 0) {
|
||||
if (memcpy_s(resJob->name, MAX_JOB_NAME_LEN, jobNameStr, strlen(jobNameStr)) != EOK) {
|
||||
return 0;
|
||||
}
|
||||
resJob->name[strlen(jobNameStr)] = '\0';
|
||||
return 1;
|
||||
}
|
||||
//size_t supportJobCnt = sizeof(g_supportedJobs) / sizeof(g_supportedJobs[0]);
|
||||
//for (size_t i = 0; i < supportJobCnt; ++i) {
|
||||
// if (strlen(g_supportedJobs[i]) == strlen(jobNameStr) &&
|
||||
// strncmp(g_supportedJobs[i], jobNameStr, strlen(g_supportedJobs[i])) == 0) {
|
||||
// if (memcpy_s(resJob->name, MAX_JOB_NAME_LEN, jobNameStr, strlen(jobNameStr)) != EOK) {
|
||||
// return 0;
|
||||
// }
|
||||
// resJob->name[strlen(jobNameStr)] = '\0';
|
||||
// return 1;
|
||||
// }
|
||||
//}
|
||||
if (memcpy_s(resJob->name, MAX_JOB_NAME_LEN, jobNameStr, strlen(jobNameStr)) != EOK) {
|
||||
printf("[Init], Get job name \"%s\" failed\n", jobNameStr);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
resJob->name[strlen(jobNameStr)] = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void ParseJob(const cJSON* jobItem, Job* resJob)
|
||||
{
|
||||
if (!GetJobName(jobItem, resJob)) {
|
||||
printf("[Init][Debug], get JobName failed\n");
|
||||
(void)memset_s(resJob, sizeof(*resJob), 0, sizeof(*resJob));
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON* cmdsItem = cJSON_GetObjectItem(jobItem, CMDS_ARR_NAME_IN_JSON);
|
||||
if (!cJSON_IsArray(cmdsItem)) {
|
||||
printf("[Init][Debug], job %s is not an arrary\n", resJob->name);
|
||||
return;
|
||||
}
|
||||
|
||||
int cmdLinesCnt = cJSON_GetArraySize(cmdsItem);
|
||||
if (cmdLinesCnt <= 0) { // empty job, no cmd
|
||||
printf("[Init][Debug], empty job \"%s\"\n", resJob->name);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("[Init][Debug], job = %s, cmdLineCnt = %d\n", resJob->name, cmdLinesCnt);
|
||||
if (cmdLinesCnt > MAX_CMD_CNT_IN_ONE_JOB) {
|
||||
printf("[Init] ParseAllJobs, too many cmds[cnt %d] in one job, it should not exceed %d.\n",
|
||||
cmdLinesCnt, MAX_CMD_CNT_IN_ONE_JOB);
|
||||
@ -81,6 +104,7 @@ static void ParseJob(const cJSON* jobItem, Job* resJob)
|
||||
|
||||
resJob->cmdLines = (CmdLine*)malloc(cmdLinesCnt * sizeof(CmdLine));
|
||||
if (resJob->cmdLines == NULL) {
|
||||
printf("[Init][Debug], allocate memory for command line failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -117,13 +141,14 @@ void ParseAllJobs(const cJSON* fileRoot)
|
||||
return;
|
||||
}
|
||||
|
||||
Job* retJobs = (Job*)malloc(sizeof(Job) * jobArrSize);
|
||||
Job* retJobs = (Job*)realloc(g_jobs, sizeof(Job) * (g_jobCnt + jobArrSize));
|
||||
if (retJobs == NULL) {
|
||||
printf("[Init] ParseAllJobs, malloc failed! job arrSize %d.\n", jobArrSize);
|
||||
return;
|
||||
}
|
||||
|
||||
if (memset_s(retJobs, sizeof(Job) * jobArrSize, 0, sizeof(Job) * jobArrSize) != EOK) {
|
||||
Job* tmp = retJobs + g_jobCnt;
|
||||
if (memset_s(tmp, sizeof(Job) * jobArrSize, 0, sizeof(Job) * jobArrSize) != EOK) {
|
||||
printf("[Init] ParseAllJobs, memset_s failed.\n");
|
||||
free(retJobs);
|
||||
retJobs = NULL;
|
||||
@ -132,10 +157,10 @@ void ParseAllJobs(const cJSON* fileRoot)
|
||||
|
||||
for (int i = 0; i < jobArrSize; ++i) {
|
||||
cJSON* jobItem = cJSON_GetArrayItem(jobArr, i);
|
||||
ParseJob(jobItem, &(retJobs[i]));
|
||||
ParseJob(jobItem, &(tmp[i]));
|
||||
}
|
||||
g_jobs = retJobs;
|
||||
g_jobCnt = jobArrSize;
|
||||
g_jobCnt += jobArrSize;
|
||||
}
|
||||
|
||||
void DoJob(const char* jobName)
|
||||
@ -145,13 +170,15 @@ void DoJob(const char* jobName)
|
||||
return;
|
||||
}
|
||||
|
||||
printf("[Init][Debug], Call job with name %s\n", jobName);
|
||||
for (int i = 0; i < g_jobCnt; ++i) {
|
||||
if (strncmp(jobName, g_jobs[i].name, strlen(g_jobs[i].name)) == 0) {
|
||||
CmdLine* cmdLines = g_jobs[i].cmdLines;
|
||||
for (int j = 0; j < g_jobs[i].cmdLinesCnt; ++j) {
|
||||
DoCmd(&(cmdLines[j]));
|
||||
}
|
||||
break;
|
||||
// Walk through all jobs
|
||||
// break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
61
services/src/init_log.c
Executable file
61
services/src/init_log.c
Executable file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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_log.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include "securec.h"
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
#define MAX_FORMAT_SIZE 1024
|
||||
#define MAX_LOG_SIZE 2048
|
||||
#define BASE_YEAR 1900
|
||||
|
||||
void InitLog(int logLevel, const char *fileName, int line, const char *fmt, ...)
|
||||
{
|
||||
UNUSED(logLevel);
|
||||
va_list vargs;
|
||||
va_start(vargs, fmt);
|
||||
|
||||
char tmpFmt[MAX_FORMAT_SIZE];
|
||||
if (vsnprintf_s(tmpFmt, MAX_FORMAT_SIZE, MAX_FORMAT_SIZE, fmt, vargs) == -1) {
|
||||
return;
|
||||
}
|
||||
time_t logTime;
|
||||
time(&logTime);
|
||||
struct tm *t = gmtime(&logTime);
|
||||
char logInfo[MAX_LOG_SIZE];
|
||||
if (snprintf_s(logInfo, MAX_LOG_SIZE, MAX_LOG_SIZE, "%d-%d-%d %d:%d %s %d : %s", (t->tm_year + BASE_YEAR),
|
||||
(t->tm_mon + 1), t->tm_mday, t->tm_hour, t->tm_min, fileName, line, tmpFmt) == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
int fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC | O_APPEND );
|
||||
if (fd < 1) {
|
||||
printf("xxxxxxxxxxxxxxx open failed. %d\n", errno);
|
||||
return;
|
||||
}
|
||||
if (write(fd, logInfo, strlen(logInfo)) < -1) {
|
||||
printf("xxxxxxxxxxxxxxx write failed.%d\n", errno);
|
||||
return;
|
||||
}
|
||||
va_end(vargs);
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "init_read_cfg.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <linux/capability.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -23,9 +24,16 @@
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "init_import.h"
|
||||
#include "init_jobs.h"
|
||||
#include "init_log.h"
|
||||
#include "init_perms.h"
|
||||
#include "init_service_manager.h"
|
||||
#include "init_utils.h"
|
||||
|
||||
#ifndef OHOS_LITE
|
||||
#include "trigger.h"
|
||||
#endif
|
||||
#include "securec.h"
|
||||
#ifndef __LINUX__
|
||||
#ifdef OHOS_LITE
|
||||
@ -33,368 +41,91 @@
|
||||
#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
|
||||
static const int MAX_ONE_ARG_LEN = 64; // max length of one param/path
|
||||
#define MAX_SERVICES_CNT_IN_FILE 100
|
||||
#define MAX_CAPS_CNT_FOR_ONE_SERVICE 100
|
||||
#define UID_STR_IN_CFG "uid"
|
||||
#define GID_STR_IN_CFG "gid"
|
||||
#define ONCE_STR_IN_CFG "once"
|
||||
#define IMPORTANT_STR_IN_CFG "importance"
|
||||
#define BIN_SH_NOT_ALLOWED "/bin/sh"
|
||||
|
||||
static char* ReadFileToBuf()
|
||||
#define FILE_NAME_MAX_SIZE 100
|
||||
static void ParseInitCfgContents(cJSON *root)
|
||||
{
|
||||
char* buffer = NULL;
|
||||
FILE* fd = NULL;
|
||||
struct stat fileStat = {0};
|
||||
do {
|
||||
if (stat(INIT_CONFIGURATION_FILE, &fileStat) != 0 ||
|
||||
fileStat.st_size <= 0 || fileStat.st_size > MAX_JSON_FILE_LEN) {
|
||||
break;
|
||||
}
|
||||
// parse services
|
||||
ParseAllServices(root);
|
||||
|
||||
fd = fopen(INIT_CONFIGURATION_FILE, "r");
|
||||
if (fd == NULL) {
|
||||
break;
|
||||
}
|
||||
// parse jobs
|
||||
ParseAllJobs(root);
|
||||
|
||||
buffer = (char*)malloc(fileStat.st_size + 1);
|
||||
if (buffer == NULL) {
|
||||
break;
|
||||
}
|
||||
#ifndef OHOS_LITE
|
||||
ParseTriggerConfig(root);
|
||||
#endif
|
||||
|
||||
if (fread(buffer, fileStat.st_size, 1, fd) != 1) {
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
break;
|
||||
}
|
||||
buffer[fileStat.st_size] = '\0';
|
||||
} while (0);
|
||||
|
||||
if (fd != NULL) {
|
||||
fclose(fd);
|
||||
fd = NULL;
|
||||
}
|
||||
return buffer;
|
||||
// parse imports
|
||||
ParseAllImports(root);
|
||||
}
|
||||
|
||||
static cJSON* GetArrItem(const cJSON* fileRoot, int* arrSize, const char* arrName)
|
||||
void ParseInitCfg(const char *configFile)
|
||||
{
|
||||
cJSON* arrItem = cJSON_GetObjectItemCaseSensitive(fileRoot, arrName);
|
||||
if (!cJSON_IsArray(arrItem)) {
|
||||
printf("[Init] GetArrItem, item %s is not an array!\n", arrName);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*arrSize = cJSON_GetArraySize(arrItem);
|
||||
if (*arrSize <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
return arrItem;
|
||||
}
|
||||
|
||||
static int IsForbidden(const char* fieldStr)
|
||||
{
|
||||
size_t fieldLen = strlen(fieldStr);
|
||||
size_t forbidStrLen = strlen(BIN_SH_NOT_ALLOWED);
|
||||
if (fieldLen == forbidStrLen) {
|
||||
if (strncmp(fieldStr, BIN_SH_NOT_ALLOWED, fieldLen) == 0) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
} else if (fieldLen > forbidStrLen) {
|
||||
// "/bin/shxxxx" is valid but "/bin/sh xxxx" is invalid
|
||||
if (strncmp(fieldStr, BIN_SH_NOT_ALLOWED, forbidStrLen) == 0) {
|
||||
if (fieldStr[forbidStrLen] == ' ') {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ReleaseServiceMem(Service* curServ)
|
||||
{
|
||||
if (curServ->pathArgs != NULL) {
|
||||
for (int i = 0; i < curServ->pathArgsCnt; ++i) {
|
||||
if (curServ->pathArgs[i] != NULL) {
|
||||
free(curServ->pathArgs[i]);
|
||||
curServ->pathArgs[i] = NULL;
|
||||
}
|
||||
}
|
||||
free(curServ->pathArgs);
|
||||
curServ->pathArgs = NULL;
|
||||
}
|
||||
curServ->pathArgsCnt = 0;
|
||||
|
||||
if (curServ->servPerm.caps != NULL) {
|
||||
free(curServ->servPerm.caps);
|
||||
curServ->servPerm.caps = NULL;
|
||||
}
|
||||
if (curServ->servPerm.gIDs != NULL) {
|
||||
free(curServ->servPerm.gIDs);
|
||||
curServ->servPerm.gIDs = NULL;
|
||||
}
|
||||
curServ->servPerm.capsCnt = 0;
|
||||
curServ->servPerm.gidsCnt = 0;
|
||||
}
|
||||
|
||||
static int GetServiceName(const cJSON* curArrItem, Service* curServ)
|
||||
{
|
||||
char* fieldStr = cJSON_GetStringValue(cJSON_GetObjectItem(curArrItem, "name"));
|
||||
if (fieldStr == NULL) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
size_t strLen = strlen(fieldStr);
|
||||
if (strLen == 0 || strLen > MAX_SERVICE_NAME) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
if (memcpy_s(curServ->name, MAX_SERVICE_NAME, fieldStr, strLen) != EOK) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->name[strLen] = '\0';
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
static int GetServicePathAndArgs(const cJSON* curArrItem, Service* curServ)
|
||||
{
|
||||
cJSON* pathItem = cJSON_GetObjectItem(curArrItem, "path");
|
||||
if (!cJSON_IsArray(pathItem)) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
int arrSize = cJSON_GetArraySize(pathItem);
|
||||
if (arrSize <= 0 || arrSize > MAX_PATH_ARGS_CNT) { // array size invalid
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
curServ->pathArgs = (char**)malloc((arrSize + 1) * sizeof(char*));
|
||||
if (curServ->pathArgs == NULL) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
for (int i = 0; i < arrSize + 1; ++i) {
|
||||
curServ->pathArgs[i] = NULL;
|
||||
}
|
||||
curServ->pathArgsCnt = arrSize + 1;
|
||||
|
||||
for (int i = 0; i < arrSize; ++i) {
|
||||
char* curParam = cJSON_GetStringValue(cJSON_GetArrayItem(pathItem, i));
|
||||
if (curParam == NULL || strlen(curParam) > MAX_ONE_ARG_LEN) {
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
if (i == 0 && IsForbidden(curParam)) {
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
size_t paramLen = strlen(curParam);
|
||||
curServ->pathArgs[i] = (char*)malloc(paramLen + 1);
|
||||
if (curServ->pathArgs[i] == NULL) {
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
if (memcpy_s(curServ->pathArgs[i], paramLen + 1, curParam, paramLen) != EOK) {
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->pathArgs[i][paramLen] = '\0';
|
||||
}
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
static int GetServiceNumber(const cJSON* curArrItem, Service* curServ, const char* targetField)
|
||||
{
|
||||
cJSON* filedJ = cJSON_GetObjectItem(curArrItem, targetField);
|
||||
if (!cJSON_IsNumber(filedJ)) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
int value = (int)cJSON_GetNumberValue(filedJ);
|
||||
if (value < 0) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
if (strncmp(targetField, UID_STR_IN_CFG, strlen(UID_STR_IN_CFG)) == 0) {
|
||||
curServ->servPerm.uID = value;
|
||||
} else if (strncmp(targetField, ONCE_STR_IN_CFG, strlen(ONCE_STR_IN_CFG)) == 0) {
|
||||
if (value != 0) {
|
||||
curServ->attribute |= SERVICE_ATTR_ONCE;
|
||||
}
|
||||
} else if (strncmp(targetField, IMPORTANT_STR_IN_CFG, strlen(IMPORTANT_STR_IN_CFG)) == 0) {
|
||||
if (value != 0) {
|
||||
curServ->attribute |= SERVICE_ATTR_IMPORTANT;
|
||||
}
|
||||
} else {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
static int GetServiceCaps(const cJSON* curArrItem, Service* curServ)
|
||||
{
|
||||
curServ->servPerm.capsCnt = 0;
|
||||
curServ->servPerm.caps = NULL;
|
||||
|
||||
cJSON* filedJ = cJSON_GetObjectItem(curArrItem, "caps");
|
||||
if (!cJSON_IsArray(filedJ)) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
// caps array does not exist, means do not need any capability
|
||||
int capsCnt = cJSON_GetArraySize(filedJ);
|
||||
if (capsCnt <= 0) {
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
if (capsCnt > MAX_CAPS_CNT_FOR_ONE_SERVICE) {
|
||||
printf("[Init] GetServiceCaps, too many caps[cnt %d] for one service, should not exceed %d.\n",
|
||||
capsCnt, MAX_CAPS_CNT_FOR_ONE_SERVICE);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
curServ->servPerm.caps = (unsigned int*)malloc(sizeof(unsigned int) * capsCnt);
|
||||
if (curServ->servPerm.caps == NULL) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
for (int i = 0; i < capsCnt; ++i) {
|
||||
cJSON* capJ = cJSON_GetArrayItem(filedJ, i);
|
||||
if (!cJSON_IsNumber(capJ) || cJSON_GetNumberValue(capJ) < 0) {
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->servPerm.caps[i] = (unsigned int)cJSON_GetNumberValue(capJ);
|
||||
if (curServ->servPerm.caps[i] > CAP_LAST_CAP && curServ->servPerm.caps[i] != FULL_CAP) {
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
}
|
||||
curServ->servPerm.capsCnt = capsCnt;
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
static int GetServiceGids(const cJSON* curArrItem, Service* curServ)
|
||||
{
|
||||
curServ->servPerm.gidsCnt = 0;
|
||||
curServ->servPerm.gIDs = NULL;
|
||||
int gidsCnt;
|
||||
cJSON* filedJ = cJSON_GetObjectItem(curArrItem, "gid");
|
||||
if (cJSON_IsArray(filedJ)) {
|
||||
gidsCnt = cJSON_GetArraySize(filedJ);
|
||||
if (gidsCnt <= 0) {
|
||||
// gids array does not exist, means do not need any group
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
curServ->servPerm.gIDs = (unsigned int*)malloc(sizeof(unsigned int) * gidsCnt);
|
||||
if (curServ->servPerm.gIDs == NULL) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
for (int i = 0; i < gidsCnt; ++i) {
|
||||
cJSON* gidJ = cJSON_GetArrayItem(filedJ, i);
|
||||
if (!cJSON_IsNumber(gidJ) || cJSON_GetNumberValue(gidJ) < 0) {
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->servPerm.gIDs[i] = (unsigned int)cJSON_GetNumberValue(gidJ);
|
||||
}
|
||||
} else {
|
||||
int value = (int)cJSON_GetNumberValue(filedJ);
|
||||
if (value < 0) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
gidsCnt = 1;
|
||||
curServ->servPerm.gIDs = (unsigned int*)malloc(sizeof(unsigned int));
|
||||
if (curServ->servPerm.gIDs == NULL) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->servPerm.gIDs[0] = (unsigned int)value;
|
||||
}
|
||||
curServ->servPerm.gidsCnt = gidsCnt;
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
static void ParseAllServices(const cJSON* fileRoot)
|
||||
{
|
||||
int servArrSize = 0;
|
||||
cJSON* serviceArr = GetArrItem(fileRoot, &servArrSize, SERVICES_ARR_NAME_IN_JSON);
|
||||
if (serviceArr == NULL) {
|
||||
printf("[Init] InitReadCfg, get array %s failed.\n", SERVICES_ARR_NAME_IN_JSON);
|
||||
if (configFile == NULL || *configFile == '\0') {
|
||||
printf("[Init] Invalid config file\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (servArrSize > MAX_SERVICES_CNT_IN_FILE) {
|
||||
printf("[Init] InitReadCfg, too many services[cnt %d] detected, should not exceed %d.\n",
|
||||
servArrSize, MAX_SERVICES_CNT_IN_FILE);
|
||||
return;
|
||||
}
|
||||
|
||||
Service* retServices = (Service*)malloc(sizeof(Service) * servArrSize);
|
||||
if (retServices == NULL) {
|
||||
printf("[Init] InitReadCfg, malloc for %s arr failed! %d.\n", SERVICES_ARR_NAME_IN_JSON, servArrSize);
|
||||
return;
|
||||
}
|
||||
|
||||
if (memset_s(retServices, sizeof(Service) * servArrSize, 0, sizeof(Service) * servArrSize) != EOK) {
|
||||
free(retServices);
|
||||
retServices = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < servArrSize; ++i) {
|
||||
cJSON* curItem = cJSON_GetArrayItem(serviceArr, i);
|
||||
if (GetServiceName(curItem, &retServices[i]) != SERVICE_SUCCESS ||
|
||||
GetServicePathAndArgs(curItem, &retServices[i]) != SERVICE_SUCCESS ||
|
||||
GetServiceNumber(curItem, &retServices[i], UID_STR_IN_CFG) != SERVICE_SUCCESS ||
|
||||
GetServiceGids(curItem, &retServices[i]) != SERVICE_SUCCESS ||
|
||||
GetServiceNumber(curItem, &retServices[i], ONCE_STR_IN_CFG) != SERVICE_SUCCESS ||
|
||||
GetServiceNumber(curItem, &retServices[i], IMPORTANT_STR_IN_CFG) != SERVICE_SUCCESS ||
|
||||
GetServiceCaps(curItem, &retServices[i]) != SERVICE_SUCCESS) {
|
||||
// release resources if it fails
|
||||
ReleaseServiceMem(&retServices[i]);
|
||||
retServices[i].attribute |= SERVICE_ATTR_INVALID;
|
||||
printf("[Init] InitReadCfg, parse information for service %d failed.\n", i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
RegisterServices(retServices, servArrSize);
|
||||
}
|
||||
|
||||
void InitReadCfg()
|
||||
{
|
||||
// read configuration file in json format
|
||||
char* fileBuf = ReadFileToBuf();
|
||||
if (fileBuf == NULL) {
|
||||
printf("[Init] InitReadCfg, read file %s failed! err %d.\n", INIT_CONFIGURATION_FILE, errno);
|
||||
return;
|
||||
}
|
||||
char *fileBuf = ReadFileToBuf(configFile);
|
||||
//printf("[Init] start dump config file: \n");
|
||||
//printf("%s", fileBuf);
|
||||
//printf("[Init] end dump config file: \n");
|
||||
|
||||
cJSON* fileRoot = cJSON_Parse(fileBuf);
|
||||
free(fileBuf);
|
||||
fileBuf = NULL;
|
||||
|
||||
if (fileRoot == NULL) {
|
||||
printf("[Init] InitReadCfg, parse failed! please check file %s format.\n", INIT_CONFIGURATION_FILE);
|
||||
printf("[Init] InitReadCfg, parse failed! please check file %s format.\n", configFile);
|
||||
return;
|
||||
}
|
||||
|
||||
// parse services
|
||||
ParseAllServices(fileRoot);
|
||||
|
||||
// parse jobs
|
||||
ParseAllJobs(fileRoot);
|
||||
|
||||
// release memory
|
||||
ParseInitCfgContents(fileRoot);
|
||||
// Release JSON object
|
||||
cJSON_Delete(fileRoot);
|
||||
return;
|
||||
}
|
||||
|
||||
static void ReadCfgs(const char *dirPath)
|
||||
{
|
||||
DIR *pDir = opendir(dirPath);
|
||||
if (pDir == NULL) {
|
||||
INIT_LOGE("[Init], ParseCfgs open cfg dir :%s failed.%d\n", dirPath, errno);
|
||||
return;
|
||||
}
|
||||
struct dirent *dp;
|
||||
while ((dp = readdir(pDir)) != NULL) {
|
||||
char fileName[FILE_NAME_MAX_SIZE];
|
||||
if (snprintf_s(fileName, FILE_NAME_MAX_SIZE, FILE_NAME_MAX_SIZE - 1, "%s/%s", dirPath, dp->d_name) == -1) {
|
||||
INIT_LOGE("[Init], ParseCfgs snprintf_s failed.\n");
|
||||
closedir(pDir);
|
||||
return;
|
||||
}
|
||||
struct stat st;
|
||||
if (stat(fileName, &st) == 0) {
|
||||
if (strstr(dp->d_name, ".cfg") == NULL) {
|
||||
continue;
|
||||
}
|
||||
INIT_LOGE("[Init], fileName :%s.\n", fileName);
|
||||
ParseInitCfg(fileName);
|
||||
}
|
||||
}
|
||||
closedir(pDir);
|
||||
return;
|
||||
}
|
||||
|
||||
static void ParseOtherCfgs()
|
||||
{
|
||||
ReadCfgs("/system/etc/init");
|
||||
return;
|
||||
}
|
||||
|
||||
void InitReadCfg()
|
||||
{
|
||||
ParseInitCfg(INIT_CONFIGURATION_FILE);
|
||||
ParseOtherCfgs();
|
||||
printf("[init], Parse init config file done.\n");
|
||||
|
||||
DumpAllServices();
|
||||
// DumpAllJobs();
|
||||
// do jobs
|
||||
DoJob("pre-init");
|
||||
#ifndef __LINUX__
|
||||
|
@ -19,12 +19,16 @@
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "init_adapter.h"
|
||||
#include "init_cmds.h"
|
||||
#include "init_log.h"
|
||||
#include "init_perms.h"
|
||||
#include "init_service_socket.h"
|
||||
|
||||
#define CAP_NUM 2
|
||||
|
||||
@ -33,6 +37,13 @@ static const int CRASH_TIME_LIMIT = 240;
|
||||
// maximum number of crashes within time CRASH_TIME_LIMIT for one service
|
||||
static const int CRASH_COUNT_LIMIT = 4;
|
||||
|
||||
// 240 seconds, 4 minutes
|
||||
static const int CRITICAL_CRASH_TIME_LIMIT = 240;
|
||||
// maximum number of crashes within time CRITICAL_CRASH_TIME_LIMIT for one service
|
||||
static const int CRITICAL_CRASH_COUNT_LIMIT = 4;
|
||||
static const int MAX_PID_STRING_LENGTH = 50;
|
||||
|
||||
|
||||
static int SetAllAmbientCapability()
|
||||
{
|
||||
for (int i = 0; i <= CAP_LAST_CAP; ++i) {
|
||||
@ -48,12 +59,17 @@ static int SetPerms(const Service *service)
|
||||
if (KeepCapability() != 0) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
if (setgroups(service->servPerm.gidsCnt, service->servPerm.gIDs) != 0) {
|
||||
|
||||
if (setgroups(service->servPerm.gIDCnt, service->servPerm.gIDArray) != 0) {
|
||||
INIT_LOGE("[Init] SetPerms, setgroups failed. errno = %d, gIDCnt=%d\n", errno, service->servPerm.gIDCnt);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
if (setuid(service->servPerm.uID) != 0) {
|
||||
return SERVICE_FAILURE;
|
||||
if (service->servPerm.uID != 0) {
|
||||
if (setuid(service->servPerm.uID) != 0) {
|
||||
printf("[Init] setuid of service: %s failed, uid = %d\n", service->name, service->servPerm.uID);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// umask call always succeeds and return the previous mask value which is not needed here
|
||||
@ -79,6 +95,7 @@ static int SetPerms(const Service *service)
|
||||
}
|
||||
|
||||
if (capset(&capHeader, capData) != 0) {
|
||||
printf("[Init][Debug], capset faild for service: %s, error: %d\n", service->name, errno);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
for (unsigned int i = 0; i < service->servPerm.capsCnt; ++i) {
|
||||
@ -86,6 +103,7 @@ static int SetPerms(const Service *service)
|
||||
return SetAllAmbientCapability();
|
||||
}
|
||||
if (SetAmbientCapability(service->servPerm.caps[i]) != 0) {
|
||||
printf("[Init][Debug], SetAmbientCapability faild for service: %s\n", service->name);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
}
|
||||
@ -112,19 +130,56 @@ int ServiceStart(Service *service)
|
||||
service->name, service->pathArgs[0]);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
int pid = fork();
|
||||
if (pid == 0) {
|
||||
if (service->socketCfg != NULL) { // start socket service
|
||||
printf("[init] Create socket \n");
|
||||
ret = DoCreateSocket(service->socketCfg);
|
||||
if (ret < 0) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
}
|
||||
// permissions
|
||||
if (SetPerms(service) != SERVICE_SUCCESS) {
|
||||
printf("[Init] service %s exit! set perms failed! err %d.\n", service->name, errno);
|
||||
INIT_LOGE("[Init] service %s exit! set perms failed! err %d.\n", service->name, errno);
|
||||
_exit(0x7f); // 0x7f: user specified
|
||||
}
|
||||
char pidString[MAX_PID_STRING_LENGTH]; // writepid
|
||||
pid_t childPid = getpid();
|
||||
if (snprintf(pidString, MAX_PID_STRING_LENGTH, "%d", childPid) <= 0) {
|
||||
INIT_LOGE("[Init] start service writepid sprintf failed.\n");
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
for (int i = 0; i < MAX_WRITEPID_FILES; i++) {
|
||||
if (service->writepidFiles[i] == NULL) {
|
||||
continue;
|
||||
}
|
||||
FILE *fd = fopen(service->writepidFiles[i], "wb");
|
||||
if (fd == NULL) {
|
||||
INIT_LOGE("[Init] start service writepidFiles %s invalid.\n", service->writepidFiles[i]);
|
||||
continue;
|
||||
}
|
||||
if (fwrite(pidString, 1, strlen(pidString), fd) != strlen(pidString)) {
|
||||
INIT_LOGE("[Init] start service writepid error.file:%s pid:%s\n", service->writepidFiles[i], pidString);
|
||||
}
|
||||
fclose(fd);
|
||||
printf("[Init] ServiceStart writepid filename=%s, childPid=%s, ok\n", service->writepidFiles[i], pidString);
|
||||
}
|
||||
|
||||
printf("[init] service->name is %s \n", service->name);
|
||||
#ifndef OHOS_LITE
|
||||
// L2 Can not be reset env
|
||||
if (execv(service->pathArgs[0], service->pathArgs) != 0) {
|
||||
printf("[Init] service %s execve failed! err %d.\n", service->name, errno);
|
||||
}
|
||||
#else
|
||||
char* env[] = {"LD_LIBRARY_PATH=/storage/app/libs", NULL};
|
||||
if (execve(service->pathArgs[0], service->pathArgs, env) != 0) {
|
||||
printf("[Init] service %s execve failed! err %d.\n", service->name, errno);
|
||||
}
|
||||
#endif
|
||||
|
||||
_exit(0x7f); // 0x7f: user specified
|
||||
} else if (pid < 0) {
|
||||
printf("[Init] start service %s fork failed!\n", service->name);
|
||||
@ -158,6 +213,45 @@ int ServiceStop(Service *service)
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
// the service need to be restarted, if it crashed more than 4 times in 4 minutes
|
||||
void CheckCritical(Service *service)
|
||||
{
|
||||
if (service->attribute & SERVICE_ATTR_CRITICAL) { // critical
|
||||
// crash time and count check
|
||||
time_t curTime = time(NULL);
|
||||
if (service->criticalCrashCnt == 0) {
|
||||
service->firstCriticalCrashTime = curTime;
|
||||
++service->criticalCrashCnt;
|
||||
} else if (difftime(curTime, service->firstCriticalCrashTime) > CRITICAL_CRASH_TIME_LIMIT) {
|
||||
service->firstCriticalCrashTime = curTime;
|
||||
service->criticalCrashCnt = 1;
|
||||
} else {
|
||||
++service->criticalCrashCnt;
|
||||
if (service->criticalCrashCnt > CRITICAL_CRASH_COUNT_LIMIT) {
|
||||
INIT_LOGE("[Init] reap critical service %s, crash too many times! Need reboot!\n", service->name);
|
||||
RebootSystem();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int ExecRestartCmd(const Service *service)
|
||||
{
|
||||
printf("[init] ExecRestartCmd \n");
|
||||
if ((service == NULL) || (service->onRestart == NULL) || (service->onRestart->cmdLine == NULL)) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
for (int i = 0; i < service->onRestart->cmdNum; i++) {
|
||||
printf("[init] SetOnRestart cmdLine->name %s cmdLine->cmdContent %s \n", service->onRestart->cmdLine[i].name,
|
||||
service->onRestart->cmdLine[i].cmdContent);
|
||||
DoCmd(&service->onRestart->cmdLine[i]);
|
||||
}
|
||||
free(service->onRestart->cmdLine);
|
||||
free(service->onRestart);
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
void ServiceReap(Service *service)
|
||||
{
|
||||
if (service == NULL) {
|
||||
@ -166,7 +260,6 @@ void ServiceReap(Service *service)
|
||||
}
|
||||
|
||||
service->pid = -1;
|
||||
|
||||
// stopped by system-init itself, no need to restart even if it is not one-shot service
|
||||
if (service->attribute & SERVICE_ATTR_NEED_STOP) {
|
||||
service->attribute &= (~SERVICE_ATTR_NEED_STOP);
|
||||
@ -203,9 +296,17 @@ void ServiceReap(Service *service)
|
||||
}
|
||||
}
|
||||
|
||||
int ret = ServiceStart(service);
|
||||
CheckCritical(service);
|
||||
int ret = 0;
|
||||
if (service->onRestart != NULL) {
|
||||
ret = ExecRestartCmd(service);
|
||||
if (ret != SERVICE_SUCCESS) {
|
||||
printf("[Init] SetOnRestart fail \n");
|
||||
}
|
||||
}
|
||||
ret = ServiceStart(service);
|
||||
if (ret != SERVICE_SUCCESS) {
|
||||
printf("[Init] reap service %s start failed!\n", service->name);
|
||||
INIT_LOGE("[Init] reap service %s start failed!\n", service->name);
|
||||
}
|
||||
|
||||
service->attribute &= (~SERVICE_ATTR_NEED_RESTART);
|
||||
|
@ -1,91 +1,785 @@
|
||||
/*
|
||||
* 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 "init_service_manager.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "init_adapter.h"
|
||||
#include "init_jobs.h"
|
||||
|
||||
|
||||
// All serivce processes that init will fork+exec.
|
||||
static Service* g_services = NULL;
|
||||
static int g_servicesCnt = 0;
|
||||
|
||||
void RegisterServices(Service* services, int servicesCnt)
|
||||
{
|
||||
g_services = services;
|
||||
g_servicesCnt = servicesCnt;
|
||||
}
|
||||
|
||||
static int FindServiceByName(const char* servName)
|
||||
{
|
||||
if (servName == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < g_servicesCnt; ++i) {
|
||||
if (strlen(g_services[i].name) == strlen(servName) &&
|
||||
strncmp(g_services[i].name, servName, strlen(g_services[i].name)) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void StartServiceByName(const char* servName)
|
||||
{
|
||||
// find service by name
|
||||
int servIdx = FindServiceByName(servName);
|
||||
if (servIdx < 0) {
|
||||
printf("[Init] StartServiceByName, cannot find service %s.\n", servName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ServiceStart(&g_services[servIdx]) != SERVICE_SUCCESS) {
|
||||
printf("[Init] StartServiceByName, service %s start failed!\n", g_services[servIdx].name);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void StopAllServices()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReapServiceByPID(int pid)
|
||||
{
|
||||
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
|
||||
g_services[i].pid = -1;
|
||||
StopAllServices();
|
||||
RebootSystem();
|
||||
}
|
||||
ServiceReap(&g_services[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 "init_service_manager.h"
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cJSON.h"
|
||||
#include "init_adapter.h"
|
||||
#include "init_jobs.h"
|
||||
#include "init_log.h"
|
||||
#include "init_perms.h"
|
||||
#include "init_read_cfg.h"
|
||||
#include "init_capability.h"
|
||||
#include "init_service_socket.h"
|
||||
#include "init_utils.h"
|
||||
#include "securec.h"
|
||||
|
||||
// All serivce processes that init will fork+exec.
|
||||
static Service* g_services = NULL;
|
||||
static int g_servicesCnt = 0;
|
||||
|
||||
void DumpAllServices()
|
||||
{
|
||||
printf("[Init] Ready to dump all services:\n");
|
||||
printf("[Init] total service number: %d\n", g_servicesCnt);
|
||||
for (int i = 0; i < g_servicesCnt; i++) {
|
||||
printf("\tservice name: [%s]\n", g_services[i].name);
|
||||
printf("\tpath :");
|
||||
for (int j = 0; j < g_services[i].pathArgsCnt; j++) {
|
||||
printf(" %s", g_services[i].pathArgs[j]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("[Init] Dump all services finished\n");
|
||||
}
|
||||
|
||||
void RegisterServices(Service* services, int servicesCnt)
|
||||
{
|
||||
g_services = services;
|
||||
g_servicesCnt += servicesCnt;
|
||||
}
|
||||
|
||||
static void ReleaseServiceMem(Service* curServ)
|
||||
{
|
||||
if (curServ->pathArgs != NULL) {
|
||||
for (int i = 0; i < curServ->pathArgsCnt; ++i) {
|
||||
if (curServ->pathArgs[i] != NULL) {
|
||||
free(curServ->pathArgs[i]);
|
||||
curServ->pathArgs[i] = NULL;
|
||||
}
|
||||
}
|
||||
free(curServ->pathArgs);
|
||||
curServ->pathArgs = NULL;
|
||||
}
|
||||
curServ->pathArgsCnt = 0;
|
||||
|
||||
if (curServ->servPerm.caps != NULL) {
|
||||
free(curServ->servPerm.caps);
|
||||
curServ->servPerm.caps = NULL;
|
||||
}
|
||||
curServ->servPerm.capsCnt = 0;
|
||||
|
||||
for (int i = 0; i < MAX_WRITEPID_FILES; i++) {
|
||||
if (curServ->writepidFiles[i] != NULL) {
|
||||
free(curServ->writepidFiles[i]);
|
||||
curServ->writepidFiles[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (curServ->servPerm.gIDArray != NULL) {
|
||||
free(curServ->servPerm.gIDArray);
|
||||
curServ->servPerm.gIDArray = NULL;
|
||||
}
|
||||
curServ->servPerm.gIDCnt = 0;
|
||||
}
|
||||
|
||||
static int GetServiceName(const cJSON* curArrItem, Service* curServ)
|
||||
{
|
||||
char* fieldStr = cJSON_GetStringValue(cJSON_GetObjectItem(curArrItem, "name"));
|
||||
if (fieldStr == NULL) {
|
||||
INIT_LOGE("[init] GetServiceName cJSON_GetStringValue error\n");
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
size_t strLen = strlen(fieldStr);
|
||||
if (strLen == 0 || strLen > MAX_SERVICE_NAME) {
|
||||
INIT_LOGE("[init] GetServiceName strLen = %d, error\n", strLen);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
if (memcpy_s(curServ->name, MAX_SERVICE_NAME, fieldStr, strLen) != EOK) {
|
||||
INIT_LOGE("[init] GetServiceName memcpy_s error\n");
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->name[strLen] = '\0';
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
static int IsForbidden(const char* fieldStr)
|
||||
{
|
||||
size_t fieldLen = strlen(fieldStr);
|
||||
size_t forbidStrLen = strlen(BIN_SH_NOT_ALLOWED);
|
||||
if (fieldLen == forbidStrLen) {
|
||||
if (strncmp(fieldStr, BIN_SH_NOT_ALLOWED, fieldLen) == 0) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
} else if (fieldLen > forbidStrLen) {
|
||||
// "/bin/shxxxx" is valid but "/bin/sh xxxx" is invalid
|
||||
if (strncmp(fieldStr, BIN_SH_NOT_ALLOWED, forbidStrLen) == 0) {
|
||||
if (fieldStr[forbidStrLen] == ' ') {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: move this function to common files
|
||||
static cJSON* GetArrItem(const cJSON* fileRoot, int* arrSize, const char* arrName)
|
||||
{
|
||||
cJSON* arrItem = cJSON_GetObjectItemCaseSensitive(fileRoot, arrName);
|
||||
if (!cJSON_IsArray(arrItem)) {
|
||||
printf("[Init] GetArrItem, item %s is not an array!\n", arrName);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*arrSize = cJSON_GetArraySize(arrItem);
|
||||
if (*arrSize <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
return arrItem;
|
||||
}
|
||||
|
||||
static int GetWritepidStrings(const cJSON *curArrItem, Service *curServ) // writepid
|
||||
{
|
||||
int writepidCnt = 0;
|
||||
cJSON* filedJ = GetArrItem(curArrItem, &writepidCnt, "writepid");
|
||||
if (writepidCnt <= 0) { // not item is ok.
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
if (writepidCnt > MAX_WRITEPID_FILES) {
|
||||
INIT_LOGE("[Init] GetWritepidStrings, too many writepid[cnt %d] for one service, should not exceed %d.\n",
|
||||
writepidCnt, MAX_WRITEPID_FILES);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
for (int i = 0; i < writepidCnt; ++i) {
|
||||
if (!cJSON_GetArrayItem(filedJ, i) || !cJSON_GetStringValue(cJSON_GetArrayItem(filedJ, i))
|
||||
|| strlen(cJSON_GetStringValue(cJSON_GetArrayItem(filedJ, i))) <= 0) { // check all errors
|
||||
INIT_LOGE("[Init] GetWritepidStrings, parse item[%d] error.\n", i);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
char *fieldStr = cJSON_GetStringValue(cJSON_GetArrayItem(filedJ, i));
|
||||
size_t strLen = strlen(fieldStr);
|
||||
curServ->writepidFiles[i] = (char *)malloc(sizeof(char) * strLen + 1);
|
||||
if (curServ->writepidFiles[i] == NULL) {
|
||||
INIT_LOGE("[Init] GetWritepidStrings, malloc item[%d] error.\n", i);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
if (memcpy_s(curServ->writepidFiles[i], strLen + 1, fieldStr, strLen) != EOK) {
|
||||
INIT_LOGE("[Init] GetWritepidStrings, memcpy_s error.\n");
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->writepidFiles[i][strLen] = '\0';
|
||||
}
|
||||
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
static int GetGidOneItem(const cJSON *curArrItem, Service *curServ) // gid one item
|
||||
{
|
||||
cJSON* filedJ = cJSON_GetObjectItem(curArrItem, GID_STR_IN_CFG);
|
||||
if (filedJ == NULL) {
|
||||
INIT_LOGE("[Init] GetGidOneItem, gid is not an item.\n");
|
||||
return SERVICE_FAILURE; // not found
|
||||
}
|
||||
curServ->servPerm.gIDCnt = 1;
|
||||
curServ->servPerm.gIDArray = (gid_t *)malloc(sizeof(gid_t));
|
||||
if (curServ->servPerm.gIDArray == NULL) {
|
||||
INIT_LOGE("[Init] GetGidOneItem, can't malloc, error.\n");
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
if (cJSON_IsString(filedJ)) {
|
||||
char* fieldStr = cJSON_GetStringValue(filedJ);
|
||||
gid_t gID = DecodeUid(fieldStr);
|
||||
if (gID == (gid_t)(-1)) {
|
||||
INIT_LOGE("[Init] GetGidOneItem, DecodeUid %s error.\n", fieldStr);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->servPerm.gIDArray[0] = gID;
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
if (cJSON_IsNumber(filedJ)) {
|
||||
gid_t gID = (int)cJSON_GetNumberValue(filedJ);
|
||||
if (gID < 0) {
|
||||
INIT_LOGE("[Init] GetGidOneItem, gID = %d error.\n", gID);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->servPerm.gIDArray[0] = gID;
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
INIT_LOGE("[Init] GetGidOneItem, this gid is neither a string nor a number, error.\n");
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
static int GetGidArray(const cJSON *curArrItem, Service *curServ) // gid array
|
||||
{
|
||||
int gIDCnt = 0;
|
||||
cJSON* filedJ = GetArrItem(curArrItem, &gIDCnt, GID_STR_IN_CFG); // "gid" must have 1 item.
|
||||
if (gIDCnt <= 0) { // not a array, but maybe a item?
|
||||
INIT_LOGE("[Init] GetGidArray, gid is not a list.\n");
|
||||
return GetGidOneItem(curArrItem, curServ);
|
||||
}
|
||||
|
||||
if (gIDCnt > NGROUPS_MAX + 1) {
|
||||
INIT_LOGE("[Init] GetGidArray, too many gids[cnt %d] for one service, should not exceed %d.\n",
|
||||
gIDCnt, NGROUPS_MAX + 1);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
curServ->servPerm.gIDArray = (gid_t *)malloc(sizeof(gid_t) * gIDCnt);
|
||||
if (curServ->servPerm.gIDArray == NULL) {
|
||||
INIT_LOGE("[init] GetGidArray malloc error\n");
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->servPerm.gIDCnt = gIDCnt;
|
||||
int i = 0;
|
||||
for (; i < gIDCnt; ++i) {
|
||||
if (cJSON_GetArrayItem(filedJ, i) == NULL || !cJSON_GetStringValue(cJSON_GetArrayItem(filedJ, i))
|
||||
|| strlen(cJSON_GetStringValue(cJSON_GetArrayItem(filedJ, i))) <= 0) { // check all errors
|
||||
INIT_LOGE("[Init] GetGidArray, parse item[%d] as string, error.\n", i);
|
||||
break;
|
||||
}
|
||||
char* fieldStr = cJSON_GetStringValue(cJSON_GetArrayItem(filedJ, i));
|
||||
gid_t gID = DecodeUid(fieldStr);
|
||||
if ((gID) == (gid_t)(-1)) {
|
||||
INIT_LOGE("[Init] GetGidArray, DecodeUid item[%d] error.\n", i);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->servPerm.gIDArray[i] = gID;
|
||||
}
|
||||
if (i == gIDCnt) {
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
for (i = 0; i < gIDCnt; ++i) {
|
||||
if (cJSON_GetArrayItem(filedJ, i) == NULL || !cJSON_IsNumber(cJSON_GetArrayItem(filedJ, i))) {
|
||||
INIT_LOGE("[Init] GetGidArray, parse item[%d] as number, error.\n", i);
|
||||
break;
|
||||
}
|
||||
gid_t gID = (int)cJSON_GetNumberValue(cJSON_GetArrayItem(filedJ, i));
|
||||
if (gID < 0) {
|
||||
INIT_LOGE("[init] GetGidArray gID = %d, error\n", gID);
|
||||
break;
|
||||
}
|
||||
curServ->servPerm.gIDArray[i] = gID;
|
||||
}
|
||||
int ret = i == gIDCnt ? SERVICE_SUCCESS : SERVICE_FAILURE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int GetServicePathAndArgs(const cJSON* curArrItem, Service* curServ)
|
||||
{
|
||||
cJSON* pathItem = cJSON_GetObjectItem(curArrItem, "path");
|
||||
if (!cJSON_IsArray(pathItem)) {
|
||||
INIT_LOGE("[init] GetServicePathAndArgs path item not found or not a array\n");
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
int arrSize = cJSON_GetArraySize(pathItem);
|
||||
if (arrSize <= 0 || arrSize > MAX_PATH_ARGS_CNT) { // array size invalid
|
||||
INIT_LOGE("[init] GetServicePathAndArgs arrSize = %d, error\n", arrSize);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
curServ->pathArgs = (char**)malloc((arrSize + 1) * sizeof(char*));
|
||||
if (curServ->pathArgs == NULL) {
|
||||
INIT_LOGE("[init] GetServicePathAndArgs malloc 1 error\n");
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
for (int i = 0; i < arrSize + 1; ++i) {
|
||||
curServ->pathArgs[i] = NULL;
|
||||
}
|
||||
curServ->pathArgsCnt = arrSize + 1;
|
||||
|
||||
for (int i = 0; i < arrSize; ++i) {
|
||||
char* curParam = cJSON_GetStringValue(cJSON_GetArrayItem(pathItem, i));
|
||||
if (curParam == NULL || strlen(curParam) > MAX_ONE_ARG_LEN) {
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
if (curParam == NULL) {
|
||||
INIT_LOGE("[init] GetServicePathAndArgs curParam == NULL, error\n");
|
||||
} else {
|
||||
INIT_LOGE("[init] GetServicePathAndArgs strlen = %d, error\n", strlen(curParam));
|
||||
}
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
if (i == 0 && IsForbidden(curParam)) {
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
INIT_LOGE("[init] GetServicePathAndArgs i == 0 && IsForbidden, error\n");
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
size_t paramLen = strlen(curParam);
|
||||
curServ->pathArgs[i] = (char*)malloc(paramLen + 1);
|
||||
if (curServ->pathArgs[i] == NULL) {
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
INIT_LOGE("[init] GetServicePathAndArgs i == 0 && IsForbidden, error\n");
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
if (memcpy_s(curServ->pathArgs[i], paramLen + 1, curParam, paramLen) != EOK) {
|
||||
// resources will be released by function: ReleaseServiceMem
|
||||
INIT_LOGE("[init] GetServicePathAndArgs malloc 2 error.\n");
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->pathArgs[i][paramLen] = '\0';
|
||||
}
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
static int GetServiceNumber(const cJSON* curArrItem, Service* curServ, const char* targetField)
|
||||
{
|
||||
cJSON* filedJ = cJSON_GetObjectItem(curArrItem, targetField);
|
||||
if (filedJ == NULL && (strncmp(targetField, CRITICAL_STR_IN_CFG, strlen(CRITICAL_STR_IN_CFG)) == 0
|
||||
|| strncmp(targetField, DISABLED_STR_IN_CFG, strlen(DISABLED_STR_IN_CFG)) == 0
|
||||
|| strncmp(targetField, ONCE_STR_IN_CFG, strlen(ONCE_STR_IN_CFG)) == 0
|
||||
|| strncmp(targetField, IMPORTANT_STR_IN_CFG, strlen(IMPORTANT_STR_IN_CFG)) == 0)) {
|
||||
return SERVICE_SUCCESS; // not found "critical","disabled","once","importance" item is ok
|
||||
}
|
||||
|
||||
if (!cJSON_IsNumber(filedJ)) {
|
||||
INIT_LOGE("[Init] GetServiceNumber, %s is null or is not a number, error.\n", targetField);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
int value = (int)cJSON_GetNumberValue(filedJ);
|
||||
if (value < 0) {
|
||||
INIT_LOGE("[Init] GetServiceNumber, value = %d, error.\n", value);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
if (strncmp(targetField, ONCE_STR_IN_CFG, strlen(ONCE_STR_IN_CFG)) == 0) {
|
||||
if (value != 0) {
|
||||
curServ->attribute |= SERVICE_ATTR_ONCE;
|
||||
}
|
||||
} else if (strncmp(targetField, IMPORTANT_STR_IN_CFG, strlen(IMPORTANT_STR_IN_CFG)) == 0) {
|
||||
if (value != 0) {
|
||||
curServ->attribute |= SERVICE_ATTR_IMPORTANT;
|
||||
}
|
||||
} else if (strncmp(targetField, CRITICAL_STR_IN_CFG, strlen(CRITICAL_STR_IN_CFG)) == 0) { // set critical
|
||||
curServ->attribute &= ~SERVICE_ATTR_CRITICAL;
|
||||
if (value == 1) {
|
||||
curServ->attribute |= SERVICE_ATTR_CRITICAL;
|
||||
}
|
||||
} else if (strncmp(targetField, DISABLED_STR_IN_CFG, strlen(DISABLED_STR_IN_CFG)) == 0) { // set disabled
|
||||
curServ->attribute &= ~SERVICE_ATTR_DISABLED;
|
||||
if (value == 1) {
|
||||
curServ->attribute |= SERVICE_ATTR_DISABLED;
|
||||
}
|
||||
} else {
|
||||
INIT_LOGE("[Init] GetServiceNumber, item = %s, not expected, error.\n", targetField);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
static int GetUidStringNumber(const cJSON *curArrItem, Service *curServ)
|
||||
{
|
||||
cJSON* filedJ = cJSON_GetObjectItem(curArrItem, UID_STR_IN_CFG);
|
||||
if (filedJ == NULL) {
|
||||
INIT_LOGE("[Init] GetUidStringNumber, %s not found, error.\n", UID_STR_IN_CFG);
|
||||
return SERVICE_FAILURE; // not found
|
||||
}
|
||||
|
||||
if (cJSON_IsString(filedJ)) {
|
||||
char* fieldStr = cJSON_GetStringValue(filedJ);
|
||||
int uID = DecodeUid(fieldStr);
|
||||
if (uID < 0) {
|
||||
INIT_LOGE("[Init] GetUidStringNumber, DecodeUid %s error.\n", fieldStr);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->servPerm.uID = uID;
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
if (cJSON_IsNumber(filedJ)) {
|
||||
int uID = (int)cJSON_GetNumberValue(filedJ);
|
||||
if (uID < 0) {
|
||||
INIT_LOGE("[Init] GetUidStringNumber, uID = %d error.\n", uID);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->servPerm.uID = uID;
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
INIT_LOGE("[Init] GetUidStringNumber, this uid is neither a string nor a number, error.\n");
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
static int SplitString(char *srcPtr, char **dstPtr)
|
||||
{
|
||||
if (!srcPtr) {
|
||||
return -1;
|
||||
}
|
||||
char *buf = NULL;
|
||||
dstPtr[0] = strtok_r(srcPtr, " ", &buf);
|
||||
int i = 0;
|
||||
while (dstPtr[i])
|
||||
{
|
||||
i++;
|
||||
dstPtr[i] = strtok_r(NULL, " ", &buf);
|
||||
}
|
||||
dstPtr[i] = "\0";
|
||||
int num = i;
|
||||
for (int j = 0; j < num; j++)
|
||||
{
|
||||
printf("dstPtr[%d] is %s \n", j, dstPtr[j]);
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
#define MAX_SOCK_NAME_LEN 16
|
||||
#define SOCK_OPT_NUMS 6
|
||||
enum SockOptionTab
|
||||
{
|
||||
SERVICE_SOCK_NAME = 0,
|
||||
SERVICE_SOCK_TYPE,
|
||||
SERVICE_SOCK_PERM,
|
||||
SERVICE_SOCK_UID,
|
||||
SERVICE_SOCK_GID,
|
||||
SERVICE_SOCK_SETOPT
|
||||
};
|
||||
|
||||
static int ParseServiceSocket(char **opt, const int optNum, struct ServiceSocket *sockopt)
|
||||
{
|
||||
printf("[init] ParseServiceSocket\n");
|
||||
if (optNum != SOCK_OPT_NUMS) {
|
||||
return -1;
|
||||
}
|
||||
sockopt->name = (char *)calloc(MAX_SOCK_NAME_LEN, sizeof(char));
|
||||
if (sockopt->name == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (opt[SERVICE_SOCK_NAME] == NULL) {
|
||||
return -1;
|
||||
}
|
||||
printf("[init] ParseServiceSocket SERVICE_SOCK_NAME is %s \n", opt[SERVICE_SOCK_NAME]);
|
||||
int ret = memcpy_s(sockopt->name, MAX_SOCK_NAME_LEN, opt[SERVICE_SOCK_NAME], MAX_SOCK_NAME_LEN - 1);
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (opt[SERVICE_SOCK_TYPE] == NULL) {
|
||||
return -1;
|
||||
}
|
||||
printf("[init] ParseServiceSocket SERVICE_SOCK_TYPE is %s \n", opt[SERVICE_SOCK_TYPE]);
|
||||
sockopt->type =
|
||||
strncmp(opt[SERVICE_SOCK_TYPE], "stream", strlen(opt[SERVICE_SOCK_TYPE])) == 0 ? SOCK_STREAM :
|
||||
(strncmp(opt[SERVICE_SOCK_TYPE], "dgram", strlen(opt[SERVICE_SOCK_TYPE])) == 0 ? SOCK_DGRAM : SOCK_SEQPACKET);
|
||||
|
||||
if (opt[SERVICE_SOCK_PERM] == NULL) {
|
||||
return -1;
|
||||
}
|
||||
printf("[init] ParseServiceSocket SERVICE_SOCK_PERM is %s \n", opt[SERVICE_SOCK_PERM]);
|
||||
sockopt->perm = strtoul(opt[SERVICE_SOCK_PERM], 0, 8); //¡Áa?¡¥?a8????
|
||||
|
||||
if (opt[SERVICE_SOCK_UID] == NULL) {
|
||||
return -1;
|
||||
}
|
||||
printf("[init] ParseServiceSocket SERVICE_SOCK_UID is %s \n", opt[SERVICE_SOCK_UID]);
|
||||
int uuid = DecodeUid(opt[SERVICE_SOCK_UID]);
|
||||
if (uuid < 0) {
|
||||
return -1;
|
||||
}
|
||||
sockopt->uid = uuid;
|
||||
printf("[init] ParseServiceSocket uuid is %d \n", uuid);
|
||||
|
||||
if (opt[SERVICE_SOCK_GID] == NULL) {
|
||||
return -1;
|
||||
}
|
||||
printf("[init] ParseServiceSocket SERVICE_SOCK_GID is %s \n", opt[SERVICE_SOCK_GID]);
|
||||
int ggid = DecodeUid(opt[SERVICE_SOCK_GID]);
|
||||
if (ggid < 0) {
|
||||
return -1;
|
||||
}
|
||||
sockopt->gid = ggid;
|
||||
printf("[init] ParseServiceSocket ggid is %d \n", ggid);
|
||||
|
||||
if (opt[SERVICE_SOCK_SETOPT] == NULL) {
|
||||
return -1;
|
||||
}
|
||||
printf("[init] ParseServiceSocket SERVICE_SOCK_SETOPT is %s \n", opt[SERVICE_SOCK_SETOPT]);
|
||||
sockopt->passcred = strncmp(opt[SERVICE_SOCK_SETOPT], "passcred", strlen(opt[SERVICE_SOCK_SETOPT])) == 0 ? true : false;
|
||||
sockopt->next = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int GetServiceSocket(const cJSON* curArrItem, Service* curServ)
|
||||
{
|
||||
printf("[init] GetServiceSocket \n");
|
||||
cJSON* filedJ = cJSON_GetObjectItem(curArrItem, "socket");
|
||||
if (!cJSON_IsArray(filedJ)) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
|
||||
int sockCnt = cJSON_GetArraySize(filedJ);
|
||||
if (sockCnt <= 0) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
printf("[init] GetServiceSocket sockCnt is %d \n", sockCnt);
|
||||
curServ->socketCfg = NULL;
|
||||
for (int i = 0; i < sockCnt; ++i) {
|
||||
cJSON* sockJ = cJSON_GetArrayItem(filedJ, i);
|
||||
if (!cJSON_IsString(sockJ) || !cJSON_GetStringValue(sockJ)) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
char *sockStr = cJSON_GetStringValue(sockJ);
|
||||
char *tmpStr[SOCK_OPT_NUMS] = {NULL,};
|
||||
int num = SplitString(sockStr, tmpStr);
|
||||
if (num != SOCK_OPT_NUMS) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
printf("[init] GetServiceSocket num is %d \n", num);
|
||||
struct ServiceSocket *socktmp = (struct ServiceSocket *)calloc(1, sizeof(struct ServiceSocket));
|
||||
if (!socktmp) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
printf("[init] ParseServiceSocket\n");
|
||||
int ret = ParseServiceSocket(tmpStr, SOCK_OPT_NUMS, socktmp);
|
||||
if (ret < 0) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
if (curServ->socketCfg == NULL) {
|
||||
curServ->socketCfg = socktmp;
|
||||
} else {
|
||||
socktmp->next = curServ->socketCfg->next;
|
||||
curServ->socketCfg->next = socktmp;
|
||||
}
|
||||
}
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
static int GetServiceOnRestart(const cJSON* curArrItem, Service* curServ)
|
||||
{
|
||||
printf("[init] GetServiceOnRestart \n");
|
||||
cJSON* filedJ = cJSON_GetObjectItem(curArrItem, "onrestart");
|
||||
if (!cJSON_IsArray(filedJ)) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
int cmdCnt = cJSON_GetArraySize(filedJ);
|
||||
if (cmdCnt <= 0) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->onRestart = (struct OnRestartCmd *)calloc(1, sizeof(struct OnRestartCmd));
|
||||
if (curServ->onRestart == NULL) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->onRestart->cmdLine = (CmdLine *)calloc(cmdCnt, sizeof(CmdLine));
|
||||
if (curServ->onRestart->cmdLine == NULL) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
curServ->onRestart->cmdNum = cmdCnt;
|
||||
for (int i = 0; i < cmdCnt; ++i) {
|
||||
cJSON* cmdJ = cJSON_GetArrayItem(filedJ, i);
|
||||
if (!cJSON_IsString(cmdJ) || !cJSON_GetStringValue(cmdJ)) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
char *cmdStr = cJSON_GetStringValue(cmdJ);
|
||||
ParseCmdLine(cmdStr, &curServ->onRestart->cmdLine[i]);
|
||||
printf("[init] SetOnRestart cmdLine->name %s cmdLine->cmdContent %s \n", curServ->onRestart->cmdLine[i].name,
|
||||
curServ->onRestart->cmdLine[i].cmdContent);
|
||||
}
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
static int CheckServiceKeyName(const cJSON* curService)
|
||||
{
|
||||
char *cfgServiceKeyList[] = {"name", "path", "uid", "gid", "once",
|
||||
"importance", "caps", "disabled", "writepid", "critical", "socket",
|
||||
};
|
||||
if (curService == NULL) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
cJSON *child = curService->child;
|
||||
if (child == NULL) {
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
while (child) {
|
||||
int i = 0;
|
||||
int keyListSize = sizeof(cfgServiceKeyList) / sizeof(char *);
|
||||
for (; i < keyListSize; i++) {
|
||||
if (!strcmp(child->string, cfgServiceKeyList[i])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i < keyListSize) {
|
||||
child = child->next;
|
||||
} else {
|
||||
INIT_LOGE("[Init] CheckServiceKeyName, key name %s is not found. error.\n", child->string);
|
||||
return SERVICE_FAILURE;
|
||||
}
|
||||
}
|
||||
return SERVICE_SUCCESS;
|
||||
}
|
||||
|
||||
void ParseAllServices(const cJSON* fileRoot)
|
||||
{
|
||||
int servArrSize = 0;
|
||||
cJSON* serviceArr = GetArrItem(fileRoot, &servArrSize, SERVICES_ARR_NAME_IN_JSON);
|
||||
if (serviceArr == NULL) {
|
||||
printf("[Init] InitReadCfg, get array %s failed.\n", SERVICES_ARR_NAME_IN_JSON);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("[Init] servArrSize is %d \n", servArrSize);
|
||||
if (servArrSize > MAX_SERVICES_CNT_IN_FILE) {
|
||||
printf("[Init] InitReadCfg, too many services[cnt %d] detected, should not exceed %d.\n",
|
||||
servArrSize, MAX_SERVICES_CNT_IN_FILE);
|
||||
return;
|
||||
}
|
||||
|
||||
Service* retServices = (Service*)realloc(g_services, sizeof(Service) * (g_servicesCnt + servArrSize));
|
||||
if (retServices == NULL) {
|
||||
printf("[Init] InitReadCfg, realloc for %s arr failed! %d.\n", SERVICES_ARR_NAME_IN_JSON, servArrSize);
|
||||
return;
|
||||
}
|
||||
// Skip already saved services,
|
||||
Service* tmp = retServices + g_servicesCnt;
|
||||
if (memset_s(tmp, sizeof(Service) * servArrSize, 0, sizeof(Service) * servArrSize) != EOK) {
|
||||
free(retServices);
|
||||
retServices = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < servArrSize; ++i) {
|
||||
cJSON* curItem = cJSON_GetArrayItem(serviceArr, i);
|
||||
if (CheckServiceKeyName(curItem) != SERVICE_SUCCESS) {
|
||||
ReleaseServiceMem(&tmp[i]);
|
||||
tmp[i].attribute |= SERVICE_ATTR_INVALID;
|
||||
continue;
|
||||
}
|
||||
tmp[i].servPerm.uID = (uid_t)(-1); // set 0xffffffff as init value
|
||||
int ret1 = GetServiceName(curItem, &tmp[i]);
|
||||
int ret2 = GetServicePathAndArgs(curItem, &tmp[i]);
|
||||
int ret3 = GetUidStringNumber(curItem, &tmp[i]); // uid in string or number form
|
||||
int ret4 = GetGidArray(curItem, &tmp[i]); // gid array
|
||||
int ret5 = GetServiceNumber(curItem, &tmp[i], ONCE_STR_IN_CFG);
|
||||
int ret6 = GetServiceNumber(curItem, &tmp[i], IMPORTANT_STR_IN_CFG);
|
||||
int ret7 = GetServiceNumber(curItem, &tmp[i], CRITICAL_STR_IN_CFG); // critical
|
||||
int ret8 = GetServiceNumber(curItem, &tmp[i], DISABLED_STR_IN_CFG); // disabled
|
||||
int ret9 = GetWritepidStrings(curItem, &tmp[i]); // writepid
|
||||
int reta = GetServiceCaps(curItem, &tmp[i]);
|
||||
int retAll = ret1 | ret2 | ret3 | ret4 | ret5 | ret6 | ret7 | ret8 | ret9 | reta;
|
||||
if (retAll != SERVICE_SUCCESS) {
|
||||
// release resources if it fails
|
||||
ReleaseServiceMem(&tmp[i]);
|
||||
tmp[i].attribute |= SERVICE_ATTR_INVALID;
|
||||
printf("[Init] InitReadCfg, parse information for service %d failed. ", i);
|
||||
printf("service name = [%s]\n", tmp[i].name);
|
||||
printf("ret1=%d,ret2=%d,ret3=%d,ret4=%d,ret5=%d,ret6=%d,ret7=%d,ret8=%d,ret9=%d,reta=%d,",
|
||||
ret1, ret2, ret3, ret4, ret5, ret6, ret7, ret8, ret9, reta);
|
||||
continue;
|
||||
} else {
|
||||
printf("[init] ParseAllServices ParseAllServices Service[%d] name=%s, uid=%d, critical=%d, disabled=%d\n",
|
||||
i, tmp[i].name, tmp[i].servPerm.uID, tmp[i].attribute & SERVICE_ATTR_CRITICAL ? 1 : 0,
|
||||
tmp[i].attribute & SERVICE_ATTR_DISABLED ? 1 : 0);
|
||||
for(int j = 0; j < tmp[i].servPerm.gIDCnt; j++) {
|
||||
printf("\t\tgIDArray[%d] = %d\n", j, tmp[i].servPerm.gIDArray[j]);
|
||||
}
|
||||
for(int j = 0; j < MAX_WRITEPID_FILES; j++) {
|
||||
if(tmp[i].writepidFiles[j])
|
||||
printf("\t\twritepidFiles[%d] = %s\n", j, tmp[i].writepidFiles[j]);
|
||||
}
|
||||
}
|
||||
if (GetServiceSocket(curItem, &tmp[i]) != SERVICE_SUCCESS) {
|
||||
// free list
|
||||
}
|
||||
if (GetServiceOnRestart(curItem, &tmp[i]) != SERVICE_SUCCESS) {
|
||||
// free
|
||||
}
|
||||
}
|
||||
// Increase service counter.
|
||||
RegisterServices(retServices, servArrSize);
|
||||
}
|
||||
|
||||
static int FindServiceByName(const char* servName)
|
||||
{
|
||||
if (servName == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < g_servicesCnt; ++i) {
|
||||
if (strlen(g_services[i].name) == strlen(servName) &&
|
||||
strncmp(g_services[i].name, servName, strlen(g_services[i].name)) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void StartServiceByName(const char* servName)
|
||||
{
|
||||
// find service by name
|
||||
int servIdx = FindServiceByName(servName);
|
||||
if (servIdx < 0) {
|
||||
printf("[Init] StartServiceByName, cannot find service %s.\n", servName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ServiceStart(&g_services[servIdx]) != SERVICE_SUCCESS) {
|
||||
printf("[Init] StartServiceByName, service %s start failed!\n", g_services[servIdx].name);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void StopServiceByName(const char* servName)
|
||||
{
|
||||
// find service by name
|
||||
int servIdx = FindServiceByName(servName);
|
||||
if (servIdx < 0) {
|
||||
INIT_LOGE("[Init] StopServiceByName, cannot find service %s.\n", servName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ServiceStop(&g_services[servIdx]) != SERVICE_SUCCESS) {
|
||||
INIT_LOGE("[Init] StopServiceByName, service %s start failed!\n", g_services[servIdx].name);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void StopAllServices()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReapServiceByPID(int pid)
|
||||
{
|
||||
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
|
||||
g_services[i].pid = -1;
|
||||
StopAllServices();
|
||||
RebootSystem();
|
||||
}
|
||||
ServiceReap(&g_services[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
172
services/src/init_service_socket.c
Executable file
172
services/src/init_service_socket.c
Executable file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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_service_socket.h"
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#define HOS_SOCKET_DIR "/dev/unix/socket"
|
||||
#define HOS_SOCKET_ENV_PREFIX "OHOS_SOCKET_"
|
||||
|
||||
static int CreateSocket(struct ServiceSocket *sockopt)
|
||||
{
|
||||
if (!sockopt || !sockopt->name) {
|
||||
return -1;
|
||||
}
|
||||
printf("[init] CreateSocket\n");
|
||||
int sockFd = socket(PF_UNIX, sockopt->type, 0);
|
||||
if (sockFd < 0) {
|
||||
printf("[init] socket fail %d \n", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct sockaddr_un addr;
|
||||
bzero(&addr,sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
snprintf(addr.sun_path, sizeof(addr.sun_path), HOS_SOCKET_DIR"/%s",
|
||||
sockopt->name);
|
||||
printf("[init] addr.sun_path is %s \n", addr.sun_path);
|
||||
if (access(addr.sun_path, F_OK)) {
|
||||
printf("[init] %s already exist, remove it\n", addr.sun_path);
|
||||
unlink(addr.sun_path);
|
||||
}
|
||||
if (sockopt->passcred) {
|
||||
int on = 1;
|
||||
if (setsockopt(sockFd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
|
||||
unlink(addr.sun_path);
|
||||
close(sockFd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (bind(sockFd, (struct sockaddr *)&addr, sizeof(addr))) {
|
||||
printf("[Init] Create socket for service %s failed: %d\n", sockopt->name, errno);
|
||||
unlink(addr.sun_path);
|
||||
close(sockFd);
|
||||
return -1;
|
||||
}
|
||||
printf("[init] bind socket success\n");
|
||||
if (lchown(addr.sun_path, sockopt->uid, sockopt->gid)) {
|
||||
unlink(addr.sun_path);
|
||||
close(sockFd);
|
||||
printf("[init] lchown fail %d \n", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fchmodat(AT_FDCWD, addr.sun_path, sockopt->perm, AT_SYMLINK_NOFOLLOW)) {
|
||||
unlink(addr.sun_path);
|
||||
close(sockFd);
|
||||
printf("[Init] fchmodat fail %d \n", errno);
|
||||
return -1;
|
||||
}
|
||||
printf("[Init] CreateSocket success \n");
|
||||
return sockFd;
|
||||
}
|
||||
|
||||
static int SetSocketEnv(int fd, char *name)
|
||||
{
|
||||
printf("[init] SetSocketEnv\n");
|
||||
char pubName[64] = {0};
|
||||
char val[16] = {0};
|
||||
snprintf(pubName, sizeof(pubName), HOS_SOCKET_ENV_PREFIX"%s", name);
|
||||
printf("[init] pubName is %s \n", pubName);
|
||||
snprintf(val, sizeof(val), "%d", fd);
|
||||
printf("[init] val is %s \n", val);
|
||||
int ret = setenv(pubName, val, 1);
|
||||
if (ret < 0) {
|
||||
printf("[init] setenv fail %d \n", errno);
|
||||
return -1;
|
||||
}
|
||||
fcntl(fd, F_SETFD, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DoCreateSocket(struct ServiceSocket *sockopt)
|
||||
{
|
||||
if (!sockopt) {
|
||||
return -1;
|
||||
}
|
||||
printf("[init] DoCreateSocket \n");
|
||||
struct ServiceSocket *tmpSock = sockopt;
|
||||
while (tmpSock) {
|
||||
printf("[init] tmpSock %p \n", tmpSock);
|
||||
int fd = CreateSocket(tmpSock);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
int ret = SetSocketEnv(fd, tmpSock->name);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
tmpSock = tmpSock->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetControlFromEnv(char *path)
|
||||
{
|
||||
if (path == NULL) {
|
||||
return -1;
|
||||
}
|
||||
char *cp = path;
|
||||
while (*cp) {
|
||||
if (!isalnum(*cp)) *cp = '_';
|
||||
++cp;
|
||||
}
|
||||
const char *val = getenv(path);
|
||||
if (val == NULL) {
|
||||
return -1;
|
||||
}
|
||||
errno = 0;
|
||||
int fd = strtol(val, NULL, 10);
|
||||
if (errno) {
|
||||
return -1;
|
||||
}
|
||||
if (fcntl(fd, F_GETFD) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int GetControlSocket(const char *name)
|
||||
{
|
||||
if (name == NULL) {
|
||||
return -1;
|
||||
}
|
||||
char path[128] = {0};
|
||||
snprintf(path, sizeof(path), HOS_SOCKET_ENV_PREFIX"%s", name);
|
||||
int fd = GetControlFromEnv(path);
|
||||
|
||||
struct sockaddr_un addr;
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
int ret = getsockname(fd, (struct sockaddr*)&addr, &addrlen);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
char sockDir[128] = {0};
|
||||
snprintf(sockDir, sizeof(sockDir), HOS_SOCKET_DIR"/%s", name);
|
||||
if (strncmp(sockDir, addr.sun_path, strlen(sockDir)) == 0) {
|
||||
return fd;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
180
services/src/init_utils.c
Executable file
180
services/src/init_utils.c
Executable file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* 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_utils.h"
|
||||
#include <ctype.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "init_cmds.h"
|
||||
#include "init_log.h"
|
||||
#include "init_utils.h"
|
||||
#include "securec.h"
|
||||
|
||||
#define MAX_BUF_SIZE 1024
|
||||
#ifdef STARTUP_UT
|
||||
#define LOG_FILE_NAME "/media/sf_ubuntu/test/log.txt"
|
||||
#else
|
||||
#define LOG_FILE_NAME "/data/startup_log.txt"
|
||||
#endif
|
||||
#define MAX_BUFFER 256
|
||||
#define MAX_EACH_CMD_LENGTH 30
|
||||
#define MAX_JSON_FILE_LEN 102400 // max init.cfg size 100KB
|
||||
|
||||
struct CmdArgs* GetCmd(const char *cmdContent, const char *delim)
|
||||
{
|
||||
struct CmdArgs *ctx = (struct CmdArgs *)malloc(sizeof(struct CmdArgs));
|
||||
INIT_CHECK_ONLY_RETURN(ctx != NULL, return NULL);
|
||||
|
||||
ctx->argv = (char**)malloc(sizeof(char*) * MAX_CMD_NAME_LEN);
|
||||
INIT_CHECK_ONLY_RETURN(ctx->argv != NULL, FreeCmd(&ctx); return NULL);
|
||||
|
||||
char tmpCmd[MAX_BUFFER];
|
||||
INIT_CHECK_ONLY_RETURN(strncpy_s(tmpCmd, strlen(cmdContent) + 1, cmdContent, strlen(cmdContent)) == EOK,
|
||||
FreeCmd(&ctx);
|
||||
return NULL);
|
||||
tmpCmd[strlen(cmdContent)] = '\0';
|
||||
|
||||
char *buffer = NULL;
|
||||
char *token = strtok_r(tmpCmd, delim, &buffer);
|
||||
ctx->argc = 0;
|
||||
while (token != NULL) {
|
||||
ctx->argv[ctx->argc] = calloc(sizeof(char *), MAX_EACH_CMD_LENGTH);
|
||||
INIT_CHECK_ONLY_RETURN(ctx->argv[ctx->argc] != NULL, FreeCmd(&ctx); return NULL);
|
||||
|
||||
INIT_CHECK_ONLY_RETURN(strncpy_s(ctx->argv[ctx->argc], strlen(cmdContent) + 1, token, strlen(token)) == EOK,
|
||||
FreeCmd(&ctx);
|
||||
return NULL);
|
||||
if (ctx->argc > MAX_CMD_NAME_LEN - 1) {
|
||||
INIT_LOGE("[Init] GetCmd failed, max cmd number is 10.\n");
|
||||
FreeCmd(&ctx);
|
||||
return NULL;
|
||||
}
|
||||
token = strtok_r(NULL, delim, &buffer);
|
||||
ctx->argc += 1;
|
||||
}
|
||||
ctx->argv[ctx->argc] = NULL;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void FreeCmd(struct CmdArgs **cmd)
|
||||
{
|
||||
struct CmdArgs *tmpCmd = *cmd;
|
||||
INIT_CHECK_ONLY_RETURN(tmpCmd != NULL, return);
|
||||
for (int i = 0; i < tmpCmd->argc; ++i) {
|
||||
INIT_CHECK_ONLY_RETURN(tmpCmd->argv[i] == NULL, free(tmpCmd->argv[i]));
|
||||
}
|
||||
INIT_CHECK_ONLY_RETURN(tmpCmd->argv == NULL, free(tmpCmd->argv));
|
||||
free(tmpCmd);
|
||||
return;
|
||||
}
|
||||
|
||||
void Logger(StatupLogLevel level, const char *format, ...)
|
||||
{
|
||||
FILE* pFile = fopen(LOG_FILE_NAME, "a");
|
||||
static char *logLeveInfo[] = { "VERBOSE", "INFO", "WARN", "ERROR", "FATAL" };
|
||||
if (level >= sizeof(logLeveInfo) / sizeof(char*) || pFile == NULL) {
|
||||
return;
|
||||
}
|
||||
time_t t;
|
||||
struct tm *localTimer;
|
||||
time(&t);
|
||||
localTimer = localtime (&t);
|
||||
fprintf(pFile, "[%d/%d/%d %d:%d:%d][%s]", localTimer->tm_year + 1900, localTimer->tm_mon, localTimer->tm_mday,
|
||||
localTimer->tm_hour, localTimer->tm_min, localTimer->tm_sec, logLeveInfo[level]);
|
||||
|
||||
va_list list;
|
||||
va_start(list, format);
|
||||
vfprintf(pFile, format, list);
|
||||
va_end(list);
|
||||
|
||||
fprintf(pFile, "%s", " \n");
|
||||
fflush(pFile);
|
||||
fclose(pFile);
|
||||
}
|
||||
|
||||
int DecodeUid(const char *name)
|
||||
{
|
||||
if (isalpha(name[0])) {
|
||||
struct passwd *pwd = getpwnam(name);
|
||||
if (!pwd) {
|
||||
return -1;
|
||||
}
|
||||
return pwd->pw_uid;
|
||||
} else if (isdigit(name[0])) {
|
||||
uid_t result = strtoul(name, 0, 10);
|
||||
return result;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void CheckAndCreateDir(const char *fileName)
|
||||
{
|
||||
char *path = strndup(fileName, strrchr(fileName, '/') - fileName);
|
||||
if (path != NULL && access(path, F_OK) != 0) {
|
||||
mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
|
||||
}
|
||||
free(path);
|
||||
}
|
||||
|
||||
char* ReadFileToBuf(const char *configFile)
|
||||
{
|
||||
char* buffer = NULL;
|
||||
FILE* fd = NULL;
|
||||
struct stat fileStat = {0};
|
||||
if (configFile == NULL || *configFile == '\0') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
do {
|
||||
if (stat(configFile, &fileStat) != 0 ||
|
||||
fileStat.st_size <= 0 || fileStat.st_size > MAX_JSON_FILE_LEN) {
|
||||
break;
|
||||
}
|
||||
fd = fopen(configFile, "r");
|
||||
if (fd == NULL) {
|
||||
break;
|
||||
}
|
||||
buffer = (char*)malloc(fileStat.st_size + 1);
|
||||
if (buffer == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (fread(buffer, fileStat.st_size, 1, fd) != 1) {
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
break;
|
||||
}
|
||||
buffer[fileStat.st_size] = '\0';
|
||||
} while (0);
|
||||
|
||||
if (fd != NULL) {
|
||||
fclose(fd);
|
||||
fd = NULL;
|
||||
}
|
||||
return buffer;
|
||||
}
|
@ -33,6 +33,8 @@
|
||||
|
||||
#ifndef OHOS_LITE
|
||||
#include "device.h"
|
||||
#include "property.h"
|
||||
#include "property_service.h"
|
||||
#endif
|
||||
|
||||
static const pid_t INIT_PROCESS_PID = 1;
|
||||
@ -82,6 +84,9 @@ int main(int argc, char * const argv[])
|
||||
// 2. Mount basic filesystem and create common device node.
|
||||
MountBasicFs();
|
||||
CreateDeviceNode();
|
||||
MakeSocketDir("/dev/unix/socket/", 0755);
|
||||
|
||||
InitPropertyService();
|
||||
#endif
|
||||
|
||||
// 3. signal register
|
||||
@ -107,6 +112,12 @@ int main(int argc, char * const argv[])
|
||||
// 5. read configuration file and do jobs
|
||||
InitReadCfg();
|
||||
|
||||
LoadDefaultProperty("/system/build.prop");
|
||||
LoadDefaultProperty("/system/buildz.prop");
|
||||
LoadDefaultProperty("/vendor/build.prop");
|
||||
LoadDefaultProperty("/vendor/default.prop");
|
||||
LoadDefaultProperty("/vendor/odm/etc/build.prop");
|
||||
LoadDefaultProperty("/system/etc/prop.default");
|
||||
#ifdef OHOS_DEBUG
|
||||
struct timespec tmCfg;
|
||||
if (clock_gettime(CLOCK_REALTIME, &tmCfg) != 0) {
|
||||
@ -121,6 +132,9 @@ int main(int argc, char * const argv[])
|
||||
#endif
|
||||
|
||||
printf("[Init] main, entering wait.\n");
|
||||
#ifndef OHOS_LITE
|
||||
StartPropertyService();
|
||||
#endif
|
||||
while (1) {
|
||||
// pause only returns when a signal was caught and the signal-catching function returned.
|
||||
// pause only returns -1, no need to process the return value.
|
||||
|
@ -34,6 +34,7 @@ if (defined(ohos_lite)) {
|
||||
"//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_utils.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",
|
||||
|
@ -48,7 +48,7 @@ const uid_t CFG_FILE_UID = 0;
|
||||
const gid_t CFG_FILE_GID = 0;
|
||||
const mode_t CFG_FILE_MODE = S_IRUSR;
|
||||
const int JOBS_IN_FILE_COUNT = 3; // pre-init, init, post-init
|
||||
const int MAX_SERVICES_CNT_IN_FILE = 100;
|
||||
const int MAX_SERVICES_COUNT_IN_FILE = 100;
|
||||
const int MAX_CAPS_CNT_FOR_ONE_SERVICE = 100;
|
||||
const unsigned int MAX_CAPABILITY_VALUE = 4294967295; // 0xFFFFFFFF
|
||||
const unsigned int MAX_JSON_FILE_LEN = 102400; // max init.cfg size 100KB
|
||||
@ -642,7 +642,7 @@ static void CheckServices(const cJSON* fileRoot)
|
||||
int servArrSize = 0;
|
||||
cJSON* serviceArr = GetArrItem(fileRoot, servArrSize, SERVICE_ARR_NAME_IN_JSON);
|
||||
EXPECT_TRUE(serviceArr != nullptr);
|
||||
EXPECT_TRUE(servArrSize <= MAX_SERVICES_CNT_IN_FILE);
|
||||
EXPECT_TRUE(servArrSize <= MAX_SERVICES_COUNT_IN_FILE);
|
||||
|
||||
for (int i = 0; i < servArrSize; ++i) {
|
||||
cJSON* curItem = cJSON_GetArrayItem(serviceArr, i);
|
||||
|
40
services/trigger/BUILD.gn
Executable file
40
services/trigger/BUILD.gn
Executable file
@ -0,0 +1,40 @@
|
||||
# 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.
|
||||
|
||||
import("//build/ohos.gni")
|
||||
|
||||
ohos_static_library("triggerservice") {
|
||||
sources = [
|
||||
"trigger_manager.c",
|
||||
"trigger_processor.c",
|
||||
"trigger_checker.c",
|
||||
"//base/startup/init_lite/services/src/init_utils.c",
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
".",
|
||||
"//base/startup/init_lite/services/include/property",
|
||||
"//base/startup/init_lite/services/include/trigger",
|
||||
"//base/startup/init_lite/services/include",
|
||||
"//base/startup/init_lite/services/property/include",
|
||||
"//third_party/libuv/include",
|
||||
"//third_party/cJSON",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"//third_party/libuv:uv_static",
|
||||
"//third_party/bounds_checking_function:libsec_static",
|
||||
]
|
||||
part_name = "startup"
|
||||
subsystem_name = "startup"
|
||||
}
|
298
services/trigger/trigger_checker.c
Executable file
298
services/trigger/trigger_checker.c
Executable file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
* 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 "trigger_checker.h"
|
||||
#include <ctype.h>
|
||||
#include "trigger_manager.h"
|
||||
#include "property_service.h"
|
||||
|
||||
// 申请整块能存作为计算的节点
|
||||
int CalculatorInit(LogicCalculator *calculator, int dataNumber, int dataUnit, int needCondition)
|
||||
{
|
||||
TRIGGER_CHECK(calculator != NULL, return -1, "Invalid param");
|
||||
int dataSize = dataUnit * dataNumber;
|
||||
if (needCondition) {
|
||||
dataSize += 5 * SUPPORT_DATA_BUFFER_MAX;
|
||||
}
|
||||
calculator->data = (char *)malloc(dataSize);
|
||||
TRIGGER_CHECK(calculator->data != NULL, return -1, "Failed to malloc for calculator");
|
||||
calculator->dataNumber = dataNumber;
|
||||
calculator->endIndex = 0;
|
||||
calculator->dataUnit = dataUnit;
|
||||
|
||||
dataSize = dataUnit * dataNumber;
|
||||
calculator->conditionName = calculator->data + dataSize;
|
||||
dataSize += SUPPORT_DATA_BUFFER_MAX;
|
||||
calculator->conditionContent = calculator->data + dataSize;
|
||||
dataSize += SUPPORT_DATA_BUFFER_MAX;
|
||||
calculator->inputName = calculator->data + dataSize;
|
||||
dataSize += SUPPORT_DATA_BUFFER_MAX;
|
||||
calculator->inputContent = calculator->data + dataSize;
|
||||
dataSize += SUPPORT_DATA_BUFFER_MAX;
|
||||
calculator->readContent = calculator->data + dataSize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CalculatorFree(LogicCalculator *calculator)
|
||||
{
|
||||
TRIGGER_CHECK(calculator != NULL, return, "Invalid param");
|
||||
free(calculator->data);
|
||||
calculator->data = NULL;
|
||||
}
|
||||
|
||||
static void CalculatorClear(LogicCalculator *calculator)
|
||||
{
|
||||
TRIGGER_CHECK(calculator != NULL, return, "Invalid param");
|
||||
calculator->endIndex = 0;
|
||||
}
|
||||
|
||||
static int CalculatorPushChar(LogicCalculator *calculator, char data)
|
||||
{
|
||||
TRIGGER_CHECK(calculator != NULL, return -1, "Invalid param");
|
||||
TRIGGER_CHECK(calculator->endIndex < calculator->dataNumber, return -1, "More data for calculator support");
|
||||
TRIGGER_CHECK(sizeof(char) == calculator->dataUnit, return -1, "More data for calculator support");
|
||||
calculator->data[calculator->endIndex++] = data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int CalculatorPopChar(LogicCalculator *calculator, char *data)
|
||||
{
|
||||
TRIGGER_CHECK(calculator != NULL, return -1, "Invalid param");
|
||||
TRIGGER_CHECK(calculator->endIndex < calculator->dataNumber, return -1, "More data for calculator support");
|
||||
if (calculator->endIndex == 0) {
|
||||
return -1;
|
||||
}
|
||||
*data = calculator->data[--calculator->endIndex];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int CalculatorPush(LogicCalculator *calculator, void *data)
|
||||
{
|
||||
TRIGGER_CHECK(calculator != NULL, return -1, "Invalid param");
|
||||
TRIGGER_CHECK(calculator->endIndex < calculator->dataNumber, return -1, "More data for calculator support");
|
||||
char *tmpData = (calculator->data + calculator->dataUnit * calculator->endIndex);
|
||||
int ret = memcpy_s(tmpData, calculator->dataUnit, data, calculator->dataUnit);
|
||||
TRIGGER_CHECK(ret == 0, return -1, "Failed to copy logic data");
|
||||
calculator->endIndex++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int CalculatorPop(LogicCalculator *calculator, void *data)
|
||||
{
|
||||
TRIGGER_CHECK(calculator != NULL || data == NULL, return -1, "Invalid param");
|
||||
TRIGGER_CHECK(calculator->endIndex < calculator->dataNumber, return -1, "More data for calculator support");
|
||||
if (calculator->endIndex == 0) {
|
||||
return -1;
|
||||
}
|
||||
char *tmpData = calculator->data + calculator->dataUnit * (calculator->endIndex - 1);
|
||||
int ret = memcpy_s(data, calculator->dataUnit, tmpData, calculator->dataUnit);
|
||||
TRIGGER_CHECK(ret == 0, return -1, "Failed to copy logic data");
|
||||
calculator->endIndex--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int CalculatorLength(const LogicCalculator *calculator)
|
||||
{
|
||||
TRIGGER_CHECK(calculator != NULL, return 0, "Invalid param");
|
||||
return calculator->endIndex;
|
||||
}
|
||||
|
||||
static int PrefixAdd(char *prefix, u_int32_t *prefixIndex, u_int32_t prefixLen, char op)
|
||||
{
|
||||
if ((*prefixIndex + 3) >= prefixLen) {
|
||||
return -1;
|
||||
}
|
||||
prefix[(*prefixIndex)++] = ' ';
|
||||
prefix[(*prefixIndex)++] = op;
|
||||
prefix[(*prefixIndex)++] = ' ';
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int HandleOperationOr(LogicCalculator *calculator, char *prefix, u_int32_t *prefixIndex, u_int32_t prefixLen)
|
||||
{
|
||||
int ret = 0;
|
||||
char e;
|
||||
prefix[(*prefixIndex)++] = ' ';
|
||||
if(CalculatorLength(calculator) == 0) {
|
||||
CalculatorPushChar(calculator, '|');
|
||||
} else {
|
||||
do {
|
||||
CalculatorPopChar(calculator, &e);
|
||||
if (e == '(') {
|
||||
CalculatorPushChar(calculator, e);
|
||||
} else {
|
||||
ret = PrefixAdd(prefix, prefixIndex, prefixLen, e);
|
||||
TRIGGER_CHECK(ret == 0, return -1, "Invalid prefix");
|
||||
}
|
||||
} while (CalculatorLength(calculator) > 0 && e != '(');
|
||||
CalculatorPushChar(calculator, '|');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ComputeSubCondition(LogicCalculator *calculator, LogicData *data, const char *condition)
|
||||
{
|
||||
if (!LOGIC_DATA_TEST_FLAG(data, LOGIC_DATA_FLAGS_ORIGINAL)) {
|
||||
return LOGIC_DATA_TEST_FLAG(data, LOGIC_DATA_FLAGS_TRUE);
|
||||
}
|
||||
// 解析条件
|
||||
int ret = GetValueFromContent(condition + data->startIndex,
|
||||
data->endIndex - data->startIndex, 0, calculator->conditionName, SUPPORT_DATA_BUFFER_MAX);
|
||||
TRIGGER_CHECK(ret == 0, return -1, "Failed parse content name");
|
||||
ret = GetValueFromContent(condition + data->startIndex, data->endIndex - data->startIndex,
|
||||
strlen(calculator->conditionName) + 1, calculator->conditionContent, SUPPORT_DATA_BUFFER_MAX);
|
||||
TRIGGER_CHECK(ret == 0, return -1, "Failed parse content value");
|
||||
TRIGGER_LOGI("ComputeSubCondition subcondition \'%s\' \'%s\'",
|
||||
calculator->conditionName, calculator->conditionContent);
|
||||
|
||||
// check name
|
||||
if (strcmp(calculator->conditionName, calculator->inputName) == 0) {
|
||||
if (strcmp(calculator->conditionContent, "*") == 0) {
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(calculator->conditionContent, calculator->inputContent) == 0) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
u_int32_t len = SUPPORT_DATA_BUFFER_MAX;
|
||||
ret = SystemReadParameter(calculator->conditionName, calculator->readContent, &len);
|
||||
if (ret == 0 && strcmp(calculator->conditionContent, calculator->readContent) == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetValueFromContent(const char *content, u_int32_t contentSize, u_int32_t start, char *value, u_int32_t valueSize)
|
||||
{
|
||||
u_int32_t contentIndex = start;
|
||||
u_int32_t currIndex = 0;
|
||||
while (contentIndex < contentSize && currIndex < valueSize) {
|
||||
if (isspace(content[contentIndex])) {
|
||||
contentIndex++;
|
||||
continue;
|
||||
}
|
||||
if (content[contentIndex] == '=') {
|
||||
value[currIndex++] = '\0';
|
||||
return 0;
|
||||
}
|
||||
value[currIndex++] = content[contentIndex++];
|
||||
}
|
||||
if (currIndex < valueSize) {
|
||||
value[currIndex] = '\0';
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ComputeCondition(LogicCalculator *calculator, const char *condition)
|
||||
{
|
||||
u_int32_t currIndex = 0;
|
||||
u_int32_t start = 0;
|
||||
int noneOper = 1;
|
||||
CalculatorClear(calculator);
|
||||
LogicData data1 = {};
|
||||
LogicData data2 = {};
|
||||
while (currIndex < strlen(condition)) {
|
||||
if (condition[currIndex] == '|' || condition[currIndex] == '&') {
|
||||
noneOper = 0;
|
||||
int ret = CalculatorPop(calculator, (void*)&data2);
|
||||
ret |= CalculatorPop(calculator, (void*)&data1);
|
||||
TRIGGER_CHECK(ret == 0, return -1, "Failed to pop data");
|
||||
|
||||
ret = ComputeSubCondition(calculator, &data1, condition);
|
||||
data1.flags = 0;
|
||||
if (condition[currIndex] == '|' && ret == 1) {
|
||||
LOGIC_DATA_SET_FLAG(&data1, LOGIC_DATA_FLAGS_TRUE);
|
||||
} else if (condition[currIndex] == '|' || ret == 1) {
|
||||
if (ComputeSubCondition(calculator, &data2, condition) == 1) {
|
||||
LOGIC_DATA_SET_FLAG(&data1, LOGIC_DATA_FLAGS_TRUE);
|
||||
}
|
||||
}
|
||||
ret = CalculatorPush(calculator, (void*)&data1);
|
||||
TRIGGER_CHECK(ret == 0, return -1, "Failed to push data");
|
||||
start = currIndex + 1; // 跳过符号
|
||||
} else if (isspace(condition[currIndex])) {
|
||||
if (start == currIndex) {
|
||||
start = ++currIndex;
|
||||
continue;
|
||||
}
|
||||
data1.flags = LOGIC_DATA_FLAGS_ORIGINAL;
|
||||
data1.startIndex = start;
|
||||
data1.endIndex = currIndex;
|
||||
int ret = CalculatorPush(calculator, (void*)&data1);
|
||||
TRIGGER_CHECK(ret == 0, return -1, "Failed to push data");
|
||||
start = currIndex + 1;
|
||||
}
|
||||
currIndex++;
|
||||
}
|
||||
if (noneOper) {
|
||||
data1.flags = LOGIC_DATA_FLAGS_ORIGINAL;
|
||||
data1.startIndex = start;
|
||||
data1.endIndex = strlen(condition);
|
||||
} else {
|
||||
int ret = CalculatorPop(calculator, &data1);
|
||||
TRIGGER_CHECK(ret == 0, return -1, "Invalid calculator");
|
||||
}
|
||||
return ComputeSubCondition(calculator, &data1, condition);
|
||||
}
|
||||
|
||||
int ConvertInfixToPrefix(const char *condition, char *prefix, u_int32_t prefixLen)
|
||||
{
|
||||
char e;
|
||||
int ret = 0;
|
||||
u_int32_t curr = 0;
|
||||
u_int32_t prefixIndex = 0;
|
||||
LogicCalculator calculator;
|
||||
CalculatorInit(&calculator, 100, 1, 0);
|
||||
|
||||
while (curr < strlen(condition)) {
|
||||
if (condition[curr] == ')') {
|
||||
CalculatorPopChar(&calculator, &e);
|
||||
while (e != '(') {
|
||||
ret = PrefixAdd(prefix, &prefixIndex, prefixLen, e);
|
||||
TRIGGER_CHECK(ret == 0, CalculatorFree(&calculator); return -1, "Invalid prefix");
|
||||
ret = CalculatorPopChar(&calculator, &e);
|
||||
TRIGGER_CHECK(ret == 0, CalculatorFree(&calculator); return -1, "Invalid calculator");
|
||||
}
|
||||
} else if (condition[curr] == '|') {
|
||||
TRIGGER_CHECK(condition[curr + 1] == '|', CalculatorFree(&calculator); return -1, "Invalid condition");
|
||||
ret = HandleOperationOr(&calculator, prefix, &prefixIndex, prefixLen);
|
||||
TRIGGER_CHECK(ret == 0, CalculatorFree(&calculator); return -1, "Invalid prefix");
|
||||
curr++;
|
||||
} else if (condition[curr] == '&') {
|
||||
TRIGGER_CHECK(condition[curr + 1] == '&', CalculatorFree(&calculator); return -1, "Invalid condition");
|
||||
prefix[prefixIndex++] = ' ';
|
||||
CalculatorPushChar(&calculator, condition[curr]);
|
||||
curr++;
|
||||
} else if (condition[curr] == '(') {
|
||||
CalculatorPushChar(&calculator, condition[curr]);
|
||||
} else {
|
||||
prefix[prefixIndex++] = condition[curr];
|
||||
}
|
||||
curr++;
|
||||
TRIGGER_CHECK(prefixIndex < prefixLen, CalculatorFree(&calculator); return -1, "Invalid prefixIndex");
|
||||
}
|
||||
|
||||
while (CalculatorLength(&calculator) > 0) {
|
||||
CalculatorPopChar(&calculator, &e);
|
||||
ret = PrefixAdd(prefix, &prefixIndex, prefixLen, e);
|
||||
TRIGGER_CHECK(ret == 0, CalculatorFree(&calculator);
|
||||
return -1, "Invalid prefix %u %u", prefixIndex, prefixLen);
|
||||
}
|
||||
prefix[prefixIndex] = '\0';
|
||||
CalculatorFree(&calculator);
|
||||
return 0;
|
||||
}
|
68
services/trigger/trigger_checker.h
Executable file
68
services/trigger/trigger_checker.h
Executable file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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 STARTUP_TRIGER_CHECKER_H
|
||||
#define STARTUP_TRIGER_CHECKER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define SUPPORT_DATA_BUFFER_MAX 128
|
||||
#define CONDITION_EXTEND_LEN 32
|
||||
|
||||
#define LOGIC_DATA_FLAGS_ORIGINAL 0x1
|
||||
#define LOGIC_DATA_FLAGS_TRUE 0x08
|
||||
|
||||
#define LOGIC_DATA_TEST_FLAG(data, flag) (((data)->flags & flag) == (flag))
|
||||
#define LOGIC_DATA_SET_FLAG(data, flag) (data)->flags |= (flag)
|
||||
#define LOGIC_DATA_CLEAR_FLAG(data, flag) (data)->flags &= ~(flag)
|
||||
|
||||
typedef struct {
|
||||
u_int32_t flags;
|
||||
u_int32_t startIndex;
|
||||
u_int32_t endIndex;
|
||||
} LogicData;
|
||||
|
||||
typedef struct {
|
||||
int dataNumber;
|
||||
int endIndex;
|
||||
int dataUnit;
|
||||
char *conditionName;
|
||||
char *conditionContent;
|
||||
char *inputName;
|
||||
char *inputContent;
|
||||
char *readContent;
|
||||
char *data;
|
||||
} LogicCalculator;
|
||||
|
||||
int CalculatorInit(LogicCalculator *calculator, int dataNumber, int dataUnit, int needCondition);
|
||||
void CalculatorFree(LogicCalculator *calculator);
|
||||
int ConvertInfixToPrefix(const char *condition, char *prefix, u_int32_t prefixLen);
|
||||
int ComputeCondition(LogicCalculator *calculator, const char *condition);
|
||||
int GetValueFromContent(const char *content, u_int32_t contentSize, u_int32_t start, char *value, u_int32_t valueSize);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif // STARTUP_TRIGER_CHECKER_H
|
381
services/trigger/trigger_manager.c
Executable file
381
services/trigger/trigger_manager.c
Executable file
@ -0,0 +1,381 @@
|
||||
/*
|
||||
* 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 "trigger_manager.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "init_cmds.h"
|
||||
#include "init_utils.h"
|
||||
#include "trigger_checker.h"
|
||||
|
||||
#define TRIGGER_AREA_SPACE 1024*64
|
||||
#define TRIGGER_EXECUTE_QUEUE 64
|
||||
#define BUFFER_SIZE 256
|
||||
#define CHECK_INDEX_VALID(workSpace, index) \
|
||||
(u_int32_t)(index) < sizeof((workSpace)->header) / sizeof((workSpace)->header[0])
|
||||
|
||||
#ifdef STARTUP_LOCAL
|
||||
#define TRIGGER_PATH "/media/sf_ubuntu/test/__trigger__/trigger"
|
||||
#else
|
||||
#define TRIGGER_PATH "/dev/__trigger__/trigger"
|
||||
#endif
|
||||
|
||||
int InitTriggerWorkSpace(TriggerWorkSpace *workSpace)
|
||||
{
|
||||
TRIGGER_CHECK(workSpace != NULL, return -1, "Invalid parm");
|
||||
if (workSpace->area != NULL) {
|
||||
return 0;
|
||||
}
|
||||
CheckAndCreateDir(TRIGGER_PATH);
|
||||
int fd = open(TRIGGER_PATH, O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0444);
|
||||
TRIGGER_CHECK(fd >= 0, return -1, "Open file fail error %s", strerror(errno));
|
||||
lseek(fd, TRIGGER_AREA_SPACE, SEEK_SET);
|
||||
write(fd, "", 1);
|
||||
|
||||
void *areaAddr = (void *)mmap(NULL, TRIGGER_AREA_SPACE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
TRIGGER_CHECK(areaAddr != MAP_FAILED, close(fd); return -1,
|
||||
"Failed to map memory error %s", strerror(errno));
|
||||
close(fd);
|
||||
|
||||
// 第一部分做执行队列
|
||||
workSpace->executeQueue.executeQueue = (u_int32_t *)areaAddr;
|
||||
workSpace->executeQueue.queueCount = TRIGGER_EXECUTE_QUEUE;
|
||||
workSpace->executeQueue.startIndex = 0;
|
||||
workSpace->executeQueue.endIndex = 0;
|
||||
pthread_mutex_init(&workSpace->executeQueue.mutex, NULL);
|
||||
|
||||
// 动态数据保存
|
||||
workSpace->area = (TriggerArea *)(areaAddr + TRIGGER_EXECUTE_QUEUE * sizeof(u_int32_t));
|
||||
atomic_init(&workSpace->area->serial, ATOMIC_VAR_INIT(0));
|
||||
workSpace->area->dataSize = TRIGGER_AREA_SPACE - sizeof(TriggerArea) - TRIGGER_EXECUTE_QUEUE * sizeof(u_int32_t);
|
||||
workSpace->area->currOffset = sizeof(TriggerArea) + TRIGGER_EXECUTE_QUEUE * sizeof(u_int32_t);
|
||||
for (size_t i = 0; i < sizeof(workSpace->header) / sizeof(workSpace->header[0]); i++) {
|
||||
atomic_init(&workSpace->header[i].firstTrigger, ATOMIC_VAR_INIT(0));
|
||||
atomic_init(&workSpace->header[i].lastTrigger, ATOMIC_VAR_INIT(0));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static CommandNode *GetCmdByIndex(TriggerWorkSpace *workSpace, TriggerNode *trigger, u_int32_t index)
|
||||
{
|
||||
if (index == 0 || index == (u_int32_t)-1) {
|
||||
return NULL;
|
||||
}
|
||||
u_int32_t size = sizeof(CommandNode) + 2;
|
||||
TRIGGER_CHECK((index + size) < workSpace->area->dataSize,
|
||||
return NULL, "Invalid index for cmd %u", index);
|
||||
return (CommandNode *)(workSpace->area->data + index);
|
||||
}
|
||||
|
||||
static u_int32_t AddCommand(TriggerWorkSpace *workSpace, TriggerNode *trigger, const char *cmdName, const char *content)
|
||||
{
|
||||
TRIGGER_CHECK(workSpace != NULL && trigger != NULL, return 0, "list is null");
|
||||
TRIGGER_CHECK(content != NULL, return 0, "command is null");
|
||||
u_int32_t size = sizeof(CommandNode) + strlen(cmdName) + 1;
|
||||
size += (content == NULL) ? 1 : strlen(content) + 1;
|
||||
TRIGGER_CHECK((workSpace->area->currOffset + size) < workSpace->area->dataSize,
|
||||
return 0, "Not enough memory for cmd %u %u", size, workSpace->area->currOffset);
|
||||
|
||||
CommandNode *node = (CommandNode *)(workSpace->area->data + workSpace->area->currOffset);
|
||||
TRIGGER_CHECK(node != NULL, return 0, "Failed to alloc memory for command");
|
||||
|
||||
int ret = memcpy_s(node->name, sizeof(node->name) - 1, cmdName, strlen(cmdName));
|
||||
TRIGGER_CHECK(ret == 0, return 0, "Failed to copy command");
|
||||
node->name[strlen(cmdName)] = '\0';
|
||||
if (content != NULL) {
|
||||
ret = memcpy_s(node->content, size, content, strlen(content));
|
||||
node->content[strlen(content)] = '\0';
|
||||
TRIGGER_CHECK(ret == 0, return 0, "Failed to copy command");
|
||||
} else {
|
||||
node->content[0] = '\0';
|
||||
}
|
||||
|
||||
u_int32_t offset = workSpace->area->currOffset;
|
||||
atomic_init(&node->next, ATOMIC_VAR_INIT(0));
|
||||
// 插入队列
|
||||
if (trigger->firstCmd == 0) {
|
||||
atomic_store_explicit(&trigger->firstCmd, offset, memory_order_release);
|
||||
atomic_store_explicit(&trigger->lastCmd, offset, memory_order_release);
|
||||
} else {
|
||||
CommandNode *lastNode = GetCmdByIndex(workSpace, trigger, trigger->lastCmd);
|
||||
if (lastNode != NULL) {
|
||||
atomic_store_explicit(&lastNode->next, offset, memory_order_release);
|
||||
}
|
||||
atomic_store_explicit(&trigger->lastCmd, offset, memory_order_release);
|
||||
}
|
||||
workSpace->area->currOffset += size;
|
||||
return offset;
|
||||
}
|
||||
|
||||
static TriggerNode *GetTriggerByIndex(TriggerWorkSpace *workSpace, u_int32_t index)
|
||||
{
|
||||
if (index == 0 || index == (u_int32_t)-1) {
|
||||
return NULL;
|
||||
}
|
||||
u_int32_t size = sizeof(TriggerNode) + 1;
|
||||
TRIGGER_CHECK((index + size) < workSpace->area->dataSize,
|
||||
return NULL, "Invalid index for trigger %u", index);
|
||||
return (TriggerNode *)(workSpace->area->data + index);
|
||||
}
|
||||
|
||||
static u_int32_t AddTrigger(TriggerWorkSpace *workSpace, int type, const char *name, const char *condition)
|
||||
{
|
||||
TRIGGER_CHECK(workSpace != NULL && name != NULL, return 0, "list is null");
|
||||
const char *tmpCond = condition;
|
||||
if (type == TRIGGER_BOOT && condition == NULL) {
|
||||
tmpCond = name;
|
||||
}
|
||||
u_int32_t conditionSize = (tmpCond == NULL) ? 1 : strlen(tmpCond) + 1 + CONDITION_EXTEND_LEN;
|
||||
TRIGGER_CHECK((workSpace->area->currOffset + sizeof(TriggerNode) + conditionSize) < workSpace->area->dataSize,
|
||||
return -1, "Not enough memory for cmd");
|
||||
|
||||
TriggerNode *node = (TriggerNode *)(workSpace->area->data + workSpace->area->currOffset);
|
||||
TRIGGER_CHECK(node != NULL, return 0, "Failed to alloc memory for trigger");
|
||||
node->type = type;
|
||||
int ret = memcpy_s(node->name, sizeof(node->name) - 1, name, strlen(name));
|
||||
TRIGGER_CHECK(ret == 0, return 0, "Failed to memcpy_s for trigger");
|
||||
node->name[strlen(name)] = '\0';
|
||||
|
||||
if (tmpCond != NULL) {
|
||||
if (type == TRIGGER_PROPERTY) {
|
||||
ret = ConvertInfixToPrefix(tmpCond, node->condition, conditionSize);
|
||||
TRIGGER_CHECK(ret == 0, return 0, "Failed to memcpy_s for trigger");
|
||||
} else {
|
||||
ret = memcpy_s(node->condition, strlen(tmpCond) + 1, tmpCond, strlen(tmpCond));
|
||||
TRIGGER_CHECK(ret == 0, return 0, "Failed to memcpy_s for trigger");
|
||||
node->condition[strlen(tmpCond)] = '\0';
|
||||
}
|
||||
} else {
|
||||
node->condition[0] = '\0';
|
||||
}
|
||||
|
||||
u_int32_t offset = workSpace->area->currOffset;
|
||||
atomic_init(&node->serial, ATOMIC_VAR_INIT(0));
|
||||
atomic_init(&node->next, ATOMIC_VAR_INIT(0));
|
||||
atomic_init(&node->firstCmd, ATOMIC_VAR_INIT(0));
|
||||
atomic_init(&node->lastCmd, ATOMIC_VAR_INIT(0));
|
||||
|
||||
// 插入到trigger队列中
|
||||
if (workSpace->header[type].firstTrigger == 0) {
|
||||
atomic_store_explicit(&workSpace->header[type].firstTrigger, offset, memory_order_release);
|
||||
atomic_store_explicit(&workSpace->header[type].lastTrigger, offset, memory_order_release);
|
||||
} else {
|
||||
TriggerNode *lastNode = GetTriggerByIndex(workSpace, workSpace->header[type].lastTrigger);
|
||||
if (lastNode != NULL) {
|
||||
atomic_store_explicit(&lastNode->next, offset, memory_order_release);
|
||||
}
|
||||
atomic_store_explicit(&workSpace->header[type].lastTrigger, offset, memory_order_release);
|
||||
}
|
||||
workSpace->area->currOffset += conditionSize + sizeof(TriggerNode);
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int GetTriggerIndex(const char *type)
|
||||
{
|
||||
if (strncmp("property", type, strlen("property")) == 0) {
|
||||
return TRIGGER_PROPERTY;
|
||||
}
|
||||
static const char *triggerType[] = {
|
||||
"boot", "early-init", "init", "early-init", "late-init",
|
||||
"early-fs", "post-fs", "late-fs", "post-fs-data",
|
||||
"nonencrypted",
|
||||
"firmware_mounts_complete",
|
||||
"load_persist_props_action"
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(triggerType) / sizeof(char*); i++) {
|
||||
if (strncmp(triggerType[i], type, strlen(triggerType[i])) == 0) {
|
||||
return TRIGGER_BOOT;
|
||||
}
|
||||
}
|
||||
return TRIGGER_UNKNOW;
|
||||
}
|
||||
|
||||
static int CheckBootTriggerMatch(TriggerNode *trigger, void *content, u_int32_t contentSize)
|
||||
{
|
||||
if (strncmp(trigger->name, (char *)content, contentSize) == 0) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ParseTrigger(TriggerWorkSpace *workSpace, cJSON *triggerItem)
|
||||
{
|
||||
TRIGGER_CHECK(triggerItem != NULL, return -1, "Invalid file");
|
||||
TRIGGER_CHECK(workSpace != NULL, return -1, "Failed to create trigger list");
|
||||
|
||||
char *name = cJSON_GetStringValue(cJSON_GetObjectItem(triggerItem, "name"));
|
||||
TRIGGER_CHECK(name != NULL, return -1, "Can not get name from cfg");
|
||||
char *condition = cJSON_GetStringValue(cJSON_GetObjectItem(triggerItem, "condition"));
|
||||
|
||||
int index = GetTriggerIndex(name);
|
||||
TRIGGER_CHECK(CHECK_INDEX_VALID(workSpace, index), return -1, "Failed to get trigger index");
|
||||
|
||||
u_int32_t offset = AddTrigger(workSpace, index, name, condition);
|
||||
//TRIGGER_LOGE("AddTrigger %u %s %u", offset, name, workSpace->area->currOffset);
|
||||
TRIGGER_CHECK(offset > 0, return -1, "Failed to create trigger %s", name);
|
||||
TriggerNode *trigger = GetTriggerByIndex(workSpace, offset);
|
||||
|
||||
// 添加命令行
|
||||
cJSON* cmdItems = cJSON_GetObjectItem(triggerItem, CMDS_ARR_NAME_IN_JSON);
|
||||
TRIGGER_CHECK(cJSON_IsArray(cmdItems), return -1, "Command item must be array");
|
||||
int cmdLinesCnt = cJSON_GetArraySize(cmdItems);
|
||||
TRIGGER_CHECK(cmdLinesCnt > 0, return -1, "Command array size must positive");
|
||||
|
||||
for (int i = 0; i < cmdLinesCnt; ++i) {
|
||||
char *cmdLineStr = cJSON_GetStringValue(cJSON_GetArrayItem(cmdItems, i));
|
||||
TRIGGER_CHECK(cmdLinesCnt > 0, continue, "Command is null");
|
||||
|
||||
size_t cmdLineLen = strlen(cmdLineStr);
|
||||
const char *matchCmd = GetMatchCmd(cmdLineStr);
|
||||
if (matchCmd == NULL && strncmp(cmdLineStr, TRIGGER_CMD, strlen(TRIGGER_CMD)) == 0) {
|
||||
matchCmd = TRIGGER_CMD;
|
||||
}
|
||||
TRIGGER_CHECK(matchCmd != NULL, continue, "Command not support %s", cmdLineStr);
|
||||
size_t matchLen = strlen(matchCmd);
|
||||
if (matchLen == cmdLineLen) {
|
||||
offset = AddCommand(workSpace, trigger, matchCmd, NULL);
|
||||
} else {
|
||||
offset = AddCommand(workSpace, trigger, matchCmd, cmdLineStr + matchLen);
|
||||
}
|
||||
//TRIGGER_LOGE("AddCommand %u %s %u", offset, cmdLineStr, workSpace->area->currOffset);
|
||||
TRIGGER_CHECK(offset > 0, continue, "Failed to add command %s", cmdLineStr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ExecuteTrigger(TriggerWorkSpace *workSpace, TriggerNode *trigger, CMD_EXECUTE cmdExecuter)
|
||||
{
|
||||
TRIGGER_CHECK(workSpace != NULL && trigger != NULL && cmdExecuter != NULL, return -1, "Invalid param");
|
||||
TRIGGER_LOGI("ExecuteCmds trigger %s", trigger->name);
|
||||
CommandNode *cmd = GetCmdByIndex(workSpace, trigger, trigger->firstCmd);
|
||||
while (cmd != NULL) {
|
||||
cmdExecuter(trigger, cmd->name, cmd->content);
|
||||
cmd = GetCmdByIndex(workSpace, trigger, cmd->next);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ExecuteQueuePush(TriggerWorkSpace *workSpace, TriggerNode *trigger, u_int32_t triggerIndex)
|
||||
{
|
||||
TRIGGER_CHECK(workSpace != NULL, return -1, "Invalid area");
|
||||
pthread_mutex_lock(&workSpace->executeQueue.mutex);
|
||||
u_int32_t index = workSpace->executeQueue.endIndex++ % workSpace->executeQueue.queueCount;
|
||||
workSpace->executeQueue.executeQueue[index] = triggerIndex;
|
||||
pthread_mutex_unlock(&workSpace->executeQueue.mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
TriggerNode *ExecuteQueuePop(TriggerWorkSpace *workSpace)
|
||||
{
|
||||
if (workSpace->executeQueue.endIndex <= workSpace->executeQueue.startIndex) {
|
||||
return NULL;
|
||||
}
|
||||
pthread_mutex_lock(&workSpace->executeQueue.mutex);
|
||||
u_int32_t currIndex = workSpace->executeQueue.startIndex % workSpace->executeQueue.queueCount;
|
||||
u_int32_t triggerIndex = workSpace->executeQueue.executeQueue[currIndex];
|
||||
workSpace->executeQueue.executeQueue[currIndex] = 0;
|
||||
workSpace->executeQueue.startIndex++;
|
||||
pthread_mutex_unlock(&workSpace->executeQueue.mutex);
|
||||
return GetTriggerByIndex(workSpace, triggerIndex);
|
||||
}
|
||||
|
||||
int ExecuteQueueSize(TriggerWorkSpace *workSpace)
|
||||
{
|
||||
TRIGGER_CHECK(workSpace != NULL, return 0, "Invalid param");
|
||||
return workSpace->executeQueue.endIndex - workSpace->executeQueue.startIndex;
|
||||
}
|
||||
|
||||
int CheckTrigger(TriggerWorkSpace *workSpace,
|
||||
int type, void *content, u_int32_t contentSize, TRIGGER_CHECK_DONE triggerExecuter)
|
||||
{
|
||||
static TRIGGER_MATCH triggerCheckMatch[TRIGGER_MAX] = {
|
||||
CheckBootTriggerMatch, NULL, NULL
|
||||
};
|
||||
TRIGGER_LOGI("ExecuteTrigger check content %s", (char*)content);
|
||||
TRIGGER_CHECK(workSpace != NULL, return -1, "Trigger not init");
|
||||
TRIGGER_CHECK(CHECK_INDEX_VALID(workSpace, type), return -1, "Invalid type %d", type);
|
||||
TRIGGER_CHECK((u_int32_t)type < sizeof(triggerCheckMatch) / sizeof(triggerCheckMatch[0]),
|
||||
return -1, "Failed to get check function");
|
||||
TRIGGER_CHECK(triggerCheckMatch[type] != NULL, return 0, "Failed to get check function");
|
||||
u_int32_t index = workSpace->header[type].firstTrigger;
|
||||
TriggerNode *trigger = GetTriggerByIndex(workSpace, workSpace->header[type].firstTrigger);
|
||||
while (trigger != NULL) {
|
||||
if (triggerCheckMatch[type](trigger, content, contentSize) == 1) { // 等于1 则认为匹配
|
||||
triggerExecuter(trigger, index);
|
||||
}
|
||||
index = trigger->next;
|
||||
trigger = GetTriggerByIndex(workSpace, trigger->next);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CheckPropertyTrigger(TriggerWorkSpace *workSpace,
|
||||
const char *content, u_int32_t contentSize, TRIGGER_CHECK_DONE triggerExecuter)
|
||||
{
|
||||
TRIGGER_CHECK(workSpace != NULL && content != NULL && triggerExecuter != NULL,
|
||||
return -1, "Failed arg for property trigger");
|
||||
LogicCalculator calculator;
|
||||
CalculatorInit(&calculator, 100, sizeof(LogicData), 1);
|
||||
|
||||
// 先解析content
|
||||
int ret = GetValueFromContent(content, contentSize, 0, calculator.inputName, SUPPORT_DATA_BUFFER_MAX);
|
||||
TRIGGER_CHECK(ret == 0, CalculatorFree(&calculator); return -1, "Failed parse content name");
|
||||
ret = GetValueFromContent(content, contentSize,
|
||||
strlen(calculator.inputName) + 1, calculator.inputContent, SUPPORT_DATA_BUFFER_MAX);
|
||||
TRIGGER_CHECK(ret == 0, CalculatorFree(&calculator); return -1, "Failed parse content value");
|
||||
TRIGGER_LOGI("CheckPropertyTrigger content %s ", content);
|
||||
|
||||
u_int32_t index = workSpace->header[TRIGGER_PROPERTY].firstTrigger;
|
||||
TriggerNode *trigger = GetTriggerByIndex(workSpace, workSpace->header[TRIGGER_PROPERTY].firstTrigger);
|
||||
while (trigger != NULL) {
|
||||
TRIGGER_LOGI("CheckPropertyTrigger name:%s condition \'%s\' ", trigger->name, trigger->condition);
|
||||
ret = ComputeCondition(&calculator, trigger->condition);
|
||||
if (ret == 1) {
|
||||
triggerExecuter(trigger, index);
|
||||
}
|
||||
index = trigger->next;
|
||||
trigger = GetTriggerByIndex(workSpace, trigger->next);
|
||||
}
|
||||
CalculatorFree(&calculator);
|
||||
return 0;
|
||||
}
|
||||
|
||||
TriggerNode *GetTriggerByName(TriggerWorkSpace *workSpace, const char *triggerName, u_int32_t *triggerIndex)
|
||||
{
|
||||
TRIGGER_CHECK(workSpace != NULL && triggerName != NULL, return NULL, "Invalid param");
|
||||
for (size_t i = 0; i < sizeof(workSpace->header) / sizeof(workSpace->header[0]); i++) {
|
||||
u_int32_t index = workSpace->header[i].firstTrigger;
|
||||
TriggerNode *trigger = GetTriggerByIndex(workSpace, workSpace->header[i].firstTrigger);
|
||||
while (trigger != NULL) {
|
||||
if (strcmp(triggerName, trigger->name) == 0) {
|
||||
*triggerIndex = index;
|
||||
return trigger;
|
||||
}
|
||||
index = trigger->next;
|
||||
trigger = GetTriggerByIndex(workSpace, trigger->next);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
147
services/trigger/trigger_manager.h
Executable file
147
services/trigger/trigger_manager.h
Executable file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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 STARTUP_TRIGER_MANAGER_H
|
||||
#define STARTUP_TRIGER_MANAGER_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "cJSON.h"
|
||||
#include "init_log.h"
|
||||
#include "list.h"
|
||||
#include "property_service.h"
|
||||
#include "securec.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define TRIGGER_LOGI(fmt, ...) STARTUP_LOGI("Trigger", fmt, ##__VA_ARGS__)
|
||||
#define TRIGGER_LOGE(fmt, ...) STARTUP_LOGE("Trigger", fmt, ##__VA_ARGS__)
|
||||
|
||||
#define TRIGGER_CHECK(retCode, exper, ...) \
|
||||
if (!(retCode)) { \
|
||||
TRIGGER_LOGE(__VA_ARGS__); \
|
||||
exper; \
|
||||
}
|
||||
|
||||
#define COND_STACK_SIZE 20
|
||||
#define TRIGGER_CMD "trigger "
|
||||
#define TRIGGER_ARR_NAME_IN_JSON "jobs"
|
||||
#define CMDS_ARR_NAME_IN_JSON "cmds"
|
||||
|
||||
typedef struct {
|
||||
char data[COND_STACK_SIZE];
|
||||
int top;
|
||||
} CONDITION_STACK;
|
||||
|
||||
/*
|
||||
on boot
|
||||
exec /system/bin/sleep 4
|
||||
start telephony_sa
|
||||
*/
|
||||
typedef enum {
|
||||
TRIGGER_BOOT = 0,
|
||||
TRIGGER_PROPERTY,
|
||||
TRIGGER_UNKNOW,
|
||||
TRIGGER_MAX
|
||||
}TriggerType;
|
||||
|
||||
#define MAX_TRIGGER_CMD_NAME_LEN 16
|
||||
#define MAX_TRIGGER_NAME_LEN 64
|
||||
#define MAX_TRIGGER_TYPE_LEN 16
|
||||
|
||||
// Command对象列表,主要存储每个triger需要执行那些Command操作。
|
||||
typedef struct CommandNode {
|
||||
atomic_uint_least32_t next;
|
||||
char name[MAX_TRIGGER_CMD_NAME_LEN];
|
||||
char content[0];
|
||||
} CommandNode;
|
||||
|
||||
typedef struct {
|
||||
atomic_uint_least32_t serial;
|
||||
atomic_uint_least32_t next;
|
||||
atomic_uint_least32_t firstCmd;
|
||||
atomic_uint_least32_t lastCmd;
|
||||
int type;
|
||||
char name[MAX_TRIGGER_NAME_LEN];
|
||||
char condition[0];
|
||||
} TriggerNode;
|
||||
|
||||
typedef struct {
|
||||
atomic_uint_least32_t serial;
|
||||
u_int32_t dataSize;
|
||||
u_int32_t startSize;
|
||||
u_int32_t currOffset;
|
||||
char data[0];
|
||||
} TriggerArea;
|
||||
|
||||
typedef struct {
|
||||
atomic_uint_least32_t firstTrigger;
|
||||
atomic_uint_least32_t lastTrigger;
|
||||
} TriggerHeader;
|
||||
|
||||
typedef struct {
|
||||
u_int32_t *executeQueue;
|
||||
u_int32_t queueCount;
|
||||
u_int32_t startIndex;
|
||||
u_int32_t endIndex;
|
||||
pthread_mutex_t mutex;
|
||||
} TriggerExecuteQueue;
|
||||
|
||||
typedef struct TriggerWorkSpace {
|
||||
TriggerExecuteQueue executeQueue;
|
||||
TriggerHeader header[TRIGGER_MAX];
|
||||
TriggerArea *area;
|
||||
} TriggerWorkSpace;
|
||||
|
||||
int InitTriggerWorkSpace(TriggerWorkSpace *workSpace);
|
||||
int ParseTrigger(TriggerWorkSpace *workSpace, cJSON *triggerItem);
|
||||
|
||||
typedef int (*TRIGGER_MATCH)(TriggerNode *trigger, void *content, u_int32_t contentSize);
|
||||
typedef int (*TRIGGER_CHECK_DONE) (TriggerNode *trigger, u_int32_t index);
|
||||
typedef int (*CMD_EXECUTE) (TriggerNode *trigger, const char *cmdName, const char *command);
|
||||
|
||||
TriggerNode *GetTriggerByName(TriggerWorkSpace *workSpace, const char *triggerName, u_int32_t *triggerIndex);
|
||||
int ExecuteTrigger(TriggerWorkSpace *workSpace, TriggerNode *trigger, CMD_EXECUTE cmdExecuter);
|
||||
int CheckTrigger(TriggerWorkSpace *workSpace,
|
||||
int type, void *content, u_int32_t contentSize, TRIGGER_CHECK_DONE triggerExecuter);
|
||||
int CheckPropertyTrigger(TriggerWorkSpace *workSpace,
|
||||
const char *content, u_int32_t contentSize, TRIGGER_CHECK_DONE triggerExecuter);
|
||||
|
||||
TriggerNode *ExecuteQueuePop(TriggerWorkSpace *workSpace);
|
||||
int ExecuteQueuePush(TriggerWorkSpace *workSpace, TriggerNode *trigger, u_int32_t index);
|
||||
int ExecuteQueueSize(TriggerWorkSpace *workSpace);
|
||||
|
||||
#define TRIGGER_NODE_IN_QUEUE(trigger) \
|
||||
(atomic_load_explicit(&(trigger)->serial, memory_order_relaxed) & 0x01)
|
||||
#define TRIGGER_NODE_SET_QUEUE_FLAG(trigger) \
|
||||
atomic_store_explicit(&(trigger)->serial, (trigger)->serial | 0x01, memory_order_relaxed)
|
||||
#define TRIGGER_NODE_CLEAR_QUEUE_FLAG(trigger) \
|
||||
atomic_store_explicit(&(trigger)->serial, (trigger)->serial & ~0x01, memory_order_relaxed)
|
||||
|
||||
TriggerWorkSpace *GetTriggerWorkSpace();
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif // STARTUP_TRIGER_MANAGER_H
|
225
services/trigger/trigger_processor.c
Executable file
225
services/trigger/trigger_processor.c
Executable file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* 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 "trigger_processor.h"
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "init_cmds.h"
|
||||
#include "property_manager.h"
|
||||
#include "trigger_checker.h"
|
||||
#include "uv.h"
|
||||
|
||||
#define SYS_POWER_CTRL "sys.powerctrl."
|
||||
static int g_triggerServiceStart = 0;
|
||||
static TriggerWorkSpace g_triggerWorkSpace = {};
|
||||
|
||||
static int DoCmdExecute(TriggerNode *trigger, const char *cmdName, const char *command)
|
||||
{
|
||||
TRIGGER_CHECK(trigger != NULL && cmdName != NULL && command != NULL, return -1, "Invalid param");
|
||||
if (strncmp(cmdName, TRIGGER_CMD, strlen(TRIGGER_CMD)) == 0) {
|
||||
u_int32_t triggerIndex = 0;
|
||||
TriggerNode *node = GetTriggerByName(&g_triggerWorkSpace, command, &triggerIndex);
|
||||
if (node != NULL && !TRIGGER_NODE_IN_QUEUE(node)) { // 不在队列中
|
||||
TRIGGER_LOGI("DoCmdExecute trigger %s", node->name);
|
||||
TRIGGER_NODE_SET_QUEUE_FLAG(node);
|
||||
ExecuteQueuePush(&g_triggerWorkSpace, node, triggerIndex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
TRIGGER_LOGI("DoCmdExecute trigger %s cmd %s", trigger->name, cmdName);
|
||||
DoCmdByName(cmdName, command);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int DoTiggerCheckResult(TriggerNode *trigger, u_int32_t triggerIndex)
|
||||
{
|
||||
// 直接执行,不需要添加队列
|
||||
if (!g_triggerServiceStart) {
|
||||
TRIGGER_LOGI("DoTiggerExecute trigger %s", trigger->name);
|
||||
ExecuteTrigger(&g_triggerWorkSpace, trigger, DoCmdExecute);
|
||||
TRIGGER_NODE_CLEAR_QUEUE_FLAG(trigger);
|
||||
}
|
||||
|
||||
// 已经在队列中了,则不执行 TODO
|
||||
if (TRIGGER_NODE_IN_QUEUE(trigger)) {
|
||||
TRIGGER_LOGI("DoTiggerExecute trigger %s has been waiting execute", trigger->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (trigger->type == TRIGGER_BOOT) { // 立刻执行
|
||||
TRIGGER_LOGI("DoTiggerExecute trigger %s", trigger->name);
|
||||
ExecuteTrigger(&g_triggerWorkSpace, trigger, DoCmdExecute);
|
||||
TRIGGER_NODE_CLEAR_QUEUE_FLAG(trigger);
|
||||
} else {
|
||||
TRIGGER_NODE_SET_QUEUE_FLAG(trigger);
|
||||
TRIGGER_LOGI("DoTiggerExecute trigger %s", trigger->name);
|
||||
ExecuteQueuePush(&g_triggerWorkSpace, trigger, triggerIndex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ExecuteQueueWork()
|
||||
{
|
||||
int executeCount = 0;
|
||||
TriggerNode *trigger = ExecuteQueuePop(&g_triggerWorkSpace);
|
||||
while (trigger != NULL) {
|
||||
ExecuteTrigger(&g_triggerWorkSpace, trigger, DoCmdExecute);
|
||||
TRIGGER_NODE_CLEAR_QUEUE_FLAG(trigger);
|
||||
executeCount++;
|
||||
if (executeCount > 5) {
|
||||
break;
|
||||
}
|
||||
trigger = ExecuteQueuePop(&g_triggerWorkSpace);
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckTriggers(int type, void *content, u_int32_t contentLen)
|
||||
{
|
||||
switch (type) {
|
||||
case EVENT_PROPERTY: {
|
||||
CheckPropertyTrigger(&g_triggerWorkSpace, content, contentLen, DoTiggerCheckResult);
|
||||
break;
|
||||
}
|
||||
case EVENT_BOOT: {
|
||||
CheckTrigger(&g_triggerWorkSpace, TRIGGER_BOOT, content, contentLen, DoTiggerCheckResult);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
TRIGGER_LOGI("CheckTriggers: %d", type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ProcessAfterEvent(uv_work_t *req, int status)
|
||||
{
|
||||
free(req);
|
||||
ExecuteQueueWork();
|
||||
}
|
||||
|
||||
static void ProcessEvent(uv_work_t *req)
|
||||
{
|
||||
TriggerDataEvent *event = (TriggerDataEvent *)req;
|
||||
CheckTriggers(event->type, event->content, event->contentSize);
|
||||
}
|
||||
|
||||
static const char *GetCmdInfo(const char *content, u_int32_t contentSize, char **cmdParam)
|
||||
{
|
||||
char cmd[MAX_CMD_NAME_LEN + 1] = { 0 };
|
||||
int ret = GetValueFromContent(content, contentSize, 0, cmd, sizeof(cmd));
|
||||
TRIGGER_CHECK(ret == 0, return NULL, "Failed parse cmd");
|
||||
u_int32_t cmdLen = strlen(cmd);
|
||||
TRIGGER_CHECK(cmdLen < MAX_CMD_NAME_LEN, return NULL, "Failed parse cmd");
|
||||
cmd[cmdLen] = ' ';
|
||||
cmd[cmdLen + 1] = '\0';
|
||||
*cmdParam = content + cmdLen + 1;
|
||||
return GetMatchCmd(cmd);
|
||||
}
|
||||
|
||||
static void SendTriggerEvent(TriggerDataEvent *event)
|
||||
{
|
||||
int ctrlSize = strlen(SYS_POWER_CTRL);
|
||||
if (strncmp(event->content, SYS_POWER_CTRL, ctrlSize) == 0) {
|
||||
char *cmdParam = NULL;
|
||||
const char *matchCmd = GetCmdInfo(event->content + ctrlSize, event->contentSize - ctrlSize, &cmdParam);
|
||||
if (matchCmd != NULL) {
|
||||
DoCmdByName(matchCmd, cmdParam);
|
||||
} else {
|
||||
TRIGGER_LOGE("SendTriggerEvent cmd %s not found", event->content);
|
||||
}
|
||||
free(event);
|
||||
return;
|
||||
}
|
||||
if (event->type == EVENT_BOOT || g_triggerServiceStart == 0) {
|
||||
CheckTriggers(EVENT_PROPERTY, event->content, event->contentSize);
|
||||
free(event);
|
||||
} else {
|
||||
uv_queue_work(uv_default_loop(), &event->request, ProcessEvent, ProcessAfterEvent);
|
||||
}
|
||||
}
|
||||
|
||||
void PostPropertyTrigger(const char *name, const char *value)
|
||||
{
|
||||
TRIGGER_CHECK(name != NULL && value != NULL, return, "Invalid param");
|
||||
TRIGGER_LOGI("PostPropertyTrigger %s ", name);
|
||||
int contentLen = strlen(name) + strlen(value) + 2;
|
||||
TriggerDataEvent *event = (TriggerDataEvent *)malloc(sizeof(TriggerDataEvent) + contentLen);
|
||||
TRIGGER_CHECK(event != NULL, return, "Failed to alloc memory");
|
||||
event->type = EVENT_PROPERTY;
|
||||
event->request.data = (char*)event + sizeof(uv_work_t);
|
||||
event->contentSize = BuildPropertyContent(event->content, contentLen, name, value);
|
||||
TRIGGER_CHECK(event->contentSize > 0, return, "Failed to copy porperty");
|
||||
SendTriggerEvent(event);
|
||||
TRIGGER_LOGI("PostPropertyTrigger %s success", name);
|
||||
}
|
||||
|
||||
void PostTrigger(EventType type, void *content, u_int32_t contentLen)
|
||||
{
|
||||
TRIGGER_LOGI("PostTrigger %d", type);
|
||||
TRIGGER_CHECK(content != NULL && contentLen > 0, return, "Invalid param");
|
||||
if (type == EVENT_BOOT || g_triggerServiceStart == 0) {
|
||||
CheckTriggers(type, content, contentLen);
|
||||
} else {
|
||||
TriggerDataEvent *event = (TriggerDataEvent *)malloc(sizeof(TriggerDataEvent) + contentLen + 1);
|
||||
TRIGGER_CHECK(event != NULL, return, "Failed to alloc memory");
|
||||
event->type = type;
|
||||
event->request.data = (char*)event + sizeof(uv_work_t);
|
||||
event->contentSize = contentLen;
|
||||
memcpy_s(event->content, contentLen, content, contentLen);
|
||||
event->content[contentLen] = '\0';
|
||||
SendTriggerEvent(event);
|
||||
}
|
||||
TRIGGER_LOGI("PostTrigger %d success", type);
|
||||
}
|
||||
|
||||
void StartTriggerService()
|
||||
{
|
||||
TRIGGER_LOGI("StartTriggerService ");
|
||||
g_triggerServiceStart = 1;
|
||||
}
|
||||
|
||||
int ParseTriggerConfig(cJSON *fileRoot)
|
||||
{
|
||||
TRIGGER_CHECK(fileRoot != NULL, return -1, "Invalid file");
|
||||
int ret = InitTriggerWorkSpace(&g_triggerWorkSpace);
|
||||
TRIGGER_CHECK(ret == 0, return -1, "Failed to init trigger");
|
||||
|
||||
cJSON *triggers = cJSON_GetObjectItemCaseSensitive(fileRoot, TRIGGER_ARR_NAME_IN_JSON);
|
||||
TRIGGER_CHECK(cJSON_IsArray(triggers), return -1, "Trigger item must array");
|
||||
|
||||
int size = cJSON_GetArraySize(triggers);
|
||||
TRIGGER_CHECK(size > 0, return -1, "Trigger array size must positive");
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
cJSON *item = cJSON_GetArrayItem(triggers, i);
|
||||
ParseTrigger(&g_triggerWorkSpace, item);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DoTriggerExec(const char *content)
|
||||
{
|
||||
TRIGGER_CHECK(content != NULL, return, "Invalid trigger content");
|
||||
u_int32_t triggerIndex = 0;
|
||||
TriggerNode *trigger = GetTriggerByName(&g_triggerWorkSpace, content, &triggerIndex);
|
||||
if (trigger != NULL) {
|
||||
ExecuteTrigger(&g_triggerWorkSpace, trigger, DoCmdExecute);
|
||||
}
|
||||
}
|
||||
|
||||
TriggerWorkSpace *GetTriggerWorkSpace()
|
||||
{
|
||||
return &g_triggerWorkSpace;
|
||||
}
|
54
services/trigger/trigger_processor.h
Executable file
54
services/trigger/trigger_processor.h
Executable file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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_EVENT_MANAGER_H
|
||||
#define BASE_STARTUP_EVENT_MANAGER_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "property.h"
|
||||
#include "trigger.h"
|
||||
#include "trigger_manager.h"
|
||||
#include "uv.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef struct TriggerEvent {
|
||||
uv_work_t request;
|
||||
EventType type;
|
||||
} TriggerEvent;
|
||||
|
||||
typedef struct {
|
||||
uv_work_t request;
|
||||
EventType type;
|
||||
u_int32_t contentSize;
|
||||
char content[0];
|
||||
} TriggerDataEvent;
|
||||
|
||||
typedef struct TriggerExecute {
|
||||
TriggerEvent event;
|
||||
TriggerNode *trigger;
|
||||
} TriggerExecute;
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user