2 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "helper-cgroup.h"
19 #define RELEASE_AGENT "release_agent"
20 #define NOTIFY_ON_RELEASE "notify_on_release"
22 #define CGROUP_FILE_NAME "cgroup.procs"
23 #define CLASSID_FILE_NAME "net_cls.classid"
25 #define MAX_PATH_LENGTH 512
27 static bool cgroup_is_exists(const char *cgroup_full_path)
30 return stat(cgroup_full_path, &stat_buf) == 0;
33 static int cgroup_create(const char *cgroup_full_path)
35 if (mkdir(cgroup_full_path,
36 S_IRUSR | S_IWUSR | S_IRGRP) < 0)
37 return -errno; //LCOV_EXCL_LINE
43 * @desc place pid to cgroup.procs file
44 * @return 0 in case of success, errno value in case of failure
46 stc_error_e cgroup_write_pid_fullpath(const char *cgroup_full_path,
52 STC_LOGE("try to write empty pid to %s", cgroup_full_path); //LCOV_EXCL_LINE
53 return STC_ERROR_NO_DATA; //LCOV_EXCL_LINE
56 ret = cgroup_write_node_uint32(cgroup_full_path, CGROUP_FILE_NAME,
59 ret_value_msg_if(ret < 0, STC_ERROR_FAIL,
60 "Failed place all pid to cgroup %s", cgroup_full_path);
61 return STC_ERROR_NONE;
64 stc_error_e cgroup_write_pid(const char *cgroup_subsystem,
65 const char *cgroup_name, const int pid)
67 char buf[MAX_PATH_LENGTH];
68 snprintf(buf, sizeof(buf), "%s/%s", cgroup_subsystem, cgroup_name);
69 return cgroup_write_pid_fullpath(buf, pid);
73 stc_error_e cgroup_write_pidtree(const char *cgroup_subsystem,
74 const char *cgroup_name, const int pid)
76 char buf[MAX_PATH_LENGTH];
78 /*/proc/%d/task/%d/children */
79 char child_buf[21 + MAX_DEC_SIZE(int) + MAX_DEC_SIZE(int) + 1];
80 char pidbuf[MAX_DEC_SIZE(int)];
85 snprintf(buf, sizeof(buf), "%s/%s", cgroup_subsystem, cgroup_name);
87 ret = cgroup_write_pid_fullpath(buf, pid);
88 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
89 "Failed to put parent process %d into %s cgroup",
92 snprintf(child_buf, sizeof(child_buf), PROC_TASK_CHILDREN,
94 f = fopen(child_buf, "r");
95 ret_value_msg_if(!f, STC_ERROR_FAIL, "Failed to get child pids!");
96 while (fgets(pidbuf, sizeof(pidbuf), f) != NULL) {
97 int child_pid = atoi(pidbuf);
99 STC_LOGE("Invalid child pid!");
101 return STC_ERROR_FAIL;
103 stc_error_e ret = cgroup_write_pid_fullpath(buf, child_pid);
104 if (ret != STC_ERROR_NONE) {
105 STC_LOGE("Failed to put parent process %d into %s cgroup",
112 return STC_ERROR_NONE;
116 int cgroup_write_node_uint32(const char *cgroup_name,
117 const char *file_name, uint32_t value)
119 char buf[MAX_PATH_LENGTH];
120 snprintf(buf, sizeof(buf), "%s/%s", cgroup_name, file_name);
123 STC_LOGD("cgroup_buf %s, value %d\n", buf, value); //LCOV_EXCL_LINE
125 return fwrite_uint(buf, value);
128 int cgroup_write_node_str(const char *cgroup_name,
129 const char *file_name, const char *string)
131 char buf[MAX_PATH_LENGTH];
132 snprintf(buf, sizeof(buf), "%s/%s", cgroup_name, file_name);
135 STC_LOGD("cgroup_buf %s, string %s\n", buf, string); //LCOV_EXCL_LINE
137 return fwrite_str(buf, string);
140 int cgroup_read_node_uint32(const char *cgroup_name,
141 const char *file_name, uint32_t *value)
143 char buf[MAX_PATH_LENGTH];
145 snprintf(buf, sizeof(buf), "%s/%s", cgroup_name, file_name);
146 ret = fread_uint(buf, value);
149 STC_LOGD("cgroup_buf %s, value %d\n", buf, *value); //LCOV_EXCL_LINE
154 int cgroup_make_subdir(const char *parentdir, const char *cgroup_name,
157 char buf[MAX_PATH_LENGTH];
162 ret = snprintf(buf, sizeof(buf), "%s/%s",
163 parentdir, cgroup_name);
165 ret = snprintf(buf, sizeof(buf), "%s",
168 ret_value_msg_if(ret > sizeof(buf), STC_ERROR_FAIL,
169 "Not enought buffer size for %s%s",
170 parentdir, cgroup_name);
172 cgroup_exists = cgroup_is_exists(buf);
173 if (!cgroup_exists) {
174 bool cgroup_remount = false;
176 if (parentdir && !strncmp(parentdir, DEFAULT_CGROUP,
177 sizeof(DEFAULT_CGROUP))) {
178 ret = mount("tmpfs", DEFAULT_CGROUP, "tmpfs", //LCOV_EXCL_LINE
179 MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
182 STC_LOGE("Fail to RW mount cgroup directory. Can't make %s cgroup", cgroup_name); //LCOV_EXCL_LINE
183 return STC_ERROR_FAIL; //LCOV_EXCL_LINE
185 cgroup_remount = true;
188 ret = cgroup_create(buf);
189 ret_value_msg_if(ret < 0, STC_ERROR_FAIL,
190 "Fail to create cgroup %s : err %d",
193 if (cgroup_remount) {
194 ret = mount("tmpfs", DEFAULT_CGROUP, "tmpfs", //LCOV_EXCL_LINE
195 MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY,
198 STC_LOGD("Fail to RO mount"); //LCOV_EXCL_LINE
203 *already = cgroup_exists;
205 return STC_ERROR_NONE;
208 int cgroup_set_release_agent(const char *cgroup_subsys,
209 const char *release_agent)
211 _cleanup_free_ char *buf = NULL;
214 r = asprintf(&buf, "%s/%s", DEFAULT_CGROUP, cgroup_subsys);
218 r = cgroup_write_node_str(buf, RELEASE_AGENT, release_agent);
222 return cgroup_write_node_str(buf, NOTIFY_ON_RELEASE, "1");
225 void cgroup_init(void)
227 /* create stc cgroup directory */
228 cgroup_make_subdir(CGROUP_NETWORK, STC_CGROUP_NAME, NULL);
230 /* create background cgroup directory */
231 cgroup_make_subdir(STC_CGROUP_NETWORK, STC_BACKGROUND_CGROUP_NAME,
234 cgroup_write_node_uint32(BACKGROUND_CGROUP_NETWORK,
235 CLASSID_FILE_NAME, STC_BACKGROUND_APP_CLASSID);
237 /* create foreground cgroup directory */
238 cgroup_make_subdir(STC_CGROUP_NETWORK, STC_FOREGROUND_CGROUP_NAME,