diff --git a/initsync/src/init_sync.c b/initsync/src/init_sync.c index 73ba642b7afcddc341e892277ae9104ad60a97ad..e58145b6cc970367cc6c35704bf1b3e99065544b 100644 --- a/initsync/src/init_sync.c +++ b/initsync/src/init_sync.c @@ -18,14 +18,13 @@ #include #include #include -#include -#include #include #include #include #include #include #include "init_log.h" + static int SendCmd(int cmd, unsigned long arg) { int fd = open(QUICKSTART_NODE, O_RDONLY); diff --git a/interfaces/innerkits/dynamic_service/BUILD.gn b/interfaces/innerkits/dynamic_service/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..460cd06376e3699c81e32b51718522d409c87def --- /dev/null +++ b/interfaces/innerkits/dynamic_service/BUILD.gn @@ -0,0 +1,29 @@ +# 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_shared_library("dynamic_service") { + sources = [ "dynamic_service.c" ] + + include_dirs = [ + "//base/startup/syspara_lite/interfaces/innerkits/native/syspara/include", + "//base/startup/init_lite/interfaces/innerkits/include", + ] + + deps = [ + "//base/startup/syspara_lite/interfaces/innerkits/native/syspara:syspara", + ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + install_images = [ "system" ] + part_name = "init" +} diff --git a/interfaces/innerkits/dynamic_service/dynamic_service.c b/interfaces/innerkits/dynamic_service/dynamic_service.c new file mode 100755 index 0000000000000000000000000000000000000000..db4a8c02019ec0a945deeae51bcf00386b967d48 --- /dev/null +++ b/interfaces/innerkits/dynamic_service/dynamic_service.c @@ -0,0 +1,52 @@ +/* +* 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 "dynamic_service.h" + +#include +#include "hilog/log.h" +#include "parameter.h" + +#undef LOG_TAG +#undef LOG_DOMAIN +#define LOG_TAG "Init" +#define LOG_DOMAIN 0xD000719 + +int32_t StartDynamicProcess(const char *name) +{ + if (name == NULL) { + HILOG_ERROR(LOG_CORE, "Start dynamic service failed, service name is null."); + return -1; + } + if (SetParameter("ohos.ctl.start", name) != 0) { + HILOG_ERROR(LOG_CORE, "Set param for %{public}s failed.\n", name); + return -1; + } + return 0; +} + +int32_t StopDynamicProcess(const char *name) +{ + if (name == NULL) { + HILOG_ERROR(LOG_CORE, "Stop dynamic service failed, service is null.\n"); + return -1; + } + if (SetParameter("ohos.ctl.stop", name) != 0) { + HILOG_ERROR(LOG_CORE, "Set param for %{public}s failed.\n", name); + return -1; + } + return 0; +} + diff --git a/services/param/include/trigger_processor.h b/interfaces/innerkits/include/dynamic_service.h old mode 100644 new mode 100755 similarity index 61% rename from services/param/include/trigger_processor.h rename to interfaces/innerkits/include/dynamic_service.h index fc9a5e89e29a3dfcba0aae7918e1397b59a3e3b5..61bf8bf82960801396a83d5014eee43a17af8ebe --- a/services/param/include/trigger_processor.h +++ b/interfaces/innerkits/include/dynamic_service.h @@ -13,15 +13,10 @@ * limitations under the License. */ -#ifndef BASE_STARTUP_EVENT_MANAGER_H -#define BASE_STARTUP_EVENT_MANAGER_H +#ifndef DYNAMIC_SERVICE_API_H +#define DYNAMIC_SERVICE_API_H -#include - -#include "sys_param.h" -#include "init_param.h" -#include "trigger_manager.h" -#include "uv.h" +#include #ifdef __cplusplus #if __cplusplus @@ -29,21 +24,13 @@ 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; +int32_t StartDynamicProcess(const char *name); +int32_t StopDynamicProcess(const char *name); #ifdef __cplusplus #if __cplusplus } #endif #endif -#endif \ No newline at end of file + +#endif // DYNAMIC_SERVICE_API_H \ No newline at end of file diff --git a/interfaces/innerkits/reboot/BUILD.gn b/interfaces/innerkits/reboot/BUILD.gn index d603b712bd10d036e37f1d8144c7bb743e3a0268..a34705e6c72bc12326205b3a3aa9a3265ebc476d 100644 --- a/interfaces/innerkits/reboot/BUILD.gn +++ b/interfaces/innerkits/reboot/BUILD.gn @@ -25,7 +25,7 @@ ohos_static_library("libreboot") { deps = [ "//base/startup/init_lite/services/log:init_log", - "//base/startup/init_lite/services/param:paramclient", + "//base/startup/init_lite/services/param:param_client", "//third_party/bounds_checking_function:libsec_static", ] } diff --git a/interfaces/innerkits/reboot/init_reboot.c b/interfaces/innerkits/reboot/init_reboot.c index 51ac77497edcfaacd60075eb40437a9722f99453..e2e3fb4ba795e139465e14c05975b3b54325a9f2 100644 --- a/interfaces/innerkits/reboot/init_reboot.c +++ b/interfaces/innerkits/reboot/init_reboot.c @@ -46,7 +46,7 @@ int DoReboot(const char *cmdContent) } return 0; } - int length = strlen(cmdContent); + size_t length = strlen(cmdContent); if (length > MAX_REBOOT_VAUE_SIZE) { INIT_LOGE("DoReboot api error, cmdContent = %s, length = %d.", cmdContent, length); return -1; diff --git a/interfaces/innerkits/socket/init_socket.c b/interfaces/innerkits/socket/init_socket.c index f822a8340073175bfa53be0d15e15556e70ee890..ce28193de958de442ea0308b1cb2da09a4cebb2e 100755 --- a/interfaces/innerkits/socket/init_socket.c +++ b/interfaces/innerkits/socket/init_socket.c @@ -18,11 +18,7 @@ #include #include #include -#include -#include #include -#include -#include #include #include #include @@ -34,7 +30,7 @@ #define MAX_SOCKET_ENV_PREFIX_LEN 64 #define MAX_SOCKET_DIR_LEN 128 -static int GetControlFromEnv(char *path, int length) +static int GetControlFromEnv(const char *path, int length) { if (path == NULL || length <= 0) { return -1; diff --git a/services/BUILD.gn b/services/BUILD.gn index 1994c2efafb84e51013f454979fdc76ae94f7bf0..9b8bb8603a66b864f0a5e2bc950515f3616b2836 100644 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -112,7 +112,7 @@ if (defined(ohos_lite)) { ] deps = [ "//base/startup/init_lite/services/log:init_log", - "//base/startup/init_lite/services/param:paramservice", + "//base/startup/init_lite/services/param:param_service", "//third_party/bounds_checking_function:libsec_static", "//third_party/cJSON:cjson_static", ] @@ -134,13 +134,17 @@ if (defined(ohos_lite)) { deps = [ ":init", ":init_etc", + "//base/startup/init_lite/interfaces/innerkits/dynamic_service:dynamic_service", "//base/startup/init_lite/interfaces/innerkits/socket:libsocket", "//base/startup/init_lite/services/cmds/reboot:reboot", "//base/startup/init_lite/services/cmds/service_control:service_control", - "//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/param:param", + "//base/startup/init_lite/services/param:param_client", + "//base/startup/init_lite/services/param:param_service", + "//base/startup/init_lite/services/param:param_watcher", + "//base/startup/init_lite/services/param:param_watcher.rc", + "//base/startup/init_lite/services/param:param_watcheragent", + "//base/startup/init_lite/services/param/watcher/sa_profile:param_watcher_profile", ] } @@ -179,8 +183,15 @@ if (defined(ohos_lite)) { } ohos_prebuilt_etc("ohos.para") { - source = "//base/startup/init_lite/services/etc/ohos.para" + source = "//base/startup/init_lite/services/etc/param/ohos.para" part_name = "init" + module_install_dir = "etc/param" + } + + ohos_prebuilt_etc("ohos.para.dac") { + source = "//base/startup/init_lite/services/etc/param/ohos.para.dac" + part_name = "init" + module_install_dir = "etc/param" } group("init_etc") { @@ -190,6 +201,7 @@ if (defined(ohos_lite)) { ":init.usb.cfg", ":init.usb.configfs.cfg", ":ohos.para", + ":ohos.para.dac", ":passwd", ] } diff --git a/services/cmds/reboot/init_cmd_reboot.c b/services/cmds/reboot/init_cmd_reboot.c index 943021b1e6112a308a702d540adcffcdaf329edf..528a9d370c6719f15863351441cbfd1581112970 100644 --- a/services/cmds/reboot/init_cmd_reboot.c +++ b/services/cmds/reboot/init_cmd_reboot.c @@ -19,17 +19,26 @@ #include "init_reboot.h" #define REBOOT_CMD_NUMBER 2 +#define USAGE_INFO "usage: reboot shutdown\n"\ + " reboot updater\n"\ + " reboot updater[:options]\n" \ + " reboot flash\n" \ + " reboot flash[:options]\n" \ + " reboot\n" int main(int argc, char* argv[]) { if (argc > REBOOT_CMD_NUMBER) { - printf("usage: reboot shutdown\n reboot updater\n reboot updater[:options]\n reboot\n"); + printf("%s", USAGE_INFO); return 0; } + if (argc == REBOOT_CMD_NUMBER && 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"); + strcmp(argv[1], "flash") != 0 && + strncmp(argv[1], "updater:", strlen("updater:")) != 0 && + strncmp(argv[1], "flash:", strlen("flash:")) != 0) { + printf("%s", USAGE_INFO); return 0; } int ret = 0; diff --git a/services/cmds/service_control/BUILD.gn b/services/cmds/service_control/BUILD.gn index 0e8f91315cadb335534da7af473659048e20a73f..682b137f5cec80295ae7c52301be7000a1e656e1 100755 --- a/services/cmds/service_control/BUILD.gn +++ b/services/cmds/service_control/BUILD.gn @@ -19,7 +19,7 @@ ohos_executable("service_control") { "//base/startup/init_lite/services/include", ] deps = [ - "//base/startup/init_lite/services/param:paramclient", + "//base/startup/init_lite/services/param:param_client", "//third_party/bounds_checking_function:libsec_static", ] symlink_target_name = [ diff --git a/services/etc/init.cfg b/services/etc/init.cfg index f32a7bbb05eaee385220c2c283a41fe5181263dd..e0e54bea5dad413423b8e87cbe06653b28cb6eec 100755 --- a/services/etc/init.cfg +++ b/services/etc/init.cfg @@ -63,27 +63,7 @@ "mount configfs none /config nodev noexec nosuid", "chmod 0770 /config/sdcardfs", "chown system package_info /config/sdcardfs", - "mkdir /mnt/secure 0700 root root", - "mkdir /mnt/secure/asec 0700 root root", - "mkdir /mnt/asec 0755 root system", - "mkdir /mnt/obb 0755 root system", - "mkdir /mnt/media_rw 0750 root media_rw", - "mkdir /mnt/user 0755 root root", - "mkdir /mnt/user/0 0755 root root", - "mkdir /mnt/expand 0771 system system", - "mkdir /mnt/appfuse 0711 root root", - "mkdir /mnt/runtime 0700 root root", - "mkdir /mnt/runtime/default 0755 root root", - "mkdir /mnt/runtime/default/self 0755 root root", - "mkdir /mnt/runtime/read 0755 root root", - "mkdir /mnt/runtime/read/self 0755 root root", - "mkdir /mnt/runtime/write 0755 root root", - "mkdir /mnt/runtime/write/self 0755 root root", - "mkdir /mnt/runtime/full 0755 root root", - "mkdir /mnt/runtime/full/self 0755 root root", "symlink /storage/self/primary /sdcard", - "symlink /storage/self/primary /mnt/sdcard", - "symlink /mnt/user/0/primary /mnt/runtime/default/self/primary", "write /proc/sys/kernel/panic_on_oops 1", "write /proc/sys/kernel/hung_task_timeout_secs 0", "write /proc/cpu/alignment 4", @@ -153,25 +133,12 @@ "chmod 0600 /dev/cg2_bpf", "mount bpf bpf /sys/fs/bpf nodev noexec nosuid", "mkdir /dev/fscklogs 0770 root system", - "mount pstore pstore /sys/fs/pstore nodev noexec nosuid", - "chown system log /sys/fs/pstore", - "chmod 0550 /sys/fs/pstore", - "chown system log /sys/fs/pstore/console-ramoops", - "chmod 0440 /sys/fs/pstore/console-ramoops", - "chown system log /sys/fs/pstore/console-ramoops-0", - "chmod 0440 /sys/fs/pstore/console-ramoops-0", - "chown system log /sys/fs/pstore/pmsg-ramoops-0", - "chmod 0440 /sys/fs/pstore/pmsg-ramoops-0", "write /proc/sys/abi/swp 1", "symlink /proc/self/fd /dev/fd", "export DOWNLOAD_CACHE /data/cache", "setrlimit RLIMIT_NICE 40 40", "setrlimit RLIMIT_NOFILE 32768 32768", "write /sys/class/leds/vibrator/trigger transient", - "write /dev/cpu_variant:${ro.bionic.arch} ${ro.bionic.cpu_variant}", - "chmod 0444 /dev/cpu_variant:${ro.bionic.arch}", - "write /dev/cpu_variant:${ro.bionic.2nd_arch} ${ro.bionic.2nd_cpu_variant}", - "chmod 0444 /dev/cpu_variant:${ro.bionic.2nd_arch}", "chown system system /sys/power/state", "chown system system /sys/power/wakeup_count", "chmod 0660 /sys/power/state", @@ -182,6 +149,7 @@ }, { "name" : "load_persist_props_action", "cmds" : [ + "mkdir /data/parameters 0770 root root", "load_persist_params load_persist_params" ] }, { @@ -205,27 +173,14 @@ }, { "name" : "post-fs", "cmds" : [ - "exec - system system -- /system/bin/vdc checkpoint markBootAttempt", "mount rootfs rootfs / remount bind ro nodev", - "mount none /mnt/runtime/default /storage bind rec", - "mount none none /storage slave rec", - "chown system cache /cache", - "chmod 0770 /cache", - "mkdir /cache/recovery 0770 system cache", - "mkdir /cache/backup_stage 0700 system system", - "mkdir /cache/backup 0700 system system", "chown root log /proc/vmallocinfo", "chmod 0440 /proc/vmallocinfo", "chown root log /proc/slabinfo", "chmod 0440 /proc/slabinfo", "chown root system /proc/kmsg", "chmod 0440 /proc/kmsg", - "chown root system /proc/sysrq-trigger", - "chmod 0220 /proc/sysrq-trigger", - "chown system log /proc/last_kmsg", - "chmod 0440 /proc/last_kmsg", - "chmod 0444 /sys/fs/selinux/policy", - "mkdir /cache/lost+found 0770 root root" + "chmod 0444 /sys/fs/selinux/policy" ] }, { "name" : "late-fs", @@ -325,6 +280,7 @@ "mkdir /data/cache/recovery 0770 system cache", "mkdir /data/cache/backup_stage 0700 system system", "mkdir /data/cache/backup 0700 system system", + "mkdir /data/init_agent 0776 shell shell", "setparam sys.use_memfd false", "chown root system /dev/fscklogs/log", "chmod 0770 /dev/fscklogs/log" @@ -346,11 +302,6 @@ "write /proc/sys/vm/dirty_expire_centisecs 200", "write /proc/sys/vm/dirty_background_ratio 5", "write /sys/fs/f2fs/${dev.mnt.blk.data}/cp_interval 200", - "chown radio system /sys/android_power/state", - "chown radio system /sys/android_power/request_state", - "chown radio system /sys/android_power/acquire_full_wake_lock", - "chown radio system /sys/android_power/acquire_partial_wake_lock", - "chown radio system /sys/android_power/release_wake_lock", "chown system system /sys/power/autosleep", "chown radio wakelock /sys/power/wake_lock", "chown radio wakelock /sys/power/wake_unlock", diff --git a/services/etc/ohos.para b/services/etc/param/ohos.para similarity index 100% rename from services/etc/ohos.para rename to services/etc/param/ohos.para diff --git a/services/etc/param/ohos.para.dac b/services/etc/param/ohos.para.dac new file mode 100755 index 0000000000000000000000000000000000000000..51473e979e946098aaa28956e87be3d87dd628ce --- /dev/null +++ b/services/etc/param/ohos.para.dac @@ -0,0 +1,34 @@ +# 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. + +build_version root:root:0777 +hw_sc.build.os.enable root:root:0777 +hw_sc.build.os.apiversion root:root:0777 +hw_sc.build.os.version root:root:0777 +hw_sc.build.os.releasetype root:root:0777 + +const.actionable_compatible_property.enabled root:root:0777 +const.postinstall.fstab.prefix root:root:0777 +const.secure root:root:0777 +security.perf_harden root:root:0777 +const.allow.mock.location root:root:0777 +const.debuggable root:root:0777 +persist.sys.usb.config root:root:0777 + +# default forbit other user to start service +ohos.servicectrl. root:root:0777 + +test.permission. root:root:0770 +test.permission.read. root:root:0774 +test.permission.write. root:root:0772 +test.permission.watcher. root:root:0771 \ No newline at end of file diff --git a/services/include/init_cmds.h b/services/include/init_cmds.h index 232f24a3d3a515cca0eb3217a1b7bcfffada763e..343ec32d5980ddb2beae8ff91e68a275baa7f5d0 100644 --- a/services/include/init_cmds.h +++ b/services/include/init_cmds.h @@ -52,13 +52,15 @@ struct CmdArgs { int GetParamValue(const char *symValue, char *paramValue, unsigned int paramLen); struct CmdArgs* GetCmd(const char *cmdContent, const char *delim, int argsCount); -void FreeCmd(struct CmdArgs **cmd); +void FreeCmd(struct CmdArgs *cmd); 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); +const char *GetMatchCmd(const char *cmdStr, unsigned int *index); +const char *GetCmdKey(unsigned int index); + #ifdef __cplusplus #if __cplusplus } diff --git a/services/include/init_import.h b/services/include/init_import.h index 48b6c01dd4ec79018b48140176110913bf140d59..5def1efa8c212517ea3f09afeb04729deccdfd8d 100644 --- a/services/include/init_import.h +++ b/services/include/init_import.h @@ -12,8 +12,10 @@ * 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 +#ifndef BASE_STARTUP_INITLITE_IMPORT_H +#define BASE_STARTUP_INITLITE_IMPORT_H + +#include "cJSON.h" +void ParseAllImports(const cJSON *root); + +#endif diff --git a/services/include/init_jobs.h b/services/include/init_jobs.h index 7c7ffaed5cd53b53715f2317d128f7a9594f1e48..47937a77e3196a8c646df06521442684ffdaad5e 100644 --- a/services/include/init_jobs.h +++ b/services/include/init_jobs.h @@ -36,8 +36,8 @@ typedef struct { void ParseAllJobs(const cJSON* fileRoot); void DoJob(const char* jobName); -void ReleaseAllJobs(); -void DumpAllJobs(); +void ReleaseAllJobs(void); +void DumpAllJobs(void); #ifdef __cplusplus #if __cplusplus } diff --git a/services/include/init_service.h b/services/include/init_service.h index fd269c23887f201e354d8eafd671c7ea27068b7b..69d5e643a2bc9070b23e3ecbefec8f10ac219a45 100644 --- a/services/include/init_service.h +++ b/services/include/init_service.h @@ -39,6 +39,7 @@ extern "C" { #define SERVICE_ATTR_CRITICAL 0x020 // critical, will reboot if it crash 4 times in 4 minutes #define SERVICE_ATTR_DISABLED 0x040 // disabled #define SERVICE_ATTR_CONSOLE 0x080 // console +#define SERVICE_ATTR_DYNAMIC 0x100 // dynamic service #define MAX_SERVICE_NAME 32 #define MAX_WRITEPID_FILES 100 diff --git a/services/include/init_service_manager.h b/services/include/init_service_manager.h index 3e680d3a9b7787e01a473348b8e279d34ed6aa12..1208307ab9e15ca96aae97fe5b4b998be28f27ea 100644 --- a/services/include/init_service_manager.h +++ b/services/include/init_service_manager.h @@ -36,15 +36,15 @@ extern "C" { #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 RegisterServices(Service *services, int servicesCnt); +void StartServiceByName(const char *serviceName, bool checkDynamic); +void StopServiceByName(const char *serviceName); +void StopAllServices(void); +void StopAllServicesBeforeReboot(void); void ReapServiceByPID(int pid); -void ParseAllServices(const cJSON* fileRoot); +void ParseAllServices(const cJSON *fileRoot); #ifdef OHOS_SERVICE_DUMP -void DumpAllServices(); +void DumpAllServices(void); #endif #ifdef __cplusplus #if __cplusplus diff --git a/services/include/init_service_socket.h b/services/include/init_service_socket.h index 32669508531a6ac7d837e7b7421c9d89e722e9c1..6ff5ed5638f0697c198866a62418a82a7ea995d2 100644 --- a/services/include/init_service_socket.h +++ b/services/include/init_service_socket.h @@ -23,8 +23,7 @@ #define MAX_SOCK_NAME_LEN 16 #define SOCK_OPT_NUMS 6 -enum SockOptionTab -{ +enum SockOptionTab { SERVICE_SOCK_NAME = 0, SERVICE_SOCK_TYPE, SERVICE_SOCK_PERM, @@ -34,8 +33,7 @@ enum SockOptionTab }; struct ServiceSocket; -struct ServiceSocket -{ +struct ServiceSocket { char *name; // service name int type; // socket type uid_t uid; // uid diff --git a/services/include/init_utils.h b/services/include/init_utils.h index 3dcdbcbdac7c0174f3224f518b55135cc3d8d435..17fe242393445c3df804033e98f5b46d8b024dca 100644 --- a/services/include/init_utils.h +++ b/services/include/init_utils.h @@ -16,6 +16,8 @@ #ifndef INIT_UTILS_H #define INIT_UTILS_H +#include + #ifdef __cplusplus #if __cplusplus extern "C" { @@ -26,12 +28,12 @@ extern "C" { #define OCTAL_BASE 8 #define DECIMAL_BASE 10 -int DecodeUid(const char *name); -void CheckAndCreateDir(const char *fileName); +#define ARRAY_LENGTH(array) (sizeof((array)) / sizeof((array)[0])) +uid_t DecodeUid(const char *name); char* ReadFileToBuf(const char *configFile); int SplitString(char *srcPtr, char **dstPtr, int maxNum); void WaitForFile(const char *source, unsigned int maxCount); - +size_t WriteAll(int fd, char *buffer, size_t size); #ifdef __cplusplus #if __cplusplus } diff --git a/ueventd/list.h b/services/include/list.h similarity index 85% rename from ueventd/list.h rename to services/include/list.h index 06eaaff05d799f7c4c5f2f7c172c09fa69f8d841..ebb1dc9548fa93040f42482a60a9d9808793678f 100755 --- a/ueventd/list.h +++ b/services/include/list.h @@ -28,9 +28,8 @@ typedef struct ListNode { } ListNode; #define ListEmpty(node) ((node).next == &(node) && (node).prev == &(node)) -#define ListEntry(ptr, type, member) (type *)((char *)(ptr) - offsetof(type, member)) -#define ForEachListEntry(list, node) \ - for (node = (list)->next; node != (list); node = node->next) +#define ListEntry(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member))) +#define ForEachListEntry(list, node) for (node = (list)->next; node != (list); node = node->next) 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 index dfdd52b0b966dbabf63d928398f38c46e968330c..802198f352e03d027241adc7795e3894e32d81d8 100644 --- a/services/include/param/init_param.h +++ b/services/include/param/init_param.h @@ -15,62 +15,50 @@ #ifndef BASE_STARTUP_INIT_PARAM_H #define BASE_STARTUP_INIT_PARAM_H +#include #include -#include "cJSON.h" -#include "sys_param.h" +#include "cJSON.h" +#include "param.h" #ifdef __cplusplus #if __cplusplus extern "C" { #endif #endif - -typedef enum { - EVENT_PROPERTY, // 参数修改事件 - EVENT_BOOT -} EventType; - /** * Init 接口 * 初始化参数服务 * */ -void InitParamService(); +void InitParamService(void); /** * Init 接口 * 启动参数服务,在main启动的最后调用,阻赛当前线程 * */ -int StartParamService(); +int StartParamService(void); /** * Init 接口 * 停止参数服务 * */ -void StopParamService(); +void StopParamService(void); /** * Init 接口 * 加载默认的参数值 * */ -int LoadDefaultParams(const char *fileName); - -/** - * Init 接口 - * 安全使用,加载参数的信息,包括selinux label 等 - * - */ -int LoadParamInfos(const char *fileName); +int LoadDefaultParams(const char *fileName, int mode); /** * Init 接口 * 加载默认参数。 * */ -int LoadPersistParams(); +int LoadPersistParams(void); /** * Init 接口 @@ -91,28 +79,21 @@ int SystemReadParam(const char *name, char *value, unsigned int *len); * 触发一个trigger操作。 * */ -void PostTrigger(EventType type, const char *content, u_int32_t contentLen); - -/** - * 对Init接口 - * 触发一个参数trigger操作。 - * - */ -void PostParamTrigger(const char *name, const char *value); +void PostTrigger(EventType type, const char *content, uint32_t contentLen); /** * 对Init接口 * 解析trigger文件。 * */ -int ParseTriggerConfig(cJSON *fileRoot); +int ParseTriggerConfig(const cJSON *fileRoot); /** * 对Init接口 * 按名字执行对应的trigger。 * */ -void DoTriggerExec(const char *content); +void DoTriggerExec(const char *triggerName); /** * 对Init接口 diff --git a/services/include/param/param.h b/services/include/param/param.h new file mode 100755 index 0000000000000000000000000000000000000000..7a57bf0006314b27998ec6e70c11586e216fa0a1 --- /dev/null +++ b/services/include/param/param.h @@ -0,0 +1,61 @@ +/* + * 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_H +#define BASE_STARTUP_PARAM_H +#include +#include + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +#define PARAM_CONST_VALUE_LEN_MAX 4096 +#define PARAM_VALUE_LEN_MAX 96 +#define PARAM_NAME_LEN_MAX 96 +typedef uint32_t ParamHandle; + +typedef enum { + PARAM_CODE_ERROR = -1, + PARAM_CODE_SUCCESS = 0, + PARAM_CODE_INVALID_PARAM = 100, + PARAM_CODE_INVALID_NAME, + PARAM_CODE_INVALID_VALUE, + PARAM_CODE_REACHED_MAX, + PARAM_CODE_NOT_SUPPORT, + PARAM_CODE_TIMEOUT, + PARAM_CODE_NOT_FOUND, + PARAM_CODE_READ_ONLY, + PARAM_CODE_FAIL_CONNECT, + PARAM_CODE_MAX +} PARAM_CODE; + +typedef enum { + EVENT_TRIGGER_PARAM, + EVENT_TRIGGER_BOOT, + EVENT_TRIGGER_PARAM_WAIT, + EVENT_TRIGGER_PARAM_WATCH +} EventType; + +#define LOAD_PARAM_NORMAL 0x00 +#define LOAD_PARAM_ONLY_ADD 0x01 +#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 index f5b030bdbcfc13c62a8b1fa4c99846dc914ebee5..970898197619a8257d7f8e2784ed20e1ceebf35a 100644 --- a/services/include/param/sys_param.h +++ b/services/include/param/sys_param.h @@ -16,34 +16,18 @@ #ifndef BASE_STARTUP_SYS_PARAM_H #define BASE_STARTUP_SYS_PARAM_H #include -#include +#include #include +#include "param.h" #ifdef __cplusplus #if __cplusplus extern "C" { #endif #endif -#define PARAM_VALUE_LEN_MAX 96 -#define PARAM_NAME_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; +#define DEFAULT_PARAM_WAIT_TIMEOUT 30 // 30s +#define DEFAULT_PARAM_SET_TIMEOUT 10 // 10s /** * 对外接口 @@ -61,6 +45,21 @@ int SystemSetParameter(const char *name, const char *value); */ int SystemGetParameter(const char *name, char *value, unsigned int *len); +/** + * 对外接口 + * 查询参数,主要用于其他进程使用,找到对应属性的handle。 + * + */ +int SystemFindParameter(const char *name, ParamHandle *handle); + +/** + * 对外接口 + * 根据handle获取对应数据的修改标识。 + * commitId 获取计数变化 + * + */ +int SystemGetParameterCommitId(ParamHandle handle, uint32_t *commitId); + /** * 外部接口 * 遍历参数。 @@ -83,6 +82,19 @@ int SystemGetParameterName(ParamHandle handle, char *name, unsigned int len); * */ int SystemGetParameterValue(ParamHandle handle, char *value, unsigned int *len); + +/** + * 外部接口 + * 等待某个参数值被修改,阻塞直到参数值被修改或超时 + * + */ +int SystemWaitParameter(const char *name, const char *value, int32_t timeout); + +typedef void (*ParameterChangePtr)(const char *key, const char *value, void *context); +int SystemWatchParameter(const char *keyprefix, ParameterChangePtr change, void *context); + +void SystemDumpParameters(int verbose); + #ifdef __cplusplus #if __cplusplus } diff --git a/services/log/BUILD.gn b/services/log/BUILD.gn index 0603b625dc2e5602d97111f437712344ab40bf33..adac11b5c9e4cc9a8a57848edb1bc927221c1d7f 100644 --- a/services/log/BUILD.gn +++ b/services/log/BUILD.gn @@ -25,4 +25,13 @@ if (defined(ohos_lite)) { part_name = "startup" subsystem_name = "startup" } + + ohos_static_library("agent_log") { + sources = [ "init_log.c" ] + deps = [ "//third_party/bounds_checking_function:libsec_static" ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + defines = [ "INIT_AGENT" ] + part_name = "startup" + subsystem_name = "startup" + } } diff --git a/services/log/init_log.c b/services/log/init_log.c index 5c5719d9cb27e1bc4ea4c886f8b5073d0bd16f9a..5a1457645e62613dd6aff3410ea7e5ea9f8157a2 100644 --- a/services/log/init_log.c +++ b/services/log/init_log.c @@ -65,6 +65,7 @@ void InitToHiLog(LogLevel logLevel, const char *fmt, ...) } #endif +#ifndef INIT_AGENT // for init static int g_fd = -1; void OpenLogDevice(void) { @@ -126,3 +127,41 @@ void InitLog(InitLogLevel logLevel, const char *fileName, int line, const char * } return; } +#else // for other process +static FILE *g_outfile = NULL; +void InitLog(InitLogLevel logLevel, const char *fileName, int line, const char *kLevel, + const char *fmt, ...) +{ + if (logLevel < g_logLevel) { + return; + } + time_t second = time(0); + if (second < 0) { + return; + } + struct tm *t = localtime(&second); + if (t == NULL) { + return; + } + + if (g_outfile == NULL) { + chmod(PARAM_AGENT_LOG_PATH, S_IRWXU | S_IRWXG | S_IRWXO); + g_outfile = fopen(PARAM_AGENT_LOG_PATH, "w+"); + } + if (g_outfile == NULL) { + (void)fprintf(stdout, "%s[%d-%d-%d %d:%d:%d][pid=%d][%s:%d][%s][%s] ", kLevel, (t->tm_year + BASE_YEAR), + (t->tm_mon + 1), t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, gettid(), fileName, + line, INIT_LOG_TAG, LOG_LEVEL_STR[logLevel]); + printf("output %s error: %s \n", fmt, strerror(errno)); + return; + } + (void)fprintf(g_outfile, "%s[%d-%d-%d %d:%d:%d][pid=%d][%s:%d][%s][%s] ", kLevel, (t->tm_year + BASE_YEAR), + (t->tm_mon + 1), t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, getpid(), fileName, + line, INIT_LOG_TAG, LOG_LEVEL_STR[logLevel]); + va_list list; + va_start(list, fmt); + (void)vfprintf(g_outfile, fmt, list); + va_end(list); + (void)fflush(g_outfile); +} +#endif \ No newline at end of file diff --git a/services/log/init_log.h b/services/log/init_log.h index 37817237a777d7745bc24c6a8971a5c28761e4ae..84240a559ba8472e903c28fd6307a01f677d52c2 100644 --- a/services/log/init_log.h +++ b/services/log/init_log.h @@ -69,10 +69,36 @@ void SetHiLogLevel(LogLevel logLevel); #define INIT_LOGE(fmt, ...) InitLog(INIT_ERROR, (FILE_NAME), (__LINE__), "<3>", fmt"\n", ##__VA_ARGS__) #define INIT_LOGF(fmt, ...) InitLog(INIT_FATAL, (FILE_NAME), (__LINE__), "<3>", fmt"\n", ##__VA_ARGS__) +#ifndef INIT_AGENT #define STARTUP_LOGD(LABEL, fmt, ...) InitLog(INIT_DEBUG, (FILE_NAME), (__LINE__), "<7>", fmt "\n", ##__VA_ARGS__) #define STARTUP_LOGI(LABEL, fmt, ...) InitLog(INIT_INFO, (FILE_NAME), (__LINE__), "<6>", fmt "\n", ##__VA_ARGS__) #define STARTUP_LOGE(LABEL, fmt, ...) InitLog(INIT_ERROR, (FILE_NAME), (__LINE__), "<3>", fmt "\n", ##__VA_ARGS__) +#else +#include "hilog/log.h" +#define PARAM_AGENT_LOG_PATH "/data/init_agent/init_agent.log" + +#define STARTUP_LOGD(LABEL, fmt, ...) \ + do { \ + InitLog(INIT_DEBUG, (FILE_NAME), (__LINE__), "", fmt "\n", ##__VA_ARGS__); \ + (void)HiLogPrint(LOG_APP, LOG_DEBUG, LOG_DOMAIN, LABEL, "[%{public}s(%{public}d)] " fmt, \ + (FILE_NAME), (__LINE__), ##__VA_ARGS__); \ + } while (0) + +#define STARTUP_LOGI(LABEL, fmt, ...) \ + do { \ + InitLog(INIT_INFO, (FILE_NAME), (__LINE__), "", fmt "\n", ##__VA_ARGS__); \ + (void)HiLogPrint(LOG_APP, LOG_INFO, LOG_DOMAIN, LABEL, "[%{public}s(%{public}d)] " fmt, \ + FILE_NAME, __LINE__, ##__VA_ARGS__); \ + } while (0) +#define STARTUP_LOGE(LABEL, fmt, ...) \ + do { \ + InitLog(INIT_ERROR, (FILE_NAME), (__LINE__), "", fmt "\n", ##__VA_ARGS__); \ + (void)HiLogPrint(LOG_APP, LOG_ERROR, LOG_DOMAIN, LABEL, "[%{public}s(%{public}d)] " fmt, \ + FILE_NAME, __LINE__, ##__VA_ARGS__); \ + } while (0) + +#endif void InitLog(InitLogLevel logLevel, const char *fileName, int line, const char *kLevel, const char *fmt, ...); void SetLogLevel(InitLogLevel logLevel); @@ -117,6 +143,13 @@ void EnableDevKmsg(void); } \ } while (0) +#define INIT_CHECK_ONLY_ELOG(ret, format, ...) \ + do { \ + if (!(ret)) { \ + INIT_LOGE(format, ##__VA_ARGS__); \ + } \ + } while (0) + #ifdef __cplusplus #if __cplusplus } diff --git a/services/param/BUILD.gn b/services/param/BUILD.gn index 07e1d27849151a38ed8427a639bcd9d523f8f6be..3249c348af373da7de9c4bdb62d70cba9ad6ed7f 100644 --- a/services/param/BUILD.gn +++ b/services/param/BUILD.gn @@ -12,12 +12,29 @@ # limitations under the License. import("//build/ohos.gni") -ohos_static_library("paramservice") { +declare_args() { + param_security = "dac" +} + +ohos_prebuilt_etc("param_watcher.rc") { + if (use_musl) { + source = "watcher/etc/param_watcher.cfg" + } else { + source = "watcher/etc/param_watcher.rc" + } + relative_install_dir = "init" + part_name = "init" +} + +ohos_static_library("param_service") { sources = [ - "//base/startup/init_lite/services/src/init_utils.c", - "manager/param_cache.c", + "//base/startup/init_lite/services/src/list.c", + "adapter/param_libuvadp.c", + "adapter/param_persistadp.c", "manager/param_manager.c", + "manager/param_message.c", "manager/param_trie.c", + "manager/param_utils.c", "service/param_persist.c", "service/param_service.c", "trigger/trigger_checker.c", @@ -27,6 +44,7 @@ ohos_static_library("paramservice") { include_dirs = [ "include", + "adapter", "//base/startup/init_lite/services/include/param", "//base/startup/init_lite/services/include", "//base/startup/init_lite/services/log", @@ -34,6 +52,16 @@ ohos_static_library("paramservice") { "//third_party/cJSON", ] + defines = [ "PARAM_SUPPORT_SAVE_PERSIST" ] + + if (param_security == "selinux") { + sources += [ "adapter/param_selinux.c" ] + defines += [ "PARAM_SUPPORT_SELINUX" ] + } else { + sources += [ "adapter/param_dac.c" ] + defines += [ "PARAM_SUPPORT_DAC" ] + } + deps = [ "//third_party/bounds_checking_function:libsec_static", "//third_party/libuv:uv_static", @@ -42,13 +70,13 @@ ohos_static_library("paramservice") { subsystem_name = "startup" } -ohos_static_library("paramclient") { +ohos_shared_library("param_client") { sources = [ - "//base/startup/init_lite/services/src/init_utils.c", "client/param_request.c", - "manager/param_cache.c", "manager/param_manager.c", + "manager/param_message.c", "manager/param_trie.c", + "manager/param_utils.c", ] include_dirs = [ @@ -56,49 +84,132 @@ ohos_static_library("paramclient") { "//base/startup/init_lite/services/include/param", "//base/startup/init_lite/services/include", "//base/startup/init_lite/services/log", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", "//third_party/libuv/include", - "//third_party/cJSON", ] + defines = [ "INIT_AGENT" ] + + if (param_security == "selinux") { + sources += [ "adapter/param_selinux.c" ] + defines += [ "PARAM_SUPPORT_SELINUX" ] + } else { + sources += [ "adapter/param_dac.c" ] + defines += [ "PARAM_SUPPORT_DAC" ] + } + deps = [ - "//base/startup/init_lite/services/log:init_log", + "//base/startup/init_lite/services/log:agent_log", "//third_party/bounds_checking_function:libsec_static", - "//third_party/libuv:uv_static", ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] part_name = "init" - subsystem_name = "startup" } -ohos_executable("getparam") { - sources = [ "cmd/param_get.c" ] +ohos_shared_library("param_watcheragent") { + sources = [ + "watcher/agent/watcher.cpp", + "watcher/agent/watcher_manager_kits.cpp", + "watcher/agent/watcher_manager_proxy.cpp", + "watcher/agent/watcher_stub.cpp", + ] + include_dirs = [ "include", "//base/startup/init_lite/services/include/param", + "//base/startup/init_lite/services/param/watcher/include", + "//base/startup/init_lite/services/param/watcher/agent", "//base/startup/init_lite/services/include", "//base/startup/init_lite/services/log", + "//base/update/updateservice/interfaces/innerkits/include", ] + + defines = [ "INIT_AGENT" ] + deps = [ - "//base/startup/init_lite/services/param:paramclient", + "//base/startup/init_lite/services/log:agent_log", + "//base/startup/init_lite/services/param:param_client", "//third_party/bounds_checking_function:libsec_static", - "//third_party/cJSON:cjson_static", + "//utils/native/base:utils", ] - install_enable = true + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr_L2:samgr_proxy", + ] + part_name = "init" } -ohos_executable("setparam") { - sources = [ "cmd/param_set.c" ] +ohos_shared_library("param_watcher") { + sources = [ + "watcher/proxy/watcher_manager.cpp", + "watcher/proxy/watcher_manager_stub.cpp", + "watcher/proxy/watcher_proxy.cpp", + ] + + include_dirs = [ + "include", + "//base/startup/init_lite/services/include/param", + "//base/startup/init_lite/services/param/watcher/proxy", + "//base/startup/init_lite/services/param/watcher/include", + "//base/startup/init_lite/services/include", + "//base/startup/init_lite/services/log", + "//third_party/libuv/include", + "//third_party/cJSON", + "//utils/native/base/include", + "//utils/system/safwk/native/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/distributedschedule/safwk/services/safwk/include", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + ] + + defines = [ "INIT_AGENT" ] + + deps = [ + "//base/startup/init_lite/services/log:agent_log", + "//base/startup/init_lite/services/param:param_client", + "//third_party/bounds_checking_function:libsec_static", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr_L2:samgr_proxy", + ] + install_images = [ "system" ] + part_name = "init" +} + +ohos_executable("param") { + sources = [ "cmd/param_cmd.c" ] include_dirs = [ "include", "//base/startup/init_lite/services/include/param", "//base/startup/init_lite/services/include", "//base/startup/init_lite/services/log", + "//base/update/updateservice/interfaces/innerkits/include", ] + + defines = [ + "PARAM_TEST", + "INIT_AGENT", + ] + deps = [ - "//base/startup/init_lite/services/param:paramclient", + "//base/startup/init_lite/services/log:agent_log", + "//base/startup/init_lite/services/param:param_client", + "//base/startup/init_lite/services/param:param_watcheragent", + "//base/update/updateservice/interfaces/innerkits/engine:updateservicekits", "//third_party/bounds_checking_function:libsec_static", - "//third_party/cJSON:cjson_static", ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] install_enable = true part_name = "init" } diff --git a/services/param/adapter/param_dac.c b/services/param/adapter/param_dac.c new file mode 100755 index 0000000000000000000000000000000000000000..11adc177a80957641408b104cced66962ae968a2 --- /dev/null +++ b/services/param/adapter/param_dac.c @@ -0,0 +1,230 @@ +/* + * 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 + +#include "param_security.h" +#include "param_utils.h" + +#define OCT_BASE 8 +#define LABEL "PARAM_DAC" +static ParamSecurityLabel g_localSecurityLabel = {}; + +static void GetUserIdByName(FILE *fp, uid_t *uid, const char *name, uint32_t nameLen) +{ + *uid = -1; + (void)fseek(fp, 0, SEEK_SET); + struct passwd *data = NULL; + while ((data = fgetpwent(fp)) != NULL) { + if (strlen(data->pw_name) == nameLen && strncmp(data->pw_name, name, nameLen) == 0) { + *uid = data->pw_uid; + return; + } + } +} + +static void GetGroupIdByName(FILE *fp, gid_t *gid, const char *name, uint32_t nameLen) +{ + *gid = -1; + (void)fseek(fp, 0, SEEK_SET); + struct group *data = NULL; + while ((data = fgetgrent(fp)) != NULL) { + if (strlen(data->gr_name) == nameLen && strncmp(data->gr_name, name, nameLen) == 0) { + *gid = data->gr_gid; + break; + } + } +} + +// user:group:r|w +static int GetParamDacData(FILE *fpForGroup, FILE *fpForUser, ParamDacData *dacData, const char *value) +{ + char *groupName = strstr(value, ":"); + if (groupName == NULL) { + return -1; + } + char *mode = strstr(groupName + 1, ":"); + if (mode == NULL) { + return -1; + } + GetUserIdByName(fpForUser, &dacData->uid, value, groupName - value); + GetGroupIdByName(fpForGroup, &dacData->gid, groupName + 1, mode - groupName - 1); + dacData->mode = strtol(mode + 1, NULL, OCT_BASE); + return 0; +} + +static int InitLocalSecurityLabel(ParamSecurityLabel **security, int isInit) +{ + UNUSED(isInit); + PARAM_LOGD("InitLocalSecurityLabel uid:%d gid:%d euid: %d egid: %d ", getuid(), getgid(), geteuid(), getegid()); + g_localSecurityLabel.cred.pid = getpid(); + g_localSecurityLabel.cred.uid = geteuid(); + g_localSecurityLabel.cred.gid = getegid(); + *security = &g_localSecurityLabel; + // support check write permission in client + (*security)->flags |= LABEL_CHECK_FOR_ALL_PROCESS; + return 0; +} + +static int FreeLocalSecurityLabel(ParamSecurityLabel *srcLabel) +{ + return 0; +} + +static int EncodeSecurityLabel(const ParamSecurityLabel *srcLabel, char *buffer, uint32_t *bufferSize) +{ + PARAM_CHECK(bufferSize != NULL, return -1, "Invalid param"); + if (buffer == NULL) { + *bufferSize = sizeof(ParamSecurityLabel); + return 0; + } + PARAM_CHECK(*bufferSize >= sizeof(ParamSecurityLabel), return -1, "Invalid buffersize %u", *bufferSize); + *bufferSize = sizeof(ParamSecurityLabel); + return memcpy_s(buffer, *bufferSize, srcLabel, sizeof(ParamSecurityLabel)); +} + +static int DecodeSecurityLabel(ParamSecurityLabel **srcLabel, char *buffer, uint32_t bufferSize) +{ + PARAM_CHECK(bufferSize >= sizeof(ParamSecurityLabel), return -1, "Invalid buffersize %u", bufferSize); + PARAM_CHECK(srcLabel != NULL && buffer != NULL, return -1, "Invalid param"); + *srcLabel = (ParamSecurityLabel *)buffer; + return 0; +} + +static int LoadParamLabels(const char *fileName, SecurityLabelFunc label, void *context) +{ + FILE *fpForGroup = fopen(GROUP_FILE_PATH, "r"); + FILE *fpForUser = fopen(USER_FILE_PATH, "r"); + FILE *fp = fopen(fileName, "r"); + SubStringInfo *info = malloc(sizeof(SubStringInfo) * (SUBSTR_INFO_DAC + 1)); + PARAM_CHECK(fpForGroup != NULL && fpForUser != NULL && fp != NULL && info != NULL, + goto exit, "Can not open file for load param labels"); + + uint32_t infoCount = 0; + char buff[PARAM_BUFFER_SIZE]; + ParamAuditData auditData = {}; + while (fgets(buff, PARAM_BUFFER_SIZE, fp) != NULL) { + int subStrNumber = GetSubStringInfo(buff, strlen(buff), ' ', info, SUBSTR_INFO_DAC + 1); + if (subStrNumber <= SUBSTR_INFO_DAC) { + continue; + } + auditData.name = info[SUBSTR_INFO_NAME].value; +#ifdef STARTUP_INIT_TEST + auditData.label = info[SUBSTR_INFO_NAME].value; +#endif + int ret = GetParamDacData(fpForGroup, fpForUser, &auditData.dacData, info[SUBSTR_INFO_DAC].value); + PARAM_CHECK(ret == 0, continue, "Failed to get param info %d %s", ret, buff); + ret = label(&auditData, context); + PARAM_CHECK(ret == 0, continue, "Failed to write param info %d %s", ret, buff); + infoCount++; + } + PARAM_LOGI("Load parameter label total %u success %s", infoCount, fileName); +exit: + if (fp) { + (void)fclose(fp); + } + if (info) { + free(info); + } + if (fpForGroup) { + (void)fclose(fpForGroup); + } + if (fpForUser) { + (void)fclose(fpForUser); + } + return 0; +} + +static int ProcessParamFile(const char *fileName, void *context) +{ + LabelFuncContext *cxt = (LabelFuncContext *)context; + return LoadParamLabels(fileName, cxt->label, cxt->context); +} + +static int GetParamSecurityLabel(SecurityLabelFunc label, const char *path, void *context) +{ + PARAM_CHECK(label != NULL && path != NULL, return -1, "Invalid param"); + struct stat st; + LabelFuncContext cxt = {label, context}; + if ((stat(path, &st) == 0) && !S_ISDIR(st.st_mode)) { + return ProcessParamFile(path, &cxt); + } + return ReadFileInDir(path, ".para.dac", ProcessParamFile, &cxt); +} + +static int CheckFilePermission(const ParamSecurityLabel *localLabel, const char *fileName, int flags) +{ + UNUSED(flags); + PARAM_CHECK(localLabel != NULL && fileName != NULL, return -1, "Invalid param"); + return 0; +} + +static int CheckParamPermission(const ParamSecurityLabel *srcLabel, const ParamAuditData *auditData, int mode) +{ + int ret = DAC_RESULT_FORBIDED; + PARAM_CHECK(srcLabel != NULL && auditData != NULL && auditData->name != NULL, return ret, "Invalid param"); + PARAM_CHECK((mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) != 0, return ret, "Invalid mode %x", mode); + + /** + * DAC group 实现的label的定义 + * user:group:read|write|watch + */ + uint32_t localMode = 0; + if (srcLabel->cred.uid == auditData->dacData.uid) { + localMode = mode & (DAC_READ | DAC_WRITE | DAC_WATCH); + } else if (srcLabel->cred.gid == auditData->dacData.gid) { + localMode = (mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) >> DAC_GROUP_START; + } else { + localMode = (mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) >> DAC_OTHER_START; + } + if ((auditData->dacData.mode & localMode) != 0) { + ret = DAC_RESULT_PERMISSION; + } + PARAM_LOGD("Src label %d %d ", srcLabel->cred.gid, srcLabel->cred.uid); + PARAM_LOGD("auditData label %d %d mode %o lable %s", + auditData->dacData.gid, auditData->dacData.uid, auditData->dacData.mode, auditData->label); + PARAM_LOGD("%s check %o localMode %o ret %d", auditData->name, mode, localMode, ret); + return ret; +} + +PARAM_STATIC int RegisterSecurityDacOps(ParamSecurityOps *ops, int isInit) +{ + PARAM_CHECK(ops != NULL, return -1, "Invalid param"); + PARAM_LOGI("RegisterSecurityDacOps %d", isInit); + ops->securityGetLabel = NULL; + ops->securityDecodeLabel = NULL; + ops->securityEncodeLabel = NULL; + ops->securityInitLabel = InitLocalSecurityLabel; + ops->securityCheckFilePermission = CheckFilePermission; + ops->securityCheckParamPermission = CheckParamPermission; + ops->securityFreeLabel = FreeLocalSecurityLabel; + if (isInit) { + ops->securityGetLabel = GetParamSecurityLabel; + ops->securityDecodeLabel = DecodeSecurityLabel; + } else { + ops->securityEncodeLabel = EncodeSecurityLabel; + } + return 0; +} + +#ifdef PARAM_SUPPORT_DAC +int RegisterSecurityOps(ParamSecurityOps *ops, int isInit) +{ + return RegisterSecurityDacOps(ops, isInit); +} +#endif \ No newline at end of file diff --git a/services/param/adapter/param_libuvadp.c b/services/param/adapter/param_libuvadp.c new file mode 100755 index 0000000000000000000000000000000000000000..1ce83379c6aeb475564e7e64c9d601c035b56718 --- /dev/null +++ b/services/param/adapter/param_libuvadp.c @@ -0,0 +1,357 @@ +/* + * 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_libuvadp.h" +#include + +#define LABEL "Libuvadp" +static LibuvWorkSpace libuv = { NULL }; +static const uint32_t RECV_BUFFER_MAX = 5 * 1024; + +static LibuvBaseTask *CreateLibuvTask(uint32_t size, uint32_t flags, uint16_t userDataSize, TaskClose close) +{ + PARAM_CHECK(size <= RECV_BUFFER_MAX, return NULL, "Invaid size %u", size); + PARAM_CHECK(userDataSize <= RECV_BUFFER_MAX, return NULL, "Invaid user size %u", userDataSize); + LibuvBaseTask *worker = (LibuvBaseTask *)malloc(size + userDataSize); + PARAM_CHECK(worker != NULL, return NULL, "Failed to create param woker"); + worker->worker.flags = flags; + worker->userDataSize = userDataSize; + worker->userDataOffset = size; + worker->close = close; + return worker; +} + +static void OnClientClose(uv_handle_t *handle) +{ + PARAM_LOGD("OnClientClose handle: %p", handle); + PARAM_CHECK(handle != NULL, return, "Invalid handle"); + LibuvStreamTask *worker = PARAM_ENTRY(handle, LibuvStreamTask, stream); + if (worker->base.close != NULL) { + worker->base.close((ParamTaskPtr)worker); + } + free(worker); +} + +static void OnServerClose(uv_handle_t *handle) +{ + PARAM_LOGD("OnServerClose handle: %p", handle); + PARAM_CHECK(handle != NULL, return, "Invalid handle"); + LibuvServerTask *worker = PARAM_ENTRY(handle, LibuvServerTask, server); + if (worker->base.close != NULL) { + worker->base.close((ParamTaskPtr)worker); + } + free(worker); +} + +static void OnTimerClose(uv_handle_t *handle) +{ + PARAM_CHECK(handle != NULL, return, "Invalid handle"); + LibuvTimerTask *worker = PARAM_ENTRY(handle, LibuvTimerTask, timer); + if (worker->base.close != NULL) { + worker->base.close((ParamTaskPtr)worker); + } + free(worker); +} + +static void OnReceiveAlloc(uv_handle_t *handle, size_t suggestedSize, uv_buf_t *buf) +{ + UNUSED(suggestedSize); + PARAM_CHECK(handle != NULL, return, "Invalid handle"); + buf->len = RECV_BUFFER_MAX; + buf->base = (char *)malloc(buf->len); +} + +static void OnWriteResponse(uv_write_t *req, int status) +{ + UNUSED(status); + PARAM_CHECK(req != NULL, return, "Invalid req"); + PARAM_LOGD("OnWriteResponse handle: %p", req); +} + +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, OnClientClose); + if (buf != NULL) { + free(buf->base); + } + return; + } + LibuvStreamTask *client = PARAM_ENTRY(handle, LibuvStreamTask, stream); + if (client->recvMessage != NULL) { + client->recvMessage(&client->base.worker, (const ParamMessage *)buf->base); + } + free(buf->base); +} + +static void OnAsyncCloseCallback(uv_handle_t *handle) +{ + PARAM_CHECK(handle != NULL, return, "Invalid handle"); + free(handle); +} + +static void OnAsyncCallback(uv_async_t *handle) +{ + PARAM_CHECK(handle != NULL, return, "Invalid handle"); + LibuvAsyncEvent *event = (LibuvAsyncEvent *)handle; + if (event->task != NULL && event->task->process != NULL) { + event->task->process(event->eventId, event->content, event->contentSize); + } + uv_close((uv_handle_t *)handle, OnAsyncCloseCallback); +} + +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"); + LibuvServerTask *pipeServer = PARAM_ENTRY(server, LibuvServerTask, server); + PARAM_LOGD("OnConnection pipeServer: %p pip %p", pipeServer, server); + if (pipeServer->incomingConnect) { + pipeServer->incomingConnect((ParamTaskPtr)pipeServer, 0); + } +} + +static void LibuvFreeMsg(const ParamTaskPtr stream, const ParamMessage *msg) +{ + PARAM_CHECK(stream != NULL, return, "Invalid stream"); + PARAM_CHECK(msg != NULL, return, "Invalid msg"); + ParamMessage *message = (ParamMessage *)msg; + free(message); +} + +static int InitPipeSocket(uv_pipe_t *pipeServer) +{ + uv_fs_t req; + uv_fs_unlink(uv_default_loop(), &req, PIPE_NAME, NULL); + 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)); + PARAM_CHECK(chmod(PIPE_NAME, S_IRWXU | S_IRWXG | S_IRWXO) == 0, + return -1, "Open file %s error %s", PIPE_NAME, strerror(errno)); + return 0; +} + +static void LibuvTimerCallback(uv_timer_t *handle) +{ + PARAM_CHECK(handle != NULL, return, "Invalid handle"); + LibuvTimerTask *timer = PARAM_ENTRY(handle, LibuvTimerTask, timer); + timer->timerProcess(&timer->base.worker, timer->context); +} + +int ParamServerCreate(ParamTaskPtr *stream, const ParamStreamInfo *info) +{ + PARAM_CHECK(stream != NULL && info != NULL, return -1, "Invalid param"); + PARAM_CHECK(info->incomingConnect != NULL, return -1, "Invalid incomingConnect"); + + LibuvServerTask *worker = (LibuvServerTask *)CreateLibuvTask( + sizeof(LibuvServerTask), WORKER_TYPE_SERVER | info->flags, 0, info->close); + PARAM_CHECK(worker != NULL, return -1, "Failed to add param woker"); + InitPipeSocket(&worker->server.pipe); + PARAM_LOGD("OnConnection pipeServer: %p pipe %p", worker, &worker->server.pipe); + worker->incomingConnect = info->incomingConnect; + *stream = &worker->base.worker; + return 0; +} + +int ParamStreamCreate(ParamTaskPtr *stream, ParamTaskPtr server, const ParamStreamInfo *info, uint16_t userDataSize) +{ + PARAM_CHECK(stream != NULL && info != NULL, return -1, "Invalid stream"); + PARAM_CHECK(info->recvMessage != NULL, return -1, "Invalid recvMessage"); + PARAM_CHECK(info->close != NULL, return -1, "Invalid close"); + + LibuvServerTask *pipeServer = (LibuvServerTask *)server; + LibuvStreamTask *client = (LibuvStreamTask *)CreateLibuvTask(sizeof(LibuvStreamTask), + info->flags | WORKER_TYPE_MSG, userDataSize, info->close); + PARAM_CHECK(client != NULL, return -1, "Failed to add client"); + if (server != NULL) { + uv_pipe_t *pipe = &client->stream.pipe; + int ret = uv_pipe_init(uv_default_loop(), (uv_pipe_t *)pipe, 1); + PARAM_CHECK(ret == 0, free(client); + return -1, "Failed to uv_pipe_init %d", ret); + pipe->data = &pipeServer->server; + PARAM_LOGD("OnConnection pipeServer: %p pipe %p", pipeServer, &pipeServer->server); + if ((info->flags & WORKER_TYPE_TEST) != WORKER_TYPE_TEST) { + ret = uv_accept((uv_stream_t *)&pipeServer->server.pipe, (uv_stream_t *)pipe); + PARAM_CHECK(ret == 0, uv_close((uv_handle_t *)pipe, NULL); + free(client); + return -1, "Failed to uv_accept %d", ret); + ret = uv_read_start((uv_stream_t *)pipe, OnReceiveAlloc, OnReceiveRequest); + PARAM_CHECK(ret == 0, uv_close((uv_handle_t *)pipe, NULL); + free(client); + return -1, "Failed to uv_read_start %d", ret); + } + } + client->recvMessage = info->recvMessage; + *stream = &client->base.worker; + return 0; +} + +void *ParamGetTaskUserData(ParamTaskPtr stream) +{ + PARAM_CHECK(stream != NULL, return NULL, "Invalid stream"); + if ((stream->flags & WORKER_TYPE_CLIENT) != WORKER_TYPE_CLIENT) { + return NULL; + } + LibuvStreamTask *client = (LibuvStreamTask *)stream; + if (client->base.userDataSize == 0) { + return NULL; + } + return (void *)(((char *)stream) + client->base.userDataOffset); +} + +int ParamTaskSendMsg(const ParamTaskPtr stream, const ParamMessage *msg) +{ + PARAM_CHECK(stream != NULL && msg != NULL, LibuvFreeMsg(stream, msg); + return -1, "Invalid stream"); + LibuvStreamTask *worker = (LibuvStreamTask *)stream; + if ((stream->flags & WORKER_TYPE_MSG) != WORKER_TYPE_MSG) { + LibuvFreeMsg(stream, msg); + return -1; + } + if ((stream->flags & WORKER_TYPE_TEST) != WORKER_TYPE_TEST) { + uv_buf_t buf = uv_buf_init((char *)msg, msg->msgSize); + int ret = uv_write(&worker->writer, (uv_stream_t *)&worker->stream.pipe, &buf, 1, OnWriteResponse); + PARAM_CHECK(ret >= 0, LibuvFreeMsg(stream, msg); + return -1, "Failed to uv_write2 ret %s", uv_strerror(ret)); + } + LibuvFreeMsg(stream, msg); + return 0; +} + +int ParamEventTaskCreate(ParamTaskPtr *stream, EventProcess eventProcess, EventProcess eventBeforeProcess) +{ + PARAM_CHECK(stream != NULL && eventProcess != NULL, return -1, "Invalid info or stream"); + LibuvEventTask *worker = (LibuvEventTask *)CreateLibuvTask(sizeof(LibuvEventTask), + WORKER_TYPE_EVENT | WORKER_TYPE_ASYNC, 0, NULL); + PARAM_CHECK(worker != NULL, return -1, "Failed to alloc worker"); + worker->process = eventProcess; + worker->beforeProcess = eventBeforeProcess; + *stream = &worker->base.worker; + return 0; +} + +int ParamEventSend(ParamTaskPtr stream, uint64_t eventId, const char *content, uint32_t size) +{ + PARAM_CHECK(stream != NULL, return -1, "Invalid stream"); + PARAM_CHECK((stream->flags & WORKER_TYPE_EVENT) == WORKER_TYPE_EVENT, return -1, "Invalid stream type"); + int ret = PARAM_CODE_INVALID_PARAM; + if (stream->flags & WORKER_TYPE_ASYNC) { + LibuvEventTask *worker = (LibuvEventTask *)stream; + LibuvAsyncEvent *event = (LibuvAsyncEvent *)malloc(sizeof(LibuvAsyncEvent) + size + 1); + PARAM_CHECK(event != NULL, return -1, "Failed to alloc event"); + event->eventId = eventId; + event->contentSize = size + 1; + event->task = worker; + if (content != NULL) { + ret = memcpy_s(event->content, event->contentSize, content, size); + PARAM_CHECK(ret == EOK, free(event); + return -1, "Failed to memcpy content "); + event->content[size] = '\0'; + } + uv_async_init(uv_default_loop(), &event->async, OnAsyncCallback); + if (worker->beforeProcess != NULL) { + worker->beforeProcess(eventId, content, size); + } + uv_async_send(&event->async); + ret = 0; + } + return ret; +} + +int ParamTaskClose(ParamTaskPtr stream) +{ + PARAM_CHECK(stream != NULL, return -1, "Invalid param"); + if (stream->flags & WORKER_TYPE_TIMER) { + LibuvTimerTask *worker = (LibuvTimerTask *)stream; + uv_timer_stop(&worker->timer); + uv_close((uv_handle_t *)(&worker->timer), OnTimerClose); + } else if (stream->flags & WORKER_TYPE_SERVER) { + LibuvServerTask *worker = (LibuvServerTask *)stream; + uv_close((uv_handle_t *)(&worker->server.pipe), OnServerClose); + } else if (stream->flags & WORKER_TYPE_MSG) { + LibuvStreamTask *worker = (LibuvStreamTask *)stream; + uv_close((uv_handle_t *)(&worker->stream.pipe), OnClientClose); + } else if (stream->flags & WORKER_TYPE_EVENT) { + LibuvAsyncEvent *event = (LibuvAsyncEvent *)stream; + uv_close((uv_handle_t *)&event->async, OnAsyncCloseCallback); + } else { + free(stream); + } + return 0; +} + +int ParamTimerCreate(ParamTaskPtr *timer, TimerProcess process, void *context) +{ + PARAM_CHECK(timer != NULL && process != NULL, return -1, "Invalid timer"); + LibuvTimerTask *worker = (LibuvTimerTask *)CreateLibuvTask(sizeof(LibuvTimerTask), WORKER_TYPE_TIMER, 0, NULL); + PARAM_CHECK(worker != NULL, return -1, "Failed to alloc timer worker"); + worker->base.worker.flags = WORKER_TYPE_TIMER; + worker->timerProcess = process; + worker->context = context; + uv_timer_init(uv_default_loop(), &worker->timer); + *timer = &worker->base.worker; + return 0; +} + +int ParamTimerStart(ParamTaskPtr timer, uint64_t timeout, uint64_t repeat) +{ + PARAM_CHECK(timer != NULL, return -1, "Invalid timer"); + if (timer->flags & WORKER_TYPE_TIMER) { + LibuvTimerTask *worker = (LibuvTimerTask *)timer; + uv_timer_start(&worker->timer, LibuvTimerCallback, timeout, repeat); + return 0; + } + return -1; +} + +static void SignalHandler(uv_signal_t *handle, int signum) +{ + UNUSED(handle); + if (signum != SIGCHLD) { + return; + } + pid_t pid = 0; + int procStat = 0; + while (1) { + pid = waitpid(-1, &procStat, WNOHANG); + if (pid <= 0) { + break; + } + } + if (libuv.pidDeleteProcess != NULL) { + libuv.pidDeleteProcess(pid); + } +} + +int ParamServiceStart(ProcessPidDelete pidDelete) +{ + libuv.pidDeleteProcess = pidDelete; + uv_signal_t sigchldHandler; + int ret = uv_signal_init(uv_default_loop(), &sigchldHandler); + int ret1 = uv_signal_start(&sigchldHandler, SignalHandler, SIGCHLD); + PARAM_CHECK(ret == 0 && ret1 == 0, return -1, "Failed to process signal "); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + return 0; +} + +int ParamServiceStop(void) +{ + uv_fs_t req; + uv_fs_unlink(uv_default_loop(), &req, PIPE_NAME, NULL); + uv_stop(uv_default_loop()); + return 0; +} \ No newline at end of file diff --git a/services/param/adapter/param_libuvadp.h b/services/param/adapter/param_libuvadp.h new file mode 100755 index 0000000000000000000000000000000000000000..fb7ff0bcd718514068b4863ea9241915d6ba3d4b --- /dev/null +++ b/services/param/adapter/param_libuvadp.h @@ -0,0 +1,75 @@ +/* + * 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_LIBUVADP_H +#define BASE_STARTUP_PARAM_LIBUVADP_H +#include +#include +#include +#include + +#include "param_message.h" +#include "param_utils.h" +#include "uv.h" + +typedef struct { + ProcessPidDelete pidDeleteProcess; +} LibuvWorkSpace; + +typedef struct { + ParamTask worker; + TaskClose close; + uint16_t userDataSize; + uint16_t userDataOffset; +} LibuvBaseTask; + +typedef struct { + LibuvBaseTask base; + RecvMessage recvMessage; + union { + uv_pipe_t pipe; + } stream; + uv_write_t writer; +} LibuvStreamTask; + +typedef struct { + LibuvBaseTask base; + IncomingConnect incomingConnect; + union { + uv_pipe_t pipe; + } server; +} LibuvServerTask; + +typedef struct { + LibuvBaseTask base; + EventProcess process; + EventProcess beforeProcess; +} LibuvEventTask; + +typedef struct { + uv_async_t async; + LibuvEventTask *task; + uint64_t eventId; + uint32_t contentSize; + char content[0]; +} LibuvAsyncEvent; + +typedef struct { + LibuvBaseTask base; + uv_timer_t timer; + TimerProcess timerProcess; + void *context; +} LibuvTimerTask; + +#endif // BASE_STARTUP_PARAM_LIBUVADP_H \ No newline at end of file diff --git a/services/param/adapter/param_persistadp.c b/services/param/adapter/param_persistadp.c new file mode 100755 index 0000000000000000000000000000000000000000..63673e4c1a4e94bb7fd3f01311c8e551df2c31be --- /dev/null +++ b/services/param/adapter/param_persistadp.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include "param_persist.h" +#include "param_utils.h" + +#define LABEL "PERSIST_ADP" + +typedef struct { + void *context; + PersistParamGetPtr persistParamGet; +} PersistAdpContext; + +static int LoadPersistParam(PersistParamGetPtr persistParamGet, void *context) +{ + CheckAndCreateDir(PARAM_PERSIST_SAVE_PATH); + FILE *fp = fopen(PARAM_PERSIST_SAVE_TMP_PATH, "r"); + if (fp == NULL) { + fp = fopen(PARAM_PERSIST_SAVE_PATH, "r"); + PARAM_LOGI("LoadPersistParam open file %s", PARAM_PERSIST_SAVE_PATH); + } + PARAM_CHECK(fp != NULL, return -1, "No valid persist parameter file %s", PARAM_PERSIST_SAVE_PATH); + + char *buff = (char *)malloc(PARAM_BUFFER_SIZE); + SubStringInfo *info = malloc(sizeof(SubStringInfo) * (SUBSTR_INFO_VALUE + 1)); + while (info != NULL && buff != NULL && fgets(buff, PARAM_BUFFER_SIZE, fp) != NULL) { + int subStrNumber = GetSubStringInfo(buff, strlen(buff), '=', info, SUBSTR_INFO_VALUE + 1); + if (subStrNumber <= SUBSTR_INFO_VALUE) { + continue; + } + int ret = persistParamGet(info[0].value, info[1].value, context); + PARAM_CHECK(ret == 0, continue, "Failed to set param %d %s", ret, buff); + } + free(info); + free(buff); + (void)fclose(fp); + return 0; +} + +static int BatchSavePersistParamBegin(PERSIST_SAVE_HANDLE *handle) +{ + FILE *fp = fopen(PARAM_PERSIST_SAVE_TMP_PATH, "w"); + PARAM_CHECK(fp != NULL, return -1, "Open file %s fail error %s", PARAM_PERSIST_SAVE_TMP_PATH, strerror(errno)); + *handle = (PERSIST_SAVE_HANDLE)fp; + return 0; +} + +static int BatchSavePersistParam(PERSIST_SAVE_HANDLE handle, const char *name, const char *value) +{ + FILE *fp = (FILE *)handle; + int ret = fprintf(fp, "%s=%s\n", name, value); + PARAM_CHECK(ret > 0, return -1, "Failed to write param"); + PARAM_LOGD("BatchSavePersistParam %s=%s", name, value); + return 0; +} + +static void BatchSavePersistParamEnd(PERSIST_SAVE_HANDLE handle) +{ + FILE *fp = (FILE *)handle; + (void)fclose(fp); + unlink(PARAM_PERSIST_SAVE_PATH); + int ret = rename(PARAM_PERSIST_SAVE_TMP_PATH, PARAM_PERSIST_SAVE_PATH); + PARAM_CHECK(ret == 0, return, "BatchSavePersistParamEnd %s fail error %s", + PARAM_PERSIST_SAVE_TMP_PATH, strerror(errno)); +} + +int RegisterPersistParamOps(PersistParamOps *ops) +{ + ops->save = NULL; + ops->load = LoadPersistParam; + ops->batchSaveBegin = BatchSavePersistParamBegin; + ops->batchSave = BatchSavePersistParam; + ops->batchSaveEnd = BatchSavePersistParamEnd; + return 0; +} \ No newline at end of file diff --git a/services/param/adapter/param_selinux.c b/services/param/adapter/param_selinux.c new file mode 100755 index 0000000000000000000000000000000000000000..139bfabc0d74d06d3e7e2a146bd4ef8c4bad4b58 --- /dev/null +++ b/services/param/adapter/param_selinux.c @@ -0,0 +1,152 @@ +/* + * 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 "param_security.h" +#include "param_utils.h" + +#define LABEL "PARAM_SELINUX" +#define SELINUX_LABEL_LEN 128 + +typedef struct SELinuxSecurityLabel { + ParamSecurityLabel securityLabel; + char label[SELINUX_LABEL_LEN]; +} SELinuxSecurityLabel; + +static SELinuxSecurityLabel g_localSecurityLabel = {}; + +static int InitLocalSecurityLabel(ParamSecurityLabel **security, int isInit) +{ + UNUSED(isInit); + PARAM_LOGI("TestDacGetLabel uid:%d gid:%d euid: %d egid: %d ", getuid(), getgid(), geteuid(), getegid()); + g_localSecurityLabel.securityLabel.cred.pid = getpid(); + g_localSecurityLabel.securityLabel.cred.uid = geteuid(); + g_localSecurityLabel.securityLabel.cred.gid = getegid(); + *security = &g_localSecurityLabel.securityLabel; + return 0; +} + +static int FreeLocalSecurityLabel(ParamSecurityLabel *srcLabel) +{ + return 0; +} + +static int EncodeSecurityLabel(const ParamSecurityLabel *srcLabel, char *buffer, uint32_t *bufferSize) +{ + PARAM_CHECK(bufferSize != NULL, return -1, "Invalid param"); + if (buffer == NULL) { + *bufferSize = sizeof(SELinuxSecurityLabel); + return 0; + } + PARAM_CHECK(*bufferSize >= sizeof(SELinuxSecurityLabel), return -1, "Invalid buffersize %u", *bufferSize); + *bufferSize = sizeof(SELinuxSecurityLabel); + return memcpy_s(buffer, *bufferSize, srcLabel, sizeof(SELinuxSecurityLabel)); +} + +static int DecodeSecurityLabel(ParamSecurityLabel **srcLabel, char *buffer, uint32_t bufferSize) +{ + PARAM_CHECK(bufferSize >= sizeof(SELinuxSecurityLabel), return -1, "Invalid buffersize %u", bufferSize); + PARAM_CHECK(srcLabel != NULL && buffer != NULL, return -1, "Invalid param"); + *srcLabel = &((SELinuxSecurityLabel *)buffer)->securityLabel; + return 0; +} + +static int LoadParamLabels(const char *fileName, SecurityLabelFunc label, void *context) +{ + int ret = 0; + FILE *fp = fopen(fileName, "r"); + PARAM_CHECK(fp != NULL, return -1, "Open file %s fail", fileName); + SubStringInfo *info = malloc(sizeof(SubStringInfo) * (SUBSTR_INFO_DAC + 1)); + PARAM_CHECK(info != NULL, (void)fclose(fp); + return -1, "Failed to malloc for %s", fileName); + char buff[PARAM_BUFFER_SIZE]; + int infoCount = 0; + ParamAuditData auditData = {}; + while (fgets(buff, PARAM_BUFFER_SIZE, fp) != NULL) { + int subStrNumber = GetSubStringInfo(buff, strlen(buff), ' ', info, SUBSTR_INFO_DAC + 1); + if (subStrNumber <= SUBSTR_INFO_DAC) { + continue; + } + auditData.name = info[SUBSTR_INFO_NAME].value; + auditData.label = info[SUBSTR_INFO_LABEL].value; + ret = label(&auditData, context); + PARAM_CHECK(ret == 0, continue, "Failed to write param info %d %s", ret, buff); + infoCount++; + } + (void)fclose(fp); + free(info); + PARAM_LOGI("Load parameter info %d success %s", infoCount, fileName); + return 0; +} + +static int ProcessParamFile(const char *fileName, void *context) +{ + LabelFuncContext *cxt = (LabelFuncContext *)context; + return LoadParamLabels(fileName, cxt->label, cxt->context); +} + +static int GetParamSecurityLabel(SecurityLabelFunc label, const char *path, void *context) +{ + PARAM_CHECK(label != NULL, return -1, "Invalid param"); + int ret = 0; + struct stat st; + LabelFuncContext cxt = { label, context }; + if ((stat(path, &st) == 0) && !S_ISDIR(st.st_mode)) { + ret = ProcessParamFile(path, &cxt); + } else { + ret = ReadFileInDir(path, ".para.selinux", ProcessParamFile, &cxt); + } + return ret; +} + +static int CheckFilePermission(const ParamSecurityLabel *localLabel, const char *fileName, int flags) +{ + UNUSED(flags); + PARAM_CHECK(localLabel != NULL && fileName != NULL, return -1, "Invalid param"); + return 0; +} + +static int CheckParamPermission(const ParamSecurityLabel *srcLabel, const ParamAuditData *auditData, int mode) +{ + PARAM_LOGI("CheckParamPermission "); + PARAM_CHECK(srcLabel != NULL && auditData != NULL && auditData->name != NULL, return -1, "Invalid param"); + return 0; +} + +PARAM_STATIC int RegisterSecuritySelinuxOps(ParamSecurityOps *ops, int isInit) +{ + PARAM_CHECK(ops != NULL, return -1, "Invalid param"); + ops->securityGetLabel = NULL; + ops->securityDecodeLabel = NULL; + ops->securityEncodeLabel = NULL; + ops->securityInitLabel = InitLocalSecurityLabel; + ops->securityCheckFilePermission = CheckFilePermission; + ops->securityCheckParamPermission = CheckParamPermission; + ops->securityFreeLabel = FreeLocalSecurityLabel; + if (isInit) { + ops->securityGetLabel = GetParamSecurityLabel; + ops->securityDecodeLabel = DecodeSecurityLabel; + } else { + ops->securityEncodeLabel = EncodeSecurityLabel; + } + return 0; +} +#ifdef PARAM_SUPPORT_SELINUX +int RegisterSecurityOps(ParamSecurityOps *ops, int isInit) +{ + return RegisterSecuritySelinuxOps(ops, isInit); +} +#endif \ No newline at end of file diff --git a/services/param/client/param_request.c b/services/param/client/param_request.c index ebed012fc40fa1c7e18b1a2239505afeec026d4c..b8d83f39ec7e33a444afb0a38fda02a1aa154c32 100644 --- a/services/param/client/param_request.c +++ b/services/param/client/param_request.c @@ -14,149 +14,298 @@ */ #include "param_request.h" - +#include +#include +#include +#include #include +#include #include -#include #include "param_manager.h" -#include "uv.h" +#include "param_message.h" +#define INVALID_SOCKET (-1) #define LABEL "Client" -#define BUFFER_SIZE 200 -#define ParamEntry(ptr, type, member) (type *)((char *)(ptr) - offsetof(type, member)) +static const uint32_t RECV_BUFFER_MAX = 5 * 1024; + +static atomic_uint g_requestId = ATOMIC_VAR_INIT(1); +static ClientWorkSpace g_clientSpace = { {}, -1, {} }; -static ParamWorkSpace g_paramWorkSpaceReadOnly = {ATOMIC_VAR_INIT(0), {}, {}, {}}; +__attribute__((constructor)) static void ClientInit(void); +__attribute__((destructor)) static void ClientDeinit(void); -static void OnWrite(uv_write_t *req, int status) +static int InitParamClient(void) { - PARAM_LOGD("OnWrite status %d", status); + if (PARAM_TEST_FLAG(g_clientSpace.paramSpace.flags, WORKSPACE_FLAGS_INIT)) { + return 0; + } + PARAM_LOGI("InitParamClient"); + pthread_mutex_init(&g_clientSpace.mutex, NULL); + g_clientSpace.clientFd = INVALID_SOCKET; + return InitParamWorkSpace(&g_clientSpace.paramSpace, 1); } -static void OnReceiveAlloc(uv_handle_t* handle, size_t suggestedSize, uv_buf_t* buf) +void ClientInit(void) { - // 这里需要按实际回复大小申请内存,不需要大内存 - buf->base = (char *)malloc(sizeof(ResponseMsg)); - PARAM_CHECK(buf->base != NULL, return, "OnReceiveAlloc malloc failed"); - buf->len = sizeof(ResponseMsg); - PARAM_LOGD("OnReceiveAlloc handle %p %zu", handle, suggestedSize); + PARAM_LOGI("ClientInit"); + (void)InitParamClient(); } -static void OnReceiveResponse(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) +void ClientDeinit(void) { - RequestNode *req = ParamEntry(handle, RequestNode, handle); - PARAM_LOGD("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; + CloseParamWorkSpace(&g_clientSpace.paramSpace); +} + +static ParamSecurityOps *GetClientParamSecurityOps(void) +{ + return &g_clientSpace.paramSpace.paramSecurityOps; +} + +static int FillLabelContent(ParamMessage *request, uint32_t *start, uint32_t length) +{ + uint32_t bufferSize = request->msgSize - sizeof(ParamMessage); + uint32_t offset = *start; + PARAM_CHECK((offset + sizeof(ParamMsgContent) + length) <= bufferSize, + return -1, "Invalid msgSize %u offset %u", request->msgSize, offset); + ParamMsgContent *content = (ParamMsgContent *)(request->data + offset); + content->type = PARAM_LABEL; + content->contentSize = 0; + ParamSecurityOps *ops = GetClientParamSecurityOps(); + if (length != 0 && ops != NULL && ops->securityEncodeLabel != NULL) { + int ret = ops->securityEncodeLabel(g_clientSpace.paramSpace.securityLabel, content->content, &length); + PARAM_CHECK(ret == 0, return -1, "Failed to get label length"); + content->contentSize = length; } - ResponseMsg *response = (ResponseMsg *)(buf->base); - PARAM_CHECK(response != NULL, return, "The response is null"); - PARAM_LOGD("OnReceiveResponse %p cmd %d result: %d", handle, response->type, response->result); - switch (response->type) { - case SET_PARAM: - req->result = response->result; + offset += sizeof(ParamMsgContent) + PARAM_ALIGN(content->contentSize); + *start = offset; + return 0; +} + +static int ProcessRecvMsg(const ParamMessage *recvMsg) +{ + PARAM_LOGD("ProcessRecvMsg type: %u msgId: %u name %s", recvMsg->type, recvMsg->id.msgId, recvMsg->key); + int result = PARAM_CODE_INVALID_PARAM; + switch (recvMsg->type) { + case MSG_SET_PARAM: + result = ((ParamResponseMessage *)recvMsg)->result; + break; + case MSG_NOTIFY_PARAM: + result = 0; break; default: - PARAM_LOGE("not supported the command: %d", response->type); break; } - PARAM_LOGD("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_LOGD("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(); - PARAM_CHECK(request->loop != NULL, return -1, "StartRequest uv_loop_new failed"); - 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; } +static int StartRequest(int *fd, ParamMessage *request, int timeout) +{ + int ret = 0; + struct timeval time; + time.tv_sec = timeout; + time.tv_usec = 0; + do { + int clientFd = *fd; + if (clientFd == INVALID_SOCKET) { + clientFd = socket(AF_UNIX, SOCK_STREAM, 0); + PARAM_CHECK(clientFd >= 0, return PARAM_CODE_FAIL_CONNECT, "Failed to create socket"); + ret = ConntectServer(clientFd, PIPE_NAME); + PARAM_CHECK(ret == 0, close(clientFd); + return PARAM_CODE_FAIL_CONNECT, "Failed to connect server"); + setsockopt(clientFd, SOL_SOCKET, SO_SNDTIMEO, (char *)&time, sizeof(struct timeval)); + setsockopt(clientFd, SOL_SOCKET, SO_RCVTIMEO, (char *)&time, sizeof(struct timeval)); + *fd = clientFd; + } + ssize_t recvLen = 0; + ssize_t sendLen = send(clientFd, (char *)request, request->msgSize, 0); + if (sendLen > 0) { + recvLen = recv(clientFd, (char *)request, RECV_BUFFER_MAX, 0); + if (recvLen > 0) { + break; + } + } + ret = errno; + close(clientFd); + *fd = INVALID_SOCKET; + if (errno == EAGAIN || recvLen == 0) { + ret = PARAM_CODE_TIMEOUT; + break; + } + PARAM_LOGE("Send or recv msg fail errno %d %zd %zd", errno, sendLen, recvLen); + } while (1); + + if (ret == 0) { // check result + ret = ProcessRecvMsg(request); + } + return ret; +} + int SystemSetParameter(const char *name, const char *value) { - PARAM_CHECK(name != NULL && value != NULL, return -1, "Invalid param"); + InitParamClient(); + PARAM_CHECK(name != NULL && value != NULL, return -1, "Invalid name or value"); int ret = CheckParamName(name, 0); - PARAM_CHECK(ret == 0, return ret, "Illegal param name"); + PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", name); + uint32_t msgSize = sizeof(ParamMessage) + sizeof(ParamMsgContent) + PARAM_ALIGN(strlen(value) + 1); + uint32_t labelLen = 0; + ParamSecurityOps *ops = GetClientParamSecurityOps(); + if (LABEL_IS_CLIENT_CHECK_PERMITTED(g_clientSpace.paramSpace.securityLabel)) { + ret = CheckParamPermission(&g_clientSpace.paramSpace, g_clientSpace.paramSpace.securityLabel, name, DAC_WRITE); + PARAM_CHECK(ret == 0, return ret, "Forbit to set parameter %s", name); + } else if (!LABEL_IS_ALL_PERMITTED(g_clientSpace.paramSpace.securityLabel)) { // check local can check permissions + PARAM_CHECK(ops != NULL && ops->securityEncodeLabel != NULL, return -1, "Invalid securityEncodeLabel"); + ret = ops->securityEncodeLabel(g_clientSpace.paramSpace.securityLabel, NULL, &labelLen); + PARAM_CHECK(ret == 0, return -1, "Failed to get label length"); + } + msgSize += sizeof(ParamMsgContent) + labelLen; + msgSize = msgSize < RECV_BUFFER_MAX ? RECV_BUFFER_MAX : msgSize; - PARAM_LOGD("StartRequest %s", name); - u_int32_t msgSize = sizeof(RequestMsg) + strlen(name) + strlen(value) + 2; - RequestNode *request = (RequestNode *)malloc(sizeof(RequestNode) + msgSize); + ParamMessage *request = (ParamMessage *)CreateParamMessage(MSG_SET_PARAM, name, msgSize); PARAM_CHECK(request != NULL, return -1, "Failed to malloc for connect"); + uint32_t offset = 0; + ret = FillParamMsgContent(request, &offset, PARAM_VALUE, value, strlen(value)); + PARAM_CHECK(ret == 0, free(request); + return -1, "Failed to fill value"); + ret = FillLabelContent(request, &offset, labelLen); + PARAM_CHECK(ret == 0, free(request); + return -1, "Failed to fill label"); + request->msgSize = offset + sizeof(ParamMessage); + request->id.msgId = atomic_fetch_add(&g_requestId, 1); - 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); + pthread_mutex_lock(&g_clientSpace.mutex); + ret = StartRequest(&g_clientSpace.clientFd, request, DEFAULT_PARAM_SET_TIMEOUT); + pthread_mutex_unlock(&g_clientSpace.mutex); + free(request); + return ret; +} + +int SystemWaitParameter(const char *name, const char *value, int32_t timeout) +{ + InitParamClient(); + PARAM_CHECK(name != NULL, return -1, "Invalid name"); + int ret = CheckParamName(name, 0); + PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", name); + ParamHandle handle = 0; + ret = ReadParamWithCheck(&g_clientSpace.paramSpace, name, DAC_READ, &handle); + if (ret != PARAM_CODE_NOT_FOUND && ret != 0) { + PARAM_CHECK(ret == 0, return ret, "Forbid to wait parameter %s", name); + } + if (timeout == 0) { + timeout = DEFAULT_PARAM_WAIT_TIMEOUT; + } + uint32_t msgSize = sizeof(ParamMessage) + sizeof(ParamMsgContent) + sizeof(ParamMsgContent) + sizeof(uint32_t); + msgSize = msgSize < RECV_BUFFER_MAX ? RECV_BUFFER_MAX : msgSize; + uint32_t offset = 0; + ParamMessage *request = NULL; + if (value != NULL) { + msgSize += PARAM_ALIGN(strlen(value) + 1); + request = (ParamMessage *)CreateParamMessage(MSG_WAIT_PARAM, name, msgSize); + PARAM_CHECK(request != NULL, return -1, "Failed to malloc for wait"); + ret = FillParamMsgContent(request, &offset, PARAM_VALUE, value, strlen(value)); + } else { + msgSize += PARAM_ALIGN(1); + request = (ParamMessage *)CreateParamMessage(MSG_WAIT_PARAM, name, msgSize); + PARAM_CHECK(request != NULL, return -1, "Failed to malloc for wait"); + ret = FillParamMsgContent(request, &offset, PARAM_VALUE, "*", 1); + } + PARAM_CHECK(ret == 0, free(request); + return -1, "Failed to fill value"); + ParamMsgContent *content = (ParamMsgContent *)(request->data + offset); + content->type = PARAM_WAIT_TIMEOUT; + content->contentSize = sizeof(uint32_t); + *((uint32_t *)(content->content)) = timeout; + offset += sizeof(ParamMsgContent) + sizeof(uint32_t); + + request->msgSize = offset + sizeof(ParamMessage); + request->id.waitId = atomic_fetch_add(&g_requestId, 1); + int fd = INVALID_SOCKET; + ret = StartRequest(&fd, request, timeout); + if (fd != INVALID_SOCKET) { + close(fd); + } + free(request); + PARAM_LOGI("SystemWaitParameter %s value %s result %d ", name, value, ret); + return ret; } int SystemGetParameter(const char *name, char *value, unsigned int *len) { + InitParamClient(); 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 ret = ReadParamWithCheck(&g_clientSpace.paramSpace, name, DAC_READ, &handle); + if (ret != PARAM_CODE_NOT_FOUND && ret != 0) { + PARAM_CHECK(ret == 0, return ret, "Forbid to get parameter %s", name); + } + return ReadParamValue(&g_clientSpace.paramSpace, handle, value, len); +} + +int SystemFindParameter(const char *name, ParamHandle *handle) +{ + InitParamClient(); + PARAM_CHECK(name != NULL && handle != NULL, return -1, "The name or handle is null"); + int ret = ReadParamWithCheck(&g_clientSpace.paramSpace, name, DAC_READ, handle); + if (ret != PARAM_CODE_NOT_FOUND && ret != 0) { + PARAM_CHECK(ret == 0, return ret, "Forbid to access parameter %s", name); + } + return 0; +} + +int SystemGetParameterCommitId(ParamHandle handle, uint32_t *commitId) +{ + PARAM_CHECK(handle != 0 || commitId != NULL, return -1, "The handle is null"); + return ReadParamCommitId(&g_clientSpace.paramSpace, handle, commitId); } 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); + return ReadParamName(&g_clientSpace.paramSpace, 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); + return ReadParamValue(&g_clientSpace.paramSpace, handle, value, len); } -int SystemTraversalParameter(void (*traversalParameter)(ParamHandle handle, void* cookie), void* cookie) +int SystemTraversalParameter(void (*traversalParameter)(ParamHandle handle, void *cookie), void *cookie) { + InitParamClient(); PARAM_CHECK(traversalParameter != NULL, return -1, "The param is null"); - InitParamWorkSpace(&g_paramWorkSpaceReadOnly, 1, NULL); - return TraversalParam(&g_paramWorkSpaceReadOnly, traversalParameter, cookie); + ParamHandle handle = 0; + // check default dac + int ret = ReadParamWithCheck(&g_clientSpace.paramSpace, "#", DAC_READ, &handle); + if (ret != PARAM_CODE_NOT_FOUND && ret != 0) { + PARAM_CHECK(ret == 0, return ret, "Forbid to traversal parameters"); + } + return TraversalParam(&g_clientSpace.paramSpace, traversalParameter, cookie); +} + +void SystemDumpParameters(int verbose) +{ + InitParamClient(); + DumpParameters(&g_clientSpace.paramSpace, verbose); +} + +int WatchParamCheck(const char *keyprefix) +{ + InitParamClient(); + PARAM_CHECK(keyprefix != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid keyprefix"); + int ret = CheckParamName(keyprefix, 0); + PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", keyprefix); + ParamHandle handle = 0; + ret = ReadParamWithCheck(&g_clientSpace.paramSpace, keyprefix, DAC_WATCH, &handle); + if (ret != PARAM_CODE_NOT_FOUND && ret != 0) { + PARAM_CHECK(ret == 0, return ret, "Forbid to watch parameter %s", keyprefix); + } + return 0; } -const char *SystemDetectParamChange(ParamCache *cache, - ParamEvaluatePtr evaluate, u_int32_t count, const char *parameters[][2]) +#ifdef STARTUP_INIT_TEST +ParamWorkSpace *GetClientParamWorkSpace(void) { - PARAM_CHECK(cache != NULL && evaluate != NULL && parameters != NULL, return NULL, "The param is null"); - return DetectParamChange(&g_paramWorkSpaceReadOnly, cache, evaluate, count, parameters); + return &g_clientSpace.paramSpace; } +#endif \ No newline at end of file diff --git a/services/param/cmd/param_cmd.c b/services/param/cmd/param_cmd.c new file mode 100755 index 0000000000000000000000000000000000000000..812c8814eef509c28a613e179efdca9cd6d90387 --- /dev/null +++ b/services/param/cmd/param_cmd.c @@ -0,0 +1,177 @@ +/* + * 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 "param_manager.h" +#include "param_utils.h" +#include "sys_param.h" + +#define USAGE_INFO_PARAM_GET "param get [key]" +#define USAGE_INFO_PARAM_SET "param set key value" +#define USAGE_INFO_PARAM_WAIT "param wait key value" +#define USAGE_INFO_PARAM_DUMP "param dump [verbose]" +#define USAGE_INFO_PARAM_READ "param read key" +#define USAGE_INFO_PARAM_WATCH "param watch key" +#define READ_DURATION 100000 +#define MIN_ARGC 2 +#define WAIT_TIMEOUT_INDEX 2 + +struct CmdArgs { + char name[8]; + int minArg; + void (*DoFuncion)(int argc, char *argv[], int start); + char help[128]; +}; + +static void ShowParam(ParamHandle handle, void *cookie) +{ + char *name = (char *)cookie; + char *value = ((char *)cookie) + PARAM_NAME_LEN_MAX; + SystemGetParameterName(handle, name, PARAM_NAME_LEN_MAX); + uint32_t size = PARAM_CONST_VALUE_LEN_MAX; + SystemGetParameterValue(handle, value, &size); + printf("\t%s = %s \n", name, value); +} + +static void ExeuteCmdParamGet(int argc, char *argv[], int start) +{ + uint32_t size = PARAM_CONST_VALUE_LEN_MAX + PARAM_NAME_LEN_MAX + 1 + 1; + char *buffer = (char *)malloc(size); + if (buffer == NULL) { + printf("Get parameterfail\n"); + return; + } + memset_s(buffer, size, 0, size); + if (argc == start) { + SystemTraversalParameter(ShowParam, (void *)buffer); + } else { + int ret = SystemGetParameter(argv[start], buffer, &size); + if (ret == 0) { + printf("%s \n", buffer); + } else { + printf("Get parameter \"%s\" fail\n", argv[start]); + } + } + free(buffer); +} + +static void ExeuteCmdParamSet(int argc, char *argv[], int start) +{ + UNUSED(argc); + int ret = SystemSetParameter(argv[start], argv[start + 1]); + if (ret == 0) { + printf("Set parameter %s %s success\n", argv[start], argv[start + 1]); + } else { + printf("Set parameter %s %s fail\n", argv[start], argv[start + 1]); + } + return; +} + +static void ExeuteCmdParamDump(int argc, char *argv[], int start) +{ + int verbose = 0; + if (argc > start && strcmp(argv[start], "verbose") == 0) { + verbose = 1; + } + SystemDumpParameters(verbose); +} + +static void ExeuteCmdParamWait(int argc, char *argv[], int start) +{ + char *value = NULL; + uint32_t timeout = DEFAULT_PARAM_WAIT_TIMEOUT; + if (argc > (start + 1)) { + value = argv[start + 1]; + } + if (argc > (start + WAIT_TIMEOUT_INDEX)) { + timeout = atol(argv[start + WAIT_TIMEOUT_INDEX]); + } + SystemWaitParameter(argv[start], value, timeout); +} + +#ifdef PARAM_TEST +static void ExeuteCmdParamRead(int argc, char *argv[], int start) +{ + srand((unsigned)time(NULL)); // srand()函数产生一个以当前时间开始的随机种子 + while (1) { + ExeuteCmdParamGet(argc, argv, start); + int wait = rand() / READ_DURATION + READ_DURATION; // 100ms + usleep(wait); + } +} + +static void HandleParamChange(const char *key, const char *value, void *context) +{ + printf("Receive parameter change %s %s \n", key, value); +} + +static void ExeuteCmdParamWatch(int argc, char *argv[], int start) +{ + int ret = SystemWatchParameter(argv[start], HandleParamChange, NULL); + if (ret != 0) { + return; + } + while (1) { + (void)pause(); + } +} +#endif + +int RunParamCommand(int argc, char *argv[]) +{ + static struct CmdArgs paramCmds[] = { + { "set", 4, ExeuteCmdParamSet, USAGE_INFO_PARAM_SET }, + { "get", 2, ExeuteCmdParamGet, USAGE_INFO_PARAM_GET }, + { "wait", 3, ExeuteCmdParamWait, USAGE_INFO_PARAM_WAIT }, + { "dump", 2, ExeuteCmdParamDump, USAGE_INFO_PARAM_DUMP }, +#ifdef PARAM_TEST + { "read", 2, ExeuteCmdParamRead, USAGE_INFO_PARAM_READ }, + { "watch", 2, ExeuteCmdParamWatch, USAGE_INFO_PARAM_WATCH }, +#endif + }; + if (argc < MIN_ARGC) { + printf("usage: \n"); + for (size_t i = 0; i < sizeof(paramCmds) / sizeof(paramCmds[0]); i++) { + printf("\t %s\n", paramCmds[i].help); + } + return 0; + } + + for (size_t i = 0; i < sizeof(paramCmds) / sizeof(paramCmds[0]); i++) { + if (strncmp(argv[1], paramCmds[i].name, strlen(paramCmds[i].name)) == 0) { + if (argc < paramCmds[i].minArg) { + printf("usage: %s\n", paramCmds[i].help); + return 0; + } + paramCmds[i].DoFuncion(argc, argv, MIN_ARGC); + return 0; + } + } + printf("usage: \n"); + for (size_t i = 0; i < sizeof(paramCmds) / sizeof(paramCmds[0]); i++) { + printf("\t%s\n", paramCmds[i].help); + } + return 0; +} + +#ifndef STARTUP_INIT_TEST +int main(int argc, char *argv[]) +{ + return RunParamCommand(argc, argv); +} +#endif \ No newline at end of file diff --git a/services/param/cmd/param_get.c b/services/param/cmd/param_get.c deleted file mode 100644 index 1435dab09c2f2f1b263f9d30fd99537e0577323f..0000000000000000000000000000000000000000 --- a/services/param/cmd/param_get.c +++ /dev/null @@ -1,59 +0,0 @@ -/* -* 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) -{ - if (cookie == NULL) { - printf("ProcessParam cookie is NULL\n"); - return; - } - 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("%s \n", 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 deleted file mode 100644 index 3c3943df95ad2df4048cecf61777cacc77536050..0000000000000000000000000000000000000000 --- a/services/param/cmd/param_set.c +++ /dev/null @@ -1,39 +0,0 @@ -/* -* 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 index dc969651fa10cb078bbd1e773c5b287b16d695df..2c108146991473fbc29bb7bbf4ea72d4213183cd 100644 --- a/services/param/include/param_manager.h +++ b/services/param/include/param_manager.h @@ -18,140 +18,60 @@ #include #include -#include "init_log.h" -#include "sys_param.h" +#include "param_message.h" +#include "param_persist.h" +#include "param_security.h" #include "param_trie.h" -#include "securec.h" +#include "param_utils.h" +#include "sys_param.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_LOGD(fmt, ...) STARTUP_LOGD(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; +#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 { - 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; + uint32_t flags; WorkSpace paramSpace; - ParamSecurityLabel label; + ParamSecurityLabel *securityLabel; + ParamSecurityOps paramSecurityOps; + ParamTaskPtr serverTask; + ParamTaskPtr timer; } ParamWorkSpace; typedef struct { - atomic_uint_least32_t flags; - WorkSpace persistWorkSpace; + uint32_t flags; + ParamTaskPtr saveTimer; + time_t lastSaveTimer; + PersistParamOps persistParamOps; } ParamPersistWorkSpace; -typedef struct { - char value[128]; -} SubStringInfo; - -int InitParamWorkSpace(ParamWorkSpace *workSpace, int onlyRead, const char *context); +int InitParamWorkSpace(ParamWorkSpace *workSpace, int onlyRead); 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 ReadParamWithCheck(ParamWorkSpace *workSpace, const char *name, int op, ParamHandle *handle); +int ReadParamValue(ParamWorkSpace *workSpace, ParamHandle handle, char *value, uint32_t *len); +int ReadParamName(ParamWorkSpace *workSpace, ParamHandle handle, char *name, uint32_t len); +int ReadParamCommitId(ParamWorkSpace *workSpace, ParamHandle handle, uint32_t *commitId); -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 CheckParamPermission(ParamWorkSpace *workSpace, const ParamSecurityLabel *srcLabel, const char *name, int mode); -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 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]); - +ParamWorkSpace *GetParamWorkSpace(void); +ParamWorkSpace *GetClientParamWorkSpace(void); +void DumpParameters(ParamWorkSpace *workSpace, int verbose); #ifdef __cplusplus #if __cplusplus } diff --git a/services/param/include/param_message.h b/services/param/include/param_message.h new file mode 100755 index 0000000000000000000000000000000000000000..f93a52505c5879f72034c43975c4b12b78070f4d --- /dev/null +++ b/services/param/include/param_message.h @@ -0,0 +1,137 @@ +/* + * 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_PARAM_MESSAGE_H +#define BASE_STARTUP_PARAM_MESSAGE_H +#include +#include +#include +#include + +#include "param.h" +#include "param_utils.h" +#include "securec.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +#ifndef PARAM_SUPPORT_LIBUV +#ifndef PARAM_SUPPORT_EVENT +#define PARAM_SUPPORT_LIBUV 1 +#endif +#endif + +#define WORKER_TYPE_MSG 0x01 +#define WORKER_TYPE_EVENT 0x02 +#define WORKER_TYPE_TIMER 0x08 + +#define WORKER_TYPE_ASYNC 0x10 +#define WORKER_TYPE_SERVER 0x20 +#define WORKER_TYPE_CLIENT 0x40 + +#define WORKER_TYPE_TEST 0x01000000 + +typedef enum { + MSG_SET_PARAM, + MSG_WAIT_PARAM, + MSG_ADD_WATCHER, + MSG_DEL_WATCHER, + MSG_NOTIFY_PARAM +} ParamMsgType; + +typedef enum ContentType { + PARAM_NAME, + PARAM_VALUE, + PARAM_LABEL, + PARAM_WAIT_TIMEOUT, + PARAM_NAME_VALUE, +} ContentType; + +typedef struct { + uint8_t type; + uint8_t rev; + uint16_t contentSize; + char content[0]; +} ParamMsgContent; + +typedef struct { + uint32_t type; + uint32_t msgSize; + union { + uint32_t msgId; + uint32_t watcherId; + uint32_t waitId; + } id; + char key[PARAM_NAME_LEN_MAX]; + char data[0]; +} ParamMessage; + +typedef struct { + ParamMessage msg; + uint32_t result; +} ParamResponseMessage; + +struct ParamTask_; +typedef struct ParamTask_ *ParamTaskPtr; +typedef int (*IncomingConnect)(const ParamTaskPtr stream, int flags); +typedef int (*RecvMessage)(const ParamTaskPtr stream, const ParamMessage *msg); +typedef void (*TimerProcess)(const ParamTaskPtr stream, void *context); +typedef void (*EventProcess)(uint64_t eventId, const char *context, uint32_t size); +typedef void (*TaskClose)(const ParamTaskPtr stream); +typedef void (*ProcessPidDelete)(pid_t pid); + +typedef struct ParamTask_ { + int32_t flags; +} ParamTask; + +typedef struct { + int flags; + char *server; + IncomingConnect incomingConnect; + RecvMessage recvMessage; + TaskClose close; +} ParamStreamInfo; + +int ParamServiceStop(void); +int ParamServiceStart(ProcessPidDelete pidDelete); + +int ParamTaskClose(ParamTaskPtr stream); +int ParamServerCreate(ParamTaskPtr *server, const ParamStreamInfo *info); +int ParamStreamCreate(ParamTaskPtr *client, ParamTaskPtr server, const ParamStreamInfo *info, uint16_t userDataSize); +int ParamTaskSendMsg(const ParamTaskPtr stream, const ParamMessage *msg); + +int ParamEventTaskCreate(ParamTaskPtr *stream, EventProcess eventProcess, EventProcess eventBeforeProcess); +int ParamEventSend(ParamTaskPtr stream, uint64_t eventId, const char *content, uint32_t size); + +int ParamTimerCreate(ParamTaskPtr *timer, TimerProcess process, void *context); +int ParamTimerStart(ParamTaskPtr timer, uint64_t timeout, uint64_t repeat); + +void *ParamGetTaskUserData(ParamTaskPtr stream); + +int FillParamMsgContent(ParamMessage *request, uint32_t *start, int type, const char *value, uint32_t length); +ParamMsgContent *GetNextContent(const ParamMessage *reqest, uint32_t *offset); +ParamMessage *CreateParamMessage(int type, const char *name, uint32_t msgSize); + +int ConntectServer(int fd, const char *servername); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif +#endif // BASE_STARTUP_PARAM_MESSAGE_H \ No newline at end of file diff --git a/services/param/include/param_persist.h b/services/param/include/param_persist.h new file mode 100755 index 0000000000000000000000000000000000000000..95b14f6130c4ac8f4650289780aed6236bff921f --- /dev/null +++ b/services/param/include/param_persist.h @@ -0,0 +1,52 @@ +/* + * 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_PERSIST_H +#define BASE_STARTUP_PARAM_PERSIST_H +#include +#include +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +typedef int (*PersistParamGetPtr)(const char *name, const char *value, void *context); + +typedef void *PERSIST_SAVE_HANDLE; +typedef struct { + int (*load)(PersistParamGetPtr persistParamGet, void *context); + int (*save)(const char *name, const char *value); + int (*batchSaveBegin)(PERSIST_SAVE_HANDLE *handle); + int (*batchSave)(PERSIST_SAVE_HANDLE handle, const char *name, const char *value); + void (*batchSaveEnd)(PERSIST_SAVE_HANDLE handle); +} PersistParamOps; + +#ifndef PARAM_SUPPORT_SAVE_PERSIST +#define PARAM_SUPPORT_SAVE_PERSIST 1 // default +#endif + +#ifdef PARAM_SUPPORT_SAVE_PERSIST +int RegisterPersistParamOps(PersistParamOps *ops); +#define PARAM_MUST_SAVE_PARAM_DIFF 10 // 10s +#else +#define PARAM_MUST_SAVE_PARAM_DIFF UINT32_MAX +#endif +#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 index d2ed318d6b17c3583b863d2e1f69ac48c2412ea7..43452e5b83517a7c76078c751e180c00b549e637 100644 --- a/services/param/include/param_request.h +++ b/services/param/include/param_request.h @@ -1,3 +1,4 @@ + /* * Copyright (c) 2020 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,54 +16,27 @@ #ifndef BASE_STARTUP_PARAM_REQUEST_H #define BASE_STARTUP_PARAM_REQUEST_H - +#include +#include #include -#include "sys_param.h" #include "param_manager.h" - -#include "uv.h" +#include "sys_param.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; + ParamWorkSpace paramSpace; + int clientFd; + pthread_mutex_t mutex; +} ClientWorkSpace; +int WatchParamCheck(const char *keyprefix); #ifdef __cplusplus #if __cplusplus } #endif #endif -#endif \ No newline at end of file +#endif diff --git a/services/param/include/param_security.h b/services/param/include/param_security.h new file mode 100755 index 0000000000000000000000000000000000000000..b3b15e63b2838e795b4833e7209a60e62e800461 --- /dev/null +++ b/services/param/include/param_security.h @@ -0,0 +1,109 @@ +/* + * 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_SECURITY_H +#define BASE_STARTUP_PARAM_SECURITY_H +#include +#include +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +#define DAC_GROUP_START 3 +#define DAC_OTHER_START 6 +#define DAC_READ 0x0100 +#define DAC_WRITE 0x0080 +#define DAC_WATCH 0x0040 +#define DAC_ALL_PERMISSION 0777 + +#define LABEL_ALL_PERMISSION 0x04 +#define LABEL_CHECK_FOR_ALL_PROCESS 0x02 +#define LABEL_INIT_FOR_INIT 0x01 + +#define LABEL_IS_CLIENT_CHECK_PERMITTED(label) \ + ((label) != NULL) && ((((label)->flags & (LABEL_CHECK_FOR_ALL_PROCESS)) == (LABEL_CHECK_FOR_ALL_PROCESS)) && \ + (((label)->flags & (LABEL_ALL_PERMISSION)) != (LABEL_ALL_PERMISSION))) + +#define LABEL_IS_ALL_PERMITTED(label) \ + (((label) == NULL) || ((label)->flags & LABEL_ALL_PERMISSION) == (LABEL_ALL_PERMISSION)) + +typedef enum { + DAC_RESULT_PERMISSION = 0, + DAC_RESULT_INVALID_PARAM = 1000, + DAC_RESULT_FORBIDED, +} DAC_RESULT; + +typedef struct UserCred { + pid_t pid; + uid_t uid; + gid_t gid; +} UserCred; + +typedef struct { + uint32_t flags; + UserCred cred; +} ParamSecurityLabel; + +typedef struct { + pid_t pid; + uid_t uid; + gid_t gid; + uint32_t mode; // 访问权限 +} ParamDacData; + +typedef struct { + ParamDacData dacData; + const char *name; + const char *label; +} ParamAuditData; + +typedef int (*SecurityLabelFunc)(const ParamAuditData *auditData, void *context); + +typedef struct { + int (*securityInitLabel)(ParamSecurityLabel **label, int isInit); + int (*securityGetLabel)(SecurityLabelFunc label, const char *path, void *context); + int (*securityCheckFilePermission)(const ParamSecurityLabel *label, const char *fileName, int flags); + int (*securityCheckParamPermission)(const ParamSecurityLabel *srcLabel, const ParamAuditData *auditData, int mode); + int (*securityEncodeLabel)(const ParamSecurityLabel *srcLabel, char *buffer, uint32_t *bufferSize); + int (*securityDecodeLabel)(ParamSecurityLabel **srcLabel, char *buffer, uint32_t bufferSize); + int (*securityFreeLabel)(ParamSecurityLabel *srcLabel); +} ParamSecurityOps; + +typedef int (*RegisterSecurityOpsPtr)(ParamSecurityOps *ops, int isInit); + +int RegisterSecurityOps(ParamSecurityOps *ops, int isInit); + +typedef struct { + SecurityLabelFunc label; + void *context; +} LabelFuncContext; + + +#ifdef PARAM_SUPPORT_SELINUX +#ifdef PARAM_SUPPORT_DAC +#error param security only support one. +#endif +#else +#define PARAM_SUPPORT_DAC 1 // default support dac +#endif + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif +#endif // BASE_STARTUP_PARAM_SECURITY_H \ No newline at end of file diff --git a/services/param/include/param_service.h b/services/param/include/param_service.h index 8a0d8554937c2b103626963113db0b6364832152..4b048b9248b1fd0ba3a9f67ec3edab22572105fc 100644 --- a/services/param/include/param_service.h +++ b/services/param/include/param_service.h @@ -15,20 +15,38 @@ #ifndef BASE_STARTUP_PARAM_SERVICE_H #define BASE_STARTUP_PARAM_SERVICE_H +#include #include -#include "sys_param.h" + #include "param_manager.h" +#include "sys_param.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); +#define PARAM_WATCH_FLAGS_WAIT 0x01 +struct CmdLineEntry { + char *key; + int set; +}; + +int WriteParam(WorkSpace *workSpace, const char *name, const char *value, uint32_t *dataIndex, int onlyAdd); + +int InitPersistParamWorkSpace(ParamWorkSpace *workSpace); +void ClosePersistParamWorkSpace(void); +int LoadPersistParam(ParamWorkSpace *workSpace); +int WritePersistParam(ParamWorkSpace *workSpace, const char *name, const char *value); + +#ifdef STARTUP_INIT_TEST +int ProcessMessage(const ParamTaskPtr worker, const ParamMessage *msg); +int AddSecurityLabel(const ParamAuditData *auditData, void *context); +#endif +int ProcessParamWaitAdd(ParamWorkSpace *worksapce, const ParamTaskPtr worker, const ParamMessage *msg); +int ProcessParamWatchAdd(ParamWorkSpace *worksapce, const ParamTaskPtr worker, const ParamMessage *msg); #ifdef __cplusplus #if __cplusplus } diff --git a/services/param/include/param_trie.h b/services/param/include/param_trie.h index 8c3e3f9848e10b76d58ac90c1f23f8561ab15385..53bb6a54aa4c458e9dd37cc3bdf292d0221e792b 100644 --- a/services/param/include/param_trie.h +++ b/services/param/include/param_trie.h @@ -15,121 +15,109 @@ #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 "param_security.h" #include "securec.h" +#include "sys_param.h" -#ifdef __cplusplus -#if __cplusplus -extern "C" { -#endif +#ifndef __NR_futex +#define PARAM_NR_FUTEX 202 /* syscall number */ +#else +#define PARAM_NR_FUTEX __NR_futex #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 +#if defined FUTEX_WAIT || defined FUTEX_WAKE +#include +#else +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 -#define TRIE_NODE_HEADER \ - atomic_uint_least32_t serial; \ - NODE_INDEX left; \ - NODE_INDEX right; +#define PARAM_FUTEX(ftx, op, value, timeout, bitset) \ + do { \ + struct timespec d_timeout = { 0, 1000 * 1000 * (timeout) }; \ + syscall(PARAM_NR_FUTEX, ftx, op, value, &d_timeout, NULL, bitset); \ + } while (0) -#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_wake(ftx, count) PARAM_FUTEX(ftx, FUTEX_WAKE, count, 0, 0) +#define futex_wait(ftx, value) PARAM_FUTEX(ftx, FUTEX_WAIT, value, 100, 0) +#endif -#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) +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif +#define PARAM_WORKSPACE_MAX (80 * 1024) +#define FILENAME_LEN_MAX 255 typedef struct { - TRIE_NODE_HEADER; + uint32_t left; + uint32_t right; + uint32_t child; + uint32_t labelIndex; + uint32_t dataIndex; + uint16_t length; char key[0]; -} TrieNode; +} ParamTrieNode; + +#define PARAM_FLAGS_MODIFY 0x80000000 +#define PARAM_FLAGS_TRIGGED 0x40000000 +#define PARAM_FLAGS_WAITED 0x20000000 +#define PARAM_FLAGS_COMMITID 0x0000ffff typedef struct { - TRIE_NODE_HEADER; - NODE_INDEX child; - NODE_INDEX labelIndex; - NODE_INDEX dataIndex; - char key[0]; -} TrieDataNode; + atomic_uint commitId; + uint16_t keyLength; + uint16_t valueLength; + char data[0]; +} ParamNode; typedef struct { - atomic_uint_least32_t serial; - atomic_uint_least32_t dataLength; + uid_t uid; + gid_t gid; + uint16_t mode; + uint16_t length; char data[0]; -} DataEntry; +} ParamSecruityNode; typedef struct { - atomic_uint_least32_t serial; - u_int32_t currOffset; - u_int32_t firstNode; - u_int32_t dataSize; - u_int32_t reserved_[28]; + uint32_t trieNodeCount; + uint32_t paramNodeCount; + uint32_t securityNodeCount; + uint32_t currOffset; + uint32_t firstNode; + uint32_t dataSize; + uint32_t reserved_[28]; char data[0]; -} WorkArea; +} ParamTrieHeader; 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; + uint32_t (*allocTrieNode)(struct WorkSpace_ *workSpace, const char *key, uint32_t keyLen); + int (*compareTrieNode)(ParamTrieNode *node, const char *key2, uint32_t key2Len); + ParamTrieHeader *area; } 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); +ParamTrieNode *GetTrieNode(WorkSpace *workSpace, uint32_t offset); +void SaveIndex(uint32_t *index, uint32_t offset); + +ParamTrieNode *AddTrieNode(WorkSpace *workSpace, const char *key, uint32_t keyLen); +ParamTrieNode *FindTrieNode(WorkSpace *workSpace, const char *key, uint32_t keyLen, uint32_t *matchLabel); -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); +typedef int (*TraversalTrieNodePtr)(WorkSpace *workSpace, ParamTrieNode *node, void *cookie); +int TraversalTrieNode(WorkSpace *workSpace, ParamTrieNode *subTrie, TraversalTrieNodePtr walkFunc, void *cookie); +uint32_t AddParamSecruityNode(WorkSpace *workSpace, const ParamAuditData *auditData); +uint32_t AddParamNode(WorkSpace *workSpace, const char *key, uint32_t keyLen, const char *value, uint32_t valueLen); #ifdef __cplusplus #if __cplusplus } diff --git a/services/param/include/param_utils.h b/services/param/include/param_utils.h new file mode 100755 index 0000000000000000000000000000000000000000..61decf08f413d91a29509694db52c021c948ad62 --- /dev/null +++ b/services/param/include/param_utils.h @@ -0,0 +1,121 @@ +/* + * 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_UTILS_H +#define BASE_STARTUP_PARAM_UTILS_H +#include +#include + +#include "init_log.h" +#include "securec.h" +#include "sys_param.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +typedef enum { + PARAM_CODE_NOT_INIT = PARAM_CODE_MAX + 1, + PARAM_CODE_ERROR_MAP_FILE, +} PARAM_INNER_CODE; + +#define MS_UNIT 1000 +#define UNUSED(x) (void)(x) +#define PARAM_ALIGN(len) (((len) + 0x03) & (~0x03)) +#define PARAM_ENTRY(ptr, type, member) (type *)((char *)(ptr)-offsetof(type, member)) + +#define IS_READY_ONLY(name) \ + ((strncmp((name), "const.", strlen("const.")) == 0) || (strncmp((name), "ro.", strlen("ro.")) == 0)) +#define PARAM_CONST_PREFIX "persist." + +#define SYS_POWER_CTRL "sys.powerctrl=" +#define OHOS_CTRL_START "ohos.ctl.start=" +#define OHOS_CTRL_STOP "ohos.ctl.stop=" +#define OHOS_SERVICE_CTRL_PREFIX "ohos.servicectrl." +#define OHOS_BOOT "ohos.boot." + +#ifdef STARTUP_INIT_TEST +#define PARAM_STATIC +#define PARAM_DEFAULT_PATH "" +#define PIPE_NAME "/data/paramservice" +#define PARAM_STORAGE_PATH PARAM_DEFAULT_PATH"/__parameters__/param_storage" +#define PARAM_PERSIST_SAVE_PATH PARAM_DEFAULT_PATH"/param/persist_parameters" +#define PARAM_PERSIST_SAVE_TMP_PATH PARAM_DEFAULT_PATH"/param/tmp_persist_parameters" +#define PARAM_CMD_LINE PARAM_DEFAULT_PATH"/proc/cmdline" +#define GROUP_FILE_PATH PARAM_DEFAULT_PATH"/etc/group" +#define USER_FILE_PATH PARAM_DEFAULT_PATH"/etc/passwd" +#else +#define PARAM_DEFAULT_PATH "" +#define PARAM_STATIC static +#define PIPE_NAME "/dev/unix/socket/paramservice" +#define PARAM_STORAGE_PATH "/dev/__parameters__/param_storage" +#define PARAM_PERSIST_SAVE_PATH "/data/parameters/persist_parameters" +#define PARAM_PERSIST_SAVE_TMP_PATH "/data/parameters/tmp_persist_parameters" +#define PARAM_CMD_LINE "/proc/cmdline" +#define GROUP_FILE_PATH "/etc/group" +#define USER_FILE_PATH "/etc/passwd" +#endif + +#define WORKSPACE_FLAGS_INIT 0x01 +#define WORKSPACE_FLAGS_LOADED 0x02 +#define WORKSPACE_FLAGS_UPDATE 0x04 +#define WORKSPACE_FLAGS_LABEL_LOADED 0x08 + +#define PARAM_SET_FLAG(node, flag) ((node) |= (flag)) +#define PARAM_CLEAR_FLAG(node, flag) ((node) &= ~(flag)) +#define PARAM_TEST_FLAG(node, flag) (((node) & (flag)) == (flag)) + +#define PARAM_LOGI(fmt, ...) STARTUP_LOGI(LABEL, fmt, ##__VA_ARGS__) +#define PARAM_LOGE(fmt, ...) STARTUP_LOGE(LABEL, fmt, ##__VA_ARGS__) +#define PARAM_LOGD(fmt, ...) STARTUP_LOGD(LABEL, fmt, ##__VA_ARGS__) + +#define PARAM_CHECK(retCode, exper, ...) \ + if (!(retCode)) { \ + PARAM_LOGE(__VA_ARGS__); \ + exper; \ + } + +#define MAX_LABEL_LEN 256 +#define PARAM_BUFFER_SIZE 256 + +#define SUBSTR_INFO_NAME 0 +#define SUBSTR_INFO_VALUE 1 +#ifdef PARAM_SUPPORT_SELINUX +#define SUBSTR_INFO_LABEL 1 +#define SUBSTR_INFO_DAC 2 +#else +#define SUBSTR_INFO_LABEL 1 +#define SUBSTR_INFO_DAC 1 +#endif + +typedef struct { + int length; + char value[PARAM_BUFFER_SIZE]; +} SubStringInfo; + +#define MAX_DATA_BUFFER 2048 +char *ReadFileData(const char *fileName); +void CheckAndCreateDir(const char *fileName); +int ReadFileInDir(const char *dirPath, const char *includeExt, + int (*processFile)(const char *fileName, void *context), void *context); +int GetSubStringInfo(const char *buff, uint32_t buffLen, char delimiter, SubStringInfo *info, int subStrNumber); +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif +#endif \ No newline at end of file diff --git a/services/param/include/trigger_checker.h b/services/param/include/trigger_checker.h index 8bba9e1e40eca25a95b76bf0797c82b1759c6814..ad38e5f717e3110166d5771cb75632847607128f 100644 --- a/services/param/include/trigger_checker.h +++ b/services/param/include/trigger_checker.h @@ -15,8 +15,7 @@ #ifndef STARTUP_TRIGER_CHECKER_H #define STARTUP_TRIGER_CHECKER_H - -#include +#include #include #include @@ -31,6 +30,7 @@ extern "C" { #define MAX_TRIGGER_TYPE_LEN 16 #define SUPPORT_DATA_BUFFER_MAX 128 +#define MAX_DATA_BUFFER_MAX (SUPPORT_DATA_BUFFER_MAX * 5) #define CONDITION_EXTEND_LEN 32 #define LOGIC_DATA_FLAGS_ORIGINAL 0x1 @@ -41,16 +41,16 @@ extern "C" { #define LOGIC_DATA_CLEAR_FLAG(data, flag) (data)->flags &= ~(flag) typedef struct { - u_int32_t flags; - u_int32_t startIndex; - u_int32_t endIndex; + uint32_t flags; + uint32_t startIndex; + uint32_t endIndex; } LogicData; -struct tagTriggerNode; - +struct tagTriggerNode_; +typedef int (*PARAM_CHECK_DONE)(struct tagTriggerNode_ *trigger, const char *content, uint32_t size); typedef struct { char triggerContent[MAX_TRIGGER_NAME_LEN]; - int (*triggerExecuter)(struct tagTriggerNode *trigger, u_int32_t index); + PARAM_CHECK_DONE triggerExecuter; int dataNumber; int endIndex; int dataUnit; @@ -64,10 +64,10 @@ typedef struct { 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 ConvertInfixToPrefix(const char *condition, char *prefix, uint32_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); -char *GetMatchedSubCondition(const char *condition, const char *input, int length); +int GetValueFromContent(const char *content, uint32_t contentSize, uint32_t start, char *value, uint32_t valueSize); +int CheckMatchSubCondition(const char *condition, const char *input, int length); #ifdef __cplusplus #if __cplusplus diff --git a/services/param/include/trigger_manager.h b/services/param/include/trigger_manager.h index 6e32fa5d36c86ee15e2c80bd40b08c8dcb56ba96..e6795d05728ed4ef2393c692e485f620ef8bfab2 100644 --- a/services/param/include/trigger_manager.h +++ b/services/param/include/trigger_manager.h @@ -15,16 +15,16 @@ #ifndef STARTUP_TRIGER_MANAGER_H #define STARTUP_TRIGER_MANAGER_H -#include -#include -#include +#include #include #include "cJSON.h" #include "init_log.h" -#include "param_manager.h" -#include "trigger_checker.h" +#include "list.h" +#include "param_message.h" +#include "param_utils.h" #include "securec.h" +#include "trigger_checker.h" #ifdef __cplusplus #if __cplusplus @@ -36,88 +36,132 @@ extern "C" { #define TRIGGER_ARR_NAME_IN_JSON "jobs" #define CMDS_ARR_NAME_IN_JSON "cmds" -#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) +#define TRIGGER_EXECUTE_QUEUE 64 +#define MAX_CONDITION_NUMBER 64 + +#define TRIGGER_FLAGS_QUEUE 0x01 +#define TRIGGER_FLAGS_RELATED 0x02 +#define TRIGGER_FLAGS_ONCE 0x04 // 执行完成后释放 +#define TRIGGER_FLAGS_SUBTRIGGER 0x08 // 对init执行后,需要执行的init:xxx=aaa的trigger + +#define CMD_INDEX_FOR_PARA_WAIT 0xfffE +#define CMD_INDEX_FOR_PARA_WATCH 0xffff + +#define TRIGGER_IN_QUEUE(trigger) (((trigger)->flags & TRIGGER_FLAGS_QUEUE) == TRIGGER_FLAGS_QUEUE) +#define TRIGGER_SET_FLAG(trigger, flag) ((trigger)->flags |= (flag)) +#define TRIGGER_CLEAR_FLAG(trigger, flag) ((trigger)->flags &= ~(flag)) +#define TRIGGER_TEST_FLAG(trigger, flag) (((trigger)->flags & (flag)) == (flag)) +#define TRIGGER_GET_EXT_DATA(trigger, TYPE) \ + (trigger)->extDataSize == 0 ? NULL : (TYPE *)(((char *)(trigger)) + (trigger)->extDataOffset) typedef enum { TRIGGER_BOOT = 0, TRIGGER_PARAM, TRIGGER_UNKNOW, - TRIGGER_MAX -}TriggerType; + TRIGGER_MAX, + TRIGGER_PARAM_WAIT, + TRIGGER_PARAM_WATCH +} TriggerType; + +#define PARAM_TRIGGER_FOR_WAIT 0 +#define PARAM_TRIGGER_FOR_WATCH 1 + +typedef struct { + ListNode triggerList; + uint32_t triggerCount; + uint32_t cmdNodeCount; +} TriggerHeader; + +#define PARAM_TRIGGER_HEAD_INIT(head) \ + do { \ + ListInit(&(head).triggerList); \ + (head).triggerCount = 0; \ + (head).cmdNodeCount = 0; \ + } while (0) // Command对象列表,主要存储每个triger需要执行那些Command操作。 -typedef struct CommandNode { - atomic_uint_least32_t next; - char name[MAX_TRIGGER_CMD_NAME_LEN]; +typedef struct CommandNode_ { + struct CommandNode_ *next; + uint32_t cmdKeyIndex; char content[0]; } CommandNode; -typedef struct tagTriggerNode { - 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]; +typedef struct tagTriggerNode_ { + ListNode node; + uint32_t flags : 24; + uint32_t type : 8; + TriggerHeader *triggerHead; + CommandNode *firstCmd; + CommandNode *lastCmd; + uint16_t extDataOffset; + uint16_t extDataSize; + char *condition; + char name[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; + uint32_t queueCount; + uint32_t startIndex; + uint32_t endIndex; + TriggerNode **executeQueue; +} TriggerExecuteQueue; 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; + TriggerHeader triggerHead; + ListNode node; + uint32_t timeout; + ParamTaskPtr stream; +} ParamWatcher; + +typedef struct TriggerExtData_ { + int (*excuteCmd)(struct TriggerExtData_ *trigger, int cmd, const char *content); + uint32_t watcherId; + ParamWatcher *watcher; +} TriggerExtData; typedef struct TriggerWorkSpace { + void (*cmdExec)(TriggerNode *trigger, CommandNode *cmd, const char *content, uint32_t size); + ParamTaskPtr eventHandle; + char buffer[PARAM_NAME_LEN_MAX + PARAM_CONST_VALUE_LEN_MAX]; TriggerExecuteQueue executeQueue; - TriggerHeader header[TRIGGER_MAX]; - TriggerArea *area; + TriggerHeader triggerHead[TRIGGER_MAX]; + ParamWatcher watcher; + ListNode waitList; } TriggerWorkSpace; -int InitTriggerWorkSpace(TriggerWorkSpace *workSpace); -int ParseTrigger(TriggerWorkSpace *workSpace, cJSON *triggerItem); - -typedef int (*TRIGGER_MATCH)(LogicCalculator *calculator, TriggerNode *trigger, const char *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); +int InitTriggerWorkSpace(void); +void CloseTriggerWorkSpace(void); -TriggerNode *GetTriggerByName(TriggerWorkSpace *workSpace, const char *triggerName, u_int32_t *triggerIndex); -int ExecuteTrigger(TriggerWorkSpace *workSpace, TriggerNode *trigger, CMD_EXECUTE cmdExecuter); -int CheckTrigger(const 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); -int CheckAndExecuteTrigger(TriggerWorkSpace *workSpace, const char *content, PARAM_CHECK_DONE triggerExecuter); +typedef int (*TRIGGER_MATCH)(TriggerWorkSpace *workSpace, LogicCalculator *calculator, + TriggerNode *trigger, const char *content, uint32_t contentSize); +int CheckTrigger(TriggerWorkSpace *workSpace, int type, + const char *content, uint32_t contentSize, PARAM_CHECK_DONE triggerExecuter); +int MarkTriggerToParam(TriggerWorkSpace *workSpace, TriggerHeader *triggerHead, const char *name); +int CheckAndMarkTrigger(int type, const char *name); TriggerNode *ExecuteQueuePop(TriggerWorkSpace *workSpace); -int ExecuteQueuePush(TriggerWorkSpace *workSpace, TriggerNode *trigger, u_int32_t index); +int ExecuteQueuePush(TriggerWorkSpace *workSpace, TriggerNode *trigger); int ExecuteQueueSize(TriggerWorkSpace *workSpace); -u_int32_t AddTrigger(TriggerWorkSpace *workSpace, int type, const char *name, const char *condition); -u_int32_t AddCommand(TriggerWorkSpace *workSpace, TriggerNode *trigger, const char *cmdName, const char *content); +TriggerNode *AddTrigger(TriggerHeader *triggerHead, const char *name, const char *condition, uint16_t extDataSize); +TriggerNode *GetTriggerByName(TriggerWorkSpace *workSpace, const char *triggerName); +void FreeTrigger(TriggerNode *trigger); +void ClearTrigger(TriggerHeader *head); + +int AddCommand(TriggerNode *trigger, uint32_t cmdIndex, const char *content); +CommandNode *GetNextCmdNode(TriggerNode *trigger, CommandNode *curr); + +void DumpTrigger(TriggerWorkSpace *workSpace); +void PostParamTrigger(int type, const char *name, const char *value); -TriggerWorkSpace *GetTriggerWorkSpace(); +ParamWatcher *GetParamWatcher(const ParamTaskPtr worker); +ParamWatcher *GetNextParamWatcher(TriggerWorkSpace *workSpace, ParamWatcher *curr); +TriggerNode *AddWatcherTrigger(ParamWatcher *watcher, + int triggerType, const char *name, const char *condition, const TriggerExtData *extData); +void DelWatcherTrigger(ParamWatcher *watcher, uint32_t watcherId); +void ClearWatcherTrigger(ParamWatcher *watcher); +TriggerWorkSpace *GetTriggerWorkSpace(void); #ifdef __cplusplus #if __cplusplus } diff --git a/services/param/manager/param_cache.c b/services/param/manager/param_cache.c deleted file mode 100644 index 690de37e869cb0a8777f1a275013d02da97d8aae..0000000000000000000000000000000000000000 --- a/services/param/manager/param_cache.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * 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 index d0a9b11bd10cbcdd3bfc3a48618b4c80610735f9..8324197cef7434b9e8a8714c02fc300292e47d7d 100644 --- a/services/param/manager/param_manager.c +++ b/services/param/manager/param_manager.c @@ -1,5 +1,5 @@ /* - * 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 @@ -14,325 +14,145 @@ */ #include "param_manager.h" - #include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #define LABEL "Manager" +#if !defined PARAM_SUPPORT_SELINUX && !defined PARAM_SUPPORT_DAC +static ParamSecurityLabel g_defaultSecurityLabel; +#endif -#ifdef PARAM_SUPPORT_SELINUX -static int SelinuxAuditCallback(void *data, - __attribute__((unused))security_class_t class, char *msgBuf, size_t msgSize) +static int GetParamSecurityOps(ParamWorkSpace *workSpace, int isInit) { - 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"); - if (snprintf_s(msgBuf, msgSize, msgSize - 1, "param=%s pid=%d uid=%d gid=%d", - auditData->name, auditData->cr->pid, auditData->cr->uid, auditData->cr->gid) == -1) { - return PARAM_CODE_INVALID_PARAM; - } - return 0; -} + UNUSED(isInit); + int ret = 0; +#if (defined PARAM_SUPPORT_SELINUX || defined PARAM_SUPPORT_DAC) + ret = RegisterSecurityOps(&workSpace->paramSecurityOps, isInit); + PARAM_CHECK(workSpace->paramSecurityOps.securityInitLabel != NULL, return -1, "Invalid securityInitLabel"); + ret = workSpace->paramSecurityOps.securityInitLabel(&workSpace->securityLabel, isInit); + PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_NAME, "Failed to init security"); +#else + workSpace->securityLabel = &g_defaultSecurityLabel; + workSpace->securityLabel->flags |= LABEL_ALL_PERMISSION; #endif + return ret; +} -int InitParamWorkSpace(ParamWorkSpace *workSpace, int onlyRead, const char *context) +int InitParamWorkSpace(ParamWorkSpace *workSpace, int onlyRead) { - u_int32_t flags = atomic_load_explicit(&workSpace->flags, memory_order_relaxed); - if ((flags & WORKSPACE_FLAGS_INIT) == WORKSPACE_FLAGS_INIT) { + PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_NAME, "Invalid param"); + if (PARAM_TEST_FLAG(workSpace->flags, 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); + int isInit = 0; + int op = DAC_READ; + if (onlyRead == 0) { + isInit = LABEL_INIT_FOR_INIT; + op = DAC_WRITE; + } + int ret = GetParamSecurityOps(workSpace, isInit); + PARAM_CHECK(ret == 0, return -1, "Failed to get security operations"); + ParamSecurityOps *paramSecurityOps = &workSpace->paramSecurityOps; + if (!LABEL_IS_ALL_PERMITTED(workSpace->securityLabel)) { + PARAM_CHECK(paramSecurityOps->securityFreeLabel != NULL, return -1, "Invalid securityFreeLabel"); + PARAM_CHECK(paramSecurityOps->securityCheckFilePermission != NULL, return -1, "Invalid securityCheck"); + PARAM_CHECK(paramSecurityOps->securityCheckParamPermission != NULL, return -1, "Invalid securityCheck"); + if (isInit == LABEL_INIT_FOR_INIT) { + PARAM_CHECK(paramSecurityOps->securityGetLabel != NULL, return -1, "Invalid securityGetLabel"); + PARAM_CHECK(paramSecurityOps->securityDecodeLabel != NULL, return -1, "Invalid securityDecodeLabel"); + } else { + PARAM_CHECK(paramSecurityOps->securityEncodeLabel != NULL, return -1, "Invalid securityEncodeLabel"); + } + ret = paramSecurityOps->securityCheckFilePermission(workSpace->securityLabel, PARAM_STORAGE_PATH, op); + PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_NAME, "No permission to read file %s", PARAM_STORAGE_PATH); } -#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); - PARAM_CHECK(ret == 0, return ret, "InitWorkSpace failed."); - - workSpace->paramLabelSpace.compareTrieNode = CompareTrieNode; // 必须先设置 - workSpace->paramLabelSpace.allocTrieNode = AllocateTrieNode; - ret = InitWorkSpace(PARAM_INFO_PATH, &workSpace->paramLabelSpace, onlyRead); - PARAM_CHECK(ret == 0, return ret, "InitWorkSpace failed."); - - atomic_store_explicit(&workSpace->flags, WORKSPACE_FLAGS_INIT, memory_order_release); + ret = InitWorkSpace(PARAM_STORAGE_PATH, &workSpace->paramSpace, onlyRead); + PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_NAME, "Failed to init workspace"); + PARAM_SET_FLAG(workSpace->flags, WORKSPACE_FLAGS_INIT); return ret; } void CloseParamWorkSpace(ParamWorkSpace *workSpace) { CloseWorkSpace(&workSpace->paramSpace); - CloseWorkSpace(&workSpace->paramLabelSpace); - atomic_store_explicit(&workSpace->flags, 0, memory_order_release); + if (workSpace->paramSecurityOps.securityFreeLabel != NULL) { + workSpace->paramSecurityOps.securityFreeLabel(workSpace->securityLabel); + } + workSpace->flags = 0; } -int WriteParamInfo(ParamWorkSpace *workSpace, SubStringInfo *info, int subStrNumber) +static uint32_t ReadCommitId(ParamNode *entry) { - 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"; + uint32_t commitId = atomic_load_explicit(&entry->commitId, memory_order_acquire); + while (commitId & PARAM_FLAGS_MODIFY) { + futex_wait(&entry->commitId, commitId); + commitId = atomic_load_explicit(&entry->commitId, memory_order_acquire); } - - 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; + return commitId & PARAM_FLAGS_COMMITID; } -int AddParam(WorkSpace *workSpace, const char *name, const char *value) +int ReadParamCommitId(ParamWorkSpace *workSpace, ParamHandle handle, uint32_t *commitId) { - 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); + PARAM_CHECK(workSpace != NULL && commitId != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid workSpace"); + ParamNode *entry = (ParamNode *)GetTrieNode(&workSpace->paramSpace, handle); 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); + return -1; } - 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); + *commitId = ReadCommitId(entry); 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) +int ReadParamWithCheck(ParamWorkSpace *workSpace, const char *name, int op, ParamHandle *handle) { - 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; - } - + PARAM_CHECK(handle != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param handle"); + PARAM_CHECK(workSpace != NULL && name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param name"); *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); + int ret = CheckParamPermission(workSpace, workSpace->securityLabel, name, op); + PARAM_CHECK(ret == 0, return ret, "Forbid to access parameter %s", name); - // 查找结点 - TrieDataNode *node = FindTrieDataNode(&workSpace->paramSpace, name, strlen(name), 0); + ParamTrieNode *node = FindTrieNode(&workSpace->paramSpace, name, strlen(name), NULL); 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; + return PARAM_CODE_NOT_FOUND; } -int ReadParamValue(ParamWorkSpace *workSpace, ParamHandle handle, char *value, u_int32_t *len) +int ReadParamValue(ParamWorkSpace *workSpace, ParamHandle handle, char *value, uint32_t *length) { - 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); + PARAM_CHECK(workSpace != NULL && length != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); + ParamNode *entry = (ParamNode *)GetTrieNode(&workSpace->paramSpace, handle); if (entry == NULL) { return -1; } - if (value == NULL) { - *len = DATA_ENTRY_DATA_LEN(entry) + 1; + *length = entry->valueLength + 1; 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; - } - } + PARAM_CHECK(*length > entry->valueLength, return PARAM_CODE_INVALID_PARAM, + "Invalid value len %u %u", *length, entry->valueLength); + uint32_t commitId = ReadCommitId(entry); + do { + int ret = memcpy_s(value, *length, entry->data + entry->keyLength + 1, entry->valueLength); + PARAM_CHECK(ret == EOK, return -1, "Failed to copy value"); + value[entry->valueLength] = '\0'; + *length = entry->valueLength; + } while (commitId != ReadCommitId(entry)); return 0; } -int ReadParamName(ParamWorkSpace *workSpace, ParamHandle handle, char *name, u_int32_t len) +int ReadParamName(ParamWorkSpace *workSpace, ParamHandle handle, char *name, uint32_t length) { PARAM_CHECK(workSpace != NULL && name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); - DataEntry *entry = (DataEntry *)GetTrieNode(&workSpace->paramSpace, &handle); + ParamNode *entry = (ParamNode *)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, strlen("ctl.") + strlen(value) + 1, "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; + PARAM_CHECK(length > entry->keyLength, return -1, "Invalid param size %u %u", entry->keyLength, length); + int ret = memcpy_s(name, length, entry->data, entry->keyLength); + PARAM_CHECK(ret == EOK, return PARAM_CODE_INVALID_PARAM, "Failed to copy name"); + name[entry->keyLength] = '\0'; + return 0; } int CheckParamName(const char *name, int info) @@ -341,6 +161,9 @@ int CheckParamName(const char *name, int info) if (nameLen >= PARAM_NAME_LEN_MAX) { return PARAM_CODE_INVALID_NAME; } + if (strcmp(name, "#") == 0) { + return 0; + } if (nameLen < 1 || name[0] == '.' || (!info && name[nameLen - 1] == '.')) { PARAM_LOGE("CheckParamName %s %d", name, info); @@ -367,168 +190,106 @@ int CheckParamName(const char *name, int info) return 0; } -int CheckParamValue(WorkSpace *workSpace, const TrieDataNode *node, const char *name, const char *value) +static int ProcessParamTraversal(WorkSpace *workSpace, ParamTrieNode *node, void *cookie) { - 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"); + UNUSED(workSpace); + ParamTraversalContext *context = (ParamTraversalContext *)cookie; + ParamTrieNode *current = (ParamTrieNode *)node; + if (current == NULL) { + return 0; } + if (current->dataIndex == 0) { + return 0; + } + context->traversalParamPtr(current->dataIndex, context->context); return 0; } -int CheckMacPerms(ParamWorkSpace *workSpace, - const ParamSecurityLabel *srcLabel, const char *name, u_int32_t labelIndex) +int TraversalParam(ParamWorkSpace *workSpace, TraversalParamPtr walkFunc, void *cookie) { -#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 + ParamTraversalContext context = { + walkFunc, cookie + }; + return TraversalTrieNode(&workSpace->paramSpace, NULL, ProcessParamTraversal, &context); } -int CanWriteParam(ParamWorkSpace *workSpace, - const ParamSecurityLabel *srcLabel, const TrieDataNode *node, const char *name, const char *value) +int CheckParamPermission(ParamWorkSpace *workSpace, + const ParamSecurityLabel *srcLabel, const char *name, int mode) { - 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); + if (LABEL_IS_ALL_PERMITTED(workSpace->securityLabel)) { + return 0; } + PARAM_CHECK(name != NULL && srcLabel != NULL, return -1, "Invalid param"); + if (workSpace->paramSecurityOps.securityCheckParamPermission == NULL) { + return DAC_RESULT_FORBIDED; + } + uint32_t labelIndex = 0; + FindTrieNode(&workSpace->paramSpace, name, strlen(name), &labelIndex); + ParamSecruityNode *node = (ParamSecruityNode *)GetTrieNode(&workSpace->paramSpace, labelIndex); + PARAM_CHECK(node != NULL, return DAC_RESULT_FORBIDED, "Can not get security label %d", labelIndex); - 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; + 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 + auditData.dacData.uid = node->uid; + auditData.dacData.gid = node->gid; + auditData.dacData.mode = node->mode; + auditData.label = node->data; + return workSpace->paramSecurityOps.securityCheckParamPermission(srcLabel, &auditData, mode); } -int GetSubStringInfo(const char *buff, u_int32_t buffLen, char delimiter, SubStringInfo *info, int subStrNumber) +static int DumpTrieDataNodeTraversal(WorkSpace *workSpace, ParamTrieNode *node, void *cookie) { - size_t i = 0; - // 去掉开始的空格 - for (; i < strlen(buff); i++) { - if (!isspace(buff[i])) { - break; - } + int verbose = *(int *)cookie; + ParamTrieNode *current = (ParamTrieNode *)node; + if (current == NULL) { + return 0; } - // 过滤掉注释 - if (buff[i] == '#') { - return -1; + if (verbose) { + printf(" Trie node info [%5u,%5u,%5u] data [%5u,%5u] length:%-5d %s \n", + current->left, current->right, current->child, + current->dataIndex, current->labelIndex, current->length, current->key); } - // 分割字符串 - 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 (current->dataIndex != 0) { + ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, current->dataIndex); + if (entry != NULL) { + printf("\tparameter length [%5d,%5d] %s \n", + entry->keyLength, entry->valueLength, (entry != NULL) ? entry->data : "null"); } } - if (valueCurr > 0) { - info[curr].value[valueCurr] = '\0'; - valueCurr = 0; - curr++; + if (current->labelIndex != 0) { + ParamSecruityNode *label = (ParamSecruityNode *)GetTrieNode(workSpace, current->labelIndex); + if (label != NULL) { + printf("\tparameter label dac %d %d %o %s \n", + label->uid, label->gid, label->mode, (label->length > 0) ? label->data : "null"); + } } - return curr; + return 0; } -int BuildParamContent(char *content, u_int32_t contentSize, const char *name, const char *value) +static void DumpWorkSpace(ParamWorkSpace *workSpace, int verbose) { - 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); - PARAM_CHECK(ret == 0, return -1, "Failed to copy porperty"); - offset += nameLen; - ret = memcpy_s(content + offset, contentSize - offset, "=", 1); - PARAM_CHECK(ret == 0, return -1, "Failed to copy porperty"); - 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; + printf("workSpace information \n"); + printf(" map file: %s \n", workSpace->paramSpace.fileName); + printf(" total size: %d \n", workSpace->paramSpace.area->dataSize); + printf(" first offset: %d \n", workSpace->paramSpace.area->firstNode); + printf(" current offset: %d \n", workSpace->paramSpace.area->currOffset); + printf(" total node: %d \n", workSpace->paramSpace.area->trieNodeCount); + printf(" total param node: %d \n", workSpace->paramSpace.area->paramNodeCount); + printf(" total security node: %d\n", workSpace->paramSpace.area->securityNodeCount); + printf(" node info: \n"); + TraversalTrieNode(&workSpace->paramSpace, NULL, DumpTrieDataNodeTraversal, (void *)&verbose); } -int ProcessParamTraversal(WorkSpace *workSpace, TrieNode *node, void *cookie) +void DumpParameters(ParamWorkSpace *workSpace, int verbose) { - 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; + printf("Dump all paramters begin ...\n"); + DumpWorkSpace(workSpace, verbose); + if (verbose) { + printf("Local sercurity information\n"); + printf("\t pid: %d uid: %d gid: %d \n", + workSpace->securityLabel->cred.pid, + workSpace->securityLabel->cred.uid, + workSpace->securityLabel->cred.gid); + } + printf("Dump all paramters finish\n"); } - -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_message.c b/services/param/manager/param_message.c new file mode 100755 index 0000000000000000000000000000000000000000..9d5d8dcfa9286fc15e1ffb90853e45c39102a678 --- /dev/null +++ b/services/param/manager/param_message.c @@ -0,0 +1,86 @@ +/* + * 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_message.h" +#include +#include +#include +#include +#include +#include + +#define LABEL "PARAM_MSG" +int ConntectServer(int fd, const char *servername) +{ + PARAM_CHECK(fd >= 0, return -1, "Invalid fd %d", fd); + PARAM_CHECK(servername != NULL, return -1, "Invalid servername"); + struct sockaddr_un addr; + /* fill socket address structure with server's address */ + int ret = memset_s(&addr, sizeof(addr), 0, sizeof(addr)); + PARAM_CHECK(ret == 0, return -1, "Failed to memset server address"); + addr.sun_family = AF_UNIX; + ret = sprintf_s(addr.sun_path, sizeof(addr.sun_path) - 1, "%s", servername); + PARAM_CHECK(ret > EOK, return -1, "Failed to sprintf_s server address"); + int len = offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path); + ret = connect(fd, (struct sockaddr *)&addr, len); + PARAM_CHECK(ret != -1, return -1, "Failed to connect server %s %s", servername, strerror(errno)); + return 0; +} + +int FillParamMsgContent(ParamMessage *request, uint32_t *start, int type, const char *value, uint32_t length) +{ + PARAM_CHECK(request != NULL && start != NULL, return -1, "Invalid param"); + PARAM_CHECK(value != NULL && length > 0, return -1, "Invalid value"); + uint32_t bufferSize = request->msgSize - sizeof(ParamMessage); + uint32_t offset = *start; + PARAM_CHECK((offset + sizeof(ParamMsgContent) + length) <= bufferSize, + return -1, "Invalid msgSize %u offset %u %d", request->msgSize, offset, type); + ParamMsgContent *content = (ParamMsgContent *)(request->data + offset); + content->type = type; + content->contentSize = length + 1; + int ret = memcpy_s(content->content, content->contentSize - 1, value, length); + PARAM_CHECK(ret == EOK, return -1, "Failed to copy value for %d", type); + content->content[length] = '\0'; + offset += sizeof(ParamMsgContent) + PARAM_ALIGN(content->contentSize); + *start = offset; + return 0; +} + +ParamMessage *CreateParamMessage(int type, const char *name, uint32_t msgSize) +{ + if (msgSize < sizeof(ParamMessage)) { + msgSize = sizeof(ParamMessage); + } + ParamMessage *msg = (ParamMessage *)malloc(msgSize); + PARAM_CHECK(msg != NULL, return NULL, "Failed to malloc message"); + msg->type = type; + msg->id.msgId = 0; + msg->msgSize = msgSize; + int ret = strcpy_s(msg->key, sizeof(msg->key) - 1, name); + PARAM_CHECK(ret == EOK, free(msg); + return NULL, "Failed to fill name"); + return msg; +} + +ParamMsgContent *GetNextContent(const ParamMessage *reqest, uint32_t *offset) +{ + ParamMessage *msg = (ParamMessage *)reqest; + if ((msg == NULL) || ((*offset + sizeof(ParamMessage) + sizeof(ParamMsgContent)) >= msg->msgSize)) { + return NULL; + } + ParamMsgContent *content = (ParamMsgContent *)(msg->data + *offset); + *offset += sizeof(ParamMsgContent) + PARAM_ALIGN(content->contentSize); + return content; +} diff --git a/services/param/manager/param_trie.c b/services/param/manager/param_trie.c index c380a87869dab5896f3020900a8c9321f3167cca..1de0df13449ca5c80d14de7b0aae25fc0df446b5 100644 --- a/services/param/manager/param_trie.c +++ b/services/param/manager/param_trie.c @@ -19,8 +19,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -28,70 +28,27 @@ #include #include "init_utils.h" +#include "param_utils.h" #include "sys_param.h" -#include "param_manager.h" #define LABEL "Manager" -int InitWorkSpace(const char *fileName, WorkSpace *workSpace, int onlyRead) +static int InitWorkSpace_(WorkSpace *workSpace, int mode, int prot, uint32_t spaceSize, int readOnly) { - 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 != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid workSpace"); PARAM_CHECK(workSpace->allocTrieNode != NULL, - return PARAM_CODE_INVALID_PARAM, "Invalid param %s", workSpace->fileName); + return PARAM_CODE_INVALID_PARAM, "Invalid allocTrieNode %s", workSpace->fileName); PARAM_CHECK(workSpace->compareTrieNode != NULL, - return PARAM_CODE_INVALID_PARAM, "Invalid param %s", workSpace->fileName); + return PARAM_CODE_INVALID_PARAM, "Invalid compareTrieNode %s", workSpace->fileName); PARAM_LOGD("InitWorkSpace %s ", workSpace->fileName); CheckAndCreateDir(workSpace->fileName); - int fd = open(workSpace->fileName, mode, 00777); //0444); + int fd = open(workSpace->fileName, mode, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); PARAM_CHECK(fd >= 0, return PARAM_CODE_INVALID_NAME, - "Open file %s fail error %s", workSpace->fileName, strerror(errno)); + "Open file %s mode %x fail error %s", workSpace->fileName, mode, strerror(errno)); if (!readOnly) { - lseek(fd, spaceSize - 1, SEEK_SET); - write(fd, "", 1); + ftruncate(fd, spaceSize); } void *areaAddr = (void *)mmap(NULL, spaceSize, prot, MAP_SHARED, fd, 0); PARAM_CHECK(areaAddr != MAP_FAILED, close(fd); return PARAM_CODE_ERROR_MAP_FILE, @@ -99,164 +56,154 @@ int InitWorkSpace_(WorkSpace *workSpace, int mode, int prot, u_int32_t spaceSize 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 = (ParamTrieHeader *)areaAddr; + workSpace->area->trieNodeCount = 0; + workSpace->area->paramNodeCount = 0; + workSpace->area->securityNodeCount = 0; + workSpace->area->dataSize = spaceSize - sizeof(ParamTrieHeader); + workSpace->area->currOffset = 0; + uint32_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); + workSpace->area = (ParamTrieHeader *)areaAddr; } PARAM_LOGD("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) +static uint32_t AllocateParamTrieNode(WorkSpace *workSpace, const char *key, uint32_t keyLen) { - u_int32_t len = keyLen + sizeof(TrieNode) + 1; - len = (len + 0x03) & (~0x03); + uint32_t len = keyLen + sizeof(ParamTrieNode) + 1; + len = PARAM_ALIGN(len); 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)); + ParamTrieNode *node = (ParamTrieNode*)(workSpace->area->data + workSpace->area->currOffset); + node->length = keyLen; 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"); + PARAM_CHECK(ret == EOK, 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; + uint32_t offset = workSpace->area->currOffset; workSpace->area->currOffset += len; + workSpace->area->trieNodeCount++; return offset; } -TrieNode *GetTrieNode(WorkSpace *workSpace, NODE_INDEX *index) +static int CompareParamTrieNode(ParamTrieNode *node, const char *key, uint32_t keyLen) { - 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; + if (node->length > keyLen) { + return -1; + } else if (node->length < keyLen) { + return 1; } - return (TrieNode*)(workSpace->area->data + offset); + return strncmp(node->key, key, keyLen); } -u_int32_t GetTrieKeyLen(TrieNode *current) +int InitWorkSpace(const char *fileName, WorkSpace *workSpace, int onlyRead) { - return (current)->serial >> TRIE_SERIAL_KEY_LEN_OFFSET; + PARAM_CHECK(fileName != NULL, return PARAM_CODE_INVALID_NAME, "Invalid fileName"); + PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_NAME, "Invalid workSpace"); + if (workSpace->area != NULL) { + return 0; + } + workSpace->compareTrieNode = CompareParamTrieNode; + workSpace->allocTrieNode = AllocateParamTrieNode; + int ret = memcpy_s(workSpace->fileName, FILENAME_LEN_MAX, fileName, strlen(fileName)); + PARAM_CHECK(ret == EOK, 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; } -u_int32_t GetTrieNodeOffset(WorkSpace *workSpace, const TrieNode *current) +void CloseWorkSpace(WorkSpace *workSpace) { - return (((char *)current) - workSpace->area->data); + PARAM_CHECK(workSpace != NULL && workSpace->area != NULL, return, "The workspace is null"); + munmap((char *)workSpace->area, workSpace->area->dataSize); + workSpace->area = NULL; } -void SaveIndex(NODE_INDEX *index, u_int32_t offset) +static ParamTrieNode *GetTrieRoot(WorkSpace *workSpace) { - // atomic_store_explicit(¤t->children, new_offset, memory_order_release); - *index = offset; + return (ParamTrieNode *)(workSpace->area->data + workSpace->area->firstNode); } -int CompareTrieDataNode(TrieNode *node, const char *key, u_int32_t keyLen) +static void GetNextKey(const char **remainingKey, char **subKey, uint32_t *subKeyLen) { - TrieDataNode *data = (TrieDataNode *)node; - u_int32_t len = GetTrieKeyLen((TrieNode *)data); - if (len > keyLen) { - return -1; - } else if (len < keyLen) { - return 1; + *subKey = strchr(*remainingKey, '.'); + if (*subKey != NULL) { + *subKeyLen = *subKey - *remainingKey; + } else { + *subKeyLen = strlen(*remainingKey); } - return strncmp(data->key, key, keyLen); } -int CompareTrieNode(TrieNode *node, const char *key, u_int32_t keyLen) +static ParamTrieNode *AddToSubTrie(WorkSpace *workSpace, ParamTrieNode *current, const char *key, uint32_t keyLen) { - u_int32_t len = GetTrieKeyLen(node); - if (len > keyLen) { - return -1; - } else if (len < keyLen) { - return 1; + if (current == NULL) { + return NULL; } - return strncmp(node->key, key, keyLen); -} - -static void GetNextKey(const char **remainingKey, char **subKey, u_int32_t *subKeyLen) -{ - *subKey = strchr(*remainingKey, '.'); - if (*subKey != NULL) { - *subKeyLen = *subKey - *remainingKey; + ParamTrieNode *subTrie = NULL; + int ret = workSpace->compareTrieNode(current, key, keyLen); + if (ret == 0) { + return current; + } + if (ret < 0) { + subTrie = GetTrieNode(workSpace, current->left); + if (subTrie == NULL) { + uint32_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, current->left); + } } else { - *subKeyLen = strlen(*remainingKey); + subTrie = GetTrieNode(workSpace, current->right); + if (subTrie == NULL) { + uint32_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, current->right); + } } + return AddToSubTrie(workSpace, subTrie, key, keyLen); } -TrieDataNode *AddTrieDataNode(WorkSpace *workSpace, const char *key, u_int32_t keyLen) +ParamTrieNode *AddTrieNode(WorkSpace *workSpace, const char *key, uint32_t keyLen) { + PARAM_CHECK(key != NULL && keyLen > 0, return NULL, "Invalid param "); + PARAM_CHECK(workSpace != NULL, return NULL, "Invalid param %s", key); 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; + ParamTrieNode *current = GetTrieRoot(workSpace); PARAM_CHECK(current != NULL, return NULL, "Invalid current param %s", key); while (1) { - u_int32_t subKeyLen = 0; + uint32_t subKeyLen = 0; char *subKey = NULL; GetNextKey(&remainingKey, &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); - } + ParamTrieNode *next = GetTrieNode(workSpace, current->child); + current = AddToSubTrie(workSpace, next, remainingKey, subKeyLen); } else { - current = (TrieDataNode*)AddToSubTrie(workSpace, current, key, offset); + uint32_t dataOffset = workSpace->allocTrieNode(workSpace, remainingKey, subKeyLen); + PARAM_CHECK(dataOffset != 0, return NULL, "Failed to allocate key %s", key); + SaveIndex(¤t->child, dataOffset); + current = (ParamTrieNode *)GetTrieNode(workSpace, current->child); } if (current == NULL) { return NULL; @@ -269,265 +216,175 @@ TrieDataNode *AddTrieDataNode(WorkSpace *workSpace, const char *key, u_int32_t k return current; } -TrieDataNode *AddToSubTrie(WorkSpace *workSpace, TrieDataNode *dataNode, const char *key, u_int32_t keyLen) +static ParamTrieNode *FindSubTrie(WorkSpace *workSpace, + ParamTrieNode *current, const char *key, uint32_t keyLen, uint32_t *matchLabel) { - 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); - } + if (current == NULL) { + return NULL; } - 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; + ParamTrieNode *subTrie = NULL; + int ret = workSpace->compareTrieNode(current, key, keyLen); + if (ret == 0) { + if (matchLabel != NULL && current->labelIndex != 0) { // 有效前缀 + *matchLabel = current->labelIndex; } - int ret = workSpace->compareTrieNode(current, key, keyLen); - if (ret == 0) { - return current; + return current; + } + if (ret < 0) { + subTrie = (ParamTrieNode *)GetTrieNode(workSpace, current->left); + if (subTrie == NULL) { + return NULL; } - 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); - } + } else { + subTrie = (ParamTrieNode *)GetTrieNode(workSpace, current->right); + if (subTrie == NULL) { + return NULL; } - current = next; } - return current; + return FindSubTrie(workSpace, subTrie, key, keyLen, matchLabel); } -TrieDataNode *FindTrieDataNode(WorkSpace *workSpace, const char *key, u_int32_t keyLen, int matchPrefix) +ParamTrieNode *FindTrieNode(WorkSpace *workSpace, const char *key, uint32_t keyLen, uint32_t *matchLabel) { - PARAM_CHECK(workSpace->allocTrieNode != NULL, return NULL, "Invalid param %s", key); - PARAM_CHECK(workSpace->compareTrieNode != NULL, return NULL, "Invalid param %s", key); - + PARAM_CHECK(key != NULL && keyLen > 0, return NULL, "Invalid key "); + PARAM_CHECK(workSpace != NULL, return NULL, "Invalid workSpace %s", key); + PARAM_CHECK(workSpace->allocTrieNode != NULL, return NULL, "Invalid alloc function %s", key); + PARAM_CHECK(workSpace->compareTrieNode != NULL, return NULL, "Invalid compare function %s", key); const char *remainingKey = key; - TrieDataNode *matchNode = (TrieDataNode *)workSpace->rootNode; - TrieDataNode *current = (TrieDataNode *)workSpace->rootNode; + ParamTrieNode *current = GetTrieRoot(workSpace); PARAM_CHECK(current != NULL, return NULL, "Invalid current param %s", key); + if (matchLabel != NULL) { + *matchLabel = current->labelIndex; + } + int ret = workSpace->compareTrieNode(current, key, keyLen); + if (ret == 0) { + return current; + } while (1) { - u_int32_t subKeyLen = 0; + uint32_t subKeyLen = 0; char *subKey = NULL; GetNextKey(&remainingKey, &subKey, &subKeyLen); if (!subKeyLen) { - return matchPrefix ? matchNode : NULL; + 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*)FindSubTrie(workSpace, current, key, offset); - } + if (current->child != 0) { + ParamTrieNode *next = GetTrieNode(workSpace, current->child); + current = FindSubTrie(workSpace, next, remainingKey, subKeyLen, matchLabel); } else { - current = (TrieDataNode*)FindSubTrie(workSpace, current, key, offset); + current = FindSubTrie(workSpace, current, remainingKey, subKeyLen, matchLabel); } if (current == NULL) { - return matchPrefix ? matchNode : NULL; + return NULL; + } else if (matchLabel != NULL && current->labelIndex != 0) { + *matchLabel = current->labelIndex; } - 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); + return current; } -TrieNode *FindTrieNode(WorkSpace *workSpace, TrieNode *root, const char *key, u_int32_t keyLen) +static int TraversalSubTrieNode(WorkSpace *workSpace, + ParamTrieNode *current, TraversalTrieNodePtr walkFunc, void *cookie) { - 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; + if (current == NULL) { + return 0; } - return current; + walkFunc(workSpace, (ParamTrieNode *)current, cookie); + TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->child), walkFunc, cookie); + TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->left), walkFunc, cookie); + TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->right), walkFunc, cookie); + return 0; } -int TraversalTrieDataNode(WorkSpace *workSpace, TrieDataNode *current, TraversalTrieNodePtr walkFunc, void* cookie) +int TraversalTrieNode(WorkSpace *workSpace, ParamTrieNode *root, 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"); + ParamTrieNode *current = root; + if (root == NULL) { + current = GetTrieRoot(workSpace); + } 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; + walkFunc(workSpace, (ParamTrieNode *)current, cookie); + TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->child), walkFunc, cookie); + if (root == NULL) { + TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->left), walkFunc, cookie); + TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->right), walkFunc, cookie); } return 0; } -int TraversalTrieNode(WorkSpace *workSpace, TrieNode *root, TraversalTrieNodePtr walkFunc, void* cookie) +uint32_t AddParamSecruityNode(WorkSpace *workSpace, const ParamAuditData *auditData) { - 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; + PARAM_CHECK(workSpace != NULL, return 0, "Invalid param"); + PARAM_CHECK(auditData != NULL && auditData->name != NULL, return 0, "Invalid auditData"); + uint32_t labelLen = ((auditData->label == NULL) || (strlen(auditData->label) == 0)) ? 0 : strlen(auditData->label); + uint32_t realLen = sizeof(ParamSecruityNode) + PARAM_ALIGN(labelLen + 1); + PARAM_CHECK((workSpace->area->currOffset + realLen) < workSpace->area->dataSize, return 0, + "Failed to allocate currOffset %u, dataSize %u datalen %u", + workSpace->area->currOffset, workSpace->area->dataSize, realLen); + + ParamSecruityNode *node = (ParamSecruityNode *)(workSpace->area->data + workSpace->area->currOffset); + node->uid = auditData->dacData.uid; + node->gid = auditData->dacData.gid; + node->mode = auditData->dacData.mode; + node->length = 0; + if (labelLen != 0) { + int ret = memcpy_s(node->data, labelLen, auditData->label, labelLen); + PARAM_CHECK(ret == EOK, return 0, "Failed to copy key"); + node->data[labelLen] = '\0'; + node->length = labelLen; } - TraversalTrieNode(workSpace, GetTrieNode(workSpace, &root->left), walkFunc, cookie); - TraversalTrieNode(workSpace, GetTrieNode(workSpace, &root->right), walkFunc, cookie); - walkFunc(workSpace, (TrieNode *)root, cookie); - return 0; + uint32_t offset = workSpace->area->currOffset; + workSpace->area->currOffset += realLen; + workSpace->area->securityNodeCount++; + return offset; } -u_int32_t AddData(WorkSpace *workSpace, const char *key, u_int32_t keyLen, const char *value, u_int32_t valueLen) +uint32_t AddParamNode(WorkSpace *workSpace, const char *key, uint32_t keyLen, const char *value, uint32_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; + + uint32_t realLen = sizeof(ParamNode) + 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); + realLen = PARAM_ALIGN(realLen); PARAM_CHECK((workSpace->area->currOffset + realLen) < workSpace->area->dataSize, return 0, - "Failed to allocate currOffset %d, dataSize %d", workSpace->area->currOffset, workSpace->area->dataSize); + "Failed to allocate currOffset %u, dataSize %u datalen %u", + workSpace->area->currOffset, workSpace->area->dataSize, realLen); + + ParamNode *node = (ParamNode *)(workSpace->area->data + workSpace->area->currOffset); + atomic_init(&node->commitId, 0); - 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); - PARAM_CHECK(ret == 0, return 0, "Failed to copy key"); - 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; + node->keyLength = keyLen; + node->valueLength = valueLen; + int ret = sprintf_s(node->data, realLen - 1, "%s=%s", key, value); + PARAM_CHECK(ret > EOK, return 0, "Failed to sprint key and value"); + uint32_t offset = workSpace->area->currOffset; workSpace->area->currOffset += realLen; - //PARAM_LOGI("AddData node %p %u %d", node, offset, gettid()); + workSpace->area->paramNodeCount++; 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_LOGD("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) +ParamTrieNode *GetTrieNode(WorkSpace *workSpace, uint32_t offset) { - 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); + if (offset == 0 || offset > workSpace->area->dataSize) { + return NULL; } - return serial; + return (ParamTrieNode *)(workSpace->area->data + offset); } -int GetDataName(const DataEntry *entry, char *name, u_int32_t len) +void SaveIndex(uint32_t *index, uint32_t offset) { - 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; + *index = offset; } diff --git a/services/param/manager/param_utils.c b/services/param/manager/param_utils.c new file mode 100755 index 0000000000000000000000000000000000000000..7b1070cc610b3b16ea30dcc6b37f539e50667aa7 --- /dev/null +++ b/services/param/manager/param_utils.c @@ -0,0 +1,161 @@ +/* + * 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_utils.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LABEL "PARAM_UTILS" +void CheckAndCreateDir(const char *fileName) +{ + if (fileName == NULL || *fileName == '\0') { + return; + } + 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); +} + +int ReadFileInDir(const char *dirPath, const char *includeExt, + int (*processFile)(const char *fileName, void *context), void *context) +{ + DIR *pDir = opendir(dirPath); + PARAM_CHECK(pDir != NULL, return -1, "Read dir :%s failed.%d", dirPath, errno); + char *fileName = malloc(PARAM_BUFFER_SIZE); + PARAM_CHECK(fileName != NULL, closedir(pDir); + return -1, "Failed to malloc for %s", dirPath); + + struct dirent *dp; + while ((dp = readdir(pDir)) != NULL) { + if (dp->d_type == DT_DIR) { + continue; + } + PARAM_LOGD("ReadFileInDir %s", dp->d_name); + if (includeExt != NULL) { + char *tmp = strstr(dp->d_name, includeExt); + if (tmp == NULL) { + continue; + } + if (strcmp(tmp, includeExt) != 0) { + continue; + } + } + int ret = snprintf_s(fileName, PARAM_BUFFER_SIZE, PARAM_BUFFER_SIZE - 1, "%s/%s", dirPath, dp->d_name); + PARAM_CHECK(ret > EOK, continue, "Failed to get file name for %s", dp->d_name); + struct stat st; + if (stat(fileName, &st) == 0) { + processFile(fileName, context); + } + } + free(fileName); + closedir(pDir); + return 0; +} + +char *ReadFileData(const char *fileName) +{ + if (fileName == NULL) { + return NULL; + } + char *buffer = NULL; + int fd = -1; + do { + fd = open(fileName, O_RDONLY); + PARAM_CHECK(fd >= 0, break, "Failed to read file %s", fileName); + + buffer = (char *)malloc(MAX_DATA_BUFFER); + PARAM_CHECK(buffer != NULL, break, "Failed to allocate memory for %s", fileName); + ssize_t readLen = read(fd, buffer, MAX_DATA_BUFFER - 1); + PARAM_CHECK(readLen > 0, break, "Failed to read data for %s", fileName); + buffer[readLen] = '\0'; + } while (0); + if (fd != -1) { + close(fd); + } + return buffer; +} + +static void TrimString(char *string, uint32_t currLen) +{ + for (int i = currLen - 1; i >= 0; i--) { + if (string[i] == ' ' || string[i] == '\0') { + string[i] = '\0'; + } else { + break; + } + } +} + +int GetSubStringInfo(const char *buff, uint32_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' || buff[i] == '\0') { + break; + } + if (buff[i] == delimiter && valueCurr != 0) { + info[curr].value[valueCurr] = '\0'; + TrimString(info[curr].value, valueCurr); + valueCurr = 0; + curr++; + spaceIsValid = 0; + } else { + if (!spaceIsValid && isspace(buff[i])) { // 过滤开始前的无效字符 + continue; + } + spaceIsValid = 1; + 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'; + TrimString(info[curr].value, valueCurr); + valueCurr = 0; + curr++; + } + return curr; +} \ No newline at end of file diff --git a/services/param/service/param_persist.c b/services/param/service/param_persist.c index 7086357cb867e02c8d53a4c0bc132bb6f826aca9..09df4be2ae8a056ba962d43606728ece15112821 100644 --- a/services/param/service/param_persist.c +++ b/services/param/service/param_persist.c @@ -12,145 +12,167 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "sys_param.h" -#include +#include "param_persist.h" #include #include -#include -#include -#include -#include -#include -#include -#include +#include #include #include "param_manager.h" +#include "param_service.h" #include "param_trie.h" +#include "sys_param.h" #define LABEL "Manager" -#define MAX_BUFF 256 -typedef struct { - WorkSpace *workSpace; - WorkSpace *persistWorkSpace; - char *buffer; -} PersistContext; +static ParamPersistWorkSpace g_persistWorkSpace = { 0, NULL, 0, { NULL, NULL, NULL, NULL, NULL } }; -static ParamPersistWorkSpace g_persistWorkSpace = {ATOMIC_VAR_INIT(0), }; +static int AddPersistParam(const char *name, const char *value, void *context) +{ + PARAM_CHECK(value != NULL && name != NULL && context != NULL, + return PARAM_CODE_INVALID_PARAM, "Invalid name or context"); + WorkSpace *workSpace = (WorkSpace *)context; + uint32_t dataIndex = 0; + int ret = WriteParam(workSpace, name, value, &dataIndex, 0); + PARAM_CHECK(ret == 0, return ret, "Failed to write param %d name:%s %s", ret, name, value); + return 0; +} -static int ProcessParamTraversal(WorkSpace *workSpace, TrieNode *node, void *cookie) +static int SavePersistParam(WorkSpace *workSpace, ParamTrieNode *node, void *cookie) { - PARAM_CHECK(workSpace != 0 && node != NULL && cookie != NULL, return -1, "Invalid param"); - TrieDataNode *current = (TrieDataNode *)node; + ParamTrieNode *current = (ParamTrieNode *)node; if (current == NULL || current->dataIndex == 0) { return 0; } - DataEntry *entry = (DataEntry *)GetTrieNode(workSpace, ¤t->dataIndex); + ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, current->dataIndex); if (entry == NULL) { - return -1; - } - PersistContext *persistContext = (PersistContext *)cookie; - int ret = GetDataName(entry, persistContext->buffer, MAX_BUFF); - PARAM_CHECK(ret == 0, return ret, "GetDataName failed"); - 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_LOGD("SavePersistParam %s", entry->data); + if (strncmp(entry->data, PARAM_CONST_PREFIX, strlen(PARAM_CONST_PREFIX)) != 0) { + return 0; } - PARAM_CHECK(ret == 0, return ret, "Failed to add persist param"); + static char name[PARAM_NAME_LEN_MAX] = { 0 }; + int ret = memcpy_s(name, PARAM_NAME_LEN_MAX - 1, entry->data, entry->keyLength); + PARAM_CHECK(ret == EOK, return -1, "Failed to read param name %s", entry->data); + name[entry->keyLength] = '\0'; + ret = g_persistWorkSpace.persistParamOps.batchSave(cookie, name, entry->data + entry->keyLength + 1); + PARAM_CHECK(ret == 0, return -1, "Failed to write param %s", current->key); return ret; } -static int ProcessPersistPropertTraversal(WorkSpace *workSpace, TrieNode *node, void *cookie) +static int BatchSavePersistParam(WorkSpace *workSpace) { - TrieDataNode *current = (TrieDataNode *)node; - if (current == NULL || current->dataIndex == 0) { + PARAM_LOGI("BatchSavePersistParam"); + if (g_persistWorkSpace.persistParamOps.batchSaveBegin == NULL || + g_persistWorkSpace.persistParamOps.batchSave == NULL || + g_persistWorkSpace.persistParamOps.batchSaveEnd == NULL) { 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); - PARAM_CHECK(ret == 0, return ret, "GetDataName failed"); - 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"); + + PERSIST_SAVE_HANDLE handle; + int ret = g_persistWorkSpace.persistParamOps.batchSaveBegin(&handle); + PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_NAME, "Failed to save persist"); + ParamTrieNode *root = FindTrieNode(workSpace, PARAM_CONST_PREFIX, strlen(PARAM_CONST_PREFIX), NULL); + ret = TraversalTrieNode(workSpace, root, SavePersistParam, handle); + g_persistWorkSpace.persistParamOps.batchSaveEnd(handle); + PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_NAME, "Save persist param fail"); + + PARAM_CLEAR_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_UPDATE); + (void)time(&g_persistWorkSpace.lastSaveTimer); return ret; } -int InitPersistParamWorkSpace(const char *context) +int InitPersistParamWorkSpace(ParamWorkSpace *workSpace) { - u_int32_t flags = atomic_load_explicit(&g_persistWorkSpace.flags, memory_order_relaxed); - if ((flags & WORKSPACE_FLAGS_INIT) == WORKSPACE_FLAGS_INIT) { + if (PARAM_TEST_FLAG(g_persistWorkSpace.flags, 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; + (void)time(&g_persistWorkSpace.lastSaveTimer); +#ifdef PARAM_SUPPORT_SAVE_PERSIST + RegisterPersistParamOps(&g_persistWorkSpace.persistParamOps); +#endif + PARAM_SET_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_INIT); + return 0; +} + +void ClosePersistParamWorkSpace(void) +{ + if (g_persistWorkSpace.saveTimer != NULL) { + ParamTaskClose(g_persistWorkSpace.saveTimer); + } + g_persistWorkSpace.flags = 0; } -int RefreshPersistParams(ParamWorkSpace *workSpace, const char *context) +int LoadPersistParam(ParamWorkSpace *workSpace) { - int ret = InitPersistParamWorkSpace(context); + int ret = InitPersistParamWorkSpace(workSpace); 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"); + if (PARAM_TEST_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_LOADED)) { + PARAM_LOGE("Persist param 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; + ret = -1; + if (g_persistWorkSpace.persistParamOps.load != NULL) { + ret = g_persistWorkSpace.persistParamOps.load(AddPersistParam, &workSpace->paramSpace); + } + if (ret == 0) { + PARAM_SET_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_LOADED); + } else { + PARAM_LOGE("Failed to load persist param "); + } + // 刷新新增的常量到persist + BatchSavePersistParam(&workSpace->paramSpace); + return 0; } -void ClosePersistParamWorkSpace() +static void TimerCallbackForSave(ParamTaskPtr timer, void *context) { - CloseWorkSpace(&g_persistWorkSpace.persistWorkSpace); - atomic_store_explicit(&g_persistWorkSpace.flags, 0, memory_order_release); + UNUSED(context); + ParamTaskClose(timer); + g_persistWorkSpace.saveTimer = NULL; + if (!PARAM_TEST_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_UPDATE)) { + return; + } + BatchSavePersistParam((WorkSpace *)context); } -int WritePersistParam(const char *name, const char *value) +int WritePersistParam(ParamWorkSpace *workSpace, 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) { + if (strncmp(name, PARAM_CONST_PREFIX, strlen(PARAM_CONST_PREFIX)) != 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) { + if (!PARAM_TEST_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_LOADED)) { + PARAM_LOGE("Can not save persist param before load %s ", name); return 0; } - return WriteParam(&g_persistWorkSpace.persistWorkSpace, name, value); + PARAM_LOGD("WritePersistParam name %s ", name); + if (g_persistWorkSpace.persistParamOps.save != NULL) { + g_persistWorkSpace.persistParamOps.save(name, value); + } + + // 不需要批量保存 + if (g_persistWorkSpace.persistParamOps.batchSave == NULL) { + return 0; + } + + // check timer for save all + time_t currTimer; + (void)time(&currTimer); + uint32_t diff = (uint32_t)difftime(currTimer, g_persistWorkSpace.lastSaveTimer); + if (diff > PARAM_MUST_SAVE_PARAM_DIFF) { + if (g_persistWorkSpace.saveTimer != NULL) { + ParamTaskClose(g_persistWorkSpace.saveTimer); + g_persistWorkSpace.saveTimer = NULL; + } + return BatchSavePersistParam(&workSpace->paramSpace); + } + PARAM_SET_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_UPDATE); + if (g_persistWorkSpace.saveTimer == NULL) { + ParamTimerCreate(&g_persistWorkSpace.saveTimer, TimerCallbackForSave, &workSpace->paramSpace); + ParamTimerStart(g_persistWorkSpace.saveTimer, PARAM_MUST_SAVE_PARAM_DIFF * MS_UNIT, MS_UNIT); + } + return 0; } diff --git a/services/param/service/param_service.c b/services/param/service/param_service.c index 58d6c8c3ed04908d9e16af932b6595b00a720734..e17b43d0381b4682bf2e4a36f20f214b974afdd5 100644 --- a/services/param/service/param_service.c +++ b/services/param/service/param_service.c @@ -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, @@ -14,266 +14,698 @@ */ #include "param_service.h" - +#include +#include +#include #include #include #include +#include +#include +#include #include -#include "sys_param.h" +#include "init_param.h" +#include "param_message.h" #include "param_manager.h" #include "param_request.h" -#include "init_param.h" +#include "trigger_manager.h" -#include "uv.h" +#define LABEL "ParamServer" +static ParamWorkSpace g_paramWorkSpace = { 0, {}, NULL, {}, NULL, NULL }; -#define BUFFER_SIZE 256 -#define LABEL "Server" +static void OnClose(ParamTaskPtr client) +{ + ParamWatcher *watcher = (ParamWatcher *)ParamGetTaskUserData(client); + if (watcher == GetParamWatcher(NULL)) { + return; + } + ClearWatcherTrigger(watcher); + ListRemove(&watcher->node); +} -static char *g_initContext = ""; -static ParamWorkSpace g_paramWorkSpace = {ATOMIC_VAR_INIT(0), {}, {}, {}}; +static int AddParam(WorkSpace *workSpace, const char *name, const char *value, uint32_t *dataIndex) +{ + ParamTrieNode *node = AddTrieNode(workSpace, name, strlen(name)); + PARAM_CHECK(node != NULL, return PARAM_CODE_REACHED_MAX, "Failed to add node"); + ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, node->dataIndex); + if (entry == NULL) { + uint32_t offset = AddParamNode(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); + } + *dataIndex = node->dataIndex; + return 0; +} -void InitParamService() +static int UpdateParam(WorkSpace *workSpace, uint32_t *dataIndex, const char *name, const char *value) { - int ret = InitParamWorkSpace(&g_paramWorkSpace, 0, g_initContext); - PARAM_CHECK(ret == 0, return, "Init parameter workspace fail"); + ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, *dataIndex); + PARAM_CHECK(entry != NULL, return PARAM_CODE_REACHED_MAX, "Failed to update param value %s %u", name, *dataIndex); + PARAM_CHECK(entry->keyLength == strlen(name), return PARAM_CODE_INVALID_NAME, "Failed to check name len %s", name); + + uint32_t valueLen = strlen(value); + uint32_t commitId = atomic_load_explicit(&entry->commitId, memory_order_relaxed); + atomic_store_explicit(&entry->commitId, commitId | PARAM_FLAGS_MODIFY, memory_order_relaxed); + + if (entry->valueLength < PARAM_VALUE_LEN_MAX && valueLen < PARAM_VALUE_LEN_MAX) { + int ret = memcpy_s(entry->data + entry->keyLength + 1, PARAM_VALUE_LEN_MAX, value, valueLen + 1); + PARAM_CHECK(ret == EOK, return PARAM_CODE_INVALID_VALUE, "Failed to copy value"); + entry->valueLength = valueLen; + } + uint32_t flags = commitId & ~PARAM_FLAGS_COMMITID; + atomic_store_explicit(&entry->commitId, (++commitId) | flags, memory_order_release); + futex_wake(&entry->commitId, INT_MAX); + return 0; } -int LoadDefaultParams(const char *fileName) +static int CheckParamValue(WorkSpace *workSpace, const ParamTrieNode *node, const char *name, const char *value) { - 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; + if (IS_READY_ONLY(name)) { + PARAM_CHECK(strlen(value) < PARAM_CONST_VALUE_LEN_MAX, + return PARAM_CODE_INVALID_VALUE, "Illegal param value %s", value); + if (node != NULL && node->dataIndex != 0) { + PARAM_LOGE("Read-only param was already set %s", name); + return PARAM_CODE_READ_ONLY; + } + } else { + // 限制非read only的参数,防止参数值修改后,原空间不能保存 + PARAM_CHECK(strlen(value) < PARAM_VALUE_LEN_MAX, + return PARAM_CODE_INVALID_VALUE, "Illegal param value %s", value); } - 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)); - PARAM_CHECK(info != NULL, return -1, "malloc failed"); + return 0; +} - while(fgets(buff, BUFFER_SIZE, fp) != NULL) { - int subStrNumber = GetSubStringInfo(buff, strlen(buff), '=', info, SUBSTR_INFO_LABEL + 1); - if (subStrNumber <= SUBSTR_INFO_LABEL) { - continue; +int WriteParam(WorkSpace *workSpace, const char *name, const char *value, uint32_t *dataIndex, int onlyAdd) +{ + PARAM_CHECK(workSpace != NULL && dataIndex != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid workSpace"); + PARAM_CHECK(value != NULL && name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid name or value"); + ParamTrieNode *node = FindTrieNode(workSpace, name, strlen(name), NULL); + int ret = CheckParamValue(workSpace, node, name, value); + PARAM_CHECK(ret == 0, return ret, "Invalid param value param: %s=%s", name, value); + if (node != NULL && node->dataIndex != 0) { + *dataIndex = node->dataIndex; + if (onlyAdd) { + return 0; } + return UpdateParam(workSpace, &node->dataIndex, name, value); + } + return AddParam(workSpace, name, value, dataIndex); +} - if (strncmp(info[0].value, "ctl.", strlen("ctl.")) == 0) { - PARAM_LOGE("Do not set ctl. parameters from init %s", info[0].value); - continue; +PARAM_STATIC int AddSecurityLabel(const ParamAuditData *auditData, void *context) +{ + PARAM_CHECK(auditData != NULL && auditData->name != NULL, return -1, "Invalid auditData"); + PARAM_CHECK(context != NULL, return -1, "Invalid context"); + ParamWorkSpace *workSpace = (ParamWorkSpace *)context; + int ret = CheckParamName(auditData->name, 1); + PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", auditData->name); + + ParamTrieNode *node = FindTrieNode(&workSpace->paramSpace, auditData->name, strlen(auditData->name), NULL); + if (node == NULL) { + node = AddTrieNode(&workSpace->paramSpace, auditData->name, strlen(auditData->name)); + } + PARAM_CHECK(node != NULL, return PARAM_CODE_REACHED_MAX, "Failed to add node %s", auditData->name); + if (node->labelIndex == 0) { // can not support update for label + uint32_t offset = AddParamSecruityNode(&workSpace->paramSpace, auditData); + PARAM_CHECK(offset != 0, return PARAM_CODE_REACHED_MAX, "Failed to add label"); + SaveIndex(&node->labelIndex, offset); + } else { +#ifdef STARTUP_INIT_TEST + ParamSecruityNode *label = (ParamSecruityNode *)GetTrieNode(&workSpace->paramSpace, node->labelIndex); + label->mode = auditData->dacData.mode; +#endif + PARAM_LOGE("Error, repeate to add label for name %s", auditData->name); + } + PARAM_LOGD("AddSecurityLabel label uid %d gid %d mode %o name: %s", auditData->dacData.gid, auditData->dacData.gid, + auditData->dacData.mode, auditData->name); + return 0; +} + +static char *GetServiceCtrlName(const char *name, const char *value) +{ + static char *ctrlParam[] = { + "ohos.ctl.start", + "ohos.ctl.stop" + }; + static char *powerCtrlArg[][2] = { + {"reboot,shutdown", "reboot.shutdown"}, + {"reboot,updater", "reboot.updater"}, + {"reboot,flash", "reboot.flash"}, + {"reboot", "reboot"}, + }; + char *key = NULL; + if (strcmp("sys.powerctrl", name) == 0) { + for (size_t i = 0; i < sizeof(powerCtrlArg) / sizeof(powerCtrlArg[0]); i++) { + if (strncmp(value, powerCtrlArg[i][0], strlen(powerCtrlArg[i][0])) == 0) { + uint32_t keySize = strlen(powerCtrlArg[i][1]) + strlen(OHOS_SERVICE_CTRL_PREFIX) + 1; + key = (char *)malloc(keySize + 1); + PARAM_CHECK(key != NULL, return NULL, "Failed to alloc memory for %s", name); + int ret = sprintf_s(key, keySize, "%s%s", OHOS_SERVICE_CTRL_PREFIX, powerCtrlArg[i][1]); + PARAM_CHECK(ret > EOK, return NULL, "Failed to format key for %s", name); + return key; + } } - if (strcmp(info[0].value, "selinux.restorecon_recursive") == 0) { - PARAM_LOGE("Do not set selinux.restorecon_recursive from init %s", info[0].value); - continue; + } else { + for (size_t i = 0; i < sizeof(ctrlParam) / sizeof(ctrlParam[0]); i++) { + if (strcmp(name, ctrlParam[i]) == 0) { + uint32_t keySize = strlen(value) + strlen(OHOS_SERVICE_CTRL_PREFIX) + 1; + key = (char *)malloc(keySize + 1); + PARAM_CHECK(key != NULL, return NULL, "Failed to alloc memory for %s", name); + int ret = sprintf_s(key, keySize, "%s%s", OHOS_SERVICE_CTRL_PREFIX, value); + PARAM_CHECK(ret > EOK, return NULL, "Failed to format key for %s", name); + return key; + } } - int ret = CheckParamName(info[0].value, 0); - PARAM_CHECK(ret == 0, continue, "Illegal param name %s", info[0].value); + } + return key; +} - ret = WriteParam(&g_paramWorkSpace.paramSpace, info[0].value, info[1].value); - PARAM_CHECK(ret == 0, continue, "Failed to set param %d %s", ret, buff); +static void CheckAndSendTrigger(ParamWorkSpace *workSpace, uint32_t dataIndex, const char *name, const char *value) +{ + ParamNode *entry = (ParamNode *)GetTrieNode(&workSpace->paramSpace, dataIndex); + PARAM_CHECK(entry != NULL, return, "Failed to get data %s ", name); + uint32_t trigger = 1; + if ((atomic_load_explicit(&entry->commitId, memory_order_relaxed) & PARAM_FLAGS_TRIGGED) != PARAM_FLAGS_TRIGGED) { + trigger = CheckAndMarkTrigger(TRIGGER_PARAM, name) != 0 ? 1 : 0; } - fclose(fp); - free(info); - PARAM_LOGI("LoadDefaultParams proterty success %s", fileName); - return 0; + if (trigger) { + atomic_store_explicit(&entry->commitId, + atomic_load_explicit(&entry->commitId, memory_order_relaxed) | PARAM_FLAGS_TRIGGED, memory_order_release); + // notify event to process trigger + PostParamTrigger(EVENT_TRIGGER_PARAM, name, value); + } + + int wait = 1; + if ((atomic_load_explicit(&entry->commitId, memory_order_relaxed) & PARAM_FLAGS_WAITED) != PARAM_FLAGS_WAITED) { + wait = CheckAndMarkTrigger(TRIGGER_PARAM_WAIT, name) != 0 ? 1 : 0; + } + if (wait) { + atomic_store_explicit(&entry->commitId, + atomic_load_explicit(&entry->commitId, memory_order_relaxed) | PARAM_FLAGS_WAITED, memory_order_release); + PostParamTrigger(EVENT_TRIGGER_PARAM_WAIT, name, value); + } + PostParamTrigger(EVENT_TRIGGER_PARAM_WATCH, name, value); } -int LoadParamInfos(const char *fileName) +static int SystemSetParam(const char *name, const char *value, const ParamSecurityLabel *srcLabel) { - 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; + PARAM_LOGD("SystemSetParam name %s value: %s", name, value); + int ret = CheckParamName(name, 0); + PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", name); + + int serviceCtrl = 0; + char *key = GetServiceCtrlName(name, value); + if (srcLabel != NULL) { + ret = CheckParamPermission(&g_paramWorkSpace, srcLabel, (key == NULL) ? name : key, DAC_WRITE); + PARAM_CHECK(ret == 0, return ret, "Forbit to set parameter %s", name); } - FILE *fp = fopen(fileName, "r"); - PARAM_CHECK(fp != NULL, return -1, "Open file %s fail", fileName); - SubStringInfo *info = malloc(sizeof(SubStringInfo) * SUBSTR_INFO_MAX); - PARAM_CHECK(info != NULL, return -1, "Load parameter malloc failed."); - 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++; + if (key != NULL) { + serviceCtrl = 1; + free(key); } - fclose(fp); - free(info); - PARAM_LOGI("Load parameter info %d success %s", infoCount, fileName); - return 0; + uint32_t dataIndex = 0; + ret = WriteParam(&g_paramWorkSpace.paramSpace, name, value, &dataIndex, 0); + PARAM_CHECK(ret == 0, return ret, "Failed to set param %d name %s %s", ret, name, value); + ret = WritePersistParam(&g_paramWorkSpace, name, value); + PARAM_CHECK(ret == 0, return ret, "Failed to set persist param name %s", name); + if (serviceCtrl) { + PostParamTrigger(EVENT_TRIGGER_PARAM, name, value); + } else { + CheckAndSendTrigger(&g_paramWorkSpace, dataIndex, name, value); + } + return ret; } -static int ProcessParamSet(RequestMsg *msg) +static int SendResponseMsg(ParamTaskPtr worker, const ParamMessage *msg, int result) { - PARAM_CHECK(msg != NULL, return PARAM_CODE_INVALID_PARAM, "Failed to check param"); + ParamResponseMessage *response = NULL; + response = (ParamResponseMessage *)CreateParamMessage(msg->type, msg->key, sizeof(ParamResponseMessage)); + PARAM_CHECK(response != NULL, return PARAM_CODE_ERROR, "Failed to alloc memory for response"); + response->msg.id.msgId = msg->id.msgId; + response->result = result; + response->msg.msgSize = sizeof(ParamResponseMessage); + ParamTaskSendMsg(worker, (ParamMessage *)response); + return 0; +} - 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); +static int SendWatcherNotifyMessage(TriggerExtData *extData, int cmd, const char *content) +{ + UNUSED(cmd); + PARAM_CHECK(content != NULL, return -1, "Invalid content"); + PARAM_CHECK(extData != NULL && extData->watcher != NULL, return -1, "Invalid extData"); + uint32_t msgSize = sizeof(ParamMessage) + PARAM_ALIGN(strlen(content) + 1); + ParamMessage *msg = (ParamMessage *)CreateParamMessage(MSG_NOTIFY_PARAM, "*", msgSize); + PARAM_CHECK(msg != NULL, return -1, "Failed to create msg "); + + uint32_t offset = 0; + int ret = 0; + char *tmp = strstr(content, "="); + if (tmp != NULL) { + ret = strncpy_s(msg->key, sizeof(msg->key) - 1, content, tmp - content); + PARAM_CHECK(ret == 0, free(msg); + return -1, "Failed to fill value"); + tmp++; + ret = FillParamMsgContent(msg, &offset, PARAM_VALUE, tmp, strlen(tmp)); + PARAM_CHECK(ret == 0, free(msg); + return -1, "Failed to fill value"); + } else { + ret = FillParamMsgContent(msg, &offset, PARAM_VALUE, tmp, strlen(content)); + PARAM_CHECK(ret == 0, free(msg); + return -1, "Failed to fill value"); + } - PARAM_LOGD("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); + msg->id.msgId = extData->watcherId; + msg->msgSize = sizeof(ParamMessage) + offset; + PARAM_LOGD("SendWatcherNotifyMessage watcherId %d msgSize %d para: %s", extData->watcherId, msg->msgSize, content); + ParamTaskSendMsg(extData->watcher->stream, msg); return 0; } -static void OnClose(uv_handle_t *handle) +static int HandleParamSet(const ParamTaskPtr worker, const ParamMessage *msg) { - free(handle); + uint32_t offset = 0; + ParamMsgContent *valueContent = GetNextContent(msg, &offset); + PARAM_CHECK(valueContent != NULL, return -1, "Invalid msg for %s", msg->key); + int ret = 0; + ParamMsgContent *lableContent = GetNextContent(msg, &offset); + ParamSecurityLabel *srcLabel = NULL; + if (lableContent != NULL && lableContent->contentSize != 0) { + PARAM_CHECK(g_paramWorkSpace.paramSecurityOps.securityDecodeLabel != NULL, + return -1, "Can not get decode function"); + ret = g_paramWorkSpace.paramSecurityOps.securityDecodeLabel(&srcLabel, + lableContent->content, lableContent->contentSize); + PARAM_CHECK(ret == 0, return ret, + "Failed to decode param %d name %s %s", ret, msg->key, valueContent->content); + } + + ret = SystemSetParam(msg->key, valueContent->content, srcLabel); + if (srcLabel != NULL && g_paramWorkSpace.paramSecurityOps.securityFreeLabel != NULL) { + g_paramWorkSpace.paramSecurityOps.securityFreeLabel(srcLabel); + } + return SendResponseMsg(worker, msg, ret); } -static void OnReceiveAlloc(uv_handle_t *handle, size_t suggestedSize, uv_buf_t* buf) +static ParamNode *CheckMatchParamWait(ParamWorkSpace *worksapce, const char *name, const char *value) { - // 这里需要按实际消息的大小申请内存,取最大消息的长度 - buf->len = sizeof(RequestMsg) + BUFFER_SIZE * 2; - buf->base = (char *)malloc(buf->len); + uint32_t nameLength = strlen(name); + ParamTrieNode *node = FindTrieNode(&worksapce->paramSpace, name, nameLength, NULL); + if (node == NULL || node->dataIndex == 0) { + return NULL; + } + ParamNode *param = (ParamNode *)GetTrieNode(&worksapce->paramSpace, node->dataIndex); + if (param == NULL) { + return NULL; + } + if ((param->keyLength != nameLength) || (strncmp(param->data, name, nameLength) != 0)) { // compare name + return NULL; + } + atomic_store_explicit(¶m->commitId, + atomic_load_explicit(¶m->commitId, memory_order_relaxed) | PARAM_FLAGS_WAITED, memory_order_release); + if ((strncmp(value, "*", 1) == 0) || (strcmp(param->data + nameLength + 1, value) == 0)) { // compare value + return param; + } + char *tmp = strstr(value, "*"); + if (tmp != NULL && (strncmp(param->data + nameLength + 1, value, tmp - value) == 0)) { + return param; + } + return NULL; } -static void OnWriteResponse(uv_write_t *req, int status) +static int HandleParamWaitAdd(ParamWorkSpace *worksapce, const ParamTaskPtr worker, const ParamMessage *msg) { - // 发送成功,释放请求内存 - PARAM_LOGD("OnWriteResponse status %d", status); - ResponseNode *node = (ResponseNode*)req; - free(node); + PARAM_CHECK(msg != NULL, return -1, "Invalid message"); + uint32_t offset = 0; + uint32_t timeout = DEFAULT_PARAM_WAIT_TIMEOUT; + ParamMsgContent *valueContent = GetNextContent(msg, &offset); + PARAM_CHECK(valueContent != NULL, return -1, "Invalid msg"); + ParamMsgContent *timeoutContent = GetNextContent(msg, &offset); + if (timeoutContent != NULL) { + timeout = *((uint32_t *)(timeoutContent->content)); + } + + PARAM_LOGD("HandleParamWaitAdd name %s timeout %d", msg->key, timeout); + ParamWatcher *watcher = GetParamWatcher(worker); + PARAM_CHECK(watcher != NULL, return -1, "Failed to get param watcher data"); + watcher->timeout = timeout; + + TriggerExtData extData = {}; + extData.excuteCmd = SendWatcherNotifyMessage; + extData.watcherId = msg->id.watcherId; + extData.watcher = watcher; + // first check match, if match send response to client + ParamNode *param = CheckMatchParamWait(worksapce, msg->key, valueContent->content); + if (param != NULL) { + SendWatcherNotifyMessage(&extData, CMD_INDEX_FOR_PARA_WAIT, param->data); + return 0; + } + + uint32_t buffSize = strlen(msg->key) + valueContent->contentSize + 1 + 1; + char *condition = malloc(buffSize); + PARAM_CHECK(condition != NULL, return -1, "Failed to create condition for %s", msg->key); + int ret = sprintf_s(condition, buffSize - 1, "%s=%s", msg->key, valueContent->content); + PARAM_CHECK(ret > EOK, free(condition); + return -1, "Failed to copy name for %s", msg->key); + TriggerNode *trigger = AddWatcherTrigger(watcher, TRIGGER_PARAM_WAIT, msg->key, condition, &extData); + PARAM_CHECK(trigger != NULL, free(condition); + return -1, "Failed to add trigger for %s", msg->key); + free(condition); + return 0; } -static void SendResponse(uv_stream_t *handle, RequestType type, int result, const void *content, int size) +static int HandleParamWatcherAdd(ParamWorkSpace *workSpace, const ParamTaskPtr worker, const ParamMessage *msg) { + PARAM_CHECK(msg != NULL, return -1, "Invalid message"); + TriggerExtData extData = {}; + extData.excuteCmd = SendWatcherNotifyMessage; + extData.watcherId = msg->id.watcherId; + int ret = 0; + do { + ParamWatcher *watcher = GetParamWatcher(NULL); + PARAM_CHECK(watcher != NULL, ret = -1; + break, "Failed to get param watcher data"); + watcher->stream = worker; + TriggerNode *trigger = AddWatcherTrigger(watcher, TRIGGER_PARAM_WATCH, msg->key, NULL, &extData); + PARAM_CHECK(trigger != NULL, ret = -1; + break, "Failed to add trigger for %s", msg->key); + } while (0); + PARAM_LOGD("HandleParamWatcherAdd name %s watcher: %d", msg->key, msg->id.watcherId); + return SendResponseMsg(worker, msg, ret); +} + +static int HandleParamWatcherDel(ParamWorkSpace *workSpace, const ParamTaskPtr worker, const ParamMessage *msg) +{ + PARAM_CHECK(msg != NULL, return -1, "Invalid message"); + ParamWatcher *watcher = GetParamWatcher(NULL); + PARAM_CHECK(watcher != NULL, return -1, "Failed to get param watcher data"); + PARAM_LOGD("HandleParamWatcherDel name %s watcher: %d", msg->key, msg->id.watcherId); + DelWatcherTrigger(watcher, msg->id.watcherId); + return SendResponseMsg(worker, msg, 0); +} + +PARAM_STATIC int ProcessMessage(const ParamTaskPtr worker, const ParamMessage *msg) +{ + PARAM_CHECK(msg != NULL, return -1, "Invalid msg"); + PARAM_CHECK(worker != NULL, return -1, "Invalid worker"); 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, uv_buf_t *buf) -{ - if (nread <= 0 || buf == NULL || buf->base == NULL) { - uv_close((uv_handle_t*)handle, OnClose); - if (buf != NULL && buf->base != NULL) { - 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); + case MSG_SET_PARAM: + ret = HandleParamSet(worker, msg); + break; + case MSG_WAIT_PARAM: + ret = HandleParamWaitAdd(&g_paramWorkSpace, worker, msg); + break; + case MSG_ADD_WATCHER: + ret = HandleParamWatcherAdd(&g_paramWorkSpace, worker, (const ParamMessage *)msg); + break; + case MSG_DEL_WATCHER: + ret = HandleParamWatcherDel(&g_paramWorkSpace, worker, (const ParamMessage *)msg); break; - } default: - PARAM_LOGE("not supported the command: %d", msg->type); break; } - free(buf->base); - buf->base = NULL; - uv_close((uv_handle_t*)handle, OnClose); + PARAM_CHECK(ret == 0, return -1, "Failed to process message ret %d", ret); + return 0; } -static void OnConnection(uv_stream_t *server, int status) +static int LoadDefaultParam_(const char *fileName, int mode, const char *exclude[], uint32_t count) { - 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); + uint32_t paramNum = 0; + FILE *fp = fopen(fileName, "r"); + PARAM_CHECK(fp != NULL, return -1, "Open file %s fail", fileName); + char *buff = malloc(sizeof(SubStringInfo) * (SUBSTR_INFO_VALUE + 1) + PARAM_BUFFER_SIZE); + PARAM_CHECK(buff != NULL, (void)fclose(fp); + return -1, "Failed to alloc memory for load %s", fileName); + + SubStringInfo *info = (SubStringInfo *)(buff + PARAM_BUFFER_SIZE); + while (fgets(buff, PARAM_BUFFER_SIZE, fp) != NULL) { + int subStrNumber = GetSubStringInfo(buff, strlen(buff), '=', info, SUBSTR_INFO_VALUE + 1); + if (subStrNumber <= SUBSTR_INFO_VALUE) { + continue; + } + // 过滤 + for (uint32_t i = 0; i < count; i++) { + if (strncmp(info[0].value, exclude[i], strlen(exclude[i])) == 0) { + PARAM_LOGI("Do not set %s parameters", info[0].value); + continue; + } + } + int ret = CheckParamName(info[0].value, 0); + PARAM_CHECK(ret == 0, continue, "Illegal param name %s", info[0].value); + PARAM_LOGI("Add default parameter %s %s", info[0].value, info[1].value); + uint32_t dataIndex = 0; + ret = WriteParam(&g_paramWorkSpace.paramSpace, + info[0].value, info[1].value, &dataIndex, mode & LOAD_PARAM_ONLY_ADD); + PARAM_CHECK(ret == 0, continue, "Failed to set param %d %s", ret, buff); + paramNum++; + } + (void)fclose(fp); + free(buff); + PARAM_LOGI("Load parameters success %s total %u", fileName, paramNum); + return 0; +} - 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); +static int OnIncomingConnect(const ParamTaskPtr server, int flags) +{ + PARAM_LOGD("OnIncomingConnect %p", server); + ParamStreamInfo info = {}; + info.flags = WORKER_TYPE_CLIENT | flags; + info.server = NULL; + info.close = OnClose; + info.recvMessage = ProcessMessage; + info.incomingConnect = NULL; + ParamTaskPtr client = NULL; + int ret = ParamStreamCreate(&client, server, &info, sizeof(ParamWatcher)); + PARAM_CHECK(ret == 0, return -1, "Failed to create client"); + + ParamWatcher *watcher = (ParamWatcher *)ParamGetTaskUserData(client); + ListInit(&watcher->node); + PARAM_TRIGGER_HEAD_INIT(watcher->triggerHead); + ListAddTail(&GetTriggerWorkSpace()->waitList, &watcher->node); + watcher->stream = client; + watcher->timeout = UINT32_MAX; + return 0; +} - 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); +static void TimerCallback(ParamTaskPtr timer, void *context) +{ + UNUSED(context); + ParamWatcher *watcher = GetNextParamWatcher(GetTriggerWorkSpace(), NULL); + while (watcher != NULL) { + ParamWatcher *next = GetNextParamWatcher(GetTriggerWorkSpace(), watcher); + if (watcher->timeout > 0) { + watcher->timeout--; + } else { + PARAM_LOGD("TimerCallback watcher->timeout %p ", watcher); + ParamTaskClose(watcher->stream); + } + watcher = next; + } } -void StopParamService() +static int CopyBootParam(char *buffer, const char *key, size_t keyLen) { - 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."); + size_t bootLen = strlen(OHOS_BOOT); + int ret = strncpy_s(buffer, PARAM_NAME_LEN_MAX - 1, OHOS_BOOT, bootLen); + PARAM_CHECK(ret == EOK, return -1, "Failed to cpy boot"); + size_t i = 0; + for (; (i < PARAM_NAME_LEN_MAX - 1 - bootLen) && (i <= keyLen); i++) { + buffer[i + bootLen] = key[i]; + } + if (i > (PARAM_NAME_LEN_MAX - 1 - bootLen)) { + return -1; + } + buffer[i + bootLen] = '\0'; + return 0; } -int StartParamService() +static int FindKey(const char *key, struct CmdLineEntry *cmdLineEntry, int length) { - PARAM_LOGI("StartParamService."); - uv_fs_t req; - uv_fs_unlink(uv_default_loop(), &req, PIPE_NAME, NULL); + PARAM_CHECK(key != NULL && cmdLineEntry != NULL && length > 0, return -1, "Input param error."); + for (int i = 0; i < length; i++) { + if (strstr(key, cmdLineEntry[i].key) != NULL) { + cmdLineEntry[i].set = 1; + return 1; + } + } + return 0; +} - 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 = chmod(PIPE_NAME, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - PARAM_CHECK(ret == 0, return ret, "Failed to chmod %s, err %d. ", PIPE_NAME, errno); - 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."); +static int LoadParamFromCmdLine(struct CmdLineEntry *cmdLineEntry, int length) +{ + PARAM_CHECK(cmdLineEntry != NULL && length > 0, return -1, "Input params error."); + char *buffer = ReadFileData(PARAM_CMD_LINE); + PARAM_CHECK(buffer != NULL, return -1, "Failed to read file %s", PARAM_CMD_LINE); + char *data = malloc(PARAM_NAME_LEN_MAX + PARAM_CONST_VALUE_LEN_MAX); + PARAM_CHECK(data != NULL, free(buffer); + return -1, "Failed to read file %s", PARAM_CMD_LINE); + + char *endBuffer = buffer + strlen(buffer); + char *key = data; + char *value = data + PARAM_NAME_LEN_MAX; + char *tmp = strchr(buffer, '='); + char *next = buffer; + while (tmp != 0) { + int ret = CopyBootParam(key, next, tmp - next - 1); + int ret1 = 0; + next = strchr(tmp + 1, '='); + if (next != NULL) { + while (!isspace(*next) && (next > buffer)) { // 直到属性值结束位置 + next--; + } + while (isspace(*next) && (next > buffer)) { // 去掉空格 + next--; + } + ret1 = strncpy_s(value, PARAM_CONST_VALUE_LEN_MAX - 1, tmp + 1, next - tmp); + next++; + while (isspace(*next) && (next < endBuffer)) { // 跳过空格 + next++; + } + } else { + ret1 = strncpy_s(value, PARAM_CONST_VALUE_LEN_MAX - 1, tmp + 1, endBuffer - tmp); + } + if ((ret == 0) && (ret1 == 0) && (CheckParamName(key, 0) == 0)) { + uint32_t dataIndex = 0; + if (FindKey(key, cmdLineEntry, length) == 1) { + PARAM_LOGD("LoadParamFromCmdLine %s %s", key, value); + (void)WriteParam(&g_paramWorkSpace.paramSpace, key, value, &dataIndex, 0); + } + } + if (next == NULL) { + break; + } + tmp = strchr(next, '='); + } + for (int i = 0; i < length; i++) { + if (cmdLineEntry[i].set == 0) { + PARAM_LOGI("Warning, LoadParamFromCmdLine key %s is not found.", cmdLineEntry[i].key); + } + } + free(data); + free(buffer); 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_CHECK(ret == 0, return ret, "Failed to set param %s", name); - ret = WritePersistParam(name, value); - PARAM_CHECK(ret == 0, return ret, "Failed to set persist param %s", name); - - // notify event to process trigger - PostParamTrigger(name, value); - return ret; + return SystemSetParam(name, value, g_paramWorkSpace.securityLabel); } 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); + int ret = ReadParamWithCheck(&g_paramWorkSpace, name, DAC_READ, &handle); if (ret == 0) { ret = ReadParamValue(&g_paramWorkSpace, handle, value, len); } return ret; } -ParamWorkSpace *GetParamWorkSpace() +int SystemTraversalParam(void (*traversalParameter)(ParamHandle handle, void *cookie), void *cookie) { - return &g_paramWorkSpace; + PARAM_CHECK(traversalParameter != NULL, return -1, "The param is null"); + return TraversalParam(&g_paramWorkSpace, traversalParameter, cookie); } -int LoadPersistParams() +int LoadPersistParams(void) { - return RefreshPersistParams(&g_paramWorkSpace, g_initContext); + return LoadPersistParam(&g_paramWorkSpace); } -int SystemTraversalParam(void (*traversalParameter)(ParamHandle handle, void* cookie), void* cookie) +static int ProcessParamFile(const char *fileName, void *context) { - PARAM_CHECK(traversalParameter != NULL, return -1, "The param is null"); - return TraversalParam(&g_paramWorkSpace, traversalParameter, cookie); -} \ No newline at end of file + static const char *exclude[] = {"ctl.", "selinux.restorecon_recursive"}; + int mode = *(int *)context; + return LoadDefaultParam_(fileName, mode, exclude, sizeof(exclude) / sizeof(exclude[0])); +} + +int LoadDefaultParams(const char *fileName, int mode) +{ + PARAM_CHECK(fileName != NULL, return -1, "Invalid fielname for load"); + if (!PARAM_TEST_FLAG(g_paramWorkSpace.flags, WORKSPACE_FLAGS_INIT)) { + return PARAM_CODE_NOT_INIT; + } + PARAM_LOGI("load default parameters %s.", fileName); + int ret = 0; + struct stat st; + if ((stat(fileName, &st) == 0) && !S_ISDIR(st.st_mode)) { + ret = ProcessParamFile(fileName, &mode); + } else { + ret = ReadFileInDir(fileName, ".para", ProcessParamFile, &mode); + } + + // load security label + ParamSecurityOps *ops = &g_paramWorkSpace.paramSecurityOps; + if (ops->securityGetLabel != NULL) { + ret = ops->securityGetLabel(AddSecurityLabel, fileName, (void *)&g_paramWorkSpace); + } + return ret; +} + +void InitParamService(void) +{ + PARAM_LOGI("InitParamService pipe: %s.", PIPE_NAME); + CheckAndCreateDir(PIPE_NAME); + int ret = InitParamWorkSpace(&g_paramWorkSpace, 0); + PARAM_CHECK(ret == 0, return, "Init parameter workspace fail"); + ret = InitPersistParamWorkSpace(&g_paramWorkSpace); + PARAM_CHECK(ret == 0, return, "Init persist parameter workspace fail"); + if (g_paramWorkSpace.serverTask == NULL) { + ParamStreamInfo info = {}; + info.flags = WORKER_TYPE_SERVER; + info.server = PIPE_NAME; + info.close = NULL; + info.recvMessage = NULL; + info.incomingConnect = OnIncomingConnect; + ret = ParamServerCreate(&g_paramWorkSpace.serverTask, &info); + PARAM_CHECK(ret == 0, return, "Failed to create server"); + PARAM_LOGD("OnIncomingConnect %p", g_paramWorkSpace.serverTask); + } + + if (g_paramWorkSpace.timer == NULL) { + ParamTimerCreate(&g_paramWorkSpace.timer, TimerCallback, &g_paramWorkSpace); + ParamTimerStart(g_paramWorkSpace.timer, 1, MS_UNIT); + PARAM_LOGD("Start timer %p", g_paramWorkSpace.timer); + } + ret = InitTriggerWorkSpace(); + PARAM_CHECK(ret == 0, return, "Failed to init trigger"); + + ParamAuditData auditData = {}; + auditData.name = "#"; + auditData.label = NULL; + auditData.dacData.gid = getegid(); + auditData.dacData.uid = geteuid(); + auditData.dacData.mode = DAC_ALL_PERMISSION; + ret = AddSecurityLabel(&auditData, (void *)&g_paramWorkSpace); + PARAM_CHECK(ret == 0, return, "Failed to add default dac label"); + + // 读取cmdline的参数 + struct CmdLineEntry cmdLineEntry[] = {{"hardware", 0}}; + LoadParamFromCmdLine(cmdLineEntry, sizeof(cmdLineEntry) / sizeof(cmdLineEntry[0])); +} + +static void OnPidDelete(pid_t pid) +{ + UNUSED(pid); +} + +int StartParamService(void) +{ + return ParamServiceStart(OnPidDelete); +} + +void StopParamService(void) +{ + PARAM_LOGI("StopParamService."); + CloseParamWorkSpace(&g_paramWorkSpace); + CloseTriggerWorkSpace(); + g_paramWorkSpace.serverTask = NULL; + ParamServiceStop(); +} + +ParamWorkSpace *GetParamWorkSpace(void) +{ + return &g_paramWorkSpace; +} diff --git a/services/param/trigger/trigger_checker.c b/services/param/trigger/trigger_checker.c index fff388e10254a5dcf1f0cd794c76c32d7ecf36f5..990ab9383fd362145b594a2d7d6fb3640affea56 100644 --- a/services/param/trigger/trigger_checker.c +++ b/services/param/trigger/trigger_checker.c @@ -15,9 +15,11 @@ #include "trigger_checker.h" #include -#include "trigger_manager.h" + #include "init_param.h" +#include "trigger_manager.h" +#define MAX_CALC_PARAM 100 #define LABEL "Trigger" // 申请整块能存作为计算的节点 int CalculatorInit(LogicCalculator *calculator, int dataNumber, int dataUnit, int needCondition) @@ -25,7 +27,7 @@ int CalculatorInit(LogicCalculator *calculator, int dataNumber, int dataUnit, in PARAM_CHECK(calculator != NULL, return -1, "Invalid param"); int dataSize = dataUnit * dataNumber; if (needCondition) { - dataSize += 5 * SUPPORT_DATA_BUFFER_MAX; + dataSize += MAX_DATA_BUFFER_MAX; } calculator->data = (char *)malloc(dataSize); PARAM_CHECK(calculator->data != NULL, return -1, "Failed to malloc for calculator"); @@ -86,7 +88,7 @@ static int CalculatorPush(LogicCalculator *calculator, const void *data) 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"); + PARAM_CHECK(ret == EOK, return -1, "Failed to copy logic data"); calculator->endIndex++; return 0; } @@ -100,7 +102,7 @@ static int CalculatorPop(LogicCalculator *calculator, void *data) } 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"); + PARAM_CHECK(ret == EOK, return -1, "Failed to copy logic data"); calculator->endIndex--; return 0; } @@ -111,9 +113,9 @@ static int CalculatorLength(const LogicCalculator *calculator) return calculator->endIndex; } -static int PrefixAdd(char *prefix, u_int32_t *prefixIndex, u_int32_t prefixLen, char op) +static int PrefixAdd(char *prefix, uint32_t *prefixIndex, uint32_t prefixLen, char op) { - if ((*prefixIndex + 3) >= prefixLen) { + if ((*prefixIndex + 1 + 1 + 1) >= prefixLen) { return -1; } prefix[(*prefixIndex)++] = ' '; @@ -122,12 +124,12 @@ static int PrefixAdd(char *prefix, u_int32_t *prefixIndex, u_int32_t prefixLen, return 0; } -static int HandleOperationOr(LogicCalculator *calculator, char *prefix, u_int32_t *prefixIndex, u_int32_t prefixLen) +static int HandleOperationOr(LogicCalculator *calculator, char *prefix, uint32_t *prefixIndex, uint32_t prefixLen) { int ret = 0; char e; prefix[(*prefixIndex)++] = ' '; - if(CalculatorLength(calculator) == 0) { + if (CalculatorLength(calculator) == 0) { CalculatorPushChar(calculator, '|'); } else { do { @@ -144,48 +146,59 @@ static int HandleOperationOr(LogicCalculator *calculator, char *prefix, u_int32_ return 0; } +static int CompareValue(const char *condition, const char *value) +{ + if (strcmp(condition, "*") == 0) { + return 1; + } + if (strcmp(condition, value) == 0) { + return 1; + } + char *tmp = strstr(condition, "*"); + if (tmp != NULL && (strncmp(value, condition, tmp - condition) == 0)) { + return 1; + } + 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); } - // 解析条件 + uint32_t triggerContentSize = strlen(calculator->triggerContent); + // 解析条件, aaaa && bbb=1 && ccc=1的场景 char *subStr = strstr(condition + data->startIndex, "="); - if (subStr != NULL && ((u_int32_t)(subStr - condition) > data->endIndex)) { - if (strncmp(condition + data->startIndex, calculator->triggerContent, strlen(calculator->triggerContent)) == 0) { + if (subStr != NULL && ((uint32_t)(subStr - condition) > data->endIndex)) { + if (strncmp(condition + data->startIndex, calculator->triggerContent, triggerContentSize) == 0) { return 1; } - } else { - 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 (calculator->inputName && 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, "*") == 0 || - strcmp(calculator->conditionContent, calculator->readContent) == 0)) { - return 1; - } + return 0; + } + 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 ((calculator->inputName != NULL) && (strcmp(calculator->conditionName, calculator->inputName) == 0)) { + return CompareValue(calculator->conditionContent, calculator->inputContent); + } else if (calculator->conditionName != NULL && strlen(calculator->conditionName) > 0) { + uint32_t len = SUPPORT_DATA_BUFFER_MAX; + ret = SystemReadParam(calculator->conditionName, calculator->readContent, &len); + if (ret != 0) { + return 0; } + return CompareValue(calculator->conditionContent, calculator->readContent); } return 0; } -int GetValueFromContent(const char *content, u_int32_t contentSize, u_int32_t start, char *value, u_int32_t valueSize) +int GetValueFromContent(const char *content, uint32_t contentSize, uint32_t start, char *value, uint32_t valueSize) { - u_int32_t contentIndex = start; - u_int32_t currIndex = 0; + uint32_t contentIndex = start; + uint32_t currIndex = 0; while (contentIndex < contentSize && currIndex < valueSize) { if (content[contentIndex] == '=') { value[currIndex++] = '\0'; @@ -202,8 +215,8 @@ int GetValueFromContent(const char *content, u_int32_t contentSize, u_int32_t st int ComputeCondition(LogicCalculator *calculator, const char *condition) { - u_int32_t currIndex = 0; - u_int32_t start = 0; + uint32_t currIndex = 0; + uint32_t start = 0; int noneOper = 1; CalculatorClear(calculator); LogicData data1 = {}; @@ -219,12 +232,11 @@ int ComputeCondition(LogicCalculator *calculator, const char *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); - } + } else if ((condition[currIndex] == '|' || ret == 1) && + (ComputeSubCondition(calculator, &data2, condition) == 1)) { + LOGIC_DATA_SET_FLAG(&data1, LOGIC_DATA_FLAGS_TRUE); } - ret = CalculatorPush(calculator, (void*)&data1); + ret = CalculatorPush(calculator, (void *)&data1); PARAM_CHECK(ret == 0, return -1, "Failed to push data"); start = currIndex + 1; // 跳过符号 } else if (isspace(condition[currIndex])) { @@ -235,7 +247,7 @@ int ComputeCondition(LogicCalculator *calculator, const char *condition) data1.flags = LOGIC_DATA_FLAGS_ORIGINAL; data1.startIndex = start; data1.endIndex = currIndex; - int ret = CalculatorPush(calculator, (void*)&data1); + int ret = CalculatorPush(calculator, (void *)&data1); PARAM_CHECK(ret == 0, return -1, "Failed to push data"); start = currIndex + 1; } @@ -252,31 +264,34 @@ int ComputeCondition(LogicCalculator *calculator, const char *condition) return ComputeSubCondition(calculator, &data1, condition); } -int ConvertInfixToPrefix(const char *condition, char *prefix, u_int32_t prefixLen) +int ConvertInfixToPrefix(const char *condition, char *prefix, uint32_t prefixLen) { char e = 0; int ret = 0; - u_int32_t curr = 0; - u_int32_t prefixIndex = 0; + uint32_t curr = 0; + uint32_t prefixIndex = 0; LogicCalculator calculator; - CalculatorInit(&calculator, 100, 1, 0); + CalculatorInit(&calculator, MAX_CALC_PARAM, 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"); + PARAM_CHECK(ret == 0, + CalculatorFree(&calculator); return -1, "Invalid prefix"); + CalculatorPopChar(&calculator, &e); } } else if (condition[curr] == '|') { - PARAM_CHECK(condition[curr + 1] == '|', CalculatorFree(&calculator); return -1, "Invalid condition"); + 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"); + 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"); + PARAM_CHECK(condition[curr + 1] == '&', + CalculatorFree(&calculator); return -1, "Invalid condition"); prefix[prefixIndex++] = ' '; CalculatorPushChar(&calculator, condition[curr]); curr++; @@ -286,13 +301,15 @@ int ConvertInfixToPrefix(const char *condition, char *prefix, u_int32_t prefixLe prefix[prefixIndex++] = condition[curr]; } curr++; - PARAM_CHECK(prefixIndex < prefixLen, CalculatorFree(&calculator); return -1, "Invalid prefixIndex"); + 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); + PARAM_CHECK(ret == 0, + CalculatorFree(&calculator); return -1, "Invalid prefix %u %u", prefixIndex, prefixLen); } prefix[prefixIndex] = '\0'; @@ -300,13 +317,11 @@ int ConvertInfixToPrefix(const char *condition, char *prefix, u_int32_t prefixLe return 0; } -char *GetMatchedSubCondition(const char *condition, const char *input, int length) +int CheckMatchSubCondition(const char *condition, const char *input, int length) { - const char *p = condition; - for(;(p = strchr(p, *input)) != 0; p++) { - if(strncmp(p, input, length) == 0) { - return (char*)p; - } + char *tmp = strstr(condition, input); + if ((tmp != NULL) && (strlen(tmp) > length) && (tmp[length] == '=')) { + return 1; } - return NULL; + return 0; } diff --git a/services/param/trigger/trigger_manager.c b/services/param/trigger/trigger_manager.c index 7d2d104baeb4c19b983cd5ccc26a6d394aa85686..fcf84ebc04dae1f3cbba94d600f6bd8bccb65225 100644 --- a/services/param/trigger/trigger_manager.c +++ b/services/param/trigger/trigger_manager.c @@ -19,8 +19,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -28,270 +28,184 @@ #include "init_cmds.h" #include "init_utils.h" +#include "param_manager.h" #include "trigger_checker.h" #define LABEL "Trigger" -#define TRIGGER_AREA_SPACE 1024*128 -#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) +int AddCommand(TriggerNode *trigger, uint32_t cmdKeyIndex, const char *content) { - PARAM_CHECK(workSpace != NULL, return -1, "Invalid parm"); - if (workSpace->area != NULL) { - return 0; + PARAM_CHECK(trigger != NULL, return -1, "trigger is null"); + uint32_t size = sizeof(CommandNode); + size += (content == NULL || strlen(content) == 0) ? 1 : strlen(content) + 1; + size = PARAM_ALIGN(size); + + CommandNode *node = (CommandNode *)malloc(size); + PARAM_CHECK(node != NULL, return -1, "Failed to alloc memory for command"); + node->cmdKeyIndex = cmdKeyIndex; + node->next = NULL; + node->content[0] = '\0'; + if (content != NULL && strlen(content) != 0) { + int ret = memcpy_s(node->content, size, content, strlen(content)); + node->content[strlen(content)] = '\0'; + PARAM_CHECK(ret == EOK, return 0, "Failed to copy command"); } - 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)); + // 插入队列 + if (trigger->firstCmd == NULL) { + trigger->firstCmd = node; + trigger->lastCmd = node; + } else { + trigger->lastCmd->next = node; + trigger->lastCmd = node; } + trigger->triggerHead->cmdNodeCount++; return 0; } -static CommandNode *GetCmdByIndex(TriggerWorkSpace *workSpace, TriggerNode *trigger, u_int32_t index) +CommandNode *GetNextCmdNode(TriggerNode *trigger, CommandNode *curr) { - if (index == 0 || index == (u_int32_t)-1) { - return NULL; + if (curr == NULL) { + return trigger->firstCmd; } - 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); + return curr->next; } -u_int32_t AddCommand(TriggerWorkSpace *workSpace, TriggerNode *trigger, const char *cmdName, const char *content) +TriggerNode *AddTrigger(TriggerHeader *triggerHead, const char *name, const char *condition, uint16_t extDataSize) { - 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; - size = (size + 0x03) & (~0x03); - 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'; + PARAM_CHECK(triggerHead != NULL && name != NULL, return NULL, "triggerHead is null"); + PARAM_CHECK(extDataSize <= PARAM_CONST_VALUE_LEN_MAX, return NULL, "extDataSize is longest %d", extDataSize); + uint32_t nameLen = strlen(name); + uint32_t triggerNodeLen = PARAM_ALIGN(nameLen + 1) + sizeof(TriggerNode); + uint32_t conditionLen = 0; + if (condition != NULL && strlen(condition) != 0) { + conditionLen = PARAM_ALIGN(strlen(condition) + 1) + CONDITION_EXTEND_LEN; } - 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); + TriggerNode *node = (TriggerNode *)malloc(triggerNodeLen + conditionLen + extDataSize); + PARAM_CHECK(node != NULL, return NULL, "Failed to alloc memory for trigger"); + int ret = memcpy_s(node->name, triggerNodeLen - sizeof(TriggerNode), name, nameLen); + PARAM_CHECK(ret == EOK, free(node); + return NULL, "Failed to memcpy_s for trigger"); + node->name[nameLen] = '\0'; + node->condition = NULL; + if (conditionLen != 0) { + char *cond = node->name + PARAM_ALIGN(nameLen + 1); + ret = ConvertInfixToPrefix(condition, cond, conditionLen); + PARAM_CHECK(ret == 0, free(node); + return NULL, "Failed to convert condition for trigger"); + node->condition = cond; } - workSpace->area->currOffset += size; - return offset; + node->flags = 0; + node->firstCmd = NULL; + node->lastCmd = NULL; + node->triggerHead = triggerHead; + ListInit(&node->node); + node->extDataSize = extDataSize; + node->extDataOffset = triggerNodeLen + conditionLen; + ListAddTail(&triggerHead->triggerList, &node->node); + triggerHead->triggerCount++; + return node; } -static TriggerNode *GetTriggerByIndex(TriggerWorkSpace *workSpace, u_int32_t index) +void ClearTrigger(TriggerHeader *head) { - if (index == 0 || index == (u_int32_t)-1) { - return NULL; + ListNode *node = head->triggerList.next; + while (node != &head->triggerList) { + ListRemove(node); + ListInit(node); + TriggerNode *trigger = ListEntry(node, TriggerNode, node); + FreeTrigger(trigger); + node = head->triggerList.next; } - 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); + ListInit(&head->triggerList); } -u_int32_t AddTrigger(TriggerWorkSpace *workSpace, int type, const char *name, const char *condition) +void FreeTrigger(TriggerNode *trigger) { - PARAM_CHECK(workSpace != NULL && name != NULL, return 0, "list is null"); - const char *tmpCond = condition; - if (type == TRIGGER_BOOT && condition == NULL) { - tmpCond = name; + PARAM_CHECK(trigger != NULL, return, "trigger is null"); + PARAM_LOGD("FreeTrigger %s", trigger->name); + TriggerHeader *triggerHead = trigger->triggerHead; + CommandNode *cmd = trigger->firstCmd; + while (cmd != NULL) { + CommandNode *next = cmd->next; + free(cmd); + triggerHead->cmdNodeCount--; + cmd = next; } - u_int32_t conditionSize = (tmpCond == NULL) ? 1 : strlen(tmpCond) + 1 + CONDITION_EXTEND_LEN; - conditionSize = (conditionSize + 0x03) & (~0x03); - 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) { - ret = ConvertInfixToPrefix(tmpCond, node->condition, conditionSize); - PARAM_CHECK(ret == 0, return 0, "Failed to memcpy_s for trigger"); - } else { - node->condition[0] = '\0'; + trigger->lastCmd = NULL; + trigger->firstCmd = NULL; + ListRemove(&trigger->node); + triggerHead->triggerCount--; + + // 如果在执行队列,从队列中移走 + if (!TRIGGER_IN_QUEUE(trigger)) { + free(trigger); + return; } - - 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); + TriggerExecuteQueue *executeQueue = &GetTriggerWorkSpace()->executeQueue; + for (uint32_t i = executeQueue->startIndex; i < executeQueue->endIndex; i++) { + if (executeQueue->executeQueue[i] == trigger) { + executeQueue->executeQueue[i] = NULL; + break; } - atomic_store_explicit(&workSpace->header[type].lastTrigger, offset, memory_order_release); } - workSpace->area->currOffset += conditionSize + sizeof(TriggerNode); - return offset; + free(trigger); } -static int GetTriggerIndex(const char *type) +static TriggerNode *GetNextTrigger(TriggerHeader *triggerHead, TriggerNode *curr) { - if (strncmp("param:", type, strlen("param:")) == 0) { - return TRIGGER_PARAM; + ListNode *node = NULL; + if (curr != NULL) { + node = curr->node.next; + } else { + node = triggerHead->triggerList.next; } - static const char *triggerType[] = { - "pre-init", "boot", "early-init", "init", "late-init", "post-init", - "early-fs", "post-fs", "late-fs", "post-fs-data" - }; - for (size_t i = 0; i < sizeof(triggerType) / sizeof(char*); i++) { - if (strcmp(triggerType[i], type) == 0) { - return TRIGGER_BOOT; - } + if (node != &triggerHead->triggerList) { + return ListEntry(node, TriggerNode, node); } - return TRIGGER_UNKNOW; + return NULL; } -int ParseTrigger(TriggerWorkSpace *workSpace, cJSON *triggerItem) +static const char *GetTriggerCondition(TriggerWorkSpace *workSpace, TriggerNode *trigger) { - 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_LOGD("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(cmdLineStr != NULL, 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; + return trigger->condition == NULL ? "" : trigger->condition; } -int ExecuteTrigger(TriggerWorkSpace *workSpace, TriggerNode *trigger, CMD_EXECUTE cmdExecuter) +TriggerNode *GetTriggerByName(TriggerWorkSpace *workSpace, const char *triggerName) { - PARAM_CHECK(workSpace != NULL && trigger != NULL && cmdExecuter != NULL, return -1, "Invalid param"); - PARAM_LOGI("ExecuteTrigger 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); + PARAM_CHECK(workSpace != NULL && triggerName != NULL, return NULL, "Invalid param"); + for (size_t i = 0; i < sizeof(workSpace->triggerHead) / sizeof(workSpace->triggerHead[0]); i++) { + TriggerNode *trigger = GetNextTrigger(&workSpace->triggerHead[i], NULL); + while (trigger != NULL) { + if (strcmp(triggerName, trigger->name) == 0) { + return trigger; + } + trigger = GetNextTrigger(&workSpace->triggerHead[i], trigger); + } } - return 0; + return NULL; } -int ExecuteQueuePush(TriggerWorkSpace *workSpace, TriggerNode *trigger, u_int32_t triggerIndex) +int ExecuteQueuePush(TriggerWorkSpace *workSpace, TriggerNode *trigger) { 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); + uint32_t index = workSpace->executeQueue.endIndex++ % workSpace->executeQueue.queueCount; + workSpace->executeQueue.executeQueue[index] = trigger; 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); + TriggerNode *trigger = NULL; + do { + if (workSpace->executeQueue.endIndex <= workSpace->executeQueue.startIndex) { + return NULL; + } + uint32_t currIndex = workSpace->executeQueue.startIndex % workSpace->executeQueue.queueCount; + trigger = workSpace->executeQueue.executeQueue[currIndex]; + workSpace->executeQueue.executeQueue[currIndex] = NULL; + workSpace->executeQueue.startIndex++; + } while (trigger == NULL); + return trigger; } int ExecuteQueueSize(TriggerWorkSpace *workSpace) @@ -300,8 +214,8 @@ int ExecuteQueueSize(TriggerWorkSpace *workSpace) return workSpace->executeQueue.endIndex - workSpace->executeQueue.startIndex; } -static int CheckBootTriggerMatch(LogicCalculator *calculator, - TriggerNode *trigger, const char *content, u_int32_t contentSize) +static int CheckBootTriggerMatch(TriggerWorkSpace *workSpace, LogicCalculator *calculator, + TriggerNode *trigger, const char *content, uint32_t contentSize) { if (strncmp(trigger->name, (char *)content, contentSize) == 0) { return 1; @@ -309,113 +223,248 @@ static int CheckBootTriggerMatch(LogicCalculator *calculator, return 0; } -static int CheckParamTriggerMatch(LogicCalculator *calculator, - TriggerNode *trigger, const char *content, u_int32_t contentSize) +static int CheckWatcherTriggerMatch(TriggerWorkSpace *workSpace, LogicCalculator *calculator, + TriggerNode *trigger, const char *content, uint32_t contentSize) { + if (strncmp(trigger->name, (char *)content, strlen(trigger->name)) == 0) { + return 1; + } + return 0; +} + +static int CheckParamTriggerMatch(TriggerWorkSpace *workSpace, LogicCalculator *calculator, + TriggerNode *trigger, const char *content, uint32_t contentSize) +{ + UNUSED(content); + UNUSED(contentSize); + const char *condition = GetTriggerCondition(workSpace, trigger); if (calculator->inputName != NULL) { // 存在input数据时,先过滤非input的 - if (GetMatchedSubCondition(trigger->condition, content, strlen(calculator->inputName) + 1) == NULL) { + if (!CheckMatchSubCondition(condition, calculator->inputName, strlen(calculator->inputName))) { return 0; } } - return ComputeCondition(calculator, trigger->condition); + return ComputeCondition(calculator, condition); +} + +static int CheckOtherTriggerMatch(TriggerWorkSpace *workSpace, LogicCalculator *calculator, + TriggerNode *trigger, const char *content, uint32_t contentSize) +{ + const char *condition = GetTriggerCondition(workSpace, trigger); + return ComputeCondition(calculator, condition); +} + +static int CheckParamWaitMatch(TriggerWorkSpace *workSpace, int type, + LogicCalculator *calculator, const char *content, uint32_t contentSize) +{ + UNUSED(type); + ParamWatcher *watcher = GetNextParamWatcher(workSpace, NULL); + while (watcher != NULL) { + TriggerNode *trigger = GetNextTrigger(&watcher->triggerHead, NULL); + while (trigger != NULL) { + TriggerNode *next = GetNextTrigger(&watcher->triggerHead, trigger); + if (CheckParamTriggerMatch(workSpace, calculator, trigger, content, contentSize) == 1) { + calculator->triggerExecuter(trigger, content, contentSize); + } + trigger = next; + } + watcher = GetNextParamWatcher(workSpace, watcher); + } + return 0; } -static int CheckOtherTriggerMatch(LogicCalculator *calculator, - TriggerNode *trigger, const char *content, u_int32_t contentSize) +static int CheckParamWatcherMatch(TriggerWorkSpace *workSpace, int type, + LogicCalculator *calculator, const char *content, uint32_t contentSize) { - return ComputeCondition(calculator, trigger->condition); + UNUSED(type); + TriggerNode *trigger = GetNextTrigger(&workSpace->watcher.triggerHead, NULL); + while (trigger != NULL) { + TriggerNode *next = GetNextTrigger(&workSpace->watcher.triggerHead, trigger); + if (CheckWatcherTriggerMatch(workSpace, calculator, trigger, content, contentSize) == 1) { + calculator->triggerExecuter(trigger, content, contentSize); + } + trigger = next; + } + return 0; } static int CheckTrigger_(TriggerWorkSpace *workSpace, - LogicCalculator *calculator, int type, const char *content, u_int32_t contentSize) + LogicCalculator *calculator, int type, const char *content, uint32_t contentSize) { static TRIGGER_MATCH triggerCheckMatch[TRIGGER_MAX] = { CheckBootTriggerMatch, CheckParamTriggerMatch, CheckOtherTriggerMatch }; - PARAM_LOGD("CheckTrigger_ content %s ", content); PARAM_CHECK(calculator != NULL, return -1, "Failed to check calculator"); - PARAM_CHECK(CHECK_INDEX_VALID(workSpace, type), return -1, "Invalid type %d", type); - PARAM_CHECK((u_int32_t)type < sizeof(triggerCheckMatch) / sizeof(triggerCheckMatch[0]), + PARAM_CHECK(type < TRIGGER_MAX, return -1, "Invalid type %d", type); + PARAM_CHECK((uint32_t)type < sizeof(triggerCheckMatch) / sizeof(triggerCheckMatch[0]), return -1, "Failed to get check function"); PARAM_CHECK(triggerCheckMatch[type] != NULL, return -1, "Failed to get check function"); - u_int32_t index = workSpace->header[type].firstTrigger; - TriggerNode *trigger = GetTriggerByIndex(workSpace, workSpace->header[type].firstTrigger); + TriggerNode *trigger = GetNextTrigger(&workSpace->triggerHead[type], NULL); while (trigger != NULL) { - if (triggerCheckMatch[type](calculator, trigger, content, contentSize) == 1) { // 等于1 则认为匹配 - calculator->triggerExecuter(trigger, index); + if (triggerCheckMatch[type](workSpace, calculator, trigger, content, contentSize) == 1) { // 等于1 则认为匹配 + calculator->triggerExecuter(trigger, content, contentSize); } - index = trigger->next; - trigger = GetTriggerByIndex(workSpace, trigger->next); + trigger = GetNextTrigger(&workSpace->triggerHead[type], trigger); } return 0; } -int CheckTrigger(const TriggerWorkSpace *workSpace, - int type, void *content, u_int32_t contentSize, PARAM_CHECK_DONE triggerExecuter) +int CheckTrigger(TriggerWorkSpace *workSpace, int type, + const char *content, uint32_t contentSize, PARAM_CHECK_DONE triggerExecuter) { PARAM_CHECK(workSpace != NULL && content != NULL && triggerExecuter != NULL, return -1, "Failed arg for trigger"); - - LogicCalculator calculator = {}; + PARAM_LOGD("CheckTrigger type: %d content: %s ", type, content); + int ret = 0; + LogicCalculator calculator; + CalculatorInit(&calculator, MAX_CONDITION_NUMBER, sizeof(LogicData), 1); calculator.triggerExecuter = triggerExecuter; - return CheckTrigger_(workSpace, &calculator, type, (char *)content, contentSize); + if (type == TRIGGER_PARAM || type == TRIGGER_PARAM_WAIT) { + 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"); + } else if (type == TRIGGER_UNKNOW) { + ret = memcpy_s(calculator.triggerContent, sizeof(calculator.triggerContent), content, contentSize); + PARAM_CHECK(ret == EOK, CalculatorFree(&calculator); + return -1, "Failed to memcpy"); + calculator.inputName = NULL; + calculator.inputContent = NULL; + } + if (type == TRIGGER_PARAM_WAIT) { + CheckParamWaitMatch(workSpace, PARAM_TRIGGER_FOR_WAIT, &calculator, content, contentSize); + } else if (type == TRIGGER_PARAM_WATCH) { + CheckParamWatcherMatch(workSpace, PARAM_TRIGGER_FOR_WATCH, &calculator, content, contentSize); + } else { + CheckTrigger_(workSpace, &calculator, type, content, contentSize); + } + CalculatorFree(&calculator); + return 0; } -int CheckParamTrigger(TriggerWorkSpace *workSpace, - const char *content, u_int32_t contentSize, PARAM_CHECK_DONE triggerExecuter) +int MarkTriggerToParam(TriggerWorkSpace *workSpace, TriggerHeader *triggerHead, const char *name) { - PARAM_CHECK(workSpace != NULL && content != NULL && triggerExecuter != NULL, - return -1, "Failed arg for param trigger"); - LogicCalculator calculator = {}; - CalculatorInit(&calculator, 100, sizeof(LogicData), 1); + int ret = 0; + TriggerNode *trigger = GetNextTrigger(triggerHead, NULL); + while (trigger != NULL) { + const char *tmp = strstr(GetTriggerCondition(workSpace, trigger), name); + if (tmp != NULL && strncmp(tmp + strlen(name), "=", 1) == 0) { + TRIGGER_SET_FLAG(trigger, TRIGGER_FLAGS_RELATED); + ret = 1; + } + trigger = GetNextTrigger(triggerHead, trigger); + } + return ret; +} - // 先解析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"); - calculator.triggerExecuter = triggerExecuter; - CheckTrigger_(workSpace, &calculator, TRIGGER_PARAM, content, contentSize); - CalculatorFree(&calculator); - return 0; +ParamWatcher *GetNextParamWatcher(TriggerWorkSpace *workSpace, ParamWatcher *curr) +{ + ListNode *node = NULL; + if (curr != NULL) { + node = curr->node.next; + } else { + node = workSpace->waitList.next; + } + if (node == &workSpace->waitList) { + return NULL; + } + return ListEntry(node, ParamWatcher, node); } -int CheckAndExecuteTrigger(TriggerWorkSpace *workSpace, const char *content, PARAM_CHECK_DONE triggerExecuter) +TriggerNode *AddWatcherTrigger(ParamWatcher *watcher, + int triggerType, const char *name, const char *condition, const TriggerExtData *extData) { - PARAM_CHECK(workSpace != NULL && content != NULL && triggerExecuter != NULL, - return -1, "Failed arg for param trigger"); - LogicCalculator calculator = {}; - CalculatorInit(&calculator, 100, sizeof(LogicData), 1); + PARAM_CHECK(name != NULL, return NULL, "Invalid name"); + PARAM_CHECK(watcher != NULL && extData != NULL, return NULL, "Invalid watcher for %s", name); + + TriggerNode *trigger = AddTrigger(&watcher->triggerHead, name, condition, sizeof(TriggerExtData)); + PARAM_CHECK(trigger != NULL, return NULL, "Failed to create trigger for %s", name); + // add command and arg is "name" + int cmd = CMD_INDEX_FOR_PARA_WATCH; + if (triggerType == TRIGGER_PARAM_WAIT) { // wait 回复后立刻删除 + TRIGGER_SET_FLAG(trigger, TRIGGER_FLAGS_ONCE); + cmd = CMD_INDEX_FOR_PARA_WAIT; + } + int ret = AddCommand(trigger, cmd, name); + PARAM_CHECK(ret == 0, FreeTrigger(trigger); + return NULL, "Failed to add command for %s", name); + TriggerExtData *localData = TRIGGER_GET_EXT_DATA(trigger, TriggerExtData); + PARAM_CHECK(localData != NULL, return NULL, "Failed to get trigger ext data"); + localData->excuteCmd = extData->excuteCmd; + localData->watcherId = extData->watcherId; + localData->watcher = watcher; + return trigger; +} - int ret = memcpy_s(calculator.triggerContent, sizeof(calculator.triggerContent), content, strlen(content)); - PARAM_CHECK(ret == 0, CalculatorFree(&calculator); return -1, "Failed to memcpy"); +void DelWatcherTrigger(ParamWatcher *watcher, uint32_t watcherId) +{ + PARAM_CHECK(watcher != NULL, return, "Failed to add watcher "); + TriggerNode *trigger = GetNextTrigger(&watcher->triggerHead, NULL); + while (trigger != NULL) { + TriggerExtData *extData = TRIGGER_GET_EXT_DATA(trigger, TriggerExtData); + PARAM_CHECK(extData != NULL, continue, "Failed to get trigger ext data"); + TriggerNode *next = GetNextTrigger(&watcher->triggerHead, trigger); + if (extData->watcherId == watcherId) { + FreeTrigger(trigger); + break; + } + trigger = next; + } +} - calculator.triggerExecuter = triggerExecuter; - calculator.inputName = NULL; - calculator.inputContent = NULL; - // 执行完成后,对第三类trigger检查,执行必须是在本阶段执行的trigger - CheckTrigger_(workSpace, &calculator, TRIGGER_UNKNOW, content, 0); - CalculatorFree(&calculator); - return 0; +void ClearWatcherTrigger(ParamWatcher *watcher) +{ + PARAM_CHECK(watcher != NULL, return, "Invalid watcher "); + TriggerNode *trigger = GetNextTrigger(&watcher->triggerHead, NULL); + while (trigger != NULL) { + TriggerExtData *extData = TRIGGER_GET_EXT_DATA(trigger, TriggerExtData); + PARAM_CHECK(extData != NULL, continue, "Failed to get trigger ext data"); + FreeTrigger(trigger); + trigger = GetNextTrigger(&watcher->triggerHead, NULL); + } } -TriggerNode *GetTriggerByName(TriggerWorkSpace *workSpace, const char *triggerName, u_int32_t *triggerIndex) +#define DUMP_DEBUG PARAM_LOGD +static void DumpTriggerQueue(TriggerWorkSpace *workSpace, int index) { - 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); + TriggerNode *trigger = GetNextTrigger(&workSpace->triggerHead[index], NULL); + while (trigger != NULL) { + DUMP_DEBUG("trigger 0x%08x", trigger->flags); + DUMP_DEBUG("trigger name %s ", trigger->name); + DUMP_DEBUG("trigger condition %s ", trigger->condition); + + CommandNode *cmd = GetNextCmdNode(trigger, NULL); + while (cmd != NULL) { + DUMP_DEBUG("\t command name %s", GetCmdKey(cmd->cmdKeyIndex)); + DUMP_DEBUG("\t command args %s", cmd->content); + cmd = GetNextCmdNode(trigger, cmd); + } + trigger = GetNextTrigger(&workSpace->triggerHead[index], trigger); + } +} + +void DumpTrigger(TriggerWorkSpace *workSpace) +{ + DUMP_DEBUG("Ready to dump all trigger memory"); + DUMP_DEBUG("workspace queue BOOT info:"); + DumpTriggerQueue(workSpace, TRIGGER_BOOT); + DUMP_DEBUG("workspace queue parameter info:"); + DumpTriggerQueue(workSpace, TRIGGER_PARAM); + DUMP_DEBUG("workspace queue other info:"); + DumpTriggerQueue(workSpace, TRIGGER_UNKNOW); + + DUMP_DEBUG("workspace queue execute info:"); + DUMP_DEBUG("queue info count: %u start: %u end: %u", + workSpace->executeQueue.queueCount, workSpace->executeQueue.startIndex, workSpace->executeQueue.endIndex); + for (uint32_t index = workSpace->executeQueue.startIndex; index < workSpace->executeQueue.endIndex; index++) { + TriggerNode *trigger = workSpace->executeQueue.executeQueue[index % workSpace->executeQueue.queueCount]; + if (trigger != 0) { + DUMP_DEBUG("queue node trigger name: %s ", trigger->name); } } - return NULL; } diff --git a/services/param/trigger/trigger_processor.c b/services/param/trigger/trigger_processor.c index 96d67fc46b9864a43f1ff4983c5021cd4801bca0..1642767e327e78368f9ce64c3c502cbb5e683f44 100644 --- a/services/param/trigger/trigger_processor.c +++ b/services/param/trigger/trigger_processor.c @@ -12,178 +12,281 @@ * 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 "init_service_manager.h" #include "param_manager.h" +#include "param_utils.h" #include "trigger_checker.h" -#include "uv.h" +#include "trigger_manager.h" #define LABEL "Trigger" #define MAX_TRIGGER_COUNT_RUN_ONCE 20 -#define SYS_POWER_CTRL "sys.powerctrl=" -#define OHOS_CTL_START "ohos.ctl.start=" -#define OHOS_CTL_STOP "ohos.ctl.stop=" - static TriggerWorkSpace g_triggerWorkSpace = {}; -static int DoCmdExecute(TriggerNode *trigger, const char *cmdName, const char *command) +void DoTriggerExec(const char *triggerName) { - PARAM_CHECK(trigger != NULL && cmdName != NULL && command != NULL, return -1, "Invalid param"); - PARAM_LOGD("DoCmdExecute trigger %s cmd %s %s", trigger->name, cmdName, command); + PARAM_CHECK(triggerName != NULL, return, "Invalid param"); + TriggerNode *trigger = GetTriggerByName(&g_triggerWorkSpace, triggerName); + if (trigger != NULL && !TRIGGER_IN_QUEUE(trigger)) { // 不在队列中 + PARAM_LOGI("DoTriggerExec trigger %s", trigger->name); + TRIGGER_SET_FLAG(trigger, TRIGGER_FLAGS_QUEUE); + ExecuteQueuePush(&g_triggerWorkSpace, trigger); + } +} + +static void DoCmdExec(TriggerNode *trigger, CommandNode *cmd, const char *content, uint32_t size) +{ + if (cmd->cmdKeyIndex == CMD_INDEX_FOR_PARA_WAIT || cmd->cmdKeyIndex == CMD_INDEX_FOR_PARA_WATCH) { + TriggerExtData *extData = TRIGGER_GET_EXT_DATA(trigger, TriggerExtData); + if (extData != NULL && extData->excuteCmd != NULL) { + extData->excuteCmd(extData, cmd->cmdKeyIndex, content); + } + return; + } + const char *cmdName = GetCmdKey(cmd->cmdKeyIndex); + if (cmdName == NULL) { + return; + } if (strncmp(cmdName, TRIGGER_CMD, strlen(TRIGGER_CMD)) == 0) { - DoTriggerExec(command); - return 0; + DoTriggerExec(cmd->content); + return; + } +#ifndef STARTUP_INIT_TEST + DoCmdByName(cmdName, cmd->content); +#endif +} + +static int ExecuteTrigger(TriggerWorkSpace *workSpace, TriggerNode *trigger) +{ + PARAM_CHECK(workSpace != NULL && trigger != NULL, return -1, "Invalid trigger"); + PARAM_CHECK(workSpace->cmdExec != NULL, return -1, "Invalid cmdExec"); + PARAM_LOGI("ExecuteTrigger trigger %s", trigger->name); + CommandNode *cmd = GetNextCmdNode(trigger, NULL); + while (cmd != NULL) { + workSpace->cmdExec(trigger, cmd, NULL, 0); + cmd = GetNextCmdNode(trigger, cmd); } - DoCmdByName(cmdName, command); return 0; } -static int DoTiggerCheckResult(TriggerNode *trigger, u_int32_t triggerIndex) +static int DoTiggerCheckResult(TriggerNode *trigger, const char *content, uint32_t size) { - // 已经在队列中了,则不执行 TODO - if (TRIGGER_NODE_IN_QUEUE(trigger)) { + UNUSED(content); + UNUSED(size); + if (TRIGGER_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); + TRIGGER_SET_FLAG(trigger, TRIGGER_FLAGS_QUEUE); + PARAM_LOGI("Add trigger %s to execute queue", trigger->name); + ExecuteQueuePush(&g_triggerWorkSpace, trigger); return 0; } -static int ExecuteTiggerImmediately(TriggerNode *trigger, u_int32_t triggerIndex) +static int ExecuteTiggerImmediately(TriggerNode *trigger, const char *content, uint32_t size) { - return ExecuteTrigger(&g_triggerWorkSpace, trigger, DoCmdExecute); + PARAM_CHECK(trigger != NULL, return -1, "Invalid trigger"); + PARAM_CHECK(g_triggerWorkSpace.cmdExec != NULL, return -1, "Invalid cmdExec"); + PARAM_LOGI("ExecuteTiggerImmediately trigger %s", trigger->name); + CommandNode *cmd = GetNextCmdNode(trigger, NULL); + while (cmd != NULL) { + g_triggerWorkSpace.cmdExec(trigger, cmd, content, size); + cmd = GetNextCmdNode(trigger, cmd); + } + if (TRIGGER_TEST_FLAG(trigger, TRIGGER_FLAGS_ONCE)) { + FreeTrigger(trigger); + } + return 0; } -void ExecuteQueueWork(u_int32_t maxCount) +static void ExecuteQueueWork(uint32_t maxCount) { - u_int32_t executeCount = 0; + uint32_t executeCount = 0; TriggerNode *trigger = ExecuteQueuePop(&g_triggerWorkSpace); while (trigger != NULL) { - ExecuteTrigger(&g_triggerWorkSpace, trigger, DoCmdExecute); - TRIGGER_NODE_CLEAR_QUEUE_FLAG(trigger); - CheckAndExecuteTrigger(&g_triggerWorkSpace, trigger->name, ExecuteTiggerImmediately); - + ExecuteTrigger(&g_triggerWorkSpace, trigger); + TRIGGER_CLEAR_FLAG(trigger, TRIGGER_FLAGS_QUEUE); + if (TRIGGER_TEST_FLAG(trigger, TRIGGER_FLAGS_SUBTRIGGER)) { // 检查boot:xxx=xxx 的trigger + CheckTrigger(&g_triggerWorkSpace, TRIGGER_UNKNOW, + trigger->name, strlen(trigger->name), ExecuteTiggerImmediately); + } + if (TRIGGER_TEST_FLAG(trigger, TRIGGER_FLAGS_ONCE)) { + FreeTrigger(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) +static void ProcessParamEvent(uint64_t eventId, const char *content, uint32_t size) +{ + UNUSED(eventId); + UNUSED(content); + UNUSED(size); + ExecuteQueueWork(MAX_TRIGGER_COUNT_RUN_ONCE); +} + +static void ProcessBeforeEvent(uint64_t eventId, const char *content, uint32_t size) { - switch (type) { - case EVENT_PROPERTY: { - CheckParamTrigger(&g_triggerWorkSpace, content, contentLen, DoTiggerCheckResult); + switch (eventId) { + case EVENT_TRIGGER_PARAM: { + CheckTrigger(&g_triggerWorkSpace, TRIGGER_PARAM, content, size, DoTiggerCheckResult); break; } - case EVENT_BOOT: { - CheckTrigger(&g_triggerWorkSpace, TRIGGER_BOOT, content, contentLen, DoTiggerCheckResult); + case EVENT_TRIGGER_BOOT: { + CheckTrigger(&g_triggerWorkSpace, TRIGGER_BOOT, content, size, DoTiggerCheckResult); + break; + } + case EVENT_TRIGGER_PARAM_WAIT: { + CheckTrigger(&g_triggerWorkSpace, TRIGGER_PARAM_WAIT, content, size, ExecuteTiggerImmediately); + break; + } + case EVENT_TRIGGER_PARAM_WATCH: { + CheckTrigger(&g_triggerWorkSpace, TRIGGER_PARAM_WATCH, content, size, ExecuteTiggerImmediately); break; } default: - PARAM_LOGI("CheckTriggers: %d", type); + PARAM_LOGI("CheckTriggers: %lu", eventId); break; } } -static void ProcessAfterEvent(uv_work_t *req, int status) -{ - free(req); - ExecuteQueueWork(MAX_TRIGGER_COUNT_RUN_ONCE); -} - -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) +static const char *GetCmdInfo(const char *content, uint32_t contentSize, char **cmdParam) { static const char *ctrlCmds[][2] = { {"reboot", "reboot "} }; + uint32_t index = 0; for (size_t i = 0; i < sizeof(ctrlCmds) / sizeof(ctrlCmds[0]); i++) { if (strncmp(content, ctrlCmds[i][0], strlen(ctrlCmds[i][0])) == 0) { *cmdParam = (char *)content; - return GetMatchCmd(ctrlCmds[i][1]); + return GetMatchCmd(ctrlCmds[i][1], &index); } } return NULL; } -static void SendTriggerEvent(TriggerDataEvent *event) +static void SendTriggerEvent(int type, const char *content, uint32_t contentLen) { - if (event == NULL) { - return; - } - 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); + PARAM_CHECK(content != NULL, return, "Invalid param"); + PARAM_LOGD("SendTriggerEvent type %d content %s", type, content); + if (type == EVENT_TRIGGER_PARAM) { + int ctrlSize = strlen(SYS_POWER_CTRL); + if (strncmp(content, SYS_POWER_CTRL, ctrlSize) == 0) { + char *cmdParam = NULL; + const char *matchCmd = GetCmdInfo(content + ctrlSize, contentLen - ctrlSize, &cmdParam); + PARAM_LOGD("SendTriggerEvent matchCmd %s", matchCmd); + if (matchCmd != NULL) { +#ifndef STARTUP_INIT_TEST + DoCmdByName(matchCmd, cmdParam); +#endif + } else { + PARAM_LOGE("SendTriggerEvent cmd %s not found", content); + } + } else if (strncmp(content, OHOS_CTRL_START, strlen(OHOS_CTRL_START)) == 0) { + StartServiceByName(content + strlen(OHOS_CTRL_START), false); + } else if (strncmp(content, OHOS_CTRL_STOP, strlen(OHOS_CTRL_STOP)) == 0) { + StopServiceByName(content + strlen(OHOS_CTRL_STOP)); } else { - PARAM_LOGE("SendTriggerEvent cmd %s not found", event->content); + ParamEventSend(g_triggerWorkSpace.eventHandle, (uint64_t)type, content, contentLen); } - } else if (strncmp(event->content, OHOS_CTL_START, strlen(OHOS_CTL_START)) == 0) { - DoCmdByName("start ", event->content + strlen(OHOS_CTL_START)); - } else if (strncmp(event->content, OHOS_CTL_STOP, strlen(OHOS_CTL_STOP)) == 0) { - DoCmdByName("stop ", event->content + strlen(OHOS_CTL_STOP)); } else { - uv_queue_work(uv_default_loop(), &event->request, ProcessEvent, ProcessAfterEvent); - event = NULL; - } - if (event != NULL) { - free(event); + ParamEventSend(g_triggerWorkSpace.eventHandle, (uint64_t)type, content, contentLen); } } -void PostParamTrigger(const char *name, const char *value) +void PostParamTrigger(int type, const char *name, const char *value) { PARAM_CHECK(name != NULL && value != NULL, return, "Invalid param"); - PARAM_LOGD("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); + uint32_t bufferSize = strlen(name) + strlen(value) + 1 + 1 + 1; + char *buffer = (char *)malloc(bufferSize); + PARAM_CHECK(buffer != NULL, return, "Failed to alloc memory for param %s", name); + int ret = sprintf_s(buffer, bufferSize - 1, "%s=%s", name, value); + PARAM_CHECK(ret > EOK, free(buffer); + return, "Failed to copy param"); + SendTriggerEvent(type, buffer, strlen(buffer)); + free(buffer); } -void PostTrigger(EventType type, const char *content, u_int32_t contentLen) +void PostTrigger(EventType type, const char *content, uint32_t contentLen) { - PARAM_LOGD("PostTrigger %d %s", type, content); 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; - PARAM_CHECK(memcpy_s(event->content, contentLen, content, contentLen) == 0, return, "Failed to copy content"); - event->content[contentLen] = '\0'; - SendTriggerEvent(event); - PARAM_LOGD("PostTrigger %d success", type); + SendTriggerEvent(type, content, contentLen); } -int ParseTriggerConfig(cJSON *fileRoot) +static int GetTriggerType(const char *type) { - PARAM_CHECK(fileRoot != NULL, return -1, "Invalid file"); - int ret = InitTriggerWorkSpace(&g_triggerWorkSpace); - PARAM_CHECK(ret == 0, return -1, "Failed to init trigger"); + if (strncmp("param:", type, strlen("param:")) == 0) { + return TRIGGER_PARAM; + } + const char *triggerTypeStr[] = { + "pre-init", "boot", "early-init", "init", "early-init", "late-init", "post-init", + "early-fs", "post-fs", "late-fs", "post-fs-data" + }; + for (size_t i = 0; i < sizeof(triggerTypeStr) / sizeof(char *); i++) { + if (strcmp(triggerTypeStr[i], type) == 0) { + return TRIGGER_BOOT; + } + } + return TRIGGER_UNKNOW; +} + +static 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 type = GetTriggerType(name); + PARAM_CHECK(type < TRIGGER_MAX, return -1, "Failed to get trigger index"); + + TriggerNode *trigger = GetTriggerByName(workSpace, name); + if (trigger == NULL) { + trigger = AddTrigger(&workSpace->triggerHead[type], name, condition, 0); + PARAM_CHECK(trigger != NULL, return -1, "Failed to create trigger %s", name); + } + if (type == TRIGGER_BOOT) { // 设置trigger立刻删除,如果是boot + TRIGGER_SET_FLAG(trigger, TRIGGER_FLAGS_ONCE); + TRIGGER_SET_FLAG(trigger, TRIGGER_FLAGS_SUBTRIGGER); + } + PARAM_LOGD("ParseTrigger %s type %d count %d", name, type, workSpace->triggerHead[type].triggerCount); + + // 添加命令行 + 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); + int ret = 0; + uint32_t cmdKeyIndex = 0; + 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, &cmdKeyIndex); + PARAM_CHECK(matchCmd != NULL, continue, "Command not support %s", cmdLineStr); + size_t matchLen = strlen(matchCmd); + if (matchLen == cmdLineLen) { + ret = AddCommand(trigger, cmdKeyIndex, NULL); + } else { + ret = AddCommand(trigger, cmdKeyIndex, cmdLineStr + matchLen); + } + PARAM_CHECK(ret == 0, continue, "Failed to add command %s", cmdLineStr); + } + return 0; +} + +int ParseTriggerConfig(const cJSON *fileRoot) +{ + PARAM_CHECK(fileRoot != NULL, return -1, "Invalid file"); cJSON *triggers = cJSON_GetObjectItemCaseSensitive(fileRoot, TRIGGER_ARR_NAME_IN_JSON); PARAM_CHECK(cJSON_IsArray(triggers), return -1, "Trigger item must array"); @@ -192,24 +295,78 @@ int ParseTriggerConfig(cJSON *fileRoot) for (int i = 0; i < size; ++i) { cJSON *item = cJSON_GetArrayItem(triggers, i); - ParseTrigger(&g_triggerWorkSpace, item); + ParseTrigger_(&g_triggerWorkSpace, item); } return 0; } -void DoTriggerExec(const char *content) +int InitTriggerWorkSpace(void) { - 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); + if (g_triggerWorkSpace.eventHandle != NULL) { + return 0; } + g_triggerWorkSpace.cmdExec = DoCmdExec; + ParamEventTaskCreate(&g_triggerWorkSpace.eventHandle, ProcessParamEvent, ProcessBeforeEvent); + PARAM_CHECK(g_triggerWorkSpace.eventHandle != NULL, return -1, "Failed to event handle"); + + // executeQueue + g_triggerWorkSpace.executeQueue.executeQueue = malloc(TRIGGER_EXECUTE_QUEUE * sizeof(TriggerNode *)); + g_triggerWorkSpace.executeQueue.queueCount = TRIGGER_EXECUTE_QUEUE; + g_triggerWorkSpace.executeQueue.startIndex = 0; + g_triggerWorkSpace.executeQueue.endIndex = 0; + PARAM_CHECK(g_triggerWorkSpace.executeQueue.executeQueue != NULL, + return -1, "Failed to alloc memory for executeQueue"); + int ret = memset_s(g_triggerWorkSpace.executeQueue.executeQueue, + TRIGGER_EXECUTE_QUEUE * sizeof(TriggerNode *), 0, TRIGGER_EXECUTE_QUEUE * sizeof(TriggerNode *)); + PARAM_CHECK(ret == EOK, return -1, "Failed to memset for executeQueue"); + + // normal trigger + for (size_t i = 0; i < sizeof(g_triggerWorkSpace.triggerHead) / sizeof(g_triggerWorkSpace.triggerHead[0]); i++) { + PARAM_TRIGGER_HEAD_INIT(g_triggerWorkSpace.triggerHead[i]); + } + // for watcher trigger + PARAM_TRIGGER_HEAD_INIT(g_triggerWorkSpace.watcher.triggerHead); + ListInit(&g_triggerWorkSpace.waitList); + return 0; } -TriggerWorkSpace *GetTriggerWorkSpace() +void CloseTriggerWorkSpace(void) +{ + // 释放trigger + for (size_t i = 0; i < sizeof(g_triggerWorkSpace.triggerHead) / sizeof(g_triggerWorkSpace.triggerHead[0]); i++) { + ClearTrigger(&g_triggerWorkSpace.triggerHead[i]); + } + free(g_triggerWorkSpace.executeQueue.executeQueue); + ParamTaskClose(g_triggerWorkSpace.eventHandle); +} + +int CheckAndMarkTrigger(int type, const char *name) +{ + if (type == TRIGGER_PARAM) { + return MarkTriggerToParam(&g_triggerWorkSpace, &g_triggerWorkSpace.triggerHead[type], name); + } else if (type != TRIGGER_PARAM_WAIT) { + return 0; + } + + ParamWatcher *watcher = GetNextParamWatcher(&g_triggerWorkSpace, NULL); + while (watcher != NULL) { + if (MarkTriggerToParam(&g_triggerWorkSpace, &watcher->triggerHead, name)) { + return 1; + } + watcher = GetNextParamWatcher(&g_triggerWorkSpace, watcher); + } + return 0; +} + +TriggerWorkSpace *GetTriggerWorkSpace(void) { return &g_triggerWorkSpace; } + +ParamWatcher *GetParamWatcher(const ParamTaskPtr worker) +{ + if (worker != NULL) { + return (ParamWatcher *)ParamGetTaskUserData(worker); + } + return &g_triggerWorkSpace.watcher; +} diff --git a/services/param/watcher/agent/watcher.cpp b/services/param/watcher/agent/watcher.cpp new file mode 100755 index 0000000000000000000000000000000000000000..e1f099f02bcb8beb836fbdbd38c273f2db6c75e1 --- /dev/null +++ b/services/param/watcher/agent/watcher.cpp @@ -0,0 +1,31 @@ +/* + * 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 "watcher.h" + +#include "iservice_registry.h" +#include "securec.h" +#include "system_ability_definition.h" +#include "watcher_utils.h" + +namespace OHOS { +namespace init_param { +void Watcher::OnParamerterChange(const std::string &name, const std::string &value) +{ + UNUSED(name); + UNUSED(value); +} +} // namespace init_param +} // namespace OHOS diff --git a/services/param/watcher/agent/watcher.h b/services/param/watcher/agent/watcher.h new file mode 100755 index 0000000000000000000000000000000000000000..6c80f2503c041f5a217b3b6424a08facd5bb500d --- /dev/null +++ b/services/param/watcher/agent/watcher.h @@ -0,0 +1,33 @@ +/* + * 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 START_WATCHER_H +#define START_WATCHER_H + +#include +#include "watcher_stub.h" + +namespace OHOS { +namespace init_param { +class Watcher : public WatcherStub { +public: + explicit Watcher() = default; + ~Watcher() = default; + + void OnParamerterChange(const std::string &name, const std::string &value) override; +}; +} // namespace init_param +} // namespace OHOS +#endif // START_WATCHER_H \ No newline at end of file diff --git a/services/param/watcher/agent/watcher_manager_kits.cpp b/services/param/watcher/agent/watcher_manager_kits.cpp new file mode 100755 index 0000000000000000000000000000000000000000..0a60e7d08e94e960bc81a5e6ca0c8b60ceacb01c --- /dev/null +++ b/services/param/watcher/agent/watcher_manager_kits.cpp @@ -0,0 +1,162 @@ +/* + * 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 "watcher_manager_kits.h" + +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "iwatcher.h" +#include "iwatcher_manager.h" +#include "param_request.h" +#include "system_ability_definition.h" +#include "watcher_utils.h" + +namespace OHOS { +namespace init_param { +WatcherManagerKits &WatcherManagerKits::GetInstance() +{ + return DelayedRefSingleton::GetInstance(); +} + +WatcherManagerKits::WatcherManagerKits() {} + +WatcherManagerKits::~WatcherManagerKits() {} + +void WatcherManagerKits::ResetService(const wptr &remote) +{ + WATCHER_LOGI("Remote is dead, reset service instance"); + std::lock_guard lock(lock_); + if (watcherManager_ != nullptr) { + sptr object = watcherManager_->AsObject(); + if ((object != nullptr) && (remote == object)) { + object->RemoveDeathRecipient(deathRecipient_); + watcherManager_ = nullptr; + } + } +} + +sptr WatcherManagerKits::GetService() +{ + std::lock_guard lock(lock_); + if (watcherManager_ != nullptr) { + return watcherManager_; + } + + sptr samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + WATCHER_CHECK(samgr != nullptr, return nullptr, "Get samgr failed"); + sptr object = samgr->GetSystemAbility(PARAM_WATCHER_DISTRIBUTED_SERVICE_ID); + WATCHER_CHECK(object != nullptr, return nullptr, "Get watcher manager object from samgr failed"); + if (deathRecipient_ == nullptr) { + deathRecipient_ = new DeathRecipient(); + } + + if ((object->IsProxyObject()) && (!object->AddDeathRecipient(deathRecipient_))) { + WATCHER_LOGE("Failed to add death recipient"); + } + watcherManager_ = iface_cast(object); + if (watcherManager_ == nullptr) { + WATCHER_LOGE("watcher manager iface_cast failed"); + } + return watcherManager_; +} + +void WatcherManagerKits::DeathRecipient::OnRemoteDied(const wptr &remote) +{ + DelayedRefSingleton::GetInstance().ResetService(remote); +} + +WatcherManagerKits::ParamWatcherKitPtr WatcherManagerKits::GetParamWatcher(const std::string &keyPrefix) +{ + std::lock_guard lock(mutex_); + if (watchers_.find(keyPrefix) == watchers_.end()) { + return nullptr; + } + return watchers_[keyPrefix]; +} + +void WatcherManagerKits::SetParamWatcher(const std::string &keyPrefix, ParamWatcherKitPtr watcher) +{ + std::lock_guard lock(mutex_); + if (watchers_.find(keyPrefix) != watchers_.end()) { + watchers_[keyPrefix] = watcher; + } +} + +int32_t WatcherManagerKits::AddWatcher(const std::string &keyPrefix, ParameterChangePtr callback, void *context) +{ + WATCHER_LOGI("AddWatcher keyPrefix %s", keyPrefix.c_str()); + ParamWatcherKitPtr watcher = GetParamWatcher(keyPrefix); + if (watcher != nullptr) { + WATCHER_LOGE("Has been watched by keyPrefix %s", keyPrefix.c_str()); + return 0; + } + watcher = new ParamWatcher(keyPrefix, callback, context); + WATCHER_CHECK(watcher != nullptr, return -1, "Failed to create watcher for %s", keyPrefix.c_str()); + auto watcherManager = GetService(); + WATCHER_CHECK(watcherManager != nullptr, return -1, "Failed to get watcher manager"); + uint32_t watcherId = watcherManager->AddWatcher(keyPrefix, watcher); + WATCHER_CHECK(watcherId != 0, return -1, "Failed to add watcher for %s", keyPrefix.c_str()); + watcher->SetWatcherId(watcherId); + SetParamWatcher(keyPrefix, watcher); + return watcher->GetWatcherId(); +} + +int32_t WatcherManagerKits::DelWatcher(const std::string &keyPrefix) +{ + ParamWatcherKitPtr watcher = GetParamWatcher(keyPrefix); + if (watcher == nullptr) { + WATCHER_LOGE("Has been watched by keyPrefix %s", keyPrefix.c_str()); + return 0; + } + auto watcherManager = GetService(); + WATCHER_CHECK(watcherManager != nullptr, return -1, "Failed to get watcher manager"); + int ret = watcherManager->DelWatcher(keyPrefix, watcher->GetWatcherId()); + WATCHER_CHECK(ret == 0, return -1, "Failed to delete watcher for %s", keyPrefix.c_str()); + SetParamWatcher(keyPrefix, nullptr); + return 0; +} + +void WatcherManagerKits::ParamWatcher::OnParamerterChange(const std::string &name, const std::string &value) +{ + WATCHER_LOGD("OnParamerterChange name %s value %s", name.c_str(), value.c_str()); + if (callback_ != nullptr) { + callback_(name.c_str(), value.c_str(), context_); + } +} +} // namespace init_param +} // namespace OHOS + +int SystemWatchParameter(const char *keyPrefix, ParameterChangePtr callback, void *context) +{ + if (keyPrefix == nullptr) { + return PARAM_CODE_INVALID_PARAM; + } + int ret = 0; + std::string key(keyPrefix); + if (key.rfind("*") == key.length() - 1) { + ret = WatchParamCheck(key.substr(0, key.length() - 1).c_str()); + } else { + ret = WatchParamCheck(keyPrefix); + } + if (ret != 0) { + return ret; + } + OHOS::init_param::WatcherManagerKits &instance = OHOS::init_param::WatcherManagerKits::GetInstance(); + if (callback != nullptr) { + ret = (instance.AddWatcher(keyPrefix, callback, context) > 0) ? 0 : -1; + } else { + ret = instance.DelWatcher(keyPrefix); + } + return ret; +} diff --git a/services/param/watcher/agent/watcher_manager_kits.h b/services/param/watcher/agent/watcher_manager_kits.h new file mode 100755 index 0000000000000000000000000000000000000000..acca6cd796e8319ee9eb194dad31788c676ff6f4 --- /dev/null +++ b/services/param/watcher/agent/watcher_manager_kits.h @@ -0,0 +1,88 @@ +/* + * 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 WATCHER_MANAGER_KITS_H +#define WATCHER_MANAGER_KITS_H +#include +#include +#include + +#include "iwatcher.h" +#include "iwatcher_manager.h" +#include "singleton.h" +#include "sys_param.h" +#include "watcher.h" +#include "watcher_utils.h" + +namespace OHOS { +namespace init_param { +class WatcherManagerKits final : public DelayedRefSingleton { + DECLARE_DELAYED_REF_SINGLETON(WatcherManagerKits); +public: + DISALLOW_COPY_AND_MOVE(WatcherManagerKits); + + static WatcherManagerKits &GetInstance(); + int32_t AddWatcher(const std::string &keyPrefix, ParameterChangePtr callback, void *context); + int32_t DelWatcher(const std::string &keyPrefix); +private: + class ParamWatcher final : public Watcher { + public: + ParamWatcher(const std::string &key, ParameterChangePtr callback, void *context) + : keyPrefix_(key), callback_(callback), context_(context) {} + ~ParamWatcher() = default; + + void OnParamerterChange(const std::string &name, const std::string &value) override; + + void SetWatcherId(uint32_t watcherId) + { + watcherId_ = watcherId; + } + uint32_t GetWatcherId() + { + return watcherId_; + } + + private: + uint32_t watcherId_{ 0 }; + std::string keyPrefix_{}; + ParameterChangePtr callback_{ nullptr }; + void *context_ { nullptr }; + }; + + // For death event procession + class DeathRecipient final : public IRemoteObject::DeathRecipient { + public: + DeathRecipient() = default; + ~DeathRecipient() final = default; + DISALLOW_COPY_AND_MOVE(DeathRecipient); + void OnRemoteDied(const wptr &remote) final; + }; + +private: + using ParamWatcherKitPtr = sptr; + ParamWatcherKitPtr GetParamWatcher(const std::string &keyPrefix); + void SetParamWatcher(const std::string &keyPrefix, ParamWatcherKitPtr watcher); + void ResetService(const wptr &remote); + sptr GetService(); + std::mutex lock_; + sptr watcherManager_{}; + sptr deathRecipient_{}; + + std::mutex mutex_; + std::map watchers_; +}; +} // namespace init_param +} // namespace OHOS +#endif // WATCHER_MANAGER_KITS_H diff --git a/services/param/watcher/agent/watcher_manager_proxy.cpp b/services/param/watcher/agent/watcher_manager_proxy.cpp new file mode 100755 index 0000000000000000000000000000000000000000..28dc1de2994b7a91d1ff81b6fe9f0d452fbdfe87 --- /dev/null +++ b/services/param/watcher/agent/watcher_manager_proxy.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "watcher_manager_proxy.h" +#include "watcher_utils.h" + +namespace OHOS { +namespace init_param { +uint32_t WatcherManagerProxy::AddWatcher(const std::string &keyPrefix, const sptr &watcher) +{ + WATCHER_CHECK(watcher != nullptr, return ERR_INVALID_VALUE, "Invalid param"); + WATCHER_LOGD("WatcherManagerProxy::AddWatcher %s", keyPrefix.c_str()); + auto remote = Remote(); + WATCHER_CHECK(remote != nullptr, return 0, "Can not get remote"); + + MessageParcel data; + data.WriteString(keyPrefix); + bool ret = data.WriteRemoteObject(watcher->AsObject()); + WATCHER_CHECK(ret, return 0, "Can not get remote"); + + MessageParcel reply; + MessageOption option { MessageOption::TF_SYNC }; + int32_t res = remote->SendRequest(ADD_WATCHER, data, reply, option); + WATCHER_CHECK(res == ERR_OK, return 0, "Transact error"); + return reply.ReadUint32(); +} +int32_t WatcherManagerProxy::DelWatcher(const std::string &keyPrefix, uint32_t watcherId) +{ + WATCHER_LOGD("WatcherManagerProxy::DelWatcher %s", keyPrefix.c_str()); + auto remote = Remote(); + WATCHER_CHECK(remote != nullptr, return ERR_FLATTEN_OBJECT, "Can not get remote"); + + MessageParcel data; + data.WriteString(keyPrefix); + data.WriteUint32(watcherId); + MessageParcel reply; + MessageOption option { MessageOption::TF_SYNC }; + int32_t res = remote->SendRequest(DEL_WATCHER, data, reply, option); + WATCHER_CHECK(res == ERR_OK, return ERR_FLATTEN_OBJECT, "Transact error"); + return reply.ReadInt32(); +} +} +} // namespace OHOS diff --git a/services/param/watcher/agent/watcher_manager_proxy.h b/services/param/watcher/agent/watcher_manager_proxy.h new file mode 100755 index 0000000000000000000000000000000000000000..b8b5961c0884dada128645d8ec6689d0f9e48bfc --- /dev/null +++ b/services/param/watcher/agent/watcher_manager_proxy.h @@ -0,0 +1,35 @@ +/* + * 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_WATCH_MANAGER_PROXY_H +#define STARTUP_WATCH_MANAGER_PROXY_H + +#include "iremote_proxy.h" +#include "iwatcher_manager.h" + +namespace OHOS { +namespace init_param { +class WatcherManagerProxy : public IRemoteProxy { +public: + explicit WatcherManagerProxy(const sptr &impl) : IRemoteProxy(impl) {} + + uint32_t AddWatcher(const std::string &keyPrefix, const sptr &watcher) override; + int32_t DelWatcher(const std::string &keyPrefix, uint32_t watcherId) override; +private: + static inline BrokerDelegator delegator_; +}; +} // namespace init_param +} // namespace OHOS +#endif // STARTUP_WATCH_MANAGER_PROXY_H \ No newline at end of file diff --git a/services/param/watcher/agent/watcher_stub.cpp b/services/param/watcher/agent/watcher_stub.cpp new file mode 100755 index 0000000000000000000000000000000000000000..3bc29a0251d719cae9c8db51457de2c4f790252a --- /dev/null +++ b/services/param/watcher/agent/watcher_stub.cpp @@ -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 "watcher_stub.h" + +#include "securec.h" +#include "watcher_utils.h" + +namespace OHOS { +namespace init_param { +int32_t WatcherStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + switch (code) { + case PARAM_CHANGE: { + std::string name = data.ReadString(); + std::string value = data.ReadString(); + OnParamerterChange(name, value); + break; + } + default: { + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); + } + } + return 0; +} +} // namespace init_param +} // namespace OHOS diff --git a/services/param/watcher/agent/watcher_stub.h b/services/param/watcher/agent/watcher_stub.h new file mode 100755 index 0000000000000000000000000000000000000000..64c06f3cb4b52fa02827cd87c6d4b73f425bf1bc --- /dev/null +++ b/services/param/watcher/agent/watcher_stub.h @@ -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. + */ + +#ifndef STARTUP_WATCHER_STUB_H_ +#define STARTUP_WATCHER_STUB_H_ + +#include "iremote_stub.h" +#include "iwatcher.h" +#include "message_parcel.h" +#include "parcel.h" + +namespace OHOS { +namespace init_param { +class WatcherStub : public IRemoteStub { +public: + int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; +}; +} // namespace init_param +} // namespace OHOS +#endif // !defined(STARTUP_WATCHER_STUB_H_) diff --git a/services/param/watcher/etc/param_watcher.cfg b/services/param/watcher/etc/param_watcher.cfg new file mode 100755 index 0000000000000000000000000000000000000000..a6b3a15f4257630fc22960048718b4e96ff49d52 --- /dev/null +++ b/services/param/watcher/etc/param_watcher.cfg @@ -0,0 +1,16 @@ +{ + "jobs" : [{ + "name" : "boot", + "cmds" : [ + "start param_watcher" + ] + } + ], + "services" : [{ + "name" : "param_watcher", + "path" : ["/system/bin/sa_main", "/system/profile/param_watcher.xml"], + "uid" : "system", + "gid" : ["system", "shell"] + } + ] +} diff --git a/services/param/watcher/etc/param_watcher.rc b/services/param/watcher/etc/param_watcher.rc new file mode 100755 index 0000000000000000000000000000000000000000..fdfbd3b0ba9ea01e70e6114c455fbf5e025d5ca7 --- /dev/null +++ b/services/param/watcher/etc/param_watcher.rc @@ -0,0 +1,21 @@ +# 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. +service param_watcher /system/bin/sa_main /system/profile/param_watcher.xml +class z_core +user system +group system shell +seclabel u:r:param_watcher:s0 + +on boot + start param_watcher + diff --git a/services/param/watcher/include/iwatcher.h b/services/param/watcher/include/iwatcher.h new file mode 100755 index 0000000000000000000000000000000000000000..957a0a0da1e99fe55b12e18783bd1189fd3e340f --- /dev/null +++ b/services/param/watcher/include/iwatcher.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 ISTARTUP_WATCHER_H +#define ISTARTUP_WATCHER_H + +#include +#include "iremote_broker.h" +#include "iremote_proxy.h" + +namespace OHOS { +namespace init_param { +class IWatcher : public OHOS::IRemoteBroker { +public: + virtual ~IWatcher() = default; + enum { + PARAM_CHANGE = 1, + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.Startup.IWatcher"); +public: + virtual void OnParamerterChange(const std::string &name, const std::string &value) = 0; +}; +} // namespace init_param +} // namespace OHOS +#endif // ISTARTUP_WATCHER_H diff --git a/services/param/watcher/include/iwatcher_manager.h b/services/param/watcher/include/iwatcher_manager.h new file mode 100755 index 0000000000000000000000000000000000000000..ac503463e252a9415ae4d6a996e8cb8fd6b70da7 --- /dev/null +++ b/services/param/watcher/include/iwatcher_manager.h @@ -0,0 +1,40 @@ +/* + * 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 ISTARTUP_WATCHER_MANAGER_H +#define ISTARTUP_WATCHER_MANAGER_H + +#include +#include "iremote_broker.h" +#include "iremote_proxy.h" +#include "iwatcher.h" + +namespace OHOS { +namespace init_param { +class IWatcherManager : public OHOS::IRemoteBroker { +public: + enum { + ADD_WATCHER, + DEL_WATCHER + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.Startup.IWatcherManager"); +public: + virtual uint32_t AddWatcher(const std::string &keyPrefix, const sptr &watcher) = 0; + virtual int32_t DelWatcher(const std::string &keyPrefix, uint32_t watcherId) = 0; +}; +} // namespace update_engine +} // namespace OHOS +#endif // ISTARTUP_WATCHER_MANAGER_H diff --git a/services/param/watcher/include/watcher_utils.h b/services/param/watcher/include/watcher_utils.h new file mode 100755 index 0000000000000000000000000000000000000000..1026e5c47203bae39226e7d5927d9e2c584a0de2 --- /dev/null +++ b/services/param/watcher/include/watcher_utils.h @@ -0,0 +1,45 @@ +/* + * 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_WATCHER_UTILS_H +#define STARTUP_WATCHER_UTILS_H +#include + +#include "init_log.h" +#include "iremote_broker.h" +#include "iremote_proxy.h" + +#include "securec.h" + +namespace OHOS { +namespace init_param { +#define UNUSED(x) (void)(x) + +#ifndef LABEL +#define LABEL "Watcher" +#endif + +#define WATCHER_LOGI(fmt, ...) STARTUP_LOGI(LABEL, fmt, ##__VA_ARGS__) +#define WATCHER_LOGE(fmt, ...) STARTUP_LOGE(LABEL, fmt, ##__VA_ARGS__) +#define WATCHER_LOGD(fmt, ...) STARTUP_LOGD(LABEL, fmt, ##__VA_ARGS__) + +#define WATCHER_CHECK(retCode, exper, ...) \ + if (!(retCode)) { \ + WATCHER_LOGE(__VA_ARGS__); \ + exper; \ + } +} // namespace init_param +} // namespace OHOS +#endif // STARTUP_WATCHER_UTILS_H diff --git a/services/param/watcher/proxy/watcher_manager.cpp b/services/param/watcher/proxy/watcher_manager.cpp new file mode 100755 index 0000000000000000000000000000000000000000..7f615d7b8f37818dd4edc2b942e026bd54e00347 --- /dev/null +++ b/services/param/watcher/proxy/watcher_manager.cpp @@ -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 "watcher_manager.h" +#include +#include +#include +#include +#include + +#include "param_message.h" +#include "sys_param.h" +#include "system_ability_definition.h" +#include "watcher_utils.h" + +namespace OHOS { +namespace init_param { +REGISTER_SYSTEM_ABILITY_BY_ID(WatcherManager, PARAM_WATCHER_DISTRIBUTED_SERVICE_ID, true) + +const static int32_t INVALID_SOCKET = -1; +const static int32_t SLEEP_TIME = 2000; +uint32_t WatcherManager::AddWatcher(const std::string &keyPrefix, const sptr &watcher) +{ + WATCHER_CHECK(watcher != nullptr, return 0, "Invalid remove watcher for %s", keyPrefix.c_str()); + if (watcherId_ == 0) { + watcherId_++; + } + ParamWatcherPtr paramWather = std::make_shared(watcherId_, watcher); + WATCHER_CHECK(paramWather != nullptr, return 0, "Failed to create watcher for %s", keyPrefix.c_str()); + WatcherGroupPtr group = GetWatcherGroup(keyPrefix); + if (group == nullptr) { + group = std::make_shared(++groupId_, keyPrefix); + } + WATCHER_CHECK(group != nullptr, return 0, "Failed to create group for %s", keyPrefix.c_str()); + AddWatcherGroup(keyPrefix, group); + + if (group->Emptry()) { + StartLoop(); + SendMessage(group, MSG_ADD_WATCHER); + } + SendLocalChange(keyPrefix, paramWather); + group->AddWatcher(paramWather); + WATCHER_LOGD("AddWatcher %s watcherId: %u", keyPrefix.c_str(), paramWather->GetWatcherId()); + return paramWather->GetWatcherId(); +} + +int32_t WatcherManager::DelWatcher(const std::string &keyPrefix, uint32_t watcherId) +{ + auto group = GetWatcherGroup(keyPrefix); + if (group == nullptr) { + WATCHER_LOGE("DelWatcher can not find group %s", keyPrefix.c_str()); + return 0; + } + group->DelWatcher(watcherId); + if (group->Emptry()) { + SendMessage(group, MSG_DEL_WATCHER); + DelWatcherGroup(group); + } + return 0; +} + +int WatcherManager::SendMessage(WatcherGroupPtr group, int type) +{ + ParamMessage *request = nullptr; + request = (ParamMessage *)CreateParamMessage(type, group->GetKeyPrefix().c_str(), sizeof(ParamMessage)); + PARAM_CHECK(request != NULL, return PARAM_CODE_ERROR, "Failed to malloc for watch"); + request->id.watcherId = group->GetGroupId(); + request->msgSize = sizeof(ParamMessage); + do { + int fd = GetServerFd(false); + if (fd != INVALID_SOCKET) { + ssize_t sendLen = send(serverFd_, (char *)request, request->msgSize, 0); + if (sendLen > 0) { + PARAM_LOGD("SendMessage key: %s %d success", group->GetKeyPrefix().c_str(), type); + break; + } + } + // fail, try again + PARAM_LOGE("Failed to connect server %s, try again", PIPE_NAME); + fd = GetServerFd(true); + } while (1); + free(request); + return 0; +} + +void WatcherManager::ProcessWatcherMessage(const char *buffer, uint32_t dataSize) +{ + ParamMessage *msg = (ParamMessage *)buffer; + uint32_t offset = 0; + if (msg->type != MSG_NOTIFY_PARAM) { + return; + } + PARAM_CHECK(msg->msgSize <= dataSize, return, "Invalid msg size %d", msg->msgSize); + ParamMsgContent *valueContent = GetNextContent((const ParamMessage *)msg, &offset); + PARAM_CHECK(valueContent != NULL, return, "Invalid msg "); + PARAM_LOGI("ProcessWatcherMessage name %s watcherId %u ", msg->key, msg->id.watcherId); + + WatcherGroupPtr group = GetWatcherGroup(msg->id.watcherId); + if (group != nullptr) { + group->ProcessParameterChange(msg->key, valueContent->content); + } +} + +WatcherManager::WatcherGroupPtr WatcherManager::GetWatcherGroup(uint32_t groupId) +{ + std::lock_guard lock(watcherMutex_); + if (watcherGroups_.find(groupId) != watcherGroups_.end()) { + return watcherGroups_[groupId]; + } + return nullptr; +} + +WatcherManager::WatcherGroupPtr WatcherManager::GetWatcherGroup(const std::string &keyPrefix) +{ + if (groupMap_.find(keyPrefix) == groupMap_.end()) { + return nullptr; + } + return GetWatcherGroup(groupMap_[keyPrefix]); +} + +void WatcherManager::AddWatcherGroup(const std::string &keyPrefix, WatcherGroupPtr group) +{ + uint32_t groupId = group->GetGroupId(); + groupMap_[keyPrefix] = groupId; + + std::lock_guard lock(watcherMutex_); + if (watcherGroups_.find(groupId) != watcherGroups_.end()) { + return; + } + watcherGroups_[groupId] = group; +} + +void WatcherManager::DelWatcherGroup(WatcherGroupPtr group) +{ + groupMap_[group->GetKeyPrefix()] = 0; + std::lock_guard lock(watcherMutex_); + watcherGroups_[group->GetGroupId()] = nullptr; +} + +void WatcherManager::WatcherGroup::AddWatcher(const ParamWatcherPtr &watcher) +{ + watchers_[watcher->GetWatcherId()] = watcher; +} + +void WatcherManager::WatcherGroup::DelWatcher(uint32_t watcherId) +{ + if (watchers_.find(watcherId) != watchers_.end()) { + watchers_[watcherId] = nullptr; + } +} + +WatcherManager::ParamWatcherPtr WatcherManager::WatcherGroup::GetWatcher(uint32_t watcherId) +{ + if (watchers_.find(watcherId) != watchers_.end()) { + return watchers_[watcherId]; + } + return nullptr; +} + +void WatcherManager::WatcherGroup::ProcessParameterChange(const std::string &name, const std::string &value) +{ + // walk watcher + for (auto iter = watchers_.begin(); iter != watchers_.end(); iter++) { + iter->second->ProcessParameterChange(name, value); + } +} + +static int FilterParam(const char *name, const std::string &keyPrefix) +{ + if (keyPrefix.rfind("*") == keyPrefix.length() - 1) { + return strncmp(name, keyPrefix.c_str(), keyPrefix.length() - 1) == 0; + } + return strcmp(name, keyPrefix.c_str()) == 0; +} + +void WatcherManager::SendLocalChange(const std::string &keyPrefix, ParamWatcherPtr watcher) +{ + struct Context { + char *buffer; + ParamWatcherPtr watcher; + std::string keyPrefix; + }; + std::vector buffer(PARAM_NAME_LEN_MAX + PARAM_CONST_VALUE_LEN_MAX); + struct Context context = {buffer.data(), watcher, keyPrefix}; + // walk watcher + SystemTraversalParameter( + [](ParamHandle handle, void *cookie) { + struct Context *context = (struct Context *)(cookie); + SystemGetParameterName(handle, context->buffer, PARAM_NAME_LEN_MAX); + if (!FilterParam(context->buffer, context->keyPrefix)) { + return; + } + uint32_t size = PARAM_CONST_VALUE_LEN_MAX; + SystemGetParameterValue(handle, context->buffer + PARAM_NAME_LEN_MAX, &size); + PARAM_LOGD("SendLocalChange key %s value: %s ", context->buffer, context->buffer + PARAM_NAME_LEN_MAX); + context->watcher->ProcessParameterChange(context->buffer, context->buffer + PARAM_NAME_LEN_MAX); + }, (void *)&context); +} + +void WatcherManager::RunLoop() +{ + const int32_t RECV_BUFFER_MAX = 5 * 1024; + char *buffer = (char *)malloc(RECV_BUFFER_MAX); + PARAM_CHECK(buffer != NULL, return, "Failed to create buffer for recv"); + while (!stop) { + int fd = GetServerFd(false); + ssize_t recvLen = recv(fd, buffer, RECV_BUFFER_MAX, 0); + if (recvLen <= 0) { + if (errno == EAGAIN) { // 超时,继续等待 + continue; + } + fd = GetServerFd(true); + PARAM_LOGE("Failed to recv msg from server errno %d", errno); + } + PARAM_LOGD("Recv msg from server"); + if (recvLen >= (ssize_t)sizeof(ParamMessage)) { + ProcessWatcherMessage(buffer, recvLen); + } + } + PARAM_LOGI("Exit runLoop"); +} + +void WatcherManager::StartLoop() +{ + if (pRecvThread_ == nullptr) { + pRecvThread_ = new (std::nothrow)std::thread(&WatcherManager::RunLoop, this); + WATCHER_CHECK(pRecvThread_ != nullptr, return, "Failed to create thread"); + } +} + +int WatcherManager::GetServerFd(bool retry) +{ + std::lock_guard lock(mutex_); + if (retry && serverFd_ != INVALID_SOCKET) { + close(serverFd_); + serverFd_ = INVALID_SOCKET; + } + if (serverFd_ != INVALID_SOCKET) { + return serverFd_; + } + struct timeval time; + time.tv_sec = 1; + time.tv_usec = 0; + do { + serverFd_ = socket(AF_UNIX, SOCK_STREAM, 0); + int ret = ConntectServer(serverFd_, PIPE_NAME); + if (ret != 0) { + close(serverFd_); + serverFd_ = INVALID_SOCKET; + usleep(SLEEP_TIME); + } else { + (void)setsockopt(serverFd_, SOL_SOCKET, SO_RCVTIMEO, &time, sizeof(struct timeval)); + break; + } + } while (1); + return serverFd_; +} + +void WatcherManager::OnStart() +{ + PARAM_LOGI("WatcherManager OnStart"); + bool res = Publish(this); + if (!res) { + PARAM_LOGI("WatcherManager OnStart failed"); + } + return; +} + +void WatcherManager::OnStop() +{ + PARAM_LOGI("WatcherManager OnStop"); + stop = true; + { + std::lock_guard lock(mutex_); + close(serverFd_); + serverFd_ = INVALID_SOCKET; + } + if (pRecvThread_ != nullptr) { + pRecvThread_->join(); + delete pRecvThread_; + pRecvThread_ = nullptr; + } +} +} // namespace init_param +} // namespace OHOS diff --git a/services/param/watcher/proxy/watcher_manager.h b/services/param/watcher/proxy/watcher_manager.h new file mode 100755 index 0000000000000000000000000000000000000000..079d52bdcb065c6f27a59c234de4bbc3844de105 --- /dev/null +++ b/services/param/watcher/proxy/watcher_manager.h @@ -0,0 +1,120 @@ +/* + * 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 WATCHER_MANAGER_H_ +#define WATCHER_MANAGER_H_ +#include +#include +#include +#include +#include +#include + +#include "iremote_stub.h" +#include "iwatcher.h" +#include "message_parcel.h" +#include "parcel.h" +#include "system_ability.h" +#include "watcher_manager_stub.h" + +namespace OHOS { +namespace init_param { +class WatcherManager : public SystemAbility, public WatcherManagerStub { +public: + DECLARE_SYSTEM_ABILITY(WatcherManager); + DISALLOW_COPY_AND_MOVE(WatcherManager); + explicit WatcherManager(int32_t systemAbilityId, bool runOnCreate = true) + : SystemAbility(systemAbilityId, runOnCreate) {} + ~WatcherManager() override + { + watcherGroups_.clear(); + groupMap_.clear(); + }; + + class ParamWatcher { + public: + ParamWatcher(uint32_t watcherId, const sptr &watcher) : watcherId_(watcherId), watcher_(watcher) {} + ~ParamWatcher() = default; + uint32_t GetWatcherId() + { + return watcherId_; + } + void ProcessParameterChange(const std::string &name, const std::string &value) + { + watcher_->OnParamerterChange(name, value); + } + private: + uint32_t watcherId_ = { 0 }; + sptr watcher_; + }; + using ParamWatcherPtr = std::shared_ptr; + + class WatcherGroup { + public: + WatcherGroup(uint32_t groupId, const std::string &key) : groupId_(groupId), keyPrefix_(key) {} + ~WatcherGroup() = default; + void AddWatcher(const ParamWatcherPtr &watcher); + void DelWatcher(uint32_t watcherId); + void ProcessParameterChange(const std::string &name, const std::string &value); + ParamWatcherPtr GetWatcher(uint32_t watcherId); + + const std::string GetKeyPrefix() + { + return keyPrefix_; + } + bool Emptry() + { + return watchers_.size() == 0; + } + uint32_t GetGroupId() + { + return groupId_; + } + private: + uint32_t groupId_; + std::string keyPrefix_ { }; + std::map watchers_; + }; + using WatcherGroupPtr = std::shared_ptr; + + uint32_t AddWatcher(const std::string &keyPrefix, const sptr &watcher) override; + int32_t DelWatcher(const std::string &keyPrefix, uint32_t watcherId) override; +protected: + void OnStart() override; + void OnStop() override; +private: + WatcherGroupPtr GetWatcherGroup(uint32_t groupId); + WatcherGroupPtr GetWatcherGroup(const std::string &keyPrefix); + void AddWatcherGroup(const std::string &keyPrefix, WatcherGroupPtr group); + void DelWatcherGroup(WatcherGroupPtr group); + void RunLoop(); + void StartLoop(); + void SendLocalChange(const std::string &keyPrefix, ParamWatcherPtr watcher); + void ProcessWatcherMessage(const char *buffer, uint32_t dataSize); + int SendMessage(WatcherGroupPtr group, int type); + int GetServerFd(bool retry); +private: + std::atomic watcherId_ { 0 }; + std::atomic groupId_ { 0 }; + std::mutex mutex_; + std::mutex watcherMutex_; + int serverFd_ { -1 }; + std::thread *pRecvThread_ { nullptr }; + std::atomic stop { false }; + std::map groupMap_ {}; + std::map watcherGroups_ {}; +}; +} // namespace init_param +} // namespace OHOS +#endif // WATCHER_MANAGER_H_ \ No newline at end of file diff --git a/services/param/watcher/proxy/watcher_manager_stub.cpp b/services/param/watcher/proxy/watcher_manager_stub.cpp new file mode 100755 index 0000000000000000000000000000000000000000..6c1ecfe1e3074bac3f9f6c3c1a16e8751ca799cf --- /dev/null +++ b/services/param/watcher/proxy/watcher_manager_stub.cpp @@ -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 "watcher_manager_stub.h" +#include "watcher_utils.h" + +namespace OHOS { +namespace init_param { +int32_t WatcherManagerStub::OnRemoteRequest(uint32_t code, + MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + switch (code) { + case ADD_WATCHER: { + std::string key = data.ReadString(); + auto remote = data.ReadRemoteObject(); + // 0 is invalid watcherId + WATCHER_CHECK(remote != nullptr, reply.WriteUint32(0); + return 0, "Failed to read remote watcher"); + uint32_t watcherId = AddWatcher(key, iface_cast(remote)); + reply.WriteUint32(watcherId); + break; + } + case DEL_WATCHER: { + std::string key = data.ReadString(); + uint32_t watcherId = data.ReadUint32(); + int ret = DelWatcher(key, watcherId); + reply.WriteInt32(ret); + break; + } + default: { + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); + } + } + return 0; +} +} +} diff --git a/services/param/watcher/proxy/watcher_manager_stub.h b/services/param/watcher/proxy/watcher_manager_stub.h new file mode 100755 index 0000000000000000000000000000000000000000..1fbbba53ae9df203c9eda093064e0172d63e8a15 --- /dev/null +++ b/services/param/watcher/proxy/watcher_manager_stub.h @@ -0,0 +1,33 @@ +/* + * 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 WATCHER_MANAGER_STUB_H_ +#define WATCHER_MANAGER_STUB_H_ + +#include "iremote_stub.h" +#include "iwatcher_manager.h" +#include "message_parcel.h" +#include "parcel.h" + +namespace OHOS { +namespace init_param { +class WatcherManagerStub : public IRemoteStub { +public: + int32_t OnRemoteRequest(uint32_t code, MessageParcel& data, MessageParcel& reply, + MessageOption &option) override; +}; +} +} +#endif // WATCHER_MANAGER_STUB_H_ \ No newline at end of file diff --git a/services/param/watcher/proxy/watcher_proxy.cpp b/services/param/watcher/proxy/watcher_proxy.cpp new file mode 100755 index 0000000000000000000000000000000000000000..62e6aaeb513984f7bb645865b4cf8c6237be1a50 --- /dev/null +++ b/services/param/watcher/proxy/watcher_proxy.cpp @@ -0,0 +1,42 @@ +/* + * 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 "watcher_proxy.h" + +#include +#include "parcel.h" +#include "message_parcel.h" +#include "watcher_utils.h" +#include "securec.h" + +namespace OHOS { +namespace init_param { +void WatcherProxy::OnParamerterChange(const std::string &name, const std::string &value) +{ + WATCHER_LOGD("WatcherProxy::OnParamerterChange %s %s", name.c_str(), value.c_str()); + MessageParcel data; + MessageParcel reply; + MessageOption option { MessageOption::TF_ASYNC }; + auto remote = Remote(); + WATCHER_CHECK(remote != nullptr, return, "Can not get remote"); + + data.WriteString(name); + data.WriteString(value); + int ret = remote->SendRequest(PARAM_CHANGE, data, reply, option); + WATCHER_CHECK(ret == ERR_OK, return, "Can not SendRequest for name %s", name.c_str()); + return; +} +} +} // namespace OHOS diff --git a/services/param/watcher/proxy/watcher_proxy.h b/services/param/watcher/proxy/watcher_proxy.h new file mode 100755 index 0000000000000000000000000000000000000000..877d9f1b42fce7c5a7b8339130ce865927fce19c --- /dev/null +++ b/services/param/watcher/proxy/watcher_proxy.h @@ -0,0 +1,37 @@ +/* + * 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_WATCHER_PROXY_H +#define STARTUP_WATCHER_PROXY_H + +#include "iremote_proxy.h" +#include "iwatcher.h" + +namespace OHOS { +namespace init_param { +class WatcherProxy : public IRemoteProxy { +public: + explicit WatcherProxy(const sptr& impl) : IRemoteProxy(impl) {} + + virtual ~WatcherProxy() = default; + + void OnParamerterChange(const std::string &name, const std::string &value) override; + +private: + static inline BrokerDelegator delegator_; +}; +} +} // namespace OHOS +#endif // STARTUP_WATCHER_PROXY_H \ No newline at end of file diff --git a/services/param/watcher/sa_profile/3901.xml b/services/param/watcher/sa_profile/3901.xml new file mode 100755 index 0000000000000000000000000000000000000000..2c45d21d90b397be482f1b024ed09dd7e0bffb38 --- /dev/null +++ b/services/param/watcher/sa_profile/3901.xml @@ -0,0 +1,24 @@ + + + + param_watcher + + 3901 + libparam_watcher.z.so + true + false + 1 + + diff --git a/services/param/watcher/sa_profile/BUILD.gn b/services/param/watcher/sa_profile/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..7ca4643a16ee62bfabef55ec1e24a3ceeccc5548 --- /dev/null +++ b/services/param/watcher/sa_profile/BUILD.gn @@ -0,0 +1,20 @@ +# 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/sa_profile/sa_profile.gni") + +ohos_sa_profile("param_watcher_profile") { + sources = [ "3901.xml" ] + + part_name = "init" +} diff --git a/services/src/init_capability.c b/services/src/init_capability.c index 58884ef3116c95209184e003e0198586623cc155..d86b4b23334a14c7f5b51736aec8507e10a2aa8d 100644 --- a/services/src/init_capability.c +++ b/services/src/init_capability.c @@ -17,19 +17,16 @@ #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" +#include "init_utils.h" #define MAX_CAPS_CNT_FOR_ONE_SERVICE 100 @@ -93,7 +90,7 @@ static int GetServiceStringCaps(const cJSON* filedJ, Service* curServ) INIT_LOGE("fieldStr is NULL"); break; } - int mapSize = sizeof(g_capStrCapNum) / sizeof(struct CapStrCapNum); // search + int mapSize = ARRAY_LENGTH(g_capStrCapNum); // search int j = 0; for (; j < mapSize; j++) { if (!strcmp(fieldStr, g_capStrCapNum[j].capStr)) { @@ -112,7 +109,7 @@ static int GetServiceStringCaps(const cJSON* filedJ, Service* curServ) return SERVICE_FAILURE; } } - int ret = i == curServ->servPerm.capsCnt ? SERVICE_SUCCESS : SERVICE_FAILURE; + int ret = (i == curServ->servPerm.capsCnt ? SERVICE_SUCCESS : SERVICE_FAILURE); return ret; } @@ -156,7 +153,7 @@ int GetServiceCaps(const cJSON* curArrItem, Service* curServ) 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 + if (curServ->servPerm.caps[i] > CAP_LAST_CAP && curServ->servPerm.caps[i] != FULL_CAP) { // resources will be released by function: ReleaseServiceMem INIT_LOGE("service=%s, caps = %d, error.", curServ->name, curServ->servPerm.caps[i]); return SERVICE_FAILURE; diff --git a/services/src/init_cmds.c b/services/src/init_cmds.c index d929e7976765fa8b75222158416957ae8b6a3eba..9663b4349b9dbc2b8fc8a120baa482904ac01316 100644 --- a/services/src/init_cmds.c +++ b/services/src/init_cmds.c @@ -21,6 +21,7 @@ #ifndef OHOS_LITE #include #endif +#include #include #include #include @@ -69,7 +70,6 @@ int GetParamValue(const char *symValue, char *paramValue, unsigned int paramLen) } char tmpName[MAX_PARAM_NAME_LEN] = {0}; char tmpValue[MAX_PARAM_VALUE_LEN] = {0}; - unsigned int tmpLen = 0; char *p = NULL; char *tmpptr = NULL; p = strchr(symValue, '$'); @@ -77,7 +77,7 @@ int GetParamValue(const char *symValue, char *paramValue, unsigned int paramLen) INIT_CHECK_RETURN_VALUE(strncpy_s(paramValue, paramLen, symValue, paramLen - 1) == EOK, -1); return 0; } - tmpLen = p - symValue; + unsigned int tmpLen = p - symValue; if (tmpLen > 0) { // copy '$' front string INIT_CHECK_RETURN_VALUE(strncpy_s(paramValue, paramLen, symValue, tmpLen) == EOK, -1); } @@ -122,189 +122,192 @@ inline int GetParamValue(const char *symValue, char *paramValue, unsigned int pa } #endif -struct CmdArgs* GetCmd(const char *cmdContent, const char *delim, int argsCount) +static struct CmdArgs *CopyCmd(struct CmdArgs *ctx, const char *cmd, size_t allocSize) +{ + if (cmd == NULL) { + FreeCmd(ctx); + return NULL; + } + + ctx->argv[ctx->argc] = calloc(sizeof(char), allocSize); + INIT_CHECK(ctx->argv[ctx->argc] != NULL, FreeCmd(ctx); + return NULL); + INIT_CHECK(GetParamValue(cmd, ctx->argv[ctx->argc], allocSize) == 0, FreeCmd(ctx); + return NULL); + ctx->argc += 1; + ctx->argv[ctx->argc] = NULL; + return ctx; +} + +#define SKIP_SPACES(p) \ + do { \ + while (isspace(*(p))) { \ + (p)++; \ + } \ + } while (0) + +struct CmdArgs *GetCmd(const char *cmdContent, const char *delim, int argsCount) { INIT_CHECK_RETURN_VALUE(cmdContent != NULL, NULL); struct CmdArgs *ctx = (struct CmdArgs *)malloc(sizeof(struct CmdArgs)); INIT_CHECK_RETURN_VALUE(ctx != NULL, NULL); - if (argsCount > SPACES_CNT_IN_CMD_MAX) { - INIT_LOGW("Too much arguments for command, max number is %d", SPACES_CNT_IN_CMD_MAX); - argsCount = SPACES_CNT_IN_CMD_MAX; - } - ctx->argv = (char**)malloc(sizeof(char*) * (size_t)argsCount + 1); - INIT_CHECK(ctx->argv != NULL, FreeCmd(&ctx); return NULL); + ctx->argv = (char**)malloc(sizeof(char*) * (size_t)(argsCount + 1)); + INIT_CHECK(ctx->argv != NULL, FreeCmd(ctx); + return NULL); - char tmpCmd[MAX_BUFFER]; + char tmpCmd[MAX_BUFFER] = {0}; size_t cmdLength = strlen(cmdContent); if (cmdLength > MAX_BUFFER - 1) { - INIT_LOGE("command line is too larget, should not bigger than %d. ignore...\n", MAX_BUFFER); - FreeCmd(&ctx); + FreeCmd(ctx); return NULL; } - INIT_CHECK(strncpy_s(tmpCmd, MAX_BUFFER - 1, cmdContent, cmdLength) == EOK, - FreeCmd(&ctx); + INIT_CHECK(strncpy_s(tmpCmd, MAX_BUFFER - 1, cmdContent, cmdLength) == EOK, FreeCmd(ctx); return NULL); - tmpCmd[strlen(cmdContent)] = '\0'; char *p = tmpCmd; char *token = NULL; size_t allocSize = 0; // Skip lead whitespaces - while (isspace(*p)) { - p++; - } + SKIP_SPACES(p); ctx->argc = 0; token = strstr(p, delim); if (token == NULL) { // No whitespaces // Make surce there is enough memory to store parameter value allocSize = (size_t)(cmdLength + MAX_PARAM_VALUE_LEN + 1); - ctx->argv[ctx->argc] = calloc(sizeof(char), allocSize); - INIT_CHECK(ctx->argv[ctx->argc] != NULL, FreeCmd(&ctx); return NULL); - INIT_CHECK(GetParamValue(p, ctx->argv[ctx->argc], allocSize) == 0, - FreeCmd(&ctx); return NULL); - ctx->argc += 1; - ctx->argv[ctx->argc] = NULL; - return ctx; + return CopyCmd(ctx, p, allocSize); } - int index = ctx->argc; while (token != NULL) { // Too more arguments, treat rest of data as one argument - if (index == (argsCount - 1)) { + if (ctx->argc == (argsCount - 1)) { break; } *token = '\0'; // replace it with '\0'; allocSize = (size_t)((token - p) + MAX_PARAM_VALUE_LEN + 1); - ctx->argv[index] = calloc(sizeof(char), allocSize); - INIT_CHECK(ctx->argv[index] != NULL, FreeCmd(&ctx); return NULL); - INIT_CHECK(GetParamValue(p, ctx->argv[index], allocSize) == 0, - FreeCmd(&ctx); return NULL); + ctx = CopyCmd(ctx, p, allocSize); + INIT_CHECK_RETURN_VALUE(ctx != NULL, NULL); p = token + 1; // skip '\0' // Skip lead whitespaces - while (isspace(*p)) { - p++; - } - index++; + SKIP_SPACES(p); token = strstr(p, delim); } - ctx->argc = index; if (p < tmpCmd + cmdLength) { // no more white space or encounter max argument count size_t restSize = tmpCmd + cmdLength - p; allocSize = restSize + MAX_PARAM_VALUE_LEN + 1; - ctx->argv[index] = calloc(sizeof(char), allocSize); - INIT_CHECK(ctx->argv[index] != NULL, FreeCmd(&ctx); return NULL); - INIT_CHECK(GetParamValue(p, ctx->argv[index], allocSize) == 0, - FreeCmd(&ctx); return NULL); - ctx->argc = index + 1; + ctx = CopyCmd(ctx, p, allocSize); + INIT_CHECK_RETURN_VALUE(ctx != NULL, NULL); } - - ctx->argv[ctx->argc] = NULL; return ctx; } -void FreeCmd(struct CmdArgs **cmd) +void FreeCmd(struct CmdArgs *cmd) { - struct CmdArgs *tmpCmd = *cmd; - INIT_CHECK_ONLY_RETURN(tmpCmd != NULL); - for (int i = 0; i < tmpCmd->argc; ++i) { - INIT_CHECK(tmpCmd->argv[i] == NULL, free(tmpCmd->argv[i])); + INIT_CHECK_ONLY_RETURN(cmd != NULL); + for (int i = 0; i < cmd->argc; ++i) { + INIT_CHECK(cmd->argv[i] == NULL, free(cmd->argv[i])); } - INIT_CHECK(tmpCmd->argv == NULL, free(tmpCmd->argv)); - free(tmpCmd); + INIT_CHECK(cmd->argv == NULL, free(cmd->argv)); + free(cmd); return; } -#define EXTRACT_ARGS(cmdname, cmdContent, args) \ - struct CmdArgs *ctx = GetCmd(cmdContent, " ", args); \ - if ((ctx == NULL) || (ctx->argv == NULL) || (ctx->argc != args)) { \ - INIT_LOGE("Command \"%s\" with invalid arguments: %s", #cmdname, cmdContent); \ - goto out; \ - } \ - -static void DoSetDomainname(const char *cmdContent, int maxArg) +static void WriteCommon(const char *file, char *buffer, int flags, mode_t mode) { - EXTRACT_ARGS(domainname, cmdContent, maxArg) - int fd = open("/proc/sys/kernel/domainname", O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, - S_IRUSR | S_IWUSR); - if (fd < 0) { - INIT_LOGE("DoSetDomainame failed to open \"/proc/sys/kernel/domainname\". err = %d", errno); - goto out; + if (file == NULL || *file == '\0' || buffer == NULL || *buffer == '\0') { + INIT_LOGE("Invalid arugment"); + return; } + char realPath[PATH_MAX] = {0}; + char *rp = realpath(file, realPath); - size_t size = strlen(ctx->argv[0]); - ssize_t n = write(fd, ctx->argv[0], size); - if (n != (ssize_t)size) { - INIT_LOGE("DoSetHostname failed to write %s to \"/proc/sys/kernel/domainname\". err = %d", errno); + if (rp == NULL) { + INIT_LOGE("Failed resolve real path name of %s", rp); + return; } - close(fd); -out: - FreeCmd(&ctx); + int fd = open(rp, flags, mode); + if (fd >= 0) { + size_t totalSize = strlen(buffer); + size_t written = WriteAll(fd, buffer, totalSize); + if (written != totalSize) { + INIT_LOGE("Write %lu bytes to file failed", totalSize, file); + } + close(fd); + } fd = -1; +} + +static void DoSetDomainname(const char *cmdContent, int maxArg) +{ + struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); + + if ((ctx == NULL) || (ctx->argv == NULL) || (ctx->argc != maxArg)) { + INIT_LOGE("Command setdomainname with invalid arugment"); + FreeCmd(ctx); + return; + } + + WriteCommon("/proc/sys/kernel/domainname", ctx->argv[0], O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, + S_IRUSR | S_IWUSR); + FreeCmd(ctx); return; } static void DoSetHostname(const char *cmdContent, int maxArg) { - EXTRACT_ARGS(hostname, cmdContent, maxArg) - int fd = open("/proc/sys/kernel/hostname", O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, - S_IRUSR | S_IWUSR); - if (fd < 0) { - INIT_LOGE("DoSetHostname failed to open \"/proc/sys/kernel/hostname\". err = %d", errno); - goto out; - } + struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); - size_t size = strlen(ctx->argv[0]); - ssize_t n = write(fd, ctx->argv[0], size); - if (n != (ssize_t)size) { - INIT_LOGE("DoSetHostname failed to write %s to \"/proc/sys/kernel/hostname\". err = %d", errno); + if ((ctx == NULL) || (ctx->argv == NULL) || (ctx->argc != maxArg)) { + INIT_LOGE("Command sethostname with invalid arugment"); + FreeCmd(ctx); + return; } - - close(fd); -out: - FreeCmd(&ctx); - fd = -1; + WriteCommon("/proc/sys/kernel/hostname", ctx->argv[0], O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, + S_IRUSR | S_IWUSR); + FreeCmd(ctx); return; } #ifndef OHOS_LITE static void DoIfup(const char *cmdContent, int maxArg) { - EXTRACT_ARGS(ifup, cmdContent, maxArg) + struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); + if ((ctx == NULL) || (ctx->argv == NULL) || (ctx->argc != maxArg)) { + INIT_LOGE("Command ifup with invalid arguments"); + FreeCmd(ctx); + return; + } + struct ifreq interface; if (strncpy_s(interface.ifr_name, IFNAMSIZ - 1, ctx->argv[0], strlen(ctx->argv[0])) != EOK) { - INIT_LOGE("DoIfup failed to copy interface name"); - goto out; + INIT_LOGE("Failed to copy interface name"); + FreeCmd(ctx); + return; } - INIT_LOGD("interface name: %s", interface.ifr_name); int fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - INIT_LOGE("DoIfup failed to create socket, err = %d", errno); - goto out; - } - - if (ioctl(fd, SIOCGIFFLAGS, &interface) < 0) { - INIT_LOGE("DoIfup failed to do ioctl with command \"SIOCGIFFLAGS\", err = %d", errno); + if (fd >= 0) { + do { + if (ioctl(fd, SIOCGIFFLAGS, &interface) < 0) { + INIT_LOGE("Failed to do ioctl with command \"SIOCGIFFLAGS\", err = %d", errno); + break; + } + interface.ifr_flags |= IFF_UP; + if (ioctl(fd, SIOCSIFFLAGS, &interface) < 0) { + INIT_LOGE("Failed to do ioctl with command \"SIOCSIFFLAGS\", err = %d", errno); + break; + } + } while (0); close(fd); fd = -1; - goto out; - } - interface.ifr_flags |= IFF_UP; - - if (ioctl(fd, SIOCSIFFLAGS, &interface) < 0) { - INIT_LOGE("DoIfup failed to do ioctl with command \"SIOCSIFFLAGS\", err = %d", errno); } - close(fd); -out: - FreeCmd(&ctx); - fd = -1; + FreeCmd(ctx); return; } #endif @@ -312,18 +315,14 @@ out: static void DoSleep(const char *cmdContent, int maxArg) { struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); - if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("DoSleep invalid arguments :%s", cmdContent); - goto out; - } - errno = 0; - unsigned long sleepTime = strtoul(ctx->argv[0], NULL, DECIMAL_BASE); - if (errno != 0) { - INIT_LOGE("cannot covert sleep time in command \" sleep \""); - goto out; + if ((ctx == NULL) || (ctx->argv == NULL) || (ctx->argc != maxArg)) { + INIT_LOGE("Command sleep with invalid arguments"); + FreeCmd(ctx); + return; } + unsigned long sleepTime = strtoul(ctx->argv[0], NULL, DECIMAL_BASE); // Limit sleep time in 5 seconds const unsigned long sleepTimeLimit = 5; if (sleepTime > sleepTimeLimit) { @@ -331,198 +330,239 @@ static void DoSleep(const char *cmdContent, int maxArg) } INIT_LOGI("Sleeping %d second(s)", sleepTime); sleep((unsigned int)sleepTime); -out: - FreeCmd(&ctx); + + FreeCmd(ctx); return; } -static void DoStart(const char* cmdContent, int maxArg) +static void DoStart(const char *cmdContent, int maxArg) { struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("DoStart invalid arguments :%s", cmdContent); - goto out; + INIT_LOGE("Command start with invalid arguments"); + FreeCmd(ctx); + return; } - INIT_LOGD("DoStart %s", cmdContent); - StartServiceByName(cmdContent); -out: - FreeCmd(&ctx); + INIT_LOGD("Starting service \" %s \"", ctx->argv[0]); + StartServiceByName(ctx->argv[0], true); + + FreeCmd(ctx); return; } -static void DoStop(const char* cmdContent, int maxArg) +static void DoStop(const char *cmdContent, int maxArg) { struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("DoStop invalid arguments :%s", cmdContent); - goto out; + INIT_LOGE("Command stop with invalid arguments"); + FreeCmd(ctx); + return; } - INIT_LOGD("DoStop %s", cmdContent); - StopServiceByName(cmdContent); -out: - FreeCmd(&ctx); + INIT_LOGD("Stopping service \" %s \"", ctx->argv[0]); + StopServiceByName(ctx->argv[0]); + + FreeCmd(ctx); return; } -static void DoReset(const char* cmdContent, int maxArg) +static void DoReset(const char *cmdContent, int maxArg) { struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("DoReset invalid arguments :%s", cmdContent); - goto out; - } - INIT_LOGD("DoReset %s", cmdContent); - DoStop(cmdContent, maxArg); - DoStart(cmdContent, maxArg); -out: - FreeCmd(&ctx); + INIT_LOGE("Command reset with invalid arguments"); + FreeCmd(ctx); + return; + } + INIT_LOGD("Reseting service %s", ctx->argv[0]); + DoStop(ctx->argv[0], maxArg); + DoStart(ctx->argv[0], maxArg); + + FreeCmd(ctx); return; } -static void DoCopy(const char* cmdContent, int maxArg) +static void DoCopyInernal(const char *source, const char *target) +{ + bool isSuccess = true; + if (source == NULL || target == NULL) { + INIT_LOGE("Copy file with invalid arguments"); + return; + } + + struct stat st = {0}; + int srcFd = open(source, O_RDONLY | O_CLOEXEC, S_IRUSR | S_IWUSR); + if (srcFd < 0) { + INIT_LOGE("Open \" %s \" failed, err = %d", source, errno); + close(srcFd); + srcFd = -1; + return; + } + + if (fstat(srcFd, &st) < 0) { + INIT_LOGE("Failed to get file \" %s \" stat", source); + close(srcFd); + srcFd = -1; + return; + } + int dstFd = open(target, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, st.st_mode); + if (dstFd >= 0) { + char buf[MAX_COPY_BUF_SIZE] = {0}; + ssize_t readn = -1; + ssize_t writen = -1; + while ((readn = read(srcFd, buf, MAX_COPY_BUF_SIZE - 1)) > 0) { + writen = WriteAll(dstFd, buf, (size_t)readn); + if (writen != readn) { + isSuccess = false; + break; + } + } + } + + if (!isSuccess) { + INIT_LOGE("Copy from \" %s \" to \" %s \" failed", source, target); + } else { + fsync(dstFd); + } + close(srcFd); + close(dstFd); + srcFd = -1; + dstFd = -1; +} + +static void DoCopy(const char *cmdContent, int maxArg) { - int srcFd = -1; - int dstFd = -1; - int rdLen = 0; - int rtLen = 0; - char buf[MAX_COPY_BUF_SIZE] = {0}; - char *realPath1 = NULL; - char *realPath2 = NULL; - mode_t mode = 0; - struct stat fileStat = {0}; struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); - if (ctx == NULL || ctx->argv == NULL || ctx->argv[0] == NULL || ctx->argv[1] == NULL || - ctx->argc != DEFAULT_COPY_ARGS_CNT) { - INIT_LOGE("DoCopy invalid arguments :%s", cmdContent); - goto out; - } - realPath1 = realpath(ctx->argv[0], NULL); - if (realPath1 == NULL) { - goto out; - } - realPath2 = realpath(ctx->argv[1], NULL); - if (realPath2 == NULL) { - goto out; - } - srcFd = open(realPath1, O_RDONLY); - INIT_ERROR_CHECK(srcFd >= 0, goto out, "copy open %s fail %d! ", ctx->argv[0], errno); - INIT_ERROR_CHECK(stat(ctx->argv[0], &fileStat) == 0, goto out, "stat fail "); - mode = fileStat.st_mode; - dstFd = open(realPath2, O_WRONLY | O_TRUNC | O_CREAT, mode); - INIT_ERROR_CHECK(dstFd >= 0, goto out, "copy open %s fail %d! ", 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! ", ctx->argv[1], errno); - } - fsync(dstFd); -out: - FreeCmd(&ctx); + if (ctx == NULL || ctx->argv == NULL || ctx->argc != DEFAULT_COPY_ARGS_CNT) { + INIT_LOGE("Command copy with invalid arguments"); + FreeCmd(ctx); + return; + } + char *sourceFile = realpath(ctx->argv[0], NULL); + char *targetFile = realpath(ctx->argv[1], NULL); + + if (sourceFile == NULL || targetFile == NULL) { + INIT_LOGE("Failed resolve real path name in copy command"); + FreeCmd(ctx); + return; + } + + DoCopyInernal(sourceFile, targetFile); + FreeCmd(ctx); + free(sourceFile); + free(targetFile); ctx = NULL; - INIT_CHECK(srcFd < 0, close(srcFd); srcFd = -1); - INIT_CHECK(dstFd < 0, close(dstFd); dstFd = -1); - INIT_CHECK(realPath1 == NULL, free(realPath1); realPath1 = NULL); - INIT_CHECK(realPath2 == NULL, free(realPath2); realPath2 = NULL); + sourceFile = NULL; + targetFile = NULL; return; } -static void DoChown(const char* cmdContent, int maxArg) +static int Chown(const char *path, const char *uid, const char *gid) { - // format: chown owner group /xxx/xxx/xxx - struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); - if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("DoChown invalid arguments :%s", cmdContent); - goto out; + if (path == NULL || uid == NULL || gid == NULL) { + return -1; + } + uid_t user = DecodeUid(uid); + gid_t group = DecodeUid(gid); + if (user == (uid_t) -1 || group == (uid_t)-1) { + INIT_LOGE("Change path owner with invalid user/group"); + return -1; } - uid_t owner = DecodeUid(ctx->argv[0]); - INIT_ERROR_CHECK(owner != (uid_t)-1, goto out, "DoChown invalid uid :%s.", ctx->argv[0]); - - gid_t group = DecodeUid(ctx->argv[1]); - INIT_ERROR_CHECK(group != (gid_t)-1, goto out, "DoChown invalid gid :%s.", ctx->argv[1]); + int rc = chown(path, user, group); + if (rc < 0) { + INIT_LOGE("Change path \" %s \" ower to user: %s group: %s failed", + path, uid, gid); + return -1; + } + return 0; +} - int pathPos = 2; - if (chown(ctx->argv[pathPos], owner, group) != 0) { - INIT_LOGE("DoChown, failed for %s, err %d.", cmdContent, errno); +static void DoChown(const char *cmdContent, int maxArg) +{ + struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); + if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { + INIT_LOGE("Command chown with invalid arguments"); + FreeCmd(ctx); + return; + } + const int uidPos = 0; + const int gidPos = 1; + const int pathPos = 2; + int ret = Chown(ctx->argv[pathPos], ctx->argv[uidPos], ctx->argv[gidPos]); + if (ret < 0) { + INIT_LOGE("Run command chown failed"); } -out: - FreeCmd(&ctx); + FreeCmd(ctx); return; } -static void DoMkDir(const char* cmdContent, int maxArg) +static void DoMkDir(const char *cmdContent, int maxArg) { // mkdir support format: - // 1.mkdir path - // 2.mkdir path mode - // 3.mkdir path mode owner group + // 1.mkdir path + // 2.mkdir path mode + // 3.mkdir path mode owner group struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); if (ctx == NULL || ctx->argv == NULL || ctx->argc < 1) { - INIT_LOGE("DoMkDir invalid arguments :%s", cmdContent); - goto out; - } - - const int withModeArg = 2; - if (ctx->argc != 1 && ctx->argc != maxArg && ctx->argc != withModeArg) { - INIT_LOGE("DoMkDir invalid arguments: %s", cmdContent); - goto out; - } - - mode_t mode = DEFAULT_DIR_MODE; - if (mkdir(ctx->argv[0], mode) != 0 && errno != EEXIST) { - INIT_LOGE("DoMkDir, failed for %s, err %d.", cmdContent, errno); - goto out; + INIT_LOGE("Command mkdir with invalid arguments"); + FreeCmd(ctx); + 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.", cmdContent, errno); - } - if (ctx->argc == withModeArg) { - goto out; + int rc = -1; + do { + int index = 0; + rc = mkdir(ctx->argv[index], DEFAULT_DIR_MODE); + if (rc < 0) { + if (errno == EEXIST) { + INIT_LOGE("Path \" %s \" already exist", ctx->argv[0]); + rc = 0; + } + break; } - const int ownerPos = 2; - const int groupPos = 3; - - uid_t owner = DecodeUid(ctx->argv[ownerPos]); - INIT_ERROR_CHECK(owner != (uid_t)-1, goto out, "DoMkDir invalid uid :%s.", ctx->argv[ownerPos]); - gid_t group = DecodeUid(ctx->argv[groupPos]); - INIT_ERROR_CHECK(group != (gid_t)-1, goto out, "DoMkDir invalid gid :%s.", ctx->argv[groupPos]); - - if (chown(ctx->argv[0], owner, group) != 0) { - INIT_LOGE("DoMkDir, chown failed for %s, err %d.", cmdContent, errno); + if (ctx->argv[++index] != NULL) { // mkdir with specific mode + mode_t mode = strtoul(ctx->argv[1], NULL, OCTAL_BASE); + rc = chmod(ctx->argv[0], mode); + if (rc < 0) { + INIT_LOGE("Change path \" %s \" mode to %04o failed", ctx->argv[0], mode); + break; + } + index = index + 1; + if ((ctx->argv[index] != NULL) && (ctx->argv[index + 1] != NULL)) { + rc = Chown(ctx->argv[0], ctx->argv[index], ctx->argv[index + 1]); + } else { + rc = -1; + } } + } while (0); + + if (rc < 0) { + INIT_LOGE("Run command mkdir failed err = %d", errno); + (void)rmdir(ctx->argv[0]); } -out: - FreeCmd(&ctx); - return; + FreeCmd(ctx); } -static void DoChmod(const char* cmdContent, int maxArg) +static void DoChmod(const char *cmdContent, int maxArg) { - // format: chmod xxxx /xxx/xxx/xxx struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("DoChmod invalid arguments :%s", cmdContent); - goto out; - } - - mode_t mode = strtoul(ctx->argv[0], NULL, OCTAL_TYPE); - if (mode == 0) { - INIT_LOGE("DoChmod, strtoul failed for %s, er %d.", cmdContent, errno); - goto out; + INIT_LOGE("Command chmod with invalid arguments"); + FreeCmd(ctx); + return; } - if (chmod(ctx->argv[1], mode) != 0) { - INIT_LOGE("DoChmod, failed for %s, err %d.", cmdContent, errno); + mode_t mode = strtoul(ctx->argv[0], NULL, OCTAL_BASE); + if (mode != 0) { + if (chmod(ctx->argv[1], mode) != 0) { + INIT_LOGE("Failed to change file \" %s \" mode to %04o, err = %d", ctx->argv[1], mode, errno); + } } -out: - FreeCmd(&ctx); + FreeCmd(ctx); return; } -static char* CopySubStr(const char* srcStr, size_t startPos, size_t endPos) +static char* CopySubStr(const char *srcStr, size_t startPos, size_t endPos) { if (endPos <= startPos) { INIT_LOGE("DoMount, invalid params<%zu, %zu> for %s.", endPos, startPos, srcStr); @@ -551,7 +591,7 @@ static char* CopySubStr(const char* srcStr, size_t startPos, size_t endPos) return retStr; } -static int GetMountFlag(unsigned long* mountflags, const char* targetStr, const char *source) +static int GetMountFlag(unsigned long *mountflags, const char *targetStr, const char *source) { if (targetStr == NULL) { return 0; @@ -575,7 +615,7 @@ static int GetMountFlag(unsigned long* mountflags, const char* targetStr, const return 1; } -static int CountSpaces(const char* cmdContent, size_t* spaceCnt, size_t* spacePosArr, size_t spacePosArrLen) +static int CountSpaces(const char *cmdContent, size_t *spaceCnt, size_t *spacePosArr, size_t spacePosArrLen) { *spaceCnt = 0; size_t strLen = strlen(cmdContent); @@ -607,7 +647,7 @@ static int CountSpaces(const char* cmdContent, size_t* spaceCnt, size_t* spacePo return 1; } -static void DoMount(const char* cmdContent, int maxArg) +static void DoMount(const char *cmdContent, int maxArg) { size_t spaceCnt = 0; size_t spacePosArr[SPACES_CNT_IN_CMD_MAX] = {0}; @@ -675,7 +715,7 @@ static void DoMount(const char* cmdContent, int maxArg) #ifndef OHOS_LITE #define OPTIONS_SIZE 128u -static void DoInsmodInternal(const char *fileName, char *secondPtr, char *restPtr, int flags) +static void DoInsmodInternal(const char *fileName, const char *secondPtr, const char *restPtr, int flags) { char options[OPTIONS_SIZE] = {0}; if (flags == 0) { // '-f' option @@ -768,17 +808,64 @@ static void DoInsmod(const char *cmdContent, int maxArg) return; } -static void DoSetParam(const char* cmdContent, int maxArg) +static void DoSetParam(const char *cmdContent, int maxArg) { struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("DoSetParam invalid arguments :%s", cmdContent); - goto out; + INIT_LOGE("Command setparam with invalid arguments"); + FreeCmd(ctx); + return; } - INIT_LOGE("param name: %s, value %s ", ctx->argv[0], ctx->argv[1]); + INIT_LOGD("param name: %s, value %s ", ctx->argv[0], ctx->argv[1]); SystemWriteParam(ctx->argv[0], ctx->argv[1]); -out: - FreeCmd(&ctx); + + FreeCmd(ctx); + return; +} + + +static void DoLoadPersistParams(const char *cmdContent, int maxArg) +{ + struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); + if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { + INIT_LOGE("Command load_persist_params with invalid arguments"); + FreeCmd(ctx); + return; + } + INIT_LOGD("load persist params : %s", cmdContent); + LoadPersistParams(); + FreeCmd(ctx); + return; +} + +static void DoTriggerCmd(const char *cmdContent, int maxArg) +{ + struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); + if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { + INIT_LOGE("Command trigger with invalid arguments"); + FreeCmd(ctx); + return; + } + INIT_LOGD("Trigger job :%s", ctx->argv[0]); + DoTriggerExec(ctx->argv[0]); + FreeCmd(ctx); + return; +} + +static void DoLoadDefaultParams(const char *cmdContent, int maxArg) +{ + struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); + if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { + INIT_LOGE("Command load_param with invalid arguments"); + FreeCmd(ctx); + return; + } + int mode = 0; + if (strcmp(ctx->argv[1], "onlyadd") == 0) { + mode = LOAD_PARAM_ONLY_ADD; + } + LoadDefaultParams(ctx->argv[0], mode); + FreeCmd(ctx); return; } @@ -786,7 +873,7 @@ out: static bool CheckValidCfg(const char *path) { - size_t cfgCnt = sizeof(g_supportCfg) / sizeof(g_supportCfg[0]); + size_t cfgCnt = ARRAY_LENGTH(g_supportCfg); struct stat fileStat = {0}; if (stat(path, &fileStat) != 0 || fileStat.st_size <= 0 || fileStat.st_size > LOADCFG_MAX_FILE_LEN) { @@ -807,7 +894,7 @@ static void DoLoadCfg(const char *path, int maxArg) FILE *fp = NULL; size_t maxLoop = 0; CmdLine *cmdLine = NULL; - int len; + size_t len; INIT_CHECK_ONLY_RETURN(path != NULL); INIT_LOGI("DoLoadCfg cfg file %s", path); if (!CheckValidCfg(path)) { @@ -859,53 +946,32 @@ static void DoWrite(const char *cmdContent, int maxArg) // format: write path content struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); if (ctx == NULL || ctx->argv == NULL || ctx->argv[0] == NULL || ctx->argc != maxArg) { - INIT_LOGE("DoWrite: invalid arguments :%s", cmdContent); - goto out; - } - char *realPath = realpath(ctx->argv[0], NULL); - if (realPath == NULL) { - goto out; - } - int fd = open(realPath, O_WRONLY | O_CREAT | O_NOFOLLOW | O_CLOEXEC, S_IRUSR | S_IWUSR); - if (fd == -1) { - INIT_LOGE("DoWrite: open %s failed: %d", ctx->argv[0], errno); - free(realPath); - realPath = NULL; - goto out; + INIT_LOGE("Command write with invalid arguments"); + FreeCmd(ctx); + return; } - size_t ret = write(fd, ctx->argv[1], strlen(ctx->argv[1])); - if (ret < 0) { - INIT_LOGE("DoWrite: write to file %s failed: %d", ctx->argv[0], errno); - free(realPath); - realPath = NULL; - close(fd); - goto out; - } - free(realPath); - realPath = NULL; - close(fd); -out: - FreeCmd(&ctx); + WriteCommon(ctx->argv[0], ctx->argv[1], O_WRONLY | O_CREAT | O_NOFOLLOW | O_CLOEXEC, + S_IRUSR | S_IWUSR); + + FreeCmd(ctx); return; } static void DoRmdir(const char *cmdContent, int maxArg) { - // format: rmdir path struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("DoRmdir: invalid arguments :%s", cmdContent); - goto out; + INIT_LOGE("Command rmdir with invalid arguments"); + FreeCmd(ctx); + return; } int ret = rmdir(ctx->argv[0]); if (ret == -1) { - INIT_LOGE("DoRmdir: remove %s failed: %d.", ctx->argv[0], errno); - goto out; + INIT_LOGE("Remove directory \" %s \" failed, err = %d", ctx->argv[0], errno); } -out: - FreeCmd(&ctx); + FreeCmd(ctx); return; } @@ -913,60 +979,18 @@ static void DoRebootCmd(const char *cmdContent, int maxArg) { struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("DoReboot invalid arguments :%s", cmdContent); - goto out; + INIT_LOGE("Command reboot with invalid arguments"); + FreeCmd(ctx); + return; } DoReboot(cmdContent); -out: - FreeCmd(&ctx); - return; -} - -static void DoLoadPersistParams(const char *cmdContent, int maxArg) -{ - struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); - if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("DoLoadPersistParams invalid arguments :%s", cmdContent); - goto out; - } - INIT_LOGD("load persist params : %s", cmdContent); - LoadPersistParams(); -out: - FreeCmd(&ctx); - return; -} - -static void DoTriggerCmd(const char *cmdContent, int maxArg) -{ - struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); - if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("DoTrigger invalid arguments :%s", cmdContent); - goto out; - } - INIT_LOGD("DoTrigger :%s", cmdContent); - DoTriggerExec(cmdContent); -out: - FreeCmd(&ctx); - return; -} - -static void DoLoadDefaultParams(const char *cmdContent, int maxArg) -{ - struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); - if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("DoLoadDefaultParams invalid arguments :%s", cmdContent); - goto out; - } - INIT_LOGD("load persist params : %s", cmdContent); - LoadDefaultParams(cmdContent); -out: - FreeCmd(&ctx); + FreeCmd(ctx); return; } static void DoSetrlimit(const char *cmdContent, int maxArg) { - char *resource[] = { + static const char *resource[] = { "RLIMIT_CPU", "RLIMIT_FSIZE", "RLIMIT_DATA", "RLIMIT_STACK", "RLIMIT_CORE", "RLIMIT_RSS", "RLIMIT_NPROC", "RLIMIT_NOFILE", "RLIMIT_MEMLOCK", "RLIMIT_AS", "RLIMIT_LOCKS", "RLIMIT_SIGPENDING", "RLIMIT_MSGQUEUE", "RLIMIT_NICE", "RLIMIT_RTPRIO", "RLIMIT_RTTIME", "RLIM_NLIMITS" @@ -975,72 +999,69 @@ static void DoSetrlimit(const char *cmdContent, int maxArg) struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); const int rlimMaxPos = 2; if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("DoSetrlimit: invalid arguments :%s", cmdContent); - goto out; + INIT_LOGE("Command setrlimit with invalid arguments"); + FreeCmd(ctx); + return; } struct rlimit limit; limit.rlim_cur = (rlim_t)atoi(ctx->argv[1]); limit.rlim_max = (rlim_t)atoi(ctx->argv[rlimMaxPos]); int rcs = -1; - for (unsigned int i = 0 ; i < sizeof(resource) / sizeof(char*); ++i) { + for (unsigned int i = 0; i < ARRAY_LENGTH(resource); ++i) { if (strcmp(ctx->argv[0], resource[i]) == 0) { rcs = (int)i; } } if (rcs == -1) { - INIT_LOGE("DoSetrlimit failed, resouces :%s not support.", ctx->argv[0]); - goto out; - } - int ret = setrlimit(rcs, &limit); - if (ret) { - INIT_LOGE("DoSetrlimit failed : %d", errno); - goto out; + INIT_LOGE("Set limit with unsupported resource \" %s \"", ctx->argv[0]); + } else { + int ret = setrlimit(rcs, &limit); + if (ret) { + INIT_LOGE("Set limit with resource %s, value : %lu, max value: %lu failed, err = %d", + ctx->argv[0], limit.rlim_cur, limit.rlim_max, errno); + } } -out: - FreeCmd(&ctx); + FreeCmd(ctx); return; } static void DoRm(const char *cmdContent, int maxArg) { - // format: rm /xxx/xxx/xxx struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("DoRm: invalid arguments :%s", cmdContent); - goto out; + INIT_LOGE("Command rm with invalid arguments"); + FreeCmd(ctx); + return; } int ret = unlink(ctx->argv[0]); if (ret == -1) { - INIT_LOGE("DoRm: unlink %s failed: %d.", ctx->argv[0], errno); - goto out; + INIT_LOGE("Unlink %s failed, err = %d", ctx->argv[0], errno); } -out: - FreeCmd(&ctx); + FreeCmd(ctx); return; } static void DoExport(const char *cmdContent, int maxArg) { - // format: export xxx /xxx/xxx/xxx struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("DoExport: invalid arguments :%s", cmdContent); - goto out; + INIT_LOGE("Command export with invalid arguments"); + FreeCmd(ctx); + return; } int ret = setenv(ctx->argv[0], ctx->argv[1], 1); if (ret != 0) { - INIT_LOGE("DoExport: set %s with %s failed: %d", ctx->argv[0], ctx->argv[1], errno); - goto out; + INIT_LOGE("export env name \" %s \", value \" %s \" failed, err = %d ", + ctx->argv[0], ctx->argv[1], errno); } -out: - FreeCmd(&ctx); + + FreeCmd(ctx); return; } static void DoExec(const char *cmdContent, int maxArg) { - // format: exec /xxx/xxx/xxx xxx pid_t pid = fork(); if (pid < 0) { INIT_LOGE("DoExec: failed to fork child process to exec \"%s\"", cmdContent); @@ -1049,7 +1070,7 @@ static void DoExec(const char *cmdContent, int maxArg) if (pid == 0) { struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); if (ctx == NULL || ctx->argv == NULL || ctx->argv[0] == NULL) { - INIT_LOGE("DoExec: invalid arguments :%s", cmdContent); + INIT_LOGE("Command exec with invalid arguments"); _exit(0x7f); } #ifdef OHOS_LITE @@ -1060,7 +1081,7 @@ static void DoExec(const char *cmdContent, int maxArg) if (ret == -1) { INIT_LOGE("DoExec: execute \"%s\" failed: %d.", cmdContent, errno); } - FreeCmd(&ctx); + FreeCmd(ctx); _exit(0x7f); } return; @@ -1072,17 +1093,17 @@ static void DoSymlink(const char *cmdContent, int maxArg) // format: symlink /xxx/xxx/xxx /xxx/xxx/xxx struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("DoSymlink: invalid arguments :%s", cmdContent); - goto out; + INIT_LOGE("Command symlink with invalid arguments"); + FreeCmd(ctx); + return; } int ret = symlink(ctx->argv[0], ctx->argv[1]); if (ret != 0) { - INIT_LOGE("DoSymlink: link %s to %s failed: %d", ctx->argv[0], ctx->argv[1], errno); - goto out; + INIT_LOGE("Link \" %s \" to target \" %s \" failed, err = %d", ctx->argv[0], ctx->argv[1], errno); } -out: - FreeCmd(&ctx); + + FreeCmd(ctx); return; } @@ -1111,55 +1132,56 @@ static void DoMakeNode(const char *cmdContent, int maxArg) const int authorityPos = 2; const int majorDevicePos = 3; const int minorDevicePos = 4; - const int decimal = 10; - const int octal = 8; + if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("DoMakeNode: invalid arguments :%s", cmdContent); - goto out; + INIT_LOGE("Command mknode with invalid arguments"); + FreeCmd(ctx); + return; } if (!access(ctx->argv[1], F_OK)) { - INIT_LOGE("DoMakeNode failed, path has not sexisted"); - 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); + INIT_LOGE("Cannot access \" %s \", err = %d", ctx->argv[1], errno); + } else { + mode_t deviceMode = GetDeviceMode(ctx->argv[deviceTypePos]); + unsigned int major = strtoul(ctx->argv[majorDevicePos], NULL, DECIMAL_BASE); + unsigned int minor = strtoul(ctx->argv[minorDevicePos], NULL, DECIMAL_BASE); + mode_t mode = strtoul(ctx->argv[authorityPos], NULL, OCTAL_BASE); - int ret = mknod(ctx->argv[0], deviceMode | authority, makedev(major, minor)); - if (ret != 0) { - INIT_LOGE("DoMakeNode: path: %s failed: %d", ctx->argv[0], errno); - goto out; + int ret = mknod(ctx->argv[0], deviceMode | mode, makedev(major, minor)); + if (ret != 0) { + INIT_LOGE("Create device node \" %s \" failed, err = %d", ctx->argv[0], errno); + } } -out: - FreeCmd(&ctx); + + FreeCmd(ctx); return; } static void DoMakeDevice(const char *cmdContent, int maxArg) { - // format: makedev major minor struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); - const int decimal = 10; + if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("DoMakedevice: invalid arguments :%s", cmdContent); - goto out; + INIT_LOGE("Command makedev with invalid arguments"); + FreeCmd(ctx); + return; + } + unsigned int major = strtoul(ctx->argv[0], NULL, DECIMAL_BASE); + unsigned int minor = strtoul(ctx->argv[1], NULL, DECIMAL_BASE); + if (major == 0 || minor == 0) { + return; } - 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 ", cmdContent, errno); - goto out; + INIT_LOGE("Make device with major %u, minor %u failed :%d ", major, minor, errno); } -out: - FreeCmd(&ctx); + + FreeCmd(ctx); return; } #endif // __LITEOS__ -void DoCmd(const CmdLine* curCmd) +void DoCmd(const CmdLine *curCmd) { // null curCmd or empty command, just quit. if (curCmd == NULL || curCmd->name[0] == '\0') { @@ -1194,7 +1216,7 @@ static const struct CmdTable CMD_TABLE[] = { { "insmod ", 10, DoInsmod }, { "setparam ", 2, DoSetParam }, { "load_persist_params ", 1, DoLoadPersistParams }, - { "load_param ", 1, DoLoadDefaultParams }, + { "load_param ", 2, DoLoadDefaultParams }, { "ifup ", 1, DoIfup }, #endif { "stop ", 1, DoStop }, @@ -1213,7 +1235,7 @@ void DoCmdByName(const char *name, const char *cmdContent) return; } - size_t cmdCnt = sizeof(CMD_TABLE) / sizeof(CMD_TABLE[0]); + size_t cmdCnt = ARRAY_LENGTH(CMD_TABLE); unsigned int i = 0; for (; i < cmdCnt; ++i) { if (strncmp(name, CMD_TABLE[i].name, strlen(CMD_TABLE[i].name)) == 0) { @@ -1226,29 +1248,14 @@ void DoCmdByName(const char *name, const char *cmdContent) } } -const char *GetMatchCmd(const char *cmdStr) -{ - if (cmdStr == NULL) { - return NULL; - } - size_t supportCmdCnt = sizeof(CMD_TABLE) / sizeof(CMD_TABLE[0]); - for (size_t i = 0; i < supportCmdCnt; ++i) { - size_t curCmdNameLen = strlen(CMD_TABLE[i].name); - if (strncmp(CMD_TABLE[i].name, cmdStr, curCmdNameLen) == 0) { - return CMD_TABLE[i].name; - } - } - return NULL; -} - -void ParseCmdLine(const char* cmdStr, CmdLine* resCmd) +void ParseCmdLine(const char *cmdStr, CmdLine *resCmd) { size_t cmdLineLen = 0; if (cmdStr == NULL || resCmd == NULL || (cmdLineLen = strlen(cmdStr)) == 0) { return; } - size_t supportCmdCnt = sizeof(CMD_TABLE) / sizeof(CMD_TABLE[0]); + size_t supportCmdCnt = ARRAY_LENGTH(CMD_TABLE); int foundAndSucceed = 0; for (size_t i = 0; i < supportCmdCnt; ++i) { size_t curCmdNameLen = strlen(CMD_TABLE[i].name); @@ -1276,3 +1283,27 @@ void ParseCmdLine(const char* cmdStr, CmdLine* resCmd) } } +const char *GetMatchCmd(const char *cmdStr, unsigned int *index) +{ + if (cmdStr == NULL || index == NULL) { + return NULL; + } + size_t supportCmdCnt = ARRAY_LENGTH(CMD_TABLE); + for (size_t i = 0; i < supportCmdCnt; ++i) { + size_t curCmdNameLen = strlen(CMD_TABLE[i].name); + if (strncmp(CMD_TABLE[i].name, cmdStr, curCmdNameLen) == 0) { + *index = (unsigned int)i; + return CMD_TABLE[i].name; + } + } + return NULL; +} + +const char *GetCmdKey(unsigned int index) +{ + size_t supportCmdCnt = ARRAY_LENGTH(CMD_TABLE); + if (index >= supportCmdCnt) { + return NULL; + } + return CMD_TABLE[index].name; +} \ No newline at end of file diff --git a/services/src/init_import.c b/services/src/init_import.c index 36d031fd4a2830afa9a7ce2676ccdfe62149d97e..319c26516bd57d0303a9c853b7d93b151c22918b 100644 --- a/services/src/init_import.c +++ b/services/src/init_import.c @@ -40,7 +40,7 @@ static int ExtractCfgFile(char **cfgFile, const char *content) } #endif -void ParseAllImports(cJSON *root) +void ParseAllImports(const cJSON *root) { cJSON *importAttr = cJSON_GetObjectItemCaseSensitive(root, "import"); char *cfgFile = NULL; @@ -79,6 +79,6 @@ void ParseAllImports(cJSON *root) free(cfgFile); cfgFile = NULL; } - INIT_LOGD("parse import file done"); + INIT_LOGD("parse import file done"); return; } diff --git a/services/src/init_jobs.c b/services/src/init_jobs.c index 563a5065dc73e069bf0c3b2e3608114a952366d1..1bac3d7faf19ef421e142defe605368ebd843e3c 100644 --- a/services/src/init_jobs.c +++ b/services/src/init_jobs.c @@ -23,21 +23,14 @@ #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 100 -// static const char* g_supportedJobs[] = { -// "pre-init", -// "init", -// "post-init", -// }; - static Job* g_jobs = NULL; static int g_jobCnt = 0; -void DumpAllJobs() +void DumpAllJobs(void) { INIT_LOGD("Ready to dump all jobs:"); for (int i = 0; i < g_jobCnt; i++) { @@ -168,13 +161,11 @@ void DoJob(const char* jobName) for (int j = 0; j < g_jobs[i].cmdLinesCnt; ++j) { DoCmd(&(cmdLines[j])); } - // Walk through all jobs - // break; } } } -void ReleaseAllJobs() +void ReleaseAllJobs(void) { if (g_jobs == NULL) { return; diff --git a/services/src/init_read_cfg.c b/services/src/init_read_cfg.c index 336820ea174bf62dffcde75d46823e773f75e675..732f7db87370a7c86b538b38328d7dee6d7939d0 100644 --- a/services/src/init_read_cfg.c +++ b/services/src/init_read_cfg.c @@ -42,13 +42,13 @@ #endif #define FILE_NAME_MAX_SIZE 100 -static void ParseInitCfgContents(cJSON *root) +static void ParseInitCfgContents(const cJSON *root) { if (root == NULL) { INIT_LOGE("ParseInitCfgContents root is NULL"); return; } - // parse services + // parse services ParseAllServices(root); #ifdef OHOS_LITE // parse jobs @@ -125,7 +125,9 @@ void InitReadCfg() { #ifndef OHOS_LITE InitParamService(); - LoadDefaultParams("/system/etc/ohos.para"); + LoadDefaultParams("/system/etc/param/ohos_const", LOAD_PARAM_NORMAL); + LoadDefaultParams("/vendor/etc/param", LOAD_PARAM_NORMAL); + LoadDefaultParams("/system/etc/param", LOAD_PARAM_ONLY_ADD); #endif ParseInitCfg(INIT_CONFIGURATION_FILE); ParseOtherCfgs(); @@ -154,11 +156,11 @@ void InitReadCfg() #endif ReleaseAllJobs(); #else - PostTrigger(EVENT_BOOT, "pre-init", strlen("pre-init")); + PostTrigger(EVENT_TRIGGER_BOOT, "pre-init", strlen("pre-init")); - PostTrigger(EVENT_BOOT, "init", strlen("init")); + PostTrigger(EVENT_TRIGGER_BOOT, "init", strlen("init")); - PostTrigger(EVENT_BOOT, "post-init", strlen("post-init")); + PostTrigger(EVENT_TRIGGER_BOOT, "post-init", strlen("post-init")); #endif } diff --git a/services/src/init_reboot.c b/services/src/init_reboot.c index e65e9c65dbc7ae676cb1e673a146f4c95df8fec8..f5242776d05e65a3f1a2a71e0e8892fac917d670 100644 --- a/services/src/init_reboot.c +++ b/services/src/init_reboot.c @@ -19,14 +19,15 @@ #include #include #include -#include #include #include #include -#include "securec.h" +#include +#include "init_log.h" #include "init_service.h" #include "init_service_manager.h" -#include "init_log.h" +#include "init_utils.h" +#include "securec.h" #define MAX_VALUE_LENGTH 500 #define MAX_COMMAND_SIZE 20 @@ -37,7 +38,7 @@ struct RBMiscUpdateMessage { char update[MAX_UPDATE_SIZE]; }; -static bool RBMiscWriteUpdaterMessage(const char *path, struct RBMiscUpdateMessage *boot) +static bool RBMiscWriteUpdaterMessage(const char *path, const struct RBMiscUpdateMessage *boot) { if (path == NULL || boot == NULL) { INIT_LOGE("path or boot is NULL."); @@ -129,103 +130,81 @@ static int GetMountStatusForMountPoint(const char *mountPoint) return 0; } -static int UpdateUpdaterStatus(const char *valueData) +static int CheckAndRebootToUpdater(const char *valueData, const char *cmd, const char *cmdExt, const char *boot) { + // "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("RBMiscReadUpdaterMessage error."); - return -1; - } - if (snprintf_s(msg.command, MAX_COMMAND_SIZE, MAX_COMMAND_SIZE - 1, "%s", "boot_updater") == -1) { - INIT_LOGE("RBMiscWriteUpdaterMessage error"); - return -1; - } - if (strlen(valueData) > strlen("updater:") && strncmp(valueData, "updater:", strlen("updater:")) == 0) { - if (snprintf_s(msg.update, MAX_UPDATE_SIZE, MAX_UPDATE_SIZE - 1, "%s", valueData + strlen("updater:")) == -1) { - INIT_LOGE("RBMiscWriteUpdaterMessage error"); - return -1; - } - ret = RBMiscWriteUpdaterMessage(miscFile, &msg); - if (ret != true) { - INIT_LOGE("RBMiscWriteUpdaterMessage error"); - return -1; - } - } else if (strlen(valueData) == strlen("updater") && strncmp(valueData, "updater", strlen("updater")) == 0) { - ret = RBMiscWriteUpdaterMessage(miscFile, &msg); - if (ret != true) { - INIT_LOGE("RBMiscWriteUpdaterMessage error"); - return -1; - } - } else { - return -1; + bool bRet = RBMiscReadUpdaterMessage(miscFile, &msg); + INIT_ERROR_CHECK(bRet, return -1, "Failed to get misc info for %s.", cmd); + + int ret = snprintf_s(msg.command, MAX_COMMAND_SIZE, MAX_COMMAND_SIZE - 1, "%s", boot); + INIT_ERROR_CHECK(ret > 0, return -1, "Failed to format cmd for %s.", cmd); + msg.command[MAX_COMMAND_SIZE - 1] = 0; + + if (strncmp(valueData, cmdExt, strlen(cmdExt)) == 0) { + const char *p = valueData + strlen(cmdExt); + ret = snprintf_s(msg.update, MAX_UPDATE_SIZE, MAX_UPDATE_SIZE - 1, "%s", p); + INIT_ERROR_CHECK(ret > 0, return -1, "Failed to format param for %s.", cmd); + msg.update[MAX_UPDATE_SIZE - 1] = 0; } - return 0; -} -static int DoRebootCore(const char *valueData) -{ - if (valueData == NULL) { - reboot(RB_AUTOBOOT); - return 0; - } else if (strncmp(valueData, "shutdown", strlen("shutdown")) == 0) { - reboot(RB_POWER_OFF); - return 0; - } else if (strncmp(valueData, "updater", strlen("updater")) == 0) { - int ret = UpdateUpdaterStatus(valueData); - if (ret == 0) { - reboot(RB_AUTOBOOT); - return 0; - } - } else { - return -1; + if (RBMiscWriteUpdaterMessage(miscFile, &msg)) { + return reboot(RB_AUTOBOOT); } - return 0; + return -1; } void DoReboot(const char *value) { - if (value == NULL) { + static const char *g_cmdParams[] = { + "shutdown", "updater", "updater:", "flashing", "flashing:", "NoArgument", "bootloader" + }; + if (value == NULL || strlen(value) > MAX_VALUE_LENGTH) { INIT_LOGE("DoReboot value = NULL"); return; } - INIT_LOGI("DoReboot value = %s", value); - - if (strlen(value) > MAX_VALUE_LENGTH || strlen(value) < strlen("reboot") || strlen(value) == strlen("reboot,")) { - INIT_LOGE("DoReboot reboot value error, value = %s.", value); - return; - } const char *valueData = NULL; - if (strncmp(value, "reboot,", strlen("reboot,")) == 0) { - valueData = value + strlen("reboot,"); - } else if (strlen(value) < strlen("reboot,") && strncmp(value, "reboot", strlen("reboot")) == 0) { + if (strcmp(value, "reboot") == 0) { valueData = NULL; - } else { + } else if (strncmp(value, "reboot,", strlen("reboot,")) != 0) { INIT_LOGE("DoReboot reboot value = %s, must started with reboot ,error.", value); return; + } else { + valueData = value + strlen("reboot,"); } - if (valueData != NULL && strncmp(valueData, "shutdown", strlen("shutdown")) != 0 && - strncmp(valueData, "updater:", strlen("updater:")) != 0 && - strncmp(valueData, "updater", strlen("updater")) != 0) { - INIT_LOGE("DoReboot value = %s, parameters error.", value); - return; + if (valueData != NULL) { + size_t i = 0; + for (; i < ARRAY_LENGTH(g_cmdParams); i++) { + if (strncmp(valueData, g_cmdParams[i], strlen(g_cmdParams[i])) == 0) { + break; + } + } + if (i >= ARRAY_LENGTH(g_cmdParams)) { + INIT_LOGE("DoReboot value = %s, parameters error.", value); + return; + } } StopAllServicesBeforeReboot(); sync(); - if (GetMountStatusForMountPoint("/vendor") != 0) { - if (umount("/vendor") != 0) { - INIT_LOGE("DoReboot umount vendor failed! errno = %d.", errno); - } + if (GetMountStatusForMountPoint("/vendor") != 0 && umount("/vendor") != 0) { + INIT_LOGE("DoReboot umount vendor failed! errno = %d.", errno); } - if (GetMountStatusForMountPoint("/data") != 0) { - if (umount("/data") != 0) { - INIT_LOGE("DoReboot umount data failed! errno = %d.", errno); - } + if (GetMountStatusForMountPoint("/data") != 0 && umount("/data") != 0) { + INIT_LOGE("DoReboot umount data failed! errno = %d.", errno); } - int ret = DoRebootCore(valueData); - if (ret != 0) { - INIT_LOGE("DoReboot value = %s, error.", value); + int ret = 0; + if (valueData == NULL) { + ret = reboot(RB_AUTOBOOT); + } else if (strcmp(valueData, "shutdown") == 0) { + ret = reboot(RB_POWER_OFF); + } else if (strcmp(valueData, "bootloader") == 0) { + ret = reboot(RB_POWER_OFF); + } else if (strncmp(valueData, "updater", strlen("updater")) == 0) { + ret = CheckAndRebootToUpdater(valueData, "updater", "updater:", "boot_updater"); + } else if (strncmp(valueData, "flashing", strlen("flashing")) == 0) { + ret = CheckAndRebootToUpdater(valueData, "flashing", "flashing:", "boot_flashing"); } + INIT_LOGI("DoReboot value = %s %s.", value, (ret == 0) ? "success" : "fail"); return; } diff --git a/services/src/init_service.c b/services/src/init_service.c index 248c1962d75f4ab7d9b6888592a36f895f3ee0d7..482d5a82808da9cad3886c16d8c2b89bfedb7faa 100644 --- a/services/src/init_service.c +++ b/services/src/init_service.c @@ -15,7 +15,6 @@ #include "init_service.h" -#include #include #include #include @@ -65,7 +64,7 @@ static const int CRITICAL_CRASH_COUNT_LIMIT = 4; static const int MAX_PID_STRING_LENGTH = 50; -static int SetAllAmbientCapability() +static int SetAllAmbientCapability(void) { for (int i = 0; i <= CAP_LAST_CAP; ++i) { if (SetAmbientCapability(i) != 0) { @@ -132,7 +131,7 @@ static int SetPerms(const Service *service) return SERVICE_SUCCESS; } -static void OpenConsole() +static void OpenConsole(void) { setsid(); WaitForFile("/dev/console", WAIT_MAX_COUNT); @@ -141,7 +140,7 @@ static void OpenConsole() ioctl(fd, TIOCSCTTY, 0); dup2(fd, 0); dup2(fd, 1); - dup2(fd, 2); + dup2(fd, 2); // Redirect fd to 0, 1, 2 close(fd); } else { INIT_LOGE("Open /dev/console failed. err = %d", errno); @@ -149,113 +148,78 @@ static void OpenConsole() return; } -int ServiceStart(Service *service) +static void WriteServicePid(Service *service, pid_t pid) { - if (service == NULL) { - INIT_LOGE("start service failed! null ptr."); - return SERVICE_FAILURE; - } - if (service->pid > 0) { - INIT_LOGI("service : %s had started already.", service->name); - return SERVICE_SUCCESS; + char pidString[MAX_PID_STRING_LENGTH]; + INIT_ERROR_CHECK(snprintf_s(pidString, MAX_PID_STRING_LENGTH, MAX_PID_STRING_LENGTH - 1, "%d", pid) >= 0, + _exit(0x7f), "Build pid string failed"); + + for (int i = 0; i < MAX_WRITEPID_FILES; i++) { + if (service->writepidFiles[i] == NULL) { + break; + } + char *realPath = realpath(service->writepidFiles[i], NULL); + if (realPath == NULL) { + continue; + } + FILE *fd = fopen(realPath, "wb"); + free(realPath); + realPath = NULL; + INIT_ERROR_CHECK(fd != NULL, continue, "Open file %s failed, err = %d", service->writepidFiles[i], errno); + INIT_CHECK_ONLY_ELOG(fwrite(pidString, 1, strlen(pidString), fd) == strlen(pidString), + "write pid %s to file %s failed, err = %d", pidString, service->writepidFiles[i], errno); + fclose(fd); } +} + +int ServiceStart(Service *service) +{ + INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "start service failed! null ptr."); + INIT_INFO_CHECK(service->pid <= 0, return SERVICE_SUCCESS, "service : %s had started already.", service->name); if (service->attribute & SERVICE_ATTR_INVALID) { INIT_LOGE("start service %s invalid.", service->name); return SERVICE_FAILURE; } - if (service->pathArgs == NULL) { - INIT_LOGE("start service pathArgs is NULL."); - return SERVICE_FAILURE; - } + INIT_ERROR_CHECK(service->pathArgs != NULL, return SERVICE_FAILURE, "start service pathArgs is NULL."); struct stat pathStat = {0}; service->attribute &= (~(SERVICE_ATTR_NEED_RESTART | SERVICE_ATTR_NEED_STOP)); - if (stat(service->pathArgs[0], &pathStat) != 0) { - service->attribute |= SERVICE_ATTR_INVALID; - INIT_LOGE("start service %s invalid, please check %s.",\ - service->name, service->pathArgs[0]); - return SERVICE_FAILURE; - } - int ret = 0; - int pid = fork(); + INIT_ERROR_CHECK(stat(service->pathArgs[0], &pathStat) == 0, service->attribute |= SERVICE_ATTR_INVALID; + return SERVICE_FAILURE, "start service %s invalid, please check %s.", service->name, service->pathArgs[0]); + pid_t pid = fork(); if (pid == 0) { if (service->socketCfg != NULL) { // start socket service - INIT_LOGI("Create socket "); - ret = DoCreateSocket(service->socketCfg); - if (ret < 0) { - INIT_LOGE("DoCreateSocket failed. "); - _exit(0x7f); // 0x7f: user specified - } + INIT_ERROR_CHECK(DoCreateSocket(service->socketCfg) >= 0, _exit(0x7f), "Create Socket failed. "); } if (service->attribute & SERVICE_ATTR_CONSOLE) { OpenConsole(); } - // permissions - if (SetPerms(service) != SERVICE_SUCCESS) { - INIT_LOGE("service %s exit! set perms failed! err %d.", service->name, errno); - _exit(0x7f); // 0x7f: user specified - } - char pidString[MAX_PID_STRING_LENGTH]; // writepid - pid_t childPid = getpid(); - if (snprintf_s(pidString, MAX_PID_STRING_LENGTH, MAX_PID_STRING_LENGTH - 1, "%d", childPid) < 0) { - INIT_LOGE("start service writepid sprintf failed."); - _exit(0x7f); // 0x7f: user specified - } - for (int i = 0; i < MAX_WRITEPID_FILES; i++) { - if (service->writepidFiles[i] == NULL) { - continue; - } - char *realPath = realpath(service->writepidFiles[i], NULL); - if (realPath == NULL) { - continue; - } - FILE *fd = fopen(realPath, "wb"); - if (fd == NULL) { - INIT_LOGE("start service writepidFiles %s invalid.", service->writepidFiles[i]); - free(realPath); - realPath = NULL; - continue; - } - if (fwrite(pidString, 1, strlen(pidString), fd) != strlen(pidString)) { - INIT_LOGE("start service writepid error.file:%s pid:%s", service->writepidFiles[i], pidString); - } - free(realPath); - realPath = NULL; - fclose(fd); - INIT_LOGE("ServiceStart writepid filename=%s, childPid=%s, ok", service->writepidFiles[i], - pidString); - } - + INIT_ERROR_CHECK(SetPerms(service) == SERVICE_SUCCESS, _exit(0x7f), + "service %s exit! set perms failed! err %d.", service->name, errno); + WriteServicePid(service, getpid()); INIT_LOGI("service->name is %s ", service->name); #ifndef OHOS_LITE if (service->importance != 0) { - if (setpriority(PRIO_PROCESS, 0, service->importance) != 0) { - INIT_LOGE("setpriority failed for %s, importance = %d", service->name, service->importance); - _exit(0x7f); // 0x7f: user specified - } + INIT_ERROR_CHECK(setpriority(PRIO_PROCESS, 0, service->importance) == 0, _exit(0x7f), + "setpriority failed for %s, importance = %d", service->name, service->importance); } // L2 Can not be reset env - if (execv(service->pathArgs[0], service->pathArgs) != 0) { - INIT_LOGE("service %s execve failed! err %d.", service->name, errno); - } + INIT_CHECK_ONLY_ELOG(execv(service->pathArgs[0], service->pathArgs) == 0, + "service %s execve failed! err %d.", service->name, errno); #else char* env[] = {"LD_LIBRARY_PATH=/storage/app/libs", NULL}; - if (execve(service->pathArgs[0], service->pathArgs, env) != 0) { - INIT_LOGE("service %s execve failed! err %d.", service->name, errno); - } + INIT_CHECK_ONLY_ELOG(execve(service->pathArgs[0], service->pathArgs, env) == 0, + "service %s execve failed! err %d.", service->name, errno); #endif - _exit(0x7f); // 0x7f: user specified } else if (pid < 0) { INIT_LOGE("start service %s fork failed!", service->name); return SERVICE_FAILURE; } - service->pid = pid; #ifndef OHOS_LITE char paramName[PARAM_NAME_LEN_MAX] = {0}; - if (snprintf_s(paramName, PARAM_NAME_LEN_MAX, PARAM_NAME_LEN_MAX - 1, "init.svc.%s", service->name) < 0) { - INIT_LOGE("snprintf_s paramName error %d ", errno); - } + INIT_CHECK_ONLY_ELOG(snprintf_s(paramName, PARAM_NAME_LEN_MAX, PARAM_NAME_LEN_MAX - 1, "init.svc.%s", + service->name) >= 0, "snprintf_s paramName error %d ", errno); SystemWriteParam(paramName, "running"); #endif return SERVICE_SUCCESS; @@ -338,7 +302,6 @@ void ServiceReap(Service *service) INIT_LOGE("reap service failed! null ptr."); return; } - service->pid = -1; #ifndef OHOS_LITE char paramName[PARAM_NAME_LEN_MAX] = {0}; @@ -351,14 +314,12 @@ void ServiceReap(Service *service) INIT_LOGE("ServiceReap service %s invalid.", service->name); return; } - // 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); service->crashCnt = 0; return; } - // for one-shot service if (service->attribute & SERVICE_ATTR_ONCE) { // no need to restart @@ -366,9 +327,7 @@ void ServiceReap(Service *service) service->attribute &= (~SERVICE_ATTR_NEED_STOP); return; } - // the service could be restart even if it is one-shot service } - // the service that does not need to be restarted restarts, indicating that it has crashed if (!(service->attribute & SERVICE_ATTR_NEED_RESTART)) { // crash time and count check @@ -387,20 +346,11 @@ void ServiceReap(Service *service) } } } - CheckCritical(service); - int ret = 0; if (service->onRestart != NULL) { - ret = ExecRestartCmd(service); - if (ret != SERVICE_SUCCESS) { - INIT_LOGE("SetOnRestart fail "); - } + INIT_CHECK_ONLY_ELOG(ExecRestartCmd(service) == SERVICE_SUCCESS, "SetOnRestart fail "); } - ret = ServiceStart(service); - if (ret != SERVICE_SUCCESS) { - INIT_LOGE("reap service %s start failed!", service->name); - } - + INIT_CHECK_ONLY_ELOG(ServiceStart(service) == SERVICE_SUCCESS, "reap service %s start failed!", service->name); service->attribute &= (~SERVICE_ATTR_NEED_RESTART); } diff --git a/services/src/init_service_manager.c b/services/src/init_service_manager.c index 8079fbe8cb7c529689003a245e9d2d720eba9e41..06fca3db6a86cf85daeb71e60ff47604c5d60f4e 100644 --- a/services/src/init_service_manager.c +++ b/services/src/init_service_manager.c @@ -42,7 +42,7 @@ static Service* g_services = NULL; static int g_servicesCnt = 0; #ifdef OHOS_SERVICE_DUMP -void DumpAllServices() +void DumpAllServices(void) { if (g_services == NULL) { return; @@ -158,7 +158,6 @@ static int IsForbidden(const char* fieldStr) } #endif -// TODO: move this function to common files static cJSON* GetArrItem(const cJSON* fileRoot, int* arrSize, const char* arrName) { cJSON* arrItem = cJSON_GetObjectItemCaseSensitive(fileRoot, arrName); @@ -260,13 +259,11 @@ static int GetGidArray(const cJSON *curArrItem, Service *curServ) // gid if ((gIDCnt <= 0) || (filedJ == NULL)) { // not a array, but maybe a item? return GetGidOneItem(curArrItem, curServ); } - if (gIDCnt > NGROUPS_MAX + 1) { INIT_LOGE("GetGidArray, too many gids[cnt %d] for one service, should not exceed %d.", 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"); @@ -290,9 +287,7 @@ static int GetGidArray(const cJSON *curArrItem, Service *curServ) // gid } curServ->servPerm.gIDArray[i] = gID; } - if (i == gIDCnt) { - return SERVICE_SUCCESS; - } + INIT_CHECK_RETURN_VALUE(i != gIDCnt, SERVICE_SUCCESS); for (i = 0; i < gIDCnt; ++i) { cJSON *item = cJSON_GetArrayItem(filedJ, i); if (item == NULL) { @@ -308,27 +303,26 @@ static int GetGidArray(const cJSON *curArrItem, Service *curServ) // gid } curServ->servPerm.gIDArray[i] = gID; } - int ret = i == gIDCnt ? SERVICE_SUCCESS : SERVICE_FAILURE; - return ret; + return (((i == gIDCnt) ? SERVICE_SUCCESS : SERVICE_FAILURE)); } -static int GetServicePathAndArgs(const cJSON* curArrItem, Service* curServ) +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"); + INIT_LOGE("Path item not found or not a array"); 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", arrSize); + INIT_LOGE("Array size = %d is wrong", arrSize); return SERVICE_FAILURE; } - curServ->pathArgs = (char**)malloc((arrSize + 1) * sizeof(char*)); + curServ->pathArgs = (char **)malloc((arrSize + 1) * sizeof(char *)); if (curServ->pathArgs == NULL) { - INIT_LOGE("GetServicePathAndArgs malloc 1 error"); + INIT_LOGE("Current path is null."); return SERVICE_FAILURE; } for (int i = 0; i < arrSize + 1; ++i) { @@ -341,16 +335,16 @@ static int GetServicePathAndArgs(const cJSON* curArrItem, Service* curServ) 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"); + INIT_LOGE("Current param is null."); } else { - INIT_LOGE("GetServicePathAndArgs strlen = %d, error", strlen(curParam)); + INIT_LOGE("Length of current param is too long."); } return SERVICE_FAILURE; } if (i == 0 && IsForbidden(curParam)) { // resources will be released by function: ReleaseServiceMem - INIT_LOGE("GetServicePathAndArgs i == 0 && IsForbidden, error"); + INIT_LOGE("Service %s is forbidden.", curServ->name); return SERVICE_FAILURE; } @@ -358,13 +352,13 @@ static int GetServicePathAndArgs(const cJSON* curArrItem, Service* curServ) 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"); + INIT_LOGE("Service %s path is null.", curServ->name); 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."); + INIT_LOGE("memcpy_s failed."); return SERVICE_FAILURE; } curServ->pathArgs[i][paramLen] = '\0'; @@ -382,7 +376,7 @@ static int GetImportantValue(int value, Service *curServ) if (value >= MIN_IMPORTANT_LEVEL && value <= MAX_IMPORTANT_LEVEL) { // -20~19 curServ->importance = value; } else { - INIT_LOGE("importance level = %d, is not between -20 and 19, error", value); + INIT_LOGE("Importance level = %d, is not between -20 and 19, error", value); return SERVICE_FAILURE; } #endif @@ -401,7 +395,7 @@ static int GetServiceNumber(const cJSON* curArrItem, Service* curServ, const cha } if (!cJSON_IsNumber(filedJ)) { - INIT_LOGE("%s is null or is not a number, error.service name is %s", targetField, curServ->name); + INIT_LOGE("%s is null or is not a number, service name is %s", targetField, curServ->name); return SERVICE_FAILURE; } @@ -409,7 +403,7 @@ static int GetServiceNumber(const cJSON* curArrItem, Service* curServ, const cha // importance value allow < 0 if (strncmp(targetField, IMPORTANT_STR_IN_CFG, strlen(IMPORTANT_STR_IN_CFG)) != 0) { if (value < 0) { - INIT_LOGE("value = %d, error.service name is %s", value, curServ->name); + INIT_LOGE("Service %s value = %d is wrong", curServ->name, value); return SERVICE_FAILURE; } } @@ -436,7 +430,7 @@ static int GetServiceNumber(const cJSON* curArrItem, Service* curServ, const cha curServ->attribute |= SERVICE_ATTR_CONSOLE; } } else { - INIT_LOGE("item = %s, not expected, error.service name is %s", targetField, curServ->name); + INIT_LOGE("Item = %s, not expected, error.service name is %s", targetField, curServ->name); return SERVICE_FAILURE; } return SERVICE_SUCCESS; @@ -454,9 +448,9 @@ static int GetUidStringNumber(const cJSON *curArrItem, Service *curServ) if (fieldStr == NULL) { return SERVICE_FAILURE; } - int uID = DecodeUid(fieldStr); - if (uID < 0) { - INIT_LOGE("GetUidStringNumber, DecodeUid %s error.", fieldStr); + uid_t uID = DecodeUid(fieldStr); + if (uID == (uid_t)-1) { + INIT_LOGE("Decode uid %s error.", fieldStr); return SERVICE_FAILURE; } curServ->servPerm.uID = uID; @@ -466,14 +460,14 @@ static int GetUidStringNumber(const cJSON *curArrItem, Service *curServ) if (cJSON_IsNumber(filedJ)) { int uID = (int)cJSON_GetNumberValue(filedJ); if (uID < 0) { - INIT_LOGE("GetUidStringNumber, uID = %d error.", uID); + INIT_LOGE("Uid = %d error.", uID); return SERVICE_FAILURE; } curServ->servPerm.uID = uID; return SERVICE_SUCCESS; } - INIT_LOGE("GetUidStringNumber, this uid is neither a string nor a number, error."); + INIT_LOGE("This uid is neither a string nor a number, error."); return SERVICE_FAILURE; } @@ -486,8 +480,8 @@ static int ParseServiceSocket(char **opt, const int optNum, struct ServiceSocket 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); + ((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; @@ -496,23 +490,24 @@ static int ParseServiceSocket(char **opt, const int optNum, struct ServiceSocket if (opt[SERVICE_SOCK_UID] == NULL) { return -1; } - int uuid = DecodeUid(opt[SERVICE_SOCK_UID]); - if (uuid < 0) { + uid_t uid = DecodeUid(opt[SERVICE_SOCK_UID]); + if (uid == (uid_t)-1) { return -1; } - sockopt->uid = uuid; + sockopt->uid = uid; if (opt[SERVICE_SOCK_GID] == NULL) { return -1; } - int ggid = DecodeUid(opt[SERVICE_SOCK_GID]); - if (ggid < 0) { + gid_t gid = DecodeUid(opt[SERVICE_SOCK_GID]); + if (gid == (gid_t)-1) { return -1; } - sockopt->gid = ggid; + sockopt->gid = gid; 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->passcred = ((strncmp(opt[SERVICE_SOCK_SETOPT], "passcred", + strlen(opt[SERVICE_SOCK_SETOPT])) == 0) ? true : false); if (opt[SERVICE_SOCK_NAME] == NULL) { return -1; } @@ -533,7 +528,7 @@ static int ParseServiceSocket(char **opt, const int optNum, struct ServiceSocket static void FreeServiceSocket(struct ServiceSocket *sockopt) { - if (!sockopt) { + if (sockopt == NULL) { return; } struct ServiceSocket *tmpSock = NULL; @@ -548,6 +543,7 @@ static void FreeServiceSocket(struct ServiceSocket *sockopt) } return; } + static int GetServiceSocket(const cJSON* curArrItem, Service* curServ) { cJSON* filedJ = cJSON_GetObjectItem(curArrItem, "socket"); @@ -566,13 +562,13 @@ static int GetServiceSocket(const cJSON* curArrItem, Service* curServ) return SERVICE_FAILURE; } char *sockStr = cJSON_GetStringValue(sockJ); - char *tmpStr[SOCK_OPT_NUMS] = {NULL,}; + char *tmpStr[SOCK_OPT_NUMS] = {NULL}; int num = SplitString(sockStr, tmpStr, SOCK_OPT_NUMS); if (num != SOCK_OPT_NUMS) { return SERVICE_FAILURE; } struct ServiceSocket *socktmp = (struct ServiceSocket *)calloc(1, sizeof(struct ServiceSocket)); - if (!socktmp) { + if (socktmp == NULL) { return SERVICE_FAILURE; } int ret = ParseServiceSocket(tmpStr, SOCK_OPT_NUMS, socktmp); @@ -630,10 +626,51 @@ static int GetServiceOnRestart(const cJSON* curArrItem, Service* curServ) return SERVICE_SUCCESS; } +static bool IsServiceInMainStrap(Service *curServ) +{ + char *mainServiceList[] = { + "appspawn", "udevd", "samgr", "multimodalinput", "weston", "installs", "hiview", "hilogd", "hdf_devmgr", + "distributedsche", "softbus_server", "foundation" + }; + unsigned int length = ARRAY_LENGTH(mainServiceList); + for (unsigned int i = 0; i < length; ++i) { + if (strncmp(curServ->name, mainServiceList[i], strlen(mainServiceList[i])) == 0) { + INIT_LOGI("%s must be main service", curServ->name); + return true; + } + } + return false; +} + +static int GetDynamicService(const cJSON *curArrItem, Service *curServ) +{ + cJSON *item = cJSON_GetObjectItem(curArrItem, "dynamic"); + if (item == NULL) { + return SERVICE_SUCCESS; + } + + INIT_ERROR_CHECK(cJSON_IsBool(item), return SERVICE_FAILURE, + "Service : %s dynamic value only support bool.", curServ->name); + bool isDynamic = (bool)cJSON_GetNumberValue(item); + if (!isDynamic) { + INIT_LOGI("Service : %s dynamic value is false, it will be started with init.", curServ->name); + return SERVICE_SUCCESS; + } + + if (IsServiceInMainStrap(curServ)) { + return SERVICE_SUCCESS; + } + INIT_LOGI("%s is dynamic service", curServ->name); + curServ->attribute |= SERVICE_ATTR_DYNAMIC; + curServ->attribute |= SERVICE_ATTR_ONCE; + return SERVICE_SUCCESS; +} + static int CheckServiceKeyName(const cJSON* curService) { - char *cfgServiceKeyList[] = {"name", "path", "uid", "gid", "once", - "importance", "caps", "disabled", "writepid", "critical", "socket", "console" + char *cfgServiceKeyList[] = { + "name", "path", "uid", "gid", "once", "importance", "caps", "disabled", + "writepid", "critical", "socket", "console", "dynamic" }; if (curService == NULL) { return SERVICE_FAILURE; @@ -642,15 +679,15 @@ static int CheckServiceKeyName(const cJSON* curService) if (child == NULL) { return SERVICE_FAILURE; } - while (child) { + while (child != NULL) { int i = 0; - int keyListSize = sizeof(cfgServiceKeyList) / sizeof(char *); + int keyListSize = ARRAY_LENGTH(cfgServiceKeyList); for (; i < keyListSize; i++) { - if (!strcmp(child->string, cfgServiceKeyList[i])) { + if (strcmp(child->string, cfgServiceKeyList[i]) == 0) { break; } } - if(i < keyListSize) { + if (i < keyListSize) { child = child->next; } else { INIT_LOGE("CheckServiceKeyName, key name %s is not found. error.", child->string); @@ -660,28 +697,41 @@ static int CheckServiceKeyName(const cJSON* curService) return SERVICE_SUCCESS; } +static int ParseOneService(const cJSON *curItem, Service *service) +{ + if (curItem == NULL || service == NULL) { + return SERVICE_FAILURE; + } + int ret = GetServiceName(curItem, service); + ret |= GetServicePathAndArgs(curItem, service); + ret |= GetUidStringNumber(curItem, service); + ret |= GetGidArray(curItem, service); + ret |= GetServiceNumber(curItem, service, ONCE_STR_IN_CFG); + ret |= GetServiceNumber(curItem, service, IMPORTANT_STR_IN_CFG); + ret |= GetServiceNumber(curItem, service, CRITICAL_STR_IN_CFG); + ret |= GetServiceNumber(curItem, service, DISABLED_STR_IN_CFG); + ret |= GetServiceNumber(curItem, service, CONSOLE_STR_IN_CFG); + ret |= GetWritepidStrings(curItem, service); + ret |= GetServiceCaps(curItem, service); + ret |= GetDynamicService(curItem, service); + return ret; +} + void ParseAllServices(const cJSON* fileRoot) { int servArrSize = 0; cJSON* serviceArr = GetArrItem(fileRoot, &servArrSize, SERVICES_ARR_NAME_IN_JSON); - if (serviceArr == NULL) { - INIT_LOGI("ParseAllServices, this config does not contain service array."); - return; - } + INIT_INFO_CHECK(serviceArr != NULL, return, "This config does not contain service array."); + + INIT_ERROR_CHECK(servArrSize <= MAX_SERVICES_CNT_IN_FILE, return, + "Too many services[cnt %d] detected, should not exceed %d.", + servArrSize, MAX_SERVICES_CNT_IN_FILE); + INIT_CHECK_ONLY_RETURN((g_servicesCnt + servArrSize) > 0); - if (servArrSize > MAX_SERVICES_CNT_IN_FILE) { - INIT_LOGE("ParseAllServices, too many services[cnt %d] detected, should not exceed %d.", - servArrSize, MAX_SERVICES_CNT_IN_FILE); - return; - } - if ((g_servicesCnt + servArrSize) <= 0) { - return; - } Service* retServices = (Service*)realloc(g_services, sizeof(Service) * (g_servicesCnt + servArrSize)); - if (retServices == NULL) { - INIT_LOGE("ParseAllServices, realloc for %s arr failed! %d.", SERVICES_ARR_NAME_IN_JSON, servArrSize); - return; - } + INIT_ERROR_CHECK(retServices != NULL, return, + "Realloc for %s arr failed! %d.", SERVICES_ARR_NAME_IN_JSON, servArrSize); + // Skip already saved services, Service* tmp = retServices + g_servicesCnt; if (memset_s(tmp, sizeof(Service) * servArrSize, 0, sizeof(Service) * servArrSize) != EOK) { @@ -697,28 +747,17 @@ void ParseAllServices(const cJSON* fileRoot) 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 = GetServiceNumber(curItem, &tmp[i], CONSOLE_STR_IN_CFG); // console - int reta = GetWritepidStrings(curItem, &tmp[i]); // writepid - int retb = GetServiceCaps(curItem, &tmp[i]); - int retAll = ret1 | ret2 | ret3 | ret4 | ret5 | ret6 | ret7 | ret8 | ret9 | reta | retb; - if (retAll != SERVICE_SUCCESS) { + int ret = ParseOneService(curItem, &tmp[i]); + if (ret != 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); + INIT_LOGE("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", - i, tmp[i].name, tmp[i].servPerm.uID, tmp[i].attribute & SERVICE_ATTR_CRITICAL ? 1 : 0, - tmp[i].attribute & SERVICE_ATTR_DISABLED ? 1 : 0); + INIT_LOGD("service[%d] name=%s, uid=%d, critical=%d, disabled=%d", + 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) { if (tmp[i].socketCfg != NULL) { @@ -747,19 +786,21 @@ static int FindServiceByName(const char* servName) return -1; } -void StartServiceByName(const char* servName) +void StartServiceByName(const char *servName, bool checkDynamic) { // find service by name int servIdx = FindServiceByName(servName); if (servIdx < 0) { - INIT_LOGE("StartServiceByName, cannot find service %s.", servName); + INIT_LOGE("Cannot find service %s.", servName); + return; + } + if (checkDynamic && (g_services[servIdx].attribute & SERVICE_ATTR_DYNAMIC)) { + INIT_LOGI("%s is dynamic service.", servName); return; } - if (ServiceStart(&g_services[servIdx]) != SERVICE_SUCCESS) { - INIT_LOGE("StartServiceByName, service %s start failed!", g_services[servIdx].name); + INIT_LOGE("Service %s start failed!", g_services[servIdx].name); } - return; } @@ -768,31 +809,30 @@ void StopServiceByName(const char* servName) // find service by name int servIdx = FindServiceByName(servName); if (servIdx < 0) { - INIT_LOGE("StopServiceByName, cannot find service %s.", servName); + INIT_LOGE("Cannot find service %s.", servName); return; } if (ServiceStop(&g_services[servIdx]) != SERVICE_SUCCESS) { - INIT_LOGE("StopServiceByName, service %s start failed!", g_services[servIdx].name); + INIT_LOGE("Service %s start failed!", g_services[servIdx].name); } return; } -void StopAllServices() +void StopAllServices(void) { if (g_services == NULL) { return; } - for (int i = 0; i < g_servicesCnt; i++) { if (ServiceStop(&g_services[i]) != SERVICE_SUCCESS) { - INIT_LOGE("StopAllServices, service %s stop failed!", g_services[i].name); + INIT_LOGE("Service %s stop failed!", g_services[i].name); } } } -void StopAllServicesBeforeReboot() +void StopAllServicesBeforeReboot(void) { if (g_services == NULL) { return; @@ -801,7 +841,7 @@ 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!", g_services[i].name); + INIT_LOGE("Service %s stop failed!", g_services[i].name); } } } @@ -828,4 +868,3 @@ void ReapServiceByPID(int pid) } } - diff --git a/services/src/init_service_socket.c b/services/src/init_service_socket.c index f6d9720c249c1014c62f53b8d06f5384c091b9e1..653f3f8242a240c21caaaaf374b8e078a909cdbd 100644 --- a/services/src/init_service_socket.c +++ b/services/src/init_service_socket.c @@ -33,7 +33,7 @@ static int CreateSocket(struct ServiceSocket *sockopt) { - if (!sockopt || !sockopt->name) { + if (sockopt == NULL || sockopt->name == NULL) { return -1; } if (sockopt->sockFd >= 0) { @@ -41,13 +41,10 @@ static int CreateSocket(struct ServiceSocket *sockopt) sockopt->sockFd = -1; } sockopt->sockFd = socket(PF_UNIX, sockopt->type, 0); - if (sockopt->sockFd < 0) { - INIT_LOGE("socket fail %d ", errno); - return -1; - } + INIT_ERROR_CHECK(sockopt->sockFd >= 0, return -1, "socket fail %d ", errno); struct sockaddr_un addr; - bzero(&addr,sizeof(addr)); + bzero(&addr, sizeof(addr)); addr.sun_family = AF_UNIX; if (snprintf_s(addr.sun_path, sizeof(addr.sun_path), sizeof(addr.sun_path) - 1, HOS_SOCKET_DIR"/%s", sockopt->name) < 0) { @@ -117,11 +114,11 @@ static int SetSocketEnv(int fd, const char *name) int DoCreateSocket(struct ServiceSocket *sockopt) { - if (!sockopt) { + if (sockopt == NULL) { return -1; } struct ServiceSocket *tmpSock = sockopt; - while (tmpSock) { + while (tmpSock != NULL) { int fd = CreateSocket(tmpSock); if (fd < 0) { return -1; diff --git a/services/src/init_signal_handler.c b/services/src/init_signal_handler.c index b17fa929cde068bd6913cbbe0c87604d772c1817..81fdf42011d8960d5a94bf249d0d163c2e8b9385 100644 --- a/services/src/init_signal_handler.c +++ b/services/src/init_signal_handler.c @@ -27,7 +27,6 @@ #include "init_service_manager.h" #ifndef OHOS_LITE -#include "init_param.h" #include "uv.h" #endif @@ -72,7 +71,7 @@ static void SigHandler(int sig) } if (WIFEXITED(procStat)) { - INIT_LOGE("Child process %d exit with code : %d", sigPID, WEXITSTATUS(procStat)); + INIT_LOGE("Child process %d exit with code : %d", sigPID, WEXITSTATUS((unsigned int)procStat)); } #endif diff --git a/services/src/init_utils.c b/services/src/init_utils.c index f1dba38a040d2f80527d30f0effbfea289cacff6..58c2262498f8b4e81e207a6d17a730f0562f58e4 100644 --- a/services/src/init_utils.c +++ b/services/src/init_utils.c @@ -14,20 +14,15 @@ */ #include "init_utils.h" #include -#include -#include -#include -#include -#include #include #include -#include +#include #include -#include #include -#include +#include #include #include +#include #include #include "init_log.h" @@ -43,23 +38,29 @@ #endif #define MAX_JSON_FILE_LEN 102400 // max init.cfg size 100KB -#define CONVERT_MICROSEC_TO_SEC(x) ((x) / 1000 / 1000.0) +#define THOUSAND_UNIT_INT 1000 +#define THOUSAND_UNIT_FLOAT 1000.0 + +float ConvertMicrosecondToSecond(int x) +{ + return ((x / THOUSAND_UNIT_INT) / THOUSAND_UNIT_FLOAT); +} -int DecodeUid(const char *name) +uid_t DecodeUid(const char *name) { if (name == NULL) { return -1; } - bool digitFlag = true; + int digitFlag = 1; for (unsigned int i = 0; i < strlen(name); ++i) { if (isalpha(name[i])) { - digitFlag = false; + digitFlag = 0; break; } } if (digitFlag) { errno = 0; - uid_t result = strtoul(name, 0, 10); + uid_t result = strtoul(name, 0, DECIMAL_BASE); if (errno != 0) { return -1; } @@ -73,18 +74,6 @@ int DecodeUid(const char *name) } } -void CheckAndCreateDir(const char *fileName) -{ - if (fileName == NULL || *fileName == '\0') { - return; - } - 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; @@ -128,7 +117,7 @@ char* ReadFileToBuf(const char *configFile) int SplitString(char *srcPtr, char **dstPtr, int maxNum) { - if ((!srcPtr) || (!dstPtr)){ + if (srcPtr == NULL || dstPtr == NULL) { return -1; } char *buf = NULL; @@ -155,9 +144,33 @@ void WaitForFile(const char *source, unsigned int maxCount) usleep(waitTime); count++; } while ((stat(source, &sourceInfo) < 0) && (errno == ENOENT) && (count < maxCount)); + float secTime = ConvertMicrosecondToSecond(waitTime); if (count == maxCount) { - INIT_LOGE("wait for file:%s failed after %f.", source, maxCount * CONVERT_MICROSEC_TO_SEC(waitTime)); + INIT_LOGE("wait for file:%s failed after %f.", source, maxCount * secTime); } return; } +size_t WriteAll(int fd, char *buffer, size_t size) +{ + if (fd < 0 || buffer == NULL || *buffer == '\0') { + return 0; + } + + char *p = buffer; + size_t left = size; + ssize_t written = -1; + + while (left > 0) { + do { + written = write(fd, p, left); + } while (written < 0 && errno == EINTR); + if (written < 0) { + INIT_LOGE("Failed to write %lu bytes, err = %d", left, errno); + break; + } + p += written; + left -= written; + } + return size - left; +} \ No newline at end of file diff --git a/ueventd/list.c b/services/src/list.c similarity index 85% rename from ueventd/list.c rename to services/src/list.c index 17e6f468fc9087fa8ef81ac29fd9a18d103f01fa..805d095c830023aa3f33b938606b673969c0e082 100755 --- a/ueventd/list.c +++ b/services/src/list.c @@ -15,14 +15,22 @@ #include "list.h" +#include + void ListInit(struct ListNode *node) { + if (node == NULL) { + return; + } node->next = node; node->prev = node; } void ListAddTail(struct ListNode *head, struct ListNode *item) { + if (head == NULL || item == NULL) { + return; + } item->next = head; item->prev = head->prev; head->prev->next = item; @@ -31,6 +39,9 @@ void ListAddTail(struct ListNode *head, struct ListNode *item) void ListRemove(struct ListNode *item) { + if (item == NULL) { + return; + } item->next->prev = item->prev; item->prev->next = item->next; } diff --git a/services/src/main.c b/services/src/main.c index 8c027bcd21ab8b261475685dadd9f2774bc81d82..40a6de2798a684221d6ab935f1efe0a0cd5d9c92 100644 --- a/services/src/main.c +++ b/services/src/main.c @@ -66,14 +66,13 @@ static long TimeDiffMs(const struct timespec* tmBefore, const struct timespec* t int main(int argc, char **argv) { #ifndef OHOS_LITE - if(setenv("UV_THREADPOOL_SIZE", "1", 1) != 0) { + if (setenv("UV_THREADPOOL_SIZE", "1", 1) != 0) { INIT_LOGE("set UV_THREADPOOL_SIZE error : %d.", errno); } - CloseStdio(); OpenLogDevice(); - #endif + #ifdef OHOS_DEBUG struct timespec tmEnter; if (clock_gettime(CLOCK_REALTIME, &tmEnter) != 0) { @@ -85,19 +84,15 @@ int main(int argc, char **argv) INIT_LOGE("main, current process id is %d not %d, failed!", getpid(), INIT_PROCESS_PID); return 0; } - - // 1. print system info PrintSysInfo(); #ifndef OHOS_LITE - // 2. Mount basic filesystem and create common device node. MountBasicFs(); CreateDeviceNode(); EnableDevKmsg(); MakeSocketDir("/dev/unix/socket/", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); #endif - // 3. signal register SignalInitModule(); #ifdef OHOS_DEBUG @@ -107,7 +102,6 @@ int main(int argc, char **argv) } #endif // OHOS_DEBUG - // 4. execute rcs ExecuteRcs(); #ifdef OHOS_DEBUG @@ -116,7 +110,6 @@ int main(int argc, char **argv) INIT_LOGE("main, after rcs, get time failed! err %d.", errno); } #endif // OHOS_DEBUG - // 5. read configuration file and do jobs InitReadCfg(); #ifdef OHOS_DEBUG struct timespec tmCfg; @@ -125,7 +118,6 @@ int main(int argc, char **argv) } #endif // OHOS_DEBUG - // 6. keep process alive #ifdef OHOS_DEBUG INIT_LOGI("main, time used: sigInfo %ld ms, rcs %ld ms, cfg %ld ms.", \ TimeDiffMs(&tmEnter, &tmSysInfo), TimeDiffMs(&tmSysInfo, &tmRcs), TimeDiffMs(&tmRcs, &tmCfg)); @@ -136,8 +128,6 @@ int main(int argc, char **argv) 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. (void)pause(); } return 0; diff --git a/services/test/unittest/common/cmd_func_test.cpp b/services/test/unittest/common/cmd_func_test.cpp index 66450f7e063724b82d0cde13fcd510deaa1af691..03a92d5afb0f633af11855f0443910e70b9df095 100644 --- a/services/test/unittest/common/cmd_func_test.cpp +++ b/services/test/unittest/common/cmd_func_test.cpp @@ -934,7 +934,7 @@ HWTEST_F(StartupInitUTest, cmdJobTest_001, TestSize.Level0) DoJob("job name does not exist"); ReleaseAllJobs(); RegisterServices(nullptr, 0); - StartServiceByName("service name does not exist"); + StartServiceByName("service name does not exist", false); StopAllServices(); ReapServiceByPID(INVALID_PID); ServiceReap(nullptr); diff --git a/ueventd/BUILD.gn b/ueventd/BUILD.gn index 5d725eff9dc11259cb8dead521bf21f4303553d2..719441da6eec4437201dd07f028e360fcec658f2 100755 --- a/ueventd/BUILD.gn +++ b/ueventd/BUILD.gn @@ -16,19 +16,20 @@ if (!defined(ohos_lite)) { ohos_executable("ueventd") { sources = [ - "list.c", - "ueventd.c", - "ueventd_device_handler.c", - "ueventd_firmware_handler.c", - "ueventd_read_cfg.c", - "ueventd_socket.c", - "ueventd_utils.c", + "//base/startup/init_lite/services/src/list.c", + "//base/startup/init_lite/ueventd/ueventd.c", + "//base/startup/init_lite/ueventd/ueventd_device_handler.c", + "//base/startup/init_lite/ueventd/ueventd_firmware_handler.c", + "//base/startup/init_lite/ueventd/ueventd_read_cfg.c", + "//base/startup/init_lite/ueventd/ueventd_socket.c", + "//base/startup/init_lite/ueventd/ueventd_utils.c", ] include_dirs = [ "include", "//third_party/bounds_checking_function/include", "//base/startup/init_lite/services/log", + "//base/startup/init_lite/services/include", ] deps = [ diff --git a/ueventd/ueventd.c b/ueventd/ueventd.c index 98ab43e55731cffa7cd9cc2d6a5e158dccc563c2..c086608ba18d38ef1bdf98adb6a4d0a8cd1dbbeb 100755 --- a/ueventd/ueventd.c +++ b/ueventd/ueventd.c @@ -140,9 +140,9 @@ static void AddUevent(struct Uevent *uevent, const char *event, size_t len) } else if (STARTSWITH(event, "MINOR=")) { uevent->minor = StringToInt(event + strlen("MINOR="), -1); } else if (STARTSWITH(event, "DEVUID")) { - uevent->ug.uid = StringToInt(event + strlen("DEVUID="), 0); + uevent->ug.uid = (uid_t)StringToInt(event + strlen("DEVUID="), 0); } else if (STARTSWITH(event, "DEVGID")) { - uevent->ug.gid = StringToInt(event + strlen("DEVGID="), 0); + uevent->ug.gid = (gid_t)StringToInt(event + strlen("DEVGID="), 0); } else if (STARTSWITH(event, "FIRMWARE=")) { uevent->firmware = event + strlen("FIRMWARE="); } else if (STARTSWITH(event, "BUSNUM=")) { @@ -153,7 +153,7 @@ static void AddUevent(struct Uevent *uevent, const char *event, size_t len) // Ignore other events } -static void ParseUeventMessage(char *buffer, ssize_t length, struct Uevent *uevent) +static void ParseUeventMessage(const char *buffer, ssize_t length, struct Uevent *uevent) { if (buffer == NULL || uevent == NULL || length == 0) { // Ignore invalid buffer @@ -168,7 +168,7 @@ static void ParseUeventMessage(char *buffer, ssize_t length, struct Uevent *ueve uevent->devNum = -1; ssize_t pos = 0; while (pos < length) { - char *event = buffer + pos; + const char *event = buffer + pos; size_t len = strlen(event); if (len == 0) { break; diff --git a/ueventd/ueventd_device_handler.c b/ueventd/ueventd_device_handler.c index d23277242204fcc9a68b01788288b11f03d74416..1511ed988db0b2b58ff59169ef98d46b1f23fb99 100755 --- a/ueventd/ueventd_device_handler.c +++ b/ueventd/ueventd_device_handler.c @@ -104,7 +104,7 @@ static int CreateDeviceNode(const struct Uevent *uevent, const char *deviceNode, INIT_LOGE("Create path \" %s \" failed", devicePath); return rc; } - + GetDeviceNodePermissions(deviceNode, &uid, &gid, &mode); mode |= isBlock ? S_IFBLK : S_IFCHR; dev_t dev = makedev(major, minor); @@ -112,15 +112,15 @@ static int CreateDeviceNode(const struct Uevent *uevent, const char *deviceNode, rc = mknod(deviceNode, mode, dev); if (rc < 0) { if (errno != EEXIST) { - INIT_LOGE("Create device node[%s %d, %d] failed", deviceNode, major, minor, errno); + INIT_LOGE("Create device node[%s %d, %d] failed. %d", deviceNode, major, minor, errno); return rc; } } AdjustDeviceNodePermissions(deviceNode, uid, gid, mode); - if (symLinks) { + if (symLinks != NULL) { CreateSymbolLinks(deviceNode, symLinks); } - // No matter what result the symbol links returns, + // No matter what result the symbol links returns, // as long as create device node done, just returns success. rc = 0; return rc; @@ -128,10 +128,9 @@ static int CreateDeviceNode(const struct Uevent *uevent, const char *deviceNode, static int RemoveDeviceNode(const char *deviceNode, char **symLinks) { - int rc = -1; if (INVALIDSTRING(deviceNode)) { INIT_LOGE("Invalid device node"); - return rc; + return -1; } if (symLinks != NULL) { for (int i = 0; symLinks[i] != NULL; i++) { @@ -149,9 +148,44 @@ static int RemoveDeviceNode(const char *deviceNode, char **symLinks) return unlink(deviceNode); } +static char *FindPlatformDeviceName(char *path) +{ + if (INVALIDSTRING(path)) { + return NULL; + } + + if (STARTSWITH(path, "/sys/devices/platform/")) { + path += strlen("/sys/devices/platform/"); + return path; + } + return NULL; +} + +static void BuildDeviceSymbolLinks(char **links, int linkNum, const char *parent, const char *partitionName) +{ + if (linkNum > BLOCKDEVICE_LINKS - 1) { + INIT_LOGW("Too many links, ignore"); + return; + } + + // If a block device without partition name. + // For now, we will not create symbol link for it. + if (!INVALIDSTRING(partitionName)) { + links[linkNum] = calloc(sizeof(char), DEVICE_FILE_SIZE); + if (links[linkNum] == NULL) { + INIT_LOGE("Failed to allocate memory for link, err = %d", errno); + return; + } + if (snprintf_s(links[linkNum], DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, + "/dev/block/platform/%s/by-name/%s", parent, partitionName) == -1) { + INIT_LOGE("Failed to build link"); + } + } +} + static char **GetBlockDeviceSymbolLinks(const struct Uevent *uevent) { - if (uevent == NULL || !STRINGEQUAL(uevent->subsystem, "block")) { + if (uevent == NULL || uevent->subsystem == NULL || STRINGEQUAL(uevent->subsystem, "block") == 0) { INIT_LOGW("Invalid arguments, Skip to get device symbol links."); return NULL; } @@ -163,7 +197,7 @@ static char **GetBlockDeviceSymbolLinks(const struct Uevent *uevent) // For block device under one platform device. // check subsystem file under directory, see if it links to bus/platform. // For now, only support platform device. - char sysPath[SYSPATH_SIZE] = {}; + char sysPath[SYSPATH_SIZE] = {}; if (snprintf_s(sysPath, SYSPATH_SIZE, SYSPATH_SIZE - 1, "/sys%s", uevent->syspath) == -1) { INIT_LOGE("Failed to build sys path for device %s", uevent->syspath); return NULL; @@ -173,6 +207,7 @@ static char **GetBlockDeviceSymbolLinks(const struct Uevent *uevent) int linkNum = 0; if (links == NULL) { INIT_LOGE("Failed to allocate memory for links, err = %d", errno); + return NULL; } // Reverse walk through sysPath, and check subystem file under each directory. @@ -185,39 +220,19 @@ static char **GetBlockDeviceSymbolLinks(const struct Uevent *uevent) } char *bus = realpath(subsystem, NULL); - if (bus == NULL) { - goto loop; - } - - if (STRINGEQUAL(bus, "/sys/bus/platform")) { - INIT_LOGD("Find a platform device: %s", parent); - if (STARTSWITH(parent, "/sys/devices/platform/")) { - parent += strlen("/sys/devices/platform/"); - if (linkNum > BLOCKDEVICE_LINKS - 1) { - INIT_LOGW("Too much links, ignore"); - break; - } - links[linkNum] = calloc(sizeof(char), DEVICE_FILE_SIZE); - if (links[linkNum] == NULL) { - INIT_LOGE("Failed to allocate memory for link, err = %d", errno); - break; - } - // If a block device without partition name. - // For now, we will not create symbol link for it. - if (!INVALIDSTRING(uevent->partitionName)) { - if (snprintf_s(links[linkNum], DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, - "/dev/block/platform/%s/by-name/%s", parent, uevent->partitionName) == -1) { - INIT_LOGE("Failed to build link"); - break; - } + if (bus != NULL) { + if (STRINGEQUAL(bus, "/sys/bus/platform")) { + INIT_LOGD("Find a platform device: %s", parent); + parent = FindPlatformDeviceName(parent); + if (parent != NULL) { + BuildDeviceSymbolLinks(links, linkNum, parent, uevent->partitionName); } linkNum++; } } -loop: parent = dirname(parent); - continue; } + links[linkNum] = NULL; return links; } @@ -340,6 +355,9 @@ void HandleBlockDeviceEvent(const struct Uevent *uevent) char deviceNode[DEVICE_FILE_SIZE] = {}; char sysPath[SYSPATH_SIZE] = {}; + if (uevent->syspath == NULL) { + return; + } if (strncpy_s(sysPath, SYSPATH_SIZE - 1, uevent->syspath, strlen(uevent->syspath) != EOK)) { INIT_LOGE("Failed to copy sys path"); return; @@ -359,7 +377,7 @@ void HandleBlockDeviceEvent(const struct Uevent *uevent) void HandleOtherDeviceEvent(const struct Uevent *uevent) { - if (uevent == NULL || uevent->subsystem == NULL) { + if (uevent == NULL || uevent->subsystem == NULL || uevent->syspath == NULL) { INIT_LOGE("Invalid uevent received"); return; } @@ -383,10 +401,10 @@ void HandleOtherDeviceEvent(const struct Uevent *uevent) } INIT_LOGD("HandleOtherDeviceEvent, devPath = %s, devName = %s", devPath, devName); - // For usb devices, should take care of it specially. - // if usb devices report DEVNAME, just create device node. - // otherwise, create deviceNode with bus number and device number. - if (STRINGEQUAL(uevent->subsystem, "usb")) { + // For usb devices, should take care of it specially. + // if usb devices report DEVNAME, just create device node. + // otherwise, create deviceNode with bus number and device number. + if (STRINGEQUAL(uevent->subsystem, "usb")) { if (uevent->deviceName != NULL) { if (snprintf_s(deviceNode, DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, "/dev/%s", uevent->deviceName) == -1) { INIT_LOGE("Make device file for device [%d : %d]", uevent->major, uevent->minor); @@ -398,19 +416,19 @@ void HandleOtherDeviceEvent(const struct Uevent *uevent) INIT_LOGE("usb device with invalid bus number or device number"); return; } - if (snprintf_s(deviceNode, DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, + if (snprintf_s(deviceNode, DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, "/dev/bus/usb/%03d/%03d", uevent->busNum, uevent->devNum) == -1) { - INIT_LOGE("Make usb device node for device [%d : %d]", uevent->busNum, uevent->devNum); + INIT_LOGE("Make usb device node for device [%d : %d]", uevent->busNum, uevent->devNum); } } - } else if (STARTSWITH(uevent->subsystem, "usb")) { - // Other usb devies, do not handle it. - return; - } else { + } else if (STARTSWITH(uevent->subsystem, "usb")) { + // Other usb devies, do not handle it. + return; + } else { if (snprintf_s(deviceNode, DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, "%s/%s", devPath, devName) == -1) { INIT_LOGE("Make device file for device [%d : %d]", uevent->major, uevent->minor); return; } - } - HandleDeviceNode(uevent, deviceNode, false); + } + HandleDeviceNode(uevent, deviceNode, false); } diff --git a/ueventd/ueventd_read_cfg.c b/ueventd/ueventd_read_cfg.c index ef938be08f15a481061fe186f1521fc0935a79ce..3585924b9cfb00d755225794da2dbf7a495a04f1 100755 --- a/ueventd/ueventd_read_cfg.c +++ b/ueventd/ueventd_read_cfg.c @@ -15,6 +15,7 @@ #include "ueventd_read_cfg.h" #include +#include #include #include #include @@ -29,6 +30,18 @@ // default item count in config files #define DEFAULTITEMCOUNT (100) + +#define SYS_CONFIG_PATH_NUM 0 +#define SYS_CONFIG_ATTR_NUM 1 +#define SYS_CONFIG_MODE_NUM 2 +#define SYS_CONFIG_UID_NUM 3 +#define SYS_CONFIG_GID_NUM 4 + +#define DEVICE_CONFIG_NAME_NUM 0 +#define DEVICE_CONFIG_MODE_NUM 1 +#define DEVICE_CONFIG_UID_NUM 2 +#define DEVICE_CONFIG_GID_NUM 3 + typedef enum SECTION { SECTION_INVALID = -1, SECTION_DEVICE = 0, @@ -74,23 +87,25 @@ static char **SplitUeventConfig(char *buffer, const char *del, int *returnCount, { char *rest = NULL; int count = 0; + int average = 2; char *p = strtok_r(buffer, del, &rest); - if (maxItemCount < 0) { + int maxItemCountTmp = maxItemCount; + if (maxItemCountTmp < 0) { return NULL; } - if (maxItemCount > DEFAULTITEMCOUNT) { - maxItemCount = DEFAULTITEMCOUNT; + if (maxItemCountTmp > DEFAULTITEMCOUNT) { + maxItemCountTmp = DEFAULTITEMCOUNT; } - char **items = (char **)malloc(sizeof(char*) * maxItemCount); + char **items = (char **)malloc(sizeof(char*) * maxItemCountTmp); if (items == NULL) { INIT_LOGE("No enough memory to store uevent config"); return NULL; } while (p != NULL) { - if (count > maxItemCount - 1) { - maxItemCount += (maxItemCount / 2) + 1; + if (count > (maxItemCountTmp - 1)) { + maxItemCountTmp += (maxItemCountTmp / average) + 1; INIT_LOGD("Too many items,expand size"); - char **expand = (char **)(realloc(items, sizeof(char *) * maxItemCount)); + char **expand = (char **)(realloc(items, sizeof(char *) * maxItemCountTmp)); if (expand == NULL) { INIT_LOGE("Failed to expand memory for uevent config parser"); FreeConfigItems(items, count); @@ -124,7 +139,7 @@ static int ParseDeviceConfig(char *p) char **items = NULL; int count = -1; // format: - int expectedCount = 4; + const int expectedCount = 4; if (INVALIDSTRING(p)) { INIT_LOGE("Invalid argument"); @@ -142,15 +157,15 @@ static int ParseDeviceConfig(char *p) FreeConfigItems(items, count); return -1; } - config->name = strdup(items[0]); // device node + config->name = strdup(items[DEVICE_CONFIG_NAME_NUM]); // device node errno = 0; - config->mode = strtoul(items[1], NULL, OCTONARY); + config->mode = strtoul(items[DEVICE_CONFIG_MODE_NUM], NULL, OCTONARY); if (errno != 0) { INIT_LOGE("Invalid mode in config file for device node %s. use default mode", config->name); config->mode = DEVMODE; } - config->uid = StringToInt(items[2], 0); - config->gid = StringToInt(items[3], 0); + config->uid = (uid_t)StringToInt(items[DEVICE_CONFIG_UID_NUM], 0); + config->gid = (gid_t)StringToInt(items[DEVICE_CONFIG_GID_NUM], 0); ListAddTail(&g_devices, &config->list); FreeConfigItems(items, count); return 0; @@ -162,7 +177,7 @@ static int ParseSysfsConfig(char *p) char **items = NULL; int count = -1; // format: - int expectedCount = 5; + const int expectedCount = 5; if (INVALIDSTRING(p)) { INIT_LOGE("Invalid argument"); @@ -179,16 +194,16 @@ static int ParseSysfsConfig(char *p) FreeConfigItems(items, count); return -1; } - config->sysPath = strdup(items[0]); // sys path - config->attr = strdup(items[1]); // attribute + config->sysPath = strdup(items[SYS_CONFIG_PATH_NUM]); // sys path + config->attr = strdup(items[SYS_CONFIG_ATTR_NUM]); // attribute errno = 0; - config->mode = strtoul(items[2], NULL, OCTONARY); + config->mode = strtoul(items[SYS_CONFIG_MODE_NUM], NULL, OCTONARY); if (errno != 0) { INIT_LOGE("Invalid mode in config file for sys path %s. use default mode", config->sysPath); config->mode = DEVMODE; } - config->uid = StringToInt(items[3], 0); - config->gid = StringToInt(items[4], 0); + config->uid = (uid_t)StringToInt(items[SYS_CONFIG_UID_NUM], 0); + config->gid = (gid_t)StringToInt(items[SYS_CONFIG_GID_NUM], 0); ListAddTail(&g_sysDevices, &config->list); return 0; } @@ -222,7 +237,7 @@ static int ParseFirmwareConfig(char *p) return 0; } -static SECTION GetSection(char *section) +static SECTION GetSection(const char *section) { if (INVALIDSTRING(section)) { return SECTION_INVALID; @@ -276,11 +291,14 @@ int ParseUeventConfig(char *buffer) return callback != NULL ? callback(p) : -1; } -static void DoUeventConfigParse(char *buffer) +static void DoUeventConfigParse(char *buffer, size_t length) { + if (length < 0) { + return; + } char **items = NULL; int count = -1; - int maxItemCount = DEFAULTITEMCOUNT; + const int maxItemCount = DEFAULTITEMCOUNT; items = SplitUeventConfig(buffer, "\n", &count, maxItemCount); INIT_LOGD("Dump items count = %d", count); @@ -309,8 +327,12 @@ void ParseUeventdConfigFile(const char *file) if (INVALIDSTRING(file)) { return; } - - int fd = open(file, O_RDONLY | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + char *config = realpath(file, NULL); + if (config == NULL) { + return; + } + int fd = open(config, O_RDONLY | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + free(config); if (fd < 0) { INIT_LOGE("Read from %s failed", file); return; @@ -320,6 +342,7 @@ void ParseUeventdConfigFile(const char *file) if (fstat(fd, &st) < 0) { INIT_LOGE("Failed to get file stat. err = %d", errno); close(fd); + fd = -1; return; } @@ -337,14 +360,16 @@ void ParseUeventdConfigFile(const char *file) free(buffer); buffer = NULL; close(fd); + fd = -1; return; } buffer[size] = '\0'; - DoUeventConfigParse(buffer); + DoUeventConfigParse(buffer, size); free(buffer); buffer = NULL; close(fd); + fd = -1; } void GetDeviceNodePermissions(const char *devNode, uid_t *uid, gid_t *gid, mode_t *mode) @@ -361,11 +386,11 @@ void GetDeviceNodePermissions(const char *devNode, uid_t *uid, gid_t *gid, mode_ *uid = config->uid; *gid = config->gid; *mode = config->mode; - break; + break; } } } - return; + return; } void ChangeSysAttributePermissions(const char *sysPath) @@ -380,7 +405,7 @@ void ChangeSysAttributePermissions(const char *sysPath) ForEachListEntry(&g_sysDevices, node) { config = ListEntry(node, struct SysUdevConf, list); if (STRINGEQUAL(config->sysPath, sysPath)) { - break; + break; } } } diff --git a/ueventd/ueventd_socket.c b/ueventd/ueventd_socket.c index 2243aa7f37e8b48fe647ab2b06f46f6b1bacd7c1..c34c439dcf8cb5957ec86b6515be4655fe2c773e 100755 --- a/ueventd/ueventd_socket.c +++ b/ueventd/ueventd_socket.c @@ -30,11 +30,12 @@ #define INIT_LOG_TAG "ueventd" #include "init_log.h" -int UeventdSocketInit() +#define UEVENT_SOCKET_BUFF_SIZE (256 * 1024) + +int UeventdSocketInit(void) { struct sockaddr_nl addr; - int sockfd; - int buffSize = 256 * 1024; + int buffSize = UEVENT_SOCKET_BUFF_SIZE; int on = 1; if (memset_s(&addr, sizeof(addr), 0, sizeof(addr) != EOK)) { @@ -45,8 +46,7 @@ int UeventdSocketInit() addr.nl_pid = getpid(); addr.nl_groups = 0xffffffff; - sockfd = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT); - + int sockfd = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT); if (sockfd < 0) { INIT_LOGE("Create socket failed, err = %d", errno); return -1; @@ -55,7 +55,7 @@ int UeventdSocketInit() setsockopt(sockfd, SOL_SOCKET, SO_RCVBUFFORCE, &buffSize, sizeof(buffSize)); setsockopt(sockfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); - if(bind(sockfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { INIT_LOGE("Bind socket failed, err = %d", errno); close(sockfd); return -1; @@ -70,7 +70,6 @@ ssize_t ReadUeventMessage(int sockFd, char *buffer, size_t length) struct iovec iov; struct sockaddr_nl addr; char credMsg[CMSG_SPACE(sizeof(struct ucred))]; - struct cmsghdr *cmsghdr; // sanity check if (sockFd < 0 || buffer == NULL) { @@ -90,7 +89,7 @@ ssize_t ReadUeventMessage(int sockFd, char *buffer, size_t length) if (n <= 0) { return n; } - cmsghdr = CMSG_FIRSTHDR(&msghdr); + struct cmsghdr *cmsghdr = CMSG_FIRSTHDR(&msghdr); if (cmsghdr == NULL || cmsghdr->cmsg_type != SCM_CREDENTIALS) { INIT_LOGE("Unexpected control message, ignored"); // Drop this message diff --git a/ueventd/ueventd_socket.h b/ueventd/ueventd_socket.h index 922a94ce18f25a6f34f5c58afa541ef31caa6452..13e9ea28bb5c5e9f6b34353ab44734916b119cd2 100755 --- a/ueventd/ueventd_socket.h +++ b/ueventd/ueventd_socket.h @@ -16,6 +16,6 @@ #ifndef BASE_STARTUP_INITLITE_UEVENTD_SOCKET_H #define BASE_STARTUP_INITLITE_UEVENTD_SOCKET_H #include -int UeventdSocketInit(); +int UeventdSocketInit(void); ssize_t ReadUeventMessage(int sockFd, char *buffer, size_t length); #endif // BASE_STARTUP_INITLITE_LIST_H diff --git a/ueventd/ueventd_utils.c b/ueventd/ueventd_utils.c index 22b03da4b15ec64f066f654345867684aee66754..590eae61e304e1640affc61845e23c3cf0e78dba 100755 --- a/ueventd/ueventd_utils.c +++ b/ueventd/ueventd_utils.c @@ -77,6 +77,6 @@ int StringToInt(const char *str, int defaultValue) return defaultValue; } errno = 0; - int value = strtoul(str, NULL, DECIMALISM); + int value = (int)strtoul(str, NULL, DECIMALISM); return errno != 0 ? defaultValue : value; }