1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <errno.h>
17 #include <inttypes.h>
18 #include <limits.h>
19 #include <signal.h>
20
21 #include "securec.h"
22 #include "init.h"
23 #include "init_log.h"
24 #include "init_utils.h"
25 #include "init_service.h"
26
GetCgroupPath(Service * service,char * buffer,uint32_t buffLen)27 INIT_STATIC int GetCgroupPath(Service *service, char *buffer, uint32_t buffLen)
28 {
29 int ret = snprintf_s(buffer, buffLen, buffLen - 1, "/dev/pids/native/%s/pid_%d/", service->name, service->pid);
30 INIT_ERROR_CHECK(ret > 0, return ret, "Failed to snprintf_s in GetCgroupPath, errno: %d", errno);
31 INIT_LOGV("Cgroup path %s ", buffer);
32 return 0;
33 }
34
WriteToFile(const char * path,pid_t pid)35 static int WriteToFile(const char *path, pid_t pid)
36 {
37 INIT_CHECK_RETURN_VALUE(pid != 0, -1);
38 char pidName[PATH_MAX] = {0};
39 int fd = open(path, O_RDWR | O_APPEND);
40 INIT_ERROR_CHECK(fd >= 0, return -1, "Failed to open file errno: %d path: %s", errno, path);
41 int ret = 0;
42 INIT_LOGV(" WriteToFile pid %d", pid);
43 do {
44 ret = snprintf_s(pidName, sizeof(pidName), sizeof(pidName) - 1, "%d", pid);
45 INIT_ERROR_CHECK(ret > 0, break, "Failed to snprintf_s in WriteToFile, errno: %d", errno);
46 ret = write(fd, pidName, strlen(pidName));
47 INIT_ERROR_CHECK(ret > 0, break, "Failed to write file errno: %d path: %s %s", errno, path, pidName);
48 ret = 0;
49 } while (0);
50
51 close(fd);
52 return ret;
53 }
54
KillProcessesByCGroup(const char * path,Service * service)55 static void KillProcessesByCGroup(const char *path, Service *service)
56 {
57 FILE *file = fopen(path, "r");
58 INIT_ERROR_CHECK(file != NULL, return, "Open file fail %s errno: %d", path, errno);
59 pid_t pid = 0;
60 while (fscanf_s(file, "%d\n", &pid) == 1 && pid > 0) {
61 INIT_LOGV(" KillProcessesByCGroup pid %d ", pid);
62 if (pid == service->pid) {
63 continue;
64 }
65 INIT_LOGI("Kill service pid %d now ...", pid);
66 if (kill(pid, SIGKILL) != 0) {
67 INIT_LOGE("Unable to kill process, pid: %d ret: %d", pid, errno);
68 }
69 }
70 (void)fclose(file);
71 }
72
DoRmdir(const TimerHandle handler,void * context)73 static void DoRmdir(const TimerHandle handler, void *context)
74 {
75 UNUSED(handler);
76 Service *service = (Service *)context;
77 INIT_ERROR_CHECK(service != NULL, return, "Service timer process with invalid service");
78 ServiceStopTimer(service);
79
80 char path[PATH_MAX] = {};
81 int ret = GetCgroupPath(service, path, sizeof(path));
82 free(service->name);
83 free(service);
84 INIT_ERROR_CHECK(ret == 0, return, "Failed to get real path errno: %d", errno);
85 ret = rmdir(path);
86 if (ret != 0) {
87 INIT_LOGE("Failed to rmdir %s errno: %d", path, errno);
88 }
89 }
90
RmdirTimer(Service * service,uint64_t timeout)91 static void RmdirTimer(Service *service, uint64_t timeout)
92 {
93 Service *serviceRmdir = (Service *)calloc(1, sizeof(Service));
94 INIT_ERROR_CHECK(serviceRmdir != NULL, return, "Failed to malloc for serviceRmdir");
95 serviceRmdir->pid = service->pid;
96 int strLen = strlen(service->name);
97 serviceRmdir->name = (char *)malloc(sizeof(char)*(strLen + 1));
98 INIT_ERROR_CHECK(serviceRmdir->name != NULL, free(serviceRmdir); return, "Failed to malloc for serviceRmdir->name");
99 int ret = strcpy_s(serviceRmdir->name, strLen + 1, service->name);
100 if (ret != 0) {
101 free(serviceRmdir->name);
102 free(serviceRmdir);
103 INIT_LOGE("Failed to copy, ret: %d", errno);
104 return;
105 }
106 LE_STATUS status = LE_CreateTimer(LE_GetDefaultLoop(), &serviceRmdir->timer, DoRmdir, (void *)serviceRmdir);
107 if (status != LE_SUCCESS) {
108 INIT_LOGE("Create service timer for service \' %s Rmdir \' failed, status = %d", serviceRmdir->name, status);
109 free(serviceRmdir->name);
110 free(serviceRmdir);
111 return;
112 }
113 status = LE_StartTimer(LE_GetDefaultLoop(), serviceRmdir->timer, timeout, 1);
114 if (status != LE_SUCCESS) {
115 INIT_LOGE("Start service timer for service \' %s Rmdir \' failed, status = %d", serviceRmdir->name, status);
116 free(serviceRmdir->name);
117 free(serviceRmdir);
118 }
119 }
120
ProcessServiceDied(Service * service)121 int ProcessServiceDied(Service *service)
122 {
123 INIT_CHECK_RETURN_VALUE(service != NULL, -1);
124 INIT_CHECK_RETURN_VALUE(service->pid != -1, 0);
125 INIT_CHECK_RETURN_VALUE(service->isCgroupEnabled, 0);
126 char path[PATH_MAX] = {};
127 INIT_LOGV("ProcessServiceDied %d to cgroup ", service->pid);
128 int ret = GetCgroupPath(service, path, sizeof(path));
129 INIT_ERROR_CHECK(ret == 0, return -1, "Failed to get real path errno: %d", errno);
130 ret = strcat_s(path, sizeof(path), "cgroup.procs");
131 INIT_ERROR_CHECK(ret == 0, return ret, "Failed to strcat_s errno: %d", errno);
132 KillProcessesByCGroup(path, service);
133 RmdirTimer(service, 200); // 200ms
134 return ret;
135 }
136
ProcessServiceAdd(Service * service)137 int ProcessServiceAdd(Service *service)
138 {
139 INIT_CHECK_RETURN_VALUE(service != NULL, -1);
140 INIT_CHECK_RETURN_VALUE(service->isCgroupEnabled, 0);
141 char path[PATH_MAX] = {};
142 INIT_LOGV("ProcessServiceAdd %d to cgroup ", service->pid);
143 int ret = GetCgroupPath(service, path, sizeof(path));
144 INIT_ERROR_CHECK(ret == 0, return -1, "Failed to get real path errno: %d", errno);
145 (void)MakeDirRecursive(path, 0755); // 0755 default mode
146 ret = strcat_s(path, sizeof(path), "cgroup.procs");
147 INIT_ERROR_CHECK(ret == 0, return ret, "Failed to strcat_s errno: %d", errno);
148 ret = WriteToFile(path, service->pid);
149 INIT_ERROR_CHECK(ret == 0, return ret, "write pid to cgroup.procs fail %s", path);
150 INIT_LOGV("Add service %d to cgroup %s success", service->pid, path);
151 return 0;
152 }