1 /* SPDX-License-Identifier: GPL-2.0 */
7 #include <linux/limits.h>
13 #include <sys/types.h>
17 #include "cgroup_util.h"
19 static ssize_t
read_text(const char *path
, char *buf
, size_t max_len
)
24 fd
= open(path
, O_RDONLY
);
28 len
= read(fd
, buf
, max_len
- 1);
38 static ssize_t
write_text(const char *path
, char *buf
, ssize_t len
)
42 fd
= open(path
, O_WRONLY
| O_APPEND
);
46 len
= write(fd
, buf
, len
);
57 char *cg_name(const char *root
, const char *name
)
59 size_t len
= strlen(root
) + strlen(name
) + 2;
60 char *ret
= malloc(len
);
62 snprintf(ret
, len
, "%s/%s", root
, name
);
67 char *cg_name_indexed(const char *root
, const char *name
, int index
)
69 size_t len
= strlen(root
) + strlen(name
) + 10;
70 char *ret
= malloc(len
);
72 snprintf(ret
, len
, "%s/%s_%d", root
, name
, index
);
77 char *cg_control(const char *cgroup
, const char *control
)
79 size_t len
= strlen(cgroup
) + strlen(control
) + 2;
80 char *ret
= malloc(len
);
82 snprintf(ret
, len
, "%s/%s", cgroup
, control
);
87 int cg_read(const char *cgroup
, const char *control
, char *buf
, size_t len
)
91 snprintf(path
, sizeof(path
), "%s/%s", cgroup
, control
);
93 if (read_text(path
, buf
, len
) >= 0)
99 int cg_read_strcmp(const char *cgroup
, const char *control
,
100 const char *expected
)
106 /* Handle the case of comparing against empty string */
110 size
= strlen(expected
) + 1;
116 if (cg_read(cgroup
, control
, buf
, size
)) {
121 ret
= strcmp(expected
, buf
);
126 int cg_read_strstr(const char *cgroup
, const char *control
, const char *needle
)
130 if (cg_read(cgroup
, control
, buf
, sizeof(buf
)))
133 return strstr(buf
, needle
) ? 0 : -1;
136 long cg_read_long(const char *cgroup
, const char *control
)
140 if (cg_read(cgroup
, control
, buf
, sizeof(buf
)))
146 long cg_read_key_long(const char *cgroup
, const char *control
, const char *key
)
151 if (cg_read(cgroup
, control
, buf
, sizeof(buf
)))
154 ptr
= strstr(buf
, key
);
158 return atol(ptr
+ strlen(key
));
161 int cg_write(const char *cgroup
, const char *control
, char *buf
)
164 ssize_t len
= strlen(buf
);
166 snprintf(path
, sizeof(path
), "%s/%s", cgroup
, control
);
168 if (write_text(path
, buf
, len
) == len
)
174 int cg_find_unified_root(char *root
, size_t len
)
176 char buf
[10 * PAGE_SIZE
];
177 char *fs
, *mount
, *type
;
178 const char delim
[] = "\n\t ";
180 if (read_text("/proc/self/mounts", buf
, sizeof(buf
)) <= 0)
185 * cgroup /sys/fs/cgroup cgroup2 rw,seclabel,noexec,relatime 0 0
187 for (fs
= strtok(buf
, delim
); fs
; fs
= strtok(NULL
, delim
)) {
188 mount
= strtok(NULL
, delim
);
189 type
= strtok(NULL
, delim
);
194 if (strcmp(type
, "cgroup2") == 0) {
195 strncpy(root
, mount
, len
);
203 int cg_create(const char *cgroup
)
205 return mkdir(cgroup
, 0644);
208 int cg_wait_for_proc_count(const char *cgroup
, int count
)
210 char buf
[10 * PAGE_SIZE
] = {0};
214 for (attempts
= 10; attempts
>= 0; attempts
--) {
217 if (cg_read(cgroup
, "cgroup.procs", buf
, sizeof(buf
)))
220 for (ptr
= buf
; *ptr
; ptr
++)
233 int cg_killall(const char *cgroup
)
238 if (cg_read(cgroup
, "cgroup.procs", buf
, sizeof(buf
)))
241 while (ptr
< buf
+ sizeof(buf
)) {
242 int pid
= strtol(ptr
, &ptr
, 10);
250 if (kill(pid
, SIGKILL
))
257 int cg_destroy(const char *cgroup
)
263 if (ret
&& errno
== EBUSY
) {
269 if (ret
&& errno
== ENOENT
)
275 int cg_enter(const char *cgroup
, int pid
)
279 snprintf(pidbuf
, sizeof(pidbuf
), "%d", pid
);
280 return cg_write(cgroup
, "cgroup.procs", pidbuf
);
283 int cg_enter_current(const char *cgroup
)
287 snprintf(pidbuf
, sizeof(pidbuf
), "%d", getpid());
288 return cg_write(cgroup
, "cgroup.procs", pidbuf
);
291 int cg_run(const char *cgroup
,
292 int (*fn
)(const char *cgroup
, void *arg
),
300 } else if (pid
== 0) {
303 snprintf(buf
, sizeof(buf
), "%d", getpid());
304 if (cg_write(cgroup
, "cgroup.procs", buf
))
306 exit(fn(cgroup
, arg
));
308 waitpid(pid
, &retcode
, 0);
309 if (WIFEXITED(retcode
))
310 return WEXITSTATUS(retcode
);
316 int cg_run_nowait(const char *cgroup
,
317 int (*fn
)(const char *cgroup
, void *arg
),
326 snprintf(buf
, sizeof(buf
), "%d", getpid());
327 if (cg_write(cgroup
, "cgroup.procs", buf
))
329 exit(fn(cgroup
, arg
));
335 int get_temp_fd(void)
337 return open(".", O_TMPFILE
| O_RDWR
| O_EXCL
);
340 int alloc_pagecache(int fd
, size_t size
)
351 if (ftruncate(fd
, size
))
354 for (i
= 0; i
< size
; i
+= sizeof(buf
))
355 read(fd
, buf
, sizeof(buf
));
363 int alloc_anon(const char *cgroup
, void *arg
)
365 size_t size
= (unsigned long)arg
;
369 for (ptr
= buf
; ptr
< buf
+ size
; ptr
+= PAGE_SIZE
)
376 int is_swap_enabled(void)
379 const char delim
[] = "\n";
383 if (read_text("/proc/swaps", buf
, sizeof(buf
)) <= 0)
386 for (line
= strtok(buf
, delim
); line
; line
= strtok(NULL
, delim
))
392 int set_oom_adj_score(int pid
, int score
)
397 sprintf(path
, "/proc/%d/oom_score_adj", pid
);
399 fd
= open(path
, O_WRONLY
| O_APPEND
);
403 len
= dprintf(fd
, "%d", score
);
413 char proc_read_text(int pid
, const char *item
, char *buf
, size_t size
)
417 snprintf(path
, sizeof(path
), "/proc/%d/%s", pid
, item
);
419 return read_text(path
, buf
, size
);