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 int read_uint(FILE *handler, uint32_t *out)
29 return fscanf(handler, "%u", out);
32 static int write_uint(FILE *handler, uint32_t number)
34 _cleanup_free_ char *digit_buf = NULL;
37 ret = asprintf(&digit_buf, "%u\n", number);
38 ret_value_errno_msg_if(ret < 0, -ENOMEM, "asprintf failed\n");
40 ret = fputs(digit_buf, handler);
41 ret_value_errno_msg_if(ret == EOF, errno ? -errno : -EIO,
42 "Fail to write file");
47 static bool cgroup_is_exists(const char *cgroup_full_path)
50 return stat(cgroup_full_path, &stat_buf) == 0;
53 static int cgroup_create(const char *cgroup_full_path)
55 if (mkdir(cgroup_full_path,
56 S_IRUSR | S_IWUSR | S_IRGRP) < 0)
63 * @desc place pid to cgroup.procs file
64 * @return 0 in case of success, errno value in case of failure
66 stc_error_e cgroup_write_pid_fullpath(const char *cgroup_full_path,
72 STC_LOGE("try to write empty pid to %s", cgroup_full_path);
73 return STC_ERROR_NO_DATA;
76 ret = cgroup_write_node_uint32(cgroup_full_path, CGROUP_FILE_NAME,
79 ret_value_msg_if(ret < 0, STC_ERROR_FAIL,
80 "Failed place all pid to cgroup %s", cgroup_full_path);
81 return STC_ERROR_NONE;
84 stc_error_e cgroup_write_pid(const char *cgroup_subsystem,
85 const char *cgroup_name, const int pid)
87 char buf[MAX_PATH_LENGTH];
88 snprintf(buf, sizeof(buf), "%s/%s", cgroup_subsystem, cgroup_name);
89 return cgroup_write_pid_fullpath(buf, pid);
92 stc_error_e cgroup_write_pidtree(const char *cgroup_subsystem,
93 const char *cgroup_name, const int pid)
95 char buf[MAX_PATH_LENGTH];
97 /*/proc/%d/task/%d/children */
98 char child_buf[21 + MAX_DEC_SIZE(int) + MAX_DEC_SIZE(int)];
99 char pidbuf[MAX_DEC_SIZE(int)];
104 snprintf(buf, sizeof(buf), "%s/%s", cgroup_subsystem, cgroup_name);
106 ret = cgroup_write_pid_fullpath(buf, pid);
107 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
108 "Failed to put parent process %d into %s cgroup",
111 snprintf(child_buf, sizeof(child_buf), PROC_TASK_CHILDREN,
113 f = fopen(child_buf, "r");
114 ret_value_msg_if(!f, STC_ERROR_FAIL, "Failed to get child pids!");
115 while (fgets(pidbuf, sizeof(pidbuf), f) != NULL) {
116 int child_pid = atoi(pidbuf);
118 STC_LOGE("Invalid child pid!");
120 return STC_ERROR_FAIL;
122 stc_error_e ret = cgroup_write_pid_fullpath(buf, child_pid);
123 if (ret != STC_ERROR_NONE) {
124 STC_LOGE("Failed to put parent process %d into %s cgroup",
131 return STC_ERROR_NONE;
134 int cgroup_write_node_uint32(const char *cgroup_name,
135 const char *file_name, uint32_t value)
137 char buf[MAX_PATH_LENGTH];
138 snprintf(buf, sizeof(buf), "%s/%s", cgroup_name, file_name);
139 STC_LOGD("cgroup_buf %s, value %d\n", buf, value);
140 return fwrite_uint(buf, value);
143 int cgroup_write_node_str(const char *cgroup_name,
144 const char *file_name, const char *string)
146 char buf[MAX_PATH_LENGTH];
147 snprintf(buf, sizeof(buf), "%s/%s", cgroup_name, file_name);
148 STC_LOGD("cgroup_buf %s, string %s\n", buf, string);
149 return fwrite_str(buf, string);
152 int cgroup_read_node_uint32(const char *cgroup_name,
153 const char *file_name, uint32_t *value)
155 char buf[MAX_PATH_LENGTH];
157 snprintf(buf, sizeof(buf), "%s/%s", cgroup_name, file_name);
158 ret = fread_uint(buf, value);
159 STC_LOGD("cgroup_buf %s, value %d\n", buf, *value);
163 int cgroup_make_subdir(const char *parentdir, const char *cgroup_name,
166 char buf[MAX_PATH_LENGTH];
171 ret = snprintf(buf, sizeof(buf), "%s/%s",
172 parentdir, cgroup_name);
174 ret = snprintf(buf, sizeof(buf), "%s",
177 ret_value_msg_if(ret > sizeof(buf), STC_ERROR_FAIL,
178 "Not enought buffer size for %s%s",
179 parentdir, cgroup_name);
181 cgroup_exists = cgroup_is_exists(buf);
182 if (!cgroup_exists) {
183 bool cgroup_remount = false;
185 if (parentdir && !strncmp(parentdir, DEFAULT_CGROUP,
186 sizeof(DEFAULT_CGROUP))) {
187 ret = mount("tmpfs", DEFAULT_CGROUP, "tmpfs",
188 MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
191 STC_LOGE("Fail to RW mount cgroup directory. Can't make %s cgroup", cgroup_name);
192 return STC_ERROR_FAIL;
194 cgroup_remount = true;
197 ret = cgroup_create(buf);
198 ret_value_msg_if(ret < 0, STC_ERROR_FAIL,
199 "Fail to create cgroup %s : err %d",
202 if (cgroup_remount) {
203 ret = mount("tmpfs", DEFAULT_CGROUP, "tmpfs",
204 MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY,
207 STC_LOGD("Fail to RO mount");
212 *already = cgroup_exists;
214 return STC_ERROR_NONE;
217 /* FIXME: tasks is not removed from tasks list */
218 int cgroup_remove_pid(const char *cgroup_subsystem, const char *cgroup_name,
221 char cgroup_tasks_file_path[MAX_PATH_LENGTH];
224 pid_t pid_for_read = 0;
226 guint pid_count = 0;;
228 snprintf(cgroup_tasks_file_path, sizeof(cgroup_tasks_file_path),
229 "%s/%s/tasks", cgroup_subsystem, cgroup_name);
231 handler = fopen(cgroup_tasks_file_path, "r");
233 STC_LOGE("Read file open failed");
237 pids = g_array_new(FALSE, FALSE, sizeof(pid_t));
239 while (read_uint(handler, (uint32_t *)&pid_for_read) >= 0) {
240 if (pid_for_read != pid) {
241 pids = g_array_append_val(pids, pid_for_read);
248 handler = fopen(cgroup_tasks_file_path, "w");
250 STC_LOGE("Write file open failed");
254 for (i = 0; i < pid_count; i++)
255 write_uint(handler, g_array_index(pids, pid_t, i));
258 g_array_free(pids, TRUE);
262 int cgroup_set_release_agent(const char *cgroup_subsys,
263 const char *release_agent)
265 _cleanup_free_ char *buf = NULL;
268 r = asprintf(&buf, "%s/%s", DEFAULT_CGROUP, cgroup_subsys);
272 r = cgroup_write_node_str(buf, RELEASE_AGENT, release_agent);
276 return cgroup_write_node_str(buf, NOTIFY_ON_RELEASE, "1");
279 void cgroup_init(void)
281 /* create stc cgroup directory */
282 cgroup_make_subdir(CGROUP_NETWORK, STC_CGROUP_NAME, NULL);
284 /* create background cgroup directory */
285 cgroup_make_subdir(STC_CGROUP_NETWORK, STC_BACKGROUND_CGROUP_NAME,
288 cgroup_write_node_uint32(BACKGROUND_CGROUP_NETWORK,
289 CLASSID_FILE_NAME, STC_BACKGROUND_APP_CLASSID);
291 /* create foreground cgroup directory */
292 cgroup_make_subdir(STC_CGROUP_NETWORK, STC_FOREGROUND_CGROUP_NAME,