diff --git a/OAT.xml b/OAT.xml index 32f3b55..5f8a157 100644 --- a/OAT.xml +++ b/OAT.xml @@ -62,7 +62,8 @@ - + + diff --git a/interfaces/innerkits/dynamic_service/dynamic_service.c b/interfaces/innerkits/dynamic_service/dynamic_service.c index ada23dc..db4a8c0 100755 --- a/interfaces/innerkits/dynamic_service/dynamic_service.c +++ b/interfaces/innerkits/dynamic_service/dynamic_service.c @@ -31,7 +31,7 @@ int32_t StartDynamicProcess(const char *name) return -1; } if (SetParameter("ohos.ctl.start", name) != 0) { - HILOG_ERROR(LOG_CORE, "Set param for {public}%s failed.\n", name); + HILOG_ERROR(LOG_CORE, "Set param for %{public}s failed.\n", name); return -1; } return 0; @@ -44,7 +44,7 @@ int32_t StopDynamicProcess(const char *name) return -1; } if (SetParameter("ohos.ctl.stop", name) != 0) { - HILOG_ERROR(LOG_CORE, "Set param for {public}%s failed.\n", name); + HILOG_ERROR(LOG_CORE, "Set param for %{public}s failed.\n", name); return -1; } return 0; diff --git a/interfaces/innerkits/fs_manager/BUILD.gn b/interfaces/innerkits/fs_manager/BUILD.gn new file mode 100755 index 0000000..add5f51 --- /dev/null +++ b/interfaces/innerkits/fs_manager/BUILD.gn @@ -0,0 +1,50 @@ +# 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") + +fs_manager_sources = [ + "fstab.c", + "fstab_mount.c", +] + +fs_manager_include_dirs = [ + "//base/startup/init_lite/interfaces/innerkits/include", + "//third_party/bounds_checking_function/include", + "//base/startup/init_lite/services/log", + "//base/startup/init_lite/services/include", +] + +fs_manager_deps = [ + "//base/startup/init_lite/services/log:init_log", + "//base/startup/init_lite/services/utils:libinit_utils", + "//third_party/bounds_checking_function:libsec_static", +] + +ohos_shared_library("libfsmanager_shared") { + sources = fs_manager_sources + deps = fs_manager_deps + include_dirs = fs_manager_include_dirs + part_name = "init" + install_images = [ + "system", + ] +} + +ohos_static_library("libfsmanager_static") { + sources = fs_manager_sources + deps = fs_manager_deps + include_dirs = fs_manager_include_dirs + part_name = "init" +} + diff --git a/interfaces/innerkits/fs_manager/fstab.c b/interfaces/innerkits/fs_manager/fstab.c new file mode 100755 index 0000000..37a52fc --- /dev/null +++ b/interfaces/innerkits/fs_manager/fstab.c @@ -0,0 +1,391 @@ +/* + * 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. + */ + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fs_manager/fs_manager.h" +#include "init_utils.h" +#include "securec.h" + +struct FsManagerFlags { + char *name; + unsigned int flags; +}; + +struct MountFlags { + char *name; + unsigned long flags; +}; + +unsigned int ConvertFlags(char *flagBuffer) +{ + static struct FsManagerFlags fsFlags[] = { + {"check", FS_MANAGER_CHECK}, + {"wait", FS_MANAGER_WAIT}, + {"required", FS_MANAGER_REQUIRED}, + }; + + if (flagBuffer == NULL || *flagBuffer == '\0') { + // No valid flags. + return 0; + } + printf("[fs_manager][debug], fstab flags string: %s\n", flagBuffer); + int flagCount = 0; + unsigned int flags = 0; + const int maxCount = 3; + char **vector = SplitStringExt(flagBuffer, ",", &flagCount, maxCount); + if (vector == NULL || flagCount == 0) { + return 0; + } + + for (size_t i = 0; i < ARRAY_LENGTH(fsFlags); i++) { + for (int j = 0; j < flagCount; j++) { + printf("[fs_manager][debug], flag: %s\n", vector[j]); + if (strcmp(fsFlags[i].name, vector[j]) == 0) { + flags |= fsFlags[i].flags; + } + } + } + FreeStringVector(vector, flagCount); + return flags; +} + +static void AddToFstab(Fstab *fstab, FstabItem *item) +{ + if (fstab == NULL || item == NULL) { + return; + } + if (fstab->head != NULL) { + item->next = fstab->head->next; + fstab->head->next = item; + } else { + fstab->head = item; + } +} + +void ReleaseFstabItem(FstabItem *item) +{ + if (item != NULL) { + if (item->deviceName != NULL) { + free(item->deviceName); + item->deviceName = NULL; + } + + if (item->mountPoint != NULL) { + free(item->mountPoint); + item->mountPoint = NULL; + } + + if (item->fsType != NULL) { + free(item->fsType); + item->fsType = NULL; + } + + if (item->mountOptions != NULL) { + free(item->mountOptions); + item->mountOptions = NULL; + } + free(item); + item = NULL; + } +} + +void ReleaseFstab(Fstab *fstab) +{ + if (fstab != NULL) { + FstabItem *item = fstab->head; + while (item != NULL) { + FstabItem *tmp = item->next; + ReleaseFstabItem(item); + item = tmp; + } + free(fstab); + fstab = NULL; + } +} + +static int ParseFstabPerLine(char *str, Fstab *fstab, bool procMounts) +{ + if (str == NULL || fstab == NULL) { + return -1; + } + const char *separator = " \t"; + char *rest = NULL; + FstabItem *item = NULL; + char *p = NULL; + + if ((item = (FstabItem *)calloc(1, sizeof(FstabItem))) == NULL) { + errno = ENOMEM; + printf("[fs_manager] Allocate memory for FS table item failed, err = %d\n", errno); + return -1; + } + + do { + if ((p = strtok_r(str, separator, &rest)) == NULL) { + fprintf(stderr, "Failed to parse block device.\n"); + break; + } + item->deviceName = strdup(p); + + if ((p = strtok_r(NULL, separator, &rest)) == NULL) { + fprintf(stderr, "Failed to parse mount point.\n"); + break; + } + item->mountPoint = strdup(p); + + if ((p = strtok_r(NULL, separator, &rest)) == NULL) { + fprintf(stderr, "Failed to parse fs type.\n"); + break; + } + item->fsType = strdup(p); + + if ((p = strtok_r(NULL, separator, &rest)) == NULL) { + fprintf(stderr, "Failed to parse mount options.\n"); + break; + } + item->mountOptions = strdup(p); + + if ((p = strtok_r(NULL, separator, &rest)) == NULL) { + fprintf(stderr, "Failed to parse fs manager flags.\n"); + break; + } + // @fsManagerFlags only for fstab + // Ignore it if we read from /proc/mounts + if (!procMounts) { + item->fsManagerFlags = ConvertFlags(p); + } else { + item->fsManagerFlags = 0; + } + AddToFstab(fstab, item); + return 0; + } while (0); + + free(item); + item = NULL; + return -1; +} + +Fstab *ReadFstabFromFile(const char *file, bool procMounts) +{ + char *line = NULL; + size_t allocn = 0; + ssize_t readn = 0; + Fstab *fstab = NULL; + + if (file == NULL) { + printf("[fs_manager], invalid file\n"); + return NULL; + } + + FILE *fp = fopen(file, "r"); + if (fp == NULL) { + printf("[fs_manager] Open %s failed, err = %d", file, errno); + return NULL; + } + + if ((fstab = (Fstab *)calloc(1, sizeof(Fstab))) == NULL) { + printf("[fs_manager] Allocate memory for FS table failed, err = %d\n", errno); + return NULL; + } + + // Record line number of fstab file + size_t ln = 0; + while ((readn = getline(&line, &allocn, fp)) != -1) { + char *p = NULL; + ln++; + if (line[readn - 1] == '\n') { + line[readn - 1] = '\0'; + } + p = line; + while (isspace(*p)) { + p++; + } + + if (*p == '\0' || *p == '#') { + continue; + } + + if (ParseFstabPerLine(p, fstab, procMounts) < 0) { + if (errno == ENOMEM) { + // Ran out of memory, there is no reason to continue. + break; + } + // If one line in fstab file parsed with a failure. just give a warning + // and skip it. + printf("[fs_manager][warning] Cannot parse file \" %s \" at line %u. skip it\n", file, ln); + continue; + } + } + if (line != NULL) { + free(line); + } + return fstab; +} + +FstabItem *FindFstabItemForMountPoint(Fstab fstab, const char *mp) +{ + FstabItem *item = NULL; + if (mp != NULL) { + for (item = fstab.head; item != NULL; item = item->next) { + if (strcmp(item->mountPoint, mp) == 0) { + break; + } + } + } + return item; +} + +FstabItem *FindFstabItemForPath(Fstab fstab, const char *path) +{ + FstabItem *item = NULL; + + if (path == NULL) { + return NULL; + } + + char tmp[PATH_MAX] = {0}; + char *dir = NULL; + if (strncpy_s(tmp, PATH_MAX -1, path, strlen(path)) != EOK) { + printf("[fs_manager][error], Failed to copy path\n"); + return NULL; + } + + dir = tmp; + while (true) { + item = FindFstabItemForMountPoint(fstab, dir); + if (item != NULL) { + break; + } + dir = dirname(dir); + // Reverse walk through path and met "/", just quit. + if (dir == NULL || strcmp(dir, "/") == 0) { + break; + } + } + return item; +} + +static const struct MountFlags mountFlags[] = { + { "noatime", MS_NOATIME }, + { "noexec", MS_NOEXEC }, + { "nosuid", MS_NOSUID }, + { "nodev", MS_NODEV }, + { "nodiratime", MS_NODIRATIME }, + { "ro", MS_RDONLY }, + { "rw", 0 }, + { "sync", MS_SYNCHRONOUS }, + { "remount", MS_REMOUNT }, + { "bind", MS_BIND }, + { "rec", MS_REC }, + { "unbindable", MS_UNBINDABLE }, + { "private", MS_PRIVATE }, + { "slave", MS_SLAVE }, + { "shared", MS_SHARED }, + { "defaults", 0 }, +}; + +static bool IsDefaultMountFlags(const char *str) { + bool isDefault = false; + + if (str != NULL) { + for (size_t i = 0; i < ARRAY_LENGTH(mountFlags); i++) { + if (strcmp(str, mountFlags[i].name) == 0) { + isDefault = true; + } + } + } + return isDefault; +} + +static unsigned long ParseDefaultMountFlag(const char *str) +{ + unsigned long flags = 0; + + if (str != NULL) { + for (size_t i = 0; i < ARRAY_LENGTH(mountFlags); i++) { + if (strcmp(str, mountFlags[i].name) == 0) { + flags = mountFlags[i].flags; + break; + } + } + } + return flags; +} + +unsigned long GetMountFlags(char *mountFlags, char *fsSpecificData, size_t fsSpecificDataSize) +{ + unsigned long flags = 0; + + if (mountFlags == NULL || fsSpecificData == NULL) { + return 0; + } + + int flagCount = 0; + // Why max count of mount flags is 15? + // There are lots for mount flags defined in sys/mount.h + // But we only support to parse 15 in @ParseDefaultMountFlags() function + // So set default mount flag number to 15. + // If the item configured in fstab contains flag over than 15, + // @SplitStringExt can handle it and parse them all. but the parse function will drop it. + const int maxCount = 15; + char **flagsVector = SplitStringExt(mountFlags, ",", &flagCount, maxCount); + + if (flagsVector == NULL || flagCount == 0) { + // No flags or something wrong in SplitStringExt,just return. + return 0; + } + + for (int i = 0; i < flagCount; i++) { + char *p = flagsVector[i]; + if (IsDefaultMountFlags(p)) { + flags |= ParseDefaultMountFlag(p); + } else { + if (strncat_s(fsSpecificData, fsSpecificDataSize - 1, p, strlen(p)) != EOK) { + printf("[fs_manager][warning], Failed to append mount flag \" %s \", ignore it\n", p); + continue; + } + if (i == flagCount - 1) { // last flags, do not need to append ',' + break; + } + // Combined each mount flag with ',' + if (strncat_s(fsSpecificData, fsSpecificDataSize - 1, ",", 1) != EOK) { + printf("[fs_manager][warning], Failed to append comma\n"); + break; // If cannot add ',' to the end of flags, there is not reason to continue. + } + } + } + + FreeStringVector(flagsVector, flagCount); + return flags; +} +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif \ No newline at end of file diff --git a/interfaces/innerkits/fs_manager/fstab_mount.c b/interfaces/innerkits/fs_manager/fstab_mount.c new file mode 100755 index 0000000..7761d80 --- /dev/null +++ b/interfaces/innerkits/fs_manager/fstab_mount.c @@ -0,0 +1,297 @@ +/* + * 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. + */ + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fs_manager/fs_manager.h" +#include "init_log.h" +#include "init_utils.h" +#include "securec.h" + +#define FS_MANAGER_BUFFER_SIZE 512 +bool IsSupportedFilesystem(const char *fsType) +{ + static const char *supportedFilesystem[] = {"ext4", "f2fs", NULL}; + + bool supported = false; + int index = 0; + if (fsType != NULL) { + while (supportedFilesystem[index] != NULL) { + if (strcmp(supportedFilesystem[index++], fsType) == 0) { + supported = true; + break; + } + } + } + return supported; +} + +static int ExecCommand(int argc, char **argv) +{ + if (argc == 0 || argv == NULL || argv[0] == NULL) { + return -1; + } + pid_t pid = fork(); + if (pid < 0) { + INIT_LOGE("Fork new process to format failed: %d", errno); + return -1; + } + if (pid == 0) { + execv(argv[0], argv); + exit(-1); + } + int status; + waitpid(pid, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + printf("Command %s failed with status %d", argv[0], WEXITSTATUS(status)); + } + return WEXITSTATUS(status); +} + +int DoFormat(const char *devPath, const char *fsType) +{ + if (devPath == NULL || fsType == NULL) { + return -1; + } + + if (!IsSupportedFilesystem(fsType)) { + printf("[fs_manager][error] Do not support filesystem \" %s \"\n", fsType); + return -1; + } + int ret = 0; + #define BLOCK_SIZE_BUFFER (64) + char blockSizeBuffer[BLOCK_SIZE_BUFFER] = {0}; + if (strcmp(fsType, "ext4") == 0) { + const unsigned int blockSize = 4096; + if (snprintf_s(blockSizeBuffer, BLOCK_SIZE_BUFFER, BLOCK_SIZE_BUFFER - 1, "%u", blockSize) == -1) { + printf("[fs_manager][error] Failed to build block size buffer\n"); + return -1; + } + char *formatCmds[] = { + "/bin/mke2fs", "-F", "-t", (char *)fsType, "-b", blockSizeBuffer, (char *)devPath, NULL + }; + int argc = ARRAY_LENGTH(formatCmds); + char **argv = (char **)formatCmds; + ret = ExecCommand(argc, argv); + } else if (strcmp(fsType, "f2fs") == 0) { + char *formatCmds[] = { + "/bin/make_f2fs", (char *)devPath, NULL + }; + int argc = ARRAY_LENGTH(formatCmds); + char **argv = (char **)formatCmds; + ret = ExecCommand(argc, argv); + } + #undef BLOCK_SIZE_BUFFER + return ret; +} + +MountStatus GetMountStatusForMountPoint(const char *mp) +{ + if (mp == NULL) { + return MOUNT_ERROR; + } + char buffer[FS_MANAGER_BUFFER_SIZE] = {0}; + size_t n = 0; + const int expectedItems = 6; + int count = 0; + char **mountItems = NULL; + MountStatus status = MOUNT_ERROR; + bool found = false; + + FILE *fp = fopen("/proc/mounts", "r"); + if (fp == NULL) { + return status; + } + while (fgets(buffer, sizeof(buffer) - 1, fp) != NULL) { + n = strlen(buffer); + if (buffer[n - 1] == '\n') { + buffer[n - 1] = '\0'; + } + mountItems = SplitStringExt(buffer, " ", &count, expectedItems); + if (mountItems != NULL && count == expectedItems) { + // Second item in /proc/mounts is mount point + if (strcmp(mountItems[1], mp) == 0) { + FreeStringVector(mountItems, count); + found = true; + break; + } + FreeStringVector(mountItems, count); + } + } + if (found == true) { + status = MOUNT_MOUNTED; + } else if (feof(fp) > 0) { + status = MOUNT_UMOUNTED; + } + fclose(fp); + fp = NULL; + return status; +} + +static int Mount(const char *source, const char *target, const char *fsType, + unsigned long flags, const char *data) +{ + struct stat st = {}; + int rc = -1; + + if (source == NULL || target == NULL || fsType == NULL) { + printf("[fs_manager][error] Invalid argment for mount\n"); + return -1; + } + if (stat(target, &st) != 0 && errno != ENOENT) { + printf("[fs_manager][error] Cannot get stat of \" %s \", err = %d\n", target, errno); + return -1; + } + if ((st.st_mode & S_IFMT) == S_IFLNK) { // link, delete it. + unlink(target); + } + if (mkdir(target, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0) { + if (errno != EEXIST) { + printf("[fs_manager][error] Failed to create dir \" %s \", err = %d\n", target, errno); + return -1; + } + } + errno = 0; + while ((rc = mount(source, target, fsType, flags, data) != 0)) { + if (errno == EAGAIN) { + printf("[fs_manager][warning] Mount %s to %s failed. try again", source, target); + continue; + } else { + break; + } + } + return rc; +} + +int MountOneItem(FstabItem *item) +{ + if (item == NULL) { + return -1; + } + unsigned long mountFlags; + char fsSpecificData[FS_MANAGER_BUFFER_SIZE] = {0}; + + mountFlags = GetMountFlags(item->mountOptions, fsSpecificData, sizeof(fsSpecificData)); + if (!IsSupportedFilesystem(item->fsType)) { + printf("[fs_manager][error]Unsupported file system \" %s \"", item->fsType); + return -1; + } + if (FM_MANAGER_WAIT_ENABLED(item->fsManagerFlags)) { + WaitForFile(item->deviceName, WAIT_MAX_COUNT); + } + int rc = Mount(item->deviceName, item->mountPoint, item->fsType, mountFlags, fsSpecificData); + if (rc != 0) { + INIT_LOGE("Mount %s to %s failed %d", item->deviceName, item->mountPoint, errno); + } else { + INIT_LOGI("Mount %s to %s successful", item->deviceName, item->mountPoint); + } + return rc; +} + +int CheckRequiredAndMount(FstabItem *item, bool required) +{ + int rc = -1; + if (item == NULL) { + return rc; + } + if (required) { // Mount partition during first startup. + if (FM_MANAGER_REQUIRED_ENABLED(item->fsManagerFlags)) { + rc = MountOneItem(item); + } + } else { // Mount partition during second startup. + if (!FM_MANAGER_REQUIRED_ENABLED(item->fsManagerFlags)) { + rc = MountOneItem(item); + } + } + return rc; +} + +int MountAllWithFstabFile(const char *fstabFile, bool required) +{ + if (fstabFile == NULL || *fstabFile == '\0') { + return -1; + } + Fstab *fstab = NULL; + if ((fstab = ReadFstabFromFile(fstabFile, false)) == NULL) { + printf("[fs_manager][error] Read fstab file \" %s \" failed\n", fstabFile); + return -1; + } + + FstabItem *item = NULL; + int rc = -1; + for (item = fstab->head; item != NULL; item = item->next) { + rc = CheckRequiredAndMount(item, required); + } + ReleaseFstab(fstab); + fstab = NULL; + return rc; +} + +int UmountAllWithFstabFile(const char *fstabFile) +{ + if (fstabFile == NULL || *fstabFile == '\0') { + return -1; + } + Fstab *fstab = NULL; + if ((fstab = ReadFstabFromFile(fstabFile, false)) == NULL) { + printf("[fs_manager][error] Read fstab file \" %s \" failed\n", fstabFile); + return -1;; + } + + FstabItem *item = NULL; + int rc = -1; + for (item = fstab->head; item != NULL; item = item->next) { + printf("[fs_manager][info]Umount %s\n", item->mountPoint); + MountStatus status = GetMountStatusForMountPoint(item->mountPoint); + if (status == MOUNT_ERROR) { + printf("[fs_manager][warning] Cannot get mount status of mount point \" %s \"\n", item->mountPoint); + continue; // Cannot get mount status, just ignore it and try next one. + } else if (status == MOUNT_UMOUNTED) { + printf("[fs_manager][info] Mount point \" %s \" already unmounted. device path: %s, fs type: %s\n", + item->mountPoint, item->deviceName, item->fsType); + continue; + } else { + rc = umount(item->mountPoint); + if (rc == -1) { + printf("[fs_manager][error] Umount %s failed, device path: %s, fs type: %s, err = %d", + item->mountPoint, item->deviceName, item->fsType, errno); + } else { + printf("[fs_manager][info] Umount %s successfully\n", + item->mountPoint); + } + } + } + ReleaseFstab(fstab); + fstab = NULL; + return rc; +} +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif diff --git a/interfaces/innerkits/include/fs_manager/fs_manager.h b/interfaces/innerkits/include/fs_manager/fs_manager.h new file mode 100755 index 0000000..59df574 --- /dev/null +++ b/interfaces/innerkits/include/fs_manager/fs_manager.h @@ -0,0 +1,75 @@ +/* + * 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_FS_MANAGER_H +#define STARTUP_FS_MANAGER_H + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif +#include + +/* Fs manager flags definition */ +#define FS_MANAGER_CHECK 0x00000001 +#define FS_MANAGER_WAIT 0x00000002 +#define FS_MANAGER_REQUIRED 0x00000004 + +#define VALID_FS_MANAGER_FLAGS (FS_MANAGER_CHECK | FS_MANAGER_WAIT | FS_MANAGER_REQUIRED) +#define FS_MANAGER_FLAGS_ENABLED(fsMgrFlags, flag) (((fsMgrFlags) & FS_MANAGER_##flag) != 0) + +#define FM_MANAGER_CHECK_ENABLED(fsMgrFlags) FS_MANAGER_FLAGS_ENABLED((fsMgrFlags), CHECK) +#define FM_MANAGER_WAIT_ENABLED(fsMgrFlags) FS_MANAGER_FLAGS_ENABLED((fsMgrFlags), WAIT) +#define FM_MANAGER_REQUIRED_ENABLED(fsMgrFlags) FS_MANAGER_FLAGS_ENABLED((fsMgrFlags), REQUIRED) + +typedef enum MountStatus { + MOUNT_ERROR = -1, + MOUNT_UMOUNTED = 0, + MOUNT_MOUNTED = 1, +} MountStatus; + +typedef struct FstabItem { + char *deviceName; // Block device name + char *mountPoint; // Mount point + char *fsType; // File system type + char * mountOptions; // File system mount options. readonly, rw, remount etc. + unsigned int fsManagerFlags; // flags defined by fs manager. + struct FstabItem *next; +} FstabItem; + +typedef struct { + struct FstabItem *head; +} Fstab; + +void ReleaseFstab(Fstab *fstab); +Fstab *ReadFstabFromFile(const char *file, bool procMounts); +FstabItem *FindFstabItemForPath(Fstab fstab, const char *path); +FstabItem* FindFstabItemForMountPoint(Fstab fstab, const char *mp); + +bool IsSupportedFilesystem(const char *fsType); +int DoFormat(const char *devPath, const char *fsType); +int MountOneItem(FstabItem *item); +MountStatus GetMountStatusForMountPoint(const char *mp); +int MountAllWithFstabFile(const char *file, bool required); +int UmountAllWithFstabFile(const char *file); +unsigned long GetMountFlags(char *mountFlags, char *fsSpecificFlags, size_t fsSpecificFlagSize); +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif + +#endif // STARTUP_FS_MANAGER_H \ No newline at end of file diff --git a/interfaces/innerkits/reboot/BUILD.gn b/interfaces/innerkits/reboot/BUILD.gn old mode 100644 new mode 100755 diff --git a/interfaces/innerkits/reboot/init_reboot.c b/interfaces/innerkits/reboot/init_reboot.c old mode 100644 new mode 100755 index bbbab36..6e6df19 --- a/interfaces/innerkits/reboot/init_reboot.c +++ b/interfaces/innerkits/reboot/init_reboot.c @@ -17,6 +17,7 @@ #include #include #include + #include "init_log.h" #include "param.h" #include "securec.h" @@ -45,7 +46,7 @@ int DoReboot(const char *option) } return 0; } - size_t length = strlen(option); + int length = strlen(option); if (length > MAX_REBOOT_OPTION_SIZE) { INIT_LOGE("Reboot option \" %s \" is too large, overflow", option); return -1; diff --git a/interfaces/innerkits/socket/BUILD.gn b/interfaces/innerkits/socket/BUILD.gn old mode 100644 new mode 100755 diff --git a/interfaces/innerkits/socket/init_socket.c b/interfaces/innerkits/socket/init_socket.c index f71e120..ce28193 100755 --- a/interfaces/innerkits/socket/init_socket.c +++ b/interfaces/innerkits/socket/init_socket.c @@ -14,7 +14,6 @@ */ #include "init_socket.h" - #include #include #include diff --git a/interfaces/kits/init_sync.h b/interfaces/kits/init_sync.h old mode 100644 new mode 100755 diff --git a/ohos.build b/ohos.build index a8ef47b..84b89d8 100644 --- a/ohos.build +++ b/ohos.build @@ -5,7 +5,11 @@ "module_list": [ "//base/startup/init_lite/services:startup_init", "//base/startup/init_lite/ueventd:ueventd", - "//base/startup/init_lite/ueventd:ueventd.config" + "//base/startup/init_lite/ueventd:ueventd.config", + "//base/startup/init_lite/watchdog:watchdog" + ], + "test_list": [ + "//base/startup/init_lite/services/test/unittest:init_test" ] } } diff --git a/services/BUILD.gn b/services/BUILD.gn old mode 100644 new mode 100755 index 2e3317e..4dc1be4 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -10,6 +10,20 @@ # 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. + +init_common_sources = [ + "init/init_capability.c", + "init/init_common_cmds.c", + "init/init_config.c", + "init/init_common_service.c", + "init/init_service_manager.c", + "init/init_service_socket.c", + "init/main.c", + "log/init_log.c", + "utils/init_utils.c", + "utils/list.c", +] + if (defined(ohos_lite)) { # feature: init executable("init_lite") { @@ -19,27 +33,21 @@ if (defined(ohos_lite)) { "OHOS_LITE", ] sources = [ - "log/init_log.c", - "src/init_adapter.c", - "src/init_capability.c", - "src/init_cmds.c", - "src/init_import.c", - "src/init_jobs.c", - "src/init_read_cfg.c", - "src/init_reboot.c", - "src/init_service.c", - "src/init_service_manager.c", - "src/init_service_socket.c", - "src/init_signal_handler.c", - "src/main.c", - "utils/init_utils.c", + "init/adapter/init_adapter.c", + "init/lite/init.c", + "init/lite/init_cmds.c", + "init/lite/init_jobs.c", + "init/lite/init_reboot.c", + "init/lite/init_service.c", + "init/lite/init_signal_handler.c", ] + sources += init_common_sources + include_dirs = [ "//base/startup/init_lite/services/include", - "//base/startup/init_lite/services/param/include", + "//base/startup/init_lite/services/init/include", "//base/startup/init_lite/services/log", - "//base/startup/init_lite/services/utils", "//third_party/cJSON", "//third_party/bounds_checking_function/include", "//base/startup/syspara_lite/interfaces/kits", @@ -88,33 +96,34 @@ if (defined(ohos_lite)) { ohos_executable("init") { sources = [ - "src/device.c", - "src/init_adapter.c", - "src/init_capability.c", - "src/init_cmds.c", - "src/init_import.c", - "src/init_jobs.c", - "src/init_read_cfg.c", - "src/init_reboot.c", - "src/init_service.c", - "src/init_service_manager.c", - "src/init_service_socket.c", - "src/init_signal_handler.c", - "src/main.c", + "init/adapter/init_adapter.c", + "init/standard/device.c", + "init/standard/init.c", + "init/standard/init_cmds.c", + "init/standard/init_jobs.c", + "init/standard/init_reboot.c", + "init/standard/init_service.c", + "init/standard/init_signal_handler.c", + "init/standard/switch_root.c", + "init/standard/init_mount.c", ] + + sources += init_common_sources + include_dirs = [ "//base/startup/init_lite/services/include/param", "//base/startup/init_lite/services/include", + "//base/startup/init_lite/services/init/include", "//base/startup/init_lite/services/log", - "//base/startup/init_lite/services/utils", + "//base/startup/init_lite/interfaces/innerkits/include", "//third_party/cJSON", "//third_party/bounds_checking_function/include", "//third_party/libuv/include", ] deps = [ + "//base/startup/init_lite/interfaces/innerkits/fs_manager:libfsmanager_static", "//base/startup/init_lite/services/log:init_log", "//base/startup/init_lite/services/param:param_service", - "//base/startup/init_lite/services/utils:libinit_utils", "//third_party/bounds_checking_function:libsec_static", "//third_party/cJSON:cjson_static", ] @@ -138,6 +147,7 @@ if (defined(ohos_lite)) { ":init_etc", "//base/startup/init_lite/interfaces/innerkits/dynamic_service:dynamic_service", "//base/startup/init_lite/interfaces/innerkits/socket:libsocket", + "//base/startup/init_lite/interfaces/innerkits/fs_manager:libfsmanager_shared", "//base/startup/init_lite/services/cmds/reboot:reboot", "//base/startup/init_lite/services/cmds/service_control:service_control", "//base/startup/init_lite/services/param:param", diff --git a/services/cmds/reboot/init_cmd_reboot.c b/services/cmds/reboot/init_cmd_reboot.c old mode 100644 new mode 100755 index 39b4069..528a9d3 --- a/services/cmds/reboot/init_cmd_reboot.c +++ b/services/cmds/reboot/init_cmd_reboot.c @@ -32,9 +32,7 @@ int main(int argc, char* argv[]) printf("%s", USAGE_INFO); return 0; } - if (argv[1] == NULL) { - return -1; - } + if (argc == REBOOT_CMD_NUMBER && strcmp(argv[1], "shutdown") != 0 && strcmp(argv[1], "updater") != 0 && strcmp(argv[1], "flash") != 0 && @@ -43,7 +41,7 @@ int main(int argc, char* argv[]) printf("%s", USAGE_INFO); return 0; } - int ret; + int ret = 0; if (argc == REBOOT_CMD_NUMBER) { ret = DoReboot(argv[1]); } else { diff --git a/services/cmds/service_control/service_control.c b/services/cmds/service_control/service_control.c index c000c28..320e155 100755 --- a/services/cmds/service_control/service_control.c +++ b/services/cmds/service_control/service_control.c @@ -67,9 +67,7 @@ int main(int argc, char** argv) ServiceControlUsage(); return -1; } - if (argv[0] == NULL) { - return -1; - } + char serviceCtl[SERVICE_CONTROL_MAX_SIZE]; if (strcmp(argv[0], "start_service") == 0) { if (strncpy_s(serviceCtl, sizeof(serviceCtl), "ohos.ctl.start", sizeof(serviceCtl) - 1) != EOK) { diff --git a/services/etc/init.cfg b/services/etc/init.cfg index e0e54be..5e07aac 100755 --- a/services/etc/init.cfg +++ b/services/etc/init.cfg @@ -3,8 +3,7 @@ "/etc/init.usb.cfg", "/etc/init.usb.configfs.cfg", "/etc/init.usb.cfg", - "/etc/init.Hi3516DV300.usb.cfg", - "/etc/init.Hi3516DV300.cfg" + "/vendor/etc/init.${ohos.boot.hardware}.cfg" ], "jobs" : [{ "name" : "pre-init", @@ -16,10 +15,9 @@ "mkdir /dev/memcg/apps/ 0755 system system", "mkdir /dev/memcg/system 0550 system system", "start ueventd", - "mkdir /vendor", + "start watchdog_service", "mkdir /data", - "mount ext4 /dev/block/platform/soc/10100000.himci.eMMC/by-name/vendor /vendor wait rdonly barrier=1", - "mount ext4 /dev/block/platform/soc/10100000.himci.eMMC/by-name/userdata /data wait nosuid nodev noatime barrier=1,data=ordered,noauto_da_alloc" + "mount_fstab /vendor/etc/fstab.${ohos.boot.hardware}" ] }, { "name" : "init", @@ -386,8 +384,8 @@ "write /proc/sys/kernel/perf_event_paranoid 3" ] }, { - "name" : "boot && param:ro.debuggable=1", - "condition" : "boot && ro.debuggable=1", + "name" : "boot && param:const.debuggable=1", + "condition" : "boot && const.debuggable=1", "cmds" : [ "chmod 0773 /data/misc/trace", "chmod 0775 /data/misc/wmtrace", @@ -406,6 +404,13 @@ "console" : 1, "uid" : "root", "gid" : ["shell", "log", "readproc"] + }, { + "name" : "watchdog_service", + "path" : ["/system/bin/watchdog_service", "10", "2"], + "disabled" : 1, + "uid" : "root", + "gid" : ["shell", "log", "readproc"] } + ] } diff --git a/services/etc/init.usb.cfg b/services/etc/init.usb.cfg index dd282c0..10cf95f 100755 --- a/services/etc/init.usb.cfg +++ b/services/etc/init.usb.cfg @@ -1,4 +1,7 @@ { + "import" : [ + "/vendor/etc/init.${ohos.boot.hardware}.usb.cfg" + ], "jobs" : [{ "name" : "boot", "cmds" : [ diff --git a/services/etc/param/ohos.para b/services/etc/param/ohos.para index f53e55a..8c910ab 100755 --- a/services/etc/param/ohos.para +++ b/services/etc/param/ohos.para @@ -27,13 +27,13 @@ hw_sc.build.os.version=2.2.0 # ohos release type hw_sc.build.os.releasetype=Canary1 -ro.actionable_compatible_property.enabled=false -ro.postinstall.fstab.prefix=/system -ro.secure=1 +const.actionable_compatible_property.enabled=false +const.postinstall.fstab.prefix=/system +const.secure=1 security.perf_harden=1 -ro.allow.mock.location=0 -ro.debuggable=1 -ro.build.characteristics="default" -ro.product.model="ohos" -ro.product.name="OpenHarmony 2.0 Canary" +const.allow.mock.location=0 +const.debuggable=1 +const.build.characteristics="default" +const.product.model="ohos" +const.product.name="OpenHarmony 2.0 Canary" persist.sys.usb.config=hdc diff --git a/services/include/init_cmds.h b/services/include/init_cmds.h deleted file mode 100644 index 343ec32..0000000 --- a/services/include/init_cmds.h +++ /dev/null @@ -1,70 +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. - */ - -#ifndef BASE_STARTUP_INITLITE_CMDS_H -#define BASE_STARTUP_INITLITE_CMDS_H - -#ifdef __cplusplus -#if __cplusplus -extern "C" { -#endif -#endif - -#define MAX_CMD_NAME_LEN 32 -#define MAX_CMD_CONTENT_LEN 256 -#define MAX_CMD_CNT_IN_ONE_JOB 200 -#define MAX_COPY_BUF_SIZE 256 -#define DEFAULT_COPY_ARGS_CNT 2 - -#ifndef OHOS_LITE -// Limit max length of parameter value to 96 -#define MAX_PARAM_VALUE_LEN 96 -// Limit max length of parameter name to 96 -#define MAX_PARAM_NAME_LEN 96 -#else -// For lite ohos, do not support parameter operation -#define MAX_PARAM_VALUE_LEN 0 -#define MAX_PARAM_NAME_LEN 0 -#endif - -// one cmd line -typedef struct { - char name[MAX_CMD_NAME_LEN + 1]; - char cmdContent[MAX_CMD_CONTENT_LEN + 1]; -} CmdLine; - -struct CmdArgs { - int argc; - char **argv; -}; - -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 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, unsigned int *index); -const char *GetCmdKey(unsigned int index); - -#ifdef __cplusplus -#if __cplusplus -} -#endif -#endif - -#endif // BASE_STARTUP_INITLITE_CMDS_H diff --git a/services/include/init_service.h b/services/include/init_service.h deleted file mode 100644 index dc887a1..0000000 --- a/services/include/init_service.h +++ /dev/null @@ -1,89 +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. - */ - -#ifndef BASE_STARTUP_INITLITE_SERVICE_H -#define BASE_STARTUP_INITLITE_SERVICE_H - -#include -#include "init_cmds.h" -#include "init_service_socket.h" - -#ifdef __cplusplus -#if __cplusplus -extern "C" { -#endif -#endif - -// return value -#define SERVICE_FAILURE (-1) -#define SERVICE_SUCCESS 0 - -// service attributes -#define SERVICE_ATTR_INVALID 0x001 // option invalid -#define SERVICE_ATTR_ONCE 0x002 // do not restart when it exits -#define SERVICE_ATTR_NEED_RESTART 0x004 // will restart in the near future -#define SERVICE_ATTR_NEED_STOP 0x008 // will stop in reap -#define SERVICE_ATTR_IMPORTANT 0x010 // will reboot if it crash -#define SERVICE_ATTR_CRITICAL 0x020 // critical, will reboot if it crash 4 times in 4 minutes -#define SERVICE_ATTR_DISABLED 0x040 // disabled -#define SERVICE_ATTR_CONSOLE 0x080 // console -#define SERVICE_ATTR_DYNAMIC 0x100 // dynamic service - -#define MAX_SERVICE_NAME 32 -#define MAX_WRITEPID_FILES 100 - -#define CAP_NUM 2 - -#define SERVICES_ARR_NAME_IN_JSON "services" - -typedef struct { - uid_t uID; - gid_t *gIDArray; - int gIDCnt; - unsigned int *caps; - unsigned int capsCnt; -} Perms; - -struct OnRestartCmd { - CmdLine *cmdLine; - int cmdNum; -}; - -typedef struct { - char name[MAX_SERVICE_NAME + 1]; - char** pathArgs; - int pathArgsCnt; - int pid; - int crashCnt; - time_t firstCrashTime; - char *writepidFiles[MAX_WRITEPID_FILES]; - unsigned int attribute; - int importance; - Perms servPerm; - struct OnRestartCmd *onRestart; - struct ServiceSocket *socketCfg; -} Service; - -int ServiceStart(Service *service); -int ServiceStop(Service *service); -void ServiceReap(Service *service); - -#ifdef __cplusplus -#if __cplusplus -} -#endif -#endif - -#endif // BASE_STARTUP_INITLITE_SERVICE_H diff --git a/services/utils/init_utils.h b/services/include/init_utils.h similarity index 72% rename from services/utils/init_utils.h rename to services/include/init_utils.h index d7d39f2..52d460a 100755 --- a/services/utils/init_utils.h +++ b/services/include/init_utils.h @@ -28,18 +28,23 @@ extern "C" { #define BINARY_BASE 2 #define OCTAL_BASE 8 #define DECIMAL_BASE 10 +#define WAIT_MAX_COUNT 10 #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); +int SplitString(char *srcPtr, const char *del, char **dstPtr, int maxNum); void WaitForFile(const char *source, unsigned int maxCount); size_t WriteAll(int fd, const char *buffer, size_t size); -char *Realpath(const char *source, char *resolvedPath, size_t resolvedPathSize); +char *GetRealPath(const char *source); int StringToInt(const char *str, int defaultValue); int MakeDirRecursive(const char *dir, mode_t mode); int MakeDir(const char *dir, mode_t mode); - +int ReadFileInDir(const char *dirPath, const char *includeExt, + int (*processFile)(const char *fileName, void *context), void *context); +char **SplitStringExt(char *buffer, const char *del, int *returnCount, int maxItemCount); +void FreeStringVector(char **vector, int count); +int InUpdaterMode(void); #ifdef __cplusplus #if __cplusplus } diff --git a/services/include/param/init_param.h b/services/include/param/init_param.h old mode 100644 new mode 100755 index 3ef4dab..5d9eb45 --- a/services/include/param/init_param.h +++ b/services/include/param/init_param.h @@ -97,10 +97,10 @@ void DoTriggerExec(const char *triggerName); /** * 对Init接口 - * 按名字执行对应的trigger。 + * dump 参数和trigger信息 * */ -int SystemTraversalParam(void (*traversalParameter)(ParamHandle handle, void* cookie), void* cookie); +void DumpParametersAndTriggers(void); #ifdef __cplusplus #if __cplusplus diff --git a/services/include/param/sys_param.h b/services/include/param/sys_param.h old mode 100644 new mode 100755 diff --git a/services/include/init_capability.h b/services/include/switch_root.h old mode 100644 new mode 100755 similarity index 78% rename from services/include/init_capability.h rename to services/include/switch_root.h index 842959e..833edbb --- a/services/include/init_capability.h +++ b/services/include/switch_root.h @@ -13,13 +13,7 @@ * limitations under the License. */ -#ifndef INIT_CAPABILITY_H -#define INIT_CAPABILITY_H - -#include "cJSON.h" -#include "init_service.h" - -int GetServiceCaps(const cJSON* curArrItem, Service* curServ); - -#endif - + #ifndef INIT_SWITCH_ROOT_H + #define INIT_SWITCH_ROOT_H + int SwitchRoot(const char *newRoot); + #endif // INIT_SWITCH_ROOT_H \ No newline at end of file diff --git a/services/src/init_adapter.c b/services/init/adapter/init_adapter.c old mode 100644 new mode 100755 similarity index 72% rename from services/src/init_adapter.c rename to services/init/adapter/init_adapter.c index 2788e64..0cd8eb7 --- a/services/src/init_adapter.c +++ b/services/init/adapter/init_adapter.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Huawei Device Co., Ltd. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,23 +12,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #include "init_adapter.h" #include +#include #include -#include #include #include +#include +#if defined OHOS_LITE && !defined __LINUX__ +#include +#else +#include +#endif + #if ((defined __LINUX__) || (!defined OHOS_LITE)) #include #endif -#ifdef __LINUX__ -#include "init_signal_handler.h" -#endif #include "init_log.h" -void RebootSystem() +void RebootSystem(void) { int ret = reboot(RB_AUTOBOOT); if (ret != 0) { @@ -36,7 +39,7 @@ void RebootSystem() } } -int KeepCapability() +int KeepCapability(void) { #if ((defined __LINUX__) || (!defined OHOS_LITE)) if (prctl(PR_SET_SECUREBITS, SECBIT_NO_SETUID_FIXUP | SECBIT_NO_SETUID_FIXUP_LOCKED)) { @@ -58,7 +61,33 @@ int SetAmbientCapability(int cap) return 0; } -void ExecuteRcs() +#ifdef __LINUX__ +static pid_t g_waitPid = -1; +static sem_t *g_waitSem = NULL; +static void SignalRegWaitSem(pid_t waitPid, sem_t *waitSem) +{ + g_waitPid = waitPid; + g_waitSem = waitSem; +} + +void CheckWaitPid(pid_t sigPID) +{ + if (g_waitPid == sigPID && g_waitSem != NULL) { + if (sem_post(g_waitSem) != 0) { + INIT_LOGE("CheckWaitPid, sem_post failed, errno %d.", errno); + } + g_waitPid = -1; + g_waitSem = NULL; + } +} +#else +void CheckWaitPid(pid_t sigPID) +{ + (void)(sigPID); +} +#endif + +void SystemExecuteRcs(void) { #if (defined __LINUX__) && (defined NEED_EXEC_RCS_LINUX) pid_t retPid = fork(); @@ -90,4 +119,3 @@ void ExecuteRcs() } #endif } - diff --git a/services/include/device.h b/services/init/include/device.h old mode 100644 new mode 100755 similarity index 95% rename from services/include/device.h rename to services/init/include/device.h index c68d456..043b2f1 --- a/services/include/device.h +++ b/services/init/include/device.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Huawei Device Co., Ltd. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,10 +12,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #ifndef BASE_STARTUP_INITLITE_DEVICE_H #define BASE_STARTUP_INITLITE_DEVICE_H - #include #ifdef __cplusplus diff --git a/services/include/init_signal_handler.h b/services/init/include/init.h old mode 100644 new mode 100755 similarity index 51% rename from services/include/init_signal_handler.h rename to services/init/include/init.h index 433d4f9..966c4d6 --- a/services/include/init_signal_handler.h +++ b/services/init/include/init.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Huawei Device Co., Ltd. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,14 +12,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -#ifndef BASE_STARTUP_INITLITE_SIGNAL_HANDLE_H -#define BASE_STARTUP_INITLITE_SIGNAL_HANDLE_H - -#ifdef __LINUX__ -#include -#include -#endif +#ifndef BASE_STARTUP_INIT_H +#define BASE_STARTUP_INIT_H #ifdef __cplusplus #if __cplusplus @@ -27,16 +21,31 @@ extern "C" { #endif #endif -void SignalInitModule(); - -#ifdef __LINUX__ -void SignalRegWaitSem(pid_t waitPid, sem_t* waitSem); +#ifndef PARAM_VALUE_LEN_MAX +#define PARAM_VALUE_LEN_MAX 96 #endif +#define PROCESS_EXIT_CODE 0x7f // 0x7f: user specified +// kit framework +#define DEFAULT_UID_KIT_FRAMEWORK 3 +// max length of one param/path +#define MAX_ONE_ARG_LEN 200 + +#define UNUSED(x) (void)(x) + +void SystemInit(void); +void LogInit(void); +void SystemPrepare(void); +void SystemConfig(void); +void SystemRun(void); +void SystemExecuteRcs(void); + +void ReadConfig(void); +void SignalInit(void); + #ifdef __cplusplus #if __cplusplus } #endif #endif - -#endif // BASE_STARTUP_INITLITE_SIGNAL_HANDLE_H +#endif // BASE_STARTUP_INIT_H diff --git a/services/include/init_adapter.h b/services/init/include/init_adapter.h old mode 100644 new mode 100755 similarity index 65% rename from services/include/init_adapter.h rename to services/init/include/init_adapter.h index ea02c1e..36f91de --- a/services/include/init_adapter.h +++ b/services/init/include/init_adapter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Huawei Device Co., Ltd. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,16 +12,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #ifndef BASE_STARTUP_INITLITE_ADAPTER_H #define BASE_STARTUP_INITLITE_ADAPTER_H - -#if defined OHOS_LITE && !defined __LINUX__ -#include -#else -#include -#endif - +#include #ifdef __cplusplus #if __cplusplus extern "C" { @@ -31,27 +24,27 @@ extern "C" { #ifndef OHOS_LITE /* Control the ambient capability set */ #ifndef PR_CAP_AMBIENT -#define PR_CAP_AMBIENT 47 +#define PR_CAP_AMBIENT 47 #endif #ifndef PR_CAP_AMBIENT_IS_SET -#define PR_CAP_AMBIENT_IS_SET 1 +#define PR_CAP_AMBIENT_IS_SET 1 #endif #ifndef PR_CAP_AMBIENT_RAISE -#define PR_CAP_AMBIENT_RAISE 2 +#define PR_CAP_AMBIENT_RAISE 2 #endif #ifndef PR_CAP_AMBIENT_LOWER -#define PR_CAP_AMBIENT_LOWER 3 +#define PR_CAP_AMBIENT_LOWER 3 #endif #ifndef PR_CAP_AMBIENT_CLEAR_ALL -#define PR_CAP_AMBIENT_CLEAR_ALL 4 +#define PR_CAP_AMBIENT_CLEAR_ALL 4 #endif -extern int capset(void *a, void *b); #endif -void RebootSystem(); -int KeepCapability(); +void RebootSystem(void); +int KeepCapability(void); int SetAmbientCapability(int cap); -void ExecuteRcs(); +void ExecuteRcs(void); +void CheckWaitPid(pid_t sigPID); #ifdef __cplusplus #if __cplusplus @@ -59,4 +52,4 @@ void ExecuteRcs(); #endif #endif -#endif // BASE_STARTUP_INITLITE_ADAPTER_H \ No newline at end of file +#endif // BASE_STARTUP_INITLITE_ADAPTER_H \ No newline at end of file diff --git a/services/init/include/init_cmds.h b/services/init/include/init_cmds.h new file mode 100755 index 0000000..a616673 --- /dev/null +++ b/services/init/include/init_cmds.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef BASE_STARTUP_INIT_CMDS_H +#define BASE_STARTUP_INIT_CMDS_H +#include +#include +#include +#include +#include "cJSON.h" +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +#define DEFAULT_DIR_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH | S_IROTH) // mkdir, default mode +#define SPACES_CNT_IN_CMD_MAX 10 // mount, max number of spaces in cmdline +#define SPACES_CNT_IN_CMD_MIN 2 // mount, min number of spaces in cmdline + +#define LOADCFG_BUF_SIZE 128 // loadcfg, max buffer for one cmdline +#define LOADCFG_MAX_FILE_LEN 51200 // loadcfg, max file size is 50K +#define LOADCFG_MAX_LOOP 20 // loadcfg, to prevent to be trapped in infite loop +#define OCTAL_TYPE 8 // 8 means octal to decimal +#define MAX_BUFFER 256UL +#define AUTHORITY_MAX_SIZE 128 + +#define MAX_CMD_NAME_LEN 32 +#define MAX_CMD_CONTENT_LEN 256 +#define MAX_CMD_CNT_IN_ONE_JOB 200 +#define MAX_COPY_BUF_SIZE 256 +#define DEFAULT_COPY_ARGS_CNT 2 + +#define OPTIONS_SIZE 128 + +#define SUPPORT_MAX_ARG_FOR_EXEC 10 +// one cmd line +typedef struct { + int cmdIndex; + char cmdContent[MAX_CMD_CONTENT_LEN + 1]; +} CmdLine; + +typedef struct { + int cmdNum; + CmdLine cmds[0]; +} CmdLines; + +struct CmdArgs { + int argc; + char *argv[0]; +}; + +struct CmdTable { + char name[MAX_CMD_NAME_LEN]; + unsigned char minArg; + unsigned char maxArg; + void (*DoFuncion)(const struct CmdArgs *ctx, const char *cmdContent); +}; + +int GetParamValue(const char *symValue, unsigned int symLen, char *paramValue, unsigned int paramLen); +const struct CmdArgs *GetCmdArg(const char *cmdContent, const char *delim, int argsCount); +void FreeCmdArg(struct CmdArgs *cmd); +void DoCmdByName(const char *name, const char *cmdContent); +void DoCmdByIndex(int index, const char *cmdContent); +const char *GetMatchCmd(const char *cmdStr, int *index); +const char *GetCmdKey(int index); +const struct CmdTable *GetCmdTable(int *number); +int GetCmdLinesFromJson(const cJSON *root, CmdLines **cmdLines); +const struct CmdTable *GetCmdByName(const char *name); +void ExecReboot(const char *value); +char *BuildStringFromCmdArg(const struct CmdArgs *ctx, int startIndex); +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif + +#endif // BASE_STARTUP_INITLITE_CMDS_H diff --git a/services/include/init_jobs.h b/services/init/include/init_jobs.h old mode 100644 new mode 100755 similarity index 74% rename from services/include/init_jobs.h rename to services/init/include/init_jobs.h index 47937a7..e74cb25 --- a/services/include/init_jobs.h +++ b/services/init/include/init_jobs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Huawei Device Co., Ltd. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,12 +12,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #ifndef BASE_STARTUP_INITLITE_JOBS_H #define BASE_STARTUP_INITLITE_JOBS_H - -#include "init_cmds.h" #include "cJSON.h" +#include "init_cmds.h" #ifdef __cplusplus #if __cplusplus @@ -30,14 +28,20 @@ extern "C" { // one job, could have many cmd lines typedef struct { char name[MAX_JOB_NAME_LEN + 1]; - int cmdLinesCnt; - CmdLine* cmdLines; + CmdLines *cmdLines; } Job; -void ParseAllJobs(const cJSON* fileRoot); -void DoJob(const char* jobName); +void ParseAllJobs(const cJSON *fileRoot); +void DoJob(const char *jobName); void ReleaseAllJobs(void); void DumpAllJobs(void); + +#define INIT_CONFIGURATION_FILE "/etc/init.cfg" +#define OTHER_CFG_PATH "/system/etc/init" +#define MAX_PATH_ARGS_CNT 20 + +void ReadConfig(void); + #ifdef __cplusplus #if __cplusplus } diff --git a/services/init/include/init_service.h b/services/init/include/init_service.h new file mode 100755 index 0000000..87713e1 --- /dev/null +++ b/services/init/include/init_service.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef BASE_STARTUP_INITLITE_SERVICE_H +#define BASE_STARTUP_INITLITE_SERVICE_H +#include + +#include "cJSON.h" +#include "init_cmds.h" +#include "init_service_socket.h" +#include "list.h" +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +// return value +#define SERVICE_FAILURE (-1) +#define SERVICE_SUCCESS 0 + +// service attributes +#define SERVICE_ATTR_INVALID 0x001 // option invalid +#define SERVICE_ATTR_ONCE 0x002 // do not restart when it exits +#define SERVICE_ATTR_NEED_RESTART 0x004 // will restart in the near future +#define SERVICE_ATTR_NEED_STOP 0x008 // will stop in reap +#define SERVICE_ATTR_IMPORTANT 0x010 // will reboot if it crash +#define SERVICE_ATTR_CRITICAL 0x020 // critical, will reboot if it crash 4 times in 4 minutes +#define SERVICE_ATTR_DISABLED 0x040 // disabled +#define SERVICE_ATTR_CONSOLE 0x080 // console +#define SERVICE_ATTR_DYNAMIC 0x100 // dynamic service + +#define MAX_SERVICE_NAME 32 +#define MAX_WRITEPID_FILES 100 + +#define FULL_CAP 0xFFFFFFFF +// init +#define DEFAULT_UMASK_INIT 022 + +#define CAP_NUM 2 + +#define SERVICES_ARR_NAME_IN_JSON "services" + +typedef struct { + uid_t uID; + gid_t *gIDArray; + int gIDCnt; + unsigned int *caps; + unsigned int capsCnt; +} Perms; + +typedef struct { + int count; + char **argv; +} ServiceArgs; + +typedef struct { + ListNode node; + char name[MAX_SERVICE_NAME + 1]; + int pid; + int crashCnt; + time_t firstCrashTime; + unsigned int attribute; + int importance; + Perms servPerm; + ServiceArgs pathArgs; + ServiceArgs writePidArgs; + CmdLines *restartArg; + ServiceSocket *socketCfg; +} Service; + +int ServiceStart(Service *service); +int ServiceStop(Service *service); +void ServiceReap(Service *service); +void ReapService(Service *service); + +void NotifyServiceChange(const char *serviceName, const char *change); +int IsForbidden(const char *fieldStr); +int SetImportantValue(Service *curServ, const char *attrName, int value, int flag); +int GetServiceCaps(const cJSON *curArrItem, Service *curServ); +int ServiceExec(const Service *service); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif + +#endif // BASE_STARTUP_INITLITE_SERVICE_H diff --git a/services/include/init_service_manager.h b/services/init/include/init_service_manager.h old mode 100644 new mode 100755 similarity index 57% rename from services/include/init_service_manager.h rename to services/init/include/init_service_manager.h index 1208307..45c91d8 --- a/services/include/init_service_manager.h +++ b/services/init/include/init_service_manager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Huawei Device Co., Ltd. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,12 +12,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #ifndef BASE_STARTUP_INITLITE_SERVICEMANAGER_H #define BASE_STARTUP_INITLITE_SERVICEMANAGER_H #include "init_service.h" #include "cJSON.h" +#include "list.h" #ifdef __cplusplus #if __cplusplus @@ -25,26 +25,37 @@ extern "C" { #endif #endif -#define UID_STR_IN_CFG "uid" -#define GID_STR_IN_CFG "gid" -#define ONCE_STR_IN_CFG "once" -#define IMPORTANT_STR_IN_CFG "importance" -#define BIN_SH_NOT_ALLOWED "/bin/sh" -#define CRITICAL_STR_IN_CFG "critical" -#define DISABLED_STR_IN_CFG "disabled" -#define CONSOLE_STR_IN_CFG "console" +#define UID_STR_IN_CFG "uid" +#define GID_STR_IN_CFG "gid" +#define ONCE_STR_IN_CFG "once" +#define IMPORTANT_STR_IN_CFG "importance" +#define BIN_SH_NOT_ALLOWED "/bin/sh" +#define CRITICAL_STR_IN_CFG "critical" +#define DISABLED_STR_IN_CFG "disabled" +#define CONSOLE_STR_IN_CFG "console" #define MAX_SERVICES_CNT_IN_FILE 100 -void RegisterServices(Service *services, int servicesCnt); +typedef struct { + char *capStr; + unsigned int CapNum; +} CapStrCapNum; + +typedef struct { + ListNode services; + int serviceCount; +} ServiceSpace; + +Service *GetServiceByPid(pid_t pid); +Service *GetServiceByName(const char *servName); +cJSON *GetArrayItem(const cJSON *fileRoot, int *arrSize, const char *arrName); + void StartServiceByName(const char *serviceName, bool checkDynamic); void StopServiceByName(const char *serviceName); -void StopAllServices(void); -void StopAllServicesBeforeReboot(void); -void ReapServiceByPID(int pid); +void StopAllServices(int flags); void ParseAllServices(const cJSON *fileRoot); #ifdef OHOS_SERVICE_DUMP -void DumpAllServices(void); +void DumpAllServices(); #endif #ifdef __cplusplus #if __cplusplus diff --git a/services/include/init_service_socket.h b/services/init/include/init_service_socket.h old mode 100644 new mode 100755 similarity index 57% rename from services/include/init_service_socket.h rename to services/init/include/init_service_socket.h index 6ff5ed5..0b216c4 --- a/services/include/init_service_socket.h +++ b/services/init/include/init_service_socket.h @@ -1,10 +1,10 @@ /* - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * 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, @@ -12,17 +12,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #ifndef INIT_SERVICE_SOCKET_ #define INIT_SERVICE_SOCKET_ #include -#include #include +#include #include #include +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif -#define MAX_SOCK_NAME_LEN 16 -#define SOCK_OPT_NUMS 6 +#define MAX_SOCK_NAME_LEN 16 +#define SOCK_OPT_NUMS 6 enum SockOptionTab { SERVICE_SOCK_NAME = 0, SERVICE_SOCK_TYPE, @@ -32,18 +36,23 @@ enum SockOptionTab { SERVICE_SOCK_SETOPT }; -struct ServiceSocket; -struct ServiceSocket { - char *name; // service name - int type; // socket type - uid_t uid; // uid - gid_t gid; // gid - bool passcred; // setsocketopt - mode_t perm; // Setting permissions +typedef struct ServiceSocket_ { + struct ServiceSocket_ *next; + int type; // socket type + uid_t uid; // uid + gid_t gid; // gid + bool passcred; // setsocketopt + mode_t perm; // Setting permissions int sockFd; - struct ServiceSocket *next; -}; + char name[0]; // service name +} ServiceSocket; -int DoCreateSocket(struct ServiceSocket *sockopt); +int CreateServiceSocket(ServiceSocket *sockopt); +void CloseServiceSocket(ServiceSocket *sockopt); +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif #endif diff --git a/services/init/init_capability.c b/services/init/init_capability.c new file mode 100755 index 0000000..48d1806 --- /dev/null +++ b/services/init/init_capability.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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 +#if defined OHOS_LITE && !defined __LINUX__ +#include +#else +#include +#endif +#include +#include + +#include "init_log.h" +#include "init_service.h" +#include "init_service_manager.h" +#include "init_utils.h" + +#define MAX_CAPS_CNT_FOR_ONE_SERVICE 100 + +static unsigned int GetCapByString(const char *capStr) +{ + static const CapStrCapNum capStrCapNum[] = { + { "CHOWN", CAP_CHOWN }, + { "DAC_OVERRIDE", CAP_DAC_OVERRIDE }, + { "DAC_READ_SEARCH", CAP_DAC_READ_SEARCH }, + { "FOWNER", CAP_FOWNER }, + { "FSETID", CAP_FSETID }, + { "KILL", CAP_KILL }, + { "SETGID", CAP_SETGID }, + { "SETUID", CAP_SETUID }, + { "SETPCAP", CAP_SETPCAP }, + { "LINUX_IMMUTABLE", CAP_LINUX_IMMUTABLE }, + { "NET_BIND_SERVICE", CAP_NET_BIND_SERVICE }, + { "NET_BROADCAST", CAP_NET_BROADCAST }, + { "NET_ADMIN", CAP_NET_ADMIN }, + { "NET_RAW", CAP_NET_RAW }, + { "IPC_LOCK", CAP_IPC_LOCK }, + { "IPC_OWNER", CAP_IPC_OWNER }, + { "SYS_MODULE", CAP_SYS_MODULE }, + { "SYS_RAWIO", CAP_SYS_RAWIO }, + { "SYS_CHROOT", CAP_SYS_CHROOT }, + { "SYS_PTRACE", CAP_SYS_PTRACE }, + { "SYS_PACCT", CAP_SYS_PACCT }, + { "SYS_ADMIN", CAP_SYS_ADMIN }, + { "SYS_BOOT", CAP_SYS_BOOT }, + { "SYS_NICE", CAP_SYS_NICE }, + { "SYS_RESOURCE", CAP_SYS_RESOURCE }, + { "SYS_TIME", CAP_SYS_TIME }, + { "SYS_TTY_CONFIG", CAP_SYS_TTY_CONFIG }, + { "MKNOD", CAP_MKNOD }, + { "LEASE", CAP_LEASE }, + { "AUDIT_WRITE", CAP_AUDIT_WRITE }, + { "AUDIT_CONTROL", CAP_AUDIT_CONTROL }, + { "SETFCAP", CAP_SETFCAP }, + { "MAC_OVERRIDE", CAP_MAC_OVERRIDE }, + { "MAC_ADMIN", CAP_MAC_ADMIN }, + { "SYSLOG", CAP_SYSLOG }, + { "WAKE_ALARM", CAP_WAKE_ALARM }, + { "BLOCK_SUSPEND", CAP_BLOCK_SUSPEND }, + { "AUDIT_READ", CAP_AUDIT_READ }, + }; + int mapSize = (int)ARRAY_LENGTH(capStrCapNum); + for (int j = 0; j < mapSize; j++) { + if (strcmp(capStr, capStrCapNum[j].capStr) == 0) { + return capStrCapNum[j].CapNum; + } + } + return -1; +} + +int GetServiceCaps(const cJSON *curArrItem, Service *service) +{ + INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "service is null ptr."); + INIT_ERROR_CHECK(curArrItem != NULL, return SERVICE_FAILURE, "json is null ptr."); + service->servPerm.capsCnt = 0; + service->servPerm.caps = NULL; + int capsCnt = 0; + cJSON *filedJ = GetArrayItem(curArrItem, &capsCnt, "caps"); + if (filedJ == NULL) { + return SERVICE_SUCCESS; + } + if (capsCnt > MAX_CAPS_CNT_FOR_ONE_SERVICE) { + INIT_LOGE("service=%s, too many caps[cnt %d] for one service", service->name, capsCnt); + return SERVICE_FAILURE; + } + service->servPerm.caps = (unsigned int *)calloc(1, sizeof(unsigned int) * capsCnt); + if (service->servPerm.caps == NULL) { + INIT_LOGE("Failed to malloc for service %s", service->name); + return SERVICE_FAILURE; + } + service->servPerm.capsCnt = capsCnt; + unsigned int caps = FULL_CAP; + for (int i = 0; i < capsCnt; ++i) { // number form + cJSON *capJson = cJSON_GetArrayItem(filedJ, i); + if (cJSON_IsNumber(capJson)) { // for number + caps = (unsigned int)cJSON_GetNumberValue(capJson); + } else if (cJSON_IsString(capJson)) { + char *capStr = cJSON_GetStringValue(capJson); + if (capStr == NULL || strlen(capStr) <= 0) { // check all errors + INIT_LOGE("service=%s, parse item[%d] as string, error.", service->name, i); + break; + } + caps = GetCapByString(capStr); + } + if (caps < 0) { + return SERVICE_FAILURE; + } + if ((caps > CAP_LAST_CAP) && (caps != (unsigned int)FULL_CAP)) { + INIT_LOGE("service=%s, caps = %d, error.", service->name, caps); + return SERVICE_FAILURE; + } + service->servPerm.caps[i] = (unsigned int)caps; + } + return 0; +} diff --git a/services/init/init_common_cmds.c b/services/init/init_common_cmds.c new file mode 100755 index 0000000..90a7721 --- /dev/null +++ b/services/init/init_common_cmds.c @@ -0,0 +1,731 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "init_cmds.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "init.h" +#include "init_jobs.h" +#include "init_log.h" +#include "init_service_manager.h" +#include "init_utils.h" +#include "securec.h" + +static char *AddOneArg(const char *param, size_t paramLen) +{ + int valueCount = 1; + char *begin = strchr(param, '$'); + while (begin != NULL) { + valueCount++; + begin = strchr(begin + 1, '$'); + } + size_t allocSize = paramLen + (PARAM_VALUE_LEN_MAX * valueCount) + 1; + char *arg = calloc(sizeof(char), allocSize); + INIT_CHECK(arg != NULL, return NULL); + int ret = GetParamValue(param, paramLen, arg, allocSize); + INIT_ERROR_CHECK(ret == 0, free(arg); + return NULL, "Failed to get value for %s", param); + return arg; +} + +char *BuildStringFromCmdArg(const struct CmdArgs *ctx, int startIndex) +{ + char *options = (char *)calloc(1, OPTIONS_SIZE + 1); + INIT_ERROR_CHECK(options != NULL, return NULL, "Failed to get memory "); + options[0] = '\0'; + int curr = 0; + for (int i = startIndex; i < ctx->argc; i++) { // save opt + if (ctx->argv[i] == NULL) { + continue; + } + int len = snprintf_s(options + curr, OPTIONS_SIZE - curr, OPTIONS_SIZE - 1 - curr, "%s ", ctx->argv[i]); + if (len <= 0) { + INIT_LOGE("Failed to format other opt"); + options[0] = '\0'; + return options; + } + curr += len; + } + if ((curr > 0) && (curr < OPTIONS_SIZE)) { + options[curr - 1] = '\0'; + } + return options; +} + +const struct CmdArgs *GetCmdArg(const char *cmdContent, const char *delim, int argsCount) +{ + INIT_CHECK_RETURN_VALUE(cmdContent != 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; + } + struct CmdArgs *ctx = (struct CmdArgs *)calloc(1, sizeof(struct CmdArgs) + sizeof(char *) * (argsCount + 1)); + INIT_ERROR_CHECK(ctx != NULL, return NULL, "Failed to malloc memory for arg"); + ctx->argc = 0; + char *p = (char *)cmdContent; + char *end = (char *)cmdContent + strlen(cmdContent); + char *token = NULL; + do { + // Skip lead whitespaces + while (isspace(*p)) { + p++; + } + token = strstr(p, delim); + if (token == NULL) { + ctx->argv[ctx->argc] = AddOneArg(p, end - p); + INIT_CHECK(ctx->argv[ctx->argc] != NULL, FreeCmdArg(ctx); + return NULL); + } else { + ctx->argv[ctx->argc] = AddOneArg(p, token - p); + INIT_CHECK(ctx->argv[ctx->argc] != NULL, FreeCmdArg(ctx); + return NULL); + } + ctx->argc++; + ctx->argv[ctx->argc] = NULL; + if (ctx->argc == argsCount) { + break; + } + p = token; + } while (token != NULL); + return ctx; +} + +void FreeCmdArg(struct CmdArgs *cmd) +{ + INIT_CHECK_ONLY_RETURN(cmd != NULL); + for (int i = 0; i < cmd->argc; ++i) { + if (cmd->argv[i] != NULL) { + free(cmd->argv[i]); + } + } + free(cmd); + return; +} + +static void ExecCmd(const struct CmdTable *cmd, const char *cmdContent) +{ + if (cmd == NULL) { + INIT_LOGE("Invalid cmd for %s", cmdContent); + return; + } + + const struct CmdArgs *ctx = GetCmdArg(cmdContent, " ", cmd->maxArg); + if (ctx == NULL) { + INIT_LOGE("Invalid arguments cmd: %s content: %s", cmd->name, cmdContent); + } else if ((ctx->argc <= cmd->maxArg) && (ctx->argc >= cmd->minArg)) { + cmd->DoFuncion(ctx, cmdContent); + } else { + INIT_LOGE("Invalid arguments cmd: %s content: %s argc: %d %d", cmd->name, cmdContent, ctx->argc, cmd->maxArg); + } + FreeCmdArg((struct CmdArgs *)ctx); +} + +static void SetProcName(const struct CmdArgs *ctx, const char *procFile) +{ + int fd = open(procFile, O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, S_IRUSR | S_IWUSR); + INIT_ERROR_CHECK(fd >= 0, return, "Failed to set %s errno: %d", procFile, errno); + + size_t size = strlen(ctx->argv[0]); + ssize_t n = write(fd, ctx->argv[0], size); + INIT_ERROR_CHECK(n == (ssize_t)size, close(fd); + return, "Failed to write domainname errno: %d", errno); + close(fd); +} + +static void DoSetDomainname(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(cmdContent); + SetProcName(ctx, "/proc/sys/kernel/domainname"); +} + +static void DoSetHostname(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(cmdContent); + SetProcName(ctx, "/proc/sys/kernel/hostname"); +} + +static void DoSleep(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(cmdContent); + errno = 0; + unsigned long sleepTime = strtoul(ctx->argv[0], NULL, DECIMAL_BASE); + if (errno != 0) { + INIT_LOGE("cannot covert sleep time in command \" sleep \""); + return; + } + + // Limit sleep time in 5 seconds + const unsigned long sleepTimeLimit = 5; + if (sleepTime > sleepTimeLimit) { + sleepTime = sleepTimeLimit; + } + INIT_LOGI("Sleeping %d second(s)", sleepTime); + sleep((unsigned int)sleepTime); +} + +static void DoStart(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(ctx); + INIT_LOGD("DoStart %s", cmdContent); + StartServiceByName(cmdContent, true); +} + +static void DoStop(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(ctx); + INIT_LOGD("DoStop %s", cmdContent); + StopServiceByName(cmdContent); + return; +} + +static void DoReset(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(ctx); + INIT_LOGD("DoReset %s", cmdContent); + DoStop(ctx, cmdContent); + DoStart(ctx, cmdContent); +} + +static void DoCopy(const struct CmdArgs *ctx, const char *cmdContent) +{ + int srcFd = -1; + int dstFd = -1; + char buf[MAX_COPY_BUF_SIZE] = { 0 }; + char *realPath1 = NULL; + char *realPath2 = NULL; + if (ctx == NULL || ctx->argc != DEFAULT_COPY_ARGS_CNT) { + INIT_LOGE("DoCopy invalid arguments :%s", cmdContent); + return; + } + do { + realPath1 = GetRealPath(ctx->argv[0]); + if (realPath1 == NULL) { + INIT_LOGE("Failed to get real path %s", ctx->argv[0]); + break; + } + srcFd = open(realPath1, O_RDONLY); + if (srcFd < 0) { + INIT_LOGE("Failed to open source path %s %d", ctx->argv[0], errno); + break; + } + struct stat fileStat = { 0 }; + if (stat(ctx->argv[0], &fileStat) != 0) { + INIT_LOGE("Failed to state source path %s %d", ctx->argv[0], errno); + break; + } + mode_t mode = fileStat.st_mode; + realPath2 = GetRealPath(ctx->argv[1]); + if (realPath2 != NULL) { + dstFd = open(realPath2, O_WRONLY | O_TRUNC | O_CREAT, mode); + } else { + dstFd = open(ctx->argv[1], O_WRONLY | O_TRUNC | O_CREAT, mode); + } + if (srcFd < 0) { + INIT_LOGE("Failed to open dest path %s %d", ctx->argv[1], errno); + break; + } + int rdLen = 0; + while ((rdLen = read(srcFd, buf, sizeof(buf) - 1)) > 0) { + int rtLen = write(dstFd, buf, rdLen); + if (rtLen != rdLen) { + INIT_LOGE("Failed to write to dest path %s %d", ctx->argv[1], errno); + break; + } + } + fsync(dstFd); + } while (0); + INIT_CHECK(srcFd < 0, close(srcFd)); + INIT_CHECK(dstFd < 0, close(dstFd)); + INIT_CHECK(realPath1 == NULL, free(realPath1)); + INIT_CHECK(realPath2 == NULL, free(realPath2)); +} + +static int SetOwner(const char *file, const char *ownerStr, const char *groupStr) +{ + INIT_ERROR_CHECK(file != NULL, return -1, "SetOwner invalid file."); + INIT_ERROR_CHECK(ownerStr != NULL, return -1, "SetOwner invalid file."); + INIT_ERROR_CHECK(groupStr != NULL, return -1, "SetOwner invalid file."); + + uid_t owner = DecodeUid(ownerStr); + INIT_ERROR_CHECK(owner != (uid_t)-1, return -1, "SetOwner invalid uid :%s.", ownerStr); + gid_t group = DecodeUid(groupStr); + INIT_ERROR_CHECK(group != (gid_t)-1, return -1, "SetOwner invalid gid :%s.", groupStr); + return (chown(file, owner, group) != 0) ? -1 : 0; +} + +static void DoChown(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(cmdContent); + // format: chown owner group /xxx/xxx/xxx + const int pathPos = 2; + int ret = SetOwner(ctx->argv[pathPos], ctx->argv[0], ctx->argv[1]); + if (ret != 0) { + INIT_LOGE("Failed to change owner %s, err %d.", cmdContent, errno); + } + return; +} + +static void DoMkDir(const struct CmdArgs *ctx, const char *cmdContent) +{ + // mkdir support format: + // 1.mkdir path + // 2.mkdir path mode + // 3.mkdir path mode owner group + UNUSED(cmdContent); + const int ownerPos = 2; + const int groupPos = 3; + if (ctx->argc != 1 && ctx->argc != (groupPos + 1) && ctx->argc != ownerPos) { + INIT_LOGE("DoMkDir invalid arguments: %s", cmdContent); + return; + } + mode_t mode = DEFAULT_DIR_MODE; + if (mkdir(ctx->argv[0], mode) != 0 && errno != EEXIST) { + INIT_LOGE("DoMkDir, failed for '%s', err %d.", ctx->argv[0], errno); + return; + } + if (ctx->argc <= 1) { + return; + } + + mode = strtoul(ctx->argv[1], NULL, OCTAL_TYPE); + if (chmod(ctx->argv[0], mode) != 0) { + INIT_LOGE("DoMkDir failed for '%s', err %d.", ctx->argv[0], errno); + } + if (ctx->argc <= ownerPos) { + return; + } + int ret = SetOwner(ctx->argv[0], ctx->argv[ownerPos], ctx->argv[groupPos]); + if (ret != 0) { + INIT_LOGE("Failed to change owner %s, err %d.", cmdContent, errno); + } + return; +} + +static void DoChmod(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(cmdContent); + // format: chmod xxxx /xxx/xxx/xxx + mode_t mode = strtoul(ctx->argv[0], NULL, OCTAL_TYPE); + if (mode == 0) { + INIT_LOGE("DoChmod, strtoul failed for %s, er %d.", cmdContent, errno); + return; + } + + if (chmod(ctx->argv[1], mode) != 0) { + INIT_LOGE("Failed to change mode \" %s \" mode to %04o, err = %d", ctx->argv[1], mode, errno); + } +} + +static int GetMountFlag(unsigned long *mountflag, const char *targetStr, const char *source) +{ + if (targetStr == NULL || mountflag == NULL) { + return 0; + } + struct { + char *flagName; + int value; + } mountFlagMap[] = { + { "noatime", MS_NOATIME }, + { "noexec", MS_NOEXEC }, + { "nosuid", MS_NOSUID }, + { "nodev", MS_NODEV }, + { "nodiratime", MS_NODIRATIME }, + { "ro", MS_RDONLY }, + { "rdonly", MS_RDONLY }, + { "rw", 0 }, + { "sync", MS_SYNCHRONOUS }, + { "remount", MS_REMOUNT }, + { "bind", MS_BIND }, + { "rec", MS_REC }, + { "unbindable", MS_UNBINDABLE }, + { "private", MS_PRIVATE }, + { "slave", MS_SLAVE }, + { "shared", MS_SHARED }, + { "defaults", 0 }, + }; + for (unsigned int i = 0; i < ARRAY_LENGTH(mountFlagMap); i++) { + if (strncmp(targetStr, mountFlagMap[i].flagName, strlen(mountFlagMap[i].flagName)) == 0) { + *mountflag |= mountFlagMap[i].value; + return 1; + } + } + if (strncmp(targetStr, "wait", strlen("wait")) == 0) { + WaitForFile(source, WAIT_MAX_COUNT); + return 1; + } + return 0; +} + +static void DoMount(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(ctx); + INIT_ERROR_CHECK(ctx->argc <= SPACES_CNT_IN_CMD_MAX, return, "Invalid arg number"); + // format: fileSystemType source target mountFlag1 mountFlag2... data + int index = 0; + char *fileSysType = (ctx->argc > index) ? ctx->argv[index] : NULL; + INIT_ERROR_CHECK(fileSysType != NULL, return, "Failed to get fileSysType %s", cmdContent); + index++; + + char *source = (ctx->argc > index) ? ctx->argv[index] : NULL; + INIT_ERROR_CHECK(source != NULL, return, "Failed to get source %s", cmdContent); + index++; + + // maybe only has "filesystype source target", 2 spaces + char *target = (ctx->argc > index) ? ctx->argv[index] : NULL; + INIT_ERROR_CHECK(target != NULL, return, "Failed to get target %s", cmdContent); + ++index; + + int ret = 0; + unsigned long mountflags = 0; + while (index < ctx->argc) { + ret = GetMountFlag(&mountflags, ctx->argv[index], source); + if (ret == 0) { + break; + } + index++; + } + if (index >= ctx->argc) { + ret = mount(source, target, fileSysType, mountflags, NULL); + } else { + char *data = BuildStringFromCmdArg(ctx, index); + INIT_ERROR_CHECK(data != NULL, return, "Failed to get data %s", cmdContent); + ret = mount(source, target, fileSysType, mountflags, data); + free(data); + } + if (ret != 0) { + INIT_LOGE("Failed to mount %s, err %d.", cmdContent, errno); + } +} + +static bool CheckValidCfg(const char *path) +{ + static const char *supportCfg[] = { + "/etc/patch.cfg", + "/patch/fstab.cfg", + }; + INIT_ERROR_CHECK(path != NULL, return false, "Invalid path for cfg"); + struct stat fileStat = { 0 }; + if (stat(path, &fileStat) != 0 || fileStat.st_size <= 0 || fileStat.st_size > LOADCFG_MAX_FILE_LEN) { + return false; + } + size_t cfgCnt = ARRAY_LENGTH(supportCfg); + for (size_t i = 0; i < cfgCnt; ++i) { + if (strcmp(path, supportCfg[i]) == 0) { + return true; + } + } + return false; +} + +static void DoLoadCfg(const struct CmdArgs *ctx, const char *path) +{ + UNUSED(ctx); + char buf[LOADCFG_BUF_SIZE] = { 0 }; + size_t maxLoop = 0; + int len; + if (!CheckValidCfg(path)) { + INIT_LOGE("CheckCfg file %s Failed", path); + return; + } + char *realPath = GetRealPath(path); + INIT_ERROR_CHECK(realPath != NULL, return, "Failed to get realpath %s", path); + FILE *fp = fopen(realPath, "r"); + if (fp == NULL) { + INIT_LOGE("Failed to open cfg %s error:%d", path, errno); + free(realPath); + return; + } + + while (fgets(buf, LOADCFG_BUF_SIZE - 1, fp) != NULL && maxLoop < LOADCFG_MAX_LOOP) { + maxLoop++; + len = strlen(buf); + if (len < 1) { + continue; + } + if (buf[len - 1] == '\n') { + buf[len - 1] = '\0'; // we replace '\n' with '\0' + } + const struct CmdTable *cmd = GetCmdByName(buf); + if (cmd == NULL) { + INIT_LOGE("Cannot support command: %s", buf); + continue; + } + ExecCmd(cmd, &buf[strlen(cmd->name) + 1]); + } + free(realPath); + (void)fclose(fp); +} + +static void DoWrite(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(cmdContent); + // format: write path content + char *realPath = GetRealPath(ctx->argv[0]); + int fd = -1; + if (realPath != NULL) { + fd = open(realPath, O_WRONLY | O_CREAT | O_NOFOLLOW | O_CLOEXEC, S_IRUSR | S_IWUSR); + } else { + fd = open(ctx->argv[0], O_WRONLY | O_CREAT | O_NOFOLLOW | O_CLOEXEC, S_IRUSR | S_IWUSR); + } + if (fd >= 0) { + 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); + } + } + if (realPath != NULL) { + free(realPath); + } + realPath = NULL; + close(fd); +} + +static void DoRmdir(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(cmdContent); + // format: rmdir path + int ret = rmdir(ctx->argv[0]); + if (ret == -1) { + INIT_LOGE("DoRmdir: remove %s failed: %d.", ctx->argv[0], errno); + } + return; +} + +static void DoRebootCmd(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(ctx); + ExecReboot(cmdContent); + return; +} + +static void DoSetrlimit(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(cmdContent); + 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" + }; + // format: setrlimit resource curValue maxValue + const int rlimMaxPos = 2; + 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 < 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]); + return; + } + int ret = setrlimit(rcs, &limit); + if (ret) { + INIT_LOGE("DoSetrlimit failed : %d", errno); + } +} + +static void DoRm(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(cmdContent); + // format: rm /xxx/xxx/xxx + int ret = unlink(ctx->argv[0]); + if (ret == -1) { + INIT_LOGE("DoRm: unlink %s failed: %d.", ctx->argv[0], errno); + } +} + +static void DoExport(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(cmdContent); + // format: export xxx /xxx/xxx/xxx + 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); + } +} + +static const struct CmdTable g_cmdTable[] = { + { "start ", 0, 1, DoStart }, + { "mkdir ", 1, 4, DoMkDir }, + { "chmod ", 2, 2, DoChmod }, + { "chown ", 3, 3, DoChown }, + { "mount ", 1, 10, DoMount }, + { "export ", 2, 2, DoExport }, + { "loadcfg ", 1, 1, DoLoadCfg }, + { "rm ", 1, 1, DoRm }, + { "rmdir ", 1, 1, DoRmdir }, + { "write ", 2, 2, DoWrite }, + { "stop ", 1, 1, DoStop }, + { "reset ", 1, 1, DoReset }, + { "copy ", 2, 2, DoCopy }, + { "reboot ", 1, 1, DoRebootCmd }, + { "setrlimit ", 3, 3, DoSetrlimit }, + { "sleep ", 1, 1, DoSleep }, + { "hostname ", 1, 1, DoSetHostname }, + { "domainname ", 1, 1, DoSetDomainname } +}; + +static const struct CmdTable *GetCommCmdTable(int *number) +{ + *number = (int)ARRAY_LENGTH(g_cmdTable); + return g_cmdTable; +} + +const struct CmdTable *GetCmdByName(const char *name) +{ + int cmdCnt = 0; + const struct CmdTable *commCmds = GetCommCmdTable(&cmdCnt); + for (int i = 0; i < cmdCnt; ++i) { + if (strncmp(name, commCmds[i].name, strlen(commCmds[i].name)) == 0) { + return &commCmds[i]; + } + } + int number = 0; + const struct CmdTable *cmds = GetCmdTable(&number); + for (int i = 0; i < number; ++i) { + if (strncmp(name, cmds[i].name, strlen(cmds[i].name)) == 0) { + return &cmds[i]; + } + } + return NULL; +} + +const char *GetMatchCmd(const char *cmdStr, int *index) +{ + if (cmdStr == NULL || index == NULL) { + return NULL; + } + int cmdCnt = 0; + const struct CmdTable *commCmds = GetCommCmdTable(&cmdCnt); + for (int i = 0; i < cmdCnt; ++i) { + if (strncmp(cmdStr, commCmds[i].name, strlen(commCmds[i].name)) == 0) { + *index = i; + return commCmds[i].name; + } + } + int number = 0; + const struct CmdTable *cmds = GetCmdTable(&number); + for (int i = 0; i < number; ++i) { + if (strncmp(cmdStr, cmds[i].name, strlen(cmds[i].name)) == 0) { + *index = cmdCnt + i; + return cmds[i].name; + } + } + return NULL; +} + +const char *GetCmdKey(int index) +{ + int cmdCnt = 0; + const struct CmdTable *commCmds = GetCommCmdTable(&cmdCnt); + if (index < cmdCnt) { + return commCmds[index].name; + } + int number = 0; + const struct CmdTable *cmds = GetCmdTable(&number); + if (index < number) { + return cmds[index].name; + } + return NULL; +} + +int GetCmdLinesFromJson(const cJSON *root, CmdLines **cmdLines) +{ + INIT_CHECK(root != NULL, return -1); + INIT_CHECK(cmdLines != NULL, return -1); + *cmdLines = NULL; + if (!cJSON_IsArray(root)) { + return -1; + } + int cmdCnt = cJSON_GetArraySize(root); + if (cmdCnt <= 0) { + return -1; + } + *cmdLines = (CmdLines *)calloc(1, sizeof(CmdLines) + sizeof(CmdLine) * cmdCnt); + if (*cmdLines == NULL) { + return -1; + } + (*cmdLines)->cmdNum = 0; + for (int i = 0; i < cmdCnt; ++i) { + cJSON *line = cJSON_GetArrayItem(root, i); + if (!cJSON_IsString(line)) { + continue; + } + char *tmp = cJSON_GetStringValue(line); + if (tmp == NULL) { + continue; + } + int index = 0; + const char *cmd = GetMatchCmd(tmp, &index); + if (cmd == NULL) { + INIT_LOGE("Cannot support command: %s", tmp); + continue; + } + int ret = strcpy_s((*cmdLines)->cmds[(*cmdLines)->cmdNum].cmdContent, MAX_CMD_CONTENT_LEN, tmp + strlen(cmd)); + if (ret != EOK) { + INIT_LOGE("Invalid cmd arg: %s", tmp); + continue; + } + (*cmdLines)->cmds[(*cmdLines)->cmdNum].cmdIndex = index; + (*cmdLines)->cmdNum++; + } + return 0; +} + +void DoCmdByName(const char *name, const char *cmdContent) +{ + if (name == NULL || cmdContent == NULL) { + return; + } + const struct CmdTable *cmd = GetCmdByName(name); + ExecCmd(cmd, cmdContent); +} + +void DoCmdByIndex(int index, const char *cmdContent) +{ + if (cmdContent == NULL) { + return; + } + int cmdCnt = 0; + const struct CmdTable *commCmds = GetCommCmdTable(&cmdCnt); + if (index < cmdCnt) { + ExecCmd(&commCmds[index], cmdContent); + return; + } + int number = 0; + const struct CmdTable *cmds = GetCmdTable(&number); + if (index < (cmdCnt + number)) { + ExecCmd(&cmds[index - cmdCnt], cmdContent); + return; + } +} diff --git a/services/src/init_service.c b/services/init/init_common_service.c old mode 100644 new mode 100755 similarity index 57% rename from services/src/init_service.c rename to services/init/init_common_service.c index 4cb4a7c..197db70 --- a/services/src/init_service.c +++ b/services/init/init_common_service.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Huawei Device Co., Ltd. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,12 +12,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #include "init_service.h" #include #include -#include #include #include #include @@ -25,46 +23,32 @@ #ifdef __MUSL__ #include #endif +#include #include -#ifndef OHOS_LITE -#include -#endif #include #include #include +#include "init.h" #include "init_adapter.h" #include "init_cmds.h" #include "init_log.h" -#ifndef OHOS_LITE -#include "init_param.h" -#endif -#include "init_perms.h" -#include "init_reboot.h" #include "init_service_socket.h" #include "init_utils.h" #include "securec.h" -#ifndef OHOS_LITE -#include "sys_param.h" -#endif - -#define CAP_NUM 2 -#define WAIT_MAX_COUNT 10 #ifndef TIOCSCTTY #define TIOCSCTTY 0x540E #endif // 240 seconds, 4 minutes -static const int CRASH_TIME_LIMIT = 240; +static const int CRASH_TIME_LIMIT = 240; // maximum number of crashes within time CRASH_TIME_LIMIT for one service static const int CRASH_COUNT_LIMIT = 4; // 240 seconds, 4 minutes -static const int CRITICAL_CRASH_TIME_LIMIT = 240; +static const int CRITICAL_CRASH_TIME_LIMIT = 240; // maximum number of crashes within time CRITICAL_CRASH_TIME_LIMIT for one service static const int CRITICAL_CRASH_COUNT_LIMIT = 4; -static const int MAX_PID_STRING_LENGTH = 50; - static int SetAllAmbientCapability(void) { @@ -101,14 +85,13 @@ static int SetPerms(const Service *service) struct __user_cap_header_struct capHeader; capHeader.version = _LINUX_CAPABILITY_VERSION_3; capHeader.pid = 0; - struct __user_cap_data_struct capData[CAP_NUM] = {}; for (unsigned int i = 0; i < service->servPerm.capsCnt; ++i) { if (service->servPerm.caps[i] == FULL_CAP) { - for (int i = 0; i < CAP_NUM; ++i) { - capData[i].effective = FULL_CAP; - capData[i].permitted = FULL_CAP; - capData[i].inheritable = FULL_CAP; + for (int j = 0; j < CAP_NUM; ++j) { + capData[j].effective = FULL_CAP; + capData[j].permitted = FULL_CAP; + capData[j].inheritable = FULL_CAP; } break; } @@ -135,6 +118,7 @@ static int SetPerms(const Service *service) static void OpenConsole(void) { + const int stdError = 2; setsid(); WaitForFile("/dev/console", WAIT_MAX_COUNT); int fd = open("/dev/console", O_RDWR); @@ -142,7 +126,7 @@ static void OpenConsole(void) ioctl(fd, TIOCSCTTY, 0); dup2(fd, 0); dup2(fd, 1); - dup2(fd, 2); // Redirect fd to 0, 1, 2 + dup2(fd, stdError); // Redirect fd to 0, 1, 2 close(fd); } else { INIT_LOGE("Open /dev/console failed. err = %d", errno); @@ -150,107 +134,106 @@ static void OpenConsole(void) return; } -static void WriteServicePid(const Service *service, pid_t pid) +static int WritePid(const Service *service) { - 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) { + const int maxPidStrLen = 50; + char pidString[maxPidStrLen]; + pid_t childPid = getpid(); + int len = snprintf_s(pidString, maxPidStrLen, maxPidStrLen - 1, "%d", childPid); + if (len <= 0) { + INIT_LOGE("Failed to format pid for service %s", service->name); + return SERVICE_FAILURE; + } + for (int i = 0; i < service->writePidArgs.count; i++) { + if (service->writePidArgs.argv[i] == 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); + FILE *fd = NULL; + char *realPath = GetRealPath(service->writePidArgs.argv[i]); + if (realPath != NULL) { + fd = fopen(realPath, "wb"); + } else { + fd = fopen(service->writePidArgs.argv[i], "wb"); + } + if (fd != NULL) { + if ((int)fwrite(pidString, 1, len, fd) != len) { + INIT_LOGE("Failed to write %s pid:%s", service->writePidArgs.argv[i], pidString); + } + (void)fclose(fd); + } else { + INIT_LOGE("Failed to open %s.", service->writePidArgs.argv[i]); + } + if (realPath != NULL) { + free(realPath); + } + INIT_LOGD("ServiceStart writepid filename=%s, childPid=%s, ok", service->writePidArgs.argv[i], pidString); } + return SERVICE_SUCCESS; } 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); + INIT_ERROR_CHECK(service->pid <= 0, return SERVICE_SUCCESS, "service : %s had started already.", service->name); + INIT_ERROR_CHECK(service->pathArgs.count > 0, + return SERVICE_FAILURE, "start service %s pathArgs is NULL.", service->name); if (service->attribute & SERVICE_ATTR_INVALID) { INIT_LOGE("start service %s invalid.", service->name); return SERVICE_FAILURE; } - INIT_ERROR_CHECK(service->pathArgs != NULL, return SERVICE_FAILURE, "start service pathArgs is NULL."); - struct stat pathStat = {0}; + struct stat pathStat = { 0 }; service->attribute &= (~(SERVICE_ATTR_NEED_RESTART | SERVICE_ATTR_NEED_STOP)); - 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 (stat(service->pathArgs.argv[0], &pathStat) != 0) { + service->attribute |= SERVICE_ATTR_INVALID; + INIT_LOGE("start service %s invalid, please check %s.", service->name, service->pathArgs.argv[0]); + return SERVICE_FAILURE; + } + int pid = fork(); if (pid == 0) { - if (service->socketCfg != NULL) { // start socket service - INIT_ERROR_CHECK(DoCreateSocket(service->socketCfg) >= 0, _exit(0x7f), "Create Socket failed. "); + int ret = CreateServiceSocket(service->socketCfg); + if (ret < 0) { + INIT_LOGE("service %s exit! create socket failed!", service->name); + _exit(PROCESS_EXIT_CODE); } if (service->attribute & SERVICE_ATTR_CONSOLE) { OpenConsole(); } - 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) { - INIT_ERROR_CHECK(setpriority(PRIO_PROCESS, 0, service->importance) == 0, _exit(0x7f), - "setpriority failed for %s, importance = %d", service->name, service->importance); + // permissions + if (SetPerms(service) != SERVICE_SUCCESS) { + INIT_LOGE("service %s exit! set perms failed! err %d.", service->name, errno); + _exit(PROCESS_EXIT_CODE); } - // L2 Can not be reset env - 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}; - 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 + // write pid + if (WritePid(service) != SERVICE_SUCCESS) { + INIT_LOGE("service %s exit! write pid failed!", service->name); + _exit(PROCESS_EXIT_CODE); + } + ServiceExec(service); + _exit(PROCESS_EXIT_CODE); } else if (pid < 0) { INIT_LOGE("start service %s fork failed!", service->name); return SERVICE_FAILURE; } + INIT_LOGI("service %s starting pid %d", service->name, pid); service->pid = pid; -#ifndef OHOS_LITE - char paramName[PARAM_NAME_LEN_MAX] = {0}; - int ret = snprintf_s(paramName, PARAM_NAME_LEN_MAX, PARAM_NAME_LEN_MAX - 1, "init.svc.%s", service->name); - INIT_CHECK_ONLY_ELOG(ret >= 0, "snprintf_s paramName error %d ", errno); - SystemWriteParam(paramName, "running"); -#endif + NotifyServiceChange(service->name, "running"); return SERVICE_SUCCESS; } int ServiceStop(Service *service) { - if (service == NULL) { - INIT_LOGE("stop service failed! null ptr."); - return SERVICE_FAILURE; - } - + INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "stop service failed! null ptr."); service->attribute &= ~SERVICE_ATTR_NEED_RESTART; service->attribute |= SERVICE_ATTR_NEED_STOP; if (service->pid <= 0) { return SERVICE_SUCCESS; } - + CloseServiceSocket(service->socketCfg); if (kill(service->pid, SIGKILL) != 0) { INIT_LOGE("stop service %s pid %d failed! err %d.", service->name, service->pid, errno); return SERVICE_FAILURE; } -#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); - } - SystemWriteParam(paramName, "stopping"); -#endif + NotifyServiceChange(service->name, "stopping"); INIT_LOGI("stop service %s, pid %d.", service->name, service->pid); return SERVICE_SUCCESS; } @@ -277,46 +260,37 @@ static bool CalculateCrashTime(Service *service, int crashTimeLimit, int crashCo static int ExecRestartCmd(const Service *service) { - INIT_LOGI("ExecRestartCmd "); - if ((service == NULL) || (service->onRestart == NULL) || (service->onRestart->cmdLine == NULL)) { - return SERVICE_FAILURE; - } + INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "Exec service failed! null ptr."); + INIT_ERROR_CHECK(service->restartArg != NULL, return SERVICE_FAILURE, "restartArg is null"); - for (int i = 0; i < service->onRestart->cmdNum; i++) { - INIT_LOGI("SetOnRestart cmdLine->name %s cmdLine->cmdContent %s ", service->onRestart->cmdLine[i].name, - service->onRestart->cmdLine[i].cmdContent); - DoCmd(&service->onRestart->cmdLine[i]); + for (int i = 0; i < service->restartArg->cmdNum; i++) { + INIT_LOGI("ExecRestartCmd cmdLine->cmdContent %s ", service->restartArg->cmds[i].cmdContent); + DoCmdByIndex(service->restartArg->cmds[i].cmdIndex, service->restartArg->cmds[i].cmdContent); } - free(service->onRestart->cmdLine); - service->onRestart->cmdLine = NULL; - free(service->onRestart); + free(service->restartArg); return SERVICE_SUCCESS; } void ServiceReap(Service *service) { - if (service == NULL) { - INIT_LOGE("reap service failed! null ptr."); - return; - } + INIT_CHECK(service != NULL, return); + INIT_LOGI("Reap service %s, pid %d.", service->name, service->pid); service->pid = -1; -#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); - } - SystemWriteParam(paramName, "stopped"); -#endif + NotifyServiceChange(service->name, "stopped"); + if (service->attribute & SERVICE_ATTR_INVALID) { - INIT_LOGE("ServiceReap service %s invalid.", service->name); + INIT_LOGE("Reap service %s invalid.", service->name); return; } + + CloseServiceSocket(service->socketCfg); // 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 @@ -324,12 +298,14 @@ void ServiceReap(Service *service) service->attribute &= (~SERVICE_ATTR_NEED_STOP); return; } + // the service could be restart even if it is one-shot service } - if (service->attribute & SERVICE_ATTR_CRITICAL) { // critical + + if (service->attribute & SERVICE_ATTR_CRITICAL) { // critical if (CalculateCrashTime(service, CRITICAL_CRASH_TIME_LIMIT, CRITICAL_CRASH_COUNT_LIMIT) == false) { INIT_LOGE("Critical service \" %s \" crashed %d times, rebooting system", service->name, CRITICAL_CRASH_COUNT_LIMIT); - DoReboot("reboot"); + ExecReboot("reboot"); } } else if (!(service->attribute & SERVICE_ATTR_NEED_RESTART)) { if (CalculateCrashTime(service, CRASH_TIME_LIMIT, CRASH_COUNT_LIMIT) == false) { @@ -337,10 +313,17 @@ void ServiceReap(Service *service) return; } } - if (service->onRestart != NULL) { - INIT_CHECK_ONLY_ELOG(ExecRestartCmd(service) == SERVICE_SUCCESS, "SetOnRestart fail "); + + int ret = 0; + if (service->restartArg != NULL) { + ret = ExecRestartCmd(service); + if (ret != SERVICE_SUCCESS) { + INIT_LOGE("Failed to exec restartArg for %s", service->name); + } + } + 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/init/init_config.c b/services/init/init_config.c new file mode 100755 index 0000000..af59132 --- /dev/null +++ b/services/init/init_config.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "init.h" +#include "init_jobs.h" +#include "init_log.h" +#include "init_service_manager.h" +#include "init_utils.h" + +static void ParseAllImports(const cJSON *root); + +static void ParseInitCfgContents(const char *cfgName, const cJSON *root) +{ + INIT_ERROR_CHECK(root != NULL, return, "Root is null"); + INIT_LOGI("Parse init cfg %s ", cfgName); + + ParseAllServices(root); + // parse jobs + ParseAllJobs(root); + // parse imports + ParseAllImports(root); +} + +static int ParseInitCfg(const char *configFile, void *context) +{ + UNUSED(context); + char *fileBuf = ReadFileToBuf(configFile); + INIT_ERROR_CHECK(fileBuf != NULL, return -1, "Failed to read file content %s", configFile); + + cJSON *fileRoot = cJSON_Parse(fileBuf); + INIT_ERROR_CHECK(fileRoot != NULL, free(fileBuf); + return -1, "Failed to parse json file %s", configFile); + + ParseInitCfgContents(configFile, fileRoot); + cJSON_Delete(fileRoot); + free(fileBuf); + return 0; +} + +static void ParseAllImports(const cJSON *root) +{ + char *tmpParamValue = malloc(PARAM_VALUE_LEN_MAX + 1); + INIT_ERROR_CHECK(tmpParamValue != 0, return, "Failed to alloc memory for param"); + + cJSON *importAttr = cJSON_GetObjectItemCaseSensitive(root, "import"); + if (!cJSON_IsArray(importAttr)) { + free(tmpParamValue); + return; + } + int importAttrSize = cJSON_GetArraySize(importAttr); + for (int i = 0; i < importAttrSize; i++) { + cJSON *importItem = cJSON_GetArrayItem(importAttr, i); + if (!cJSON_IsString(importItem)) { + INIT_LOGE("Invalid type of import item. should be string"); + break; + } + char *importContent = cJSON_GetStringValue(importItem); + if (importContent == NULL) { + INIT_LOGE("cannot get import config file"); + break; + } + int ret = GetParamValue(importContent, strlen(importContent), tmpParamValue, PARAM_VALUE_LEN_MAX); + if (ret != 0) { + INIT_LOGE("cannot get value for %s", importContent); + continue; + } + INIT_LOGI("Import %s ...", tmpParamValue); + ParseInitCfg(tmpParamValue, NULL); + } + free(tmpParamValue); + return; +} + +void ReadConfig(void) +{ + // parse cfg + if (InUpdaterMode() == 0) { + ParseInitCfg(INIT_CONFIGURATION_FILE, NULL); + ReadFileInDir(OTHER_CFG_PATH, ".cfg", ParseInitCfg, NULL); + } else { + ReadFileInDir("/etc", ".cfg", ParseInitCfg, NULL); + } +} diff --git a/services/init/init_service_manager.c b/services/init/init_service_manager.c new file mode 100755 index 0000000..ccdba93 --- /dev/null +++ b/services/init/init_service_manager.c @@ -0,0 +1,584 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "init_service_manager.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cJSON.h" +#include "init.h" +#include "init_jobs.h" +#include "init_log.h" +#include "init_service_socket.h" +#include "init_utils.h" +#include "securec.h" + +// All serivce processes that init will fork+exec. +static ServiceSpace g_serviceSpace = { { &g_serviceSpace.services, &g_serviceSpace.services }, 0 }; + +#ifdef OHOS_SERVICE_DUMP +static void DumpServiceArgs(const char *info, const ServiceArgs *args) +{ + INIT_LOGD("\t\t%s count %d", info, args->count); + for (int j = 0; j < args->count; j++) { + if (args->argv[j] != NULL) { + INIT_LOGD("\t\tinfo [%d] %s", j, args->argv[j]); + } + } +} + +void DumpAllServices() +{ + INIT_LOGD("Ready to dump all services:"); + INIT_LOGD("total service number: %d", g_serviceSpace.serviceCount); + ListNode *node = g_serviceSpace.services.next; + while (node != &g_serviceSpace.services) { + Service *service = ListEntry(node, Service, node); + INIT_LOGD("\tservice name: [%s]", service->name); + INIT_LOGD("\tservice pid: [%d]", service->pid); + INIT_LOGD("\tservice crashCnt: [%d]", service->crashCnt); + INIT_LOGD("\tservice attribute: [%d]", service->attribute); + INIT_LOGD("\tservice importance: [%d]", service->importance); + INIT_LOGD("\tservice perms uID [%d]", service->servPerm.uID); + DumpServiceArgs("path arg", &service->pathArgs); + DumpServiceArgs("writepid file", &service->writePidArgs); + + INIT_LOGD("\tservice perms groupId %d", service->servPerm.gIDCnt); + for (int i = 0; i < service->servPerm.gIDCnt; i++) { + INIT_LOGD("\t\tservice perms groupId %d", service->servPerm.gIDArray[i]); + } + + INIT_LOGD("\tservice perms capability %d", service->servPerm.capsCnt); + for (int i = 0; i < service->servPerm.capsCnt; i++) { + INIT_LOGD("\t\tservice perms capability %d", service->servPerm.caps[i]); + } + if (service->restartArg != NULL) { + for (int j = 0; j < service->restartArg->cmdNum; j++) { + CmdLine *cmd = &service->restartArg->cmds[j]; + INIT_LOGD("\t\tcmd arg: %s %s", GetCmdKey(cmd->cmdIndex), cmd->cmdContent); + } + } + if (service->socketCfg != NULL) { + INIT_LOGD("\tservice socket name: %s", service->socketCfg->name); + INIT_LOGD("\tservice socket type: %d", service->socketCfg->type); + INIT_LOGD("\tservice socket uid: %d", service->socketCfg->uid); + INIT_LOGD("\tservice socket gid: %d", service->socketCfg->gid); + } + node = node->next; + } + INIT_LOGD("Dump all services finished"); +} +#endif + +static void FreeServiceArg(ServiceArgs *arg) +{ + if (arg != NULL) { + return; + } + for (int i = 0; i < arg->count; ++i) { + if (arg->argv[i] != NULL) { + free(arg->argv[i]); + arg->argv[i] = NULL; + } + } + free(arg->argv); + arg->argv = NULL; + arg->count = 0; +} + +static void FreeServiceSocket(ServiceSocket *sockopt) +{ + while (sockopt != NULL) { + ServiceSocket *tmp = sockopt; + if (tmp->sockFd >= 0) { + close(tmp->sockFd); + tmp->sockFd = -1; + } + sockopt = sockopt->next; + free(tmp); + } + return; +} + +static Service *AddService(void) +{ + Service *service = (Service *)calloc(1, sizeof(Service)); + INIT_ERROR_CHECK(service != NULL, return NULL, "Failed to malloc for service"); + ListInit(&service->node); + ListAddTail(&g_serviceSpace.services, &service->node); + g_serviceSpace.serviceCount++; + return service; +} + +static void ReleaseService(Service *service) +{ + if (service == NULL) { + return; + } + FreeServiceArg(&service->pathArgs); + FreeServiceArg(&service->writePidArgs); + + if (service->servPerm.caps != NULL) { + free(service->servPerm.caps); + service->servPerm.caps = NULL; + } + service->servPerm.capsCnt = 0; + if (service->servPerm.gIDArray != NULL) { + free(service->servPerm.gIDArray); + service->servPerm.gIDArray = NULL; + } + service->servPerm.gIDCnt = 0; + FreeServiceSocket(service->socketCfg); + + if (!ListEmpty(service->node)) { + ListRemove(&service->node); + g_serviceSpace.serviceCount--; + } + free(service); +} + +static int GetStringItem(const cJSON *json, const char *name, char *buffer, int buffLen) +{ + INIT_ERROR_CHECK(json != NULL, return SERVICE_FAILURE, "Invalid json for %s", name); + char *fieldStr = cJSON_GetStringValue(cJSON_GetObjectItem(json, name)); + INIT_ERROR_CHECK(fieldStr != NULL, return SERVICE_FAILURE, "Failed to get string for %s", name); + size_t strLen = strlen(fieldStr); + if ((strLen == 0) || (strLen > (size_t)buffLen)) { + INIT_LOGE("Invalid str filed %s for %s", fieldStr, name); + return SERVICE_FAILURE; + } + return strcpy_s(buffer, buffLen, fieldStr); +} + +cJSON *GetArrayItem(const cJSON *fileRoot, int *arrSize, const char *arrName) +{ + cJSON *arrItem = cJSON_GetObjectItemCaseSensitive(fileRoot, arrName); + if (!cJSON_IsArray(arrItem)) { + return NULL; + } + *arrSize = cJSON_GetArraySize(arrItem); + if (*arrSize <= 0) { + return NULL; + } + return arrItem; +} + +static int GetServiceArgs(const cJSON *argJson, const char *name, int maxCount, ServiceArgs *args) +{ + INIT_ERROR_CHECK(argJson != NULL, return SERVICE_FAILURE, "Invalid argJson"); + cJSON *obj = cJSON_GetObjectItem(argJson, name); + INIT_CHECK(obj != NULL, return SERVICE_FAILURE); + + int ret = cJSON_IsArray(obj); + INIT_ERROR_CHECK(ret, return SERVICE_FAILURE, "Invalid type"); + int count = cJSON_GetArraySize(obj); + INIT_ERROR_CHECK((count > 0) && (count < maxCount), return SERVICE_FAILURE, "Array size = %d is wrong", count); + + args->argv = (char **)malloc((count + 1) * sizeof(char *)); + INIT_ERROR_CHECK(args->argv != NULL, return SERVICE_FAILURE, "Failed to malloc for argv"); + for (int i = 0; i < count + 1; ++i) { + args->argv[i] = NULL; + } + args->count = count + 1; + for (int i = 0; i < count; ++i) { + char *curParam = cJSON_GetStringValue(cJSON_GetArrayItem(obj, i)); + INIT_ERROR_CHECK(curParam != NULL, return SERVICE_FAILURE, "Invalid arg %d", i); + INIT_ERROR_CHECK(strlen(curParam) <= MAX_ONE_ARG_LEN, return SERVICE_FAILURE, "Arg %s is tool long", curParam); + args->argv[i] = strdup(curParam); + INIT_ERROR_CHECK(args->argv[i] != NULL, return SERVICE_FAILURE, "Failed to dupstring %s", curParam); + } + return SERVICE_SUCCESS; +} + +static int GetUid(cJSON *json, uid_t *uid) +{ + INIT_CHECK_RETURN_VALUE(json != NULL, SERVICE_SUCCESS); + if (cJSON_IsString(json)) { + char *str = cJSON_GetStringValue(json); + INIT_ERROR_CHECK(str != NULL, return SERVICE_FAILURE, "Invalid str"); + *uid = DecodeUid(str); + } else if (cJSON_IsNumber(json)) { + *uid = (uid_t)cJSON_GetNumberValue(json); + } + if (*uid == (uid_t)(-1)) { + return SERVICE_FAILURE; + } + return SERVICE_SUCCESS; +} + +static int GetServiceGids(const cJSON *curArrItem, Service *curServ) +{ + int gidCount = 0; + cJSON *arrItem = cJSON_GetObjectItemCaseSensitive(curArrItem, GID_STR_IN_CFG); + if (!cJSON_IsArray(arrItem)) { + gidCount = 1; + } else { + gidCount = cJSON_GetArraySize(arrItem); + } + if ((gidCount == 0) || (gidCount > NGROUPS_MAX + 1)) { + INIT_LOGE("Invalid gid count %d", gidCount); + return SERVICE_FAILURE; + } + curServ->servPerm.gIDArray = (gid_t *)malloc(sizeof(gid_t) * gidCount); + INIT_ERROR_CHECK(curServ->servPerm.gIDArray != NULL, return SERVICE_FAILURE, "Failed to malloc"); + curServ->servPerm.gIDCnt = gidCount; + + gid_t gid; + if (!cJSON_IsArray(arrItem)) { + int ret = GetUid(arrItem, &gid); + INIT_ERROR_CHECK(ret == 0, return SERVICE_FAILURE, "Failed to uid"); + curServ->servPerm.gIDArray[0] = gid; + return SERVICE_SUCCESS; + } + + for (int i = 0; i < gidCount; ++i) { + cJSON *item = cJSON_GetArrayItem(arrItem, i); + int ret = GetUid(item, &gid); + if (ret != 0) { + curServ->servPerm.gIDArray[i] = 0; + continue; + } + curServ->servPerm.gIDArray[i] = gid; + } + return SERVICE_SUCCESS; +} + +static int GetServiceAttr(const cJSON *curArrItem, Service *curServ, const char *attrName, int flag, + int (*processAttr)(Service *curServ, const char *attrName, int value, int flag)) +{ + cJSON *filedJ = cJSON_GetObjectItem(curArrItem, attrName); + if (filedJ == NULL) { + return SERVICE_SUCCESS; + } + if (!cJSON_IsNumber(filedJ)) { + INIT_LOGE("%s is null or is not a number, service name is %s", attrName, curServ->name); + return SERVICE_FAILURE; + } + + int value = (int)cJSON_GetNumberValue(filedJ); + if (processAttr == NULL) { + curServ->attribute &= ~flag; + if (value == 1) { + curServ->attribute |= flag; + } + return 0; + } + return processAttr(curServ, attrName, value, flag); +} + +static int AddServiceSocket(cJSON *json, Service *service) +{ + char *opt[SOCK_OPT_NUMS] = { + NULL, + }; + if (!cJSON_IsString(json) || !cJSON_GetStringValue(json)) { + return SERVICE_FAILURE; + } + char *sockStr = cJSON_GetStringValue(json); + int num = SplitString(sockStr, " ", opt, SOCK_OPT_NUMS); + if (num != SOCK_OPT_NUMS) { + return SERVICE_FAILURE; + } + if (opt[SERVICE_SOCK_NAME] == NULL || opt[SERVICE_SOCK_TYPE] == NULL || opt[SERVICE_SOCK_PERM] == NULL || + opt[SERVICE_SOCK_UID] == NULL || opt[SERVICE_SOCK_GID] == NULL || opt[SERVICE_SOCK_SETOPT] == NULL) { + INIT_LOGE("Invalid socket opt"); + return SERVICE_FAILURE; + } + + ServiceSocket *sockopt = (ServiceSocket *)calloc(1, sizeof(ServiceSocket) + strlen(opt[SERVICE_SOCK_NAME]) + 1); + INIT_INFO_CHECK(sockopt != NULL, return SERVICE_FAILURE, "Failed to malloc for socket %s", opt[SERVICE_SOCK_NAME]); + int ret = strcpy_s(sockopt->name, strlen(opt[SERVICE_SOCK_NAME]) + 1, opt[SERVICE_SOCK_NAME]); + INIT_INFO_CHECK(ret == 0, free(sockopt); + return SERVICE_FAILURE, "Failed to copy socket name %s", opt[SERVICE_SOCK_NAME]); + + sockopt->type = SOCK_SEQPACKET; + if (strncmp(opt[SERVICE_SOCK_TYPE], "stream", strlen(opt[SERVICE_SOCK_TYPE])) == 0) { + sockopt->type = SOCK_STREAM; + } else if (strncmp(opt[SERVICE_SOCK_TYPE], "dgram", strlen(opt[SERVICE_SOCK_TYPE])) == 0) { + sockopt->type = SOCK_DGRAM; + } + sockopt->perm = strtoul(opt[SERVICE_SOCK_PERM], 0, OCTAL_BASE); + sockopt->uid = DecodeUid(opt[SERVICE_SOCK_UID]); + sockopt->gid = DecodeUid(opt[SERVICE_SOCK_GID]); + if (sockopt->uid == (uid_t)-1 || sockopt->gid == (uid_t)-1) { + free(sockopt); + INIT_LOGE("Invalid uid %d or gid %d", sockopt->uid, sockopt->gid); + return SERVICE_FAILURE; + } + sockopt->passcred = false; + if (strncmp(opt[SERVICE_SOCK_SETOPT], "passcred", strlen(opt[SERVICE_SOCK_SETOPT])) == 0) { + sockopt->passcred = true; + } + sockopt->next = NULL; + if (service->socketCfg == NULL) { + service->socketCfg = sockopt; + } else { + sockopt->next = service->socketCfg->next; + service->socketCfg->next = sockopt; + } + return SERVICE_SUCCESS; +} + +static int ParseServiceSocket(const cJSON *curArrItem, Service *curServ) +{ + int sockCnt = 0; + cJSON *filedJ = GetArrayItem(curArrItem, &sockCnt, "socket"); + INIT_CHECK(filedJ != NULL && sockCnt > 0, return SERVICE_FAILURE); + int ret = 0; + curServ->socketCfg = NULL; + for (int i = 0; i < sockCnt; ++i) { + cJSON *sockJ = cJSON_GetArrayItem(filedJ, i); + ret = AddServiceSocket(sockJ, curServ); + if (ret != 0) { + break; + } + } + return ret; +} + +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", "dynamic" + }; + if (curService == NULL) { + return SERVICE_FAILURE; + } + cJSON *child = curService->child; + if (child == NULL) { + return SERVICE_FAILURE; + } + while (child != NULL) { + int i = 0; + int keyListSize = ARRAY_LENGTH(cfgServiceKeyList); + for (; i < keyListSize; i++) { + if (strcmp(child->string, cfgServiceKeyList[i]) == 0) { + break; + } + } + if (i < keyListSize) { + child = child->next; + } else { + INIT_LOGE("CheckServiceKeyName, key name %s is not found. error.", child->string); + return SERVICE_FAILURE; + } + } + return SERVICE_SUCCESS; +} + +static int ParseOneService(const cJSON *curItem, Service *service) +{ + if (curItem == NULL || service == NULL) { + return SERVICE_FAILURE; + } + int ret = GetStringItem(curItem, "name", service->name, MAX_SERVICE_NAME); + INIT_ERROR_CHECK(ret == 0, return SERVICE_FAILURE, "Failed to get service name"); + ret = GetServiceArgs(curItem, "path", MAX_PATH_ARGS_CNT, &service->pathArgs); + INIT_ERROR_CHECK(ret == 0, return SERVICE_FAILURE, "Failed to get path for service %s", service->name); + if ((service->pathArgs.count > 0) && IsForbidden(service->pathArgs.argv[0])) { + INIT_LOGE("Service %s is forbidden.", service->name); + return SERVICE_FAILURE; + } + ret = GetUid(cJSON_GetObjectItem(curItem, UID_STR_IN_CFG), &service->servPerm.uID); + INIT_ERROR_CHECK(ret == 0, return SERVICE_FAILURE, "Failed to get uid for service %s", service->name); + ret = GetServiceGids(curItem, service); + INIT_ERROR_CHECK(ret == 0, return SERVICE_FAILURE, "Failed to get gid for service %s", service->name); + + ret = GetServiceAttr(curItem, service, ONCE_STR_IN_CFG, SERVICE_ATTR_ONCE, NULL); + INIT_ERROR_CHECK(ret == 0, return SERVICE_FAILURE, "Failed to get once flag for service %s", service->name); + ret = GetServiceAttr(curItem, service, IMPORTANT_STR_IN_CFG, SERVICE_ATTR_IMPORTANT, SetImportantValue); + INIT_ERROR_CHECK(ret == 0, return SERVICE_FAILURE, "Failed to get import flag for service %s", service->name); + ret = GetServiceAttr(curItem, service, CRITICAL_STR_IN_CFG, SERVICE_ATTR_CRITICAL, NULL); + INIT_ERROR_CHECK(ret == 0, return SERVICE_FAILURE, "Failed to get critical flag for service %s", service->name); + ret = GetServiceAttr(curItem, service, DISABLED_STR_IN_CFG, SERVICE_ATTR_DISABLED, NULL); + INIT_ERROR_CHECK(ret == 0, return SERVICE_FAILURE, "Failed to get disabled flag for service %s", service->name); + ret = GetServiceAttr(curItem, service, CONSOLE_STR_IN_CFG, SERVICE_ATTR_CONSOLE, NULL); + INIT_ERROR_CHECK(ret == 0, return SERVICE_FAILURE, "Failed to get console for service %s", service->name); + + ret = GetServiceArgs(curItem, "writepid", MAX_WRITEPID_FILES, &service->writePidArgs); + INIT_CHECK_ONLY_ELOG(ret == 0, "No writepid arg for service %s", service->name); + ret = GetServiceCaps(curItem, service); + INIT_ERROR_CHECK(ret == 0, return SERVICE_FAILURE, "Failed to get caps for service %s", service->name); + ret = GetDynamicService(curItem, service); + INIT_ERROR_CHECK(ret == 0, return SERVICE_FAILURE, "Failed to get dynamic flag for service %s", service->name); + return ret; +} + +void ParseAllServices(const cJSON *fileRoot) +{ + int servArrSize = 0; + cJSON *serviceArr = GetArrayItem(fileRoot, &servArrSize, SERVICES_ARR_NAME_IN_JSON); + 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); + + Service tmpService = {}; + for (int i = 0; i < servArrSize; ++i) { + cJSON *curItem = cJSON_GetArrayItem(serviceArr, i); + int ret = GetStringItem(curItem, "name", tmpService.name, MAX_SERVICE_NAME); + if (ret != 0) { + INIT_LOGE("Failed to get service name %s", tmpService.name); + continue; + } + if (CheckServiceKeyName(curItem) != SERVICE_SUCCESS) { // invalid service + INIT_LOGE("Invalid service name %s", tmpService.name); + continue; + } + Service *service = GetServiceByName(tmpService.name); + if (service != NULL) { + INIT_LOGE("Service name %s has been exist", tmpService.name); + continue; + } + service = AddService(); + if (service == NULL) { + INIT_LOGE("Failed to create service name %s", tmpService.name); + continue; + } + + ret = ParseOneService(curItem, service); + if (ret != SERVICE_SUCCESS) { + ReleaseService(service); + continue; + } + ret = ParseServiceSocket(curItem, service); + if (ret != SERVICE_SUCCESS) { + FreeServiceSocket(service->socketCfg); + service->socketCfg = NULL; + } + ret = GetCmdLinesFromJson(cJSON_GetObjectItem(curItem, "onrestart"), &service->restartArg); + if (ret != SERVICE_SUCCESS) { + service->restartArg = NULL; + } + INIT_LOGD("service[%d] name=%s, uid=%d, critical=%d, disabled=%d", + i, service->name, service->servPerm.uID, + (service->attribute & SERVICE_ATTR_CRITICAL) ? 1 : 0, + (service->attribute & SERVICE_ATTR_DISABLED) ? 1 : 0); + } +} + +void StartServiceByName(const char *servName, bool checkDynamic) +{ + Service *service = GetServiceByName(servName); + INIT_ERROR_CHECK(service != NULL, return, "Cannot find service %s.", servName); + + if (checkDynamic && (service->attribute & SERVICE_ATTR_DYNAMIC)) { + INIT_LOGI("%s is dynamic service.", servName); + return; + } + if (ServiceStart(service) != SERVICE_SUCCESS) { + INIT_LOGE("Service %s start failed!", servName); + } + return; +} + +void StopServiceByName(const char *servName) +{ + Service *service = GetServiceByName(servName); + INIT_ERROR_CHECK(service != NULL, return, "Cannot find service %s.", servName); + + if (ServiceStop(service) != SERVICE_SUCCESS) { + INIT_LOGE("Service %s start failed!", servName); + } + return; +} + +void StopAllServices(int flags) +{ + ListNode *node = g_serviceSpace.services.next; + while (node != &g_serviceSpace.services) { + Service *service = ListEntry(node, Service, node); + service->attribute |= flags; + int ret = ServiceStop(service); + if (ret != SERVICE_SUCCESS) { + INIT_LOGE("Service %s stop failed!", service->name); + } + node = node->next; + } +} + +Service *GetServiceByPid(pid_t pid) +{ + ListNode *node = g_serviceSpace.services.next; + while (node != &g_serviceSpace.services) { + Service *service = ListEntry(node, Service, node); + if (service->pid == pid) { + return service; + } + node = node->next; + } + return NULL; +} + +Service *GetServiceByName(const char *servName) +{ + ListNode *node = g_serviceSpace.services.next; + while (node != &g_serviceSpace.services) { + Service *service = ListEntry(node, Service, node); + if (strcmp(service->name, servName) == 0) { + return service; + } + node = node->next; + } + return NULL; +} diff --git a/services/init/init_service_socket.c b/services/init/init_service_socket.c new file mode 100755 index 0000000..11d2bdb --- /dev/null +++ b/services/init/init_service_socket.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "init_service_socket.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "init_log.h" +#include "init_service.h" +#include "securec.h" + +#define HOS_SOCKET_DIR "/dev/unix/socket" +#define HOS_SOCKET_ENV_PREFIX "OHOS_SOCKET_" +#define MAX_SOCKET_ENV_PREFIX_LEN 64 +#define MAX_SOCKET_FD_LEN 16 + +static int GetSocketAddr(struct sockaddr_un *addr, const char *name) +{ + bzero(addr, sizeof(struct sockaddr_un)); + addr->sun_family = AF_UNIX; + size_t addrLen = sizeof(addr->sun_path); + int ret = snprintf_s(addr->sun_path, addrLen, addrLen - 1, HOS_SOCKET_DIR "/%s", name); + INIT_ERROR_CHECK(ret >= 0, return -1, "Failed to format addr %s", name); + return 0; +} + +static int CreateSocket(ServiceSocket *sockopt) +{ + INIT_ERROR_CHECK(sockopt != NULL, return SERVICE_FAILURE, "Invalid socket opt"); + if (sockopt->sockFd >= 0) { + close(sockopt->sockFd); + sockopt->sockFd = -1; + } + sockopt->sockFd = socket(PF_UNIX, sockopt->type, 0); + INIT_ERROR_CHECK(sockopt->sockFd >= 0, return -1, "socket fail %d ", errno); + + struct sockaddr_un addr; + int ret = GetSocketAddr(&addr, sockopt->name); + INIT_ERROR_CHECK(ret == 0, return -1, "Failed to format addr %s", sockopt->name); + + do { + ret = -1; + if (access(addr.sun_path, F_OK)) { + INIT_LOGI("%s already exist, remove it", addr.sun_path); + unlink(addr.sun_path); + } + if (sockopt->passcred) { + int on = 1; + if (setsockopt(sockopt->sockFd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) { + break; + } + } + if (bind(sockopt->sockFd, (struct sockaddr *)&addr, sizeof(addr))) { + INIT_LOGE("Create socket for service %s failed: %d", sockopt->name, errno); + break; + } + if (lchown(addr.sun_path, sockopt->uid, sockopt->gid)) { + INIT_LOGE("lchown fail %d ", errno); + break; + } + if (fchmodat(AT_FDCWD, addr.sun_path, sockopt->perm, AT_SYMLINK_NOFOLLOW)) { + INIT_LOGE("fchmodat fail %d ", errno); + break; + } + ret = 0; + } while (0); + if (ret != 0) { + close(sockopt->sockFd); + unlink(addr.sun_path); + return -1; + } + INIT_LOGI("CreateSocket %s success", sockopt->name); + return sockopt->sockFd; +} + +static int SetSocketEnv(int fd, const char *name) +{ + INIT_ERROR_CHECK(name != NULL, return SERVICE_FAILURE, "Invalid name"); + char pubName[MAX_SOCKET_ENV_PREFIX_LEN] = { 0 }; + char val[MAX_SOCKET_FD_LEN] = { 0 }; + if (snprintf_s(pubName, sizeof(pubName), sizeof(pubName) - 1, HOS_SOCKET_ENV_PREFIX "%s", name) < 0) { + return -1; + } + if (snprintf_s(val, sizeof(val), sizeof(val) - 1, "%d", fd) < 0) { + return -1; + } + int ret = setenv(pubName, val, 1); + if (ret < 0) { + INIT_LOGE("setenv fail %d ", errno); + return -1; + } + fcntl(fd, F_SETFD, 0); + return 0; +} + +int CreateServiceSocket(ServiceSocket *sockopt) +{ + INIT_CHECK(sockopt != NULL, return 0); + ServiceSocket *tmpSock = sockopt; + while (tmpSock != NULL) { + int fd = CreateSocket(tmpSock); + if (fd < 0) { + return -1; + } + int ret = SetSocketEnv(fd, tmpSock->name); + if (ret < 0) { + return -1; + } + tmpSock = tmpSock->next; + } + return 0; +} + +void CloseServiceSocket(ServiceSocket *sockopt) +{ + INIT_CHECK(sockopt != NULL, return); + struct sockaddr_un addr; + ServiceSocket *tmpSock = sockopt; + while (tmpSock != NULL) { + if (sockopt->sockFd >= 0) { + close(sockopt->sockFd); + sockopt->sockFd = -1; + } + if (GetSocketAddr(&addr, sockopt->name) == 0) { + unlink(addr.sun_path); + } + tmpSock = tmpSock->next; + } + return; +} \ No newline at end of file diff --git a/services/init/lite/init.c b/services/init/lite/init.c new file mode 100755 index 0000000..b3374c8 --- /dev/null +++ b/services/init/lite/init.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "init.h" +#include "init_log.h" +#include "init_jobs.h" +#ifndef __LINUX__ +#include "init_stage.h" +#endif +#include "parameter.h" +#include "securec.h" + +static void PrintSysInfo(void) +{ + const char *sysInfo = GetVersionId(); + if (sysInfo != NULL) { + INIT_LOGE("%s", sysInfo); + return; + } +} + +void SystemInit(void) +{ + SignalInit(); +} + +void LogInit(void) +{ + +} + +void SystemPrepare(void) +{ + PrintSysInfo(); +} + +void SystemConfig(void) +{ + // read config + ReadConfig(); + + // dump config +#ifdef OHOS_SERVICE_DUMP + DumpAllServices(); +#endif + + // execute init + DoJob("pre-init"); +#ifndef __LINUX__ + TriggerStage(EVENT1, EVENT1_WAITTIME, QS_STAGE1); +#endif + + DoJob("init"); +#ifndef __LINUX__ + TriggerStage(EVENT2, EVENT2_WAITTIME, QS_STAGE2); +#endif + + DoJob("post-init"); +#ifndef __LINUX__ + TriggerStage(EVENT3, EVENT3_WAITTIME, QS_STAGE3); + InitStageFinished(); +#endif + ReleaseAllJobs(); +} + +void SystemRun(void) +{ + 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(); + } +} \ No newline at end of file diff --git a/services/init/lite/init_cmds.c b/services/init/lite/init_cmds.c new file mode 100755 index 0000000..5534777 --- /dev/null +++ b/services/init/lite/init_cmds.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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 "init.h" +#include "init_cmds.h" +#include "init_log.h" +#include "init_utils.h" +#include "securec.h" + +int GetParamValue(const char *symValue, unsigned int symLen, char *paramValue, unsigned int paramLen) +{ + return (strncpy_s(paramValue, paramLen, symValue, symLen) == EOK) ? 0 : -1; +} + +static void DoExec(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(ctx); + // 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); + return; + } + if (pid == 0) { + struct CmdArgs *subCtx = GetCmdArg(cmdContent, " ", SUPPORT_MAX_ARG_FOR_EXEC); + if (subCtx == NULL || subCtx->argv[0] == NULL) { + INIT_LOGE("DoExec: invalid arguments :%s", cmdContent); + _exit(0x7f); + } + int ret = execve(subCtx->argv[0], subCtx->argv, NULL); + if (ret == -1) { + INIT_LOGE("DoExec: execute \"%s\" failed: %d.", cmdContent, errno); + } + FreeCmdArg(subCtx); + _exit(0x7f); + } + return; +} + +static const struct CmdTable g_cmdTable[] = { { "exec ", 1, 10, DoExec } }; + +const struct CmdTable *GetCmdTable(int *number) +{ + *number = (int)ARRAY_LENGTH(g_cmdTable); + return g_cmdTable; +} diff --git a/services/src/init_jobs.c b/services/init/lite/init_jobs.c old mode 100644 new mode 100755 similarity index 56% rename from services/src/init_jobs.c rename to services/init/lite/init_jobs.c index 1bac3d7..ab09c6a --- a/services/src/init_jobs.c +++ b/services/init/lite/init_jobs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Huawei Device Co., Ltd. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,7 +12,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #include "init_jobs.h" #include @@ -25,28 +24,31 @@ #define JOBS_ARR_NAME_IN_JSON "jobs" #define CMDS_ARR_NAME_IN_JSON "cmds" -#define MAX_JOBS_COUNT 100 +#define MAX_JOBS_COUNT 100 -static Job* g_jobs = NULL; +static Job *g_jobs = NULL; static int g_jobCnt = 0; void DumpAllJobs(void) { - INIT_LOGD("Ready to dump all jobs:"); + INIT_LOGD("Start to dump all jobs..."); for (int i = 0; i < g_jobCnt; i++) { INIT_LOGD("\tjob name: %s", g_jobs[i].name); + if (g_jobs[i].cmdLines == NULL) { + continue; + } INIT_LOGD("\tlist all commands:"); - for (int j = 0; j < g_jobs[i].cmdLinesCnt; j++) { - INIT_LOGD("\t\tcommand name : %s, command options: %s", - g_jobs[i].cmdLines[j].name, g_jobs[i].cmdLines[j].cmdContent); + for (int j = 0; j < g_jobs[i].cmdLines->cmdNum; j++) { + CmdLine *cmd = &g_jobs[i].cmdLines->cmds[j]; + INIT_LOGD("\t\tcommand: %s %s", GetCmdKey(cmd->cmdIndex), cmd->cmdContent); } } - INIT_LOGD("To dump all jobs finished"); + INIT_LOGD("Finish dump all jobs"); } -static int GetJobName(const cJSON* jobItem, Job* resJob) +static int GetJobName(const cJSON *jobItem, Job *resJob) { - char* jobNameStr = cJSON_GetStringValue(cJSON_GetObjectItem(jobItem, "name")); + char *jobNameStr = cJSON_GetStringValue(cJSON_GetObjectItem(jobItem, "name")); if (jobNameStr == NULL) { return 0; } @@ -59,7 +61,7 @@ static int GetJobName(const cJSON* jobItem, Job* resJob) return 1; } -static void ParseJob(const cJSON* jobItem, Job* resJob) +static void ParseJob(const cJSON *jobItem, Job *resJob) { if (!GetJobName(jobItem, resJob)) { INIT_LOGE("get JobName failed"); @@ -67,52 +69,27 @@ static void ParseJob(const cJSON* jobItem, Job* resJob) return; } - cJSON* cmdsItem = cJSON_GetObjectItem(jobItem, CMDS_ARR_NAME_IN_JSON); + cJSON *cmdsItem = cJSON_GetObjectItem(jobItem, CMDS_ARR_NAME_IN_JSON); if (!cJSON_IsArray(cmdsItem)) { INIT_LOGE("job %s is not an arrary", resJob->name); return; } - - int cmdLinesCnt = cJSON_GetArraySize(cmdsItem); - if (cmdLinesCnt <= 0) { // empty job, no cmd - INIT_LOGE("empty job \"%s\"", resJob->name); + int ret = GetCmdLinesFromJson(cmdsItem, &resJob->cmdLines); + if (ret != 0) { + INIT_LOGE("ParseJob, faild to get cmds for job!"); return; } - - INIT_LOGD("job = %s, cmdLineCnt = %d", resJob->name, cmdLinesCnt); - if (cmdLinesCnt > MAX_CMD_CNT_IN_ONE_JOB) { - INIT_LOGE("ParseAllJobs, too many cmds[cnt %d] in one job, it should not exceed %d.", - cmdLinesCnt, MAX_CMD_CNT_IN_ONE_JOB); - return; - } - - resJob->cmdLines = (CmdLine*)malloc(cmdLinesCnt * sizeof(CmdLine)); - if (resJob->cmdLines == NULL) { - INIT_LOGE("allocate memory for command line failed"); - return; - } - - if (memset_s(resJob->cmdLines, cmdLinesCnt * sizeof(CmdLine), 0, cmdLinesCnt * sizeof(CmdLine)) != EOK) { - free(resJob->cmdLines); - resJob->cmdLines = NULL; - return; - } - resJob->cmdLinesCnt = cmdLinesCnt; - - for (int i = 0; i < cmdLinesCnt; ++i) { - char* cmdLineStr = cJSON_GetStringValue(cJSON_GetArrayItem(cmdsItem, i)); - ParseCmdLine(cmdLineStr, &(resJob->cmdLines[i])); - } + return; } -void ParseAllJobs(const cJSON* fileRoot) +void ParseAllJobs(const cJSON *fileRoot) { if (fileRoot == NULL) { INIT_LOGE("ParseAllJobs, input fileRoot is NULL!"); return; } - cJSON* jobArr = cJSON_GetObjectItemCaseSensitive(fileRoot, JOBS_ARR_NAME_IN_JSON); + cJSON *jobArr = cJSON_GetObjectItemCaseSensitive(fileRoot, JOBS_ARR_NAME_IN_JSON); if (!cJSON_IsArray(jobArr)) { INIT_LOGE("ParseAllJobs, job item is not array!"); return; @@ -125,13 +102,13 @@ void ParseAllJobs(const cJSON* fileRoot) return; } - Job* retJobs = (Job*)realloc(g_jobs, sizeof(Job) * (g_jobCnt + jobArrSize)); + Job *retJobs = (Job *)realloc(g_jobs, sizeof(Job) * (g_jobCnt + jobArrSize)); if (retJobs == NULL) { INIT_LOGE("ParseAllJobs, malloc failed! job arrSize %d.", jobArrSize); return; } - Job* tmp = retJobs + g_jobCnt; + Job *tmp = retJobs + g_jobCnt; if (memset_s(tmp, sizeof(Job) * jobArrSize, 0, sizeof(Job) * jobArrSize) != EOK) { INIT_LOGE("ParseAllJobs, memset_s failed."); free(retJobs); @@ -140,14 +117,14 @@ void ParseAllJobs(const cJSON* fileRoot) } for (int i = 0; i < jobArrSize; ++i) { - cJSON* jobItem = cJSON_GetArrayItem(jobArr, i); + cJSON *jobItem = cJSON_GetArrayItem(jobArr, i); ParseJob(jobItem, &(tmp[i])); } g_jobs = retJobs; g_jobCnt += jobArrSize; } -void DoJob(const char* jobName) +void DoJob(const char *jobName) { if (jobName == NULL) { INIT_LOGE("DoJob, input jobName NULL!"); @@ -157,9 +134,12 @@ void DoJob(const char* jobName) INIT_LOGD("Call job with name %s", jobName); for (int i = 0; i < g_jobCnt; ++i) { if (strncmp(jobName, g_jobs[i].name, strlen(g_jobs[i].name)) == 0) { - CmdLine* cmdLines = g_jobs[i].cmdLines; - for (int j = 0; j < g_jobs[i].cmdLinesCnt; ++j) { - DoCmd(&(cmdLines[j])); + CmdLines *cmdLines = g_jobs[i].cmdLines; + if (cmdLines == NULL) { + continue; + } + for (int j = 0; j < cmdLines->cmdNum; ++j) { + DoCmdByIndex(cmdLines->cmds[j].cmdIndex, cmdLines->cmds[j].cmdContent); } } } @@ -174,13 +154,10 @@ void ReleaseAllJobs(void) for (int i = 0; i < g_jobCnt; ++i) { if (g_jobs[i].cmdLines != NULL) { free(g_jobs[i].cmdLines); - g_jobs[i].cmdLines = NULL; - g_jobs[i].cmdLinesCnt = 0; } } free(g_jobs); g_jobs = NULL; g_jobCnt = 0; -} - +} \ No newline at end of file diff --git a/services/init/lite/init_reboot.c b/services/init/lite/init_reboot.c new file mode 100755 index 0000000..b041723 --- /dev/null +++ b/services/init/lite/init_reboot.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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 "init.h" +#include "init_log.h" + +void ExecReboot(const char *value) +{ + UNUSED(value); + int ret = reboot(RB_AUTOBOOT); + if (ret != 0) { + INIT_LOGE("reboot failed! syscall ret %d, err %d.", ret, errno); + } + return; +} diff --git a/services/init/lite/init_service.c b/services/init/lite/init_service.c new file mode 100755 index 0000000..2395e1a --- /dev/null +++ b/services/init/lite/init_service.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "init_service.h" + +#include +#include +#include +#include + +#include "init.h" +#include "init_log.h" +#include "init_service_manager.h" +#include "securec.h" + +void NotifyServiceChange(const char *serviceName, const char *change) +{ + UNUSED(serviceName); + UNUSED(change); +} + +int IsForbidden(const char *fieldStr) +{ + size_t fieldLen = strlen(fieldStr); + size_t forbidStrLen = strlen(BIN_SH_NOT_ALLOWED); + if (fieldLen == forbidStrLen) { + if (strncmp(fieldStr, BIN_SH_NOT_ALLOWED, fieldLen) == 0) { + return 1; + } + return 0; + } else if (fieldLen > forbidStrLen) { + // "/bin/shxxxx" is valid but "/bin/sh xxxx" is invalid + if (strncmp(fieldStr, BIN_SH_NOT_ALLOWED, forbidStrLen) == 0) { + if (fieldStr[forbidStrLen] == ' ') { + return 1; + } + } + return 0; + } else { + return 0; + } +} + +int SetImportantValue(Service *service, const char *attrName, int value, int flag) +{ + UNUSED(attrName); + UNUSED(flag); + INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "Set service attr failed! null ptr."); + if (value != 0) { + service->attribute |= SERVICE_ATTR_IMPORTANT; + } + return SERVICE_SUCCESS; +} + +int ServiceExec(const Service *service) +{ + INIT_ERROR_CHECK(service != NULL && service->pathArgs.count > 0, + return SERVICE_FAILURE, "Exec service failed! null ptr."); + INIT_LOGI("service->name is %s ", service->name); + char *env[] = { "LD_LIBRARY_PATH=/storage/app/libs", NULL }; + if (execve(service->pathArgs.argv[0], service->pathArgs.argv, env) != 0) { + INIT_LOGE("service %s execve failed! err %d.", service->name, errno); + return errno; + } + return SERVICE_SUCCESS; +} \ No newline at end of file diff --git a/services/init/lite/init_signal_handler.c b/services/init/lite/init_signal_handler.c new file mode 100755 index 0000000..f78d407 --- /dev/null +++ b/services/init/lite/init_signal_handler.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include + +#include "init_adapter.h" +#include "init_log.h" +#include "init_service_manager.h" + +void ReapService(Service *service) +{ + if (service == NULL) { + return; + } + if (service->attribute & SERVICE_ATTR_IMPORTANT) { + // important process exit, need to reboot system + service->pid = -1; + StopAllServices(0); + RebootSystem(); + } + ServiceReap(service); +} + +static void SigHandler(int sig) +{ + switch (sig) { + case SIGCHLD: { + pid_t sigPID; + int procStat = 0; + while (1) { + sigPID = waitpid(-1, &procStat, WNOHANG); + if (sigPID <= 0) { + break; + } + CheckWaitPid(sigPID); + ReapService(GetServiceByPid(sigPID)); + } + break; + } + case SIGTERM: { + StopAllServices(0); + break; + } + default: + break; + } +} + +void SignalInit(void) +{ + struct sigaction act; + act.sa_handler = SigHandler; + act.sa_flags = SA_RESTART; + (void)sigfillset(&act.sa_mask); + + sigaction(SIGCHLD, &act, NULL); + sigaction(SIGTERM, &act, NULL); +} \ No newline at end of file diff --git a/services/include/init_read_cfg.h b/services/init/main.c old mode 100644 new mode 100755 similarity index 50% rename from services/include/init_read_cfg.h rename to services/init/main.c index 4cb57e1..e97e11e --- a/services/include/init_read_cfg.h +++ b/services/init/main.c @@ -12,26 +12,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include +#include "init.h" +#include "init_log.h" -#ifndef BASE_STARTUP_INITLITE_READ_CFG_H -#define BASE_STARTUP_INITLITE_READ_CFG_H - -#ifdef __cplusplus -#if __cplusplus -extern "C" { -#endif -#endif -#define INIT_CONFIGURATION_FILE "/etc/init.cfg" -#define MAX_PATH_ARGS_CNT 20 -#define MAX_ONE_ARG_LEN 200 // max length of one param/path - -void InitReadCfg(); -void ParseInitCfg(const char *configFile); - -#ifdef __cplusplus -#if __cplusplus +static const pid_t INIT_PROCESS_PID = 1; +int main(int argc, char* const argv[]) +{ + int isSecondStage = 0; + if (argc == 2 && (strcmp(argv[1], "--second-stage") == 0)) { + isSecondStage = 1; + } + if (getpid() != INIT_PROCESS_PID) { + INIT_LOGE("Process id error %d!", getpid()); + return 0; + } + LogInit(); + if (isSecondStage == 0) { + SystemPrepare(); + } + SystemInit(); + SystemExecuteRcs(); + SystemConfig(); + SystemRun(); + return 0; } -#endif -#endif - -#endif // BASE_STARTUP_INITLITE_READ_CFG_H diff --git a/services/src/device.c b/services/init/standard/device.c old mode 100644 new mode 100755 similarity index 91% rename from services/src/device.c rename to services/init/standard/device.c index 43ec88a..1a548f5 --- a/services/src/device.c +++ b/services/init/standard/device.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Huawei Device Co., Ltd. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,14 +12,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #include "device.h" + #include #include #include #include #include #include + #include "init_log.h" #define DEFAULT_RW_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) @@ -62,9 +63,6 @@ void MountBasicFs(void) void CreateDeviceNode(void) { - if (mknod("/dev/kmsg", S_IFCHR | DEFAULT_NO_AUTHORITY_MODE, makedev(MEM_MAJOR, DEV_KMSG_MINOR)) != 0) { - INIT_LOGE("Create /dev/kmsg device node failed. %s", strerror(errno)); - } if (mknod("/dev/null", S_IFCHR | DEFAULT_RW_MODE, makedev(MEM_MAJOR, DEV_NULL_MINOR)) != 0) { INIT_LOGE("Create /dev/null device node failed. %s", strerror(errno)); } diff --git a/services/init/standard/init.c b/services/init/standard/init.c new file mode 100755 index 0000000..65aea93 --- /dev/null +++ b/services/init/standard/init.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "init.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "init_log.h" +#include "init_mount.h" +#include "init_param.h" +#include "init_utils.h" +#include "securec.h" +#include "switch_root.h" + +void SystemInit(void) +{ + SignalInit(); + MakeDirRecursive("/dev/unix/socket", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); +} + +void LogInit(void) +{ + CloseStdio(); + int ret = mknod("/dev/kmsg", S_IFCHR | S_IWUSR | S_IRUSR, + makedev(MEM_MAJOR, DEV_KMSG_MINOR)); + if (ret == 0) { + OpenLogDevice(); + } +} + +static pid_t StartUeventd(void) +{ + char *const argv[] = { + "/bin/ueventd", + NULL, + }; + pid_t pid = fork(); + if (pid < 0) { + INIT_LOGE("Failed to fork child process"); + } + if (pid == 0) { + if (execv(argv[0], argv) != 0) { + INIT_LOGE("service %s execve failed! err %d.", argv[0], errno); + } + _exit(0x7f); // 0x7f: user specified + } + return pid; +} + +static void StartInitSecondStage(void) +{ + pid_t ueventPid = StartUeventd(); + if (ueventPid < 0) { + INIT_LOGE("Failed to start ueventd"); + abort(); + } + if (MountRequriedPartitions() < 0) { + // If mount required partitions failure. + // There is no necessary to continue. + // Just abort + INIT_LOGE("Mount requried partitions failed"); + abort(); + } + // Kill ueventd, because init second stage will start it again. + (void)kill(ueventPid, SIGKILL); + // The init process in ramdisk has done its job. + // It's ready to switch to system partition. + // The system partition mounted in first stage to /usr + // Because the directory /system is in use. we cannot use it. + // After switch root. /usr will become new root. + SwitchRoot("/usr"); + // Execute init second stage + char *const args[] = { + "/bin/init", + "--second-stage", + NULL, + }; + if (execv("/bin/init", args) != 0) { + INIT_LOGE("Failed to exec \"/bin/init\", err = %d", errno); + exit(-1); + } +} + +void SystemPrepare(void) +{ + MountBasicFs(); + // Make sure init log always output to /dev/kmsg. + EnableDevKmsg(); + CreateDeviceNode(); + // Only ohos normal system support + // two stages of init. + // If we are in updater mode, only one stage of init, + if (InUpdaterMode() == 0) { + StartInitSecondStage(); + } +} + +void SystemConfig(void) +{ + InitParamService(); + // parse parameters + LoadDefaultParams("/system/etc/param/ohos_const", LOAD_PARAM_NORMAL); + LoadDefaultParams("/vendor/etc/param", LOAD_PARAM_NORMAL); + LoadDefaultParams("/system/etc/param", LOAD_PARAM_ONLY_ADD); + + // read config + ReadConfig(); + INIT_LOGI("Parse init config file done."); + + // dump config +#ifdef OHOS_SERVICE_DUMP + DumpAllServices(); + DumpParametersAndTriggers(); +#endif + + // execute init + PostTrigger(EVENT_TRIGGER_BOOT, "pre-init", strlen("pre-init")); + PostTrigger(EVENT_TRIGGER_BOOT, "init", strlen("init")); + PostTrigger(EVENT_TRIGGER_BOOT, "post-init", strlen("post-init")); +} + +void SystemRun(void) +{ + StartParamService(); +} diff --git a/services/init/standard/init_cmds.c b/services/init/standard/init_cmds.c new file mode 100755 index 0000000..df90153 --- /dev/null +++ b/services/init/standard/init_cmds.c @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "init_cmds.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "init.h" +#include "init_jobs.h" +#include "init_log.h" +#include "init_param.h" +#include "init_service_manager.h" +#include "init_utils.h" +#include "fs_manager/fs_manager.h" +#include "securec.h" + +int GetParamValue(const char *symValue, unsigned int symLen, char *paramValue, unsigned int paramLen) +{ + if ((symValue == NULL) || (paramValue == NULL) || (paramLen == 0)) { + return -1; + } + char tmpName[PARAM_NAME_LEN_MAX] = { 0 }; + int ret = 0; + uint32_t curr = 0; + char *start = (char *)symValue; + char *end = (char *)symValue + symLen; + do { + char *begin = strchr(start, '$'); + if (begin == NULL || begin >= end) { // not has '$' copy the original string + ret = strncpy_s(paramValue + curr, paramLen - curr, start, symLen); + INIT_ERROR_CHECK(ret == EOK, return -1, "Failed to copy start %s", start); + break; + } else { + ret = memcpy_s(paramValue + curr, paramLen - curr, start, begin - start); + INIT_ERROR_CHECK(ret == 0, return -1, "Failed to copy first value %s", symValue); + curr += begin - start; + } + while (*begin != '{') { + begin++; + } + begin++; + char *left = strchr(begin, '}'); + if (left == NULL) { + return -1; + } + // copy param name + ret = strncpy_s(tmpName, PARAM_NAME_LEN_MAX, begin, left - begin); + INIT_ERROR_CHECK(ret == EOK, return -1, "Invalid param name %s", symValue); + uint32_t valueLen = paramLen - curr; + ret = SystemReadParam(tmpName, paramValue + curr, &valueLen); + INIT_ERROR_CHECK(ret == 0, return -1, "Failed to get param %s", tmpName); + curr += valueLen; + left++; + if ((unsigned int)(left - symValue) >= symLen) { + break; + } + start = left; + } while (1); + return 0; +} + +static void DoIfup(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(cmdContent); + 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"); + 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); + return; + } + + if (ioctl(fd, SIOCGIFFLAGS, &interface) >= 0) { + 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); +} + +// format insmod [-f] [options] +static void DoInsmod(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(cmdContent); + int index = 0; + int flags = 0; + char *fileName = NULL; + if (ctx->argc > index) { + fileName = ctx->argv[index]; + index++; + } + INIT_ERROR_CHECK(fileName != NULL, return, "Can not find file name from param %s", cmdContent); + INIT_LOGD("Install mode %s ", fileName); + char *realPath = GetRealPath(fileName); + INIT_ERROR_CHECK(realPath != NULL, return, "Can not get real file name from param %s", cmdContent); + if (ctx->argc > 1 && ctx->argv[1] != NULL && strcmp(ctx->argv[1], "-f") == 0) { // [-f] + flags = MODULE_INIT_IGNORE_VERMAGIC | MODULE_INIT_IGNORE_MODVERSIONS; + index++; + } + char *options = BuildStringFromCmdArg(ctx, index); // [options] + int fd = open(realPath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); + if (fd >= 0) { + int rc = syscall(__NR_finit_module, fd, options, flags); + if (rc == -1) { + INIT_LOGE("Failed to install mode for %s failed options %s err: %d", realPath, options, errno); + } + } + if (options != NULL) { + free(options); + } + if (fd >= 0) { + close(fd); + } + free(realPath); + return; +} + +static void DoSetParam(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(cmdContent); + INIT_LOGD("set param name: %s, value %s ", ctx->argv[0], ctx->argv[1]); + SystemWriteParam(ctx->argv[0], ctx->argv[1]); +} + +static void DoLoadPersistParams(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(ctx); + INIT_LOGD("load persist params : %s", cmdContent); + LoadPersistParams(); +} + +static void DoTriggerCmd(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(ctx); + INIT_LOGD("DoTrigger :%s", cmdContent); + DoTriggerExec(cmdContent); +} + +static void DoLoadDefaultParams(const struct CmdArgs *ctx, const char *cmdContent) +{ + int mode = 0; + if (ctx->argc > 1 && strcmp(ctx->argv[1], "onlyadd") == 0) { + mode = LOAD_PARAM_ONLY_ADD; + } + INIT_LOGD("DoLoadDefaultParams args : %s %d", cmdContent, mode); + LoadDefaultParams(ctx->argv[0], mode); +} + +static void DoExec(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(cmdContent); + UNUSED(ctx); + // 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); + return; + } + if (pid == 0) { + const struct CmdArgs *subCtx = GetCmdArg(cmdContent, " ", SUPPORT_MAX_ARG_FOR_EXEC); + if (subCtx == NULL || subCtx->argv[0] == NULL) { + INIT_LOGE("DoExec: invalid arguments :%s", cmdContent); + _exit(0x7f); + } + int ret = execv(subCtx->argv[0], subCtx->argv); + if (ret == -1) { + INIT_LOGE("DoExec: execute \"%s\" failed: %d.", cmdContent, errno); + } + FreeCmdArg((struct CmdArgs *)subCtx); + _exit(0x7f); + } + return; +} + +static void DoSymlink(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(cmdContent); + // format: symlink /xxx/xxx/xxx /xxx/xxx/xxx + int ret = symlink(ctx->argv[0], ctx->argv[1]); + if (ret != 0 && errno != EEXIST) { + INIT_LOGE("DoSymlink: link %s to %s failed: %d", ctx->argv[0], ctx->argv[1], errno); + } +} + +static mode_t GetDeviceMode(const char *deviceStr) +{ + switch (*deviceStr) { + case 'b': + case 'B': + return S_IFBLK; + case 'c': + case 'C': + return S_IFCHR; + case 'f': + case 'F': + return S_IFIFO; + default: + return -1; + } +} + +static void DoMakeNode(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(cmdContent); + // format: mknod path b 0644 1 9 + const int deviceTypePos = 1; + const int authorityPos = 2; + const int majorDevicePos = 3; + const int minorDevicePos = 4; + const int decimal = 10; + const int octal = 8; + if (!access(ctx->argv[1], F_OK)) { + INIT_LOGE("DoMakeNode failed, path has not sexisted"); + return; + } + mode_t deviceMode = GetDeviceMode(ctx->argv[deviceTypePos]); + errno = 0; + unsigned int major = strtoul(ctx->argv[majorDevicePos], NULL, decimal); + INIT_CHECK_ONLY_ELOG(errno != ERANGE, "Failed to strtoul %s", ctx->argv[majorDevicePos]); + unsigned int minor = strtoul(ctx->argv[minorDevicePos], NULL, decimal); + INIT_CHECK_ONLY_ELOG(errno != ERANGE, "Failed to strtoul %s", ctx->argv[minorDevicePos]); + mode_t authority = strtoul(ctx->argv[authorityPos], NULL, octal); + INIT_CHECK_ONLY_ELOG(errno != ERANGE, "Failed to strtoul %s", ctx->argv[authorityPos]); + 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); + } +} + +static void DoMakeDevice(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(cmdContent); + // format: makedev major minor + const int decimal = 10; + errno = 0; + unsigned int major = strtoul(ctx->argv[0], NULL, decimal); + INIT_CHECK_ONLY_ELOG(errno != ERANGE, "Failed to strtoul %s", ctx->argv[0]); + unsigned int minor = strtoul(ctx->argv[1], NULL, decimal); + INIT_CHECK_ONLY_ELOG(errno != ERANGE, "Failed to strtoul %s", ctx->argv[1]); + dev_t deviceId = makedev(major, minor); + if (deviceId < 0) { + INIT_LOGE("DoMakedevice \" %s \" failed :%d ", cmdContent, errno); + } +} + +static void DoMountFstabFile(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(cmdContent); + INIT_LOGI("Mount partitions from fstab file \" %s \"", ctx->argv[0]); + int rc = MountAllWithFstabFile(ctx->argv[0], 0); + if (rc < 0) { + INIT_LOGE("Run command mount_fstab failed"); + } else { + INIT_LOGI("Mount partitions from fstab done"); + } +} + +static void DoUmountFstabFile(const struct CmdArgs *ctx, const char *cmdContent) +{ + UNUSED(cmdContent); + INIT_LOGI("Umount partitions from fstab file \" %s \"", ctx->argv[0]); + int rc = UmountAllWithFstabFile(ctx->argv[0]); + if (rc < 0) { + INIT_LOGE("Run command umount_fstab failed"); + } else { + INIT_LOGI("Umount partitions from fstab done"); + } +} + +static const struct CmdTable CMD_TABLE[] = { + { "exec ", 1, 10, DoExec }, + { "mknode ", 1, 5, DoMakeNode }, + { "makedev ", 2, 2, DoMakeDevice }, + { "symlink ", 2, 2, DoSymlink }, + { "trigger ", 1, 1, DoTriggerCmd }, + { "insmod ", 1, 10, DoInsmod }, + { "setparam ", 2, 2, DoSetParam }, + { "load_persist_params ", 1, 1, DoLoadPersistParams }, + { "load_param ", 1, 2, DoLoadDefaultParams }, + { "ifup ", 1, 1, DoIfup }, + { "mount_fstab ", 1, 1, DoMountFstabFile }, + { "umount_fstab ", 1, 1, DoUmountFstabFile }, +}; + +const struct CmdTable *GetCmdTable(int *number) +{ + *number = (int)ARRAY_LENGTH(CMD_TABLE); + return CMD_TABLE; +} diff --git a/services/include/init_reboot.h b/services/init/standard/init_jobs.c old mode 100644 new mode 100755 similarity index 73% rename from services/include/init_reboot.h rename to services/init/standard/init_jobs.c index 181d811..18d3ff1 --- a/services/include/init_reboot.h +++ b/services/init/standard/init_jobs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Huawei Device Co., Ltd. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,9 +13,10 @@ * limitations under the License. */ -#ifndef INIT_REBOOT_H -#define INIT_REBOOT_H +#include "init_jobs.h" +#include "init_param.h" -void DoReboot(const char *value); - -#endif +void ParseAllJobs(const cJSON *fileRoot) +{ + ParseTriggerConfig(fileRoot); +} \ No newline at end of file diff --git a/services/init/standard/init_mount.c b/services/init/standard/init_mount.c new file mode 100755 index 0000000..f608c75 --- /dev/null +++ b/services/init/standard/init_mount.c @@ -0,0 +1,65 @@ +/* + * 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 "device.h" +#include "fs_manager/fs_manager.h" +#include "init.h" +#include "init_cmds.h" +#include "init_log.h" +#include "securec.h" + +// This function will malloc memory. +// Do not forget to free it after used. +static char *GetExpandFileName(const char *fileName) +{ + if (fileName == NULL) { + return NULL; + } + size_t expandSize = strlen(fileName) + PARAM_VALUE_LEN_MAX + 1; + char *expandName = (char *)calloc(sizeof(char), expandSize); + if (expandName == NULL) { + INIT_LOGE("Failed to allocate memory for file name \" %s \"", fileName); + return NULL; + } + int ret = GetParamValue(fileName, strlen(fileName), expandName, expandSize); + INIT_ERROR_CHECK(ret == 0, free(expandName); + return NULL, "Failed to get value for %s", fileName); + return expandName; +} + +int MountRequriedPartitions(void) +{ + const char *fstabFiles[] = {"/etc/fstab.required", NULL}; + int i = 0; + int rc = -1; + while (fstabFiles[i] != NULL) { + char *fstabFile = GetExpandFileName(fstabFiles[i]); + if (fstabFile != NULL) { + if (access(fstabFile, F_OK) == 0) { + INIT_LOGI("Mount required partition from %s", fstabFile); + rc = MountAllWithFstabFile(fstabFile, 1); + } else { + INIT_LOGE("Cannot access fstab file \" %s \"", fstabFile); + } + free(fstabFile); + fstabFile = NULL; + } + if (rc == 0) { + break; + } + i++; + } + return rc; +} \ No newline at end of file diff --git a/services/include/init_import.h b/services/init/standard/init_mount.h old mode 100644 new mode 100755 similarity index 80% rename from services/include/init_import.h rename to services/init/standard/init_mount.h index 5def1ef..a2f9a3f --- a/services/include/init_import.h +++ b/services/init/standard/init_mount.h @@ -12,10 +12,8 @@ * 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(const cJSON *root); - -#endif +#ifndef BASE_STARTUP_INITLITE_MOUNT_H +#define BASE_STARTUP_INITLITE_MOUNT_H +int MountRequriedPartitions(void); +#endif \ No newline at end of file diff --git a/services/init/standard/init_reboot.c b/services/init/standard/init_reboot.c new file mode 100755 index 0000000..0d44131 --- /dev/null +++ b/services/init/standard/init_reboot.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include + +#include "init_log.h" +#include "init_service.h" +#include "init_service_manager.h" +#include "init_utils.h" +#include "securec.h" + +#define MAX_VALUE_LENGTH 500 +#define MAX_COMMAND_SIZE 20 +#define MAX_UPDATE_SIZE 100 + +struct RBMiscUpdateMessage { + char command[MAX_COMMAND_SIZE]; + char update[MAX_UPDATE_SIZE]; +}; + +static int RBMiscWriteUpdaterMessage(const char *path, const struct RBMiscUpdateMessage *boot) +{ + char *realPath = GetRealPath(path); + if (realPath == NULL) { + return -1; + } + int ret = 0; + FILE *fp = fopen(realPath, "rb+"); + if (fp != NULL) { + size_t writeLen = fwrite(boot, sizeof(struct RBMiscUpdateMessage), 1, fp); + if (writeLen != 1) { + INIT_LOGE("Failed to write misc for reboot"); + ret = -1; + } + } else { + ret = -1; + INIT_LOGE("Failed to open %s", path); + } + free(realPath); + realPath = NULL; + (void)fclose(fp); + return ret; +} + +static int RBMiscReadUpdaterMessage(const char *path, struct RBMiscUpdateMessage *boot) +{ + char *realPath = GetRealPath(path); + if (realPath == NULL) { + return -1; + } + + int ret = 0; + FILE *fp = fopen(realPath, "rb"); + if (fp != NULL) { + size_t readLen = fread(boot, 1, sizeof(struct RBMiscUpdateMessage), fp); + if (readLen <= 0) { + ret = -1; + INIT_LOGE("Failed to read misc for reboot"); + } + } else { + ret = -1; + INIT_LOGE("Failed to open %s", path); + } + free(realPath); + realPath = NULL; + (void)fclose(fp); + return ret; +} + +static int GetMountStatusForMountPoint(const char *mountPoint) +{ + const int bufferMaxSize = 512; + char buffer[bufferMaxSize]; + size_t n; + const char *mountFile = "/proc/mounts"; + FILE *fp = fopen(mountFile, "r"); + if (fp == NULL) { + return 1; + } + + while (fgets(buffer, sizeof(buffer) - 1, fp) != NULL) { + n = strlen(buffer); + if (buffer[n - 1] == '\n') { + buffer[n - 1] = '\0'; + } + if (strstr(buffer, mountPoint) != NULL) { + (void)fclose(fp); + return 1; + } + } + (void)fclose(fp); + return 0; +} + +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; + int ret = RBMiscReadUpdaterMessage(miscFile, &msg); + INIT_ERROR_CHECK(ret == 0, return -1, "Failed to get misc info for %s.", cmd); + + if (boot != NULL) { + 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; + } else { + ret = memset_s(msg.command, MAX_COMMAND_SIZE, 0, MAX_COMMAND_SIZE); + INIT_ERROR_CHECK(ret == 0, return -1, "Failed to format cmd for %s.", cmd); + } + + if ((cmdExt != NULL) && (valueData != NULL) && (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; + } + + if (RBMiscWriteUpdaterMessage(miscFile, &msg) == 0) { + return reboot(RB_AUTOBOOT); + } + return -1; +} + +static int CheckRebootParam(const char *valueData) +{ + if (valueData == NULL) { + return 0; + } + static const char *cmdParams[] = { + "shutdown", "updater", "updater:", "flash", "flash:", "NoArgument", "bootloader" + }; + size_t i = 0; + for (; i < ARRAY_LENGTH(cmdParams); i++) { + if (strncmp(valueData, cmdParams[i], strlen(cmdParams[i])) == 0) { + break; + } + } + if (i >= ARRAY_LENGTH(cmdParams)) { + return -1; + } + return 0; +} + +void ExecReboot(const char *value) +{ + INIT_ERROR_CHECK(value != NULL && strlen(value) <= MAX_VALUE_LENGTH, return, "Invalid arg"); + const char *valueData = NULL; + if (strncmp(value, "reboot,", strlen("reboot,")) == 0) { + valueData = value + strlen("reboot,"); + } else if (strcmp(value, "reboot") != 0) { + INIT_LOGE("Reboot value = %s, must started with reboot", value); + return; + } + if (CheckRebootParam(valueData) != 0) { + INIT_LOGE("Invalid arg %s for reboot.", value); + return; + } + + StopAllServices(SERVICE_ATTR_INVALID); + sync(); + if (GetMountStatusForMountPoint("/vendor") != 0 && umount("/vendor") != 0) { + INIT_LOGE("Failed to umount vendor. errno = %d.", errno); + } + if (GetMountStatusForMountPoint("/data") != 0) { + if (umount("/data") != 0 && umount2("/data", MNT_FORCE) != 0) { + INIT_LOGE("Failed umount data. errno = %d.", errno); + } + } else { + INIT_LOGE("Failed to get mount point \"/data\""); + } + + int ret = 0; + if (valueData == NULL) { + ret = CheckAndRebootToUpdater(NULL, "reboot", NULL, NULL); + } 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, "flash", strlen("flash")) == 0) { + ret = CheckAndRebootToUpdater(valueData, "flash", "flash:", "boot_flash"); + } + INIT_LOGI("Reboot %s %s.", value, (ret == 0) ? "success" : "fail"); + return; +} diff --git a/services/init/standard/init_service.c b/services/init/standard/init_service.c new file mode 100755 index 0000000..533addb --- /dev/null +++ b/services/init/standard/init_service.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "init_service.h" + +#include +#include +#include +#include +#include + +#include "init.h" +#include "init_log.h" +#include "init_param.h" +#include "securec.h" + +#define MIN_IMPORTANT_LEVEL (-20) +#define MAX_IMPORTANT_LEVEL 19 + +void NotifyServiceChange(const char *serviceName, const char *change) +{ + char paramName[PARAM_NAME_LEN_MAX] = { 0 }; + if (snprintf_s(paramName, PARAM_NAME_LEN_MAX, PARAM_NAME_LEN_MAX - 1, "init.svc.%s", serviceName) < 0) { + INIT_LOGE("snprintf_s paramName error %d ", errno); + } + SystemWriteParam(paramName, change); +} + +int IsForbidden(const char *fieldStr) +{ + UNUSED(fieldStr); + return 0; +} + +int SetImportantValue(Service *service, const char *attrName, int value, int flag) +{ + UNUSED(attrName); + UNUSED(flag); + INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "Set service attr failed! null ptr."); + if (value >= MIN_IMPORTANT_LEVEL && value <= MAX_IMPORTANT_LEVEL) { // -20~19 + service->attribute |= SERVICE_ATTR_IMPORTANT; + service->importance = value; + } else { + INIT_LOGE("Importance level = %d, is not between -20 and 19, error", value); + return SERVICE_FAILURE; + } + return SERVICE_SUCCESS; +} + +int ServiceExec(const Service *service) +{ + INIT_ERROR_CHECK(service != NULL && service->pathArgs.count > 0, + return SERVICE_FAILURE, "Exec service failed! null ptr."); + 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 + } + } + // L2 Can not be reset env + if (execv(service->pathArgs.argv[0], service->pathArgs.argv) != 0) { + INIT_LOGE("service %s execve failed! err %d.", service->name, errno); + } + return SERVICE_SUCCESS; +} \ No newline at end of file diff --git a/services/src/init_signal_handler.c b/services/init/standard/init_signal_handler.c old mode 100644 new mode 100755 similarity index 62% rename from services/src/init_signal_handler.c rename to services/init/standard/init_signal_handler.c index 81fdf42..9f70ada --- a/services/src/init_signal_handler.c +++ b/services/init/standard/init_signal_handler.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Huawei Device Co., Ltd. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,45 +12,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -#include "init_signal_handler.h" - #include #include #include -#ifdef __LINUX__ -#include -#include -#endif /* __LINUX__ */ +#include "init_adapter.h" #include "init_log.h" #include "init_service_manager.h" - -#ifndef OHOS_LITE #include "uv.h" -#endif -#ifdef __LINUX__ -static pid_t g_waitPid = -1; -static sem_t* g_waitSem = NULL; - -void SignalRegWaitSem(pid_t waitPid, sem_t* waitSem) -{ - g_waitPid = waitPid; - g_waitSem = waitSem; -} - -static void CheckWaitPid(pid_t sigPID) -{ - if (g_waitPid == sigPID && g_waitSem != NULL) { - if (sem_post(g_waitSem) != 0) { - INIT_LOGE("CheckWaitPid, sem_post failed, errno %d.", errno); - } - g_waitPid = -1; - g_waitSem = NULL; - } -} -#endif /* __LINUX__ */ +uv_signal_t g_sigchldHandler; +uv_signal_t g_sigtermHandler; static void SigHandler(int sig) { @@ -63,29 +35,22 @@ static void SigHandler(int sig) if (sigPID <= 0) { break; } - -#ifndef OHOS_LITE // check child process exit status if (WIFSIGNALED(procStat)) { INIT_LOGE("Child process %d exit with signal: %d", sigPID, WTERMSIG(procStat)); } - if (WIFEXITED(procStat)) { - INIT_LOGE("Child process %d exit with code : %d", sigPID, WEXITSTATUS((unsigned int)procStat)); + INIT_LOGE("Child process %d exit with code : %d", sigPID, WEXITSTATUS(procStat)); } -#endif - INIT_LOGI("SigHandler, SIGCHLD received, sigPID = %d.", sigPID); -#ifdef __LINUX__ CheckWaitPid(sigPID); -#endif /* __LINUX__ */ - ReapServiceByPID((int)sigPID); + ServiceReap(GetServiceByPid(sigPID)); } break; } case SIGTERM: { INIT_LOGI("SigHandler, SIGTERM received."); - StopAllServices(); + StopAllServices(0); break; } default: @@ -94,27 +59,12 @@ static void SigHandler(int sig) } } -#ifdef OHOS_LITE -void SignalInitModule() -{ - struct sigaction act; - act.sa_handler = SigHandler; - act.sa_flags = SA_RESTART; - (void)sigfillset(&act.sa_mask); - - sigaction(SIGCHLD, &act, NULL); - sigaction(SIGTERM, &act, NULL); -} -#else // L2 or above, use signal event in libuv -uv_signal_t g_sigchldHandler; -uv_signal_t g_sigtermHandler; - -static void UVSignalHandler(uv_signal_t* handle, int signum) +static void UVSignalHandler(uv_signal_t *handle, int signum) { SigHandler(signum); } -void SignalInitModule() +void SignalInit(void) { int ret = uv_signal_init(uv_default_loop(), &g_sigchldHandler); int ret1 = uv_signal_init(uv_default_loop(), &g_sigtermHandler); @@ -129,5 +79,4 @@ void SignalInitModule() if (uv_signal_start(&g_sigtermHandler, UVSignalHandler, SIGTERM) != 0) { INIT_LOGW("start SIGTERM handler failed"); } -} -#endif +} \ No newline at end of file diff --git a/services/init/standard/switch_root.c b/services/init/standard/switch_root.c new file mode 100755 index 0000000..c2a5bf9 --- /dev/null +++ b/services/init/standard/switch_root.c @@ -0,0 +1,163 @@ +/* + * 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 "switch_root.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "init_log.h" +#include "init_utils.h" +#include "fs_manager/fs_manager.h" +#include "securec.h" + +static void FreeOldRoot(DIR *dir, dev_t dev) +{ + if (dir == NULL) { + return; + } + int dfd = dirfd(dir); + bool isDir = false; + struct dirent *de = NULL; + while ((de = readdir(dir)) != NULL) { + if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) { + continue; + } + + if (de->d_type == DT_DIR || de->d_type == DT_UNKNOWN) { + struct stat st = {}; + if (fstatat(dfd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) { + INIT_LOGE("Failed to get stat of %s", de->d_name); + continue; + } + + if (st.st_dev != dev) { + continue; // Not the same device, ignore. + } + + if (S_ISDIR(st.st_mode)) { + int fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY); + isDir = true; + if (fd >= 0) { + DIR *subDir = fdopendir(fd); + if (subDir != NULL) { + FreeOldRoot(subDir, dev); + closedir(subDir); + } else { + close(fd); + } + } + } + } + if (unlinkat(dfd, de->d_name, isDir ? AT_REMOVEDIR : 0) < 0) { + INIT_LOGE("Failed to unlink %s, err = %d", de->d_name, errno); + } + } +} + +static int MountToNewTarget(const char *target) +{ + if (target == NULL || *target == '\0') { + return -1; + } + Fstab *fstab = ReadFstabFromFile("/proc/mounts", true); + if (fstab == NULL) { + INIT_LOGE("Fatal error. Read mounts info from \" /proc/mounts \" failed"); + return -1; + } + + for (FstabItem *item = fstab->head; item != NULL; item = item->next) { + const char *mountPoint = item->mountPoint; + if (mountPoint == NULL || strcmp(mountPoint, "/") == 0 || + strcmp(mountPoint, target) == 0) { + continue; + } + char newMountPoint[PATH_MAX] = {0}; + if (snprintf_s(newMountPoint, PATH_MAX, PATH_MAX - 1, "%s%s", target, mountPoint) == -1) { + INIT_LOGW("Cannot build new mount point for old mount point \" %s \"", mountPoint); + // Just ignore this one or return error? + continue; + } + INIT_LOGI("new mount point is: %s", newMountPoint); + if (mount(mountPoint, newMountPoint, NULL, MS_MOVE, NULL) < 0) { + INIT_LOGE("Failed to mount moving %s to %s, err = %d", mountPoint, newMountPoint, errno); + // If one mount entry cannot move to new mountpoint, umount it. + umount2(mountPoint, MNT_FORCE); + continue; + } + } + ReleaseFstab(fstab); + fstab = NULL; + return 0; +} + +// Switch root from ramdisk to system +int SwitchRoot(const char *newRoot) +{ + if (newRoot == NULL || *newRoot == '\0') { + errno = EINVAL; + INIT_LOGE("Fatal error. Try to switch to new root with invalid new mount point"); + return -1; + } + + struct stat oldRootStat = {}; + if (stat("/", &oldRootStat) != 0) { + INIT_LOGE("Failed to get old root \"/\" stat"); + return -1; + } + DIR *oldRoot = opendir("/"); + if (oldRoot == NULL) { + INIT_LOGE("Failed to open root dir \"/\""); + return -1; + } + struct stat newRootStat = {}; + if (stat(newRoot, &newRootStat) != 0) { + INIT_LOGE("Failed to get new root \" %s \" stat", newRoot); + return -1; + } + + if (oldRootStat.st_dev == newRootStat.st_dev) { + INIT_LOGW("Try to switch root in same device, skip switching root"); + return 0; + } + if (MountToNewTarget(newRoot) < 0) { + INIT_LOGE("Failed to move mount to new root \" %s \" stat", newRoot); + return -1; + } + // OK, we've done move mount. + // Now mount new root. + if (chdir(newRoot) < 0) { + INIT_LOGE("Failed to change directory to %s, err = %d", newRoot, errno); + return -1; + } + + if (mount(newRoot, "/", NULL, MS_MOVE, NULL) < 0) { + INIT_LOGE("Failed to mount moving %s to %s, err = %d", newRoot, "/", errno); + return -1; + } + + if (chroot(".") < 0) { + INIT_LOGE("Failed to change root directory"); + return -1; + } + FreeOldRoot(oldRoot, oldRootStat.st_dev); + closedir(oldRoot); + oldRoot = NULL; + return 0; +} diff --git a/services/log/BUILD.gn b/services/log/BUILD.gn old mode 100644 new mode 100755 diff --git a/services/log/init_log.c b/services/log/init_log.c old mode 100644 new mode 100755 index 36504d5..c408049 --- a/services/log/init_log.c +++ b/services/log/init_log.c @@ -14,7 +14,6 @@ */ #include "init_log.h" - #include #include #include @@ -34,22 +33,15 @@ static InitLogLevel g_logLevel = INIT_INFO; static const char *LOG_LEVEL_STR[] = { "DEBUG", "INFO", "WARNING", "ERROR", "FATAL" }; -void SetLogLevel(InitLogLevel logLevel) +void SetInitLogLevel(InitLogLevel logLevel) { g_logLevel = logLevel; } #ifdef OHOS_LITE -static LogLevel g_hiLogLevel = LOG_INFO; - -void SetHiLogLevel(LogLevel logLevel) +void InitToHiLog(InitLogLevel logLevel, const char *fmt, ...) { - g_hiLogLevel = logLevel; -} - -void InitToHiLog(LogLevel logLevel, const char *fmt, ...) -{ - if (logLevel < g_hiLogLevel) { + if (logLevel < g_logLevel) { return; } @@ -84,7 +76,7 @@ void EnableDevKmsg(void) if (fd < 0) { return; } - const char *kmsgStatus = "on"; + char *kmsgStatus = "on"; write(fd, kmsgStatus, strlen(kmsgStatus) + 1); close(fd); fd = -1; diff --git a/services/log/init_log.h b/services/log/init_log.h old mode 100644 new mode 100755 index 2c0de5c..825c480 --- a/services/log/init_log.h +++ b/services/log/init_log.h @@ -19,13 +19,6 @@ #include #include #include -#ifdef OHOS_LITE -#include "hilog/log.h" -#else -#ifdef INIT_AGENT -#include "hilog/log.h" -#endif -#endif #ifdef __cplusplus #if __cplusplus @@ -41,6 +34,8 @@ typedef enum InitLogLevel { INIT_FATAL } InitLogLevel; +void SetInitLogLevel(InitLogLevel logLevel); + #ifdef LABEL #define INIT_LOG_TAG LABEL #endif @@ -50,22 +45,22 @@ typedef enum InitLogLevel { #endif #ifdef OHOS_LITE +#include "hilog/log.h" #undef LOG_DOMAIN #define LOG_DOMAIN 0xD000719 -#define INIT_LOGD(fmt, ...) InitToHiLog(LOG_DEBUG, "%s : "fmt, (__FUNCTION__), ##__VA_ARGS__) -#define INIT_LOGI(fmt, ...) InitToHiLog(LOG_INFO, "%s : "fmt, (__FUNCTION__), ##__VA_ARGS__) -#define INIT_LOGW(fmt, ...) InitToHiLog(LOG_WARN, "%s : "fmt, (__FUNCTION__), ##__VA_ARGS__) -#define INIT_LOGE(fmt, ...) InitToHiLog(LOG_ERROR, "%s : "fmt, (__FUNCTION__), ##__VA_ARGS__) -#define INIT_LOGF(fmt, ...) InitToHiLog(LOG_FATAL, "%s : "fmt, (__FUNCTION__), ##__VA_ARGS__) +#define INIT_LOGD(fmt, ...) InitToHiLog(INIT_DEBUG, "%s : "fmt, (__FUNCTION__), ##__VA_ARGS__) +#define INIT_LOGI(fmt, ...) InitToHiLog(INIT_INFO, "%s : "fmt, (__FUNCTION__), ##__VA_ARGS__) +#define INIT_LOGW(fmt, ...) InitToHiLog(INIT_WARN, "%s : "fmt, (__FUNCTION__), ##__VA_ARGS__) +#define INIT_LOGE(fmt, ...) InitToHiLog(INIT_ERROR, "%s : "fmt, (__FUNCTION__), ##__VA_ARGS__) +#define INIT_LOGF(fmt, ...) InitToHiLog(INIT_FATAL, "%s : "fmt, (__FUNCTION__), ##__VA_ARGS__) -#define STARTUP_LOGD(LABEL, fmt, ...) InitToHiLog(LABEL, LOG_DEBUG, "%s : "fmt, (__FUNCTION__), ##__VA_ARGS__) -#define STARTUP_LOGI(LABEL, fmt, ...) InitToHiLog(LABEL, LOG_INFO, "%s : "fmt, (__FUNCTION__), ##__VA_ARGS__) -#define STARTUP_LOGE(LABEL, fmt, ...) InitToHiLog(LABEL, LOG_ERROR, "%s : "fmt, (__FUNCTION__), ##__VA_ARGS__) +#define STARTUP_LOGD(LABEL, fmt, ...) InitToHiLog(LABEL, INIT_DEBUG, "%s : "fmt, (__FUNCTION__), ##__VA_ARGS__) +#define STARTUP_LOGI(LABEL, fmt, ...) InitToHiLog(INIT_INFO, "%s : "fmt, (__FUNCTION__), ##__VA_ARGS__) +#define STARTUP_LOGE(LABEL, fmt, ...) InitToHiLog(INIT_ERROR, "%s : "fmt, (__FUNCTION__), ##__VA_ARGS__) -void InitToHiLog(LogLevel logLevel, const char *fmt, ...); -void SetHiLogLevel(LogLevel logLevel); +void InitToHiLog(InitLogLevel logLevel, const char *fmt, ...); #else #define FILE_NAME (strrchr((__FILE__), '/') ? strrchr((__FILE__), '/') + 1 : (__FILE__)) @@ -80,7 +75,11 @@ void SetHiLogLevel(LogLevel logLevel); #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 +#ifndef LABEL +#define LABEL "ParamAgent" +#endif +#include "hilog/log.h" #define PARAM_AGENT_LOG_PATH "/data/init_agent/init_agent.log" #define STARTUP_LOGD(LABEL, fmt, ...) \ @@ -107,7 +106,6 @@ void SetHiLogLevel(LogLevel logLevel); #endif void InitLog(InitLogLevel logLevel, const char *fileName, int line, const char *kLevel, const char *fmt, ...); -void SetLogLevel(InitLogLevel logLevel); void OpenLogDevice(void); void EnableDevKmsg(void); #endif diff --git a/services/param/BUILD.gn b/services/param/BUILD.gn old mode 100644 new mode 100755 index 3249c34..ce86867 --- a/services/param/BUILD.gn +++ b/services/param/BUILD.gn @@ -14,6 +14,7 @@ import("//build/ohos.gni") declare_args() { param_security = "dac" + param_test = "false" } ohos_prebuilt_etc("param_watcher.rc") { @@ -28,7 +29,8 @@ ohos_prebuilt_etc("param_watcher.rc") { ohos_static_library("param_service") { sources = [ - "//base/startup/init_lite/services/src/list.c", + "//base/startup/init_lite/services/utils/init_utils.c", + "//base/startup/init_lite/services/utils/list.c", "adapter/param_libuvadp.c", "adapter/param_persistadp.c", "manager/param_manager.c", @@ -47,6 +49,7 @@ ohos_static_library("param_service") { "adapter", "//base/startup/init_lite/services/include/param", "//base/startup/init_lite/services/include", + "//base/startup/init_lite/services/init/include", "//base/startup/init_lite/services/log", "//third_party/libuv/include", "//third_party/cJSON", @@ -54,6 +57,10 @@ ohos_static_library("param_service") { defines = [ "PARAM_SUPPORT_SAVE_PERSIST" ] + if (param_test == "true") { + defines += [ "PARAM_TEST" ] + } + if (param_security == "selinux") { sources += [ "adapter/param_selinux.c" ] defines += [ "PARAM_SUPPORT_SELINUX" ] @@ -72,6 +79,7 @@ ohos_static_library("param_service") { ohos_shared_library("param_client") { sources = [ + "//base/startup/init_lite/services/utils/init_utils.c", "client/param_request.c", "manager/param_manager.c", "manager/param_message.c", @@ -98,11 +106,19 @@ ohos_shared_library("param_client") { defines += [ "PARAM_SUPPORT_DAC" ] } + if (param_test == "true") { + defines += [ "PARAM_TEST" ] + } + deps = [ "//base/startup/init_lite/services/log:agent_log", "//third_party/bounds_checking_function:libsec_static", ] external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + install_images = [ + "system", + "updater", + ] part_name = "init" } @@ -197,19 +213,25 @@ ohos_executable("param") { "//base/update/updateservice/interfaces/innerkits/include", ] - defines = [ - "PARAM_TEST", - "INIT_AGENT", - ] + defines = [ "INIT_AGENT" ] deps = [ "//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", ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + + if (param_test == "true") { + defines += [ "PARAM_TEST" ] + deps += [ "//base/startup/init_lite/services/param:param_watcheragent" ] + } else { + install_images = [ + "system", + "updater", + ] + } install_enable = true part_name = "init" } diff --git a/services/param/adapter/param_dac.c b/services/param/adapter/param_dac.c index 9f59dde..8be0406 100755 --- a/services/param/adapter/param_dac.c +++ b/services/param/adapter/param_dac.c @@ -18,11 +18,11 @@ #include #include +#include "init_utils.h" #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) @@ -170,6 +170,7 @@ static int GetParamSecurityLabel(SecurityLabelFunc label, const char *path, void if ((stat(path, &st) == 0) && !S_ISDIR(st.st_mode)) { return ProcessParamFile(path, &cxt); } + PARAM_LOGD("GetParamSecurityLabel %s ", path); return ReadFileInDir(path, ".para.dac", ProcessParamFile, &cxt); } diff --git a/services/param/adapter/param_libuvadp.c b/services/param/adapter/param_libuvadp.c index dce7492..7f4e949 100755 --- a/services/param/adapter/param_libuvadp.c +++ b/services/param/adapter/param_libuvadp.c @@ -15,7 +15,6 @@ #include "param_libuvadp.h" #include -#define LABEL "Libuvadp" static LibuvWorkSpace libuv = { NULL }; static const uint32_t RECV_BUFFER_MAX = 5 * 1024; diff --git a/services/param/adapter/param_persistadp.c b/services/param/adapter/param_persistadp.c index 023130d..11a309c 100755 --- a/services/param/adapter/param_persistadp.c +++ b/services/param/adapter/param_persistadp.c @@ -21,8 +21,6 @@ #include "param_persist.h" #include "param_utils.h" -#define LABEL "PERSIST_ADP" - typedef struct { void *context; PersistParamGetPtr persistParamGet; @@ -59,6 +57,12 @@ static int LoadPersistParam(PersistParamGetPtr persistParamGet, void *context) return 0; } +static int SavePersistParam(const char *name, const char *value) +{ + PARAM_LOGD("SavePersistParam %s=%s", name, value); + return 0; +} + static int BatchSavePersistParamBegin(PERSIST_SAVE_HANDLE *handle) { FILE *fp = fopen(PARAM_PERSIST_SAVE_TMP_PATH, "w"); @@ -88,7 +92,7 @@ static void BatchSavePersistParamEnd(PERSIST_SAVE_HANDLE handle) int RegisterPersistParamOps(PersistParamOps *ops) { PARAM_CHECK(ops != NULL, return -1, "Invalid ops"); - ops->save = NULL; + ops->save = SavePersistParam; ops->load = LoadPersistParam; ops->batchSaveBegin = BatchSavePersistParamBegin; ops->batchSave = BatchSavePersistParam; diff --git a/services/param/adapter/param_selinux.c b/services/param/adapter/param_selinux.c index 8b5c9d8..ecd25c8 100755 --- a/services/param/adapter/param_selinux.c +++ b/services/param/adapter/param_selinux.c @@ -15,10 +15,10 @@ #include +#include "init_utils.h" #include "param_security.h" #include "param_utils.h" -#define LABEL "PARAM_SELINUX" #define SELINUX_LABEL_LEN 128 typedef struct SELinuxSecurityLabel { ParamSecurityLabel securityLabel; diff --git a/services/param/client/param_request.c b/services/param/client/param_request.c old mode 100644 new mode 100755 index fba5486..b7606f8 --- a/services/param/client/param_request.c +++ b/services/param/client/param_request.c @@ -12,8 +12,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #include "param_request.h" + #include #include #include @@ -26,7 +26,7 @@ #define INVALID_SOCKET (-1) #define INIT_PROCESS_PID 1 -#define LABEL "Client" + static const uint32_t RECV_BUFFER_MAX = 5 * 1024; static atomic_uint g_requestId = ATOMIC_VAR_INIT(1); @@ -114,7 +114,7 @@ static int StartRequest(int *fd, ParamMessage *request, int timeout) 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); + ret = ConntectServer(clientFd, CLIENT_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)); @@ -291,6 +291,12 @@ int SystemTraversalParameter( void SystemDumpParameters(int verbose) { InitParamClient(); + // check default dac + ParamHandle handle = 0; + int ret = ReadParamWithCheck(&g_clientSpace.paramSpace, "#", DAC_READ, &handle); + if (ret != PARAM_CODE_NOT_FOUND && ret != 0) { + PARAM_CHECK(ret == 0, return, "Forbid to dump parameters"); + } DumpParameters(&g_clientSpace.paramSpace, verbose); } @@ -308,7 +314,7 @@ int WatchParamCheck(const char *keyprefix) return 0; } -#ifdef STARTUP_INIT_TEST +#if (defined STARTUP_INIT_TEST || defined PARAM_TEST) ParamWorkSpace *GetClientParamWorkSpace(void) { return &g_clientSpace.paramSpace; diff --git a/services/param/cmd/param_cmd.c b/services/param/cmd/param_cmd.c index 56630b2..0c46e9b 100755 --- a/services/param/cmd/param_cmd.c +++ b/services/param/cmd/param_cmd.c @@ -32,10 +32,10 @@ #define WAIT_TIMEOUT_INDEX 2 struct CmdArgs { - char name[8]; + char name[8]; // cmd name length int minArg; void (*DoFuncion)(int argc, char *argv[], int start); - char help[128]; + char help[128]; // cmd help length }; static void ShowParam(ParamHandle handle, void *cookie) @@ -100,17 +100,89 @@ static void ExeuteCmdParamWait(int argc, char *argv[], int start) if (argc > (start + WAIT_TIMEOUT_INDEX)) { timeout = atol(argv[start + WAIT_TIMEOUT_INDEX]); } - SystemWaitParameter(argv[start], value, timeout); + int ret = SystemWaitParameter(argv[start], value, timeout); + if (ret == 0) { + printf("Param wait success "); + } else { + printf("Param wait fail"); + } } +#ifdef PARAM_TEST +static void ExeuteCmdParamRead(int argc, char *argv[], int start) +{ + SystemSetParameter("test.randrom.test.start", "1"); + char buffer[PARAM_NAME_LEN_MAX] = {0}; + printf("SystemGetParameter start \n"); + srand((unsigned)time(NULL)); + while (1) { + int wait = rand() / READ_DURATION + READ_DURATION; // 100ms + uint32_t size = PARAM_NAME_LEN_MAX; + int ret = SystemGetParameter(argv[start], buffer, &size); + if (ret == 0) { + printf("SystemGetParameter value %s %d \n", buffer, wait); + } else { + printf("SystemGetParameter fail %d \n", wait); + } + usleep(wait); + } +} + +static void HandleParamChange(const char *key, const char *value, void *context) +{ + if (key == NULL || value == NULL) { + return; + } + UNUSED(context); + printf("Receive parameter change %s %s \n", key, value); +} + +static void ExeuteCmdParamWatch(int argc, char *argv[], int start) +{ + if (argc <= start) { + return; + } + 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 }, - }; + { "set", 4, ExeuteCmdParamSet, USAGE_INFO_PARAM_SET }, // set param count + { "get", 2, ExeuteCmdParamGet, USAGE_INFO_PARAM_GET }, // get param count + { "wait", 3, ExeuteCmdParamWait, USAGE_INFO_PARAM_WAIT }, // wait param count + { "dump", 2, ExeuteCmdParamDump, USAGE_INFO_PARAM_DUMP }, // dump param count +#ifdef PARAM_TEST + { "read", 2, ExeuteCmdParamRead, USAGE_INFO_PARAM_READ }, // read param count + { "watch", 2, ExeuteCmdParamWatch, USAGE_INFO_PARAM_WATCH }, // watch param count +#endif + }; +#ifdef PARAM_TEST + ParamWorkSpace *space = GetClientParamWorkSpace(); + if (space != NULL && space->securityLabel != NULL) { + const int testUid = 1000; + space->securityLabel->cred.uid = testUid; + space->securityLabel->cred.gid = testUid; + } +#endif + if ((strcmp(argv[0], "./paramset") == 0) || (strcmp(argv[0], "paramset") == 0)) { + if (argc == (MIN_ARGC + 1)) { + ExeuteCmdParamSet(argc, argv, 1); + } else { + printf("param set key value \n"); + } + return 0; + } else if ((strcmp(argv[0], "./paramget") == 0) || (strcmp(argv[0], "paramget") == 0)) { + ExeuteCmdParamSet(argc, argv, 1); + return 0; + } if (argc < MIN_ARGC) { printf("usage: \n"); for (size_t i = 0; i < sizeof(paramCmds) / sizeof(paramCmds[0]); i++) { diff --git a/services/param/include/param_manager.h b/services/param/include/param_manager.h old mode 100644 new mode 100755 diff --git a/services/param/include/param_persist.h b/services/param/include/param_persist.h index 95b14f6..fedf317 100755 --- a/services/param/include/param_persist.h +++ b/services/param/include/param_persist.h @@ -40,8 +40,12 @@ typedef struct { #ifdef PARAM_SUPPORT_SAVE_PERSIST int RegisterPersistParamOps(PersistParamOps *ops); +#ifdef STARTUP_INIT_TEST #define PARAM_MUST_SAVE_PARAM_DIFF 10 // 10s #else +#define PARAM_MUST_SAVE_PARAM_DIFF 1 +#endif +#else #define PARAM_MUST_SAVE_PARAM_DIFF UINT32_MAX #endif #ifdef __cplusplus diff --git a/services/param/include/param_request.h b/services/param/include/param_request.h old mode 100644 new mode 100755 index f6d5ccf..a6b786f --- a/services/param/include/param_request.h +++ b/services/param/include/param_request.h @@ -16,6 +16,7 @@ #ifndef BASE_STARTUP_PARAM_REQUEST_H #define BASE_STARTUP_PARAM_REQUEST_H +#include #include "param_manager.h" #include "sys_param.h" #ifdef __cplusplus diff --git a/services/param/include/param_service.h b/services/param/include/param_service.h old mode 100644 new mode 100755 diff --git a/services/param/include/param_trie.h b/services/param/include/param_trie.h old mode 100644 new mode 100755 diff --git a/services/param/include/param_utils.h b/services/param/include/param_utils.h index 61decf0..54ae0e8 100755 --- a/services/param/include/param_utils.h +++ b/services/param/include/param_utils.h @@ -48,16 +48,17 @@ typedef enum { #define OHOS_SERVICE_CTRL_PREFIX "ohos.servicectrl." #define OHOS_BOOT "ohos.boot." +#define CLIENT_PIPE_NAME "/dev/unix/socket/paramservice" +#define CLIENT_PARAM_STORAGE_PATH "/dev/__parameters__/param_storage" + #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_DEFAULT_PATH "/data/init_ut" +#define PIPE_NAME PARAM_DEFAULT_PATH"/param/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 @@ -66,9 +67,10 @@ typedef enum { #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" +#endif + #define GROUP_FILE_PATH "/etc/group" #define USER_FILE_PATH "/etc/passwd" -#endif #define WORKSPACE_FLAGS_INIT 0x01 #define WORKSPACE_FLAGS_LOADED 0x02 @@ -79,6 +81,10 @@ typedef enum { #define PARAM_CLEAR_FLAG(node, flag) ((node) &= ~(flag)) #define PARAM_TEST_FLAG(node, flag) (((node) & (flag)) == (flag)) +#ifndef LABEL +#define LABEL "Parameter" +#endif + #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__) @@ -110,8 +116,6 @@ typedef struct { #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 diff --git a/services/param/include/trigger_checker.h b/services/param/include/trigger_checker.h old mode 100644 new mode 100755 diff --git a/services/param/include/trigger_manager.h b/services/param/include/trigger_manager.h old mode 100644 new mode 100755 diff --git a/services/param/manager/param_manager.c b/services/param/manager/param_manager.c old mode 100644 new mode 100755 index abd7372..b2e36c0 --- a/services/param/manager/param_manager.c +++ b/services/param/manager/param_manager.c @@ -14,9 +14,9 @@ */ #include "param_manager.h" + #include -#define LABEL "Manager" #if !defined PARAM_SUPPORT_SELINUX && !defined PARAM_SUPPORT_DAC static ParamSecurityLabel g_defaultSecurityLabel; #endif @@ -64,7 +64,11 @@ int InitParamWorkSpace(ParamWorkSpace *workSpace, int onlyRead) 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); } - ret = InitWorkSpace(PARAM_STORAGE_PATH, &workSpace->paramSpace, onlyRead); + if (onlyRead) { + ret = InitWorkSpace(CLIENT_PARAM_STORAGE_PATH, &workSpace->paramSpace, onlyRead); + } else { + 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; @@ -272,12 +276,14 @@ static void DumpWorkSpace(const ParamWorkSpace *workSpace, int verbose) { 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); + if (workSpace->paramSpace.area != NULL) { + 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); } diff --git a/services/param/manager/param_message.c b/services/param/manager/param_message.c index e1ff245..48dc528 100755 --- a/services/param/manager/param_message.c +++ b/services/param/manager/param_message.c @@ -14,6 +14,7 @@ */ #include "param_message.h" + #include #include #include @@ -21,7 +22,6 @@ #include #include -#define LABEL "PARAM_MSG" int ConntectServer(int fd, const char *servername) { PARAM_CHECK(fd >= 0, return -1, "Invalid fd %d", fd); diff --git a/services/param/manager/param_trie.c b/services/param/manager/param_trie.c old mode 100644 new mode 100755 index af6c78d..94d7086 --- a/services/param/manager/param_trie.c +++ b/services/param/manager/param_trie.c @@ -27,8 +27,6 @@ #include "param_utils.h" #include "sys_param.h" -#define LABEL "Manager" - static int InitWorkSpace_(WorkSpace *workSpace, int mode, int prot, uint32_t spaceSize, int readOnly) { PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid workSpace"); diff --git a/services/param/manager/param_utils.c b/services/param/manager/param_utils.c index ee0dadf..64ab646 100755 --- a/services/param/manager/param_utils.c +++ b/services/param/manager/param_utils.c @@ -26,7 +26,6 @@ #include #include -#define LABEL "PARAM_UTILS" void CheckAndCreateDir(const char *fileName) { if (fileName == NULL || *fileName == '\0') { @@ -39,45 +38,6 @@ void CheckAndCreateDir(const char *fileName) free(path); } -int ReadFileInDir(const char *dirPath, const char *includeExt, - int (*processFile)(const char *fileName, void *context), void *context) -{ - if (dirPath == NULL || processFile == NULL) { - return -1; - } - 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) { @@ -86,7 +46,7 @@ char *ReadFileData(const char *fileName) char *buffer = NULL; int fd = -1; do { - fd = open(fileName, O_RDONLY); + fd = open(fileName, O_RDONLY); // 阶段早,不能使用realpath PARAM_CHECK(fd >= 0, break, "Failed to read file %s", fileName); buffer = (char *)malloc(MAX_DATA_BUFFER); diff --git a/services/param/service/param_persist.c b/services/param/service/param_persist.c old mode 100644 new mode 100755 index a2d2b3b..1bfcff5 --- a/services/param/service/param_persist.c +++ b/services/param/service/param_persist.c @@ -12,8 +12,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #include "param_persist.h" + #include #include #include @@ -24,8 +24,6 @@ #include "param_trie.h" #include "sys_param.h" -#define LABEL "Manager" - static ParamPersistWorkSpace g_persistWorkSpace = { 0, NULL, 0, { NULL, NULL, NULL, NULL, NULL } }; static int AddPersistParam(const char *name, const char *value, void *context) @@ -110,10 +108,12 @@ int LoadPersistParam(ParamWorkSpace *workSpace) PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid workSpace"); int ret = InitPersistParamWorkSpace(workSpace); PARAM_CHECK(ret == 0, return ret, "Failed to init persist param"); +#ifndef STARTUP_INIT_TEST if (PARAM_TEST_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_LOADED)) { PARAM_LOGE("Persist param has been loaded"); return 0; } +#endif if (g_persistWorkSpace.persistParamOps.load != NULL) { ret = g_persistWorkSpace.persistParamOps.load(AddPersistParam, &workSpace->paramSpace); PARAM_SET_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_LOADED); @@ -124,10 +124,11 @@ int LoadPersistParam(ParamWorkSpace *workSpace) return 0; } -static void TimerCallbackForSave(ParamTaskPtr timer, void *context) +PARAM_STATIC void TimerCallbackForSave(ParamTaskPtr timer, void *context) { UNUSED(context); - ParamTaskClose(timer); + UNUSED(timer); + ParamTaskClose(g_persistWorkSpace.saveTimer); g_persistWorkSpace.saveTimer = NULL; if (!PARAM_TEST_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_UPDATE)) { return; diff --git a/services/param/service/param_service.c b/services/param/service/param_service.c old mode 100644 new mode 100755 index 8f3c0a0..f78f663 --- a/services/param/service/param_service.c +++ b/services/param/service/param_service.c @@ -25,12 +25,12 @@ #include #include "init_param.h" +#include "init_utils.h" #include "param_message.h" #include "param_manager.h" #include "param_request.h" #include "trigger_manager.h" -#define LABEL "ParamServer" static ParamWorkSpace g_paramWorkSpace = { 0, {}, NULL, {}, NULL, NULL }; static void OnClose(ParamTaskPtr client) @@ -133,6 +133,8 @@ PARAM_STATIC int AddSecurityLabel(const ParamAuditData *auditData, void *context #ifdef STARTUP_INIT_TEST ParamSecruityNode *label = (ParamSecruityNode *)GetTrieNode(&workSpace->paramSpace, node->labelIndex); label->mode = auditData->dacData.mode; + label->uid = auditData->dacData.uid; + label->gid = auditData->dacData.gid; #endif PARAM_LOGE("Error, repeate to add label for name %s", auditData->name); } @@ -155,7 +157,7 @@ static char *GetServiceCtrlName(const char *name, const char *value) }; char *key = NULL; if (strcmp("sys.powerctrl", name) == 0) { - for (size_t i = 0; i < sizeof(powerCtrlArg) / sizeof(powerCtrlArg[0]); i++) { + for (size_t i = 0; i < ARRAY_LENGTH(powerCtrlArg); 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); @@ -167,7 +169,7 @@ static char *GetServiceCtrlName(const char *name, const char *value) } } } else { - for (size_t i = 0; i < sizeof(ctrlParam) / sizeof(ctrlParam[0]); i++) { + for (size_t i = 0; i < ARRAY_LENGTH(ctrlParam); i++) { if (strcmp(name, ctrlParam[i]) == 0) { uint32_t keySize = strlen(value) + strlen(OHOS_SERVICE_CTRL_PREFIX) + 1; key = (char *)malloc(keySize + 1); @@ -225,14 +227,15 @@ static int SystemSetParam(const char *name, const char *value, const ParamSecuri free(key); } PARAM_CHECK(ret == 0, return ret, "Forbit to set parameter %s", name); - 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 { + 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); CheckAndSendTrigger(&g_paramWorkSpace, dataIndex, name, value); } return ret; @@ -508,6 +511,97 @@ static void TimerCallback(ParamTaskPtr timer, void *context) } } +static int GetParamValueFromBuffer(const char *name, const char *buffer, char *value, int length) +{ + char *endData = (char *)buffer + strlen(buffer); + size_t bootLen = strlen(OHOS_BOOT); + char *tmp = strstr(buffer, name + bootLen); + do { + if (tmp == NULL) { + return -1; + } + tmp = tmp + strlen(name) - bootLen; + while (tmp < endData && *tmp == ' ') { + tmp++; + } + if (*tmp == '=') { + break; + } + tmp = strstr(tmp + 1, name + bootLen); + } while (tmp < endData); + tmp++; + size_t i = 0; + size_t endIndex = 0; + while (tmp < endData && *tmp == ' ') { + tmp++; + } + for (; i < (size_t)length; tmp++) { + if (tmp >= endData) { + endIndex = i; + break; + } + if (*tmp == ' ') { + endIndex = i; + } + if (*tmp == '=') { + if (endIndex != 0) { // for root=uuid=xxxx + break; + } + i = 0; + endIndex = 0; + continue; + } + value[i++] = *tmp; + } + if (i >= (size_t)length) { + return -1; + } + value[endIndex] = '\0'; + return 0; +} + +static int LoadParamFromCmdLine(void) +{ + static const char *cmdLines[] = { + OHOS_BOOT"hardware", +#ifdef STARTUP_INIT_TEST + OHOS_BOOT"mem", + OHOS_BOOT"console", + OHOS_BOOT"mmz", + OHOS_BOOT"androidboot.selinux", + OHOS_BOOT"init", + OHOS_BOOT"root", + OHOS_BOOT"uuid", + OHOS_BOOT"aaaaa", + OHOS_BOOT"rootfstype", + OHOS_BOOT"blkdevparts", +#endif + }; + char *data = ReadFileData(PARAM_CMD_LINE); + PARAM_CHECK(data != NULL, return -1, "Failed to read file %s", PARAM_CMD_LINE); + char *value = malloc(PARAM_CONST_VALUE_LEN_MAX); + PARAM_CHECK(value != NULL, free(data); + return -1, "Failed to read file %s", PARAM_CMD_LINE); + + for (size_t i = 0; i < ARRAY_LENGTH(cmdLines); i++) { + int ret = GetParamValueFromBuffer(cmdLines[i], data, value, PARAM_CONST_VALUE_LEN_MAX); + if (ret == 0) { + PARAM_LOGD("Add param from cmdline %s %s", cmdLines[i], value); + ret = CheckParamName(cmdLines[i], 0); + PARAM_CHECK(ret == 0, return -1, "Invalid name %s", cmdLines[i]); + uint32_t dataIndex = 0; + ret = WriteParam(&g_paramWorkSpace.paramSpace, cmdLines[i], value, &dataIndex, 0); + PARAM_CHECK(ret == 0, return -1, "Failed to write param %s %s", cmdLines[i], value); + } else { + PARAM_LOGE("Can not find arrt %s", cmdLines[i]); + } + } + PARAM_LOGD("Parse cmdline finish %s", PARAM_CMD_LINE); + free(data); + free(value); + return 0; +} + int SystemWriteParam(const char *name, const char *value) { PARAM_CHECK(name != NULL && value != NULL, return -1, "The name is null"); @@ -525,12 +619,6 @@ int SystemReadParam(const char *name, char *value, unsigned int *len) return ret; } -int SystemTraversalParam(void (*traversalParameter)(ParamHandle handle, void *cookie), void *cookie) -{ - PARAM_CHECK(traversalParameter != NULL, return -1, "The param is null"); - return TraversalParam(&g_paramWorkSpace, traversalParameter, cookie); -} - int LoadPersistParams(void) { return LoadPersistParam(&g_paramWorkSpace); @@ -540,7 +628,7 @@ static int ProcessParamFile(const char *fileName, void *context) { static const char *exclude[] = {"ctl.", "selinux.restorecon_recursive"}; uint32_t mode = *(int *)context; - return LoadDefaultParam_(fileName, mode, exclude, sizeof(exclude) / sizeof(exclude[0])); + return LoadDefaultParam_(fileName, mode, exclude, ARRAY_LENGTH(exclude)); } int LoadDefaultParams(const char *fileName, uint32_t mode) @@ -602,6 +690,9 @@ void InitParamService(void) auditData.dacData.mode = DAC_ALL_PERMISSION; ret = AddSecurityLabel(&auditData, (void *)&g_paramWorkSpace); PARAM_CHECK(ret == 0, return, "Failed to add default dac label"); + + // 读取cmdline的参数 + LoadParamFromCmdLine(); } static void OnPidDelete(pid_t pid) @@ -628,3 +719,11 @@ ParamWorkSpace *GetParamWorkSpace(void) { return &g_paramWorkSpace; } + +void DumpParametersAndTriggers(void) +{ + DumpParameters(&g_paramWorkSpace, 1); + if (GetTriggerWorkSpace() != NULL) { + DumpTrigger(GetTriggerWorkSpace()); + } +} \ No newline at end of file diff --git a/services/param/trigger/trigger_checker.c b/services/param/trigger/trigger_checker.c old mode 100644 new mode 100755 index 2bd1e89..ee40975 --- a/services/param/trigger/trigger_checker.c +++ b/services/param/trigger/trigger_checker.c @@ -20,7 +20,6 @@ #include "trigger_manager.h" #define MAX_CALC_PARAM 100 -#define LABEL "Trigger" // 申请整块能存作为计算的节点 int CalculatorInit(LogicCalculator *calculator, int dataNumber, int dataUnit, int needCondition) { diff --git a/services/param/trigger/trigger_manager.c b/services/param/trigger/trigger_manager.c old mode 100644 new mode 100755 index 97e4639..7602cdd --- a/services/param/trigger/trigger_manager.c +++ b/services/param/trigger/trigger_manager.c @@ -27,7 +27,6 @@ #include "param_manager.h" #include "trigger_checker.h" -#define LABEL "Trigger" int AddCommand(TriggerNode *trigger, uint32_t cmdKeyIndex, const char *content) { PARAM_CHECK(trigger != NULL, return -1, "trigger is null"); @@ -44,15 +43,14 @@ int AddCommand(TriggerNode *trigger, uint32_t cmdKeyIndex, const char *content) int ret = memcpy_s(node->content, size, content, strlen(content)); node->content[strlen(content)] = '\0'; PARAM_CHECK(ret == EOK, free(node); - return -1, "Failed to copy command"); + return 0, "Failed to copy command"); } // 插入队列 if (trigger->firstCmd == NULL) { trigger->firstCmd = node; trigger->lastCmd = node; } else { - PARAM_CHECK(trigger->lastCmd != NULL, free(node); - return -1, "Invalid last cmd"); + PARAM_CHECK(trigger->lastCmd != NULL, return 0, "Invalid last cmd"); trigger->lastCmd->next = node; trigger->lastCmd = node; } @@ -257,6 +255,8 @@ static int CheckParamTriggerMatch(TriggerWorkSpace *workSpace, LogicCalculator * static int CheckOtherTriggerMatch(TriggerWorkSpace *workSpace, LogicCalculator *calculator, TriggerNode *trigger, const char *content, uint32_t contentSize) { + UNUSED(content); + UNUSED(contentSize); const char *condition = GetTriggerCondition(workSpace, trigger); return ComputeCondition(calculator, condition); } diff --git a/services/param/trigger/trigger_processor.c b/services/param/trigger/trigger_processor.c old mode 100644 new mode 100755 index e87efac..81260bb --- a/services/param/trigger/trigger_processor.c +++ b/services/param/trigger/trigger_processor.c @@ -12,20 +12,58 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #include - +#include #include "init_cmds.h" +#include "init_param.h" #include "init_service_manager.h" +#include "init_utils.h" #include "param_manager.h" #include "param_utils.h" #include "trigger_checker.h" #include "trigger_manager.h" -#define LABEL "Trigger" #define MAX_TRIGGER_COUNT_RUN_ONCE 20 static TriggerWorkSpace g_triggerWorkSpace = {}; +#ifdef PARAM_TEST +#define MAX_COUNT 1000 +#define READ_DURATION 100000 +#define TEST_PARAM_NAME "test.random.read.001" +static void AddTestTrigger(const TriggerWorkSpace *workSpace) +{ + TriggerHeader *header = (TriggerHeader *)&workSpace->triggerHead[TRIGGER_PARAM]; + TriggerNode *trigger = AddTrigger(header, "param:test.randrom.test.start=1", "test.randrom.test.start=1", 0); + PARAM_CHECK(trigger != NULL, return, "Failed to create test trigger"); + int cmdKeyIndex = 0; + GetMatchCmd("setparam ", &cmdKeyIndex); + int ret = AddCommand(trigger, (uint32_t)CMD_INDEX_FOR_PARA_TEST, NULL); + PARAM_CHECK(ret == 0, return, "Failed to add command"); +} + +static void TestTimerCallback(ParamTaskPtr timer, void *context) +{ + srand((unsigned)time(NULL)); + char buffer[32] = { 0 }; + static int index = 0; + index++; + if (index >= MAX_COUNT) { + ParamTaskClose(timer); + } + static uint32_t value = 0; + int count = 0; + while (count < MAX_COUNT) { + int wait = rand() / READ_DURATION + READ_DURATION; // 100ms + sprintf_s(buffer, sizeof(buffer), "%u", value); + PARAM_LOGI("set param name: %s, value %s", TEST_PARAM_NAME, buffer); + SystemWriteParam(TEST_PARAM_NAME, buffer); + usleep(wait); + count++; + value++; + } +} +#endif + void DoTriggerExec(const char *triggerName) { PARAM_CHECK(triggerName != NULL, return, "Invalid param"); @@ -45,17 +83,16 @@ static void DoCmdExec(const TriggerNode *trigger, const CommandNode *cmd, const 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(cmd->content); +#ifdef PARAM_TEST + } else if (cmd->cmdKeyIndex == CMD_INDEX_FOR_PARA_TEST) { + ParamTaskPtr timer = NULL; + ParamTimerCreate(&timer, TestTimerCallback, NULL); + ParamTimerStart(timer, READ_DURATION, MAX_COUNT); return; +#endif } #ifndef STARTUP_INIT_TEST - DoCmdByName(cmdName, cmd->content); + DoCmdByIndex(cmd->cmdKeyIndex, cmd->content); #endif } @@ -162,7 +199,7 @@ static const char *GetCmdInfo(const char *content, uint32_t contentSize, char ** static const char *ctrlCmds[][2] = { {"reboot", "reboot "} }; - uint32_t index = 0; + int 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; @@ -231,7 +268,7 @@ static int GetTriggerType(const char *type) "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++) { + for (size_t i = 0; i < ARRAY_LENGTH(triggerTypeStr); i++) { if (strcmp(triggerTypeStr[i], type) == 0) { return TRIGGER_BOOT; } @@ -267,7 +304,7 @@ static int ParseTrigger_(const TriggerWorkSpace *workSpace, const cJSON *trigger PARAM_CHECK(cmdLinesCnt > 0, return -1, "Command array size must positive %s", name); int ret; - uint32_t cmdKeyIndex = 0; + int cmdKeyIndex = 0; for (int i = 0; (i < cmdLinesCnt) && (i < TRIGGER_MAX_CMD); ++i) { char *cmdLineStr = cJSON_GetStringValue(cJSON_GetArrayItem(cmdItems, i)); PARAM_CHECK(cmdLineStr != NULL, continue, "Command is null"); @@ -277,9 +314,9 @@ static int ParseTrigger_(const TriggerWorkSpace *workSpace, const cJSON *trigger PARAM_CHECK(matchCmd != NULL, continue, "Command not support %s", cmdLineStr); size_t matchLen = strlen(matchCmd); if (matchLen == cmdLineLen) { - ret = AddCommand(trigger, cmdKeyIndex, NULL); + ret = AddCommand(trigger, (uint32_t)cmdKeyIndex, NULL); } else { - ret = AddCommand(trigger, cmdKeyIndex, cmdLineStr + matchLen); + ret = AddCommand(trigger, (uint32_t)cmdKeyIndex, cmdLineStr + matchLen); } PARAM_CHECK(ret == 0, continue, "Failed to add command %s", cmdLineStr); } @@ -299,6 +336,10 @@ int ParseTriggerConfig(const cJSON *fileRoot) cJSON *item = cJSON_GetArrayItem(triggers, i); ParseTrigger_(&g_triggerWorkSpace, item); } +#ifdef PARAM_TEST + // for test + AddTestTrigger(&g_triggerWorkSpace); +#endif return 0; } @@ -312,15 +353,12 @@ int InitTriggerWorkSpace(void) 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.executeQueue = calloc(1, TRIGGER_EXECUTE_QUEUE * sizeof(TriggerNode *)); + PARAM_CHECK(g_triggerWorkSpace.executeQueue.executeQueue != NULL, + return -1, "Failed to alloc memory for executeQueue"); 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++) { diff --git a/services/param/watcher/agent/watcher_manager_kits.cpp b/services/param/watcher/agent/watcher_manager_kits.cpp index 0a60e7d..fd452c1 100755 --- a/services/param/watcher/agent/watcher_manager_kits.cpp +++ b/services/param/watcher/agent/watcher_manager_kits.cpp @@ -88,7 +88,7 @@ WatcherManagerKits::ParamWatcherKitPtr WatcherManagerKits::GetParamWatcher(const void WatcherManagerKits::SetParamWatcher(const std::string &keyPrefix, ParamWatcherKitPtr watcher) { std::lock_guard lock(mutex_); - if (watchers_.find(keyPrefix) != watchers_.end()) { + if (watchers_.find(keyPrefix) == watchers_.end()) { watchers_[keyPrefix] = watcher; } } diff --git a/services/param/watcher/include/watcher_utils.h b/services/param/watcher/include/watcher_utils.h index 1026e5c..09aa72b 100755 --- a/services/param/watcher/include/watcher_utils.h +++ b/services/param/watcher/include/watcher_utils.h @@ -28,7 +28,7 @@ namespace init_param { #define UNUSED(x) (void)(x) #ifndef LABEL -#define LABEL "Watcher" +#define LABEL "ParameterWatcher" #endif #define WATCHER_LOGI(fmt, ...) STARTUP_LOGI(LABEL, fmt, ##__VA_ARGS__) diff --git a/services/param/watcher/proxy/watcher_manager.cpp b/services/param/watcher/proxy/watcher_manager.cpp index 02991b9..a568c41 100755 --- a/services/param/watcher/proxy/watcher_manager.cpp +++ b/services/param/watcher/proxy/watcher_manager.cpp @@ -32,9 +32,9 @@ const static int32_t INVALID_SOCKET = -1; 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_++; - } + watcherId_++; + WATCHER_LOGD("AddWatcher begin %s", keyPrefix.c_str()); + 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); @@ -44,6 +44,7 @@ uint32_t WatcherManager::AddWatcher(const std::string &keyPrefix, const sptrEmptry()) { StartLoop(); SendMessage(group, MSG_ADD_WATCHER); @@ -76,19 +77,19 @@ int WatcherManager::SendMessage(WatcherGroupPtr group, int type) 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; - } + + WATCHER_LOGD("SendMessage %s", group->GetKeyPrefix().c_str()); + 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); + } else { + PARAM_LOGD("SendMessage key: %s %d fail", group->GetKeyPrefix().c_str(), type); } - // fail, try again - PARAM_LOGE("Failed to connect server %s, try again", PIPE_NAME); - fd = GetServerFd(true); - } while (1); + } else { + PARAM_LOGD("SendMessage key: %s %d fail", group->GetKeyPrefix().c_str(), type); + } free(request); return 0; } @@ -97,6 +98,7 @@ void WatcherManager::ProcessWatcherMessage(const std::vector &buffer, uint { ParamMessage *msg = (ParamMessage *)buffer.data(); PARAM_CHECK(msg != NULL, return, "Invalid msg"); + PARAM_LOGD("ProcessWatcherMessage %d", msg->type); uint32_t offset = 0; if (msg->type != MSG_NOTIFY_PARAM) { return; @@ -123,18 +125,22 @@ WatcherManager::WatcherGroupPtr WatcherManager::GetWatcherGroup(uint32_t groupId WatcherManager::WatcherGroupPtr WatcherManager::GetWatcherGroup(const std::string &keyPrefix) { + std::lock_guard lock(watcherMutex_); if (groupMap_.find(keyPrefix) == groupMap_.end()) { return nullptr; } - return GetWatcherGroup(groupMap_[keyPrefix]); + uint32_t groupId = groupMap_[keyPrefix]; + if (watcherGroups_.find(groupId) != watcherGroups_.end()) { + return watcherGroups_[groupId]; + } + return nullptr; } void WatcherManager::AddWatcherGroup(const std::string &keyPrefix, WatcherGroupPtr group) { uint32_t groupId = group->GetGroupId(); - groupMap_[keyPrefix] = groupId; - std::lock_guard lock(watcherMutex_); + groupMap_[keyPrefix] = groupId; if (watcherGroups_.find(groupId) != watcherGroups_.end()) { return; } @@ -143,9 +149,9 @@ void WatcherManager::AddWatcherGroup(const std::string &keyPrefix, WatcherGroupP void WatcherManager::DelWatcherGroup(WatcherGroupPtr group) { - groupMap_[group->GetKeyPrefix()] = 0; std::lock_guard lock(watcherMutex_); - watcherGroups_[group->GetGroupId()] = nullptr; + groupMap_.erase(group->GetKeyPrefix()); + watcherGroups_.erase(group->GetGroupId()); } void WatcherManager::WatcherGroup::AddWatcher(const ParamWatcherPtr &watcher) @@ -156,7 +162,7 @@ void WatcherManager::WatcherGroup::AddWatcher(const ParamWatcherPtr &watcher) void WatcherManager::WatcherGroup::DelWatcher(uint32_t watcherId) { if (watchers_.find(watcherId) != watchers_.end()) { - watchers_[watcherId] = nullptr; + watchers_.erase(watcherId); } } @@ -191,6 +197,7 @@ void WatcherManager::SendLocalChange(const std::string &keyPrefix, ParamWatcherP ParamWatcherPtr watcher; std::string keyPrefix; }; + PARAM_LOGD("SendLocalChange key %s ", keyPrefix.c_str()); std::vector buffer(PARAM_NAME_LEN_MAX + PARAM_CONST_VALUE_LEN_MAX); struct Context context = {buffer.data(), watcher, keyPrefix}; // walk watcher @@ -211,7 +218,7 @@ void WatcherManager::RunLoop() { const int32_t RECV_BUFFER_MAX = 5 * 1024; std::vector buffer(RECV_BUFFER_MAX, 0); - while (!stop) { + while (!stop_) { int fd = GetServerFd(false); ssize_t recvLen = recv(fd, buffer.data(), RECV_BUFFER_MAX, 0); if (recvLen <= 0) { @@ -222,6 +229,9 @@ void WatcherManager::RunLoop() PARAM_LOGE("Failed to recv msg from server errno %d", errno); } PARAM_LOGD("Recv msg from server"); + if (stop_) { + break; + } if (recvLen >= (ssize_t)sizeof(ParamMessage)) { ProcessWatcherMessage(buffer, recvLen); } @@ -240,6 +250,7 @@ void WatcherManager::StartLoop() int WatcherManager::GetServerFd(bool retry) { const int32_t sleepTime = 2000; + const int32_t maxRetry = 10; std::lock_guard lock(mutex_); if (retry && serverFd_ != INVALID_SOCKET) { close(serverFd_); @@ -251,9 +262,10 @@ int WatcherManager::GetServerFd(bool retry) struct timeval time {}; time.tv_sec = 1; time.tv_usec = 0; + int32_t retryCount = 0; do { serverFd_ = socket(AF_UNIX, SOCK_STREAM, 0); - int ret = ConntectServer(serverFd_, PIPE_NAME); + int ret = ConntectServer(serverFd_, CLIENT_PIPE_NAME); if (ret != 0) { close(serverFd_); serverFd_ = INVALID_SOCKET; @@ -262,7 +274,9 @@ int WatcherManager::GetServerFd(bool retry) (void)setsockopt(serverFd_, SOL_SOCKET, SO_RCVTIMEO, &time, sizeof(struct timeval)); break; } - } while (1); + retryCount++; + } while (retryCount < maxRetry); + PARAM_LOGD("SendMessage retryCount %d", retryCount); return serverFd_; } @@ -276,10 +290,10 @@ void WatcherManager::OnStart() return; } -void WatcherManager::OnStop() +void WatcherManager::StopLoop() { - PARAM_LOGI("WatcherManager OnStop"); - stop = true; + PARAM_LOGI("WatcherManager StopLoop"); + stop_ = true; { std::lock_guard lock(mutex_); close(serverFd_); @@ -291,5 +305,10 @@ void WatcherManager::OnStop() pRecvThread_ = nullptr; } } + +void WatcherManager::OnStop() +{ + StopLoop(); +} } // namespace init_param } // namespace OHOS diff --git a/services/param/watcher/proxy/watcher_manager.h b/services/param/watcher/proxy/watcher_manager.h index 8e769d8..78e3b7d 100755 --- a/services/param/watcher/proxy/watcher_manager.h +++ b/services/param/watcher/proxy/watcher_manager.h @@ -90,6 +90,7 @@ public: uint32_t AddWatcher(const std::string &keyPrefix, const sptr &watcher) override; int32_t DelWatcher(const std::string &keyPrefix, uint32_t watcherId) override; + void StopLoop(); protected: void OnStart() override; void OnStop() override; @@ -111,7 +112,7 @@ private: std::mutex watcherMutex_; int serverFd_ { -1 }; std::thread *pRecvThread_ { nullptr }; - std::atomic stop { false }; + std::atomic stop_ { false }; std::map groupMap_ {}; std::map watcherGroups_ {}; }; diff --git a/services/src/init_capability.c b/services/src/init_capability.c deleted file mode 100644 index 7c2cf13..0000000 --- a/services/src/init_capability.c +++ /dev/null @@ -1,168 +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 "init_capability.h" - -#include -#include -#if defined OHOS_LITE && !defined __LINUX__ -#include -#else -#include -#endif -#include - -#include "init_log.h" -#include "init_perms.h" -#include "init_utils.h" - -#define MAX_CAPS_CNT_FOR_ONE_SERVICE 100 - -struct CapStrCapNum { - char *capStr; - int CapNum; -}; - -static const struct CapStrCapNum g_capStrCapNum[] = { - {"CHOWN", CAP_CHOWN}, - {"DAC_OVERRIDE", CAP_DAC_OVERRIDE}, - {"DAC_READ_SEARCH", CAP_DAC_READ_SEARCH}, - {"FOWNER", CAP_FOWNER}, - {"FSETID", CAP_FSETID}, - {"KILL", CAP_KILL}, - {"SETGID", CAP_SETGID}, - {"SETUID", CAP_SETUID}, - {"SETPCAP", CAP_SETPCAP}, - {"LINUX_IMMUTABLE", CAP_LINUX_IMMUTABLE}, - {"NET_BIND_SERVICE", CAP_NET_BIND_SERVICE}, - {"NET_BROADCAST", CAP_NET_BROADCAST}, - {"NET_ADMIN", CAP_NET_ADMIN}, - {"NET_RAW", CAP_NET_RAW}, - {"IPC_LOCK", CAP_IPC_LOCK}, - {"IPC_OWNER", CAP_IPC_OWNER}, - {"SYS_MODULE", CAP_SYS_MODULE}, - {"SYS_RAWIO", CAP_SYS_RAWIO}, - {"SYS_CHROOT", CAP_SYS_CHROOT}, - {"SYS_PTRACE", CAP_SYS_PTRACE}, - {"SYS_PACCT", CAP_SYS_PACCT}, - {"SYS_ADMIN", CAP_SYS_ADMIN}, - {"SYS_BOOT", CAP_SYS_BOOT}, - {"SYS_NICE", CAP_SYS_NICE}, - {"SYS_RESOURCE", CAP_SYS_RESOURCE}, - {"SYS_TIME", CAP_SYS_TIME}, - {"SYS_TTY_CONFIG", CAP_SYS_TTY_CONFIG}, - {"MKNOD", CAP_MKNOD}, - {"LEASE", CAP_LEASE}, - {"AUDIT_WRITE", CAP_AUDIT_WRITE}, - {"AUDIT_CONTROL", CAP_AUDIT_CONTROL}, - {"SETFCAP", CAP_SETFCAP}, - {"MAC_OVERRIDE", CAP_MAC_OVERRIDE}, - {"MAC_ADMIN", CAP_MAC_ADMIN}, - {"SYSLOG", CAP_SYSLOG}, - {"WAKE_ALARM", CAP_WAKE_ALARM}, - {"BLOCK_SUSPEND", CAP_BLOCK_SUSPEND}, - {"AUDIT_READ", CAP_AUDIT_READ}, -}; - -static int GetServiceStringCaps(const cJSON* filedJ, Service* curServ) // string form -{ - unsigned int i = 0; - for (; i < curServ->servPerm.capsCnt; ++i) { - if (cJSON_GetArrayItem(filedJ, i) == NULL || !cJSON_GetStringValue(cJSON_GetArrayItem(filedJ, i)) - || strlen(cJSON_GetStringValue(cJSON_GetArrayItem(filedJ, i))) <= 0) { // check all errors - INIT_LOGE("service=%s, parse item[%d] as string, error.", curServ->name, i); - break; - } - char* fieldStr = cJSON_GetStringValue(cJSON_GetArrayItem(filedJ, i)); - if (fieldStr == NULL) { - INIT_LOGE("fieldStr is NULL"); - break; - } - int mapSize = ARRAY_LENGTH(g_capStrCapNum); // search - int j = 0; - for (; j < mapSize; j++) { - if (!strcmp(fieldStr, g_capStrCapNum[j].capStr)) { - break; - } - } - if (j < mapSize) { - curServ->servPerm.caps[i] = g_capStrCapNum[j].CapNum; - } else { - INIT_LOGE("service=%s, CapbilityName=%s, error.", curServ->name, fieldStr); - break; - } - if (curServ->servPerm.caps[i] > CAP_LAST_CAP && curServ->servPerm.caps[i] != FULL_CAP) { - // resources will be released by function: ReleaseServiceMem - INIT_LOGE("service=%s, cap = %d, error.", curServ->name, curServ->servPerm.caps[i]); - return SERVICE_FAILURE; - } - } - int ret = ((i == curServ->servPerm.capsCnt) ? SERVICE_SUCCESS : SERVICE_FAILURE); - return ret; -} - -int GetServiceCaps(const cJSON* curArrItem, Service* curServ) -{ - if (curServ == NULL || curArrItem == NULL) { - INIT_LOGE("GetServiceCaps failed, curServ or curArrItem is NULL."); - return SERVICE_FAILURE; - } - curServ->servPerm.capsCnt = 0; - curServ->servPerm.caps = NULL; - cJSON* filedJ = cJSON_GetObjectItem(curArrItem, "caps"); - if (filedJ == NULL) { - return SERVICE_SUCCESS; - } - if (!cJSON_IsArray(filedJ)) { - INIT_LOGE("service=%s, caps is not a list, error.", curServ->name); - return SERVICE_FAILURE; - } - // caps array does not exist, means do not need any capability - int capsCnt = cJSON_GetArraySize(filedJ); - if (capsCnt <= 0) { - return SERVICE_SUCCESS; - } - if (capsCnt > MAX_CAPS_CNT_FOR_ONE_SERVICE) { - INIT_LOGE("service=%s, too many caps[cnt %d] for one service, max is %d.", - curServ->name, capsCnt, MAX_CAPS_CNT_FOR_ONE_SERVICE); - return SERVICE_FAILURE; - } - curServ->servPerm.caps = (unsigned int*)malloc(sizeof(unsigned int) * capsCnt); - if (curServ->servPerm.caps == NULL) { - INIT_LOGE("GetServiceCaps, service=%s, malloc error.", curServ->name); - return SERVICE_FAILURE; - } - curServ->servPerm.capsCnt = capsCnt; - int i = 0; - for (; i < capsCnt; ++i) { // number form - cJSON* capJ = cJSON_GetArrayItem(filedJ, i); - if (!cJSON_IsNumber(capJ) || cJSON_GetNumberValue(capJ) < 0) { - // resources will be released by function: ReleaseServiceMem - break; - } - curServ->servPerm.caps[i] = (unsigned int)cJSON_GetNumberValue(capJ); - if (curServ->servPerm.caps[i] > CAP_LAST_CAP && curServ->servPerm.caps[i] != FULL_CAP) { - // resources will be released by function: ReleaseServiceMem - INIT_LOGE("service=%s, caps = %d, error.", curServ->name, curServ->servPerm.caps[i]); - return SERVICE_FAILURE; - } - } - if (i == capsCnt) { - return SERVICE_SUCCESS; - } - int ret = GetServiceStringCaps(filedJ, curServ); - return ret; -} - diff --git a/services/src/init_cmds.c b/services/src/init_cmds.c deleted file mode 100644 index 81b4097..0000000 --- a/services/src/init_cmds.c +++ /dev/null @@ -1,1293 +0,0 @@ -/* - * Copyright (c) 2020-2021 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "init_cmds.h" - -#include -#include -#include -#ifndef OHOS_LITE -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "init_jobs.h" -#include "init_log.h" -#ifndef OHOS_LITE -#include "init_param.h" -#endif -#include "init_reboot.h" -#include "init_service_manager.h" -#include "init_utils.h" -#include "securec.h" - -#define DEFAULT_DIR_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH | S_IROTH) // mkdir, default mode -#define SPACES_CNT_IN_CMD_MAX 10 // mount, max number of spaces in cmdline -#define SPACES_CNT_IN_CMD_MIN 2 // mount, min number of spaces in cmdline - -#define LOADCFG_BUF_SIZE 128 // loadcfg, max buffer for one cmdline -#define LOADCFG_MAX_FILE_LEN 51200 // loadcfg, max file size is 50K -#define LOADCFG_MAX_LOOP 20 // loadcfg, to prevent to be trapped in infite loop -#define OCTAL_TYPE 8 // 8 means octal to decimal -#define MAX_BUFFER 256UL -#define AUTHORITY_MAX_SIZE 128 -#define WAIT_MAX_COUNT 10 - -static const char *g_supportCfg[] = { - "/etc/patch.cfg", - "/patch/fstab.cfg", -}; - -#ifndef OHOS_LITE -int GetParamValue(const char *symValue, char *paramValue, unsigned int paramLen) -{ - if ((symValue == NULL) || (paramValue == NULL) || (paramLen == 0)) { - return -1; - } - char tmpName[MAX_PARAM_NAME_LEN] = {0}; - char tmpValue[MAX_PARAM_VALUE_LEN] = {0}; - char *p = NULL; - char *tmpptr = NULL; - p = strchr(symValue, '$'); - if (p == NULL) { // not has '$' copy the original string - INIT_CHECK_RETURN_VALUE(strncpy_s(paramValue, paramLen, symValue, paramLen - 1) == EOK, -1); - return 0; - } - unsigned int tmpLen = p - symValue; - if (tmpLen > 0) { // copy '$' front string - INIT_CHECK_RETURN_VALUE(strncpy_s(paramValue, paramLen, symValue, tmpLen) == EOK, -1); - } - p++; - if (*p == '{') { - p++; - char *right = strchr(p, '}'); - if (right == NULL) { - INIT_LOGE("Invalid cfg file name, miss '}'."); - return -1; - } - tmpLen = right - p; - if (tmpLen > MAX_PARAM_NAME_LEN) { - INIT_LOGE("Parameter name longer than %d", MAX_PARAM_NAME_LEN); - return -1; - } - INIT_CHECK_RETURN_VALUE(strncpy_s(tmpName, MAX_PARAM_NAME_LEN, p, tmpLen) == EOK, -1); - tmpLen = MAX_PARAM_VALUE_LEN; - int ret = SystemReadParam(tmpName, tmpValue, &tmpLen); // get param - if (ret != 0) { - INIT_LOGE("Failed to read parameter \" %s \"", tmpName); - return -1; - } - // change param to new string - INIT_CHECK_RETURN_VALUE(strncat_s(paramValue, paramLen, tmpValue, MAX_PARAM_VALUE_LEN) == EOK, -1); - tmpptr = right + 1; - tmpLen = paramLen - (tmpptr - symValue); - if (*tmpptr != '\0') { // copy last string - INIT_CHECK_RETURN_VALUE(strncat_s(paramValue, paramLen, tmpptr, tmpLen) == EOK, -1); - } - INIT_LOGI("paramValue is %s ", paramValue); - return 0; - } else { - INIT_LOGE("Invalid cfg file name, miss '{'."); - return -1; - } -} -#else -// For ite ohos, do not support parameter operation. just do string copy -inline int GetParamValue(const char *symValue, char *paramValue, unsigned int paramLen) -{ - return (strncpy_s(paramValue, paramLen, symValue, strlen(symValue)) == EOK) ? 0 : -1; -} -#endif - -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 && delim != NULL, NULL); - struct CmdArgs *ctx = (struct CmdArgs *)calloc(sizeof(struct CmdArgs), 1); - INIT_CHECK_RETURN_VALUE(ctx != NULL, NULL); - - ctx->argv = (char**)calloc(sizeof(char*), (size_t)(argsCount + 1)); - INIT_CHECK(ctx->argv != NULL, FreeCmd(ctx); - return NULL); - - char tmpCmd[MAX_BUFFER] = {0}; - size_t cmdLength = strlen(cmdContent); - if (cmdLength > MAX_BUFFER - 1) { - FreeCmd(ctx); - return NULL; - } - - INIT_CHECK(strncpy_s(tmpCmd, MAX_BUFFER - 1, cmdContent, cmdLength) == EOK, FreeCmd(ctx); - return NULL); - - char *p = tmpCmd; - char *token = NULL; - size_t allocSize = 0; - - // Skip lead whitespaces - SKIP_SPACES(p); - ctx->argc = 0; - token = strstr(p, delim); - if (token == NULL) { // No whitespaces - // Make sure there is enough memory to store parameter value - allocSize = (size_t)(cmdLength + MAX_PARAM_VALUE_LEN + 1); - return CopyCmd(ctx, p, allocSize); - } - - while (token != NULL) { - // Too many arguments, treat rest of data as one argument - if (ctx->argc == (argsCount - 1)) { - break; - } - *token = '\0'; // replace it with '\0'; - allocSize = (size_t)((token - p) + MAX_PARAM_VALUE_LEN + 1); - ctx = CopyCmd(ctx, p, allocSize); - INIT_CHECK_RETURN_VALUE(ctx != NULL, NULL); - p = token + 1; // skip '\0' - // Skip lead whitespaces - SKIP_SPACES(p); - token = strstr(p, delim); - } - - 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 = CopyCmd(ctx, p, allocSize); - INIT_CHECK_RETURN_VALUE(ctx != NULL, NULL); - } - return ctx; -} - -void FreeCmd(struct CmdArgs *cmd) -{ - 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(cmd->argv == NULL, free(cmd->argv)); - free(cmd); - return; -} - -static void WriteCommon(const char *file, const char *buffer, int flags, mode_t mode) -{ - if (file == NULL || *file == '\0' || buffer == NULL || *buffer == '\0') { - INIT_LOGE("Invalid arugment"); - return; - } - char realPath[PATH_MAX] = {0}; - if (Realpath(file, realPath, sizeof(realPath)) != NULL) { - int fd = open(realPath, 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 %s 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) -{ - struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); - - if ((ctx == NULL) || (ctx->argv == NULL) || (ctx->argc != maxArg)) { - INIT_LOGE("Command sethostname with invalid arugment"); - FreeCmd(ctx); - return; - } - 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) -{ - 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("Failed to copy interface name"); - FreeCmd(ctx); - return; - } - - int fd = socket(AF_INET, SOCK_DGRAM, 0); - 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; - } - - FreeCmd(ctx); - return; -} -#endif - -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("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) { - sleepTime = sleepTimeLimit; - } - INIT_LOGI("Sleeping %d second(s)", sleepTime); - sleep((unsigned int)sleepTime); - - FreeCmd(ctx); - return; -} - -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("Command start with invalid arguments"); - FreeCmd(ctx); - return; - } - INIT_LOGD("Starting service \" %s \"", ctx->argv[0]); - StartServiceByName(ctx->argv[0], true); - - FreeCmd(ctx); - return; -} - -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("Command stop with invalid arguments"); - FreeCmd(ctx); - return; - } - INIT_LOGD("Stopping service \" %s \"", ctx->argv[0]); - StopServiceByName(ctx->argv[0]); - - FreeCmd(ctx); - return; -} - -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("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 DoCopyInernal(const char *source, const char *target) -{ - 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); - 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; - bool isSuccess = true; - while ((readn = read(srcFd, buf, MAX_COPY_BUF_SIZE - 1)) > 0) { - ssize_t 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(dstFd); - dstFd = -1; - } - close(srcFd); - srcFd = -1; -} - -static void DoCopy(const char *cmdContent, int maxArg) -{ - struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); - if (ctx == NULL || ctx->argv == NULL || ctx->argc != DEFAULT_COPY_ARGS_CNT) { - INIT_LOGE("Command copy with invalid arguments"); - FreeCmd(ctx); - return; - } - char srcPath[PATH_MAX] = {0}; - char dstPath[PATH_MAX] = {0}; - if ((Realpath(ctx->argv[0], srcPath, sizeof(srcPath)) == NULL) || - (Realpath(ctx->argv[1], dstPath, sizeof(dstPath)) == NULL)) { - FreeCmd(ctx); - ctx = NULL; - return; - } - - DoCopyInernal(srcPath, dstPath); - FreeCmd(ctx); - ctx = NULL; - return; -} - -static int Chown(const char *path, const char *uid, const char *gid) -{ - 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; - } - - 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; -} - -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"); - } - FreeCmd(ctx); - return; -} - -static void DoMkDir(const char *cmdContent, int maxArg) -{ - // mkdir support format: - // 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("Command mkdir with invalid arguments"); - FreeCmd(ctx); - return; - } - int rc; - 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; - } - - 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) { - break; - } - if (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 %s failed err = %d ", ctx->argv[0], errno); - (void)rmdir(ctx->argv[0]); - } - FreeCmd(ctx); -} - -static void DoChmod(const char *cmdContent, int maxArg) -{ - struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); - if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("Command chmod with invalid arguments"); - FreeCmd(ctx); - return; - } - - 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); - } - } - FreeCmd(ctx); - return; -} - -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); - return NULL; - } - - size_t mallocLen = endPos - startPos + 1; - char* retStr = (char*)malloc(mallocLen); - if (retStr == NULL) { - INIT_LOGE("DoMount, malloc failed! malloc size %zu, for %s.", mallocLen, srcStr); - return NULL; - } - - const char* copyStart = srcStr + startPos; - if (memcpy_s(retStr, mallocLen, copyStart, endPos - startPos) != EOK) { - INIT_LOGE("DoMount, memcpy_s failed for %s.", srcStr); - free(retStr); - return NULL; - } - retStr[mallocLen - 1] = '\0'; - - // for example, source may be none - if (strncmp(retStr, "none", strlen("none")) == 0) { - retStr[0] = '\0'; - } - return retStr; -} - -static int GetMountFlag(unsigned long *mountflags, const char *targetStr, const char *source) -{ - if (targetStr == NULL) { - return 0; - } - - if (strncmp(targetStr, "nodev", strlen("nodev")) == 0) { - (*mountflags) |= MS_NODEV; - } else if (strncmp(targetStr, "noexec", strlen("noexec")) == 0) { - (*mountflags) |= MS_NOEXEC; - } else if (strncmp(targetStr, "nosuid", strlen("nosuid")) == 0) { - (*mountflags) |= MS_NOSUID; - } else if (strncmp(targetStr, "rdonly", strlen("rdonly")) == 0) { - (*mountflags) |= MS_RDONLY; - } else if (strncmp(targetStr, "noatime", strlen("noatime")) == 0) { - (*mountflags) |= MS_NOATIME; - } else if (strncmp(targetStr, "wait", strlen("wait")) == 0) { - WaitForFile(source, WAIT_MAX_COUNT); - } else { - return 0; - } - return 1; -} - -static int CountSpaces(const char *cmdContent, size_t *spaceCnt, size_t *spacePosArr, size_t spacePosArrLen) -{ - *spaceCnt = 0; - size_t strLen = strlen(cmdContent); - for (size_t i = 0; i < strLen; ++i) { - if (cmdContent[i] == ' ') { - ++(*spaceCnt); - if ((*spaceCnt) > spacePosArrLen) { - INIT_LOGE("DoMount, too many spaces, bad format for %s.", cmdContent); - return 0; - } - spacePosArr[(*spaceCnt) - 1] = i; - } - } - - if ((*spaceCnt) < SPACES_CNT_IN_CMD_MIN || // spaces count should not less than 2(at least 3 items) - spacePosArr[0] == 0 || // should not start with space - spacePosArr[(*spaceCnt) - 1] == strLen - 1) { // should not end with space - INIT_LOGE("DoMount, bad format for %s.", cmdContent); - return 0; - } - - // spaces should not be adjacent - for (size_t i = 1; i < (*spaceCnt); ++i) { - if (spacePosArr[i] == spacePosArr[i - 1] + 1) { - INIT_LOGE("DoMount, bad format for %s.", cmdContent); - return 0; - } - } - return 1; -} - -static void DoMount(const char *cmdContent, int maxArg) -{ - size_t spaceCnt = 0; - size_t spacePosArr[SPACES_CNT_IN_CMD_MAX] = {0}; - if (!CountSpaces(cmdContent, &spaceCnt, spacePosArr, SPACES_CNT_IN_CMD_MAX)) { - return; - } - - // format: fileSystemType source target mountFlag1 mountFlag2... data - unsigned long mountflags = 0; - size_t strLen = strlen(cmdContent); - size_t indexOffset = 0; - char* fileSysType = CopySubStr(cmdContent, 0, spacePosArr[indexOffset]); - if (fileSysType == NULL) { - return; - } - - char* source = CopySubStr(cmdContent, spacePosArr[indexOffset] + 1, spacePosArr[indexOffset + 1]); - if (source == NULL) { - free(fileSysType); - return; - } - ++indexOffset; - - // maybe only has "filesystype source target", 2 spaces - size_t targetEndPos = (indexOffset == spaceCnt - 1) ? strLen : spacePosArr[indexOffset + 1]; - char* target = CopySubStr(cmdContent, spacePosArr[indexOffset] + 1, targetEndPos); - if (target == NULL) { - free(fileSysType); - free(source); - return; - } - ++indexOffset; - - // get mountflags, if fail, the rest part of string will be data - while (indexOffset < spaceCnt) { - size_t tmpStrEndPos = (indexOffset == spaceCnt - 1) ? strLen : spacePosArr[indexOffset + 1]; - char* tmpStr = CopySubStr(cmdContent, spacePosArr[indexOffset] + 1, tmpStrEndPos); - int ret = GetMountFlag(&mountflags, tmpStr, source); - free(tmpStr); - tmpStr = NULL; - - // get flag failed, the rest part of string will be data - if (ret == 0) { - break; - } - ++indexOffset; - } - - int mountRet; - if (indexOffset >= spaceCnt) { // no data - mountRet = mount(source, target, fileSysType, mountflags, NULL); - } else { - const char* dataStr = cmdContent + spacePosArr[indexOffset] + 1; - mountRet = mount(source, target, fileSysType, mountflags, dataStr); - } - - if (mountRet != 0) { - INIT_LOGE("DoMount, failed for %s, err %d.", cmdContent, errno); - } - - free(fileSysType); - free(source); - free(target); -} - -#ifndef OHOS_LITE -#define OPTIONS_SIZE 128u -static void DoInsmodInternal(const char *fileName, const char *secondPtr, const char *restPtr, int flags) -{ - char options[OPTIONS_SIZE] = {0}; - if (flags == 0) { // '-f' option - if (restPtr != NULL && secondPtr != NULL) { // Reset arugments, combine then all. - if (snprintf_s(options, sizeof(options), OPTIONS_SIZE -1, "%s %s", secondPtr, restPtr) == -1) { - return; - } - } else if (secondPtr != NULL) { - if (strncpy_s(options, OPTIONS_SIZE - 1, secondPtr, strlen(secondPtr)) != 0) { - return; - } - } - } else { // Only restPtr is option - if (restPtr != NULL) { - if (strncpy_s(options, OPTIONS_SIZE - 1, restPtr, strlen(restPtr)) != 0) { - return; - } - } - } - if (fileName == NULL) { - return; - } - char realPath[PATH_MAX] = {0}; - if (Realpath(fileName, realPath, sizeof(realPath)) == NULL) { - return; - } - int fd = open(realPath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); - if (fd < 0) { - INIT_LOGE("failed to open %s: %d", realPath, errno); - return; - } - int rc = syscall(__NR_finit_module, fd, options, flags); - if (rc == -1) { - INIT_LOGE("finit_module for %s failed: %d", realPath, errno); - } - if (fd >= 0) { - close(fd); - } - return; -} - -// format insmod [-f] [options] -static void DoInsmod(const char *cmdContent, int maxArg) -{ - char *p = NULL; - char *restPtr = NULL; - char *fileName = NULL; - char *line = NULL; - int flags = 0; - - size_t count = strlen(cmdContent); - if (count > OPTIONS_SIZE) { - INIT_LOGE("DoInsmod options too long, maybe lost some of options"); - } - line = (char *)malloc(count + 1); - if (line == NULL) { - INIT_LOGE("DoInsmod allocate memory failed."); - return; - } - - if (memcpy_s(line, count + 1, cmdContent, count) != EOK) { - INIT_LOGE("DoInsmod memcpy failed"); - free(line); - return; - } - line[count] = '\0'; - do { - if ((p = strtok_r(line, " ", &restPtr)) == NULL) { - INIT_LOGE("DoInsmod cannot get filename."); - free(line); - return; - } - fileName = p; - INIT_LOGI("DoInsmod fileName is [%s].", fileName); - if ((p = strtok_r(NULL, " ", &restPtr)) == NULL) { - break; - } - if (!strcmp(p, "-f")) { - flags = MODULE_INIT_IGNORE_VERMAGIC | MODULE_INIT_IGNORE_MODVERSIONS; - } - } while (0); - DoInsmodInternal(fileName, p, restPtr, flags); - if (line != NULL) { - free(line); - } - return; -} - -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("Command setparam with invalid arguments"); - FreeCmd(ctx); - return; - } - INIT_LOGD("param name: %s, value %s ", ctx->argv[0], ctx->argv[1]); - SystemWriteParam(ctx->argv[0], ctx->argv[1]); - - 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; -} - -#endif // OHOS_LITE - -static bool CheckValidCfg(const char *path) -{ - 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) { - return false; - } - - for (size_t i = 0; i < cfgCnt; ++i) { - if (strcmp(path, g_supportCfg[i]) == 0) { - return true; - } - } - return false; -} - -static void DoLoadCfg(const char *path, int maxArg) -{ - char buf[LOADCFG_BUF_SIZE] = {0}; - FILE *fp = NULL; - size_t maxLoop = 0; - CmdLine *cmdLine = NULL; - size_t len; - INIT_CHECK_ONLY_RETURN(path != NULL); - INIT_LOGI("DoLoadCfg cfg file %s", path); - if (!CheckValidCfg(path)) { - INIT_LOGE("CheckCfg file %s Failed", path); - return; - } - INIT_ERROR_CHECK(path != NULL, return, "CheckCfg path is NULL."); - char realPath[PATH_MAX] = {0}; - if (Realpath(path, realPath, sizeof(realPath)) == NULL) { - return; - } - fp = fopen(realPath, "r"); - if (fp == NULL) { - INIT_LOGE("open cfg error = %d", errno); - return; - } - - cmdLine = (CmdLine *)malloc(sizeof(CmdLine)); - if (cmdLine == NULL) { - INIT_LOGE("malloc cmdline error"); - fclose(fp); - return; - } - - while (fgets(buf, LOADCFG_BUF_SIZE - 1, fp) != NULL && maxLoop < LOADCFG_MAX_LOOP) { - maxLoop++; - len = strlen(buf); - if (len < 1) { - continue; - } - if (buf[len - 1] == '\n') { - buf[len - 1] = '\0'; // we replace '\n' with '\0' - } - (void)memset_s(cmdLine, sizeof(CmdLine), 0, sizeof(CmdLine)); - ParseCmdLine(buf, cmdLine); - DoCmd(cmdLine); - (void)memset_s(buf, sizeof(char) * LOADCFG_BUF_SIZE, 0, sizeof(char) * LOADCFG_BUF_SIZE); - } - free(cmdLine); - fclose(fp); -} - -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("Command write with invalid arguments"); - FreeCmd(ctx); - return; - } - - 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) -{ - struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); - if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("Command rmdir with invalid arguments"); - FreeCmd(ctx); - return; - } - - int ret = rmdir(ctx->argv[0]); - if (ret == -1) { - INIT_LOGE("Remove directory \" %s \" failed, err = %d", ctx->argv[0], errno); - } - FreeCmd(ctx); - return; -} - -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("Command reboot with invalid arguments"); - FreeCmd(ctx); - return; - } - DoReboot(cmdContent); - FreeCmd(ctx); - return; -} - -static void DoSetrlimit(const char *cmdContent, int maxArg) -{ - 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" - }; - // format: setrlimit resource curValue maxValue - struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); - const int rlimMaxPos = 2; - if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - 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 < ARRAY_LENGTH(resource); ++i) { - if (strcmp(ctx->argv[0], resource[i]) == 0) { - rcs = (int)i; - } - } - if (rcs == -1) { - 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); - } - } - FreeCmd(ctx); - return; -} - -static void DoRm(const char *cmdContent, int maxArg) -{ - struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); - if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("Command rm with invalid arguments"); - FreeCmd(ctx); - return; - } - int ret = unlink(ctx->argv[0]); - if (ret == -1) { - INIT_LOGE("Unlink %s failed, err = %d", ctx->argv[0], errno); - } - FreeCmd(ctx); - return; -} - -static void DoExport(const char *cmdContent, int maxArg) -{ - struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); - if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - 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("export env name \" %s \", value \" %s \" failed, err = %d ", - ctx->argv[0], ctx->argv[1], errno); - } - - FreeCmd(ctx); - return; -} - -static void DoExec(const char *cmdContent, int maxArg) -{ - pid_t pid = fork(); - if (pid < 0) { - INIT_LOGE("DoExec: failed to fork child process to exec \"%s\"", cmdContent); - return; - } - if (pid == 0) { - struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); - if (ctx == NULL || ctx->argv == NULL || ctx->argv[0] == NULL) { - INIT_LOGE("Command exec with invalid arguments"); - _exit(0x7f); - } -#ifdef OHOS_LITE - int ret = execve(ctx->argv[0], ctx->argv, NULL); -#else - int ret = execv(ctx->argv[0], ctx->argv); -#endif - if (ret == -1) { - INIT_LOGE("DoExec: execute \"%s\" failed: %d.", cmdContent, errno); - } - FreeCmd(ctx); - _exit(0x7f); - } - return; -} - -#ifndef __LITEOS__ -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("Command symlink with invalid arguments"); - FreeCmd(ctx); - return; - } - - int ret = symlink(ctx->argv[0], ctx->argv[1]); - if (ret != 0) { - INIT_LOGE("Link \" %s \" to target \" %s \" failed, err = %d", ctx->argv[0], ctx->argv[1], errno); - } - - FreeCmd(ctx); - return; -} - -static mode_t GetDeviceMode(const char *deviceStr) -{ - switch (*deviceStr) { - case 'b': - case 'B': - return S_IFBLK; - case 'c': - case 'C': - return S_IFCHR; - case 'f': - case 'F': - return S_IFIFO; - default: - return -1; - } -} - -static void DoMakeNode(const char *cmdContent, int maxArg) -{ - // format: mknod path b 0644 1 9 - struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); - const int deviceTypePos = 1; - const int authorityPos = 2; - const int majorDevicePos = 3; - const int minorDevicePos = 4; - - if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - INIT_LOGE("Command mknode with invalid arguments"); - FreeCmd(ctx); - return; - } - - if (!access(ctx->argv[1], F_OK)) { - 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 | mode, makedev(major, minor)); - if (ret != 0) { - INIT_LOGE("Create device node \" %s \" failed, err = %d", ctx->argv[0], errno); - } - } - - FreeCmd(ctx); - return; -} - -static void DoMakeDevice(const char *cmdContent, int maxArg) -{ - struct CmdArgs *ctx = GetCmd(cmdContent, " ", maxArg); - - if (ctx == NULL || ctx->argv == NULL || ctx->argc != maxArg) { - 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) { - FreeCmd(ctx); - return; - } - dev_t deviceId = makedev(major, minor); - if (deviceId < 0) { - INIT_LOGE("Make device with major %u, minor %u failed :%d ", major, minor, errno); - } - - FreeCmd(ctx); - return; -} -#endif // __LITEOS__ - -void DoCmd(const CmdLine *curCmd) -{ - // null curCmd or empty command, just quit. - if (curCmd == NULL || curCmd->name[0] == '\0') { - return; - } - DoCmdByName(curCmd->name, curCmd->cmdContent); -} - -struct CmdTable { - char name[MAX_CMD_NAME_LEN]; - int maxArg; - void (*DoFuncion)(const char *cmdContent, int maxArg); -}; - -static const struct CmdTable CMD_TABLE[] = { - { "start ", 1, DoStart }, - { "mkdir ", 4, DoMkDir }, - { "chmod ", 2, DoChmod }, - { "chown ", 3, DoChown }, - { "mount ", 10, DoMount }, - { "export ", 2, DoExport }, - { "loadcfg ", 1, DoLoadCfg }, - { "rm ", 1, DoRm }, - { "rmdir ", 1, DoRmdir }, - { "write ", 2, DoWrite }, - { "exec ", 10, DoExec }, -#ifndef OHOS_LITE - { "mknode ", 5, DoMakeNode }, - { "makedev ", 2, DoMakeDevice }, - { "symlink ", 2, DoSymlink }, - { "trigger ", 1, DoTriggerCmd }, - { "insmod ", 10, DoInsmod }, - { "setparam ", 2, DoSetParam }, - { "load_persist_params ", 1, DoLoadPersistParams }, - { "load_param ", 2, DoLoadDefaultParams }, - { "ifup ", 1, DoIfup }, -#endif - { "stop ", 1, DoStop }, - { "reset ", 1, DoReset }, - { "copy ", 2, DoCopy }, - { "reboot ", 1, DoRebootCmd }, - { "setrlimit ", 3, DoSetrlimit }, - { "sleep ", 1, DoSleep }, - { "hostname ", 1, DoSetHostname }, - { "domainname ", 1, DoSetDomainname } -}; - -void DoCmdByName(const char *name, const char *cmdContent) -{ - if (name == NULL || cmdContent == NULL) { - return; - } - - 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) { - CMD_TABLE[i].DoFuncion(cmdContent, CMD_TABLE[i].maxArg); - break; - } - } - if (i == cmdCnt) { - INIT_LOGE("DoCmd, unknown cmd name %s.", name); - } -} - -void ParseCmdLine(const char *cmdStr, CmdLine *resCmd) -{ - size_t cmdLineLen = 0; - if (cmdStr == NULL || resCmd == NULL || (cmdLineLen = strlen(cmdStr)) == 0) { - return; - } - - 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); - if (cmdLineLen > curCmdNameLen && cmdLineLen <= (curCmdNameLen + MAX_CMD_CONTENT_LEN) && - strncmp(CMD_TABLE[i].name, cmdStr, curCmdNameLen) == 0) { - if (memcpy_s(resCmd->name, MAX_CMD_NAME_LEN, cmdStr, curCmdNameLen) != EOK) { - break; - } - resCmd->name[curCmdNameLen] = '\0'; - - const char* cmdContent = cmdStr + curCmdNameLen; - size_t cmdContentLen = cmdLineLen - curCmdNameLen; - if (memcpy_s(resCmd->cmdContent, MAX_CMD_CONTENT_LEN, cmdContent, cmdContentLen) != EOK) { - break; - } - resCmd->cmdContent[cmdContentLen] = '\0'; - foundAndSucceed = 1; - break; - } - } - - if (!foundAndSucceed) { - INIT_LOGE("Cannot parse command: %s", cmdStr); - (void)memset_s(resCmd, sizeof(*resCmd), 0, sizeof(*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; -} diff --git a/services/src/init_import.c b/services/src/init_import.c deleted file mode 100644 index 6ce17de..0000000 --- a/services/src/init_import.c +++ /dev/null @@ -1,84 +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 "init_import.h" - -#include -#include "cJSON.h" -#include "init_cmds.h" -#include "init_log.h" -#include "init_read_cfg.h" -#include "securec.h" - -#ifndef OHOS_LITE -static int ExtractCfgFile(char **cfgFile, const char *content) -{ - if ((!cfgFile) || (!content)) { - return -1; - } - size_t cfgFileLen = strlen(content) + MAX_PARAM_VALUE_LEN + 1; - if (cfgFileLen <= 0) { - return -1; - } - if ((*cfgFile = malloc(cfgFileLen)) == NULL) { - INIT_LOGW("Failed to allocate memory to import cfg file. err = %d", errno); - return -1; - } - return GetParamValue(content, *cfgFile, cfgFileLen); -} -#endif - -void ParseAllImports(const cJSON *root) -{ - cJSON *importAttr = cJSON_GetObjectItemCaseSensitive(root, "import"); - char *cfgFile = NULL; - if (!cJSON_IsArray(importAttr)) { - return; - } - int importAttrSize = cJSON_GetArraySize(importAttr); - - for (int i = 0; i < importAttrSize; i++) { - cJSON *importItem = cJSON_GetArrayItem(importAttr, i); - if (!cJSON_IsString(importItem)) { - INIT_LOGE("Invalid type of import item. should be string"); - return; - } - char *importContent = cJSON_GetStringValue(importItem); - if (importContent == NULL) { - INIT_LOGE("cannot get import config file"); - return; - } -// Only OHOS L2 support parameter. -#ifndef OHOS_LITE - if (ExtractCfgFile(&cfgFile, importContent) < 0) { - INIT_LOGW("Failed to import from %s", importContent); - if (cfgFile != NULL) { - free(cfgFile); - cfgFile = NULL; - } - continue; - } -#else - cfgFile = importContent; -#endif - INIT_LOGI("Import %s...", cfgFile); - ParseInitCfg(cfgFile); - // Do not forget to free memory. - free(cfgFile); - cfgFile = NULL; - } - INIT_LOGD("parse import file done"); - return; -} diff --git a/services/src/init_read_cfg.c b/services/src/init_read_cfg.c deleted file mode 100644 index 732f7db..0000000 --- a/services/src/init_read_cfg.c +++ /dev/null @@ -1,166 +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 "init_read_cfg.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "init_import.h" -#include "init_jobs.h" -#include "init_log.h" -#include "init_perms.h" -#include "init_service_manager.h" -#include "init_utils.h" - -#ifndef OHOS_LITE -#include "init_param.h" -#endif -#include "securec.h" -#ifndef __LINUX__ -#ifdef OHOS_LITE -#include "init_stage.h" -#endif -#endif - -#define FILE_NAME_MAX_SIZE 100 -static void ParseInitCfgContents(const cJSON *root) -{ - if (root == NULL) { - INIT_LOGE("ParseInitCfgContents root is NULL"); - return; - } - // parse services - ParseAllServices(root); -#ifdef OHOS_LITE - // parse jobs - ParseAllJobs(root); -#else - ParseTriggerConfig(root); -#endif - - // parse imports - ParseAllImports(root); -} - -void ParseInitCfg(const char *configFile) -{ - if (configFile == NULL || *configFile == '\0') { - INIT_LOGE("Invalid config file"); - return; - } - - char *fileBuf = ReadFileToBuf(configFile); - if (fileBuf == NULL) { - INIT_LOGE("Read %s failed", configFile); - return; - } - cJSON* fileRoot = cJSON_Parse(fileBuf); - free(fileBuf); - fileBuf = NULL; - - if (fileRoot == NULL) { - INIT_LOGE("InitReadCfg, parse failed! please check file %s format.", configFile); - return; - } - ParseInitCfgContents(fileRoot); - // Release JSON object - cJSON_Delete(fileRoot); - return; -} - -static void ReadCfgs(const char *dirPath) -{ - DIR *pDir = opendir(dirPath); - if (pDir == NULL) { - INIT_LOGE("ParseCfgs open cfg dir :%s failed.%d", dirPath, errno); - return; - } - struct dirent *dp; - while ((dp = readdir(pDir)) != NULL) { - char fileName[FILE_NAME_MAX_SIZE]; - if (snprintf_s(fileName, FILE_NAME_MAX_SIZE, FILE_NAME_MAX_SIZE - 1, "%s/%s", dirPath, dp->d_name) == -1) { - INIT_LOGE("ParseCfgs snprintf_s failed."); - closedir(pDir); - return; - } - struct stat st; - if (stat(fileName, &st) == 0) { - if (strstr(dp->d_name, ".cfg") == NULL) { - continue; - } - INIT_LOGI("ReadCfgs :%s from %s success.", fileName, dirPath); - ParseInitCfg(fileName); - } - } - closedir(pDir); - return; -} - -static void ParseOtherCfgs() -{ - ReadCfgs("/system/etc/init"); - return; -} - -void InitReadCfg() -{ -#ifndef OHOS_LITE - InitParamService(); - 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(); - INIT_LOGI("Parse init config file done."); -#ifdef OHOS_SERVICE_DUMP - DumpAllServices(); -#endif - -#ifdef OHOS_LITE - // do jobs - DoJob("pre-init"); -#ifndef __LINUX__ - TriggerStage(EVENT1, EVENT1_WAITTIME, QS_STAGE1); -#endif - - DoJob("init"); -#ifndef __LINUX__ - TriggerStage(EVENT2, EVENT2_WAITTIME, QS_STAGE2); -#endif - - DoJob("post-init"); -#ifndef __LINUX__ - TriggerStage(EVENT3, EVENT3_WAITTIME, QS_STAGE3); - - InitStageFinished(); -#endif - ReleaseAllJobs(); -#else - PostTrigger(EVENT_TRIGGER_BOOT, "pre-init", strlen("pre-init")); - - PostTrigger(EVENT_TRIGGER_BOOT, "init", strlen("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 deleted file mode 100644 index 443c110..0000000 --- a/services/src/init_reboot.c +++ /dev/null @@ -1,216 +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 "init_reboot.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "init_log.h" -#include "init_service.h" -#include "init_service_manager.h" -#include "init_utils.h" -#include "securec.h" - -#define MAX_VALUE_LENGTH 500 -#define MAX_COMMAND_SIZE 20 -#define MAX_UPDATE_SIZE 100 - -struct RBMiscUpdateMessage { - char command[MAX_COMMAND_SIZE]; - char update[MAX_UPDATE_SIZE]; -}; - -static bool RBMiscWriteUpdaterMessage(const char *path, const struct RBMiscUpdateMessage *boot) -{ - if (path == NULL || boot == NULL) { - INIT_LOGE("path or boot is NULL."); - return false; - } - - char realPath[PATH_MAX] = {0}; - if (Realpath(path, realPath, sizeof(realPath)) == NULL) { - return false; - } - FILE *fp = fopen(realPath, "rb+"); - if (fp == NULL) { - INIT_LOGE("open %s failed", path); - return false; - } - - size_t ret = fwrite(boot, sizeof(struct RBMiscUpdateMessage), 1, fp); - if (ret < 0) { - INIT_LOGE("write to misc failed"); - (void)fclose(fp); - return false; - } - (void)fclose(fp); - return true; -} - -static bool RBMiscReadUpdaterMessage(const char *path, struct RBMiscUpdateMessage *boot) -{ - if (path == NULL || boot == NULL) { - INIT_LOGE("path or boot is NULL."); - return false; - } - char realPath[PATH_MAX] = {0}; - if (Realpath(path, realPath, sizeof(realPath)) == NULL) { - return false; - } - FILE *fp = fopen(realPath, "rb"); - if (fp == NULL) { - INIT_LOGE("open %s failed", path); - return false; - } - - size_t ret = fread(boot, 1, sizeof(struct RBMiscUpdateMessage), fp); - if (ret <= 0) { - INIT_LOGE("read to misc failed"); - (void)fclose(fp); - return false; - } - (void)fclose(fp); - return true; -} - -static int GetMountStatusForMountPoint(const char *mountPoint) -{ - const int bufferMaxSize = 512; - char buffer[bufferMaxSize]; - size_t n; - const char *mountFile = "/proc/mounts"; - FILE *fp = fopen(mountFile, "r"); - if (fp == NULL) { - INIT_LOGE("DoReboot %s can't open.", mountPoint); - return 1; - } - - while (fgets(buffer, sizeof(buffer) - 1, fp) != NULL) { - n = strlen(buffer); - if (buffer[n - 1] == '\n') { - buffer[n - 1] = '\0'; - } - if (strstr(buffer, mountPoint) != NULL) { - (void)fclose(fp); - return 1; - } - } - - // Cannot find it from system. - (void)fclose(fp); - return 0; -} - -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 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; - } - - if (RBMiscWriteUpdaterMessage(miscFile, &msg)) { - return reboot(RB_AUTOBOOT); - } - return -1; -} - -static int CheckRebootValue(const char *valueData) -{ - if (valueData == NULL) { - return 0; - } - static const char *g_cmdParams[] = { - "shutdown", "updater", "updater:", "flashing", "flashing:", "NoArgument", "bootloader" - }; - 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 valueData = %s, parameters error.", valueData); - return -1; - } - return 0; -} - -void DoReboot(const char *value) -{ -#ifndef OHOS_LITE - if (value == NULL || strlen(value) > MAX_VALUE_LENGTH) { - INIT_LOGE("DoReboot value = NULL"); - return; - } - const char *valueData = NULL; - if (strncmp(value, "reboot,", strlen("reboot,")) == 0) { - valueData = value + strlen("reboot,"); - } else if (strcmp(value, "reboot") != 0) { - INIT_LOGE("Reboot value = %s, must started with reboot", value); - return; - } - if (valueData != NULL) { - if (CheckRebootValue(valueData) < 0) { - return; - } - } - StopAllServicesBeforeReboot(); - sync(); - if (GetMountStatusForMountPoint("/vendor") != 0 && umount("/vendor") != 0) { - INIT_LOGE("DoReboot umount vendor failed! errno = %d.", errno); - } - if (GetMountStatusForMountPoint("/data") != 0 && umount("/data") != 0) { - INIT_LOGE("DoReboot umount data failed! errno = %d.", errno); - } - 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"); -#else - int ret = reboot(RB_AUTOBOOT); - if (ret != 0) { - INIT_LOGE("reboot failed! syscall ret %d, err %d.", ret, errno); - } -#endif - return; -} diff --git a/services/src/init_service_manager.c b/services/src/init_service_manager.c deleted file mode 100644 index 3529a3c..0000000 --- a/services/src/init_service_manager.c +++ /dev/null @@ -1,876 +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 "init_service_manager.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cJSON.h" -#include "init_adapter.h" -#include "init_jobs.h" -#include "init_log.h" -#include "init_perms.h" -#include "init_read_cfg.h" -#include "init_capability.h" -#include "init_service_socket.h" -#include "init_utils.h" -#include "securec.h" - -#define MIN_IMPORTANT_LEVEL (-20) -#define MAX_IMPORTANT_LEVEL 19 - -// All serivce processes that init will fork+exec. -static Service* g_services = NULL; -static int g_servicesCnt = 0; - -#ifdef OHOS_SERVICE_DUMP -void DumpAllServices(void) -{ - if (g_services == NULL) { - return; - } - INIT_LOGD("Ready to dump all services:"); - INIT_LOGD("total service number: %d", g_servicesCnt); - for (int i = 0; i < g_servicesCnt; i++) { - INIT_LOGD("\tservice name: [%s]", g_services[i].name); - INIT_LOGD("\tpath :"); - for (int j = 0; j < g_services[i].pathArgsCnt; j++) { - if (g_services[i].pathArgs[j] != NULL) { - INIT_LOGD(" %s", g_services[i].pathArgs[j]); - } - } - } - INIT_LOGD("Dump all services finished"); -} -#endif - -void RegisterServices(Service *services, int servicesCnt) -{ - if (services == NULL) { - return; - } - g_services = services; - g_servicesCnt += servicesCnt; -} - -static void ReleaseServiceMem(Service *curServ) -{ - if (curServ == NULL) { - return; - } - if (curServ->pathArgs != NULL) { - for (int i = 0; i < curServ->pathArgsCnt; ++i) { - if (curServ->pathArgs[i] != NULL) { - free(curServ->pathArgs[i]); - curServ->pathArgs[i] = NULL; - } - } - free(curServ->pathArgs); - curServ->pathArgs = NULL; - } - curServ->pathArgsCnt = 0; - - if (curServ->servPerm.caps != NULL) { - free(curServ->servPerm.caps); - curServ->servPerm.caps = NULL; - } - curServ->servPerm.capsCnt = 0; - for (int i = 0; i < MAX_WRITEPID_FILES; i++) { - if (curServ->writepidFiles[i] != NULL) { - free(curServ->writepidFiles[i]); - curServ->writepidFiles[i] = NULL; - } - } - - if (curServ->servPerm.gIDArray != NULL) { - free(curServ->servPerm.gIDArray); - curServ->servPerm.gIDArray = NULL; - } - curServ->servPerm.gIDCnt = 0; -} - -static int GetServiceName(const cJSON *curArrItem, Service *curServ) -{ - char* fieldStr = cJSON_GetStringValue(cJSON_GetObjectItem(curArrItem, "name")); - if (fieldStr == NULL) { - INIT_LOGE("GetServiceName cJSON_GetStringValue error"); - return SERVICE_FAILURE; - } - - size_t strLen = strlen(fieldStr); - if (strLen == 0 || strLen > MAX_SERVICE_NAME) { - INIT_LOGE("GetServiceName strLen = %d, error", strLen); - return SERVICE_FAILURE; - } - - if (memcpy_s(curServ->name, MAX_SERVICE_NAME, fieldStr, strLen) != EOK) { - INIT_LOGE("GetServiceName memcpy_s error"); - return SERVICE_FAILURE; - } - curServ->name[strLen] = '\0'; - return SERVICE_SUCCESS; -} - -#ifdef OHOS_LITE -static int IsForbidden(const char *fieldStr) -{ - size_t fieldLen = strlen(fieldStr); - size_t forbidStrLen = strlen(BIN_SH_NOT_ALLOWED); - if (fieldLen == forbidStrLen) { - if (strncmp(fieldStr, BIN_SH_NOT_ALLOWED, fieldLen) == 0) { - return 1; - } - return 0; - } else if (fieldLen > forbidStrLen) { - // "/bin/shxxxx" is valid but "/bin/sh xxxx" is invalid - if (strncmp(fieldStr, BIN_SH_NOT_ALLOWED, forbidStrLen) == 0) { - if (fieldStr[forbidStrLen] == ' ') { - return 1; - } - } - return 0; - } else { - return 0; - } -} -#else -static int IsForbidden(const char *fieldStr) -{ - return 0; -} -#endif - -static cJSON* GetArrItem(const cJSON *fileRoot, int *arrSize, const char *arrName) -{ - cJSON* arrItem = cJSON_GetObjectItemCaseSensitive(fileRoot, arrName); - if (!cJSON_IsArray(arrItem)) { - return NULL; - } - - *arrSize = cJSON_GetArraySize(arrItem); - if (*arrSize <= 0) { - return NULL; - } - return arrItem; -} - -static int GetWritepidStrings(const cJSON *curArrItem, Service *curServ) // writepid -{ - int writepidCnt = 0; - cJSON *filedJ = GetArrItem(curArrItem, &writepidCnt, "writepid"); - if ((writepidCnt <= 0) || (filedJ == NULL)) { // not item is ok. - return SERVICE_SUCCESS; - } - - if (writepidCnt > MAX_WRITEPID_FILES) { - INIT_LOGE("GetWritepidStrings, too many writepid[cnt %d] for one service, should not exceed %d.", - writepidCnt, MAX_WRITEPID_FILES); - return SERVICE_FAILURE; - } - - for (int i = 0; i < writepidCnt; ++i) { - cJSON *item = cJSON_GetArrayItem(filedJ, i); - if (item == NULL) { - return SERVICE_FAILURE; - } - char *fieldStr = cJSON_GetStringValue(item); - if ((fieldStr == NULL) || (fieldStr[0] == '\0')) { - return SERVICE_FAILURE; - } - size_t strLen = strlen(fieldStr); - curServ->writepidFiles[i] = (char *)malloc(sizeof(char) * strLen + 1); - if (curServ->writepidFiles[i] == NULL) { - INIT_LOGE("GetWritepidStrings, malloc item[%d] error.", i); - return SERVICE_FAILURE; - } - if (memcpy_s(curServ->writepidFiles[i], strLen + 1, fieldStr, strLen) != EOK) { - INIT_LOGE("GetWritepidStrings, memcpy_s error."); - return SERVICE_FAILURE; - } - curServ->writepidFiles[i][strLen] = '\0'; - } - - return SERVICE_SUCCESS; -} - -static int GetGidOneItem(const cJSON *curArrItem, Service *curServ) // gid one item -{ - cJSON *filedJ = cJSON_GetObjectItem(curArrItem, GID_STR_IN_CFG); - if (filedJ == NULL) { - return SERVICE_SUCCESS; // not found - } - curServ->servPerm.gIDCnt = 1; - curServ->servPerm.gIDArray = (gid_t *)malloc(sizeof(gid_t)); - if (curServ->servPerm.gIDArray == NULL) { - INIT_LOGE("GetGidOneItem, can't malloc, error."); - return SERVICE_FAILURE; - } - - if (cJSON_IsString(filedJ)) { - char *fieldStr = cJSON_GetStringValue(filedJ); - if (fieldStr == NULL) { - return SERVICE_FAILURE; - } - gid_t gID = DecodeUid(fieldStr); - if (gID == (gid_t)(-1)) { - INIT_LOGE("GetGidOneItem, DecodeUid %s error.", fieldStr); - return SERVICE_FAILURE; - } - curServ->servPerm.gIDArray[0] = gID; - return SERVICE_SUCCESS; - } - - if (cJSON_IsNumber(filedJ)) { - int value = (int)cJSON_GetNumberValue(filedJ); - if (value < 0) { - return SERVICE_FAILURE; - } - gid_t gID = value; - curServ->servPerm.gIDArray[0] = gID; - return SERVICE_SUCCESS; - } - - INIT_LOGE("GetGidOneItem, this gid is neither a string nor a number, error."); - return SERVICE_FAILURE; -} - -static int GetGidArray(const cJSON *curArrItem, Service *curServ) // gid array -{ - int gIDCnt = 0; - cJSON *filedJ = GetArrItem(curArrItem, &gIDCnt, GID_STR_IN_CFG); // "gid" must have 1 item. - if ((gIDCnt <= 0) || (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 *)calloc(sizeof(gid_t), gIDCnt); - if (curServ->servPerm.gIDArray == NULL) { - INIT_LOGE("GetGidArray malloc error"); - return SERVICE_FAILURE; - } - curServ->servPerm.gIDCnt = gIDCnt; - int i = 0; - for (; i < gIDCnt; ++i) { - cJSON *item = cJSON_GetArrayItem(filedJ, i); - if (item == NULL) { - break; - } - char *fieldStr = cJSON_GetStringValue(item); - if ((fieldStr == NULL) || (fieldStr[0] == '\0')) { - break; - } - gid_t gID = DecodeUid(fieldStr); - if ((gID) == (gid_t)(-1)) { - INIT_LOGE("GetGidArray, DecodeUid item[%d] error.", i); - return SERVICE_FAILURE; - } - curServ->servPerm.gIDArray[i] = gID; - } - INIT_CHECK_RETURN_VALUE(i != gIDCnt, SERVICE_SUCCESS); - for (i = 0; i < gIDCnt; ++i) { - cJSON *item = cJSON_GetArrayItem(filedJ, i); - if (item == NULL) { - break; - } - if (!cJSON_IsNumber(item)) { - break; - } - int value = (int)cJSON_GetNumberValue(item); - if (value < 0) { - break; - } - gid_t gID = value; - curServ->servPerm.gIDArray[i] = gID; - } - return (((i == gIDCnt) ? SERVICE_SUCCESS : SERVICE_FAILURE)); -} - -static int GetServicePathAndArgs(const cJSON *curArrItem, Service *curServ) -{ - cJSON* pathItem = cJSON_GetObjectItem(curArrItem, "path"); - if (!cJSON_IsArray(pathItem)) { - 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("Array size = %d is wrong", arrSize); - return SERVICE_FAILURE; - } - - curServ->pathArgs = (char **)malloc((arrSize + 1) * sizeof(char *)); - if (curServ->pathArgs == NULL) { - INIT_LOGE("Current path is null."); - return SERVICE_FAILURE; - } - for (int i = 0; i < arrSize + 1; ++i) { - curServ->pathArgs[i] = NULL; - } - curServ->pathArgsCnt = arrSize + 1; - - for (int i = 0; i < arrSize; ++i) { - char* curParam = cJSON_GetStringValue(cJSON_GetArrayItem(pathItem, i)); - if (curParam == NULL || strlen(curParam) > MAX_ONE_ARG_LEN) { - // resources will be released by function: ReleaseServiceMem - if (curParam == NULL) { - INIT_LOGE("Current param is null."); - } else { - 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("Service %s is forbidden.", curServ->name); - return SERVICE_FAILURE; - } - - size_t paramLen = strlen(curParam); - curServ->pathArgs[i] = (char*)malloc(paramLen + 1); - if (curServ->pathArgs[i] == NULL) { - // resources will be released by function: ReleaseServiceMem - INIT_LOGE("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("memcpy_s failed."); - return SERVICE_FAILURE; - } - curServ->pathArgs[i][paramLen] = '\0'; - } - return SERVICE_SUCCESS; -} - -static int GetImportantValue(int value, Service *curServ) -{ -#ifdef OHOS_LITE - if (value != 0) { - curServ->attribute |= SERVICE_ATTR_IMPORTANT; - } -#else - 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); - return SERVICE_FAILURE; - } -#endif - return SERVICE_SUCCESS; -} - -static int GetServiceNumber(const cJSON *curArrItem, Service *curServ, const char *targetField) -{ - cJSON* filedJ = cJSON_GetObjectItem(curArrItem, targetField); - if (filedJ == NULL && (strncmp(targetField, CRITICAL_STR_IN_CFG, strlen(CRITICAL_STR_IN_CFG)) == 0 - || strncmp(targetField, DISABLED_STR_IN_CFG, strlen(DISABLED_STR_IN_CFG)) == 0 - || strncmp(targetField, ONCE_STR_IN_CFG, strlen(ONCE_STR_IN_CFG)) == 0 - || strncmp(targetField, IMPORTANT_STR_IN_CFG, strlen(IMPORTANT_STR_IN_CFG)) == 0 - || strncmp(targetField, CONSOLE_STR_IN_CFG, strlen(CONSOLE_STR_IN_CFG)) == 0)) { - return SERVICE_SUCCESS; // not found "critical","disabled","once","importance","console" item is ok - } - - if (!cJSON_IsNumber(filedJ)) { - INIT_LOGE("%s is null or is not a number, service name is %s", targetField, curServ->name); - return SERVICE_FAILURE; - } - - int value = (int)cJSON_GetNumberValue(filedJ); - // importance value allow < 0 - if (strncmp(targetField, IMPORTANT_STR_IN_CFG, strlen(IMPORTANT_STR_IN_CFG)) != 0) { - if (value < 0) { - INIT_LOGE("Service %s value = %d is wrong", curServ->name, value); - return SERVICE_FAILURE; - } - } - - if (strncmp(targetField, ONCE_STR_IN_CFG, strlen(ONCE_STR_IN_CFG)) == 0) { - if (value != 0) { - curServ->attribute |= SERVICE_ATTR_ONCE; - } - } else if (strncmp(targetField, IMPORTANT_STR_IN_CFG, strlen(IMPORTANT_STR_IN_CFG)) == 0) { - INIT_CHECK_RETURN_VALUE(GetImportantValue(value, curServ) == SERVICE_SUCCESS, SERVICE_FAILURE); - } else if (strncmp(targetField, CRITICAL_STR_IN_CFG, strlen(CRITICAL_STR_IN_CFG)) == 0) { // set critical - curServ->attribute &= ~SERVICE_ATTR_CRITICAL; - if (value == 1) { - curServ->attribute |= SERVICE_ATTR_CRITICAL; - } - } else if (strncmp(targetField, DISABLED_STR_IN_CFG, strlen(DISABLED_STR_IN_CFG)) == 0) { // set disabled - curServ->attribute &= ~SERVICE_ATTR_DISABLED; - if (value == 1) { - curServ->attribute |= SERVICE_ATTR_DISABLED; - } - } else if (strncmp(targetField, CONSOLE_STR_IN_CFG, strlen(CONSOLE_STR_IN_CFG)) == 0) { // set console - curServ->attribute &= ~SERVICE_ATTR_CONSOLE; - if (value == 1) { - curServ->attribute |= SERVICE_ATTR_CONSOLE; - } - } else { - INIT_LOGE("Item = %s, not expected, error.service name is %s", targetField, curServ->name); - return SERVICE_FAILURE; - } - return SERVICE_SUCCESS; -} - -static int GetUidStringNumber(const cJSON *curArrItem, Service *curServ) -{ - cJSON *filedJ = cJSON_GetObjectItem(curArrItem, UID_STR_IN_CFG); - if (filedJ == NULL) { - return SERVICE_SUCCESS; // uID not found, but ok. - } - - if (cJSON_IsString(filedJ)) { - char *fieldStr = cJSON_GetStringValue(filedJ); - if (fieldStr == NULL) { - return SERVICE_FAILURE; - } - uid_t uID = DecodeUid(fieldStr); - if (uID == (uid_t)-1) { - INIT_LOGE("Decode uid %s error.", fieldStr); - return SERVICE_FAILURE; - } - curServ->servPerm.uID = uID; - return SERVICE_SUCCESS; - } - - if (cJSON_IsNumber(filedJ)) { - int uID = (int)cJSON_GetNumberValue(filedJ); - if (uID < 0) { - INIT_LOGE("Uid = %d error.", uID); - return SERVICE_FAILURE; - } - curServ->servPerm.uID = uID; - return SERVICE_SUCCESS; - } - - INIT_LOGE("This uid is neither a string nor a number, error."); - return SERVICE_FAILURE; -} - -static int ParseServiceSocket(char **opt, const int optNum, struct ServiceSocket *sockopt) -{ - if (optNum != SOCK_OPT_NUMS) { - return -1; - } - if (opt[SERVICE_SOCK_TYPE] == NULL) { - return -1; - } - sockopt->type = - ((strncmp(opt[SERVICE_SOCK_TYPE], "stream", strlen(opt[SERVICE_SOCK_TYPE])) == 0) ? SOCK_STREAM : - ((strncmp(opt[SERVICE_SOCK_TYPE], "dgram", strlen(opt[SERVICE_SOCK_TYPE])) == 0) ? SOCK_DGRAM : SOCK_SEQPACKET)); - - if (opt[SERVICE_SOCK_PERM] == NULL) { - return -1; - } - sockopt->perm = strtoul(opt[SERVICE_SOCK_PERM], 0, OCTAL_BASE); - if (opt[SERVICE_SOCK_UID] == NULL) { - return -1; - } - uid_t uid = DecodeUid(opt[SERVICE_SOCK_UID]); - if (uid == (uid_t)-1) { - return -1; - } - sockopt->uid = uid; - if (opt[SERVICE_SOCK_GID] == NULL) { - return -1; - } - gid_t gid = DecodeUid(opt[SERVICE_SOCK_GID]); - if (gid == (gid_t)-1) { - return -1; - } - 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); - if (opt[SERVICE_SOCK_NAME] == NULL) { - return -1; - } - sockopt->name = (char *)calloc(MAX_SOCK_NAME_LEN, sizeof(char)); - if (sockopt->name == NULL) { - return -1; - } - int ret = memcpy_s(sockopt->name, MAX_SOCK_NAME_LEN, opt[SERVICE_SOCK_NAME], MAX_SOCK_NAME_LEN - 1); - if (ret != 0) { - free(sockopt->name); - sockopt->name = NULL; - return -1; - } - sockopt->next = NULL; - sockopt->sockFd = -1; - return 0; -} - -static void FreeServiceSocket(struct ServiceSocket *sockopt) -{ - if (sockopt == NULL) { - return; - } - struct ServiceSocket *tmpSock = NULL; - while (sockopt != NULL) { - tmpSock = sockopt; - if (sockopt->name != NULL) { - free(sockopt->name); - sockopt->name = NULL; - } - sockopt = tmpSock->next; - free(tmpSock); - } - return; -} - -static int GetServiceSocket(const cJSON *curArrItem, Service *curServ) -{ - cJSON* filedJ = cJSON_GetObjectItem(curArrItem, "socket"); - if (!cJSON_IsArray(filedJ)) { - return SERVICE_FAILURE; - } - - int sockCnt = cJSON_GetArraySize(filedJ); - if (sockCnt <= 0) { - return SERVICE_FAILURE; - } - curServ->socketCfg = NULL; - for (int i = 0; i < sockCnt; ++i) { - cJSON *sockJ = cJSON_GetArrayItem(filedJ, i); - if (!cJSON_IsString(sockJ) || !cJSON_GetStringValue(sockJ)) { - return SERVICE_FAILURE; - } - char *sockStr = cJSON_GetStringValue(sockJ); - char *tmpStr[SOCK_OPT_NUMS] = {NULL}; - int num = SplitString(sockStr, tmpStr, SOCK_OPT_NUMS); - if (num != SOCK_OPT_NUMS) { - return SERVICE_FAILURE; - } - struct ServiceSocket *socktmp = (struct ServiceSocket *)calloc(1, sizeof(struct ServiceSocket)); - if (socktmp == NULL) { - return SERVICE_FAILURE; - } - int ret = ParseServiceSocket(tmpStr, SOCK_OPT_NUMS, socktmp); - if (ret < 0) { - free(socktmp); - socktmp = NULL; - return SERVICE_FAILURE; - } - if (curServ->socketCfg == NULL) { - curServ->socketCfg = socktmp; - } else { - socktmp->next = curServ->socketCfg->next; - curServ->socketCfg->next = socktmp; - } - } - return SERVICE_SUCCESS; -} - -static int GetServiceOnRestart(const cJSON *curArrItem, Service *curServ) -{ - cJSON* filedJ = cJSON_GetObjectItem(curArrItem, "onrestart"); - if (filedJ == NULL) { - return SERVICE_SUCCESS; // onrestart not found, but ok. - } - if (!cJSON_IsArray(filedJ)) { - return SERVICE_FAILURE; - } - int cmdCnt = cJSON_GetArraySize(filedJ); - if (cmdCnt <= 0) { - return SERVICE_FAILURE; - } - curServ->onRestart = (struct OnRestartCmd *)calloc(1, sizeof(struct OnRestartCmd)); - if (curServ->onRestart == NULL) { - return SERVICE_FAILURE; - } - curServ->onRestart->cmdLine = (CmdLine *)calloc(cmdCnt, sizeof(CmdLine)); - if (curServ->onRestart->cmdLine == NULL) { - free(curServ->onRestart); - curServ->onRestart = NULL; - return SERVICE_FAILURE; - } - curServ->onRestart->cmdNum = cmdCnt; - for (int i = 0; i < cmdCnt; ++i) { - cJSON* cmdJ = cJSON_GetArrayItem(filedJ, i); - if (!cJSON_IsString(cmdJ) || !cJSON_GetStringValue(cmdJ)) { - free(curServ->onRestart->cmdLine); - curServ->onRestart->cmdLine = NULL; - free(curServ->onRestart); - curServ->onRestart = NULL; - return SERVICE_FAILURE; - } - char *cmdStr = cJSON_GetStringValue(cmdJ); - ParseCmdLine(cmdStr, &curServ->onRestart->cmdLine[i]); - } - return SERVICE_SUCCESS; -} - -static bool IsServiceInMainStrap(const 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", "dynamic" - }; - if (curService == NULL) { - return SERVICE_FAILURE; - } - cJSON *child = curService->child; - if (child == NULL) { - return SERVICE_FAILURE; - } - while (child != NULL) { - int i = 0; - int keyListSize = ARRAY_LENGTH(cfgServiceKeyList); - for (; i < keyListSize; i++) { - if (strcmp(child->string, cfgServiceKeyList[i]) == 0) { - break; - } - } - if (i < keyListSize) { - child = child->next; - } else { - INIT_LOGE("CheckServiceKeyName, key name %s is not found. error.", child->string); - return SERVICE_FAILURE; - } - } - 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); - if (ret < 0) { - return SERVICE_FAILURE; - } else { - return SERVICE_SUCCESS; - } -} - -void ParseAllServices(const cJSON *fileRoot) -{ - int servArrSize = 0; - cJSON* serviceArr = GetArrItem(fileRoot, &servArrSize, SERVICES_ARR_NAME_IN_JSON); - 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); - - Service* retServices = (Service*)realloc(g_services, sizeof(Service) * (g_servicesCnt + servArrSize)); - 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) { - free(retServices); - retServices = NULL; - return; - } - - for (int i = 0; i < servArrSize; ++i) { - cJSON* curItem = cJSON_GetArrayItem(serviceArr, i); - if (CheckServiceKeyName(curItem) != SERVICE_SUCCESS) { - ReleaseServiceMem(&tmp[i]); - tmp[i].attribute |= SERVICE_ATTR_INVALID; - continue; - } - int 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("Parse information for service %s failed. ", tmp[i].name); - continue; - } else { - 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) { - FreeServiceSocket(tmp[i].socketCfg); - tmp[i].socketCfg = NULL; - } - } - if (GetServiceOnRestart(curItem, &tmp[i]) == SERVICE_FAILURE) { - INIT_LOGE("Failed Get Service OnRestart service"); - } - } - // Increase service counter. - RegisterServices(retServices, servArrSize); -} - -static int FindServiceByName(const char *servName) -{ - if ((servName == NULL) || (g_services == NULL)) { - return -1; - } - - for (int i = 0; i < g_servicesCnt; ++i) { - if (strlen(g_services[i].name) == strlen(servName) && - strncmp(g_services[i].name, servName, strlen(g_services[i].name)) == 0) { - return i; - } - } - return -1; -} - -void StartServiceByName(const char *servName, bool checkDynamic) -{ - // find service by name - int servIdx = FindServiceByName(servName); - if (servIdx < 0) { - 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("Service %s start failed!", g_services[servIdx].name); - } - return; -} - -void StopServiceByName(const char *servName) -{ - // find service by name - int servIdx = FindServiceByName(servName); - if (servIdx < 0) { - INIT_LOGE("Cannot find service %s.", servName); - return; - } - - if (ServiceStop(&g_services[servIdx]) != SERVICE_SUCCESS) { - INIT_LOGE("Service %s start failed!", g_services[servIdx].name); - } - - return; -} - -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("Service %s stop failed!", g_services[i].name); - } - } -} - -void StopAllServicesBeforeReboot(void) -{ - if (g_services == NULL) { - return; - } - - for (int i = 0; i < g_servicesCnt; i++) { - g_services[i].attribute |= SERVICE_ATTR_INVALID; - if (ServiceStop(&g_services[i]) != SERVICE_SUCCESS) { - INIT_LOGE("Service %s stop failed!", g_services[i].name); - } - } -} - -void ReapServiceByPID(int pid) -{ - if (g_services == NULL) { - return; - } - - for (int i = 0; i < g_servicesCnt; i++) { - if (g_services[i].pid == pid) { -#ifdef OHOS_LITE - if (g_services[i].attribute & SERVICE_ATTR_IMPORTANT) { - // important process exit, need to reboot system - g_services[i].pid = -1; - StopAllServices(); - RebootSystem(); - } -#endif - ServiceReap(&g_services[i]); - break; - } - } -} - diff --git a/services/src/init_service_socket.c b/services/src/init_service_socket.c deleted file mode 100644 index a509296..0000000 --- a/services/src/init_service_socket.c +++ /dev/null @@ -1,138 +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 "init_service_socket.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "init_log.h" -#include "securec.h" - -#define HOS_SOCKET_DIR "/dev/unix/socket" -#define HOS_SOCKET_ENV_PREFIX "OHOS_SOCKET_" -#define MAX_SOCKET_ENV_PREFIX_LEN 64 -#define MAX_SOCKET_FD_LEN 16 - -static int CreateSocket(struct ServiceSocket *sockopt) -{ - if (sockopt == NULL || sockopt->name == NULL) { - return -1; - } - if (sockopt->sockFd >= 0) { - close(sockopt->sockFd); - sockopt->sockFd = -1; - } - sockopt->sockFd = socket(PF_UNIX, sockopt->type, 0); - INIT_ERROR_CHECK(sockopt->sockFd >= 0, return -1, "socket fail %d ", errno); - - struct sockaddr_un 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) { - return -1; - } - if (access(addr.sun_path, F_OK) == 0) { - INIT_LOGE("%s already exist, remove it", addr.sun_path); - if (unlink(addr.sun_path) != 0) { - INIT_LOGE("ulink fail err %d ", errno); - } - } - if (sockopt->passcred) { - int on = 1; - if (setsockopt(sockopt->sockFd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) { - unlink(addr.sun_path); - close(sockopt->sockFd); - return -1; - } - } - - if (bind(sockopt->sockFd, (struct sockaddr *)&addr, sizeof(addr))) { - INIT_LOGE("Create socket for service %s failed: %d", sockopt->name, errno); - unlink(addr.sun_path); - close(sockopt->sockFd); - return -1; - } - - if (lchown(addr.sun_path, sockopt->uid, sockopt->gid)) { - unlink(addr.sun_path); - close(sockopt->sockFd); - INIT_LOGE("lchown fail %d ", errno); - return -1; - } - - if (fchmodat(AT_FDCWD, addr.sun_path, sockopt->perm, AT_SYMLINK_NOFOLLOW)) { - unlink(addr.sun_path); - close(sockopt->sockFd); - INIT_LOGE("fchmodat fail %d ", errno); - return -1; - } - INIT_LOGI("CreateSocket success "); - return sockopt->sockFd; -} - -static int SetSocketEnv(int fd, const char *name) -{ - if (name == NULL) { - return -1; - } - char pubName[MAX_SOCKET_ENV_PREFIX_LEN] = {0}; - char val[MAX_SOCKET_FD_LEN] = {0}; - if (snprintf_s(pubName, MAX_SOCKET_ENV_PREFIX_LEN, MAX_SOCKET_ENV_PREFIX_LEN - 1, - HOS_SOCKET_ENV_PREFIX"%s", name) < 0) { - return -1; - } - if (snprintf_s(val, MAX_SOCKET_FD_LEN, MAX_SOCKET_FD_LEN - 1, "%d", fd) < 0) { - return -1; - } - int ret = setenv(pubName, val, 1); - if (ret < 0) { - INIT_LOGE("setenv fail %d ", errno); - return -1; - } - fcntl(fd, F_SETFD, 0); - return 0; -} - -int DoCreateSocket(struct ServiceSocket *sockopt) -{ - if (sockopt == NULL) { - return -1; - } - struct ServiceSocket *tmpSock = sockopt; - while (tmpSock != NULL) { - int fd = CreateSocket(tmpSock); - if (fd < 0) { - return -1; - } - if (tmpSock->name == NULL) { - return -1; - } - int ret = SetSocketEnv(fd, tmpSock->name); - if (ret < 0) { - return -1; - } - tmpSock = tmpSock->next; - } - return 0; -} - diff --git a/services/src/main.c b/services/src/main.c deleted file mode 100644 index d3239e0..0000000 --- a/services/src/main.c +++ /dev/null @@ -1,128 +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 -#include -#include -#include -#include - -#ifdef OHOS_DEBUG -#include -#endif // OHOS_DEBUG - -#include - -#include "init_adapter.h" -#include "init_log.h" -#include "init_read_cfg.h" -#include "init_signal_handler.h" -#ifdef OHOS_LITE -#include "parameter.h" -#endif - -#ifndef OHOS_LITE -#include "device.h" -#include "init_param.h" -#endif -#include "init_utils.h" - -static const pid_t INIT_PROCESS_PID = 1; - -static void PrintSysInfo() -{ -#ifdef OHOS_LITE - const char* sysInfo = GetVersionId(); - if (sysInfo != NULL) { - INIT_LOGE("%s", sysInfo); - return; - } - INIT_LOGE("main, GetVersionId failed!"); -#endif -} - -#ifdef OHOS_DEBUG -static long TimeDiffMs(const struct timespec* tmBefore, const struct timespec* tmAfter) -{ - if (tmBefore != NULL && tmAfter != NULL) { - long timeUsed = (tmAfter->tv_sec - tmBefore->tv_sec) * 1000 + // 1 s = 1000 ms - (tmAfter->tv_nsec - tmBefore->tv_nsec) / 1000000L; // 1 ms = 1000000 ns - return timeUsed; - } - return -1; -} -#endif // OHOS_DEBUG - -int main(int argc, char **argv) -{ -#ifndef OHOS_LITE - INIT_CHECK_ONLY_ELOG(setenv("UV_THREADPOOL_SIZE", "1", 1) == 0, "set UV_THREADPOOL_SIZE error : %d.", errno); - CloseStdio(); - OpenLogDevice(); -#endif - -#ifdef OHOS_DEBUG - struct timespec tmEnter; - INIT_CHECK_ONLY_ELOG(clock_gettime(CLOCK_REALTIME, &tmEnter) == 0, - "main, enter, get time failed! err %d.\n", errno); -#endif // OHOS_DEBUG - - if (getpid() != INIT_PROCESS_PID) { - INIT_LOGE("main, current process id is %d not %d, failed!", getpid(), INIT_PROCESS_PID); - return 0; - } - PrintSysInfo(); - -#ifndef OHOS_LITE - MountBasicFs(); - CreateDeviceNode(); - EnableDevKmsg(); - MakeDirRecursive("/dev/unix/socket", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); -#endif - - SignalInitModule(); - -#ifdef OHOS_DEBUG - struct timespec tmSysInfo; - INIT_CHECK_ONLY_ELOG(clock_gettime(CLOCK_REALTIME, &tmSysInfo) == 0, - "main, after sysinfo, get time failed! err %d.", errno); -#endif // OHOS_DEBUG - - ExecuteRcs(); - -#ifdef OHOS_DEBUG - struct timespec tmRcs; - INIT_CHECK_ONLY_ELOG(clock_gettime(CLOCK_REALTIME, &tmRcs) == 0, - "main, after rcs, get time failed! err %d.", errno); -#endif // OHOS_DEBUG - InitReadCfg(); -#ifdef OHOS_DEBUG - struct timespec tmCfg; - INIT_CHECK_ONLY_ELOG(clock_gettime(CLOCK_REALTIME, &tmCfg) == 0, "main, get time failed! err %d.", errno); -#endif // OHOS_DEBUG - -#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)); -#endif - - INIT_LOGI("main, entering wait."); -#ifndef OHOS_LITE - StartParamService(); -#endif - while (1) { - (void)pause(); - } - return 0; -} diff --git a/services/test/unittest/BUILD.gn b/services/test/unittest/BUILD.gn new file mode 100755 index 0000000..1686f18 --- /dev/null +++ b/services/test/unittest/BUILD.gn @@ -0,0 +1,145 @@ +# 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/test.gni") + +config("utest_config") { + visibility = [ ":*" ] + + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "-Wno-implicit-fallthrough", + "-Wno-unused-function", + ] + cflags_cc = [ + "-Wno-implicit-fallthrough", + "-fexceptions", + ] + + ldflags = [ "--coverage" ] +} + +ohos_unittest("init_ut") { + module_out_path = "startup/init" + sources = [ + "//base/startup/init_lite/services/init/adapter/init_adapter.c", + "//base/startup/init_lite/services/init/init_capability.c", + "//base/startup/init_lite/services/init/init_common_cmds.c", + "//base/startup/init_lite/services/init/init_config.c", + "//base/startup/init_lite/services/init/init_common_service.c", + "//base/startup/init_lite/services/init/init_service_manager.c", + "//base/startup/init_lite/services/init/init_service_socket.c", + "//base/startup/init_lite/services/init/standard/device.c", + "//base/startup/init_lite/services/init/standard/init.c", + "//base/startup/init_lite/services/init/standard/init_cmds.c", + "//base/startup/init_lite/services/init/standard/init_jobs.c", + "//base/startup/init_lite/services/init/standard/init_reboot.c", + "//base/startup/init_lite/services/init/standard/init_service.c", + "//base/startup/init_lite/services/init/standard/init_signal_handler.c", + "//base/startup/init_lite/services/log/init_log.c", + "//base/startup/init_lite/services/param/adapter/param_dac.c", + "//base/startup/init_lite/services/param/adapter/param_libuvadp.c", + "//base/startup/init_lite/services/param/adapter/param_persistadp.c", + "//base/startup/init_lite/services/param/adapter/param_selinux.c", + "//base/startup/init_lite/services/param/client/param_request.c", + "//base/startup/init_lite/services/param/cmd/param_cmd.c", + "//base/startup/init_lite/services/param/manager/param_manager.c", + "//base/startup/init_lite/services/param/manager/param_message.c", + "//base/startup/init_lite/services/param/manager/param_trie.c", + "//base/startup/init_lite/services/param/manager/param_utils.c", + "//base/startup/init_lite/services/param/service/param_persist.c", + "//base/startup/init_lite/services/param/service/param_service.c", + "//base/startup/init_lite/services/param/trigger/trigger_checker.c", + "//base/startup/init_lite/services/param/trigger/trigger_manager.c", + "//base/startup/init_lite/services/param/trigger/trigger_processor.c", + "//base/startup/init_lite/services/param/watcher/agent/watcher.cpp", + "//base/startup/init_lite/services/param/watcher/agent/watcher_manager_kits.cpp", + "//base/startup/init_lite/services/param/watcher/agent/watcher_manager_proxy.cpp", + "//base/startup/init_lite/services/param/watcher/agent/watcher_stub.cpp", + "//base/startup/init_lite/services/param/watcher/proxy/watcher_manager.cpp", + "//base/startup/init_lite/services/param/watcher/proxy/watcher_manager_stub.cpp", + "//base/startup/init_lite/services/param/watcher/proxy/watcher_proxy.cpp", + "//base/startup/init_lite/services/utils/init_utils.c", + "//base/startup/init_lite/services/utils/list.c", + ] + + sources += [ + "init/cmds_unittest.cpp", + "init/service_unittest.cpp", + "param/client_unittest.cpp", + "param/dac_unittest.cpp", + "param/param_unittest.cpp", + "param/selinux_unittest.cpp", + "param/trigger_unittest.cpp", + "param/watcher_agent_unittest.cpp", + "param/watcher_proxy_unittest.cpp", + ] + + configs = [ "//base/startup/init_lite/services/test/unittest:utest_config" ] + + include_dirs = [ + "//base/startup/init_lite/services/include", + "//base/startup/init_lite/services/init/include", + "//base/startup/init_lite/services/include/param", + "//base/startup/init_lite/services/log", + "//base/startup/init_lite/services/param/adapter", + "//base/startup/init_lite/services/param/include", + "//base/startup/init_lite/services/param/watcher/agent", + "//base/startup/init_lite/services/param/watcher/include", + "//base/startup/init_lite/services/param/watcher/proxy", + "//base/startup/init_lite/services/test/unittest", + "//base/startup/init_lite/services/test/unittest/param", + "//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", + "//utils/native/base/include", + "//utils/system/safwk/native/include", + "//third_party/bounds_checking_function/include", + "//third_party/libuv/include", + "//third_party/cJSON", + ] + + deps = [ + "//third_party/bounds_checking_function:libsec_static", + "//third_party/cJSON:cjson_static", + "//third_party/googletest:gmock", + "//third_party/googletest:gtest", + "//third_party/libuv:uv_static", + "//utils/native/base:utils", + ] + + defines = [ + "INIT_AGENT", + "STARTUP_INIT_TEST", + "PARAM_SUPPORT_SAVE_PERSIST", + "PARAM_SUPPORT_DAC", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr_L2:samgr_proxy", + ] + + cflags_cc = [ "-fexceptions" ] +} + +group("init_test") { + testonly = true + deps = [ + ":init_ut" + ] +} diff --git a/services/test/unittest/common/BUILD.gn b/services/test/unittest/common/BUILD.gn old mode 100644 new mode 100755 index 38ea9fb..e1503a2 --- a/services/test/unittest/common/BUILD.gn +++ b/services/test/unittest/common/BUILD.gn @@ -29,9 +29,8 @@ if (defined(ohos_lite)) { include_dirs = [ "//base/startup/init_lite/services/include", - "//base/startup/init_lite/services/param/include", + "//base/startup/init_lite/services/init/include", "//base/startup/init_lite/services/log", - "//base/startup/init_lite/services/utils", "//third_party/cJSON", "//third_party/bounds_checking_function/include", "//base/startup/syspara_lite/interfaces/kits", @@ -39,19 +38,22 @@ if (defined(ohos_lite)) { ] sources = [ + "//base/startup/init_lite/services/init/adapter/init_adapter.c", + "//base/startup/init_lite/services/init/init_capability.c", + "//base/startup/init_lite/services/init/init_common_cmds.c", + "//base/startup/init_lite/services/init/init_config.c", + "//base/startup/init_lite/services/init/init_common_service.c", + "//base/startup/init_lite/services/init/init_service_manager.c", + "//base/startup/init_lite/services/init/init_service_socket.c", + "//base/startup/init_lite/services/init/lite/init.c", + "//base/startup/init_lite/services/init/lite/init_cmds.c", + "//base/startup/init_lite/services/init/lite/init_jobs.c", + "//base/startup/init_lite/services/init/lite/init_reboot.c", + "//base/startup/init_lite/services/init/lite/init_service.c", + "//base/startup/init_lite/services/init/lite/init_signal_handler.c", "//base/startup/init_lite/services/log/init_log.c", - "//base/startup/init_lite/services/src/init_adapter.c", - "//base/startup/init_lite/services/src/init_capability.c", - "//base/startup/init_lite/services/src/init_cmds.c", - "//base/startup/init_lite/services/src/init_import.c", - "//base/startup/init_lite/services/src/init_jobs.c", - "//base/startup/init_lite/services/src/init_read_cfg.c", - "//base/startup/init_lite/services/src/init_reboot.c", - "//base/startup/init_lite/services/src/init_service.c", - "//base/startup/init_lite/services/src/init_service_manager.c", - "//base/startup/init_lite/services/src/init_service_socket.c", - "//base/startup/init_lite/services/src/init_signal_handler.c", "//base/startup/init_lite/services/utils/init_utils.c", + "//base/startup/init_lite/services/utils/list.c", "cmd_func_test.cpp", ] diff --git a/services/test/unittest/common/cmd_func_test.cpp b/services/test/unittest/common/cmd_func_test.cpp old mode 100644 new mode 100755 index 03a92d5..41f8139 --- a/services/test/unittest/common/cmd_func_test.cpp +++ b/services/test/unittest/common/cmd_func_test.cpp @@ -12,19 +12,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include #include #include #include +#include #include #include #include + #include "cJSON.h" -#include "gtest/gtest.h" -#include "securec.h" +#include "init_cmds.h" #include "init_jobs.h" #include "init_service_manager.h" +#include "securec.h" +#include "gtest/gtest.h" +using namespace std; using namespace testing::ext; namespace OHOS { @@ -37,7 +40,6 @@ const std::string TEST_PROC_MOUNTS = "/proc/mounts"; const uid_t TEST_FILE_UID = 999; const gid_t TEST_FILE_GID = 999; const mode_t TEST_FILE_MODE = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; -const mode_t DEFAULT_DIR_MODE = 0755; // init.cfg releated const std::string CFG_FILE = "/etc/init.cfg"; @@ -47,14 +49,14 @@ const std::string CMDS_ARR_NAME_IN_JSON = "cmds"; const uid_t CFG_FILE_UID = 0; const gid_t CFG_FILE_GID = 0; const mode_t CFG_FILE_MODE = S_IRUSR; -const int JOBS_IN_FILE_COUNT = 3; // pre-init, init, post-init +const int JOBS_IN_FILE_COUNT = 3; // pre-init, init, post-init const int MAX_SERVICES_COUNT_IN_FILE = 100; const int MAX_CAPS_CNT_FOR_ONE_SERVICE = 100; -const unsigned int MAX_CAPABILITY_VALUE = 4294967295; // 0xFFFFFFFF -const unsigned int MAX_JSON_FILE_LEN = 102400; // max init.cfg size 100KB -const int MAX_PATH_ARGS_CNT = 20; // max path and args count -const int MAX_ONE_ARG_LEN = 64; // max length of one param/path -const int CAT_BUF_SIZE = 512; // standard Cat buffer size from vfs_shell_cmd +const unsigned int MAX_CAPABILITY_VALUE = 4294967295; // 0xFFFFFFFF +const unsigned int MAX_JSON_FILE_LEN = 102400; // max init.cfg size 100KB +const int TEST_MAX_PATH_ARGS_CNT = 20; // max path and args count +const int TEST_MAX_ONE_ARG_LEN = 64; // max length of one param/path +const int CAT_BUF_SIZE = 512; // standard Cat buffer size from vfs_shell_cmd // job test releated const pid_t INVALID_PID = -1; @@ -62,6 +64,11 @@ const std::string PRE_INIT_DIR = ROOT_DIR + "preInitDir/"; const std::string INIT_DIR = PRE_INIT_DIR + "initDir"; const std::string POST_INIT_DIR = INIT_DIR + "postInitDir"; +using TestCmdLine = struct { + char name[MAX_CMD_NAME_LEN + 1]; + char cmdContent[MAX_CMD_CONTENT_LEN + 1]; +}; + class StartupInitUTest : public testing::Test { public: static void SetUpTestCase() @@ -72,8 +79,7 @@ public: g_supportedCmds.push_back(std::string("chown ")); g_supportedCmds.push_back(std::string("mount ")); g_supportedCmds.push_back(std::string("loadcfg ")); - - mode_t mode = DEFAULT_DIR_MODE; + const mode_t mode = 0755; if (mkdir(TEST_DRI.c_str(), mode) != 0) { if (errno != EEXIST) { printf("[----------] StartupInitUTest, mkdir for %s failed, error %d.\n",\ @@ -82,7 +88,7 @@ public: } } - FILE* testFile = fopen(TEST_FILE.c_str(), "w+"); + FILE *testFile = fopen(TEST_FILE.c_str(), "w+"); if (testFile == nullptr) { printf("[----------] StartupInitUTest, open file %s failed, error %d.\n",\ TEST_FILE.c_str(), errno); @@ -129,6 +135,41 @@ public: void TearDown() {} }; +void ParseCmdLine(const char *content, TestCmdLine *resCmd) +{ + if (content == nullptr || resCmd == nullptr) { + return; + } + + const struct CmdTable *cmd = GetCmdByName(content); + if (cmd == nullptr) { + printf("Cannot support command: %s \n", content); + (void)memset_s(resCmd, sizeof(TestCmdLine), 0, sizeof(TestCmdLine)); + return; + } + if (strlen(content) <= (strlen(cmd->name) + 1)) { + printf("Error content for command: %s \n", content); + (void)memset_s(resCmd, sizeof(TestCmdLine), 0, sizeof(TestCmdLine)); + return; + } + int ret1 = strcpy_s(resCmd->name, MAX_CMD_NAME_LEN, cmd->name); + int ret2 = strcpy_s(resCmd->cmdContent, MAX_CMD_CONTENT_LEN, content + strlen(cmd->name)); + if (ret1 || ret2) { + printf("Error copy command: %s \n", content); + (void)memset_s(resCmd, sizeof(TestCmdLine), 0, sizeof(TestCmdLine)); + return; + } +} + +void DoCmd(const TestCmdLine *resCmd) +{ + if (resCmd == nullptr) { + return; + } + + DoCmdByName(resCmd->name, resCmd->cmdContent); +} + /* ** @tc.name: cmdFuncParseCmdTest_001 ** @tc.desc: parse function, nullptr test @@ -149,7 +190,7 @@ HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_001, TestSize.Level0) **/ HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_002, TestSize.Level0) { - CmdLine curCmdLine; + TestCmdLine curCmdLine; memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); ParseCmdLine(nullptr, &curCmdLine); @@ -177,7 +218,7 @@ HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_002, TestSize.Level0) **/ HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_003, TestSize.Level0) { - CmdLine curCmdLine; + TestCmdLine curCmdLine; memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); for (size_t i = 0; i < g_supportedCmds.size(); ++i) { @@ -195,7 +236,7 @@ HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_003, TestSize.Level0) **/ HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_004, TestSize.Level0) { - CmdLine curCmdLine; + TestCmdLine curCmdLine; memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); char toLongContent[MAX_CMD_CONTENT_LEN + 10]; @@ -203,7 +244,7 @@ HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_004, TestSize.Level0) toLongContent[MAX_CMD_CONTENT_LEN + 9] = '\0'; for (size_t i = 0; i < g_supportedCmds.size(); ++i) { size_t curCmdLen = g_supportedCmds[i].length(); - char* curCmd = (char*)malloc(curCmdLen + MAX_CMD_CONTENT_LEN + 10); + char *curCmd = (char *)malloc(curCmdLen + MAX_CMD_CONTENT_LEN + 10); if (curCmd == nullptr) { printf("[----------] StartupInitUTest, cmdFuncParseCmdTest004, malloc failed.\n"); break; @@ -236,7 +277,7 @@ HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_004, TestSize.Level0) **/ HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_005, TestSize.Level0) { - CmdLine curCmdLine; + TestCmdLine curCmdLine; memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); ParseCmdLine("start InitTestService", &curCmdLine); @@ -280,7 +321,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_001, TestSize.Level0) **/ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_002, TestSize.Level0) { - CmdLine curCmdLine; + TestCmdLine curCmdLine; memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); std::string cmdStr = "start "; @@ -300,7 +341,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_002, TestSize.Level0) **/ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_003, TestSize.Level0) { - CmdLine curCmdLine; + TestCmdLine curCmdLine; memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); std::string cmdStr = "mkdir "; @@ -312,7 +353,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_003, TestSize.Level0) DoCmd(&curCmdLine); // make sure that the directory does not exist - DIR* dirTmp = opendir(cmdContentStr.c_str()); + DIR *dirTmp = opendir(cmdContentStr.c_str()); EXPECT_TRUE(dirTmp == nullptr); EXPECT_TRUE(errno == ENOENT); if (dirTmp != nullptr) { // just in case @@ -346,7 +387,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_003, TestSize.Level0) **/ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_004, TestSize.Level0) { - CmdLine curCmdLine; + TestCmdLine curCmdLine; memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); std::string cmdStr = "chmod "; @@ -403,7 +444,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_004, TestSize.Level0) **/ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_005, TestSize.Level0) { - CmdLine curCmdLine; + TestCmdLine curCmdLine; memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); std::string cmdStr = "chown "; @@ -440,7 +481,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_005, TestSize.Level0) **/ HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_006, TestSize.Level0) { - CmdLine curCmdLine; + TestCmdLine curCmdLine; // mkdir success std::string cmdStr = "mkdir "; @@ -519,8 +560,8 @@ HWTEST_F(StartupInitUTest, cfgCheckStat_001, TestSize.Level0) static char* ReadFileToBuf() { - char* buffer = nullptr; - FILE* fd = nullptr; + char *buffer = nullptr; + FILE *fd = nullptr; struct stat fileStat = {0}; (void)stat(CFG_FILE.c_str(), &fileStat); do { @@ -549,9 +590,9 @@ static char* ReadFileToBuf() return buffer; } -static cJSON* GetArrItem(const cJSON* fileRoot, int& arrSize, const std::string& arrName) +static cJSON *GetArrItem(const cJSON *fileRoot, int &arrSize, const std::string &arrName) { - cJSON* arrItem = cJSON_GetObjectItemCaseSensitive(fileRoot, arrName.c_str()); + cJSON *arrItem = cJSON_GetObjectItemCaseSensitive(fileRoot, arrName.c_str()); arrSize = cJSON_GetArraySize(arrItem); if (arrSize <= 0) { return nullptr; @@ -559,7 +600,7 @@ static cJSON* GetArrItem(const cJSON* fileRoot, int& arrSize, const std::string& return arrItem; } -static int IsForbidden(const char* fieldStr) +static int IsForbidden(const char *fieldStr) { size_t fieldLen = strlen(fieldStr); size_t forbidStrLen = strlen("/bin/sh"); @@ -587,31 +628,31 @@ static void CheckService(const cJSON* curItem) return; } - char* nameStr = cJSON_GetStringValue(cJSON_GetObjectItem(curItem, "name")); + char *nameStr = cJSON_GetStringValue(cJSON_GetObjectItem(curItem, "name")); if (nameStr == nullptr) { EXPECT_TRUE(nameStr != nullptr); } else { EXPECT_TRUE(strlen(nameStr) > 0); } - cJSON* pathArgsItem = cJSON_GetObjectItem(curItem, "path"); + cJSON *pathArgsItem = cJSON_GetObjectItem(curItem, "path"); EXPECT_TRUE(cJSON_IsArray(pathArgsItem)); int pathArgsCnt = cJSON_GetArraySize(pathArgsItem); EXPECT_TRUE(pathArgsCnt > 0); - EXPECT_TRUE(pathArgsCnt <= MAX_PATH_ARGS_CNT); + EXPECT_TRUE(pathArgsCnt <= TEST_MAX_PATH_ARGS_CNT); for (int i = 0; i < pathArgsCnt; ++i) { - char* curParam = cJSON_GetStringValue(cJSON_GetArrayItem(pathArgsItem, i)); - EXPECT_TRUE(curParam != NULL); + char *curParam = cJSON_GetStringValue(cJSON_GetArrayItem(pathArgsItem, i)); + EXPECT_TRUE(curParam != nullptr); EXPECT_TRUE(strlen(curParam) > 0); - EXPECT_TRUE(strlen(curParam) <= MAX_ONE_ARG_LEN); + EXPECT_TRUE(strlen(curParam) <= TEST_MAX_ONE_ARG_LEN); if (i == 0) { EXPECT_TRUE(IsForbidden(curParam) == 0); } } - cJSON* filedJ = cJSON_GetObjectItem(curItem, "uid"); + cJSON *filedJ = cJSON_GetObjectItem(curItem, "uid"); EXPECT_TRUE(cJSON_IsNumber(filedJ)); EXPECT_TRUE(cJSON_GetNumberValue(filedJ) >= 0.0); @@ -630,7 +671,7 @@ static void CheckService(const cJSON* curItem) int capsCnt = cJSON_GetArraySize(filedJ); EXPECT_TRUE(capsCnt <= MAX_CAPS_CNT_FOR_ONE_SERVICE); for (int i = 0; i < capsCnt; ++i) { - cJSON* capJ = cJSON_GetArrayItem(filedJ, i); + cJSON *capJ = cJSON_GetArrayItem(filedJ, i); EXPECT_TRUE(cJSON_IsNumber(capJ)); EXPECT_TRUE(cJSON_GetNumberValue(capJ) >= 0.0); @@ -644,21 +685,21 @@ static void CheckService(const cJSON* curItem) } } -static void CheckServices(const cJSON* fileRoot) +static void CheckServices(const cJSON *fileRoot) { int servArrSize = 0; - cJSON* serviceArr = GetArrItem(fileRoot, servArrSize, SERVICE_ARR_NAME_IN_JSON); + cJSON *serviceArr = GetArrItem(fileRoot, servArrSize, SERVICE_ARR_NAME_IN_JSON); EXPECT_TRUE(serviceArr != nullptr); EXPECT_TRUE(servArrSize <= MAX_SERVICES_COUNT_IN_FILE); for (int i = 0; i < servArrSize; ++i) { - cJSON* curItem = cJSON_GetArrayItem(serviceArr, i); + cJSON *curItem = cJSON_GetArrayItem(serviceArr, i); EXPECT_TRUE(curItem != nullptr); CheckService(curItem); } } -static void CheckCmd(const CmdLine* resCmd) +static void CheckCmd(const TestCmdLine *resCmd) { EXPECT_TRUE(strlen(resCmd->name) > 0); EXPECT_TRUE(strlen(resCmd->cmdContent) > 0); @@ -708,13 +749,13 @@ static void CheckCmd(const CmdLine* resCmd) } } -static void CheckJob(const cJSON* jobItem) +static void CheckJob(const cJSON *jobItem) { if (jobItem == nullptr) { return; } - cJSON* cmdsItem = cJSON_GetObjectItem(jobItem, CMDS_ARR_NAME_IN_JSON.c_str()); + cJSON *cmdsItem = cJSON_GetObjectItem(jobItem, CMDS_ARR_NAME_IN_JSON.c_str()); EXPECT_TRUE(cmdsItem != nullptr); EXPECT_TRUE(cJSON_IsArray(cmdsItem)); @@ -722,11 +763,11 @@ static void CheckJob(const cJSON* jobItem) EXPECT_TRUE(cmdLinesCnt <= MAX_CMD_CNT_IN_ONE_JOB); for (int i = 0; i < cmdLinesCnt; ++i) { - char* cmdLineStr = cJSON_GetStringValue(cJSON_GetArrayItem(cmdsItem, i)); + char *cmdLineStr = cJSON_GetStringValue(cJSON_GetArrayItem(cmdsItem, i)); EXPECT_TRUE(cmdLineStr != nullptr); EXPECT_TRUE(strlen(cmdLineStr) > 0); - CmdLine resCmd; + TestCmdLine resCmd; (void)memset_s(&resCmd, sizeof(resCmd), 0, sizeof(resCmd)); ParseCmdLine(cmdLineStr, &resCmd); CheckCmd(&resCmd); @@ -736,7 +777,7 @@ static void CheckJob(const cJSON* jobItem) static void CheckJobs(const cJSON* fileRoot) { int jobArrSize = 0; - cJSON* jobArr = GetArrItem(fileRoot, jobArrSize, JOBS_ARR_NAME_IN_JSON); + cJSON *jobArr = GetArrItem(fileRoot, jobArrSize, JOBS_ARR_NAME_IN_JSON); EXPECT_TRUE(jobArr != nullptr); EXPECT_TRUE(jobArrSize == JOBS_IN_FILE_COUNT); @@ -744,9 +785,9 @@ static void CheckJobs(const cJSON* fileRoot) bool findInit = false; bool findPostInit = false; for (int i = 0; i < jobArrSize; ++i) { - cJSON* jobItem = cJSON_GetArrayItem(jobArr, i); + cJSON *jobItem = cJSON_GetArrayItem(jobArr, i); EXPECT_TRUE(jobItem != nullptr); - char* jobNameStr = cJSON_GetStringValue(cJSON_GetObjectItem(jobItem, "name")); + char *jobNameStr = cJSON_GetStringValue(cJSON_GetObjectItem(jobItem, "name")); EXPECT_TRUE(jobNameStr != nullptr); if (strcmp(jobNameStr, "pre-init") == 0) { findPreInit = true; @@ -773,13 +814,13 @@ static void CheckJobs(const cJSON* fileRoot) **/ HWTEST_F(StartupInitUTest, cfgCheckContent_001, TestSize.Level0) { - char* fileBuf = ReadFileToBuf(); + char *fileBuf = ReadFileToBuf(); if (fileBuf == nullptr) { EXPECT_TRUE(fileBuf != nullptr); return; } - cJSON* fileRoot = cJSON_Parse(fileBuf); + cJSON *fileRoot = cJSON_Parse(fileBuf); free(fileBuf); fileBuf = nullptr; @@ -799,7 +840,7 @@ HWTEST_F(StartupInitUTest, cfgCheckContent_001, TestSize.Level0) */ static void CreateIllegalCfg() { - FILE* testCfgFile = fopen(TEST_CFG_ILLEGAL.c_str(), "w+"); + FILE *testCfgFile = fopen(TEST_CFG_ILLEGAL.c_str(), "w+"); if (testCfgFile == nullptr) { printf("[----------] StartupInitUTest, open file %s failed, error %d.\n", TEST_CFG_ILLEGAL.c_str(), errno); return; @@ -823,7 +864,7 @@ static void CreateIllegalCfg() */ HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_001, TestSize.Level0) { - CmdLine curCmdLine; + TestCmdLine curCmdLine; memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); ParseCmdLine("loadcfg /patch/fstab.cfg", &curCmdLine); @@ -839,7 +880,7 @@ HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_001, TestSize.Level0) */ HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_002, TestSize.Level0) { - CmdLine curCmdLine; + TestCmdLine curCmdLine; std::string cmdStr = "loadcfg "; std::string cmdContentStr = "/patch/file_not_exist.cfg"; struct stat testCfgStat = {0}; @@ -879,12 +920,12 @@ HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_002, TestSize.Level0) */ HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_003, TestSize.Level0) { - CmdLine curCmdLine; + TestCmdLine curCmdLine; std::string cmdStr = "loadcfg "; std::string cmdContentStr = "/patch/fstab.cfg"; char buf[CAT_BUF_SIZE] = {0}; struct stat testCfgStat = {0}; - FILE* fd = nullptr; + FILE *fd = nullptr; size_t size; bool hasZpfs = false; std::string command = cmdStr + cmdContentStr; @@ -933,10 +974,8 @@ HWTEST_F(StartupInitUTest, cmdJobTest_001, TestSize.Level0) DoJob(nullptr); DoJob("job name does not exist"); ReleaseAllJobs(); - RegisterServices(nullptr, 0); StartServiceByName("service name does not exist", false); - StopAllServices(); - ReapServiceByPID(INVALID_PID); + StopAllServices(0); ServiceReap(nullptr); EXPECT_NE(0, ServiceStart(nullptr)); EXPECT_NE(0, ServiceStop(nullptr)); diff --git a/services/test/unittest/init/cmds_unittest.cpp b/services/test/unittest/init/cmds_unittest.cpp new file mode 100755 index 0000000..458b04c --- /dev/null +++ b/services/test/unittest/init/cmds_unittest.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "init_cmds.h" +#include "init_param.h" +#include "init_unittest.h" + +using namespace testing::ext; +using namespace std; + +namespace init_ut { +class CmdsUnitTest : public testing::Test { +public: + static void SetUpTestCase(void) + { + InitParamService(); + }; + static void TearDownTestCase(void) {}; + void SetUp() {}; + void TearDown() {}; +}; + +HWTEST_F(CmdsUnitTest, TestGetValueForCmd, TestSize.Level1) +{ + // 1, test one param + SystemWriteParam("ro.test.1111.2222", "2.3.4.5.6.7.8"); + char *tmpParamValue = (char *)malloc(PARAM_VALUE_LEN_MAX + 1); + if (tmpParamValue == nullptr) { + EXPECT_EQ(1, 0); + return; + } + tmpParamValue[0] = '\0'; + const char *cmd1 = "init.${ro.test.1111.2222}.usb.cfg"; + GetParamValue(cmd1, strlen(cmd1), tmpParamValue, PARAM_VALUE_LEN_MAX); + printf("Tmp value %s \n", tmpParamValue); + EXPECT_EQ(strcmp("init.2.3.4.5.6.7.8.usb.cfg", tmpParamValue), 0); + + // 2, test two param + const char *cmd2 = "init.${ro.test.1111.2222}.usb.${ro.test.1111.2222}"; + GetParamValue(cmd2, strlen(cmd2), tmpParamValue, PARAM_VALUE_LEN_MAX); + printf("Tmp value %s \n", tmpParamValue); + EXPECT_EQ(strcmp("init.2.3.4.5.6.7.8.usb.2.3.4.5.6.7.8", tmpParamValue), 0); + + // 3, test two param + const char *cmd3 = "${ro.test.1111.2222}.init.${ro.test.1111.2222}.usb.${ro.test.1111.2222}"; + GetParamValue(cmd3, strlen(cmd3), tmpParamValue, PARAM_VALUE_LEN_MAX); + printf("Tmp value %s \n", tmpParamValue); + EXPECT_EQ(strcmp("2.3.4.5.6.7.8.init.2.3.4.5.6.7.8.usb.2.3.4.5.6.7.8", tmpParamValue), 0); + free(tmpParamValue); +} +HWTEST_F(CmdsUnitTest, TestDoCopy, TestSize.Level1) +{ + DoCmdByName("copy ", "libdemo.z.so aaaa.so"); +} +} // namespace init_ut diff --git a/services/include/init_perms.h b/services/test/unittest/init/service_unittest.cpp old mode 100644 new mode 100755 similarity index 61% rename from services/include/init_perms.h rename to services/test/unittest/init/service_unittest.cpp index ee8d998..47779d4 --- a/services/include/init_perms.h +++ b/services/test/unittest/init/service_unittest.cpp @@ -1,38 +1,34 @@ -/* - * Copyright (c) 2020 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef BASE_STARTUP_INITLITE_PERMS_H -#define BASE_STARTUP_INITLITE_PERMS_H - -#ifdef __cplusplus -#if __cplusplus -extern "C" { -#endif -#endif - -#define FULL_CAP 0xFFFFFFFF - -// init -#define DEFAULT_UMASK_INIT 022 - -// kit framework -#define DEFAULT_UID_KIT_FRAMEWORK 3 - -#ifdef __cplusplus -#if __cplusplus -} -#endif -#endif - -#endif // BASE_STARTUP_INITLITE_PERMS_H +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "init_unittest.h" + +using namespace testing::ext; +using namespace std; + +namespace init_ut { +class ServiceUnitTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase(void) {}; + void SetUp() {}; + void TearDown() {}; +}; + +HWTEST_F(ServiceUnitTest, case01, TestSize.Level1) +{ +} + +} // namespace init_ut diff --git a/services/test/unittest/init_unittest.h b/services/test/unittest/init_unittest.h new file mode 100755 index 0000000..e02be3c --- /dev/null +++ b/services/test/unittest/init_unittest.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INIT_UNITTEST_CONST_H +#define INIT_UNITTEST_CONST_H +#include +#include +#include +#include +#include +#include + +#endif // INIT_UNITTEST_CONST_H diff --git a/services/test/unittest/param/client_unittest.cpp b/services/test/unittest/param/client_unittest.cpp new file mode 100755 index 0000000..7b3726f --- /dev/null +++ b/services/test/unittest/param/client_unittest.cpp @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "init_unittest.h" +#include "init_utils.h" +#include "param_request.h" +#include "param_stub.h" +#include "sys_param.h" + +using namespace std; + +int g_testPermissionResult = DAC_RESULT_PERMISSION; +static const int THREAD_NUM_TEST = 2; + +static void ClientCheckParamValue(const char *name, const char *expectValue) +{ + char tmp[PARAM_BUFFER_SIZE] = { 0 }; + u_int32_t len = sizeof(tmp); + int ret = SystemGetParameter(name, tmp, &len); + printf("ClientCheckParamValue name %s value: \'%s\' expectValue:\'%s\' \n", name, tmp, expectValue); + if (ret == 0 && len > 0) { + EXPECT_NE((int)strlen(tmp), 0); + if (expectValue != nullptr) { + EXPECT_EQ(strcmp(tmp, expectValue), 0); + } + } else { + EXPECT_NE(0, 0); + } +} + +// 多线程测试 +static void *TestSendParamSetMsg(void *args) +{ + std::string name = (char *)args; + printf("TestSendParamSetMsg name :\'%s\' \n", name.c_str()); + SystemSetParameter(name.c_str(), name.c_str()); + ClientCheckParamValue(name.c_str(), name.c_str()); + return nullptr; +} + +static void *TestSendParamWaitMsg(void *args) +{ + std::string name = "Wati."; + name = name + (char *)args; + printf("TestSendParamWaitMsg name :\'%s\' \n", name.c_str()); + SystemWaitParameter(name.c_str(), name.c_str(), 1); + return nullptr; +} + +static void TestForMultiThread() +{ + printf("TestForMultiThread \n"); + pthread_t tids[THREAD_NUM_TEST + THREAD_NUM_TEST]; + const char *names[] = { + "thread.1111.2222.3333.4444.5555", + "thread.2222.1111.2222.3333.4444", + "thread.3333.1111.2222.4444.5555", + "thread.4444.5555.1111.2222.3333", + "thread.5555.1111.2222.3333.4444" + }; + for (size_t i = 0; i < THREAD_NUM_TEST; i++) { + pthread_create(&tids[i], nullptr, TestSendParamSetMsg, (void *)names[i % ARRAY_LENGTH(names)]); + } + for (size_t i = THREAD_NUM_TEST; i < THREAD_NUM_TEST + THREAD_NUM_TEST; i++) { + pthread_create(&tids[i], nullptr, TestSendParamWaitMsg, (void *)names[i % ARRAY_LENGTH(names)]); + } + for (size_t i = 0; i < THREAD_NUM_TEST + THREAD_NUM_TEST; i++) { + pthread_join(tids[i], nullptr); + } +} + +static void TestParamTraversal() +{ + SystemTraversalParameter( + [](ParamHandle handle, void *cookie) { + char value[PARAM_BUFFER_SIZE + PARAM_BUFFER_SIZE] = { 0 }; + uint32_t commitId = 0; + int ret = SystemGetParameterCommitId(handle, &commitId); + EXPECT_EQ(ret, 0); + SystemGetParameterName(handle, value, PARAM_BUFFER_SIZE); + u_int32_t len = PARAM_BUFFER_SIZE; + SystemGetParameterValue(handle, ((char *)value) + PARAM_BUFFER_SIZE, &len); + printf("$$$$$$$$Param %s=%s \n", (char *)value, ((char *)value) + PARAM_BUFFER_SIZE); + }, nullptr); +} + +static void TestPersistParam() +{ + SystemSetParameter("persist.111.ffff.bbbb.cccc.dddd.eeee", "1101"); + SystemSetParameter("persist.111.aaaa.bbbb.cccc.dddd.eeee", "1102"); + SystemSetParameter("persist.111.bbbb.cccc.dddd.eeee", "1103"); + ClientCheckParamValue("persist.111.bbbb.cccc.dddd.eeee", "1103"); + SystemSetParameter("persist.111.cccc.bbbb.cccc.dddd.eeee", "1104"); + SystemSetParameter("persist.111.eeee.bbbb.cccc.dddd.eeee", "1105"); + ClientCheckParamValue("persist.111.ffff.bbbb.cccc.dddd.eeee", "1101"); + SystemSetParameter("persist.111.ffff.bbbb.cccc.dddd.eeee", "1106"); + ClientCheckParamValue("persist.111.ffff.bbbb.cccc.dddd.eeee", "1106"); +} + +static void TestPermission() +{ + const char *testName = "persist.111.ffff.bbbb.cccc.dddd.eeee.55555"; + char tmp[PARAM_BUFFER_SIZE] = { 0 }; + // 允许本地校验 + ParamSecurityOps *paramSecurityOps = &GetClientParamWorkSpace()->paramSecurityOps; + paramSecurityOps->securityCheckParamPermission = TestCheckParamPermission; + g_testPermissionResult = DAC_RESULT_FORBIDED; + GetClientParamWorkSpace()->securityLabel->flags = LABEL_CHECK_FOR_ALL_PROCESS; + int ret = SystemSetParameter(testName, "22202"); + EXPECT_EQ(ret, DAC_RESULT_FORBIDED); + + paramSecurityOps->securityEncodeLabel = TestEncodeSecurityLabel; + paramSecurityOps->securityDecodeLabel = TestDecodeSecurityLabel; + paramSecurityOps->securityFreeLabel = TestFreeLocalSecurityLabel; + paramSecurityOps->securityCheckParamPermission = TestCheckParamPermission; + g_testPermissionResult = 0; + ret = SystemSetParameter(testName, "22202"); + EXPECT_EQ(ret, 0); + ClientCheckParamValue(testName, "22202"); + + const int testResult = 201; + g_testPermissionResult = testResult; + // 禁止写/读 + ret = SystemSetParameter(testName, "3333"); + EXPECT_EQ(ret, testResult); + u_int32_t len = sizeof(tmp); + ret = SystemGetParameter(testName, tmp, &len); + EXPECT_EQ(ret, testResult); + RegisterSecurityOps(paramSecurityOps, 0); +} + +static void TestCmd() +{ + // set + const char *argForSet[] = { "param", "set", "aaaa", "2222" }; + RunParamCommand(ARRAY_LENGTH(argForSet), const_cast(argForSet)); + + // get + const char *argForGet[] = { "param", "get", "aaaa" }; + RunParamCommand(ARRAY_LENGTH(argForGet), const_cast(argForGet)); + + // get all + const char *argForGet2[] = { "param", "get" }; + RunParamCommand(ARRAY_LENGTH(argForGet2), const_cast(argForGet2)); + + // set 失败 + const char *argForSet2[] = { "param", "set", "aaaa" }; + RunParamCommand(ARRAY_LENGTH(argForSet2), const_cast(argForSet2)); + + const char *argForSet3[] = { "paramset", "aaaa", "aaaa" }; + RunParamCommand(ARRAY_LENGTH(argForSet3), const_cast(argForSet3)); + + const char *argForSet4[] = { "paramset", "aaaa" }; + RunParamCommand(ARRAY_LENGTH(argForSet4), const_cast(argForSet4)); + + const char *argForSet5[] = { "param" }; + RunParamCommand(ARRAY_LENGTH(argForSet5), const_cast(argForSet5)); + + const char *argForSet6[] = { "param", "44444" }; + RunParamCommand(ARRAY_LENGTH(argForSet6), const_cast(argForSet6)); + + const char *argForSet7[] = { "paramget", "aaaa" }; + RunParamCommand(ARRAY_LENGTH(argForSet7), const_cast(argForSet7)); + + const char *argForSet8[] = { "param dump", "verbose" }; + RunParamCommand(ARRAY_LENGTH(argForSet8), const_cast(argForSet8)); + + const char *argForSet9[] = { "param wait", "test.wait.001", "1" }; + RunParamCommand(ARRAY_LENGTH(argForSet9), const_cast(argForSet9)); +} + +void TestClient(int index) +{ + char testBuffer[PARAM_BUFFER_SIZE] = { 0 }; + const std::string value = "test.add.client.value.001"; + std::string name = "test.add.client.001"; + name += std::to_string(index); + switch (index) { + case 0: { + ParamWorkSpace *space = GetClientParamWorkSpace(); + if (space != nullptr && space->securityLabel != nullptr) { + space->securityLabel->cred.uid = TEST_UID; + space->securityLabel->cred.gid = TEST_UID; + } + } + case 1: { // set + SystemSetParameter(name.c_str(), value.c_str()); + ClientCheckParamValue(name.c_str(), value.c_str()); + SystemWaitParameter(name.c_str(), value.c_str(), 1); + TestPersistParam(); + // wait + SystemWaitParameter(name.c_str(), value.c_str(), 1); + SystemWaitParameter(name.c_str(), nullptr, 0); + break; + } + case 2: { // find + ParamHandle handle; + uint32_t size = PARAM_BUFFER_SIZE; + int ret = SystemFindParameter(name.c_str(), &handle); + SystemSetParameter(name.c_str(), value.c_str()); + ret = SystemFindParameter(name.c_str(), &handle); + EXPECT_EQ(ret, 0); + uint32_t commitId = 0; + ret = SystemGetParameterCommitId(handle, &commitId); + EXPECT_EQ(ret, 0); + ret = SystemGetParameterName(handle, testBuffer, size); + EXPECT_EQ(ret, 0); + EXPECT_EQ(strcmp(testBuffer, name.c_str()), 0); + ret = SystemGetParameterValue(handle, testBuffer, &size); + EXPECT_EQ(ret, 0); + EXPECT_EQ(strcmp(testBuffer, value.c_str()), 0); + break; + } + case 3: // Traversal + TestParamTraversal(); + SystemDumpParameters(1); + break; + case 4: { // watcher + int ret = WatchParamCheck(name.c_str()); + EXPECT_EQ(ret, 0); + ret = WatchParamCheck("&&&&&.test.tttt"); + EXPECT_NE(ret, 0); + // test permission + TestPermission(); + // test cmd + TestCmd(); + break; + } + case 5: // multi + TestForMultiThread(); + break; + default: + break; + } +} + +int TestEncodeSecurityLabel(const ParamSecurityLabel *srcLabel, char *buffer, uint32_t *bufferSize) +{ + PARAM_CHECK(bufferSize != nullptr, return -1, "Invalid param"); + if (buffer == nullptr) { + *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)); +} + +int TestDecodeSecurityLabel(ParamSecurityLabel **srcLabel, const char *buffer, uint32_t bufferSize) +{ + PARAM_CHECK(bufferSize >= sizeof(ParamSecurityLabel), return -1, "Invalid buffersize %u", bufferSize); + PARAM_CHECK(srcLabel != nullptr && buffer != nullptr, return -1, "Invalid param"); + *srcLabel = (ParamSecurityLabel *)buffer; + return 0; +} + +int TestCheckParamPermission(const ParamSecurityLabel *srcLabel, const ParamAuditData *auditData, uint32_t mode) +{ + // DAC_RESULT_FORBIDED + return g_testPermissionResult; +} + +int TestFreeLocalSecurityLabel(ParamSecurityLabel *srcLabel) +{ + return 0; +} \ No newline at end of file diff --git a/services/test/unittest/param/dac_unittest.cpp b/services/test/unittest/param/dac_unittest.cpp new file mode 100755 index 0000000..5a40951 --- /dev/null +++ b/services/test/unittest/param/dac_unittest.cpp @@ -0,0 +1,339 @@ +/* + * 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" +#include "securec.h" +#include "init_unittest.h" + +extern "C" { +extern int RegisterSecurityDacOps(ParamSecurityOps *ops, int isInit); +} + +using namespace testing::ext; +using namespace std; + +static int SecurityLabelGet(const ParamAuditData *auditData, void *context) +{ + return 0; +} + +class ParamDacTest : public ::testing::Test { +public: + ParamDacTest() {} + virtual ~ParamDacTest() {} + + void SetUp() {} + void TearDown() {} + void TestBody() {} + + int TestDacGetLabel() + { + int ret = RegisterSecurityDacOps(&initParamSercurityOps, LABEL_INIT_FOR_INIT); + EXPECT_EQ(ret, 0); + + if (initParamSercurityOps.securityGetLabel == nullptr) { + EXPECT_EQ(1, 0); + return -1; + } + ret = initParamSercurityOps.securityGetLabel(SecurityLabelGet, + PARAM_DEFAULT_PATH "/system/etc/param", nullptr); + EXPECT_EQ(ret, 0); + return 0; + } + + int TestDacInitLocalLabel() + { + int ret = RegisterSecurityDacOps(&initParamSercurityOps, LABEL_INIT_FOR_INIT); + EXPECT_EQ(ret, 0); + + if (initParamSercurityOps.securityInitLabel == nullptr || initParamSercurityOps.securityFreeLabel == nullptr) { + return -1; + } + ParamSecurityLabel *label = nullptr; + ret = initParamSercurityOps.securityInitLabel(&label, LABEL_INIT_FOR_INIT); + EXPECT_EQ(ret, 0); + ret = initParamSercurityOps.securityFreeLabel(label); + EXPECT_EQ(ret, 0); + return 0; + } + + int TestDacCheckFilePermission(const char *fileName) + { + int ret = RegisterSecurityDacOps(&initParamSercurityOps, LABEL_INIT_FOR_INIT); + EXPECT_EQ(ret, 0); + if (initParamSercurityOps.securityCheckFilePermission == nullptr) { + return -1; + } + ParamSecurityLabel *label = nullptr; + ret = initParamSercurityOps.securityInitLabel(&label, LABEL_INIT_FOR_INIT); + EXPECT_EQ(ret, 0); + ret = initParamSercurityOps.securityCheckFilePermission(label, fileName, DAC_WRITE); + EXPECT_EQ(ret, 0); + ret = initParamSercurityOps.securityFreeLabel(label); + EXPECT_EQ(ret, 0); + return 0; + } + + int TestDacCheckParaPermission(const char *name, ParamDacData *dacData, int mode) + { + int ret = RegisterSecurityDacOps(&initParamSercurityOps, LABEL_INIT_FOR_INIT); + EXPECT_EQ(ret, 0); + if (initParamSercurityOps.securityCheckFilePermission == nullptr) { + return -1; + } + ParamSecurityLabel *srclabel = nullptr; + ret = initParamSercurityOps.securityInitLabel(&srclabel, LABEL_INIT_FOR_INIT); + EXPECT_EQ(ret, 0); + + ParamAuditData auditData = {}; + auditData.name = name; + auditData.label = nullptr; + memcpy_s(&auditData.dacData, sizeof(ParamDacData), dacData, sizeof(ParamDacData)); + ret = initParamSercurityOps.securityCheckParamPermission(srclabel, &auditData, mode); + initParamSercurityOps.securityFreeLabel(srclabel); + return ret; + } + + int TestClientDacCheckFilePermission(const char *fileName) + { + int ret = RegisterSecurityDacOps(&clientParamSercurityOps, 0); + EXPECT_EQ(ret, 0); + if (clientParamSercurityOps.securityDecodeLabel != nullptr) { + EXPECT_EQ(1, 0); + } + if (clientParamSercurityOps.securityGetLabel != nullptr) { + EXPECT_EQ(1, 0); + } + if (clientParamSercurityOps.securityCheckFilePermission == nullptr) { + EXPECT_EQ(1, 0); + return -1; + } + ParamSecurityLabel *label = nullptr; + ret = clientParamSercurityOps.securityInitLabel(&label, 0); + EXPECT_EQ(ret, 0); + ret = clientParamSercurityOps.securityCheckFilePermission(label, fileName, DAC_READ); + EXPECT_EQ(ret, 0); + ret = clientParamSercurityOps.securityFreeLabel(label); + EXPECT_EQ(ret, 0); + return 0; + } + + int TestEncode(const ParamSecurityLabel *label, std::vector &buffer) + { + int ret = RegisterSecurityDacOps(&clientParamSercurityOps, 0); + EXPECT_EQ(ret, 0); + if (clientParamSercurityOps.securityDecodeLabel != nullptr) { + EXPECT_EQ(1, 0); + } + if (clientParamSercurityOps.securityGetLabel != nullptr) { + EXPECT_EQ(1, 0); + } + if (clientParamSercurityOps.securityEncodeLabel == nullptr) { + EXPECT_EQ(1, 0); + return -1; + } + uint32_t bufferSize = 0; + ret = clientParamSercurityOps.securityEncodeLabel(label, nullptr, &bufferSize); + EXPECT_EQ(ret, 0); + buffer.resize(bufferSize + 1); + ret = clientParamSercurityOps.securityEncodeLabel(label, buffer.data(), &bufferSize); + EXPECT_EQ(ret, 0); + return 0; + } + + int TestDecode(const ParamSecurityLabel *label, std::vector &buffer) + { + int ret = RegisterSecurityDacOps(&clientParamSercurityOps, 1); + EXPECT_EQ(ret, 0); + if (clientParamSercurityOps.securityDecodeLabel == nullptr) { + EXPECT_EQ(1, 0); + } + if (clientParamSercurityOps.securityEncodeLabel != nullptr) { + EXPECT_EQ(1, 0); + return -1; + } + ParamSecurityLabel *tmp = nullptr; + ret = clientParamSercurityOps.securityDecodeLabel(&tmp, buffer.data(), buffer.size()); + EXPECT_EQ(ret, 0); + EXPECT_EQ(label->cred.gid, tmp->cred.gid); + EXPECT_EQ(label->cred.uid, tmp->cred.uid); + return 0; + } + +private: + ParamSecurityOps initParamSercurityOps; + ParamSecurityOps clientParamSercurityOps; +}; + +HWTEST_F(ParamDacTest, TestDacGetLabel, TestSize.Level1) +{ + ParamDacTest test; + test.TestDacGetLabel(); +} + +HWTEST_F(ParamDacTest, TestDacInitLocalLabel, TestSize.Level1) +{ + ParamDacTest test; + test.TestDacInitLocalLabel(); +} + +HWTEST_F(ParamDacTest, TestDacLabelEncode, TestSize.Level1) +{ + ParamDacTest test; + std::vector buffer; + ParamSecurityLabel label = {0, { 4444, 5555}}; + test.TestEncode(&label, buffer); + test.TestDecode(&label, buffer); +} + +HWTEST_F(ParamDacTest, TestDacCheckFilePermission, TestSize.Level1) +{ + ParamDacTest test; + test.TestDacCheckFilePermission(PARAM_DEFAULT_PATH"/trigger_test.cfg"); +} + +HWTEST_F(ParamDacTest, TestDacCheckUserParaPermission, TestSize.Level1) +{ + // 相同用户 + ParamDacTest test; + ParamDacData dacData; + dacData.gid = getegid(); + dacData.uid = geteuid(); + // read + dacData.mode = 0400; + int ret = test.TestDacCheckParaPermission("test.permission.read.aaa", &dacData, DAC_READ); + EXPECT_EQ(ret, 0); + dacData.mode = 0400; + ret = test.TestDacCheckParaPermission("test.permission.read.aaa", &dacData, DAC_WRITE); + EXPECT_NE(ret, 0); + dacData.mode = 0400; + ret = test.TestDacCheckParaPermission("test.permission.read.aaa", &dacData, DAC_WATCH); + EXPECT_NE(ret, 0); + + // write + dacData.mode = 0200; + ret = test.TestDacCheckParaPermission("test.permission.write.aaa", &dacData, DAC_READ); + EXPECT_NE(ret, 0); + dacData.mode = 0200; + ret = test.TestDacCheckParaPermission("test.permission.write.aaa", &dacData, DAC_WRITE); + EXPECT_EQ(ret, 0); + dacData.mode = 0200; + ret = test.TestDacCheckParaPermission("test.permission.write.aaa", &dacData, DAC_WATCH); + EXPECT_NE(ret, 0); + + // watch + dacData.mode = 0100; + ret = test.TestDacCheckParaPermission("test.permission.watch.aaa", &dacData, DAC_READ); + EXPECT_NE(ret, 0); + dacData.mode = 0100; + ret = test.TestDacCheckParaPermission("test.permission.watch.aaa", &dacData, DAC_WRITE); + EXPECT_NE(ret, 0); + dacData.mode = 0100; + ret = test.TestDacCheckParaPermission("test.permission.watch.aaa", &dacData, DAC_WATCH); + EXPECT_EQ(ret, 0); +} + +HWTEST_F(ParamDacTest, TestDacCheckGroupParaPermission, TestSize.Level1) +{ + // 相同组 + ParamDacTest test; + ParamDacData dacData; + dacData.gid = getegid(); + dacData.uid = 13333; + // read + dacData.mode = 0040; + int ret = test.TestDacCheckParaPermission("test.permission.read.aaa", &dacData, DAC_READ); + EXPECT_EQ(ret, 0); + dacData.mode = 0040; + ret = test.TestDacCheckParaPermission("test.permission.read.aaa", &dacData, DAC_WRITE); + EXPECT_NE(ret, 0); + dacData.mode = 0040; + ret = test.TestDacCheckParaPermission("test.permission.read.aaa", &dacData, DAC_WATCH); + EXPECT_NE(ret, 0); + + // write + dacData.mode = 0020; + ret = test.TestDacCheckParaPermission("test.permission.write.aaa", &dacData, DAC_READ); + EXPECT_NE(ret, 0); + dacData.mode = 0020; + ret = test.TestDacCheckParaPermission("test.permission.write.aaa", &dacData, DAC_WRITE); + EXPECT_EQ(ret, 0); + dacData.mode = 0020; + ret = test.TestDacCheckParaPermission("test.permission.write.aaa", &dacData, DAC_WATCH); + EXPECT_NE(ret, 0); + + // watch + dacData.mode = 0010; + ret = test.TestDacCheckParaPermission("test.permission.watch.aaa", &dacData, DAC_READ); + EXPECT_NE(ret, 0); + dacData.mode = 0010; + ret = test.TestDacCheckParaPermission("test.permission.watch.aaa", &dacData, DAC_WRITE); + EXPECT_NE(ret, 0); + dacData.mode = 0010; + ret = test.TestDacCheckParaPermission("test.permission.watch.aaa", &dacData, DAC_WATCH); + EXPECT_EQ(ret, 0); +} + +HWTEST_F(ParamDacTest, TestDacCheckOtherParaPermission, TestSize.Level1) +{ + // 其他用户 + ParamDacTest test; + ParamDacData dacData; + dacData.gid = 13333; + dacData.uid = 13333; + // read + dacData.mode = 0004; + int ret = test.TestDacCheckParaPermission("test.permission.read.aaa", &dacData, DAC_READ); + EXPECT_EQ(ret, 0); + dacData.mode = 0004; + ret = test.TestDacCheckParaPermission("test.permission.read.aaa", &dacData, DAC_WRITE); + EXPECT_NE(ret, 0); + dacData.mode = 0004; + ret = test.TestDacCheckParaPermission("test.permission.read.aaa", &dacData, DAC_WATCH); + EXPECT_NE(ret, 0); + + // write + dacData.mode = 0002; + ret = test.TestDacCheckParaPermission("test.permission.write.aaa", &dacData, DAC_READ); + EXPECT_NE(ret, 0); + dacData.mode = 0002; + ret = test.TestDacCheckParaPermission("test.permission.write.aaa", &dacData, DAC_WRITE); + EXPECT_EQ(ret, 0); + dacData.mode = 0002; + ret = test.TestDacCheckParaPermission("test.permission.write.aaa", &dacData, DAC_WATCH); + EXPECT_NE(ret, 0); + + // watch + dacData.mode = 0001; + ret = test.TestDacCheckParaPermission("test.permission.watch.aaa", &dacData, DAC_READ); + EXPECT_NE(ret, 0); + dacData.mode = 0001; + ret = test.TestDacCheckParaPermission("test.permission.watch.aaa", &dacData, DAC_WRITE); + EXPECT_NE(ret, 0); + dacData.mode = 0001; + ret = test.TestDacCheckParaPermission("test.permission.watch.aaa", &dacData, DAC_WATCH); + EXPECT_EQ(ret, 0); +} + +HWTEST_F(ParamDacTest, TestClientDacCheckFilePermission, TestSize.Level1) +{ + ParamDacTest test; + test.TestClientDacCheckFilePermission(PARAM_DEFAULT_PATH"/trigger_test.cfg"); +} diff --git a/services/test/unittest/param/param_stub.h b/services/test/unittest/param/param_stub.h new file mode 100755 index 0000000..7ae9f7a --- /dev/null +++ b/services/test/unittest/param/param_stub.h @@ -0,0 +1,47 @@ +/* + * 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 PARAM_TEST_STUB_ +#define PARAM_TEST_STUB_ +#include "param_libuvadp.h" +#include "param_manager.h" +#include "param_security.h" +#include "param_service.h" +#include "param_utils.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif +extern int RunParamCommand(int argc, char *argv[]); +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif + +static const int TEST_UID = 1000; +static const int TEST_GID = 9999; +static const int TEST_DAC_GID = 2002; +static const int TEST_DAC_GID2 = 2003; +static const int TEST_READ_AND_WRITE = 0666; + +void TestClient(int index); +int TestEncodeSecurityLabel(const ParamSecurityLabel *srcLabel, char *buffer, uint32_t *bufferSize); +int TestDecodeSecurityLabel(ParamSecurityLabel **srcLabel, const char *buffer, uint32_t bufferSize); +int TestCheckParamPermission(const ParamSecurityLabel *srcLabel, const ParamAuditData *auditData, uint32_t mode); +int TestFreeLocalSecurityLabel(ParamSecurityLabel *srcLabel); + +#endif // PARAM_TEST_STUB_ \ No newline at end of file diff --git a/services/test/unittest/param/param_unittest.cpp b/services/test/unittest/param/param_unittest.cpp new file mode 100755 index 0000000..0e90073 --- /dev/null +++ b/services/test/unittest/param/param_unittest.cpp @@ -0,0 +1,660 @@ +/* + * 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 "init_param.h" +#include "init_unittest.h" +#include "param_stub.h" +#include "trigger_manager.h" + +using namespace testing::ext; +using namespace std; +static int CheckServerParamValue(const char *name, const char *expectValue) +{ + char tmp[PARAM_BUFFER_SIZE] = { 0 }; + u_int32_t len = sizeof(tmp); + SystemReadParam(name, tmp, &len); + printf("CheckParamValue name %s value: \'%s\' expectValue:\'%s\' \n", name, tmp, expectValue); + EXPECT_NE((int)strlen(tmp), 0); + if (expectValue != nullptr) { + EXPECT_EQ(strcmp(tmp, expectValue), 0); + } + return 0; +} + +extern "C" { +extern void TimerCallbackForSave(ParamTaskPtr timer, void *context); +} + +static ParamTask *g_worker = nullptr; +class ParamServiceTest : public ::testing::Test { +public: + ParamServiceTest() {} + virtual ~ParamServiceTest() {} + + void SetUp() {} + void TearDown() {} + void TestBody() {} + + int TestParamServiceInit() + { + InitParamService(); + // parse parameters + LoadDefaultParams(PARAM_DEFAULT_PATH"/system/etc/param/ohos_const", LOAD_PARAM_NORMAL); + LoadDefaultParams(PARAM_DEFAULT_PATH"/vendor/etc/param", LOAD_PARAM_NORMAL); + LoadDefaultParams(PARAM_DEFAULT_PATH"/system/etc/param", LOAD_PARAM_ONLY_ADD); + CheckServerParamValue("const.actionable_compatible_property.enabled", "false"); + CheckServerParamValue("build_version", "2.0"); + CheckServerParamValue("ohos.boot.hardware", "Hi3516DV300"); + return 0; + } + + int TestSetParams(const char *params[][1 + 1], int num) + { + for (int i = 0; i < num; i++) { + SystemWriteParam(params[i][0], params[i][1]); + } + + // check + for (int i = 0; i < num; i++) { + CheckServerParamValue(params[i][0], params[i][1]); + } + + for (int i = num - 1; i >= 0; i--) { + CheckServerParamValue(params[i][0], params[i][1]); + } + return 0; + } + + int TestAddSecurityLabel1() + { + GetParamWorkSpace()->securityLabel->cred.gid = TEST_GID; + const char *name = "label1.test.aaa.bbb.ccc.dddd.eee"; + const char *value = "2001"; + uint32_t labelIndex = 0; + SystemWriteParam(name, value); + // 获取到跟属性 + ParamTrieNode *paramNode = FindTrieNode(&GetParamWorkSpace()->paramSpace, name, strlen(name), &labelIndex); + ParamSecruityNode *node = (ParamSecruityNode *)GetTrieNode(&GetParamWorkSpace()->paramSpace, labelIndex); + if (paramNode == nullptr || node == nullptr) { + EXPECT_EQ(1, 0); + return 0; + } + EXPECT_EQ(node->gid, getegid()); + return 0; + } + + // 添加一个label,最长匹配到这个节点 + int TestAddSecurityLabel2() + { + GetParamWorkSpace()->securityLabel->cred.gid = TEST_GID; + const char *name = "label2.test.aaa.bbb.ccc.dddd.eee"; + const char *value = "2001"; + ParamAuditData auditData = {}; + auditData.name = "label2.test.aaa"; + auditData.label = "label2.test.aaa"; + auditData.dacData.gid = TEST_DAC_GID; + auditData.dacData.uid = geteuid(); + auditData.dacData.mode = TEST_READ_AND_WRITE; + SystemWriteParam(name, value); + uint32_t labelIndex = 0; + AddSecurityLabel(&auditData, GetParamWorkSpace()); + ParamTrieNode *paramNode = FindTrieNode(&GetParamWorkSpace()->paramSpace, name, strlen(name), &labelIndex); + ParamSecruityNode *node = (ParamSecruityNode *)GetTrieNode(&GetParamWorkSpace()->paramSpace, labelIndex); + if (paramNode == nullptr || node == nullptr) { + EXPECT_EQ(1, 0); + } + EXPECT_EQ(node->gid, auditData.dacData.gid); + return 0; + } + + // 添加一个label,最长匹配到最后一个相同节点 + int TestAddSecurityLabel3() + { + GetParamWorkSpace()->securityLabel->cred.gid = TEST_GID; + const char *name = "label3.test.aaa.bbb.ccc.dddd.eee"; + const char *value = "2001"; + ParamAuditData auditData = {}; + auditData.name = "label3.test.aaa"; + auditData.label = "label3.test.aaa"; + auditData.dacData.gid = TEST_DAC_GID2; + auditData.dacData.uid = geteuid(); + auditData.dacData.mode = TEST_READ_AND_WRITE; + SystemWriteParam(name, value); + AddSecurityLabel(&auditData, GetParamWorkSpace()); + + auditData.name = "label3.test.aaa.bbb.ccc.dddd.eee.dddd"; + auditData.label = "label3.test.aaa.bbb.ccc.dddd.eee.dddd"; + auditData.dacData.gid = TEST_DAC_GID; + auditData.dacData.uid = geteuid(); + auditData.dacData.mode = TEST_READ_AND_WRITE; + SystemWriteParam(name, value); + AddSecurityLabel(&auditData, GetParamWorkSpace()); + + uint32_t labelIndex = 0; + ParamTrieNode *paramNode = FindTrieNode(&GetParamWorkSpace()->paramSpace, name, strlen(name), &labelIndex); + ParamSecruityNode *node = (ParamSecruityNode *)GetTrieNode(&GetParamWorkSpace()->paramSpace, labelIndex); + if (paramNode == nullptr || node == nullptr) { + EXPECT_EQ(1, 0); + } + EXPECT_EQ((int)node->gid, TEST_DAC_GID2); + return 0; + } + + // 添加一个label,完全匹配 + int TestAddSecurityLabel4() + { + GetParamWorkSpace()->securityLabel->cred.gid = TEST_GID; + const char *name = "label4.test.aaa.bbb.ccc.dddd.eee"; + const char *value = "2001"; + ParamAuditData auditData = {}; + auditData.name = "label4.test.aaa.bbb.ccc.dddd.eee"; + auditData.label = "label4.test.aaa.bbb.ccc.dddd.eee"; + auditData.dacData.gid = TEST_DAC_GID2; + auditData.dacData.uid = geteuid(); + auditData.dacData.mode = TEST_READ_AND_WRITE; + SystemWriteParam(name, value); + uint32_t labelIndex = 0; + AddSecurityLabel(&auditData, GetParamWorkSpace()); + ParamTrieNode *paramNode = FindTrieNode(&GetParamWorkSpace()->paramSpace, name, strlen(name), &labelIndex); + ParamSecruityNode *node = (ParamSecruityNode *)GetTrieNode(&GetParamWorkSpace()->paramSpace, labelIndex); + if (paramNode == nullptr || node == nullptr) { + EXPECT_EQ(1, 0); + } + EXPECT_EQ(node->gid, auditData.dacData.gid); + return 0; + } + + void TestBufferValue(char *buffer, uint32_t len) + { + const int printBase = 10; + for (uint32_t index = 0; index <= len; index++) { + buffer[index] = '0' + index % printBase; + if (index != 0 && index % printBase == 0) { + buffer[index] = '.'; + } + } + buffer[len] = '\0'; + } + + int TestNameIsValid() + { + char buffer[PARAM_BUFFER_SIZE]; + // set name length = 127 + TestBufferValue(buffer, PARAM_NAME_LEN_MAX - 1); + int ret = SystemWriteParam(buffer, "1111"); + EXPECT_EQ(ret, 0); + TestBufferValue(buffer, PARAM_NAME_LEN_MAX); + ret = SystemWriteParam(buffer, "1111"); + EXPECT_NE(ret, 0); + TestBufferValue(buffer, PARAM_NAME_LEN_MAX + 1); + ret = SystemWriteParam(buffer, "1111"); + EXPECT_NE(ret, 0); + + // 保存一个只读的属性,大于最大值 + TestBufferValue(buffer, PARAM_VALUE_LEN_MAX - 1); + ret = SystemWriteParam("const.test_readonly.dddddddddddddddddd.fffffffffffffffffff", buffer); + EXPECT_EQ(ret, 0); + + TestBufferValue(buffer, PARAM_VALUE_LEN_MAX + 1); + ret = SystemWriteParam("const.test_readonly.aaaaaaaaaaaaaaaaaa.fffffffffffffffffff", buffer); + EXPECT_EQ(ret, 0); + + // 更新只读项目 + TestBufferValue(buffer, PARAM_VALUE_LEN_MAX - 1); + ret = SystemWriteParam("const.test_readonly.dddddddddddddddddd.fffffffffffffffffff", buffer); + EXPECT_NE(ret, 0); + + // 写普通属性 + TestBufferValue(buffer, PARAM_VALUE_LEN_MAX - 1); + ret = SystemWriteParam("test.bigvalue.dddddddddddddddddd.fffffffffffffffffff", buffer); + EXPECT_EQ(ret, 0); + TestBufferValue(buffer, PARAM_VALUE_LEN_MAX + 1); + ret = SystemWriteParam("test.bigvalue.dddddddddddddddddd.fffffffffffffffffff", buffer); + EXPECT_NE(ret, 0); + + // invalid name + TestBufferValue(buffer, PARAM_VALUE_LEN_MAX - 1); + ret = SystemWriteParam("test.invalidname..fffffffffffffffffff", buffer); + EXPECT_NE(ret, 0); + ret = SystemWriteParam("test.invalidname.%fffffffffffffffffff", buffer); + EXPECT_NE(ret, 0); + ret = SystemWriteParam("test.invalidname.$fffffffffffffffffff", buffer); + EXPECT_NE(ret, 0); + return 0; + } + + int TestParamTraversal() + { + char value[PARAM_BUFFER_SIZE + PARAM_BUFFER_SIZE] = { 0 }; + TraversalParam (GetParamWorkSpace(), + [](ParamHandle handle, void *cookie) { + ReadParamName(GetParamWorkSpace(), handle, (char *)cookie, PARAM_BUFFER_SIZE); + u_int32_t len = PARAM_BUFFER_SIZE; + ReadParamValue(GetParamWorkSpace(), handle, ((char *)cookie) + PARAM_BUFFER_SIZE, &len); + printf("$$$$$$$$Param %s=%s \n", (char *)cookie, ((char *)cookie) + PARAM_BUFFER_SIZE); + }, + (void *)value); + return 0; + } + + int TestUpdateParam(const char *name, const char *value) + { + SystemWriteParam(name, value); + SystemWriteParam(name, value); + SystemWriteParam(name, value); + SystemWriteParam(name, value); + CheckServerParamValue(name, value); + return 0; + } + + int TestPersistParam() + { + LoadPersistParams(); + SystemWriteParam("persist.111.ffff.bbbb.cccc.dddd.eeee", "1101"); + SystemWriteParam("persist.111.aaaa.bbbb.cccc.dddd.eeee", "1102"); + SystemWriteParam("persist.111.bbbb.cccc.dddd.eeee", "1103"); + CheckServerParamValue("persist.111.bbbb.cccc.dddd.eeee", "1103"); + SystemWriteParam("persist.111.cccc.bbbb.cccc.dddd.eeee", "1104"); + SystemWriteParam("persist.111.eeee.bbbb.cccc.dddd.eeee", "1105"); + CheckServerParamValue("persist.111.ffff.bbbb.cccc.dddd.eeee", "1101"); + SystemWriteParam("persist.111.ffff.bbbb.cccc.dddd.eeee", "1106"); + CheckServerParamValue("persist.111.ffff.bbbb.cccc.dddd.eeee", "1106"); + sleep(1); + SystemWriteParam("persist.111.bbbb.cccc.dddd.1107", "1107"); + SystemWriteParam("persist.111.bbbb.cccc.dddd.1108", "1108"); + SystemWriteParam("persist.111.bbbb.cccc.dddd.1109", "1108"); + sleep(1); + SystemWriteParam("persist.111.bbbb.cccc.dddd.1110", "1108"); + SystemWriteParam("persist.111.bbbb.cccc.dddd.1111", "1108"); + TimerCallbackForSave(NULL, NULL); + // 加载 + LoadPersistParam(GetParamWorkSpace()); + return 0; + } + + int FillLabelContent(ParamSecurityOps *paramSecurityOps, ParamMessage *request, uint32_t *start, uint32_t length) + { + if (length == 0) { + return 0; + } + 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 length %u", request->msgSize, offset, bufferSize); + ParamMsgContent *content = (ParamMsgContent *)(request->data + offset); + content->type = PARAM_LABEL; + content->contentSize = 0; + if (length != 0 && paramSecurityOps->securityEncodeLabel != nullptr) { + int ret = paramSecurityOps->securityEncodeLabel( + GetParamWorkSpace()->securityLabel, content->content, &length); + PARAM_CHECK(ret == 0, return -1, "Failed to get label length"); + content->contentSize = length; + } + offset += sizeof(ParamMsgContent) + PARAM_ALIGN(content->contentSize); + *start = offset; + return 0; + } + + ParamTask *CreateAndGetStreamTask() + { + LibuvServerTask *server = (LibuvServerTask *)GetParamWorkSpace()->serverTask; + if (server == nullptr) { + EXPECT_NE(0, 0); + return nullptr; + } + + // 创建stream task + server->incomingConnect((ParamTaskPtr)server, WORKER_TYPE_TEST); + ParamWatcher *watcher = GetNextParamWatcher(GetTriggerWorkSpace(), nullptr); + return watcher != nullptr ? watcher->stream : nullptr; + } + + int TestServiceProcessMessage(const char *name, const char *value, int userLabel) + { + if (g_worker == nullptr) { + g_worker = CreateAndGetStreamTask(); + } + uint32_t labelLen = 0; + ParamSecurityOps *paramSecurityOps = &GetParamWorkSpace()->paramSecurityOps; + if (userLabel) { + paramSecurityOps->securityEncodeLabel = TestEncodeSecurityLabel; + paramSecurityOps->securityDecodeLabel = TestDecodeSecurityLabel; + paramSecurityOps->securityFreeLabel = TestFreeLocalSecurityLabel; + paramSecurityOps->securityCheckParamPermission = TestCheckParamPermission; + } + uint32_t msgSize = sizeof(ParamMessage) + sizeof(ParamMsgContent) + PARAM_ALIGN(strlen(value) + 1); + if (paramSecurityOps->securityEncodeLabel != nullptr) { + int ret = paramSecurityOps->securityEncodeLabel(GetParamWorkSpace()->securityLabel, nullptr, &labelLen); + PARAM_CHECK(ret == 0, return -1, "Failed to get label length"); + msgSize += sizeof(ParamMsgContent) + PARAM_ALIGN(labelLen); + } + ParamMessage *request = (ParamMessage *)CreateParamMessage(MSG_SET_PARAM, name, msgSize); + PARAM_CHECK(request != nullptr, return -1, "Failed to malloc for connect"); + do { + request->type = MSG_SET_PARAM; + uint32_t offset = 0; + int ret = FillParamMsgContent(request, &offset, PARAM_VALUE, value, strlen(value)); + PARAM_CHECK(ret == 0, break, "Failed to fill value"); + ret = FillLabelContent(paramSecurityOps, request, &offset, labelLen); + PARAM_CHECK(ret == 0, break, "Failed to fill label"); + ProcessMessage((const ParamTaskPtr)g_worker, (const ParamMessage *)request); + } while (0); + free(request); + CheckServerParamValue(name, value); + RegisterSecurityOps(paramSecurityOps, 1); + return 0; + } + + int AddWatch(int type, const char *name, const char *value) + { + if (g_worker == nullptr) { + g_worker = CreateAndGetStreamTask(); + } + uint32_t msgSize = sizeof(ParamMessage) + sizeof(ParamMsgContent) + PARAM_ALIGN(strlen(value) + 1); + ParamMessage *request = (ParamMessage *)(ParamMessage *)CreateParamMessage(type, name, msgSize); + PARAM_CHECK(request != nullptr, return -1, "Failed to malloc for connect"); + do { + uint32_t offset = 0; + int ret = FillParamMsgContent(request, &offset, PARAM_VALUE, value, strlen(value)); + PARAM_CHECK(ret == 0, return -1, "Failed to fill value"); + ProcessMessage((const ParamTaskPtr)g_worker, (const ParamMessage *)request); + } while (0); + free(request); + return 0; + } + + // 无匹配 + int TestAddParamWait1() + { + const char *name = "wait.aaa.bbb.ccc.111"; + const char *value = "wait1"; + AddWatch(MSG_WAIT_PARAM, name, value); + SystemWriteParam(name, value); + return 0; + } + + // 模糊匹配 + int TestAddParamWait2() + { + const char *name = "wait.aaa.bbb.ccc.222"; + const char *value = "wait2"; + AddWatch(MSG_WAIT_PARAM, name, "*"); + SystemWriteParam(name, value); + return 0; + } + + // 属性存在 + int TestAddParamWait3() + { + const char *name = "wait.aaa.bbb.ccc.333"; + const char *value = "wait3"; + SystemWriteParam(name, value); + AddWatch(MSG_WAIT_PARAM, name, value); + return 0; + } + + int TestAddParamWatch1() + { + const char *name = "watch.aaa.bbb.ccc.111"; + const char *value = "watch1"; + AddWatch(MSG_ADD_WATCHER, name, value); + std::string newName = name; + newName += ".test.test.test"; + SystemWriteParam(newName.c_str(), value); + return 0; + } + + int TestAddParamWatch2() + { + const char *name = "watch.aaa.bbb.ccc.222"; + const char *value = "watch2"; + AddWatch(MSG_ADD_WATCHER, name, "*"); + SystemWriteParam(name, value); + return 0; + } + + int TestAddParamWatch3() + { + const char *name = "watch.aaa.bbb.ccc.333"; + const char *value = "watch3"; + std::string newName = name; + newName += ".test.test.test"; + SystemWriteParam(newName.c_str(), value); + AddWatch(MSG_ADD_WATCHER, name, value); + return 0; + } + + int TestCloseTriggerWatch() + { + ParamWatcher *watcher = (ParamWatcher *)ParamGetTaskUserData(g_worker); + ClearWatcherTrigger(watcher); + ParamTaskClose(g_worker); + g_worker = nullptr; + return 0; + } + + int TestDumpParamMemory() + { + DumpParametersAndTriggers(); + return 0; + } + + int TestServiceCtrl(const char *serviceName, int mode) + { + // service forbit + ParamAuditData auditData = {}; + auditData.name = "ohos.servicectrl."; + auditData.label = ""; + auditData.dacData.gid = TEST_DAC_GID; + auditData.dacData.uid = TEST_DAC_GID; + auditData.dacData.mode = mode; + AddSecurityLabel(&auditData, GetParamWorkSpace()); + return SystemWriteParam("ohos.ctl.start", serviceName); + } + + int TestPowerCtrl(const char *reboot, int mode) + { + // service forbit + ParamAuditData auditData = {}; + auditData.name = "ohos.servicectrl."; + auditData.label = ""; + auditData.dacData.gid = TEST_DAC_GID; + auditData.dacData.uid = TEST_DAC_GID; + auditData.dacData.mode = mode; + AddSecurityLabel(&auditData, GetParamWorkSpace()); + return SystemWriteParam("sys.powerctrl", reboot); + } +}; + +HWTEST_F(ParamServiceTest, TestParamServiceInit, TestSize.Level1) +{ + ParamServiceTest test; + test.TestParamServiceInit(); +} + +HWTEST_F(ParamServiceTest, TestPersistParam, TestSize.Level1) +{ + ParamServiceTest test; + test.TestPersistParam(); +} + +HWTEST_F(ParamServiceTest, TestSetParam_1, TestSize.Level1) +{ + ParamServiceTest test; + const char *params[][2] = { { "111.2222", "1" }, + { "111.2222.3333", "2" }, + { "111.2222.3333.4444", "3" }, + { "111.2222.3333.4444.666", "4" }, + { "111.2222.3333.4444.666.777", "5" } }; + test.TestSetParams(params, 5); +} + +HWTEST_F(ParamServiceTest, TestSetParam_2, TestSize.Level1) +{ + ParamServiceTest test; + const char *params[][2] = { { "111.2222.xxxx.xxx.xxx", "1_1" }, + { "111.2222.3333.xxx", "1_2" }, + { "111.2222.xxxx.3333.4444", "1_3" }, + { "111.2222.3333.xxxx.4444.666", "1_4" }, + { "111.2222.3333.4444.666.xxxxx.777", "1_5" } }; + test.TestSetParams(params, 5); + + const char *ctrlParams[][2] = { { "ctl.start.111.2222.xxxx.xxx.xxx", "2_1" }, + { "ctl.start.111.2222.3333.xxx", "2_2" }, + { "ctl.start.111.2222.xxxx.3333.4444", "2_3" }, + { "ctl.start.111.2222.3333.xxxx.4444.666", "2_4" }, + { "ctl.start.111.2222.3333.4444.666.xxxxx.777", "2_5" } }; + test.TestSetParams(ctrlParams, 5); + + const char *sysParams[][2] = { { "sys.powerctrl.111.2222.xxxx.xxx.xxx", "3_1" }, + { "sys.powerctrl.111.2222.3333.xxx", "3_2" }, + { "sys.powerctrl.111.2222.xxxx.3333.4444", "3_3" }, + { "sys.powerctrl.111.2222.3333.xxxx.4444.666", "3_4" }, + { "sys.powerctrl.111.2222.3333.4444.666.xxxxx.777", "3_5" } }; + test.TestSetParams(sysParams, 5); +} + +HWTEST_F(ParamServiceTest, TestNameIsValid, TestSize.Level1) +{ + ParamServiceTest test; + test.TestNameIsValid(); +} + +HWTEST_F(ParamServiceTest, TestAddSecurityLabel1, TestSize.Level1) +{ + ParamServiceTest test; + test.TestAddSecurityLabel1(); +} + +HWTEST_F(ParamServiceTest, TestAddSecurityLabel2, TestSize.Level1) +{ + ParamServiceTest test; + test.TestAddSecurityLabel2(); +} + +HWTEST_F(ParamServiceTest, TestAddSecurityLabel3, TestSize.Level1) +{ + ParamServiceTest test; + test.TestAddSecurityLabel3(); +} + +HWTEST_F(ParamServiceTest, TestAddSecurityLabel4, TestSize.Level1) +{ + ParamServiceTest test; + test.TestAddSecurityLabel4(); +} + +HWTEST_F(ParamServiceTest, TestUpdateParam, TestSize.Level1) +{ + ParamServiceTest test; + test.TestUpdateParam("test.aaa.bbb.ccc.ddd", "100"); + test.TestUpdateParam("test.aaa.bbb.ccc.ddd", "101"); + test.TestUpdateParam("test.aaa.bbb.ccc.ddd", "102"); + test.TestUpdateParam("test.aaa.bbb.ccc.ddd", "103"); + test.TestUpdateParam("net.tcp.default_init_rwnd", "60"); +} + +HWTEST_F(ParamServiceTest, TestServiceProcessMessage, TestSize.Level1) +{ + ParamServiceTest test; + test.TestServiceProcessMessage("wertt.qqqq.wwww.rrrr", "wwww.eeeee", 1); + test.TestServiceProcessMessage("wertt.2222.wwww.3333", "wwww.eeeee", 0); +} + +HWTEST_F(ParamServiceTest, TestAddParamWait1, TestSize.Level1) +{ + ParamServiceTest test; + test.TestAddParamWait1(); +} + +HWTEST_F(ParamServiceTest, TestAddParamWait2, TestSize.Level1) +{ + ParamServiceTest test; + test.TestAddParamWait2(); +} + +HWTEST_F(ParamServiceTest, TestAddParamWait3, TestSize.Level1) +{ + ParamServiceTest test; + test.TestAddParamWait3(); +} + +HWTEST_F(ParamServiceTest, TestAddParamWatch1, TestSize.Level1) +{ + ParamServiceTest test; + test.TestAddParamWatch1(); +} + +HWTEST_F(ParamServiceTest, TestAddParamWatch2, TestSize.Level1) +{ + ParamServiceTest test; + test.TestAddParamWatch2(); +} + +HWTEST_F(ParamServiceTest, TestAddParamWatch3, TestSize.Level1) +{ + ParamServiceTest test; + test.TestAddParamWatch3(); +} + +HWTEST_F(ParamServiceTest, TestCloseTriggerWatch, TestSize.Level1) +{ + ParamServiceTest test; + test.TestCloseTriggerWatch(); +} + +HWTEST_F(ParamServiceTest, TestParamTraversal, TestSize.Level1) +{ + ParamServiceTest test; + test.TestParamTraversal(); +} + +HWTEST_F(ParamServiceTest, TestDumpParamMemory, TestSize.Level1) +{ + ParamServiceTest test; + test.TestDumpParamMemory(); +} + +HWTEST_F(ParamServiceTest, TestServiceCtrl, TestSize.Level1) +{ + ParamServiceTest test; + int ret = test.TestServiceCtrl("server1", 0770); + EXPECT_NE(ret, 0); + ret = test.TestServiceCtrl("server2", 0772); + EXPECT_EQ(ret, 0); +} + +HWTEST_F(ParamServiceTest, TestPowerCtrl, TestSize.Level1) +{ + ParamServiceTest test; + int ret = test.TestPowerCtrl("reboot,shutdown", 0770); + EXPECT_NE(ret, 0); + ret = test.TestPowerCtrl("reboot,shutdown", 0772); + EXPECT_EQ(ret, 0); + ret = test.TestPowerCtrl("reboot,updater", 0770); + EXPECT_NE(ret, 0); + ret = test.TestPowerCtrl("reboot,updater", 0772); + EXPECT_EQ(ret, 0); + ret = test.TestPowerCtrl("reboot,flash", 0770); + EXPECT_NE(ret, 0); + ret = test.TestPowerCtrl("reboot,flash", 0772); + EXPECT_EQ(ret, 0); + ret = test.TestPowerCtrl("reboot", 0770); + EXPECT_NE(ret, 0); + ret = test.TestPowerCtrl("reboot", 0772); + EXPECT_EQ(ret, 0); +} \ No newline at end of file diff --git a/services/test/unittest/param/selinux_unittest.cpp b/services/test/unittest/param/selinux_unittest.cpp new file mode 100755 index 0000000..00d4717 --- /dev/null +++ b/services/test/unittest/param/selinux_unittest.cpp @@ -0,0 +1,284 @@ +/* + * 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 "init_unittest.h" +#include "param_security.h" +#include "param_utils.h" +#include "securec.h" + +extern "C" { +extern int RegisterSecuritySelinuxOps(ParamSecurityOps *ops, int isInit); +} + +using namespace testing::ext; +using namespace std; + +static int SecurityLabelGet(const ParamAuditData *auditData, void *context) +{ + return 0; +} + +class ParamSelinuxTest : public ::testing::Test { +public: + ParamSelinuxTest() {} + virtual ~ParamSelinuxTest() {} + + void SetUp() {} + void TearDown() {} + void TestBody() {} + + int TestSelinuxGetLabel() + { + int ret = RegisterSecuritySelinuxOps(&initParamSercurityOps, LABEL_INIT_FOR_INIT); + EXPECT_EQ(ret, 0); + + if (initParamSercurityOps.securityGetLabel == nullptr) { + EXPECT_EQ(1, 0); + return -1; + } + ret = initParamSercurityOps.securityGetLabel(SecurityLabelGet, + PARAM_DEFAULT_PATH "/system/etc/param", nullptr); + EXPECT_EQ(ret, 0); + return 0; + } + + int TestSelinuxInitLocalLabel() + { + int ret = RegisterSecuritySelinuxOps(&initParamSercurityOps, LABEL_INIT_FOR_INIT); + EXPECT_EQ(ret, 0); + + if (initParamSercurityOps.securityInitLabel == nullptr || initParamSercurityOps.securityFreeLabel == nullptr) { + return -1; + } + ParamSecurityLabel *label = nullptr; + ret = initParamSercurityOps.securityInitLabel(&label, LABEL_INIT_FOR_INIT); + EXPECT_EQ(ret, 0); + ret = initParamSercurityOps.securityFreeLabel(label); + EXPECT_EQ(ret, 0); + return 0; + } + + int TestSelinuxCheckFilePermission(const char *fileName) + { + int ret = RegisterSecuritySelinuxOps(&initParamSercurityOps, LABEL_INIT_FOR_INIT); + EXPECT_EQ(ret, 0); + if (initParamSercurityOps.securityCheckFilePermission == nullptr) { + return -1; + } + ParamSecurityLabel *label = nullptr; + ret = initParamSercurityOps.securityInitLabel(&label, LABEL_INIT_FOR_INIT); + EXPECT_EQ(ret, 0); + ret = initParamSercurityOps.securityCheckFilePermission(label, fileName, DAC_WRITE); + EXPECT_EQ(ret, 0); + ret = initParamSercurityOps.securityFreeLabel(label); + EXPECT_EQ(ret, 0); + return 0; + } + + int TestSelinuxCheckParaPermission(const char *name, const char *label) + { + int ret = RegisterSecuritySelinuxOps(&initParamSercurityOps, LABEL_INIT_FOR_INIT); + EXPECT_EQ(ret, 0); + if (initParamSercurityOps.securityCheckFilePermission == nullptr) { + return -1; + } + ParamSecurityLabel *srclabel = nullptr; + ret = initParamSercurityOps.securityInitLabel(&srclabel, LABEL_INIT_FOR_INIT); + EXPECT_EQ(ret, 0); + + ParamAuditData auditData = {}; + auditData.name = name; + auditData.label = label; + + ret = initParamSercurityOps.securityCheckParamPermission(srclabel, &auditData, DAC_WRITE); + EXPECT_EQ(ret, 0); + ret = initParamSercurityOps.securityFreeLabel(srclabel); + EXPECT_EQ(ret, 0); + return 0; + } + + int TestClientSelinuxCheckFilePermission(const char *fileName) + { + int ret = RegisterSecuritySelinuxOps(&clientParamSercurityOps, 0); + EXPECT_EQ(ret, 0); + if (clientParamSercurityOps.securityDecodeLabel != nullptr) { + EXPECT_EQ(1, 0); + } + if (clientParamSercurityOps.securityGetLabel != nullptr) { + EXPECT_EQ(1, 0); + } + if (clientParamSercurityOps.securityCheckFilePermission == nullptr) { + EXPECT_EQ(1, 0); + return -1; + } + ParamSecurityLabel *label = nullptr; + ret = clientParamSercurityOps.securityInitLabel(&label, 0); + EXPECT_EQ(ret, 0); + ret = clientParamSercurityOps.securityCheckFilePermission(label, fileName, DAC_READ); + EXPECT_EQ(ret, 0); + ret = clientParamSercurityOps.securityFreeLabel(label); + EXPECT_EQ(ret, 0); + return 0; + } + + int TestClientSelinuxCheckParaPermissionWrite(const char *name, const char *label) + { + int ret = RegisterSecuritySelinuxOps(&clientParamSercurityOps, 0); + EXPECT_EQ(ret, 0); + + if (clientParamSercurityOps.securityCheckFilePermission == nullptr) { + return -1; + } + ParamSecurityLabel *srclabel = nullptr; + ret = clientParamSercurityOps.securityInitLabel(&srclabel, 0); + EXPECT_EQ(ret, 0); + + ParamAuditData auditData = {}; + auditData.name = name; + auditData.label = label; + + ret = clientParamSercurityOps.securityCheckParamPermission(srclabel, &auditData, DAC_WRITE); + EXPECT_EQ(ret, 0); + ret = clientParamSercurityOps.securityFreeLabel(srclabel); + EXPECT_EQ(ret, 0); + return 0; + } + + int TestClientSelinuxCheckParaPermissionRead(const char *name, const char *label) + { + int ret = RegisterSecuritySelinuxOps(&clientParamSercurityOps, 0); + EXPECT_EQ(ret, 0); + if (clientParamSercurityOps.securityCheckFilePermission == nullptr) { + return -1; + } + ParamSecurityLabel *srclabel = nullptr; + ret = clientParamSercurityOps.securityInitLabel(&srclabel, 0); + EXPECT_EQ(ret, 0); + + ParamAuditData auditData = {}; + auditData.name = name; + auditData.label = label; + + ret = clientParamSercurityOps.securityCheckParamPermission(srclabel, &auditData, DAC_READ); + EXPECT_EQ(ret, 0); + ret = clientParamSercurityOps.securityFreeLabel(srclabel); + EXPECT_EQ(ret, 0); + return 0; + } + + int TestEncode(ParamSecurityLabel *&label, std::vector &buffer) + { + int ret = RegisterSecuritySelinuxOps(&clientParamSercurityOps, 0); + EXPECT_EQ(ret, 0); + if (clientParamSercurityOps.securityDecodeLabel != nullptr) { + EXPECT_EQ(1, 0); + } + if (clientParamSercurityOps.securityGetLabel != nullptr) { + EXPECT_EQ(1, 0); + } + if (clientParamSercurityOps.securityEncodeLabel == nullptr) { + EXPECT_EQ(1, 0); + return -1; + } + ret = clientParamSercurityOps.securityInitLabel(&label, 0); + EXPECT_EQ(ret, 0); + + uint32_t bufferSize = 0; + ret = clientParamSercurityOps.securityEncodeLabel(label, nullptr, &bufferSize); + EXPECT_EQ(ret, 0); + buffer.resize(bufferSize + 1); + ret = clientParamSercurityOps.securityEncodeLabel(label, buffer.data(), &bufferSize); + EXPECT_EQ(ret, 0); + return 0; + } + + int TestDecode(ParamSecurityLabel *label, std::vector &buffer) + { + int ret = RegisterSecuritySelinuxOps(&clientParamSercurityOps, 1); + EXPECT_EQ(ret, 0); + if (clientParamSercurityOps.securityDecodeLabel == nullptr) { + EXPECT_EQ(1, 0); + } + if (clientParamSercurityOps.securityEncodeLabel != nullptr) { + EXPECT_EQ(1, 0); + return -1; + } + ParamSecurityLabel *tmp = nullptr; + ret = clientParamSercurityOps.securityDecodeLabel(&tmp, buffer.data(), buffer.size()); + EXPECT_EQ(ret, 0); + EXPECT_EQ(label->cred.gid, tmp->cred.gid); + EXPECT_EQ(label->cred.uid, tmp->cred.uid); + ret = clientParamSercurityOps.securityFreeLabel(tmp); + EXPECT_EQ(ret, 0); + ret = clientParamSercurityOps.securityFreeLabel(label); + EXPECT_EQ(ret, 0); + return 0; + } + +private: + ParamSecurityOps initParamSercurityOps; + ParamSecurityOps clientParamSercurityOps; +}; + +HWTEST_F(ParamSelinuxTest, TestSelinuxGetLabel, TestSize.Level1) +{ + ParamSelinuxTest test; + test.TestSelinuxGetLabel(); +} + +HWTEST_F(ParamSelinuxTest, TestSelinuxInitLocalLabel, TestSize.Level1) +{ + ParamSelinuxTest test; + test.TestSelinuxInitLocalLabel(); +} + +HWTEST_F(ParamSelinuxTest, TestSelinuxCheckFilePermission, TestSize.Level1) +{ + ParamSelinuxTest test; + test.TestSelinuxCheckFilePermission(PARAM_DEFAULT_PATH"/trigger_test.cfg"); +} + +HWTEST_F(ParamSelinuxTest, TestSelinuxCheckParaPermission, TestSize.Level1) +{ + ParamSelinuxTest test; + test.TestSelinuxCheckParaPermission("aaa.bbb.bbb.ccc", "user:group1:r"); +} + +HWTEST_F(ParamSelinuxTest, TestClientDacCheckFilePermission, TestSize.Level1) +{ + ParamSelinuxTest test; + test.TestClientSelinuxCheckFilePermission(PARAM_DEFAULT_PATH"/trigger_test.cfg"); +} + +HWTEST_F(ParamSelinuxTest, TestClientDacCheckParaPermission, TestSize.Level1) +{ + ParamSelinuxTest test; + test.TestClientSelinuxCheckParaPermissionWrite("aaa.bbb.bbb.ccc", "user:group1:r"); + test.TestClientSelinuxCheckParaPermissionRead("aaa.bbb.bbb.ccc", "user:group1:r"); +} + +HWTEST_F(ParamSelinuxTest, TestSeliniuxLabelEncode, TestSize.Level1) +{ + ParamSelinuxTest test; + std::vector buffer; + ParamSecurityLabel *label; + test.TestEncode(label, buffer); + test.TestDecode(label, buffer); +} \ No newline at end of file diff --git a/services/test/unittest/param/trigger_unittest.cpp b/services/test/unittest/param/trigger_unittest.cpp new file mode 100755 index 0000000..44f0e9d --- /dev/null +++ b/services/test/unittest/param/trigger_unittest.cpp @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "init_jobs.h" +#include "init_param.h" +#include "init_unittest.h" +#include "init_utils.h" +#include "param_libuvadp.h" +#include "param_manager.h" +#include "param_service.h" +#include "param_stub.h" +#include "param_utils.h" +#include "securec.h" +#include "trigger_checker.h" +#include "trigger_manager.h" + +using namespace testing::ext; +using namespace std; + +const static int32_t g_maxCount = 6; +static int32_t g_repeatCount = 0; +static void TimerCallback(ParamTaskPtr timer, void *context) +{ + TestClient(g_repeatCount); + g_repeatCount = g_repeatCount + 1; + if (g_repeatCount >= g_maxCount) { + ParamTaskClose(timer); + StopParamService(); + } +} + +static const int triggerBuffer = 512; +static uint32_t g_execCmdId = 0; +static int g_matchTrigger = 0; +static char g_matchTriggerName[triggerBuffer] = { 0 }; +static void TestCmdExec(const TriggerNode *trigger, const 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 != nullptr && extData->excuteCmd != nullptr) { + extData->excuteCmd(extData, cmd->cmdKeyIndex, content); + } + return; + } + g_execCmdId = cmd->cmdKeyIndex; +} + +static int TestTriggerExecute(TriggerNode *trigger, const char *content, uint32_t size) +{ + int ret = memcpy_s(g_matchTriggerName, (int)sizeof(g_matchTriggerName) - 1, trigger->name, strlen(trigger->name)); + EXPECT_EQ(ret, 0); + g_matchTriggerName[strlen(trigger->name)] = '\0'; + g_matchTrigger++; + return 0; +} + +class TriggerTest : public ::testing::Test { +public: + TriggerTest() {} + virtual ~TriggerTest() {} + + void SetUp() {} + void TearDown() {} + void TestBody() {} + + int TestRunClient() + { + TestClient(0); + ParamTaskPtr timer = nullptr; + ParamTimerCreate(&timer, TimerCallback, nullptr); + ParamTimerStart(timer, 1000, g_maxCount); + StartParamService(); + return 0; + } + + int ParseInitCfg(const char *configFile) + { + char *fileBuf = ReadFileToBuf(configFile); + INIT_ERROR_CHECK(fileBuf != nullptr, return -1, "Failed to read file content %s", configFile); + cJSON *fileRoot = cJSON_Parse(fileBuf); + INIT_ERROR_CHECK(fileRoot != nullptr, return -1, "Failed to parse json file %s", configFile); + ParseTriggerConfig(fileRoot); + cJSON_Delete(fileRoot); + free(fileBuf); + fileBuf = nullptr; + return 0; + } + + int TestLoadTrigger() + { + int cmdKeyIndex = 0; + const char *matchCmd = GetMatchCmd("setparam aaaa aaaa", &cmdKeyIndex); + printf("cmd %d \n", matchCmd != nullptr); + EXPECT_EQ(matchCmd != 0, 1); + + ReadConfig(); + ParseInitCfg(PARAM_DEFAULT_PATH "/trigger_test.cfg"); + // trigger + PostTrigger(EVENT_TRIGGER_BOOT, "pre-init", strlen("pre-init")); + PostTrigger(EVENT_TRIGGER_BOOT, "init", strlen("init")); + PostTrigger(EVENT_TRIGGER_BOOT, "post-init", strlen("post-init")); + LibuvEventTask *task = (LibuvEventTask *)(GetTriggerWorkSpace()->eventHandle); + if (task != nullptr) { // 触发队列执行 + task->process(1, nullptr, 0); + } + return 0; + } + + TriggerHeader *GetTriggerHeader(int type) + { + return &GetTriggerWorkSpace()->triggerHead[type]; + } + + int TestAddTriggerForBoot() + { + TriggerNode *node = AddTrigger(GetTriggerHeader(TRIGGER_BOOT), "init-later", "", 0); + TriggerNode *trigger = GetTriggerByName(GetTriggerWorkSpace(), "init-later"); + EXPECT_EQ(node, trigger); + EXPECT_EQ(strcmp(trigger->name, "init-later"), 0); + + // add command + int cmdIndex = 0; + GetMatchCmd("reboot ", &cmdIndex); + int ret = AddCommand(trigger, cmdIndex, nullptr); + EXPECT_EQ(ret, 0); + ret = AddCommand(trigger, cmdIndex, "update: aaaaaaa"); + EXPECT_EQ(ret, 0); + return 0; + } + + int TestAddTriggerForParm() + { + const char *triggerName = "param:test_param.000"; + TriggerNode *node = AddTrigger(GetTriggerHeader(TRIGGER_PARAM), triggerName, "test_param.000=1", 0); + TriggerNode *trigger = GetTriggerByName(GetTriggerWorkSpace(), triggerName); + EXPECT_EQ(trigger, node); + EXPECT_EQ(strcmp(trigger->name, triggerName), 0); + + // add command + int cmdIndex = 0; + GetMatchCmd("reboot ", &cmdIndex); + int ret = AddCommand(trigger, cmdIndex, nullptr); + ret |= AddCommand(trigger, cmdIndex, "update: aaaaaaa"); + EXPECT_EQ(ret, 0); + return 0; + } + + int TestParamEvent() + { + PostParamTrigger(EVENT_TRIGGER_PARAM, "net.tcp.default_init_rwnd", "60"); + const char *sysctrl = "sys.powerctrl=reboot, shutdown"; + PostTrigger(EVENT_TRIGGER_PARAM, sysctrl, strlen(sysctrl)); + PostParamTrigger(EVENT_TRIGGER_PARAM, "sys.powerctrl", "reboot, shutdown"); + + const char *startCmd = "ohos.ctl.start=hdc -t"; + PostTrigger(EVENT_TRIGGER_PARAM, startCmd, strlen(startCmd)); + PostParamTrigger(EVENT_TRIGGER_PARAM, "ohos.ctl.start", "hdc -t"); + + const char *stopCmd = "ohos.ctl.stop=hdc -t"; + PostTrigger(EVENT_TRIGGER_PARAM, stopCmd, strlen(stopCmd)); + PostParamTrigger(EVENT_TRIGGER_PARAM, "ohos.ctl.stop", "hdc -t"); + return 0; + } + + int TestBootEvent(const char *boot) + { + PostTrigger(EVENT_TRIGGER_BOOT, boot, strlen(boot)); + return 0; + } + + int TestCheckParamTrigger1() + { + const char *triggerName = "param:test_param.111"; + const char *param = "test_param.aaa.111.2222"; + const char *value = "1"; + char buffer[triggerBuffer]; + int ret = sprintf_s(buffer, sizeof(buffer), "%s=%s", param, value); + EXPECT_GE(ret, 0); + TriggerNode *node = AddTrigger(GetTriggerHeader(TRIGGER_PARAM), triggerName, buffer, 0); + TriggerNode *trigger = GetTriggerByName(GetTriggerWorkSpace(), triggerName); + EXPECT_EQ(trigger, node); + + g_matchTrigger = 0; + ret = sprintf_s(buffer, sizeof(buffer), "%s=%s", param, "2"); + EXPECT_GE(ret, 0); + CheckTrigger(GetTriggerWorkSpace(), TRIGGER_PARAM, buffer, strlen(buffer), TestTriggerExecute); + EXPECT_EQ(0, g_matchTrigger); + + g_matchTrigger = 0; + ret = sprintf_s(buffer, sizeof(buffer), "%s=%s", param, value); + EXPECT_GE(ret, 0); + CheckTrigger(GetTriggerWorkSpace(), TRIGGER_PARAM, buffer, strlen(buffer), TestTriggerExecute); + EXPECT_EQ(1, g_matchTrigger); + EXPECT_EQ(0, strcmp(triggerName, g_matchTriggerName)); + return 0; + } + + int TestCheckParamTrigger2() + { + const char *triggerName = "param:test_param.222"; + const char *param = "test_param.aaa.222.2222"; + const char *value = "1"; + char buffer[triggerBuffer]; + int ret = sprintf_s(buffer, sizeof(buffer), "%s=*", param); + EXPECT_GE(ret, 0); + TriggerNode *node = AddTrigger(GetTriggerHeader(TRIGGER_PARAM), triggerName, buffer, 0); + TriggerNode *trigger = GetTriggerByName(GetTriggerWorkSpace(), triggerName); + EXPECT_EQ(trigger, node); + + g_matchTrigger = 0; + ret = sprintf_s(buffer, sizeof(buffer), "%s=%s", param, "2"); + EXPECT_GE(ret, 0); + CheckTrigger(GetTriggerWorkSpace(), TRIGGER_PARAM, buffer, strlen(buffer), TestTriggerExecute); + EXPECT_EQ(1, g_matchTrigger); + EXPECT_EQ(0, strcmp(triggerName, g_matchTriggerName)); + + g_matchTrigger = 0; + ret = sprintf_s(buffer, sizeof(buffer), "%s=%s", param, value); + EXPECT_GE(ret, 0); + CheckTrigger(GetTriggerWorkSpace(), TRIGGER_PARAM, param, strlen(param), TestTriggerExecute); + EXPECT_EQ(1, g_matchTrigger); + EXPECT_EQ(0, strcmp(triggerName, g_matchTriggerName)); + return 0; + } + + int TestCheckParamTrigger3() + { + const char *triggerName = "param:test_param.333"; + const char *param1 = "test_param.aaa.333.2222=1"; + const char *param2 = "test_param.aaa.333.3333=2"; + char buffer[triggerBuffer]; + int ret = sprintf_s(buffer, sizeof(buffer), "%s || %s", param1, param2); + EXPECT_GE(ret, 0); + TriggerNode *node = AddTrigger(GetTriggerHeader(TRIGGER_PARAM), triggerName, buffer, 0); + TriggerNode *trigger = GetTriggerByName(GetTriggerWorkSpace(), triggerName); + EXPECT_EQ(trigger, node); + + g_matchTrigger = 0; + CheckTrigger(GetTriggerWorkSpace(), TRIGGER_PARAM, param1, strlen(param1), TestTriggerExecute); + EXPECT_EQ(1, g_matchTrigger); + EXPECT_EQ(0, strcmp(triggerName, g_matchTriggerName)); + + g_matchTrigger = 0; + CheckTrigger(GetTriggerWorkSpace(), TRIGGER_PARAM, param2, strlen(param2), TestTriggerExecute); + EXPECT_EQ(1, g_matchTrigger); + EXPECT_EQ(0, strcmp(triggerName, g_matchTriggerName)); + return 0; + } + + int TestCheckParamTrigger4() + { + const char *triggerName = "param:test_param.444"; + const char *param1 = "test_param.aaa.444.2222"; + const char *param2 = "test_param.aaa.444.3333"; + char buffer[triggerBuffer]; + int ret = sprintf_s(buffer, sizeof(buffer), "%s=%s && %s=%s", param1, "1", param2, "2"); + EXPECT_GE(ret, 0); + TriggerNode *node = AddTrigger(GetTriggerHeader(TRIGGER_PARAM), triggerName, buffer, 0); + TriggerNode *trigger = GetTriggerByName(GetTriggerWorkSpace(), triggerName); + EXPECT_EQ(trigger, node); + + g_matchTrigger = 0; + SystemWriteParam(param1, "1"); + ret = sprintf_s(buffer, sizeof(buffer), "%s=%s", param1, "1"); + EXPECT_GE(ret, 0); + CheckTrigger(GetTriggerWorkSpace(), TRIGGER_PARAM, buffer, strlen(buffer), TestTriggerExecute); + EXPECT_EQ(0, g_matchTrigger); + + SystemWriteParam(param2, "2"); + g_matchTrigger = 0; + ret = sprintf_s(buffer, sizeof(buffer), "%s=%s", param2, "2"); + EXPECT_GE(ret, 0); + CheckTrigger(GetTriggerWorkSpace(), TRIGGER_PARAM, buffer, strlen(buffer), TestTriggerExecute); + EXPECT_EQ(1, g_matchTrigger); + EXPECT_EQ(0, strcmp(triggerName, g_matchTriggerName)); + return 0; + } + + // test for trigger aaaa:test_param.aaa 被加入unknown执行 + int TestCheckParamTrigger5() + { + const char *triggerName = "aaaa:test_param.aaa"; + const char *param1 = "test_param.aaa.aaa.2222"; + const char *param2 = "test_param.aaa.aaa.3333"; + char buffer[triggerBuffer]; + int ret = sprintf_s(buffer, sizeof(buffer), "aaaa && %s=%s && %s=%s", param1, "1", param2, "2"); + EXPECT_GE(ret, 0); + TriggerNode *node = AddTrigger(GetTriggerHeader(TRIGGER_UNKNOW), triggerName, buffer, 0); + TriggerNode *trigger = GetTriggerByName(GetTriggerWorkSpace(), triggerName); + EXPECT_EQ(trigger, node); + + g_matchTrigger = 0; + SystemWriteParam(param1, "1"); + ret = sprintf_s(buffer, sizeof(buffer), "%s=%s", param1, "1"); + EXPECT_GE(ret, 0); + CheckTrigger(GetTriggerWorkSpace(), TRIGGER_PARAM, buffer, strlen(buffer), TestTriggerExecute); + EXPECT_EQ(0, g_matchTrigger); + + SystemWriteParam(param2, "2"); + g_matchTrigger = 0; + CheckTrigger(GetTriggerWorkSpace(), TRIGGER_UNKNOW, "aaaa", strlen("aaaa"), TestTriggerExecute); + EXPECT_EQ(1, g_matchTrigger); + EXPECT_EQ(0, strcmp(triggerName, g_matchTriggerName)); + return 0; + } + + int TestComputeCondition(const char *condition) + { + u_int32_t size = strlen(condition) + CONDITION_EXTEND_LEN; + char *prefix = (char *)malloc(size); + ConvertInfixToPrefix(condition, prefix, size); + printf("prefix %s \n", prefix); + free(prefix); + return 0; + } + + // 普通的属性trigger + int TestExecuteParamTrigger1() + { + const char *triggerName = "aaaa:test_param.eee"; + const char *param = "test_param.eee.aaa.1111"; + const char *value = "eee"; + char buffer[triggerBuffer]; + int ret = sprintf_s(buffer, sizeof(buffer), "%s=%s", param, value); + EXPECT_GE(ret, 0); + TriggerNode *node = AddTrigger(GetTriggerHeader(TRIGGER_PARAM), triggerName, buffer, 0); + TriggerNode *trigger = GetTriggerByName(GetTriggerWorkSpace(), triggerName); + EXPECT_EQ(trigger, node); + + const uint32_t cmdIndex = 100; + ret = AddCommand(trigger, cmdIndex, value); + EXPECT_EQ(ret, 0); + // 修改命令为测试执行 + GetTriggerWorkSpace()->cmdExec = TestCmdExec; + LibuvEventTask *task = (LibuvEventTask *)(GetTriggerWorkSpace()->eventHandle); + SystemWriteParam(param, value); + // 触发队列执行 + task->process(1, nullptr, 0); + EXPECT_EQ(g_execCmdId, cmdIndex); + return 0; + } + + int TestExecuteParamTrigger2() + { + const char *triggerName = "param:test_param.dddd"; + const char *param = "test_param.dddd.aaa.2222"; + const char *value = "2222"; + char buffer[triggerBuffer]; + int ret = sprintf_s(buffer, sizeof(buffer), "%s=%s", param, value); + EXPECT_GE(ret, 0); + TriggerNode *node = AddTrigger(GetTriggerHeader(TRIGGER_PARAM), triggerName, buffer, 0); + TriggerNode *trigger = GetTriggerByName(GetTriggerWorkSpace(), triggerName); + EXPECT_EQ(trigger, node); + const uint32_t cmdIndex = 102; + ret = AddCommand(trigger, cmdIndex, value); + EXPECT_EQ(ret, 0); + // 修改命令为测试执行 + GetTriggerWorkSpace()->cmdExec = TestCmdExec; + LibuvEventTask *task = (LibuvEventTask *)(GetTriggerWorkSpace()->eventHandle); + task->beforeProcess(EVENT_TRIGGER_PARAM, buffer, strlen(buffer)); + // 触发队列执行 + task->process(EVENT_TRIGGER_PARAM, nullptr, 0); + EXPECT_EQ(g_execCmdId, cmdIndex); + return 0; + } + + // 测试执行后立刻删除 + int TestExecuteParamTrigger3() + { + const char *triggerName = "param:test_param.3333"; + const char *param = "test_param.dddd.aaa.3333"; + const char *value = "3333"; + char buffer[triggerBuffer]; + int ret = sprintf_s(buffer, sizeof(buffer), "%s=%s", param, value); + EXPECT_GE(ret, 0); + TriggerNode *node = AddTrigger(GetTriggerHeader(TRIGGER_PARAM), triggerName, buffer, 0); + TriggerNode *trigger = GetTriggerByName(GetTriggerWorkSpace(), triggerName); + EXPECT_EQ(trigger, node); + const uint32_t cmdIndex = 103; + ret = AddCommand(trigger, cmdIndex, value); + EXPECT_EQ(ret, 0); + TRIGGER_SET_FLAG(trigger, TRIGGER_FLAGS_ONCE); + + // 修改命令为测试执行 + GetTriggerWorkSpace()->cmdExec = TestCmdExec; + LibuvEventTask *task = (LibuvEventTask *)(GetTriggerWorkSpace()->eventHandle); + task->beforeProcess(EVENT_TRIGGER_PARAM, buffer, strlen(buffer)); + // 触发队列执行 + task->process(EVENT_TRIGGER_PARAM, nullptr, 0); + EXPECT_EQ(g_execCmdId, cmdIndex); + trigger = GetTriggerByName(GetTriggerWorkSpace(), triggerName); + if (trigger != nullptr) { + EXPECT_EQ(1, 0); + } + return 0; + } + + // 测试删除队列中的trigger + int TestExecuteParamTrigger4() + { + const char *triggerName = "param:test_param.4444"; + const char *param = "test_param.dddd.aaa.4444"; + const char *value = "4444"; + char buffer[triggerBuffer]; + int ret = sprintf_s(buffer, sizeof(buffer), "%s=%s", param, value); + EXPECT_GE(ret, 0); + TriggerNode *node = AddTrigger(GetTriggerHeader(TRIGGER_PARAM), triggerName, buffer, 0); + TriggerNode *trigger = GetTriggerByName(GetTriggerWorkSpace(), triggerName); + EXPECT_EQ(trigger, node); + const uint32_t cmdIndex = 105; + ret = AddCommand(trigger, cmdIndex, value); + EXPECT_EQ(ret, 0); + TRIGGER_SET_FLAG(trigger, TRIGGER_FLAGS_ONCE); + + // 修改命令为测试执行 + GetTriggerWorkSpace()->cmdExec = TestCmdExec; + LibuvEventTask *task = (LibuvEventTask *)(GetTriggerWorkSpace()->eventHandle); + task->beforeProcess(EVENT_TRIGGER_PARAM, buffer, strlen(buffer)); + + // 删除对应的trigger + FreeTrigger(trigger); + + // 触发队列执行 + task->process(EVENT_TRIGGER_PARAM, nullptr, 0); + EXPECT_NE(g_execCmdId, cmdIndex); + trigger = GetTriggerByName(GetTriggerWorkSpace(), triggerName); + if (trigger != nullptr) { + EXPECT_EQ(1, 0); + } + return 0; + } + + // 测试执行后检查子trigger执行 + int TestExecuteParamTrigger5() + { + const char *boot = "boot2"; + const char *triggerName = "boot2:test_param.5555"; + const char *param = "test_param.dddd.aaa.5555"; + const char *value = "5555"; + TriggerNode *trigger = AddTrigger(GetTriggerHeader(TRIGGER_BOOT), boot, nullptr, 0); + const int testCmdIndex = 1105; + int ret = AddCommand(trigger, testCmdIndex, value); + EXPECT_EQ(ret, 0); + TRIGGER_SET_FLAG(trigger, TRIGGER_FLAGS_SUBTRIGGER); + + char buffer[triggerBuffer]; + ret = sprintf_s(buffer, sizeof(buffer), "boot2 && %s=%s", param, value); + EXPECT_GE(ret, 0); + trigger = AddTrigger(GetTriggerHeader(TRIGGER_UNKNOW), triggerName, buffer, 0); + const int testCmdIndex2 = 105; + ret = AddCommand(trigger, testCmdIndex2, value); + + // 修改命令为测试执行 + GetTriggerWorkSpace()->cmdExec = TestCmdExec; + // 设置属性值 + SystemWriteParam(param, value); + + // 触发boot + TestBootEvent(boot); + + LibuvEventTask *task = (LibuvEventTask *)(GetTriggerWorkSpace()->eventHandle); + // 触发队列执行 + task->process(EVENT_TRIGGER_PARAM, nullptr, 0); + // 连续执行两个trigger + EXPECT_EQ(g_execCmdId, (uint32_t)testCmdIndex2); + return 0; + } + + int TestDumpTrigger() + { + DumpTrigger(GetTriggerWorkSpace()); + return 0; + } +}; + +HWTEST_F(TriggerTest, TestLoadTrigger, TestSize.Level1) +{ + TriggerTest test; + test.TestLoadTrigger(); +} + +HWTEST_F(TriggerTest, TestBootEvent, TestSize.Level1) +{ + TriggerTest test; + test.TestBootEvent("pre-init"); + test.TestBootEvent("init"); + test.TestBootEvent("post-init"); + test.TestBootEvent("early-init"); +} + +HWTEST_F(TriggerTest, TestAddTriggerForBoot, TestSize.Level1) +{ + TriggerTest test; + test.TestAddTriggerForBoot(); +} + +HWTEST_F(TriggerTest, TestAddTriggerForParm, TestSize.Level1) +{ + TriggerTest test; + test.TestAddTriggerForParm(); +} + +HWTEST_F(TriggerTest, TestCheckParamTrigger1, TestSize.Level1) +{ + TriggerTest test; + test.TestCheckParamTrigger1(); +} + +HWTEST_F(TriggerTest, TestCheckParamTrigger2, TestSize.Level1) +{ + TriggerTest test; + test.TestCheckParamTrigger2(); +} + +HWTEST_F(TriggerTest, TestCheckParamTrigger3, TestSize.Level1) +{ + TriggerTest test; + test.TestCheckParamTrigger3(); +} + +HWTEST_F(TriggerTest, TestCheckParamTrigger4, TestSize.Level1) +{ + TriggerTest test; + test.TestCheckParamTrigger4(); +} + +HWTEST_F(TriggerTest, TestCheckParamTrigger5, TestSize.Level1) +{ + TriggerTest test; + test.TestCheckParamTrigger5(); +} + +HWTEST_F(TriggerTest, TestParamEvent, TestSize.Level1) +{ + TriggerTest test; + test.TestParamEvent(); +} + +HWTEST_F(TriggerTest, ComputerCondition, TestSize.Level1) +{ + TriggerTest test; + test.TestComputeCondition("aaa=111||aaa=222||aaa=333"); + test.TestComputeCondition("aaa=111||aaa=222&&aaa=333"); + test.TestComputeCondition("(aaa=111||aaa=222)&&aaa=333"); + test.TestComputeCondition("aaa=111||(aaa=222&&aaa=333)"); +} + +HWTEST_F(TriggerTest, TestExecuteParamTrigger1, TestSize.Level1) +{ + TriggerTest test; + test.TestExecuteParamTrigger1(); +} + +HWTEST_F(TriggerTest, TestExecuteParamTrigger2, TestSize.Level1) +{ + TriggerTest test; + test.TestExecuteParamTrigger2(); +} + +HWTEST_F(TriggerTest, TestExecuteParamTrigger3, TestSize.Level1) +{ + TriggerTest test; + test.TestExecuteParamTrigger3(); +} + +HWTEST_F(TriggerTest, TestExecuteParamTrigger4, TestSize.Level1) +{ + TriggerTest test; + test.TestExecuteParamTrigger4(); +} + +HWTEST_F(TriggerTest, TestExecuteParamTrigger5, TestSize.Level1) +{ + TriggerTest test; + test.TestExecuteParamTrigger5(); +} + +HWTEST_F(TriggerTest, TestRunClient, TestSize.Level1) +{ + TriggerTest test; + int ret = test.TestRunClient(); + EXPECT_EQ(ret, 0); +} \ No newline at end of file diff --git a/services/test/unittest/param/watcher_agent_unittest.cpp b/services/test/unittest/param/watcher_agent_unittest.cpp new file mode 100755 index 0000000..94eef6a --- /dev/null +++ b/services/test/unittest/param/watcher_agent_unittest.cpp @@ -0,0 +1,89 @@ +/* + * 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 "iwatcher.h" +#include "iwatcher_manager.h" +#include "param_utils.h" +#include "sys_param.h" +#include "watcher_manager_kits.h" + +using namespace testing::ext; +using namespace std; + +void TestParameterChange(const char *key, const char *value, void *context) +{ + printf("TestParameterChange key:%s %s", key, value); +} + +class WatcherAgentTest : public ::testing::Test { +public: + WatcherAgentTest() {} + virtual ~WatcherAgentTest() {} + + void SetUp() {} + void TearDown() {} + void TestBody() {} + + int TestAddWatcher() + { + int ret = SystemWatchParameter("test.permission.watcher.test1", TestParameterChange, nullptr); + EXPECT_EQ(ret, 0); + ret = SystemWatchParameter("test.permission.watcher.test1*", TestParameterChange, nullptr); + EXPECT_EQ(ret, 0); + // 非法 + ret = SystemWatchParameter("test.permission.watcher.tes^^^^t1*", TestParameterChange, nullptr); + EXPECT_NE(ret, 0); + // 被禁止 + ret = SystemWatchParameter("test.permission.read.test1*", TestParameterChange, nullptr); + EXPECT_NE(ret, 0); + return 0; + } + + int TestDelWatcher() + { + int ret = SystemWatchParameter("test.permission.watcher.test1", nullptr, nullptr); + EXPECT_EQ(ret, 0); + ret = SystemWatchParameter("test.permission.watcher.test1*", nullptr, nullptr); + EXPECT_EQ(ret, 0); + // 非法 + ret = SystemWatchParameter("test.permission.watcher.tes^^^^t1*", nullptr, nullptr); + EXPECT_NE(ret, 0); + // 被禁止 + ret = SystemWatchParameter("test.permission.read.test1*", nullptr, nullptr); + EXPECT_NE(ret, 0); + return 0; + } + + int TestRecvMessage() + { + return 0; + } +}; + +HWTEST_F(WatcherAgentTest, TestAddWatcher, TestSize.Level1) +{ + WatcherAgentTest test; + test.TestAddWatcher(); +} + +HWTEST_F(WatcherAgentTest, TestDelWatcher, TestSize.Level1) +{ + WatcherAgentTest test; + test.TestDelWatcher(); +} \ No newline at end of file diff --git a/services/test/unittest/param/watcher_proxy_unittest.cpp b/services/test/unittest/param/watcher_proxy_unittest.cpp new file mode 100755 index 0000000..521e74c --- /dev/null +++ b/services/test/unittest/param/watcher_proxy_unittest.cpp @@ -0,0 +1,151 @@ +/* + * 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 "init_unittest.h" +#include "iwatcher_manager.h" +#include "message_parcel.h" +#include "param_utils.h" +#include "parcel.h" +#include "securec.h" +#include "watcher.h" +#include "watcher_manager.h" +#include "watcher_utils.h" + +using namespace testing::ext; +using namespace std; +using namespace OHOS; +using namespace OHOS::init_param; + +class TestWatcher final : public Watcher { +public: + TestWatcher() {} + ~TestWatcher() = default; + + void OnParamerterChange(const std::string &name, const std::string &value) override + { + printf("TestWatcher::OnParamerterChange name %s %s \n", name.c_str(), value.c_str()); + } +}; + +using WatcherManagerPtr = WatcherManager *; +WatcherManagerPtr g_watcherManager{ nullptr }; + +class WatcherProxyTest : public ::testing::Test { +public: + WatcherProxyTest() {} + virtual ~WatcherProxyTest() {} + + void SetUp() {} + void TearDown() {} + void TestBody() {} + + int TestAddWatcher(const std::string &keyPrefix, uint32_t &watcherId) + { + WatcherManagerPtr watcherManager = GetWatcherManager(); + WATCHER_CHECK(watcherManager != nullptr, return -1, "Failed to create manager"); + MessageParcel data; + MessageParcel reply; + MessageOption option; + + data.WriteString(keyPrefix); + std::shared_ptr watcher = std::make_shared(); + bool ret = data.WriteRemoteObject(watcher->AsObject()); + WATCHER_CHECK(ret, return 0, "Can not get remote"); + watcherManager->OnRemoteRequest(IWatcherManager::ADD_WATCHER, data, reply, option); + watcherId = reply.ReadUint32(); + EXPECT_NE(watcherId, 0); + printf("TestAddWatcher %s watcherId %d %p \n", keyPrefix.c_str(), watcherId, watcherManager); + return 0; + } + + int TestDelWatcher(const std::string &keyPrefix, uint32_t &watcherId) + { + WatcherManagerPtr watcherManager = GetWatcherManager(); + WATCHER_CHECK(watcherManager != nullptr, return -1, "Failed to create manager"); + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteString(keyPrefix); + data.WriteUint32(watcherId); + watcherManager->OnRemoteRequest(IWatcherManager::DEL_WATCHER, data, reply, option); + EXPECT_EQ(reply.ReadInt32(), 0); + watcherManager->StopLoop(); + printf("TestDelWatcher %s watcherId %d %p \n", keyPrefix.c_str(), watcherId, watcherManager); + return 0; + } + + WatcherManagerPtr GetWatcherManager() + { + if (g_watcherManager == nullptr) { + g_watcherManager = new WatcherManager(0, true); + if (g_watcherManager == nullptr) { + return nullptr; + } + } + return g_watcherManager; + } +}; + +HWTEST_F(WatcherProxyTest, TestAddWatcher, TestSize.Level1) +{ + WatcherProxyTest test; + uint32_t watcherId = 0; + test.TestAddWatcher("test.permission.watcher.test1", watcherId); +} + +HWTEST_F(WatcherProxyTest, TestAddWatcher2, TestSize.Level1) +{ + WatcherProxyTest test; + uint32_t watcherId = 0; + test.TestAddWatcher("test.permission.watcher.test2", watcherId); + test.TestAddWatcher("test.permission.watcher.test2", watcherId); + test.TestAddWatcher("test.permission.watcher.test2", watcherId); +} + +HWTEST_F(WatcherProxyTest, TestAddWatcher3, TestSize.Level1) +{ + WatcherProxyTest test; + uint32_t watcherId = 0; + test.TestAddWatcher("test.permission.watcher.test3", watcherId); +} + +HWTEST_F(WatcherProxyTest, TestAddWatcher4, TestSize.Level1) +{ + WatcherProxyTest test; + uint32_t watcherId = 0; + SystemSetParameter("test.permission.watcher.test4", "1101"); + SystemSetParameter("test.permission.watcher.test4.test", "1102"); + test.TestAddWatcher("test.permission.watcher.test*", watcherId); +} + +HWTEST_F(WatcherProxyTest, TestAddWatcher5, TestSize.Level1) +{ + WatcherProxyTest test; + uint32_t watcherId = 0; + test.TestAddWatcher("test.permission.watcher.test5", watcherId); + SystemSetParameter("test.permission.watcher.test5", "1101"); +} + +HWTEST_F(WatcherProxyTest, TestDelWatcher, TestSize.Level1) +{ + WatcherProxyTest test; + uint32_t watcherId = 0; + test.TestAddWatcher("test.permission.watcher.testDel", watcherId); + test.TestDelWatcher("test.permission.watcher.testDel", watcherId); +} \ No newline at end of file diff --git a/services/test/unittest/test_data/proc/cmdline b/services/test/unittest/test_data/proc/cmdline new file mode 100755 index 0000000..c75edef --- /dev/null +++ b/services/test/unittest/test_data/proc/cmdline @@ -0,0 +1 @@ +mem=640M console=ttyAMA0,115200 mmz=anonymous,0,0xA8000000,384M clk_ignore_unused androidboot.selinux=permissive skip_initramfs rootdelay=10 init = /init root=uuid=aaaaa=/dev/mmcblk0p5 hardware=Hi3516DV300 rootfstype=ext4 ro dddddd=blkdevparts=mmcblk0:1M(boot),15M(kernel),20M(updater),1M(misc),3307M(system),256M(vendor),-(userdata) \ No newline at end of file diff --git a/services/test/unittest/test_data/system/etc/param/ohos.para b/services/test/unittest/test_data/system/etc/param/ohos.para new file mode 100755 index 0000000..b27c935 --- /dev/null +++ b/services/test/unittest/test_data/system/etc/param/ohos.para @@ -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. + +build_version = 2.0 + +# whether ohos is enabled. +hw_sc.build.os.enable=true + +# ohos API version number. +hw_sc.build.os.apiversion=6 + +# ohos system version. +hw_sc.build.os.version=2.2.0 + +# ohos device type please use hw_sc.build.os.devicetype + +# ohos release type +hw_sc.build.os.releasetype=Canary1 + +const.hardware=Hi3516DV300 +const.actionable_compatible_property.enabled=false +const.postinstall.fstab.prefix=/system +const.secure=1 +security.perf_harden=1 +const.allow.mock.location=0 +const.debuggable=1 +const.build.characteristics="default" +const.product.model="ohos" +const.product.name="OpenHarmony 2.0 Canary" +persist.sys.usb.config=hdc diff --git a/services/test/unittest/test_data/system/etc/param/ohos.para.dac b/services/test/unittest/test_data/system/etc/param/ohos.para.dac new file mode 100755 index 0000000..51473e9 --- /dev/null +++ b/services/test/unittest/test_data/system/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/test/unittest/test_data/system/etc/param/ohos.para.selinux b/services/test/unittest/test_data/system/etc/param/ohos.para.selinux new file mode 100755 index 0000000..0723720 --- /dev/null +++ b/services/test/unittest/test_data/system/etc/param/ohos.para.selinux @@ -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. + +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 \ No newline at end of file diff --git a/services/test/unittest/test_data/system/etc/param/persist_parameters b/services/test/unittest/test_data/system/etc/param/persist_parameters new file mode 100755 index 0000000..c047328 --- /dev/null +++ b/services/test/unittest/test_data/system/etc/param/persist_parameters @@ -0,0 +1,8 @@ +persist.sys.usb.config=hdc +persist.111.ffff.bbbb.cccc.dddd.eeee=1106 +persist.111.ffff.bbbb.cccc.dddd.eeee.55555=22202 +persist.111.aaaa.bbbb.cccc.dddd.eeee=1102 +persist.111.bbbb.cccc.dddd.eeee=1103 +persist.111.cccc.bbbb.cccc.dddd.eeee=1104 +persist.111.eeee.bbbb.cccc.dddd.eeee=1105 +persist.aaaa.aaa=3377 diff --git a/services/test/unittest/test_data/trigger_test.cfg b/services/test/unittest/test_data/trigger_test.cfg new file mode 100755 index 0000000..5c6dec2 --- /dev/null +++ b/services/test/unittest/test_data/trigger_test.cfg @@ -0,0 +1,50 @@ +{ + + "jobs" : [{ + "name" : "early-init", + "cmds" : [ + "write /proc/sys/kernel/sysrq 0", + "restorecon /adb_keys", + "restorecon /postinstall", + "mkdir /acct/uid", + "chown root system /dev/memcg/memory.pressure_level", + "chmod 0040 /dev/memcg/memory.pressure_level", + "mkdir /dev/memcg/apps/ 0755 system system", + "mkdir /dev/memcg/system 0550 system system", + "start ueventd", + "exec_start apexd-bootstrap", + "setparam sys.usb.config ${persist.sys.usb.config}" + ] + }, + { + "name" : "param:trigger_test_1", + "condition" : "test.sys.boot_from_charger_mode=5", + "cmds" : [ + "class_stop charger", + "trigger late-init" + ] + }, + { + "name" : "param:trigger_test_2", + "condition" : "test.sys.boot_from_charger_mode=1 || test.sys.boot_from_charger_mode=2 || test.sys.boot_from_charger_mode=3", + "cmds" : [ + "class_stop charger", + "trigger late-init" + ] + }, + { + "name" : "load_persist_params_action", + "cmds" : [ + "load_persist_params", + "start logd", + "start logd-reinit" + ] + }, + { + "name" : "firmware_mounts_complete", + "cmds" : [ + "rm /dev/.booting" + ] + } + ] +} diff --git a/services/test/unittest/tools/prepare_testdata.sh b/services/test/unittest/tools/prepare_testdata.sh new file mode 100755 index 0000000..35be3a6 --- /dev/null +++ b/services/test/unittest/tools/prepare_testdata.sh @@ -0,0 +1,146 @@ +#! /bin/bash +# 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. + +# This Script used to push test data to devices +# Usage: +# ./prepare_testdata.sh path +# path is the rootdir of ohos projects. + +if [ $# -lt 1 ];then + echo "Usage $0 " + exit 1 +fi + +function hdc_shell_cmd() { + # do nothing if there are not any arguments + if [ $# -eq 0 ];then + return; + fi + echo "Running command $@" + hdc shell $@ +} + +function hdc_push_cmd() { + # do nothing if there are not any arguments + if [ $# -ne 2 ];then + return; + fi + echo "Pushing resouces to device" + hdc file send $@ +} + +hdc target mount + +ut_target_path="/data/init_ut" +echo "Remove ${ut_target_path}" +hdc_shell_cmd "rm -rf ${ut_target_path}" +hdc_shell_cmd "rm /bin/init_ut" + +echo "Create ${ut_target_path}" +hdc_shell_cmd "umask 022" +hdc_shell_cmd "mkdir -p ${ut_target_path}" +hdc_shell_cmd "mkdir -p ${ut_target_path}/proc" + +ohos_root="$1" +ohos_root=${ohos_root%%/} +ohos_init="${ohos_root}/base/startup/init_lite" +ohos_init_ut="${ohos_init}/services/test/unittest" + +hdc_shell_cmd "mkdir -p ${ut_target_path}/coverage" +sleep 0.25 + +# copy file to test +hdc_shell_cmd "mkdir -p ${ut_target_path}/system" +hdc_shell_cmd "mkdir -p ${ut_target_path}/system/etc" +hdc_shell_cmd "mkdir -p ${ut_target_path}/system/etc/param" +hdc_shell_cmd "mkdir -p ${ut_target_path}/system/etc/param/ohos_const" +hdc_shell_cmd "mkdir -p ${ut_target_path}/vendor" +hdc_shell_cmd "mkdir -p ${ut_target_path}/vendor/etc" +hdc_shell_cmd "mkdir -p ${ut_target_path}/vendor/etc/param" + +hdc_shell_cmd "cp ${ohos_root}/base/startup/init_lite/services/test/unittest/test_data/system/etc/param/ohos_const/* ${ut_target_path}/system/etc/param/ohos_const/" +hdc_push_cmd ${ohos_root}/base/startup/init_lite/services/test/unittest/test_data/system/etc/param/ohos.para ${ut_target_path}/system/etc/param/ohos.para +hdc_push_cmd ${ohos_root}/base/startup/init_lite/services/test/unittest/test_data/system/etc/param/ohos.para.dac ${ut_target_path}/system/etc/param/ohos.para.dac +hdc_push_cmd ${ohos_root}/base/startup/init_lite/services/test/unittest/test_data/system/etc/param/ohos.para.selinux ${ut_target_path}/system/etc/param/ohos.para.selinux + +hdc_push_cmd ${ohos_root}/base/startup/init_lite/services/test/unittest/test_data/trigger_test.cfg /data/init_ut/trigger_test.cfg +hdc_push_cmd ${ohos_root}/base/startup/init_lite/services/test/unittest/test_data/proc/cmdline /data/init_ut/proc/cmdline + +sleep 0.25 +hdc file send ${ohos_root}/out/ohos-arm-release/exe.unstripped/tests/unittest/startup/init/init_ut /data/init_ut/init_ut +sleep 0.25 +hdc_shell_cmd "cp /data/init_ut/init_ut /bin/init_ut" + +hdc_shell_cmd "chmod 777 /data/init_ut/* -R" +hdc_shell_cmd "chmod 777 /bin/init_ut" + +hdc_shell_cmd "export GCOV_PREFIX=${ut_target_path}/coverage&&export GCOV_PREFIX_STRIP=14&&init_ut" + +if [ $? -ne 0 ]; then + echo "Execute init_ut in device failed. please check the log" +fi +echo "Running init unittests end..." +echo "Ready to generate coverage..." +pushd ${ohos_init} +rm -rf ./g.sh +rm -rf *.gcno +rm -rf *.gcda +echo "Copy .gcta files to ${ohos_init}}" + +for file in $(hdc_shell_cmd ls /data/init_ut/coverage/*.gcda); do + hdc file recv ${file} ${ohos_init}/${file:23} + chmod 777 ${ohos_init}/${file:23} +done + + +echo "Find out all gcno files and copy to ${ohos_init}" +find ${ohos_root}/out/ohos-arm-release/obj/ -name "*.gcno" -type f -exec cp {} . \; +if [ $? -ne 0 ]; then + echo "find gcno failed." + popd 2>&1 > /dev/null + exit 1 +fi + +if [ ! -f ${ohos_init}/g.sh ]; then + echo "create g.sh" + touch ${ohos_init}/g.sh + echo "${ohos_root}/prebuilts/clang/ohos/linux-x86_64/llvm/bin/llvm-cov gcov \$@" > ${ohos_init}/g.sh + chmod 755 ${ohos_init}/g.sh +fi + +echo "Running command lcov" +lcov -d . -o "${ohos_init}/init_ut_tmp.info" -b . -c --gcov-tool ${ohos_init}/g.sh + +if [ $? -ne 0 ]; then + echo "Run command lcov failed" + popd 2>&1 > /dev/null +fi + +echo "Filter out don\'t cared dir" +lcov --remove init_ut_tmp.info "*third_party*" "*prebuilts*" "*test/unittest/*" -o ${ohos_init}/init_ut.info + +genhtml -o ${HOME}/init_coverage init_ut.info +if [ $? -ne 0 ]; then + echo "Run genhtml failed." + popd 2>&1 > /dev/null + exit 1 +fi +echo "Clear tmp files" +rm -rf ./g.sh *.gcno *.gcda init_ut.info init_ut_tmp.info +hdc_shell_cmd "rm -rf ${ut_target_path}" +echo +echo "Generate init ut coverage done." +echo "Check coverage in ${HOME}/init_coverage." +echo +popd 2>&1 > /dev/null diff --git a/services/utils/BUILD.gn b/services/utils/BUILD.gn index fb163f4..b1d70f9 100755 --- a/services/utils/BUILD.gn +++ b/services/utils/BUILD.gn @@ -19,7 +19,7 @@ ohos_static_library("libinit_utils") { include_dirs = [ "//third_party/bounds_checking_function/include", "//base/startup/init_lite/services/log", - "//base/startup/init_lite/services/utils", + "//base/startup/init_lite/services/include", ] deps = [ diff --git a/services/utils/init_utils.c b/services/utils/init_utils.c index 820bb71..506572e 100755 --- a/services/utils/init_utils.c +++ b/services/utils/init_utils.c @@ -16,19 +16,21 @@ #include #include +#include #include #include #include +#include #include #include #include #include #include #include + #include "init_log.h" #include "securec.h" -#define WAIT_MAX_COUNT 10 #define MAX_BUF_SIZE 1024 #ifdef STARTUP_UT #define LOG_FILE_NAME "/media/sf_ubuntu/test/log.txt" @@ -37,6 +39,11 @@ #endif #define MAX_JSON_FILE_LEN 102400 // max init.cfg size 100KB +#define CONVERT_MICROSEC_TO_SEC(x) ((x) / 1000 / 1000.0) +#ifndef DT_DIR +#define DT_DIR 4 +#endif + #define THOUSAND_UNIT_INT 1000 #define THOUSAND_UNIT_FLOAT 1000.0 @@ -108,19 +115,19 @@ char *ReadFileToBuf(const char *configFile) } while (0); if (fd != NULL) { - fclose(fd); + (void)fclose(fd); fd = NULL; } return buffer; } -int SplitString(char *srcPtr, char **dstPtr, int maxNum) +int SplitString(char *srcPtr, const char *del, char **dstPtr, int maxNum) { - if (srcPtr == NULL || dstPtr == NULL) { + if (srcPtr == NULL || dstPtr == NULL || del == NULL) { return -1; } char *buf = NULL; - dstPtr[0] = strtok_r(srcPtr, " ", &buf); + dstPtr[0] = strtok_r(srcPtr, del, &buf); int counter = 0; while (dstPtr[counter] != NULL && (counter < maxNum)) { counter++; @@ -130,6 +137,71 @@ int SplitString(char *srcPtr, char **dstPtr, int maxNum) return counter; } +void FreeStringVector(char **vector, int count) +{ + if (vector != NULL) { + for (int i = 0; i < count; i++) { + if (vector[i] != NULL) { + free(vector[i]); + } + } + free(vector); + vector = NULL; + } +} + +char **SplitStringExt(char *buffer, const char *del, int *returnCount, int maxItemCount) +{ + INIT_CHECK_RETURN_VALUE((maxItemCount >= 0) && (buffer != NULL) && (del != NULL) && (returnCount != NULL), NULL); + // Why is this number? + // Now we use this function to split a string with a given delimeter + // We do not know how many sub-strings out there after splitting. + // 50 is just a guess value. + const int defaultItemCounts = 50; + int itemCounts = maxItemCount; + + if (maxItemCount > defaultItemCounts) { + itemCounts = defaultItemCounts; + } + char **items = (char **)malloc(sizeof(char*) * itemCounts); + if (items == NULL) { + INIT_LOGE("No enough memory to store items"); + return NULL; + } + char *rest = NULL; + char *p = strtok_r(buffer, del, &rest); + int count = 0; + while (p != NULL) { + if (count > itemCounts - 1) { + itemCounts += (itemCounts / 2) + 1; + INIT_LOGD("Too many items,expand size"); + char **expand = (char **)(realloc(items, sizeof(char *) * itemCounts)); + if (expand == NULL) { + INIT_LOGE("Failed to expand memory for uevent config parser"); + FreeStringVector(items, count); + return NULL; + } + items = expand; + } + size_t len = strlen(p); + items[count] = (char *)malloc(len + 1); + if (items[count] == NULL) { + FreeStringVector(items, count); + return NULL; + } + if (strncpy_s(items[count], len + 1, p, len) != EOK) { + INIT_LOGE("Copy string failed"); + FreeStringVector(items, count); + return NULL; + } + items[count][len] = '\0'; + count++; + p = strtok_r(NULL, del, &rest); + } + *returnCount = count; + return items; +} + void WaitForFile(const char *source, unsigned int maxCount) { unsigned int maxCountTmp = maxCount; @@ -137,7 +209,7 @@ void WaitForFile(const char *source, unsigned int maxCount) INIT_LOGE("WaitForFile max time is 5s"); maxCountTmp = WAIT_MAX_COUNT; } - struct stat sourceInfo; + struct stat sourceInfo = {}; const unsigned int waitTime = 500000; unsigned int count = 0; do { @@ -159,7 +231,7 @@ size_t WriteAll(int fd, const char *buffer, size_t size) const char *p = buffer; size_t left = size; - ssize_t written; + ssize_t written = -1; while (left > 0) { do { @@ -175,18 +247,19 @@ size_t WriteAll(int fd, const char *buffer, size_t size) return size - left; } -char *Realpath(const char *source, char *resolvedPath, size_t resolvedPathSize) +char *GetRealPath(const char *source) { - if ((source == NULL) || (resolvedPath == NULL) || (resolvedPathSize != PATH_MAX)) { + if (source == NULL) { return NULL; } - if (realpath(source, resolvedPath) == NULL) { + char *path = realpath(source, NULL); + if (path == NULL) { if (errno != ENOENT) { - INIT_LOGE("Fail resolve %s real path err=%d", source, errno); + INIT_LOGE("Failed to resolve %s real path err=%d", source, errno); return NULL; } } - return resolvedPath; + return path; } int MakeDir(const char *dir, mode_t mode) @@ -245,6 +318,58 @@ int StringToInt(const char *str, int defaultValue) } errno = 0; int value = (int)strtoul(str, NULL, DECIMAL_BASE); - return ((errno != 0) ? defaultValue : value); + return errno != 0 ? defaultValue : value; } +int ReadFileInDir(const char *dirPath, const char *includeExt, + int (*processFile)(const char *fileName, void *context), void *context) +{ + if (dirPath == NULL || processFile == NULL) { + return -1; + } + DIR *pDir = opendir(dirPath); + INIT_ERROR_CHECK(pDir != NULL, return -1, "Read dir :%s failed.%d", dirPath, errno); + char *fileName = malloc(MAX_BUF_SIZE); + INIT_ERROR_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; + } + INIT_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, MAX_BUF_SIZE, MAX_BUF_SIZE - 1, "%s/%s", dirPath, dp->d_name); + if (ret <= 0) { + INIT_LOGE("Failed to get file name for %s", dp->d_name); + continue; + } + struct stat st; + if (stat(fileName, &st) == 0) { + processFile(fileName, context); + } + } + free(fileName); + closedir(pDir); + return 0; +} + +// Check if in updater mode. +int InUpdaterMode(void) +{ + const char * const updaterExecutabeFile = "/bin/updater"; + if (access(updaterExecutabeFile, X_OK) == 0) { + return 1; + } else { + return 0; + } +} diff --git a/services/src/list.c b/services/utils/list.c similarity index 100% rename from services/src/list.c rename to services/utils/list.c diff --git a/ueventd/BUILD.gn b/ueventd/BUILD.gn index fab83e9..fcc47eb 100755 --- a/ueventd/BUILD.gn +++ b/ueventd/BUILD.gn @@ -16,7 +16,7 @@ if (!defined(ohos_lite)) { ohos_executable("ueventd") { sources = [ - "//base/startup/init_lite/services/src/list.c", + "//base/startup/init_lite/services/utils/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", diff --git a/ueventd/ueventd.c b/ueventd/ueventd.c index a8b8d4a..26e2cce 100755 --- a/ueventd/ueventd.c +++ b/ueventd/ueventd.c @@ -14,7 +14,6 @@ */ #include "ueventd.h" - #include #include #include @@ -206,7 +205,7 @@ static void DoTrigger(const char *ueventPath, int sockFd) if (fd < 0) { INIT_LOGE("Open \" %s \" failed, err = %d", ueventPath, errno); } else { - ssize_t n = write(fd, "add\n", strlen("add\n")); + ssize_t n = write(fd, "add\n", 4); if (n < 0) { INIT_LOGE("Write \" %s \" failed, err = %d", ueventPath, errno); close(fd); @@ -223,33 +222,31 @@ static void DoTrigger(const char *ueventPath, int sockFd) static void Trigger(const char *path, int sockFd) { DIR *dir = opendir(path); - if (dir == NULL) { - return; + if (dir != NULL) { + struct dirent *dirent = NULL; + while ((dirent = readdir(dir)) != NULL) { + if (dirent->d_name[0] == '.') { + continue; + } + if (dirent->d_type == DT_DIR) { + char pathBuffer[PATH_MAX]; + if (snprintf_s(pathBuffer, PATH_MAX, PATH_MAX - 1, "%s/%s", path, dirent->d_name) == -1) { + continue; + } + Trigger(pathBuffer, sockFd); + } else { + if (!strcmp(dirent->d_name, "uevent")) { + char ueventBuffer[PATH_MAX]; + if (snprintf_s(ueventBuffer, PATH_MAX, PATH_MAX - 1, "%s/%s", path, "uevent") == -1) { + INIT_LOGW("Cannnot build uevent path under %s", path); + continue; + } + DoTrigger(ueventBuffer, sockFd); + } + } + } + closedir(dir); } - struct dirent *dirent = NULL; - while ((dirent = readdir(dir)) != NULL) { - if (dirent->d_name[0] == '.') { - continue; - } - if (dirent->d_type == DT_DIR) { - char pathBuffer[PATH_MAX]; - if (snprintf_s(pathBuffer, PATH_MAX, PATH_MAX - 1, "%s/%s", path, dirent->d_name) == -1) { - continue; - } - Trigger(pathBuffer, sockFd); - } else { - if (strcmp(dirent->d_name, "uevent") != 0) { - continue; - } - char ueventBuffer[PATH_MAX]; - if (snprintf_s(ueventBuffer, PATH_MAX, PATH_MAX - 1, "%s/%s", path, "uevent") == -1) { - INIT_LOGW("Cannnot build uevent path under %s", path); - continue; - } - DoTrigger(ueventBuffer, sockFd); - } - } - closedir(dir); } static void RetriggerUevent(int sockFd) @@ -266,6 +263,7 @@ int main(int argc, char **argv) { char *ueventdConfigs[] = {"/etc/ueventd.config", NULL}; int i = 0; + int ret = -1; while (ueventdConfigs[i] != NULL) { ParseUeventdConfigFile(ueventdConfigs[i++]); } @@ -282,7 +280,7 @@ int main(int argc, char **argv) while (1) { pfd.revents = 0; - int ret = poll(&pfd, 1, -1); + ret = poll(&pfd, 1, -1); if (ret <= 0) { continue; } diff --git a/ueventd/ueventd_device_handler.c b/ueventd/ueventd_device_handler.c index 0a03e3e..449c2eb 100755 --- a/ueventd/ueventd_device_handler.c +++ b/ueventd/ueventd_device_handler.c @@ -79,11 +79,8 @@ static inline void AdjustDeviceNodePermissions(const char *deviceNode, uid_t uid static int CreateDeviceNode(const struct Uevent *uevent, const char *deviceNode, char **symLinks, bool isBlock) { int rc = -1; - if (uevent->major < 0 || uevent->minor < 0) { - return rc; - } - size_t major = uevent->major; - size_t minor = uevent->minor; + int major = uevent->major; + int minor = uevent->minor; uid_t uid = uevent->ug.uid; gid_t gid = uevent->ug.gid; mode_t mode = DEVMODE; @@ -164,19 +161,23 @@ static char *FindPlatformDeviceName(char *path) path += strlen("/sys/devices/platform/"); return path; } + + // Some platform devices may not be registered under platform device. + if (STARTSWITH(path, "/sys/devices/")) { + path += strlen("/sys/devices/"); + return path; + } return NULL; } static void BuildDeviceSymbolLinks(char **links, int linkNum, const char *parent, const char *partitionName, const char *deviceName) { - if ((linkNum > BLOCKDEVICE_LINKS - 1) || (linkNum < 0)) { - INIT_LOGW("Failed set linkNum, links ignore"); - return; - } - if (parent == NULL) { + if (linkNum > BLOCKDEVICE_LINKS - 1) { + INIT_LOGW("Too many links, ignore"); return; } + links[linkNum] = calloc(sizeof(char), DEVICE_FILE_SIZE); if (links[linkNum] == NULL) { INIT_LOGE("Failed to allocate memory for link, err = %d", errno); @@ -191,9 +192,8 @@ static void BuildDeviceSymbolLinks(char **links, int linkNum, const char *parent INIT_LOGE("Failed to build link"); } } else if (!INVALIDSTRING(deviceName)) { - // If a device does not have a partition name, create a symbol link for it separately. if (snprintf_s(links[linkNum], DEVICE_FILE_SIZE, DEVICE_FILE_SIZE - 1, - "/dev/block/platform/%s/%s", parent, deviceName) == -1) { + "/dev/block/platform/%s/by-name/%s", parent, deviceName) == -1) { INIT_LOGE("Failed to build link"); } } @@ -201,8 +201,7 @@ static void BuildDeviceSymbolLinks(char **links, int linkNum, const char *parent static char **GetBlockDeviceSymbolLinks(const struct Uevent *uevent) { - if (uevent == NULL || uevent->syspath == NULL || uevent->subsystem == NULL || - STRINGEQUAL(uevent->subsystem, "block") == 0) { + if (uevent == NULL || uevent->subsystem == NULL || STRINGEQUAL(uevent->subsystem, "block") == 0) { INIT_LOGW("Invalid arguments, Skip to get device symbol links."); return NULL; } @@ -230,14 +229,14 @@ static char **GetBlockDeviceSymbolLinks(const struct Uevent *uevent) // Reverse walk through sysPath, and check subystem file under each directory. char *parent = dirname(sysPath); while (parent != NULL && !STRINGEQUAL(parent, "/") && !STRINGEQUAL(parent, ".")) { - char subsystem[SYSPATH_SIZE] = {0}; + char subsystem[SYSPATH_SIZE]; if (snprintf_s(subsystem, SYSPATH_SIZE, SYSPATH_SIZE - 1, "%s/subsystem", parent) == -1) { INIT_LOGE("Failed to build subsystem path for device \" %s \"", uevent->syspath); return NULL; } - char bus[PATH_MAX] = {0}; - if (Realpath(subsystem, bus, sizeof(bus)) == NULL) { + char *bus = GetRealPath(subsystem); + if (bus == NULL) { parent = dirname(parent); continue; } @@ -249,6 +248,7 @@ static char **GetBlockDeviceSymbolLinks(const struct Uevent *uevent) } linkNum++; } + free(bus); parent = dirname(parent); } @@ -304,7 +304,7 @@ static const char *GetDeviceName(char *sysPath, const char *deviceName) } if (deviceName != NULL && deviceName[0] != '\0') { // if device name reported by kernel includes '/', skip it. - // use entire device name reported by kernel + // TODO: use entire device name reported by kernel devName = basename((char *)deviceName); char *p = strrchr(deviceName, '/'); if (p != NULL) { // device name includes slash diff --git a/ueventd/ueventd_firmware_handler.c b/ueventd/ueventd_firmware_handler.c index f368f8a..16b4fff 100755 --- a/ueventd/ueventd_firmware_handler.c +++ b/ueventd/ueventd_firmware_handler.c @@ -13,12 +13,17 @@ * limitations under the License. */ +#include +#include +#include + +#include "ueventd_firmware_handler.h" #include "ueventd.h" #define INIT_LOG_TAG "ueventd" #include "init_log.h" void HandleFimwareDeviceEvent(const struct Uevent *uevent) { - // Implement it later. + // TODO, implement it later. INIT_LOGI("Firmware handler not implemented yet."); } diff --git a/ueventd/ueventd_read_cfg.c b/ueventd/ueventd_read_cfg.c index 9694dfc..599c846 100755 --- a/ueventd/ueventd_read_cfg.c +++ b/ueventd/ueventd_read_cfg.c @@ -16,21 +16,22 @@ #include "ueventd_read_cfg.h" #include -#include -#include #include #include -#include +#include #include +#include +#include +#include #include "init_utils.h" #include "list.h" -#include "securec.h" #include "ueventd_utils.h" +#include "securec.h" #define INIT_LOG_TAG "ueventd" #include "init_log.h" // default item count in config files -#define DEFAULTITEMCOUNT (100) +#define DEFAULTITEMCOUNT (50) #define SYS_CONFIG_PATH_NUM 0 #define SYS_CONFIG_ATTR_NUM 1 @@ -71,69 +72,6 @@ struct ListNode g_firmwares = { .prev = &g_firmwares, }; -static void FreeConfigItems(char **items, int count) -{ - if (items != NULL) { - for (int i = 0; i < count; i++) { - if (items[i] != NULL) { - free(items[i]); - } - } - free(items); - items = NULL; - } -} - -static char **SplitUeventConfig(char *buffer, const char *del, int *returnCount, int maxItemCount) -{ - char *rest = NULL; - int count = 0; - const int average = 2; - char *p = strtok_r(buffer, del, &rest); - int maxItemCountTmp = maxItemCount; - if (maxItemCountTmp < 0) { - return NULL; - } - if (maxItemCountTmp > DEFAULTITEMCOUNT) { - maxItemCountTmp = DEFAULTITEMCOUNT; - } - 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 > (maxItemCountTmp - 1)) { - maxItemCountTmp += (maxItemCountTmp / average) + 1; - INIT_LOGD("Too many items,expand size"); - char **expand = (char **)(realloc(items, sizeof(char *) * maxItemCountTmp)); - if (expand == NULL) { - INIT_LOGE("Failed to expand memory for uevent config parser"); - FreeConfigItems(items, count); - return NULL; - } - items = expand; - } - size_t len = strlen(p); - items[count] = (char *)malloc(len + 1); - if (items[count] == NULL) { - FreeConfigItems(items, count); - return NULL; - } - if (strncpy_s(items[count], len + 1, p, len) != EOK) { - INIT_LOGE("Copy string failed"); - FreeConfigItems(items, count); - return NULL; - } - items[count][strlen(p)] = '\0'; - count++; - p = strtok_r(NULL, del, &rest); - } - items[count] = NULL; - *returnCount = count; - return items; -} - static int ParseDeviceConfig(char *p) { INIT_LOGD("Parse device config info: %s", p); @@ -145,17 +83,17 @@ static int ParseDeviceConfig(char *p) if (INVALIDSTRING(p)) { INIT_LOGE("Invalid argument"); } - items = SplitUeventConfig(p, " ", &count, expectedCount); + items = SplitStringExt(p, " ", &count, expectedCount); if (count != expectedCount) { INIT_LOGE("Ignore invalid item: %s", p); - FreeConfigItems(items, count); + FreeStringVector(items, count); return 0; } struct DeviceUdevConf *config = calloc(1, sizeof(struct DeviceUdevConf)); if (config == NULL) { errno = ENOMEM; - FreeConfigItems(items, count); + FreeStringVector(items, count); return -1; } config->name = strdup(items[DEVICE_CONFIG_NAME_NUM]); // device node @@ -168,7 +106,7 @@ static int ParseDeviceConfig(char *p) 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); + FreeStringVector(items, count); return 0; } @@ -183,16 +121,16 @@ static int ParseSysfsConfig(char *p) if (INVALIDSTRING(p)) { INIT_LOGE("Invalid argument"); } - items = SplitUeventConfig(p, " ", &count, expectedCount); + items = SplitStringExt(p, " ", &count, expectedCount); if (count != expectedCount) { INIT_LOGE("Ignore invalid item: %s", p); - FreeConfigItems(items, count); + FreeStringVector(items, count); return 0; } struct SysUdevConf *config = calloc(1, sizeof(struct SysUdevConf)); if (config == NULL) { errno = ENOMEM; - FreeConfigItems(items, count); + FreeStringVector(items, count); return -1; } config->sysPath = strdup(items[SYS_CONFIG_PATH_NUM]); // sys path @@ -206,7 +144,7 @@ static int ParseSysfsConfig(char *p) 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); - FreeConfigItems(items, count); + FreeStringVector(items, count); return 0; } @@ -291,7 +229,7 @@ int ParseUeventConfig(char *buffer) callback = funcMapper[type].func; return 0; } - return ((callback != NULL) ? callback(p) : -1); + return callback != NULL ? callback(p) : -1; } static void DoUeventConfigParse(char *buffer, size_t length) @@ -303,7 +241,7 @@ static void DoUeventConfigParse(char *buffer, size_t length) int count = -1; const int maxItemCount = DEFAULTITEMCOUNT; - items = SplitUeventConfig(buffer, "\n", &count, maxItemCount); + items = SplitStringExt(buffer, "\n", &count, maxItemCount); INIT_LOGD("Dump items count = %d", count); for (int i = 0; i < count; i++) { char *p = items[i]; @@ -322,7 +260,7 @@ static void DoUeventConfigParse(char *buffer, size_t length) } } // release memory - FreeConfigItems(items, count); + FreeStringVector(items, count); } void ParseUeventdConfigFile(const char *file) @@ -330,11 +268,12 @@ void ParseUeventdConfigFile(const char *file) if (INVALIDSTRING(file)) { return; } - char config[PATH_MAX] = {0}; - if (Realpath(file, config, sizeof(config)) == NULL) { + char *config = GetRealPath(file); + 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; @@ -384,13 +323,11 @@ void GetDeviceNodePermissions(const char *devNode, uid_t *uid, gid_t *gid, mode_ if (!ListEmpty(g_devices)) { ForEachListEntry(&g_devices, node) { struct DeviceUdevConf *config = ListEntry(node, struct DeviceUdevConf, list); - if (config != NULL) { - if (STRINGEQUAL(config->name, devNode)) { - *uid = config->uid; - *gid = config->gid; - *mode = config->mode; - break; - } + if (STRINGEQUAL(config->name, devNode)) { + *uid = config->uid; + *gid = config->gid; + *mode = config->mode; + break; } } } @@ -419,12 +356,10 @@ void ChangeSysAttributePermissions(const char *sysPath) if (matched == 0) { return; } - char sysAttr[SYSPATH_SIZE] = {0}; - if (config->sysPath != NULL && config->attr != NULL) { - if (snprintf_s(sysAttr, SYSPATH_SIZE, SYSPATH_SIZE - 1, "/sys%s/%s", config->sysPath, config->attr) == -1) { - INIT_LOGE("Failed to build sys attribute for sys path %s, attr: %s", config->sysPath, config->attr); - return; - } + char sysAttr[SYSPATH_SIZE] = {}; + if (snprintf_s(sysAttr, SYSPATH_SIZE, SYSPATH_SIZE - 1, "/sys%s/%s", config->sysPath, config->attr) == -1) { + INIT_LOGE("Failed to build sys attribute for sys path %s, attr: %s", config->sysPath, config->attr); + return; } if (chown(sysAttr, config->uid, config->gid) < 0) { INIT_LOGE("chown for file %s failed, err = %d", sysAttr, errno); diff --git a/ueventd/ueventd_socket.c b/ueventd/ueventd_socket.c index 3f947b8..c34c439 100755 --- a/ueventd/ueventd_socket.c +++ b/ueventd/ueventd_socket.c @@ -66,7 +66,7 @@ int UeventdSocketInit(void) ssize_t ReadUeventMessage(int sockFd, char *buffer, size_t length) { ssize_t n = -1; - struct msghdr msghdr = {0}; + struct msghdr msghdr; struct iovec iov; struct sockaddr_nl addr; char credMsg[CMSG_SPACE(sizeof(struct ucred))]; diff --git a/watchdog/BUILD.gn b/watchdog/BUILD.gn new file mode 100755 index 0000000..d9109e7 --- /dev/null +++ b/watchdog/BUILD.gn @@ -0,0 +1,27 @@ +# 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. + +group("watchdog") { + if (defined(ohos_lite)) { + if (ohos_kernel_type == "linux") { + deps = [ + "//base/startup/init_lite/watchdog/linux:linux_watchdog", + ] + } + } else { + deps = [ + "//base/startup/init_lite/watchdog/linux:linux_watchdog", + ] + } +} + diff --git a/watchdog/linux/BUILD.gn b/watchdog/linux/BUILD.gn new file mode 100755 index 0000000..bc21e69 --- /dev/null +++ b/watchdog/linux/BUILD.gn @@ -0,0 +1,50 @@ +# 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. + +group("linux_watchdog") { + deps = [ + ":watchdog_service" + ] + +} + +if (defined(ohos_lite)) { + executable("watchdog_service") { + sources = [ + "init_linux_watchdog.c", + ] + include_dirs = [ + "//base/startup/init_lite/services/log", + ] + deps = [ + "//base/startup/init_lite/services/log:init_log", + ] + } +} else { + import("//build/ohos.gni") + ohos_executable("watchdog_service") { + sources = [ + "init_linux_watchdog.c", + ] + include_dirs = [ + "//base/startup/init_lite/services/log", + ] + deps = [ + "//base/startup/init_lite/services/log:init_log", + ] + install_enable = true + part_name = "init" + } +} + + diff --git a/watchdog/linux/init_linux_watchdog.c b/watchdog/linux/init_linux_watchdog.c new file mode 100755 index 0000000..b039e28 --- /dev/null +++ b/watchdog/linux/init_linux_watchdog.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "init_log.h" + +#define WAIT_MAX_COUNT 10 +#define DEFAULT_INTERVAL 3 +#define DEFAULT_GAP 3 + +static void WaitAtStartup(const char *source) +{ + unsigned int count = 0; + struct stat sourceInfo; + const unsigned int waitTime = 500000; + do { + usleep(waitTime); + count++; + } while ((stat(source, &sourceInfo) < 0) && (errno == ENOENT) && (count < WAIT_MAX_COUNT)); + if (count == WAIT_MAX_COUNT) { + INIT_LOGE("wait for file:%s failed after %f.", source, WAIT_MAX_COUNT>>1); + } + return; +} + +int main(int argc, const char *argv[]) +{ + WaitAtStartup("/dev/watchdog"); + int fd = open("/dev/watchdog", O_RDWR); + if (fd == -1) { + INIT_LOGE("Can't open /dev/watchdog."); + return 1; + } + + int interval = 0; + if (argc >= 2) { // Argument nums greater than or equal to 2. + interval = atoi(argv[1]); + } + interval = interval > 0 ? interval : DEFAULT_INTERVAL; + + int gap = 0; + if (argc >= 3) { // Argument nums greater than or equal to 3. + gap = atoi(argv[2]); // Second parameter. + } + gap = gap > 0 ? gap : DEFAULT_GAP; + + INIT_LOGI("watchdoge started (interval %d, margin %d), fd = %d\n", interval, gap, fd); + + int timeoutSet = interval + gap; + int timeoutGet = 0; + int ret = ioctl(fd, WDIOC_SETTIMEOUT, &timeoutSet); + if (ret) { + INIT_LOGE("Failed to set timeout to %d\n", timeoutSet); + } + ret = ioctl(fd, WDIOC_GETTIMEOUT, &timeoutGet); + if (ret) { + INIT_LOGE("Failed to get timeout\n"); + } else { + interval = timeoutGet > gap ? timeoutGet - gap : 1; + } + while (1) { + ioctl(fd, WDIOC_KEEPALIVE); + sleep(interval); + } + close(fd); + fd = -1; + return -1; +}