diff --git a/initsync/BUILD.gn b/initsync/BUILD.gn index 86b0ad0703058e33e629ee37434573bf07ead162..2a2d1f2613058391fb3878cfdaec9ca17e5363c2 100644 --- a/initsync/BUILD.gn +++ b/initsync/BUILD.gn @@ -18,21 +18,32 @@ lite_component("initsync") { } shared_library("libinitsync_shared") { - sources = [ "src/init_sync.c" ] + sources = [ + "src/init_sync.c", + ] cflags = [ "-Wall" ] include_dirs = [ "//base/startup/init_lite/initsync/include", "//base/startup/init_lite/interfaces/kits", + "//base/startup/init_lite/services/log", + ] + public_deps = [ + "//base/startup/init_lite/services/log:init_log", + "//third_party/bounds_checking_function:libsec_shared", ] - public_deps = [ "//third_party/bounds_checking_function:libsec_shared" ] } static_library("libinitsync_static") { - sources = [ "src/init_sync.c" ] + sources = [ + "src/init_sync.c", + ] cflags = [ "-Wall" ] include_dirs = [ "//base/startup/init_lite/initsync/include", "//base/startup/init_lite/interfaces/kits", + "//base/startup/init_lite/services/log", + ] + public_deps = [ + "//third_party/bounds_checking_function:libsec_static", ] - public_deps = [ "//third_party/bounds_checking_function:libsec_static" ] } diff --git a/initsync/src/init_sync.c b/initsync/src/init_sync.c index 24aa1cdd951b83e2fa1087bd086a4d79978c71ca..9eca4edfefc18b67773abb6123ece566ec9c1fd7 100644 --- a/initsync/src/init_sync.c +++ b/initsync/src/init_sync.c @@ -24,19 +24,19 @@ #include #include #include - +#include "init_log.h" static int SendCmd(int cmd, unsigned long arg) { int fd = open(QUICKSTART_NODE, O_RDONLY); if (fd != -1) { int ret = ioctl(fd, cmd, arg); if (ret == -1) { - printf("[ERR][%s,%d] %s!\n", __FUNCTION__, __LINE__, strerror(errno)); + INIT_LOGE("[Init] [ERR] %s!\n", strerror(errno)); } close(fd); return ret; } - printf("[ERR][%s,%d] %s!\n", __FUNCTION__, __LINE__, strerror(errno)); + INIT_LOGE("[Init] [ERR] %s!\n", strerror(errno)); return fd; } @@ -56,7 +56,7 @@ int NotifyInit(unsigned long event) int SystemInitStage(QuickstartStage stage) { if (stage >= QS_STAGE_LIMIT || stage < QS_STAGE1) { - printf("[ERR][%s,%d] the stage(%d) is not expected!\n", __FUNCTION__, __LINE__, stage); + INIT_LOGE("[Init] the stage(%d) is not expected!\n", stage); return -1; } return SendCmd(QUICKSTART_STAGE(stage), 0); diff --git a/interfaces/innerkits/include/init_reboot_api.h b/interfaces/innerkits/include/init_reboot_api.h new file mode 100644 index 0000000000000000000000000000000000000000..7495d15498b03b52b7b7b791ac61046d20a216b6 --- /dev/null +++ b/interfaces/innerkits/include/init_reboot_api.h @@ -0,0 +1,22 @@ +/* + * 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_REBOOT_API_H +#define INIT_REBOOT_API_H + +int DoRebootApi(const char *cmdContent); + +#endif + diff --git a/interfaces/innerkits/include/init_socket_api.h b/interfaces/innerkits/include/init_socket_api.h new file mode 100644 index 0000000000000000000000000000000000000000..420264d147bf965ee58dc44f2b2a07dd856af2a8 --- /dev/null +++ b/interfaces/innerkits/include/init_socket_api.h @@ -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 \ No newline at end of file diff --git a/interfaces/innerkits/reboot/BUILD.gn b/interfaces/innerkits/reboot/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..0bd7d5ca818ea81d525c5e76431fb258f9e1a66d --- /dev/null +++ b/interfaces/innerkits/reboot/BUILD.gn @@ -0,0 +1,32 @@ +# 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("libreboot") { + sources = [ + "//base/startup/init_lite/interfaces/innerkits/reboot/init_reboot_api.c", + ] + + include_dirs = [ + "//base/startup/init_lite/interfaces/innerkits/include", + "//base/startup/init_lite/services/include/param", + "//third_party/bounds_checking_function/include", + "//base/startup/init_lite/services/log", + ] + + deps = [ + "//base/startup/init_lite/services/log:init_log", + "//base/startup/init_lite/services/param:paramclient", + "//third_party/bounds_checking_function:libsec_static", + ] +} diff --git a/interfaces/innerkits/reboot/init_reboot_api.c b/interfaces/innerkits/reboot/init_reboot_api.c new file mode 100644 index 0000000000000000000000000000000000000000..5d8b1f54838790c637d468edcdf306fbb46b647c --- /dev/null +++ b/interfaces/innerkits/reboot/init_reboot_api.c @@ -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_reboot_api.h" + +#include +#include +#include "sys_param.h" +#include "securec.h" +#include "init_log.h" + +#define SYS_POWER_CTRL "sys.powerctrl." +#define MAX_REBOOT_NAME_SIZE 100 +#define MAX_REBOOT_VAUE_SIZE 500 + +int DoRebootApi(const char *cmdContent) +{ + char name[MAX_REBOOT_VAUE_SIZE]; + if (cmdContent == NULL) { + INIT_LOGE("DoReboot api error, cmdContent is NULL.\n"); + return -1; + } + int length = strlen(cmdContent); + if (length == 0 || length > MAX_REBOOT_VAUE_SIZE) { + INIT_LOGE("DoReboot api error, cmdContent = %s, length = %d.\n", cmdContent, length); + return -1; + } + if (snprintf_s(name, MAX_REBOOT_NAME_SIZE, MAX_REBOOT_NAME_SIZE - 1, "%s%s", SYS_POWER_CTRL, "reboot") < 0) { + INIT_LOGE("DoReboot api error, MAX_REBOOT_NAME_SIZE is not enough\n"); + return -1; + } + if (SystemSetParameter(name, cmdContent) != 0) { + INIT_LOGE("DoRebootApi SystemSetParameter error\n"); + return -1; + } + return 0; +} + diff --git a/interfaces/innerkits/socket/BUILD.gn b/interfaces/innerkits/socket/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..dc7ca57b5090d836d8607adf89dd80395c33b541 --- /dev/null +++ b/interfaces/innerkits/socket/BUILD.gn @@ -0,0 +1,23 @@ +# 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 = [] +} diff --git a/interfaces/innerkits/socket/init_socket_api.c b/interfaces/innerkits/socket/init_socket_api.c new file mode 100644 index 0000000000000000000000000000000000000000..7126f9191b8d87a26460c7c3ef8bcf55c8d561f9 --- /dev/null +++ b/interfaces/innerkits/socket/init_socket_api.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + } + INIT_LOGI("GetControlFromEnv path is %s \n", path); + const char *val = getenv(path); + if (val == NULL) { + INIT_LOGE("GetControlFromEnv val is null %d\n", errno); + return -1; + } + errno = 0; + int fd = strtol(val, NULL, N_DEC); + if (errno) { + return -1; + } + INIT_LOGI("GetControlFromEnv fd is %d \n", fd); + if (fcntl(fd, F_GETFD) < 0) { + INIT_LOGE("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); + INIT_LOGI("GetControlSocket path is %s \n", path); + int fd = GetControlFromEnv(path); + if (fd < 0) { + INIT_LOGE("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) { + INIT_LOGE("GetControlSocket errno %d \n", errno); + return -1; + } + char sockDir[MAX_SOCKET_DIR_LEN] = {0}; + snprintf(sockDir, sizeof(sockDir), OHOS_SOCKET_DIR"/%s", name); + INIT_LOGI("sockDir %s \n", sockDir); + INIT_LOGI("addr.sun_path %s \n", addr.sun_path); + if (strncmp(sockDir, addr.sun_path, strlen(sockDir)) == 0) { + return fd; + } + return -1; +} diff --git a/ohos.build b/ohos.build new file mode 100644 index 0000000000000000000000000000000000000000..c6cdbf243676ed456a75ccd691441b85613a6645 --- /dev/null +++ b/ohos.build @@ -0,0 +1,10 @@ +{ + "subsystem": "startup", + "parts": { + "init": { + "module_list": [ + "//base/startup/init_lite/services:startup_init" + ] + } + } +} diff --git a/services/BUILD.gn b/services/BUILD.gn index 286dadf956a3d7eea7fccce55f271a6564aad512..cd7c6818b98ecc34ab8c95b4ee7206dfc5e8c2f3 100644 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -20,17 +20,24 @@ if (defined(ohos_lite)) { ] sources = [ "src/init_adapter.c", + "src/init_capability.c", "src/init_cmds.c", + "src/init_import.c", "src/init_jobs.c", "src/init_read_cfg.c", + "src/init_reboot.c", "src/init_service.c", "src/init_service_manager.c", + "src/init_service_socket.c", "src/init_signal_handler.c", + "src/init_utils.c", "src/main.c", ] include_dirs = [ - "include", + "//base/startup/init_lite/services/include", + "//base/startup/init_lite/services/param/include", + "//base/startup/init_lite/services/log", "//third_party/cJSON", "//third_party/bounds_checking_function/include", "//base/startup/syspara_lite/interfaces/kits", @@ -39,8 +46,9 @@ if (defined(ohos_lite)) { cflags = [ "-Wall" ] deps = [ - "//base/startup/syspara_lite/frameworks/parameter:parameter", "//base/startup/init_lite/initsync:initsync", + "//base/startup/init_lite/services/log:init_log", + "//base/startup/syspara_lite/frameworks/parameter:parameter", "//build/lite/config/component/cJSON:cjson_shared", "//third_party/bounds_checking_function:libsec_shared", ] @@ -74,7 +82,6 @@ if (defined(ohos_lite)) { } } else { import("//build/ohos.gni") - ohos_executable("updaterueventd") { sources = [ "src/list.c", @@ -83,40 +90,72 @@ if (defined(ohos_lite)) { include_dirs = [ "include", "//third_party/bounds_checking_function/include", + "//base/startup/init_lite/services/log", + ] + deps = [ + "//base/startup/init_lite/services/log:init_log", + "//third_party/bounds_checking_function:libsec_static", ] - 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_capability.c", "src/init_cmds.c", + "src/init_import.c", "src/init_jobs.c", "src/init_read_cfg.c", + "src/init_reboot.c", "src/init_service.c", "src/init_service_manager.c", + "src/init_service_socket.c", "src/init_signal_handler.c", + "src/init_utils.c", "src/main.c", ] include_dirs = [ - "include", + "//base/startup/init_lite/services/include/param", + "//base/startup/init_lite/services/include", + "//base/startup/init_lite/services/log", "//third_party/cJSON", "//third_party/bounds_checking_function/include", + "//third_party/libuv/include", ] deps = [ + "//base/startup/init_lite/services/log:init_log", + "//base/startup/init_lite/services/param:paramservice", "//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", + ":init.cfg", + ":updaterueventd", + "//base/startup/init_lite/services/param:getparam", + "//base/startup/init_lite/services/param:paramclient", + "//base/startup/init_lite/services/param:paramservice", + "//base/startup/init_lite/services/param:setparam", + "//base/startup/init_lite/services/reboot:reboot", + ] } } diff --git a/services/include/device.h b/services/include/device.h old mode 100755 new mode 100644 index 6739b2bc78280535403a06546405950ba2656f38..aebe7e07ea8a13c5fa560bc970dea597dfafab25 --- a/services/include/device.h +++ b/services/include/device.h @@ -21,9 +21,11 @@ extern "C" { #endif #endif +#include void MountBasicFs(); void CreateDeviceNode(); +int MakeSocketDir(const char *path, mode_t mode); #ifdef __cplusplus #if __cplusplus diff --git a/services/include/init_adapter.h b/services/include/init_adapter.h old mode 100755 new mode 100644 index d6376df403dfb4b45bd829d6db4dc59af273ba56..ea02c1e06b7fd1ef97c7f649080263cc3e079e13 --- a/services/include/init_adapter.h +++ b/services/include/init_adapter.h @@ -16,10 +16,10 @@ #ifndef BASE_STARTUP_INITLITE_ADAPTER_H #define BASE_STARTUP_INITLITE_ADAPTER_H -#ifdef __LINUX__ -#include -#else +#if defined OHOS_LITE && !defined __LINUX__ #include +#else +#include #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 diff --git a/services/include/init_capability.h b/services/include/init_capability.h new file mode 100644 index 0000000000000000000000000000000000000000..842959e73e0cc043949640656e435d7aa01e8d26 --- /dev/null +++ b/services/include/init_capability.h @@ -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 + diff --git a/services/include/init_cmds.h b/services/include/init_cmds.h index da4b2b29303c20e14c6be76975e3846f91b7a4c7..e7777f4d434ce032e9eae203a608388a86567574 100644 --- a/services/include/init_cmds.h +++ b/services/include/init_cmds.h @@ -22,10 +22,11 @@ extern "C" { #endif #endif -#define MAX_CMD_NAME_LEN 10 -#define MAX_CMD_CONTENT_LEN 128 -#define MAX_CMD_CNT_IN_ONE_JOB 30 - +#define MAX_CMD_NAME_LEN 32 +#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 } diff --git a/services/include/init_import.h b/services/include/init_import.h new file mode 100644 index 0000000000000000000000000000000000000000..48b6c01dd4ec79018b48140176110913bf140d59 --- /dev/null +++ b/services/include/init_import.h @@ -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 \ No newline at end of file diff --git a/services/include/init_jobs.h b/services/include/init_jobs.h index 5a6a6b3b75f21096a9660b586203f224b5c11bb5..7c7ffaed5cd53b53715f2317d128f7a9594f1e48 100644 --- a/services/include/init_jobs.h +++ b/services/include/init_jobs.h @@ -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 } diff --git a/services/include/init_perms.h b/services/include/init_perms.h old mode 100755 new mode 100644 diff --git a/services/include/init_read_cfg.h b/services/include/init_read_cfg.h index c596128127076889cd03892406c40be50305d887..3ab3a29ee123f74154b89c164dec89f2d7c44ad4 100644 --- a/services/include/init_read_cfg.h +++ b/services/include/init_read_cfg.h @@ -21,10 +21,16 @@ extern "C" { #endif #endif - +#ifndef OHOS_LITE +#define INIT_CONFIGURATION_FILE "/init.cfg" +#else #define INIT_CONFIGURATION_FILE "/etc/init.cfg" +#endif +#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 diff --git a/services/include/init_reboot.h b/services/include/init_reboot.h new file mode 100644 index 0000000000000000000000000000000000000000..181d811327ea1f4dfeb1bbf2c32b95ea8527687f --- /dev/null +++ b/services/include/init_reboot.h @@ -0,0 +1,21 @@ +/* + * 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 INIT_REBOOT_H +#define INIT_REBOOT_H + +void DoReboot(const char *value); + +#endif diff --git a/services/include/init_service.h b/services/include/init_service.h old mode 100755 new mode 100644 index b6c7cfb328818d24c2cfc5e834edf78423286a99..ba4e046744cfbd2f80f6f2c243434e275bf68e3c --- a/services/include/init_service.h +++ b/services/include/init_service.h @@ -17,6 +17,8 @@ #define BASE_STARTUP_INITLITE_SERVICE_H #include +#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); diff --git a/services/include/init_service_manager.h b/services/include/init_service_manager.h index 37e97d7af825e28114fab530ff6e2afa2e8cd5b7..33a8c7608bd348fc2582f9616e64a02dffa35cbf 100644 --- a/services/include/init_service_manager.h +++ b/services/include/init_service_manager.h @@ -17,6 +17,7 @@ #define BASE_STARTUP_INITLITE_SERVICEMANAGER_H #include "init_service.h" +#include "cJSON.h" #ifdef __cplusplus #if __cplusplus @@ -24,10 +25,24 @@ 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 StopAllServicesBeforeReboot(); void ReapServiceByPID(int pid); +void ParseAllServices(const cJSON* fileRoot); +void DumpAllServices(); #ifdef __cplusplus #if __cplusplus diff --git a/services/include/init_service_socket.h b/services/include/init_service_socket.h new file mode 100644 index 0000000000000000000000000000000000000000..9fe5e1a80c4cac546f88c4b5981928b1aefafccb --- /dev/null +++ b/services/include/init_service_socket.h @@ -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 +#include +#include +#include +#include + +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 diff --git a/services/include/init_utils.h b/services/include/init_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..dfe3734f82f27f3a7773728644e2fcf9de52a13f --- /dev/null +++ b/services/include/init_utils.h @@ -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 diff --git a/services/include/list.h b/services/include/list.h old mode 100755 new mode 100644 index ee2220cc078053150768ea0735f1b57a40c1b646..4aaf9dcf65bc02fe7b4e416c011995719c7bbb78 --- a/services/include/list.h +++ b/services/include/list.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); diff --git a/services/include/param/init_param.h b/services/include/param/init_param.h new file mode 100644 index 0000000000000000000000000000000000000000..34fb66f1d6e2c8a0ab9e064e58d170f0b6329822 --- /dev/null +++ b/services/include/param/init_param.h @@ -0,0 +1,136 @@ +/* + * 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_INIT_PARAM_H +#define BASE_STARTUP_INIT_PARAM_H +#include +#include "cJSON.h" +#include "sys_param.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +typedef enum { + EVENT_PROPERTY, // 参数修改事件 + EVENT_BOOT +} EventType; + +/** + * Init 接口 + * 初始化参数服务 + * + */ +void InitParamService(); + +/** + * 对Init接口 + * 启动trigger服务。 + * + */ +void StartTriggerService(); + +/** + * Init 接口 + * 启动参数服务,在main启动的最后调用,阻赛当前线程 + * + */ +int StartParamService(); + +/** + * Init 接口 + * 停止参数服务 + * + */ +void StopParamService(); + +/** + * Init 接口 + * 加载默认的参数值 + * + */ +int LoadDefaultParams(const char *fileName); + +/** + * Init 接口 + * 安全使用,加载参数的信息,包括selinux label 等 + * + */ +int LoadParamInfos(const char *fileName); + +/** + * Init 接口 + * 加载默认参数。 + * + */ +int LoadPersistParams(); + +/** + * Init 接口 + * 设置参数,主要用于其他进程使用,通过管道修改参数 + * + */ +int SystemWriteParam(const char *name, const char *value); + +/** + * Init 接口 + * 查询参数。 + * + */ +int SystemReadParam(const char *name, char *value, unsigned int *len); + +/** + * 对Init接口 + * 触发一个trigger操作。 + * + */ +void PostTrigger(EventType type, void *content, u_int32_t contentLen); + +/** + * 对Init接口 + * 触发一个参数trigger操作。 + * + */ +void PostParamTrigger(const char *name, const char *value); + +/** + * 对Init接口 + * 解析trigger文件。 + * + */ +int ParseTriggerConfig(cJSON *fileRoot); + +/** + * 对Init接口 + * 按名字执行对应的trigger。 + * + */ +void DoTriggerExec(const char *content); + +/** + * 对Init接口 + * 按名字执行对应的trigger。 + * + */ +int SystemTraversalParam(void (*traversalParameter)(ParamHandle handle, void* cookie), void* cookie); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif +#endif \ No newline at end of file diff --git a/services/include/param/sys_param.h b/services/include/param/sys_param.h new file mode 100644 index 0000000000000000000000000000000000000000..5500a5077e786a895d37ad9f5f693f609ae7876c --- /dev/null +++ b/services/include/param/sys_param.h @@ -0,0 +1,90 @@ +/* + * 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_SYS_PARAM_H +#define BASE_STARTUP_SYS_PARAM_H +#include +#include +#include + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +#define PARAM_VALUE_LEN_MAX 96 +typedef u_int32_t ParamHandle; + +typedef struct { + u_int32_t serial; + ParamHandle handle; + char value[PARAM_VALUE_LEN_MAX]; +} ParamCacheNode; + +typedef const char *(*ParamEvaluatePtr)(u_int32_t cacheCount, ParamCacheNode *node); + +typedef struct { + pthread_mutex_t lock; + u_int32_t serial; + u_int32_t cacheCount; + ParamEvaluatePtr evaluate; + ParamCacheNode *cacheNode; +} ParamCache; + +/** + * 对外接口 + * 设置参数,主要用于其他进程使用,通过管道修改参数。 + * + */ +int SystemSetParameter(const char *name, const char *value); + +/** + * 对外接口 + * 查询参数,主要用于其他进程使用,需要给定足够的内存保存参数。 + * 如果 value == null,获取value的长度 + * 否则value的大小认为是len + * + */ +int SystemGetParameter(const char *name, char *value, unsigned int *len); + +/** + * 外部接口 + * 遍历参数。 + * + */ +int SystemTraversalParameter(void (*traversalParameter)(ParamHandle handle, void* cookie), void* cookie); + +/** + * 外部接口 + * 查询参数,主要用于其他进程使用,需要给定足够的内存保存参数。 + * 如果 value == null,获取value的长度 + * 否则value的大小认为是len + * + */ +int SystemGetParameterName(ParamHandle handle, char *name, unsigned int len); + +/** + * 外部接口 + * 获取参数值。 + * + */ +int SystemGetParameterValue(ParamHandle handle, char *value, unsigned int *len); +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif +#endif \ No newline at end of file diff --git a/services/log/BUILD.gn b/services/log/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..bf58f511f3490005bf38a9dc988449164490e5c2 --- /dev/null +++ b/services/log/BUILD.gn @@ -0,0 +1,26 @@ +# 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. +if (defined(ohos_lite)) { + static_library("init_log") { + sources = [ "init_log.c" ] + public_deps = [ "//third_party/bounds_checking_function:libsec_static" ] + } +} else { + import("//build/ohos.gni") + ohos_static_library("init_log") { + sources = [ "init_log.c" ] + deps = [ "//third_party/bounds_checking_function:libsec_static" ] + part_name = "startup" + subsystem_name = "startup" + } +} diff --git a/services/log/init_log.c b/services/log/init_log.c new file mode 100644 index 0000000000000000000000000000000000000000..83c4b00d9cf19f611296d89d05469175b8cad348 --- /dev/null +++ b/services/log/init_log.c @@ -0,0 +1,77 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include "securec.h" + +#define UNUSED(x) (void)(x) +#define MAX_FORMAT_SIZE 1024 +#define MAX_LOG_SIZE 2048 +#define BASE_YEAR 1900 + +static InitLogLevel g_logLevel = INIT_INFO; + +static const char *LOG_LEVEL_STR[] = { "DEBUG", "INFO", "WARNING", "ERROR", "FATAL" }; + +void SetLogLevel(InitLogLevel logLevel) +{ + g_logLevel = logLevel; +} + +void InitLog(const char *tag, InitLogLevel logLevel, const char *fileName, int line, const char *fmt, ...) +{ + if (logLevel < g_logLevel) { + return; + } + 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, "%s %d-%d-%d %d:%d %s:%d [%s] [pid=%d] %s", tag, + (t->tm_year + BASE_YEAR), (t->tm_mon + 1), t->tm_mday, t->tm_hour, t->tm_min, fileName, line, + LOG_LEVEL_STR[logLevel], getpid(), tmpFmt) == -1) { + return; + } + printf("%s", logInfo ); +#if 0 + 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); + close(fd); + return; + } + close(fd); +#endif + va_end(vargs); +} + diff --git a/services/log/init_log.h b/services/log/init_log.h new file mode 100644 index 0000000000000000000000000000000000000000..81ddc316d7bc6a3e233892557094cbb53bcb9c3c --- /dev/null +++ b/services/log/init_log.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INIT_LOG_H +#define INIT_LOG_H +#include +#include +#include +#include + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +typedef enum InitLogLevel { + INIT_DEBUG = 0, + INIT_INFO, + INIT_WARN, + INIT_ERROR, + INIT_FATAL +} InitLogLevel; + +#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_LOGD(format, ...) InitLog("[Init]", INIT_DEBUG, (__FILE_NAME__), (__LINE__), format, ##__VA_ARGS__) +#define INIT_LOGI(format, ...) InitLog("[Init]", INIT_INFO, (__FILE_NAME__), (__LINE__), format, ##__VA_ARGS__) +#define INIT_LOGW(format, ...) InitLog("[Init]", INIT_WARN, (__FILE_NAME__), (__LINE__), format, ##__VA_ARGS__) +#define INIT_LOGE(format, ...) InitLog("[Init]", INIT_ERROR, (__FILE_NAME__), (__LINE__), format, ##__VA_ARGS__) +#define INIT_LOGF(format, ...) InitLog("[Init]", INIT_FATAL, (__FILE_NAME__), (__LINE__), format, ##__VA_ARGS__) + +void InitLog(const char *tag, InitLogLevel logLevel, const char *fileName, int line, const char *fmt, ...); +void SetLogLevel(InitLogLevel logLevel); + +void Logger(InitLogLevel 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"}; + +InitLogLevel level_; +int JudgeLevel(const InitLogLevel level) { return return; } + +#define STARTUP_LOG(LEVEL, LABEL, Level, fmt, ...) \ + InitLog("[Init]", LEVEL, __FILE_NAME__, (__LINE__), fmt, ##__VA_ARGS__); \ + if (JudgeLevel(InitLogLevel::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:%d][%s:%d] " fmt "\n", LABEL, getpid(), __FILE_NAME__, __LINE__, ##__VA_ARGS__); +#endif + +#define STARTUP_LOGI(LABEL, fmt, ...) STARTUP_LOG(INIT_INFO, LABEL, Info, fmt, ##__VA_ARGS__) +#define STARTUP_LOGE(LABEL, fmt, ...) STARTUP_LOG(INIT_ERROR, LABEL, Error, fmt, ##__VA_ARGS__) + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif + +#endif // INIT_LOG_H diff --git a/services/param/BUILD.gn b/services/param/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..07e1d27849151a38ed8427a639bcd9d523f8f6be --- /dev/null +++ b/services/param/BUILD.gn @@ -0,0 +1,104 @@ +# 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("paramservice") { + sources = [ + "//base/startup/init_lite/services/src/init_utils.c", + "manager/param_cache.c", + "manager/param_manager.c", + "manager/param_trie.c", + "service/param_persist.c", + "service/param_service.c", + "trigger/trigger_checker.c", + "trigger/trigger_manager.c", + "trigger/trigger_processor.c", + ] + + include_dirs = [ + "include", + "//base/startup/init_lite/services/include/param", + "//base/startup/init_lite/services/include", + "//base/startup/init_lite/services/log", + "//third_party/libuv/include", + "//third_party/cJSON", + ] + + deps = [ + "//third_party/bounds_checking_function:libsec_static", + "//third_party/libuv:uv_static", + ] + part_name = "init" + subsystem_name = "startup" +} + +ohos_static_library("paramclient") { + sources = [ + "//base/startup/init_lite/services/src/init_utils.c", + "client/param_request.c", + "manager/param_cache.c", + "manager/param_manager.c", + "manager/param_trie.c", + ] + + include_dirs = [ + "include", + "//base/startup/init_lite/services/include/param", + "//base/startup/init_lite/services/include", + "//base/startup/init_lite/services/log", + "//third_party/libuv/include", + "//third_party/cJSON", + ] + + deps = [ + "//base/startup/init_lite/services/log:init_log", + "//third_party/bounds_checking_function:libsec_static", + "//third_party/libuv:uv_static", + ] + part_name = "init" + subsystem_name = "startup" +} + +ohos_executable("getparam") { + sources = [ "cmd/param_get.c" ] + include_dirs = [ + "include", + "//base/startup/init_lite/services/include/param", + "//base/startup/init_lite/services/include", + "//base/startup/init_lite/services/log", + ] + deps = [ + "//base/startup/init_lite/services/param:paramclient", + "//third_party/bounds_checking_function:libsec_static", + "//third_party/cJSON:cjson_static", + ] + install_enable = true + part_name = "init" +} + +ohos_executable("setparam") { + sources = [ "cmd/param_set.c" ] + include_dirs = [ + "include", + "//base/startup/init_lite/services/include/param", + "//base/startup/init_lite/services/include", + "//base/startup/init_lite/services/log", + ] + deps = [ + "//base/startup/init_lite/services/param:paramclient", + "//third_party/bounds_checking_function:libsec_static", + "//third_party/cJSON:cjson_static", + ] + install_enable = true + part_name = "init" +} diff --git a/services/param/client/param_request.c b/services/param/client/param_request.c new file mode 100644 index 0000000000000000000000000000000000000000..bf8af8094667ea75d0d3021441abd7174e61bd97 --- /dev/null +++ b/services/param/client/param_request.c @@ -0,0 +1,160 @@ +/* + * 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 "param_request.h" + +#include +#include +#include + +#include "param_manager.h" +#include "uv.h" + +#define LABEL "Client" +#define BUFFER_SIZE 200 +#define ParamEntry(ptr, type, member) (type *)((char *)(ptr) - offsetof(type, member)) + +static ParamWorkSpace g_paramWorkSpaceReadOnly = {ATOMIC_VAR_INIT(0), {}, {}, {}}; + +static void OnWrite(uv_write_t *req, int status) +{ + PARAM_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 = sizeof(ResponseMsg); + PARAM_LOGI("OnReceiveAlloc handle %p %zu", handle, suggestedSize); +} + +static void OnReceiveResponse(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) +{ + RequestNode *req = ParamEntry(handle, RequestNode, handle); + PARAM_LOGI("OnReceiveResponse %p", handle); + if (nread <= 0 || buf == NULL || handle == NULL || buf->base == NULL) { + if (buf != NULL && buf->base != NULL) { + free(buf->base); + } + if (handle != NULL) { + uv_close((uv_handle_t*)handle, NULL); + uv_stop(req->loop); + } + return; + } + ResponseMsg *response = (ResponseMsg *)(buf->base); + PARAM_CHECK(response != NULL, return, "The response is null"); + PARAM_LOGI("OnReceiveResponse %p cmd %d result: %d", handle, response->type, response->result); + switch (response->type) { + case SET_PARAM: + req->result = response->result; + break; + default: + PARAM_LOGE("not supported the command: %d", response->type); + break; + } + PARAM_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) +{ + PARAM_CHECK(status >= 0, return, "Failed to conntect status %s", uv_strerror(status)); + RequestNode *request = ParamEntry(connect, RequestNode, connect); + PARAM_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(&request->wr, (uv_stream_t*)&(request->handle), &buf, 1, (uv_stream_t*)&(request->handle), OnWrite); + PARAM_CHECK(ret >= 0, return, "Failed to uv_write2 porperty"); + + // read result + ret = uv_read_start((uv_stream_t*)&(request->handle), OnReceiveAlloc, OnReceiveResponse); + PARAM_CHECK(ret >= 0, return, "Failed to uv_read_start response"); +} + +static int StartRequest(int cmd, RequestNode *request) +{ + PARAM_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); + uv_loop_delete(request->loop); + int result = request->result; + free(request); + return result; +} + +int SystemSetParameter(const char *name, const char *value) +{ + PARAM_CHECK(name != NULL && value != NULL, return -1, "Invalid param"); + int ret = CheckParamName(name, 0); + PARAM_CHECK(ret == 0, return ret, "Illegal param name"); + + PARAM_LOGI("StartRequest %s", name); + u_int32_t msgSize = sizeof(RequestMsg) + strlen(name) + strlen(value) + 2; + RequestNode *request = (RequestNode *)malloc(sizeof(RequestNode) + msgSize); + PARAM_CHECK(request != NULL, return -1, "Failed to malloc for connect"); + + memset_s(request, sizeof(RequestNode), 0, sizeof(RequestNode)); + // 带字符串结束符 + int contentSize = BuildParamContent(request->msg.content, msgSize - sizeof(RequestMsg), name, value); + PARAM_CHECK(contentSize > 0, free(request); return -1, "Failed to copy porperty"); + request->msg.contentSize = contentSize; + return StartRequest(SET_PARAM, request); +} + +int SystemGetParameter(const char *name, char *value, unsigned int *len) +{ + PARAM_CHECK(name != NULL && len != NULL, return -1, "The name or value is null"); + InitParamWorkSpace(&g_paramWorkSpaceReadOnly, 1, NULL); + + ParamHandle handle = 0; + int ret = ReadParamWithCheck(&g_paramWorkSpaceReadOnly, name, &handle); + PARAM_CHECK(ret == 0, return ret, "Can not get param for %s", name); + return ReadParamValue(&g_paramWorkSpaceReadOnly, handle, value, len); +} + +int SystemGetParameterName(ParamHandle handle, char *name, unsigned int len) +{ + PARAM_CHECK(name != NULL && handle != 0, return -1, "The name is null"); + InitParamWorkSpace(&g_paramWorkSpaceReadOnly, 1, NULL); + return ReadParamName(&g_paramWorkSpaceReadOnly, handle, name, len); +} + +int SystemGetParameterValue(ParamHandle handle, char *value, unsigned int *len) +{ + PARAM_CHECK(len != NULL && handle != 0, return -1, "The value is null"); + InitParamWorkSpace(&g_paramWorkSpaceReadOnly, 1, NULL); + return ReadParamValue(&g_paramWorkSpaceReadOnly, handle, value, len); +} + +int SystemTraversalParameter(void (*traversalParameter)(ParamHandle handle, void* cookie), void* cookie) +{ + PARAM_CHECK(traversalParameter != NULL, return -1, "The param is null"); + InitParamWorkSpace(&g_paramWorkSpaceReadOnly, 1, NULL); + return TraversalParam(&g_paramWorkSpaceReadOnly, traversalParameter, cookie); +} + +const char *SystemDetectParamChange(ParamCache *cache, + ParamEvaluatePtr evaluate, u_int32_t count, const char *parameters[][2]) +{ + PARAM_CHECK(cache != NULL && evaluate != NULL && parameters != NULL, return NULL, "The param is null"); + return DetectParamChange(&g_paramWorkSpaceReadOnly, cache, evaluate, count, parameters); +} diff --git a/services/param/cmd/param_get.c b/services/param/cmd/param_get.c new file mode 100644 index 0000000000000000000000000000000000000000..bba06fcdf3068e54226e2dd87c0b51059775f825 --- /dev/null +++ b/services/param/cmd/param_get.c @@ -0,0 +1,55 @@ +/* +* 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 +#include +#include "sys_param.h" + +#define HELP_PARAM "--help" +#define BUFFER_SIZE 256 + +static void ProcessParam(ParamHandle 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: getparam NAME VALUE\n"); + return 0; + } + if (argc != 2) { + printf("usage: getparam 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("getparam %s %s \n", argv[1], value); + } else { + printf("getparam %s %s fail\n", argv[1], value); + } + +} diff --git a/services/param/cmd/param_set.c b/services/param/cmd/param_set.c new file mode 100644 index 0000000000000000000000000000000000000000..3c3943df95ad2df4048cecf61777cacc77536050 --- /dev/null +++ b/services/param/cmd/param_set.c @@ -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 +#include + +#include "sys_param.h" + +#define HELP_PARAM "--help" + +int main(int argc, char* argv[]) +{ + if (argc == 1 || argc > 3) { + printf("setparam: Need 2 arguments (see \"setparam --help\")\n"); + return 0; + } + if (argc == 2 && strncmp(argv[1], HELP_PARAM, strlen(HELP_PARAM)) == 0) { + printf("usage: setparam NAME VALUE\n"); + return 0; + } + int ret = SystemSetParameter(argv[1], argv[2]); + if (ret == 0) { + printf("setparam %s %s success\n", argv[1], argv[2]); + } else { + printf("setparam %s %s fail\n", argv[1], argv[2]); + } +} diff --git a/services/param/include/param_manager.h b/services/param/include/param_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..96e754341dfc6c2757d3dd27c0e80ae308f9f012 --- /dev/null +++ b/services/param/include/param_manager.h @@ -0,0 +1,159 @@ +/* + * 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_PARAM_MANAGER_H +#define BASE_STARTUP_PARAM_MANAGER_H +#include +#include + +#include "init_log.h" +#include "sys_param.h" +#include "param_trie.h" +#include "securec.h" +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +typedef enum { + PARAM_CODE_INVALID_PARAM = 100, + PARAM_CODE_INVALID_NAME, + PARAM_CODE_INVALID_VALUE, + PARAM_CODE_REACHED_MAX, + PARAM_CODE_PERMISSION_DENIED, + PARAM_CODE_READ_ONLY_PROPERTY, + PARAM_CODE_NOT_SUPPORT, + PARAM_CODE_ERROR_MAP_FILE, + PARAM_CODE_NOT_FOUND_PROP, + PARAM_CODE_NOT_INIT +} PARAM_CODE; + +#define IS_READY_ONLY(name) strncmp((name), "ro.", strlen("ro.")) == 0 +#define LABEL_STRING_LEN 128 + +#ifdef STARTUP_LOCAL +#define PIPE_NAME "/tmp/paramservice" +#define PARAM_STORAGE_PATH "/media/sf_ubuntu/test/__parameters__/param_storage" +#define PARAM_PERSIST_PATH "/media/sf_ubuntu/test/param/persist_parameters" +#define PARAM_INFO_PATH "/media/sf_ubuntu/test/__parameters__/param_info" +#else +#define PIPE_NAME "/dev/unix/socket/paramservice" +#define PARAM_STORAGE_PATH "/dev/__parameters__/param_storage" +#define PARAM_PERSIST_PATH "/data/param/persist_parameters" +#define PARAM_INFO_PATH "/dev/__parameters__/param_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 PARAM_LOGI(fmt, ...) STARTUP_LOGI(LABEL, fmt, ##__VA_ARGS__) +#define PARAM_LOGE(fmt, ...) STARTUP_LOGE(LABEL, fmt, ##__VA_ARGS__) + +#define PARAM_CHECK(retCode, exper, ...) \ + if (!(retCode)) { \ + PARAM_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; +} ParamSecurityLabel; + +typedef struct ParamAuditData { + const UserCred *cr; + const char *name; +} ParamAuditData; + +typedef struct { + atomic_uint_least32_t flags; + WorkSpace paramLabelSpace; + WorkSpace paramSpace; + ParamSecurityLabel label; +} ParamWorkSpace; + +typedef struct { + atomic_uint_least32_t flags; + WorkSpace persistWorkSpace; +} ParamPersistWorkSpace; + +typedef struct { + char value[128]; +} SubStringInfo; + +int InitParamWorkSpace(ParamWorkSpace *workSpace, int onlyRead, const char *context); +void CloseParamWorkSpace(ParamWorkSpace *workSpace); + +int ReadParamWithCheck(ParamWorkSpace *workSpace, const char *name, ParamHandle *handle); +int ReadParamValue(ParamWorkSpace *workSpace, ParamHandle handle, char *value, u_int32_t *len); +int ReadParamName(ParamWorkSpace *workSpace, ParamHandle handle, char *name, u_int32_t len); +u_int32_t ReadParamSerial(ParamWorkSpace *workSpace, ParamHandle handle); + +int AddParam(WorkSpace *workSpace, const char *name, const char *value); +int WriteParam(WorkSpace *workSpace, const char *name, const char *value); +int WriteParamWithCheck(ParamWorkSpace *workSpace, + const ParamSecurityLabel *srcLabel, const char *name, const char *value); +int WriteParamInfo(ParamWorkSpace *workSpace, SubStringInfo *info, int subStrNumber); + +int CheckParamValue(WorkSpace *workSpace, const TrieDataNode *node, const char *name, const char *value); +int CheckParamName(const char *name, int paramInfo); +int CanReadParam(ParamWorkSpace *workSpace, u_int32_t labelIndex, const char *name); +int CanWriteParam(ParamWorkSpace *workSpace, + const ParamSecurityLabel *srcLabel, const TrieDataNode *node, const char *name, const char *value); + +int CheckMacPerms(ParamWorkSpace *workSpace, + const ParamSecurityLabel *srcLabel, const char *name, u_int32_t labelIndex); +int CheckControlParamPerms(ParamWorkSpace *workSpace, + const ParamSecurityLabel *srcLabel, const char *name, const char *value); + +int GetSubStringInfo(const char *buff, u_int32_t buffLen, char delimiter, SubStringInfo *info, int subStrNumber); +int BuildParamContent(char *content, u_int32_t contentSize, const char *name, const char *value); +ParamWorkSpace *GetParamWorkSpace(); + +typedef void (*TraversalParamPtr)(ParamHandle handle, void* context); +typedef struct { + TraversalParamPtr traversalParamPtr; + void *context; +} ParamTraversalContext; +int TraversalParam(ParamWorkSpace *workSpace, TraversalParamPtr walkFunc, void *cookie); + +const char *DetectParamChange(ParamWorkSpace *workSpace, ParamCache *cache, + ParamEvaluatePtr evaluate, u_int32_t count, const char *parameters[][2]); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif +#endif \ No newline at end of file diff --git a/services/param/include/param_request.h b/services/param/include/param_request.h new file mode 100644 index 0000000000000000000000000000000000000000..d2ed318d6b17c3583b863d2e1f69ac48c2412ea7 --- /dev/null +++ b/services/param/include/param_request.h @@ -0,0 +1,68 @@ +/* + * 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_PARAM_REQUEST_H +#define BASE_STARTUP_PARAM_REQUEST_H + +#include +#include "sys_param.h" +#include "param_manager.h" + +#include "uv.h" +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +typedef enum RequestType { + SET_PARAM, + GET_PARAM, +} RequestType; + +typedef struct { + ParamSecurityLabel 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; + uv_write_t wr; + int result; + RequestMsg msg; +} RequestNode; + +typedef struct { + uv_write_t writer; + ResponseMsg msg; +} ResponseNode; + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif +#endif \ No newline at end of file diff --git a/services/param/include/param_service.h b/services/param/include/param_service.h new file mode 100644 index 0000000000000000000000000000000000000000..8a0d8554937c2b103626963113db0b6364832152 --- /dev/null +++ b/services/param/include/param_service.h @@ -0,0 +1,37 @@ +/* + * 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_PARAM_SERVICE_H +#define BASE_STARTUP_PARAM_SERVICE_H +#include +#include "sys_param.h" +#include "param_manager.h" +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +int InitPersistParamWorkSpace(const char *context); +int RefreshPersistParams(ParamWorkSpace *workSpace, const char *context); +void ClosePersistParamWorkSpace(); +int WritePersistParam(const char *name, const char *value); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif +#endif \ No newline at end of file diff --git a/services/param/include/param_trie.h b/services/param/include/param_trie.h new file mode 100644 index 0000000000000000000000000000000000000000..8c3e3f9848e10b76d58ac90c1f23f8561ab15385 --- /dev/null +++ b/services/param/include/param_trie.h @@ -0,0 +1,138 @@ +/* + * 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_PARAM_TRIE_H +#define BASE_STARTUP_PARAM_TRIE_H +#include +#include +#include +#include +#include + +#include "init_log.h" +#include "sys_param.h" +#include "securec.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +#define PARAM_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_PARAM_TRIE_H \ No newline at end of file diff --git a/services/param/include/trigger_checker.h b/services/param/include/trigger_checker.h new file mode 100644 index 0000000000000000000000000000000000000000..e3b9a3ed202e026c8280926901e8390b4f5bdf41 --- /dev/null +++ b/services/param/include/trigger_checker.h @@ -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 +#include +#include + +#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 \ No newline at end of file diff --git a/services/param/include/trigger_manager.h b/services/param/include/trigger_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..4dcbf6e03769bba04b934ba866cf403580554e3c --- /dev/null +++ b/services/param/include/trigger_manager.h @@ -0,0 +1,125 @@ +/* + * 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 +#include +#include +#include + +#include "cJSON.h" +#include "init_log.h" +#include "param_manager.h" +#include "securec.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +#define TRIGGER_CMD "trigger " +#define TRIGGER_ARR_NAME_IN_JSON "jobs" +#define CMDS_ARR_NAME_IN_JSON "cmds" + +#define MAX_TRIGGER_CMD_NAME_LEN 32 +#define MAX_TRIGGER_NAME_LEN 64 +#define MAX_TRIGGER_TYPE_LEN 16 + +#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) + +typedef enum { + TRIGGER_BOOT = 0, + TRIGGER_PROPERTY, + TRIGGER_UNKNOW, + TRIGGER_MAX +}TriggerType; + +// 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 (*PARAM_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, PARAM_CHECK_DONE triggerExecuter); +int CheckParamTrigger(TriggerWorkSpace *workSpace, + const char *content, u_int32_t contentSize, PARAM_CHECK_DONE triggerExecuter); + +TriggerNode *ExecuteQueuePop(TriggerWorkSpace *workSpace); +int ExecuteQueuePush(TriggerWorkSpace *workSpace, TriggerNode *trigger, u_int32_t index); +int ExecuteQueueSize(TriggerWorkSpace *workSpace); + +TriggerWorkSpace *GetTriggerWorkSpace(); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif +#endif // STARTUP_TRIGER_MANAGER_H \ No newline at end of file diff --git a/services/param/include/trigger_processor.h b/services/param/include/trigger_processor.h new file mode 100644 index 0000000000000000000000000000000000000000..b57822889aaeba64a825b64946b89ca72d0718a1 --- /dev/null +++ b/services/param/include/trigger_processor.h @@ -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 + +#include "sys_param.h" +#include "init_param.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 \ No newline at end of file diff --git a/services/param/manager/param_cache.c b/services/param/manager/param_cache.c new file mode 100644 index 0000000000000000000000000000000000000000..690de37e869cb0a8777f1a275013d02da97d8aae --- /dev/null +++ b/services/param/manager/param_cache.c @@ -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 "sys_param.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "param_manager.h" + +#define LABEL "Manager" +#define MAX_PROPERT_IN_WATCH 5 +#define NORMAL_MEMORY_FOR_PARAM_CACHE 4 * 1024 +static WorkSpace g_workSpace; +static pthread_mutex_t cacheLock = PTHREAD_MUTEX_INITIALIZER; + +static int InitNormalMemory(WorkSpace *workSpace, u_int32_t spaceSize) +{ + PARAM_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); + PARAM_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); + PARAM_LOGI("InitNormalMemory success, currOffset %u firstNode %u dataSize %u", + workSpace->area->currOffset, workSpace->area->firstNode, workSpace->area->dataSize); + return 0; +} + +static ParamCacheNode *AllocParamCacheNode(WorkSpace *workSpace, u_int32_t size) +{ + PARAM_CHECK(workSpace != NULL, return 0, "Invalid param"); + PARAM_CHECK((workSpace->area->currOffset + size) < workSpace->area->dataSize, return 0, + "Failed to allocate currOffset %d, dataSize %d", workSpace->area->currOffset, workSpace->area->dataSize); + ParamCacheNode *cache = (ParamCacheNode *)(workSpace->area->data + workSpace->area->currOffset); + workSpace->area->currOffset += size; + return cache; +} + +static int CreateParamCache(ParamCache *cache, ParamWorkSpace *workSpace, ParamEvaluatePtr evaluate) +{ + PARAM_CHECK(cache != NULL && evaluate != NULL, return -1, "Invalid param"); + if (cache->cacheNode != NULL) { + return 0; + } + int ret = InitNormalMemory(&g_workSpace, NORMAL_MEMORY_FOR_PARAM_CACHE); + PARAM_CHECK(ret == 0, return -1, "Failed to init normal memory"); + pthread_mutex_init(&cache->lock, NULL); + cache->serial = GetWorkSpaceSerial(&workSpace->paramSpace); + cache->cacheCount = 0; + cache->evaluate = evaluate; + cache->cacheNode = (ParamCacheNode *)AllocParamCacheNode(&g_workSpace, + sizeof(ParamCache) * MAX_PROPERT_IN_WATCH); + PARAM_CHECK(cache->cacheNode != NULL, return -1, "Failed to malloc memory"); + return 0; +} + +static int AddParamNode(ParamCache *cache, ParamWorkSpace *workSpace, const char *name, const char *defValue) +{ + PARAM_CHECK(cache != NULL && name != NULL, return -1, "Invalid param"); + PARAM_CHECK(cache->cacheCount < MAX_PROPERT_IN_WATCH, return -1, "Full param in cache"); + + ParamCacheNode *cacheNode = &cache->cacheNode[cache->cacheCount++]; + int ret = memcpy_s(cacheNode->value, sizeof(cacheNode->value), defValue, strlen(defValue)); + PARAM_CHECK(ret == 0, return -1, "Failed to copy default value"); + + ret = ReadParamWithCheck(workSpace, name, &cacheNode->handle); + PARAM_CHECK(ret == 0, return -1, "Failed to read param"); + cacheNode->serial = ReadParamSerial(workSpace, cacheNode->handle); + return ret; +} + +static int CheckCacheNode(ParamWorkSpace *workSpace, ParamCacheNode *cacheNode) +{ + return cacheNode && ReadParamSerial(workSpace, cacheNode->handle) != cacheNode->serial; +} + +static void RefreshCacheNode(ParamWorkSpace *workSpace, ParamCacheNode *cacheNode) +{ + cacheNode->serial = ReadParamSerial(workSpace, cacheNode->handle); + u_int32_t len = sizeof(cacheNode->value); + ReadParamValue(workSpace, cacheNode->handle, cacheNode->value, &len); +} + +static const char *TestParamCache(ParamCache *cache, ParamWorkSpace *workSpace) +{ + int changeDetected = 0; + if (pthread_mutex_trylock(&cache->lock)) { + return cache->evaluate(cache->cacheCount, cache->cacheNode); + } + if (GetWorkSpaceSerial(&workSpace->paramSpace) != 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->paramSpace); + } + pthread_mutex_unlock(&cache->lock); + + return cache->evaluate(cache->cacheCount, cache->cacheNode); +} + +const char *DetectParamChange(ParamWorkSpace *workSpace, ParamCache *cache, + ParamEvaluatePtr evaluate, u_int32_t count, const char *parameters[][2]) +{ + pthread_mutex_lock(&cacheLock); + while (cache->cacheCount == 0) { + int ret = CreateParamCache(cache, workSpace, evaluate); + PARAM_CHECK(ret == 0, break, "Failed to create cache"); + for (u_int32_t i = 0; i < count; i++) { + ret = AddParamNode(cache, workSpace, parameters[i][0], parameters[i][1]); + PARAM_CHECK(ret == 0, break, "Failed to add param cache"); + } + PARAM_CHECK(ret == 0, break, "Failed to add param cache"); + } + pthread_mutex_unlock(&cacheLock); + return TestParamCache(cache, workSpace); +} diff --git a/services/param/manager/param_manager.c b/services/param/manager/param_manager.c new file mode 100644 index 0000000000000000000000000000000000000000..20f079e6cbe7ddfab518ed396dfeb96a179f1d59 --- /dev/null +++ b/services/param/manager/param_manager.c @@ -0,0 +1,527 @@ +/* + * 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 "param_manager.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LABEL "Manager" + +#ifdef PARAM_SUPPORT_SELINUX +static int SelinuxAuditCallback(void *data, + __attribute__((unused))security_class_t class, char *msgBuf, size_t msgSize) +{ + ParamAuditData *auditData = (ParamAuditData*)(data); + PARAM_CHECK(auditData != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); + PARAM_CHECK(auditData->name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); + PARAM_CHECK(auditData->cr != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); + snprintf(msgBuf, msgSize, "param=%s pid=%d uid=%d gid=%d", + auditData->name, auditData->cr->pid, auditData->cr->uid, auditData->cr->gid); + return 0; +} +#endif + +int InitParamWorkSpace(ParamWorkSpace *workSpace, int onlyRead, const char *context) +{ + u_int32_t flags = atomic_load_explicit(&workSpace->flags, memory_order_relaxed); + if ((flags & WORKSPACE_FLAGS_INIT) == WORKSPACE_FLAGS_INIT) { + return 0; + } + +#ifdef PARAM_SUPPORT_SELINUX + union selinux_callback cb; + cb.func_audit = SelinuxAuditCallback; + selinux_set_callback(SELINUX_CB_AUDIT, cb); +#endif + +#ifdef PARAM_SUPPORT_SELINUX + if (context && fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0) != 0) { + PARAM_LOGI("fsetxattr context %s fail", context); + } +#endif + PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_NAME, "Invalid param"); + workSpace->paramSpace.compareTrieNode = CompareTrieDataNode; + workSpace->paramSpace.allocTrieNode = AllocateTrieDataNode; + int ret = InitWorkSpace(PARAM_STORAGE_PATH, &workSpace->paramSpace, onlyRead); + + workSpace->paramLabelSpace.compareTrieNode = CompareTrieNode; // 必须先设置 + workSpace->paramLabelSpace.allocTrieNode = AllocateTrieNode; + ret |= InitWorkSpace(PARAM_INFO_PATH, &workSpace->paramLabelSpace, onlyRead); + atomic_store_explicit(&workSpace->flags, WORKSPACE_FLAGS_INIT, memory_order_release); + return ret; +} + +void CloseParamWorkSpace(ParamWorkSpace *workSpace) +{ + CloseWorkSpace(&workSpace->paramSpace); + CloseWorkSpace(&workSpace->paramLabelSpace); + atomic_store_explicit(&workSpace->flags, 0, memory_order_release); +} + +int WriteParamInfo(ParamWorkSpace *workSpace, SubStringInfo *info, int subStrNumber) +{ + PARAM_CHECK(workSpace != NULL && info != NULL && subStrNumber > SUBSTR_INFO_NAME, + return PARAM_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 = CheckParamName(name, 1); + PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", name); + + // 先保存标签值 + TrieNode *node = AddTrieNode(&workSpace->paramLabelSpace, + workSpace->paramLabelSpace.rootNode, label, strlen(label)); + PARAM_CHECK(node != NULL, return PARAM_CODE_REACHED_MAX, "Failed to add label"); + u_int32_t offset = GetTrieNodeOffset(&workSpace->paramLabelSpace, node); + + TrieDataNode *dataNode = AddTrieDataNode(&workSpace->paramSpace, name, strlen(name)); + PARAM_CHECK(dataNode != NULL, return PARAM_CODE_REACHED_MAX, "Failed to add node %s", name); + TrieNode *entry = (TrieNode *)GetTrieNode(&workSpace->paramLabelSpace, &dataNode->labelIndex); + if (entry != 0) { // 已经存在label + PARAM_LOGE("Has been set label %s old label %s new label: %s", name, entry->key, label); + } + SaveIndex(&dataNode->labelIndex, offset); + return 0; +} + +int AddParam(WorkSpace *workSpace, const char *name, const char *value) +{ + PARAM_CHECK(workSpace != NULL && name != NULL && value != NULL, + return PARAM_CODE_INVALID_PARAM, "Failed to check param"); + + TrieDataNode *node = AddTrieDataNode(workSpace, name, strlen(name)); + PARAM_CHECK(node != NULL, return PARAM_CODE_REACHED_MAX, "Failed to add node"); + DataEntry *entry = (DataEntry *)GetTrieNode(workSpace, &node->dataIndex); + //PARAM_LOGI("AddParam entry %p", entry); + if (entry == NULL) { + u_int32_t offset = AddData(workSpace, name, strlen(name), value, strlen(value)); + PARAM_CHECK(offset > 0, return PARAM_CODE_REACHED_MAX, "Failed to allocate name %s", name); + SaveIndex(&node->dataIndex, offset); + //PARAM_LOGI("AddParam entry %p %u", entry, offset); + } + 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 UpdateParam(WorkSpace *workSpace, u_int32_t *dataIndex, const char *name, const char *value) +{ + PARAM_CHECK(workSpace != NULL && name != NULL && value != NULL, + return PARAM_CODE_INVALID_PARAM, "Failed to check param"); + + DataEntry *entry = (DataEntry *)GetTrieNode(workSpace, dataIndex); + PARAM_CHECK(entry != NULL, return PARAM_CODE_REACHED_MAX, + "Failed to update param value %s %u", name, *dataIndex); + u_int32_t keyLen = DATA_ENTRY_KEY_LEN(entry); + PARAM_CHECK(keyLen == strlen(name), return PARAM_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) { + PARAM_LOGE("Failed to update param value %s %s", name, value); + } + //PARAM_LOGI("UpdateParam entry %p", entry); + 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 *FindParam(WorkSpace *workSpace, const char *name) +{ + PARAM_CHECK(workSpace != NULL, return NULL, "Failed to check param"); + PARAM_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 WriteParamWithCheck(ParamWorkSpace *workSpace, + const ParamSecurityLabel *srcLabel, const char *name, const char *value) +{ + PARAM_CHECK(workSpace != NULL && srcLabel != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); + PARAM_CHECK(value != NULL && name != NULL, return PARAM_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 PARAM_CODE_NOT_INIT; + } + + int ret = CheckParamName(name, 0); + PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", name); + TrieDataNode *info = FindTrieDataNode(&workSpace->paramSpace, name, strlen(name), 1); + ret = CanWriteParam(workSpace, srcLabel, info, name, value); + //PARAM_LOGI("WriteParamWithCheck info %p", info); + PARAM_CHECK(ret == 0, return ret, "Permission to write param %s", name); + return WriteParam(&workSpace->paramSpace, name, value); +} + +int WriteParam(WorkSpace *workSpace, const char *name, const char *value) +{ + PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); + PARAM_CHECK(value != NULL && name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); + + TrieDataNode *node = FindTrieDataNode(workSpace, name, strlen(name), 0); + int ret = CheckParamValue(workSpace, node, name, value); + PARAM_CHECK(ret == 0, return ret, "Invalid value %s %s", name, value); + //PARAM_LOGI("WriteParamWithCheck node %p", node); + if (node != NULL && node->dataIndex != 0) { + return UpdateParam(workSpace, &node->dataIndex, name, value); + } + return AddParam(workSpace, name, value); +} + +int ReadParamWithCheck(ParamWorkSpace *workSpace, const char *name, ParamHandle *handle) +{ + PARAM_CHECK(handle != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); + PARAM_CHECK(workSpace != NULL && name != NULL, return PARAM_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 PARAM_CODE_NOT_INIT; + } + + *handle = 0; + // 取最长匹配 + TrieDataNode *paramInfo = FindTrieDataNode(&workSpace->paramSpace, name, strlen(name), 1); + int ret = CanReadParam(workSpace, paramInfo == NULL ? 0 : paramInfo->labelIndex, name); + PARAM_CHECK(ret == 0, return ret, "Permission to read param %s", name); + + // 查找结点 + TrieDataNode *node = FindTrieDataNode(&workSpace->paramSpace, name, strlen(name), 0); + if (node != NULL && node->dataIndex != 0) { + //PARAM_LOGI("ReadParamWithCheck trie %p dataIndex %u name %s", node, node->dataIndex, name); + *handle = node->dataIndex; + return 0; + } + return PARAM_CODE_NOT_FOUND_PROP; +} + +int ReadParamValue(ParamWorkSpace *workSpace, ParamHandle handle, char *value, u_int32_t *len) +{ + PARAM_CHECK(workSpace != NULL, return PARAM_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 PARAM_CODE_NOT_INIT; + } + DataEntry *entry = (DataEntry *)GetTrieNode(&workSpace->paramSpace, &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); + PARAM_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 ReadParamName(ParamWorkSpace *workSpace, ParamHandle handle, char *name, u_int32_t len) +{ + PARAM_CHECK(workSpace != NULL && name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); + DataEntry *entry = (DataEntry *)GetTrieNode(&workSpace->paramSpace, &handle); + if (entry == NULL) { + return -1; + } + return GetDataName(entry, name, len); +} + +u_int32_t ReadParamSerial(ParamWorkSpace *workSpace, ParamHandle handle) +{ + PARAM_CHECK(workSpace != NULL, return 0, "Invalid param"); + DataEntry *entry = (DataEntry *)GetTrieNode(&workSpace->paramSpace, &handle); + if (entry == NULL) { + return 0; + } + return GetDataSerial(entry); +} + +int CheckControlParamPerms(ParamWorkSpace *workSpace, + const ParamSecurityLabel *srcLabel, const char *name, const char *value) +{ + PARAM_CHECK(srcLabel != NULL && name != NULL && value != NULL, + return PARAM_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); + PARAM_CHECK(legacyName != NULL, return PARAM_CODE_INVALID_PARAM, "Failed to alloc memory"); + + // We check the legacy method first but these parameters are dontaudit, so we only log an audit + // if the newer method fails as well. We only do this with the legacy ctl. parameters. + for (size_t i = 0; i < sizeof(ctrlName) / sizeof(char*); i++) { + if (strcmp(name, ctrlName[i]) == 0) { + // The legacy permissions model is that ctl. parameters have their name ctl. 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. to + // check permissions. + int n = snprintf_s(legacyName, size, size, "ctl.%s", value); + PARAM_CHECK(n > 0, free(legacyName); return PARAM_CODE_INVALID_PARAM, "Failed to snprintf value"); + legacyName[n] = '\0'; + + TrieDataNode *node = FindTrieDataNode(&workSpace->paramSpace, 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); + PARAM_CHECK(n > 0, free(legacyName); return PARAM_CODE_INVALID_PARAM, "Failed to snprintf value"); + + TrieDataNode *node = FindTrieDataNode(&workSpace->paramSpace, name, strlen(name), 1); + int ret = CheckMacPerms(workSpace, srcLabel, name, node == NULL ? 0 : node->labelIndex); + free(legacyName); + return ret; +} + +int CheckParamName(const char *name, int info) +{ + size_t nameLen = strlen(name); + if (nameLen >= PARAM_VALUE_LEN_MAX) { + return PARAM_CODE_INVALID_NAME; + } + + if (nameLen < 1 || name[0] == '.' || (!info && name[nameLen - 1] == '.')) { + PARAM_LOGE("CheckParamName %s %d", name, info); + return PARAM_CODE_INVALID_NAME; + } + + /* Only allow alphanumeric, plus '.', '-', '@', ':', or '_' */ + /* Don't allow ".." to appear in a param name */ + for (size_t i = 0; i < nameLen; i++) { + if (name[i] == '.') { + if (name[i - 1] == '.') { + return PARAM_CODE_INVALID_NAME; + } + continue; + } + if (name[i] == '_' || name[i] == '-' || name[i] == '@' || name[i] == ':') { + continue; + } + if (isalnum(name[i])) { + continue; + } + return PARAM_CODE_INVALID_NAME; + } + return 0; +} + +int CheckParamValue(WorkSpace *workSpace, const TrieDataNode *node, const char *name, const char *value) +{ + if (IS_READY_ONLY(name)) { + if (node != NULL && node->dataIndex != 0) { + PARAM_LOGE("Read-only param was already set %s", name); + return PARAM_CODE_READ_ONLY_PROPERTY; + } + } else { + // 限制非read only的参数,防止参数值修改后,原空间不能保存 + PARAM_CHECK(strlen(value) < PARAM_VALUE_LEN_MAX, + return PARAM_CODE_INVALID_VALUE, "Illegal param value"); + } + return 0; +} + +int CheckMacPerms(ParamWorkSpace *workSpace, + const ParamSecurityLabel *srcLabel, const char *name, u_int32_t labelIndex) +{ +#ifdef PARAM_SUPPORT_SELINUX + ParamAuditData auditData; + auditData.name = name; + auditData.cr = &srcLabel->cred; + + int ret = 0; + TrieNode *node = (TrieNode *)GetTrieNode(&workSpace->paramLabelSpace, &labelIndex); + if (node != 0) { // 已经存在label + ret = selinux_check_access(srcLabel, node->key, "param_service", "set", &auditData); + } else { + ret = selinux_check_access(srcLabel, "u:object_r:default_prop:s0", "param_service", "set", &auditData); + } + return ret == 0 ? 0 : PARAM_CODE_PERMISSION_DENIED; +#else + return 0; +#endif +} + +int CanWriteParam(ParamWorkSpace *workSpace, + const ParamSecurityLabel *srcLabel, const TrieDataNode *node, const char *name, const char *value) +{ + PARAM_CHECK(workSpace != NULL && name != NULL && value != NULL && srcLabel != NULL, + return PARAM_CODE_INVALID_PARAM, "Invalid param"); + + if (strncmp(name, "ctl.", strlen("ctl.")) == 0) { // 处理ctrl TODO + return CheckControlParamPerms(workSpace, srcLabel, name, value); + } + + int ret = CheckMacPerms(workSpace, srcLabel, name, node == NULL ? 0 : node->labelIndex); + PARAM_CHECK(ret == 0, return ret, "SELinux permission check failed"); + return 0; +} + +int CanReadParam(ParamWorkSpace *workSpace, u_int32_t labelIndex, const char *name) +{ + PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); + PARAM_CHECK(name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); +#ifdef PARAM_SUPPORT_SELINUX + ParamAuditData auditData; + auditData.name = name; + UserCred cr = {.pid = 0, .uid = 0, .gid = 0}; + auditData.cr = &cr; + + int ret = 0; + TrieNode *node = (TrieNode *)GetTrieNode(&workSpace->paramLabelSpace, &labelIndex); + if (node != 0) { // 已经存在label + ret = selinux_check_access(&workSpace->context, node->key, "param_service", "read", &auditData); + } else { + ret = selinux_check_access(&workSpace->context, "selinux_check_access", "file", "read", &auditData); + } + return ret == 0 ? 0 : PARAM_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 spaceIsValid = 0; + 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++; + spaceIsValid = 1; + } else { + if (!spaceIsValid && isspace(buff[i])) { + continue; + } + 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 BuildParamContent(char *content, u_int32_t contentSize, const char *name, const char *value) +{ + PARAM_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); + PARAM_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'; + PARAM_CHECK(ret == 0, return -1, "Failed to copy porperty"); + offset += 1; + return offset; +} + +int ProcessParamTraversal(WorkSpace *workSpace, TrieNode *node, void *cookie) +{ + ParamTraversalContext *context = (ParamTraversalContext *)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 TraversalParam(ParamWorkSpace *workSpace, TraversalParamPtr walkFunc, void *cookie) +{ + ParamTraversalContext context = { + walkFunc, cookie + }; + return TraversalTrieDataNode(&workSpace->paramSpace, + (TrieDataNode *)workSpace->paramSpace.rootNode, ProcessParamTraversal, &context); +} \ No newline at end of file diff --git a/services/param/manager/param_trie.c b/services/param/manager/param_trie.c new file mode 100644 index 0000000000000000000000000000000000000000..b8b3b67a9b343e315fe47080aee41676a1c148a0 --- /dev/null +++ b/services/param/manager/param_trie.c @@ -0,0 +1,542 @@ +/* + * 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 "param_trie.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "init_utils.h" +#include "sys_param.h" +#include "param_manager.h" + +#define LABEL "Manager" + +int InitWorkSpace(const char *fileName, WorkSpace *workSpace, int onlyRead) +{ + PARAM_CHECK(fileName != NULL, return PARAM_CODE_INVALID_NAME, "Invalid param"); + PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_NAME, "Invalid param"); + if (workSpace->area != NULL) { + return 0; + } + + int ret = memcpy_s(workSpace->fileName, FILENAME_LEN_MAX, fileName, strlen(fileName)); + PARAM_CHECK(ret == 0, return PARAM_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, PARAM_WORKSPACE_MAX, onlyRead); + PARAM_CHECK(ret == 0, return ret, "Failed to init workspace %s", workSpace->fileName); + return ret; +} + +int InitPersistWorkSpace(const char *fileName, WorkSpace *workSpace) +{ + PARAM_CHECK(fileName != NULL, return PARAM_CODE_INVALID_NAME, "Invalid param"); + PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_NAME, "Invalid param"); + if (workSpace->area != NULL) { + return 0; + } + + int ret = memcpy_s(workSpace->fileName, FILENAME_LEN_MAX, fileName, strlen(fileName)); + PARAM_CHECK(ret == 0, return PARAM_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, PARAM_WORKSPACE_MAX, flag); + PARAM_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) +{ + PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid fileName"); + PARAM_CHECK(workSpace->allocTrieNode != NULL, + return PARAM_CODE_INVALID_PARAM, "Invalid param %s", workSpace->fileName); + PARAM_CHECK(workSpace->compareTrieNode != NULL, + return PARAM_CODE_INVALID_PARAM, "Invalid param %s", workSpace->fileName); + PARAM_LOGI("InitWorkSpace %s ", workSpace->fileName); + CheckAndCreateDir(workSpace->fileName); + + int fd = open(workSpace->fileName, mode, 00777); //0444); + PARAM_CHECK(fd >= 0, return PARAM_CODE_INVALID_NAME, + "Open file %s fail error %s", workSpace->fileName, strerror(errno)); + + if (!readOnly) { + lseek(fd, spaceSize - 1, SEEK_SET); + write(fd, "", 1); + } + void *areaAddr = (void *)mmap(NULL, spaceSize, prot, MAP_SHARED, fd, 0); + PARAM_CHECK(areaAddr != MAP_FAILED, close(fd); return PARAM_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); + } + PARAM_LOGI("InitWorkSpace success, readOnly %d currOffset %u firstNode %u dataSize %u", + readOnly, workSpace->area->currOffset, workSpace->area->firstNode, workSpace->area->dataSize); + return 0; +} + +void CloseWorkSpace(WorkSpace *workSpace) +{ + PARAM_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) +{ + PARAM_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; + len = (len + 0x03) & (~0x03); + PARAM_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); + PARAM_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; + len = (len + 0x03) & (~0x03); + PARAM_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); + PARAM_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) +{ + PARAM_CHECK(workSpace->allocTrieNode != NULL, return NULL, "Invalid param %s", key); + PARAM_CHECK(workSpace->compareTrieNode != NULL, return NULL, "Invalid param %s", key); + + const char *remainingKey = key; + TrieDataNode *current = (TrieDataNode *)workSpace->rootNode; + PARAM_CHECK(current != NULL, return NULL, "Invalid current param %s", key); + 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); + PARAM_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); + PARAM_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); + PARAM_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) +{ + PARAM_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); + PARAM_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); + PARAM_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) +{ + PARAM_CHECK(workSpace->allocTrieNode != NULL, return NULL, "Invalid param %s", key); + PARAM_CHECK(workSpace->compareTrieNode != NULL, return NULL, "Invalid param %s", key); + + const char *remainingKey = key; + TrieDataNode *matchNode = (TrieDataNode *)workSpace->rootNode; + TrieDataNode *current = (TrieDataNode *)workSpace->rootNode; + PARAM_CHECK(current != NULL, return NULL, "Invalid current param %s", key); + 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) +{ + PARAM_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) +{ + PARAM_CHECK(walkFunc != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); + PARAM_CHECK(workSpace != NULL, return PARAM_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) +{ + PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); + PARAM_CHECK(walkFunc != NULL, return PARAM_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) +{ + PARAM_CHECK(workSpace != NULL, return 0, "Invalid param"); + PARAM_CHECK(key != NULL && value != NULL, return 0, "Invalid param"); + u_int32_t realLen = sizeof(DataEntry) + 1 + 1; + if (valueLen > PARAM_VALUE_LEN_MAX) { + realLen += keyLen + valueLen; + } else { + realLen += keyLen + PARAM_VALUE_LEN_MAX; + } + realLen = (realLen + 0x03) & (~0x03); + //PARAM_LOGI("AddData realLen %u %u %u", realLen, keyLen, valueLen); + PARAM_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); + PARAM_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; + //PARAM_LOGI("AddData node %p %u %d", node, offset, gettid()); + return offset; +} + +int UpdateDataValue(DataEntry *entry, const char *value) +{ + PARAM_CHECK(entry != NULL && value != NULL, return PARAM_CODE_INVALID_PARAM, "Failed to check param"); + int ret = PARAM_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 < PARAM_VALUE_LEN_MAX && valueLen < PARAM_VALUE_LEN_MAX) { + PARAM_LOGE("Old value %s new value %s", entry->data + keyLen + 1, value); + ret = memcpy_s(entry->data + keyLen + 1, PARAM_VALUE_LEN_MAX, value, valueLen + 1); + PARAM_CHECK(ret == 0, return PARAM_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) +{ + PARAM_CHECK(entry != NULL && name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); + u_int32_t keyLen = DATA_ENTRY_KEY_LEN(entry); + PARAM_CHECK(len > keyLen, return -1, "Invalid param size"); + int ret = memcpy_s(name, len, entry->data, keyLen); + PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_PARAM, "Failed to copy name"); + name[keyLen] = '\0'; + return ret; +} + +int GetDataValue(const DataEntry *entry, char *value, u_int32_t len) +{ + PARAM_CHECK(entry != NULL && value != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); + u_int32_t keyLen = DATA_ENTRY_KEY_LEN(entry); + u_int32_t valueLen = DATA_ENTRY_DATA_LEN(entry); + PARAM_CHECK(len > valueLen, return PARAM_CODE_INVALID_PARAM, "Invalid value len %u %u", len, valueLen); + int ret = memcpy_s(value, len, entry->data + keyLen + 1, valueLen); + PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_PARAM, "Failed to copy value"); + value[valueLen] = '\0'; + return ret; +} diff --git a/services/param/service/param_persist.c b/services/param/service/param_persist.c new file mode 100644 index 0000000000000000000000000000000000000000..d538dd5351ab65d31daf810fef2bf6c226239189 --- /dev/null +++ b/services/param/service/param_persist.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "sys_param.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "param_manager.h" +#include "param_trie.h" + +#define LABEL "Manager" +#define MAX_BUFF 256 + +typedef struct { + WorkSpace *workSpace; + WorkSpace *persistWorkSpace; + char *buffer; +} PersistContext; + +static ParamPersistWorkSpace g_persistWorkSpace = {ATOMIC_VAR_INIT(0), }; + +static int ProcessParamTraversal(WorkSpace *workSpace, TrieNode *node, void *cookie) +{ + PARAM_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) { // 只支持新建 + //PARAM_LOGI("Insert new persist param from normal param %s %s", + // persistContext->buffer, persistContext->buffer + MAX_BUFF); + ret = AddParam(persistContext->persistWorkSpace, persistContext->buffer, persistContext->buffer + MAX_BUFF); + } + PARAM_CHECK(ret == 0, return ret, "Failed to add persist param"); + 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) { + //PARAM_LOGI("update normal param %s %s from persist param %u", + // persistContext->buffer, persistContext->buffer + MAX_BUFF, current->dataIndex); + ret = WriteParam(persistContext->workSpace, persistContext->buffer, persistContext->buffer + MAX_BUFF); + } + PARAM_CHECK(ret == 0, return ret, "Failed to add persist param"); + return ret; +} + +int InitPersistParamWorkSpace(const char *context) +{ + u_int32_t flags = atomic_load_explicit(&g_persistWorkSpace.flags, memory_order_relaxed); + if ((flags & WORKSPACE_FLAGS_INIT) == WORKSPACE_FLAGS_INIT) { + return 0; + } + g_persistWorkSpace.persistWorkSpace.compareTrieNode = CompareTrieDataNode; + g_persistWorkSpace.persistWorkSpace.allocTrieNode = AllocateTrieDataNode; + int ret = InitPersistWorkSpace(PARAM_PERSIST_PATH, &g_persistWorkSpace.persistWorkSpace); + PARAM_CHECK(ret == 0, return ret, "Failed to init persist param"); + atomic_store_explicit(&g_persistWorkSpace.flags, WORKSPACE_FLAGS_INIT, memory_order_release); + return ret; +} + +int RefreshPersistParams(ParamWorkSpace *workSpace, const char *context) +{ + int ret = InitPersistParamWorkSpace(context); + PARAM_CHECK(ret == 0, return ret, "Failed to init persist param"); + u_int32_t flags = atomic_load_explicit(&g_persistWorkSpace.flags, memory_order_relaxed); + if ((flags & WORKSPACE_FLAGS_LOADED) == WORKSPACE_FLAGS_LOADED) { + PARAM_LOGE("RefreshPersistParams has been loaded"); + return 0; + } + + // 申请临时的缓存,用于数据读取 + char *buffer = (char *)malloc(MAX_BUFF + MAX_BUFF); + PARAM_CHECK(buffer != NULL, return -1, "Failed to malloc memory for param"); + PersistContext persistContext = { + &workSpace->paramSpace, &g_persistWorkSpace.persistWorkSpace, buffer + }; + + // 遍历当前的参数,并把persist的写入 + ret = TraversalTrieDataNode(&workSpace->paramSpace, + (TrieDataNode *)workSpace->paramSpace.rootNode, ProcessParamTraversal, &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 ClosePersistParamWorkSpace() +{ + CloseWorkSpace(&g_persistWorkSpace.persistWorkSpace); + atomic_store_explicit(&g_persistWorkSpace.flags, 0, memory_order_release); +} + +int WritePersistParam(const char *name, const char *value) +{ + PARAM_CHECK(value != NULL && name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); + if (strncmp(name, "persist.", strlen("persist.")) != 0) { + return 0; + } + int ret = InitPersistParamWorkSpace(""); + PARAM_CHECK(ret == 0, return ret, "Failed to init persist param"); + u_int32_t flags = atomic_load_explicit(&g_persistWorkSpace.flags, memory_order_relaxed); + if ((flags & WORKSPACE_FLAGS_LOADED) != WORKSPACE_FLAGS_LOADED) { + return 0; + } + return WriteParam(&g_persistWorkSpace.persistWorkSpace, name, value); +} diff --git a/services/param/service/param_service.c b/services/param/service/param_service.c new file mode 100644 index 0000000000000000000000000000000000000000..bea25c1d0998a896e49eb2853d6f277246e66dbd --- /dev/null +++ b/services/param/service/param_service.c @@ -0,0 +1,276 @@ +/* + * 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 "param_service.h" + +#include +#include +#include +#include + +#include "sys_param.h" +#include "param_manager.h" +#include "param_request.h" +#include "init_param.h" + +#include "uv.h" + +#define BUFFER_SIZE 256 +#define LABEL "Server" + +static char *g_initContext = ""; +static ParamWorkSpace g_paramWorkSpace = {ATOMIC_VAR_INIT(0), {}, {}, {}}; + +void InitParamService() +{ + int ret = InitParamWorkSpace(&g_paramWorkSpace, 0, g_initContext); + PARAM_CHECK(ret == 0, return, "Init parameter workspace fail"); +} + +int LoadDefaultParams(const char *fileName) +{ + u_int32_t flags = atomic_load_explicit(&g_paramWorkSpace.flags, memory_order_relaxed); + if ((flags & WORKSPACE_FLAGS_INIT) != WORKSPACE_FLAGS_INIT) { + return PARAM_CODE_NOT_INIT; + } + + FILE *fp = fopen(fileName, "r"); + PARAM_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), '=', info, SUBSTR_INFO_LABEL + 1); + if (subStrNumber <= SUBSTR_INFO_LABEL) { + continue; + } + + if (strncmp(info[0].value, "ctl.", strlen("ctl.")) == 0) { + PARAM_LOGE("Do not set ctl. parameters from init %s", info[0].value); + continue; + } + if (strcmp(info[0].value, "selinux.restorecon_recursive") == 0) { + PARAM_LOGE("Do not set selinux.restorecon_recursive from init %s", info[0].value); + continue; + } + int ret = CheckParamName(info[0].value, 0); + PARAM_CHECK(ret == 0, continue, "Illegal param name %s", info[0].value); + + ret = WriteParam(&g_paramWorkSpace.paramSpace, info[0].value, info[1].value); + PARAM_CHECK(ret == 0, continue, "Failed to set param %d %s", ret, buff); + } + fclose(fp); + free(info); + PARAM_LOGI("LoadDefaultParams proterty success %s", fileName); + return 0; +} + +int LoadParamInfos(const char *fileName) +{ + u_int32_t flags = atomic_load_explicit(&g_paramWorkSpace.flags, memory_order_relaxed); + if ((flags & WORKSPACE_FLAGS_INIT) != WORKSPACE_FLAGS_INIT) { + return PARAM_CODE_NOT_INIT; + } + FILE *fp = fopen(fileName, "r"); + PARAM_CHECK(fp != NULL, return -1, "Open file %s fail", fileName); + SubStringInfo *info = malloc(sizeof(SubStringInfo) * SUBSTR_INFO_MAX); + char buff[BUFFER_SIZE]; + int infoCount = 0; + while(fgets(buff, BUFFER_SIZE, fp) != NULL) { + int subStrNumber = GetSubStringInfo(buff, strlen(buff), ' ', info, SUBSTR_INFO_MAX); + if (subStrNumber <= 0) { + continue; + } + int ret = WriteParamInfo(&g_paramWorkSpace, info, subStrNumber); + PARAM_CHECK(ret == 0, continue, "Failed to write param info %d %s", ret, buff); + infoCount++; + } + fclose(fp); + free(info); + PARAM_LOGI("Load parameter info %d success %s", infoCount, fileName); + return 0; +} + +static int ProcessParamSet(RequestMsg *msg) +{ + PARAM_CHECK(msg != NULL, return PARAM_CODE_INVALID_PARAM, "Failed to check param"); + + SubStringInfo info[3]; + int ret = GetSubStringInfo(msg->content, msg->contentSize, '=', info, sizeof(info)/sizeof(info[0])); + PARAM_CHECK(ret >= 2, return ret, "Failed to get name from content %s", msg->content); + + PARAM_LOGI("ProcessParamSet name %s value: %s", info[0].value, info[1].value); + ret = WriteParamWithCheck(&g_paramWorkSpace, &msg->securitylabel, info[0].value, info[1].value); + PARAM_CHECK(ret == 0, return ret, "Failed to set param %d name %s %s", ret, info[0].value, info[1].value); + ret = WritePersistParam(info[0].value, info[1].value); + PARAM_CHECK(ret == 0, return ret, "Failed to set param"); + // 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->len = sizeof(RequestMsg) + BUFFER_SIZE * 2; + buf->base = (char *)malloc(buf->len); +} + +static void OnWriteResponse(uv_write_t *req, int status) +{ + // 发送成功,释放请求内存 + PARAM_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); + PARAM_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); + PARAM_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); + PARAM_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_PARAM: { + freeHandle = 0; + int ret = ProcessParamSet(msg); + SendResponse(handle, SET_PARAM, ret, NULL, 0); + break; + } + default: + PARAM_LOGE("not supported the command: %d", msg->type); + break; + } + free(buf->base); + uv_close((uv_handle_t*)handle, OnClose); +} + +static void OnConnection(uv_stream_t *server, int status) +{ + PARAM_CHECK(status >= 0, return, "Error status %d", status); + PARAM_CHECK(server != NULL, return, "Error server"); + uv_pipe_t *stream = (uv_pipe_t*)malloc(sizeof(uv_pipe_t)); + PARAM_CHECK(stream != NULL, return, "Failed to alloc stream"); + + int ret = uv_pipe_init(uv_default_loop(), (uv_pipe_t*)stream, 1); + PARAM_CHECK(ret == 0, free(stream); return, "Failed to uv_pipe_init %d", ret); + + stream->data = server; + ret = uv_accept(server, (uv_stream_t *)stream); + PARAM_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); + PARAM_CHECK(ret == 0, uv_close((uv_handle_t*)stream, NULL); free(stream); + return, "Failed to uv_read_start %d", ret); +} + +void StopParamService() +{ + uv_fs_t req; + uv_fs_unlink(uv_default_loop(), &req, PIPE_NAME, NULL); + CloseParamWorkSpace(&g_paramWorkSpace); + ClosePersistParamWorkSpace(); + uv_stop(uv_default_loop()); + PARAM_LOGI("StopParamService."); +} + +int StartParamService() +{ + PARAM_LOGI("StartParamService."); + uv_fs_t req; + uv_fs_unlink(uv_default_loop(), &req, PIPE_NAME, NULL); + + uv_pipe_t pipeServer; + int ret = uv_pipe_init(uv_default_loop(), &pipeServer, 0); + PARAM_CHECK(ret == 0, return ret, "Failed to uv_pipe_init %d", ret); + ret = uv_pipe_bind(&pipeServer, PIPE_NAME); + PARAM_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); + PARAM_CHECK(ret == 0, return ret, "Failed to uv_listen %d %s", ret, uv_err_name(ret)); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + PARAM_LOGI("Start service exit."); + return 0; +} + +int SystemWriteParam(const char *name, const char *value) +{ + PARAM_CHECK(name != NULL && value != NULL, return -1, "The name is null"); + PARAM_LOGI("SystemWriteParam name %s value: %s", name, value); + int ret = WriteParamWithCheck(&g_paramWorkSpace, &g_paramWorkSpace.label, name, value); + //PARAM_LOGI("SystemWriteParam name %s value: %s", name, value); + if (ret == 0) { + ret = WritePersistParam(name, value); + PARAM_CHECK(ret == 0, return ret, "Failed to set param"); + } else { + PARAM_LOGE("Failed to set param %d name %s %s", ret, name, value); + } + // notify event to process trigger + PostParamTrigger(name, value); + return 0; +} + +int SystemReadParam(const char *name, char *value, unsigned int *len) +{ + PARAM_CHECK(name != NULL && len != NULL, return -1, "The name is null"); + ParamHandle handle = 0; + int ret = ReadParamWithCheck(&g_paramWorkSpace, name, &handle); + if (ret == 0) { + ret = ReadParamValue(&g_paramWorkSpace, handle, value, len); + } + return ret; +} + +ParamWorkSpace *GetParamWorkSpace() +{ + return &g_paramWorkSpace; +} + +int LoadPersistParams() +{ + return RefreshPersistParams(&g_paramWorkSpace, g_initContext); +} + +int SystemTraversalParam(void (*traversalParameter)(ParamHandle handle, void* cookie), void* cookie) +{ + PARAM_CHECK(traversalParameter != NULL, return -1, "The param is null"); + return TraversalParam(&g_paramWorkSpace, traversalParameter, cookie); +} \ No newline at end of file diff --git a/services/param/trigger/trigger_checker.c b/services/param/trigger/trigger_checker.c new file mode 100644 index 0000000000000000000000000000000000000000..618641545c946c4a1fb1f25a0e6857b712d8b54c --- /dev/null +++ b/services/param/trigger/trigger_checker.c @@ -0,0 +1,296 @@ +/* + * 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 +#include "trigger_manager.h" +#include "param_service.h" + +#define LABEL "Trigger" +// 申请整块能存作为计算的节点 +int CalculatorInit(LogicCalculator *calculator, int dataNumber, int dataUnit, int needCondition) +{ + PARAM_CHECK(calculator != NULL, return -1, "Invalid param"); + int dataSize = dataUnit * dataNumber; + if (needCondition) { + dataSize += 5 * SUPPORT_DATA_BUFFER_MAX; + } + calculator->data = (char *)malloc(dataSize); + PARAM_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) +{ + PARAM_CHECK(calculator != NULL, return, "Invalid param"); + free(calculator->data); + calculator->data = NULL; +} + +static void CalculatorClear(LogicCalculator *calculator) +{ + PARAM_CHECK(calculator != NULL, return, "Invalid param"); + calculator->endIndex = 0; +} + +static int CalculatorPushChar(LogicCalculator *calculator, char data) +{ + PARAM_CHECK(calculator != NULL, return -1, "Invalid param"); + PARAM_CHECK(calculator->endIndex < calculator->dataNumber, return -1, "More data for calculator support"); + PARAM_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) +{ + PARAM_CHECK(calculator != NULL, return -1, "Invalid param"); + PARAM_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) +{ + PARAM_CHECK(calculator != NULL, return -1, "Invalid param"); + PARAM_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); + PARAM_CHECK(ret == 0, return -1, "Failed to copy logic data"); + calculator->endIndex++; + return 0; +} + +static int CalculatorPop(LogicCalculator *calculator, void *data) +{ + PARAM_CHECK(calculator != NULL || data == NULL, return -1, "Invalid param"); + PARAM_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); + PARAM_CHECK(ret == 0, return -1, "Failed to copy logic data"); + calculator->endIndex--; + return 0; +} + +static int CalculatorLength(const LogicCalculator *calculator) +{ + PARAM_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); + PARAM_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); + PARAM_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); + PARAM_CHECK(ret == 0, return -1, "Failed parse content value"); + // 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 = SystemReadParam(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); + PARAM_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); + PARAM_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); + PARAM_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); + PARAM_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); + PARAM_CHECK(ret == 0, CalculatorFree(&calculator); return -1, "Invalid prefix"); + ret = CalculatorPopChar(&calculator, &e); + PARAM_CHECK(ret == 0, CalculatorFree(&calculator); return -1, "Invalid calculator"); + } + } else if (condition[curr] == '|') { + PARAM_CHECK(condition[curr + 1] == '|', CalculatorFree(&calculator); return -1, "Invalid condition"); + ret = HandleOperationOr(&calculator, prefix, &prefixIndex, prefixLen); + PARAM_CHECK(ret == 0, CalculatorFree(&calculator); return -1, "Invalid prefix"); + curr++; + } else if (condition[curr] == '&') { + PARAM_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++; + PARAM_CHECK(prefixIndex < prefixLen, CalculatorFree(&calculator); return -1, "Invalid prefixIndex"); + } + + while (CalculatorLength(&calculator) > 0) { + CalculatorPopChar(&calculator, &e); + ret = PrefixAdd(prefix, &prefixIndex, prefixLen, e); + PARAM_CHECK(ret == 0, CalculatorFree(&calculator); + return -1, "Invalid prefix %u %u", prefixIndex, prefixLen); + } + prefix[prefixIndex] = '\0'; + CalculatorFree(&calculator); + return 0; +} \ No newline at end of file diff --git a/services/param/trigger/trigger_manager.c b/services/param/trigger/trigger_manager.c new file mode 100644 index 0000000000000000000000000000000000000000..3b187d7449450bfee990283b3aff398279a435e3 --- /dev/null +++ b/services/param/trigger/trigger_manager.c @@ -0,0 +1,388 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "init_cmds.h" +#include "init_utils.h" +#include "trigger_checker.h" + +#define LABEL "Trigger" +#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) +{ + PARAM_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); + PARAM_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); + PARAM_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; + PARAM_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) +{ + PARAM_CHECK(workSpace != NULL && trigger != NULL, return 0, "list is null"); + u_int32_t size = sizeof(CommandNode) + strlen(cmdName) + 1; + size += (content == NULL) ? 1 : strlen(content) + 1; + PARAM_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); + PARAM_CHECK(node != NULL, return 0, "Failed to alloc memory for command"); + + int ret = memcpy_s(node->name, sizeof(node->name) - 1, cmdName, strlen(cmdName)); + PARAM_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'; + PARAM_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; + PARAM_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) +{ + PARAM_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; + PARAM_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); + PARAM_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)); + PARAM_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); + PARAM_CHECK(ret == 0, return 0, "Failed to memcpy_s for trigger"); + } else { + ret = memcpy_s(node->condition, strlen(tmpCond) + 1, tmpCond, strlen(tmpCond)); + PARAM_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("param", type, strlen("param")) == 0) { + return TRIGGER_PROPERTY; + } + static const char *triggerType[] = { + "pre-init", "boot", "early-init", "init", "early-init", "late-init", "post-init", + "early-fs", "post-fs", "late-fs", "post-fs-data", + "nonencrypted", + "firmware_mounts_complete", + "load_persist_params_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_BOOT; +} + +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) +{ + PARAM_CHECK(triggerItem != NULL, return -1, "Invalid file"); + PARAM_CHECK(workSpace != NULL, return -1, "Failed to create trigger list"); + + char *name = cJSON_GetStringValue(cJSON_GetObjectItem(triggerItem, "name")); + PARAM_CHECK(name != NULL, return -1, "Can not get name from cfg"); + char *condition = cJSON_GetStringValue(cJSON_GetObjectItem(triggerItem, "condition")); + + int index = GetTriggerIndex(name); + PARAM_CHECK(CHECK_INDEX_VALID(workSpace, index), return -1, "Failed to get trigger index"); + + u_int32_t offset = 0; + TriggerNode *trigger = GetTriggerByName(workSpace, name, &offset); + if (trigger == NULL) { + offset = AddTrigger(workSpace, index, name, condition); + PARAM_CHECK(offset > 0, return -1, "Failed to create trigger %s", name); + trigger = GetTriggerByIndex(workSpace, offset); + } else { + if (condition != NULL) { + PARAM_LOGE("Warning parseTrigger %s %s", name, condition); + } + } + PARAM_LOGE("ParseTrigger %s %u", name, offset); + + // 添加命令行 + cJSON* cmdItems = cJSON_GetObjectItem(triggerItem, CMDS_ARR_NAME_IN_JSON); + PARAM_CHECK(cJSON_IsArray(cmdItems), return -1, "Command item must be array"); + int cmdLinesCnt = cJSON_GetArraySize(cmdItems); + PARAM_CHECK(cmdLinesCnt > 0, return -1, "Command array size must positive %s", name); + + for (int i = 0; i < cmdLinesCnt; ++i) { + char *cmdLineStr = cJSON_GetStringValue(cJSON_GetArrayItem(cmdItems, i)); + PARAM_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; + } + PARAM_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); + } + //PARAM_LOGE("AddCommand %u %s %u", offset, cmdLineStr, workSpace->area->currOffset); + PARAM_CHECK(offset > 0, continue, "Failed to add command %s", cmdLineStr); + } + return 0; +} + +int ExecuteTrigger(TriggerWorkSpace *workSpace, TriggerNode *trigger, CMD_EXECUTE cmdExecuter) +{ + PARAM_CHECK(workSpace != NULL && trigger != NULL && cmdExecuter != NULL, return -1, "Invalid param"); + PARAM_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) +{ + PARAM_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) +{ + PARAM_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, PARAM_CHECK_DONE triggerExecuter) +{ + static TRIGGER_MATCH triggerCheckMatch[TRIGGER_MAX] = { + CheckBootTriggerMatch, NULL, NULL + }; + PARAM_LOGI("ExecuteTrigger check content %s", (char*)content); + PARAM_CHECK(workSpace != NULL, return -1, "Trigger not init"); + PARAM_CHECK(CHECK_INDEX_VALID(workSpace, type), return -1, "Invalid type %d", type); + PARAM_CHECK((u_int32_t)type < sizeof(triggerCheckMatch) / sizeof(triggerCheckMatch[0]), + return -1, "Failed to get check function"); + PARAM_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 CheckParamTrigger(TriggerWorkSpace *workSpace, + const char *content, u_int32_t contentSize, PARAM_CHECK_DONE triggerExecuter) +{ + PARAM_CHECK(workSpace != NULL && content != NULL && triggerExecuter != NULL, + return -1, "Failed arg for param trigger"); + LogicCalculator calculator; + CalculatorInit(&calculator, 100, sizeof(LogicData), 1); + + // 先解析content + int ret = GetValueFromContent(content, contentSize, 0, calculator.inputName, SUPPORT_DATA_BUFFER_MAX); + PARAM_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); + PARAM_CHECK(ret == 0, CalculatorFree(&calculator); return -1, "Failed parse content value"); + PARAM_LOGI("CheckParamTrigger content %s ", content); + + u_int32_t index = workSpace->header[TRIGGER_PROPERTY].firstTrigger; + TriggerNode *trigger = GetTriggerByIndex(workSpace, workSpace->header[TRIGGER_PROPERTY].firstTrigger); + while (trigger != NULL) { + 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) +{ + PARAM_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; +} \ No newline at end of file diff --git a/services/param/trigger/trigger_processor.c b/services/param/trigger/trigger_processor.c new file mode 100644 index 0000000000000000000000000000000000000000..de154b5e13c9948131b693414859a9e401dac6d7 --- /dev/null +++ b/services/param/trigger/trigger_processor.c @@ -0,0 +1,215 @@ +/* + * 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 +#include + +#include "init_cmds.h" +#include "param_manager.h" +#include "trigger_checker.h" +#include "uv.h" + +#define LABEL "Trigger" +#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) +{ + PARAM_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)) { // 不在队列中 + PARAM_LOGI("DoCmdExecute trigger %s", node->name); + TRIGGER_NODE_SET_QUEUE_FLAG(node); + ExecuteQueuePush(&g_triggerWorkSpace, node, triggerIndex); + } + return 0; + } + PARAM_LOGI("DoCmdExecute trigger %s cmd %s %s", trigger->name, cmdName, command); + DoCmdByName(cmdName, command); + return 0; +} + +static int DoTiggerCheckResult(TriggerNode *trigger, u_int32_t triggerIndex) +{ + // 已经在队列中了,则不执行 TODO + if (TRIGGER_NODE_IN_QUEUE(trigger)) { + PARAM_LOGI("DoTiggerExecute trigger %s has been waiting execute", trigger->name); + return 0; + } + TRIGGER_NODE_SET_QUEUE_FLAG(trigger); + PARAM_LOGI("Waiting to exec trigger %s", trigger->name); + ExecuteQueuePush(&g_triggerWorkSpace, trigger, triggerIndex); + return 0; +} + +void ExecuteQueueWork(u_int32_t maxCount) +{ + PARAM_LOGI("ExecuteQueueWork %d %d", getpid(), gettid()); + u_int32_t executeCount = 0; + TriggerNode *trigger = ExecuteQueuePop(&g_triggerWorkSpace); + while (trigger != NULL) { + ExecuteTrigger(&g_triggerWorkSpace, trigger, DoCmdExecute); + TRIGGER_NODE_CLEAR_QUEUE_FLAG(trigger); + executeCount++; + if (executeCount > maxCount) { + break; + } + PARAM_LOGI("ExecuteQueueWork %u", executeCount); + trigger = ExecuteQueuePop(&g_triggerWorkSpace); + } +} + +static void CheckTriggers(int type, void *content, u_int32_t contentLen) +{ + switch (type) { + case EVENT_PROPERTY: { + CheckParamTrigger(&g_triggerWorkSpace, content, contentLen, DoTiggerCheckResult); + break; + } + case EVENT_BOOT: { + CheckTrigger(&g_triggerWorkSpace, TRIGGER_BOOT, content, contentLen, DoTiggerCheckResult); + break; + } + default: + PARAM_LOGI("CheckTriggers: %d", type); + break; + } +} + +static void ProcessAfterEvent(uv_work_t *req, int status) +{ + free(req); + ExecuteQueueWork(UINT32_MAX); +} + +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)); + PARAM_CHECK(ret == 0, return NULL, "Failed parse cmd"); + u_int32_t cmdLen = strlen(cmd); + PARAM_CHECK(cmdLen < MAX_CMD_NAME_LEN, return NULL, "Failed parse cmd"); + cmd[cmdLen] = ' '; + cmd[cmdLen + 1] = '\0'; + *cmdParam = (char *)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 { + PARAM_LOGE("SendTriggerEvent cmd %s not found", event->content); + } + } + else if (event->type == EVENT_BOOT || g_triggerServiceStart == 0) { + CheckTriggers(event->type, event->content, event->contentSize); + ExecuteQueueWork(UINT32_MAX); // 需要立刻执行 + } else { + uv_queue_work(uv_default_loop(), &event->request, ProcessEvent, ProcessAfterEvent); + event = NULL; + } + if (event != NULL) { + free(event); + } +} + +void PostParamTrigger(const char *name, const char *value) +{ + PARAM_CHECK(name != NULL && value != NULL, return, "Invalid param"); + PARAM_LOGI("PostParamTrigger %s ", name); + int contentLen = strlen(name) + strlen(value) + 2; + TriggerDataEvent *event = (TriggerDataEvent *)malloc(sizeof(TriggerDataEvent) + contentLen); + PARAM_CHECK(event != NULL, return, "Failed to alloc memory"); + event->type = EVENT_PROPERTY; + event->request.data = (char*)event + sizeof(uv_work_t); + event->contentSize = BuildParamContent(event->content, contentLen, name, value); + PARAM_CHECK(event->contentSize > 0, return, "Failed to copy porperty"); + SendTriggerEvent(event); + PARAM_LOGI("PostParamTrigger %s success", name); +} + +void PostTrigger(EventType type, void *content, u_int32_t contentLen) +{ + PARAM_LOGI("PostTrigger %d", type); + PARAM_CHECK(content != NULL && contentLen > 0, return, "Invalid param"); + TriggerDataEvent *event = (TriggerDataEvent *)malloc(sizeof(TriggerDataEvent) + contentLen + 1); + PARAM_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); + PARAM_LOGI("PostTrigger %d success", type); +} + +void StartTriggerService() +{ + PARAM_LOGI("StartTriggerService "); + g_triggerServiceStart = 1; +} + +int ParseTriggerConfig(cJSON *fileRoot) +{ + PARAM_CHECK(fileRoot != NULL, return -1, "Invalid file"); + int ret = InitTriggerWorkSpace(&g_triggerWorkSpace); + PARAM_CHECK(ret == 0, return -1, "Failed to init trigger"); + + cJSON *triggers = cJSON_GetObjectItemCaseSensitive(fileRoot, TRIGGER_ARR_NAME_IN_JSON); + PARAM_CHECK(cJSON_IsArray(triggers), return -1, "Trigger item must array"); + + int size = cJSON_GetArraySize(triggers); + PARAM_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) +{ + PARAM_CHECK(content != NULL, return, "Invalid trigger content"); + u_int32_t triggerIndex = 0; + TriggerNode *trigger = GetTriggerByName(&g_triggerWorkSpace, content, &triggerIndex); + if (trigger != NULL && !TRIGGER_NODE_IN_QUEUE(trigger)) { // 不在队列中 + PARAM_LOGI("DoTriggerExec trigger %s", trigger->name); + TRIGGER_NODE_SET_QUEUE_FLAG(trigger); + ExecuteQueuePush(&g_triggerWorkSpace, trigger, triggerIndex); + } + ExecuteQueueWork(UINT32_MAX); // 需要立刻执行 +} + +TriggerWorkSpace *GetTriggerWorkSpace() +{ + return &g_triggerWorkSpace; +} \ No newline at end of file diff --git a/services/reboot/BUILD.gn b/services/reboot/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..724a5cfc46eb439e6cfa1599b2b336e59e4cdf67 --- /dev/null +++ b/services/reboot/BUILD.gn @@ -0,0 +1,30 @@ +# 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_executable("reboot") { + sources = [ + "init_cmd_reboot.c", + ] + include_dirs = [ + "//base/startup/init_lite/interfaces/innerkits/include", + "//base/startup/init_lite/services/include/param/", + "//third_party/bounds_checking_function/include", + ] + deps = [ + "//base/startup/init_lite/interfaces/innerkits/reboot:libreboot", + ] + install_enable = true + part_name = "init" +} diff --git a/services/reboot/init_cmd_reboot.c b/services/reboot/init_cmd_reboot.c new file mode 100644 index 0000000000000000000000000000000000000000..bf6dba27fabc6826ea82011654e89f010cab63b8 --- /dev/null +++ b/services/reboot/init_cmd_reboot.c @@ -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 +#include +#include +#include "init_reboot_api.h" + +int main(int argc, char* argv[]) +{ + if (argc > 2) { + printf("usage: reboot shutdown\n reboot updater\n reboot updater[:options]\n reboot\n"); + return 0; + } + if (argc == 2 && strcmp(argv[1], "shutdown") != 0 && + strcmp(argv[1], "updater") != 0 && + strncmp(argv[1], "updater:", strlen("updater:")) != 0 ) { + printf("usage: reboot shutdown\n reboot updater\n reboot updater[:options]\n reboot\n"); + return 0; + } + int ret = 0; + if (argc == 2) { + ret = DoRebootApi(argv[1]); + } else { + ret = DoRebootApi("NoArgument"); + } + if (ret != 0) { + printf("[reboot command] DoRebootApi return error\n"); + } else { + printf("[reboot command] DoRebootApi return ok\n"); + } + while (1) { + pause(); + } + return 0; +} + diff --git a/services/src/device.c b/services/src/device.c old mode 100755 new mode 100644 index 84013a2cbf376ed2ab91a7b59036ff5ec844edf2..d9e9dfffe0c2da92b7540e42f07e5312a1606d7b --- a/services/src/device.c +++ b/services/src/device.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include "init_log.h" #define DEFAULT_RW_MODE 0666 #define DEFAULT_NO_AUTHORITY_MODE 0600 @@ -30,29 +32,50 @@ void MountBasicFs() { if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755") != 0) { - printf("Mount tmpfs failed. %s\n", strerror(errno)); + INIT_LOGE("Mount tmpfs failed. %s\n", strerror(errno)); } if (mount("proc", "/proc", "proc", 0, "hidepid=2") != 0) { - printf("Mount procfs failed. %s\n", strerror(errno)); + INIT_LOGE("Mount procfs failed. %s\n", strerror(errno)); } if (mount("sysfs", "/sys", "sysfs", 0, NULL) != 0) { - printf("Mount sysfs failed. %s\n", strerror(errno)); + INIT_LOGE("Mount sysfs failed. %s\n", strerror(errno)); } +#ifndef __LITEOS__ + if (mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL) != 0) { + INIT_LOGE("Mount selinuxfs failed. %s\n", strerror(errno)); + } +#endif } void CreateDeviceNode() { if (mknod("/dev/kmsg", S_IFCHR | DEFAULT_NO_AUTHORITY_MODE, makedev(1, DEVICE_ID_ELEVNTH)) != 0) { - printf("Create /dev/kmsg device node failed. %s\n", strerror(errno)); + INIT_LOGE("Create /dev/kmsg device node failed. %s\n", strerror(errno)); } if (mknod("/dev/null", S_IFCHR | DEFAULT_RW_MODE, makedev(1, DEVICE_ID_THIRD)) != 0) { - printf("Create /dev/null device node failed. %s\n", strerror(errno)); + INIT_LOGE("Create /dev/null device node failed. %s\n", strerror(errno)); } if (mknod("/dev/random", S_IFCHR | DEFAULT_RW_MODE, makedev(1, DEVICE_ID_EIGHTH)) != 0) { - printf("Create /dev/random device node failed. %s\n", strerror(errno)); + INIT_LOGE("Create /dev/random device node failed. %s\n", strerror(errno)); } if (mknod("/dev/urandom", S_IFCHR | DEFAULT_RW_MODE, makedev(1, DEVICE_ID_NINTH)) != 0) { - printf("Create /dev/urandom device node failed. %s\n", strerror(errno)); + INIT_LOGE("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) { + INIT_LOGE("Create %s failed. %d\n", path, errno); + return -1; + } + rc = mkdir("/dev/unix/socket/", mode); + if (rc < 0 && errno != EEXIST) { + INIT_LOGE("Create %s failed. %d\n", path, errno); + return -1; + } + return rc; +} + diff --git a/services/src/init_adapter.c b/services/src/init_adapter.c index 34c46408b42119df54b41760bb7c8d0ccc9de1e6..c27bc9c79194ce6fea942f7223a581ff7da942ca 100644 --- a/services/src/init_adapter.c +++ b/services/src/init_adapter.c @@ -20,24 +20,27 @@ #include #include #include -#ifdef __LINUX__ +#if ((defined __LINUX__) || (!defined OHOS_LITE)) #include +#endif +#ifdef __LINUX__ #include "init_signal_handler.h" #endif +#include "init_log.h" void RebootSystem() { int ret = reboot(RB_AUTOBOOT); if (ret != 0) { - printf("[Init] reboot failed! syscall ret %d, err %d.\n", ret, errno); + INIT_LOGE("reboot failed! syscall ret %d, err %d.\n", ret, errno); } } 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"); + INIT_LOGE("prctl PR_SET_SECUREBITS failed: %d\n", errno); return -1; } #endif @@ -46,9 +49,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"); + INIT_LOGE("prctl PR_CAP_AMBIENT failed: %d\n", errno); return -1; } #endif @@ -60,15 +63,15 @@ void ExecuteRcs() #if (defined __LINUX__) && (defined NEED_EXEC_RCS_LINUX) pid_t retPid = fork(); if (retPid < 0) { - printf("[Init] ExecuteRcs, fork failed! err %d.\n", errno); + INIT_LOGE("ExecuteRcs, fork failed! err %d.\n", errno); return; } // child process if (retPid == 0) { - printf("[Init] ExecuteRcs, child process id %d.\n", getpid()); + INIT_LOGI("ExecuteRcs, child process id %d.\n", getpid()); if (execle("/bin/sh", "sh", "/etc/init.d/rcS", NULL, NULL) != 0) { - printf("[Init] ExecuteRcs, execle failed! err %d.\n", errno); + INIT_LOGE("ExecuteRcs, execle failed! err %d.\n", errno); } _exit(0x7f); // 0x7f: user specified } @@ -76,14 +79,14 @@ void ExecuteRcs() // init process sem_t sem; if (sem_init(&sem, 0, 0) != 0) { - printf("[Init] ExecuteRcs, sem_init failed, err %d.\n", errno); + INIT_LOGE("ExecuteRcs, sem_init failed, err %d.\n", errno); return; } SignalRegWaitSem(retPid, &sem); // wait until rcs process exited if (sem_wait(&sem) != 0) { - printf("[Init] ExecuteRcs, sem_wait failed, err %d.\n", errno); + INIT_LOGE("ExecuteRcs, sem_wait failed, err %d.\n", errno); } #endif } diff --git a/services/src/init_capability.c b/services/src/init_capability.c new file mode 100644 index 0000000000000000000000000000000000000000..1c23acfe15a0edc6a24a9976fd901726bb1b1eae --- /dev/null +++ b/services/src/init_capability.c @@ -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 +#include +#include +#include +#include +#if defined OHOS_LITE && !defined __LINUX__ +#include +#else +#include +#endif +#include +#include + +#include "init_log.h" +#include "init_perms.h" + +#define MAX_CAPS_CNT_FOR_ONE_SERVICE 100 + +struct CapStrCapNum { + char *capStr; + int CapNum; +}; + +static const 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("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("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("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("GetServiceCaps, caps is not found. but maybe ok.\n"); + return SERVICE_SUCCESS; + } + if (!cJSON_IsArray(filedJ)) { + INIT_LOGE("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("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("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("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("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; +} + diff --git a/services/src/init_cmds.c b/services/src/init_cmds.c index b79c561823120e208274e35f2106afaaa9dc4eff..8af044e9891d5de9b3f42e6bbabd95fef300d1cb 100644 --- a/services/src/init_cmds.c +++ b/services/src/init_cmds.c @@ -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 #include #include +#include +#include #include -#ifndef OHOS_LITE #include +#ifndef OHOS_LITE #include -#include #endif - +#include +#include "init_jobs.h" +#include "init_log.h" +#include "init_reboot.h" #include "init_service_manager.h" +#include "init_utils.h" #include "securec.h" +#ifndef OHOS_LITE +#include "init_param.h" +#endif -#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,24 @@ static const char* g_supportedCmds[] = { "chmod ", "chown ", "mount ", + "export ", "loadcfg ", "insmod ", + "rm ", + "rmdir ", + "write ", + "exec ", + "mknode ", + "makedev ", + "symlink ", + "stop ", + "trigger ", + "reset ", + "copy ", + "setparam ", + "load_persist_params ", + "load_param ", + "reboot ", }; void ParseCmdLine(const char* cmdStr, CmdLine* resCmd) @@ -88,112 +114,185 @@ void ParseCmdLine(const char* cmdStr, CmdLine* resCmd) } if (!foundAndSucceed) { + INIT_LOGE("Cannot parse command: %s\n", cmdStr); (void)memset_s(resCmd, sizeof(*resCmd), 0, sizeof(*resCmd)); } } static void DoStart(const char* cmdContent) { + INIT_LOGD("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); - } - } + INIT_LOGD("DoStop %s \n", cmdContent); + 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_LOGD("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("DoCopy failed.\n"); + goto out; + } + srcFd = open(ctx->argv[0], O_RDONLY); + INIT_ERROR_CHECK(srcFd >= 0, goto out, "copy open %s fail %d! \n", ctx->argv[0], errno); + INIT_ERROR_CHECK(stat(ctx->argv[0], &fileStat) == 0, goto out, "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, "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, "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: chown owner group /xxx/xxx/xxx + struct CmdArgs *ctx = GetCmd(cmdContent, " "); + if (ctx == NULL || ctx->argv == NULL || ctx->argc != 3) { + INIT_LOGE("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, "DoChown decode owner failed.\n"); + } else { + owner = strtoul(ctx->argv[0], NULL, 0); } - 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 (isalpha(ctx->argv[1][0])) { + group = DecodeUid(ctx->argv[1]); + INIT_ERROR_CHECK(group != (gid_t)-1, goto out, "DoChown decode group failed.\n"); + } else { + group = strtoul(ctx->argv[1], NULL, 0); } - if (chmod(pathBeginStr, mode) != 0) { - printf("[Init] DoChmod, failed for %s, err %d.\n", cmdContent, errno); + int pathPos = 2; + if (chown(ctx->argv[pathPos], owner, group) != 0) { + INIT_LOGE("DoChown, failed for %s, err %d.\n", cmdContent, errno); } +out: + FreeCmd(&ctx); + return; } -static void DoChown(const char* cmdContent) +static void DoMkDir(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: 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("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 (secondSpace <= firstSpace || firstSpace + 1 == secondSpace || secondSpace == strLen - 1) { - printf("[Init] DoChown, bad format for %s.\n", cmdContent); - return; + if (access(ctx->argv[0], 0) != 0) { + if (mkdir(ctx->argv[0], mode) != 0 && errno != EEXIST) { + INIT_LOGE("DoMkDir %s failed, err %d.\n", ctx->argv[0], errno); + goto out; + } } - // 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) { + INIT_LOGE("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("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("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("DoChmod, strtoul failed for %s, er %d.\n", cmdContent, errno); + goto out; } + + if (chmod(ctx->argv[1], mode) != 0) { + INIT_LOGE("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) { if (endPos <= startPos) { - printf("[Init] DoMount, invalid params<%zu, %zu> for %s.\n", endPos, startPos, srcStr); + INIT_LOGE("DoMount, invalid params<%zu, %zu> for %s.\n", endPos, startPos, srcStr); return NULL; } size_t mallocLen = endPos - startPos + 1; char* retStr = (char*)malloc(mallocLen); if (retStr == NULL) { - printf("[Init] DoMount, malloc failed! malloc size %zu, for %s.\n", mallocLen, srcStr); + INIT_LOGE("DoMount, malloc failed! malloc size %zu, for %s.\n", mallocLen, srcStr); return NULL; } const char* copyStart = srcStr + startPos; if (memcpy_s(retStr, mallocLen, copyStart, endPos - startPos) != EOK) { - printf("[Init] DoMount, memcpy_s failed for %s.\n", srcStr); + INIT_LOGE("DoMount, memcpy_s failed for %s.\n", srcStr); free(retStr); return NULL; } @@ -206,7 +305,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("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 +335,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; } @@ -234,7 +353,7 @@ static int CountSpaces(const char* cmdContent, size_t* spaceCnt, size_t* spacePo if (cmdContent[i] == ' ') { ++(*spaceCnt); if ((*spaceCnt) > spacePosArrLen) { - printf("[Init] DoMount, too many spaces, bad format for %s.\n", cmdContent); + INIT_LOGE("DoMount, too many spaces, bad format for %s.\n", cmdContent); return 0; } spacePosArr[(*spaceCnt) - 1] = i; @@ -244,14 +363,14 @@ static int CountSpaces(const char* cmdContent, size_t* spaceCnt, size_t* spacePo if ((*spaceCnt) < SPACES_CNT_IN_CMD_MIN || // spaces count should not less than 2(at least 3 items) spacePosArr[0] == 0 || // should not start with space spacePosArr[(*spaceCnt) - 1] == strLen - 1) { // should not end with space - printf("[Init] DoMount, bad format for %s.\n", cmdContent); + INIT_LOGE("DoMount, bad format for %s.\n", cmdContent); return 0; } // spaces should not be adjacent for (size_t i = 1; i < (*spaceCnt); ++i) { if (spacePosArr[i] == spacePosArr[i - 1] + 1) { - printf("[Init] DoMount, bad format for %s.\n", cmdContent); + INIT_LOGE("DoMount, bad format for %s.\n", cmdContent); return 0; } } @@ -296,7 +415,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; @@ -316,7 +435,7 @@ static void DoMount(const char* cmdContent) } if (mountRet != 0) { - printf("[Init] DoMount, failed for %s, err %d.\n", cmdContent, errno); + INIT_LOGE("DoMount, failed for %s, err %d.\n", cmdContent, errno); } free(fileSysType); @@ -356,13 +475,13 @@ static void DoInsmodInternal(const char *fileName, char *secondPtr, char *restPt realPath = realpath(fileName, realPath); int fd = open(realPath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd < 0) { - printf("[Init] failed to open %s: %d\n", realPath, errno); + INIT_LOGE("failed to open %s: %d\n", realPath, errno); free(realPath); return; } int rc = syscall(__NR_finit_module, fd, options, flags); if (rc == -1) { - printf("[Init] finit_module for %s failed: %d\n", realPath, errno); + INIT_LOGE("finit_module for %s failed: %d\n", realPath, errno); } if (fd >= 0) { close(fd); @@ -382,28 +501,28 @@ static void DoInsmod(const char *cmdContent) size_t count = strlen(cmdContent); if (count > OPTIONS_SIZE) { - printf("[Init], options too long, maybe lost some of options\n"); + INIT_LOGE("options too long, maybe lost some of options\n"); } line = (char *)malloc(count + 1); if (line == NULL) { - printf("[Init] Allocate memory failed.\n"); + INIT_LOGE("Allocate memory failed.\n"); return; } if (memcpy_s(line, count, cmdContent, count) != EOK) { - printf("[Init] memcpy failed\n"); + INIT_LOGE("memcpy failed\n"); free(line); return; } line[count] = '\0'; do { if ((p = strtok_r(line, " ", &restPtr)) == NULL) { - printf("[Init] debug, cannot get filename\n"); + INIT_LOGE("debug, cannot get filename\n"); free(line); return; } fileName = p; - printf("[Init] debug, fileName is [%s]\n", fileName); + INIT_LOGE("debug, fileName is [%s]\n", fileName); if ((p = strtok_r(NULL, " ", &restPtr)) == NULL) { break; } @@ -417,6 +536,21 @@ static void DoInsmod(const char *cmdContent) } return; } + +static void DoSetParam(const char* cmdContent) +{ + struct CmdArgs *ctx = GetCmd(cmdContent, " "); + if (ctx == NULL || ctx->argv == NULL || ctx->argc != 2) { + INIT_LOGE("DoSetParam failed.\n"); + goto out; + } + INIT_LOGE("param name: %s, value %s \n", ctx->argv[0], ctx->argv[1]); + SystemWriteParam(ctx->argv[0], ctx->argv[1]); +out: + FreeCmd(&ctx); + return; +} + #endif // OHOS_LITE static bool CheckValidCfg(const char *path) @@ -449,21 +583,21 @@ static void DoLoadCfg(const char *path) return; } - printf("[Init] DoLoadCfg cfg file %s\n", path); + INIT_LOGI("DoLoadCfg cfg file %s\n", path); if (!CheckValidCfg(path)) { - printf("[Init] CheckCfg file %s Failed\n", path); + INIT_LOGE("CheckCfg file %s Failed\n", path); return; } fp = fopen(path, "r"); if (fp == NULL) { - printf("[Init] open cfg error = %d\n", errno); + INIT_LOGE("open cfg error = %d\n", errno); return; } cmdLine = (CmdLine *)malloc(sizeof(CmdLine)); if (cmdLine == NULL) { - printf("[Init] malloc cmdline error"); + INIT_LOGE("malloc cmdline error"); fclose(fp); return; } @@ -487,30 +621,296 @@ static void DoLoadCfg(const char *path) fclose(fp); } +static void DoWrite(const char *cmdContent) +{ + // format: write path content + struct CmdArgs *ctx = GetCmd(cmdContent, " "); + int writeCmdNumber = 2; + if (ctx == NULL || ctx->argv == NULL || ctx->argc != writeCmdNumber) { + INIT_LOGE("DoWrite: invalid arguments\n"); + goto out; + } + + int fd = open(ctx->argv[0], O_WRONLY | O_CREAT | O_NOFOLLOW | O_CLOEXEC, S_IRWXU | + S_IRGRP | S_IROTH); + if (fd == -1) { + INIT_LOGE("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) { + INIT_LOGE("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("DoRmdir: invalid arguments\n"); + goto out; + } + + int ret = rmdir(ctx->argv[0]); + if (ret == -1) { + INIT_LOGE("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) { + INIT_LOGE("DoRm: invalid arguments\n"); + goto out; + } + int ret = unlink(ctx->argv[0]); + if (ret == -1) { + INIT_LOGE("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) { + INIT_LOGE("DoExport: invalid arguments\n"); + goto out; + } + int ret = setenv(ctx->argv[0], ctx->argv[1], 1); + if (ret != 0) { + INIT_LOGE("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 + pid_t pid = fork(); + if (pid < 0) { + INIT_LOGE("DoExec: failed to fork child process to exec \"%s\"\n", cmdContent); + return; + } + if (pid == 0) { + struct CmdArgs *ctx = GetCmd(cmdContent, " "); + if (ctx == NULL || ctx->argv == NULL) { + INIT_LOGE("DoExec: invalid arguments\n"); + _exit(0x7f); + } +#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("DoExec: execute \"%s\" failed: %d.\n", cmdContent, errno); + } + FreeCmd(&ctx); + _exit(0x7f); + } + 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("DoSymlink: invalid arguments.\n"); + goto out; + } + + int ret = symlink(ctx->argv[0], ctx->argv[1]); + if (ret != 0) { + INIT_LOGE("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("DoMakeNode: invalid arguments\n"); + goto out; + } + + if (!access(ctx->argv[1], F_OK)) { + INIT_LOGE("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("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("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("DoMakedevice \" %s \" failed :%d \n", cmdContent, errno); + goto out; + } +out: + FreeCmd(&ctx); + return; +} +#endif // __LITEOS__ + void DoCmd(const CmdLine* curCmd) { - if (curCmd == NULL) { + // 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); +} - 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); +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(curCmd->name, "insmod ", strlen("insmod ")) == 0) { - DoInsmod(curCmd->cmdContent); + } else if (strncmp(name, "insmod ", strlen("insmod ")) == 0) { + DoInsmod(cmdContent); + } else if (strncmp(name, "trigger ", strlen("trigger ")) == 0) { + INIT_LOGD("ready to trigger job: %s\n", name); + DoTriggerExec(cmdContent); + } else if (strncmp(name, "load_persist_params ", strlen("load_persist_params ")) == 0) { + LoadPersistParams(); + } else if (strncmp(name, "setparam ", strlen("setparam ")) == 0) { + DoSetParam(cmdContent); + } else if (strncmp(name, "load_param ", strlen("load_param ")) == 0) { + LoadDefaultParams(cmdContent); #endif - } else { - printf("[Init] DoCmd, unknown cmd name %s.\n", curCmd->name); + } else if (strncmp(name, "reboot ", strlen("reboot ")) == 0) { + DoReboot(cmdContent); + } else { + INIT_LOGE("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; +} diff --git a/services/src/init_import.c b/services/src/init_import.c new file mode 100644 index 0000000000000000000000000000000000000000..68751635266cd22d7d81aae5b78b224daeb73211 --- /dev/null +++ b/services/src/init_import.c @@ -0,0 +1,51 @@ +/* + * 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 +#include +#include "cJSON.h" +#include "init_log.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)) { + INIT_LOGE("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)) { + INIT_LOGE("Invalid type of import item. should be string\n"); + return; + } + char *importFile = cJSON_GetStringValue(importItem); + if (importFile == NULL) { + INIT_LOGE("cannot get import config file\n"); + return; + } + INIT_LOGD("ready to import %s...\n", importFile); + ParseInitCfg(importFile); + } + INIT_LOGD("parse import file done\n"); + return; +} diff --git a/services/src/init_jobs.c b/services/src/init_jobs.c index e41e623c817880b2777c75cfb41868953712b2ff..fa8a9fd194e48ace410da22b9a5b1ab87930b6c0 100644 --- a/services/src/init_jobs.c +++ b/services/src/init_jobs.c @@ -17,24 +17,40 @@ #include #include +#include #include "init_cmds.h" +#include "init_log.h" #include "securec.h" #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() +{ + INIT_LOGD("Ready to dump all jobs:\n"); + for (int i = 0; i < g_jobCnt; i++) { + INIT_LOGD("\tjob name: %s\n", g_jobs[i].name); + INIT_LOGD("\tlist all commands:\n"); + for (int j = 0; j < g_jobs[i].cmdLinesCnt; j++) { + INIT_LOGD("\t\tcommand name : %s, command options: %s\n", + g_jobs[i].cmdLines[j].name, g_jobs[i].cmdLines[j].cmdContent); + } + } + INIT_LOGD("To dump all jobs finished\n"); +} + static int GetJobName(const cJSON* jobItem, Job* resJob) { char* jobNameStr = cJSON_GetStringValue(cJSON_GetObjectItem(jobItem, "name")); @@ -42,45 +58,44 @@ 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; - } + if (memcpy_s(resJob->name, MAX_JOB_NAME_LEN, jobNameStr, strlen(jobNameStr)) != EOK) { + INIT_LOGE("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)) { + INIT_LOGE("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)) { + INIT_LOGE("job %s is not an arrary\n", resJob->name); return; } int cmdLinesCnt = cJSON_GetArraySize(cmdsItem); if (cmdLinesCnt <= 0) { // empty job, no cmd + INIT_LOGE("empty job \"%s\"\n", resJob->name); return; } + INIT_LOGD("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", + INIT_LOGE("ParseAllJobs, too many cmds[cnt %d] in one job, it should not exceed %d.\n", cmdLinesCnt, MAX_CMD_CNT_IN_ONE_JOB); return; } resJob->cmdLines = (CmdLine*)malloc(cmdLinesCnt * sizeof(CmdLine)); if (resJob->cmdLines == NULL) { + INIT_LOGE("allocate memory for command line failed\n"); return; } @@ -100,31 +115,32 @@ static void ParseJob(const cJSON* jobItem, Job* resJob) void ParseAllJobs(const cJSON* fileRoot) { if (fileRoot == NULL) { - printf("[Init] ParseAllJobs, input fileRoot is NULL!\n"); + INIT_LOGE("ParseAllJobs, input fileRoot is NULL!\n"); return; } cJSON* jobArr = cJSON_GetObjectItemCaseSensitive(fileRoot, JOBS_ARR_NAME_IN_JSON); if (!cJSON_IsArray(jobArr)) { - printf("[Init] ParseAllJobs, job item is not array!\n"); + INIT_LOGE("ParseAllJobs, job item is not array!\n"); return; } int jobArrSize = cJSON_GetArraySize(jobArr); if (jobArrSize <= 0 || jobArrSize > MAX_JOBS_COUNT) { - printf("[Init] ParseAllJobs, jobs count %d is invalid, should be positive and not exceeding %d.\n", + INIT_LOGE("ParseAllJobs, jobs count %d is invalid, should be positive and not exceeding %d.\n", jobArrSize, MAX_JOBS_COUNT); 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); + INIT_LOGE("ParseAllJobs, malloc failed! job arrSize %d.\n", jobArrSize); return; } - if (memset_s(retJobs, sizeof(Job) * jobArrSize, 0, sizeof(Job) * jobArrSize) != EOK) { - printf("[Init] ParseAllJobs, memset_s failed.\n"); + Job* tmp = retJobs + g_jobCnt; + if (memset_s(tmp, sizeof(Job) * jobArrSize, 0, sizeof(Job) * jobArrSize) != EOK) { + INIT_LOGE("ParseAllJobs, memset_s failed.\n"); free(retJobs); retJobs = NULL; return; @@ -132,26 +148,28 @@ 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) { if (jobName == NULL) { - printf("[Init] DoJob, input jobName NULL!\n"); + INIT_LOGE("DoJob, input jobName NULL!\n"); return; } + INIT_LOGD("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; } } } diff --git a/services/src/init_read_cfg.c b/services/src/init_read_cfg.c index 4d6cbd3d45c370fb9d4ba0fa191a84ed91549dfa..b6f8e1c8116c4d5151a8b512b8547477433d843e 100644 --- a/services/src/init_read_cfg.c +++ b/services/src/init_read_cfg.c @@ -16,6 +16,7 @@ #include "init_read_cfg.h" #include +#include #include #include #include @@ -23,9 +24,16 @@ #include #include +#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 "init_param.h" +#endif #include "securec.h" #ifndef __LINUX__ #ifdef OHOS_LITE @@ -33,368 +41,93 @@ #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() -{ - 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; - } - - fd = fopen(INIT_CONFIGURATION_FILE, "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; -} - -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 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) +#define FILE_NAME_MAX_SIZE 100 +static void ParseInitCfgContents(cJSON *root) { - 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; - } + // parse services + ParseAllServices(root); - if (i == 0 && IsForbidden(curParam)) { - // resources will be released by function: ReleaseServiceMem - return SERVICE_FAILURE; - } + // parse jobs + ParseAllJobs(root); - 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; - } +#ifndef OHOS_LITE + ParseTriggerConfig(root); +#endif - 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; + // parse imports + ParseAllImports(root); } -static int GetServiceNumber(const cJSON* curArrItem, Service* curServ, const char* targetField) +void ParseInitCfg(const char *configFile) { - cJSON* filedJ = cJSON_GetObjectItem(curArrItem, targetField); - if (!cJSON_IsNumber(filedJ)) { - return SERVICE_FAILURE; + if (configFile == NULL || *configFile == '\0') { + INIT_LOGE("Invalid config file\n"); + return; } - int value = (int)cJSON_GetNumberValue(filedJ); - if (value < 0) { - return SERVICE_FAILURE; - } + char *fileBuf = ReadFileToBuf(configFile); + cJSON* fileRoot = cJSON_Parse(fileBuf); + free(fileBuf); + fileBuf = NULL; - 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; + if (fileRoot == NULL) { + INIT_LOGE("InitReadCfg, parse failed! please check file %s format.\n", configFile); + return; } - return SERVICE_SUCCESS; + ParseInitCfgContents(fileRoot); + // Release JSON object + cJSON_Delete(fileRoot); + return; } -static int GetServiceCaps(const cJSON* curArrItem, Service* curServ) +static void ReadCfgs(const char *dirPath) { - 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; - } + DIR *pDir = opendir(dirPath); + if (pDir == NULL) { + INIT_LOGE("ParseCfgs open cfg dir :%s failed.%d\n", dirPath, errno); + return; } - 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; + 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("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("fileName :%s.\n", fileName); + ParseInitCfg(fileName); } - curServ->servPerm.gIDs[0] = (unsigned int)value; } - curServ->servPerm.gidsCnt = gidsCnt; - return SERVICE_SUCCESS; + closedir(pDir); + return; } -static void ParseAllServices(const cJSON* fileRoot) +static void ParseOtherCfgs() { - 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; - } - - 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); + ReadCfgs("/system/etc/init"); + return; } 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; - } - - 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); - return; - } - - // parse services - ParseAllServices(fileRoot); - - // parse jobs - ParseAllJobs(fileRoot); - - // release memory - cJSON_Delete(fileRoot); +#ifndef OHOS_LITE + InitParamService(); + LoadDefaultParams("/system/etc/prop.default"); + LoadDefaultParams("/system/build.prop"); + LoadDefaultParams("/system/buildz.prop"); +#endif + ParseInitCfg(INIT_CONFIGURATION_FILE); + ParseOtherCfgs(); + INIT_LOGI("Parse init config file done.\n"); + DumpAllServices(); + // DumpAllJobs(); // do jobs DoJob("pre-init"); #ifndef __LINUX__ diff --git a/services/src/init_reboot.c b/services/src/init_reboot.c new file mode 100644 index 0000000000000000000000000000000000000000..5b950533a5e1df7128295e434646a16ead1a7732 --- /dev/null +++ b/services/src/init_reboot.c @@ -0,0 +1,188 @@ +/* + * 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_reboot.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include "init_service.h" +#include "init_service_manager.h" +#include "init_log.h" + +#define MAX_VALUE_LENGTH 500 +#define MAX_COMMAND_SIZE 20 +#define MAX_UPDATE_SIZE 100 + +struct RBMiscUpdateMessage { + char command[MAX_COMMAND_SIZE]; + char update[MAX_UPDATE_SIZE]; +}; + +static bool RBMiscWriteUpdaterMessage(const char *path, struct RBMiscUpdateMessage *boot) +{ + FILE* fp = fopen(path, "rb+"); + if (fp == NULL) { + INIT_LOGE("open %s failed", path); + return false; + } + + size_t ret = fwrite(boot, sizeof(struct RBMiscUpdateMessage), 1, fp); + if (ret < 0) { + INIT_LOGE("write to misc failed\n"); + fclose(fp); + return false; + } + + fclose(fp); + return true; +} + +static bool RBMiscReadUpdaterMessage(const char *path, struct RBMiscUpdateMessage *boot) +{ + FILE* fp = fopen(path, "rb"); + if (fp == NULL) { + INIT_LOGE("open %s failed", path); + return false; + } + + size_t ret = fread(boot, 1, sizeof(struct RBMiscUpdateMessage), fp); + if (ret <= 0) { + INIT_LOGE("read to misc failed"); + fclose(fp); + return false; + } + fclose(fp); + return true; +} + +static int GetMountStatusForMountPoint(const char *mountPoint) +{ + char buffer[512]; + size_t n; + const char *mountFile = "/proc/mounts"; + FILE *fp = fopen(mountFile, "r"); + if (fp == NULL) { + INIT_LOGE("[init] DoReboot %s can't open.\n", mountPoint); + return 1; + } + + while (fgets(buffer, sizeof(buffer), fp) != NULL) { + n = strlen(buffer); + if (buffer[n - 1] == '\n') { + buffer[n - 1] = '\0'; + } + if (strstr(buffer, mountPoint) != NULL) { + fclose(fp); + return 1; + } + } + + // Cannot find it from system. + fclose(fp); + return 0; +} + +void DoReboot(const char *value) +{ + if (value == NULL) { + INIT_LOGE("[init] DoReboot value = NULL\n"); + return; + } + INIT_LOGI("[init] DoReboot value = %s\n", value); + + if (strlen(value) > MAX_VALUE_LENGTH) { + INIT_LOGE("DoReboot reboot value error, value = %s.\n", value); + return; + } + + if (GetMountStatusForMountPoint("/vendor")) { + if (umount("/vendor") != 0) { + INIT_LOGE("DoReboot umount vendor failed! errno = %d.\n", errno); + } + } + if (GetMountStatusForMountPoint("/data")) { + if (umount("/data") != 0) { + INIT_LOGE("DoReboot umount data failed! errno = %d.\n", errno); + } + } + StopAllServicesBeforeReboot(); + // "shutdown" + if (strncmp(value, "shutdown", sizeof("shutdown")) == 0) { + int ret = reboot(RB_POWER_OFF); + if (ret != 0) { + INIT_LOGE("DoReboot reboot(RB_POWER_OFF) failed! syscall ret %d, err %d.\n", ret, errno); + } + return; + } + // "updater" or "updater:" + const char *miscFile = "/dev/block/platform/soc/10100000.himci.eMMC/by-name/misc"; + struct RBMiscUpdateMessage msg; + bool ret = RBMiscReadUpdaterMessage(miscFile, &msg); + if(!ret) { + INIT_LOGE("[init] DoReboot RBMiscReadUpdaterMessage error.\n"); + return; + } + const int commandSize = 12; + snprintf(msg.command, MAX_COMMAND_SIZE, "%s", "boot_updater"); + msg.command[commandSize] = 0; + + if (strlen(value) > strlen("updater:") && strncmp(value, "updater:", strlen("updater:")) == 0) { + const char *p = value + strlen("updater:"); + if (snprintf(msg.update, MAX_UPDATE_SIZE, "%s", p) > MAX_UPDATE_SIZE) { + INIT_LOGE("[init] DoReboot updater: RBMiscWriteUpdaterMessage error\n"); + return; + } + msg.update[MAX_UPDATE_SIZE - 1] = 0; + ret = RBMiscWriteUpdaterMessage(miscFile, &msg); + if(true != ret) { + INIT_LOGE("[init] DoReboot updater: RBMiscWriteUpdaterMessage error\n"); + return; + } + ret = reboot(RB_AUTOBOOT); + if (ret != 0) { + INIT_LOGE("DoReboot updater: reboot(RB_AUTOBOOT) failed! syscall ret %d, err %d.\n", ret, errno); + } + return; + } + if (strlen(value) == strlen("updater") && strncmp(value, "updater", strlen("updater")) == 0) { + ret = RBMiscWriteUpdaterMessage(miscFile, &msg); + if(true != ret) { + INIT_LOGE("[init] DoReboot updater RBMiscWriteUpdaterMessage error\n"); + return; + } + ret = reboot(RB_AUTOBOOT); + if (ret != 0) { + INIT_LOGE("DoReboot updater reboot(RB_AUTOBOOT) failed! syscall ret %d, err %d.\n", ret, errno); + } + return; + } + if (strlen(value) == strlen("NoArgument") && strncmp(value, "NoArgument", strlen("NoArgument")) == 0) { + ret = reboot(RB_AUTOBOOT); + if (ret != 0) { + INIT_LOGE("DoReboot updater: reboot(RB_AUTOBOOT) failed! syscall ret %d, err %d.\n", ret, errno); + } + return; + } + INIT_LOGE("DoReboot value = %s, error.\n", value); + return; + +} + diff --git a/services/src/init_service.c b/services/src/init_service.c index 3974ea8b8a27e5e34155fd90e2d0b186366639e2..fc85be1628ede0cbc130dfc58744e10f5d4a9ba3 100644 --- a/services/src/init_service.c +++ b/services/src/init_service.c @@ -19,12 +19,16 @@ #include #include #include +#include #include #include #include #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("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) { + INIT_LOGE("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) { + INIT_LOGE("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) { + INIT_LOGE("SetAmbientCapability faild for service: %s\n", service->name); return SERVICE_FAILURE; } } @@ -95,12 +113,12 @@ static int SetPerms(const Service *service) int ServiceStart(Service *service) { if (service == NULL) { - printf("[Init] start service failed! null ptr.\n"); + INIT_LOGE("start service failed! null ptr.\n"); return SERVICE_FAILURE; } if (service->attribute & SERVICE_ATTR_INVALID) { - printf("[Init] start service %s invalid.\n", service->name); + INIT_LOGE("start service %s invalid.\n", service->name); return SERVICE_FAILURE; } @@ -108,38 +126,77 @@ int ServiceStart(Service *service) service->attribute &= (~(SERVICE_ATTR_NEED_RESTART | SERVICE_ATTR_NEED_STOP)); if (stat(service->pathArgs[0], &pathStat) != 0) { service->attribute |= SERVICE_ATTR_INVALID; - printf("[Init] start service %s invalid, please check %s.\n",\ + INIT_LOGE("start service %s invalid, please check %s.\n",\ service->name, service->pathArgs[0]); return SERVICE_FAILURE; } - + int ret = 0; int pid = fork(); if (pid == 0) { + if (service->socketCfg != NULL) { // start socket service + INIT_LOGI("Create socket \n"); + ret = DoCreateSocket(service->socketCfg); + if (ret < 0) { + INIT_LOGE("DoCreateSocket failed. \n"); + _exit(0x7f); // 0x7f: user specified + } + } // permissions if (SetPerms(service) != SERVICE_SUCCESS) { - printf("[Init] service %s exit! set perms failed! err %d.\n", service->name, errno); + INIT_LOGE("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("start service writepid sprintf failed.\n"); + _exit(0x7f); // 0x7f: user specified + } + 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("start service writepidFiles %s invalid.\n", service->writepidFiles[i]); + continue; + } + if (fwrite(pidString, 1, strlen(pidString), fd) != strlen(pidString)) { + INIT_LOGE("start service writepid error.file:%s pid:%s\n", service->writepidFiles[i], pidString); + } + fclose(fd); + INIT_LOGE("ServiceStart writepid filename=%s, childPid=%s, ok\n", service->writepidFiles[i], + pidString); + } + INIT_LOGI("service->name is %s \n", service->name); +#ifndef OHOS_LITE + // L2 Can not be reset env + if (execv(service->pathArgs[0], service->pathArgs) != 0) { + INIT_LOGE("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); + INIT_LOGE("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); + INIT_LOGE("start service %s fork failed!\n", service->name); return SERVICE_FAILURE; } service->pid = pid; - printf("[Init] start service %s succeed, pid %d.\n", service->name, service->pid); + INIT_LOGI("start service %s succeed, pid %d.\n", service->name, service->pid); return SERVICE_SUCCESS; } int ServiceStop(Service *service) { if (service == NULL) { - printf("[Init] stop service failed! null ptr.\n"); + INIT_LOGE("stop service failed! null ptr.\n"); return SERVICE_FAILURE; } @@ -150,23 +207,66 @@ int ServiceStop(Service *service) } if (kill(service->pid, SIGKILL) != 0) { - printf("[Init] stop service %s pid %d failed! err %d.\n", service->name, service->pid, errno); + INIT_LOGE("stop service %s pid %d failed! err %d.\n", service->name, service->pid, errno); return SERVICE_FAILURE; } - printf("[Init] stop service %s, pid %d.\n", service->name, service->pid); + INIT_LOGI("stop service %s, pid %d.\n", service->name, service->pid); + 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("reap critical service %s, crash too many times! Need reboot!\n", service->name); + RebootSystem(); + } + } + } +} + +static int ExecRestartCmd(const Service *service) +{ + INIT_LOGI("ExecRestartCmd \n"); + if ((service == NULL) || (service->onRestart == NULL) || (service->onRestart->cmdLine == NULL)) { + return SERVICE_FAILURE; + } + + for (int i = 0; i < service->onRestart->cmdNum; i++) { + INIT_LOGI("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) { - printf("[Init] reap service failed! null ptr.\n"); + INIT_LOGE("reap service failed! null ptr.\n"); return; } - service->pid = -1; + if (service->attribute & SERVICE_ATTR_INVALID) { + INIT_LOGE("ServiceReap service %s invalid.\n", service->name); + return; + } + 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); @@ -197,15 +297,23 @@ void ServiceReap(Service *service) } else { ++service->crashCnt; if (service->crashCnt > CRASH_COUNT_LIMIT) { - printf("[Init] reap service %s, crash too many times!\n", service->name); + INIT_LOGE("reap service %s, crash too many times!\n", service->name); return; } } } - int ret = ServiceStart(service); + CheckCritical(service); + int ret = 0; + if (service->onRestart != NULL) { + ret = ExecRestartCmd(service); + if (ret != SERVICE_SUCCESS) { + INIT_LOGE("SetOnRestart fail \n"); + } + } + ret = ServiceStart(service); if (ret != SERVICE_SUCCESS) { - printf("[Init] reap service %s start failed!\n", service->name); + INIT_LOGE("reap service %s start failed!\n", service->name); } service->attribute &= (~SERVICE_ATTR_NEED_RESTART); diff --git a/services/src/init_service_manager.c b/services/src/init_service_manager.c old mode 100755 new mode 100644 index 2a7cbcbbe4cc13e82cac5accd1d0639b1e907bbf..99f8c35f5ae5705508849dda80bdaf63d966fc42 --- a/services/src/init_service_manager.c +++ b/services/src/init_service_manager.c @@ -1,91 +1,775 @@ -/* - * 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 -#include -#include - -#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 +#include +#include +#include +#include +#include +#include +#include + +#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() +{ + INIT_LOGD("Ready to dump all services:\n"); + INIT_LOGD("total service number: %d\n", g_servicesCnt); + for (int i = 0; i < g_servicesCnt; i++) { + INIT_LOGD("\tservice name: [%s]\n", g_services[i].name); + INIT_LOGD("\tpath :"); + for (int j = 0; j < g_services[i].pathArgsCnt; j++) { + INIT_LOGD(" %s", g_services[i].pathArgs[j]); + } + INIT_LOGD("\n"); + } + INIT_LOGD("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("GetServiceName cJSON_GetStringValue error\n"); + return SERVICE_FAILURE; + } + + size_t strLen = strlen(fieldStr); + if (strLen == 0 || strLen > MAX_SERVICE_NAME) { + INIT_LOGE("GetServiceName strLen = %d, error\n", strLen); + return SERVICE_FAILURE; + } + + if (memcpy_s(curServ->name, MAX_SERVICE_NAME, fieldStr, strLen) != EOK) { + INIT_LOGE("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)) { + INIT_LOGE("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("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("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("GetWritepidStrings, malloc item[%d] error.\n", i); + return SERVICE_FAILURE; + } + if (memcpy_s(curServ->writepidFiles[i], strLen + 1, fieldStr, strLen) != EOK) { + INIT_LOGE("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("GetGidOneItem, gid is not found too, but ok.\n"); + return SERVICE_SUCCESS; // not found + } + curServ->servPerm.gIDCnt = 1; + curServ->servPerm.gIDArray = (gid_t *)malloc(sizeof(gid_t)); + if (curServ->servPerm.gIDArray == NULL) { + INIT_LOGE("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("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("GetGidOneItem, gID = %d error.\n", gID); + return SERVICE_FAILURE; + } + curServ->servPerm.gIDArray[0] = gID; + return SERVICE_SUCCESS; + } + + INIT_LOGE("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("GetGidArray, gid is not a list.\n"); + return GetGidOneItem(curArrItem, curServ); + } + + if (gIDCnt > NGROUPS_MAX + 1) { + INIT_LOGE("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("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("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("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("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("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("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("GetServicePathAndArgs arrSize = %d, error\n", arrSize); + return SERVICE_FAILURE; + } + + curServ->pathArgs = (char**)malloc((arrSize + 1) * sizeof(char*)); + if (curServ->pathArgs == NULL) { + INIT_LOGE("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("GetServicePathAndArgs curParam == NULL, error\n"); + } else { + INIT_LOGE("GetServicePathAndArgs strlen = %d, error\n", strlen(curParam)); + } + return SERVICE_FAILURE; + } + + if (i == 0 && IsForbidden(curParam)) { + // resources will be released by function: ReleaseServiceMem + INIT_LOGE("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("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("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("GetServiceNumber, %s is null or is not a number, error.\n", targetField); + return SERVICE_FAILURE; + } + + int value = (int)cJSON_GetNumberValue(filedJ); + // important value allow < 0 + if (strncmp(targetField, IMPORTANT_STR_IN_CFG, strlen(IMPORTANT_STR_IN_CFG)) != 0) { + if (value < 0) { + INIT_LOGE("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("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("GetUidStringNumber, %s not found, but ok.\n", UID_STR_IN_CFG); + return SERVICE_SUCCESS; // uID not found, but ok. + } + + if (cJSON_IsString(filedJ)) { + char* fieldStr = cJSON_GetStringValue(filedJ); + int uID = DecodeUid(fieldStr); + if (uID < 0) { + INIT_LOGE("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("GetUidStringNumber, uID = %d error.\n", uID); + return SERVICE_FAILURE; + } + curServ->servPerm.uID = uID; + return SERVICE_SUCCESS; + } + + INIT_LOGE("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++) { + INIT_LOGI("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) +{ + INIT_LOGI("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; + } + 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; + } + 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; + } + sockopt->perm = strtoul(opt[SERVICE_SOCK_PERM], 0, 8); //¡Áa?¡¥?a8???? + + if (opt[SERVICE_SOCK_UID] == NULL) { + return -1; + } + int uuid = DecodeUid(opt[SERVICE_SOCK_UID]); + if (uuid < 0) { + return -1; + } + sockopt->uid = uuid; + + if (opt[SERVICE_SOCK_GID] == NULL) { + return -1; + } + int ggid = DecodeUid(opt[SERVICE_SOCK_GID]); + if (ggid < 0) { + return -1; + } + sockopt->gid = ggid; + + if (opt[SERVICE_SOCK_SETOPT] == NULL) { + return -1; + } + 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) +{ + INIT_LOGI("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; + } + 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; + } + struct ServiceSocket *socktmp = (struct ServiceSocket *)calloc(1, sizeof(struct ServiceSocket)); + if (!socktmp) { + return SERVICE_FAILURE; + } + 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) +{ + INIT_LOGI("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]); + } + 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("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) { + INIT_LOGE("ParseAllServices, get array %s failed.\n", SERVICES_ARR_NAME_IN_JSON); + return; + } + + INIT_LOGI("servArrSize is %d \n", servArrSize); + if (servArrSize > MAX_SERVICES_CNT_IN_FILE) { + INIT_LOGE("ParseAllServices, 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) { + INIT_LOGE("ParseAllServices, 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; + } + 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; + INIT_LOGE("ParseAllServices, parse information for service %s failed. ", tmp[i].name); + continue; + } else { + INIT_LOGD("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); + } + 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) { + INIT_LOGE("StartServiceByName, cannot find service %s.\n", servName); + return; + } + + if (ServiceStart(&g_services[servIdx]) != SERVICE_SUCCESS) { + INIT_LOGE("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("StopServiceByName, cannot find service %s.\n", servName); + return; + } + + if (ServiceStop(&g_services[servIdx]) != SERVICE_SUCCESS) { + INIT_LOGE("StopServiceByName, service %s start failed!\n", g_services[servIdx].name); + } + + return; +} + +void StopAllServices() +{ + for (int i = 0; i < g_servicesCnt; i++) { + if (strcmp(g_services[i].name, "console") != 0 && strcmp(g_services[i].name, "ueventd") != 0) { + if (ServiceStop(&g_services[i]) != SERVICE_SUCCESS) { + INIT_LOGE("[Init] StopAllServices, service %s stop failed!\n", g_services[i].name); + } + } + } +} + +void StopAllServicesBeforeReboot() +{ + for (int i = 0; i < g_servicesCnt; i++) { + g_services[i].attribute |= SERVICE_ATTR_INVALID; + if (ServiceStop(&g_services[i]) != SERVICE_SUCCESS) { + INIT_LOGE("StopAllServicesBeforeReboot, 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; + } + } +} + + diff --git a/services/src/init_service_socket.c b/services/src/init_service_socket.c new file mode 100644 index 0000000000000000000000000000000000000000..c661f69216405b50be21e6579551030f7c257b5e --- /dev/null +++ b/services/src/init_service_socket.c @@ -0,0 +1,167 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "init_log.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; + } + + int sockFd = socket(PF_UNIX, sockopt->type, 0); + if (sockFd < 0) { + INIT_LOGE("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); + if (access(addr.sun_path, F_OK)) { + INIT_LOGE("%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))) { + INIT_LOGE("Create socket for service %s failed: %d\n", sockopt->name, errno); + unlink(addr.sun_path); + close(sockFd); + return -1; + } + + if (lchown(addr.sun_path, sockopt->uid, sockopt->gid)) { + unlink(addr.sun_path); + close(sockFd); + INIT_LOGE("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); + INIT_LOGE("fchmodat fail %d \n", errno); + return -1; + } + INIT_LOGI("CreateSocket success \n"); + return sockFd; +} + +static int SetSocketEnv(int fd, char *name) +{ + char pubName[64] = {0}; + char val[16] = {0}; + snprintf(pubName, sizeof(pubName), HOS_SOCKET_ENV_PREFIX"%s", name); + snprintf(val, sizeof(val), "%d", fd); + int ret = setenv(pubName, val, 1); + if (ret < 0) { + INIT_LOGE("setenv fail %d \n", errno); + return -1; + } + fcntl(fd, F_SETFD, 0); + return 0; +} + +int DoCreateSocket(struct ServiceSocket *sockopt) +{ + if (!sockopt) { + return -1; + } + struct ServiceSocket *tmpSock = sockopt; + while (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; +} + diff --git a/services/src/init_signal_handler.c b/services/src/init_signal_handler.c index c79feca9a49b8b93486bb44bc5942e33c6cb1f4d..bd5ca1c31005c80c53b217cf97e13e35cba2809c 100644 --- a/services/src/init_signal_handler.c +++ b/services/src/init_signal_handler.c @@ -23,8 +23,13 @@ #include #endif /* __LINUX__ */ +#include "init_log.h" #include "init_service_manager.h" +#ifndef OHOS_LITE +#include "init_param.h" +#include "uv.h" +#endif #ifdef __LINUX__ static pid_t g_waitPid = -1; @@ -40,7 +45,7 @@ static void CheckWaitPid(pid_t sigPID) { if (g_waitPid == sigPID && g_waitSem != NULL) { if (sem_post(g_waitSem) != 0) { - printf("[Init] CheckWaitPid, sem_post failed, errno %d.\n", errno); + INIT_LOGE("CheckWaitPid, sem_post failed, errno %d.\n", errno); } g_waitPid = -1; g_waitSem = NULL; @@ -59,7 +64,7 @@ static void SigHandler(int sig) if (sigPID <= 0) { break; } - printf("[Init] SigHandler, SIGCHLD received, sigPID = %d.\n", sigPID); + INIT_LOGI("SigHandler, SIGCHLD received, sigPID = %d.\n", sigPID); #ifdef __LINUX__ CheckWaitPid(sigPID); #endif /* __LINUX__ */ @@ -68,16 +73,23 @@ static void SigHandler(int sig) break; } case SIGTERM: { - printf("[Init] SigHandler, SIGTERM received.\n"); + INIT_LOGI("SigHandler, SIGTERM received.\n"); StopAllServices(); break; } + case SIGINT: +#ifndef OHOS_LITE + StopParamService(); +#endif + exit(0); + break; default: - printf("[Init] SigHandler, unsupported signal %d.\n", sig); + INIT_LOGI("SigHandler, unsupported signal %d.\n", sig); break; } } +#ifdef OHOS_LITE void SignalInitModule() { struct sigaction act; @@ -88,4 +100,34 @@ void SignalInitModule() sigaction(SIGCHLD, &act, NULL); sigaction(SIGTERM, &act, NULL); } +#else // L2 or above, use signal event in libuv +uv_signal_t g_sigchldHandler; +uv_signal_t g_sigtermHandler; +uv_signal_t g_sigintHandler; + +static void UVSignalHandler(uv_signal_t* handle, int signum) +{ + SigHandler(signum); +} + +void SignalInitModule() +{ + int ret = uv_signal_init(uv_default_loop(), &g_sigchldHandler); + ret |= uv_signal_init(uv_default_loop(), &g_sigtermHandler); + ret |= uv_signal_init(uv_default_loop(), &g_sigintHandler); + if (ret != 0) { + INIT_LOGW("initialize signal handler failed\n"); + return; + } + if (uv_signal_start(&g_sigchldHandler, UVSignalHandler, SIGCHLD) != 0) { + INIT_LOGW("start SIGCHLD handler failed\n"); + } + if (uv_signal_start(&g_sigtermHandler, UVSignalHandler, SIGTERM) != 0) { + INIT_LOGW("start SIGTERM handler failed\n"); + } + if (uv_signal_start(&g_sigintHandler, UVSignalHandler, SIGINT) != 0) { + INIT_LOGW("start SIGTERM handler failed\n"); + } +} +#endif diff --git a/services/src/init_utils.c b/services/src/init_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..d1e7e55095ac8c2b3b7c3b3928ddd29f09b1c94d --- /dev/null +++ b/services/src/init_utils.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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("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(InitLogLevel 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; +} \ No newline at end of file diff --git a/services/src/list.c b/services/src/list.c old mode 100755 new mode 100644 diff --git a/services/src/main.c b/services/src/main.c old mode 100755 new mode 100644 index 40ab4241076b031b2acdd33311375bb6250eb3ac..0b3fa214627d6011c43ca83487535ebeafef3cb4 --- a/services/src/main.c +++ b/services/src/main.c @@ -25,6 +25,7 @@ #include #include "init_adapter.h" +#include "init_log.h" #include "init_read_cfg.h" #include "init_signal_handler.h" #ifdef OHOS_LITE @@ -33,6 +34,7 @@ #ifndef OHOS_LITE #include "device.h" +#include "init_param.h" #endif static const pid_t INIT_PROCESS_PID = 1; @@ -42,10 +44,10 @@ static void PrintSysInfo() #ifdef OHOS_LITE const char* sysInfo = GetVersionId(); if (sysInfo != NULL) { - printf("[Init] %s\n", sysInfo); + INIT_LOGE("%s\n", sysInfo); return; } - printf("[Init] main, GetVersionId failed!\n"); + INIT_LOGE("main, GetVersionId failed!\n"); #endif } @@ -66,12 +68,12 @@ int main(int argc, char * const argv[]) #ifdef OHOS_DEBUG struct timespec tmEnter; if (clock_gettime(CLOCK_REALTIME, &tmEnter) != 0) { - printf("[Init] main, enter, get time failed! err %d.\n", errno); + INIT_LOGE("main, enter, get time failed! err %d.\n", errno); } #endif // OHOS_DEBUG if (getpid() != INIT_PROCESS_PID) { - printf("[Init] main, current process id is %d not %d, failed!\n", getpid(), INIT_PROCESS_PID); + INIT_LOGE("main, current process id is %d not %d, failed!\n", getpid(), INIT_PROCESS_PID); return 0; } @@ -82,6 +84,7 @@ int main(int argc, char * const argv[]) // 2. Mount basic filesystem and create common device node. MountBasicFs(); CreateDeviceNode(); + MakeSocketDir("/dev/unix/socket/", 0755); #endif // 3. signal register @@ -90,7 +93,7 @@ int main(int argc, char * const argv[]) #ifdef OHOS_DEBUG struct timespec tmSysInfo; if (clock_gettime(CLOCK_REALTIME, &tmSysInfo) != 0) { - printf("[Init] main, after sysinfo, get time failed! err %d.\n", errno); + INIT_LOGE("main, after sysinfo, get time failed! err %d.\n", errno); } #endif // OHOS_DEBUG @@ -100,27 +103,28 @@ int main(int argc, char * const argv[]) #ifdef OHOS_DEBUG struct timespec tmRcs; if (clock_gettime(CLOCK_REALTIME, &tmRcs) != 0) { - printf("[Init] main, after rcs, get time failed! err %d.\n", errno); + INIT_LOGE("main, after rcs, get time failed! err %d.\n", errno); } #endif // OHOS_DEBUG - // 5. read configuration file and do jobs InitReadCfg(); - #ifdef OHOS_DEBUG struct timespec tmCfg; if (clock_gettime(CLOCK_REALTIME, &tmCfg) != 0) { - printf("[Init] main, after cfg, get time failed! err %d.\n", errno); + INIT_LOGE("main, after cfg, get time failed! err %d.\n", errno); } #endif // OHOS_DEBUG // 6. keep process alive #ifdef OHOS_DEBUG - printf("[Init] main, time used: sigInfo %ld ms, rcs %ld ms, cfg %ld ms.\n", \ + INIT_LOGI("main, time used: sigInfo %ld ms, rcs %ld ms, cfg %ld ms.\n", \ TimeDiffMs(&tmEnter, &tmSysInfo), TimeDiffMs(&tmSysInfo, &tmRcs), TimeDiffMs(&tmRcs, &tmCfg)); #endif - printf("[Init] main, entering wait.\n"); + INIT_LOGI("main, entering wait.\n"); +#ifndef OHOS_LITE + StartParamService(); +#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. diff --git a/services/src/uevent.c b/services/src/uevent.c old mode 100755 new mode 100644 index 08cf8afe18befc60dd41a35a7ae6f2fff5874fc2..b55bc6c74fcd288c1959b175a74dbde71f6e6413 --- a/services/src/uevent.c +++ b/services/src/uevent.c @@ -28,6 +28,7 @@ #include #include #include +#include "init_log.h" #include "list.h" #include "securec.h" @@ -148,7 +149,7 @@ void Trigger(const char *sysPath) static void RetriggerUevent() { if (access(g_trigger, F_OK) == 0) { - printf("Skip trigger uevent, alread done\n"); + INIT_LOGI("Skip trigger uevent, alread done\n"); return; } Trigger("/sys/class"); @@ -158,7 +159,7 @@ static void RetriggerUevent() if (fd >= 0) { close(fd); } - printf("Re-trigger uevent done\n"); + INIT_LOGI("Re-trigger uevent done\n"); } static void UeventSockInit() @@ -176,7 +177,7 @@ static void UeventSockInit() int sockfd = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT); if (sockfd < 0) { - printf("Create socket failed. %d\n", errno); + INIT_LOGE("Create socket failed. %d\n", errno); return; } @@ -184,7 +185,7 @@ static void UeventSockInit() setsockopt(sockfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); if (bind(sockfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - printf("Bind socket failed. %d\n", errno); + INIT_LOGE("Bind socket failed. %d\n", errno); close(sockfd); return; } @@ -288,7 +289,7 @@ static int MakeDir(const char *path, mode_t mode) { int rc = mkdir(path, mode); if (rc < 0 && errno != EEXIST) { - printf("Create %s failed. %d\n", path, errno); + INIT_LOGE("Create %s failed. %d\n", path, errno); } return rc; } @@ -352,7 +353,7 @@ static char **ParsePlatformBlockDevice(const struct Uevent *uevent) p = strdup(uevent->partitionName); CheckValidPartitionName(p); if (strcmp(uevent->partitionName, p)) { - printf("Linking partition '%s' as '%s'\n", uevent->partitionName, p); + INIT_LOGI("Linking partition '%s' as '%s'\n", uevent->partitionName, p); } if (asprintf(&links[linkNum], "%s/by-name/%s", linkPath, p) > 0) { linkNum++; @@ -388,7 +389,7 @@ static void MakeDevice(const char *devpath, const char *path, int block, int maj setegid(gid); if (mknod(devpath, mode, dev) != 0) { if (errno != EEXIST) { - printf("Make device node[%d, %d] failed. %d\n", major, minor, errno); + INIT_LOGE("Make device node[%d, %d] failed. %d\n", major, minor, errno); } } } @@ -410,7 +411,7 @@ int MkdirRecursive(const char *pathName, mode_t mode) continue; } if ((unsigned int)width > sizeof(buf) - 1) { - printf("path too long for MkdirRecursive\n"); + INIT_LOGE("path too long for MkdirRecursive\n"); return -1; } if (memcpy_s(buf, width, pathName, width) != 0) { @@ -461,11 +462,11 @@ static void MakeLink(const char *oldPath, const char *newPath) buf[width] = 0; int ret = MkdirRecursive(buf, DEFAULT_DIR_MODE); if (ret) { - printf("Failed to create directory %s: %s (%d)\n", buf, strerror(errno), errno); + INIT_LOGE("Failed to create directory %s: %s (%d)\n", buf, strerror(errno), errno); } ret = symlink(oldPath, newPath); if (ret && errno != EEXIST) { - printf("Failed to symlink %s to %s: %s (%d)\n", oldPath, newPath, strerror(errno), errno); + INIT_LOGE("Failed to symlink %s to %s: %s (%d)\n", oldPath, newPath, strerror(errno), errno); } } @@ -536,7 +537,7 @@ static void AddPlatformDevice(const char *path) name += DEV_PLAT_FORM; } } - printf("adding platform device %s (%s)\n", name, path); + INIT_LOGI("adding platform device %s (%s)\n", name, path); struct PlatformNode *bus = calloc(1, sizeof(struct PlatformNode)); if (!bus) { return; @@ -556,7 +557,7 @@ static void RemovePlatformDevice(const char *path) for (node = (&g_platformNames)->prev; node != &g_platformNames; node = node->prev) { bus = (struct PlatformNode *)(((char*)(node)) - offsetof(struct PlatformNode, list)); if (!strcmp(path, bus->path)) { - printf("removing platform device %s\n", bus->name); + INIT_LOGI("removing platform device %s\n", bus->name); free(bus->path); ListRemove(node); free(bus); @@ -693,7 +694,7 @@ static void HandleDeviceEvent(struct Uevent *event, char *devpath, int len, cons links = GetCharacterDeviceSymlinks(event); if (!devpath[0]) { if (snprintf_s(devpath, len, len - 1, "%s%s", base, name) == -1) { - printf("[Init] snprintf_s err \n"); + INIT_LOGE("snprintf_s err \n"); goto err; } } @@ -804,7 +805,7 @@ void UeventInit() int main(const int argc, const char **argv) { - printf("Uevent demo starting...\n"); + INIT_LOGI("Uevent demo starting...\n"); UeventInit(); return 0; } diff --git a/services/test/unittest/common/BUILD.gn b/services/test/unittest/common/BUILD.gn index a692ab44a0803cf9c4abed127124bd93d64d7f53..f654300f263b6e1229972c81284a51a81060e8e3 100644 --- a/services/test/unittest/common/BUILD.gn +++ b/services/test/unittest/common/BUILD.gn @@ -22,12 +22,15 @@ if (defined(ohos_lite)) { "-lpthread", "-lm", ] - defines = ["OHOS_LITE"] + defines = [ "OHOS_LITE" ] if (storage_type == "emmc") { defines += [ "USE_EMMC_STORAGE" ] } - include_dirs = [ "//base/startup/init_lite/services/include" ] + include_dirs = [ + "//base/startup/init_lite/services/include", + "//base/startup/init_lite/services/log", + ] sources = [ "//base/startup/init_lite/services/src/init_adapter.c", @@ -36,6 +39,8 @@ if (defined(ohos_lite)) { "//base/startup/init_lite/services/src/init_service.c", "//base/startup/init_lite/services/src/init_service_manager.c", "//base/startup/init_lite/services/src/init_signal_handler.c", + "//base/startup/init_lite/services/src/init_utils.c", + "//base/startup/init_lite/services/src/init_reboot.c", "cmd_func_test.cpp", ] diff --git a/services/test/unittest/common/cmd_func_test.cpp b/services/test/unittest/common/cmd_func_test.cpp index 676403b7e43f6c15fa6be53364fabab29840db5d..7e3cc721b2535eefac8a45a129dc879a78c6daaa 100644 --- a/services/test/unittest/common/cmd_func_test.cpp +++ b/services/test/unittest/common/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);