compctl: Fail more gracefully if ran on a non-compctld enabled machine
[compctl.git] / cgroup.c
blob31fd23069a2fcaf784373a2a259816340f789fe6
1 #include <limits.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <sys/mount.h>
6 #include <sys/stat.h>
7 #include <unistd.h>
9 #include "cgroup.h"
10 #include "common.h"
12 #if SWAP_LIMIT
13 #define MEMSW ".memsw"
14 #else
15 #define MEMSW
16 #endif
18 void (*cgroup_perror)(const char *s) = perror;
19 static const char cgroupfs[] = "/sys/fs/cgroup/";
21 int
22 cgroup_setup(const char *chier, const char *controllers)
24 char chierdir[PATH_MAX];
25 snprintf(chierdir, sizeof(chierdir), "%s%s", cgroupfs, chier);
26 if (access(chierdir, F_OK) >= 0)
27 return 0;
29 if (mount("none", cgroupfs, "tmpfs", 0, NULL) < 0) {
30 cgroup_perror(cgroupfs);
31 return -1;
33 if (mkdir(chierdir, 0777) < 0) {
34 cgroup_perror(chierdir);
35 return -1;
37 if (mount("none", chierdir, "cgroup", 0, controllers) < 0) {
38 cgroup_perror(chierdir);
39 return -1;
41 return 1;
44 int
45 cgroup_create(const char *chier, const char *cgroup)
47 char cgroupdir[PATH_MAX];
48 snprintf(cgroupdir, sizeof(cgroupdir), "%s%s/%s", cgroupfs, chier, cgroup);
49 if (access(cgroupdir, F_OK) >= 0)
50 return 0;
51 if (mkdir(cgroupdir, 0777) < 0) {
52 cgroup_perror(cgroupdir);
53 return -1;
55 return 1;
58 bool
59 cgroup_available(const char *chier, const char *cgroup)
61 char cgroupdir[PATH_MAX];
62 snprintf(cgroupdir, sizeof(cgroupdir), "%s%s/%s", cgroupfs, chier, cgroup);
63 return (access(cgroupdir, F_OK) >= 0);
67 int
68 cgroup_add_task(const char *chier, const char *cgroup, pid_t pid)
70 char tasksfile[PATH_MAX];
71 snprintf(tasksfile, sizeof(tasksfile), "%s%s/%s/tasks", cgroupfs, chier, cgroup);
72 FILE *tasks = fopen(tasksfile, "a");
73 if (!tasks) {
74 cgroup_perror(tasksfile);
75 return -1;
77 if (fprintf(tasks, "%d\n", pid) < 0) {
78 cgroup_perror(tasksfile);
79 fclose(tasks);
80 return -1;
82 if (fclose(tasks) < 0) {
83 cgroup_perror(tasksfile);
84 return -1;
86 return 1;
89 int
90 cgroup_is_task_in_cgroup(const char *chier, const char *cgroup, pid_t pid)
92 char tasksfile[PATH_MAX];
93 snprintf(tasksfile, sizeof(tasksfile), "%s%s/%s/tasks", cgroupfs, chier, cgroup);
94 FILE *tasks = fopen(tasksfile, "r");
95 if (!tasks) {
96 cgroup_perror(tasksfile);
97 return -1;
100 bool exists = false;
101 char line[128];
102 while (fgets(line, sizeof(line), tasks)) {
103 if (atoi(line) == pid) {
104 exists = true;
105 break;
108 fclose(tasks);
109 return exists;
113 cgroup_task_list(const char *chier, const char *cgroup, pid_t **tasklist)
115 char tasksfile[PATH_MAX];
116 snprintf(tasksfile, sizeof(tasksfile), "%s%s/%s/tasks", cgroupfs, chier, cgroup);
117 FILE *tasks = fopen(tasksfile, "r");
118 if (!tasks) {
119 cgroup_perror(tasksfile);
120 return -1;
123 int ntasks = 0;
124 *tasklist = NULL;
125 char line[128];
126 while (fgets(line, sizeof(line), tasks)) {
127 if (!(ntasks % 32))
128 *tasklist = realloc(*tasklist, (ntasks + 32) * sizeof(*tasklist));
129 (*tasklist)[ntasks++] = atoi(line);
131 fclose(tasks);
132 return ntasks;
136 size_t
137 cgroup_get_mem_limit(const char *chier, const char *cgroup)
139 char limitfile[PATH_MAX];
140 snprintf(limitfile, sizeof(limitfile), "%s%s/%s/memory"MEMSW".limit_in_bytes", cgroupfs, chier, cgroup);
141 FILE *limit = fopen(limitfile, "r");
142 if (!limit) {
143 cgroup_perror(limitfile);
144 return -1;
146 size_t nlimit = 0;
147 fscanf(limit, "%zu", &nlimit);
148 fclose(limit);
149 return nlimit;
152 static int
153 cgroup_set_mem_limit_do(const char *chier, const char *cgroup, size_t nlimit, char *memsw)
155 char limitfile[PATH_MAX];
156 snprintf(limitfile, sizeof(limitfile), "%s%s/%s/memory%s.limit_in_bytes", cgroupfs, chier, cgroup, memsw);
157 FILE *limit = fopen(limitfile, "w");
158 if (!limit) {
159 cgroup_perror(limitfile);
160 return -1;
162 if (fprintf(limit, "%zu\n", nlimit) < 0) {
163 cgroup_perror(limitfile);
164 fclose(limit);
165 return -1;
167 if (fclose(limit) < 0) {
168 cgroup_perror(limitfile);
169 return -1;
171 return 1;
174 static int
175 cgroup_set_mem_limit_twice(const char *chier, const char *cgroup, size_t nlimit, char *memsw1, char *memsw2)
177 int ret = cgroup_set_mem_limit_do(chier, cgroup, nlimit, memsw1);
178 if (ret >= 0) {
179 int ret2 = cgroup_set_mem_limit_do(chier, cgroup, nlimit, memsw2);
180 ret = ret2 < 0 ? ret2 : (ret || ret2);
182 return ret;
186 cgroup_set_mem_limit(const char *chier, const char *cgroup, size_t nlimit)
188 #if SWAP_LIMIT
189 /* We need to set both the "normal" and memsw limits, but in such
190 * order that normal <= memsw always holds. */
191 size_t curlimit = cgroup_get_mem_limit(chier, cgroup);
192 if (nlimit < curlimit)
193 return cgroup_set_mem_limit_twice(chier, cgroup, nlimit, "", MEMSW);
194 else
195 return cgroup_set_mem_limit_twice(chier, cgroup, nlimit, MEMSW, "");
196 #else
197 return cgroup_set_mem_limit_do(chier, cgroup, nlimit, "");
198 #endif
201 size_t
202 cgroup_get_mem_usage(const char *chier, const char *cgroup)
204 char usagefile[PATH_MAX];
205 snprintf(usagefile, sizeof(usagefile), "%s%s/%s/memory"MEMSW".usage_in_bytes", cgroupfs, chier, cgroup);
206 FILE *usage = fopen(usagefile, "r");
207 if (!usage) {
208 cgroup_perror(usagefile);
209 return -1;
211 size_t nusage = 0;
212 fscanf(usage, "%zu", &nusage);
213 fclose(usage);
214 return nusage;