init: add service file func

Signed-off-by: xionglei6 <xionglei6@huawei.com>
This commit is contained in:
xionglei6 2021-10-27 10:14:23 +08:00
parent 00280336ba
commit 99705c0896
11 changed files with 436 additions and 3 deletions

View File

@ -0,0 +1,31 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/ohos.gni")
ohos_static_library("libfile") {
sources =
[ "//base/startup/init_lite/interfaces/innerkits/file/init_file.c" ]
include_dirs = [
"//base/startup/init_lite/interfaces/innerkits/include",
"//base/startup/init_lite/services/log",
"//base/startup/init_lite/services/include",
"//third_party/bounds_checking_function/include",
]
deps = [
"//base/startup/init_lite/services/log:init_log",
"//base/startup/init_lite/services/utils:libinit_utils",
"//third_party/bounds_checking_function:libsec_static",
]
}

View File

@ -0,0 +1,71 @@
/*
* 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_file.h"
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include "init_log.h"
#include "init_utils.h"
#include "securec.h"
#define N_DEC 10
int GetControlFile(const char *pathName)
{
if (pathName == NULL) {
return -1;
}
char *name = (char *)calloc(1, strlen(pathName) + 1);
INIT_CHECK(name != NULL, return -1);
if (strncpy_s(name, strlen(pathName) + 1, pathName, strlen(pathName)) < 0) {
INIT_LOGE("Failed strncpy_s err=%d", errno);
free(name);
return -1;
}
if (StringReplaceChr(name, '/', '_') < 0) {
free(name);
return -1;
}
char path[PATH_MAX] = { 0 };
if (snprintf_s(path, sizeof(path), sizeof(path) - 1, OHOS_FILE_ENV_PREFIX"%s", name) == -1) {
free(name);
return -1;
}
free(name);
INIT_LOGI("Environment path is %s ", path);
const char *val = getenv(path);
if (val == NULL) {
INIT_LOGE("Failed getenv err=%d", errno);
return -1;
}
errno = 0;
int fd = strtol(val, NULL, N_DEC);
if (errno != 0) {
INIT_LOGE("Failed strtol val");
return -1;
}
INIT_LOGI("Get environment fd is %d ", fd);
if (fcntl(fd, F_GETFD) < 0) {
INIT_LOGE("Failed fcntl fd err=%d ", errno);
return -1;
}
return fd;
}

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef INIT_FILE_API_H
#define INIT_FILE_API_H
#define OHOS_FILE_ENV_PREFIX "OHOS_FILE_"
int GetControlFile(const char *name);
#endif

View File

@ -18,6 +18,7 @@ init_common_sources = [
"init/init_config.c",
"init/init_service_manager.c",
"init/init_service_socket.c",
"init/init_service_file.c",
"init/main.c",
"log/init_log.c",
"utils/init_utils.c",
@ -168,6 +169,7 @@ if (defined(ohos_lite)) {
"//base/startup/init_lite/interfaces/innerkits/dynamic_service:dynamic_service",
"//base/startup/init_lite/interfaces/innerkits/fs_manager:libfsmanager_shared",
"//base/startup/init_lite/interfaces/innerkits/socket:libsocket",
"//base/startup/init_lite/interfaces/innerkits/file:libfile",
"//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",

View File

@ -45,6 +45,8 @@ int ReadFileInDir(const char *dirPath, const char *includeExt,
char **SplitStringExt(char *buffer, const char *del, int *returnCount, int maxItemCount);
void FreeStringVector(char **vector, int count);
int InUpdaterMode(void);
int StringReplaceChr(char *strl, char oldChr, char newChr);
#ifdef __cplusplus
#if __cplusplus
}

View File

@ -18,6 +18,7 @@
#include "cJSON.h"
#include "init_cmds.h"
#include "init_service_file.h"
#include "init_service_socket.h"
#ifdef WITH_SELINUX
# include "init_selinux_param.h"
@ -84,6 +85,7 @@ typedef struct {
ServiceArgs writePidArgs;
CmdLines *restartArg;
ServiceSocket *socketCfg;
ServiceFile *fileCfg;
} Service;
int ServiceStart(Service *service);

View File

@ -0,0 +1,53 @@
/*
* 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 INIT_SERVICE_FILE_
#define INIT_SERVICE_FILE_
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
#define FILE_OPT_NUMS 5
#define SERVICE_FILE_NAME 0
#define SERVICE_FILE_FLAGS 1
#define SERVICE_FILE_PERM 2
#define SERVICE_FILE_UID 3
#define SERVICE_FILE_GID 4
typedef struct ServiceFile_ {
struct ServiceFile_ *next;
int flags;
uid_t uid; // uid
gid_t gid; // gid
mode_t perm; // Setting permissions
int fd;
char fileName[0];
} ServiceFile;
void CreateServiceFile(ServiceFile *fileOpt);
void CloseServiceFile(ServiceFile *fileOpt);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif

View File

@ -213,6 +213,7 @@ int ServiceStart(Service *service)
INIT_LOGE("service %s exit! create socket failed!", service->name);
_exit(PROCESS_EXIT_CODE);
}
CreateServiceFile(service->fileCfg);
if (service->attribute & SERVICE_ATTR_CONSOLE) {
OpenConsole();
}
@ -248,6 +249,7 @@ int ServiceStop(Service *service)
return SERVICE_SUCCESS;
}
CloseServiceSocket(service->socketCfg);
CloseServiceFile(service->fileCfg);
if (kill(service->pid, SIGKILL) != 0) {
INIT_LOGE("stop service %s pid %d failed! err %d.", service->name, service->pid, errno);
return SERVICE_FAILURE;
@ -303,6 +305,7 @@ void ServiceReap(Service *service)
}
CloseServiceSocket(service->socketCfg);
CloseServiceFile(service->fileCfg);
// 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);

143
services/init/init_service_file.c Executable file
View File

@ -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_service_file.h"
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "init_log.h"
#include "init_service.h"
#include "init_utils.h"
#include "securec.h"
#define HOS_FILE_ENV_PREFIX "OHOS_FILE_"
#define MAX_FILE_FD_LEN 16
static int CreateFile(ServiceFile *file)
{
INIT_CHECK(file != NULL && file->fileName != NULL, return -1);
char path[PATH_MAX] = {0};
char *realPath = GetRealPath(file->fileName);
if (realPath == NULL && errno == ENOENT) {
if (strncpy_s(path, strlen(file->fileName) + 1, file->fileName, strlen(file->fileName)) != 0) {
return -1;
}
} else if (realPath != NULL) {
if (strncpy_s(path, strlen(realPath) + 1, realPath, strlen(realPath)) != 0) {
free(realPath);
return -1;
}
free(realPath);
} else {
INIT_LOGE("GetRealPath failed err=%d", errno);
return -1;
}
INIT_LOGI("File path =%s . file flags =%d, file perm =%u ", path, file->flags, file->perm);
if (file->fd >= 0) {
close(file->fd);
file->fd = -1;
}
int fd = open(path, file->flags | O_CREAT, file->perm);
if (fd < 0) {
INIT_LOGE("Failed open %s, err=%d ", path, errno);
return -1;
}
close(fd);
fd = -1;
if (chmod(path, file->perm) < 0) {
INIT_LOGE("Failed chmod err=%d", errno);
}
if (chown(path, file->uid, file->gid) < 0) {
INIT_LOGE("Failed chown err=%d", errno);
}
file->fd = open(path, file->flags);
return file->fd;
}
static int SetFileEnv(int fd, const char *pathName)
{
INIT_ERROR_CHECK(pathName != NULL, return -1, "Invalid fileName");
char *name = (char *)calloc(1, strlen(pathName) + 1);
INIT_CHECK(name != NULL, return -1);
if (strncpy_s(name, strlen(pathName) + 1, pathName, strlen(pathName)) < 0) {
INIT_LOGE("Failed strncpy_s err=%d", errno);
free(name);
return -1;
}
if (StringReplaceChr(name, '/', '_') < 0) {
free(name);
return -1;
}
char pubName[PATH_MAX] = { 0 };
if (snprintf_s(pubName, sizeof(pubName), sizeof(pubName) - 1, HOS_FILE_ENV_PREFIX "%s", name) < 0) {
free(name);
return -1;
}
free(name);
char val[MAX_FILE_FD_LEN] = { 0 };
if (snprintf_s(val, sizeof(val), sizeof(val) - 1, "%d", fd) < 0) {
return -1;
}
INIT_LOGE("Set file env pubName =%s, val =%s.", pubName, val);
int ret = setenv(pubName, val, 1);
if (ret < 0) {
INIT_LOGE("Failed setenv err=%d ", errno);
return -1;
}
fcntl(fd, F_SETFD, 0);
return 0;
}
void CreateServiceFile(ServiceFile *fileOpt)
{
INIT_CHECK(fileOpt != NULL, return);
ServiceFile *tmpFile = fileOpt;
while (tmpFile != NULL) {
int fd = CreateFile(tmpFile);
if (fd < 0) {
INIT_LOGE("Failed Create File err=%d ", errno);
tmpFile = tmpFile->next;
continue;
}
int ret = SetFileEnv(fd, tmpFile->fileName);
if (ret < 0) {
INIT_LOGE("Failed Set File Env");
}
tmpFile = tmpFile->next;
}
return;
}
void CloseServiceFile(ServiceFile *fileOpt)
{
INIT_CHECK(fileOpt != NULL, return);
ServiceFile *tmpFileOpt = fileOpt;
while (tmpFileOpt != NULL) {
ServiceFile *tmp = tmpFileOpt;
if (tmp->fd >= 0) {
close(tmp->fd);
tmp->fd = -1;
}
tmpFileOpt = tmpFileOpt->next;
}
return;
}

View File

@ -27,6 +27,7 @@
#include "init.h"
#include "init_jobs_internal.h"
#include "init_log.h"
#include "init_service_file.h"
#include "init_service_socket.h"
#include "init_utils.h"
#include "securec.h"
@ -131,6 +132,20 @@ static Service *AddService(void)
return service;
}
static void FreeServiceFile(ServiceFile *fileOpt)
{
while (fileOpt != NULL) {
ServiceFile *tmp = fileOpt;
if (tmp->fd >= 0) {
close(tmp->fd);
tmp->fd = -1;
}
fileOpt = fileOpt->next;
free(tmp);
}
return;
}
static void ReleaseService(Service *service)
{
if (service == NULL) {
@ -150,6 +165,7 @@ static void ReleaseService(Service *service)
}
service->servPerm.gIDCnt = 0;
FreeServiceSocket(service->socketCfg);
FreeServiceFile(service->fileCfg);
if (!ListEmpty(service->node)) {
ListRemove(&service->node);
@ -331,6 +347,7 @@ static int AddServiceSocket(cJSON *json, Service *service)
if (strncmp(opt[SERVICE_SOCK_SETOPT], "passcred", strlen(opt[SERVICE_SOCK_SETOPT])) == 0) {
sockopt->passcred = true;
}
sockopt->sockFd = -1;
sockopt->next = NULL;
if (service->socketCfg == NULL) {
service->socketCfg = sockopt;
@ -358,6 +375,75 @@ static int ParseServiceSocket(const cJSON *curArrItem, Service *curServ)
return ret;
}
static int AddServiceFile(cJSON *json, Service *service)
{
if (!cJSON_IsString(json) || !cJSON_GetStringValue(json)) {
return SERVICE_FAILURE;
}
char *fileStr = cJSON_GetStringValue(json);
char *opt[FILE_OPT_NUMS] = {
NULL,
};
int num = SplitString(fileStr, " ", opt, FILE_OPT_NUMS);
if (num != FILE_OPT_NUMS) {
return SERVICE_FAILURE;
}
if (opt[SERVICE_FILE_NAME] == NULL || opt[SERVICE_FILE_FLAGS] == NULL || opt[SERVICE_FILE_PERM] == NULL ||
opt[SERVICE_FILE_UID] == NULL || opt[SERVICE_FILE_GID] == NULL) {
INIT_LOGE("Invalid file opt");
return SERVICE_FAILURE;
}
ServiceFile *fileOpt = (ServiceFile *)calloc(1, sizeof(ServiceFile) + strlen(opt[SERVICE_FILE_NAME]) + 1);
INIT_INFO_CHECK(fileOpt != NULL, return SERVICE_FAILURE, "Failed to calloc for file %s", opt[SERVICE_FILE_NAME]);
int ret = strcpy_s(fileOpt->fileName, strlen(opt[SERVICE_FILE_NAME]) + 1, opt[SERVICE_FILE_NAME]);
INIT_INFO_CHECK(ret == 0, free(fileOpt);
return SERVICE_FAILURE, "Failed to copy file name %s", opt[SERVICE_FILE_NAME]);
if (strcmp(opt[SERVICE_FILE_FLAGS], "rd") == 0) {
fileOpt->flags = O_RDONLY;
} else if (strcmp(opt[SERVICE_FILE_FLAGS], "wd") == 0) {
fileOpt->flags = O_WRONLY;
} else if (strcmp(opt[SERVICE_FILE_FLAGS], "rw") == 0) {
fileOpt->flags = O_RDWR;
} else {
INIT_LOGE("Failed file flags %s", opt[SERVICE_FILE_FLAGS]);
return SERVICE_FAILURE;
}
fileOpt->perm = strtoul(opt[SERVICE_FILE_PERM], 0, OCTAL_BASE);
fileOpt->uid = DecodeUid(opt[SERVICE_FILE_UID]);
fileOpt->gid = DecodeUid(opt[SERVICE_FILE_GID]);
if (fileOpt->uid == (uid_t)-1 || fileOpt->gid == (gid_t)-1) {
free(fileOpt);
INIT_LOGE("Invalid uid %d or gid %d", fileOpt->uid, fileOpt->gid);
return SERVICE_FAILURE;
}
fileOpt->fd = -1;
fileOpt->next = NULL;
if (service->fileCfg == NULL) {
service->fileCfg = fileOpt;
} else {
fileOpt->next = service->fileCfg->next;
service->fileCfg->next = fileOpt;
}
return SERVICE_SUCCESS;
}
static int ParseServiceFile(const cJSON *curArrItem, Service *curServ)
{
int fileCnt = 0;
cJSON *filedJ = GetArrayItem(curArrItem, &fileCnt, "file");
INIT_CHECK(filedJ != NULL && fileCnt > 0, return SERVICE_FAILURE);
int ret = 0;
curServ->fileCfg = NULL;
for (int i = 0; i < fileCnt; ++i) {
cJSON *fileJ = cJSON_GetArrayItem(filedJ, i);
ret = AddServiceFile(fileJ, curServ);
if (ret != 0) {
break;
}
}
return ret;
}
static bool IsServiceInMainStrap(Service *curServ)
{
char *mainServiceList[] = {
@ -402,7 +488,7 @@ static int CheckServiceKeyName(const cJSON *curService)
{
char *cfgServiceKeyList[] = {
"name", "path", "uid", "gid", "once", "importance", "caps", "disabled",
"writepid", "critical", "socket", "console", "dynamic",
"writepid", "critical", "socket", "console", "dynamic", "file",
#ifdef WITH_SELINUX
SECON_STR_IN_CFG,
#endif // WITH_SELINUX
@ -512,11 +598,14 @@ void ParseAllServices(const cJSON *fileRoot)
ReleaseService(service);
continue;
}
ret = ParseServiceSocket(curItem, service);
if (ret != SERVICE_SUCCESS) {
if (ParseServiceSocket(curItem, service) != SERVICE_SUCCESS) {
FreeServiceSocket(service->socketCfg);
service->socketCfg = NULL;
}
if (ParseServiceFile(curItem, service) != SERVICE_SUCCESS) {
FreeServiceFile(service->fileCfg);
service->fileCfg = NULL;
}
ret = GetCmdLinesFromJson(cJSON_GetObjectItem(curItem, "onrestart"), &service->restartArg);
if (ret != SERVICE_SUCCESS) {
service->restartArg = NULL;

View File

@ -372,3 +372,17 @@ int InUpdaterMode(void)
return 0;
}
}
int StringReplaceChr(char *strl, char oldChr, char newChr)
{
INIT_ERROR_CHECK(strl != NULL, return -1, "Invalid parament");
char *p = strl;
while (*p != '\0') {
if (*p == oldChr) {
*p = newChr;
}
p++;
}
INIT_LOGD("strl is %s", strl);
return 0;
}